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) 8000; "
74 "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) 8000; "
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 || !strcmp (tag_name, "encoder")) {
427 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
428 GST_TAG_ENCODER, s, NULL);
430 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
439 gboolean end_of_object_marker = FALSE;
441 while (!end_of_object_marker) {
442 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
443 &end_of_object_marker);
445 if (G_UNLIKELY (!ok)) {
446 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
453 case 8: /* ECMA array */
455 guint32 nb_elems = 0;
456 gboolean end_of_object_marker = FALSE;
458 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
461 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
464 while (!end_of_object_marker) {
465 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
466 &end_of_object_marker);
468 if (G_UNLIKELY (!ok)) {
469 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
476 case 9: /* End marker */
478 GST_DEBUG_OBJECT (demux, "end marker ?");
479 if (tag_name[0] == '\0') {
481 GST_DEBUG_OBJECT (demux, "end marker detected");
490 guint32 nb_elems = 0;
492 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
495 GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
497 if (!strcmp (tag_name, "times")) {
499 g_array_free (demux->times, TRUE);
501 demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
502 } else if (!strcmp (tag_name, "filepositions")) {
503 if (demux->filepositions) {
504 g_array_free (demux->filepositions, TRUE);
506 demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
510 guint8 elem_type = 0;
512 if (!gst_byte_reader_get_uint8 (reader, &elem_type))
520 if (!gst_byte_reader_get_float64_be (reader, &d))
523 GST_DEBUG_OBJECT (demux, "element is a double %f", d);
525 if (!strcmp (tag_name, "times") && demux->times) {
526 g_array_append_val (demux->times, d);
527 } else if (!strcmp (tag_name, "filepositions") &&
528 demux->filepositions) {
529 g_array_append_val (demux->filepositions, d);
534 GST_WARNING_OBJECT (demux, "unsupported array element type %d",
546 if (!gst_byte_reader_get_float64_be (reader, &d))
549 if (!gst_byte_reader_get_int16_be (reader, &i))
552 GST_DEBUG_OBJECT (demux,
553 "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
555 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
560 GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
574 gst_flv_demux_clear_tags (GstFlvDemux * demux)
576 GST_DEBUG_OBJECT (demux, "clearing taglist");
578 if (demux->taglist) {
579 gst_tag_list_unref (demux->taglist);
581 demux->taglist = gst_tag_list_new_empty ();
582 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
584 if (demux->audio_tags) {
585 gst_tag_list_unref (demux->audio_tags);
587 demux->audio_tags = gst_tag_list_new_empty ();
589 if (demux->video_tags) {
590 gst_tag_list_unref (demux->video_tags);
592 demux->video_tags = gst_tag_list_new_empty ();
596 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
598 GstFlowReturn ret = GST_FLOW_OK;
599 GstByteReader reader;
603 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 7, GST_FLOW_ERROR);
605 gst_buffer_map (buffer, &map, GST_MAP_READ);
606 gst_byte_reader_init (&reader, map.data, map.size);
608 gst_byte_reader_skip_unchecked (&reader, 7);
610 GST_LOG_OBJECT (demux, "parsing a script tag");
612 if (!gst_byte_reader_get_uint8 (&reader, &type))
617 gchar *function_name;
620 function_name = FLV_GET_STRING (&reader);
622 GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
624 if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
625 gboolean end_marker = FALSE;
626 GST_DEBUG_OBJECT (demux, "we have a metadata script object");
628 gst_flv_demux_clear_tags (demux);
630 if (!gst_byte_reader_get_uint8 (&reader, &type)) {
631 g_free (function_name);
638 guint32 nb_elems = 0;
641 if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
642 g_free (function_name);
646 /* The number of elements is just a hint, some files have
647 nb_elements == 0 and actually contain items. */
648 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
651 /* fallthrough to read data */
655 while (!end_marker) {
657 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
659 if (G_UNLIKELY (!ok)) {
660 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
667 GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
668 g_free (function_name);
672 gst_flv_demux_push_tags (demux);
675 g_free (function_name);
677 if (demux->times && demux->filepositions) {
680 /* If an index was found, insert associations */
681 num = MIN (demux->times->len, demux->filepositions->len);
682 for (i = 0; i < num; i++) {
683 guint64 time, fileposition;
685 time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
686 fileposition = g_array_index (demux->filepositions, gdouble, i);
687 gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
690 demux->indexed = TRUE;
695 gst_buffer_unmap (buffer, &map);
701 have_group_id (GstFlvDemux * demux)
705 event = gst_pad_get_sticky_event (demux->sinkpad, GST_EVENT_STREAM_START, 0);
707 if (gst_event_parse_group_id (event, &demux->group_id))
708 demux->have_group_id = TRUE;
710 demux->have_group_id = FALSE;
711 gst_event_unref (event);
712 } else if (!demux->have_group_id) {
713 demux->have_group_id = TRUE;
714 demux->group_id = gst_util_group_id_next ();
717 return demux->have_group_id;
721 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
722 guint32 rate, guint32 channels, guint32 width)
724 GstCaps *caps = NULL, *old_caps;
725 gboolean ret = FALSE;
726 guint adjusted_rate = rate;
727 guint adjusted_channels = channels;
733 caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
738 caps = gst_caps_new_simple ("audio/mpeg",
739 "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
740 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
745 GstAudioFormat format;
747 /* Assuming little endian for 0 (aka endianness of the
748 * system on which the file was created) as most people
749 * are probably using little endian machines */
750 format = gst_audio_format_build_integer ((width == 8) ? FALSE : TRUE,
751 G_LITTLE_ENDIAN, width, width);
753 caps = gst_caps_new_simple ("audio/x-raw",
754 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
755 "layout", G_TYPE_STRING, "interleaved", NULL);
761 caps = gst_caps_new_empty_simple ("audio/x-nellymoser");
766 if (!demux->audio_codec_data) {
767 GST_DEBUG_OBJECT (demux, "don't have AAC codec data yet");
772 gst_buffer_map (demux->audio_codec_data, &map, GST_MAP_READ);
774 /* use codec-data to extract and verify samplerate */
778 freq_index = GST_READ_UINT16_BE (map.data);
779 freq_index = (freq_index & 0x0780) >> 7;
781 gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
783 if (adjusted_rate && (rate != adjusted_rate)) {
784 GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
787 adjusted_rate = rate;
791 gst_codec_utils_aac_get_channels (map.data, map.size);
793 if (adjusted_channels && (channels != adjusted_channels)) {
794 GST_LOG_OBJECT (demux, "Ajusting AAC channels %d -> %d", channels,
797 adjusted_channels = channels;
800 gst_buffer_unmap (demux->audio_codec_data, &map);
802 caps = gst_caps_new_simple ("audio/mpeg",
803 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
804 "stream-format", G_TYPE_STRING, "raw", NULL);
808 caps = gst_caps_new_empty_simple ("audio/x-alaw");
811 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
815 GValue streamheader = G_VALUE_INIT;
816 GValue value = G_VALUE_INIT;
818 GstStructure *structure;
822 caps = gst_caps_new_empty_simple ("audio/x-speex");
823 structure = gst_caps_get_structure (caps, 0);
825 GST_DEBUG_OBJECT (demux, "generating speex header");
827 /* Speex decoder expects streamheader to be { [header], [comment] } */
828 g_value_init (&streamheader, GST_TYPE_ARRAY);
831 gst_byte_writer_init_with_size (&w, 80, TRUE);
832 gst_byte_writer_put_data (&w, (guint8 *) "Speex ", 8);
833 gst_byte_writer_put_data (&w, (guint8 *) "1.1.12", 7);
834 gst_byte_writer_fill (&w, 0, 13);
835 gst_byte_writer_put_uint32_le (&w, 1); /* version */
836 gst_byte_writer_put_uint32_le (&w, 80); /* header_size */
837 gst_byte_writer_put_uint32_le (&w, 16000); /* rate */
838 gst_byte_writer_put_uint32_le (&w, 1); /* mode: Wideband */
839 gst_byte_writer_put_uint32_le (&w, 4); /* mode_bitstream_version */
840 gst_byte_writer_put_uint32_le (&w, 1); /* nb_channels: 1 */
841 gst_byte_writer_put_uint32_le (&w, -1); /* bitrate */
842 gst_byte_writer_put_uint32_le (&w, 0x50); /* frame_size */
843 gst_byte_writer_put_uint32_le (&w, 0); /* VBR */
844 gst_byte_writer_put_uint32_le (&w, 1); /* frames_per_packet */
845 gst_byte_writer_put_uint32_le (&w, 0); /* extra_headers */
846 gst_byte_writer_put_uint32_le (&w, 0); /* reserved1 */
847 gst_byte_writer_put_uint32_le (&w, 0); /* reserved2 */
848 g_assert (gst_byte_writer_get_size (&w) == 80);
850 g_value_init (&value, GST_TYPE_BUFFER);
851 g_value_take_boxed (&value, gst_byte_writer_reset_and_get_buffer (&w));
852 gst_value_array_append_value (&streamheader, &value);
853 g_value_unset (&value);
856 g_value_init (&value, GST_TYPE_BUFFER);
857 tags = gst_tag_list_new_empty ();
858 buf = gst_tag_list_to_vorbiscomment_buffer (tags, NULL, 0, "No comments");
859 gst_tag_list_unref (tags);
860 g_value_take_boxed (&value, buf);
861 gst_value_array_append_value (&streamheader, &value);
862 g_value_unset (&value);
864 gst_structure_take_value (structure, "streamheader", &streamheader);
867 adjusted_rate = 16000;
871 GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
875 if (G_UNLIKELY (!caps)) {
876 GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
880 gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
881 "channels", G_TYPE_INT, adjusted_channels, NULL);
883 if (demux->audio_codec_data) {
884 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
885 demux->audio_codec_data, NULL);
888 old_caps = gst_pad_get_current_caps (demux->audio_pad);
891 gst_pad_create_stream_id (demux->audio_pad, GST_ELEMENT_CAST (demux),
894 event = gst_event_new_stream_start (stream_id);
895 if (have_group_id (demux))
896 gst_event_set_group_id (event, demux->group_id);
897 gst_pad_push_event (demux->audio_pad, event);
900 if (!old_caps || !gst_caps_is_equal (old_caps, caps))
901 ret = gst_pad_set_caps (demux->audio_pad, caps);
906 gst_caps_unref (old_caps);
909 if (G_LIKELY (ret)) {
910 /* Store the caps we got from tags */
911 demux->audio_codec_tag = codec_tag;
913 demux->channels = channels;
914 demux->width = width;
917 GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
918 GST_PTR_FORMAT, caps);
920 gst_flv_demux_push_tags (demux);
922 GST_DEBUG_OBJECT (demux->audio_pad, "delayed setting caps");
925 GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
926 GST_PTR_FORMAT, caps);
930 gst_caps_unref (caps);
937 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
941 if (demux->audio_pad)
942 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
944 if (demux->video_pad)
945 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
947 gst_event_unref (event);
953 gst_flv_demux_add_codec_tag (GstFlvDemux * demux, const gchar * tag,
957 GstCaps *caps = gst_pad_get_current_caps (pad);
960 gchar *codec_name = gst_pb_utils_get_codec_description (caps);
963 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
964 tag, codec_name, NULL);
968 gst_caps_unref (caps);
974 gst_flv_demux_push_tags (GstFlvDemux * demux)
976 gst_flv_demux_add_codec_tag (demux, GST_TAG_AUDIO_CODEC, demux->audio_pad);
977 gst_flv_demux_add_codec_tag (demux, GST_TAG_VIDEO_CODEC, demux->video_pad);
979 GST_DEBUG_OBJECT (demux, "pushing %" GST_PTR_FORMAT, demux->taglist);
981 gst_flv_demux_push_src_event (demux,
982 gst_event_new_tag (gst_tag_list_copy (demux->taglist)));
984 #ifdef TIZEN_FEATURE_FLVDEMUX_MODIFICATION
985 GST_DEBUG_OBJECT (demux, "post tag msg %" GST_PTR_FORMAT, demux->taglist);
987 /* post message flv tag (for early recive application) */
988 gst_element_post_message (GST_ELEMENT_CAST (demux),
989 gst_message_new_tag (GST_OBJECT_CAST (demux),
990 gst_tag_list_copy (demux->taglist)));
993 if (demux->audio_pad) {
994 GST_DEBUG_OBJECT (demux->audio_pad, "pushing audio %" GST_PTR_FORMAT,
996 gst_pad_push_event (demux->audio_pad,
997 gst_event_new_tag (gst_tag_list_copy (demux->audio_tags)));
1000 if (demux->video_pad) {
1001 GST_DEBUG_OBJECT (demux->video_pad, "pushing video %" GST_PTR_FORMAT,
1003 gst_pad_push_event (demux->video_pad,
1004 gst_event_new_tag (gst_tag_list_copy (demux->video_tags)));
1009 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 dts, gboolean discont,
1010 guint32 * last, GstClockTime * offset)
1012 gboolean ret = FALSE;
1013 gint32 ddts = dts - *last;
1014 if (!discont && ddts <= -RESYNC_THRESHOLD) {
1015 /* Theoretically, we should use substract the duration of the last buffer,
1016 but this demuxer sends no durations on buffers, not sure if it cannot
1017 know, or just does not care to calculate. */
1018 *offset -= ddts * GST_MSECOND;
1019 GST_WARNING_OBJECT (demux,
1020 "Large dts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
1021 GST_TIME_FORMAT "", ddts, GST_TIME_ARGS (*offset));
1030 static GstFlowReturn
1031 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
1033 GstFlowReturn ret = GST_FLOW_OK;
1034 guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
1035 guint32 codec_data = 0, pts_ext = 0;
1041 GST_LOG_OBJECT (demux, "parsing an audio tag");
1043 if (G_UNLIKELY (!demux->audio_pad && demux->no_more_pads)) {
1044 #ifndef GST_DISABLE_DEBUG
1045 if (G_UNLIKELY (!demux->no_audio_warned)) {
1046 GST_WARNING_OBJECT (demux,
1047 "Signaled no-more-pads already but had no audio pad -- ignoring");
1048 demux->no_audio_warned = TRUE;
1054 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1057 /* Error out on tags with too small headers */
1058 if (gst_buffer_get_size (buffer) < 11) {
1059 GST_ERROR_OBJECT (demux, "Too small tag size (%" G_GSIZE_FORMAT ")",
1060 gst_buffer_get_size (buffer));
1061 return GST_FLOW_ERROR;
1064 gst_buffer_map (buffer, &map, GST_MAP_READ);
1067 /* Grab information about audio tag */
1068 pts = GST_READ_UINT24_BE (data);
1069 /* read the pts extension to 32 bits integer */
1070 pts_ext = GST_READ_UINT8 (data + 3);
1072 pts |= pts_ext << 24;
1074 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1075 data[2], data[3], pts);
1077 /* Skip the stream id and go directly to the flags */
1078 flags = GST_READ_UINT8 (data + 7);
1080 /* Silently skip buffers with no data */
1093 if ((flags & 0x0C) == 0x0C) {
1095 } else if ((flags & 0x0C) == 0x08) {
1097 } else if ((flags & 0x0C) == 0x04) {
1101 codec_tag = flags >> 4;
1102 if (codec_tag == 10) { /* AAC has an extra byte for packet type */
1108 /* codec tags with special rates */
1109 if (codec_tag == 5 || codec_tag == 14 || codec_tag == 7 || codec_tag == 8)
1111 else if ((codec_tag == 4) || (codec_tag == 11))
1114 GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
1115 "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
1118 if (codec_tag == 10) {
1119 guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
1121 switch (aac_packet_type) {
1124 /* AudioSpecificConfig data */
1125 GST_LOG_OBJECT (demux, "got an AAC codec data packet");
1126 if (demux->audio_codec_data) {
1127 gst_buffer_unref (demux->audio_codec_data);
1129 demux->audio_codec_data =
1130 gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1131 7 + codec_data, demux->tag_data_size - codec_data);
1133 /* Use that buffer data in the caps */
1134 if (demux->audio_pad)
1135 gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1140 if (!demux->audio_codec_data) {
1141 GST_ERROR_OBJECT (demux, "got AAC audio packet before codec data");
1145 /* AAC raw packet */
1146 GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
1149 GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
1154 /* If we don't have our audio pad created, then create it. */
1155 if (G_UNLIKELY (!demux->audio_pad)) {
1157 gst_pad_new_from_template (gst_element_class_get_pad_template
1158 (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
1159 if (G_UNLIKELY (!demux->audio_pad)) {
1160 GST_WARNING_OBJECT (demux, "failed creating audio pad");
1161 ret = GST_FLOW_ERROR;
1165 /* Set functions on the pad */
1166 gst_pad_set_query_function (demux->audio_pad,
1167 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1168 gst_pad_set_event_function (demux->audio_pad,
1169 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1171 gst_pad_use_fixed_caps (demux->audio_pad);
1173 /* Make it active */
1174 gst_pad_set_active (demux->audio_pad, TRUE);
1176 /* Negotiate caps */
1177 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1179 gst_object_unref (demux->audio_pad);
1180 demux->audio_pad = NULL;
1181 ret = GST_FLOW_ERROR;
1184 #ifndef GST_DISABLE_GST_DEBUG
1188 caps = gst_pad_get_current_caps (demux->audio_pad);
1189 GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
1192 gst_caps_unref (caps);
1196 /* We need to set caps before adding */
1197 gst_element_add_pad (GST_ELEMENT (demux),
1198 gst_object_ref (demux->audio_pad));
1199 gst_flow_combiner_add_pad (demux->flowcombiner, demux->audio_pad);
1201 /* We only emit no more pads when we have audio and video. Indeed we can
1202 * not trust the FLV header to tell us if there will be only audio or
1203 * only video and we would just break discovery of some files */
1204 if (demux->audio_pad && demux->video_pad) {
1205 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1206 gst_element_no_more_pads (GST_ELEMENT (demux));
1207 demux->no_more_pads = TRUE;
1211 /* Check if caps have changed */
1212 if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
1213 codec_tag != demux->audio_codec_tag || width != demux->width)) {
1214 GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
1216 gst_buffer_replace (&demux->audio_codec_data, NULL);
1218 /* Negotiate caps */
1219 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
1221 ret = GST_FLOW_ERROR;
1226 /* Check if we have anything to push */
1227 if (demux->tag_data_size <= codec_data) {
1228 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1232 /* Create buffer from pad */
1233 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1234 7 + codec_data, demux->tag_data_size - codec_data);
1236 /* detect (and deem to be resyncs) large pts gaps */
1237 if (gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
1238 &demux->last_audio_pts, &demux->audio_time_offset)) {
1239 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
1242 /* Fill buffer with data */
1243 GST_BUFFER_PTS (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
1244 GST_BUFFER_DTS (outbuf) = GST_BUFFER_PTS (outbuf);
1245 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1246 GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
1247 GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
1249 if (demux->duration == GST_CLOCK_TIME_NONE ||
1250 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1251 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1253 /* Only add audio frames to the index if we have no video,
1254 * and if the index is not yet complete */
1255 if (!demux->has_video && !demux->indexed) {
1256 gst_flv_demux_parse_and_add_index_entry (demux,
1257 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
1260 if (G_UNLIKELY (demux->audio_need_discont)) {
1261 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1262 demux->audio_need_discont = FALSE;
1265 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1267 /* Do we need a newsegment event ? */
1268 if (G_UNLIKELY (demux->audio_need_segment)) {
1269 if (!demux->new_seg_event) {
1270 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1271 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1272 GST_TIME_ARGS (demux->segment.position),
1273 GST_TIME_ARGS (demux->segment.stop));
1274 demux->segment.start = demux->segment.time = demux->segment.position;
1275 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1277 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1280 gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1282 demux->audio_need_segment = FALSE;
1285 GST_LOG_OBJECT (demux,
1286 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1287 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1288 gst_buffer_get_size (outbuf),
1289 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1290 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1292 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1293 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1295 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1296 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1299 if (G_UNLIKELY (!demux->no_more_pads
1300 && (GST_CLOCK_DIFF (demux->audio_start,
1301 GST_BUFFER_TIMESTAMP (outbuf)) > NO_MORE_PADS_THRESHOLD))) {
1302 GST_DEBUG_OBJECT (demux,
1303 "Signalling no-more-pads because no video stream was found"
1304 " after 6 seconds of audio");
1305 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1306 demux->no_more_pads = TRUE;
1309 /* Push downstream */
1310 ret = gst_pad_push (demux->audio_pad, outbuf);
1312 if (G_UNLIKELY (ret != GST_FLOW_OK) &&
1313 demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1314 demux->segment.position > demux->segment.stop) {
1315 /* In reverse playback we can get a GST_FLOW_EOS when
1316 * we are at the end of the segment, so we just need to jump
1317 * back to the previous section. */
1318 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1319 demux->audio_done = TRUE;
1324 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner,
1325 demux->audio_pad, ret);
1328 gst_buffer_unmap (buffer, &map);
1334 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1336 gboolean ret = FALSE;
1337 GstCaps *caps = NULL, *old_caps;
1341 /* Generate caps for that pad */
1342 switch (codec_tag) {
1345 gst_caps_new_simple ("video/x-flash-video", "flvversion", G_TYPE_INT,
1349 caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1352 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1355 caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1358 if (!demux->video_codec_data) {
1359 GST_DEBUG_OBJECT (demux, "don't have h264 codec data yet");
1364 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1367 /* The following two are non-standard but apparently used, see in ffmpeg
1368 * https://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/flvdec.c;h=2bf1e059e1cbeeb79e4af9542da23f4560e1cf59;hb=b18d6c58000beed872d6bb1fe7d0fbe75ae26aef#l254
1369 * https://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavformat/flvdec.c;h=2bf1e059e1cbeeb79e4af9542da23f4560e1cf59;hb=b18d6c58000beed872d6bb1fe7d0fbe75ae26aef#l282
1372 caps = gst_caps_new_empty_simple ("video/x-h263");
1376 gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
1377 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
1380 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1383 if (G_UNLIKELY (!caps)) {
1384 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1388 if (demux->got_par) {
1389 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1390 demux->par_x, demux->par_y, NULL);
1393 if (G_LIKELY (demux->w)) {
1394 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1397 if (G_LIKELY (demux->h)) {
1398 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1401 if (G_LIKELY (demux->framerate)) {
1402 gint num = 0, den = 0;
1404 gst_video_guess_framerate (GST_SECOND / demux->framerate, &num, &den);
1405 GST_DEBUG_OBJECT (demux->video_pad,
1406 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1409 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1412 if (demux->video_codec_data) {
1413 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1414 demux->video_codec_data, NULL);
1417 old_caps = gst_pad_get_current_caps (demux->video_pad);
1420 gst_pad_create_stream_id (demux->video_pad, GST_ELEMENT_CAST (demux),
1422 event = gst_event_new_stream_start (stream_id);
1425 if (have_group_id (demux))
1426 gst_event_set_group_id (event, demux->group_id);
1427 gst_pad_push_event (demux->video_pad, event);
1430 if (!old_caps || !gst_caps_is_equal (old_caps, caps))
1431 ret = gst_pad_set_caps (demux->video_pad, caps);
1436 gst_caps_unref (old_caps);
1439 if (G_LIKELY (ret)) {
1440 /* Store the caps we have set */
1441 demux->video_codec_tag = codec_tag;
1444 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1445 GST_PTR_FORMAT, caps);
1447 gst_flv_demux_push_tags (demux);
1449 GST_DEBUG_OBJECT (demux->video_pad, "delayed setting caps");
1452 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1453 GST_PTR_FORMAT, caps);
1457 gst_caps_unref (caps);
1463 static GstFlowReturn
1464 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1466 GstFlowReturn ret = GST_FLOW_OK;
1467 guint32 dts = 0, codec_data = 1, dts_ext = 0;
1469 gboolean keyframe = FALSE;
1470 guint8 flags = 0, codec_tag = 0;
1475 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1478 GST_LOG_OBJECT (demux, "parsing a video tag");
1481 (!demux->video_pad && demux->no_more_pads) {
1482 #ifndef GST_DISABLE_DEBUG
1484 (!demux->no_video_warned) {
1485 GST_WARNING_OBJECT (demux,
1486 "Signaled no-more-pads already but had no video pad -- ignoring");
1487 demux->no_video_warned = TRUE;
1493 if (gst_buffer_get_size (buffer) < 12) {
1494 GST_ERROR_OBJECT (demux, "Too small tag size");
1495 return GST_FLOW_ERROR;
1498 gst_buffer_map (buffer, &map, GST_MAP_READ);
1501 /* Grab information about video tag */
1502 dts = GST_READ_UINT24_BE (data);
1503 /* read the dts extension to 32 bits integer */
1504 dts_ext = GST_READ_UINT8 (data + 3);
1506 dts |= dts_ext << 24;
1508 GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1509 data[2], data[3], dts);
1511 /* Skip the stream id and go directly to the flags */
1512 flags = GST_READ_UINT8 (data + 7);
1515 if ((flags >> 4) == 1) {
1519 codec_tag = flags & 0x0F;
1520 if (codec_tag == 4 || codec_tag == 5) {
1522 } else if (codec_tag == 7) {
1525 cts = GST_READ_UINT24_BE (data + 9);
1526 cts = (cts + 0xff800000) ^ 0xff800000;
1528 if (cts < 0 && ABS (cts) > dts) {
1529 GST_ERROR_OBJECT (demux, "Detected a negative composition time offset "
1530 "'%d' that would lead to negative PTS, fixing", cts);
1531 cts += ABS (cts) - dts;
1534 GST_LOG_OBJECT (demux, "got cts %d", cts);
1537 GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1538 "(flags %02X)", codec_tag, keyframe, flags);
1540 if (codec_tag == 7) {
1541 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1543 switch (avc_packet_type) {
1546 if (demux->tag_data_size < codec_data) {
1547 GST_ERROR_OBJECT (demux, "Got invalid H.264 codec, ignoring.");
1551 /* AVCDecoderConfigurationRecord data */
1552 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1553 if (demux->video_codec_data) {
1554 gst_buffer_unref (demux->video_codec_data);
1556 demux->video_codec_data = gst_buffer_copy_region (buffer,
1557 GST_BUFFER_COPY_MEMORY, 7 + codec_data,
1558 demux->tag_data_size - codec_data);;
1559 /* Use that buffer data in the caps */
1560 if (demux->video_pad)
1561 gst_flv_demux_video_negotiate (demux, codec_tag);
1565 /* H.264 NALU packet */
1566 if (!demux->video_codec_data) {
1567 GST_ERROR_OBJECT (demux, "got H.264 video packet before codec data");
1571 GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1574 GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1579 /* If we don't have our video pad created, then create it. */
1580 if (G_UNLIKELY (!demux->video_pad)) {
1582 gst_pad_new_from_template (gst_element_class_get_pad_template
1583 (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1584 if (G_UNLIKELY (!demux->video_pad)) {
1585 GST_WARNING_OBJECT (demux, "failed creating video pad");
1586 ret = GST_FLOW_ERROR;
1590 /* Set functions on the pad */
1591 gst_pad_set_query_function (demux->video_pad,
1592 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1593 gst_pad_set_event_function (demux->video_pad,
1594 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1596 gst_pad_use_fixed_caps (demux->video_pad);
1598 /* Make it active */
1599 gst_pad_set_active (demux->video_pad, TRUE);
1601 /* Needs to be active before setting caps */
1602 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1603 gst_object_unref (demux->video_pad);
1604 demux->video_pad = NULL;
1605 ret = GST_FLOW_ERROR;
1609 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1610 * metadata tag that would come later and trigger a caps change */
1611 demux->got_par = FALSE;
1613 #ifndef GST_DISABLE_GST_DEBUG
1617 caps = gst_pad_get_current_caps (demux->video_pad);
1618 GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1621 gst_caps_unref (caps);
1625 /* We need to set caps before adding */
1626 gst_element_add_pad (GST_ELEMENT (demux),
1627 gst_object_ref (demux->video_pad));
1628 gst_flow_combiner_add_pad (demux->flowcombiner, demux->video_pad);
1630 /* We only emit no more pads when we have audio and video. Indeed we can
1631 * not trust the FLV header to tell us if there will be only audio or
1632 * only video and we would just break discovery of some files */
1633 if (demux->audio_pad && demux->video_pad) {
1634 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1635 gst_element_no_more_pads (GST_ELEMENT (demux));
1636 demux->no_more_pads = TRUE;
1640 /* Check if caps have changed */
1641 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1642 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1643 gst_buffer_replace (&demux->video_codec_data, NULL);
1645 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1646 ret = GST_FLOW_ERROR;
1650 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1651 * metadata tag that would come later and trigger a caps change */
1652 demux->got_par = FALSE;
1655 /* Check if we have anything to push */
1656 if (demux->tag_data_size <= codec_data) {
1657 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1661 /* Create buffer from pad */
1662 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1663 7 + codec_data, demux->tag_data_size - codec_data);
1665 /* detect (and deem to be resyncs) large dts gaps */
1666 if (gst_flv_demux_update_resync (demux, dts, demux->video_need_discont,
1667 &demux->last_video_dts, &demux->video_time_offset)) {
1668 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
1671 /* Fill buffer with data */
1672 GST_LOG_OBJECT (demux, "dts %u pts %u cts %d", dts, dts + cts, cts);
1674 GST_BUFFER_PTS (outbuf) =
1675 (dts + cts) * GST_MSECOND + demux->video_time_offset;
1676 GST_BUFFER_DTS (outbuf) = dts * GST_MSECOND + demux->video_time_offset;
1677 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1678 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1679 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1681 if (demux->duration == GST_CLOCK_TIME_NONE ||
1682 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1683 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1686 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1688 if (!demux->indexed) {
1689 gst_flv_demux_parse_and_add_index_entry (demux,
1690 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1693 if (G_UNLIKELY (demux->video_need_discont)) {
1694 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1695 demux->video_need_discont = FALSE;
1698 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1700 /* Do we need a newsegment event ? */
1701 if (G_UNLIKELY (demux->video_need_segment)) {
1702 if (!demux->new_seg_event) {
1703 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1704 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1705 GST_TIME_ARGS (demux->segment.position),
1706 GST_TIME_ARGS (demux->segment.stop));
1707 demux->segment.start = demux->segment.time = demux->segment.position;
1708 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1710 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1713 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1715 demux->video_need_segment = FALSE;
1718 GST_LOG_OBJECT (demux,
1719 "pushing %" G_GSIZE_FORMAT " bytes buffer at dts %" GST_TIME_FORMAT
1720 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1721 ", keyframe (%d)", gst_buffer_get_size (outbuf),
1722 GST_TIME_ARGS (GST_BUFFER_DTS (outbuf)),
1723 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1726 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1727 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1729 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1730 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1733 if (G_UNLIKELY (!demux->no_more_pads
1734 && (GST_CLOCK_DIFF (demux->video_start,
1735 GST_BUFFER_TIMESTAMP (outbuf)) > NO_MORE_PADS_THRESHOLD))) {
1736 GST_DEBUG_OBJECT (demux,
1737 "Signalling no-more-pads because no audio stream was found"
1738 " after 6 seconds of video");
1739 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1740 demux->no_more_pads = TRUE;
1743 /* Push downstream */
1744 ret = gst_pad_push (demux->video_pad, outbuf);
1746 if (G_UNLIKELY (ret != GST_FLOW_OK) &&
1747 demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1748 demux->segment.position > demux->segment.stop) {
1749 /* In reverse playback we can get a GST_FLOW_EOS when
1750 * we are at the end of the segment, so we just need to jump
1751 * back to the previous section. */
1752 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1753 demux->video_done = TRUE;
1758 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner,
1759 demux->video_pad, ret);
1762 gst_buffer_unmap (buffer, &map);
1767 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1768 GstBuffer * buffer, size_t * tag_size)
1770 guint32 dts = 0, dts_ext = 0;
1771 guint32 tag_data_size;
1773 gboolean keyframe = TRUE;
1774 GstClockTime ret = GST_CLOCK_TIME_NONE;
1779 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1780 GST_CLOCK_TIME_NONE);
1782 gst_buffer_map (buffer, &map, GST_MAP_READ);
1788 if (type != 9 && type != 8 && type != 18) {
1789 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1794 demux->has_video = TRUE;
1796 demux->has_audio = TRUE;
1798 tag_data_size = GST_READ_UINT24_BE (data + 1);
1800 if (size >= tag_data_size + 11 + 4) {
1801 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1802 GST_WARNING_OBJECT (demux, "Invalid tag size");
1808 *tag_size = tag_data_size + 11 + 4;
1812 GST_LOG_OBJECT (demux, "dts bytes %02X %02X %02X %02X", data[0], data[1],
1815 /* Grab timestamp of tag tag */
1816 dts = GST_READ_UINT24_BE (data);
1817 /* read the dts extension to 32 bits integer */
1818 dts_ext = GST_READ_UINT8 (data + 3);
1820 dts |= dts_ext << 24;
1825 keyframe = ((data[0] >> 4) == 1);
1828 ret = dts * GST_MSECOND;
1829 GST_LOG_OBJECT (demux, "dts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1831 if (index && !demux->indexed && (type == 9 || (type == 8
1832 && !demux->has_video))) {
1833 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1837 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1838 demux->duration = ret;
1841 gst_buffer_unmap (buffer, &map);
1845 static GstFlowReturn
1846 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1848 GstFlowReturn ret = GST_FLOW_OK;
1849 guint8 tag_type = 0;
1852 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1854 gst_buffer_map (buffer, &map, GST_MAP_READ);
1856 tag_type = map.data[0];
1858 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1859 * 4 bytes of previous tag size */
1860 demux->tag_data_size = GST_READ_UINT24_BE (map.data + 1);
1861 demux->tag_size = demux->tag_data_size + 11;
1863 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1864 demux->tag_data_size);
1866 gst_buffer_unmap (buffer, &map);
1870 demux->state = FLV_STATE_TAG_VIDEO;
1871 demux->has_video = TRUE;
1874 demux->state = FLV_STATE_TAG_AUDIO;
1875 demux->has_audio = TRUE;
1878 demux->state = FLV_STATE_TAG_SCRIPT;
1881 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1882 demux->state = FLV_STATE_SKIP;
1888 static GstFlowReturn
1889 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1891 GstFlowReturn ret = GST_FLOW_OK;
1894 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1896 gst_buffer_map (buffer, &map, GST_MAP_READ);
1898 /* Check for the FLV tag */
1899 if (map.data[0] == 'F' && map.data[1] == 'L' && map.data[2] == 'V') {
1900 GST_DEBUG_OBJECT (demux, "FLV header detected");
1902 if (G_UNLIKELY (demux->strict)) {
1903 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1909 if (map.data[3] == '1') {
1910 GST_DEBUG_OBJECT (demux, "FLV version 1 detected");
1912 if (G_UNLIKELY (demux->strict)) {
1913 GST_WARNING_OBJECT (demux, "invalid header version detected");
1920 /* Now look at audio/video flags */
1922 guint8 flags = map.data[4];
1924 demux->has_video = demux->has_audio = FALSE;
1927 GST_DEBUG_OBJECT (demux, "there is a video stream");
1928 demux->has_video = TRUE;
1931 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1932 demux->has_audio = TRUE;
1936 /* do a one-time seekability check */
1937 gst_flv_demux_check_seekability (demux);
1939 /* We don't care about the rest */
1940 demux->need_header = FALSE;
1943 gst_buffer_unmap (buffer, &map);
1949 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1951 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1953 gst_adapter_clear (demux->adapter);
1955 demux->audio_need_discont = TRUE;
1956 demux->video_need_discont = TRUE;
1958 demux->flushing = FALSE;
1960 /* Only in push mode and if we're not during a seek */
1961 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1962 /* After a flush we expect a tag_type */
1963 demux->state = FLV_STATE_TAG_TYPE;
1964 /* We reset the offset and will get one from first push */
1970 gst_flv_demux_cleanup (GstFlvDemux * demux)
1972 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1974 demux->state = FLV_STATE_HEADER;
1976 demux->have_group_id = FALSE;
1977 demux->group_id = G_MAXUINT;
1979 demux->flushing = FALSE;
1980 demux->need_header = TRUE;
1981 demux->audio_need_segment = TRUE;
1982 demux->video_need_segment = TRUE;
1983 demux->audio_need_discont = TRUE;
1984 demux->video_need_discont = TRUE;
1986 demux->has_audio = FALSE;
1987 demux->has_video = FALSE;
1988 demux->got_par = FALSE;
1990 demux->indexed = FALSE;
1991 demux->upstream_seekable = FALSE;
1992 demux->file_size = 0;
1994 demux->index_max_pos = 0;
1995 demux->index_max_time = 0;
1997 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1998 demux->last_audio_pts = demux->last_video_dts = 0;
1999 demux->audio_time_offset = demux->video_time_offset = 0;
2001 demux->no_more_pads = FALSE;
2003 #ifndef GST_DISABLE_DEBUG
2004 demux->no_audio_warned = FALSE;
2005 demux->no_video_warned = FALSE;
2008 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
2010 demux->w = demux->h = 0;
2011 demux->framerate = 0.0;
2012 demux->par_x = demux->par_y = 1;
2013 demux->video_offset = 0;
2014 demux->audio_offset = 0;
2015 demux->offset = demux->cur_tag_offset = 0;
2016 demux->tag_size = demux->tag_data_size = 0;
2017 demux->duration = GST_CLOCK_TIME_NONE;
2019 if (demux->new_seg_event) {
2020 gst_event_unref (demux->new_seg_event);
2021 demux->new_seg_event = NULL;
2024 gst_adapter_clear (demux->adapter);
2026 if (demux->audio_codec_data) {
2027 gst_buffer_unref (demux->audio_codec_data);
2028 demux->audio_codec_data = NULL;
2031 if (demux->video_codec_data) {
2032 gst_buffer_unref (demux->video_codec_data);
2033 demux->video_codec_data = NULL;
2036 if (demux->audio_pad) {
2037 gst_flow_combiner_remove_pad (demux->flowcombiner, demux->audio_pad);
2038 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
2039 gst_object_unref (demux->audio_pad);
2040 demux->audio_pad = NULL;
2043 if (demux->video_pad) {
2044 gst_flow_combiner_remove_pad (demux->flowcombiner, demux->video_pad);
2045 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
2046 gst_object_unref (demux->video_pad);
2047 demux->video_pad = NULL;
2051 g_array_free (demux->times, TRUE);
2052 demux->times = NULL;
2055 if (demux->filepositions) {
2056 g_array_free (demux->filepositions, TRUE);
2057 demux->filepositions = NULL;
2060 gst_flv_demux_clear_tags (demux);
2064 * Create and push a flushing seek event upstream
2067 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
2072 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
2075 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
2076 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
2077 GST_SEEK_TYPE_NONE, -1);
2079 res = gst_pad_push_event (demux->sinkpad, event);
2082 demux->offset = offset;
2086 static GstFlowReturn
2087 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
2089 GstFlowReturn ret = GST_FLOW_OK;
2090 GstFlvDemux *demux = NULL;
2092 demux = GST_FLV_DEMUX (parent);
2094 GST_LOG_OBJECT (demux,
2095 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
2096 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
2097 GST_BUFFER_OFFSET (buffer));
2099 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
2100 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
2101 demux->state = FLV_STATE_HEADER;
2105 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
2106 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
2107 demux->offset = GST_BUFFER_OFFSET (buffer);
2110 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
2111 GST_DEBUG_OBJECT (demux, "Discontinuity");
2112 gst_adapter_clear (demux->adapter);
2115 gst_adapter_push (demux->adapter, buffer);
2117 if (demux->seeking) {
2118 demux->state = FLV_STATE_SEEK;
2119 GST_OBJECT_LOCK (demux);
2120 demux->seeking = FALSE;
2121 GST_OBJECT_UNLOCK (demux);
2125 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2126 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
2130 if (G_UNLIKELY (demux->flushing)) {
2131 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
2132 ret = GST_FLOW_FLUSHING;
2136 switch (demux->state) {
2137 case FLV_STATE_HEADER:
2139 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
2142 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
2144 ret = gst_flv_demux_parse_header (demux, buffer);
2146 gst_buffer_unref (buffer);
2147 demux->offset += FLV_HEADER_SIZE;
2149 demux->state = FLV_STATE_TAG_TYPE;
2155 case FLV_STATE_TAG_TYPE:
2157 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
2160 /* Remember the tag offset in bytes */
2161 demux->cur_tag_offset = demux->offset;
2163 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
2165 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2167 gst_buffer_unref (buffer);
2168 demux->offset += FLV_TAG_TYPE_SIZE;
2170 /* last tag is not an index => no index/don't know where the index is
2171 * seek back to the beginning */
2172 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
2180 case FLV_STATE_TAG_VIDEO:
2182 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2185 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2187 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2189 gst_buffer_unref (buffer);
2190 demux->offset += demux->tag_size;
2192 demux->state = FLV_STATE_TAG_TYPE;
2198 case FLV_STATE_TAG_AUDIO:
2200 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2203 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2205 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2207 gst_buffer_unref (buffer);
2208 demux->offset += demux->tag_size;
2210 demux->state = FLV_STATE_TAG_TYPE;
2216 case FLV_STATE_TAG_SCRIPT:
2218 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2221 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
2223 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2225 gst_buffer_unref (buffer);
2226 demux->offset += demux->tag_size;
2228 demux->state = FLV_STATE_TAG_TYPE;
2230 /* if there's a seek event we're here for the index so if we don't have it
2231 * we seek back to the beginning */
2232 if (demux->seek_event) {
2234 demux->state = FLV_STATE_SEEK;
2244 case FLV_STATE_SEEK:
2250 if (!demux->indexed) {
2251 if (demux->offset == demux->file_size - sizeof (guint32)) {
2252 guint64 seek_offset;
2255 data = gst_adapter_take (demux->adapter, 4);
2259 seek_offset = demux->file_size - sizeof (guint32) -
2260 GST_READ_UINT32_BE (data);
2263 GST_INFO_OBJECT (demux,
2264 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
2266 demux->state = FLV_STATE_TAG_TYPE;
2267 flv_demux_seek_to_offset (demux, seek_offset);
2273 GST_OBJECT_LOCK (demux);
2274 event = demux->seek_event;
2275 demux->seek_event = NULL;
2276 GST_OBJECT_UNLOCK (demux);
2278 /* calculate and perform seek */
2279 if (!flv_demux_handle_seek_push (demux, event))
2282 gst_event_unref (event);
2283 demux->state = FLV_STATE_TAG_TYPE;
2286 case FLV_STATE_SKIP:
2287 /* Skip unknown tags (set in _parse_tag_type()) */
2288 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
2289 gst_adapter_flush (demux->adapter, demux->tag_size);
2290 demux->offset += demux->tag_size;
2291 demux->state = FLV_STATE_TAG_TYPE;
2297 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
2306 GST_OBJECT_LOCK (demux);
2307 demux->seeking = FALSE;
2308 gst_event_unref (demux->seek_event);
2309 demux->seek_event = NULL;
2310 GST_OBJECT_UNLOCK (demux);
2311 GST_WARNING_OBJECT (demux,
2312 "failed to find an index, seeking back to beginning");
2313 flv_demux_seek_to_offset (demux, 0);
2318 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2319 return GST_FLOW_ERROR;
2324 static GstFlowReturn
2325 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2326 guint size, GstBuffer ** buffer)
2330 ret = gst_pad_pull_range (pad, offset, size, buffer);
2331 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2332 GST_WARNING_OBJECT (demux,
2333 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2334 size, offset, gst_flow_get_name (ret));
2339 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2340 GST_WARNING_OBJECT (demux,
2341 "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
2342 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
2343 gst_buffer_unref (*buffer);
2352 static GstFlowReturn
2353 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2355 GstBuffer *buffer = NULL;
2356 GstFlowReturn ret = GST_FLOW_OK;
2358 /* Store tag offset */
2359 demux->cur_tag_offset = demux->offset;
2361 /* Get the first 4 bytes to identify tag type and size */
2362 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2363 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2366 /* Identify tag type */
2367 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2369 gst_buffer_unref (buffer);
2371 if (G_UNLIKELY (ret != GST_FLOW_OK))
2374 /* Jump over tag type + size */
2375 demux->offset += FLV_TAG_TYPE_SIZE;
2377 /* Pull the whole tag */
2379 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2380 demux->tag_size, &buffer)) != GST_FLOW_OK))
2383 switch (demux->state) {
2384 case FLV_STATE_TAG_VIDEO:
2385 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2387 case FLV_STATE_TAG_AUDIO:
2388 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2390 case FLV_STATE_TAG_SCRIPT:
2391 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2394 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2397 gst_buffer_unref (buffer);
2399 /* Jump over that part we've just parsed */
2400 demux->offset += demux->tag_size;
2402 /* Make sure we reinitialize the tag size */
2403 demux->tag_size = 0;
2405 /* Ready for the next tag */
2406 demux->state = FLV_STATE_TAG_TYPE;
2408 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2409 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2410 "neither video nor audio are linked");
2417 static GstFlowReturn
2418 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2420 GstBuffer *buffer = NULL;
2421 GstFlowReturn ret = GST_FLOW_OK;
2423 /* Get the first 9 bytes */
2424 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2425 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2428 ret = gst_flv_demux_parse_header (demux, buffer);
2430 gst_buffer_unref (buffer);
2432 /* Jump over the header now */
2433 demux->offset += FLV_HEADER_SIZE;
2434 demux->state = FLV_STATE_TAG_TYPE;
2441 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2444 demux->offset = offset;
2446 /* Tell all the stream we moved to a different position (discont) */
2447 demux->audio_need_discont = TRUE;
2448 demux->video_need_discont = TRUE;
2450 /* next section setup */
2451 demux->from_offset = -1;
2452 demux->audio_done = demux->video_done = FALSE;
2453 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2456 demux->from_offset = -1;
2457 demux->to_offset = G_MAXINT64;
2460 /* If we seeked at the beginning of the file parse the header again */
2461 if (G_UNLIKELY (!demux->offset)) {
2462 demux->state = FLV_STATE_HEADER;
2463 } else { /* or parse a tag */
2464 demux->state = FLV_STATE_TAG_TYPE;
2468 static GstFlowReturn
2469 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2471 GstFlowReturn ret = GST_FLOW_EOS;
2473 GstIndexEntry *entry = NULL;
2475 GST_DEBUG_OBJECT (demux,
2476 "terminated section started at offset %" G_GINT64_FORMAT,
2477 demux->from_offset);
2479 /* we are done if we got all audio and video */
2480 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2481 demux->audio_first_ts < demux->segment.start) &&
2482 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2483 demux->video_first_ts < demux->segment.start))
2486 if (demux->from_offset <= 0)
2489 GST_DEBUG_OBJECT (demux, "locating previous position");
2491 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2493 /* locate index entry before previous start position */
2495 entry = gst_index_get_assoc_entry (index, demux->index_id,
2496 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2497 GST_FORMAT_BYTES, demux->from_offset - 1);
2500 gint64 bytes = 0, time = 0;
2502 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2503 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2505 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2506 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2507 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2509 /* setup for next section */
2510 demux->to_offset = demux->from_offset;
2511 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2515 gst_object_unref (index);
2522 static GstFlowReturn
2523 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2529 GstClockTime tag_time;
2530 GstFlowReturn ret = GST_FLOW_OK;
2532 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2535 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2536 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2538 old_offset = demux->offset;
2539 demux->offset = pos;
2542 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2543 12, &buffer)) == GST_FLOW_OK) {
2545 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2547 gst_buffer_unref (buffer);
2550 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2553 demux->offset += tag_size;
2556 if (ret == GST_FLOW_EOS) {
2557 /* file ran out, so mark we have complete index */
2558 demux->indexed = TRUE;
2563 demux->offset = old_offset;
2569 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2571 gint64 ret = 0, offset;
2572 size_t tag_size, size;
2573 GstBuffer *buffer = NULL;
2576 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2580 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2581 if (G_UNLIKELY (offset < 4))
2585 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2589 gst_buffer_map (buffer, &map, GST_MAP_READ);
2590 tag_size = GST_READ_UINT32_BE (map.data);
2591 gst_buffer_unmap (buffer, &map);
2592 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2593 gst_buffer_unref (buffer);
2596 if (G_UNLIKELY (offset < tag_size))
2600 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2604 /* a consistency check */
2605 gst_buffer_map (buffer, &map, GST_MAP_READ);
2606 size = GST_READ_UINT24_BE (map.data + 1);
2607 if (size != tag_size - 11) {
2608 gst_buffer_unmap (buffer, &map);
2609 GST_DEBUG_OBJECT (demux,
2610 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2611 ", corrupt or truncated file", size, tag_size - 11);
2615 /* try to update duration with timestamp in any case */
2616 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2618 /* maybe get some more metadata */
2619 if (map.data[0] == 18) {
2620 gst_buffer_unmap (buffer, &map);
2621 gst_buffer_unref (buffer);
2623 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2625 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2627 gst_flv_demux_parse_tag_script (demux, buffer);
2629 gst_buffer_unmap (buffer, &map);
2634 gst_buffer_unref (buffer);
2640 gst_flv_demux_loop (GstPad * pad)
2642 GstFlvDemux *demux = NULL;
2643 GstFlowReturn ret = GST_FLOW_OK;
2645 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2648 switch (demux->state) {
2649 case FLV_STATE_TAG_TYPE:
2650 if (demux->from_offset == -1)
2651 demux->from_offset = demux->offset;
2652 ret = gst_flv_demux_pull_tag (pad, demux);
2653 /* if we have seen real data, we probably passed a possible metadata
2654 * header located at start. So if we do not yet have an index,
2655 * try to pick up metadata (index, duration) at the end */
2656 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2657 (demux->has_video || demux->has_audio)))
2658 demux->file_size = gst_flv_demux_get_metadata (demux);
2660 case FLV_STATE_DONE:
2663 case FLV_STATE_SEEK:
2664 /* seek issued with insufficient index;
2665 * scan for index in task thread from current maximum offset to
2666 * desired time and then perform seek */
2667 /* TODO maybe some buffering message or so to indicate scan progress */
2668 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2670 if (ret != GST_FLOW_OK)
2672 /* position and state arranged by seek,
2673 * also unrefs event */
2674 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2675 demux->seek_event = NULL;
2678 ret = gst_flv_demux_pull_header (pad, demux);
2679 /* index scans start after header */
2680 demux->index_max_pos = demux->offset;
2684 if (demux->segment.rate < 0.0) {
2685 /* check end of section */
2686 if ((gint64) demux->offset >= demux->to_offset ||
2687 demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2688 (demux->audio_done && demux->video_done))
2689 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2691 /* check EOS condition */
2692 if ((demux->segment.stop != -1) &&
2693 (demux->segment.position >= demux->segment.stop)) {
2698 /* pause if something went wrong or at end */
2699 if (G_UNLIKELY (ret != GST_FLOW_OK) && !(ret == GST_FLOW_NOT_LINKED
2700 && !demux->no_more_pads))
2703 gst_object_unref (demux);
2709 const gchar *reason = gst_flow_get_name (ret);
2711 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2712 gst_pad_pause_task (pad);
2714 if (ret == GST_FLOW_EOS) {
2715 /* handle end-of-stream/segment */
2716 /* so align our position with the end of it, if there is one
2717 * this ensures a subsequent will arrive at correct base/acc time */
2718 if (demux->segment.rate > 0.0 &&
2719 GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2720 demux->segment.position = demux->segment.stop;
2721 else if (demux->segment.rate < 0.0)
2722 demux->segment.position = demux->segment.start;
2724 /* perform EOS logic */
2725 if (!demux->no_more_pads) {
2726 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2727 demux->no_more_pads = TRUE;
2730 if (demux->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
2733 /* for segment playback we need to post when (in stream time)
2734 * we stopped, this is either stop (when set) or the duration. */
2735 if ((stop = demux->segment.stop) == -1)
2736 stop = demux->segment.duration;
2738 if (demux->segment.rate >= 0) {
2739 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2740 gst_element_post_message (GST_ELEMENT_CAST (demux),
2741 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2742 GST_FORMAT_TIME, stop));
2743 gst_flv_demux_push_src_event (demux,
2744 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2745 } else { /* Reverse playback */
2746 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2748 gst_element_post_message (GST_ELEMENT_CAST (demux),
2749 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2750 GST_FORMAT_TIME, demux->segment.start));
2751 gst_flv_demux_push_src_event (demux,
2752 gst_event_new_segment_done (GST_FORMAT_TIME,
2753 demux->segment.start));
2756 /* normal playback, send EOS to all linked pads */
2757 if (!demux->no_more_pads) {
2758 gst_element_no_more_pads (GST_ELEMENT (demux));
2759 demux->no_more_pads = TRUE;
2762 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2763 if (!demux->audio_pad && !demux->video_pad)
2764 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2765 ("Internal data stream error."), ("Got EOS before any data"));
2766 else if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2767 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2769 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2770 GST_ELEMENT_FLOW_ERROR (demux, ret);
2771 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2773 gst_object_unref (demux);
2779 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment,
2780 GstSeekFlags seek_flags)
2785 GstIndexEntry *entry;
2787 g_return_val_if_fail (segment != NULL, 0);
2789 time = segment->position;
2791 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2794 /* Let's check if we have an index entry for that seek time */
2795 entry = gst_index_get_assoc_entry (index, demux->index_id,
2796 seek_flags & GST_SEEK_FLAG_SNAP_AFTER ?
2797 GST_INDEX_LOOKUP_AFTER : GST_INDEX_LOOKUP_BEFORE,
2798 GST_ASSOCIATION_FLAG_KEY_UNIT, GST_FORMAT_TIME, time);
2801 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2802 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2804 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2805 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2806 GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2808 /* Key frame seeking */
2809 if (seek_flags & GST_SEEK_FLAG_KEY_UNIT) {
2810 /* Adjust the segment so that the keyframe fits in */
2811 segment->start = segment->time = time;
2812 segment->position = time;
2815 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2816 GST_TIME_ARGS (segment->start));
2819 gst_object_unref (index);
2826 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2830 GstSeekType start_type, stop_type;
2833 gboolean update, flush, ret;
2834 GstSegment seeksegment;
2836 gst_event_parse_seek (event, &rate, &format, &flags,
2837 &start_type, &start, &stop_type, &stop);
2839 if (format != GST_FORMAT_TIME)
2842 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2844 /* Work on a copy until we are sure the seek succeeded. */
2845 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2847 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2850 /* Apply the seek to our segment */
2851 gst_segment_do_seek (&seeksegment, rate, format, flags,
2852 start_type, start, stop_type, stop, &update);
2854 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2857 if (flush || seeksegment.position != demux->segment.position) {
2858 /* Do the actual seeking */
2859 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment, flags);
2861 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2862 G_GUINT64_FORMAT, offset);
2863 ret = gst_pad_push_event (demux->sinkpad,
2864 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2865 flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2866 offset, GST_SEEK_TYPE_NONE, 0));
2867 if (G_UNLIKELY (!ret)) {
2868 GST_WARNING_OBJECT (demux, "upstream seek failed");
2871 gst_flow_combiner_reset (demux->flowcombiner);
2872 /* Tell all the stream we moved to a different position (discont) */
2873 demux->audio_need_discont = TRUE;
2874 demux->video_need_discont = TRUE;
2880 /* Ok seek succeeded, take the newly configured segment */
2881 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2883 /* Tell all the stream a new segment is needed */
2884 demux->audio_need_segment = TRUE;
2885 demux->video_need_segment = TRUE;
2886 /* Clean any potential newsegment event kept for the streams. The first
2887 * stream needing a new segment will create a new one. */
2888 if (G_UNLIKELY (demux->new_seg_event)) {
2889 gst_event_unref (demux->new_seg_event);
2890 demux->new_seg_event = NULL;
2892 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2893 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2894 GST_TIME_ARGS (demux->segment.start),
2895 GST_TIME_ARGS (demux->segment.stop));
2896 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2897 gst_event_unref (event);
2899 ret = gst_pad_push_event (demux->sinkpad, event);
2907 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2908 gst_event_unref (event);
2914 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2918 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2920 if (format != GST_FORMAT_TIME) {
2921 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2922 gst_event_unref (event);
2926 /* First try upstream */
2927 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2928 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2929 gst_event_unref (event);
2933 if (!demux->indexed) {
2934 guint64 seek_offset = 0;
2935 gboolean building_index;
2937 GST_OBJECT_LOCK (demux);
2938 /* handle the seek in the chain function */
2939 demux->seeking = TRUE;
2940 demux->state = FLV_STATE_SEEK;
2942 /* copy the event */
2943 if (demux->seek_event)
2944 gst_event_unref (demux->seek_event);
2945 demux->seek_event = gst_event_ref (event);
2947 /* set the building_index flag so that only one thread can setup the
2948 * structures for index seeking. */
2949 building_index = demux->building_index;
2950 if (!building_index) {
2951 demux->building_index = TRUE;
2952 if (!demux->file_size
2953 && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2954 &demux->file_size)) {
2955 GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2956 GST_OBJECT_UNLOCK (demux);
2960 /* we hope the last tag is a scriptdataobject containing an index
2961 * the size of the last tag is given in the last guint32 bits
2962 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2963 seek_offset = demux->file_size - sizeof (guint32);
2964 GST_DEBUG_OBJECT (demux,
2965 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2967 GST_OBJECT_UNLOCK (demux);
2969 if (!building_index) {
2970 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2972 return flv_demux_seek_to_offset (demux, seek_offset);
2975 /* FIXME: we have to always return true so that we don't block the seek
2977 * Note: maybe it is OK to return true if we're still building the index */
2981 return flv_demux_handle_seek_push (demux, event);
2985 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2990 GstSeekType start_type, stop_type;
2993 gboolean update, flush, ret = FALSE;
2994 GstSegment seeksegment;
2996 gst_event_parse_seek (event, &rate, &format, &flags,
2997 &start_type, &start, &stop_type, &stop);
2999 if (format != GST_FORMAT_TIME)
3002 /* mark seeking thread entering flushing/pausing */
3003 GST_OBJECT_LOCK (demux);
3005 demux->seeking = seeking;
3006 GST_OBJECT_UNLOCK (demux);
3008 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
3011 /* Flush start up and downstream to make sure data flow and loops are
3013 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
3014 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
3016 /* Pause the pulling task */
3017 gst_pad_pause_task (demux->sinkpad);
3020 /* Take the stream lock */
3021 GST_PAD_STREAM_LOCK (demux->sinkpad);
3024 /* Stop flushing upstream we need to pull */
3025 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
3028 /* Work on a copy until we are sure the seek succeeded. */
3029 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
3031 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
3034 /* Apply the seek to our segment */
3035 gst_segment_do_seek (&seeksegment, rate, format, flags,
3036 start_type, start, stop_type, stop, &update);
3038 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
3041 if (flush || seeksegment.position != demux->segment.position) {
3042 /* Do the actual seeking */
3043 /* index is reliable if it is complete or we do not go to far ahead */
3044 if (seeking && !demux->indexed &&
3045 seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
3046 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
3047 " index only up to %" GST_TIME_FORMAT,
3048 GST_TIME_ARGS (demux->index_max_time));
3049 /* stop flushing for now */
3051 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
3052 /* delegate scanning and index building to task thread to avoid
3053 * occupying main (UI) loop */
3054 if (demux->seek_event)
3055 gst_event_unref (demux->seek_event);
3056 demux->seek_event = gst_event_ref (event);
3057 demux->seek_time = seeksegment.position;
3058 demux->state = FLV_STATE_SEEK;
3059 /* do not know about succes yet, but we did care and handled it */
3064 /* now index should be as reliable as it can be for current purpose */
3065 gst_flv_demux_move_to_offset (demux,
3066 gst_flv_demux_find_offset (demux, &seeksegment, flags), TRUE);
3073 /* Stop flushing, the sinks are at time 0 now */
3074 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
3078 /* Ok seek succeeded, take the newly configured segment */
3079 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
3081 /* Notify about the start of a new segment */
3082 if (demux->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
3083 gst_element_post_message (GST_ELEMENT (demux),
3084 gst_message_new_segment_start (GST_OBJECT (demux),
3085 demux->segment.format, demux->segment.position));
3088 gst_flow_combiner_reset (demux->flowcombiner);
3089 /* Tell all the stream a new segment is needed */
3090 demux->audio_need_segment = TRUE;
3091 demux->video_need_segment = TRUE;
3092 /* Clean any potential newsegment event kept for the streams. The first
3093 * stream needing a new segment will create a new one. */
3094 if (G_UNLIKELY (demux->new_seg_event)) {
3095 gst_event_unref (demux->new_seg_event);
3096 demux->new_seg_event = NULL;
3098 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
3099 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
3100 GST_TIME_ARGS (demux->segment.start),
3101 GST_TIME_ARGS (demux->segment.stop));
3102 demux->new_seg_event = gst_event_new_segment (&demux->segment);
3106 GST_OBJECT_LOCK (demux);
3107 seeking = demux->seeking && !seeking;
3108 demux->seeking = FALSE;
3109 GST_OBJECT_UNLOCK (demux);
3111 /* if we detect an external seek having started (and possibly already having
3112 * flushed), do not restart task to give it a chance.
3113 * Otherwise external one's flushing will take care to pause task */
3115 gst_pad_pause_task (demux->sinkpad);
3117 gst_pad_start_task (demux->sinkpad,
3118 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad, NULL);
3121 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
3123 gst_event_unref (event);
3129 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
3130 gst_event_unref (event);
3135 /* If we can pull that's prefered */
3137 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
3142 query = gst_query_new_scheduling ();
3144 if (!gst_pad_peer_query (sinkpad, query)) {
3145 gst_query_unref (query);
3149 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
3150 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
3151 gst_query_unref (query);
3156 GST_DEBUG_OBJECT (sinkpad, "activating pull");
3157 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
3161 GST_DEBUG_OBJECT (sinkpad, "activating push");
3162 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
3167 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
3168 GstPadMode mode, gboolean active)
3173 demux = GST_FLV_DEMUX (parent);
3176 case GST_PAD_MODE_PUSH:
3177 demux->random_access = FALSE;
3180 case GST_PAD_MODE_PULL:
3182 demux->random_access = TRUE;
3183 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
3186 demux->random_access = FALSE;
3187 res = gst_pad_stop_task (sinkpad);
3198 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
3201 gboolean ret = FALSE;
3203 demux = GST_FLV_DEMUX (parent);
3205 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3207 switch (GST_EVENT_TYPE (event)) {
3208 case GST_EVENT_FLUSH_START:
3209 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
3210 demux->flushing = TRUE;
3211 ret = gst_flv_demux_push_src_event (demux, event);
3213 case GST_EVENT_FLUSH_STOP:
3214 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
3215 gst_flv_demux_flush (demux, TRUE);
3216 ret = gst_flv_demux_push_src_event (demux, event);
3222 GST_DEBUG_OBJECT (demux, "received EOS");
3224 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
3227 GST_DEBUG_OBJECT (demux, "committing index");
3228 gst_index_commit (index, demux->index_id);
3229 gst_object_unref (index);
3232 if (!demux->audio_pad && !demux->video_pad) {
3233 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
3234 ("Internal data stream error."), ("Got EOS before any data"));
3235 gst_event_unref (event);
3237 if (!demux->no_more_pads) {
3238 gst_element_no_more_pads (GST_ELEMENT (demux));
3239 demux->no_more_pads = TRUE;
3242 if (!gst_flv_demux_push_src_event (demux, event))
3243 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
3248 case GST_EVENT_SEGMENT:
3250 GstSegment in_segment;
3252 GST_DEBUG_OBJECT (demux, "received new segment");
3254 gst_event_copy_segment (event, &in_segment);
3256 if (in_segment.format == GST_FORMAT_TIME) {
3257 /* time segment, this is perfect, copy over the values. */
3258 memcpy (&demux->segment, &in_segment, sizeof (in_segment));
3260 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
3264 ret = gst_flv_demux_push_src_event (demux, event);
3266 /* non-time format */
3267 demux->audio_need_segment = TRUE;
3268 demux->video_need_segment = TRUE;
3270 gst_event_unref (event);
3271 if (demux->new_seg_event) {
3272 gst_event_unref (demux->new_seg_event);
3273 demux->new_seg_event = NULL;
3276 gst_flow_combiner_reset (demux->flowcombiner);
3280 ret = gst_pad_event_default (pad, parent, event);
3288 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
3291 gboolean ret = FALSE;
3293 demux = GST_FLV_DEMUX (parent);
3295 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3297 switch (GST_EVENT_TYPE (event)) {
3298 case GST_EVENT_SEEK:
3299 /* Try to push upstream first */
3300 gst_event_ref (event);
3301 ret = gst_pad_push_event (demux->sinkpad, event);
3303 gst_event_unref (event);
3306 if (demux->random_access) {
3307 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
3309 ret = gst_flv_demux_handle_seek_push (demux, event);
3313 ret = gst_pad_push_event (demux->sinkpad, event);
3321 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
3323 gboolean res = TRUE;
3326 demux = GST_FLV_DEMUX (parent);
3328 switch (GST_QUERY_TYPE (query)) {
3329 case GST_QUERY_DURATION:
3333 gst_query_parse_duration (query, &format, NULL);
3335 /* duration is time only */
3336 if (format != GST_FORMAT_TIME) {
3337 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
3343 /* Try to push upstream first */
3344 res = gst_pad_peer_query (demux->sinkpad, query);
3348 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3349 GST_TIME_ARGS (demux->duration));
3351 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3355 case GST_QUERY_POSITION:
3359 gst_query_parse_position (query, &format, NULL);
3361 /* position is time only */
3362 if (format != GST_FORMAT_TIME) {
3363 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3369 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3370 GST_TIME_ARGS (demux->segment.position));
3372 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3377 case GST_QUERY_SEEKING:{
3380 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3382 /* First ask upstream */
3383 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3386 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3393 /* FIXME, check index this way is not thread safe */
3394 if (fmt != GST_FORMAT_TIME || !demux->index) {
3395 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3396 } else if (demux->random_access) {
3397 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3400 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3401 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3404 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3405 gst_query_unref (peerquery);
3408 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3411 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3415 case GST_QUERY_SEGMENT:
3420 format = demux->segment.format;
3423 gst_segment_to_stream_time (&demux->segment, format,
3424 demux->segment.start);
3425 if ((stop = demux->segment.stop) == -1)
3426 stop = demux->segment.duration;
3428 stop = gst_segment_to_stream_time (&demux->segment, format, stop);
3430 gst_query_set_segment (query, demux->segment.rate, format, start, stop);
3434 case GST_QUERY_LATENCY:
3436 res = gst_pad_query_default (pad, parent, query);
3445 static GstStateChangeReturn
3446 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3449 GstStateChangeReturn ret;
3451 demux = GST_FLV_DEMUX (element);
3453 switch (transition) {
3454 case GST_STATE_CHANGE_READY_TO_PAUSED:
3455 /* If this is our own index destroy it as the
3456 * old entries might be wrong for the new stream */
3457 if (demux->own_index) {
3458 gst_object_unref (demux->index);
3459 demux->index = NULL;
3460 demux->own_index = FALSE;
3463 /* If no index was created, generate one */
3464 if (G_UNLIKELY (!demux->index)) {
3465 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3467 demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3469 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3471 demux->own_index = TRUE;
3473 gst_flv_demux_cleanup (demux);
3479 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3480 if (ret == GST_STATE_CHANGE_FAILURE)
3483 switch (transition) {
3484 case GST_STATE_CHANGE_PAUSED_TO_READY:
3485 gst_flv_demux_cleanup (demux);
3496 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3498 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3499 GstIndex *old_index;
3501 GST_OBJECT_LOCK (demux);
3503 old_index = demux->index;
3506 demux->index = gst_object_ref (index);
3507 demux->own_index = FALSE;
3509 demux->index = NULL;
3512 gst_object_unref (demux->index);
3514 gst_object_ref (index);
3516 GST_OBJECT_UNLOCK (demux);
3518 /* object lock might be taken again */
3520 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3522 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3524 gst_object_unref (index);
3529 gst_flv_demux_get_index (GstElement * element)
3531 GstIndex *result = NULL;
3533 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3535 GST_OBJECT_LOCK (demux);
3537 result = gst_object_ref (demux->index);
3538 GST_OBJECT_UNLOCK (demux);
3544 gst_flv_demux_dispose (GObject * object)
3546 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3548 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3550 if (demux->adapter) {
3551 gst_adapter_clear (demux->adapter);
3552 g_object_unref (demux->adapter);
3553 demux->adapter = NULL;
3556 if (demux->taglist) {
3557 gst_tag_list_unref (demux->taglist);
3558 demux->taglist = NULL;
3561 if (demux->audio_tags) {
3562 gst_tag_list_unref (demux->audio_tags);
3563 demux->audio_tags = NULL;
3566 if (demux->video_tags) {
3567 gst_tag_list_unref (demux->video_tags);
3568 demux->video_tags = NULL;
3571 if (demux->flowcombiner) {
3572 gst_flow_combiner_free (demux->flowcombiner);
3573 demux->flowcombiner = NULL;
3576 if (demux->new_seg_event) {
3577 gst_event_unref (demux->new_seg_event);
3578 demux->new_seg_event = NULL;
3581 if (demux->audio_codec_data) {
3582 gst_buffer_unref (demux->audio_codec_data);
3583 demux->audio_codec_data = NULL;
3586 if (demux->video_codec_data) {
3587 gst_buffer_unref (demux->video_codec_data);
3588 demux->video_codec_data = NULL;
3591 if (demux->audio_pad) {
3592 gst_object_unref (demux->audio_pad);
3593 demux->audio_pad = NULL;
3596 if (demux->video_pad) {
3597 gst_object_unref (demux->video_pad);
3598 demux->video_pad = NULL;
3602 gst_object_unref (demux->index);
3603 demux->index = NULL;
3607 g_array_free (demux->times, TRUE);
3608 demux->times = NULL;
3611 if (demux->filepositions) {
3612 g_array_free (demux->filepositions, TRUE);
3613 demux->filepositions = NULL;
3616 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3620 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3622 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3623 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3625 gobject_class->dispose = gst_flv_demux_dispose;
3627 gstelement_class->change_state =
3628 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3631 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3632 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3635 gst_element_class_add_static_pad_template (gstelement_class,
3636 &flv_sink_template);
3637 gst_element_class_add_static_pad_template (gstelement_class,
3638 &audio_src_template);
3639 gst_element_class_add_static_pad_template (gstelement_class,
3640 &video_src_template);
3641 gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
3642 "Codec/Demuxer", "Demux FLV feeds into digital streams",
3643 "Julien Moutte <julien@moutte.net>");
3647 gst_flv_demux_init (GstFlvDemux * demux)
3650 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3652 gst_pad_set_event_function (demux->sinkpad,
3653 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3654 gst_pad_set_chain_function (demux->sinkpad,
3655 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3656 gst_pad_set_activate_function (demux->sinkpad,
3657 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3658 gst_pad_set_activatemode_function (demux->sinkpad,
3659 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3661 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3663 demux->adapter = gst_adapter_new ();
3664 demux->flowcombiner = gst_flow_combiner_new ();
3666 demux->own_index = FALSE;
3668 GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3670 gst_flv_demux_cleanup (demux);
3674 plugin_init (GstPlugin * plugin)
3676 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3678 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3679 gst_flv_demux_get_type ()) ||
3680 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3681 gst_flv_mux_get_type ()))
3687 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3688 flv, "FLV muxing and demuxing plugin",
3689 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)