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

移植live555 上的 rtsp

一、V4L2视频采集模块(完整示例)

#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <fcntl.h>// 初始化V4L2摄像头
int init_v4l2_camera(const char* dev_path, int width, int height) {int fd = open(dev_path, O_RDWR);if (fd < 0) {perror("Failed to open V4L2 device");return -1;}// 设置视频格式(YUV422)struct v4l2_format fmt = {0};fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;fmt.fmt.pix.width = width;fmt.fmt.pix.height = height;fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; // 海思可能要求NV12fmt.fmt.pix.field = V4L2_FIELD_NONE;if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) {perror("Failed to set video format");close(fd);return -1;}// 申请视频缓冲区(MMAP方式)struct v4l2_requestbuffers req = {0};req.count = 4;req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;req.memory = V4L2_MEMORY_MMAP;if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {perror("Failed to request buffers");close(fd);return -1;}// 映射缓冲区到用户空间struct v4l2_buffer buf = {0};for (int i = 0; i < req.count; ++i) {buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;buf.index = i;if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) {perror("Failed to query buffer");close(fd);return -1;}void* buffer = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);// 保存buffer指针...}// 启动视频流enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if (ioctl(fd, VIDIOC_STREAMON, &type) < 0) {perror("Failed to start streaming");close(fd);return -1;}return fd; // 返回设备句柄
}

关键点解释

  • 海思平台可能要求输入NV12格式,需根据硬件文档调整V4L2_PIX_FMT_*
  • MMAP方式减少内存拷贝,适合高帧率场景
  • 需循环调用VIDIOC_QBUFVIDIOC_DQBUF获取视频帧

二、海思H.264硬件编码模块

#include "hi_comm_venc.h"
#include "mpi_venc.h"// 初始化海思编码通道
HI_S32 init_hisi_venc(int width, int height, int fps) {HI_S32 s32Ret;VENC_CHN VencChn = 0;VENC_ATTR_S stVencAttr;// 配置编码参数memset(&stVencAttr, 0, sizeof(VENC_ATTR_S));stVencAttr.enType = PT_H264;stVencAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;stVencAttr.stRcAttr.stH264Cbr.u32Gop = fps * 2; // GOP为2秒stVencAttr.stRcAttr.stH264Cbr.u32BitRate = 2000; // 2000kbpsstVencAttr.stVencAttr.stAttrH264e.u32MaxPicWidth = width;stVencAttr.stVencAttr.stAttrH264e.u32MaxPicHeight = height;stVencAttr.stVencAttr.stAttrH264e.u32PicWidth = width;stVencAttr.stVencAttr.stAttrH264e.u32PicHeight = height;// 创建编码通道s32Ret = HI_MPI_VENC_CreateChn(VencChn, &stVencAttr);if (s32Ret != HI_SUCCESS) {printf("Create VENC channel failed: 0x%x\n", s32Ret);return s32Ret;}// 设置帧率VENC_PARAM_FRMRATE_PARA_S stFrmRate;stFrmRate.stSrcFrmRate.s32FrmRate = fps * 1000; // 以毫秒为单位stFrmRate.stDstFrmRate.s32FrmRate = fps * 1000;HI_MPI_VENC_SetFrmRate(VencChn, &stFrmRate);return HI_SUCCESS;
}// 获取编码后的H.264流
void get_h264_stream(VENC_CHN VencChn, unsigned char** ppBuffer, HI_U32* pSize) {VENC_STREAM_S stStream;HI_S32 s32Ret = HI_MPI_VENC_GetStream(VencChn, &stStream, 2000); // 2秒超时if (s32Ret == HI_SUCCESS) {*ppBuffer = stStream.pstPack[0].pu8Addr;*pSize = stStream.pstPack[0].u32Len;HI_MPI_VENC_ReleaseStream(VencChn, &stStream); // 必须释放}
}

关键点

  • 使用HI_MPI_VENC_GetStream非阻塞方式获取码流
  • 必须调用HI_MPI_VENC_ReleaseStream释放资源,否则会导致内存泄漏
  • 海思SDK要求严格的内存对齐,需按照文档配置参数

