// 使用GST_APP_API和Action signal的方式
void CreatePipeline()
{
// ...
if (!(m_appsink = gst_element_factory_make ("appsink", "appsink"))) {
LOG_ERROR_MSG ("Failed to create element appsink named appsink");
goto exit;
}
// equals to gst_app_sink_set_emit_signals (GST_APP_SINK_CAST (m_appsink), true);
g_object_set (m_appsink, "emit-signals", TRUE, NULL);
// full definition of appsink callbacks
/*
GstAppSinkCallbacks callbacks = {cb_appsink_eos,
cb_appsink_new_preroll, cb_appsink_new_sample};
gst_app_sink_set_callbacks (GST_APP_SINK_CAST (m_appsink),
&callbacks, reinterpret_cast<void*> (this), NULL);
*/
g_signal_connect (m_appsink, "new-sample",
G_CALLBACK (cb_appsink_new_sample), reinterpret_cast<void*> (this));
gst_bin_add_many (GST_BIN (m_sinkPipeline), m_appsink, NULL);
//...
}
GstFlowReturn cb_appsink_new_sample (
GstElement* appsink,
gpointer user_data)
{
// LOG_INFO_MSG ("cb_appsink_new_sample called, user data: %p", user_data);
SinkPipeline* sp = reinterpret_cast<SinkPipeline*> (user_data);
GstSample* sample = NULL;
GstBuffer* buffer = NULL;
GstMapInfo map;
const GstStructure* info = NULL;
GstCaps* caps = NULL;
GstFlowReturn ret = GST_FLOW_OK;
int sample_width = 0;
int sample_height = 0;
// equals to gst_app_sink_pull_sample (GST_APP_SINK_CAST (appsink), sample);
g_signal_emit_by_name (appsink, "pull-sample", &sample, &ret);
if (ret != GST_FLOW_OK) {
LOG_ERROR_MSG ("can't pull GstSample.");
return ret;
}
if (sample) {
buffer = gst_sample_get_buffer (sample);
if ( buffer == NULL ) {
LOG_ERROR_MSG ("get buffer is null");
goto exit;
}
gst_buffer_map (buffer, &map, GST_MAP_READ);
caps = gst_sample_get_caps (sample);
if ( caps == NULL ) {
LOG_ERROR_MSG ("get caps is null");
goto exit;
}
info = gst_caps_get_structure (caps, 0);
if ( info == NULL ) {
LOG_ERROR_MSG ("get info is null");
goto exit;
}
// -------- Read frame and convert to opencv format --------
// convert gstreamer data to OpenCV Mat, you could actually
// resolve height / width from caps...
gst_structure_get_int (info, "width", &sample_width);
gst_structure_get_int (info, "height", &sample_height);
// customized user action
{
// init a cv::Mat with gst buffer address: deep copy
// sometime you may got a empty buffer
if (map.data == NULL) {
LOG_ERROR_MSG("appsink buffer data empty\n");
return GST_FLOW_OK;
}
cv::Mat img (sample_height, sample_width, CV_8UC3,
(unsigned char*)map.data, cv::Mat::AUTO_STEP);
img = img.clone();
// redirection outside operation: for decoupling use
if (sp->m_putDataFunc) {
sp->m_putDataFunc(std::make_shared<cv::Mat> (img),
sp->m_putDataArgs);
} else {
goto exit;
}
}
}
exit:
if (buffer) {
gst_buffer_unmap (buffer, &map);
}
if (sample) {
gst_sample_unref (sample);
}
return GST_FLOW_OK;
}