|
|
@@ -49,55 +49,63 @@ PlayerCoreV2::PlayerCoreV2(const SyncConfigV2& syncConfig)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 创建分离的视频和音频包队列
|
|
|
- m_videoPacketQueue = av::utils::PacketQueueFactory::createStandardQueue(1000); // 视频包队列
|
|
|
+ // 创建分离的视频和音频包队列 - 使用高容量队列以避免丢帧
|
|
|
+ m_videoPacketQueue = av::utils::PacketQueueFactory::createHighCapacityQueue(2000); // 视频包队列,增大容量
|
|
|
if (!m_videoPacketQueue) {
|
|
|
Logger::instance().error("Failed to create video packet queue");
|
|
|
setState(PlayerState::Error);
|
|
|
return;
|
|
|
}
|
|
|
+ // 禁用丢包策略
|
|
|
+ m_videoPacketQueue->setDropPolicy(false, true);
|
|
|
|
|
|
- m_audioPacketQueue = av::utils::PacketQueueFactory::createStandardQueue(1000); // 音频包队列
|
|
|
+ m_audioPacketQueue = av::utils::PacketQueueFactory::createHighCapacityQueue(2000); // 音频包队列,增大容量
|
|
|
if (!m_audioPacketQueue) {
|
|
|
Logger::instance().error("Failed to create audio packet queue");
|
|
|
setState(PlayerState::Error);
|
|
|
return;
|
|
|
}
|
|
|
+ // 禁用丢包策略
|
|
|
+ m_audioPacketQueue->setDropPolicy(false, true);
|
|
|
|
|
|
- m_videoFrameQueue = av::utils::FrameQueueFactory::createStandardQueue(50); // 增加视频帧队列
|
|
|
+ m_videoFrameQueue = av::utils::FrameQueueFactory::createHighCapacityQueue(100); // 增加视频帧队列容量并禁用丢帧
|
|
|
if (!m_videoFrameQueue) {
|
|
|
Logger::instance().error("Failed to create video frame queue");
|
|
|
setState(PlayerState::Error);
|
|
|
return;
|
|
|
}
|
|
|
+ // 禁用丢帧策略
|
|
|
+ m_videoFrameQueue->setDropPolicy(false, true);
|
|
|
|
|
|
- m_audioFrameQueue = av::utils::FrameQueueFactory::createStandardQueue(200); // 增加音频帧队列
|
|
|
+ m_audioFrameQueue = av::utils::FrameQueueFactory::createHighCapacityQueue(400); // 增加音频帧队列容量并禁用丢帧
|
|
|
if (!m_audioFrameQueue) {
|
|
|
Logger::instance().error("Failed to create audio frame queue");
|
|
|
setState(PlayerState::Error);
|
|
|
return;
|
|
|
}
|
|
|
+ // 禁用丢帧策略
|
|
|
+ m_audioFrameQueue->setDropPolicy(false, true);
|
|
|
|
|
|
// 创建改进的同步器
|
|
|
- // m_synchronizer = std::make_unique<Synchronizer>(syncConfig);
|
|
|
- // if (!m_synchronizer) {
|
|
|
- // Logger::instance().error("Failed to create synchronizer");
|
|
|
- // setState(PlayerState::Error);
|
|
|
- // return;
|
|
|
- // }
|
|
|
+ m_synchronizer = std::make_unique<SynchronizerV2>(syncConfig);
|
|
|
+ if (!m_synchronizer) {
|
|
|
+ Logger::instance().error("Failed to create synchronizer");
|
|
|
+ setState(PlayerState::Error);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
// 设置同步器回调
|
|
|
- // m_synchronizer->setSyncErrorCallback([this](double error, const std::string& reason) {
|
|
|
- // handleSyncError(error, reason);
|
|
|
- // });
|
|
|
-
|
|
|
- // m_synchronizer->setFrameDropCallback([this](av::utils::ClockType type, int64_t pts) {
|
|
|
- // std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
- // m_stats.droppedFrames++;
|
|
|
- // if (m_eventCallback) {
|
|
|
- // m_eventCallback->onFrameDropped(m_stats.droppedFrames);
|
|
|
- // }
|
|
|
- // });
|
|
|
+ m_synchronizer->setSyncErrorCallback([this](double error, const std::string& reason) {
|
|
|
+ handleSyncError(error, reason);
|
|
|
+ });
|
|
|
+
|
|
|
+ m_synchronizer->setFrameDropCallback([this](av::utils::ClockType type, int64_t pts) {
|
|
|
+ std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
+ m_stats.droppedFrames++;
|
|
|
+ if (m_eventCallback) {
|
|
|
+ m_eventCallback->onFrameDropped(m_stats.droppedFrames);
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
// 创建解码器
|
|
|
m_videoDecoder = std::make_unique<VideoDecoder>();
|
|
|
@@ -240,10 +248,10 @@ ErrorCode PlayerCoreV2::play() {
|
|
|
}
|
|
|
|
|
|
// 启动同步器
|
|
|
- // if (m_synchronizer->start() != ErrorCode::SUCCESS) {
|
|
|
- // Logger::instance().error("Failed to start synchronizer");
|
|
|
- // return ErrorCode::SYNC_ERROR;
|
|
|
- // }
|
|
|
+ if (m_synchronizer && m_synchronizer->start() != ErrorCode::SUCCESS) {
|
|
|
+ Logger::instance().error("Failed to start synchronizer");
|
|
|
+ return ErrorCode::SYNC_ERROR;
|
|
|
+ }
|
|
|
|
|
|
// 记录播放开始时间
|
|
|
m_playStartTime = std::chrono::steady_clock::now();
|
|
|
@@ -299,12 +307,12 @@ ErrorCode PlayerCoreV2::play() {
|
|
|
return ErrorCode::THREAD_ERROR;
|
|
|
}
|
|
|
|
|
|
- if (m_mediaInfo.hasVideo && !startVideoPlayThread()) {
|
|
|
+ if (m_mediaInfo.hasVideo && m_videoStreamEnabled && !startVideoPlayThread()) {
|
|
|
Logger::instance().error("Failed to start video play thread");
|
|
|
return ErrorCode::THREAD_ERROR;
|
|
|
}
|
|
|
|
|
|
- if (m_mediaInfo.hasAudio && !startAudioPlayThread()) {
|
|
|
+ if (m_mediaInfo.hasAudio && m_audioStreamEnabled && !startAudioPlayThread()) {
|
|
|
Logger::instance().error("Failed to start audio play thread");
|
|
|
return ErrorCode::THREAD_ERROR;
|
|
|
}
|
|
|
@@ -324,10 +332,10 @@ ErrorCode PlayerCoreV2::pause() {
|
|
|
return ErrorCode::INVALID_STATE;
|
|
|
}
|
|
|
|
|
|
- // // 暂停同步器
|
|
|
- // if (m_synchronizer->pause() != ErrorCode::SUCCESS) {
|
|
|
- // Logger::instance().warning("Failed to pause synchronizer");
|
|
|
- // }
|
|
|
+ // 暂停同步器
|
|
|
+ if (m_synchronizer && m_synchronizer->pause() != ErrorCode::SUCCESS) {
|
|
|
+ Logger::instance().warning("Failed to pause synchronizer");
|
|
|
+ }
|
|
|
|
|
|
// 记录暂停时的播放时间
|
|
|
if (m_playStartTime.time_since_epoch().count() != 0) {
|
|
|
@@ -356,10 +364,10 @@ ErrorCode PlayerCoreV2::stop() {
|
|
|
return ErrorCode::SUCCESS;
|
|
|
}
|
|
|
|
|
|
- // // 停止同步器
|
|
|
- // if (m_synchronizer) {
|
|
|
- // m_synchronizer->stop();
|
|
|
- // }
|
|
|
+ // 停止同步器
|
|
|
+ if (m_synchronizer) {
|
|
|
+ m_synchronizer->stop();
|
|
|
+ }
|
|
|
|
|
|
// 停止音频输出
|
|
|
if (m_audioOutput) {
|
|
|
@@ -410,10 +418,10 @@ ErrorCode PlayerCoreV2::seek(int64_t timestamp) {
|
|
|
m_baseTime = timestamp;
|
|
|
m_playStartTime = std::chrono::steady_clock::now();
|
|
|
|
|
|
- // // 重置同步器
|
|
|
- // if (m_synchronizer) {
|
|
|
- // m_synchronizer->reset();
|
|
|
- // }
|
|
|
+ // 重置同步器
|
|
|
+ if (m_synchronizer) {
|
|
|
+ m_synchronizer->reset();
|
|
|
+ }
|
|
|
|
|
|
// 清空队列
|
|
|
flushBuffers();
|
|
|
@@ -436,10 +444,10 @@ ErrorCode PlayerCoreV2::setPlaybackSpeed(double speed) {
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
m_playbackSpeed = speed;
|
|
|
|
|
|
- // // 设置同步器的播放速度
|
|
|
- // if (m_synchronizer) {
|
|
|
- // m_synchronizer->setPlaybackSpeed(speed);
|
|
|
- // }
|
|
|
+ // 设置同步器的播放速度
|
|
|
+ if (m_synchronizer) {
|
|
|
+ m_synchronizer->setPlaybackSpeed(speed);
|
|
|
+ }
|
|
|
|
|
|
// 设置音频输出的播放速度
|
|
|
if (m_audioOutput) {
|
|
|
@@ -471,15 +479,15 @@ PlaybackStats PlayerCoreV2::getStats() const {
|
|
|
if (m_videoFrameQueue) stats.queuedVideoFrames = m_videoFrameQueue->size();
|
|
|
if (m_audioFrameQueue) stats.queuedAudioFrames = m_audioFrameQueue->size();
|
|
|
|
|
|
- // // 更新同步统计
|
|
|
- // if (m_synchronizer) {
|
|
|
- // auto syncStats = m_synchronizer->getStats();
|
|
|
- // stats.syncError = syncStats.syncError;
|
|
|
- // // stats.avgSyncError = syncStats.avgSyncError;
|
|
|
- // // stats.maxSyncError = syncStats.maxSyncError;
|
|
|
- // stats.droppedFrames = syncStats.droppedFrames;
|
|
|
- // stats.duplicatedFrames = syncStats.duplicatedFrames;
|
|
|
- // }
|
|
|
+ // 更新同步统计
|
|
|
+ if (m_synchronizer) {
|
|
|
+ auto syncStats = m_synchronizer->getStats();
|
|
|
+ stats.syncError = syncStats.audioVideoSyncError;
|
|
|
+ stats.avgSyncError = syncStats.avgSyncError;
|
|
|
+ stats.maxSyncError = syncStats.maxSyncError;
|
|
|
+ stats.droppedFrames = syncStats.droppedFrames;
|
|
|
+ stats.duplicatedFrames = syncStats.duplicatedFrames;
|
|
|
+ }
|
|
|
|
|
|
return stats;
|
|
|
}
|
|
|
@@ -520,18 +528,79 @@ void PlayerCoreV2::setVolume(double volume) {
|
|
|
Logger::instance().debug("Volume set to: " + std::to_string(volume));
|
|
|
}
|
|
|
|
|
|
-// void PlayerCore::setSyncConfig(const SyncConfig& config) {
|
|
|
-// // if (m_synchronizer) {
|
|
|
-// // m_synchronizer->setConfig(config);
|
|
|
-// // }
|
|
|
-// }
|
|
|
+// 流控制接口实现
|
|
|
+void PlayerCoreV2::enableVideoStream(bool enable) {
|
|
|
+ if (m_videoStreamEnabled == enable) {
|
|
|
+ return; // 状态未变,不需要处理
|
|
|
+ }
|
|
|
+
|
|
|
+ m_videoStreamEnabled = enable;
|
|
|
+ Logger::instance().info("Video stream " + std::string(enable ? "enabled" : "disabled"));
|
|
|
+
|
|
|
+ // 如果播放器已经打开文件,需要更新同步器的流信息
|
|
|
+ if (m_formatContext && m_synchronizer) {
|
|
|
+ bool useAudio = m_mediaInfo.hasAudio && m_audioStreamEnabled;
|
|
|
+ bool useVideo = m_mediaInfo.hasVideo && m_videoStreamEnabled;
|
|
|
+ m_synchronizer->setStreamInfo(useAudio, useVideo);
|
|
|
+
|
|
|
+ // 如果正在播放,需要重新启动播放
|
|
|
+ if (m_state == PlayerState::Playing || m_state == PlayerState::Paused) {
|
|
|
+ // 停止当前播放
|
|
|
+ PlayerState oldState = m_state;
|
|
|
+ stop();
|
|
|
+ // 重新开始播放
|
|
|
+ openFile(m_mediaInfo.filename);
|
|
|
+ if (oldState == PlayerState::Playing) {
|
|
|
+ play();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void PlayerCoreV2::enableAudioStream(bool enable) {
|
|
|
+ if (m_audioStreamEnabled == enable) {
|
|
|
+ return; // 状态未变,不需要处理
|
|
|
+ }
|
|
|
+
|
|
|
+ m_audioStreamEnabled = enable;
|
|
|
+ Logger::instance().info("Audio stream " + std::string(enable ? "enabled" : "disabled"));
|
|
|
+
|
|
|
+ // 如果播放器已经打开文件,需要更新同步器的流信息
|
|
|
+ if (m_formatContext && m_synchronizer) {
|
|
|
+ bool useAudio = m_mediaInfo.hasAudio && m_audioStreamEnabled;
|
|
|
+ bool useVideo = m_mediaInfo.hasVideo && m_videoStreamEnabled;
|
|
|
+ m_synchronizer->setStreamInfo(useAudio, useVideo);
|
|
|
+
|
|
|
+ // 如果正在播放,需要重新启动播放
|
|
|
+ if (m_state == PlayerState::Playing) {
|
|
|
+ // 暂停当前播放
|
|
|
+ pause();
|
|
|
+ // 重新开始播放
|
|
|
+ play();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool PlayerCoreV2::isVideoStreamEnabled() const {
|
|
|
+ return m_videoStreamEnabled;
|
|
|
+}
|
|
|
+
|
|
|
+bool PlayerCoreV2::isAudioStreamEnabled() const {
|
|
|
+ return m_audioStreamEnabled;
|
|
|
+}
|
|
|
+
|
|
|
+void PlayerCoreV2::setSyncConfig(const SyncConfigV2& config) {
|
|
|
+ if (m_synchronizer) {
|
|
|
+ m_synchronizer->setConfig(config);
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-// SyncConfig PlayerCoreV2::getSyncConfig() const {
|
|
|
-// if (m_synchronizer) {
|
|
|
-// return m_synchronizer->getConfig();
|
|
|
-// }
|
|
|
-// return SyncConfig();
|
|
|
-// }
|
|
|
+SyncConfigV2 PlayerCoreV2::getSyncConfig() const {
|
|
|
+ if (m_synchronizer) {
|
|
|
+ return m_synchronizer->getConfig();
|
|
|
+ }
|
|
|
+ return SyncConfigV2();
|
|
|
+}
|
|
|
|
|
|
void PlayerCoreV2::setOpenGLVideoRenderer(OpenGLVideoWidget* renderer) {
|
|
|
m_openGLVideoRenderer = renderer;
|
|
|
@@ -605,9 +674,9 @@ std::string PlayerCoreV2::getDebugInfo() const {
|
|
|
oss << " Volume: " << m_volume << "\n";
|
|
|
oss << " Error Count: " << m_errorCount << "\n";
|
|
|
|
|
|
- // if (m_synchronizer) {
|
|
|
- // oss << "\n" << m_synchronizer->getDebugInfo();
|
|
|
- // }
|
|
|
+ if (m_synchronizer) {
|
|
|
+ oss << "\n" << m_synchronizer->getDebugInfo();
|
|
|
+ }
|
|
|
|
|
|
return oss.str();
|
|
|
}
|
|
|
@@ -704,19 +773,21 @@ bool PlayerCoreV2::openMediaFile(const std::string& filename) {
|
|
|
std::to_string(m_mediaInfo.channels) + " channels");
|
|
|
}
|
|
|
|
|
|
- // // 设置同步器的流信息
|
|
|
- // if (m_synchronizer) {
|
|
|
- // m_synchronizer->setStreamInfo(m_mediaInfo.hasAudio, m_mediaInfo.hasVideo);
|
|
|
- // Logger::instance().info("Synchronizer stream info set: hasAudio=" + std::to_string(m_mediaInfo.hasAudio) +
|
|
|
- // ", hasVideo=" + std::to_string(m_mediaInfo.hasVideo));
|
|
|
-
|
|
|
- // // 在设置流信息后初始化同步器,确保主时钟选择基于正确的流信息
|
|
|
- // if (m_synchronizer->initialize() != ErrorCode::SUCCESS) {
|
|
|
- // Logger::instance().error("Failed to initialize synchronizer");
|
|
|
- // return false;
|
|
|
- // }
|
|
|
- // Logger::instance().info("Synchronizer initialized with correct stream info");
|
|
|
- // }
|
|
|
+ // 设置同步器的流信息
|
|
|
+ if (m_synchronizer) {
|
|
|
+ bool useAudio = m_mediaInfo.hasAudio && m_audioStreamEnabled;
|
|
|
+ bool useVideo = m_mediaInfo.hasVideo && m_videoStreamEnabled;
|
|
|
+ m_synchronizer->setStreamInfo(useAudio, useVideo);
|
|
|
+ Logger::instance().info("Synchronizer stream info set: hasAudio=" + std::to_string(useAudio) +
|
|
|
+ ", hasVideo=" + std::to_string(useVideo));
|
|
|
+
|
|
|
+ // 在设置流信息后初始化同步器,确保主时钟选择基于正确的流信息
|
|
|
+ if (m_synchronizer->initialize() != ErrorCode::SUCCESS) {
|
|
|
+ Logger::instance().error("Failed to initialize synchronizer");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Logger::instance().info("Synchronizer initialized with correct stream info");
|
|
|
+ }
|
|
|
|
|
|
Logger::instance().info("Media file opened successfully: " + filename);
|
|
|
return true;
|
|
|
@@ -1000,12 +1071,22 @@ void PlayerCoreV2::handleError(const std::string& error) {
|
|
|
}
|
|
|
|
|
|
void PlayerCoreV2::updateSynchronization() {
|
|
|
- // if (!m_synchronizer || !m_threadsRunning) {
|
|
|
- // return;
|
|
|
- // }
|
|
|
+ if (!m_synchronizer || !m_threadsRunning) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
// 同步器会在内部自动更新
|
|
|
- // 这里可以添加额外的同步逻辑
|
|
|
+ // 更新同步器统计信息
|
|
|
+ //m_synchronizer->updateStats();
|
|
|
+
|
|
|
+ // 获取同步器统计信息并更新播放器统计
|
|
|
+ std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
+ auto syncStats = m_synchronizer->getStats();
|
|
|
+ m_stats.syncError = syncStats.audioVideoSyncError;
|
|
|
+ m_stats.avgSyncError = syncStats.avgSyncError;
|
|
|
+ m_stats.maxSyncError = syncStats.maxSyncError;
|
|
|
+ m_stats.droppedFrames = syncStats.droppedFrames;
|
|
|
+ m_stats.duplicatedFrames = syncStats.duplicatedFrames;
|
|
|
}
|
|
|
|
|
|
void PlayerCoreV2::updateStats() {
|
|
|
@@ -1120,11 +1201,16 @@ void PlayerCoreV2::readThreadFunc() {
|
|
|
m_seekCondition.notify_all();
|
|
|
}
|
|
|
|
|
|
- // 检查队列是否已满
|
|
|
- bool videoQueueFull = m_videoPacketQueue && m_videoPacketQueue->size() > 500;
|
|
|
- bool audioQueueFull = m_audioPacketQueue && m_audioPacketQueue->size() > 500;
|
|
|
- if (videoQueueFull && audioQueueFull) {
|
|
|
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
|
+ // 检查队列是否接近容量上限 - 使用队列容量的90%作为警告阈值,但不丢弃包
|
|
|
+ bool videoQueueNearFull = m_videoPacketQueue && m_videoPacketQueue->size() > 1800; // 2000的90%
|
|
|
+ bool audioQueueNearFull = m_audioPacketQueue && m_audioPacketQueue->size() > 1800; // 2000的90%
|
|
|
+ if (videoQueueNearFull || audioQueueNearFull) {
|
|
|
+ // 队列接近满,暂停一段时间让解码线程处理
|
|
|
+ Logger::instance().warning("Packet queue is getting large: Video=" +
|
|
|
+ std::to_string(m_videoPacketQueue ? m_videoPacketQueue->size() : 0) +
|
|
|
+ ", Audio=" + std::to_string(m_audioPacketQueue ? m_audioPacketQueue->size() : 0) +
|
|
|
+ ". Slowing down read thread.");
|
|
|
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
@@ -1165,28 +1251,38 @@ void PlayerCoreV2::readThreadFunc() {
|
|
|
}
|
|
|
|
|
|
// 根据流索引将数据包分发到对应队列
|
|
|
- if (packet->stream_index == m_mediaInfo.videoStreamIndex) {
|
|
|
- // 视频包放入视频队列
|
|
|
- if (m_videoPacketQueue && (!videoQueueFull || m_videoPacketQueue->size() < 500)) {
|
|
|
+ if (packet->stream_index == m_mediaInfo.videoStreamIndex && m_videoStreamEnabled) {
|
|
|
+ // 视频包放入视频队列 - 不考虑队列是否已满,确保不丢包
|
|
|
+ if (m_videoPacketQueue) {
|
|
|
AVPacket* packetCopy = av_packet_alloc();
|
|
|
if (packetCopy && av_packet_ref(packetCopy, packet) == 0) {
|
|
|
m_videoPacketQueue->push(packetCopy);
|
|
|
+
|
|
|
+ // 记录队列大小,用于监控
|
|
|
+ if (m_videoPacketQueue->size() % 100 == 0) {
|
|
|
+ Logger::instance().debug("Video packet queue size: " + std::to_string(m_videoPacketQueue->size()));
|
|
|
+ }
|
|
|
} else {
|
|
|
av_packet_free(&packetCopy);
|
|
|
}
|
|
|
}
|
|
|
- } else if (packet->stream_index == m_mediaInfo.audioStreamIndex) {
|
|
|
- // 音频包放入音频队列
|
|
|
- if (m_audioPacketQueue && (!audioQueueFull || m_audioPacketQueue->size() < 500)) {
|
|
|
+ } else if (packet->stream_index == m_mediaInfo.audioStreamIndex && m_audioStreamEnabled) {
|
|
|
+ // 音频包放入音频队列 - 不考虑队列是否已满,确保不丢包
|
|
|
+ if (m_audioPacketQueue) {
|
|
|
AVPacket* packetCopy = av_packet_alloc();
|
|
|
if (packetCopy && av_packet_ref(packetCopy, packet) == 0) {
|
|
|
m_audioPacketQueue->push(packetCopy);
|
|
|
+
|
|
|
+ // 记录队列大小,用于监控
|
|
|
+ if (m_audioPacketQueue->size() % 100 == 0) {
|
|
|
+ Logger::instance().debug("Audio packet queue size: " + std::to_string(m_audioPacketQueue->size()));
|
|
|
+ }
|
|
|
} else {
|
|
|
av_packet_free(&packetCopy);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
av_packet_unref(packet);
|
|
|
}
|
|
|
|
|
|
@@ -1270,14 +1366,16 @@ void PlayerCoreV2::videoDecodeThreadFunc() {
|
|
|
Logger::instance().debug("Frame PTS: " + std::to_string(framePtr->pts));
|
|
|
}
|
|
|
|
|
|
- // 将帧放入队列
|
|
|
- if (m_videoFrameQueue->size() < 30) { // 限制队列大小
|
|
|
- // 释放智能指针的所有权,让队列管理帧的生命周期
|
|
|
- m_videoFrameQueue->push(framePtr.release());
|
|
|
- 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");
|
|
|
+ // 将帧放入队列 - 不丢弃任何帧
|
|
|
+ // 释放智能指针的所有权,让队列管理帧的生命周期
|
|
|
+ m_videoFrameQueue->push(framePtr.release());
|
|
|
+ m_frameCount++;
|
|
|
+ Logger::instance().debug("Video frame pushed to queue, queue size: " + std::to_string(m_videoFrameQueue->size()));
|
|
|
+
|
|
|
+ // 如果队列大小超过警告阈值,记录警告但不丢弃
|
|
|
+ if (m_videoFrameQueue->size() > 80) {
|
|
|
+ Logger::instance().warning("Video frame queue is getting large: " + std::to_string(m_videoFrameQueue->size()) +
|
|
|
+ " frames. Performance may be affected.");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -1366,13 +1464,15 @@ void PlayerCoreV2::audioDecodeThreadFunc() {
|
|
|
Logger::instance().debug("Audio Frame PTS: " + std::to_string(framePtr->pts));
|
|
|
}
|
|
|
|
|
|
- // 将帧放入队列
|
|
|
- if (m_audioFrameQueue->size() < 100) { // 限制队列大小
|
|
|
- // 释放智能指针的所有权,让队列管理帧的生命周期
|
|
|
- m_audioFrameQueue->push(framePtr.release());
|
|
|
- Logger::instance().debug("Audio frame pushed to queue, queue size: " + std::to_string(m_audioFrameQueue->size()));
|
|
|
- } else {
|
|
|
- Logger::instance().warning("Audio frame queue full, dropping frame");
|
|
|
+ // 将帧放入队列 - 不丢弃任何帧
|
|
|
+ // 释放智能指针的所有权,让队列管理帧的生命周期
|
|
|
+ m_audioFrameQueue->push(framePtr.release());
|
|
|
+ Logger::instance().debug("Audio frame pushed to queue, queue size: " + std::to_string(m_audioFrameQueue->size()));
|
|
|
+
|
|
|
+ // 如果队列大小超过警告阈值,记录警告但不丢弃
|
|
|
+ if (m_audioFrameQueue->size() > 300) {
|
|
|
+ Logger::instance().warning("Audio frame queue is getting large: " + std::to_string(m_audioFrameQueue->size()) +
|
|
|
+ " frames. Performance may be affected.");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -1390,8 +1490,11 @@ void PlayerCoreV2::audioDecodeThreadFunc() {
|
|
|
void PlayerCoreV2::videoPlayThreadFunc() {
|
|
|
Logger::instance().info("Video play thread started");
|
|
|
|
|
|
+ // 用于计算帧持续时间的变量
|
|
|
+ AVFrame* lastFrame = nullptr;
|
|
|
+
|
|
|
while (!m_threadsShouldStop) {
|
|
|
- if (!m_videoFrameQueue /*|| !m_synchronizer*/) {
|
|
|
+ if (!m_videoFrameQueue || !m_synchronizer) {
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
|
continue;
|
|
|
}
|
|
|
@@ -1408,32 +1511,69 @@ void PlayerCoreV2::videoPlayThreadFunc() {
|
|
|
|
|
|
Logger::instance().debug("Video play thread got frame, pts=" + std::to_string(frame->pts));
|
|
|
|
|
|
- // 尝试获取下一帧的PTS来计算精确的帧持续时间
|
|
|
- double nextPts = AV_NOPTS_VALUE;
|
|
|
- if (m_videoFrameQueue->size() > 0) {
|
|
|
- AVFrame* nextFrame = m_videoFrameQueue->peekFrame();
|
|
|
- if (nextFrame && nextFrame->pts != AV_NOPTS_VALUE) {
|
|
|
- nextPts = nextFrame->pts;
|
|
|
+ // 创建智能指针管理帧内存
|
|
|
+ AVFramePtr framePtr(frame);
|
|
|
+
|
|
|
+ // 使用同步器计算视频帧显示时间
|
|
|
+ double pts = frame->pts * av_q2d(m_formatContext->streams[m_mediaInfo.videoStreamIndex]->time_base);
|
|
|
+
|
|
|
+ // 更新视频时钟
|
|
|
+ m_synchronizer->setClock(av::utils::ClockType::VIDEO, pts, 0);
|
|
|
+
|
|
|
+ // 计算帧持续时间
|
|
|
+ double last_duration = 0.0;
|
|
|
+ if (lastFrame && lastFrame->pts != AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE) {
|
|
|
+ // 计算两帧之间的时间差
|
|
|
+ double last_pts = lastFrame->pts * av_q2d(m_formatContext->streams[m_mediaInfo.videoStreamIndex]->time_base);
|
|
|
+ last_duration = pts - last_pts;
|
|
|
+ if (last_duration < 0 || last_duration > 10.0) {
|
|
|
+ // 如果持续时间不合理,使用帧率的倒数作为默认值
|
|
|
+ last_duration = 1.0 / m_mediaInfo.fps;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ // 如果没有上一帧,使用帧率的倒数作为默认值
|
|
|
+ last_duration = 1.0 / m_mediaInfo.fps;
|
|
|
}
|
|
|
+
|
|
|
+ // 计算视频帧延迟并决定是否显示
|
|
|
+ FrameDecision decision = m_synchronizer->synchronizeVideo(pts, 0, last_duration);
|
|
|
|
|
|
- // 创建智能指针管理帧内存
|
|
|
- AVFramePtr framePtr(frame);
|
|
|
- // 显示帧
|
|
|
- if (m_openGLVideoRenderer) {
|
|
|
- m_openGLVideoRenderer->Render(framePtr.get());
|
|
|
+ if (decision.action == FrameAction::DISPLAY) {
|
|
|
+ // 如果需要延迟显示,等待指定时间
|
|
|
+ if (decision.delay > 0.0) {
|
|
|
+ std::this_thread::sleep_for(std::chrono::microseconds(static_cast<int64_t>(decision.delay * 1000000)));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 显示帧
|
|
|
+ if (m_openGLVideoRenderer) {
|
|
|
+ m_openGLVideoRenderer->Render(framePtr.get());
|
|
|
+ Logger::instance().debug("Video frame displayed, pts=" + std::to_string(pts) + ", delay=" + std::to_string(decision.delay));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新上一帧指针
|
|
|
+ if (lastFrame) {
|
|
|
+ av_frame_free(&lastFrame);
|
|
|
+ }
|
|
|
+ lastFrame = av_frame_clone(frame);
|
|
|
+ } else if (decision.action == FrameAction::DROP) {
|
|
|
+ Logger::instance().debug("Video frame dropped due to sync, pts=" + std::to_string(pts) + ", error=" + std::to_string(decision.syncError));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // 清理最后一帧
|
|
|
+ if (lastFrame) {
|
|
|
+ av_frame_free(&lastFrame);
|
|
|
+ }
|
|
|
+
|
|
|
Logger::instance().info("Video play thread finished");
|
|
|
}
|
|
|
|
|
|
void PlayerCoreV2::audioPlayThreadFunc() {
|
|
|
Logger::instance().info("Audio play thread started");
|
|
|
-
|
|
|
+
|
|
|
int frameCount = 0;
|
|
|
while (!m_threadsShouldStop) {
|
|
|
- if (!m_audioFrameQueue || /* !m_synchronizer ||*/ !m_audioOutput) {
|
|
|
+ if (!m_audioFrameQueue || !m_synchronizer || !m_audioOutput) {
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
|
continue;
|
|
|
}
|
|
|
@@ -1447,25 +1587,44 @@ void PlayerCoreV2::audioPlayThreadFunc() {
|
|
|
}
|
|
|
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++;
|
|
|
- Logger::instance().debug("Audio play thread got frame #" + std::to_string(frameCount) +
|
|
|
- ", pts=" + std::to_string(frame->pts) +
|
|
|
- ", nb_samples=" + std::to_string(frame->nb_samples));
|
|
|
+ Logger::instance().debug("Audio play thread got frame #" + std::to_string(frameCount)
|
|
|
+ + ", pts=" + std::to_string(frame->pts)
|
|
|
+ + ", nb_samples=" + std::to_string(frame->nb_samples));
|
|
|
|
|
|
// 创建智能指针管理帧内存
|
|
|
AVFramePtr framePtr(frame);
|
|
|
+
|
|
|
+ // 计算音频PTS
|
|
|
+ double pts = frame->pts
|
|
|
+ * av_q2d(m_formatContext->streams[m_mediaInfo.audioStreamIndex]->time_base);
|
|
|
+
|
|
|
+ // 更新音频时钟
|
|
|
+ m_synchronizer->setClock(av::utils::ClockType::AUDIO, pts, 0);
|
|
|
+
|
|
|
+ // 同步音频样本数量
|
|
|
+ int originalSamples = frame->nb_samples;
|
|
|
+ int adjustedSamples = m_synchronizer->synchronizeAudio((short*) frame->data[0],
|
|
|
+ frame->nb_samples,
|
|
|
+ pts);
|
|
|
+
|
|
|
+ if (adjustedSamples != originalSamples) {
|
|
|
+ Logger::instance().debug("Audio samples adjusted from " + std::to_string(originalSamples)
|
|
|
+ + " to " + std::to_string(adjustedSamples) + " for sync");
|
|
|
+ }
|
|
|
+
|
|
|
{
|
|
|
Logger::instance().debug("Writing audio frame to output device");
|
|
|
bool writeResult = m_audioOutput->writeFrame(framePtr);
|
|
|
@@ -1480,8 +1639,9 @@ void PlayerCoreV2::audioPlayThreadFunc() {
|
|
|
|
|
|
// 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));
|
|
|
}
|
|
|
|
|
|
} // namespace player
|