File indexing completed on 2025-01-19 03:57:03

0001 /*********************************************************
0002  * Copyright (C) 2020, Val Doroshchuk <valbok@gmail.com> *
0003  *                                                       *
0004  * This file is part of QtAVPlayer.                      *
0005  * Free Qt Media Player based on FFmpeg.                 *
0006  *********************************************************/
0007 
0008 #include "qavaudioframe.h"
0009 #include "qavframe_p.h"
0010 #include "qavaudiocodec_p.h"
0011 #include <QDebug>
0012 
0013 extern "C" {
0014 #include "libswresample/swresample.h"
0015 }
0016 
0017 QT_BEGIN_NAMESPACE
0018 
0019 class QAVAudioFramePrivate : public QAVFramePrivate
0020 {
0021 public:
0022     QAVAudioFormat outAudioFormat;
0023     int inSampleRate = 0;
0024     SwrContext *swr_ctx = nullptr;
0025     uint8_t *audioBuf = nullptr;
0026     QByteArray data;
0027 };
0028 
0029 QAVAudioFrame::QAVAudioFrame()
0030     : QAVFrame(*new QAVAudioFramePrivate)
0031 {
0032 }
0033 
0034 QAVAudioFrame::~QAVAudioFrame()
0035 {
0036     Q_D(QAVAudioFrame);
0037     swr_free(&d->swr_ctx);
0038     av_freep(&d->audioBuf);
0039 }
0040 
0041 QAVAudioFrame::QAVAudioFrame(const QAVFrame &other)
0042     : QAVFrame(*new QAVAudioFramePrivate)
0043 {
0044     operator=(other);
0045 }
0046 
0047 QAVAudioFrame::QAVAudioFrame(const QAVAudioFrame &other)
0048     : QAVFrame(*new QAVAudioFramePrivate)
0049 {
0050     operator=(other);
0051 }
0052 
0053 QAVAudioFrame::QAVAudioFrame(const QAVAudioFormat &format, const QByteArray &data)
0054     : QAVAudioFrame()
0055 {
0056     Q_D(QAVAudioFrame);
0057     d->outAudioFormat = format;
0058     d->data = data;
0059 }
0060 
0061 QAVAudioFrame &QAVAudioFrame::operator=(const QAVFrame &other)
0062 {
0063     Q_D(QAVAudioFrame);
0064     QAVFrame::operator=(other);
0065     d->data.clear();
0066 
0067     return *this;
0068 }
0069 
0070 QAVAudioFrame &QAVAudioFrame::operator=(const QAVAudioFrame &other)
0071 {
0072     Q_D(QAVAudioFrame);
0073     QAVFrame::operator=(other);
0074     auto rhs = reinterpret_cast<QAVAudioFramePrivate *>(other.d_ptr.get());
0075     d->outAudioFormat = rhs->outAudioFormat;
0076     d->data = rhs->data;
0077 
0078     return *this;
0079 }
0080 
0081 QAVAudioFrame::operator bool() const
0082 {
0083     Q_D(const QAVAudioFrame);
0084     return (d->outAudioFormat &&!d->data.isEmpty()) || QAVFrame::operator bool();
0085 }
0086 
0087 static const QAVAudioCodec *audioCodec(const QAVCodec *c)
0088 {
0089     return reinterpret_cast<const QAVAudioCodec *>(c);
0090 }
0091 
0092 QAVAudioFormat QAVAudioFrame::format() const
0093 {
0094     Q_D(const QAVAudioFrame);
0095     if (d->outAudioFormat)
0096         return d->outAudioFormat;
0097 
0098     if (!d->stream)
0099         return {};
0100 
0101     auto c = audioCodec(d->stream.codec().data());
0102     if (!c)
0103         return {};
0104 
0105     auto format = c->audioFormat();
0106     if (format.sampleFormat() != QAVAudioFormat::Int32)
0107         format.setSampleFormat(QAVAudioFormat::Int32);
0108 
0109     return format;
0110 }
0111 
0112 QByteArray QAVAudioFrame::data() const
0113 {
0114     auto d = const_cast<QAVAudioFramePrivate *>(reinterpret_cast<QAVAudioFramePrivate *>(d_ptr.get()));
0115     const auto frame = d->frame;
0116     if (!frame)
0117         return {};
0118 
0119     if (d->outAudioFormat && !d->data.isEmpty())
0120         return d->data;
0121 
0122     const auto fmt = format();
0123     AVSampleFormat outFormat = AV_SAMPLE_FMT_NONE;
0124 #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 23, 0)
0125     int64_t outChannelLayout = av_get_default_channel_layout(fmt.channelCount());
0126 #else
0127     AVChannelLayout outChannelLayout;
0128     av_channel_layout_default(&outChannelLayout, fmt.channelCount());
0129 #endif
0130     int outSampleRate = fmt.sampleRate();
0131 
0132     switch (fmt.sampleFormat()) {
0133     case QAVAudioFormat::UInt8:
0134         outFormat = AV_SAMPLE_FMT_U8;
0135         break;
0136     case QAVAudioFormat::Int16:
0137         outFormat = AV_SAMPLE_FMT_S16;
0138         break;
0139     case QAVAudioFormat::Int32:
0140         outFormat = AV_SAMPLE_FMT_S32;
0141         break;
0142     case QAVAudioFormat::Float:
0143         outFormat = AV_SAMPLE_FMT_FLT;
0144         break;
0145     default:
0146         qWarning() << "Could not negotiate output format:" << fmt.sampleFormat();
0147         return {};
0148     }
0149 
0150 #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 23, 0)
0151     int64_t channelLayout = (frame->channel_layout && frame->channels == av_get_channel_layout_nb_channels(frame->channel_layout))
0152         ? frame->channel_layout
0153         : av_get_default_channel_layout(frame->channels);
0154     bool needsConvert = frame->format != outFormat || channelLayout != outChannelLayout || frame->sample_rate != outSampleRate;
0155 #else
0156     AVChannelLayout channelLayout =frame->ch_layout;
0157     bool needsConvert = frame->format != outFormat || av_channel_layout_compare(&channelLayout, &outChannelLayout) || frame->sample_rate != outSampleRate;
0158 #endif
0159 
0160     if (needsConvert && (fmt != d->outAudioFormat || frame->sample_rate != d->inSampleRate || !d->swr_ctx)) {
0161         swr_free(&d->swr_ctx);
0162 #if LIBSWRESAMPLE_VERSION_INT <= AV_VERSION_INT(4, 4, 0)
0163         d->swr_ctx = swr_alloc_set_opts(nullptr,
0164                                         outChannelLayout, outFormat, outSampleRate,
0165                                         channelLayout, AVSampleFormat(frame->format), frame->sample_rate,
0166                                         0, nullptr);
0167 #else
0168         swr_alloc_set_opts2(&d->swr_ctx,
0169                             &outChannelLayout, outFormat, outSampleRate,
0170                             &channelLayout, AVSampleFormat(frame->format), frame->sample_rate,
0171                             0, nullptr);
0172 #endif
0173         int ret = swr_init(d->swr_ctx);
0174         if (!d->swr_ctx || ret < 0) {
0175             qWarning() << "Could not init SwrContext:" << ret;
0176             return {};
0177         }
0178     }
0179 
0180     if (d->swr_ctx) {
0181         const uint8_t **in = (const uint8_t **)frame->extended_data;
0182         int outCount = (int64_t)frame->nb_samples * outSampleRate / frame->sample_rate + 256;
0183         int outSize = av_samples_get_buffer_size(nullptr, fmt.channelCount(), outCount, outFormat, 0);
0184 
0185         av_freep(&d->audioBuf);
0186         uint8_t **out = &d->audioBuf;
0187         unsigned bufSize = 0;
0188         av_fast_malloc(&d->audioBuf, &bufSize, outSize);
0189 
0190         int samples = swr_convert(d->swr_ctx, out, outCount, in, frame->nb_samples);
0191         if (samples < 0) {
0192             qWarning() << "Could not convert audio samples";
0193             return {};
0194         }
0195 
0196         int size = samples * fmt.channelCount() * av_get_bytes_per_sample(outFormat);
0197         // Make deep copy
0198         d->data = QByteArray((const char *)d->audioBuf, size);
0199     } else {
0200         int size = av_samples_get_buffer_size(nullptr,
0201 #if LIBAVUTIL_VERSION_INT <= AV_VERSION_INT(57, 23, 0)
0202                                               frame->channels,
0203 #else
0204                                               outChannelLayout.nb_channels,
0205 #endif
0206                                               frame->nb_samples,
0207                                               AVSampleFormat(frame->format), 1);
0208         d->data = QByteArray::fromRawData((const char *)frame->data[0], size);
0209     }
0210 
0211     d->inSampleRate = frame->sample_rate;
0212     d->outAudioFormat = fmt;
0213     return d->data;
0214 }
0215 
0216 QT_END_NAMESPACE