|
import roop.globals |
|
|
|
from threading import Thread |
|
from chain_img_processor import ChainImgProcessor |
|
|
|
class ThreadWithReturnValue(Thread): |
|
|
|
def __init__(self, group=None, target=None, name=None, |
|
args=(), kwargs={}, Verbose=None): |
|
Thread.__init__(self, group, target, name, args, kwargs) |
|
self._return = None |
|
|
|
def run(self): |
|
if self._target is not None: |
|
self._return = self._target(*self._args, |
|
**self._kwargs) |
|
|
|
def join(self, *args): |
|
Thread.join(self, *args) |
|
return self._return |
|
|
|
|
|
|
|
class ChainVideoProcessor(ChainImgProcessor): |
|
def __init__(self): |
|
ChainImgProcessor.__init__(self) |
|
|
|
self.video_save_codec = "libx264" |
|
self.video_save_crf = 14 |
|
|
|
def init_with_plugins(self): |
|
self.init_plugins(["core","core_video"]) |
|
self.display_init_info() |
|
|
|
init_on_start_arr = self.init_on_start.split(",") |
|
for proc_id in init_on_start_arr: |
|
self.init_processor(proc_id) |
|
|
|
def run_video_chain(self, source_video, target_video, fps, threads:int = 1, chain = None, params_frame_gen_func = None, video_audio = None): |
|
import cv2 |
|
from tqdm import tqdm |
|
from chain_img_processor.ffmpeg_writer import FFMPEG_VideoWriter |
|
|
|
cap = cv2.VideoCapture(source_video) |
|
|
|
|
|
frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) |
|
|
|
|
|
ret, frame = cap.read() |
|
if params_frame_gen_func is not None: |
|
params = params_frame_gen_func(self, frame) |
|
else: |
|
params = {} |
|
params["original_frame"] = frame |
|
frame_processed, params = self.run_chain(frame,params,chain) |
|
height, width, channels = frame_processed.shape |
|
|
|
self.fill_processors_for_thread_chains(threads,chain) |
|
|
|
|
|
|
|
locks: list[bool] = [] |
|
for i in range(threads): |
|
|
|
locks.append(False) |
|
|
|
temp = [] |
|
with FFMPEG_VideoWriter(target_video, (width, height), fps, codec=roop.globals.video_encoder, crf=roop.globals.video_quality, audiofile=video_audio) as output_video_ff: |
|
with tqdm(total=frame_count, desc='Processing', unit="frame", dynamic_ncols=True, |
|
bar_format='{l_bar}{bar}| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, {rate_fmt}{postfix}]') as progress: |
|
|
|
|
|
output_video_ff.write_frame(frame_processed) |
|
progress.update(1) |
|
cnt_frames = 0 |
|
|
|
|
|
while True: |
|
|
|
ret, frame = cap.read() |
|
|
|
if not ret: |
|
break |
|
cnt_frames+=1 |
|
thread_ind = cnt_frames % threads |
|
|
|
|
|
|
|
while locks[thread_ind]: |
|
|
|
|
|
frame_processed, params = temp.pop(0).join() |
|
locks[params["_thread_index"]] = False |
|
|
|
|
|
output_video_ff.write_frame(frame_processed) |
|
|
|
progress.update(1) |
|
|
|
|
|
if params_frame_gen_func is not None: |
|
params = params_frame_gen_func(self,frame) |
|
else: |
|
params = {} |
|
|
|
|
|
locks[thread_ind] = True |
|
|
|
params["original_frame"] = frame |
|
temp.append( |
|
ThreadWithReturnValue(target=self.run_chain, args=(frame, params, chain, thread_ind))) |
|
temp[-1].start() |
|
|
|
while len(temp) > 0: |
|
|
|
frame_processed, params = temp.pop(0).join() |
|
locks[params["_thread_index"]] = False |
|
|
|
output_video_ff.write_frame(frame_processed) |
|
|
|
progress.update(1) |
|
|
|
|
|
|
|
_video_processor:ChainVideoProcessor = None |
|
def get_single_video_processor() -> ChainVideoProcessor: |
|
global _video_processor |
|
if _video_processor is None: |
|
_video_processor = ChainVideoProcessor() |
|
_video_processor.init_with_plugins() |
|
return _video_processor |
|
|