From 32dc8c6957e7913ae84a5c3987de87ef86536bbf Mon Sep 17 00:00:00 2001 From: Roland van Laar Date: Mon, 30 Oct 2023 20:14:18 +0100 Subject: [PATCH 1/2] Expose bits_per_coded_sample on VideoCodecContext qtrle decoder needs `bits_per_coded_sample` to be set when decoding a packet. --- av/video/codeccontext.pyx | 8 ++++++++ include/libavcodec/avcodec.pxd | 2 ++ 2 files changed, 10 insertions(+) diff --git a/av/video/codeccontext.pyx b/av/video/codeccontext.pyx index 33efc5d54..891f5ccaf 100644 --- a/av/video/codeccontext.pyx +++ b/av/video/codeccontext.pyx @@ -92,6 +92,14 @@ cdef class VideoCodecContext(CodecContext): self.ptr.height = value self._build_format() + property bits_per_coded_sample: + def __get__(self): + return self.ptr.bits_per_coded_sample + + def __set__(self, unsigned int value): + self.ptr.bits_per_coded_sample = value + self._build_format() + property pix_fmt: """ The pixel format's name. diff --git a/include/libavcodec/avcodec.pxd b/include/libavcodec/avcodec.pxd index 11d968b1a..bdd73c5fe 100644 --- a/include/libavcodec/avcodec.pxd +++ b/include/libavcodec/avcodec.pxd @@ -170,6 +170,8 @@ cdef extern from "libavcodec/avcodec.h" nogil: int bit_rate_tolerance int mb_decision + int bits_per_coded_sample + int global_quality int compression_level From 726f1364354a910dd4c7dd4bdef29aee104518f8 Mon Sep 17 00:00:00 2001 From: WyattBlue Date: Tue, 12 Mar 2024 03:21:21 -0400 Subject: [PATCH 2/2] Add bits_per_coded_sample tests --- av/video/codeccontext.pyx | 5 +++++ tests/test_codec_context.py | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/av/video/codeccontext.pyx b/av/video/codeccontext.pyx index 700c91279..8f6762fcf 100644 --- a/av/video/codeccontext.pyx +++ b/av/video/codeccontext.pyx @@ -102,6 +102,8 @@ cdef class VideoCodecContext(CodecContext): """ The number of bits per sample in the codedwords, basically the bitrate per sample. It is mandatory for this to be set for some formats to decode them. + + Wraps :ffmpeg:`AVCodecContext::bits_per_coded_sample` :type: int """ @@ -109,6 +111,9 @@ cdef class VideoCodecContext(CodecContext): @bits_per_coded_sample.setter def bits_per_coded_sample(self, int value): + if self.is_encoder: + raise ValueError("Not supported for encoders") + self.ptr.bits_per_coded_sample = value self._build_format() diff --git a/tests/test_codec_context.py b/tests/test_codec_context.py index 0be4ed621..2f9a34aa7 100644 --- a/tests/test_codec_context.py +++ b/tests/test_codec_context.py @@ -146,6 +146,31 @@ def test_encoder_pix_fmt(self): self.assertEqual(str(cm.exception), "not a pixel format: '__unknown_pix_fmt'") self.assertEqual(ctx.pix_fmt, "yuv420p") + def test_bits_per_coded_sample(self): + with av.open(fate_suite("qtrle/aletrek-rle.mov")) as container: + stream = container.streams.video[0] + stream.bits_per_coded_sample = 32 + + for packet in container.demux(stream): + for frame in packet.decode(): + pass + self.assertEqual(packet.stream.bits_per_coded_sample, 32) + + with av.open(fate_suite("qtrle/aletrek-rle.mov")) as container: + stream = container.streams.video[0] + stream.bits_per_coded_sample = 31 + + with self.assertRaises(av.error.InvalidDataError): + for packet in container.demux(stream): + for frame in packet.decode(): + pass + + with av.open(self.sandboxed("output.mov"), "w") as output: + stream = output.add_stream("qtrle") + + with self.assertRaises(ValueError): + stream.codec_context.bits_per_coded_sample = 32 + def test_parse(self): # This one parses into a single packet. self._assert_parse("mpeg4", fate_suite("h264/interlaced_crop.mp4"))