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);
117 static void gst_flv_demux_push_tags (GstFlvDemux * demux);
120 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
121 guint64 pos, gboolean keyframe)
123 GstIndexAssociation associations[2];
125 GstIndexEntry *entry;
127 GST_LOG_OBJECT (demux,
128 "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
129 keyframe, GST_TIME_ARGS (ts), pos);
131 /* if upstream is not seekable there is no point in building an index */
132 if (!demux->upstream_seekable)
135 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
140 /* entry may already have been added before, avoid adding indefinitely */
141 entry = gst_index_get_assoc_entry (index, demux->index_id,
142 GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
145 #ifndef GST_DISABLE_GST_DEBUG
149 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
150 key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
151 GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
152 ", keyframe %d", GST_TIME_ARGS (time), key);
153 /* there is not really a way to delete the existing one */
154 if (time != ts || key != ! !keyframe)
155 GST_DEBUG_OBJECT (demux, "metadata mismatch");
157 gst_object_unref (index);
161 associations[0].format = GST_FORMAT_TIME;
162 associations[0].value = ts;
163 associations[1].format = GST_FORMAT_BYTES;
164 associations[1].value = pos;
166 gst_index_add_associationv (index, demux->index_id,
167 (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
168 GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
169 (const GstIndexAssociation *) &associations);
171 if (pos > demux->index_max_pos)
172 demux->index_max_pos = pos;
173 if (ts > demux->index_max_time)
174 demux->index_max_time = ts;
176 gst_object_unref (index);
180 FLV_GET_STRING (GstByteReader * reader)
182 guint16 string_size = 0;
183 gchar *string = NULL;
184 const guint8 *str = NULL;
186 g_return_val_if_fail (reader != NULL, NULL);
188 if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
191 if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
194 string = g_try_malloc0 (string_size + 1);
195 if (G_UNLIKELY (!string)) {
199 if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
204 memcpy (string, str, string_size);
205 if (!g_utf8_validate (string, string_size, NULL)) {
214 gst_flv_demux_check_seekability (GstFlvDemux * demux)
217 gint64 start = -1, stop = -1;
219 demux->upstream_seekable = FALSE;
221 query = gst_query_new_seeking (GST_FORMAT_BYTES);
222 if (!gst_pad_peer_query (demux->sinkpad, query)) {
223 GST_DEBUG_OBJECT (demux, "seeking query failed");
224 gst_query_unref (query);
228 gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
231 gst_query_unref (query);
233 /* try harder to query upstream size if we didn't get it the first time */
234 if (demux->upstream_seekable && stop == -1) {
235 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
236 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
239 /* if upstream doesn't know the size, it's likely that it's not seekable in
240 * practice even if it technically may be seekable */
241 if (demux->upstream_seekable && (start != 0 || stop <= start)) {
242 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
243 demux->upstream_seekable = FALSE;
246 GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
250 parse_flv_demux_parse_date_string (const gchar * s)
252 static const gchar months[12][4] = {
253 "Jan", "Feb", "Mar", "Apr",
254 "May", "Jun", "Jul", "Aug",
255 "Sep", "Oct", "Nov", "Dec"
257 GstDateTime *dt = NULL;
260 gchar *endptr, *stripped;
262 gint year = -1, month = -1, day = -1;
263 gint hour = -1, minute = -1, seconds = -1;
265 stripped = g_strstrip (g_strdup (s));
267 /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
268 tokens = g_strsplit (stripped, " ", -1);
272 if (g_strv_length (tokens) != 5)
276 d = g_ascii_strtoull (tokens[4], &endptr, 10);
277 if (d == 0 && *endptr != '\0')
283 if (strlen (tokens[1]) != 3)
285 for (i = 0; i < 12; i++) {
286 if (!strcmp (tokens[1], months[i])) {
296 d = g_ascii_strtoull (tokens[2], &endptr, 10);
297 if (d == 0 && *endptr != '\0')
304 if (sscanf (tokens[3], "%d:%d:%d", &hh, &mm, &ss) < 2)
306 if (hh >= 0 && hh < 24 && mm >= 0 && mm < 60 && ss >= 0 && ss < 60) {
318 dt = gst_date_time_new (0.0, year, month, day, hour, minute, seconds);
324 gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
325 gboolean * end_marker)
327 gchar *tag_name = NULL;
330 /* Initialize the end_marker flag to FALSE */
333 /* Name of the tag */
334 tag_name = FLV_GET_STRING (reader);
335 if (G_UNLIKELY (!tag_name)) {
336 GST_WARNING_OBJECT (demux, "failed reading tag name");
340 /* What kind of object is that */
341 if (!gst_byte_reader_get_uint8 (reader, &tag_type))
344 GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
348 { /* Use a union to read the uint64 and then as a double */
351 if (!gst_byte_reader_get_float64_be (reader, &d))
354 GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
356 if (!strcmp (tag_name, "duration")) {
357 demux->duration = d * GST_SECOND;
359 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
360 GST_TAG_DURATION, demux->duration, NULL);
361 } else if (!strcmp (tag_name, "AspectRatioX")) {
363 demux->got_par = TRUE;
364 } else if (!strcmp (tag_name, "AspectRatioY")) {
366 demux->got_par = TRUE;
367 } else if (!strcmp (tag_name, "width")) {
369 } else if (!strcmp (tag_name, "height")) {
371 } else if (!strcmp (tag_name, "framerate")) {
372 demux->framerate = d;
373 } else if (!strcmp (tag_name, "audiodatarate")) {
374 gst_tag_list_add (demux->audio_tags, GST_TAG_MERGE_REPLACE,
375 GST_TAG_NOMINAL_BITRATE, (guint) (d * 1024), NULL);
376 } else if (!strcmp (tag_name, "videodatarate")) {
377 gst_tag_list_add (demux->video_tags, GST_TAG_MERGE_REPLACE,
378 GST_TAG_NOMINAL_BITRATE, (guint) (d * 1024), NULL);
380 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
385 case 1: /* Boolean */
389 if (!gst_byte_reader_get_uint8 (reader, &b))
392 GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
394 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
402 s = FLV_GET_STRING (reader);
406 GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
408 if (!strcmp (tag_name, "creationdate")) {
411 dt = parse_flv_demux_parse_date_string (s);
413 GST_DEBUG_OBJECT (demux, "Failed to parse '%s' into datetime", s);
415 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
416 GST_TAG_DATE_TIME, dt, NULL);
417 gst_date_time_unref (dt);
419 } else if (!strcmp (tag_name, "creator")) {
420 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
421 GST_TAG_ARTIST, s, NULL);
422 } else if (!strcmp (tag_name, "title")) {
423 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
424 GST_TAG_TITLE, s, NULL);
425 } else if (!strcmp (tag_name, "metadatacreator")) {
426 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
427 GST_TAG_ENCODER, s, NULL);
429 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
438 gboolean end_of_object_marker = FALSE;
440 while (!end_of_object_marker) {
441 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
442 &end_of_object_marker);
444 if (G_UNLIKELY (!ok)) {
445 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
452 case 8: /* ECMA array */
454 guint32 nb_elems = 0;
455 gboolean end_of_object_marker = FALSE;
457 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
460 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
463 while (!end_of_object_marker) {
464 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
465 &end_of_object_marker);
467 if (G_UNLIKELY (!ok)) {
468 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
475 case 9: /* End marker */
477 GST_DEBUG_OBJECT (demux, "end marker ?");
478 if (tag_name[0] == '\0') {
480 GST_DEBUG_OBJECT (demux, "end marker detected");
489 guint32 nb_elems = 0;
491 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
494 GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
496 if (!strcmp (tag_name, "times")) {
498 g_array_free (demux->times, TRUE);
500 demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
501 } else if (!strcmp (tag_name, "filepositions")) {
502 if (demux->filepositions) {
503 g_array_free (demux->filepositions, TRUE);
505 demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
509 guint8 elem_type = 0;
511 if (!gst_byte_reader_get_uint8 (reader, &elem_type))
519 if (!gst_byte_reader_get_float64_be (reader, &d))
522 GST_DEBUG_OBJECT (demux, "element is a double %f", d);
524 if (!strcmp (tag_name, "times") && demux->times) {
525 g_array_append_val (demux->times, d);
526 } else if (!strcmp (tag_name, "filepositions") &&
527 demux->filepositions) {
528 g_array_append_val (demux->filepositions, d);
533 GST_WARNING_OBJECT (demux, "unsupported array element type %d",
545 if (!gst_byte_reader_get_float64_be (reader, &d))
548 if (!gst_byte_reader_get_int16_be (reader, &i))
551 GST_DEBUG_OBJECT (demux,
552 "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
554 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
559 GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
573 gst_flv_demux_clear_tags (GstFlvDemux * demux)
575 GST_DEBUG_OBJECT (demux, "clearing taglist");
577 if (demux->taglist) {
578 gst_tag_list_unref (demux->taglist);
580 demux->taglist = gst_tag_list_new_empty ();
581 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
583 if (demux->audio_tags) {
584 gst_tag_list_unref (demux->audio_tags);
586 demux->audio_tags = gst_tag_list_new_empty ();
588 if (demux->video_tags) {
589 gst_tag_list_unref (demux->video_tags);
591 demux->video_tags = gst_tag_list_new_empty ();
595 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
597 GstFlowReturn ret = GST_FLOW_OK;
598 GstByteReader reader;
602 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 7, GST_FLOW_ERROR);
604 gst_buffer_map (buffer, &map, GST_MAP_READ);
605 gst_byte_reader_init (&reader, map.data, map.size);
607 gst_byte_reader_skip_unchecked (&reader, 7);
609 GST_LOG_OBJECT (demux, "parsing a script tag");
611 if (!gst_byte_reader_get_uint8 (&reader, &type))
616 gchar *function_name;
619 function_name = FLV_GET_STRING (&reader);
621 GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
623 if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
624 gboolean end_marker = FALSE;
625 GST_DEBUG_OBJECT (demux, "we have a metadata script object");
627 gst_flv_demux_clear_tags (demux);
629 if (!gst_byte_reader_get_uint8 (&reader, &type)) {
630 g_free (function_name);
637 guint32 nb_elems = 0;
640 if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
641 g_free (function_name);
645 /* The number of elements is just a hint, some files have
646 nb_elements == 0 and actually contain items. */
647 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
650 /* fallthrough to read data */
654 while (!end_marker) {
656 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
658 if (G_UNLIKELY (!ok)) {
659 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
666 GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
667 g_free (function_name);
671 gst_flv_demux_push_tags (demux);
674 g_free (function_name);
676 if (demux->times && demux->filepositions) {
679 /* If an index was found, insert associations */
680 num = MIN (demux->times->len, demux->filepositions->len);
681 for (i = 0; i < num; i++) {
682 guint64 time, fileposition;
684 time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
685 fileposition = g_array_index (demux->filepositions, gdouble, i);
686 gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
689 demux->indexed = TRUE;
694 gst_buffer_unmap (buffer, &map);
700 have_group_id (GstFlvDemux * demux)
704 event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
706 if (gst_event_parse_group_id (event, &demux->group_id))
707 demux->have_group_id = TRUE;
709 demux->have_group_id = FALSE;
710 gst_event_unref (event);
711 } else if (!demux->have_group_id) {
712 demux->have_group_id = TRUE;
713 demux->group_id = gst_util_group_id_next ();
716 return demux->have_group_id;
720 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
721 guint32 rate, guint32 channels, guint32 width)
723 GstCaps *caps = NULL, *old_caps;
724 gboolean ret = FALSE;
725 guint adjusted_rate = rate;
726 guint adjusted_channels = channels;
732 caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
737 caps = gst_caps_new_simple ("audio/mpeg",
738 "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
739 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
744 GstAudioFormat format;
746 /* Assuming little endian for 0 (aka endianness of the
747 * system on which the file was created) as most people
748 * are probably using little endian machines */
749 format = gst_audio_format_build_integer ((width == 8) ? FALSE : TRUE,
750 G_LITTLE_ENDIAN, width, width);
752 caps = gst_caps_new_simple ("audio/x-raw",
753 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
754 "layout", G_TYPE_STRING, "interleaved", NULL);
760 caps = gst_caps_new_empty_simple ("audio/x-nellymoser");
765 if (!demux->audio_codec_data) {
766 GST_DEBUG_OBJECT (demux, "don't have AAC codec data yet");
771 gst_buffer_map (demux->audio_codec_data, &map, GST_MAP_READ);
773 /* use codec-data to extract and verify samplerate */
777 freq_index = GST_READ_UINT16_BE (map.data);
778 freq_index = (freq_index & 0x0780) >> 7;
780 gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
782 if (adjusted_rate && (rate != adjusted_rate)) {
783 GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
786 adjusted_rate = rate;
790 gst_codec_utils_aac_get_channels (map.data, map.size);
792 if (adjusted_channels && (channels != adjusted_channels)) {
793 GST_LOG_OBJECT (demux, "Ajusting AAC channels %d -> %d", channels,
796 adjusted_channels = channels;
799 gst_buffer_unmap (demux->audio_codec_data, &map);
801 caps = gst_caps_new_simple ("audio/mpeg",
802 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
803 "stream-format", G_TYPE_STRING, "raw", NULL);
807 caps = gst_caps_new_empty_simple ("audio/x-alaw");
810 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
814 GValue streamheader = G_VALUE_INIT;
815 GValue value = G_VALUE_INIT;
817 GstStructure *structure;
821 caps = gst_caps_new_empty_simple ("audio/x-speex");
822 structure = gst_caps_get_structure (caps, 0);
824 GST_DEBUG_OBJECT (demux, "generating speex header");
826 /* Speex decoder expects streamheader to be { [header], [comment] } */
827 g_value_init (&streamheader, GST_TYPE_ARRAY);
830 gst_byte_writer_init_with_size (&w, 80, TRUE);
831 gst_byte_writer_put_data (&w, (guint8 *) "Speex ", 8);
832 gst_byte_writer_put_data (&w, (guint8 *) "1.1.12", 7);
833 gst_byte_writer_fill (&w, 0, 13);
834 gst_byte_writer_put_uint32_le (&w, 1); /* version */
835 gst_byte_writer_put_uint32_le (&w, 80); /* header_size */
836 gst_byte_writer_put_uint32_le (&w, 16000); /* rate */
837 gst_byte_writer_put_uint32_le (&w, 1); /* mode: Wideband */
838 gst_byte_writer_put_uint32_le (&w, 4); /* mode_bitstream_version */
839 gst_byte_writer_put_uint32_le (&w, 1); /* nb_channels: 1 */
840 gst_byte_writer_put_uint32_le (&w, -1); /* bitrate */
841 gst_byte_writer_put_uint32_le (&w, 0x50); /* frame_size */
842 gst_byte_writer_put_uint32_le (&w, 0); /* VBR */
843 gst_byte_writer_put_uint32_le (&w, 1); /* frames_per_packet */
844 gst_byte_writer_put_uint32_le (&w, 0); /* extra_headers */
845 gst_byte_writer_put_uint32_le (&w, 0); /* reserved1 */
846 gst_byte_writer_put_uint32_le (&w, 0); /* reserved2 */
847 g_assert (gst_byte_writer_get_size (&w) == 80);
849 g_value_init (&value, GST_TYPE_BUFFER);
850 g_value_take_boxed (&value, gst_byte_writer_reset_and_get_buffer (&w));
851 gst_value_array_append_value (&streamheader, &value);
852 g_value_unset (&value);
855 g_value_init (&value, GST_TYPE_BUFFER);
856 tags = gst_tag_list_new_empty ();
857 buf = gst_tag_list_to_vorbiscomment_buffer (tags, NULL, 0, "No comments");
858 gst_tag_list_unref (tags);
859 g_value_take_boxed (&value, buf);
860 gst_value_array_append_value (&streamheader, &value);
861 g_value_unset (&value);
863 gst_structure_take_value (structure, "streamheader", &streamheader);
866 adjusted_rate = 16000;
870 GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
874 if (G_UNLIKELY (!caps)) {
875 GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
879 gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
880 "channels", G_TYPE_INT, adjusted_channels, NULL);
882 if (demux->audio_codec_data) {
883 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
884 demux->audio_codec_data, NULL);
887 old_caps = gst_pad_get_current_caps (demux->audio_pad);
890 gst_pad_create_stream_id (demux->audio_pad, GST_ELEMENT_CAST (demux),
893 event = gst_event_new_stream_start (stream_id);
894 if (have_group_id (demux))
895 gst_event_set_group_id (event, demux->group_id);
896 gst_pad_push_event (demux->audio_pad, event);
899 if (!old_caps || !gst_caps_is_equal (old_caps, caps))
900 ret = gst_pad_set_caps (demux->audio_pad, caps);
905 gst_caps_unref (old_caps);
908 if (G_LIKELY (ret)) {
909 /* Store the caps we got from tags */
910 demux->audio_codec_tag = codec_tag;
912 demux->channels = channels;
913 demux->width = width;
916 GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
917 GST_PTR_FORMAT, caps);
919 gst_flv_demux_push_tags (demux);
921 GST_DEBUG_OBJECT (demux->audio_pad, "delayed setting caps");
924 GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
925 GST_PTR_FORMAT, caps);
929 gst_caps_unref (caps);
936 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
940 if (demux->audio_pad)
941 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
943 if (demux->video_pad)
944 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
946 gst_event_unref (event);
952 gst_flv_demux_add_codec_tag (GstFlvDemux * demux, const gchar * tag,
956 GstCaps *caps = gst_pad_get_current_caps (pad);
959 gchar *codec_name = gst_pb_utils_get_codec_description (caps);
962 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
963 tag, codec_name, NULL);
967 gst_caps_unref (caps);
973 gst_flv_demux_push_tags (GstFlvDemux * demux)
975 gst_flv_demux_add_codec_tag (demux, GST_TAG_AUDIO_CODEC, demux->audio_pad);
976 gst_flv_demux_add_codec_tag (demux, GST_TAG_VIDEO_CODEC, demux->video_pad);
978 GST_DEBUG_OBJECT (demux, "pushing %" GST_PTR_FORMAT, demux->taglist);
980 gst_flv_demux_push_src_event (demux,
981 gst_event_new_tag (gst_tag_list_copy (demux->taglist)));
983 if (demux->audio_pad) {
984 GST_DEBUG_OBJECT (demux->audio_pad, "pushing audio %" GST_PTR_FORMAT,
986 gst_pad_push_event (demux->audio_pad,
987 gst_event_new_tag (gst_tag_list_copy (demux->audio_tags)));
990 if (demux->video_pad) {
991 GST_DEBUG_OBJECT (demux->video_pad, "pushing video %" GST_PTR_FORMAT,
993 gst_pad_push_event (demux->video_pad,
994 gst_event_new_tag (gst_tag_list_copy (demux->video_tags)));
999 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 dts, gboolean discont,
1000 guint32 * last, GstClockTime * offset)
1002 gboolean ret = FALSE;
1003 gint32 ddts = dts - *last;
1004 if (!discont && ddts <= -RESYNC_THRESHOLD) {
1005 /* Theoretically, we should use substract the duration of the last buffer,
1006 but this demuxer sends no durations on buffers, not sure if it cannot
1007 know, or just does not care to calculate. */
1008 *offset -= ddts * GST_MSECOND;
1009 GST_WARNING_OBJECT (demux,
1010 "Large dts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
1011 GST_TIME_FORMAT "", ddts, GST_TIME_ARGS (*offset));
1020 static GstFlowReturn
1021 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
1023 GstFlowReturn ret = GST_FLOW_OK;
1024 guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
1025 guint32 codec_data = 0, pts_ext = 0;
1031 GST_LOG_OBJECT (demux, "parsing an audio tag");
1033 if (G_UNLIKELY (!demux->audio_pad && demux->no_more_pads)) {
1034 #ifndef GST_DISABLE_DEBUG
1035 if (G_UNLIKELY (!demux->no_audio_warned)) {
1036 GST_WARNING_OBJECT (demux,
1037 "Signaled no-more-pads already but had no audio pad -- ignoring");
1038 demux->no_audio_warned = TRUE;
1044 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1047 /* Error out on tags with too small headers */
1048 if (gst_buffer_get_size (buffer) < 11) {
1049 GST_ERROR_OBJECT (demux, "Too small tag size (%" G_GSIZE_FORMAT ")",
1050 gst_buffer_get_size (buffer));
1051 return GST_FLOW_ERROR;
1054 gst_buffer_map (buffer, &map, GST_MAP_READ);
1057 /* Grab information about audio tag */
1058 pts = GST_READ_UINT24_BE (data);
1059 /* read the pts extension to 32 bits integer */
1060 pts_ext = GST_READ_UINT8 (data + 3);
1062 pts |= pts_ext << 24;
1064 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1065 data[2], data[3], pts);
1067 /* Skip the stream id and go directly to the flags */
1068 flags = GST_READ_UINT8 (data + 7);
1070 /* Silently skip buffers with no data */
1083 if ((flags & 0x0C) == 0x0C) {
1085 } else if ((flags & 0x0C) == 0x08) {
1087 } else if ((flags & 0x0C) == 0x04) {
1091 codec_tag = flags >> 4;
1092 if (codec_tag == 10) { /* AAC has an extra byte for packet type */
1098 /* codec tags with special rates */
1099 if (codec_tag == 5 || codec_tag == 14)
1101 else if ((codec_tag == 4) || (codec_tag == 11))
1104 GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
1105 "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
1108 if (codec_tag == 10) {
1109 guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
1111 switch (aac_packet_type) {
1114 /* AudioSpecificConfig data */
1115 GST_LOG_OBJECT (demux, "got an AAC codec data packet");
1116 if (demux->audio_codec_data) {
1117 gst_buffer_unref (demux->audio_codec_data);
1119 demux->audio_codec_data =
1120 gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1121 7 + codec_data, demux->tag_data_size - codec_data);
1123 /* Use that buffer data in the caps */
1124 if (demux->audio_pad)
1125 gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1130 if (!demux->audio_codec_data) {
1131 GST_ERROR_OBJECT (demux, "got AAC audio packet before codec data");
1135 /* AAC raw packet */
1136 GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
1139 GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
1144 /* If we don't have our audio pad created, then create it. */
1145 if (G_UNLIKELY (!demux->audio_pad)) {
1147 gst_pad_new_from_template (gst_element_class_get_pad_template
1148 (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
1149 if (G_UNLIKELY (!demux->audio_pad)) {
1150 GST_WARNING_OBJECT (demux, "failed creating audio pad");
1151 ret = GST_FLOW_ERROR;
1155 /* Set functions on the pad */
1156 gst_pad_set_query_function (demux->audio_pad,
1157 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1158 gst_pad_set_event_function (demux->audio_pad,
1159 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1161 gst_pad_use_fixed_caps (demux->audio_pad);
1163 /* Make it active */
1164 gst_pad_set_active (demux->audio_pad, TRUE);
1166 /* Negotiate caps */
1167 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1169 gst_object_unref (demux->audio_pad);
1170 demux->audio_pad = NULL;
1171 ret = GST_FLOW_ERROR;
1174 #ifndef GST_DISABLE_GST_DEBUG
1178 caps = gst_pad_get_current_caps (demux->audio_pad);
1179 GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
1182 gst_caps_unref (caps);
1186 /* We need to set caps before adding */
1187 gst_element_add_pad (GST_ELEMENT (demux),
1188 gst_object_ref (demux->audio_pad));
1189 gst_flow_combiner_add_pad (demux->flowcombiner, demux->audio_pad);
1191 /* We only emit no more pads when we have audio and video. Indeed we can
1192 * not trust the FLV header to tell us if there will be only audio or
1193 * only video and we would just break discovery of some files */
1194 if (demux->audio_pad && demux->video_pad) {
1195 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1196 gst_element_no_more_pads (GST_ELEMENT (demux));
1197 demux->no_more_pads = TRUE;
1201 /* Check if caps have changed */
1202 if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
1203 codec_tag != demux->audio_codec_tag || width != demux->width)) {
1204 GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
1206 gst_buffer_replace (&demux->audio_codec_data, NULL);
1208 /* Negotiate caps */
1209 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1211 ret = GST_FLOW_ERROR;
1216 /* Check if we have anything to push */
1217 if (demux->tag_data_size <= codec_data) {
1218 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1222 /* Create buffer from pad */
1223 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1224 7 + codec_data, demux->tag_data_size - codec_data);
1226 /* detect (and deem to be resyncs) large pts gaps */
1227 if (gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
1228 &demux->last_audio_pts, &demux->audio_time_offset)) {
1229 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
1232 /* Fill buffer with data */
1233 GST_BUFFER_PTS (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
1234 GST_BUFFER_DTS (outbuf) = GST_BUFFER_PTS (outbuf);
1235 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1236 GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
1237 GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
1239 if (demux->duration == GST_CLOCK_TIME_NONE ||
1240 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1241 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1243 /* Only add audio frames to the index if we have no video,
1244 * and if the index is not yet complete */
1245 if (!demux->has_video && !demux->indexed) {
1246 gst_flv_demux_parse_and_add_index_entry (demux,
1247 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
1250 if (G_UNLIKELY (demux->audio_need_discont)) {
1251 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1252 demux->audio_need_discont = FALSE;
1255 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1257 /* Do we need a newsegment event ? */
1258 if (G_UNLIKELY (demux->audio_need_segment)) {
1259 if (!demux->new_seg_event) {
1260 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1261 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1262 GST_TIME_ARGS (demux->segment.position),
1263 GST_TIME_ARGS (demux->segment.stop));
1264 demux->segment.start = demux->segment.time = demux->segment.position;
1265 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1267 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1270 gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1272 demux->audio_need_segment = FALSE;
1275 GST_LOG_OBJECT (demux,
1276 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1277 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1278 gst_buffer_get_size (outbuf),
1279 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1280 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1282 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1283 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1285 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1286 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1289 if (G_UNLIKELY (!demux->no_more_pads
1290 && (GST_CLOCK_DIFF (demux->audio_start,
1291 GST_BUFFER_TIMESTAMP (outbuf)) > NO_MORE_PADS_THRESHOLD))) {
1292 GST_DEBUG_OBJECT (demux,
1293 "Signalling no-more-pads because no video stream was found"
1294 " after 6 seconds of audio");
1295 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1296 demux->no_more_pads = TRUE;
1299 /* Push downstream */
1300 ret = gst_pad_push (demux->audio_pad, outbuf);
1302 if (G_UNLIKELY (ret != GST_FLOW_OK) &&
1303 demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1304 demux->segment.position > demux->segment.stop) {
1305 /* In reverse playback we can get a GST_FLOW_EOS when
1306 * we are at the end of the segment, so we just need to jump
1307 * back to the previous section. */
1308 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1309 demux->audio_done = TRUE;
1314 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner,
1315 demux->audio_pad, ret);
1318 gst_buffer_unmap (buffer, &map);
1324 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1326 gboolean ret = FALSE;
1327 GstCaps *caps = NULL, *old_caps;
1331 /* Generate caps for that pad */
1332 switch (codec_tag) {
1335 gst_caps_new_simple ("video/x-flash-video", "flvversion", G_TYPE_INT,
1339 caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1342 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1345 caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1348 if (!demux->video_codec_data) {
1349 GST_DEBUG_OBJECT (demux, "don't have h264 codec data yet");
1354 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1357 /* The following two are non-standard but apparently used, see in ffmpeg
1358 * https://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/flvdec.c;h=2bf1e059e1cbeeb79e4af9542da23f4560e1cf59;hb=b18d6c58000beed872d6bb1fe7d0fbe75ae26aef#l254
1359 * https://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/flvdec.c;h=2bf1e059e1cbeeb79e4af9542da23f4560e1cf59;hb=b18d6c58000beed872d6bb1fe7d0fbe75ae26aef#l282
1362 caps = gst_caps_new_empty_simple ("video/x-h263");
1366 gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
1367 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1370 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1373 if (G_UNLIKELY (!caps)) {
1374 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1378 if (demux->got_par) {
1379 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1380 demux->par_x, demux->par_y, NULL);
1383 if (G_LIKELY (demux->w)) {
1384 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1387 if (G_LIKELY (demux->h)) {
1388 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1391 if (G_LIKELY (demux->framerate)) {
1392 gint num = 0, den = 0;
1394 gst_video_guess_framerate (GST_SECOND / demux->framerate, &num, &den);
1395 GST_DEBUG_OBJECT (demux->video_pad,
1396 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1399 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1402 if (demux->video_codec_data) {
1403 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1404 demux->video_codec_data, NULL);
1407 old_caps = gst_pad_get_current_caps (demux->video_pad);
1410 gst_pad_create_stream_id (demux->video_pad, GST_ELEMENT_CAST (demux),
1412 event = gst_event_new_stream_start (stream_id);
1415 if (have_group_id (demux))
1416 gst_event_set_group_id (event, demux->group_id);
1417 gst_pad_push_event (demux->video_pad, event);
1420 if (!old_caps || !gst_caps_is_equal (old_caps, caps))
1421 ret = gst_pad_set_caps (demux->video_pad, caps);
1426 gst_caps_unref (old_caps);
1429 if (G_LIKELY (ret)) {
1430 /* Store the caps we have set */
1431 demux->video_codec_tag = codec_tag;
1434 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1435 GST_PTR_FORMAT, caps);
1437 gst_flv_demux_push_tags (demux);
1439 GST_DEBUG_OBJECT (demux->video_pad, "delayed setting caps");
1442 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1443 GST_PTR_FORMAT, caps);
1447 gst_caps_unref (caps);
1453 static GstFlowReturn
1454 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1456 GstFlowReturn ret = GST_FLOW_OK;
1457 guint32 dts = 0, codec_data = 1, dts_ext = 0;
1459 gboolean keyframe = FALSE;
1460 guint8 flags = 0, codec_tag = 0;
1465 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1468 GST_LOG_OBJECT (demux, "parsing a video tag");
1471 (!demux->video_pad && demux->no_more_pads) {
1472 #ifndef GST_DISABLE_DEBUG
1474 (!demux->no_video_warned) {
1475 GST_WARNING_OBJECT (demux,
1476 "Signaled no-more-pads already but had no video pad -- ignoring");
1477 demux->no_video_warned = TRUE;
1483 if (gst_buffer_get_size (buffer) < 12) {
1484 GST_ERROR_OBJECT (demux, "Too small tag size");
1485 return GST_FLOW_ERROR;
1488 gst_buffer_map (buffer, &map, GST_MAP_READ);
1491 /* Grab information about video tag */
1492 dts = GST_READ_UINT24_BE (data);
1493 /* read the dts extension to 32 bits integer */
1494 dts_ext = GST_READ_UINT8 (data + 3);
1496 dts |= dts_ext << 24;
1498 GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1499 data[2], data[3], dts);
1501 /* Skip the stream id and go directly to the flags */
1502 flags = GST_READ_UINT8 (data + 7);
1505 if ((flags >> 4) == 1) {
1509 codec_tag = flags & 0x0F;
1510 if (codec_tag == 4 || codec_tag == 5) {
1512 } else if (codec_tag == 7) {
1515 cts = GST_READ_UINT24_BE (data + 9);
1516 cts = (cts + 0xff800000) ^ 0xff800000;
1518 if (cts < 0 && ABS (cts) > dts) {
1519 GST_ERROR_OBJECT (demux, "Detected a negative composition time offset "
1520 "'%d' that would lead to negative PTS, fixing", cts);
1521 cts += ABS (cts) - dts;
1524 GST_LOG_OBJECT (demux, "got cts %d", cts);
1527 GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1528 "(flags %02X)", codec_tag, keyframe, flags);
1530 if (codec_tag == 7) {
1531 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1533 switch (avc_packet_type) {
1536 if (demux->tag_data_size < codec_data) {
1537 GST_ERROR_OBJECT (demux, "Got invalid H.264 codec, ignoring.");
1541 /* AVCDecoderConfigurationRecord data */
1542 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1543 if (demux->video_codec_data) {
1544 gst_buffer_unref (demux->video_codec_data);
1546 demux->video_codec_data = gst_buffer_copy_region (buffer,
1547 GST_BUFFER_COPY_MEMORY, 7 + codec_data,
1548 demux->tag_data_size - codec_data);;
1549 /* Use that buffer data in the caps */
1550 if (demux->video_pad)
1551 gst_flv_demux_video_negotiate (demux, codec_tag);
1555 /* H.264 NALU packet */
1556 if (!demux->video_codec_data) {
1557 GST_ERROR_OBJECT (demux, "got H.264 video packet before codec data");
1561 GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1564 GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1569 /* If we don't have our video pad created, then create it. */
1570 if (G_UNLIKELY (!demux->video_pad)) {
1572 gst_pad_new_from_template (gst_element_class_get_pad_template
1573 (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1574 if (G_UNLIKELY (!demux->video_pad)) {
1575 GST_WARNING_OBJECT (demux, "failed creating video pad");
1576 ret = GST_FLOW_ERROR;
1580 /* Set functions on the pad */
1581 gst_pad_set_query_function (demux->video_pad,
1582 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1583 gst_pad_set_event_function (demux->video_pad,
1584 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1586 gst_pad_use_fixed_caps (demux->video_pad);
1588 /* Make it active */
1589 gst_pad_set_active (demux->video_pad, TRUE);
1591 /* Needs to be active before setting caps */
1592 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1593 gst_object_unref (demux->video_pad);
1594 demux->video_pad = NULL;
1595 ret = GST_FLOW_ERROR;
1599 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1600 * metadata tag that would come later and trigger a caps change */
1601 demux->got_par = FALSE;
1603 #ifndef GST_DISABLE_GST_DEBUG
1607 caps = gst_pad_get_current_caps (demux->video_pad);
1608 GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1611 gst_caps_unref (caps);
1615 /* We need to set caps before adding */
1616 gst_element_add_pad (GST_ELEMENT (demux),
1617 gst_object_ref (demux->video_pad));
1618 gst_flow_combiner_add_pad (demux->flowcombiner, demux->video_pad);
1620 /* We only emit no more pads when we have audio and video. Indeed we can
1621 * not trust the FLV header to tell us if there will be only audio or
1622 * only video and we would just break discovery of some files */
1623 if (demux->audio_pad && demux->video_pad) {
1624 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1625 gst_element_no_more_pads (GST_ELEMENT (demux));
1626 demux->no_more_pads = TRUE;
1630 /* Check if caps have changed */
1631 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1632 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1633 gst_buffer_replace (&demux->video_codec_data, NULL);
1635 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1636 ret = GST_FLOW_ERROR;
1640 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1641 * metadata tag that would come later and trigger a caps change */
1642 demux->got_par = FALSE;
1645 /* Check if we have anything to push */
1646 if (demux->tag_data_size <= codec_data) {
1647 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1651 /* Create buffer from pad */
1652 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1653 7 + codec_data, demux->tag_data_size - codec_data);
1655 /* detect (and deem to be resyncs) large dts gaps */
1656 if (gst_flv_demux_update_resync (demux, dts, demux->video_need_discont,
1657 &demux->last_video_dts, &demux->video_time_offset)) {
1658 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
1661 /* Fill buffer with data */
1662 GST_LOG_OBJECT (demux, "dts %u pts %u cts %d", dts, dts + cts, cts);
1664 GST_BUFFER_PTS (outbuf) =
1665 (dts + cts) * GST_MSECOND + demux->video_time_offset;
1666 GST_BUFFER_DTS (outbuf) = dts * GST_MSECOND + demux->video_time_offset;
1667 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1668 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1669 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1671 if (demux->duration == GST_CLOCK_TIME_NONE ||
1672 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1673 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1676 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1678 if (!demux->indexed) {
1679 gst_flv_demux_parse_and_add_index_entry (demux,
1680 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1683 if (G_UNLIKELY (demux->video_need_discont)) {
1684 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1685 demux->video_need_discont = FALSE;
1688 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1690 /* Do we need a newsegment event ? */
1691 if (G_UNLIKELY (demux->video_need_segment)) {
1692 if (!demux->new_seg_event) {
1693 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1694 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1695 GST_TIME_ARGS (demux->segment.position),
1696 GST_TIME_ARGS (demux->segment.stop));
1697 demux->segment.start = demux->segment.time = demux->segment.position;
1698 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1700 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1703 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1705 demux->video_need_segment = FALSE;
1708 GST_LOG_OBJECT (demux,
1709 "pushing %" G_GSIZE_FORMAT " bytes buffer at dts %" GST_TIME_FORMAT
1710 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1711 ", keyframe (%d)", gst_buffer_get_size (outbuf),
1712 GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
1713 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1716 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1717 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1719 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1720 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1723 if (G_UNLIKELY (!demux->no_more_pads
1724 && (GST_CLOCK_DIFF (demux->video_start,
1725 GST_BUFFER_TIMESTAMP (outbuf)) > NO_MORE_PADS_THRESHOLD))) {
1726 GST_DEBUG_OBJECT (demux,
1727 "Signalling no-more-pads because no audio stream was found"
1728 " after 6 seconds of video");
1729 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1730 demux->no_more_pads = TRUE;
1733 /* Push downstream */
1734 ret = gst_pad_push (demux->video_pad, outbuf);
1736 if (G_UNLIKELY (ret != GST_FLOW_OK) &&
1737 demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1738 demux->segment.position > demux->segment.stop) {
1739 /* In reverse playback we can get a GST_FLOW_EOS when
1740 * we are at the end of the segment, so we just need to jump
1741 * back to the previous section. */
1742 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1743 demux->video_done = TRUE;
1748 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner,
1749 demux->video_pad, ret);
1752 gst_buffer_unmap (buffer, &map);
1757 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1758 GstBuffer * buffer, size_t * tag_size)
1760 guint32 dts = 0, dts_ext = 0;
1761 guint32 tag_data_size;
1763 gboolean keyframe = TRUE;
1764 GstClockTime ret = GST_CLOCK_TIME_NONE;
1769 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1770 GST_CLOCK_TIME_NONE);
1772 gst_buffer_map (buffer, &map, GST_MAP_READ);
1778 if (type != 9 && type != 8 && type != 18) {
1779 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1784 demux->has_video = TRUE;
1786 demux->has_audio = TRUE;
1788 tag_data_size = GST_READ_UINT24_BE (data + 1);
1790 if (size >= tag_data_size + 11 + 4) {
1791 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1792 GST_WARNING_OBJECT (demux, "Invalid tag size");
1798 *tag_size = tag_data_size + 11 + 4;
1802 GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X", data[0], data[1],
1805 /* Grab timestamp of tag tag */
1806 dts = GST_READ_UINT24_BE (data);
1807 /* read the dts extension to 32 bits integer */
1808 dts_ext = GST_READ_UINT8 (data + 3);
1810 dts |= dts_ext << 24;
1815 keyframe = ((data[0] >> 4) == 1);
1818 ret = dts * GST_MSECOND;
1819 GST_LOG_OBJECT (demux, "dts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1821 if (index && !demux->indexed && (type == 9 || (type == 8
1822 && !demux->has_video))) {
1823 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1827 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1828 demux->duration = ret;
1831 gst_buffer_unmap (buffer, &map);
1835 static GstFlowReturn
1836 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1838 GstFlowReturn ret = GST_FLOW_OK;
1839 guint8 tag_type = 0;
1842 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1844 gst_buffer_map (buffer, &map, GST_MAP_READ);
1846 tag_type = map.data[0];
1848 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1849 * 4 bytes of previous tag size */
1850 demux->tag_data_size = GST_READ_UINT24_BE (map.data + 1);
1851 demux->tag_size = demux->tag_data_size + 11;
1853 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1854 demux->tag_data_size);
1856 gst_buffer_unmap (buffer, &map);
1860 demux->state = FLV_STATE_TAG_VIDEO;
1861 demux->has_video = TRUE;
1864 demux->state = FLV_STATE_TAG_AUDIO;
1865 demux->has_audio = TRUE;
1868 demux->state = FLV_STATE_TAG_SCRIPT;
1871 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1872 demux->state = FLV_STATE_SKIP;
1878 static GstFlowReturn
1879 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1881 GstFlowReturn ret = GST_FLOW_OK;
1884 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1886 gst_buffer_map (buffer, &map, GST_MAP_READ);
1888 /* Check for the FLV tag */
1889 if (map.data[0] == 'F' && map.data[1] == 'L' && map.data[2] == 'V') {
1890 GST_DEBUG_OBJECT (demux, "FLV header detected");
1892 if (G_UNLIKELY (demux->strict)) {
1893 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1899 if (map.data[3] == '1') {
1900 GST_DEBUG_OBJECT (demux, "FLV version 1 detected");
1902 if (G_UNLIKELY (demux->strict)) {
1903 GST_WARNING_OBJECT (demux, "invalid header version detected");
1910 /* Now look at audio/video flags */
1912 guint8 flags = map.data[4];
1914 demux->has_video = demux->has_audio = FALSE;
1917 GST_DEBUG_OBJECT (demux, "there is a video stream");
1918 demux->has_video = TRUE;
1921 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1922 demux->has_audio = TRUE;
1926 /* do a one-time seekability check */
1927 gst_flv_demux_check_seekability (demux);
1929 /* We don't care about the rest */
1930 demux->need_header = FALSE;
1933 gst_buffer_unmap (buffer, &map);
1939 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1941 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1943 gst_adapter_clear (demux->adapter);
1945 demux->audio_need_discont = TRUE;
1946 demux->video_need_discont = TRUE;
1948 demux->flushing = FALSE;
1950 /* Only in push mode and if we're not during a seek */
1951 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1952 /* After a flush we expect a tag_type */
1953 demux->state = FLV_STATE_TAG_TYPE;
1954 /* We reset the offset and will get one from first push */
1960 gst_flv_demux_cleanup (GstFlvDemux * demux)
1962 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1964 demux->state = FLV_STATE_HEADER;
1966 demux->have_group_id = FALSE;
1967 demux->group_id = G_MAXUINT;
1969 demux->flushing = FALSE;
1970 demux->need_header = TRUE;
1971 demux->audio_need_segment = TRUE;
1972 demux->video_need_segment = TRUE;
1973 demux->audio_need_discont = TRUE;
1974 demux->video_need_discont = TRUE;
1976 demux->has_audio = FALSE;
1977 demux->has_video = FALSE;
1978 demux->got_par = FALSE;
1980 demux->indexed = FALSE;
1981 demux->upstream_seekable = FALSE;
1982 demux->file_size = 0;
1984 demux->index_max_pos = 0;
1985 demux->index_max_time = 0;
1987 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1988 demux->last_audio_pts = demux->last_video_dts = 0;
1989 demux->audio_time_offset = demux->video_time_offset = 0;
1991 demux->no_more_pads = FALSE;
1993 #ifndef GST_DISABLE_DEBUG
1994 demux->no_audio_warned = FALSE;
1995 demux->no_video_warned = FALSE;
1998 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
2000 demux->w = demux->h = 0;
2001 demux->framerate = 0.0;
2002 demux->par_x = demux->par_y = 1;
2003 demux->video_offset = 0;
2004 demux->audio_offset = 0;
2005 demux->offset = demux->cur_tag_offset = 0;
2006 demux->tag_size = demux->tag_data_size = 0;
2007 demux->duration = GST_CLOCK_TIME_NONE;
2009 if (demux->new_seg_event) {
2010 gst_event_unref (demux->new_seg_event);
2011 demux->new_seg_event = NULL;
2014 gst_adapter_clear (demux->adapter);
2016 if (demux->audio_codec_data) {
2017 gst_buffer_unref (demux->audio_codec_data);
2018 demux->audio_codec_data = NULL;
2021 if (demux->video_codec_data) {
2022 gst_buffer_unref (demux->video_codec_data);
2023 demux->video_codec_data = NULL;
2026 if (demux->audio_pad) {
2027 gst_flow_combiner_remove_pad (demux->flowcombiner, demux->audio_pad);
2028 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
2029 gst_object_unref (demux->audio_pad);
2030 demux->audio_pad = NULL;
2033 if (demux->video_pad) {
2034 gst_flow_combiner_remove_pad (demux->flowcombiner, demux->video_pad);
2035 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
2036 gst_object_unref (demux->video_pad);
2037 demux->video_pad = NULL;
2041 g_array_free (demux->times, TRUE);
2042 demux->times = NULL;
2045 if (demux->filepositions) {
2046 g_array_free (demux->filepositions, TRUE);
2047 demux->filepositions = NULL;
2050 gst_flv_demux_clear_tags (demux);
2054 * Create and push a flushing seek event upstream
2057 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
2062 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
2065 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
2066 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
2067 GST_SEEK_TYPE_NONE, -1);
2069 res = gst_pad_push_event (demux->sinkpad, event);
2072 demux->offset = offset;
2076 static GstFlowReturn
2077 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
2079 GstFlowReturn ret = GST_FLOW_OK;
2080 GstFlvDemux *demux = NULL;
2082 demux = GST_FLV_DEMUX (parent);
2084 GST_LOG_OBJECT (demux,
2085 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
2086 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
2087 GST_BUFFER_OFFSET (buffer));
2089 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
2090 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
2091 demux->state = FLV_STATE_HEADER;
2095 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
2096 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
2097 demux->offset = GST_BUFFER_OFFSET (buffer);
2100 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
2101 GST_DEBUG_OBJECT (demux, "Discontinuity");
2102 gst_adapter_clear (demux->adapter);
2105 gst_adapter_push (demux->adapter, buffer);
2107 if (demux->seeking) {
2108 demux->state = FLV_STATE_SEEK;
2109 GST_OBJECT_LOCK (demux);
2110 demux->seeking = FALSE;
2111 GST_OBJECT_UNLOCK (demux);
2115 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2116 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
2120 if (G_UNLIKELY (demux->flushing)) {
2121 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
2122 ret = GST_FLOW_FLUSHING;
2126 switch (demux->state) {
2127 case FLV_STATE_HEADER:
2129 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
2132 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
2134 ret = gst_flv_demux_parse_header (demux, buffer);
2136 gst_buffer_unref (buffer);
2137 demux->offset += FLV_HEADER_SIZE;
2139 demux->state = FLV_STATE_TAG_TYPE;
2145 case FLV_STATE_TAG_TYPE:
2147 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
2150 /* Remember the tag offset in bytes */
2151 demux->cur_tag_offset = demux->offset;
2153 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
2155 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2157 gst_buffer_unref (buffer);
2158 demux->offset += FLV_TAG_TYPE_SIZE;
2160 /* last tag is not an index => no index/don't know where the index is
2161 * seek back to the beginning */
2162 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
2170 case FLV_STATE_TAG_VIDEO:
2172 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2175 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2177 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2179 gst_buffer_unref (buffer);
2180 demux->offset += demux->tag_size;
2182 demux->state = FLV_STATE_TAG_TYPE;
2188 case FLV_STATE_TAG_AUDIO:
2190 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2193 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2195 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2197 gst_buffer_unref (buffer);
2198 demux->offset += demux->tag_size;
2200 demux->state = FLV_STATE_TAG_TYPE;
2206 case FLV_STATE_TAG_SCRIPT:
2208 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2211 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2213 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2215 gst_buffer_unref (buffer);
2216 demux->offset += demux->tag_size;
2218 demux->state = FLV_STATE_TAG_TYPE;
2220 /* if there's a seek event we're here for the index so if we don't have it
2221 * we seek back to the beginning */
2222 if (demux->seek_event) {
2224 demux->state = FLV_STATE_SEEK;
2234 case FLV_STATE_SEEK:
2240 if (!demux->indexed) {
2241 if (demux->offset == demux->file_size - sizeof (guint32)) {
2242 guint64 seek_offset;
2245 data = gst_adapter_take (demux->adapter, 4);
2249 seek_offset = demux->file_size - sizeof (guint32) -
2250 GST_READ_UINT32_BE (data);
2253 GST_INFO_OBJECT (demux,
2254 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
2256 demux->state = FLV_STATE_TAG_TYPE;
2257 flv_demux_seek_to_offset (demux, seek_offset);
2263 GST_OBJECT_LOCK (demux);
2264 event = demux->seek_event;
2265 demux->seek_event = NULL;
2266 GST_OBJECT_UNLOCK (demux);
2268 /* calculate and perform seek */
2269 if (!flv_demux_handle_seek_push (demux, event))
2272 gst_event_unref (event);
2273 demux->state = FLV_STATE_TAG_TYPE;
2276 case FLV_STATE_SKIP:
2277 /* Skip unknown tags (set in _parse_tag_type()) */
2278 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2279 gst_adapter_flush (demux->adapter, demux->tag_size);
2280 demux->offset += demux->tag_size;
2281 demux->state = FLV_STATE_TAG_TYPE;
2287 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
2296 GST_OBJECT_LOCK (demux);
2297 demux->seeking = FALSE;
2298 gst_event_unref (demux->seek_event);
2299 demux->seek_event = NULL;
2300 GST_OBJECT_UNLOCK (demux);
2301 GST_WARNING_OBJECT (demux,
2302 "failed to find an index, seeking back to beginning");
2303 flv_demux_seek_to_offset (demux, 0);
2308 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2309 return GST_FLOW_ERROR;
2314 static GstFlowReturn
2315 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2316 guint size, GstBuffer ** buffer)
2320 ret = gst_pad_pull_range (pad, offset, size, buffer);
2321 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2322 GST_WARNING_OBJECT (demux,
2323 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2324 size, offset, gst_flow_get_name (ret));
2329 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2330 GST_WARNING_OBJECT (demux,
2331 "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
2332 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
2333 gst_buffer_unref (*buffer);
2342 static GstFlowReturn
2343 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2345 GstBuffer *buffer = NULL;
2346 GstFlowReturn ret = GST_FLOW_OK;
2348 /* Store tag offset */
2349 demux->cur_tag_offset = demux->offset;
2351 /* Get the first 4 bytes to identify tag type and size */
2352 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2353 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2356 /* Identify tag type */
2357 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2359 gst_buffer_unref (buffer);
2361 if (G_UNLIKELY (ret != GST_FLOW_OK))
2364 /* Jump over tag type + size */
2365 demux->offset += FLV_TAG_TYPE_SIZE;
2367 /* Pull the whole tag */
2369 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2370 demux->tag_size, &buffer)) != GST_FLOW_OK))
2373 switch (demux->state) {
2374 case FLV_STATE_TAG_VIDEO:
2375 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2377 case FLV_STATE_TAG_AUDIO:
2378 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2380 case FLV_STATE_TAG_SCRIPT:
2381 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2384 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2387 gst_buffer_unref (buffer);
2389 /* Jump over that part we've just parsed */
2390 demux->offset += demux->tag_size;
2392 /* Make sure we reinitialize the tag size */
2393 demux->tag_size = 0;
2395 /* Ready for the next tag */
2396 demux->state = FLV_STATE_TAG_TYPE;
2398 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2399 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2400 "neither video nor audio are linked");
2407 static GstFlowReturn
2408 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2410 GstBuffer *buffer = NULL;
2411 GstFlowReturn ret = GST_FLOW_OK;
2413 /* Get the first 9 bytes */
2414 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2415 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2418 ret = gst_flv_demux_parse_header (demux, buffer);
2420 gst_buffer_unref (buffer);
2422 /* Jump over the header now */
2423 demux->offset += FLV_HEADER_SIZE;
2424 demux->state = FLV_STATE_TAG_TYPE;
2431 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2434 demux->offset = offset;
2436 /* Tell all the stream we moved to a different position (discont) */
2437 demux->audio_need_discont = TRUE;
2438 demux->video_need_discont = TRUE;
2440 /* next section setup */
2441 demux->from_offset = -1;
2442 demux->audio_done = demux->video_done = FALSE;
2443 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2446 demux->from_offset = -1;
2447 demux->to_offset = G_MAXINT64;
2450 /* If we seeked at the beginning of the file parse the header again */
2451 if (G_UNLIKELY (!demux->offset)) {
2452 demux->state = FLV_STATE_HEADER;
2453 } else { /* or parse a tag */
2454 demux->state = FLV_STATE_TAG_TYPE;
2458 static GstFlowReturn
2459 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2461 GstFlowReturn ret = GST_FLOW_EOS;
2463 GstIndexEntry *entry = NULL;
2465 GST_DEBUG_OBJECT (demux,
2466 "terminated section started at offset %" G_GINT64_FORMAT,
2467 demux->from_offset);
2469 /* we are done if we got all audio and video */
2470 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2471 demux->audio_first_ts < demux->segment.start) &&
2472 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2473 demux->video_first_ts < demux->segment.start))
2476 if (demux->from_offset <= 0)
2479 GST_DEBUG_OBJECT (demux, "locating previous position");
2481 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2483 /* locate index entry before previous start position */
2485 entry = gst_index_get_assoc_entry (index, demux->index_id,
2486 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2487 GST_FORMAT_BYTES, demux->from_offset - 1);
2490 gint64 bytes = 0, time = 0;
2492 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2493 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2495 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2496 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2497 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2499 /* setup for next section */
2500 demux->to_offset = demux->from_offset;
2501 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2505 gst_object_unref (index);
2512 static GstFlowReturn
2513 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2519 GstClockTime tag_time;
2520 GstFlowReturn ret = GST_FLOW_OK;
2522 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2525 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2526 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2528 old_offset = demux->offset;
2529 demux->offset = pos;
2532 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2533 12, &buffer)) == GST_FLOW_OK) {
2535 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2537 gst_buffer_unref (buffer);
2540 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2543 demux->offset += tag_size;
2546 if (ret == GST_FLOW_EOS) {
2547 /* file ran out, so mark we have complete index */
2548 demux->indexed = TRUE;
2553 demux->offset = old_offset;
2559 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2561 gint64 ret = 0, offset;
2562 size_t tag_size, size;
2563 GstBuffer *buffer = NULL;
2566 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2570 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2571 if (G_UNLIKELY (offset < 4))
2575 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2579 gst_buffer_map (buffer, &map, GST_MAP_READ);
2580 tag_size = GST_READ_UINT32_BE (map.data);
2581 gst_buffer_unmap (buffer, &map);
2582 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2583 gst_buffer_unref (buffer);
2586 if (G_UNLIKELY (offset < tag_size))
2590 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2594 /* a consistency check */
2595 gst_buffer_map (buffer, &map, GST_MAP_READ);
2596 size = GST_READ_UINT24_BE (map.data + 1);
2597 if (size != tag_size - 11) {
2598 gst_buffer_unmap (buffer, &map);
2599 GST_DEBUG_OBJECT (demux,
2600 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2601 ", corrupt or truncated file", size, tag_size - 11);
2605 /* try to update duration with timestamp in any case */
2606 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2608 /* maybe get some more metadata */
2609 if (map.data[0] == 18) {
2610 gst_buffer_unmap (buffer, &map);
2611 gst_buffer_unref (buffer);
2613 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2615 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2617 gst_flv_demux_parse_tag_script (demux, buffer);
2619 gst_buffer_unmap (buffer, &map);
2624 gst_buffer_unref (buffer);
2630 gst_flv_demux_loop (GstPad * pad)
2632 GstFlvDemux *demux = NULL;
2633 GstFlowReturn ret = GST_FLOW_OK;
2635 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2638 switch (demux->state) {
2639 case FLV_STATE_TAG_TYPE:
2640 if (demux->from_offset == -1)
2641 demux->from_offset = demux->offset;
2642 ret = gst_flv_demux_pull_tag (pad, demux);
2643 /* if we have seen real data, we probably passed a possible metadata
2644 * header located at start. So if we do not yet have an index,
2645 * try to pick up metadata (index, duration) at the end */
2646 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2647 (demux->has_video || demux->has_audio)))
2648 demux->file_size = gst_flv_demux_get_metadata (demux);
2650 case FLV_STATE_DONE:
2653 case FLV_STATE_SEEK:
2654 /* seek issued with insufficient index;
2655 * scan for index in task thread from current maximum offset to
2656 * desired time and then perform seek */
2657 /* TODO maybe some buffering message or so to indicate scan progress */
2658 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2660 if (ret != GST_FLOW_OK)
2662 /* position and state arranged by seek,
2663 * also unrefs event */
2664 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2665 demux->seek_event = NULL;
2668 ret = gst_flv_demux_pull_header (pad, demux);
2669 /* index scans start after header */
2670 demux->index_max_pos = demux->offset;
2674 if (demux->segment.rate < 0.0) {
2675 /* check end of section */
2676 if ((gint64) demux->offset >= demux->to_offset ||
2677 demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2678 (demux->audio_done && demux->video_done))
2679 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2681 /* check EOS condition */
2682 if ((demux->segment.stop != -1) &&
2683 (demux->segment.position >= demux->segment.stop)) {
2688 /* pause if something went wrong or at end */
2689 if (G_UNLIKELY (ret != GST_FLOW_OK))
2692 gst_object_unref (demux);
2698 const gchar *reason = gst_flow_get_name (ret);
2700 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2701 gst_pad_pause_task (pad);
2703 if (ret == GST_FLOW_EOS) {
2704 /* handle end-of-stream/segment */
2705 /* so align our position with the end of it, if there is one
2706 * this ensures a subsequent will arrive at correct base/acc time */
2707 if (demux->segment.rate > 0.0 &&
2708 GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2709 demux->segment.position = demux->segment.stop;
2710 else if (demux->segment.rate < 0.0)
2711 demux->segment.position = demux->segment.start;
2713 /* perform EOS logic */
2714 if (!demux->no_more_pads) {
2715 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2716 demux->no_more_pads = TRUE;
2719 if (demux->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
2722 /* for segment playback we need to post when (in stream time)
2723 * we stopped, this is either stop (when set) or the duration. */
2724 if ((stop = demux->segment.stop) == -1)
2725 stop = demux->segment.duration;
2727 if (demux->segment.rate >= 0) {
2728 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2729 gst_element_post_message (GST_ELEMENT_CAST (demux),
2730 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2731 GST_FORMAT_TIME, stop));
2732 gst_flv_demux_push_src_event (demux,
2733 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2734 } else { /* Reverse playback */
2735 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2737 gst_element_post_message (GST_ELEMENT_CAST (demux),
2738 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2739 GST_FORMAT_TIME, demux->segment.start));
2740 gst_flv_demux_push_src_event (demux,
2741 gst_event_new_segment_done (GST_FORMAT_TIME,
2742 demux->segment.start));
2745 /* normal playback, send EOS to all linked pads */
2746 if (!demux->no_more_pads) {
2747 gst_element_no_more_pads (GST_ELEMENT (demux));
2748 demux->no_more_pads = TRUE;
2751 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2752 if (!demux->audio_pad && !demux->video_pad)
2753 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2754 ("Internal data stream error."), ("Got EOS before any data"));
2755 else if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2756 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2758 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2759 GST_ELEMENT_FLOW_ERROR (demux, ret);
2760 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2762 gst_object_unref (demux);
2768 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment,
2769 GstSeekFlags seek_flags)
2774 GstIndexEntry *entry;
2776 g_return_val_if_fail (segment != NULL, 0);
2778 time = segment->position;
2780 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2783 /* Let's check if we have an index entry for that seek time */
2784 entry = gst_index_get_assoc_entry (index, demux->index_id,
2785 seek_flags & GST_SEEK_FLAG_SNAP_AFTER ?
2786 GST_INDEX_LOOKUP_AFTER : GST_INDEX_LOOKUP_BEFORE,
2787 GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, time);
2790 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2791 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2793 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2794 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2795 GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2797 /* Key frame seeking */
2798 if (seek_flags & GST_SEEK_FLAG_KEY_UNIT) {
2799 /* Adjust the segment so that the keyframe fits in */
2800 segment->start = segment->time = time;
2801 segment->position = time;
2804 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2805 GST_TIME_ARGS (segment->start));
2808 gst_object_unref (index);
2815 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2819 GstSeekType start_type, stop_type;
2822 gboolean update, flush, ret;
2823 GstSegment seeksegment;
2825 gst_event_parse_seek (event, &rate, &format, &flags,
2826 &start_type, &start, &stop_type, &stop);
2828 if (format != GST_FORMAT_TIME)
2831 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2833 /* Work on a copy until we are sure the seek succeeded. */
2834 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2836 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2839 /* Apply the seek to our segment */
2840 gst_segment_do_seek (&seeksegment, rate, format, flags,
2841 start_type, start, stop_type, stop, &update);
2843 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2846 if (flush || seeksegment.position != demux->segment.position) {
2847 /* Do the actual seeking */
2848 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment, flags);
2850 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2851 G_GUINT64_FORMAT, offset);
2852 ret = gst_pad_push_event (demux->sinkpad,
2853 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2854 flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2855 offset, GST_SEEK_TYPE_NONE, 0));
2856 if (G_UNLIKELY (!ret)) {
2857 GST_WARNING_OBJECT (demux, "upstream seek failed");
2860 gst_flow_combiner_reset (demux->flowcombiner);
2861 /* Tell all the stream we moved to a different position (discont) */
2862 demux->audio_need_discont = TRUE;
2863 demux->video_need_discont = TRUE;
2869 /* Ok seek succeeded, take the newly configured segment */
2870 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2872 /* Tell all the stream a new segment is needed */
2873 demux->audio_need_segment = TRUE;
2874 demux->video_need_segment = TRUE;
2875 /* Clean any potential newsegment event kept for the streams. The first
2876 * stream needing a new segment will create a new one. */
2877 if (G_UNLIKELY (demux->new_seg_event)) {
2878 gst_event_unref (demux->new_seg_event);
2879 demux->new_seg_event = NULL;
2881 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2882 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2883 GST_TIME_ARGS (demux->segment.start),
2884 GST_TIME_ARGS (demux->segment.stop));
2885 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2886 gst_event_unref (event);
2888 ret = gst_pad_push_event (demux->sinkpad, event);
2896 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2897 gst_event_unref (event);
2903 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2907 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2909 if (format != GST_FORMAT_TIME) {
2910 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2911 gst_event_unref (event);
2915 /* First try upstream */
2916 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2917 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2918 gst_event_unref (event);
2922 if (!demux->indexed) {
2923 guint64 seek_offset = 0;
2924 gboolean building_index;
2926 GST_OBJECT_LOCK (demux);
2927 /* handle the seek in the chain function */
2928 demux->seeking = TRUE;
2929 demux->state = FLV_STATE_SEEK;
2931 /* copy the event */
2932 if (demux->seek_event)
2933 gst_event_unref (demux->seek_event);
2934 demux->seek_event = gst_event_ref (event);
2936 /* set the building_index flag so that only one thread can setup the
2937 * structures for index seeking. */
2938 building_index = demux->building_index;
2939 if (!building_index) {
2940 demux->building_index = TRUE;
2941 if (!demux->file_size
2942 && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2943 &demux->file_size)) {
2944 GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2945 GST_OBJECT_UNLOCK (demux);
2949 /* we hope the last tag is a scriptdataobject containing an index
2950 * the size of the last tag is given in the last guint32 bits
2951 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2952 seek_offset = demux->file_size - sizeof (guint32);
2953 GST_DEBUG_OBJECT (demux,
2954 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2956 GST_OBJECT_UNLOCK (demux);
2958 if (!building_index) {
2959 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2961 return flv_demux_seek_to_offset (demux, seek_offset);
2964 /* FIXME: we have to always return true so that we don't block the seek
2966 * Note: maybe it is OK to return true if we're still building the index */
2970 return flv_demux_handle_seek_push (demux, event);
2974 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2979 GstSeekType start_type, stop_type;
2982 gboolean update, flush, ret = FALSE;
2983 GstSegment seeksegment;
2985 gst_event_parse_seek (event, &rate, &format, &flags,
2986 &start_type, &start, &stop_type, &stop);
2988 if (format != GST_FORMAT_TIME)
2991 /* mark seeking thread entering flushing/pausing */
2992 GST_OBJECT_LOCK (demux);
2994 demux->seeking = seeking;
2995 GST_OBJECT_UNLOCK (demux);
2997 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
3000 /* Flush start up and downstream to make sure data flow and loops are
3002 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
3003 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
3005 /* Pause the pulling task */
3006 gst_pad_pause_task (demux->sinkpad);
3009 /* Take the stream lock */
3010 GST_PAD_STREAM_LOCK (demux->sinkpad);
3013 /* Stop flushing upstream we need to pull */
3014 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
3017 /* Work on a copy until we are sure the seek succeeded. */
3018 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
3020 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
3023 /* Apply the seek to our segment */
3024 gst_segment_do_seek (&seeksegment, rate, format, flags,
3025 start_type, start, stop_type, stop, &update);
3027 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
3030 if (flush || seeksegment.position != demux->segment.position) {
3031 /* Do the actual seeking */
3032 /* index is reliable if it is complete or we do not go to far ahead */
3033 if (seeking && !demux->indexed &&
3034 seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
3035 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
3036 " index only up to %" GST_TIME_FORMAT,
3037 GST_TIME_ARGS (demux->index_max_time));
3038 /* stop flushing for now */
3040 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
3041 /* delegate scanning and index building to task thread to avoid
3042 * occupying main (UI) loop */
3043 if (demux->seek_event)
3044 gst_event_unref (demux->seek_event);
3045 demux->seek_event = gst_event_ref (event);
3046 demux->seek_time = seeksegment.position;
3047 demux->state = FLV_STATE_SEEK;
3048 /* do not know about succes yet, but we did care and handled it */
3053 /* now index should be as reliable as it can be for current purpose */
3054 gst_flv_demux_move_to_offset (demux,
3055 gst_flv_demux_find_offset (demux, &seeksegment, flags), TRUE);
3062 /* Stop flushing, the sinks are at time 0 now */
3063 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
3067 /* Ok seek succeeded, take the newly configured segment */
3068 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
3070 /* Notify about the start of a new segment */
3071 if (demux->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
3072 gst_element_post_message (GST_ELEMENT (demux),
3073 gst_message_new_segment_start (GST_OBJECT (demux),
3074 demux->segment.format, demux->segment.position));
3077 gst_flow_combiner_reset (demux->flowcombiner);
3078 /* Tell all the stream a new segment is needed */
3079 demux->audio_need_segment = TRUE;
3080 demux->video_need_segment = TRUE;
3081 /* Clean any potential newsegment event kept for the streams. The first
3082 * stream needing a new segment will create a new one. */
3083 if (G_UNLIKELY (demux->new_seg_event)) {
3084 gst_event_unref (demux->new_seg_event);
3085 demux->new_seg_event = NULL;
3087 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
3088 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
3089 GST_TIME_ARGS (demux->segment.start),
3090 GST_TIME_ARGS (demux->segment.stop));
3091 demux->new_seg_event = gst_event_new_segment (&demux->segment);
3095 GST_OBJECT_LOCK (demux);
3096 seeking = demux->seeking && !seeking;
3097 demux->seeking = FALSE;
3098 GST_OBJECT_UNLOCK (demux);
3100 /* if we detect an external seek having started (and possibly already having
3101 * flushed), do not restart task to give it a chance.
3102 * Otherwise external one's flushing will take care to pause task */
3104 gst_pad_pause_task (demux->sinkpad);
3106 gst_pad_start_task (demux->sinkpad,
3107 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad, NULL);
3110 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
3112 gst_event_unref (event);
3118 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
3119 gst_event_unref (event);
3124 /* If we can pull that's prefered */
3126 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
3131 query = gst_query_new_scheduling ();
3133 if (!gst_pad_peer_query (sinkpad, query)) {
3134 gst_query_unref (query);
3138 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
3139 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
3140 gst_query_unref (query);
3145 GST_DEBUG_OBJECT (sinkpad, "activating pull");
3146 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
3150 GST_DEBUG_OBJECT (sinkpad, "activating push");
3151 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
3156 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
3157 GstPadMode mode, gboolean active)
3162 demux = GST_FLV_DEMUX (parent);
3165 case GST_PAD_MODE_PUSH:
3166 demux->random_access = FALSE;
3169 case GST_PAD_MODE_PULL:
3171 demux->random_access = TRUE;
3172 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
3175 demux->random_access = FALSE;
3176 res = gst_pad_stop_task (sinkpad);
3187 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
3190 gboolean ret = FALSE;
3192 demux = GST_FLV_DEMUX (parent);
3194 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3196 switch (GST_EVENT_TYPE (event)) {
3197 case GST_EVENT_FLUSH_START:
3198 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
3199 demux->flushing = TRUE;
3200 ret = gst_flv_demux_push_src_event (demux, event);
3202 case GST_EVENT_FLUSH_STOP:
3203 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
3204 gst_flv_demux_flush (demux, TRUE);
3205 ret = gst_flv_demux_push_src_event (demux, event);
3211 GST_DEBUG_OBJECT (demux, "received EOS");
3213 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
3216 GST_DEBUG_OBJECT (demux, "committing index");
3217 gst_index_commit (index, demux->index_id);
3218 gst_object_unref (index);
3221 if (!demux->audio_pad && !demux->video_pad) {
3222 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
3223 ("Internal data stream error."), ("Got EOS before any data"));
3224 gst_event_unref (event);
3226 if (!demux->no_more_pads) {
3227 gst_element_no_more_pads (GST_ELEMENT (demux));
3228 demux->no_more_pads = TRUE;
3231 if (!gst_flv_demux_push_src_event (demux, event))
3232 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
3237 case GST_EVENT_SEGMENT:
3239 GstSegment in_segment;
3241 GST_DEBUG_OBJECT (demux, "received new segment");
3243 gst_event_copy_segment (event, &in_segment);
3245 if (in_segment.format == GST_FORMAT_TIME) {
3246 /* time segment, this is perfect, copy over the values. */
3247 memcpy (&demux->segment, &in_segment, sizeof (in_segment));
3249 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
3253 ret = gst_flv_demux_push_src_event (demux, event);
3255 /* non-time format */
3256 demux->audio_need_segment = TRUE;
3257 demux->video_need_segment = TRUE;
3259 gst_event_unref (event);
3260 if (demux->new_seg_event) {
3261 gst_event_unref (demux->new_seg_event);
3262 demux->new_seg_event = NULL;
3265 gst_flow_combiner_reset (demux->flowcombiner);
3269 ret = gst_pad_event_default (pad, parent, event);
3277 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
3280 gboolean ret = FALSE;
3282 demux = GST_FLV_DEMUX (parent);
3284 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3286 switch (GST_EVENT_TYPE (event)) {
3287 case GST_EVENT_SEEK:
3288 /* Try to push upstream first */
3289 gst_event_ref (event);
3290 ret = gst_pad_push_event (demux->sinkpad, event);
3292 gst_event_unref (event);
3295 if (demux->random_access) {
3296 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
3298 ret = gst_flv_demux_handle_seek_push (demux, event);
3302 ret = gst_pad_push_event (demux->sinkpad, event);
3310 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
3312 gboolean res = TRUE;
3315 demux = GST_FLV_DEMUX (parent);
3317 switch (GST_QUERY_TYPE (query)) {
3318 case GST_QUERY_DURATION:
3322 gst_query_parse_duration (query, &format, NULL);
3324 /* duration is time only */
3325 if (format != GST_FORMAT_TIME) {
3326 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
3332 /* Try to push upstream first */
3333 res = gst_pad_peer_query (demux->sinkpad, query);
3337 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3338 GST_TIME_ARGS (demux->duration));
3340 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3344 case GST_QUERY_POSITION:
3348 gst_query_parse_position (query, &format, NULL);
3350 /* position is time only */
3351 if (format != GST_FORMAT_TIME) {
3352 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3358 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3359 GST_TIME_ARGS (demux->segment.position));
3361 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3366 case GST_QUERY_SEEKING:{
3369 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3371 /* First ask upstream */
3372 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3375 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3382 /* FIXME, check index this way is not thread safe */
3383 if (fmt != GST_FORMAT_TIME || !demux->index) {
3384 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3385 } else if (demux->random_access) {
3386 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3389 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3390 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3393 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3394 gst_query_unref (peerquery);
3397 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3400 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3404 case GST_QUERY_SEGMENT:
3409 format = demux->segment.format;
3412 gst_segment_to_stream_time (&demux->segment, format,
3413 demux->segment.start);
3414 if ((stop = demux->segment.stop) == -1)
3415 stop = demux->segment.duration;
3417 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
3419 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
3423 case GST_QUERY_LATENCY:
3425 res = gst_pad_query_default (pad, parent, query);
3434 static GstStateChangeReturn
3435 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3438 GstStateChangeReturn ret;
3440 demux = GST_FLV_DEMUX (element);
3442 switch (transition) {
3443 case GST_STATE_CHANGE_READY_TO_PAUSED:
3444 /* If this is our own index destroy it as the
3445 * old entries might be wrong for the new stream */
3446 if (demux->own_index) {
3447 gst_object_unref (demux->index);
3448 demux->index = NULL;
3449 demux->own_index = FALSE;
3452 /* If no index was created, generate one */
3453 if (G_UNLIKELY (!demux->index)) {
3454 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3456 demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3458 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3460 demux->own_index = TRUE;
3462 gst_flv_demux_cleanup (demux);
3468 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3469 if (ret == GST_STATE_CHANGE_FAILURE)
3472 switch (transition) {
3473 case GST_STATE_CHANGE_PAUSED_TO_READY:
3474 gst_flv_demux_cleanup (demux);
3485 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3487 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3488 GstIndex *old_index;
3490 GST_OBJECT_LOCK (demux);
3492 old_index = demux->index;
3495 demux->index = gst_object_ref (index);
3496 demux->own_index = FALSE;
3498 demux->index = NULL;
3501 gst_object_unref (demux->index);
3503 gst_object_ref (index);
3505 GST_OBJECT_UNLOCK (demux);
3507 /* object lock might be taken again */
3509 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3511 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3513 gst_object_unref (index);
3518 gst_flv_demux_get_index (GstElement * element)
3520 GstIndex *result = NULL;
3522 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3524 GST_OBJECT_LOCK (demux);
3526 result = gst_object_ref (demux->index);
3527 GST_OBJECT_UNLOCK (demux);
3533 gst_flv_demux_dispose (GObject * object)
3535 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3537 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3539 if (demux->adapter) {
3540 gst_adapter_clear (demux->adapter);
3541 g_object_unref (demux->adapter);
3542 demux->adapter = NULL;
3545 if (demux->taglist) {
3546 gst_tag_list_unref (demux->taglist);
3547 demux->taglist = NULL;
3550 if (demux->audio_tags) {
3551 gst_tag_list_unref (demux->audio_tags);
3552 demux->audio_tags = NULL;
3555 if (demux->video_tags) {
3556 gst_tag_list_unref (demux->video_tags);
3557 demux->video_tags = NULL;
3560 if (demux->flowcombiner) {
3561 gst_flow_combiner_free (demux->flowcombiner);
3562 demux->flowcombiner = NULL;
3565 if (demux->new_seg_event) {
3566 gst_event_unref (demux->new_seg_event);
3567 demux->new_seg_event = NULL;
3570 if (demux->audio_codec_data) {
3571 gst_buffer_unref (demux->audio_codec_data);
3572 demux->audio_codec_data = NULL;
3575 if (demux->video_codec_data) {
3576 gst_buffer_unref (demux->video_codec_data);
3577 demux->video_codec_data = NULL;
3580 if (demux->audio_pad) {
3581 gst_object_unref (demux->audio_pad);
3582 demux->audio_pad = NULL;
3585 if (demux->video_pad) {
3586 gst_object_unref (demux->video_pad);
3587 demux->video_pad = NULL;
3591 gst_object_unref (demux->index);
3592 demux->index = NULL;
3596 g_array_free (demux->times, TRUE);
3597 demux->times = NULL;
3600 if (demux->filepositions) {
3601 g_array_free (demux->filepositions, TRUE);
3602 demux->filepositions = NULL;
3605 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3609 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3611 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3612 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3614 gobject_class->dispose = gst_flv_demux_dispose;
3616 gstelement_class->change_state =
3617 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3620 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3621 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3624 gst_element_class_add_static_pad_template (gstelement_class,
3625 &flv_sink_template);
3626 gst_element_class_add_static_pad_template (gstelement_class,
3627 &audio_src_template);
3628 gst_element_class_add_static_pad_template (gstelement_class,
3629 &video_src_template);
3630 gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
3631 "Codec/Demuxer", "Demux FLV feeds into digital streams",
3632 "Julien Moutte <julien@moutte.net>");
3636 gst_flv_demux_init (GstFlvDemux * demux)
3639 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3641 gst_pad_set_event_function (demux->sinkpad,
3642 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3643 gst_pad_set_chain_function (demux->sinkpad,
3644 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3645 gst_pad_set_activate_function (demux->sinkpad,
3646 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3647 gst_pad_set_activatemode_function (demux->sinkpad,
3648 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3650 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3652 demux->adapter = gst_adapter_new ();
3653 demux->flowcombiner = gst_flow_combiner_new ();
3655 demux->own_index = FALSE;
3657 GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3659 gst_flv_demux_cleanup (demux);
3663 plugin_init (GstPlugin * plugin)
3665 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3667 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3668 gst_flv_demux_get_type ()) ||
3669 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3670 gst_flv_mux_get_type ()))
3676 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3677 flv, "FLV muxing and demuxing plugin",
3678 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)