Objective C How to to present AVPlayer with multiple filePath possibilities - ios

I am using AVPlayer to load up with no controls and act as an animation. With the background presenting the first and last screen of the animation.
When the AVPlayerController is presented, the screen flashes black for a split second as the controller loads up with the corresponding video.
The obvious answer would be to preload the AVPlayerController as soon as possible i.e. when the page loads.
However, my problem is that depending on what button the user clicks, the video must correspond correctly. Therefore, I can't preload as it is undetermined which video the user will need to see.
The function playAnimation gets called with the corresponding filePath of the video.
AVPlayer *player;
AVPlayerViewController *playerViewController;
- (void) playAnimation: (NSString*)filePath {
NSURL *videoURL = [NSURL fileURLWithPath:filePath];
//filePath may be from the Bundle or from the Saved file Directory, it is just the path for the video
player = [AVPlayer playerWithURL:videoURL];
playerViewController = [AVPlayerViewController new];
playerViewController.player = player;
playerViewController.showsPlaybackControls = false;
[self presentViewController:playerViewController animated:false completion:^{
[playerViewController.player play];//Used to Play animation
}];
Would there be any way to load this video controller in the viewDidLoad before hand and then change its source and play upon request without affecting smoothness?

I worked it out!
I created an AVPlayerLayer and then attached this to a UIView, the reason it works without causing a flash of black screen and looking a lot smoother to transition is because it gets initialised first with the correct video file path, then added as a subLayer onto a UIView and then I call to play the video.
Here is the code I used in the end. It may be helpful for anyone also wondering how to attach an AVPlayer to a UIView.
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
CGFloat width = self.view.frame.size.width;
CGFloat height = self.view.frame.size.height;
playerLayer.frame = CGRectMake(0, 0, width, height);
The following code adds the AVPlayerLayer to the UIView but also adds it into an array of layers which I can use when I need to call removeFromSuperlayer in order to dismiss once it has finished playing.
[self.videoView.layer addSublayer:playerLayer];
[arrayOfLayers addObject:playerLayer];
[playerViewController.player play];
To dismiss the view once it has played, I then add a notification observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playBackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];
AVPlayerItem *playerItem = player.currentItem;
And this is the function that gets called to dismiss the view...
-(void)playBackFinished:(NSNotification *) notification {
[arrayOfLayers makeObjectsPerformSelector:#selector(removeFromSuperlayer)];
}

Related

What is the better way to implement video files playback in application background?

I do need to implement iOS application with video files played back in background.
E.g. on first viewController one video should be played back in background instead of some photo or color background.
on second viewController another video should be played back in background instead of some photo or color background.
and so on.
What is the best way to implement this?
* is it better to import those video files in project?
* or is it better to store them in some external place and playback via network?
From the AppStore approval point of view and from the Apple Guidlines point of view - is this case with video correct? Or it's better to avoid video usage in mobile applications?
Thank you in advance.
Found solution with local video files playback via native AVPlayer from AVFoundation
1.Import AVFoundation:
#import <AVFoundation/AVFoundation.h>
2.Use property for player:
#property (nonatomic) AVPlayer *avPlayer;
3.Add video file into "Video" folder and added "Video" into project
4.Initialize the player
NSString *filepath = [[NSBundle mainBundle] pathForResource:#"shutterstock_v885172.mp4" ofType:nil inDirectory:#"Video"];
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
self.avPlayer = [AVPlayer playerWithURL:fileURL];
self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
AVPlayerLayer *videoLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
videoLayer.frame = self.view.bounds;
videoLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer addSublayer:videoLayer];
[self.avPlayer play];
5.Subscribe for event - video did play to the end
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:[self.avPlayer currentItem]];
6.Resume video playback to the very start in related method
- (void)itemDidFinishPlaying:(NSNotification *)notification {
AVPlayerItem *player = [notification object];
[player seekToTime:kCMTimeZero];
}

Playing a mp4 video file using MPMoviePlayerController showing error randomly

I want to play mp4 video files using MPMoviePlayerController.
Here is the code I am currently using:
NSURL *url = [NSURL URLWithString:
videoLink];
MPMoviePlayerController *controller = [[MPMoviePlayerController alloc ]init];
[controller`enter code here` prepareToPlay];
self.mp = controller; //Save obj reference
Also I am re using same player object because have to load another video file as soon as next or previous clicked on UI.
controller.view.frame = CGRectMake(0, yMargin, self.view.frame.size.width, self.view.frame.size.width*9/16); //Set the size
[self.view addSubview:controller.view];//Show the view
[controller setContentURL:url];
[controller play]; //Start playing
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification object:self.mp ];
Sometimes it's loading video properly but randomly showing an error message as given below.
itemFailedToPlayToEnd: {
kind = 1;
new = 2;
old = 0;
}
If error comes it doesn't load any other video afterwards at least for next 15(approx.) attempts.This behaviour is very random as sometimes it keeps showing the error in log and player doesn't load the video at all.
Has someone else faced this similar issue ? I found many questions posted related to this problem but nothing seems to be working for me.
Other solution i found playing a video using web view but auto play
doesn't work for web view.

