mirror of
https://github.com/facefusion/facefusion.git
synced 2026-07-27 12:30:55 +02:00
fix order of workflow
This commit is contained in:
@@ -18,6 +18,7 @@ VIDEO_POOL_SET : VideoPoolSet =\
|
||||
}
|
||||
|
||||
|
||||
#todo: needs review - [process] [critical: medium] new ffmpeg raw pipe reader with seek based start, stderr devnull hides decode errors
|
||||
def create_video_reader_process(video_path : str, frame_position : int, video_fps : Fps) -> subprocess.Popen[bytes]:
|
||||
color_transfer = extract_video_metadata(video_path).get('color_transfer')
|
||||
commands = ffmpeg_builder.chain(
|
||||
@@ -33,6 +34,7 @@ def create_video_reader_process(video_path : str, frame_position : int, video_fp
|
||||
return subprocess.Popen(commands, stdout = subprocess.PIPE, stderr = subprocess.DEVNULL)
|
||||
|
||||
|
||||
#todo: needs review - [perf] [critical: medium] select filter decodes the entire range to sample frames, runs at lowered process priority
|
||||
def create_video_sampler_process(video_path : str, frame_start : int, frame_end : int, frame_stride : int) -> subprocess.Popen[bytes]:
|
||||
color_transfer = extract_video_metadata(video_path).get('color_transfer')
|
||||
sample_total = len([ frame_number for frame_number in range(frame_start, frame_end) if frame_number % frame_stride == 0 ])
|
||||
@@ -57,10 +59,12 @@ def create_video_sampler_process(video_path : str, frame_start : int, frame_end
|
||||
return subprocess.Popen(commands, stdout = subprocess.PIPE, stderr = subprocess.DEVNULL, preexec_fn = demote_process_priority)
|
||||
|
||||
|
||||
#todo: needs review - [process] [critical: low] posix only nice fallback for the sampler priority
|
||||
def demote_process_priority() -> None:
|
||||
os.nice(10)
|
||||
|
||||
|
||||
#todo: needs review - [memory] [critical: medium] pooled reader per path is created without lock and only reaped via clear_video_pool
|
||||
def get_video_reader(video_path : str) -> VideoReader:
|
||||
if video_path not in VIDEO_POOL_SET.get('reader'):
|
||||
video_metadata = extract_video_metadata(video_path)
|
||||
@@ -81,6 +85,7 @@ def get_video_reader(video_path : str) -> VideoReader:
|
||||
return VIDEO_POOL_SET.get('reader').get(video_path)
|
||||
|
||||
|
||||
#todo: needs review - [perf] [critical: high] forward skip up to 128 frames by draining the pipe, everything else restarts the ffmpeg process
|
||||
def conditional_set_video_reader_position(video_reader : VideoReader, frame_position : int) -> None:
|
||||
skip_margin = 128
|
||||
skipping = video_reader.get('position') < frame_position and frame_position - video_reader.get('position') <= skip_margin
|
||||
@@ -93,6 +98,7 @@ def conditional_set_video_reader_position(video_reader : VideoReader, frame_posi
|
||||
restart_video_reader(video_reader, frame_position)
|
||||
|
||||
|
||||
#todo: needs review - [process] [critical: high] kill and respawn per out of order seek, frequent restarts stack up on random access
|
||||
def restart_video_reader(video_reader : VideoReader, frame_position : int) -> None:
|
||||
video_reader.get('process').kill()
|
||||
video_reader.get('process').wait()
|
||||
@@ -101,6 +107,7 @@ def restart_video_reader(video_reader : VideoReader, frame_position : int) -> No
|
||||
video_reader['frame_buffer'].clear()
|
||||
|
||||
|
||||
#todo: needs review - [correctness] [critical: high] partial pipe read returns none and desyncs position from the actual stream
|
||||
def read_video_reader_frame(video_reader : VideoReader) -> Tuple[bool, Optional[VisionFrame]]:
|
||||
frame_size = video_reader.get('width') * video_reader.get('height') * 3
|
||||
frame_buffer = video_reader.get('process').stdout.read(frame_size)
|
||||
@@ -111,6 +118,7 @@ def read_video_reader_frame(video_reader : VideoReader) -> Tuple[bool, Optional[
|
||||
return False, None
|
||||
|
||||
|
||||
#todo: needs review - [memory] [critical: medium] eviction only trims below frame_start, look ahead growth is bounded by the window callers
|
||||
def evict_video_reader_buffer(video_reader : VideoReader, frame_start : int, buffer_margin : int) -> None:
|
||||
frame_buffer = video_reader.get('frame_buffer')
|
||||
|
||||
@@ -118,6 +126,7 @@ def evict_video_reader_buffer(video_reader : VideoReader, frame_start : int, buf
|
||||
del frame_buffer[frame_number]
|
||||
|
||||
|
||||
#todo: needs review - [memory] [critical: high] frame_buffer keeps decoded frames in ram, restart heuristic depends on buffer_margin 16
|
||||
def read_video_reader_window(video_reader : VideoReader, frame_start : int, frame_end : int) -> VideoReaderBuffer:
|
||||
frame_buffer = video_reader.get('frame_buffer')
|
||||
buffer_margin = 16
|
||||
@@ -143,11 +152,13 @@ def read_video_reader_window(video_reader : VideoReader, frame_start : int, fram
|
||||
return frame_buffer
|
||||
|
||||
|
||||
#todo: needs review - [correctness] [critical: low] rounds odd dimensions to even for yuv420p compatibility
|
||||
def pack_video_resolution(resolution : Resolution) -> str:
|
||||
width, height = resolution
|
||||
return str(round(width / 2) * 2) + 'x' + str(round(height / 2) * 2)
|
||||
|
||||
|
||||
#todo: needs review - [color] [critical: high] output is always converted and tagged bt709, encoder_thread_count hardcoded to 16
|
||||
def create_video_writer_process(target_path : str, temp_video_fps : Fps, temp_video_resolution : Resolution, output_video_resolution : Resolution, output_video_fps : Fps) -> subprocess.Popen[bytes]:
|
||||
output_video_encoder = state_manager.get_item('output_video_encoder')
|
||||
output_video_quality = state_manager.get_item('output_video_quality')
|
||||
@@ -179,6 +190,7 @@ def create_video_writer_process(target_path : str, temp_video_fps : Fps, temp_vi
|
||||
return subprocess.Popen(commands, stdin = subprocess.PIPE, stdout = subprocess.DEVNULL)
|
||||
|
||||
|
||||
#todo: needs review - [process] [critical: low] pooled writer keyed by target_path
|
||||
def get_video_writer(target_path : str, temp_video_fps : Fps, temp_video_resolution : Resolution, output_video_resolution : Resolution, output_video_fps : Fps) -> subprocess.Popen[bytes]:
|
||||
if target_path not in VIDEO_POOL_SET.get('writer'):
|
||||
VIDEO_POOL_SET['writer'][target_path] = create_video_writer_process(target_path, temp_video_fps, temp_video_resolution, output_video_resolution, output_video_fps)
|
||||
|
||||
@@ -24,10 +24,10 @@ def process(start_time : float) -> ErrorCode:
|
||||
tasks =\
|
||||
[
|
||||
setup,
|
||||
enforce_analysis,
|
||||
extract_frames,
|
||||
process_disk_frames,
|
||||
merge_frames,
|
||||
enforce_analysis,
|
||||
restore_audio,
|
||||
partial(finalize_video, start_time)
|
||||
]
|
||||
@@ -36,8 +36,8 @@ def process(start_time : float) -> ErrorCode:
|
||||
tasks =\
|
||||
[
|
||||
setup,
|
||||
process_stream_frames,
|
||||
enforce_analysis,
|
||||
process_stream_frames,
|
||||
restore_audio,
|
||||
partial(finalize_video, start_time)
|
||||
]
|
||||
@@ -54,15 +54,6 @@ def process(start_time : float) -> ErrorCode:
|
||||
return 0
|
||||
|
||||
|
||||
def enforce_analysis() -> ErrorCode:
|
||||
trim_frame_start, trim_frame_end = restrict_trim_frame(state_manager.get_item('target_path'), state_manager.get_item('trim_frame_start'), state_manager.get_item('trim_frame_end'))
|
||||
|
||||
if analyse_video(state_manager.get_item('target_path'), trim_frame_start, trim_frame_end):
|
||||
clear_temp_directory(state_manager.get_item('target_path'))
|
||||
return 3
|
||||
return 0
|
||||
|
||||
|
||||
def setup() -> ErrorCode:
|
||||
if clear_temp_directory(state_manager.get_item('target_path')):
|
||||
logger.debug(translator.get('clearing_temp'), __name__)
|
||||
@@ -73,6 +64,15 @@ def setup() -> ErrorCode:
|
||||
return 0
|
||||
|
||||
|
||||
def enforce_analysis() -> ErrorCode:
|
||||
trim_frame_start, trim_frame_end = restrict_trim_frame(state_manager.get_item('target_path'), state_manager.get_item('trim_frame_start'), state_manager.get_item('trim_frame_end'))
|
||||
|
||||
if analyse_video(state_manager.get_item('target_path'), trim_frame_start, trim_frame_end):
|
||||
clear_temp_directory(state_manager.get_item('target_path'))
|
||||
return 3
|
||||
return 0
|
||||
|
||||
|
||||
def extract_frames() -> ErrorCode:
|
||||
trim_frame_start, trim_frame_end = restrict_trim_frame(state_manager.get_item('target_path'), state_manager.get_item('trim_frame_start'), state_manager.get_item('trim_frame_end'))
|
||||
output_video_resolution = scale_resolution(detect_video_resolution(state_manager.get_item('target_path')), state_manager.get_item('output_video_scale'))
|
||||
|
||||
Reference in New Issue
Block a user