Explorar el Código

防止 数据包卡

zhuizhu hace 8 meses
padre
commit
dce0538b7c
Se han modificado 2 ficheros con 380 adiciones y 116 borrados
  1. 21 9
      AV/code/player/player_core_v2.cpp
  2. 359 107
      main.cpp

+ 21 - 9
AV/code/player/player_core_v2.cpp

@@ -1158,10 +1158,22 @@ void PlayerCoreV2::stopAllThreads() {
 }
 
 void PlayerCoreV2::flushBuffers() {
-    if (m_videoPacketQueue) m_videoPacketQueue->clear();
-    if (m_audioPacketQueue) m_audioPacketQueue->clear();
-    if (m_videoFrameQueue) m_videoFrameQueue->clear();
-    if (m_audioFrameQueue) m_audioFrameQueue->clear();
+    if (m_videoPacketQueue) {
+        m_videoPacketQueue->clear();
+        m_videoPacketQueue->wakeup(); // 唤醒等待的解码线程
+    }
+    if (m_audioPacketQueue) {
+        m_audioPacketQueue->clear();
+        m_audioPacketQueue->wakeup(); // 唤醒等待的解码线程
+    }
+    if (m_videoFrameQueue) {
+        m_videoFrameQueue->clear();
+        m_videoFrameQueue->wakeup(); // 唤醒等待的播放线程
+    }
+    if (m_audioFrameQueue) {
+        m_audioFrameQueue->clear();
+        m_audioFrameQueue->wakeup(); // 唤醒等待的播放线程
+    }
 }
 
 void PlayerCoreV2::readThreadFunc() {
@@ -1305,7 +1317,7 @@ void PlayerCoreV2::videoDecodeThreadFunc() {
         AVPacket* packet = nullptr;
         while (!m_threadsShouldStop && !packet) {
             Logger::instance().info("Video decode thread read Packet");
-            packet = m_videoPacketQueue->pop(100);
+            packet = m_videoPacketQueue->pop(10); // 减少超时时间以提高seek响应速度
             Logger::instance().infof("Video decode thread read Packet %d", packet);
             if (packet) {
                 // 检查是否是EOF标记
@@ -1405,7 +1417,7 @@ void PlayerCoreV2::audioDecodeThreadFunc() {
         // 从音频包队列获取包
         AVPacket* packet = nullptr;
         while (!m_threadsShouldStop && !packet) {
-            packet = m_audioPacketQueue->pop(100);
+            packet = m_audioPacketQueue->pop(10); // 减少超时时间以提高seek响应速度
             if (packet) {
                 // 检查是否是EOF标记
                 if (packet->stream_index == -1 && packet->data == nullptr) {
@@ -1501,7 +1513,7 @@ void PlayerCoreV2::videoPlayThreadFunc() {
         }
 
         // 获取视频帧,使用超时避免无限阻塞
-        AVFrame* frame = m_videoFrameQueue->pop(100); // 100ms超时
+        AVFrame* frame = m_videoFrameQueue->pop(10); // 减少超时时间以提高seek响应速度
         if (!frame) {
             // 检查是否应该继续等待
             if (m_threadsShouldStop) {
@@ -1580,8 +1592,8 @@ void PlayerCoreV2::audioPlayThreadFunc() {
             continue;
         }
 
-        // 获取音频帧,使用较长的超时时间以确保能接收到EOF帧
-        AVFrame* frame = m_audioFrameQueue->pop(100); // 100ms超时
+        // 获取音频帧,使用较短的超时时间以提高seek响应速度
+        AVFrame* frame = m_audioFrameQueue->pop(10); // 减少超时时间以提高seek响应速度
         if (!frame) {
             // 检查是否应该继续等待
             if (m_threadsShouldStop) {

+ 359 - 107
main.cpp

@@ -1,133 +1,385 @@
-// #include "AVPlayer2/mainwindowa.h"
-// #include "mainwindow.h"
-// #include "thememanager.h"
-// #include "themesettingswidget.h"
-
-// #include <QApplication>
-// #include <QAudioDeviceInfo>
-// #include <QAudioOutput>
-// #include <QDebug>
-// #include <QVBoxLayout>
-// #include <qendian.h>
-// #include <qmath.h>
-// #include <QFile>
-// #include <QTextStream>
-// #include <QDateTime>
-// #include <QMutex>
-// #include <QLoggingCategory>
-
-// QFile g_logFile;
-// QTextStream* g_logStream = nullptr;
-// QMutex g_logMutex;
-
-// void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+// #include "AV/code/base/logger.h"
+// #include "AV/code/player/player_core_v2.h"
+// #include <chrono>
+// #include <iostream>
+// #include <string>
+// #include <thread>
+
+// using namespace av::player;
+// using namespace av::utils;
+
+// // 示例事件回调类
+// class ExamplePlayerCallback : public PlayerEventCallback
 // {
-//     QMutexLocker locker(&g_logMutex);
-//     if (!g_logStream) return;
-
-//     QString typeStr;
-//     switch (type) {
-//     case QtDebugMsg:    typeStr = "DEBUG"; break;
-//     case QtWarningMsg:  typeStr = "WARN "; break;
-//     case QtCriticalMsg: typeStr = "ERROR"; break;
-//     case QtFatalMsg:    typeStr = "FATAL"; break;
-//     case QtInfoMsg:
-//         break;
+// public:
+//     void onStateChanged(PlayerState newState) override
+//     {
+//         std::string stateStr;
+//         switch (newState) {
+//         case PlayerState::Idle:
+//             stateStr = "Idle";
+//             break;
+//         case PlayerState::Opening:
+//             stateStr = "Opening";
+//             break;
+//         case PlayerState::Stopped:
+//             stateStr = "Stopped";
+//             break;
+//         case PlayerState::Playing:
+//             stateStr = "Playing";
+//             break;
+//         case PlayerState::Paused:
+//             stateStr = "Paused";
+//             break;
+//         case PlayerState::Seeking:
+//             stateStr = "Seeking";
+//             break;
+//         case PlayerState::Error:
+//             stateStr = "Error";
+//             break;
+//         }
+//         std::cout << "[EVENT] State changed to: " << stateStr << std::endl;
 //     }
 
-//     QString logMsg = QString("%1 [%2] %3 (%4:%5)\n")
-//         .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz"))
-//         .arg(typeStr)
-//         .arg(msg)
-//         .arg(QString(context.file ? context.file : ""))
-//         .arg(context.line);
+//     void onPositionChanged(int64_t position) override
+//     {
+//         // 每秒更新一次位置信息
+//         static auto lastUpdate = std::chrono::steady_clock::now();
+//         auto now = std::chrono::steady_clock::now();
+//         if (std::chrono::duration_cast<std::chrono::seconds>(now - lastUpdate).count() >= 1) {
+//             double seconds = position / 1000000.0;
+//             std::cout << "[EVENT] Position: " << std::fixed << std::setprecision(2) << seconds
+//                       << "s" << std::endl;
+//             lastUpdate = now;
+//         }
+//     }
 
-//     (*g_logStream) << logMsg;
-//     g_logStream->flush();
+//     void onMediaInfoChanged(const MediaInfo& info) override
+//     {
+//         std::cout << "[EVENT] Media info changed:" << std::endl;
+//         std::cout << "  File: " << info.filename << std::endl;
+//         std::cout << "  Duration: " << (info.duration / 1000000.0) << "s" << std::endl;
+//         std::cout << "  Has Video: " << (info.hasVideo ? "Yes" : "No") << std::endl;
+//         std::cout << "  Has Audio: " << (info.hasAudio ? "Yes" : "No") << std::endl;
 
-//     if (type == QtFatalMsg)
-//         abort();
-// }
-// namespace avrecorder::video { void InitWinRTCapture(); }
-// int main(int argc, char* argv[])
+//         if (info.hasVideo) {
+//             std::cout << "  Video: " << info.width << "x" << info.height << " @ " << info.fps
+//                       << " fps" << std::endl;
+//         }
+
+//         if (info.hasAudio) {
+//             std::cout << "  Audio: " << info.sampleRate << " Hz, " << info.channels << " channels"
+//                       << std::endl;
+//         }
+//     }
+
+//     void onErrorOccurred(const std::string& error) override
+//     {
+//         std::cout << "[ERROR] " << error << std::endl;
+//     }
+
+//     void onFrameDropped(int64_t totalDropped) override
+//     {
+//         std::cout << "[WARNING] Frame dropped, total: " << totalDropped << std::endl;
+//     }
+
+//     void onSyncError(double error, const std::string& reason) override
+//     {
+//         std::cout << "[WARNING] Sync error: " << (error * 1000) << "ms, reason: " << reason
+//                   << std::endl;
+//     }
+
+//     void onEndOfFile() override { std::cout << "[EVENT] End of file reached" << std::endl; }
+// };
+
+// // 简单的命令行界面
+// class SimplePlayerUI
 // {
-//     QLoggingCategory::setFilterRules(QStringLiteral("player.controller.ReadThread=false\n"
-//                                                     "player.controller.AudioPlayThread=false\n"));
-//     // QLoggingCategory::setFilterRules("*.debug=false\n"
-//     //                                  "*.info=false\n"
-//     //                                  "*.warning=false\n"
-//     //                                  "*.critical=false\n"
-//     //                                  "player.controller.*.debug=true\n"
-//     //                                  "player.controller.*.info=true\n");
+// public:
+//     SimplePlayerUI(PlayerCoreV2* player)
+//         : m_player(player)
+//         , m_running(true)
+//     {}
 
-//     // 打开日志文件(覆盖模式)
-//     g_logFile.setFileName("log.txt");
-//     g_logFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
-//     g_logStream = new QTextStream(&g_logFile);
+//     void run()
+//     {
+//         std::cout << "\n=== PlayerCoreV2 Example ===" << std::endl;
+//         std::cout << "Commands:" << std::endl;
+//         std::cout << "  open <filename>  - Open media file" << std::endl;
+//         std::cout << "  play             - Start playback" << std::endl;
+//         std::cout << "  pause            - Pause playback" << std::endl;
+//         std::cout << "  stop             - Stop playback" << std::endl;
+//         std::cout << "  seek <seconds>   - Seek to position" << std::endl;
+//         std::cout << "  speed <rate>     - Set playback speed (0.5-4.0)" << std::endl;
+//         std::cout << "  volume <level>   - Set volume (0.0-1.0)" << std::endl;
+//         std::cout << "  stats            - Show playback statistics" << std::endl;
+//         std::cout << "  debug            - Show debug information" << std::endl;
+//         std::cout << "  config           - Show sync configuration" << std::endl;
+//         std::cout << "  quit             - Exit program" << std::endl;
+//         std::cout << "============================\n" << std::endl;
 
-//     // 安装日志处理器
-//     //qInstallMessageHandler(myMessageHandler);
+//         std::string line;
+//         while (m_running && std::getline(std::cin, line)) {
+//             processCommand(line);
+//         }
+//     }
 
-//     // std::freopen(nullptr, "w", stdout);
-//     setvbuf(stdout, nullptr, _IONBF, 0);
+// private:
+//     void processCommand(const std::string& line)
+//     {
+//         std::istringstream iss(line);
+//         std::string command;
+//         iss >> command;
 
-// #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
-//     QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
-//         Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
-// #endif
-// #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-//     QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
-//     QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
-// #endif
+//         if (command == "open") {
+//             std::string filename;
+//             iss >> filename;
+//             if (!filename.empty()) {
+//                 auto result = m_player->openFile(filename);
+//                 if (result == ErrorCode::SUCCESS) {
+//                     std::cout << "File opened successfully" << std::endl;
+//                 } else {
+//                     std::cout << "Failed to open file: " << static_cast<int>(result) << std::endl;
+//                 }
+//             } else {
+//                 std::cout << "Usage: open <filename>" << std::endl;
+//             }
+//         } else if (command == "play") {
+//             auto result = m_player->play();
+//             if (result == ErrorCode::SUCCESS) {
+//                 std::cout << "Playback started" << std::endl;
+//             } else {
+//                 std::cout << "Failed to start playback: " << static_cast<int>(result) << std::endl;
+//             }
+//         } else if (command == "pause") {
+//             auto result = m_player->pause();
+//             if (result == ErrorCode::SUCCESS) {
+//                 std::cout << "Playback paused" << std::endl;
+//             } else {
+//                 std::cout << "Failed to pause playback: " << static_cast<int>(result) << std::endl;
+//             }
+//         } else if (command == "stop") {
+//             auto result = m_player->stop();
+//             if (result == ErrorCode::SUCCESS) {
+//                 std::cout << "Playback stopped" << std::endl;
+//             } else {
+//                 std::cout << "Failed to stop playback: " << static_cast<int>(result) << std::endl;
+//             }
+//         } else if (command == "seek") {
+//             double seconds;
+//             iss >> seconds;
+//             if (iss) {
+//                 int64_t timestamp = static_cast<int64_t>(seconds * 1000000); // 转换为微秒
+//                 auto result = m_player->seek(timestamp);
+//                 if (result == ErrorCode::SUCCESS) {
+//                     std::cout << "Seeking to " << seconds << "s" << std::endl;
+//                 } else {
+//                     std::cout << "Failed to seek: " << static_cast<int>(result) << std::endl;
+//                 }
+//             } else {
+//                 std::cout << "Usage: seek <seconds>" << std::endl;
+//             }
+//         } else if (command == "speed") {
+//             double speed;
+//             iss >> speed;
+//             if (iss) {
+//                 auto result = m_player->setPlaybackSpeed(speed);
+//                 if (result == ErrorCode::SUCCESS) {
+//                     std::cout << "Playback speed set to " << speed << "x" << std::endl;
+//                 } else {
+//                     std::cout << "Failed to set playback speed: " << static_cast<int>(result)
+//                               << std::endl;
+//                 }
+//             } else {
+//                 std::cout << "Usage: speed <rate>" << std::endl;
+//             }
+//         } else if (command == "volume") {
+//             double volume;
+//             iss >> volume;
+//             if (iss) {
+//                 m_player->setVolume(volume);
+//                 std::cout << "Volume set to " << volume << std::endl;
+//             } else {
+//                 std::cout << "Usage: volume <level>" << std::endl;
+//             }
+//         } else if (command == "stats") {
+//             showStats();
+//         } else if (command == "debug") {
+//             std::cout << m_player->getDebugInfo() << std::endl;
+//         } else if (command == "config") {
+//             showSyncConfig();
+//         } else if (command == "quit" || command == "exit") {
+//             m_running = false;
+//             std::cout << "Exiting..." << std::endl;
+//         } else if (!command.empty()) {
+//             std::cout << "Unknown command: " << command << std::endl;
+//         }
+//     }
+
+//     void showStats()
+//     {
+//         auto stats = m_player->getStats();
+
+//         std::cout << "\n=== Playback Statistics ===" << std::endl;
+//         std::cout << "Current Time: " << std::fixed << std::setprecision(2)
+//                   << (stats.currentTime / 1000000.0) << "s" << std::endl;
+//         std::cout << "Playback Speed: " << stats.playbackSpeed << "x" << std::endl;
+//         std::cout << "Total Frames: " << stats.totalFrames << std::endl;
+//         std::cout << "Dropped Frames: " << stats.droppedFrames << std::endl;
+//         std::cout << "Duplicated Frames: " << stats.duplicatedFrames << std::endl;
+//         std::cout << "Sync Error: " << std::fixed << std::setprecision(1)
+//                   << (stats.syncError * 1000) << "ms" << std::endl;
+//         std::cout << "Avg Sync Error: " << std::fixed << std::setprecision(1)
+//                   << (stats.avgSyncError * 1000) << "ms" << std::endl;
+//         std::cout << "Max Sync Error: " << std::fixed << std::setprecision(1)
+//                   << (stats.maxSyncError * 1000) << "ms" << std::endl;
+//         std::cout << "CPU Usage: " << std::fixed << std::setprecision(1) << stats.cpuUsage << "%"
+//                   << std::endl;
+//         std::cout << "Memory Usage: " << std::fixed << std::setprecision(1) << stats.memoryUsage
+//                   << "MB" << std::endl;
+//         std::cout << "Queued Packets: " << stats.queuedPackets << std::endl;
+//         std::cout << "Queued Video Frames: " << stats.queuedVideoFrames << std::endl;
+//         std::cout << "Queued Audio Frames: " << stats.queuedAudioFrames << std::endl;
+//         std::cout << "Bitrate: " << std::fixed << std::setprecision(1) << stats.bitrate << " kbps"
+//                   << std::endl;
+//         std::cout << "===========================\n" << std::endl;
+//     }
 
-//     QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
+//     void showSyncConfig()
+//     {
+//         auto config = m_player->getSyncConfig();
 
-//     QApplication a(argc, argv);
+//         std::cout << "\n=== Sync Configuration ===" << std::endl;
+//         std::cout << "Sync Strategy: " << static_cast<int>(config.syncStrategy) << std::endl;
+//         std::cout << "Audio Sync Threshold: " << (config.audioSyncThreshold * 1000) << "ms"
+//                   << std::endl;
+//         std::cout << "Video Sync Threshold: " << (config.videoSyncThreshold * 1000) << "ms"
+//                   << std::endl;
+//         std::cout << "Max Sync Error: " << (config.maxSyncError * 1000) << "ms" << std::endl;
+//         std::cout << "Clock Update Interval: " << config.clockUpdateInterval << "ms" << std::endl;
+//         std::cout << "Smoothing Window: " << config.smoothingWindow << std::endl;
+//         std::cout << "Adaptive Sync: " << (config.enableAdaptiveSync ? "Enabled" : "Disabled")
+//                   << std::endl;
+//         std::cout << "Frame Drop: " << (config.enableFrameDrop ? "Enabled" : "Disabled")
+//                   << std::endl;
+//         std::cout << "Frame Duplicate: " << (config.enableFrameDuplicate ? "Enabled" : "Disabled")
+//                   << std::endl;
+//         std::cout << "Prediction: " << (config.enablePrediction ? "Enabled" : "Disabled")
+//                   << std::endl;
+//         std::cout << "==========================\n" << std::endl;
+//     }
+
+//     PlayerCoreV2* m_player;
+//     bool m_running;
+// };
 
-//     ThemeManager::instance().setThemeMode(ThemeManager::Light);
+// int main(int argc, char* argv[])
+// {
+//     // 初始化日志系统
+//     Logger::instance().initialize("test.log", LogLevel::DEBUG, false, true);
+//     Logger::instance().setLevel(LogLevel::DEBUG);
+//     Logger::instance().info("PlayerCoreV2 Example Started");
 
-//     // 注册Room 相关的类型 方便 序列化
-//     void initRoomType();
-//     initRoomType();
+//     try {
+//         // 创建同步配置
+//         SyncConfigV2 syncConfig;
+//         syncConfig.syncStrategy = SyncStrategy::ADAPTIVE; // 使用自适应同步策略
+//         syncConfig.audioSyncThreshold = 0.040;            // 40ms
+//         syncConfig.videoSyncThreshold = 0.020;            // 20ms
+//         syncConfig.maxSyncError = 0.200;                  // 200ms
+//         syncConfig.clockUpdateInterval = 10;              // 10ms
+//         syncConfig.smoothingWindow = 10;                  // 10个样本
+//         syncConfig.enableAdaptiveSync = true;
+//         syncConfig.enableFrameDrop = true;
+//         syncConfig.enableFrameDuplicate = true;
+//         syncConfig.enablePrediction = true;
+//         syncConfig.enableErrorRecovery = true;
 
-//     // 初始化wgc
+//         // 创建播放器实例
+//         auto player = std::make_unique<PlayerCoreV2>(syncConfig);
 
-//     avrecorder::video::InitWinRTCapture();
+//         // 创建事件回调
+//         auto callback = std::make_unique<ExamplePlayerCallback>();
+//         player->setEventCallback(callback.get());
 
-//     /*
-// docker run -itd  --name zlmediakit --restart=always
-// -p 1935:1935 -p 8080:80 -p 8443:443
-// -p 8554:554 -p 10000:10000
-// -p 10000:10000/udp -p 8000:8000/udp
-// -p 9000:9000/udp
-// -v /data/zlmediakit/media/bin:/opt/media/bin
-// -v /data/zlmediakit/media/conf:/opt/media/conf
-// zlmediakit/zlmediakit:master
-// */
-//     // MainWindow w;
-//     // w.show();
+//         // 如果命令行提供了文件名,自动打开
+//         if (argc > 1) {
+//             std::string filename = argv[1];
+//             std::cout << "Opening file: " << filename << std::endl;
 
-//     // 视频播放测试
-//     MainWindowA aa;
-//     aa.show();
+//             auto result = player->openFile(filename);
+//             if (result == ErrorCode::SUCCESS) {
+//                 std::cout << "File opened successfully" << std::endl;
 
-//     // ThemeSettingsWidget ThemeSettingsWidget;
-//     // ThemeSettingsWidget.show();
+//                 // 自动开始播放
+//                 result = player->play();
+//                 if (result == ErrorCode::SUCCESS) {
+//                     std::cout << "Playback started" << std::endl;
+//                 } else {
+//                     std::cout << "Failed to start playback: " << static_cast<int>(result)
+//                               << std::endl;
+//                 }
+//             } else {
+//                 std::cout << "Failed to open file: " << static_cast<int>(result) << std::endl;
+//             }
+//         }
 
-//     // PlayerWindow w;
-//     // w.resize(960, 540);
-//     // w.show();
+//         // 启动用户界面
+//         SimplePlayerUI ui(player.get());
 
-//     // // 这里填你的流地址
-//     // // w.startPlay("http://vd3.bdstatic.com/mda-jennyc5ci1ugrxzi/mda-jennyc5ci1ugrxzi.mp4");
+//         // 启动更新线程
+//         std::atomic<bool> shouldStop(false);
+//         std::thread updateThread([&player, &shouldStop]() {
+//             while (!shouldStop) {
+//                 player->update();
+//                 std::this_thread::sleep_for(std::chrono::milliseconds(16)); // ~60 FPS
+//             }
+//         });
 
-//     // w.open("C:/Users/zhuizhu/Videos/1.mp4");
-//     // // w.startPlay("rtmp://192.168.3.76:1935/stream/V1/stream");
+//         // 运行用户界面
+//         ui.run();
 
-//     int ret = a.exec();
+//         // 停止更新线程
+//         shouldStop = true;
+//         if (updateThread.joinable()) {
+//             updateThread.join();
+//         }
 
-//     delete g_logStream;
-//     g_logFile.close();
+//         // 等待播放完成后再停止播放器
+//         if (player->getState() == PlayerState::Playing) {
+//             auto mediaInfo = player->getMediaInfo();
+//             if (mediaInfo.duration > 0) {
+//                 std::cout << "Waiting for playback to complete..." << std::endl;
+
+//                 // 等待播放完成
+//                 while (player->getState() == PlayerState::Playing) {
+//                     auto currentTime = player->getCurrentTime();
+//                     auto duration = mediaInfo.duration;
+
+//                     // 如果播放时间接近总时长(留100ms缓冲),认为播放完成
+//                     if (currentTime >= duration - 100000) { // 100ms = 100000微秒
+//                         std::cout << "Playback completed naturally" << std::endl;
+//                         break;
+//                     }
+
+//                     // 每100ms检查一次
+//                     std::this_thread::sleep_for(std::chrono::milliseconds(100));
+//                 }
+//             }
+//         }
+
+//         // 停止播放器
+//         player->stop();
+
+//         std::cout << "PlayerCoreV2 Example finished" << std::endl;
+
+//     } catch (const std::exception& e) {
+//         std::cerr << "Exception: " << e.what() << std::endl;
+//         return 1;
+//     } catch (...) {
+//         std::cerr << "Unknown exception occurred" << std::endl;
+//         return 1;
+//     }
 
-//     return ret;
+//     return 0;
 // }