Specify start and end time during multiple movie playback

Hi,
We have been playing multiple movies sequentially without a break by using async flag 4 for first movie and then 6 for all subsequent movies. And this is working very well. Now we want to specify a start and end frame that each movie should play. The movies should still play without a break. Does anyone have an idea of how to do this ?

After using SetMovieTimeIndex for the first movie, we tried using SetMovieTimeIndex right after we detect a change in movie, but it seems we lose 2-4 frames before the new setting takes effect.

We are running Psychtoolbox 3 on Linux in Matlab 2022b.

Thanks, Best, Saumil

There isn’t any support for doing this seamlessly atm., apart from the slightly glitchy method you are using right now. I’ll have to think if something can be done to support this in the future…

The good thing is that when I say “no can do”, my brain usually starts some background processing, because it hates that answer, and some solution may pop up within finite time. No guarantees though, given a lot of stuff on my todo list atm.

Update: That was faster than expected. The power of procrastination on more important tasks…

So I was wrong, and stuff can probably be done under the approach I recommended and you followed in the other thread.

  1. As you may hopefully have noticed, with async flag +4 there ain’t no audio-video sync, because a frame is returned for display as soon as it is decoded, i.e. possibly earlier than what would be appropriate for audio-video sync. And decoding starts immediately at start of the first movie, running at full playback rate. This means that you can do things like set the requested playback rate in Screen('PlayMovie', movie, rate, ...) to higher than 1, e.g., to 2 for decoding at twice the actual desired speed of the movie. In this case you have to control the actual rate of presentation yourself by timing vbl = Screen('Flip', win, tWhen) accordingly by use of tWhen = vbl + ifi with ifi selected as 1/fps, ie. for a movie that is supposed to play at 30 fps aka one frame every 0.3333 seconds, ifi would need to be 0.3333 seconds. Iow. playback speed is no longer automatically determined by ‘rate’ and movie ‘fps’, but by manual throttling of Flip’s to the proper target display rate. Obviously none of this works reliably with sound due to the total loss of automatic audio-video sync.
  2. If you specify the optional ‘preloadSecs’ parameter in the first ‘OpenMovie’ call, ie. in line 64 of PlayMoviesWithoutGapDemo2.m which we used as reference, then the engine will preload and buffer that many seconds of movie footage as a reserve, reducing the chance of running out of material. The default for buffering is 1 second, you can set higher values, maybe the whole duration of a typical movie for short movies, or even the value -1 to request infinite buffering / buffering of whole movies → Caution with long movies or you might run out of system RAM.
  3. If you want to end the movie before its regular end, you can compare the pts values again to find out when you reached the final frame/time index of your movie. Then you can do a [~, pts] = Screen('GetMovieImage', win, movie, 1, forTimeIndex, [], 2); call, setting forTimeIndex to the total duration of your movie. What this does is performing a fast forward seek to forTimeIndex and thereby to the end of the currently playing movie, without actually generating video textures. It is specifically made for fast and precise forward skipping. pts should contain the pts of the last regular frame of the movie if you chose forTimeIndex correctly. You can skip the regular GetMovieImageDrawTextureFlipClose cycle in this case. The whole point of this is to stop playback at the defined final frame you want to display, and to get the movie playback engine to load and prebuffer and switch to the next movie in your gapless sequence, as loading of a new movie only starts once decoding/playback of the previous one is finished → Which we achieve by fast-skipping to the end.
  4. An if prefetched==1 && pts < lastpts statement that usually detects start of the following movie will also need to be added to the top of the playback loop, before the ‘DrawTexture’ → ‘Flip’ → ‘Close’ statements, to detect as early as possible that “playback” of the new following movie has started. Once you detect that, you first ‘Close’ the just fetched first video image which you don’t want to display, then try to skip ahead to the true start frame of your successive movie, via a “skip ahead” GetMovieImage call a la [tex, pts] = Screen('GetMovieImage', win, movie, 1, newStartTimeInNewMovie, [], 2); with newStartTimeInNewMovie being the desired start frame time index of the new movie. Just like you used fast skipping to the end in point 3 above, but this time without throwing away the actual movie image.

If you did everything right, this should allow starting/stopping successive movies at desired points in time, with minimized chance of dropped/skipped frames.

Many of the mechanisms around async flag 4 and such were actually designed to allow fine-grained efficient seeking and such, way more demanding than what you want. It was never combined with flag 2 though for the original application of this thing: The MPI CyberMotion Simulator - YouTube, which also implemented some paradigms involving high performance playback of stereo high resolution video, where visual and audio stimulation was driven by Psychtoolbox, synchronized with robot motion controlled by a different computer etc. I totally forgot about that.

The brain is calmed down now. No guarantees it will work, but I think it should. But also, you got way more free advice than is usually appropriate for non-paying users. So any further advice will definitely need paid support, which would not even cover the time already spent on this reply.