1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#ifndef QFFMPEG_P_H
4#define QFFMPEG_P_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17#include "qffmpegdefs_p.h"
18#include "qffmpegavaudioformat_p.h"
19#include <QtMultimedia/qvideoframeformat.h>
20
21#include <qstring.h>
22#include <optional>
23
24inline bool operator==(const AVRational &lhs, const AVRational &rhs)
25{
26 return lhs.num == rhs.num && lhs.den == rhs.den;
27}
28
29inline bool operator!=(const AVRational &lhs, const AVRational &rhs)
30{
31 return !(lhs == rhs);
32}
33
34QT_BEGIN_NAMESPACE
35
36namespace QFFmpeg
37{
38
39inline std::optional<qint64> mul(qint64 a, AVRational b)
40{
41 return b.den != 0 ? (a * b.num + b.den / 2) / b.den : std::optional<qint64>{};
42}
43
44inline std::optional<qreal> mul(qreal a, AVRational b)
45{
46 return b.den != 0 ? a * qreal(b.num) / qreal(b.den) : std::optional<qreal>{};
47}
48
49inline std::optional<qint64> timeStampMs(qint64 ts, AVRational base)
50{
51 return mul(a: 1'000 * ts, b: base);
52}
53
54inline std::optional<qint64> timeStampUs(qint64 ts, AVRational base)
55{
56 return mul(a: 1'000'000 * ts, b: base);
57}
58
59inline std::optional<float> toFloat(AVRational r)
60{
61 return r.den != 0 ? float(r.num) / float(r.den) : std::optional<float>{};
62}
63
64inline QString err2str(int errnum)
65{
66 char buffer[AV_ERROR_MAX_STRING_SIZE + 1] = {};
67 av_make_error_string(errbuf: buffer, AV_ERROR_MAX_STRING_SIZE, errnum);
68 return QString::fromLocal8Bit(ba: buffer);
69}
70
71inline void setAVFrameTime(AVFrame &frame, int64_t pts, const AVRational &timeBase)
72{
73 frame.pts = pts;
74#if QT_FFMPEG_HAS_FRAME_TIME_BASE
75 frame.time_base = timeBase;
76#else
77 Q_UNUSED(timeBase);
78#endif
79}
80
81inline void getAVFrameTime(const AVFrame &frame, int64_t &pts, AVRational &timeBase)
82{
83 pts = frame.pts;
84#if QT_FFMPEG_HAS_FRAME_TIME_BASE
85 timeBase = frame.time_base;
86#else
87 timeBase = { .num: 0, .den: 1 };
88#endif
89}
90
91inline int64_t getAVFrameDuration(const AVFrame &frame)
92{
93#if QT_FFMPEG_HAS_FRAME_DURATION
94 return frame.duration;
95#else
96 Q_UNUSED(frame);
97 return 0;
98#endif
99}
100
101#if QT_FFMPEG_HAS_AVCODEC_GET_SUPPORTED_CONFIG
102void logGetCodecConfigError(const AVCodec *codec, AVCodecConfig config, int error);
103
104template <typename T>
105inline const T *getCodecConfig(const AVCodec *codec, AVCodecConfig config)
106{
107 const T *result = nullptr;
108 const auto error = avcodec_get_supported_config(
109 nullptr, codec, config, 0u, reinterpret_cast<const void **>(&result), nullptr);
110 if (error != 0) {
111 logGetCodecConfigError(codec, config, error);
112 return nullptr;
113 }
114 return result;
115}
116#endif
117
118inline const AVPixelFormat *getCodecPixelFormats(const AVCodec *codec)
119{
120#if QT_FFMPEG_HAS_AVCODEC_GET_SUPPORTED_CONFIG
121 return getCodecConfig<AVPixelFormat>(codec, AV_CODEC_CONFIG_PIX_FORMAT);
122#else
123 return codec->pix_fmts;
124#endif
125}
126
127inline const AVSampleFormat *getCodecSampleFormats(const AVCodec *codec)
128{
129#if QT_FFMPEG_HAS_AVCODEC_GET_SUPPORTED_CONFIG
130 return getCodecConfig<AVSampleFormat>(codec, AV_CODEC_CONFIG_SAMPLE_FORMAT);
131#else
132 return codec->sample_fmts;
133#endif
134}
135
136inline const int *getCodecSampleRates(const AVCodec *codec)
137{
138#if QT_FFMPEG_HAS_AVCODEC_GET_SUPPORTED_CONFIG
139 return getCodecConfig<int>(codec, AV_CODEC_CONFIG_SAMPLE_RATE);
140#else
141 return codec->supported_samplerates;
142#endif
143}
144
145#if QT_FFMPEG_HAS_AV_CHANNEL_LAYOUT
146
147inline const AVChannelLayout *getCodecChannelLayouts(const AVCodec *codec)
148{
149#if QT_FFMPEG_HAS_AVCODEC_GET_SUPPORTED_CONFIG
150 return getCodecConfig<AVChannelLayout>(codec, AV_CODEC_CONFIG_CHANNEL_LAYOUT);
151#else
152 return codec->ch_layouts;
153#endif
154}
155
156#else
157
158inline const uint64_t *getCodecChannelLayouts(const AVCodec *codec)
159{
160 return codec->channel_layouts;
161}
162
163#endif
164
165inline const AVRational *getCodecFrameRates(const AVCodec *codec)
166{
167#if QT_FFMPEG_HAS_AVCODEC_GET_SUPPORTED_CONFIG
168 return getCodecConfig<AVRational>(codec, AV_CODEC_CONFIG_FRAME_RATE);
169#else
170 return codec->supported_framerates;
171#endif
172}
173
174struct AVDictionaryHolder
175{
176 AVDictionary *opts = nullptr;
177
178 operator AVDictionary **() { return &opts; }
179
180 AVDictionaryHolder() = default;
181
182 Q_DISABLE_COPY(AVDictionaryHolder)
183
184 AVDictionaryHolder(AVDictionaryHolder &&other) noexcept
185 : opts(std::exchange(obj&: other.opts, new_val: nullptr))
186 {
187 }
188
189 ~AVDictionaryHolder()
190 {
191 if (opts)
192 av_dict_free(m: &opts);
193 }
194};
195
196template<typename FunctionType, FunctionType F>
197struct AVDeleter
198{
199 template <typename T, std::invoke_result_t<FunctionType, T **> * = nullptr>
200 void operator()(T *object) const
201 {
202 if (object)
203 F(&object);
204 }
205
206 template <typename T, std::invoke_result_t<FunctionType, T *> * = nullptr>
207 void operator()(T *object) const
208 {
209 F(object);
210 }
211};
212
213using AVFrameUPtr = std::unique_ptr<AVFrame, AVDeleter<decltype(&av_frame_free), &av_frame_free>>;
214
215inline AVFrameUPtr makeAVFrame()
216{
217 return AVFrameUPtr(av_frame_alloc());
218}
219
220using AVPacketUPtr =
221 std::unique_ptr<AVPacket, AVDeleter<decltype(&av_packet_free), &av_packet_free>>;
222
223using AVCodecContextUPtr =
224 std::unique_ptr<AVCodecContext,
225 AVDeleter<decltype(&avcodec_free_context), &avcodec_free_context>>;
226
227using AVBufferUPtr =
228 std::unique_ptr<AVBufferRef, AVDeleter<decltype(&av_buffer_unref), &av_buffer_unref>>;
229
230using AVHWFramesConstraintsUPtr = std::unique_ptr<
231 AVHWFramesConstraints,
232 AVDeleter<decltype(&av_hwframe_constraints_free), &av_hwframe_constraints_free>>;
233
234using SwrContextUPtr = std::unique_ptr<SwrContext, AVDeleter<decltype(&swr_free), &swr_free>>;
235
236using SwsContextUPtr =
237 std::unique_ptr<SwsContext, AVDeleter<decltype(&sws_freeContext), &sws_freeContext>>;
238
239template <typename T>
240inline constexpr auto InvalidAvValue = T{};
241
242template<>
243inline constexpr auto InvalidAvValue<AVSampleFormat> = AV_SAMPLE_FMT_NONE;
244
245template<>
246inline constexpr auto InvalidAvValue<AVPixelFormat> = AV_PIX_FMT_NONE;
247
248bool isAVFormatSupported(const AVCodec *codec, PixelOrSampleFormat format);
249
250template <typename Format>
251bool hasAVValue(const Format *fmts, Format format)
252{
253 return findAVValue(fmts, [format](Format f) { return f == format; }) != InvalidAvValue<Format>;
254}
255
256template <typename AVValue, typename Predicate>
257AVValue findAVValue(const AVValue *fmts, const Predicate &predicate)
258{
259 auto scoresGetter = [&predicate](AVValue value) {
260 return predicate(value) ? BestAVScore : NotSuitableAVScore;
261 };
262 return findBestAVValue(fmts, scoresGetter).first;
263}
264
265template <typename Predicate>
266const AVCodecHWConfig *findHwConfig(const AVCodec *codec, const Predicate &predicate)
267{
268 for (int i = 0; const auto hwConfig = avcodec_get_hw_config(codec, index: i); ++i) {
269 if (predicate(hwConfig))
270 return hwConfig;
271 }
272
273 return nullptr;
274}
275
276template <typename Predicate>
277AVPixelFormat findAVPixelFormat(const AVCodec *codec, const Predicate &predicate)
278{
279 const auto pixelFormats = getCodecPixelFormats(codec);
280 const AVPixelFormat format = findAVValue(pixelFormats, predicate);
281 if (format != AV_PIX_FMT_NONE)
282 return format;
283
284 auto checkHwConfig = [&predicate](const AVCodecHWConfig *config) {
285 return config->pix_fmt != AV_PIX_FMT_NONE && predicate(config->pix_fmt);
286 };
287
288 if (auto hwConfig = findHwConfig(codec, checkHwConfig))
289 return hwConfig->pix_fmt;
290
291 return AV_PIX_FMT_NONE;
292}
293
294template <typename Value, typename CalculateScore>
295auto findBestAVValue(const Value *values, const CalculateScore &calculateScore)
296{
297 using Limits = std::numeric_limits<decltype(calculateScore(*values))>;
298
299 const Value invalidValue = InvalidAvValue<Value>;
300 std::pair result(invalidValue, Limits::min());
301 if (values) {
302
303 for (; *values != invalidValue && result.second != Limits::max(); ++values) {
304 const auto score = calculateScore(*values);
305 if (score > result.second)
306 result = { *values, score };
307 }
308 }
309
310 return result;
311}
312
313bool isHwPixelFormat(AVPixelFormat format);
314
315inline bool isSwPixelFormat(AVPixelFormat format)
316{
317 return !isHwPixelFormat(format);
318}
319
320bool isAVCodecExperimental(const AVCodec *codec);
321
322void applyExperimentalCodecOptions(const AVCodec *codec, AVDictionary** opts);
323
324AVPixelFormat pixelFormatForHwDevice(AVHWDeviceType deviceType);
325
326AVPacketSideData *addStreamSideData(AVStream *stream, AVPacketSideData sideData);
327
328const AVPacketSideData *streamSideData(const AVStream *stream, AVPacketSideDataType type);
329
330SwrContextUPtr createResampleContext(const AVAudioFormat &inputFormat,
331 const AVAudioFormat &outputFormat);
332
333QVideoFrameFormat::ColorTransfer fromAvColorTransfer(AVColorTransferCharacteristic colorTrc);
334
335AVColorTransferCharacteristic toAvColorTransfer(QVideoFrameFormat::ColorTransfer colorTrc);
336
337QVideoFrameFormat::ColorSpace fromAvColorSpace(AVColorSpace colorSpace);
338
339AVColorSpace toAvColorSpace(QVideoFrameFormat::ColorSpace colorSpace);
340
341QVideoFrameFormat::ColorRange fromAvColorRange(AVColorRange colorRange);
342
343AVColorRange toAvColorRange(QVideoFrameFormat::ColorRange colorRange);
344
345AVHWDeviceContext *avFrameDeviceContext(const AVFrame *frame);
346
347SwsContextUPtr createSwsContext(const QSize &srcSize, AVPixelFormat srcPixFmt, const QSize &dstSize,
348 AVPixelFormat dstPixFmt, int conversionType = SWS_BICUBIC);
349
350#ifdef Q_OS_DARWIN
351bool isCVFormatSupported(uint32_t format);
352
353std::string cvFormatToString(uint32_t format);
354
355#endif
356}
357
358QDebug operator<<(QDebug, const AVRational &);
359
360#if QT_FFMPEG_HAS_AV_CHANNEL_LAYOUT
361QDebug operator<<(QDebug, const AVChannelLayout &);
362#endif
363
364QT_END_NAMESPACE
365
366#endif
367

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtmultimedia/src/plugins/multimedia/ffmpeg/qffmpeg_p.h