Video Controls for Pausing and Unpausing a Movie

Hello, I am attempting to allow a video to ONLY play when a key on the keyboard is pressed, and then the spacebar key is supposed to record when the participant is done pressing the other key. For instance, imagine a paused video and you must press the ‘c’ key for it to play AND continue playing, but once you are done watching, you can hit the spacebar key to move onto another video. I am rather new to programming, so any advice or assistance would be much appreciated.

— Run Routine “trial” —

    while continueRoutine:
        # get current time
        t = routineTimer.getTime()
        tThisFlip = win.getFutureFlipTime(clock=routineTimer)
        tThisFlipGlobal = win.getFutureFlipTime(clock=None)
        frameN = frameN + 1  # number of completed frames (so 0 is the first frame)
        # update/draw components on each frame
        
        # *fixation* updates
        if fixation.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
            # keep track of start time/frame for later
            fixation.frameNStart = frameN  # exact frame index
            fixation.tStart = t  # local t and not account for scr refresh
            fixation.tStartRefresh = tThisFlipGlobal  # on global time
            win.timeOnFlip(fixation, 'tStartRefresh')  # time at next scr refresh
            fixation.setAutoDraw(True)
        if fixation.status == STARTED:
            # is it time to stop? (based on global clock, using actual start)
            if tThisFlipGlobal > fixation.tStartRefresh + 1-frameTolerance:
                # keep track of stop time/frame for later
                fixation.tStop = t  # not accounting for scr refresh
                fixation.frameNStop = frameN  # exact frame index
                fixation.setAutoDraw(False)
        
        # *video* updates
        if video.status == NOT_STARTED and tThisFlip >= 1-frameTolerance:
            # keep track of start time/frame for later
            video.frameNStart = frameN  # exact frame index
            video.tStart = t  # local t and not account for scr refresh
            video.tStartRefresh = tThisFlipGlobal  # on global time
            win.timeOnFlip(video, 'tStartRefresh')  # time at next scr refresh
            video.setAutoDraw(True)
        if video.status == FINISHED:  # force-end the routine
            continueRoutine = False
        
        # *response* updates
        waitOnFlip = False
        if response.status == NOT_STARTED and tThisFlip >= 1-frameTolerance:
            # keep track of start time/frame for later
            response.frameNStart = frameN  # exact frame index
            response.tStart = t  # local t and not account for scr refresh
            response.tStartRefresh = tThisFlipGlobal  # on global time
            win.timeOnFlip(response, 'tStartRefresh')  # time at next scr refresh
            # add timestamp to datafile
            thisExp.timestampOnFlip(win, 'response.started')
            response.status = STARTED
            # keyboard checking is just starting
            waitOnFlip = True
            win.callOnFlip(response.clock.reset)  # t=0 on next screen flip
            win.callOnFlip(response.clearEvents, eventType='keyboard')  # clear events on next screen flip
        if response.status == STARTED and not waitOnFlip:
            theseKeys = response.getKeys(keyList=['space'], waitRelease=False)
            _response_allKeys.extend(theseKeys)
            if len(_response_allKeys):
                response.keys = _response_allKeys[0].name  # just the first key pressed
                response.rt = _response_allKeys[0].rt
                # a response ends the routine
                continueRoutine = False
        # Run 'Each Frame' code from code
        if video.status == FINISHED and checkvideo==1:
            video.tStop=t
        #    videoframe=frameN
            checkvideo=0
        
        
        # check for quit (typically the Esc key)
        if endExpNow or defaultKeyboard.getKeys(keyList=["escape"]):
            core.quit()
        
        # 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
            win.flip()

It looks like this is generated from the builder. You want to add a code component to the trial in that case. I think you can do it with just this in the “Each Frame” tab of your code component:

playKey = response.getKeys(keyList=['c'], waitRelease=False)
if len(playKey):
    video.play()
else:
    video.pause()

It looks like the movie automatically starts playing before the “each frame” code would be called, so it may play for a couple frames before pausing.

Thank you so much for your assistance! However, psychopy says:
############### Experiment ended with exit code -11 [pid:96259] ################

And, I changed the coding under Run ‘Each Frame’ code by code:

   # Run 'Each Frame' code from code
        playKey = response.getKeys(keyList=['c'], waitRelease=False)
        if len(playKey):
            video.play()
        else:
            video.pause()
        if video.status == FINISHED and checkvideo==1:
            video.tStop=t
        #    videoframe=frameN
            checkvideo=0

The exit code doesn’t say exactly what went wrong. There should be some more specific error text above it, but -11 is going to be something other than a simple Python error (that’s exit code 1).

Is it working or how exactly is it behaving?

The last time I ran it, the audio turned off for the videos and the videos continued to play. I pressed c, but nothing happened. It seems the videos aren’t pausing at all. But, Psychopy did say something above the exit code 0.

128.2371 WARNING Max reportNDroppedFrames reached, will not log any more dropped frames
130.3724 WARNING 0.11352558399084955: Video catchup needed, advancing self._nextFrameT from 0.0 to 0.04

If it says exit code 0 it ran successfully. I suspect -11 is some kind of memory error, which can happen when you’re rapidly playing and pausing a video. The audio issue is probably related

If it’s never pausing, try this for your ‘each frame’ code:

playKey = response.getKeys(keyList=['c'], waitRelease=False)
if playKey and not video.isPlaying:
    video.play()
elif video.isPlaying and not playKey:
    video.pause()

The “isPlaying” property should say whether or not the video is currently playing, which means it will only call ‘play’ if it’s not playing and ‘pause’ if it is.

Hello, sorry for the late reply!

But, Psychopy says is ‘isPlaying’ doesn’t exist.

And, for some reason, even if it is exit code 0, the video isn’t pausing though. At all.

Thanks!

Exit code 0 just means there’s no error that stops the code from running, that doesn’t mean it works as intended. The fact that isPlaying isn’t working is annoying, and might indicate that this is using a different movie backend than I thought. What version of PsychoPy are you on?

In any case this might work:

playKey = response.getKeys(keyList=['c'], waitRelease=False)
if playKey:
    video.play()
else:
    video.pause()

But it might also cause the memory error from “play” and “pause” being called too frequently. Try it and see what happens.

Thank you so much for your assistance, but it still is not pausing. It likes to continue to play. Even when I press c, its like it pauses for a fraction of a second, before resuming to play. I’m thinking it may have something to do with ContinueRoutine or something. I am running PsychoPy (v2022.2.5).

Sincerely,
Jazmyne Ross

Can you share your experiment’s psyexp file?

Please have a look at my movie-stim-control demo:
video_control_minimal [PsychoPy] (use “p” for play and “s” for stop)

Just Updated the Demo to the newest PsychoPy Version and I added a part for Keyboard Control (find the part for “Only Play during keypress” in the comments of the Python Code).

https://gitlab.pavlovia.org/luke.boelling/movie_stim_controls/

As @jonathan.kominsky pointed out (Video Controls for Pausing and Unpausing a Movie - #6 by jonathan.kominsky) memory issues appear if you have rapid calls of the .play()/.pause() functions (e.g. per frame).

My code avoids many issues both for Offline and Online Experiments that might occur due to timing problems (e.g. .isPlaying seems to be not reliable enough if you do not check explicitly frame by frame “manually”).

1 Like

Thank you all so much for your help! The video didn’t pause after uncommenting…
else:
movieIsPlaying = False
However, using this line of code did work.
if globalClock.getTime() < (t+1):
movieIsPlaying = False

Thanks!