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