将图像推入Gstreamer管道

我一直在关注将图像推送到Gstreamer管道的许多例子,但我仍然无法使我的代码工作。

任何建议(除了告诉我尝试使用Gstreamer1.0而不是0.10)将非常感激。 我想了解以下脚本中的错误,该脚本使用jpeg图像提供appsrc元素。 稍后我将使用相同的代码来提供我从相机中获取的openCv图像,但首先我想通过使这个简单的示例工作来理解基础知识。

 #include  #include  #include  #include  #include  #define VIDEO_CAPS "video/x-raw-rgb,bpp=8,depth=8,width=640,height=360,framerate=5/1,red_mask=224,green_mask=28,blue_mask=3,endianness=1234;" /* Structure to contain all our information, so we can pass it to callbacks */ guint64 imagecounter=1; typedef struct _CustomData { GstElement *pipeline, *app_source; GstElement *video_convert, *video_sink; GstElement *image_manage; guint64 num_samples; /* Number of samples generated so far (for timestamp generation) */ guint sourceid; /* To control the GSource */ GMainLoop *main_loop; /* GLib's Main Loop */ } CustomData; /* This method is called by the idle GSource in the mainloop, to feed CHUNK_SIZE bytes into appsrc. * The idle handler is added to the mainloop when appsrc requests us to start sending data (need-data signal) * and is removed when appsrc has enough data (enough-data signal). */ static gboolean push_data (CustomData *data) { GstBuffer *buffer; GstFlowReturn ret; int i; gint8 *raw; gint num_samples; gfloat freq; int size,depth,height,width,step,channels; guchar *data1; IplImage* img; g_print("push_data is beginning\n"); img=cvLoadImage("frame1.jpg",CV_LOAD_IMAGE_COLOR); height = img->height; width = img->width; step = img->widthStep; channels = img->nChannels; depth = img->depth; data1 = (guchar *)img->imageData; num_samples = height*width*channels; g_print("height %d\n",height); g_print("width %d\n",width); g_print("widthStep %d\n",step); g_print("nChannels %d\n",channels); g_print("depth %d\n",depth); g_print("image_number %" G_GUINT64_FORMAT "\n", imagecounter); g_print("sizeof guchar: %lu\n",sizeof(guchar)); /* Create a new empty buffer */ buffer = gst_buffer_new_and_alloc (num_samples); // guint size :the size in bytes of the new buffer's data. size = GST_BUFFER_SIZE(buffer); g_print("nSize %d\n",size); g_print("buffer initialized\n"); /* Set its timestamp and duration */ GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale (imagecounter, GST_SECOND, 5 ); imagecounter += 1; GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale (num_samples, GST_SECOND,5); memcpy( (guchar *)GST_BUFFER_DATA( buffer ), data1, GST_BUFFER_SIZE( buffer ) ); g_print("image data copied into buffer\n"); data->num_samples += num_samples; /* Push the buffer into the appsrc */ g_signal_emit_by_name (data->app_source, "push-buffer", buffer, &ret); g_print("buffer pushed\n"); /* Free the buffer now that we are done with it */ gst_buffer_unref (buffer); g_print("buffer unreferenced\n"); if (ret != GST_FLOW_OK) { g_printerr("something wrong in sending data"); /* We got some error, stop sending data */ return FALSE; } g_print("push_data is ending\n"); return TRUE; } /* This signal callback triggers when appsrc needs data. Here, we add an idle handler * to the mainloop to start pushing data into the appsrc */ static void start_feed (GstElement *source, guint size, CustomData *data) { if (data->sourceid == 0) { g_print ("Start feeding\n"); data->sourceid = g_idle_add ((GSourceFunc) push_data, data); g_print ("push_data started\n"); } } /* This callback triggers when appsrc has enough data and we can stop sending. * We remove the idle handler from the mainloop */ static void stop_feed (GstElement *source, CustomData *data) { if (data->sourceid != 0) { g_print ("Stop feeding\n"); g_source_remove (data->sourceid); data->sourceid = 0; } } /* This function is called when an error message is posted on the bus */ static void error_cb (GstBus *bus, GstMessage *msg, CustomData *data) { GError *err; gchar *debug_info; /* Print error details on the screen */ gst_message_parse_error (msg, &err, &debug_info); g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message); g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none"); g_clear_error (&err); g_free (debug_info); g_main_loop_quit (data->main_loop); } int main(int argc, char *argv[]) { CustomData data; gchar *video_caps_text; GstCaps *video_caps; GstBus *bus; /* Initialize cumstom data structure */ memset (&data, 0, sizeof (data)); /* Initialize GStreamer */ gst_init (&argc, &argv); /* Create the elements */ data.app_source = gst_element_factory_make ("appsrc", "video_source"); data.video_convert = gst_element_factory_make ("ffmpegcolorspace", "csp"); data.video_sink = gst_element_factory_make ("v4l2sink", "video_sink"); data.image_manage= gst_element_factory_make("imagefreeze","image_manage"); /* Create the empty pipeline */ data.pipeline = gst_pipeline_new ("test-pipeline"); if (!data.pipeline || !data.app_source || !data.video_convert || !data.video_sink || !data.image_manage) { g_printerr ("Not all elements could be created.\n"); return -1; } /* Configure appsrc */ video_caps_text = g_strdup_printf (VIDEO_CAPS); video_caps = gst_caps_from_string (video_caps_text); if( !GST_IS_CAPS(video_caps) ) { g_printerr("Error creating Caps for OpenCV-Source, exiting..."); exit( 1 ); } g_object_set (data.app_source, "caps", video_caps, NULL); g_signal_connect (data.app_source, "need-data", G_CALLBACK (start_feed), &data); g_signal_connect (data.app_source, "enough-data", G_CALLBACK (stop_feed), &data); /* Configure v4l2loopback videosink*/ //g_object_set (data.video_sink, "device", "/dev/video0", NULL); /* Link all elements that can be automatically linked because they have "Always" pads */ gst_bin_add_many (GST_BIN (data.pipeline), data.app_source, data.image_manage, data.video_convert, data.video_sink, NULL); if ( gst_element_link_many ( data.app_source, data.video_convert,data.video_sink, NULL) != TRUE) { g_printerr ("Elements could not be linked.\n"); gst_object_unref (data.pipeline); return -1;} /* /* Instruct the bus to emit signals for each received message, and connect to the interesting signals */ bus = gst_element_get_bus (data.pipeline); gst_bus_add_signal_watch (bus); g_signal_connect (G_OBJECT (bus), "message::error", (GCallback)error_cb, &data); gst_object_unref (bus); /* Start playing the pipeline */ gst_element_set_state (data.pipeline, GST_STATE_PLAYING); /* Create a GLib Main Loop and set it to run */ data.main_loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (data.main_loop); /* Free resources */ gst_element_set_state (data.pipeline, GST_STATE_NULL); gst_object_unref (data.pipeline); return 0; } 

