OSDN Git Service

CLI: Fixes optical scan reading in OS X by mirroring the MacGui work from r821. Thank...
authorjbrjake <jbrjake@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Thu, 24 Apr 2008 21:56:39 +0000 (21:56 +0000)
committerjbrjake <jbrjake@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Thu, 24 Apr 2008 21:56:39 +0000 (21:56 +0000)
git-svn-id: svn://localhost/HandBrake/trunk@1436 b64f7644-9d1e-0410-96f1-a4d463321fa5

macosx/HandBrake.xcodeproj/project.pbxproj
test/test.c

index 9f28079..943abc7 100644 (file)
                A9DE40450C959834008A5440 /* minus-8.png in Resources */ = {isa = PBXBuildFile; fileRef = A9DE40430C959834008A5440 /* minus-8.png */; };
                A9DE40460C959834008A5440 /* plus-8.png in Resources */ = {isa = PBXBuildFile; fileRef = A9DE40440C959834008A5440 /* plus-8.png */; };
                B48359A80C82960500E04440 /* lang.c in Sources */ = {isa = PBXBuildFile; fileRef = B48359A70C82960500E04440 /* lang.c */; };
+               D289A9F30DBBE7AC00CE614B /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D289A9F20DBBE7AC00CE614B /* CoreServices.framework */; };
+               D289AAC40DBBF3F100CE614B /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DEB2024052B055F00C39CA9 /* IOKit.framework */; };
                D4D49FED0C83355600F01215 /* lang.c in Sources */ = {isa = PBXBuildFile; fileRef = B48359A70C82960500E04440 /* lang.c */; };
                E3003C7F0C88505D0072F2A8 /* DeleteHighlightPressed.png in Resources */ = {isa = PBXBuildFile; fileRef = E3003C7E0C88505D0072F2A8 /* DeleteHighlightPressed.png */; };
                E3003CB50C8852B70072F2A8 /* DeletePressed.png in Resources */ = {isa = PBXBuildFile; fileRef = E3003CB40C8852B70072F2A8 /* DeletePressed.png */; };
                A9DE40430C959834008A5440 /* minus-8.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "minus-8.png"; sourceTree = "<group>"; };
                A9DE40440C959834008A5440 /* plus-8.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "plus-8.png"; sourceTree = "<group>"; };
                B48359A70C82960500E04440 /* lang.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = lang.c; path = ../libhb/lang.c; sourceTree = SOURCE_ROOT; };
+               D289A9F20DBBE7AC00CE614B /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = "<absolute>"; };
                E3003C7E0C88505D0072F2A8 /* DeleteHighlightPressed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DeleteHighlightPressed.png; sourceTree = "<group>"; };
                E3003CB40C8852B70072F2A8 /* DeletePressed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DeletePressed.png; sourceTree = "<group>"; };
                E37167830C92F6180072B384 /* JobPassSecondSmall.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = JobPassSecondSmall.png; sourceTree = "<group>"; };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               D289AAC40DBBF3F100CE614B /* IOKit.framework in Frameworks */,
+                               D289A9F30DBBE7AC00CE614B /* CoreServices.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                29B97323FDCFA39411CA2CEA /* Frameworks */ = {
                        isa = PBXGroup;
                        children = (
+                               D289A9F20DBBE7AC00CE614B /* CoreServices.framework */,
                                A2D0A0AA0D3E5929002D57CB /* Sparkle.framework */,
                                A29E057F0BE1283E000533F5 /* Growl.framework */,
                                4D1125D709D72FD200E0657B /* libz.dylib */,
index 90a95e3..bfcd875 100644 (file)
 #include "hb.h"
 #include "parsecsv.h"
 
+#ifdef __APPLE_CC__
+#import <CoreServices/CoreServices.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IODVDMedia.h>
+#endif
+
 /* Options */
 static int    debug       = HB_DEBUG_NONE;
 static int    update      = 0;
@@ -95,6 +102,14 @@ static int  HandleEvents( hb_handle_t * h );
 static int get_acodec_for_string( char *codec );
 static int is_sample_rate_valid(int rate);
 
+#ifdef __APPLE_CC__
+static char* bsd_name_for_path(char *path);
+static int device_is_dvd(char *device);
+static io_service_t get_iokit_service( char *device );
+static int is_dvd_service( io_service_t service );
+static is_whole_media_service( io_service_t service );
+#endif
+
 /* Only print the "Muxing..." message once */
 static int show_mux_warning = 1;
 
@@ -1641,6 +1656,20 @@ static int ParseOptions( int argc, char ** argv )
                 break;
             case 'i':
                 input = strdup( optarg );
+                #ifdef __APPLE_CC__
+                char *devName = bsd_name_for_path( input );
+                if( devName == NULL )
+                {
+                    return 0;
+                }
+                if( device_is_dvd( devName ) )
+                {
+                    char *newInput = malloc( strlen("/dev/") + strlen( devName ) + 1);
+                    sprintf( newInput, "/dev/%s", devName );
+                    free(input);
+                    input = newInput;
+                }
+                #endif
                 break;
             case 'o':
                 output = strdup( optarg );
@@ -2098,3 +2127,160 @@ static int is_sample_rate_valid(int rate)
     }
     return 0;
 }
