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's Matroska muxer does not work with H264 video codec
338 for (auto &encoder : encoders) {
339 if (encoder.format == QMediaFormat::Matroska) {
340 encoder.video.removeAll(VideoCodec::H264);
341
342 // And on macOS, also not with H265
343 if constexpr (QOperatingSystemVersion::currentType()
344 == QOperatingSystemVersion::MacOS) {
345 encoder.video.removeAll(VideoCodec::H265);
346 }
347 }
348 }
349
350 // FFmpeg can currently only decode WMA and WMV, not encode
351 auto findDecoder = [&](QMediaFormat::FileFormat fmt) -> CodecMap * {
352 auto it = ranges::find_if(decoders, [&](const CodecMap &m) {
353 return m.format == fmt;
354 });
355 return it != decoders.end() ? &*it : nullptr;
356 };
357
358 if (extraAudioDecoders.contains(AudioCodec::WMA)) {
359 if (auto *wma = findDecoder(QMediaFormat::WMA))
360 wma->audio.append(AudioCodec::WMA);
361 if (auto *wmv = findDecoder(QMediaFormat::WMV))
362 wmv->audio.append(AudioCodec::WMA);
363 }
364
365 if (extraVideoDecoders.contains(VideoCodec::WMV)) {
366 if (auto *wmv = findDecoder(QMediaFormat::WMV))
367 wmv->video.append(VideoCodec::WMV);
368 }
369
370 // Add image formats we support. We currently simply use Qt's built-in image write
371 // to save images. That doesn't give us HDR support or support for larger bit depths,
372 // but most cameras can currently not generate those anyway.
373 const QList<QByteArray> imgFormats = QImageWriter::supportedImageFormats();
374 for (const auto &f : imgFormats) {
375 if (f == "png")
376 imageFormats.append(QImageCapture::PNG);
377 else if (f == "jpeg")
378 imageFormats.append(QImageCapture::JPEG);
379 else if (f == "tiff")
380 imageFormats.append(QImageCapture::Tiff);
381 else if (f == "webp")
382 imageFormats.append(QImageCapture::WebP);
383 }
384
385 fixupCodecMaps();
386}
387
388QFFmpegMediaFormatInfo::~QFFmpegMediaFormatInfo() = default;
389
390QMediaFormat::AudioCodec QFFmpegMediaFormatInfo::audioCodecForAVCodecId(AVCodecID id)
391{
392 return audioCodecFromId(id);
393}
394
395QMediaFormat::VideoCodec QFFmpegMediaFormatInfo::videoCodecForAVCodecId(AVCodecID id)
396{
397 return videoCodecFromId(id);
398}
399
400QMediaFormat::FileFormat
401QFFmpegMediaFormatInfo::fileFormatForAVInputFormat(const AVInputFormat &format)
402{
403 return formatForAVInputFormat(format);
404}
405
406const AVOutputFormat *
407QFFmpegMediaFormatInfo::outputFormatForFileFormat(QMediaFormat::FileFormat format)
408{
409 return avFormatForFormat(format);
410}
411
412AVCodecID QFFmpegMediaFormatInfo::codecIdForVideoCodec(QMediaFormat::VideoCodec codec)
413{
414 return codecId(codec);
415}
416
417AVCodecID QFFmpegMediaFormatInfo::codecIdForAudioCodec(QMediaFormat::AudioCodec codec)
418{
419 return codecId(codec);
420}
421
422QAudioFormat::SampleFormat QFFmpegMediaFormatInfo::sampleFormat(AVSampleFormat format)
423{
424 switch (format) {
425 case AV_SAMPLE_FMT_NONE:
426 default:
427 return QAudioFormat::Unknown;
428 case AV_SAMPLE_FMT_U8: ///< unsigned 8 bits
429 case AV_SAMPLE_FMT_U8P: ///< unsigned 8 bits: planar
430 return QAudioFormat::UInt8;
431 case AV_SAMPLE_FMT_S16: ///< signed 16 bits
432 case AV_SAMPLE_FMT_S16P: ///< signed 16 bits: planar
433 return QAudioFormat::Int16;
434 case AV_SAMPLE_FMT_S32: ///< signed 32 bits
435 case AV_SAMPLE_FMT_S32P: ///< signed 32 bits: planar
436 return QAudioFormat::Int32;
437 case AV_SAMPLE_FMT_FLT: ///< float
438 case AV_SAMPLE_FMT_FLTP: ///< float: planar
439 return QAudioFormat::Float;
440 case AV_SAMPLE_FMT_DBL: ///< double
441 case AV_SAMPLE_FMT_DBLP: ///< double: planar
442 case AV_SAMPLE_FMT_S64: ///< signed 64 bits
443 case AV_SAMPLE_FMT_S64P: ///< signed 64 bits, planar
444 // let's use float
445 return QAudioFormat::Float;
446 }
447}
448
449AVSampleFormat QFFmpegMediaFormatInfo::avSampleFormat(QAudioFormat::SampleFormat format)
450{
451 switch (format) {
452 case QAudioFormat::UInt8:
453 return AV_SAMPLE_FMT_U8;
454 case QAudioFormat::Int16:
455 return AV_SAMPLE_FMT_S16;
456 case QAudioFormat::Int32:
457 return AV_SAMPLE_FMT_S32;
458 case QAudioFormat::Float:
459 return AV_SAMPLE_FMT_FLT;
460 default:
461 return AV_SAMPLE_FMT_NONE;
462 }
463}
464
465int64_t QFFmpegMediaFormatInfo::avChannelLayout(QAudioFormat::ChannelConfig channelConfig)
466{
467 int64_t avChannelLayout = 0;
468 if (channelConfig & (1 << QAudioFormat::FrontLeft))
469 avChannelLayout |= AV_CH_FRONT_LEFT;
470 if (channelConfig & (1 << QAudioFormat::FrontRight))
471 avChannelLayout |= AV_CH_FRONT_RIGHT;
472 if (channelConfig & (1 << QAudioFormat::FrontCenter))
473 avChannelLayout |= AV_CH_FRONT_CENTER;
474 if (channelConfig & (1 << QAudioFormat::LFE))
475 avChannelLayout |= AV_CH_LOW_FREQUENCY;
476 if (channelConfig & (1 << QAudioFormat::BackLeft))
477 avChannelLayout |= AV_CH_BACK_LEFT;
478 if (channelConfig & (1 << QAudioFormat::BackRight))
479 avChannelLayout |= AV_CH_BACK_RIGHT;
480 if (channelConfig & (1 << QAudioFormat::FrontLeftOfCenter))
481 avChannelLayout |= AV_CH_FRONT_LEFT_OF_CENTER;
482 if (channelConfig & (1 << QAudioFormat::FrontRightOfCenter))
483 avChannelLayout |= AV_CH_FRONT_RIGHT_OF_CENTER;
484 if (channelConfig & (1 << QAudioFormat::BackCenter))
485 avChannelLayout |= AV_CH_BACK_CENTER;
486 if (channelConfig & (1 << QAudioFormat::LFE2))
487 avChannelLayout |= AV_CH_LOW_FREQUENCY_2;
488 if (channelConfig & (1 << QAudioFormat::SideLeft))
489 avChannelLayout |= AV_CH_SIDE_LEFT;
490 if (channelConfig & (1 << QAudioFormat::SideRight))
491 avChannelLayout |= AV_CH_SIDE_RIGHT;
492 if (channelConfig & (1 << QAudioFormat::TopFrontLeft))
493 avChannelLayout |= AV_CH_TOP_FRONT_LEFT;
494 if (channelConfig & (1 << QAudioFormat::TopFrontRight))
495 avChannelLayout |= AV_CH_TOP_FRONT_RIGHT;
496 if (channelConfig & (1 << QAudioFormat::TopFrontCenter))
497 avChannelLayout |= AV_CH_TOP_FRONT_CENTER;
498 if (channelConfig & (1 << QAudioFormat::TopCenter))
499 avChannelLayout |= AV_CH_TOP_CENTER;
500 if (channelConfig & (1 << QAudioFormat::TopBackLeft))
501 avChannelLayout |= AV_CH_TOP_BACK_LEFT;
502 if (channelConfig & (1 << QAudioFormat::TopBackRight))
503 avChannelLayout |= AV_CH_TOP_BACK_RIGHT;
504 if (channelConfig & (1 << QAudioFormat::TopBackCenter))
505 avChannelLayout |= AV_CH_TOP_BACK_CENTER;
506 if (channelConfig & (1 << QAudioFormat::TopSideLeft))
507 avChannelLayout |= AV_CH_TOP_SIDE_LEFT;
508 if (channelConfig & (1 << QAudioFormat::TopSideRight))
509 avChannelLayout |= AV_CH_TOP_SIDE_RIGHT;
510 if (channelConfig & (1 << QAudioFormat::BottomFrontCenter))
511 avChannelLayout |= AV_CH_BOTTOM_FRONT_CENTER;
512 if (channelConfig & (1 << QAudioFormat::BottomFrontLeft))
513 avChannelLayout |= AV_CH_BOTTOM_FRONT_LEFT;
514 if (channelConfig & (1 << QAudioFormat::BottomFrontRight))
515 avChannelLayout |= AV_CH_BOTTOM_FRONT_RIGHT;
516 return avChannelLayout;
517}
518
519QAudioFormat::ChannelConfig QFFmpegMediaFormatInfo::channelConfigForAVLayout(int64_t avChannelLayout)
520{
521 quint32 channelConfig = 0;
522 if (avChannelLayout & AV_CH_FRONT_LEFT)
523 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontLeft);
524 if (avChannelLayout & AV_CH_FRONT_RIGHT)
525 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontRight);
526 if (avChannelLayout & AV_CH_FRONT_CENTER)
527 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontCenter);
528 if (avChannelLayout & AV_CH_LOW_FREQUENCY)
529 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::LFE);
530 if (avChannelLayout & AV_CH_BACK_LEFT)
531 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BackLeft);
532 if (avChannelLayout & AV_CH_BACK_RIGHT)
533 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BackRight);
534 if (avChannelLayout & AV_CH_FRONT_LEFT_OF_CENTER)
535 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontLeftOfCenter);
536 if (avChannelLayout & AV_CH_FRONT_RIGHT_OF_CENTER)
537 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontRightOfCenter);
538 if (avChannelLayout & AV_CH_BACK_CENTER)
539 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BackCenter);
540 if (avChannelLayout & AV_CH_LOW_FREQUENCY_2)
541 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::LFE2);
542 if (avChannelLayout & AV_CH_SIDE_LEFT)
543 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::SideLeft);
544 if (avChannelLayout & AV_CH_SIDE_RIGHT)
545 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::SideRight);
546 if (avChannelLayout & AV_CH_TOP_FRONT_LEFT)
547 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopFrontLeft);
548 if (avChannelLayout & AV_CH_TOP_FRONT_RIGHT)
549 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopFrontRight);
550 if (avChannelLayout & AV_CH_TOP_FRONT_CENTER)
551 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopFrontCenter);
552 if (avChannelLayout & AV_CH_TOP_CENTER)
553 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopCenter);
554 if (avChannelLayout & AV_CH_TOP_BACK_LEFT)
555 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopBackLeft);
556 if (avChannelLayout & AV_CH_TOP_BACK_RIGHT)
557 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopBackRight);
558 if (avChannelLayout & AV_CH_TOP_BACK_CENTER)
559 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopBackCenter);
560 if (avChannelLayout & AV_CH_TOP_SIDE_LEFT)
561 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopSideLeft);
562 if (avChannelLayout & AV_CH_TOP_SIDE_RIGHT)
563 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopSideRight);
564 if (avChannelLayout & AV_CH_BOTTOM_FRONT_CENTER)
565 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BottomFrontCenter);
566 if (avChannelLayout & AV_CH_BOTTOM_FRONT_LEFT)
567 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BottomFrontLeft);
568 if (avChannelLayout & AV_CH_BOTTOM_FRONT_RIGHT)
569 channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BottomFrontRight);
570 return QAudioFormat::ChannelConfig(channelConfig);
571}
572
573QAudioFormat
574QFFmpegMediaFormatInfo::audioFormatFromCodecParameters(const AVCodecParameters &codecpar)
575{
576 QAudioFormat format;
577 format.setSampleFormat(sampleFormat(AVSampleFormat(codecpar.format)));
578 format.setSampleRate(codecpar.sample_rate);
579#if QT_FFMPEG_HAS_AV_CHANNEL_LAYOUT
580 uint64_t channelLayout = 0;
581 if (codecpar.ch_layout.order == AV_CHANNEL_ORDER_NATIVE)
582 channelLayout = codecpar.ch_layout.u.mask;
583 else
584 channelLayout = avChannelLayout(QAudioFormat::defaultChannelConfigForChannelCount(codecpar.ch_layout.nb_channels));
585#else
586 uint64_t channelLayout = codecpar.channel_layout;
587 if (!channelLayout)
588 channelLayout = avChannelLayout(QAudioFormat::defaultChannelConfigForChannelCount(codecpar.channels));
589#endif
590 format.setChannelConfig(channelConfigForAVLayout(channelLayout));
591 return format;
592}
593
594QT_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