Files
facefusion/facefusion/streamer.py
T
henryruhsandClaude Opus 4.8 be89f03b27 Merge branch 'master' into v4
Resolve 57 conflicts keeping v4's architecture (UI removal, api app
context, path isolation, streaming/codecs/rtc, workflow-mode superset,
args_helper) and taking master's post-fork features so none are dropped:
inference override/adjust provider hooks (+ face_swapper 3.8.1 coreml
fix), is_vision_frame validity guards, resolve_temp_frame_set frame
numbering with the source audio/voice trim offset, the ffmpeg color
pipeline (restrict_color_transfer / convert_color_space / temp_pixel_format),
ffprobe select_stream v:0 + format duration, pre_check ffprobe with
dependency_not_installed, onnxruntime arena-leak guard + version lru_cache,
installer cuda@12/@13 provider split, workflow_strategy disk/memory
(memory default), and the dependency version bumps. content_analyser hash
guard rehashed to 3c6ce25e.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V7MdZEmd1GE8uSDTMyq34r
2026-08-05 22:12:54 +02:00

100 lines
3.8 KiB
Python

import os
import subprocess
from collections import deque
from concurrent.futures import ThreadPoolExecutor
from typing import Deque, Iterator, List
import cv2
from tqdm import tqdm
from facefusion import ffmpeg_builder, logger, state_manager, translator
from facefusion.audio import create_empty_audio_frame
from facefusion.content_analyser import analyse_stream
from facefusion.ffmpeg import open_ffmpeg
from facefusion.filesystem import is_directory
from facefusion.processors.core import get_processors_modules
from facefusion.types import Buffer, Fps, StreamMode, VisionFrame
from facefusion.vision import extract_vision_mask, is_vision_frame, read_static_images
def multi_process_capture(camera_capture : cv2.VideoCapture, camera_fps : Fps) -> Iterator[VisionFrame]:
capture_deque : Deque[VisionFrame] = deque()
source_vision_frames = read_static_images(state_manager.get_item('source_paths'))
with tqdm(desc = translator.get('streaming'), unit = 'frame', disable = state_manager.get_item('log_level') in [ 'warn', 'error' ]) as progress:
with ThreadPoolExecutor(max_workers = state_manager.get_item('execution_thread_count')) as executor:
futures = []
while camera_capture and camera_capture.isOpened():
_, capture_vision_frame = camera_capture.read()
if analyse_stream(capture_vision_frame, camera_fps):
camera_capture.release()
if is_vision_frame(capture_vision_frame):
future = executor.submit(process_stream_frame, source_vision_frames, capture_vision_frame)
futures.append(future)
for future_done in [ future for future in futures if future.done() ]:
capture_vision_frame = future_done.result()
capture_deque.append(capture_vision_frame)
futures.remove(future_done)
while capture_deque:
progress.update()
yield capture_deque.popleft()
def process_stream_frame(source_vision_frames : List[VisionFrame], target_vision_frame : VisionFrame) -> VisionFrame:
source_audio_frame = create_empty_audio_frame()
source_voice_frame = create_empty_audio_frame()
temp_vision_frame = target_vision_frame.copy()
temp_vision_mask = extract_vision_mask(temp_vision_frame)
for processor_module in get_processors_modules(state_manager.get_item('processors')):
logger.disable()
if processor_module.pre_process('stream'):
logger.enable()
temp_vision_frame, temp_vision_mask = processor_module.process_frame(
{
'source_vision_frames': source_vision_frames,
'source_audio_frame': source_audio_frame,
'source_voice_frame': source_voice_frame,
'target_vision_frames': [ target_vision_frame ],
'temp_vision_frame': temp_vision_frame,
'temp_vision_mask': temp_vision_mask
})
logger.enable()
return temp_vision_frame
def open_stream(stream_mode : StreamMode, stream_resolution : str, stream_fps : Fps) -> subprocess.Popen[Buffer]:
commands = ffmpeg_builder.chain(
ffmpeg_builder.capture_video(),
ffmpeg_builder.set_media_resolution(stream_resolution),
ffmpeg_builder.set_input_fps(stream_fps)
)
if stream_mode == 'udp':
commands.extend(ffmpeg_builder.set_input('-'))
commands.extend(ffmpeg_builder.set_stream_mode('udp'))
commands.extend(ffmpeg_builder.set_stream_quality(2000))
commands.extend(ffmpeg_builder.set_output('udp://localhost:27000?pkt_size=1316'))
if stream_mode == 'v4l2':
device_directory_path = '/sys/devices/virtual/video4linux'
commands.extend(ffmpeg_builder.set_input('-'))
commands.extend(ffmpeg_builder.set_stream_mode('v4l2'))
if is_directory(device_directory_path):
device_names = os.listdir(device_directory_path)
for device_name in device_names:
device_path = '/dev/' + device_name
commands.extend(ffmpeg_builder.set_output(device_path))
else:
logger.error(translator.get('stream_not_loaded').format(stream_mode = stream_mode), __name__)
return open_ffmpeg(commands)