From 873b3d46a6601a18cf36fff7e92125d5a6122f09 Mon Sep 17 00:00:00 2001 From: WyattBlue Date: Sat, 20 Jul 2024 19:54:10 -0400 Subject: [PATCH] Add container.supported_codecs --- av/container/output.pyi | 2 ++ av/container/output.pyx | 20 ++++++++++++++++++++ include/libavcodec/avcodec.pxd | 15 +++++++-------- include/libavformat/avformat.pxd | 2 ++ tests/test_containerformat.py | 3 +++ 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/av/container/output.pyi b/av/container/output.pyi index 882592667..9e46b413a 100644 --- a/av/container/output.pyi +++ b/av/container/output.pyi @@ -25,3 +25,5 @@ class OutputContainer(Container): def default_audio_codec(self) -> str: ... @property def default_subtitle_codec(self) -> str: ... + @property + def supported_codecs(self) -> set[str]: ... diff --git a/av/container/output.pyx b/av/container/output.pyx index 184a30b2d..e9bfad256 100644 --- a/av/container/output.pyx +++ b/av/container/output.pyx @@ -194,6 +194,26 @@ cdef class OutputContainer(Container): self._started = True + @property + def supported_codecs(self): + """ + List of supported codecs. + """ + result = set() + cdef const lib.AVCodec *codec = NULL + cdef void *opaque = NULL + + while True: + codec = lib.av_codec_iterate(&opaque) + if codec == NULL: + break + + if lib.avformat_query_codec(self.ptr.oformat, codec.id, lib.FF_COMPLIANCE_NORMAL) == 1: + result.add(codec.name) + + return result + + @property def default_video_codec(self): """ diff --git a/include/libavcodec/avcodec.pxd b/include/libavcodec/avcodec.pxd index cc11a5e9b..d4335b2a9 100644 --- a/include/libavcodec/avcodec.pxd +++ b/include/libavcodec/avcodec.pxd @@ -1,15 +1,14 @@ from libc.stdint cimport int8_t, int64_t, uint16_t, uint32_t +cdef extern from "libavcodec/codec.h": + struct AVCodecTag: + pass + +cdef extern from "libavcodec/codec_id.h": + AVCodecID av_codec_get_id(const AVCodecTag *const *tags, uint32_t tag) + cdef extern from "libavcodec/avcodec.h" nogil: - """ - // AV_FRAME_DATA_SEI_UNREGISTERED available since version 56.54.100 of libavutil (FFmpeg >= 4.4) - #define HAS_AV_FRAME_DATA_SEI_UNREGISTERED (LIBAVUTIL_VERSION_INT >= 3683940) - - #if !HAS_AV_FRAME_DATA_SEI_UNREGISTERED - #define AV_FRAME_DATA_SEI_UNREGISTERED -1 - #endif - """ cdef set pyav_get_available_codecs() cdef int avcodec_version() diff --git a/include/libavformat/avformat.pxd b/include/libavformat/avformat.pxd index 9d9061cc2..f51ba269b 100644 --- a/include/libavformat/avformat.pxd +++ b/include/libavformat/avformat.pxd @@ -115,6 +115,8 @@ cdef extern from "libavformat/avformat.h" nogil: # const AVCodecTag* const *codec_tag const AVClass *priv_class + int avformat_query_codec(const AVOutputFormat *oformat, AVCodecID codec_id, int std_compliance) + # AVInputFormat.flags and AVOutputFormat.flags cdef enum: AVFMT_NOFILE diff --git a/tests/test_containerformat.py b/tests/test_containerformat.py index f0460b131..5b6d31c35 100644 --- a/tests/test_containerformat.py +++ b/tests/test_containerformat.py @@ -9,6 +9,7 @@ def test_matroska(self) -> None: self.assertNotEqual(container.default_video_codec, "none") self.assertNotEqual(container.default_audio_codec, "none") self.assertEqual(container.default_subtitle_codec, "ass") + self.assertIn("ass", container.supported_codecs) fmt = ContainerFormat("matroska") self.assertTrue(fmt.is_input) @@ -23,6 +24,7 @@ def test_mov(self) -> None: self.assertNotEqual(container.default_video_codec, "none") self.assertNotEqual(container.default_audio_codec, "none") self.assertEqual(container.default_subtitle_codec, "none") + self.assertIn("h264", container.supported_codecs) fmt = ContainerFormat("mov") self.assertTrue(fmt.is_input) @@ -37,6 +39,7 @@ def test_gif(self) -> None: self.assertEqual(container.default_video_codec, "gif") self.assertEqual(container.default_audio_codec, "none") self.assertEqual(container.default_subtitle_codec, "none") + self.assertIn("gif", container.supported_codecs) def test_stream_segment(self) -> None: # This format goes by two names, check both.