Lag when playing a video (coder)

Hello,

I am struggling with a small lag that occurs when I play a video. I am using the coder to implement my experiment. To show the video, I took some code that was generated by the builder and adapted it.

This is the function I use to play the video:
It is supposed to play for 750 ms.
Window has the following specifications:

    window = visual.Window([1280, 720], # 1280, 720
                            monitor="testMonitor",
                            pos=(0,0),
                            units='pix',
                            fullscr=True,
                            screen=0
                            )

Movie:

    movie = visual.MovieStim(
        window, 
        name='movie',
        movieLib='ffpyplayer',
        loop=False, 
        volume=1.0,
        pos=(0, 0), 
        size=(640,360), 
        units=None,
        ori=0.0, 
        anchor='center',
        opacity=None, 
        contrast=1.0,
        )

Stimulus contains the path to the video, and the other 3 are clocks I use to keep track of time.

This is the function I use to play the video:

def run_video(window, stimulus, clock_t0, clock_block, clock_trial, movie):
    
    
    movie.filename = stimulus  

    # Create some handy timers
    routineTimer = core.Clock()  # to track time remaining of each (possibly non-slip) routine 

    # --- Prepare to start Routine "trial" ---
    continueRoutine = True
    routineForceEnded = False
    # update component parameters for each repeat
    # keep track of which components have finished
    trialComponents = [movie]
    for thisComponent in trialComponents:
        thisComponent.tStart = None
        thisComponent.tStop = None
        thisComponent.tStartRefresh = None
        thisComponent.tStopRefresh = None
        if hasattr(thisComponent, 'status'):
            thisComponent.status = NOT_STARTED
    # reset timers
    t = 0
    _timeToFirstFrame = window.getFutureFlipTime(clock="now")
    frameN = -1
    
    onset_stim_t0 = clock_t0.getTime()
    onset_stim_block = clock_block.getTime()                                                               
    onset_stim_trial = clock_trial.getTime()  
    print('pre vid', clock_t0.getTime())


    # --- Run Routine "trial" ---
    while continueRoutine and routineTimer.getTime() < 0.75:
        # get current time
        t = routineTimer.getTime()
        tThisFlip = window.getFutureFlipTime(clock=routineTimer)
        tThisFlipGlobal = window.getFutureFlipTime(clock=None)
        frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
        # update/draw components on each frame
        
        # *movie* updates
        if movie.status == NOT_STARTED and tThisFlip >= 0-frameTolerance:
            # keep track of start time/frame for later
            movie.frameNStart = frameN  # exact frame index
            movie.tStart = t  # local t and not account for scr refresh
            movie.tStartRefresh = tThisFlipGlobal  # on global time
            window.timeOnFlip(movie, 'tStartRefresh')  # time at next scr refresh
            # add timestamp to datafile
            movie.setAutoDraw(True)
            movie.play()
        if movie.status == STARTED:
            # is it time to stop? (based on global clock, using actual start)
            if tThisFlipGlobal > movie.tStartRefresh + 0.75-frameTolerance:
                # keep track of stop time/frame for later
                movie.tStop = t  # not accounting for scr refresh
                movie.frameNStop = frameN  # exact frame index
                # add timestamp to datafile
                movie.setAutoDraw(False)
                movie.stop()
        
        # check if all components have finished
        if not continueRoutine:  # a component has requested a forced-end of Routine
            routineForceEnded = True
            break
        continueRoutine = False  # will revert to True if at least one component still running
        for thisComponent in trialComponents:
            if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
                continueRoutine = True
                break  # at least one component has not yet finished
        
        # refresh the screen
        if continueRoutine:  # don't flip if this routine is over or we'll get a blank screen
            window.flip()
            # print('Frame: ', frameN)
            # print(clock_trial.getTime())

    # --- Ending Routine "trial" ---
    for thisComponent in trialComponents:
        if hasattr(thisComponent, "setAutoDraw"):
            thisComponent.setAutoDraw(False)
    movie.stop()
    # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
    if routineForceEnded:
        routineTimer.reset()
    else:
        routineTimer.addTime(-0.7500000)
    print('post vid', clock_t0.getTime())

    return onset_stim_t0, onset_stim_block, onset_stim_trial

I often end up with about 0.8 ish seconds and overall have an increasing lag in my experiment.
I read about static methods, but am not sure if I can improve it here as I show the video frame by frame.
Any help is very much appreciated.

Best wishes
Fabian

How big is the movie file? What resolution? Is there audio?

The movie playback system in general is not super high-performance, unfortunately, but in my experience, movie files without audio and with lower resolutions tend to do better.

You could also experiment with the other movie backends, like MoviePy (the backend of MovieStim3) and see if that does any better.

1 Like

Hi Jonathan,

thanks for your reply!

The movie files range between 100 and 400KB in size.
Resolution is 640*360
There is no audio. (do you think the arguments in movie could cause it to be slow?)

I will try the other backends!

OK, with such small file-size, it’s something about the movie player system initializing or loading playback that’s causing the delay. It might be very slightly faster if you remove the “size” argument (since you are displaying the move at its full size anyway), but I think your best bet is to experiment with different movie backends and see if any of them provide better performance.