Merge branch 'master' of https://github.com/iluvcapra/pycmx into feat-adobe

This commit is contained in:
Jamie Hardt
2025-01-05 11:33:57 -08:00
3 changed files with 93 additions and 72 deletions

View File

@@ -20,6 +20,8 @@ class EditList:
""" """
The detected format of the EDL. Possible values are: "3600", "File32", The detected format of the EDL. Possible values are: "3600", "File32",
"File128", and "unknown". "File128", and "unknown".
Adobe EDLs with more than 999 events will be reported as "3600".
""" """
first_event = next( (s for s in self.event_statements if type(s) is StmtEvent), None) first_event = next( (s for s in self.event_statements if type(s) is StmtEvent), None)

View File

@@ -8,11 +8,11 @@ from .edit_list import EditList
from typing import TextIO from typing import TextIO
def parse_cmx3600(f: TextIO): def parse_cmx3600(f: TextIO) -> EditList:
""" """
Parse a CMX 3600 EDL. Parse a CMX 3600 EDL.
:param TextIO f: a file-like object, anything that's readlines-able. :param TextIO f: a file-like object, an opened CMX 3600 .EDL file.
:returns: An :class:`pycmx.edit_list.EditList`. :returns: An :class:`pycmx.edit_list.EditList`.
""" """
statements = parse_cmx3600_statements(f) statements = parse_cmx3600_statements(f)

View File

