Gstreamer硬解码海康rtsp流 转cvMat BGR帧 Jeston

目录

硬件平台:研华mic-710ailx 有基于Jeston的gpu硬件

1.可行性验证

1.1屏幕输出

1.2后端获取

2.代码实现

元件都放入管道后进行rtspsrc之后的连接:

接收到pad-added信号进行rtsp和rtph264depay连接的回调函数:

接收到new-sample信号进行获取和转码图像数据的回调函数:

BGRx转BGR:


硬件平台:研华mic-710ailx 有基于Jeston的gpu硬件

阅读本博客需要有对gstreamer基础知识的了解,这里给出学习链接:

GStreamer系列 - 基本介绍 - John.Leng - 博客园

关于这个硬件设备下使用ffmpeg进行硬解码,我研究了很久都没有办法支持,而使用英伟达的硬解码API又过于底层抽象,难以理解还涉及到cuda编程。关于ffmpeg使用该类型的gpu进行rtsp H264硬解码的问题,有懂的老哥dd我~

1.可行性验证

1.1屏幕输出

使用gst-lauch-1.0验证rtsp硬解码管道连接和输出帧是否正常:

gst-launch-1.0 rtspsrc location=你的rtsp地址 ! queue ! rtph264depay ! h264parse ! queue ! omxh264dec ! autovideosink

可以看到这个pipeline由7个element元件构成,每个element都实现各自的功能:

  • rtspsrc 读取rtsp流
  • queue 缓存数据
  • rtph264depay 从rtspsrc接收到rtp包
  • h264parse 分割输出H264帧数据
  • queue 缓存数据
  • omxh264dec 硬解码H264帧数据
  • autovideosink 获取帧数据并自动找到屏幕进行输出

注:如果没有显示器屏幕可能会报错 ,可以将autovideosink换成appsink观察命令是否正常执行不会异常退出

使用该命令会将获取到的rtsp流视频在屏幕上显示出来,验证其可使用omxh264dec进行硬解码H264帧数据

1.2后端获取

为了能在程序中获取帧数据以及尽可能将解封装和解码使用gpu来完成,可指定以下命令:

gst-launch-1.0 rtspsrc location=你的rtsp地址 ! rtph264depay ! h264parse ! omxh264dec ! nvvidconv ! video/x-raw,width=1280,height=720,format=BGRx,latency=200 ! videoconvert ! appsink

可以看到这个pipeline由7个element元件构成,每个element都实现各自的功能:

  • rtspsrc 读取rtsp流
  • rtph264depay 从rtspsrc接收到rtp包
  • h264parse 分割输出H264帧数据
  • omxh264dec 硬解码H264帧数据
  • nvvidconv 硬解码drm_prime帧数据成BGRx
  • videoconvert 转换video数据格式
  • appsink 获取BGRx数据

其中:

“location=你的rtsp地址”紧跟着rtspsrc意为给rtspsrc元件成员location赋值,用于指定rtsp流url。

“video/x-raw,width=1280,height=720,format=BGRx,latency=200”意为通过Cap来指定输出的数据类型

若命令没有异常退出,可视作各元件可正常使用并能获取到rtsp数据

2.代码实现

gstreamer初始化,监听信号和设置响应回调函数略,可以参考我之前的gstreamer读取解析mipi csi摄像头的博客:

Gstreamer使用mipi csi摄像头,转码成BGR格式的cv::Mat_幡神的博客-CSDN博客

以下给出伪代码:

元件都放入管道后进行rtspsrc之后的连接:

/*
* 初始化,监听信号和设置回调略
*/
 
//在进行各个元件连接时注意:
//连接元素,注意顺序不能错,rtspsrc没法在这里和rtph264depay连接,因为还没有确定数据的格式
//所以将rtsp之后的元件连接起来,检查判断返回值是否成功
gst_element_link_many (rtph264depay,h264parse,omxh264dec,nvvidconv,videoconvert,appsink, NULL)
 
