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>
47 /* FIXME: don't rely on own GstIndex */
49 #include "gstmemindex.c"
50 #define GST_ASSOCIATION_FLAG_NONE GST_INDEX_ASSOCIATION_FLAG_NONE
51 #define GST_ASSOCIATION_FLAG_KEY_UNIT GST_INDEX_ASSOCIATION_FLAG_KEY_UNIT
52 #define GST_ASSOCIATION_FLAG_DELTA_UNIT GST_INDEX_ASSOCIATION_FLAG_DELTA_UNIT
54 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
57 GST_STATIC_CAPS ("video/x-flv")
60 static GstStaticPadTemplate audio_src_template =
61 GST_STATIC_PAD_TEMPLATE ("audio",
65 ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
66 "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
67 "audio/mpeg, mpegversion = (int) 4, stream-format = (string) raw, framed = (boolean) TRUE; "
68 "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
69 "audio/x-raw, format = (string) { U8, S16LE }, layout = (string) interleaved, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
70 "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
71 "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
72 "audio/x-speex, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 };")
75 static GstStaticPadTemplate video_src_template =
76 GST_STATIC_PAD_TEMPLATE ("video",
79 GST_STATIC_CAPS ("video/x-flash-video, flvversion=(int) 1; "
80 "video/x-flash-screen; "
81 "video/x-vp6-flash; " "video/x-vp6-alpha; "
82 "video/x-h264, stream-format=avc;")
85 GST_DEBUG_CATEGORY_STATIC (flvdemux_debug);
86 #define GST_CAT_DEFAULT flvdemux_debug
88 #define gst_flv_demux_parent_class parent_class
89 G_DEFINE_TYPE (GstFlvDemux, gst_flv_demux, GST_TYPE_ELEMENT);
91 /* 9 bytes of header + 4 bytes of first previous tag size */
92 #define FLV_HEADER_SIZE 13
93 /* 1 byte of tag type + 3 bytes of tag data size */
94 #define FLV_TAG_TYPE_SIZE 4
96 /* two seconds - consider pts are resynced to another base if this different */
97 #define RESYNC_THRESHOLD 2000
99 static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
101 static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
102 GstEvent * event, gboolean seeking);
104 static gboolean gst_flv_demux_query (GstPad * pad, GstObject * parent,
106 static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent,
109 static GstIndex *gst_flv_demux_get_index (GstElement * element);
112 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
113 guint64 pos, gboolean keyframe)
115 GstIndexAssociation associations[2];
117 GstIndexEntry *entry;
119 GST_LOG_OBJECT (demux,
120 "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
121 keyframe, GST_TIME_ARGS (ts), pos);
123 /* if upstream is not seekable there is no point in building an index */
124 if (!demux->upstream_seekable)
127 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
132 /* entry may already have been added before, avoid adding indefinitely */
133 entry = gst_index_get_assoc_entry (index, demux->index_id,
134 GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
137 #ifndef GST_DISABLE_GST_DEBUG
141 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
142 key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
143 GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
144 ", keyframe %d", GST_TIME_ARGS (time), key);
145 /* there is not really a way to delete the existing one */
146 if (time != ts || key != ! !keyframe)
147 GST_DEBUG_OBJECT (demux, "metadata mismatch");
149 gst_object_unref (index);
153 associations[0].format = GST_FORMAT_TIME;
154 associations[0].value = ts;
155 associations[1].format = GST_FORMAT_BYTES;
156 associations[1].value = pos;
158 gst_index_add_associationv (index, demux->index_id,
159 (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
160 GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
161 (const GstIndexAssociation *) &associations);
163 if (pos > demux->index_max_pos)
164 demux->index_max_pos = pos;
165 if (ts > demux->index_max_time)
166 demux->index_max_time = ts;
168 gst_object_unref (index);
172 FLV_GET_STRING (GstByteReader * reader)
174 guint16 string_size = 0;
175 gchar *string = NULL;
176 const guint8 *str = NULL;
178 g_return_val_if_fail (reader != NULL, NULL);
180 if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
183 if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
186 string = g_try_malloc0 (string_size + 1);
187 if (G_UNLIKELY (!string)) {
191 if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
196 memcpy (string, str, string_size);
197 if (!g_utf8_validate (string, string_size, NULL)) {
206 gst_flv_demux_check_seekability (GstFlvDemux * demux)
209 gint64 start = -1, stop = -1;
211 demux->upstream_seekable = FALSE;
213 query = gst_query_new_seeking (GST_FORMAT_BYTES);
214 if (!gst_pad_peer_query (demux->sinkpad, query)) {
215 GST_DEBUG_OBJECT (demux, "seeking query failed");
216 gst_query_unref (query);
220 gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
223 gst_query_unref (query);
225 /* try harder to query upstream size if we didn't get it the first time */
226 if (demux->upstream_seekable && stop == -1) {
227 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
228 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
231 /* if upstream doesn't know the size, it's likely that it's not seekable in
232 * practice even if it technically may be seekable */
233 if (demux->upstream_seekable && (start != 0 || stop <= start)) {
234 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
235 demux->upstream_seekable = FALSE;
238 GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
242 parse_flv_demux_parse_date_string (GDate * date, const gchar * s)
244 g_date_set_parse (date, s);
245 if (g_date_valid (date))
248 /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
250 static const gchar *months[] = {
251 "Jan", "Feb", "Mar", "Apr",
252 "May", "Jun", "Jul", "Aug",
253 "Sep", "Oct", "Nov", "Dec"
255 gchar **tokens = g_strsplit (s, " ", -1);
260 if (g_strv_length (tokens) != 5)
263 if (strlen (tokens[1]) != 3)
265 for (i = 0; i < 12; i++) {
266 if (!strcmp (tokens[1], months[i])) {
272 g_date_set_month (date, i + 1);
274 d = g_ascii_strtoull (tokens[2], &endptr, 10);
275 if (d == 0 && *endptr != '\0')
278 g_date_set_day (date, d);
280 d = g_ascii_strtoull (tokens[4], &endptr, 10);
281 if (d == 0 && *endptr != '\0')
284 g_date_set_year (date, d);
293 gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
294 gboolean * end_marker)
296 gchar *tag_name = NULL;
299 /* Initialize the end_marker flag to FALSE */
302 /* Name of the tag */
303 tag_name = FLV_GET_STRING (reader);
304 if (G_UNLIKELY (!tag_name)) {
305 GST_WARNING_OBJECT (demux, "failed reading tag name");
309 /* What kind of object is that */
310 if (!gst_byte_reader_get_uint8 (reader, &tag_type))
313 GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
317 { /* Use a union to read the uint64 and then as a double */
320 if (!gst_byte_reader_get_float64_be (reader, &d))
323 GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
325 if (!strcmp (tag_name, "duration")) {
326 demux->duration = d * GST_SECOND;
328 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
329 GST_TAG_DURATION, demux->duration, NULL);
330 } else if (!strcmp (tag_name, "AspectRatioX")) {
332 demux->got_par = TRUE;
333 } else if (!strcmp (tag_name, "AspectRatioY")) {
335 demux->got_par = TRUE;
336 } else if (!strcmp (tag_name, "width")) {
338 } else if (!strcmp (tag_name, "height")) {
340 } else if (!strcmp (tag_name, "framerate")) {
341 demux->framerate = d;
343 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
348 case 1: /* Boolean */
352 if (!gst_byte_reader_get_uint8 (reader, &b))
355 GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
357 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
365 s = FLV_GET_STRING (reader);
369 GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
371 if (!strcmp (tag_name, "creationdate")) {
372 GDate *date = g_date_new ();
374 parse_flv_demux_parse_date_string (date, s);
375 if (!g_date_valid (date)) {
376 GST_DEBUG_OBJECT (demux, "Failed to parse string as date");
378 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
379 GST_TAG_DATE, date, NULL);
382 } else if (!strcmp (tag_name, "creator")) {
383 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
384 GST_TAG_ARTIST, s, NULL);
385 } else if (!strcmp (tag_name, "title")) {
386 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
387 GST_TAG_TITLE, s, NULL);
388 } else if (!strcmp (tag_name, "metadatacreator")) {
389 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
390 GST_TAG_ENCODER, s, NULL);
392 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
401 gboolean end_of_object_marker = FALSE;
403 while (!end_of_object_marker) {
404 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
405 &end_of_object_marker);
407 if (G_UNLIKELY (!ok)) {
408 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
415 case 8: /* ECMA array */
417 guint32 nb_elems = 0;
418 gboolean end_of_object_marker = FALSE;
420 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
423 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
426 while (!end_of_object_marker) {
427 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
428 &end_of_object_marker);
430 if (G_UNLIKELY (!ok)) {
431 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
438 case 9: /* End marker */
440 GST_DEBUG_OBJECT (demux, "end marker ?");
441 if (tag_name[0] == '\0') {
443 GST_DEBUG_OBJECT (demux, "end marker detected");
452 guint32 nb_elems = 0;
454 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
457 GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
459 if (!strcmp (tag_name, "times")) {
461 g_array_free (demux->times, TRUE);
463 demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
464 } else if (!strcmp (tag_name, "filepositions")) {
465 if (demux->filepositions) {
466 g_array_free (demux->filepositions, TRUE);
468 demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
472 guint8 elem_type = 0;
474 if (!gst_byte_reader_get_uint8 (reader, &elem_type))
482 if (!gst_byte_reader_get_float64_be (reader, &d))
485 GST_DEBUG_OBJECT (demux, "element is a double %f", d);
487 if (!strcmp (tag_name, "times") && demux->times) {
488 g_array_append_val (demux->times, d);
489 } else if (!strcmp (tag_name, "filepositions") &&
490 demux->filepositions) {
491 g_array_append_val (demux->filepositions, d);
496 GST_WARNING_OBJECT (demux, "unsupported array element type %d",
508 if (!gst_byte_reader_get_float64_be (reader, &d))
511 if (!gst_byte_reader_get_int16_be (reader, &i))
514 GST_DEBUG_OBJECT (demux,
515 "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
517 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
522 GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
536 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
538 GstFlowReturn ret = GST_FLOW_OK;
539 GstByteReader reader;
543 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 7, GST_FLOW_ERROR);
545 gst_buffer_map (buffer, &map, GST_MAP_READ);
546 gst_byte_reader_init (&reader, map.data, map.size);
548 gst_byte_reader_skip_unchecked (&reader, 7);
550 GST_LOG_OBJECT (demux, "parsing a script tag");
552 if (!gst_byte_reader_get_uint8 (&reader, &type))
557 gchar *function_name;
560 function_name = FLV_GET_STRING (&reader);
562 GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
564 if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
565 gboolean end_marker = FALSE;
566 GST_DEBUG_OBJECT (demux, "we have a metadata script object");
568 if (!gst_byte_reader_get_uint8 (&reader, &type)) {
569 g_free (function_name);
576 guint32 nb_elems = 0;
579 if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
580 g_free (function_name);
584 /* The number of elements is just a hint, some files have
585 nb_elements == 0 and actually contain items. */
586 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
589 /* fallthrough to read data */
593 while (!end_marker) {
595 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
597 if (G_UNLIKELY (!ok)) {
598 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
605 GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
606 g_free (function_name);
610 demux->push_tags = TRUE;
613 g_free (function_name);
615 if (demux->times && demux->filepositions) {
618 /* If an index was found, insert associations */
619 num = MIN (demux->times->len, demux->filepositions->len);
620 for (i = 0; i < num; i++) {
621 guint64 time, fileposition;
623 time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
624 fileposition = g_array_index (demux->filepositions, gdouble, i);
625 gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
628 demux->indexed = TRUE;
633 gst_buffer_unmap (buffer, &map);
639 have_group_id (GstFlvDemux * demux)
643 event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
645 if (gst_event_parse_group_id (event, &demux->group_id))
646 demux->have_group_id = TRUE;
648 demux->have_group_id = FALSE;
649 gst_event_unref (event);
650 } else if (!demux->have_group_id) {
651 demux->have_group_id = TRUE;
652 demux->group_id = gst_util_group_id_next ();
655 return demux->have_group_id;
659 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
660 guint32 rate, guint32 channels, guint32 width)
662 GstCaps *caps = NULL;
663 gchar *codec_name = NULL;
664 gboolean ret = FALSE;
665 guint adjusted_rate = rate;
671 caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
676 caps = gst_caps_new_simple ("audio/mpeg",
677 "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
678 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
683 GstAudioFormat format;
685 /* Assuming little endian for 0 (aka endianness of the
686 * system on which the file was created) as most people
687 * are probably using little endian machines */
688 format = gst_audio_format_build_integer ((width == 8) ? FALSE : TRUE,
689 G_LITTLE_ENDIAN, width, width);
691 caps = gst_caps_new_simple ("audio/x-raw",
692 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
693 "layout", G_TYPE_STRING, "interleaved", NULL);
699 caps = gst_caps_new_empty_simple ("audio/x-nellymoser");
703 if (demux->audio_codec_data) {
706 gst_buffer_map (demux->audio_codec_data, &map, GST_MAP_READ);
708 /* use codec-data to extract and verify samplerate */
712 freq_index = GST_READ_UINT16_BE (map.data);
713 freq_index = (freq_index & 0x0780) >> 7;
715 gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
717 if (adjusted_rate && (rate != adjusted_rate)) {
718 GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
721 adjusted_rate = rate;
724 gst_buffer_unmap (demux->audio_codec_data, &map);
727 caps = gst_caps_new_simple ("audio/mpeg",
728 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
729 "stream-format", G_TYPE_STRING, "raw", NULL);
733 caps = gst_caps_new_empty_simple ("audio/x-alaw");
736 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
740 GValue streamheader = G_VALUE_INIT;
741 GValue value = G_VALUE_INIT;
743 GstStructure *structure;
746 caps = gst_caps_new_empty_simple ("audio/x-speex");
747 structure = gst_caps_get_structure (caps, 0);
749 GST_DEBUG_OBJECT (demux, "generating speex header");
751 /* Speex decoder expects streamheader to be { [header], [comment] } */
752 g_value_init (&streamheader, GST_TYPE_ARRAY);
755 gst_byte_writer_init_with_size (&w, 80, TRUE);
756 gst_byte_writer_put_data (&w, (guint8 *) "Speex ", 8);
757 gst_byte_writer_put_data (&w, (guint8 *) "1.1.12", 7);
758 gst_byte_writer_fill (&w, 0, 13);
759 gst_byte_writer_put_uint32_le (&w, 1); /* version */
760 gst_byte_writer_put_uint32_le (&w, 80); /* header_size */
761 gst_byte_writer_put_uint32_le (&w, 16000); /* rate */
762 gst_byte_writer_put_uint32_le (&w, 1); /* mode: Wideband */
763 gst_byte_writer_put_uint32_le (&w, 4); /* mode_bitstream_version */
764 gst_byte_writer_put_uint32_le (&w, 1); /* nb_channels: 1 */
765 gst_byte_writer_put_uint32_le (&w, -1); /* bitrate */
766 gst_byte_writer_put_uint32_le (&w, 0x50); /* frame_size */
767 gst_byte_writer_put_uint32_le (&w, 0); /* VBR */
768 gst_byte_writer_put_uint32_le (&w, 1); /* frames_per_packet */
769 gst_byte_writer_put_uint32_le (&w, 0); /* extra_headers */
770 gst_byte_writer_put_uint32_le (&w, 0); /* reserved1 */
771 gst_byte_writer_put_uint32_le (&w, 0); /* reserved2 */
772 g_assert (gst_byte_writer_get_size (&w) == 80);
774 g_value_init (&value, GST_TYPE_BUFFER);
775 g_value_take_boxed (&value, gst_byte_writer_reset_and_get_buffer (&w));
776 gst_value_array_append_value (&streamheader, &value);
777 g_value_unset (&value);
780 g_value_init (&value, GST_TYPE_BUFFER);
781 buf = gst_buffer_new_wrapped (g_memdup ("No comments", 12), 12);
782 g_value_take_boxed (&value, buf);
783 gst_value_array_append_value (&streamheader, &value);
784 g_value_unset (&value);
786 gst_structure_take_value (structure, "streamheader", &streamheader);
790 GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
794 if (G_UNLIKELY (!caps)) {
795 GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
799 gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
800 "channels", G_TYPE_INT, channels, NULL);
802 if (demux->audio_codec_data) {
803 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
804 demux->audio_codec_data, NULL);
808 gst_pad_create_stream_id (demux->audio_pad, GST_ELEMENT_CAST (demux),
811 event = gst_event_new_stream_start (stream_id);
812 if (have_group_id (demux))
813 gst_event_set_group_id (event, demux->group_id);
814 gst_pad_push_event (demux->audio_pad, event);
817 ret = gst_pad_set_caps (demux->audio_pad, caps);
819 if (G_LIKELY (ret)) {
820 /* Store the caps we got from tags */
821 demux->audio_codec_tag = codec_tag;
823 demux->channels = channels;
824 demux->width = width;
826 codec_name = gst_pb_utils_get_codec_description (caps);
829 if (demux->taglist == NULL)
830 demux->taglist = gst_tag_list_new_empty ();
831 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
832 GST_TAG_AUDIO_CODEC, codec_name, NULL);
836 GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
837 GST_PTR_FORMAT, caps);
839 GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
840 GST_PTR_FORMAT, caps);
843 gst_caps_unref (caps);
850 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
854 if (demux->audio_pad)
855 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
857 if (demux->video_pad)
858 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
860 gst_event_unref (event);
866 gst_flv_demux_push_tags (GstFlvDemux * demux)
868 if (demux->has_audio && !demux->audio_pad) {
869 GST_DEBUG_OBJECT (demux,
870 "Waiting for audio stream pad to come up before we can push tags");
873 if (demux->has_video && !demux->video_pad) {
874 GST_DEBUG_OBJECT (demux,
875 "Waiting for video stream pad to come up before we can push tags");
878 if (demux->taglist) {
879 GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
881 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
882 gst_flv_demux_push_src_event (demux, gst_event_new_tag (demux->taglist));
883 demux->taglist = gst_tag_list_new_empty ();
884 demux->push_tags = FALSE;
889 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, gboolean discont,
890 guint32 * last, GstClockTime * offset)
892 gint32 dpts = pts - *last;
893 if (!discont && ABS (dpts) >= RESYNC_THRESHOLD) {
894 /* Theoretically, we should use substract the duration of the last buffer,
895 but this demuxer sends no durations on buffers, not sure if it cannot
896 know, or just does not care to calculate. */
897 *offset -= dpts * GST_MSECOND;
898 GST_WARNING_OBJECT (demux,
899 "Large pts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
900 GST_TIME_FORMAT "", dpts, GST_TIME_ARGS (*offset));
906 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
908 GstFlowReturn ret = GST_FLOW_OK;
909 guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
910 guint32 codec_data = 0, pts_ext = 0;
916 GST_LOG_OBJECT (demux, "parsing an audio tag");
918 if (demux->no_more_pads && !demux->audio_pad) {
919 GST_WARNING_OBJECT (demux,
920 "Signaled no-more-pads already but had no audio pad -- ignoring");
924 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
927 /* Error out on tags with too small headers */
928 if (gst_buffer_get_size (buffer) < 11) {
929 GST_ERROR_OBJECT (demux, "Too small tag size (%" G_GSIZE_FORMAT ")",
930 gst_buffer_get_size (buffer));
931 return GST_FLOW_ERROR;
934 gst_buffer_map (buffer, &map, GST_MAP_READ);
937 /* Grab information about audio tag */
938 pts = GST_READ_UINT24_BE (data);
939 /* read the pts extension to 32 bits integer */
940 pts_ext = GST_READ_UINT8 (data + 3);
942 pts |= pts_ext << 24;
944 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
945 data[2], data[3], pts);
947 /* Skip the stream id and go directly to the flags */
948 flags = GST_READ_UINT8 (data + 7);
950 /* Silently skip buffers with no data */
963 if ((flags & 0x0C) == 0x0C) {
965 } else if ((flags & 0x0C) == 0x08) {
967 } else if ((flags & 0x0C) == 0x04) {
971 codec_tag = flags >> 4;
972 if (codec_tag == 10) { /* AAC has an extra byte for packet type */
978 /* codec tags with special rates */
979 if (codec_tag == 5 || codec_tag == 14)
981 else if (codec_tag == 4)
984 GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
985 "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
988 /* If we don't have our audio pad created, then create it. */
989 if (G_UNLIKELY (!demux->audio_pad)) {
992 gst_pad_new_from_template (gst_element_class_get_pad_template
993 (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
994 if (G_UNLIKELY (!demux->audio_pad)) {
995 GST_WARNING_OBJECT (demux, "failed creating audio pad");
996 ret = GST_FLOW_ERROR;
1000 /* Set functions on the pad */
1001 gst_pad_set_query_function (demux->audio_pad,
1002 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1003 gst_pad_set_event_function (demux->audio_pad,
1004 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1006 gst_pad_use_fixed_caps (demux->audio_pad);
1008 /* Make it active */
1009 gst_pad_set_active (demux->audio_pad, TRUE);
1011 /* Negotiate caps */
1012 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1014 gst_object_unref (demux->audio_pad);
1015 demux->audio_pad = NULL;
1016 ret = GST_FLOW_ERROR;
1019 #ifndef GST_DISABLE_GST_DEBUG
1023 caps = gst_pad_get_current_caps (demux->audio_pad);
1024 GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
1027 gst_caps_unref (caps);
1031 /* We need to set caps before adding */
1032 gst_element_add_pad (GST_ELEMENT (demux),
1033 gst_object_ref (demux->audio_pad));
1035 /* We only emit no more pads when we have audio and video. Indeed we can
1036 * not trust the FLV header to tell us if there will be only audio or
1037 * only video and we would just break discovery of some files */
1038 if (demux->audio_pad && demux->video_pad) {
1039 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1040 gst_element_no_more_pads (GST_ELEMENT (demux));
1041 demux->no_more_pads = TRUE;
1042 demux->push_tags = TRUE;
1046 /* Check if caps have changed */
1047 if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
1048 codec_tag != demux->audio_codec_tag || width != demux->width)) {
1049 GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
1051 /* Negotiate caps */
1052 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1054 ret = GST_FLOW_ERROR;
1059 /* Push taglist if present */
1060 if (G_UNLIKELY (demux->push_tags))
1061 gst_flv_demux_push_tags (demux);
1063 /* Check if we have anything to push */
1064 if (demux->tag_data_size <= codec_data) {
1065 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1069 /* Create buffer from pad */
1070 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1071 7 + codec_data, demux->tag_data_size - codec_data);
1073 if (demux->audio_codec_tag == 10) {
1074 guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
1076 switch (aac_packet_type) {
1079 /* AudioSpecificConfig data */
1080 GST_LOG_OBJECT (demux, "got an AAC codec data packet");
1081 if (demux->audio_codec_data) {
1082 gst_buffer_unref (demux->audio_codec_data);
1084 demux->audio_codec_data = outbuf;
1085 /* Use that buffer data in the caps */
1086 gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels, width);
1091 /* AAC raw packet */
1092 GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
1095 GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
1100 /* detect (and deem to be resyncs) large pts gaps */
1101 gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
1102 &demux->last_audio_pts, &demux->audio_time_offset);
1104 /* Fill buffer with data */
1105 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
1106 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1107 GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
1108 GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
1110 if (demux->duration == GST_CLOCK_TIME_NONE ||
1111 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1112 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1114 /* Only add audio frames to the index if we have no video,
1115 * and if the index is not yet complete */
1116 if (!demux->has_video && !demux->indexed) {
1117 gst_flv_demux_parse_and_add_index_entry (demux,
1118 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
1121 if (G_UNLIKELY (demux->audio_need_discont)) {
1122 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1123 demux->audio_need_discont = FALSE;
1126 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1128 /* Do we need a newsegment event ? */
1129 if (G_UNLIKELY (demux->audio_need_segment)) {
1130 if (!demux->new_seg_event) {
1131 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1132 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1133 GST_TIME_ARGS (demux->segment.position),
1134 GST_TIME_ARGS (demux->segment.stop));
1135 demux->segment.start = demux->segment.time = demux->segment.position;
1136 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1138 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1141 gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1143 demux->audio_need_segment = FALSE;
1146 GST_LOG_OBJECT (demux,
1147 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1148 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1149 gst_buffer_get_size (outbuf),
1150 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1151 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1153 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1154 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1156 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1157 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1160 if (G_UNLIKELY (!demux->no_more_pads
1161 && (GST_CLOCK_DIFF (demux->audio_start,
1162 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1163 GST_DEBUG_OBJECT (demux,
1164 "Signalling no-more-pads because no video stream was found"
1165 " after 6 seconds of audio");
1166 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1167 demux->no_more_pads = TRUE;
1168 demux->push_tags = TRUE;
1171 /* Push downstream */
1172 ret = gst_pad_push (demux->audio_pad, outbuf);
1173 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1174 if (demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1175 demux->segment.position > demux->segment.stop) {
1176 /* In reverse playback we can get a GST_FLOW_EOS when
1177 * we are at the end of the segment, so we just need to jump
1178 * back to the previous section. */
1179 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1180 demux->audio_done = TRUE;
1183 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1184 " bytes audio buffer: %s", demux->tag_data_size,
1185 gst_flow_get_name (ret));
1186 if (ret == GST_FLOW_NOT_LINKED) {
1187 demux->audio_linked = FALSE;
1193 demux->audio_linked = TRUE;
1196 gst_buffer_unmap (buffer, &map);
1202 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1204 gboolean ret = FALSE;
1205 GstCaps *caps = NULL;
1206 gchar *codec_name = NULL;
1210 /* Generate caps for that pad */
1211 switch (codec_tag) {
1214 gst_caps_new_simple ("video/x-flash-video", "flvversion", G_TYPE_INT,
1218 caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1221 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1224 caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1228 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1232 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1235 if (G_UNLIKELY (!caps)) {
1236 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1240 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1241 demux->par_x, demux->par_y, NULL);
1243 if (G_LIKELY (demux->w)) {
1244 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1247 if (G_LIKELY (demux->h)) {
1248 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1251 if (G_LIKELY (demux->framerate)) {
1252 gint num = 0, den = 0;
1254 gst_util_double_to_fraction (demux->framerate, &num, &den);
1255 GST_DEBUG_OBJECT (demux->video_pad,
1256 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1259 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1262 if (demux->video_codec_data) {
1263 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1264 demux->video_codec_data, NULL);
1268 gst_pad_create_stream_id (demux->video_pad, GST_ELEMENT_CAST (demux),
1270 event = gst_event_new_stream_start (stream_id);
1273 if (have_group_id (demux))
1274 gst_event_set_group_id (event, demux->group_id);
1275 gst_pad_push_event (demux->video_pad, event);
1276 ret = gst_pad_set_caps (demux->video_pad, caps);
1278 if (G_LIKELY (ret)) {
1279 /* Store the caps we have set */
1280 demux->video_codec_tag = codec_tag;
1282 codec_name = gst_pb_utils_get_codec_description (caps);
1285 if (demux->taglist == NULL)
1286 demux->taglist = gst_tag_list_new_empty ();
1287 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1288 GST_TAG_VIDEO_CODEC, codec_name, NULL);
1289 g_free (codec_name);
1292 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1293 GST_PTR_FORMAT, caps);
1295 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1296 GST_PTR_FORMAT, caps);
1299 gst_caps_unref (caps);
1305 static GstFlowReturn
1306 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1308 GstFlowReturn ret = GST_FLOW_OK;
1309 guint32 pts = 0, codec_data = 1, pts_ext = 0;
1310 gboolean keyframe = FALSE;
1311 guint8 flags = 0, codec_tag = 0;
1316 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1319 GST_LOG_OBJECT (demux, "parsing a video tag");
1321 if (demux->no_more_pads && !demux->video_pad) {
1322 GST_WARNING_OBJECT (demux,
1323 "Signaled no-more-pads already but had no audio pad -- ignoring");
1327 if (gst_buffer_get_size (buffer) < 12) {
1328 GST_ERROR_OBJECT (demux, "Too small tag size");
1329 return GST_FLOW_ERROR;
1332 gst_buffer_map (buffer, &map, GST_MAP_READ);
1335 /* Grab information about video tag */
1336 pts = GST_READ_UINT24_BE (data);
1337 /* read the pts extension to 32 bits integer */
1338 pts_ext = GST_READ_UINT8 (data + 3);
1340 pts |= pts_ext << 24;
1342 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1343 data[2], data[3], pts);
1345 /* Skip the stream id and go directly to the flags */
1346 flags = GST_READ_UINT8 (data + 7);
1349 if ((flags >> 4) == 1) {
1353 codec_tag = flags & 0x0F;
1354 if (codec_tag == 4 || codec_tag == 5) {
1356 } else if (codec_tag == 7) {
1361 cts = GST_READ_UINT24_BE (data + 9);
1362 cts = (cts + 0xff800000) ^ 0xff800000;
1364 GST_LOG_OBJECT (demux, "got cts %d", cts);
1366 /* avoid negative overflow */
1367 if (cts >= 0 || pts >= -cts)
1371 GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1372 "(flags %02X)", codec_tag, keyframe, flags);
1374 /* If we don't have our video pad created, then create it. */
1375 if (G_UNLIKELY (!demux->video_pad)) {
1377 gst_pad_new_from_template (gst_element_class_get_pad_template
1378 (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1379 if (G_UNLIKELY (!demux->video_pad)) {
1380 GST_WARNING_OBJECT (demux, "failed creating video pad");
1381 ret = GST_FLOW_ERROR;
1385 /* Set functions on the pad */
1386 gst_pad_set_query_function (demux->video_pad,
1387 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1388 gst_pad_set_event_function (demux->video_pad,
1389 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1391 gst_pad_use_fixed_caps (demux->video_pad);
1393 /* Make it active */
1394 gst_pad_set_active (demux->video_pad, TRUE);
1396 /* Needs to be active before setting caps */
1397 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1398 gst_object_unref (demux->video_pad);
1399 demux->video_pad = NULL;
1400 ret = GST_FLOW_ERROR;
1404 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1405 * metadata tag that would come later and trigger a caps change */
1406 demux->got_par = FALSE;
1408 #ifndef GST_DISABLE_GST_DEBUG
1412 caps = gst_pad_get_current_caps (demux->video_pad);
1413 GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1416 gst_caps_unref (caps);
1420 /* We need to set caps before adding */
1421 gst_element_add_pad (GST_ELEMENT (demux),
1422 gst_object_ref (demux->video_pad));
1424 /* We only emit no more pads when we have audio and video. Indeed we can
1425 * not trust the FLV header to tell us if there will be only audio or
1426 * only video and we would just break discovery of some files */
1427 if (demux->audio_pad && demux->video_pad) {
1428 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1429 gst_element_no_more_pads (GST_ELEMENT (demux));
1430 demux->no_more_pads = TRUE;
1431 demux->push_tags = TRUE;
1435 /* Check if caps have changed */
1436 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1438 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1440 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1441 ret = GST_FLOW_ERROR;
1445 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1446 * metadata tag that would come later and trigger a caps change */
1447 demux->got_par = FALSE;
1450 /* Push taglist if present */
1451 if (G_UNLIKELY (demux->push_tags))
1452 gst_flv_demux_push_tags (demux);
1454 /* Check if we have anything to push */
1455 if (demux->tag_data_size <= codec_data) {
1456 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1460 /* Create buffer from pad */
1461 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1462 7 + codec_data, demux->tag_data_size - codec_data);
1464 if (demux->video_codec_tag == 7) {
1465 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1467 switch (avc_packet_type) {
1470 /* AVCDecoderConfigurationRecord data */
1471 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1472 if (demux->video_codec_data) {
1473 gst_buffer_unref (demux->video_codec_data);
1475 demux->video_codec_data = outbuf;
1476 /* Use that buffer data in the caps */
1477 gst_flv_demux_video_negotiate (demux, codec_tag);
1482 /* H.264 NALU packet */
1483 GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1486 GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1491 /* detect (and deem to be resyncs) large pts gaps */
1492 gst_flv_demux_update_resync (demux, pts, demux->video_need_discont,
1493 &demux->last_video_pts, &demux->video_time_offset);
1495 /* Fill buffer with data */
1496 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
1497 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1498 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1499 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1501 if (demux->duration == GST_CLOCK_TIME_NONE ||
1502 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1503 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1506 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1508 if (!demux->indexed) {
1509 gst_flv_demux_parse_and_add_index_entry (demux,
1510 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1513 if (G_UNLIKELY (demux->video_need_discont)) {
1514 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1515 demux->video_need_discont = FALSE;
1518 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1520 /* Do we need a newsegment event ? */
1521 if (G_UNLIKELY (demux->video_need_segment)) {
1522 if (!demux->new_seg_event) {
1523 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1524 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1525 GST_TIME_ARGS (demux->segment.position),
1526 GST_TIME_ARGS (demux->segment.stop));
1527 demux->segment.start = demux->segment.time = demux->segment.position;
1528 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1530 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1533 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1535 demux->video_need_segment = FALSE;
1538 GST_LOG_OBJECT (demux,
1539 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1540 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1541 ", keyframe (%d)", gst_buffer_get_size (outbuf),
1542 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1543 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1546 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1547 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1549 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1550 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1553 if (G_UNLIKELY (!demux->no_more_pads
1554 && (GST_CLOCK_DIFF (demux->video_start,
1555 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1556 GST_DEBUG_OBJECT (demux,
1557 "Signalling no-more-pads because no audio stream was found"
1558 " after 6 seconds of video");
1559 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1560 demux->no_more_pads = TRUE;
1561 demux->push_tags = TRUE;
1564 /* Push downstream */
1565 ret = gst_pad_push (demux->video_pad, outbuf);
1567 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1568 if (demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1569 demux->segment.position > demux->segment.stop) {
1570 /* In reverse playback we can get a GST_FLOW_EOS when
1571 * we are at the end of the segment, so we just need to jump
1572 * back to the previous section. */
1573 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1574 demux->video_done = TRUE;
1577 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1578 " bytes video buffer: %s", demux->tag_data_size,
1579 gst_flow_get_name (ret));
1580 if (ret == GST_FLOW_NOT_LINKED) {
1581 demux->video_linked = FALSE;
1587 demux->video_linked = TRUE;
1590 gst_buffer_unmap (buffer, &map);
1595 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1596 GstBuffer * buffer, size_t * tag_size)
1598 guint32 pts = 0, pts_ext = 0;
1599 guint32 tag_data_size;
1601 gboolean keyframe = TRUE;
1602 GstClockTime ret = GST_CLOCK_TIME_NONE;
1607 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1608 GST_CLOCK_TIME_NONE);
1610 gst_buffer_map (buffer, &map, GST_MAP_READ);
1616 if (type != 9 && type != 8 && type != 18) {
1617 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1622 demux->has_video = TRUE;
1624 demux->has_audio = TRUE;
1626 tag_data_size = GST_READ_UINT24_BE (data + 1);
1628 if (size >= tag_data_size + 11 + 4) {
1629 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1630 GST_WARNING_OBJECT (demux, "Invalid tag size");
1636 *tag_size = tag_data_size + 11 + 4;
1640 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
1643 /* Grab timestamp of tag tag */
1644 pts = GST_READ_UINT24_BE (data);
1645 /* read the pts extension to 32 bits integer */
1646 pts_ext = GST_READ_UINT8 (data + 3);
1648 pts |= pts_ext << 24;
1653 keyframe = ((data[0] >> 4) == 1);
1656 ret = pts * GST_MSECOND;
1657 GST_LOG_OBJECT (demux, "pts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1659 if (index && !demux->indexed && (type == 9 || (type == 8
1660 && !demux->has_video))) {
1661 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1665 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1666 demux->duration = ret;
1669 gst_buffer_unmap (buffer, &map);
1673 static GstFlowReturn
1674 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1676 GstFlowReturn ret = GST_FLOW_OK;
1677 guint8 tag_type = 0;
1680 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1682 gst_buffer_map (buffer, &map, GST_MAP_READ);
1684 tag_type = map.data[0];
1688 demux->state = FLV_STATE_TAG_VIDEO;
1689 demux->has_video = TRUE;
1692 demux->state = FLV_STATE_TAG_AUDIO;
1693 demux->has_audio = TRUE;
1696 demux->state = FLV_STATE_TAG_SCRIPT;
1699 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1702 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1703 * 4 bytes of previous tag size */
1704 demux->tag_data_size = GST_READ_UINT24_BE (map.data + 1);
1705 demux->tag_size = demux->tag_data_size + 11;
1707 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1708 demux->tag_data_size);
1710 gst_buffer_unmap (buffer, &map);
1715 static GstFlowReturn
1716 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1718 GstFlowReturn ret = GST_FLOW_OK;
1721 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1723 gst_buffer_map (buffer, &map, GST_MAP_READ);
1725 /* Check for the FLV tag */
1726 if (map.data[0] == 'F' && map.data[1] == 'L' && map.data[2] == 'V') {
1727 GST_DEBUG_OBJECT (demux, "FLV header detected");
1729 if (G_UNLIKELY (demux->strict)) {
1730 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1736 if (map.data[3] == '1') {
1737 GST_DEBUG_OBJECT (demux, "FLV version 1 detected");
1739 if (G_UNLIKELY (demux->strict)) {
1740 GST_WARNING_OBJECT (demux, "invalid header version detected");
1747 /* Now look at audio/video flags */
1749 guint8 flags = map.data[4];
1751 demux->has_video = demux->has_audio = FALSE;
1754 GST_DEBUG_OBJECT (demux, "there is a video stream");
1755 demux->has_video = TRUE;
1758 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1759 demux->has_audio = TRUE;
1763 /* do a one-time seekability check */
1764 gst_flv_demux_check_seekability (demux);
1766 /* We don't care about the rest */
1767 demux->need_header = FALSE;
1770 gst_buffer_unmap (buffer, &map);
1776 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1778 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1780 gst_adapter_clear (demux->adapter);
1782 demux->audio_need_discont = TRUE;
1783 demux->video_need_discont = TRUE;
1785 demux->flushing = FALSE;
1787 /* Only in push mode and if we're not during a seek */
1788 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1789 /* After a flush we expect a tag_type */
1790 demux->state = FLV_STATE_TAG_TYPE;
1791 /* We reset the offset and will get one from first push */
1797 gst_flv_demux_cleanup (GstFlvDemux * demux)
1799 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1801 demux->state = FLV_STATE_HEADER;
1803 demux->have_group_id = FALSE;
1804 demux->group_id = G_MAXUINT;
1806 demux->flushing = FALSE;
1807 demux->need_header = TRUE;
1808 demux->audio_need_segment = TRUE;
1809 demux->video_need_segment = TRUE;
1810 demux->audio_need_discont = TRUE;
1811 demux->video_need_discont = TRUE;
1813 /* By default we consider them as linked */
1814 demux->audio_linked = TRUE;
1815 demux->video_linked = TRUE;
1817 demux->has_audio = FALSE;
1818 demux->has_video = FALSE;
1819 demux->push_tags = FALSE;
1820 demux->got_par = FALSE;
1822 demux->indexed = FALSE;
1823 demux->upstream_seekable = FALSE;
1824 demux->file_size = 0;
1826 demux->index_max_pos = 0;
1827 demux->index_max_time = 0;
1829 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1830 demux->last_audio_pts = demux->last_video_pts = 0;
1831 demux->audio_time_offset = demux->video_time_offset = 0;
1833 demux->no_more_pads = FALSE;
1835 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1837 demux->w = demux->h = 0;
1838 demux->framerate = 0.0;
1839 demux->par_x = demux->par_y = 1;
1840 demux->video_offset = 0;
1841 demux->audio_offset = 0;
1842 demux->offset = demux->cur_tag_offset = 0;
1843 demux->tag_size = demux->tag_data_size = 0;
1844 demux->duration = GST_CLOCK_TIME_NONE;
1846 if (demux->new_seg_event) {
1847 gst_event_unref (demux->new_seg_event);
1848 demux->new_seg_event = NULL;
1851 gst_adapter_clear (demux->adapter);
1853 if (demux->audio_codec_data) {
1854 gst_buffer_unref (demux->audio_codec_data);
1855 demux->audio_codec_data = NULL;
1858 if (demux->video_codec_data) {
1859 gst_buffer_unref (demux->video_codec_data);
1860 demux->video_codec_data = NULL;
1863 if (demux->audio_pad) {
1864 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1865 gst_object_unref (demux->audio_pad);
1866 demux->audio_pad = NULL;
1869 if (demux->video_pad) {
1870 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1871 gst_object_unref (demux->video_pad);
1872 demux->video_pad = NULL;
1876 g_array_free (demux->times, TRUE);
1877 demux->times = NULL;
1880 if (demux->filepositions) {
1881 g_array_free (demux->filepositions, TRUE);
1882 demux->filepositions = NULL;
1887 * Create and push a flushing seek event upstream
1890 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1895 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1898 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1899 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1900 GST_SEEK_TYPE_NONE, -1);
1902 res = gst_pad_push_event (demux->sinkpad, event);
1905 demux->offset = offset;
1909 static GstFlowReturn
1910 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1912 GstFlowReturn ret = GST_FLOW_OK;
1913 GstFlvDemux *demux = NULL;
1915 demux = GST_FLV_DEMUX (parent);
1917 GST_LOG_OBJECT (demux,
1918 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
1919 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
1920 GST_BUFFER_OFFSET (buffer));
1922 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1923 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1924 demux->state = FLV_STATE_HEADER;
1928 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
1929 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
1930 demux->offset = GST_BUFFER_OFFSET (buffer);
1933 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1934 GST_DEBUG_OBJECT (demux, "Discontinuity");
1935 gst_adapter_clear (demux->adapter);
1938 gst_adapter_push (demux->adapter, buffer);
1940 if (demux->seeking) {
1941 demux->state = FLV_STATE_SEEK;
1942 GST_OBJECT_LOCK (demux);
1943 demux->seeking = FALSE;
1944 GST_OBJECT_UNLOCK (demux);
1948 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1949 if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
1950 || demux->video_linked)) {
1953 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
1958 if (G_UNLIKELY (demux->flushing)) {
1959 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
1960 ret = GST_FLOW_FLUSHING;
1964 switch (demux->state) {
1965 case FLV_STATE_HEADER:
1967 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
1970 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
1972 ret = gst_flv_demux_parse_header (demux, buffer);
1974 gst_buffer_unref (buffer);
1975 demux->offset += FLV_HEADER_SIZE;
1977 demux->state = FLV_STATE_TAG_TYPE;
1983 case FLV_STATE_TAG_TYPE:
1985 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
1988 /* Remember the tag offset in bytes */
1989 demux->cur_tag_offset = demux->offset;
1991 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
1993 ret = gst_flv_demux_parse_tag_type (demux, buffer);
1995 gst_buffer_unref (buffer);
1996 demux->offset += FLV_TAG_TYPE_SIZE;
1998 /* last tag is not an index => no index/don't know where the index is
1999 * seek back to the beginning */
2000 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
2008 case FLV_STATE_TAG_VIDEO:
2010 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2013 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2015 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2017 gst_buffer_unref (buffer);
2018 demux->offset += demux->tag_size;
2020 demux->state = FLV_STATE_TAG_TYPE;
2026 case FLV_STATE_TAG_AUDIO:
2028 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2031 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2033 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2035 gst_buffer_unref (buffer);
2036 demux->offset += demux->tag_size;
2038 demux->state = FLV_STATE_TAG_TYPE;
2044 case FLV_STATE_TAG_SCRIPT:
2046 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2049 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2051 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2053 gst_buffer_unref (buffer);
2054 demux->offset += demux->tag_size;
2056 demux->state = FLV_STATE_TAG_TYPE;
2058 /* if there's a seek event we're here for the index so if we don't have it
2059 * we seek back to the beginning */
2060 if (demux->seek_event) {
2062 demux->state = FLV_STATE_SEEK;
2072 case FLV_STATE_SEEK:
2078 if (!demux->indexed) {
2079 if (demux->offset == demux->file_size - sizeof (guint32)) {
2080 guint64 seek_offset;
2083 data = gst_adapter_take (demux->adapter, 4);
2087 seek_offset = demux->file_size - sizeof (guint32) -
2088 GST_READ_UINT32_BE (data);
2091 GST_INFO_OBJECT (demux,
2092 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
2094 demux->state = FLV_STATE_TAG_TYPE;
2095 flv_demux_seek_to_offset (demux, seek_offset);
2101 GST_OBJECT_LOCK (demux);
2102 event = demux->seek_event;
2103 demux->seek_event = NULL;
2104 GST_OBJECT_UNLOCK (demux);
2106 /* calculate and perform seek */
2107 if (!flv_demux_handle_seek_push (demux, event))
2110 gst_event_unref (event);
2111 demux->state = FLV_STATE_TAG_TYPE;
2115 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
2119 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2120 /* If either audio or video is linked we return GST_FLOW_OK */
2121 if (demux->audio_linked || demux->video_linked) {
2131 GST_OBJECT_LOCK (demux);
2132 demux->seeking = FALSE;
2133 gst_event_unref (demux->seek_event);
2134 demux->seek_event = NULL;
2135 GST_OBJECT_UNLOCK (demux);
2136 GST_WARNING_OBJECT (demux,
2137 "failed to find an index, seeking back to beginning");
2138 flv_demux_seek_to_offset (demux, 0);
2143 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2144 return GST_FLOW_ERROR;
2149 static GstFlowReturn
2150 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2151 guint size, GstBuffer ** buffer)
2155 ret = gst_pad_pull_range (pad, offset, size, buffer);
2156 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2157 GST_WARNING_OBJECT (demux,
2158 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2159 size, offset, gst_flow_get_name (ret));
2164 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2165 GST_WARNING_OBJECT (demux,
2166 "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
2167 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
2168 gst_buffer_unref (*buffer);
2177 static GstFlowReturn
2178 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2180 GstBuffer *buffer = NULL;
2181 GstFlowReturn ret = GST_FLOW_OK;
2183 /* Store tag offset */
2184 demux->cur_tag_offset = demux->offset;
2186 /* Get the first 4 bytes to identify tag type and size */
2187 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2188 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2191 /* Identify tag type */
2192 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2194 gst_buffer_unref (buffer);
2196 if (G_UNLIKELY (ret != GST_FLOW_OK))
2199 /* Jump over tag type + size */
2200 demux->offset += FLV_TAG_TYPE_SIZE;
2202 /* Pull the whole tag */
2204 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2205 demux->tag_size, &buffer)) != GST_FLOW_OK))
2208 switch (demux->state) {
2209 case FLV_STATE_TAG_VIDEO:
2210 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2212 case FLV_STATE_TAG_AUDIO:
2213 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2215 case FLV_STATE_TAG_SCRIPT:
2216 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2219 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2222 gst_buffer_unref (buffer);
2224 /* Jump over that part we've just parsed */
2225 demux->offset += demux->tag_size;
2227 /* Make sure we reinitialize the tag size */
2228 demux->tag_size = 0;
2230 /* Ready for the next tag */
2231 demux->state = FLV_STATE_TAG_TYPE;
2233 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2234 /* If either audio or video is linked we return GST_FLOW_OK */
2235 if (demux->audio_linked || demux->video_linked) {
2238 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2239 "neither video nor audio are linked");
2247 static GstFlowReturn
2248 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2250 GstBuffer *buffer = NULL;
2251 GstFlowReturn ret = GST_FLOW_OK;
2253 /* Get the first 9 bytes */
2254 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2255 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2258 ret = gst_flv_demux_parse_header (demux, buffer);
2260 gst_buffer_unref (buffer);
2262 /* Jump over the header now */
2263 demux->offset += FLV_HEADER_SIZE;
2264 demux->state = FLV_STATE_TAG_TYPE;
2271 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2274 demux->offset = offset;
2276 /* Tell all the stream we moved to a different position (discont) */
2277 demux->audio_need_discont = TRUE;
2278 demux->video_need_discont = TRUE;
2280 /* next section setup */
2281 demux->from_offset = -1;
2282 demux->audio_done = demux->video_done = FALSE;
2283 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2286 demux->from_offset = -1;
2287 demux->to_offset = G_MAXINT64;
2290 /* If we seeked at the beginning of the file parse the header again */
2291 if (G_UNLIKELY (!demux->offset)) {
2292 demux->state = FLV_STATE_HEADER;
2293 } else { /* or parse a tag */
2294 demux->state = FLV_STATE_TAG_TYPE;
2298 static GstFlowReturn
2299 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2301 GstFlowReturn ret = GST_FLOW_EOS;
2303 GstIndexEntry *entry = NULL;
2305 GST_DEBUG_OBJECT (demux,
2306 "terminated section started at offset %" G_GINT64_FORMAT,
2307 demux->from_offset);
2309 /* we are done if we got all audio and video */
2310 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2311 demux->audio_first_ts < demux->segment.start) &&
2312 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2313 demux->video_first_ts < demux->segment.start))
2316 if (demux->from_offset <= 0)
2319 GST_DEBUG_OBJECT (demux, "locating previous position");
2321 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2323 /* locate index entry before previous start position */
2325 entry = gst_index_get_assoc_entry (index, demux->index_id,
2326 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2327 GST_FORMAT_BYTES, demux->from_offset - 1);
2330 gint64 bytes = 0, time = 0;
2332 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2333 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2335 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2336 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2337 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2339 /* setup for next section */
2340 demux->to_offset = demux->from_offset;
2341 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2345 gst_object_unref (index);
2353 static GstFlowReturn
2354 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2360 GstClockTime tag_time;
2361 GstFlowReturn ret = GST_FLOW_OK;
2363 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2366 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2367 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2369 old_offset = demux->offset;
2370 demux->offset = pos;
2373 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2374 12, &buffer)) == GST_FLOW_OK) {
2376 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2378 gst_buffer_unref (buffer);
2381 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2384 demux->offset += tag_size;
2387 if (ret == GST_FLOW_EOS) {
2388 /* file ran out, so mark we have complete index */
2389 demux->indexed = TRUE;
2394 demux->offset = old_offset;
2400 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2402 gint64 ret = 0, offset;
2403 size_t tag_size, size;
2404 GstBuffer *buffer = NULL;
2407 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2411 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2412 if (G_UNLIKELY (offset < 4))
2416 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2420 gst_buffer_map (buffer, &map, GST_MAP_READ);
2421 tag_size = GST_READ_UINT32_BE (map.data);
2422 gst_buffer_unmap (buffer, &map);
2423 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2424 gst_buffer_unref (buffer);
2428 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2432 /* a consistency check */
2433 gst_buffer_map (buffer, &map, GST_MAP_READ);
2434 size = GST_READ_UINT24_BE (map.data + 1);
2435 if (size != tag_size - 11) {
2436 gst_buffer_unmap (buffer, &map);
2437 GST_DEBUG_OBJECT (demux,
2438 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2439 ", corrupt or truncated file", size, tag_size - 11);
2443 /* try to update duration with timestamp in any case */
2444 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2446 /* maybe get some more metadata */
2447 if (map.data[0] == 18) {
2448 gst_buffer_unmap (buffer, &map);
2449 gst_buffer_unref (buffer);
2451 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2453 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2455 gst_flv_demux_parse_tag_script (demux, buffer);
2457 gst_buffer_unmap (buffer, &map);
2462 gst_buffer_unref (buffer);
2468 gst_flv_demux_loop (GstPad * pad)
2470 GstFlvDemux *demux = NULL;
2471 GstFlowReturn ret = GST_FLOW_OK;
2473 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2476 switch (demux->state) {
2477 case FLV_STATE_TAG_TYPE:
2478 if (demux->from_offset == -1)
2479 demux->from_offset = demux->offset;
2480 ret = gst_flv_demux_pull_tag (pad, demux);
2481 /* if we have seen real data, we probably passed a possible metadata
2482 * header located at start. So if we do not yet have an index,
2483 * try to pick up metadata (index, duration) at the end */
2484 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2485 (demux->has_video || demux->has_audio)))
2486 demux->file_size = gst_flv_demux_get_metadata (demux);
2488 case FLV_STATE_DONE:
2491 case FLV_STATE_SEEK:
2492 /* seek issued with insufficient index;
2493 * scan for index in task thread from current maximum offset to
2494 * desired time and then perform seek */
2495 /* TODO maybe some buffering message or so to indicate scan progress */
2496 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2498 if (ret != GST_FLOW_OK)
2500 /* position and state arranged by seek,
2501 * also unrefs event */
2502 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2503 demux->seek_event = NULL;
2506 ret = gst_flv_demux_pull_header (pad, demux);
2507 /* index scans start after header */
2508 demux->index_max_pos = demux->offset;
2512 if (demux->segment.rate < 0.0) {
2513 /* check end of section */
2514 if ((gint64) demux->offset >= demux->to_offset ||
2515 demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2516 (demux->audio_done && demux->video_done))
2517 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2519 /* check EOS condition */
2520 if ((demux->segment.stop != -1) &&
2521 (demux->segment.position >= demux->segment.stop)) {
2526 /* pause if something went wrong or at end */
2527 if (G_UNLIKELY (ret != GST_FLOW_OK))
2530 gst_object_unref (demux);
2536 const gchar *reason = gst_flow_get_name (ret);
2538 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2539 gst_pad_pause_task (pad);
2541 if (ret == GST_FLOW_EOS) {
2542 /* handle end-of-stream/segment */
2543 /* so align our position with the end of it, if there is one
2544 * this ensures a subsequent will arrive at correct base/acc time */
2545 if (demux->segment.rate > 0.0 &&
2546 GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2547 demux->segment.position = demux->segment.stop;
2548 else if (demux->segment.rate < 0.0)
2549 demux->segment.position = demux->segment.start;
2551 /* perform EOS logic */
2552 if (!demux->no_more_pads) {
2553 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2554 demux->no_more_pads = TRUE;
2557 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2560 /* for segment playback we need to post when (in stream time)
2561 * we stopped, this is either stop (when set) or the duration. */
2562 if ((stop = demux->segment.stop) == -1)
2563 stop = demux->segment.duration;
2565 if (demux->segment.rate >= 0) {
2566 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2567 gst_element_post_message (GST_ELEMENT_CAST (demux),
2568 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2569 GST_FORMAT_TIME, stop));
2570 gst_flv_demux_push_src_event (demux,
2571 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2572 } else { /* Reverse playback */
2573 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2575 gst_element_post_message (GST_ELEMENT_CAST (demux),
2576 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2577 GST_FORMAT_TIME, demux->segment.start));
2578 gst_flv_demux_push_src_event (demux,
2579 gst_event_new_segment_done (GST_FORMAT_TIME,
2580 demux->segment.start));
2583 /* normal playback, send EOS to all linked pads */
2584 if (!demux->no_more_pads) {
2585 gst_element_no_more_pads (GST_ELEMENT (demux));
2586 demux->no_more_pads = TRUE;
2589 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2590 if (!demux->audio_pad && !demux->video_pad)
2591 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2592 ("Internal data stream error."), ("Got EOS before any data"));
2593 else if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2594 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2596 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2597 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2598 ("Internal data stream error."),
2599 ("stream stopped, reason %s", reason));
2600 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2602 gst_object_unref (demux);
2608 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2613 GstIndexEntry *entry;
2615 g_return_val_if_fail (segment != NULL, 0);
2617 time = segment->position;
2619 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2622 /* Let's check if we have an index entry for that seek time */
2623 entry = gst_index_get_assoc_entry (index, demux->index_id,
2624 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2625 GST_FORMAT_TIME, time);
2628 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2629 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2631 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2632 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2633 GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2635 /* Key frame seeking */
2636 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2637 /* Adjust the segment so that the keyframe fits in */
2638 if (time < segment->start) {
2639 segment->start = segment->time = time;
2641 segment->position = time;
2644 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2645 GST_TIME_ARGS (segment->start));
2648 gst_object_unref (index);
2655 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2659 GstSeekType start_type, stop_type;
2662 gboolean update, flush, ret;
2663 GstSegment seeksegment;
2665 gst_event_parse_seek (event, &rate, &format, &flags,
2666 &start_type, &start, &stop_type, &stop);
2668 if (format != GST_FORMAT_TIME)
2671 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2672 /* FIXME : the keyframe flag is never used ! */
2674 /* Work on a copy until we are sure the seek succeeded. */
2675 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2677 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2680 /* Apply the seek to our segment */
2681 gst_segment_do_seek (&seeksegment, rate, format, flags,
2682 start_type, start, stop_type, stop, &update);
2684 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2687 if (flush || seeksegment.position != demux->segment.position) {
2688 /* Do the actual seeking */
2689 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2691 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2692 G_GUINT64_FORMAT, offset);
2693 ret = gst_pad_push_event (demux->sinkpad,
2694 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2695 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2696 offset, GST_SEEK_TYPE_NONE, 0));
2697 if (G_UNLIKELY (!ret)) {
2698 GST_WARNING_OBJECT (demux, "upstream seek failed");
2701 /* Tell all the stream we moved to a different position (discont) */
2702 demux->audio_need_discont = TRUE;
2703 demux->video_need_discont = TRUE;
2709 /* Ok seek succeeded, take the newly configured segment */
2710 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2712 /* Tell all the stream a new segment is needed */
2713 demux->audio_need_segment = TRUE;
2714 demux->video_need_segment = TRUE;
2715 /* Clean any potential newsegment event kept for the streams. The first
2716 * stream needing a new segment will create a new one. */
2717 if (G_UNLIKELY (demux->new_seg_event)) {
2718 gst_event_unref (demux->new_seg_event);
2719 demux->new_seg_event = NULL;
2721 gst_event_unref (event);
2723 ret = gst_pad_push_event (demux->sinkpad, event);
2731 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2732 gst_event_unref (event);
2738 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2742 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2744 if (format != GST_FORMAT_TIME) {
2745 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2746 gst_event_unref (event);
2750 /* First try upstream */
2751 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2752 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2753 gst_event_unref (event);
2757 if (!demux->indexed) {
2758 guint64 seek_offset = 0;
2759 gboolean building_index;
2761 GST_OBJECT_LOCK (demux);
2762 /* handle the seek in the chain function */
2763 demux->seeking = TRUE;
2764 demux->state = FLV_STATE_SEEK;
2766 /* copy the event */
2767 if (demux->seek_event)
2768 gst_event_unref (demux->seek_event);
2769 demux->seek_event = gst_event_ref (event);
2771 /* set the building_index flag so that only one thread can setup the
2772 * structures for index seeking. */
2773 building_index = demux->building_index;
2774 if (!building_index) {
2775 demux->building_index = TRUE;
2776 if (!demux->file_size
2777 && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2778 &demux->file_size)) {
2779 GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2780 GST_OBJECT_UNLOCK (demux);
2784 /* we hope the last tag is a scriptdataobject containing an index
2785 * the size of the last tag is given in the last guint32 bits
2786 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2787 seek_offset = demux->file_size - sizeof (guint32);
2788 GST_DEBUG_OBJECT (demux,
2789 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2791 GST_OBJECT_UNLOCK (demux);
2793 if (!building_index) {
2794 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2796 return flv_demux_seek_to_offset (demux, seek_offset);
2799 /* FIXME: we have to always return true so that we don't block the seek
2801 * Note: maybe it is OK to return true if we're still building the index */
2805 return flv_demux_handle_seek_push (demux, event);
2809 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2814 GstSeekType start_type, stop_type;
2817 gboolean update, flush, ret = FALSE;
2818 GstSegment seeksegment;
2820 gst_event_parse_seek (event, &rate, &format, &flags,
2821 &start_type, &start, &stop_type, &stop);
2823 if (format != GST_FORMAT_TIME)
2826 /* mark seeking thread entering flushing/pausing */
2827 GST_OBJECT_LOCK (demux);
2829 demux->seeking = seeking;
2830 GST_OBJECT_UNLOCK (demux);
2832 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2833 /* FIXME : the keyframe flag is never used */
2836 /* Flush start up and downstream to make sure data flow and loops are
2838 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2839 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2841 /* Pause the pulling task */
2842 gst_pad_pause_task (demux->sinkpad);
2845 /* Take the stream lock */
2846 GST_PAD_STREAM_LOCK (demux->sinkpad);
2849 /* Stop flushing upstream we need to pull */
2850 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2853 /* Work on a copy until we are sure the seek succeeded. */
2854 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2856 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2859 /* Apply the seek to our segment */
2860 gst_segment_do_seek (&seeksegment, rate, format, flags,
2861 start_type, start, stop_type, stop, &update);
2863 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2866 if (flush || seeksegment.position != demux->segment.position) {
2867 /* Do the actual seeking */
2868 /* index is reliable if it is complete or we do not go to far ahead */
2869 if (seeking && !demux->indexed &&
2870 seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2871 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2872 " index only up to %" GST_TIME_FORMAT,
2873 GST_TIME_ARGS (demux->index_max_time));
2874 /* stop flushing for now */
2876 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2877 /* delegate scanning and index building to task thread to avoid
2878 * occupying main (UI) loop */
2879 if (demux->seek_event)
2880 gst_event_unref (demux->seek_event);
2881 demux->seek_event = gst_event_ref (event);
2882 demux->seek_time = seeksegment.position;
2883 demux->state = FLV_STATE_SEEK;
2884 /* do not know about succes yet, but we did care and handled it */
2888 /* now index should be as reliable as it can be for current purpose */
2889 gst_flv_demux_move_to_offset (demux,
2890 gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2897 /* Stop flushing, the sinks are at time 0 now */
2898 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2902 /* Ok seek succeeded, take the newly configured segment */
2903 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2905 /* Notify about the start of a new segment */
2906 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2907 gst_element_post_message (GST_ELEMENT (demux),
2908 gst_message_new_segment_start (GST_OBJECT (demux),
2909 demux->segment.format, demux->segment.position));
2912 /* Tell all the stream a new segment is needed */
2913 demux->audio_need_segment = TRUE;
2914 demux->video_need_segment = TRUE;
2915 /* Clean any potential newsegment event kept for the streams. The first
2916 * stream needing a new segment will create a new one. */
2917 if (G_UNLIKELY (demux->new_seg_event)) {
2918 gst_event_unref (demux->new_seg_event);
2919 demux->new_seg_event = NULL;
2921 if (demux->segment.rate < 0.0) {
2922 /* we can't generate a segment by locking on
2923 * to the first timestamp we see */
2924 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2925 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2926 GST_TIME_ARGS (demux->segment.start),
2927 GST_TIME_ARGS (demux->segment.stop));
2928 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2933 GST_OBJECT_LOCK (demux);
2934 seeking = demux->seeking && !seeking;
2935 demux->seeking = FALSE;
2936 GST_OBJECT_UNLOCK (demux);
2938 /* if we detect an external seek having started (and possibly already having
2939 * flushed), do not restart task to give it a chance.
2940 * Otherwise external one's flushing will take care to pause task */
2942 gst_pad_pause_task (demux->sinkpad);
2944 gst_pad_start_task (demux->sinkpad,
2945 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad, NULL);
2948 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2950 gst_event_unref (event);
2956 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2957 gst_event_unref (event);
2962 /* If we can pull that's prefered */
2964 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
2969 query = gst_query_new_scheduling ();
2971 if (!gst_pad_peer_query (sinkpad, query)) {
2972 gst_query_unref (query);
2976 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
2977 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
2978 gst_query_unref (query);
2983 GST_DEBUG_OBJECT (sinkpad, "activating pull");
2984 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
2988 GST_DEBUG_OBJECT (sinkpad, "activating push");
2989 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
2994 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
2995 GstPadMode mode, gboolean active)
3000 demux = GST_FLV_DEMUX (parent);
3003 case GST_PAD_MODE_PUSH:
3004 demux->random_access = FALSE;
3007 case GST_PAD_MODE_PULL:
3009 demux->random_access = TRUE;
3010 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
3013 demux->random_access = FALSE;
3014 res = gst_pad_stop_task (sinkpad);
3025 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
3028 gboolean ret = FALSE;
3030 demux = GST_FLV_DEMUX (parent);
3032 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3034 switch (GST_EVENT_TYPE (event)) {
3035 case GST_EVENT_FLUSH_START:
3036 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
3037 demux->flushing = TRUE;
3038 ret = gst_flv_demux_push_src_event (demux, event);
3040 case GST_EVENT_FLUSH_STOP:
3041 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
3042 gst_flv_demux_flush (demux, TRUE);
3043 ret = gst_flv_demux_push_src_event (demux, event);
3049 GST_DEBUG_OBJECT (demux, "received EOS");
3051 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
3054 GST_DEBUG_OBJECT (demux, "committing index");
3055 gst_index_commit (index, demux->index_id);
3056 gst_object_unref (index);
3059 if (!demux->audio_pad && !demux->video_pad)
3060 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
3061 ("Internal data stream error."), ("Got EOS before any data"));
3063 if (!demux->no_more_pads) {
3064 gst_element_no_more_pads (GST_ELEMENT (demux));
3065 demux->no_more_pads = TRUE;
3068 if (!gst_flv_demux_push_src_event (demux, event))
3069 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
3074 case GST_EVENT_SEGMENT:
3076 GstSegment in_segment;
3078 GST_DEBUG_OBJECT (demux, "received new segment");
3080 gst_event_copy_segment (event, &in_segment);
3082 if (in_segment.format == GST_FORMAT_TIME) {
3083 /* time segment, this is perfect, copy over the values. */
3084 memcpy (&demux->segment, &in_segment, sizeof (in_segment));
3086 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
3090 ret = gst_flv_demux_push_src_event (demux, event);
3092 /* non-time format */
3093 demux->audio_need_segment = TRUE;
3094 demux->video_need_segment = TRUE;
3096 gst_event_unref (event);
3097 if (demux->new_seg_event) {
3098 gst_event_unref (demux->new_seg_event);
3099 demux->new_seg_event = NULL;
3105 ret = gst_pad_event_default (pad, parent, event);
3113 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
3116 gboolean ret = FALSE;
3118 demux = GST_FLV_DEMUX (parent);
3120 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3122 switch (GST_EVENT_TYPE (event)) {
3123 case GST_EVENT_SEEK:
3124 if (demux->random_access) {
3125 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
3127 ret = gst_flv_demux_handle_seek_push (demux, event);
3131 ret = gst_pad_push_event (demux->sinkpad, event);
3139 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
3141 gboolean res = TRUE;
3144 demux = GST_FLV_DEMUX (parent);
3146 switch (GST_QUERY_TYPE (query)) {
3147 case GST_QUERY_DURATION:
3151 gst_query_parse_duration (query, &format, NULL);
3153 /* duration is time only */
3154 if (format != GST_FORMAT_TIME) {
3155 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
3161 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3162 GST_TIME_ARGS (demux->duration));
3164 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3168 case GST_QUERY_POSITION:
3172 gst_query_parse_position (query, &format, NULL);
3174 /* position is time only */
3175 if (format != GST_FORMAT_TIME) {
3176 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3182 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3183 GST_TIME_ARGS (demux->segment.position));
3185 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3190 case GST_QUERY_SEEKING:{
3193 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3195 /* First ask upstream */
3196 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3199 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3206 /* FIXME, check index this way is not thread safe */
3207 if (fmt != GST_FORMAT_TIME || !demux->index) {
3208 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3209 } else if (demux->random_access) {
3210 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3213 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3214 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3217 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3218 gst_query_unref (peerquery);
3221 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3224 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3228 case GST_QUERY_SEGMENT:
3233 format = demux->segment.format;
3236 gst_segment_to_stream_time (&demux->segment, format,
3237 demux->segment.start);
3238 if ((stop = demux->segment.stop) == -1)
3239 stop = demux->segment.duration;
3241 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
3243 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
3247 case GST_QUERY_LATENCY:
3249 res = gst_pad_query_default (pad, parent, query);
3258 static GstStateChangeReturn
3259 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3262 GstStateChangeReturn ret;
3264 demux = GST_FLV_DEMUX (element);
3266 switch (transition) {
3267 case GST_STATE_CHANGE_READY_TO_PAUSED:
3268 /* If this is our own index destroy it as the
3269 * old entries might be wrong for the new stream */
3270 if (demux->own_index) {
3271 gst_object_unref (demux->index);
3272 demux->index = NULL;
3273 demux->own_index = FALSE;
3276 /* If no index was created, generate one */
3277 if (G_UNLIKELY (!demux->index)) {
3278 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3280 demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3282 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3284 demux->own_index = TRUE;
3286 gst_flv_demux_cleanup (demux);
3292 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3293 if (ret == GST_STATE_CHANGE_FAILURE)
3296 switch (transition) {
3297 case GST_STATE_CHANGE_PAUSED_TO_READY:
3298 gst_flv_demux_cleanup (demux);
3309 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3311 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3312 GstIndex *old_index;
3314 GST_OBJECT_LOCK (demux);
3316 old_index = demux->index;
3319 demux->index = gst_object_ref (index);
3320 demux->own_index = FALSE;
3322 demux->index = NULL;
3325 gst_object_unref (demux->index);
3327 gst_object_ref (index);
3329 GST_OBJECT_UNLOCK (demux);
3331 /* object lock might be taken again */
3333 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3335 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3337 gst_object_unref (index);
3342 gst_flv_demux_get_index (GstElement * element)
3344 GstIndex *result = NULL;
3346 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3348 GST_OBJECT_LOCK (demux);
3350 result = gst_object_ref (demux->index);
3351 GST_OBJECT_UNLOCK (demux);
3357 gst_flv_demux_dispose (GObject * object)
3359 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3361 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3363 if (demux->adapter) {
3364 gst_adapter_clear (demux->adapter);
3365 g_object_unref (demux->adapter);
3366 demux->adapter = NULL;
3369 if (demux->taglist) {
3370 gst_tag_list_unref (demux->taglist);
3371 demux->taglist = NULL;
3374 if (demux->new_seg_event) {
3375 gst_event_unref (demux->new_seg_event);
3376 demux->new_seg_event = NULL;
3379 if (demux->audio_codec_data) {
3380 gst_buffer_unref (demux->audio_codec_data);
3381 demux->audio_codec_data = NULL;
3384 if (demux->video_codec_data) {
3385 gst_buffer_unref (demux->video_codec_data);
3386 demux->video_codec_data = NULL;
3389 if (demux->audio_pad) {
3390 gst_object_unref (demux->audio_pad);
3391 demux->audio_pad = NULL;
3394 if (demux->video_pad) {
3395 gst_object_unref (demux->video_pad);
3396 demux->video_pad = NULL;
3400 gst_object_unref (demux->index);
3401 demux->index = NULL;
3405 g_array_free (demux->times, TRUE);
3406 demux->times = NULL;
3409 if (demux->filepositions) {
3410 g_array_free (demux->filepositions, TRUE);
3411 demux->filepositions = NULL;
3414 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3418 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3420 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3421 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3423 gobject_class->dispose = gst_flv_demux_dispose;
3425 gstelement_class->change_state =
3426 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3429 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3430 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3433 gst_element_class_add_pad_template (gstelement_class,
3434 gst_static_pad_template_get (&flv_sink_template));
3435 gst_element_class_add_pad_template (gstelement_class,
3436 gst_static_pad_template_get (&audio_src_template));
3437 gst_element_class_add_pad_template (gstelement_class,
3438 gst_static_pad_template_get (&video_src_template));
3439 gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
3441 "Demux FLV feeds into digital streams",
3442 "Julien Moutte <julien@moutte.net>");
3446 gst_flv_demux_init (GstFlvDemux * demux)
3449 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3451 gst_pad_set_event_function (demux->sinkpad,
3452 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3453 gst_pad_set_chain_function (demux->sinkpad,
3454 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3455 gst_pad_set_activate_function (demux->sinkpad,
3456 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3457 gst_pad_set_activatemode_function (demux->sinkpad,
3458 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3460 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3462 demux->adapter = gst_adapter_new ();
3463 demux->taglist = gst_tag_list_new_empty ();
3464 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3466 demux->own_index = FALSE;
3468 GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3470 gst_flv_demux_cleanup (demux);
3474 plugin_init (GstPlugin * plugin)
3476 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3478 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3479 gst_flv_demux_get_type ()) ||
3480 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3481 gst_flv_mux_get_type ()))
3487 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3488 flv, "FLV muxing and demuxing plugin",
3489 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)