我正在尝试为 gstreamer 管道(如下所示)编写 c++ 代码,我可以调整其帧速率。
gst-launch-1.0 filesrc location= VD19_peoplewalking.mp4 ! qtdemux ! h264parse ! nvv4l2decoder ! nvvideoconvert ! videorate ! capsfilter ! "video/x-raw(ANY), width=384,height=288,framerate=7/1" ! nveglglessink
我可以通过更改framerate通过终端运行管道。例如
gst-launch-1.0 filesrc location= VD19_peoplewalking.mp4 ! qtdemux ! h264parse ! nvv4l2decoder ! nvvideoconvert ! videorate ! capsfilter ! "video/x-raw(ANY), width=384,height=288,framerate=1/1" ! nveglglessink
在代码中,我尝试使用g_object_set()设置帧速率,如下所示
GstCaps *filtercaps;
filtercaps = gst_caps_new_simple ("video/x-raw",
"width", G_TYPE_INT, 384,
"height", G_TYPE_INT, 288,
"framerate", GST_TYPE_FRACTION, 7,1,
NULL);
g_object_set (G_OBJECT (filter1), "caps", filtercaps, NULL);
插件元素及其链接方式如下所示
GstElement *src, *dbin, *conv, *mux, *parse, *pipeline;
GstElement *videorate1, *sink1, *filter1;
pipeline = gst_pipeline_new (NULL);
src = gst_element_factory_make ("filesrc", NULL);
mux = gst_element_factory_make("qtdemux",NULL);
parse = gst_element_factory_make("h264parse",NULL);
dbin = gst_element_factory_make ("nvv4l2decoder", NULL);
conv = gst_element_factory_make ("nvvideoconvert", NULL);
sink1 = gst_element_factory_make ("nveglglessink", NULL);
filter1 = gst_element_factory_make ("capsfilter", "filter");
videorate1 = gst_element_factory_make("videorate",NULL);
gst_bin_add_many (GST_BIN (pipeline), src, dbin, conv, mux, parse, videorate1, filter1, sink1, NULL);
if (!gst_element_link_many(src,mux,NULL) || !gst_element_link_many(parse,dbin, conv, videorate1, filter1 ,sink1, NULL) )//|| !gst_element_link_many (conv, tee, NULL))
{
std::cout << "test1\n";
g_error("Failed to link elements");
return -3;
}
每当我在代码中将帧速率更改为视频的原始帧速率(此处为 7)以外的任何其他值时,我都会遇到错误。
注意:mux (qtdemux)
和 parse (h264parse)
在运行时通过调用回调函数链接pad_added_handler
作为参考,我在下面粘贴整个代码
#include <iostream>
#include <string.h>
#include <gst/gst.h>
#include <gst/app/app.h>
using namespace std;
GstElement *src, *dbin, *conv, *mux, *parse, *pipeline;
GstElement *videorate1, *sink1, *filter1;
GMainLoop *loop;
static gboolean
message_cb (GstBus * bus, GstMessage * message, gpointer user_data)
{
//Cpipeline *obj_pipeline = (Cpipeline*)user_data;
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR:{
GError *err = NULL;
gchar *name, *debug = NULL;
name = gst_object_get_path_string (message->src);
gst_message_parse_error (message, &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);
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_WARNING:{
GError *err = NULL;
gchar *name, *debug = NULL;
name = gst_object_get_path_string (message->src);
gst_message_parse_warning (message, &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;
}
case GST_MESSAGE_EOS:
g_print ("\nGot EOS\n");
g_main_loop_quit (loop);
break;
default:
break;
}
return TRUE;
}
static void pad_added_handler (GstElement *src, GstPad *new_pad, gpointer x)
{
std::cout << "\nHi inside pad_added_handler\n";
GstPad *sink_pad = gst_element_get_static_pad (parse, "sink");
GstPadLinkReturn ret;
GstCaps *new_pad_caps = NULL;
GstStructure *new_pad_struct = NULL;
const gchar *new_pad_type = NULL;
/* If our converter is already linked, we have nothing to do here */
if (gst_pad_is_linked (sink_pad)) {
g_print ("We are already linked. Ignoring.\n");
goto exit;
}
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);
std::cout << "\n" << new_pad_type << "\n";
if (!g_str_has_prefix (new_pad_type, "video/x-h264")) {
g_print ("It has type '%s' which is not raw video. Ignoring.\n", new_pad_type);
goto exit;
}
ret = gst_pad_link (new_pad, sink_pad);
if (GST_PAD_LINK_FAILED (ret)) {
g_print ("Type is '%s' but link failed.\n", new_pad_type);
goto exit;
}
exit:
/* Unreference the new pad's caps, if we got them */
if (new_pad_caps != NULL)
gst_caps_unref (new_pad_caps);
/* Unreference the sink pad */
gst_object_unref (sink_pad);
}
int main()
{
gst_init (NULL, NULL);
pipeline = gst_pipeline_new (NULL);
src = gst_element_factory_make ("filesrc", NULL);
mux = gst_element_factory_make("qtdemux",NULL);
parse = gst_element_factory_make("h264parse",NULL);
dbin = gst_element_factory_make ("nvv4l2decoder", NULL);
conv = gst_element_factory_make ("nvvideoconvert", NULL);
sink1 = gst_element_factory_make ("nveglglessink", NULL);
filter1 = gst_element_factory_make ("capsfilter", "filter");
videorate1 = gst_element_factory_make("videorate",NULL);
std::string url = "VD19_peoplewalking.mp4";
std::cout << "test1\n";
if (!pipeline || !src || !dbin || !conv || !mux || !parse || !sink1 || !videorate1 || !filter1 || !sink1 ) {
g_error ("Failed to create elements");
return -1;
}
std::cout << "test1\n";
g_object_set (src, "location", url.c_str(), NULL);
gst_bin_add_many (GST_BIN (pipeline), src, dbin, conv, mux, parse, videorate1, filter1, sink1, NULL);
if (!gst_element_link_many(src,mux,NULL) || !gst_element_link_many(parse,dbin, conv, videorate1, filter1 ,sink1, NULL) )//|| !gst_element_link_many (conv, tee, NULL))
{
std::cout << "test1\n";
g_error("Failed to link elements");
return -3;
}
GstCaps *filtercaps;
filtercaps = gst_caps_new_simple ("video/x-raw",
"width", G_TYPE_INT, 384,
"height", G_TYPE_INT, 288,
"framerate", GST_TYPE_FRACTION, 1,1,
NULL);
g_object_set (G_OBJECT (filter1), "caps", filtercaps, NULL);
std::cout << "test1";
g_signal_connect (mux, "pad-added", G_CALLBACK (pad_added_handler), NULL);
GstBus *bus;
loop = g_main_loop_new (NULL, FALSE);
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bus_add_signal_watch (bus);
g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (message_cb), NULL);
gst_object_unref (GST_OBJECT (bus));
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_main_loop_run (loop);
gst_element_set_state (pipeline, GST_STATE_NULL);
g_main_loop_unref (loop);
gst_object_unref (pipeline);
}