发送几个缓冲区后,我收到以下输出:

Error received from element video_source: Internal data flow error

 Debugging information: gstbasesrc.c(2625): gst_base_src_loop (): /GstPipeline:test-pipeline/GstAppSrc:video_source: streaming task paused, reason not-negotiated (-4) 

我找到了一种方法让它发挥作用。 我切换到Gstreamer1.0,一切都变得容易了。 我仍然不知道旧代码中的问题是什么,但是因为这个新代码没问题,所以不需要浪费其他时间。

 #include  #include  #include  static GMainLoop *loop; static void cb_need_data (GstElement *appsrc, guint unused_size, gpointer user_data) { static gboolean white = FALSE; static GstClockTime timestamp = 0; GstBuffer *buffer; guint size,depth,height,width,step,channels; GstFlowReturn ret; IplImage* img; guchar *data1; GstMapInfo map; img=cvLoadImage("frame1.jpg",CV_LOAD_IMAGE_COLOR); height = img->height; width = img->width; step = img->widthStep; channels = img->nChannels; depth = img->depth; data1 = (guchar *)img->imageData; size = height*width*channels; buffer = gst_buffer_new_allocate (NULL, size, NULL); gst_buffer_map (buffer, &map, GST_MAP_WRITE); memcpy( (guchar *)map.data, data1, gst_buffer_get_size( buffer ) ); /* this makes the image black/white */ //gst_buffer_memset (buffer, 0, white ? 0xff : 0x0, size); white = !white; GST_BUFFER_PTS (buffer) = timestamp; GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (1, GST_SECOND, 2); timestamp += GST_BUFFER_DURATION (buffer); g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret); if (ret != GST_FLOW_OK) { /* something wrong, stop pushing */ g_main_loop_quit (loop); } } gint main (gint argc, gchar *argv[]) { GstElement *pipeline, *appsrc, *conv, *videosink; /* init GStreamer */ gst_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); /* setup pipeline */ pipeline = gst_pipeline_new ("pipeline"); appsrc = gst_element_factory_make ("appsrc", "source"); conv = gst_element_factory_make ("videoconvert", "conv"); videosink = gst_element_factory_make ("autovideosink", "videosink"); /* setup */ g_object_set (G_OBJECT (appsrc), "caps", gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "RGB", "width", G_TYPE_INT, 640, "height", G_TYPE_INT, 360, "framerate", GST_TYPE_FRACTION, 1, 1, NULL), NULL); gst_bin_add_many (GST_BIN (pipeline), appsrc, conv, videosink, NULL); gst_element_link_many (appsrc, conv, videosink, NULL); //g_object_set (videosink, "device", "/dev/video0", NULL); /* setup appsrc */ g_object_set (G_OBJECT (appsrc), "stream-type", 0, "format", GST_FORMAT_TIME, NULL); g_signal_connect (appsrc, "need-data", G_CALLBACK (cb_need_data), NULL); /* play */ gst_element_set_state (pipeline, GST_STATE_PLAYING); g_main_loop_run (loop); /* clean up */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); g_main_loop_unref (loop); return 0; }