// 因为rtsp和rtph264depay还没有连接,所以必须设置pad-added信号监听,在管道开始工作后,确定了数据格式,再把它们连接起来
// 注意必须使用静态函数来实现回调:static void pad_added_handler(GstElement *src, GstPad *new_pad, GstreamerRTSPData *data);
// 回调里使用&gstData进行与外部通讯
g_signal_connect(rtsp, "pad-added", G_CALLBACK (pad_added_handler), &gstData);

接收到pad-added信号进行rtsp和rtph264depay连接的回调函数:

// 这个是pad-added信号的回调函数
void pad_added_handler(GstElement *src, GstPad *new_pad, GstreamerRTSPData *data){
    //获取到gstData->rtph264depay的sink pad
    GstPad *sink_pad = gst_element_get_static_pad (gstData->rtph264depay, "sink");
    //使用gst_pad_is_linked(sink_pad)来检查是否已经连接好了,若是则忽略该信号,这里略
 
    // 用于获取rtspsrc pad信息的变量
    // new_pad在这里指就是rtspsrc的source pad
    GstCaps *new_pad_caps;
    GstStructure *new_pad_struct;
    const gchar *new_pad_type;
 
    new_pad_caps = gst_pad_get_current_caps (new_pad);
    new_pad_struct = gst_caps_get_structure (new_pad_caps, 0);
    new_pad_type = gst_structure_get_name (new_pad_struct);
    //因为rtph264depay要求application/x-rtp格式的输入数据,所以找rtspsrc的pad里面有没有这种格式的数据,判断返回略
    g_str_has_prefix (new_pad_type, "application/x-rtp");
 
    //如果找到了application/x-rtp格式的输入数据,则将rtspsrc的source pad和rtph264depay的sink pad连起来
    //GstPadLinkReturn ret;通过ret来检查结果,这里略
    gst_pad_link (new_pad, sink_pad);
     
    //释放资源略
}

接收到new-sample信号进行获取和转码图像数据的回调函数:

/*
* 从sink中获取sample、获取宽高 以及
* 从sample获取buffer和把buffer映射到map流程与处理mipi csi摄像头的流程一致
* 这里略
*/
 
GstFlowReturn RTSPGstreamerReader::get_sample(GstElement *sink,
        GstreamerRTSPData *gstData) {
    //前略,已从buffer映射数据到了map,可以通过map.data取到buffer的数据
     
    /*
    * 与mipi csi摄像头处理不同的是,此时map.data中的数据格式是BGRx的
    * BGRx通道为4,与BGR对比只是多了一位x数据用来存储其他信息
    * 舍弃掉x位那一位的数据将其保存至BGR中即可
    * 舍弃掉x位后经测试没有发现图像质量有下降
    */
 
    //创建一个三通道的cv::Mat用于保存结果
    gstData->outData.bgrImg.create(gstData->outData.height, gstData->outData.width, CV_8UC3);
    //将BGRx转成BGR
    cvtColorBGRx2BGR(gstData->outData.bgrImg.data,gstData->outData.map.data,gstData->outData.width,gstData->outData.height);   
     
    //这样,解析完成的BGR格式的cv::Mat就保存在gstData->outData.bgrImg中
    //资源释放、抽帧和返回这里略
}

BGRx转BGR:

//获取到的数据是BGRx,比需要的BGR多一个通道,需要进行转换
void RTSPGstreamerReader::cvtColorBGRx2BGR(guint8 *BGR, const guint8 *BGRx, int width, int height)
{
	for (int h = 0; h < height; h++)
	{
		for (int w = 0, w1 = 0; w < width*3; w += 3, w1 += 4)
		{
			BGR[w]     = BGRx[w1];
			BGR[w + 1] = BGRx[w1+1];
			BGR[w + 2] = BGRx[w1+2];
		}
		BGR += width*3;
		BGRx += width*4;
	}
	return;
}

 源码链接:

https://download.csdn.net/download/qq_42711516/88670221


  • 5
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值