X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=macosx%2FHBPreviewController.m;h=4b60d7e4ae45989c7ab385b9720c04a8b52d222a;hb=23de4c1438ad602f8076e3a059a124cec632d1cb;hp=764da459d7deed8381f2063ab74b7b1a47f70e63;hpb=1a0570e11dffce6dbf9d9caeea353de670e6805c;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/macosx/HBPreviewController.m b/macosx/HBPreviewController.m index 764da459..4b60d7e4 100644 --- a/macosx/HBPreviewController.m +++ b/macosx/HBPreviewController.m @@ -14,6 +14,8 @@ } @end + + @interface PreviewController (Private) - (NSSize)optimalViewSizeForImageSize: (NSSize)imageSize; @@ -44,12 +46,13 @@ int loggingLevel = [[[NSUserDefaults standardUserDefaults] objectForKey:@"LoggingLevel"] intValue]; fPreviewLibhb = hb_init(loggingLevel, 0); + + } return self; } - //------------------------------------------------------------------------------------ // Displays and brings the picture window to the front //------------------------------------------------------------------------------------ @@ -130,6 +133,8 @@ // Show the picture view [fPictureView setHidden:NO]; [fMovieView pause:nil]; + [fMovieTimer invalidate]; + [fMovieTimer release]; [fMovieView setHidden:YES]; [fMovieView setMovie:nil]; @@ -157,11 +162,16 @@ [fHudTimer invalidate]; [fHudTimer release]; + [fMovieTimer invalidate]; + [fMovieTimer release]; + [fPicturePreviews release]; [fFullScreenWindow release]; hb_close(&fPreviewLibhb); - + + [self removeMovieCallbacks]; + [super dealloc]; } @@ -213,12 +223,6 @@ MaxOutputHeight = title->height - job->crop[0] - job->crop[1]; [self SettingsChanged: nil]; - - /* set the top of the hud controller boxes centered vertically with the origin of our window */ - NSPoint hudControlBoxOrigin = [fPictureControlBox frame].origin; - hudControlBoxOrigin.y = ([[self window] frame].size.height / 2) - [fPictureControlBox frame].size.height; - [fPictureControlBox setFrameOrigin:hudControlBoxOrigin]; - [fEncodingControlBox setFrameOrigin:hudControlBoxOrigin]; } @@ -232,11 +236,15 @@ /* lets make sure that the still picture view is not hidden and that * the movie preview is */ + aMovie = nil; [fMovieView pause:nil]; [fMovieView setHidden:YES]; [fMovieView setMovie:nil]; [fMovieCreationProgressIndicator stopAnimation: nil]; [fMovieCreationProgressIndicator setHidden: YES]; + [fMoviePlaybackControlBox setHidden: YES]; + [self stopMovieTimer]; + [fPictureControlBox setHidden: NO]; [fPictureView setHidden:NO]; @@ -378,6 +386,15 @@ } [self setViewSize:viewSize]; + + /* relocate our hud origins as per setViewSize */ + NSPoint hudControlBoxOrigin = [fPictureControlBox frame].origin; + hudControlBoxOrigin.y = ([[self window] frame].size.height / 2) - (viewSize.height / 2); + hudControlBoxOrigin.x = ([[self window] frame].size.width / 2) - ([fPictureControlBox frame].size.width / 2); + [fPictureControlBox setFrameOrigin:hudControlBoxOrigin]; + [fEncodingControlBox setFrameOrigin:hudControlBoxOrigin]; + [fMoviePlaybackControlBox setFrameOrigin:hudControlBoxOrigin]; + NSString *scaleString; CGFloat scale = ( ( CGFloat )[fPictureView frame].size.width) / ( ( CGFloat )imageScaledSize.width); @@ -473,19 +490,35 @@ NSPoint mouseLoc = [theEvent locationInWindow]; /* Test for mouse location to show/hide hud controls */ - if( isEncoding == NO ) { + if( isEncoding == NO ) + { + /* Since we are not encoding, verify which control hud to show + * or hide based on aMovie ( aMovie indicates we need movie controls ) + */ + NSBox * hudBoxToShow; + if ( aMovie == nil ) // No movie loaded up + { + hudBoxToShow = fPictureControlBox; + } + else // We have a movie + { + hudBoxToShow = fMoviePlaybackControlBox; + } + if( NSPointInRect( mouseLoc, [fPictureControlBox frame] ) ) { - [[fPictureControlBox animator] setHidden: NO]; + [[hudBoxToShow animator] setHidden: NO]; [self stopHudTimer]; } else if( NSPointInRect( mouseLoc, [fPictureViewArea frame] ) ) { - [[fPictureControlBox animator] setHidden: NO]; + [[hudBoxToShow animator] setHidden: NO]; [self startHudTimer]; } else - [[fPictureControlBox animator] setHidden: YES]; + { + [[hudBoxToShow animator] setHidden: YES]; + } } } @@ -513,8 +546,13 @@ - (void) hudTimerFired: (NSTimer*)theTimer { hudTimerSeconds++; - if( hudTimerSeconds >= 10 ) { + if( hudTimerSeconds >= 10 ) + { + /* Regardless which control box is active, after the timer + * period we want either one to fade to hidden. + */ [[fPictureControlBox animator] setHidden: YES]; + [[fMoviePlaybackControlBox animator] setHidden: YES]; [self stopHudTimer]; } } @@ -923,6 +961,7 @@ [fMovieCreationProgressIndicator stopAnimation: nil]; [fMovieCreationProgressIndicator setHidden: YES]; [fEncodingControlBox setHidden: YES]; + [fPictureControlBox setHidden: YES]; isEncoding = NO; // Show the movie view @@ -934,6 +973,103 @@ } } +- (IBAction) toggleMoviePreviewPlayPause: (id) sender +{ + /* make sure a movie is even loaded up */ + if (aMovie != nil) + { + /* For some stupid reason there is no "isPlaying" method for a QTMovie + * object, given that, we detect the rate to determine whether the movie + * is playing or not. + */ + if ([aMovie rate] != 0) // we are playing + { + [fMovieView pause:aMovie]; + [fPlayPauseButton setTitle: @">"]; + } + else // we are paused or stopped + { + [fMovieView play:aMovie]; + [fPlayPauseButton setTitle: @"||"]; + } + } + +} + +- (IBAction) moviePlaybackGoToBeginning: (id) sender +{ + /* make sure a movie is even loaded up */ + if (aMovie != nil) + { + [fMovieView gotoBeginning:aMovie]; + } + +} + +- (IBAction) moviePlaybackGoToEnd: (id) sender +{ + /* make sure a movie is even loaded up */ + if (aMovie != nil) + { + [fMovieView gotoEnd:aMovie]; + } + +} + +- (IBAction) moviePlaybackGoBackwardOneFrame: (id) sender +{ + /* make sure a movie is even loaded up */ + if (aMovie != nil) + { + [fMovieView pause:aMovie]; // Pause the movie + [fMovieView stepBackward:aMovie]; + } + +} + +- (IBAction) moviePlaybackGoForwardOneFrame: (id) sender +{ + /* make sure a movie is even loaded up */ + if (aMovie != nil) + { + [fMovieView pause:aMovie]; // Pause the movie + [fMovieView stepForward:aMovie]; + } + +} + + +- (void) startMovieTimer +{ + if( fMovieTimer ) { + [fMovieTimer invalidate]; + [fMovieTimer release]; + } + fMovieTimer = [NSTimer scheduledTimerWithTimeInterval:0.10 target:self selector:@selector(movieTimerFired:) userInfo:nil repeats:YES]; + [fMovieTimer retain]; +} + +- (void) stopMovieTimer +{ + if( fMovieTimer ) + { + [fMovieTimer invalidate]; + [fMovieTimer release]; + fMovieTimer = nil; + } +} + +- (void) movieTimerFired: (NSTimer*)theTimer +{ + if (aMovie != nil) + { + [self adjustPreviewScrubberForCurrentMovieTime]; + [fMovieInfoField setStringValue: [NSString stringWithFormat:NSLocalizedString( @"%@", @"" ),[self calculatePlaybackSMTPETimecodeForDisplay]]]; + } +} + + + - (IBAction) showMoviePreview: (NSString *) path { /* Since the gray background for the still images is part of @@ -946,7 +1082,7 @@ /* Load the new movie into fMovieView */ if (path) { - QTMovie * aMovie; + //QTMovie * aMovie; NSError *outError; NSURL *movieUrl = [NSURL fileURLWithPath:path]; NSDictionary *movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys: @@ -955,11 +1091,13 @@ [NSNumber numberWithBool:YES], @"QTMovieOpenForPlaybackAttribute", [NSNumber numberWithBool:NO], @"QTMovieOpenAsyncRequiredAttribute", [NSNumber numberWithBool:NO], @"QTMovieOpenAsyncOKAttribute", + [NSNumber numberWithBool:YES], @"QTMovieIsSteppableAttribute", QTMovieApertureModeClean, QTMovieApertureModeAttribute, nil]; aMovie = [[[QTMovie alloc] initWithAttributes:movieAttributes error:&outError] autorelease]; + if (!aMovie) { NSLog(@"Unable to open movie"); @@ -973,6 +1111,7 @@ movieBounds.size.height = movieSize.height; /* We also get our view size to use for scaling fMovieView's size */ NSSize scaledMovieViewSize = [fPictureView frame].size; + [fMovieView setControllerVisible:FALSE]; if ([fMovieView isControllerVisible]) { CGFloat controllerBarHeight = [fMovieView controllerBarHeight]; @@ -994,23 +1133,6 @@ if (scaledMovieViewSize.height > [[self window] frame].size.height) { [fHBController writeToActivityLog: "showMoviePreview: Our window is not tall enough to show the controller bar ..."]; - /*we need to scale the movie down vertically by 15 px to allow for the controller bar - * and scale the width accordingly. - */ - - // FIX ME: currently trying to scale everything to show the controller bar does not work right. - // Commented out til fixed, resulting issue when the movie is the full size of the window is no - // controller bar is visible. Live Preview still plays fine though. - /* - CGFloat pictureAspectRatio = scaledMovieViewSize.width / scaledMovieViewSize.height; - scaledMovieViewSize.height = [[self window] frame].size.height - 15; - scaledMovieViewSize.width = scaledMovieViewSize.height * pictureAspectRatio; - NSRect windowFrame = [[self window] frame]; - windowFrame.size.width = scaledMovieViewSize.width; - windowFrame.size.height = scaledMovieViewSize.height + 15; - [[self window] setFrame:windowFrame display:YES animate:YES]; - [fPictureView setFrameSize:scaledMovieViewSize]; - */ } @@ -1028,12 +1150,193 @@ [fMovieView setFrameOrigin:origin]; [fMovieView setMovie:aMovie]; [fMovieView setHidden:NO]; + [fMoviePlaybackControlBox setHidden: NO]; + [fPictureControlBox setHidden: YES]; + // to actually play the movie + + [self initPreviewScrubberForMovie]; + [self startMovieTimer]; + /* Install amovie notifications */ + [aMovie setDelegate:self]; + [self installMovieCallbacks]; [fMovieView play:aMovie]; + } } isEncoding = NO; } +#pragma mark *** Movie Playback Scrubber and time code methods *** + +/* Since MacOSX Leopard QTKit has taken over some responsibility for assessing movie playback + * information from the old QuickTime carbon api ( time code information as well as fps, etc.). + * However, the QTKit devs at apple were not really big on documentation and further ... + * QuickTimes ability to playback HB's largely variable framerate output makes perfectly frame + * accurate information at best convoluted. Still, for the purpose of a custom hud based custom + * playback scrubber slider this has so far proven to be as accurate as I have found. To say it + * could use some better accuracy is not understating it enough probably. + * Most of this was gleaned from this obscure Apple Mail list thread: + * http://www.mailinglistarchive.com/quicktime-api@lists.apple.com/msg05642.html + * Now as we currently do not show a QTKit control bar with scrubber for display sizes > container + * size, this seems to facilitate playback control from the HB custom HUD controller fairly close + * to the built in controller bar. + * Further work needs to be done to try to get accurate frame by frame playback display if we want it. + * Note that the keyboard commands for frame by frame step through etc. work as always. + */ + +// Returns a human readable string from the currentTime of movie playback +- (NSString*) calculatePlaybackSMTPETimecodeForDisplay +{ + QTTime time = [aMovie currentTime]; + + NSString *smtpeTimeCodeString; + int days, hour, minute, second, frame; + long long result; + + result = time.timeValue / time.timeScale; // second + frame = (time.timeValue % time.timeScale) / 100; + + second = result % 60; + + result = result / 60; // minute + minute = result % 60; + + result = result / 60; // hour + hour = result % 24; + days = result; + + smtpeTimeCodeString = [NSString stringWithFormat:@"Time: %02d:%02d:%02d", hour, minute, second]; // hh:mm:ss + return smtpeTimeCodeString; + +} + + +// Initialize the preview scrubber min/max to appropriate values for the current movie +-(void) initPreviewScrubberForMovie +{ + if (aMovie) + { + + QTTime duration = [aMovie duration]; + float result = duration.timeValue / duration.timeScale; + + [fMovieScrubberSlider setMinValue:0.0]; + [fMovieScrubberSlider setMaxValue: (float)result]; + [fMovieScrubberSlider setFloatValue: 0.0]; + } +} + + +-(void) adjustPreviewScrubberForCurrentMovieTime +{ + if (aMovie) + { + QTTime time = [aMovie currentTime]; + + float result = (float)time.timeValue / (float)time.timeScale;; + [fMovieScrubberSlider setFloatValue:result]; + } +} + +- (IBAction) previewScrubberChanged: (id) sender +{ + if (aMovie) + { + [fMovieView pause:aMovie]; // Pause the movie + QTTime time = [aMovie currentTime]; + [self setTime: time.timeScale * [fMovieScrubberSlider floatValue]]; + [self calculatePlaybackSMTPETimecodeForDisplay]; + } +} +#pragma mark *** Movie Notifications *** + +- (void) installMovieCallbacks +{ + + +/*Notification for any time the movie rate changes */ + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(movieRateDidChange:) + name:@"QTMovieRateDidChangeNotification" + object:aMovie]; + /*Notification for when the movie ends */ + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(movieDidEnd:) + name:@"QTMovieDidEndNotification" + object:aMovie]; +} + +- (void)removeMovieCallbacks +{ + if (aMovie) + { + /*Notification for any time the movie rate changes */ + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"QTMovieRateDidChangeNotification" + object:aMovie]; + /*Notification for when the movie ends */ + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"QTMovieDidEndNotification" + object:aMovie]; + } +} + +- (void)movieRateDidChange:(NSNotification *)notification +{ + if (aMovie != nil) + { + /* For some stupid reason there is no "isPlaying" method for a QTMovie + * object, given that, we detect the rate to determine whether the movie + * is playing or not. + */ + //[self adjustPreviewScrubberForCurrentMovieTime]; + if ([aMovie rate] != 0) // we are playing + { + [fPlayPauseButton setTitle: @"||"]; + } + else // we are paused or stopped + { + [fPlayPauseButton setTitle: @">"]; + } + } +} +/* This notification is not currently used. However we should keep it "just in case" as + * live preview playback is enhanced. + */ +- (void)movieDidEnd:(NSNotification *)notification +{ + + //[fHBController writeToActivityLog: "Movie DidEnd Notification Received"]; +} + + +#pragma mark *** QTTime Utilities *** + + // convert a time value (long) to a QTTime structure +-(void)timeToQTTime:(long)timeValue resultTime:(QTTime *)aQTTime +{ + NSNumber *timeScaleObj; + long timeScaleValue; + + timeScaleObj = [aMovie attributeForKey:QTMovieTimeScaleAttribute]; + timeScaleValue = [timeScaleObj longValue]; + + *aQTTime = QTMakeTime(timeValue, timeScaleValue); +} + + // set the movie's current time +-(void)setTime:(int)timeValue +{ + QTTime movieQTTime; + NSValue *valueForQTTime; + + [self timeToQTTime:timeValue resultTime:&movieQTTime]; + + valueForQTTime = [NSValue valueWithQTTime:movieQTTime]; + + [aMovie setAttribute:valueForQTTime forKey:QTMovieCurrentTimeAttribute]; +} + @end