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];
1686 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1687 * 4 bytes of previous tag size */
1688 demux->tag_data_size = GST_READ_UINT24_BE (map.data + 1);
1689 demux->tag_size = demux->tag_data_size + 11;
1691 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1692 demux->tag_data_size);
1694 gst_buffer_unmap (buffer, &map);
1698 demux->state = FLV_STATE_TAG_VIDEO;
1699 demux->has_video = TRUE;
1702 demux->state = FLV_STATE_TAG_AUDIO;
1703 demux->has_audio = TRUE;
1706 demux->state = FLV_STATE_TAG_SCRIPT;
1709 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1710 demux->state = FLV_STATE_SKIP;
1716 static GstFlowReturn
1717 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1719 GstFlowReturn ret = GST_FLOW_OK;
1722 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1724 gst_buffer_map (buffer, &map, GST_MAP_READ);
1726 /* Check for the FLV tag */
1727 if (map.data[0] == 'F' && map.data[1] == 'L' && map.data[2] == 'V') {
1728 GST_DEBUG_OBJECT (demux, "FLV header detected");
1730 if (G_UNLIKELY (demux->strict)) {
1731 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1737 if (map.data[3] == '1') {
1738 GST_DEBUG_OBJECT (demux, "FLV version 1 detected");
1740 if (G_UNLIKELY (demux->strict)) {
1741 GST_WARNING_OBJECT (demux, "invalid header version detected");
1748 /* Now look at audio/video flags */
1750 guint8 flags = map.data[4];
1752 demux->has_video = demux->has_audio = FALSE;
1755 GST_DEBUG_OBJECT (demux, "there is a video stream");
1756 demux->has_video = TRUE;
1759 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1760 demux->has_audio = TRUE;
1764 /* do a one-time seekability check */
1765 gst_flv_demux_check_seekability (demux);
1767 /* We don't care about the rest */
1768 demux->need_header = FALSE;
1771 gst_buffer_unmap (buffer, &map);
1777 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1779 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1781 gst_adapter_clear (demux->adapter);
1783 demux->audio_need_discont = TRUE;
1784 demux->video_need_discont = TRUE;
1786 demux->flushing = FALSE;
1788 /* Only in push mode and if we're not during a seek */
1789 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1790 /* After a flush we expect a tag_type */
1791 demux->state = FLV_STATE_TAG_TYPE;
1792 /* We reset the offset and will get one from first push */
1798 gst_flv_demux_cleanup (GstFlvDemux * demux)
1800 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1802 demux->state = FLV_STATE_HEADER;
1804 demux->have_group_id = FALSE;
1805 demux->group_id = G_MAXUINT;
1807 demux->flushing = FALSE;
1808 demux->need_header = TRUE;
1809 demux->audio_need_segment = TRUE;
1810 demux->video_need_segment = TRUE;
1811 demux->audio_need_discont = TRUE;
1812 demux->video_need_discont = TRUE;
1814 /* By default we consider them as linked */
1815 demux->audio_linked = TRUE;
1816 demux->video_linked = TRUE;
1818 demux->has_audio = FALSE;
1819 demux->has_video = FALSE;
1820 demux->push_tags = FALSE;
1821 demux->got_par = FALSE;
1823 demux->indexed = FALSE;
1824 demux->upstream_seekable = FALSE;
1825 demux->file_size = 0;
1827 demux->index_max_pos = 0;
1828 demux->index_max_time = 0;
1830 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1831 demux->last_audio_pts = demux->last_video_pts = 0;
1832 demux->audio_time_offset = demux->video_time_offset = 0;
1834 demux->no_more_pads = FALSE;
1836 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1838 demux->w = demux->h = 0;
1839 demux->framerate = 0.0;
1840 demux->par_x = demux->par_y = 1;
1841 demux->video_offset = 0;
1842 demux->audio_offset = 0;
1843 demux->offset = demux->cur_tag_offset = 0;
1844 demux->tag_size = demux->tag_data_size = 0;
1845 demux->duration = GST_CLOCK_TIME_NONE;
1847 if (demux->new_seg_event) {
1848 gst_event_unref (demux->new_seg_event);
1849 demux->new_seg_event = NULL;
1852 gst_adapter_clear (demux->adapter);
1854 if (demux->audio_codec_data) {
1855 gst_buffer_unref (demux->audio_codec_data);
1856 demux->audio_codec_data = NULL;
1859 if (demux->video_codec_data) {
1860 gst_buffer_unref (demux->video_codec_data);
1861 demux->video_codec_data = NULL;
1864 if (demux->audio_pad) {
1865 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1866 gst_object_unref (demux->audio_pad);
1867 demux->audio_pad = NULL;
1870 if (demux->video_pad) {
1871 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1872 gst_object_unref (demux->video_pad);
1873 demux->video_pad = NULL;
1877 g_array_free (demux->times, TRUE);
1878 demux->times = NULL;
1881 if (demux->filepositions) {
1882 g_array_free (demux->filepositions, TRUE);
1883 demux->filepositions = NULL;
1888 * Create and push a flushing seek event upstream
1891 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1896 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1899 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1900 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1901 GST_SEEK_TYPE_NONE, -1);
1903 res = gst_pad_push_event (demux->sinkpad, event);
1906 demux->offset = offset;
1910 static GstFlowReturn
1911 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1913 GstFlowReturn ret = GST_FLOW_OK;
1914 GstFlvDemux *demux = NULL;
1916 demux = GST_FLV_DEMUX (parent);
1918 GST_LOG_OBJECT (demux,
1919 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
1920 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
1921 GST_BUFFER_OFFSET (buffer));
1923 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1924 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1925 demux->state = FLV_STATE_HEADER;
1929 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
1930 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
1931 demux->offset = GST_BUFFER_OFFSET (buffer);
1934 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1935 GST_DEBUG_OBJECT (demux, "Discontinuity");
1936 gst_adapter_clear (demux->adapter);
1939 gst_adapter_push (demux->adapter, buffer);
1941 if (demux->seeking) {
1942 demux->state = FLV_STATE_SEEK;
1943 GST_OBJECT_LOCK (demux);
1944 demux->seeking = FALSE;
1945 GST_OBJECT_UNLOCK (demux);
1949 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1950 if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
1951 || demux->video_linked)) {
1954 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
1959 if (G_UNLIKELY (demux->flushing)) {
1960 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
1961 ret = GST_FLOW_FLUSHING;
1965 switch (demux->state) {
1966 case FLV_STATE_HEADER:
1968 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
1971 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
1973 ret = gst_flv_demux_parse_header (demux, buffer);
1975 gst_buffer_unref (buffer);
1976 demux->offset += FLV_HEADER_SIZE;
1978 demux->state = FLV_STATE_TAG_TYPE;
1984 case FLV_STATE_TAG_TYPE:
1986 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
1989 /* Remember the tag offset in bytes */
1990 demux->cur_tag_offset = demux->offset;
1992 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
1994 ret = gst_flv_demux_parse_tag_type (demux, buffer);
1996 gst_buffer_unref (buffer);
1997 demux->offset += FLV_TAG_TYPE_SIZE;
1999 /* last tag is not an index => no index/don't know where the index is
2000 * seek back to the beginning */
2001 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
2009 case FLV_STATE_TAG_VIDEO:
2011 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2014 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2016 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2018 gst_buffer_unref (buffer);
2019 demux->offset += demux->tag_size;
2021 demux->state = FLV_STATE_TAG_TYPE;
2027 case FLV_STATE_TAG_AUDIO:
2029 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2032 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2034 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2036 gst_buffer_unref (buffer);
2037 demux->offset += demux->tag_size;
2039 demux->state = FLV_STATE_TAG_TYPE;
2045 case FLV_STATE_TAG_SCRIPT:
2047 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2050 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2052 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2054 gst_buffer_unref (buffer);
2055 demux->offset += demux->tag_size;
2057 demux->state = FLV_STATE_TAG_TYPE;
2059 /* if there's a seek event we're here for the index so if we don't have it
2060 * we seek back to the beginning */
2061 if (demux->seek_event) {
2063 demux->state = FLV_STATE_SEEK;
2073 case FLV_STATE_SEEK:
2079 if (!demux->indexed) {
2080 if (demux->offset == demux->file_size - sizeof (guint32)) {
2081 guint64 seek_offset;
2084 data = gst_adapter_take (demux->adapter, 4);
2088 seek_offset = demux->file_size - sizeof (guint32) -
2089 GST_READ_UINT32_BE (data);
2092 GST_INFO_OBJECT (demux,
2093 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
2095 demux->state = FLV_STATE_TAG_TYPE;
2096 flv_demux_seek_to_offset (demux, seek_offset);
2102 GST_OBJECT_LOCK (demux);
2103 event = demux->seek_event;
2104 demux->seek_event = NULL;
2105 GST_OBJECT_UNLOCK (demux);
2107 /* calculate and perform seek */
2108 if (!flv_demux_handle_seek_push (demux, event))
2111 gst_event_unref (event);
2112 demux->state = FLV_STATE_TAG_TYPE;
2115 case FLV_STATE_SKIP:
2116 /* Skip unknown tags (set in _parse_tag_type()) */
2117 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2118 gst_adapter_flush (demux->adapter, demux->tag_size);
2119 demux->offset += demux->tag_size;
2120 demux->state = FLV_STATE_TAG_TYPE;
2126 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
2130 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2131 /* If either audio or video is linked we return GST_FLOW_OK */
2132 if (demux->audio_linked || demux->video_linked) {
2142 GST_OBJECT_LOCK (demux);
2143 demux->seeking = FALSE;
2144 gst_event_unref (demux->seek_event);
2145 demux->seek_event = NULL;
2146 GST_OBJECT_UNLOCK (demux);
2147 GST_WARNING_OBJECT (demux,
2148 "failed to find an index, seeking back to beginning");
2149 flv_demux_seek_to_offset (demux, 0);
2154 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2155 return GST_FLOW_ERROR;
2160 static GstFlowReturn
2161 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2162 guint size, GstBuffer ** buffer)
2166 ret = gst_pad_pull_range (pad, offset, size, buffer);
2167 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2168 GST_WARNING_OBJECT (demux,
2169 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2170 size, offset, gst_flow_get_name (ret));
2175 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2176 GST_WARNING_OBJECT (demux,
2177 "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
2178 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
2179 gst_buffer_unref (*buffer);
2188 static GstFlowReturn
2189 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2191 GstBuffer *buffer = NULL;
2192 GstFlowReturn ret = GST_FLOW_OK;
2194 /* Store tag offset */
2195 demux->cur_tag_offset = demux->offset;
2197 /* Get the first 4 bytes to identify tag type and size */
2198 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2199 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2202 /* Identify tag type */
2203 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2205 gst_buffer_unref (buffer);
2207 if (G_UNLIKELY (ret != GST_FLOW_OK))
2210 /* Jump over tag type + size */
2211 demux->offset += FLV_TAG_TYPE_SIZE;
2213 /* Pull the whole tag */
2215 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2216 demux->tag_size, &buffer)) != GST_FLOW_OK))
2219 switch (demux->state) {
2220 case FLV_STATE_TAG_VIDEO:
2221 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2223 case FLV_STATE_TAG_AUDIO:
2224 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2226 case FLV_STATE_TAG_SCRIPT:
2227 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2230 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2233 gst_buffer_unref (buffer);
2235 /* Jump over that part we've just parsed */
2236 demux->offset += demux->tag_size;
2238 /* Make sure we reinitialize the tag size */
2239 demux->tag_size = 0;
2241 /* Ready for the next tag */
2242 demux->state = FLV_STATE_TAG_TYPE;
2244 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2245 /* If either audio or video is linked we return GST_FLOW_OK */
2246 if (demux->audio_linked || demux->video_linked) {
2249 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2250 "neither video nor audio are linked");
2258 static GstFlowReturn
2259 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2261 GstBuffer *buffer = NULL;
2262 GstFlowReturn ret = GST_FLOW_OK;
2264 /* Get the first 9 bytes */
2265 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2266 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2269 ret = gst_flv_demux_parse_header (demux, buffer);
2271 gst_buffer_unref (buffer);
2273 /* Jump over the header now */
2274 demux->offset += FLV_HEADER_SIZE;
2275 demux->state = FLV_STATE_TAG_TYPE;
2282 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2285 demux->offset = offset;
2287 /* Tell all the stream we moved to a different position (discont) */
2288 demux->audio_need_discont = TRUE;
2289 demux->video_need_discont = TRUE;
2291 /* next section setup */
2292 demux->from_offset = -1;
2293 demux->audio_done = demux->video_done = FALSE;
2294 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2297 demux->from_offset = -1;
2298 demux->to_offset = G_MAXINT64;
2301 /* If we seeked at the beginning of the file parse the header again */
2302 if (G_UNLIKELY (!demux->offset)) {
2303 demux->state = FLV_STATE_HEADER;
2304 } else { /* or parse a tag */
2305 demux->state = FLV_STATE_TAG_TYPE;
2309 static GstFlowReturn
2310 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2312 GstFlowReturn ret = GST_FLOW_EOS;
2314 GstIndexEntry *entry = NULL;
2316 GST_DEBUG_OBJECT (demux,
2317 "terminated section started at offset %" G_GINT64_FORMAT,
2318 demux->from_offset);
2320 /* we are done if we got all audio and video */
2321 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2322 demux->audio_first_ts < demux->segment.start) &&
2323 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2324 demux->video_first_ts < demux->segment.start))
2327 if (demux->from_offset <= 0)
2330 GST_DEBUG_OBJECT (demux, "locating previous position");
2332 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2334 /* locate index entry before previous start position */
2336 entry = gst_index_get_assoc_entry (index, demux->index_id,
2337 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2338 GST_FORMAT_BYTES, demux->from_offset - 1);
2341 gint64 bytes = 0, time = 0;
2343 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2344 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2346 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2347 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2348 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2350 /* setup for next section */
2351 demux->to_offset = demux->from_offset;
2352 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2356 gst_object_unref (index);
2364 static GstFlowReturn
2365 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2371 GstClockTime tag_time;
2372 GstFlowReturn ret = GST_FLOW_OK;
2374 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2377 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2378 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2380 old_offset = demux->offset;
2381 demux->offset = pos;
2384 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2385 12, &buffer)) == GST_FLOW_OK) {
2387 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2389 gst_buffer_unref (buffer);
2392 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2395 demux->offset += tag_size;
2398 if (ret == GST_FLOW_EOS) {
2399 /* file ran out, so mark we have complete index */
2400 demux->indexed = TRUE;
2405 demux->offset = old_offset;
2411 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2413 gint64 ret = 0, offset;
2414 size_t tag_size, size;
2415 GstBuffer *buffer = NULL;
2418 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2422 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2423 if (G_UNLIKELY (offset < 4))
2427 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2431 gst_buffer_map (buffer, &map, GST_MAP_READ);
2432 tag_size = GST_READ_UINT32_BE (map.data);
2433 gst_buffer_unmap (buffer, &map);
2434 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2435 gst_buffer_unref (buffer);
2439 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2443 /* a consistency check */
2444 gst_buffer_map (buffer, &map, GST_MAP_READ);
2445 size = GST_READ_UINT24_BE (map.data + 1);
2446 if (size != tag_size - 11) {
2447 gst_buffer_unmap (buffer, &map);
2448 GST_DEBUG_OBJECT (demux,
2449 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2450 ", corrupt or truncated file", size, tag_size - 11);
2454 /* try to update duration with timestamp in any case */
2455 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2457 /* maybe get some more metadata */
2458 if (map.data[0] == 18) {
2459 gst_buffer_unmap (buffer, &map);
2460 gst_buffer_unref (buffer);
2462 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2464 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2466 gst_flv_demux_parse_tag_script (demux, buffer);
2468 gst_buffer_unmap (buffer, &map);
2473 gst_buffer_unref (buffer);
2479 gst_flv_demux_loop (GstPad * pad)
2481 GstFlvDemux *demux = NULL;
2482 GstFlowReturn ret = GST_FLOW_OK;
2484 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2487 switch (demux->state) {
2488 case FLV_STATE_TAG_TYPE:
2489 if (demux->from_offset == -1)
2490 demux->from_offset = demux->offset;
2491 ret = gst_flv_demux_pull_tag (pad, demux);
2492 /* if we have seen real data, we probably passed a possible metadata
2493 * header located at start. So if we do not yet have an index,
2494 * try to pick up metadata (index, duration) at the end */
2495 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2496 (demux->has_video || demux->has_audio)))
2497 demux->file_size = gst_flv_demux_get_metadata (demux);
2499 case FLV_STATE_DONE:
2502 case FLV_STATE_SEEK:
2503 /* seek issued with insufficient index;
2504 * scan for index in task thread from current maximum offset to
2505 * desired time and then perform seek */
2506 /* TODO maybe some buffering message or so to indicate scan progress */
2507 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2509 if (ret != GST_FLOW_OK)
2511 /* position and state arranged by seek,
2512 * also unrefs event */
2513 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2514 demux->seek_event = NULL;
2517 ret = gst_flv_demux_pull_header (pad, demux);
2518 /* index scans start after header */
2519 demux->index_max_pos = demux->offset;
2523 if (demux->segment.rate < 0.0) {
2524 /* check end of section */
2525 if ((gint64) demux->offset >= demux->to_offset ||
2526 demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2527 (demux->audio_done && demux->video_done))
2528 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2530 /* check EOS condition */
2531 if ((demux->segment.stop != -1) &&
2532 (demux->segment.position >= demux->segment.stop)) {
2537 /* pause if something went wrong or at end */
2538 if (G_UNLIKELY (ret != GST_FLOW_OK))
2541 gst_object_unref (demux);
2547 const gchar *reason = gst_flow_get_name (ret);
2549 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2550 gst_pad_pause_task (pad);
2552 if (ret == GST_FLOW_EOS) {
2553 /* handle end-of-stream/segment */
2554 /* so align our position with the end of it, if there is one
2555 * this ensures a subsequent will arrive at correct base/acc time */
2556 if (demux->segment.rate > 0.0 &&
2557 GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2558 demux->segment.position = demux->segment.stop;
2559 else if (demux->segment.rate < 0.0)
2560 demux->segment.position = demux->segment.start;
2562 /* perform EOS logic */
2563 if (!demux->no_more_pads) {
2564 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2565 demux->no_more_pads = TRUE;
2568 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2571 /* for segment playback we need to post when (in stream time)
2572 * we stopped, this is either stop (when set) or the duration. */
2573 if ((stop = demux->segment.stop) == -1)
2574 stop = demux->segment.duration;
2576 if (demux->segment.rate >= 0) {
2577 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2578 gst_element_post_message (GST_ELEMENT_CAST (demux),
2579 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2580 GST_FORMAT_TIME, stop));
2581 gst_flv_demux_push_src_event (demux,
2582 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2583 } else { /* Reverse playback */
2584 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2586 gst_element_post_message (GST_ELEMENT_CAST (demux),
2587 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2588 GST_FORMAT_TIME, demux->segment.start));
2589 gst_flv_demux_push_src_event (demux,
2590 gst_event_new_segment_done (GST_FORMAT_TIME,
2591 demux->segment.start));
2594 /* normal playback, send EOS to all linked pads */
2595 if (!demux->no_more_pads) {
2596 gst_element_no_more_pads (GST_ELEMENT (demux));
2597 demux->no_more_pads = TRUE;
2600 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2601 if (!demux->audio_pad && !demux->video_pad)
2602 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2603 ("Internal data stream error."), ("Got EOS before any data"));
2604 else if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2605 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2607 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2608 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2609 ("Internal data stream error."),
2610 ("stream stopped, reason %s", reason));
2611 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2613 gst_object_unref (demux);
2619 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2624 GstIndexEntry *entry;
2626 g_return_val_if_fail (segment != NULL, 0);
2628 time = segment->position;
2630 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2633 /* Let's check if we have an index entry for that seek time */
2634 entry = gst_index_get_assoc_entry (index, demux->index_id,
2635 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2636 GST_FORMAT_TIME, time);
2639 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2640 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2642 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2643 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2644 GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2646 /* Key frame seeking */
2647 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2648 /* Adjust the segment so that the keyframe fits in */
2649 if (time < segment->start) {
2650 segment->start = segment->time = time;
2652 segment->position = time;
2655 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2656 GST_TIME_ARGS (segment->start));
2659 gst_object_unref (index);
2666 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2670 GstSeekType start_type, stop_type;
2673 gboolean update, flush, ret;
2674 GstSegment seeksegment;
2676 gst_event_parse_seek (event, &rate, &format, &flags,
2677 &start_type, &start, &stop_type, &stop);
2679 if (format != GST_FORMAT_TIME)
2682 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2683 /* FIXME : the keyframe flag is never used ! */
2685 /* Work on a copy until we are sure the seek succeeded. */
2686 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2688 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2691 /* Apply the seek to our segment */
2692 gst_segment_do_seek (&seeksegment, rate, format, flags,
2693 start_type, start, stop_type, stop, &update);
2695 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2698 if (flush || seeksegment.position != demux->segment.position) {
2699 /* Do the actual seeking */
2700 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2702 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2703 G_GUINT64_FORMAT, offset);
2704 ret = gst_pad_push_event (demux->sinkpad,
2705 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2706 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2707 offset, GST_SEEK_TYPE_NONE, 0));
2708 if (G_UNLIKELY (!ret)) {
2709 GST_WARNING_OBJECT (demux, "upstream seek failed");
2712 /* Tell all the stream we moved to a different position (discont) */
2713 demux->audio_need_discont = TRUE;
2714 demux->video_need_discont = TRUE;
2720 /* Ok seek succeeded, take the newly configured segment */
2721 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2723 /* Tell all the stream a new segment is needed */
2724 demux->audio_need_segment = TRUE;
2725 demux->video_need_segment = TRUE;
2726 /* Clean any potential newsegment event kept for the streams. The first
2727 * stream needing a new segment will create a new one. */
2728 if (G_UNLIKELY (demux->new_seg_event)) {
2729 gst_event_unref (demux->new_seg_event);
2730 demux->new_seg_event = NULL;
2732 gst_event_unref (event);
2734 ret = gst_pad_push_event (demux->sinkpad, event);
2742 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2743 gst_event_unref (event);
2749 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2753 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2755 if (format != GST_FORMAT_TIME) {
2756 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2757 gst_event_unref (event);
2761 /* First try upstream */
2762 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2763 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2764 gst_event_unref (event);
2768 if (!demux->indexed) {
2769 guint64 seek_offset = 0;
2770 gboolean building_index;
2772 GST_OBJECT_LOCK (demux);
2773 /* handle the seek in the chain function */
2774 demux->seeking = TRUE;
2775 demux->state = FLV_STATE_SEEK;
2777 /* copy the event */
2778 if (demux->seek_event)
2779 gst_event_unref (demux->seek_event);
2780 demux->seek_event = gst_event_ref (event);
2782 /* set the building_index flag so that only one thread can setup the
2783 * structures for index seeking. */
2784 building_index = demux->building_index;
2785 if (!building_index) {
2786 demux->building_index = TRUE;
2787 if (!demux->file_size
2788 && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2789 &demux->file_size)) {
2790 GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2791 GST_OBJECT_UNLOCK (demux);
2795 /* we hope the last tag is a scriptdataobject containing an index
2796 * the size of the last tag is given in the last guint32 bits
2797 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2798 seek_offset = demux->file_size - sizeof (guint32);
2799 GST_DEBUG_OBJECT (demux,
2800 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2802 GST_OBJECT_UNLOCK (demux);
2804 if (!building_index) {
2805 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2807 return flv_demux_seek_to_offset (demux, seek_offset);
2810 /* FIXME: we have to always return true so that we don't block the seek
2812 * Note: maybe it is OK to return true if we're still building the index */
2816 return flv_demux_handle_seek_push (demux, event);
2820 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2825 GstSeekType start_type, stop_type;
2828 gboolean update, flush, ret = FALSE;
2829 GstSegment seeksegment;
2831 gst_event_parse_seek (event, &rate, &format, &flags,
2832 &start_type, &start, &stop_type, &stop);
2834 if (format != GST_FORMAT_TIME)
2837 /* mark seeking thread entering flushing/pausing */
2838 GST_OBJECT_LOCK (demux);
2840 demux->seeking = seeking;
2841 GST_OBJECT_UNLOCK (demux);
2843 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2844 /* FIXME : the keyframe flag is never used */
2847 /* Flush start up and downstream to make sure data flow and loops are
2849 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2850 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2852 /* Pause the pulling task */
2853 gst_pad_pause_task (demux->sinkpad);
2856 /* Take the stream lock */
2857 GST_PAD_STREAM_LOCK (demux->sinkpad);
2860 /* Stop flushing upstream we need to pull */
2861 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2864 /* Work on a copy until we are sure the seek succeeded. */
2865 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2867 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2870 /* Apply the seek to our segment */
2871 gst_segment_do_seek (&seeksegment, rate, format, flags,
2872 start_type, start, stop_type, stop, &update);
2874 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2877 if (flush || seeksegment.position != demux->segment.position) {
2878 /* Do the actual seeking */
2879 /* index is reliable if it is complete or we do not go to far ahead */
2880 if (seeking && !demux->indexed &&
2881 seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2882 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2883 " index only up to %" GST_TIME_FORMAT,
2884 GST_TIME_ARGS (demux->index_max_time));
2885 /* stop flushing for now */
2887 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2888 /* delegate scanning and index building to task thread to avoid
2889 * occupying main (UI) loop */
2890 if (demux->seek_event)
2891 gst_event_unref (demux->seek_event);
2892 demux->seek_event = gst_event_ref (event);
2893 demux->seek_time = seeksegment.position;
2894 demux->state = FLV_STATE_SEEK;
2895 /* do not know about succes yet, but we did care and handled it */
2899 /* now index should be as reliable as it can be for current purpose */
2900 gst_flv_demux_move_to_offset (demux,
2901 gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2908 /* Stop flushing, the sinks are at time 0 now */
2909 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2913 /* Ok seek succeeded, take the newly configured segment */
2914 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2916 /* Notify about the start of a new segment */
2917 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2918 gst_element_post_message (GST_ELEMENT (demux),
2919 gst_message_new_segment_start (GST_OBJECT (demux),
2920 demux->segment.format, demux->segment.position));
2923 /* Tell all the stream a new segment is needed */
2924 demux->audio_need_segment = TRUE;
2925 demux->video_need_segment = TRUE;
2926 /* Clean any potential newsegment event kept for the streams. The first
2927 * stream needing a new segment will create a new one. */
2928 if (G_UNLIKELY (demux->new_seg_event)) {
2929 gst_event_unref (demux->new_seg_event);
2930 demux->new_seg_event = NULL;
2932 if (demux->segment.rate < 0.0) {
2933 /* we can't generate a segment by locking on
2934 * to the first timestamp we see */
2935 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2936 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2937 GST_TIME_ARGS (demux->segment.start),
2938 GST_TIME_ARGS (demux->segment.stop));
2939 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2944 GST_OBJECT_LOCK (demux);
2945 seeking = demux->seeking && !seeking;
2946 demux->seeking = FALSE;
2947 GST_OBJECT_UNLOCK (demux);
2949 /* if we detect an external seek having started (and possibly already having
2950 * flushed), do not restart task to give it a chance.
2951 * Otherwise external one's flushing will take care to pause task */
2953 gst_pad_pause_task (demux->sinkpad);
2955 gst_pad_start_task (demux->sinkpad,
2956 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad, NULL);
2959 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2961 gst_event_unref (event);
2967 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2968 gst_event_unref (event);
2973 /* If we can pull that's prefered */
2975 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
2980 query = gst_query_new_scheduling ();
2982 if (!gst_pad_peer_query (sinkpad, query)) {
2983 gst_query_unref (query);
2987 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
2988 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
2989 gst_query_unref (query);
2994 GST_DEBUG_OBJECT (sinkpad, "activating pull");
2995 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
2999 GST_DEBUG_OBJECT (sinkpad, "activating push");
3000 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
3005 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
3006 GstPadMode mode, gboolean active)
3011 demux = GST_FLV_DEMUX (parent);
3014 case GST_PAD_MODE_PUSH:
3015 demux->random_access = FALSE;
3018 case GST_PAD_MODE_PULL:
3020 demux->random_access = TRUE;
3021 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
3024 demux->random_access = FALSE;
3025 res = gst_pad_stop_task (sinkpad);
3036 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
3039 gboolean ret = FALSE;
3041 demux = GST_FLV_DEMUX (parent);
3043 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3045 switch (GST_EVENT_TYPE (event)) {
3046 case GST_EVENT_FLUSH_START:
3047 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
3048 demux->flushing = TRUE;
3049 ret = gst_flv_demux_push_src_event (demux, event);
3051 case GST_EVENT_FLUSH_STOP:
3052 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
3053 gst_flv_demux_flush (demux, TRUE);
3054 ret = gst_flv_demux_push_src_event (demux, event);
3060 GST_DEBUG_OBJECT (demux, "received EOS");
3062 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
3065 GST_DEBUG_OBJECT (demux, "committing index");
3066 gst_index_commit (index, demux->index_id);
3067 gst_object_unref (index);
3070 if (!demux->audio_pad && !demux->video_pad)
3071 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
3072 ("Internal data stream error."), ("Got EOS before any data"));
3074 if (!demux->no_more_pads) {
3075 gst_element_no_more_pads (GST_ELEMENT (demux));
3076 demux->no_more_pads = TRUE;
3079 if (!gst_flv_demux_push_src_event (demux, event))
3080 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
3085 case GST_EVENT_SEGMENT:
3087 GstSegment in_segment;
3089 GST_DEBUG_OBJECT (demux, "received new segment");
3091 gst_event_copy_segment (event, &in_segment);
3093 if (in_segment.format == GST_FORMAT_TIME) {
3094 /* time segment, this is perfect, copy over the values. */
3095 memcpy (&demux->segment, &in_segment, sizeof (in_segment));
3097 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
3101 ret = gst_flv_demux_push_src_event (demux, event);
3103 /* non-time format */
3104 demux->audio_need_segment = TRUE;
3105 demux->video_need_segment = TRUE;
3107 gst_event_unref (event);
3108 if (demux->new_seg_event) {
3109 gst_event_unref (demux->new_seg_event);
3110 demux->new_seg_event = NULL;
3116 ret = gst_pad_event_default (pad, parent, event);
3124 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
3127 gboolean ret = FALSE;
3129 demux = GST_FLV_DEMUX (parent);
3131 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3133 switch (GST_EVENT_TYPE (event)) {
3134 case GST_EVENT_SEEK:
3135 if (demux->random_access) {
3136 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
3138 ret = gst_flv_demux_handle_seek_push (demux, event);
3142 ret = gst_pad_push_event (demux->sinkpad, event);
3150 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
3152 gboolean res = TRUE;
3155 demux = GST_FLV_DEMUX (parent);
3157 switch (GST_QUERY_TYPE (query)) {
3158 case GST_QUERY_DURATION:
3162 gst_query_parse_duration (query, &format, NULL);
3164 /* duration is time only */
3165 if (format != GST_FORMAT_TIME) {
3166 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
3172 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3173 GST_TIME_ARGS (demux->duration));
3175 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3179 case GST_QUERY_POSITION:
3183 gst_query_parse_position (query, &format, NULL);
3185 /* position is time only */
3186 if (format != GST_FORMAT_TIME) {
3187 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3193 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3194 GST_TIME_ARGS (demux->segment.position));
3196 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3201 case GST_QUERY_SEEKING:{
3204 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3206 /* First ask upstream */
3207 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3210 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3217 /* FIXME, check index this way is not thread safe */
3218 if (fmt != GST_FORMAT_TIME || !demux->index) {
3219 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3220 } else if (demux->random_access) {
3221 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3224 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3225 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3228 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3229 gst_query_unref (peerquery);
3232 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3235 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3239 case GST_QUERY_SEGMENT:
3244 format = demux->segment.format;
3247 gst_segment_to_stream_time (&demux->segment, format,
3248 demux->segment.start);
3249 if ((stop = demux->segment.stop) == -1)
3250 stop = demux->segment.duration;
3252 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
3254 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
3258 case GST_QUERY_LATENCY:
3260 res = gst_pad_query_default (pad, parent, query);
3269 static GstStateChangeReturn
3270 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3273 GstStateChangeReturn ret;
3275 demux = GST_FLV_DEMUX (element);
3277 switch (transition) {
3278 case GST_STATE_CHANGE_READY_TO_PAUSED:
3279 /* If this is our own index destroy it as the
3280 * old entries might be wrong for the new stream */
3281 if (demux->own_index) {
3282 gst_object_unref (demux->index);
3283 demux->index = NULL;
3284 demux->own_index = FALSE;
3287 /* If no index was created, generate one */
3288 if (G_UNLIKELY (!demux->index)) {
3289 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3291 demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3293 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3295 demux->own_index = TRUE;
3297 gst_flv_demux_cleanup (demux);
3303 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3304 if (ret == GST_STATE_CHANGE_FAILURE)
3307 switch (transition) {
3308 case GST_STATE_CHANGE_PAUSED_TO_READY:
3309 gst_flv_demux_cleanup (demux);
3320 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3322 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3323 GstIndex *old_index;
3325 GST_OBJECT_LOCK (demux);
3327 old_index = demux->index;
3330 demux->index = gst_object_ref (index);
3331 demux->own_index = FALSE;
3333 demux->index = NULL;
3336 gst_object_unref (demux->index);
3338 gst_object_ref (index);
3340 GST_OBJECT_UNLOCK (demux);
3342 /* object lock might be taken again */
3344 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3346 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3348 gst_object_unref (index);
3353 gst_flv_demux_get_index (GstElement * element)
3355 GstIndex *result = NULL;
3357 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3359 GST_OBJECT_LOCK (demux);
3361 result = gst_object_ref (demux->index);
3362 GST_OBJECT_UNLOCK (demux);
3368 gst_flv_demux_dispose (GObject * object)
3370 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3372 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3374 if (demux->adapter) {
3375 gst_adapter_clear (demux->adapter);
3376 g_object_unref (demux->adapter);
3377 demux->adapter = NULL;
3380 if (demux->taglist) {
3381 gst_tag_list_unref (demux->taglist);
3382 demux->taglist = NULL;
3385 if (demux->new_seg_event) {
3386 gst_event_unref (demux->new_seg_event);
3387 demux->new_seg_event = NULL;
3390 if (demux->audio_codec_data) {
3391 gst_buffer_unref (demux->audio_codec_data);
3392 demux->audio_codec_data = NULL;
3395 if (demux->video_codec_data) {
3396 gst_buffer_unref (demux->video_codec_data);
3397 demux->video_codec_data = NULL;
3400 if (demux->audio_pad) {
3401 gst_object_unref (demux->audio_pad);
3402 demux->audio_pad = NULL;
3405 if (demux->video_pad) {
3406 gst_object_unref (demux->video_pad);
3407 demux->video_pad = NULL;
3411 gst_object_unref (demux->index);
3412 demux->index = NULL;
3416 g_array_free (demux->times, TRUE);
3417 demux->times = NULL;
3420 if (demux->filepositions) {
3421 g_array_free (demux->filepositions, TRUE);
3422 demux->filepositions = NULL;
3425 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3429 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3431 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3432 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3434 gobject_class->dispose = gst_flv_demux_dispose;
3436 gstelement_class->change_state =
3437 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3440 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3441 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3444 gst_element_class_add_pad_template (gstelement_class,
3445 gst_static_pad_template_get (&flv_sink_template));
3446 gst_element_class_add_pad_template (gstelement_class,
3447 gst_static_pad_template_get (&audio_src_template));
3448 gst_element_class_add_pad_template (gstelement_class,
3449 gst_static_pad_template_get (&video_src_template));
3450 gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
3452 "Demux FLV feeds into digital streams",
3453 "Julien Moutte <julien@moutte.net>");
3457 gst_flv_demux_init (GstFlvDemux * demux)
3460 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3462 gst_pad_set_event_function (demux->sinkpad,
3463 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3464 gst_pad_set_chain_function (demux->sinkpad,
3465 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3466 gst_pad_set_activate_function (demux->sinkpad,
3467 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3468 gst_pad_set_activatemode_function (demux->sinkpad,
3469 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3471 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3473 demux->adapter = gst_adapter_new ();
3474 demux->taglist = gst_tag_list_new_empty ();
3475 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3477 demux->own_index = FALSE;
3479 GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3481 gst_flv_demux_cleanup (demux);
3485 plugin_init (GstPlugin * plugin)
3487 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3489 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3490 gst_flv_demux_get_type ()) ||
3491 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3492 gst_flv_mux_get_type ()))
3498 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3499 flv, "FLV muxing and demuxing plugin",
3500 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)