rtsp音视频流媒体网络协议常用于无线图传,目前主要应用领域用:
- 无人机图传
- 安防摄像头图传
- 相机图传
- 其他应用场景媒体传输等
可以说有相机,摄像头的产品上只要有无线音视频传输都应用到了rtsp协议。随着这几年的媒体娱乐,以及各种各样的影像类产品的不断增多,生活中常见的手机,相机,电视,电脑,监控摄像头,无人机,智能家居等产品都包含了音视频传输的功能,让可视,可听,可说带入了人机交互。让产品与用户之间更加具备交互性,可玩性,实用性。所以说对应一个涉及音视频应用的开发者来说,掌握如何使用rtsp协议来实现音视频流媒体传输是非常重要的一项技能。我这里以安防摄像头为例,演示摄像头怎么通过rtsp协议将摄像头采集到的音视频媒体数据传输到手机,PC机等终端设备进行实时显示播放。
本案例使用到的硬件设备有:一台PC电脑、一台手机、一个带网络的摄像头模块。
本案例使用的软件有:live555、vlc、rtsp手机客户端、ubuntu系统(16.04.版本以上)。
我们分三步来完成上图框架的搭建:1、摄像头模组端的rtsp服务器搭建。2、摄像头模组采集音视频编码并进行rtsp推流。3、pc电脑和手机的拉流解码显示。
一、摄像头模组端的rtsp服务器搭建
wget http://www.live555.com/liveMedia/public/live555-latest.tar.gz
- 减压源码包。
tar xvf live555-latest.tar.gz
2. 根据平台配置live555的config配置文件
- 复制live555源码目录下的任意一个config文件,并修改配置文件的工具链为对应平台的工具链, 以及添加安装路径PREFIX=$(pwd)/_install。
cp config.armlinux config.mips-linux-uclibc
- 打开配置文件vim config.mips-linux-uclibc,修改对应平台工具链
3. 编译live555源码
- 执行genMakefiles生成对应平台的Makefile文件
./genMakefiles mips-linux-uclibc
- 执行make -j8进行编译
- 编写一个install.sh文件,将对应的编译出来的库文件和头文件拷贝到对应目录, 内容如下:
- 执行./install.sh。
./install.sh
- 可见编译出来的bin lib include已经存放到了指定的live555-lib安装目录下。
二、摄像头模组采集音视频编码并进行rtsp推流
1、找到对应芯片平台获取音视频的sample。不管你手头的摄像头模组是海思、rk、sigmastar、安霸、君正、全智还是其他的平台的芯片,平台都有对应的SDK,SDK里面都有对应获取到音视频的sample例子。这里我们找到获取H264/H265编码的视频sample,然后找到获取一帧一帧H264的视频接口。因为这里我们会将获取到的H264/H265视频数据打包成rtp包上传到rtsp服务器。大概的逻辑图如下:
2、基于以上编译出来的live555函数库和头文件,调用live555相应的函数接口和类创建一个rtsp服务器,其服务器实现代码如下:
#include <liveMedia.hh>
#include <BasicUsageEnvironment.hh>
#include <GroupsockHelper.hh>
// 定义一个RTSP服务器的类
class RTSPServer {
public:
RTSPServer(UsageEnvironment& env, Port rtspPort);
virtual ~RTSPServer();
private:
UsageEnvironment& fEnv;
RTSPServer* fRtspServer;
};
// 构造函数
RTSPServer::RTSPServer(UsageEnvironment& env, Port rtspPort)
: fEnv(env) {
fRtspServer = RTSPServer::createNew(env, rtspPort, NULL, 65);
if (fRtspServer == NULL) {
env << "创建RTSP服务器失败: " << env.getResultMsg() << "\n";
exit(1);
}
}
// 析构函数
RTSPServer::~RTSPServer() {
Medium::close(fRtspServer);
}
// 主函数
int main(int argc, char** argv) {
// 初始化live555环境
TaskScheduler* scheduler = BasicTaskScheduler::createNew();
UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);
// 设置RTSP服务器
Port rtspPort = 8554; // 根据需要更改端口号
RTSPServer rtspServer(*env, rtspPort);
// 启动事件循环
env->taskScheduler().doEventLoop();
return 0;
}
3、将获取到的H264/H265打包成rtp推流到rtsp服务器,要实现将获取到的H.264编码数据打包成RTP包并推流到RTSP服务器,你需要做以下几步:
(1)调用 get_h264_encodeframe() 函数获取H.264编码数据。
(2)将H.264编码数据打包成RTP包。
(3)使用live555库中的 FramedSource 类创建一个新的 RTP 数据源。
(4)将 RTP 数据源添加到 RTSP 服务器中。
实现代码如下:
#include <liveMedia.hh>
#include <BasicUsageEnvironment.hh>
#include <GroupsockHelper.hh>
// 获取H.264编码数据的函数接口
extern int get_h264_encodeframe(unsigned char* buffer, int bufferSize);
// RTP 数据源类,用于将H.264数据打包成RTP包
class H264RTPSource : public FramedSource {
public:
static H264RTPSource* createNew(UsageEnvironment& env);
virtual ~H264RTPSource();
void doGetNextFrame();
static void deliverFrameStub(void* clientData);
private:
H264RTPSource(UsageEnvironment& env);
void deliverFrame();
private:
unsigned char* fBuffer;
int fBufferSize;
};
H264RTPSource::H264RTPSource(UsageEnvironment& env)
: FramedSource(env), fBuffer(nullptr), fBufferSize(0) {
// Allocate buffer for H.264 frame
fBufferSize = 100000; // Adjust as needed
fBuffer = new unsigned char[fBufferSize];
}
H264RTPSource::~H264RTPSource() {
delete[] fBuffer;
}
void H264RTPSource::doGetNextFrame() {
if (fBuffer == nullptr) {
handleClosure();
return;
}
// Get H.264 frame from the function interface
int frameSize = get_h264_encodeframe(fBuffer, fBufferSize);
if (frameSize <= 0) {
handleClosure();
return;
}
// Deliver the frame
fFrameSize = frameSize;
fPresentationTime.tv_sec = fPresentationTime.tv_usec = 0;
fDurationInMicroseconds = 0;
fFrameType = 0;
fNumTruncatedBytes = 0;
afterGetting(this);
}
void H264RTPSource::deliverFrameStub(void* clientData) {
reinterpret_cast<H264RTPSource*>(clientData)->deliverFrame();
}
void H264RTPSource::deliverFrame() {
if (!isCurrentlyAwaitingData()) {
return;
}
// Deliver H.264 frame as RTP packet
if (fFrameSize > 0) {
// Create RTP packet and send it
// Code to create RTP packet and send it to RTSP server
}
// Continue fetching next frame
doGetNextFrame();
}
// RTSP服务器类
class RTSPServer {
public:
RTSPServer(UsageEnvironment& env, Port rtspPort);
virtual ~RTSPServer();
void addH264RTPSource(H264RTPSource* rtpSource);
private:
UsageEnvironment& fEnv;
RTSPServer* fRtspServer;
ServerMediaSession* fSession;
};
RTSPServer::RTSPServer(UsageEnvironment& env, Port rtspPort)
: fEnv(env), fRtspServer(nullptr), fSession(nullptr) {
fRtspServer = RTSPServer::createNew(env, rtspPort, NULL, 65);
if (fRtspServer == NULL) {
env << "Failed to create RTSP server: " << env.getResultMsg() << "\n";
exit(1);
}
}
RTSPServer::~RTSPServer() {
Medium::close(fRtspServer);
}
void RTSPServer::addH264RTPSource(H264RTPSource* rtpSource) {
fSession = ServerMediaSession::createNew(fEnv, "H264Stream", NULL, "H.264 RTP Stream");
fSession->addSubsession(RTPSink::createNew(fEnv, rtpSource));
fRtspServer->addServerMediaSession(fSession);
}
// 主函数
int main(int argc, char** argv) {
// 初始化live555环境
TaskScheduler* scheduler = BasicTaskScheduler::createNew();
UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);
// 设置RTSP服务器
Port rtspPort = 8554; // 根据需要更改端口号
RTSPServer rtspServer(*env, rtspPort);
// 创建H.264 RTP数据源
H264RTPSource* rtpSource = H264RTPSource::createNew(*env);
rtspServer.addH264RTPSource(rtpSource);
// 启动事件循环
env->taskScheduler().doEventLoop();
return 0;
}
三、pc电脑或者手机端拉流解码显示
1、pc电脑vlc拉流看图,输入rtsp拉流地址,点击播放即可。
简单记录,有什么不足的地方还请各位指出,非常感谢!