三、ALSA音频采集与AAC编码

#include <alsa/asoundlib.h>
#include <fdk-aac/aacenc_lib.h>// 初始化ALSA音频采集
snd_pcm_t* init_alsa(const char* device, int sample_rate, int channels) {snd_pcm_t* handle;snd_pcm_hw_params_t* params;if (snd_pcm_open(&handle, device, SND_PCM_STREAM_CAPTURE, 0) < 0) {fprintf(stderr, "ALSA open error\n");return NULL;}snd_pcm_hw_params_malloc(&params);snd_pcm_hw_params_any(handle, params);// 设置参数snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);snd_pcm_hw_params_set_channels(handle, params, channels);snd_pcm_hw_params_set_rate_near(handle, params, (unsigned int*)&sample_rate, 0);// 应用参数if (snd_pcm_hw_params(handle, params) < 0) {fprintf(stderr, "ALSA set params failed\n");snd_pcm_close(handle);return NULL;}return handle;
}// 初始化AAC编码器
AACENCODER* init_aac_encoder(int sample_rate, int channels) {AACENCODER* hEncoder;if (aacEncOpen(&hEncoder, 0, channels) != AACENC_OK) {return NULL;}// 设置编码参数aacEncoder_SetParam(hEncoder, AACENC_AOT, AOT_AAC_LC);aacEncoder_SetParam(hEncoder, AACENC_SAMPLERATE, sample_rate);aacEncoder_SetParam(hEncoder, AACENC_CHANNELMODE, MODE_2);aacEncoder_SetParam(hEncoder, AACENC_BITRATE, 64000); // 64kbpsif (aacEncEncode(hEncoder, NULL, NULL, NULL, NULL) != AACENC_OK) {aacEncClose(&hEncoder);return NULL;}return hEncoder;
}

四、live555自定义FramedSource实现

#include <liveMedia.hh>class Hi3516VideoSource : public FramedSource {
public:static Hi3516VideoSource* createNew(UsageEnvironment& env, VENC_CHN vencChn) {return new Hi3516VideoSource(env, vencChn);}protected:Hi3516VideoSource(UsageEnvironment& env, VENC_CHN vencChn) : FramedSource(env), mVencChn(vencChn) {}virtual void doGetNextFrame() {// 从海思编码器获取H.264数据unsigned char* pData = nullptr;HI_U32 dataSize = 0;get_h264_stream(mVencChn, &pData, &dataSize);if (dataSize > 0) {if (dataSize > fMaxSize) { // 处理分包fNumTruncatedBytes = dataSize - fMaxSize;dataSize = fMaxSize;}memcpy(fTo, pData, dataSize);fFrameSize = dataSize;// 设置时间戳(使用系统时钟)gettimeofday(&fPresentationTime, NULL);} else {fFrameSize = 0;}// 立即通知框架可以发送数据afterGetting(this);}private:VENC_CHN mVencChn;
};

关键逻辑

  • doGetNextFrame()是live555的核心回调函数,当需要发送数据时自动触发
  • 时间戳必须转换为RTP时间基准(视频:90000Hz,音频:采样率)
  • 若数据超过缓冲区大小,需设置fNumTruncatedBytes

五、RTSP服务端搭建

#include "liveMedia.hh"
#include "BasicUsageEnvironment.hh"void start_rtsp_server() {TaskScheduler* scheduler = BasicTaskScheduler::createNew();UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);// 创建RTSP服务器(端口554需要root权限)RTSPServer* rtspServer = RTSPServer::createNew(*env, 554, NULL);if (rtspServer == NULL) {*env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";exit(1);}// 创建媒体会话(H.264 + AAC)ServerMediaSession* sms = ServerMediaSession::createNew(*env, "live", "Hi3516 Live Stream", "Session for Hi3516");// 添加视频子会话sms->addSubsession(H264VideoFileServerMediaSubsession::createNew(*env, "dummy", NULL)); // 实际应使用自定义Source// 添加音频子会话(AAC)sms->addSubsession(ADTSAudioFileServerMediaSubsession::createNew(*env, "dummy", NULL));rtspServer->addServerMediaSession(sms);// 打印RTSP URLchar* url = rtspServer->rtspURL(sms);*env << "RTSP URL: " << url << "\n";delete[] url;env->taskScheduler().doEventLoop(); // 进入主循环
}

