如何控制uridecodebin中编码数据的解码帧率?
解决方案
核心思路:在解码前插入帧率控制元件
你需要在视频解码器之前插入帧率控制逻辑,避免解码后丢帧浪费资源。uridecodebin是自动搭建内部管道的元件,所以要通过监听它的信号动态插入自定义元件——autovideosrc并不适用,它是本地视频输入源的自动选择工具(比如摄像头、屏幕录制),和你处理URI源的场景不匹配。
具体实现方案
方案1:用urisourcebin + decodebin手动搭建管道(灵活可控)
urisourcebin负责处理各类URI源(RTSP/HTTP/文件)并输出解复用后的流,你可以在它和decodebin之间插入帧率控制元件,实现解码前降帧:
# 通用示例:将帧率降到1帧/60秒 gst-launch-1.0 urisourcebin uri=rtsp://your-stream-uri \ ! queue \ ! videorate \ ! video/x-raw,framerate=1/60 \ ! decodebin \ ! autovideosink
如果是H.264编码的流,可更精准地在解封装后插入控制逻辑:
gst-launch-1.0 urisourcebin uri=rtsp://your-stream-uri \ ! application/x-rtp,media=video \ ! rtph264depay \ ! h264parse \ ! videorate \ ! video/x-h264,framerate=1/60 \ ! avdec_h264 \ ! autovideosink
方案2:监听uridecodebin信号动态插入元件(适配自动管道)
通过uridecodebin的pad-added信号,在内部解复用器输出视频pad时,插入videorate和capsfilter来控制帧率:
#include <gst/gst.h> static GstPadProbeReturn pad_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data) { GstElement *videorate = gst_element_factory_make("videorate", NULL); GstElement *capsfilter = gst_element_factory_make("capsfilter", NULL); GstCaps *caps = gst_caps_from_string("video/x-raw,framerate=1/60"); g_object_set(capsfilter, "caps", caps, NULL); gst_caps_unref(caps); GstElement *pipeline = GST_ELEMENT(user_data); gst_bin_add_many(GST_BIN(pipeline), videorate, capsfilter, NULL); gst_element_sync_state_with_parent(videorate); gst_element_sync_state_with_parent(capsfilter); // 重新连接管道:原pad → videorate → capsfilter → 解码器 GstPad *src_pad = gst_element_get_static_pad(videorate, "sink"); gst_pad_link(pad, src_pad); gst_object_unref(src_pad); src_pad = gst_element_get_static_pad(videorate, "src"); GstPad *sink_pad = gst_element_get_static_pad(capsfilter, "sink"); gst_pad_link(src_pad, sink_pad); gst_object_unref(src_pad); gst_object_unref(sink_pad); src_pad = gst_element_get_static_pad(capsfilter, "src"); GstPad *decode_pad = gst_element_get_request_pad(GST_ELEMENT(info->data), "sink"); gst_pad_link(src_pad, decode_pad); gst_object_unref(src_pad); gst_object_unref(decode_pad); return GST_PAD_PROBE_REMOVE; } static void pad_added_cb(GstElement *src, GstPad *new_pad, gpointer user_data) { gchar *pad_name = gst_pad_get_name(new_pad); if (g_str_has_prefix(pad_name, "video_")) { gst_pad_add_probe(new_pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, pad_probe_cb, user_data, NULL); } g_free(pad_name); } int main(int argc, char *argv[]) { gst_init(&argc, &argv); GstElement *pipeline = gst_pipeline_new("frame-rate-control-pipeline"); GstElement *uridecodebin = gst_element_factory_make("uridecodebin", NULL); GstElement *sink = gst_element_factory_make("autovideosink", NULL); g_object_set(uridecodebin, "uri", argv[1], NULL); gst_bin_add_many(GST_BIN(pipeline), uridecodebin, sink, NULL); g_signal_connect(uridecodebin, "pad-added", G_CALLBACK(pad_added_cb), pipeline); gst_element_link_many(uridecodebin, sink, NULL); gst_element_set_state(pipeline, GST_STATE_PLAYING); GstBus *bus = gst_element_get_bus(pipeline); gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS); gst_element_set_state(pipeline, GST_STATE_NULL); gst_object_unref(pipeline); return 0; }
关键说明
videorate元件会根据设置的帧率在解码前丢弃多余帧,避免解码器做无用功;- 若处理固定编码格式的流,用
urisourcebin搭建管道更简单易维护;若需兼容多种编码,监听uridecodebin信号是通用方案。
内容的提问来源于stack exchange,提问作者Il'ya Zhenin
相关产品推荐
相关产品推荐

