playercontroller.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. #include "playercontroller.h"
  2. #include "common.h"
  3. #include <QApplication>
  4. #include <QElapsedTimer>
  5. #include <QStatusBar>
  6. #include <cassert>
  7. #include <memory>
  8. #include "ffmpeg_init.h"
  9. #include "start_play_thread.h"
  10. #include "video_state.h"
  11. #include "audio_decode_thread.h"
  12. #include "audio_effect_helper.h"
  13. #include "audio_play_thread.h"
  14. #include "play_control_window.h"
  15. #include "read_thread.h"
  16. #include "start_play_thread.h"
  17. #include "stopplay_waiting_thread.h"
  18. #include "subtitle_decode_thread.h"
  19. #include "video_decode_thread.h"
  20. #include "video_play_thread.h"
  21. #include "video_state.h"
  22. PlayerController::PlayerController(QWidget* parent)
  23. : QObject(parent)
  24. {
  25. ffmpeg_init();
  26. connect(this,
  27. &PlayerController::asyncInitFinished,
  28. this,
  29. &PlayerController::onAsyncInitFinished);
  30. m_state = PlayerState::Idle;
  31. }
  32. PlayerController::~PlayerController()
  33. {
  34. if (m_initThread.joinable()) {
  35. m_initThread.join();
  36. }
  37. stopPlay();
  38. }
  39. void PlayerController::startToPlay(const QString& file)
  40. {
  41. std::lock_guard<std::mutex> lock(m_stopMutex);
  42. // 自愈:如果状态为Playing但所有线程都已退出,强制Idle
  43. if (m_state == PlayerState::Playing) {
  44. if (!m_packetReadThread && !m_decodeVideoThread && !m_decodeAudioThread &&
  45. !m_audioPlayThread && !m_videoPlayThread && !m_decodeSubtitleThread) {
  46. m_videoState.reset();
  47. m_currentFile.clear();
  48. m_state = PlayerState::Idle;
  49. qDebug() << "[PlayerController] All threads stopped, force reset to Idle.";
  50. }
  51. }
  52. if (m_state == PlayerState::Initializing) {
  53. qDebug() << "Player is initializing. Ignoring request.";
  54. return;
  55. }
  56. if (m_state == PlayerState::Playing) {
  57. if (m_currentFile == file) {
  58. qDebug() << "Already playing the same file. Ignoring request.";
  59. return;
  60. } else {
  61. qDebug() << "Player is busy with another file, stopping and switching to:" << file;
  62. stopPlay();
  63. // 这里直接 fallthrough 到 Idle 状态
  64. }
  65. }
  66. if (m_state == PlayerState::Idle) {
  67. qDebug() << "Player is idle. Starting playback for:" << file;
  68. m_state = PlayerState::Initializing;
  69. m_currentFile = file;
  70. if (m_initThread.joinable()) {
  71. m_initThread.join();
  72. }
  73. m_initThread = std::thread(&PlayerController::asyncInit, this, file);
  74. }
  75. }
  76. void PlayerController::asyncInit(const QString& file)
  77. {
  78. bool success = false;
  79. QElapsedTimer timer;
  80. timer.start();
  81. qDebug("[Init] asyncInit started");
  82. if (file.isEmpty()) {
  83. qWarning("Filename is invalid. Please select a valid media file.");
  84. success = false;
  85. } else {
  86. qInfo("Check file: %s", qUtf8Printable(toNativePath(file)));
  87. success = true;
  88. }
  89. m_initSuccess = success;
  90. emit asyncInitFinished(file, success);
  91. qDebug("[Init] asyncInit finished in %lld ms", timer.elapsed());
  92. }
  93. void PlayerController::onAsyncInitFinished(const QString& file, bool success)
  94. {
  95. std::lock_guard<std::mutex> lock(m_stopMutex);
  96. if (!success) {
  97. playFailed(m_currentFile);
  98. m_state = PlayerState::Idle;
  99. return;
  100. }
  101. qDebug("[Init] createReadThread...");
  102. if (!createReadThread()) {
  103. qWarning("Packet read thread creation failed");
  104. playFailed(m_currentFile);
  105. m_state = PlayerState::Idle;
  106. return;
  107. }
  108. qDebug("[Init] createVideoState...");
  109. if (!createVideoState(m_currentFile)) {
  110. qWarning("Video state creation failed");
  111. readPacketStopped();
  112. playFailed(m_currentFile);
  113. m_state = PlayerState::Idle;
  114. return;
  115. }
  116. assert(m_videoState);
  117. if (!m_videoState) {
  118. qWarning("Video state initialization error");
  119. playFailed(m_currentFile);
  120. m_state = PlayerState::Idle;
  121. return;
  122. }
  123. m_packetReadThread->set_video_state(m_videoState->get_state());
  124. const bool hasVideo = playingHasVideo();
  125. const bool hasAudio = playingHasAudio();
  126. const bool hasSubtitle = playingHasSubtitle();
  127. if (hasVideo) {
  128. if (!createDecodeVideoThread() || !createVideoPlayThread()) {
  129. qWarning("Video processing setup failed");
  130. playFailed(m_currentFile);
  131. stopPlay();
  132. m_state = PlayerState::Idle;
  133. return;
  134. }
  135. }
  136. if (hasAudio) {
  137. if (!createDecodeAudioThread() || !createAudioPlayThread()) {
  138. qWarning("Audio processing setup failed");
  139. playFailed(m_currentFile);
  140. stopPlay();
  141. m_state = PlayerState::Idle;
  142. return;
  143. }
  144. }
  145. if (hasSubtitle && !createDecodeSubtitleThread()) {
  146. qWarning("Subtitle processing setup failed");
  147. playFailed(m_currentFile);
  148. stopPlay();
  149. m_state = PlayerState::Idle;
  150. return;
  151. }
  152. if (hasAudio) {
  153. startPlayThread();
  154. } else {
  155. playStarted();
  156. }
  157. emit startToPlaySignal();
  158. m_state = PlayerState::Playing;
  159. }
  160. void PlayerController::stopPlay()
  161. {
  162. std::lock_guard<std::mutex> lock(m_stopMutex);
  163. if (m_state == PlayerState::Idle)
  164. return;
  165. m_state = PlayerState::Stopping;
  166. auto stopAndReset = [](auto& threadPtr) {
  167. if (threadPtr) {
  168. threadPtr->stop_thread();
  169. threadPtr->wait(3000); // 最多等3秒
  170. threadPtr.reset();
  171. }
  172. };
  173. stopAndReset(m_stopPlayWaitingThread);
  174. stopAndReset(m_beforePlayThread);
  175. stopAndReset(m_packetReadThread);
  176. stopAndReset(m_decodeVideoThread);
  177. stopAndReset(m_decodeAudioThread);
  178. stopAndReset(m_decodeSubtitleThread);
  179. stopAndReset(m_videoPlayThread);
  180. stopAndReset(m_audioPlayThread);
  181. m_videoState.reset();
  182. m_currentFile.clear();
  183. m_state = PlayerState::Idle;
  184. }
  185. void PlayerController::pausePlay()
  186. {
  187. if (!m_videoState)
  188. return;
  189. if (auto state = m_videoState->get_state())
  190. toggle_pause(state, !state->paused);
  191. emit updatePlayControlStatus();
  192. }
  193. void PlayerController::playMute(bool mute)
  194. {
  195. if (!m_videoState)
  196. return;
  197. if (auto state = m_videoState->get_state())
  198. toggle_mute(state, mute);
  199. }
  200. void PlayerController::playStartSeek()
  201. {
  202. emit playSeek();
  203. pausePlay();
  204. }
  205. void PlayerController::playSeekPre()
  206. {
  207. videoSeekInc(-2);
  208. }
  209. void PlayerController::playSeekNext()
  210. {
  211. videoSeekInc(2);
  212. }
  213. void PlayerController::setVolume(int volume, int maxValue)
  214. {
  215. if (!m_audioPlayThread)
  216. return;
  217. const float vol = static_cast<float>(volume) / maxValue;
  218. m_audioPlayThread->set_device_volume(vol);
  219. }
  220. void PlayerController::setPlaySpeed(double speed)
  221. {
  222. if (m_videoState) {
  223. if (auto state = m_videoState->get_state()) {
  224. #if USE_AVFILTER_AUDIO
  225. set_audio_playspeed(state, speed);
  226. #endif
  227. }
  228. }
  229. }
  230. // 状态访问接口
  231. QString PlayerController::playingFile() const
  232. {
  233. return isPlaying() ? m_currentFile : QString();
  234. }
  235. bool PlayerController::isPlaying() const
  236. {
  237. return m_state == PlayerState::Playing;
  238. }
  239. bool PlayerController::playingHasVideo()
  240. {
  241. return m_videoState ? m_videoState->has_video() : false;
  242. }
  243. bool PlayerController::playingHasAudio()
  244. {
  245. return m_videoState ? m_videoState->has_audio() : false;
  246. }
  247. bool PlayerController::playingHasSubtitle()
  248. {
  249. return m_videoState ? m_videoState->has_subtitle() : false;
  250. }
  251. VideoState* PlayerController::state()
  252. {
  253. return m_videoState ? m_videoState->get_state() : nullptr;
  254. }
  255. float PlayerController::deviceVolume() const
  256. {
  257. return m_audioPlayThread ? m_audioPlayThread->get_device_volume() : 0.0f;
  258. }
  259. void PlayerController::setDeviceVolume(float volume)
  260. {
  261. if (m_audioPlayThread)
  262. m_audioPlayThread->set_device_volume(volume);
  263. }
  264. // 播放状态回调槽函数
  265. void PlayerController::playStarted(bool success)
  266. {
  267. if (!success) {
  268. qWarning("Audio device initialization failed!");
  269. return;
  270. }
  271. allThreadStart();
  272. setThreads();
  273. }
  274. void PlayerController::playFailed(const QString& file)
  275. {
  276. emit showMessage(QString("Playback failed: %1").arg(toNativePath(file)), "Warning", "");
  277. }
  278. // 线程 finished 槽函数只做日志和信号
  279. void PlayerController::readPacketStopped()
  280. {
  281. qDebug("************* Read packets thread stopped signal received.");
  282. m_packetReadThread.reset();
  283. checkAndResetState();
  284. emit audioStopped();
  285. }
  286. void PlayerController::decodeVideoStopped()
  287. {
  288. qDebug("************* Video decode thread stopped.");
  289. m_decodeVideoThread.reset();
  290. checkAndResetState();
  291. }
  292. void PlayerController::decodeAudioStopped()
  293. {
  294. qDebug("************* Audio decode thread stopped.");
  295. m_decodeAudioThread.reset();
  296. checkAndResetState();
  297. }
  298. void PlayerController::decodeSubtitleStopped()
  299. {
  300. qDebug("************* Subtitle decode thread stopped.");
  301. m_decodeSubtitleThread.reset();
  302. checkAndResetState();
  303. }
  304. void PlayerController::audioPlayStopped()
  305. {
  306. qDebug("************* Audio play thread stopped.");
  307. emit audioStopped();
  308. m_audioPlayThread.reset();
  309. checkAndResetState();
  310. }
  311. void PlayerController::videoPlayStopped()
  312. {
  313. qDebug("************* Video play thread stopped.");
  314. emit videoStopped();
  315. m_videoPlayThread.reset();
  316. checkAndResetState();
  317. }
  318. // 线程管理槽函数
  319. void PlayerController::setThreads()
  320. {
  321. if (!m_videoState)
  322. return;
  323. Threads threads;
  324. threads.read_tid = m_packetReadThread.get();
  325. threads.video_decode_tid = m_decodeVideoThread.get();
  326. threads.audio_decode_tid = m_decodeAudioThread.get();
  327. threads.video_play_tid = m_videoPlayThread.get();
  328. threads.audio_play_tid = m_audioPlayThread.get();
  329. threads.subtitle_decode_tid = m_decodeSubtitleThread.get();
  330. m_videoState->threads_setting(m_videoState->get_state(), threads);
  331. }
  332. void PlayerController::startSendData(bool send)
  333. {
  334. if (m_audioPlayThread)
  335. m_audioPlayThread->send_visual_open(send);
  336. }
  337. void PlayerController::videoSeek(double position, double increment)
  338. {
  339. if (!m_videoState)
  340. return;
  341. auto state = m_videoState->get_state();
  342. if (!state)
  343. return;
  344. if (state->ic->start_time != AV_NOPTS_VALUE
  345. && position < state->ic->start_time / static_cast<double>(AV_TIME_BASE)) {
  346. position = state->ic->start_time / static_cast<double>(AV_TIME_BASE);
  347. }
  348. stream_seek(state,
  349. static_cast<int64_t>(position * AV_TIME_BASE),
  350. static_cast<int64_t>(increment * AV_TIME_BASE),
  351. 0);
  352. }
  353. // 核心私有实现
  354. bool PlayerController::startPlay()
  355. {
  356. QElapsedTimer timer;
  357. timer.start();
  358. if (m_currentFile.isEmpty()) {
  359. qWarning("Filename is invalid. Please select a valid media file.");
  360. return false;
  361. }
  362. qInfo("Starting playback: %s", qUtf8Printable(toNativePath(m_currentFile)));
  363. // 创建数据包读取线程
  364. if (!createReadThread()) {
  365. qWarning("Packet read thread creation failed");
  366. return false;
  367. }
  368. // 创建视频状态对象
  369. if (!createVideoState(m_currentFile)) {
  370. qWarning("Video state creation failed");
  371. readPacketStopped();
  372. return false;
  373. }
  374. // 检查状态有效性
  375. assert(m_videoState);
  376. if (!m_videoState) {
  377. qWarning("Video state initialization error");
  378. return false;
  379. }
  380. m_packetReadThread->set_video_state(m_videoState->get_state());
  381. const bool hasVideo = playingHasVideo();
  382. const bool hasAudio = playingHasAudio();
  383. const bool hasSubtitle = playingHasSubtitle();
  384. // 创建视频相关线程
  385. if (hasVideo) {
  386. if (!createDecodeVideoThread() || !createVideoPlayThread()) {
  387. qWarning("Video processing setup failed");
  388. return false;
  389. }
  390. }
  391. // 创建音频相关线程
  392. if (hasAudio) {
  393. if (!createDecodeAudioThread() || !createAudioPlayThread()) {
  394. qWarning("Audio processing setup failed");
  395. return false;
  396. }
  397. }
  398. // 创建字幕线程
  399. if (hasSubtitle && !createDecodeSubtitleThread()) {
  400. qWarning("Subtitle processing setup failed");
  401. return false;
  402. }
  403. // 开始播放
  404. if (hasAudio) {
  405. startPlayThread(); // 异步启动(处理音频设备初始化)
  406. } else {
  407. playStarted(); // 同步启动(无音频流)
  408. }
  409. qDebug("Playback initialized in %lld ms", timer.elapsed());
  410. return true;
  411. }
  412. void PlayerController::waitStopPlay(const QString& file)
  413. {
  414. m_stopPlayWaitingThread = std::make_unique<StopWaitingThread>(this, file);
  415. connect(m_stopPlayWaitingThread.get(),
  416. &StopWaitingThread::stopPlay,
  417. this,
  418. &PlayerController::stopPlay);
  419. connect(m_stopPlayWaitingThread.get(),
  420. &StopWaitingThread::startPlay,
  421. this,
  422. &PlayerController::startToPlay);
  423. m_stopPlayWaitingThread->start();
  424. qDebug("++++++++++ StopPlay waiting thread started");
  425. }
  426. void PlayerController::allThreadStart()
  427. {
  428. // 启动所有创建的线程
  429. if (m_packetReadThread) {
  430. m_packetReadThread->start();
  431. qDebug("++++++++++ Read packets thread started");
  432. }
  433. if (m_decodeVideoThread) {
  434. m_decodeVideoThread->start();
  435. qDebug("++++++++++ Video decode thread started");
  436. }
  437. if (m_decodeAudioThread) {
  438. m_decodeAudioThread->start(QThread::Priority::HighPriority);
  439. qDebug("++++++++++ Audio decode thread started");
  440. }
  441. if (m_decodeSubtitleThread) {
  442. m_decodeSubtitleThread->start();
  443. qDebug("++++++++++ Subtitle decode thread started");
  444. }
  445. if (m_videoPlayThread) {
  446. m_videoPlayThread->start();
  447. qDebug("++++++++++ Video play thread started");
  448. }
  449. if (m_audioPlayThread) {
  450. m_audioPlayThread->start();
  451. qDebug("++++++++++ Audio play thread started");
  452. }
  453. // 通知UI更新
  454. emit setPlayControlWnd(true);
  455. emit updatePlayControlVolume();
  456. emit updatePlayControlStatus();
  457. }
  458. // 辅助函数
  459. void PlayerController::videoSeekInc(double increment)
  460. {
  461. if (!m_videoState)
  462. return;
  463. auto state = m_videoState->get_state();
  464. if (!state)
  465. return;
  466. double position = get_master_clock(state);
  467. if (std::isnan(position)) {
  468. position = static_cast<double>(state->seek_pos) / AV_TIME_BASE;
  469. }
  470. position += increment;
  471. videoSeek(position, increment);
  472. }
  473. // 新增自愈机制辅助函数
  474. void PlayerController::checkAndResetState()
  475. {
  476. std::lock_guard<std::mutex> lock(m_stopMutex);
  477. if (!m_packetReadThread && !m_decodeVideoThread && !m_decodeAudioThread &&
  478. !m_audioPlayThread && !m_videoPlayThread && !m_decodeSubtitleThread) {
  479. m_videoState.reset();
  480. m_currentFile.clear();
  481. m_state = PlayerState::Idle;
  482. qDebug() << "[PlayerController] All threads stopped, state reset to Idle.";
  483. emit playbackFinished(); // 新增:通知UI
  484. } else {
  485. qDebug() << "[PlayerController] checkAndResetState: "
  486. << "m_packetReadThread:" << (bool)m_packetReadThread
  487. << "m_decodeVideoThread:" << (bool)m_decodeVideoThread
  488. << "m_decodeAudioThread:" << (bool)m_decodeAudioThread
  489. << "m_audioPlayThread:" << (bool)m_audioPlayThread
  490. << "m_videoPlayThread:" << (bool)m_videoPlayThread
  491. << "m_decodeSubtitleThread:" << (bool)m_decodeSubtitleThread;
  492. }
  493. }
  494. // 线程创建方法
  495. bool PlayerController::createVideoState(const QString& file)
  496. {
  497. const bool useHardware = false; // 待实现:来自UI设置
  498. const bool loop = false; // 待实现:来自UI设置
  499. if (m_videoState)
  500. return false;
  501. m_videoState = std::make_unique<VideoStateData>(useHardware, loop);
  502. const int ret = m_videoState->create_video_state(file.toUtf8().constData());
  503. if (ret < 0) {
  504. m_videoState.reset();
  505. qWarning("Video state creation failed (error: %d)", ret);
  506. return false;
  507. }
  508. return true;
  509. }
  510. void PlayerController::deleteVideoState()
  511. {
  512. m_videoState.reset();
  513. }
  514. bool PlayerController::createReadThread()
  515. {
  516. if (m_packetReadThread)
  517. return false;
  518. m_packetReadThread = std::make_unique<ReadThread>(this);
  519. connect(m_packetReadThread.get(),
  520. &ReadThread::finished,
  521. this,
  522. &PlayerController::readPacketStopped);
  523. return true;
  524. }
  525. bool PlayerController::createDecodeVideoThread()
  526. {
  527. if (!m_videoState || m_decodeVideoThread)
  528. return false;
  529. auto state = m_videoState->get_state();
  530. if (!state)
  531. return false;
  532. m_decodeVideoThread = std::make_unique<VideoDecodeThread>(this, state);
  533. connect(m_decodeVideoThread.get(),
  534. &VideoDecodeThread::finished,
  535. this,
  536. &PlayerController::decodeVideoStopped);
  537. auto codecContext = m_videoState->get_contex(AVMEDIA_TYPE_VIDEO);
  538. // 初始化视频解码器
  539. int ret = decoder_init(&state->viddec,
  540. codecContext,
  541. &state->videoq,
  542. state->continue_read_thread);
  543. if (ret < 0) {
  544. qWarning("Video decoder initialization failed (error: %d)", ret);
  545. return false;
  546. }
  547. ret = decoder_start(&state->viddec, m_decodeVideoThread.get(), "video_decoder");
  548. if (ret < 0) {
  549. qWarning("Video decoder start failed (error: %d)", ret);
  550. return false;
  551. }
  552. state->queue_attachments_req = 1;
  553. return true;
  554. }
  555. bool PlayerController::createDecodeAudioThread()
  556. {
  557. if (!m_videoState || m_decodeAudioThread)
  558. return false;
  559. auto state = m_videoState->get_state();
  560. if (!state)
  561. return false;
  562. m_decodeAudioThread = std::make_unique<AudioDecodeThread>(this, state);
  563. connect(m_decodeAudioThread.get(),
  564. &AudioDecodeThread::finished,
  565. this,
  566. &PlayerController::decodeAudioStopped);
  567. auto codecContext = m_videoState->get_contex(AVMEDIA_TYPE_AUDIO);
  568. // 初始化音频解码器
  569. int ret = decoder_init(&state->auddec,
  570. codecContext,
  571. &state->audioq,
  572. state->continue_read_thread);
  573. if (ret < 0) {
  574. qWarning("Audio decoder initialization failed (error: %d)", ret);
  575. return false;
  576. }
  577. ret = decoder_start(&state->auddec, m_decodeAudioThread.get(), "audio_decoder");
  578. if (ret < 0) {
  579. qWarning("Audio decoder start failed (error: %d)", ret);
  580. return false;
  581. }
  582. return true;
  583. }
  584. bool PlayerController::createDecodeSubtitleThread()
  585. {
  586. if (!m_videoState || m_decodeSubtitleThread)
  587. return false;
  588. auto state = m_videoState->get_state();
  589. if (!state)
  590. return false;
  591. m_decodeSubtitleThread = std::make_unique<SubtitleDecodeThread>(this, state);
  592. connect(m_decodeSubtitleThread.get(),
  593. &SubtitleDecodeThread::finished,
  594. this,
  595. &PlayerController::decodeSubtitleStopped);
  596. auto codecContext = m_videoState->get_contex(AVMEDIA_TYPE_SUBTITLE);
  597. // 初始化字幕解码器
  598. int ret = decoder_init(&state->subdec,
  599. codecContext,
  600. &state->subtitleq,
  601. state->continue_read_thread);
  602. if (ret < 0) {
  603. qWarning("Subtitle decoder initialization failed (error: %d)", ret);
  604. return false;
  605. }
  606. ret = decoder_start(&state->subdec, m_decodeSubtitleThread.get(), "subtitle_decoder");
  607. if (ret < 0) {
  608. qWarning("Subtitle decoder start failed (error: %d)", ret);
  609. return false;
  610. }
  611. return true;
  612. }
  613. bool PlayerController::createVideoPlayThread()
  614. {
  615. if (!m_videoState || m_videoPlayThread)
  616. return false;
  617. auto state = m_videoState->get_state();
  618. if (!state)
  619. return false;
  620. m_videoPlayThread = std::make_unique<VideoPlayThread>(this, state);
  621. // 连接信号
  622. connect(m_videoPlayThread.get(),
  623. &VideoPlayThread::finished,
  624. this,
  625. &PlayerController::videoPlayStopped);
  626. connect(m_videoPlayThread.get(),
  627. &VideoPlayThread::frameReady,
  628. this,
  629. &PlayerController::frameReady);
  630. connect(m_videoPlayThread.get(),
  631. &VideoPlayThread::subtitle_ready,
  632. this,
  633. &PlayerController::subtitleReady);
  634. connect(this,
  635. &PlayerController::stopVideoPlayThread,
  636. m_videoPlayThread.get(),
  637. &VideoPlayThread::stop_thread);
  638. // 初始化参数
  639. auto videoContext = m_videoState->get_contex(AVMEDIA_TYPE_VIDEO);
  640. const bool useHardware = m_videoState->is_hardware_decode();
  641. if (!m_videoPlayThread->init_resample_param(videoContext, useHardware)) {
  642. qWarning("Video resample parameters initialization failed");
  643. return false;
  644. }
  645. return true;
  646. }
  647. bool PlayerController::createAudioPlayThread()
  648. {
  649. if (!m_videoState || m_audioPlayThread)
  650. return false;
  651. auto state = m_videoState->get_state();
  652. if (!state)
  653. return false;
  654. m_audioPlayThread = std::make_unique<AudioPlayThread>(this, state);
  655. // 连接信号
  656. connect(m_audioPlayThread.get(),
  657. &AudioPlayThread::finished,
  658. this,
  659. &PlayerController::audioPlayStopped);
  660. connect(this,
  661. &PlayerController::stopAudioPlayThread,
  662. m_audioPlayThread.get(),
  663. &AudioPlayThread::stop_thread);
  664. connect(m_audioPlayThread.get(),
  665. &AudioPlayThread::update_play_time,
  666. this,
  667. &PlayerController::updatePlayTime);
  668. connect(m_audioPlayThread.get(),
  669. &AudioPlayThread::data_visual_ready,
  670. this,
  671. &PlayerController::audioData);
  672. // 音频设备初始化在独立线程中完成
  673. return true;
  674. }
  675. bool PlayerController::startPlayThread()
  676. {
  677. if (m_beforePlayThread)
  678. return false;
  679. m_beforePlayThread = std::make_unique<StartPlayThread>(this, this);
  680. connect(m_beforePlayThread.get(),
  681. &StartPlayThread::audio_device_init,
  682. this,
  683. &PlayerController::playStarted);
  684. m_beforePlayThread->start();
  685. qDebug("++++++++++ StartPlay thread (audio init) started");
  686. return true;
  687. }
  688. // 调试辅助函数
  689. void PlayerController::printDecodeContext(const AVCodecContext* codecCtx, bool isVideo) const
  690. {
  691. if (!codecCtx)
  692. return;
  693. qInfo("%s codec: %s", isVideo ? "Video" : "Audio", codecCtx->codec->name);
  694. qInfo(" Type: %d, ID: %d, Tag: %d",
  695. codecCtx->codec_type,
  696. codecCtx->codec_id,
  697. codecCtx->codec_tag);
  698. if (isVideo) {
  699. qInfo(" Dimensions: %dx%d", codecCtx->width, codecCtx->height);
  700. } else {
  701. qInfo(" Sample rate: %d Hz, Channels: %d, Format: %d",
  702. codecCtx->sample_rate,
  703. codecCtx->ch_layout.nb_channels,
  704. codecCtx->sample_fmt);
  705. qInfo(" Frame size: %d, Block align: %d", codecCtx->frame_size, codecCtx->block_align);
  706. }
  707. }