OpenShot Library | libopenshot  0.6.0
FFmpegUtilities.h
Go to the documentation of this file.
1 
9 // Copyright (c) 2008-2024 OpenShot Studios, LLC
10 //
11 // SPDX-License-Identifier: LGPL-3.0-or-later
12 
13 #ifndef OPENSHOT_FFMPEG_UTILITIES_H
14 #define OPENSHOT_FFMPEG_UTILITIES_H
15 
16 #include "OpenShotVersion.h" // For FFMPEG_USE_SWRESAMPLE
17 
18 // Required for libavformat to build on Windows
19 #ifndef INT64_C
20 #define INT64_C(c) (c ## LL)
21 #define UINT64_C(c) (c ## ULL)
22 #endif
23 
24 #ifndef IS_FFMPEG_3_2
25 #define IS_FFMPEG_3_2 (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 64, 101))
26 #endif
27 
28 #ifndef USE_HW_ACCEL
29 #define USE_HW_ACCEL (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 107, 100))
30 #endif
31 
32 #ifndef USE_SW
33 #define USE_SW FFMPEG_USE_SWRESAMPLE
34 #endif
35 
36 #define HAVE_CH_LAYOUT (LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100))
37 
38 // Include the FFmpeg headers
39 extern "C" {
40  #include <libavcodec/avcodec.h>
41  #include <libavformat/avformat.h>
42  #include <libavutil/display.h>
43 
44 #if (LIBAVFORMAT_VERSION_MAJOR >= 57)
45  #include <libavutil/hwcontext.h> //PM
46 #endif
47  #include <libswscale/swscale.h>
48 
49 #if USE_SW
50  #include <libswresample/swresample.h>
51 #else
52  #include <libavresample/avresample.h>
53 #endif
54 
55  #include <libavutil/mathematics.h>
56  #include <libavutil/pixfmt.h>
57  #include <libavutil/pixdesc.h>
58 
59  // libavutil changed folders at some point
60 #if LIBAVFORMAT_VERSION_MAJOR >= 53
61  #include <libavutil/opt.h>
62 #else
63  #include <libavcodec/opt.h>
64 #endif
65 
66  // channel header refactored
67 #if LIBAVFORMAT_VERSION_MAJOR >= 54
68  #include <libavutil/channel_layout.h>
69 #endif
70 
71 #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 0, 0)
72  #include <libavutil/spherical.h>
73 #endif
74 
75 #if IS_FFMPEG_3_2
76  #include "libavutil/imgutils.h"
77 #endif
78 }
79 
80 // This was removed from newer versions of FFmpeg (but still used in libopenshot)
81 #ifndef AVCODEC_MAX_AUDIO_FRAME_SIZE
82  // 1 second of 48khz 32bit audio
83  #define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
84 #endif
85 #ifndef AV_ERROR_MAX_STRING_SIZE
86  #define AV_ERROR_MAX_STRING_SIZE 64
87 #endif
88 #ifndef AUDIO_PACKET_ENCODING_SIZE
89  // 48khz * S16 (2 bytes) * max channels (8)
90  #define AUDIO_PACKET_ENCODING_SIZE 768000
91 #endif
92 
93 // This wraps an unsafe C macro to be C++ compatible function
94 inline static const std::string av_err2string(int errnum)
95 {
96  char errbuf[AV_ERROR_MAX_STRING_SIZE];
97  av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE);
98  return static_cast<std::string>(errbuf);
99 }
100 
101 // Redefine the C macro to use our new C++ function
102 #undef av_err2str
103 #define av_err2str(errnum) av_err2string(errnum).c_str()
104 
105 // Define this for compatibility
106 #ifndef PixelFormat
107  #define PixelFormat AVPixelFormat
108 #endif
109 #ifndef PIX_FMT_RGBA
110  #define PIX_FMT_RGBA AV_PIX_FMT_RGBA
111 #endif
112 #ifndef PIX_FMT_NONE
113  #define PIX_FMT_NONE AV_PIX_FMT_NONE
114 #endif
115 #ifndef PIX_FMT_RGB24
116  #define PIX_FMT_RGB24 AV_PIX_FMT_RGB24
117 #endif
118 #ifndef PIX_FMT_YUV420P
119  #define PIX_FMT_YUV420P AV_PIX_FMT_YUV420P
120 #endif
121 #ifndef PIX_FMT_YUV444P
122  #define PIX_FMT_YUV444P AV_PIX_FMT_YUV444P
123 #endif
124 #ifndef AV_PROFILE_H264_BASELINE
125  #ifdef FF_PROFILE_H264_BASELINE
126  #define AV_PROFILE_H264_BASELINE FF_PROFILE_H264_BASELINE
127  #endif
128 #endif
129 #ifndef AV_PROFILE_H264_CONSTRAINED
130  #ifdef FF_PROFILE_H264_CONSTRAINED
131  #define AV_PROFILE_H264_CONSTRAINED FF_PROFILE_H264_CONSTRAINED
132  #endif
133 #endif
134 #ifndef AV_PROFILE_H264_CONSTRAINED_BASELINE
135  #if defined(AV_PROFILE_H264_BASELINE) && defined(AV_PROFILE_H264_CONSTRAINED)
136  #define AV_PROFILE_H264_CONSTRAINED_BASELINE (AV_PROFILE_H264_BASELINE | AV_PROFILE_H264_CONSTRAINED)
137  #elif defined(FF_PROFILE_H264_CONSTRAINED_BASELINE)
138  #define AV_PROFILE_H264_CONSTRAINED_BASELINE FF_PROFILE_H264_CONSTRAINED_BASELINE
139  #endif
140 #endif
141 
142 // Does ffmpeg pixel format contain an alpha channel?
143 inline static bool ffmpeg_has_alpha(PixelFormat pix_fmt) {
144  const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(pix_fmt);
145  return bool(fmt_desc->flags & AV_PIX_FMT_FLAG_ALPHA);
146 }
147 
148 // Allocate and populate an AVCodecContext from stream codec parameters.
149 inline static AVCodecContext* ffmpeg_get_codec_context(AVStream *av_stream, const AVCodec *av_codec) {
150  AVCodecContext *context = avcodec_alloc_context3(av_codec);
151  if (context)
152  avcodec_parameters_to_context(context, av_stream->codecpar);
153  return context;
154 }
155 
156 #if HAVE_CH_LAYOUT
157 inline static AVChannelLayout ffmpeg_default_channel_layout(int channels) {
158  AVChannelLayout layout = {};
159  if (channels > 0)
160  av_channel_layout_default(&layout, channels);
161  return layout;
162 }
163 
164 inline static AVChannelLayout ffmpeg_get_valid_channel_layout(
165  const AVChannelLayout &layout, int fallback_channels) {
166  AVChannelLayout normalized = {};
167  if (layout.nb_channels > 0 && av_channel_layout_check(&layout) == 1) {
168  av_channel_layout_copy(&normalized, &layout);
169  return normalized;
170  }
171  return ffmpeg_default_channel_layout(fallback_channels);
172 }
173 
174 inline static uint64_t ffmpeg_channel_layout_mask(const AVChannelLayout &layout) {
175  return layout.order == AV_CHANNEL_ORDER_NATIVE ? layout.u.mask : 0;
176 }
177 #endif
178 
179 // Access stream side data across FFmpeg API changes.
180 inline static const uint8_t* ffmpeg_stream_get_side_data(
181  const AVStream *stream, enum AVPacketSideDataType type, size_t *size) {
182 #if (LIBAVFORMAT_VERSION_MAJOR >= 61)
183  const AVPacketSideData *side_data = av_packet_side_data_get(
184  stream->codecpar->coded_side_data,
185  stream->codecpar->nb_coded_side_data,
186  type);
187  if (!side_data) {
188  if (size)
189  *size = 0;
190  return nullptr;
191  }
192  if (size)
193  *size = side_data->size;
194  return side_data->data;
195 #else
196  #if defined(__GNUC__) || defined(__clang__)
197  #pragma GCC diagnostic push
198  #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
199  #endif
200  #if (LIBAVFORMAT_VERSION_MAJOR >= 59)
201  const uint8_t *data = av_stream_get_side_data(stream, type, size);
202  #else
203  int old_size = 0;
204  const uint8_t *data = av_stream_get_side_data(
205  const_cast<AVStream*>(stream), type, &old_size);
206  if (size)
207  *size = old_size >= 0 ? static_cast<size_t>(old_size) : 0;
208  #endif
209  #if defined(__GNUC__) || defined(__clang__)
210  #pragma GCC diagnostic pop
211  #endif
212  return data;
213 #endif
214 }
215 
216 // Add stream side data across FFmpeg API changes.
217 inline static int ffmpeg_stream_add_side_data(
218  AVStream *stream, enum AVPacketSideDataType type, uint8_t *data, size_t size) {
219 #if (LIBAVFORMAT_VERSION_MAJOR >= 61)
220  AVPacketSideData *side_data = av_packet_side_data_add(
221  &stream->codecpar->coded_side_data,
222  &stream->codecpar->nb_coded_side_data,
223  type,
224  data,
225  size,
226  0);
227  return side_data ? 0 : AVERROR(ENOMEM);
228 #else
229  #if defined(__GNUC__) || defined(__clang__)
230  #pragma GCC diagnostic push
231  #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
232  #endif
233  int result = av_stream_add_side_data(stream, type, data, size);
234  #if defined(__GNUC__) || defined(__clang__)
235  #pragma GCC diagnostic pop
236  #endif
237  return result;
238 #endif
239 }
240 
241 // FFmpeg's libavutil/common.h defines an RSHIFT incompatible with Ruby's
242 // definition in ruby/config.h, so we move it to FF_RSHIFT
243 #ifdef RSHIFT
244  #define FF_RSHIFT(a, b) RSHIFT(a, b)
245  #undef RSHIFT
246 #endif
247 
248 // libswresample/libavresample API switching
249 #if USE_SW
250  #define SWR_CONVERT(ctx, out, linesize, out_count, in, linesize2, in_count) \
251  swr_convert(ctx, out, out_count, (const uint8_t **)in, in_count)
252  #define SWR_ALLOC() swr_alloc()
253  #define SWR_CLOSE(ctx) {}
254  #define SWR_FREE(ctx) swr_free(ctx)
255  #define SWR_INIT(ctx) swr_init(ctx)
256  #define SWRCONTEXT SwrContext
257 
258 #else
259  #define SWR_CONVERT(ctx, out, linesize, out_count, in, linesize2, in_count) \
260  avresample_convert(ctx, out, linesize, out_count, (uint8_t **)in, linesize2, in_count)
261  #define SWR_ALLOC() avresample_alloc_context()
262  #define SWR_CLOSE(ctx) avresample_close(ctx)
263  #define SWR_FREE(ctx) avresample_free(ctx)
264  #define SWR_INIT(ctx) avresample_open(ctx)
265  #define SWRCONTEXT AVAudioResampleContext
266 #endif
267 
268 
269 #if (LIBAVFORMAT_VERSION_MAJOR >= 58)
270  #define AV_REGISTER_ALL
271  #define AVCODEC_REGISTER_ALL
272  #define AV_FILENAME url
273  #define AV_SET_FILENAME(oc, f) oc->AV_FILENAME = av_strdup(f)
274  #define MY_INPUT_BUFFER_PADDING_SIZE AV_INPUT_BUFFER_PADDING_SIZE
275  #define AV_ALLOCATE_FRAME() av_frame_alloc()
276  #define AV_ALLOCATE_IMAGE(av_frame, pix_fmt, width, height) \
277  av_image_alloc(av_frame->data, av_frame->linesize, width, height, pix_fmt, 32)
278  #define AV_RESET_FRAME(av_frame) av_frame_unref(av_frame)
279  #define AV_FREE_FRAME(av_frame) av_frame_free(av_frame)
280  #define AV_FREE_PACKET(av_packet) av_packet_unref(av_packet)
281  #define AV_FREE_CONTEXT(av_context) avcodec_free_context(&av_context)
282  #define AV_GET_CODEC_TYPE(av_stream) av_stream->codecpar->codec_type
283  #define AV_FIND_DECODER_CODEC_ID(av_stream) av_stream->codecpar->codec_id
284  #define AV_GET_CODEC_CONTEXT(av_stream, av_codec) ffmpeg_get_codec_context(av_stream, av_codec)
285  #define AV_GET_CODEC_PAR_CONTEXT(av_stream, av_codec) av_codec;
286  #define AV_GET_CODEC_FROM_STREAM(av_stream,codec_in)
287  #define AV_GET_CODEC_ATTRIBUTES(av_stream, av_context) av_stream->codecpar
288  #define AV_GET_CODEC_PIXEL_FORMAT(av_stream, av_context) (AVPixelFormat) av_stream->codecpar->format
289  #define AV_GET_SAMPLE_FORMAT(av_stream, av_context) av_stream->codecpar->format
290  #define AV_GET_IMAGE_SIZE(pix_fmt, width, height) \
291  av_image_get_buffer_size(pix_fmt, width, height, 1)
292  #define AV_COPY_PICTURE_DATA(av_frame, buffer, pix_fmt, width, height) \
293  av_image_fill_arrays(av_frame->data, av_frame->linesize, buffer, pix_fmt, width, height, 1)
294  #define AV_OUTPUT_CONTEXT(output_context, path) avformat_alloc_output_context2( output_context, NULL, NULL, path)
295  #define AV_OPTION_FIND(priv_data, name) av_opt_find(priv_data, name, NULL, 0, 0)
296  #define AV_OPTION_SET( av_stream, priv_data, name, value, avcodec) \
297  av_opt_set(priv_data, name, value, 0); \
298  avcodec_parameters_from_context(av_stream->codecpar, avcodec);
299  #define ALLOC_CODEC_CTX(ctx, codec, stream) \
300  ctx = avcodec_alloc_context3(codec);
301  #define AV_COPY_PARAMS_FROM_CONTEXT(av_stream, av_codec_ctx) \
302  avcodec_parameters_from_context(av_stream->codecpar, av_codec_ctx);
303 
304 #elif IS_FFMPEG_3_2
305  #define AV_REGISTER_ALL av_register_all();
306  #define AVCODEC_REGISTER_ALL avcodec_register_all();
307  #define AV_FILENAME filename
308  #define AV_SET_FILENAME(oc, f) snprintf(oc->AV_FILENAME, sizeof(oc->AV_FILENAME), "%s", f)
309  #define MY_INPUT_BUFFER_PADDING_SIZE FF_INPUT_BUFFER_PADDING_SIZE
310  #define AV_ALLOCATE_FRAME() av_frame_alloc()
311  #define AV_ALLOCATE_IMAGE(av_frame, pix_fmt, width, height) \
312  av_image_alloc(av_frame->data, av_frame->linesize, width, height, pix_fmt, 32)
313  #define AV_RESET_FRAME(av_frame) av_frame_unref(av_frame)
314  #define AV_FREE_FRAME(av_frame) av_frame_free(av_frame)
315  #define AV_FREE_PACKET(av_packet) av_packet_unref(av_packet)
316  #define AV_FREE_CONTEXT(av_context) avcodec_free_context(&av_context)
317  #define AV_GET_CODEC_TYPE(av_stream) av_stream->codecpar->codec_type
318  #define AV_FIND_DECODER_CODEC_ID(av_stream) av_stream->codecpar->codec_id
319  #define AV_GET_CODEC_CONTEXT(av_stream, av_codec) ffmpeg_get_codec_context(av_stream, av_codec)
320  #define AV_GET_CODEC_PAR_CONTEXT(av_stream, av_codec) av_codec;
321  #define AV_GET_CODEC_FROM_STREAM(av_stream,codec_in)
322  #define AV_GET_CODEC_ATTRIBUTES(av_stream, av_context) av_stream->codecpar
323  #define AV_GET_CODEC_PIXEL_FORMAT(av_stream, av_context) \
324  (AVPixelFormat) av_stream->codecpar->format
325  #define AV_GET_SAMPLE_FORMAT(av_stream, av_context) av_stream->codecpar->format
326  #define AV_GET_IMAGE_SIZE(pix_fmt, width, height) av_image_get_buffer_size(pix_fmt, width, height, 1)
327  #define AV_COPY_PICTURE_DATA(av_frame, buffer, pix_fmt, width, height) \
328  av_image_fill_arrays(av_frame->data, av_frame->linesize, buffer, pix_fmt, width, height, 1)
329  #define AV_OUTPUT_CONTEXT(output_context, path) \
330  avformat_alloc_output_context2( output_context, NULL, NULL, path)
331  #define AV_OPTION_FIND(priv_data, name) av_opt_find(priv_data, name, NULL, 0, 0)
332  #define AV_OPTION_SET( av_stream, priv_data, name, value, avcodec) \
333  av_opt_set(priv_data, name, value, 0); \
334  avcodec_parameters_from_context(av_stream->codecpar, avcodec);
335  #define ALLOC_CODEC_CTX(ctx, codec, stream) \
336  ctx = avcodec_alloc_context3(codec);
337  #define AV_COPY_PARAMS_FROM_CONTEXT(av_stream, av_codec) \
338  avcodec_parameters_from_context(av_stream->codecpar, av_codec);
339 
340 #elif LIBAVFORMAT_VERSION_MAJOR >= 55
341  #define AV_REGISTER_ALL av_register_all();
342  #define AVCODEC_REGISTER_ALL avcodec_register_all();
343  #define AV_FILENAME filename
344  #define AV_SET_FILENAME(oc, f) snprintf(oc->AV_FILENAME, sizeof(oc->AV_FILENAME), "%s", f)
345  #define MY_INPUT_BUFFER_PADDING_SIZE FF_INPUT_BUFFER_PADDING_SIZE
346  #define AV_ALLOCATE_FRAME() av_frame_alloc()
347  #define AV_ALLOCATE_IMAGE(av_frame, pix_fmt, width, height) \
348  avpicture_alloc((AVPicture *) av_frame, pix_fmt, width, height)
349  #define AV_RESET_FRAME(av_frame) av_frame_unref(av_frame)
350  #define AV_FREE_FRAME(av_frame) av_frame_free(av_frame)
351  #define AV_FREE_PACKET(av_packet) av_packet_unref(av_packet)
352  #define AV_FREE_CONTEXT(av_context) avcodec_close(av_context)
353  #define AV_GET_CODEC_TYPE(av_stream) av_stream->codec->codec_type
354  #define AV_FIND_DECODER_CODEC_ID(av_stream) av_stream->codec->codec_id
355  #define AV_GET_CODEC_CONTEXT(av_stream, av_codec) av_stream->codec
356  #define AV_GET_CODEC_PAR_CONTEXT(av_stream, av_codec) av_stream->codec
357  #define AV_GET_CODEC_FROM_STREAM(av_stream, codec_in) codec_in = av_stream->codec;
358  #define AV_GET_CODEC_ATTRIBUTES(av_stream, av_context) av_context
359  #define AV_GET_CODEC_PIXEL_FORMAT(av_stream, av_context) av_context->pix_fmt
360  #define AV_GET_SAMPLE_FORMAT(av_stream, av_context) av_context->sample_fmt
361  #define AV_GET_IMAGE_SIZE(pix_fmt, width, height) avpicture_get_size(pix_fmt, width, height)
362  #define AV_COPY_PICTURE_DATA(av_frame, buffer, pix_fmt, width, height) \
363  avpicture_fill((AVPicture *) av_frame, buffer, pix_fmt, width, height)
364  #define AV_OUTPUT_CONTEXT(output_context, path) oc = avformat_alloc_context()
365  #define AV_OPTION_FIND(priv_data, name) av_opt_find(priv_data, name, NULL, 0, 0)
366  #define AV_OPTION_SET(av_stream, priv_data, name, value, avcodec) av_opt_set (priv_data, name, value, 0)
367  #define ALLOC_CODEC_CTX(ctx, av_codec, stream) \
368  avcodec_get_context_defaults3(av_st->codec, av_codec); \
369  ctx = av_st->codec;
370  #define AV_COPY_PARAMS_FROM_CONTEXT(av_stream, av_codec)
371 
372 #else
373  #define AV_REGISTER_ALL av_register_all();
374  #define AVCODEC_REGISTER_ALL avcodec_register_all();
375  #define AV_FILENAME filename
376  #define AV_SET_FILENAME(oc, f) snprintf(oc->AV_FILENAME, sizeof(oc->AV_FILENAME), "%s", f)
377  #define MY_INPUT_BUFFER_PADDING_SIZE FF_INPUT_BUFFER_PADDING_SIZE
378  #define AV_ALLOCATE_FRAME() avcodec_alloc_frame()
379  #define AV_ALLOCATE_IMAGE(av_frame, pix_fmt, width, height) \
380  avpicture_alloc((AVPicture *) av_frame, pix_fmt, width, height)
381  #define AV_RESET_FRAME(av_frame) avcodec_get_frame_defaults(av_frame)
382  #define AV_FREE_FRAME(av_frame) avcodec_free_frame(av_frame)
383  #define AV_FREE_PACKET(av_packet) av_free_packet(av_packet)
384  #define AV_FREE_CONTEXT(av_context) avcodec_close(av_context)
385  #define AV_GET_CODEC_TYPE(av_stream) av_stream->codec->codec_type
386  #define AV_FIND_DECODER_CODEC_ID(av_stream) av_stream->codec->codec_id
387  #define AV_GET_CODEC_CONTEXT(av_stream, av_codec) av_stream->codec
388  #define AV_GET_CODEC_PAR_CONTEXT(av_stream, av_codec) av_stream->codec
389  #define AV_GET_CODEC_FROM_STREAM(av_stream, codec_in ) codec_in = av_stream->codec;
390  #define AV_GET_CODEC_ATTRIBUTES(av_stream, av_context) av_context
391  #define AV_GET_CODEC_PIXEL_FORMAT(av_stream, av_context) av_context->pix_fmt
392  #define AV_GET_SAMPLE_FORMAT(av_stream, av_context) av_context->sample_fmt
393  #define AV_GET_IMAGE_SIZE(pix_fmt, width, height) avpicture_get_size(pix_fmt, width, height)
394  #define AV_COPY_PICTURE_DATA(av_frame, buffer, pix_fmt, width, height) \
395  avpicture_fill((AVPicture *) av_frame, buffer, pix_fmt, width, height)
396  #define AV_OUTPUT_CONTEXT(output_context, path) oc = avformat_alloc_context()
397  #define AV_OPTION_FIND(priv_data, name) av_opt_find(priv_data, name, NULL, 0, 0)
398  #define AV_OPTION_SET(av_stream, priv_data, name, value, avcodec) av_opt_set (priv_data, name, value, 0)
399  #define ALLOC_CODEC_CTX(ctx, av_codec, stream) \
400  avcodec_get_context_defaults3(stream->codec, av_codec); \
401  ctx = stream->codec;
402  #define AV_COPY_PARAMS_FROM_CONTEXT(av_stream, av_codec)
403 #endif
404 
405 // Aligned memory allocation helpers (cross-platform)
406 #if defined(_WIN32)
407 #include <malloc.h>
408 #endif
409 
410 inline static void* aligned_malloc(size_t size, size_t alignment = 32)
411 {
412 #if defined(_WIN32)
413  return _aligned_malloc(size, alignment);
414 #elif defined(__APPLE__) || defined(__linux__)
415  void* ptr = nullptr;
416  if (posix_memalign(&ptr, alignment, size) != 0)
417  return nullptr;
418  return ptr;
419 #else
420 #error "aligned_malloc not implemented on this platform"
421 #endif
422 }
423 
424 #endif // OPENSHOT_FFMPEG_UTILITIES_H
PixelFormat
#define PixelFormat
Definition: FFmpegUtilities.h:107
OpenShotVersion.h
Header file that includes the version number of libopenshot.
AV_ERROR_MAX_STRING_SIZE
#define AV_ERROR_MAX_STRING_SIZE
Definition: FFmpegUtilities.h:86