OSDN Git Service

Not needed! bad commit...
[handbrake-jp/handbrake-jp-git.git] / macosx / ExpressController.m
index 6a56072..c1a78a8 100644 (file)
@@ -1,13 +1,18 @@
 #import "ExpressController.h"
+#import "DriveDetector.h"
+
+#define INSERT_STRING @"Insert a DVD"
 
 @interface ExpressController (Private)
 
+- (void) openUpdateDrives: (NSDictionary *) drives;
 - (void) openBrowseDidEnd: (NSOpenPanel *) sheet returnCode: (int)
     returnCode contextInfo: (void *) contextInfo;
 - (void) openEnable: (BOOL) b;
 - (void) openTimer: (NSTimer *) timer;
 
 - (void) convertShow;
+- (void) convertEnable: (BOOL) b;
 - (void) convertTimer: (NSTimer *) timer;
 
 @end
  **********************************************************************/
 - (void) awakeFromNib
 {
+    NSEnumerator * enumerator;
+
     /* Show the "Open DVD" interface */
+    fDriveDetector = [[DriveDetector alloc] initWithCallback: self
+        selector: @selector( openUpdateDrives: )];
+    [fDriveDetector run];
     [self openEnable: YES];
     [fWindow setContentSize: [fOpenView frame].size];
     [fWindow setContentView: fOpenView];
     [fWindow makeKeyAndOrderFront: nil];
 
     /* NSTableView initializations */
-    NSTableColumn * tableColumn = [fConvertTableView
-        tableColumnWithIdentifier: @"Check"];
-    NSButtonCell * buttonCell = [[[NSButtonCell alloc]
-        initTextCell: @""] autorelease];
+     NSButtonCell * buttonCell;
+     NSTableColumn * tableColumn;
+     enumerator = [[fConvertTableView tableColumns] objectEnumerator];
+     while( ( tableColumn = [enumerator nextObject] ) )
+     {
+         [tableColumn setEditable: NO];
+     }
+     tableColumn = [fConvertTableView tableColumnWithIdentifier: @"Check"];
+     buttonCell = [[[NSButtonCell alloc] initTextCell: @""] autorelease];
     [buttonCell setEditable: YES];
     [buttonCell setButtonType: NSSwitchButton];
     [tableColumn setDataCell: buttonCell];
@@ -42,7 +57,7 @@
 
 - (void) applicationWillFinishLaunching: (NSNotification *) n
 {
-    fHandle = hb_init( HB_DEBUG_NONE, 0 );
+    fHandle = hb_init_express( HB_DEBUG_NONE, 0 );
     fList   = hb_get_titles( fHandle );
 }
 
@@ -52,7 +67,7 @@
 }
 
 /***********************************************************************
- * Tableview delegate methods
+ * Tableview datasource methods
  **********************************************************************/
 - (int) numberOfRowsInTableView: (NSTableView *) t
 {
@@ -77,7 +92,7 @@
             return [@"Title " stringByAppendingFormat: @"%d",
                     title->index];
         }
