Gstreamer 从T形三通中删除分支时将EoS发送到FileLink

Gstreamer 从T形三通中删除分支时将EoS发送到FileLink,gstreamer,Gstreamer,我已经为v4l2src同时显示和录制编写了一个代码。 我的管道看起来像: / [queue] ! [videosink] v4l2src ! tee ! \ [queue] ! [filesink] 目前,我可以同时显示+record,还可以随意动态地启动和停止记录分支(使用ctrl+c sigint处理程序启动/停止)。 我使用了@thiagoss的建议作为回答,以及文章的部分内容 问题: 我面临的唯一问题是在断开链接时将EoS

我已经为v4l2src同时显示和录制编写了一个代码。 我的管道看起来像:

               / [queue] ! [videosink]
v4l2src ! tee !  
               \ [queue] ! [filesink]
目前,我可以同时显示+record,还可以随意动态地启动和停止记录分支(使用ctrl+c sigint处理程序启动/停止)。 我使用了@thiagoss的建议作为回答,以及文章的部分内容

问题:

我面临的唯一问题是在断开链接时将EoS发送到FileLink分支。我要发送到哪个元素
gst\u元素\u发送\u事件(-->?src);
gst\消息\解析\错误(消息、错误和调试);
g_printerr(“错误:来自元素%s:%s\n”,名称,错误->消息);
如果(调试!=NULL)
g_printerr(“其他调试信息:\n%s\n”,调试);
g_无错误(err);
g_自由(调试);
g_free(姓名);
g_主循环退出(循环);
打破
}
案例信息警告:{
GError*err=NULL;
gchar*name,*debug=NULL;
name=gst\u object\u get\u path\u string(message->src);
gst\u消息\u解析\u警告(消息、错误和调试);
g_printerr(“错误:来自元素%s:%s\n”,名称,错误->消息);
如果(调试!=NULL)
g_printerr(“其他调试信息:\n%s\n”,调试);
g_无错误(err);
g_自由(调试);
g_free(姓名);
打破
}
案例GST\信息\ EOS:{
g_print(“获得EOS\n”);
g_主循环退出(循环);
gst\元素\集合\状态(管道,gst\状态\空);
g_主回路_unref(回路);
gst_对象_unref(管道);
出口(0);
打破
}
违约:
打破
}
返回TRUE;
}
静态GstPadProbeReturn unlink_cb(GstPad*pad、GstPadProbeInfo*info、gpointer用户_数据){
g_打印(“取消链接…”);
GstPad*下沉板;
sinkpad=gst_元素_获取_静态_垫(队列_记录,“接收器”);
gst_pad_unlink(teepad、sinkpad);
gst_object_unref(下沉板);
gst_元素_发送_事件(文件链接,gst_事件_新建_eos());
睡眠(1);
gst_-bin_移除(gst_-bin(管道)、队列记录);
gst_-bin_移除(gst_-bin(管道)、编码器);
//gst_-bin_移除(gst_-bin(管道),muxer);
gst_-bin_移除(gst_-bin(管道)、文件链接);
gst元素设置状态(队列记录,gst状态为空);
gst元素设置状态(编码器,gst状态为空);
//gst_元素_集合_状态(muxer,gst_状态_NULL);
gst元素设置状态(文件链接,gst状态为空);
gst_对象_unref(队列记录);
gst_object_unref(编码器);
//商品及服务税(muxer);
gst_object_unref(文件链接);
gst、元件、释放、请求、垫(三通、三通);
gst_object_unref(teepad);
g_print(“未链接的\n”);
返回GST\u焊盘\u探头\u移除;
}
void stopRecording(){
g_print(“停止录制”);
gst_焊盘_添加_探头(teepad、gst_焊盘_探头_类型_空闲、取消链接_cb、NULL、(GDestroyNotify)g_免费);
记录=假;
}
无效开始记录(){
g_print(“startRecording\n”);
GstPad*下沉板;
GstPadTemplate*模板;
templ=gst_元素_类_获取_垫_模板(gst_元素_获取_类(tee),“src_uu%u”);
teepad=gst\u元素\u请求\u垫(tee,temp,NULL,NULL);
队列记录=gst元素工厂制造(“队列”、“队列记录”);
编码器=gst元素工厂制造(“x264enc”,空);
//muxer=gst\u元素\u工厂制造商(“mp4mux”,空);
filesink=gst\u元素\u工厂\u品牌(“filesink”,NULL);
char*文件名=(char*)malloc(100*sizeof(char));
sprintf(文件名,“/home/rish/Desktop/rec%d.mp4”,计数器++);
g_打印(文件名);
g_对象_集(文件链接,“位置”,文件名,空);
g_对象_集(编码器,“调谐”,4,空);
免费(文件名);
gst_bin_add_many(gst_bin(管道)、gst_object_ref(队列记录)、gst_object_ref(编码器)、gst_object_ref(文件链接)、NULL);
gst\u元素\u链接\u多(队列\u记录、编码器、文件链接、空);
gst\u元素\u与\u父项同步\u状态\u(队列\u记录);
gst\u元素\u与\u父项(编码器)同步\u状态\u;
//gst\u元素\u与父级同步\u状态\u(muxer);
gst\u元素\u与\u父项同步\u状态\u(文件链接);
sinkpad=gst_元素_获取_静态_垫(队列_记录,“接收器”);
gst_pad_link(teepad、sinkpad);
gst_object_unref(下沉板);
记录=真;
}
int sigintHandler(int未使用){
g_print(“您ctrl-c!\n”);
如果(录音)
停止录制();
其他的
startRecording();
返回0;
}
int main(int argc,char*argv[])
{
信号(SIGINT,sigintHandler);
gst_init(&argc,&argv);
管道=gst_管道_新(空);
src=gst元素工厂制造(“v4l2src”,空);
三通=gst、元件、工厂制造(“三通”、“三通”);
队列显示=gst元素工厂制造(“队列”、“队列显示”);
videoconvert=gst元素工厂制造(“videoconvert”,空);
videosink=gst元素工厂制造(“自动视频接收器”,空);
如果(!pipeline | | |!src | |!tee | |!videoconvert | |!videosink | |!队列|显示){
g_错误(“未能创建元素”);
返回-1;
}
gst_bin_add_many(gst_bin(管道)、src、tee、队列显示、videoconvert、videosink、NULL);
如果(!gst\u元素\u链接\u多(src,tee,NULL)
||!gst\u元素\u链接\u多(T形三通、队列\u显示、videoconvert、videosink、NULL)){
g_错误(“链接元素失败”);
返回-2;
}
startRecording();
loop=g_main_loop_new(NULL,FALSE);
总线=gst_管道_获取_总线(gst_管道(管道));
gst_总线_添加_信号_手表(总线);
g_信号_连接(g_对象(总线),“消息”,g_回调(消息_cb),NULL);
gst_对象_unref(gst_对象(总线));
gst元素设置状态(管道、gst状态);
g_打印(“开始循环\n”);
g_主循环运行(循环);
返回0;
}

