import time import re from pathlib import Path import os import bpy from bpy.types import Operator from bpy.props import BoolProperty from vse_toolbox.sequencer_utils import (get_strips, render_strip, render_sound, render_scene, get_render_attributes) from vse_toolbox.bl_utils import (get_scene_settings, background_render) from vse_toolbox.file_utils import install_module, expand class VSETB_OT_render(Operator): bl_idname = "vse_toolbox.strips_render" bl_label = "Render Shots Strips" bl_description = "Render Shots Strips" bl_options = {"REGISTER", "UNDO"} #selected_only : BoolProperty(name="Selected Only", default=False) @classmethod def poll(cls, context): settings = get_scene_settings() return settings.active_project def invoke(self, context, event): scn = context.scene settings = get_scene_settings() return context.window_manager.invoke_props_dialog(self, width=500) def draw_export_row(self, layout, text, data, enable_prop, template_prop): row = layout.split(factor=0.1) heading = row.row(align=True) heading.alignment = 'RIGHT' heading.label(text=text) heading.prop(data, enable_prop, text='') row = row.row(align=True) row.enabled = getattr(data, enable_prop) row.prop(data, template_prop, text='') def draw(self, context): scn = context.scene settings = get_scene_settings() layout = self.layout #layout.use_property_split = True #layout.use_property_decorate = False box = layout.box() col = box.column() row = col.row(align=True) row.prop(settings.active_project, "render_single_file", text='') row.label(icon='FILE_MOVIE') row.label(text='Single File') if settings.active_project.render_single_file: self.draw_export_row(col ,'Video', settings.active_project, 'render_video', 'render_video_template' ) self.draw_export_row(col, 'Audio', settings.active_project, 'render_audio', 'render_audio_template' ) #layout.separator() box = layout.box() col = box.column() row = col.row(align=True) row.prop(settings.active_project, "render_sequence", text='') row.label(icon='SEQUENCE') row.label(text='One file per sequence') if settings.active_project.render_sequence: self.draw_export_row(col ,'Video', settings.active_project, 'render_video_per_sequence', 'render_video_sequence_template' ) self.draw_export_row(col, 'Audio', settings.active_project, 'render_audio_per_sequence', 'render_audio_sequence_template' ) #col.prop(settings, 'channel', text='Channel') #col.prop(self, 'selected_only') #layout.separator() box = layout.box() col = box.column() row = col.row(align=True) row.prop(settings.active_project, "render_shot", text='') row.label(icon='SEQ_SEQUENCER') row.label(text='One file per shot') if settings.active_project.render_shot: self.draw_export_row(col ,'Video', settings.active_project, 'render_video_per_strip', 'render_video_strip_template' ) self.draw_export_row(col, 'Audio', settings.active_project, 'render_audio_per_strip', 'render_audio_strip_template' ) row = layout.row() row.prop(settings.active_project, "render_selected_only", text='Selected Only') #col.prop(settings, 'channel', text='Channel') #col.prop(self, 'selected_only') def execute(self, context): scn = context.scene settings = get_scene_settings() project = settings.active_project project_templates = {t.name: t.value for t in project.templates} format_data = {**settings.format_data, **project.format_data} single_file = False sequence_strips = [] shot_strips = [] render_attrs = get_render_attributes() start_time = time.perf_counter() if project.render_single_file: single_file = True if project.render_video: video_template = expand(project.render_video_template, **project_templates) video_path = video_template.format(**format_data) render_scene(video_path, attributes=render_attrs) #background_render(output=video_path) if project.render_audio: audio_template = expand(project.render_audio_template, **project_templates) audio_path = audio_template.format(**format_data) bpy.ops.sound.mixdown(filepath=audio_path) if project.render_sequence: print('Render Sequences...') sequence_strips = get_strips(channel='Sequences', selected_only=project.render_selected_only) for strip in sequence_strips: #print(strip.name) strip_settings = strip.vsetb_strip_settings strip_data = {**format_data, **strip_settings.format_data} if project.render_sequence and project.render_video_per_sequence: video_sequence_template = expand(project.render_video_sequence_template, **project_templates) sequence_render_path = video_sequence_template.format(**strip_data) render_strip(strip, sequence_render_path, attributes=render_attrs) if project.render_shot and project.render_audio_per_sequence: audio_sequence_template = expand(project.render_audio_sequence_template, **project_templates) audio_render_path = audio_sequence_template.format(**strip_data) render_sound(strip, audio_render_path) if project.render_shot: shot_strips = get_strips(channel='Shots', selected_only=project.render_selected_only) for strip in shot_strips: strip_settings = strip.vsetb_strip_settings strip_data = {**format_data, **strip_settings.format_data} if project.render_video_per_strip: video_strip_template = expand(project.render_video_strip_template, **project_templates) strip_render_path = video_strip_template.format(**strip_data) render_strip(strip, strip_render_path, attributes=render_attrs) if project.render_audio_per_strip: audio_strip_template = expand(project.render_audio_strip_template, **project_templates) audio_render_path = audio_strip_template.format(**strip_data) render_sound(strip, audio_render_path) if not single_file and not sequence_strips and not shot_strips: self.report({"ERROR"}, f'No strips rendered, select sequence or shot strips') return {"CANCELLED"} self.report({"INFO"}, f'Strips rendered in {time.perf_counter()-start_time} seconds') return {"FINISHED"} class VSETB_OT_export_edl(Operator): bl_idname = "vse_toolbox.export_edl" bl_label = "Export Edl" bl_description = "Export Edl" bl_options = {"REGISTER", "UNDO"} #selected_only : BoolProperty(name="Selected Only", default=False) @classmethod def poll(cls, context): settings = get_scene_settings() return settings.active_project def invoke(self, context, event): scn = context.scene settings = get_scene_settings() return context.window_manager.invoke_props_dialog(self) def draw(self, context): scn = context.scene settings = get_scene_settings() layout = self.layout col = layout.column() col.use_property_split = True col.use_property_decorate = False #col.prop(settings, 'channel', text='Channel') #col.prop(self, 'selected_only') col.prop(settings.active_project, "export_edl_template") def execute(self, context): opentimelineio = install_module('opentimelineio') from opentimelineio.schema import (Clip, Timeline, Track, ExternalReference) from opentimelineio.opentime import (RationalTime, TimeRange) start_time = time.perf_counter() scn = context.scene settings = get_scene_settings() fps = scn.render.fps project = settings.active_project format_data = {**settings.format_data, **project.format_data} output_edl = project.export_edl_template.format(**format_data) output_edl = os.path.abspath(bpy.path.abspath(output_edl)) output_edl = Path(output_edl) timeline = Timeline(output_edl.stem) track = Track(f"Track 1") track.kind = "Video" timeline.tracks.append(track) for strip in get_strips(channel='Shots', selected_only=False): strip_data = {**format_data, **strip.vsetb_strip_settings.format_data} strip_render_path = project.render_video_strip_template.format(**strip_data) clip = Clip(Path(strip_render_path).name) clip.metadata.setdefault("cmx_3600", {}) clip.metadata['cmx_3600']['reel'] = strip.name #clip.metadata['cmx_3600']['flags'] = 'IS_CLIP' #clip.media_reference = ExternalReference(f'//render/{strip.name}.mov') #clip.media_reference.name = strip.name #clip.available_range = TimeRange(RationalTime(0, fps), RationalTime(strip.frame_duration, fps)) clip.source_range = TimeRange(RationalTime(strip.frame_offset_start, fps), RationalTime(strip.frame_final_duration, fps)) track.append(clip) output_edl.parent.mkdir(exist_ok=True, parents=True) edl = opentimelineio.adapters.write_to_string(timeline, 'cmx_3600') output_edl.write_text(edl) #opentimelineio.adapters.write_to_file(timeline, str(output_edl), 'cmx_3600') self.report({"INFO"}, f'Edl Exported in {time.perf_counter()-start_time} seconds') return {"FINISHED"} classes = ( VSETB_OT_render, VSETB_OT_export_edl ) def register(): for cls in classes: bpy.utils.register_class(cls) def unregister(): for cls in reversed(classes): bpy.utils.unregister_class(cls)