Skip to content

Commit bb2bf7d

Browse files
committed
Fix fcp11 warnings/errors
Closes: 741
1 parent 8a03d0e commit bb2bf7d

File tree

2 files changed

+48
-4
lines changed

2 files changed

+48
-4
lines changed

auto_editor/exports/fcp11.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,35 @@ def make_name(src: FileInfo, tb: Fraction) -> str:
4545
return "FFVideoFormatRateUndefined"
4646

4747

48+
def parseSMPTE(val: str, fps: Fraction, log: Log) -> int:
49+
if len(val) == 0:
50+
return 0
51+
try:
52+
parts = val.split(":")
53+
if len(parts) != 4:
54+
raise ValueError(f"Invalid SMPTE format: {val}")
55+
56+
hours, minutes, seconds, frames = map(int, parts)
57+
58+
if (
59+
hours < 0
60+
or minutes < 0
61+
or minutes >= 60
62+
or seconds < 0
63+
or seconds >= 60
64+
or frames < 0
65+
):
66+
raise ValueError(f"Invalid SMPTE values: {val}")
67+
68+
if frames >= fps:
69+
raise ValueError(f"Frame count {frames} exceeds fps {fps}")
70+
71+
total_frames = (hours * 3600 + minutes * 60 + seconds) * fps + frames
72+
return int(round(total_frames))
73+
except (ValueError, ZeroDivisionError) as e:
74+
log.error(f"Cannot parse SMPTE timecode '{val}': {e}")
75+
76+
4877
def fcp11_write_xml(
4978
group_name: str, version: int, output: str, resolve: bool, tl: v3, log: Log
5079
) -> None:
@@ -83,12 +112,14 @@ def fraction(val: int) -> str:
83112
height=f"{tl.res[1]}",
84113
colorSpace=get_colorspace(one_src),
85114
)
115+
116+
startPoint = parseSMPTE(one_src.timecode, tl.tb, log)
86117
r2 = SubElement(
87118
resources,
88119
"asset",
89120
id=f"r{i * 2 + 2}",
90121
name=one_src.path.stem,
91-
start="0s",
122+
start=fraction(startPoint),
92123
hasVideo="1" if one_src.videos else "0",
93124
format=f"r{i * 2 + 1}",
94125
hasAudio="1" if one_src.audios else "0",
@@ -115,12 +146,14 @@ def fraction(val: int) -> str:
115146
spine = SubElement(sequence, "spine")
116147

117148
def make_clip(ref: str, clip: Clip) -> None:
149+
startPoint = parseSMPTE(clip.src.timecode, tl.tb, log)
150+
118151
clip_properties = {
119152
"name": proj_name,
120153
"ref": ref,
121-
"offset": fraction(clip.start),
154+
"offset": fraction(clip.start + startPoint),
122155
"duration": fraction(clip.dur),
123-
"start": fraction(clip.offset),
156+
"start": fraction(clip.offset + startPoint),
124157
"tcFormat": "NDF",
125158
}
126159
asset = SubElement(spine, "asset-clip", clip_properties)

auto_editor/ffwrapper.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class FileInfo:
6666
path: Path
6767
bitrate: int
6868
duration: float
69+
timecode: str # in SMPTE
6970
videos: tuple[VideoStream, ...]
7071
audios: tuple[AudioStream, ...]
7172
subtitles: tuple[SubtitleStream, ...]
@@ -165,12 +166,22 @@ def init(self, path: str, log: Log) -> FileInfo:
165166
ext = sub_exts.get(codec, "vtt")
166167
subtitles += (SubtitleStream(codec, ext, s.language),)
167168

169+
def get_timecode() -> str:
170+
for d in cont.streams.data:
171+
if (result := d.metadata.get("timecode")) is not None:
172+
return result
173+
for v in cont.streams.video:
174+
if (result := v.metadata.get("timecode")) is not None:
175+
return result
176+
return "00:00:00:00"
177+
178+
timecode = get_timecode()
168179
bitrate = 0 if cont.bit_rate is None else cont.bit_rate
169180
dur = 0 if cont.duration is None else cont.duration / bv.time_base
170181

171182
cont.close()
172183

173-
return FileInfo(Path(path), bitrate, dur, videos, audios, subtitles)
184+
return FileInfo(Path(path), bitrate, dur, timecode, videos, audios, subtitles)
174185

175186
def __repr__(self) -> str:
176187
return f"@{self.path.name}"

0 commit comments

Comments
 (0)