
Recherche avancée
Médias (1)
-
La conservation du net art au musée. Les stratégies à l’œuvre
26 mai 2011
Mis à jour : Juillet 2013
Langue : français
Type : Texte
Autres articles (35)
-
La file d’attente de SPIPmotion
28 novembre 2010, parUne file d’attente stockée dans la base de donnée
Lors de son installation, SPIPmotion crée une nouvelle table dans la base de donnée intitulée spip_spipmotion_attentes.
Cette nouvelle table est constituée des champs suivants : id_spipmotion_attente, l’identifiant numérique unique de la tâche à traiter ; id_document, l’identifiant numérique du document original à encoder ; id_objet l’identifiant unique de l’objet auquel le document encodé devra être attaché automatiquement ; objet, le type d’objet auquel (...) -
Websites made with MediaSPIP
2 mai 2011, parThis page lists some websites based on MediaSPIP.
-
Creating farms of unique websites
13 avril 2011, parMediaSPIP platforms can be installed as a farm, with a single "core" hosted on a dedicated server and used by multiple websites.
This allows (among other things) : implementation costs to be shared between several different projects / individuals rapid deployment of multiple unique sites creation of groups of like-minded sites, making it possible to browse media in a more controlled and selective environment than the major "open" (...)
Sur d’autres sites (7247)
-
Revision 29928 : On réutilise l’ancien code pour débuter notre branche
17 juillet 2009, par kent1@… — LogOn réutilise l’ancien code pour débuter notre branche
-
Revision 33976 : bugs html
27 décembre 2009, par cedric@… — Logbugs html
-
Real time playback of two blended videos with alpha channel and synched audio in pygame ?
22 décembre 2024, par Francesco CalderoneI need to play two videos with synched sound in real-time with Pygame.
Pygame does not currently support video streams, so I am using a ffmpeg subprocess.
The first video is a prores422_hq. This is a background video with no alpha channel.
The second video is a prores4444 overlay video with an alpha channel, and it needs to be played in real-tim on top of the first video (with transparency).
All of this needs synched sound from the first base video only.


I have tried many libraries, including pymovie pyav and opencv. The best result so far is to use a subprocess with ffmpeg.


ffmpeg -i testing/stefano_prores422_hq.mov -stream_loop -1 -i testing/key_prores4444.mov -filter_complex "[1:v]format=rgba,colorchannelmixer=aa=1.0[overlay];[0:v][overlay]overlay" -f nut pipe:1 | ffplay -


When running this in the terminal and playing with ffplay, everything is perfect, the overlay looks good, no dropped frames, and the sound is in synch.


However, trying to feed that to pygame via a subprocess creates either video delays and drop frames or audio not in synch.


EXAMPLE ONE :


# SOUND IS NOT SYNCHED - sound is played via ffplay
import pygame
import subprocess
import numpy as np
import sys

def main():
 pygame.init()
 screen_width, screen_height = 1920, 1080
 screen = pygame.display.set_mode((screen_width, screen_height))
 pygame.display.set_caption("PyGame + FFmpeg Overlay with Audio")
 clock = pygame.time.Clock()

 # LAUNCH AUDIO-ONLY SUBPROCESS
 audio_cmd = [
 "ffplay",
 "-nodisp", # no video window
 "-autoexit", # exit when video ends
 "-loglevel", "quiet",
 "testing/stefano_prores422_hq.mov"
 ]
 audio_process = subprocess.Popen(audio_cmd)

 # LAUNCH VIDEO-OVERLAY SUBPROCESS
 ffmpeg_command = [
 "ffmpeg",
 "-i", "testing/stefano_prores422_hq.mov",
 "-stream_loop", "-1", # loop alpha video
 "-i", "testing/key_prores4444.mov",
 "-filter_complex",
 "[1:v]format=rgba,colorchannelmixer=aa=1.0[overlay];" # ensure alpha channel
 "[0:v][overlay]overlay", # overlay second input onto first
 "-f", "rawvideo", # output raw video
 "-pix_fmt", "rgba", # RGBA format
 "pipe:1" # write to STDOUT
 ]
 video_process = subprocess.Popen(
 ffmpeg_command,
 stdout=subprocess.PIPE,
 stderr=subprocess.DEVNULL
 )
 frame_size = screen_width * screen_height * 4 # RGBA = 4 bytes/pixel
 running = True
 while running:
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
 running = False
 break

 raw_frame = video_process.stdout.read(frame_size)

 if len(raw_frame) < frame_size:
 running = False
 break
 # Convert raw bytes -> NumPy array -> PyGame surface
 frame_array = np.frombuffer(raw_frame, dtype=np.uint8)
 frame_array = frame_array.reshape((screen_height, screen_width, 4))
 frame_surface = pygame.image.frombuffer(frame_array.tobytes(), 
 (screen_width, screen_height), 
 "RGBA")
 screen.blit(frame_surface, (0, 0))
 pygame.display.flip()
 clock.tick(25)
 video_process.terminate()
 video_process.wait()
 audio_process.terminate()
 audio_process.wait()
 pygame.quit()
 sys.exit()

