def encode_and_decode(stream): f = BytesIO() autofill_and_serialise_stream(f, stream) f.seek(0) pictures = [] state = State( _output_picture_callback=lambda p, vp, pcm: pictures.append(p)) init_io(state, f) parse_stream(state) return pictures
def serialise_and_decode_pictures(self, stream): f = BytesIO() autofill_and_serialise_stream(f, stream) pictures = [] state = State( _output_picture_callback=lambda pic, vp, pcm: pictures.append(pic)) f.seek(0) decoder.init_io(state, f) decoder.parse_stream(state) return pictures
def check_codec_features_valid(codec_feature_sets): """ Verify that the codec features requested don't themselves violate the spec (e.g. violate a level constraint). This is done by generating then validating a bitstream containing a single mid-gray frame. Prints an error to stderr and calls :py:func:`sys.exit` if a problem is encountered. """ logging.info("Checking codec feature sets are valid...") for name, codec_features in codec_feature_sets.items(): logging.info("Checking %r...", name) f = BytesIO() # Sanity-check the color format (since this won't raise a validation # error but will result in a useless gamut being available). sanity = sanity_check_video_parameters(codec_features["video_parameters"]) if not sanity: logging.warning( "Color specification for codec configuration %r be malformed: %s", name, sanity.explain(), ) # Generate a minimal bitstream try: autofill_and_serialise_stream(f, static_gray(codec_features)) except UnsatisfiableCodecFeaturesError as e: sys.stderr.write( "Error: Codec configuration {!r} is invalid:\n".format(name) ) terminal_width = get_terminal_size()[0] sys.stderr.write(wrap_paragraphs(e.explain(), terminal_width)) sys.stderr.write("\n") sys.exit(4) f.seek(0) # Validate it meets the spec state = State() init_io(state, f) try: parse_stream(state) except ConformanceError as e: sys.stderr.write( "Error: Codec configuration {!r} is invalid:\n".format(name) ) terminal_width = get_terminal_size()[0] sys.stderr.write(wrap_paragraphs(e.explain(), terminal_width)) sys.stderr.write("\n") sys.exit(4)
def test_is_end_of_stream(): f = BytesIO(b"\xFF") state = State() decoder.init_io(state, f) # At start of stream assert decoder.is_end_of_stream(state) is False # Part-way through byte decoder.read_nbits(state, 4) assert decoder.is_end_of_stream(state) is False # At end of stream decoder.read_nbits(state, 4) assert decoder.is_end_of_stream(state) is True
def run(self): try: self._file = open(self._filename, "rb") self._filesize_bytes = os.path.getsize(self._filename) except Exception as e: # Catch-all exception handler excuse: Catching only file-related # exceptions is challenging, particularly in a backward-compatible # manner. However, none of the above are known to produce # exceptions *except* due to file-related issues. self._print_error(str(e)) return 1 self._state = State(_output_picture_callback=self._output_picture) init_io(self._state, self._file) if self._show_status: self._update_status_line("Starting bitstream validation...") try: parse_stream(self._state) self._hide_status_line() if tell(self._state) == (0, 7): sys.stdout.flush() sys.stderr.write( "Warning: 0 bytes read, bitstream is empty.\n") print( "No errors found in bitstream. Verify decoded pictures to confirm conformance." ) return 0 except ConformanceError as e: # Bitstream failed validation exc_type, exc_value, exc_tb = sys.exc_info() self._hide_status_line() self._print_conformance_error(e, traceback.extract_tb(exc_tb)) self._print_error("non-conformant bitstream (see above)") return 2 except Exception as e: # Internal error (shouldn't happen(!)) self._hide_status_line() self._print_error("internal error in bitstream validator: {}: {} " "(probably a bug in this program)".format( type(e).__name__, str(e), )) return 3
def test_tell(): f = BytesIO(b"\xAA\xFF") state = State() decoder.init_io(state, f) # At start of stream assert decoder.tell(state) == (0, 7) # Part-way through byte decoder.read_nbits(state, 4) assert decoder.tell(state) == (0, 3) # In next byte decoder.read_nbits(state, 8) assert decoder.tell(state) == (1, 3) # At EOF decoder.read_nbits(state, 4) assert decoder.tell(state) == (2, 7)
def serialize_and_decode(sequence): # Serialise f = BytesIO() autofill_and_serialise_stream(f, Stream(sequences=[sequence])) # Setup callback to capture decoded pictures decoded_pictures = [] def output_picture_callback(picture, video_parameters, picture_coding_mode): decoded_pictures.append(picture) # Feed to conformance checking decoder f.seek(0) state = State(_output_picture_callback=output_picture_callback) init_io(state, f) parse_stream(state) return decoded_pictures
def check_for_signal_clipping(sequence): """ Given a :py:class:`vc2_conformance.bitstream.Sequence`, return True if any picture component signal was clipped during decoding. """ # NB: Internally we just check for saturated signal levels. This way we # avoid the need to modify the decoder to remove the clipper and all that # faff... # Serialise f = BytesIO() # NB: Deepcopy required due to autofill_and_serialise_stream mutating the # stream stream = Stream(sequences=[deepcopy(sequence)]) autofill_and_serialise_stream(f, stream) f.seek(0) # Decode and look for saturated pixel values state = State() may_have_clipped = [False] def output_picture_callback(picture, video_parameters, picture_coding_mode): components_and_depths = [ ("Y", state["luma_depth"]), ("C1", state["color_diff_depth"]), ("C2", state["color_diff_depth"]), ] for component, depth in components_and_depths: min_value = min(min(row) for row in picture[component]) max_value = max(max(row) for row in picture[component]) if min_value == 0: may_have_clipped[0] = True if max_value == (1 << depth) - 1: may_have_clipped[0] = True state["_output_picture_callback"] = output_picture_callback init_io(state, f) parse_stream(state) return may_have_clipped[0]
def test_non_empty_file(self): f = BytesIO(b"\xAA\xFF") state = State() decoder.init_io(state, f) assert decoder.read_nbits(state, 16) == 0xAAFF