gstreamer:将录制从一个文件切换到另一个文件
gstreamer: Switch recording from one file to another
我正在编写一个应用程序,将传入的视频记录到一个文件中,每隔 't' 秒,保存该文件并记录到一个新文件中。 splitmuxsink 似乎确实实现了这一点,但没有达到我的目的,因为 -
- 不允许连续文件重叠。我希望一个文件的最后几秒也出现在下一个文件中。
- splitmuxsink 也有其他奇怪的问题(与普通文件接收器相比有巨大的延迟,不记录音频和文件接收器,文件的时间戳不正确等)
所以,我想让应用程序每 't' 秒触发一次基于时间的回调。在我的管道中,我有一个多路复用器,我通过它同时写入两个文件一段时间(取决于重叠),然后基于另一个计时器回调,断开旧的文件接收器。
我有以下问题 -
- 以上方案好吗?有更好的想法吗?
- 如何注册定时器回调?仅 OS 系统调用或 gstreamer 是否提供任何 API?
- 断开旧文件接收器的安全方法是什么?是不是应该先断线再发EOS信号?我在这里有点困惑。
- 更改新文件在管道中的时间。 splitmuxsink 中的一个问题是文件的时间戳是管道的 运行 时间,但实际上每次创建新文件时都会重置。 (我不介意目前还没有得到答案;它可能应该完全是一个单独的问题。)
为了了解所涉及的时间,每个文件的持续时间可能为 5 分钟,重叠可能为 1%、3 秒。
我会实施以下解决方案
- 使用
tee
元素将视频分成 2 个动态(在运行时)创建的源(src pad),其中 mux
和 filesink
作为每个 [=15= 的下游元素]
根据您的逻辑动态地 add/remove tee
src 填充 1 和 2(以及附加元素 src->mux->filesink)。在您的情况下,您需要以标准方式为您的环境实施 2 个计时器。
正如您所说,有一种安全的断开连接方式"older filesink"。在建议的解决方案中,您需要 disconnect/remove "old" src->mux->filesink 管道的一部分,方法是在要删除的 tee
src pad 上注册阻塞 probe
。例如,安全删除 src1 及其下游元素可以像这样实现
GstElement* videoTee = gst_bin_get_by_name(GST_BIN(pipeline), "tee");
GstPad* srcPad = gst_element_get_static_pad(videoTee, "src_1");
gst_pad_add_probe(srcPad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, remove_video_tee_block_probe_cb, &user_data, NULL);
gst_object_unref(srcPad);
gst_object_unref(videoTee);
然后,在remove_video_tee_block_probe_cb
回调中,可以移除src pad和连接的mux和filesink
GstPadProbeReturn remove_video_tee_block_probe_cb(GstPad* pad, GstPadProbeInfo* info, gpointer user_data) {
/*user_data should contain reference to pipeline*/
StreamData* streamData = (StreamData*)user_data;
GstElement* videoTee = gst_bin_get_by_name(GST_BIN(streamData->pipeline), "videoTee");
/*video tee src pad is blocked now and it can be safely removed*/
gst_element_release_request_pad(videoTee, pad);
GstElement* mux = gst_bin_get_by_name(GST_BIN(streamData->pipeline), "mux1");
GstElement* fileSink =gst_bin_get_by_name(GST_BIN(streamData->pipeline), "sink1");
/* set state of element from PLAYING to NULL */
gst_element_set_state(mux, GST_STATE_NULL);
gst_element_set_state(fileSink, GST_STATE_NULL);
/* remove elements from pipeline */
gst_bin_remove(GST_BIN(streamData->pipeline), mux);
gst_bin_remove(GST_BIN(streamData->pipeline), fileSink);
gst_object_unref(videoTee);
/* remove the probe*/
gst_pad_remove_probe(pad, GST_PAD_PROBE_INFO_ID(info));
return GST_PAD_PROBE_OK;
}
此解决方案将允许您通过 adding/removing src->mux->filesink 管道部分根据您的逻辑在计时器回调中控制运行时文件接收器的存在。
我正在编写一个应用程序,将传入的视频记录到一个文件中,每隔 't' 秒,保存该文件并记录到一个新文件中。 splitmuxsink 似乎确实实现了这一点,但没有达到我的目的,因为 -
- 不允许连续文件重叠。我希望一个文件的最后几秒也出现在下一个文件中。
- splitmuxsink 也有其他奇怪的问题(与普通文件接收器相比有巨大的延迟,不记录音频和文件接收器,文件的时间戳不正确等)
所以,我想让应用程序每 't' 秒触发一次基于时间的回调。在我的管道中,我有一个多路复用器,我通过它同时写入两个文件一段时间(取决于重叠),然后基于另一个计时器回调,断开旧的文件接收器。
我有以下问题 -
- 以上方案好吗?有更好的想法吗?
- 如何注册定时器回调?仅 OS 系统调用或 gstreamer 是否提供任何 API?
- 断开旧文件接收器的安全方法是什么?是不是应该先断线再发EOS信号?我在这里有点困惑。
- 更改新文件在管道中的时间。 splitmuxsink 中的一个问题是文件的时间戳是管道的 运行 时间,但实际上每次创建新文件时都会重置。 (我不介意目前还没有得到答案;它可能应该完全是一个单独的问题。)
为了了解所涉及的时间,每个文件的持续时间可能为 5 分钟,重叠可能为 1%、3 秒。
我会实施以下解决方案
- 使用
tee
元素将视频分成 2 个动态(在运行时)创建的源(src pad),其中mux
和filesink
作为每个 [=15= 的下游元素]
根据您的逻辑动态地 add/remove
tee
src 填充 1 和 2(以及附加元素 src->mux->filesink)。在您的情况下,您需要以标准方式为您的环境实施 2 个计时器。正如您所说,有一种安全的断开连接方式"older filesink"。在建议的解决方案中,您需要 disconnect/remove "old" src->mux->filesink 管道的一部分,方法是在要删除的
tee
src pad 上注册阻塞probe
。例如,安全删除 src1 及其下游元素可以像这样实现GstElement* videoTee = gst_bin_get_by_name(GST_BIN(pipeline), "tee"); GstPad* srcPad = gst_element_get_static_pad(videoTee, "src_1"); gst_pad_add_probe(srcPad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, remove_video_tee_block_probe_cb, &user_data, NULL); gst_object_unref(srcPad); gst_object_unref(videoTee);
然后,在
remove_video_tee_block_probe_cb
回调中,可以移除src pad和连接的mux和filesinkGstPadProbeReturn remove_video_tee_block_probe_cb(GstPad* pad, GstPadProbeInfo* info, gpointer user_data) { /*user_data should contain reference to pipeline*/ StreamData* streamData = (StreamData*)user_data; GstElement* videoTee = gst_bin_get_by_name(GST_BIN(streamData->pipeline), "videoTee"); /*video tee src pad is blocked now and it can be safely removed*/ gst_element_release_request_pad(videoTee, pad); GstElement* mux = gst_bin_get_by_name(GST_BIN(streamData->pipeline), "mux1"); GstElement* fileSink =gst_bin_get_by_name(GST_BIN(streamData->pipeline), "sink1"); /* set state of element from PLAYING to NULL */ gst_element_set_state(mux, GST_STATE_NULL); gst_element_set_state(fileSink, GST_STATE_NULL); /* remove elements from pipeline */ gst_bin_remove(GST_BIN(streamData->pipeline), mux); gst_bin_remove(GST_BIN(streamData->pipeline), fileSink); gst_object_unref(videoTee); /* remove the probe*/ gst_pad_remove_probe(pad, GST_PAD_PROBE_INFO_ID(info)); return GST_PAD_PROBE_OK; }
此解决方案将允许您通过 adding/removing src->mux->filesink 管道部分根据您的逻辑在计时器回调中控制运行时文件接收器的存在。