|
|
@@ -8,13 +8,10 @@
|
|
|
#include <cassert>
|
|
|
#include <memory>
|
|
|
|
|
|
-#include "ffmpeg_init.h"
|
|
|
-#include "start_play_thread.h"
|
|
|
-#include "video_state.h"
|
|
|
-
|
|
|
#include "audio_decode_thread.h"
|
|
|
#include "audio_effect_helper.h"
|
|
|
#include "audio_play_thread.h"
|
|
|
+#include "ffmpeg_init.h"
|
|
|
#include "play_control_window.h"
|
|
|
#include "read_thread.h"
|
|
|
#include "start_play_thread.h"
|
|
|
@@ -44,40 +41,59 @@ PlayerController::~PlayerController()
|
|
|
|
|
|
void PlayerController::startToPlay(const QString& file)
|
|
|
{
|
|
|
- std::lock_guard<std::mutex> lock(m_stopMutex);
|
|
|
- qCDebug(playerControllerLog) << "[PlayerController] m_state" << (int) m_state.load();
|
|
|
-
|
|
|
- // 自愈:如果状态为Playing但所有线程都已退出,强制Idle
|
|
|
- if (m_state == PlayerState::Playing && areAllThreadsStopped()) {
|
|
|
- stopAndResetThreads();
|
|
|
- m_videoState.reset();
|
|
|
- m_currentFile.clear();
|
|
|
- m_state = PlayerState::Idle;
|
|
|
- qCDebug(playerControllerLog)
|
|
|
- << "[PlayerController] All threads stopped, force reset to Idle.";
|
|
|
+ // 使用局部变量保存当前状态,避免在锁外使用成员变量
|
|
|
+ PlayerState currentState = m_state;
|
|
|
+ QString currentFile = m_currentFile;
|
|
|
+
|
|
|
+ {
|
|
|
+ std::lock_guard<std::mutex> lock(m_stopMutex);
|
|
|
+ qCDebug(playerControllerLog) << "[PlayerController] m_state" << (int) m_state.load();
|
|
|
+
|
|
|
+ // 自愈:如果状态为Playing但所有线程都已退出,强制Idle
|
|
|
+ if (m_state == PlayerState::Playing && areAllThreadsStopped()) {
|
|
|
+ stopAndResetThreads();
|
|
|
+ m_videoState.reset();
|
|
|
+ m_currentFile.clear();
|
|
|
+ m_state = PlayerState::Idle;
|
|
|
+ qCDebug(playerControllerLog)
|
|
|
+ << "[PlayerController] All threads stopped, force reset to Idle.";
|
|
|
+ }
|
|
|
+
|
|
|
+ currentState = m_state;
|
|
|
+ currentFile = m_currentFile;
|
|
|
}
|
|
|
|
|
|
// 初始化中,忽略新请求
|
|
|
- if (m_state == PlayerState::Initializing) {
|
|
|
+ if (currentState == PlayerState::Initializing) {
|
|
|
qCDebug(playerControllerLog) << "Player is initializing. Ignoring request.";
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 正在播放中,检查是否需要切换文件
|
|
|
- if (m_state == PlayerState::Playing) {
|
|
|
- if (m_currentFile == file) {
|
|
|
+ if (currentState == PlayerState::Playing) {
|
|
|
+ if (currentFile == file) {
|
|
|
qCDebug(playerControllerLog) << "Already playing the same file. Ignoring request.";
|
|
|
return;
|
|
|
} else {
|
|
|
qCDebug(playerControllerLog)
|
|
|
<< "Player is busy with another file, stopping and switching to:" << file;
|
|
|
+ // 在锁外调用stopPlay,避免死锁
|
|
|
stopPlay();
|
|
|
- // 这里直接 fallthrough 到 Idle 状态
|
|
|
+ // 停止后重新获取状态
|
|
|
+ currentState = PlayerState::Idle; // 假设stopPlay会将状态设为Idle
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 空闲状态,开始新播放
|
|
|
- if (m_state == PlayerState::Idle) {
|
|
|
+ if (currentState == PlayerState::Idle) {
|
|
|
+ std::lock_guard<std::mutex> lock(m_stopMutex);
|
|
|
+
|
|
|
+ // 再次检查状态,确保在获取锁的过程中状态没有改变
|
|
|
+ if (m_state != PlayerState::Idle) {
|
|
|
+ qCDebug(playerControllerLog) << "State changed while waiting for lock. Current state:" << (int)m_state.load();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
// 确保所有线程已停止
|
|
|
if (!areAllThreadsStopped()) {
|
|
|
qCDebug(playerControllerLog) << "Some threads still running, stopping them first";
|
|
|
@@ -131,7 +147,7 @@ void PlayerController::asyncInit(const QString& file)
|
|
|
|
|
|
void PlayerController::onAsyncInitFinished(const QString& file, bool success)
|
|
|
{
|
|
|
- std::lock_guard<std::mutex> lock(m_stopMutex);
|
|
|
+ // 移除互斥锁,避免与stopPlay产生死锁
|
|
|
QElapsedTimer timer;
|
|
|
timer.start();
|
|
|
|
|
|
@@ -224,7 +240,7 @@ void PlayerController::onAsyncInitFinished(const QString& file, bool success)
|
|
|
|
|
|
void PlayerController::stopPlay()
|
|
|
{
|
|
|
- std::lock_guard<std::mutex> lock(m_stopMutex);
|
|
|
+ // 移除互斥锁,避免与startToPlay中的锁冲突
|
|
|
if (m_state == PlayerState::Idle)
|
|
|
return;
|
|
|
|
|
|
@@ -387,14 +403,9 @@ void PlayerController::readPacketStopped()
|
|
|
dump();
|
|
|
qCDebug(playerControllerLog) << "************* Read packets thread stopped signal received.";
|
|
|
|
|
|
- auto state = m_videoState->get_state();
|
|
|
- // if (state) {
|
|
|
- // state->abort_request = 1;
|
|
|
- // }
|
|
|
- if (m_videoState && m_videoState->get_state()) {
|
|
|
- m_videoState->delete_video_state(); // stream_close
|
|
|
- }
|
|
|
-
|
|
|
+ // 不在这里调用delete_video_state,避免与stopAndResetThreads中的调用重复
|
|
|
+ // 资源清理统一由stopAndResetThreads处理
|
|
|
+
|
|
|
emit audioStopped();
|
|
|
}
|
|
|
|
|
|
@@ -643,13 +654,11 @@ void PlayerController::stopAndResetThreads()
|
|
|
stopAndReset(m_audioPlayThread, "AudioPlay");
|
|
|
|
|
|
// 解码前先 关闭流 不然会卡死异常
|
|
|
+ // 注意:这里是唯一调用delete_video_state的地方,readPacketStopped不再调用
|
|
|
+ // 以避免重复关闭导致的异常
|
|
|
if (m_videoState && m_videoState->get_state()) {
|
|
|
m_videoState->delete_video_state();
|
|
|
}
|
|
|
- // auto state = m_videoState->get_state();
|
|
|
- // if (state) {
|
|
|
- // state->abort_request = 1;
|
|
|
- // }
|
|
|
stopAndReset(m_packetReadThread, "PacketRead");
|
|
|
|
|
|
stopAndReset(m_decodeVideoThread, "DecodeVideo");
|