+
+#ifdef __APPLE_CC__
+/****************************************************************************
+ * bsd_name_for_path
+ *
+ * Returns the BSD device name for the block device that contains the
+ * passed-in path. Returns NULL on failure.
+ ****************************************************************************/
+static char* bsd_name_for_path(char *path)
+{
+    OSStatus err;
+    FSRef ref;
+    err = FSPathMakeRef( (const UInt8 *) input, &ref, NULL );
+    if( err != noErr )
+    {
+        return NULL;
+    }
+
+    // Get the volume reference number.
+    FSCatalogInfo catalogInfo;
+    err = FSGetCatalogInfo( &ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL,
+                            NULL);
+    if( err != noErr )
+    {
+        return NULL;
+    }
+    FSVolumeRefNum volRefNum = catalogInfo.volume;
+
+    // Now let's get the device name
+    GetVolParmsInfoBuffer volumeParms;
+    err = FSGetVolumeParms( volRefNum, &volumeParms, sizeof( volumeParms ) );
+    if( err != noErr )
+    {
+        return NULL;
+    }
+
+    // A version 4 GetVolParmsInfoBuffer contains the BSD node name in the
+    // vMDeviceID field. It is actually a char * value. This is mentioned in the
+    // header CoreServices/CarbonCore/Files.h.
+    return volumeParms.vMDeviceID;
+}
+
+/****************************************************************************
+ * device_is_dvd
+ *
+ * Returns whether or not the passed in BSD device represents a DVD, or other
+ * optical media.
+ ****************************************************************************/
+static int device_is_dvd(char *device)
+{
+    io_service_t service = get_iokit_service(device);
+    if( service == IO_OBJECT_NULL )
+    {
+        return 0;
+    }
+    int result = is_dvd_service(service);
+    IOObjectRelease(service);
+    return result;
+}
+
+/****************************************************************************
+ * get_iokit_service
+ *
+ * Returns the IOKit service object for the passed in BSD device name.
+ ****************************************************************************/
+static io_service_t get_iokit_service( char *device )
+{
+    CFMutableDictionaryRef matchingDict;
+    matchingDict = IOBSDNameMatching( kIOMasterPortDefault, 0, device );
+    if( matchingDict == NULL )
+    {
+        return IO_OBJECT_NULL;
+    }
+    // Fetch the object with the matching BSD node name. There should only be
+    // one match, so IOServiceGetMatchingService is used instead of
+    // IOServiceGetMatchingServices to simplify the code.
+    return IOServiceGetMatchingService( kIOMasterPortDefault, matchingDict );
+}
+
+/****************************************************************************
+ * is_dvd_service
+ *
+ * Returns whether or not the service passed in is a DVD.
+ *
+ * Searches for an IOMedia object that represents the entire (whole) media that
+ * the volume is on. If the volume is on partitioned media, the whole media
+ * object will be a parent of the volume's media object. If the media is not
+ * partitioned, the volume's media object will be the whole media object.
+ ****************************************************************************/
+static int is_dvd_service( io_service_t service )
+{
+    kern_return_t  kernResult;
+    io_iterator_t  iter;
+
+    // Create an iterator across all parents of the service object passed in.
+    kernResult = IORegistryEntryCreateIterator( service,
+                                                kIOServicePlane,
+                                                kIORegistryIterateRecursively | kIORegistryIterateParents,
+                                                &iter );
+    if( kernResult != KERN_SUCCESS )
+    {
+        return 0;
+    }
+    if( iter == IO_OBJECT_NULL )
+    {
+        return 0;
+    }
+
+    // A reference on the initial service object is released in the do-while
+    // loop below, so add a reference to balance.
+    IOObjectRetain( service );
+
+    int result = 0;
+    do
+    {
+        if( is_whole_media_service( service ) &&
+            IOObjectConformsTo( service, kIODVDMediaClass) )
+        {
+            result = 1;
+        }
+        IOObjectRelease( service );
+    } while( !result && (service = IOIteratorNext( iter )) );
+    IOObjectRelease( iter );
+
+    return result;
+}
+
+/****************************************************************************
+ * is_whole_media_service
+ *
+ * Returns whether or not the service passed in is an IOMedia service and
+ * represents the "whole" media instead of just a partition.
+ *
+ * The whole media object is indicated in the IORegistry by the presence of a
+ * property with the key "Whole" and value "Yes".
+ ****************************************************************************/
+static is_whole_media_service( io_service_t service )
+{
+    int result = 0;
+
+    if( IOObjectConformsTo( service, kIOMediaClass ) )
+    {
+        CFTypeRef wholeMedia = IORegistryEntryCreateCFProperty( service,
+                                                                CFSTR( kIOMediaWholeKey ),
+                                                                kCFAllocatorDefault,
+                                                                0 );
+        if ( !wholeMedia )
+        {
+            return 0;
+        }
+        result = CFBooleanGetValue( (CFBooleanRef)wholeMedia );
+        CFRelease( wholeMedia );
+    }
+
+    return result;
+}
+#endif // __APPLE_CC__