SHA256
15
0
forked from pool/python-av
Files
python-av/python-av-ffmpeg5-compatibility.patch
Dirk Mueller c606411153 Accepting request 994510 from home:badshah400:branches:home:dimstar:ffmpeg5
Add python-av-ffmpeg5-compatibility.patch to drop references to symbols in ffmpeg4 and dropped from ffmpeg5 to allow building against ffmpeg5; patch taken from upstream git commit.

OBS-URL: https://build.opensuse.org/request/show/994510
OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-av?expand=0&rev=21
2022-08-15 07:14:29 +00:00

747 lines
28 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
From 18704658487ea25e5202ac18438d836dfe65b9d0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jeremy=20Lain=C3=A9?= <jeremy.laine@m4x.org>
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 '<av.%s #%d %s/%s at 0x%x>' % (
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):