2 * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 * SECTION:element-flvdemux
23 * flvdemux demuxes an FLV file into the different contained streams.
26 * <title>Example launch line</title>
28 * gst-launch-1.0 -v filesrc location=/path/to/flv ! flvdemux ! audioconvert ! autoaudiosink
29 * ]| This pipeline demuxes an FLV file and outputs the contained raw audio streams.
37 #include "gstflvdemux.h"
38 #include "gstflvmux.h"
41 #include <gst/base/gstbytereader.h>
42 #include <gst/base/gstbytewriter.h>
43 #include <gst/pbutils/descriptions.h>
44 #include <gst/pbutils/pbutils.h>
45 #include <gst/audio/audio.h>
46 #include <gst/video/video.h>
48 /* FIXME: don't rely on own GstIndex */
50 #include "gstmemindex.c"
51 #define GST_ASSOCIATION_FLAG_NONE GST_INDEX_ASSOCIATION_FLAG_NONE
52 #define GST_ASSOCIATION_FLAG_KEY_UNIT GST_INDEX_ASSOCIATION_FLAG_KEY_UNIT
53 #define GST_ASSOCIATION_FLAG_DELTA_UNIT GST_INDEX_ASSOCIATION_FLAG_DELTA_UNIT
55 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
58 GST_STATIC_CAPS ("video/x-flv")
61 static GstStaticPadTemplate audio_src_template =
62 GST_STATIC_PAD_TEMPLATE ("audio",
66 ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
67 "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
68 "audio/mpeg, mpegversion = (int) 4, stream-format = (string) raw, framed = (boolean) TRUE; "
69 "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
70 "audio/x-raw, format = (string) { U8, S16LE }, layout = (string) interleaved, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
71 "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
72 "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
73 "audio/x-speex, channels = (int) 1, rate = (int) 16000;")
76 static GstStaticPadTemplate video_src_template =
77 GST_STATIC_PAD_TEMPLATE ("video",
80 GST_STATIC_CAPS ("video/x-flash-video, flvversion=(int) 1; "
81 "video/x-flash-screen; "
82 "video/x-vp6-flash; " "video/x-vp6-alpha; "
83 "video/x-h264, stream-format=avc;")
86 GST_DEBUG_CATEGORY_STATIC (flvdemux_debug);
87 #define GST_CAT_DEFAULT flvdemux_debug
89 #define gst_flv_demux_parent_class parent_class
90 G_DEFINE_TYPE (GstFlvDemux, gst_flv_demux, GST_TYPE_ELEMENT);
92 /* 9 bytes of header + 4 bytes of first previous tag size */
93 #define FLV_HEADER_SIZE 13
94 /* 1 byte of tag type + 3 bytes of tag data size */
95 #define FLV_TAG_TYPE_SIZE 4
97 /* two seconds - consider dts are resynced to another base if this different */
98 #define RESYNC_THRESHOLD 2000
100 static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
102 static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
103 GstEvent * event, gboolean seeking);
105 static gboolean gst_flv_demux_query (GstPad * pad, GstObject * parent,
107 static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent,
110 static GstIndex *gst_flv_demux_get_index (GstElement * element);
113 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
114 guint64 pos, gboolean keyframe)
116 GstIndexAssociation associations[2];
118 GstIndexEntry *entry;
120 GST_LOG_OBJECT (demux,
121 "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
122 keyframe, GST_TIME_ARGS (ts), pos);
124 /* if upstream is not seekable there is no point in building an index */
125 if (!demux->upstream_seekable)
128 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
133 /* entry may already have been added before, avoid adding indefinitely */
134 entry = gst_index_get_assoc_entry (index, demux->index_id,
135 GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
138 #ifndef GST_DISABLE_GST_DEBUG
142 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
143 key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
144 GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
145 ", keyframe %d", GST_TIME_ARGS (time), key);
146 /* there is not really a way to delete the existing one */
147 if (time != ts || key != ! !keyframe)
148 GST_DEBUG_OBJECT (demux, "metadata mismatch");
150 gst_object_unref (index);
154 associations[0].format = GST_FORMAT_TIME;
155 associations[0].value = ts;
156 associations[1].format = GST_FORMAT_BYTES;
157 associations[1].value = pos;
159 gst_index_add_associationv (index, demux->index_id,
160 (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
161 GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
162 (const GstIndexAssociation *) &associations);
164 if (pos > demux->index_max_pos)
165 demux->index_max_pos = pos;
166 if (ts > demux->index_max_time)
167 demux->index_max_time = ts;
169 gst_object_unref (index);
173 FLV_GET_STRING (GstByteReader * reader)
175 guint16 string_size = 0;
176 gchar *string = NULL;
177 const guint8 *str = NULL;
179 g_return_val_if_fail (reader != NULL, NULL);
181 if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
184 if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
187 string = g_try_malloc0 (string_size + 1);
188 if (G_UNLIKELY (!string)) {
192 if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
197 memcpy (string, str, string_size);
198 if (!g_utf8_validate (string, string_size, NULL)) {
207 gst_flv_demux_check_seekability (GstFlvDemux * demux)
210 gint64 start = -1, stop = -1;
212 demux->upstream_seekable = FALSE;
214 query = gst_query_new_seeking (GST_FORMAT_BYTES);
215 if (!gst_pad_peer_query (demux->sinkpad, query)) {
216 GST_DEBUG_OBJECT (demux, "seeking query failed");
217 gst_query_unref (query);
221 gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
224 gst_query_unref (query);
226 /* try harder to query upstream size if we didn't get it the first time */
227 if (demux->upstream_seekable && stop == -1) {
228 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
229 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
232 /* if upstream doesn't know the size, it's likely that it's not seekable in
233 * practice even if it technically may be seekable */
234 if (demux->upstream_seekable && (start != 0 || stop <= start)) {
235 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
236 demux->upstream_seekable = FALSE;
239 GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
243 parse_flv_demux_parse_date_string (GDate * date, const gchar * s)
245 g_date_set_parse (date, s);
246 if (g_date_valid (date))
249 /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
251 static const gchar *months[] = {
252 "Jan", "Feb", "Mar", "Apr",
253 "May", "Jun", "Jul", "Aug",
254 "Sep", "Oct", "Nov", "Dec"
256 gchar **tokens = g_strsplit (s, " ", -1);
261 if (g_strv_length (tokens) != 5)
264 if (strlen (tokens[1]) != 3)
266 for (i = 0; i < 12; i++) {
267 if (!strcmp (tokens[1], months[i])) {
273 g_date_set_month (date, i + 1);
275 d = g_ascii_strtoull (tokens[2], &endptr, 10);
276 if (d == 0 && *endptr != '\0')
279 g_date_set_day (date, d);
281 d = g_ascii_strtoull (tokens[4], &endptr, 10);
282 if (d == 0 && *endptr != '\0')
285 g_date_set_year (date, d);
294 gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
295 gboolean * end_marker)
297 gchar *tag_name = NULL;
300 /* Initialize the end_marker flag to FALSE */
303 /* Name of the tag */
304 tag_name = FLV_GET_STRING (reader);
305 if (G_UNLIKELY (!tag_name)) {
306 GST_WARNING_OBJECT (demux, "failed reading tag name");
310 /* What kind of object is that */
311 if (!gst_byte_reader_get_uint8 (reader, &tag_type))
314 GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
318 { /* Use a union to read the uint64 and then as a double */
321 if (!gst_byte_reader_get_float64_be (reader, &d))
324 GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
326 if (!strcmp (tag_name, "duration")) {
327 demux->duration = d * GST_SECOND;
329 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
330 GST_TAG_DURATION, demux->duration, NULL);
331 } else if (!strcmp (tag_name, "AspectRatioX")) {
333 demux->got_par = TRUE;
334 } else if (!strcmp (tag_name, "AspectRatioY")) {
336 demux->got_par = TRUE;
337 } else if (!strcmp (tag_name, "width")) {
339 } else if (!strcmp (tag_name, "height")) {
341 } else if (!strcmp (tag_name, "framerate")) {
342 demux->framerate = d;
344 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
349 case 1: /* Boolean */
353 if (!gst_byte_reader_get_uint8 (reader, &b))
356 GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
358 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
366 s = FLV_GET_STRING (reader);
370 GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
372 if (!strcmp (tag_name, "creationdate")) {
373 GDate *date = g_date_new ();
375 parse_flv_demux_parse_date_string (date, s);
376 if (!g_date_valid (date)) {
377 GST_DEBUG_OBJECT (demux, "Failed to parse string as date");
379 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
380 GST_TAG_DATE, date, NULL);
383 } else if (!strcmp (tag_name, "creator")) {
384 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
385 GST_TAG_ARTIST, s, NULL);
386 } else if (!strcmp (tag_name, "title")) {
387 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
388 GST_TAG_TITLE, s, NULL);
389 } else if (!strcmp (tag_name, "metadatacreator")) {
390 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
391 GST_TAG_ENCODER, s, NULL);
393 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
402 gboolean end_of_object_marker = FALSE;
404 while (!end_of_object_marker) {
405 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
406 &end_of_object_marker);
408 if (G_UNLIKELY (!ok)) {
409 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
416 case 8: /* ECMA array */
418 guint32 nb_elems = 0;
419 gboolean end_of_object_marker = FALSE;
421 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
424 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
427 while (!end_of_object_marker) {
428 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
429 &end_of_object_marker);
431 if (G_UNLIKELY (!ok)) {
432 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
439 case 9: /* End marker */
441 GST_DEBUG_OBJECT (demux, "end marker ?");
442 if (tag_name[0] == '\0') {
444 GST_DEBUG_OBJECT (demux, "end marker detected");
453 guint32 nb_elems = 0;
455 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
458 GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
460 if (!strcmp (tag_name, "times")) {
462 g_array_free (demux->times, TRUE);
464 demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
465 } else if (!strcmp (tag_name, "filepositions")) {
466 if (demux->filepositions) {
467 g_array_free (demux->filepositions, TRUE);
469 demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
473 guint8 elem_type = 0;
475 if (!gst_byte_reader_get_uint8 (reader, &elem_type))
483 if (!gst_byte_reader_get_float64_be (reader, &d))
486 GST_DEBUG_OBJECT (demux, "element is a double %f", d);
488 if (!strcmp (tag_name, "times") && demux->times) {
489 g_array_append_val (demux->times, d);
490 } else if (!strcmp (tag_name, "filepositions") &&
491 demux->filepositions) {
492 g_array_append_val (demux->filepositions, d);
497 GST_WARNING_OBJECT (demux, "unsupported array element type %d",
509 if (!gst_byte_reader_get_float64_be (reader, &d))
512 if (!gst_byte_reader_get_int16_be (reader, &i))
515 GST_DEBUG_OBJECT (demux,
516 "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
518 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
523 GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
537 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
539 GstFlowReturn ret = GST_FLOW_OK;
540 GstByteReader reader;
544 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 7, GST_FLOW_ERROR);
546 gst_buffer_map (buffer, &map, GST_MAP_READ);
547 gst_byte_reader_init (&reader, map.data, map.size);
549 gst_byte_reader_skip_unchecked (&reader, 7);
551 GST_LOG_OBJECT (demux, "parsing a script tag");
553 if (!gst_byte_reader_get_uint8 (&reader, &type))
558 gchar *function_name;
561 function_name = FLV_GET_STRING (&reader);
563 GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
565 if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
566 gboolean end_marker = FALSE;
567 GST_DEBUG_OBJECT (demux, "we have a metadata script object");
569 if (!gst_byte_reader_get_uint8 (&reader, &type)) {
570 g_free (function_name);
577 guint32 nb_elems = 0;
580 if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
581 g_free (function_name);
585 /* The number of elements is just a hint, some files have
586 nb_elements == 0 and actually contain items. */
587 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
590 /* fallthrough to read data */
594 while (!end_marker) {
596 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
598 if (G_UNLIKELY (!ok)) {
599 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
606 GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
607 g_free (function_name);
611 demux->push_tags = TRUE;
614 g_free (function_name);
616 if (demux->times && demux->filepositions) {
619 /* If an index was found, insert associations */
620 num = MIN (demux->times->len, demux->filepositions->len);
621 for (i = 0; i < num; i++) {
622 guint64 time, fileposition;
624 time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
625 fileposition = g_array_index (demux->filepositions, gdouble, i);
626 gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
629 demux->indexed = TRUE;
634 gst_buffer_unmap (buffer, &map);
640 have_group_id (GstFlvDemux * demux)
644 event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
646 if (gst_event_parse_group_id (event, &demux->group_id))
647 demux->have_group_id = TRUE;
649 demux->have_group_id = FALSE;
650 gst_event_unref (event);
651 } else if (!demux->have_group_id) {
652 demux->have_group_id = TRUE;
653 demux->group_id = gst_util_group_id_next ();
656 return demux->have_group_id;
660 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
661 guint32 rate, guint32 channels, guint32 width)
663 GstCaps *caps = NULL;
664 gchar *codec_name = NULL;
665 gboolean ret = FALSE;
666 guint adjusted_rate = rate;
672 caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
677 caps = gst_caps_new_simple ("audio/mpeg",
678 "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
679 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
684 GstAudioFormat format;
686 /* Assuming little endian for 0 (aka endianness of the
687 * system on which the file was created) as most people
688 * are probably using little endian machines */
689 format = gst_audio_format_build_integer ((width == 8) ? FALSE : TRUE,
690 G_LITTLE_ENDIAN, width, width);
692 caps = gst_caps_new_simple ("audio/x-raw",
693 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
694 "layout", G_TYPE_STRING, "interleaved", NULL);
700 caps = gst_caps_new_empty_simple ("audio/x-nellymoser");
704 if (demux->audio_codec_data) {
707 gst_buffer_map (demux->audio_codec_data, &map, GST_MAP_READ);
709 /* use codec-data to extract and verify samplerate */
713 freq_index = GST_READ_UINT16_BE (map.data);
714 freq_index = (freq_index & 0x0780) >> 7;
716 gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
718 if (adjusted_rate && (rate != adjusted_rate)) {
719 GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
722 adjusted_rate = rate;
725 gst_buffer_unmap (demux->audio_codec_data, &map);
728 caps = gst_caps_new_simple ("audio/mpeg",
729 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
730 "stream-format", G_TYPE_STRING, "raw", NULL);
734 caps = gst_caps_new_empty_simple ("audio/x-alaw");
737 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
741 GValue streamheader = G_VALUE_INIT;
742 GValue value = G_VALUE_INIT;
744 GstStructure *structure;
747 caps = gst_caps_new_empty_simple ("audio/x-speex");
748 structure = gst_caps_get_structure (caps, 0);
750 GST_DEBUG_OBJECT (demux, "generating speex header");
752 /* Speex decoder expects streamheader to be { [header], [comment] } */
753 g_value_init (&streamheader, GST_TYPE_ARRAY);
756 gst_byte_writer_init_with_size (&w, 80, TRUE);
757 gst_byte_writer_put_data (&w, (guint8 *) "Speex ", 8);
758 gst_byte_writer_put_data (&w, (guint8 *) "1.1.12", 7);
759 gst_byte_writer_fill (&w, 0, 13);
760 gst_byte_writer_put_uint32_le (&w, 1); /* version */
761 gst_byte_writer_put_uint32_le (&w, 80); /* header_size */
762 gst_byte_writer_put_uint32_le (&w, 16000); /* rate */
763 gst_byte_writer_put_uint32_le (&w, 1); /* mode: Wideband */
764 gst_byte_writer_put_uint32_le (&w, 4); /* mode_bitstream_version */
765 gst_byte_writer_put_uint32_le (&w, 1); /* nb_channels: 1 */
766 gst_byte_writer_put_uint32_le (&w, -1); /* bitrate */
767 gst_byte_writer_put_uint32_le (&w, 0x50); /* frame_size */
768 gst_byte_writer_put_uint32_le (&w, 0); /* VBR */
769 gst_byte_writer_put_uint32_le (&w, 1); /* frames_per_packet */
770 gst_byte_writer_put_uint32_le (&w, 0); /* extra_headers */
771 gst_byte_writer_put_uint32_le (&w, 0); /* reserved1 */
772 gst_byte_writer_put_uint32_le (&w, 0); /* reserved2 */
773 g_assert (gst_byte_writer_get_size (&w) == 80);
775 g_value_init (&value, GST_TYPE_BUFFER);
776 g_value_take_boxed (&value, gst_byte_writer_reset_and_get_buffer (&w));
777 gst_value_array_append_value (&streamheader, &value);
778 g_value_unset (&value);
781 g_value_init (&value, GST_TYPE_BUFFER);
782 buf = gst_buffer_new_wrapped (g_memdup ("No comments", 12), 12);
783 g_value_take_boxed (&value, buf);
784 gst_value_array_append_value (&streamheader, &value);
785 g_value_unset (&value);
787 gst_structure_take_value (structure, "streamheader", &streamheader);
790 adjusted_rate = 16000;
794 GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
798 if (G_UNLIKELY (!caps)) {
799 GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
803 gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
804 "channels", G_TYPE_INT, channels, NULL);
806 if (demux->audio_codec_data) {
807 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
808 demux->audio_codec_data, NULL);
812 gst_pad_create_stream_id (demux->audio_pad, GST_ELEMENT_CAST (demux),
815 event = gst_event_new_stream_start (stream_id);
816 if (have_group_id (demux))
817 gst_event_set_group_id (event, demux->group_id);
818 gst_pad_push_event (demux->audio_pad, event);
821 ret = gst_pad_set_caps (demux->audio_pad, caps);
823 if (G_LIKELY (ret)) {
824 /* Store the caps we got from tags */
825 demux->audio_codec_tag = codec_tag;
827 demux->channels = channels;
828 demux->width = width;
830 codec_name = gst_pb_utils_get_codec_description (caps);
833 if (demux->taglist == NULL)
834 demux->taglist = gst_tag_list_new_empty ();
835 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
836 GST_TAG_AUDIO_CODEC, codec_name, NULL);
840 GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
841 GST_PTR_FORMAT, caps);
843 GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
844 GST_PTR_FORMAT, caps);
847 gst_caps_unref (caps);
854 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
858 if (demux->audio_pad)
859 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
861 if (demux->video_pad)
862 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
864 gst_event_unref (event);
870 gst_flv_demux_push_tags (GstFlvDemux * demux)
872 if (demux->has_audio && !demux->audio_pad) {
873 GST_DEBUG_OBJECT (demux,
874 "Waiting for audio stream pad to come up before we can push tags");
877 if (demux->has_video && !demux->video_pad) {
878 GST_DEBUG_OBJECT (demux,
879 "Waiting for video stream pad to come up before we can push tags");
882 if (demux->taglist) {
883 GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
885 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
886 gst_flv_demux_push_src_event (demux, gst_event_new_tag (demux->taglist));
887 demux->taglist = gst_tag_list_new_empty ();
888 demux->push_tags = FALSE;
893 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 dts, gboolean discont,
894 guint32 * last, GstClockTime * offset)
896 gboolean ret = FALSE;
897 gint32 ddts = dts - *last;
898 if (!discont && ddts <= -RESYNC_THRESHOLD) {
899 /* Theoretically, we should use substract the duration of the last buffer,
900 but this demuxer sends no durations on buffers, not sure if it cannot
901 know, or just does not care to calculate. */
902 *offset -= ddts * GST_MSECOND;
903 GST_WARNING_OBJECT (demux,
904 "Large dts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
905 GST_TIME_FORMAT "", ddts, GST_TIME_ARGS (*offset));
915 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
917 GstFlowReturn ret = GST_FLOW_OK;
918 guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
919 guint32 codec_data = 0, pts_ext = 0;
925 GST_LOG_OBJECT (demux, "parsing an audio tag");
927 if (demux->no_more_pads && !demux->audio_pad) {
928 GST_WARNING_OBJECT (demux,
929 "Signaled no-more-pads already but had no audio pad -- ignoring");
933 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
936 /* Error out on tags with too small headers */
937 if (gst_buffer_get_size (buffer) < 11) {
938 GST_ERROR_OBJECT (demux, "Too small tag size (%" G_GSIZE_FORMAT ")",
939 gst_buffer_get_size (buffer));
940 return GST_FLOW_ERROR;
943 gst_buffer_map (buffer, &map, GST_MAP_READ);
946 /* Grab information about audio tag */
947 pts = GST_READ_UINT24_BE (data);
948 /* read the pts extension to 32 bits integer */
949 pts_ext = GST_READ_UINT8 (data + 3);
951 pts |= pts_ext << 24;
953 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
954 data[2], data[3], pts);
956 /* Skip the stream id and go directly to the flags */
957 flags = GST_READ_UINT8 (data + 7);
959 /* Silently skip buffers with no data */
972 if ((flags & 0x0C) == 0x0C) {
974 } else if ((flags & 0x0C) == 0x08) {
976 } else if ((flags & 0x0C) == 0x04) {
980 codec_tag = flags >> 4;
981 if (codec_tag == 10) { /* AAC has an extra byte for packet type */
987 /* codec tags with special rates */
988 if (codec_tag == 5 || codec_tag == 14)
990 else if (codec_tag == 4)
993 GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
994 "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
997 /* If we don't have our audio pad created, then create it. */
998 if (G_UNLIKELY (!demux->audio_pad)) {
1001 gst_pad_new_from_template (gst_element_class_get_pad_template
1002 (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
1003 if (G_UNLIKELY (!demux->audio_pad)) {
1004 GST_WARNING_OBJECT (demux, "failed creating audio pad");
1005 ret = GST_FLOW_ERROR;
1009 /* Set functions on the pad */
1010 gst_pad_set_query_function (demux->audio_pad,
1011 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1012 gst_pad_set_event_function (demux->audio_pad,
1013 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1015 gst_pad_use_fixed_caps (demux->audio_pad);
1017 /* Make it active */
1018 gst_pad_set_active (demux->audio_pad, TRUE);
1020 /* Negotiate caps */
1021 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1023 gst_object_unref (demux->audio_pad);
1024 demux->audio_pad = NULL;
1025 ret = GST_FLOW_ERROR;
1028 #ifndef GST_DISABLE_GST_DEBUG
1032 caps = gst_pad_get_current_caps (demux->audio_pad);
1033 GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
1036 gst_caps_unref (caps);
1040 /* We need to set caps before adding */
1041 gst_element_add_pad (GST_ELEMENT (demux),
1042 gst_object_ref (demux->audio_pad));
1043 gst_flow_combiner_add_pad (demux->flowcombiner, demux->audio_pad);
1045 /* We only emit no more pads when we have audio and video. Indeed we can
1046 * not trust the FLV header to tell us if there will be only audio or
1047 * only video and we would just break discovery of some files */
1048 if (demux->audio_pad && demux->video_pad) {
1049 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1050 gst_element_no_more_pads (GST_ELEMENT (demux));
1051 demux->no_more_pads = TRUE;
1052 demux->push_tags = TRUE;
1056 /* Check if caps have changed */
1057 if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
1058 codec_tag != demux->audio_codec_tag || width != demux->width)) {
1059 GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
1061 /* Negotiate caps */
1062 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1064 ret = GST_FLOW_ERROR;
1069 /* Push taglist if present */
1070 if (G_UNLIKELY (demux->push_tags))
1071 gst_flv_demux_push_tags (demux);
1073 /* Check if we have anything to push */
1074 if (demux->tag_data_size <= codec_data) {
1075 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1079 /* Create buffer from pad */
1080 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1081 7 + codec_data, demux->tag_data_size - codec_data);
1083 if (demux->audio_codec_tag == 10) {
1084 guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
1086 switch (aac_packet_type) {
1089 /* AudioSpecificConfig data */
1090 GST_LOG_OBJECT (demux, "got an AAC codec data packet");
1091 if (demux->audio_codec_data) {
1092 gst_buffer_unref (demux->audio_codec_data);
1094 demux->audio_codec_data = outbuf;
1095 /* Use that buffer data in the caps */
1096 gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels, width);
1100 /* AAC raw packet */
1101 GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
1104 GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
1109 /* detect (and deem to be resyncs) large pts gaps */
1110 if (gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
1111 &demux->last_audio_pts, &demux->audio_time_offset)) {
1112 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
1115 /* Fill buffer with data */
1116 GST_BUFFER_PTS (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
1117 GST_BUFFER_DTS (outbuf) = GST_BUFFER_PTS (outbuf);
1118 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1119 GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
1120 GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
1122 if (demux->duration == GST_CLOCK_TIME_NONE ||
1123 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1124 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1126 /* Only add audio frames to the index if we have no video,
1127 * and if the index is not yet complete */
1128 if (!demux->has_video && !demux->indexed) {
1129 gst_flv_demux_parse_and_add_index_entry (demux,
1130 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
1133 if (G_UNLIKELY (demux->audio_need_discont)) {
1134 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1135 demux->audio_need_discont = FALSE;
1138 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1140 /* Do we need a newsegment event ? */
1141 if (G_UNLIKELY (demux->audio_need_segment)) {
1142 if (!demux->new_seg_event) {
1143 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1144 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1145 GST_TIME_ARGS (demux->segment.position),
1146 GST_TIME_ARGS (demux->segment.stop));
1147 demux->segment.start = demux->segment.time = demux->segment.position;
1148 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1150 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1153 gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1155 demux->audio_need_segment = FALSE;
1158 GST_LOG_OBJECT (demux,
1159 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1160 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1161 gst_buffer_get_size (outbuf),
1162 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1163 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1165 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1166 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1168 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1169 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1172 if (G_UNLIKELY (!demux->no_more_pads
1173 && (GST_CLOCK_DIFF (demux->audio_start,
1174 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1175 GST_DEBUG_OBJECT (demux,
1176 "Signalling no-more-pads because no video stream was found"
1177 " after 6 seconds of audio");
1178 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1179 demux->no_more_pads = TRUE;
1180 demux->push_tags = TRUE;
1183 /* Push downstream */
1184 ret = gst_pad_push (demux->audio_pad, outbuf);
1186 if (G_UNLIKELY (ret != GST_FLOW_OK) &&
1187 demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1188 demux->segment.position > demux->segment.stop) {
1189 /* In reverse playback we can get a GST_FLOW_EOS when
1190 * we are at the end of the segment, so we just need to jump
1191 * back to the previous section. */
1192 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1193 demux->audio_done = TRUE;
1198 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
1201 gst_buffer_unmap (buffer, &map);
1207 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1209 gboolean ret = FALSE;
1210 GstCaps *caps = NULL;
1211 gchar *codec_name = NULL;
1215 /* Generate caps for that pad */
1216 switch (codec_tag) {
1219 gst_caps_new_simple ("video/x-flash-video", "flvversion", G_TYPE_INT,
1223 caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1226 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1229 caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1233 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1237 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1240 if (G_UNLIKELY (!caps)) {
1241 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1245 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1246 demux->par_x, demux->par_y, NULL);
1248 if (G_LIKELY (demux->w)) {
1249 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1252 if (G_LIKELY (demux->h)) {
1253 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1256 if (G_LIKELY (demux->framerate)) {
1257 gint num = 0, den = 0;
1259 gst_video_guess_framerate (GST_SECOND / demux->framerate, &num, &den);
1260 GST_DEBUG_OBJECT (demux->video_pad,
1261 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1264 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1267 if (demux->video_codec_data) {
1268 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1269 demux->video_codec_data, NULL);
1273 gst_pad_create_stream_id (demux->video_pad, GST_ELEMENT_CAST (demux),
1275 event = gst_event_new_stream_start (stream_id);
1278 if (have_group_id (demux))
1279 gst_event_set_group_id (event, demux->group_id);
1280 gst_pad_push_event (demux->video_pad, event);
1281 ret = gst_pad_set_caps (demux->video_pad, caps);
1283 if (G_LIKELY (ret)) {
1284 /* Store the caps we have set */
1285 demux->video_codec_tag = codec_tag;
1287 codec_name = gst_pb_utils_get_codec_description (caps);
1290 if (demux->taglist == NULL)
1291 demux->taglist = gst_tag_list_new_empty ();
1292 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1293 GST_TAG_VIDEO_CODEC, codec_name, NULL);
1294 g_free (codec_name);
1297 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1298 GST_PTR_FORMAT, caps);
1300 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1301 GST_PTR_FORMAT, caps);
1304 gst_caps_unref (caps);
1310 static GstFlowReturn
1311 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1313 GstFlowReturn ret = GST_FLOW_OK;
1314 guint32 dts = 0, codec_data = 1, dts_ext = 0;
1316 gboolean keyframe = FALSE;
1317 guint8 flags = 0, codec_tag = 0;
1322 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1325 GST_LOG_OBJECT (demux, "parsing a video tag");
1327 if (demux->no_more_pads && !demux->video_pad) {
1328 GST_WARNING_OBJECT (demux,
1329 "Signaled no-more-pads already but had no video pad -- ignoring");
1333 if (gst_buffer_get_size (buffer) < 12) {
1334 GST_ERROR_OBJECT (demux, "Too small tag size");
1335 return GST_FLOW_ERROR;
1338 gst_buffer_map (buffer, &map, GST_MAP_READ);
1341 /* Grab information about video tag */
1342 dts = GST_READ_UINT24_BE (data);
1343 /* read the dts extension to 32 bits integer */
1344 dts_ext = GST_READ_UINT8 (data + 3);
1346 dts |= dts_ext << 24;
1348 GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1349 data[2], data[3], dts);
1351 /* Skip the stream id and go directly to the flags */
1352 flags = GST_READ_UINT8 (data + 7);
1355 if ((flags >> 4) == 1) {
1359 codec_tag = flags & 0x0F;
1360 if (codec_tag == 4 || codec_tag == 5) {
1362 } else if (codec_tag == 7) {
1365 cts = GST_READ_UINT24_BE (data + 9);
1366 cts = (cts + 0xff800000) ^ 0xff800000;
1368 GST_LOG_OBJECT (demux, "got cts %d", 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));
1423 gst_flow_combiner_add_pad (demux->flowcombiner, demux->video_pad);
1425 /* We only emit no more pads when we have audio and video. Indeed we can
1426 * not trust the FLV header to tell us if there will be only audio or
1427 * only video and we would just break discovery of some files */
1428 if (demux->audio_pad && demux->video_pad) {
1429 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1430 gst_element_no_more_pads (GST_ELEMENT (demux));
1431 demux->no_more_pads = TRUE;
1432 demux->push_tags = TRUE;
1436 /* Check if caps have changed */
1437 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1439 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1441 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1442 ret = GST_FLOW_ERROR;
1446 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1447 * metadata tag that would come later and trigger a caps change */
1448 demux->got_par = FALSE;
1451 /* Push taglist if present */
1452 if (G_UNLIKELY (demux->push_tags))
1453 gst_flv_demux_push_tags (demux);
1455 /* Check if we have anything to push */
1456 if (demux->tag_data_size <= codec_data) {
1457 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1461 /* Create buffer from pad */
1462 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1463 7 + codec_data, demux->tag_data_size - codec_data);
1465 if (demux->video_codec_tag == 7) {
1466 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1468 switch (avc_packet_type) {
1471 /* AVCDecoderConfigurationRecord data */
1472 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1473 if (demux->video_codec_data) {
1474 gst_buffer_unref (demux->video_codec_data);
1476 demux->video_codec_data = outbuf;
1477 /* Use that buffer data in the caps */
1478 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 dts gaps */
1492 if (gst_flv_demux_update_resync (demux, dts, demux->video_need_discont,
1493 &demux->last_video_dts, &demux->video_time_offset)) {
1494 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
1497 /* Fill buffer with data */
1498 GST_LOG_OBJECT (demux, "dts %u pts %u cts %d", dts, dts + cts, cts);
1500 GST_BUFFER_PTS (outbuf) =
1501 (dts + cts) * GST_MSECOND + demux->video_time_offset;
1502 GST_BUFFER_DTS (outbuf) = dts * GST_MSECOND + demux->video_time_offset;
1503 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1504 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1505 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1507 if (demux->duration == GST_CLOCK_TIME_NONE ||
1508 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1509 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1512 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1514 if (!demux->indexed) {
1515 gst_flv_demux_parse_and_add_index_entry (demux,
1516 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1519 if (G_UNLIKELY (demux->video_need_discont)) {
1520 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1521 demux->video_need_discont = FALSE;
1524 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1526 /* Do we need a newsegment event ? */
1527 if (G_UNLIKELY (demux->video_need_segment)) {
1528 if (!demux->new_seg_event) {
1529 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1530 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1531 GST_TIME_ARGS (demux->segment.position),
1532 GST_TIME_ARGS (demux->segment.stop));
1533 demux->segment.start = demux->segment.time = demux->segment.position;
1534 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1536 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1539 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1541 demux->video_need_segment = FALSE;
1544 GST_LOG_OBJECT (demux,
1545 "pushing %" G_GSIZE_FORMAT " bytes buffer at dts %" GST_TIME_FORMAT
1546 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1547 ", keyframe (%d)", gst_buffer_get_size (outbuf),
1548 GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
1549 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1552 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1553 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1555 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1556 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1559 if (G_UNLIKELY (!demux->no_more_pads
1560 && (GST_CLOCK_DIFF (demux->video_start,
1561 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1562 GST_DEBUG_OBJECT (demux,
1563 "Signalling no-more-pads because no audio stream was found"
1564 " after 6 seconds of video");
1565 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1566 demux->no_more_pads = TRUE;
1567 demux->push_tags = TRUE;
1570 /* Push downstream */
1571 ret = gst_pad_push (demux->video_pad, outbuf);
1573 if (G_UNLIKELY (ret != GST_FLOW_OK) &&
1574 demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1575 demux->segment.position > demux->segment.stop) {
1576 /* In reverse playback we can get a GST_FLOW_EOS when
1577 * we are at the end of the segment, so we just need to jump
1578 * back to the previous section. */
1579 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1580 demux->video_done = TRUE;
1585 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
1588 gst_buffer_unmap (buffer, &map);
1593 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1594 GstBuffer * buffer, size_t * tag_size)
1596 guint32 dts = 0, dts_ext = 0;
1597 guint32 tag_data_size;
1599 gboolean keyframe = TRUE;
1600 GstClockTime ret = GST_CLOCK_TIME_NONE;
1605 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1606 GST_CLOCK_TIME_NONE);
1608 gst_buffer_map (buffer, &map, GST_MAP_READ);
1614 if (type != 9 && type != 8 && type != 18) {
1615 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1620 demux->has_video = TRUE;
1622 demux->has_audio = TRUE;
1624 tag_data_size = GST_READ_UINT24_BE (data + 1);
1626 if (size >= tag_data_size + 11 + 4) {
1627 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1628 GST_WARNING_OBJECT (demux, "Invalid tag size");
1634 *tag_size = tag_data_size + 11 + 4;
1638 GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X", data[0], data[1],
1641 /* Grab timestamp of tag tag */
1642 dts = GST_READ_UINT24_BE (data);
1643 /* read the dts extension to 32 bits integer */
1644 dts_ext = GST_READ_UINT8 (data + 3);
1646 dts |= dts_ext << 24;
1651 keyframe = ((data[0] >> 4) == 1);
1654 ret = dts * GST_MSECOND;
1655 GST_LOG_OBJECT (demux, "dts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1657 if (index && !demux->indexed && (type == 9 || (type == 8
1658 && !demux->has_video))) {
1659 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1663 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1664 demux->duration = ret;
1667 gst_buffer_unmap (buffer, &map);
1671 static GstFlowReturn
1672 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1674 GstFlowReturn ret = GST_FLOW_OK;
1675 guint8 tag_type = 0;
1678 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1680 gst_buffer_map (buffer, &map, GST_MAP_READ);
1682 tag_type = map.data[0];
1684 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1685 * 4 bytes of previous tag size */
1686 demux->tag_data_size = GST_READ_UINT24_BE (map.data + 1);
1687 demux->tag_size = demux->tag_data_size + 11;
1689 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1690 demux->tag_data_size);
1692 gst_buffer_unmap (buffer, &map);
1696 demux->state = FLV_STATE_TAG_VIDEO;
1697 demux->has_video = TRUE;
1700 demux->state = FLV_STATE_TAG_AUDIO;
1701 demux->has_audio = TRUE;
1704 demux->state = FLV_STATE_TAG_SCRIPT;
1707 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1708 demux->state = FLV_STATE_SKIP;
1714 static GstFlowReturn
1715 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1717 GstFlowReturn ret = GST_FLOW_OK;
1720 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1722 gst_buffer_map (buffer, &map, GST_MAP_READ);
1724 /* Check for the FLV tag */
1725 if (map.data[0] == 'F' && map.data[1] == 'L' && map.data[2] == 'V') {
1726 GST_DEBUG_OBJECT (demux, "FLV header detected");
1728 if (G_UNLIKELY (demux->strict)) {
1729 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1735 if (map.data[3] == '1') {
1736 GST_DEBUG_OBJECT (demux, "FLV version 1 detected");
1738 if (G_UNLIKELY (demux->strict)) {
1739 GST_WARNING_OBJECT (demux, "invalid header version detected");
1746 /* Now look at audio/video flags */
1748 guint8 flags = map.data[4];
1750 demux->has_video = demux->has_audio = FALSE;
1753 GST_DEBUG_OBJECT (demux, "there is a video stream");
1754 demux->has_video = TRUE;
1757 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1758 demux->has_audio = TRUE;
1762 /* do a one-time seekability check */
1763 gst_flv_demux_check_seekability (demux);
1765 /* We don't care about the rest */
1766 demux->need_header = FALSE;
1769 gst_buffer_unmap (buffer, &map);
1775 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1777 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1779 gst_adapter_clear (demux->adapter);
1781 demux->audio_need_discont = TRUE;
1782 demux->video_need_discont = TRUE;
1784 demux->flushing = FALSE;
1786 /* Only in push mode and if we're not during a seek */
1787 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1788 /* After a flush we expect a tag_type */
1789 demux->state = FLV_STATE_TAG_TYPE;
1790 /* We reset the offset and will get one from first push */
1796 gst_flv_demux_cleanup (GstFlvDemux * demux)
1798 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1800 demux->state = FLV_STATE_HEADER;
1802 demux->have_group_id = FALSE;
1803 demux->group_id = G_MAXUINT;
1805 demux->flushing = FALSE;
1806 demux->need_header = TRUE;
1807 demux->audio_need_segment = TRUE;
1808 demux->video_need_segment = TRUE;
1809 demux->audio_need_discont = TRUE;
1810 demux->video_need_discont = TRUE;
1812 demux->has_audio = FALSE;
1813 demux->has_video = FALSE;
1814 demux->push_tags = FALSE;
1815 demux->got_par = FALSE;
1817 demux->indexed = FALSE;
1818 demux->upstream_seekable = FALSE;
1819 demux->file_size = 0;
1821 demux->index_max_pos = 0;
1822 demux->index_max_time = 0;
1824 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1825 demux->last_audio_pts = demux->last_video_dts = 0;
1826 demux->audio_time_offset = demux->video_time_offset = 0;
1828 demux->no_more_pads = FALSE;
1830 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1832 demux->w = demux->h = 0;
1833 demux->framerate = 0.0;
1834 demux->par_x = demux->par_y = 1;
1835 demux->video_offset = 0;
1836 demux->audio_offset = 0;
1837 demux->offset = demux->cur_tag_offset = 0;
1838 demux->tag_size = demux->tag_data_size = 0;
1839 demux->duration = GST_CLOCK_TIME_NONE;
1841 if (demux->new_seg_event) {
1842 gst_event_unref (demux->new_seg_event);
1843 demux->new_seg_event = NULL;
1846 gst_adapter_clear (demux->adapter);
1848 if (demux->audio_codec_data) {
1849 gst_buffer_unref (demux->audio_codec_data);
1850 demux->audio_codec_data = NULL;
1853 if (demux->video_codec_data) {
1854 gst_buffer_unref (demux->video_codec_data);
1855 demux->video_codec_data = NULL;
1858 if (demux->audio_pad) {
1859 gst_flow_combiner_remove_pad (demux->flowcombiner, demux->audio_pad);
1860 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1861 gst_object_unref (demux->audio_pad);
1862 demux->audio_pad = NULL;
1865 if (demux->video_pad) {
1866 gst_flow_combiner_remove_pad (demux->flowcombiner, demux->video_pad);
1867 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1868 gst_object_unref (demux->video_pad);
1869 demux->video_pad = NULL;
1873 g_array_free (demux->times, TRUE);
1874 demux->times = NULL;
1877 if (demux->filepositions) {
1878 g_array_free (demux->filepositions, TRUE);
1879 demux->filepositions = NULL;
1884 * Create and push a flushing seek event upstream
1887 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1892 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1895 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1896 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1897 GST_SEEK_TYPE_NONE, -1);
1899 res = gst_pad_push_event (demux->sinkpad, event);
1902 demux->offset = offset;
1906 static GstFlowReturn
1907 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1909 GstFlowReturn ret = GST_FLOW_OK;
1910 GstFlvDemux *demux = NULL;
1912 demux = GST_FLV_DEMUX (parent);
1914 GST_LOG_OBJECT (demux,
1915 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
1916 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
1917 GST_BUFFER_OFFSET (buffer));
1919 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1920 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1921 demux->state = FLV_STATE_HEADER;
1925 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
1926 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
1927 demux->offset = GST_BUFFER_OFFSET (buffer);
1930 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1931 GST_DEBUG_OBJECT (demux, "Discontinuity");
1932 gst_adapter_clear (demux->adapter);
1935 gst_adapter_push (demux->adapter, buffer);
1937 if (demux->seeking) {
1938 demux->state = FLV_STATE_SEEK;
1939 GST_OBJECT_LOCK (demux);
1940 demux->seeking = FALSE;
1941 GST_OBJECT_UNLOCK (demux);
1945 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1946 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
1950 if (G_UNLIKELY (demux->flushing)) {
1951 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
1952 ret = GST_FLOW_FLUSHING;
1956 switch (demux->state) {
1957 case FLV_STATE_HEADER:
1959 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
1962 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
1964 ret = gst_flv_demux_parse_header (demux, buffer);
1966 gst_buffer_unref (buffer);
1967 demux->offset += FLV_HEADER_SIZE;
1969 demux->state = FLV_STATE_TAG_TYPE;
1975 case FLV_STATE_TAG_TYPE:
1977 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
1980 /* Remember the tag offset in bytes */
1981 demux->cur_tag_offset = demux->offset;
1983 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
1985 ret = gst_flv_demux_parse_tag_type (demux, buffer);
1987 gst_buffer_unref (buffer);
1988 demux->offset += FLV_TAG_TYPE_SIZE;
1990 /* last tag is not an index => no index/don't know where the index is
1991 * seek back to the beginning */
1992 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
2000 case FLV_STATE_TAG_VIDEO:
2002 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2005 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2007 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2009 gst_buffer_unref (buffer);
2010 demux->offset += demux->tag_size;
2012 demux->state = FLV_STATE_TAG_TYPE;
2018 case FLV_STATE_TAG_AUDIO:
2020 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2023 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2025 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2027 gst_buffer_unref (buffer);
2028 demux->offset += demux->tag_size;
2030 demux->state = FLV_STATE_TAG_TYPE;
2036 case FLV_STATE_TAG_SCRIPT:
2038 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2041 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2043 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2045 gst_buffer_unref (buffer);
2046 demux->offset += demux->tag_size;
2048 demux->state = FLV_STATE_TAG_TYPE;
2050 /* if there's a seek event we're here for the index so if we don't have it
2051 * we seek back to the beginning */
2052 if (demux->seek_event) {
2054 demux->state = FLV_STATE_SEEK;
2064 case FLV_STATE_SEEK:
2070 if (!demux->indexed) {
2071 if (demux->offset == demux->file_size - sizeof (guint32)) {
2072 guint64 seek_offset;
2075 data = gst_adapter_take (demux->adapter, 4);
2079 seek_offset = demux->file_size - sizeof (guint32) -
2080 GST_READ_UINT32_BE (data);
2083 GST_INFO_OBJECT (demux,
2084 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
2086 demux->state = FLV_STATE_TAG_TYPE;
2087 flv_demux_seek_to_offset (demux, seek_offset);
2093 GST_OBJECT_LOCK (demux);
2094 event = demux->seek_event;
2095 demux->seek_event = NULL;
2096 GST_OBJECT_UNLOCK (demux);
2098 /* calculate and perform seek */
2099 if (!flv_demux_handle_seek_push (demux, event))
2102 gst_event_unref (event);
2103 demux->state = FLV_STATE_TAG_TYPE;
2106 case FLV_STATE_SKIP:
2107 /* Skip unknown tags (set in _parse_tag_type()) */
2108 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2109 gst_adapter_flush (demux->adapter, demux->tag_size);
2110 demux->offset += demux->tag_size;
2111 demux->state = FLV_STATE_TAG_TYPE;
2117 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
2126 GST_OBJECT_LOCK (demux);
2127 demux->seeking = FALSE;
2128 gst_event_unref (demux->seek_event);
2129 demux->seek_event = NULL;
2130 GST_OBJECT_UNLOCK (demux);
2131 GST_WARNING_OBJECT (demux,
2132 "failed to find an index, seeking back to beginning");
2133 flv_demux_seek_to_offset (demux, 0);
2138 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2139 return GST_FLOW_ERROR;
2144 static GstFlowReturn
2145 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2146 guint size, GstBuffer ** buffer)
2150 ret = gst_pad_pull_range (pad, offset, size, buffer);
2151 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2152 GST_WARNING_OBJECT (demux,
2153 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2154 size, offset, gst_flow_get_name (ret));
2159 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2160 GST_WARNING_OBJECT (demux,
2161 "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
2162 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
2163 gst_buffer_unref (*buffer);
2172 static GstFlowReturn
2173 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2175 GstBuffer *buffer = NULL;
2176 GstFlowReturn ret = GST_FLOW_OK;
2178 /* Store tag offset */
2179 demux->cur_tag_offset = demux->offset;
2181 /* Get the first 4 bytes to identify tag type and size */
2182 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2183 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2186 /* Identify tag type */
2187 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2189 gst_buffer_unref (buffer);
2191 if (G_UNLIKELY (ret != GST_FLOW_OK))
2194 /* Jump over tag type + size */
2195 demux->offset += FLV_TAG_TYPE_SIZE;
2197 /* Pull the whole tag */
2199 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2200 demux->tag_size, &buffer)) != GST_FLOW_OK))
2203 switch (demux->state) {
2204 case FLV_STATE_TAG_VIDEO:
2205 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2207 case FLV_STATE_TAG_AUDIO:
2208 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2210 case FLV_STATE_TAG_SCRIPT:
2211 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2214 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2217 gst_buffer_unref (buffer);
2219 /* Jump over that part we've just parsed */
2220 demux->offset += demux->tag_size;
2222 /* Make sure we reinitialize the tag size */
2223 demux->tag_size = 0;
2225 /* Ready for the next tag */
2226 demux->state = FLV_STATE_TAG_TYPE;
2228 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2229 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2230 "neither video nor audio are linked");
2237 static GstFlowReturn
2238 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2240 GstBuffer *buffer = NULL;
2241 GstFlowReturn ret = GST_FLOW_OK;
2243 /* Get the first 9 bytes */
2244 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2245 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2248 ret = gst_flv_demux_parse_header (demux, buffer);
2250 gst_buffer_unref (buffer);
2252 /* Jump over the header now */
2253 demux->offset += FLV_HEADER_SIZE;
2254 demux->state = FLV_STATE_TAG_TYPE;
2261 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2264 demux->offset = offset;
2266 /* Tell all the stream we moved to a different position (discont) */
2267 demux->audio_need_discont = TRUE;
2268 demux->video_need_discont = TRUE;
2270 /* next section setup */
2271 demux->from_offset = -1;
2272 demux->audio_done = demux->video_done = FALSE;
2273 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2276 demux->from_offset = -1;
2277 demux->to_offset = G_MAXINT64;
2280 /* If we seeked at the beginning of the file parse the header again */
2281 if (G_UNLIKELY (!demux->offset)) {
2282 demux->state = FLV_STATE_HEADER;
2283 } else { /* or parse a tag */
2284 demux->state = FLV_STATE_TAG_TYPE;
2288 static GstFlowReturn
2289 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2291 GstFlowReturn ret = GST_FLOW_EOS;
2293 GstIndexEntry *entry = NULL;
2295 GST_DEBUG_OBJECT (demux,
2296 "terminated section started at offset %" G_GINT64_FORMAT,
2297 demux->from_offset);
2299 /* we are done if we got all audio and video */
2300 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2301 demux->audio_first_ts < demux->segment.start) &&
2302 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2303 demux->video_first_ts < demux->segment.start))
2306 if (demux->from_offset <= 0)
2309 GST_DEBUG_OBJECT (demux, "locating previous position");
2311 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2313 /* locate index entry before previous start position */
2315 entry = gst_index_get_assoc_entry (index, demux->index_id,
2316 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2317 GST_FORMAT_BYTES, demux->from_offset - 1);
2320 gint64 bytes = 0, time = 0;
2322 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2323 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2325 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2326 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2327 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2329 /* setup for next section */
2330 demux->to_offset = demux->from_offset;
2331 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2335 gst_object_unref (index);
2343 static GstFlowReturn
2344 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2350 GstClockTime tag_time;
2351 GstFlowReturn ret = GST_FLOW_OK;
2353 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2356 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2357 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2359 old_offset = demux->offset;
2360 demux->offset = pos;
2363 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2364 12, &buffer)) == GST_FLOW_OK) {
2366 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2368 gst_buffer_unref (buffer);
2371 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2374 demux->offset += tag_size;
2377 if (ret == GST_FLOW_EOS) {
2378 /* file ran out, so mark we have complete index */
2379 demux->indexed = TRUE;
2384 demux->offset = old_offset;
2390 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2392 gint64 ret = 0, offset;
2393 size_t tag_size, size;
2394 GstBuffer *buffer = NULL;
2397 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2401 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2402 if (G_UNLIKELY (offset < 4))
2406 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2410 gst_buffer_map (buffer, &map, GST_MAP_READ);
2411 tag_size = GST_READ_UINT32_BE (map.data);
2412 gst_buffer_unmap (buffer, &map);
2413 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2414 gst_buffer_unref (buffer);
2418 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2422 /* a consistency check */
2423 gst_buffer_map (buffer, &map, GST_MAP_READ);
2424 size = GST_READ_UINT24_BE (map.data + 1);
2425 if (size != tag_size - 11) {
2426 gst_buffer_unmap (buffer, &map);
2427 GST_DEBUG_OBJECT (demux,
2428 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2429 ", corrupt or truncated file", size, tag_size - 11);
2433 /* try to update duration with timestamp in any case */
2434 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2436 /* maybe get some more metadata */
2437 if (map.data[0] == 18) {
2438 gst_buffer_unmap (buffer, &map);
2439 gst_buffer_unref (buffer);
2441 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2443 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2445 gst_flv_demux_parse_tag_script (demux, buffer);
2447 gst_buffer_unmap (buffer, &map);
2452 gst_buffer_unref (buffer);
2458 gst_flv_demux_loop (GstPad * pad)
2460 GstFlvDemux *demux = NULL;
2461 GstFlowReturn ret = GST_FLOW_OK;
2463 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2466 switch (demux->state) {
2467 case FLV_STATE_TAG_TYPE:
2468 if (demux->from_offset == -1)
2469 demux->from_offset = demux->offset;
2470 ret = gst_flv_demux_pull_tag (pad, demux);
2471 /* if we have seen real data, we probably passed a possible metadata
2472 * header located at start. So if we do not yet have an index,
2473 * try to pick up metadata (index, duration) at the end */
2474 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2475 (demux->has_video || demux->has_audio)))
2476 demux->file_size = gst_flv_demux_get_metadata (demux);
2478 case FLV_STATE_DONE:
2481 case FLV_STATE_SEEK:
2482 /* seek issued with insufficient index;
2483 * scan for index in task thread from current maximum offset to
2484 * desired time and then perform seek */
2485 /* TODO maybe some buffering message or so to indicate scan progress */
2486 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2488 if (ret != GST_FLOW_OK)
2490 /* position and state arranged by seek,
2491 * also unrefs event */
2492 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2493 demux->seek_event = NULL;
2496 ret = gst_flv_demux_pull_header (pad, demux);
2497 /* index scans start after header */
2498 demux->index_max_pos = demux->offset;
2502 if (demux->segment.rate < 0.0) {
2503 /* check end of section */
2504 if ((gint64) demux->offset >= demux->to_offset ||
2505 demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2506 (demux->audio_done && demux->video_done))
2507 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2509 /* check EOS condition */
2510 if ((demux->segment.stop != -1) &&
2511 (demux->segment.position >= demux->segment.stop)) {
2516 /* pause if something went wrong or at end */
2517 if (G_UNLIKELY (ret != GST_FLOW_OK))
2520 gst_object_unref (demux);
2526 const gchar *reason = gst_flow_get_name (ret);
2528 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2529 gst_pad_pause_task (pad);
2531 if (ret == GST_FLOW_EOS) {
2532 /* handle end-of-stream/segment */
2533 /* so align our position with the end of it, if there is one
2534 * this ensures a subsequent will arrive at correct base/acc time */
2535 if (demux->segment.rate > 0.0 &&
2536 GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2537 demux->segment.position = demux->segment.stop;
2538 else if (demux->segment.rate < 0.0)
2539 demux->segment.position = demux->segment.start;
2541 /* perform EOS logic */
2542 if (!demux->no_more_pads) {
2543 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2544 demux->no_more_pads = TRUE;
2547 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2550 /* for segment playback we need to post when (in stream time)
2551 * we stopped, this is either stop (when set) or the duration. */
2552 if ((stop = demux->segment.stop) == -1)
2553 stop = demux->segment.duration;
2555 if (demux->segment.rate >= 0) {
2556 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2557 gst_element_post_message (GST_ELEMENT_CAST (demux),
2558 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2559 GST_FORMAT_TIME, stop));
2560 gst_flv_demux_push_src_event (demux,
2561 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2562 } else { /* Reverse playback */
2563 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2565 gst_element_post_message (GST_ELEMENT_CAST (demux),
2566 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2567 GST_FORMAT_TIME, demux->segment.start));
2568 gst_flv_demux_push_src_event (demux,
2569 gst_event_new_segment_done (GST_FORMAT_TIME,
2570 demux->segment.start));
2573 /* normal playback, send EOS to all linked pads */
2574 if (!demux->no_more_pads) {
2575 gst_element_no_more_pads (GST_ELEMENT (demux));
2576 demux->no_more_pads = TRUE;
2579 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2580 if (!demux->audio_pad && !demux->video_pad)
2581 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2582 ("Internal data stream error."), ("Got EOS before any data"));
2583 else if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2584 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2586 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2587 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2588 ("Internal data stream error."),
2589 ("stream stopped, reason %s", reason));
2590 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2592 gst_object_unref (demux);
2598 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2603 GstIndexEntry *entry;
2605 g_return_val_if_fail (segment != NULL, 0);
2607 time = segment->position;
2609 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2612 /* Let's check if we have an index entry for that seek time */
2613 entry = gst_index_get_assoc_entry (index, demux->index_id,
2614 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2615 GST_FORMAT_TIME, time);
2618 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2619 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2621 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2622 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2623 GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2625 /* Key frame seeking */
2626 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2627 /* Adjust the segment so that the keyframe fits in */
2628 if (time < segment->start) {
2629 segment->start = segment->time = time;
2631 segment->position = time;
2634 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2635 GST_TIME_ARGS (segment->start));
2638 gst_object_unref (index);
2645 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2649 GstSeekType start_type, stop_type;
2652 gboolean update, flush, ret;
2653 GstSegment seeksegment;
2655 gst_event_parse_seek (event, &rate, &format, &flags,
2656 &start_type, &start, &stop_type, &stop);
2658 if (format != GST_FORMAT_TIME)
2661 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2662 /* FIXME : the keyframe flag is never used ! */
2664 /* Work on a copy until we are sure the seek succeeded. */
2665 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2667 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2670 /* Apply the seek to our segment */
2671 gst_segment_do_seek (&seeksegment, rate, format, flags,
2672 start_type, start, stop_type, stop, &update);
2674 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2677 if (flush || seeksegment.position != demux->segment.position) {
2678 /* Do the actual seeking */
2679 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2681 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2682 G_GUINT64_FORMAT, offset);
2683 ret = gst_pad_push_event (demux->sinkpad,
2684 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2685 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2686 offset, GST_SEEK_TYPE_NONE, 0));
2687 if (G_UNLIKELY (!ret)) {
2688 GST_WARNING_OBJECT (demux, "upstream seek failed");
2691 /* Tell all the stream we moved to a different position (discont) */
2692 demux->audio_need_discont = TRUE;
2693 demux->video_need_discont = TRUE;
2699 /* Ok seek succeeded, take the newly configured segment */
2700 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2702 /* Tell all the stream a new segment is needed */
2703 demux->audio_need_segment = TRUE;
2704 demux->video_need_segment = TRUE;
2705 /* Clean any potential newsegment event kept for the streams. The first
2706 * stream needing a new segment will create a new one. */
2707 if (G_UNLIKELY (demux->new_seg_event)) {
2708 gst_event_unref (demux->new_seg_event);
2709 demux->new_seg_event = NULL;
2711 gst_event_unref (event);
2713 ret = gst_pad_push_event (demux->sinkpad, event);
2721 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2722 gst_event_unref (event);
2728 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2732 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2734 if (format != GST_FORMAT_TIME) {
2735 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2736 gst_event_unref (event);
2740 /* First try upstream */
2741 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2742 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2743 gst_event_unref (event);
2747 if (!demux->indexed) {
2748 guint64 seek_offset = 0;
2749 gboolean building_index;
2751 GST_OBJECT_LOCK (demux);
2752 /* handle the seek in the chain function */
2753 demux->seeking = TRUE;
2754 demux->state = FLV_STATE_SEEK;
2756 /* copy the event */
2757 if (demux->seek_event)
2758 gst_event_unref (demux->seek_event);
2759 demux->seek_event = gst_event_ref (event);
2761 /* set the building_index flag so that only one thread can setup the
2762 * structures for index seeking. */
2763 building_index = demux->building_index;
2764 if (!building_index) {
2765 demux->building_index = TRUE;
2766 if (!demux->file_size
2767 && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2768 &demux->file_size)) {
2769 GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2770 GST_OBJECT_UNLOCK (demux);
2774 /* we hope the last tag is a scriptdataobject containing an index
2775 * the size of the last tag is given in the last guint32 bits
2776 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2777 seek_offset = demux->file_size - sizeof (guint32);
2778 GST_DEBUG_OBJECT (demux,
2779 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2781 GST_OBJECT_UNLOCK (demux);
2783 if (!building_index) {
2784 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2786 return flv_demux_seek_to_offset (demux, seek_offset);
2789 /* FIXME: we have to always return true so that we don't block the seek
2791 * Note: maybe it is OK to return true if we're still building the index */
2795 return flv_demux_handle_seek_push (demux, event);
2799 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2804 GstSeekType start_type, stop_type;
2807 gboolean update, flush, ret = FALSE;
2808 GstSegment seeksegment;
2810 gst_event_parse_seek (event, &rate, &format, &flags,
2811 &start_type, &start, &stop_type, &stop);
2813 if (format != GST_FORMAT_TIME)
2816 /* mark seeking thread entering flushing/pausing */
2817 GST_OBJECT_LOCK (demux);
2819 demux->seeking = seeking;
2820 GST_OBJECT_UNLOCK (demux);
2822 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2823 /* FIXME : the keyframe flag is never used */
2826 /* Flush start up and downstream to make sure data flow and loops are
2828 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2829 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2831 /* Pause the pulling task */
2832 gst_pad_pause_task (demux->sinkpad);
2835 /* Take the stream lock */
2836 GST_PAD_STREAM_LOCK (demux->sinkpad);
2839 /* Stop flushing upstream we need to pull */
2840 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2843 /* Work on a copy until we are sure the seek succeeded. */
2844 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2846 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2849 /* Apply the seek to our segment */
2850 gst_segment_do_seek (&seeksegment, rate, format, flags,
2851 start_type, start, stop_type, stop, &update);
2853 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2856 if (flush || seeksegment.position != demux->segment.position) {
2857 /* Do the actual seeking */
2858 /* index is reliable if it is complete or we do not go to far ahead */
2859 if (seeking && !demux->indexed &&
2860 seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2861 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2862 " index only up to %" GST_TIME_FORMAT,
2863 GST_TIME_ARGS (demux->index_max_time));
2864 /* stop flushing for now */
2866 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2867 /* delegate scanning and index building to task thread to avoid
2868 * occupying main (UI) loop */
2869 if (demux->seek_event)
2870 gst_event_unref (demux->seek_event);
2871 demux->seek_event = gst_event_ref (event);
2872 demux->seek_time = seeksegment.position;
2873 demux->state = FLV_STATE_SEEK;
2874 /* do not know about succes yet, but we did care and handled it */
2878 /* now index should be as reliable as it can be for current purpose */
2879 gst_flv_demux_move_to_offset (demux,
2880 gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2887 /* Stop flushing, the sinks are at time 0 now */
2888 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2892 /* Ok seek succeeded, take the newly configured segment */
2893 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2895 /* Notify about the start of a new segment */
2896 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2897 gst_element_post_message (GST_ELEMENT (demux),
2898 gst_message_new_segment_start (GST_OBJECT (demux),
2899 demux->segment.format, demux->segment.position));
2902 /* Tell all the stream a new segment is needed */
2903 demux->audio_need_segment = TRUE;
2904 demux->video_need_segment = TRUE;
2905 /* Clean any potential newsegment event kept for the streams. The first
2906 * stream needing a new segment will create a new one. */
2907 if (G_UNLIKELY (demux->new_seg_event)) {
2908 gst_event_unref (demux->new_seg_event);
2909 demux->new_seg_event = NULL;
2911 if (demux->segment.rate < 0.0) {
2912 /* we can't generate a segment by locking on
2913 * to the first timestamp we see */
2914 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2915 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2916 GST_TIME_ARGS (demux->segment.start),
2917 GST_TIME_ARGS (demux->segment.stop));
2918 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2923 GST_OBJECT_LOCK (demux);
2924 seeking = demux->seeking && !seeking;
2925 demux->seeking = FALSE;
2926 GST_OBJECT_UNLOCK (demux);
2928 /* if we detect an external seek having started (and possibly already having
2929 * flushed), do not restart task to give it a chance.
2930 * Otherwise external one's flushing will take care to pause task */
2932 gst_pad_pause_task (demux->sinkpad);
2934 gst_pad_start_task (demux->sinkpad,
2935 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad, NULL);
2938 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2940 gst_event_unref (event);
2946 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2947 gst_event_unref (event);
2952 /* If we can pull that's prefered */
2954 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
2959 query = gst_query_new_scheduling ();
2961 if (!gst_pad_peer_query (sinkpad, query)) {
2962 gst_query_unref (query);
2966 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
2967 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
2968 gst_query_unref (query);
2973 GST_DEBUG_OBJECT (sinkpad, "activating pull");
2974 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
2978 GST_DEBUG_OBJECT (sinkpad, "activating push");
2979 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
2984 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
2985 GstPadMode mode, gboolean active)
2990 demux = GST_FLV_DEMUX (parent);
2993 case GST_PAD_MODE_PUSH:
2994 demux->random_access = FALSE;
2997 case GST_PAD_MODE_PULL:
2999 demux->random_access = TRUE;
3000 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
3003 demux->random_access = FALSE;
3004 res = gst_pad_stop_task (sinkpad);
3015 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
3018 gboolean ret = FALSE;
3020 demux = GST_FLV_DEMUX (parent);
3022 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3024 switch (GST_EVENT_TYPE (event)) {
3025 case GST_EVENT_FLUSH_START:
3026 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
3027 demux->flushing = TRUE;
3028 ret = gst_flv_demux_push_src_event (demux, event);
3030 case GST_EVENT_FLUSH_STOP:
3031 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
3032 gst_flv_demux_flush (demux, TRUE);
3033 ret = gst_flv_demux_push_src_event (demux, event);
3039 GST_DEBUG_OBJECT (demux, "received EOS");
3041 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
3044 GST_DEBUG_OBJECT (demux, "committing index");
3045 gst_index_commit (index, demux->index_id);
3046 gst_object_unref (index);
3049 if (!demux->audio_pad && !demux->video_pad)
3050 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
3051 ("Internal data stream error."), ("Got EOS before any data"));
3053 if (!demux->no_more_pads) {
3054 gst_element_no_more_pads (GST_ELEMENT (demux));
3055 demux->no_more_pads = TRUE;
3058 if (!gst_flv_demux_push_src_event (demux, event))
3059 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
3064 case GST_EVENT_SEGMENT:
3066 GstSegment in_segment;
3068 GST_DEBUG_OBJECT (demux, "received new segment");
3070 gst_event_copy_segment (event, &in_segment);
3072 if (in_segment.format == GST_FORMAT_TIME) {
3073 /* time segment, this is perfect, copy over the values. */
3074 memcpy (&demux->segment, &in_segment, sizeof (in_segment));
3076 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
3080 ret = gst_flv_demux_push_src_event (demux, event);
3082 /* non-time format */
3083 demux->audio_need_segment = TRUE;
3084 demux->video_need_segment = TRUE;
3086 gst_event_unref (event);
3087 if (demux->new_seg_event) {
3088 gst_event_unref (demux->new_seg_event);
3089 demux->new_seg_event = NULL;
3095 ret = gst_pad_event_default (pad, parent, event);
3103 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
3106 gboolean ret = FALSE;
3108 demux = GST_FLV_DEMUX (parent);
3110 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3112 switch (GST_EVENT_TYPE (event)) {
3113 case GST_EVENT_SEEK:
3114 /* Try to push upstream first */
3115 ret = gst_pad_push_event (demux->sinkpad, event);
3118 if (demux->random_access) {
3119 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
3121 ret = gst_flv_demux_handle_seek_push (demux, event);
3125 ret = gst_pad_push_event (demux->sinkpad, event);
3133 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
3135 gboolean res = TRUE;
3138 demux = GST_FLV_DEMUX (parent);
3140 switch (GST_QUERY_TYPE (query)) {
3141 case GST_QUERY_DURATION:
3145 gst_query_parse_duration (query, &format, NULL);
3147 /* duration is time only */
3148 if (format != GST_FORMAT_TIME) {
3149 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
3155 /* Try to push upstream first */
3156 res = gst_pad_peer_query (demux->sinkpad, query);
3160 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3161 GST_TIME_ARGS (demux->duration));
3163 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3167 case GST_QUERY_POSITION:
3171 gst_query_parse_position (query, &format, NULL);
3173 /* position is time only */
3174 if (format != GST_FORMAT_TIME) {
3175 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3181 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3182 GST_TIME_ARGS (demux->segment.position));
3184 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3189 case GST_QUERY_SEEKING:{
3192 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3194 /* First ask upstream */
3195 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3198 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3205 /* FIXME, check index this way is not thread safe */
3206 if (fmt != GST_FORMAT_TIME || !demux->index) {
3207 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3208 } else if (demux->random_access) {
3209 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3212 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3213 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3216 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3217 gst_query_unref (peerquery);
3220 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3223 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3227 case GST_QUERY_SEGMENT:
3232 format = demux->segment.format;
3235 gst_segment_to_stream_time (&demux->segment, format,
3236 demux->segment.start);
3237 if ((stop = demux->segment.stop) == -1)
3238 stop = demux->segment.duration;
3240 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
3242 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
3246 case GST_QUERY_LATENCY:
3248 res = gst_pad_query_default (pad, parent, query);
3257 static GstStateChangeReturn
3258 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3261 GstStateChangeReturn ret;
3263 demux = GST_FLV_DEMUX (element);
3265 switch (transition) {
3266 case GST_STATE_CHANGE_READY_TO_PAUSED:
3267 /* If this is our own index destroy it as the
3268 * old entries might be wrong for the new stream */
3269 if (demux->own_index) {
3270 gst_object_unref (demux->index);
3271 demux->index = NULL;
3272 demux->own_index = FALSE;
3275 /* If no index was created, generate one */
3276 if (G_UNLIKELY (!demux->index)) {
3277 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3279 demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3281 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3283 demux->own_index = TRUE;
3285 gst_flv_demux_cleanup (demux);
3291 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3292 if (ret == GST_STATE_CHANGE_FAILURE)
3295 switch (transition) {
3296 case GST_STATE_CHANGE_PAUSED_TO_READY:
3297 gst_flv_demux_cleanup (demux);
3308 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3310 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3311 GstIndex *old_index;
3313 GST_OBJECT_LOCK (demux);
3315 old_index = demux->index;
3318 demux->index = gst_object_ref (index);
3319 demux->own_index = FALSE;
3321 demux->index = NULL;
3324 gst_object_unref (demux->index);
3326 gst_object_ref (index);
3328 GST_OBJECT_UNLOCK (demux);
3330 /* object lock might be taken again */
3332 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3334 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3336 gst_object_unref (index);
3341 gst_flv_demux_get_index (GstElement * element)
3343 GstIndex *result = NULL;
3345 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3347 GST_OBJECT_LOCK (demux);
3349 result = gst_object_ref (demux->index);
3350 GST_OBJECT_UNLOCK (demux);
3356 gst_flv_demux_dispose (GObject * object)
3358 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3360 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3362 if (demux->adapter) {
3363 gst_adapter_clear (demux->adapter);
3364 g_object_unref (demux->adapter);
3365 demux->adapter = NULL;
3368 if (demux->taglist) {
3369 gst_tag_list_unref (demux->taglist);
3370 demux->taglist = NULL;
3373 if (demux->flowcombiner) {
3374 gst_flow_combiner_free (demux->flowcombiner);
3375 demux->flowcombiner = NULL;
3378 if (demux->new_seg_event) {
3379 gst_event_unref (demux->new_seg_event);
3380 demux->new_seg_event = NULL;
3383 if (demux->audio_codec_data) {
3384 gst_buffer_unref (demux->audio_codec_data);
3385 demux->audio_codec_data = NULL;
3388 if (demux->video_codec_data) {
3389 gst_buffer_unref (demux->video_codec_data);
3390 demux->video_codec_data = NULL;
3393 if (demux->audio_pad) {
3394 gst_object_unref (demux->audio_pad);
3395 demux->audio_pad = NULL;
3398 if (demux->video_pad) {
3399 gst_object_unref (demux->video_pad);
3400 demux->video_pad = NULL;
3404 gst_object_unref (demux->index);
3405 demux->index = NULL;
3409 g_array_free (demux->times, TRUE);
3410 demux->times = NULL;
3413 if (demux->filepositions) {
3414 g_array_free (demux->filepositions, TRUE);
3415 demux->filepositions = NULL;
3418 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3422 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3424 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3425 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3427 gobject_class->dispose = gst_flv_demux_dispose;
3429 gstelement_class->change_state =
3430 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3433 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3434 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3437 gst_element_class_add_pad_template (gstelement_class,
3438 gst_static_pad_template_get (&flv_sink_template));
3439 gst_element_class_add_pad_template (gstelement_class,
3440 gst_static_pad_template_get (&audio_src_template));
3441 gst_element_class_add_pad_template (gstelement_class,
3442 gst_static_pad_template_get (&video_src_template));
3443 gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
3445 "Demux FLV feeds into digital streams",
3446 "Julien Moutte <julien@moutte.net>");
3450 gst_flv_demux_init (GstFlvDemux * demux)
3453 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3455 gst_pad_set_event_function (demux->sinkpad,
3456 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3457 gst_pad_set_chain_function (demux->sinkpad,
3458 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3459 gst_pad_set_activate_function (demux->sinkpad,
3460 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3461 gst_pad_set_activatemode_function (demux->sinkpad,
3462 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3464 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3466 demux->adapter = gst_adapter_new ();
3467 demux->taglist = gst_tag_list_new_empty ();
3468 demux->flowcombiner = gst_flow_combiner_new ();
3469 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3471 demux->own_index = FALSE;
3473 GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3475 gst_flv_demux_cleanup (demux);
3479 plugin_init (GstPlugin * plugin)
3481 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3483 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3484 gst_flv_demux_get_type ()) ||
3485 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3486 gst_flv_mux_get_type ()))
3492 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3493 flv, "FLV muxing and demuxing plugin",
3494 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)