support for rgba via stream

This commit is contained in:
henryruhs
2026-07-22 22:15:29 +02:00
parent c7a59fed8d
commit 5d2536cabe
7 changed files with 22 additions and 6 deletions
+1
View File
@@ -45,6 +45,7 @@ def apply_args(args : Args, apply_state_item : ApplyStateItem) -> None:
apply_state_item('trim_frame_start', args.get('trim_frame_start'))
apply_state_item('trim_frame_end', args.get('trim_frame_end'))
apply_state_item('temp_frame_format', args.get('temp_frame_format'))
apply_state_item('temp_pixel_format', args.get('temp_pixel_format'))
apply_state_item('workflow_mode', args.get('workflow_mode'))
apply_state_item('target_frame_amount', args.get('target_frame_amount'))
apply_state_item('output_image_quality', args.get('output_image_quality'))
+3 -1
View File
@@ -2,7 +2,7 @@ import logging
from typing import List, Sequence, get_args
from facefusion.common_helper import create_float_range, create_int_range
from facefusion.types import Angle, AudioEncoder, AudioFormat, AudioTypeSet, BenchmarkMode, BenchmarkResolution, BenchmarkSet, DownloadProvider, DownloadProviderSet, DownloadScope, EncoderSet, ExecutionProvider, ExecutionProviderSet, FaceDetectorModel, FaceDetectorSet, FaceLandmarkerModel, FaceMaskArea, FaceMaskAreaSet, FaceMaskRegion, FaceMaskRegionSet, FaceMaskType, FaceOccluderModel, FaceParserModel, FaceSelectorGender, FaceSelectorMode, FaceSelectorOrder, FaceSelectorRace, Gender, ImageFormat, ImageTypeSet, JobStatus, LogLevel, LogLevelSet, Race, Score, TempFrameFormat, UiWorkflow, VideoEncoder, VideoFormat, VideoMemoryStrategy, VideoPreset, VideoTypeSet, VoiceExtractorModel, WorkflowMode
from facefusion.types import Angle, AudioEncoder, AudioFormat, AudioTypeSet, BenchmarkMode, BenchmarkResolution, BenchmarkSet, DownloadProvider, DownloadProviderSet, DownloadScope, EncoderSet, ExecutionProvider, ExecutionProviderSet, FaceDetectorModel, FaceDetectorSet, FaceLandmarkerModel, FaceMaskArea, FaceMaskAreaSet, FaceMaskRegion, FaceMaskRegionSet, FaceMaskType, FaceOccluderModel, FaceParserModel, FaceSelectorGender, FaceSelectorMode, FaceSelectorOrder, FaceSelectorRace, Gender, ImageFormat, ImageTypeSet, JobStatus, LogLevel, LogLevelSet, Race, Score, TempFrameFormat, TempPixelFormat, UiWorkflow, VideoEncoder, VideoFormat, VideoMemoryStrategy, VideoPreset, VideoTypeSet, VoiceExtractorModel, WorkflowMode
face_detector_set : FaceDetectorSet =\
{
@@ -80,6 +80,8 @@ audio_formats : List[AudioFormat] = list(get_args(AudioFormat))
image_formats : List[ImageFormat] = list(get_args(ImageFormat))
video_formats : List[VideoFormat] = list(get_args(VideoFormat))
temp_frame_formats : List[TempFrameFormat] = list(get_args(TempFrameFormat))
#todo: needs review - [config] [critical: low] temp pixel format choices for the stream pipe
temp_pixel_formats : List[TempPixelFormat] = list(get_args(TempPixelFormat))
output_audio_encoders : List[AudioEncoder] = list(get_args(AudioEncoder))
#todo: needs review - [config] [critical: low] workflow mode choices for disk and stream
+1
View File
@@ -136,6 +136,7 @@ LOCALES : Locales =\
'trim_frame_start': 'specify the starting frame of the target video',
'trim_frame_end': 'specify the ending frame of the target video',
'temp_frame_format': 'specify the temporary resources format',
'temp_pixel_format': 'specify the pixel format for the stream pipe (rgba keeps the alpha channel)',
#todo: needs review - [ui] [critical: low] workflow_mode help text replaces keep_temp
'workflow_mode': 'specify how frames flow through processing (disk extracts and merges temp frames, stream pipes frames through ffmpeg)',
'target_frame_amount': 'specify the amount of target frames forwarded to the processor',
+3 -1
View File
@@ -169,9 +169,11 @@ def create_frame_extraction_program() -> ArgumentParser:
group_frame_extraction.add_argument('--trim-frame-start', help = translator.get('help.trim_frame_start'), type = int, default = facefusion.config.get_int_value('frame_extraction', 'trim_frame_start'))
group_frame_extraction.add_argument('--trim-frame-end', help = translator.get('help.trim_frame_end'), type = int, default = facefusion.config.get_int_value('frame_extraction', 'trim_frame_end'))
group_frame_extraction.add_argument('--temp-frame-format', help = translator.get('help.temp_frame_format'), default = config.get_str_value('frame_extraction', 'temp_frame_format', 'png'), choices = facefusion.choices.temp_frame_formats)
#todo: needs review - [streaming] [critical: low] new temp pixel format option, rgba enables alpha through the stream pipe
group_frame_extraction.add_argument('--temp-pixel-format', help = translator.get('help.temp_pixel_format'), default = config.get_str_value('frame_extraction', 'temp_pixel_format', 'rgb'), choices = facefusion.choices.temp_pixel_formats)
#todo: needs review - [workflow] [critical: medium] keep_temp cli option replaced by workflow_mode, breaks existing configs and jobs
group_frame_extraction.add_argument('--workflow-mode', help = translator.get('help.workflow_mode'), default = config.get_str_value('frame_extraction', 'workflow_mode', 'disk'), choices = facefusion.choices.workflow_modes)
job_store.register_step_keys([ 'trim_frame_start', 'trim_frame_end', 'temp_frame_format', 'workflow_mode' ])
job_store.register_step_keys([ 'trim_frame_start', 'trim_frame_end', 'temp_frame_format', 'temp_pixel_format', 'workflow_mode' ])
return program
+4
View File
@@ -172,6 +172,8 @@ AudioFormat = Literal['flac', 'm4a', 'mp3', 'ogg', 'opus', 'wav']
ImageFormat = Literal['bmp', 'jpeg', 'png', 'tiff', 'webp']
VideoFormat = Literal['avi', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mxf', 'webm', 'wmv']
TempFrameFormat = Literal['bmp', 'jpeg', 'png', 'tiff']
#todo: needs review - [streaming] [critical: low] new temp pixel format controls the stream pipe channels
TempPixelFormat = Literal['rgb', 'rgba']
#todo: needs review - [workflow] [critical: medium] new workflow mode replaces keep_temp in state and jobs
WorkflowMode = Literal['disk', 'stream']
AudioTypeSet : TypeAlias = Dict[AudioFormat, str]
@@ -344,6 +346,7 @@ StateKey = Literal\
'trim_frame_start',
'trim_frame_end',
'temp_frame_format',
'temp_pixel_format',
'workflow_mode',
'target_frame_amount',
'output_image_quality',
@@ -415,6 +418,7 @@ State = TypedDict('State',
'trim_frame_start' : int,
'trim_frame_end' : int,
'temp_frame_format' : TempFrameFormat,
'temp_pixel_format' : TempPixelFormat,
'workflow_mode' : WorkflowMode,
'target_frame_amount' : int,
'output_image_quality' : int,
+6 -2
View File
@@ -167,10 +167,14 @@ def create_video_writer_process(target_path : str, temp_video_fps : Fps, temp_vi
temp_video_format = cast(VideoFormat, get_file_format(temp_video_path))
output_video_encoder = ffmpeg_builder.fix_video_encoder(temp_video_format, output_video_encoder)
encoder_thread_count = 16
writer_pixel_format = 'bgr24'
if state_manager.get_item('temp_pixel_format') == 'rgba':
writer_pixel_format = 'bgra'
commands = ffmpeg_builder.chain(
ffmpeg_builder.set_output_format('rawvideo'),
#todo: consider to introduce a argument to pass --output-pixel-format
ffmpeg_builder.enforce_pixel_format('bgra'),
ffmpeg_builder.enforce_pixel_format(writer_pixel_format),
ffmpeg_builder.set_media_resolution(pack_video_resolution(temp_video_resolution)),
ffmpeg_builder.set_input_fps(temp_video_fps),
ffmpeg_builder.set_input('pipe:0'),
+4 -2
View File
@@ -279,7 +279,7 @@ def process_disk_frames() -> ErrorCode:
return 0
#todo: needs review - [streaming] [critical: high] middle frame resized to temp resolution before processing, returns contiguous bgra matching the writer pipe
#todo: needs review - [streaming] [critical: high] middle frame resized to temp resolution before processing, channels follow temp_pixel_format to match the writer pipe
def process_stream_frame(frame_number : int, temp_video_resolution : Resolution) -> Tuple[int, VisionFrame]:
target_vision_frames = select_video_frames(state_manager.get_item('target_path'), frame_number, state_manager.get_item('target_frame_amount'))
target_vision_frame = get_middle(target_vision_frames)
@@ -289,8 +289,10 @@ def process_stream_frame(frame_number : int, temp_video_resolution : Resolution)
temp_vision_frame = cv2.resize(target_vision_frame, temp_video_resolution)
temp_vision_frame = process_target_frame(frame_number, target_vision_frames, temp_vision_frame)
if temp_vision_frame.shape[2] == 3:
if state_manager.get_item('temp_pixel_format') == 'rgba':
temp_vision_frame = cv2.cvtColor(temp_vision_frame, cv2.COLOR_BGR2BGRA)
if state_manager.get_item('temp_pixel_format') == 'rgb':
temp_vision_frame = temp_vision_frame[:, :, :3]
return frame_number, numpy.ascontiguousarray(temp_vision_frame)