3939
4040#import < Foundation/Foundation.h>
4141#import < UIKit/UIKit.h>
42- #import < MediaPlayer/MPMoviePlayerController.h>
43- #import < MediaPlayer/MPMoviePlayerViewController.h>
42+ #import < AVKit/AVKit.h>
4443
4544// //////////////////////////////////////////////////////////////////////////////
4645
4948
5049// //////////////////////////////////////////////////////////////////////////////
5150
52- MPMoviePlayerViewController *g_movie_player = nil ;
53-
54- // //////////////////////////////////////////////////////////////////////////////
55-
56- static NSObject *s_movie_player_delegate = nil ;
51+ static AVPlayerViewController *s_movie_player = nil ;
5752
5853// //////////////////////////////////////////////////////////////////////////////
5954
6055@interface com_runrev_livecode_MCFullscreenMovieDelegate : NSObject
6156{
6257bool m_running;
58+ bool m_looping;
59+ CMTime m_start_time;
60+ AVPlayer *m_player;
6361UIControl *m_overlay;
6462}
6563
66- - (id )initWithPlayer ;
64+ - (id )initWithPlayer : (AVPlayer*) player startTime : (CMTime) startTime looping : ( BOOL ) looping ;
6765- (void )dealloc ;
6866
6967- (void )begin : (bool )p_add_overlay ;
7068- (void )end ;
7169- (void )stop ;
7270- (bool )isRunning ;
7371
74- - (void )movieFinished : (NSNotification *) p_notification ;
75- - (void )moviePreloadFinished : (NSNotification *) p_notification ;
72+ - (void )observeValueForKeyPath : (NSString *)keyPath ofObject : (id )object change : (NSDictionary <NSKeyValueChangeKey,id> *)change context : (void *)context ;
73+ - (void )playerItemDidPlayToEndTime : (NSNotification *)notification ;
74+ - (void )playerItemFailedToPlayToEndTime : (NSNotification *)notification ;
7675- (void )movieWindowTouched : (UIControl*) p_sender ;
7776
7877@end
7978
79+ @compatibility_alias MCFullscreenMovieDelegate com_runrev_livecode_MCFullscreenMovieDelegate;
80+
81+ // //////////////////////////////////////////////////////////////////////////////
82+
83+ static MCFullscreenMovieDelegate *s_movie_player_delegate = nil ;
84+
85+ // //////////////////////////////////////////////////////////////////////////////
86+
8087@implementation com_runrev_livecode_MCFullscreenMovieDelegate
8188
8289// AL-2014-09-09: [[ Bug 13354 ]] Replace deprecated MPMoviePlayerContentPreloadDidFinishNotification
83- - (id )initWithPlayer : (MPMoviePlayerController *)p_player
90+ - (id )initWithPlayer : (AVPlayer *)p_player startTime : (CMTime) startTime looping : ( BOOL ) looping
8491{
8592self = [super init ];
8693if (self == nil )
8794return nil ;
8895
89- [[NSNotificationCenter defaultCenter ] addObserver: self
90- selector: @selector (movieFinished: )
91- name: MPMoviePlayerPlaybackDidFinishNotification
92- object: nil ];
93-
94- [[NSNotificationCenter defaultCenter ] addObserver: self
95- selector: @selector (moviePreloadFinished: )
96- name: MPMoviePlayerLoadStateDidChangeNotification
97- object: p_player];
96+ m_player = [p_player retain ];
9897
98+ [m_player.currentItem
99+ addObserver: self
100+ forKeyPath: @" status"
101+ options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
102+ context: nil ];
103+ [NSNotificationCenter .defaultCenter
104+ addObserver: self
105+ selector: @selector (playerItemDidPlayToEndTime: )
106+ name: AVPlayerItemDidPlayToEndTimeNotification
107+ object: m_player.currentItem];
108+ [NSNotificationCenter .defaultCenter
109+ addObserver: self
110+ selector: @selector (playerItemFailedToPlayToEndTime: )
111+ name: AVPlayerItemFailedToPlayToEndTimeNotification
112+ object: m_player.currentItem];
113+
99114m_running = true ;
100115m_overlay = nil ;
101116
117+ m_start_time = startTime;
118+ m_looping = looping;
119+
102120s_movie_player_delegate = self;
103121
104122return self;
@@ -107,7 +125,8 @@ - (id)initWithPlayer: (MPMoviePlayerController *)p_player
107125- (void )dealloc
108126{
109127s_movie_player_delegate = nil ;
110- [[NSNotificationCenter defaultCenter ] removeObserver: self ];
128+ [NSNotificationCenter .defaultCenter removeObserver: self ];
129+ [m_player release ];
111130[super dealloc ];
112131}
113132
@@ -149,23 +168,37 @@ - (bool)isRunning
149168
150169// ////////
151170
152- - (void )movieFinished : (NSNotification *) p_notification
171+ - (void )playerItemDidPlayToEndTime : (NSNotification *)notification
153172{
173+ if (m_looping)
174+ {
175+ [m_player seekToTime: m_start_time];
176+ return ;
177+ }
178+
154179m_running = false ;
155180
156181// MW-2011-08-16: [[ Wait ]] Tell the wait to exit (our wait has anyevent == True).
157182MCscreen -> pingwait ();
158183}
159184
160- - (void )moviePreloadFinished : (NSNotification *) p_notification
185+ - (void )playerItemFailedToPlayToEndTime : (NSNotification *)notification
161186{
162- // AL-2014-09-09: [[ Bug 13354 ]] Replace deprecated MPMoviePlayerContentPreloadDidFinishNotification
163- if ([[p_notification object ] loadState ] & MPMovieLoadStateUnknown)
187+ m_running = false ;
188+ MCscreen->pingwait ();
189+ }
190+
191+ - (void )observeValueForKeyPath : (NSString *)keyPath ofObject : (id )object change : (NSDictionary <NSKeyValueChangeKey,id> *)change context : (void *)context
192+ {
193+ if ([keyPath isEqualToString: @" status" ])
164194{
165- m_running = false ;
166-
167- // MW-2011-08-16: [[ Wait ]] Tell the wait to exit (our wait has anyevent == True).
168- MCscreen -> pingwait ();
195+ if (((AVPlayerItem*)object).status == AVPlayerItemStatusFailed)
196+ {
197+ m_running = false ;
198+
199+ // MW-2011-08-16: [[ Wait ]] Tell the wait to exit (our wait has anyevent == True).
200+ MCscreen -> pingwait ();
201+ }
169202}
170203}
171204
@@ -177,25 +210,29 @@ - (void)movieWindowTouched: (UIControl*) p_sender
177210
178211@end
179212
180- static void configure_playback_range (MPMoviePlayerController *p_player)
213+ static void configure_playback_range (AVPlayerViewController *p_player, CMTime &r_start_time )
181214{
182215if (!MCtemplateplayer -> getflag (F_PLAY_SELECTION))
216+ {
217+ r_start_time = kCMTimeZero ;
183218return ;
219+ }
184220
185221uint32_t t_start_time, t_end_time;
186222t_start_time = MCtemplateplayer -> getstarttime ();
187223t_end_time = MCtemplateplayer -> getendtime ();
188- [ p_player setInitialPlaybackTime: t_start_time / 1000.0 ] ;
189- [p_player setEndPlaybackTime: t_end_time / 1000.0 ] ;
224+ p_player. player . currentItem . forwardPlaybackEndTime = CMTimeMake (t_end_time, 1000 ) ;
225+ r_start_time = CMTimeMake (t_start_time, 1000 ) ;
190226}
191227
192228struct play_fullscreen_t
193229{
194230NSURL *url;
195231bool looping;
196232bool with_controller;
197- MPMoviePlayerController *movie_player;
198- com_runrev_livecode_MCFullscreenMovieDelegate *delegate;
233+ AVPlayerViewController *movie_player;
234+ MCFullscreenMovieDelegate *delegate;
235+ CMTime start_time;
199236};
200237
201238static void play_fullscreen_movie_prewait (void *p_context)
@@ -205,41 +242,49 @@ static void play_fullscreen_movie_prewait(void *p_context)
205242
206243 // MM-2011-12-09: [[ Bug 9892 ]] Destroy previous movie player. Fixes bug with iOS 5 where
207244// showController is ignored on second running.
208- if (g_movie_player != nil )
245+ if (s_movie_player != nil )
209246{
210- [g_movie_player release ];
211- g_movie_player = nil ;
247+ [s_movie_player release ];
248+ s_movie_player = nil ;
212249 }
213250
214251// Make sure we have a movie player view controller with correct url
215- g_movie_player = [[MPMoviePlayerViewController alloc ] initWithContentURL: ctxt -> url];
252+ s_movie_player = [[AVPlayerViewController alloc ] init ];
253+ s_movie_player.player = [AVPlayer playerWithURL: ctxt->url];
216254
217- ctxt -> movie_player = [g_movie_player moviePlayer ] ;
255+ ctxt-> movie_player = s_movie_player ;
218256
219- [[ctxt -> movie_player view ] setHidden: NO ];
220- [[ctxt -> movie_player view ] setOpaque: YES ];
221- [[ctxt -> movie_player view ] setAlpha: 1 .0f ];
222- [[ctxt -> movie_player backgroundView ] setBackgroundColor: [UIColor blackColor ]];
223- [ctxt -> movie_player setFullscreen: YES ];
224- [ctxt -> movie_player setScalingMode: MPMovieScalingModeAspectFit];
225- [ctxt -> movie_player setControlStyle: (ctxt -> with_controller ? MPMovieControlStyleFullscreen : MPMovieControlStyleNone)];
226- [ctxt -> movie_player setUseApplicationAudioSession: YES ];
227- [ctxt -> movie_player setInitialPlaybackTime: -1 ];
228- [ctxt -> movie_player setEndPlaybackTime: -1 ];
229- [ctxt -> movie_player setShouldAutoplay: YES ];
257+ ctxt->movie_player .view .hidden = NO ;
258+ ctxt->movie_player .view .opaque = YES ;
259+ ctxt->movie_player .view .alpha = 1 .0f ;
260+ ctxt->movie_player .view .backgroundColor = [UIColor blackColor ];
261+
262+ ctxt->movie_player .videoGravity = AVLayerVideoGravityResizeAspect;
263+ ctxt->movie_player .showsPlaybackControls = ctxt->with_controller ;
230264if (ctxt -> looping)
231- [ctxt -> movie_player setRepeatMode: MPMovieRepeatModeOne];
232- if (MCmajorosversion >= 430 )
233- [ctxt -> movie_player setAllowsAirPlay: NO ];
265+ ctxt->movie_player .player .actionAtItemEnd = AVPlayerActionAtItemEndNone;
266+
267+ ctxt->movie_player .allowsPictureInPicturePlayback = NO ;
268+ ctxt->movie_player .player .allowsExternalPlayback = NO ;
234269
235- configure_playback_range (ctxt -> movie_player);
270+ CMTime t_start_time;
271+ configure_playback_range (ctxt -> movie_player, t_start_time);
236272
237- ctxt -> delegate = [[com_runrev_livecode_MCFullscreenMovieDelegate alloc ] initWithPlayer: ctxt -> movie_player];
273+ ctxt -> delegate = [[MCFullscreenMovieDelegate alloc ]
274+ initWithPlayer: ctxt -> movie_player.player
275+ startTime: t_start_time
276+ looping: ctxt->looping];
238277
239278// Present the view controller and get the delegate to setup its overlay
240279// if needed.
241- [MCIPhoneGetViewController () presentModalViewController: g_movie_player animated: NO ];
242- [ctxt -> delegate begin: !ctxt -> with_controller];
280+ [MCIPhoneGetViewController ()
281+ presentViewController: s_movie_player
282+ animated: NO
283+ completion: ^{
284+ [s_movie_player.player seekToTime: t_start_time];
285+ [s_movie_player.player play ];
286+ }];
287+ [ctxt -> delegate begin: !ctxt -> with_controller];
243288}
244289
245290static void play_fullscreen_movie_postwait (void *p_context)
@@ -249,14 +294,14 @@ static void play_fullscreen_movie_postwait(void *p_context)
249294
250295// Clear up and overlay and dismiss the controller.
251296[ctxt -> delegate end ];
252- [MCIPhoneGetViewController () dismissModalViewControllerAnimated: NO ];
297+ [MCIPhoneGetViewController () dismissViewControllerAnimated: NO completion: ^{} ];
253298
254299// Cleanup the delegate
255300[ctxt -> delegate release ];
256301
257302// Make sure we reset the movie player to nothing.
258- [ctxt -> movie_player stop ];
259- [ctxt -> movie_player setContentURL: [NSURL URLWithString: @" " ]];
303+ [ctxt-> movie_player.player pause ];
304+ [ctxt-> movie_player.player replaceCurrentItemWithPlayerItem: [AVPlayerItem playerItemWithURL: [NSURL URLWithString: @" " ] ]];
260305}
261306
262307static bool play_fullscreen_movie_new (NSURL *p_movie, bool p_looping, bool p_with_controller)
@@ -291,19 +336,13 @@ bool MCSystemPlayVideo(MCStringRef p_video)
291336if (MCStringBeginsWithCString (p_video, (const char_t *)" http://" , kMCStringOptionCompareExact )
292337|| MCStringBeginsWithCString (p_video, (const char_t *)" https://" , kMCStringOptionCompareExact ))
293338{
294- CFStringRef cfstrurl = nil ;
295- /* UNCHECKED */ MCStringConvertToCFStringRef (p_video, cfstrurl);
296- t_url = [NSURL URLWithString: (NSString *)cfstrurl];
297- CFRelease (cfstrurl);
339+ t_url = [NSURL URLWithString: MCStringConvertToAutoreleasedNSString (p_video)];
298340}
299341else
300342{
301343MCAutoStringRef t_path;
302- CFStringRef cfstrpath = nil ;
303344/* UNCHECKED */ MCS_resolvepath (p_video, &t_path);
304- /* UNCHECKED */ MCStringConvertToCFStringRef (*t_path, cfstrpath);
305- t_url = [NSURL fileURLWithPath: (NSString *)cfstrpath];
306- CFRelease (cfstrpath);
345+ t_url = [NSURL fileURLWithPath: MCStringConvertToAutoreleasedNSString (*t_path)];
307346}
308347
309348if (t_url == nil )
0 commit comments