Gray screen before video with VlcMovieStim

I am adapting a PsychoPy movie-watching task for an fMRI study, where I need the timing to be fairly exact. The original task used MovieStim3, but there was a serious mismatch between audio and video (I assume because the video is longer than MovieStim3 can easily handle), so I switched to VlcMovieStim without modifying much else in the task. The video plays really well, but the task shows a gray screen after the video is triggered, but before it starts playing. I was wondering if there was any trick to eliminating the gray screen?

Is the gray screen due to the video loading? Can I force PsychoPy to load the video before the video is supposed to play?

Below is the task code if that would help:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""A video task for an fMRI study.

The task shows a static image (image.png) until the scanner trigger signal
is sent (5 key), after which the video will play (video.mp4).
"""

import os

from psychopy import core, data, event, gui, logging, visual
from psychopy.constants import FINISHED, NOT_STARTED, STARTED
from psychopy.visual.vlcmoviestim import VlcMovieStim

# Ensure that relative paths start from the same directory as this script
script_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(script_dir)

# Store info about the experiment session
experiment_name = "TEST"
experiment_info = {"participant": "", "stimulus": ["test"]}

dlg = gui.DlgFromDict(dictionary=experiment_info, title=experiment_name)
if dlg.OK is False:
    core.quit()

experiment_info["date"] = data.getDateStr()  # add a simple timestamp
experiment_info["experiment_name"] = experiment_name
image_file = "image.png"
if experiment_info["stimulus"] == "test":
    movie_file = "video.mp4"
    video_duration = 427

# Data file name stem = absolute path + name; later add .psyexp, .csv, .log, etc
filename = os.path.join(
    script_dir,
    "data",
    f'{experiment_info["participant"]}_{experiment_name}_{experiment_info["date"]}',
)

# An ExperimentHandler isn't essential but helps with data saving
thisExp = data.ExperimentHandler(
    name=experiment_name,
    version="",
    extraInfo=experiment_info,
    runtimeInfo=None,
    originPath=None,
    savePickle=True,
    saveWideText=True,
    dataFileName=filename,
)
# save a log file for detail verbose info
logFile = logging.LogFile(filename + ".log", level=logging.EXP)
logging.console.setLevel(logging.WARNING)  # this outputs to the screen, not a file

endExpNow = False  # flag for 'escape' or other condition => quit the exp


def save_and_quit(experiment, window, filename):
    experiment.saveAsWideText(filename + ".csv")
    experiment.saveAsPickle(filename)
    logging.flush()
    experiment.abort()
    window.close()
    core.quit()


# Start Code - component code to be run before the window creation

# Set up the Window
win = visual.Window(
    size=(1920, 1080),
    fullscr=True,
    screen=0,
    allowGUI=False,
    allowStencil=False,
    monitor=None,
    color=[0, 0, 0],
    colorSpace="rgb",
    blendMode="avg",
    useFBO=True,
)
win.mouseVisible = False

# store frame rate of monitor if we can measure it
experiment_info["frameRate"] = win.getActualFrameRate()
if experiment_info["frameRate"] is not None:
    frameDur = 1.0 / round(experiment_info["frameRate"])
else:
    frameDur = 1.0 / 60.0  # could not measure, so guess
    print("frameRate not found")

# Initialize components for Routine "trial"
trialClock = core.Clock()
image = visual.ImageStim(
    win=win,
    name="image",
    image=image_file,
    mask=None,
    ori=0,
    pos=(0, 0),
    size=(1920, 1080),
    units="pix",  # added units, changed size from 0.5, 0.5 (ATP)
    color=[1, 1, 1],
    colorSpace="rgb",
    opacity=1,
    flipHoriz=False,
    flipVert=False,
    texRes=128,
    interpolate=True,
    depth=0.0,
)
movie = VlcMovieStim(
    win=win,
    name="movie",
    noAudio=False,
    filename=movie_file,
    ori=0,
    pos=(0, 0),
    opacity=1,
    depth=-1.0,
    size=(1920, 1080),  # size=(1440,900)  # used (1600,900) with Shared PC
)

# Create some handy timers
# to track the time since experiment started
globalClock = core.Clock()
# to track time remaining of each (non-slip) routine
routineTimer = core.CountdownTimer()

# ------Prepare to start Routine "trial"-------
t = 0
trialClock.reset()  # clock
frameN = -1
continueRoutine = True
# allows for time between running the script and starting the scan
# The routineTimer will stop the task after the timer runs out.
routineTimer.add(video_duration)
# update component parameters for each repeat
# keep track of which components have finished
trialComponents = [image, movie]
for thisComponent in trialComponents:
    if hasattr(thisComponent, "status"):
        thisComponent.status = NOT_STARTED

# -------Start Routine "trial"-------
# note: globalClock has been reset to 0.0 by launchScan()
while continueRoutine and routineTimer.getTime() > 0:
    # get current time
    t = trialClock.getTime()
    frameN = frameN + 1  # number of completed frames (so 0 is the first frame)

    if t >= 0.0 and image.status == NOT_STARTED:
        # keep track of start time/frame for later
        image.tStart = t
        image.frameNStart = frameN  # exact frame index
        image.setAutoDraw(True)

    # Changed trigger from "t" key to 5 (TS)
    allKeys = event.getKeys(keyList=["5", "escape"])
    for key in allKeys:
        if image.status == STARTED and key == "5":
            image.setAutoDraw(False)

            movie.tStart = t
            movie.frameNStart = frameN  # exact frame index
            movie.setAutoDraw(True)
            win.flip()

        if key == "escape":
            save_and_quit(thisExp, win, filename)

    if movie.status == FINISHED:
        save_and_quit(thisExp, win, filename)

    # refresh the screen
    # don't flip if this routine is over or we'll get a blank screen
    if continueRoutine:
        win.flip()

Have you tried using the new MovieStim? Assuming you are using a fairly recent version of PsychoPy, it’s better than the old MovieStim3 and should be able to handle larger files. I think this is most likely a vlcMovieStim issue though I couldn’t say exactly what’s causing it.

Switching to MovieStim solved my problem. Thank you!