Source code for cgl.plugins.otio.tools.extract_shots

import re
from collections import OrderedDict

import opentimelineio as otio
from cgl.plugins.otio.tools.fcp import fcp_extract_shots
from cgl.plugins.otio.tools.aaf import aaf_extract_shots


SEQUENCE_NAME_FMT = r"(?P<sequence>[0-9]{1,3}[a-zA-Z]{0,3})"
SHOT_NUMBER_FMT = r"(?P<shot>[0-9]{4})"

SHOT_NAME_FMT = SEQUENCE_NAME_FMT + "_" + SHOT_NUMBER_FMT

HANDLES = 0


[docs] def clean_seq_name(name): name = name.split(":")[0] FMT = r"(?P<number>[0-9]{1,3})(?P<letters>[a-zA-Z]{0,3})" m = re.fullmatch(FMT, name) d = m.groupdict() clean_name = "%02d" % int(d["number"]) clean_name += d.get("letters", "") return clean_name
[docs] def parse_shot_name(name): # print(name) name = name.split(":")[0] m = re.fullmatch(SHOT_NAME_FMT, name) if m: return clean_seq_name(m.group("sequence")), m.group("shot") m = re.fullmatch(SHOT_NUMBER_FMT, name) if m: return None, m.group("shot") m = re.fullmatch(SEQUENCE_NAME_FMT, name) if m: return clean_seq_name(m.group("sequence")), None return None, None
[docs] def parse_sequence_name(name): m = re.search(SEQUENCE_NAME_FMT, name) if m: return clean_seq_name(m.group("sequence")) return None
[docs] def clean_name(name): sequence, shot = parse_shot_name(name) if sequence and shot: return f"{sequence}_{shot}" else: return None
[docs] def get_target_url(clip): if not isinstance(clip, otio.schema.Clip): return None media_ref = clip.media_reference if media_ref and isinstance(media_ref, otio.schema.ExternalReference): return media_ref.target_url
[docs] def is_aaf(path): if path.lower().endswith(".aaf"): return True return False
[docs] def simplify_timeline(source_path): if is_aaf(source_path): timeline, shot_dict = aaf_extract_shots.simplify_timeline(source_path) print(1, shot_dict) result = {} for shot_name, item in shot_dict.items(): if shot_name: clean_name = shot_name.split(":")[0] result[clean_name] = aaf_extract_shots.get_item_timings(item) return timeline, result else: # working with fcp from premiere print(source_path) return fcp_extract_shots.simplify_timeline(source_path)
[docs] def generate_simplified_otio(source_path, otio_path): print(source_path) timeline, shot_dict = simplify_timeline(source_path) if not shot_dict: raise ValueError( f"Unable to find shots in timeline.\n" + f"Nested sequence labels color might not be set to: SHOT_LABEL_COLOR\n" + f"Shots might not be following naming convention" ) print(f"{timeline.name}") for shot_name, source_media in shot_dict.items(): print(f" {shot_name}") for target_url, start_frame, abs_frame, duration in source_media: print(f" {target_url} {start_frame} {abs_frame} {duration}") otio.adapters.write_to_file(timeline, otio_path) return shot_dict
[docs] def extract_shot_edit_dict(source_path): timeline, shot_dict = fcp_extract_shots.simplify_timeline(source_path) global_start = timeline.global_start_time.to_frames() shot_edit_dict = OrderedDict() cut_order = 0 for track in timeline.video_tracks(): for item in track: source_data = shot_dict.get(item.name, None) if not source_data: continue range_in_parent = item.range_in_parent() cut_in = range_in_parent.start_time.to_frames() + global_start cut_duration = range_in_parent.duration.to_frames() cut_out = cut_in + cut_duration head_in = item.source_range.start_time.to_frames() tail_out = head_in + range_in_parent.duration.to_frames() working_duration = item.available_range().duration.to_frames() sg = {} sg["in"] = cut_in sg["out"] = cut_out sg["duration"] = cut_duration sg["head_in"] = head_in sg["tail_out"] = tail_out sg["working_duration"] = working_duration sg["cut_order"] = cut_order sg["source_data"] = {} for sd in source_data: print(sd) filename, start_frame, abs_frame, duration = sd if filename.startswith("/"): filename = filename[1:] source_dict = { "filename": filename, "start_frame": start_frame, "abs_frame": abs_frame, "duration": duration, } sg["source_data"][filename] = source_dict cut_order += 1 shot_edit_dict[item.name] = sg # pprint(shot_edit_dict) return shot_edit_dict
if __name__ == '__main__': source_path = r"Z:\Alchemy\jhcs\ttas\VERSIONS\0\000\source\shots\103\s01\SEQ\edt\default\tmakota\000.000\high\MDC_103_MonsterOpposites_RC_251021.xml" dict_ = extract_shot_edit_dict(source_path) print(dict_.keys()) if __name__ == "__main__": xml_path = r"E:\Alchemy\jhcs\ttas\VERSIONS\0\000\render\shots\103\s01\SEQ\edt\default\tom\000.000\high\mdc_103.xml" print(extract_shot_edit_dict(xml_path))