From 4dbf61d1ef1441a7600346cec970e272512a4319 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 30 Mar 2021 15:34:11 -0400 Subject: [PATCH] alphacodecdemux: Implement meta demuxing Produce two streams from a buffer that has GstVideoCodecAlphaMeta attached. Part-of: --- gst/codecalpha/gstcodecalphademux.c | 223 +++++++++++++++++++++++++++++++++++- 1 file changed, 217 insertions(+), 6 deletions(-) diff --git a/gst/codecalpha/gstcodecalphademux.c b/gst/codecalpha/gstcodecalphademux.c index 2d013bc..bb0b0ca 100644 --- a/gst/codecalpha/gstcodecalphademux.c +++ b/gst/codecalpha/gstcodecalphademux.c @@ -22,9 +22,9 @@ * SECTION:element-codecalphademux * @title: CODEC Alpha Demuxer * - * Extract the CODEC (typically VP8/VP9) alpha stream stored at meta and - * expose it as a stream. This element allow using single stream VP9 decoders - * in order to decode both streams. + * Extracts the CODEC (typically VP8/VP9) alpha stream stored as meta and + * exposes it as a stream. This element allow using single stream VP8/9 + * decoders in order to decode both streams. * * ## Example launch line * |[ @@ -33,8 +33,9 @@ * d.video ! queue ! vp9dec ! autovideosink * d.alpha ! queue ! vp9dec ! autovideosink * ]| This pipeline splits and decode the video and the alpha stream, showing - * the result on seperate window. + * the result on seperate windows. * + * Since: 1.20 */ #ifdef HAVE_CONFIG_H @@ -42,6 +43,8 @@ #endif #include +#include + #include "gstcodecalphademux.h" GST_DEBUG_CATEGORY_STATIC (codecalphademux_debug); @@ -50,10 +53,16 @@ GST_DEBUG_CATEGORY_STATIC (codecalphademux_debug); struct _GstCodecAlphaDemux { GstElement parent; + + GstPad *sink_pad; + GstPad *src_pad; + GstPad *alpha_pad; + + GstFlowCombiner *flow_combiner; }; #define gst_codec_alpha_demux_parent_class parent_class -G_DEFINE_TYPE_WITH_CODE (GstCodecAlphaDemux, gst_codec_alpha_demux, +G_DEFINE_TYPE_WITH_CODE (GstCodecAlphaDemux, gst_codec_alpha_demux, GST_TYPE_ELEMENT, GST_DEBUG_CATEGORY_INIT (codecalphademux_debug, "codecalphademux", 0, "codecalphademux")); @@ -82,10 +91,187 @@ GST_STATIC_PAD_TEMPLATE ("alpha", GST_STATIC_CAPS ("ANY") ); +static GstFlowReturn +gst_codec_alpha_demux_chain (GstPad * pad, GstObject * object, + GstBuffer * buffer) +{ + GstCodecAlphaDemux *self = GST_CODEC_ALPHA_DEMUX (object); + GstVideoCodecAlphaMeta *alpha_meta = + gst_buffer_get_video_codec_alpha_meta (buffer); + GstBuffer *alpha_buffer = NULL; + GstClockTime pts = GST_BUFFER_PTS (buffer); + GstClockTime duration = GST_BUFFER_DURATION (buffer); + GstFlowReturn ret; + + if (alpha_meta) + alpha_buffer = gst_buffer_ref (alpha_meta->buffer); + + ret = gst_flow_combiner_update_pad_flow (self->flow_combiner, + self->src_pad, gst_pad_push (self->src_pad, buffer)); + + /* we lost ownership here */ + buffer = NULL; + alpha_meta = NULL; + + if (alpha_buffer) + ret = gst_flow_combiner_update_pad_flow (self->flow_combiner, + self->alpha_pad, gst_pad_push (self->alpha_pad, alpha_buffer)); + else + ret = gst_flow_combiner_update_pad_flow (self->flow_combiner, + self->alpha_pad, gst_pad_push_event (self->alpha_pad, + gst_event_new_gap (pts, duration))); + + + return ret; +} + +static GstCaps * +gst_codec_alpha_demux_transform_caps (GstCaps * caps, gboolean codec_alpha) +{ + if (!caps) + return NULL; + + caps = gst_caps_copy (caps); + gst_caps_set_simple (caps, "codec-alpha", G_TYPE_BOOLEAN, codec_alpha, NULL); + + return caps; +} + +static GstEvent * +gst_codec_alpha_demux_transform_caps_event (GstEvent * src_event) +{ + GstEvent *dst_event; + GstCaps *caps; + + gst_event_parse_caps (src_event, &caps); + + caps = gst_codec_alpha_demux_transform_caps (caps, FALSE); + dst_event = gst_event_new_caps (caps); + gst_event_set_seqnum (dst_event, gst_event_get_seqnum (src_event)); + + gst_caps_unref (caps); + gst_event_unref (src_event); + return dst_event; +} + +static gboolean +gst_codec_alpha_demux_sink_event (GstPad * sink_pad, GstObject * parent, + GstEvent * event) +{ + GstCodecAlphaDemux *self = GST_CODEC_ALPHA_DEMUX (parent); + + switch (event->type) { + case GST_EVENT_FLUSH_STOP: + gst_flow_combiner_reset (self->flow_combiner); + break; + case GST_EVENT_CAPS: + event = gst_codec_alpha_demux_transform_caps_event (event); + break; + default: + break; + } + + return gst_pad_event_default (sink_pad, parent, event); +} + +static gboolean +gst_codec_alpha_demux_sink_query (GstPad * sink_pad, GstObject * parent, + GstQuery * query) +{ + GstQuery *peer_query; + GstCaps *caps; + gboolean ret; + + switch (query->type) { + case GST_QUERY_CAPS: + gst_query_parse_caps (query, &caps); + caps = gst_codec_alpha_demux_transform_caps (caps, FALSE); + peer_query = gst_query_new_caps (caps); + gst_clear_caps (&caps); + break; + case GST_QUERY_ACCEPT_CAPS: + gst_query_parse_accept_caps (query, &caps); + caps = gst_codec_alpha_demux_transform_caps (caps, FALSE); + peer_query = gst_query_new_accept_caps (caps); + gst_clear_caps (&caps); + break; + default: + peer_query = query; + break; + } + + ret = gst_pad_query_default (sink_pad, parent, peer_query); + if (!ret) { + if (peer_query != query) + gst_query_unref (peer_query); + return FALSE; + } + + switch (query->type) { + case GST_QUERY_CAPS: + gst_query_parse_caps_result (peer_query, &caps); + caps = gst_caps_copy (caps); + caps = gst_codec_alpha_demux_transform_caps (caps, TRUE); + gst_query_set_caps_result (query, caps); + gst_caps_unref (caps); + gst_query_unref (peer_query); + break; + case GST_QUERY_ACCEPT_CAPS: + { + gboolean result; + gst_query_parse_accept_caps_result (peer_query, &result); + gst_query_set_accept_caps_result (query, result); + gst_query_unref (peer_query); + break; + } + default: + break; + } + + + return ret; +} + +static void +gst_codec_alpha_demux_start (GstCodecAlphaDemux * self) +{ + gst_flow_combiner_reset (self->flow_combiner); +} + +static GstStateChangeReturn +gst_codec_alpha_demux_change_state (GstElement * element, + GstStateChange transition) +{ + GstCodecAlphaDemux *self = GST_CODEC_ALPHA_DEMUX (element); + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + gst_codec_alpha_demux_start (self); + default: + break; + } + + return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); +} + +static void +gst_codec_alpha_demux_dispose (GObject * object) +{ + GstCodecAlphaDemux *self = GST_CODEC_ALPHA_DEMUX (object); + + g_clear_object (&self->sink_pad); + g_clear_object (&self->src_pad); + g_clear_object (&self->alpha_pad); + g_clear_pointer (&self->flow_combiner, gst_flow_combiner_unref); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + static void gst_codec_alpha_demux_class_init (GstCodecAlphaDemuxClass * klass) { GstElementClass *element_class = (GstElementClass *) klass; + GObjectClass *object_class = (GObjectClass *) klass; gst_element_class_set_static_metadata (element_class, "CODEC Alpha Demuxer", "Codec/Demuxer", @@ -98,9 +284,34 @@ gst_codec_alpha_demux_class_init (GstCodecAlphaDemuxClass * klass) &gst_codec_alpha_demux_src_template); gst_element_class_add_static_pad_template (element_class, &gst_codec_alpha_demux_alpha_template); + + element_class->change_state = + GST_DEBUG_FUNCPTR (gst_codec_alpha_demux_change_state); + + object_class->dispose = GST_DEBUG_FUNCPTR (gst_codec_alpha_demux_dispose); } static void -gst_codec_alpha_demux_init (GstCodecAlphaDemux * demux) +gst_codec_alpha_demux_init (GstCodecAlphaDemux * self) { + gst_element_create_all_pads (GST_ELEMENT (self)); + self->sink_pad = gst_element_get_static_pad (GST_ELEMENT (self), "sink"); + self->src_pad = gst_element_get_static_pad (GST_ELEMENT (self), "src"); + self->alpha_pad = gst_element_get_static_pad (GST_ELEMENT (self), "alpha"); + + self->flow_combiner = gst_flow_combiner_new (); + gst_flow_combiner_add_pad (self->flow_combiner, self->src_pad); + gst_flow_combiner_add_pad (self->flow_combiner, self->alpha_pad); + + GST_PAD_SET_PROXY_CAPS (self->sink_pad); + GST_PAD_SET_PROXY_CAPS (self->src_pad); + GST_PAD_SET_PROXY_CAPS (self->alpha_pad); + + GST_PAD_SET_PROXY_SCHEDULING (self->sink_pad); + GST_PAD_SET_PROXY_SCHEDULING (self->src_pad); + GST_PAD_SET_PROXY_SCHEDULING (self->alpha_pad); + + gst_pad_set_chain_function (self->sink_pad, gst_codec_alpha_demux_chain); + gst_pad_set_event_function (self->sink_pad, gst_codec_alpha_demux_sink_event); + gst_pad_set_query_function (self->sink_pad, gst_codec_alpha_demux_sink_query); } -- 2.7.4