Difference between revisions of "Video Playback"

From TSG Doc
Jump to navigation Jump to search
Line 116: Line 116:
 
|}
 
|}
 
=== Python ===
 
=== Python ===
Example demonstrating how to create audio:
+
Example demonstrating how to check your audio:
 
<syntaxhighlight lang="python" line>
 
<syntaxhighlight lang="python" line>
 
#!/usr/bin/env python3.10
 
#!/usr/bin/env python3.10
# -*- coding: utf-8 -*-
+
 
 +
import psychopy
 +
print(psychopy.__version__)
 +
import sys
 +
print(sys.version)
 +
 
 +
import keyboard
 +
from psychopy import prefs
 +
from psychopy import visual, core, event
 +
 
 +
from psychopy.sound import backend_ptb
 +
# 0: No special settings (default, not optimized)
 +
# 1: Try low-latency but allow some delay
 +
# 2: Aggressive low-latency
 +
# 3: Exclusive mode, lowest latency but may not work on all systems
 +
backend_ptb.SoundPTB.latencyMode = 2
 +
 
 +
prefs.hardware['audioLib'] = ['PTB']
 +
prefs.hardware['audioDriver'] = ['ASIO']
 +
prefs.hardware['audioDevice'] = ['ASIO4ALL v2']
 +
from psychopy import sound
 +
 
 +
# --- OS-level audio device sample rate ---
 +
default_output = sd.query_devices(kind='output')
 +
print("\nDefault output device info (OS level):")
 +
print(f"  Name: {default_output['name']}")
 +
print(f"  Default Sample Rate: {default_output['default_samplerate']} Hz")
 +
print(f"  Max Output Channels: {default_output['max_output_channels']}")
 +
 
 +
# Confirm the audio library and output settings
 +
print(f"Using {sound.audioLib} for sound playback.")
 +
print(f"Audio library options: {prefs.hardware['audioLib']}")
 +
print(f"Audio driver: {prefs.hardware.get('audioDriver', 'Default')}")
 +
print(f"Audio device: {prefs.hardware.get('audioDevice', 'Default')}")
 +
 
 +
audio_file = 'tick_rhythm_5min.wav'
 +
 
 +
print("Creating sound...")
 +
wave_file = sound.Sound(audio_file)
 +
 
 +
print("Playing sound...")
 +
wave_file.play()
 +
 
 +
while not keyboard.is_pressed('q'):
 +
    pass
 +
 
 +
# Clean up
 +
print("Exiting...")
 +
win.close()
 +
core.quit()
 +
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  

Revision as of 14:26, 28 April 2025

When using video in your experiment, especially when presenting time-critical stimuli, special care should be taken to optimize the video and audio settings on multiple levels (hardware, OS, script), as many things can go wrong along the way.

This page outlines some best practices; however, we advise to always consult a TSG member if you plan to run a video experiment in the labs.

Video encoding

When recording video for stimulus material or as input for your experiment, please: Use a high-quality camera, with settings appropriate for your application (e.g., frame rate, resolution). Use a high-quality recorder or capture device, capable of recording at 1080p (1920×1080) and 60fps or higher. Stabilize the camera and avoid automatic exposure, white balance, or focus during recording to prevent inconsistencies. Record in a controlled environment with consistent lighting and minimal background distractions. You can use the facecam for high quality video recording.

Video Settings

We recommend using the following settings:

File format .mp4 (H.264 codec(libx264)) ik wil hier een link naar de dll?
Frame rate 60 fps (frames per second)
Resolution 1920×1080 (Full HD) or match your experiment's display settings
Bitrate 10-20 Mbps for Full HD video
Constant Frame Rate (CFR) enforce a constant frame rate

Python

Example demonstrating how to record a video with a facecam:

 1#!/usr/bin/env python3.10
 2# -*- coding: utf-8 -*-
 3
 4import datetime
 5import cv2
 6import ctypes
 7import ffmpegcv
 8
 9#set sleep to 1ms accuracy
10winmm = ctypes.WinDLL('winmm')
11winmm.timeBeginPeriod(1)
12
13def configure_webcam(cam_id, width=1920, height=1080, fps=60):
14    cap = cv2.VideoCapture(cam_id, cv2.CAP_DSHOW)
15    if not cap.isOpened():
16        print(f"Error: Couldn't open webcam {cam_id}.")
17        return None
18
19    # Try to set each property
20    cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
21    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
22    cap.set(cv2.CAP_PROP_FPS, fps)
23
24    # Read back the values
25    actual_width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
26    actual_height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
27    actual_fps = cap.get(cv2.CAP_PROP_FPS)
28
29    print(f"Resolution set to: {actual_width}x{actual_height}")
30    print(f"FPS set to: {actual_fps}")
31
32    return cap
33
34def getWebcamData():
35    global frame_width
36    global frame_height
37
38    print("opening webcam...")
39    camera = configure_webcam(1, frame_width, frame_height)
40    time_stamp = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
41    file_name = time_stamp +'_output.avi'
42    video_writer = ffmpegcv.VideoWriter(file_name, 'h264', fps=freq)
43    
44    while True:
45        grabbed = camera.grab()
46        if grabbed:
47            grabbed, frame = camera.retrieve()
48            
49            video_writer.write(frame)  # Write the video to the file system
50            
51            frame = cv2.resize(frame, (int(frame_width/4),int(frame_height/4)))
52            cv2.imshow("Frame", frame)  # show the frame to our screen
53        
54        if cv2.waitKey(1) & 0xFF == ord('q'):
55            break
56
57freq = 60
58frame_width = 1920 
59frame_height = 1080
60
61getWebcamData()
62
63cv2.destroyAllWindows()

Audio encoding

Audio Settings

We recommend using the following settings:

