我们必须为视频转换创建打击垫吗

问题描述 投票:0回答:1

我是gstreamer的新手,我想知道我们是否必须创建源和接收板来进行转换,例如在管道中进行视频转换。我有这样的管道

gst-launch-1.0 v4l2src ! video/x-raw,format=YUY2 !  videoconvert ! xvimagesink

我正在尝试创建一个简单的c应用程序以了解填充板的创建,并想知道视频转换是否也具有源填充板和接收填充板。我正在为过滤器创建源和汇焊盘。

编辑:是的,您知道的,我尝试了下面的动态管道示例,并在下面编写了代码

#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)
{
  g_print("In pad handler\n");
  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);
     g_print ("It has type '%s' which is not raw audio. Ignoring.\n", new_pad_type);

     if(!g_str_has_prefix(new_pad_type, "video/x-raw,format=(string)YUY2"))
     {
         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_print("before signal connect\n");
        gint id= g_signal_connect(G_OBJECT(data.source), "pad-added", G_CALLBACK(pad_added_handler), &data );
    g_print("after signal connect with id = %d\n", id);
  //g_signal_connect(G_OBJECT(data.source), "pad-added", G_CALLBACK(handler), &data);
    //   gst_element_link(data.source, data.convert);
     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;
}

它给了我一个错误

before signal connect
after signal connect with id = 1
Pipeline state changed from NULL to READY:
Pipeline state changed from READY to PAUSED:
Error received from element source: Internal data stream error.
Debugging information: gstbasesrc.c(3055): gst_base_src_loop (): /GstPipeline:new-pipeline/GstV4l2Src:source:
streaming stopped, reason not-linked (-1)

((如果我在要转换和接收的元素链接语句之后写gst_elements_link(data.source,data.convert),以上代码将起作用)

因此,我尝试了将所有元素添加并链接在一起的正常方法,并且无需使用垫子即可开始工作。

#include <gst/gst.h>

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

  gst_init(&argc, &argv);

  source = gst_element_factory_make("v4l2src", "source");
  convert = gst_element_factory_make("nvvidconv", "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);
  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);

}

但是,为了完全掌握打击垫的知识,我想用打击垫执行更简单的管道。我只是不完全了解打击垫的用途,无法将其与所有零件连接起来。

EDIT2:

最终,我想为这样的管道编写应用程序,该应用程序在命令行上可以很好地工作,

gst-launch-1.0 v4l2src device='/dev/video0' ! 'video/x-raw,format=(string)YUY2,width=(int)640,height=(int)480' ! nvvidconv ! 'video/x-raw(memory:NVMM),format=(string)NV12,width=(int)640,height=(int)480' ! nvvidconv ! 'video/x-raw,format=(string)NV12,width=(int)640,height=(int)480' ! nvvideoconvert ! 'video/x-raw(memory:NVMM),format=(string)NV12,width=(int)640,height=(int)480' ! mux.sink_0 nvstreammux live-source=1 name=mux batch-size=1 width=640 height=480 ! nvinfer config-file-path=/opt/nvidia/deepstream/deepstream-4.0/sources/apps/sample_apps/deepstream-test1/dstest1_pgie_config.txt batch-size=1 ! nvmultistreamtiler rows=1 columns=1 width=640 height=480 ! nvvideoconvert ! nvdsosd ! nvegltransform ! nveglglessink sync=false -v

但是由于我不了解打击垫和垃圾桶的用法,因此无法在上述管道中实现它们。但是,我尝试过此,

#include <gst/gst.h>
#include <glib.h>
#include <stdio.h>
#include "gstnvdsmeta.h"


#define MAX_DISPLAY_LEN 64

#define PGIE_CLASS_ID_VEHICLE 0
#define PGIE_CLASS_ID_PERSON 2

gint frame_number = 0;
gchar pgie_classes_str[4][32] = { "Vehicle", "TwoWheeler", "Person",
  "Roadsign"
};


