当前位置: 首页 > article >正文

基于zlmediakit的RTSP流媒体服务器嵌入式开发指南

1. 为什么选择zlmediakit作为嵌入式RTSP服务器第一次接触流媒体开发时我试过用FFmpeg直接搭建服务结果被复杂的协议栈和线程管理折腾得够呛。后来发现zlmediakit这个宝藏项目它把RTSP/RTMP/HTTP-FLV等协议封装得特别友好特别适合嵌入到现有程序中。实测下来它的CAPI接口设计得很直观不需要启动独立进程直接作为SDK调用就能搞定流媒体服务。这个方案最大的优势是轻量级和高集成度。比如在智能门禁设备上我们既需要处理视频分析算法又要提供实时视频流。如果跑个独立的媒体服务器内存占用直接翻倍。而用zlmediakit的libmk_api.so内存只增加了不到10MB还能复用主程序的线程池。2. 环境搭建与基础配置2.1 编译与项目集成编译zlmediakit的过程比想象中简单。在Ubuntu 20.04上实测只需要git clone --depth1 https://github.com/ZLMediaKit/ZLMediaKit cd ZLMediaKit mkdir build cd build cmake .. -DENABLE_APION make -j4编译完成后会得到三个关键目录bin包含独立运行的MediaServer我们不用它lib重点关注的libmk_api.so动态库include所有CAPI头文件建议把libmk_api.so拷贝到你的项目lib目录头文件放到include/zlm。我在CMakeLists.txt里这样配置target_link_libraries(your_project PRIVATE ${CMAKE_SOURCE_DIR}/lib/libmk_api.so) include_directories(${CMAKE_SOURCE_DIR}/include/zlm)2.2 配置文件精讲从源码里拷贝的config.ini需要重点关注这些参数[rtsp] port554 # 开启UDP传输能降低延迟 enable_udp1 [h264] # 关键帧间隔影响秒开效果 gop_cache1有个坑我踩过如果程序运行时找不到配置文件需要手动指定路径。建议用这段代码获取可执行文件所在目录char *get_config_path(const char *filename) { char path[1024] {0}; readlink(/proc/self/exe, path, sizeof(path)); *strrchr(path, /) \0; return mk_util_string_format(%s/%s, path, filename); }3. 核心API实战解析3.1 服务初始化四步曲初始化流程就像搭积木顺序很重要环境配置日志级别设为0DEBUG方便调试启动服务HTTP服务建议开在8080避免权限问题事件监听至少实现on_mk_media_no_reader回调媒体源创建vhost填defaultVhost最省事实测可用的初始化代码模板mk_config config { .ini config.ini, .log_level 0, .log_mask LOG_CONSOLE // 同时输出到控制台和文件 }; mk_env_init(config); // 非阻塞启动服务 mk_http_server_start(8080, 0); mk_rtsp_server_start(554, 0); mk_events events { .on_mk_media_no_reader [](mk_media media) { printf(无人观看时自动关闭流\n); mk_media_release(media); } }; mk_events_listen(events);3.2 视频轨道动态管理创建H264轨道时有个性能优化技巧提前设置SPS/PPS。比如海康摄像头的流可以这样注入参数集codec_args v_args { .video { .width 1920, .height 1080, .fps 25, .bitrate 2048, .sps x00x00x00x01x67..., // 实际SPS数据 .pps x00x00x00x01x68... // 实际PPS数据 } }; mk_track v_track mk_track_create(MKCodecH264, v_args);动态切换分辨率也很实用。在无人机图传场景中我这样实现码率自适应void change_resolution(mk_media media, int width, int height) { mk_media_clear_tracks(media); // 先清除旧轨道 codec_args new_args { /* 新参数 */ }; mk_track new_track mk_track_create(MKCodecH264, new_args); mk_media_init_track(media, new_track); mk_media_init_complete(media); // 立即生效 }4. 帧数据输入优化技巧4.1 时间戳处理方案刚开始我直接用系统时间戳结果播放器老是卡顿。后来发现必须遵循严格的40ms间隔针对25fps。推荐两种可靠方案方案一硬件时钟同步#include time.h struct timespec ts; clock_gettime(CLOCK_MONOTONIC, ts); int dts ts.tv_nsec / 1000000; // 毫秒精度方案二动态计算补偿static int last_dts 0; if (last_dts 0) { last_dts get_current_ms(); } else { // 自动补偿延迟 int now get_current_ms(); last_dts (now - last_dts) 50 ? 40 : (now - last_dts); }4.2 内存管理避坑指南输入H264帧时最容易内存泄漏。必须遵循谁创建谁释放原则// 错误示例直接传递栈内存 uint8_t frame_data[1024]; mk_frame frame mk_frame_create(..., frame_data, ...); // 崩溃 // 正确做法使用堆内存 uint8_t *frame_data malloc(size); // ...填充数据... mk_frame frame mk_frame_create(..., frame_data, size, [](void *ptr) { free(ptr); }, // 自定义释放回调 NULL);对于持续输入的场景建议预分配帧缓冲区#define POOL_SIZE 10 mk_frame frame_pool[POOL_SIZE]; void init_pool() { for (int i0; iPOOL_SIZE; i) { frame_pool[i] mk_frame_create_empty(MKCodecH264); } } void input_frame(mk_media media, uint8_t *data, int size) { static int index 0; mk_frame_refresh(frame_pool[index], data, size); mk_media_input_frame(media, frame_pool[index]); index (index 1) % POOL_SIZE; }5. 高级功能实战5.1 多路流负载均衡在NVR系统中我这样管理多个媒体源typedef struct { mk_media media; pthread_mutex_t lock; } StreamContext; StreamContext* create_stream(const char *stream_id) { StreamContext *ctx malloc(sizeof(StreamContext)); pthread_mutex_init(ctx-lock, NULL); ctx-media mk_media_create(__defaultVhost__, live, stream_id, 0, 0, 0); return ctx; } void input_frame_thread_safe(StreamContext *ctx, uint8_t *data, int size) { pthread_mutex_lock(ctx-lock); mk_frame frame mk_frame_create(...); mk_media_input_frame(ctx-media, frame); mk_frame_unref(frame); pthread_mutex_unlock(ctx-lock); }5.2 自定义鉴权实现安全要求高的场景需要重写RTSP鉴权mk_events events { .on_mk_rtsp_auth [](const char *realm, const char *user, const char *pwd) { // 查询数据库验证 return check_password_in_db(user, pwd) ? 0 : -1; } };有个细节要注意默认鉴权是Basic模式如果要改Digest模式需要修改config.ini[rtsp] auth_methoddigest6. 性能调优经验在树莓派4B上实测优化前后差距巨大优化项CPU占用率延迟内存占用默认配置75%400ms48MB开启UDP传输68%220ms50MB预分配帧缓冲区52%180ms55MB关闭调试日志41%150ms42MB关键调优参数[thread] # 根据CPU核心数设置 event_threads2 async_threads2 [h264] # 减少缓冲帧数 gop_cache_num1记得在release版本关闭日志mk_config config { .log_level 3, // ERROR级别 .log_mask LOG_FILE // 只输出到文件 };

