v4l2src通往C应用程序的简单管道

时间:2019-12-17 20:05:30

标签: gstreamer-1.0

我的管道是这样的

gst-launch-1.0 v4l2src  ! videoconvert ! xvimagesink

我的代码就是这样

#include <gst/gst.h>


// easier to pass them as callbacks
typedef struct _CustomData{
  GstElement *pipeline;
  GstElement *source;
  GstElement *convert;
  GstElement *sink;
}CustomData;

// callback function

// here src is the v4l2src, newpad is gstpad that has just been added to src element. This is usually the pad to which we want to lnk
// data is the pointer we provided when attaching to the signal.

static void pad_added_handler(GstElement *src, GstPad *new_pad,CustomData *data)
{
  GstPad *sink_pad = gst_element_get_static_pad(data->convert, "sink");
  GstPadLinkReturn ret;
  GstCaps *new_pad_caps = NULL;
  GstStructure *new_pad_struct = NULL;
  const gchar *new_pad_type = NULL;

  if(gst_pad_is_linked(sink_pad))
    {
      g_print("we are linked. igonring\n");
    }
  // check the new pad types
  // we have previously created a piece of pipeline which deals with videoconvert linked with xvimagesink and we will nto be able to link it to a pad producing video.
  //gst-pad_get_current_caps()- retrieves current capabilities of pad 
    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);

  if(!g_str_has_prefix(new_pad_type, "video/x-raw"))
     {
         g_print("It has new pad type");
     }

  // gst_pad_link tries to link two pads . the link must be specified from source to sink and both pads must be owned by elements residing in same pipeline
  ret = gst_pad_link(new_pad, sink_pad);
  if(GST_PAD_LINK_FAILED(ret))
    {
      g_print("type is new_pad_type");
    }
  if(new_pad_caps !=NULL)
    {
      gst_caps_unref(new_pad_caps);
        }
    gst_object_unref(sink_pad);
}

int main(int argc, char *argv[])
{
  GMainLoop *loop;
  CustomData data;
    GstBus *bus;
  GstMessage *msg;
  gboolean terminate = FALSE;
  gst_init(&argc, &argv);
  //  loop = g_main_loop_new(NULL, FALSE);
  // create the elements
  data.source = gst_element_factory_make("v4l2src", "source");
  data.convert = gst_element_factory_make("videoconvert", "convert");
  data.sink = gst_element_factory_make("xvimagesink", "sink");

  data.pipeline = gst_pipeline_new("new-pipeline");

  if(!data.pipeline || !data.source || !data.convert || !data.sink)
    {
      g_printerr("Not all elements could be created\n");
      return -1;
    }

  //we did not link source at this point of time, we will do it later
  gst_bin_add_many(GST_BIN(data.pipeline), data.source, data.convert, data.sink, NULL);
  // we link convert element to sink, do not link them with source. we dont have source pads here. so we just have videoconvert->sink unlinked
  //  gst_element_link(data.source, data.convert);
  if(!gst_element_link(data.convert,data.sink))
    {
      g_printerr("elements could not be linked\n");
      gst_object_unref(data.pipeline);
      return -1;
    }

  // we set the device source
  //g_object_set(source, "device", "/dev/video0", NULL);

  //connect to pad added signal.
  // we want to attach pad added signal to source element. to do so, we are using g_signal_connect and provide callback function and datapointer.
  // when source element has enough information to start producing data, it will create source pads and trigger the pad added signal. at this point, our callback is called 
         g_signal_connect(G_OBJECT(data.source), "pad-added", G_CALLBACK(pad_added_handler), &data );

  //g_signal_connect(G_OBJECT(data.source), "pad-added", G_CALLBACK(handler), &data);

     GstStateChangeReturn ret;
  ret =gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
   if (ret == GST_STATE_CHANGE_FAILURE) {
    g_printerr ("Unable to set the pipeline to the playing state.\n");
    gst_object_unref (data.pipeline);
    return -1;
   }
   //   g_main_loop_run(loop);
    /* Listen to the bus */
  bus = gst_element_get_bus (data.pipeline);
  do {
    msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE,
        GST_MESSAGE_STATE_CHANGED | GST_MESSAGE_ERROR | GST_MESSAGE_EOS);

    /* Parse message */
    if (msg != NULL) {
      GError *err;
      gchar *debug_info;

      switch (GST_MESSAGE_TYPE (msg)) {
        case GST_MESSAGE_ERROR:
          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);
          terminate = TRUE;
          break;
        case GST_MESSAGE_EOS:
          g_print ("End-Of-Stream reached.\n");
          terminate = TRUE;
          break;
        case GST_MESSAGE_STATE_CHANGED:
          /* We are only interested in state-changed messages from the pipeline */
          if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data.pipeline)) {
            GstState old_state, new_state, pending_state;
            gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
            g_print ("Pipeline state changed from %s to %s:\n",
                gst_element_state_get_name (old_state), gst_element_state_get_name (new_state));
          }
          break;
        default:
          /* We should not reach here */
          g_printerr ("Unexpected message received.\n");
          break;
      }
      gst_message_unref (msg);
    }
  } while (!terminate);

  /* Free resources */
  gst_object_unref (bus);

  gst_element_set_state(data.pipeline, GST_STATE_NULL);
  gst_object_unref(data.pipeline);
  return 0;
}

我遇到这样的错误

管道状态从NULL更改为READY: 管道状态从“就绪”更改为“已暂停”: 从元素源接收到错误:内部数据流错误。 调试信息:gstbasesrc.c(3055):gst_base_src_loop():/ GstPipeline:new-pipeline / GstV4l2Src:source: 流停止,原因未链接(-1)

请让我知道为使管道正常工作应该进行哪些更改。谢谢!上面的代码基于gstreamer教程中的动态管道示例。我不明白我要去哪里错了。

1 个答案:

答案 0 :(得分:0)

以下方法可以解决

#include <gst/gst.h>

int main(int argc, char *argv[])
{
  GstElement *pipeline, *source,*filter, *convert, *sink;
  GstBus *bus;
  GstMessage *msg;
  GstCaps *caps;

  gst_init(&argc, &argv);

  source = gst_element_factory_make("v4l2src", "source");
  filter = gst_element_factory_make("capsfilter","filter");
  convert = gst_element_factory_make("videoconvert", "convert");
  sink = gst_element_factory_make("xvimagesink", "sink");\

  pipeline = gst_pipeline_new("pipe");

  gst_bin_add_many(GST_BIN(pipeline), source, convert,sink, NULL);
  gst_element_link_many(source,convert,sink,NULL);
  caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "YUY2", NULL);
    g_object_set(G_OBJECT(filter), "caps", caps, NULL);
  gst_element_set_state(pipeline,GST_STATE_PLAYING);



bus = gst_element_get_bus (pipeline);
  msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS);

  /* Parse message */
  if (msg != NULL) {
    GError *err;
    gchar *debug_info;

    switch (GST_MESSAGE_TYPE (msg)) {
      case GST_MESSAGE_ERROR:
        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);
        break;
      case GST_MESSAGE_EOS:
        g_print ("End-Of-Stream reached.\n");
        break;
      default:
        /* We should not reach here because we only asked for ERRORs and EOS */
        g_printerr ("Unexpected message received.\n");
        break;
    }
    gst_message_unref (msg);
  }

  /* Free resources */
  gst_object_unref(bus);

  gst_element_set_state(pipeline,GST_STATE_NULL);
  gst_object_unref(pipeline);


}

有什么想法为什么要加垫,效果不好??