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