Looping a specific segment of a movie using AVPlayer - always seeks back to beginning - objective-c

I have a video that is about 12 seconds long. Seconds 5-10 are loopable.
I want to play the video from the start the first time, then continue to loop over seconds 5-10 afterwards indefinitely.
However when I try, the video just jumps back to the beginning again.
Am I doing something wrong here? The video is H.264 mp4 format.
Here's a snippet of code I use: (the update function gets called every frame)
-(void) update:(double)timeDelta
{
if ( !m_player ) {
return;
}
CMTime time = m_player.m_player.currentTime;
if ( CMTimeGetSeconds(time) > 10.0f ) {
[m_player seekToTime:CMTimeMakeWithSeconds(5.0f, time.timescale)];
}
}
Any help would be much appreciated.
Thanks,
Rich

Most players will only seek to I pictures (Intra pictures). It may be that your clip only has a I picture in the begining and another one after 5 seconds. Check that. If you can re-encode, then re-encode with I pictures inserted every 1 second to allow you to do this.

It's probably seeking to a keyframe, if the keyframe interval on that particular video is greater than 5 seconds.
Try either adjusting the way the video is encoded such that you are able to get a keyframe at the 5 second mark or use
[m_player seekToTime:CMTimeMakeWithSeconds(5.0f, time.timescale) toleranceBefore: kCMTimeZero toleranceAfter: kCMTimeZero];
Note that if you do this, the decoder will have to decode those 5 seconds of video before resuming playback at the point you want, so you may end up with a brief delay in your loop.

Related

Repeating a short sound very fast with CreateJS

Goal
I am trying to create a fast ticking sound in a Cordova app using Createjs.
The ticking sound speed changes based on user settings. At the moment the timing is erratic
Setup
I have an mp3 audio file of a single tick sound that is 50ms long.
A target speed of repetition could be as fast as 10 times per second.
Question
How can I get the sound to play evenly and consistently at that speed?
More Technical Detail
createjs.Ticker.timingMode = createjs.Ticker.RAF_SYNCHED;
createjs.Ticker.framerate = 30;
Cheers for any help
This should be pretty straightforward. I set up a quick fiddle to play a sound a specific amount of times per second. It seems pretty reliable, even when playing at 60fps.
https://jsfiddle.net/lannymcnie/ghjejvq9/
The approach is to just check every Ticker.tick if the amount of time has passed since the last tick sound. The duration is derived by 1000/ticksPerSecond.
// Every tick
var d = new Date().getTime();
if (d > lastTick + 1000/ticksPerSecond) {
createjs.Sound.play("tick");
lastTick = d;
}

Sprite in Game Maker doesn't act the way I want it to

I'm currently working on animating my player so that he behaves like he's breathing.
if(time mod 60==0){
if(image_index==0){
image_index=1;
}
else{
image_index=0;
}
}
time++;
The whole thing is put in the step event and sprite is changing every single step and it even changes to an index 2 and 3, which I haven't even used in the code.
So if anyone has some ideas why does it work like this then please tell me.
It is because the sprite you use has multiple sub-images. GameMaker will naturally iterate the image index every frame.
So first, you need to stop the animation from running with
image_speed = 0;
You have to run this line when the sprite has just been changed, so ideally just after the "sprite_index" variable is changed. If you don't change it, just set image_speed to zero in the creation code.
If you are curious, I found the answer here : How to freeze sprite animation on last frame?

Display AVplayer playback speed in macOS app

