summaryrefslogtreecommitdiffstats
path: root/gst/flv
diff options
context:
space:
mode:
Diffstat (limited to 'gst/flv')
-rw-r--r--gst/flv/gstflvdemux.c63
-rw-r--r--gst/flv/gstflvparse.c84
-rw-r--r--gst/flv/gstflvparse.h2
3 files changed, 96 insertions, 53 deletions
diff --git a/gst/flv/gstflvdemux.c b/gst/flv/gstflvdemux.c
index 8f13ef0b..6448d6a5 100644
--- a/gst/flv/gstflvdemux.c
+++ b/gst/flv/gstflvdemux.c
@@ -449,6 +449,34 @@ gst_flv_demux_push_src_event (GstFLVDemux * demux, GstEvent * event)
}
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)
{
GstFLVDemux *demux = NULL;
@@ -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 b68edd68..87d7f689 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;
+
+ g_return_val_if_fail (data_size >= 12, GST_CLOCK_TIME_NONE);
+
+ type = data[0];
- if (data[0] != 9 && data[0] != 8 && data[0] != 18) {
+ 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 0dfeaa97..55eae29e 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__ */