audio_output.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. #include "audio_output.h"
  2. #include <QAudioDeviceInfo>
  3. #include <QDebug>
  4. #include "../base/logger.h"
  5. #include "../utils/utils_synchronizer_v2.h"
  6. #include "AV/code/base/media_common.h"
  7. #include <algorithm>
  8. #include <chrono>
  9. #include <cstring>
  10. #include <thread>
  11. extern "C" {
  12. #include <libavutil/channel_layout.h>
  13. #include <libavutil/avutil.h>
  14. #include <libavutil/time.h>
  15. #include <libavutil/opt.h>
  16. #include <libswresample/swresample.h>
  17. }
  18. namespace av {
  19. namespace player {
  20. AudioOutput::AudioOutput(QObject* parent)
  21. : QObject(parent)
  22. , m_audioOutput(nullptr)
  23. , m_audioDevice(nullptr)
  24. , m_sampleRate(44100)
  25. , m_channels(2)
  26. , m_inputFormat(AV_SAMPLE_FMT_S16)
  27. , m_swrContext(nullptr)
  28. , m_needResampling(false)
  29. , m_volume(1.0)
  30. , m_playbackSpeed(1.0)
  31. , m_lastAudioPts(0.0)
  32. , m_initialized(false)
  33. , m_playing(false)
  34. {
  35. }
  36. AudioOutput::~AudioOutput()
  37. {
  38. stop();
  39. cleanupResampler();
  40. if (m_audioOutput) {
  41. delete m_audioOutput;
  42. m_audioOutput = nullptr;
  43. }
  44. }
  45. bool AudioOutput::initialize(int sampleRate, int channels, AVSampleFormat sampleFormat)
  46. {
  47. QMutexLocker locker(&m_mutex);
  48. if (m_initialized) {
  49. av::Logger::instance().warning("Audio output already initialized");
  50. return true;
  51. }
  52. m_sampleRate = sampleRate;
  53. m_channels = channels;
  54. m_inputFormat = sampleFormat;
  55. // 设置Qt音频格式
  56. m_audioFormat.setSampleRate(sampleRate);
  57. m_audioFormat.setChannelCount(channels);
  58. m_audioFormat.setSampleSize(16); // 输出16位
  59. m_audioFormat.setCodec("audio/pcm");
  60. m_audioFormat.setByteOrder(QAudioFormat::LittleEndian);
  61. m_audioFormat.setSampleType(QAudioFormat::SignedInt);
  62. // 检查设备是否支持该格式
  63. QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultOutputDevice();
  64. if (!deviceInfo.isFormatSupported(m_audioFormat)) {
  65. av::Logger::instance().warning("Audio format not supported, using nearest format");
  66. m_audioFormat = deviceInfo.nearestFormat(m_audioFormat);
  67. // 验证获取的格式是否有效
  68. if (m_audioFormat.sampleRate() <= 0 || m_audioFormat.channelCount() <= 0) {
  69. av::Logger::instance().warning("Device returned invalid audio format, using fallback");
  70. av::Logger::instance().warningf("Invalid format: {}Hz, {}ch",
  71. m_audioFormat.sampleRate(),
  72. m_audioFormat.channelCount());
  73. // 使用默认格式作为后备
  74. m_audioFormat.setSampleRate(44100);
  75. m_audioFormat.setChannelCount(2);
  76. m_audioFormat.setSampleSize(16);
  77. m_audioFormat.setCodec("audio/pcm");
  78. m_audioFormat.setByteOrder(QAudioFormat::LittleEndian);
  79. m_audioFormat.setSampleType(QAudioFormat::SignedInt);
  80. av::Logger::instance().info("Using fallback audio format: 44100Hz, 2ch, 16bit");
  81. }
  82. // 记录实际使用的格式
  83. av::Logger::instance().info("Using audio format: " +
  84. std::to_string(m_audioFormat.sampleRate()) + "Hz, " +
  85. std::to_string(m_audioFormat.channelCount()) + "ch, " +
  86. std::to_string(m_audioFormat.sampleSize()) + "bit");
  87. }
  88. // 创建音频输出设备
  89. m_audioOutput = new QAudioOutput(m_audioFormat, this);
  90. if (!m_audioOutput) {
  91. av::Logger::instance().error("Failed to create audio output device");
  92. return false;
  93. }
  94. // 设置缓冲区大小
  95. m_audioOutput->setBufferSize(32768); // 32KB缓冲区
  96. // 连接状态变化信号
  97. connect(m_audioOutput, &QAudioOutput::stateChanged,
  98. this, &AudioOutput::onStateChanged);
  99. // 记录音频格式信息
  100. av::Logger::instance().info("Audio format: " +
  101. std::to_string(m_audioFormat.sampleRate()) + "Hz, " +
  102. std::to_string(m_audioFormat.channelCount()) + "ch, " +
  103. std::to_string(m_audioFormat.sampleSize()) + "bit, " +
  104. m_audioFormat.codec().toStdString());
  105. // 初始化重采样器(如果需要)
  106. if (!initResampler()) {
  107. av::Logger::instance().error("Failed to initialize audio resampler");
  108. return false;
  109. }
  110. m_initialized = true;
  111. av::Logger::instance().info("Audio output initialized successfully");
  112. return true;
  113. }
  114. void AudioOutput::start()
  115. {
  116. QMutexLocker locker(&m_mutex);
  117. if (!m_initialized || !m_audioOutput) {
  118. av::Logger::instance().error("Audio output not initialized");
  119. return;
  120. }
  121. if (m_playing) {
  122. return;
  123. }
  124. av::Logger::instance().debug("Starting audio output device...");
  125. av::Logger::instance().debug("Audio output state before start: " + std::to_string(m_audioOutput->state()));
  126. // 检查音频格式
  127. QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultOutputDevice();
  128. av::Logger::instance().debug("Default audio device: " + deviceInfo.deviceName().toStdString());
  129. av::Logger::instance().debug("Audio format supported: " + std::to_string(deviceInfo.isFormatSupported(m_audioFormat)));
  130. // 确保音频输出设备处于正确状态
  131. if (m_audioOutput->state() == QAudio::StoppedState) {
  132. av::Logger::instance().debug("Resetting audio output device");
  133. m_audioOutput->reset();
  134. // 给设备一点时间重置
  135. std::this_thread::sleep_for(std::chrono::milliseconds(50));
  136. }
  137. // 如果设备不支持当前格式,尝试使用最接近的格式
  138. if (!deviceInfo.isFormatSupported(m_audioFormat)) {
  139. av::Logger::instance().warning("Audio format not supported, using nearest format");
  140. QAudioFormat nearestFormat = deviceInfo.nearestFormat(m_audioFormat);
  141. // m_audioOutput->setFormat(nearestFormat);
  142. av::Logger::instance().info("Using nearest format: " +
  143. std::to_string(nearestFormat.sampleRate()) + "Hz, " +
  144. std::to_string(nearestFormat.channelCount()) + "ch, " +
  145. std::to_string(nearestFormat.sampleSize()) + "bit");
  146. }
  147. // 尝试多次启动音频设备
  148. int retryCount = 0;
  149. const int maxRetries = 5; // 增加重试次数
  150. bool deviceStarted = false;
  151. while (retryCount < maxRetries && !deviceStarted) {
  152. if (retryCount > 0) {
  153. av::Logger::instance().info("Retrying audio device start (attempt " + std::to_string(retryCount + 1) + "/" + std::to_string(maxRetries) + ")");
  154. // 重新创建音频输出设备
  155. if (m_audioOutput) {
  156. m_audioOutput->stop();
  157. delete m_audioOutput;
  158. m_audioOutput = nullptr;
  159. }
  160. // 等待更长时间让系统释放音频资源
  161. std::this_thread::sleep_for(std::chrono::milliseconds(500));
  162. m_audioOutput = new QAudioOutput(m_audioFormat, this);
  163. if (!m_audioOutput) {
  164. av::Logger::instance().error("Failed to recreate audio output device");
  165. return;
  166. }
  167. m_audioOutput->setBufferSize(32768);
  168. connect(m_audioOutput, &QAudioOutput::stateChanged, this, &AudioOutput::onStateChanged);
  169. }
  170. // 检查音频设备可用性
  171. QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultOutputDevice();
  172. if (deviceInfo.isNull()) {
  173. av::Logger::instance().error("No audio output device available");
  174. return;
  175. }
  176. av::Logger::instance().debug("Starting audio device (attempt " + std::to_string(retryCount + 1) + ")");
  177. m_audioDevice = m_audioOutput->start();
  178. if (!m_audioDevice) {
  179. av::Logger::instance().warning("Failed to start audio output device (attempt " + std::to_string(retryCount + 1) + ")");
  180. retryCount++;
  181. continue;
  182. }
  183. av::Logger::instance().debug("Audio device started, waiting for active state...");
  184. // 写入一些静音数据来激活设备
  185. QByteArray silentData(2048, 0); // 增加静音数据大小
  186. qint64 written = m_audioDevice->write(silentData);
  187. av::Logger::instance().debug("Written silent data: " + std::to_string(written) + " bytes");
  188. // 等待音频设备进入活动状态
  189. int maxWaitMs = 2000; // 增加等待时间到2秒
  190. int waitMs = 0;
  191. while (m_audioOutput->state() != QAudio::ActiveState && waitMs < maxWaitMs) {
  192. std::this_thread::sleep_for(std::chrono::milliseconds(100));
  193. waitMs += 100;
  194. if (waitMs % 500 == 0) {
  195. av::Logger::instance().debug("Audio output state: " + std::to_string(m_audioOutput->state()) +
  196. " (waited " + std::to_string(waitMs) + "ms)");
  197. // 尝试再次写入数据激活设备
  198. if (m_audioDevice && m_audioOutput->state() == QAudio::IdleState) {
  199. QByteArray moreData(1024, 0);
  200. m_audioDevice->write(moreData);
  201. }
  202. }
  203. }
  204. if (m_audioOutput->state() == QAudio::ActiveState) {
  205. deviceStarted = true;
  206. av::Logger::instance().info("Audio device successfully entered active state");
  207. } else if (m_audioOutput->state() == QAudio::IdleState) {
  208. // IdleState也可以接受,表示设备已准备好但暂时没有数据
  209. deviceStarted = true;
  210. av::Logger::instance().info("Audio device in idle state, ready for playback");
  211. } else {
  212. av::Logger::instance().warning("Audio device failed to enter active/idle state: " + std::to_string(m_audioOutput->state()) + " (attempt " + std::to_string(retryCount + 1) + ")");
  213. m_audioDevice = nullptr;
  214. retryCount++;
  215. }
  216. }
  217. if (!deviceStarted) {
  218. av::Logger::instance().error("Failed to start audio device after " + std::to_string(maxRetries) + " attempts");
  219. m_initialized = false;
  220. return;
  221. }
  222. av::Logger::instance().debug("Audio device entered active state");
  223. m_playing = true;
  224. av::Logger::instance().info("Audio output started successfully");
  225. }
  226. void AudioOutput::stop()
  227. {
  228. QMutexLocker locker(&m_mutex);
  229. if (!m_playing || !m_audioOutput) {
  230. return;
  231. }
  232. m_audioOutput->stop();
  233. m_audioDevice = nullptr;
  234. m_playing = false;
  235. av::Logger::instance().info("Audio output stopped");
  236. }
  237. void AudioOutput::pause()
  238. {
  239. QMutexLocker locker(&m_mutex);
  240. if (!m_playing || !m_audioOutput) {
  241. return;
  242. }
  243. m_audioOutput->suspend();
  244. av::Logger::instance().info("Audio output paused");
  245. }
  246. void AudioOutput::resume()
  247. {
  248. QMutexLocker locker(&m_mutex);
  249. if (!m_playing || !m_audioOutput) {
  250. return;
  251. }
  252. m_audioOutput->resume();
  253. av::Logger::instance().info("Audio output resumed");
  254. }
  255. bool AudioOutput::writeFrame(const AVFramePtr& frame)
  256. {
  257. if (!frame || !m_playing || !m_audioDevice) {
  258. av::Logger::instance().debug("Audio write failed: frame=" + std::to_string(frame != nullptr) +
  259. ", playing=" + std::to_string(m_playing) + ", device=" + std::to_string(m_audioDevice != nullptr));
  260. return false;
  261. }
  262. // 检查是否是EOF帧,EOF帧不需要处理,直接返回成功
  263. if (!frame->data[0] && frame->nb_samples == 0) {
  264. av::Logger::instance().debug("Received EOF frame in audio output, ignoring");
  265. return true;
  266. }
  267. // 检查音频设备状态 - 允许ActiveState和IdleState
  268. if (m_audioOutput) {
  269. QAudio::State currentState = m_audioOutput->state();
  270. if (currentState != QAudio::ActiveState && currentState != QAudio::IdleState) {
  271. av::Logger::instance().warning("Audio device not in playable state: " + std::to_string(currentState));
  272. // 尝试重新启动设备
  273. if (currentState == QAudio::StoppedState) {
  274. av::Logger::instance().info("Attempting to restart stopped audio device");
  275. m_audioDevice = m_audioOutput->start();
  276. if (!m_audioDevice) {
  277. av::Logger::instance().error("Failed to restart audio device");
  278. return false;
  279. }
  280. // 写入静音数据激活设备
  281. QByteArray silentData(1024, 0);
  282. m_audioDevice->write(silentData);
  283. // 短暂等待设备状态更新
  284. std::this_thread::sleep_for(std::chrono::milliseconds(50));
  285. currentState = m_audioOutput->state();
  286. if (currentState != QAudio::ActiveState && currentState != QAudio::IdleState) {
  287. av::Logger::instance().error("Audio device restart failed, state: " + std::to_string(currentState));
  288. return false;
  289. }
  290. } else {
  291. return false;
  292. }
  293. }
  294. }
  295. // 使用Synchronizer进行时间同步
  296. if (frame->pts != AV_NOPTS_VALUE /*&& m_synchronizer*/) {
  297. // 使用原始PTS值和时间基准
  298. int64_t audioPts = frame->pts;
  299. double timeBase = 1.0 / AV_TIME_BASE; // 假设使用AV_TIME_BASE作为时间基准
  300. m_lastAudioPts = audioPts * timeBase; // 转换为秒用于记录
  301. }
  302. // 转换音频帧格式
  303. QByteArray audioData = convertFrame(frame);
  304. if (audioData.isEmpty()) {
  305. av::Logger::instance().warning("Audio frame conversion failed");
  306. return false;
  307. }
  308. // 应用音量控制
  309. applyVolume(audioData);
  310. // 写入音频设备 - 添加重试机制和异常处理
  311. const int maxRetries = 10;
  312. const int retryDelayMs = 5;
  313. for (int retry = 0; retry < maxRetries; ++retry) {
  314. try {
  315. qint64 bytesWritten = m_audioDevice->write(audioData);
  316. if (bytesWritten == audioData.size()) {
  317. av::Logger::instance().debug("Audio frame written successfully: " +
  318. std::to_string(audioData.size()) + " bytes");
  319. return true;
  320. }
  321. // 写入不完整,记录警告并重试
  322. av::Logger::instance().warning("Audio write incomplete (attempt " +
  323. std::to_string(retry + 1) + "/" + std::to_string(maxRetries) + "): " +
  324. std::to_string(bytesWritten) + "/" + std::to_string(audioData.size()));
  325. // 如果不是最后一次重试,等待一段时间再重试
  326. if (retry < maxRetries - 1) {
  327. std::this_thread::sleep_for(std::chrono::milliseconds(retryDelayMs));
  328. }
  329. } catch (const std::exception& e) {
  330. av::Logger::instance().error("Exception during audio write (attempt " +
  331. std::to_string(retry + 1) + "): " + std::string(e.what()));
  332. if (retry < maxRetries - 1) {
  333. std::this_thread::sleep_for(std::chrono::milliseconds(retryDelayMs));
  334. }
  335. } catch (...) {
  336. av::Logger::instance().error("Unknown exception during audio write (attempt " +
  337. std::to_string(retry + 1) + ")");
  338. if (retry < maxRetries - 1) {
  339. std::this_thread::sleep_for(std::chrono::milliseconds(retryDelayMs));
  340. }
  341. }
  342. }
  343. av::Logger::instance().error("Audio write failed after " + std::to_string(maxRetries) + " attempts");
  344. return false;
  345. }
  346. void AudioOutput::setVolume(double volume)
  347. {
  348. m_volume = std::clamp(volume, 0.0, 1.0);
  349. if (m_audioOutput) {
  350. m_audioOutput->setVolume(m_volume);
  351. }
  352. }
  353. double AudioOutput::getVolume() const
  354. {
  355. return m_volume;
  356. }
  357. void AudioOutput::setPlaybackSpeed(double speed)
  358. {
  359. speed = std::max(0.1, std::min(4.0, speed));
  360. m_playbackSpeed = speed;
  361. av::Logger::instance().debug("Audio playback speed set to: " + std::to_string(speed));
  362. }
  363. double AudioOutput::getPlaybackSpeed() const
  364. {
  365. return m_playbackSpeed;
  366. }
  367. void AudioOutput::flush()
  368. {
  369. QMutexLocker locker(&m_mutex);
  370. if (m_audioOutput) {
  371. m_audioOutput->reset();
  372. }
  373. }
  374. int AudioOutput::getBufferSize() const
  375. {
  376. if (m_audioOutput) {
  377. return m_audioOutput->bufferSize() * 1000 /
  378. (m_audioFormat.sampleRate() * m_audioFormat.channelCount() *
  379. m_audioFormat.sampleSize() / 8);
  380. }
  381. return 0;
  382. }
  383. bool AudioOutput::isPlaying() const
  384. {
  385. return m_playing;
  386. }
  387. void AudioOutput::onStateChanged(QAudio::State state)
  388. {
  389. switch (state) {
  390. case QAudio::ActiveState:
  391. av::Logger::instance().debug("Audio output state: Active");
  392. break;
  393. case QAudio::SuspendedState:
  394. av::Logger::instance().debug("Audio output state: Suspended");
  395. break;
  396. case QAudio::StoppedState:
  397. av::Logger::instance().debug("Audio output state: Stopped");
  398. break;
  399. case QAudio::IdleState:
  400. av::Logger::instance().debug("Audio output state: Idle");
  401. break;
  402. }
  403. }
  404. bool AudioOutput::initResampler()
  405. {
  406. // 检查是否需要重采样
  407. bool needSampleRateConversion = (m_audioFormat.sampleRate() != m_sampleRate);
  408. bool needChannelConversion = (m_audioFormat.channelCount() != m_channels);
  409. bool needFormatConversion = (m_inputFormat != AV_SAMPLE_FMT_S16);
  410. m_needResampling = needSampleRateConversion || needChannelConversion || needFormatConversion;
  411. if (!m_needResampling) {
  412. av::Logger::instance().info("No audio resampling needed");
  413. return true;
  414. }
  415. // 参数验证
  416. if (m_sampleRate <= 0 || m_sampleRate > 192000) {
  417. av::Logger::instance().errorf("Invalid input sample rate: {}", m_sampleRate);
  418. return false;
  419. }
  420. if (m_audioFormat.sampleRate() <= 0 || m_audioFormat.sampleRate() > 192000) {
  421. av::Logger::instance().errorf("Invalid output sample rate: {}", m_audioFormat.sampleRate());
  422. return false;
  423. }
  424. if (m_channels <= 0 || m_channels > 32) {
  425. av::Logger::instance().errorf("Invalid input channels: {}", m_channels);
  426. return false;
  427. }
  428. if (m_audioFormat.channelCount() <= 0 || m_audioFormat.channelCount() > 32) {
  429. av::Logger::instance().errorf("Invalid output channels: {}", m_audioFormat.channelCount());
  430. return false;
  431. }
  432. // 记录参数信息用于调试
  433. av::Logger::instance().infof("Resampler config: {}Hz,{}ch,{} -> {}Hz,{}ch,S16",
  434. m_sampleRate, m_channels,
  435. av_get_sample_fmt_name(m_inputFormat),
  436. m_audioFormat.sampleRate(), m_audioFormat.channelCount());
  437. // 创建重采样上下文
  438. m_swrContext = swr_alloc();
  439. if (!m_swrContext) {
  440. av::Logger::instance().error("Failed to allocate resampler context");
  441. return false;
  442. }
  443. // 设置输入参数
  444. AVChannelLayout inputLayout;
  445. av_channel_layout_default(&inputLayout, m_channels);
  446. // 设置输出参数
  447. AVChannelLayout outputLayout;
  448. av_channel_layout_default(&outputLayout, m_audioFormat.channelCount());
  449. // 使用分步设置方式替代swr_alloc_set_opts2
  450. av_opt_set_chlayout(m_swrContext, "in_chlayout", &inputLayout, 0);
  451. av_opt_set_int(m_swrContext, "in_sample_rate", m_sampleRate, 0);
  452. av_opt_set_sample_fmt(m_swrContext, "in_sample_fmt", m_inputFormat, 0);
  453. av_opt_set_chlayout(m_swrContext, "out_chlayout", &outputLayout, 0);
  454. av_opt_set_int(m_swrContext, "out_sample_rate", m_audioFormat.sampleRate(), 0);
  455. av_opt_set_sample_fmt(m_swrContext, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
  456. // 初始化重采样器
  457. int ret = swr_init(m_swrContext);
  458. if (ret < 0) {
  459. av::Logger::instance().errorf("Failed to initialize resampler: {}",
  460. ffmpeg_utils::errorToString(ret));
  461. av::Logger::instance().errorf("Input: {}Hz, {}ch, {}",
  462. m_sampleRate, m_channels,
  463. av_get_sample_fmt_name(m_inputFormat));
  464. av::Logger::instance().errorf("Output: {}Hz, {}ch, S16",
  465. m_audioFormat.sampleRate(),
  466. m_audioFormat.channelCount());
  467. swr_free(&m_swrContext);
  468. return false;
  469. }
  470. av::Logger::instance().info("Audio resampler initialized successfully");
  471. return true;
  472. }
  473. void AudioOutput::cleanupResampler()
  474. {
  475. if (m_swrContext) {
  476. swr_free(&m_swrContext);
  477. m_swrContext = nullptr;
  478. }
  479. }
  480. QByteArray AudioOutput::convertFrame(const AVFramePtr& frame)
  481. {
  482. if (!frame) {
  483. av::Logger::instance().error("convertFrame: null frame pointer");
  484. return QByteArray();
  485. }
  486. // 检查帧数据有效性
  487. if (!frame->data[0] || frame->nb_samples <= 0) {
  488. av::Logger::instance().error("convertFrame: invalid frame data, nb_samples=" + std::to_string(frame->nb_samples));
  489. return QByteArray();
  490. }
  491. av::Logger::instance().debug("convertFrame: input samples=" + std::to_string(frame->nb_samples) +
  492. ", channels=" + std::to_string(m_channels) +
  493. ", format=" + std::to_string(m_inputFormat) +
  494. ", need_resampling=" + std::to_string(m_needResampling));
  495. if (!m_needResampling) {
  496. // 直接复制数据
  497. int dataSize = frame->nb_samples * m_channels * sizeof(int16_t);
  498. av::Logger::instance().debug("convertFrame: direct copy, size=" + std::to_string(dataSize));
  499. return QByteArray(reinterpret_cast<const char*>(frame->data[0]), dataSize);
  500. }
  501. if (!m_swrContext) {
  502. av::Logger::instance().error("convertFrame: resampler not initialized");
  503. return QByteArray();
  504. }
  505. // 计算输出采样数
  506. int outputSamples = swr_get_out_samples(m_swrContext, frame->nb_samples);
  507. if (outputSamples <= 0) {
  508. av::Logger::instance().error("convertFrame: invalid output samples=" + std::to_string(outputSamples));
  509. return QByteArray();
  510. }
  511. // 分配输出缓冲区
  512. int outputChannels = m_audioFormat.channelCount();
  513. int outputDataSize = outputSamples * outputChannels * sizeof(int16_t);
  514. QByteArray outputData(outputDataSize, 0);
  515. uint8_t* outputBuffer = reinterpret_cast<uint8_t*>(outputData.data());
  516. av::Logger::instance().debug("convertFrame: resampling " + std::to_string(frame->nb_samples) +
  517. " -> " + std::to_string(outputSamples) + " samples");
  518. // 执行重采样
  519. int convertedSamples = swr_convert(m_swrContext,
  520. &outputBuffer, outputSamples,
  521. const_cast<const uint8_t**>(frame->data), frame->nb_samples);
  522. if (convertedSamples < 0) {
  523. char errorBuf[256];
  524. av_strerror(convertedSamples, errorBuf, sizeof(errorBuf));
  525. av::Logger::instance().error("convertFrame: resampling failed with error " +
  526. std::to_string(convertedSamples) + ": " + std::string(errorBuf));
  527. return QByteArray();
  528. }
  529. // 调整输出数据大小
  530. int actualDataSize = convertedSamples * outputChannels * sizeof(int16_t);
  531. outputData.resize(actualDataSize);
  532. av::Logger::instance().debug("convertFrame: successfully converted " + std::to_string(convertedSamples) +
  533. " samples, output size=" + std::to_string(actualDataSize));
  534. return outputData;
  535. }
  536. void AudioOutput::applyVolume(QByteArray& data)
  537. {
  538. if (std::abs(m_volume - 1.0) < 0.001) {
  539. return; // 音量为1.0,无需调整
  540. }
  541. int16_t* samples = reinterpret_cast<int16_t*>(data.data());
  542. int sampleCount = data.size() / sizeof(int16_t);
  543. for (int i = 0; i < sampleCount; ++i) {
  544. samples[i] = static_cast<int16_t>(samples[i] * m_volume);
  545. }
  546. }
  547. } // namespace player
  548. } // namespace av