From a6ff6f6faaa80c1876e29f621183c592c5e61f43 Mon Sep 17 00:00:00 2001 From: ritsuka Date: Sat, 29 Aug 2009 07:00:01 +0000 Subject: MacGUI: Renamed HBPreviewController.mm to HBPreviewController.m to enable the new clang static analyzer goodness, there was no reason for this file to use Objective-C++ git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@2788 b64f7644-9d1e-0410-96f1-a4d463321fa5 --- macosx/HBPreviewController.h | 2 +- macosx/HBPreviewController.m | 1325 ++++++++++++++++++++++++++++ macosx/HBPreviewController.mm | 1324 --------------------------- macosx/HandBrake.xcodeproj/project.pbxproj | 8 +- 4 files changed, 1330 insertions(+), 1329 deletions(-) create mode 100644 macosx/HBPreviewController.m delete mode 100644 macosx/HBPreviewController.mm diff --git a/macosx/HBPreviewController.h b/macosx/HBPreviewController.h index 6edddeaba..df5cf2b1c 100644 --- a/macosx/HBPreviewController.h +++ b/macosx/HBPreviewController.h @@ -96,7 +96,7 @@ - (void) stopReceivingLibhbNotifications; - (IBAction) createMoviePreview: (id) sender; -- (void) libhbStateChanged: (hb_state_t &) state; +- (void) libhbStateChanged: (hb_state_t ) state; - (IBAction) showMoviePreview: (NSString *) path; - (IBAction) previewDurationPopUpChanged: (id) sender; diff --git a/macosx/HBPreviewController.m b/macosx/HBPreviewController.m new file mode 100644 index 000000000..5397fe5d6 --- /dev/null +++ b/macosx/HBPreviewController.m @@ -0,0 +1,1325 @@ +/* $Id: HBPreviewController.mm,v 1.11 2005/08/01 15:10:44 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: . + It may be used under the terms of the GNU General Public License. */ + +#import "HBPreviewController.h" +#import "Controller.h" + +@implementation QTMovieView ( HBQTkitExt ) +- (void) mouseMoved:(NSEvent *)theEvent +{ + [super mouseMoved:theEvent]; +} +@end + +@interface PreviewController (Private) + +- (NSSize)optimalViewSizeForImageSize: (NSSize)imageSize; +- (void)resizeSheetForViewSize: (NSSize)viewSize; +- (void)setViewSize: (NSSize)viewSize; +- (BOOL)viewNeedsToResizeToSize: (NSSize)newSize; + +@end + +@implementation PreviewController + +- (id)init +{ + if (self = [super initWithWindowNibName:@"PicturePreview"]) + { + // NSWindowController likes to lazily load its window. However since + // this controller tries to set all sorts of outlets before the window + // is displayed, we need it to load immediately. The correct way to do + // this, according to the documentation, is simply to invoke the window + // getter once. + // + // If/when we switch a lot of this stuff to bindings, this can probably + // go away. + [self window]; + + fPicturePreviews = [[NSMutableDictionary dictionaryWithCapacity: HB_NUM_HBLIB_PICTURES] retain]; + /* Init libhb with check for updates libhb style set to "0" so its ignored and lets sparkle take care of it */ + int loggingLevel = [[[NSUserDefaults standardUserDefaults] objectForKey:@"LoggingLevel"] intValue]; + fPreviewLibhb = hb_init(loggingLevel, 0); + + } + return self; +} + + + +//------------------------------------------------------------------------------------ +// Displays and brings the picture window to the front +//------------------------------------------------------------------------------------ +- (IBAction) showPreviewWindow: (id)sender +{ + [self showWindow:sender]; + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"PreviewWindowIsOpen"]; + + /* lets set the preview window to accept mouse moved events */ + [fPreviewWindow setAcceptsMouseMovedEvents:YES]; + hudTimerSeconds = 0; + [self pictureSliderChanged:nil]; + [self startReceivingLibhbNotifications]; +} + +- (void)setHBController: (HBController *)controller +{ + fHBController = controller; +} + +- (void)awakeFromNib +{ + [fPreviewWindow setDelegate:self]; + if( ![[self window] setFrameUsingName:@"Preview"] ) + [[self window] center]; + [self setWindowFrameAutosaveName:@"Preview"]; + [[self window] setExcludedFromWindowsMenu:YES]; + + /* lets set the preview window to accept mouse moved events */ + [fPreviewWindow setAcceptsMouseMovedEvents:YES]; + //[self pictureSliderChanged:nil]; + [self startReceivingLibhbNotifications]; + + isFullScreen = NO; + hudTimerSeconds = 0; + /* we set the progress indicator to not use threaded animation + * as it causes a conflict with the qtmovieview's controllerbar + */ + [fMovieCreationProgressIndicator setUsesThreadedAnimation:NO]; + + /* Setup our layers for core animation */ + [fPictureViewArea setWantsLayer:YES]; + [fPictureView setWantsLayer:YES]; + + [fCancelPreviewMovieButton setWantsLayer:YES]; + [fMovieCreationProgressIndicator setWantsLayer:YES]; + + [fPictureControlBox setWantsLayer:YES]; + [fEncodingControlBox setWantsLayer:YES]; + [fMovieView setWantsLayer:YES]; + [fMovieView setHidden:YES]; + [fMovieView setDelegate:self]; + + /* Since the xib has everything off center for easy acess + * we align our views and windows here we an align to anything + * since it will actually change later upon source load, but + * for convenience we will use the fPictureViewArea + */ + + /* Align the still preview image view to the picture box */ + [fPictureView setFrameSize:[fPictureViewArea frame].size]; + [fMovieView setFrameSize:[fPictureViewArea frame].size]; + //[fPreviewWindow setFrameSize:[fPictureViewArea frame].size]; + + +} +- (BOOL)acceptsMouseMovedEvents +{ + return YES; +} + +- (void)windowWillClose:(NSNotification *)aNotification +{ + /* Upon Closing the picture window, we make sure we clean up any + * preview movie that might be playing + */ + hb_stop( fPreviewLibhb ); + isEncoding = NO; + // Show the picture view + [fPictureView setHidden:NO]; + [fMovieView pause:nil]; + [fMovieView setHidden:YES]; + [fMovieView setMovie:nil]; + + isFullScreen = NO; + hudTimerSeconds = 0; + [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"PreviewWindowIsOpen"]; +} + +- (BOOL)windowShouldClose:(id)fPictureWindow +{ + return YES; +} + +- (void) dealloc +{ + hb_stop(fPreviewLibhb); + if (fPreviewMoviePath) + { + [[NSFileManager defaultManager] removeFileAtPath:fPreviewMoviePath handler:nil]; + [fPreviewMoviePath release]; + } + + [fLibhbTimer invalidate]; + [fLibhbTimer release]; + + [fHudTimer invalidate]; + [fHudTimer release]; + + [fPicturePreviews release]; + [fFullScreenWindow release]; + + [super dealloc]; +} + +- (void) SetHandle: (hb_handle_t *) handle +{ + fHandle = handle; + + + + /* we set the preview length popup in seconds */ + [fPreviewMovieLengthPopUp removeAllItems]; + [fPreviewMovieLengthPopUp addItemWithTitle: @"5"]; + [fPreviewMovieLengthPopUp addItemWithTitle: @"10"]; + [fPreviewMovieLengthPopUp addItemWithTitle: @"15"]; + [fPreviewMovieLengthPopUp addItemWithTitle: @"20"]; + [fPreviewMovieLengthPopUp addItemWithTitle: @"25"]; + [fPreviewMovieLengthPopUp addItemWithTitle: @"30"]; + [fPreviewMovieLengthPopUp addItemWithTitle: @"35"]; + [fPreviewMovieLengthPopUp addItemWithTitle: @"40"]; + [fPreviewMovieLengthPopUp addItemWithTitle: @"45"]; + [fPreviewMovieLengthPopUp addItemWithTitle: @"50"]; + [fPreviewMovieLengthPopUp addItemWithTitle: @"55"]; + [fPreviewMovieLengthPopUp addItemWithTitle: @"60"]; + + /* adjust the preview slider length */ + /* We use our advance pref to determine how many previews we scanned */ + int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue]; + [fPictureSlider setMaxValue: hb_num_previews - 1.0]; + [fPictureSlider setNumberOfTickMarks: hb_num_previews]; + + if ([[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewLength"]) + { + [fPreviewMovieLengthPopUp selectItemWithTitle:[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewLength"]]; + } + else + { + /* currently hard set default to 10 seconds */ + [fPreviewMovieLengthPopUp selectItemAtIndex: 1]; + } +} + +- (void) SetTitle: (hb_title_t *) title +{ + hb_job_t * job = title->job; + + fTitle = title; + fPicture = 0; + MaxOutputWidth = title->width - job->crop[2] - job->crop[3]; + MaxOutputHeight = title->height - job->crop[0] - job->crop[1]; + [self SettingsChanged: nil]; +} + + + +// Adjusts the window to draw the current picture (fPicture) adjusting its size as +// necessary to display as much of the picture as possible. +- (void) displayPreview +{ + hb_job_t * job = fTitle->job; + /* lets make sure that the still picture view is not hidden and that + * the movie preview is + */ + [fMovieView pause:nil]; + [fMovieView setHidden:YES]; + [fMovieView setMovie:nil]; + [fMovieCreationProgressIndicator stopAnimation: nil]; + [fMovieCreationProgressIndicator setHidden: YES]; + + [fPictureView setHidden:NO]; + + //[fHBController writeToActivityLog: "displayPreview called"]; + + NSImage *fPreviewImage = [self imageForPicture: fPicture]; + NSSize imageScaledSize = [fPreviewImage size]; + [fPictureView setImage: fPreviewImage]; + + NSSize displaySize = NSMakeSize( ( CGFloat )fTitle->width, ( CGFloat )fTitle->height ); + NSString *sizeInfoString; + /* Set the picture size display fields below the Preview Picture*/ + if( fTitle->job->anamorphic.mode == 1 ) // Original PAR Implementation + { + output_width = fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3]; + output_height = fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1]; + display_width = output_width * fTitle->job->anamorphic.par_width / fTitle->job->anamorphic.par_height; + sizeInfoString = [NSString stringWithFormat: + @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d Strict", + fTitle->width, fTitle->height, output_width, output_height, display_width, output_height]; + + displaySize.width = display_width; + displaySize.height = fTitle->height; + imageScaledSize.width = display_width; + imageScaledSize.height = output_height; + } + else if (fTitle->job->anamorphic.mode == 2) // Loose Anamorphic + { + hb_set_anamorphic_size(job, &output_width, &output_height, &output_par_width, &output_par_height); + display_width = output_width * output_par_width / output_par_height; + sizeInfoString = [NSString stringWithFormat: + @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d Loose", + fTitle->width, fTitle->height, output_width, output_height, display_width, output_height]; + + displaySize.width = display_width; + displaySize.height = fTitle->height; + imageScaledSize.width = display_width; + imageScaledSize.height = output_height; + } + else if (fTitle->job->anamorphic.mode == 3) // Custom Anamorphic + { + hb_set_anamorphic_size(job, &output_width, &output_height, &output_par_width, &output_par_height); + display_width = output_width * output_par_width / output_par_height; + sizeInfoString = [NSString stringWithFormat: + @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d Custom", + fTitle->width, fTitle->height, output_width, output_height, fTitle->job->anamorphic.dar_width, fTitle->job->anamorphic.dar_height]; + + displaySize.width = fTitle->job->anamorphic.dar_width + fTitle->job->crop[2] + fTitle->job->crop[3]; + displaySize.height = fTitle->job->anamorphic.dar_height + fTitle->job->crop[0] + fTitle->job->crop[1]; + imageScaledSize.width = (int)fTitle->job->anamorphic.dar_width; + imageScaledSize.height = (int)fTitle->job->height; + } + else // No Anamorphic + { + sizeInfoString = [NSString stringWithFormat: + @"Source: %dx%d, Output: %dx%d", fTitle->width, fTitle->height, + fTitle->job->width, fTitle->job->height]; + + displaySize.width = fTitle->width; + displaySize.height = fTitle->height; + imageScaledSize.width = fTitle->job->width; + imageScaledSize.height = fTitle->job->height; + } + + NSSize viewSize = [self optimalViewSizeForImageSize:displaySize]; + + /* Initially set our preview image here */ + /* + if (scaleToScreen == YES) + { + viewSize.width = viewSize.width - (viewSize.width - imageScaledSize.width); + viewSize.height = viewSize.height - (viewSize.height - imageScaledSize.height); + [fPreviewImage setSize: viewSize]; + //[fPictureView setFrameSize: viewSize]; + } + + else + { + [fPreviewImage setSize: imageScaledSize]; + [fPictureView setFrameSize: imageScaledSize]; + } + [fPictureView setImage: fPreviewImage]; + // center it vertically and horizontally + NSPoint origin = [fPictureViewArea frame].origin; + origin.y += ([fPictureViewArea frame].size.height - + [fPictureView frame].size.height) / 2.0; + + origin.x += ([fPictureViewArea frame].size.width - + [fPictureView frame].size.width) / 2.0; + [fPictureView setFrameOrigin:origin]; + */ + /* we also need to take into account scaling to full screen to activate switching the view size */ + if( [self viewNeedsToResizeToSize:viewSize]) + { + if (fTitle->job->anamorphic.mode != 2 || (fTitle->job->anamorphic.mode == 2 && fTitle->width == fTitle->job->width)) + { + [self resizeSheetForViewSize:viewSize]; + //[self setViewSize:viewSize]; + + } + } + + viewSize.width = viewSize.width - (viewSize.width - imageScaledSize.width); + viewSize.height = viewSize.height - (viewSize.height - imageScaledSize.height); + [self setViewSize:viewSize]; + + /* special case for scaleToScreen */ + if (scaleToScreen == YES) + { + [fPreviewImage setSize: viewSize]; + [fPictureView setImage: fPreviewImage]; + } + + NSString *scaleString; + + if( imageScaledSize.height > [fPictureView frame].size.height) + { + CGFloat scale = ( ( CGFloat )[fPictureView frame].size.width) / ( ( CGFloat )imageScaledSize.width); + scaleString = [NSString stringWithFormat: + NSLocalizedString( @" (Scaled to %.0f%% actual size)", + @"String shown when a preview is scaled" ), scale * 100.0]; + } + else + { + scaleString = @""; + } + /* Set the info fields in the hud controller */ + [fInfoField setStringValue: [NSString stringWithFormat: + @"%@", sizeInfoString]]; + + [fscaleInfoField setStringValue: [NSString stringWithFormat: + @"%@", scaleString]]; + /* Set the info field in the window title bar */ + [[self window] setTitle:[NSString stringWithFormat: @"Preview - %@ %@",sizeInfoString, scaleString]]; +} + +- (IBAction) previewDurationPopUpChanged: (id) sender +{ + + [[NSUserDefaults standardUserDefaults] setObject:[fPreviewMovieLengthPopUp titleOfSelectedItem] forKey:@"PreviewLength"]; + +} + +- (IBAction) SettingsChanged: (id) sender +{ + // Purge the existing picture previews so they get recreated the next time + // they are needed. + [self purgeImageCache]; + [self pictureSliderChanged:nil]; +} + +- (IBAction) pictureSliderChanged: (id) sender +{ + // Show the picture view + [fPictureView setHidden:NO]; + [fMovieView pause:nil]; + [fMovieView setHidden:YES]; + [fMovieView setMovie:nil]; + [fEncodingControlBox setHidden: YES]; + + int newPicture = [fPictureSlider intValue]; + if (newPicture != fPicture) + { + fPicture = newPicture; + } + [self displayPreview]; + +} + +- (IBAction)showPreviewPanel: (id)sender forTitle: (hb_title_t *)title +{ + if ([fPreviewWindow isVisible]) + { + [fPreviewWindow close]; + } + else + { + [self showWindow:sender]; + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"PreviewWindowIsOpen"]; + [fPreviewWindow setAcceptsMouseMovedEvents:YES]; + isFullScreen = NO; + scaleToScreen = NO; + [self pictureSliderChanged:nil]; + } + +} + +- (NSString*) pictureSizeInfoString +{ + return [fInfoField stringValue]; +} + +- (IBAction)showPictureSettings:(id)sender +{ + [fHBController showPicturePanel:self]; +} + +#pragma mark Hud Control Overlay +- (void) mouseMoved:(NSEvent *)theEvent +{ + [super mouseMoved:theEvent]; + NSPoint mouseLoc = [theEvent locationInWindow]; + + /* Test for mouse location to show/hide hud controls */ + if( isEncoding == NO ) { + if( NSPointInRect( mouseLoc, [fPictureControlBox frame] ) ) + { + [[fPictureControlBox animator] setHidden: NO]; + [self stopHudTimer]; + } + else if( NSPointInRect( mouseLoc, [fPictureViewArea frame] ) ) + { + [[fPictureControlBox animator] setHidden: NO]; + [self startHudTimer]; + } + else + [[fPictureControlBox animator] setHidden: YES]; + } +} + +- (void) startHudTimer +{ + if( fHudTimer ) { + [fHudTimer invalidate]; + [fHudTimer release]; + } + fHudTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(hudTimerFired:) userInfo:nil repeats:YES]; + [fHudTimer retain]; +} + +- (void) stopHudTimer +{ + if( fHudTimer ) + { + [fHudTimer invalidate]; + [fHudTimer release]; + fHudTimer = nil; + hudTimerSeconds = 0; + } +} + +- (void) hudTimerFired: (NSTimer*)theTimer +{ + hudTimerSeconds++; + if( hudTimerSeconds >= 10 ) { + [[fPictureControlBox animator] setHidden: YES]; + [self stopHudTimer]; + } +} + +#pragma mark Fullscreen Mode + +- (IBAction)toggleScreenMode:(id)sender +{ + if (!isFullScreen) + { + [self goFullScreen:nil]; + } + else + { + [self goWindowedScreen:nil]; + } +} + +- (IBAction)toggleScaleToScreen:(id)sender +{ + if (scaleToScreen == YES) + { + scaleToScreen = NO; + /* make sure we are set to a still preview */ + [self pictureSliderChanged:nil]; + [fScaleToScreenToggleButton setTitle:@"<->"]; + } + else + { + scaleToScreen = YES; + /* make sure we are set to a still preview */ + [self pictureSliderChanged:nil]; + [fScaleToScreenToggleButton setTitle:@">-<"]; + } +} + +- (BOOL)fullScreen +{ + return isFullScreen; +} + +- (IBAction)goFullScreen:(id)sender +{ + // Get the screen information. + NSScreen* mainScreen = [fPreviewWindow screen]; + NSDictionary* screenInfo = [mainScreen deviceDescription]; + NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"]; + // Capture the screen. + CGDirectDisplayID displayID = (CGDirectDisplayID)[screenID longValue]; + CGDisplayErr err = CGDisplayCapture(displayID); + + if (err == CGDisplayNoErr) + { + + /* make sure we are set to a still preview and not scaled to screen */ + scaleToScreen = NO; + [self pictureSliderChanged:nil]; + + // Create the full-screen window. + //NSRect winRect = [mainScreen frame]; + //fPictureViewArea + NSRect winRect = [fPictureViewArea frame]; + + fFullScreenWindow = [[NSWindow alloc] initWithContentRect:winRect + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO + screen:mainScreen]; + + // Establish the window attributes. + [fFullScreenWindow setReleasedWhenClosed:NO]; + [fFullScreenWindow setDisplaysWhenScreenProfileChanges:YES]; + [fFullScreenWindow setDelegate:self]; + + /* insert a view into the new window */ + [fFullScreenWindow setContentView:fPictureViewArea]; + [fPictureViewArea setNeedsDisplay:YES]; + + /* Better to center the window using the screen's frame + * and the windows origin. Note that we should take into + * account the auto sizing and alignment that occurs in + * setViewSize each time the preview changes. + * Note: by using [fFullScreenWindow screen] (instead of + * [NSScreen mainScreen]) in referencing the screen + * coordinates, the full screen window will show up on + * whichever display was being used in windowed mode + * on multi-display systems + */ + + NSSize screenSize = [[fFullScreenWindow screen] frame].size; + NSSize windowSize = [fFullScreenWindow frame].size; + NSPoint windowOrigin = [fFullScreenWindow frame].origin; + + /* Adjust our origin y (vertical) based on the screen height */ + windowOrigin.y += (screenSize.height - windowSize.height) / 2.0; + windowOrigin.x += (screenSize.width - windowSize.width) / 2.0; + + [fFullScreenWindow setFrameOrigin:windowOrigin]; + + /* lets kill the timer for now */ + [self stopReceivingLibhbNotifications]; + + /* We need to retain the fPreviewWindow */ + [fPreviewWindow retain]; + + [self setWindow:fFullScreenWindow]; + + // The window has to be above the level of the shield window. + int32_t shieldLevel = CGShieldingWindowLevel(); + + [fFullScreenWindow setLevel:shieldLevel]; + + // Show the window. + [fFullScreenWindow makeKeyAndOrderFront:self]; + + + /* Change the name of fFullScreenToggleButton appropriately */ + [fFullScreenToggleButton setTitle: @"Windowed"]; + + /* Lets fire the timer back up for the hud controls, etc. */ + [self startReceivingLibhbNotifications]; + + isFullScreen = YES; + [fScaleToScreenToggleButton setHidden:NO]; + + /* make sure we are set to a still preview */ + [self pictureSliderChanged:nil]; + + [fFullScreenWindow setAcceptsMouseMovedEvents:YES]; + + + hudTimerSeconds = 0; + [self startHudTimer]; + } +} + +// Title-less windows normally don't receive key presses, override this +- (BOOL)canBecomeKeyWindow +{ + return YES; +} + +// Title-less windows normally can't become main which means that another +// non-fullscreen window will have the "active" titlebar in expose. Bad, fix it. +- (BOOL)canBecomeMainWindow +{ + return YES; +} + + +- (IBAction)goWindowedScreen:(id)sender +{ + + /* Get the screen info to release the display but don't actually do + * it until the windowed screen is setup. + */ + scaleToScreen = NO; + [self pictureSliderChanged:nil]; + [fScaleToScreenToggleButton setTitle:@"<->"]; + + NSScreen* mainScreen = [NSScreen mainScreen]; + NSDictionary* screenInfo = [mainScreen deviceDescription]; + NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"]; + CGDirectDisplayID displayID = (CGDirectDisplayID)[screenID longValue]; + + [fFullScreenWindow dealloc]; + [fFullScreenWindow release]; + + + [fPreviewWindow setContentView:fPictureViewArea]; + [fPictureViewArea setNeedsDisplay:YES]; + [self setWindow:fPreviewWindow]; + + // Show the window. + [fPreviewWindow makeKeyAndOrderFront:self]; + + /* Set the window back to regular level */ + [fPreviewWindow setLevel:NSNormalWindowLevel]; + + /* Set the isFullScreen flag back to NO */ + isFullScreen = NO; + scaleToScreen = NO; + /* make sure we are set to a still preview */ + [self pictureSliderChanged:nil]; + [self showPreviewWindow:nil]; + + /* Change the name of fFullScreenToggleButton appropriately */ + [fFullScreenToggleButton setTitle: @"Full Screen"]; + // [fScaleToScreenToggleButton setHidden:YES]; + /* set the picture settings pallete back to normal level */ + [fHBController picturePanelWindowed]; + + /* Release the display now that the we are back in windowed mode */ + CGDisplayRelease(displayID); + + [fPreviewWindow setAcceptsMouseMovedEvents:YES]; + //[fFullScreenWindow setAcceptsMouseMovedEvents:NO]; + + hudTimerSeconds = 0; + [self startHudTimer]; + +} + + +#pragma mark Still Preview Image Processing + + +// This function converts an image created by libhb (specified via pictureIndex) into +// an NSImage suitable for the GUI code to use. If removeBorders is YES, +// makeImageForPicture crops the image generated by libhb stripping off the gray +// border around the content. This is the low-level method that generates the image. +// -imageForPicture calls this function whenever it can't find an image in its cache. ++ (NSImage *) makeImageForPicture: (int)pictureIndex + libhb:(hb_handle_t*)handle + title:(hb_title_t*)title +{ + static uint8_t * buffer; + static int bufferSize; + + // Make sure we have a big enough buffer to receive the image from libhb. libhb + int dstWidth = title->job->width; + int dstHeight = title->job->height; + + int newSize; + newSize = dstWidth * dstHeight * 4; + if( bufferSize < newSize ) + { + bufferSize = newSize; + buffer = (uint8_t *) realloc( buffer, bufferSize ); + } + + hb_get_preview( handle, title, pictureIndex, buffer ); + + // Create an NSBitmapImageRep and copy the libhb image into it, converting it from + // libhb's format to one suitable for NSImage. Along the way, we'll strip off the + // border around libhb's image. + + // The image data returned by hb_get_preview is 4 bytes per pixel, BGRA format. + // Alpha is ignored. + + NSBitmapFormat bitmapFormat = (NSBitmapFormat)NSAlphaFirstBitmapFormat; + NSBitmapImageRep * imgrep = [[[NSBitmapImageRep alloc] + initWithBitmapDataPlanes:nil + pixelsWide:dstWidth + pixelsHigh:dstHeight + bitsPerSample:8 + samplesPerPixel:3 // ignore alpha + hasAlpha:NO + isPlanar:NO + colorSpaceName:NSCalibratedRGBColorSpace + bitmapFormat:bitmapFormat + bytesPerRow:dstWidth * 4 + bitsPerPixel:32] autorelease]; + + UInt32 * src = (UInt32 *)buffer; + UInt32 * dst = (UInt32 *)[imgrep bitmapData]; + int r, c; + for (r = 0; r < dstHeight; r++) + { + for (c = 0; c < dstWidth; c++) +#if TARGET_RT_LITTLE_ENDIAN + *dst++ = Endian32_Swap(*src++); +#else + *dst++ = *src++; +#endif + } + + NSImage * img = [[[NSImage alloc] initWithSize: NSMakeSize(dstWidth, dstHeight)] autorelease]; + [img addRepresentation:imgrep]; + + return img; +} + +// Returns the preview image for the specified index, retrieving it from its internal +// cache or by calling makeImageForPicture if it is not cached. Generally, you should +// use imageForPicture so that images are cached. Calling makeImageForPicture will +// always generate a new copy of the image. +- (NSImage *) imageForPicture: (int) pictureIndex +{ + // The preview for the specified index may not currently exist, so this method + // generates it if necessary. + NSString * key = [NSString stringWithFormat:@"%d", pictureIndex]; + NSImage * theImage = [fPicturePreviews objectForKey:key]; + if (!theImage) + { + theImage = [PreviewController makeImageForPicture:pictureIndex libhb:fHandle title:fTitle]; + [fPicturePreviews setObject:theImage forKey:key]; + } + return theImage; +} + +// Purges all images from the cache. The next call to imageForPicture will cause a new +// image to be generated. +- (void) purgeImageCache +{ + [fPicturePreviews removeAllObjects]; +} + + + +#pragma mark Movie Preview +- (IBAction) createMoviePreview: (id) sender +{ + + + /* Lets make sure the still picture previews are showing in case + * there is currently a movie showing */ + [self pictureSliderChanged:nil]; + + /* Rip or Cancel ? */ + hb_state_t s; + hb_get_state2( fPreviewLibhb, &s ); + + if(sender == fCancelPreviewMovieButton && (s.state == HB_STATE_WORKING || s.state == HB_STATE_PAUSED)) + { + hb_stop( fPreviewLibhb ); + [fPictureView setHidden:NO]; + [fMovieView pause:nil]; + [fMovieView setHidden:YES]; + [fMovieView setMovie:nil]; + [fPictureSlider setHidden:NO]; + isEncoding = NO; + + return; + } + + + /* we use controller.mm's prepareJobForPreview to go ahead and set all of our settings + * however, we want to use a temporary destination field of course + * so that we do not put our temp preview in the users chosen + * directory */ + + hb_job_t * job = fTitle->job; + + /* We run our current setting through prepeareJob in Controller.mm + * just as if it were a regular encode */ + + [fHBController prepareJobForPreview]; + + /* Destination file. We set this to our preview directory + * changing the extension appropriately.*/ + if (fTitle->job->mux == HB_MUX_MP4) // MP4 file + { + /* we use .m4v for our mp4 files so that ac3 and chapters in mp4 will play properly */ + fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.m4v"; + } + else if (fTitle->job->mux == HB_MUX_MKV) // MKV file + { + fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.mkv"; + } + else if (fTitle->job->mux == HB_MUX_AVI) // AVI file + { + fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.avi"; + } + else if (fTitle->job->mux == HB_MUX_OGM) // OGM file + { + fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.ogm"; + } + + fPreviewMoviePath = [[fPreviewMoviePath stringByExpandingTildeInPath]retain]; + + /* See if there is an existing preview file, if so, delete it */ + if( ![[NSFileManager defaultManager] fileExistsAtPath:fPreviewMoviePath] ) + { + [[NSFileManager defaultManager] removeFileAtPath:fPreviewMoviePath + handler:nil]; + } + + /* We now direct our preview encode to fPreviewMoviePath */ + fTitle->job->file = [fPreviewMoviePath UTF8String]; + + /* We use our advance pref to determine how many previews to scan */ + int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue]; + job->start_at_preview = fPicture + 1; + job->seek_points = hb_num_previews; + + /* we use the preview duration popup to get the specified + * number of seconds for the preview encode. + */ + + job->pts_to_stop = [[fPreviewMovieLengthPopUp titleOfSelectedItem] intValue] * 90000LL; + + /* lets go ahead and send it off to libhb + * Note: unlike a full encode, we only send 1 pass regardless if the final encode calls for 2 passes. + * this should suffice for a fairly accurate short preview and cuts our preview generation time in half. + * However we also need to take into account the indepth scan for subtitles. + */ + /* + * If scanning we need to do some extra setup of the job. + */ + if( job->indepth_scan == 1 ) + { + char *x264opts_tmp; + + /* + * When subtitle scan is enabled do a fast pre-scan job + * which will determine which subtitles to enable, if any. + */ + job->pass = -1; + x264opts_tmp = job->x264opts; + + job->x264opts = NULL; + job->indepth_scan = 1; + /* + * Add the pre-scan job + */ + hb_add( fPreviewLibhb, job ); + job->x264opts = x264opts_tmp; + } + /* Go ahead and perform the actual encoding preview scan */ + job->indepth_scan = 0; + job->pass = 0; + hb_add( fPreviewLibhb, job ); + + [fEncodingControlBox setHidden: NO]; + [fPictureControlBox setHidden: YES]; + + [fMovieCreationProgressIndicator setHidden: NO]; + [fPreviewMovieStatusField setHidden: NO]; + + isEncoding = YES; + + /* Let fPreviewLibhb do the job */ + hb_start( fPreviewLibhb ); + +} + +- (void) startReceivingLibhbNotifications +{ + if (!fLibhbTimer) + { + fLibhbTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(libhbTimerFired:) userInfo:nil repeats:YES]; + [fLibhbTimer retain]; + } +} + +- (void) stopReceivingLibhbNotifications +{ + if (fLibhbTimer) + { + [fLibhbTimer invalidate]; + [fLibhbTimer release]; + fLibhbTimer = nil; + } +} +- (void) libhbTimerFired: (NSTimer*)theTimer +{ + hb_state_t s; + hb_get_state( fPreviewLibhb, &s ); + [self libhbStateChanged: s]; + +} + +- (void) libhbStateChanged: (hb_state_t)state +{ + switch( state.state ) + { + case HB_STATE_IDLE: + case HB_STATE_SCANNING: + case HB_STATE_SCANDONE: + break; + + case HB_STATE_WORKING: + { +#define p state.param.working + + NSMutableString * string; + /* Update text field */ + string = [NSMutableString stringWithFormat: NSLocalizedString( @"Encoding preview: %.2f %%", @"" ), 100.0 * p.progress]; + + if( p.seconds > -1 ) + { + [string appendFormat: + NSLocalizedString( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)", @"" ), + p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds]; + } + [fPreviewMovieStatusField setStringValue: string]; + + [fMovieCreationProgressIndicator setIndeterminate: NO]; + /* Update slider */ + [fMovieCreationProgressIndicator setDoubleValue: 100.0 * p.progress]; + + [fCreatePreviewMovieButton setTitle: @"Cancel Preview"]; + + break; + + } +#undef p + +#define p state.param.muxing + case HB_STATE_MUXING: + { + // Update fMovieCreationProgressIndicator + [fMovieCreationProgressIndicator setIndeterminate: YES]; + [fMovieCreationProgressIndicator startAnimation: nil]; + [fPreviewMovieStatusField setStringValue: [NSString stringWithFormat: + NSLocalizedString( @"Muxing Preview ...", @"" )]]; + break; + } +#undef p + case HB_STATE_PAUSED: + [fMovieCreationProgressIndicator stopAnimation: nil]; + break; + + case HB_STATE_WORKDONE: + { + // Delete all remaining jobs since libhb doesn't do this on its own. + hb_job_t * job; + while( ( job = hb_job(fPreviewLibhb, 0) ) ) + hb_rem( fHandle, job ); + + [fPreviewMovieStatusField setStringValue: @""]; + [fPreviewMovieStatusField setHidden: YES]; + + [fMovieCreationProgressIndicator stopAnimation: nil]; + [fMovieCreationProgressIndicator setHidden: YES]; + [fEncodingControlBox setHidden: YES]; + isEncoding = NO; + /* we make sure the picture slider and preview match */ + [self pictureSliderChanged:nil]; + + // Show the movie view + [self showMoviePreview:fPreviewMoviePath]; + [fCreatePreviewMovieButton setTitle: @"Live Preview"]; + + break; + } + } +} + +- (IBAction) showMoviePreview: (NSString *) path +{ + /* Since the gray background for the still images is part of + * fPictureView, lets leave the picture view visible and postion + * the fMovieView over the image portion of fPictureView so + * we retain the gray cropping border we have already established + * with the still previews + */ + + /* Load the new movie into fMovieView */ + if (path) { + QTMovie * aMovie; + NSError *outError; + NSURL *movieUrl = [NSURL fileURLWithPath:path]; + NSDictionary *movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys: + movieUrl, QTMovieURLAttribute, + [NSNumber numberWithBool:NO], QTMovieAskUnresolvedDataRefsAttribute, + [NSNumber numberWithBool:YES], @"QTMovieOpenForPlaybackAttribute", + [NSNumber numberWithBool:NO], @"QTMovieOpenAsyncRequiredAttribute", + [NSNumber numberWithBool:NO], @"QTMovieOpenAsyncOKAttribute", + QTMovieApertureModeClean, QTMovieApertureModeAttribute, + nil]; + + aMovie = [[[QTMovie alloc] initWithAttributes:movieAttributes error:&outError] autorelease]; + + if (!aMovie) { + NSLog(@"Unable to open movie"); + } + else { + NSRect movieBounds; + /* we get some size information from the preview movie */ + NSSize movieSize= [[aMovie attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]; + movieBounds = [fMovieView movieBounds]; + movieBounds.size.height = movieSize.height; + + if ([fMovieView isControllerVisible]) { + CGFloat controllerBarHeight = [fMovieView controllerBarHeight]; + if ( controllerBarHeight != 0 ) //Check if QTKit return a real value or not. + movieBounds.size.height += controllerBarHeight; + else + movieBounds.size.height += 15; + } + + movieBounds.size.width = movieSize.width; + + /* We need to find out if the preview movie needs to be scaled down so + * that it doesn't overflow our available viewing container (just like for image + * in -displayPreview) for HD sources, etc. [fPictureViewArea frame].size.height*/ + if( (movieBounds.size.height) > [fPictureViewArea frame].size.height || scaleToScreen == YES ) + { + /* The preview movie would be larger than the available viewing area + * in the preview movie, so we go ahead and scale it down to the same size + * as the still preview or we readjust our window to allow for the added height if need be + */ + NSSize displaySize = NSMakeSize( ( CGFloat ) movieBounds.size.width, ( CGFloat ) movieBounds.size.height ); + NSSize viewSize = [self optimalViewSizeForImageSize:displaySize]; + if( [self viewNeedsToResizeToSize:viewSize] ) { + [self resizeSheetForViewSize:viewSize]; + [self setViewSize:viewSize]; + } + [fMovieView setFrameSize:viewSize]; + } + else + { + /* Since the preview movie is smaller than the available viewing area + * we can go ahead and use the preview movies native size */ + [fMovieView setFrameSize:movieBounds.size]; + } + + //lets reposition the movie if need be + + NSPoint origin = [fPictureViewArea frame].origin; + origin.x += trunc( ( [fPictureViewArea frame].size.width - + [fMovieView frame].size.width ) / 2.0 ); + /* We need to detect whether or not we are currently less than the available height.*/ + if( movieBounds.size.height < [fPictureView frame].size.height ) + { + /* If we are, we are adding 15 to the height to allow for the controller bar so + * we need to subtract half of that for the origin.y to get the controller bar + * below the movie to it lines up vertically with where our still preview was + */ + origin.y += trunc( ( ( [fPictureViewArea frame].size.height - + [fMovieView frame].size.height ) / 2.0 ) - 7.5 ); + } + else + { + /* if we are >= to the height of the picture view area, the controller bar + * gets taken care of with picture resizing, so we do not want to offset the height + */ + origin.y += trunc( ( [fPictureViewArea frame].size.height - + [fMovieView frame].size.height ) / 2.0 ); + } + [fMovieView setFrameOrigin:origin]; + [fMovieView setMovie:aMovie]; + [fMovieView setHidden:NO]; + // to actually play the movie + [fMovieView play:aMovie]; + } + } + isEncoding = NO; +} + +@end + +@implementation PreviewController (Private) + +// +// -[PictureController(Private) optimalViewSizeForImageSize:] +// +// Given the size of the preview image to be shown, returns the best possible +// size for the view. +// +- (NSSize)optimalViewSizeForImageSize: (NSSize)imageSize +{ + // The min size is 320x240 + CGFloat minWidth = 480.0; + CGFloat minHeight = 360.0; + + NSSize screenSize = [[NSScreen mainScreen] frame].size; + NSSize sheetSize = [[self window] frame].size; + NSSize viewAreaSize = [fPictureViewArea frame].size; + CGFloat paddingX = sheetSize.width - viewAreaSize.width; + CGFloat paddingY = sheetSize.height - viewAreaSize.height; + CGFloat maxWidth; + CGFloat maxHeight; + + if (isFullScreen) + { + /* We are in full screen mode so lets use the full screen if we need to */ + maxWidth = screenSize.width - paddingX; + maxHeight = screenSize.height - paddingY; + } + else + { + // The max size of the view is when the sheet is taking up 85% of the screen. + maxWidth = (0.85 * screenSize.width) - paddingX; + maxHeight = (0.85 * screenSize.height) - paddingY; + } + + NSSize resultSize = imageSize; + + // Its better to have a view that's too small than a view that's too big, so + // apply the maximum constraints last. + if( resultSize.width < minWidth ) + { + resultSize.height *= (minWidth / resultSize.width); + resultSize.width = minWidth; + } + if( resultSize.height < minHeight ) + { + resultSize.width *= (minHeight / resultSize.height); + resultSize.height = minHeight; + } + if( resultSize.width > maxWidth ) + { + resultSize.height *= (maxWidth / resultSize.width); + resultSize.width = maxWidth; + } + if( resultSize.height > maxHeight ) + { + resultSize.width *= (maxHeight / resultSize.height); + resultSize.height = maxHeight; + } + + if (scaleToScreen == YES) + { + CGFloat screenAspect; + CGFloat viewAreaAspect; + //note, a mbp 15" at 1440 x 900 is a 1.6 ar + screenAspect = screenSize.width / screenSize.height; + + // Note, a standard dvd will use 720 x 480 which is a 1.5 + viewAreaAspect = viewAreaSize.width / viewAreaSize.height; + + if (screenAspect < viewAreaAspect) + { + resultSize.width = screenSize.width; + resultSize.height = (screenSize.width / viewAreaAspect); + } + else + { + resultSize.height = screenSize.height; + resultSize.width = resultSize.height * viewAreaAspect; + } + + } + + return resultSize; + + +} + +// +// -[PictureController(Private) resizePanelForViewSize:animate:] +// +// Resizes the entire window to accomodate a view of a particular size. +// +- (void)resizeSheetForViewSize: (NSSize)viewSize +{ + // Figure out the deltas for the new frame area + NSSize currentSize = [fPictureViewArea frame].size; + CGFloat deltaX = viewSize.width - currentSize.width; + CGFloat deltaY = viewSize.height - currentSize.height; + + // Now resize the whole panel by those same deltas, but don't exceed the min + NSRect frame = [[self window] frame]; + NSSize maxSize = [[self window] maxSize]; + NSSize minSize = [[self window] minSize]; + frame.size.width += deltaX; + frame.size.height += deltaY; + if( frame.size.width < minSize.width ) + { + frame.size.width = minSize.width; + } + + if( frame.size.height < minSize.height ) + { + frame.size.height = minSize.height; + } + + + // But now the sheet is off-center, so also shift the origin to center it and + // keep the top aligned. + if( frame.size.width != [[self window] frame].size.width ) + frame.origin.x -= (deltaX / 2.0); + + if (isFullScreen) + { + if( frame.size.height != [[self window] frame].size.height ) + { + frame.origin.y -= (deltaY / 2.0); + } + else + { + if( frame.size.height != [[self window] frame].size.height ) + frame.origin.y -= deltaY; + } + + [[self window] setFrame:frame display:YES animate:NO]; + } + else + { + /* Since upon launch we can open up the preview window if it was open + * the last time we quit (and at the size it was) we want to make + * sure that upon resize we do not have the window off the screen + * So check the origin against the screen origin and adjust if + * necessary. + */ + NSSize screenSize = [[[self window] screen] frame].size; + NSPoint screenOrigin = [[[self window] screen] frame].origin; + /* our origin is off the screen to the left*/ + if (frame.origin.x < screenOrigin.x) + { + /* so shift our origin to the right */ + frame.origin.x = screenOrigin.x; + } + else if ((frame.origin.x + frame.size.width) > (screenOrigin.x + screenSize.width)) + { + /* the right side of the preview is off the screen, so shift to the left */ + frame.origin.x = (screenOrigin.x + screenSize.width) - frame.size.width; + } + + [[self window] setFrame:frame display:YES animate:YES]; + } + +} + +// +// -[PictureController(Private) setViewSize:] +// +// Changes the view's size and centers it vertically inside of its area. +// Assumes resizeSheetForViewSize: has already been called. +// +- (void)setViewSize: (NSSize)viewSize +{ + /* special case for scaleToScreen */ + if (scaleToScreen == YES) + { + /* for scaleToScreen, we expand the fPictureView to fit the entire screen */ + NSSize areaSize = [fPictureViewArea frame].size; + CGFloat viewSizeAspect = viewSize.width / viewSize.height; + if (viewSizeAspect > 1.0) // we are wider than taller, so expand the width to fill the area and scale the height + { + viewSize.width = areaSize.width; + viewSize.height = viewSize.width / viewSizeAspect; + } + else + { + viewSize.height = areaSize.height; + viewSize.width = viewSize.height * viewSizeAspect; + } + + } + + [fPictureView setFrameSize:viewSize]; + + // center it vertically and horizontally + NSPoint origin = [fPictureViewArea frame].origin; + origin.y += ([fPictureViewArea frame].size.height - + [fPictureView frame].size.height) / 2.0; + + origin.x += ([fPictureViewArea frame].size.width - + [fPictureView frame].size.width) / 2.0; + + origin.x = floor( origin.x ); + origin.y = floor( origin.y ); + + [fPictureView setFrameOrigin:origin]; +} + + +- (BOOL)viewNeedsToResizeToSize: (NSSize)newSize +{ + NSSize viewSize = [fPictureViewArea frame].size; + return (newSize.width != viewSize.width || newSize.height != viewSize.height); +} + +@end diff --git a/macosx/HBPreviewController.mm b/macosx/HBPreviewController.mm deleted file mode 100644 index 622caad9b..000000000 --- a/macosx/HBPreviewController.mm +++ /dev/null @@ -1,1324 +0,0 @@ -/* $Id: HBPreviewController.mm,v 1.11 2005/08/01 15:10:44 titer Exp $ - - This file is part of the HandBrake source code. - Homepage: . - It may be used under the terms of the GNU General Public License. */ - -#import "HBPreviewController.h" -#import "Controller.h" - -@implementation QTMovieView ( HBQTkitExt ) -- (void) mouseMoved:(NSEvent *)theEvent -{ - [super mouseMoved:theEvent]; -} -@end - -@interface PreviewController (Private) - -- (NSSize)optimalViewSizeForImageSize: (NSSize)imageSize; -- (void)resizeSheetForViewSize: (NSSize)viewSize; -- (void)setViewSize: (NSSize)viewSize; -- (BOOL)viewNeedsToResizeToSize: (NSSize)newSize; - -@end - -@implementation PreviewController - -- (id)init -{ - if (self = [super initWithWindowNibName:@"PicturePreview"]) - { - // NSWindowController likes to lazily load its window. However since - // this controller tries to set all sorts of outlets before the window - // is displayed, we need it to load immediately. The correct way to do - // this, according to the documentation, is simply to invoke the window - // getter once. - // - // If/when we switch a lot of this stuff to bindings, this can probably - // go away. - [self window]; - - fPicturePreviews = [[NSMutableDictionary dictionaryWithCapacity: HB_NUM_HBLIB_PICTURES] retain]; - /* Init libhb with check for updates libhb style set to "0" so its ignored and lets sparkle take care of it */ - int loggingLevel = [[[NSUserDefaults standardUserDefaults] objectForKey:@"LoggingLevel"] intValue]; - fPreviewLibhb = hb_init(loggingLevel, 0); - - } - return self; -} - - - -//------------------------------------------------------------------------------------ -// Displays and brings the picture window to the front -//------------------------------------------------------------------------------------ -- (IBAction) showPreviewWindow: (id)sender -{ - [self showWindow:sender]; - [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"PreviewWindowIsOpen"]; - - /* lets set the preview window to accept mouse moved events */ - [fPreviewWindow setAcceptsMouseMovedEvents:YES]; - hudTimerSeconds = 0; - [self pictureSliderChanged:nil]; - [self startReceivingLibhbNotifications]; -} - -- (void)setHBController: (HBController *)controller -{ - fHBController = controller; -} - -- (void)awakeFromNib -{ - [fPreviewWindow setDelegate:self]; - if( ![[self window] setFrameUsingName:@"Preview"] ) - [[self window] center]; - [self setWindowFrameAutosaveName:@"Preview"]; - [[self window] setExcludedFromWindowsMenu:YES]; - - /* lets set the preview window to accept mouse moved events */ - [fPreviewWindow setAcceptsMouseMovedEvents:YES]; - //[self pictureSliderChanged:nil]; - [self startReceivingLibhbNotifications]; - - isFullScreen = NO; - hudTimerSeconds = 0; - /* we set the progress indicator to not use threaded animation - * as it causes a conflict with the qtmovieview's controllerbar - */ - [fMovieCreationProgressIndicator setUsesThreadedAnimation:NO]; - - /* Setup our layers for core animation */ - [fPictureViewArea setWantsLayer:YES]; - [fPictureView setWantsLayer:YES]; - - [fCancelPreviewMovieButton setWantsLayer:YES]; - [fMovieCreationProgressIndicator setWantsLayer:YES]; - - [fPictureControlBox setWantsLayer:YES]; - [fEncodingControlBox setWantsLayer:YES]; - [fMovieView setWantsLayer:YES]; - [fMovieView setHidden:YES]; - [fMovieView setDelegate:self]; - - /* Since the xib has everything off center for easy acess - * we align our views and windows here we an align to anything - * since it will actually change later upon source load, but - * for convenience we will use the fPictureViewArea - */ - - /* Align the still preview image view to the picture box */ - [fPictureView setFrameSize:[fPictureViewArea frame].size]; - [fMovieView setFrameSize:[fPictureViewArea frame].size]; - //[fPreviewWindow setFrameSize:[fPictureViewArea frame].size]; - - -} -- (BOOL)acceptsMouseMovedEvents -{ - return YES; -} - -- (void)windowWillClose:(NSNotification *)aNotification -{ - /* Upon Closing the picture window, we make sure we clean up any - * preview movie that might be playing - */ - hb_stop( fPreviewLibhb ); - isEncoding = NO; - // Show the picture view - [fPictureView setHidden:NO]; - [fMovieView pause:nil]; - [fMovieView setHidden:YES]; - [fMovieView setMovie:nil]; - - isFullScreen = NO; - hudTimerSeconds = 0; - [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"PreviewWindowIsOpen"]; -} - -- (BOOL)windowShouldClose:(id)fPictureWindow -{ - return YES; -} - -- (void) dealloc -{ - hb_stop(fPreviewLibhb); - if (fPreviewMoviePath) - { - [[NSFileManager defaultManager] removeFileAtPath:fPreviewMoviePath handler:nil]; - [fPreviewMoviePath release]; - } - - [fLibhbTimer invalidate]; - [fLibhbTimer release]; - - [fHudTimer invalidate]; - [fHudTimer release]; - - [fPicturePreviews release]; - [fFullScreenWindow release]; - - [super dealloc]; -} - -- (void) SetHandle: (hb_handle_t *) handle -{ - fHandle = handle; - - - - /* we set the preview length popup in seconds */ - [fPreviewMovieLengthPopUp removeAllItems]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"5"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"10"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"15"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"20"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"25"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"30"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"35"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"40"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"45"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"50"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"55"]; - [fPreviewMovieLengthPopUp addItemWithTitle: @"60"]; - - /* adjust the preview slider length */ - /* We use our advance pref to determine how many previews we scanned */ - int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue]; - [fPictureSlider setMaxValue: hb_num_previews - 1.0]; - [fPictureSlider setNumberOfTickMarks: hb_num_previews]; - - if ([[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewLength"]) - { - [fPreviewMovieLengthPopUp selectItemWithTitle:[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewLength"]]; - } - else - { - /* currently hard set default to 10 seconds */ - [fPreviewMovieLengthPopUp selectItemAtIndex: 1]; - } -} - -- (void) SetTitle: (hb_title_t *) title -{ - hb_job_t * job = title->job; - - fTitle = title; - fPicture = 0; - MaxOutputWidth = title->width - job->crop[2] - job->crop[3]; - MaxOutputHeight = title->height - job->crop[0] - job->crop[1]; - [self SettingsChanged: nil]; -} - - - -// Adjusts the window to draw the current picture (fPicture) adjusting its size as -// necessary to display as much of the picture as possible. -- (void) displayPreview -{ - hb_job_t * job = fTitle->job; - /* lets make sure that the still picture view is not hidden and that - * the movie preview is - */ - [fMovieView pause:nil]; - [fMovieView setHidden:YES]; - [fMovieView setMovie:nil]; - [fMovieCreationProgressIndicator stopAnimation: nil]; - [fMovieCreationProgressIndicator setHidden: YES]; - - [fPictureView setHidden:NO]; - - //[fHBController writeToActivityLog: "displayPreview called"]; - - NSImage *fPreviewImage = [self imageForPicture: fPicture]; - NSSize imageScaledSize = [fPreviewImage size]; - [fPictureView setImage: fPreviewImage]; - - NSSize displaySize = NSMakeSize( ( CGFloat )fTitle->width, ( CGFloat )fTitle->height ); - NSString *sizeInfoString; - /* Set the picture size display fields below the Preview Picture*/ - if( fTitle->job->anamorphic.mode == 1 ) // Original PAR Implementation - { - output_width = fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3]; - output_height = fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1]; - display_width = output_width * fTitle->job->anamorphic.par_width / fTitle->job->anamorphic.par_height; - sizeInfoString = [NSString stringWithFormat: - @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d Strict", - fTitle->width, fTitle->height, output_width, output_height, display_width, output_height]; - - displaySize.width = display_width; - displaySize.height = fTitle->height; - imageScaledSize.width = display_width; - imageScaledSize.height = output_height; - } - else if (fTitle->job->anamorphic.mode == 2) // Loose Anamorphic - { - hb_set_anamorphic_size(job, &output_width, &output_height, &output_par_width, &output_par_height); - display_width = output_width * output_par_width / output_par_height; - sizeInfoString = [NSString stringWithFormat: - @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d Loose", - fTitle->width, fTitle->height, output_width, output_height, display_width, output_height]; - - displaySize.width = display_width; - displaySize.height = fTitle->height; - imageScaledSize.width = display_width; - imageScaledSize.height = output_height; - } - else if (fTitle->job->anamorphic.mode == 3) // Custom Anamorphic - { - hb_set_anamorphic_size(job, &output_width, &output_height, &output_par_width, &output_par_height); - display_width = output_width * output_par_width / output_par_height; - sizeInfoString = [NSString stringWithFormat: - @"Source: %dx%d, Output: %dx%d, Anamorphic: %dx%d Custom", - fTitle->width, fTitle->height, output_width, output_height, fTitle->job->anamorphic.dar_width, fTitle->job->anamorphic.dar_height]; - - displaySize.width = fTitle->job->anamorphic.dar_width + fTitle->job->crop[2] + fTitle->job->crop[3]; - displaySize.height = fTitle->job->anamorphic.dar_height + fTitle->job->crop[0] + fTitle->job->crop[1]; - imageScaledSize.width = (int)fTitle->job->anamorphic.dar_width; - imageScaledSize.height = (int)fTitle->job->height; - } - else // No Anamorphic - { - sizeInfoString = [NSString stringWithFormat: - @"Source: %dx%d, Output: %dx%d", fTitle->width, fTitle->height, - fTitle->job->width, fTitle->job->height]; - - displaySize.width = fTitle->width; - displaySize.height = fTitle->height; - imageScaledSize.width = fTitle->job->width; - imageScaledSize.height = fTitle->job->height; - } - - NSSize viewSize = [self optimalViewSizeForImageSize:displaySize]; - - /* Initially set our preview image here */ - /* - if (scaleToScreen == YES) - { - viewSize.width = viewSize.width - (viewSize.width - imageScaledSize.width); - viewSize.height = viewSize.height - (viewSize.height - imageScaledSize.height); - [fPreviewImage setSize: viewSize]; - //[fPictureView setFrameSize: viewSize]; - } - - else - { - [fPreviewImage setSize: imageScaledSize]; - [fPictureView setFrameSize: imageScaledSize]; - } - [fPictureView setImage: fPreviewImage]; - // center it vertically and horizontally - NSPoint origin = [fPictureViewArea frame].origin; - origin.y += ([fPictureViewArea frame].size.height - - [fPictureView frame].size.height) / 2.0; - - origin.x += ([fPictureViewArea frame].size.width - - [fPictureView frame].size.width) / 2.0; - [fPictureView setFrameOrigin:origin]; - */ - /* we also need to take into account scaling to full screen to activate switching the view size */ - if( [self viewNeedsToResizeToSize:viewSize]) - { - if (fTitle->job->anamorphic.mode != 2 || (fTitle->job->anamorphic.mode == 2 && fTitle->width == fTitle->job->width)) - { - [self resizeSheetForViewSize:viewSize]; - //[self setViewSize:viewSize]; - - } - } - - viewSize.width = viewSize.width - (viewSize.width - imageScaledSize.width); - viewSize.height = viewSize.height - (viewSize.height - imageScaledSize.height); - [self setViewSize:viewSize]; - - /* special case for scaleToScreen */ - if (scaleToScreen == YES) - { - [fPreviewImage setSize: viewSize]; - [fPictureView setImage: fPreviewImage]; - } - - NSString *scaleString; - - if( imageScaledSize.height > [fPictureView frame].size.height) - { - CGFloat scale = ( ( CGFloat )[fPictureView frame].size.width) / ( ( CGFloat )imageScaledSize.width); - scaleString = [NSString stringWithFormat: - NSLocalizedString( @" (Scaled to %.0f%% actual size)", - @"String shown when a preview is scaled" ), scale * 100.0]; - } - else - { - scaleString = @""; - } - /* Set the info fields in the hud controller */ - [fInfoField setStringValue: [NSString stringWithFormat: - @"%@", sizeInfoString]]; - - [fscaleInfoField setStringValue: [NSString stringWithFormat: - @"%@", scaleString]]; - /* Set the info field in the window title bar */ - [[self window] setTitle:[NSString stringWithFormat: @"Preview - %@ %@",sizeInfoString, scaleString]]; -} - -- (IBAction) previewDurationPopUpChanged: (id) sender -{ - - [[NSUserDefaults standardUserDefaults] setObject:[fPreviewMovieLengthPopUp titleOfSelectedItem] forKey:@"PreviewLength"]; - -} - -- (IBAction) SettingsChanged: (id) sender -{ - // Purge the existing picture previews so they get recreated the next time - // they are needed. - [self purgeImageCache]; - [self pictureSliderChanged:nil]; -} - -- (IBAction) pictureSliderChanged: (id) sender -{ - // Show the picture view - [fPictureView setHidden:NO]; - [fMovieView pause:nil]; - [fMovieView setHidden:YES]; - [fMovieView setMovie:nil]; - [fEncodingControlBox setHidden: YES]; - - int newPicture = [fPictureSlider intValue]; - if (newPicture != fPicture) - { - fPicture = newPicture; - } - [self displayPreview]; - -} - -- (IBAction)showPreviewPanel: (id)sender forTitle: (hb_title_t *)title -{ - if ([fPreviewWindow isVisible]) - { - [fPreviewWindow close]; - } - else - { - [self showWindow:sender]; - [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"PreviewWindowIsOpen"]; - [fPreviewWindow setAcceptsMouseMovedEvents:YES]; - isFullScreen = NO; - scaleToScreen = NO; - [self pictureSliderChanged:nil]; - } - -} - -- (NSString*) pictureSizeInfoString -{ - return [fInfoField stringValue]; -} - -- (IBAction)showPictureSettings:(id)sender -{ - [fHBController showPicturePanel:self]; -} - -#pragma mark Hud Control Overlay -- (void) mouseMoved:(NSEvent *)theEvent -{ - [super mouseMoved:theEvent]; - NSPoint mouseLoc = [theEvent locationInWindow]; - - /* Test for mouse location to show/hide hud controls */ - if( isEncoding == NO ) { - if( NSPointInRect( mouseLoc, [fPictureControlBox frame] ) ) - { - [[fPictureControlBox animator] setHidden: NO]; - [self stopHudTimer]; - } - else if( NSPointInRect( mouseLoc, [fPictureViewArea frame] ) ) - { - [[fPictureControlBox animator] setHidden: NO]; - [self startHudTimer]; - } - else - [[fPictureControlBox animator] setHidden: YES]; - } -} - -- (void) startHudTimer -{ - if( fHudTimer ) { - [fHudTimer invalidate]; - [fHudTimer release]; - } - fHudTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(hudTimerFired:) userInfo:nil repeats:YES]; - [fHudTimer retain]; -} - -- (void) stopHudTimer -{ - if( fHudTimer ) - { - [fHudTimer invalidate]; - [fHudTimer release]; - fHudTimer = nil; - hudTimerSeconds = 0; - } -} - -- (void) hudTimerFired: (NSTimer*)theTimer -{ - hudTimerSeconds++; - if( hudTimerSeconds >= 10 ) { - [[fPictureControlBox animator] setHidden: YES]; - [self stopHudTimer]; - } -} - -#pragma mark Fullscreen Mode - -- (IBAction)toggleScreenMode:(id)sender -{ - if (!isFullScreen) - { - [self goFullScreen:nil]; - } - else - { - [self goWindowedScreen:nil]; - } -} - -- (IBAction)toggleScaleToScreen:(id)sender -{ - if (scaleToScreen == YES) - { - scaleToScreen = NO; - /* make sure we are set to a still preview */ - [self pictureSliderChanged:nil]; - [fScaleToScreenToggleButton setTitle:@"<->"]; - } - else - { - scaleToScreen = YES; - /* make sure we are set to a still preview */ - [self pictureSliderChanged:nil]; - [fScaleToScreenToggleButton setTitle:@">-<"]; - } -} - -- (BOOL)fullScreen -{ - return isFullScreen; -} - -- (IBAction)goFullScreen:(id)sender -{ - // Get the screen information. - NSScreen* mainScreen = [fPreviewWindow screen]; - NSDictionary* screenInfo = [mainScreen deviceDescription]; - NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"]; - // Capture the screen. - CGDirectDisplayID displayID = (CGDirectDisplayID)[screenID longValue]; - CGDisplayErr err = CGDisplayCapture(displayID); - - if (err == CGDisplayNoErr) - { - - /* make sure we are set to a still preview and not scaled to screen */ - scaleToScreen = NO; - [self pictureSliderChanged:nil]; - - // Create the full-screen window. - //NSRect winRect = [mainScreen frame]; - //fPictureViewArea - NSRect winRect = [fPictureViewArea frame]; - - fFullScreenWindow = [[NSWindow alloc] initWithContentRect:winRect - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO - screen:mainScreen]; - - // Establish the window attributes. - [fFullScreenWindow setReleasedWhenClosed:NO]; - [fFullScreenWindow setDisplaysWhenScreenProfileChanges:YES]; - [fFullScreenWindow setDelegate:self]; - - /* insert a view into the new window */ - [fFullScreenWindow setContentView:fPictureViewArea]; - [fPictureViewArea setNeedsDisplay:YES]; - - /* Better to center the window using the screen's frame - * and the windows origin. Note that we should take into - * account the auto sizing and alignment that occurs in - * setViewSize each time the preview changes. - * Note: by using [fFullScreenWindow screen] (instead of - * [NSScreen mainScreen]) in referencing the screen - * coordinates, the full screen window will show up on - * whichever display was being used in windowed mode - * on multi-display systems - */ - - NSSize screenSize = [[fFullScreenWindow screen] frame].size; - NSSize windowSize = [fFullScreenWindow frame].size; - NSPoint windowOrigin = [fFullScreenWindow frame].origin; - - /* Adjust our origin y (vertical) based on the screen height */ - windowOrigin.y += (screenSize.height - windowSize.height) / 2.0; - windowOrigin.x += (screenSize.width - windowSize.width) / 2.0; - - [fFullScreenWindow setFrameOrigin:windowOrigin]; - - /* lets kill the timer for now */ - [self stopReceivingLibhbNotifications]; - - /* We need to retain the fPreviewWindow */ - [fPreviewWindow retain]; - - [self setWindow:fFullScreenWindow]; - - // The window has to be above the level of the shield window. - int32_t shieldLevel = CGShieldingWindowLevel(); - - [fFullScreenWindow setLevel:shieldLevel]; - - // Show the window. - [fFullScreenWindow makeKeyAndOrderFront:self]; - - - /* Change the name of fFullScreenToggleButton appropriately */ - [fFullScreenToggleButton setTitle: @"Windowed"]; - - /* Lets fire the timer back up for the hud controls, etc. */ - [self startReceivingLibhbNotifications]; - - isFullScreen = YES; - [fScaleToScreenToggleButton setHidden:NO]; - - /* make sure we are set to a still preview */ - [self pictureSliderChanged:nil]; - - [fFullScreenWindow setAcceptsMouseMovedEvents:YES]; - - - hudTimerSeconds = 0; - [self startHudTimer]; - } -} - -// Title-less windows normally don't receive key presses, override this -- (BOOL)canBecomeKeyWindow -{ - return YES; -} - -// Title-less windows normally can't become main which means that another -// non-fullscreen window will have the "active" titlebar in expose. Bad, fix it. -- (BOOL)canBecomeMainWindow -{ - return YES; -} - - -- (IBAction)goWindowedScreen:(id)sender -{ - - /* Get the screen info to release the display but don't actually do - * it until the windowed screen is setup. - */ - scaleToScreen = NO; - [self pictureSliderChanged:nil]; - [fScaleToScreenToggleButton setTitle:@"<->"]; - - NSScreen* mainScreen = [NSScreen mainScreen]; - NSDictionary* screenInfo = [mainScreen deviceDescription]; - NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"]; - CGDirectDisplayID displayID = (CGDirectDisplayID)[screenID longValue]; - - [fFullScreenWindow dealloc]; - [fFullScreenWindow release]; - - - [fPreviewWindow setContentView:fPictureViewArea]; - [fPictureViewArea setNeedsDisplay:YES]; - [self setWindow:fPreviewWindow]; - - // Show the window. - [fPreviewWindow makeKeyAndOrderFront:self]; - - /* Set the window back to regular level */ - [fPreviewWindow setLevel:NSNormalWindowLevel]; - - /* Set the isFullScreen flag back to NO */ - isFullScreen = NO; - scaleToScreen = NO; - /* make sure we are set to a still preview */ - [self pictureSliderChanged:nil]; - [self showPreviewWindow:nil]; - - /* Change the name of fFullScreenToggleButton appropriately */ - [fFullScreenToggleButton setTitle: @"Full Screen"]; - // [fScaleToScreenToggleButton setHidden:YES]; - /* set the picture settings pallete back to normal level */ - [fHBController picturePanelWindowed]; - - /* Release the display now that the we are back in windowed mode */ - CGDisplayRelease(displayID); - - [fPreviewWindow setAcceptsMouseMovedEvents:YES]; - //[fFullScreenWindow setAcceptsMouseMovedEvents:NO]; - - hudTimerSeconds = 0; - [self startHudTimer]; - -} - - -#pragma mark Still Preview Image Processing - - -// This function converts an image created by libhb (specified via pictureIndex) into -// an NSImage suitable for the GUI code to use. If removeBorders is YES, -// makeImageForPicture crops the image generated by libhb stripping off the gray -// border around the content. This is the low-level method that generates the image. -// -imageForPicture calls this function whenever it can't find an image in its cache. -+ (NSImage *) makeImageForPicture: (int)pictureIndex - libhb:(hb_handle_t*)handle - title:(hb_title_t*)title -{ - static uint8_t * buffer; - static int bufferSize; - - // Make sure we have a big enough buffer to receive the image from libhb. libhb - int dstWidth = title->job->width; - int dstHeight = title->job->height; - - int newSize; - newSize = dstWidth * dstHeight * 4; - if( bufferSize < newSize ) - { - bufferSize = newSize; - buffer = (uint8_t *) realloc( buffer, bufferSize ); - } - - hb_get_preview( handle, title, pictureIndex, buffer ); - - // Create an NSBitmapImageRep and copy the libhb image into it, converting it from - // libhb's format to one suitable for NSImage. Along the way, we'll strip off the - // border around libhb's image. - - // The image data returned by hb_get_preview is 4 bytes per pixel, BGRA format. - // Alpha is ignored. - - NSBitmapFormat bitmapFormat = (NSBitmapFormat)NSAlphaFirstBitmapFormat; - NSBitmapImageRep * imgrep = [[[NSBitmapImageRep alloc] - initWithBitmapDataPlanes:nil - pixelsWide:dstWidth - pixelsHigh:dstHeight - bitsPerSample:8 - samplesPerPixel:3 // ignore alpha - hasAlpha:NO - isPlanar:NO - colorSpaceName:NSCalibratedRGBColorSpace - bitmapFormat:bitmapFormat - bytesPerRow:dstWidth * 4 - bitsPerPixel:32] autorelease]; - - UInt32 * src = (UInt32 *)buffer; - UInt32 * dst = (UInt32 *)[imgrep bitmapData]; - for (int r = 0; r < dstHeight; r++) - { - for (int c = 0; c < dstWidth; c++) -#if TARGET_RT_LITTLE_ENDIAN - *dst++ = Endian32_Swap(*src++); -#else - *dst++ = *src++; -#endif - } - - NSImage * img = [[[NSImage alloc] initWithSize: NSMakeSize(dstWidth, dstHeight)] autorelease]; - [img addRepresentation:imgrep]; - - return img; -} - -// Returns the preview image for the specified index, retrieving it from its internal -// cache or by calling makeImageForPicture if it is not cached. Generally, you should -// use imageForPicture so that images are cached. Calling makeImageForPicture will -// always generate a new copy of the image. -- (NSImage *) imageForPicture: (int) pictureIndex -{ - // The preview for the specified index may not currently exist, so this method - // generates it if necessary. - NSString * key = [NSString stringWithFormat:@"%d", pictureIndex]; - NSImage * theImage = [fPicturePreviews objectForKey:key]; - if (!theImage) - { - theImage = [PreviewController makeImageForPicture:pictureIndex libhb:fHandle title:fTitle]; - [fPicturePreviews setObject:theImage forKey:key]; - } - return theImage; -} - -// Purges all images from the cache. The next call to imageForPicture will cause a new -// image to be generated. -- (void) purgeImageCache -{ - [fPicturePreviews removeAllObjects]; -} - - - -#pragma mark Movie Preview -- (IBAction) createMoviePreview: (id) sender -{ - - - /* Lets make sure the still picture previews are showing in case - * there is currently a movie showing */ - [self pictureSliderChanged:nil]; - - /* Rip or Cancel ? */ - hb_state_t s; - hb_get_state2( fPreviewLibhb, &s ); - - if(sender == fCancelPreviewMovieButton && (s.state == HB_STATE_WORKING || s.state == HB_STATE_PAUSED)) - { - hb_stop( fPreviewLibhb ); - [fPictureView setHidden:NO]; - [fMovieView pause:nil]; - [fMovieView setHidden:YES]; - [fMovieView setMovie:nil]; - [fPictureSlider setHidden:NO]; - isEncoding = NO; - - return; - } - - - /* we use controller.mm's prepareJobForPreview to go ahead and set all of our settings - * however, we want to use a temporary destination field of course - * so that we do not put our temp preview in the users chosen - * directory */ - - hb_job_t * job = fTitle->job; - - /* We run our current setting through prepeareJob in Controller.mm - * just as if it were a regular encode */ - - [fHBController prepareJobForPreview]; - - /* Destination file. We set this to our preview directory - * changing the extension appropriately.*/ - if (fTitle->job->mux == HB_MUX_MP4) // MP4 file - { - /* we use .m4v for our mp4 files so that ac3 and chapters in mp4 will play properly */ - fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.m4v"; - } - else if (fTitle->job->mux == HB_MUX_MKV) // MKV file - { - fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.mkv"; - } - else if (fTitle->job->mux == HB_MUX_AVI) // AVI file - { - fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.avi"; - } - else if (fTitle->job->mux == HB_MUX_OGM) // OGM file - { - fPreviewMoviePath = @"~/Library/Application Support/HandBrake/Previews/preview_temp.ogm"; - } - - fPreviewMoviePath = [[fPreviewMoviePath stringByExpandingTildeInPath]retain]; - - /* See if there is an existing preview file, if so, delete it */ - if( ![[NSFileManager defaultManager] fileExistsAtPath:fPreviewMoviePath] ) - { - [[NSFileManager defaultManager] removeFileAtPath:fPreviewMoviePath - handler:nil]; - } - - /* We now direct our preview encode to fPreviewMoviePath */ - fTitle->job->file = [fPreviewMoviePath UTF8String]; - - /* We use our advance pref to determine how many previews to scan */ - int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue]; - job->start_at_preview = fPicture + 1; - job->seek_points = hb_num_previews; - - /* we use the preview duration popup to get the specified - * number of seconds for the preview encode. - */ - - job->pts_to_stop = [[fPreviewMovieLengthPopUp titleOfSelectedItem] intValue] * 90000LL; - - /* lets go ahead and send it off to libhb - * Note: unlike a full encode, we only send 1 pass regardless if the final encode calls for 2 passes. - * this should suffice for a fairly accurate short preview and cuts our preview generation time in half. - * However we also need to take into account the indepth scan for subtitles. - */ - /* - * If scanning we need to do some extra setup of the job. - */ - if( job->indepth_scan == 1 ) - { - char *x264opts_tmp; - - /* - * When subtitle scan is enabled do a fast pre-scan job - * which will determine which subtitles to enable, if any. - */ - job->pass = -1; - x264opts_tmp = job->x264opts; - - job->x264opts = NULL; - job->indepth_scan = 1; - /* - * Add the pre-scan job - */ - hb_add( fPreviewLibhb, job ); - job->x264opts = x264opts_tmp; - } - /* Go ahead and perform the actual encoding preview scan */ - job->indepth_scan = 0; - job->pass = 0; - hb_add( fPreviewLibhb, job ); - - [fEncodingControlBox setHidden: NO]; - [fPictureControlBox setHidden: YES]; - - [fMovieCreationProgressIndicator setHidden: NO]; - [fPreviewMovieStatusField setHidden: NO]; - - isEncoding = YES; - - /* Let fPreviewLibhb do the job */ - hb_start( fPreviewLibhb ); - -} - -- (void) startReceivingLibhbNotifications -{ - if (!fLibhbTimer) - { - fLibhbTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(libhbTimerFired:) userInfo:nil repeats:YES]; - [fLibhbTimer retain]; - } -} - -- (void) stopReceivingLibhbNotifications -{ - if (fLibhbTimer) - { - [fLibhbTimer invalidate]; - [fLibhbTimer release]; - fLibhbTimer = nil; - } -} -- (void) libhbTimerFired: (NSTimer*)theTimer -{ - hb_state_t s; - hb_get_state( fPreviewLibhb, &s ); - [self libhbStateChanged: s]; - -} - -- (void) libhbStateChanged: (hb_state_t &)state -{ - switch( state.state ) - { - case HB_STATE_IDLE: - case HB_STATE_SCANNING: - case HB_STATE_SCANDONE: - break; - - case HB_STATE_WORKING: - { -#define p state.param.working - - NSMutableString * string; - /* Update text field */ - string = [NSMutableString stringWithFormat: NSLocalizedString( @"Encoding preview: %.2f %%", @"" ), 100.0 * p.progress]; - - if( p.seconds > -1 ) - { - [string appendFormat: - NSLocalizedString( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)", @"" ), - p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds]; - } - [fPreviewMovieStatusField setStringValue: string]; - - [fMovieCreationProgressIndicator setIndeterminate: NO]; - /* Update slider */ - [fMovieCreationProgressIndicator setDoubleValue: 100.0 * p.progress]; - - [fCreatePreviewMovieButton setTitle: @"Cancel Preview"]; - - break; - - } -#undef p - -#define p state.param.muxing - case HB_STATE_MUXING: - { - // Update fMovieCreationProgressIndicator - [fMovieCreationProgressIndicator setIndeterminate: YES]; - [fMovieCreationProgressIndicator startAnimation: nil]; - [fPreviewMovieStatusField setStringValue: [NSString stringWithFormat: - NSLocalizedString( @"Muxing Preview ...", @"" )]]; - break; - } -#undef p - case HB_STATE_PAUSED: - [fMovieCreationProgressIndicator stopAnimation: nil]; - break; - - case HB_STATE_WORKDONE: - { - // Delete all remaining jobs since libhb doesn't do this on its own. - hb_job_t * job; - while( ( job = hb_job(fPreviewLibhb, 0) ) ) - hb_rem( fHandle, job ); - - [fPreviewMovieStatusField setStringValue: @""]; - [fPreviewMovieStatusField setHidden: YES]; - - [fMovieCreationProgressIndicator stopAnimation: nil]; - [fMovieCreationProgressIndicator setHidden: YES]; - [fEncodingControlBox setHidden: YES]; - isEncoding = NO; - /* we make sure the picture slider and preview match */ - [self pictureSliderChanged:nil]; - - // Show the movie view - [self showMoviePreview:fPreviewMoviePath]; - [fCreatePreviewMovieButton setTitle: @"Live Preview"]; - - break; - } - } -} - -- (IBAction) showMoviePreview: (NSString *) path -{ - /* Since the gray background for the still images is part of - * fPictureView, lets leave the picture view visible and postion - * the fMovieView over the image portion of fPictureView so - * we retain the gray cropping border we have already established - * with the still previews - */ - - /* Load the new movie into fMovieView */ - if (path) { - QTMovie * aMovie; - NSError *outError; - NSURL *movieUrl = [NSURL fileURLWithPath:path]; - NSDictionary *movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys: - movieUrl, QTMovieURLAttribute, - [NSNumber numberWithBool:NO], QTMovieAskUnresolvedDataRefsAttribute, - [NSNumber numberWithBool:YES], @"QTMovieOpenForPlaybackAttribute", - [NSNumber numberWithBool:NO], @"QTMovieOpenAsyncRequiredAttribute", - [NSNumber numberWithBool:NO], @"QTMovieOpenAsyncOKAttribute", - QTMovieApertureModeClean, QTMovieApertureModeAttribute, - nil]; - - aMovie = [[[QTMovie alloc] initWithAttributes:movieAttributes error:&outError] autorelease]; - - if (!aMovie) { - NSLog(@"Unable to open movie"); - } - else { - NSRect movieBounds; - /* we get some size information from the preview movie */ - NSSize movieSize= [[aMovie attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]; - movieBounds = [fMovieView movieBounds]; - movieBounds.size.height = movieSize.height; - - if ([fMovieView isControllerVisible]) { - CGFloat controllerBarHeight = [fMovieView controllerBarHeight]; - if ( controllerBarHeight != 0 ) //Check if QTKit return a real value or not. - movieBounds.size.height += controllerBarHeight; - else - movieBounds.size.height += 15; - } - - movieBounds.size.width = movieSize.width; - - /* We need to find out if the preview movie needs to be scaled down so - * that it doesn't overflow our available viewing container (just like for image - * in -displayPreview) for HD sources, etc. [fPictureViewArea frame].size.height*/ - if( (movieBounds.size.height) > [fPictureViewArea frame].size.height || scaleToScreen == YES ) - { - /* The preview movie would be larger than the available viewing area - * in the preview movie, so we go ahead and scale it down to the same size - * as the still preview or we readjust our window to allow for the added height if need be - */ - NSSize displaySize = NSMakeSize( ( CGFloat ) movieBounds.size.width, ( CGFloat ) movieBounds.size.height ); - NSSize viewSize = [self optimalViewSizeForImageSize:displaySize]; - if( [self viewNeedsToResizeToSize:viewSize] ) { - [self resizeSheetForViewSize:viewSize]; - [self setViewSize:viewSize]; - } - [fMovieView setFrameSize:viewSize]; - } - else - { - /* Since the preview movie is smaller than the available viewing area - * we can go ahead and use the preview movies native size */ - [fMovieView setFrameSize:movieBounds.size]; - } - - //lets reposition the movie if need be - - NSPoint origin = [fPictureViewArea frame].origin; - origin.x += trunc( ( [fPictureViewArea frame].size.width - - [fMovieView frame].size.width ) / 2.0 ); - /* We need to detect whether or not we are currently less than the available height.*/ - if( movieBounds.size.height < [fPictureView frame].size.height ) - { - /* If we are, we are adding 15 to the height to allow for the controller bar so - * we need to subtract half of that for the origin.y to get the controller bar - * below the movie to it lines up vertically with where our still preview was - */ - origin.y += trunc( ( ( [fPictureViewArea frame].size.height - - [fMovieView frame].size.height ) / 2.0 ) - 7.5 ); - } - else - { - /* if we are >= to the height of the picture view area, the controller bar - * gets taken care of with picture resizing, so we do not want to offset the height - */ - origin.y += trunc( ( [fPictureViewArea frame].size.height - - [fMovieView frame].size.height ) / 2.0 ); - } - [fMovieView setFrameOrigin:origin]; - [fMovieView setMovie:aMovie]; - [fMovieView setHidden:NO]; - // to actually play the movie - [fMovieView play:aMovie]; - } - } - isEncoding = NO; -} - -@end - -@implementation PreviewController (Private) - -// -// -[PictureController(Private) optimalViewSizeForImageSize:] -// -// Given the size of the preview image to be shown, returns the best possible -// size for the view. -// -- (NSSize)optimalViewSizeForImageSize: (NSSize)imageSize -{ - // The min size is 320x240 - CGFloat minWidth = 480.0; - CGFloat minHeight = 360.0; - - NSSize screenSize = [[NSScreen mainScreen] frame].size; - NSSize sheetSize = [[self window] frame].size; - NSSize viewAreaSize = [fPictureViewArea frame].size; - CGFloat paddingX = sheetSize.width - viewAreaSize.width; - CGFloat paddingY = sheetSize.height - viewAreaSize.height; - CGFloat maxWidth; - CGFloat maxHeight; - - if (isFullScreen) - { - /* We are in full screen mode so lets use the full screen if we need to */ - maxWidth = screenSize.width - paddingX; - maxHeight = screenSize.height - paddingY; - } - else - { - // The max size of the view is when the sheet is taking up 85% of the screen. - maxWidth = (0.85 * screenSize.width) - paddingX; - maxHeight = (0.85 * screenSize.height) - paddingY; - } - - NSSize resultSize = imageSize; - - // Its better to have a view that's too small than a view that's too big, so - // apply the maximum constraints last. - if( resultSize.width < minWidth ) - { - resultSize.height *= (minWidth / resultSize.width); - resultSize.width = minWidth; - } - if( resultSize.height < minHeight ) - { - resultSize.width *= (minHeight / resultSize.height); - resultSize.height = minHeight; - } - if( resultSize.width > maxWidth ) - { - resultSize.height *= (maxWidth / resultSize.width); - resultSize.width = maxWidth; - } - if( resultSize.height > maxHeight ) - { - resultSize.width *= (maxHeight / resultSize.height); - resultSize.height = maxHeight; - } - - if (scaleToScreen == YES) - { - CGFloat screenAspect; - CGFloat viewAreaAspect; - //note, a mbp 15" at 1440 x 900 is a 1.6 ar - screenAspect = screenSize.width / screenSize.height; - - // Note, a standard dvd will use 720 x 480 which is a 1.5 - viewAreaAspect = viewAreaSize.width / viewAreaSize.height; - - if (screenAspect < viewAreaAspect) - { - resultSize.width = screenSize.width; - resultSize.height = (screenSize.width / viewAreaAspect); - } - else - { - resultSize.height = screenSize.height; - resultSize.width = resultSize.height * viewAreaAspect; - } - - } - - return resultSize; - - -} - -// -// -[PictureController(Private) resizePanelForViewSize:animate:] -// -// Resizes the entire window to accomodate a view of a particular size. -// -- (void)resizeSheetForViewSize: (NSSize)viewSize -{ - // Figure out the deltas for the new frame area - NSSize currentSize = [fPictureViewArea frame].size; - CGFloat deltaX = viewSize.width - currentSize.width; - CGFloat deltaY = viewSize.height - currentSize.height; - - // Now resize the whole panel by those same deltas, but don't exceed the min - NSRect frame = [[self window] frame]; - NSSize maxSize = [[self window] maxSize]; - NSSize minSize = [[self window] minSize]; - frame.size.width += deltaX; - frame.size.height += deltaY; - if( frame.size.width < minSize.width ) - { - frame.size.width = minSize.width; - } - - if( frame.size.height < minSize.height ) - { - frame.size.height = minSize.height; - } - - - // But now the sheet is off-center, so also shift the origin to center it and - // keep the top aligned. - if( frame.size.width != [[self window] frame].size.width ) - frame.origin.x -= (deltaX / 2.0); - - if (isFullScreen) - { - if( frame.size.height != [[self window] frame].size.height ) - { - frame.origin.y -= (deltaY / 2.0); - } - else - { - if( frame.size.height != [[self window] frame].size.height ) - frame.origin.y -= deltaY; - } - - [[self window] setFrame:frame display:YES animate:NO]; - } - else - { - /* Since upon launch we can open up the preview window if it was open - * the last time we quit (and at the size it was) we want to make - * sure that upon resize we do not have the window off the screen - * So check the origin against the screen origin and adjust if - * necessary. - */ - NSSize screenSize = [[[self window] screen] frame].size; - NSPoint screenOrigin = [[[self window] screen] frame].origin; - /* our origin is off the screen to the left*/ - if (frame.origin.x < screenOrigin.x) - { - /* so shift our origin to the right */ - frame.origin.x = screenOrigin.x; - } - else if ((frame.origin.x + frame.size.width) > (screenOrigin.x + screenSize.width)) - { - /* the right side of the preview is off the screen, so shift to the left */ - frame.origin.x = (screenOrigin.x + screenSize.width) - frame.size.width; - } - - [[self window] setFrame:frame display:YES animate:YES]; - } - -} - -// -// -[PictureController(Private) setViewSize:] -// -// Changes the view's size and centers it vertically inside of its area. -// Assumes resizeSheetForViewSize: has already been called. -// -- (void)setViewSize: (NSSize)viewSize -{ - /* special case for scaleToScreen */ - if (scaleToScreen == YES) - { - /* for scaleToScreen, we expand the fPictureView to fit the entire screen */ - NSSize areaSize = [fPictureViewArea frame].size; - CGFloat viewSizeAspect = viewSize.width / viewSize.height; - if (viewSizeAspect > 1.0) // we are wider than taller, so expand the width to fill the area and scale the height - { - viewSize.width = areaSize.width; - viewSize.height = viewSize.width / viewSizeAspect; - } - else - { - viewSize.height = areaSize.height; - viewSize.width = viewSize.height * viewSizeAspect; - } - - } - - [fPictureView setFrameSize:viewSize]; - - // center it vertically and horizontally - NSPoint origin = [fPictureViewArea frame].origin; - origin.y += ([fPictureViewArea frame].size.height - - [fPictureView frame].size.height) / 2.0; - - origin.x += ([fPictureViewArea frame].size.width - - [fPictureView frame].size.width) / 2.0; - - origin.x = floor( origin.x ); - origin.y = floor( origin.y ); - - [fPictureView setFrameOrigin:origin]; -} - - -- (BOOL)viewNeedsToResizeToSize: (NSSize)newSize -{ - NSSize viewSize = [fPictureViewArea frame].size; - return (newSize.width != viewSize.width || newSize.height != viewSize.height); -} - -@end diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index ce2d2602a..28845e6e0 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -31,7 +31,7 @@ 4DD93F97082036E8008E1322 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 4DD93F9A082036E8008E1322 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.mm */; settings = {ATTRIBUTES = (); }; }; 4DD93F9B082036E8008E1322 /* Controller.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4DF3C8CC052889CD00A80101 /* Controller.mm */; }; - 4DD93F9E082036E8008E1322 /* HBPreviewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4D1FD382073D19CE00E46515 /* HBPreviewController.mm */; }; + 4DD93F9E082036E8008E1322 /* HBPreviewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D1FD382073D19CE00E46515 /* HBPreviewController.m */; }; 4DD93FA2082036E8008E1322 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 4DD93FA3082036E8008E1322 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DEB2024052B055F00C39CA9 /* IOKit.framework */; }; 4DD93FA4082036E8008E1322 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DDE9724052B7B2B00C39CA9 /* OpenGL.framework */; }; @@ -156,7 +156,7 @@ 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 4D1FD381073D19CE00E46515 /* HBPreviewController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = HBPreviewController.h; sourceTree = ""; }; - 4D1FD382073D19CE00E46515 /* HBPreviewController.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = HBPreviewController.mm; sourceTree = ""; }; + 4D1FD382073D19CE00E46515 /* HBPreviewController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = HBPreviewController.m; sourceTree = ""; }; 4DDE9724052B7B2B00C39CA9 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; 4DEB2024052B055F00C39CA9 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = ""; }; 4DF3C8CB052889CD00A80101 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = ""; }; @@ -348,8 +348,8 @@ A2BEA5FA0F2A1ED1001CE7A1 /* PictureController.mm */, A22C85EA0D05D35000C10E36 /* HBPresets.h */, A22C85EB0D05D35000C10E36 /* HBPresets.m */, - 4D1FD382073D19CE00E46515 /* HBPreviewController.mm */, 4D1FD381073D19CE00E46515 /* HBPreviewController.h */, + 4D1FD382073D19CE00E46515 /* HBPreviewController.m */, 4DF3C8CB052889CD00A80101 /* Controller.h */, 593034E90BBA39A100172349 /* ChapterTitles.h */, 593034EA0BBA39A100172349 /* ChapterTitles.m */, @@ -611,7 +611,7 @@ 59CBD2650BBB4D1B004A3BE3 /* ChapterTitles.m in Sources */, 4DD93F9A082036E8008E1322 /* main.mm in Sources */, 4DD93F9B082036E8008E1322 /* Controller.mm in Sources */, - 4DD93F9E082036E8008E1322 /* HBPreviewController.mm in Sources */, + 4DD93F9E082036E8008E1322 /* HBPreviewController.m in Sources */, A2A1EC3A0C76C58400827E0D /* HBDVDDetector.m in Sources */, 253886020BFE0A5B0064E995 /* HBOutputRedirect.m in Sources */, 253886180BFE0C160064E995 /* HBOutputPanelController.m in Sources */, -- cgit v1.2.3