diff options
-rw-r--r-- | macosx/HandBrake.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | test/test.c | 186 |
2 files changed, 192 insertions, 0 deletions
diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index 9f280792a..943abc78c 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -123,6 +123,8 @@ 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 */; }; @@ -287,6 +289,7 @@ 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>"; }; @@ -346,6 +349,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D289AAC40DBBF3F100CE614B /* IOKit.framework in Frameworks */, + D289A9F30DBBE7AC00CE614B /* CoreServices.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -417,6 +422,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + D289A9F20DBBE7AC00CE614B /* CoreServices.framework */, A2D0A0AA0D3E5929002D57CB /* Sparkle.framework */, A29E057F0BE1283E000533F5 /* Growl.framework */, 4D1125D709D72FD200E0657B /* libz.dylib */, diff --git a/test/test.c b/test/test.c index 90a95e3dc..bfcd87539 100644 --- a/test/test.c +++ b/test/test.c @@ -13,6 +13,13 @@ #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__ |