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"
42 #include <gst/base/gstbytereader.h>
43 #include <gst/base/gstbytewriter.h>
44 #include <gst/pbutils/descriptions.h>
45 #include <gst/pbutils/pbutils.h>
46 #include <gst/audio/audio.h>
47 #include <gst/video/video.h>
48 #include <gst/tag/tag.h>
50 /* FIXME: don't rely on own GstIndex */
52 #include "gstmemindex.c"
53 #define GST_ASSOCIATION_FLAG_NONE GST_INDEX_ASSOCIATION_FLAG_NONE
54 #define GST_ASSOCIATION_FLAG_KEY_UNIT GST_INDEX_ASSOCIATION_FLAG_KEY_UNIT
55 #define GST_ASSOCIATION_FLAG_DELTA_UNIT GST_INDEX_ASSOCIATION_FLAG_DELTA_UNIT
57 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
60 GST_STATIC_CAPS ("video/x-flv")
63 static GstStaticPadTemplate audio_src_template =
64 GST_STATIC_PAD_TEMPLATE ("audio",
68 ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
69 "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
70 "audio/mpeg, mpegversion = (int) 4, stream-format = (string) raw, framed = (boolean) TRUE; "
71 "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
72 "audio/x-raw, format = (string) { U8, S16LE }, layout = (string) interleaved, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
73 "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
74 "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
75 "audio/x-speex, channels = (int) 1, rate = (int) 16000;")
78 static GstStaticPadTemplate video_src_template =
79 GST_STATIC_PAD_TEMPLATE ("video",
82 GST_STATIC_CAPS ("video/x-flash-video, flvversion=(int) 1; "
83 "video/x-flash-screen; "
84 "video/x-vp6-flash; " "video/x-vp6-alpha; "
85 "video/x-h264, stream-format=avc;")
88 GST_DEBUG_CATEGORY_STATIC (flvdemux_debug);
89 #define GST_CAT_DEFAULT flvdemux_debug
91 #define gst_flv_demux_parent_class parent_class
92 G_DEFINE_TYPE (GstFlvDemux, gst_flv_demux, GST_TYPE_ELEMENT);
94 /* 9 bytes of header + 4 bytes of first previous tag size */
95 #define FLV_HEADER_SIZE 13
96 /* 1 byte of tag type + 3 bytes of tag data size */
97 #define FLV_TAG_TYPE_SIZE 4
99 /* two seconds - consider dts are resynced to another base if this different */
100 #define RESYNC_THRESHOLD 2000
102 /* how much stream time to wait for audio tags to appear after we have video, or vice versa */
103 #define NO_MORE_PADS_THRESHOLD (6 * GST_SECOND)
105 static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
107 static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
108 GstEvent * event, gboolean seeking);
110 static gboolean gst_flv_demux_query (GstPad * pad, GstObject * parent,
112 static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent,
115 static GstIndex *gst_flv_demux_get_index (GstElement * element);
118 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
119 guint64 pos, gboolean keyframe)
121 GstIndexAssociation associations[2];
123 GstIndexEntry *entry;
125 GST_LOG_OBJECT (demux,
126 "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
127 keyframe, GST_TIME_ARGS (ts), pos);
129 /* if upstream is not seekable there is no point in building an index */
130 if (!demux->upstream_seekable)
133 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
138 /* entry may already have been added before, avoid adding indefinitely */
139 entry = gst_index_get_assoc_entry (index, demux->index_id,
140 GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
143 #ifndef GST_DISABLE_GST_DEBUG
147 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
148 key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
149 GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
150 ", keyframe %d", GST_TIME_ARGS (time), key);
151 /* there is not really a way to delete the existing one */
152 if (time != ts || key != ! !keyframe)
153 GST_DEBUG_OBJECT (demux, "metadata mismatch");
155 gst_object_unref (index);
159 associations[0].format = GST_FORMAT_TIME;
160 associations[0].value = ts;
161 associations[1].format = GST_FORMAT_BYTES;
162 associations[1].value = pos;
164 gst_index_add_associationv (index, demux->index_id,
165 (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
166 GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
167 (const GstIndexAssociation *) &associations);
169 if (pos > demux->index_max_pos)
170 demux->index_max_pos = pos;
171 if (ts > demux->index_max_time)
172 demux->index_max_time = ts;
174 gst_object_unref (index);
178 FLV_GET_STRING (GstByteReader * reader)
180 guint16 string_size = 0;
181 gchar *string = NULL;
182 const guint8 *str = NULL;
184 g_return_val_if_fail (reader != NULL, NULL);
186 if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
189 if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
192 string = g_try_malloc0 (string_size + 1);
193 if (G_UNLIKELY (!string)) {
197 if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
202 memcpy (string, str, string_size);
203 if (!g_utf8_validate (string, string_size, NULL)) {
212 gst_flv_demux_check_seekability (GstFlvDemux * demux)
215 gint64 start = -1, stop = -1;
217 demux->upstream_seekable = FALSE;
219 query = gst_query_new_seeking (GST_FORMAT_BYTES);
220 if (!gst_pad_peer_query (demux->sinkpad, query)) {
221 GST_DEBUG_OBJECT (demux, "seeking query failed");
222 gst_query_unref (query);
226 gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
229 gst_query_unref (query);
231 /* try harder to query upstream size if we didn't get it the first time */
232 if (demux->upstream_seekable && stop == -1) {
233 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
234 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
237 /* if upstream doesn't know the size, it's likely that it's not seekable in
238 * practice even if it technically may be seekable */
239 if (demux->upstream_seekable && (start != 0 || stop <= start)) {
240 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
241 demux->upstream_seekable = FALSE;
244 GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
248 parse_flv_demux_parse_date_string (const gchar * s)
250 static const gchar months[12][4] = {
251 "Jan", "Feb", "Mar", "Apr",
252 "May", "Jun", "Jul", "Aug",
253 "Sep", "Oct", "Nov", "Dec"
255 GstDateTime *dt = NULL;
258 gchar *endptr, *stripped;
260 gint year = -1, month = -1, day = -1;
261 gint hour = -1, minute = -1, seconds = -1;
263 stripped = g_strstrip (g_strdup (s));
265 /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
266 tokens = g_strsplit (stripped, " ", -1);
270 if (g_strv_length (tokens) != 5)
274 d = g_ascii_strtoull (tokens[4], &endptr, 10);
275 if (d == 0 && *endptr != '\0')
281 if (strlen (tokens[1]) != 3)
283 for (i = 0; i < 12; i++) {
284 if (!strcmp (tokens[1], months[i])) {
294 d = g_ascii_strtoull (tokens[2], &endptr, 10);
295 if (d == 0 && *endptr != '\0')
302 if (sscanf (tokens[3], "%d:%d:%d", &hh, &mm, &ss) < 2)
304 if (hh >= 0 && hh < 24 && mm >= 0 && mm < 60 && ss >= 0 && ss < 60) {
316 dt = gst_date_time_new (0.0, year, month, day, hour, minute, seconds);
322 gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
323 gboolean * end_marker)
325 gchar *tag_name = NULL;
328 /* Initialize the end_marker flag to FALSE */
331 /* Name of the tag */
332 tag_name = FLV_GET_STRING (reader);
333 if (G_UNLIKELY (!tag_name)) {
334 GST_WARNING_OBJECT (demux, "failed reading tag name");
338 /* What kind of object is that */
339 if (!gst_byte_reader_get_uint8 (reader, &tag_type))
342 GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
346 { /* Use a union to read the uint64 and then as a double */
349 if (!gst_byte_reader_get_float64_be (reader, &d))
352 GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
354 if (!strcmp (tag_name, "duration")) {
355 demux->duration = d * GST_SECOND;
357 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
358 GST_TAG_DURATION, demux->duration, NULL);
359 } else if (!strcmp (tag_name, "AspectRatioX")) {
361 demux->got_par = TRUE;
362 } else if (!strcmp (tag_name, "AspectRatioY")) {
364 demux->got_par = TRUE;
365 } else if (!strcmp (tag_name, "width")) {
367 } else if (!strcmp (tag_name, "height")) {
369 } else if (!strcmp (tag_name, "framerate")) {
370 demux->framerate = d;
372 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
377 case 1: /* Boolean */
381 if (!gst_byte_reader_get_uint8 (reader, &b))
384 GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
386 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
394 s = FLV_GET_STRING (reader);
398 GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
400 if (!strcmp (tag_name, "creationdate")) {
403 dt = parse_flv_demux_parse_date_string (s);
405 GST_DEBUG_OBJECT (demux, "Failed to parse '%s' into datetime", s);
407 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
408 GST_TAG_DATE_TIME, dt, NULL);
409 gst_date_time_unref (dt);
411 } else if (!strcmp (tag_name, "creator")) {
412 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
413 GST_TAG_ARTIST, s, NULL);
414 } else if (!strcmp (tag_name, "title")) {
415 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
416 GST_TAG_TITLE, s, NULL);
417 } else if (!strcmp (tag_name, "metadatacreator")) {
418 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
419 GST_TAG_ENCODER, s, NULL);
421 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
430 gboolean end_of_object_marker = FALSE;
432 while (!end_of_object_marker) {
433 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
434 &end_of_object_marker);
436 if (G_UNLIKELY (!ok)) {
437 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
444 case 8: /* ECMA array */
446 guint32 nb_elems = 0;
447 gboolean end_of_object_marker = FALSE;
449 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
452 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
455 while (!end_of_object_marker) {
456 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
457 &end_of_object_marker);
459 if (G_UNLIKELY (!ok)) {
460 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
467 case 9: /* End marker */
469 GST_DEBUG_OBJECT (demux, "end marker ?");
470 if (tag_name[0] == '\0') {
472 GST_DEBUG_OBJECT (demux, "end marker detected");
481 guint32 nb_elems = 0;
483 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
486 GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
488 if (!strcmp (tag_name, "times")) {
490 g_array_free (demux->times, TRUE);
492 demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
493 } else if (!strcmp (tag_name, "filepositions")) {
494 if (demux->filepositions) {
495 g_array_free (demux->filepositions, TRUE);
497 demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
501 guint8 elem_type = 0;
503 if (!gst_byte_reader_get_uint8 (reader, &elem_type))
511 if (!gst_byte_reader_get_float64_be (reader, &d))
514 GST_DEBUG_OBJECT (demux, "element is a double %f", d);
516 if (!strcmp (tag_name, "times") && demux->times) {
517 g_array_append_val (demux->times, d);
518 } else if (!strcmp (tag_name, "filepositions") &&
519 demux->filepositions) {
520 g_array_append_val (demux->filepositions, d);
525 GST_WARNING_OBJECT (demux, "unsupported array element type %d",
537 if (!gst_byte_reader_get_float64_be (reader, &d))
540 if (!gst_byte_reader_get_int16_be (reader, &i))
543 GST_DEBUG_OBJECT (demux,
544 "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
546 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
551 GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
565 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
567 GstFlowReturn ret = GST_FLOW_OK;
568 GstByteReader reader;
572 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 7, GST_FLOW_ERROR);
574 gst_buffer_map (buffer, &map, GST_MAP_READ);
575 gst_byte_reader_init (&reader, map.data, map.size);
577 gst_byte_reader_skip_unchecked (&reader, 7);
579 GST_LOG_OBJECT (demux, "parsing a script tag");
581 if (!gst_byte_reader_get_uint8 (&reader, &type))
586 gchar *function_name;
589 function_name = FLV_GET_STRING (&reader);
591 GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
593 if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
594 gboolean end_marker = FALSE;
595 GST_DEBUG_OBJECT (demux, "we have a metadata script object");
597 if (!gst_byte_reader_get_uint8 (&reader, &type)) {
598 g_free (function_name);
605 guint32 nb_elems = 0;
608 if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
609 g_free (function_name);
613 /* The number of elements is just a hint, some files have
614 nb_elements == 0 and actually contain items. */
615 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
618 /* fallthrough to read data */
622 while (!end_marker) {
624 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
626 if (G_UNLIKELY (!ok)) {
627 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
634 GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
635 g_free (function_name);
639 demux->push_tags = TRUE;
642 g_free (function_name);
644 if (demux->times && demux->filepositions) {
647 /* If an index was found, insert associations */
648 num = MIN (demux->times->len, demux->filepositions->len);
649 for (i = 0; i < num; i++) {
650 guint64 time, fileposition;
652 time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
653 fileposition = g_array_index (demux->filepositions, gdouble, i);
654 gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
657 demux->indexed = TRUE;
662 gst_buffer_unmap (buffer, &map);
668 have_group_id (GstFlvDemux * demux)
672 event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
674 if (gst_event_parse_group_id (event, &demux->group_id))
675 demux->have_group_id = TRUE;
677 demux->have_group_id = FALSE;
678 gst_event_unref (event);
679 } else if (!demux->have_group_id) {
680 demux->have_group_id = TRUE;
681 demux->group_id = gst_util_group_id_next ();
684 return demux->have_group_id;
688 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
689 guint32 rate, guint32 channels, guint32 width)
691 GstCaps *caps = NULL, *old_caps;
692 gchar *codec_name = NULL;
693 gboolean ret = FALSE;
694 guint adjusted_rate = rate;
700 caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
705 caps = gst_caps_new_simple ("audio/mpeg",
706 "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
707 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
712 GstAudioFormat format;
714 /* Assuming little endian for 0 (aka endianness of the
715 * system on which the file was created) as most people
716 * are probably using little endian machines */
717 format = gst_audio_format_build_integer ((width == 8) ? FALSE : TRUE,
718 G_LITTLE_ENDIAN, width, width);
720 caps = gst_caps_new_simple ("audio/x-raw",
721 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
722 "layout", G_TYPE_STRING, "interleaved", NULL);
728 caps = gst_caps_new_empty_simple ("audio/x-nellymoser");
733 if (!demux->audio_codec_data) {
734 GST_DEBUG_OBJECT (demux, "don't have AAC codec data yet");
739 gst_buffer_map (demux->audio_codec_data, &map, GST_MAP_READ);
741 /* use codec-data to extract and verify samplerate */
745 freq_index = GST_READ_UINT16_BE (map.data);
746 freq_index = (freq_index & 0x0780) >> 7;
748 gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
750 if (adjusted_rate && (rate != adjusted_rate)) {
751 GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
754 adjusted_rate = rate;
757 gst_buffer_unmap (demux->audio_codec_data, &map);
759 caps = gst_caps_new_simple ("audio/mpeg",
760 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
761 "stream-format", G_TYPE_STRING, "raw", NULL);
765 caps = gst_caps_new_empty_simple ("audio/x-alaw");
768 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
772 GValue streamheader = G_VALUE_INIT;
773 GValue value = G_VALUE_INIT;
775 GstStructure *structure;
779 caps = gst_caps_new_empty_simple ("audio/x-speex");
780 structure = gst_caps_get_structure (caps, 0);
782 GST_DEBUG_OBJECT (demux, "generating speex header");
784 /* Speex decoder expects streamheader to be { [header], [comment] } */
785 g_value_init (&streamheader, GST_TYPE_ARRAY);
788 gst_byte_writer_init_with_size (&w, 80, TRUE);
789 gst_byte_writer_put_data (&w, (guint8 *) "Speex ", 8);
790 gst_byte_writer_put_data (&w, (guint8 *) "1.1.12", 7);
791 gst_byte_writer_fill (&w, 0, 13);
792 gst_byte_writer_put_uint32_le (&w, 1); /* version */
793 gst_byte_writer_put_uint32_le (&w, 80); /* header_size */
794 gst_byte_writer_put_uint32_le (&w, 16000); /* rate */
795 gst_byte_writer_put_uint32_le (&w, 1); /* mode: Wideband */
796 gst_byte_writer_put_uint32_le (&w, 4); /* mode_bitstream_version */
797 gst_byte_writer_put_uint32_le (&w, 1); /* nb_channels: 1 */
798 gst_byte_writer_put_uint32_le (&w, -1); /* bitrate */
799 gst_byte_writer_put_uint32_le (&w, 0x50); /* frame_size */
800 gst_byte_writer_put_uint32_le (&w, 0); /* VBR */
801 gst_byte_writer_put_uint32_le (&w, 1); /* frames_per_packet */
802 gst_byte_writer_put_uint32_le (&w, 0); /* extra_headers */
803 gst_byte_writer_put_uint32_le (&w, 0); /* reserved1 */
804 gst_byte_writer_put_uint32_le (&w, 0); /* reserved2 */
805 g_assert (gst_byte_writer_get_size (&w) == 80);
807 g_value_init (&value, GST_TYPE_BUFFER);
808 g_value_take_boxed (&value, gst_byte_writer_reset_and_get_buffer (&w));
809 gst_value_array_append_value (&streamheader, &value);
810 g_value_unset (&value);
813 g_value_init (&value, GST_TYPE_BUFFER);
814 tags = gst_tag_list_new_empty ();
815 buf = gst_tag_list_to_vorbiscomment_buffer (tags, NULL, 0, "No comments");
816 gst_tag_list_unref (tags);
817 g_value_take_boxed (&value, buf);
818 gst_value_array_append_value (&streamheader, &value);
819 g_value_unset (&value);
821 gst_structure_take_value (structure, "streamheader", &streamheader);
824 adjusted_rate = 16000;
828 GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
832 if (G_UNLIKELY (!caps)) {
833 GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
837 gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
838 "channels", G_TYPE_INT, channels, NULL);
840 if (demux->audio_codec_data) {
841 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
842 demux->audio_codec_data, NULL);
845 old_caps = gst_pad_get_current_caps (demux->audio_pad);
848 gst_pad_create_stream_id (demux->audio_pad, GST_ELEMENT_CAST (demux),
851 event = gst_event_new_stream_start (stream_id);
852 if (have_group_id (demux))
853 gst_event_set_group_id (event, demux->group_id);
854 gst_pad_push_event (demux->audio_pad, event);
857 if (!old_caps || !gst_caps_is_equal (old_caps, caps))
858 ret = gst_pad_set_caps (demux->audio_pad, caps);
863 gst_caps_unref (old_caps);
866 if (G_LIKELY (ret)) {
867 /* Store the caps we got from tags */
868 demux->audio_codec_tag = codec_tag;
870 demux->channels = channels;
871 demux->width = width;
874 codec_name = gst_pb_utils_get_codec_description (caps);
877 if (demux->taglist == NULL)
878 demux->taglist = gst_tag_list_new_empty ();
879 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
880 GST_TAG_AUDIO_CODEC, codec_name, NULL);
884 GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
885 GST_PTR_FORMAT, caps);
887 GST_DEBUG_OBJECT (demux->audio_pad, "delayed setting caps");
890 GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
891 GST_PTR_FORMAT, caps);
895 gst_caps_unref (caps);
902 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
906 if (demux->audio_pad)
907 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
909 if (demux->video_pad)
910 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
912 gst_event_unref (event);
918 gst_flv_demux_push_tags (GstFlvDemux * demux)
920 if (demux->has_audio && !demux->audio_pad) {
921 GST_DEBUG_OBJECT (demux,
922 "Waiting for audio stream pad to come up before we can push tags");
925 if (demux->has_video && !demux->video_pad) {
926 GST_DEBUG_OBJECT (demux,
927 "Waiting for video stream pad to come up before we can push tags");
930 if (demux->taglist) {
931 GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
933 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
934 gst_flv_demux_push_src_event (demux, gst_event_new_tag (demux->taglist));
935 demux->taglist = gst_tag_list_new_empty ();
936 demux->push_tags = FALSE;
941 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 dts, gboolean discont,
942 guint32 * last, GstClockTime * offset)
944 gboolean ret = FALSE;
945 gint32 ddts = dts - *last;
946 if (!discont && ddts <= -RESYNC_THRESHOLD) {
947 /* Theoretically, we should use substract the duration of the last buffer,
948 but this demuxer sends no durations on buffers, not sure if it cannot
949 know, or just does not care to calculate. */
950 *offset -= ddts * GST_MSECOND;
951 GST_WARNING_OBJECT (demux,
952 "Large dts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
953 GST_TIME_FORMAT "", ddts, GST_TIME_ARGS (*offset));
963 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
965 GstFlowReturn ret = GST_FLOW_OK;
966 guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
967 guint32 codec_data = 0, pts_ext = 0;
973 GST_LOG_OBJECT (demux, "parsing an audio tag");
975 if (G_UNLIKELY (!demux->audio_pad && demux->no_more_pads)) {
976 #ifndef GST_DISABLE_DEBUG
977 if (G_UNLIKELY (!demux->no_audio_warned)) {
978 GST_WARNING_OBJECT (demux,
979 "Signaled no-more-pads already but had no audio pad -- ignoring");
980 demux->no_audio_warned = TRUE;
986 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
989 /* Error out on tags with too small headers */
990 if (gst_buffer_get_size (buffer) < 11) {
991 GST_ERROR_OBJECT (demux, "Too small tag size (%" G_GSIZE_FORMAT ")",
992 gst_buffer_get_size (buffer));
993 return GST_FLOW_ERROR;
996 gst_buffer_map (buffer, &map, GST_MAP_READ);
999 /* Grab information about audio tag */
1000 pts = GST_READ_UINT24_BE (data);
1001 /* read the pts extension to 32 bits integer */
1002 pts_ext = GST_READ_UINT8 (data + 3);
1004 pts |= pts_ext << 24;
1006 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1007 data[2], data[3], pts);
1009 /* Skip the stream id and go directly to the flags */
1010 flags = GST_READ_UINT8 (data + 7);
1012 /* Silently skip buffers with no data */
1025 if ((flags & 0x0C) == 0x0C) {
1027 } else if ((flags & 0x0C) == 0x08) {
1029 } else if ((flags & 0x0C) == 0x04) {
1033 codec_tag = flags >> 4;
1034 if (codec_tag == 10) { /* AAC has an extra byte for packet type */
1040 /* codec tags with special rates */
1041 if (codec_tag == 5 || codec_tag == 14)
1043 else if ((codec_tag == 4) || (codec_tag == 11))
1046 GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
1047 "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
1050 if (codec_tag == 10) {
1051 guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
1053 switch (aac_packet_type) {
1056 /* AudioSpecificConfig data */
1057 GST_LOG_OBJECT (demux, "got an AAC codec data packet");
1058 if (demux->audio_codec_data) {
1059 gst_buffer_unref (demux->audio_codec_data);
1061 demux->audio_codec_data =
1062 gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1063 7 + codec_data, demux->tag_data_size - codec_data);
1065 /* Use that buffer data in the caps */
1066 if (demux->audio_pad)
1067 gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1072 if (!demux->audio_codec_data) {
1073 GST_ERROR_OBJECT (demux, "got AAC audio packet before codec data");
1077 /* AAC raw packet */
1078 GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
1081 GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
1086 /* If we don't have our audio pad created, then create it. */
1087 if (G_UNLIKELY (!demux->audio_pad)) {
1089 gst_pad_new_from_template (gst_element_class_get_pad_template
1090 (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
1091 if (G_UNLIKELY (!demux->audio_pad)) {
1092 GST_WARNING_OBJECT (demux, "failed creating audio pad");
1093 ret = GST_FLOW_ERROR;
1097 /* Set functions on the pad */
1098 gst_pad_set_query_function (demux->audio_pad,
1099 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1100 gst_pad_set_event_function (demux->audio_pad,
1101 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1103 gst_pad_use_fixed_caps (demux->audio_pad);
1105 /* Make it active */
1106 gst_pad_set_active (demux->audio_pad, TRUE);
1108 /* Negotiate caps */
1109 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1111 gst_object_unref (demux->audio_pad);
1112 demux->audio_pad = NULL;
1113 ret = GST_FLOW_ERROR;
1116 #ifndef GST_DISABLE_GST_DEBUG
1120 caps = gst_pad_get_current_caps (demux->audio_pad);
1121 GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
1124 gst_caps_unref (caps);
1128 /* We need to set caps before adding */
1129 gst_element_add_pad (GST_ELEMENT (demux),
1130 gst_object_ref (demux->audio_pad));
1131 gst_flow_combiner_add_pad (demux->flowcombiner, demux->audio_pad);
1133 /* We only emit no more pads when we have audio and video. Indeed we can
1134 * not trust the FLV header to tell us if there will be only audio or
1135 * only video and we would just break discovery of some files */
1136 if (demux->audio_pad && demux->video_pad) {
1137 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1138 gst_element_no_more_pads (GST_ELEMENT (demux));
1139 demux->no_more_pads = TRUE;
1140 demux->push_tags = TRUE;
1144 /* Check if caps have changed */
1145 if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
1146 codec_tag != demux->audio_codec_tag || width != demux->width)) {
1147 GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
1149 gst_buffer_replace (&demux->audio_codec_data, NULL);
1151 /* Negotiate caps */
1152 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1154 ret = GST_FLOW_ERROR;
1159 /* Push taglist if present */
1160 if (G_UNLIKELY (demux->push_tags))
1161 gst_flv_demux_push_tags (demux);
1163 /* Check if we have anything to push */
1164 if (demux->tag_data_size <= codec_data) {
1165 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1169 /* Create buffer from pad */
1170 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1171 7 + codec_data, demux->tag_data_size - codec_data);
1173 /* detect (and deem to be resyncs) large pts gaps */
1174 if (gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
1175 &demux->last_audio_pts, &demux->audio_time_offset)) {
1176 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
1179 /* Fill buffer with data */
1180 GST_BUFFER_PTS (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
1181 GST_BUFFER_DTS (outbuf) = GST_BUFFER_PTS (outbuf);
1182 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1183 GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
1184 GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
1186 if (demux->duration == GST_CLOCK_TIME_NONE ||
1187 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1188 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1190 /* Only add audio frames to the index if we have no video,
1191 * and if the index is not yet complete */
1192 if (!demux->has_video && !demux->indexed) {
1193 gst_flv_demux_parse_and_add_index_entry (demux,
1194 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
1197 if (G_UNLIKELY (demux->audio_need_discont)) {
1198 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1199 demux->audio_need_discont = FALSE;
1202 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1204 /* Do we need a newsegment event ? */
1205 if (G_UNLIKELY (demux->audio_need_segment)) {
1206 if (!demux->new_seg_event) {
1207 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1208 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1209 GST_TIME_ARGS (demux->segment.position),
1210 GST_TIME_ARGS (demux->segment.stop));
1211 demux->segment.start = demux->segment.time = demux->segment.position;
1212 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1214 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1217 gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1219 demux->audio_need_segment = FALSE;
1222 GST_LOG_OBJECT (demux,
1223 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1224 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1225 gst_buffer_get_size (outbuf),
1226 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1227 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1229 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1230 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1232 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1233 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1236 if (G_UNLIKELY (!demux->no_more_pads
1237 && (GST_CLOCK_DIFF (demux->audio_start,
1238 GST_BUFFER_TIMESTAMP (outbuf)) > NO_MORE_PADS_THRESHOLD))) {
1239 GST_DEBUG_OBJECT (demux,
1240 "Signalling no-more-pads because no video stream was found"
1241 " after 6 seconds of audio");
1242 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1243 demux->no_more_pads = TRUE;
1244 demux->push_tags = TRUE;
1247 /* Push downstream */
1248 ret = gst_pad_push (demux->audio_pad, outbuf);
1250 if (G_UNLIKELY (ret != GST_FLOW_OK) &&
1251 demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1252 demux->segment.position > demux->segment.stop) {
1253 /* In reverse playback we can get a GST_FLOW_EOS when
1254 * we are at the end of the segment, so we just need to jump
1255 * back to the previous section. */
1256 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1257 demux->audio_done = TRUE;
1262 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner,
1263 demux->audio_pad, ret);
1266 gst_buffer_unmap (buffer, &map);
1272 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1274 gboolean ret = FALSE;
1275 GstCaps *caps = NULL, *old_caps;
1276 gchar *codec_name = NULL;
1280 /* Generate caps for that pad */
1281 switch (codec_tag) {
1284 gst_caps_new_simple ("video/x-flash-video", "flvversion", G_TYPE_INT,
1288 caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1291 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1294 caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1297 if (!demux->video_codec_data) {
1298 GST_DEBUG_OBJECT (demux, "don't have h264 codec data yet");
1303 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1306 /* The following two are non-standard but apparently used, see in ffmpeg
1307 * https://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/flvdec.c;h=2bf1e059e1cbeeb79e4af9542da23f4560e1cf59;hb=b18d6c58000beed872d6bb1fe7d0fbe75ae26aef#l254
1308 * https://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/flvdec.c;h=2bf1e059e1cbeeb79e4af9542da23f4560e1cf59;hb=b18d6c58000beed872d6bb1fe7d0fbe75ae26aef#l282
1311 caps = gst_caps_new_empty_simple ("video/x-h263");
1315 gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
1316 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1319 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1322 if (G_UNLIKELY (!caps)) {
1323 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1327 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1328 demux->par_x, demux->par_y, NULL);
1330 if (G_LIKELY (demux->w)) {
1331 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1334 if (G_LIKELY (demux->h)) {
1335 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1338 if (G_LIKELY (demux->framerate)) {
1339 gint num = 0, den = 0;
1341 gst_video_guess_framerate (GST_SECOND / demux->framerate, &num, &den);
1342 GST_DEBUG_OBJECT (demux->video_pad,
1343 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1346 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1349 if (demux->video_codec_data) {
1350 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1351 demux->video_codec_data, NULL);
1354 old_caps = gst_pad_get_current_caps (demux->video_pad);
1357 gst_pad_create_stream_id (demux->video_pad, GST_ELEMENT_CAST (demux),
1359 event = gst_event_new_stream_start (stream_id);
1362 if (have_group_id (demux))
1363 gst_event_set_group_id (event, demux->group_id);
1364 gst_pad_push_event (demux->video_pad, event);
1367 if (!old_caps || !gst_caps_is_equal (old_caps, caps))
1368 ret = gst_pad_set_caps (demux->video_pad, caps);
1373 gst_caps_unref (old_caps);
1376 if (G_LIKELY (ret)) {
1377 /* Store the caps we have set */
1378 demux->video_codec_tag = codec_tag;
1381 codec_name = gst_pb_utils_get_codec_description (caps);
1384 if (demux->taglist == NULL)
1385 demux->taglist = gst_tag_list_new_empty ();
1386 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1387 GST_TAG_VIDEO_CODEC, codec_name, NULL);
1388 g_free (codec_name);
1391 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1392 GST_PTR_FORMAT, caps);
1394 GST_DEBUG_OBJECT (demux->video_pad, "delayed setting caps");
1397 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1398 GST_PTR_FORMAT, caps);
1402 gst_caps_unref (caps);
1408 static GstFlowReturn
1409 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1411 GstFlowReturn ret = GST_FLOW_OK;
1412 guint32 dts = 0, codec_data = 1, dts_ext = 0;
1414 gboolean keyframe = FALSE;
1415 guint8 flags = 0, codec_tag = 0;
1420 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1423 GST_LOG_OBJECT (demux, "parsing a video tag");
1426 (!demux->video_pad && demux->no_more_pads) {
1427 #ifndef GST_DISABLE_DEBUG
1429 (!demux->no_video_warned) {
1430 GST_WARNING_OBJECT (demux,
1431 "Signaled no-more-pads already but had no video pad -- ignoring");
1432 demux->no_video_warned = TRUE;
1438 if (gst_buffer_get_size (buffer) < 12) {
1439 GST_ERROR_OBJECT (demux, "Too small tag size");
1440 return GST_FLOW_ERROR;
1443 gst_buffer_map (buffer, &map, GST_MAP_READ);
1446 /* Grab information about video tag */
1447 dts = GST_READ_UINT24_BE (data);
1448 /* read the dts extension to 32 bits integer */
1449 dts_ext = GST_READ_UINT8 (data + 3);
1451 dts |= dts_ext << 24;
1453 GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1454 data[2], data[3], dts);
1456 /* Skip the stream id and go directly to the flags */
1457 flags = GST_READ_UINT8 (data + 7);
1460 if ((flags >> 4) == 1) {
1464 codec_tag = flags & 0x0F;
1465 if (codec_tag == 4 || codec_tag == 5) {
1467 } else if (codec_tag == 7) {
1470 cts = GST_READ_UINT24_BE (data + 9);
1471 cts = (cts + 0xff800000) ^ 0xff800000;
1473 GST_LOG_OBJECT (demux, "got cts %d", cts);
1476 GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1477 "(flags %02X)", codec_tag, keyframe, flags);
1479 if (codec_tag == 7) {
1480 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1482 switch (avc_packet_type) {
1485 /* AVCDecoderConfigurationRecord data */
1486 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1487 if (demux->video_codec_data) {
1488 gst_buffer_unref (demux->video_codec_data);
1490 demux->video_codec_data = gst_buffer_copy_region (buffer,
1491 GST_BUFFER_COPY_MEMORY, 7 + codec_data,
1492 demux->tag_data_size - codec_data);;
1493 /* Use that buffer data in the caps */
1494 if (demux->video_pad)
1495 gst_flv_demux_video_negotiate (demux, codec_tag);
1499 /* H.264 NALU packet */
1500 if (!demux->video_codec_data) {
1501 GST_ERROR_OBJECT (demux, "got H.264 video packet before codec data");
1505 GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1508 GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1513 /* If we don't have our video pad created, then create it. */
1514 if (G_UNLIKELY (!demux->video_pad)) {
1516 gst_pad_new_from_template (gst_element_class_get_pad_template
1517 (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1518 if (G_UNLIKELY (!demux->video_pad)) {
1519 GST_WARNING_OBJECT (demux, "failed creating video pad");
1520 ret = GST_FLOW_ERROR;
1524 /* Set functions on the pad */
1525 gst_pad_set_query_function (demux->video_pad,
1526 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1527 gst_pad_set_event_function (demux->video_pad,
1528 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1530 gst_pad_use_fixed_caps (demux->video_pad);
1532 /* Make it active */
1533 gst_pad_set_active (demux->video_pad, TRUE);
1535 /* Needs to be active before setting caps */
1536 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1537 gst_object_unref (demux->video_pad);
1538 demux->video_pad = NULL;
1539 ret = GST_FLOW_ERROR;
1543 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1544 * metadata tag that would come later and trigger a caps change */
1545 demux->got_par = FALSE;
1547 #ifndef GST_DISABLE_GST_DEBUG
1551 caps = gst_pad_get_current_caps (demux->video_pad);
1552 GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1555 gst_caps_unref (caps);
1559 /* We need to set caps before adding */
1560 gst_element_add_pad (GST_ELEMENT (demux),
1561 gst_object_ref (demux->video_pad));
1562 gst_flow_combiner_add_pad (demux->flowcombiner, demux->video_pad);
1564 /* We only emit no more pads when we have audio and video. Indeed we can
1565 * not trust the FLV header to tell us if there will be only audio or
1566 * only video and we would just break discovery of some files */
1567 if (demux->audio_pad && demux->video_pad) {
1568 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1569 gst_element_no_more_pads (GST_ELEMENT (demux));
1570 demux->no_more_pads = TRUE;
1571 demux->push_tags = TRUE;
1575 /* Check if caps have changed */
1576 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1577 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1578 gst_buffer_replace (&demux->video_codec_data, NULL);
1580 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1581 ret = GST_FLOW_ERROR;
1585 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1586 * metadata tag that would come later and trigger a caps change */
1587 demux->got_par = FALSE;
1590 /* Push taglist if present */
1591 if (G_UNLIKELY (demux->push_tags))
1592 gst_flv_demux_push_tags (demux);
1594 /* Check if we have anything to push */
1595 if (demux->tag_data_size <= codec_data) {
1596 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1600 /* Create buffer from pad */
1601 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1602 7 + codec_data, demux->tag_data_size - codec_data);
1604 /* detect (and deem to be resyncs) large dts gaps */
1605 if (gst_flv_demux_update_resync (demux, dts, demux->video_need_discont,
1606 &demux->last_video_dts, &demux->video_time_offset)) {
1607 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
1610 /* Fill buffer with data */
1611 GST_LOG_OBJECT (demux, "dts %u pts %u cts %d", dts, dts + cts, cts);
1613 GST_BUFFER_PTS (outbuf) =
1614 (dts + cts) * GST_MSECOND + demux->video_time_offset;
1615 GST_BUFFER_DTS (outbuf) = dts * GST_MSECOND + demux->video_time_offset;
1616 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1617 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1618 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1620 if (demux->duration == GST_CLOCK_TIME_NONE ||
1621 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1622 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1625 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1627 if (!demux->indexed) {
1628 gst_flv_demux_parse_and_add_index_entry (demux,
1629 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1632 if (G_UNLIKELY (demux->video_need_discont)) {
1633 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1634 demux->video_need_discont = FALSE;
1637 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1639 /* Do we need a newsegment event ? */
1640 if (G_UNLIKELY (demux->video_need_segment)) {
1641 if (!demux->new_seg_event) {
1642 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1643 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1644 GST_TIME_ARGS (demux->segment.position),
1645 GST_TIME_ARGS (demux->segment.stop));
1646 demux->segment.start = demux->segment.time = demux->segment.position;
1647 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1649 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1652 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1654 demux->video_need_segment = FALSE;
1657 GST_LOG_OBJECT (demux,
1658 "pushing %" G_GSIZE_FORMAT " bytes buffer at dts %" GST_TIME_FORMAT
1659 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1660 ", keyframe (%d)", gst_buffer_get_size (outbuf),
1661 GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
1662 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1665 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1666 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1668 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1669 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1672 if (G_UNLIKELY (!demux->no_more_pads
1673 && (GST_CLOCK_DIFF (demux->video_start,
1674 GST_BUFFER_TIMESTAMP (outbuf)) > NO_MORE_PADS_THRESHOLD))) {
1675 GST_DEBUG_OBJECT (demux,
1676 "Signalling no-more-pads because no audio stream was found"
1677 " after 6 seconds of video");
1678 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1679 demux->no_more_pads = TRUE;
1680 demux->push_tags = TRUE;
1683 /* Push downstream */
1684 ret = gst_pad_push (demux->video_pad, outbuf);
1686 if (G_UNLIKELY (ret != GST_FLOW_OK) &&
1687 demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1688 demux->segment.position > demux->segment.stop) {
1689 /* In reverse playback we can get a GST_FLOW_EOS when
1690 * we are at the end of the segment, so we just need to jump
1691 * back to the previous section. */
1692 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1693 demux->video_done = TRUE;
1698 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner,
1699 demux->video_pad, ret);
1702 gst_buffer_unmap (buffer, &map);
1707 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1708 GstBuffer * buffer, size_t * tag_size)
1710 guint32 dts = 0, dts_ext = 0;
1711 guint32 tag_data_size;
1713 gboolean keyframe = TRUE;
1714 GstClockTime ret = GST_CLOCK_TIME_NONE;
1719 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1720 GST_CLOCK_TIME_NONE);
1722 gst_buffer_map (buffer, &map, GST_MAP_READ);
1728 if (type != 9 && type != 8 && type != 18) {
1729 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1734 demux->has_video = TRUE;
1736 demux->has_audio = TRUE;
1738 tag_data_size = GST_READ_UINT24_BE (data + 1);
1740 if (size >= tag_data_size + 11 + 4) {
1741 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1742 GST_WARNING_OBJECT (demux, "Invalid tag size");
1748 *tag_size = tag_data_size + 11 + 4;
1752 GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X", data[0], data[1],
1755 /* Grab timestamp of tag tag */
1756 dts = GST_READ_UINT24_BE (data);
1757 /* read the dts extension to 32 bits integer */
1758 dts_ext = GST_READ_UINT8 (data + 3);
1760 dts |= dts_ext << 24;
1765 keyframe = ((data[0] >> 4) == 1);
1768 ret = dts * GST_MSECOND;
1769 GST_LOG_OBJECT (demux, "dts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1771 if (index && !demux->indexed && (type == 9 || (type == 8
1772 && !demux->has_video))) {
1773 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1777 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1778 demux->duration = ret;
1781 gst_buffer_unmap (buffer, &map);
1785 static GstFlowReturn
1786 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1788 GstFlowReturn ret = GST_FLOW_OK;
1789 guint8 tag_type = 0;
1792 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1794 gst_buffer_map (buffer, &map, GST_MAP_READ);
1796 tag_type = map.data[0];
1798 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1799 * 4 bytes of previous tag size */
1800 demux->tag_data_size = GST_READ_UINT24_BE (map.data + 1);
1801 demux->tag_size = demux->tag_data_size + 11;
1803 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1804 demux->tag_data_size);
1806 gst_buffer_unmap (buffer, &map);
1810 demux->state = FLV_STATE_TAG_VIDEO;
1811 demux->has_video = TRUE;
1814 demux->state = FLV_STATE_TAG_AUDIO;
1815 demux->has_audio = TRUE;
1818 demux->state = FLV_STATE_TAG_SCRIPT;
1821 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1822 demux->state = FLV_STATE_SKIP;
1828 static GstFlowReturn
1829 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1831 GstFlowReturn ret = GST_FLOW_OK;
1834 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1836 gst_buffer_map (buffer, &map, GST_MAP_READ);
1838 /* Check for the FLV tag */
1839 if (map.data[0] == 'F' && map.data[1] == 'L' && map.data[2] == 'V') {
1840 GST_DEBUG_OBJECT (demux, "FLV header detected");
1842 if (G_UNLIKELY (demux->strict)) {
1843 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1849 if (map.data[3] == '1') {
1850 GST_DEBUG_OBJECT (demux, "FLV version 1 detected");
1852 if (G_UNLIKELY (demux->strict)) {
1853 GST_WARNING_OBJECT (demux, "invalid header version detected");
1860 /* Now look at audio/video flags */
1862 guint8 flags = map.data[4];
1864 demux->has_video = demux->has_audio = FALSE;
1867 GST_DEBUG_OBJECT (demux, "there is a video stream");
1868 demux->has_video = TRUE;
1871 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1872 demux->has_audio = TRUE;
1876 /* do a one-time seekability check */
1877 gst_flv_demux_check_seekability (demux);
1879 /* We don't care about the rest */
1880 demux->need_header = FALSE;
1883 gst_buffer_unmap (buffer, &map);
1889 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1891 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1893 gst_adapter_clear (demux->adapter);
1895 demux->audio_need_discont = TRUE;
1896 demux->video_need_discont = TRUE;
1898 demux->flushing = FALSE;
1900 /* Only in push mode and if we're not during a seek */
1901 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1902 /* After a flush we expect a tag_type */
1903 demux->state = FLV_STATE_TAG_TYPE;
1904 /* We reset the offset and will get one from first push */
1910 gst_flv_demux_cleanup (GstFlvDemux * demux)
1912 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1914 demux->state = FLV_STATE_HEADER;
1916 demux->have_group_id = FALSE;
1917 demux->group_id = G_MAXUINT;
1919 demux->flushing = FALSE;
1920 demux->need_header = TRUE;
1921 demux->audio_need_segment = TRUE;
1922 demux->video_need_segment = TRUE;
1923 demux->audio_need_discont = TRUE;
1924 demux->video_need_discont = TRUE;
1926 demux->has_audio = FALSE;
1927 demux->has_video = FALSE;
1928 demux->push_tags = FALSE;
1929 demux->got_par = FALSE;
1931 demux->indexed = FALSE;
1932 demux->upstream_seekable = FALSE;
1933 demux->file_size = 0;
1935 demux->index_max_pos = 0;
1936 demux->index_max_time = 0;
1938 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1939 demux->last_audio_pts = demux->last_video_dts = 0;
1940 demux->audio_time_offset = demux->video_time_offset = 0;
1942 demux->no_more_pads = FALSE;
1944 #ifndef GST_DISABLE_DEBUG
1945 demux->no_audio_warned = FALSE;
1946 demux->no_video_warned = FALSE;
1949 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1951 demux->w = demux->h = 0;
1952 demux->framerate = 0.0;
1953 demux->par_x = demux->par_y = 1;
1954 demux->video_offset = 0;
1955 demux->audio_offset = 0;
1956 demux->offset = demux->cur_tag_offset = 0;
1957 demux->tag_size = demux->tag_data_size = 0;
1958 demux->duration = GST_CLOCK_TIME_NONE;
1960 if (demux->new_seg_event) {
1961 gst_event_unref (demux->new_seg_event);
1962 demux->new_seg_event = NULL;
1965 gst_adapter_clear (demux->adapter);
1967 if (demux->audio_codec_data) {
1968 gst_buffer_unref (demux->audio_codec_data);
1969 demux->audio_codec_data = NULL;
1972 if (demux->video_codec_data) {
1973 gst_buffer_unref (demux->video_codec_data);
1974 demux->video_codec_data = NULL;
1977 if (demux->audio_pad) {
1978 gst_flow_combiner_remove_pad (demux->flowcombiner, demux->audio_pad);
1979 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1980 gst_object_unref (demux->audio_pad);
1981 demux->audio_pad = NULL;
1984 if (demux->video_pad) {
1985 gst_flow_combiner_remove_pad (demux->flowcombiner, demux->video_pad);
1986 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1987 gst_object_unref (demux->video_pad);
1988 demux->video_pad = NULL;
1992 g_array_free (demux->times, TRUE);
1993 demux->times = NULL;
1996 if (demux->filepositions) {
1997 g_array_free (demux->filepositions, TRUE);
1998 demux->filepositions = NULL;
2003 * Create and push a flushing seek event upstream
2006 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
2011 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
2014 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
2015 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
2016 GST_SEEK_TYPE_NONE, -1);
2018 res = gst_pad_push_event (demux->sinkpad, event);
2021 demux->offset = offset;
2025 static GstFlowReturn
2026 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
2028 GstFlowReturn ret = GST_FLOW_OK;
2029 GstFlvDemux *demux = NULL;
2031 demux = GST_FLV_DEMUX (parent);
2033 GST_LOG_OBJECT (demux,
2034 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
2035 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
2036 GST_BUFFER_OFFSET (buffer));
2038 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
2039 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
2040 demux->state = FLV_STATE_HEADER;
2044 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
2045 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
2046 demux->offset = GST_BUFFER_OFFSET (buffer);
2049 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
2050 GST_DEBUG_OBJECT (demux, "Discontinuity");
2051 gst_adapter_clear (demux->adapter);
2054 gst_adapter_push (demux->adapter, buffer);
2056 if (demux->seeking) {
2057 demux->state = FLV_STATE_SEEK;
2058 GST_OBJECT_LOCK (demux);
2059 demux->seeking = FALSE;
2060 GST_OBJECT_UNLOCK (demux);
2064 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2065 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
2069 if (G_UNLIKELY (demux->flushing)) {
2070 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
2071 ret = GST_FLOW_FLUSHING;
2075 switch (demux->state) {
2076 case FLV_STATE_HEADER:
2078 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
2081 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
2083 ret = gst_flv_demux_parse_header (demux, buffer);
2085 gst_buffer_unref (buffer);
2086 demux->offset += FLV_HEADER_SIZE;
2088 demux->state = FLV_STATE_TAG_TYPE;
2094 case FLV_STATE_TAG_TYPE:
2096 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
2099 /* Remember the tag offset in bytes */
2100 demux->cur_tag_offset = demux->offset;
2102 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
2104 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2106 gst_buffer_unref (buffer);
2107 demux->offset += FLV_TAG_TYPE_SIZE;
2109 /* last tag is not an index => no index/don't know where the index is
2110 * seek back to the beginning */
2111 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
2119 case FLV_STATE_TAG_VIDEO:
2121 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2124 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2126 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2128 gst_buffer_unref (buffer);
2129 demux->offset += demux->tag_size;
2131 demux->state = FLV_STATE_TAG_TYPE;
2137 case FLV_STATE_TAG_AUDIO:
2139 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2142 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2144 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2146 gst_buffer_unref (buffer);
2147 demux->offset += demux->tag_size;
2149 demux->state = FLV_STATE_TAG_TYPE;
2155 case FLV_STATE_TAG_SCRIPT:
2157 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2160 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2162 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2164 gst_buffer_unref (buffer);
2165 demux->offset += demux->tag_size;
2167 demux->state = FLV_STATE_TAG_TYPE;
2169 /* if there's a seek event we're here for the index so if we don't have it
2170 * we seek back to the beginning */
2171 if (demux->seek_event) {
2173 demux->state = FLV_STATE_SEEK;
2183 case FLV_STATE_SEEK:
2189 if (!demux->indexed) {
2190 if (demux->offset == demux->file_size - sizeof (guint32)) {
2191 guint64 seek_offset;
2194 data = gst_adapter_take (demux->adapter, 4);
2198 seek_offset = demux->file_size - sizeof (guint32) -
2199 GST_READ_UINT32_BE (data);
2202 GST_INFO_OBJECT (demux,
2203 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
2205 demux->state = FLV_STATE_TAG_TYPE;
2206 flv_demux_seek_to_offset (demux, seek_offset);
2212 GST_OBJECT_LOCK (demux);
2213 event = demux->seek_event;
2214 demux->seek_event = NULL;
2215 GST_OBJECT_UNLOCK (demux);
2217 /* calculate and perform seek */
2218 if (!flv_demux_handle_seek_push (demux, event))
2221 gst_event_unref (event);
2222 demux->state = FLV_STATE_TAG_TYPE;
2225 case FLV_STATE_SKIP:
2226 /* Skip unknown tags (set in _parse_tag_type()) */
2227 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2228 gst_adapter_flush (demux->adapter, demux->tag_size);
2229 demux->offset += demux->tag_size;
2230 demux->state = FLV_STATE_TAG_TYPE;
2236 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
2245 GST_OBJECT_LOCK (demux);
2246 demux->seeking = FALSE;
2247 gst_event_unref (demux->seek_event);
2248 demux->seek_event = NULL;
2249 GST_OBJECT_UNLOCK (demux);
2250 GST_WARNING_OBJECT (demux,
2251 "failed to find an index, seeking back to beginning");
2252 flv_demux_seek_to_offset (demux, 0);
2257 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2258 return GST_FLOW_ERROR;
2263 static GstFlowReturn
2264 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2265 guint size, GstBuffer ** buffer)
2269 ret = gst_pad_pull_range (pad, offset, size, buffer);
2270 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2271 GST_WARNING_OBJECT (demux,
2272 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2273 size, offset, gst_flow_get_name (ret));
2278 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2279 GST_WARNING_OBJECT (demux,
2280 "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
2281 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
2282 gst_buffer_unref (*buffer);
2291 static GstFlowReturn
2292 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2294 GstBuffer *buffer = NULL;
2295 GstFlowReturn ret = GST_FLOW_OK;
2297 /* Store tag offset */
2298 demux->cur_tag_offset = demux->offset;
2300 /* Get the first 4 bytes to identify tag type and size */
2301 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2302 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2305 /* Identify tag type */
2306 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2308 gst_buffer_unref (buffer);
2310 if (G_UNLIKELY (ret != GST_FLOW_OK))
2313 /* Jump over tag type + size */
2314 demux->offset += FLV_TAG_TYPE_SIZE;
2316 /* Pull the whole tag */
2318 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2319 demux->tag_size, &buffer)) != GST_FLOW_OK))
2322 switch (demux->state) {
2323 case FLV_STATE_TAG_VIDEO:
2324 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2326 case FLV_STATE_TAG_AUDIO:
2327 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2329 case FLV_STATE_TAG_SCRIPT:
2330 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2333 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2336 gst_buffer_unref (buffer);
2338 /* Jump over that part we've just parsed */
2339 demux->offset += demux->tag_size;
2341 /* Make sure we reinitialize the tag size */
2342 demux->tag_size = 0;
2344 /* Ready for the next tag */
2345 demux->state = FLV_STATE_TAG_TYPE;
2347 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2348 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2349 "neither video nor audio are linked");
2356 static GstFlowReturn
2357 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2359 GstBuffer *buffer = NULL;
2360 GstFlowReturn ret = GST_FLOW_OK;
2362 /* Get the first 9 bytes */
2363 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2364 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2367 ret = gst_flv_demux_parse_header (demux, buffer);
2369 gst_buffer_unref (buffer);
2371 /* Jump over the header now */
2372 demux->offset += FLV_HEADER_SIZE;
2373 demux->state = FLV_STATE_TAG_TYPE;
2380 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2383 demux->offset = offset;
2385 /* Tell all the stream we moved to a different position (discont) */
2386 demux->audio_need_discont = TRUE;
2387 demux->video_need_discont = TRUE;
2389 /* next section setup */
2390 demux->from_offset = -1;
2391 demux->audio_done = demux->video_done = FALSE;
2392 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2395 demux->from_offset = -1;
2396 demux->to_offset = G_MAXINT64;
2399 /* If we seeked at the beginning of the file parse the header again */
2400 if (G_UNLIKELY (!demux->offset)) {
2401 demux->state = FLV_STATE_HEADER;
2402 } else { /* or parse a tag */
2403 demux->state = FLV_STATE_TAG_TYPE;
2407 static GstFlowReturn
2408 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2410 GstFlowReturn ret = GST_FLOW_EOS;
2412 GstIndexEntry *entry = NULL;
2414 GST_DEBUG_OBJECT (demux,
2415 "terminated section started at offset %" G_GINT64_FORMAT,
2416 demux->from_offset);
2418 /* we are done if we got all audio and video */
2419 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2420 demux->audio_first_ts < demux->segment.start) &&
2421 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2422 demux->video_first_ts < demux->segment.start))
2425 if (demux->from_offset <= 0)
2428 GST_DEBUG_OBJECT (demux, "locating previous position");
2430 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2432 /* locate index entry before previous start position */
2434 entry = gst_index_get_assoc_entry (index, demux->index_id,
2435 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2436 GST_FORMAT_BYTES, demux->from_offset - 1);
2439 gint64 bytes = 0, time = 0;
2441 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2442 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2444 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2445 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2446 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2448 /* setup for next section */
2449 demux->to_offset = demux->from_offset;
2450 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2454 gst_object_unref (index);
2461 static GstFlowReturn
2462 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2468 GstClockTime tag_time;
2469 GstFlowReturn ret = GST_FLOW_OK;
2471 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2474 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2475 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2477 old_offset = demux->offset;
2478 demux->offset = pos;
2481 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2482 12, &buffer)) == GST_FLOW_OK) {
2484 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2486 gst_buffer_unref (buffer);
2489 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2492 demux->offset += tag_size;
2495 if (ret == GST_FLOW_EOS) {
2496 /* file ran out, so mark we have complete index */
2497 demux->indexed = TRUE;
2502 demux->offset = old_offset;
2508 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2510 gint64 ret = 0, offset;
2511 size_t tag_size, size;
2512 GstBuffer *buffer = NULL;
2515 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2519 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2520 if (G_UNLIKELY (offset < 4))
2524 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2528 gst_buffer_map (buffer, &map, GST_MAP_READ);
2529 tag_size = GST_READ_UINT32_BE (map.data);
2530 gst_buffer_unmap (buffer, &map);
2531 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2532 gst_buffer_unref (buffer);
2536 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2540 /* a consistency check */
2541 gst_buffer_map (buffer, &map, GST_MAP_READ);
2542 size = GST_READ_UINT24_BE (map.data + 1);
2543 if (size != tag_size - 11) {
2544 gst_buffer_unmap (buffer, &map);
2545 GST_DEBUG_OBJECT (demux,
2546 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2547 ", corrupt or truncated file", size, tag_size - 11);
2551 /* try to update duration with timestamp in any case */
2552 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2554 /* maybe get some more metadata */
2555 if (map.data[0] == 18) {
2556 gst_buffer_unmap (buffer, &map);
2557 gst_buffer_unref (buffer);
2559 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2561 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2563 gst_flv_demux_parse_tag_script (demux, buffer);
2565 gst_buffer_unmap (buffer, &map);
2570 gst_buffer_unref (buffer);
2576 gst_flv_demux_loop (GstPad * pad)
2578 GstFlvDemux *demux = NULL;
2579 GstFlowReturn ret = GST_FLOW_OK;
2581 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2584 switch (demux->state) {
2585 case FLV_STATE_TAG_TYPE:
2586 if (demux->from_offset == -1)
2587 demux->from_offset = demux->offset;
2588 ret = gst_flv_demux_pull_tag (pad, demux);
2589 /* if we have seen real data, we probably passed a possible metadata
2590 * header located at start. So if we do not yet have an index,
2591 * try to pick up metadata (index, duration) at the end */
2592 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2593 (demux->has_video || demux->has_audio)))
2594 demux->file_size = gst_flv_demux_get_metadata (demux);
2596 case FLV_STATE_DONE:
2599 case FLV_STATE_SEEK:
2600 /* seek issued with insufficient index;
2601 * scan for index in task thread from current maximum offset to
2602 * desired time and then perform seek */
2603 /* TODO maybe some buffering message or so to indicate scan progress */
2604 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2606 if (ret != GST_FLOW_OK)
2608 /* position and state arranged by seek,
2609 * also unrefs event */
2610 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2611 demux->seek_event = NULL;
2614 ret = gst_flv_demux_pull_header (pad, demux);
2615 /* index scans start after header */
2616 demux->index_max_pos = demux->offset;
2620 if (demux->segment.rate < 0.0) {
2621 /* check end of section */
2622 if ((gint64) demux->offset >= demux->to_offset ||
2623 demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2624 (demux->audio_done && demux->video_done))
2625 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2627 /* check EOS condition */
2628 if ((demux->segment.stop != -1) &&
2629 (demux->segment.position >= demux->segment.stop)) {
2634 /* pause if something went wrong or at end */
2635 if (G_UNLIKELY (ret != GST_FLOW_OK))
2638 gst_object_unref (demux);
2644 const gchar *reason = gst_flow_get_name (ret);
2646 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2647 gst_pad_pause_task (pad);
2649 if (ret == GST_FLOW_EOS) {
2650 /* handle end-of-stream/segment */
2651 /* so align our position with the end of it, if there is one
2652 * this ensures a subsequent will arrive at correct base/acc time */
2653 if (demux->segment.rate > 0.0 &&
2654 GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2655 demux->segment.position = demux->segment.stop;
2656 else if (demux->segment.rate < 0.0)
2657 demux->segment.position = demux->segment.start;
2659 /* perform EOS logic */
2660 if (!demux->no_more_pads) {
2661 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2662 demux->no_more_pads = TRUE;
2665 if (demux->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
2668 /* for segment playback we need to post when (in stream time)
2669 * we stopped, this is either stop (when set) or the duration. */
2670 if ((stop = demux->segment.stop) == -1)
2671 stop = demux->segment.duration;
2673 if (demux->segment.rate >= 0) {
2674 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2675 gst_element_post_message (GST_ELEMENT_CAST (demux),
2676 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2677 GST_FORMAT_TIME, stop));
2678 gst_flv_demux_push_src_event (demux,
2679 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2680 } else { /* Reverse playback */
2681 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2683 gst_element_post_message (GST_ELEMENT_CAST (demux),
2684 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2685 GST_FORMAT_TIME, demux->segment.start));
2686 gst_flv_demux_push_src_event (demux,
2687 gst_event_new_segment_done (GST_FORMAT_TIME,
2688 demux->segment.start));
2691 /* normal playback, send EOS to all linked pads */
2692 if (!demux->no_more_pads) {
2693 gst_element_no_more_pads (GST_ELEMENT (demux));
2694 demux->no_more_pads = TRUE;
2697 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2698 if (!demux->audio_pad && !demux->video_pad)
2699 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2700 ("Internal data stream error."), ("Got EOS before any data"));
2701 else if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2702 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2704 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2705 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2706 ("Internal data stream error."),
2707 ("stream stopped, reason %s", reason));
2708 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2710 gst_object_unref (demux);
2716 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment,
2717 GstSeekFlags seek_flags)
2722 GstIndexEntry *entry;
2724 g_return_val_if_fail (segment != NULL, 0);
2726 time = segment->position;
2728 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2731 /* Let's check if we have an index entry for that seek time */
2732 entry = gst_index_get_assoc_entry (index, demux->index_id,
2733 seek_flags & GST_SEEK_FLAG_SNAP_AFTER ?
2734 GST_INDEX_LOOKUP_AFTER : GST_INDEX_LOOKUP_BEFORE,
2735 GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, time);
2738 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2739 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2741 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2742 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2743 GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2745 /* Key frame seeking */
2746 if (seek_flags & GST_SEEK_FLAG_KEY_UNIT) {
2747 /* Adjust the segment so that the keyframe fits in */
2748 segment->start = segment->time = time;
2749 segment->position = time;
2752 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2753 GST_TIME_ARGS (segment->start));
2756 gst_object_unref (index);
2763 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2767 GstSeekType start_type, stop_type;
2770 gboolean update, flush, ret;
2771 GstSegment seeksegment;
2773 gst_event_parse_seek (event, &rate, &format, &flags,
2774 &start_type, &start, &stop_type, &stop);
2776 if (format != GST_FORMAT_TIME)
2779 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2781 /* Work on a copy until we are sure the seek succeeded. */
2782 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2784 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2787 /* Apply the seek to our segment */
2788 gst_segment_do_seek (&seeksegment, rate, format, flags,
2789 start_type, start, stop_type, stop, &update);
2791 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2794 if (flush || seeksegment.position != demux->segment.position) {
2795 /* Do the actual seeking */
2796 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment, flags);
2798 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2799 G_GUINT64_FORMAT, offset);
2800 ret = gst_pad_push_event (demux->sinkpad,
2801 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2802 flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2803 offset, GST_SEEK_TYPE_NONE, 0));
2804 if (G_UNLIKELY (!ret)) {
2805 GST_WARNING_OBJECT (demux, "upstream seek failed");
2808 gst_flow_combiner_reset (demux->flowcombiner);
2809 /* Tell all the stream we moved to a different position (discont) */
2810 demux->audio_need_discont = TRUE;
2811 demux->video_need_discont = TRUE;
2817 /* Ok seek succeeded, take the newly configured segment */
2818 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2820 /* Tell all the stream a new segment is needed */
2821 demux->audio_need_segment = TRUE;
2822 demux->video_need_segment = TRUE;
2823 /* Clean any potential newsegment event kept for the streams. The first
2824 * stream needing a new segment will create a new one. */
2825 if (G_UNLIKELY (demux->new_seg_event)) {
2826 gst_event_unref (demux->new_seg_event);
2827 demux->new_seg_event = NULL;
2829 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2830 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2831 GST_TIME_ARGS (demux->segment.start),
2832 GST_TIME_ARGS (demux->segment.stop));
2833 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2834 gst_event_unref (event);
2836 ret = gst_pad_push_event (demux->sinkpad, event);
2844 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2845 gst_event_unref (event);
2851 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2855 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2857 if (format != GST_FORMAT_TIME) {
2858 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2859 gst_event_unref (event);
2863 /* First try upstream */
2864 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2865 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2866 gst_event_unref (event);
2870 if (!demux->indexed) {
2871 guint64 seek_offset = 0;
2872 gboolean building_index;
2874 GST_OBJECT_LOCK (demux);
2875 /* handle the seek in the chain function */
2876 demux->seeking = TRUE;
2877 demux->state = FLV_STATE_SEEK;
2879 /* copy the event */
2880 if (demux->seek_event)
2881 gst_event_unref (demux->seek_event);
2882 demux->seek_event = gst_event_ref (event);
2884 /* set the building_index flag so that only one thread can setup the
2885 * structures for index seeking. */
2886 building_index = demux->building_index;
2887 if (!building_index) {
2888 demux->building_index = TRUE;
2889 if (!demux->file_size
2890 && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2891 &demux->file_size)) {
2892 GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2893 GST_OBJECT_UNLOCK (demux);
2897 /* we hope the last tag is a scriptdataobject containing an index
2898 * the size of the last tag is given in the last guint32 bits
2899 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2900 seek_offset = demux->file_size - sizeof (guint32);
2901 GST_DEBUG_OBJECT (demux,
2902 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2904 GST_OBJECT_UNLOCK (demux);
2906 if (!building_index) {
2907 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2909 return flv_demux_seek_to_offset (demux, seek_offset);
2912 /* FIXME: we have to always return true so that we don't block the seek
2914 * Note: maybe it is OK to return true if we're still building the index */
2918 return flv_demux_handle_seek_push (demux, event);
2922 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2927 GstSeekType start_type, stop_type;
2930 gboolean update, flush, ret = FALSE;
2931 GstSegment seeksegment;
2933 gst_event_parse_seek (event, &rate, &format, &flags,
2934 &start_type, &start, &stop_type, &stop);
2936 if (format != GST_FORMAT_TIME)
2939 /* mark seeking thread entering flushing/pausing */
2940 GST_OBJECT_LOCK (demux);
2942 demux->seeking = seeking;
2943 GST_OBJECT_UNLOCK (demux);
2945 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2948 /* Flush start up and downstream to make sure data flow and loops are
2950 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2951 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2953 /* Pause the pulling task */
2954 gst_pad_pause_task (demux->sinkpad);
2957 /* Take the stream lock */
2958 GST_PAD_STREAM_LOCK (demux->sinkpad);
2961 /* Stop flushing upstream we need to pull */
2962 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2965 /* Work on a copy until we are sure the seek succeeded. */
2966 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2968 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2971 /* Apply the seek to our segment */
2972 gst_segment_do_seek (&seeksegment, rate, format, flags,
2973 start_type, start, stop_type, stop, &update);
2975 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2978 if (flush || seeksegment.position != demux->segment.position) {
2979 /* Do the actual seeking */
2980 /* index is reliable if it is complete or we do not go to far ahead */
2981 if (seeking && !demux->indexed &&
2982 seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2983 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2984 " index only up to %" GST_TIME_FORMAT,
2985 GST_TIME_ARGS (demux->index_max_time));
2986 /* stop flushing for now */
2988 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2989 /* delegate scanning and index building to task thread to avoid
2990 * occupying main (UI) loop */
2991 if (demux->seek_event)
2992 gst_event_unref (demux->seek_event);
2993 demux->seek_event = gst_event_ref (event);
2994 demux->seek_time = seeksegment.position;
2995 demux->state = FLV_STATE_SEEK;
2996 /* do not know about succes yet, but we did care and handled it */
3001 /* now index should be as reliable as it can be for current purpose */
3002 gst_flv_demux_move_to_offset (demux,
3003 gst_flv_demux_find_offset (demux, &seeksegment, flags), TRUE);
3010 /* Stop flushing, the sinks are at time 0 now */
3011 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
3015 /* Ok seek succeeded, take the newly configured segment */
3016 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
3018 /* Notify about the start of a new segment */
3019 if (demux->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
3020 gst_element_post_message (GST_ELEMENT (demux),
3021 gst_message_new_segment_start (GST_OBJECT (demux),
3022 demux->segment.format, demux->segment.position));
3025 gst_flow_combiner_reset (demux->flowcombiner);
3026 /* Tell all the stream a new segment is needed */
3027 demux->audio_need_segment = TRUE;
3028 demux->video_need_segment = TRUE;
3029 /* Clean any potential newsegment event kept for the streams. The first
3030 * stream needing a new segment will create a new one. */
3031 if (G_UNLIKELY (demux->new_seg_event)) {
3032 gst_event_unref (demux->new_seg_event);
3033 demux->new_seg_event = NULL;
3035 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
3036 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
3037 GST_TIME_ARGS (demux->segment.start),
3038 GST_TIME_ARGS (demux->segment.stop));
3039 demux->new_seg_event = gst_event_new_segment (&demux->segment);
3043 GST_OBJECT_LOCK (demux);
3044 seeking = demux->seeking && !seeking;
3045 demux->seeking = FALSE;
3046 GST_OBJECT_UNLOCK (demux);
3048 /* if we detect an external seek having started (and possibly already having
3049 * flushed), do not restart task to give it a chance.
3050 * Otherwise external one's flushing will take care to pause task */
3052 gst_pad_pause_task (demux->sinkpad);
3054 gst_pad_start_task (demux->sinkpad,
3055 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad, NULL);
3058 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
3060 gst_event_unref (event);
3066 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
3067 gst_event_unref (event);
3072 /* If we can pull that's prefered */
3074 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
3079 query = gst_query_new_scheduling ();
3081 if (!gst_pad_peer_query (sinkpad, query)) {
3082 gst_query_unref (query);
3086 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
3087 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
3088 gst_query_unref (query);
3093 GST_DEBUG_OBJECT (sinkpad, "activating pull");
3094 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
3098 GST_DEBUG_OBJECT (sinkpad, "activating push");
3099 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
3104 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
3105 GstPadMode mode, gboolean active)
3110 demux = GST_FLV_DEMUX (parent);
3113 case GST_PAD_MODE_PUSH:
3114 demux->random_access = FALSE;
3117 case GST_PAD_MODE_PULL:
3119 demux->random_access = TRUE;
3120 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
3123 demux->random_access = FALSE;
3124 res = gst_pad_stop_task (sinkpad);
3135 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
3138 gboolean ret = FALSE;
3140 demux = GST_FLV_DEMUX (parent);
3142 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3144 switch (GST_EVENT_TYPE (event)) {
3145 case GST_EVENT_FLUSH_START:
3146 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
3147 demux->flushing = TRUE;
3148 ret = gst_flv_demux_push_src_event (demux, event);
3150 case GST_EVENT_FLUSH_STOP:
3151 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
3152 gst_flv_demux_flush (demux, TRUE);
3153 ret = gst_flv_demux_push_src_event (demux, event);
3159 GST_DEBUG_OBJECT (demux, "received EOS");
3161 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
3164 GST_DEBUG_OBJECT (demux, "committing index");
3165 gst_index_commit (index, demux->index_id);
3166 gst_object_unref (index);
3169 if (!demux->audio_pad && !demux->video_pad) {
3170 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
3171 ("Internal data stream error."), ("Got EOS before any data"));
3172 gst_event_unref (event);
3174 if (!demux->no_more_pads) {
3175 gst_element_no_more_pads (GST_ELEMENT (demux));
3176 demux->no_more_pads = TRUE;
3179 if (!gst_flv_demux_push_src_event (demux, event))
3180 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
3185 case GST_EVENT_SEGMENT:
3187 GstSegment in_segment;
3189 GST_DEBUG_OBJECT (demux, "received new segment");
3191 gst_event_copy_segment (event, &in_segment);
3193 if (in_segment.format == GST_FORMAT_TIME) {
3194 /* time segment, this is perfect, copy over the values. */
3195 memcpy (&demux->segment, &in_segment, sizeof (in_segment));
3197 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
3201 ret = gst_flv_demux_push_src_event (demux, event);
3203 /* non-time format */
3204 demux->audio_need_segment = TRUE;
3205 demux->video_need_segment = TRUE;
3207 gst_event_unref (event);
3208 if (demux->new_seg_event) {
3209 gst_event_unref (demux->new_seg_event);
3210 demux->new_seg_event = NULL;
3213 gst_flow_combiner_reset (demux->flowcombiner);
3217 ret = gst_pad_event_default (pad, parent, event);
3225 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
3228 gboolean ret = FALSE;
3230 demux = GST_FLV_DEMUX (parent);
3232 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3234 switch (GST_EVENT_TYPE (event)) {
3235 case GST_EVENT_SEEK:
3236 /* Try to push upstream first */
3237 gst_event_ref (event);
3238 ret = gst_pad_push_event (demux->sinkpad, event);
3240 gst_event_unref (event);
3243 if (demux->random_access) {
3244 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
3246 ret = gst_flv_demux_handle_seek_push (demux, event);
3250 ret = gst_pad_push_event (demux->sinkpad, event);
3258 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
3260 gboolean res = TRUE;
3263 demux = GST_FLV_DEMUX (parent);
3265 switch (GST_QUERY_TYPE (query)) {
3266 case GST_QUERY_DURATION:
3270 gst_query_parse_duration (query, &format, NULL);
3272 /* duration is time only */
3273 if (format != GST_FORMAT_TIME) {
3274 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
3280 /* Try to push upstream first */
3281 res = gst_pad_peer_query (demux->sinkpad, query);
3285 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3286 GST_TIME_ARGS (demux->duration));
3288 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3292 case GST_QUERY_POSITION:
3296 gst_query_parse_position (query, &format, NULL);
3298 /* position is time only */
3299 if (format != GST_FORMAT_TIME) {
3300 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3306 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3307 GST_TIME_ARGS (demux->segment.position));
3309 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3314 case GST_QUERY_SEEKING:{
3317 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3319 /* First ask upstream */
3320 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3323 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3330 /* FIXME, check index this way is not thread safe */
3331 if (fmt != GST_FORMAT_TIME || !demux->index) {
3332 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3333 } else if (demux->random_access) {
3334 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3337 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3338 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3341 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3342 gst_query_unref (peerquery);
3345 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3348 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3352 case GST_QUERY_SEGMENT:
3357 format = demux->segment.format;
3360 gst_segment_to_stream_time (&demux->segment, format,
3361 demux->segment.start);
3362 if ((stop = demux->segment.stop) == -1)
3363 stop = demux->segment.duration;
3365 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
3367 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
3371 case GST_QUERY_LATENCY:
3373 res = gst_pad_query_default (pad, parent, query);
3382 static GstStateChangeReturn
3383 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3386 GstStateChangeReturn ret;
3388 demux = GST_FLV_DEMUX (element);
3390 switch (transition) {
3391 case GST_STATE_CHANGE_READY_TO_PAUSED:
3392 /* If this is our own index destroy it as the
3393 * old entries might be wrong for the new stream */
3394 if (demux->own_index) {
3395 gst_object_unref (demux->index);
3396 demux->index = NULL;
3397 demux->own_index = FALSE;
3400 /* If no index was created, generate one */
3401 if (G_UNLIKELY (!demux->index)) {
3402 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3404 demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3406 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3408 demux->own_index = TRUE;
3410 gst_flv_demux_cleanup (demux);
3416 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3417 if (ret == GST_STATE_CHANGE_FAILURE)
3420 switch (transition) {
3421 case GST_STATE_CHANGE_PAUSED_TO_READY:
3422 gst_flv_demux_cleanup (demux);
3433 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3435 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3436 GstIndex *old_index;
3438 GST_OBJECT_LOCK (demux);
3440 old_index = demux->index;
3443 demux->index = gst_object_ref (index);
3444 demux->own_index = FALSE;
3446 demux->index = NULL;
3449 gst_object_unref (demux->index);
3451 gst_object_ref (index);
3453 GST_OBJECT_UNLOCK (demux);
3455 /* object lock might be taken again */
3457 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3459 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3461 gst_object_unref (index);
3466 gst_flv_demux_get_index (GstElement * element)
3468 GstIndex *result = NULL;
3470 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3472 GST_OBJECT_LOCK (demux);
3474 result = gst_object_ref (demux->index);
3475 GST_OBJECT_UNLOCK (demux);
3481 gst_flv_demux_dispose (GObject * object)
3483 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3485 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3487 if (demux->adapter) {
3488 gst_adapter_clear (demux->adapter);
3489 g_object_unref (demux->adapter);
3490 demux->adapter = NULL;
3493 if (demux->taglist) {
3494 gst_tag_list_unref (demux->taglist);
3495 demux->taglist = NULL;
3498 if (demux->flowcombiner) {
3499 gst_flow_combiner_free (demux->flowcombiner);
3500 demux->flowcombiner = NULL;
3503 if (demux->new_seg_event) {
3504 gst_event_unref (demux->new_seg_event);
3505 demux->new_seg_event = NULL;
3508 if (demux->audio_codec_data) {
3509 gst_buffer_unref (demux->audio_codec_data);
3510 demux->audio_codec_data = NULL;
3513 if (demux->video_codec_data) {
3514 gst_buffer_unref (demux->video_codec_data);
3515 demux->video_codec_data = NULL;
3518 if (demux->audio_pad) {
3519 gst_object_unref (demux->audio_pad);
3520 demux->audio_pad = NULL;
3523 if (demux->video_pad) {
3524 gst_object_unref (demux->video_pad);
3525 demux->video_pad = NULL;
3529 gst_object_unref (demux->index);
3530 demux->index = NULL;
3534 g_array_free (demux->times, TRUE);
3535 demux->times = NULL;
3538 if (demux->filepositions) {
3539 g_array_free (demux->filepositions, TRUE);
3540 demux->filepositions = NULL;
3543 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3547 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3549 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3550 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3552 gobject_class->dispose = gst_flv_demux_dispose;
3554 gstelement_class->change_state =
3555 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3558 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3559 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3562 gst_element_class_add_static_pad_template (gstelement_class,
3563 &flv_sink_template);
3564 gst_element_class_add_static_pad_template (gstelement_class,
3565 &audio_src_template);
3566 gst_element_class_add_static_pad_template (gstelement_class,
3567 &video_src_template);
3568 gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
3569 "Codec/Demuxer", "Demux FLV feeds into digital streams",
3570 "Julien Moutte <julien@moutte.net>");
3574 gst_flv_demux_init (GstFlvDemux * demux)
3577 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3579 gst_pad_set_event_function (demux->sinkpad,
3580 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3581 gst_pad_set_chain_function (demux->sinkpad,
3582 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3583 gst_pad_set_activate_function (demux->sinkpad,
3584 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3585 gst_pad_set_activatemode_function (demux->sinkpad,
3586 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3588 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3590 demux->adapter = gst_adapter_new ();
3591 demux->taglist = gst_tag_list_new_empty ();
3592 demux->flowcombiner = gst_flow_combiner_new ();
3593 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3595 demux->own_index = FALSE;
3597 GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3599 gst_flv_demux_cleanup (demux);
3603 plugin_init (GstPlugin * plugin)
3605 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3607 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3608 gst_flv_demux_get_type ()) ||
3609 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3610 gst_flv_mux_get_type ()))
3616 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3617 flv, "FLV muxing and demuxing plugin",
3618 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)