codectimestamper: Implement QUERY_CAPS support

This is required to ensure that downstream restrcitions are also
propagated upstream.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4341>
This commit is contained in:
Thibault Saunier 2023-04-04 17:50:39 -04:00 committed by GStreamer Marge Bot
parent dbc6afd874
commit 5797fa09af
5 changed files with 102 additions and 5 deletions

View file

@ -76,13 +76,16 @@ static GstFlowReturn gst_codec_timestamper_chain (GstPad * pad,
GstObject * parent, GstBuffer * buffer);
static gboolean gst_codec_timestamper_sink_event (GstPad * pad,
GstObject * parent, GstEvent * event);
static gboolean gst_codec_timestamper_sink_query (GstPad * pad,
GstObject * parent, GstQuery * query);
static gboolean gst_codec_timestamper_src_query (GstPad * pad,
GstObject * parent, GstQuery * query);
static GstStateChangeReturn
gst_codec_timestamper_change_state (GstElement * element,
GstStateChange transition);
static void
gst_codec_timestamper_clear_frame (GstCodecTimestamperFrame * frame);
static GstCaps *gst_timestamper_get_caps (GstCodecTimestamper * self,
GstCaps * filter);
static GstStateChangeReturn gst_codec_timestamper_change_state (GstElement *
element, GstStateChange transition);
static void gst_codec_timestamper_clear_frame (GstCodecTimestamperFrame *
frame);
static void gst_codec_timestamper_reset (GstCodecTimestamper * self);
static void gst_codec_timestamper_drain (GstCodecTimestamper * self);
@ -142,6 +145,9 @@ gst_codec_timestamper_class_init (GstCodecTimestamperClass * klass)
element_class->change_state =
GST_DEBUG_FUNCPTR (gst_codec_timestamper_change_state);
/* Default implementation is correct for both H264 and H265 */
klass->get_sink_caps = gst_timestamper_get_caps;
GST_DEBUG_CATEGORY_INIT (gst_codec_timestamper_debug, "codectimestamper", 0,
"codectimestamper");
@ -169,6 +175,9 @@ gst_codec_timestamper_init (GstCodecTimestamper * self,
GST_DEBUG_FUNCPTR (gst_codec_timestamper_chain));
gst_pad_set_event_function (self->sinkpad,
GST_DEBUG_FUNCPTR (gst_codec_timestamper_sink_event));
gst_pad_set_query_function (self->sinkpad,
GST_DEBUG_FUNCPTR (gst_codec_timestamper_sink_query));
GST_PAD_SET_PROXY_SCHEDULING (self->sinkpad);
GST_PAD_SET_ACCEPT_INTERSECT (self->sinkpad);
GST_PAD_SET_ACCEPT_TEMPLATE (self->sinkpad);
@ -582,6 +591,76 @@ gst_codec_timestamper_chain (GstPad * pad, GstObject * parent,
return gst_codec_timestamper_process_output_frame (self);
}
static GstCaps *
gst_timestamper_get_caps (GstCodecTimestamper * self, GstCaps * filter)
{
GstCaps *peercaps, *templ;
GstCaps *res, *tmp, *pcopy;
templ = gst_pad_get_pad_template_caps (self->sinkpad);
if (filter) {
GstCaps *fcopy = gst_caps_copy (filter);
peercaps = gst_pad_peer_query_caps (self->srcpad, fcopy);
gst_caps_unref (fcopy);
} else {
peercaps = gst_pad_peer_query_caps (self->srcpad, NULL);
}
pcopy = gst_caps_copy (peercaps);
res = gst_caps_intersect_full (pcopy, templ, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (pcopy);
gst_caps_unref (templ);
if (filter) {
GstCaps *tmp = gst_caps_intersect_full (res, filter,
GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (res);
res = tmp;
}
/* Try if we can put the downstream caps first */
pcopy = gst_caps_copy (peercaps);
tmp = gst_caps_intersect_full (pcopy, res, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (pcopy);
if (!gst_caps_is_empty (tmp))
res = gst_caps_merge (tmp, res);
else
gst_caps_unref (tmp);
gst_caps_unref (peercaps);
return res;
}
static gboolean
gst_codec_timestamper_sink_query (GstPad * pad, GstObject * parent,
GstQuery * query)
{
GstCodecTimestamper *self = GST_CODEC_TIMESTAMPER (parent);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CAPS:{
GstCaps *caps, *filter;
GstCodecTimestamperClass *klass = GST_CODEC_TIMESTAMPER_GET_CLASS (self);
gst_query_parse_caps (query, &filter);
g_assert (klass->get_sink_caps);
caps = klass->get_sink_caps (self, filter);
GST_LOG_OBJECT (self, "sink getcaps returning caps %" GST_PTR_FORMAT,
caps);
gst_query_set_caps_result (query, caps);
gst_caps_unref (caps);
return TRUE;
}
default:
break;
}
return gst_pad_query_default (pad, parent, query);
}
static gboolean
gst_codec_timestamper_src_query (GstPad * pad, GstObject * parent,
GstQuery * query)

View file

@ -54,6 +54,9 @@ struct _GstCodecTimestamperClass
gboolean (*set_caps) (GstCodecTimestamper * timestamper,
GstCaps * caps);
GstCaps * (*get_sink_caps) (GstCodecTimestamper * timestamper,
GstCaps * filter);
GstFlowReturn (*handle_buffer) (GstCodecTimestamper * timestamper,
GstBuffer * buffer);
};

View file

@ -0,0 +1,9 @@
meta,
args = {
"videotestsrc num-buffers=1 ! video/x-raw,width=1920,height=1080,format=I420 ! videoscale ! x264enc tune=zerolatency ! h264timestamper ! video/x-h264,width=50,height=50 ! fakesink name=sink",
},
configs = {
"$(validateflow), pad=sink:sink, buffers-checksum=as-id, caps-properties={width, height}, ignored-event-types={tag}",
}

View file

@ -0,0 +1,5 @@
event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1;
event caps: video/x-h264, height=(int)50, width=(int)50;
event segment: format=TIME, start=1000:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=1000:00:00.000000000
buffer: content-id=0, dts=1000:00:00.000000000, pts=1000:00:00.000000000, dur=0:00:00.033333333, flags=discont marker
event eos: (no structure)

View file

@ -6,6 +6,7 @@ endif
tests = [
{'path': 'opencv/cvtracker'},
{'path': 'testsrcbin/caps_spec'},
{'path': 'codectimestamper/h264_propagate_caps'},
{'path': 'wpe/load_bytes_first', 'skip': not building_wpe},
]