AudioPlayer.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #include "AudioPlayer.h"
  2. #include <cstring>
  3. #include <cmath>
  4. extern "C" {
  5. #include <libavutil/avutil.h>
  6. #include <libavutil/samplefmt.h>
  7. #include <libavutil/channel_layout.h>
  8. #include <libavutil/frame.h>
  9. #include <libavutil/mem.h>
  10. #include <libswresample/swresample.h>
  11. }
  12. #include "sonic/sonic.h"
  13. #include <QAudioDeviceInfo>
  14. #include <QAudioFormat>
  15. #include <QDebug>
  16. AudioPlayer::AudioPlayer() {}
  17. AudioPlayer::~AudioPlayer() { reset(); }
  18. void AudioPlayer::reset() {
  19. if (m_sonicCtx) {
  20. sonicDestroyStream(m_sonicCtx);
  21. m_sonicCtx = nullptr;
  22. }
  23. if (m_swrCtx) {
  24. swr_free(&m_swrCtx);
  25. m_swrCtx = nullptr;
  26. }
  27. if (m_swrBuffer) {
  28. av_free(m_swrBuffer);
  29. m_swrBuffer = nullptr;
  30. m_swrBufferSize = 0;
  31. }
  32. freeBuffers();
  33. if (m_audioOutput) {
  34. m_audioOutput->stop();
  35. delete m_audioOutput;
  36. m_audioOutput = nullptr;
  37. }
  38. m_audioDevice = nullptr;
  39. m_sampleRate = 0;
  40. m_channels = 0;
  41. m_format = AV_SAMPLE_FMT_NONE;
  42. m_lastSpeed = 1.0f;
  43. }
  44. void AudioPlayer::freeBuffers() {
  45. if (m_abuf) {
  46. av_freep(&m_abuf);
  47. m_abuf = nullptr;
  48. }
  49. if (m_abufOut) {
  50. av_freep(&m_abufOut);
  51. m_abufOut = nullptr;
  52. m_abufOutSize = 0;
  53. }
  54. m_maxBufSize = -1;
  55. }
  56. void AudioPlayer::init(const AVFrame* frame, float speed) {
  57. reset();
  58. initAudioOutput(frame, speed);
  59. }
  60. void AudioPlayer::initAudioOutput(const AVFrame* frame, float speed) {
  61. m_sampleRate = frame->sample_rate;
  62. m_channels = frame->ch_layout.nb_channels;
  63. m_format = (AVSampleFormat)frame->format;
  64. m_lastSpeed = speed;
  65. if (m_sonicCtx) {
  66. sonicDestroyStream(m_sonicCtx);
  67. m_sonicCtx = nullptr;
  68. }
  69. m_sonicCtx = sonicCreateStream(m_sampleRate, m_channels);
  70. setSpeed(speed);
  71. QAudioFormat fmt;
  72. fmt.setSampleRate(m_sampleRate);
  73. fmt.setChannelCount(m_channels);
  74. fmt.setSampleSize(16); // 目标格式 S16
  75. fmt.setCodec("audio/pcm");
  76. fmt.setByteOrder(QAudioFormat::LittleEndian);
  77. fmt.setSampleType(QAudioFormat::SignedInt);
  78. QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
  79. if (!info.isFormatSupported(fmt)) {
  80. qWarning() << "音频格式不支持,尝试最近格式";
  81. fmt = info.nearestFormat(fmt);
  82. }
  83. m_audioOutput = new QAudioOutput(fmt, nullptr);
  84. m_audioDevice = m_audioOutput->start();
  85. }
  86. void AudioPlayer::setSpeed(float speed) {
  87. if (m_sonicCtx) {
  88. sonicSetSpeed(m_sonicCtx, speed);
  89. sonicSetPitch(m_sonicCtx, 1.0f);
  90. sonicSetRate(m_sonicCtx, 1.0f);
  91. }
  92. m_lastSpeed = speed;
  93. }
  94. void AudioPlayer::setOutputDevice(QIODevice* device) {
  95. m_audioDevice = device;
  96. }
  97. void AudioPlayer::setAudioOutput(QAudioOutput* output) {
  98. m_audioOutput = output;
  99. }
  100. QIODevice* AudioPlayer::getOutputDevice() const {
  101. return m_audioDevice;
  102. }
  103. QAudioOutput* AudioPlayer::getAudioOutput() const {
  104. return m_audioOutput;
  105. }
  106. bool AudioPlayer::needReinit(const AVFrame* frame, float speed) const {
  107. if (!m_audioOutput) return true;
  108. if (m_sampleRate != frame->sample_rate) return true;
  109. if (m_channels != frame->ch_layout.nb_channels) return true;
  110. if (m_format != (AVSampleFormat)frame->format) return true;
  111. if (std::abs(m_lastSpeed - speed) > 1e-3) return true;
  112. return false;
  113. }
  114. void AudioPlayer::play(AVFrame* frame, float speed) {
  115. if (!m_audioDevice) return;
  116. m_sampleRate = frame->sample_rate;
  117. m_channels = frame->ch_layout.nb_channels;
  118. m_format = (AVSampleFormat)frame->format;
  119. // 1. 重采样到 S16
  120. const AVSampleFormat targetFmt = AV_SAMPLE_FMT_S16;
  121. uint8_t* inputData = nullptr;
  122. int inputSamples = frame->nb_samples;
  123. int inputBytes = av_samples_get_buffer_size(nullptr, m_channels, inputSamples, targetFmt, 1);
  124. if (m_format != targetFmt) {
  125. if (!m_swrCtx) {
  126. m_swrCtx = swr_alloc();
  127. swr_alloc_set_opts2(&m_swrCtx,
  128. &frame->ch_layout, // out_ch_layout
  129. targetFmt,
  130. m_sampleRate,
  131. &frame->ch_layout, // in_ch_layout
  132. m_format,
  133. m_sampleRate,
  134. 0,
  135. nullptr);
  136. swr_init(m_swrCtx);
  137. }
  138. if (!m_swrBuffer || m_swrBufferSize < inputBytes) {
  139. if (m_swrBuffer) av_free(m_swrBuffer);
  140. m_swrBuffer = (uint8_t*)av_malloc(inputBytes);
  141. m_swrBufferSize = inputBytes;
  142. }
  143. int outSamples = swr_convert(
  144. m_swrCtx,
  145. &m_swrBuffer, inputSamples,
  146. (const uint8_t**)frame->extended_data, inputSamples
  147. );
  148. inputData = m_swrBuffer;
  149. inputSamples = outSamples;
  150. inputBytes = av_samples_get_buffer_size(nullptr, m_channels, outSamples, targetFmt, 1);
  151. } else {
  152. inputData = frame->data[0];
  153. inputBytes = av_samples_get_buffer_size(nullptr, m_channels, inputSamples, targetFmt, 1);
  154. }
  155. // 2. 送 sonic 变速
  156. if (!m_sonicCtx) {
  157. m_sonicCtx = sonicCreateStream(m_sampleRate, m_channels);
  158. }
  159. setSpeed(speed);
  160. int out_ret = sonicWriteShortToStream(m_sonicCtx, (int16_t*)inputData, inputBytes / (m_channels * 2));
  161. int num_samples = sonicSamplesAvailable(m_sonicCtx);
  162. int out_size = num_samples * 2 * m_channels;
  163. av_fast_malloc(&m_abufOut, &m_abufOutSize, out_size);
  164. int sonic_samples = 0;
  165. if (out_ret) {
  166. sonic_samples = sonicReadShortFromStream(m_sonicCtx, (int16_t*)m_abufOut, num_samples);
  167. out_size = sonic_samples * 2 * m_channels;
  168. }
  169. // 3. 输出到Qt
  170. int bytesWrite = 0;
  171. while (bytesWrite < out_size) {
  172. int written = m_audioDevice->write((const char*)m_abufOut + bytesWrite, out_size - bytesWrite);
  173. if (written <= 0) break;
  174. bytesWrite += written;
  175. }
  176. }