How can I remove "Loading..." label from MPMoviePlayerViewController?

I have a MPMoviePlayerViewController, I don't want to initialize it with a content url, I just want to have a empty movie player GUI out there. Whenever I want it to load a movie, it then starts loading. But I can't
self.playerViewController = [[MPMoviePlayerViewController alloc] init];
MPMoviePlayerController *player = [self.playerViewController moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerPlaybackStateChanged:) name:MPMoviePlayerPlaybackStateDidChangeNotification object:nil];
player.shouldAutoplay = FALSE;
player.initialPlaybackTime = 0;
[player setFullscreen:FALSE];
[player.view setFrame:CGRectMake(0, -20, self.view.bounds.size.width, self.view.bounds.size.height/2)];
[self.view addSubview:player.view];
As you see, I init the MPMoviePlayerViewController with no content url, and I set the autoplay to false, but when I run the application. Even though there is no video url given, I can still see a label "Loading ..." near the "Done" button, why???? How can I remove the loading label?
Just use MPMoviePlayerController instead of MPMoviePlayerViewController. You'll need to build a view controller around it if you want to display it modally.
You could also maybe iterate through [MPMoviePlayerViewController view].subviews until you find the UILabel, but that approach might break in future versions of iOS.

MPMoviePlayerController showing black empty screen

I use MPMoviePlayerController to play a local file in my Application Document folder which have I have downloaded for a server URL:
itemMoviePlayerController = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];
[self.view addSubview:itemMoviePlayerController.view];
itemMoviePlayerController.fullscreen = YES;
itemMoviePlayerController.movieSourceType = MPMovieSourceTypeFile;
itemMoviePlayerController.initialPlaybackTime = -1.0;
[itemMoviePlayerController play];
When I play .mov file just after I downloaded it, It shows up a black empty screen & app UI is unusable.
But if play same local file next time, it plays fine.
I even verified playState & localState for MPMoviePlayerController they seems fine.
What could be reason for black empty screen?
You need to retain your instance of MPMoviePlayerController i.e. as a property or an instance variable. The reference to the movie player is lost if you do not retain it.
You could try to put [itemMoviePlayerController prepareToPlay];
before the [itemMoviePlayerController play];
The way preferred by Apple to display an only full screen video is to present a modal MPMoviePlayerViewController (as Hollance said).
To present it, you should use something like :
moviePlayerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:fileURL];
[self presentMoviePlayerViewControllerAnimated:moviePlayerViewController];
[itemMoviePlayerController play];
This is documented by Apple here
You can read there that you should keep a reference to your MPMoviePlayerViewController in order to dismiss it later with
[self dismissMoviePlayerViewControllerAnimated:moviePlayerViewController].
I fixed this by putting
#property (strong, nonatomic) MPMoviePlayerController *moviePlayer;
in my .h file, and calling self.moviePlayer in all my code and it worked!
You need to use MPMoviePlayerViewController instead. Notice the word "View" in there.
I hope this will help. I solved this problem in my project
-(void)startPlayingMovie
{
NSLog(#"startPlayingMovie");
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"Start_video" ofType:#"mov"]];
moviePlayer = [[MPMoviePlayerViewController alloc]
initWithContentURL:url];
moviePlayer.view.frame = CGRectMake(0, 0, self.view.bounds.size.height, self.view.bounds.size.width);
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer.moviePlayer];
moviePlayer.moviePlayer.controlStyle = MPMovieControlStyleNone;
moviePlayer.moviePlayer.shouldAutoplay = YES;
[self presentMoviePlayerViewControllerAnimated:moviePlayer];
[moviePlayer.moviePlayer setFullscreen:YES animated:NO];
NSLog(#"endPlayingMovie");
}
Same thing happened to me. It turns out, I had tried to play the movie while the UIImagePicker wasn't dismissed yet.
In my UIImagePickerDelegate I had to first dismiss the UIImagePicker Popup and then open the ViewController managing the MPMediaPlayerController:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)infoDict
{
//the first thing to do: dismiss the media picker
if ([ipPop isPopoverVisible])
{
[ipPop dismissPopoverAnimated:ANIMATION_SETTING];
}
myMediaPlayerViewController * playerVC = [[myMediaPlayerViewController alloc] initWithMediaDict:infoDict];
[self.navigationController pushViewController:playerVC animated:ANIMATION_SETTING];
}
I had this same problem and it made me crazy. It would work on one view controller fine (audio and video), but not work on another (black screen with just audio). In the end, all I did was CHANGE THE ORDER of the calls: I simply waited until I was done configuring the movie player before adding it to the view. In other words, I called "addSubview" on the line just before the call to "play".
This is the code I'm using to play a file from URL:
MPMoviePlayerViewController *movieViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:contentUrl]];
movieViewController.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[self presentMoviePlayerViewControllerAnimated:movieViewController];
[movieViewController release];
It seems to work fine for me. Two notes:
Some simulators (like the current iOS 5.0) crash when playing a movie, but it works on a real device
If you leave out the movieSourceType part, a black screen is shown for about a second before the movie starts
I had the same problem, solved it changing the extension of the file being played from .mpg to .mp4. apparently MPMoviePlayerController expects a correct extension, though from the documentation it is not clear to me that this is a requirement:
http://developer.apple.com/library/ios/#documentation/mediaplayer/reference/MPMoviePlayerController_Class/Reference/Reference.html
Supported Formats This class plays any movie or audio file supported
in iOS. This includes both streamed content and fixed-length files.
For movie files, this typically means files with the extensions .mov,
.mp4, .mpv, and .3gp and using one of the following compression
standards:
This issue seems fixed after updating device iOS to 5.0.
Seems to iOS SDK issue for previous version
you must do like that with CGRectMake(0, 0, 0, 0) in the finished callback!
-(void)playMovieAtURL:(NSURL*)theURL
{
MPMoviePlayerController* theMovie=[[MPMoviePlayerController alloc] initWithContentURL:theURL];
theMovie.scalingMode=MPMovieScalingModeAspectFill;
theMovie.view.frame = CGRectMake(2, 246, 317, 70);
[self.view addSubview:theMovie.view];
// Register for the playback finished notification.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(myMovieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:theMovie];
// Movie playback is asynchronous, so this method returns immediately.
[theMovie play];
}
// When the movie is done,release the controller.
-(void)myMovieFinishedCallback:(NSNotification*)aNotification
{
MPMoviePlayerController* theMovie=[aNotification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:theMovie];
theMovie.view.frame = CGRectMake(0, 0, 0, 0);
// Release the movie instance created in playMovieAtURL
[theMovie release];
}
I was having a similar issue. After playback there comes an empty screen, which prevents me to play video again.
Well here is my work around. That way play button doesn't disappear.
[self.movieController stop];
[self.movieController prepareToPlay];
[self.movieController pause];
Also, If you are using http URLs, make sure you disable App Transport Security in your projects *.plist file. It will also cause a black screen.
Add the following code:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key><true/>
</dict>
Here:
[INSERT CODE ABOVE HERE]
</dict>
</plist>
----- BOTTOM OF PLIST FILE

