我正在尝试在 C 中使用 gstreamer 创建一个循环缓冲区。目前源是我的 PC 网络摄像头“v4l2src”。 一旦缓冲区列表达到预定义的大小,我就会刷新列表中最旧的缓冲区并插入一个新缓冲区。 我正在使用 gst_buffer_list 来实现相同的目的。我需要这个循环缓冲区连续运行,当收到任何回调时, 我复制此缓冲区列表并使用 emit 信号属性将其发送到另一个管道的 appsrc。两条管道都在以下链接下:
出于测试目的,我直接编写代码,如果 buffer_length == 50 ---> 然后创建 buffer_list 的副本(深)并发送到 pipeline2
通过 g_emit_signal(push_buffer_list)。
我成功地获得了缓冲区(有一些我不明白为什么的警告)并保存到文件中。我可以看到文件大小也达到了几MB
但文件无法播放。当我用 ffplay
我想了解我是否正确使用了 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