zhuizhu 8 ماه پیش
والد
کامیت
97091dcab3

+ 2 - 0
.gitignore

@@ -16,3 +16,5 @@
 /bin_debug
 /AV/build
 /AV/.xmake
+/.xmake
+/ci_build

+ 0 - 10
.xmake/windows/x64/cache/config

@@ -1,10 +0,0 @@
-{
-    options = {
-        qt = [[D:\Qt\5.15.2\msvc2019_64]]
-    },
-    mtimes = {
-        ["AV\\xmake.lua"] = 1753569640,
-        ["xmake.lua"] = 1753559920
-    },
-    recheck = false
-}

+ 0 - 1
.xmake/windows/x64/cache/cxxmodules

@@ -1 +0,0 @@
-{ }

+ 0 - 43
.xmake/windows/x64/cache/detect

@@ -1,43 +0,0 @@
-{
-    ["lib.detect.has_flags"] = {
-        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx_cxflags_-nologo_cl_sourceDependencies"] = true,
-        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx_cxflags_-nologo_-DNDEBUG"] = true,
-        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx_cxflags_-nologo_/W3"] = true,
-        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx_cxflags_-nologo_/utf-8"] = true,
-        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx_cxflags_-nologo_cl_external_includedir"] = true,
-        ["windows_x64_C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe_19.39.33523_cxx__-nologo_-O2"] = true
-    },
-    find_program_msvc_arch_x64_plat_windows_checktoolar = {
-        ["link.exe"] = [[C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.39.33519\bin\HostX64\x64\link.exe]]
-    },
-    find_program = {
-        ["C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe"] = [[C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.39.33519\bin\HostX64\x64\cl.exe]],
-        ["cl.exe"] = [[C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.39.33519\bin\HostX64\x64\cl.exe]],
-        nim = false
-    },
-    find_programver = {
-        ["C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX64\\x64\\cl.exe"] = "19.39.33523"
-    },
-    find_program_msvc_arch_x64_plat_windows_checktoolcxx = {
-        ["cl.exe"] = [[C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.39.33519\bin\HostX64\x64\cl.exe]]
-    },
-    ["detect.sdks.find_qt"] = {
-        ["D:\\Qt\\5.15.2\\msvc2019_64"] = {
-            qt = {
-                bindir = "D:/Qt/5.15.2/msvc2019_64/bin",
-                sdkdir = "D:/Qt/5.15.2/msvc2019_64",
-                mkspecsdir = [[D:\Qt\5.15.2\msvc2019_64\mkspecs]],
-                pluginsdir = "D:/Qt/5.15.2/msvc2019_64/plugins",
-                libdir = "D:/Qt/5.15.2/msvc2019_64/lib",
-                bindir_host = "D:/Qt/5.15.2/msvc2019_64/bin",
-                libexecdir = "D:/Qt/5.15.2/msvc2019_64/bin",
-                sdkver = "5.15.2",
-                includedir = "D:/Qt/5.15.2/msvc2019_64/include",
-                qmldir = "D:/Qt/5.15.2/msvc2019_64/qml"
-            }
-        }
-    },
-    find_program_msvc_arch_x64_plat_windows_checktoolld = {
-        ["link.exe"] = [[C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.39.33519\bin\HostX64\x64\link.exe]]
-    }
-}

+ 0 - 24
.xmake/windows/x64/cache/history

@@ -1,24 +0,0 @@
-{
-    cmdlines = {
-        "xmake ",
-        [[xmake f --qt=D:\Qt\5.15.2\msvc2019_64]],
-        "xmake ",
-        "xmake ",
-        "xmake ",
-        "xmake ",
-        "xmake ",
-        "xmake build",
-        "xmake build",
-        "xmake build",
-        "xmake build",
-        "xmake build",
-        "xmake build",
-        "xmake build",
-        "xmake build",
-        "xmake build",
-        "xmake ",
-        "xmake ",
-        "xmake ",
-        "xmake "
-    }
-}

+ 0 - 1
.xmake/windows/x64/cache/option

@@ -1 +0,0 @@
-{ }

+ 0 - 1
.xmake/windows/x64/cache/package

@@ -1 +0,0 @@
-{ }

+ 0 - 1
.xmake/windows/x64/cache/project

@@ -1 +0,0 @@
-{ }

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 221
.xmake/windows/x64/cache/toolchain


+ 0 - 0
.xmake/windows/x64/project.lock


+ 0 - 32
.xmake/windows/x64/xmake.conf

