diff --git a/av-10.0.0.tar.gz b/av-10.0.0.tar.gz new file mode 100644 index 0000000..e73affa --- /dev/null +++ b/av-10.0.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8afd3d5610e1086f3b2d8389d66672ea78624516912c93612de64dcaa4c67e05 +size 2434348 diff --git a/av-9.2.0.tar.gz b/av-9.2.0.tar.gz deleted file mode 100644 index 2a0c92d..0000000 --- a/av-9.2.0.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f2a7c226724d7f7745b376b459c500d9d17bd8d0473b7ea6bf8ddb4f7957c69d -size 2391613 diff --git a/python-av-ffmpeg5-compatibility.patch b/python-av-ffmpeg5-compatibility.patch deleted file mode 100644 index 95af6ea..0000000 --- a/python-av-ffmpeg5-compatibility.patch +++ /dev/null @@ -1,746 +0,0 @@ -From 18704658487ea25e5202ac18438d836dfe65b9d0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jeremy=20Lain=C3=A9?= -Date: Fri, 11 Mar 2022 16:30:43 +0100 -Subject: [PATCH] [streams] stop using deprecated Stream.codec, it's gone in - FFmpeg 5 - -We now allocate and populate an AVCodecContext ourselves. -avcodec_copy_context is also gone, so stop using it. - -We relax the Stream.average_rate tests for older FFmpeg, as the videos -output by these older FFmpeg's seem to give a slightly wrong FPS since -the switch to our own AVCodecContext. ---- - av/codec/context.pxd | 5 +- - av/codec/context.pyx | 7 ++- - av/container/input.pyx | 38 +++++++++----- - av/container/output.pyx | 28 ++++------- - av/container/streams.pyx | 10 ++-- - av/data/stream.pyx | 2 +- - av/packet.pyx | 2 +- - av/stream.pxd | 10 ++-- - av/stream.pyx | 85 +++++++++++++------------------- - av/video/stream.pyx | 4 +- - include/libavcodec/avcodec.pxd | 14 ++++-- - include/libavformat/avformat.pxd | 1 - - tests/common.py | 1 + - tests/test_codec_context.py | 4 +- - tests/test_encode.py | 50 +++++++++++++++---- - 15 files changed, 143 insertions(+), 118 deletions(-) - -diff --git a/av/codec/context.pxd b/av/codec/context.pxd -index d9b6906f9..387cb7de4 100644 ---- a/av/codec/context.pxd -+++ b/av/codec/context.pxd -@@ -11,9 +11,6 @@ cdef class CodecContext(object): - - cdef lib.AVCodecContext *ptr - -- # Whether the AVCodecContext should be de-allocated upon destruction. -- cdef bint allocated -- - # Whether AVCodecContext.extradata should be de-allocated upon destruction. - cdef bint extradata_set - -@@ -64,4 +61,4 @@ cdef class CodecContext(object): - cdef Frame _alloc_next_frame(self) - - --cdef CodecContext wrap_codec_context(lib.AVCodecContext*, const lib.AVCodec*, bint allocated) -+cdef CodecContext wrap_codec_context(lib.AVCodecContext*, const lib.AVCodec*) -diff --git a/av/codec/context.pyx b/av/codec/context.pyx -index c9f5177c1..5c8314615 100644 ---- a/av/codec/context.pyx -+++ b/av/codec/context.pyx -@@ -20,7 +20,7 @@ from av.dictionary import Dictionary - cdef object _cinit_sentinel = object() - - --cdef CodecContext wrap_codec_context(lib.AVCodecContext *c_ctx, const lib.AVCodec *c_codec, bint allocated): -+cdef CodecContext wrap_codec_context(lib.AVCodecContext *c_ctx, const lib.AVCodec *c_codec): - """Build an av.CodecContext for an existing AVCodecContext.""" - - cdef CodecContext py_ctx -@@ -38,7 +38,6 @@ cdef CodecContext wrap_codec_context(lib.AVCodecContext *c_ctx, const lib.AVCode - else: - py_ctx = CodecContext(_cinit_sentinel) - -- py_ctx.allocated = allocated - py_ctx._init(c_ctx, c_codec) - - return py_ctx -@@ -147,7 +146,7 @@ cdef class CodecContext(object): - def create(codec, mode=None): - cdef Codec cy_codec = codec if isinstance(codec, Codec) else Codec(codec, mode) - cdef lib.AVCodecContext *c_ctx = lib.avcodec_alloc_context3(cy_codec.ptr) -- return wrap_codec_context(c_ctx, cy_codec.ptr, True) -+ return wrap_codec_context(c_ctx, cy_codec.ptr) - - def __cinit__(self, sentinel=None, *args, **kwargs): - if sentinel is not _cinit_sentinel: -@@ -307,7 +306,7 @@ cdef class CodecContext(object): - def __dealloc__(self): - if self.ptr and self.extradata_set: - lib.av_freep(&self.ptr.extradata) -- if self.ptr and self.allocated: -+ if self.ptr: - lib.avcodec_close(self.ptr) - lib.avcodec_free_context(&self.ptr) - if self.parser: -diff --git a/av/container/input.pyx b/av/container/input.pyx -index e0c7dcc22..e508f16f4 100644 ---- a/av/container/input.pyx -+++ b/av/container/input.pyx -@@ -1,6 +1,7 @@ - from libc.stdint cimport int64_t - from libc.stdlib cimport free, malloc - -+from av.codec.context cimport CodecContext, wrap_codec_context - from av.container.streams cimport StreamContainer - from av.dictionary cimport _Dictionary - from av.error cimport err_check -@@ -22,7 +23,11 @@ cdef class InputContainer(Container): - - def __cinit__(self, *args, **kwargs): - -+ cdef CodecContext py_codec_context - cdef unsigned int i -+ cdef lib.AVStream *stream -+ cdef lib.AVCodec *codec -+ cdef lib.AVCodecContext *codec_context - - # If we have either the global `options`, or a `stream_options`, prepare - # a mashup of those options for each stream. -@@ -65,7 +70,18 @@ cdef class InputContainer(Container): - - self.streams = StreamContainer() - for i in range(self.ptr.nb_streams): -- self.streams.add_stream(wrap_stream(self, self.ptr.streams[i])) -+ stream = self.ptr.streams[i] -+ codec = lib.avcodec_find_decoder(stream.codecpar.codec_id) -+ if codec: -+ # allocate and initialise decoder -+ codec_context = lib.avcodec_alloc_context3(codec) -+ err_check(lib.avcodec_parameters_to_context(codec_context, stream.codecpar)) -+ codec_context.pkt_timebase = stream.time_base -+ py_codec_context = wrap_codec_context(codec_context, codec) -+ else: -+ # no decoder is available -+ py_codec_context = None -+ self.streams.add_stream(wrap_stream(self, stream, py_codec_context)) - - self.metadata = avdict_to_dict(self.ptr.metadata, self.metadata_encoding, self.metadata_errors) - -@@ -155,7 +171,7 @@ cdef class InputContainer(Container): - if packet.ptr.stream_index < len(self.streams): - packet._stream = self.streams[packet.ptr.stream_index] - # Keep track of this so that remuxing is easier. -- packet._time_base = packet._stream._stream.time_base -+ packet._time_base = packet._stream.ptr.time_base - yield packet - - # Flush! -@@ -163,7 +179,7 @@ cdef class InputContainer(Container): - if include_stream[i]: - packet = Packet() - packet._stream = self.streams[i] -- packet._time_base = packet._stream._stream.time_base -+ packet._time_base = packet._stream.ptr.time_base - yield packet - - finally: -@@ -254,11 +270,11 @@ cdef class InputContainer(Container): - self.flush_buffers() - - cdef flush_buffers(self): -- cdef unsigned int i -- cdef lib.AVStream *stream -- -- with nogil: -- for i in range(self.ptr.nb_streams): -- stream = self.ptr.streams[i] -- if stream.codec and stream.codec.codec and stream.codec.codec_id != lib.AV_CODEC_ID_NONE: -- lib.avcodec_flush_buffers(stream.codec) -+ cdef Stream stream -+ cdef CodecContext codec_context -+ -+ for stream in self.streams: -+ codec_context = stream.codec_context -+ if codec_context and codec_context.is_open: -+ with nogil: -+ lib.avcodec_flush_buffers(codec_context.ptr) -diff --git a/av/container/output.pyx b/av/container/output.pyx -index 621ac8f18..a454e121e 100644 ---- a/av/container/output.pyx -+++ b/av/container/output.pyx -@@ -3,12 +3,13 @@ import logging - import os - - from av.codec.codec cimport Codec -+from av.codec.context cimport CodecContext, wrap_codec_context - from av.container.streams cimport StreamContainer - from av.dictionary cimport _Dictionary - from av.error cimport err_check - from av.packet cimport Packet - from av.stream cimport Stream, wrap_stream --from av.utils cimport dict_to_avdict -+from av.utils cimport dict_to_avdict, to_avrational - - from av.dictionary import Dictionary - -@@ -64,14 +65,11 @@ cdef class OutputContainer(Container): - - if codec_name is not None: - codec_obj = codec_name if isinstance(codec_name, Codec) else Codec(codec_name, 'w') -- codec = codec_obj.ptr -- - else: -- if not template._codec: -- raise ValueError("template has no codec") -- if not template._codec_context: -+ if not template.codec_context: - raise ValueError("template has no codec context") -- codec = template._codec -+ codec_obj = template.codec_context.codec -+ codec = codec_obj.ptr - - # Assert that this format supports the requested codec. - if not lib.avformat_query_codec( -@@ -82,16 +80,13 @@ cdef class OutputContainer(Container): - raise ValueError("%r format does not support %r codec" % (self.format.name, codec_name)) - - # Create new stream in the AVFormatContext, set AVCodecContext values. -- # As of last check, avformat_new_stream only calls avcodec_alloc_context3 to create -- # the context, but doesn't modify it in any other way. Ergo, we can allow CodecContext -- # to finish initializing it. - lib.avformat_new_stream(self.ptr, codec) - cdef lib.AVStream *stream = self.ptr.streams[self.ptr.nb_streams - 1] -- cdef lib.AVCodecContext *codec_context = stream.codec # For readability. -+ cdef lib.AVCodecContext *codec_context = lib.avcodec_alloc_context3(codec) - - # Copy from the template. - if template is not None: -- lib.avcodec_copy_context(codec_context, template._codec_context) -+ err_check(lib.avcodec_parameters_to_context(codec_context, template.ptr.codecpar)) - # Reset the codec tag assuming we are remuxing. - codec_context.codec_tag = 0 - -@@ -103,11 +98,7 @@ cdef class OutputContainer(Container): - codec_context.bit_rate = 1024000 - codec_context.bit_rate_tolerance = 128000 - codec_context.ticks_per_frame = 1 -- -- rate = Fraction(rate or 24) -- -- codec_context.framerate.num = rate.numerator -- codec_context.framerate.den = rate.denominator -+ to_avrational(rate or 24, &codec_context.framerate) - - stream.avg_frame_rate = codec_context.framerate - stream.time_base = codec_context.time_base -@@ -126,7 +117,8 @@ cdef class OutputContainer(Container): - codec_context.flags |= lib.AV_CODEC_FLAG_GLOBAL_HEADER - - # Construct the user-land stream -- cdef Stream py_stream = wrap_stream(self, stream) -+ cdef CodecContext py_codec_context = wrap_codec_context(codec_context, codec) -+ cdef Stream py_stream = wrap_stream(self, stream, py_codec_context) - self.streams.add_stream(py_stream) - - if options: -diff --git a/av/container/streams.pyx b/av/container/streams.pyx -index 4ed2223d4..eb85d9ff3 100644 ---- a/av/container/streams.pyx -+++ b/av/container/streams.pyx -@@ -37,16 +37,16 @@ cdef class StreamContainer(object): - - cdef add_stream(self, Stream stream): - -- assert stream._stream.index == len(self._streams) -+ assert stream.ptr.index == len(self._streams) - self._streams.append(stream) - -- if stream._codec_context.codec_type == lib.AVMEDIA_TYPE_VIDEO: -+ if stream.ptr.codecpar.codec_type == lib.AVMEDIA_TYPE_VIDEO: - self.video = self.video + (stream, ) -- elif stream._codec_context.codec_type == lib.AVMEDIA_TYPE_AUDIO: -+ elif stream.ptr.codecpar.codec_type == lib.AVMEDIA_TYPE_AUDIO: - self.audio = self.audio + (stream, ) -- elif stream._codec_context.codec_type == lib.AVMEDIA_TYPE_SUBTITLE: -+ elif stream.ptr.codecpar.codec_type == lib.AVMEDIA_TYPE_SUBTITLE: - self.subtitles = self.subtitles + (stream, ) -- elif stream._codec_context.codec_type == lib.AVMEDIA_TYPE_DATA: -+ elif stream.ptr.codecpar.codec_type == lib.AVMEDIA_TYPE_DATA: - self.data = self.data + (stream, ) - else: - self.other = self.other + (stream, ) -diff --git a/av/data/stream.pyx b/av/data/stream.pyx -index 698242c51..c019961d0 100644 ---- a/av/data/stream.pyx -+++ b/av/data/stream.pyx -@@ -20,7 +20,7 @@ cdef class DataStream(Stream): - - property name: - def __get__(self): -- cdef const lib.AVCodecDescriptor *desc = lib.avcodec_descriptor_get(self._codec_context.codec_id) -+ cdef const lib.AVCodecDescriptor *desc = lib.avcodec_descriptor_get(self.ptr.codecpar.codec_id) - if desc == NULL: - return None - return desc.name -diff --git a/av/packet.pyx b/av/packet.pyx -index fae970ee3..0687b2237 100644 ---- a/av/packet.pyx -+++ b/av/packet.pyx -@@ -112,7 +112,7 @@ cdef class Packet(Buffer): - - def __set__(self, Stream stream): - self._stream = stream -- self.ptr.stream_index = stream._stream.index -+ self.ptr.stream_index = stream.ptr.index - - property time_base: - """ -diff --git a/av/stream.pxd b/av/stream.pxd -index 4a3cab488..5ad3b965e 100644 ---- a/av/stream.pxd -+++ b/av/stream.pxd -@@ -8,24 +8,20 @@ from av.packet cimport Packet - - - cdef class Stream(object): -+ cdef lib.AVStream *ptr - - # Stream attributes. - cdef readonly Container container -- -- cdef lib.AVStream *_stream - cdef readonly dict metadata - - # CodecContext attributes. -- cdef lib.AVCodecContext *_codec_context -- cdef const lib.AVCodec *_codec -- - cdef readonly CodecContext codec_context - - # Private API. -- cdef _init(self, Container, lib.AVStream*) -+ cdef _init(self, Container, lib.AVStream*, CodecContext) - cdef _finalize_for_output(self) - cdef _set_time_base(self, value) - cdef _set_id(self, value) - - --cdef Stream wrap_stream(Container, lib.AVStream*) -+cdef Stream wrap_stream(Container, lib.AVStream*, CodecContext) -diff --git a/av/stream.pyx b/av/stream.pyx -index cbab9dde1..73cb3504d 100644 ---- a/av/stream.pyx -+++ b/av/stream.pyx -@@ -17,7 +17,7 @@ from av.utils cimport ( - cdef object _cinit_bypass_sentinel = object() - - --cdef Stream wrap_stream(Container container, lib.AVStream *c_stream): -+cdef Stream wrap_stream(Container container, lib.AVStream *c_stream, CodecContext codec_context): - """Build an av.Stream for an existing AVStream. - - The AVStream MUST be fully constructed and ready for use before this is -@@ -30,22 +30,22 @@ cdef Stream wrap_stream(Container container, lib.AVStream *c_stream): - - cdef Stream py_stream - -- if c_stream.codec.codec_type == lib.AVMEDIA_TYPE_VIDEO: -+ if c_stream.codecpar.codec_type == lib.AVMEDIA_TYPE_VIDEO: - from av.video.stream import VideoStream - py_stream = VideoStream.__new__(VideoStream, _cinit_bypass_sentinel) -- elif c_stream.codec.codec_type == lib.AVMEDIA_TYPE_AUDIO: -+ elif c_stream.codecpar.codec_type == lib.AVMEDIA_TYPE_AUDIO: - from av.audio.stream import AudioStream - py_stream = AudioStream.__new__(AudioStream, _cinit_bypass_sentinel) -- elif c_stream.codec.codec_type == lib.AVMEDIA_TYPE_SUBTITLE: -+ elif c_stream.codecpar.codec_type == lib.AVMEDIA_TYPE_SUBTITLE: - from av.subtitles.stream import SubtitleStream - py_stream = SubtitleStream.__new__(SubtitleStream, _cinit_bypass_sentinel) -- elif c_stream.codec.codec_type == lib.AVMEDIA_TYPE_DATA: -+ elif c_stream.codecpar.codec_type == lib.AVMEDIA_TYPE_DATA: - from av.data.stream import DataStream - py_stream = DataStream.__new__(DataStream, _cinit_bypass_sentinel) - else: - py_stream = Stream.__new__(Stream, _cinit_bypass_sentinel) - -- py_stream._init(container, c_stream) -+ py_stream._init(container, c_stream, codec_context) - return py_stream - - -@@ -69,14 +69,15 @@ cdef class Stream(object): - def __cinit__(self, name): - if name is _cinit_bypass_sentinel: - return -- raise RuntimeError('cannot manually instatiate Stream') -- -- cdef _init(self, Container container, lib.AVStream *stream): -+ raise RuntimeError('cannot manually instantiate Stream') - -+ cdef _init(self, Container container, lib.AVStream *stream, CodecContext codec_context): - self.container = container -- self._stream = stream -+ self.ptr = stream - -- self._codec_context = stream.codec -+ self.codec_context = codec_context -+ if self.codec_context: -+ self.codec_context.stream_index = stream.index - - self.metadata = avdict_to_dict( - stream.metadata, -@@ -84,23 +85,6 @@ cdef class Stream(object): - errors=self.container.metadata_errors, - ) - -- # This is an input container! -- if self.container.ptr.iformat: -- -- # Find the codec. -- self._codec = lib.avcodec_find_decoder(self._codec_context.codec_id) -- if not self._codec: -- # TODO: Setup a dummy CodecContext. -- self.codec_context = None -- return -- -- # This is an output container! -- else: -- self._codec = self._codec_context.codec -- -- self.codec_context = wrap_codec_context(self._codec_context, self._codec, False) -- self.codec_context.stream_index = stream.index -- - def __repr__(self): - return '' % ( - self.__class__.__name__, -@@ -137,17 +121,17 @@ cdef class Stream(object): - cdef _finalize_for_output(self): - - dict_to_avdict( -- &self._stream.metadata, self.metadata, -+ &self.ptr.metadata, self.metadata, - encoding=self.container.metadata_encoding, - errors=self.container.metadata_errors, - ) - -- if not self._stream.time_base.num: -- self._stream.time_base = self._codec_context.time_base -+ if not self.ptr.time_base.num: -+ self.ptr.time_base = self.codec_context.ptr.time_base - - # It prefers if we pass it parameters via this other object. - # Lets just copy what we want. -- err_check(lib.avcodec_parameters_from_context(self._stream.codecpar, self._stream.codec)) -+ err_check(lib.avcodec_parameters_from_context(self.ptr.codecpar, self.codec_context.ptr)) - - def encode(self, frame=None): - """ -@@ -165,7 +149,7 @@ cdef class Stream(object): - cdef Packet packet - for packet in packets: - packet._stream = self -- packet.ptr.stream_index = self._stream.index -+ packet.ptr.stream_index = self.ptr.index - return packets - - def decode(self, packet=None): -@@ -190,16 +174,16 @@ cdef class Stream(object): - - """ - def __get__(self): -- return self._stream.id -+ return self.ptr.id - - cdef _set_id(self, value): - """ - Setter used by __setattr__ for the id property. - """ - if value is None: -- self._stream.id = 0 -+ self.ptr.id = 0 - else: -- self._stream.id = value -+ self.ptr.id = value - - property profile: - """ -@@ -208,8 +192,8 @@ cdef class Stream(object): - :type: str - """ - def __get__(self): -- if self._codec and lib.av_get_profile_name(self._codec, self._codec_context.profile): -- return lib.av_get_profile_name(self._codec, self._codec_context.profile) -+ if self.codec_context: -+ return self.codec_context.profile - else: - return None - -@@ -219,7 +203,7 @@ cdef class Stream(object): - - :type: int - """ -- def __get__(self): return self._stream.index -+ def __get__(self): return self.ptr.index - - property time_base: - """ -@@ -229,13 +213,13 @@ cdef class Stream(object): - - """ - def __get__(self): -- return avrational_to_fraction(&self._stream.time_base) -+ return avrational_to_fraction(&self.ptr.time_base) - - cdef _set_time_base(self, value): - """ - Setter used by __setattr__ for the time_base property. - """ -- to_avrational(value, &self._stream.time_base) -+ to_avrational(value, &self.ptr.time_base) - - property average_rate: - """ -@@ -249,7 +233,7 @@ cdef class Stream(object): - - """ - def __get__(self): -- return avrational_to_fraction(&self._stream.avg_frame_rate) -+ return avrational_to_fraction(&self.ptr.avg_frame_rate) - - property base_rate: - """ -@@ -263,7 +247,7 @@ cdef class Stream(object): - - """ - def __get__(self): -- return avrational_to_fraction(&self._stream.r_frame_rate) -+ return avrational_to_fraction(&self.ptr.r_frame_rate) - - property guessed_rate: - """The guessed frame rate of this stream. -@@ -276,7 +260,7 @@ cdef class Stream(object): - """ - def __get__(self): - # The two NULL arguments aren't used in FFmpeg >= 4.0 -- cdef lib.AVRational val = lib.av_guess_frame_rate(NULL, self._stream, NULL) -+ cdef lib.AVRational val = lib.av_guess_frame_rate(NULL, self.ptr, NULL) - return avrational_to_fraction(&val) - - property start_time: -@@ -287,8 +271,8 @@ cdef class Stream(object): - :type: :class:`int` or ``None`` - """ - def __get__(self): -- if self._stream.start_time != lib.AV_NOPTS_VALUE: -- return self._stream.start_time -+ if self.ptr.start_time != lib.AV_NOPTS_VALUE: -+ return self.ptr.start_time - - property duration: - """ -@@ -298,8 +282,8 @@ cdef class Stream(object): - - """ - def __get__(self): -- if self._stream.duration != lib.AV_NOPTS_VALUE: -- return self._stream.duration -+ if self.ptr.duration != lib.AV_NOPTS_VALUE: -+ return self.ptr.duration - - property frames: - """ -@@ -309,7 +293,8 @@ cdef class Stream(object): - - :type: :class:`int` - """ -- def __get__(self): return self._stream.nb_frames -+ def __get__(self): -+ return self.ptr.nb_frames - - property language: - """ -@@ -329,4 +314,4 @@ cdef class Stream(object): - - :type: str - """ -- return lib.av_get_media_type_string(self._codec_context.codec_type) -+ return lib.av_get_media_type_string(self.ptr.codecpar.codec_type) -diff --git a/av/video/stream.pyx b/av/video/stream.pyx -index 70b8f3209..8694b63ba 100644 ---- a/av/video/stream.pyx -+++ b/av/video/stream.pyx -@@ -6,7 +6,7 @@ cdef class VideoStream(Stream): - self.index, - self.name, - self.format.name if self.format else None, -- self._codec_context.width, -- self._codec_context.height, -+ self.codec_context.width, -+ self.codec_context.height, - id(self), - ) -diff --git a/include/libavcodec/avcodec.pxd b/include/libavcodec/avcodec.pxd -index 8c0a9685b..1e6111808 100644 ---- a/include/libavcodec/avcodec.pxd -+++ b/include/libavcodec/avcodec.pxd -@@ -194,6 +194,7 @@ cdef extern from "libavcodec/avcodec.h" nogil: - float rc_min_vbv_overflow_use - - AVRational framerate -+ AVRational pkt_timebase - AVRational time_base - int ticks_per_frame - -@@ -237,7 +238,6 @@ cdef extern from "libavcodec/avcodec.h" nogil: - cdef void avcodec_free_context(AVCodecContext **ctx) - - cdef AVClass* avcodec_get_class() -- cdef int avcodec_copy_context(AVCodecContext *dst, const AVCodecContext *src) - - cdef struct AVCodecDescriptor: - AVCodecID id -@@ -455,10 +455,18 @@ cdef extern from "libavcodec/avcodec.h" nogil: - - - cdef struct AVCodecParameters: -- pass -+ AVMediaType codec_type -+ AVCodecID codec_id - -+ cdef int avcodec_parameters_copy( -+ AVCodecParameters *dst, -+ const AVCodecParameters *src -+ ) - cdef int avcodec_parameters_from_context( - AVCodecParameters *par, - const AVCodecContext *codec, - ) -- -+ cdef int avcodec_parameters_to_context( -+ AVCodecContext *codec, -+ const AVCodecParameters *par -+ ) -diff --git a/include/libavformat/avformat.pxd b/include/libavformat/avformat.pxd -index 0a33cf9f6..ed3e503f5 100644 ---- a/include/libavformat/avformat.pxd -+++ b/include/libavformat/avformat.pxd -@@ -33,7 +33,6 @@ cdef extern from "libavformat/avformat.h" nogil: - int index - int id - -- AVCodecContext *codec - AVCodecParameters *codecpar - - AVRational time_base -diff --git a/tests/common.py b/tests/common.py -index 5d1bf74cc..a49b7bec2 100644 ---- a/tests/common.py -+++ b/tests/common.py -@@ -82,6 +82,7 @@ def _inner(self, *args, **kwargs): - return func(self, *args, **kwargs) - finally: - os.chdir(current_dir) -+ - return _inner - - -diff --git a/tests/test_codec_context.py b/tests/test_codec_context.py -index a62c05c4e..7087804f7 100644 ---- a/tests/test_codec_context.py -+++ b/tests/test_codec_context.py -@@ -180,7 +180,7 @@ def image_sequence_encode(self, codec_name): - - ctx.width = width - ctx.height = height -- ctx.time_base = video_stream.codec_context.time_base -+ ctx.time_base = video_stream.time_base - ctx.pix_fmt = pix_fmt - ctx.open() - -@@ -262,7 +262,7 @@ def video_encoding(self, codec_name, options={}, codec_tag=None): - width = options.pop("width", 640) - height = options.pop("height", 480) - max_frames = options.pop("max_frames", 50) -- time_base = options.pop("time_base", video_stream.codec_context.time_base) -+ time_base = options.pop("time_base", video_stream.time_base) - - ctx = codec.create() - ctx.width = width -diff --git a/tests/test_encode.py b/tests/test_encode.py -index 018c6ac31..7c5d0353f 100644 ---- a/tests/test_encode.py -+++ b/tests/test_encode.py -@@ -70,27 +70,59 @@ def assert_rgb_rotate(self, input_, is_dash=False): - if is_dash: - # FFmpeg 4.2 added parsing of the programme information and it is named "Title" - if av.library_versions["libavformat"] >= (58, 28): -- self.assertTrue(input_.metadata.get("Title") == "container", input_.metadata) -+ self.assertTrue( -+ input_.metadata.get("Title") == "container", input_.metadata -+ ) - else: - self.assertEqual(input_.metadata.get("title"), "container", input_.metadata) - self.assertEqual(input_.metadata.get("key"), None) -+ - stream = input_.streams[0] -- self.assertIsInstance(stream, VideoStream) -- self.assertEqual(stream.type, "video") -- self.assertEqual(stream.name, "mpeg4") -- self.assertEqual( -- stream.average_rate, 24 -- ) # Only because we constructed is precisely. -- self.assertEqual(stream.rate, Fraction(24, 1)) -+ - if is_dash: - # The DASH format doesn't provide a duration for the stream - # and so the container duration (micro seconds) is checked instead - self.assertEqual(input_.duration, 2000000) -+ expected_average_rate = 24 -+ expected_duration = None -+ expected_frames = 0 -+ expected_id = 0 - else: -- self.assertEqual(stream.time_base * stream.duration, 2) -+ if av.library_versions["libavformat"] < (58, 76): -+ # FFmpeg < 4.4 -+ expected_average_rate = Fraction(1152, 47) -+ expected_duration = 24064 -+ else: -+ # FFmpeg >= 4.4 -+ expected_average_rate = 24 -+ expected_duration = 24576 -+ expected_frames = 48 -+ expected_id = 1 -+ -+ # actual stream properties -+ self.assertIsInstance(stream, VideoStream) -+ self.assertEqual(stream.average_rate, expected_average_rate) -+ self.assertEqual(stream.base_rate, 24) -+ self.assertEqual(stream.duration, expected_duration) -+ self.assertEqual(stream.guessed_rate, 24) -+ self.assertEqual(stream.frames, expected_frames) -+ self.assertEqual(stream.id, expected_id) -+ self.assertEqual(stream.index, 0) -+ self.assertEqual(stream.profile, "Simple Profile") -+ self.assertEqual(stream.start_time, 0) -+ self.assertEqual(stream.time_base, Fraction(1, 12288)) -+ self.assertEqual(stream.type, "video") -+ -+ # codec properties -+ self.assertEqual(stream.name, "mpeg4") -+ self.assertEqual(stream.long_name, "MPEG-4 part 2") -+ -+ # codec context properties - self.assertEqual(stream.format.name, "yuv420p") - self.assertEqual(stream.format.width, WIDTH) - self.assertEqual(stream.format.height, HEIGHT) -+ self.assertEqual(stream.rate, None) -+ self.assertEqual(stream.ticks_per_frame, 1) - - - class TestBasicVideoEncoding(TestCase): diff --git a/python-av.changes b/python-av.changes index f8f3dc3..ca009fe 100644 --- a/python-av.changes +++ b/python-av.changes @@ -1,3 +1,20 @@ +------------------------------------------------------------------- +Wed Nov 30 13:43:36 UTC 2022 - Guillaume GARDET + +- Update to 10.0.0: + * Add support for FFmpeg 5.0 and 5.1 (:issue:`817`). + * Drop support for FFmpeg < 4.3. + * Deprecate CodecContext.time_base for decoders (:issue:`966`). + * Deprecate VideoStream.framerate and VideoStream.rate (:issue:`1005`). + * Stop proxying Codec from Stream instances (:issue:`1037`). + * Add VideoFrame ndarray operations for gbrp formats (:issue:`986`). + * Add VideoFrame ndarray operations for gbrpf32 formats (:issue:`1028`). + * Add VideoFrame ndarray operations for nv12 format (:issue:`996`). + * Fix conversion to numpy array for multi-byte formats (:issue:`981`). + * Safely iterate over filter pads (:issue:`1000`). +- Drop upstream patch: + * python-av-ffmpeg5-compatibility.patch + ------------------------------------------------------------------- Mon Aug 8 21:41:40 UTC 2022 - Atri Bhattacharya diff --git a/python-av.spec b/python-av.spec index 95a48dd..98f8245 100644 --- a/python-av.spec +++ b/python-av.spec @@ -19,14 +19,12 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-av -Version: 9.2.0 +Version: 10.0.0 Release: 0 Summary: Python bindings for FFmpeg's libraries License: BSD-3-Clause URL: https://github.com/PyAV-Org/PyAV Source: https://files.pythonhosted.org/packages/source/a/av/av-%{version}.tar.gz -# PATCH-FIX-UPSTREAM gh#PyAV-Org/PyAV#817 badshah400@gmail.com -- Add ffmpeg5 support, patch taken from upstream git -Patch0: https://github.com/PyAV-Org/PyAV/commit/18704658487ea25e5202ac18438d836dfe65b9d0.patch#/python-av-ffmpeg5-compatibility.patch BuildRequires: %{python_module Cython} BuildRequires: %{python_module devel} BuildRequires: %{python_module numpy}