From eaacbf4ec014d690cce8c81d642154fe3772be86 Mon Sep 17 00:00:00 2001 From: Brett Williams Date: Sat, 27 May 2023 16:01:54 -0500 Subject: [PATCH] Blender image sequences now generate a preview mp4 on completion --- lib/render_workers/base_worker.py | 4 ++++ lib/render_workers/blender_worker.py | 18 ++++++++++++++++++ lib/server/job_server.py | 2 +- lib/utilities/ffmpeg_helper.py | 7 ++++--- scheduler_gui.py | 2 +- 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/lib/render_workers/base_worker.py b/lib/render_workers/base_worker.py index 975eea9..c544111 100644 --- a/lib/render_workers/base_worker.py +++ b/lib/render_workers/base_worker.py @@ -187,6 +187,10 @@ class BaseRenderWorker(object): if not self.errors: self.errors = [self.last_output] self.is_finished = True + self.post_processing() + + def post_processing(self): + pass def is_running(self): if self.__thread: diff --git a/lib/render_workers/blender_worker.py b/lib/render_workers/blender_worker.py index 8dbc3f1..3f167cb 100644 --- a/lib/render_workers/blender_worker.py +++ b/lib/render_workers/blender_worker.py @@ -113,6 +113,24 @@ class BlenderRenderWorker(BaseRenderWorker): total_percent = whole_frame_percent + adjusted_frame_percent return max(total_percent, 0) + def post_processing(self): + output_dir = os.listdir(os.path.dirname(self.output_path)) + if self.render_all_frames and len(output_dir) > 1: + from ..utilities.ffmpeg_helper import image_sequence_to_video + logger.info("Generating preview for image sequence") + + # get proper file extension + found_output = next(obj for obj in output_dir if os.path.basename(self.output_path) in obj) + glob_pattern = self.output_path + '%04d' + ('.' + found_output.split('.')[-1] if found_output else "") + + try: + image_sequence_to_video(source_glob_pattern=glob_pattern, + output_path=self.output_path + '_preview.mp4', + framerate=self.scene_info['fps']) + logger.info('Successfully generated preview image sequence') + except Exception as e: + logger.error('Error generating image sequence') + if __name__ == '__main__': diff --git a/lib/server/job_server.py b/lib/server/job_server.py index 5b0832c..7466c92 100755 --- a/lib/server/job_server.py +++ b/lib/server/job_server.py @@ -269,7 +269,7 @@ def add_job_handler(): job['input_path'] = uploaded_file_local_path output_dir = os.path.join(job_dir, job.get('name', None) or 'output') os.makedirs(output_dir, exist_ok=True) - job['output_path'] = os.path.join(output_dir, os.path.basename(job['output_path'])) + job['output_path'] = os.path.join(output_dir, os.path.basename(job.get('name', job['output_path']))) remove_job_dir = len(jobs_list) == 1 and uploaded_file_local_path # remove failed job dir for single file uploads only add_result = add_job(job, remove_job_dir_on_failure=remove_job_dir) results.append(add_result) diff --git a/lib/utilities/ffmpeg_helper.py b/lib/utilities/ffmpeg_helper.py index 611591f..080af66 100644 --- a/lib/utilities/ffmpeg_helper.py +++ b/lib/utilities/ffmpeg_helper.py @@ -1,5 +1,6 @@ import subprocess import ffmpeg # todo: remove all references to ffmpeg library and instead use direct subprocesses +from ..render_engines.ffmpeg_engine import FFMPEG def file_info(path): @@ -10,9 +11,9 @@ def file_info(path): return None -def image_sequence_to_video(source_glob_pattern, output_path, framerate="24", encoder="libx264"): - subprocess.run(['ffmpeg', "-y", "-framerate", framerate, "-pattern_type", "glob", "-i", f"{source_glob_pattern}", - "-c:v", encoder, output_path]) +def image_sequence_to_video(source_glob_pattern, output_path, framerate="24", encoder="libx264", pix_fmt="yuv420p"): + subprocess.run([FFMPEG.renderer_path(), "-framerate", str(framerate), "-i", f"{source_glob_pattern}", + "-c:v", encoder, "-pix_fmt", pix_fmt, output_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def save_first_frame(source_path, dest_path, max_width=1280, run_async=False): diff --git a/scheduler_gui.py b/scheduler_gui.py index bdea367..930f011 100755 --- a/scheduler_gui.py +++ b/scheduler_gui.py @@ -214,7 +214,7 @@ class ScheduleJob(Frame): self.output_entry.delete(0, END) if self.chosen_file: # Generate a default output name - output_name = os.path.basename(self.chosen_file).split('.')[0] + '-output' + output_name = os.path.basename(self.chosen_file).split('.')[0] self.output_entry.insert(0, os.path.basename(output_name)) # Try to determine file type extension = self.chosen_file.split('.')[-1] # not the best way to do this