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推流服务。

b499d4eb-3f37-4dc5-8aa0-28d0b4161da8

三、RTSP 服务代码详解

  1. 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)
	};
}

 

posted @ 2026-03-20 17:28  潇潇O  阅读(8)  评论(0)    收藏  举报