-        else if( [[col identifier] isEqualToString: @"Length"] )
+        else if( [[col identifier] isEqualToString: @"Duration"] )
         {
             if( title->hours > 0 )
             {
     [fWindow setContentView: fEmptyView];
     [fWindow setFrame: frame display: YES animate: YES];
     [fWindow setContentView: fOpenView];
+
+    [fDriveDetector run];
 }
 
 - (void) openMatrixChanged: (id) sender
 {
     [self openEnable: YES];
+    if( [fOpenMatrix selectedRow] )
+    {
+        [self openBrowse: self];
+    }
 }
 
 - (void) openBrowse: (id) sender
     [self openEnable: NO];
     [fOpenIndicator setIndeterminate: YES];
     [fOpenIndicator startAnimation: nil];
+    [fOpenProgressField setStringValue: @"Opening..."];
+    [fDriveDetector stop];
 
-    hb_scan( fHandle, [fOpenFolderString UTF8String], 0 );
+    if( [fOpenMatrix selectedRow] )
+    {
+        hb_scan( fHandle, [fOpenFolderString UTF8String], 0 );
+    }
+    else
+    {
+        hb_scan( fHandle, [[fDrives objectForKey: [fOpenPopUp
+                 titleOfSelectedItem]] UTF8String], 0 );
+    }
 
-    NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
+    NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval: 2.0
         target: self selector: @selector( openTimer: ) userInfo: nil
         repeats: YES];
 }
 
 - (void) convertGo: (id) sender
 {
-    int i;
+    int i, j;
 
     for( i = 0; i < hb_list_count( fList ); i++ )
     {
         hb_title_t * title = hb_list_item( fList, i );
         hb_job_t   * job   = title->job;
 
-        job->width = 320;
-        for( ;; )
+        int pixels = 307200;
+               int aspect = title->aspect;
+               if( [fConvertAspectPopUp indexOfSelectedItem] == 1)
+               {
+            aspect = 4 * HB_ASPECT_BASE / 3;
+               }
+
+               int maxwidth = 640;
+               job->vbitrate = 1000;
+               if( [fConvertMaxWidthPopUp indexOfSelectedItem] == 1)
+               {
+            maxwidth = 320;
+                       job->vbitrate = 500;
+               }
+               job->deinterlace = 1;
+               
+               do
+               {
+                       hb_set_size( job, aspect, pixels );
+                       pixels -= 10;
+               } while(job->width > maxwidth);
+               
+        if( [fConvertFormatPopUp indexOfSelectedItem] == 0 )
         {
-            /* XXX */
-            hb_fix_aspect( job, HB_KEEP_WIDTH );
-            if( job->height == 240 )
+            /* iPod / H.264 */
+            job->mux      = HB_MUX_IPOD;
+            job->vcodec   = HB_VCODEC_X264;
+                       job->h264_level = 30;
+        }
+        else if( [fConvertFormatPopUp indexOfSelectedItem] == 1 )
+        {
+            /* iPod / MPEG-4 */
+            job->mux      = HB_MUX_MP4;
+            job->vcodec   = HB_VCODEC_FFMPEG;
+        }
+        else
+        {
+            /* PSP / MPEG-4 */
+            job->mux        = HB_MUX_PSP;
+            job->vrate      = 27000000;
+            job->vrate_base = 900900;   /* 29.97 fps */
+            job->vcodec     = HB_VCODEC_FFMPEG;
+            job->vbitrate   = 600;
+            pixels          = 76800;
+            job->arate      = 24000;
+            job->abitrate   = 96;
+            aspect          = 16 * HB_ASPECT_BASE / 9;
+
+                       if( [fConvertAspectPopUp indexOfSelectedItem] )
+                       {
+                               aspect = -1;
+                       }
+
+                       hb_set_size( job, aspect, pixels );
+        }
+
+        job->vquality = -1.0;
+
+        const char * lang;
+
+        /* Audio selection */
+        hb_audio_t * audio;
+        lang = [[fConvertAudioPopUp titleOfSelectedItem] UTF8String];
+        job->audios[0] = -1;
+        for( j = 0; j < hb_list_count( title->list_audio ); j++ )
+        {
+            /* Choose the first track that matches the language */
+            audio = hb_list_item( title->list_audio, j );
+            if( !strcmp( lang, audio->lang_simple ) )
             {
+                job->audios[0] = j;
                 break;
             }
-            else if( job->height < 240 )
-            {
-                job->crop[2] += 2;
-                job->crop[3] += 2;
-            }
-            else
+        }
+        if( job->audios[0] == -1 )
+        {
+            /* If the language isn't available in this title, choose
+               the first track */
+            job->audios[0] = 0;
+        }
+        job->audios[1] = -1;
+
+        /* Subtitle selection */
+        hb_subtitle_t * subtitle;
+        lang = [[fConvertSubtitlePopUp titleOfSelectedItem] UTF8String];
+        job->subtitle = -1;
+        for( j = 0; j < hb_list_count( title->list_subtitle ); j++ )
+        {
+            /* Choose the first track that matches the language */
+            subtitle = hb_list_item( title->list_subtitle, j );
+            if( !strcmp( lang, subtitle->lang ) )
             {
-                job->crop[0] += 2;
-                job->crop[1] += 2;
+                job->subtitle = j;
+                break;
             }
         }
-        job->vquality = -1.0;
-        job->vbitrate = 600;
-        job->vcodec   = HB_VCODEC_X264;
-        job->h264_13  = 1;
-        job->file     = strdup( [[NSString stringWithFormat:
-            @"%@/%p - Title %d.mp4", fConvertFolderString, self,
-            title->index] UTF8String] );
+        
+        job->file = strdup( [[NSString stringWithFormat:                 
+                @"%@/%s - Title %d.m4v", fConvertFolderString,      
+                title->name, title->index] UTF8String] );
         hb_add( fHandle, job );
     }
 
     hb_start( fHandle );
 
-    NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
+    NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval: 2.0
         target: self selector: @selector( convertTimer: ) userInfo: nil
         repeats: YES];
+
+    [self convertEnable: NO];
+}
+
+- (void) convertCancel: (id) sender
+{
+    hb_stop( fHandle );
+    [self convertEnable: YES];
 }
 
 @end
 
 @implementation ExpressController (Private)
 
