diff options
author | dynaflash <[email protected]> | 2007-08-16 19:10:11 +0000 |
---|---|---|
committer | dynaflash <[email protected]> | 2007-08-16 19:10:11 +0000 |
commit | 332f66902d4d5ff350b1925ab8e2f501d361022b (patch) | |
tree | f68fb1576e275a36e5d864d061f3bc6ccbb73838 | |
parent | 3f1f0e0db601b683901aee9e6ba2a763eabbdba2 (diff) |
MacGui: fix scancontroller to use mount point instead of file path for physical commercial dvds.
- thanks for the work on this one blindjimmy !
- needs to be prettier, but wanted it checked in asap before release for testing.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@821 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r-- | macosx/ScanController.h | 8 | ||||
-rw-r--r-- | macosx/ScanController.mm | 204 |
2 files changed, 205 insertions, 7 deletions
diff --git a/macosx/ScanController.h b/macosx/ScanController.h index 9e31f3ce2..1b31ec1e4 100644 --- a/macosx/ScanController.h +++ b/macosx/ScanController.h @@ -7,7 +7,7 @@ #include <Cocoa/Cocoa.h> #include "hb.h" -@class DriveDetector; +//@class DriveDetector; @interface ScanController : NSObject { hb_handle_t * fHandle; @@ -20,8 +20,8 @@ IBOutlet NSProgressIndicator * fIndicator; - DriveDetector * fDriveDetector; - NSDictionary * fDrives; + // DriveDetector * fDriveDetector; + // NSDictionary * fDrives; } - (void) SetHandle: (hb_handle_t *) handle; @@ -30,6 +30,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 f894cf2a6..7fab46eaa 100644 --- a/macosx/ScanController.mm +++ b/macosx/ScanController.mm @@ -11,8 +11,14 @@ #include <IOKit/storage/IODVDMedia.h> */ +#include <IOKit/IOKitLib.h> +#include <IOKit/storage/IOMedia.h> +#include <IOKit/storage/IODVDMedia.h> + #include "ScanController.h" -#include "DriveDetector.h" +//#include "DriveDetector.h" + +#include "dvdread/dvd_reader.h" #define _(a) NSLocalizedString(a,nil) #define INSERT_STRING @"Insert a DVD" @@ -66,13 +72,24 @@ [fIndicator setHidden: NO]; [fIndicator setIndeterminate: YES]; [fIndicator startAnimation: nil]; - [fDriveDetector stop]; + /* we set the last source directory in the prefs here */ NSString *sourceDirectory = [[[sheet filenames] objectAtIndex: 0] stringByDeletingLastPathComponent]; [[NSUserDefaults standardUserDefaults] setObject:sourceDirectory forKey:@"LastSourceDirectory"]; - hb_scan( fHandle, [[[sheet filenames] objectAtIndex: 0] UTF8String], 0 ); + + + NSString *path = [[sheet filenames] objectAtIndex: 0]; + NSString *dvdPath = [self dvdDevicePathForVolume: path]; + if (dvdPath) + { + // The chosen path was actually a mount point for a DVD, so use the + // raw block device instead. + path = dvdPath; + } + + hb_scan( fHandle, [path UTF8String], 0 ); [self Cancel: nil]; } @@ -94,4 +111,185 @@ [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 |