def test_parse_drop_frame_time_code(self): time_code = SmpteTimeCode.parse("01:02:03;04", FPS_29_97) self.assertEqual(1, time_code.get_hours()) self.assertEqual(2, time_code.get_minutes()) self.assertEqual(3, time_code.get_seconds()) self.assertEqual(4, time_code.get_frames()) self.assertEqual(FPS_29_97, time_code.get_frame_rate()) self.assertTrue(time_code.is_drop_frame()) self.assertEqual(111582, time_code.to_frames()) self.assertEqual(Fraction(111582, Fraction(30000, 1001)), time_code.to_temporal_offset()) self.assertEqual("01:02:03;04", str(time_code)) time_code = SmpteTimeCode.parse("01;02;03;04", FPS_29_97) self.assertEqual(1, time_code.get_hours()) self.assertEqual(2, time_code.get_minutes()) self.assertEqual(3, time_code.get_seconds()) self.assertEqual(4, time_code.get_frames()) self.assertEqual(FPS_29_97, time_code.get_frame_rate()) self.assertTrue(time_code.is_drop_frame()) self.assertEqual(111582, time_code.to_frames()) self.assertEqual(Fraction(111582, Fraction(30000, 1001)), time_code.to_temporal_offset()) self.assertEqual("01:02:03;04", str(time_code)) time_code = SmpteTimeCode.parse("01:02:03;04", FPS_30) self.assertEqual(1, time_code.get_hours()) self.assertEqual(2, time_code.get_minutes()) self.assertEqual(3, time_code.get_seconds()) self.assertEqual(4, time_code.get_frames()) self.assertEqual(FPS_29_97, time_code.get_frame_rate()) self.assertTrue(time_code.is_drop_frame()) self.assertEqual(111582, time_code.to_frames()) self.assertEqual(Fraction(111582, Fraction(30000, 1001)), time_code.to_temporal_offset()) self.assertEqual("01:02:03;04", str(time_code)) time_code = SmpteTimeCode.parse("01:02:03.04", FPS_29_97) self.assertEqual(1, time_code.get_hours()) self.assertEqual(2, time_code.get_minutes()) self.assertEqual(3, time_code.get_seconds()) self.assertEqual(4, time_code.get_frames()) self.assertEqual(FPS_29_97, time_code.get_frame_rate()) self.assertTrue(time_code.is_drop_frame()) self.assertEqual(111582, time_code.to_frames()) self.assertEqual(Fraction(111582, Fraction(30000, 1001)), time_code.to_temporal_offset()) self.assertEqual("01:02:03;04", str(time_code)) time_code = SmpteTimeCode.parse("01.02.03.04", FPS_29_97) self.assertEqual(1, time_code.get_hours()) self.assertEqual(2, time_code.get_minutes()) self.assertEqual(3, time_code.get_seconds()) self.assertEqual(4, time_code.get_frames()) self.assertEqual(FPS_29_97, time_code.get_frame_rate()) self.assertTrue(time_code.is_drop_frame()) self.assertEqual(111582, time_code.to_frames()) self.assertEqual(Fraction(111582, Fraction(30000, 1001)), time_code.to_temporal_offset()) self.assertEqual("01:02:03;04", str(time_code))
def test_to_paragraph(self): caption_paragraph = SccCaptionParagraph() doc = ContentDocument() self.assertRaisesRegex(TypeError, "Element id must be a valid xml:id string", caption_paragraph.to_paragraph, doc) caption_paragraph.set_id("test-id") origin = caption_paragraph.get_origin() self.assertEqual(0, origin.x.value) self.assertEqual(0, origin.y.value) extent = caption_paragraph.get_extent() self.assertEqual(0, extent.width.value) self.assertEqual(0, extent.height.value) paragraph = caption_paragraph.to_paragraph(doc) self.assertEqual("test-id", paragraph.get_id()) self.assertEqual(doc, paragraph.get_doc()) self.assertIsNone(paragraph.get_begin()) self.assertIsNone(paragraph.get_end()) children = list(paragraph) self.assertEqual(0, len(children)) caption_paragraph.set_begin(SmpteTimeCode.parse("00:01:02:03", FPS_30)) caption_paragraph.set_end(SmpteTimeCode.parse("00:02:03:04", FPS_30)) caption_paragraph.set_cursor_at(0) caption_paragraph.new_caption_text() caption_paragraph.append_text("Hello") caption_paragraph.set_cursor_at(1) caption_paragraph.new_caption_text() caption_paragraph.append_text("World") paragraph = caption_paragraph.to_paragraph(doc) self.assertEqual("test-id", paragraph.get_id()) self.assertEqual(doc, paragraph.get_doc()) self.assertEqual(Fraction(1863, 30), paragraph.get_begin()) self.assertEqual(Fraction(3694, 30), paragraph.get_end()) children = list(paragraph) self.assertEqual(3, len(children)) self.assertIsInstance(children[0], Span) self.assertEqual("Hello", list(children[0])[0].get_text()) self.assertIsInstance(children[1], Br) self.assertIsInstance(children[2], Span) self.assertEqual("World", list(children[2])[0].get_text())
def test_irt_requirement_0062_002_modified(self): '''Testing Time Code Out with value media 25 frames upper bound''' with open("src/test/resources/stl/irt/requirement-0062-002_modified.stl", "rb") as f: doc = ttconv.stl.reader.to_model(f) p = doc.get_body().first_child().first_child() self.assertEqual(p.get_end(), SmpteTimeCode.parse("23:59:59:24",FPS_25).to_temporal_offset())
def test_irt_requirement_0061_001(self): '''Testing Time Code In with value media 25 frames lowerbounds''' with open("src/test/resources/stl/irt/requirement-0061-001.stl", "rb") as f: doc = ttconv.stl.reader.to_model(f) p = doc.get_body().first_child().first_child() self.assertEqual(p.get_begin(), SmpteTimeCode.parse("00:00:00:00",FPS_25).to_temporal_offset())
def test_parse_non_drop_frame_time_code(self): time_code = SmpteTimeCode.parse("01:02:03:04", FPS_30) self.assertEqual(1, time_code.get_hours()) self.assertEqual(2, time_code.get_minutes()) self.assertEqual(3, time_code.get_seconds()) self.assertEqual(4, time_code.get_frames()) self.assertEqual(FPS_30, time_code.get_frame_rate()) self.assertFalse(time_code.is_drop_frame()) self.assertEqual(111694, time_code.to_frames()) self.assertAlmostEqual(3723.133, time_code.to_seconds(), delta=0.001) self.assertEqual("01:02:03:04", str(time_code))
def check_caption(self, paragraph: P, caption_id: str, begin: str, end: Optional[str], *children): self.assertEqual(caption_id, paragraph.get_id()) self.assertEqual( SmpteTimeCode.parse(begin, FPS_30).to_temporal_offset(), paragraph.get_begin()) if end is not None: self.assertEqual( SmpteTimeCode.parse(end, FPS_30).to_temporal_offset(), paragraph.get_end()) p_children = list(paragraph) self.assertEqual(len(children), len(p_children)) for (index, child) in enumerate(p_children): expected_child = children[index] if isinstance(expected_child, str): texts = list(child) self.assertEqual(expected_child, texts[0].get_text()) else: self.assertEqual(expected_child, Br)
def test_add_frames(self): time_code = SmpteTimeCode.parse("01:02:03:04", FPS_30) time_code.add_frames(30) self.assertEqual(1, time_code.get_hours()) self.assertEqual(2, time_code.get_minutes()) self.assertEqual(4, time_code.get_seconds()) self.assertEqual(4, time_code.get_frames()) self.assertEqual(FPS_30, time_code.get_frame_rate()) self.assertFalse(time_code.is_drop_frame()) self.assertEqual(111724, time_code.to_frames()) self.assertEqual(Fraction(111724, 30), time_code.to_temporal_offset()) self.assertEqual("01:02:04:04", str(time_code)) time_code = SmpteTimeCode.parse("00:00:59;29", FPS_29_97) time_code.add_frames() self.assertEqual(0, time_code.get_hours()) self.assertEqual(1, time_code.get_minutes()) self.assertEqual(0, time_code.get_seconds()) self.assertEqual(2, time_code.get_frames()) self.assertEqual(FPS_29_97, time_code.get_frame_rate()) self.assertTrue(time_code.is_drop_frame()) self.assertEqual(1_800, time_code.to_frames()) self.assertEqual(Fraction(1800, Fraction(30000, 1001)), time_code.to_temporal_offset()) self.assertEqual("00:01:00;02", str(time_code)) time_code = SmpteTimeCode.parse("00:19:59;29", FPS_29_97) time_code.add_frames() self.assertEqual(0, time_code.get_hours()) self.assertEqual(20, time_code.get_minutes()) self.assertEqual(0, time_code.get_seconds()) self.assertEqual(0, time_code.get_frames()) self.assertEqual(FPS_29_97, time_code.get_frame_rate()) self.assertTrue(time_code.is_drop_frame()) self.assertEqual(35_964, time_code.to_frames()) self.assertEqual(Fraction(35964, Fraction(30000, 1001)), time_code.to_temporal_offset()) self.assertEqual("00:20:00;00", str(time_code))
def from_str(line: str) -> Optional[SccLine]: """Creates a SCC line instance from the specified string""" if not line: return None regex = re.compile(SCC_LINE_PATTERN) match = regex.match(line) if match is None: return None time_code = match.group(1) time_offset = SmpteTimeCode.parse(time_code, FPS_30) hex_words = line.split('\t')[1].split(' ') scc_words = [SccWord.from_str(hex_word) for hex_word in hex_words if hex_word] return SccLine(time_offset, scc_words)
def __init__(self, gsi_block: bytes, disable_fill_line_gap: bool = False, disable_line_padding: bool = False, start_tc: typing.Optional[str] = None, font_stack: typing.Tuple[typing.Union[ str, styles.GenericFontFamilyType]] = None, max_row_count: typing.Optional[typing.Union[int, str]] = None): self.gsi = _GSIBlock._make( struct.unpack( '3s8sc2s2s32s32s32s32s32s32s16s6s6s2s5s5s3s2s2s1s8s8s1s1s3s32s32s32s75x576s', gsi_block)) self.doc = model.ContentDocument() self.doc.set_cell_resolution( model.CellResolutionType( columns=round(100 * DEFAULT_TELETEXT_COLS / (100 - 2 * DEFAULT_HORIZONTAL_SAFE_MARGIN_PCT)), rows=round(100 * DEFAULT_TELETEXT_ROWS / (100 - 2 * DEFAULT_VERTICAL_SAFE_MARGIN_PCT)))) self.doc.set_active_area( model.ActiveAreaType( left_offset=DEFAULT_HORIZONTAL_SAFE_MARGIN_PCT / 100, top_offset=DEFAULT_VERTICAL_SAFE_MARGIN_PCT / 100, width=1 - 2 * DEFAULT_HORIZONTAL_SAFE_MARGIN_PCT / 100, height=1 - 2 * DEFAULT_VERTICAL_SAFE_MARGIN_PCT / 100)) self.body = model.Body(self.doc) if not disable_fill_line_gap: self.body.set_style(styles.StyleProperties.FillLineGap, True) if not disable_line_padding: self.body.set_style( styles.StyleProperties.LinePadding, styles.LengthType(LINE_PADDING_LENGTH_C, styles.LengthType.Units.c)) if font_stack is not None: self.body.set_style(styles.StyleProperties.FontFamily, font_stack) else: self.body.set_style(styles.StyleProperties.FontFamily, DEFAULT_FONT_STACK) self.doc.set_body(self.body) self.sgn_to_div_map = {} self.last_sn = None self.is_in_extension = False self.tti_tf = None self.fps = _DFC_FRACTION_MAP.get(self.gsi.DFC) if self.fps is None: LOGGER.error("Unknown GSI DFC value %s, defaulting to 25 fps", self.gsi.DFC) self.fps = Fraction(25) else: LOGGER.debug("GSI DFC: %s", self.gsi.DFC) self.cct = self.gsi.CCT LOGGER.debug("GSI CCT: %s", self.gsi.CCT) try: self.tti_count = int(self.gsi.TNB) LOGGER.debug("GSI TNB: %s", self.gsi.TNB) except ValueError: LOGGER.error("Invalid TNB field value: %s", self.gsi.TNB) self.tti_count = sys.maxsize self.language = _LC_BCP47_MAP.get(self.gsi.LC) if self.language is None: LOGGER.warning( "Unknown LC value: %s, defaulting to 'unspecified''", self.gsi.LC) self.language = "" else: LOGGER.debug("GSI LC: %s", self.gsi.LC) self.doc.set_lang(self.language) if start_tc is None: self.start_offset = 0 elif start_tc == "TCP": try: self.start_offset = SmpteTimeCode( int(self.gsi.TCP[0:2]), int(self.gsi.TCP[2:4]), int(self.gsi.TCP[4:6]), int(self.gsi.TCP[6:8]), self.get_fps()).to_temporal_offset() LOGGER.debug("GSI TCP: %s", self.gsi.TCP) except ValueError: LOGGER.error("Invalid TCP value: %s", self.gsi.tcp) self.start_offset = 0 else: try: self.start_offset = SmpteTimeCode.parse( start_tc, self.get_fps()).to_temporal_offset() except ValueError: LOGGER.error("Invalid start_tc value") raise if max_row_count is None or self.is_teletext(): self.max_row_count = DEFAULT_TELETEXT_ROWS elif isinstance(max_row_count, str) and max_row_count == "MNR": try: self.max_row_count = int(self.gsi.MNR) LOGGER.debug("GSI MNR: %s", self.gsi.MNR) except ValueError: LOGGER.error("Invalid MNR value: %s", self.gsi.MNR) self.start_offset = DEFAULT_TELETEXT_ROWS else: self.max_row_count = max_row_count # p_element for use across cumulative subtitles self.cur_p_element = None