diff options
-rw-r--r-- | macosx/HBDVDDetector.h | 25 | ||||
-rw-r--r-- | macosx/HBDriveDetector.m | 240 | ||||
-rw-r--r-- | macosx/HandBrake.xcodeproj/project.pbxproj | 8 | ||||
-rw-r--r-- | macosx/ScanController.h | 5 | ||||
-rw-r--r-- | macosx/ScanController.mm | 199 |
5 files changed, 281 insertions, 196 deletions
diff --git a/macosx/HBDVDDetector.h b/macosx/HBDVDDetector.h new file mode 100644 index 000000000..935dd065c --- /dev/null +++ b/macosx/HBDVDDetector.h @@ -0,0 +1,25 @@ + /** + * HBDVDDetector.h + * 8/17/2007 + * + * This file is part of the HandBrake source code. + * Homepage: <http://handbrake.m0k.org/>. + * It may be used under the terms of the GNU General Public License. + */ + +#import <Cocoa/Cocoa.h> + + +@interface HBDVDDetector : NSObject +{ + NSString *path; + NSString *bsdName; +} + ++ (HBDVDDetector *)detectorForPath: (NSString *)aPath; +- (HBDVDDetector *)initWithPath: (NSString *)aPath; + +- (BOOL)isVideoDVD; +- (NSString *)devicePath; + +@end
\ No newline at end of file diff --git a/macosx/HBDriveDetector.m b/macosx/HBDriveDetector.m new file mode 100644 index 000000000..2b57237d9 --- /dev/null +++ b/macosx/HBDriveDetector.m @@ -0,0 +1,240 @@ +/** + * HBDriveDetector.m + * 8/17/2007 + * + * This file is part of the HandBrake source code. + * Homepage: <http://handbrake.m0k.org/>. + * It may be used under the terms of the GNU General Public License. + */ + +#include <IOKit/IOKitLib.h> +#include <IOKit/storage/IOMedia.h> +#include <IOKit/storage/IODVDMedia.h> + +#import "HBDVDDetector.h" + + +@interface HBDVDDetector (Private) + +- (NSString *)bsdNameForPath; +- (BOOL)pathHasVideoTS; +- (BOOL)deviceIsDVD; +- (io_service_t)getIOKitServiceForBSDName; +- (BOOL)isDVDService: (io_service_t)service; +- (BOOL)isWholeMediaService: (io_service_t)service; + +@end + + +@implementation HBDVDDetector + ++ (HBDVDDetector *)detectorForPath: (NSString *)aPath +{ + return [[[self alloc] initWithPath:aPath] autorelease]; +} + + +- (HBDVDDetector *)initWithPath: (NSString *)aPath +{ + NSAssert(aPath, @"nil string passed to drive detector."); + if( self = [super init] ) + { + path = [aPath retain]; + bsdName = nil; + } + return self; +} + + +- (void)dealloc +{ + [path release]; + path = nil; + [bsdName release]; + bsdName = nil; + [super dealloc]; +} + + +- (BOOL)isVideoDVD +{ + if( !bsdName ) + { + bsdName = [[self bsdNameForPath] retain]; + } + return ( [self pathHasVideoTS] && [self deviceIsDVD] ); +} + + +- (NSString *)devicePath +{ + if( !bsdName ) + { + bsdName = [[self bsdNameForPath] retain]; + } + return [NSString stringWithFormat:@"/dev/%@", bsdName]; +} + +@end + + +@implementation HBDVDDetector (Private) + +- (NSString *)bsdNameForPath +{ + OSStatus err; + FSRef ref; + err = FSPathMakeRef( (const UInt8 *) [path fileSystemRepresentation], + &ref, NULL ); + if( err != noErr ) + { + return nil; + } + + // Get the volume reference number. + FSCatalogInfo catalogInfo; + err = FSGetCatalogInfo( &ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL, + NULL); + if( err != noErr ) + { + return nil; + } + FSVolumeRefNum volRefNum = catalogInfo.volume; + + // Mow let's get the device name + GetVolParmsInfoBuffer volumeParms; + HParamBlockRec pb; + pb.ioParam.ioNamePtr = NULL; + pb.ioParam.ioVRefNum = volRefNum; + pb.ioParam.ioBuffer = (Ptr) &volumeParms; + pb.ioParam.ioReqCount = sizeof( volumeParms ); + err = PBHGetVolParmsSync( &pb ); + if( err != noErr ) + { + return nil; + } + + // 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 [NSString stringWithCString:(char *)volumeParms.vMDeviceID]; +} + + +- (BOOL)pathHasVideoTS +{ + // Check one level under the path + if( [[NSFileManager defaultManager] fileExistsAtPath: + [path stringByAppendingPathComponent:@"VIDEO_TS"]] ) + { + return YES; + } + + // Now check above the path + return [[path pathComponents] containsObject:@"VIDEO_TS"]; +} + + +- (BOOL)deviceIsDVD +{ + io_service_t service = [self getIOKitServiceForBSDName]; + if( service == IO_OBJECT_NULL ) + { + return NO; + } + BOOL result = [self isDVDService:service]; + IOObjectRelease(service); + return result; +} + + +- (io_service_t)getIOKitServiceForBSDName +{ + CFMutableDictionaryRef matchingDict; + matchingDict = IOBSDNameMatching( kIOMasterPortDefault, 0, [bsdName cString] ); + 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 ); +} + + +- (BOOL)isDVDService: (io_service_t)service +{ + // Find the 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. + // + // The whole media object is indicated in the IORegistry by the presence of + // a property with the key "Whole" and value "Yes". + + // Create an iterator across all parents of the service object passed in. + kern_return_t kernResult; + io_iterator_t iter; + kernResult = IORegistryEntryCreateIterator( service, + kIOServicePlane, + kIORegistryIterateRecursively | kIORegistryIterateParents, + &iter ); + if( kernResult != KERN_SUCCESS ) + { + return NO; + } + if( iter == IO_OBJECT_NULL ) + { + return NO; + } + + + // A reference on the initial service object is released in the do-while loop below, + // so add a reference to balance. + IOObjectRetain( service ); + + BOOL isDVD = NO; + do + { + isDVD = ( [self isWholeMediaService:service] && + IOObjectConformsTo(service, kIODVDMediaClass) ); + IOObjectRelease(service); + } while( !isDVD && (service = IOIteratorNext(iter)) ); + IOObjectRelease( iter ); + + return isDVD; +} + + +- (BOOL)isWholeMediaService: (io_service_t)service +{ + // + // Determine if the object passed in represents an IOMedia (or subclass) object. + // If it does, test the "Whole" property. + // + + Boolean isWholeMedia = NO; + + if( IOObjectConformsTo(service, kIOMediaClass) ) + { + CFTypeRef wholeMedia; + wholeMedia = IORegistryEntryCreateCFProperty( service, + CFSTR(kIOMediaWholeKey), + kCFAllocatorDefault, + 0); + if( !wholeMedia ) + { + return NO; + } + isWholeMedia = CFBooleanGetValue( (CFBooleanRef)wholeMedia ); + CFRelease(wholeMedia); + } + + return isWholeMedia; +} + + +@end
\ No newline at end of file diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index d9276afd3..40f88438a 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -124,6 +124,8 @@ A28468680C5A43D900EF9A98 /* Disc.tiff in Resources */ = {isa = PBXBuildFile; fileRef = A28468670C5A43D900EF9A98 /* Disc.tiff */; }; A29E05800BE1283E000533F5 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A29E057F0BE1283E000533F5 /* Growl.framework */; }; A29E058B0BE12889000533F5 /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = A29E057F0BE1283E000533F5 /* Growl.framework */; }; + A2A1EC310C76C35E00827E0D /* HBDVDDetector.h in Headers */ = {isa = PBXBuildFile; fileRef = A2A1EC300C76C35E00827E0D /* HBDVDDetector.h */; }; + A2A1EC3A0C76C58400827E0D /* HBDriveDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = A2A1EC390C76C58400827E0D /* HBDriveDetector.m */; }; A2DFC66E0C6196D900E66E89 /* actionWidget.png in Resources */ = {isa = PBXBuildFile; fileRef = A2DFC66C0C6196D900E66E89 /* actionWidget.png */; }; A2DFC66F0C6196D900E66E89 /* actionWidgetPressed.png in Resources */ = {isa = PBXBuildFile; fileRef = A2DFC66D0C6196D900E66E89 /* actionWidgetPressed.png */; }; A2DFC6750C6197C600E66E89 /* MVMenuButton.h in Headers */ = {isa = PBXBuildFile; fileRef = A2DFC6740C6197C600E66E89 /* MVMenuButton.h */; }; @@ -264,6 +266,8 @@ A273E0950C57C19500493A45 /* muxmkv.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = muxmkv.c; path = ../libhb/muxmkv.c; sourceTree = SOURCE_ROOT; }; A28468670C5A43D900EF9A98 /* Disc.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Disc.tiff; sourceTree = "<group>"; }; A29E057F0BE1283E000533F5 /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Growl.framework; sourceTree = "<group>"; }; + A2A1EC300C76C35E00827E0D /* HBDVDDetector.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HBDVDDetector.h; sourceTree = "<group>"; }; + A2A1EC390C76C58400827E0D /* HBDriveDetector.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = HBDriveDetector.m; sourceTree = "<group>"; }; A2DFC66C0C6196D900E66E89 /* actionWidget.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = actionWidget.png; sourceTree = "<group>"; }; A2DFC66D0C6196D900E66E89 /* actionWidgetPressed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = actionWidgetPressed.png; sourceTree = "<group>"; }; A2DFC6740C6197C600E66E89 /* MVMenuButton.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MVMenuButton.h; sourceTree = "<group>"; }; @@ -460,6 +464,8 @@ 4D2AE78A09CCB24C007E18F6 /* DriveDetector.h */, 593034E90BBA39A100172349 /* ChapterTitles.h */, 593034EA0BBA39A100172349 /* ChapterTitles.m */, + A2A1EC300C76C35E00827E0D /* HBDVDDetector.h */, + A2A1EC390C76C58400827E0D /* HBDriveDetector.m */, 253885FF0BFE0A5B0064E995 /* HBOutputRedirect.h */, 253886000BFE0A5B0064E995 /* HBOutputRedirect.m */, 253886150BFE0C160064E995 /* HBOutputPanelController.h */, @@ -526,6 +532,7 @@ 4DD93F92082036E8008E1322 /* PictureController.h in Headers */, 4DD93F93082036E8008E1322 /* QueueController.h in Headers */, 4D2AEA2A09CCB8FC007E18F6 /* DriveDetector.h in Headers */, + A2A1EC310C76C35E00827E0D /* HBDVDDetector.h in Headers */, 253886010BFE0A5B0064E995 /* HBOutputRedirect.h in Headers */, 253886170BFE0C160064E995 /* HBOutputPanelController.h in Headers */, 25DE1FB60C169A0C00F01FC8 /* HBPreferencesController.h in Headers */, @@ -799,6 +806,7 @@ 4DD93F9E082036E8008E1322 /* PictureController.mm in Sources */, 4DD93F9F082036E8008E1322 /* QueueController.mm in Sources */, 4D2AEA2909CCB8F9007E18F6 /* DriveDetector.m in Sources */, + A2A1EC3A0C76C58400827E0D /* HBDriveDetector.m in Sources */, 253886020BFE0A5B0064E995 /* HBOutputRedirect.m in Sources */, 253886180BFE0C160064E995 /* HBOutputPanelController.m in Sources */, 25DE1FB70C169A0C00F01FC8 /* HBPreferencesController.m in Sources */, diff --git a/macosx/ScanController.h b/macosx/ScanController.h index 1b31ec1e4..5bd72cd38 100644 --- a/macosx/ScanController.h +++ b/macosx/ScanController.h @@ -18,10 +18,7 @@ IBOutlet NSTextField * fStatusField; IBOutlet NSProgressIndicator * fIndicator; - - // DriveDetector * fDriveDetector; - // NSDictionary * fDrives; } - (void) SetHandle: (hb_handle_t *) handle; @@ -30,6 +27,6 @@ - (IBAction) Cancel: (id) sender; - (void) BrowseDone: (NSOpenPanel *) sheet returnCode: (int) returnCode contextInfo: (void *) contextInfo; -- (NSString *)dvdDevicePathForVolume: (NSString *)volumePath;; + @end diff --git a/macosx/ScanController.mm b/macosx/ScanController.mm index 7fab46eaa..81b27236c 100644 --- a/macosx/ScanController.mm +++ b/macosx/ScanController.mm @@ -15,8 +15,8 @@ #include <IOKit/storage/IOMedia.h> #include <IOKit/storage/IODVDMedia.h> +#include "HBDVDDetector.h" #include "ScanController.h" -//#include "DriveDetector.h" #include "dvdread/dvd_reader.h" @@ -81,215 +81,30 @@ NSString *path = [[sheet filenames] objectAtIndex: 0]; - NSString *dvdPath = [self dvdDevicePathForVolume: path]; - if (dvdPath) + HBDVDDetector *detector = [HBDVDDetector detectorForPath:path]; + if( [detector isVideoDVD] ) { - // The chosen path was actually a mount point for a DVD, so use the - // raw block device instead. - path = dvdPath; + // The chosen path was actually on a DVD, so use the raw block + // device path instead. + path = [detector devicePath]; } - + hb_scan( fHandle, [path UTF8String], 0 ); [self Cancel: nil]; } else // User clicked Cancel in browse window { - [self Cancel: nil]; - } } - - (IBAction) Cancel: (id) sender { [NSApp endSheet:fPanel]; [fPanel orderOut:self]; } - -Boolean IsDVD(io_service_t service) -{ - // - // Determine if the object passed in represents an IOMedia (or subclass) object. - // If it does, retrieve the "Whole" property. - // If this is the whole media object, find out if it is a DVD. - // If it isn't the whole media object, iterate across its parents in the IORegistry - // until the whole media object is found. - // - - Boolean isWholeMedia = NO; - - if (IOObjectConformsTo(service, kIOMediaClass)) - { - CFTypeRef wholeMedia; - - wholeMedia = IORegistryEntryCreateCFProperty(service, - CFSTR(kIOMediaWholeKey), - kCFAllocatorDefault, - 0); - - if (!wholeMedia) - { - return NO; - } - else - { - isWholeMedia = CFBooleanGetValue((CFBooleanRef)wholeMedia); - CFRelease(wholeMedia); - } - } - - if (isWholeMedia && IOObjectConformsTo(service, kIODVDMediaClass)) - { - return YES; - } - - return NO; -} - -Boolean FindDVD(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 NO; - } - - if (iter == IO_OBJECT_NULL) - { - return NO; - } - - Boolean isDVD; - - // A reference on the initial service object is released in the do-while loop below, - // so add a reference to balance - IOObjectRetain(service); - - do - { - isDVD = IsDVD(service); - IOObjectRelease(service); - } while (!isDVD && (service = IOIteratorNext(iter))); - - IOObjectRelease(iter); - - return isDVD; -} - -Boolean DeviceIsDVD(char *bsdName) -{ - // The idea is that given the BSD node name corresponding to a volume, - // I/O Kit can be used to find the information about the media, drive, bus, and so on - // that is maintained in the IORegistry. - // - // In this sample, we find out if the volume is on a CD, DVD, or some other media. - // This is done as follows: - // - // 1. Find the 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, (a floppy disk, for example) the volume's media - // object will be the whole media object. - // - // The whole media object is indicated in the IORegistry by the presence of a property with the key - // "Whole" and value "Yes". - // - // 2. Determine which I/O Kit class the whole media object belongs to. - // - // 3. For DVD media, return YES; - // - - CFMutableDictionaryRef matchingDict; - io_service_t service; - - matchingDict = IOBSDNameMatching(kIOMasterPortDefault, 0, bsdName); - if (matchingDict == NULL) - { - return NO; - } - - // Fetch the object with the matching BSD node name. // Note that there should only be one match, so IOServiceGetMatchingService is used instead of - // IOServiceGetMatchingServices to simplify the code. - service = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict); - - if (service == IO_OBJECT_NULL) { - return NO; - } - - Boolean isDVD = FindDVD(service); - IOObjectRelease(service); - return isDVD; -} - - -- (NSString *)dvdDevicePathForVolume: (NSString *)volumePath -{ - OSStatus err; - FSRef ref; - FSVolumeRefNum actualVolume; - err = FSPathMakeRef ( (const UInt8 *) [volumePath fileSystemRepresentation], &ref, NULL ); - - // get a FSVolumeRefNum from mountPath - if ( err != noErr ) - { - return nil; - } - - FSCatalogInfo catalogInfo; - err = FSGetCatalogInfo ( &ref, - kFSCatInfoVolume, - &catalogInfo, - NULL, - NULL, - NULL - ); - if ( err != noErr ) - { - return nil; - } - - actualVolume = catalogInfo.volume; - - // now let's get the device name - GetVolParmsInfoBuffer volumeParms; - HParamBlockRec pb; - - // Use the volume reference number to retrieve the volume parameters. See the documentation - // on PBHGetVolParmsSync for other possible ways to specify a volume. - pb.ioParam.ioNamePtr = NULL; - pb.ioParam.ioVRefNum = actualVolume; - pb.ioParam.ioBuffer = (Ptr) &volumeParms; - pb.ioParam.ioReqCount = sizeof(volumeParms); - - // 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. - err = PBHGetVolParmsSync(&pb); - - // Now that we have the device name, check to see if is a DVD or not. - //[self DeviceIsDVD: ((char *)volumeParms.vMDeviceID)] // cocoa - //if (!DeviceIsDVD) - char *deviceID = (char *)volumeParms.vMDeviceID; - //if (!DeviceIsDVD((char *)volumeParms.vMDeviceID)) // c - if (!DeviceIsDVD(deviceID)) - { - return nil; - } - return [NSString stringWithFormat: @"/dev/%s", deviceID]; -} - - - @end |