Blender V4.3
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
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 <libswscale/swscale.h>
21
22/* Check if our ffmpeg is new enough, avoids user complaints.
23 * Minimum supported version is currently 3.2.0 which mean the following library versions:
24 * libavutil > 55.30
25 * libavcodec > 57.60
26 * libavformat > 57.50
27 *
28 * We only check for one of these as they are usually updated in tandem.
29 */
30#if (LIBAVFORMAT_VERSION_MAJOR < 57) || \
31 ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR <= 50))
32# error "FFmpeg 3.2.0 or newer is needed, Upgrade your FFmpeg or disable it"
33#endif
34/* end sanity check */
35
36/* visual studio 2012 does not define inline for C */
37#ifdef _MSC_VER
38# define FFMPEG_INLINE static __inline
39#else
40# define FFMPEG_INLINE static inline
41#endif
42
43#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(58, 29, 100)
44/* In ffmpeg 6.1 usage of the "key_frame" variable from "AVFrame" has been deprecated.
45 * used the new method to query for the "AV_FRAME_FLAG_KEY" flag instead.
46 */
47# define FFMPEG_OLD_KEY_FRAME_QUERY_METHOD
48#endif
49
50#if (LIBAVFORMAT_VERSION_MAJOR < 59)
51/* For versions older than ffmpeg 5.0, use the old channel layout variables.
52 * We intend to only keep this workaround for around two releases (3.5, 3.6).
53 * If it sticks around any longer, then we should consider refactoring this.
54 */
55# define FFMPEG_USE_OLD_CHANNEL_VARS
56#endif
57
58/* Threaded sws_scale_frame was added in ffmpeg 5.0 (swscale version 6.1). */
59#if (LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(6, 1, 100))
60# define FFMPEG_SWSCALE_THREADING
61#endif
62
63/* AV_CODEC_CAP_AUTO_THREADS was renamed to AV_CODEC_CAP_OTHER_THREADS with
64 * upstream commit
65 * github.com/FFmpeg/FFmpeg/commit/7d09579190def3ef7562399489e628f3b65714ce
66 * (lavc 58.132.100) and removed with commit
67 * github.com/FFmpeg/FFmpeg/commit/10c9a0874cb361336237557391d306d26d43f137
68 * for ffmpeg 6.0.
69 */
70#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 132, 100)
71# define AV_CODEC_CAP_OTHER_THREADS AV_CODEC_CAP_AUTO_THREADS
72#endif
73
74#if (LIBAVFORMAT_VERSION_MAJOR < 58) || \
75 ((LIBAVFORMAT_VERSION_MAJOR == 58) && (LIBAVFORMAT_VERSION_MINOR < 76))
76# define FFMPEG_USE_DURATION_WORKAROUND 1
77
78/* Before ffmpeg 4.4, package duration calculation used depricated variables to calculate the
79 * packet duration. Use the function from commit
80 * github.com/FFmpeg/FFmpeg/commit/1c0885334dda9ee8652e60c586fa2e3674056586
81 * to calculate the correct framerate for ffmpeg < 4.4.
82 */
83
85void my_guess_pkt_duration(AVFormatContext *s, AVStream *st, AVPacket *pkt)
86{
87 if (pkt->duration < 0 && st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
88 av_log(s,
89 AV_LOG_WARNING,
90 "Packet with invalid duration %" PRId64 " in stream %d\n",
91 pkt->duration,
92 pkt->stream_index);
93 pkt->duration = 0;
94 }
95
96 if (pkt->duration) {
97 return;
98 }
99
100 switch (st->codecpar->codec_type) {
101 case AVMEDIA_TYPE_VIDEO:
102 if (st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0) {
103 pkt->duration = av_rescale_q(1, av_inv_q(st->avg_frame_rate), st->time_base);
104 }
105 else if (st->time_base.num * 1000LL > st->time_base.den) {
106 pkt->duration = 1;
107 }
108 break;
109 case AVMEDIA_TYPE_AUDIO: {
110 int frame_size = av_get_audio_frame_duration2(st->codecpar, pkt->size);
111 if (frame_size && st->codecpar->sample_rate) {
112 pkt->duration = av_rescale_q(
113 frame_size, (AVRational){1, st->codecpar->sample_rate}, st->time_base);
114 }
115 break;
116 }
117 default:
118 break;
119 }
120}
121#endif
122
125{
126 /* Some videos do not have any pts values, use dts instead in those cases if
127 * possible. Usually when this happens dts can act as pts because as all frames
128 * should then be presented in their decoded in order. IE pts == dts. */
129 if (pts == AV_NOPTS_VALUE) {
130 return dts;
131 }
132 return pts;
133}
134
137{
138 return timestamp_from_pts_or_dts(picture->pts, picture->pkt_dts);
139}
140
141/* Duration of the frame, in the same units as pts. 0 if unknown. */
144{
145#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 30, 100)
146 return picture->pkt_duration;
147#else
148 return picture->duration;
149#endif
150}
151
153{
154 /* NOTE: even if av_frame_get_buffer suggests to pass 0 for alignment,
155 * as of ffmpeg 6.1/7.0 it does not use correct alignment for AVX512
156 * CPU (frame.c get_video_buffer ends up always using 32 alignment,
157 * whereas it should have used 64). Reported upstream:
158 * https://trac.ffmpeg.org/ticket/11116 and the fix on their code
159 * side is to use 64 byte alignment as soon as AVX512 is compiled
160 * in (even if CPU might not support it). So play safe and
161 * use at least 64 byte alignment here too. Currently larger than
162 * 64 alignment would not happen anywhere, but keep on querying
163 * av_cpu_max_align just in case some future platform might. */
164 size_t align = av_cpu_max_align();
165 if (align < 64) {
166 align = 64;
167 }
168 return align;
169}
170
171/* -------------------------------------------------------------------- */
177#define MAX_NEG_CROP 1024
178
179#define times4(x) x, x, x, x
180#define times256(x) times4(times4(times4(times4(times4(x)))))
181
182static const uint8_t ff_compat_crop_tab[256 + 2 * MAX_NEG_CROP] = {
183 times256(0x00), 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
184 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
185 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22,
186 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E,
187 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
188 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
189 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52,
190 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E,
191 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
192 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
193 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82,
194 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E,
195 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A,
196 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
197 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2,
198 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
199 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA,
200 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
201 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2,
202 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE,
203 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA,
204 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, times256(0xFF)};
205
206#undef times4
207#undef times256
208
209/* filter parameters: [-1 4 2 4 -1] // 8 */
212 const uint8_t *lum_m4,
213 const uint8_t *lum_m3,
214 const uint8_t *lum_m2,
215 const uint8_t *lum_m1,
216 const uint8_t *lum,
217 int size)
218{
220 int sum;
221
222 for (; size > 0; size--) {
223 sum = -lum_m4[0];
224 sum += lum_m3[0] << 2;
225 sum += lum_m2[0] << 1;
226 sum += lum_m1[0] << 2;
227 sum += -lum[0];
228 dst[0] = cm[(sum + 4) >> 3];
229 lum_m4++;
230 lum_m3++;
231 lum_m2++;
232 lum_m1++;
233 lum++;
234 dst++;
235 }
236}
237
240 uint8_t *lum_m4, uint8_t *lum_m3, uint8_t *lum_m2, uint8_t *lum_m1, uint8_t *lum, int size)
241{
243 int sum;
244
245 for (; size > 0; size--) {
246 sum = -lum_m4[0];
247 sum += lum_m3[0] << 2;
248 sum += lum_m2[0] << 1;
249 lum_m4[0] = lum_m2[0];
250 sum += lum_m1[0] << 2;
251 sum += -lum[0];
252 lum_m2[0] = cm[(sum + 4) >> 3];
253 lum_m4++;
254 lum_m3++;
255 lum_m2++;
256 lum_m1++;
257 lum++;
258 }
259}
260
261/* deinterlacing : 2 temporal taps, 3 spatial taps linear filter. The
262 * top field is copied as is, but the bottom field is deinterlaced
263 * against the top field. */
266 uint8_t *dst, int dst_wrap, const uint8_t *src1, int src_wrap, int width, int height)
267{
268 const uint8_t *src_m2, *src_m1, *src_0, *src_p1, *src_p2;
269 int y;
270
271 src_m2 = src1;
272 src_m1 = src1;
273 src_0 = &src_m1[src_wrap];
274 src_p1 = &src_0[src_wrap];
275 src_p2 = &src_p1[src_wrap];
276 for (y = 0; y < (height - 2); y += 2) {
277 memcpy(dst, src_m1, width);
278 dst += dst_wrap;
279 deinterlace_line(dst, src_m2, src_m1, src_0, src_p1, src_p2, width);
280 src_m2 = src_0;
281 src_m1 = src_p1;
282 src_0 = src_p2;
283 src_p1 += 2 * src_wrap;
284 src_p2 += 2 * src_wrap;
285 dst += dst_wrap;
286 }
287 memcpy(dst, src_m1, width);
288 dst += dst_wrap;
289 /* do last line */
290 deinterlace_line(dst, src_m2, src_m1, src_0, src_0, src_0, width);
291}
292
294int deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap, int width, int height)
295{
296 uint8_t *src_m1, *src_0, *src_p1, *src_p2;
297 int y;
298 uint8_t *buf = (uint8_t *)av_malloc(width);
299 if (!buf) {
300 return AVERROR(ENOMEM);
301 }
302
303 src_m1 = src1;
304 memcpy(buf, src_m1, width);
305 src_0 = &src_m1[src_wrap];
306 src_p1 = &src_0[src_wrap];
307 src_p2 = &src_p1[src_wrap];
308 for (y = 0; y < (height - 2); y += 2) {
309 deinterlace_line_inplace(buf, src_m1, src_0, src_p1, src_p2, width);
310 src_m1 = src_p1;
311 src_0 = src_p2;
312 src_p1 += 2 * src_wrap;
313 src_p2 += 2 * src_wrap;
314 }
315 /* do last line */
316 deinterlace_line_inplace(buf, src_m1, src_0, src_0, src_0, width);
317 av_free(buf);
318 return 0;
319}
320
323 AVFrame *dst, const AVFrame *src, enum AVPixelFormat pix_fmt, int width, int height)
324{
325 int i, ret;
326
327 if (pix_fmt != AV_PIX_FMT_YUV420P && pix_fmt != AV_PIX_FMT_YUVJ420P &&
328 pix_fmt != AV_PIX_FMT_YUV422P && pix_fmt != AV_PIX_FMT_YUVJ422P &&
329 pix_fmt != AV_PIX_FMT_YUV444P && pix_fmt != AV_PIX_FMT_YUV411P &&
330 pix_fmt != AV_PIX_FMT_GRAY8)
331 {
332 return -1;
333 }
334 if ((width & 3) != 0 || (height & 3) != 0) {
335 return -1;
336 }
337
338 for (i = 0; i < 3; i++) {
339 if (i == 1) {
340 switch (pix_fmt) {
341 case AV_PIX_FMT_YUVJ420P:
342 case AV_PIX_FMT_YUV420P:
343 width >>= 1;
344 height >>= 1;
345 break;
346 case AV_PIX_FMT_YUV422P:
347 case AV_PIX_FMT_YUVJ422P:
348 width >>= 1;
349 break;
350 case AV_PIX_FMT_YUV411P:
351 width >>= 2;
352 break;
353 default:
354 break;
355 }
356 if (pix_fmt == AV_PIX_FMT_GRAY8) {
357 break;
358 }
359 }
360 if (src == dst) {
361 ret = deinterlace_bottom_field_inplace(dst->data[i], dst->linesize[i], width, height);
362 if (ret < 0) {
363 return ret;
364 }
365 }
366 else {
368 dst->data[i], dst->linesize[i], src->data[i], src->linesize[i], width, height);
369 }
370 }
371 return 0;
372}
373
376#endif
static T sum(const btAlignedObjectArray< T > &items)
FFMPEG_INLINE int64_t av_get_frame_duration_in_pts_units(const AVFrame *picture)
FFMPEG_INLINE size_t ffmpeg_get_buffer_alignment()
FFMPEG_INLINE void deinterlace_line_inplace(uint8_t *lum_m4, uint8_t *lum_m3, uint8_t *lum_m2, uint8_t *lum_m1, uint8_t *lum, int size)
static const uint8_t ff_compat_crop_tab[256+2 *MAX_NEG_CROP]
FFMPEG_INLINE int64_t timestamp_from_pts_or_dts(int64_t pts, int64_t dts)
#define MAX_NEG_CROP
FFMPEG_INLINE int64_t av_get_pts_from_frame(AVFrame *picture)
FFMPEG_INLINE void deinterlace_line(uint8_t *dst, const uint8_t *lum_m4, const uint8_t *lum_m3, const uint8_t *lum_m2, const uint8_t *lum_m1, const uint8_t *lum, int size)
FFMPEG_INLINE void deinterlace_bottom_field(uint8_t *dst, int dst_wrap, const uint8_t *src1, int src_wrap, int width, int height)
FFMPEG_INLINE int deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap, int width, int height)
#define times256(x)
FFMPEG_INLINE void my_guess_pkt_duration(AVFormatContext *s, AVStream *st, AVPacket *pkt)
#define FFMPEG_INLINE
FFMPEG_INLINE int av_image_deinterlace(AVFrame *dst, const AVFrame *src, enum AVPixelFormat pix_fmt, int width, int height)
#define PRId64
Definition inttypes.h:78
return ret
__int64 int64_t
Definition stdint.h:89
unsigned char uint8_t
Definition stdint.h:78