diff options
Diffstat (limited to 'src/plugins/multimedia/ffmpeg/qffmpegmediaformatinfo.cpp')
-rw-r--r-- | src/plugins/multimedia/ffmpeg/qffmpegmediaformatinfo.cpp | 517 |
1 files changed, 517 insertions, 0 deletions
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegmediaformatinfo.cpp b/src/plugins/multimedia/ffmpeg/qffmpegmediaformatinfo.cpp new file mode 100644 index 000000000..6389b4eed --- /dev/null +++ b/src/plugins/multimedia/ffmpeg/qffmpegmediaformatinfo.cpp @@ -0,0 +1,517 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qffmpegmediaformatinfo_p.h" +#include "qaudioformat.h" +#include "qimagewriter.h" + +#include <qloggingcategory.h> + +QT_BEGIN_NAMESPACE + +static Q_LOGGING_CATEGORY(qLcMediaFormatInfo, "qt.multimedia.ffmpeg.mediaformatinfo") + +static struct { + AVCodecID id; + QMediaFormat::VideoCodec codec; +} videoCodecMap [] = { + { AV_CODEC_ID_MPEG1VIDEO, QMediaFormat::VideoCodec::MPEG1 }, + { AV_CODEC_ID_MPEG2VIDEO, QMediaFormat::VideoCodec::MPEG2 }, + { AV_CODEC_ID_MPEG4, QMediaFormat::VideoCodec::MPEG4 }, + { AV_CODEC_ID_H264, QMediaFormat::VideoCodec::H264 }, + { AV_CODEC_ID_HEVC, QMediaFormat::VideoCodec::H265 }, + { AV_CODEC_ID_VP8, QMediaFormat::VideoCodec::VP8 }, + { AV_CODEC_ID_VP9, QMediaFormat::VideoCodec::VP9 }, + { AV_CODEC_ID_AV1, QMediaFormat::VideoCodec::AV1 }, + { AV_CODEC_ID_THEORA, QMediaFormat::VideoCodec::Theora }, + { AV_CODEC_ID_WMV3, QMediaFormat::VideoCodec::WMV }, + { AV_CODEC_ID_MJPEG, QMediaFormat::VideoCodec::MotionJPEG } +}; + +static AVCodecID codecId(QMediaFormat::VideoCodec codec) +{ + for (const auto &c : videoCodecMap) { + if (c.codec == codec) + return c.id; + } + return AV_CODEC_ID_NONE; +} + +static struct { + AVCodecID id; + QMediaFormat::AudioCodec codec; +} audioCodecMap [] = { + { AV_CODEC_ID_MP3, QMediaFormat::AudioCodec::MP3 }, + { AV_CODEC_ID_AAC, QMediaFormat::AudioCodec::AAC }, + { AV_CODEC_ID_AC3, QMediaFormat::AudioCodec::AC3 }, + { AV_CODEC_ID_EAC3, QMediaFormat::AudioCodec::EAC3 }, + { AV_CODEC_ID_FLAC, QMediaFormat::AudioCodec::FLAC }, + { AV_CODEC_ID_TRUEHD, QMediaFormat::AudioCodec::DolbyTrueHD }, + { AV_CODEC_ID_OPUS, QMediaFormat::AudioCodec::Opus }, + { AV_CODEC_ID_VORBIS, QMediaFormat::AudioCodec::Vorbis }, + { AV_CODEC_ID_PCM_S16LE, QMediaFormat::AudioCodec::Wave }, + { AV_CODEC_ID_WMAPRO, QMediaFormat::AudioCodec::WMA }, + { AV_CODEC_ID_ALAC, QMediaFormat::AudioCodec::ALAC } +}; + +static AVCodecID codecId(QMediaFormat::AudioCodec codec) +{ + for (const auto &c : audioCodecMap) { + if (c.codec == codec) + return c.id; + } + return AV_CODEC_ID_NONE; +} + +// mimetypes are mostly copied from qmediaformat.cpp. Unfortunately, FFmpeg uses +// in some cases slightly different mimetypes +static const struct +{ + QMediaFormat::FileFormat fileFormat; + const char *mimeType; + const char *name; // disambiguate if we have several muxers/demuxers +} map[QMediaFormat::LastFileFormat + 1] = { + { QMediaFormat::WMV, "video/x-ms-asf", "asf" }, + { QMediaFormat::AVI, "video/x-msvideo", nullptr }, + { QMediaFormat::Matroska, "video/x-matroska", nullptr }, + { QMediaFormat::MPEG4, "video/mp4", "mp4" }, + { QMediaFormat::Ogg, "video/ogg", nullptr }, + // QuickTime is the same as MP4 + { QMediaFormat::WebM, "video/webm", "webm" }, + // Audio Formats + // Mpeg4Audio is the same as MP4 without the video codecs + { QMediaFormat::AAC, "audio/aac", nullptr }, + // WMA is the same as WMV + { QMediaFormat::FLAC, "audio/x-flac", nullptr }, + { QMediaFormat::MP3, "audio/mpeg", "mp3" }, + { QMediaFormat::Wave, "audio/x-wav", nullptr }, + { QMediaFormat::UnspecifiedFormat, nullptr, nullptr } +}; + +template <typename AVFormat> +static QMediaFormat::FileFormat formatForAVFormat(AVFormat *format) +{ + + if (!format->mime_type || !*format->mime_type) + return QMediaFormat::UnspecifiedFormat; + + auto *m = map; + while (m->fileFormat != QMediaFormat::UnspecifiedFormat) { + if (m->mimeType && !strcmp(m->mimeType, format->mime_type)) { + // check if the name matches. This is used to disambiguate where FFmpeg provides + // multiple muxers or demuxers + if (!m->name || !strcmp(m->name, format->name)) + return m->fileFormat; + } + ++m; + } + + return QMediaFormat::UnspecifiedFormat; +} + +static const AVOutputFormat *avFormatForFormat(QMediaFormat::FileFormat format) +{ + if (format == QMediaFormat::QuickTime || format == QMediaFormat::Mpeg4Audio) + format = QMediaFormat::MPEG4; + if (format == QMediaFormat::WMA) + format = QMediaFormat::WMV; + + auto *m = map; + while (m->fileFormat != QMediaFormat::UnspecifiedFormat) { + if (m->fileFormat == format) + return av_guess_format(m->name, nullptr, m->mimeType); + ++m; + } + + return nullptr; +} + + +QFFmpegMediaFormatInfo::QFFmpegMediaFormatInfo() +{ + qCDebug(qLcMediaFormatInfo) << ">>>> listing codecs"; + + QList<QMediaFormat::AudioCodec> audioEncoders; + QList<QMediaFormat::AudioCodec> extraAudioDecoders; + QList<QMediaFormat::VideoCodec> videoEncoders; + QList<QMediaFormat::VideoCodec> extraVideoDecoders; + + const AVCodecDescriptor *descriptor = nullptr; + while ((descriptor = avcodec_descriptor_next(descriptor))) { + const bool canEncode = QFFmpeg::findAVEncoder(descriptor->id) != nullptr; + const bool canDecode = QFFmpeg::findAVDecoder(descriptor->id) != nullptr; + auto videoCodec = videoCodecForAVCodecId(descriptor->id); + auto audioCodec = audioCodecForAVCodecId(descriptor->id); + if (descriptor->type == AVMEDIA_TYPE_VIDEO && videoCodec != QMediaFormat::VideoCodec::Unspecified) { + if (canEncode) { + if (!videoEncoders.contains(videoCodec)) + videoEncoders.append(videoCodec); + } else if (canDecode) { + if (!extraVideoDecoders.contains(videoCodec)) + extraVideoDecoders.append(videoCodec); + } + } else if (descriptor->type == AVMEDIA_TYPE_AUDIO + && audioCodec != QMediaFormat::AudioCodec::Unspecified) { + if (canEncode) { + if (!audioEncoders.contains(audioCodec)) + audioEncoders.append(audioCodec); + } else if (canDecode) { + if (!extraAudioDecoders.contains(audioCodec)) + extraAudioDecoders.append(audioCodec); + } + } + } + + // get demuxers +// qCDebug(qLcMediaFormatInfo) << ">>>> Muxers"; + void *opaque = nullptr; + const AVOutputFormat *outputFormat = nullptr; + while ((outputFormat = av_muxer_iterate(&opaque))) { + auto mediaFormat = formatForAVFormat(outputFormat); + if (mediaFormat == QMediaFormat::UnspecifiedFormat) + continue; +// qCDebug(qLcMediaFormatInfo) << " mux:" << outputFormat->name << outputFormat->long_name << outputFormat->mime_type << outputFormat->extensions << mediaFormat; + + CodecMap encoder; + encoder.format = mediaFormat; + + for (auto codec : audioEncoders) { + auto id = codecId(codec); + // only add the codec if it can be used with this container + if (avformat_query_codec(outputFormat, id, FF_COMPLIANCE_NORMAL) == 1) { + // add codec for container +// qCDebug(qLcMediaFormatInfo) << " " << codec << Qt::hex << av_codec_get_tag(outputFormat->codec_tag, id); + encoder.audio.append(codec); + } + } + for (auto codec : videoEncoders) { + auto id = codecId(codec); + // only add the codec if it can be used with this container + if (avformat_query_codec(outputFormat, id, FF_COMPLIANCE_NORMAL) == 1) { + // add codec for container +// qCDebug(qLcMediaFormatInfo) << " " << codec << Qt::hex << av_codec_get_tag(outputFormat->codec_tag, id); + encoder.video.append(codec); + } + } + + // sanity checks and handling special cases + if (encoder.audio.isEmpty() && encoder.video.isEmpty()) + continue; + switch (encoder.format) { + case QMediaFormat::WMV: + // add WMA + encoders.append({ QMediaFormat::WMA, encoder.audio, {} }); + break; + case QMediaFormat::MPEG4: + // add Mpeg4Audio and QuickTime + encoders.append({ QMediaFormat::QuickTime, encoder.audio, encoder.video }); + encoders.append({ QMediaFormat::Mpeg4Audio, encoder.audio, {} }); + break; + case QMediaFormat::Wave: + // FFmpeg allows other encoded formats in WAV containers, but we do not want that + if (!encoder.audio.contains(QMediaFormat::AudioCodec::Wave)) + continue; + encoder.audio = { QMediaFormat::AudioCodec::Wave }; + break; + default: + break; + } + encoders.append(encoder); + } + + // FFmpeg doesn't allow querying supported codecs for decoders + // we take a simple approximation stating that we can decode what we + // can encode. That's a safe subset. + decoders = encoders; + +#ifdef Q_OS_WINDOWS + // MediaFoundation HVEC encoder fails when processing frames + for (auto &encoder : encoders) { + auto h265index = encoder.video.indexOf(QMediaFormat::VideoCodec::H265); + if (h265index >= 0) + encoder.video.removeAt(h265index); + } +#endif + +// qCDebug(qLcMediaFormatInfo) << "extraDecoders:" << extraAudioDecoders << extraVideoDecoders; + // FFmpeg can currently only decode WMA and WMV, not encode + if (extraAudioDecoders.contains(QMediaFormat::AudioCodec::WMA)) { + decoders[QMediaFormat::WMA].audio.append(QMediaFormat::AudioCodec::WMA); + decoders[QMediaFormat::WMV].audio.append(QMediaFormat::AudioCodec::WMA); + } + if (extraVideoDecoders.contains(QMediaFormat::VideoCodec::WMV)) { + decoders[QMediaFormat::WMV].video.append(QMediaFormat::VideoCodec::WMV); + } + + // Add image formats we support. We currently simply use Qt's built-in image write + // to save images. That doesn't give us HDR support or support for larger bit depths, + // but most cameras can currently not generate those anyway. + const auto imgFormats = QImageWriter::supportedImageFormats(); + for (const auto &f : imgFormats) { + if (f == "png") + imageFormats.append(QImageCapture::PNG); + else if (f == "jpeg") + imageFormats.append(QImageCapture::JPEG); + else if (f == "tiff") + imageFormats.append(QImageCapture::Tiff); + else if (f == "webp") + imageFormats.append(QImageCapture::WebP); + } + +} + +QFFmpegMediaFormatInfo::~QFFmpegMediaFormatInfo() = default; + +QMediaFormat::AudioCodec QFFmpegMediaFormatInfo::audioCodecForAVCodecId(AVCodecID id) +{ + for (const auto &c : audioCodecMap) { + if (c.id == id) + return c.codec; + } + return QMediaFormat::AudioCodec::Unspecified; +} + +QMediaFormat::VideoCodec QFFmpegMediaFormatInfo::videoCodecForAVCodecId(AVCodecID id) +{ + for (const auto &c : videoCodecMap) { + if (c.id == id) + return c.codec; + } + return QMediaFormat::VideoCodec::Unspecified; +} + +QMediaFormat::FileFormat +QFFmpegMediaFormatInfo::fileFormatForAVInputFormat(const AVInputFormat *format) +{ + // Seems like FFmpeg uses different names for muxers and demuxers of the same format. + // that makes it somewhat cumbersome to detect things correctly. + // The input formats have a comma separated list of short names. We check the first one of those + // as the docs specify that you only append to the list + static const struct + { + QMediaFormat::FileFormat fileFormat; + const char *name; + } map[QMediaFormat::LastFileFormat + 1] = { + { QMediaFormat::WMV, "asf" }, + { QMediaFormat::AVI, "avi" }, + { QMediaFormat::Matroska, "matroska" }, + { QMediaFormat::MPEG4, "mov" }, + { QMediaFormat::Ogg, "ogg" }, + { QMediaFormat::WebM, "webm" }, + // Audio Formats + // Mpeg4Audio is the same as MP4 without the video codecs + { QMediaFormat::AAC, "aac"}, + // WMA is the same as WMV + { QMediaFormat::FLAC, "flac" }, + { QMediaFormat::MP3, "mp3" }, + { QMediaFormat::Wave, "wav" }, + { QMediaFormat::UnspecifiedFormat, nullptr } + }; + + if (!format->name) + return QMediaFormat::UnspecifiedFormat; + + auto *m = map; + while (m->fileFormat != QMediaFormat::UnspecifiedFormat) { + if (!strncmp(m->name, format->name, strlen(m->name))) + return m->fileFormat; + ++m; + } + + return QMediaFormat::UnspecifiedFormat; +} + +const AVOutputFormat * +QFFmpegMediaFormatInfo::outputFormatForFileFormat(QMediaFormat::FileFormat format) +{ + return avFormatForFormat(format); +} + +AVCodecID QFFmpegMediaFormatInfo::codecIdForVideoCodec(QMediaFormat::VideoCodec codec) +{ + return codecId(codec); +} + +AVCodecID QFFmpegMediaFormatInfo::codecIdForAudioCodec(QMediaFormat::AudioCodec codec) +{ + return codecId(codec); +} + +QAudioFormat::SampleFormat QFFmpegMediaFormatInfo::sampleFormat(AVSampleFormat format) +{ + switch (format) { + case AV_SAMPLE_FMT_NONE: + default: + return QAudioFormat::Unknown; + case AV_SAMPLE_FMT_U8: ///< unsigned 8 bits + case AV_SAMPLE_FMT_U8P: ///< unsigned 8 bits: planar + return QAudioFormat::UInt8; + case AV_SAMPLE_FMT_S16: ///< signed 16 bits + case AV_SAMPLE_FMT_S16P: ///< signed 16 bits: planar + return QAudioFormat::Int16; + case AV_SAMPLE_FMT_S32: ///< signed 32 bits + case AV_SAMPLE_FMT_S32P: ///< signed 32 bits: planar + return QAudioFormat::Int32; + case AV_SAMPLE_FMT_FLT: ///< float + case AV_SAMPLE_FMT_FLTP: ///< float: planar + return QAudioFormat::Float; + case AV_SAMPLE_FMT_DBL: ///< double + case AV_SAMPLE_FMT_DBLP: ///< double: planar + case AV_SAMPLE_FMT_S64: ///< signed 64 bits + case AV_SAMPLE_FMT_S64P: ///< signed 64 bits, planar + // let's use float + return QAudioFormat::Float; + } +} + +AVSampleFormat QFFmpegMediaFormatInfo::avSampleFormat(QAudioFormat::SampleFormat format) +{ + switch (format) { + case QAudioFormat::UInt8: + return AV_SAMPLE_FMT_U8; + case QAudioFormat::Int16: + return AV_SAMPLE_FMT_S16; + case QAudioFormat::Int32: + return AV_SAMPLE_FMT_S32; + case QAudioFormat::Float: + return AV_SAMPLE_FMT_FLT; + default: + return AV_SAMPLE_FMT_NONE; + } +} + +int64_t QFFmpegMediaFormatInfo::avChannelLayout(QAudioFormat::ChannelConfig channelConfig) +{ + int64_t avChannelLayout = 0; + if (channelConfig & (1 << QAudioFormat::FrontLeft)) + avChannelLayout |= AV_CH_FRONT_LEFT; + if (channelConfig & (1 << QAudioFormat::FrontRight)) + avChannelLayout |= AV_CH_FRONT_RIGHT; + if (channelConfig & (1 << QAudioFormat::FrontCenter)) + avChannelLayout |= AV_CH_FRONT_CENTER; + if (channelConfig & (1 << QAudioFormat::LFE)) + avChannelLayout |= AV_CH_LOW_FREQUENCY; + if (channelConfig & (1 << QAudioFormat::BackLeft)) + avChannelLayout |= AV_CH_BACK_LEFT; + if (channelConfig & (1 << QAudioFormat::BackRight)) + avChannelLayout |= AV_CH_BACK_RIGHT; + if (channelConfig & (1 << QAudioFormat::FrontLeftOfCenter)) + avChannelLayout |= AV_CH_FRONT_LEFT_OF_CENTER; + if (channelConfig & (1 << QAudioFormat::FrontRightOfCenter)) + avChannelLayout |= AV_CH_FRONT_RIGHT_OF_CENTER; + if (channelConfig & (1 << QAudioFormat::BackCenter)) + avChannelLayout |= AV_CH_BACK_CENTER; + if (channelConfig & (1 << QAudioFormat::LFE2)) + avChannelLayout |= AV_CH_LOW_FREQUENCY_2; + if (channelConfig & (1 << QAudioFormat::SideLeft)) + avChannelLayout |= AV_CH_SIDE_LEFT; + if (channelConfig & (1 << QAudioFormat::SideRight)) + avChannelLayout |= AV_CH_SIDE_RIGHT; + if (channelConfig & (1 << QAudioFormat::TopFrontLeft)) + avChannelLayout |= AV_CH_TOP_FRONT_LEFT; + if (channelConfig & (1 << QAudioFormat::TopFrontRight)) + avChannelLayout |= AV_CH_TOP_FRONT_RIGHT; + if (channelConfig & (1 << QAudioFormat::TopFrontCenter)) + avChannelLayout |= AV_CH_TOP_FRONT_CENTER; + if (channelConfig & (1 << QAudioFormat::TopCenter)) + avChannelLayout |= AV_CH_TOP_CENTER; + if (channelConfig & (1 << QAudioFormat::TopBackLeft)) + avChannelLayout |= AV_CH_TOP_BACK_LEFT; + if (channelConfig & (1 << QAudioFormat::TopBackRight)) + avChannelLayout |= AV_CH_TOP_BACK_RIGHT; + if (channelConfig & (1 << QAudioFormat::TopBackCenter)) + avChannelLayout |= AV_CH_TOP_BACK_CENTER; + // The defines used below got added together for FFmpeg 4.4 +#ifdef AV_CH_TOP_SIDE_LEFT + if (channelConfig & (1 << QAudioFormat::TopSideLeft)) + avChannelLayout |= AV_CH_TOP_SIDE_LEFT; + if (channelConfig & (1 << QAudioFormat::TopSideRight)) + avChannelLayout |= AV_CH_TOP_SIDE_RIGHT; + if (channelConfig & (1 << QAudioFormat::BottomFrontCenter)) + avChannelLayout |= AV_CH_BOTTOM_FRONT_CENTER; + if (channelConfig & (1 << QAudioFormat::BottomFrontLeft)) + avChannelLayout |= AV_CH_BOTTOM_FRONT_LEFT; + if (channelConfig & (1 << QAudioFormat::BottomFrontRight)) + avChannelLayout |= AV_CH_BOTTOM_FRONT_RIGHT; +#endif + return avChannelLayout; +} + +QAudioFormat::ChannelConfig QFFmpegMediaFormatInfo::channelConfigForAVLayout(int64_t avChannelLayout) +{ + quint32 channelConfig = 0; + if (avChannelLayout & AV_CH_FRONT_LEFT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontLeft); + if (avChannelLayout & AV_CH_FRONT_RIGHT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontRight); + if (avChannelLayout & AV_CH_FRONT_CENTER) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontCenter); + if (avChannelLayout & AV_CH_LOW_FREQUENCY) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::LFE); + if (avChannelLayout & AV_CH_BACK_LEFT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BackLeft); + if (avChannelLayout & AV_CH_BACK_RIGHT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BackRight); + if (avChannelLayout & AV_CH_FRONT_LEFT_OF_CENTER) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontLeftOfCenter); + if (avChannelLayout & AV_CH_FRONT_RIGHT_OF_CENTER) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::FrontRightOfCenter); + if (avChannelLayout & AV_CH_BACK_CENTER) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BackCenter); + if (avChannelLayout & AV_CH_LOW_FREQUENCY_2) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::LFE2); + if (avChannelLayout & AV_CH_SIDE_LEFT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::SideLeft); + if (avChannelLayout & AV_CH_SIDE_RIGHT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::SideRight); + if (avChannelLayout & AV_CH_TOP_FRONT_LEFT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopFrontLeft); + if (avChannelLayout & AV_CH_TOP_FRONT_RIGHT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopFrontRight); + if (avChannelLayout & AV_CH_TOP_FRONT_CENTER) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopFrontCenter); + if (avChannelLayout & AV_CH_TOP_CENTER) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopCenter); + if (avChannelLayout & AV_CH_TOP_BACK_LEFT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopBackLeft); + if (avChannelLayout & AV_CH_TOP_BACK_RIGHT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopBackRight); + if (avChannelLayout & AV_CH_TOP_BACK_CENTER) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopBackCenter); + // The defines used below got added together for FFmpeg 4.4 +#ifdef AV_CH_TOP_SIDE_LEFT + if (avChannelLayout & AV_CH_TOP_SIDE_LEFT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopSideLeft); + if (avChannelLayout & AV_CH_TOP_SIDE_RIGHT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::TopSideRight); + if (avChannelLayout & AV_CH_BOTTOM_FRONT_CENTER) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BottomFrontCenter); + if (avChannelLayout & AV_CH_BOTTOM_FRONT_LEFT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BottomFrontLeft); + if (avChannelLayout & AV_CH_BOTTOM_FRONT_RIGHT) + channelConfig |= QAudioFormat::channelConfig(QAudioFormat::BottomFrontRight); +#endif + return QAudioFormat::ChannelConfig(channelConfig); +} + +QAudioFormat QFFmpegMediaFormatInfo::audioFormatFromCodecParameters(AVCodecParameters *codecpar) +{ + QAudioFormat format; + format.setSampleFormat(sampleFormat(AVSampleFormat(codecpar->format))); + format.setSampleRate(codecpar->sample_rate); +#if QT_FFMPEG_OLD_CHANNEL_LAYOUT + uint64_t channelLayout = codecpar->channel_layout; + if (!channelLayout) + channelLayout = avChannelLayout(QAudioFormat::defaultChannelConfigForChannelCount(codecpar->channels)); +#else + uint64_t channelLayout = 0; + if (codecpar->ch_layout.order == AV_CHANNEL_ORDER_NATIVE) + channelLayout = codecpar->ch_layout.u.mask; + else + channelLayout = avChannelLayout(QAudioFormat::defaultChannelConfigForChannelCount(codecpar->ch_layout.nb_channels)); +#endif + format.setChannelConfig(channelConfigForAVLayout(channelLayout)); + return format; +} + +QT_END_NAMESPACE |