From 0a10191772eecb23d31c1ac7442a2efc22eff074 Mon Sep 17 00:00:00 2001 From: Julien Moutte Date: Wed, 25 Jul 2007 13:29:04 +0000 Subject: [PATCH] gst/flv/: Handle not linked pads, try to make it reusable, more safety checks. Original commit message from CVS: 2007-07-25 Julien MOUTTE (gst_flv_demux_chain), (gst_flv_demux_pull_tag), (gst_flv_demux_change_state), (gst_flv_demux_dispose), (gst_flv_demux_init): * gst/flv/gstflvdemux.h: * gst/flv/gstflvparse.c: (FLV_GET_STRING), (gst_flv_parse_metadata_item), (gst_flv_parse_tag_script), (gst_flv_parse_tag_audio), (gst_flv_parse_tag_video), (gst_flv_parse_header): * gst/flv/gstflvparse.h: Handle not linked pads, try to make it reusable, more safety checks. --- ChangeLog | 13 ++++++++ gst/flv/gstflvdemux.c | 74 ++++++++++++++++++++++++++++++++++++++----- gst/flv/gstflvdemux.h | 48 ++++++++++++++-------------- gst/flv/gstflvparse.c | 63 ++++++++++++++++++++++++++++++++---- gst/flv/gstflvparse.h | 8 ++--- 5 files changed, 164 insertions(+), 42 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7c518d5383..23bcc4fe87 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2007-07-25 Julien MOUTTE + + (gst_flv_demux_chain), (gst_flv_demux_pull_tag), + (gst_flv_demux_change_state), (gst_flv_demux_dispose), + (gst_flv_demux_init): + * gst/flv/gstflvdemux.h: + * gst/flv/gstflvparse.c: (FLV_GET_STRING), + (gst_flv_parse_metadata_item), (gst_flv_parse_tag_script), + (gst_flv_parse_tag_audio), (gst_flv_parse_tag_video), + (gst_flv_parse_header): + * gst/flv/gstflvparse.h: Handle not linked pads, try to make it + reusable, more safety checks. + 2007-07-25 Stefan Kost * ext/timidity/gsttimidity.c: (gst_timidity_init), diff --git a/gst/flv/gstflvdemux.c b/gst/flv/gstflvdemux.c index f91763dbaa..dac3ab0af0 100644 --- a/gst/flv/gstflvdemux.c +++ b/gst/flv/gstflvdemux.c @@ -74,6 +74,46 @@ static void gst_flv_demux_cleanup (GstFLVDemux * demux) { GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer"); + + demux->state = FLV_STATE_HEADER; + + demux->need_header = TRUE; + demux->audio_need_segment = TRUE; + demux->video_need_segment = TRUE; + demux->audio_need_discont = TRUE; + demux->video_need_discont = TRUE; + + /* By default we consider them as linked */ + demux->audio_linked = TRUE; + demux->video_linked = TRUE; + + demux->has_audio = FALSE; + demux->has_video = FALSE; + demux->push_tags = FALSE; + + demux->video_offset = 0; + demux->audio_offset = 0; + demux->offset = demux->tag_size = demux->tag_data_size = 0; + demux->duration = GST_CLOCK_TIME_NONE; + + if (demux->new_seg_event) { + gst_event_unref (demux->new_seg_event); + demux->new_seg_event = NULL; + } + + gst_adapter_clear (demux->adapter); + + if (demux->audio_pad) { + gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad); + gst_object_unref (demux->audio_pad); + demux->audio_pad = NULL; + } + + if (demux->video_pad) { + gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad); + gst_object_unref (demux->video_pad); + demux->video_pad = NULL; + } } static GstFlowReturn @@ -177,6 +217,13 @@ parse: } beach: + if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) { + /* If either audio or video is linked we return GST_FLOW_OK */ + if (demux->audio_linked || demux->video_linked) { + ret = GST_FLOW_OK; + } + } + gst_object_unref (demux); return ret; @@ -256,6 +303,13 @@ gst_flv_demux_pull_tag (GstPad * pad, GstFLVDemux * demux) /* Ready for the next tag */ demux->state = FLV_STATE_TAG_TYPE; + if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) { + /* If either audio or video is linked we return GST_FLOW_OK */ + if (demux->audio_linked || demux->video_linked) { + ret = GST_FLOW_OK; + } + } + beach: return ret; } @@ -547,10 +601,7 @@ gst_flv_demux_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: - demux->state = FLV_STATE_HEADER; - demux->need_header = TRUE; - demux->audio_need_discont = TRUE; - demux->video_need_discont = TRUE; + gst_flv_demux_cleanup (demux); break; default: break; @@ -599,6 +650,16 @@ gst_flv_demux_dispose (GObject * object) demux->new_seg_event = NULL; } + if (demux->audio_pad) { + gst_object_unref (demux->audio_pad); + demux->audio_pad = NULL; + } + + if (demux->video_pad) { + gst_object_unref (demux->video_pad); + demux->video_pad = NULL; + } + GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); } @@ -652,10 +713,7 @@ gst_flv_demux_init (GstFLVDemux * demux, GstFLVDemuxClass * g_class) demux->taglist = gst_tag_list_new (); gst_segment_init (demux->segment, GST_FORMAT_TIME); - demux->offset = 0; - - demux->strict = FALSE; - demux->push_tags = FALSE; + gst_flv_demux_cleanup (demux); } static gboolean diff --git a/gst/flv/gstflvdemux.h b/gst/flv/gstflvdemux.h index 09de14fd4c..63878f1dfc 100644 --- a/gst/flv/gstflvdemux.h +++ b/gst/flv/gstflvdemux.h @@ -24,7 +24,6 @@ #include G_BEGIN_DECLS - #define GST_TYPE_FLV_DEMUX \ (gst_flv_demux_get_type()) #define GST_FLV_DEMUX(obj) \ @@ -35,11 +34,11 @@ G_BEGIN_DECLS (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FLV_DEMUX)) #define GST_IS_FLV_DEMUX_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FLV_DEMUX)) - typedef struct _GstFLVDemux GstFLVDemux; typedef struct _GstFLVDemuxClass GstFLVDemuxClass; -typedef enum { +typedef enum +{ FLV_STATE_HEADER, FLV_STATE_TAG_TYPE, FLV_STATE_TAG_VIDEO, @@ -49,29 +48,30 @@ typedef enum { FLV_STATE_NONE } GstFLVDemuxState; -struct _GstFLVDemux { +struct _GstFLVDemux +{ GstElement element; - GstPad * sinkpad; - - GstPad * audio_pad; - GstPad * video_pad; - - GstAdapter * adapter; - - GstSegment * segment; - - GstEvent * new_seg_event; - - GstTagList * taglist; - + GstPad *sinkpad; + + GstPad *audio_pad; + GstPad *video_pad; + + GstAdapter *adapter; + + GstSegment *segment; + + GstEvent *new_seg_event; + + GstTagList *taglist; + GstFLVDemuxState state; - + guint64 offset; GstClockTime duration; guint64 tag_size; guint64 tag_data_size; - + /* Audio infos */ guint16 rate; guint16 channels; @@ -80,7 +80,8 @@ struct _GstFLVDemux { guint64 audio_offset; gboolean audio_need_discont; gboolean audio_need_segment; - + gboolean audio_linked; + /* Video infos */ guint32 w; guint32 h; @@ -88,7 +89,8 @@ struct _GstFLVDemux { guint64 video_offset; gboolean video_need_discont; gboolean video_need_segment; - + gboolean video_linked; + gboolean random_access; gboolean need_header; gboolean has_audio; @@ -97,12 +99,12 @@ struct _GstFLVDemux { gboolean strict; }; -struct _GstFLVDemuxClass { +struct _GstFLVDemuxClass +{ GstElementClass parent_class; }; GType gst_flv_demux_get_type (void); G_END_DECLS - #endif /* __FLV_DEMUX_H__ */ diff --git a/gst/flv/gstflvparse.c b/gst/flv/gstflvparse.c index 023df66c62..ef0f1f34ca 100644 --- a/gst/flv/gstflvparse.c +++ b/gst/flv/gstflvparse.c @@ -48,6 +48,9 @@ FLV_GET_STRING (const guint8 * data, size_t data_size) g_return_val_if_fail (data_size >= 3, 0); string_size = GST_READ_UINT16_BE (data); + if (G_UNLIKELY (string_size > data_size)) { + return NULL; + } string = g_try_malloc0 (string_size + 1); if (G_UNLIKELY (!string)) { @@ -135,6 +138,10 @@ gst_flv_parse_metadata_item (GstFLVDemux * demux, const guint8 * data, /* Name of the tag */ tag_name = FLV_GET_STRING (data, data_size); + if (G_UNLIKELY (!tag_name)) { + GST_WARNING_OBJECT (demux, "failed reading tag name"); + goto beach; + } offset += strlen (tag_name) + 2; @@ -245,6 +252,7 @@ gst_flv_parse_metadata_item (GstFLVDemux * demux, const guint8 * data, g_free (tag_name); +beach: return offset; } @@ -278,8 +286,14 @@ gst_flv_parse_tag_script (GstFLVDemux * demux, const guint8 * data, GST_DEBUG_OBJECT (demux, "there are %d elements in the array", nb_elems); while (nb_elems--) { - offset += gst_flv_parse_metadata_item (demux, data + offset, + size_t read = gst_flv_parse_metadata_item (demux, data + offset, data_size - offset); + + if (G_UNLIKELY (!read)) { + GST_WARNING_OBJECT (demux, "failed reading a tag, skipping"); + break; + } + offset += read; } demux->push_tags = TRUE; @@ -299,13 +313,18 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, GstFlowReturn ret = GST_FLOW_OK; GstBuffer *buffer = NULL; guint32 pts = 0, codec_tag = 0, rate = 0, width = 0, channels = 0; - guint32 codec_data = 0; + guint32 codec_data = 0, pts_ext = 0; guint8 flags = 0; GST_LOG_OBJECT (demux, "parsing an audio tag"); /* Grab information about audio tag */ pts = FLV_GET_BEUI24 (data, data_size); + /* read the pts extension to 32 bits integer */ + pts_ext = GST_READ_UINT8 (data + 3); + /* Combine them */ + pts |= pts_ext << 24; + /* Skip the stream id and go directly to the flags */ flags = GST_READ_UINT8 (data + 7); /* Channels */ @@ -392,6 +411,9 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, gst_pad_set_caps (demux->audio_pad, caps); + GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT, + caps); + gst_caps_unref (caps); /* Store the caps we have set */ @@ -407,7 +429,14 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, GST_DEBUG_FUNCPTR (gst_flv_demux_query)); /* We need to set caps before adding */ - gst_element_add_pad (GST_ELEMENT (demux), demux->audio_pad); + gst_element_add_pad (GST_ELEMENT (demux), + gst_object_ref (demux->audio_pad)); + + if ((demux->has_audio & (demux->audio_pad != NULL)) && + (demux->has_video & (demux->video_pad != NULL))) { + GST_DEBUG_OBJECT (demux, "emitting no more pads"); + gst_element_no_more_pads (GST_ELEMENT (demux)); + } } /* Check if caps have changed */ @@ -468,9 +497,14 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, if (G_UNLIKELY (ret != GST_FLOW_OK)) { GST_WARNING_OBJECT (demux, "failed allocating a %d bytes buffer", demux->tag_data_size); + if (ret == GST_FLOW_NOT_LINKED) { + demux->audio_linked = FALSE; + } goto beach; } + demux->audio_linked = TRUE; + /* Fill buffer with data */ GST_BUFFER_TIMESTAMP (buffer) = pts * GST_MSECOND; GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; @@ -578,10 +612,10 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, caps = gst_caps_new_simple ("video/x-flash-video", NULL); break; case 4: - caps = gst_caps_new_simple ("video/x-vp6", NULL); + caps = gst_caps_new_simple ("video/x-vp6-flash", NULL); break; case 5: - caps = gst_caps_new_simple ("video/x-vp6", NULL); + caps = gst_caps_new_simple ("video/x-vp6-flash", NULL); break; default: GST_WARNING_OBJECT (demux, "unsupported video codec tag %d", codec_tag); @@ -597,6 +631,9 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, gst_pad_set_caps (demux->video_pad, caps); + GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT, + caps); + gst_caps_unref (caps); /* Store the caps we have set */ @@ -609,7 +646,14 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, GST_DEBUG_FUNCPTR (gst_flv_demux_query)); /* We need to set caps before adding */ - gst_element_add_pad (GST_ELEMENT (demux), demux->video_pad); + gst_element_add_pad (GST_ELEMENT (demux), + gst_object_ref (demux->video_pad)); + + if ((demux->has_audio & (demux->audio_pad != NULL)) && + (demux->has_video & (demux->video_pad != NULL))) { + GST_DEBUG_OBJECT (demux, "emitting no more pads"); + gst_element_no_more_pads (GST_ELEMENT (demux)); + } } /* Check if caps have changed */ @@ -667,9 +711,14 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, if (G_UNLIKELY (ret != GST_FLOW_OK)) { GST_WARNING_OBJECT (demux, "failed allocating a %d bytes buffer", demux->tag_data_size); + if (ret == GST_FLOW_NOT_LINKED) { + demux->video_linked = FALSE; + } goto beach; } + demux->video_linked = TRUE; + /* Fill buffer with data */ GST_BUFFER_TIMESTAMP (buffer) = pts * GST_MSECOND; GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; @@ -779,6 +828,8 @@ gst_flv_parse_header (GstFLVDemux * demux, const guint8 * data, { guint8 flags = data[0]; + demux->has_video = demux->has_audio = FALSE; + if (flags & 1) { GST_DEBUG_OBJECT (demux, "there is a video stream"); demux->has_video = TRUE; diff --git a/gst/flv/gstflvparse.h b/gst/flv/gstflvparse.h index 027aaeda77..7b9d498efc 100644 --- a/gst/flv/gstflvparse.h +++ b/gst/flv/gstflvparse.h @@ -16,15 +16,14 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ - + #ifndef __FLV_PARSE_H__ #define __FLV_PARSE_H__ #include "gstflvdemux.h" G_BEGIN_DECLS - -GstFlowReturn gst_flv_parse_tag_script (GstFLVDemux * demux, + GstFlowReturn gst_flv_parse_tag_script (GstFLVDemux * demux, const guint8 * data, size_t data_size); GstFlowReturn gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, @@ -32,7 +31,7 @@ GstFlowReturn gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, GstFlowReturn gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, size_t data_size); - + GstFlowReturn gst_flv_parse_tag_type (GstFLVDemux * demux, const guint8 * data, size_t data_size); @@ -40,5 +39,4 @@ GstFlowReturn gst_flv_parse_header (GstFLVDemux * demux, const guint8 * data, size_t data_size); G_END_DECLS - #endif /* __FLV_PARSE_H__ */