multi reader approach

This commit is contained in:
henryruhs
2026-07-25 16:10:55 +02:00
parent 07cbd09304
commit 8a12f98762
5 changed files with 34 additions and 57 deletions
+6 -4
View File
@@ -4,12 +4,12 @@ from typing import Tuple
import numpy
from tqdm import tqdm
from facefusion import inference_manager, state_manager, translator
from facefusion import inference_manager, state_manager, translator, video_manager
from facefusion.download import conditional_download_hashes, conditional_download_sources, resolve_download_url
from facefusion.filesystem import resolve_relative_path
from facefusion.thread_helper import conditional_thread_semaphore
from facefusion.types import Detection, DownloadScope, DownloadSet, Fps, InferencePool, ModelSet, VisionFrame
from facefusion.vision import detect_video_fps, fit_contain_frame, read_image, read_video_frame
from facefusion.vision import detect_video_fps, fit_contain_frame, read_image
STREAM_COUNTER = 0
@@ -161,13 +161,15 @@ def analyse_video(video_path : str, trim_frame_start : int, trim_frame_end : int
rate = 0.0
total = 0
counter = 0
video_reader = video_manager.get_reader(video_path, 'analyse_video')
video_manager.seek_video_reader(video_reader, trim_frame_start)
with tqdm(total = len(frame_range), desc = translator.get('analysing'), unit = 'frame', ascii = ' =', disable = state_manager.get_item('log_level') in [ 'warn', 'error' ]) as progress:
for frame_number in frame_range:
if frame_number % int(video_fps) == 0:
vision_frame = read_video_frame(video_path, frame_number)
vision_frame = video_manager.read_video_frame(video_reader)
if frame_number % int(video_fps) == 0:
if numpy.any(vision_frame):
total += 1
+1 -1
View File
@@ -100,7 +100,7 @@ def pre_check() -> bool:
def common_pre_check() -> bool:
content_analyser_content = inspect.getsource(content_analyser).encode()
return hash_helper.create_hash(content_analyser_content) == '975d67d6'
return hash_helper.create_hash(content_analyser_content) == '5f04e67c'
def processors_pre_check() -> bool:
+13 -21
View File
@@ -1,3 +1,4 @@
import hashlib
import uuid
from typing import Optional
@@ -14,40 +15,31 @@ VIDEO_POOL_SET : VideoPoolSet =\
}
def get_reader(video_path : str) -> VideoReader:
if video_path not in VIDEO_POOL_SET.get('reader'):
def get_reader(video_path : str, context : str) -> VideoReader:
reader_id = hashlib.sha1((video_path + '_' + context).encode()).hexdigest()
if reader_id not in VIDEO_POOL_SET.get('reader'):
video_metadata = ffprobe.extract_static_video_metadata(video_path)
VIDEO_POOL_SET['reader'][video_path] =\
VIDEO_POOL_SET['reader'][reader_id] =\
{
'id': uuid.uuid4().hex,
'id': reader_id,
'file_path': video_path,
'process': ffmpeg.create_video_reader(video_path, 0, video_metadata),
'metadata': video_metadata,
'frame_number': 0
}
return VIDEO_POOL_SET.get('reader').get(video_path)
def conditional_seek_video_reader(video_reader : VideoReader, frame_number : int = 0) -> None:
frame_number = min(video_reader.get('metadata').get('frame_total'), frame_number)
skip_total = frame_number - video_reader.get('frame_number')
skip_margin = 128
if 0 < skip_total <= skip_margin:
for _ in range(skip_total):
read_video_frame(video_reader)
if not video_reader.get('frame_number') == frame_number:
seek_video_reader(video_reader, frame_number)
return VIDEO_POOL_SET.get('reader').get(reader_id)
def seek_video_reader(video_reader : VideoReader, frame_number : int = 0) -> None:
close_video_reader(video_reader)
frame_number = min(video_reader.get('metadata').get('frame_total'), frame_number)
video_reader['process'] = ffmpeg.create_video_reader(video_reader.get('file_path'), frame_number, video_reader.get('metadata'))
video_reader['frame_number'] = frame_number
if not video_reader.get('frame_number') == frame_number:
close_video_reader(video_reader)
video_reader['process'] = ffmpeg.create_video_reader(video_reader.get('file_path'), frame_number, video_reader.get('metadata'))
video_reader['frame_number'] = frame_number
#todo: needs review - [decoding] [critical: high] partial pipe read returns none and desyncs position from the actual stream
+3 -3
View File
@@ -77,10 +77,10 @@ def read_static_video_frame(video_path : str, frame_number : int = 0) -> Optiona
def read_video_frame(video_path : str, frame_number : int = 0) -> Optional[VisionFrame]:
if is_video(video_path):
video_reader = video_manager.get_reader(video_path)
video_reader = video_manager.get_reader(video_path, 'read_video_frame')
with thread_semaphore():
video_manager.conditional_seek_video_reader(video_reader, frame_number)
video_manager.seek_video_reader(video_reader, frame_number)
return video_manager.read_video_frame(video_reader)
return None
@@ -93,7 +93,7 @@ def select_video_frames(video_path : str, frame_number : int = 0, frame_offset :
if is_video(video_path):
with thread_lock():
video_reader = video_manager.get_reader(video_path)
video_reader = video_manager.get_reader(video_path, 'select_video_frames')
frame_set = video_manager.read_video_frames(video_reader, max(frame_start, 0), frame_end)
for frame_number in range(frame_start, frame_end + 1):
+11 -28
View File
@@ -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_seek_video_reader, get_reader, get_writer, read_video_frame, read_video_frames, seek_video_reader, write_video_frame
from facefusion.video_manager import clear_video_pool, close_video_writer, get_reader, get_writer, read_video_frame, read_video_frames, seek_video_reader, write_video_frame
from .helper import get_test_example_file, get_test_examples_directory
@@ -46,38 +46,21 @@ def before_each() -> None:
#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_get_reader() -> None:
video_reader = get_reader(get_test_example_file('target-240p-25fps.mp4'))
video_reader = get_reader(get_test_example_file('target-240p-25fps.mp4'), 'read_video_frame')
video_metadata = video_reader.get('metadata')
assert video_metadata.get('resolution') == (426, 226)
assert video_metadata.get('fps') == 25.0
assert video_metadata.get('frame_total') == 270
assert video_reader.get('frame_number') == 0
assert get_reader(get_test_example_file('target-240p-25fps.mp4')) is video_reader
#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_conditional_seek_video_reader() -> None:
video_reader = get_reader(get_test_example_file('target-240p-25fps.mp4'))
conditional_seek_video_reader(video_reader, 50)
assert video_reader.get('frame_number') == 50
conditional_seek_video_reader(video_reader, 10)
assert video_reader.get('frame_number') == 10
conditional_seek_video_reader(video_reader, 200)
assert video_reader.get('frame_number') == 200
assert get_reader(get_test_example_file('target-240p-25fps.mp4'), 'read_video_frame') is video_reader
assert not get_reader(get_test_example_file('target-240p-25fps.mp4'), 'select_video_frames').get('id') == video_reader.get('id')
#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_seek_video_reader() -> None:
video_reader = get_reader(get_test_example_file('target-240p-25fps.mp4'))
video_reader = get_reader(get_test_example_file('target-240p-25fps.mp4'), 'read_video_frame')
sequential_frames = {}
for frame_number in range(30):
@@ -93,13 +76,13 @@ def test_seek_video_reader() -> None:
#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_read_video_frame() -> None:
video_reader = get_reader(get_test_example_file('target-240p-25fps.mp4'))
video_reader = get_reader(get_test_example_file('target-240p-25fps.mp4'), 'read_video_frame')
vision_frame = read_video_frame(video_reader)
assert vision_frame.shape == (226, 426, 3)
assert video_reader.get('frame_number') == 1
conditional_seek_video_reader(video_reader, 269)
seek_video_reader(video_reader, 269)
vision_frame = read_video_frame(video_reader)
assert vision_frame.shape == (226, 426, 3)
@@ -109,7 +92,7 @@ def test_read_video_frame() -> None:
#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_read_video_frames() -> None:
video_reader = get_reader(get_test_example_file('target-240p-25fps.mp4'))
video_reader = get_reader(get_test_example_file('target-240p-25fps.mp4'), 'read_video_frame')
frame_set = read_video_frames(video_reader, 0, 4)
assert sorted(frame_set) == [ 0, 1, 2, 3, 4 ]
@@ -145,7 +128,7 @@ def test_get_writer() -> None:
def test_write_video_frame() -> None:
target_path = get_test_example_file('target-240p-25fps.mp4')
create_temp_directory(target_path)
video_reader = get_reader(target_path)
video_reader = get_reader(target_path, 'read_video_frame')
video_writer = get_writer(target_path, 25.0, (426, 226), (426, 226), 25.0)
for frame_number in range(25):
@@ -168,7 +151,7 @@ def test_write_video_frame() -> None:
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_reader = get_reader(target_path, 'read_video_frame')
video_writer = get_writer(target_path, 30.0, (426, 226), (426, 226), 30.0)
vision_frame = read_video_frame(video_reader)
write_video_frame(video_writer, vision_frame)
@@ -181,7 +164,7 @@ def test_close_video_writer() -> None:
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_reader = get_reader(target_path, 'read_video_frame')
video_writer = get_writer(target_path, 25.0, (426, 226), (426, 226), 25.0)
vision_frame = read_video_frame(video_reader)
write_video_frame(video_writer, vision_frame)