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