六、音视频同步策略

// 全局时间戳生成器(单位:微秒)
uint64_t get_ntp_timestamp() {struct timeval tv;gettimeofday(&tv, NULL);return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
}// 在FramedSource中设置时间戳
void Hi3516VideoSource::doGetNextFrame() {// ... 获取数据 ...uint64_t now = get_ntp_timestamp();fPresentationTime.tv_sec = now / 1000000;fPresentationTime.tv_usec = now % 1000000;
}// 音频同步需转换为采样数
uint32_t audio_rtp_timestamp(uint64_t ntp_ts, int sample_rate) {return (uint32_t)((ntp_ts * sample_rate) / 1000000);
}

七、完整流程整合

  1. 初始化硬件模块

    int v4l2_fd = init_v4l2_camera("/dev/video0", 1280, 720);
    init_hisi_venc(1280, 720, 30);
    snd_pcm_t* audio_handle = init_alsa("default", 44100, 2);
    AACENCODER* aac_enc = init_aac_encoder(44100, 2);
    
  2. 启动RTSP服务线程

    std::thread rtsp_thread(start_rtsp_server);
    rtsp_thread.detach();
    
  3. 主循环采集数据

    while (1) {// 视频采集->编码->存入队列struct v4l2_buffer buf = {0};ioctl(v4l2_fd, VIDIOC_DQBUF, &buf);HI_MPI_VENC_SendFrame(vencChn, &raw_frame); // 送入编码器ioctl(v4l2_fd, VIDIOC_QBUF, &buf);// 音频采集->编码->存入队列snd_pcm_readi(audio_handle, pcm_buffer, samples);aacEncEncode(aac_enc, ...);
    }
    

八、调试技巧

  1. 验证视频编码

    # 将H.264流保存为文件
    ./your_program > test.h264
    # 使用ffplay播放
    ffplay -f h264 test.h264
    
  2. 分析RTSP协议

    wireshark -f "tcp port 554 or udp port range 6970-6999"
    
  3. 海思SDK调试

    HI_MPI_LOG_SetLevel(LOG_LEVEL_DEBUG); // 开启海思SDK日志
    

通过以上完整实现,您可以在hi3516平台上构建稳定的RTSP音视频服务。实际部署时需根据硬件特性调整缓冲区大小、线程优先级等参数。

相关文章:

移植live555 上的 rtsp

一、V4L2视频采集模块&#xff08;完整示例&#xff09; #include <linux/videodev2.h> #include <sys/ioctl.h> #include <fcntl.h>// 初始化V4L2摄像头 int init_v4l2_camera(const char* dev_path, int width, int height) {int fd open(dev_path, O_RD…...

Web Worker终极优化指南:4秒卡顿→0延迟的实战蜕变

&#x1f4a1; 导读&#xff1a;从4秒卡顿到丝滑响应 真实痛点场景&#xff1a;当斐波那契数列计算量达10亿次时&#xff0c;页面完全冻结4.2秒&#xff01;通过Web Worker优化后&#xff0c;UI响应时间降至16ms以内。本文手把手带您实现性能蜕变&#xff01; 一、Web Worker核…...

redis中的Lua脚本,redis的事务机制

lua脚本的特点 lua脚本可以操作redis数据库&#xff0c;并且脚本中的代码满足原子性&#xff0c;要么全部被执行&#xff0c;要么全部不执行 lua脚本的语法 脚本示例 lua脚本的草稿&#xff1a; 最终的lua脚本 lua脚本在java里调用的方法 RedisTemplete类里有一个方法&…...

CPU多级缓存与缓存一致性协议

