How to observe MPMoviePlayerController according to the playback time? - ios

In order to invoke some events for the specified time, for example, when the video goes to 10.0s, or 20.0s , there should be some events to be invoked, is that possible to observe some property of the instance of MPMoviePlayerController for such cases ? Or any other solutions ?

I had to do almost the same thing and I didn't find any good solution except by using my own NSTimer and look at some moments the current time of the MPMoviePlayer...
So basically, every seconds I'm watching what current time it is and when I'm interrested in the time, I do my stuff.

Related

Syncronizing TMediaPlayer.Position and TTrackBar.Position via LiveBindings

I have a TTrackBar and a TMediaPlayer, I'm looking for a way to change the TTrackBar position according to the TMediaPlayer position using the LiveBindigs feature.
The problem is, there is no event on the TMediaPlayer to watch the changes of the TMediaPlayer.Position property, so my TTrackBar.Position can't synchronize.
Is it possible to watch the changes of a component property without trigger an event?
Not it is not possible to monitor changes of certain property without suitable event.
And you would not want to have any event binded to MediaPlayer.Position property either. Why?
For instance when you are playing a video position is changed for each and every frame which menans that when playing a video with 30 FPS such event would be fired 30 times per second. So depending on the code in that event it could quickly bring your application to a crawl.
So best suggestion that I can give you is for you to place a timer on your form and then check media player position in certain intervals to update your TrackBar. I believe one second interval would is more than enough but you can make it shorter if you will.
Just make sure that if you also use TrackBar for seeking ability to use some control variable to see whether the TrackBar position is being updated by user or by your Timer. Other vise you will end up with weird stuttering (happened to me the first time).
As for achieving all this with LiveBindings alone I don't think it is possible.

AVAudioPlayer setting a pre-defined stop point on the audio file without input from user

I've been struggling trying to set specific points for start and stop an audio file. I downloaded Apple's sample code avTouchController. So far I've been successful in changing currentTime to start the playback. I have tried several ways to create a stopPlayer method. I created it and have no issues. However, so far the player doesn't stop.
ANy clues?
Here's the method I've implemented
(void)stopPlaybackForPlayer:(AVAudioPlayer *)p
{ if (p.playing)
if (p.currentTime == 6 )
{
[p stop];
[self updateViewForPlayerState:p];
}
}
How are you calling this method? Have you put a breakpoint into it to see what is happening?
As far as I can see, the only way to do this with an AVAudioPlayer is to set an NSTimer which will call that method for you when it fires. Having an equality check for the currentTime is probably not a good idea there because it the time might not be exactly what you expect and can be slightly smaller or larger. If you've set a timer for roughly the time you want it to stop, having the method execute and stop the player unconditionally should be fine.
Have you considered using an AVPlayer instead? You can achieve this more easily by simply using the addPeriodicTimeObserverForInterval:queue:usingBlock: method to accomplish this pretty easily.

AVPlayer pauses for no obvious reason

While playing a video, I'm seeing rate change notifications from AVPlayer that don't seem to be connected to app activity.
When my app receives a UIApplicationDidEnterBackgroundNotification notification, I tell the AVPlayer to pause.  The logic is that it should come back to the foreground at the same place the user left. If I do not call pause when going to the background, the problem doesn't appear.
The sequence of events sent to the player is pause, seekToTime:, play.  Generally, this works fine but, after the app has been sent to the background and then returned to the foreground, each play invocation results in two rate changes from the AVPlayer.  The first is to 1 and the second, immediately following, is to 0.  This pattern continues for each call to  -[AVPlayer play] as long as that player instance is in use.
I'm able to put a breakpoint on -[AVPlayer pause] and I do not see it being hit when the rate changes to 0.  If I comment out the seekToTime: call, the problem goes away.  If I use seekToTime:completionHandler:, I also get the same problem although my block's finished parameter is YES.
Apart from "how do I fix this", I'm interested in any details about how to detect the reason for rate changes in AVPlayer that aren't connected to play/pause.  (Putting a breakpoint on -[AVPlayer setRate:] never seems to trigger.)
(One workaround that almost works is to save the player position when entering the background, let it play, and fix the position when returning to the foreground.  This also requires some manipulation of audio levels, which is probably doable, but another problem is that not all background notifications indicate that the view has been obscured (e.g. double-tap home button).  This leads to cases where my workaround shows a distracting moving image when the app is interrupted but still visible.)
Suggestions?
(A last bit of extra information: In all the cases I've tried, I eventually get to a state where the AVPlayer is changing the rate from 1 to 0 moments after I invoke 'play' if I've returned from the background and then performed a seek. There are things I can do to make it less frequent but none that eliminate it except getting rid of the AVPlayer and creating a new instance. This results is very long delays but is better than a complete malfunction...I guess.
I have some evidence that the seek distance affects the result, which suggests that the error might be in the underlying buffering mechanism. Without knowing what causes the rate change (other than play/pause) I don't see a way to investigate further.)
You are probably getting an AVPlayerItemPlaybackStalledNotification.
Try this:
[[NSNotificationCenter defaultCenter]
addObserverForName:AVPlayerItemPlaybackStalledNotification
object:cell.avPlayerItem
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
DDLogVerbose(#"%#", #"AVPlayerItemPlaybackStalledNotification");
}];
However, Apple docs say Playback will continue once a sufficient amount of media has subsequently been delivered. (https://developer.apple.com/library/iOS/documentation/AVFoundation/Reference/AVPlayerItem_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40009532-CH1-SW83)
This is not happening for me or you.
I am still tracking the reason down.
EDIT:
This was the problem for me. When AVPlayerItem.likelyToKeepUp was YES then it wouldn't happen.
Not sure why it wasn't resuming.
EDIT:
From the Apple docs there is a situation where playback will not resume:
This property communicates a prediction of playability. Factors
considered in this prediction include I/O throughput and media decode
performance. It is possible for playbackLikelyToKeepUp to indicate NO
while the property playbackBufferFull indicates YES. In this event the
playback buffer has reached capacity but there isn't the statistical
data to support a prediction that playback is likely to keep up in the
future.
It is up to you to decide whether to continue media playback.

Timer and Dispatcher Timer in Emulator vs. Device

I need to use a timer in my WP7 application and display it's value in the UI.
I managed to get it working two ways: one using the DispatcherTimer class and the other using the Timer class.
The problem is that the DispatcherTimer is slower than "real-time" and the Timer class actually goes faster than "real-time". So both go wrong.
Is this because I'm running it in the emulator? Don't have a device to test it on. Anyone had this issue and tested on both?
To show time accurate to one second on screen, I use a DispatcherTimer that updates every 500 milliseconds and then subtract the current time from the start time to get the time elapsed and display that on-screen.
Does that help?

what is the best way to update a timer UI

My app draws a timer (with detail to .1 seconds), for which I am currently using a NSTime which fires every .1 seconds. This feels like an absolutely terrible idea, but I'm not sure how else to do it. I don't really care about the .1 seconds updating always, but I would like it to update more than once per second. Is there a good way to do this?
NSTimer doesn't strike me as a bad approach. NSTimer is generally a very regular way to keep track of time (indeed it was used for animation timing before CADisplayLink came along). Unless you are seeing unacceptable performance of your timer display updating, I would stick with this approach.
If you are having issues with delays and inaccurate time readings, you could store the start time in NSDate, and continue to use the NSTimer but only to update the display. On each timer event firing, you then update the display by finding the NSTimeInterval from the start time to now. This way even if there is a performance issue, at least the time being display should remain accurate at the time of display.

Resources