+- (void) openUpdateDrives: (NSDictionary *) drives
+{
+    if( fDrives )
+    {
+        [fDrives release];
+    }
+    fDrives = [[NSDictionary alloc] initWithDictionary: drives];
+
+    NSString * device;
+    NSEnumerator * enumerator = [fDrives keyEnumerator];
+    [fOpenPopUp removeAllItems];
+    while( ( device = [enumerator nextObject] ) )
+    {
+        [fOpenPopUp addItemWithTitle: device];
+    }
+
+    if( ![fOpenPopUp numberOfItems] )
+    {
+        [fOpenPopUp addItemWithTitle: INSERT_STRING];
+    }
+    [fOpenPopUp selectItemAtIndex: 0];
+    if( [fOpenMatrix isEnabled] )
+    {
+        [self openEnable: YES];
+    }
+}
+
 - (void) openBrowseDidEnd: (NSOpenPanel *) sheet returnCode: (int)
     returnCode contextInfo: (void *) contextInfo
 {
         [fOpenFolderString release];
     fOpenFolderString = [[[sheet filenames] objectAtIndex: 0] retain];
     [fOpenFolderField setStringValue: [fOpenFolderString lastPathComponent]];
+    [self openGo: self];
 }
 
 - (void) openEnable: (BOOL) b
         {
             [fOpenFolderField  setEnabled: NO];
             [fOpenBrowseButton setEnabled: NO];
+            if( [[fOpenPopUp titleOfSelectedItem]
+                    isEqualToString: INSERT_STRING] )
+            {
+                [fOpenGoButton setEnabled: NO];
+            }
         }
     }
 }
             {
                 [self convertShow];
             }
