【问题标题】:Output video duration mismatch with GStreamer in C++输出视频持续时间与 C++ 中的 GStreamer 不匹配
【发布时间】:2019-08-31 23:03:30
【问题描述】:

我正在尝试从 USB 摄像头录制视频,使用 GStreamer 对其进行编码和保存。每 20 秒我想停止视频,更改输出名称并重新开始捕获/编码。

我将发布我的代码的简化版本,因为它很长而且无关紧要。

其他细节: timer 跟踪经过的时间(以秒为单位)。 create_pip(j) 构建以下 gst 管道并将 j 附加到文件名(如 test_rgb_0.mp4、test_rgb_1.mp4 等)

    "v4l2src ! video/x-raw, width=1280, height=720, framerate=30/1, format=RGB ! videoconvert ! omxh265enc bitrate=2000000 qp-range=35,51:35,51:-1,-1 vbv-size=1 iframeinterval=60 ! matroskamux ! filesink location=test_rgb.mp4 -e" 
    // declarations and stuff
    // this for is just to have 3 different video files
    for(int j=0; j<3; j++){
        // create pipeline
        pipeline = gst_parse_launch(create_pip(j).c_str(),NULL);
        gst_element_set_state(pipeline,GST_STATE_PLAYING);
        timer.reset();        // reset timer to 0
        while(timer.elapsed()<=20){
            // do some other stuff, can be ignored
        }
        // stop stream and release pipeline
        gst_element_set_state(pipeline,GST_STATE_NULL);
        gst_object_unref(pipeline);
    }

一切正常,输出视频时长为 20 秒,但 vlc(或 mediainfo)显示视频时长为 0 或 1 秒。如果我打开视频,它实际上是 20 秒长,所以剩余时间为负数(-19 或 -20 秒)。由于我创建的管道在命令行上运行良好,我认为我的程序在关闭流时无法保存一些元数据。抱歉,我对 Gstreamer 还很陌生,我错过了什么?

【问题讨论】:

  • 好吧,既然多路复用器不知道你将不会开始一个新文件,一些元数据可能会丢失。有什么理由不想改用multifilesink
  • 或者splitmuxsink 甚至..
  • @FlorianZwoch 我很笨,我完全忘记了multifilesink 的存在。我刚刚尝试用它建立一个新的管道,但我仍然遇到同样的问题。这是我使用的管道:"v4l2src ! video/x-raw, width=1280, height=720, framerate=30/1, format=RGB ! videoconvert ! omxh265enc bitrate=2000000 qp-range=35,51:35,51:-1,-1 vbv-size=1 iframeinterval=60 ! matroskamux ! multifilesink next-file=5 max-file-duration=20000000000 location=test_rgb_%02d.mp4 -e"
  • 我忘了提,即使我使用gst-launch-1.0 v4l2src ! video/x-raw, width=1280, height=720, framerate=30/1, format=RGB ! videoconvert ! omxh265enc bitrate=2000000 qp-range=35,51:35,51:-1,-1 vbv-size=1 iframeinterval=60 ! matroskamux ! multifilesink next-file=5 max-file-duration=20000000000 location=test_rgb_%02d.mp4 -e 从命令行启动管道,我也会遇到同样的问题。 splitmuxsink 似乎没有链接到 h265enc,但如果我将编码器更改为 h264 并生成 20 秒长的视频,它就可以工作

标签: c++11 gstreamer


【解决方案1】:

哦,我没有意识到您重新启动了整个管道。你需要通过我认为的管道发送 EOS,而不仅仅是将其状态设置为 NULL。

-e 特定于 gst-launch-1.0 应用程序。我相信它不是常规启动语法的一部分。您必须自己执行此操作。

例如

// send EOS to pipeline
gst_element_send_event(pipeline, gst_event_new_eos());

// wait for the EOS to traverse the pipeline and is reported to the bus
GstBus *bus = gst_element_get_bus(pipeline);
gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS);

gst_element_set_state(pipeline, GST_STATE_NULL);

[..]

不过,我不确定是否有实时资源。也许您需要告诉 v4l2src 自己发送 EOS 而不是整个管道。还是只是mp4mux?至少我很确定 mp4 多路复用器在某些时候需要 EOS 才能正确完成文件。

【讨论】:

  • 是的,我肯定错过了 EOS 活动。我实现了您的代码,第一个视频完美运行。但我必须调整我的代码,因为我收到“设备未准备好”错误。我认为该程序试图在它仍在关闭时过早地打开管道。我会及时通知你。
  • 可能是设备需要先结算,你是对的。但也要确保释放所有对象(在获取总线后释放总线等)。再说一次,如果您的目标是连续捕获,我建议您保持运行并使用splitmuxsink。我很惊讶它不适用于 H.265,这是已知的还是错误(?)
  • 其实我觉得mp4mux可能对H.265有具体的要求。也许在splitmuxsink 之前插入h265parse 会有所帮助。再说一次,我不明白为什么到 mp4 的常规管道会起作用..
  • 哦,因为你作弊了,使用 matroskamux 但将其命名为 mp4!如果设置正确,您也可以将 matroskamux 与 splitmuxsink 一起使用(默认为 mp4mux)。
  • 感谢您的提示,我使用了splitmuxsink,并将h265parsemuxer=matroskamux 添加到管道中。一切正常,但我的输出文件比我设置的短 2 秒(例如,如果我设置 max-size-time=10000000000 视频为 8 秒长)。可能是什么问题?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-19
  • 2022-11-06
  • 1970-01-01
相关资源
最近更新 更多