I'm starting from an apple demo app called AVMovieEditor. I'm trying to add a visual display of the playback speed. Without any modification from me AVMovieEditor responds to the J,K & L keys like a video editing application. J plays in reverse, J again plays faster in reverse, K is pause, L plays, L again plays faster, etc...
I've successfully created an observer however every time I check the AVplayer.rate it is either -1,0 or 1, despite playing faster than realtime. Indeed when L is pressed the rate goes from 0 to 1, but then L is pressed a second time and the playback speeds up the rate changes back from 1 to 0? The result is similar with J and reverse playback except the rate changes to -1 and then back to 0.
- (void)addPeriodicTimeObserver {
// about 30 times pr second
CMTime interval = CMTimeMake(33, 1000);
// Queue on which to invoke the callback
dispatch_queue_t mainQueue = dispatch_get_main_queue();
// Add time observer
self.timeObserverToken =
[self.movieViewController.playerView.player addPeriodicTimeObserverForInterval:interval
queue:mainQueue
usingBlock:^(CMTime time) {
NSLog(#"%f %f",
self.movieViewController.playerView.player.rate
// only shows -1,0,1 despite playback faster then 100%
[[self.movieViewController.playerView.player.currentItem.tracks[0] assetTrack] nominalFrameRate]);
// Always shows 29.97
}];
}
After much searching I am stumped as to how I can find a useful playback rate?
I'd like to know the actual frame rate of playback, and then I will make an indicator in my GUI to inform the end user the current playback rate.
Edit: I've found another interesting bit of data, but it doesn't solve my problem...
self.movieViewController.playerView.player.currentItem.tracks[0].currentVideoFrameRate
When the above is observed upon starting playback it ramps up from 0 to 30ish, then when L is pressed a second time it ramps up to 60ish. This would solve my problem but for 2 details. First when L is pressed a third time video playback increases, but the currentVideoFrameRate still hangs around 60ish. Second problem is that currentVideoFrameRate only shows positive values. If J is pressed twice and AVPlayer.rate goes back to 0 from -1, there is no way of knowing the frames are traversing in reverse order!
One thing I have found no information on that I think might shed light on a solution is what entity is capturing the J,K & L keyboard events, and what response is being applied?
Edit2: Apple's quicktime player has the functionality I am looking for. It responds to J,K & L like AVMovieEditor but it displays 2x, 5x, 10x, 30x & 60x respectively for it's playback speed and displays them on the left for reverse playback. Is this something reserved for Apple only or can I have it too!?
Edit3: Based on an answer ( Thanks! ) I've started looking at another property AVplayerItem.timebase.rate However this is giving similarly incorrect results.
I can confirm that visually the players rate increases as expected with each press of the "L" key. I would expect that also the "Requested Rate" ( AVplayer.rate ) I was using previously would also increase since I see it visually represented in playback, but not in the reported "Requested Rate". ( it goes to 0 )
The "Playback Actually Occurring Rate" behaves similarly. Except that when I press a stop key, it still displays a rate of 1 presumably because the player was playing at the time of the request to stop. But also AVplayerItem.timebase.rate reports an "Playback Actually Occurring Rate" of 0 when the playback rate is greater than 1 or less than -1.
This is the code I am currently using to see the rate. It's triggered on an observer that watches for changes in the requested rate. Is there a problem with how I am looking at these?
NSLog(#"RequestedPlaybackRate:%f",myAVPlayer.rate);
NSLog(#"OccuringPlaybackRate:%f",CMTimebaseGetRate(myAVPlayerItem.timebase));
I will clarify also that the "Requested Rate" is actually what I want, not the "Playback Actually Occurring Rate".
Edit4:
Created a github project for easy reproduction of this problem and submitted a bug report with Apple.
https://github.com/markjwill/AVPlayerRateBug
AVPlayer.rate is the app's requested playback rate.
The rate at which playback is actually occurring is found with AVPlayerItem.timebase.rate
This is explained in detail in WWDC 2016 Session, "Advances in AVFoundation Playback"
https://developer.apple.com/videos/play/wwdc2016/503/?time=378

Action Script 3. How to prevent lag bugs issues in flash games?

How to prevent lag bugs issues in flash games? For example If game have countdown timer 1 minute and player have to catch that much items that possible.
Here are following lag bugs issues:
If items moving (don't have static position) - that higher lag player
have, that slower items move;
Timer starting count slowly when player have lags (CPU usage 90-100%).
So for example If player without lags can get 100 points, player with slow / bad computer can get 4-6x more, like 400-600.
I think that because It's on client side, but how to move It to server side? Should I insert (and update) countdown time to database? But how to update It on every millisecond?
And how about items position solution? If player have big lags, items moving very very slowly, so easy to click on that, have you any ideas?
Moving the functionality to the server side doesn't solve the problem.
Now if there are many players connected to the server, the server will lag and give those players more time to react.
To make your logic independent from lag, do not base it on the screen update.
Because this assumes a constant time between screen updates (or frames)
Instead, make your logic based on the actual time that passed between frames.
Use getTimer to measure how much time passed between the current and the last frame.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/package.html
Of course, your logic should include calculations for what happens in between frames.
In order to mostly fix speed issues on the client you need to make all your speed related code based on actual time, not frames. For example:
Here is a fairly typical example code used to move an object based on frames:
// speed = pixels per frame
var xSpeed:Number = 5;
var ySpeed:Number = 5;
addEventListener(Event.ENTER_FRAME, update);
function update(e:Event):void {
player.x += xSpeed;
player.y += ySpeed;
}
While this code is simple and good enough for a single client, it is very dependent on the frame rate, and as you know the frame rate is very "elastic" and actual frame rate is heavily influenced by the client CPU speed.
Instead, here is an example where the movement is based on actual elapsed time:
// speed = pixels per second
var xSpeed:Number = 5 * stage.frameRate;
var ySpeed:Number = 5 * stage.frameRate;
var lastTime:int = getTimer();
addEventListener(Event.ENTER_FRAME, update);
function update(e:Event):void {
var currentTime:int = getTimer();
var elapsedSeconds:Number = (currentTime - lastTime) / 1000;
player.x += xSpeed * elapsedSeconds;
player.y += ySpeed * elapsedSeconds;
lastTime = currentTime;
}
The crucial part here is that the current time is tracked using getTimer(), and each update moves the player based on the actual elapsed time, not a fixed amount. I set the xSpeed and ySpeed to 5 * stage.frameRate to illustrate how it can be equivelent to the other example, but you don't have to do it that way. The end result is that the second example would have consistent speed of movement regardless of the actual frame rate.

audio sequencer with swing (shuffle) Obj-C

I'm working on a drum computer with sequencer for the iPad. The drum computer is working just fine and writing the sequencer wasn't that much of a problem either. However, the sequencer is currently only capable of a straight beat (each step has equal duration). I would like to add a swing (or shuffle as some seem to call it) option, but I'm having trouble figuring out how.
'Swing' according to Wikipedia
Straight beat (midi, low volume)
Beat with Swing (midi, low volume)
If I understand correctly, swing is pretty much achieved by offsetting the eights notes between the 1-2-3-4 with a configurable amount. So instead of
1 + 2 + 3 + 4 +
it becomes something like
1 +2 +3 +4 +
The linked midi files illustrate this better...
However, the sequencer works with 1/16th or even 1/32th steps, so if the 2/8th (4/16th) note is offset, how would that affect the 5/16th note.
I'm probably not approaching this the correct way. Any pointers?
Sequencer code
This is the basics of how I implemented the sequencer. I figured altering the stepDuration at certain points should give me the swing effect I want, but how?
#define STEPS_PER_BAR 32
// thread
- (void) sequencerLoop
{
while(isRunning)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// prepare for step
currentStep++;
if(currentStep >= STEPS_PER_BAR * activePatternNumBars)
currentStep = 0;
// handle the step/tick
...
//calculate the time to sleep until the next step
NSTimeInterval stepDuration = (60.0f / (float)bpm) / (STEPS_PER_BAR / 4);
nextStepStartTime = nextStepStartTime + stepDuration;
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
// sleep if there is time left
if(nextStepStartTime > now)
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceReferenceDate:nextStepStartTime]];
else {
NSLog(#"WARNING: sequencer loop is lagging behind");
}
[pool release];
}
}
Edit: added code
I'm not familiar with the sequencer on iOS, but usually sequencers subdivide steps or beats into "ticks", so the way to do this would be to shift the notes that don't fall right on a beat back by a few "ticks" durring playback. So if the user programmed:
1 + 2 + 3 + 4 +
Instead of playing it back like that, you shift any notes falling on the "and" back by however many ticks (depending on exactly where it falls, how much "swing" was used, and how many "ticks" per beat)
1 + 2 + 3 + 4 +
Sorry if that's not much help, or if I'm not much more than restating the question, but the point is you should be able to do this, probably using something called "ticks". You may need to access another layer of the API to do this.
Update:
So say there are 32 ticks per beat. That means the "+" in the diagram above is tick # 16 -- that's what needs to be shifted. (that's not really a lot of resolution, so having more ticks is better).
Lets call the amount we move it, the "swing factor", s. For no swing, s = 1, for "infinite" swing, s=2. You probably want to use a value like 1.1 or 1.2. For simplicity, we'll use linear interpolation to determine the new position. (As a side note, for more on linear interpolation and how it pertains to audio, I wrote a little tutorial) we need to break the time before and after 16 into two sections, since the time before is going to be stretched and the time after is going to be compressed.
if( tick <= 16 )
tick *= s; //stretch
else
tick = (2-s)*tick + 32*(s-1) //compress
How you deal with rounding is up to you. Obviously, you'll want to do this on playback only and not store the new values, since you won't be able to recover the original value exactly due to rounding.
Change the number of steps to 12 instead of 16. Then each beat has 3 steps instead of 4. Triplets instead of 16th notes. Put sounds on the first and third triplet and it swings. Musicians playing swing use the second triplet also.
Offsetting the notes to create a shuffle does not give you access to the middle triplet.