updating header info, adding AVKit support, iOS support

(cherry picked from commit a485823cb7 and 2e2cfd9d55)
This commit is contained in:
Stefan Csomor
2014-07-15 19:12:35 +02:00
committed by Tobias Taschner
parent 34527f7473
commit 32464a364f

View File

@@ -1,10 +1,10 @@
/////////////////////////////////////////////////////////////////////////////
// Name: src/cocoa/mediactrl.cpp
// Name: src/osx/cocoa/mediactrl.mm
// Purpose: Built-in Media Backends for Cocoa
// Author: Ryan Norton <wxprojects@comcast.net>
// Author: Ryan Norton <wxprojects@comcast.net>, Stefan Csomor
// Modified by:
// Created: 02/03/05
// Copyright: (c) 2004-2005 Ryan Norton, (c) 2005 David Elliot
// Copyright: (c) 2004-2005 Ryan Norton, (c) 2005 David Elliot, (c) Stefan Csomor
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
@@ -36,10 +36,34 @@
#include "wx/osx/private.h"
#ifndef wxOSX_USE_QTKIT
#if wxOSX_USE_IPHONE
#define wxOSX_USE_QTKIT 0
#define wxOSX_USE_AVFOUNDATION 1
#else
#define wxOSX_USE_QTKIT 1
#define wxOSX_USE_AVFOUNDATION 0
#endif
#else
#if wxOSX_USE_QTKIT
#define wxOSX_USE_AVFOUNDATION 0
#else
#define wxOSX_USE_AVFOUNDATION 1
#endif
#endif
#if wxOSX_USE_AVFOUNDATION && wxOSX_USE_COCOA && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
#define wxOSX_USE_AVKIT 1
#else
#define wxOSX_USE_AVKIT 0
#endif
//===========================================================================
// BACKEND DECLARATIONS
//===========================================================================
#if wxOSX_USE_QTKIT
//---------------------------------------------------------------------------
//
// wxQTMediaBackend
@@ -147,9 +171,9 @@ private:
-(void)dealloc
{
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:self];
[nc removeObserver:self];
[super dealloc];
[super dealloc];
}
-(wxQTMediaBackend*) backend
@@ -173,17 +197,17 @@ private:
- (void)movieRateChanged:(NSNotification *)notification
{
NSDictionary *userInfo = [notification userInfo];
NSNumber *newRate = [userInfo objectForKey:QTMovieRateDidChangeNotificationParameter];
NSDictionary *userInfo = [notification userInfo];
if ([newRate intValue] == 0)
{
m_backend->QueuePauseEvent();
}
NSNumber *newRate = [userInfo objectForKey:QTMovieRateDidChangeNotificationParameter];
if ([newRate intValue] == 0)
{
m_backend->QueuePauseEvent();
}
else if ( [self isPlaying] == NO )
{
m_backend->QueuePlayEvent();
m_backend->QueuePlayEvent();
}
}
@@ -207,12 +231,12 @@ private:
-(BOOL)isPlaying
{
if ([self rate] == 0)
{
return NO;
}
return YES;
if ([self rate] == 0)
{
return NO;
}
return YES;
}
@end
@@ -433,6 +457,547 @@ void wxQTMediaBackend::DoShowPlayerControls(wxMediaCtrlPlayerControls flags)
}
}
#endif
#if wxOSX_USE_AVFOUNDATION
//---------------------------------------------------------------------------
//
// wxAVMediaBackend
//
//---------------------------------------------------------------------------
#import <AVFoundation/AVFoundation.h>
#if wxOSX_USE_AVKIT
#import <AVKit/AVKit.h>
#endif
class WXDLLIMPEXP_FWD_MEDIA wxAVMediaBackend;
static void *AVSPPlayerItemStatusContext = &AVSPPlayerItemStatusContext;
static void *AVSPPlayerRateContext = &AVSPPlayerRateContext;
@interface wxAVPlayer : AVPlayer {
AVPlayerLayer *playerLayer;
wxAVMediaBackend* m_backend;
}
-(BOOL)isPlaying;
@property (retain) AVPlayerLayer *playerLayer;
@end
class WXDLLIMPEXP_MEDIA wxAVMediaBackend : public wxMediaBackendCommonBase
{
public:
wxAVMediaBackend();
~wxAVMediaBackend();
virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
long style,
const wxValidator& validator,
const wxString& name);
virtual bool Play();
virtual bool Pause();
virtual bool Stop();
virtual bool Load(const wxString& fileName);
virtual bool Load(const wxURI& location);
virtual wxMediaState GetState();
virtual bool SetPosition(wxLongLong where);
virtual wxLongLong GetPosition();
virtual wxLongLong GetDuration();
virtual void Move(int x, int y, int w, int h);
wxSize GetVideoSize() const;
virtual double GetPlaybackRate();
virtual bool SetPlaybackRate(double dRate);
virtual double GetVolume();
virtual bool SetVolume(double dVolume);
void Cleanup();
void FinishLoad();
virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags);
private:
void DoShowPlayerControls(wxMediaCtrlPlayerControls flags);
wxSize m_bestSize; //Original movie size
wxAVPlayer* m_player; //AVPlayer handle/instance
wxMediaCtrlPlayerControls m_interfaceflags; // Saved interface flags
wxDECLARE_DYNAMIC_CLASS(wxAVMediaBackend);
};
// --------------------------------------------------------------------------
// wxAVMediaBackend
// --------------------------------------------------------------------------
@implementation wxAVPlayer
@synthesize playerLayer;
- (id) init
{
self = [super init];
[self addObserver:self forKeyPath:@"currentItem.status"
options:NSKeyValueObservingOptionNew context:AVSPPlayerItemStatusContext];
[self addObserver:self forKeyPath:@"rate"
options:NSKeyValueObservingOptionNew context:AVSPPlayerRateContext];
return self;
}
- (void)dealloc
{
[playerLayer release];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self removeObserver:self forKeyPath:@"rate" context:AVSPPlayerRateContext];
[self removeObserver:self forKeyPath:@"currentItem.status" context:AVSPPlayerItemStatusContext];
[super dealloc];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == AVSPPlayerItemStatusContext)
{
id val = [change objectForKey:NSKeyValueChangeNewKey];
if ( val != [NSNull null ] )
{
AVPlayerStatus status = [ val integerValue];
switch (status)
{
case AVPlayerItemStatusUnknown:
break;
case AVPlayerItemStatusReadyToPlay:
[[NSNotificationCenter defaultCenter]
addObserver:self selector:@selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification object:self.currentItem];
m_backend->FinishLoad();
break;
case AVPlayerItemStatusFailed:
break;
default:
break;
}
}
}
else if (context == AVSPPlayerRateContext)
{
NSNumber* newRate = [change objectForKey:NSKeyValueChangeNewKey];
if ([newRate intValue] == 0)
{
m_backend->QueuePauseEvent();
}
else if ( [self isPlaying] == NO )
{
m_backend->QueuePlayEvent();
}
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
-(wxAVMediaBackend*) backend
{
return m_backend;
}
-(void) setBackend:(wxAVMediaBackend*) backend
{
m_backend = backend;
}
- (void)playerItemDidReachEnd:(NSNotification *)notification
{
if ( m_backend )
{
if ( m_backend->SendStopEvent() )
m_backend->QueueFinishEvent();
}
}
-(BOOL)isPlaying
{
if ([self rate] == 0)
{
return NO;
}
return YES;
}
@end
#if wxOSX_USE_IPHONE
@interface wxAVView : UIView
{
}
@end
@implementation wxAVView
+ (void)initialize
{
static BOOL initialized = NO;
if (!initialized)
{
initialized = YES;
wxOSXIPhoneClassAddWXMethods( self );
}
}
+ (Class)layerClass
{
return [AVPlayerLayer class];
}
- (id) initWithFrame:(CGRect)rect player:(wxAVPlayer*) player
{
if ( !(self=[super initWithFrame:rect]) )
return nil;
AVPlayerLayer* playerLayer = (AVPlayerLayer*) [self layer];
[playerLayer setPlayer: player];
[player setPlayerLayer:playerLayer];
return self;
}
- (AVPlayerLayer*) playerLayer
{
return (AVPlayerLayer*) [self layer];
}
@end
#else
#if wxOSX_USE_AVKIT
@interface wxAVPlayerView : AVPlayerView
{
}
@end
@implementation wxAVPlayerView
+ (void)initialize
{
static BOOL initialized = NO;
if (!initialized)
{
initialized = YES;
wxOSXCocoaClassAddWXMethods( self );
}
}
- (id) initWithFrame:(NSRect)rect player:(wxAVPlayer*) player
{
if ( !(self=[super initWithFrame:rect]) )
return nil;
self.player = player;
return self;
}
- (AVPlayerLayer*) playerLayer
{
return (AVPlayerLayer*) [[[self layer] sublayers] firstObject];
}
@end
#endif // wxOSX_USE_AVKIT
@interface wxAVView : NSView
{
}
@end
@implementation wxAVView
+ (void)initialize
{
static BOOL initialized = NO;
if (!initialized)
{
initialized = YES;
wxOSXCocoaClassAddWXMethods( self );
}
}
- (id) initWithFrame:(NSRect)rect player:(AVPlayer*) player
{
if ( !(self=[super initWithFrame:rect]) )
return nil;
[self setWantsLayer:YES];
AVPlayerLayer* playerlayer = [[AVPlayerLayer playerLayerWithPlayer: player] retain];
[player setPlayerLayer:playerlayer];
[playerlayer setFrame:[[self layer] bounds]];
[playerlayer setAutoresizingMask:kCALayerWidthSizable | kCALayerHeightSizable];
[[self layer] addSublayer:playerlayer];
return self;
}
- (AVPlayerLayer*) playerLayer
{
return (AVPlayerLayer*) [[[self layer] sublayers] firstObject];
}
@end
#endif
IMPLEMENT_DYNAMIC_CLASS(wxAVMediaBackend, wxMediaBackend);
wxAVMediaBackend::wxAVMediaBackend() :
m_player(nil),
m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE)
{
}
wxAVMediaBackend::~wxAVMediaBackend()
{
Cleanup();
}
bool wxAVMediaBackend::CreateControl(wxControl* inctrl, wxWindow* parent,
wxWindowID wid,
const wxPoint& pos,
const wxSize& size,
long style,
const wxValidator& validator,
const wxString& name)
{
wxMediaCtrl* mediactrl = (wxMediaCtrl*) inctrl;
mediactrl->DontCreatePeer();
if ( !mediactrl->wxControl::Create(
parent, wid, pos, size,
wxWindow::MacRemoveBordersFromStyle(style),
validator, name))
{
return false;
}
m_player = [[wxAVPlayer alloc] init];
[m_player setBackend:this];
NSRect r = wxOSXGetFrameForControl( mediactrl, pos , size ) ;
WXWidget view = NULL;
#if wxOSX_USE_AVKIT
if ( NSClassFromString(@"AVPlayerView") )
{
view = [[wxAVPlayerView alloc] initWithFrame: r player:m_player];
[(wxAVPlayerView*) view setControlsStyle:AVPlayerViewControlsStyleNone];
}
#endif
if ( view == NULL )
{
view = [[wxAVView alloc] initWithFrame: r player:m_player];
}
#if wxOSX_USE_IPHONE
wxWidgetIPhoneImpl* impl = new wxWidgetIPhoneImpl(mediactrl,view);
#else
wxWidgetCocoaImpl* impl = new wxWidgetCocoaImpl(mediactrl,view);
#endif
mediactrl->SetPeer(impl);
m_ctrl = mediactrl;
return true;
}
bool wxAVMediaBackend::Load(const wxString& fileName)
{
return Load(
wxURI(
wxString( wxT("file://") ) + fileName
)
);
}
bool wxAVMediaBackend::Load(const wxURI& location)
{
wxCFStringRef uri(location.BuildURI());
NSURL *url = [NSURL URLWithString: uri.AsNSString()];
AVAsset* asset = [AVAsset assetWithURL:url];
if (! asset )
return false;
if ( [asset isPlayable] )
{
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
[m_player replaceCurrentItemWithPlayerItem:playerItem];
return playerItem != nil;
}
return false;
}
void wxAVMediaBackend::FinishLoad()
{
DoShowPlayerControls(m_interfaceflags);
AVPlayerItem *playerItem = [m_player currentItem];
CGSize s = [playerItem presentationSize];
m_bestSize = wxSize(s.width, s.height);
NotifyMovieLoaded();
}
bool wxAVMediaBackend::Play()
{
[m_player play];
return true;
}
bool wxAVMediaBackend::Pause()
{
[m_player pause];
return true;
}
bool wxAVMediaBackend::Stop()
{
[m_player pause];
[m_player seekToTime:kCMTimeZero];
return true;
}
double wxAVMediaBackend::GetVolume()
{
return [m_player volume];
}
bool wxAVMediaBackend::SetVolume(double dVolume)
{
[m_player setVolume:dVolume];
return true;
}
double wxAVMediaBackend::GetPlaybackRate()
{
return [m_player rate];
}
bool wxAVMediaBackend::SetPlaybackRate(double dRate)
{
[m_player setRate:dRate];
return true;
}
bool wxAVMediaBackend::SetPosition(wxLongLong where)
{
[m_player seekToTime:CMTimeMakeWithSeconds(where.GetValue() / 1000.0, 1)
toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
return true;
}
wxLongLong wxAVMediaBackend::GetPosition()
{
return CMTimeGetSeconds([m_player currentTime])*1000.0;
}
wxLongLong wxAVMediaBackend::GetDuration()
{
AVPlayerItem *playerItem = [m_player currentItem];
if ([playerItem status] == AVPlayerItemStatusReadyToPlay)
return CMTimeGetSeconds([[playerItem asset] duration])*1000.0;
else
return 0.f;
}
wxMediaState wxAVMediaBackend::GetState()
{
if ( [m_player isPlaying] )
return wxMEDIASTATE_PLAYING;
else
{
if ( GetPosition() == 0 )
return wxMEDIASTATE_STOPPED;
else
return wxMEDIASTATE_PAUSED;
}
}
void wxAVMediaBackend::Cleanup()
{
[m_player pause];
[m_player release];
m_player = nil;
}
wxSize wxAVMediaBackend::GetVideoSize() const
{
return m_bestSize;
}
void wxAVMediaBackend::Move(int x, int y, int w, int h)
{
// as we have a native player, no need to move the video area
}
bool wxAVMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
{
if ( m_interfaceflags != flags )
DoShowPlayerControls(flags);
m_interfaceflags = flags;
return true;
}
void wxAVMediaBackend::DoShowPlayerControls(wxMediaCtrlPlayerControls flags)
{
#if wxOSX_USE_AVKIT
NSView* view = m_ctrl->GetHandle();
if ( [view isKindOfClass:[wxAVPlayerView class]] )
{
wxAVPlayerView* playerView = (wxAVPlayerView*) view;
if (flags == wxMEDIACTRLPLAYERCONTROLS_NONE )
playerView.controlsStyle = AVPlayerViewControlsStyleNone;
else
playerView.controlsStyle = AVPlayerViewControlsStyleDefault;
}
#endif
}
#endif
//in source file that contains stuff you don't directly use
#include "wx/html/forcelnk.h"
FORCE_LINK_ME(basewxmediabackends);