海思Hi3516平台Live555 RTSP服务器移植实战指南
2026/9/3 9:00:40 网站建设 项目流程

简介:本资源是面向嵌入式音视频开发工程师与海思平台移植实践者的live555 RTSP服务器移植工程包,聚焦于海思Hi3516(ARM Cortex-A7)平台的完整适配落地,解决在国产安防芯片上构建低延迟、高稳定视频流转发服务的核心难题。压缩包共47个文件,涵盖11个编译目标文件(.o)、8个头文件(.h/.hh)、7个C源码(.c)、4个C++源码(.cpp)及关键构建脚本(Makefile、makecompile、replace.csh)和调试工具(gdb-arm-hisiv300-linux、gdbserver),总大小4.21MB;其中DynamicRTSPServer、H264VideoLiveServerMediaSubsession、LiveDeviceSource等模块已针对海思共享内存数据获取与RTP封装完成定制化改造。已有1817人学习下载,资源提供可直接编译运行的交叉编译工程结构、海思专用线程/信号处理机制(rtsp_threads.c/h、rtsp_signal.c/h)、初始化与销毁流程(rtsp_init/fini.c/h)及典型H.264流媒体子会话实现,大幅降低从零移植门槛,助力开发者快速验证RTSP推流、调试内存拷贝瓶颈并开展性能优化。

1. 项目概述:为什么要在海思3516上折腾Live555?

如果你手头正好有一块海思Hi3516的开发板,想在上面实现一个RTSP流媒体服务器,把板子上的摄像头画面或者编码后的视频流推出去,那么“Live555海思平台移植”这个项目就是你绕不开的一道坎。这活儿我干过不止一次,从Hi3516A到Hi3516DV300都折腾过,过程说不上多复杂,但里头的坑和门道,没踩过的人还真容易迷糊。

简单来说,Live555是一个用C++编写的开源流媒体处理库,功能非常纯粹和经典:它实现了RTSP/RTP/RTCP等流媒体协议栈。你可以基于它,用相对较少的代码,快速搭建起一个RTSP服务器(Server)或客户端(Client)。而海思Hi3516系列芯片,是安防监控、物联网摄像头等领域最常见的SoC之一,它内置了强大的视频编码器(H.264/H.265),但通常不直接提供完整的、可编程的RTSP服务器实现。官方的MPP(媒体处理平台)样例里,往往只给到网络发送裸码流的demo。所以,把Live555移植到海思平台上,本质就是让Live555这个“协议大脑”去驱动海思的“编码肌肉”,从而输出标准的、能被VLC、FFmpeg、EasyPlayer等通用播放器识别的RTSP视频流。

这个项目的价值非常直接:它让你的海思设备从一个单纯的“编码盒子”,变成了一个标准的网络流媒体源。无论是用于设备调试、方案验证,还是集成到更大的视频系统中,都提供了极大的便利。适合谁呢?首先是海思平台的嵌入式开发工程师,其次是做IPC(网络摄像机)、NVR(网络视频录像机)或智能视频分析设备的开发者,甚至是对流媒体协议感兴趣的嵌入式爱好者,都可以通过这个项目深入理解从编码到网络传输的完整链条。

2. 核心思路与方案选型:为什么是Live555?还有其他选择吗?

决定移植Live555之前,我们得先盘算一下手头的选项。在海思平台上实现RTSP服务,大体有三条路:

  1. 使用海思SDK自带的网络传输模块:海思MPP样本里通常有sample_venc结合socket发送码流的例子。但这只是简单的TCP/UDP传输,需要自己实现RTSP信令交互、RTP打包、SDP描述等一整套复杂逻辑,相当于重新造轮子,对大多数项目来说性价比极低。
  2. 集成其他RTSP服务器库:比如gStreamerrtspserverMediaMTX(原rtsp-simple-server)或者一些商业库。gStreamer功能强大但体系庞大,交叉编译和裁剪对嵌入式平台是个挑战;MediaMTX用Go编写,虽然部署简单,但在资源受限的海思平台上运行一个Go程序可能不是最优解。
  3. 移植Live555:这是最经典、最轻量级的选择。Live555代码风格古老但稳定,核心库体积小,功能专注(就是RTSP/RTP/RTCP),交叉编译相对容易。更重要的是,它在嵌入式领域有广泛的成功应用案例,社区里能找到的参考也多。

