|
@@ -92,15 +92,7 @@ PlayerCoreV2::PlayerCoreV2(const SyncConfigV2& syncConfig)
|
|
|
m_eventCallback->onFrameDropped(m_stats.droppedFrames);
|
|
m_eventCallback->onFrameDropped(m_stats.droppedFrames);
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
-
|
|
|
|
|
- // 创建线程管理器
|
|
|
|
|
- m_threadManager = std::make_unique<ThreadManager>();
|
|
|
|
|
- if (!m_threadManager) {
|
|
|
|
|
- Logger::instance().error("Failed to create thread manager");
|
|
|
|
|
- setState(PlayerState::Error);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// 创建解码器
|
|
// 创建解码器
|
|
|
m_videoDecoder = std::make_unique<VideoDecoder>();
|
|
m_videoDecoder = std::make_unique<VideoDecoder>();
|
|
|
if (!m_videoDecoder) {
|
|
if (!m_videoDecoder) {
|
|
@@ -210,19 +202,16 @@ ErrorCode PlayerCoreV2::openFile(const std::string& filename) {
|
|
|
// 如果已设置视频渲染器且有视频流,重新初始化渲染器
|
|
// 如果已设置视频渲染器且有视频流,重新初始化渲染器
|
|
|
if (m_mediaInfo.hasVideo && m_openGLVideoRenderer) {
|
|
if (m_mediaInfo.hasVideo && m_openGLVideoRenderer) {
|
|
|
AVStream* videoStream = m_formatContext->streams[m_mediaInfo.videoStreamIndex];
|
|
AVStream* videoStream = m_formatContext->streams[m_mediaInfo.videoStreamIndex];
|
|
|
- double fps = m_mediaInfo.fps > 0 ? m_mediaInfo.fps : 25.0;
|
|
|
|
|
|
|
|
|
|
- bool rendererInitResult = m_openGLVideoRenderer->initialize(
|
|
|
|
|
|
|
+ bool rendererInitResult = m_openGLVideoRenderer->Open(
|
|
|
videoStream->codecpar->width,
|
|
videoStream->codecpar->width,
|
|
|
- videoStream->codecpar->height,
|
|
|
|
|
- static_cast<AVPixelFormat>(videoStream->codecpar->format),
|
|
|
|
|
- fps
|
|
|
|
|
|
|
+ videoStream->codecpar->height
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
if (!rendererInitResult) {
|
|
if (!rendererInitResult) {
|
|
|
Logger::instance().warning("Failed to initialize OpenGL video renderer");
|
|
Logger::instance().warning("Failed to initialize OpenGL video renderer");
|
|
|
} else {
|
|
} else {
|
|
|
- Logger::instance().info("OpenGL video renderer initialized successfully with fps: " + std::to_string(fps));
|
|
|
|
|
|
|
+ Logger::instance().info("OpenGL video renderer initialized successfully");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -274,15 +263,25 @@ ErrorCode PlayerCoreV2::play() {
|
|
|
if (m_state == PlayerState::Paused) {
|
|
if (m_state == PlayerState::Paused) {
|
|
|
m_audioOutput->resume();
|
|
m_audioOutput->resume();
|
|
|
} else {
|
|
} else {
|
|
|
|
|
+ Logger::instance().info("Starting audio output device...");
|
|
|
m_audioOutput->start();
|
|
m_audioOutput->start();
|
|
|
|
|
+
|
|
|
|
|
+ // 检查音频设备是否成功启动
|
|
|
|
|
+ if (!m_audioOutput->isPlaying()) {
|
|
|
|
|
+ Logger::instance().error("Audio output device failed to start");
|
|
|
|
|
+ // 不要因为音频失败而停止整个播放,继续播放视频
|
|
|
|
|
+ Logger::instance().warning("Continuing playback without audio");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Logger::instance().info("Audio output device started successfully");
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 设置音频参数
|
|
// 设置音频参数
|
|
|
m_audioOutput->setVolume(m_volume);
|
|
m_audioOutput->setVolume(m_volume);
|
|
|
m_audioOutput->setPlaybackSpeed(m_playbackSpeed);
|
|
m_audioOutput->setPlaybackSpeed(m_playbackSpeed);
|
|
|
|
|
|
|
|
- // 给音频输出设备时间初始化
|
|
|
|
|
- std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
|
|
|
|
|
|
+ // 给音频输出设备更多时间初始化
|
|
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 启动线程
|
|
// 启动线程
|
|
@@ -367,7 +366,7 @@ ErrorCode PlayerCoreV2::stop() {
|
|
|
|
|
|
|
|
// 清空OpenGL视频渲染器
|
|
// 清空OpenGL视频渲染器
|
|
|
if (m_openGLVideoRenderer) {
|
|
if (m_openGLVideoRenderer) {
|
|
|
- m_openGLVideoRenderer->clear();
|
|
|
|
|
|
|
+ m_openGLVideoRenderer->Close();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 停止所有线程
|
|
// 停止所有线程
|
|
@@ -530,7 +529,7 @@ SyncConfigV2 PlayerCoreV2::getSyncConfig() const {
|
|
|
return SyncConfigV2();
|
|
return SyncConfigV2();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void PlayerCoreV2::setOpenGLVideoRenderer(OpenGLVideoRenderer* renderer) {
|
|
|
|
|
|
|
+void PlayerCoreV2::setOpenGLVideoRenderer(OpenGLVideoWidget* renderer) {
|
|
|
m_openGLVideoRenderer = renderer;
|
|
m_openGLVideoRenderer = renderer;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -726,40 +725,39 @@ bool PlayerCoreV2::setupVideoDecoder() {
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 分配解码器上下文
|
|
|
|
|
- AVCodecContext* codecContext = avcodec_alloc_context3(codec);
|
|
|
|
|
- if (!codecContext) {
|
|
|
|
|
- Logger::instance().error("Failed to allocate video codec context");
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 复制流参数到解码器上下文
|
|
|
|
|
- if (avcodec_parameters_to_context(codecContext, videoStream->codecpar) < 0) {
|
|
|
|
|
- Logger::instance().error("Failed to copy video codec parameters");
|
|
|
|
|
- avcodec_free_context(&codecContext);
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 打开解码器
|
|
|
|
|
- if (avcodec_open2(codecContext, codec, nullptr) < 0) {
|
|
|
|
|
- Logger::instance().error("Failed to open video codec");
|
|
|
|
|
- avcodec_free_context(&codecContext);
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ Logger::instance().info("Found video codec: " + std::string(codec->name));
|
|
|
|
|
+ Logger::instance().info("Video stream info: width=" + std::to_string(videoStream->codecpar->width) +
|
|
|
|
|
+ ", height=" + std::to_string(videoStream->codecpar->height) +
|
|
|
|
|
+ ", format=" + std::to_string(videoStream->codecpar->format));
|
|
|
|
|
|
|
|
// 创建视频解码器参数
|
|
// 创建视频解码器参数
|
|
|
VideoDecoderParams videoParams;
|
|
VideoDecoderParams videoParams;
|
|
|
videoParams.codecName = codec->name;
|
|
videoParams.codecName = codec->name;
|
|
|
- videoParams.width = codecContext->width;
|
|
|
|
|
- videoParams.height = codecContext->height;
|
|
|
|
|
- videoParams.pixelFormat = codecContext->pix_fmt;
|
|
|
|
|
- videoParams.hardwareAccel = true;
|
|
|
|
|
|
|
+ videoParams.width = videoStream->codecpar->width;
|
|
|
|
|
+ videoParams.height = videoStream->codecpar->height;
|
|
|
|
|
+ videoParams.pixelFormat = static_cast<AVPixelFormat>(videoStream->codecpar->format);
|
|
|
|
|
+ videoParams.hardwareAccel = false; // 先禁用硬件加速来排除问题
|
|
|
videoParams.lowLatency = false;
|
|
videoParams.lowLatency = false;
|
|
|
|
|
|
|
|
|
|
+ Logger::instance().info("Video decoder params: codec=" + videoParams.codecName +
|
|
|
|
|
+ ", size=" + std::to_string(videoParams.width) + "x" + std::to_string(videoParams.height) +
|
|
|
|
|
+ ", format=" + std::to_string(static_cast<int>(videoParams.pixelFormat)));
|
|
|
|
|
+
|
|
|
// 初始化视频解码器
|
|
// 初始化视频解码器
|
|
|
if (m_videoDecoder->initialize(videoParams) != ErrorCode::SUCCESS) {
|
|
if (m_videoDecoder->initialize(videoParams) != ErrorCode::SUCCESS) {
|
|
|
Logger::instance().error("Failed to initialize video decoder");
|
|
Logger::instance().error("Failed to initialize video decoder");
|
|
|
- avcodec_free_context(&codecContext);
|
|
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 设置流参数
|
|
|
|
|
+ if (m_videoDecoder->setStreamParameters(videoStream->codecpar) != ErrorCode::SUCCESS) {
|
|
|
|
|
+ Logger::instance().error("Failed to set video decoder stream parameters");
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 打开视频解码器
|
|
|
|
|
+ if (m_videoDecoder->open(videoParams) != ErrorCode::SUCCESS) {
|
|
|
|
|
+ Logger::instance().error("Failed to open video decoder");
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1105,8 +1103,8 @@ void PlayerCoreV2::readThreadFunc() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
m_seeking = false;
|
|
m_seeking = false;
|
|
|
- setState(m_state == PlayerState::Seeking ? PlayerState::Playing : m_state);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ setState(m_state == PlayerState::Seeking ? PlayerState::Playing : m_state.load());
|
|
|
|
|
+
|
|
|
lock.unlock();
|
|
lock.unlock();
|
|
|
m_seekCondition.notify_all();
|
|
m_seekCondition.notify_all();
|
|
|
}
|
|
}
|
|
@@ -1121,8 +1119,20 @@ void PlayerCoreV2::readThreadFunc() {
|
|
|
int ret = av_read_frame(m_formatContext, packet);
|
|
int ret = av_read_frame(m_formatContext, packet);
|
|
|
if (ret < 0) {
|
|
if (ret < 0) {
|
|
|
if (ret == AVERROR_EOF) {
|
|
if (ret == AVERROR_EOF) {
|
|
|
- Logger::instance().info("End of file reached");
|
|
|
|
|
- // 文件结束,可以选择循环播放或停止
|
|
|
|
|
|
|
+ Logger::instance().info("End of file reached, sending EOF packets to queues");
|
|
|
|
|
+
|
|
|
|
|
+ // 向队列发送EOF标记,让解码线程知道文件结束
|
|
|
|
|
+ if (m_packetQueue) {
|
|
|
|
|
+ // 创建EOF标记包
|
|
|
|
|
+ AVPacket* eofPacket = av_packet_alloc();
|
|
|
|
|
+ if (eofPacket) {
|
|
|
|
|
+ eofPacket->data = nullptr;
|
|
|
|
|
+ eofPacket->size = 0;
|
|
|
|
|
+ eofPacket->stream_index = -1; // 特殊标记表示EOF
|
|
|
|
|
+ m_packetQueue->push(eofPacket);
|
|
|
|
|
+ Logger::instance().info("EOF packet sent to queue");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
break;
|
|
break;
|
|
|
} else {
|
|
} else {
|
|
|
Logger::instance().error("Error reading frame: " + std::to_string(ret));
|
|
Logger::instance().error("Error reading frame: " + std::to_string(ret));
|
|
@@ -1155,6 +1165,8 @@ void PlayerCoreV2::readThreadFunc() {
|
|
|
void PlayerCoreV2::videoDecodeThreadFunc() {
|
|
void PlayerCoreV2::videoDecodeThreadFunc() {
|
|
|
Logger::instance().info("Video decode thread started");
|
|
Logger::instance().info("Video decode thread started");
|
|
|
|
|
|
|
|
|
|
+ int packetCount = 0;
|
|
|
|
|
+ int frameCount = 0;
|
|
|
while (!m_threadsShouldStop) {
|
|
while (!m_threadsShouldStop) {
|
|
|
if (!m_packetQueue || !m_videoFrameQueue || !m_videoDecoder) {
|
|
if (!m_packetQueue || !m_videoFrameQueue || !m_videoDecoder) {
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
@@ -1165,43 +1177,97 @@ void PlayerCoreV2::videoDecodeThreadFunc() {
|
|
|
AVPacket* packet = nullptr;
|
|
AVPacket* packet = nullptr;
|
|
|
while (!m_threadsShouldStop && !packet) {
|
|
while (!m_threadsShouldStop && !packet) {
|
|
|
packet = m_packetQueue->pop();
|
|
packet = m_packetQueue->pop();
|
|
|
- if (packet && packet->stream_index != m_mediaInfo.videoStreamIndex) {
|
|
|
|
|
- // packet已经被packetPtr管理,不需要手动释放
|
|
|
|
|
- packet = nullptr;
|
|
|
|
|
|
|
+ if (packet) {
|
|
|
|
|
+ // 检查是否是EOF标记
|
|
|
|
|
+ if (packet->stream_index == -1 && packet->data == nullptr) {
|
|
|
|
|
+ Logger::instance().info("Video decode thread received EOF packet");
|
|
|
|
|
+ av_packet_free(&packet);
|
|
|
|
|
+
|
|
|
|
|
+ // 向视频帧队列发送EOF标记
|
|
|
|
|
+ if (m_videoFrameQueue) {
|
|
|
|
|
+ AVFrame* eofFrame = av_frame_alloc();
|
|
|
|
|
+ if (eofFrame) {
|
|
|
|
|
+ eofFrame->data[0] = nullptr;
|
|
|
|
|
+ eofFrame->width = 0;
|
|
|
|
|
+ eofFrame->height = 0;
|
|
|
|
|
+ eofFrame->pts = AV_NOPTS_VALUE;
|
|
|
|
|
+ m_videoFrameQueue->push(eofFrame);
|
|
|
|
|
+ Logger::instance().info("EOF frame sent to video frame queue");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 视频解码线程结束
|
|
|
|
|
+ Logger::instance().info("Video decode thread finishing due to EOF");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (packet->stream_index != m_mediaInfo.videoStreamIndex) {
|
|
|
|
|
+ Logger::instance().debug("Skipping non-video packet, stream_index=" + std::to_string(packet->stream_index) +
|
|
|
|
|
+ ", expected=" + std::to_string(m_mediaInfo.videoStreamIndex));
|
|
|
|
|
+ av_packet_free(&packet);
|
|
|
|
|
+ packet = nullptr;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
if (!packet) {
|
|
if (!packet) {
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (!packet) continue;
|
|
|
|
|
|
|
+ if (!packet) {
|
|
|
|
|
+ Logger::instance().debug("Video decode thread: no more packets available");
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ packetCount++;
|
|
|
|
|
+ Logger::instance().debug("Video decode thread got packet #" + std::to_string(packetCount) +
|
|
|
|
|
+ ", size=" + std::to_string(packet->size) +
|
|
|
|
|
+ ", pts=" + std::to_string(packet->pts));
|
|
|
|
|
|
|
|
// 解码视频帧
|
|
// 解码视频帧
|
|
|
AVPacketPtr packetPtr(packet);
|
|
AVPacketPtr packetPtr(packet);
|
|
|
std::vector<AVFramePtr> frames;
|
|
std::vector<AVFramePtr> frames;
|
|
|
- if (m_videoDecoder->decode(packetPtr, frames) == ErrorCode::SUCCESS) {
|
|
|
|
|
- for (const auto& framePtr : frames) {
|
|
|
|
|
|
|
+ ErrorCode decodeResult = m_videoDecoder->decode(packetPtr, frames);
|
|
|
|
|
+
|
|
|
|
|
+ Logger::instance().debug("Video decode result: " + std::to_string(static_cast<int>(decodeResult)) +
|
|
|
|
|
+ ", frames count: " + std::to_string(frames.size()));
|
|
|
|
|
+
|
|
|
|
|
+ if (decodeResult == ErrorCode::SUCCESS) {
|
|
|
|
|
+ for (auto& framePtr : frames) {
|
|
|
if (framePtr && !m_threadsShouldStop) {
|
|
if (framePtr && !m_threadsShouldStop) {
|
|
|
|
|
+ frameCount++;
|
|
|
|
|
+ Logger::instance().debug("Processing video frame #" + std::to_string(frameCount) +
|
|
|
|
|
+ ", width=" + std::to_string(framePtr->width) +
|
|
|
|
|
+ ", height=" + std::to_string(framePtr->height) +
|
|
|
|
|
+ ", pts=" + std::to_string(framePtr->pts));
|
|
|
|
|
+
|
|
|
// 设置帧的时间戳
|
|
// 设置帧的时间戳
|
|
|
if (framePtr->pts != AV_NOPTS_VALUE) {
|
|
if (framePtr->pts != AV_NOPTS_VALUE) {
|
|
|
AVStream* stream = m_formatContext->streams[m_mediaInfo.videoStreamIndex];
|
|
AVStream* stream = m_formatContext->streams[m_mediaInfo.videoStreamIndex];
|
|
|
double pts = framePtr->pts * av_q2d(stream->time_base) * 1000000; // 转换为微秒
|
|
double pts = framePtr->pts * av_q2d(stream->time_base) * 1000000; // 转换为微秒
|
|
|
framePtr->pts = static_cast<int64_t>(pts);
|
|
framePtr->pts = static_cast<int64_t>(pts);
|
|
|
|
|
+ Logger::instance().debug("Frame PTS converted to: " + std::to_string(framePtr->pts) + " microseconds");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 将帧放入队列
|
|
// 将帧放入队列
|
|
|
if (m_videoFrameQueue->size() < 30) { // 限制队列大小
|
|
if (m_videoFrameQueue->size() < 30) { // 限制队列大小
|
|
|
- m_videoFrameQueue->push(framePtr.get());
|
|
|
|
|
|
|
+ // 释放智能指针的所有权,让队列管理帧的生命周期
|
|
|
|
|
+ m_videoFrameQueue->push(framePtr.release());
|
|
|
m_frameCount++;
|
|
m_frameCount++;
|
|
|
|
|
+ Logger::instance().debug("Video frame pushed to queue, queue size: " + std::to_string(m_videoFrameQueue->size()));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Logger::instance().warning("Video frame queue full, dropping frame");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Logger::instance().warning("Video decode failed with error: " + std::to_string(static_cast<int>(decodeResult)));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// packet已经被packetPtr管理,不需要手动释放
|
|
// packet已经被packetPtr管理,不需要手动释放
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Logger::instance().info("Video decode thread finished");
|
|
|
|
|
|
|
+ Logger::instance().info("Video decode thread finished, packets processed: " + std::to_string(packetCount) +
|
|
|
|
|
+ ", frames decoded: " + std::to_string(frameCount));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void PlayerCoreV2::audioDecodeThreadFunc() {
|
|
void PlayerCoreV2::audioDecodeThreadFunc() {
|
|
@@ -1219,11 +1285,35 @@ void PlayerCoreV2::audioDecodeThreadFunc() {
|
|
|
AVPacket* packet = nullptr;
|
|
AVPacket* packet = nullptr;
|
|
|
while (!m_threadsShouldStop && !packet) {
|
|
while (!m_threadsShouldStop && !packet) {
|
|
|
packet = m_packetQueue->pop();
|
|
packet = m_packetQueue->pop();
|
|
|
- if (packet && packet->stream_index != m_mediaInfo.audioStreamIndex) {
|
|
|
|
|
- Logger::instance().debug("Skipping non-audio packet, stream_index=" + std::to_string(packet->stream_index) +
|
|
|
|
|
- ", expected=" + std::to_string(m_mediaInfo.audioStreamIndex));
|
|
|
|
|
- av_packet_free(&packet);
|
|
|
|
|
- packet = nullptr;
|
|
|
|
|
|
|
+ if (packet) {
|
|
|
|
|
+ // 检查是否是EOF标记
|
|
|
|
|
+ if (packet->stream_index == -1 && packet->data == nullptr) {
|
|
|
|
|
+ Logger::instance().info("Audio decode thread received EOF packet");
|
|
|
|
|
+ av_packet_free(&packet);
|
|
|
|
|
+
|
|
|
|
|
+ // 向音频帧队列发送EOF标记
|
|
|
|
|
+ if (m_audioFrameQueue) {
|
|
|
|
|
+ AVFrame* eofFrame = av_frame_alloc();
|
|
|
|
|
+ if (eofFrame) {
|
|
|
|
|
+ eofFrame->data[0] = nullptr;
|
|
|
|
|
+ eofFrame->nb_samples = 0;
|
|
|
|
|
+ eofFrame->pts = AV_NOPTS_VALUE;
|
|
|
|
|
+ m_audioFrameQueue->push(eofFrame);
|
|
|
|
|
+ Logger::instance().info("EOF frame sent to audio frame queue");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 音频解码线程结束
|
|
|
|
|
+ Logger::instance().info("Audio decode thread finishing due to EOF");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (packet->stream_index != m_mediaInfo.audioStreamIndex) {
|
|
|
|
|
+ Logger::instance().debug("Skipping non-audio packet, stream_index=" + std::to_string(packet->stream_index) +
|
|
|
|
|
+ ", expected=" + std::to_string(m_mediaInfo.audioStreamIndex));
|
|
|
|
|
+ av_packet_free(&packet);
|
|
|
|
|
+ packet = nullptr;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
if (!packet) {
|
|
if (!packet) {
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
|
@@ -1249,7 +1339,7 @@ void PlayerCoreV2::audioDecodeThreadFunc() {
|
|
|
", frames count: " + std::to_string(frames.size()));
|
|
", frames count: " + std::to_string(frames.size()));
|
|
|
|
|
|
|
|
if (decodeResult == ErrorCode::SUCCESS) {
|
|
if (decodeResult == ErrorCode::SUCCESS) {
|
|
|
- for (const auto& framePtr : frames) {
|
|
|
|
|
|
|
+ for (auto& framePtr : frames) {
|
|
|
if (framePtr && !m_threadsShouldStop) {
|
|
if (framePtr && !m_threadsShouldStop) {
|
|
|
frameCount++;
|
|
frameCount++;
|
|
|
Logger::instance().debug("Processing audio frame #" + std::to_string(frameCount) +
|
|
Logger::instance().debug("Processing audio frame #" + std::to_string(frameCount) +
|
|
@@ -1266,7 +1356,8 @@ void PlayerCoreV2::audioDecodeThreadFunc() {
|
|
|
|
|
|
|
|
// 将帧放入队列
|
|
// 将帧放入队列
|
|
|
if (m_audioFrameQueue->size() < 100) { // 限制队列大小
|
|
if (m_audioFrameQueue->size() < 100) { // 限制队列大小
|
|
|
- m_audioFrameQueue->push(framePtr.get());
|
|
|
|
|
|
|
+ // 释放智能指针的所有权,让队列管理帧的生命周期
|
|
|
|
|
+ m_audioFrameQueue->push(framePtr.release());
|
|
|
Logger::instance().debug("Audio frame pushed to queue, queue size: " + std::to_string(m_audioFrameQueue->size()));
|
|
Logger::instance().debug("Audio frame pushed to queue, queue size: " + std::to_string(m_audioFrameQueue->size()));
|
|
|
} else {
|
|
} else {
|
|
|
Logger::instance().warning("Audio frame queue full, dropping frame");
|
|
Logger::instance().warning("Audio frame queue full, dropping frame");
|
|
@@ -1296,13 +1387,18 @@ void PlayerCoreV2::videoPlayThreadFunc() {
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 获取视频帧
|
|
|
|
|
- AVFrame* frame = m_videoFrameQueue->pop();
|
|
|
|
|
|
|
+ // 获取视频帧,使用超时避免无限阻塞
|
|
|
|
|
+ AVFrame* frame = m_videoFrameQueue->pop(100); // 100ms超时
|
|
|
if (!frame) {
|
|
if (!frame) {
|
|
|
- std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
|
|
|
|
|
|
+ // 检查是否应该继续等待
|
|
|
|
|
+ if (m_threadsShouldStop) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ Logger::instance().debug("Video play thread got frame, pts=" + std::to_string(frame->pts));
|
|
|
|
|
+
|
|
|
// 更新视频时钟
|
|
// 更新视频时钟
|
|
|
if (frame->pts != AV_NOPTS_VALUE) {
|
|
if (frame->pts != AV_NOPTS_VALUE) {
|
|
|
m_synchronizer->setVideoClock(frame->pts / 1000000.0); // 转换为秒
|
|
m_synchronizer->setVideoClock(frame->pts / 1000000.0); // 转换为秒
|
|
@@ -1311,12 +1407,14 @@ void PlayerCoreV2::videoPlayThreadFunc() {
|
|
|
// 检查是否应该显示这一帧
|
|
// 检查是否应该显示这一帧
|
|
|
auto decision = m_synchronizer->shouldDisplayVideoFrame(frame->pts / 1000000.0);
|
|
auto decision = m_synchronizer->shouldDisplayVideoFrame(frame->pts / 1000000.0);
|
|
|
|
|
|
|
|
|
|
+ // 创建智能指针管理帧内存
|
|
|
|
|
+ AVFramePtr framePtr(frame);
|
|
|
|
|
+
|
|
|
switch (decision.action) {
|
|
switch (decision.action) {
|
|
|
case av::utils::FrameAction::DISPLAY:
|
|
case av::utils::FrameAction::DISPLAY:
|
|
|
// 显示帧
|
|
// 显示帧
|
|
|
if (m_openGLVideoRenderer) {
|
|
if (m_openGLVideoRenderer) {
|
|
|
- AVFramePtr framePtr(frame);
|
|
|
|
|
- m_openGLVideoRenderer->renderFrame(framePtr);
|
|
|
|
|
|
|
+ m_openGLVideoRenderer->Render(framePtr.get());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 计算下一帧的延迟
|
|
// 计算下一帧的延迟
|
|
@@ -1334,8 +1432,7 @@ void PlayerCoreV2::videoPlayThreadFunc() {
|
|
|
case av::utils::FrameAction::Frame_DUPLICATE:
|
|
case av::utils::FrameAction::Frame_DUPLICATE:
|
|
|
// 重复显示上一帧(这里简化处理)
|
|
// 重复显示上一帧(这里简化处理)
|
|
|
if (m_openGLVideoRenderer) {
|
|
if (m_openGLVideoRenderer) {
|
|
|
- AVFramePtr framePtr(frame);
|
|
|
|
|
- m_openGLVideoRenderer->renderFrame(framePtr);
|
|
|
|
|
|
|
+ m_openGLVideoRenderer->Render(framePtr.get());
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
@@ -1344,13 +1441,12 @@ void PlayerCoreV2::videoPlayThreadFunc() {
|
|
|
auto delayMs = static_cast<int>(decision.delay * 1000);
|
|
auto delayMs = static_cast<int>(decision.delay * 1000);
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
|
|
|
if (m_openGLVideoRenderer) {
|
|
if (m_openGLVideoRenderer) {
|
|
|
- AVFramePtr framePtr(frame);
|
|
|
|
|
- m_openGLVideoRenderer->renderFrame(framePtr);
|
|
|
|
|
|
|
+ m_openGLVideoRenderer->Render(framePtr.get());
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- av_frame_free(&frame);
|
|
|
|
|
|
|
+ // framePtr 会自动释放内存,无需手动调用 av_frame_free
|
|
|
|
|
|
|
|
// 更新帧时间
|
|
// 更新帧时间
|
|
|
lastFrameTime = std::chrono::steady_clock::now();
|
|
lastFrameTime = std::chrono::steady_clock::now();
|
|
@@ -1369,13 +1465,27 @@ void PlayerCoreV2::audioPlayThreadFunc() {
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 获取音频帧
|
|
|
|
|
- AVFrame* frame = m_audioFrameQueue->pop();
|
|
|
|
|
|
|
+ // 获取音频帧,使用较长的超时时间以确保能接收到EOF帧
|
|
|
|
|
+ AVFrame* frame = m_audioFrameQueue->pop(100); // 100ms超时
|
|
|
if (!frame) {
|
|
if (!frame) {
|
|
|
- std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
|
|
|
|
|
|
+ // 检查是否应该继续等待
|
|
|
|
|
+ if (m_threadsShouldStop) {
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 检查是否是EOF帧
|
|
|
|
|
+ if (frame->data[0] == nullptr && frame->nb_samples == 0) {
|
|
|
|
|
+ Logger::instance().info("Audio play thread received EOF frame, playback completed");
|
|
|
|
|
+ av_frame_free(&frame);
|
|
|
|
|
+
|
|
|
|
|
+ // 通知播放完成
|
|
|
|
|
+ setState(PlayerState::Stopped);
|
|
|
|
|
+ Logger::instance().info("Audio playback finished naturally");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
frameCount++;
|
|
frameCount++;
|
|
|
Logger::instance().debug("Audio play thread got frame #" + std::to_string(frameCount) +
|
|
Logger::instance().debug("Audio play thread got frame #" + std::to_string(frameCount) +
|
|
|
", pts=" + std::to_string(frame->pts) +
|
|
", pts=" + std::to_string(frame->pts) +
|
|
@@ -1392,12 +1502,14 @@ void PlayerCoreV2::audioPlayThreadFunc() {
|
|
|
Logger::instance().debug("Audio frame decision: action=" + std::to_string(static_cast<int>(decision.action)) +
|
|
Logger::instance().debug("Audio frame decision: action=" + std::to_string(static_cast<int>(decision.action)) +
|
|
|
", delay=" + std::to_string(decision.delay));
|
|
", delay=" + std::to_string(decision.delay));
|
|
|
|
|
|
|
|
|
|
+ // 创建智能指针管理帧内存
|
|
|
|
|
+ AVFramePtr framePtr(frame);
|
|
|
|
|
+
|
|
|
switch (decision.action) {
|
|
switch (decision.action) {
|
|
|
case av::utils::FrameAction::DISPLAY:
|
|
case av::utils::FrameAction::DISPLAY:
|
|
|
// 播放音频帧
|
|
// 播放音频帧
|
|
|
{
|
|
{
|
|
|
Logger::instance().debug("Writing audio frame to output device");
|
|
Logger::instance().debug("Writing audio frame to output device");
|
|
|
- AVFramePtr framePtr(frame);
|
|
|
|
|
bool writeResult = m_audioOutput->writeFrame(framePtr);
|
|
bool writeResult = m_audioOutput->writeFrame(framePtr);
|
|
|
Logger::instance().debug("Audio frame write result: " + std::to_string(writeResult));
|
|
Logger::instance().debug("Audio frame write result: " + std::to_string(writeResult));
|
|
|
}
|
|
}
|
|
@@ -1418,7 +1530,6 @@ void PlayerCoreV2::audioPlayThreadFunc() {
|
|
|
// 重复播放(音频中较少使用)
|
|
// 重复播放(音频中较少使用)
|
|
|
{
|
|
{
|
|
|
Logger::instance().debug("Duplicating audio frame");
|
|
Logger::instance().debug("Duplicating audio frame");
|
|
|
- AVFramePtr framePtr(frame);
|
|
|
|
|
bool writeResult = m_audioOutput->writeFrame(framePtr);
|
|
bool writeResult = m_audioOutput->writeFrame(framePtr);
|
|
|
Logger::instance().debug("Audio frame duplicate write result: " + std::to_string(writeResult));
|
|
Logger::instance().debug("Audio frame duplicate write result: " + std::to_string(writeResult));
|
|
|
}
|
|
}
|
|
@@ -1430,14 +1541,13 @@ void PlayerCoreV2::audioPlayThreadFunc() {
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(delayMs));
|
|
|
{
|
|
{
|
|
|
Logger::instance().debug("Writing delayed audio frame to output device");
|
|
Logger::instance().debug("Writing delayed audio frame to output device");
|
|
|
- AVFramePtr framePtr(frame);
|
|
|
|
|
bool writeResult = m_audioOutput->writeFrame(framePtr);
|
|
bool writeResult = m_audioOutput->writeFrame(framePtr);
|
|
|
Logger::instance().debug("Audio frame delayed write result: " + std::to_string(writeResult));
|
|
Logger::instance().debug("Audio frame delayed write result: " + std::to_string(writeResult));
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- av_frame_free(&frame);
|
|
|
|
|
|
|
+ // framePtr 会自动释放内存,无需手动调用 av_frame_free
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Logger::instance().info("Audio play thread finished, total frames processed: " + std::to_string(frameCount));
|
|
Logger::instance().info("Audio play thread finished, total frames processed: " + std::to_string(frameCount));
|