Gstreamer 1.0 v4l2src到c应用程序的简单管道
我的管道是这样的Gstreamer 1.0 v4l2src到c应用程序的简单管道,gstreamer-1.0,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; }Cust
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;
}
我的代码是这样的
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;
}
#包括
//更容易将它们作为回调传递
类型定义结构\u自定义数据{
GstElement*管道;
GstElement*来源;
GstElement*转换;
GstElement*水槽;
}海关数据;
//回调函数
//这里src是v4l2src,newpad是刚刚添加到src元素的gstpad。这通常是我们想要的键盘
//数据是我们在附加到信号时提供的指针。
添加了静态无效填充处理程序(GstElement*src、GstPad*新填充、CustomData*数据)
{
GstPad*sink\u pad=gst\u element\u get\u static\u pad(数据->转换,“sink”);
gstpadlinkret;
GstCaps*新焊盘焊帽=NULL;
GST结构*new_pad_struct=NULL;
常量gchar*新焊盘类型=空;
如果(gst_焊盘_连接(水槽_焊盘))
{
g_print(“我们是链接的。igonring\n”);
}
//检查新的焊盘类型
//我们之前已经创建了一条处理与xvimagesink链接的videoconvert的管道,我们将能够将其链接到制作视频的pad。
//gst-pad\u get\u current\u caps()-检索pad的当前功能
新焊盘盖=gst焊盘盖获取当前焊盘盖(新焊盘);
new_pad_struct=gst_caps_get_structure(new_pad_caps,0);
新建垫块类型=gst垫块结构名称(新建垫块结构);
如果(!g_str_具有_前缀(新的_pad_类型,“视频/x-raw”))
{
g_print(“它有新的衬垫类型”);
}
//gst_pad_link尝试链接两个焊盘。必须指定从源到接收器的链接,并且两个焊盘必须由驻留在同一管道中的元素所有
ret=gst_焊盘_链路(新_焊盘、水槽_焊盘);
如果(GST_焊盘_连接_失败(ret))
{
g_打印(“类型是新的_pad_类型”);
}
如果(新焊盘焊帽!=NULL)
{
gst_caps_unref(新的_pad_caps);
}
gst_对象_unref(水槽_垫);
}
int main(int argc,char*argv[])
{
GMainLoop*循环;
客户数据;
GstBus*总线;
GstMessage*msg;
gboolean终止=FALSE;
gst_init(&argc,&argv);
//loop=g_main_loop_new(NULL,FALSE);
//创建元素
data.source=gst元素工厂制造(“v4l2src”,“source”);
data.convert=gst元素工厂制造(“视频转换”、“转换”);
data.sink=gst元素工厂制造(“xImage sink”、“sink”);
data.pipeline=gst_pipeline_new(“新管道”);
如果(!data.pipeline | | |!data.source | |!data.convert | |!data.sink)
{
g_printerr(“不是所有元素都可以创建\n”);
返回-1;
}
//目前我们还没有链接源代码,我们将稍后再做
gst_bin_add_many(gst_bin(data.pipeline)、data.source、data.convert、data.sink、NULL);
//我们将convert元素链接到sink,而不是将它们链接到source。我们这里没有source Pad。所以我们只有videoconvert->sink unlinked
//gst_元素_链接(data.source,data.convert);
if(!gst_元素_链接(data.convert,data.sink))
{
g_printerr(“无法链接元素”);
gst_object_unref(数据管道);
返回-1;
}
//我们设置了设备源
//g_对象_集(源,“设备”,“/dev/video0”,空);
//连接到pad附加信号。
//我们希望将pad添加的信号附加到源元素。为此,我们使用g_signal_connect并提供回调函数和数据指针。
//当源元素有足够的信息开始生成数据时,它将创建源pad并触发pad added信号
g_信号连接(g_对象(data.source),“添加了焊盘”,g_回调(添加了焊盘处理程序),&data);
//g_信号连接(g_对象(data.source),“添加了pad”,g_回调(handler),&data);
GSTStateChangeRet;
ret=gst\u元素\u集合\u状态(data.pipeline,gst\u状态\u PLAYING);
如果(ret==GST\u状态\u变化\u失败){
g_printerr(“无法将管道设置为播放状态。\n”);
gst_object_unref(数据管道);
返回-1;
}
//g_主循环运行(循环);
/*听公共汽车*/
总线=gst\u元素\u获取\u总线(数据管道);
做{
msg=gst\总线\定时\弹出\过滤(总线、gst\时钟\时间\无、,
GST_消息_状态_变更| GST_消息_错误| GST_消息_EOS);
/*解析消息*/
如果(msg!=NULL){
GError*err;
gchar*调试信息;
开关(GST\信息\类型(msg)){
案例GST\u消息\u错误:
gst\消息\解析\错误(消息、错误和调试\信息);
g_printerr(“从元素%s接收到错误:%s\n”,GST_对象名称(msg->src),err->message);
g_printerr(“调试信息:%s\n”,调试信息?调试信息:“无”);
g_清除_错误(&err);
g_免费(调试信息);
终止=真;
打破
案例GST\信息\ EOS:
g_print(“到达流结束。\n”);
终止=真;
打破
案例GST\消息\状态\更改:
/*我们只对来自管道的状态更改消息感兴趣*/
if(GST_MESSAGE_SRC(msg)=GST_对象(data.pipeline)){
GST状态旧状态、新状态、待定状态;
gst\消息\解析\状态\已更改(消息、旧状态、新状态和挂起状态);
g_print(“管道状态从%s更改为%s:\n”,
gst_元素_状态_获取名称(旧状态),gst_元素_状态_获取名称(新状态));
}
打破
违约:
/*我们不应该到达这里*/
g_printerr(“收到意外消息。\n”);
打破
}
gst_消息_unref(msg);
}
}而(!终止);
/*免费资源*/
商品及服务税(巴士);
gst_元素_集合_状态(data.pipeline,gst_状态_NULL);
gst_object_unref(数据管道);
返回0;
}
我得到了这样的错误
管道状态从NULL更改为READY:
管道状态已从就绪更改为暂停:
从元素源接收到错误:内部数据流错误。
调试信息:gstbasesrc.c(3055):gst_base_src_loop():/GstPipeline:new pipeline/GstV4l2Src:source:
流停止,原因不是-l