mirror of
https://github.com/blw1138/Zordon.git
synced 2025-12-17 16:58:12 +00:00
Blender image sequences now generate a preview mp4 on completion
This commit is contained in:
@@ -187,6 +187,10 @@ class BaseRenderWorker(object):
|
|||||||
if not self.errors:
|
if not self.errors:
|
||||||
self.errors = [self.last_output]
|
self.errors = [self.last_output]
|
||||||
self.is_finished = True
|
self.is_finished = True
|
||||||
|
self.post_processing()
|
||||||
|
|
||||||
|
def post_processing(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def is_running(self):
|
def is_running(self):
|
||||||
if self.__thread:
|
if self.__thread:
|
||||||
|
|||||||
@@ -113,6 +113,24 @@ class BlenderRenderWorker(BaseRenderWorker):
|
|||||||
total_percent = whole_frame_percent + adjusted_frame_percent
|
total_percent = whole_frame_percent + adjusted_frame_percent
|
||||||
return max(total_percent, 0)
|
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__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ def add_job_handler():
|
|||||||
job['input_path'] = uploaded_file_local_path
|
job['input_path'] = uploaded_file_local_path
|
||||||
output_dir = os.path.join(job_dir, job.get('name', None) or 'output')
|
output_dir = os.path.join(job_dir, job.get('name', None) or 'output')
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
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
|
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)
|
add_result = add_job(job, remove_job_dir_on_failure=remove_job_dir)
|
||||||
results.append(add_result)
|
results.append(add_result)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
import ffmpeg # todo: remove all references to ffmpeg library and instead use direct subprocesses
|
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):
|
def file_info(path):
|
||||||
@@ -10,9 +11,9 @@ def file_info(path):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def image_sequence_to_video(source_glob_pattern, output_path, framerate="24", encoder="libx264"):
|
def image_sequence_to_video(source_glob_pattern, output_path, framerate="24", encoder="libx264", pix_fmt="yuv420p"):
|
||||||
subprocess.run(['ffmpeg', "-y", "-framerate", framerate, "-pattern_type", "glob", "-i", f"{source_glob_pattern}",
|
subprocess.run([FFMPEG.renderer_path(), "-framerate", str(framerate), "-i", f"{source_glob_pattern}",
|
||||||
"-c:v", encoder, output_path])
|
"-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):
|
def save_first_frame(source_path, dest_path, max_width=1280, run_async=False):
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ class ScheduleJob(Frame):
|
|||||||
self.output_entry.delete(0, END)
|
self.output_entry.delete(0, END)
|
||||||
if self.chosen_file:
|
if self.chosen_file:
|
||||||
# Generate a default output name
|
# 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))
|
self.output_entry.insert(0, os.path.basename(output_name))
|
||||||
# Try to determine file type
|
# Try to determine file type
|
||||||
extension = self.chosen_file.split('.')[-1] # not the best way to do this
|
extension = self.chosen_file.split('.')[-1] # not the best way to do this
|
||||||
|
|||||||
Reference in New Issue
Block a user