mirror of
https://github.com/facefusion/facefusion.git
synced 2026-07-27 12:30:55 +02:00
Cleanup Part1 (#1201)
* remove some todos, improve video manager, simplify ffmpeg commands and more * do more * remove thread count for filters
This commit is contained in:
@@ -32,6 +32,7 @@ def conditional_download(download_directory_path : str, urls : List[str]) -> Non
|
||||
curl_builder.set_timeout(5),
|
||||
curl_builder.set_retry(5)
|
||||
)
|
||||
|
||||
open_curl(commands)
|
||||
current_size = initial_size
|
||||
progress.set_postfix(download_providers = state_manager.get_item('download_providers'), file_name = download_file_name)
|
||||
@@ -48,6 +49,7 @@ def get_static_download_size(url : str) -> int:
|
||||
curl_builder.ping(url),
|
||||
curl_builder.set_timeout(5)
|
||||
)
|
||||
|
||||
process = open_curl(commands)
|
||||
lines = reversed(process.stdout.readlines())
|
||||
|
||||
@@ -66,6 +68,7 @@ def ping_static_url(url : str) -> bool:
|
||||
curl_builder.ping(url),
|
||||
curl_builder.set_timeout(5)
|
||||
)
|
||||
|
||||
process = open_curl(commands)
|
||||
process.communicate()
|
||||
return process.returncode == 0
|
||||
|
||||
+18
-14
@@ -10,7 +10,7 @@ import facefusion.choices
|
||||
from facefusion import ffmpeg_builder, ffprobe, logger, process_manager, state_manager, translator, vision
|
||||
from facefusion.filesystem import get_file_format, remove_file
|
||||
from facefusion.temp_helper import get_temp_file_path, get_temp_frame_pattern
|
||||
from facefusion.types import AudioBuffer, AudioEncoder, Command, EncoderSet, Fps, Resolution, UpdateProgress, VideoEncoder, VideoFormat, VideoMetadata
|
||||
from facefusion.types import AudioBuffer, AudioEncoder, Command, EncoderSet, Fps, Resolution, UpdateProgress, VideoEncoder, VideoFormat, VideoReaderMetadata
|
||||
|
||||
|
||||
def run_ffmpeg_with_progress(commands : List[Command], update_progress : UpdateProgress) -> subprocess.Popen[bytes]:
|
||||
@@ -69,24 +69,20 @@ def open_ffmpeg(commands : List[Command]) -> subprocess.Popen[bytes]:
|
||||
return subprocess.Popen(commands, stdin = subprocess.PIPE, stdout = subprocess.PIPE)
|
||||
|
||||
|
||||
#todo: needs review - [decoding] [critical: medium] raw pipe reader with seek based start, spawn moved from the POC video_manager into ffmpeg
|
||||
#todo: question if this does too much
|
||||
def create_video_reader(video_path : str, frame_position : int, video_metadata : VideoMetadata) -> subprocess.Popen[bytes]:
|
||||
def create_video_reader(video_path : str, frame_position : int, video_metadata : VideoReaderMetadata) -> subprocess.Popen[bytes]:
|
||||
commands = ffmpeg_builder.chain(
|
||||
ffmpeg_builder.set_input_seek(frame_position / video_metadata.get('fps')),
|
||||
ffmpeg_builder.seek_to(frame_position / video_metadata.get('fps')),
|
||||
ffmpeg_builder.set_input(video_path),
|
||||
ffmpeg_builder.set_filter_thread_count(4),
|
||||
ffmpeg_builder.restrict_color_transfer(video_metadata.get('color_transfer')),
|
||||
ffmpeg_builder.prevent_frame_drop(),
|
||||
ffmpeg_builder.enforce_pixel_format('bgr24'),
|
||||
ffmpeg_builder.set_output_format('rawvideo'),
|
||||
ffmpeg_builder.cast_stream()
|
||||
)
|
||||
|
||||
return open_ffmpeg(commands)
|
||||
|
||||
|
||||
#todo: needs review - [encoding] [critical: high] pipe writer always converts and tags bt709, temp_pixel_format drives the pipe channels, encoder_thread_count hardcoded to 16
|
||||
#todo: question if this does too much
|
||||
def create_video_writer(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')
|
||||
@@ -94,7 +90,6 @@ def create_video_writer(target_path : str, temp_video_fps : Fps, temp_video_reso
|
||||
temp_video_path = get_temp_file_path(target_path)
|
||||
temp_video_format = cast(VideoFormat, get_file_format(temp_video_path))
|
||||
output_video_encoder = fix_video_encoder(temp_video_format, output_video_encoder)
|
||||
encoder_thread_count = 16
|
||||
|
||||
commands = ffmpeg_builder.chain(
|
||||
ffmpeg_builder.set_output_format('rawvideo'),
|
||||
@@ -102,10 +97,9 @@ def create_video_writer(target_path : str, temp_video_fps : Fps, temp_video_reso
|
||||
ffmpeg_builder.set_media_resolution(vision.pack_resolution(temp_video_resolution)),
|
||||
ffmpeg_builder.set_input_fps(temp_video_fps),
|
||||
ffmpeg_builder.set_input('pipe:0'),
|
||||
ffmpeg_builder.set_filter_thread_count(4),
|
||||
ffmpeg_builder.set_media_resolution(vision.pack_resolution(output_video_resolution)),
|
||||
ffmpeg_builder.set_video_encoder(output_video_encoder),
|
||||
ffmpeg_builder.set_global_thread_count(encoder_thread_count),
|
||||
ffmpeg_builder.set_thread_count(16),
|
||||
ffmpeg_builder.set_video_tag(output_video_encoder, temp_video_format),
|
||||
ffmpeg_builder.set_video_quality(output_video_encoder, output_video_quality),
|
||||
ffmpeg_builder.set_video_preset(output_video_encoder, output_video_preset),
|
||||
@@ -116,6 +110,7 @@ def create_video_writer(target_path : str, temp_video_fps : Fps, temp_video_reso
|
||||
ffmpeg_builder.set_pixel_format(output_video_encoder),
|
||||
ffmpeg_builder.force_output(temp_video_path)
|
||||
)
|
||||
|
||||
return open_ffmpeg(commands)
|
||||
|
||||
|
||||
@@ -160,6 +155,7 @@ def extract_frames(target_path : str, temp_video_resolution : Resolution, temp_v
|
||||
color_transfer = ffprobe.extract_static_video_metadata(target_path).get('color_transfer')
|
||||
extract_frame_total = vision.predict_video_frame_total(target_path, temp_video_fps, trim_frame_start, trim_frame_end)
|
||||
temp_frame_pattern = get_temp_frame_pattern(target_path, '%08d')
|
||||
|
||||
commands = ffmpeg_builder.chain(
|
||||
ffmpeg_builder.set_input(target_path),
|
||||
ffmpeg_builder.set_media_resolution(vision.pack_resolution(temp_video_resolution)),
|
||||
@@ -181,24 +177,28 @@ def extract_frames(target_path : str, temp_video_resolution : Resolution, temp_v
|
||||
|
||||
def copy_image(target_path : str, temp_image_resolution : Resolution) -> bool:
|
||||
temp_image_path = get_temp_file_path(target_path)
|
||||
|
||||
commands = ffmpeg_builder.chain(
|
||||
ffmpeg_builder.set_input(target_path),
|
||||
ffmpeg_builder.set_media_resolution(vision.pack_resolution(temp_image_resolution)),
|
||||
ffmpeg_builder.set_image_quality(target_path, 100),
|
||||
ffmpeg_builder.force_output(temp_image_path)
|
||||
)
|
||||
|
||||
return run_ffmpeg(commands).returncode == 0
|
||||
|
||||
|
||||
def finalize_image(target_path : str, output_path : str, output_image_resolution : Resolution) -> bool:
|
||||
output_image_quality = state_manager.get_item('output_image_quality')
|
||||
temp_image_path = get_temp_file_path(target_path)
|
||||
|
||||
commands = ffmpeg_builder.chain(
|
||||
ffmpeg_builder.set_input(temp_image_path),
|
||||
ffmpeg_builder.set_media_resolution(vision.pack_resolution(output_image_resolution)),
|
||||
ffmpeg_builder.set_image_quality(target_path, output_image_quality),
|
||||
ffmpeg_builder.force_output(output_path)
|
||||
)
|
||||
|
||||
return run_ffmpeg(commands).returncode == 0
|
||||
|
||||
|
||||
@@ -228,8 +228,8 @@ def restore_audio(target_path : str, output_path : str, trim_frame_start : int,
|
||||
temp_video_format = cast(VideoFormat, get_file_format(temp_video_path))
|
||||
temp_video_duration = vision.detect_video_duration(temp_video_path)
|
||||
output_video_format = cast(VideoFormat, get_file_format(output_path))
|
||||
|
||||
output_audio_encoder = fix_audio_encoder(temp_video_format, output_audio_encoder)
|
||||
|
||||
commands = ffmpeg_builder.chain(
|
||||
ffmpeg_builder.set_input(temp_video_path),
|
||||
ffmpeg_builder.select_media_range(trim_frame_start, trim_frame_end, target_video_fps),
|
||||
@@ -244,6 +244,7 @@ def restore_audio(target_path : str, output_path : str, trim_frame_start : int,
|
||||
ffmpeg_builder.set_faststart(output_video_format),
|
||||
ffmpeg_builder.force_output(output_path)
|
||||
)
|
||||
|
||||
return run_ffmpeg(commands).returncode == 0
|
||||
|
||||
|
||||
@@ -255,8 +256,8 @@ def replace_audio(target_path : str, audio_path : str, output_path : str) -> boo
|
||||
temp_video_format = cast(VideoFormat, get_file_format(temp_video_path))
|
||||
temp_video_duration = vision.detect_video_duration(temp_video_path)
|
||||
output_video_format = cast(VideoFormat, get_file_format(output_path))
|
||||
|
||||
output_audio_encoder = fix_audio_encoder(temp_video_format, output_audio_encoder)
|
||||
|
||||
commands = ffmpeg_builder.chain(
|
||||
ffmpeg_builder.set_input(temp_video_path),
|
||||
ffmpeg_builder.set_input(audio_path),
|
||||
@@ -268,6 +269,7 @@ def replace_audio(target_path : str, audio_path : str, output_path : str) -> boo
|
||||
ffmpeg_builder.set_faststart(output_video_format),
|
||||
ffmpeg_builder.force_output(output_path)
|
||||
)
|
||||
|
||||
return run_ffmpeg(commands).returncode == 0
|
||||
|
||||
|
||||
@@ -279,8 +281,8 @@ def merge_video(target_path : str, temp_video_fps : Fps, output_video_resolution
|
||||
temp_video_path = get_temp_file_path(target_path)
|
||||
temp_video_format = cast(VideoFormat, get_file_format(temp_video_path))
|
||||
temp_frame_pattern = get_temp_frame_pattern(target_path, '%08d')
|
||||
|
||||
output_video_encoder = fix_video_encoder(temp_video_format, output_video_encoder)
|
||||
|
||||
commands = ffmpeg_builder.chain(
|
||||
ffmpeg_builder.set_input_fps(temp_video_fps),
|
||||
ffmpeg_builder.set_start_number(trim_frame_start),
|
||||
@@ -316,6 +318,7 @@ def concat_video(output_path : str, temp_output_paths : List[str]) -> bool:
|
||||
|
||||
output_path = os.path.abspath(output_path)
|
||||
output_video_format = cast(VideoFormat, get_file_format(output_path))
|
||||
|
||||
commands = ffmpeg_builder.chain(
|
||||
ffmpeg_builder.unsafe_concat(),
|
||||
ffmpeg_builder.set_input(concat_video_file.name),
|
||||
@@ -324,6 +327,7 @@ def concat_video(output_path : str, temp_output_paths : List[str]) -> bool:
|
||||
ffmpeg_builder.set_faststart(output_video_format),
|
||||
ffmpeg_builder.force_output(output_path)
|
||||
)
|
||||
|
||||
process = run_ffmpeg(commands)
|
||||
process.communicate()
|
||||
remove_file(concat_video_path)
|
||||
|
||||
@@ -83,14 +83,10 @@ def unsafe_concat() -> List[Command]:
|
||||
return [ '-f', 'concat', '-safe', '0' ]
|
||||
|
||||
|
||||
#todo: needs review - [seeking] [critical: low] seek based start for the pipe reader
|
||||
#todo: question to rename set_input_seek to just set_input
|
||||
def set_input_seek(seek_time : float) -> List[Command]:
|
||||
return [ '-ss', str(seek_time) ]
|
||||
def seek_to(time : float) -> List[Command]:
|
||||
return [ '-ss', str(time)]
|
||||
|
||||
|
||||
#todo: needs review - [decoding] [critical: low] raw output format for pipe io
|
||||
#todo: question if set_output_format is needed
|
||||
def set_output_format(output_format : str) -> List[Command]:
|
||||
return [ '-f', output_format ]
|
||||
|
||||
@@ -206,15 +202,10 @@ def set_audio_volume(audio_volume : int) -> List[Command]:
|
||||
|
||||
|
||||
#todo: needs review - [encoding] [critical: low] explicit ffmpeg thread cap
|
||||
def set_global_thread_count(thread_count : int) -> List[Command]:
|
||||
def set_thread_count(thread_count : int) -> List[Command]:
|
||||
return [ '-threads', str(thread_count) ]
|
||||
|
||||
|
||||
#todo: needs review - [decoding] [critical: low] threads the filter graph, new against the POC
|
||||
def set_filter_thread_count(thread_count : int) -> List[Command]:
|
||||
return [ '-filter_threads', str(thread_count) ]
|
||||
|
||||
|
||||
def set_video_encoder(video_encoder : str) -> List[Command]:
|
||||
return [ '-c:v', video_encoder ]
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ def probe_audio_entries(audio_path : str, entries : List[str]) -> Dict[str, str]
|
||||
ffprobe_builder.format_to_key_value(),
|
||||
ffprobe_builder.set_input(audio_path)
|
||||
)
|
||||
|
||||
output, _ = run_ffprobe(commands).communicate()
|
||||
|
||||
return parse_entries(output)
|
||||
@@ -44,6 +45,7 @@ def probe_video_entries(video_path : str, entries : List[str]) -> Dict[str, str]
|
||||
ffprobe_builder.format_to_key_value(),
|
||||
ffprobe_builder.set_input(video_path)
|
||||
)
|
||||
|
||||
output, _ = run_ffprobe(commands).communicate()
|
||||
|
||||
return parse_entries(output)
|
||||
@@ -55,6 +57,7 @@ def probe_format_entries(media_path : str, entries : List[str]) -> Dict[str, str
|
||||
ffprobe_builder.format_to_key_value(),
|
||||
ffprobe_builder.set_input(media_path)
|
||||
)
|
||||
|
||||
output, _ = run_ffprobe(commands).communicate()
|
||||
|
||||
return parse_entries(output)
|
||||
|
||||
+10
-6
@@ -123,23 +123,27 @@ VideoMetadata = TypedDict('VideoMetadata',
|
||||
'bit_rate' : BitRate,
|
||||
'color_transfer' : ColorTransfer
|
||||
})
|
||||
#todo: needs review - [types] [critical: low] reader and writer state around ffmpeg processes, metadata embedded whole
|
||||
#todo: question if the body of VideoReader and VideoWriter needs all the keys
|
||||
VideoReaderMetadata : TypeAlias = VideoMetadata
|
||||
VideoWriterMetadata = TypedDict('VideoWriterMetadata',
|
||||
{
|
||||
'fps' : Fps,
|
||||
'resolution' : Resolution
|
||||
})
|
||||
VideoReader = TypedDict('VideoReader',
|
||||
{
|
||||
'id' : str,
|
||||
'process' : subprocess.Popen[bytes],
|
||||
'file_path' : str,
|
||||
'metadata' : VideoMetadata,
|
||||
'process' : subprocess.Popen[bytes],
|
||||
'metadata' : VideoReaderMetadata,
|
||||
'position' : int
|
||||
})
|
||||
VideoReaderSet : TypeAlias = Dict[str, VideoReader]
|
||||
VideoWriter = TypedDict('VideoWriter',
|
||||
{
|
||||
'id' : str,
|
||||
'process' : subprocess.Popen[bytes],
|
||||
'file_path' : str,
|
||||
'metadata' : VideoMetadata
|
||||
'process' : subprocess.Popen[bytes],
|
||||
'metadata' : VideoWriterMetadata
|
||||
})
|
||||
VideoWriterSet : TypeAlias = Dict[str, VideoWriter]
|
||||
VideoPoolSet = TypedDict('VideoPoolSet',
|
||||
|
||||
+27
-25
@@ -5,7 +5,7 @@ import numpy
|
||||
|
||||
from facefusion import ffmpeg, ffprobe, frame_store
|
||||
from facefusion.common_helper import get_first, get_last
|
||||
from facefusion.types import Fps, Resolution, VideoMetadata, VideoPoolSet, VideoReader, VideoWriter, VisionFrame, VisionFrameSet
|
||||
from facefusion.types import Fps, Resolution, VideoPoolSet, VideoReader, VideoWriter, VisionFrame, VisionFrameSet
|
||||
|
||||
VIDEO_POOL_SET : VideoPoolSet =\
|
||||
{
|
||||
@@ -14,7 +14,6 @@ VIDEO_POOL_SET : VideoPoolSet =\
|
||||
}
|
||||
|
||||
|
||||
#todo: needs review - [lifecycle] [critical: medium] pooled reader per path is created without lock and only reaped via clear_video_pool
|
||||
def get_reader(video_path : str) -> VideoReader:
|
||||
if video_path not in VIDEO_POOL_SET.get('reader'):
|
||||
video_metadata = ffprobe.extract_static_video_metadata(video_path)
|
||||
@@ -22,8 +21,8 @@ def get_reader(video_path : str) -> VideoReader:
|
||||
VIDEO_POOL_SET['reader'][video_path] =\
|
||||
{
|
||||
'id': uuid.uuid4().hex,
|
||||
'process': ffmpeg.create_video_reader(video_path, 0, video_metadata),
|
||||
'file_path': video_path,
|
||||
'process': ffmpeg.create_video_reader(video_path, 0, video_metadata),
|
||||
'metadata': video_metadata,
|
||||
'position': 0
|
||||
}
|
||||
@@ -33,10 +32,10 @@ def get_reader(video_path : str) -> VideoReader:
|
||||
|
||||
#todo: needs review - [seeking] [critical: high] forward skip up to 128 frames by draining the pipe, everything else refreshes the process
|
||||
def conditional_set_video_reader_position(video_reader : VideoReader, frame_position : int) -> None:
|
||||
skip_margin = 128
|
||||
skip_total = frame_position - video_reader.get('position')
|
||||
skip_margin = 128
|
||||
|
||||
if skip_total > 0 and skip_total <= skip_margin:
|
||||
if 0 < skip_total <= skip_margin:
|
||||
for _ in range(skip_total):
|
||||
read_video_reader_frame(video_reader)
|
||||
|
||||
@@ -44,10 +43,9 @@ def conditional_set_video_reader_position(video_reader : VideoReader, frame_posi
|
||||
refresh_video_reader(video_reader, frame_position)
|
||||
|
||||
|
||||
#todo: needs review - [seeking] [critical: high] kill and respawn per out of order seek, frequent refreshes stack up on random access
|
||||
def refresh_video_reader(video_reader : VideoReader, frame_position : int) -> None:
|
||||
video_reader.get('process').kill()
|
||||
video_reader.get('process').wait()
|
||||
close_video_reader(video_reader)
|
||||
|
||||
video_reader['process'] = ffmpeg.create_video_reader(video_reader.get('file_path'), frame_position, video_reader.get('metadata'))
|
||||
video_reader['position'] = frame_position
|
||||
|
||||
@@ -93,42 +91,46 @@ def read_video_reader_window(video_reader : VideoReader, frame_start : int, fram
|
||||
return frame_store.select_frame_set(id, frame_start, frame_end)
|
||||
|
||||
|
||||
#todo: needs review - [lifecycle] [critical: low] pooled writer keyed by target_path, metadata forwarded by the caller
|
||||
def get_writer(target_path : str, video_metadata : VideoMetadata, temp_video_fps : Fps, temp_video_resolution : Resolution, output_video_resolution : Resolution, output_video_fps : Fps) -> VideoWriter:
|
||||
if target_path not in VIDEO_POOL_SET.get('writer'):
|
||||
VIDEO_POOL_SET['writer'][target_path] =\
|
||||
def close_video_reader(video_reader : VideoReader) -> None:
|
||||
video_reader.get('process').kill()
|
||||
video_reader.get('process').wait()
|
||||
frame_store.clear_frames(video_reader.get('id'))
|
||||
|
||||
|
||||
def get_writer(video_path : str, temp_video_fps : Fps, temp_video_resolution : Resolution, output_video_resolution : Resolution, output_video_fps : Fps) -> VideoWriter:
|
||||
if video_path not in VIDEO_POOL_SET.get('writer'):
|
||||
VIDEO_POOL_SET['writer'][video_path] =\
|
||||
{
|
||||
'id': uuid.uuid4().hex,
|
||||
'process': ffmpeg.create_video_writer(target_path, temp_video_fps, temp_video_resolution, output_video_resolution, output_video_fps),
|
||||
'file_path': target_path,
|
||||
'metadata': video_metadata
|
||||
'file_path': video_path,
|
||||
'process': ffmpeg.create_video_writer(video_path, temp_video_fps, temp_video_resolution, output_video_resolution, output_video_fps),
|
||||
'metadata':
|
||||
{
|
||||
'fps': output_video_fps,
|
||||
'resolution': output_video_resolution,
|
||||
}
|
||||
}
|
||||
|
||||
return VIDEO_POOL_SET.get('writer').get(target_path)
|
||||
return VIDEO_POOL_SET.get('writer').get(video_path)
|
||||
|
||||
|
||||
#todo: needs review - [encoding] [critical: medium] blocking stdin write without backpressure or broken pipe handling
|
||||
def write_video_writer_frame(video_writer : VideoWriter, vision_frame : VisionFrame) -> None:
|
||||
def write_video_writer(video_writer : VideoWriter, vision_frame : VisionFrame) -> None:
|
||||
video_writer.get('process').stdin.write(vision_frame.tobytes())
|
||||
|
||||
|
||||
#todo: needs review - [encoding] [critical: medium] encoder failures only surface via returncode at close time
|
||||
def close_video_writer(video_writer : VideoWriter) -> bool:
|
||||
video_writer.get('process').stdin.close()
|
||||
video_writer.get('process').wait()
|
||||
|
||||
return video_writer.get('process').returncode == 0
|
||||
|
||||
|
||||
#todo: needs review - [lifecycle] [critical: high] kill over terminate, sigterm deadlocks while the pipe is full
|
||||
def clear_video_pool() -> None:
|
||||
for video_reader in VIDEO_POOL_SET.get('reader').values():
|
||||
video_reader.get('process').kill()
|
||||
video_reader.get('process').wait()
|
||||
frame_store.clear_frames(video_reader.get('id'))
|
||||
close_video_reader(video_reader)
|
||||
|
||||
for video_writer in VIDEO_POOL_SET.get('writer').values():
|
||||
video_writer.get('process').kill()
|
||||
video_writer.get('process').wait()
|
||||
close_video_writer(video_writer)
|
||||
|
||||
VIDEO_POOL_SET['reader'].clear()
|
||||
VIDEO_POOL_SET['writer'].clear()
|
||||
|
||||
@@ -5,7 +5,7 @@ import numpy
|
||||
from tqdm import tqdm
|
||||
|
||||
import facefusion.workflows.image_to_video as image_to_video
|
||||
from facefusion import ffprobe, logger, process_manager, state_manager, translator, video_manager
|
||||
from facefusion import logger, process_manager, state_manager, translator, video_manager
|
||||
from facefusion.audio import create_empty_audio_frame, get_audio_frame, get_voice_frame
|
||||
from facefusion.common_helper import get_first
|
||||
from facefusion.filesystem import filter_audio_paths
|
||||
@@ -138,8 +138,7 @@ def process_stream_frames() -> ErrorCode:
|
||||
frame_range = range(trim_frame_start, trim_frame_end)
|
||||
|
||||
if frame_range:
|
||||
video_metadata = ffprobe.extract_static_video_metadata(state_manager.get_item('target_path'))
|
||||
video_writer = video_manager.get_writer(state_manager.get_item('target_path'), video_metadata, temp_video_fps, temp_video_resolution, output_video_resolution, state_manager.get_item('output_video_fps'))
|
||||
video_writer = video_manager.get_writer(state_manager.get_item('target_path'), temp_video_fps, temp_video_resolution, output_video_resolution, state_manager.get_item('output_video_fps'))
|
||||
frame_look_ahead = image_to_video.calculate_frame_look_ahead(temp_video_resolution)
|
||||
|
||||
with tqdm(total = len(frame_range), desc = translator.get('processing'), unit = 'frame', ascii = ' =', disable = state_manager.get_item('log_level') in [ 'warn', 'error' ]) as progress:
|
||||
|
||||
@@ -186,7 +186,7 @@ def write_stream_frame(video_writer : VideoWriter, futures : List[Future[Tuple[i
|
||||
|
||||
if not future.cancelled():
|
||||
_, temp_vision_frame = future.result()
|
||||
video_manager.write_video_writer_frame(video_writer, temp_vision_frame)
|
||||
video_manager.write_video_writer(video_writer, temp_vision_frame)
|
||||
progress.update()
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from shutil import which
|
||||
|
||||
from facefusion import ffmpeg_builder
|
||||
from facefusion.ffmpeg_builder import chain, concat, convert_color_space, keep_video_alpha, restrict_color_transfer, run, select_frame_range, set_audio_quality, set_audio_sample_size, set_faststart, set_filter_thread_count, set_global_thread_count, set_input_seek, set_output_format, set_stream_mode, set_video_encoder, set_video_fps, set_video_quality, set_video_tag
|
||||
from facefusion.ffmpeg_builder import chain, concat, convert_color_space, keep_video_alpha, restrict_color_transfer, run, seek_to, select_frame_range, set_audio_quality, set_audio_sample_size, set_faststart, set_output_format, set_stream_mode, set_thread_count, set_video_encoder, set_video_fps, set_video_quality, set_video_tag
|
||||
|
||||
|
||||
def test_run() -> None:
|
||||
@@ -41,9 +41,9 @@ def test_set_stream_mode() -> None:
|
||||
assert set_stream_mode('v4l2') == [ '-f', 'v4l2' ]
|
||||
|
||||
|
||||
def test_set_input_seek() -> None:
|
||||
assert set_input_seek(0.0) == [ '-ss', '0.0' ]
|
||||
assert set_input_seek(1.5) == [ '-ss', '1.5' ]
|
||||
def test_seek_to() -> None:
|
||||
assert seek_to(0.0) == [ '-ss', '0.0' ]
|
||||
assert seek_to(1.5) == [ '-ss', '1.5' ]
|
||||
|
||||
|
||||
def test_set_output_format() -> None:
|
||||
@@ -92,14 +92,9 @@ def test_set_audio_quality() -> None:
|
||||
assert set_audio_quality('flac', 100) == []
|
||||
|
||||
|
||||
def test_set_global_thread_count() -> None:
|
||||
assert set_global_thread_count(8) == [ '-threads', '8' ]
|
||||
assert set_global_thread_count(16) == [ '-threads', '16' ]
|
||||
|
||||
|
||||
def test_set_filter_thread_count() -> None:
|
||||
assert set_filter_thread_count(8) == [ '-filter_threads', '8' ]
|
||||
assert set_filter_thread_count(16) == [ '-filter_threads', '16' ]
|
||||
def test_set_thread_count() -> None:
|
||||
assert set_thread_count(8) == [ '-threads', '8' ]
|
||||
assert set_thread_count(16) == [ '-threads', '16' ]
|
||||
|
||||
|
||||
def test_set_faststart() -> None:
|
||||
|
||||
+13
-12
@@ -9,7 +9,7 @@ from facefusion.download import conditional_download
|
||||
from facefusion.ffprobe import extract_video_metadata
|
||||
from facefusion.frame_store import get_frame_store
|
||||
from facefusion.temp_helper import create_temp_directory, get_temp_file_path
|
||||
from facefusion.video_manager import clear_video_pool, close_video_writer, conditional_set_video_reader_position, get_reader, get_writer, read_video_reader_frame, read_video_reader_window, refresh_video_reader, write_video_writer_frame
|
||||
from facefusion.video_manager import clear_video_pool, close_video_writer, conditional_set_video_reader_position, get_reader, get_writer, read_video_reader_frame, read_video_reader_window, refresh_video_reader, write_video_writer
|
||||
from .helper import get_test_example_file, get_test_examples_directory
|
||||
|
||||
|
||||
@@ -134,24 +134,23 @@ def test_read_video_reader_window() -> None:
|
||||
#todo: run mutation testing, strip down to the minimum, test with real data
|
||||
def test_get_writer() -> None:
|
||||
target_path = get_test_example_file('target-240p-25fps.mp4')
|
||||
video_metadata = extract_video_metadata(target_path)
|
||||
create_temp_directory(target_path)
|
||||
video_writer = get_writer(target_path, video_metadata, 25.0, (426, 226), (426, 226), 25.0)
|
||||
video_writer = get_writer(target_path, 25.0, (426, 226), (426, 226), 25.0)
|
||||
|
||||
assert get_writer(target_path, video_metadata, 25.0, (426, 226), (426, 226), 25.0) is video_writer
|
||||
assert get_writer(target_path, 25.0, (426, 226), (426, 226), 25.0) is video_writer
|
||||
|
||||
|
||||
#todo: needs review - [testing] question if the assertions are good
|
||||
#todo: run mutation testing, strip down to the minimum, test with real data
|
||||
def test_write_video_writer_frame() -> None:
|
||||
def test_write_video_writer() -> None:
|
||||
target_path = get_test_example_file('target-240p-25fps.mp4')
|
||||
create_temp_directory(target_path)
|
||||
video_reader = get_reader(target_path)
|
||||
video_writer = get_writer(target_path, video_reader.get('metadata'), 25.0, (426, 226), (426, 226), 25.0)
|
||||
video_writer = get_writer(target_path, 25.0, (426, 226), (426, 226), 25.0)
|
||||
|
||||
for frame_number in range(25):
|
||||
vision_frame = read_video_reader_frame(video_reader)
|
||||
write_video_writer_frame(video_writer, vision_frame)
|
||||
write_video_writer(video_writer, vision_frame)
|
||||
|
||||
assert close_video_writer(video_writer) is True
|
||||
|
||||
@@ -170,9 +169,9 @@ def test_close_video_writer() -> None:
|
||||
target_path = get_test_example_file('target-240p-30fps.mp4')
|
||||
create_temp_directory(target_path)
|
||||
video_reader = get_reader(target_path)
|
||||
video_writer = get_writer(target_path, video_reader.get('metadata'), 30.0, (426, 226), (426, 226), 30.0)
|
||||
video_writer = get_writer(target_path, 30.0, (426, 226), (426, 226), 30.0)
|
||||
vision_frame = read_video_reader_frame(video_reader)
|
||||
write_video_writer_frame(video_writer, vision_frame)
|
||||
write_video_writer(video_writer, vision_frame)
|
||||
|
||||
assert close_video_writer(video_writer) is True
|
||||
|
||||
@@ -183,13 +182,15 @@ def test_clear_video_pool() -> None:
|
||||
target_path = get_test_example_file('target-240p-25fps.mp4')
|
||||
create_temp_directory(target_path)
|
||||
video_reader = get_reader(target_path)
|
||||
video_writer = get_writer(target_path, video_reader.get('metadata'), 25.0, (426, 226), (426, 226), 25.0)
|
||||
video_writer = get_writer(target_path, 25.0, (426, 226), (426, 226), 25.0)
|
||||
vision_frame = read_video_reader_frame(video_reader)
|
||||
write_video_writer(video_writer, vision_frame)
|
||||
clear_video_pool()
|
||||
|
||||
if is_windows():
|
||||
assert video_reader.get('process').returncode == 1
|
||||
assert video_writer.get('process').returncode == 1
|
||||
|
||||
if is_linux() or is_macos():
|
||||
assert video_reader.get('process').returncode == -9
|
||||
assert video_writer.get('process').returncode == -9
|
||||
|
||||
assert video_writer.get('process').returncode == 0
|
||||
|
||||
Reference in New Issue
Block a user