系列文章
Gstreamer中获取帧数据的方式
gstreamer中如何使用probe(探针)获取帧数据
gstreamer拉流rtsp使用appsink获取帧数据(预览+截图)
gstreamer中如何使用fakesink获取帧数据(预览+截图)
gstreamer中tee如何实现可控连接(预览+截图+录像)
前言
前面已经介绍了两种在gstreamer实际使用中获取帧数据的例子probe和appsink。本文主要讲用fakesink的方式获取帧数据
fakesink介绍
简单来说fakesink会吞下任何馈送它的数据。在调试时很有用,可以替换您的普通接收器并将它们排除在等式之外。官网有更详细的介绍
当上游的element和fakesink 元素协商大小时,它会收到一个 NULL 缓冲池,因为 fakesink 不提供缓冲池。然后它会选择自己的自定义缓冲池来开始数据传输。利用fakesink不提供缓冲池,将它放放入管道中tee一个支路专门用来获取少量我们想要的帧数据。也算是避免浪费性能。
管道结构
还是先直接上本次演示示例的管道结构图
此次管道是使用tee的方式videotestsrc(gstreamer的视频测试源)流分为两路,一路为显示预览,一路为fakesink用来获取帧数据并保存图片。为了演示使用的是videotestsrc。当然也可以将source用摄像头(linux下为v4l2src)或者其他网络流rtmp,rtsp来代替,都是一样的效果。
fakesink定义
代码如下(示例):
GstElementf *akesink = gst_element_factory_make ("fakesink", "fsink");
g_object_set(date.fsink, "signal-handoffs", TRUE, NULL); //信号开启
/* state-error 设置
none( 0 ) – 没有状态改变错误
null-to-ready( 1 ) – 失败状态从 NULL 变为 READY
ready-to-paused( 2 ) – 失败状态从 READY 变为 PAUSED
paused-to-playing( 3 ) – 失败状态从暂停变为播放
playing-to-paused( 4 ) – 失败状态从 PLAYING 变为 PAUSED
paused-to-ready( 5 ) – 故障状态从暂停变为就绪
ready-to-null( 6 ) – Fail 状态从 READY 变为 NULL
因为实际使用中应该想要获取实时帧数据 所以选4 */
g_object_set(date.fsink, "state-error", 4, NULL);
gulong uret = g_signal_connect(G_OBJECT(fakesink), "handoff", G_CALLBACK(fakesink_handoff_handler), gpointer user_data);
if (0 == uret) {
g_printerr("Error connect signal handoff! \n");
return -1;
}
fakesink回调函数
回调中获取帧数据的方式和appsink有些类似。代码如下(示例):
static void
fakesink_handoff_handler(GstElement *object,
GstBuffer *buffer,
GstPad *pad,
CustomData * date) { //这里data是一个全局变量的结构体 主要将所要用到的相关变量都放在里面
if (true == date->capture_flag) { //这里是qwidget中按键触发采集开始标志
GstSample *sample = nullptr;
GstStructure *s;
gint width, height; //图片的尺寸
GstCaps *videosink_caps =gst_pad_get_current_caps(pad);
s = gst_caps_get_structure (videosink_caps, 0);
if(s){
gboolean res;
res = gst_structure_get_int (s, "width", &width); //获取图片的宽
res |= gst_structure_get_int (s, "height", &height); //获取图片的高
if (!res) {
g_print ("gst_structure_get_int fail\n");
return ;
}
if(!buffer){
g_print ("gst_sample_get_buffer fail\n");
gst_sample_unref (sample);
return ;
}
// 使用mapinfo获取图像数据
GstMapInfo map;
if (gst_buffer_map (buffer, &map, GST_MAP_READ)){ //把buffer映射到map,这样我们就可以通过map.data取到buffer的数据
g_print("jpg size = %ld \n", map.size);
QImage img(map.data, width, height, width * 3, QImage::Format_RGB888);
QString strFile = QString("Capture-%0.jpg").arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmssz"));
img.save(strFile, "jpg");
g_print("save %s succese\n",strFile.toStdString().c_str());
gst_buffer_unmap (buffer, &map); //解除映射
}
date->capture_flag = false; //停止采集
GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(date->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "capture");
return ;
}
return ;
}
return ;
}
还是和前面一样用Qimage来保存图片。
总结
当然获取帧数据方式还有很多。在使用中只需要选和所我们创建的管道结构相适应的一种方式就行。暂时就先介绍这几种方式,后面将此基础上介绍如何实现可控的录像。