def test_scc_mid_row_codes_valid_italics(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[28]), SccMidRowCode.ITALICS, None, FontStyleType.italic, None) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[29]), SccMidRowCode.ITALICS, None, FontStyleType.italic, None)
def test_scc_mid_row_codes_valid_magenta(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[24]), SccMidRowCode.MAGENTA, NamedColors.magenta.value, None, None) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[25]), SccMidRowCode.MAGENTA, NamedColors.magenta.value, None, None)
def test_scc_mid_row_codes_valid_white(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[0]), SccMidRowCode.WHITE, NamedColors.white.value, None, None) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[1]), SccMidRowCode.WHITE, NamedColors.white.value, None, None)
def test_scc_mid_row_codes_valid_yellow(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[20]), SccMidRowCode.YELLOW, NamedColors.yellow.value, None, None) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[21]), SccMidRowCode.YELLOW, NamedColors.yellow.value, None, None)
def test_scc_mid_row_codes_valid_cyan(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[12]), SccMidRowCode.CYAN, NamedColors.cyan.value, None, None) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[13]), SccMidRowCode.CYAN, NamedColors.cyan.value, None, None)
def test_scc_mid_row_codes_valid_red(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[16]), SccMidRowCode.RED, NamedColors.red.value, None, None) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[17]), SccMidRowCode.RED, NamedColors.red.value, None, None)
def test_scc_mid_row_codes_valid_green(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[4]), SccMidRowCode.GREEN, NamedColors.green.value, None, None) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[5]), SccMidRowCode.GREEN, NamedColors.green.value, None, None)
def test_scc_mid_row_codes_valid_blue(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[8]), SccMidRowCode.BLUE, NamedColors.blue.value, None, None) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[9]), SccMidRowCode.BLUE, NamedColors.blue.value, None, None)
def process_mid_row_code(self, mid_row_code: SccMidRowCode, time_code: SmpteTimeCode): """Processes SCC Mid-Row Code to map it to the model""" # If the Paint-On or Roll-Up style is activated, write directly on active caption processed_caption = self.buffered_caption if self.current_style in (SccCaptionStyle.PaintOn, SccCaptionStyle.RollUp): processed_caption = self.active_caption if processed_caption is None: raise ValueError("No current SCC caption initialized") if processed_caption.get_current_text() is not None \ and processed_caption.get_current_text().get_text() \ and not processed_caption.get_current_text().get_text().isspace(): processed_caption.new_caption_text() processed_caption.get_current_text().add_style_property( StyleProperties.Color, mid_row_code.get_color()) processed_caption.get_current_text().add_style_property( StyleProperties.FontStyle, mid_row_code.get_font_style()) processed_caption.get_current_text().add_style_property( StyleProperties.TextDecoration, mid_row_code.get_text_decoration()) # The cursor moves one column to the right after each Mid-Row Code processed_caption.append_text(" ") if processed_caption.get_caption_style() is SccCaptionStyle.PaintOn: processed_caption.get_current_text().set_begin(time_code)
def test_scc_mid_row_codes_valid_yellow_underline(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[22]), SccMidRowCode.YELLOW_UNDERLINE, NamedColors.yellow.value, None, TextDecorationType(underline=True)) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[23]), SccMidRowCode.YELLOW_UNDERLINE, NamedColors.yellow.value, None, TextDecorationType(underline=True))
def test_scc_mid_row_codes_valid_cyan_underline(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[14]), SccMidRowCode.CYAN_UNDERLINE, NamedColors.cyan.value, None, TextDecorationType(underline=True)) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[15]), SccMidRowCode.CYAN_UNDERLINE, NamedColors.cyan.value, None, TextDecorationType(underline=True))
def test_scc_mid_row_codes_valid_italics_underline(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[30]), SccMidRowCode.ITALICS_UNDERLINE, None, FontStyleType.italic, TextDecorationType(underline=True)) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[31]), SccMidRowCode.ITALICS_UNDERLINE, None, FontStyleType.italic, TextDecorationType(underline=True))
def test_scc_mid_row_codes_valid_magenta_underline(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[26]), SccMidRowCode.MAGENTA_UNDERLINE, NamedColors.magenta.value, None, TextDecorationType(underline=True)) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[27]), SccMidRowCode.MAGENTA_UNDERLINE, NamedColors.magenta.value, None, TextDecorationType(underline=True))
def test_scc_mid_row_codes_valid_blue_underline(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[10]), SccMidRowCode.BLUE_UNDERLINE, NamedColors.blue.value, None, TextDecorationType(underline=True)) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[11]), SccMidRowCode.BLUE_UNDERLINE, NamedColors.blue.value, None, TextDecorationType(underline=True))
def process_mid_row_code(self, mid_row_code: SccMidRowCode, time_code: SmpteTimeCode): """Processes SCC Mid-Row Code to map it to the model""" # If the Paint-On or Roll-Up style is activated, write directly on active caption processed_caption = self.buffered_caption if self.current_style in (SccCaptionStyle.PaintOn, SccCaptionStyle.RollUp): processed_caption = self.active_caption if processed_caption is None: raise ValueError("No current SCC caption initialized") color = mid_row_code.get_color() font_style = mid_row_code.get_font_style() text_decoration = mid_row_code.get_text_decoration() if self.previous_code_type is not SccMidRowCode: # In case of multiple mid-row codes, move right only after the first code # If there is already text on the current line if processed_caption.get_current_text() is not None \ and processed_caption.get_current_text().get_text() != "": # In case of paint-on replacing text if self.current_style is SccCaptionStyle.PaintOn \ and processed_caption.get_current_line().get_cursor() < processed_caption.get_current_line().get_length(): processed_caption.append_text(" ") else: if text_decoration is None: processed_caption.new_caption_text() processed_caption.append_text(" ") else: processed_caption.append_text(" ") processed_caption.new_caption_text() else: processed_caption.append_text(" ") self.current_color = color self.current_font_style = font_style self.current_text_decoration = text_decoration else: if color is not None: self.current_color = color if font_style is not None: self.current_font_style = font_style if text_decoration is not None: self.current_text_decoration = text_decoration processed_caption.append_text(" ") processed_caption.new_caption_text() if processed_caption.get_caption_style() is SccCaptionStyle.PaintOn: processed_caption.get_current_text().set_begin(time_code)
def test_scc_mid_row_codes_valid_green_underline(self): self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[6]), SccMidRowCode.GREEN_UNDERLINE, NamedColors.green.value, None, TextDecorationType(underline=True)) self.check_mid_row_code(SccMidRowCode.find(MID_ROW_CODE_VALUES[7]), SccMidRowCode.GREEN_UNDERLINE, NamedColors.green.value, None, TextDecorationType(underline=True))
def to_disassembly(self) -> str: """Converts SCC line into the disassembly format""" disassembly_line = str(self.time_code) + "\t" for scc_word in self.scc_words: if scc_word.value == 0x0000: disassembly_line += "{}" continue if scc_word.byte_1 < 0x20: attribute_code = SccAttributeCode.find(scc_word.value) control_code = SccControlCode.find(scc_word.value) mid_row_code = SccMidRowCode.find(scc_word.value) pac = SccPreambleAddressCode.find(scc_word.byte_1, scc_word.byte_2) spec_char = SccSpecialAndExtendedCharacter.find(scc_word.value) if pac is not None: disassembly_line += f"{{{pac.get_row():02}" color = pac.get_color() indent = pac.get_indent() if indent is not None and indent > 0: disassembly_line += f"{indent :02}" elif color is not None: disassembly_line += get_color_disassembly(color) disassembly_line += get_font_style_disassembly(pac.get_font_style()) disassembly_line += get_text_decoration_disassembly(pac.get_text_decoration()) else: disassembly_line += "00" disassembly_line += "}" elif attribute_code is not None: disassembly_line += "{" disassembly_line += "B" if attribute_code.is_background() else "" disassembly_line += get_color_disassembly(attribute_code.get_color()) disassembly_line += get_text_decoration_disassembly(attribute_code.get_text_decoration()) disassembly_line += "}" elif mid_row_code is not None: disassembly_line += "{" disassembly_line += get_color_disassembly(mid_row_code.get_color()) disassembly_line += get_font_style_disassembly(mid_row_code.get_font_style()) disassembly_line += get_text_decoration_disassembly(mid_row_code.get_text_decoration()) disassembly_line += "}" elif control_code is not None: disassembly_line += "{" + control_code.get_name() + "}" elif spec_char is not None: disassembly_line += spec_char.get_unicode_value() else: disassembly_line += "{??}" LOGGER.warning("Unsupported SCC word: %s", hex(scc_word.value)) else: disassembly_line += scc_word.to_text() return disassembly_line
def test_scc_mid_row_codes_invalid(self): other_code_values = [ code for code in range(0x0000, 0xFFFF) if code not in MID_ROW_CODE_VALUES ] for mrc in other_code_values: self.assertIsNone(SccMidRowCode.find(mrc))
def process_line(self, line: SccLine) -> SmpteTimeCode: """Converts the SCC line to the data model""" debug = str(line.time_code) + "\t" for scc_word in line.scc_words: if self.previous_code == scc_word.value: continue line.time_code.add_frames() if scc_word.value == 0x0000: continue if scc_word.byte_1 < 0x20: control_code = SccControlCode.find(scc_word.value) if control_code is not None \ and control_code is SccControlCode.find(self.previous_code): # Skip duplicated control code from 'Field 2' line.time_code.add_frames(-1) continue attribute_code = SccAttributeCode.find(scc_word.value) mid_row_code = SccMidRowCode.find(scc_word.value) pac = SccPreambleAddressCode.find(scc_word.byte_1, scc_word.byte_2) spec_char = SccSpecialCharacter.find(scc_word.value) extended_char = SccExtendedCharacter.find(scc_word.value) if pac is not None: debug += "[PAC|" + str(pac.get_row()) + "|" + str( pac.get_indent()) if pac.get_color() is not None: debug += "|" + str(pac.get_color()) if pac.get_font_style() is not None: debug += "|I" if pac.get_text_decoration() is not None: debug += "|U" debug += "/" + hex(scc_word.value) + "]" self.process_preamble_address_code(pac, line.time_code) self.previous_code_type = type(pac) elif attribute_code is not None: debug += "[ATC/" + hex(scc_word.value) + "]" self.process_attribute_code(attribute_code) self.previous_code_type = type(attribute_code) elif mid_row_code is not None: debug += "[MRC|" + mid_row_code.get_name() + "/" + hex( scc_word.value) + "]" self.process_mid_row_code(mid_row_code, line.time_code) self.previous_code_type = type(mid_row_code) elif control_code is not None: debug += "[CC|" + control_code.get_name() + "/" + hex( scc_word.value) + "]" self.process_control_code(control_code, line.time_code) self.previous_code_type = type(control_code) elif spec_char is not None: word = spec_char.get_unicode_value() debug += word self.process_text(word, line.time_code) self.previous_code_type = type(spec_char) elif extended_char is not None: if self.current_style in (SccCaptionStyle.PaintOn, SccCaptionStyle.RollUp): self.active_caption.get_current_text().backspace() else: self.buffered_caption.get_current_text().backspace() word = extended_char.get_unicode_value() debug += word self.process_text(word, line.time_code) self.previous_code_type = type(extended_char) else: debug += "[??/" + hex(scc_word.value) + "]" LOGGER.warning("Unsupported SCC word: %s", hex(scc_word.value)) self.previous_code_type = None else: word = scc_word.to_text() debug += word self.process_text(word, line.time_code) self.previous_code_type = str self.previous_code = scc_word.value LOGGER.debug(debug) return line.time_code
def to_model(self, context: _SccContext) -> SccTimeCode: """Converts the SCC line to the data model""" debug = str(self.time_code) + "\t" for scc_word in self.scc_words: if context.previous_code == scc_word.value: continue self.time_code.add_frames() if scc_word.value == 0x0000: continue if scc_word.byte_1 < 0x20: attribute_code = SccAttributeCode.find(scc_word.value) control_code = SccControlCode.find(scc_word.value) mid_row_code = SccMidRowCode.find(scc_word.value) pac = SccPreambleAddressCode.find(scc_word.byte_1, scc_word.byte_2) spec_char = SccSpecialAndExtendedCharacter.find(scc_word.value) if pac is not None: debug += "[PAC|" + str(pac.get_row()) + "|" + str(pac.get_indent()) if pac.get_color() is not None: debug += "|" + str(pac.get_color()) if pac.get_font_style() is not None: debug += "|I" if pac.get_text_decoration() is not None: debug += "|U" debug += "/" + hex(scc_word.value) + "]" context.process_preamble_address_code(pac, self.time_code) elif attribute_code is not None: debug += "[ATC/" + hex(scc_word.value) + "]" context.process_attribute_code(attribute_code) elif mid_row_code is not None: debug += "[MRC|" + mid_row_code.get_name() + "/" + hex(scc_word.value) + "]" context.process_mid_row_code(mid_row_code) elif control_code is not None: debug += "[CC|" + control_code.get_name() + "/" + hex(scc_word.value) + "]" context.process_control_code(control_code, self.time_code) elif spec_char is not None: word = spec_char.get_unicode_value() debug += word context.process_text(word, self.time_code) else: debug += "[??/" + hex(scc_word.value) + "]" LOGGER.warning("Unsupported SCC word: %s", hex(scc_word.value)) context.previous_code = scc_word.value else: word = scc_word.to_text() debug += word context.process_text(word, self.time_code) context.previous_code = scc_word.value LOGGER.debug(debug) return self.time_code
def process_mid_row_code(self, mid_row_code: SccMidRowCode): """Processes SCC Mid-Row Code to map it to the model""" if self.current_caption is None: raise ValueError("No current SCC caption initialized") if self.current_caption.get_current_text() is not None and self.current_caption.get_current_text().get_text(): self.current_caption.new_caption_text() self.current_caption.apply_current_text_offsets() self.current_caption.get_current_text().add_style_property(StyleProperties.Color, mid_row_code.get_color()) self.current_caption.get_current_text().add_style_property(StyleProperties.FontStyle, mid_row_code.get_font_style()) self.current_caption.get_current_text().add_style_property(StyleProperties.TextDecoration, mid_row_code.get_text_decoration())