@@ -1,32 +0,0 @@
-{
-    __toolchains_windows_x64 = {
-        "msvc",
-        "yasm",
-        "nasm",
-        "cuda",
-        "rust",
-        "swift",
-        "go",
-        "gfortran",
-        "fpc"
-    },
-    arch = "x64",
-    buildir = "build",
-    ccache = true,
-    clean = true,
-    host = "windows",
-    kind = "static",
-    mode = "release",
-    ndk_stdcxx = true,
-    network = "public",
-    pkg_cachedir = "H:/.xmake/cache",
-    pkg_installdir = "H:/.xmake/packages",
-    pkg_searchdirs = "H:/.xmake/packages",
-    plat = "windows",
-    proxy = "http://192.168.3.28:20171",
-    proxy_pac = "pac.lua",
-    qt = "D:/Qt/5.15.2/msvc2019_64",
-    qt_sdkver = "5.15.2",
-    theme = "default",
-    vs = "2022"
-}

+ 33 - 6
AV/code/player/player_core_v2.cpp

@@ -358,6 +358,15 @@ ErrorCode PlayerCoreV2::pause() {
         std::lock_guard<std::mutex> lock(m_pauseMutex);
         Logger::instance().info("Setting m_paused to true");
         m_paused = true;
+
+        m_videoPacketQueue->wakeup(); // 唤醒等待的解码线程
+
+        m_audioPacketQueue->wakeup(); // 唤醒等待的解码线程
+
+        m_videoFrameQueue->wakeup(); // 唤醒等待的播放线程
+
+        m_audioFrameQueue->wakeup(); // 唤醒等待的播放线程
+
         Logger::instance().info("m_paused set to: " + std::to_string(m_paused.load()));
     }
     // 立即通知所有等待的线程检查暂停状态
@@ -1259,15 +1268,15 @@ void PlayerCoreV2::readThreadFunc() {
     while (!m_threadsShouldStop) {
         // 检查暂停状态,类似ffplay.c中的paused检查
         bool pausedState = m_paused.load();
-        Logger::instance().debug("Video play thread loop - m_paused: " + std::to_string(pausedState));
+        Logger::instance().debug("Read thread loop - m_paused: " + std::to_string(pausedState));
         if (pausedState) {
-            Logger::instance().info("Video play thread entering pause wait");
+            Logger::instance().info("Read thread entering pause wait");
             std::unique_lock<std::mutex> lock(m_pauseMutex);
             m_pauseCondition.wait(lock, [this] { return !m_paused || m_threadsShouldStop; });
             if (m_threadsShouldStop) {
                 break;
             }
-            Logger::instance().info("Video play thread exiting pause wait");
+            Logger::instance().info("Read thread exiting pause wait");
             // 暂停状态结束后,继续下一次循环
             continue;
         }
@@ -1337,6 +1346,12 @@ void PlayerCoreV2::readThreadFunc() {
             continue;
         }
         
+        // 在读取数据包前检查暂停状态,避免在读取期间阻塞
+        if (m_paused.load()) {
+            Logger::instance().debug("Read thread detected pause before av_read_frame");
+            continue;
+        }
+        
         // 读取数据包
         int ret = av_read_frame(m_formatContext, packet);
         if (ret < 0) {
@@ -1395,7 +1410,6 @@ void PlayerCoreV2::readThreadFunc() {
                 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()));
@@ -1405,6 +1419,8 @@ void PlayerCoreV2::readThreadFunc() {
                 }
             }
         }
+        m_audioPacketQueue->wakeup();
+        m_videoPacketQueue->wakeup();
 
         av_packet_unref(packet);
     }
