Change AVPlayer Video MacOS Objective-C Cocoa - objective-c

For MacOS, not iOS. I am playing a video in an AVPlayerView in an XIB. Just experimenting with video playback. I would like to be able to choose a selection from the File Menu (For instance File / Videos / Video 1, Video2, Video3, etc) and change the currently playing video in the XIB when I select the menu item.
Currently I am using this to play a video:
- (void)windowDidChangeOcclusionState:(NSNotification *)notification
{
if (self.window.occlusionState & NSWindowOcclusionStateVisible)
{
loopPlayer = YES;
[_aspectView setAspectRatio:NSMakeSize(16, 9)];
NSBundle *mb = [NSBundle mainBundle];
NSURL *demoURL = [mb URLForResource:#"Video1" withExtension:#"mp4"];
player = [[AVPlayer alloc] initWithURL:demoURL];
self.playerView.player = player;
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(movieEndDetected:)
name:#"AVPlayerItemDidPlayToEndTimeNotification"
object:player.currentItem];
[player play];
}
else
{
[player pause];
[player seekToTime:kCMTimeZero];
}
}
and to loop the video playing:
- (void) movieEndDetected:(NSNotification *) note
{
if (loopPlayer) {
[player seekToTime:kCMTimeZero];
[player play];
}
}
But I would like to change the playing video in the XIB on the fly by choosing a menu button. Any ideas how this can be done? I have heard of AVPlayerQueue maybe working for this kind of thing, but I am very new and can't get it working on MacOS.