static GstPadProbeReturn osd_sink_pad_buffer_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
{
  GstBuffer *buf=(GstBuffer *)info->data;
  guint num_rects =0;
  NvDsObjectMeta *obj_meta = NULL;
    guint vehicle_count = 0;
    guint person_count = 0;
    NvDsMetaList * l_frame = NULL;
    NvDsMetaList * l_obj = NULL;
    NvDsDisplayMeta *display_meta = NULL;

    NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta (buf);

    for (l_frame = batch_meta->frame_meta_list; l_frame != NULL;
      l_frame = l_frame->next) {
        NvDsFrameMeta *frame_meta = (NvDsFrameMeta *) (l_frame->data);
        int offset = 0;
        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_VEHICLE) {
                vehicle_count++;
                num_rects++;
            }
            if (obj_meta->class_id == PGIE_CLASS_ID_PERSON) {
                person_count++;
                num_rects++;
            }
        }
        display_meta = nvds_acquire_display_meta_from_pool(batch_meta);
        NvOSD_TextParams *txt_params  = &display_meta->text_params[0];
        display_meta->num_labels = 1;
        txt_params->display_text = g_malloc0 (MAX_DISPLAY_LEN);
        offset = snprintf(txt_params->display_text, MAX_DISPLAY_LEN, "Person = %d ", person_count);
        offset = snprintf(txt_params->display_text + offset , MAX_DISPLAY_LEN, "Vehicle = %d ", vehicle_count);

        /* Now set the offsets where the string should appear */
        txt_params->x_offset = 10;
        txt_params->y_offset = 12;

        /* Font , font-color and font-size */
        txt_params->font_params.font_name = "Serif";
        txt_params->font_params.font_size = 10;
        txt_params->font_params.font_color.red = 1.0;
        txt_params->font_params.font_color.green = 1.0;
        txt_params->font_params.font_color.blue = 1.0;
        txt_params->font_params.font_color.alpha = 1.0;

        /* Text background color */
        txt_params->set_bg_clr = 1;
        txt_params->text_bg_clr.red = 0.0;
        txt_params->text_bg_clr.green = 0.0;
        txt_params->text_bg_clr.blue = 0.0;
        txt_params->text_bg_clr.alpha = 1.0;

        nvds_add_display_meta_to_frame(frame_meta, display_meta);
    }

    g_print ("Frame Number = %d Number of objects = %d "
            "Vehicle Count = %d Person Count = %d\n",
            frame_number, num_rects, vehicle_count, person_count);
    frame_number++;
    return GST_PAD_PROBE_OK;

}

int main(int argc, char *argv[])
{
   GstElement *pipeline,  *source, *filter1, *convert,*filter2, *filter3, *vidconv, *filter4, *mux, *infer, *tiler, *osd, *transform , *sink, *bin, *convert2 , *vidconv2;
   GMainLoop *loop;
   GstCaps *caps1, *caps2, *caps3, *caps4;
   GstPad *osd_sink_pad =NULL, *srcpad, *sinkpad;


   loop = g_main_loop_new(NULL,FALSE);
   gst_init(&argc, &argv);
   pipeline = gst_pipeline_new("nv_pipeline");
   gchar *string1 = "video/x-raw(memory:NVMM),format=(string)NV12";

   source = gst_element_factory_make("v4l2src", "source");
   filter1 = gst_element_factory_make("capsfilter", "filter1");
   convert = gst_element_factory_make("nvvidconv", "convert");
   filter2 = gst_element_factory_make("capsfilter", "filter2");
   filter3 = gst_element_factory_make("capsfilter", "filter3");
   filter4 = gst_element_factory_make("capsfilter", "filter4");
   vidconv = gst_element_factory_make("nvvideoconvert", "vidconv");
   mux = gst_element_factory_make("nvstreammux", "mux");
   infer = gst_element_factory_make("nvinfer", "infer");
   tiler = gst_element_factory_make("nvmultistreamtiler", "tiler");
   osd = gst_element_factory_make("nvosd", "osd");
   transform = gst_element_factory_make("nvegltransform", "transform");
   sink = gst_element_factory_make("nveglglessink", "sink");
   convert2 = gst_element_factory_make("nvvidconv", "convert2");
   vidconv2 = gst_element_factory_make("nvvideoconvert", "vidconv2");

   gst_bin_add_many(GST_BIN(pipeline), source,filter1,convert,filter2, convert2,filter3,vidconv, filter4,mux,infer, tiler,vidconv2, osd,transform,sink,NULL);

   gst_element_link_many(source,filter1,convert,filter2, convert2,filter3, vidconv, filter4,mux,infer, tiler,vidconv2, osd,transform,sink,NULL);

   osd_sink_pad = gst_element_get_static_pad(osd, "sink");
   gst_pad_add_probe(osd_sink_pad, GST_PAD_PROBE_TYPE_BUFFER, osd_sink_pad_buffer_probe, NULL, NULL);

   caps1 = gst_caps_new_simple("video/x-raw", "format",G_TYPE_STRING,"YUY2",NULL);
   caps2 = gst_caps_from_string(string1);
   caps3 = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING,"NV12", NULL);
   caps4 = gst_caps_from_string(string1);

   g_object_set(G_OBJECT(filter1), "caps", caps1, NULL);
   g_object_set(G_OBJECT(filter2), "caps", caps2, NULL);
   g_object_set(G_OBJECT(filter3), "caps", caps3, NULL);
   g_object_set(G_OBJECT(filter4), "caps", caps4, NULL);

   g_object_set(G_OBJECT(mux), "live-source", 1, "name", "mux", "batch-size", 1, "width", 1280, "height", 720, NULL);
   g_object_set(G_OBJECT(infer), "config-file-path","/opt/nvidia/deepstream/deepstream-4.0/sources/apps/sample_apps/deepstream-test1/dstest1_pgie_config.txt",NULL);
   g_object_set(G_OBJECT(infer), "batch-size", 1, NULL);
   g_object_set(G_OBJECT(tiler), "rows", 1, "columns", 1, "width", 1280, "height", 720, NULL);

   gst_caps_unref(caps1);
   gst_caps_unref(caps2);
   gst_caps_unref(caps3);
   gst_caps_unref(caps4);

   gst_element_set_state(pipeline, GST_STATE_PLAYING);
   g_print("Running ...\n");
   g_main_loop_run(loop);

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

