MPMoviePlayerController audio/video out of sync - objective-c

In my iPad App, I create an MPMoviePlayerController that plays an MP4 off of a website. In the MP4 there are people talking. In the App, I have noticed that the audio and video are out of sync by half a second or a quarter-second, perhaps. (I can tell this because I view the video in a web browser and there is no lag.)
The only clue that I have to this is that when the MPMoviePlayerController first loads up, the audio starts playing, but the video doesn't--then the video starts playing and it seems to skip a couple of frames to "catch up" to the audio...but it doesn't quite sync.
Seeing as how this class is a "black box" per the Apple Documentation, and none of the existing methods or properties come across as helpful to this problem, I'm a bit stumped. I may have to leave it how it is with the slight lag, rather than face weird workarounds. I wanted to see if anyone has experienced this before or could suggest a solution.
I'm running on Mountain Lion, latest XCode, iPad 2 with iOS 6.
The code I use to generate the controller is:
-(void) startVideoPlaying {
if (!self.theMoviePlayer) {
self.theMoviePlayer = [[MPMoviePlayerController alloc] initWithContentURL: movieURL];
[self.bgView addSubview: self.theMoviePlayer.view];
[self.theMoviePlayer.view setFrame: movieContainer.frame]; // player's frame must match parent's
} else {
[self.theMoviePlayer setContentURL:movieURL];
}
self.theMoviePlayer.shouldAutoplay = YES;
[self.theMoviePlayer play];
}
Thanks for any help.

After a variety of tests, I must conclude that there is something wrong with the encoding on the MP4s that I have been playing. I am not a video codec guru, but I made the following tests, which tell me this:
1) Downloading the MP4, placing it into the app and loading it into the MPMoviePlayerController via a file URL. Audio still out of sync, so not a connectivity issue.
2) Finding another MP4 on the web (something off Vimeo) and streaming it into the Player. Audio synced properly, potentially something wrong with the MP4s I was attempting to play.
3) Downloading the MP4, and using Handbrake to convert it into M4V with a variety of different settings (including the iPad preset). The Audio was synced fine.
Based on this, it seems to me like there's something wrong with the file I was attempting to play rather than the player (or the player can't handle it). Unfortunately, the files I am attempting to play cannot simply be converted, they are part of a large website system and many hundreds of files would have to change, and so on. So, while I have answered my own question, I haven't solved the problem.

Related

iOS wrong video orientation, BUG?

When I record video, it always records in landscape mode, regardless of real device orientation. How to force UIImagePicker to set the Portrait orientation?
AGAIN, UIImagePicker is used -- not AVFoundation recording classes.
1) The various properties (movie source type, dimensions, duration, etc.) of MPMoviePlayerController are only available after the movie has been visually played to the user. Before that they all come back 0. I've tried various things like forcing the system to wait a few seconds (to see if it was just a timing issue), but so far, nothing has worked other than actually playing the movie. Evan at that point, I believe those properties are acting as read-only; it's not like I can adjust them directly.
2) The various CGImageSourceRef calls and routines work only on actual images, not movies, on iOS. On MacOS there is more support for movies, also going through the CV (for Video) as opposed to CI (Image) or CG (Graphic) routines. At least, all the examples I've found so far work only on MacOS, and nothing I've found shows working code on iOS, which matches my results of getting a nil result when I attempt to use it.

Is it possible play multiple clips using presentMoviePlayerViewControllerAnimated?

I have a situation where I'd like to play 2 video clips back to back using an MPMoviePlayerViewController displayed using presentMoviePlayerViewControllerAnimated.
The problem is that the modal view automatically closes itself as soon as the first movie is complete.
Has anyone found a way to do this?
Three options:
You may use MPMoviePlayerController and start the playback of the 2nd (Nth) item after the previous is complete. This however will introduce a small gap between the videos cause by identification and pre buffering of the content.
You may use AVQueuePlayer; AVQueuePlayer is a subclass of AVPlayer you use to play a number of items in sequence. See its reference for more.
You may use AVComposition for at runtime composing one video out of the two (or N) you need to play back. Note, this works only on locally stored videos and not on remote (streaming or progressive download). Then use AVPlayer for the playback.
It's not possible. If the video assets are in local file system, consider AVComposition.

AVPlayer seekToTime: Poor performance while looping short videos