My solution was to use many avplayer views in xibs and when one was open from a menu item, close another.
- (void)Visual02Menu:(id)sender {
if (!visual02Window) {
visual02Window = [[Visual02 alloc] initWithWindowNibName:#"Visual02"]; }
[visual01Window close];
[visual02Window showWindow:self];

Related

How to change video url for MPMoviePlayerViewController?

I am developing for iOS 6 using Xcode 4.6.1 (Target is iPad)
I am trying to change the video URL when the user swipes the screen.
This is my ViewController.m file:
#import "ViewController.h"
#interface experiencesViewController () {
MPMoviePlayerViewController *playerViewController;
MPMoviePlayerController *player;
}
#end
...
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSString *url = [[NSBundle mainBundle] pathForResource:"video" ofType:#"mp4"];
playerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:url]];
player = [playerViewController moviePlayer];
[player setMovieSourceType:MPMovieSourceTypeFile];
player.fullscreen = YES;
[player play];
...
}
...
Now, I want to change the video on a swipe event. I tried doing this:
- (IBAction)didSwipeLeft:(UITapGestureRecognizer *)recognizer {
NSLog(#"Left");
player.movieSourceType = MPMovieSourceTypeFile;
player.contentURL = [NSURL URLWithString:#"video2.mp4"];
[player prepareToPlay];
[player play];
}
However, this doesn't work. The video stops playing and nothing happens after that. Any help would be highly appreciated.
Thanks :)
remove the [player play] because the video is not yet ready to play.

MPMoviePlayerLoadStateDidChangeNotification works in iOS 5 but not in iOS 6

I want to play a video with an MPMoviePlayerViewController. So in my view controller I register as an observer for MPMoviePlayerLoadStateDidChangeNotification.
I then initialise the MPMoviePlayerViewController:
self.mPlayerVC = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:#"<videoURL>"]];
and wait for the notification to arrive. When it does I execute this code:
MPMoviePlayerController* playerController = notification.object;
if ([playerController loadState] & MPMovieLoadStatePlayable) {
if (self.mPlayerVC) {
[self presentMoviePlayerViewControllerAnimated:self.mPlayerVC];
}
}
Anyone an idea why this works for iOS 5 but not for iOS 6? Thanks
There seems to be a bug in iOS 6' MediaPlayer.framework. To get the video to play I call prepareToPlay after initialising the MPMoviePlayerViewController
self.mPlayerVC = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:#"<videoURL>"]];
[self.mPlayerVC.moviePlayer prepareToPlay];
Now the notifications come in again but the app crashes when I call [self presentMoviePlayerViewControllerAnimated:self.mPlayerVC]; in the method that is called for the MPMoviePlayerLoadStateDidChangeNotification.
To prevent the crash replace
[self presentMoviePlayerViewControllerAnimated:self.mPlayerVC];
with something like
if ([self respondsToSelector:#selector(presentViewController:animated:completion:)]) {
[self presentViewController:self.mPlayerVC animated:YES completion:nil];
}
else if ([self respondsToSelector:#selector(presentModalViewController:animated:)]) {
[self presentModalViewController:self.mPlayerVC animated:YES];
}

MPMoviePlayerViewController backgrounding deal. How to continue playing after returning from background to foreground?

I'm working on application for video streaming. It is built with ARC for iOS5.
To display view I use MPMoviePlayerViewController this way:
.h
#interface EpisodesTableViewController : UITableViewController<EpisodeUrlResolverDelegate> {
NSTimeInterval playbackTime;
EpisodeUrlResolver *episodeUrlResolver;
}
#property (strong, nonatomic) MPMoviePlayerViewController *player;
#end
.m
#implementation EpisodesTableViewController
#synthesize episodes, player;
- (void)viewDidLoad
{
[super viewDidLoad];
episodeUrlResolver = [[Soap4MeEpisodeUrlResolver alloc] init];
[episodeUrlResolver setDelegate:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willEnterForeground) name:#"WillEnterForeground" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willEnterBackground) name:#"WillEnterBackground" object:nil];
}
- (void)viewDidUnload
{
episodeUrlResolver = nil;
player = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"WillEnterForeground" object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"WillEnterBackground" object:nil];
[super viewDidUnload];
}
- (void)url:(NSURL *)url WasResolvedForEpisode:(Episode *)episode {
player = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
player.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
player.moviePlayer.allowsAirPlay = YES;
[self presentModalViewController:player animated:YES];
}
- (void)willEnterBackground {
if (player) {
playbackTime = player.moviePlayer.currentPlaybackTime;
}
}
- (void)willEnterForeground {
if (!player)
return;
if(player.moviePlayer.playbackState == MPMoviePlaybackStateInterrupted || player.moviePlayer.playbackState == MPMoviePlaybackStateStopped || player.moviePlayer.playbackState == MPMoviePlaybackStatePaused)
{
[self continuePlayback];
}
}
- (void)continuePlayback {
[self presentModalViewController:player animated:YES];
[player.moviePlayer setInitialPlaybackTime:playbackTime];
NSLog(#"%f", player.moviePlayer.initialPlaybackTime);
[player.moviePlayer play];
}
Few words about presented code:
when url for video is resolved I create the MPMoviePlayerViewController object for video playback. Playback is started. Then when app is going background with home button MPMoviePlayerViewController automatically pauses playback and dissapears from screen (weird behavior, as for me). Thats why I have to save playback time when app is going background and show existing MPMoviePlayerViewController again with restored playback time when app is back to foreground.
It works fine when user presses home button and then is going back to application.
But it doesn't work when user locks the device. WillEnterBackground notification is fired when
applicationWillEnterForeground is called, so for locking event it is called too.
But in case when user locks the device MPMoviePlayerViewController wasn't being dismissed properly as in situation when user presses home button. It is hidden from the screen, but calling the code
[self presentModalViewController:player animated:YES];
throws the exception
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present modally an active controller <EpisodesTableViewController: 0x91b3950>.'
I tried to change the code to dismiss controller:
- (void)willEnterForeground {
if (!player)
return;
if(player.moviePlayer.playbackState == MPMoviePlaybackStateInterrupted || player.moviePlayer.playbackState == MPMoviePlaybackStateStopped || player.moviePlayer.playbackState == MPMoviePlaybackStatePaused)
{
if (self.presentedViewController) {
[self dismissViewControllerAnimated:YES completion:^{
[self continuePlayback];
}];
}
else {
[self continuePlayback];
}
}
}
Now it doesn't throw the exception, but displays warning
wait_fences: failed to receive reply: 10004003
Also completion block is never called.
How to properly to solve the background/foreground continue playing with modally displayed MPMoviePlayerViewController?
Thanks for replies.
I solved the problem.
Method -willEnterBackground should look like:
- (void)willEnterBackground {
if (player) {
playbackTime = player.moviePlayer.currentPlaybackTime;
[self dismissModalViewControllerAnimated:NO];
}
}
We have to dismiss MPMoviePlayerViewController manually when app is entering background mode.
Pay attention to use only
[self dismissModalViewControllerAnimated:NO];
instead of
[self dismissMoviePlayerViewControllerAnimated];
Thats because MPMoviePlayerViewController was shown with
[self presentModalViewController:player animated:YES];

Can not detect MPMoviePlayerDidExitFullscreenNotification

In my project, I used MPMoviePlayerController to stream video from an http url. It plays fullscreen. When the video is playing, if you tap on "Done" button the video stops and it disappears, but the problem is; if you pinch to close video screen the video screen disappears but it still plays, sound of video continues to play.
I tried to detect exit fullscreen notification and manually stop the video but it didn't work. My moviePlayerDidExitFullScreen method didn't called.
To control that if I am getting the notifications on the right way I tried to get another notification : MPMoviePlayerPlaybackStateDidChangeNotification, and it is working. It calls the method on video launching.
I searched many forums and Apple documentations but I couldn't find enough information.
Here is my code to open a fullscreen video and detect exit fullscreen :
- (void)openFullVideo
{
NSString* path = #"http://trtvizyon.mysys.com/test/leyla_ile_mecnun.mp4";
NSURL *fileURL = [NSURL URLWithString:path];
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerDidExitFullScreen:) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
player.controlStyle = MPMovieControlStyleDefault;
player.movieSourceType = MPMovieSourceTypeStreaming;
[self.view addSubview:player.view];
[player setFullscreen:YES animated:YES];
[player play];
}
- (void) moviePlayerDidExitFullScreen:(id)sender {
NSLog(#"moviePlayerDidExitFullScreen");
}
OK, I played with your code for a while, and finally shot that little bug in the gut.
Your first problem is not retaining the player object (assuming you are using ARC, if not, then skip this). So, just make sure you retain it as an instance variable for example:
//Header File
#interface ViewController : UIViewController {
MPMoviePlayerController* _player;
}
// Implementation File
- (void)openFullVideo {
// ...
_player = player;
}
Now, if that just works, then great!! But I am getting a dreaded unsolved bug on apple's side:
An AVPlayerItem can occupy only one position in a player's queue at a time
To solve this issue, do it like so:
NSString* path = #"http://trtvizyon.mysys.com/test/leyla_ile_mecnun.mp4";
NSURL *fileURL = [NSURL URLWithString:path];
MPMoviePlayerController *player = [[MPMoviePlayerController alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerDidExitFullScreen:) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
player.controlStyle = MPMovieControlStyleDefault;
player.movieSourceType = MPMovieSourceTypeStreaming;
[self.view addSubview:player.view];
[player setContentURL:fileURL];
[player setInitialPlaybackTime:-1.f];
[player setFullscreen:YES animated:YES];
[player prepareToPlay];
[player play];
_player = player;
That should do it!
Some Other Friendly Advice:
Make sure you remove yourself from NSNotificationCenter before playing the movie again.
I would suggest adding something like if (_player != nil) to avoid recreating the object.

Programmatically show controls in MPMoviePlayerController

I have a MPMoviePlayerController subclass that should show the controls when playback is finished. I have attached a responder to the MPMoviePlayerPlaybackDidFinishNotification notification and tried setting the control style as follows:
[self setControlStyle:MPMovieControlStyleEmbedded];
This is not working. In essence, at the end of the video I want to controls to show.
How can I show controls programatically?
NOTE: The controller is NOT in fullscreen mode.
Kindly find my full Code about this , it's working with me
add .h class add this
#property(strong,nonatomic) MPMoviePlayerViewController * moviePlayer;
at .m class add this code "pass the movie URl"
-(void) playMovie:(NSString *)filePath
{
NSURL *theOutputURL = [NSURL fileURLWithPath:filePath];
if(_moviePlayer)
[_moviePlayer.moviePlayer setContentURL:theOutputURL];
else
_moviePlayer = [[MPMoviePlayerViewController alloc] initWithContentURL:theOutputURL];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myMovieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:_moviePlayer.moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerPlaybackStateDidChange:) name:MPMoviePlayerPlaybackStateDidChangeNotification object:_moviePlayer.moviePlayer];
if (![_moviePlayer.moviePlayer isPreparedToPlay])
[_moviePlayer.moviePlayer prepareToPlay];
_moviePlayer.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[_moviePlayer.moviePlayer setFullscreen:YES];
_moviePlayer.moviePlayer.controlStyle=MPMovieControlStyleEmbedded;
[_moviePlayer.moviePlayer setContentURL:theOutputURL];
_moviePlayer.view.frame = CGRectMake(0, 0, [[UIScreen mainScreen]bounds].size.width, [[UIScreen mainScreen]bounds].size.height);
[_moviePlayer shouldAutorotateToInterfaceOrientation: AVCaptureVideoOrientationLandscapeRight];
[self.view addSubview:_moviePlayer.view];
}
- (void) moviePlayerPlaybackStateDidChange: (NSNotification *) notification {
if (_moviePlayer.moviePlayer.playbackState == MPMoviePlaybackStateStopped) {
[_moviePlayer.moviePlayer setContentURL:[_moviePlayer.moviePlayer contentURL]];
[_moviePlayer.moviePlayer play];
}
}
-(void)myMovieFinishedCallback:(NSNotification*)aNotification
{
// to add your code after playback is finished
}