Video disappearing when played after using UIImagePickerController in a UIPopoverController

I am having the toughest time playing a video after select anything from a UIImagePickerController when the UIImagePickerController is presented in a UIPopoverController.
Here is the code that presents the video:
-(void) presentMovie{
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"demo" ofType:#"mov"];
NSURL *movieURL = [NSURL URLWithString:filePath];
[[mp moviePlayer] setContentURL:movieURL];
[[mp moviePlayer] prepareToPlay];
[[mp moviePlayer] setShouldAutoplay:NO];
[[mp moviePlayer] setControlStyle:MPMovieControlStyleEmbedded];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(videoPlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
[[mp moviePlayer] setAllowsAirPlay:YES];
[[mp view] setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
[screen addSubview:mp.view];
[[mp view] setFrame:screen.bounds];}
mp is a MPMoviePlayerViewController ivar that is allocated and initialized in my viewDidLoad
[self presentMovie] works perfectly unless it is being called from within the -imagePickerController:didFinishPickingMediaWithInfo: method
When called from that delegate methode, the video being displayed by MPMoviePlayerVideoController simply disappears from as soon as it is played. If the 'shouldAutoPlay' property is set to YES, I just see loading for a split second and then blackness. If the 'shouldAutoPlay' property is set to NO, then I see the first frame of the video, and I can scrub to a different location in the vido, take the video in and out of full screen, etc. but soon as I hit play, the view that the video is in goes black. This is true if the video that I'm attempting to play is from the UIImagePickerController selection or from the mainBundle. Once the UIImagePicker is selected, the video will not play.
I have gone through several steps of debugging and this does not happen with the UIImagePickerControll is presented in a modal view on the iPhone only when it's in a UIPopoverController on the iPad.
any ideas? anyone else able to successfully play a video on the iPad selected from a UIImagePickerController?
Turns out the answer is "roll your own" using ALAsssetsLibrary. UIImagePickerContorller doesn't work with video on iPads, and creating your own custom picker isn't too hard. There's sample code from the WWDC 2010 as well as code from Mat Tuzzolo on GitHub https://github.com/elc/ELCImagePickerController
I had this problem, that the video would not play after being picked from UIImagePickerController, but I wasn't fully releasing the popover. When I released it properly, it worked fine.
Thanks to prudence # UIImagePickerController choosing video prevents MPMoviePlayerViewController instance from working

Resources