Blender V5.0
ffmpeg_compat.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 Peter Schlaile
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
13
14#ifndef __FFMPEG_COMPAT_H__
15#define __FFMPEG_COMPAT_H__
16
17#include <libavcodec/avcodec.h>
18#include <libavformat/avformat.h>
19#include <libavutil/cpu.h>
20#include <libavutil/display.h>
21#include <libswscale/swscale.h>
22
23/* Check if our FFMPEG is new enough, avoids user complaints.
24 * Minimum supported version is currently 3.2.0 which mean the following library versions:
25 * `libavutil` > 55.30
26 * `libavcodec` > 57.60
27 * `libavformat` > 57.50
28 *
29 * We only check for one of these as they are usually updated in tandem.
30 */
31#if (LIBAVFORMAT_VERSION_MAJOR < 57) || \
32 ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR <= 50))
33# error "FFmpeg 3.2.0 or newer is needed, Upgrade your FFmpeg or disable it"
34#endif
35/* end sanity check */
36
37/* visual studio 2012 does not define inline for C */
38#ifdef _MSC_VER
39# define FFMPEG_INLINE static __inline
40#else
41# define FFMPEG_INLINE static inline
42#endif
43
44#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(58, 29, 100)
45/* In FFMPEG 6.1 usage of the "key_frame" variable from "AVFrame" has been deprecated.
46 * used the new method to query for the "AV_FRAME_FLAG_KEY" flag instead.
47 */
48# define FFMPEG_OLD_KEY_FRAME_QUERY_METHOD
49#endif
50
51#if (LIBAVFORMAT_VERSION_MAJOR < 59)
52/* For versions older than FFMPEG 5.0, use the old channel layout variables.
53 * We intend to only keep this workaround for around two releases (3.5, 3.6).
54 * If it sticks around any longer, then we should consider refactoring this.
55 */
56# define FFMPEG_USE_OLD_CHANNEL_VARS
57#endif
58
59/* Threaded sws_scale_frame was added in FFMPEG 5.0 (`swscale` version 6.1). */
60#if (LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(6, 1, 100))
61# define FFMPEG_SWSCALE_THREADING
62#endif
63
64/* AV_CODEC_CAP_AUTO_THREADS was renamed to AV_CODEC_CAP_OTHER_THREADS with
65 * upstream commit
66 * `github.com/FFmpeg/FFmpeg/commit/7d09579190def3ef7562399489e628f3b65714ce`
67 * (`lavc` 58.132.100) and removed with commit
68 * `github.com/FFmpeg/FFmpeg/commit/10c9a0874cb361336237557391d306d26d43f137`
69 * for FFMPEG 6.0.
70 */
71#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 132, 100)
72# define AV_CODEC_CAP_OTHER_THREADS AV_CODEC_CAP_AUTO_THREADS
73#endif
74
75#if (LIBAVFORMAT_VERSION_MAJOR < 58) || \
76 ((LIBAVFORMAT_VERSION_MAJOR == 58) && (LIBAVFORMAT_VERSION_MINOR < 76))
77# define FFMPEG_USE_DURATION_WORKAROUND 1
78
79/* Before FFMPEG 4.4, package duration calculation used deprecated variables to calculate the
80 * packet duration. Use the function from commit
81 * `github.com/FFmpeg/FFmpeg/commit/1c0885334dda9ee8652e60c586fa2e3674056586`
82 * to calculate the correct frame-rate for FFMPEG < 4.4.
83 */
84
86void my_guess_pkt_duration(AVFormatContext *s, AVStream *st, AVPacket *pkt)
87{
88 if (pkt->duration < 0 && st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
89 av_log(s,
90 AV_LOG_WARNING,
91 "Packet with invalid duration %" PRId64 " in stream %d\n",
92 pkt->duration,
93 pkt->stream_index);
94 pkt->duration = 0;
95 }
96
97 if (pkt->duration) {
98 return;
99 }
100
101 switch (st->codecpar->codec_type) {
102 case AVMEDIA_TYPE_VIDEO:
103 if (st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0) {
104 pkt->duration = av_rescale_q(1, av_inv_q(st->avg_frame_rate), st->time_base);
105 }
106 else if (st->time_base.num * 1000LL > st->time_base.den) {
107 pkt->duration = 1;
108 }
109 break;
110 case AVMEDIA_TYPE_AUDIO: {
111 int frame_size = av_get_audio_frame_duration2(st->codecpar, pkt->size);
112 if (frame_size && st->codecpar->sample_rate) {
113 pkt->duration = av_rescale_q(
114 frame_size, (AVRational){1, st->codecpar->sample_rate}, st->time_base);
115 }
116 break;
117 }
118 default:
119 break;
120 }
121}
122#endif
123
126{
127 /* Some videos do not have any pts values, use dts instead in those cases if
128 * possible. Usually when this happens dts can act as pts because as all frames
129 * should then be presented in their decoded in order. IE pts == dts. */
130 if (pts == AV_NOPTS_VALUE) {
131 return dts;
132 }
133 return pts;
134}
135
138{
139 return timestamp_from_pts_or_dts(picture->pts, picture->pkt_dts);
140}
141
142/* Duration of the frame, in the same units as pts. 0 if unknown. */
145{
146#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 30, 100)
147 return picture->pkt_duration;
148#else
149 return picture->duration;
150#endif
151}
152
154{
155 /* NOTE: even if av_frame_get_buffer suggests to pass 0 for alignment,
156 * as of FFMPEG 6.1/7.0 it does not use correct alignment for AVX512
157 * CPU (frame.c get_video_buffer ends up always using 32 alignment,
158 * whereas it should have used 64). Reported upstream:
159 * https://trac.ffmpeg.org/ticket/11116 and the fix on their code
160 * side is to use 64 byte alignment as soon as AVX512 is compiled
161 * in (even if CPU might not support it). So play safe and
162 * use at least 64 byte alignment here too. Currently larger than
163 * 64 alignment would not happen anywhere, but keep on querying
164 * av_cpu_max_align just in case some future platform might. */
165 size_t align = av_cpu_max_align();
166 if (align < 64) {
167 align = 64;
168 }
169 return align;
170}
171
172FFMPEG_INLINE void ffmpeg_copy_display_matrix(const AVStream *src, AVStream *dst)
173{
174#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(60, 29, 100)
175 const AVPacketSideData *src_matrix = av_packet_side_data_get(src->codecpar->coded_side_data,
176 src->codecpar->nb_coded_side_data,
177 AV_PKT_DATA_DISPLAYMATRIX);
178 if (src_matrix != nullptr) {
179 uint8_t *dst_matrix = (uint8_t *)av_memdup(src_matrix->data, src_matrix->size);
180 av_packet_side_data_add(&dst->codecpar->coded_side_data,
181 &dst->codecpar->nb_coded_side_data,
182 AV_PKT_DATA_DISPLAYMATRIX,
183 dst_matrix,
184 src_matrix->size,
185 0);
186 }
187#endif
188}
189
190FFMPEG_INLINE int ffmpeg_get_video_rotation(const AVStream *stream)
191{
192#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(60, 29, 100)
193 const AVPacketSideData *src_matrix = av_packet_side_data_get(
194 stream->codecpar->coded_side_data,
195 stream->codecpar->nb_coded_side_data,
196 AV_PKT_DATA_DISPLAYMATRIX);
197 if (src_matrix != nullptr) {
198 /* ffmpeg reports rotation in [-180..+180] range; our image rotation
199 * uses different direction and [0..360] range. */
200 double theta = -av_display_rotation_get((const int32_t *)src_matrix->data);
201 if (theta < 0.0) {
202 theta += 360.0;
203 }
204 return int(theta);
205 }
206#endif
207 return 0;
208}
209
210#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)
211FFMPEG_INLINE const enum AVPixelFormat *ffmpeg_get_pix_fmts(struct AVCodecContext *context,
212 const AVCodec *codec)
213{
214 const enum AVPixelFormat *pix_fmts = NULL;
215 avcodec_get_supported_config(
216 context, codec, AV_CODEC_CONFIG_PIX_FORMAT, 0, (const void **)&pix_fmts, NULL);
217 return pix_fmts;
218}
219
220FFMPEG_INLINE const enum AVSampleFormat *ffmpeg_get_sample_fmts(struct AVCodecContext *context,
221 const AVCodec *codec)
222{
223 const enum AVSampleFormat *sample_fmts = NULL;
224 avcodec_get_supported_config(
225 context, codec, AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, (const void **)&sample_fmts, NULL);
226 return sample_fmts;
227}
228
229FFMPEG_INLINE const int *ffmpeg_get_sample_rates(struct AVCodecContext *context,
230 const AVCodec *codec)
231{
232 const int *sample_rates = NULL;
233 avcodec_get_supported_config(
234 context, codec, AV_CODEC_CONFIG_SAMPLE_RATE, 0, (const void **)&sample_rates, NULL);
235 return sample_rates;
236}
237#else
238FFMPEG_INLINE const enum AVPixelFormat *ffmpeg_get_pix_fmts(struct AVCodecContext * /*context*/,
239 const AVCodec *codec)
240{
241 return codec->pix_fmts;
242}
243
244FFMPEG_INLINE const enum AVSampleFormat *ffmpeg_get_sample_fmts(
245 struct AVCodecContext * /*context*/, const AVCodec *codec)
246{
247 return codec->sample_fmts;
248}
249
250FFMPEG_INLINE const int *ffmpeg_get_sample_rates(struct AVCodecContext * /*context*/,
251 const AVCodec *codec)
252{
253 return codec->supported_samplerates;
254}
255#endif
256
257#endif
long long int int64_t
FFMPEG_INLINE int64_t av_get_frame_duration_in_pts_units(const AVFrame *picture)
FFMPEG_INLINE size_t ffmpeg_get_buffer_alignment()
FFMPEG_INLINE int64_t timestamp_from_pts_or_dts(int64_t pts, int64_t dts)
FFMPEG_INLINE enum AVSampleFormat * ffmpeg_get_sample_fmts(struct AVCodecContext *context, const AVCodec *codec)
FFMPEG_INLINE int64_t av_get_pts_from_frame(AVFrame *picture)
FFMPEG_INLINE const int * ffmpeg_get_sample_rates(struct AVCodecContext *context, const AVCodec *codec)
FFMPEG_INLINE enum AVPixelFormat * ffmpeg_get_pix_fmts(struct AVCodecContext *context, const AVCodec *codec)
FFMPEG_INLINE int ffmpeg_get_video_rotation(const AVStream *stream)
FFMPEG_INLINE void my_guess_pkt_duration(AVFormatContext *s, AVStream *st, AVPacket *pkt)
#define FFMPEG_INLINE
FFMPEG_INLINE void ffmpeg_copy_display_matrix(const AVStream *src, AVStream *dst)
#define PRId64
Definition inttypes.h:78