Gstreamer:如何直接从缓冲区列表创建视频

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

我正在尝试在 C 中使用 gstreamer 创建一个循环缓冲区。目前源是我的 PC 网络摄像头“v4l2src”。 一旦缓冲区列表达到预定义的大小,我就会刷新列表中最旧的缓冲区并插入一个新缓冲区。 我正在使用 gst_buffer_list 来实现相同的目的。我需要这个循环缓冲区连续运行,当收到任何回调时, 我复制此缓冲区列表并使用 emit 信号属性将其发送到另一个管道的 appsrc。两条管道都在以下链接下:

Gstreamer Pipelines

出于测试目的,我直接编写代码,如果 buffer_length == 50 ---> 然后创建 buffer_list 的副本(深)并发送到 pipeline2 通过 g_emit_signal(push_buffer_list)。 我成功地获得了缓冲区(有一些我不明白为什么的警告)并保存到文件中。我可以看到文件大小也达到了几MB 但文件无法播放。当我用 ffplay 播放文件时,我可以看到 2-3 帧。

我想了解我是否正确使用了 push_buffer_list 信号。可以对这些 pipeline2 做些什么来使其正常工作。

#include <gst/gst.h>
#include<stdio.h>
#include <gst/app/gstappsrc.h>
#include <time.h>

static GstElement *pipeline, *video_src, *video_sink, *videoconvert, *videoencode,*identity, *identity1, *identity2,*queue, *fake_sink, *tee, *muxer;
static GstElement *pipeline2, *appsrc, *file_sink2;
GstBufferList *buflist, *copy_buflist;
static GstPad *blockpad, *probepad,*probepad2, *id2sink_pad, *fakesink_pad;
// GstPad *tee_src1_pad, *tee_src2_pad;
GstPadTemplate *templ;
GMainLoop *loop, *loop2;
GstBuffer *buff;


static gboolean 
bus_cb (GstBus * bus, GstMessage * msg, gpointer user_data)
{
  GMainLoop *loop = user_data;
  

  switch (GST_MESSAGE_TYPE (msg)) {

    
    case GST_MESSAGE_ERROR:{
      GError *err = NULL;
      gchar *dbg;

      gst_message_parse_error (msg, &err, &dbg);
      gst_object_default_error (msg->src, err, dbg);
      g_clear_error (&err);
      g_free (dbg);
      g_main_loop_quit (loop);
      break;
    }
    case GST_MESSAGE_EOS:{
        g_print ("End-Of-Stream reached.\n");
        // g_main_loop_quit (loop2);
        // gst_element_set_state (pipeline2, GST_STATE_NULL);
        // g_main_loop_unref (loop2);
        // gst_object_unref (pipeline2);
        exit(0);
        break;
    }

    case GST_MESSAGE_WARNING:{
        GError *err = NULL;
        gchar *name, *debug = NULL;

        name = gst_object_get_path_string (msg->src);
        gst_message_parse_warning (msg, &err, &debug);

        g_printerr ("ERROR: from element %s: %s\n", name, err->message);
        if (debug != NULL)
        g_printerr ("Additional debug info:\n%s\n", debug);

        g_error_free (err);
        g_free (debug);
        g_free (name);
        break;
    }

    default:
      break;
  }
  return TRUE;
}


static GstPadProbeReturn
block_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)    
{   
    g_print("in block prode\n");
    return GST_PAD_PROBE_OK;
}


static GstPadProbeReturn
debug_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{   
    g_print("coming in fakesink \n");
    return GST_PAD_PROBE_OK;
}


static GstPadProbeReturn
pad_probe_buflist_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{   
    GstFlowReturn retval;
    g_print("coming in filesink Senfing EOS NOW\n");
    // g_signal_emit_by_name (appsrc, "end-of-stream", &retval);
    gst_element_send_event(pipeline2, gst_event_new_eos()); 

    return GST_PAD_PROBE_OK;
}


static GstPadProbeReturn
pad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
  
  GstFlowReturn retval;
  static GstClockTime timestamp = 0;
  
  g_print("pointer comes in pad probe\n");
//   g_print("probe type %d \n",info->type);
  buff = gst_pad_probe_info_get_buffer(info);
//   GST_BUFFER_PTS (buff) = timestamp;
//   GST_BUFFER_DURATION (buff) = gst_util_uint64_scale_int (1, GST_SECOND, 2);
//   timestamp += GST_BUFFER_DURATION (buff);

  guint buflen = gst_buffer_list_length (buflist);
  g_print("buffer length is %d \n",buflen);

  if (buflen==50) // This is custom
  {
    copy_buflist = gst_buffer_list_copy_deep (buflist);
    gst_element_set_state (pipeline2, GST_STATE_PLAYING);
    g_signal_emit_by_name (appsrc, "push-buffer-list", copy_buflist, &retval);
    GstFlowReturn retval = gst_app_src_push_buffer_list((GstAppSrc*)appsrc,copy_buflist);
    g_print("RETVAL %d\n", retval);
    g_signal_emit_by_name (appsrc, "end-of-stream", &retval);
  }