CPU多级缓存与缓存一致性协议 CPU多级缓存和缓存一致性协议是计算机体系结构中优化性能与保证数据正确性的核心机制。以下从缓存层级设计、工作原理、一致性协议&#xff08;如MESI&#xff09;及其实现细节展开说明。 一、为什么需要多级缓存&#xff1f; CPU的计算速度远高…...

Apifox 增强 AI 接口调试功能:自动合并 SSE 响应、展示DeepSeek思考过程

在现代的API接口调试中&#xff0c;效率和精确性对于开发者和测试人员来说至关重要。Apifox&#xff0c;作为一款功能强大的API管理和调试工具&#xff0c;近年来不断提升其用户体验和智能化功能。最近&#xff0c;Apifox 推出了增强版的AI接口调试功能&#xff0c;其中包括自动…...

【电机控制】42步进电机+arduino:WHEELTEC_MS42DDC

轮趣科技 42步进电机arduino:WHEELTEC_MS42DDC 接线方式&#xff1a; WHEELTEC_MS42DDC有两个接口&#xff0c; 一端接口连接配套的DC电源&#xff0c;另外一端只需要用三根线&#xff0c;一根负极连接ardino 的GND&#xff0c;然后把该端口的tx和rx连接到arduino的rx和tx,下…...

使用LangChain构建第一个ReAct Agent

使用LangChain构建第一个ReAct Agent 准备环境 使用Anaconda 安装python 3.10 安装langchain、langchain_openai、langchain_community &#xff08;安装命令 pip install XXX&#xff09; 申请DeepSeek API&#xff1a;https://platform.deepseek.com/api_keys&#xff08;也…...

萝卜头笔作文赏析

在遥远的无寻王国&#xff0c;有这么一支小小的笔诞生了&#xff0c;人们见它又短又小&#xff0c;于是就给它取名叫萝卜头笔。萝卜头笔渐渐长大了&#xff0c;除了身子变粗些&#xff0c;其他什么都没变。一天&#xff0c;萝卜头笔来到了深山老林&#xff0c;那里枝叶繁茂&…...

RT-Thread+STM32L475VET6——USB鼠标模拟

文章目录 前言一、板载资源二、具体步骤1.配置icm20608传感器2.打开CubeMX进行USB配置3. 配置USB3.1 打开USB驱动3.2 声明USB3.3 剪切stm32xxxx_hal_msp.c中的void HAL_PCD_MspInit(PCD_HandleTypeDef* hpcd)和void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd)函数至board.c3.…...

rust 安全性

Rust 是 静态类型&#xff08;statically typed&#xff09; 语言&#xff0c; 也就是说在编译时就必须知道所有变量的类型&#xff0c; 这一点将贯穿整个章节。 C/C的安全问题 内存的不正确访问引发的内存安全问题 由于多个变量指向同一块内存区域导致的数据一致性问题 由于…...

大模型驱动的围术期质控系统全面解析与应用探索

目录 一、引言 1.1 研究背景与意义 1.2 研究目的与方法 1.3 研究创新点 二、大模型技术与围术期管理概述 2.1 大模型技术原理与发展现状 2.2 围术期管理流程与挑战 三、大模型在术前的应用 3.1 病历内涵质控 3.2 智能医学问答与知识查询 3.3 疾病风险预测与评估 3.…...

中兴B863AV3.2-T/B863AV3.1-T2/B863AV3.1-T2K_电信高安_S905L3A-B_安卓9.0_线刷固件包

中兴B863AV3.2-T&#xff0f;B863AV3.1-T2&#xff0f;B863AV3.1-T2K_电信高安_S905L3A-B_安卓9.0_线刷固件包 B863AV3.2-T B863AV3.1-T2 已知可通刷贵州、江苏、贵州、北京、河南、陕西等省份。 线刷方法&#xff1a;&#xff08;新手参考借鉴一下&#xff09; 1、准备好一…...

Android Binder机制

Binder是IPC&#xff08;进程间通信&#xff09;的一种机制&#xff0c;它允许不同的应用或系统服务在不同的进程中安全地交换数据。Binder的核心原理是基于客户端-服务器模型&#xff08;C/S架构)。 一、Binder的定义 1. Binder是Android中的一个类&#xff0c;它继承了IBind…...

