flvdemux: Refactor metadata tag handling

The FLV header cannot be trusted to indicate video or
audio presence, as the comments already mention. Don't
delay pushing tags waiting for streams that might never
appear.

Tags are now pushed immediately after they change:
  - After parsing an onMetaData script object
  - After negotiating caps on a pad

https://bugzilla.gnome.org/show_bug.cgi?id=768440
This commit is contained in:
Jan Alexander Steffens (heftig) 2016-07-06 09:24:49 +02:00 committed by Sebastian Dröge
parent a85dbfc246
commit ee44e60f7b
2 changed files with 51 additions and 56 deletions

View File

@ -114,6 +114,8 @@ static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent,
static GstIndex *gst_flv_demux_get_index (GstElement * element); static GstIndex *gst_flv_demux_get_index (GstElement * element);
static void gst_flv_demux_push_tags (GstFlvDemux * demux);
static void static void
gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts, gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
guint64 pos, gboolean keyframe) guint64 pos, gboolean keyframe)
@ -561,6 +563,18 @@ error:
return FALSE; return FALSE;
} }
static void
gst_flv_demux_clear_tags (GstFlvDemux * demux)
{
GST_DEBUG_OBJECT (demux, "clearing taglist");
if (demux->taglist) {
gst_tag_list_unref (demux->taglist);
}
demux->taglist = gst_tag_list_new_empty ();
gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
}
static GstFlowReturn static GstFlowReturn
gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer) gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
{ {
@ -594,6 +608,8 @@ gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
gboolean end_marker = FALSE; gboolean end_marker = FALSE;
GST_DEBUG_OBJECT (demux, "we have a metadata script object"); GST_DEBUG_OBJECT (demux, "we have a metadata script object");
gst_flv_demux_clear_tags (demux);
if (!gst_byte_reader_get_uint8 (&reader, &type)) { if (!gst_byte_reader_get_uint8 (&reader, &type)) {
g_free (function_name); g_free (function_name);
goto cleanup; goto cleanup;
@ -636,7 +652,7 @@ gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
goto cleanup; goto cleanup;
} }
demux->push_tags = TRUE; gst_flv_demux_push_tags (demux);
} }
g_free (function_name); g_free (function_name);
@ -689,7 +705,6 @@ gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
guint32 rate, guint32 channels, guint32 width) guint32 rate, guint32 channels, guint32 width)
{ {
GstCaps *caps = NULL, *old_caps; GstCaps *caps = NULL, *old_caps;
gchar *codec_name = NULL;
gboolean ret = FALSE; gboolean ret = FALSE;
guint adjusted_rate = rate; guint adjusted_rate = rate;
GstEvent *event; GstEvent *event;
@ -871,18 +886,10 @@ done:
demux->width = width; demux->width = width;
if (caps) { if (caps) {
codec_name = gst_pb_utils_get_codec_description (caps);
if (codec_name) {
if (demux->taglist == NULL)
demux->taglist = gst_tag_list_new_empty ();
gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
GST_TAG_AUDIO_CODEC, codec_name, NULL);
g_free (codec_name);
}
GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %" GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
GST_PTR_FORMAT, caps); GST_PTR_FORMAT, caps);
gst_flv_demux_push_tags (demux);
} else { } else {
GST_DEBUG_OBJECT (demux->audio_pad, "delayed setting caps"); GST_DEBUG_OBJECT (demux->audio_pad, "delayed setting caps");
} }
@ -914,27 +921,37 @@ gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
return ret; return ret;
} }
static void
gst_flv_demux_add_codec_tag (GstFlvDemux * demux, const gchar * tag,
GstPad * pad)
{
if (pad) {
GstCaps *caps = gst_pad_get_current_caps (pad);
if (caps) {
gchar *codec_name = gst_pb_utils_get_codec_description (caps);
if (codec_name) {
gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
tag, codec_name, NULL);
g_free (codec_name);
}
gst_caps_unref (caps);
}
}
}
static void static void
gst_flv_demux_push_tags (GstFlvDemux * demux) gst_flv_demux_push_tags (GstFlvDemux * demux)
{ {
if (demux->has_audio && !demux->audio_pad) { gst_flv_demux_add_codec_tag (demux, GST_TAG_AUDIO_CODEC, demux->audio_pad);
GST_DEBUG_OBJECT (demux, gst_flv_demux_add_codec_tag (demux, GST_TAG_VIDEO_CODEC, demux->video_pad);
"Waiting for audio stream pad to come up before we can push tags");
return; GST_DEBUG_OBJECT (demux, "pushing %" GST_PTR_FORMAT, demux->taglist);
}
if (demux->has_video && !demux->video_pad) { gst_flv_demux_push_src_event (demux,
GST_DEBUG_OBJECT (demux, gst_event_new_tag (gst_tag_list_copy (demux->taglist)));
"Waiting for video stream pad to come up before we can push tags");
return;
}
if (demux->taglist) {
GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
demux->taglist);
gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
gst_flv_demux_push_src_event (demux, gst_event_new_tag (demux->taglist));
demux->taglist = gst_tag_list_new_empty ();
demux->push_tags = FALSE;
}
} }
static gboolean static gboolean
@ -1137,7 +1154,6 @@ gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
GST_DEBUG_OBJECT (demux, "emitting no more pads"); GST_DEBUG_OBJECT (demux, "emitting no more pads");
gst_element_no_more_pads (GST_ELEMENT (demux)); gst_element_no_more_pads (GST_ELEMENT (demux));
demux->no_more_pads = TRUE; demux->no_more_pads = TRUE;
demux->push_tags = TRUE;
} }
} }
@ -1156,10 +1172,6 @@ gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
} }
} }
/* Push taglist if present */
if (G_UNLIKELY (demux->push_tags))
gst_flv_demux_push_tags (demux);
/* Check if we have anything to push */ /* Check if we have anything to push */
if (demux->tag_data_size <= codec_data) { if (demux->tag_data_size <= codec_data) {
GST_LOG_OBJECT (demux, "Nothing left in this tag, returning"); GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
@ -1241,7 +1253,6 @@ gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
" after 6 seconds of audio"); " after 6 seconds of audio");
gst_element_no_more_pads (GST_ELEMENT_CAST (demux)); gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
demux->no_more_pads = TRUE; demux->no_more_pads = TRUE;
demux->push_tags = TRUE;
} }
/* Push downstream */ /* Push downstream */
@ -1273,7 +1284,6 @@ gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
GstCaps *caps = NULL, *old_caps; GstCaps *caps = NULL, *old_caps;
gchar *codec_name = NULL;
GstEvent *event; GstEvent *event;
gchar *stream_id; gchar *stream_id;
@ -1378,18 +1388,10 @@ done:
demux->video_codec_tag = codec_tag; demux->video_codec_tag = codec_tag;
if (caps) { if (caps) {
codec_name = gst_pb_utils_get_codec_description (caps);
if (codec_name) {
if (demux->taglist == NULL)
demux->taglist = gst_tag_list_new_empty ();
gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
GST_TAG_VIDEO_CODEC, codec_name, NULL);
g_free (codec_name);
}
GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %" GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
GST_PTR_FORMAT, caps); GST_PTR_FORMAT, caps);
gst_flv_demux_push_tags (demux);
} else { } else {
GST_DEBUG_OBJECT (demux->video_pad, "delayed setting caps"); GST_DEBUG_OBJECT (demux->video_pad, "delayed setting caps");
} }
@ -1568,7 +1570,6 @@ gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
GST_DEBUG_OBJECT (demux, "emitting no more pads"); GST_DEBUG_OBJECT (demux, "emitting no more pads");
gst_element_no_more_pads (GST_ELEMENT (demux)); gst_element_no_more_pads (GST_ELEMENT (demux));
demux->no_more_pads = TRUE; demux->no_more_pads = TRUE;
demux->push_tags = TRUE;
} }
} }
@ -1587,10 +1588,6 @@ gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
demux->got_par = FALSE; demux->got_par = FALSE;
} }
/* Push taglist if present */
if (G_UNLIKELY (demux->push_tags))
gst_flv_demux_push_tags (demux);
/* Check if we have anything to push */ /* Check if we have anything to push */
if (demux->tag_data_size <= codec_data) { if (demux->tag_data_size <= codec_data) {
GST_LOG_OBJECT (demux, "Nothing left in this tag, returning"); GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
@ -1677,7 +1674,6 @@ gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
" after 6 seconds of video"); " after 6 seconds of video");
gst_element_no_more_pads (GST_ELEMENT_CAST (demux)); gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
demux->no_more_pads = TRUE; demux->no_more_pads = TRUE;
demux->push_tags = TRUE;
} }
/* Push downstream */ /* Push downstream */
@ -1925,7 +1921,6 @@ gst_flv_demux_cleanup (GstFlvDemux * demux)
demux->has_audio = FALSE; demux->has_audio = FALSE;
demux->has_video = FALSE; demux->has_video = FALSE;
demux->push_tags = FALSE;
demux->got_par = FALSE; demux->got_par = FALSE;
demux->indexed = FALSE; demux->indexed = FALSE;
@ -1997,6 +1992,8 @@ gst_flv_demux_cleanup (GstFlvDemux * demux)
g_array_free (demux->filepositions, TRUE); g_array_free (demux->filepositions, TRUE);
demux->filepositions = NULL; demux->filepositions = NULL;
} }
gst_flv_demux_clear_tags (demux);
} }
/* /*
@ -3588,7 +3585,6 @@ gst_flv_demux_init (GstFlvDemux * demux)
gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad); gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
demux->adapter = gst_adapter_new (); demux->adapter = gst_adapter_new ();
demux->taglist = gst_tag_list_new_empty ();
demux->flowcombiner = gst_flow_combiner_new (); demux->flowcombiner = gst_flow_combiner_new ();
gst_segment_init (&demux->segment, GST_FORMAT_TIME); gst_segment_init (&demux->segment, GST_FORMAT_TIME);

View File

@ -126,7 +126,6 @@ struct _GstFlvDemux
gboolean need_header; gboolean need_header;
gboolean has_audio; gboolean has_audio;
gboolean has_video; gboolean has_video;
gboolean push_tags;
gboolean strict; gboolean strict;
gboolean flushing; gboolean flushing;