gst_asf_demux_process_queued_extended_stream_objects (GstASFDemux * demux);
static gboolean gst_asf_demux_pull_headers (GstASFDemux * demux,
GstFlowReturn * pflow);
-static void gst_asf_demux_pull_indices (GstASFDemux * demux);
+static GstFlowReturn gst_asf_demux_pull_indices (GstASFDemux * demux);
static void gst_asf_demux_reset_stream_state_after_discont (GstASFDemux * asf);
static gboolean
gst_asf_demux_parse_data_object_start (GstASFDemux * demux, guint8 * data);
"Codec/Demuxer",
"Demultiplexes ASF Streams", "Owen Fraser-Green <owen@discobabe.net>");
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&audio_src_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&video_src_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_asf_demux_sink_template));
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &audio_src_template);
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &video_src_template);
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &gst_asf_demux_sink_template);
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_asf_demux_change_state);
g_array_free (stream->payloads, TRUE);
stream->payloads = NULL;
}
+
+ if (stream->payloads_rev) {
+ while (stream->payloads_rev->len > 0) {
+ AsfPayload *payload;
+ guint last;
+
+ last = stream->payloads_rev->len - 1;
+ payload = &g_array_index (stream->payloads_rev, AsfPayload, last);
+ gst_buffer_replace (&payload->buf, NULL);
+ g_array_remove_index (stream->payloads_rev, last);
+ }
+ g_array_free (stream->payloads_rev, TRUE);
+ stream->payloads_rev = NULL;
+ }
+
if (stream->ext_props.valid) {
g_free (stream->ext_props.payload_extensions);
stream->ext_props.payload_extensions = NULL;
demux->need_newsegment = TRUE;
demux->segment_seqnum = 0;
demux->segment_running = FALSE;
+ demux->keyunit_sync = FALSE;
demux->accurate = FALSE;
demux->metadata = gst_caps_new_empty ();
demux->global_metadata = gst_structure_new_empty ("metadata");
GST_DEBUG_FUNCPTR (gst_asf_demux_activate_mode));
gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
+#ifdef TIZEN_FEATURE_ASFDEMUX_DISABLE_UNSUPPORTED_FORMAT
+ demux->is_supported_format = TRUE;
+#endif
+
/* set initial state */
gst_asf_demux_reset (demux, FALSE);
}
demux->need_newsegment = TRUE;
demux->segment_seqnum = gst_event_get_seqnum (event);
gst_asf_demux_reset_stream_state_after_discont (demux);
+ /* if we seek back after reaching EOS, go back to packet reading state */
+ if (demux->data_offset > 0 && segment->start >= demux->data_offset
+ && demux->state == GST_ASF_DEMUX_STATE_INDEX) {
+ demux->state = GST_ASF_DEMUX_STATE_DATA;
+ }
GST_OBJECT_UNLOCK (demux);
gst_event_unref (event);
break;
}
flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
+ if (!demux->activated_streams) {
+ /* If we still haven't got activated streams, the file is most likely corrupt */
+ GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE,
+ (_("This stream contains no data.")),
+ ("got eos and didn't receive a complete header object"));
+ break;
+ }
if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
- GST_ELEMENT_ERROR (demux, STREAM, FAILED,
- (_("Internal data stream error.")),
- ("streaming stopped, reason %s", gst_flow_get_name (flow)));
+ GST_ELEMENT_FLOW_ERROR (demux, flow);
break;
}
GstSeekType cur_type, stop_type;
GstFormat format;
gboolean only_need_update;
- gboolean keyunit_sync, after, before, next;
+ gboolean after, before, next;
gboolean flush;
gdouble rate;
gint64 cur, stop;
gboolean eos;
guint32 seqnum;
GstEvent *fevent;
+ gint i;
gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
&stop_type, &stop);
}
if (G_UNLIKELY (rate <= 0.0)) {
- GST_LOG_OBJECT (demux, "backward playback is not supported yet");
- return FALSE;
+ GST_LOG_OBJECT (demux, "backward playback");
+ demux->seek_to_cur_pos = TRUE;
+ for (i = 0; i < demux->num_streams; i++) {
+ demux->stream[i].reverse_kf_ready = FALSE;
+ }
}
seqnum = gst_event_get_seqnum (event);
flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
demux->accurate =
((flags & GST_SEEK_FLAG_ACCURATE) == GST_SEEK_FLAG_ACCURATE);
- keyunit_sync = ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
+ demux->keyunit_sync =
+ ((flags & GST_SEEK_FLAG_KEY_UNIT) == GST_SEEK_FLAG_KEY_UNIT);
after = ((flags & GST_SEEK_FLAG_SNAP_AFTER) == GST_SEEK_FLAG_SNAP_AFTER);
before = ((flags & GST_SEEK_FLAG_SNAP_BEFORE) == GST_SEEK_FLAG_SNAP_BEFORE);
next = after && !before;
* forever */
GST_PAD_STREAM_LOCK (demux->sinkpad);
- /* we now can stop flushing, since we have the stream lock now */
- fevent = gst_event_new_flush_stop (TRUE);
- gst_event_set_seqnum (fevent, seqnum);
- gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
-
- if (G_LIKELY (flush))
+ if (G_LIKELY (flush)) {
+ /* we now can stop flushing, since we have the stream lock now */
+ fevent = gst_event_new_flush_stop (TRUE);
+ gst_event_set_seqnum (fevent, seqnum);
+ gst_pad_push_event (demux->sinkpad, gst_event_ref (fevent));
gst_asf_demux_send_event_unlocked (demux, fevent);
- else
- gst_event_unref (fevent);
+ }
/* operating on copy of segment until we know the seek worked */
segment = demux->segment;
- if (G_UNLIKELY (demux->segment_running && !flush)) {
- GstSegment newsegment;
- GstEvent *newseg;
-
- /* create the segment event to close the current segment */
- gst_segment_copy_into (&segment, &newsegment);
- newseg = gst_event_new_segment (&newsegment);
- gst_event_set_seqnum (newseg, seqnum);
-
- gst_asf_demux_send_event_unlocked (demux, newseg);
- }
-
gst_segment_do_seek (&segment, rate, format, flags, cur_type,
cur, stop_type, stop, &only_need_update);
* the hope of hitting a keyframe and let the sinks throw away the stuff
* before the segment start. For audio-only this is unnecessary as every
* frame is 'key'. */
- if (flush && (demux->accurate || (keyunit_sync && !next))
+ if (flush && (demux->accurate || (demux->keyunit_sync && !next))
&& demux->num_video_streams > 0) {
seek_time -= 5 * GST_SECOND;
if (seek_time < 0)
packet = demux->num_packets;
}
} else {
- if (G_LIKELY (keyunit_sync)) {
+ if (G_LIKELY (demux->keyunit_sync && !demux->accurate)) {
GST_DEBUG_OBJECT (demux, "key unit seek, adjust seek_time = %"
GST_TIME_FORMAT " to index_time = %" GST_TIME_FORMAT,
GST_TIME_ARGS (seek_time), GST_TIME_ARGS (idx_time));
GST_OBJECT_LOCK (demux);
demux->segment = segment;
- demux->packet = packet;
+ if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
+ demux->packet = (gint64) gst_util_uint64_scale (demux->num_packets,
+ stop, demux->play_time);
+ } else {
+ demux->packet = packet;
+ }
+
demux->need_newsegment = TRUE;
demux->segment_seqnum = seqnum;
- demux->speed_packets = speed_count;
+ demux->speed_packets =
+ GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) ? 1 : speed_count;
gst_asf_demux_reset_stream_state_after_discont (demux);
GST_OBJECT_UNLOCK (demux);
} AsfObject;
-/* expect is true when the user is expeting an object,
- * when false, it will give no warnings if the object
- * is not identified
+/* Peek for an object.
+ *
+ * Returns FALSE is the object is corrupted (such as the reported
+ * object size being greater than 2**32bits.
*/
static gboolean
asf_demux_peek_object (GstASFDemux * demux, const guint8 * data,
{
ASFGuid guid;
+ /* Callers should have made sure that data_len is big enough */
+ g_assert (data_len >= ASF_OBJECT_HEADER_SIZE);
+
if (data_len < ASF_OBJECT_HEADER_SIZE)
return FALSE;
guid.v3 = GST_READ_UINT32_LE (data + 8);
guid.v4 = GST_READ_UINT32_LE (data + 12);
- object->size = GST_READ_UINT64_LE (data + 16);
-
/* FIXME: make asf_demux_identify_object_guid() */
object->id = gst_asf_demux_identify_guid (asf_object_guids, &guid);
if (object->id == ASF_OBJ_UNDEFINED && expect) {
guid.v1, guid.v2, guid.v3, guid.v4);
}
+ object->size = GST_READ_UINT64_LE (data + 16);
+ if (object->id != ASF_OBJ_DATA && object->size >= G_MAXUINT) {
+ GST_WARNING_OBJECT (demux,
+ "ASF Object size corrupted (greater than 32bit)");
+ return FALSE;
+ }
+
+
return TRUE;
}
static GstFlowReturn
gst_asf_demux_chain_headers (GstASFDemux * demux)
{
- GstFlowReturn flow;
AsfObject obj;
guint8 *header_data, *data = NULL;
const guint8 *cdata = NULL;
guint64 header_size;
+ GstFlowReturn flow = GST_FLOW_OK;
cdata = (guint8 *) gst_adapter_map (demux->adapter, ASF_OBJECT_HEADER_SIZE);
if (cdata == NULL)
goto need_more_data;
- asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
+ if (!asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, TRUE))
+ goto parse_failed;
if (obj.id != ASF_OBJ_HEADER)
goto wrong_type;
return TRUE;
}
-static void
+static GstFlowReturn
gst_asf_demux_pull_indices (GstASFDemux * demux)
{
GstBuffer *buf = NULL;
guint64 offset;
guint num_read = 0;
+ GstFlowReturn ret = GST_FLOW_OK;
offset = demux->index_offset;
if (G_UNLIKELY (offset == 0)) {
GST_DEBUG_OBJECT (demux, "can't read indices, don't know index offset");
- return;
+ /* non-fatal */
+ return GST_FLOW_OK;
}
while (gst_asf_demux_pull_data (demux, offset, 16 + 8, &buf, NULL)) {
- GstFlowReturn flow;
AsfObject obj;
GstMapInfo map;
guint8 *bufdata;
+ guint64 obj_size;
gst_buffer_map (buf, &map, GST_MAP_READ);
g_assert (map.size >= 16 + 8);
- asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
+ if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
+ GST_DEBUG_OBJECT (demux, "No valid object, corrupted index, ignoring");
+ GST_MEMDUMP_OBJECT (demux, "Corrupted index ?", map.data, MIN (map.size,
+ 64));
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_replace (&buf, NULL);
+ /* Non-fatal, return */
+ break;
+ }
gst_buffer_unmap (buf, &map);
gst_buffer_replace (&buf, NULL);
gst_buffer_map (buf, &map, GST_MAP_READ);
g_assert (map.size >= obj.size);
bufdata = (guint8 *) map.data;
- flow = gst_asf_demux_process_object (demux, &bufdata, &obj.size);
+ obj_size = obj.size;
+ ret = gst_asf_demux_process_object (demux, &bufdata, &obj_size);
gst_buffer_unmap (buf, &map);
gst_buffer_replace (&buf, NULL);
- if (G_UNLIKELY (flow != GST_FLOW_OK))
+ if (ret == ASF_FLOW_NEED_MORE_DATA) {
+ /* Since indices are at the end of the file, if we need more data,
+ * we consider it as a non-fatal corrupted index */
+ ret = GST_FLOW_OK;
+ break;
+ }
+
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
break;
++num_read;
}
- GST_DEBUG_OBJECT (demux, "read %u index objects", num_read);
+
+ GST_DEBUG_OBJECT (demux, "read %u index objects , returning %s", num_read,
+ gst_flow_get_name (ret));
+ return ret;
}
static gboolean
{
AsfObject obj;
- asf_demux_peek_object (demux, data, 50, &obj, TRUE);
+ if (!asf_demux_peek_object (demux, data, 50, &obj, TRUE)) {
+ GST_WARNING_OBJECT (demux, "Corrupted data");
+ return FALSE;
+ }
if (obj.id != ASF_OBJ_DATA) {
GST_WARNING_OBJECT (demux, "headers not followed by a DATA object");
return FALSE;
"data_offset=%" G_GINT64_FORMAT ", data_size=%" G_GINT64_FORMAT
", index_offset=%" G_GUINT64_FORMAT, demux->num_packets,
demux->data_offset, demux->data_size, demux->index_offset);
-
+#ifdef TIZEN_FEATURE_ASFDEMUX_CHECK_DATA_SIZE
+ if (demux->data_size == 0) {
+ GST_WARNING_OBJECT (demux, "DATA object size is zero");
+ return FALSE;
+ }
+#endif
return TRUE;
}
gst_buffer_map (buf, &map, GST_MAP_READ);
g_assert (map.size >= 16 + 8);
- asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE);
+ if (!asf_demux_peek_object (demux, map.data, 16 + 8, &obj, TRUE)) {
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_replace (&buf, NULL);
+ flow = GST_FLOW_ERROR;
+ goto read_failed;
+ }
gst_buffer_unmap (buf, &map);
gst_buffer_replace (&buf, NULL);
if (obj.id != ASF_OBJ_HEADER)
goto wrong_type;
- GST_LOG_OBJECT (demux, "header size = %u", (guint) obj.size);
+ GST_LOG_OBJECT (demux, "header size = %" G_GUINT64_FORMAT, obj.size);
/* pull HEADER object */
if (!gst_asf_demux_pull_data (demux, demux->base_offset, obj.size, &buf,
if (buf)
gst_buffer_unmap (buf, &map);
gst_buffer_replace (&buf, NULL);
+ if (flow == ASF_FLOW_NEED_MORE_DATA)
+ flow = GST_FLOW_ERROR;
*pflow = flow;
return FALSE;
}
{
GstClockTime preroll_time;
guint i, num_no_data = 0;
+ AsfStreamType prerolled_types = 0, all_types = 0;
/* Allow at least 500ms of preroll_time */
preroll_time = MAX (demux->preroll, 500 * GST_MSECOND);
gint last_idx;
stream = &demux->stream[i];
+
+ all_types |= stream->type;
+
if (G_UNLIKELY (stream->payloads->len == 0)) {
++num_no_data;
GST_LOG_OBJECT (stream->pad, "no data queued");
continue;
}
+ prerolled_types |= stream->type;
+
/* find last payload with timestamp */
for (last_idx = stream->payloads->len - 1;
last_idx >= 0 && (last_payload == NULL
}
}
+ GST_LOG_OBJECT (demux, "all_types:%d prerolled_types:%d",
+ all_types, prerolled_types);
+
+ /* If streams of each present type have prerolled, we are good to go */
+ if (all_types != 0 && prerolled_types == all_types)
+ return TRUE;
+
if (G_UNLIKELY (num_no_data > 0))
return FALSE;
}
static gboolean
-gst_asf_demux_check_first_ts (GstASFDemux * demux, gboolean force)
+gst_asf_demux_get_first_ts (GstASFDemux * demux)
{
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (demux->first_ts))) {
GstClockTime first_ts = GST_CLOCK_TIME_NONE;
/* there are some DVR ms files where first packet has TS of 0 (instead of -1) while subsequent packets have
regular (singificantly larger) timestamps. If we don't deal with it, we may end up with huge gap in timestamps
- which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
+ which makes playback stuck. The 0 timestamp may also be valid though, if the second packet timestamp continues
from it. I havent found a better way to distinguish between these two, except to set an arbitrary boundary
and disregard the first 0 timestamp if the second timestamp is bigger than the boundary) */
- if (stream_min_ts == 0 && stream_min_ts2 == GST_CLOCK_TIME_NONE && !force) /* still waiting for the second timestamp */
- return FALSE;
+ GST_DEBUG_OBJECT (demux,
+ "stream #%u stream_min_ts %" GST_TIME_FORMAT " stream_min_ts2 %"
+ GST_TIME_FORMAT, stream->id, GST_TIME_ARGS (stream_min_ts),
+ GST_TIME_ARGS (stream_min_ts2));
if (stream_min_ts == 0 && stream_min_ts2 > GST_SECOND) /* first timestamp is 0 and second is significantly larger, disregard the 0 */
stream_min_ts = stream_min_ts2;
- /* if we don't have timestamp for this stream, wait for more data */
- if (!GST_CLOCK_TIME_IS_VALID (stream_min_ts) && !force)
- return FALSE;
-
if (GST_CLOCK_TIME_IS_VALID (stream_min_ts) &&
(!GST_CLOCK_TIME_IS_VALID (first_ts) || first_ts > stream_min_ts))
first_ts = stream_min_ts;
}
- if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen with force = TRUE */
+ if (!GST_CLOCK_TIME_IS_VALID (first_ts)) /* can happen */
first_ts = 0;
demux->first_ts = first_ts;
static gboolean
gst_asf_demux_check_activate_streams (GstASFDemux * demux, gboolean force)
{
- guint i;
+ guint i, actual_streams = 0;
if (demux->activated_streams)
return TRUE;
- if (G_UNLIKELY (!gst_asf_demux_check_first_ts (demux, force)))
- return FALSE;
-
if (!all_streams_prerolled (demux) && !force) {
GST_DEBUG_OBJECT (demux, "not all streams with data beyond preroll yet");
return FALSE;
}
+ if (G_UNLIKELY (!gst_asf_demux_get_first_ts (demux)))
+ return FALSE;
+
for (i = 0; i < demux->num_streams; ++i) {
AsfStream *stream = &demux->stream[i];
* a stream, then we active it, or we don't, then we'll ignore it */
GST_LOG_OBJECT (stream->pad, "is prerolled - activate!");
gst_asf_demux_activate_stream (demux, stream);
+ actual_streams += 1;
} else {
GST_LOG_OBJECT (stream->pad, "no data, ignoring stream");
}
}
+ if (actual_streams == 0) {
+ /* We don't have any streams activated ! */
+ GST_ERROR_OBJECT (demux, "No streams activated!");
+ return FALSE;
+ }
+
gst_asf_demux_release_old_pads (demux);
demux->activated_streams = TRUE;
AsfPayload *payload = NULL;
gint last_idx;
- /* find last payload with timestamp */
- for (last_idx = stream->payloads->len - 1;
- last_idx >= 0 && (payload == NULL
- || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
- payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
- }
+ if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
+ /* Reverse playback */
+
+ if (stream->is_video) {
+ /* We have to push payloads from KF to the first frame we accumulated (reverse order) */
+ if (stream->reverse_kf_ready) {
+ payload =
+ &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
+ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (payload->ts))) {
+ /* TODO : remove payload from the list? */
+ continue;
+ }
+ } else {
+ continue;
+ }
+ } else {
+ /* find first complete payload with timestamp */
+ for (j = stream->payloads->len - 1;
+ j >= 0 && (payload == NULL
+ || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --j) {
+ payload = &g_array_index (stream->payloads, AsfPayload, j);
+ }
- /* if this is first payload after seek we might need to update the segment */
- if (GST_CLOCK_TIME_IS_VALID (payload->ts))
- gst_asf_demux_check_segment_ts (demux, payload->ts);
+ /* If there's a complete payload queued for this stream */
+ if (!gst_asf_payload_is_complete (payload))
+ continue;
- if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
- (payload->ts < demux->segment.start))) {
- if (G_UNLIKELY ((!demux->accurate) && payload->keyframe)) {
- GST_DEBUG_OBJECT (stream->pad,
- "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
- GST_TIME_ARGS (payload->ts));
- demux->segment.start = payload->ts;
- demux->segment.time = payload->ts;
- } else {
- GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
- GST_TIME_FORMAT " which is before our segment start %"
- GST_TIME_FORMAT ", not pushing yet", GST_TIME_ARGS (payload->ts),
- GST_TIME_ARGS (demux->segment.start));
- continue;
}
- }
+ } else {
- /* Now see if there's a complete payload queued for this stream */
+ /* find last payload with timestamp */
+ for (last_idx = stream->payloads->len - 1;
+ last_idx >= 0 && (payload == NULL
+ || !GST_CLOCK_TIME_IS_VALID (payload->ts)); --last_idx) {
+ payload = &g_array_index (stream->payloads, AsfPayload, last_idx);
+ }
- payload = NULL;
- /* find first complete payload with timestamp */
- for (j = 0;
- j < stream->payloads->len && (payload == NULL
- || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
- payload = &g_array_index (stream->payloads, AsfPayload, j);
- }
+ /* if this is first payload after seek we might need to update the segment */
+ if (GST_CLOCK_TIME_IS_VALID (payload->ts))
+ gst_asf_demux_check_segment_ts (demux, payload->ts);
+
+ if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (payload->ts) &&
+ (payload->ts < demux->segment.start))) {
+ if (G_UNLIKELY ((demux->keyunit_sync) && (!demux->accurate)
+ && payload->keyframe)) {
+ GST_DEBUG_OBJECT (stream->pad,
+ "Found keyframe, updating segment start to %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (payload->ts));
+ demux->segment.start = payload->ts;
+ demux->segment.time = payload->ts;
+ } else {
+ GST_DEBUG_OBJECT (stream->pad, "Last queued payload has timestamp %"
+ GST_TIME_FORMAT " which is before our segment start %"
+ GST_TIME_FORMAT ", not pushing yet",
+ GST_TIME_ARGS (payload->ts),
+ GST_TIME_ARGS (demux->segment.start));
+ continue;
+ }
+ }
+ payload = NULL;
+ /* find first complete payload with timestamp */
+ for (j = 0;
+ j < stream->payloads->len && (payload == NULL
+ || !GST_CLOCK_TIME_IS_VALID (payload->ts)); ++j) {
+ payload = &g_array_index (stream->payloads, AsfPayload, j);
+ }
- if (!gst_asf_payload_is_complete (payload))
- continue;
+ /* Now see if there's a complete payload queued for this stream */
+ if (!gst_asf_payload_is_complete (payload))
+ continue;
+ }
/* ... and whether its timestamp is lower than the current best */
if (best_stream == NULL || best_payload->ts > payload->ts) {
while ((stream = gst_asf_demux_find_stream_with_complete_payload (demux))) {
AsfPayload *payload;
+ GstClockTime timestamp = GST_CLOCK_TIME_NONE;
+ GstClockTime duration = GST_CLOCK_TIME_NONE;
/* wait until we had a chance to "lock on" some payload's timestamp */
if (G_UNLIKELY (demux->need_newsegment
&& !GST_CLOCK_TIME_IS_VALID (demux->segment_ts)))
return GST_FLOW_OK;
- payload = &g_array_index (stream->payloads, AsfPayload, 0);
+ if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
+ && stream->payloads->len) {
+ payload = &g_array_index (stream->payloads, AsfPayload, stream->kf_pos);
+ } else {
+ payload = &g_array_index (stream->payloads, AsfPayload, 0);
+ }
/* do we need to send a newsegment event */
if ((G_UNLIKELY (demux->need_newsegment))) {
}
/* FIXME : only if ACCURATE ! */
- if (G_LIKELY (!demux->accurate
- && (GST_CLOCK_TIME_IS_VALID (payload->ts)))) {
+ if (G_LIKELY (demux->keyunit_sync && !demux->accurate
+ && (GST_CLOCK_TIME_IS_VALID (payload->ts)))
+ && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
GST_DEBUG ("Adjusting newsegment start to %" GST_TIME_FORMAT,
GST_TIME_ARGS (payload->ts));
demux->segment.start = payload->ts;
* typically useful for live src, but might (unavoidably) mess with
* position reporting if a live src is playing not so live content
* (e.g. rtspsrc taking some time to fall back to tcp) */
- GST_BUFFER_PTS (payload->buf) = payload->ts;
- if (GST_BUFFER_PTS_IS_VALID (payload->buf)) {
- GST_BUFFER_PTS (payload->buf) += demux->in_gap;
+ timestamp = payload->ts;
+ if (GST_CLOCK_TIME_IS_VALID (timestamp)
+ && !GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
+ timestamp += demux->in_gap;
+
+ /* Check if we're after the segment already, if so no need to push
+ * anything here */
+ if (demux->segment.stop != -1 && timestamp > demux->segment.stop) {
+ GST_DEBUG_OBJECT (stream->pad,
+ "Payload after segment stop %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (demux->segment.stop));
+ ret =
+ gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
+ GST_FLOW_EOS);
+ gst_buffer_unref (payload->buf);
+ payload->buf = NULL;
+ g_array_remove_index (stream->payloads, 0);
+ /* Break out as soon as we have an issue */
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ break;
+
+ continue;
+ }
}
+
+ GST_BUFFER_PTS (payload->buf) = timestamp;
+
if (payload->duration == GST_CLOCK_TIME_NONE
- && stream->ext_props.avg_time_per_frame != 0)
- GST_BUFFER_DURATION (payload->buf) =
- stream->ext_props.avg_time_per_frame * 100;
- else
- GST_BUFFER_DURATION (payload->buf) = payload->duration;
+ && stream->ext_props.avg_time_per_frame != 0) {
+ duration = stream->ext_props.avg_time_per_frame * 100;
+ } else {
+ duration = payload->duration;
+ }
+ GST_BUFFER_DURATION (payload->buf) = duration;
/* FIXME: we should really set durations on buffers if we can */
GST_LOG_OBJECT (stream->pad, "pushing buffer, %" GST_PTR_FORMAT,
payload->buf);
+ if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video) {
+ if (stream->reverse_kf_ready == TRUE && stream->kf_pos == 0) {
+ GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
+ }
+ } else if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)) {
+ GST_BUFFER_FLAG_SET (payload->buf, GST_BUFFER_FLAG_DISCONT);
+ }
+
+
if (stream->active) {
if (G_UNLIKELY (stream->first_buffer)) {
if (stream->streamheader != NULL) {
stream->first_buffer = FALSE;
}
+ if (GST_CLOCK_TIME_IS_VALID (timestamp)
+ && timestamp > demux->segment.position) {
+ demux->segment.position = timestamp;
+ if (GST_CLOCK_TIME_IS_VALID (duration))
+ demux->segment.position += timestamp;
+ }
+
ret = gst_pad_push (stream->pad, payload->buf);
- ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
+ ret =
+ gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
+ ret);
} else {
gst_buffer_unref (payload->buf);
ret = GST_FLOW_OK;
}
payload->buf = NULL;
- g_array_remove_index (stream->payloads, 0);
+ if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment) && stream->is_video
+ && stream->reverse_kf_ready) {
+ g_array_remove_index (stream->payloads, stream->kf_pos);
+ stream->kf_pos--;
+
+ if (stream->reverse_kf_ready == TRUE && stream->kf_pos < 0) {
+ stream->kf_pos = 0;
+ stream->reverse_kf_ready = FALSE;
+ }
+ } else {
+ g_array_remove_index (stream->payloads, 0);
+ }
/* Break out as soon as we have an issue */
if (G_UNLIKELY (ret != GST_FLOW_OK))
{
AsfObject obj;
GstMapInfo map;
+ gboolean valid;
g_assert (buf != NULL);
GST_LOG_OBJECT (demux, "Checking if buffer is a header");
}
/* check if it is a header */
- asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj, TRUE);
+ valid =
+ asf_demux_peek_object (demux, map.data, ASF_OBJECT_HEADER_SIZE, &obj,
+ TRUE);
gst_buffer_unmap (buf, &map);
- if (obj.id == ASF_OBJ_HEADER) {
+ if (valid && obj.id == ASF_OBJ_HEADER) {
return TRUE;
}
return FALSE;
GstFlowReturn flow = GST_FLOW_OK;
GstBuffer *buf = NULL;
guint64 off;
- gboolean sent_eos = FALSE;
if (G_UNLIKELY (demux->state == GST_ASF_DEMUX_STATE_HEADER)) {
if (!gst_asf_demux_pull_headers (demux, &flow)) {
goto pause;
}
- gst_asf_demux_pull_indices (demux);
+ flow = gst_asf_demux_pull_indices (demux);
+ if (flow != GST_FLOW_OK)
+ goto pause;
}
g_assert (demux->state == GST_ASF_DEMUX_STATE_DATA);
if (G_UNLIKELY (!gst_asf_demux_pull_data (demux, off,
demux->packet_size * demux->speed_packets, &buf, &flow))) {
GST_DEBUG_OBJECT (demux, "got flow %s", gst_flow_get_name (flow));
- if (flow == GST_FLOW_EOS)
+ if (flow == GST_FLOW_EOS) {
goto eos;
- else if (flow == GST_FLOW_FLUSHING) {
+ } else if (flow == GST_FLOW_FLUSHING) {
GST_DEBUG_OBJECT (demux, "Not fatal");
goto pause;
- } else
+ } else {
goto read_failed;
+ }
}
if (G_LIKELY (demux->speed_packets == 1)) {
GST_INFO_OBJECT (demux, "Ignoring recoverable parse error");
gst_buffer_unref (buf);
- ++demux->packet;
+
+ if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
+ && !demux->seek_to_cur_pos) {
+ --demux->packet;
+ if (demux->packet < 0) {
+ goto eos;
+ }
+ } else {
+ ++demux->packet;
+ }
+
return;
}
flow = gst_asf_demux_push_complete_payloads (demux, FALSE);
- ++demux->packet;
+ if (GST_ASF_DEMUX_IS_REVERSE_PLAYBACK (demux->segment)
+ && !demux->seek_to_cur_pos) {
+ --demux->packet;
+ if (demux->packet < 0) {
+ goto eos;
+ }
+ } else {
+ ++demux->packet;
+ }
} else {
guint n;
gst_buffer_unref (buf);
- if (G_UNLIKELY (demux->num_packets > 0
- && demux->packet >= demux->num_packets)) {
+ if (G_UNLIKELY ((demux->num_packets > 0
+ && demux->packet >= demux->num_packets)
+ || flow == GST_FLOW_EOS)) {
GST_LOG_OBJECT (demux, "reached EOS");
goto eos;
}
* less data queued than required for preroll; force stream activation and
* send any pending payloads before sending EOS */
if (!demux->activated_streams)
- gst_asf_demux_push_complete_payloads (demux, TRUE);
+ flow = gst_asf_demux_push_complete_payloads (demux, TRUE);
/* we want to push an eos or post a segment-done in any case */
if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
return;
}
}
- /* normal playback, send EOS to all linked pads */
- GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
- gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
- sent_eos = TRUE;
+
+ if (!(demux->segment.flags & GST_SEEK_FLAG_SEGMENT)) {
+ if (demux->activated_streams) {
+ /* normal playback, send EOS to all linked pads */
+ GST_INFO_OBJECT (demux, "Sending EOS, at end of stream");
+ gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
+ } else {
+ GST_WARNING_OBJECT (demux, "EOS without exposed streams");
+ flow = GST_FLOW_EOS;
+ }
+ }
/* ... and fall through to pause */
}
pause:
demux->segment_running = FALSE;
gst_pad_pause_task (demux->sinkpad);
- /* For the error cases (not EOS) */
- if (!sent_eos) {
- if (flow == GST_FLOW_EOS)
- gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
- else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
- /* Post an error. Hopefully something else already has, but if not... */
- GST_ELEMENT_ERROR (demux, STREAM, FAILED,
- (_("Internal data stream error.")),
- ("streaming stopped, reason %s", gst_flow_get_name (flow)));
- }
+ /* For the error cases */
+ if (flow == GST_FLOW_EOS && !demux->activated_streams) {
+ GST_ELEMENT_ERROR (demux, STREAM, WRONG_TYPE, (NULL),
+ ("This doesn't seem to be an ASF file"));
+ } else if (flow < GST_FLOW_EOS || flow == GST_FLOW_NOT_LINKED) {
+ /* Post an error. Hopefully something else already has, but if not... */
+ GST_ELEMENT_FLOW_ERROR (demux, flow);
+ gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
}
+
return;
}
read_failed:
{
GST_DEBUG_OBJECT (demux, "Read failed, doh");
- gst_asf_demux_send_event_unlocked (demux, gst_event_new_eos ());
flow = GST_FLOW_EOS;
goto pause;
}
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 {
+ if (asf_demux_peek_object (demux, cdata, ASF_OBJECT_HEADER_SIZE, &obj, FALSE)
+ && obj.id == ASF_OBJ_HEADER) {
return GST_ASF_DEMUX_CHECK_HEADER_YES;
}
+
+ return GST_ASF_DEMUX_CHECK_HEADER_NO;
}
static GstFlowReturn
audio->word_size = gst_asf_demux_get_uint16 (p_data, p_size);
/* Codec specific data size */
audio->size = gst_asf_demux_get_uint16 (p_data, p_size);
+ if (audio->size > *p_size) {
+ GST_WARNING ("Corrupted audio codec_data (should be at least %u bytes, is %"
+ G_GUINT64_FORMAT " long)", audio->size, *p_size);
+ return FALSE;
+ }
return TRUE;
}
return FALSE;
fmt->size = gst_asf_demux_get_uint32 (p_data, p_size);
+ /* Sanity checks */
+ if (fmt->size < 40) {
+ GST_WARNING ("Corrupted asf_stream_video_format (size < 40)");
+ return FALSE;
+ }
+ if ((guint64) fmt->size - 4 > *p_size) {
+ GST_WARNING ("Corrupted asf_stream_video_format (codec_data is too small)");
+ return FALSE;
+ }
fmt->width = gst_asf_demux_get_uint32 (p_data, p_size);
fmt->height = gst_asf_demux_get_uint32 (p_data, p_size);
fmt->planes = gst_asf_demux_get_uint16 (p_data, p_size);
stream->payloads = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
+ /* TODO: create this array during reverse play? */
+ stream->payloads_rev = g_array_new (FALSE, FALSE, sizeof (AsfPayload));
+
GST_INFO ("Created pad %s for stream %u with caps %" GST_PTR_FORMAT,
GST_PAD_NAME (src_pad), demux->num_streams, caps);
src_pad = gst_pad_new_from_static_template (&audio_src_template, name);
g_free (name);
- /* Swallow up any left over data and set up the
+ /* Swallow up any left over data and set up the
* standard properties from the header info */
if (size_left) {
GST_INFO_OBJECT (demux, "Audio header contains %d bytes of "
g_free (codec_name);
}
+ if (audio->byte_rate > 0) {
+ /* Some ASF files have no bitrate props object (often seen with
+ * ASF files that contain raw audio data). Example files can
+ * be generated with FFmpeg (tested with v2.8.6), like this:
+ *
+ * ffmpeg -i sine-wave.wav -c:a pcm_alaw file.asf
+ *
+ * In this case, if audio->byte_rate is nonzero, use that as
+ * the bitrate. */
+
+ guint bitrate = audio->byte_rate * 8;
+
+ if (tags == NULL)
+ tags = gst_tag_list_new_empty ();
+
+ /* Add bitrate, but only if there is none set already, since
+ * this is just a fallback in case there is no bitrate tag
+ * already present */
+ gst_tag_list_add (tags, GST_TAG_MERGE_KEEP, GST_TAG_BITRATE, bitrate, NULL);
+ }
+
if (extradata)
gst_buffer_unref (extradata);
++demux->num_audio_streams;
+#ifdef TIZEN_FEATURE_ASFDEMUX_POST_TAG_MSG
+ if (tags) {
+ /* post now, send event on pad later */
+ gst_element_post_message (GST_ELEMENT_CAST (demux),
+ gst_message_new_tag (GST_OBJECT_CAST (demux), gst_tag_list_copy (tags)));
+ }
+#endif
+
return gst_asf_demux_setup_pad (demux, src_pad, caps, id, FALSE, NULL, tags);
}
gchar *str;
gchar *name = NULL;
gchar *codec_name = NULL;
- gint size_left = video->size - 40;
+ guint64 size_left = video->size - 40;
GstBuffer *streamheader = NULL;
guint par_w = 1, par_h = 1;
/* Now try some gstreamer formatted MIME types (from gst_avi_demux_strf_vids) */
if (size_left) {
- GST_LOG ("Video header has %d bytes of codec specific data", size_left);
+ GST_LOG ("Video header has %" G_GUINT64_FORMAT
+ " bytes of codec specific data (vs %" G_GUINT64_FORMAT ")", size_left,
+ *p_size);
g_assert (size_left <= *p_size);
gst_asf_demux_get_buffer (&extradata, size_left, p_data, p_size);
}
streamheader = gst_buffer_ref (buf);
gst_asf_demux_add_stream_headers_to_caps (demux, buf, caps_s);
gst_structure_remove_field (caps_s, "codec_data");
+ gst_structure_set (caps_s, "stream-format", G_TYPE_STRING,
+ "byte-stream", NULL);
+ } else {
+ gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "avc",
+ NULL);
}
gst_buffer_unmap (buf, &mapinfo);
}
+ } else {
+ gst_structure_set (caps_s, "stream-format", G_TYPE_STRING, "byte-stream",
+ NULL);
}
}
++demux->num_video_streams;
+#ifdef TIZEN_FEATURE_ASFDEMUX_POST_TAG_MSG
+ if (tags) {
+ /* post now, send event on pad later */
+ gst_element_post_message (GST_ELEMENT_CAST (demux),
+ gst_message_new_tag (GST_OBJECT_CAST (demux), gst_tag_list_copy (tags)));
+ }
+#endif
+
return gst_asf_demux_setup_pad (demux, src_pad, caps, id, TRUE,
streamheader, tags);
}
flags = gst_asf_demux_get_uint16 (&data, &size);
stream_id = flags & 0x7f;
- is_encrypted = ! !((flags & 0x8000) << 15);
+ is_encrypted = ! !(flags & 0x8000);
unknown = gst_asf_demux_get_uint32 (&data, &size);
GST_DEBUG_OBJECT (demux, "Found stream %u, time_offset=%" GST_TIME_FORMAT,
&data, &size)) {
goto not_enough_data;
}
-
+#ifdef TIZEN_FEATURE_ASFDEMUX_DISABLE_UNSUPPORTED_FORMAT
+ /* Compare video format WMV*, WVC* */
+ if (((video_format_object.tag & 0x00ffffff) == (guint32)(('W')|('M')<<8|('V')<<16))
+ || ((video_format_object.tag & 0x00ffffff) == (guint32)(('W')|('V')<<8|('C')<<16))) {
+ GST_ERROR_OBJECT (demux, "WMV file format is not supported.");
+ demux->is_supported_format = FALSE;
+ return NULL;
+ }
+#endif
stream = gst_asf_demux_add_video_stream (demux, &video_format_object,
stream_id, &data, &size);
break;
}
- if (stream)
+ if (stream) {
stream->inspect_payload = inspect_payload;
+ stream->type = stream_type;
+ }
return stream;
not_enough_data:
break;
}
case ASF_DEMUX_DATA_TYPE_DWORD:{
- guint uint_val = GST_READ_UINT32_LE (value);
+ guint uint_val;
+
+ if (value_len < 4)
+ break;
+
+ uint_val = GST_READ_UINT32_LE (value);
/* this is the track number */
g_value_init (&tag_value, G_TYPE_UINT);
}
/* Detect 3D */
case ASF_DEMUX_DATA_TYPE_BOOL:{
- gboolean bool_val = GST_READ_UINT32_LE (value);
+ gboolean bool_val;
+
+ if (value_len < 4)
+ break;
+
+ bool_val = GST_READ_UINT32_LE (value);
if (strncmp ("Stereoscopic", name_utf8, strlen (name_utf8)) == 0) {
if (bool_val) {
unknown = gst_asf_demux_get_uint8 (&data, &size);
GST_INFO_OBJECT (demux, "object is a header with %u parts", num_objects);
-
+ demux->saw_file_header = FALSE;
/* Loop through the header's objects, processing those */
for (i = 0; i < num_objects; ++i) {
GST_INFO_OBJECT (demux, "reading header part %u", i);
break;
}
}
+ if (!demux->saw_file_header) {
+ GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL),
+ ("Header does not have mandatory FILE section"));
+ return GST_FLOW_ERROR;
+ }
return ret;
packets_count);
GST_INFO ("preroll = %" G_GUINT64_FORMAT, demux->preroll);
+ demux->saw_file_header = TRUE;
+
return GST_FLOW_OK;
/* ERRORS */
GST_DEBUG_OBJECT (demux, "bitrate of stream %u = %u", stream_id, bitrate);
stream = gst_asf_demux_get_stream (demux, stream_id);
if (stream) {
- if (stream->pending_tags == NULL) {
- stream->pending_tags =
- gst_tag_list_new (GST_TAG_BITRATE, bitrate, NULL);
- }
+ if (stream->pending_tags == NULL)
+ stream->pending_tags = gst_tag_list_new_empty ();
+ gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
+ GST_TAG_BITRATE, bitrate, NULL);
} else {
GST_WARNING_OBJECT (demux, "Stream id %u wasn't found", stream_id);
}
GST_WARNING_OBJECT (demux, "short read parsing language list object!");
g_free (demux->languages);
demux->languages = NULL;
+ demux->num_languages = 0;
return GST_FLOW_OK; /* not fatal */
}
}
data_start = data;
obj_size = (guint) size;
+ esp.payload_extensions = NULL;
+
if (size < 64)
goto not_enough_data;
if (num_payload_ext > 0)
esp.payload_extensions = g_new0 (AsfPayloadExtension, num_payload_ext + 1);
- else
- esp.payload_extensions = NULL;
for (i = 0; i < num_payload_ext; ++i) {
AsfPayloadExtension ext;
goto done;
}
+ if (size < ASF_OBJECT_HEADER_SIZE)
+ goto not_enough_data;
+
/* get size of the stream object */
if (!asf_demux_peek_object (demux, data, size, &stream_obj, TRUE))
- goto not_enough_data;
+ goto corrupted_stream;
if (stream_obj.id != ASF_OBJ_STREAM)
goto expected_stream_object;
stream = gst_asf_demux_parse_stream_object (demux, stream_obj_data, len);
g_free (stream_obj_data);
+#ifdef TIZEN_FEATURE_ASFDEMUX_DISABLE_UNSUPPORTED_FORMAT
+ if ((stream == NULL) && (demux->is_supported_format == FALSE)) {
+ g_free (esp.payload_extensions);
+ return GST_FLOW_NOT_SUPPORTED;
+ }
+#endif
+
done:
if (stream) {
GST_WARNING_OBJECT (demux, "Ext. stream properties for unknown stream");
}
+ if (!stream)
+ g_free (esp.payload_extensions);
+
return GST_FLOW_OK;
/* Errors */
not_enough_data:
{
GST_WARNING_OBJECT (demux, "short read parsing ext stream props object!");
+ g_free (esp.payload_extensions);
return GST_FLOW_OK; /* not absolutely fatal */
}
expected_stream_object:
GST_WARNING_OBJECT (demux, "error parsing extended stream properties "
"object: expected embedded stream object, but got %s object instead!",
gst_asf_get_guid_nick (asf_object_guids, stream_obj.id));
+ g_free (esp.payload_extensions);
return GST_FLOW_OK; /* not absolutely fatal */
}
+corrupted_stream:
+ {
+ GST_WARNING_OBJECT (demux, "Corrupted stream");
+ g_free (esp.payload_extensions);
+ return GST_FLOW_ERROR;
+ }
}
static const gchar *
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, TRUE);
+ if (!asf_demux_peek_object (demux, *p_data, ASF_OBJECT_HEADER_SIZE, &obj,
+ TRUE))
+ return GST_FLOW_ERROR;
gst_asf_demux_skip_bytes (ASF_OBJECT_HEADER_SIZE, p_data, p_size);
obj_data_size = obj.size - ASF_OBJECT_HEADER_SIZE;
switch (obj.id) {
case ASF_OBJ_STREAM:
gst_asf_demux_parse_stream_object (demux, *p_data, obj_data_size);
+#ifdef TIZEN_FEATURE_ASFDEMUX_DISABLE_UNSUPPORTED_FORMAT
+ if (demux->is_supported_format == FALSE) {
+ ret = GST_FLOW_NOT_SUPPORTED;
+ break;
+ }
+#endif
ret = GST_FLOW_OK;
break;
case ASF_OBJ_FILE:
gst_segment_init (&demux->segment, GST_FORMAT_TIME);
demux->need_newsegment = TRUE;
demux->segment_running = FALSE;
+ demux->keyunit_sync = FALSE;
demux->accurate = FALSE;
demux->adapter = gst_adapter_new ();
demux->metadata = gst_caps_new_empty ();
demux->index_offset = 0;
demux->base_offset = 0;
demux->flowcombiner = gst_flow_combiner_new ();
+
break;
}
default: