代码实现rtsp推流拉流的方法(自己总结)

代码实现rtsp推流拉流的方法

理论上两种方法都可以实现硬件软件编解码

这个也可以参考 RTSP视频推流方法汇总_rtsp-simple-server-CSDN博客

f026b9f76543081b2c9ba7dc859db752.png

1. opencv接口

推流用 VideoWriter()

这个硬件编码软件编码都可以,如果软件编码把编码器由omxh265enc改为x264enc即可 https://gitee.com/maxibooksiyi/encode2rtsp/blob/master/nodes/test/encode_demo.py

通过VideoWriter()往appsrc里面传图片(gst-rtsp-server里面也是往appsrc里面传图但是用起来没有VideoWriter()这么方便我觉得) 在RK3588上使用Gstreamer做推拉流并推理记录_rk3588 gstreamer-CSDN博客

7ce8ba599d93c8b3970805d1398186ef.png

https://wenku.csdn.net/answer/784120c63c8943f880a205fa1590de72

12bcf338240a816656d77b23d8a03167.png

拉流用videoCapture("rtsp://IP:8554/test"),这种默认软解码,似乎也可以弄为硬解码

opencv+gstreamer拉流

827cdc3f9a786dc313086994f25d916e.png

 

5485902fb167f68eb666aa99883fe8bc.png

2. gst-rtsp-server

如test-launch.c

推流

rk3588s硬编码,软编码把mpph264enc 改为x264enc即可。

sudo ./test-launch "( v4l2src device=/dev/video-camera0 ! videoconvert ! mpph264enc ! rtph264pay name=pay0 pt=96  )"

拉流

rk3588s上,硬解码

gst-launch-1.0 -v rtspsrc location=rtsp://127.0.0.1:8554/test latency=0 ! rtph264depay ! h264parse ! mppvideodec ! autovideosink

 

要调节RTSP推流拉流的帧率,你需要修改代码中的相关参数。在C++中,推流拉流通常使用FFmpeg库来实现。以下是一个简单的示例代码,它使用FFmpeg库来推送RTSP流: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/time.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> #define STREAM_URL "rtsp://127.0.0.1:8554/test" int main(int argc, char **argv) { AVFormatContext *pFormatCtx; AVOutputFormat *pOutputFmt; AVStream *pStream; AVCodecContext *pCodecCtx; AVCodec *pCodec; AVFrame *pFrame; AVPacket pkt; int ret, i, frame_count = 0; struct timeval start_time, end_time; int64_t start_time_ms, end_time_ms; int video_width = 1920, video_height = 1080; int video_fps = 30; // 设置帧率为30fps char errbuf[1024]; // 初始化FFmpeg库 av_register_all(); avformat_network_init(); // 打开输出流 ret = avformat_alloc_output_context2(&pFormatCtx, NULL, "rtsp", STREAM_URL); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to allocate output context: %s\n", errbuf); return -1; } // 创建视频流 pOutputFmt = pFormatCtx->oformat; pStream = avformat_new_stream(pFormatCtx, NULL); if (!pStream) { fprintf(stderr, "Failed to allocate stream\n"); return -1; } // 设置视频编码器参数 pCodec = avcodec_find_encoder(pOutputFmt->video_codec); if (!pCodec) { fprintf(stderr, "Failed to find video encoder\n"); return -1; } pCodecCtx = avcodec_alloc_context3(pCodec); pCodecCtx->codec_id = pOutputFmt->video_codec; pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; pCodecCtx->width = video_width; pCodecCtx->height = video_height; pCodecCtx->time_base.num = 1; pCodecCtx->time_base.den = video_fps; pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; // 打开编码器 ret = avcodec_open2(pCodecCtx, pCodec, NULL); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to open video encoder: %s\n", errbuf); return -1; } // 分配帧缓存 pFrame = av_frame_alloc(); pFrame->format = pCodecCtx->pix_fmt; pFrame->width = pCodecCtx->width; pFrame->height = pCodecCtx->height; ret = av_frame_get_buffer(pFrame, 0); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to allocate frame buffer: %s\n", errbuf); return -1; } // 打开输出流 ret = avio_open(&pFormatCtx->pb, STREAM_URL, AVIO_FLAG_WRITE); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to open output stream: %s\n", errbuf); return -1; } // 写文件头 ret = avformat_write_header(pFormatCtx, NULL); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to write file header: %s\n", errbuf); return -1; } // 循环发送视频帧 gettimeofday(&start_time, NULL); start_time_ms = start_time.tv_sec * 1000 + start_time.tv_usec / 1000; for (i = 0; i < 100; i++) { // 填充图像数据 pFrame->data[0] = (uint8_t *) malloc(video_width * video_height); pFrame->data[1] = (uint8_t *) malloc(video_width * video_height / 4); pFrame->data[2] = (uint8_t *) malloc(video_width * video_height / 4); pFrame->linesize[0] = video_width; pFrame->linesize[1] = video_width / 2; pFrame->linesize[2] = video_width / 2; memset(pFrame->data[0], 255, video_width * video_height); memset(pFrame->data[1], 128, video_width * video_height / 4); memset(pFrame->data[2], 128, video_width * video_height / 4); // 编码视频帧 pFrame->pts = i * (pCodecCtx->time_base.den) / ((pCodecCtx->time_base.num) * video_fps); ret = avcodec_send_frame(pCodecCtx, pFrame); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to send frame: %s\n", errbuf); return -1; } while (1) { ret = avcodec_receive_packet(pCodecCtx, &pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break; if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to receive packet: %s\n", errbuf); return -1; } // 写视频帧到输出流 pkt.stream_index = pStream->index; av_packet_rescale_ts(&pkt, pCodecCtx->time_base, pStream->time_base); ret = av_interleaved_write_frame(pFormatCtx, &pkt); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to write frame: %s\n", errbuf); return -1; } av_packet_unref(&pkt); } free(pFrame->data[0]); free(pFrame->data[1]); free(pFrame->data[2]); } // 写文件尾 ret = av_write_trailer(pFormatCtx); if (ret < 0) { av_strerror(ret, errbuf, sizeof(errbuf)); fprintf(stderr, "Failed to write file trailer: %s\n", errbuf); return -1; } // 释放资源 avio_close(pFormatCtx->pb); avformat_free_context(pFormatCtx); avcodec_free_context(&pCodecCtx); av_frame_free(&pFrame); gettimeofday(&end_time, NULL); end_time_ms = end_time.tv_sec * 1000 + end_time.tv_usec / 1000; printf("Total time: %lldms\n", end_time_ms - start_time_ms); return 0; } ``` 要调节帧率,你需要修改以下两个参数: ``` int video_fps = 30; // 设置帧率为30fps ``` ``` pCodecCtx->time_base.den = video_fps; ``` 你可以将`video_fps`变量设置为你想要的帧率,例如60fps,然后重新编译代码即可。对于拉流,你可以在解码器的参数中设置帧率。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值