diff options
author | Thiago Santos <thiago.sousa.santos@collabora.co.uk> | 2009-10-27 17:48:03 -0300 |
---|---|---|
committer | Thiago Santos <thiago.sousa.santos@collabora.co.uk> | 2009-11-06 18:59:30 -0300 |
commit | 37e805ef24a9300ed949dd0389f7089ac0aa9b26 (patch) | |
tree | 77c66a2e45f857116b07d7a55b5e9d03f1e7d4df | |
parent | 9e3e475f3692791fb5b2252d3ea7d6d63a2760ff (diff) |
asfdemux: add support for chained asfs (push mode)
Adds support for detecting and playing chained asfs
in push mode. asfdemux tries to detect a new asf start
by identifying the header object guid in a input buffer.
When it finds it, it resets its state, removing its pads
and creates new ones for the new file.
-rw-r--r-- | gst/asfdemux/gstasfdemux.c | 108 | ||||
-rw-r--r-- | gst/asfdemux/gstasfdemux.h | 3 |
2 files changed, 93 insertions, 18 deletions
diff --git a/gst/asfdemux/gstasfdemux.c b/gst/asfdemux/gstasfdemux.c index 8e58a8fe..29d4884a 100644 --- a/gst/asfdemux/gstasfdemux.c +++ b/gst/asfdemux/gstasfdemux.c @@ -169,13 +169,13 @@ gst_asf_demux_free_stream (GstASFDemux * demux, AsfStream * stream) } static void -gst_asf_demux_reset (GstASFDemux * demux) +gst_asf_demux_reset (GstASFDemux * demux, gboolean chain_reset) { GST_LOG_OBJECT (demux, "resetting"); gst_segment_init (&demux->segment, GST_FORMAT_UNDEFINED); demux->segment_running = FALSE; - if (demux->adapter) { + if (demux->adapter && !chain_reset) { gst_adapter_clear (demux->adapter); g_object_unref (demux->adapter); demux->adapter = NULL; @@ -215,7 +215,8 @@ gst_asf_demux_reset (GstASFDemux * demux) demux->first_ts = GST_CLOCK_TIME_NONE; demux->segment_ts = GST_CLOCK_TIME_NONE; demux->in_gap = 0; - gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED); + if (!chain_reset) + gst_segment_init (&demux->in_segment, GST_FORMAT_UNDEFINED); demux->state = GST_ASF_DEMUX_STATE_HEADER; demux->seekable = FALSE; demux->broadcast = FALSE; @@ -225,6 +226,19 @@ gst_asf_demux_reset (GstASFDemux * demux) demux->sidx_entries = NULL; demux->speed_packets = 1; + + if (chain_reset) { + GST_LOG_OBJECT (demux, "Restarting"); + gst_segment_init (&demux->segment, GST_FORMAT_TIME); + demux->need_newsegment = TRUE; + demux->segment_running = FALSE; + demux->accurate = FALSE; + demux->metadata = gst_caps_new_empty (); + demux->global_metadata = gst_structure_empty_new ("metadata"); + demux->data_size = 0; + demux->data_offset = 0; + demux->index_offset = 0; + } } static void @@ -245,7 +259,7 @@ gst_asf_demux_init (GstASFDemux * demux, GstASFDemuxClass * klass) gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad); /* set initial state */ - gst_asf_demux_reset (demux); + gst_asf_demux_reset (demux, FALSE); } static gboolean @@ -720,9 +734,14 @@ typedef struct guint64 size; } AsfObject; + +/* expect is true when the user is expeting an object, + * when false, it will give no warnings if the object + * is not identified + */ static gboolean asf_demux_peek_object (GstASFDemux * demux, const guint8 * data, - guint data_len, AsfObject * object) + guint data_len, AsfObject * object, gboolean expect) { ASFGuid guid; @@ -738,7 +757,7 @@ asf_demux_peek_object (GstASFDemux * demux, const guint8 * data, /* FIXME: make asf_demux_identify_object_guid() */ object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid); - if (object->id == ASF_OBJ_UNDEFINED) { + if (object->id == ASF_OBJ_UNDEFINED && expect) { GST_WARNING_OBJECT (demux, "Unknown object %08x-%08x-%08x-%08x", guid.v1, guid.v2, guid.v3, guid.v4); } @@ -759,7 +778,7 @@ gst_asf_demux_chain_headers (GstASFDemux * demux) if (cdata == NULL) goto need_more_data; - asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj); + asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE); if (obj.id != ASF_OBJ_HEADER) goto wrong_type; @@ -890,7 +909,7 @@ gst_asf_demux_pull_indices (GstASFDemux * demux) GstFlowReturn flow; AsfObject obj; - asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj); + asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE); gst_buffer_replace (&buf, NULL); /* check for sanity */ @@ -924,7 +943,7 @@ gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data) { AsfObject obj; - asf_demux_peek_object (demux, data, 50, &obj); + asf_demux_peek_object (demux, data, 50, &obj, TRUE); if (obj.id != ASF_OBJ_DATA) { GST_WARNING_OBJECT (demux, "headers not followed by a DATA object"); return FALSE; @@ -984,7 +1003,7 @@ gst_asf_demux_pull_headers (GstASFDemux * demux) if (!gst_asf_demux_pull_data (demux, 0, 16 + 8, &buf, NULL)) goto read_failed; - asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj); + asf_demux_peek_object (demux, GST_BUFFER_DATA (buf), 16 + 8, &obj, TRUE); gst_buffer_replace (&buf, NULL); if (obj.id != ASF_OBJ_HEADER) @@ -1509,6 +1528,27 @@ parse_error: } } +#define GST_ASF_DEMUX_CHECK_HEADER_YES 0 +#define GST_ASF_DEMUX_CHECK_HEADER_NO 1 +#define GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA 2 + +static gint +gst_asf_demux_check_header (GstASFDemux * demux) +{ + AsfObject obj; + guint8 *cdata = (guint8 *) gst_adapter_peek (demux->adapter, + ASF_OBJECT_HEADER_SIZE); + if (cdata == NULL) /* need more data */ + return GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA; + + asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE); + if (obj.id != ASF_OBJ_HEADER) { + return GST_ASF_DEMUX_CHECK_HEADER_NO; + } else { + return GST_ASF_DEMUX_CHECK_HEADER_YES; + } +} + static GstFlowReturn gst_asf_demux_chain (GstPad * pad, GstBuffer * buf) { @@ -1537,6 +1577,24 @@ gst_asf_demux_chain (GstPad * pad, GstBuffer * buf) gst_adapter_push (demux->adapter, buf); switch (demux->state) { + case GST_ASF_DEMUX_STATE_INDEX:{ + gint result = gst_asf_demux_check_header (demux); + if (result == GST_ASF_DEMUX_CHECK_HEADER_NEED_DATA) /* need more data */ + break; + + if (result == GST_ASF_DEMUX_CHECK_HEADER_NO) { + /* we don't care about this, probably an index */ + /* TODO maybe would be smarter to skip all the indices + * until we got a new header or EOS to decide */ + GST_LOG_OBJECT (demux, "Received index object, its EOS"); + goto eos; + } else { + GST_INFO_OBJECT (demux, "Chained asf starting"); + /* cleanup and get ready for a chained asf */ + gst_asf_demux_reset (demux, TRUE); + /* fall through */ + } + } case GST_ASF_DEMUX_STATE_HEADER:{ ret = gst_asf_demux_chain_headers (demux); if (demux->state != GST_ASF_DEMUX_STATE_DATA) @@ -1552,10 +1610,22 @@ gst_asf_demux_chain (GstPad * pad, GstBuffer * buf) while (gst_adapter_available (demux->adapter) >= data_size) { GstBuffer *buf; - /* do not overshoot data section when streaming */ - if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0 - && demux->packet >= demux->num_packets)) - goto eos; + /* we don't know the length of the stream + * check for a chained asf everytime */ + if (demux->num_packets == 0) { + gint result = gst_asf_demux_check_header (demux); + + if (result == GST_ASF_DEMUX_CHECK_HEADER_YES) { + GST_INFO_OBJECT (demux, "Chained asf starting"); + /* cleanup and get ready for a chained asf */ + gst_asf_demux_reset (demux, TRUE); + break; + } + } else if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0 + && demux->packet >= demux->num_packets)) { + /* do not overshoot data section when streaming */ + break; + } buf = gst_adapter_take_buffer (demux->adapter, data_size); @@ -1572,6 +1642,10 @@ gst_asf_demux_chain (GstPad * pad, GstBuffer * buf) if (demux->packet >= 0) ++demux->packet; } + if (G_UNLIKELY (demux->num_packets != 0 && demux->packet >= 0 + && demux->packet >= demux->num_packets)) { + demux->state = GST_ASF_DEMUX_STATE_INDEX; + } break; } default: @@ -3130,7 +3204,7 @@ gst_asf_demux_process_ext_stream_props (GstASFDemux * demux, guint8 * data, } /* get size of the stream object */ - if (!asf_demux_peek_object (demux, data, size, &stream_obj)) + if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE)) goto not_enough_data; if (stream_obj.id != ASF_OBJ_STREAM) @@ -3341,7 +3415,7 @@ gst_asf_demux_process_object (GstASFDemux * demux, guint8 ** p_data, if (*p_size < ASF_OBJECT_HEADER_SIZE) return ASF_FLOW_NEED_MORE_DATA; - asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj); + asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE); gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size); obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE; @@ -3738,7 +3812,7 @@ gst_asf_demux_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_READY_TO_NULL: - gst_asf_demux_reset (demux); + gst_asf_demux_reset (demux, FALSE); break; default: break; diff --git a/gst/asfdemux/gstasfdemux.h b/gst/asfdemux/gstasfdemux.h index c2b35ce6..344314b2 100644 --- a/gst/asfdemux/gstasfdemux.h +++ b/gst/asfdemux/gstasfdemux.h @@ -115,7 +115,8 @@ typedef struct typedef enum { GST_ASF_DEMUX_STATE_HEADER, - GST_ASF_DEMUX_STATE_DATA + GST_ASF_DEMUX_STATE_DATA, + GST_ASF_DEMUX_STATE_INDEX } GstAsfDemuxState; #define GST_ASF_DEMUX_NUM_VIDEO_PADS 16 |