xop实现H.264的RTSP推流
一、什么是RTSP?
rtsp全称实时流协议,简单说就是音视频的遥控协议,他不直接传输视频画面,只负责指挥。让客户端(比如VLC、手机监控APP)向服务器发送“播放、暂停、停止、拉流”等指令,而实际的视频数据(比如H.264),会通过配套的RTP协议传输。
以我做过的某一个项目为例。 RK3568 摄像头获取到的数据是 BGR888格式,需通过 RGA 将摄像头帧格式转为 MPP 支持的格式(RGB888),由 MPP 调用 VPU 硬件编码为 H.264 码流。最后将H.264流,通过 RTSP 协议,实时推送给一个流媒体服务器,别人就可以通过VLC、播放器、网页观看。
二、xop实现RTSP推流
xop是国内开发者维护的跨平台轻量级网络库(核心聚焦音视频传输),专门适配 Linux/ARM 嵌入式场景。相比 live555(传统 RTSP 库),xop 代码更精简、API 更易用、编译体积更小,适合 RK3568 等资源受限的嵌入式平台,且原生支持 H.264/H.265/PCM 的 RTSP 推流 / 拉流。
接下来实现RTSP推流的例子
从github上拉取源码,里面有example文件,make完成后会生成RTSP SERVER的例子
git clone https://github.com/PHZ76/RtspServer.git
cd RtspServer
make -j4
example文件夹有现成的RTSP服务,启动服务
cd example
./rtsp_h264_file test.h264
用 VLC/ffplay 访问:rtsp://你的IP:554/live 即可播放,至此实现了一个简单的rtsp推流服务。

三、RTSP 服务代码详解
- main 函数入口
int main(int argc, char **argv)
{
// 1. 检查参数,打开H264文件
if(argc != 2) {
printf("Usage: %s test.h264 \n", argv[0]);
return 0;
}
H264File h264_file;
if(!h264_file.Open(argv[1])) {
printf("Open %s failed.\n", argv[1]);
return 0;
}
// 2. 配置RTSP服务器参数
std::string suffix = "live";
std::string ip = "127.0.0.1";
std::string port = "554";
std::string rtsp_url = "rtsp://" + ip + ":" + port + "/" + suffix;
// 3. 创建事件循环和RTSP服务器
std::shared_ptr<xop::EventLoop> event_loop(new xop::EventLoop());
std::shared_ptr<xop::RtspServer> server = xop::RtspServer::Create(event_loop.get());
if (!server->Start("0.0.0.0", atoi(port.c_str()))) { // 监听所有网卡的554端口
printf("RTSP Server listen on %s failed.\n", port.c_str());
return 0;
}
// 4. 可选:配置认证(需定义AUTH_CONFIG宏)
#ifdef AUTH_CONFIG
server->SetAuthConfig("-_-", "admin", "12345");
#endif
// 5. 创建媒体会话
xop::MediaSession *session = xop::MediaSession::CreateNew("live");
session->AddSource(xop::channel_0, xop::H264Source::CreateNew()); // 添加H264流源
//session->StartMulticast(); // 可选:开启组播
// 6. 客户端连接/断开回调
session->AddNotifyConnectedCallback([] (xop::MediaSessionId sessionId, std::string peer_ip, uint16_t peer_port){
printf("RTSP client connect, ip=%s, port=%hu \n", peer_ip.c_str(), peer_port);
});
session->AddNotifyDisconnectedCallback([](xop::MediaSessionId sessionId, std::string peer_ip, uint16_t peer_port) {
printf("RTSP client disconnect, ip=%s, port=%hu \n", peer_ip.c_str(), peer_port);
});
// 7. 将会话添加到服务器
xop::MediaSessionId session_id = server->AddSession(session);
// 8. 启动推送H264帧的线程
std::thread t1(SendFrameThread, server.get(), session_id, &h264_file);
t1.detach(); // 分离线程,后台运行
std::cout << "Play URL: " << rtsp_url << std::endl;
// 9. 主线程阻塞
while (1) {
xop::Timer::Sleep(100);
}
getchar();
return 0;
}
2. SendFrameThread:帧推送线程
void SendFrameThread(xop::RtspServer* rtsp_server, xop::MediaSessionId session_id, H264File* h264_file)
{
int buf_size = 2000000;
std::unique_ptr<uint8_t> frame_buf(new uint8_t[buf_size]); // 帧缓冲区
while(1) {
bool end_of_frame = false;
// 读取一帧H264数据
int frame_size = h264_file->ReadFrame((char*)frame_buf.get(), buf_size, &end_of_frame);
if(frame_size > 0) {
// 封装为AVFrame结构体
xop::AVFrame videoFrame = {0};
videoFrame.type = 0; // 0表示视频帧(H264)
videoFrame.size = frame_size;
videoFrame.timestamp = xop::H264Source::GetTimestamp(); // 获取时间戳(毫秒级)
videoFrame.buffer.reset(new uint8_t[videoFrame.size]);
memcpy(videoFrame.buffer.get(), frame_buf.get(), frame_size);
// 推送帧到RTSP服务器
rtsp_server->PushFrame(session_id, xop::channel_0, videoFrame);
}
else {
break; // 读取失败则退出循环
}
xop::Timer::Sleep(40); // 约25fps(1000/40=25)
};
}

浙公网安备 33010602011771号