summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--macosx/HandBrake.xcodeproj/project.pbxproj6
-rw-r--r--test/test.c186
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__