| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- #include "AudioPlayer.h"
- #include <cstring>
- #include <cmath>
- extern "C" {
- #include <libavutil/avutil.h>
- #include <libavutil/samplefmt.h>
- #include <libavutil/channel_layout.h>
- #include <libavutil/frame.h>
- #include <libavutil/mem.h>
- #include <libswresample/swresample.h>
- }
- #include "sonic/sonic.h"
- #include <QAudioDeviceInfo>
- #include <QAudioFormat>
- #include <QDebug>
- AudioPlayer::AudioPlayer() {}
- AudioPlayer::~AudioPlayer() { reset(); }
- void AudioPlayer::reset() {
- if (m_sonicCtx) {
- sonicDestroyStream(m_sonicCtx);
- m_sonicCtx = nullptr;
- }
- if (m_swrCtx) {
- swr_free(&m_swrCtx);
- m_swrCtx = nullptr;
- }
- if (m_swrBuffer) {
- av_free(m_swrBuffer);
- m_swrBuffer = nullptr;
- m_swrBufferSize = 0;
- }
- freeBuffers();
- if (m_audioOutput) {
- m_audioOutput->stop();
- delete m_audioOutput;
- m_audioOutput = nullptr;
- }
- m_audioDevice = nullptr;
- m_sampleRate = 0;
- m_channels = 0;
- m_format = AV_SAMPLE_FMT_NONE;
- m_lastSpeed = 1.0f;
- }
- void AudioPlayer::freeBuffers() {
- if (m_abuf) {
- av_freep(&m_abuf);
- m_abuf = nullptr;
- }
- if (m_abufOut) {
- av_freep(&m_abufOut);
- m_abufOut = nullptr;
- m_abufOutSize = 0;
- }
- m_maxBufSize = -1;
- }
- void AudioPlayer::init(const AVFrame* frame, float speed) {
- reset();
- initAudioOutput(frame, speed);
- }
- void AudioPlayer::initAudioOutput(const AVFrame* frame, float speed) {
- m_sampleRate = frame->sample_rate;
- m_channels = frame->ch_layout.nb_channels;
- m_format = (AVSampleFormat)frame->format;
- m_lastSpeed = speed;
- if (m_sonicCtx) {
- sonicDestroyStream(m_sonicCtx);
- m_sonicCtx = nullptr;
- }
- m_sonicCtx = sonicCreateStream(m_sampleRate, m_channels);
- setSpeed(speed);
- QAudioFormat fmt;
- fmt.setSampleRate(m_sampleRate);
- fmt.setChannelCount(m_channels);
- fmt.setSampleSize(16); // 目标格式 S16
- fmt.setCodec("audio/pcm");
- fmt.setByteOrder(QAudioFormat::LittleEndian);
- fmt.setSampleType(QAudioFormat::SignedInt);
- QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
- if (!info.isFormatSupported(fmt)) {
- qWarning() << "音频格式不支持,尝试最近格式";
- fmt = info.nearestFormat(fmt);
- }
- m_audioOutput = new QAudioOutput(fmt, nullptr);
- m_audioDevice = m_audioOutput->start();
- }
- void AudioPlayer::setSpeed(float speed) {
- if (m_sonicCtx) {
- sonicSetSpeed(m_sonicCtx, speed);
- sonicSetPitch(m_sonicCtx, 1.0f);
- sonicSetRate(m_sonicCtx, 1.0f);
- }
- m_lastSpeed = speed;
- }
- void AudioPlayer::setOutputDevice(QIODevice* device) {
- m_audioDevice = device;
- }
- void AudioPlayer::setAudioOutput(QAudioOutput* output) {
- m_audioOutput = output;
- }
- QIODevice* AudioPlayer::getOutputDevice() const {
- return m_audioDevice;
- }
- QAudioOutput* AudioPlayer::getAudioOutput() const {
- return m_audioOutput;
- }
- bool AudioPlayer::needReinit(const AVFrame* frame, float speed) const {
- if (!m_audioOutput) return true;
- if (m_sampleRate != frame->sample_rate) return true;
- if (m_channels != frame->ch_layout.nb_channels) return true;
- if (m_format != (AVSampleFormat)frame->format) return true;
- if (std::abs(m_lastSpeed - speed) > 1e-3) return true;
- return false;
- }
- void AudioPlayer::play(AVFrame* frame, float speed) {
- if (!m_audioDevice) return;
- m_sampleRate = frame->sample_rate;
- m_channels = frame->ch_layout.nb_channels;
- m_format = (AVSampleFormat)frame->format;
- // 1. 重采样到 S16
- const AVSampleFormat targetFmt = AV_SAMPLE_FMT_S16;
- uint8_t* inputData = nullptr;
- int inputSamples = frame->nb_samples;
- int inputBytes = av_samples_get_buffer_size(nullptr, m_channels, inputSamples, targetFmt, 1);
- if (m_format != targetFmt) {
- if (!m_swrCtx) {
- m_swrCtx = swr_alloc();
- swr_alloc_set_opts2(&m_swrCtx,
- &frame->ch_layout, // out_ch_layout
- targetFmt,
- m_sampleRate,
- &frame->ch_layout, // in_ch_layout
- m_format,
- m_sampleRate,
- 0,
- nullptr);
- swr_init(m_swrCtx);
- }
- if (!m_swrBuffer || m_swrBufferSize < inputBytes) {
- if (m_swrBuffer) av_free(m_swrBuffer);
- m_swrBuffer = (uint8_t*)av_malloc(inputBytes);
- m_swrBufferSize = inputBytes;
- }
- int outSamples = swr_convert(
- m_swrCtx,
- &m_swrBuffer, inputSamples,
- (const uint8_t**)frame->extended_data, inputSamples
- );
- inputData = m_swrBuffer;
- inputSamples = outSamples;
- inputBytes = av_samples_get_buffer_size(nullptr, m_channels, outSamples, targetFmt, 1);
- } else {
- inputData = frame->data[0];
- inputBytes = av_samples_get_buffer_size(nullptr, m_channels, inputSamples, targetFmt, 1);
- }
- // 2. 送 sonic 变速
- if (!m_sonicCtx) {
- m_sonicCtx = sonicCreateStream(m_sampleRate, m_channels);
- }
- setSpeed(speed);
- int out_ret = sonicWriteShortToStream(m_sonicCtx, (int16_t*)inputData, inputBytes / (m_channels * 2));
- int num_samples = sonicSamplesAvailable(m_sonicCtx);
- int out_size = num_samples * 2 * m_channels;
- av_fast_malloc(&m_abufOut, &m_abufOutSize, out_size);
- int sonic_samples = 0;
- if (out_ret) {
- sonic_samples = sonicReadShortFromStream(m_sonicCtx, (int16_t*)m_abufOut, num_samples);
- out_size = sonic_samples * 2 * m_channels;
- }
- // 3. 输出到Qt
- int bytesWrite = 0;
- while (bytesWrite < out_size) {
- int written = m_audioDevice->write((const char*)m_abufOut + bytesWrite, out_size - bytesWrite);
- if (written <= 0) break;
- bytesWrite += written;
- }
- }
|