//   retval = gst_app_src_end_of_stream ((GstAppSrc*)appsrc);
//   g_print("RETVAL %d\n", retval);
  gst_buffer_list_insert(buflist, buflen,buff);

//   gst_buffer_unref (buff);
//   gst_buffer (copy_buflist);
  
  return GST_PAD_PROBE_OK;
}


int tutorial_main(int argc, char *argv[])
{

    GstBus *bus;
    GstMessage *msg;
    GstStateChangeReturn ret,ret2;
    GstStateChangeReturn sret;
    GstStateChangeReturn pause_flag =0;
    GstState state;
    GstPad *srcpad;

    gst_init (&argc, &argv);
    video_src = gst_element_factory_make ("v4l2src", "source");
    appsrc = gst_element_factory_make ("appsrc", "source");
    
    videoconvert = gst_element_factory_make("videoconvert","convert");
  
    videoencode = gst_element_factory_make("x264enc","encode");

    video_sink = gst_element_factory_make ("filesink", "sink");

    fake_sink = gst_element_factory_make ("fakesink", "fakesink");

    identity1 = gst_element_factory_make ("identity", "identity1");

    identity2 = gst_element_factory_make ("identity", "identity2");
    
    muxer = gst_element_factory_make("flvmux", "muxer");

    queue = gst_element_factory_make ("queue", "queue");

    tee = gst_element_factory_make("tee","tee");


    file_sink2 = gst_element_factory_make ("filesink", "filesink");
    

    pipeline = gst_pipeline_new ("test-pipeline");
    pipeline2 = gst_pipeline_new ("filesink-pipeline");


    g_object_set(file_sink2,"location","/home/jafar/gps.mp4",NULL); /// YOU NEED TO UPDATE THE FILE LOCATION

    if (!pipeline || !video_src || !video_sink ||!videoconvert ||!videoencode ||!identity1 ||!identity2 ||!fake_sink ) {
        g_printerr ("Not all elements could be created.\n");
        return -1;
    }

    //Pipeline1 v4l2---->createbuffer---->fakesink
    gst_bin_add_many (GST_BIN (pipeline), video_src,videoconvert,videoencode,identity1,identity2,fake_sink, NULL);
    if ((gst_element_link_many(video_src,videoconvert,videoencode,identity1, identity2, fake_sink, NULL) != TRUE ))  {
        g_printerr ("Elements could not be linked.\n");
        gst_object_unref (pipeline);
        return -1;
      }

    //pipeline2 buffer--->appsrc---->filesink
    gst_bin_add_many (GST_BIN (pipeline2), appsrc,file_sink2, NULL);
    if ((gst_element_link_many(appsrc,file_sink2, NULL) != TRUE ))  {
        g_printerr ("Elements could not be linked.\n");
        gst_object_unref (pipeline2);
        return -1;
      } 
    

    fakesink_pad = gst_element_get_static_pad(fake_sink, "sink");
    id2sink_pad = gst_element_get_static_pad(identity2, "sink");

    
    //Get forurce pad
    probepad = gst_element_get_static_pad (identity1, "src");
    probepad2 = gst_element_get_static_pad (file_sink2, "sink");
    buflist = gst_buffer_list_new(); //init bufffer list

    //install a probe on identity1 src pad 
    gst_pad_add_probe (probepad, GST_PAD_PROBE_TYPE_BUFFER, pad_probe_cb, loop, NULL);

    g_print("COde blocks here!!!\n");
    time_t now = time(NULL);

    /* Start playing */
    ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
    ret2 = gst_element_set_state (pipeline2, GST_STATE_PAUSED);


    bus = gst_element_get_bus (pipeline);    

    loop = g_main_loop_new (NULL, FALSE);
    loop2 = g_main_loop_new (NULL, FALSE);

    gst_bus_add_watch (GST_ELEMENT_BUS (pipeline), bus_cb, loop);
    gst_bus_add_watch (GST_ELEMENT_BUS (pipeline2), bus_cb, loop2);

    // g_timeout_add_seconds (20, timeout_cb, loop);
    
    g_main_loop_run (loop);
    g_main_loop_run (loop2);
    

  /* Free resources */
 
  gst_object_unref (bus);
  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_element_set_state (pipeline2, GST_STATE_NULL);
  gst_object_unref (blockpad);
  gst_object_unref (probepad);
  gst_bus_remove_watch (GST_ELEMENT_BUS (pipeline));
  gst_object_unref (pipeline);
  gst_object_unref (pipeline2);
  g_main_loop_unref (loop);
  g_main_loop_unref (loop2);
  
  return 0;


}


int
main (int argc, char *argv[])
{
#if defined(__APPLE__) && TARGET_OS_MAC && !TARGET_OS_IPHONE
  return gst_macos_main (tutorial_main, argc, argv, NULL);
#else
  return tutorial_main (argc, argv);
#endif
}

编译代码执行如下:

gcc buffer-tutorial-2.c -o buffer-tutorial-2 `pkg-config --cflags --libs gstreamer-1.0 gstreamer-audio-1.0` -lgstapp-1.0

代码的输出在此链接下: Code output

c gstreamer video-processing gstreamer-1.0 circular-buffer
© www.soinside.com 2019 - 2024. All rights reserved.