所以,选择Live555进行移植,是基于以下几个核心考量:轻量、专注、可控、有迹可循。你不需要一个全功能的媒体框架,你只需要一个可靠的协议栈,把海思编码器产生的H.264/H.265码流,按照标准规范打包发送出去。Live555完美契合这个需求。

整个移植工作的核心思路可以概括为:“搭桥”。我们需要在海思的编码数据输出端(通常是通过HI_MPI_VENC_GetStream获取码流帧)和Live555的媒体输入源之间,搭建一座数据桥梁。具体来说,就是实现一个Live555框架下的FramedSource子类。这个子类负责从海思的编码缓冲区中“拉取”或“等待”视频帧数据,然后以Live555能理解的方式(比如通过afterGetting回调)提交给下游的RTPSink进行RTP打包和发送。同时,我们还需要一个ServerMediaSubsession的子类来管理这个自定义的Source,并将其纳入RTSP会话的生命周期管理中。

3. 环境准备与源码获取:工欲善其事,必先利其器

动手之前,先把“战场”布置好。这里主要分两部分:海思开发环境和Live555源码。

3.1 海思SDK与交叉编译工具链

这是基础中的基础。你需要从海思官方(或你的方案商)获取对应你芯片型号的SDK包,比如Hi3516EV200_SDK_Vx.x.x.x。解压后,重点关注以下内容:

  • osdrv/opensource/toolchain/:这里面放着交叉编译工具链。对于Hi3516(通常是arm-hisiv300-linux或arm-hisiv400-linux),工具链路径类似arm-hisiv300-linux/bin/arm-hisiv300-linux-gcc。你需要将其加入系统的PATH环境变量。
    export PATH=/your_sdk_path/osdrv/opensource/toolchain/arm-hisiv300-linux/bin:$PATH
  • mpp/:媒体处理平台(MPP)的头文件和库文件。后续我们编译自己的应用程序和Live555时,需要链接这些库(如libmpi.a,libive.a,libhigo.a等)。
  • sample/:参考样例,特别是sample_venc。这是我们理解如何获取编码码流的关键。

注意:不同版本SDK的目录结构可能有细微差异,请以你手中的实际SDK为准。确保你的Ubuntu编译主机(或其他Linux发行版)已经安装了基本的开发工具,如make,g++(用于本地编译Live555的生成工具)。

3.2 Live555源码下载与本地配置

Live555官网(live555.com)提供了源码压缩包。下载最新稳定版即可。我们先在本地x86电脑上进行一些预处理。

wget http://www.live555.com/liveMedia/public/live555-latest.tar.gz tar -xzf live555-latest.tar.gz cd live555

在编译给海思用的库之前,我们需要先用本地编译器生成一些必要的工具(如genWatchTables),这些工具在配置阶段会被使用。执行:

./genMakefiles linux make -j4

这一步会在本地生成live555ProxyServer等测试程序,我们主要目的是生成那些工具。编译完成后,先别急着清理,我们接下来要修改配置用于交叉编译。

4. 交叉编译Live555库:关键配置与编译脚本