this is my first question, but I've readed StackOverflow for years.
Well the thing is that I must concatenate a set of videos (MP4) in a particular order, and the last one must loop continuously. Okay, let's try AVFoundation.
I've defined all the elements such as AVComposition, AVURLAsset and AVPlayerItem. Then I build the AVPlayer and the AVPlayerLayer. Everything is okay and the videos are played in the correct order but... (and here comes the problem)
I can note a tiny flick when the AVPlayer passes from one video to the next one. I can ignore that one, but when AVPlayer reaches AVPlayerItem's end, and the selector is called for AVPlayerItemDidPlayToEndTimeNotification, I use seekToTime to move the reading head to the correct and then play it again. Works fine, but a GREAT flick is repeated when using seekToTime and playing again. I cannot allow that.
Does anybody know how to repeat the last asset on AVPlayerItem continuously and without flicks?
Thank you all.
Absolutely stupid,
Friends, when making video manipulation apps be sure that the videos don't have annoying black frames. That was the root of all problems. [AVPlayer seekToTime:] works perfectly.
Thanks for your time and patience

Playing Audio and Video of a mp4 file separately using AVFoundation Framework

I have developed a media player using AVFoundation for iOS. I am using AVPlayer to play the audio-video files (eg. a mp4 file). It seems quiet simple to play the file using AVPlayer, by directly calling the play, pause APIs.
Now I want to separate the audio and video and play them as individual entities simultaneously. I want to do this because, I may do some editing to the audio or video track, and then play the file.
I can separate the two using AVAssetTracks, but I dont know how to play the tracks. Also, I would like to play the two tracks simultaneously, so that no AVSync problem occurs.
Please guide me how to achieve this target, i.e. audio and video rendering with no AVSync problem.
Thanks..
The easiest way to achieve this would be to have multiple player items. I would create a playerItem with all the tracks in their original form (ie the mp4 file). Then create another asset using AVMutableComposition (a subclass of AVAsset). This allows you to put only certain tracks into the composition (ie the audio track only). When you want to play the audio only, play the playerItem (AVPLayer setCurrentItem:) that has the mutable composition with the audio only track. When you want to play the video only, play the playerItem that has the mutable composition with the video only track. When you want to play both in sync, play the playerItem with the original asset.
I'm assuming you want to play the edited versions in sync. For that you will have to create another AVMutableComposition and add all of the edited tracks. Then call setCurrentItem: with the newly created AVMutableComposition.
If all you are trying to do is edit the different tracks, and never have to play them by themselves, you can do this with one single AVMutableComposition. Just add an audio and video AVMutableCompositionTrack and edit until your hearts content. They will always play in sync no matter how much you edit them separately (assuming your editing logic is correct). Just make sure you don't try to edit while playing. For that, you must create a copy and edit the copy.

AVPlayerLayer - ReProgramming the Wheel?

I'm currently using an AVPlayer, along with an AVPlayerLayer to play back some video. While playing back the video, I've registered for time updates every 30th of a second during the video. This is used to draw a graph of the acceleration at that point in the video, and have it update along with the video. The graph is using the CMTime from the video, so if I skip to a different portion of the video, the graph immediately represents that point in time in the video with no extra work.
Anywho, as far as I'm aware, if I want to get an interface similar to what the MediaPlayer framework offers, I'm going to have to do that myself.
What I'm wondering is, is there a way to use my AVPlayer with the MediaPlayer framework? (Not that I can see.) Or, is there a way to register for incremental time updates with the MediaPlayer framework.
My code, if anyone is interested, follows :
[moviePlayer addPeriodicTimeObserverForInterval: CMTimeMake(1, 30) queue: dispatch_queue_create("eventQueue", NULL) usingBlock: ^(CMTime time) {
loopCount = (int)(CMTimeGetSeconds(time) * 30);
if(loopCount < [dataPointArray count]) {
dispatch_sync(dispatch_get_main_queue(), ^{
[graphLayer setNeedsDisplay];
});
}
}];
Thanks!
If you're talking about the window chrome displayed by MPMoviePlayer then I'm afraid you are looking at creating this UI yourself.
AFAIK there is no way of achieving the timing behaviour you need using the MediaPlayer framework, which is very much a simple "play some media" framework. You're doing the right thing by using AVFoundation.
Which leaves you needing to create the UI yourself. My suggestion would be to start with a XIB file to create the general layout; toolbar at the top with a done button, a large view that represents a custom playback view (using your AVPlayerLayer) and a separate view to contain your controls.
You'll need to write some custom controller code to automatically show/hide the playback controls and toolbar as needed if you want to simulate the MPMoviePlayer UI.
You can use https://bitbucket.org/brentsimmons/ngmovieplayer as a starting point (if it existed at the time you asked).
From the project page: "Replicates much of the behavior of MPMoviePlayerViewController -- but uses AVFoundation."
You might want to look for AVSynchronizedLayer class. I don't think there's a lot in the official programming guide. You can find bits of info here and there: subfurther, Otter Software.
In O'Really Programming iOS 4 (or 5) there's also a short reference on how to let a square move/stop along a line in synch with the animation.
Another demo (not a lot of code) is shown during WWDC 2011 session Working with Media in AV Foundation.