相关文章:

基于zlmediakit的RTSP流媒体服务器嵌入式开发指南

1. 为什么选择zlmediakit作为嵌入式RTSP服务器 第一次接触流媒体开发时,我试过用FFmpeg直接搭建服务,结果被复杂的协议栈和线程管理折腾得够呛。后来发现zlmediakit这个宝藏项目,它把RTSP/RTMP/HTTP-FLV等协议封装得特别友好,特别…...

【技术突破】douyin-downloader:重新定义抖音内容采集效率的智能引擎

【技术突破】douyin-downloader:重新定义抖音内容采集效率的智能引擎 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser …...

Gemini 3.1镜像实战:用三层思考架构与多模态引擎解决视频内容生产

谷歌2026年初发布的Gemini 3.1 Pro,凭借可配置的三层思考架构(低/中/高推理深度)和集成Veo视频引擎、Lyria 3音频引擎的多模态能力,为实际业务问题提供了全新的解决范式。国内开发者和内容创作者可通过聚合平台RskAi(w…...

FPGA新手必看:Vivado 2023.1里用DDS IP核生成1MHz正弦波,附完整仿真代码

FPGA实战:从零构建1MHz正弦波生成器的Vivado全流程解析 刚拿到FPGA开发板时,我最想实现的第一个项目就是信号发生器。看着示波器上跳动的波形从自己编写的代码中产生,这种成就感无可替代。本文将带你用Xilinx Vivado 2023.1中的DDS IP核&…...

MLCC陶瓷电容选型避坑指南:从X7R到C0G,5个关键参数决定电路稳定性

MLCC陶瓷电容选型避坑指南:从X7R到C0G,5个关键参数决定电路稳定性 当你在设计一个精密电源模块时,突然发现输出电压在高温环境下出现异常波动;或者调试射频电路时,明明计算无误的滤波网络却始终达不到预期效果——这些…...

256K上下文颠覆智能编程:Qwen3-Coder重构全栈开发效率范式

256K上下文颠覆智能编程:Qwen3-Coder重构全栈开发效率范式 【免费下载链接】Qwen3-Coder-30B-A3B-Instruct 项目地址: https://ai.gitcode.com/hf_mirrors/unsloth/Qwen3-Coder-30B-A3B-Instruct 问题发现:传统AI编程助手的三大痛点 2025年Stac…...

从温控器到无人机:PID参数整定的‘手感’秘籍,附C语言代码避坑指南

从温控器到无人机:PID参数整定的‘手感’秘籍与实战避坑指南 在工业自动化和智能硬件开发中,PID控制算法就像一位隐形的调音师,默默调节着系统的每一个细微变化。无论是缓慢升温的工业烘箱,还是高速响应的四旋翼无人机&#xff0c…...

GLM-4.1V-9B-Base基础教程:3步完成图片上传→中文提问→结果解析

GLM-4.1V-9B-Base基础教程:3步完成图片上传→中文提问→结果解析 1. 认识GLM-4.1V-9B-Base GLM-4.1V-9B-Base是智谱开源的一款视觉多模态理解模型,专门用于处理图像内容识别、场景描述、目标问答和中文视觉理解任务。这个模型已经完成了Web化封装&…...

硬件基础常识【2】--BJT深度饱和区的参数设计与工程实践

1. BJT深度饱和区的核心参数设计 三极管作为电子设计中最基础的元器件之一,其开关特性在实际工程中应用极为广泛。要让BJT稳定工作在深度饱和区,关键是要掌握几个核心参数的相互关系。我当年在设计第一个开关电路时,就因为没吃透这些参数关系…...

告别复杂配置!OSHI+JNA五分钟搞定Windows/Linux/macOS硬件信息采集

五分钟极简指南:用OSHIJNA实现全平台硬件监控零门槛接入 运维工程师小张最近接手了公司混合云环境下的服务器监控任务。当他面对Windows服务器、Linux虚拟机、macOS开发机三种不同系统时,传统方案需要分别调用WMI、/proc文件系统和system_profiler&#…...

AI 开发实战:质量门禁怎么设计,才不会让流程只剩形式

AI 开发实战:质量门禁怎么设计,才不会让流程只剩形式 一、这个问题为什么值得专门拿出来做? 在 AI 工程落地里,真正拖慢团队的往往不是模型本身,而是流程和协作方式没有跟上。 围绕“质量门禁怎么设计,才不…...

开源堡垒机Guacamole二次开发实战:SFTP与录屏功能深度优化

1. Guacamole堡垒机二次开发背景与挑战 Guacamole作为一款优秀的开源堡垒机,在企业远程办公和运维管理中扮演着重要角色。但在实际生产环境中,我们常常会遇到一些原生功能无法满足需求的情况。比如在分布式部署场景下,guacd服务与Java后端分离…...

多模态学习:结合文本和图像的旋转判断

多模态学习:结合文本和图像的旋转判断 1. 引言 你有没有遇到过这样的情况:拍了一张带文字的图片,结果发现方向不对,需要手动旋转才能正常阅读?传统的图像旋转判断方法往往只依赖视觉特征,对于包含文字的图…...

GLM-4-9B-Chat-1M实战教程:构建私有化AI客服——长FAQ精准匹配引擎

GLM-4-9B-Chat-1M实战教程:构建私有化AI客服——长FAQ精准匹配引擎 你是不是也遇到过这样的烦恼?公司客服系统里堆满了成百上千条产品文档、用户手册和常见问题解答,每当用户提问时,客服要么得在茫茫文档里大海捞针,要…...

USB设备映射混乱?三招教你通过终端识别/dev/ttyUSB*对应的物理插槽

USB设备映射混乱?三招教你通过终端识别/dev/ttyUSB*对应的物理插槽 当你的工作台上同时连接着五个相同型号的温湿度传感器,系统却将它们随机分配为/dev/ttyUSB0到4时,那种抓狂的感觉每个物联网开发者都深有体会。上周调试智能农业大棚时&…...

FPGA实战:手把手教你用Verilog实现以太网PHY芯片MDIO寄存器读写(附完整代码)

FPGA实战:手把手教你用Verilog实现以太网PHY芯片MDIO寄存器读写 在当今高速网络设备开发中,FPGA与以太网PHY芯片的协同工作已成为工业级设计的标配。MDIO(Management Data Input/Output)接口作为IEEE 802.3标准定义的两线制串行总…...

三角函数公式速查手册:从基础到进阶的实用指南

三角函数公式速查手册:从基础到进阶的实用指南 三角函数是数学中最基础也最重要的工具之一,无论是学生应对考试,还是开发者在图形编程、信号处理等领域的实际应用,都离不开这些公式的灵活运用。本文将系统整理从基础定义到高级变换…...

OpenStack Train版三节点部署全攻略:从CentOS 7.6配置到Dashboard上线

OpenStack Train版三节点部署实战:从CentOS 7.6到Dashboard的完整指南 当企业需要构建私有云平台时,OpenStack作为最成熟的开源IaaS解决方案之一,其灵活性和可扩展性备受青睐。本文将带您完成一个生产级的三节点OpenStack Train版部署&#x…...

Hitboxer终极指南:游戏键盘冲突一键解决,操作精度提升300%

Hitboxer终极指南:游戏键盘冲突一键解决,操作精度提升300% 【免费下载链接】socd SOCD cleaner tool for epic gamers 项目地址: https://gitcode.com/gh_mirrors/so/socd 还在为游戏操作中的方向键冲突而烦恼吗?当你在激烈的对战中同…...

微信小程序支付V3接口在ThinkPHP6中的封装实践:如何设计一个可复用的支付服务类?

微信小程序支付V3接口在ThinkPHP6中的高复用封装实践 微信支付作为小程序生态中最核心的商业化能力,其技术实现的质量直接影响着用户体验和系统稳定性。本文将分享如何在ThinkPHP6框架下,从零构建一个符合SOLID原则的支付服务类,实现一次封装…...

利用HunyuanVideo-Foley为游戏开发赋能:动态环境音效与技能音效生成实践

利用HunyuanVideo-Foley为游戏开发赋能:动态环境音效与技能音效生成实践 1. 游戏音效开发的痛点与机遇 在游戏开发过程中,音效设计往往是最容易被低估却又至关重要的环节之一。传统音效制作需要大量预录制音频素材,一个中型游戏项目动辄需要…...

新手也能懂:用Altium Designer搞定SPI Flash、eMMC和USB3.0的PCB等长与阻抗控制

Altium Designer实战:SPI Flash、eMMC与USB3.0的等长布线及阻抗控制指南 刚接触高速PCB设计时,面对密密麻麻的规则手册总让人望而生畏。3H原则、500mil误差、阻抗匹配这些术语听起来像天书,但当你用Altium Designer(AD&#xff09…...

小模型大能力:DeepSeek-R1-Distill-Qwen-1.5B在边缘计算中的应用

小模型大能力:DeepSeek-R1-Distill-Qwen-1.5B在边缘计算中的应用 1. 引言:边缘计算时代的轻量级AI解决方案 在AI技术快速发展的今天,大模型已经展现出惊人的能力。然而,当我们把目光投向边缘计算场景时,传统的百亿参…...

C# Random.Next() vs NextDouble():不同场景下的随机数生成指南

C# Random.Next() vs NextDouble():不同场景下的随机数生成指南 在游戏开发、模拟实验、密码学等众多领域,随机数生成都是不可或缺的核心功能。C#开发者通常第一时间想到的就是System.Random类,但你是否真正了解Next()和NextDouble()这些方法…...

PHP-JWT:PHP 中 JSON Web Tokens 的完整实现指南

PHP-JWT:PHP 中 JSON Web Tokens 的完整实现指南 【免费下载链接】php-jwt 项目地址: https://gitcode.com/gh_mirrors/ph/php-jwt Firebase PHP-JWT 是一个遵循 RFC 7519 标准的 PHP JSON Web Tokens 实现库,提供安全、高效的 JWT 编码和解码功…...

3步实现Web界面设计标注高效交付:面向全栈团队的Sketch Measure应用指南

3步实现Web界面设计标注高效交付:面向全栈团队的Sketch Measure应用指南 【免费下载链接】sketch-measure Make it a fun to create spec for developers and teammates 项目地址: https://gitcode.com/gh_mirrors/sk/sketch-measure 在Web开发项目中&#x…...

MusePublic插件开发指南:Photoshop艺术生成插件实战

MusePublic插件开发指南:Photoshop艺术生成插件实战 1. 前言 作为设计师,你是否曾经遇到过这样的困境:客户急着要一套海报设计方案,你却在创意构思上卡壳了好几个小时?或者想要尝试新的艺术风格,却苦于手…...

Unity 实现Slot Machine两种动态停止效果的实战解析

1. 老虎机效果设计核心思路 老虎机作为经典游戏机制,其动态停止效果直接影响玩家的游戏体验。在Unity中实现这类效果时,我们需要考虑两个关键因素:物理真实感和心理预期管理。缓慢减速效果通过逐渐降低转速营造紧张氛围,而惯性回弹…...

解决Word中MathType功能失效的VBA与注册表修复指南

1. 遇到MathType罢工?先别急着重装Office 最近帮同事处理Word文档时,发现他的MathType菜单全灰了,公式编辑功能完全瘫痪。这种情况在科研论文写作高峰期特别要命——你正赶着投稿 deadline,突然发现公式编辑器失灵了,…...

HiveWE:革新性地图编辑引擎助力魔兽争霸III创作者实现效率飞跃

HiveWE:革新性地图编辑引擎助力魔兽争霸III创作者实现效率飞跃 【免费下载链接】HiveWE A Warcraft III world editor. 项目地址: https://gitcode.com/gh_mirrors/hi/HiveWE 在魔兽争霸III地图开发领域,创作者长期面临着传统编辑器性能瓶颈与操作…...