mirror of
https://github.com/iluvcapra/pycmx.git
synced 2025-12-31 08:50:54 +00:00
retyping some CDL items
This commit is contained in:
31
pycmx/cdl.py
Normal file
31
pycmx/cdl.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# pycmx
|
||||
# (c) 2025 Jamie Hardt
|
||||
|
||||
from typing import Generic, NamedTuple, TypeVar
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
class Rgb(NamedTuple, Generic[T]):
|
||||
red: T
|
||||
green: T
|
||||
blue: T
|
||||
|
||||
|
||||
class AscSopComponents(NamedTuple, Generic[T]):
|
||||
"""
|
||||
Fields in an ASC SOP (Slope-Offset-Power) color transfer function
|
||||
statement
|
||||
"""
|
||||
slope: Rgb[T]
|
||||
offset: Rgb[T]
|
||||
power: Rgb[T]
|
||||
|
||||
|
||||
class FramecountTriple(NamedTuple):
|
||||
"""
|
||||
Fields in an FRMC statement
|
||||
"""
|
||||
start: int
|
||||
end: int
|
||||
duration: int
|
||||
@@ -1,6 +1,7 @@
|
||||
# pycmx
|
||||
# (c) 2018-2025 Jamie Hardt
|
||||
|
||||
from pycmx.cdl import AscSopComponents, FramecountTriple, Rgb
|
||||
from pycmx.statements import StmtCdlSat, StmtCdlSop, StmtFrmc
|
||||
from .transition import Transition
|
||||
from .channel_map import ChannelMap
|
||||
@@ -19,14 +20,14 @@ class Edit:
|
||||
trans_name_statement=None, asc_sop_statement=None,
|
||||
asc_sat_statement=None, frmc_statement=None):
|
||||
|
||||
self.edit_statement = edit_statement
|
||||
self.audio_ext = audio_ext_statement
|
||||
self._edit_statement = edit_statement
|
||||
self._audio_ext = audio_ext_statement
|
||||
self.clip_name_statement = clip_name_statement
|
||||
self.source_file_statement = source_file_statement
|
||||
self.trans_name_statement = trans_name_statement
|
||||
self.asc_sop_statement: Optional[StmtCdlSop] = asc_sop_statement
|
||||
self.asc_sat_statement: Optional[StmtCdlSat] = asc_sat_statement
|
||||
self.frmc_statement: Optional[StmtFrmc] = frmc_statement
|
||||
self._asc_sop_statement: Optional[StmtCdlSop] = asc_sop_statement
|
||||
self._asc_sat_statement: Optional[StmtCdlSat] = asc_sat_statement
|
||||
self._frmc_statement: Optional[StmtFrmc] = frmc_statement
|
||||
|
||||
@property
|
||||
def line_number(self) -> int:
|
||||
@@ -35,7 +36,7 @@ class Edit:
|
||||
this edit. Line numbers a zero-indexed, such that the
|
||||
"TITLE:" record is line zero.
|
||||
"""
|
||||
return self.edit_statement.line_number
|
||||
return self._edit_statement.line_number
|
||||
|
||||
@property
|
||||
def channels(self) -> ChannelMap:
|
||||
@@ -43,9 +44,9 @@ class Edit:
|
||||
Get the :obj:`ChannelMap` object associated with this Edit.
|
||||
"""
|
||||
cm = ChannelMap()
|
||||
cm._append_event(self.edit_statement.channels)
|
||||
if self.audio_ext is not None:
|
||||
cm._append_ext(self.audio_ext)
|
||||
cm._append_event(self._edit_statement.channels)
|
||||
if self._audio_ext is not None:
|
||||
cm._append_ext(self._audio_ext)
|
||||
return cm
|
||||
|
||||
@property
|
||||
@@ -54,19 +55,19 @@ class Edit:
|
||||
Get the :obj:`Transition` object associated with this edit.
|
||||
"""
|
||||
if self.trans_name_statement:
|
||||
return Transition(self.edit_statement.trans,
|
||||
self.edit_statement.trans_op,
|
||||
return Transition(self._edit_statement.trans,
|
||||
self._edit_statement.trans_op,
|
||||
self.trans_name_statement.name)
|
||||
else:
|
||||
return Transition(self.edit_statement.trans,
|
||||
self.edit_statement.trans_op, None)
|
||||
return Transition(self._edit_statement.trans,
|
||||
self._edit_statement.trans_op, None)
|
||||
|
||||
@property
|
||||
def source_in(self) -> str:
|
||||
"""
|
||||
Get the source in timecode.
|
||||
"""
|
||||
return self.edit_statement.source_in
|
||||
return self._edit_statement.source_in
|
||||
|
||||
@property
|
||||
def source_out(self) -> str:
|
||||
@@ -74,7 +75,7 @@ class Edit:
|
||||
Get the source out timecode.
|
||||
"""
|
||||
|
||||
return self.edit_statement.source_out
|
||||
return self._edit_statement.source_out
|
||||
|
||||
@property
|
||||
def record_in(self) -> str:
|
||||
@@ -82,7 +83,7 @@ class Edit:
|
||||
Get the record in timecode.
|
||||
"""
|
||||
|
||||
return self.edit_statement.record_in
|
||||
return self._edit_statement.record_in
|
||||
|
||||
@property
|
||||
def record_out(self) -> str:
|
||||
@@ -90,7 +91,7 @@ class Edit:
|
||||
Get the record out timecode.
|
||||
"""
|
||||
|
||||
return self.edit_statement.record_out
|
||||
return self._edit_statement.record_out
|
||||
|
||||
@property
|
||||
def source(self) -> str:
|
||||
@@ -98,7 +99,7 @@ class Edit:
|
||||
Get the source column. This is the 8, 32 or 128-character string on the
|
||||
event record line, this usually references the tape name of the source.
|
||||
"""
|
||||
return self.edit_statement.source
|
||||
return self._edit_statement.source
|
||||
|
||||
@property
|
||||
def black(self) -> bool:
|
||||
@@ -138,22 +139,40 @@ class Edit:
|
||||
return self.clip_name_statement.name
|
||||
|
||||
@property
|
||||
def asc_sop(self) -> Optional[StmtCdlSop]:
|
||||
def asc_sop(self) -> Optional[AscSopComponents[str]]:
|
||||
"""
|
||||
Get ASC CDL Slope-Offset-Power transfer function for clip, if present
|
||||
"""
|
||||
return self.asc_sop_statement
|
||||
if self._asc_sop_statement is None:
|
||||
return None
|
||||
|
||||
s = self._asc_sop_statement
|
||||
|
||||
return AscSopComponents(
|
||||
slope=Rgb(red=s.slope_r, green=s.slope_g,
|
||||
blue=s.slope_b),
|
||||
offset=Rgb(red=s.offset_r, green=s.offset_g,
|
||||
blue=s.offset_g),
|
||||
power=Rgb(red=s.power_r, green=s.power_g,
|
||||
blue=s.power_b)
|
||||
)
|
||||
|
||||
@property
|
||||
def asc_sat(self) -> Optional[StmtCdlSat]:
|
||||
def asc_sat(self) -> Optional[str]:
|
||||
"""
|
||||
Get ASC CDL saturation value for clip, if present
|
||||
"""
|
||||
return self.asc_sat_statement
|
||||
if self._asc_sat_statement is None:
|
||||
return None
|
||||
|
||||
return self._asc_sat_statement.value
|
||||
|
||||
@property
|
||||
def frmc(self) -> Optional[StmtFrmc]:
|
||||
def frmc(self) -> Optional[FramecountTriple]:
|
||||
"""
|
||||
Get FRMC data
|
||||
"""
|
||||
return self.frmc_statement
|
||||
if not self._frmc_statement:
|
||||
return None
|
||||
|
||||
return FramecountTriple(int())
|
||||
|
||||
@@ -141,8 +141,13 @@ def _parse_remark(line, line_number) -> object:
|
||||
return StmtRemark(line, line_number)
|
||||
|
||||
else:
|
||||
return StmtFrmc(start=match.group(1), end=match.group(2),
|
||||
duration=match.group(3), line_number=line_number)
|
||||
try:
|
||||
return StmtFrmc(start=int(match.group(1)),
|
||||
end=int(match.group(2)),
|
||||
duration=int(match.group(3)),
|
||||
line_number=line_number)
|
||||
except ValueError:
|
||||
return StmtRemark(line, line_number)
|
||||
|
||||
else:
|
||||
return StmtRemark(text=line, line_number=line_number)
|
||||
|
||||
@@ -66,9 +66,9 @@ class StmtCdlSat(NamedTuple):
|
||||
|
||||
|
||||
class StmtFrmc(NamedTuple):
|
||||
start: str
|
||||
end: str
|
||||
duration: str
|
||||
start: int
|
||||
end: int
|
||||
duration: int
|
||||
line_number: int
|
||||
|
||||
|
||||
|
||||
@@ -143,36 +143,36 @@ class TestParse(TestCase):
|
||||
edl = pycmx.parse_cmx3600(f)
|
||||
for event in edl.events:
|
||||
if event.number == 1:
|
||||
sop = event.edits[0].asc_sop_statement
|
||||
sop = event.edits[0].asc_sop
|
||||
self.assertIsNotNone(sop)
|
||||
assert sop
|
||||
self.assertEqual(sop.slope_r, "0.9405")
|
||||
self.assertEqual(sop.offset_g, "-0.0276")
|
||||
self.assertEqual(sop.slope.red, "0.9405")
|
||||
self.assertEqual(sop.offset.green, "-0.0276")
|
||||
|
||||
sat = event.edits[0].asc_sat_statement
|
||||
sat = event.edits[0].asc_sat
|
||||
self.assertIsNotNone(sat)
|
||||
assert sat
|
||||
self.assertEqual(sat.value, '0.9640')
|
||||
self.assertEqual(sat, '0.9640')
|
||||
|
||||
def test_frmc(self):
|
||||
with open("tests/edls/cdl_frmc_example01.edl", "r") as f:
|
||||
edl = pycmx.parse_cmx3600(f)
|
||||
for event in edl.events:
|
||||
if event.number == 1:
|
||||
frmc = event.edits[0].frmc_statement
|
||||
frmc = event.edits[0]._frmc_statement
|
||||
self.assertIsNotNone(frmc)
|
||||
assert frmc
|
||||
self.assertEqual(frmc.start, "1001")
|
||||
self.assertEqual(frmc.end, "1102")
|
||||
self.assertEqual(frmc.duration, "102")
|
||||
self.assertEqual(frmc.start, 1001)
|
||||
self.assertEqual(frmc.end, 1102)
|
||||
self.assertEqual(frmc.duration, 102)
|
||||
|
||||
with open("tests/edls/cdl_frmc_example02.edl", "r") as f:
|
||||
edl = pycmx.parse_cmx3600(f)
|
||||
for event in edl.events:
|
||||
if event.number == 6:
|
||||
frmc = event.edits[0].frmc_statement
|
||||
frmc = event.edits[0]._frmc_statement
|
||||
self.assertIsNotNone(frmc)
|
||||
assert frmc
|
||||
self.assertEqual(frmc.start, "1001")
|
||||
self.assertEqual(frmc.end, "1486")
|
||||
self.assertEqual(frmc.duration, "486")
|
||||
self.assertEqual(frmc.start, 1001)
|
||||
self.assertEqual(frmc.end, 1486)
|
||||
self.assertEqual(frmc.duration, 486)
|
||||
|
||||
Reference in New Issue
Block a user