这是移植的核心步骤之一。Live555使用一个名为config.*的文件来定义编译环境。我们需要为海思平台创建一个新的配置。

  1. 创建海思平台配置文件: 在Live555源码根目录,复制一个现有的配置模板,比如config.linux,命名为config.hi3516

    cp config.linux config.hi3516
  2. 编辑config.hi3516文件: 这个文件需要根据你的交叉编译工具链和海思SDK路径进行修改。以下是一个针对arm-hisiv300-linux的配置示例,关键修改处已加注释:

    # 定义交叉编译工具前缀 COMPILE_OPTS = $(INCLUDES) -I. -I/your_sdk_path/mpp/include -I/your_sdk_path/mpp/include/hi_common -I/your_sdk_path/mpp/include/hi_mpi -O2 -DSOCKLEN_T=socklen_t -DNO_SSTREAM=1 -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -fPIC # 将g++替换为交叉编译器的g++ C_COMPILER = arm-hisiv300-linux-gcc C_FLAGS = $(COMPILE_OPTS) CPLUSPLUS_COMPILER = arm-hisiv300-linux-g++ CPLUSPLUS_FLAGS = $(COMPILE_OPTS) -Wall -DBSD=1 # 链接器也使用交叉编译器的 LINK = arm-hisiv300-linux-g++ -o LINK_OPTS = -L/your_sdk_path/mpp/lib -lmpi -lhdmi -lhigo -lhi_common -lhi_memory -lpthread -ldl CONSOLE_LINK_OPTS = $(LINK_OPTS) LIBRARY_LINK = arm-hisiv300-linux-g++ -o # 指定库文件后缀和生成命令 LIBRARY_LINK_OPTS = -shared -Wl,-soname,$(NAME).so $(LINK_OPTS) LIB_SUFFIX = .so SHORT_LIB_SUFFIX = .so # 关键:指定ranlib为交叉编译工具链中的,避免链接错误 RANLIB = arm-hisiv300-linux-ranlib

    重要解释

    • -I参数:添加了海思MPP的头文件路径,这样Live555代码里才能找到海思的数据类型和函数声明。
    • -L-l参数:指定了海思MPP库的路径和需要链接的库。-lmpi是最核心的媒体处理接口库。
    • -fPIC:生成位置无关代码,这是编译动态库所必需的。
    • RANLIB:这个很容易被忽略。如果使用交叉编译工具链,必须指定对应的ranlib,否则在生成静态库(.a文件)时会报错。
  3. 生成交叉编译的Makefile并编译

    ./genMakefiles hi3516 # 使用我们刚创建的config.hi3516 make -j4

    如果一切顺利,你会在当前目录下看到为ARM平台生成的库文件(libBasicUsageEnvironment.so,libgroupsock.so,libliveMedia.so,libUsageEnvironment.so)以及一些可执行文件(如testProgs/testOnDemandRTSPServer)。

  4. 提取必要的头文件和库: 编译成功后,建议将生成的四个动态库(.so文件)和Live555的核心头文件(位于include/目录下,以及BasicUsageEnvironment/include/,groupsock/include/,liveMedia/include/,UsageEnvironment/include/)整理到一个独立的目录中,方便后续你的应用程序链接。例如,创建一个live555_for_hi3516文件夹,里面包含includelib两个子目录。