+            else
+            {
+                [fDriveDetector run];
+            }
             break;
 
         default:
 
 - (void) convertShow
 {
-    int i;
+    int i, j;
 
     fConvertCheckArray = [[NSMutableArray alloc] initWithCapacity:
         hb_list_count( fList )];
+    [fConvertAudioPopUp removeAllItems];
+    [fConvertSubtitlePopUp removeAllItems];
+    [fConvertSubtitlePopUp addItemWithTitle: @"None"];
     for( i = 0; i < hb_list_count( fList ); i++ )
     {
         /* Default is to convert titles longer than 30 minutes. */
         hb_title_t * title = hb_list_item( fList, i );
         [fConvertCheckArray addObject: [NSNumber numberWithBool:
             ( 60 * title->hours + title->minutes > 30 )]];
+
+        /* Update audio popup */
+        hb_audio_t * audio;
+        for( j = 0; j < hb_list_count( title->list_audio ); j++ )
+        {
+            audio = hb_list_item( title->list_audio, j );
+            [fConvertAudioPopUp addItemWithTitle:
+                [NSString stringWithUTF8String: audio->lang_simple]];
+        }
+               [fConvertAudioPopUp selectItemWithTitle: @"English"];
+
+        /* Update subtitle popup */
+        hb_subtitle_t * subtitle;
+        for( j = 0; j < hb_list_count( title->list_subtitle ); j++ )
+        {
+            subtitle = hb_list_item( title->list_subtitle, j );
+            [fConvertSubtitlePopUp addItemWithTitle:
+                [NSString stringWithUTF8String: subtitle->lang]];
+        }
     }
     [fConvertTableView reloadData];
 
     [image16 unlockFocus];                                                      
     [item setImage: image16];
     [image16 release];
+
+    [self convertEnable: YES];
+}
+
+- (void) convertEnable: (BOOL) b
+{
+    [fConvertTableView setEnabled: b];
+    [fConvertFolderPopUp setEnabled: b];
+    [fConvertFormatPopUp setEnabled: b];
+    [fConvertAspectPopUp setEnabled: b];
+    [fConvertMaxWidthPopUp setEnabled: b];
+    [fConvertAudioPopUp setEnabled: b];
+    [fConvertSubtitlePopUp setEnabled: b];
+    [fConvertOpenButton setEnabled: b];
+    if( b )
+    {
+        [fConvertGoButton setTitle: @"Convert"];
+        [fConvertGoButton setAction: @selector(convertGo:)];
+    }
+    else
+    {
+        [fConvertGoButton setTitle: @"Cancel"];
+        [fConvertGoButton setAction: @selector(convertCancel:)];
+    }
+}
+
+/***********************************************************************
+* UpdateDockIcon
+***********************************************************************
+* Shows a progression bar on the dock icon, filled according to
+* 'progress' (0.0 <= progress <= 1.0).
+* Called with progress < 0.0 or progress > 1.0, restores the original
+* icon.
+**********************************************************************/
+- (void) UpdateDockIcon: (float) progress
+{
+    NSImage * icon;
+    NSData * tiff;
+    NSBitmapImageRep * bmp;
+    uint32_t * pen;
+    uint32_t black = htonl( 0x000000FF );
+    uint32_t red   = htonl( 0xFF0000FF );
+    uint32_t white = htonl( 0xFFFFFFFF );
+    int row_start, row_end;
+    int i, j;
+       
+    /* Get application original icon */
+    icon = [NSImage imageNamed: @"NSApplicationIcon"];
+       
+    if( progress < 0.0 || progress > 1.0 )
+    {
+        [NSApp setApplicationIconImage: icon];
+        return;
+    }
+       
+    /* Get it in a raw bitmap form */
+    tiff = [icon TIFFRepresentationUsingCompression:
+                                          NSTIFFCompressionNone factor: 1.0];
+    bmp = [NSBitmapImageRep imageRepWithData: tiff];
+    
+    /* Draw the progression bar */
+    /* It's pretty simple (ugly?) now, but I'm no designer */
+       
+    row_start = 3 * (int) [bmp size].height / 4;
+    row_end   = 7 * (int) [bmp size].height / 8;
+       
+    for( i = row_start; i < row_start + 2; i++ )
+    {
+        pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
+        for( j = 0; j < (int) [bmp size].width; j++ )
+        {
+            pen[j] = black;
+        }
+    }
+    for( i = row_start + 2; i < row_end - 2; i++ )
+    {
+        pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
+        pen[0] = black;
+        pen[1] = black;
+        for( j = 2; j < (int) [bmp size].width - 2; j++ )
+        {
+            if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) )
+            {
+                pen[j] = red;
+            }
+            else
+            {
+                pen[j] = white;
+            }
+        }
+        pen[j]   = black;
+        pen[j+1] = black;
+    }
+    for( i = row_end - 2; i < row_end; i++ )
+    {
+        pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
+        for( j = 0; j < (int) [bmp size].width; j++ )
+        {
+            pen[j] = black;
+        }
+    }
+       
+    /* Now update the dock icon */
+    tiff = [bmp TIFFRepresentationUsingCompression:
+                                         NSTIFFCompressionNone factor: 1.0];
+    icon = [[NSImage alloc] initWithData: tiff];
+    [NSApp setApplicationIconImage: icon];
+    [icon release];
 }
 
 - (void) convertTimer: (NSTimer *) timer
     {
 #define p s.param.working
         case HB_STATE_WORKING:
+        {
+            float progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
+            NSMutableString * string = [NSMutableString
+                stringWithFormat: @"Converting: %.1f %%",
+                100.0 * progress_total];
+            if( p.seconds > -1 )
+            {
+                [string appendFormat: @" (%.1f fps, ", p.rate_avg];
+                if( p.hours > 0 )
+                {
+                    [string appendFormat: @"%d hour%s %d min%s",
+                        p.hours, p.hours == 1 ? "" : "s",
+                        p.minutes, p.minutes == 1 ? "" : "s"];
+                }
+                else if( p.minutes > 0 )
+                {
+                    [string appendFormat: @"%d min%s %d sec%s",
+                        p.minutes, p.minutes == 1 ? "" : "s",
+                        p.seconds, p.seconds == 1 ? "" : "s"];
+                }
+                else
+                {
+                    [string appendFormat: @"%d second%s",
+                        p.seconds, p.seconds == 1 ? "" : "s"];
+                }
+                [string appendString: @" left)"];
+            }
+            [fConvertInfoString setStringValue: string];
             [fConvertIndicator setIndeterminate: NO];
-            [fConvertIndicator setDoubleValue: 100.0 * p.progress];
+            [fConvertIndicator setDoubleValue: 100.0 * progress_total];
+            [self UpdateDockIcon: progress_total];
+                       break;
+        }
+#undef p
+
+#define p s.param.muxing
+        case HB_STATE_MUXING:
+        {
+            NSMutableString * string = [NSMutableString
+                stringWithFormat: @"Muxing..."];
+            [fConvertInfoString setStringValue: string];
+            [fConvertIndicator setIndeterminate: YES];
+            [fConvertIndicator startAnimation: nil];
+            [self UpdateDockIcon: 1.0];
             break;
+        }
 #undef p
 
         case HB_STATE_WORKDONE:
-            [timer invalidate];
+               {
+                       [timer invalidate];
             [fConvertIndicator setIndeterminate: NO];
             [fConvertIndicator setDoubleValue: 0.0];
-            break;
+            [self UpdateDockIcon: -1.0];
+            [self convertEnable: YES];
+                       
+#define p s.param.workdone
+                       switch(p.error)
+                       {
+                               case HB_ERROR_NONE:
+                                       [fConvertInfoString setStringValue: @"Done."];
+                                       break;
+                               case HB_ERROR_CANCELED:
+                                       [fConvertInfoString setStringValue: @"Canceled."];
+                                       break;
+                               case HB_ERROR_UNKNOWN:
+                                       [fConvertInfoString setStringValue: @"Unknown Error."];
+                                       break;
+                       }
+#undef p
 
+                       hb_job_t * job;
+            while( ( job = hb_job( fHandle, 0 ) ) )
+            {
+                hb_rem( fHandle, job );
+            }
+                       break;
+               }
         default:
             break;
     }