playercontroller.cpp 24 KB

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