2 * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 * SECTION:element-flvdemux
23 * flvdemux demuxes an FLV file into the different contained streams.
26 * <title>Example launch line</title>
28 * gst-launch-1.0 -v filesrc location=/path/to/flv ! flvdemux ! audioconvert ! autoaudiosink
29 * ]| This pipeline demuxes an FLV file and outputs the contained raw audio streams.
37 #include "gstflvdemux.h"
38 #include "gstflvmux.h"
41 #include <gst/base/gstbytereader.h>
42 #include <gst/base/gstbytewriter.h>
43 #include <gst/pbutils/descriptions.h>
44 #include <gst/pbutils/pbutils.h>
45 #include <gst/audio/audio.h>
46 #include <gst/video/video.h>
48 /* FIXME: don't rely on own GstIndex */
50 #include "gstmemindex.c"
51 #define GST_ASSOCIATION_FLAG_NONE GST_INDEX_ASSOCIATION_FLAG_NONE
52 #define GST_ASSOCIATION_FLAG_KEY_UNIT GST_INDEX_ASSOCIATION_FLAG_KEY_UNIT
53 #define GST_ASSOCIATION_FLAG_DELTA_UNIT GST_INDEX_ASSOCIATION_FLAG_DELTA_UNIT
55 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
58 GST_STATIC_CAPS ("video/x-flv")
61 static GstStaticPadTemplate audio_src_template =
62 GST_STATIC_PAD_TEMPLATE ("audio",
66 ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
67 "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
68 "audio/mpeg, mpegversion = (int) 4, stream-format = (string) raw, framed = (boolean) TRUE; "
69 "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
70 "audio/x-raw, format = (string) { U8, S16LE }, layout = (string) interleaved, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
71 "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
72 "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
73 "audio/x-speex, channels = (int) 1, rate = (int) 16000;")
76 static GstStaticPadTemplate video_src_template =
77 GST_STATIC_PAD_TEMPLATE ("video",
80 GST_STATIC_CAPS ("video/x-flash-video, flvversion=(int) 1; "
81 "video/x-flash-screen; "
82 "video/x-vp6-flash; " "video/x-vp6-alpha; "
83 "video/x-h264, stream-format=avc;")
86 GST_DEBUG_CATEGORY_STATIC (flvdemux_debug);
87 #define GST_CAT_DEFAULT flvdemux_debug
89 #define gst_flv_demux_parent_class parent_class
90 G_DEFINE_TYPE (GstFlvDemux, gst_flv_demux, GST_TYPE_ELEMENT);
92 /* 9 bytes of header + 4 bytes of first previous tag size */
93 #define FLV_HEADER_SIZE 13
94 /* 1 byte of tag type + 3 bytes of tag data size */
95 #define FLV_TAG_TYPE_SIZE 4
97 /* two seconds - consider dts are resynced to another base if this different */
98 #define RESYNC_THRESHOLD 2000
100 /* how much stream time to wait for audio tags to appear after we have video, or vice versa */
101 #define NO_MORE_PADS_THRESHOLD (6 * GST_SECOND)
103 static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
105 static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
106 GstEvent * event, gboolean seeking);
108 static gboolean gst_flv_demux_query (GstPad * pad, GstObject * parent,
110 static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent,
113 static GstIndex *gst_flv_demux_get_index (GstElement * element);
116 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
117 guint64 pos, gboolean keyframe)
119 GstIndexAssociation associations[2];
121 GstIndexEntry *entry;
123 GST_LOG_OBJECT (demux,
124 "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
125 keyframe, GST_TIME_ARGS (ts), pos);
127 /* if upstream is not seekable there is no point in building an index */
128 if (!demux->upstream_seekable)
131 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
136 /* entry may already have been added before, avoid adding indefinitely */
137 entry = gst_index_get_assoc_entry (index, demux->index_id,
138 GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
141 #ifndef GST_DISABLE_GST_DEBUG
145 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
146 key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
147 GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
148 ", keyframe %d", GST_TIME_ARGS (time), key);
149 /* there is not really a way to delete the existing one */
150 if (time != ts || key != ! !keyframe)
151 GST_DEBUG_OBJECT (demux, "metadata mismatch");
153 gst_object_unref (index);
157 associations[0].format = GST_FORMAT_TIME;
158 associations[0].value = ts;
159 associations[1].format = GST_FORMAT_BYTES;
160 associations[1].value = pos;
162 gst_index_add_associationv (index, demux->index_id,
163 (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
164 GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
165 (const GstIndexAssociation *) &associations);
167 if (pos > demux->index_max_pos)
168 demux->index_max_pos = pos;
169 if (ts > demux->index_max_time)
170 demux->index_max_time = ts;
172 gst_object_unref (index);
176 FLV_GET_STRING (GstByteReader * reader)
178 guint16 string_size = 0;
179 gchar *string = NULL;
180 const guint8 *str = NULL;
182 g_return_val_if_fail (reader != NULL, NULL);
184 if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
187 if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
190 string = g_try_malloc0 (string_size + 1);
191 if (G_UNLIKELY (!string)) {
195 if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
200 memcpy (string, str, string_size);
201 if (!g_utf8_validate (string, string_size, NULL)) {
210 gst_flv_demux_check_seekability (GstFlvDemux * demux)
213 gint64 start = -1, stop = -1;
215 demux->upstream_seekable = FALSE;
217 query = gst_query_new_seeking (GST_FORMAT_BYTES);
218 if (!gst_pad_peer_query (demux->sinkpad, query)) {
219 GST_DEBUG_OBJECT (demux, "seeking query failed");
220 gst_query_unref (query);
224 gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
227 gst_query_unref (query);
229 /* try harder to query upstream size if we didn't get it the first time */
230 if (demux->upstream_seekable && stop == -1) {
231 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
232 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
235 /* if upstream doesn't know the size, it's likely that it's not seekable in
236 * practice even if it technically may be seekable */
237 if (demux->upstream_seekable && (start != 0 || stop <= start)) {
238 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
239 demux->upstream_seekable = FALSE;
242 GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
246 parse_flv_demux_parse_date_string (GDate * date, const gchar * s)
248 g_date_set_parse (date, s);
249 if (g_date_valid (date))
252 /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
254 static const gchar *months[] = {
255 "Jan", "Feb", "Mar", "Apr",
256 "May", "Jun", "Jul", "Aug",
257 "Sep", "Oct", "Nov", "Dec"
259 gchar **tokens = g_strsplit (s, " ", -1);
264 if (g_strv_length (tokens) != 5)
267 if (strlen (tokens[1]) != 3)
269 for (i = 0; i < 12; i++) {
270 if (!strcmp (tokens[1], months[i])) {
276 g_date_set_month (date, i + 1);
278 d = g_ascii_strtoull (tokens[2], &endptr, 10);
279 if (d == 0 && *endptr != '\0')
282 g_date_set_day (date, d);
284 d = g_ascii_strtoull (tokens[4], &endptr, 10);
285 if (d == 0 && *endptr != '\0')
288 g_date_set_year (date, d);
297 gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
298 gboolean * end_marker)
300 gchar *tag_name = NULL;
303 /* Initialize the end_marker flag to FALSE */
306 /* Name of the tag */
307 tag_name = FLV_GET_STRING (reader);
308 if (G_UNLIKELY (!tag_name)) {
309 GST_WARNING_OBJECT (demux, "failed reading tag name");
313 /* What kind of object is that */
314 if (!gst_byte_reader_get_uint8 (reader, &tag_type))
317 GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
321 { /* Use a union to read the uint64 and then as a double */
324 if (!gst_byte_reader_get_float64_be (reader, &d))
327 GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
329 if (!strcmp (tag_name, "duration")) {
330 demux->duration = d * GST_SECOND;
332 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
333 GST_TAG_DURATION, demux->duration, NULL);
334 } else if (!strcmp (tag_name, "AspectRatioX")) {
336 demux->got_par = TRUE;
337 } else if (!strcmp (tag_name, "AspectRatioY")) {
339 demux->got_par = TRUE;
340 } else if (!strcmp (tag_name, "width")) {
342 } else if (!strcmp (tag_name, "height")) {
344 } else if (!strcmp (tag_name, "framerate")) {
345 demux->framerate = d;
347 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
352 case 1: /* Boolean */
356 if (!gst_byte_reader_get_uint8 (reader, &b))
359 GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
361 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
369 s = FLV_GET_STRING (reader);
373 GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
375 if (!strcmp (tag_name, "creationdate")) {
376 GDate *date = g_date_new ();
378 parse_flv_demux_parse_date_string (date, s);
379 if (!g_date_valid (date)) {
380 GST_DEBUG_OBJECT (demux, "Failed to parse string as date");
382 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
383 GST_TAG_DATE, date, NULL);
386 } else if (!strcmp (tag_name, "creator")) {
387 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
388 GST_TAG_ARTIST, s, NULL);
389 } else if (!strcmp (tag_name, "title")) {
390 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
391 GST_TAG_TITLE, s, NULL);
392 } else if (!strcmp (tag_name, "metadatacreator")) {
393 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
394 GST_TAG_ENCODER, s, NULL);
396 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
405 gboolean end_of_object_marker = FALSE;
407 while (!end_of_object_marker) {
408 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
409 &end_of_object_marker);
411 if (G_UNLIKELY (!ok)) {
412 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
419 case 8: /* ECMA array */
421 guint32 nb_elems = 0;
422 gboolean end_of_object_marker = FALSE;
424 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
427 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
430 while (!end_of_object_marker) {
431 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
432 &end_of_object_marker);
434 if (G_UNLIKELY (!ok)) {
435 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
442 case 9: /* End marker */
444 GST_DEBUG_OBJECT (demux, "end marker ?");
445 if (tag_name[0] == '\0') {
447 GST_DEBUG_OBJECT (demux, "end marker detected");
456 guint32 nb_elems = 0;
458 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
461 GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
463 if (!strcmp (tag_name, "times")) {
465 g_array_free (demux->times, TRUE);
467 demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
468 } else if (!strcmp (tag_name, "filepositions")) {
469 if (demux->filepositions) {
470 g_array_free (demux->filepositions, TRUE);
472 demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
476 guint8 elem_type = 0;
478 if (!gst_byte_reader_get_uint8 (reader, &elem_type))
486 if (!gst_byte_reader_get_float64_be (reader, &d))
489 GST_DEBUG_OBJECT (demux, "element is a double %f", d);
491 if (!strcmp (tag_name, "times") && demux->times) {
492 g_array_append_val (demux->times, d);
493 } else if (!strcmp (tag_name, "filepositions") &&
494 demux->filepositions) {
495 g_array_append_val (demux->filepositions, d);
500 GST_WARNING_OBJECT (demux, "unsupported array element type %d",
512 if (!gst_byte_reader_get_float64_be (reader, &d))
515 if (!gst_byte_reader_get_int16_be (reader, &i))
518 GST_DEBUG_OBJECT (demux,
519 "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
521 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
526 GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
540 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
542 GstFlowReturn ret = GST_FLOW_OK;
543 GstByteReader reader;
547 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 7, GST_FLOW_ERROR);
549 gst_buffer_map (buffer, &map, GST_MAP_READ);
550 gst_byte_reader_init (&reader, map.data, map.size);
552 gst_byte_reader_skip_unchecked (&reader, 7);
554 GST_LOG_OBJECT (demux, "parsing a script tag");
556 if (!gst_byte_reader_get_uint8 (&reader, &type))
561 gchar *function_name;
564 function_name = FLV_GET_STRING (&reader);
566 GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
568 if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
569 gboolean end_marker = FALSE;
570 GST_DEBUG_OBJECT (demux, "we have a metadata script object");
572 if (!gst_byte_reader_get_uint8 (&reader, &type)) {
573 g_free (function_name);
580 guint32 nb_elems = 0;
583 if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
584 g_free (function_name);
588 /* The number of elements is just a hint, some files have
589 nb_elements == 0 and actually contain items. */
590 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
593 /* fallthrough to read data */
597 while (!end_marker) {
599 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
601 if (G_UNLIKELY (!ok)) {
602 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
609 GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
610 g_free (function_name);
614 demux->push_tags = TRUE;
617 g_free (function_name);
619 if (demux->times && demux->filepositions) {
622 /* If an index was found, insert associations */
623 num = MIN (demux->times->len, demux->filepositions->len);
624 for (i = 0; i < num; i++) {
625 guint64 time, fileposition;
627 time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
628 fileposition = g_array_index (demux->filepositions, gdouble, i);
629 gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
632 demux->indexed = TRUE;
637 gst_buffer_unmap (buffer, &map);
643 have_group_id (GstFlvDemux * demux)
647 event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
649 if (gst_event_parse_group_id (event, &demux->group_id))
650 demux->have_group_id = TRUE;
652 demux->have_group_id = FALSE;
653 gst_event_unref (event);
654 } else if (!demux->have_group_id) {
655 demux->have_group_id = TRUE;
656 demux->group_id = gst_util_group_id_next ();
659 return demux->have_group_id;
663 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
664 guint32 rate, guint32 channels, guint32 width)
666 GstCaps *caps = NULL, *old_caps;
667 gchar *codec_name = NULL;
668 gboolean ret = FALSE;
669 guint adjusted_rate = rate;
675 caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
680 caps = gst_caps_new_simple ("audio/mpeg",
681 "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
682 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
687 GstAudioFormat format;
689 /* Assuming little endian for 0 (aka endianness of the
690 * system on which the file was created) as most people
691 * are probably using little endian machines */
692 format = gst_audio_format_build_integer ((width == 8) ? FALSE : TRUE,
693 G_LITTLE_ENDIAN, width, width);
695 caps = gst_caps_new_simple ("audio/x-raw",
696 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
697 "layout", G_TYPE_STRING, "interleaved", NULL);
703 caps = gst_caps_new_empty_simple ("audio/x-nellymoser");
708 if (!demux->audio_codec_data) {
709 GST_DEBUG_OBJECT (demux, "don't have AAC codec data yet");
714 gst_buffer_map (demux->audio_codec_data, &map, GST_MAP_READ);
716 /* use codec-data to extract and verify samplerate */
720 freq_index = GST_READ_UINT16_BE (map.data);
721 freq_index = (freq_index & 0x0780) >> 7;
723 gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
725 if (adjusted_rate && (rate != adjusted_rate)) {
726 GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
729 adjusted_rate = rate;
732 gst_buffer_unmap (demux->audio_codec_data, &map);
734 caps = gst_caps_new_simple ("audio/mpeg",
735 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
736 "stream-format", G_TYPE_STRING, "raw", NULL);
740 caps = gst_caps_new_empty_simple ("audio/x-alaw");
743 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
747 GValue streamheader = G_VALUE_INIT;
748 GValue value = G_VALUE_INIT;
750 GstStructure *structure;
753 caps = gst_caps_new_empty_simple ("audio/x-speex");
754 structure = gst_caps_get_structure (caps, 0);
756 GST_DEBUG_OBJECT (demux, "generating speex header");
758 /* Speex decoder expects streamheader to be { [header], [comment] } */
759 g_value_init (&streamheader, GST_TYPE_ARRAY);
762 gst_byte_writer_init_with_size (&w, 80, TRUE);
763 gst_byte_writer_put_data (&w, (guint8 *) "Speex ", 8);
764 gst_byte_writer_put_data (&w, (guint8 *) "1.1.12", 7);
765 gst_byte_writer_fill (&w, 0, 13);
766 gst_byte_writer_put_uint32_le (&w, 1); /* version */
767 gst_byte_writer_put_uint32_le (&w, 80); /* header_size */
768 gst_byte_writer_put_uint32_le (&w, 16000); /* rate */
769 gst_byte_writer_put_uint32_le (&w, 1); /* mode: Wideband */
770 gst_byte_writer_put_uint32_le (&w, 4); /* mode_bitstream_version */
771 gst_byte_writer_put_uint32_le (&w, 1); /* nb_channels: 1 */
772 gst_byte_writer_put_uint32_le (&w, -1); /* bitrate */
773 gst_byte_writer_put_uint32_le (&w, 0x50); /* frame_size */
774 gst_byte_writer_put_uint32_le (&w, 0); /* VBR */
775 gst_byte_writer_put_uint32_le (&w, 1); /* frames_per_packet */
776 gst_byte_writer_put_uint32_le (&w, 0); /* extra_headers */
777 gst_byte_writer_put_uint32_le (&w, 0); /* reserved1 */
778 gst_byte_writer_put_uint32_le (&w, 0); /* reserved2 */
779 g_assert (gst_byte_writer_get_size (&w) == 80);
781 g_value_init (&value, GST_TYPE_BUFFER);
782 g_value_take_boxed (&value, gst_byte_writer_reset_and_get_buffer (&w));
783 gst_value_array_append_value (&streamheader, &value);
784 g_value_unset (&value);
787 g_value_init (&value, GST_TYPE_BUFFER);
788 buf = gst_buffer_new_wrapped (g_memdup ("No comments", 12), 12);
789 g_value_take_boxed (&value, buf);
790 gst_value_array_append_value (&streamheader, &value);
791 g_value_unset (&value);
793 gst_structure_take_value (structure, "streamheader", &streamheader);
796 adjusted_rate = 16000;
800 GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
804 if (G_UNLIKELY (!caps)) {
805 GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
809 gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
810 "channels", G_TYPE_INT, channels, NULL);
812 if (demux->audio_codec_data) {
813 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
814 demux->audio_codec_data, NULL);
817 old_caps = gst_pad_get_current_caps (demux->audio_pad);
820 gst_pad_create_stream_id (demux->audio_pad, GST_ELEMENT_CAST (demux),
823 event = gst_event_new_stream_start (stream_id);
824 if (have_group_id (demux))
825 gst_event_set_group_id (event, demux->group_id);
826 gst_pad_push_event (demux->audio_pad, event);
829 if (!old_caps || !gst_caps_is_equal (old_caps, caps))
830 ret = gst_pad_set_caps (demux->audio_pad, caps);
835 gst_caps_unref (old_caps);
838 if (G_LIKELY (ret)) {
839 /* Store the caps we got from tags */
840 demux->audio_codec_tag = codec_tag;
842 demux->channels = channels;
843 demux->width = width;
846 codec_name = gst_pb_utils_get_codec_description (caps);
849 if (demux->taglist == NULL)
850 demux->taglist = gst_tag_list_new_empty ();
851 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
852 GST_TAG_AUDIO_CODEC, codec_name, NULL);
856 GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
857 GST_PTR_FORMAT, caps);
859 GST_DEBUG_OBJECT (demux->audio_pad, "delayed setting caps");
862 GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
863 GST_PTR_FORMAT, caps);
867 gst_caps_unref (caps);
874 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
878 if (demux->audio_pad)
879 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
881 if (demux->video_pad)
882 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
884 gst_event_unref (event);
890 gst_flv_demux_push_tags (GstFlvDemux * demux)
892 if (demux->has_audio && !demux->audio_pad) {
893 GST_DEBUG_OBJECT (demux,
894 "Waiting for audio stream pad to come up before we can push tags");
897 if (demux->has_video && !demux->video_pad) {
898 GST_DEBUG_OBJECT (demux,
899 "Waiting for video stream pad to come up before we can push tags");
902 if (demux->taglist) {
903 GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
905 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
906 gst_flv_demux_push_src_event (demux, gst_event_new_tag (demux->taglist));
907 demux->taglist = gst_tag_list_new_empty ();
908 demux->push_tags = FALSE;
913 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 dts, gboolean discont,
914 guint32 * last, GstClockTime * offset)
916 gboolean ret = FALSE;
917 gint32 ddts = dts - *last;
918 if (!discont && ddts <= -RESYNC_THRESHOLD) {
919 /* Theoretically, we should use substract the duration of the last buffer,
920 but this demuxer sends no durations on buffers, not sure if it cannot
921 know, or just does not care to calculate. */
922 *offset -= ddts * GST_MSECOND;
923 GST_WARNING_OBJECT (demux,
924 "Large dts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
925 GST_TIME_FORMAT "", ddts, GST_TIME_ARGS (*offset));
935 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
937 GstFlowReturn ret = GST_FLOW_OK;
938 guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
939 guint32 codec_data = 0, pts_ext = 0;
945 GST_LOG_OBJECT (demux, "parsing an audio tag");
947 if (G_UNLIKELY (!demux->audio_pad && demux->no_more_pads)) {
948 #ifndef GST_DISABLE_DEBUG
949 if (G_UNLIKELY (!demux->no_audio_warned)) {
950 GST_WARNING_OBJECT (demux,
951 "Signaled no-more-pads already but had no audio pad -- ignoring");
952 demux->no_audio_warned = TRUE;
958 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
961 /* Error out on tags with too small headers */
962 if (gst_buffer_get_size (buffer) < 11) {
963 GST_ERROR_OBJECT (demux, "Too small tag size (%" G_GSIZE_FORMAT ")",
964 gst_buffer_get_size (buffer));
965 return GST_FLOW_ERROR;
968 gst_buffer_map (buffer, &map, GST_MAP_READ);
971 /* Grab information about audio tag */
972 pts = GST_READ_UINT24_BE (data);
973 /* read the pts extension to 32 bits integer */
974 pts_ext = GST_READ_UINT8 (data + 3);
976 pts |= pts_ext << 24;
978 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
979 data[2], data[3], pts);
981 /* Skip the stream id and go directly to the flags */
982 flags = GST_READ_UINT8 (data + 7);
984 /* Silently skip buffers with no data */
997 if ((flags & 0x0C) == 0x0C) {
999 } else if ((flags & 0x0C) == 0x08) {
1001 } else if ((flags & 0x0C) == 0x04) {
1005 codec_tag = flags >> 4;
1006 if (codec_tag == 10) { /* AAC has an extra byte for packet type */
1012 /* codec tags with special rates */
1013 if (codec_tag == 5 || codec_tag == 14)
1015 else if (codec_tag == 4)
1018 GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
1019 "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
1022 /* If we don't have our audio pad created, then create it. */
1023 if (G_UNLIKELY (!demux->audio_pad)) {
1026 gst_pad_new_from_template (gst_element_class_get_pad_template
1027 (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
1028 if (G_UNLIKELY (!demux->audio_pad)) {
1029 GST_WARNING_OBJECT (demux, "failed creating audio pad");
1030 ret = GST_FLOW_ERROR;
1034 /* Set functions on the pad */
1035 gst_pad_set_query_function (demux->audio_pad,
1036 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1037 gst_pad_set_event_function (demux->audio_pad,
1038 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1040 gst_pad_use_fixed_caps (demux->audio_pad);
1042 /* Make it active */
1043 gst_pad_set_active (demux->audio_pad, TRUE);
1045 /* Negotiate caps */
1046 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1048 gst_object_unref (demux->audio_pad);
1049 demux->audio_pad = NULL;
1050 ret = GST_FLOW_ERROR;
1053 #ifndef GST_DISABLE_GST_DEBUG
1057 caps = gst_pad_get_current_caps (demux->audio_pad);
1058 GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
1061 gst_caps_unref (caps);
1065 /* We need to set caps before adding */
1066 gst_element_add_pad (GST_ELEMENT (demux),
1067 gst_object_ref (demux->audio_pad));
1068 gst_flow_combiner_add_pad (demux->flowcombiner, demux->audio_pad);
1070 /* We only emit no more pads when we have audio and video. Indeed we can
1071 * not trust the FLV header to tell us if there will be only audio or
1072 * only video and we would just break discovery of some files */
1073 if (demux->audio_pad && demux->video_pad) {
1074 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1075 gst_element_no_more_pads (GST_ELEMENT (demux));
1076 demux->no_more_pads = TRUE;
1077 demux->push_tags = TRUE;
1081 /* Check if caps have changed */
1082 if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
1083 codec_tag != demux->audio_codec_tag || width != demux->width)) {
1084 GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
1086 gst_buffer_replace (&demux->audio_codec_data, NULL);
1088 /* Negotiate caps */
1089 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1091 ret = GST_FLOW_ERROR;
1096 /* Push taglist if present */
1097 if (G_UNLIKELY (demux->push_tags))
1098 gst_flv_demux_push_tags (demux);
1100 /* Check if we have anything to push */
1101 if (demux->tag_data_size <= codec_data) {
1102 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1106 /* Create buffer from pad */
1107 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1108 7 + codec_data, demux->tag_data_size - codec_data);
1110 if (demux->audio_codec_tag == 10) {
1111 guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
1113 switch (aac_packet_type) {
1116 /* AudioSpecificConfig data */
1117 GST_LOG_OBJECT (demux, "got an AAC codec data packet");
1118 if (demux->audio_codec_data) {
1119 gst_buffer_unref (demux->audio_codec_data);
1121 demux->audio_codec_data = outbuf;
1122 /* Use that buffer data in the caps */
1123 gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels, width);
1127 if (!demux->audio_codec_data) {
1128 GST_ERROR_OBJECT (demux, "got AAC audio packet before codec data");
1130 gst_buffer_unref (outbuf);
1133 /* AAC raw packet */
1134 GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
1137 GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
1142 /* detect (and deem to be resyncs) large pts gaps */
1143 if (gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
1144 &demux->last_audio_pts, &demux->audio_time_offset)) {
1145 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
1148 /* Fill buffer with data */
1149 GST_BUFFER_PTS (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
1150 GST_BUFFER_DTS (outbuf) = GST_BUFFER_PTS (outbuf);
1151 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1152 GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
1153 GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
1155 if (demux->duration == GST_CLOCK_TIME_NONE ||
1156 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1157 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1159 /* Only add audio frames to the index if we have no video,
1160 * and if the index is not yet complete */
1161 if (!demux->has_video && !demux->indexed) {
1162 gst_flv_demux_parse_and_add_index_entry (demux,
1163 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
1166 if (G_UNLIKELY (demux->audio_need_discont)) {
1167 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1168 demux->audio_need_discont = FALSE;
1171 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1173 /* Do we need a newsegment event ? */
1174 if (G_UNLIKELY (demux->audio_need_segment)) {
1175 if (!demux->new_seg_event) {
1176 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1177 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1178 GST_TIME_ARGS (demux->segment.position),
1179 GST_TIME_ARGS (demux->segment.stop));
1180 demux->segment.start = demux->segment.time = demux->segment.position;
1181 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1183 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1186 gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1188 demux->audio_need_segment = FALSE;
1191 GST_LOG_OBJECT (demux,
1192 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1193 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1194 gst_buffer_get_size (outbuf),
1195 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1196 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1198 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1199 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1201 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1202 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1205 if (G_UNLIKELY (!demux->no_more_pads
1206 && (GST_CLOCK_DIFF (demux->audio_start,
1207 GST_BUFFER_TIMESTAMP (outbuf)) > NO_MORE_PADS_THRESHOLD))) {
1208 GST_DEBUG_OBJECT (demux,
1209 "Signalling no-more-pads because no video stream was found"
1210 " after 6 seconds of audio");
1211 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1212 demux->no_more_pads = TRUE;
1213 demux->push_tags = TRUE;
1216 /* Push downstream */
1217 ret = gst_pad_push (demux->audio_pad, outbuf);
1219 if (G_UNLIKELY (ret != GST_FLOW_OK) &&
1220 demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1221 demux->segment.position > demux->segment.stop) {
1222 /* In reverse playback we can get a GST_FLOW_EOS when
1223 * we are at the end of the segment, so we just need to jump
1224 * back to the previous section. */
1225 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1226 demux->audio_done = TRUE;
1231 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner,
1232 demux->audio_pad, ret);
1235 gst_buffer_unmap (buffer, &map);
1241 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1243 gboolean ret = FALSE;
1244 GstCaps *caps = NULL, *old_caps;
1245 gchar *codec_name = NULL;
1249 /* Generate caps for that pad */
1250 switch (codec_tag) {
1253 gst_caps_new_simple ("video/x-flash-video", "flvversion", G_TYPE_INT,
1257 caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1260 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1263 caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1266 if (!demux->video_codec_data) {
1267 GST_DEBUG_OBJECT (demux, "don't have h264 codec data yet");
1272 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1276 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1279 if (G_UNLIKELY (!caps)) {
1280 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1284 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1285 demux->par_x, demux->par_y, NULL);
1287 if (G_LIKELY (demux->w)) {
1288 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1291 if (G_LIKELY (demux->h)) {
1292 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1295 if (G_LIKELY (demux->framerate)) {
1296 gint num = 0, den = 0;
1298 gst_video_guess_framerate (GST_SECOND / demux->framerate, &num, &den);
1299 GST_DEBUG_OBJECT (demux->video_pad,
1300 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1303 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1306 if (demux->video_codec_data) {
1307 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1308 demux->video_codec_data, NULL);
1311 old_caps = gst_pad_get_current_caps (demux->video_pad);
1314 gst_pad_create_stream_id (demux->video_pad, GST_ELEMENT_CAST (demux),
1316 event = gst_event_new_stream_start (stream_id);
1319 if (have_group_id (demux))
1320 gst_event_set_group_id (event, demux->group_id);
1321 gst_pad_push_event (demux->video_pad, event);
1324 if (!old_caps || !gst_caps_is_equal (old_caps, caps))
1325 ret = gst_pad_set_caps (demux->video_pad, caps);
1330 gst_caps_unref (old_caps);
1333 if (G_LIKELY (ret)) {
1334 /* Store the caps we have set */
1335 demux->video_codec_tag = codec_tag;
1338 codec_name = gst_pb_utils_get_codec_description (caps);
1341 if (demux->taglist == NULL)
1342 demux->taglist = gst_tag_list_new_empty ();
1343 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1344 GST_TAG_VIDEO_CODEC, codec_name, NULL);
1345 g_free (codec_name);
1348 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1349 GST_PTR_FORMAT, caps);
1351 GST_DEBUG_OBJECT (demux->video_pad, "delayed setting caps");
1354 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1355 GST_PTR_FORMAT, caps);
1359 gst_caps_unref (caps);
1365 static GstFlowReturn
1366 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1368 GstFlowReturn ret = GST_FLOW_OK;
1369 guint32 dts = 0, codec_data = 1, dts_ext = 0;
1371 gboolean keyframe = FALSE;
1372 guint8 flags = 0, codec_tag = 0;
1377 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1380 GST_LOG_OBJECT (demux, "parsing a video tag");
1383 (!demux->video_pad && demux->no_more_pads) {
1384 #ifndef GST_DISABLE_DEBUG
1386 (!demux->no_video_warned) {
1387 GST_WARNING_OBJECT (demux,
1388 "Signaled no-more-pads already but had no video pad -- ignoring");
1389 demux->no_video_warned = TRUE;
1395 if (gst_buffer_get_size (buffer) < 12) {
1396 GST_ERROR_OBJECT (demux, "Too small tag size");
1397 return GST_FLOW_ERROR;
1400 gst_buffer_map (buffer, &map, GST_MAP_READ);
1403 /* Grab information about video tag */
1404 dts = GST_READ_UINT24_BE (data);
1405 /* read the dts extension to 32 bits integer */
1406 dts_ext = GST_READ_UINT8 (data + 3);
1408 dts |= dts_ext << 24;
1410 GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1411 data[2], data[3], dts);
1413 /* Skip the stream id and go directly to the flags */
1414 flags = GST_READ_UINT8 (data + 7);
1417 if ((flags >> 4) == 1) {
1421 codec_tag = flags & 0x0F;
1422 if (codec_tag == 4 || codec_tag == 5) {
1424 } else if (codec_tag == 7) {
1427 cts = GST_READ_UINT24_BE (data + 9);
1428 cts = (cts + 0xff800000) ^ 0xff800000;
1430 GST_LOG_OBJECT (demux, "got cts %d", cts);
1433 GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1434 "(flags %02X)", codec_tag, keyframe, flags);
1436 /* If we don't have our video pad created, then create it. */
1437 if (G_UNLIKELY (!demux->video_pad)) {
1439 gst_pad_new_from_template (gst_element_class_get_pad_template
1440 (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1441 if (G_UNLIKELY (!demux->video_pad)) {
1442 GST_WARNING_OBJECT (demux, "failed creating video pad");
1443 ret = GST_FLOW_ERROR;
1447 /* Set functions on the pad */
1448 gst_pad_set_query_function (demux->video_pad,
1449 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1450 gst_pad_set_event_function (demux->video_pad,
1451 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1453 gst_pad_use_fixed_caps (demux->video_pad);
1455 /* Make it active */
1456 gst_pad_set_active (demux->video_pad, TRUE);
1458 /* Needs to be active before setting caps */
1459 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1460 gst_object_unref (demux->video_pad);
1461 demux->video_pad = NULL;
1462 ret = GST_FLOW_ERROR;
1466 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1467 * metadata tag that would come later and trigger a caps change */
1468 demux->got_par = FALSE;
1470 #ifndef GST_DISABLE_GST_DEBUG
1474 caps = gst_pad_get_current_caps (demux->video_pad);
1475 GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1478 gst_caps_unref (caps);
1482 /* We need to set caps before adding */
1483 gst_element_add_pad (GST_ELEMENT (demux),
1484 gst_object_ref (demux->video_pad));
1485 gst_flow_combiner_add_pad (demux->flowcombiner, demux->video_pad);
1487 /* We only emit no more pads when we have audio and video. Indeed we can
1488 * not trust the FLV header to tell us if there will be only audio or
1489 * only video and we would just break discovery of some files */
1490 if (demux->audio_pad && demux->video_pad) {
1491 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1492 gst_element_no_more_pads (GST_ELEMENT (demux));
1493 demux->no_more_pads = TRUE;
1494 demux->push_tags = TRUE;
1498 /* Check if caps have changed */
1499 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1500 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1501 gst_buffer_replace (&demux->video_codec_data, NULL);
1503 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1504 ret = GST_FLOW_ERROR;
1508 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1509 * metadata tag that would come later and trigger a caps change */
1510 demux->got_par = FALSE;
1513 /* Push taglist if present */
1514 if (G_UNLIKELY (demux->push_tags))
1515 gst_flv_demux_push_tags (demux);
1517 /* Check if we have anything to push */
1518 if (demux->tag_data_size <= codec_data) {
1519 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1523 /* Create buffer from pad */
1524 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1525 7 + codec_data, demux->tag_data_size - codec_data);
1527 if (demux->video_codec_tag == 7) {
1528 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1530 switch (avc_packet_type) {
1533 /* AVCDecoderConfigurationRecord data */
1534 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1535 if (demux->video_codec_data) {
1536 gst_buffer_unref (demux->video_codec_data);
1538 demux->video_codec_data = outbuf;
1539 /* Use that buffer data in the caps */
1540 gst_flv_demux_video_negotiate (demux, codec_tag);
1544 /* H.264 NALU packet */
1545 if (!demux->video_codec_data) {
1546 GST_ERROR_OBJECT (demux, "got H.264 video packet before codec data");
1548 gst_buffer_unref (outbuf);
1551 GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1554 GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1559 /* detect (and deem to be resyncs) large dts gaps */
1560 if (gst_flv_demux_update_resync (demux, dts, demux->video_need_discont,
1561 &demux->last_video_dts, &demux->video_time_offset)) {
1562 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
1565 /* Fill buffer with data */
1566 GST_LOG_OBJECT (demux, "dts %u pts %u cts %d", dts, dts + cts, cts);
1568 GST_BUFFER_PTS (outbuf) =
1569 (dts + cts) * GST_MSECOND + demux->video_time_offset;
1570 GST_BUFFER_DTS (outbuf) = dts * GST_MSECOND + demux->video_time_offset;
1571 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1572 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1573 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1575 if (demux->duration == GST_CLOCK_TIME_NONE ||
1576 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1577 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1580 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1582 if (!demux->indexed) {
1583 gst_flv_demux_parse_and_add_index_entry (demux,
1584 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1587 if (G_UNLIKELY (demux->video_need_discont)) {
1588 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1589 demux->video_need_discont = FALSE;
1592 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1594 /* Do we need a newsegment event ? */
1595 if (G_UNLIKELY (demux->video_need_segment)) {
1596 if (!demux->new_seg_event) {
1597 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1598 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1599 GST_TIME_ARGS (demux->segment.position),
1600 GST_TIME_ARGS (demux->segment.stop));
1601 demux->segment.start = demux->segment.time = demux->segment.position;
1602 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1604 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1607 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1609 demux->video_need_segment = FALSE;
1612 GST_LOG_OBJECT (demux,
1613 "pushing %" G_GSIZE_FORMAT " bytes buffer at dts %" GST_TIME_FORMAT
1614 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1615 ", keyframe (%d)", gst_buffer_get_size (outbuf),
1616 GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
1617 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1620 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1621 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1623 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1624 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1627 if (G_UNLIKELY (!demux->no_more_pads
1628 && (GST_CLOCK_DIFF (demux->video_start,
1629 GST_BUFFER_TIMESTAMP (outbuf)) > NO_MORE_PADS_THRESHOLD))) {
1630 GST_DEBUG_OBJECT (demux,
1631 "Signalling no-more-pads because no audio stream was found"
1632 " after 6 seconds of video");
1633 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1634 demux->no_more_pads = TRUE;
1635 demux->push_tags = TRUE;
1638 /* Push downstream */
1639 ret = gst_pad_push (demux->video_pad, outbuf);
1641 if (G_UNLIKELY (ret != GST_FLOW_OK) &&
1642 demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1643 demux->segment.position > demux->segment.stop) {
1644 /* In reverse playback we can get a GST_FLOW_EOS when
1645 * we are at the end of the segment, so we just need to jump
1646 * back to the previous section. */
1647 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1648 demux->video_done = TRUE;
1653 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner,
1654 demux->video_pad, ret);
1657 gst_buffer_unmap (buffer, &map);
1662 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1663 GstBuffer * buffer, size_t * tag_size)
1665 guint32 dts = 0, dts_ext = 0;
1666 guint32 tag_data_size;
1668 gboolean keyframe = TRUE;
1669 GstClockTime ret = GST_CLOCK_TIME_NONE;
1674 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1675 GST_CLOCK_TIME_NONE);
1677 gst_buffer_map (buffer, &map, GST_MAP_READ);
1683 if (type != 9 && type != 8 && type != 18) {
1684 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1689 demux->has_video = TRUE;
1691 demux->has_audio = TRUE;
1693 tag_data_size = GST_READ_UINT24_BE (data + 1);
1695 if (size >= tag_data_size + 11 + 4) {
1696 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1697 GST_WARNING_OBJECT (demux, "Invalid tag size");
1703 *tag_size = tag_data_size + 11 + 4;
1707 GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X", data[0], data[1],
1710 /* Grab timestamp of tag tag */
1711 dts = GST_READ_UINT24_BE (data);
1712 /* read the dts extension to 32 bits integer */
1713 dts_ext = GST_READ_UINT8 (data + 3);
1715 dts |= dts_ext << 24;
1720 keyframe = ((data[0] >> 4) == 1);
1723 ret = dts * GST_MSECOND;
1724 GST_LOG_OBJECT (demux, "dts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1726 if (index && !demux->indexed && (type == 9 || (type == 8
1727 && !demux->has_video))) {
1728 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1732 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1733 demux->duration = ret;
1736 gst_buffer_unmap (buffer, &map);
1740 static GstFlowReturn
1741 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1743 GstFlowReturn ret = GST_FLOW_OK;
1744 guint8 tag_type = 0;
1747 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1749 gst_buffer_map (buffer, &map, GST_MAP_READ);
1751 tag_type = map.data[0];
1753 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1754 * 4 bytes of previous tag size */
1755 demux->tag_data_size = GST_READ_UINT24_BE (map.data + 1);
1756 demux->tag_size = demux->tag_data_size + 11;
1758 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1759 demux->tag_data_size);
1761 gst_buffer_unmap (buffer, &map);
1765 demux->state = FLV_STATE_TAG_VIDEO;
1766 demux->has_video = TRUE;
1769 demux->state = FLV_STATE_TAG_AUDIO;
1770 demux->has_audio = TRUE;
1773 demux->state = FLV_STATE_TAG_SCRIPT;
1776 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1777 demux->state = FLV_STATE_SKIP;
1783 static GstFlowReturn
1784 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1786 GstFlowReturn ret = GST_FLOW_OK;
1789 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1791 gst_buffer_map (buffer, &map, GST_MAP_READ);
1793 /* Check for the FLV tag */
1794 if (map.data[0] == 'F' && map.data[1] == 'L' && map.data[2] == 'V') {
1795 GST_DEBUG_OBJECT (demux, "FLV header detected");
1797 if (G_UNLIKELY (demux->strict)) {
1798 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1804 if (map.data[3] == '1') {
1805 GST_DEBUG_OBJECT (demux, "FLV version 1 detected");
1807 if (G_UNLIKELY (demux->strict)) {
1808 GST_WARNING_OBJECT (demux, "invalid header version detected");
1815 /* Now look at audio/video flags */
1817 guint8 flags = map.data[4];
1819 demux->has_video = demux->has_audio = FALSE;
1822 GST_DEBUG_OBJECT (demux, "there is a video stream");
1823 demux->has_video = TRUE;
1826 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1827 demux->has_audio = TRUE;
1831 /* do a one-time seekability check */
1832 gst_flv_demux_check_seekability (demux);
1834 /* We don't care about the rest */
1835 demux->need_header = FALSE;
1838 gst_buffer_unmap (buffer, &map);
1844 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1846 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1848 gst_adapter_clear (demux->adapter);
1850 demux->audio_need_discont = TRUE;
1851 demux->video_need_discont = TRUE;
1853 demux->flushing = FALSE;
1855 /* Only in push mode and if we're not during a seek */
1856 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1857 /* After a flush we expect a tag_type */
1858 demux->state = FLV_STATE_TAG_TYPE;
1859 /* We reset the offset and will get one from first push */
1865 gst_flv_demux_cleanup (GstFlvDemux * demux)
1867 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1869 demux->state = FLV_STATE_HEADER;
1871 demux->have_group_id = FALSE;
1872 demux->group_id = G_MAXUINT;
1874 demux->flushing = FALSE;
1875 demux->need_header = TRUE;
1876 demux->audio_need_segment = TRUE;
1877 demux->video_need_segment = TRUE;
1878 demux->audio_need_discont = TRUE;
1879 demux->video_need_discont = TRUE;
1881 demux->has_audio = FALSE;
1882 demux->has_video = FALSE;
1883 demux->push_tags = FALSE;
1884 demux->got_par = FALSE;
1886 demux->indexed = FALSE;
1887 demux->upstream_seekable = FALSE;
1888 demux->file_size = 0;
1890 demux->index_max_pos = 0;
1891 demux->index_max_time = 0;
1893 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1894 demux->last_audio_pts = demux->last_video_dts = 0;
1895 demux->audio_time_offset = demux->video_time_offset = 0;
1897 demux->no_more_pads = FALSE;
1899 #ifndef GST_DISABLE_DEBUG
1900 demux->no_audio_warned = FALSE;
1901 demux->no_video_warned = FALSE;
1904 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1906 demux->w = demux->h = 0;
1907 demux->framerate = 0.0;
1908 demux->par_x = demux->par_y = 1;
1909 demux->video_offset = 0;
1910 demux->audio_offset = 0;
1911 demux->offset = demux->cur_tag_offset = 0;
1912 demux->tag_size = demux->tag_data_size = 0;
1913 demux->duration = GST_CLOCK_TIME_NONE;
1915 if (demux->new_seg_event) {
1916 gst_event_unref (demux->new_seg_event);
1917 demux->new_seg_event = NULL;
1920 gst_adapter_clear (demux->adapter);
1922 if (demux->audio_codec_data) {
1923 gst_buffer_unref (demux->audio_codec_data);
1924 demux->audio_codec_data = NULL;
1927 if (demux->video_codec_data) {
1928 gst_buffer_unref (demux->video_codec_data);
1929 demux->video_codec_data = NULL;
1932 if (demux->audio_pad) {
1933 gst_flow_combiner_remove_pad (demux->flowcombiner, demux->audio_pad);
1934 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1935 gst_object_unref (demux->audio_pad);
1936 demux->audio_pad = NULL;
1939 if (demux->video_pad) {
1940 gst_flow_combiner_remove_pad (demux->flowcombiner, demux->video_pad);
1941 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1942 gst_object_unref (demux->video_pad);
1943 demux->video_pad = NULL;
1947 g_array_free (demux->times, TRUE);
1948 demux->times = NULL;
1951 if (demux->filepositions) {
1952 g_array_free (demux->filepositions, TRUE);
1953 demux->filepositions = NULL;
1958 * Create and push a flushing seek event upstream
1961 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1966 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1969 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1970 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1971 GST_SEEK_TYPE_NONE, -1);
1973 res = gst_pad_push_event (demux->sinkpad, event);
1976 demux->offset = offset;
1980 static GstFlowReturn
1981 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1983 GstFlowReturn ret = GST_FLOW_OK;
1984 GstFlvDemux *demux = NULL;
1986 demux = GST_FLV_DEMUX (parent);
1988 GST_LOG_OBJECT (demux,
1989 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
1990 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
1991 GST_BUFFER_OFFSET (buffer));
1993 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1994 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1995 demux->state = FLV_STATE_HEADER;
1999 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
2000 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
2001 demux->offset = GST_BUFFER_OFFSET (buffer);
2004 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
2005 GST_DEBUG_OBJECT (demux, "Discontinuity");
2006 gst_adapter_clear (demux->adapter);
2009 gst_adapter_push (demux->adapter, buffer);
2011 if (demux->seeking) {
2012 demux->state = FLV_STATE_SEEK;
2013 GST_OBJECT_LOCK (demux);
2014 demux->seeking = FALSE;
2015 GST_OBJECT_UNLOCK (demux);
2019 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2020 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
2024 if (G_UNLIKELY (demux->flushing)) {
2025 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
2026 ret = GST_FLOW_FLUSHING;
2030 switch (demux->state) {
2031 case FLV_STATE_HEADER:
2033 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
2036 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
2038 ret = gst_flv_demux_parse_header (demux, buffer);
2040 gst_buffer_unref (buffer);
2041 demux->offset += FLV_HEADER_SIZE;
2043 demux->state = FLV_STATE_TAG_TYPE;
2049 case FLV_STATE_TAG_TYPE:
2051 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
2054 /* Remember the tag offset in bytes */
2055 demux->cur_tag_offset = demux->offset;
2057 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
2059 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2061 gst_buffer_unref (buffer);
2062 demux->offset += FLV_TAG_TYPE_SIZE;
2064 /* last tag is not an index => no index/don't know where the index is
2065 * seek back to the beginning */
2066 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
2074 case FLV_STATE_TAG_VIDEO:
2076 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2079 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2081 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2083 gst_buffer_unref (buffer);
2084 demux->offset += demux->tag_size;
2086 demux->state = FLV_STATE_TAG_TYPE;
2092 case FLV_STATE_TAG_AUDIO:
2094 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2097 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2099 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2101 gst_buffer_unref (buffer);
2102 demux->offset += demux->tag_size;
2104 demux->state = FLV_STATE_TAG_TYPE;
2110 case FLV_STATE_TAG_SCRIPT:
2112 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2115 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2117 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2119 gst_buffer_unref (buffer);
2120 demux->offset += demux->tag_size;
2122 demux->state = FLV_STATE_TAG_TYPE;
2124 /* if there's a seek event we're here for the index so if we don't have it
2125 * we seek back to the beginning */
2126 if (demux->seek_event) {
2128 demux->state = FLV_STATE_SEEK;
2138 case FLV_STATE_SEEK:
2144 if (!demux->indexed) {
2145 if (demux->offset == demux->file_size - sizeof (guint32)) {
2146 guint64 seek_offset;
2149 data = gst_adapter_take (demux->adapter, 4);
2153 seek_offset = demux->file_size - sizeof (guint32) -
2154 GST_READ_UINT32_BE (data);
2157 GST_INFO_OBJECT (demux,
2158 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
2160 demux->state = FLV_STATE_TAG_TYPE;
2161 flv_demux_seek_to_offset (demux, seek_offset);
2167 GST_OBJECT_LOCK (demux);
2168 event = demux->seek_event;
2169 demux->seek_event = NULL;
2170 GST_OBJECT_UNLOCK (demux);
2172 /* calculate and perform seek */
2173 if (!flv_demux_handle_seek_push (demux, event))
2176 gst_event_unref (event);
2177 demux->state = FLV_STATE_TAG_TYPE;
2180 case FLV_STATE_SKIP:
2181 /* Skip unknown tags (set in _parse_tag_type()) */
2182 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2183 gst_adapter_flush (demux->adapter, demux->tag_size);
2184 demux->offset += demux->tag_size;
2185 demux->state = FLV_STATE_TAG_TYPE;
2191 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
2200 GST_OBJECT_LOCK (demux);
2201 demux->seeking = FALSE;
2202 gst_event_unref (demux->seek_event);
2203 demux->seek_event = NULL;
2204 GST_OBJECT_UNLOCK (demux);
2205 GST_WARNING_OBJECT (demux,
2206 "failed to find an index, seeking back to beginning");
2207 flv_demux_seek_to_offset (demux, 0);
2212 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2213 return GST_FLOW_ERROR;
2218 static GstFlowReturn
2219 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2220 guint size, GstBuffer ** buffer)
2224 ret = gst_pad_pull_range (pad, offset, size, buffer);
2225 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2226 GST_WARNING_OBJECT (demux,
2227 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2228 size, offset, gst_flow_get_name (ret));
2233 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2234 GST_WARNING_OBJECT (demux,
2235 "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
2236 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
2237 gst_buffer_unref (*buffer);
2246 static GstFlowReturn
2247 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2249 GstBuffer *buffer = NULL;
2250 GstFlowReturn ret = GST_FLOW_OK;
2252 /* Store tag offset */
2253 demux->cur_tag_offset = demux->offset;
2255 /* Get the first 4 bytes to identify tag type and size */
2256 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2257 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2260 /* Identify tag type */
2261 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2263 gst_buffer_unref (buffer);
2265 if (G_UNLIKELY (ret != GST_FLOW_OK))
2268 /* Jump over tag type + size */
2269 demux->offset += FLV_TAG_TYPE_SIZE;
2271 /* Pull the whole tag */
2273 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2274 demux->tag_size, &buffer)) != GST_FLOW_OK))
2277 switch (demux->state) {
2278 case FLV_STATE_TAG_VIDEO:
2279 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2281 case FLV_STATE_TAG_AUDIO:
2282 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2284 case FLV_STATE_TAG_SCRIPT:
2285 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2288 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2291 gst_buffer_unref (buffer);
2293 /* Jump over that part we've just parsed */
2294 demux->offset += demux->tag_size;
2296 /* Make sure we reinitialize the tag size */
2297 demux->tag_size = 0;
2299 /* Ready for the next tag */
2300 demux->state = FLV_STATE_TAG_TYPE;
2302 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2303 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2304 "neither video nor audio are linked");
2311 static GstFlowReturn
2312 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2314 GstBuffer *buffer = NULL;
2315 GstFlowReturn ret = GST_FLOW_OK;
2317 /* Get the first 9 bytes */
2318 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2319 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2322 ret = gst_flv_demux_parse_header (demux, buffer);
2324 gst_buffer_unref (buffer);
2326 /* Jump over the header now */
2327 demux->offset += FLV_HEADER_SIZE;
2328 demux->state = FLV_STATE_TAG_TYPE;
2335 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2338 demux->offset = offset;
2340 /* Tell all the stream we moved to a different position (discont) */
2341 demux->audio_need_discont = TRUE;
2342 demux->video_need_discont = TRUE;
2344 /* next section setup */
2345 demux->from_offset = -1;
2346 demux->audio_done = demux->video_done = FALSE;
2347 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2350 demux->from_offset = -1;
2351 demux->to_offset = G_MAXINT64;
2354 /* If we seeked at the beginning of the file parse the header again */
2355 if (G_UNLIKELY (!demux->offset)) {
2356 demux->state = FLV_STATE_HEADER;
2357 } else { /* or parse a tag */
2358 demux->state = FLV_STATE_TAG_TYPE;
2362 static GstFlowReturn
2363 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2365 GstFlowReturn ret = GST_FLOW_EOS;
2367 GstIndexEntry *entry = NULL;
2369 GST_DEBUG_OBJECT (demux,
2370 "terminated section started at offset %" G_GINT64_FORMAT,
2371 demux->from_offset);
2373 /* we are done if we got all audio and video */
2374 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2375 demux->audio_first_ts < demux->segment.start) &&
2376 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2377 demux->video_first_ts < demux->segment.start))
2380 if (demux->from_offset <= 0)
2383 GST_DEBUG_OBJECT (demux, "locating previous position");
2385 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2387 /* locate index entry before previous start position */
2389 entry = gst_index_get_assoc_entry (index, demux->index_id,
2390 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2391 GST_FORMAT_BYTES, demux->from_offset - 1);
2394 gint64 bytes = 0, time = 0;
2396 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2397 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2399 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2400 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2401 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2403 /* setup for next section */
2404 demux->to_offset = demux->from_offset;
2405 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2409 gst_object_unref (index);
2416 static GstFlowReturn
2417 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2423 GstClockTime tag_time;
2424 GstFlowReturn ret = GST_FLOW_OK;
2426 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2429 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2430 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2432 old_offset = demux->offset;
2433 demux->offset = pos;
2436 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2437 12, &buffer)) == GST_FLOW_OK) {
2439 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2441 gst_buffer_unref (buffer);
2444 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2447 demux->offset += tag_size;
2450 if (ret == GST_FLOW_EOS) {
2451 /* file ran out, so mark we have complete index */
2452 demux->indexed = TRUE;
2457 demux->offset = old_offset;
2463 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2465 gint64 ret = 0, offset;
2466 size_t tag_size, size;
2467 GstBuffer *buffer = NULL;
2470 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2474 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2475 if (G_UNLIKELY (offset < 4))
2479 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2483 gst_buffer_map (buffer, &map, GST_MAP_READ);
2484 tag_size = GST_READ_UINT32_BE (map.data);
2485 gst_buffer_unmap (buffer, &map);
2486 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2487 gst_buffer_unref (buffer);
2491 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2495 /* a consistency check */
2496 gst_buffer_map (buffer, &map, GST_MAP_READ);
2497 size = GST_READ_UINT24_BE (map.data + 1);
2498 if (size != tag_size - 11) {
2499 gst_buffer_unmap (buffer, &map);
2500 GST_DEBUG_OBJECT (demux,
2501 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2502 ", corrupt or truncated file", size, tag_size - 11);
2506 /* try to update duration with timestamp in any case */
2507 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2509 /* maybe get some more metadata */
2510 if (map.data[0] == 18) {
2511 gst_buffer_unmap (buffer, &map);
2512 gst_buffer_unref (buffer);
2514 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2516 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2518 gst_flv_demux_parse_tag_script (demux, buffer);
2520 gst_buffer_unmap (buffer, &map);
2525 gst_buffer_unref (buffer);
2531 gst_flv_demux_loop (GstPad * pad)
2533 GstFlvDemux *demux = NULL;
2534 GstFlowReturn ret = GST_FLOW_OK;
2536 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2539 switch (demux->state) {
2540 case FLV_STATE_TAG_TYPE:
2541 if (demux->from_offset == -1)
2542 demux->from_offset = demux->offset;
2543 ret = gst_flv_demux_pull_tag (pad, demux);
2544 /* if we have seen real data, we probably passed a possible metadata
2545 * header located at start. So if we do not yet have an index,
2546 * try to pick up metadata (index, duration) at the end */
2547 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2548 (demux->has_video || demux->has_audio)))
2549 demux->file_size = gst_flv_demux_get_metadata (demux);
2551 case FLV_STATE_DONE:
2554 case FLV_STATE_SEEK:
2555 /* seek issued with insufficient index;
2556 * scan for index in task thread from current maximum offset to
2557 * desired time and then perform seek */
2558 /* TODO maybe some buffering message or so to indicate scan progress */
2559 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2561 if (ret != GST_FLOW_OK)
2563 /* position and state arranged by seek,
2564 * also unrefs event */
2565 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2566 demux->seek_event = NULL;
2569 ret = gst_flv_demux_pull_header (pad, demux);
2570 /* index scans start after header */
2571 demux->index_max_pos = demux->offset;
2575 if (demux->segment.rate < 0.0) {
2576 /* check end of section */
2577 if ((gint64) demux->offset >= demux->to_offset ||
2578 demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2579 (demux->audio_done && demux->video_done))
2580 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2582 /* check EOS condition */
2583 if ((demux->segment.stop != -1) &&
2584 (demux->segment.position >= demux->segment.stop)) {
2589 /* pause if something went wrong or at end */
2590 if (G_UNLIKELY (ret != GST_FLOW_OK))
2593 gst_object_unref (demux);
2599 const gchar *reason = gst_flow_get_name (ret);
2601 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2602 gst_pad_pause_task (pad);
2604 if (ret == GST_FLOW_EOS) {
2605 /* handle end-of-stream/segment */
2606 /* so align our position with the end of it, if there is one
2607 * this ensures a subsequent will arrive at correct base/acc time */
2608 if (demux->segment.rate > 0.0 &&
2609 GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2610 demux->segment.position = demux->segment.stop;
2611 else if (demux->segment.rate < 0.0)
2612 demux->segment.position = demux->segment.start;
2614 /* perform EOS logic */
2615 if (!demux->no_more_pads) {
2616 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2617 demux->no_more_pads = TRUE;
2620 if (demux->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
2623 /* for segment playback we need to post when (in stream time)
2624 * we stopped, this is either stop (when set) or the duration. */
2625 if ((stop = demux->segment.stop) == -1)
2626 stop = demux->segment.duration;
2628 if (demux->segment.rate >= 0) {
2629 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2630 gst_element_post_message (GST_ELEMENT_CAST (demux),
2631 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2632 GST_FORMAT_TIME, stop));
2633 gst_flv_demux_push_src_event (demux,
2634 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2635 } else { /* Reverse playback */
2636 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2638 gst_element_post_message (GST_ELEMENT_CAST (demux),
2639 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2640 GST_FORMAT_TIME, demux->segment.start));
2641 gst_flv_demux_push_src_event (demux,
2642 gst_event_new_segment_done (GST_FORMAT_TIME,
2643 demux->segment.start));
2646 /* normal playback, send EOS to all linked pads */
2647 if (!demux->no_more_pads) {
2648 gst_element_no_more_pads (GST_ELEMENT (demux));
2649 demux->no_more_pads = TRUE;
2652 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2653 if (!demux->audio_pad && !demux->video_pad)
2654 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2655 ("Internal data stream error."), ("Got EOS before any data"));
2656 else if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2657 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2659 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2660 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2661 ("Internal data stream error."),
2662 ("stream stopped, reason %s", reason));
2663 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2665 gst_object_unref (demux);
2671 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment,
2672 GstSeekFlags seek_flags)
2677 GstIndexEntry *entry;
2679 g_return_val_if_fail (segment != NULL, 0);
2681 time = segment->position;
2683 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2686 /* Let's check if we have an index entry for that seek time */
2687 entry = gst_index_get_assoc_entry (index, demux->index_id,
2688 seek_flags & GST_SEEK_FLAG_SNAP_AFTER ?
2689 GST_INDEX_LOOKUP_AFTER : GST_INDEX_LOOKUP_BEFORE,
2690 GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, time);
2693 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2694 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2696 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2697 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2698 GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2700 /* Key frame seeking */
2701 if (seek_flags & GST_SEEK_FLAG_KEY_UNIT) {
2702 /* Adjust the segment so that the keyframe fits in */
2703 segment->start = segment->time = time;
2704 segment->position = time;
2707 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2708 GST_TIME_ARGS (segment->start));
2711 gst_object_unref (index);
2718 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2722 GstSeekType start_type, stop_type;
2725 gboolean update, flush, ret;
2726 GstSegment seeksegment;
2728 gst_event_parse_seek (event, &rate, &format, &flags,
2729 &start_type, &start, &stop_type, &stop);
2731 if (format != GST_FORMAT_TIME)
2734 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2736 /* Work on a copy until we are sure the seek succeeded. */
2737 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2739 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2742 /* Apply the seek to our segment */
2743 gst_segment_do_seek (&seeksegment, rate, format, flags,
2744 start_type, start, stop_type, stop, &update);
2746 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2749 if (flush || seeksegment.position != demux->segment.position) {
2750 /* Do the actual seeking */
2751 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment, flags);
2753 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2754 G_GUINT64_FORMAT, offset);
2755 ret = gst_pad_push_event (demux->sinkpad,
2756 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2757 flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2758 offset, GST_SEEK_TYPE_NONE, 0));
2759 if (G_UNLIKELY (!ret)) {
2760 GST_WARNING_OBJECT (demux, "upstream seek failed");
2763 gst_flow_combiner_reset (demux->flowcombiner);
2764 /* Tell all the stream we moved to a different position (discont) */
2765 demux->audio_need_discont = TRUE;
2766 demux->video_need_discont = TRUE;
2772 /* Ok seek succeeded, take the newly configured segment */
2773 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2775 /* Tell all the stream a new segment is needed */
2776 demux->audio_need_segment = TRUE;
2777 demux->video_need_segment = TRUE;
2778 /* Clean any potential newsegment event kept for the streams. The first
2779 * stream needing a new segment will create a new one. */
2780 if (G_UNLIKELY (demux->new_seg_event)) {
2781 gst_event_unref (demux->new_seg_event);
2782 demux->new_seg_event = NULL;
2784 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2785 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2786 GST_TIME_ARGS (demux->segment.start),
2787 GST_TIME_ARGS (demux->segment.stop));
2788 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2789 gst_event_unref (event);
2791 ret = gst_pad_push_event (demux->sinkpad, event);
2799 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2800 gst_event_unref (event);
2806 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2810 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2812 if (format != GST_FORMAT_TIME) {
2813 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2814 gst_event_unref (event);
2818 /* First try upstream */
2819 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2820 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2821 gst_event_unref (event);
2825 if (!demux->indexed) {
2826 guint64 seek_offset = 0;
2827 gboolean building_index;
2829 GST_OBJECT_LOCK (demux);
2830 /* handle the seek in the chain function */
2831 demux->seeking = TRUE;
2832 demux->state = FLV_STATE_SEEK;
2834 /* copy the event */
2835 if (demux->seek_event)
2836 gst_event_unref (demux->seek_event);
2837 demux->seek_event = gst_event_ref (event);
2839 /* set the building_index flag so that only one thread can setup the
2840 * structures for index seeking. */
2841 building_index = demux->building_index;
2842 if (!building_index) {
2843 demux->building_index = TRUE;
2844 if (!demux->file_size
2845 && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2846 &demux->file_size)) {
2847 GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2848 GST_OBJECT_UNLOCK (demux);
2852 /* we hope the last tag is a scriptdataobject containing an index
2853 * the size of the last tag is given in the last guint32 bits
2854 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2855 seek_offset = demux->file_size - sizeof (guint32);
2856 GST_DEBUG_OBJECT (demux,
2857 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2859 GST_OBJECT_UNLOCK (demux);
2861 if (!building_index) {
2862 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2864 return flv_demux_seek_to_offset (demux, seek_offset);
2867 /* FIXME: we have to always return true so that we don't block the seek
2869 * Note: maybe it is OK to return true if we're still building the index */
2873 return flv_demux_handle_seek_push (demux, event);
2877 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2882 GstSeekType start_type, stop_type;
2885 gboolean update, flush, ret = FALSE;
2886 GstSegment seeksegment;
2888 gst_event_parse_seek (event, &rate, &format, &flags,
2889 &start_type, &start, &stop_type, &stop);
2891 if (format != GST_FORMAT_TIME)
2894 /* mark seeking thread entering flushing/pausing */
2895 GST_OBJECT_LOCK (demux);
2897 demux->seeking = seeking;
2898 GST_OBJECT_UNLOCK (demux);
2900 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2903 /* Flush start up and downstream to make sure data flow and loops are
2905 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2906 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2908 /* Pause the pulling task */
2909 gst_pad_pause_task (demux->sinkpad);
2912 /* Take the stream lock */
2913 GST_PAD_STREAM_LOCK (demux->sinkpad);
2916 /* Stop flushing upstream we need to pull */
2917 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2920 /* Work on a copy until we are sure the seek succeeded. */
2921 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2923 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2926 /* Apply the seek to our segment */
2927 gst_segment_do_seek (&seeksegment, rate, format, flags,
2928 start_type, start, stop_type, stop, &update);
2930 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2933 if (flush || seeksegment.position != demux->segment.position) {
2934 /* Do the actual seeking */
2935 /* index is reliable if it is complete or we do not go to far ahead */
2936 if (seeking && !demux->indexed &&
2937 seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2938 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2939 " index only up to %" GST_TIME_FORMAT,
2940 GST_TIME_ARGS (demux->index_max_time));
2941 /* stop flushing for now */
2943 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2944 /* delegate scanning and index building to task thread to avoid
2945 * occupying main (UI) loop */
2946 if (demux->seek_event)
2947 gst_event_unref (demux->seek_event);
2948 demux->seek_event = gst_event_ref (event);
2949 demux->seek_time = seeksegment.position;
2950 demux->state = FLV_STATE_SEEK;
2951 /* do not know about succes yet, but we did care and handled it */
2956 /* now index should be as reliable as it can be for current purpose */
2957 gst_flv_demux_move_to_offset (demux,
2958 gst_flv_demux_find_offset (demux, &seeksegment, flags), TRUE);
2965 /* Stop flushing, the sinks are at time 0 now */
2966 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2970 /* Ok seek succeeded, take the newly configured segment */
2971 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2973 /* Notify about the start of a new segment */
2974 if (demux->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
2975 gst_element_post_message (GST_ELEMENT (demux),
2976 gst_message_new_segment_start (GST_OBJECT (demux),
2977 demux->segment.format, demux->segment.position));
2980 gst_flow_combiner_reset (demux->flowcombiner);
2981 /* Tell all the stream a new segment is needed */
2982 demux->audio_need_segment = TRUE;
2983 demux->video_need_segment = TRUE;
2984 /* Clean any potential newsegment event kept for the streams. The first
2985 * stream needing a new segment will create a new one. */
2986 if (G_UNLIKELY (demux->new_seg_event)) {
2987 gst_event_unref (demux->new_seg_event);
2988 demux->new_seg_event = NULL;
2990 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2991 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2992 GST_TIME_ARGS (demux->segment.start),
2993 GST_TIME_ARGS (demux->segment.stop));
2994 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2998 GST_OBJECT_LOCK (demux);
2999 seeking = demux->seeking && !seeking;
3000 demux->seeking = FALSE;
3001 GST_OBJECT_UNLOCK (demux);
3003 /* if we detect an external seek having started (and possibly already having
3004 * flushed), do not restart task to give it a chance.
3005 * Otherwise external one's flushing will take care to pause task */
3007 gst_pad_pause_task (demux->sinkpad);
3009 gst_pad_start_task (demux->sinkpad,
3010 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad, NULL);
3013 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
3015 gst_event_unref (event);
3021 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
3022 gst_event_unref (event);
3027 /* If we can pull that's prefered */
3029 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
3034 query = gst_query_new_scheduling ();
3036 if (!gst_pad_peer_query (sinkpad, query)) {
3037 gst_query_unref (query);
3041 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
3042 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
3043 gst_query_unref (query);
3048 GST_DEBUG_OBJECT (sinkpad, "activating pull");
3049 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
3053 GST_DEBUG_OBJECT (sinkpad, "activating push");
3054 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
3059 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
3060 GstPadMode mode, gboolean active)
3065 demux = GST_FLV_DEMUX (parent);
3068 case GST_PAD_MODE_PUSH:
3069 demux->random_access = FALSE;
3072 case GST_PAD_MODE_PULL:
3074 demux->random_access = TRUE;
3075 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
3078 demux->random_access = FALSE;
3079 res = gst_pad_stop_task (sinkpad);
3090 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
3093 gboolean ret = FALSE;
3095 demux = GST_FLV_DEMUX (parent);
3097 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3099 switch (GST_EVENT_TYPE (event)) {
3100 case GST_EVENT_FLUSH_START:
3101 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
3102 demux->flushing = TRUE;
3103 ret = gst_flv_demux_push_src_event (demux, event);
3105 case GST_EVENT_FLUSH_STOP:
3106 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
3107 gst_flv_demux_flush (demux, TRUE);
3108 ret = gst_flv_demux_push_src_event (demux, event);
3114 GST_DEBUG_OBJECT (demux, "received EOS");
3116 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
3119 GST_DEBUG_OBJECT (demux, "committing index");
3120 gst_index_commit (index, demux->index_id);
3121 gst_object_unref (index);
3124 if (!demux->audio_pad && !demux->video_pad)
3125 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
3126 ("Internal data stream error."), ("Got EOS before any data"));
3128 if (!demux->no_more_pads) {
3129 gst_element_no_more_pads (GST_ELEMENT (demux));
3130 demux->no_more_pads = TRUE;
3133 if (!gst_flv_demux_push_src_event (demux, event))
3134 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
3139 case GST_EVENT_SEGMENT:
3141 GstSegment in_segment;
3143 GST_DEBUG_OBJECT (demux, "received new segment");
3145 gst_event_copy_segment (event, &in_segment);
3147 if (in_segment.format == GST_FORMAT_TIME) {
3148 /* time segment, this is perfect, copy over the values. */
3149 memcpy (&demux->segment, &in_segment, sizeof (in_segment));
3151 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
3155 ret = gst_flv_demux_push_src_event (demux, event);
3157 /* non-time format */
3158 demux->audio_need_segment = TRUE;
3159 demux->video_need_segment = TRUE;
3161 gst_event_unref (event);
3162 if (demux->new_seg_event) {
3163 gst_event_unref (demux->new_seg_event);
3164 demux->new_seg_event = NULL;
3167 gst_flow_combiner_reset (demux->flowcombiner);
3171 ret = gst_pad_event_default (pad, parent, event);
3179 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
3182 gboolean ret = FALSE;
3184 demux = GST_FLV_DEMUX (parent);
3186 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3188 switch (GST_EVENT_TYPE (event)) {
3189 case GST_EVENT_SEEK:
3190 /* Try to push upstream first */
3191 gst_event_ref (event);
3192 ret = gst_pad_push_event (demux->sinkpad, event);
3194 gst_event_unref (event);
3197 if (demux->random_access) {
3198 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
3200 ret = gst_flv_demux_handle_seek_push (demux, event);
3204 ret = gst_pad_push_event (demux->sinkpad, event);
3212 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
3214 gboolean res = TRUE;
3217 demux = GST_FLV_DEMUX (parent);
3219 switch (GST_QUERY_TYPE (query)) {
3220 case GST_QUERY_DURATION:
3224 gst_query_parse_duration (query, &format, NULL);
3226 /* duration is time only */
3227 if (format != GST_FORMAT_TIME) {
3228 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
3234 /* Try to push upstream first */
3235 res = gst_pad_peer_query (demux->sinkpad, query);
3239 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3240 GST_TIME_ARGS (demux->duration));
3242 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3246 case GST_QUERY_POSITION:
3250 gst_query_parse_position (query, &format, NULL);
3252 /* position is time only */
3253 if (format != GST_FORMAT_TIME) {
3254 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3260 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3261 GST_TIME_ARGS (demux->segment.position));
3263 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3268 case GST_QUERY_SEEKING:{
3271 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3273 /* First ask upstream */
3274 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3277 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3284 /* FIXME, check index this way is not thread safe */
3285 if (fmt != GST_FORMAT_TIME || !demux->index) {
3286 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3287 } else if (demux->random_access) {
3288 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3291 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3292 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3295 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3296 gst_query_unref (peerquery);
3299 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3302 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3306 case GST_QUERY_SEGMENT:
3311 format = demux->segment.format;
3314 gst_segment_to_stream_time (&demux->segment, format,
3315 demux->segment.start);
3316 if ((stop = demux->segment.stop) == -1)
3317 stop = demux->segment.duration;
3319 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
3321 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
3325 case GST_QUERY_LATENCY:
3327 res = gst_pad_query_default (pad, parent, query);
3336 static GstStateChangeReturn
3337 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3340 GstStateChangeReturn ret;
3342 demux = GST_FLV_DEMUX (element);
3344 switch (transition) {
3345 case GST_STATE_CHANGE_READY_TO_PAUSED:
3346 /* If this is our own index destroy it as the
3347 * old entries might be wrong for the new stream */
3348 if (demux->own_index) {
3349 gst_object_unref (demux->index);
3350 demux->index = NULL;
3351 demux->own_index = FALSE;
3354 /* If no index was created, generate one */
3355 if (G_UNLIKELY (!demux->index)) {
3356 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3358 demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3360 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3362 demux->own_index = TRUE;
3364 gst_flv_demux_cleanup (demux);
3370 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3371 if (ret == GST_STATE_CHANGE_FAILURE)
3374 switch (transition) {
3375 case GST_STATE_CHANGE_PAUSED_TO_READY:
3376 gst_flv_demux_cleanup (demux);
3387 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3389 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3390 GstIndex *old_index;
3392 GST_OBJECT_LOCK (demux);
3394 old_index = demux->index;
3397 demux->index = gst_object_ref (index);
3398 demux->own_index = FALSE;
3400 demux->index = NULL;
3403 gst_object_unref (demux->index);
3405 gst_object_ref (index);
3407 GST_OBJECT_UNLOCK (demux);
3409 /* object lock might be taken again */
3411 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3413 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3415 gst_object_unref (index);
3420 gst_flv_demux_get_index (GstElement * element)
3422 GstIndex *result = NULL;
3424 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3426 GST_OBJECT_LOCK (demux);
3428 result = gst_object_ref (demux->index);
3429 GST_OBJECT_UNLOCK (demux);
3435 gst_flv_demux_dispose (GObject * object)
3437 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3439 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3441 if (demux->adapter) {
3442 gst_adapter_clear (demux->adapter);
3443 g_object_unref (demux->adapter);
3444 demux->adapter = NULL;
3447 if (demux->taglist) {
3448 gst_tag_list_unref (demux->taglist);
3449 demux->taglist = NULL;
3452 if (demux->flowcombiner) {
3453 gst_flow_combiner_free (demux->flowcombiner);
3454 demux->flowcombiner = NULL;
3457 if (demux->new_seg_event) {
3458 gst_event_unref (demux->new_seg_event);
3459 demux->new_seg_event = NULL;
3462 if (demux->audio_codec_data) {
3463 gst_buffer_unref (demux->audio_codec_data);
3464 demux->audio_codec_data = NULL;
3467 if (demux->video_codec_data) {
3468 gst_buffer_unref (demux->video_codec_data);
3469 demux->video_codec_data = NULL;
3472 if (demux->audio_pad) {
3473 gst_object_unref (demux->audio_pad);
3474 demux->audio_pad = NULL;
3477 if (demux->video_pad) {
3478 gst_object_unref (demux->video_pad);
3479 demux->video_pad = NULL;
3483 gst_object_unref (demux->index);
3484 demux->index = NULL;
3488 g_array_free (demux->times, TRUE);
3489 demux->times = NULL;
3492 if (demux->filepositions) {
3493 g_array_free (demux->filepositions, TRUE);
3494 demux->filepositions = NULL;
3497 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3501 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3503 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3504 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3506 gobject_class->dispose = gst_flv_demux_dispose;
3508 gstelement_class->change_state =
3509 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3512 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3513 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3516 gst_element_class_add_pad_template (gstelement_class,
3517 gst_static_pad_template_get (&flv_sink_template));
3518 gst_element_class_add_pad_template (gstelement_class,
3519 gst_static_pad_template_get (&audio_src_template));
3520 gst_element_class_add_pad_template (gstelement_class,
3521 gst_static_pad_template_get (&video_src_template));
3522 gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
3524 "Demux FLV feeds into digital streams",
3525 "Julien Moutte <julien@moutte.net>");
3529 gst_flv_demux_init (GstFlvDemux * demux)
3532 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3534 gst_pad_set_event_function (demux->sinkpad,
3535 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3536 gst_pad_set_chain_function (demux->sinkpad,
3537 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3538 gst_pad_set_activate_function (demux->sinkpad,
3539 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3540 gst_pad_set_activatemode_function (demux->sinkpad,
3541 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3543 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3545 demux->adapter = gst_adapter_new ();
3546 demux->taglist = gst_tag_list_new_empty ();
3547 demux->flowcombiner = gst_flow_combiner_new ();
3548 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3550 demux->own_index = FALSE;
3552 GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3554 gst_flv_demux_cleanup (demux);
3558 plugin_init (GstPlugin * plugin)
3560 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3562 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3563 gst_flv_demux_get_type ()) ||
3564 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3565 gst_flv_mux_get_type ()))
3571 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3572 flv, "FLV muxing and demuxing plugin",
3573 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)