实操心得:第一次交叉编译很大概率会失败,常见错误包括找不到海思的头文件、链接时找不到海思的库、或者ranlib错误。请务必静下心来,根据错误信息逐行检查config.hi3516中的路径和工具名是否正确。另外,海思SDK不同版本库名可能有变化,如果遇到undefined reference toHI_MPI_XXX这类错误,去/your_sdk_path/mpp/lib目录下看看实际的库文件名是什么,相应修改LINK_OPTS`。

5. 实现海思码流Source:连接数据与协议的关键桥梁

现在来到了最核心的编码部分:创建自定义的FramedSource。这是Live555获取媒体数据的源头,我们需要在这里对接海思的编码输出。

5.1 设计数据流模型

海思获取编码码流的典型方式是在一个循环中调用HI_MPI_VENC_GetStream,它会阻塞直到有一帧编码数据准备好。而Live555的FramedSource是通过事件驱动(doGetNextFrame函数)来被动获取数据的。这里存在一个生产-消费模型的差异。通常有两种处理方式:

  1. 阻塞等待模式:在doGetNextFrame里直接调用HI_MPI_VENC_GetStream,直到拿到一帧数据,然后返回。这种方式简单,但会阻塞Live555的事件循环,如果获取帧耗时过长,会影响RTSP协议响应和其他会话的处理。
  2. 缓冲区+信号量模式(推荐):创建一个独立的线程(或复用海思的编码线程),专门负责循环调用HI_MPI_VENC_GetStream,将获取到的码流帧放入一个环形缓冲区。doGetNextFrame则从缓冲区中取数据,如果缓冲区为空,则设置一个定时器延迟重试,或者利用信号量/条件变量让doGetNextFrame等待。这种方式更高效,解耦了数据生产和协议处理。

我们采用第二种模式。设计一个类HisiH264FramedSource,它继承自FramedSource,并内部管理一个缓冲区队列和一个数据生产线程。

5.2 关键代码结构解析

以下是一个高度简化的代码框架,用于说明核心逻辑:

// HisiH264FramedSource.hh #ifndef _HISI_H264_FRAMED_SOURCE_HH #define _HISI_H264_FRAMED_SOURCE_HH #include <FramedSource.hh> #include <pthread.h> #include <queue> // 定义一个结构体存放从海思获取的一帧数据 typedef struct { unsigned char* data; // 码流数据指针 unsigned int size; // 数据长度 unsigned long long pts; // 时间戳 bool isKeyFrame; // 是否为关键帧(I帧) } HisiFrameData; class HisiH264FramedSource: public FramedSource { public: static HisiH264FramedSource* createNew(UsageEnvironment& env, int vencChn); // ... 其他接口 protected: HisiH264FramedSource(UsageEnvironment& env, int vencChn); virtual ~HisiH264FramedSource(); private: // 重写父类虚函数,当Live555需要数据时调用 virtual void doGetNextFrame(); // 一个静态函数或成员函数,作为数据生产线程的入口 static void* dataFeederThread(void* clientData); void feedData(); // 实际的数据填充循环 // 处理从海思获取的原始帧,进行H.264 NALU分割等预处理 void processHisiFrame(const VENC_STREAM_S& stStream); private: int fVencChn; // 海思编码通道号 pthread_t fFeederTid; // 数据生产线程ID std::queue<HisiFrameData> fFrameQueue; // 帧数据队列 pthread_mutex_t fMutex; // 保护队列的互斥锁 pthread_cond_t fCond; // 条件变量,用于线程同步 EventTriggerId fEventTriggerId; // Live555内部事件触发器ID bool fIsFeeding; // 线程控制标志 }; #endif
// HisiH264FramedSource.cpp #include "HisiH264FramedSource.hh" #include "hi_comm_venc.h" #include "mpi_venc.h" #include <unistd.h> // 线程函数,不断从海思编码通道获取数据 void* HisiH264FramedSource::dataFeederThread(void* clientData) { HisiH264FramedSource* source = (HisiH264FramedSource*)clientData; source->feedData(); return NULL; } void HisiH264FramedSource::feedData() { VENC_STREAM_S stStream; VENC_PACK_S* pstPack; HI_S32 s32Ret; while (fIsFeeding) { // 1. 清空上次的数据结构 memset(&stStream, 0, sizeof(VENC_STREAM_S)); // 2. 阻塞获取码流,超时时间可根据需要设置 s32Ret = HI_MPI_VENC_GetStream(fVencChn, &stStream, HI_TRUE); if (s32Ret != HI_SUCCESS) { usleep(10000); // 获取失败,短暂休眠避免CPU空转 continue; } // 3. 处理获取到的码流帧 processHisiFrame(stStream); // 4. 释放海思的码流缓冲区(非常重要!否则会内存泄漏) s32Ret = HI_MPI_VENC_ReleaseStream(fVencChn, &stStream); if (s32Ret != HI_SUCCESS) { // 记录错误日志 } } } void HisiH264FramedSource::processHisiFrame(const VENC_STREAM_S& stStream) { pthread_mutex_lock(&fMutex); // 遍历一帧中的所有包(海思一帧可能分多个包传输) for (int i = 0; i < stStream.u32PackCount; ++i) { pstPack = &stStream.pstPack[i]; HisiFrameData frame; frame.size = pstPack->u32Len - pstPack->u32Offset; // 有效数据长度 frame.data = new unsigned char[frame.size]; // 拷贝数据,注意偏移量u32Offset memcpy(frame.data, pstPack->pu8Addr + pstPack->u32Offset, frame.size); frame.pts = pstPack->u64PTS; frame.isKeyFrame = (pstPack->DataType.enH264EType == H264E_NALU_ISLICE); // 判断I帧 fFrameQueue.push(frame); } // 通知等待数据的线程(即doGetNextFrame) pthread_cond_signal(&fCond); pthread_mutex_unlock(&fMutex); } void HisiH264FramedSource::doGetNextFrame() { pthread_mutex_lock(&fMutex); if (fFrameQueue.empty()) { // 队列为空,设置一个延迟事件,比如20ms后再次尝试 nextTask() = envir().taskScheduler().scheduleDelayedTask(20000, (TaskFunc*)FramedSource::afterGetting, this); pthread_mutex_unlock(&fMutex); return; } HisiFrameData frame = fFrameQueue.front(); fFrameQueue.pop(); pthread_mutex_unlock(&fMutex); // 检查输出缓冲区是否足够大 if (frame.size > fMaxSize) { fFrameSize = fMaxSize; fNumTruncatedBytes = frame.size - fMaxSize; // 可以选择只拷贝部分,或者处理错误 } else { fFrameSize = frame.size; fNumTruncatedBytes = 0; } // 将数据拷贝到Live555提供的缓冲区fTo memcpy(fTo, frame.data, fFrameSize); // 设置帧信息 fPresentationTime = frame.pts; // 注意时间戳单位转换,海思是微秒,Live555需要秒 // fDurationInMicroseconds = ... // 可以根据帧率计算每帧持续时间 // 关键:标记是否为关键帧,影响RTP打包 if (frame.isKeyFrame) { // 可能需要设置一些内部标志,具体取决于后续的Sink如何处理 } // 释放我们分配的内存 delete[] frame.data; // 通知Live555数据已就绪,进行后续处理(RTP打包等) afterGetting(this); }

5.3 实现ServerMediaSubsession

有了FramedSource,我们还需要一个ServerMediaSubsession来创建和管理它。这个类负责在RTSP客户端发起SETUP请求时,创建对应的RTPSink和我们的HisiH264FramedSource,并将它们关联起来。

// HisiH264ServerMediaSubsession.hh #include <H264VideoFileServerMediaSubsession.hh> class HisiH264ServerMediaSubsession: public H264VideoFileServerMediaSubsession { public: static HisiH264ServerMediaSubsession* createNew(UsageEnvironment& env, int vencChn); protected: HisiH264ServerMediaSubsession(UsageEnvironment& env, int vencChn); virtual ~HisiH264ServerMediaSubsession(); // 重写关键函数,返回我们自定义的FramedSource virtual FramedSource* createNewStreamSource(unsigned clientSessionId, unsigned& estBitrate); // 重写此函数,创建对应的RTPSink virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic, FramedSource* inputSource); private: int fVencChn; };

createNewStreamSource函数中,直接return HisiH264FramedSource::createNew(envir(), fVencChn);即可。

6. 整合与主程序搭建:让服务器跑起来

现在我们需要一个主程序,初始化海思的MPP系统、启动编码,然后创建Live555的RTSP服务器。

  1. 初始化海思MPP:这部分代码可以参考海思的sample_venc。主要步骤包括:

    • HI_MPI_SYS_Init()系统初始化。
    • HI_MPI_VPSS_Init()/HI_MPI_VENC_Init()初始化VPSS和VENC模块。
    • 配置并启动VI(视频输入)、VPSS(视频处理)、VENC(视频编码)绑定关系,让原始图像经过处理最终被编码成H.264码流。
  2. 创建RTSP服务器

    #include <liveMedia.hh> #include <BasicUsageEnvironment.hh> #include "HisiH264ServerMediaSubsession.hh" int main(int argc, char** argv) { // 1. 初始化海思MPP系统(省略详细代码) // ... // 2. 创建Live555调度器和环境 TaskScheduler* scheduler = BasicTaskScheduler::createNew(); UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler); // 3. 创建RTSPServer,监听554端口 RTSPServer* rtspServer = RTSPServer::createNew(*env, 554, NULL); if (rtspServer == NULL) { *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n"; exit(1); } // 4. 创建我们的媒体会话子会话,假设使用编码通道0 ServerMediaSession* sms = ServerMediaSession::createNew(*env, "live", "Hisi Live Stream", "Session from Hi3516"); sms->addSubsession(HisiH264ServerMediaSubsession::createNew(*env, 0)); // vencChn = 0 rtspServer->addServerMediaSession(sms); // 5. 打印访问URL char* url = rtspServer->rtspURL(sms); *env << "Play this stream using the URL: \"" << url << "\"\n"; delete[] url; // 6. 进入事件循环,永不返回 env->taskScheduler().doEventLoop(); return 0; // 实际上不会执行到这里 }
  3. 编译你的应用程序: 编写一个Makefile,链接海思的MPP库和你编译好的Live555库。

    CC = arm-hisiv300-linux-gcc CXX = arm-hisiv300-linux-g++ CFLAGS = -I./live555_for_hi3516/include -I/your_sdk_path/mpp/include -O2 -fPIC LDFLAGS = -L./live555_for_hi3516/lib -L/your_sdk_path/mpp/lib LIBS = -lliveMedia -lgroupsock -lBasicUsageEnvironment -lUsageEnvironment -lmpi -lhdmi -lhigo -lhi_common -lhi_memory -lpthread -ldl -lstdc++ TARGET = hisi_rtsp_server SRCS = main.cpp HisiH264FramedSource.cpp HisiH264ServerMediaSubsession.cpp OBJS = $(SRCS:.cpp=.o) all: $(TARGET) $(TARGET): $(OBJS) $(CXX) $(LDFLAGS) -o $@ $^ $(LIBS) .cpp.o: $(CXX) $(CFLAGS) -c $< -o $@ clean: rm -f $(OBJS) $(TARGET)

7. 部署、测试与问题排查实录

将编译生成的hisi_rtsp_server可执行文件以及Live555的四个动态库(lib*.so)拷贝到海思板子的文件系统中(例如/usr/lib/或与可执行文件同目录)。确保库文件路径能被系统找到(可通过设置LD_LIBRARY_PATH环境变量)。

在板子上运行:

./hisi_rtsp_server

如果看到输出Play this stream using the URL: "rtsp://<板子IP>:554/live",说明服务器启动成功。

7.1 测试方法

  1. 使用VLC测试:在PC上打开VLC,选择“媒体” -> “打开网络串流”,输入rtsp://板子IP:554/live,点击播放。
  2. 使用FFplay测试:在命令行输入ffplay -rtsp_transport tcp rtsp://板子IP:554/live。使用tcp传输可以避免UDP在复杂网络环境下的丢包问题,便于初步调试。
  3. 使用openRTSP测试(Live555自带工具):可以将流保存为文件。./openRTSP -v -t rtsp://板子IP:554/live > test.264

7.2 常见问题与排查技巧

以下是我在多次移植中遇到的典型问题及解决方案,整理成了速查表:

问题现象可能原因排查思路与解决方案
服务器启动失败,提示“Failed to create RTSP server”1. 554端口被占用。
2. 动态库未找到或加载失败。
1. 使用netstat -tlnp查看端口占用,换用其他端口(如8554)。
2. 检查LD_LIBRARY_PATH,或直接将.so库放到/lib/usr/lib下。用ldd hisi_rtsp_server查看所有依赖库是否都能找到。
VLC能连接但无法播放,黑屏或瞬间断开1. SDP信息错误(如编码类型、分辨率、帧率不匹配)。
2.FramedSource没有正确提供关键帧(I帧)。
3. 时间戳(fPresentationTime)设置错误。
1. 在HisiH264ServerMediaSubsession::createNewRTPSink中,确保H264VideoRTPSinkprofile-level-idpacketization-mode参数正确。可以在doGetNextFrame里打印前几个字节,确认是H.264 NALU起始码(0x00 0x00 0x00 0x01)。
2. 确保processHisiFrame中正确识别了I帧(H264E_NALU_ISLICE),并且在doGetNextFrame后,RTPSink能知道这是关键帧。对于H.264,关键帧的第一个NALU必须是SPS,然后是PPS,接着是IDR Slice。确保你的数据队列是按这个顺序提供数据的。
3. 海思的PTS是微秒,需要转换为秒:fPresentationTime = frame.pts / 1000000.0
播放卡顿,延迟大1. 数据生产(编码)跟不上消费(网络发送)。
2. 网络带宽不足或UDP丢包严重。
3. 缓冲区队列设计不合理,积压太多帧。
1. 降低编码分辨率或帧率,或检查海思编码通道是否配置正确。
2. 尝试在VLC或ffplay中使用-rtsp_transport tcp选项。在Live555端,可以调整OutPacketBuffer::maxSize(默认约600KB)增大网络缓冲区。
3. 在FramedSource中设置合理的队列长度,当队列过长时丢弃非关键帧,确保实时性。
内存泄漏,运行一段时间后程序崩溃1.HI_MPI_VENC_ReleaseStream未调用。
2.HisiFrameData中的data指针未释放。
3. Live555内部对象未正确销毁。
1.绝对确保每次HI_MPI_VENC_GetStream后,都必须有对应的HI_MPI_VENC_ReleaseStream,这是海思MPP的硬性要求。
2. 在doGetNextFramememcpy完成后,立即delete[] frame.data
3. 程序通常不会正常退出,但如果需要,需在析构函数中停止数据线程,清空队列,并调用Medium::close()
交叉编译链接失败,提示海思MPI函数未定义1. 链接库顺序不对。
2. 库路径错误或库文件缺失。
3. 使用了错误的工具链。
1. 调整Makefile-l的顺序,被依赖的库放在后面。尝试将-lmpi等海思库放在命令末尾。
2. 使用-L明确指定海思库的绝对路径。用`arm-hisiv300-linux-nm -D libmpi.so

