| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- #include "AudioPlayer.h"
- #include <cstring>
- #include <cmath>
- #include <QDebug>
- 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"
- AudioPlayer::AudioPlayer() {}
- AudioPlayer::~AudioPlayer() { reset(); }
- bool AudioPlayer::open(const AVFrame* frame, float speed) {
- qDebug() << "[AUDIO-PLAYER] open: sample_rate=" << frame->sample_rate << "channels=" << frame->ch_layout.nb_channels << "format=" << frame->format << "speed=" << speed;
- QMutexLocker locker(&m_mutex);
- qDebug() << "[AUDIO-PLAYER] got mutex";
- reset();
- qDebug() << "[AUDIO-PLAYER] after reset";
- return initAudioOutput(frame, speed);
- }
- bool AudioPlayer::initAudioOutput(const AVFrame* frame, float speed) {
- qDebug() << "[AUDIO-PLAYER] initAudioOutput begin";
- m_sampleRate = frame->sample_rate;
- m_channels = frame->ch_layout.nb_channels;
- m_format = (AVSampleFormat)frame->format;
- m_speed = speed;
- m_volume = 1.0f;
- releaseSonic();
- ensureSonic(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);
- qDebug() << "[AUDIO-PLAYER] before QAudioOutput, deviceInfo isNull=" << m_deviceInfo.isNull();
- if (!m_deviceInfo.isNull()) {
- if (!m_deviceInfo.isFormatSupported(fmt)) {
- qWarning() << "音频格式不支持,尝试最近格式";
- fmt = m_deviceInfo.nearestFormat(fmt);
- }
- qDebug() << "[AUDIO-PLAYER] before QAudioOutput (custom device)";
- m_audioOutput = new QAudioOutput(m_deviceInfo, fmt, nullptr);
- } else {
- QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
- if (!info.isFormatSupported(fmt)) {
- qWarning() << "音频格式不支持,尝试最近格式";
- fmt = info.nearestFormat(fmt);
- }
- qDebug() << "[AUDIO-PLAYER] before QAudioOutput (default device)";
- m_audioOutput = new QAudioOutput(fmt, nullptr);
- }
- qDebug() << "[AUDIO-PLAYER] after QAudioOutput, m_audioOutput=" << m_audioOutput;
- // m_audioOutput->setBufferSize(16384);
- m_audioOutput->setVolume(m_volume);
- qDebug() << "[AUDIO-PLAYER] before start";
- m_audioDevice = m_audioOutput->start();
- qDebug() << "[AUDIO-PLAYER] after start, m_audioDevice=" << m_audioDevice;
- return m_audioDevice != nullptr;
- }
- bool AudioPlayer::play(const AVFrame* frame, float speed) {
- QMutexLocker locker(&m_mutex);
- if (!m_audioDevice) return false;
- if (m_sampleRate != frame->sample_rate || m_channels != frame->ch_layout.nb_channels || m_format != (AVSampleFormat)frame->format) {
- open(frame, speed);
- }
- m_speed = speed;
- setSpeed(speed);
- // 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) {
- ensureResampler(frame);
- 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 变速
- ensureSonic(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. 写入音频设备前判断可用空间
- if (m_audioOutput && m_audioOutput->bytesFree() < out_size) {
- qWarning() << "[AUDIO] QAudioOutput 缓冲区不够,丢帧 out_size=" << out_size << "bytesFree=" << m_audioOutput->bytesFree();
- return false;
- }
- if (out_size > 0)
- m_audioDevice->write((const char*)m_abufOut, out_size);
- return true;
- }
- void AudioPlayer::setSpeed(float speed) {
- // QMutexLocker locker(&m_mutex);
- m_speed = speed;
- if (m_sonicCtx) {
- sonicSetSpeed(m_sonicCtx, speed);
- sonicSetPitch(m_sonicCtx, 1.0f);
- sonicSetRate(m_sonicCtx, 1.0f);
- }
- }
- void AudioPlayer::setVolume(float volume) {
- QMutexLocker locker(&m_mutex);
- m_volume = volume;
- if (m_audioOutput) {
- m_audioOutput->setVolume(volume);
- }
- }
- bool AudioPlayer::setOutputDevice(const QAudioDeviceInfo& deviceInfo) {
- QMutexLocker locker(&m_mutex);
- m_deviceInfo = deviceInfo;
- if (m_audioOutput) {
- m_audioOutput->stop();
- delete m_audioOutput;
- m_audioOutput = nullptr;
- }
- return true;
- }
- void AudioPlayer::stop() {
- QMutexLocker locker(&m_mutex);
- if (m_audioOutput) {
- m_audioOutput->stop();
- }
- }
- void AudioPlayer::reset()
- {
- releaseSonic();
- releaseResampler();
- releaseAudioOutput();
- if (m_abufOut) {
- av_freep(&m_abufOut);
- m_abufOut = nullptr;
- m_abufOutSize = 0;
- }
- m_sampleRate = 0;
- m_channels = 0;
- m_format = AV_SAMPLE_FMT_NONE;
- m_speed = 1.0f;
- m_volume = 1.0f;
- m_deviceInfo = QAudioDeviceInfo();
- }
- void AudioPlayer::freeBuffers() {
- if (m_abufOut) {
- av_freep(&m_abufOut);
- m_abufOut = nullptr;
- m_abufOutSize = 0;
- }
- }
- bool AudioPlayer::ensureResampler(const AVFrame* frame) {
- if (!m_swrCtx) {
- m_swrCtx = swr_alloc();
- swr_alloc_set_opts2(&m_swrCtx,
- &frame->ch_layout, // out_ch_layout
- AV_SAMPLE_FMT_S16,
- frame->sample_rate,
- &frame->ch_layout, // in_ch_layout
- (AVSampleFormat)frame->format,
- frame->sample_rate,
- 0,
- nullptr);
- swr_init(m_swrCtx);
- }
- return m_swrCtx != nullptr;
- }
- void AudioPlayer::releaseResampler() {
- if (m_swrCtx) {
- swr_free(&m_swrCtx);
- m_swrCtx = nullptr;
- }
- if (m_swrBuffer) {
- av_free(m_swrBuffer);
- m_swrBuffer = nullptr;
- m_swrBufferSize = 0;
- }
- }
- bool AudioPlayer::ensureSonic(int sampleRate, int channels) {
- if (!m_sonicCtx) {
- m_sonicCtx = sonicCreateStream(sampleRate, channels);
- }
- return m_sonicCtx != nullptr;
- }
- void AudioPlayer::releaseSonic() {
- if (m_sonicCtx) {
- sonicDestroyStream(m_sonicCtx);
- m_sonicCtx = nullptr;
- }
- }
- void AudioPlayer::releaseAudioOutput() {
- if (m_audioOutput) {
- m_audioOutput->stop();
- delete m_audioOutput;
- m_audioOutput = nullptr;
- }
- m_audioDevice = nullptr;
- }
- QIODevice* AudioPlayer::getOutputDevice() const {
- return m_audioDevice;
- }
- QAudioOutput* AudioPlayer::getAudioOutput() const {
- return m_audioOutput;
- }
- float AudioPlayer::getSpeed() const {
- return m_speed;
- }
- float AudioPlayer::getVolume() const {
- return m_volume;
- }
|