Skip to content

Commit

Permalink
Trade QuickTime for AVFoundation
Browse files Browse the repository at this point in the history
- The API Movist was using to get textures for display
  didn't make the transition to 64-bit so I've ditched
  it in favor of AVFoundation because QuickTime appears
  to be the past while AVFoundation is the future.
- Switched to building against 10.7 for some AVFoundation
  stuff (AVPlayerLayer specifically).
- Movist is now 64-bit!
- Switched to CoreAnimtion for MMovieView with a
  specialized layer for each movie type.
- TREMENDOUS HACKS! Video and audio plays but I've broken
  a number of things in the process. The main one
  is subtitles and the OSD stuff. They're still there,
  just not being displayed. Aspect ratios aren't
  really being respected (try and fullscreen a video).
  The plan is to put them into their own layers.
- Sadly, we can't use Perian since that's a QT component
  but the only thing we really lose is fancy Perian
  subtitles (since Movist provides FFMPEG/libav decoding).
  This can be fixed by adding fancy subtitle rendering
  to Movist (someday!).
  • Loading branch information
samiamwork committed Feb 18, 2013
1 parent 25b6f9b commit 0552ed9
Show file tree
Hide file tree
Showing 21 changed files with 1,450 additions and 1,510 deletions.
3 changes: 1 addition & 2 deletions AppController_Open.m
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,7 @@ - (BOOL)openMovie:(NSURL*)movieURL movieClass:(Class)movieClass
// open movie
NSError* error;
MMovie* movie = [self movieFromURL:movieURL withMovieClass:movieClass error:&error];
if (!movie || ![movie setOpenGLContext:[_movieView openGLContext]
pixelFormat:[_movieView pixelFormat] error:&error]) {
if (!movie) {
[self closeMovie];
if ([self isFullScreen]) {
NSString* s = [movieURL isFileURL] ? [movieURL path] : [movieURL absoluteString];
Expand Down
1,583 changes: 712 additions & 871 deletions English.lproj/MainMenu.nib/designable.nib

Large diffs are not rendered by default.

Binary file modified English.lproj/MainMenu.nib/keyedobjects.nib
Binary file not shown.
10 changes: 3 additions & 7 deletions FullScreener_Transition.m
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@ - (void)hideMainMenuAndDock
else if (p.y < NSMinY(rc)) { // bottom-side dock
p.y = NSMinY(rc) + margin;
}
CGDisplayMoveCursorToPoint([_movieView displayID],
CGPointMake(p.x, NSMaxY(rc) - p.y));
// TODO: fix
// CGDisplayMoveCursorToPoint([_movieView displayID],
// CGPointMake(p.x, NSMaxY(rc) - p.y));
}
GetSystemUIMode(&_normalSystemUIMode, &_normalSystemUIOptions);
if (_autoShowDock) {
Expand All @@ -73,10 +74,8 @@ - (void)hideMainMenuAndDock
- (void)attachMovieViewToFullWindow
{
[_mainWindow disableScreenUpdatesUntilFlush];
[_movieView lockDraw];
[_movieView removeFromSuperviewWithoutNeedingDisplay];
[_fullWindow setMovieView:_movieView];
[_movieView unlockDraw];

if ([_fullWindow level] == DesktopWindowLevel) {
[_fullWindow orderBack:nil];
Expand All @@ -94,13 +93,10 @@ - (void)detachMovieViewFromFullWindow
[_fullWindow orderOut:self];

// move _movieView to _mainWindow from _fullWindow
[_movieView lockDraw];
[_movieView removeFromSuperviewWithoutNeedingDisplay];
[[_mainWindow contentView] addSubview:_movieView];
[_movieView setFrame:_movieViewRect];
[_movieView updateMovieRect:FALSE];
[_movieView unlockDraw];
[_movieView display];

[_mainWindow makeFirstResponder:_movieView];
[_mainWindow makeKeyAndOrderFront:nil];
Expand Down
11 changes: 10 additions & 1 deletion MMovie.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#import "MMovie.h"
#import "FFTrack.h"
#import <AVFoundation/AVFoundation.h> // Needed to get the AVAssetTrack in the MTrack setEnabled: hack

@implementation MTrack

Expand Down Expand Up @@ -75,7 +76,15 @@ - (void)setAudioSampleRate:(float)rate { _audioSampleRate = rate; }
- (BOOL)isEnabled { return [_impl isEnabled]; }
- (void)setEnabled:(BOOL)enabled
{
[_impl setEnabled:enabled];
if([_impl isKindOfClass:[AVAssetTrack class]])
{
// TODO: fix this
// Enabled state of AVAssetTrack is readonly
}
else
{
[_impl setEnabled:enabled];
}

if (enabled) {
[_movie trackEnabled:self];
Expand Down
16 changes: 16 additions & 0 deletions MMovieLayer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// MMovieLayer.h
// Movist
//
// Created by Nur Monson on 2/16/13.
//
//

#import <Foundation/Foundation.h>

@class MMovie;

@protocol MMovieLayer <NSObject>
- (void)setMovie:(MMovie*)newMovie;
- (MMovie*)movie;
@end
21 changes: 21 additions & 0 deletions MMovieLayer_AVFoundation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// MMovieLayer_AVFoundation.h
// Movist
//
// Created by Nur Monson on 2/18/13.
//
//

#import <AVFoundation/AVFoundation.h>
#import "MMovieLayer.h"

@class MMovie_QuickTime;

@interface MMovieLayer_AVFoundation : AVPlayerLayer <MMovieLayer>
{
MMovie_QuickTime* _movie;
}

- (void)setMovie:(MMovie_QuickTime*)newMovie;
- (MMovie*)movie;
@end
28 changes: 28 additions & 0 deletions MMovieLayer_AVFoundation.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// MMovieLayer_AVFoundation.m
// Movist
//
// Created by Nur Monson on 2/18/13.
//
//

#import "MMovieLayer_AVFoundation.h"
#import "MMovie_QuickTime.h"

@implementation MMovieLayer_AVFoundation

- (void)setMovie:(MMovie_QuickTime*)newMovie
{
if(newMovie == _movie)
return;
[_movie release];
_movie = [newMovie retain];
self.player = [newMovie player];
}

- (MMovie*)movie
{
return _movie;
}

@end
40 changes: 40 additions & 0 deletions MMovieLayer_FFMPEG.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// Movist
//
// This file is part of Movist.
//
// Movist is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Movist is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

#import <Cocoa/Cocoa.h>
#import <QuartzCore/QuartzCore.h>
#import "MMovieLayer.h"

@class MMovie_FFmpeg;

@interface MMovieLayer_FFMPEG : NSOpenGLLayer <MMovieLayer>
{
BOOL _configured;
BOOL _movieNeedsGLContext;
MMovie_FFmpeg* _movie;
CVOpenGLTextureRef _image;
CIContext* _ciContext;
CVDisplayLinkRef _displayLink;
CGDirectDisplayID _displayID;
// NSRecursiveLock* _drawLock;
}

- (void)setMovie:(MMovie_FFmpeg*)newMovie;
- (MMovie*)movie;
@end
216 changes: 216 additions & 0 deletions MMovieLayer_FFMPEG.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
//
// MMovieLayer_FFMPEG.m
// Movist
//
// Created by Nur Monson on 7/29/12.
//
//

#import "MMovieLayer_FFMPEG.h"
#import "MMovie_FFMPEG.h"

@interface MMovieLayer_FFMPEG ()
- (void)configure;
- (CVReturn)updateImage:(const CVTimeStamp*)timeStamp;
@end

static CVReturn displayLinkOutputCallback(CVDisplayLinkRef displayLink,
const CVTimeStamp* inNow,
const CVTimeStamp* inOutputTime,
CVOptionFlags flagsIn,
CVOptionFlags* flagsOut,
void* displayLinkContext)
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
return [(MMovieLayer_FFMPEG*)displayLinkContext updateImage:inOutputTime];
}

@implementation MMovieLayer_FFMPEG

- (id)init
{
if((self = [super init]))
{
[self setOpaque:YES];
_configured = NO;
CGColorRef blue = CGColorCreateGenericRGB(0.0, 0.5, 1.0, 1.0);
self.backgroundColor = blue;
CGColorRelease(blue);
self.asynchronous = YES;
[self setNeedsDisplayOnBoundsChange:YES];

NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(windowMoved:)
name:NSWindowDidMoveNotification object:self.view.window];

//[self initCoreVideo];
}
return self;
}

- (void)dealloc
{
[self cleanupCoreVideo];
CVOpenGLTextureRelease(_image);
[_ciContext release];
[_movie release];

[super dealloc];
}

- (BOOL)initCoreVideo
{
// TODO: not sure we can assume that the current display will be the main display on init
_displayID = CGMainDisplayID();
CVReturn cvRet = CVDisplayLinkCreateWithCGDisplay(_displayID, &_displayLink);
if (cvRet != kCVReturnSuccess) {
//TRACE(@"CVDisplayLinkCreateWithCGDisplay() failed: %d", cvRet);
return FALSE;
}
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(_displayLink,
[[self openGLContext] CGLContextObj],
[[self openGLPixelFormat] CGLPixelFormatObj]);
CVDisplayLinkSetOutputCallback(_displayLink, &displayLinkOutputCallback, self);
CVDisplayLinkStart(_displayLink);
return TRUE;
}

- (void)cleanupCoreVideo
{
if (_displayLink)
{
CVDisplayLinkStop(_displayLink);
CVDisplayLinkRelease(_displayLink);
}
}

- (void)setMovie:(MMovie_FFmpeg*)newMovie
{
if(newMovie == _movie)
return;

[_movie release];
_movie = [newMovie retain];
_movieNeedsGLContext = YES;
}

- (MMovie*)movie
{
return _movie;
}

- (void)reshape
{
// //TRACE(@"%s", __PRETTY_FUNCTION__);
// [_drawLock lock];
//
// NSRect bounds = [self bounds];
// glViewport(0, 0, bounds.size.width, bounds.size.height);
//
// glMatrixMode(GL_PROJECTION);
// glLoadIdentity();
// glOrtho(0, bounds.size.width, 0, bounds.size.height, -1.0f, 1.0f);
//
// glMatrixMode(GL_MODELVIEW);
// glLoadIdentity();
//
// [_drawLock unlock];
}

- (CGDirectDisplayID)currentDisplayID
{
NSDictionary* deviceDesc = [[self.view.window screen] deviceDescription];
NSNumber* screenNumber = [deviceDesc objectForKey:@"NSScreenNumber"];

return (CGDirectDisplayID)[screenNumber intValue];
}

- (void)windowMoved:(NSNotification*)aNotification
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
CGDirectDisplayID displayID = [self currentDisplayID];
if (displayID != _displayID)
{
CVDisplayLinkSetCurrentCGDisplay(_displayLink, displayID);
_displayID = displayID;
}
}

- (void)configure
{
// TODO: put this in copyCGLContextForPixelFormat:
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
(id)colorSpace, kCIContextOutputColorSpace,
(id)colorSpace, kCIContextWorkingColorSpace, nil];
_ciContext = [[CIContext contextWithCGLContext:[self.openGLContext CGLContextObj]
pixelFormat:[self.openGLPixelFormat CGLPixelFormatObj]
colorSpace:colorSpace
options:dict] retain];
CGColorSpaceRelease(colorSpace);

//GLint swapInterval = 1;
//[[self openGLContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

_configured = YES;
}

- (CVReturn)updateImage:(const CVTimeStamp*)timeStamp
{
if(timeStamp == NULL)
return kCVReturnSuccess;
// if([_drawLock tryLock])
{
CVOpenGLTextureRef image = [_movie nextImage:timeStamp];
if(image)
{
CVOpenGLTextureRelease(_image);
_image = image;
}
// [_drawLock unlock];
}

return kCVReturnSuccess;
}

- (void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
{
// [_drawLock lock];

if(!_configured)
{
[self configure];
}
if(_movieNeedsGLContext)
{
NSError* error;
if(![_movie setOpenGLContext:self.openGLContext pixelFormat:self.openGLPixelFormat error:&error])
{
// TODO: return an bool FALSE and the NSError object
NSLog(@"error: %@", error);
}
_movieNeedsGLContext = NO;
}

// since we're async and not using displaylink callbacks
[self updateImage:timeStamp];
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, self.bounds.size.width, 0, self.bounds.size.height, -1.0f, 1.0f);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

if(_image)
{
CIImage* img = [CIImage imageWithCVImageBuffer:_image];
[_ciContext drawImage:img inRect:self.bounds fromRect:CVImageBufferGetCleanRect(_image)];
}

// [[self openGLContext] flushBuffer];
// [_drawLock unlock];
}

@end
Loading

0 comments on commit 0552ed9

Please sign in to comment.