新闻详情

新闻详情

首页 / 资讯中心 / 详情

视频不卡的关键:video-compress-cj 多线程编解码管线与 MutexManager 帧队列设计

发布时间:2026/9/26 14:43:49来源:尧图网络
视频不卡的关键:video-compress-cj 多线程编解码管线与 MutexManager 帧队列设计
视频不卡的关键video-compress-cj 多线程编解码管线与 MutexManager 帧队列设计【免费下载链接】video-compress-cj一个高性能的视频压缩器使用硬件解码和编码API(MediaCodec)。项目地址: https://gitcode.com/Cangjie-TPC/video-compress-cjvideo-compress-cj是一款基于硬件编解码MediaCodec的高性能视频压缩器它用多线程流水线 MutexManager 帧队列的设计让解封装 → 解码 → 编码 → 封装全程并行运转压缩大视频时界面不卡顿、主流程不阻塞。 为什么视频压缩会卡先想一个反面场景如果把压缩写成一条串行链路——读一帧 → 解码 → 编码 → 写盘 → 读下一帧 → ……问题立刻出现串行等待解码器在忙时编码器和写盘只能干等软解太慢CPU 软件解码 1080P 视频速度往往远低于视频本身帧率阻塞主线程压缩循环一旦占住调用线程界面直接假死。video-compress-cj的答案是三个字拆、并行、硬件跑。 核心设计一条多线程流水线整个压缩流程由 6 个组件构成编排逻辑集中在 cjcodec.cpp 的CompressVideo入口中┌─────────┐ ┌─────────┐ Surface零拷贝 ┌─────────┐ ┌─────────┐ │ DeMuxer │ → │ VideoDec │ ──────────────→ │ VideoEnc │ → │ Muxer │ │ 解封装 │ │ 硬件解码 │ (GPU 不落地) │ 硬件编码 │ │ 封装写盘 │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ (同上音视频两路并行) AudioDec │ → AudioEnc │ → │(合并写入)│ └─────────┘ └─────────┘ └─────────┘各组件的分工源码见 videocompress_ffi/src/main/cpp/组件职责源码位置DeMuxer解析文件、拿到音/视频轨道信息DeMuxer.cppVideoDec硬件视频解码H.264 / H.265VideoDec.cppVideoEnc硬件视频编码按质量降码率VideoEnc.cppAudioDec / AudioEncAAC 音频解码 / 编码audio/Muxer把音视频码流封装进 mp4muxer.cpp关键点视频解码器的输出不是内存像素而是直接渲染到编码器的输入 SurfaceOH_VideoDecoder_SetSurface见 VideoDec.cpp 的SetOutputSurface。解码后的画面在 GPU 内直通编码器全程不经过 CPU 内存拷贝这是不卡的第一个大前提。 线程模型回调只负责投递工作线程负责消费这是本设计最值得新手学习的部分。每个编解码组件都遵循同一套生产者—消费者模式硬件回调生产者OH_AVCodec的异步回调onNeedInputData/onNeedOutputData被触发时只把 buffer 索引、属性压入队列并notify_all()绝不在这条短命回调里做重活工作线程消费者常驻线程在条件变量上等待队列有数据就醒来取帧处理没数据就睡眠零 CPU 空转。以视频解码器为例信号队列定义在 VideoDec.h 的VDecSignal中——mutex condition_variable queue三件套各备一套输入、输出各一个// VDecSignal回调与工作线程之间的信物交换所 std::mutex inMutex_; std::condition_variable inCond_; std::queueuint32_t inIdxQueue; // 待推送的输入 buffer 索引 std::queueOH_AVMemory * inBufferQueue_; // outMutex_ / outCond_ / outIdxQueue_ 同理用于解码输出侧启动时解码器会拉起2 条独立线程VideoDec.cpp 的StartVideoDecoderinputLoop_→InputFunc从解封装器取包、推给硬件解码器outputLoop_→OutputFunc把解码输出渲染到编码器 Surface遇到 EOS 就通知编码器收尾。编码器侧同理VideoEnc.cpp 的OutputFunc线程负责把编码产物OH_AVMuxer_WriteSample写入封装器VideoEnc.cpp。于是运行时音、视频两路 × 解、编两级 × 输入输出两条线程并行流水——当解码器在解第 N 帧时编码器可能正在压第 N-2 帧封装器正在写第 N-3 帧三者互相不等待。这就是管线Pipeline一词的全部含义。 MutexManager帧队列与锁的中央调度台各组件之间需要共享什么锁、帧队列、轨道 ID、那块关键的 Surface。这些全被收拢进一个类——MutexManager定义见 tools.hclass MutexManager { public: std::mutex videoMutex_; // 视频队列互斥锁 std::dequestd::shared_ptrDemuxElement VMem; // 视频帧队列 std::mutex videoEncMutex; // 视频编码队列锁 std::dequeEncodeElement VRawQueue; // 视频编码码流队列 std::mutex audioMutex_; // 音频队列互斥锁 std::dequestd::shared_ptrDemuxElement AMem; // 音频帧队列 std::mutex AudioEncMutex; std::dequeEncodeElement ARawQueue; // 音频编码码流队列 OHNativeWindow *nativeWindow; // 解码→编码 共享 Surface int32_t vTrackId; // 视频轨道 ID int32_t aTrackId; // 音频轨道 ID };设计上它解决了三个问题锁与队列成对出现VMem永远和videoMutex_配套、VRawQueue永远和videoEncMutex配套多线程读写帧队列时拿锁再碰队列成为肌肉记忆杜绝数据竞争信息只登记一次DeMuxer 解析出的宽高、帧率、码率、轨道 IDDeMuxer.cpp 的GetTrackInfo统一挂到 MutexManager 上下游组件直接复用不重复解析Surface 全局唯一nativeWindow由编码器GetSurface()创建VideoEnc.cpp再交给解码器SetSurface使用两块硬件因此能零拷贝对接。每个组件通过RegisterMuxerManager(...)拿到这同一个 MutexManager 指针编排代码见 cjcodec.cpp相当于所有人领到同一本值班手册。 收尾也讲究EOS 传播与线程有序回收压缩结束靠一条 EOSEnd Of Stream信号链解封装读到末尾 → 解码器输入 EOS → 解码输出 EOS →VideoEnc-SendEncEos()通知编码器 → 编码器输出 EOS → 停止 Muxer。调用侧用WaitForEos依次 join 各工作线程cjcodec.cpp 的VideoCompressorWaitEos配合各组件StopInLoop / StopOutLoop中的清队列 唤醒 join三步曲如 VideoDec.cpp保证线程一个不漏、资源一个不泄。 如何上手体验克隆仓库git clone -b 具体分支名 --single-branch --recursive https://gitcode.com/Cangjie-TPC/video-compress-cj用 DevEco StudioCangjie 插件 5.0.13打开选中videocompressor模块执行 Make Module 完成编译在示例工程 entry/ 中调用压缩接口核心 API 文档见 doc/feature_api.mdCangjie 层封装见 video_compressor.cj。 相关文件导航内容路径流水线编排入口videocompress_ffi/src/main/cpp/cjcodec.cppMutexManager 帧队列定义videocompress_ffi/src/main/cpp/tools.h视频解码线程模型videocompress_ffi/src/main/cpp/video/decoder/VideoDec.cpp视频编码与 Surface 获取videocompress_ffi/src/main/cpp/video/encoder/VideoEnc.cpp解封装与轨道解析videocompress_ffi/src/main/cpp/demuxer/DeMuxer.cppAPI 接口文档doc/feature_api.md项目总览README.md✅ 小结视频不卡的三个秘密流水线并行解封装、解码、编码、封装各占独立线程帧在队列里接力谁也不用等谁硬件跑零拷贝MediaCodec 硬件编解码 Surface 直连像素数据不上 CPU锁队列成对管理MutexManager 把锁 帧队列 共享资源集中托管并发安全一目了然。下次再写压缩/转码功能把这套回调投递 条件变量消费 中央调度台的范式抄走卡顿自然就没了。【免费下载链接】video-compress-cj一个高性能的视频压缩器使用硬件解码和编码API(MediaCodec)。项目地址: https://gitcode.com/Cangjie-TPC/video-compress-cj创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Linux下编译安装PETSc:用 TaoToken 统一 Key 打通 AI 辅助排错链路 2026/9/26 14:43:48

