diff --git a/subprojects/gst-libav/ext/libav/gstavdemux.c b/subprojects/gst-libav/ext/libav/gstavdemux.c index e756a09666..811092b29d 100644 --- a/subprojects/gst-libav/ext/libav/gstavdemux.c +++ b/subprojects/gst-libav/ext/libav/gstavdemux.c @@ -69,6 +69,8 @@ struct _GstFFMpegDemux AVFormatContext *context; /* set while avformat_open_input() is called */ gboolean opening; + /* global tags */ + GstTagList *tags, *upstream_global_tags, *upstream_stream_tags; GstFFStream *streams[MAX_STREAMS]; @@ -345,6 +347,7 @@ gst_ffmpegdemux_close (GstFFMpegDemux * demux) } demux->videopads = 0; demux->audiopads = 0; + gst_clear_tag_list (&demux->tags); /* close demuxer context from ffmpeg */ if (demux->seekable) @@ -1223,7 +1226,7 @@ gst_ffmpegdemux_open (GstFFMpegDemux * demux) GstFFMpegDemuxClass *oclass = (GstFFMpegDemuxClass *) G_OBJECT_GET_CLASS (demux); gint res, n_streams, i; - GstTagList *tags; + GstTagList *tags = NULL; GstEvent *event; GList *cached_events; GstQuery *query; @@ -1331,10 +1334,31 @@ gst_ffmpegdemux_open (GstFFMpegDemux * demux) } /* grab the global tags */ - tags = gst_ffmpeg_metadata_to_tag_list (demux->context->metadata); - if (tags) { + demux->tags = gst_ffmpeg_metadata_to_tag_list (demux->context->metadata); + if (demux->tags) { + GstTagList *upstream_tags; + gst_tag_list_set_scope (demux->tags, GST_TAG_SCOPE_GLOBAL); - GST_INFO_OBJECT (demux, "global tags: %" GST_PTR_FORMAT, demux->tags); + GST_INFO_OBJECT (demux, "local tags: %" GST_PTR_FORMAT, demux->tags); + + upstream_tags = + gst_tag_list_merge (demux->upstream_stream_tags, + demux->upstream_global_tags, GST_TAG_MERGE_REPLACE); + + if (upstream_tags) { + tags = + gst_tag_list_merge (upstream_tags, demux->tags, + GST_TAG_MERGE_REPLACE); + if (gst_tag_list_get_scope (tags) != GST_TAG_SCOPE_GLOBAL) { + tags = gst_tag_list_make_writable (tags); + gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL); + } + gst_clear_tag_list (&upstream_tags); + } else { + tags = gst_tag_list_ref (demux->tags); + } + + GST_INFO_OBJECT (demux, "combined tags: %" GST_PTR_FORMAT, tags); } /* now handle the stream tags */ @@ -1726,6 +1750,34 @@ gst_ffmpegdemux_sink_event (GstPad * sinkpad, GstObject * parent, GST_LOG_OBJECT (demux, "dropping %s event", GST_EVENT_TYPE_NAME (event)); gst_event_unref (event); goto done; + case GST_EVENT_TAG:{ + GstTagList *tags, *upstream_tags; + guint32 seqnum; + + gst_event_parse_tag (event, &tags); + if (gst_tag_list_get_scope (tags) == GST_TAG_SCOPE_GLOBAL) + gst_tag_list_replace (&demux->upstream_global_tags, tags); + else + gst_tag_list_replace (&demux->upstream_stream_tags, tags); + + seqnum = gst_event_get_seqnum (event); + gst_event_unref (event); + upstream_tags = + gst_tag_list_merge (demux->upstream_stream_tags, + demux->upstream_global_tags, GST_TAG_MERGE_REPLACE); + tags = + gst_tag_list_merge (upstream_tags, demux->tags, + GST_TAG_MERGE_REPLACE); + if (gst_tag_list_get_scope (tags) != GST_TAG_SCOPE_GLOBAL) { + tags = gst_tag_list_make_writable (tags); + gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL); + } + gst_clear_tag_list (&upstream_tags); + event = gst_event_new_tag (tags); + gst_event_set_seqnum (event, seqnum); + + /* fall through */ + } default: /* for a serialized event, wait until an earlier data is gone, * though this is no guarantee as to when task is done with it. @@ -1975,6 +2027,8 @@ gst_ffmpegdemux_change_state (GstElement * element, GstStateChange transition) demux->cached_events = NULL; demux->have_group_id = FALSE; demux->group_id = G_MAXUINT; + gst_clear_tag_list (&demux->upstream_global_tags); + gst_clear_tag_list (&demux->upstream_stream_tags); break; default: break;