After making some simple changes to an app, the MPMoviePlayerController has begun stuttering when playing videos. The problem only happens about 10% of the time, and so far I haven't discovered any repeatable pattern. The stutter just happens at the beginning: the video starts, and then after about a second, it restarts. That's it.
Here's my setup code, as called from viewDidLoad:
self.moviePlayerController=[[MPMoviePlayerController alloc] initWithContentURL:videoURL];
[self.moviePlayerController setControlStyle:MPMovieControlStyleNone];
[self.moviePlayerController setShouldAutoplay:NO];
[self.moviePlayerController prepareToPlay];
[self.moviePlayerController.view setAlpha:0];
[self.moviePlayerController.backgroundView setBackgroundColor:[UIColor whiteColor]];
And then when the user taps a big play button:
[self.moviePlayerController play];
I've combed through all the code many times, setup up many NSLogs and breakpoints, and don't appear any closer to solving the problem. Why has this started happening? Has anyone else had this issue with MPMoviePlayerController? Thanks for reading.
I ended up swapping out MPMoviePlayerController for AVPlayerViewController. Pretty straight-forward to do, and the stutter is now gone.
Related
So I'm using AVPlayerViewController and what i'm doing to load the video is basically this:
I have a large number of videos in my database, I make a call to the db to retrieve the next video after the current video has finished playing, the issue I think may have to do with the buffer being full? After looking around on stack & the internet I couldn't find an answer that helped me.
I'm trying to find out how can I reset the buffer after each video is played, or atleast know when the buffer is out of space so that I can display an image or something while the buffer loads, so then I can make a call to continue displaying videos. Below is my code for the AVPlayerViewController.
AVPlayerViewController *playerViewController = [[AVPlayerViewController
alloc] init];
playerViewController.player = [AVPlayer #"www.videoURL.com"];
self.avPlayerViewcontroller = playerViewController;
[playerViewController.view setFrame: userView.bounds];
[userView addSubview:playerViewController.view];
self.avPlayerViewcontroller.player.volume = 0.0;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(volumeChanged:)
name:#"AVSystemController_SystemVolumeDidChangeNotification"
object:nil];
[playerViewController.player play];
[userImageView setHidden:NO];
Edit:1) I'm about to play about 15-25 videos before the video play gives me this:
Edit:2) But if I close the app and then re-open it, the videos play on the app like nothings wrong. I'm not really sure whats going on.
For anyone that encounters this same scenario, The issue for me was inside of the the same block that I was making my API call I was initializing this:
AVPlayerViewController *playerViewController =
[[AVPlayerViewController alloc] init];
AVPlayerViewController was (STRONG) reference causing a retain cycle within the block, so each time I made an API call to grab a new video I was init a whole new AVPlayerViewController without releasing the previous. Along with that, I found that I had other objects within the API success response were being referenced strong as well. So I went back made those a WEAK reference and then I moved
AVPlayerViewController *playerViewController =
[[AVPlayerViewController alloc] init];
To the view did load method, so it's initialized ONCE instead of everytime a new video URL comes through.
It took me all day to figure out what was going one, because after looking at other users having problems with this, I was so focused on "BUFFERING" or running out of buffering was the culprit, but comes to find out it was just bad implementation of objects and misplacements.
Good luck to future programmers.
I'm creating an app where the user is supposed to video record himself while another video is playing on the screen next to the camera view. The result will be two video files, one source, and one recording. Using AVCaptureSession etc., I have successfully managed to record a video at the same time as another video is playing on the screen. The problem is that It's not completely in sync.
This is how I have set it up right now:
-(void)playAndRecordInSync //Session is already set etc.
{
player = [AVPlayer playerWithURL:url];
playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
[playerLayer setFrame:leftCameraView.bounds];
[playerLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[leftCameraView.layer addSublayer:playerLayer];
//Will stop recording camera when source video reaches end(notification):
player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[player currentItem]];
//Start playback:
[player play];
//Start recording:
[movieOutput startRecordingToOutputFileURL:outputURL recordingDelegate:self];
}
- (void)playerItemDidReachEnd:(NSNotification *)notification {
[movieOutput stopRecording];
}
The result of this, is two videos, but the second (recorded) video is slightly longer than the source/original video. When playing them on top of each other (at the same time), then video nr. 2 has a delay of almost half a second. It feels like video2 has started recording way too soon, because of the "extra" time. It could probably also be that the playback started too late. Either way, I don't know how to make any consistency here based on this. I could probably play around a lot with sleep etc, but that would only work for my phone, as this has something to do with how fast the phone is.
Even if there is a delegate method like -(void)willStartPlaying for the AVPlayer, which I don't think there is, there would still be a problem with sync, as there's a minor wait till the return. Is there a way to fire two commands at once? Or is there another solution for this?
EDIT
I've been reading this (AVSynchronizedLayer), but I'm not sure if this is applicable to my situation, and I don't understand how to proceed.
I found out the delay was always caused by the playback starting too late, but both the recording and the playback were stopped at the same time, so I resolved this by finding v2.duration - v1.duration, and subtract the result from the beginning of v2, using AVAssetExportSession. When playing back both videos at once now, in different layers, there's still some delay from starting both, but by exporting the videos, I've confirmed that they're the same length and in sync now.
I am trying to have MPMoviePlayerController reach a programmed endPlaybackTime, then reassign the initial, current, and end times and "resume" play
So first play, say, from the start to 4 seconds, stop/pause, then resume and play from 4 to 8, etc...
but after I reassign current, initial, and endPlaybackTimes and run [mplayer play], the video restarts from the originally times (start to 4s) and plays to the original end time, even though debug messages confirm the new times after the second play
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
_mplayer3 = [[MPMoviePlayerController alloc] initWithContentURL:fileURL];
_mplayer3.controlStyle = MPMovieControlStyleNone;
[_mplayer3.view setFrame: self.view.bounds];
[self.view insertSubview:_mplayer3.view belowSubview:_TopBrag];
_mplayer3.endPlaybackTime = 4.0;
[_mplayer3 setShouldAutoplay:NO];
[_mplayer3 prepareToPlay];
[_mplayer3 view].userInteractionEnabled=YES;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(parallaxDownDidFinish)
name:MPMoviePlayerPlaybackDidFinishNotification
object:_mplayer3];
[_mplayer3 play];
on the end notification, there's a gesture recognizer is created that appears to work correctly. in the gesture recognizer:
_mplayer3.initialPlaybackTime=_mplayer3.endPlaybackTime;
_mplayer3.currentPlaybackTime=_mplayer3.endPlaybackTime;
_mplayer3.endPlaybackTime+=4.0;
if (_mplayer3.endPlaybackTime > _mplayer3.duration)
_mplayer3.endPlaybackTime = _mplayer3.duration;
[_mplayer3 play]
and the video plays from 0 to 4 instead of 4 to 8, even though NSLogs after the play suggest the times are what's desired
appreciate any help
MPMoviePlayerController does not adhere to the initialPlaybackTime if not used on a fresh instance. You will need to release and realloc/assign the player to get this working. All you need to do is to reuse the initial code shown in your question once the player aught to continue.
Update:
Since you seem to be keen on keeping the player view active and as you are not using the standard user interface, I would suggest you to use AVPlayer instead. It is much more flexible and for your job it seems to be the right choice then.
I'm not sure whats the problem, because it should work, the problem i think is that you are in IOS 6, IOS 6 doesn't let you make such a small change, but if in your swipe you change the initial playtime to 9 or higher it should work....
try it and then let me know ;)
I have an MPMoviePlayerController where I load a video from a URL. In iOS 3.2.2 the video started downloading when I added it to a view, but it didn't play until I hit the play button (which is what I want). However, since iOS 4.2.1 came out, it started behaving differently; the video starts downloading and plays automatically.
Here's how I load my MPMoviePlayerController:
MPMoviePlayerController *player = [[MPMoviePlayerController alloc]
initWithContentURL:[NSURL URLWithString:theVideo.fileUrl]];
player.view.frame = articleVideoFrame;
[mainView addSubview:player.view];
I even tried to perform a [player pause]; after the addSubview part, but it still plays automatically. Could you guys help me with this one?
Got it! I used player.shouldAutoplay = NO; and that did the trick. Documentation says it is by default YES, which explains it all. Probably in 3.2 default was NO, but has been switched in 4.2.
I have noticed some other behavior changes in video playback in 4.2.1...namely the video player does not become visible until it starts receiving the data for the movie...
In the previous versions it used to come up instantaneously with "Loading movie..." text on top.
Sometimes, the player gets stuck in when not in full screen mode, with no Done button available or not responding to touches on Pause and Zoom...
I am having other more subtle issues with the playback but I can't isolate the issue just yet...
I'm working on an iPad project where i have to play short video files one after another smoothly. For playing the videos i'm using MPMoviePlayerController. The problem i'm facing is that when i call
[self.moviePlayer setContentURL:videoURL]
it does start the next video, but there is ±1 sec delay of black screen before it starts to play the next video (the videos are read from the disk, not streamed). I need to avoid this black screen as well as the delay.
So maybe some of you also experienced this problem and have some solutions? Thanks.
Btw, for now, as to at least avoid the black screen, I capture the last frame of the ending video, show it in a UIImageView, and remove it after 1 sec delay. But i'm hoping to find a more elegant fix.
The effect you are talking about is actually a combination of two problems: a black blink when you change the video (which doesn't happen upon assigning the video for the first time) and the delay before the controller starts playing video.
I'm currently screwed with the second one and don't know how to solve yet. As for the first one, just try to use another instance of MPMoviePlayerController. I mean when a video finishes playing (you can subscribe to a corresponding notification) just remove the old player, create a new one and put video there. This way you will avoid blinking, but there will be a delay (not sure, because of loading the video or because of player creation) before the next video starts playing.
Hope this helps a bit.
Fond solution here
http://joris.kluivers.nl/blog/2010/01/04/mpmovieplayercontroller-handle-with-care/
you need to use [self.moviePlayer prepareToPlay]; and catch MPMoviePlayerReadyForDisplayDidChangeNotification to use [self.moviePlayer play];
Old post but Googlers will still come. :)
Creating a new MPMoviePlayerController then assigning it back to my previous player worked for me, no more black screen!
...
[self playVideoWithFilename:#"video1.mp4"];
}
- (void)playVideoWithFilename:(NSString *)fileName
{
MPMoviePlayerController *player = [MPMoviePlayerController new];
_myVidPlayer = player;
player = nil;
NSURL *vidPath = [[NSBundle mainBundle] URLForResource:fileName withExtension:nil];
[_myVidPlayer.view setBackgroundColor:[UIColor whiteColor]];
[_myVidPlayer.view setFrame:CGRectMake(0, 64, 320, 320)];
[_myVidPlayer setContentURL:vidPath];
[_myVidPlayer setControlStyle:MPMovieControlStyleNone];
[_myVidPlayer setRepeatMode:MPMovieRepeatModeOne];
[_myVidPlayer prepareToPlay];
[self.view addSubview: _myVidPlayer.view];
[_myVidPlayer play];
}
Note:
Available in iOS 2.0 and later
Deprecated in iOS 9.0
"Use AVPlayerViewController in AVKit."
I think that the problem is that the controller will fade out and back in between the movies.
You can control the background view color and contents, but I'm not sure that you can eliminate the fade in/out.