Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qffmpegmediaformatinfo.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
5
8
9#include <QtCore/qoperatingsystemversion.h>
10#include <QtCore/qvarlengtharray.h>
11#include <QtCore/private/qflatmap_p.h>
12#include <QtMultimedia/qaudioformat.h>
13#include <QtMultimedia/private/qmultimedia_ranges_p.h>
14#include <QtGui/qimagewriter.h>
15
17
18using namespace Qt::Literals;
19
20namespace {
21
22template <size_t MapSize, typename Key, typename Value>
23auto makeReverseLookupTable(std::initializer_list<std::pair<const Key, Value>> map)
24{
25 using namespace QtMultimediaPrivate;
26
27 auto keyValuePairs = map | views::transform([](const auto &pair) {
28 return std::pair<const Value, Key>(pair.second, pair.first);
29 }) | ranges::to<std::vector<std::pair<const Value, Key>>>();
30
31 return keyValuePairs | ranges::to<QVarLengthFlatMap<Value, Key, MapSize>>();
32}
33
34static constexpr auto videoCodecMap =
35 std::initializer_list<std::pair<const QMediaFormat::VideoCodec, AVCodecID>>{
36 { QMediaFormat::VideoCodec::MPEG1, AV_CODEC_ID_MPEG1VIDEO },
37 { QMediaFormat::VideoCodec::MPEG2, AV_CODEC_ID_MPEG2VIDEO },
38 { QMediaFormat::VideoCodec::MPEG4, AV_CODEC_ID_MPEG4 },
39 { QMediaFormat::VideoCodec::H264, AV_CODEC_ID_H264 },
40 { QMediaFormat::VideoCodec::H265, AV_CODEC_ID_HEVC },
41 { QMediaFormat::VideoCodec::VP8, AV_CODEC_ID_VP8 },
42 { QMediaFormat::VideoCodec::VP9, AV_CODEC_ID_VP9 },
43 { QMediaFormat::VideoCodec::AV1, AV_CODEC_ID_AV1 },
44 { QMediaFormat::VideoCodec::Theora, AV_CODEC_ID_THEORA },
45 { QMediaFormat::VideoCodec::WMV, AV_CODEC_ID_WMV3 },
46 { QMediaFormat::VideoCodec::MotionJPEG, AV_CODEC_ID_MJPEG },
47 };
48
49} // namespace
50
51AVCodecID codecId(QMediaFormat::VideoCodec codec)
52{
53 static const QVarLengthFlatMap<QMediaFormat::VideoCodec, AVCodecID, videoCodecMap.size()> map(
54 videoCodecMap.begin(), videoCodecMap.end());
55 const auto it = map.find(codec);
56 return it != map.end() ? it->second : AV_CODEC_ID_NONE;
57}
58
60{
61 using namespace QtMultimediaPrivate;
62
63 static const auto map = makeReverseLookupTable<videoCodecMap.size()>(videoCodecMap);
64
65 const auto it = map.find(id);
66 return it != map.end() ? it->second : QMediaFormat::VideoCodec::Unspecified;
67}
68
69static constexpr auto audioCodecMap =
70 std::initializer_list<std::pair<const QMediaFormat::AudioCodec, AVCodecID>>{
71 { QMediaFormat::AudioCodec::MP3, AV_CODEC_ID_MP3 },
72 { QMediaFormat::AudioCodec::AAC, AV_CODEC_ID_AAC },
73 { QMediaFormat::AudioCodec::AC3, AV_CODEC_ID_AC3 },
74 { QMediaFormat::AudioCodec::EAC3, AV_CODEC_ID_EAC3 },
75 { QMediaFormat::AudioCodec::FLAC, AV_CODEC_ID_FLAC },
76 { QMediaFormat::AudioCodec::DolbyTrueHD, AV_CODEC_ID_TRUEHD },
77 { QMediaFormat::AudioCodec::Opus, AV_CODEC_ID_OPUS },
78 { QMediaFormat::AudioCodec::Vorbis, AV_CODEC_ID_VORBIS },
79 { QMediaFormat::AudioCodec::Wave, AV_CODEC_ID_PCM_S16LE },
80 { QMediaFormat::AudioCodec::WMA, AV_CODEC_ID_WMAPRO },
81 { QMediaFormat::AudioCodec::ALAC, AV_CODEC_ID_ALAC },
82 };
83
84AVCodecID codecId(QMediaFormat::AudioCodec codec)
85{
86 static const QVarLengthFlatMap<QMediaFormat::AudioCodec, AVCodecID, audioCodecMap.size()> map(
87 audioCodecMap.begin(), audioCodecMap.end());
88 const auto it = map.find(codec);
89 return it != map.end() ? it->second : AV_CODEC_ID_NONE;
90}
91
93{
94 using namespace QtMultimediaPrivate;
95
96 static const auto map = makeReverseLookupTable<audioCodecMap.size()>(audioCodecMap);
97
98 const auto it = map.find(id);
99 return it != map.end() ? it->second : QMediaFormat::AudioCodec::Unspecified;
100}
101
102// mimetypes are mostly copied from qmediaformat.cpp. Unfortunately, FFmpeg uses
103// in some cases slightly different mimetypes
104constexpr struct
105{
106 QMediaFormat::FileFormat fileFormat;
107 const char *mimeType;
108 const char *name; // disambiguate if we have several muxers/demuxers
109} s_outputFormatMap[] = {
110 { QMediaFormat::WMV, "video/x-ms-asf", "asf" },
111 { QMediaFormat::AVI, "video/x-msvideo", nullptr },
112 { QMediaFormat::Matroska, "video/x-matroska", nullptr },
113 { QMediaFormat::MPEG4, "video/mp4", "mp4" },
114 { QMediaFormat::Ogg, "video/ogg", nullptr },
115 // QuickTime is the same as MP4
116 { QMediaFormat::WebM, "video/webm", "webm" },
117 // Audio Formats
118 // Mpeg4Audio is the same as MP4 without the video codecs
119 { QMediaFormat::AAC, "audio/aac", nullptr },
120 // WMA is the same as WMV
121 { QMediaFormat::FLAC, "audio/x-flac", nullptr },
122 { QMediaFormat::MP3, "audio/mpeg", "mp3" },
123 { QMediaFormat::Wave, "audio/x-wav", nullptr },
124 { QMediaFormat::Ogg, "audio/ogg", nullptr },
126
127QMediaFormat::FileFormat formatForAVFormat(const AVOutputFormat *format)
128{
129 if (!format->mime_type || !*format->mime_type)
130 return QMediaFormat::UnspecifiedFormat;
131
132 for (const auto &m : s_outputFormatMap) {
133 if (!strcmp(m.mimeType, format->mime_type)) {
134 // check if the name matches. This is used to disambiguate where FFmpeg provides
135 // multiple muxers or demuxers
136 if (!m.name || !strcmp(m.name, format->name))
137 return m.fileFormat;
138 }
139 }
140 return QMediaFormat::UnspecifiedFormat;
141}
142
143const AVOutputFormat *avFormatForFormat(QMediaFormat::FileFormat format)
144{
145 if (format == QMediaFormat::QuickTime || format == QMediaFormat::Mpeg4Audio)
146 format = QMediaFormat::MPEG4;
147 if (format == QMediaFormat::WMA)
148 format = QMediaFormat::WMV;
149
150 for (const auto &m : s_outputFormatMap) {
151 if (m.fileFormat == format)
152 return av_guess_format(m.name, nullptr, m.mimeType);
153 }
154
155 return nullptr;
156}
157
158// Seems like FFmpeg uses different names for muxers and demuxers of the same format.
159// that makes it somewhat cumbersome to detect things correctly.
160// The input formats have a comma separated list of short names. We check the first one of those
161// as the docs specify that you only append to the list
162constexpr struct
163{
166} s_inputFormatMap[] = {
167 { QMediaFormat::WMV, "asf"_L1 },
168 { QMediaFormat::AVI, "avi"_L1 },
169 { QMediaFormat::Matroska, "matroska"_L1 },
170 { QMediaFormat::MPEG4, "mov"_L1 },
171 { QMediaFormat::Ogg, "ogg"_L1 },
172 { QMediaFormat::WebM, "webm"_L1 },
173 // Audio Formats
174 // Mpeg4Audio is the same as MP4 without the video codecs
175 { QMediaFormat::AAC, "aac"_L1 },
176 // WMA is the same as WMV
177 { QMediaFormat::FLAC, "flac"_L1 },
178 { QMediaFormat::MP3, "mp3"_L1 },
179 { QMediaFormat::Wave, "wav"_L1 },
181
182QMediaFormat::FileFormat formatForAVInputFormat(const AVInputFormat &format)
183{
184 if (!format.name)
185 return QMediaFormat::UnspecifiedFormat;
186
187 const QLatin1String formatName(format.name);
188 for (const auto &m : s_inputFormatMap) {
189 if (formatName.startsWith(m.name))
190 return m.fileFormat;
191 }
192
193 return QMediaFormat::UnspecifiedFormat;
194}
195
196enum class CodecType : uint8_t {
199};
200
201template <CodecType Type>
202bool codecSupportsFormat(const AVOutputFormat *format, AVCodecID codecId)
203{
204 const int result = avformat_query_codec(format, codecId, FF_COMPLIANCE_NORMAL);
205 switch (result) {
206 case 1:
207 return true;
208 case AVERROR_PATCHWELCOME:
209 case 0:
210 return false;
211 default:
212 break;
213 }
214
215 if (result < 0) {
216 // A negative result means that the codec may work, but information is unavailable
217 switch (Type) {
218 case CodecType::Audio:
219 return codecId == format->audio_codec;
220 case CodecType::Video:
221 return codecId == format->video_codec;
222 }
223 }
224
225 return false;
226}
227
228QFFmpegMediaFormatInfo::QFFmpegMediaFormatInfo()
229{
230 namespace ranges = QtMultimediaPrivate::ranges;
231 namespace views = QtMultimediaPrivate::views;
232
233 using VideoCodec = QMediaFormat::VideoCodec;
234 using AudioCodec = QMediaFormat::AudioCodec;
235
236 QList<AudioCodec> audioEncoders; // All audio encoders that Qt support
237 QList<AudioCodec> extraAudioDecoders; // All audio decoders that do not support encoding
238 QList<VideoCodec> videoEncoders; // All video encoders that Qt support
239 QList<VideoCodec> extraVideoDecoders; // All video decoders that do not support encoding
240 using Descriptors =
241 QFFmpeg::FFmpegValueIteratorRange<const AVCodecDescriptor *, avcodec_descriptor_next>;
242
243 // Sort all FFmpeg's codecs into the buckets
244 for (const AVCodecDescriptor *descriptor : Descriptors{}) {
245
246 const bool canEncode{ QFFmpeg::findAVEncoder(descriptor->id).has_value() };
247 const bool canDecode{ QFFmpeg::findAVDecoder(descriptor->id).has_value() };
248 const bool isAVCodec = canEncode || canDecode;
249
250 if (!isAVCodec)
251 continue; // subtitle codec
252
253 const VideoCodec videoCodec = videoCodecForAVCodecId(descriptor->id);
254 const AudioCodec audioCodec = audioCodecForAVCodecId(descriptor->id);
255
256 if (descriptor->type == AVMEDIA_TYPE_VIDEO && videoCodec != VideoCodec::Unspecified) {
257 if (canEncode) {
258 if (!videoEncoders.contains(videoCodec))
259 videoEncoders.append(videoCodec);
260 } else if (canDecode) {
261 if (!extraVideoDecoders.contains(videoCodec))
262 extraVideoDecoders.append(videoCodec);
263 }
264 } else if (descriptor->type == AVMEDIA_TYPE_AUDIO && audioCodec != AudioCodec::Unspecified) {
265 if (canEncode) {
266 if (!audioEncoders.contains(audioCodec))
267 audioEncoders.append(audioCodec);
268 } else if (canDecode) {
269 if (!extraAudioDecoders.contains(audioCodec))
270 extraAudioDecoders.append(audioCodec);
271 }
272 }
273 }
274
275 // Update 'encoders' list with muxer/encoder combinations that Qt supports
276 using MuxerRange = QFFmpeg::FFmpegOpaqueIteratorRange<const AVOutputFormat *, av_muxer_iterate>;
277 for (const AVOutputFormat *outputFormat : MuxerRange()) {
278 QMediaFormat::FileFormat mediaFormat = formatForAVFormat(outputFormat);
279 if (mediaFormat == QMediaFormat::UnspecifiedFormat)
280 continue;
281
282 CodecMap encoder;
283 encoder.format = mediaFormat;
284
285 auto supportedAudioCodecs = audioEncoders | views::filter([&](AudioCodec codec) {
286 return codecSupportsFormat<CodecType::Audio>(outputFormat, codecId(codec));
287 });
288 encoder.audio = supportedAudioCodecs | ranges::to<QList<AudioCodec>>();
289
290 auto supportedVideoCodecs = videoEncoders | views::filter([&](VideoCodec codec) {
291 return codecSupportsFormat<CodecType::Video>(outputFormat, codecId(codec));
292 });
293 encoder.video = supportedVideoCodecs | ranges::to<QList<VideoCodec>>();
294
295 // If no encoders support either audio or video, we skip this format.
296 if (encoder.audio.isEmpty() && encoder.video.isEmpty())
297 continue;
298
299 // Handle special cases
300 switch (encoder.format) {
301 case QMediaFormat::WMV:
302 // add WMA
303 encoders.append({ QMediaFormat::WMA, encoder.audio, {} });
304 break;
305 case QMediaFormat::MPEG4:
306 // add Mpeg4Audio and QuickTime
307 encoders.append({ QMediaFormat::QuickTime, encoder.audio, encoder.video });
308 encoders.append({ QMediaFormat::Mpeg4Audio, encoder.audio, {} });
309 break;
310 case QMediaFormat::Wave:
311 // FFmpeg allows other encoded formats in WAV containers, but we do not want that
312 if (!encoder.audio.contains(AudioCodec::Wave))
313 continue;
314 encoder.audio = { AudioCodec::Wave };
315 break;
316 default:
317 break;
318 }
319
320 encoders.append(encoder);
321 }
322
323 // FFmpeg doesn't allow querying supported codecs for demuxers.
324 // We take a simple approximation stating that we can decode what we
325 // can encode. That's a safe subset.
326 decoders = encoders;
327
328 if constexpr (QOperatingSystemVersion::currentType() == QOperatingSystemVersion::Windows) {
329 // MediaFoundation HVEC encoder fails when processing frames
330 for (auto &encoder : encoders) {
331 auto h265index = encoder.video.indexOf(VideoCodec::H265);
332 if (h265index >= 0)
333 encoder.video.removeAt(h265index);
334 }
335 }
336
337 // FFmpeg can currently only decode WMA and WMV, not encode
338 auto findDecoder = [&](QMediaFormat::FileFormat fmt) -> CodecMap * {
339 auto it = ranges::find_if(decoders, [&](const CodecMap &m) {
340 return m.format == fmt;
341 });
342 return it != decoders.end() ? &*it : nullptr;
343 };
344
345 if (extraAudioDecoders.contains(AudioCodec::WMA)) {
346 if (auto *wma = findDecoder(QMediaFormat::WMA))
347 wma->audio.append(AudioCodec::WMA);
348 if (auto *wmv = findDecoder(QMediaFormat::WMV))
349 wmv->audio.append(AudioCodec::WMA);
350 }
351
352 if (extraVideoDecoders.contains(VideoCodec::WMV)) {
353 if (auto *wmv = findDecoder(QMediaFormat::WMV))
354 wmv->video.append(VideoCodec::WMV);
355 }
356
357 // Add image formats we support. We currently simply use Qt's built-in image write
358 // to save images. That doesn't give us HDR support or support for larger bit depths,
359 // but most cameras can currently not generate those anyway.
360 const QList<QByteArray> imgFormats = QImageWriter::supportedImageFormats();
361 for (const auto &f : imgFormats) {
362 if (f == "png")
363 imageFormats.append(QImageCapture::PNG);
364 else if (f == "jpeg")
365 imageFormats.append(QImageCapture::JPEG);
366 else if (f == "tiff")
367 imageFormats.append(QImageCapture::Tiff);
368 else if (f == "webp")
369 imageFormats.append(QImageCapture::WebP);
370 }
371
372 fixupCodecMaps();
373}
374
375QFFmpegMediaFormatInfo::~QFFmpegMediaFormatInfo() = default;
376
377QMediaFormat::AudioCodec QFFmpegMediaFormatInfo::audioCodecForAVCodecId(AVCodecID id)
378{
379 return audioCodecFromId(id);
380}
381
382QMediaFormat::VideoCodec QFFmpegMediaFormatInfo::videoCodecForAVCodecId(AVCodecID id)
383{
384 return videoCodecFromId(id);
385}
386
387QMediaFormat::FileFormat
388QFFmpegMediaFormatInfo::fileFormatForAVInputFormat(const AVInputFormat &format)
389{
390 return formatForAVInputFormat(format);
391}
392
393const AVOutputFormat *
394QFFmpegMediaFormatInfo::outputFormatForFileFormat(QMediaFormat::FileFormat format)
395{
396 return avFormatForFormat(format);
397}
398
399AVCodecID QFFmpegMediaFormatInfo::codecIdForVideoCodec(QMediaFormat::VideoCodec codec)
400{
401 return codecId(codec);
402}
403
404AVCodecID QFFmpegMediaFormatInfo::codecIdForAudioCodec(QMediaFormat::AudioCodec codec)
405{
406 return codecId(codec);
407}
408
409QAudioFormat::SampleFormat QFFmpegMediaFormatInfo::sampleFormat(AVSampleFormat format)
410{
411 switch (format) {
412 case AV_SAMPLE_FMT_NONE:
413 default:
414 return QAudioFormat::Unknown;
415 case AV_SAMPLE_FMT_U8: ///< unsigned 8 bits
416 case AV_SAMPLE_FMT_U8P: ///< unsigned 8 bits: planar
417 return QAudioFormat::UInt8;
418 case AV_SAMPLE_FMT_S16: ///< signed 16 bits
419 case AV_SAMPLE_FMT_S16P: ///< signed 16 bits: planar
420 return QAudioFormat::Int16;
421 case AV_SAMPLE_FMT_S32: ///< signed 32 bits
422 case AV_SAMPLE_FMT_S32P: ///< signed 32 bits: planar
423 return QAudioFormat::Int32;
424 case AV_SAMPLE_FMT_FLT: ///< float
425 case AV_SAMPLE_FMT_FLTP: ///< float: planar
426 return QAudioFormat::Float;
427 case AV_SAMPLE_FMT_DBL: ///< double
428 case AV_SAMPLE_FMT_DBLP: ///< double: planar
429 case AV_SAMPLE_FMT_S64: ///< signed 64 bits
430 case AV_SAMPLE_FMT_S64P: ///< signed 64 bits, planar
431 // let's use float
432 return QAudioFormat::Float;
433 }
434}
435
436AVSampleFormat QFFmpegMediaFormatInfo::avSampleFormat(QAudioFormat::SampleFormat format)
437{
438 switch (format) {
439 case QAudioFormat::UInt8:
440 return AV_SAMPLE_FMT_U8;
441 case QAudioFormat::Int16:
442 return AV_SAMPLE_FMT_S16;
443 case QAudioFormat::Int32:
444 return AV_SAMPLE_FMT_S32;
445 case QAudioFormat::Float:
446 return AV_SAMPLE_FMT_FLT;
447 default:
448 return AV_SAMPLE_FMT_NONE;
449 }
450}
451
452int64_t QFFmpegMediaFormatInfo::avChannelLayout(QAudioFormat::ChannelConfig channelConfig)
453{
454 int64_t avChannelLayout = 0;
455 if (channelConfig & (1 << QAudioFormat::FrontLeft))
456 avChannelLayout |= AV_CH_FRONT_LEFT;
457 if (channelConfig & (1 << QAudioFormat::FrontRight))
458 avChannelLayout |= AV_CH_FRONT_RIGHT;
459 if (channelConfig & (1 << QAudioFormat::FrontCenter))
460 avChannelLayout |= AV_CH_FRONT_CENTER;
461 if (channelConfig & (1 << QAudioFormat::LFE))
462 avChannelLayout |= AV_CH_LOW_FREQUENCY;
463 if (channelConfig & (1 << QAudioFormat::BackLeft))
464 avChannelLayout |= AV_CH_BACK_LEFT;
465 if (channelConfig & (1 << QAudioFormat::BackRight))
466 avChannelLayout |= AV_CH_BACK_RIGHT;
467 if (channelConfig & (1 << QAudioFormat::FrontLeftOfCenter))
468 avChannelLayout |= AV_CH_FRONT_LEFT_OF_CENTER;
469 if (channelConfig & (1 << QAudioFormat::FrontRightOfCenter))
470 avChannelLayout |= AV_CH_FRONT_RIGHT_OF_CENTER;
471 if (channelConfig & (1 << QAudioFormat::BackCenter))
472 avChannelLayout |= AV_CH_BACK_CENTER;
473 if (channelConfig & (1 << QAudioFormat::LFE2))
474 avChannelLayout |= AV_CH_LOW_FREQUENCY_2;
475 if (channelConfig & (1 << QAudioFormat::SideLeft))
476 avChannelLayout |= AV_CH_SIDE_LEFT;
477 if (channelConfig & (1 << QAudioFormat::SideRight))
478 avChannelLayout |= AV_CH_SIDE_RIGHT;
479 if (channelConfig & (1 << QAudioFormat::TopFrontLeft))
480 avChannelLayout |= AV_CH_TOP_FRONT_LEFT;
481 if (channelConfig & (1 << QAudioFormat::TopFrontRight))
482 avChannelLayout |= AV_CH_TOP_FRONT_RIGHT;
483 if (channelConfig & (1 << QAudioFormat::TopFrontCenter))
484 avChannelLayout |= AV_CH_TOP_FRONT_CENTER;
485 if (channelConfig & (1 << QAudioFormat::TopCenter))
486 avChannelLayout |= AV_CH_TOP_CENTER;
487 if (channelConfig & (1 << QAudioFormat::TopBackLeft))
488 avChannelLayout |= AV_CH_TOP_BACK_LEFT;
489 if (channelConfig & (1 << QAudioFormat::TopBackRight))
490 avChannelLayout |= AV_CH_TOP_BACK_RIGHT;
491 if (channelConfig & (1 << QAudioFormat::TopBackCenter))
492 avChannelLayout |= AV_CH_TOP_BACK_CENTER;
493 if (channelConfig & (1 << QAudioFormat::TopSideLeft))
494 avChannelLayout |= AV_CH_TOP_SIDE_LEFT;
495 if (channelConfig & (1 << QAudioFormat::TopSideRight))
496 avChannelLayout |= AV_CH_TOP_SIDE_RIGHT;
497 if (channelConfig & (1 << QAudioFormat::BottomFrontCenter))
498 avChannelLayout |= AV_CH_BOTTOM_FRONT_CENTER;
499 if (channelConfig & (1 << QAudioFormat::BottomFrontLeft))
500 avChannelLayout |= AV_CH_BOTTOM_FRONT_LEFT;
501 if (channelConfig & (1 << QAudioFormat::BottomFrontRight))
502 avChannelLayout |= AV_CH_BOTTOM_FRONT_RIGHT;
503 return avChannelLayout;
504}
505
506QAudioFormat::ChannelConfig QFFmpegMediaFormatInfo::channelConfigForAVLayout(int64_t avChannelLayout)
507{
508 quint32 channelConfig = 0;
509 if (avChannelLayout & AV_CH_FRONT_LEFT)
510 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontLeft);
511 if (avChannelLayout & AV_CH_FRONT_RIGHT)
512 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontRight);
513 if (avChannelLayout & AV_CH_FRONT_CENTER)
514 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontCenter);
515 if (avChannelLayout & AV_CH_LOW_FREQUENCY)
516 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::LFE);
517 if (avChannelLayout & AV_CH_BACK_LEFT)
518 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BackLeft);
519 if (avChannelLayout & AV_CH_BACK_RIGHT)
520 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BackRight);
521 if (avChannelLayout & AV_CH_FRONT_LEFT_OF_CENTER)
522 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontLeftOfCenter);
523 if (avChannelLayout & AV_CH_FRONT_RIGHT_OF_CENTER)
524 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontRightOfCenter);
525 if (avChannelLayout & AV_CH_BACK_CENTER)
526 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BackCenter);
527 if (avChannelLayout & AV_CH_LOW_FREQUENCY_2)
528 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::LFE2);
529 if (avChannelLayout & AV_CH_SIDE_LEFT)
530 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::SideLeft);
531 if (avChannelLayout & AV_CH_SIDE_RIGHT)
532 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::SideRight);
533 if (avChannelLayout & AV_CH_TOP_FRONT_LEFT)
534 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopFrontLeft);
535 if (avChannelLayout & AV_CH_TOP_FRONT_RIGHT)
536 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopFrontRight);
537 if (avChannelLayout & AV_CH_TOP_FRONT_CENTER)
538 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopFrontCenter);
539 if (avChannelLayout & AV_CH_TOP_CENTER)
540 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopCenter);
541 if (avChannelLayout & AV_CH_TOP_BACK_LEFT)
542 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopBackLeft);
543 if (avChannelLayout & AV_CH_TOP_BACK_RIGHT)
544 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopBackRight);
545 if (avChannelLayout & AV_CH_TOP_BACK_CENTER)
546 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopBackCenter);
547 if (avChannelLayout & AV_CH_TOP_SIDE_LEFT)
548 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopSideLeft);
549 if (avChannelLayout & AV_CH_TOP_SIDE_RIGHT)
550 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopSideRight);
551 if (avChannelLayout & AV_CH_BOTTOM_FRONT_CENTER)
552 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BottomFrontCenter);
553 if (avChannelLayout & AV_CH_BOTTOM_FRONT_LEFT)
554 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BottomFrontLeft);
555 if (avChannelLayout & AV_CH_BOTTOM_FRONT_RIGHT)
556 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BottomFrontRight);
557 return QAudioFormat::ChannelConfig(channelConfig);
558}
559
560QAudioFormat
561QFFmpegMediaFormatInfo::audioFormatFromCodecParameters(const AVCodecParameters &codecpar)
562{
563 QAudioFormat format;
564 format.setSampleFormat(sampleFormat(AVSampleFormat(codecpar.format)));
565 format.setSampleRate(codecpar.sample_rate);
566#if QT_FFMPEG_HAS_AV_CHANNEL_LAYOUT
567 uint64_t channelLayout = 0;
568 if (codecpar.ch_layout.order == AV_CHANNEL_ORDER_NATIVE)
569 channelLayout = codecpar.ch_layout.u.mask;
570 else
571 channelLayout = avChannelLayout(QAudioFormat::defaultChannelConfigForChannelCount(codecpar.ch_layout.nb_channels));
572#else
573 uint64_t channelLayout = codecpar.channel_layout;
574 if (!channelLayout)
575 channelLayout = avChannelLayout(QAudioFormat::defaultChannelConfigForChannelCount(codecpar.channels));
576#endif
577 format.setChannelConfig(channelConfigForAVLayout(channelLayout));
578 return format;
579}
580
581QT_END_NAMESPACE
Combined button and popup list for selecting options.
const AVOutputFormat * avFormatForFormat(QMediaFormat::FileFormat format)
static constexpr auto audioCodecMap
QLatin1String name
bool codecSupportsFormat(const AVOutputFormat *format, AVCodecID codecId)
QMediaFormat::VideoCodec videoCodecFromId(AVCodecID id)
QMediaFormat::FileFormat formatForAVFormat(const AVOutputFormat *format)
QMediaFormat::FileFormat formatForAVInputFormat(const AVInputFormat &format)
AVCodecID codecId(QMediaFormat::VideoCodec codec)
QMediaFormat::AudioCodec audioCodecFromId(AVCodecID id)
QMediaFormat::FileFormat fileFormat