在FileLink中处理Gstreamer EOS消息以动态更改位置
正在尝试动态切换输出文件,但无法处理EOS 引述: 假设您有一个如下所示的管道:在FileLink中处理Gstreamer EOS消息以动态更改位置,gstreamer,python-gstreamer,Gstreamer,Python Gstreamer,正在尝试动态切换输出文件,但无法处理EOS 引述: 假设您有一个如下所示的管道: audiosrc-->编码器-->mux-->文件链路 然后您需要将其更改为: audiosrc-->编码器-->队列-->muxsink\u bin 其中muxsink_bin是一个bin 重影板-->多路复用-->文件链接 那么程序是: 1-使用gst\u pad\u set\u blocked\u async()阻止队列srcpad 2-在被阻止的回调中: 2a-取消muxsink_bin与gst_pad_
audiosrc-->编码器-->mux-->文件链路 然后您需要将其更改为:
audiosrc-->编码器-->队列-->muxsink\u bin
其中muxsink_bin是一个bin
重影板-->多路复用-->文件链接 那么程序是:
1-使用gst\u pad\u set\u blocked\u async()阻止队列srcpad
2-在被阻止的回调中:
2a-取消muxsink_bin与gst_pad_unlink()的链接
2b-使用gst_pad_send_event()将EOS事件发送到muxsink_bin接收器垫(
2b-创建新的muxsink_bin
2c-设置文件链接位置
2d-使用gst_bin_add()将新的bin添加到管道中
2e-使用gst\u元素与父级同步\u与父级同步\u状态() 2f-使用gst\u pad\u link()将其链接到队列srcpad
2g-使用gst\u pad\u set\u blocked\u async()取消阻止队列srcpad。当取消阻止的回调发生时,您将再次录制&没有数据丢失。无需在取消阻止的回调中执行任何操作 3-处理EOS并删除旧的muxsink_bin。我在bin_init()函数中使用“gstbin_class->handle_message=GST_DEBUG_FUNCPTR(msg_handler)”&安装了一个msg处理程序:
3a-使用gst\u元素\u集\u锁定的\u状态()锁定bin状态
3b-使用gst_元素_set_state()将状态设置为NULL
3c-使用gst_bin__remove()将其从管道中移除 就这样。唯一需要注意的是,数据必须通过管道才能工作 稻谷 除旧管道的最终确定外,主要顺序有效 难点在于第3点:我可以将EOS发送到ghostpad,而FileLink可以获得它。但如何捕捉EOS呢
“使用
gstbin\u class->handle\u message=GST\u DEBUG\u FUNCPTR(msg\u handler)
安装msg handler”是什么意思?有消息转发
必须在总线上启用:
g_object_set(G_OBJECT(bin), "message-forward", TRUE, 0);
处理:
case GST_MESSAGE_ELEMENT:
{
const GstStructure *s = gst_message_get_structure (msg);
if (gst_structure_has_name (s, "GstBinForwarded"))
{
GstMessage *forward_msg = NULL;
gst_structure_get (s, "message", GST_TYPE_MESSAGE, &forward_msg, NULL);
if (GST_MESSAGE_TYPE (forward_msg) == GST_MESSAGE_EOS)
{
g_print ("EOS from element %s\n",
GST_OBJECT_NAME (GST_MESSAGE_SRC (forward_msg)));
DestroyBin();
CreateNewBin();
RemovePad();
}
gst_message_unref (forward_msg);
}
}
完整代码:
#include <gst/gst.h>
#include <iostream>
#include <cstring>
#include <cstdio>
static gchar *opt_effects = NULL;
#define DEFAULT_EFFECTS "identity,exclusion,navigationtest," \
"agingtv,videoflip,vertigotv,gaussianblur,shagadelictv,edgetv"
static GstElement *pipeline;
static GstElement * muxer;
static GstElement * sink;
static GstElement * q2;
static int i=0;
GstElement * bin;
GstPad * muxerSinkPad;
gulong probeId;
static GQueue effects = G_QUEUE_INIT;
void CreateNewBin();
void DestroyBin();
void ChangeLocation();
void RemovePad();
static GstPadProbeReturn
pad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
GstPad *sinkPad = gst_element_get_static_pad(bin, "sink");
gst_pad_unlink(pad, sinkPad);
gst_pad_send_event(sinkPad, gst_event_new_eos());
gst_object_unref(sinkPad);
return GST_PAD_PROBE_OK;
}
static gboolean
timeout_cb (gpointer user_data)
{
static int i=0;
if(i==0)
{
GstPad * q2SrcPad;
q2SrcPad = gst_element_get_static_pad(q2, "src");
std::cout << "Timeout: " << q2SrcPad << std::endl;
probeId = gst_pad_add_probe (q2SrcPad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
pad_probe_cb, user_data, NULL);
gst_object_unref(q2SrcPad);
return TRUE;
}
return FALSE;
}
static gboolean
bus_cb (GstBus * bus, GstMessage * msg, gpointer user_data)
{
GMainLoop *loop = (GMainLoop*)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_error_free (err);
g_free (dbg);
g_main_loop_quit (loop);
break;
}
case GST_EVENT_EOS:
std::cout << "EOS message is got" << std::endl;
break;
case GST_MESSAGE_ELEMENT:
{
const GstStructure *s = gst_message_get_structure (msg);
if (gst_structure_has_name (s, "GstBinForwarded"))
{
GstMessage *forward_msg = NULL;
gst_structure_get (s, "message", GST_TYPE_MESSAGE, &forward_msg, NULL);
if (GST_MESSAGE_TYPE (forward_msg) == GST_MESSAGE_EOS)
{
g_print ("EOS from element %s\n",
GST_OBJECT_NAME (GST_MESSAGE_SRC (forward_msg)));
DestroyBin();
CreateNewBin();
RemovePad();
}
gst_message_unref (forward_msg);
}
}
break;
default:
break;
}
return TRUE;
}
int
main (int argc, char **argv)
{
GError *err = NULL;
GMainLoop *loop;
GstElement *src, *q1,/* *q2,*/ /**effect,*/ /**filter1*//*, *filter2*/ *encoder;/*, *sink*/;
gst_init(&argc, &argv);
pipeline = gst_pipeline_new ("pipeline");
src = gst_element_factory_make ("videotestsrc", NULL);
//Create a caps filter between videosource videoconvert
std::string capsString = "video/x-raw,format=YV12,width=320,height=240,framerate=30/1";
GstCaps * dataFilter = gst_caps_from_string(capsString.c_str());
q1 = gst_element_factory_make ("queue", NULL);
encoder = gst_element_factory_make ("x264enc", NULL);
q2 = gst_element_factory_make("queue", NULL);
gst_bin_add_many(GST_BIN(pipeline), src, q1, encoder, q2, 0);
gboolean link = gst_element_link_filtered(src, q1, dataFilter);
link &= gst_element_link(q1, encoder);
link &= gst_element_link(encoder, q2);
CreateNewBin();
gst_element_set_state (pipeline, GST_STATE_PLAYING);
loop = g_main_loop_new (NULL, FALSE);
gst_bus_add_watch (GST_ELEMENT_BUS (pipeline), bus_cb, loop);
g_timeout_add_seconds (10, timeout_cb, loop);
g_main_loop_run (loop);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
return 0;
}
void RemovePad()
{
GstPad * q2SrcPad;
q2SrcPad = gst_element_get_static_pad(q2, "src");
gst_pad_remove_probe(q2SrcPad, probeId);
gst_object_unref(q2SrcPad);
}
void DestroyBin()
{
gst_element_set_state(bin, GST_STATE_NULL);
gst_bin_remove(GST_BIN(pipeline), bin);
}
void CreateNewBin()
{
static std::string fileLocPattern = "deneme%d.mkv";
char buffer[12];
memset(buffer, 0, sizeof(buffer));
sprintf(buffer, fileLocPattern.c_str(), i++);
//Create Muxer Element
muxer = gst_element_factory_make("matroskamux", "MatroskaMuxer");
//Create File Sink Element
sink = gst_element_factory_make("filesink", buffer);
g_object_set(G_OBJECT(sink), "location", buffer, 0);
//Create muxsinkBin
bin = gst_bin_new(buffer);
g_object_set(G_OBJECT(bin), "message-forward", TRUE, 0);
//Add a src pad to the bin
gst_bin_add_many(GST_BIN(bin), muxer, sink, 0);
gboolean linkState = TRUE;
//Connect elements within muxsink_bin
//Link: matroskamuxer -> filesink
linkState &= gst_element_link_many(muxer, sink, 0);
//Add this bin to pipeline
gst_bin_add(GST_BIN(pipeline), bin);
//Create ghostpad and manually link muxsinkBin and remaining part of the pipeline
{
GstPadTemplate * muxerSinkPadTemplate;
if( !(muxerSinkPadTemplate = gst_element_class_get_pad_template(GST_ELEMENT_GET_CLASS(muxer), "video_%u")) )
{
std::cout << "Unable to get source pad template from muxing element" << std::endl;
}
//Obtain dynamic pad from element
muxerSinkPad = gst_element_request_pad(muxer, muxerSinkPadTemplate, 0, 0);
//Add ghostpad
GstPad * ghostPad = gst_ghost_pad_new("sink", muxerSinkPad);
gst_element_add_pad(bin, ghostPad);
gst_object_unref(GST_OBJECT(muxerSinkPad));
gst_element_sync_state_with_parent(bin);
//Get src pad from queue element
GstPad * queueBeforeBinSrcPad = gst_element_get_static_pad(q2, "src");
//Link queuebeforebin to ghostpad
if (gst_pad_link(queueBeforeBinSrcPad, ghostPad) != GST_PAD_LINK_OK )
{
std::cout << "QueueBeforeBin cannot be linked to MuxerSinkPad." << std::endl;
}
gst_object_unref(queueBeforeBinSrcPad);
}
}
#包括
#包括
#包括
#包括
静态gchar*opt_effects=NULL;
#定义默认_效果“标识、排除、导航测试”\
agingtv、videoflip、vertigotv、gaussianblur、shagadelictv、edgetv
静态GstElement*管道;
静态GstElement*muxer;
静态GstElement*接收器;
静态GstElement*q2;
静态int i=0;
GstElement*bin;
GstPad*muxerSinkPad;
古龙丸;
静态GQueue effects=G_QUEUE_INIT;
void CreateNewBin();
void destroubin();
void ChangeLocation();
void RemovePad();
静态GSTPADProbe返回
pad_probe_cb(GstPad*pad、GstPadProbeInfo*信息、gpointer用户_数据)
{
GstPad*sinkPad=gst_元件_获取_静态_垫(箱,“水槽”);
gst_pad_unlink(pad,sinkPad);
gst_pad_send_事件(下沉、gst_事件_new_eos());
gst_object_unref(下沉板);
返回GST\u焊盘\u探头\u正常;
}
静态gboolean
超时\u cb(gpointer用户\u数据)
{
静态int i=0;
如果(i==0)
{
GstPad*q2SrcPad;
q2SrcPad=gst_元素_获取_静态_垫(q2,“src”);
std::cout根据您的用例,您可以使用multifilesink
元素。它将在某些事件中动态切换文件。每个缓冲区的一个文件,每个段的一个文件…检查其属性,看看是否有适合您的内容
它还可以作为一个很好的代码库,以防您想要编写类似的东西(或者可能扩展它?我将发布实际定制的GstBin代码,也称为“muxsink_-bin”,我最终实现了它,以便为管道的“可分离接收器部分”执行转发和EOS处理
plisolatedbin.h:
#pragma once
#include <gst/gst.h>
#include <gst/gstbin.h>
G_BEGIN_DECLS
#define PL_TYPE_ISOLATED_BIN (pl_isolated_bin_get_type ())
#define PL_IS_ISOLATED_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PL_TYPE_ISOLATED_BIN))
#define PL_IS_ISOLATED_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PL_TYPE_ISOLATED_BIN))
#define PL_ISOLATED_BIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PL_TYPE_ISOLATED_BIN, PlIsolatedBinClass))
#define PL_ISOLATED_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PL_TYPE_ISOLATED_BIN, PlIsolatedBin))
#define PL_ISOLATED_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PL_TYPE_ISOLATED_BIN, PlIsolatedBinClass))
#define PL_ISOLATED_BIN_CAST(obj) ((PlIsolatedBin*)(obj))
typedef struct _PlIsolatedBin PlIsolatedBin;
typedef struct _PlIsolatedBinClass PlIsolatedBinClass;
/**
* Does not forward EOS to parent by default.
*/
struct _PlIsolatedBin
{
GstBin bin;
};
struct _PlIsolatedBinClass
{
GstBinClass parent_class;
};
GType pl_isolated_bin_get_type();
GstElement* pl_isolated_bin_new();
G_END_DECLS
#pragma一次
#包括
#包括
G_BEGIN_DECLS
#定义PL_类型\隔离\宾(PL_隔离\宾\获取\类型())
#定义PL_是隔离的(obj)(G_类型检查实例类型((obj),PL_类型隔离的)
#定义PL_是隔离的(klass)(G_类型检查类(klass),PL_类型隔离的(klass))
#定义PL_隔离_BIN_GET_类(obj)(G_类型_实例_GET_类((obj),PL_类型_隔离_BIN,PlIsolatedBinClass))
#定义PL_隔离_BIN(obj)(G_类型检查_实例转换((obj),PL_类型隔离_BIN,PlIsolatedBin))
#定义PL_隔离_BIN_类(klass)(G_类型检查_类转换((klass),PL_类型隔离_BIN,PlIsolatedBinClass))
#定义PL_隔离箱(obj)((PlIsolatedBin*)(obj))
typedef结构_plisolatedbinplisolatedbin;
typedef结构_plisolatedbinclassplisolatedbinclass;
/**
*默认情况下不将EOS转发给父级。
*/
结构_PlIsolatedBin
{
GstBin-bin;
};
结构_PlIsolatedBinClass
{
GstBinClass父类;
};
GType pl_insolated_bin_get_type();
GstElement*pl_insolated_bin_new();
G_END_DECLS
plisolatedbin.c:
#include "plisolatedbin.h"
#include <assert.h>
G_DEFINE_TYPE(PlIsolatedBin, pl_isolated_bin, GST_TYPE_BIN)
static void pl_isolated_bin_init(PlIsolatedBin *plisolatedbin)
{
}
static void pl_isolated_bin_handle_message_func(GstBin *bin, GstMessage *message)
{
if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_EOS)
{
GST_BIN_CLASS(pl_isolated_bin_parent_class)->handle_message(bin, message);
}
else
{
GstMessage *forwarded = gst_message_new_element(GST_OBJECT_CAST(bin), gst_structure_new("PlIsolatedBinForwarded", "message", GST_TYPE_MESSAGE, message, NULL));
gst_element_post_message(GST_ELEMENT_CAST(bin), forwarded);
}
}
static void pl_isolated_bin_class_init(PlIsolatedBinClass *class)
{
class->parent_class.handle_message = GST_DEBUG_FUNCPTR(pl_isolated_bin_handle_message_func);
}
GstElement* pl_isolated_bin_new()
{
return g_object_new(PL_TYPE_ISOLATED_BIN, NULL);
}
#包括“plisolatedbin.h”
#包括
G_定义_类型(PlIsolatedBin、pl_隔离_bin、GST_类型_bin)
静态空洞pl_隔离_bin_init(PlIsolatedBin*PlIsolatedBin)
{
}
静态无效pl_隔离_bin_句柄_消息_func(GstBin*bin,GstMessage*message)
{
如果(GST\U消息类型(消息)!=GST\U消息\U EOS)
{
GST\u BIN\u类(pl\u隔离\u BIN\u父类)->处理消息(BIN,消息);
}
其他的
{
GstMessage*forwarded=gst_message_new_元素(gst_OBJECT_CAST(bin),gst_structure_new(“PlIsolatedBinForwarded”,“message”,gst_TYPE_message,message,NULL));
gst_元素_post_消息(gst_元素_CAST(bin),转发);
}
}
静态void pl\u隔离的\u bin\u类\u init(PlIsolatedBinClass*类)
{
class->parent\u class.handle\u message=GST\u DEBUG\u FUNCPTR(pl\u隔离\u bin\u handle\u message\u func);
}
GstElement*pl_隔离_bin_新()
{
返回g_object_new(PL_TYPE_insolated_BIN,NULL);
}
这将帮助您实现“管道播放时动态更改元素”
“使用安装消息处理程序”是什么意思
gstbin\u class->handle\u message=GST\u DEBUG\u FUNCPTR(msg\u handle
static GstPadProbeReturn
event_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
GMainLoop *loop = user_data;
GstElement *next;
if (GST_EVENT_TYPE (GST_PAD_PROBE_INFO_DATA (info)) != GST_EVENT_EOS)
return GST_PAD_PROBE_PASS;
gst_pad_remove_probe (pad, GST_PAD_PROBE_INFO_ID (info));
/* push current effect back into the queue */
g_queue_push_tail (&effects, gst_object_ref (cur_effect));
/* take next effect from the queue */
next = g_queue_pop_head (&effects);
if (next == NULL) {
GST_DEBUG_OBJECT (pad, "no more effects");
g_main_loop_quit (loop);
return GST_PAD_PROBE_DROP;
}
g_print ("Switching from '%s' to '%s'..\n", GST_OBJECT_NAME (cur_effect),
GST_OBJECT_NAME (next));
gst_element_set_state (cur_effect, GST_STATE_NULL);
/* remove unlinks automatically */
GST_DEBUG_OBJECT (pipeline, "removing %" GST_PTR_FORMAT, cur_effect);
gst_bin_remove (GST_BIN (pipeline), cur_effect);
GST_DEBUG_OBJECT (pipeline, "adding %" GST_PTR_FORMAT, next);
gst_bin_add (GST_BIN (pipeline), next);
GST_DEBUG_OBJECT (pipeline, "linking..");
gst_element_link_many (conv_before, next, conv_after, NULL);
gst_element_set_state (next, GST_STATE_PLAYING);
cur_effect = next;
GST_DEBUG_OBJECT (pipeline, "done");
return GST_PAD_PROBE_DROP;
}
static GstPadProbeReturn
pad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
GstPad *srcpad, *sinkpad;
GST_DEBUG_OBJECT (pad, "pad is blocked now");
/* remove the probe first */
gst_pad_remove_probe (pad, GST_PAD_PROBE_INFO_ID (info));
/* install new probe for EOS */
srcpad = gst_element_get_static_pad (cur_effect, "src");
gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BLOCK |
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, event_probe_cb, user_data, NULL);
gst_object_unref (srcpad);
/* push EOS into the element, the probe will be fired when the
* EOS leaves the effect and it has thus drained all of its data */
sinkpad = gst_element_get_static_pad (cur_effect, "sink");
gst_pad_send_event (sinkpad, gst_event_new_eos ());
gst_object_unref (sinkpad);
return GST_PAD_PROBE_OK;
}
gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_BLOCK |
GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, event_probe_cb, user_data, NULL);
gst_pad_send_event (sinkpad, gst_event_new_eos ());
if (GST_EVENT_TYPE (GST_PAD_PROBE_INFO_DATA (info)) != GST_EVENT_EOS)
return GST_PAD_PROBE_PASS;