您应该将其发送给编码器,以便他们能够正确完成工作,并将其转发给muxer,muxer还需要通过写入只能在末尾写入的部分头来包装文件


此外,删除该睡眠,您需要确保FileLink发布了EOS消息,以确保该消息已全部处理完毕,并且删除它们是安全的。您可能需要为管道启用
消息转发
,否则它将保留EOS消息,直到所有接收器发布其EOS(这在您的情况下不会发生,因为videosink)。

我已将带有编码器的文件链接放在一个单独的容器中,并覆盖
句柄消息()忽略EOS并将其转换为自定义消息

初始EOS被发送到ghostpad
#include <string.h>
#include <gst/gst.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

// v4l2src ! tee name=t t. ! x264enc ! mp4mux ! filesink location=/home/rish/Desktop/okay.264 t. ! videoconvert ! autovideosink

static GMainLoop *loop;
static GstElement *pipeline, *src, *tee, *encoder, *muxer, *filesink, *videoconvert, *videosink, *queue_record, *queue_display;
static GstBus *bus;
static GstPad *teepad;
static gboolean recording = FALSE;
static gint counter = 0;

static gboolean
message_cb (GstBus * bus, GstMessage * message, gpointer 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 ("Got EOS\n");
    g_main_loop_quit (loop);
    gst_element_set_state (pipeline, GST_STATE_NULL);
    g_main_loop_unref (loop);
    gst_object_unref (pipeline);
    exit(0);
    break;
}
default:
    break;
}

