Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qffmpeg.cpp
Go to the documentation of this file.
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
4#include "qffmpeg_p.h"
5
6#include <qdebug.h>
7#include <qloggingcategory.h>
8#include <qffmpeghwaccel_p.h> // TODO: probably decompose HWAccel and get rid of the header in the base utils
9
10#include <algorithm>
11#include <vector>
12#include <array>
13#include <optional>
14#include <unordered_set>
15
16extern "C" {
17#include <libavutil/pixdesc.h>
18#include <libavutil/samplefmt.h>
19
20#ifdef Q_OS_DARWIN
21#include <libavutil/hwcontext_videotoolbox.h>
22#endif
23}
24
25#ifdef Q_OS_ANDROID
26#include <QtCore/qjniobject.h>
27#include <QtCore/qjniarray.h>
28#include <QtCore/qjnitypes.h>
29#endif
30
32
33#ifdef Q_OS_ANDROID
35 "org/qtproject/qt/android/multimedia/QtVideoDeviceManager");
36Q_DECLARE_JNI_CLASS(String, "java/lang/String");
37#endif
38
39static Q_LOGGING_CATEGORY(qLcFFmpegUtils, "qt.multimedia.ffmpeg.utils");
40
41namespace QFFmpeg {
42
43namespace {
44
45enum CodecStorageType {
46 ENCODERS,
47 DECODERS,
48
49 // TODO: maybe split sw/hw codecs
50
51 CODEC_STORAGE_TYPE_COUNT
52};
53
54using CodecsStorage = std::vector<const AVCodec *>;
55
56struct CodecsComparator
57{
58 bool operator()(const AVCodec *a, const AVCodec *b) const
59 {
60 return a->id < b->id
61 || (a->id == b->id && isAVCodecExperimental(a) < isAVCodecExperimental(b));
62 }
63
64 bool operator()(const AVCodec *a, AVCodecID id) const { return a->id < id; }
65};
66
67template<typename FlagNames>
68QString flagsToString(int flags, const FlagNames &flagNames)
69{
71 int leftover = flags;
72 for (const auto &flagAndName : flagNames)
73 if ((flags & flagAndName.first) != 0) {
74 leftover &= ~flagAndName.first;
75 if (!result.isEmpty())
76 result += ", ";
77 result += flagAndName.second;
78 }
79
80 if (leftover) {
81 if (!result.isEmpty())
82 result += ", ";
83 result += QString::number(leftover, 16);
84 }
85 return result;
86}
87
88void dumpCodecInfo(const AVCodec *codec)
89{
90 using FlagNames = std::initializer_list<std::pair<int, const char *>>;
91 const auto mediaType = codec->type == AVMEDIA_TYPE_VIDEO ? "video"
92 : codec->type == AVMEDIA_TYPE_AUDIO ? "audio"
93 : codec->type == AVMEDIA_TYPE_SUBTITLE ? "subtitle"
94 : "other_type";
95
96 const auto type = av_codec_is_encoder(codec)
97 ? av_codec_is_decoder(codec) ? "encoder/decoder:" : "encoder:"
98 : "decoder:";
99
100 static const FlagNames capabilitiesNames = {
101 { AV_CODEC_CAP_DRAW_HORIZ_BAND, "DRAW_HORIZ_BAND" },
102 { AV_CODEC_CAP_DR1, "DRAW_HORIZ_DR1" },
103 { AV_CODEC_CAP_DELAY, "DELAY" },
104 { AV_CODEC_CAP_SMALL_LAST_FRAME, "SMALL_LAST_FRAME" },
105 { AV_CODEC_CAP_SUBFRAMES, "SUBFRAMES" },
106 { AV_CODEC_CAP_EXPERIMENTAL, "EXPERIMENTAL" },
107 { AV_CODEC_CAP_CHANNEL_CONF, "CHANNEL_CONF" },
108 { AV_CODEC_CAP_FRAME_THREADS, "FRAME_THREADS" },
109 { AV_CODEC_CAP_SLICE_THREADS, "SLICE_THREADS" },
110 { AV_CODEC_CAP_PARAM_CHANGE, "PARAM_CHANGE" },
111#ifdef AV_CODEC_CAP_OTHER_THREADS
112 { AV_CODEC_CAP_OTHER_THREADS, "OTHER_THREADS" },
113#endif
114 { AV_CODEC_CAP_VARIABLE_FRAME_SIZE, "VARIABLE_FRAME_SIZE" },
115 { AV_CODEC_CAP_AVOID_PROBING, "AVOID_PROBING" },
116 { AV_CODEC_CAP_HARDWARE, "HARDWARE" },
117 { AV_CODEC_CAP_HYBRID, "HYBRID" },
118 { AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, "ENCODER_REORDERED_OPAQUE" },
119#ifdef AV_CODEC_CAP_ENCODER_FLUSH
120 { AV_CODEC_CAP_ENCODER_FLUSH, "ENCODER_FLUSH" },
121#endif
122 };
123
124 qCDebug(qLcFFmpegUtils) << mediaType << type << codec->name << "id:" << codec->id
125 << "capabilities:"
126 << flagsToString(codec->capabilities, capabilitiesNames);
127
128 if (codec->pix_fmts) {
129 static const FlagNames flagNames = {
130 { AV_PIX_FMT_FLAG_BE, "BE" },
131 { AV_PIX_FMT_FLAG_PAL, "PAL" },
132 { AV_PIX_FMT_FLAG_BITSTREAM, "BITSTREAM" },
133 { AV_PIX_FMT_FLAG_HWACCEL, "HWACCEL" },
134 { AV_PIX_FMT_FLAG_PLANAR, "PLANAR" },
135 { AV_PIX_FMT_FLAG_RGB, "RGB" },
136 { AV_PIX_FMT_FLAG_ALPHA, "ALPHA" },
137 { AV_PIX_FMT_FLAG_BAYER, "BAYER" },
138 { AV_PIX_FMT_FLAG_FLOAT, "FLOAT" },
139 };
140
141 qCDebug(qLcFFmpegUtils) << " pix_fmts:";
142 for (auto f = codec->pix_fmts; *f != AV_PIX_FMT_NONE; ++f) {
143 auto desc = av_pix_fmt_desc_get(*f);
144 qCDebug(qLcFFmpegUtils)
145 << " id:" << *f << desc->name << "depth:" << desc->comp[0].depth
146 << "flags:" << flagsToString(desc->flags, flagNames);
147 }
148 } else if (codec->type == AVMEDIA_TYPE_VIDEO) {
149 qCDebug(qLcFFmpegUtils) << " pix_fmts: null";
150 }
151
152 if (codec->sample_fmts) {
153 qCDebug(qLcFFmpegUtils) << " sample_fmts:";
154 for (auto f = codec->sample_fmts; *f != AV_SAMPLE_FMT_NONE; ++f) {
155 const auto name = av_get_sample_fmt_name(*f);
156 qCDebug(qLcFFmpegUtils) << " id:" << *f << (name ? name : "unknown")
157 << "bytes_per_sample:" << av_get_bytes_per_sample(*f)
158 << "is_planar:" << av_sample_fmt_is_planar(*f);
159 }
160 } else if (codec->type == AVMEDIA_TYPE_AUDIO) {
161 qCDebug(qLcFFmpegUtils) << " sample_fmts: null";
162 }
163
164 if (avcodec_get_hw_config(codec, 0)) {
165 static const FlagNames hwConfigMethodNames = {
166 { AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX, "HW_DEVICE_CTX" },
167 { AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX, "HW_FRAMES_CTX" },
168 { AV_CODEC_HW_CONFIG_METHOD_INTERNAL, "INTERNAL" },
169 { AV_CODEC_HW_CONFIG_METHOD_AD_HOC, "AD_HOC" }
170 };
171
172 qCDebug(qLcFFmpegUtils) << " hw config:";
173 for (int index = 0; auto config = avcodec_get_hw_config(codec, index); ++index) {
174 const auto pixFmtForDevice = pixelFormatForHwDevice(config->device_type);
175 auto pixFmtDesc = av_pix_fmt_desc_get(config->pix_fmt);
176 auto pixFmtForDeviceDesc = av_pix_fmt_desc_get(pixFmtForDevice);
177 qCDebug(qLcFFmpegUtils)
178 << " device_type:" << config->device_type << "pix_fmt:" << config->pix_fmt
179 << (pixFmtDesc ? pixFmtDesc->name : "unknown")
180 << "pixelFormatForHwDevice:" << pixelFormatForHwDevice(config->device_type)
181 << (pixFmtForDeviceDesc ? pixFmtForDeviceDesc->name : "unknown")
182 << "hw_config_methods:" << flagsToString(config->methods, hwConfigMethodNames);
183 }
184 }
185}
186
187bool isCodecValid(const AVCodec *codec, const std::vector<AVHWDeviceType> &availableHwDeviceTypes,
188 const std::optional<std::unordered_set<AVCodecID>> &codecAvailableOnDevice)
189{
190 if (codec->type != AVMEDIA_TYPE_VIDEO)
191 return true;
192
193 const auto pixFmts = codec->pix_fmts;
194
195 if (!pixFmts) {
196#if defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)
197 // Disable V4L2 M2M codecs for encoding for now,
198 // TODO: Investigate on how to get them working
199 if (std::strstr(codec->name, "_v4l2m2m") && av_codec_is_encoder(codec))
200 return false;
201
202 // MediaCodec in Android is used for hardware-accelerated media processing. That is why
203 // before marking it as valid, we need to make sure if it is available on current device.
204 if (std::strstr(codec->name, "_mediacodec")
205 && (codec->capabilities & AV_CODEC_CAP_HARDWARE)
206 && codecAvailableOnDevice && codecAvailableOnDevice->count(codec->id) == 0)
207 return false;
208#endif
209
210 return true; // To be investigated. This happens for RAW_VIDEO, that is supposed to be OK,
211 // and with v4l2m2m codecs, that is suspicious.
212 }
213
214 if (findAVFormat(pixFmts, &isHwPixelFormat) == AV_PIX_FMT_NONE)
215 return true;
216
217 if ((codec->capabilities & AV_CODEC_CAP_HARDWARE) == 0)
218 return true;
219
220 auto checkDeviceType = [pixFmts](AVHWDeviceType type) {
221 return hasAVFormat(pixFmts, pixelFormatForHwDevice(type));
222 };
223
224 if (codecAvailableOnDevice && codecAvailableOnDevice->count(codec->id) == 0)
225 return false;
226
227 return std::any_of(availableHwDeviceTypes.begin(), availableHwDeviceTypes.end(),
228 checkDeviceType);
229}
230
231std::optional<std::unordered_set<AVCodecID>> availableHWCodecs(const CodecStorageType type)
232{
233#ifdef Q_OS_ANDROID
234 using namespace Qt::StringLiterals;
235 std::unordered_set<AVCodecID> availabeCodecs;
236
237 auto getCodecId = [] (const QString& codecName) {
238 if (codecName == "3gpp"_L1) return AV_CODEC_ID_H263;
239 if (codecName == "avc"_L1) return AV_CODEC_ID_H264;
240 if (codecName == "hevc"_L1) return AV_CODEC_ID_HEVC;
241 if (codecName == "mp4v-es"_L1) return AV_CODEC_ID_MPEG4;
242 if (codecName == "x-vnd.on2.vp8"_L1) return AV_CODEC_ID_VP8;
243 if (codecName == "x-vnd.on2.vp9"_L1) return AV_CODEC_ID_VP9;
244 return AV_CODEC_ID_NONE;
245 };
246
247 const QJniObject jniCodecs =
248 QtJniTypes::QtVideoDeviceManager::callStaticMethod<QtJniTypes::String[]>(
249 type == ENCODERS ? "getHWVideoEncoders" : "getHWVideoDecoders");
250
251 QJniArray<QtJniTypes::String> arrCodecs(jniCodecs.object<jobjectArray>());
252 for (int i = 0; i < arrCodecs.size(); ++i) {
253 availabeCodecs.insert(getCodecId(arrCodecs.at(i).toString()));
254 }
255 return availabeCodecs;
256#else
257 Q_UNUSED(type);
258 return {};
259#endif
260}
261
262const CodecsStorage &codecsStorage(CodecStorageType codecsType)
263{
264 static const auto &storages = []() {
265 std::array<CodecsStorage, CODEC_STORAGE_TYPE_COUNT> result;
266 void *opaque = nullptr;
267 const auto platformHwEncoders = availableHWCodecs(ENCODERS);
268 const auto platformHwDecoders = availableHWCodecs(DECODERS);
269
270 while (auto codec = av_codec_iterate(&opaque)) {
271 // TODO: to be investigated
272 // FFmpeg functions avcodec_find_decoder/avcodec_find_encoder
273 // find experimental codecs in the last order,
274 // now we don't consider them at all since they are supposed to
275 // be not stable, maybe we shouldn't.
276 // Currently, it's possible to turn them on for testing purposes.
277
278 static const auto experimentalCodecsEnabled =
279 qEnvironmentVariableIntValue("QT_ENABLE_EXPERIMENTAL_CODECS");
280
281 if (!experimentalCodecsEnabled && isAVCodecExperimental(codec)) {
282 qCDebug(qLcFFmpegUtils) << "Skip experimental codec" << codec->name;
283 continue;
284 }
285
286 if (av_codec_is_decoder(codec)) {
287 if (isCodecValid(codec, HWAccel::decodingDeviceTypes(), platformHwDecoders))
288 result[DECODERS].emplace_back(codec);
289 else
290 qCDebug(qLcFFmpegUtils)
291 << "Skip decoder" << codec->name
292 << "due to disabled matching hw acceleration, or dysfunctional codec";
293 }
294
295 if (av_codec_is_encoder(codec)) {
296 if (isCodecValid(codec, HWAccel::encodingDeviceTypes(), platformHwEncoders))
297 result[ENCODERS].emplace_back(codec);
298 else
299 qCDebug(qLcFFmpegUtils)
300 << "Skip encoder" << codec->name
301 << "due to disabled matching hw acceleration, or dysfunctional codec";
302 }
303 }
304
305 for (auto &storage : result) {
306 storage.shrink_to_fit();
307
308 // we should ensure the original order
309 std::stable_sort(storage.begin(), storage.end(), CodecsComparator{});
310 }
311
312 // It print pretty much logs, so let's print it only for special case
313 const bool shouldDumpCodecsInfo = qLcFFmpegUtils().isEnabled(QtDebugMsg)
314 && qEnvironmentVariableIsSet("QT_FFMPEG_DEBUG");
315
316 if (shouldDumpCodecsInfo) {
317 qCDebug(qLcFFmpegUtils) << "Advanced FFmpeg codecs info:";
318 for (auto &storage : result) {
319 std::for_each(storage.begin(), storage.end(), &dumpCodecInfo);
320 qCDebug(qLcFFmpegUtils) << "---------------------------";
321 }
322 }
323
324 return result;
325 }();
326
327 return storages[codecsType];
328}
329
330const char *preferredHwCodecNameSuffix(bool isEncoder, AVHWDeviceType deviceType)
331{
332 switch (deviceType) {
333 case AV_HWDEVICE_TYPE_VAAPI:
334 return "_vaapi";
335 case AV_HWDEVICE_TYPE_MEDIACODEC:
336 return "_mediacodec";
337 case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
338 return "_videotoolbox";
339 case AV_HWDEVICE_TYPE_D3D11VA:
340 case AV_HWDEVICE_TYPE_DXVA2:
341#if QT_FFMPEG_HAS_D3D12VA
342 case AV_HWDEVICE_TYPE_D3D12VA:
343#endif
344 return "_mf";
345 case AV_HWDEVICE_TYPE_CUDA:
346 case AV_HWDEVICE_TYPE_VDPAU:
347 return isEncoder ? "_nvenc" : "_cuvid";
348 default:
349 return nullptr;
350 }
351}
352
353template<typename CodecScoreGetter>
354const AVCodec *findAVCodec(CodecStorageType codecsType, AVCodecID codecId,
355 const CodecScoreGetter &scoreGetter)
356{
357 const auto &storage = codecsStorage(codecsType);
358 auto it = std::lower_bound(storage.begin(), storage.end(), codecId, CodecsComparator{});
359
360 const AVCodec *result = nullptr;
361 AVScore resultScore = NotSuitableAVScore;
362
363 for (; it != storage.end() && (*it)->id == codecId && resultScore != BestAVScore; ++it) {
364 const auto score = scoreGetter(*it);
365
366 if (score > resultScore) {
367 resultScore = score;
368 result = *it;
369 }
370 }
371
372 return result;
373}
374
375AVScore hwCodecNameScores(const AVCodec *codec, AVHWDeviceType deviceType)
376{
377 if (auto suffix = preferredHwCodecNameSuffix(av_codec_is_encoder(codec), deviceType)) {
378 const auto substr = strstr(codec->name, suffix);
379 if (substr && !substr[strlen(suffix)])
380 return BestAVScore;
381
382 return DefaultAVScore;
383 }
384
385 return BestAVScore;
386}
387
388const AVCodec *findAVCodec(CodecStorageType codecsType, AVCodecID codecId,
389 const std::optional<AVHWDeviceType> &deviceType,
390 const std::optional<PixelOrSampleFormat> &format)
391{
392 return findAVCodec(codecsType, codecId, [&](const AVCodec *codec) {
394 return NotSuitableAVScore;
395
396 if (!deviceType)
397 return BestAVScore; // find any codec with the id
398
399 if (*deviceType == AV_HWDEVICE_TYPE_NONE
400 && findAVFormat(codec->pix_fmts, &isSwPixelFormat) != AV_PIX_FMT_NONE)
401 return BestAVScore;
402
403 if (*deviceType != AV_HWDEVICE_TYPE_NONE) {
404 for (int index = 0; auto config = avcodec_get_hw_config(codec, index); ++index) {
405 if (config->device_type != deviceType)
406 continue;
407
408 if (format && config->pix_fmt != AV_PIX_FMT_NONE && config->pix_fmt != *format)
409 continue;
410
411 return hwCodecNameScores(codec, *deviceType);
412 }
413
414 // The situation happens mostly with encoders
415 // Probably, it's ffmpeg bug: avcodec_get_hw_config returns null even though
416 // hw acceleration is supported
418 return hwCodecNameScores(codec, *deviceType);
419 }
420
421 return NotSuitableAVScore;
422 });
423}
424
425} // namespace
426
427const AVCodec *findAVDecoder(AVCodecID codecId, const std::optional<AVHWDeviceType> &deviceType,
428 const std::optional<PixelOrSampleFormat> &format)
429{
430 return findAVCodec(DECODERS, codecId, deviceType, format);
431}
432
433const AVCodec *findAVEncoder(AVCodecID codecId, const std::optional<AVHWDeviceType> &deviceType,
434 const std::optional<PixelOrSampleFormat> &format)
435{
436 return findAVCodec(ENCODERS, codecId, deviceType, format);
437}
438
439const AVCodec *findAVEncoder(AVCodecID codecId,
440 const std::function<AVScore(const AVCodec *)> &scoresGetter)
441{
442 return findAVCodec(ENCODERS, codecId, scoresGetter);
443}
444
446{
447 if (codec->type == AVMEDIA_TYPE_VIDEO)
448 return hasAVFormat(codec->pix_fmts, AVPixelFormat(format));
449
450 if (codec->type == AVMEDIA_TYPE_AUDIO)
451 return hasAVFormat(codec->sample_fmts, AVSampleFormat(format));
452
453 return false;
454}
455
456bool isHwPixelFormat(AVPixelFormat format)
457{
458 const auto desc = av_pix_fmt_desc_get(format);
459 return desc && (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) != 0;
460}
461
462bool isAVCodecExperimental(const AVCodec *codec)
463{
464 return (codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL) != 0;
465}
466
467void applyExperimentalCodecOptions(const AVCodec *codec, AVDictionary** opts)
468{
470 qCWarning(qLcFFmpegUtils) << "Applying the option 'strict -2' for the experimental codec"
471 << codec->name << ". it's unlikely to work properly";
472 av_dict_set(opts, "strict", "-2", 0);
473 }
474}
475
476AVPixelFormat pixelFormatForHwDevice(AVHWDeviceType deviceType)
477{
478 switch (deviceType) {
479 case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
480 return AV_PIX_FMT_VIDEOTOOLBOX;
481 case AV_HWDEVICE_TYPE_VAAPI:
482 return AV_PIX_FMT_VAAPI;
483 case AV_HWDEVICE_TYPE_MEDIACODEC:
484 return AV_PIX_FMT_MEDIACODEC;
485 case AV_HWDEVICE_TYPE_CUDA:
486 return AV_PIX_FMT_CUDA;
487 case AV_HWDEVICE_TYPE_VDPAU:
488 return AV_PIX_FMT_VDPAU;
489 case AV_HWDEVICE_TYPE_OPENCL:
490 return AV_PIX_FMT_OPENCL;
491 case AV_HWDEVICE_TYPE_QSV:
492 return AV_PIX_FMT_QSV;
493 case AV_HWDEVICE_TYPE_D3D11VA:
494 return AV_PIX_FMT_D3D11;
495#if QT_FFMPEG_HAS_D3D12VA
496 case AV_HWDEVICE_TYPE_D3D12VA:
497 return AV_PIX_FMT_D3D12;
498#endif
499 case AV_HWDEVICE_TYPE_DXVA2:
500 return AV_PIX_FMT_DXVA2_VLD;
501 case AV_HWDEVICE_TYPE_DRM:
502 return AV_PIX_FMT_DRM_PRIME;
503#if QT_FFMPEG_HAS_VULKAN
504 case AV_HWDEVICE_TYPE_VULKAN:
505 return AV_PIX_FMT_VULKAN;
506#endif
507 default:
508 return AV_PIX_FMT_NONE;
509 }
510}
511
512AVPacketSideData *addStreamSideData(AVStream *stream, AVPacketSideData sideData)
513{
514 QScopeGuard freeData([&sideData]() { av_free(sideData.data); });
515#if QT_FFMPEG_STREAM_SIDE_DATA_DEPRECATED
516 AVPacketSideData *result = av_packet_side_data_add(
517 &stream->codecpar->coded_side_data,
518 &stream->codecpar->nb_coded_side_data,
519 sideData.type,
520 sideData.data,
521 sideData.size,
522 0);
523 if (result) {
524 // If the result is not null, the ownership is taken by AVStream,
525 // otherwise the data must be deleted.
526 freeData.dismiss();
527 return result;
528 }
529#else
531 // TODO: implement for older FFmpeg versions
532 qWarning() << "Adding stream side data is not supported for FFmpeg < 6.1";
533#endif
534
535 return nullptr;
536}
537
538const AVPacketSideData *streamSideData(const AVStream *stream, AVPacketSideDataType type)
539{
541
542#if QT_FFMPEG_STREAM_SIDE_DATA_DEPRECATED
543 return av_packet_side_data_get(stream->codecpar->coded_side_data,
544 stream->codecpar->nb_coded_side_data, type);
545#else
546 auto checkType = [type](const auto &item) { return item.type == type; };
547 const auto end = stream->side_data + stream->nb_side_data;
548 const auto found = std::find_if(stream->side_data, end, checkType);
549 return found == end ? nullptr : found;
550#endif
551}
552
554 const AVAudioFormat &outputFormat)
555{
556 SwrContext *resampler = nullptr;
557#if QT_FFMPEG_OLD_CHANNEL_LAYOUT
558 resampler = swr_alloc_set_opts(nullptr,
559 outputFormat.channelLayoutMask,
560 outputFormat.sampleFormat,
561 outputFormat.sampleRate,
562 inputFormat.channelLayoutMask,
563 inputFormat.sampleFormat,
564 inputFormat.sampleRate,
565 0,
566 nullptr);
567#else
568
569#if QT_FFMPEG_SWR_CONST_CH_LAYOUT
570 using AVChannelLayoutPrm = const AVChannelLayout*;
571#else
572 using AVChannelLayoutPrm = AVChannelLayout*;
573#endif
574
575 swr_alloc_set_opts2(&resampler,
576 const_cast<AVChannelLayoutPrm>(&outputFormat.channelLayout),
577 outputFormat.sampleFormat,
578 outputFormat.sampleRate,
579 const_cast<AVChannelLayoutPrm>(&inputFormat.channelLayout),
580 inputFormat.sampleFormat,
581 inputFormat.sampleRate,
582 0,
583 nullptr);
584#endif
585
586 swr_init(resampler);
587 return SwrContextUPtr(resampler);
588}
589
590QVideoFrameFormat::ColorTransfer fromAvColorTransfer(AVColorTransferCharacteristic colorTrc) {
591 switch (colorTrc) {
592 case AVCOL_TRC_BT709:
593 // The following three cases have transfer characteristics identical to BT709
594 case AVCOL_TRC_BT1361_ECG:
595 case AVCOL_TRC_BT2020_10:
596 case AVCOL_TRC_BT2020_12:
597 case AVCOL_TRC_SMPTE240M: // almost identical to bt709
599 case AVCOL_TRC_GAMMA22:
600 case AVCOL_TRC_SMPTE428: // No idea, let's hope for the best...
601 case AVCOL_TRC_IEC61966_2_1: // sRGB, close enough to 2.2...
602 case AVCOL_TRC_IEC61966_2_4: // not quite, but probably close enough
604 case AVCOL_TRC_GAMMA28:
606 case AVCOL_TRC_SMPTE170M:
608 case AVCOL_TRC_LINEAR:
610 case AVCOL_TRC_SMPTE2084:
612 case AVCOL_TRC_ARIB_STD_B67:
614 default:
615 break;
616 }
618}
619
620#ifdef Q_OS_DARWIN
621bool isCVFormatSupported(uint32_t cvFormat)
622{
623 return av_map_videotoolbox_format_to_pixfmt(cvFormat) != AV_PIX_FMT_NONE;
624}
625
626std::string cvFormatToString(uint32_t cvFormat)
627{
628 auto formatDescIt = std::make_reverse_iterator(reinterpret_cast<const char *>(&cvFormat));
629 return std::string(formatDescIt - 4, formatDescIt);
630}
631
632#endif
633
634} // namespace QFFmpeg
635
636QDebug operator<<(QDebug dbg, const AVRational &value)
637{
638 dbg << value.num << "/" << value.den;
639 return dbg;
640}
641
\inmodule QtCore
static const std::vector< AVHWDeviceType > & decodingDeviceTypes()
static const std::vector< AVHWDeviceType > & encodingDeviceTypes()
virtual int type() const
Returns the type of an item as an int.
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString first(qsizetype n) const &
Definition qstring.h:390
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
ColorTransfer
\value ColorTransfer_Unknown The color transfer function is unknown.
QSet< QString >::iterator it
constexpr AVScore BestAVScore
Definition qffmpeg_p.h:159
const AVCodec * findAVEncoder(AVCodecID codecId, const std::optional< AVHWDeviceType > &deviceType, const std::optional< PixelOrSampleFormat > &format)
Definition qffmpeg.cpp:433
const char * name
bool isHwPixelFormat(AVPixelFormat format)
Definition qffmpeg.cpp:456
bool isAVCodecExperimental(const AVCodec *codec)
Definition qffmpeg.cpp:462
AVPacketSideData * addStreamSideData(AVStream *stream, AVPacketSideData sideData)
Definition qffmpeg.cpp:512
int PixelOrSampleFormat
Definition qffmpeg_p.h:157
bool isAVFormatSupported(const AVCodec *codec, PixelOrSampleFormat format)
Definition qffmpeg.cpp:445
const AVCodec * findAVDecoder(AVCodecID codecId, const std::optional< AVHWDeviceType > &deviceType, const std::optional< PixelOrSampleFormat > &format)
Definition qffmpeg.cpp:427
int AVScore
Definition qffmpeg_p.h:158
bool isSwPixelFormat(AVPixelFormat format)
Definition qffmpeg_p.h:220
constexpr AVScore DefaultAVScore
Definition qffmpeg_p.h:160
bool hasAVFormat(const Format *fmts, Format format)
Definition qffmpeg_p.h:178
Format findAVFormat(const Format *fmts, const Predicate &predicate)
Definition qffmpeg_p.h:184
QVideoFrameFormat::ColorTransfer fromAvColorTransfer(AVColorTransferCharacteristic colorTrc)
Definition qffmpeg.cpp:590
void applyExperimentalCodecOptions(const AVCodec *codec, AVDictionary **opts)
Definition qffmpeg.cpp:467
constexpr AVScore NotSuitableAVScore
Definition qffmpeg_p.h:161
SwrContextUPtr createResampleContext(const AVAudioFormat &inputFormat, const AVAudioFormat &outputFormat)
Definition qffmpeg.cpp:553
AVPixelFormat pixelFormatForHwDevice(AVHWDeviceType deviceType)
Definition qffmpeg.cpp:476
std::unique_ptr< SwrContext, AVDeleter< decltype(&swr_free), &swr_free > > SwrContextUPtr
Definition qffmpeg_p.h:155
const AVPacketSideData * streamSideData(const AVStream *stream, AVPacketSideDataType type)
Definition qffmpeg.cpp:538
Combined button and popup list for selecting options.
static org qtproject qt android multimedia QtVideoDeviceManager
EGLStreamKHR stream
EGLConfig config
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
QDebug operator<<(QDebug dbg, const AVRational &value)
Definition qffmpeg.cpp:636
QMediaFormat::AudioCodec codec
static AVCodecID codecId(QMediaFormat::VideoCodec codec)
@ QtDebugMsg
Definition qlogging.h:30
#define qWarning
Definition qlogging.h:166
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLuint GLuint end
GLenum GLuint id
[7]
GLfloat GLfloat f
GLenum type
GLbitfield flags
GLuint name
GLint first
GLint GLsizei GLsizei GLenum format
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE Q_DECLARE_JNI_CLASS(Environment, "android/os/Environment")
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define Q_UNUSED(x)
static QInputDevice::DeviceType deviceType(const UINT cursorType)
if(qFloatDistance(a, b)<(1<< 7))
[0]
QStorageInfo storage
[1]
QObject::connect nullptr
QGraphicsItem * item