Codec lossless or high-quality codecs
PCM (WAV) uncompressed
Sample Rate 48 kHz

Python

Example demonstrating how to check your audio:

 1#!/usr/bin/env python3.10
 2
 3import psychopy
 4print(psychopy.__version__)
 5import sys
 6print(sys.version)
 7
 8import keyboard
 9from psychopy import prefs
10from psychopy import visual, core, event
11
12from psychopy.sound import backend_ptb
13# 0: No special settings (default, not optimized)
14# 1: Try low-latency but allow some delay
15# 2: Aggressive low-latency
16# 3: Exclusive mode, lowest latency but may not work on all systems
17backend_ptb.SoundPTB.latencyMode = 2
18
19prefs.hardware['audioLib'] = ['PTB']
20prefs.hardware['audioDriver'] = ['ASIO']
21prefs.hardware['audioDevice'] = ['ASIO4ALL v2']
22from psychopy import sound
23
24# --- OS-level audio device sample rate ---
25default_output = sd.query_devices(kind='output')
26print("\nDefault output device info (OS level):")
27print(f"  Name: {default_output['name']}")
28print(f"  Default Sample Rate: {default_output['default_samplerate']} Hz")
29print(f"  Max Output Channels: {default_output['max_output_channels']}")
30
31# Confirm the audio library and output settings
32print(f"Using {sound.audioLib} for sound playback.")
33print(f"Audio library options: {prefs.hardware['audioLib']}")
34print(f"Audio driver: {prefs.hardware.get('audioDriver', 'Default')}")
35print(f"Audio device: {prefs.hardware.get('audioDevice', 'Default')}")
36
37audio_file = 'tick_rhythm_5min.wav'
38
39print("Creating sound...")
40wave_file = sound.Sound(audio_file)
41
42print("Playing sound...")
43wave_file.play()
44
45while not keyboard.is_pressed('q'):
46    pass
47
48# Clean up
49print("Exiting...")
50win.close()
51core.quit()

FFmpeg

Synchronization

Ensure the audio and video streams have consistent timestamps:

FFmpeg Options:

       -fflags +genpts: Generates accurate presentation timestamps (PTS) for the video.

       -async 1: Synchronizes audio and video when they drift.

       -map 0:v:0 and -map 0:a:0: Explicitly map video and audio streams to avoid accidental mismatches.

Python

Example demonstrating how to use ffmpeg:

1#!/usr/bin/env python3.10
2# -*- coding: utf-8 -*-

Recommended FFmpeg Command

Here’s a command that encodes video and audio while maintaining high time accuracy: ffmpeg -i input.mp4 \

      -c:v libx264 -preset slow -crf 18 -vsync cfr -g 30 \
      -c:a pcm_s16le -ar 44100 \
      -fflags +genpts -async 1 \
      output.mp4

• -c:v libx264: Encode video using H.264. • -preset slow: Optimize for quality and compression efficiency. • -crf 18: Adjusts quality (lower = better; range: 0–51). • -vsync cfr: Enforces constant frame rate. • -c:a pcm_s16le: Encodes audio in uncompressed WAV format. • -ar 44100: Sets audio sample rate to 44.1 kHz. • -fflags +genpts: Ensures accurate timestamps. • -async 1: Synchronizes audio and video streams.

Tips

• Ensure Low Latency: If you're processing video/audio in real time, use low-latency settings (e.g., -tune zerolatency for H.264). • Avoid Resampling: If possible, use the original frame rate and sample rate to avoid timing mismatches. • Testing: Always test playback on different devices or players to confirm synchronization.

Alternatively, you can use Shotcut, a simple open-source editor, available here: https://shotcut.org/


The Lab Computer displays are typically set to 1920×1080 at 120Hz. We found that this is sufficient for most applications. There are possibilities to go higher.

Editing

We recommend using DaVinci Resolve for editing and converting video files. DaVinci Resolve is a free, professional-grade editing program, available here: https://www.blackmagicdesign.com/products/davinciresolve


Windows Settings

Windows 10 has a habit of automatically enabling video enhancements or unnecessary processing features, which can interfere with smooth playback. Therefore, please make sure these are disabled:

Open Settings → System → Display → Graphics Settings. If available, disable "Hardware-accelerated GPU scheduling" for critical timing experiments. For specific applications (e.g., PsychoPy), under "Graphics Performance Preference," set them to "High Performance" to ensure they use the dedicated GPU.

Playback

PsychoPy

Example demonstrating how to play a video:

 1#!/usr/bin/env python3.10
 2# -*- coding: utf-8 -*-
 3
 4import time
 5import keyboard
 6from psychopy import visual 
 7from psychopy import core
 8
 9## Setup Section
10win = visual.Window([720,720], fullscr=False, monitor="testMonitor", units='cm')
11
12# append this stimulus to the list of prepared stimuli
13vlc_movies = []
14my_movies = ['YourMovie.mp4']#path to your movies from this directory
15
16for movie in my_movies:
17    mov = visual.VlcMovieStim(win, movie,
18    size=600,  # set as `None` to use the native video size
19    pos=[0, 0],  # pos specifies the /center/ of the movie stim location
20    flipVert=False,  # flip the video picture vertically
21    flipHoriz=False,  # flip the video picture horizontally
22    loop=False,  # replay the video when it reaches the end
23    autoStart=True)  # start the video automatically when first drawn
24    vlc_movies.append(mov)
25
26print("playing video....")
27while not(keyboard.is_pressed('q')) and vlc_movies[0].status != visual.FINISHED:
28    vlc_movies[0].draw()
29    win.flip()
30    buffer_in = vlc_movies[0].frameIndex
31    print(vlc_movies[0].status)
32
33print("Stop")
34
35## Closing Section
36core.quit()