@@ -1446,6 +1462,11 @@ void PlayerCoreV2::videoDecodeThreadFunc() {
         // 从视频包队列获取包
         AVPacket* packet = nullptr;
         while (!m_threadsShouldStop && !packet) {
+            // 在 pop 操作前检查暂停状态,避免在 pop 期间阻塞
+            if (m_paused.load()) {
+                Logger::instance().debug("Video decode thread detected pause before pop");
+                break;
+            }
             Logger::instance().info("Video decode thread read Packet");
             packet = m_videoPacketQueue->pop(10); // 减少超时时间以提高seek响应速度
             Logger::instance().infof("Video decode thread read Packet %d", packet);
@@ -1566,6 +1587,11 @@ void PlayerCoreV2::audioDecodeThreadFunc() {
         // 从音频包队列获取包
         AVPacket* packet = nullptr;
         while (!m_threadsShouldStop && !packet) {
+            // 在 pop 操作前检查暂停状态,避免在 pop 期间阻塞
+            if (m_paused.load()) {
+                Logger::instance().debug("Audio decode thread detected pause before pop");
+                break;
+            }
             packet = m_audioPacketQueue->pop(10); // 减少超时时间以提高seek响应速度
             if (packet) {
                 // 检查是否是EOF标记
@@ -1735,9 +1761,10 @@ void PlayerCoreV2::videoPlayThreadFunc() {
         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)));
+                std::this_thread::sleep_for(
+                    std::chrono::microseconds(static_cast<int64_t>(decision.delay * 1000000)));
             }
-            
+
             // 通知显示帧
             if (m_eventCallback) {
                 m_eventCallback->onVideoFrameReady(framePtr.get());

+ 7 - 7
AV/code/utils/utils_packet_queue.cpp

@@ -78,16 +78,16 @@ ErrorCode PacketQueue::enqueue(std::unique_ptr<PacketQueueItem> item) {
             }
         } else {
             // 等待队列有空间
-            if (!notFull_.wait_for(lock, std::chrono::milliseconds(config_.timeoutMs),
-                                  [this, currentSize, currentBytes] { 
-                                      size_t newSize = config_.priorityQueue ? priorityQueue_.size() : normalQueue_.size();
-                                      size_t newBytes = totalBytes_.load();
-                                      return (newSize < config_.maxSize && newBytes < config_.maxBytes) || shutdown_; 
-                                  })) {
+            if (!notFull_.wait_for(lock, std::chrono::milliseconds(config_.timeoutMs), [this] {
+                    size_t newSize = config_.priorityQueue ? priorityQueue_.size()
+                                                           : normalQueue_.size();
+                    size_t newBytes = totalBytes_.load();
+                    return (newSize < config_.maxSize && newBytes < config_.maxBytes) || shutdown_;
+                })) {
                 Logger::instance().warning("Enqueue timeout");
                 return ErrorCode::TIMEOUT;
             }
-            
+
             if (shutdown_) {
                 return ErrorCode::INVALID_STATE;
             }

+ 2 - 2
AV/test_player_with_ui.cpp

@@ -90,8 +90,8 @@ public:
     
     void onErrorOccurred(const std::string& error) override {
         Logger::instance().error("[ERROR] " + error);
-        QMetaObject::invokeMethod(m_parent, "onPlayerError", Qt::QueuedConnection,
-                                Q_ARG(QString, QString::fromStdString(error)));
+        // QMetaObject::invokeMethod(m_parent, "onPlayerError", Qt::QueuedConnection,
+        //                         Q_ARG(QString, QString::fromStdString(error)));
     }
     
     void onFrameDropped(int64_t totalDropped) override {

+ 5 - 0
AvRecorder/ui/opengl_video_widget.cpp

@@ -587,6 +587,11 @@ bool OpenGLVideoWidget::Render(AVFrame* frame)
     }
 
     bool result = convertFromAVFrame(frame);
+    
+    // 释放传入的AVFrame,因为现在使用QueuedConnection异步调用
+    // 需要在这里释放内存,避免内存泄漏
+    av_frame_free(&frame);
+    
     return result;
 }
 

+ 3 - 1
AvRecorder/ui/opengl_video_widget.h

@@ -1,12 +1,12 @@
 #pragma once
 
+#include <QImage>
 #include <QMutex>
 #include <QOpenGLFunctions>
 #include <QOpenGLShaderProgram>
 #include <QOpenGLTexture>
 #include <QOpenGLWidget>
 #include <QTimer>
-#include <QImage>
 
 extern "C" {
 #include <libavutil/frame.h>
@@ -31,6 +31,8 @@ public:
     // 添加与 VideoRender 类似的接口
     bool Open(unsigned int width, unsigned int height);
     void Close();
+
+public slots:
     bool Render(AVFrame* frame);
     
     // 原有接口

+ 0 - 43
TODO.md

@@ -1,43 +0,0 @@
-1. 聊天组件功能完善
-- 文本选择算法优化
-  
-  - 修复多行文本选择时的位置计算问题
-  - 优化选择区域的视觉反馈效果
-- 消息气泡渲染优化
-  
-  - 实现气泡圆角和阴影效果
-  - 添加发送状态指示器(发送中、已发送、已读)
-  - 优化消息时间戳的显示位置和样式
-2. 异步消息处理框架
-- 基于QtPromise的消息发送机制
-  
-  - 实现消息队列管理
-  - 添加消息发送状态追踪
-  - 实现发送失败自动重试机制
-- 网络状态监测与适配
-  
-  - 添加网络连接状态检测
-3. 音视频功能集成
-- 语音消息功能
-  - 集成AvRecorder音频录制模块
-  - 实现语音消息的播放控件
-  - 添加语音波形可视化效果
-  - 集成视频预览功能
-- 屏幕共享功能
-  - 添加屏幕共享选项
-  - 实现屏幕区域选择
-  - 优化共享内容的帧率和清晰度
- 4. UI/UX优化与主题适配
-- 主题系统集成
-  - 使用ThemeManager实现聊天界面的主题切换
-  - 适配暗色模式下的气泡和文字颜色
-  - 优化高对比度模式的可访问性
-- 动画效果
-  
-  - 实现滚动平滑过渡
-  - 添加加载更多历史消息的进度指示器
-- 性能优化
-  
-  - 实现消息的虚拟列表,优化大量消息的渲染性能
-  - 添加图片懒加载机制
-  - 优化内存占用和资源释放

+ 107 - 1
xmake.lua

@@ -1 +1,107 @@
-includes("AV")
+-- includes("AV")
+
+
+
+target("qt_widgetapp")
+	add_rules("qt.widgetapp")
+    set_rundir("$(projectdir)/ci_build")
+
+	on_build(function (target)
+		print("build it")
+		import("core.base.hashset")
+		import("private.action.run.runenvs", {try = true})
+		if not runenvs then
+			import("private.action.run.make_runenvs")
+		end
+		-- 获取当前 target 的环境
+		function _add_target_pkgenvs(target, pkgenvs, targets_added)
+			if targets_added[target:name()] then
+				return
+			end
+			targets_added[target:name()] = true
+			table.join2(pkgenvs, target:pkgenvs())
+			for _, dep in ipairs(target:orderdeps()) do
+				_add_target_pkgenvs(dep, pkgenvs, targets_added)
+			end
+		end
+
+		local pkgenvs = {}
+		_add_target_pkgenvs(target, pkgenvs, {})
+		-- 获取当前系统的环境
+		local addrunenvs, setrunenvs = runenvs and runenvs.make(target) or make_runenvs(target)
+		local runenvs = { add = addrunenvs, set = setrunenvs }
+		for name, env in pairs(pkgenvs) do
+			runenvs.add[name] = runenvs.add[name] or {}
+			table.append(runenvs.add[name], env)
+		end
+		-- PATH 环境整合 添加 到系统
+		if type(runenvs.add) == "table" then
+			for key, value in pairs(runenvs.add) do
+				--print(key, value)
+				for i, v in pairs(value) do
+					os.addenvs({[key] = v})
+				end
+			end
+		end
+
+		-- key: LIB PATH
+		function add_toolchain_envs(key)
+			local env_table = {}
+			local search_env_set  = hashset.new()
+			local function insert_include(dir)
+				if not path.is_absolute(dir) then
+					dir = path.absolute(dir, os.projectdir())
+				end
+				if search_env_set:insert(dir) then
+					table.insert(env_table, dir)
+				end
+			end
+
+			for _, toolchain in ipairs(target:toolchains()) do
+				local runenvs = toolchain:runenvs()
+				if runenvs and runenvs[key] then
+					for _, env in ipairs(path.splitenv(runenvs[key])) do
+						insert_include(env)
+					end
+				end
+			end
+			-- INCLUDE 环境整合
+			for _, value in pairs(env_table) do
+				os.addenvs({[key] = value})
+			end
+		end
+		-- 添加工具链需要的环境信息
+		add_toolchain_envs("LIBPATH")
+		add_toolchain_envs("LIB")
+		add_toolchain_envs("INCLUDE")
+		local envs = os.getenvs()
+		local rundir = path.join(os.projectdir(), "ci_build")
+		
+		-- 确保运行目录存在
+		os.mkdir(rundir)
+
+		os.execv("qmake", {"-version"}, {envs = envs, curdir = rundir})
+		-- print(envs)
+		local proPath = path.join(os.projectdir(), "LearningSmartClient.pro")
+		print("build:", proPath)
+		if is_mode("debug") then
+			os.execv("qmake", {proPath, "-spec", "win32-msvc", "CONFIG+=debug", "CONFIG+=qml_debug"}, {envs = envs, curdir = rundir})
+		elseif is_mode("release") then
+			os.execv("qmake", {proPath, "-spec", "win32-msvc", "CONFIG+=release"}, {envs = envs, curdir = rundir})
+		else
+			print("no supp QMake")
+		end
+
+		local jom = "D:\\Qt\\Tools\\QtCreator\\bin\\jom\\jom.exe"
+
+		if is_mode("debug") then
+			os.execv(jom, {"-f", "Makefile.Debug", "qmake_all"}, {envs = envs, curdir = rundir})
+		elseif is_mode("release") then
+			os.execv(jom, {"-f", "Makefile.Release", "qmake_all"}, {envs = envs, curdir = rundir})
+		else
+			print("no supp mode Makefile")
+		end
+		os.execv(jom, {"-j24"}, {envs = envs, curdir = rundir})
+	end)
+target_end()
+

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است