将EoS发送到fileink,同时从tee删除分支 [英] Sending EoS to filesink while removing branch from tee

查看:163
本文介绍了将EoS发送到fileink,同时从tee删除分支的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have written a code for v4l2src display and recording at the same time. My pipeline looks like :

               / [queue] ! [videosink]
v4l2src ! tee !  
               \ [queue] ! [filesink]

当前,我能够一起显示+记录,还可以随意地动态启动和停止记录分支(使用ctrl + c sigint处理程序进行启动/停止). 我在中使用了@thiagoss的建议答案,以及本文的部分内容.

Currently I am able to display + record together, and also dynamically start and stop the record branch at will (using ctrl+c sigint handler for start/stop). I used @thiagoss' advice in this answer, and parts of this article.

问题:

我面临的唯一问题是在取消链接时将EoS发送到filesink分支.我将事件发送到哪个元素gst_element_send_event(-->?<--, gst_event_new_eos());?我无法将其发送到整个管道,因为1.分支现在已取消链接,并且2.即使已链接,它也会关闭videoink.

The only problem I am facing is sending EoS to filesink branch upon unlinking. To what element do I send gst_element_send_event(-->?<--, gst_event_new_eos()); the event to? I can't send it to the entire pipeline because 1. branch is now unlinked and 2. even if I do, it will close the videosink.

我尝试过的方法:在删除mp4mux并仅保存h264编码的视频时,我可以使用gst-playbin观看视频,这意味着分支的创建和取消链接是正确的.

What I've tried: On removing mp4mux and just saving h264 encoded video, I am able to use gst-playbin to view the video, meaning the branch creation and unlinking is happening correctly.

以下是我的代码.

#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;
}

推荐答案

您应该将其发送给编码器,以便他们可以正确完成工作,并将其转发给复用器,该复用器还需要通过以下方式对文件进行包装编写标头只能写到最后的部分.

You should send it to the encoders, so that they can properly finalize their work and they will forward it to the muxer that also needs to wrap up the file by writing the parts of the headers that they can only write at the end.

此外,请删除该睡眠,您将需要确保filesink发布了一条EOS消息,以确保已将其全部处理完毕,并且可以安全地删除它们.您可能需要为管道启用message-forward,否则它将保存EOS消息,直到所有接收器都发布其EOS(在这种情况下,由于视频接收器而未发生).

Also, remove that sleep and you will need to make sure filesink posted a EOS message to be sure it has all been processed and it is safe to remove them. You might need to enable message-forward for the pipeline otherwise it will hold the EOS messages until all sinks post their EOS (which isn't happening in your case because of the videosink).

这篇关于将EoS发送到fileink,同时从tee删除分支的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