Skip to content

Commit

Permalink
Decouple timeline logic in fcp11 code
Browse files Browse the repository at this point in the history
  • Loading branch information
WyattBlue committed Sep 16, 2024
1 parent 6c04013 commit 9a37368
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 47 deletions.
8 changes: 7 additions & 1 deletion auto_editor/edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,13 @@ def edit_media(paths: list[str], ffmpeg: FFmpeg, args: Args, log: Log) -> None:
from auto_editor.formats.fcp11 import fcp11_write_xml

is_resolve = export.startswith("resolve")
fcp11_write_xml(export_ops["name"], ffmpeg, output, is_resolve, tl, log)

if is_resolve:
from auto_editor.timeline import set_stream_to_0

set_stream_to_0(tl, ffmpeg, log)

fcp11_write_xml(export_ops["name"], output, is_resolve, tl, log)
return

if export == "shotcut":
Expand Down
44 changes: 17 additions & 27 deletions auto_editor/formats/fcp11.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@
from typing import TYPE_CHECKING, Any, cast
from xml.etree.ElementTree import Element, ElementTree, SubElement, indent

from auto_editor.ffwrapper import FFmpeg, FileInfo, initFileInfo

from .utils import make_tracks_dir

if TYPE_CHECKING:
from collections.abc import Sequence
from fractions import Fraction

from auto_editor.ffwrapper import FileInfo
from auto_editor.timeline import TlAudio, TlVideo, v3
from auto_editor.utils.log import Log


"""
Export a FCPXML 11 file readable with Final Cut Pro 10.6.8 or later.
Expand Down Expand Up @@ -54,7 +52,7 @@ def make_name(src: FileInfo, tb: Fraction) -> str:


def fcp11_write_xml(
group_name: str, ffmpeg: FFmpeg, output: str, resolve: bool, tl: v3, log: Log
group_name: str, output: str, resolve: bool, tl: v3, log: Log
) -> None:
def fraction(val: int) -> str:
if val == 0:
Expand All @@ -68,23 +66,10 @@ def fraction(val: int) -> str:
src_dur = int(src.duration * tl.tb)
tl_dur = src_dur if resolve else tl.out_len()

all_srcs: list[FileInfo] = [src]
all_refs: list[str] = ["r2"]
if resolve and len(src.audios) > 1:
fold = make_tracks_dir(src)

for i in range(1, len(src.audios)):
newtrack = fold / f"{i}.wav"
ffmpeg.run(
["-i", f"{src.path.resolve()}", "-map", f"0:a:{i}", f"{newtrack}"]
)
all_srcs.append(initFileInfo(f"{newtrack}", log))
all_refs.append(f"r{(i + 1) * 2}")

fcpxml = Element("fcpxml", version="1.10" if resolve else "1.11")
resources = SubElement(fcpxml, "resources")

for i, one_src in enumerate(all_srcs):
for i, one_src in enumerate(tl.unique_sources()):
SubElement(
resources,
"format",
Expand Down Expand Up @@ -126,13 +111,6 @@ def fraction(val: int) -> str:
)
spine = SubElement(sequence, "spine")

if tl.v and tl.v[0]:
clips: Sequence[TlVideo | TlAudio] = cast(Any, tl.v[0])
elif tl.a and tl.a[0]:
clips = tl.a[0]
else:
clips = []

def make_clip(ref: str, clip: TlVideo | TlAudio) -> None:
clip_properties = {
"name": proj_name,
Expand All @@ -157,7 +135,19 @@ def make_clip(ref: str, clip: TlVideo | TlAudio) -> None:
interp="smooth2",
)

for my_ref in all_refs:
if tl.v and tl.v[0]:
clips: Sequence[TlVideo | TlAudio] = cast(Any, tl.v[0])
elif tl.a and tl.a[0]:
clips = tl.a[0]
else:
clips = []

all_refs: list[str] = ["r2"]
if resolve:
for i in range(1, len(tl.a)):
all_refs.append(f"r{(i + 1) * 2}")

for my_ref in reversed(all_refs):
for clip in clips:
make_clip(my_ref, clip)

Expand Down
18 changes: 0 additions & 18 deletions auto_editor/formats/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
from xml.etree.ElementTree import Element

if TYPE_CHECKING:
from pathlib import Path

from auto_editor.ffwrapper import FileInfo
from auto_editor.utils.log import Log


Expand All @@ -19,21 +16,6 @@ def show(ele: Element, limit: int, depth: int = 0) -> None:
show(child, limit, depth + 1)


def make_tracks_dir(src: FileInfo) -> Path:
from os import mkdir
from shutil import rmtree

fold = src.path.parent / f"{src.path.stem}_tracks"

try:
mkdir(fold)
except OSError:
rmtree(fold)
mkdir(fold)

return fold


class Validator:
def __init__(self, log: Log):
self.log = log
Expand Down
47 changes: 46 additions & 1 deletion auto_editor/timeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@
from dataclasses import dataclass
from typing import TYPE_CHECKING

from auto_editor.ffwrapper import initFileInfo
from auto_editor.lib.contracts import *
from auto_editor.utils.cmdkw import Required, pAttr, pAttrs
from auto_editor.utils.types import color, natural, number, threshold

if TYPE_CHECKING:
from collections.abc import Iterator
from fractions import Fraction
from pathlib import Path
from typing import Any

from auto_editor.ffwrapper import FileInfo
from auto_editor.ffwrapper import FFmpeg, FileInfo
from auto_editor.utils.chunks import Chunks
from auto_editor.utils.log import Log


@dataclass(slots=True)
Expand Down Expand Up @@ -241,6 +244,13 @@ def sources(self) -> Iterator[FileInfo]:
for a in aclips:
yield a.src

def unique_sources(self) -> Iterator[FileInfo]:
seen = set()
for source in self.sources:
if source.path not in seen:
seen.add(source.path)
yield source

def _duration(self, layer: Any) -> int:
total_dur = 0
for clips in layer:
Expand Down Expand Up @@ -276,3 +286,38 @@ def as_dict(self) -> dict:
"v": v,
"a": a,
}


def make_tracks_dir(path: Path) -> Path:
from os import mkdir
from shutil import rmtree

tracks_dir = path.parent / f"{path.stem}_tracks"

try:
mkdir(tracks_dir)
except OSError:
rmtree(tracks_dir)
mkdir(tracks_dir)

return tracks_dir


def set_stream_to_0(tl: v3, ffmpeg: FFmpeg, log: Log) -> None:
src = tl.src
assert src is not None
fold = make_tracks_dir(src.path)
cache: dict[Path, FileInfo] = {}

def make_track(i: int, path: Path) -> FileInfo:
newtrack = fold / f"{path.stem}_{i}.wav"
if newtrack not in cache:
ffmpeg.run(["-i", f"{path}", "-map", f"0:a:{i}", f"{newtrack}"])
cache[newtrack] = initFileInfo(f"{newtrack}", log)
return cache[newtrack]

for alayer in tl.a:
for aobj in alayer:
if aobj.stream > 0:
aobj.src = make_track(aobj.stream, aobj.src.path)
aobj.stream = 0

0 comments on commit 9a37368

Please sign in to comment.