7.3 性能优化与稳定性建议

  • 线程安全是重中之重fFrameQueue的读写(pushpop)必须用互斥锁(pthread_mutex_t)保护。条件变量(pthread_cond_t)用于高效同步生产者和消费者。
  • 错误处理要健壮HI_MPI_VENC_GetStream可能返回错误,网络也可能断开。你的代码需要能处理这些异常,比如记录日志、尝试恢复编码通道、或者优雅地关闭会话。
  • SPS/PPS的发送:H.264的SPS和PPS参数集需要在会话开始时,以及每个关键帧之前发送。Live555的H264VideoRTPSink通常能处理,但你需要确保你的FramedSource在流开始时能提供这些NALU。海思编码器在创建通道后,可以通过HI_MPI_VENC_GetH264SpsPps等函数主动获取。
  • 码流控制:如果网络带宽有限,可以考虑在FramedSource中根据网络状况动态调整海思编码器的码率(通过HI_MPI_VENC_SetRcParam),实现简单的码流控制。

移植完成后,你得到的不仅仅是一个能在海思3516上运行的RTSP服务器,更是一套深入理解嵌入式流媒体系统数据流、线程同步和协议栈的实践经验。这套框架稍作修改,同样可以应用于其他平台,或者扩展支持H.265、音频流等功能。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询