Deepstream 之 appsink元素保存图片
目录1. appsink元素介绍2. appsink 元素结合cv::Mat保存图片2.1 开发环境2.2 软件代码与说明1. appsink元素介绍appsink 元素作为gstreamer的sink节点,它可以实现pipeline中的流媒体数据与其他应用程序的交换,比如实现gstreamer与CUDA交互,gstreamer与OpenCV交互,等等。主要作用是借助gstreamer pipel
·
目录
1. appsink元素介绍
appsink 元素作为gstreamer的sink节点,它可以实现pipeline中的流媒体数据与其他应用程序的交换,比如实现gstreamer与CUDA交互,gstreamer与OpenCV交互,等等。
主要作用是借助gstreamer pipeline的 media streaming, 我们通过appsink用一个buffer来收集流媒体的数据,提供给其他应用程序来处理使用。
2. appsink 元素结合cv::Mat保存图片
2.1 开发环境
硬件:NVIDIA jetson xavier agx
软件:Qt5.9、Opencv4.1.1、Deepstream 5.0、GStreamer-1.0
2.2 软件代码与说明
queue元素和nvvideoconvert元素创建省略,只说明保存元素的核心内容。
Qt配置opencv不在此说明。
- 创建appsink元素,并且设置其caps,此caps满足nvvideoconvert元素的src输出格式:
char caps[1024] = "video/x-raw,format=RGBA";
GstCaps *video_caps;
video_caps = gst_caps_from_string (caps);
if(!video_caps){
qCritical()<< "gst_caps_from_string fail";
return false;
}
g_object_set (m_sinkBin.sub_bins[index].sink, "caps", video_caps, NULL);
- 设置appsink元素的信号及其信号响应函数
// link signal new-sample
g_object_set(m_sinkBin.sub_bins[index].sink, "emit-signals", TRUE, "async", FALSE, NULL);
g_signal_connect(m_sinkBin.sub_bins[index].sink, "new-sample", G_CALLBACK(SinkElement::newSample), NULL);
- 在new-sample响应函数中保存当前视频帧为图片
GstSample *sample = gst_app_sink_pull_sample(appsink); //need free sample handle
caps = gst_sample_get_caps (sample);
if (!caps) {
g_print ("gst_sample_get_caps fail\n");
gst_sample_unref (sample);
return GST_FLOW_ERROR;
}
s = gst_caps_get_structure (caps, 0);
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");
gst_sample_unref (sample);
return GST_FLOW_ERROR;
}
GstBuffer *buffer = gst_sample_get_buffer(sample);
char fileNameString[FILE_NAME_SIZE];
snprintf (fileNameString, FILE_NAME_SIZE, "%d_%d_%d_%s_%dx%d.png",
frame_number, frame_meta->source_id, num_rects,
obj_meta->obj_label, width, height);
qDebug()<< "fileNamstring: "<< fileNameString;
//save jpg
GstMapInfo mapInfo{};
if(gst_buffer_map(buffer, &mapInfo, GST_MAP_READ))
{
std::string strFile(fileNameString);
cv::Mat frame(cv::Size(width, height), CV_8UC4, (uchar*)mapInfo.data, cv::Mat::AUTO_STEP);
if(cv::imwrite(strFile, frame))
{
qInfo()<< "save " << strFile.c_str() << " succese";
}
else
qWarning()<<"save " << strFile.c_str() << " failed";
gst_buffer_unmap (buffer, &mapInfo); //解除映射
}
gst_sample_unref (sample); //free sample
详细源码如下:
bool SinkElement::createEventPhotoFileSinkBin(uint index)
{
gchar elem_name[50];
static int uid = 0;
g_snprintf (elem_name, sizeof (elem_name), "appsink_sub_bin%d", uid);
m_sinkBin.sub_bins[index].bin = gst_bin_new (elem_name);
if (!m_sinkBin.sub_bins[index].bin) {
qCritical()<< "Failed to create "<< elem_name;
return false;
}
//sink
g_snprintf (elem_name, sizeof (elem_name), "appsink_sub_bin_%d", uid);
m_sinkBin.sub_bins[index].sink = gst_element_factory_make ("appsink", elem_name);
if (!m_sinkBin.sub_bins[index].sink) {
qCritical()<< "Failed to create " << elem_name;
return false;
}
char caps[1024] = "video/x-raw,format=RGBA";
GstCaps *video_caps;
video_caps = gst_caps_from_string (caps);
if(!video_caps){
qCritical()<< "gst_caps_from_string fail";
return false;
}
g_object_set (m_sinkBin.sub_bins[index].sink, "caps", video_caps, NULL);
// link signal new-sample
g_object_set(m_sinkBin.sub_bins[index].sink, "emit-signals", TRUE, "async", FALSE, NULL);
g_signal_connect(m_sinkBin.sub_bins[index].sink, "new-sample", G_CALLBACK(SinkElement::newSample), NULL);
//transform
g_snprintf (elem_name, sizeof (elem_name), "appsink_sub_bin_transform_%d", uid);
m_sinkBin.sub_bins[index].transform =
gst_element_factory_make ("nvvideoconvert", elem_name);
if (!m_sinkBin.sub_bins[index].transform) {
qCritical()<< "Failed to create " << elem_name;
return false;
}
//queue
g_snprintf (elem_name, sizeof (elem_name), "appsink_sub_bin_queue%d", uid);
m_sinkBin.sub_bins[index].queue = gst_element_factory_make("queue", elem_name);
if (! m_sinkBin.sub_bins[index].queue) {
qCritical()<< "Failed to create " << elem_name;
return false;
}
uid++;
gst_bin_add_many(GST_BIN(m_sinkBin.sub_bins[index].bin),
m_sinkBin.sub_bins[index].queue,
m_sinkBin.sub_bins[index].transform,
m_sinkBin.sub_bins[index].sink, NULL);
if(!gst_element_link_many(m_sinkBin.sub_bins[index].queue,
m_sinkBin.sub_bins[index].transform,
m_sinkBin.sub_bins[index].sink, NULL))
{
QString criticalOutput = QString::asprintf("Failed to link SinkBin.sub_bins[%d].queue, SinkBin.sub_bins[%d].transform, SinkBin.sub_bins[%d].sink!",
index, index, index);
qCritical()<< criticalOutput;
return false;
}
QString linkInfo = QString::asprintf("Linking SinkBin.sub_bins[%d].queue, SinkBin.sub_bins[%d].transform, SinkBin.sub_bins[%d].sink successfully",
index, index, index);
qInfo()<< linkInfo;
NVGSTDS_BIN_ADD_GHOST_PAD (m_sinkBin.sub_bins[index].bin, m_sinkBin.sub_bins[index].queue, "sink");
return true;
done:
return false;
}
GstFlowReturn SinkElement::newSample(GstAppSink *appsink, gpointer data)
{
Q_UNUSED(data);
static int frame_number = 1;
GstCaps *caps;
GstStructure *s;
gint width, height;
GstSample *sample = gst_app_sink_pull_sample(appsink); //need free sample handle
if(!sample)
{
qCritical()<< "Get sample error!";
return GST_FLOW_ERROR;
}
/*************************** 获取图片的宽,高 *************************/
caps = gst_sample_get_caps (sample);
if (!caps) {
g_print ("gst_sample_get_caps fail\n");
gst_sample_unref (sample);
return GST_FLOW_ERROR;
}
s = gst_caps_get_structure (caps, 0);
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");
gst_sample_unref (sample);
return GST_FLOW_ERROR;
}
/*********************************************************************/
/**************************** 获取事件 *****************************/
GstBuffer *buffer = gst_sample_get_buffer(sample);
if(!buffer)
{
qCritical()<< "get sample buffer error!";
return GST_FLOW_ERROR;
}
NvDsBatchMeta* batch_meta = gst_buffer_get_nvds_batch_meta(buffer);
NvDsMetaList* l_frame = NULL;
NvDsMetaList* l_obj = NULL;
NvDsObjectMeta* obj_meta = NULL;
guint person_count = 0;
guint num_rects = 0;
for(l_frame = batch_meta->frame_meta_list; l_frame != NULL; l_frame = l_frame->next)
{
NvDsFrameMeta *frame_meta = (NvDsFrameMeta*)(l_frame->data);
for(l_obj = frame_meta->obj_meta_list; l_obj != NULL; l_obj = l_obj->next)
{
obj_meta = (NvDsObjectMeta*)(l_obj->data);
if(obj_meta->class_id == PGIE_CLASS_ID_PERSON)
{
person_count++;
num_rects++;
}
}
/**************************如果person_count > 0,则保存图片*********************************/
if(person_count > 0)
{
char fileNameString[FILE_NAME_SIZE];
snprintf (fileNameString, FILE_NAME_SIZE, "%d_%d_%d_%s_%dx%d.png",
frame_number, frame_meta->source_id, num_rects,
obj_meta->obj_label, width, height);
qDebug()<< "fileNamstring: "<< fileNameString;
//save jpg
GstMapInfo mapInfo{};
if(gst_buffer_map(buffer, &mapInfo, GST_MAP_READ))
{
std::string strFile(fileNameString);
cv::Mat frame(cv::Size(width, height), CV_8UC4, (uchar*)mapInfo.data, cv::Mat::AUTO_STEP);
if(cv::imwrite(strFile, frame))
{
qInfo()<< "save " << strFile.c_str() << " succese";
}
else
qWarning()<<"save " << strFile.c_str() << " failed";
gst_buffer_unmap (buffer, &mapInfo); //解除映射
}
}
frame_number++;
}
gst_sample_unref (sample);
return GST_FLOW_OK;
}
更多推荐
已为社区贡献1条内容
所有评论(0)