| 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 |
|
|