Skip to content

Commit 69a59ee

Browse files
authored
imsc reader: tolerate bad time-clock frames values
#446
1 parent 0755cd9 commit 69a59ee

File tree

3 files changed

+19
-21
lines changed

3 files changed

+19
-21
lines changed

src/main/python/ttconv/imsc/attributes.py

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -431,13 +431,9 @@ def extract(context: TemporalAttributeParsingContext, xml_element) -> typing.Opt
431431
begin_raw = xml_element.attrib.get(BeginAttribute.qn)
432432

433433
try:
434-
435-
return utils.parse_time_expression(context.tick_rate, context.frame_rate, begin_raw) if begin_raw is not None else None
436-
434+
return utils.parse_time_expression(context.tick_rate, context.frame_rate, begin_raw, False) if begin_raw is not None else None
437435
except ValueError:
438-
439-
LOGGER.error("bad begin value")
440-
436+
LOGGER.error("Bad begin attribute value: %s", begin_raw)
441437
return None
442438

443439
@staticmethod
@@ -458,13 +454,9 @@ def extract(context: TemporalAttributeParsingContext, xml_element) -> typing.Opt
458454
end_raw = xml_element.attrib.get(EndAttribute.qn)
459455

460456
try:
461-
462-
return utils.parse_time_expression(context.tick_rate, context.frame_rate, end_raw) if end_raw is not None else None
463-
457+
return utils.parse_time_expression(context.tick_rate, context.frame_rate, end_raw, False) if end_raw is not None else None
464458
except ValueError:
465-
466-
LOGGER.error("bad end value")
467-
459+
LOGGER.error("Bad end attribute value: %s", end_raw)
468460
return None
469461

470462
@staticmethod
@@ -483,13 +475,9 @@ def extract(context: TemporalAttributeParsingContext, xml_element) -> typing.Opt
483475
dur_raw = xml_element.attrib.get(DurAttribute.qn)
484476

485477
try:
486-
487-
return utils.parse_time_expression(context.tick_rate, context.frame_rate, dur_raw) if dur_raw is not None else None
488-
478+
return utils.parse_time_expression(context.tick_rate, context.frame_rate, dur_raw, False) if dur_raw is not None else None
489479
except ValueError:
490-
491-
LOGGER.error("bad dur value")
492-
480+
LOGGER.error("Bad dur attribute value: %s", dur_raw)
493481
return None
494482

495483
@staticmethod

src/main/python/ttconv/imsc/utils.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@
2525

2626
'''IMSC style properties'''
2727

28+
import logging
2829
import re
2930
import typing
3031
from fractions import Fraction
3132
import ttconv.style_properties as styles
3233

34+
LOGGER = logging.getLogger(__name__)
35+
3336
_LENGTH_RE = re.compile(r"^((?:\+|\-)?\d*(?:\.\d+)?)(px|em|c|%|rh|rw)$")
3437

3538
_CLOCK_TIME_FRACTION_RE = re.compile(r"^(\d{2,}):(\d\d):(\d\d(?:\.\d+)?)$")
@@ -104,7 +107,7 @@ def _serialize_one_family(family):
104107
return ", ".join(map(_serialize_one_family, font_family))
105108

106109

107-
def parse_time_expression(tick_rate: typing.Optional[int], frame_rate: typing.Optional[Fraction], time_expr: str) -> Fraction:
110+
def parse_time_expression(tick_rate: typing.Optional[int], frame_rate: typing.Optional[Fraction], time_expr: str, strict: bool = True) -> Fraction:
108111
'''Parse a TTML time expression in a fractional number in seconds
109112
'''
110113

@@ -144,14 +147,18 @@ def parse_time_expression(tick_rate: typing.Optional[int], frame_rate: typing.Op
144147
return Fraction(m.group(1)) * 3600 + \
145148
Fraction(m.group(2)) * 60 + \
146149
Fraction(m.group(3))
147-
150+
148151
m = _CLOCK_TIME_FRAMES_RE.match(time_expr)
149152

150153
if m and frame_rate is not None:
151154
frames = Fraction(m.group(4)) if m.group(4) else 0
152155

153156
if frames >= frame_rate:
154-
raise ValueError("Frame cound exceeds frame rate")
157+
if strict:
158+
raise ValueError("Frame count exceeds frame rate")
159+
else:
160+
LOGGER.error("Frame count %s exceeds frame rate %s, rounding to frame rate minus 1", frames, frame_rate)
161+
frames = round(frame_rate) - 1
155162

156163
return Fraction(m.group(1)) * 3600 + \
157164
Fraction(m.group(2)) * 60 + \

src/test/python/test_imsc_time_expressions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ def test_bad_frame_count(self):
5959
with self.assertRaises(ValueError):
6060
parse_time_expression(None, 24, "100:00:00:100")
6161

62+
def test_bad_frame_count_non_strict(self):
63+
self.assertEqual(parse_time_expression(None, 24, "100:00:00:100", False), 360000 + 23/24)
64+
6265
def test_bad_syntax(self):
6366
with self.assertRaises(ValueError):
6467
parse_time_expression(60, 24, "100:00:00;01")

0 commit comments

Comments
 (0)