return TRUE;
}

static GstPadProbeReturn unlink_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) {
g_print("Unlinking...");
GstPad *sinkpad;
sinkpad = gst_element_get_static_pad (queue_record, "sink");
gst_pad_unlink (teepad, sinkpad);
gst_object_unref (sinkpad);

gst_element_send_event(filesink, gst_event_new_eos());

sleep(1);
gst_bin_remove(GST_BIN (pipeline), queue_record);
gst_bin_remove(GST_BIN (pipeline), encoder);
// gst_bin_remove(GST_BIN (pipeline), muxer);
gst_bin_remove(GST_BIN (pipeline), filesink);

gst_element_set_state(queue_record, GST_STATE_NULL);
gst_element_set_state(encoder, GST_STATE_NULL);
// gst_element_set_state(muxer, GST_STATE_NULL);
gst_element_set_state(filesink, GST_STATE_NULL);

gst_object_unref(queue_record);
gst_object_unref(encoder);
// gst_object_unref(muxer);
gst_object_unref(filesink);

gst_element_release_request_pad (tee, teepad);
gst_object_unref (teepad);

g_print("Unlinked\n");

return GST_PAD_PROBE_REMOVE;
}

void stopRecording() {
    g_print("stopRecording\n");
    gst_pad_add_probe(teepad, GST_PAD_PROBE_TYPE_IDLE, unlink_cb, NULL, (GDestroyNotify) g_free);
    recording = FALSE;
}

 void startRecording() {
g_print("startRecording\n");
GstPad *sinkpad;
GstPadTemplate *templ;

templ = gst_element_class_get_pad_template(GST_ELEMENT_GET_CLASS(tee), "src_%u");
teepad = gst_element_request_pad(tee, templ, NULL, NULL);
queue_record = gst_element_factory_make("queue", "queue_record");
encoder = gst_element_factory_make("x264enc", NULL);
// muxer = gst_element_factory_make("mp4mux", NULL);
filesink = gst_element_factory_make("filesink", NULL);
char *file_name = (char*) malloc(100*sizeof(char));
sprintf(file_name, "/home/rish/Desktop/rec%d.mp4", counter++);
g_print(file_name);
g_object_set(filesink, "location", file_name, NULL);
g_object_set(encoder, "tune", 4, NULL);
free(file_name);

gst_bin_add_many(GST_BIN(pipeline), gst_object_ref(queue_record), gst_object_ref(encoder), gst_object_ref(filesink), NULL);
gst_element_link_many(queue_record, encoder, filesink, NULL);

gst_element_sync_state_with_parent(queue_record);
gst_element_sync_state_with_parent(encoder);
// gst_element_sync_state_with_parent(muxer);
gst_element_sync_state_with_parent(filesink);

sinkpad = gst_element_get_static_pad(queue_record, "sink");
gst_pad_link(teepad, sinkpad);
gst_object_unref(sinkpad);

recording = TRUE;
}

int sigintHandler(int unused) {
g_print("You ctrl-c!\n");
if (recording)
    stopRecording();
else
    startRecording();
return 0;
}

int main(int argc, char *argv[])
{
signal(SIGINT, sigintHandler);
gst_init (&argc, &argv);

pipeline = gst_pipeline_new(NULL);
src = gst_element_factory_make("v4l2src", NULL);
tee = gst_element_factory_make("tee", "tee");
queue_display = gst_element_factory_make("queue", "queue_display");
videoconvert = gst_element_factory_make("videoconvert", NULL);
videosink = gst_element_factory_make("autovideosink", NULL);

if (!pipeline || !src || !tee || !videoconvert || !videosink || !queue_display) {
    g_error("Failed to create elements");
    return -1;
}

gst_bin_add_many(GST_BIN(pipeline), src, tee, queue_display, videoconvert, videosink, NULL);
if (!gst_element_link_many(src, tee, NULL) 
    || !gst_element_link_many(tee, queue_display, videoconvert, videosink, NULL)) {
    g_error("Failed to link elements");
    return -2;
}

startRecording();
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_print("Starting loop\n");
g_main_loop_run(loop);

return 0;
}