zhuizhu 8 hónapja
szülő
commit
f88ec8c813

+ 3 - 0
AV/code/codec/codec_video_decoder.cpp

@@ -129,6 +129,9 @@ ErrorCode VideoDecoder::flush() {
     
     if (codecCtx_) {
         avcodec_flush_buffers(codecCtx_.get());
+        
+        // 视频解码器flush完成,解码器状态已重置
+        AV_LOGGER_DEBUG("视频解码器缓冲区已清空");
     }
     
     setState(CodecState::OPENED);

+ 3 - 1
AV/code/codec/codec_video_decoder.h

@@ -112,9 +112,11 @@ private:
     AVBufferRef* hwDeviceCtx_ = nullptr;
     AVFramePtr hwFrame_;
     
-    // 硬件加速
+    // 硬件加速相关
     bool isHardwareDecoder_ = false;
     
+
+    
     // 线程安全
     mutable std::mutex decodeMutex_;
     

+ 75 - 26
AV/code/player/player_core_v2.cpp

@@ -8,6 +8,7 @@
 #include <chrono>
 #include <thread>
 #include <algorithm>
+#include <cmath>
 
 #ifdef _WIN32
 #include <windows.h>
@@ -410,8 +411,11 @@ ErrorCode PlayerCoreV2::seek(int64_t timestamp) {
     
     std::unique_lock<std::mutex> lock(m_seekMutex);
     
-    // 设置seek目标
+    // 设置seek目标和精确范围参数
     m_seekTarget = timestamp;
+    m_seekMinTime = INT64_MIN;  // 允许向前跳转的最小时间
+    m_seekMaxTime = INT64_MAX;  // 允许向后跳转的最大时间
+    m_seekFlags = AVSEEK_FLAG_BACKWARD;  // 默认向后跳转到关键帧
     m_seeking = true;
     
     // 更新基准时间为跳转目标时间
@@ -431,7 +435,7 @@ ErrorCode PlayerCoreV2::seek(int64_t timestamp) {
     // 通知seek条件
     m_seekCondition.notify_all();
     
-    Logger::instance().info("Seek initiated");
+    Logger::instance().info("Precise seek initiated with avformat_seek_file support");
     return ErrorCode::SUCCESS;
 }
 
@@ -497,19 +501,32 @@ int64_t PlayerCoreV2::getCurrentTime() const {
         return 0;
     }
     
-    if (m_state == PlayerState::Paused) {
-        return m_baseTime;
-    }
-    
-    if (m_playStartTime.time_since_epoch().count() == 0) {
-        return m_baseTime;
+    // 如果同步器可用,尝试使用主时钟的播放时间
+    if (m_synchronizer) {
+        // 获取主时钟时间(秒),转换为微秒
+        double masterClockTime = m_synchronizer->getMasterClock();
+        // 确保时间值合理(非负且不是NaN)
+        if (masterClockTime >= 0.0 && !std::isnan(masterClockTime)) {
+            return static_cast<int64_t>(masterClockTime * 1000000);
+        }
     }
-    
-    auto currentTime = std::chrono::steady_clock::now();
-    auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(
-        currentTime - m_playStartTime).count();
-    
-    return m_baseTime + static_cast<int64_t>(elapsed * m_playbackSpeed);
+
+    return 0;
+
+    // // 回退到原来的计算方式(兼容性保证)
+    // if (m_state == PlayerState::Paused) {
+    //     return m_baseTime;
+    // }
+
+    // if (m_playStartTime.time_since_epoch().count() == 0) {
+    //     return m_baseTime;
+    // }
+
+    // auto currentTime = std::chrono::steady_clock::now();
+    // auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(
+    //     currentTime - m_playStartTime).count();
+
+    // return m_baseTime + static_cast<int64_t>(elapsed * m_playbackSpeed);
 }
 
 double PlayerCoreV2::getPlaybackSpeed() const {
@@ -1190,20 +1207,45 @@ void PlayerCoreV2::readThreadFunc() {
         if (m_seeking) {
             std::unique_lock<std::mutex> lock(m_seekMutex);
             
-            // 执行seek操作
+            // 获取seek参数
+            int64_t seekMinTime = m_seekMinTime;
             int64_t seekTarget = m_seekTarget;
-            int flags = AVSEEK_FLAG_BACKWARD;
+            int64_t seekMaxTime = m_seekMaxTime;
+            int flags = m_seekFlags;
+
+            Logger::instance().info("Performing precise seek - min: " + std::to_string(seekMinTime) + 
+                                   ", target: " + std::to_string(seekTarget) + 
+                                   ", max: " + std::to_string(seekMaxTime) + 
+                                   ", flags: " + std::to_string(flags));
+
+            // 首先尝试定位到最近的关键帧以确保视频解码正常
+            int ret = av_seek_frame(m_formatContext, -1, seekTarget, AVSEEK_FLAG_BACKWARD);
+            if (ret < 0) {
+                Logger::instance().warning("Video keyframe seek failed, trying precise seek");
+                // 如果关键帧定位失败,回退到精确seek
+                ret = avformat_seek_file(m_formatContext, -1, seekMinTime, seekTarget, seekMaxTime, flags);
+                if (ret < 0) {
+                    Logger::instance().error("All seek methods failed");
+                } else {
+                    Logger::instance().info("Fallback precise seek completed to: " + std::to_string(seekTarget));
+                }
+            } else {
+                Logger::instance().info("Keyframe seek completed successfully to target: " + std::to_string(seekTarget));
+            }
             
-            if (av_seek_frame(m_formatContext, -1, seekTarget, flags) < 0) {
-                Logger::instance().error("Seek failed");
+            // 清空缓冲区
+            flushBuffers();
+            
+            // 重置解码器
+            resetDecoders();
+
+            // 重置时间
+            if (flags & AVSEEK_FLAG_BYTE) {
+                m_synchronizer->setClock(av::utils::ClockType::EXTERNAL, NAN, 0);
             } else {
-                Logger::instance().info("Seek completed to: " + std::to_string(seekTarget));
-                
-                // 清空缓冲区
-                flushBuffers();
-                
-                // 重置解码器
-                resetDecoders();
+                m_synchronizer->setClock(av::utils::ClockType::EXTERNAL,
+                                         seekTarget / (double) AV_TIME_BASE,
+                                         0);
             }
             
             m_seeking = false;
@@ -1312,6 +1354,10 @@ void PlayerCoreV2::videoDecodeThreadFunc() {
             std::this_thread::sleep_for(std::chrono::milliseconds(10));
             continue;
         }
+        if (m_seeking) {
+            std::this_thread::sleep_for(std::chrono::milliseconds(10));
+            continue;
+        }
         Logger::instance().info("Video decode thread read Packet111");
         // 从视频包队列获取包
         AVPacket* packet = nullptr;
@@ -1413,7 +1459,10 @@ void PlayerCoreV2::audioDecodeThreadFunc() {
             std::this_thread::sleep_for(std::chrono::milliseconds(10));
             continue;
         }
-        
+        if (m_seeking) {
+            std::this_thread::sleep_for(std::chrono::milliseconds(10));
+            continue;
+        }
         // 从音频包队列获取包
         AVPacket* packet = nullptr;
         while (!m_threadsShouldStop && !packet) {

+ 3 - 0
AV/code/player/player_core_v2.h

@@ -287,6 +287,9 @@ private:
     
     // Seek控制
     std::atomic<int64_t> m_seekTarget{-1};
+    std::atomic<int64_t> m_seekMinTime{INT64_MIN};
+    std::atomic<int64_t> m_seekMaxTime{INT64_MAX};
+    std::atomic<int> m_seekFlags{AVSEEK_FLAG_BACKWARD};
     std::atomic<bool> m_seeking{false};
     std::mutex m_seekMutex;
     std::condition_variable m_seekCondition;

+ 5 - 4
AV/code/utils/utils_synchronizer_v2.cpp

@@ -162,10 +162,11 @@ ErrorCode SynchronizerV2::reset() {
     m_audioDiffAvgCount = 0;
     
     // 重置统计信息
-    std::lock_guard<std::mutex> statsLock(m_statsMutex);
-    m_stats = SyncStatsV2();
-    m_stats.playbackSpeed = m_playbackSpeed;
-    
+    {
+        std::lock_guard<std::mutex> statsLock(m_statsMutex);
+        m_stats = SyncStatsV2();
+        m_stats.playbackSpeed = m_playbackSpeed;
+    }
     return ErrorCode::SUCCESS;
 }
 

+ 139 - 7
AV/test_player_with_ui.cpp

@@ -335,6 +335,64 @@ private slots:
         out << "平均同步误差: " << (stats.avgSyncError * 1000) << " ms\n";
         out << "最大同步误差: " << (stats.maxSyncError * 1000) << " ms\n\n";
         
+        // 写入详细时钟信息
+        out << "=== 时钟信息 ===\n";
+        if (m_player) {
+            auto debugInfo = QString::fromStdString(m_player->getDebugInfo());
+            QStringList lines = debugInfo.split('\n');
+            
+            for (const QString& line : lines) {
+                if (line.trimmed().startsWith("Audio:")) {
+                    QStringList parts = line.split(":");
+                    if (parts.size() >= 2) {
+                        bool ok;
+                        double value = parts[1].trimmed().toDouble(&ok);
+                        if (ok) {
+                            out << "音频时钟: " << value << " 秒\n";
+                        }
+                    }
+                } else if (line.trimmed().startsWith("Video:")) {
+                    QStringList parts = line.split(":");
+                    if (parts.size() >= 2) {
+                        bool ok;
+                        double value = parts[1].trimmed().toDouble(&ok);
+                        if (ok) {
+                            out << "视频时钟: " << value << " 秒\n";
+                        }
+                    }
+                } else if (line.trimmed().startsWith("External:")) {
+                    QStringList parts = line.split(":");
+                    if (parts.size() >= 2) {
+                        bool ok;
+                        double value = parts[1].trimmed().toDouble(&ok);
+                        if (ok) {
+                            out << "外部时钟: " << value << " 秒\n";
+                        }
+                    }
+                } else if (line.trimmed().startsWith("Master:")) {
+                    QStringList parts = line.split(":");
+                    if (parts.size() >= 2) {
+                        bool ok;
+                        double value = parts[1].trimmed().toDouble(&ok);
+                        if (ok) {
+                            out << "主时钟: " << value << " 秒\n";
+                        }
+                    }
+                } else if (line.contains("Master Clock Type:")) {
+                    QStringList parts = line.split(":");
+                    if (parts.size() >= 2) {
+                        out << "主时钟类型: " << parts[1].trimmed() << "\n";
+                    }
+                } else if (line.contains("Sync Strategy:")) {
+                    QStringList parts = line.split(":");
+                    if (parts.size() >= 2) {
+                        out << "同步策略: " << parts[1].trimmed() << "\n";
+                    }
+                }
+            }
+        }
+        out << "\n";
+
         // 写入性能统计
         out << "=== 性能统计 ===\n";
         out << "CPU使用率: " << stats.cpuUsage << "%\n";
@@ -440,11 +498,85 @@ private slots:
                          .arg(stats.queuedAudioFrames)
                          .arg(stats.queuedPackets);
             
-            // 同步统计
-            statsText += QString("\n\n同步状态:\n当前误差: %1 ms\n平均误差: %2 ms\n最大误差: %3 ms")
-                         .arg(stats.syncError * 1000, 0, 'f', 1)
-                         .arg(stats.avgSyncError * 1000, 0, 'f', 1)
-                         .arg(stats.maxSyncError * 1000, 0, 'f', 1);
+            // 同步统计 - 获取更详细的同步信息
+            QString syncText = "\n\n同步状态:\n当前误差: %1 ms\n平均误差: %2 ms\n最大误差: %3 ms";
+            
+            // 如果播放器有同步器,获取详细的时钟信息
+            if (m_player) {
+                auto debugInfo = QString::fromStdString(m_player->getDebugInfo());
+                
+                // 解析调试信息中的时钟数据
+                QStringList lines = debugInfo.split('\n');
+                QString audioClockStr = "N/A", videoClockStr = "N/A", externalClockStr = "N/A", masterClockStr = "N/A";
+                QString masterTypeStr = "N/A", syncStrategyStr = "N/A";
+                
+                for (const QString& line : lines) {
+                    if (line.trimmed().startsWith("Audio:")) {
+                        QStringList parts = line.split(":");
+                        if (parts.size() >= 2) {
+                            bool ok;
+                            double value = parts[1].trimmed().toDouble(&ok);
+                            if (ok) {
+                                audioClockStr = QString::number(value, 'f', 3) + "s";
+                            }
+                        }
+                    } else if (line.trimmed().startsWith("Video:")) {
+                        QStringList parts = line.split(":");
+                        if (parts.size() >= 2) {
+                            bool ok;
+                            double value = parts[1].trimmed().toDouble(&ok);
+                            if (ok) {
+                                videoClockStr = QString::number(value, 'f', 3) + "s";
+                            }
+                        }
+                    } else if (line.trimmed().startsWith("External:")) {
+                        QStringList parts = line.split(":");
+                        if (parts.size() >= 2) {
+                            bool ok;
+                            double value = parts[1].trimmed().toDouble(&ok);
+                            if (ok) {
+                                externalClockStr = QString::number(value, 'f', 3) + "s";
+                            }
+                        }
+                    } else if (line.trimmed().startsWith("Master:")) {
+                        QStringList parts = line.split(":");
+                        if (parts.size() >= 2) {
+                            bool ok;
+                            double value = parts[1].trimmed().toDouble(&ok);
+                            if (ok) {
+                                masterClockStr = QString::number(value, 'f', 3) + "s";
+                            }
+                        }
+                    } else if (line.contains("Master Clock Type:")) {
+                        QStringList parts = line.split(":");
+                        if (parts.size() >= 2) {
+                            masterTypeStr = parts[1].trimmed();
+                        }
+                    } else if (line.contains("Sync Strategy:")) {
+                        QStringList parts = line.split(":");
+                        if (parts.size() >= 2) {
+                            syncStrategyStr = parts[1].trimmed();
+                        }
+                    }
+                }
+                
+                syncText = QString("\n\n同步状态:\n当前误差: %1 ms\n平均误差: %2 ms\n最大误差: %3 ms\n\n时钟信息:\n音频时钟: %4\n视频时钟: %5\n外部时钟: %6\n主时钟: %7\n\n同步配置:\n主时钟类型: %8\n同步策略: %9")
+                          .arg(stats.syncError * 1000, 0, 'f', 1)
+                          .arg(stats.avgSyncError * 1000, 0, 'f', 1)
+                          .arg(stats.maxSyncError * 1000, 0, 'f', 1)
+                          .arg(audioClockStr)
+                          .arg(videoClockStr)
+                          .arg(externalClockStr)
+                          .arg(masterClockStr)
+                          .arg(masterTypeStr)
+                          .arg(syncStrategyStr);
+            } else {
+                syncText = syncText.arg(stats.syncError * 1000, 0, 'f', 1)
+                                 .arg(stats.avgSyncError * 1000, 0, 'f', 1)
+                                 .arg(stats.maxSyncError * 1000, 0, 'f', 1);
+            }
+            
+            statsText += syncText;
             
             // 性能统计
             statsText += QString("\n\n性能:\nCPU: %1%\n内存: %2 MB\n比特率: %3 kbps")
@@ -584,10 +716,10 @@ private:
         refreshLayout->addStretch();
         statsLayout->addLayout(refreshLayout);
         
-        m_statsLabel = new QLabel("帧数: 0\n丢帧: 0 (0.0%)\n重复帧: 0\n速度: 1.0x\n\n队列状态:\n视频帧: 0\n音频帧: 0\n数据包: 0\n\n同步状态:\n当前误差: 0.0 ms\n平均误差: 0.0 ms\n最大误差: 0.0 ms\n\n性能:\nCPU: 0.0%\n内存: 0.0 MB\n比特率: 0 kbps");
+        m_statsLabel = new QLabel("帧数: 0\n丢帧: 0 (0.0%)\n重复帧: 0\n速度: 1.0x\n\n队列状态:\n视频帧: 0\n音频帧: 0\n数据包: 0\n\n同步状态:\n当前误差: 0.0 ms\n平均误差: 0.0 ms\n最大误差: 0.0 ms\n\n时钟信息:\n音频时钟: N/A\n视频时钟: N/A\n外部时钟: N/A\n主时钟: N/A\n\n同步配置:\n主时钟类型: N/A\n同步策略: N/A\n\n性能:\nCPU: 0.0%\n内存: 0.0 MB\n比特率: 0 kbps");
         m_statsLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
         m_statsLabel->setWordWrap(true);
-        m_statsLabel->setMinimumHeight(300); // 设置最小高度以显示所有统计信息
+        m_statsLabel->setMinimumHeight(450); // 增加最小高度以显示更多同步信息
         statsLayout->addWidget(m_statsLabel);
         rightLayout->addWidget(statsGroup);