【算法】初等数论

初等数论 模 取余&#xff0c;遵循尽可能让商向0靠近的原则&#xff0c;结果的正负和左操作数相同 取模&#xff0c;遵循尽可能让商向负无穷靠近的原则&#xff0c;结果的正负和右操作数相同 7/&#xff08;-3&#xff09;-2.3&#xff0c;产生了两个商-2和-3&#xff0c;取…...

Spring Boot3+Vue2极速整合:10分钟搭建DeepSeek AI对话系统

前言 在生成式AI技术蓬勃发展的今天&#xff0c;大语言模型已成为企业智能化转型和个人效率提升的核心驱动力。作为国产大模型的优秀代表&#xff0c;DeepSeek凭借其卓越的中文语义理解能力和开发者友好的API生态&#xff0c;正在成为构建本土化AI应用的首选平台。 本文将以S…...

Spring事务原理 二

在上一篇博文《Spring事务原理 一》中&#xff0c;我们熟悉了Spring声明式事务的AOP原理&#xff0c;以及事务执行的大体流程。 本文中&#xff0c;介绍了Spring事务的核心组件、传播行为的源码实现。下一篇中&#xff0c;我们将结合案例&#xff0c;来讲解实战中有关事务的易…...

JVM预热

阿里电商平台每年的各种大促活动&#xff0c;对于Java技术来说&#xff0c;其中重要一个操作环节就是预热操作。 目录 预热是什么&#xff1f;为什么要预热&#xff1f; java 程序不预热和预热的调用对比 预热是什么&#xff1f; 预热是指&#xff0c;在 JVM 启动后&#xff0…...

基于flask+vue框架的的医院预约挂号系统i1616(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能:用户,医生,科室信息,就诊信息,医院概况,挂号信息,诊断信息,取消挂号 开题报告内容 基于FlaskVue框架的医院预约挂号系统开题报告 一、研究背景与意义 随着医疗技术的不断进步和人们健康意识的日益增强&#xff0c;医院就诊量逐年增加。传统的现场…...

DeepSeek掘金——SpringBoot 调用 DeepSeek API 快速实现应用开发

Spring Boot 实现 DeepSeek API 调用 1. 项目依赖 在 pom.xml 中添加以下依赖: <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>&l…...

easelog(1)基础C++日志功能实现

EaseLog(1)基础C日志功能实现 Author: Once Day Date: 2025年2月22日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 注&#xff1a;本简易日志组件代码实现参考了Google …...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...

什么是VR全景技术

VR全景技术&#xff0c;全称为虚拟现实全景技术&#xff0c;是通过计算机图像模拟生成三维空间中的虚拟世界&#xff0c;使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验&#xff0c;结合图文、3D、音视频等多媒体元素…...

面试高频问题

文章目录 &#x1f680; 消息队列核心技术揭秘&#xff1a;从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"&#xff1f;性能背后的秘密1.1 顺序写入与零拷贝&#xff1a;性能的双引擎1.2 分区并行&#xff1a;数据的"八车道高速公路"1.3 页缓存与批量处理…...

鸿蒙HarmonyOS 5军旗小游戏实现指南

1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;采用DevEco Studio实现&#xff0c;包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...

五、jmeter脚本参数化

目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...

C++中vector类型的介绍和使用

文章目录 一、vector 类型的简介1.1 基本介绍1.2 常见用法示例1.3 常见成员函数简表 二、vector 数据的插入2.1 push_back() —— 在尾部插入一个元素2.2 emplace_back() —— 在尾部“就地”构造对象2.3 insert() —— 在任意位置插入一个或多个元素2.4 emplace() —— 在任意…...

运行vue项目报错 errors and 0 warnings potentially fixable with the `--fix` option.

报错 找到package.json文件 找到这个修改成 "lint": "eslint --fix --ext .js,.vue src" 为elsint有配置结尾换行符&#xff0c;最后运行&#xff1a;npm run lint --fix...