@@ -2,9 +2,7 @@
# (c) 2018 Jamie Hardt # (c) 2018 Jamie Hardt
import re import re
import sys
from collections import namedtuple from collections import namedtuple
from itertools import count
from typing import TextIO, List from typing import TextIO, List
@@ -12,8 +10,10 @@ from .util import collimate
StmtTitle = namedtuple("Title", ["title", "line_number"]) StmtTitle = namedtuple("Title", ["title", "line_number"])
StmtFCM = namedtuple("FCM", ["drop", "line_number"]) StmtFCM = namedtuple("FCM", ["drop", "line_number"])
StmtEvent = namedtuple("Event",["event","source","channels","trans",\ StmtEvent = namedtuple("Event", ["event", "source", "channels", "trans",
"trans_op","source_in","source_out","record_in","record_out","format","line_number"]) "trans_op", "source_in", "source_out",
"record_in", "record_out", "format",
"line_number"])
StmtAudioExt = namedtuple("AudioExt", ["audio3", "audio4", "line_number"]) StmtAudioExt = namedtuple("AudioExt", ["audio3", "audio4", "line_number"])
StmtClipName = namedtuple("ClipName", ["name", "affect", "line_number"]) StmtClipName = namedtuple("ClipName", ["name", "affect", "line_number"])
StmtSourceFile = namedtuple("SourceFile", ["filename", "line_number"]) StmtSourceFile = namedtuple("SourceFile", ["filename", "line_number"])
@@ -21,7 +21,8 @@ StmtRemark = namedtuple("Remark",["text","line_number"])
StmtEffectsName = namedtuple("EffectsName", ["name", "line_number"]) StmtEffectsName = namedtuple("EffectsName", ["name", "line_number"])
StmtSourceUMID = namedtuple("Source", ["name", "umid", "line_number"]) StmtSourceUMID = namedtuple("Source", ["name", "umid", "line_number"])
StmtSplitEdit = namedtuple("SplitEdit", ["video", "magnitude", "line_number"]) StmtSplitEdit = namedtuple("SplitEdit", ["video", "magnitude", "line_number"])
StmtMotionMemory = namedtuple("MotionMemory",["source","fps"]) # FIXME needs more fields StmtMotionMemory = namedtuple(
"MotionMemory", ["source", "fps"]) # FIXME needs more fields
StmtUnrecognized = namedtuple("Unrecognized", ["content", "line_number"]) StmtUnrecognized = namedtuple("Unrecognized", ["content", "line_number"])
@@ -30,11 +31,11 @@ def parse_cmx3600_statements(file: TextIO) -> List[object]:
Return a list of every statement in the file argument. Return a list of every statement in the file argument.
""" """
lines = file.readlines() lines = file.readlines()
line_numbers = count() return [_parse_cmx3600_line(line.strip(), line_number)
return [_parse_cmx3600_line(line.strip(), line_number) \ for (line_number, line) in enumerate(lines)]
for (line, line_number) in zip(lines,line_numbers)]
def _edl_column_widths(event_field_length, source_field_length):
def _edl_column_widths(event_field_length, source_field_length) -> List[int]:
return [event_field_length, 2, source_field_length, 1, return [event_field_length, 2, source_field_length, 1,
4, 2, # chans 4, 2, # chans
4, 1, # trans 4, 1, # trans
@@ -44,13 +45,19 @@ def _edl_column_widths(event_field_length, source_field_length):
11, 1, 11, 1,
11] 11]
def _edl_m2_column_widths(): # def _edl_m2_column_widths():
return [2, # "M2" # return [2, # "M2"
3,3, # # 3,3, #
8,8,1,4,2,1,4,13,3,1,1] # 8,8,1,4,2,1,4,13,3,1,1]
def _parse_cmx3600_line(line, line_number): def _parse_cmx3600_line(line: str, line_number: int) -> object:
"""
Parses a single CMX EDL line.
:param line: A single EDL line.
:param line_number: The index of this line in the file.
"""
long_event_num_p = re.compile("^[0-9]{6} ") long_event_num_p = re.compile("^[0-9]{6} ")
short_event_num_p = re.compile("^[0-9]{3} ") short_event_num_p = re.compile("^[0-9]{3} ")
x_event_form_p = re.compile("^([0-9]{4,5}) ") x_event_form_p = re.compile("^([0-9]{4,5}) ")
@@ -89,23 +96,28 @@ def _parse_cmx3600_line(line, line_number):
return _parse_unrecognized(line, line_number) return _parse_unrecognized(line, line_number)
def _parse_title(line, line_num): def _parse_title(line, line_num) -> StmtTitle:
title = line[6:].strip() title = line[6:].strip()
return StmtTitle(title=title, line_number=line_num) return StmtTitle(title=title, line_number=line_num)
def _parse_fcm(line, line_num):
def _parse_fcm(line, line_num) -> StmtFCM:
val = line[4:].strip() val = line[4:].strip()
if val == "DROP FRAME": if val == "DROP FRAME":
return StmtFCM(drop=True, line_number=line_num) return StmtFCM(drop=True, line_number=line_num)
else: else:
return StmtFCM(drop=False, line_number=line_num) return StmtFCM(drop=False, line_number=line_num)
def _parse_long_standard_form(line, source_field_length, line_number): def _parse_long_standard_form(line, source_field_length, line_number):
return _parse_columns_for_standard_form(line, 6, source_field_length, line_number) return _parse_columns_for_standard_form(line, 6, source_field_length,
line_number)
def _parse_standard_form(line, line_number): def _parse_standard_form(line, line_number):
return _parse_columns_for_standard_form(line, 3, 8, line_number) return _parse_columns_for_standard_form(line, 3, 8, line_number)
def _parse_extended_audio_channels(line, line_number): def _parse_extended_audio_channels(line, line_number):
content = line.strip() content = line.strip()
if content == "AUD 3": if content == "AUD 3":
@@ -117,20 +129,26 @@ def _parse_extended_audio_channels(line, line_number):
else: else:
return StmtUnrecognized(content=line, line_number=line_number) return StmtUnrecognized(content=line, line_number=line_number)
def _parse_remark(line, line_number) -> object: def _parse_remark(line, line_number) -> object:
if line.startswith("FROM CLIP NAME:"): if line.startswith("FROM CLIP NAME:"):
return StmtClipName(name=line[15:].strip() , affect="from", line_number=line_number) return StmtClipName(name=line[15:].strip(), affect="from",
line_number=line_number)
elif line.startswith("TO CLIP NAME:"): elif line.startswith("TO CLIP NAME:"):
return StmtClipName(name=line[13:].strip(), affect="to", line_number=line_number) return StmtClipName(name=line[13:].strip(), affect="to",
line_number=line_number)
elif line.startswith("SOURCE FILE:"): elif line.startswith("SOURCE FILE:"):
return StmtSourceFile(filename=line[12:].strip() , line_number=line_number) return StmtSourceFile(filename=line[12:].strip(),
line_number=line_number)
else: else:
return StmtRemark(text=line, line_number=line_number) return StmtRemark(text=line, line_number=line_number)
def _parse_effects_name(line, line_number) -> StmtEffectsName: def _parse_effects_name(line, line_number) -> StmtEffectsName:
name = line[16:].strip() name = line[16:].strip()
return StmtEffectsName(name=name, line_number=line_number) return StmtEffectsName(name=name, line_number=line_number)
def _parse_split(line, line_number): def _parse_split(line, line_number):
split_type = line[10:21] split_type = line[10:21]
is_video = False is_video = False
@@ -138,7 +156,8 @@ def _parse_split(line, line_number):
is_video = True is_video = True
split_mag = line[24:35] split_mag = line[24:35]
return StmtSplitEdit(video=is_video, magnitude=split_mag, line_number=line_number) return StmtSplitEdit(video=is_video, magnitude=split_mag,
line_number=line_number)
def _parse_motion_memory(line, line_number): def _parse_motion_memory(line, line_number):
@@ -148,7 +167,9 @@ def _parse_motion_memory(line, line_number):
def _parse_unrecognized(line, line_number): def _parse_unrecognized(line, line_number):
return StmtUnrecognized(content=line, line_number=line_number) return StmtUnrecognized(content=line, line_number=line_number)
def _parse_columns_for_standard_form(line, event_field_length, source_field_length, line_number):
def _parse_columns_for_standard_form(line, event_field_length,
source_field_length, line_number):
col_widths = _edl_column_widths(event_field_length, source_field_length) col_widths = _edl_column_widths(event_field_length, source_field_length)
if sum(col_widths) > len(line): if sum(col_widths) > len(line):
@@ -165,11 +186,9 @@ def _parse_columns_for_standard_form(line, event_field_length, source_field_leng
source_out=column_strings[12].strip(), source_out=column_strings[12].strip(),
record_in=column_strings[14].strip(), record_in=column_strings[14].strip(),
record_out=column_strings[16].strip(), record_out=column_strings[16].strip(),
line_number=line_number, line_number=line_number, format=source_field_length)
format=source_field_length)
def _parse_source_umid_statement(line, line_number): def _parse_source_umid_statement(line, line_number):
trimmed = line[3:].strip() trimmed = line[3:].strip()
return StmtSourceUMID(name=None, umid=None, line_number=line_number) return StmtSourceUMID(name=None, umid=None, line_number=line_number)