Hello everyone,
I am running an experiment where I present a “Learning Block” consisting of: Fixation → Cue Clip → (Gray Screen Gap) → Target Clip.
The Problem: I consistently see a tiny “jump” or flicker (a black rectangle the size of the video element) at two specific moments:
-
Immediately after the Fixation, right before the “Cue” video starts.
-
Immediately after the “Cue” video finishes, right before the “Target” video starts.
My Setup:
-
Background: Gray (RGB = 0, 0, 0 in ‘rgb’ color space).
-
Stimuli: Short video clips using visual.MovieStim.
What I have tried:
-
Using movie.seek(0) followed by movie.draw() before the loop.
-
Adding delays with core.wait().
-
Explicitly drawing a gray fill between the movies, to mask the black one.
-
Reduce the files size.
None of these have eliminated the black frame flash at the onset of the videos.
I attached the relevant function.
Does anyone know how to solve it?
Any help is appreciated!
def run_combined_block_session(win, blocks, block_idx, subj_info, exp_info, clock,diode_cue, fixation, gray_fill,test_instr_dir, test_instr_files,ques_instr_dir, ques_instr_files,math_instr_dir, math_instr_files,screen_size):
# — SETUP —
b = block_idx
block_df = blocks[b]
current_date = datetime.now().strftime(‘%Y-%m-%d’)
stim_hours = {}
stim_times = {}
\# ---------------------------------------------------------
\# 0: SHOW LOADING SCREEN IMMEDIATELY
\# ---------------------------------------------------------
lang = subj_info.get('Language', 'e').lower()
\# Defaults
load_str = "Loading next block...\\nPlease wait."
style_to_use = 'LTR'
text_font = 'Arial'
wrap_w = exp_info.info\['monitor_x_pix'\]
loading_text = visual.TextStim(win, text=load_str,
font=text_font,
units='pix', height=exp_info.info\['text_size'\],
color=exp_info.info\['text_color'\],
languageStyle=style_to_use,
wrapWidth=wrap_w)
loading_text.draw()
win.flip()
\# ---------------------------------------------------------
\# 1. PRELOAD STIMULI
\# ---------------------------------------------------------
print(f"--- Preloading media for Block {b + 1} ---")
movie_list = \[str(p).strip() for p in block_df\['movie_path'\].tolist()\]
cue_list = \[str(p).strip() for p in block_df\['cue_path'\].tolist()\]
cue_set = set(cue_list)
unique_paths = set(movie_list + cue_list)
media_buffer = {}
for vid_path in unique_paths:
if vid_path and str(vid_path) != 'nan' and os.path.exists(str(vid_path)):
try:
if vid_path in cue_set:
vid_size = (960, 540)
else:
vid_size = (exp_info.info\['stim_x_pix'\], exp_info.info\['stim_y_pix'\])
mov = visual.MovieStim(win, filename=str(vid_path),
units='pix',
size=vid_size,
pos=(0, 0),
flipHoriz=False, flipVert=False,
loop=False,
autoStart=False)
media_buffer\[str(vid_path)\] = mov
print(f"Loaded: {os.path.basename(vid_path)}")
except Exception as e:
print(f"Error loading {vid_path}: {e}")
else:
print(f"CRITICAL WARNING: Video not found: {vid_path}")
print(f"--- Finished Loading {len(media_buffer)} unique videos ---")
win.frameIntervals = \[\]
win.recordFrameIntervals = True
\# ---------------------------------------------------------
\# 2. LEARNING PHASE
\# ---------------------------------------------------------
block_log_data = \[\]
location_cue_stim = visual.TextStim(win, text='',
units='pix', height=exp_info.info\['text_size'\],
pos=(0, 350), color=exp_info.info\['text_color'\],
languageStyle='arabic')
stim_hours\[f'block\_{b + 1}\_start'\] = datetime.now().strftime("%H:%M:%S:%f")
\# Flag to skip learning phase if 't' is pressed
skip_learning = False
for i in range(len(block_df)):
\# Check if we need to skip the rest of the learning phase
if skip_learning:
break
movie_path = str(block_df.iloc\[i\]\['movie_path'\]).strip()
cue_path = str(block_df.iloc\[i\]\['cue_path'\]).strip()
location_col_name = f"Where_space\_{subj_info\['Language'\]}"
location_text = str(block_df.iloc\[i\]\[location_col_name\])
if movie_path in media_buffer and cue_path in media_buffer:
movie = media_buffer\[movie_path\]
cue = media_buffer\[cue_path\]
cue.seek(0)
else:
print(f"Error: Missing media for trial {i}. Skipping.")
continue
location_cue_stim.setText(location_text)
\# --- CUE SEQUENCE ---
if i == 0:
fixation.draw()
win.flip()
core.wait(exp_info.info\['block_start_flash'\])
gray_fill.draw()
win.flip()
cue.play()
\# \[NEW\] LEARNING PHASE: DIODE AT START OF CUE CLIP
for \_ in range(exp_info.info\['clip_onset_flash'\]):
cue.draw()
location_cue_stim.draw()
diode_cue.draw()
win.flip()
while not cue.isFinished:
cue.draw()
location_cue_stim.draw()
win.flip()
\# Check for keys: Escape, Test (t), Next Block (n)
keys = event.getKeys(keyList=\['escape', 't', 'n'\])
if 'escape' in keys:
win.close()
core.quit()
elif 't' in keys:
cue.stop()
skip_learning = True
break # Break inner loop
elif 'n' in keys:
cue.stop()
return # Exit function immediately (Next Block)
\# If 't' was pressed, break the main loop too
if skip_learning:
break
cue.stop()
event.clearEvents()
core.wait(exp_info.info\['grey_fill_time'\])
\# --- MOVIE SEQUENCE ---
movie.seek(0)
if movie.status == visual.FINISHED:
movie.stop()
gray_fill.draw()
win.flip()
#core.wait(exp_info.info\['grey_fill_time'\])
stim_hours\[f'block\_{b + 1}\_clip\_{i + 1}\_start'\] = datetime.now().strftime("%H:%M:%S:%f")
movie.play()
\# \[NEW\] LEARNING PHASE: DIODE AT START OF CLIP
for \_ in range(exp_info.info\['clip_onset_flash'\]):
movie.draw()
diode_cue.draw()
win.flip()
while not movie.isFinished:
movie.draw()
win.flip()
\# Check for keys: Escape, Test (t), Next Block (n)
keys = event.getKeys(keyList=\['escape', 't', 'n'\])
if 'escape' in keys:
win.close()
core.quit()
elif 't' in keys:
movie.stop()
skip_learning = True
break # Break inner loop
elif 'n' in keys:
movie.stop()
return # Exit function immediately (Next Block)
\# If 't' was pressed, break the main loop too
if skip_learning:
break
stim_hours\[f'block\_{b + 1}\_clip\_{i + 1}\_end'\] = datetime.now().strftime("%H:%M:%S:%f")
\# Note: We draw fixation AND diode to signal end
fixation.draw()
diode_cue.draw()
win.flip()
core.wait(exp_info.info\['clip_offset_flash'\])
movie.stop()
block_log_data.append({
'ID': block_df.iloc\[i\]\['ID'\],
'BlockID': block_df.iloc\[i\]\['BlockID'\],
'BlockIndex': b,
'TrialIndex': i,
'cb_HMO20': block_df.iloc\[i\]\['cb_HMO20'\],
'clip_Start_H': stim_hours\[f'block\_{b + 1}\_clip\_{i + 1}\_start'\],
'clip_End_H': stim_hours\[f'block\_{b + 1}\_clip\_{i + 1}\_end'\]
})
gray_fill.draw()
win.flip()
core.wait(exp_info.info\['grey_fill_time'\])
\# Save Learning Log
block_df_log = pd.DataFrame(block_log_data)
block_log_filename = ('log_files/' + 'sub' + str(subj_info\['Subject Number'\]) +
f'\_log_block\_{b + 1}\_{current_date}.csv')
block_df_log.to_csv(block_log_filename, index=False)
stim_hours\[f'block\_{b + 1}\_end'\] = datetime.now().strftime("%H:%M:%S:%f")
\# ---------------------------------------------------------
\# 3. INTERMISSION: TEST INSTRUCTIONS
\# ---------------------------------------------------------
run_div3_distractor(
win,
subj_info=subj_info,
duration=45.0,
text_color=exp_info.info\['text_color'\],
instr_dir=math_instr_dir,
instr_files=math_instr_files,
screen_size=screen_size
)
stim_hours\[f'block\_{b + 1}\_test_break_start'\] = datetime.now().strftime("%H:%M:%S:%f")
event.clearEvents()
show_instruction_slides(win, test_instr_dir, test_instr_files, screen_size)
stim_hours\[f'block\_{b + 1}\_test_break_end'\] = datetime.now().strftime("%H:%M:%S:%f")
\# ---------------------------------------------------------
\# 4. TEST PHASE
\# ---------------------------------------------------------
test_log_data = \[\]
current_block_id = block_df\['BlockID'\].iloc\[0\]
test_order_indices = exp_info.test_orders\[current_block_id\]
max_idx = len(block_df)
test_order_indices = \[idx for idx in test_order_indices if idx < max_idx\]
location_col_name = f"Where_space\_{subj_info\['Language'\]}"
for test_i, df_row_idx in enumerate(test_order_indices):
trial_data = block_df.iloc\[df_row_idx\]
cue_path = str(trial_data\['cue_path'\]).strip()
location_text = str(trial_data\[location_col_name\])
if cue_path in media_buffer:
movie_cue = media_buffer\[cue_path\]
movie_cue.seek(0)
else:
print(f"Error: Cue video missing for test trial {test_i}")
continue
location_cue_stim.setText(location_text)
stim_hours\[f'test\_{b}\_{df_row_idx}\_start'\] = datetime.now().strftime("%H:%M:%S:%f")
stim_times\[f'test\_{b}\_{df_row_idx}\_start'\] = clock.getTime()
fixation.draw()
win.flip()
core.wait(exp_info.info\['block_start_flash'\])
\# NOTE: Previously this part flashed only text.
\# Now, we start the movie immediately to flash Diode + Movie.
gray_fill.draw()
win.flip()
movie_cue.draw()
location_cue_stim.draw()
win.flip()
movie_cue.play()
\# \[NEW\] TEST PHASE: DIODE AT BEGINNING OF SCREEN (MOVIE START)
for \_ in range(exp_info.info\['clip_onset_flash'\]):
movie_cue.draw()
location_cue_stim.draw()
diode_cue.draw()
win.flip()
while not movie_cue.isFinished:
movie_cue.draw()
location_cue_stim.draw()
win.flip()
\# Check for keys: Escape, Next Block (n)
keys = event.getKeys(keyList=\['escape', 'n'\])
if 'escape' in keys:
win.close()
core.quit()
elif 'n' in keys:
movie_cue.stop()
return # Exit function immediately (Next Block)
\# \[NEW\] TEST PHASE: FREEZE FRAME UNTIL ENTER
movie_cue.pause() # Freezes at current frame (end)
waiting_for_enter = True
event.clearEvents() # Clear old keys
while waiting_for_enter:
\# Draw static last frame
movie_cue.draw()
location_cue_stim.draw()
win.flip()
keys = event.getKeys(keyList=\['return', 'escape', 'n'\])
if 'return' in keys:
\# \[NEW\] TEST PHASE: DIODE WHEN PATIENT PRESSES ENTER
\# Flash the diode while keeping the frame
for \_ in range(exp_info.info\['clip_onset_flash'\]):
movie_cue.draw()
location_cue_stim.draw()
diode_cue.draw()
win.flip()
waiting_for_enter = False
elif 'escape' in keys:
win.close()
core.quit()
elif 'n' in keys:
movie_cue.stop()
return
movie_cue.stop()
event.clearEvents()
show_instruction_slides(win, ques_instr_dir, ques_instr_files, screen_size)
stim_times\[f'test\_{b}\_{df_row_idx}\_end'\] = clock.getTime()
stim_hours\[f'test\_{b}\_{df_row_idx}\_end'\] = datetime.now().strftime("%H:%M:%S:%f")
test_log_data.append({
'block': b,
'trial': test_i,
'df_row_idx': df_row_idx,
'cue_path': cue_path,
'location_text': location_text
})
test_log_df = pd.DataFrame(test_log_data)
current_hour = datetime.now().strftime("%H-%M-%S")
test_log_filename = ('log_files/' + 'sub' + str(subj_info\['Subject Number'\]) +
f'\_test_log_block\_{b + 1}\_{current_date}\_h\_{current_hour}.csv')
test_log_df.to_csv(test_log_filename)
time_log_filename = ('log_files_hour/' + 'sub' + str(subj_info\['Subject Number'\]) +
f'\_time_log_block\_{b + 1}\_{current_date}\_h\_{current_hour}.csv')
pd.DataFrame(\[stim_hours\]).to_csv(time_log_filename)
return