Play video from url in objective c with buffering - ios

Hi everyone I am working on an application in which I have a url of video and I have to play a video from that url. I have done this job from this code
- (IBAction)btnPlayVideo:(id)sender
{
NSString *fileName = #"Server Address/Vdieo.flv";
NSURL *streamURL = [NSURL URLWithString:fileName];
mPlayerVC = [[MPMoviePlayerViewController alloc] initWithContentURL:streamURL];
[self.view addSubview:mPlayerVC.view];
//play movie
MPMoviePlayerController *player = [mPlayerVC moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willEnterFullscreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playbackFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
player.view.frame = self.view.frame;
[player setFullscreen:YES animated:YES];
[self.view addSubview:player.view];
[player prepareToPlay];
[player play];
}
//============Other Methods====================
- (void)willEnterFullscreen:(NSNotification*)notification {
NSLog(#"willEnterFullscreen");
}
- (void)enteredFullscreen:(NSNotification*)notification {
NSLog(#"enteredFullscreen");
}
- (void)willExitFullscreen:(NSNotification*)notification {
NSLog(#"willExitFullscreen");
}
- (void)exitedFullscreen:(NSNotification*)notification {
NSLog(#"exitedFullscreen");
[mPlayerVC.view removeFromSuperview];
mPlayerVC = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)playbackFinished:(NSNotification*)notification {
NSNumber* reason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
switch ([reason intValue]) {
case MPMovieFinishReasonPlaybackEnded:
NSLog(#"playbackFinished. Reason: Playback Ended");
break;
case MPMovieFinishReasonPlaybackError:
NSLog(#"playbackFinished. Reason: Playback Error");
break;
case MPMovieFinishReasonUserExited:
NSLog(#"playbackFinished. Reason: User Exited");
NSLog(#"exitedFullscreen");
[[NSNotificationCenter defaultCenter] removeObserver:self];
break;
default:
break;
}
[mPlayerVC.view removeFromSuperview];
mPlayerVC = nil;
}
My problem is that when this code run video player open and start loading and it takes too much time to run a video. Can anybody guide me how to run video in fast way from internet?

There's nothing in the code that suggests that lag is anything other than the time it takes to make the request and sufficiently buffer. The most common technique to improve UE is to start loading as early as possible, even before the user requests playback.
If this is possible, the code should be reorganized as follows:
// hang on to the movie player
#property(nonatomic,retain) MPMoviePlayerController *mp;
// call this as soon as its possible to know the user might want to see the video
- (void)primeVideo {
NSString *fileName = #"Server Address/Vdieo.flv";
NSURL *streamURL = [NSURL URLWithString:fileName];
MPMoviePlayerController *mp = [[MPMoviePlayerViewController alloc] initWithContentURL:streamURL];
// do this also in dealloc
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willEnterFullscreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playbackFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
mp.shouldAutoplay = NO;
[mp prepareToPlay];
self.mp = mp;
}
That does as much prep as possible without changing the UI. The rest of your code from the button action is left, tweaked a little...
- (IBAction)btnPlayVideo:(id)sender {
// if there's any way that the user can request playback before
// you've called primeVideo, check for that here. But hopefully you
// can call primeVideo before user even sees the play button
if (!self.mp) [self primeVideo];
self.mp.view.frame = self.view.frame;
[self.mp setFullscreen:YES animated:YES];
[self.view addSubview:self.mp.view];
MPMovieLoadState state = [self.mp loadState];
if (state & MPMovieLoadStatePlaythroughOK) [self.mp play];
else self.mp.shouldAutoplay = YES;
}

Related

MPMoviePlayerViewController Dismiss Without playing

The problem video can be seen in :
http://app.bowerchat.com/images/118_1435046739658.mp4
MPMoviePlayerViewController Dismissing immediately without play.
What can be reason?Some videos are loaded nicely and playing.
How can i check the video can be played or not?
I tried
NSLog(#"%lu",(unsigned long)self.mpController.moviePlayer.loadState);
NSLog(#"%d",self.mpController.moviePlayer == nil);
Results always 0 - 0
MY Code to play video
self.mpController = [[MPMoviePlayerViewController alloc] initWithContentURL:moveUrl];
[self.mpController.moviePlayer prepareToPlay];
NSLog(#"%lu",(unsigned long)self.mpController.moviePlayer.loadState);
NSLog(#"%d",self.mpController.moviePlayer == nil);
[parent presentMoviePlayerViewControllerAnimated:self.mpController];
The reason could be that movie that has extention *.mp4 is actually of different type.
Also try to add the following:
self.mpController.moviePlayer.shouldAutoplay = YES;
[self.mpController.moviePlayer play];
Try this snippet :
-(void)setupMovie
{
NSURL *movieURL = [NSURL fileURLWithPath:movieURL];
self.mpController = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
self. mpController.scalingMode = MPMovieScalingModeAspectFill;
self. mpController.controlStyle = MPMovieControlStyleNone;
self.mpController.view.frame = self.view.frame;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerPlaybackStateDidChange:) name:MPMediaPlaybackIsPreparedToPlayDidChangeNotification object:nil];
[self.view addSubview:self.mpController.view];
[self.mpController prepareToPlay];
}
- (void)moviePlayBackDidFinish:(MPMoviePlayerController *)player
{
[self.mpController.view removeFromSuperview];
}
- (void)moviePlayerPlaybackStateDidChange:(NSNotification*)notification
{
if (self. mpController.isPreparedToPlay) {
[self. mpController play];
}
}
And make sure movieURL is correct and video exist by this provided url

MPMoviePlayerViewController Subview

I have a view within my view controller and have it declared as a property _movieSubview. I add a MPMoviePlayerViewController to _movieSubview and the video plays nicely.
-(void)moviePlay{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"High Rope" ofType:#"mov"]];
_playerController=[[MPMoviePlayerViewController alloc]initWithContentURL:url];
//[self presentMoviePlayerViewControllerAnimated:_playerController];
_playerController.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[_playerController.moviePlayer prepareToPlay];
_playerController.moviePlayer.repeatMode = MPMovieRepeatModeOne;
_playerController.moviePlayer.controlStyle = MPMovieControlStyleNone;
_playerController.moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
[_playerController.moviePlayer play];
/*[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:_playerController];*/
//---play partial screen---
_playerController.view.frame = CGRectMake(0, 0, 320, 460);
[_movieSubview addSubview:_playerController.view];
}
- (void)moviePlayerDidFinish:(NSNotification *)note
{
if (note.object == _playerController) {
NSInteger reason = [[note.userInfo objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] integerValue];
if (reason == MPMovieFinishReasonPlaybackEnded)
{
[_playerController.moviePlayer play];
}
}
}
My 2 questions are:
My status bar disappears when I add the MPMoviePlayerViewController inside my subview. How do I keep the status bar?
How can I have the video play twice on repeat, then wait for user to play after that?
You should present _playerController instead of adding as subview. Use this code while creating the instance of MPMoviePlayer:
[moviePlayer setFullscreen:YES animated:YES];
moviePlayer.controlStyle = MPMovieControlStyleFullscreen;
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self selector:#selector(moviePlayerEvent:) name:MPMoviePlayerLoadStateDidChangeNotification object:moviePlayer];
[notificationCenter addObserver:self selector:#selector(playBackStateChanged:) name:MPMoviePlayerPlaybackStateDidChangeNotification object:moviePlayer];
-(void)moviePlayerEvent:(NSNotification*)aNotification{
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:NO];
}
-(void)playBackStateChanged:(id)sender{
MPMoviePlaybackState playbackState = [moviePlayerViewController.moviePlayer playbackState];
switch (playbackState) {
case MPMoviePlaybackStateStopped :
//play again
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter removeObserver:self];
break;
case MPMoviePlaybackStatePlaying :
break;
case MPMoviePlaybackStateInterrupted :
break;
}
}

AVQueuePlayer AVPlayerItemDidPlayToEndTimeNotification fails to call

Im using AVQueuePlayer to loop through an array of AVPlayerItems.
The way I'm looping it, I listen to the AVPlayerItemDidPlayToEndTimeNotification and every time its called, I add the current object to the end of the queue.
heres the code:
viewWillAppear
{
...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[_queuePlayer currentItem]];
[_queuePlayer play];
}
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
AVPlayerItem *fakeNew = [[AVPlayerItem alloc] initWithAsset:p.asset];
if (_queuePlayer.items.count == 1)
{
[p seekToTime:kCMTimeZero];
[_queuePlayer play];
}
else
{
[_queuePlayer insertItem:fakeNew afterItem:[_queuePlayer.items lastObject]];
}
NSLog(#"array of items to play:%lu", (unsigned long)_queuePlayer.items.count);
}
The problem is, that the method is called only for the first video that plays, after that, the method stops getting called, so if for example i have 2 movies in the array, it would play them both+the first one again, any idea why is this happening?
More Info:
also tried to make a new player every time and set it to layer. failed to send the notification more than once just the same
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
[self.playList removeObjectAtIndex:0];
[self.playList addObject:p];
AVPlayer *newPlayer = [[AVPlayer alloc] initWithPlayerItem:[self.playList objectAtIndex:0]];
_player = newPlayer;
self.AVPlayerLayerView.layer.player = self.player;
[_player play];
}
After a lot of messing around, apparently for whatever reason, the view unregistered as observer every time, I just removed and added observer after every notification:
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
AVPlayerItem *fakeNewItem = [[AVPlayerItem alloc] initWithAsset:p.asset];
[self.playList removeObjectAtIndex:0];
[self.playList addObject:fakeNewItem];
AVPlayer *newPlayer = [[AVPlayer alloc] initWithPlayerItem:[self.playList objectAtIndex:0]];
_player = newPlayer;
self.AVPlayerLayerView.layer.player = self.player;
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[_player currentItem]];
[_player play];
}
For a clean approach to resolve this issue. I approached with the next piece of code instead
The first is you have to add the code necessary to receive a feedback from the AVPlayer when the reproduction time changes.
- (void)addPeriodicTimeObserverForReproductionChanges {
#weakify(self);
[self.player
addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(kBQDefaultTimeIntervalReproductionChanges, NSEC_PER_SEC)
queue:self.eventsQueue
usingBlock:^(CMTime time) {
#strongify(self);
[self dispatchBlockOnMainQueue:^{
if ([self.delegate respondsToSelector:#selector(playerItemController:didChangeReproductionTime:)])
[self.delegate playerItemController:self
didChangeReproductionTime:time];
[self checkForItemPlayToEnd];
}];
}];
}
- (void)checkForItemPlayToEnd
{
CMTime durationScaled = CMTimeConvertScale(self.duration,self.player.currentTime.timescale, kCMTimeRoundingMethod_Default);
if (CMTIME_COMPARE_INLINE(durationScaled, ==, self.player.currentTime)) {
[self playerDidFinishReproducingItem];
}
}

view doesn't come back after video plays

I'm running the following code. The video plays fine but after it finishes it just goes to a black srcreen, my original view never comes back. When I tap on the black screen i just see the message "loading....." Can someone please explain what I'm doing wrong. Thanks
- (IBAction)video:(UIBarButtonItem *)sender
{
{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"IMG_0973" ofType:#"MOV"]];
moviePlayer=[[MPMoviePlayerController alloc] initWithContentURL:url];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayBackDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayBackDonePressed:) name:MPMoviePlayerDidExitFullscreenNotification object:moviePlayer];
moviePlayer.controlStyle=MPMovieControlStyleDefault;
//moviePlayer.shouldAutoplay=NO;
[moviePlayer play];
[self.view addSubview:moviePlayer.view];
[moviePlayer setFullscreen:YES animated:YES];
}
}
- (void) moviePlayBackDonePressed:(NSNotification*)notification
{
[moviePlayer stop];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerDidExitFullscreenNotification object:moviePlayer];
if ([moviePlayer respondsToSelector:#selector(setFullscreen:animated:)])
{
[moviePlayer.view removeFromSuperview];
}
moviePlayer=nil;
}
- (void) moviePlayBackDidFinish:(NSNotification*)notification
{
[moviePlayer stop];
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
if ([moviePlayer respondsToSelector:#selector(setFullscreen:animated:)])
{
[moviePlayer.view removeFromSuperview];
}
}
Add this notification Method
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePreloadDidFinish:) name:MPMoviePlayerLoadStateDidChangeNotification
object:player];
This method is called after your movie is loaded and in this method you add your moviePlayer view.
-(void)moviePreloadDidFinish:(NSNotification*)notification
{
moviePlayer.controlStyle=MPMovieControlStyleDefault;
[self.view addSubview:moviePlayer.view];
[moviePlayer play];
[moviePlayer setFullscreen:YES animated:YES];
}
In your video IBAction, you need to add the subview before you tell it to play. Switch the lines [moviePlayer play] and [self.view addSubview:moviePlayer.view]. Let us know it it works! Actually you may need to place moviePlayer play even after the full screen line.
i think this will help you .....
-(void)playVideo
{
NSString *contentURL = [[NSBundle mainBundle] pathForResource:#"xyz" ofType:#"mp4"];
MPMoviePlayerViewController *moviePlayerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:contentURL]];
if (moviePlayerViewController)
{
[moviePlayerViewController.moviePlayer setMovieSourceType:MPMovieSourceTypeFile];
[moviePlayerViewController.moviePlayer setFullscreen:YES];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(MovieFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayerViewController.moviePlayer];
[moviePlayerViewController.moviePlayer play];
[navi presentModalViewController:moviePlayerViewController animated:NO];
[moviePlayerViewController release];
moviePlayerViewController = nil;
}
}
-(void)MovieFinished:(NSNotification *)notification
{
MPMoviePlayerController *player = (MPMoviePlayerController *)notification.object;
[player stop];
[[NSNotificationCenter defaultCenter] removeObserver:self];
//do rest of the stuff
}

Why is it not possible to use the MPMoviePlayerController more than once?

In MonoTouch, we ran into this problem with the Movie Player sample in that it would only play the video once, but would not play it a second time.
I am asking this question to post an answer, since it has been hitting various folks.
MPMoviePlayerController is a singleton underneath the hood. If you have not properly release'd (ObjC) or Dispose()'d (MonoTouch) and you create a second instance, it will either not play, or play audio only.
Additionally if you subscribe to MPMoviePlayerScalingModeDidChangeNotification or MPMoviePlayerPlaybackDidFinishNotification or MPMoviePlayerContentPreloadDidFinishNotification, be warned that the posted NSNotification takes a reference to the MPMoviePlayerController as well, so if you keep it around, you will have a reference the player.
Although Mono's Garbage Collector will eventually kick-in, this is a case where deterministic termination is wanted (you want the reference gone now, not gone when the GC decides to perform a collection).
This is why you want to call the Dispose () method on the controller, and the Dispose() method on the notification.
For example:
// Deterministic termination, do not wait for the GC
if (moviePlayer != null){
moviePlayer.Dispose ()
moviePlayer = null;
}
If you were listening to notifications, call Dispose in your notification handler at the end, to release the reference that it keeps to your MPMoviePlayerController for example:
var center = NSNotificationCenter.DefaultCenter;
center.AddObserver (
"MPMoviePlayerPlaybackDidFinishNotification"),
(notify) => { Console.WriteLine ("Done!"); notify.Dispose (); });
Can't see your code Nir and I don't have edit privileges so here it is again:
The secret lays in the endPlay with setting the: moviePlayer.initialPlaybackTime = -1; before releasing it. Try it out : :)
-(void)playMovie:(NSString *)urlString{ movieURL = [NSURL URLWithString:urlString];
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
moviePlayer.initialPlaybackTime = 0;
//Register to receive a notification when the movie has finished playing.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(endPlay:) name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
moviePlayer.movieControlMode = MPMovieControlModeDefault;
moviePlayer.backgroundColor = [UIColor blackColor];
[moviePlayer play];
}
-(void)endPlay: (NSNotification*)notification{
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
moviePlayer.initialPlaybackTime = -1;
[moviePlayer stop];
[moviePlayer release];
}
The secret lays in the endPlay with setting the: moviePlayer.initialPlaybackTime = -1;
before releasing it.
Try it out :
:)
-(void)playMovie:(NSString *)urlString{
movieURL = [NSURL URLWithString:urlString];
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
moviePlayer.initialPlaybackTime = 0;
//Register to receive a notification when the movie has finished playing.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(endPlay:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
moviePlayer.movieControlMode = MPMovieControlModeDefault;
moviePlayer.backgroundColor = [UIColor blackColor];
[moviePlayer play];
}
-(void)endPlay: (NSNotification*)notification{
[[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer];
moviePlayer.initialPlaybackTime = -1;
[moviePlayer stop];
[moviePlayer release];
}

Resources