1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/osx/cocoa/mediactrl.mm
3// Purpose:     Built-in Media Backends for Cocoa
4// Author:      Ryan Norton <wxprojects@comcast.net>, Stefan Csomor
5// Modified by:
6// Created:     02/03/05
7// Copyright:   (c) 2004-2005 Ryan Norton, (c) 2005 David Elliot, (c) Stefan Csomor
8// Licence:     wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11//===========================================================================
12//  DECLARATIONS
13//===========================================================================
14
15//---------------------------------------------------------------------------
16// Pre-compiled header stuff
17//---------------------------------------------------------------------------
18
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23#pragma hdrstop
24#endif
25
26//---------------------------------------------------------------------------
27// Compilation guard
28//---------------------------------------------------------------------------
29#if wxUSE_MEDIACTRL
30
31#include "wx/mediactrl.h"
32
33#ifndef WX_PRECOMP
34    #include "wx/timer.h"
35#endif
36
37#include "wx/osx/private.h"
38
39#ifndef wxOSX_USE_QTKIT
40    #if wxOSX_USE_IPHONE
41        #define wxOSX_USE_QTKIT 0
42        #define wxOSX_USE_AVFOUNDATION 1
43    #else
44        #define wxOSX_USE_QTKIT 1
45        #define wxOSX_USE_AVFOUNDATION 0
46    #endif
47#else
48    #if wxOSX_USE_QTKIT
49        #define wxOSX_USE_AVFOUNDATION 0
50    #else
51        #define wxOSX_USE_AVFOUNDATION 1
52    #endif
53#endif
54
55#if wxOSX_USE_AVFOUNDATION && wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 && defined(__LP64__)
56    #define wxOSX_USE_AVKIT 1
57#else
58    #define wxOSX_USE_AVKIT 0
59#endif
60
61//===========================================================================
62//  BACKEND DECLARATIONS
63//===========================================================================
64
65#if wxOSX_USE_QTKIT
66
67//---------------------------------------------------------------------------
68//
69//  wxQTMediaBackend
70//
71//---------------------------------------------------------------------------
72
73//---------------------------------------------------------------------------
74//  QT Includes
75//---------------------------------------------------------------------------
76#include <QTKit/QTKit.h>
77
78#include "wx/cocoa/autorelease.h"
79#include "wx/cocoa/string.h"
80
81class WXDLLIMPEXP_FWD_MEDIA wxQTMediaBackend;
82
83@interface wxQTMovie : QTMovie {
84
85    wxQTMediaBackend* m_backend;
86}
87
88-(BOOL)isPlaying;
89
90@end
91
92class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackendCommonBase
93{
94public:
95
96    wxQTMediaBackend();
97    ~wxQTMediaBackend();
98
99    virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
100                                     wxWindowID id,
101                                     const wxPoint& pos,
102                                     const wxSize& size,
103                                     long style,
104                                     const wxValidator& validator,
105                                     const wxString& name);
106
107    virtual bool Play();
108    virtual bool Pause();
109    virtual bool Stop();
110
111    virtual bool Load(const wxString& fileName);
112    virtual bool Load(const wxURI& location);
113
114    virtual wxMediaState GetState();
115
116    virtual bool SetPosition(wxLongLong where);
117    virtual wxLongLong GetPosition();
118    virtual wxLongLong GetDuration();
119
120    virtual void Move(int x, int y, int w, int h);
121    wxSize GetVideoSize() const;
122
123    virtual double GetPlaybackRate();
124    virtual bool SetPlaybackRate(double dRate);
125
126    virtual double GetVolume();
127    virtual bool SetVolume(double dVolume);
128
129    void Cleanup();
130    void FinishLoad();
131
132    virtual bool   ShowPlayerControls(wxMediaCtrlPlayerControls flags);
133private:
134    void DoShowPlayerControls(wxMediaCtrlPlayerControls flags);
135
136    wxSize m_bestSize;              //Original movie size
137    wxQTMovie* m_movie;               //QTMovie handle/instance
138    QTMovieView* m_movieview;       //QTMovieView instance
139
140    wxMediaCtrlPlayerControls m_interfaceflags; // Saved interface flags
141
142    wxDECLARE_DYNAMIC_CLASS(wxQTMediaBackend);
143};
144
145// --------------------------------------------------------------------------
146// wxQTMovie
147// --------------------------------------------------------------------------
148
149@implementation wxQTMovie
150
151- (id)initWithURL:(NSURL *)url error:(NSError **)errorPtr
152{
153    if ( [super initWithURL:url error:errorPtr] != nil )
154    {
155        m_backend = NULL;
156
157        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
158        [nc addObserver:self selector:@selector(movieDidEnd:)
159                   name:QTMovieDidEndNotification object:nil];
160        [nc addObserver:self selector:@selector(movieRateChanged:)
161                   name:QTMovieRateDidChangeNotification object:nil];
162        [nc addObserver:self selector:@selector(loadStateChanged:)
163                   name:QTMovieLoadStateDidChangeNotification object:nil];
164
165        return self;
166    }
167    else
168        return nil;
169}
170
171-(void)dealloc
172{
173    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
174    [nc removeObserver:self];
175
176    [super dealloc];
177}
178
179-(wxQTMediaBackend*) backend
180{
181    return m_backend;
182}
183
184-(void) setBackend:(wxQTMediaBackend*) backend
185{
186    m_backend = backend;
187}
188
189- (void)movieDidEnd:(NSNotification *)notification
190{
191    if ( m_backend )
192    {
193        if ( m_backend->SendStopEvent() )
194            m_backend->QueueFinishEvent();
195    }
196}
197
198- (void)movieRateChanged:(NSNotification *)notification
199{
200    NSDictionary *userInfo = [notification userInfo];
201
202    NSNumber *newRate = [userInfo objectForKey:QTMovieRateDidChangeNotificationParameter];
203
204    if ([newRate intValue] == 0)
205    {
206        m_backend->QueuePauseEvent();
207    }
208    else if ( [self isPlaying] == NO )
209    {
210        m_backend->QueuePlayEvent();
211    }
212}
213
214-(void)loadStateChanged:(NSNotification *)notification
215{
216    QTMovie *movie = [notification object];
217    long loadState = [[movie attributeForKey:QTMovieLoadStateAttribute] longValue];
218    if ( loadState == QTMovieLoadStateError )
219    {
220        // error occurred
221    }
222    else if (loadState >= QTMovieLoadStatePlayable)
223    {
224        // the movie has loaded enough media data to begin playing, but we don't have an event for that yet
225    }
226    else if (loadState >= QTMovieLoadStateComplete) // we might use QTMovieLoadStatePlaythroughOK
227    {
228        m_backend->FinishLoad();
229    }
230}
231
232-(BOOL)isPlaying
233{
234    if ([self rate] == 0)
235    {
236        return NO;
237    }
238
239    return YES;
240}
241
242@end
243
244// --------------------------------------------------------------------------
245// wxQTMediaBackend
246// --------------------------------------------------------------------------
247
248IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
249
250wxQTMediaBackend::wxQTMediaBackend() :
251    m_movie(nil), m_movieview(nil),
252    m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE)
253{
254}
255
256wxQTMediaBackend::~wxQTMediaBackend()
257{
258    Cleanup();
259}
260
261bool wxQTMediaBackend::CreateControl(wxControl* inctrl, wxWindow* parent,
262                                     wxWindowID wid,
263                                     const wxPoint& pos,
264                                     const wxSize& size,
265                                     long style,
266                                     const wxValidator& validator,
267                                     const wxString& name)
268{
269    wxMediaCtrl* mediactrl = (wxMediaCtrl*) inctrl;
270
271    mediactrl->DontCreatePeer();
272
273    if ( !mediactrl->wxControl::Create(
274                                       parent, wid, pos, size,
275                                       wxWindow::MacRemoveBordersFromStyle(style),
276                                       validator, name))
277    {
278        return false;
279    }
280
281    NSRect r = wxOSXGetFrameForControl( mediactrl, pos , size ) ;
282    QTMovieView* theView = [[QTMovieView alloc] initWithFrame: r];
283
284    wxWidgetCocoaImpl* impl = new wxWidgetCocoaImpl(mediactrl,theView);
285    mediactrl->SetPeer(impl);
286
287    m_movieview = theView;
288    // will be set up after load
289    [theView setControllerVisible:NO];
290
291    m_ctrl = mediactrl;
292    return true;
293}
294
295bool wxQTMediaBackend::Load(const wxString& fileName)
296{
297    return Load(
298                wxURI(
299                    wxString( wxT("file://") ) + fileName
300                     )
301               );
302}
303
304bool wxQTMediaBackend::Load(const wxURI& location)
305{
306    wxCFStringRef uri(location.BuildURI());
307    NSURL *url = [NSURL URLWithString: uri.AsNSString()];
308
309    if (! [wxQTMovie canInitWithURL:url])
310        return false;
311
312    [m_movie release];
313    wxQTMovie* movie = [[wxQTMovie alloc] initWithURL:url error: nil ];
314
315    m_movie = movie;
316    if (movie != nil)
317    {
318        [m_movie setBackend:this];
319        [m_movieview setMovie:movie];
320
321        // If the media file is able to be loaded quickly then there may not be
322        // any QTMovieLoadStateDidChangeNotification message sent, so we need to
323        // also check the load state here and finish our initialization if it has
324        // been loaded.
325        long loadState = [[m_movie attributeForKey:QTMovieLoadStateAttribute] longValue];
326        if (loadState >= QTMovieLoadStateComplete)
327        {
328            FinishLoad();
329        }
330    }
331
332    return movie != nil;
333}
334
335void wxQTMediaBackend::FinishLoad()
336{
337    DoShowPlayerControls(m_interfaceflags);
338
339    NSSize s = [[m_movie attributeForKey:QTMovieNaturalSizeAttribute] sizeValue];
340    m_bestSize = wxSize(s.width, s.height);
341
342    NotifyMovieLoaded();
343}
344
345bool wxQTMediaBackend::Play()
346{
347    [m_movieview play:nil];
348    return true;
349}
350
351bool wxQTMediaBackend::Pause()
352{
353    [m_movieview pause:nil];
354    return true;
355}
356
357bool wxQTMediaBackend::Stop()
358{
359    [m_movieview pause:nil];
360    [m_movieview gotoBeginning:nil];
361    return true;
362}
363
364double wxQTMediaBackend::GetVolume()
365{
366    return [m_movie volume];
367}
368
369bool wxQTMediaBackend::SetVolume(double dVolume)
370{
371    [m_movie setVolume:dVolume];
372    return true;
373}
374double wxQTMediaBackend::GetPlaybackRate()
375{
376    return [m_movie rate];
377}
378
379bool wxQTMediaBackend::SetPlaybackRate(double dRate)
380{
381    [m_movie setRate:dRate];
382    return true;
383}
384
385bool wxQTMediaBackend::SetPosition(wxLongLong where)
386{
387    QTTime position;
388    position = [m_movie currentTime];
389    position.timeValue = (where.GetValue() / 1000.0) * position.timeScale;
390    [m_movie setCurrentTime:position];
391    return true;
392}
393
394wxLongLong wxQTMediaBackend::GetPosition()
395{
396    QTTime position = [m_movie currentTime];
397    return ((double) position.timeValue) / position.timeScale * 1000;
398}
399
400wxLongLong wxQTMediaBackend::GetDuration()
401{
402    QTTime duration = [m_movie duration];
403    return ((double) duration.timeValue) / duration.timeScale * 1000;
404}
405
406wxMediaState wxQTMediaBackend::GetState()
407{
408    if ( [m_movie isPlaying] )
409        return wxMEDIASTATE_PLAYING;
410    else
411    {
412        if ( GetPosition() == 0 )
413            return wxMEDIASTATE_STOPPED;
414        else
415            return wxMEDIASTATE_PAUSED;
416    }
417}
418
419void wxQTMediaBackend::Cleanup()
420{
421    [m_movieview setMovie:NULL];
422    [m_movie release];
423    m_movie = nil;
424}
425
426wxSize wxQTMediaBackend::GetVideoSize() const
427{
428    return m_bestSize;
429}
430
431void wxQTMediaBackend::Move(int x, int y, int w, int h)
432{
433    // as we have a native player, no need to move the video area
434}
435
436bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
437{
438    if ( m_interfaceflags != flags )
439        DoShowPlayerControls(flags);
440
441    m_interfaceflags = flags;
442    return true;
443}
444
445void wxQTMediaBackend::DoShowPlayerControls(wxMediaCtrlPlayerControls flags)
446{
447    if (flags == wxMEDIACTRLPLAYERCONTROLS_NONE )
448    {
449        [m_movieview setControllerVisible:NO];
450    }
451    else
452    {
453        [m_movieview setControllerVisible:YES];
454
455        [m_movieview setStepButtonsVisible:(flags & wxMEDIACTRLPLAYERCONTROLS_STEP) ? YES:NO];
456        [m_movieview setVolumeButtonVisible:(flags & wxMEDIACTRLPLAYERCONTROLS_VOLUME) ? YES:NO];
457    }
458}
459
460#endif
461
462#if wxOSX_USE_AVFOUNDATION
463
464//---------------------------------------------------------------------------
465//
466//  wxAVMediaBackend
467//
468//---------------------------------------------------------------------------
469
470#import <AVFoundation/AVFoundation.h>
471
472#if wxOSX_USE_AVKIT
473#import <AVKit/AVKit.h>
474#endif
475
476class WXDLLIMPEXP_FWD_MEDIA wxAVMediaBackend;
477
478static void *AVSPPlayerItemStatusContext = &AVSPPlayerItemStatusContext;
479static void *AVSPPlayerRateContext = &AVSPPlayerRateContext;
480
481@interface wxAVPlayer : AVPlayer {
482
483    AVPlayerLayer *playerLayer;
484
485    wxAVMediaBackend* m_backend;
486}
487
488-(BOOL)isPlaying;
489
490@property (retain) AVPlayerLayer *playerLayer;
491
492@end
493
494class WXDLLIMPEXP_MEDIA wxAVMediaBackend : public wxMediaBackendCommonBase
495{
496public:
497
498    wxAVMediaBackend();
499    ~wxAVMediaBackend();
500
501    virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
502                               wxWindowID id,
503                               const wxPoint& pos,
504                               const wxSize& size,
505                               long style,
506                               const wxValidator& validator,
507                               const wxString& name);
508
509    virtual bool Play();
510    virtual bool Pause();
511    virtual bool Stop();
512
513    virtual bool Load(const wxString& fileName);
514    virtual bool Load(const wxURI& location);
515
516    virtual wxMediaState GetState();
517
518    virtual bool SetPosition(wxLongLong where);
519    virtual wxLongLong GetPosition();
520    virtual wxLongLong GetDuration();
521
522    virtual void Move(int x, int y, int w, int h);
523    wxSize GetVideoSize() const;
524
525    virtual double GetPlaybackRate();
526    virtual bool SetPlaybackRate(double dRate);
527
528    virtual double GetVolume();
529    virtual bool SetVolume(double dVolume);
530
531    void Cleanup();
532    void FinishLoad();
533
534    virtual bool   ShowPlayerControls(wxMediaCtrlPlayerControls flags);
535private:
536    void DoShowPlayerControls(wxMediaCtrlPlayerControls flags);
537
538    wxSize m_bestSize;              //Original movie size
539    wxAVPlayer* m_player;               //AVPlayer handle/instance
540
541    wxMediaCtrlPlayerControls m_interfaceflags; // Saved interface flags
542
543    wxDECLARE_DYNAMIC_CLASS(wxAVMediaBackend);
544};
545
546// --------------------------------------------------------------------------
547// wxAVMediaBackend
548// --------------------------------------------------------------------------
549
550@implementation wxAVPlayer
551
552@synthesize playerLayer;
553
554- (id) init
555{
556    self = [super init];
557
558    [self addObserver:self forKeyPath:@"currentItem.status"
559                  options:NSKeyValueObservingOptionNew context:AVSPPlayerItemStatusContext];
560    [self addObserver:self forKeyPath:@"rate"
561              options:NSKeyValueObservingOptionNew context:AVSPPlayerRateContext];
562
563    return self;
564}
565
566- (void)dealloc
567{
568    [playerLayer release];
569    [[NSNotificationCenter defaultCenter] removeObserver:self];
570
571    [self removeObserver:self forKeyPath:@"rate" context:AVSPPlayerRateContext];
572    [self removeObserver:self forKeyPath:@"currentItem.status" context:AVSPPlayerItemStatusContext];
573
574    [super dealloc];
575}
576
577- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
578{
579    if (context == AVSPPlayerItemStatusContext)
580    {
581        id val = [change objectForKey:NSKeyValueChangeNewKey];
582        if ( val != [NSNull null ] )
583        {
584            AVPlayerStatus status = (AVPlayerStatus) [ val integerValue];
585
586            switch (status)
587            {
588                case AVPlayerItemStatusUnknown:
589                    break;
590                case AVPlayerItemStatusReadyToPlay:
591                    [[NSNotificationCenter defaultCenter]
592                     addObserver:self selector:@selector(playerItemDidReachEnd:)
593                     name:AVPlayerItemDidPlayToEndTimeNotification object:self.currentItem];
594                    m_backend->FinishLoad();
595                    break;
596                case AVPlayerItemStatusFailed:
597                    break;
598                default:
599                    break;
600            }
601        }
602    }
603    else if (context == AVSPPlayerRateContext)
604    {
605        NSNumber* newRate = [change objectForKey:NSKeyValueChangeNewKey];
606        if ([newRate intValue] == 0)
607        {
608            m_backend->QueuePauseEvent();
609        }
610        else if ( [self isPlaying] == NO )
611        {
612            m_backend->QueuePlayEvent();
613        }
614    }
615    else
616    {
617        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
618    }
619}
620
621-(wxAVMediaBackend*) backend
622{
623    return m_backend;
624}
625
626-(void) setBackend:(wxAVMediaBackend*) backend
627{
628    m_backend = backend;
629}
630
631- (void)playerItemDidReachEnd:(NSNotification *)notification
632{
633    if ( m_backend )
634    {
635        if ( m_backend->SendStopEvent() )
636            m_backend->QueueFinishEvent();
637    }
638}
639
640-(BOOL)isPlaying
641{
642    if ([self rate] == 0)
643    {
644        return NO;
645    }
646
647    return YES;
648}
649
650@end
651
652#if wxOSX_USE_IPHONE
653
654@interface wxAVView : UIView
655{
656}
657
658@end
659
660@implementation wxAVView
661
662+ (void)initialize
663{
664    static BOOL initialized = NO;
665    if (!initialized)
666    {
667        initialized = YES;
668        wxOSXIPhoneClassAddWXMethods( self );
669    }
670}
671
672+ (Class)layerClass
673{
674    return [AVPlayerLayer class];
675}
676
677- (id) initWithFrame:(CGRect)rect player:(wxAVPlayer*) player
678{
679    if ( !(self=[super initWithFrame:rect]) )
680        return nil;
681
682    AVPlayerLayer* playerLayer = (AVPlayerLayer*) [self layer];
683    [playerLayer setPlayer: player];
684    [player setPlayerLayer:playerLayer];
685
686    return self;
687}
688
689- (AVPlayerLayer*) playerLayer
690{
691    return (AVPlayerLayer*) [self layer];
692}
693@end
694
695#else
696
697#if wxOSX_USE_AVKIT
698
699@interface wxAVPlayerView : AVPlayerView
700{
701}
702
703@end
704
705@implementation wxAVPlayerView
706
707+ (void)initialize
708{
709    static BOOL initialized = NO;
710    if (!initialized)
711    {
712        initialized = YES;
713        wxOSXCocoaClassAddWXMethods( self );
714    }
715}
716
717- (id) initWithFrame:(NSRect)rect player:(wxAVPlayer*) player
718{
719    if ( !(self=[super initWithFrame:rect]) )
720        return nil;
721
722    self.player = player;
723
724    return self;
725}
726
727- (AVPlayerLayer*) playerLayer
728{
729    return (AVPlayerLayer*) [[[self layer] sublayers] firstObject];
730}
731
732@end
733
734#endif // wxOSX_USE_AVKIT
735
736@interface wxAVView : NSView
737{
738}
739
740@end
741
742@implementation wxAVView
743
744+ (void)initialize
745{
746    static BOOL initialized = NO;
747    if (!initialized)
748    {
749        initialized = YES;
750        wxOSXCocoaClassAddWXMethods( self );
751    }
752}
753
754- (id) initWithFrame:(NSRect)rect player:(AVPlayer*) player
755{
756    if ( !(self=[super initWithFrame:rect]) )
757        return nil;
758
759    [self setWantsLayer:YES];
760    AVPlayerLayer* playerlayer = [[AVPlayerLayer playerLayerWithPlayer: player] retain];
761    [player setPlayerLayer:playerlayer];
762
763    [playerlayer setFrame:[[self layer] bounds]];
764    [playerlayer setAutoresizingMask:kCALayerWidthSizable | kCALayerHeightSizable];
765    [[self layer] addSublayer:playerlayer];
766
767    return self;
768}
769
770- (AVPlayerLayer*) playerLayer
771{
772    return (AVPlayerLayer*) [[[self layer] sublayers] firstObject];
773}
774
775@end
776
777#endif
778
779IMPLEMENT_DYNAMIC_CLASS(wxAVMediaBackend, wxMediaBackend);
780
781wxAVMediaBackend::wxAVMediaBackend() :
782m_player(nil),
783m_interfaceflags(wxMEDIACTRLPLAYERCONTROLS_NONE)
784{
785}
786
787wxAVMediaBackend::~wxAVMediaBackend()
788{
789    Cleanup();
790}
791
792bool wxAVMediaBackend::CreateControl(wxControl* inctrl, wxWindow* parent,
793                                     wxWindowID wid,
794                                     const wxPoint& pos,
795                                     const wxSize& size,
796                                     long style,
797                                     const wxValidator& validator,
798                                     const wxString& name)
799{
800    wxMediaCtrl* mediactrl = (wxMediaCtrl*) inctrl;
801
802    mediactrl->DontCreatePeer();
803
804    if ( !mediactrl->wxControl::Create(
805                                       parent, wid, pos, size,
806                                       wxWindow::MacRemoveBordersFromStyle(style),
807                                       validator, name))
808    {
809        return false;
810    }
811
812    m_player = [[wxAVPlayer alloc] init];
813    [m_player setBackend:this];
814
815    NSRect r = wxOSXGetFrameForControl( mediactrl, pos , size ) ;
816
817    WXWidget view = NULL;
818#if wxOSX_USE_AVKIT
819    if ( NSClassFromString(@"AVPlayerView") )
820    {
821        view = [[wxAVPlayerView alloc] initWithFrame: r player:m_player];
822        [(wxAVPlayerView*) view setControlsStyle:AVPlayerViewControlsStyleNone];
823    }
824#endif
825
826    if ( view == NULL )
827    {
828        view = [[wxAVView alloc] initWithFrame: r player:m_player];
829    }
830
831#if wxOSX_USE_IPHONE
832    wxWidgetIPhoneImpl* impl = new wxWidgetIPhoneImpl(mediactrl,view);
833#else
834    wxWidgetCocoaImpl* impl = new wxWidgetCocoaImpl(mediactrl,view);
835#endif
836    mediactrl->SetPeer(impl);
837
838    m_ctrl = mediactrl;
839    return true;
840}
841
842bool wxAVMediaBackend::Load(const wxString& fileName)
843{
844    return Load(
845                wxURI(
846                      wxString( wxT("file://") ) + fileName
847                      )
848                );
849}
850
851bool wxAVMediaBackend::Load(const wxURI& location)
852{
853    wxCFStringRef uri(location.BuildURI());
854    NSURL *url = [NSURL URLWithString: uri.AsNSString()];
855
856    AVAsset* asset = [AVAsset assetWithURL:url];
857    if (! asset )
858        return false;
859
860    if ( [asset isPlayable] )
861    {
862        AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
863        [m_player replaceCurrentItemWithPlayerItem:playerItem];
864
865        return playerItem != nil;
866    }
867    return false;
868}
869
870void wxAVMediaBackend::FinishLoad()
871{
872    DoShowPlayerControls(m_interfaceflags);
873
874    AVPlayerItem *playerItem = [m_player currentItem];
875
876    CGSize s = [playerItem presentationSize];
877    m_bestSize = wxSize(s.width, s.height);
878
879    NotifyMovieLoaded();
880}
881
882bool wxAVMediaBackend::Play()
883{
884    [m_player play];
885    return true;
886}
887
888bool wxAVMediaBackend::Pause()
889{
890    [m_player pause];
891    return true;
892}
893
894bool wxAVMediaBackend::Stop()
895{
896    [m_player pause];
897    [m_player seekToTime:kCMTimeZero];
898    return true;
899}
900
901double wxAVMediaBackend::GetVolume()
902{
903    return [m_player volume];
904}
905
906bool wxAVMediaBackend::SetVolume(double dVolume)
907{
908    [m_player setVolume:dVolume];
909    return true;
910}
911double wxAVMediaBackend::GetPlaybackRate()
912{
913    return [m_player rate];
914}
915
916bool wxAVMediaBackend::SetPlaybackRate(double dRate)
917{
918    [m_player setRate:dRate];
919    return true;
920}
921
922bool wxAVMediaBackend::SetPosition(wxLongLong where)
923{
924    [m_player seekToTime:CMTimeMakeWithSeconds(where.GetValue() / 1000.0, 1)
925              toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
926
927    return true;
928}
929
930wxLongLong wxAVMediaBackend::GetPosition()
931{
932    return CMTimeGetSeconds([m_player currentTime])*1000.0;
933}
934
935wxLongLong wxAVMediaBackend::GetDuration()
936{
937    AVPlayerItem *playerItem = [m_player currentItem];
938
939    if ([playerItem status] == AVPlayerItemStatusReadyToPlay)
940        return CMTimeGetSeconds([[playerItem asset] duration])*1000.0;
941    else
942        return 0.f;
943}
944
945wxMediaState wxAVMediaBackend::GetState()
946{
947    if ( [m_player isPlaying] )
948        return wxMEDIASTATE_PLAYING;
949    else
950    {
951        if ( GetPosition() == 0 )
952            return wxMEDIASTATE_STOPPED;
953        else
954            return wxMEDIASTATE_PAUSED;
955    }
956}
957
958void wxAVMediaBackend::Cleanup()
959{
960    [m_player pause];
961    [m_player release];
962    m_player = nil;
963}
964
965wxSize wxAVMediaBackend::GetVideoSize() const
966{
967    return m_bestSize;
968}
969
970void wxAVMediaBackend::Move(int x, int y, int w, int h)
971{
972    // as we have a native player, no need to move the video area
973}
974
975bool wxAVMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
976{
977    if ( m_interfaceflags != flags )
978        DoShowPlayerControls(flags);
979
980    m_interfaceflags = flags;
981    return true;
982}
983
984void wxAVMediaBackend::DoShowPlayerControls(wxMediaCtrlPlayerControls flags)
985{
986#if wxOSX_USE_AVKIT
987    NSView* view = m_ctrl->GetHandle();
988    if ( [view isKindOfClass:[wxAVPlayerView class]] )
989    {
990        wxAVPlayerView* playerView = (wxAVPlayerView*) view;
991        if (flags == wxMEDIACTRLPLAYERCONTROLS_NONE )
992            playerView.controlsStyle = AVPlayerViewControlsStyleNone;
993        else
994            playerView.controlsStyle = AVPlayerViewControlsStyleDefault;
995    }
996#endif
997}
998
999#endif
1000
1001//in source file that contains stuff you don't directly use
1002#include "wx/html/forcelnk.h"
1003FORCE_LINK_ME(basewxmediabackends);
1004
1005#endif //wxUSE_MEDIACTRL
1006