其输出与命令行gst-launch-1.0 like完全相同,

(deep_pads:15648): GLib-GObject-WARNING **: 11:29:18.761: cannot register existing type 'GstInterpolationMethod'

(deep_pads:15648): GLib-GObject-CRITICAL **: 11:29:18.761: g_param_spec_enum: assertion 'G_TYPE_IS_ENUM (enum_type)' failed

(deep_pads:15648): GLib-GObject-CRITICAL **: 11:29:18.761: validate_pspec_to_install: assertion 'G_IS_PARAM_SPEC (pspec)' failed

(deep_pads:15648): GStreamer-CRITICAL **: 11:29:18.814: gst_element_get_static_pad: assertion 'GST_IS_ELEMENT (element)' failed

(deep_pads:15648): GStreamer-CRITICAL **: 11:29:18.814: gst_pad_add_probe: assertion 'GST_IS_PAD (pad)' failed
0:00:00.843318172 15648   0x5591be52c0 INFO                 nvinfer gstnvinfer.cpp:519:gst_nvinfer_logger:<infer> NvDsInferContext[UID 1]:initialize(): Trying to create engine from model files
0:00:20.693301580 15648   0x5591be52c0 INFO                 nvinfer gstnvinfer.cpp:519:gst_nvinfer_logger:<infer> NvDsInferContext[UID 1]:generateTRTModel(): Storing the serialized cuda engine to file at /opt/nvidia/deepstream/deepstream-4.0/samples/models/Primary_Detector/resnet10.caffemodel_b1_int8.engine

除外,它不显示上述c应用程序的输出窗口,也不显示其余窗口。

gstreamer
1个回答
0
投票

您的第一个示例失败,因为data.source元素实际上从未链接到data.convert元素。由于两个元素都具有static填充,因此您需要“手动”创建它们并链接它们,然后再将管道设置为GST_STATE_PLAYING

GstPad *source_pad = gst_element_get_static_pad(data.source, "src");
GstPad *sink_pad = gst_element_get_static_pad(data.convert, "sink");
ret = gst_pad_link(source_pad, sink_pad);

您可能希望data.source元素的静态源填充会以某种方式自动创建,因此您进行了注册

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

但是,正如从调试中看到的,pad_added_handler从未被调用,因为g_signal_connect可以被注册,并且将被具有dynamic pads的元素调用。例如,解复用器tsdemux将在发现基本流期间动态创建其源极板,因此在这种情况下,必须注册pad-added回调。

学习曲线的第一步是了解“静态”(强制性,始终存在,“手动”创建),动态(有时存在,由元素自动创建)和请求(可选,在需要时“手动”创建)gstreamer pads。之后,一切对您来说都会变得容易得多。

© www.soinside.com 2019 - 2024. All rights reserved.