Linux下编译安装PETSc:用 TaoToken 统一 Key 打通 AI 辅助排错链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
深度学习人脸表情识别源码实战:从检测对齐到ONNX推理优化 2026/9/26 14:43:48

深度学习人脸表情识别源码实战:从检测对齐到ONNX推理优化

简介:这是一套面向深度学习入门与计算机视觉实践者的高精度人脸表情识别系统源码,采用Python为主、Shell脚本为辅实现,可应用于情感分析、人机交互体验优化等场景。项目共57个文件,压缩包约26.1MB,包含17个Python脚本承…

阅读更多 →
AI编程从入门到生产:工具选型、Agent工作流与代码审查实战 2026/9/26 14:43:48

AI编程从入门到生产:工具选型、Agent工作流与代码审查实战

1. 从“能跑就行”到“敢上生产”:AI编程的第二道坎上一篇聊了AI编程入门阶段的一些体会,主要围绕怎么让AI帮你写出第一版能跑的代码。这次想聊的是下半场——当你已经习惯了用Cursor、Windsurf、Copilot这些工具帮你补全函数、生成测试、解释报错之后&a…

阅读更多 →
SolidWorks自定义属性与属性标签编制程序:打通工程图标题栏和BOM数据链路 2026/9/26 14:43:42

SolidWorks自定义属性与属性标签编制程序:打通工程图标题栏和BOM数据链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
微信表情包怎么存到手机相册里? 2026/9/26 14:43:35

微信表情包怎么存到手机相册里?

微信表情包存到手机相册里,是把它发给公众号「表情保存助手」,点开它回复的下载地址、选「保存到手机」;存完之后去手机的相册(有些手机叫图库)里,按时间就能翻到。这件事其实分两半:一半是「怎…

阅读更多 →
DeepSeek V4.1 Flash本地部署实战:低显存跑大模型的关键技术与优化 2026/9/26 14:43:35

DeepSeek V4.1 Flash本地部署实战:低显存跑大模型的关键技术与优化

最近几天,我的朋友圈和技术群被同一个名字刷屏了:DeepSeek V4.1 Flash。一开始我以为又是哪个媒体在炒冷饭,把旧版本重新包装了一下。直到我自己下载了权重,在本地把那几个G的模型文件加载起来,跑了几轮推理&#xff0…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