diff --git a/ChangeLog b/ChangeLog index cc59d4622f..d1278e8b83 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2008-10-27 Sebastian Dröge + + * gst/flv/gstflvdemux.c: (gst_flv_demux_create_index), + (gst_flv_demux_loop): + * gst/flv/gstflvparse.c: (gst_flv_parse_tag_script), + (gst_flv_parse_tag_audio), (gst_flv_parse_tag_video), + (gst_flv_parse_tag_timestamp): + * gst/flv/gstflvparse.h: + In pull mode we create our own index before doing anything else + and don't use the index provided by some files (which are more than + often incorrect and cause failed seeks). + + For push mode we still use the index provided by the file and extend it + while doing the playback. + 2008-10-27 Sebastian Dröge * gst/flv/gstflvdemux.c: (gst_flv_demux_push_src_event), diff --git a/gst/flv/gstflvdemux.c b/gst/flv/gstflvdemux.c index 8f13ef0b13..6448d6a5da 100644 --- a/gst/flv/gstflvdemux.c +++ b/gst/flv/gstflvdemux.c @@ -448,6 +448,34 @@ gst_flv_demux_push_src_event (GstFLVDemux * demux, GstEvent * event) return ret; } +static void +gst_flv_demux_create_index (GstFLVDemux * demux) +{ + gint64 size; + GstFormat fmt = GST_FORMAT_BYTES; + size_t tag_size; + guint64 old_offset; + GstBuffer *buffer; + GstFlowReturn ret; + + if (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &size) || + fmt != GST_FORMAT_BYTES) + return; + + old_offset = demux->offset; + + while ((ret = + gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset, 12, + &buffer)) == GST_FLOW_OK) { + if (gst_flv_parse_tag_timestamp (demux, GST_BUFFER_DATA (buffer), + GST_BUFFER_SIZE (buffer), &tag_size) == GST_CLOCK_TIME_NONE) + break; + demux->offset += tag_size; + } + + demux->offset = old_offset; +} + static void gst_flv_demux_loop (GstPad * pad) { @@ -467,38 +495,9 @@ gst_flv_demux_loop (GstPad * pad) break; default: ret = gst_flv_demux_pull_header (pad, demux); + if (ret == GST_FLOW_OK) + gst_flv_demux_create_index (demux); - /* If we parsed the header successfully try to get an - * approximate duration by looking at the last tag's timestamp */ - if (ret == GST_FLOW_OK) { - gint64 size; - GstFormat fmt = GST_FORMAT_BYTES; - - if (gst_pad_query_peer_duration (pad, &fmt, &size) && - fmt == GST_FORMAT_BYTES && size != -1 && size > FLV_HEADER_SIZE) { - GstBuffer *buffer; - - if (gst_flv_demux_pull_range (demux, pad, size - 4, 4, - &buffer) == GST_FLOW_OK) { - guint32 prev_tag_size = - GST_READ_UINT32_BE (GST_BUFFER_DATA (buffer)); - - gst_buffer_unref (buffer); - - if (size - 4 - prev_tag_size > FLV_HEADER_SIZE && - prev_tag_size >= 8 && - gst_flv_demux_pull_range (demux, pad, - size - prev_tag_size - 4, prev_tag_size, - &buffer) == GST_FLOW_OK) { - demux->duration = - gst_flv_parse_tag_timestamp (demux, - GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer)); - - gst_buffer_unref (buffer); - } - } - } - } } /* pause if something went wrong */ @@ -527,6 +526,8 @@ gst_flv_demux_loop (GstPad * pad) break; default: ret = gst_flv_demux_pull_header (pad, demux); + if (ret == GST_FLOW_OK) + gst_flv_demux_create_index (demux); } /* pause if something went wrong */ diff --git a/gst/flv/gstflvparse.c b/gst/flv/gstflvparse.c index b68edd684d..87d7f689bf 100644 --- a/gst/flv/gstflvparse.c +++ b/gst/flv/gstflvparse.c @@ -371,8 +371,9 @@ gst_flv_parse_tag_script (GstFLVDemux * demux, const guint8 * data, g_free (function_name); - if (demux->index && demux->times && demux->filepositions) { - /* If an index was found, insert associations */ + if (demux->index && demux->times && demux->filepositions + && !demux->random_access) { + /* If an index was found and we're in push mode, insert associations */ for (i = 0; i < MIN (demux->times->len, demux->filepositions->len); i++) { guint64 time, fileposition; @@ -676,17 +677,20 @@ gst_flv_parse_tag_audio (GstFLVDemux * demux, const guint8 * data, GST_BUFFER_OFFSET (buffer) = demux->audio_offset++; GST_BUFFER_OFFSET_END (buffer) = demux->audio_offset; - /* Only add audio frames to the index if we have no video */ - if (!demux->has_video) { - if (demux->index) { - GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" - G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), - demux->cur_tag_offset); - gst_index_add_association (demux->index, demux->index_id, - GST_ASSOCIATION_FLAG_KEY_UNIT, - GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buffer), - GST_FORMAT_BYTES, demux->cur_tag_offset, NULL); - } + if (demux->duration == GST_CLOCK_TIME_NONE || + demux->duration < GST_BUFFER_TIMESTAMP (buffer)) + demux->duration = GST_BUFFER_TIMESTAMP (buffer); + + /* Only add audio frames to the index if we have no video + * and if we don't have random access */ + if (!demux->has_video && demux->index && !demux->random_access) { + GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" + G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), + demux->cur_tag_offset); + gst_index_add_association (demux->index, demux->index_id, + GST_ASSOCIATION_FLAG_KEY_UNIT, + GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buffer), + GST_FORMAT_BYTES, demux->cur_tag_offset, NULL); } if (G_UNLIKELY (demux->audio_need_discont)) { @@ -978,9 +982,13 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, GST_BUFFER_OFFSET (buffer) = demux->video_offset++; GST_BUFFER_OFFSET_END (buffer) = demux->video_offset; + if (demux->duration == GST_CLOCK_TIME_NONE || + demux->duration < GST_BUFFER_TIMESTAMP (buffer)) + demux->duration = GST_BUFFER_TIMESTAMP (buffer); + if (!keyframe) { GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT); - if (demux->index) { + if (demux->index && !demux->random_access) { GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), demux->cur_tag_offset); @@ -990,7 +998,7 @@ gst_flv_parse_tag_video (GstFLVDemux * demux, const guint8 * data, GST_FORMAT_BYTES, demux->cur_tag_offset, NULL); } } else { - if (demux->index) { + if (demux->index && !demux->random_access) { GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), demux->cur_tag_offset); @@ -1049,20 +1057,35 @@ beach: GstClockTime gst_flv_parse_tag_timestamp (GstFLVDemux * demux, const guint8 * data, - size_t data_size) + size_t data_size, size_t * tag_size) { guint32 pts = 0, pts_ext = 0; + guint32 tag_data_size; + guint8 type; + gboolean keyframe = TRUE; + GstClockTime ret; - if (data[0] != 9 && data[0] != 8 && data[0] != 18) { + g_return_val_if_fail (data_size >= 12, GST_CLOCK_TIME_NONE); + + type = data[0]; + + if (type != 9 && type != 8 && type != 18) { GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]); return GST_CLOCK_TIME_NONE; } - if (FLV_GET_BEUI24 (data + 1, data_size - 1) != data_size - 11) { - GST_WARNING_OBJECT (demux, "Invalid tag"); - return GST_CLOCK_TIME_NONE; + tag_data_size = FLV_GET_BEUI24 (data + 1, data_size - 1); + + if (data_size >= tag_data_size + 11 + 4) { + if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) { + GST_WARNING_OBJECT (demux, "Invalid tag size"); + return GST_CLOCK_TIME_NONE; + } } + if (tag_size) + *tag_size = tag_data_size + 11 + 4; + data += 4; GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1], @@ -1075,7 +1098,26 @@ gst_flv_parse_tag_timestamp (GstFLVDemux * demux, const guint8 * data, /* Combine them */ pts |= pts_ext << 24; - return pts * GST_MSECOND; + if (type == 9) { + data += 7; + + keyframe = ((data[0] >> 4) == 1); + } + + ret = pts * GST_MSECOND; + + if (demux->index && (type == 9 || (type == 8 && !demux->has_video))) { + GST_LOG_OBJECT (demux, "adding association %" GST_TIME_FORMAT "-> %" + G_GUINT64_FORMAT, GST_TIME_ARGS (ret), demux->offset); + gst_index_add_association (demux->index, demux->index_id, + (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT : GST_ASSOCIATION_FLAG_NONE, + GST_FORMAT_TIME, ret, GST_FORMAT_BYTES, demux->offset, NULL); + } + + if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret) + demux->duration = ret; + + return ret; } GstFlowReturn diff --git a/gst/flv/gstflvparse.h b/gst/flv/gstflvparse.h index 0dfeaa9762..55eae29e2c 100644 --- a/gst/flv/gstflvparse.h +++ b/gst/flv/gstflvparse.h @@ -38,7 +38,7 @@ GstFlowReturn gst_flv_parse_tag_type (GstFLVDemux * demux, const guint8 * data, GstFlowReturn gst_flv_parse_header (GstFLVDemux * demux, const guint8 * data, size_t data_size); -GstClockTime gst_flv_parse_tag_timestamp (GstFLVDemux *demux, const guint8 *data, size_t data_size); +GstClockTime gst_flv_parse_tag_timestamp (GstFLVDemux *demux, const guint8 *data, size_t data_size, size_t *tag_data_size); G_END_DECLS #endif /* __FLV_PARSE_H__ */