if __name__ == "__main__":
 main()




EXAMPLE TWO


# NO VIDEO OVERLAY - SOUND SYNCHED
import ffmpeg
import pygame
import sys
import numpy as np
import tempfile
import os

def extract_audio(input_file, output_file):
 """Extract audio from video file to temporary WAV file"""
 (
 ffmpeg
 .input(input_file)
 .output(output_file, acodec='pcm_s16le', ac=2, ar='44100')
 .overwrite_output()
 .run(capture_stdout=True, capture_stderr=True)
 )

def get_video_fps(input_file):
 probe = ffmpeg.probe(input_file)
 video_info = next(s for s in probe['streams'] if s['codec_type'] == 'video')
 fps_str = video_info.get('r_frame_rate', '25/1')
 num, den = map(int, fps_str.split('/'))
 return num / den

input_file = "testing/stefano_prores422_hq.mov"

# Create temporary WAV file
temp_audio = tempfile.NamedTemporaryFile(suffix='.wav', delete=False)
temp_audio.close()
extract_audio(input_file, temp_audio.name)

probe = ffmpeg.probe(input_file)
video_info = next(s for s in probe['streams'] if s['codec_type'] == 'video')
width = int(video_info['width'])
height = int(video_info['height'])
fps = get_video_fps(input_file)

process = (
 ffmpeg
 .input(input_file)
 .output('pipe:', format='rawvideo', pix_fmt='rgb24')
 .run_async(pipe_stdout=True)
)

pygame.init()
pygame.mixer.init(frequency=44100, size=-16, channels=2, buffer=4096)
clock = pygame.time.Clock()
screen = pygame.display.set_mode((width, height))

pygame.mixer.music.load(temp_audio.name)
pygame.mixer.music.play()

frame_count = 0
start_time = pygame.time.get_ticks()

while True:
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
 pygame.mixer.music.stop()
 os.unlink(temp_audio.name)
 sys.exit()

 in_bytes = process.stdout.read(width * height * 3)
 if not in_bytes:
 break

 # Calculate timing for synchronization
 expected_frame_time = frame_count * (1000 / fps)
 actual_time = pygame.time.get_ticks() - start_time
 
 if actual_time < expected_frame_time:
 pygame.time.wait(int(expected_frame_time - actual_time))
 
 in_frame = (
 np.frombuffer(in_bytes, dtype="uint8")
 .reshape([height, width, 3])
 )
 out_frame = pygame.surfarray.make_surface(np.transpose(in_frame, (1, 0, 2)))
 screen.blit(out_frame, (0, 0))
 pygame.display.flip()
 
 frame_count += 1

pygame.mixer.music.stop()
process.wait()
pygame.quit()
os.unlink(temp_audio.name)



I also tried using pygame mixer and a separate mp3 audio file, but that didn't work either. Any help on how to synch the sound while keeping the playback of both videos to 25 FPS would be greatly appreciated !!!