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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * SECTION:element-flvdemux
23 * flvdemux demuxes an FLV file into the different contained streams.
26 * <title>Example launch line</title>
28 * gst-launch-1.0 -v filesrc location=/path/to/flv ! flvdemux ! audioconvert ! autoaudiosink
29 * ]| This pipeline demuxes an FLV file and outputs the contained raw audio streams.
37 #include "gstflvdemux.h"
38 #include "gstflvmux.h"
41 #include <gst/base/gstbytereader.h>
42 #include <gst/pbutils/descriptions.h>
43 #include <gst/pbutils/pbutils.h>
44 #include <gst/audio/audio.h>
46 /* FIXME: don't rely on own GstIndex */
48 #include "gstmemindex.c"
49 #define GST_ASSOCIATION_FLAG_NONE GST_INDEX_ASSOCIATION_FLAG_NONE
50 #define GST_ASSOCIATION_FLAG_KEY_UNIT GST_INDEX_ASSOCIATION_FLAG_KEY_UNIT
51 #define GST_ASSOCIATION_FLAG_DELTA_UNIT GST_INDEX_ASSOCIATION_FLAG_DELTA_UNIT
53 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
56 GST_STATIC_CAPS ("video/x-flv")
59 static GstStaticPadTemplate audio_src_template =
60 GST_STATIC_PAD_TEMPLATE ("audio",
64 ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
65 "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
66 "audio/mpeg, mpegversion = (int) 4, stream-format = (string) raw, framed = (boolean) TRUE; "
67 "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
68 "audio/x-raw, format = (string) { U8, S16LE }, layout = (string) interleaved, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
69 "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
70 "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
71 "audio/x-speex, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 };")
74 static GstStaticPadTemplate video_src_template =
75 GST_STATIC_PAD_TEMPLATE ("video",
78 GST_STATIC_CAPS ("video/x-flash-video; "
79 "video/x-flash-screen; "
80 "video/x-vp6-flash; " "video/x-vp6-alpha; "
81 "video/x-h264, stream-format=avc;")
84 GST_DEBUG_CATEGORY_STATIC (flvdemux_debug);
85 #define GST_CAT_DEFAULT flvdemux_debug
87 #define gst_flv_demux_parent_class parent_class
88 G_DEFINE_TYPE (GstFlvDemux, gst_flv_demux, GST_TYPE_ELEMENT);
90 /* 9 bytes of header + 4 bytes of first previous tag size */
91 #define FLV_HEADER_SIZE 13
92 /* 1 byte of tag type + 3 bytes of tag data size */
93 #define FLV_TAG_TYPE_SIZE 4
95 /* two seconds - consider pts are resynced to another base if this different */
96 #define RESYNC_THRESHOLD 2000
98 static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
100 static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
101 GstEvent * event, gboolean seeking);
103 static gboolean gst_flv_demux_query (GstPad * pad, GstObject * parent,
105 static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent,
108 static GstIndex *gst_flv_demux_get_index (GstElement * element);
111 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
112 guint64 pos, gboolean keyframe)
114 GstIndexAssociation associations[2];
116 GstIndexEntry *entry;
118 GST_LOG_OBJECT (demux,
119 "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
120 keyframe, GST_TIME_ARGS (ts), pos);
122 /* if upstream is not seekable there is no point in building an index */
123 if (!demux->upstream_seekable)
126 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
131 /* entry may already have been added before, avoid adding indefinitely */
132 entry = gst_index_get_assoc_entry (index, demux->index_id,
133 GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
136 #ifndef GST_DISABLE_GST_DEBUG
140 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
141 key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
142 GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
143 ", keyframe %d", GST_TIME_ARGS (time), key);
144 /* there is not really a way to delete the existing one */
145 if (time != ts || key != ! !keyframe)
146 GST_DEBUG_OBJECT (demux, "metadata mismatch");
148 gst_object_unref (index);
152 associations[0].format = GST_FORMAT_TIME;
153 associations[0].value = ts;
154 associations[1].format = GST_FORMAT_BYTES;
155 associations[1].value = pos;
157 gst_index_add_associationv (index, demux->index_id,
158 (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
159 GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
160 (const GstIndexAssociation *) &associations);
162 if (pos > demux->index_max_pos)
163 demux->index_max_pos = pos;
164 if (ts > demux->index_max_time)
165 demux->index_max_time = ts;
167 gst_object_unref (index);
171 FLV_GET_STRING (GstByteReader * reader)
173 guint16 string_size = 0;
174 gchar *string = NULL;
175 const guint8 *str = NULL;
177 g_return_val_if_fail (reader != NULL, NULL);
179 if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
182 if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
185 string = g_try_malloc0 (string_size + 1);
186 if (G_UNLIKELY (!string)) {
190 if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
195 memcpy (string, str, string_size);
196 if (!g_utf8_validate (string, string_size, NULL)) {
205 gst_flv_demux_check_seekability (GstFlvDemux * demux)
208 gint64 start = -1, stop = -1;
210 demux->upstream_seekable = FALSE;
212 query = gst_query_new_seeking (GST_FORMAT_BYTES);
213 if (!gst_pad_peer_query (demux->sinkpad, query)) {
214 GST_DEBUG_OBJECT (demux, "seeking query failed");
215 gst_query_unref (query);
219 gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
222 gst_query_unref (query);
224 /* try harder to query upstream size if we didn't get it the first time */
225 if (demux->upstream_seekable && stop == -1) {
226 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
227 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
230 /* if upstream doesn't know the size, it's likely that it's not seekable in
231 * practice even if it technically may be seekable */
232 if (demux->upstream_seekable && (start != 0 || stop <= start)) {
233 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
234 demux->upstream_seekable = FALSE;
237 GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
241 parse_flv_demux_parse_date_string (GDate * date, const gchar * s)
243 g_date_set_parse (date, s);
244 if (g_date_valid (date))
247 /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
249 static const gchar *months[] = {
250 "Jan", "Feb", "Mar", "Apr",
251 "May", "Jun", "Jul", "Aug",
252 "Sep", "Oct", "Nov", "Dec"
254 gchar **tokens = g_strsplit (s, " ", -1);
259 if (g_strv_length (tokens) != 5)
262 if (strlen (tokens[1]) != 3)
264 for (i = 0; i < 12; i++) {
265 if (!strcmp (tokens[1], months[i])) {
271 g_date_set_month (date, i + 1);
273 d = g_ascii_strtoull (tokens[2], &endptr, 10);
274 if (d == 0 && *endptr != '\0')
277 g_date_set_day (date, d);
279 d = g_ascii_strtoull (tokens[4], &endptr, 10);
280 if (d == 0 && *endptr != '\0')
283 g_date_set_year (date, d);
292 gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
293 gboolean * end_marker)
295 gchar *tag_name = NULL;
298 /* Initialize the end_marker flag to FALSE */
301 /* Name of the tag */
302 tag_name = FLV_GET_STRING (reader);
303 if (G_UNLIKELY (!tag_name)) {
304 GST_WARNING_OBJECT (demux, "failed reading tag name");
308 /* What kind of object is that */
309 if (!gst_byte_reader_get_uint8 (reader, &tag_type))
312 GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
316 { /* Use a union to read the uint64 and then as a double */
319 if (!gst_byte_reader_get_float64_be (reader, &d))
322 GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
324 if (!strcmp (tag_name, "duration")) {
325 demux->duration = d * GST_SECOND;
327 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
328 GST_TAG_DURATION, demux->duration, NULL);
329 } else if (!strcmp (tag_name, "AspectRatioX")) {
331 demux->got_par = TRUE;
332 } else if (!strcmp (tag_name, "AspectRatioY")) {
334 demux->got_par = TRUE;
335 } else if (!strcmp (tag_name, "width")) {
337 } else if (!strcmp (tag_name, "height")) {
339 } else if (!strcmp (tag_name, "framerate")) {
340 demux->framerate = d;
342 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
347 case 1: /* Boolean */
351 if (!gst_byte_reader_get_uint8 (reader, &b))
354 GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
356 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
364 s = FLV_GET_STRING (reader);
368 GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
370 if (!strcmp (tag_name, "creationdate")) {
371 GDate *date = g_date_new ();
373 parse_flv_demux_parse_date_string (date, s);
374 if (!g_date_valid (date)) {
375 GST_DEBUG_OBJECT (demux, "Failed to parse string as date");
377 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
378 GST_TAG_DATE, date, NULL);
381 } else if (!strcmp (tag_name, "creator")) {
382 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
383 GST_TAG_ARTIST, s, NULL);
384 } else if (!strcmp (tag_name, "title")) {
385 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
386 GST_TAG_TITLE, s, NULL);
387 } else if (!strcmp (tag_name, "metadatacreator")) {
388 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
389 GST_TAG_ENCODER, s, NULL);
391 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
400 gboolean end_of_object_marker = FALSE;
402 while (!end_of_object_marker) {
403 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
404 &end_of_object_marker);
406 if (G_UNLIKELY (!ok)) {
407 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
414 case 8: /* ECMA array */
416 guint32 nb_elems = 0;
417 gboolean end_of_object_marker = FALSE;
419 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
422 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
425 while (!end_of_object_marker) {
426 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
427 &end_of_object_marker);
429 if (G_UNLIKELY (!ok)) {
430 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
437 case 9: /* End marker */
439 GST_DEBUG_OBJECT (demux, "end marker ?");
440 if (tag_name[0] == '\0') {
442 GST_DEBUG_OBJECT (demux, "end marker detected");
451 guint32 nb_elems = 0;
453 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
456 GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
458 if (!strcmp (tag_name, "times")) {
460 g_array_free (demux->times, TRUE);
462 demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
463 } else if (!strcmp (tag_name, "filepositions")) {
464 if (demux->filepositions) {
465 g_array_free (demux->filepositions, TRUE);
467 demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
471 guint8 elem_type = 0;
473 if (!gst_byte_reader_get_uint8 (reader, &elem_type))
481 if (!gst_byte_reader_get_float64_be (reader, &d))
484 GST_DEBUG_OBJECT (demux, "element is a double %f", d);
486 if (!strcmp (tag_name, "times") && demux->times) {
487 g_array_append_val (demux->times, d);
488 } else if (!strcmp (tag_name, "filepositions") &&
489 demux->filepositions) {
490 g_array_append_val (demux->filepositions, d);
495 GST_WARNING_OBJECT (demux, "unsupported array element type %d",
507 if (!gst_byte_reader_get_float64_be (reader, &d))
510 if (!gst_byte_reader_get_int16_be (reader, &i))
513 GST_DEBUG_OBJECT (demux,
514 "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
516 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
521 GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
535 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
537 GstFlowReturn ret = GST_FLOW_OK;
538 GstByteReader reader;
542 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 7, GST_FLOW_ERROR);
544 gst_buffer_map (buffer, &map, GST_MAP_READ);
545 gst_byte_reader_init (&reader, map.data, map.size);
547 gst_byte_reader_skip_unchecked (&reader, 7);
549 GST_LOG_OBJECT (demux, "parsing a script tag");
551 if (!gst_byte_reader_get_uint8 (&reader, &type))
556 gchar *function_name;
559 function_name = FLV_GET_STRING (&reader);
561 GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
563 if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
564 gboolean end_marker = FALSE;
565 GST_DEBUG_OBJECT (demux, "we have a metadata script object");
567 if (!gst_byte_reader_get_uint8 (&reader, &type)) {
568 g_free (function_name);
575 guint32 nb_elems = 0;
578 if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
579 g_free (function_name);
583 /* The number of elements is just a hint, some files have
584 nb_elements == 0 and actually contain items. */
585 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
588 /* fallthrough to read data */
592 while (!end_marker) {
594 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
596 if (G_UNLIKELY (!ok)) {
597 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
604 GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
605 g_free (function_name);
609 demux->push_tags = TRUE;
612 g_free (function_name);
614 if (demux->times && demux->filepositions) {
617 /* If an index was found, insert associations */
618 num = MIN (demux->times->len, demux->filepositions->len);
619 for (i = 0; i < num; i++) {
620 guint64 time, fileposition;
622 time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
623 fileposition = g_array_index (demux->filepositions, gdouble, i);
624 gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
627 demux->indexed = TRUE;
632 gst_buffer_unmap (buffer, &map);
638 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
639 guint32 rate, guint32 channels, guint32 width)
641 GstCaps *caps = NULL;
642 gchar *codec_name = NULL;
643 gboolean ret = FALSE;
644 guint adjusted_rate = rate;
649 caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
654 caps = gst_caps_new_simple ("audio/mpeg",
655 "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
656 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
661 GstAudioFormat format;
663 /* Assuming little endian for 0 (aka endianness of the
664 * system on which the file was created) as most people
665 * are probably using little endian machines */
666 format = gst_audio_format_build_integer ((width == 8) ? FALSE : TRUE,
667 G_LITTLE_ENDIAN, width, width);
669 caps = gst_caps_new_simple ("audio/x-raw",
670 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
671 "layout", G_TYPE_STRING, "interleaved", NULL);
677 caps = gst_caps_new_empty_simple ("audio/x-nellymoser");
681 if (demux->audio_codec_data) {
684 gst_buffer_map (demux->audio_codec_data, &map, GST_MAP_READ);
686 /* use codec-data to extract and verify samplerate */
690 freq_index = GST_READ_UINT16_BE (map.data);
691 freq_index = (freq_index & 0x0780) >> 7;
693 gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
695 if (adjusted_rate && (rate != adjusted_rate)) {
696 GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
699 adjusted_rate = rate;
702 gst_buffer_unmap (demux->audio_codec_data, &map);
705 caps = gst_caps_new_simple ("audio/mpeg",
706 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
707 "stream-format", G_TYPE_STRING, "raw", NULL);
711 caps = gst_caps_new_empty_simple ("audio/x-alaw");
714 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
717 caps = gst_caps_new_empty_simple ("audio/x-speex");
720 GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
723 if (G_UNLIKELY (!caps)) {
724 GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
728 gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
729 "channels", G_TYPE_INT, channels, NULL);
731 if (demux->audio_codec_data) {
732 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
733 demux->audio_codec_data, NULL);
737 gst_pad_create_stream_id (demux->audio_pad, GST_ELEMENT_CAST (demux),
739 gst_pad_push_event (demux->audio_pad, gst_event_new_stream_start (stream_id));
741 ret = gst_pad_set_caps (demux->audio_pad, caps);
743 if (G_LIKELY (ret)) {
744 /* Store the caps we got from tags */
745 demux->audio_codec_tag = codec_tag;
747 demux->channels = channels;
748 demux->width = width;
750 codec_name = gst_pb_utils_get_codec_description (caps);
753 if (demux->taglist == NULL)
754 demux->taglist = gst_tag_list_new_empty ();
755 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
756 GST_TAG_AUDIO_CODEC, codec_name, NULL);
760 GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
761 GST_PTR_FORMAT, caps);
763 GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
764 GST_PTR_FORMAT, caps);
767 gst_caps_unref (caps);
774 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
778 if (demux->audio_pad)
779 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
781 if (demux->video_pad)
782 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
784 gst_event_unref (event);
790 gst_flv_demux_push_tags (GstFlvDemux * demux)
792 if (demux->has_audio && !demux->audio_pad) {
793 GST_DEBUG_OBJECT (demux,
794 "Waiting for audio stream pad to come up before we can push tags");
797 if (demux->has_video && !demux->video_pad) {
798 GST_DEBUG_OBJECT (demux,
799 "Waiting for video stream pad to come up before we can push tags");
802 if (demux->taglist) {
803 GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
805 gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
806 gst_flv_demux_push_src_event (demux, gst_event_new_tag (demux->taglist));
807 demux->taglist = gst_tag_list_new_empty ();
808 demux->push_tags = FALSE;
813 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, gboolean discont,
814 guint32 * last, GstClockTime * offset)
816 gint32 dpts = pts - *last;
817 if (!discont && ABS (dpts) >= RESYNC_THRESHOLD) {
818 /* Theoretically, we should use substract the duration of the last buffer,
819 but this demuxer sends no durations on buffers, not sure if it cannot
820 know, or just does not care to calculate. */
821 *offset -= dpts * GST_MSECOND;
822 GST_WARNING_OBJECT (demux,
823 "Large pts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
824 GST_TIME_FORMAT "", dpts, GST_TIME_ARGS (*offset));
830 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
832 GstFlowReturn ret = GST_FLOW_OK;
833 guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
834 guint32 codec_data = 0, pts_ext = 0;
840 GST_LOG_OBJECT (demux, "parsing an audio tag");
842 if (demux->no_more_pads && !demux->audio_pad) {
843 GST_WARNING_OBJECT (demux,
844 "Signaled no-more-pads already but had no audio pad -- ignoring");
848 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
851 /* Error out on tags with too small headers */
852 if (gst_buffer_get_size (buffer) < 11) {
853 GST_ERROR_OBJECT (demux, "Too small tag size (%" G_GSIZE_FORMAT ")",
854 gst_buffer_get_size (buffer));
855 return GST_FLOW_ERROR;
858 gst_buffer_map (buffer, &map, GST_MAP_READ);
861 /* Grab information about audio tag */
862 pts = GST_READ_UINT24_BE (data);
863 /* read the pts extension to 32 bits integer */
864 pts_ext = GST_READ_UINT8 (data + 3);
866 pts |= pts_ext << 24;
868 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
869 data[2], data[3], pts);
871 /* Skip the stream id and go directly to the flags */
872 flags = GST_READ_UINT8 (data + 7);
874 /* Silently skip buffers with no data */
887 if ((flags & 0x0C) == 0x0C) {
889 } else if ((flags & 0x0C) == 0x08) {
891 } else if ((flags & 0x0C) == 0x04) {
895 codec_tag = flags >> 4;
896 if (codec_tag == 10) { /* AAC has an extra byte for packet type */
902 /* codec tags with special rates */
903 if (codec_tag == 5 || codec_tag == 14)
905 else if (codec_tag == 4)
908 GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
909 "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
912 /* If we don't have our audio pad created, then create it. */
913 if (G_UNLIKELY (!demux->audio_pad)) {
916 gst_pad_new_from_template (gst_element_class_get_pad_template
917 (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
918 if (G_UNLIKELY (!demux->audio_pad)) {
919 GST_WARNING_OBJECT (demux, "failed creating audio pad");
920 ret = GST_FLOW_ERROR;
924 /* Set functions on the pad */
925 gst_pad_set_query_function (demux->audio_pad,
926 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
927 gst_pad_set_event_function (demux->audio_pad,
928 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
930 gst_pad_use_fixed_caps (demux->audio_pad);
933 gst_pad_set_active (demux->audio_pad, TRUE);
936 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
938 gst_object_unref (demux->audio_pad);
939 demux->audio_pad = NULL;
940 ret = GST_FLOW_ERROR;
943 #ifndef GST_DISABLE_GST_DEBUG
947 caps = gst_pad_get_current_caps (demux->audio_pad);
948 GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
951 gst_caps_unref (caps);
955 /* We need to set caps before adding */
956 gst_element_add_pad (GST_ELEMENT (demux),
957 gst_object_ref (demux->audio_pad));
959 /* We only emit no more pads when we have audio and video. Indeed we can
960 * not trust the FLV header to tell us if there will be only audio or
961 * only video and we would just break discovery of some files */
962 if (demux->audio_pad && demux->video_pad) {
963 GST_DEBUG_OBJECT (demux, "emitting no more pads");
964 gst_element_no_more_pads (GST_ELEMENT (demux));
965 demux->no_more_pads = TRUE;
966 demux->push_tags = TRUE;
970 /* Check if caps have changed */
971 if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
972 codec_tag != demux->audio_codec_tag || width != demux->width)) {
973 GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
976 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
978 ret = GST_FLOW_ERROR;
983 /* Push taglist if present */
984 if (G_UNLIKELY (demux->push_tags))
985 gst_flv_demux_push_tags (demux);
987 /* Check if we have anything to push */
988 if (demux->tag_data_size <= codec_data) {
989 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
993 /* Create buffer from pad */
994 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
995 7 + codec_data, demux->tag_data_size - codec_data);
997 if (demux->audio_codec_tag == 10) {
998 guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
1000 switch (aac_packet_type) {
1003 /* AudioSpecificConfig data */
1004 GST_LOG_OBJECT (demux, "got an AAC codec data packet");
1005 if (demux->audio_codec_data) {
1006 gst_buffer_unref (demux->audio_codec_data);
1008 demux->audio_codec_data = outbuf;
1009 /* Use that buffer data in the caps */
1010 gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels, width);
1015 /* AAC raw packet */
1016 GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
1019 GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
1024 /* detect (and deem to be resyncs) large pts gaps */
1025 gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
1026 &demux->last_audio_pts, &demux->audio_time_offset);
1028 /* Fill buffer with data */
1029 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
1030 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1031 GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
1032 GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
1034 if (demux->duration == GST_CLOCK_TIME_NONE ||
1035 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1036 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1038 /* Only add audio frames to the index if we have no video,
1039 * and if the index is not yet complete */
1040 if (!demux->has_video && !demux->indexed) {
1041 gst_flv_demux_parse_and_add_index_entry (demux,
1042 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
1045 if (G_UNLIKELY (demux->audio_need_discont)) {
1046 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1047 demux->audio_need_discont = FALSE;
1050 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1052 /* Do we need a newsegment event ? */
1053 if (G_UNLIKELY (demux->audio_need_segment)) {
1054 if (!demux->new_seg_event) {
1055 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1056 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1057 GST_TIME_ARGS (demux->segment.position),
1058 GST_TIME_ARGS (demux->segment.stop));
1059 demux->segment.start = demux->segment.time = demux->segment.position;
1060 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1062 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1065 gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1067 demux->audio_need_segment = FALSE;
1070 GST_LOG_OBJECT (demux,
1071 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1072 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1073 gst_buffer_get_size (outbuf),
1074 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1075 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1077 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1078 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1080 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1081 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1084 if (G_UNLIKELY (!demux->no_more_pads
1085 && (GST_CLOCK_DIFF (demux->audio_start,
1086 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1087 GST_DEBUG_OBJECT (demux,
1088 "Signalling no-more-pads because no video stream was found"
1089 " after 6 seconds of audio");
1090 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1091 demux->no_more_pads = TRUE;
1092 demux->push_tags = TRUE;
1095 /* Push downstream */
1096 ret = gst_pad_push (demux->audio_pad, outbuf);
1097 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1098 if (demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1099 demux->segment.position > demux->segment.stop) {
1100 /* In reverse playback we can get a GST_FLOW_EOS when
1101 * we are at the end of the segment, so we just need to jump
1102 * back to the previous section. */
1103 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1104 demux->audio_done = TRUE;
1107 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1108 " bytes audio buffer: %s", demux->tag_data_size,
1109 gst_flow_get_name (ret));
1110 if (ret == GST_FLOW_NOT_LINKED) {
1111 demux->audio_linked = FALSE;
1117 demux->audio_linked = TRUE;
1120 gst_buffer_unmap (buffer, &map);
1126 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1128 gboolean ret = FALSE;
1129 GstCaps *caps = NULL;
1130 gchar *codec_name = NULL;
1133 /* Generate caps for that pad */
1134 switch (codec_tag) {
1136 caps = gst_caps_new_empty_simple ("video/x-flash-video");
1139 caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1142 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1145 caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1149 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1153 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1156 if (G_UNLIKELY (!caps)) {
1157 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1161 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1162 demux->par_x, demux->par_y, NULL);
1164 if (G_LIKELY (demux->w)) {
1165 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1168 if (G_LIKELY (demux->h)) {
1169 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1172 if (G_LIKELY (demux->framerate)) {
1173 gint num = 0, den = 0;
1175 gst_util_double_to_fraction (demux->framerate, &num, &den);
1176 GST_DEBUG_OBJECT (demux->video_pad,
1177 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1180 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1183 if (demux->video_codec_data) {
1184 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1185 demux->video_codec_data, NULL);
1189 gst_pad_create_stream_id (demux->video_pad, GST_ELEMENT_CAST (demux),
1191 gst_pad_push_event (demux->video_pad, gst_event_new_stream_start (stream_id));
1192 ret = gst_pad_set_caps (demux->video_pad, caps);
1194 if (G_LIKELY (ret)) {
1195 /* Store the caps we have set */
1196 demux->video_codec_tag = codec_tag;
1198 codec_name = gst_pb_utils_get_codec_description (caps);
1201 if (demux->taglist == NULL)
1202 demux->taglist = gst_tag_list_new_empty ();
1203 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1204 GST_TAG_VIDEO_CODEC, codec_name, NULL);
1205 g_free (codec_name);
1208 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1209 GST_PTR_FORMAT, caps);
1211 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1212 GST_PTR_FORMAT, caps);
1215 gst_caps_unref (caps);
1221 static GstFlowReturn
1222 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1224 GstFlowReturn ret = GST_FLOW_OK;
1225 guint32 pts = 0, codec_data = 1, pts_ext = 0;
1226 gboolean keyframe = FALSE;
1227 guint8 flags = 0, codec_tag = 0;
1232 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1235 GST_LOG_OBJECT (demux, "parsing a video tag");
1237 if (demux->no_more_pads && !demux->video_pad) {
1238 GST_WARNING_OBJECT (demux,
1239 "Signaled no-more-pads already but had no audio pad -- ignoring");
1243 if (gst_buffer_get_size (buffer) < 12) {
1244 GST_ERROR_OBJECT (demux, "Too small tag size");
1245 return GST_FLOW_ERROR;
1248 gst_buffer_map (buffer, &map, GST_MAP_READ);
1251 /* Grab information about video tag */
1252 pts = GST_READ_UINT24_BE (data);
1253 /* read the pts extension to 32 bits integer */
1254 pts_ext = GST_READ_UINT8 (data + 3);
1256 pts |= pts_ext << 24;
1258 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1259 data[2], data[3], pts);
1261 /* Skip the stream id and go directly to the flags */
1262 flags = GST_READ_UINT8 (data + 7);
1265 if ((flags >> 4) == 1) {
1269 codec_tag = flags & 0x0F;
1270 if (codec_tag == 4 || codec_tag == 5) {
1272 } else if (codec_tag == 7) {
1277 cts = GST_READ_UINT24_BE (data + 9);
1278 cts = (cts + 0xff800000) ^ 0xff800000;
1280 GST_LOG_OBJECT (demux, "got cts %d", cts);
1282 /* avoid negative overflow */
1283 if (cts >= 0 || pts >= -cts)
1287 GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1288 "(flags %02X)", codec_tag, keyframe, flags);
1290 /* If we don't have our video pad created, then create it. */
1291 if (G_UNLIKELY (!demux->video_pad)) {
1293 gst_pad_new_from_template (gst_element_class_get_pad_template
1294 (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1295 if (G_UNLIKELY (!demux->video_pad)) {
1296 GST_WARNING_OBJECT (demux, "failed creating video pad");
1297 ret = GST_FLOW_ERROR;
1301 /* Set functions on the pad */
1302 gst_pad_set_query_function (demux->video_pad,
1303 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1304 gst_pad_set_event_function (demux->video_pad,
1305 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1307 gst_pad_use_fixed_caps (demux->video_pad);
1309 /* Make it active */
1310 gst_pad_set_active (demux->video_pad, TRUE);
1312 /* Needs to be active before setting caps */
1313 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1314 gst_object_unref (demux->video_pad);
1315 demux->video_pad = NULL;
1316 ret = GST_FLOW_ERROR;
1320 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1321 * metadata tag that would come later and trigger a caps change */
1322 demux->got_par = FALSE;
1324 #ifndef GST_DISABLE_GST_DEBUG
1328 caps = gst_pad_get_current_caps (demux->video_pad);
1329 GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1332 gst_caps_unref (caps);
1336 /* We need to set caps before adding */
1337 gst_element_add_pad (GST_ELEMENT (demux),
1338 gst_object_ref (demux->video_pad));
1340 /* We only emit no more pads when we have audio and video. Indeed we can
1341 * not trust the FLV header to tell us if there will be only audio or
1342 * only video and we would just break discovery of some files */
1343 if (demux->audio_pad && demux->video_pad) {
1344 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1345 gst_element_no_more_pads (GST_ELEMENT (demux));
1346 demux->no_more_pads = TRUE;
1347 demux->push_tags = TRUE;
1351 /* Check if caps have changed */
1352 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1354 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1356 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1357 ret = GST_FLOW_ERROR;
1361 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1362 * metadata tag that would come later and trigger a caps change */
1363 demux->got_par = FALSE;
1366 /* Push taglist if present */
1367 if (G_UNLIKELY (demux->push_tags))
1368 gst_flv_demux_push_tags (demux);
1370 /* Check if we have anything to push */
1371 if (demux->tag_data_size <= codec_data) {
1372 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1376 /* Create buffer from pad */
1377 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1378 7 + codec_data, demux->tag_data_size - codec_data);
1380 if (demux->video_codec_tag == 7) {
1381 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1383 switch (avc_packet_type) {
1386 /* AVCDecoderConfigurationRecord data */
1387 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1388 if (demux->video_codec_data) {
1389 gst_buffer_unref (demux->video_codec_data);
1391 demux->video_codec_data = outbuf;
1392 /* Use that buffer data in the caps */
1393 gst_flv_demux_video_negotiate (demux, codec_tag);
1398 /* H.264 NALU packet */
1399 GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1402 GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1407 /* detect (and deem to be resyncs) large pts gaps */
1408 gst_flv_demux_update_resync (demux, pts, demux->video_need_discont,
1409 &demux->last_video_pts, &demux->video_time_offset);
1411 /* Fill buffer with data */
1412 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
1413 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1414 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1415 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1417 if (demux->duration == GST_CLOCK_TIME_NONE ||
1418 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1419 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1422 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1424 if (!demux->indexed) {
1425 gst_flv_demux_parse_and_add_index_entry (demux,
1426 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1429 if (G_UNLIKELY (demux->video_need_discont)) {
1430 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1431 demux->video_need_discont = FALSE;
1434 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1436 /* Do we need a newsegment event ? */
1437 if (G_UNLIKELY (demux->video_need_segment)) {
1438 if (!demux->new_seg_event) {
1439 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1440 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1441 GST_TIME_ARGS (demux->segment.position),
1442 GST_TIME_ARGS (demux->segment.stop));
1443 demux->segment.start = demux->segment.time = demux->segment.position;
1444 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1446 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1449 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1451 demux->video_need_segment = FALSE;
1454 GST_LOG_OBJECT (demux,
1455 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1456 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1457 ", keyframe (%d)", gst_buffer_get_size (outbuf),
1458 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1459 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1462 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1463 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1465 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1466 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1469 if (G_UNLIKELY (!demux->no_more_pads
1470 && (GST_CLOCK_DIFF (demux->video_start,
1471 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1472 GST_DEBUG_OBJECT (demux,
1473 "Signalling no-more-pads because no audio stream was found"
1474 " after 6 seconds of video");
1475 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1476 demux->no_more_pads = TRUE;
1477 demux->push_tags = TRUE;
1480 /* Push downstream */
1481 ret = gst_pad_push (demux->video_pad, outbuf);
1483 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1484 if (demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1485 demux->segment.position > demux->segment.stop) {
1486 /* In reverse playback we can get a GST_FLOW_EOS when
1487 * we are at the end of the segment, so we just need to jump
1488 * back to the previous section. */
1489 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1490 demux->video_done = TRUE;
1493 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1494 " bytes video buffer: %s", demux->tag_data_size,
1495 gst_flow_get_name (ret));
1496 if (ret == GST_FLOW_NOT_LINKED) {
1497 demux->video_linked = FALSE;
1503 demux->video_linked = TRUE;
1506 gst_buffer_unmap (buffer, &map);
1511 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1512 GstBuffer * buffer, size_t * tag_size)
1514 guint32 pts = 0, pts_ext = 0;
1515 guint32 tag_data_size;
1517 gboolean keyframe = TRUE;
1518 GstClockTime ret = GST_CLOCK_TIME_NONE;
1523 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1524 GST_CLOCK_TIME_NONE);
1526 gst_buffer_map (buffer, &map, GST_MAP_READ);
1532 if (type != 9 && type != 8 && type != 18) {
1533 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1538 demux->has_video = TRUE;
1540 demux->has_audio = TRUE;
1542 tag_data_size = GST_READ_UINT24_BE (data + 1);
1544 if (size >= tag_data_size + 11 + 4) {
1545 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1546 GST_WARNING_OBJECT (demux, "Invalid tag size");
1552 *tag_size = tag_data_size + 11 + 4;
1556 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
1559 /* Grab timestamp of tag tag */
1560 pts = GST_READ_UINT24_BE (data);
1561 /* read the pts extension to 32 bits integer */
1562 pts_ext = GST_READ_UINT8 (data + 3);
1564 pts |= pts_ext << 24;
1569 keyframe = ((data[0] >> 4) == 1);
1572 ret = pts * GST_MSECOND;
1573 GST_LOG_OBJECT (demux, "pts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1575 if (index && !demux->indexed && (type == 9 || (type == 8
1576 && !demux->has_video))) {
1577 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1581 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1582 demux->duration = ret;
1585 gst_buffer_unmap (buffer, &map);
1589 static GstFlowReturn
1590 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1592 GstFlowReturn ret = GST_FLOW_OK;
1593 guint8 tag_type = 0;
1596 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1598 gst_buffer_map (buffer, &map, GST_MAP_READ);
1600 tag_type = map.data[0];
1604 demux->state = FLV_STATE_TAG_VIDEO;
1605 demux->has_video = TRUE;
1608 demux->state = FLV_STATE_TAG_AUDIO;
1609 demux->has_audio = TRUE;
1612 demux->state = FLV_STATE_TAG_SCRIPT;
1615 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1618 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1619 * 4 bytes of previous tag size */
1620 demux->tag_data_size = GST_READ_UINT24_BE (map.data + 1);
1621 demux->tag_size = demux->tag_data_size + 11;
1623 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1624 demux->tag_data_size);
1626 gst_buffer_unmap (buffer, &map);
1631 static GstFlowReturn
1632 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1634 GstFlowReturn ret = GST_FLOW_OK;
1637 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1639 gst_buffer_map (buffer, &map, GST_MAP_READ);
1641 /* Check for the FLV tag */
1642 if (map.data[0] == 'F' && map.data[1] == 'L' && map.data[2] == 'V') {
1643 GST_DEBUG_OBJECT (demux, "FLV header detected");
1645 if (G_UNLIKELY (demux->strict)) {
1646 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1652 /* Now look at audio/video flags */
1654 guint8 flags = map.data[4];
1656 demux->has_video = demux->has_audio = FALSE;
1659 GST_DEBUG_OBJECT (demux, "there is a video stream");
1660 demux->has_video = TRUE;
1663 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1664 demux->has_audio = TRUE;
1668 /* do a one-time seekability check */
1669 gst_flv_demux_check_seekability (demux);
1671 /* We don't care about the rest */
1672 demux->need_header = FALSE;
1675 gst_buffer_unmap (buffer, &map);
1681 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1683 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1685 gst_adapter_clear (demux->adapter);
1687 demux->audio_need_discont = TRUE;
1688 demux->video_need_discont = TRUE;
1690 demux->flushing = FALSE;
1692 /* Only in push mode and if we're not during a seek */
1693 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1694 /* After a flush we expect a tag_type */
1695 demux->state = FLV_STATE_TAG_TYPE;
1696 /* We reset the offset and will get one from first push */
1702 gst_flv_demux_cleanup (GstFlvDemux * demux)
1704 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1706 demux->state = FLV_STATE_HEADER;
1708 demux->flushing = FALSE;
1709 demux->need_header = TRUE;
1710 demux->audio_need_segment = TRUE;
1711 demux->video_need_segment = TRUE;
1712 demux->audio_need_discont = TRUE;
1713 demux->video_need_discont = TRUE;
1715 /* By default we consider them as linked */
1716 demux->audio_linked = TRUE;
1717 demux->video_linked = TRUE;
1719 demux->has_audio = FALSE;
1720 demux->has_video = FALSE;
1721 demux->push_tags = FALSE;
1722 demux->got_par = FALSE;
1724 demux->indexed = FALSE;
1725 demux->upstream_seekable = FALSE;
1726 demux->file_size = 0;
1728 demux->index_max_pos = 0;
1729 demux->index_max_time = 0;
1731 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1732 demux->last_audio_pts = demux->last_video_pts = 0;
1733 demux->audio_time_offset = demux->video_time_offset = 0;
1735 demux->no_more_pads = FALSE;
1737 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1739 demux->w = demux->h = 0;
1740 demux->framerate = 0.0;
1741 demux->par_x = demux->par_y = 1;
1742 demux->video_offset = 0;
1743 demux->audio_offset = 0;
1744 demux->offset = demux->cur_tag_offset = 0;
1745 demux->tag_size = demux->tag_data_size = 0;
1746 demux->duration = GST_CLOCK_TIME_NONE;
1748 if (demux->new_seg_event) {
1749 gst_event_unref (demux->new_seg_event);
1750 demux->new_seg_event = NULL;
1753 gst_adapter_clear (demux->adapter);
1755 if (demux->audio_codec_data) {
1756 gst_buffer_unref (demux->audio_codec_data);
1757 demux->audio_codec_data = NULL;
1760 if (demux->video_codec_data) {
1761 gst_buffer_unref (demux->video_codec_data);
1762 demux->video_codec_data = NULL;
1765 if (demux->audio_pad) {
1766 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1767 gst_object_unref (demux->audio_pad);
1768 demux->audio_pad = NULL;
1771 if (demux->video_pad) {
1772 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1773 gst_object_unref (demux->video_pad);
1774 demux->video_pad = NULL;
1778 g_array_free (demux->times, TRUE);
1779 demux->times = NULL;
1782 if (demux->filepositions) {
1783 g_array_free (demux->filepositions, TRUE);
1784 demux->filepositions = NULL;
1789 * Create and push a flushing seek event upstream
1792 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1797 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1800 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1801 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1802 GST_SEEK_TYPE_NONE, -1);
1804 res = gst_pad_push_event (demux->sinkpad, event);
1807 demux->offset = offset;
1811 static GstFlowReturn
1812 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1814 GstFlowReturn ret = GST_FLOW_OK;
1815 GstFlvDemux *demux = NULL;
1817 demux = GST_FLV_DEMUX (parent);
1819 GST_LOG_OBJECT (demux,
1820 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
1821 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
1822 GST_BUFFER_OFFSET (buffer));
1824 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1825 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1826 demux->state = FLV_STATE_HEADER;
1830 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
1831 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
1832 demux->offset = GST_BUFFER_OFFSET (buffer);
1835 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1836 GST_DEBUG_OBJECT (demux, "Discontinuity");
1837 gst_adapter_clear (demux->adapter);
1840 gst_adapter_push (demux->adapter, buffer);
1842 if (demux->seeking) {
1843 demux->state = FLV_STATE_SEEK;
1844 GST_OBJECT_LOCK (demux);
1845 demux->seeking = FALSE;
1846 GST_OBJECT_UNLOCK (demux);
1850 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1851 if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
1852 || demux->video_linked)) {
1855 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
1860 if (G_UNLIKELY (demux->flushing)) {
1861 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
1862 ret = GST_FLOW_FLUSHING;
1866 switch (demux->state) {
1867 case FLV_STATE_HEADER:
1869 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
1872 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
1874 ret = gst_flv_demux_parse_header (demux, buffer);
1876 gst_buffer_unref (buffer);
1877 demux->offset += FLV_HEADER_SIZE;
1879 demux->state = FLV_STATE_TAG_TYPE;
1885 case FLV_STATE_TAG_TYPE:
1887 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
1890 /* Remember the tag offset in bytes */
1891 demux->cur_tag_offset = demux->offset;
1893 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
1895 ret = gst_flv_demux_parse_tag_type (demux, buffer);
1897 gst_buffer_unref (buffer);
1898 demux->offset += FLV_TAG_TYPE_SIZE;
1900 /* last tag is not an index => no index/don't know where the index is
1901 * seek back to the beginning */
1902 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
1910 case FLV_STATE_TAG_VIDEO:
1912 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1915 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1917 ret = gst_flv_demux_parse_tag_video (demux, buffer);
1919 gst_buffer_unref (buffer);
1920 demux->offset += demux->tag_size;
1922 demux->state = FLV_STATE_TAG_TYPE;
1928 case FLV_STATE_TAG_AUDIO:
1930 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1933 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1935 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
1937 gst_buffer_unref (buffer);
1938 demux->offset += demux->tag_size;
1940 demux->state = FLV_STATE_TAG_TYPE;
1946 case FLV_STATE_TAG_SCRIPT:
1948 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1951 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1953 ret = gst_flv_demux_parse_tag_script (demux, buffer);
1955 gst_buffer_unref (buffer);
1956 demux->offset += demux->tag_size;
1958 demux->state = FLV_STATE_TAG_TYPE;
1960 /* if there's a seek event we're here for the index so if we don't have it
1961 * we seek back to the beginning */
1962 if (demux->seek_event) {
1964 demux->state = FLV_STATE_SEEK;
1974 case FLV_STATE_SEEK:
1980 if (!demux->indexed) {
1981 if (demux->offset == demux->file_size - sizeof (guint32)) {
1982 guint64 seek_offset;
1985 data = gst_adapter_take (demux->adapter, 4);
1989 seek_offset = demux->file_size - sizeof (guint32) -
1990 GST_READ_UINT32_BE (data);
1993 GST_INFO_OBJECT (demux,
1994 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
1996 demux->state = FLV_STATE_TAG_TYPE;
1997 flv_demux_seek_to_offset (demux, seek_offset);
2003 GST_OBJECT_LOCK (demux);
2004 event = demux->seek_event;
2005 demux->seek_event = NULL;
2006 GST_OBJECT_UNLOCK (demux);
2008 /* calculate and perform seek */
2009 if (!flv_demux_handle_seek_push (demux, event))
2012 gst_event_unref (event);
2013 demux->state = FLV_STATE_TAG_TYPE;
2017 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
2021 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2022 /* If either audio or video is linked we return GST_FLOW_OK */
2023 if (demux->audio_linked || demux->video_linked) {
2033 GST_OBJECT_LOCK (demux);
2034 demux->seeking = FALSE;
2035 gst_event_unref (demux->seek_event);
2036 demux->seek_event = NULL;
2037 GST_OBJECT_UNLOCK (demux);
2038 GST_WARNING_OBJECT (demux,
2039 "failed to find an index, seeking back to beginning");
2040 flv_demux_seek_to_offset (demux, 0);
2045 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2046 return GST_FLOW_ERROR;
2051 static GstFlowReturn
2052 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2053 guint size, GstBuffer ** buffer)
2057 ret = gst_pad_pull_range (pad, offset, size, buffer);
2058 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2059 GST_WARNING_OBJECT (demux,
2060 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2061 size, offset, gst_flow_get_name (ret));
2066 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2067 GST_WARNING_OBJECT (demux,
2068 "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
2069 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
2070 gst_buffer_unref (*buffer);
2079 static GstFlowReturn
2080 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2082 GstBuffer *buffer = NULL;
2083 GstFlowReturn ret = GST_FLOW_OK;
2085 /* Store tag offset */
2086 demux->cur_tag_offset = demux->offset;
2088 /* Get the first 4 bytes to identify tag type and size */
2089 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2090 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2093 /* Identify tag type */
2094 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2096 gst_buffer_unref (buffer);
2098 if (G_UNLIKELY (ret != GST_FLOW_OK))
2101 /* Jump over tag type + size */
2102 demux->offset += FLV_TAG_TYPE_SIZE;
2104 /* Pull the whole tag */
2106 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2107 demux->tag_size, &buffer)) != GST_FLOW_OK))
2110 switch (demux->state) {
2111 case FLV_STATE_TAG_VIDEO:
2112 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2114 case FLV_STATE_TAG_AUDIO:
2115 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2117 case FLV_STATE_TAG_SCRIPT:
2118 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2121 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2124 gst_buffer_unref (buffer);
2126 /* Jump over that part we've just parsed */
2127 demux->offset += demux->tag_size;
2129 /* Make sure we reinitialize the tag size */
2130 demux->tag_size = 0;
2132 /* Ready for the next tag */
2133 demux->state = FLV_STATE_TAG_TYPE;
2135 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2136 /* If either audio or video is linked we return GST_FLOW_OK */
2137 if (demux->audio_linked || demux->video_linked) {
2140 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2141 "neither video nor audio are linked");
2149 static GstFlowReturn
2150 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2152 GstBuffer *buffer = NULL;
2153 GstFlowReturn ret = GST_FLOW_OK;
2155 /* Get the first 9 bytes */
2156 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2157 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2160 ret = gst_flv_demux_parse_header (demux, buffer);
2162 gst_buffer_unref (buffer);
2164 /* Jump over the header now */
2165 demux->offset += FLV_HEADER_SIZE;
2166 demux->state = FLV_STATE_TAG_TYPE;
2173 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2176 demux->offset = offset;
2178 /* Tell all the stream we moved to a different position (discont) */
2179 demux->audio_need_discont = TRUE;
2180 demux->video_need_discont = TRUE;
2182 /* next section setup */
2183 demux->from_offset = -1;
2184 demux->audio_done = demux->video_done = FALSE;
2185 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2188 demux->from_offset = -1;
2189 demux->to_offset = G_MAXINT64;
2192 /* If we seeked at the beginning of the file parse the header again */
2193 if (G_UNLIKELY (!demux->offset)) {
2194 demux->state = FLV_STATE_HEADER;
2195 } else { /* or parse a tag */
2196 demux->state = FLV_STATE_TAG_TYPE;
2200 static GstFlowReturn
2201 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2203 GstFlowReturn ret = GST_FLOW_EOS;
2205 GstIndexEntry *entry = NULL;
2207 GST_DEBUG_OBJECT (demux,
2208 "terminated section started at offset %" G_GINT64_FORMAT,
2209 demux->from_offset);
2211 /* we are done if we got all audio and video */
2212 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2213 demux->audio_first_ts < demux->segment.start) &&
2214 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2215 demux->video_first_ts < demux->segment.start))
2218 if (demux->from_offset <= 0)
2221 GST_DEBUG_OBJECT (demux, "locating previous position");
2223 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2225 /* locate index entry before previous start position */
2227 entry = gst_index_get_assoc_entry (index, demux->index_id,
2228 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2229 GST_FORMAT_BYTES, demux->from_offset - 1);
2232 gint64 bytes = 0, time = 0;
2234 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2235 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2237 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2238 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2239 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2241 /* setup for next section */
2242 demux->to_offset = demux->from_offset;
2243 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2247 gst_object_unref (index);
2255 static GstFlowReturn
2256 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2262 GstClockTime tag_time;
2263 GstFlowReturn ret = GST_FLOW_OK;
2265 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2268 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2269 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2271 old_offset = demux->offset;
2272 demux->offset = pos;
2275 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2276 12, &buffer)) == GST_FLOW_OK) {
2278 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2280 gst_buffer_unref (buffer);
2283 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2286 demux->offset += tag_size;
2289 if (ret == GST_FLOW_EOS) {
2290 /* file ran out, so mark we have complete index */
2291 demux->indexed = TRUE;
2296 demux->offset = old_offset;
2302 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2304 gint64 ret = 0, offset;
2305 size_t tag_size, size;
2306 GstBuffer *buffer = NULL;
2309 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2313 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2314 if (G_UNLIKELY (offset < 4))
2318 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2322 gst_buffer_map (buffer, &map, GST_MAP_READ);
2323 tag_size = GST_READ_UINT32_BE (map.data);
2324 gst_buffer_unmap (buffer, &map);
2325 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2326 gst_buffer_unref (buffer);
2330 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2334 /* a consistency check */
2335 gst_buffer_map (buffer, &map, GST_MAP_READ);
2336 size = GST_READ_UINT24_BE (map.data + 1);
2337 if (size != tag_size - 11) {
2338 gst_buffer_unmap (buffer, &map);
2339 GST_DEBUG_OBJECT (demux,
2340 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2341 ", corrupt or truncated file", size, tag_size - 11);
2345 /* try to update duration with timestamp in any case */
2346 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2348 /* maybe get some more metadata */
2349 if (map.data[0] == 18) {
2350 gst_buffer_unmap (buffer, &map);
2351 gst_buffer_unref (buffer);
2353 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2355 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2357 gst_flv_demux_parse_tag_script (demux, buffer);
2359 gst_buffer_unmap (buffer, &map);
2364 gst_buffer_unref (buffer);
2370 gst_flv_demux_loop (GstPad * pad)
2372 GstFlvDemux *demux = NULL;
2373 GstFlowReturn ret = GST_FLOW_OK;
2375 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2378 switch (demux->state) {
2379 case FLV_STATE_TAG_TYPE:
2380 if (demux->from_offset == -1)
2381 demux->from_offset = demux->offset;
2382 ret = gst_flv_demux_pull_tag (pad, demux);
2383 /* if we have seen real data, we probably passed a possible metadata
2384 * header located at start. So if we do not yet have an index,
2385 * try to pick up metadata (index, duration) at the end */
2386 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2387 (demux->has_video || demux->has_audio)))
2388 demux->file_size = gst_flv_demux_get_metadata (demux);
2390 case FLV_STATE_DONE:
2393 case FLV_STATE_SEEK:
2394 /* seek issued with insufficient index;
2395 * scan for index in task thread from current maximum offset to
2396 * desired time and then perform seek */
2397 /* TODO maybe some buffering message or so to indicate scan progress */
2398 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2400 if (ret != GST_FLOW_OK)
2402 /* position and state arranged by seek,
2403 * also unrefs event */
2404 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2405 demux->seek_event = NULL;
2408 ret = gst_flv_demux_pull_header (pad, demux);
2409 /* index scans start after header */
2410 demux->index_max_pos = demux->offset;
2414 if (demux->segment.rate < 0.0) {
2415 /* check end of section */
2416 if ((gint64) demux->offset >= demux->to_offset ||
2417 demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2418 (demux->audio_done && demux->video_done))
2419 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2421 /* check EOS condition */
2422 if ((demux->segment.stop != -1) &&
2423 (demux->segment.position >= demux->segment.stop)) {
2428 /* pause if something went wrong or at end */
2429 if (G_UNLIKELY (ret != GST_FLOW_OK))
2432 gst_object_unref (demux);
2438 const gchar *reason = gst_flow_get_name (ret);
2440 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2441 gst_pad_pause_task (pad);
2443 if (ret == GST_FLOW_EOS) {
2444 /* handle end-of-stream/segment */
2445 /* so align our position with the end of it, if there is one
2446 * this ensures a subsequent will arrive at correct base/acc time */
2447 if (demux->segment.rate > 0.0 &&
2448 GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2449 demux->segment.position = demux->segment.stop;
2450 else if (demux->segment.rate < 0.0)
2451 demux->segment.position = demux->segment.start;
2453 /* perform EOS logic */
2454 if (!demux->no_more_pads) {
2455 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2456 demux->no_more_pads = TRUE;
2459 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2462 /* for segment playback we need to post when (in stream time)
2463 * we stopped, this is either stop (when set) or the duration. */
2464 if ((stop = demux->segment.stop) == -1)
2465 stop = demux->segment.duration;
2467 if (demux->segment.rate >= 0) {
2468 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2469 gst_element_post_message (GST_ELEMENT_CAST (demux),
2470 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2471 GST_FORMAT_TIME, stop));
2472 gst_flv_demux_push_src_event (demux,
2473 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2474 } else { /* Reverse playback */
2475 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2477 gst_element_post_message (GST_ELEMENT_CAST (demux),
2478 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2479 GST_FORMAT_TIME, demux->segment.start));
2480 gst_flv_demux_push_src_event (demux,
2481 gst_event_new_segment_done (GST_FORMAT_TIME,
2482 demux->segment.start));
2485 /* normal playback, send EOS to all linked pads */
2486 if (!demux->no_more_pads) {
2487 gst_element_no_more_pads (GST_ELEMENT (demux));
2488 demux->no_more_pads = TRUE;
2491 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2492 if (!demux->audio_pad && !demux->video_pad)
2493 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2494 ("Internal data stream error."), ("Got EOS before any data"));
2495 else if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2496 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2498 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2499 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2500 ("Internal data stream error."),
2501 ("stream stopped, reason %s", reason));
2502 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2504 gst_object_unref (demux);
2510 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2515 GstIndexEntry *entry;
2517 g_return_val_if_fail (segment != NULL, 0);
2519 time = segment->position;
2521 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2524 /* Let's check if we have an index entry for that seek time */
2525 entry = gst_index_get_assoc_entry (index, demux->index_id,
2526 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2527 GST_FORMAT_TIME, time);
2530 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2531 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2533 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2534 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2535 GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2537 /* Key frame seeking */
2538 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2539 /* Adjust the segment so that the keyframe fits in */
2540 if (time < segment->start) {
2541 segment->start = segment->time = time;
2543 segment->position = time;
2546 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2547 GST_TIME_ARGS (segment->start));
2550 gst_object_unref (index);
2557 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2561 GstSeekType start_type, stop_type;
2564 gboolean update, flush, ret;
2565 GstSegment seeksegment;
2567 gst_event_parse_seek (event, &rate, &format, &flags,
2568 &start_type, &start, &stop_type, &stop);
2570 if (format != GST_FORMAT_TIME)
2573 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2574 /* FIXME : the keyframe flag is never used ! */
2576 /* Work on a copy until we are sure the seek succeeded. */
2577 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2579 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2582 /* Apply the seek to our segment */
2583 gst_segment_do_seek (&seeksegment, rate, format, flags,
2584 start_type, start, stop_type, stop, &update);
2586 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2589 if (flush || seeksegment.position != demux->segment.position) {
2590 /* Do the actual seeking */
2591 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2593 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2594 G_GUINT64_FORMAT, offset);
2595 ret = gst_pad_push_event (demux->sinkpad,
2596 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2597 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2598 offset, GST_SEEK_TYPE_NONE, 0));
2599 if (G_UNLIKELY (!ret)) {
2600 GST_WARNING_OBJECT (demux, "upstream seek failed");
2603 /* Tell all the stream we moved to a different position (discont) */
2604 demux->audio_need_discont = TRUE;
2605 demux->video_need_discont = TRUE;
2611 /* Ok seek succeeded, take the newly configured segment */
2612 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2614 /* Tell all the stream a new segment is needed */
2615 demux->audio_need_segment = TRUE;
2616 demux->video_need_segment = TRUE;
2617 /* Clean any potential newsegment event kept for the streams. The first
2618 * stream needing a new segment will create a new one. */
2619 if (G_UNLIKELY (demux->new_seg_event)) {
2620 gst_event_unref (demux->new_seg_event);
2621 demux->new_seg_event = NULL;
2623 gst_event_unref (event);
2625 ret = gst_pad_push_event (demux->sinkpad, event);
2633 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2634 gst_event_unref (event);
2640 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2644 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2646 if (format != GST_FORMAT_TIME) {
2647 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2648 gst_event_unref (event);
2652 /* First try upstream */
2653 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2654 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2655 gst_event_unref (event);
2659 if (!demux->indexed) {
2660 guint64 seek_offset = 0;
2661 gboolean building_index;
2663 GST_OBJECT_LOCK (demux);
2664 /* handle the seek in the chain function */
2665 demux->seeking = TRUE;
2666 demux->state = FLV_STATE_SEEK;
2668 /* copy the event */
2669 if (demux->seek_event)
2670 gst_event_unref (demux->seek_event);
2671 demux->seek_event = gst_event_ref (event);
2673 /* set the building_index flag so that only one thread can setup the
2674 * structures for index seeking. */
2675 building_index = demux->building_index;
2676 if (!building_index) {
2677 demux->building_index = TRUE;
2678 if (!demux->file_size
2679 && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2680 &demux->file_size)) {
2681 GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2682 GST_OBJECT_UNLOCK (demux);
2686 /* we hope the last tag is a scriptdataobject containing an index
2687 * the size of the last tag is given in the last guint32 bits
2688 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2689 seek_offset = demux->file_size - sizeof (guint32);
2690 GST_DEBUG_OBJECT (demux,
2691 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2693 GST_OBJECT_UNLOCK (demux);
2695 if (!building_index) {
2696 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2698 return flv_demux_seek_to_offset (demux, seek_offset);
2701 /* FIXME: we have to always return true so that we don't block the seek
2703 * Note: maybe it is OK to return true if we're still building the index */
2707 return flv_demux_handle_seek_push (demux, event);
2711 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2716 GstSeekType start_type, stop_type;
2719 gboolean update, flush, ret = FALSE;
2720 GstSegment seeksegment;
2722 gst_event_parse_seek (event, &rate, &format, &flags,
2723 &start_type, &start, &stop_type, &stop);
2725 if (format != GST_FORMAT_TIME)
2728 /* mark seeking thread entering flushing/pausing */
2729 GST_OBJECT_LOCK (demux);
2731 demux->seeking = seeking;
2732 GST_OBJECT_UNLOCK (demux);
2734 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2735 /* FIXME : the keyframe flag is never used */
2738 /* Flush start up and downstream to make sure data flow and loops are
2740 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2741 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2743 /* Pause the pulling task */
2744 gst_pad_pause_task (demux->sinkpad);
2747 /* Take the stream lock */
2748 GST_PAD_STREAM_LOCK (demux->sinkpad);
2751 /* Stop flushing upstream we need to pull */
2752 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2755 /* Work on a copy until we are sure the seek succeeded. */
2756 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2758 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2761 /* Apply the seek to our segment */
2762 gst_segment_do_seek (&seeksegment, rate, format, flags,
2763 start_type, start, stop_type, stop, &update);
2765 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2768 if (flush || seeksegment.position != demux->segment.position) {
2769 /* Do the actual seeking */
2770 /* index is reliable if it is complete or we do not go to far ahead */
2771 if (seeking && !demux->indexed &&
2772 seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2773 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2774 " index only up to %" GST_TIME_FORMAT,
2775 GST_TIME_ARGS (demux->index_max_time));
2776 /* stop flushing for now */
2778 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2779 /* delegate scanning and index building to task thread to avoid
2780 * occupying main (UI) loop */
2781 if (demux->seek_event)
2782 gst_event_unref (demux->seek_event);
2783 demux->seek_event = gst_event_ref (event);
2784 demux->seek_time = seeksegment.position;
2785 demux->state = FLV_STATE_SEEK;
2786 /* do not know about succes yet, but we did care and handled it */
2790 /* now index should be as reliable as it can be for current purpose */
2791 gst_flv_demux_move_to_offset (demux,
2792 gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2799 /* Stop flushing, the sinks are at time 0 now */
2800 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2804 /* Ok seek succeeded, take the newly configured segment */
2805 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2807 /* Notify about the start of a new segment */
2808 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2809 gst_element_post_message (GST_ELEMENT (demux),
2810 gst_message_new_segment_start (GST_OBJECT (demux),
2811 demux->segment.format, demux->segment.position));
2814 /* Tell all the stream a new segment is needed */
2815 demux->audio_need_segment = TRUE;
2816 demux->video_need_segment = TRUE;
2817 /* Clean any potential newsegment event kept for the streams. The first
2818 * stream needing a new segment will create a new one. */
2819 if (G_UNLIKELY (demux->new_seg_event)) {
2820 gst_event_unref (demux->new_seg_event);
2821 demux->new_seg_event = NULL;
2823 if (demux->segment.rate < 0.0) {
2824 /* we can't generate a segment by locking on
2825 * to the first timestamp we see */
2826 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2827 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2828 GST_TIME_ARGS (demux->segment.start),
2829 GST_TIME_ARGS (demux->segment.stop));
2830 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2835 GST_OBJECT_LOCK (demux);
2836 seeking = demux->seeking && !seeking;
2837 demux->seeking = FALSE;
2838 GST_OBJECT_UNLOCK (demux);
2840 /* if we detect an external seek having started (and possibly already having
2841 * flushed), do not restart task to give it a chance.
2842 * Otherwise external one's flushing will take care to pause task */
2844 gst_pad_pause_task (demux->sinkpad);
2846 gst_pad_start_task (demux->sinkpad,
2847 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad, NULL);
2850 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2852 gst_event_unref (event);
2858 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2859 gst_event_unref (event);
2864 /* If we can pull that's prefered */
2866 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
2871 query = gst_query_new_scheduling ();
2873 if (!gst_pad_peer_query (sinkpad, query)) {
2874 gst_query_unref (query);
2878 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
2879 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
2880 gst_query_unref (query);
2885 GST_DEBUG_OBJECT (sinkpad, "activating pull");
2886 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
2890 GST_DEBUG_OBJECT (sinkpad, "activating push");
2891 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
2896 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
2897 GstPadMode mode, gboolean active)
2902 demux = GST_FLV_DEMUX (parent);
2905 case GST_PAD_MODE_PUSH:
2906 demux->random_access = FALSE;
2909 case GST_PAD_MODE_PULL:
2911 demux->random_access = TRUE;
2912 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
2915 demux->random_access = FALSE;
2916 res = gst_pad_stop_task (sinkpad);
2927 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
2930 gboolean ret = FALSE;
2932 demux = GST_FLV_DEMUX (parent);
2934 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2936 switch (GST_EVENT_TYPE (event)) {
2937 case GST_EVENT_FLUSH_START:
2938 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
2939 demux->flushing = TRUE;
2940 ret = gst_flv_demux_push_src_event (demux, event);
2942 case GST_EVENT_FLUSH_STOP:
2943 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
2944 gst_flv_demux_flush (demux, TRUE);
2945 ret = gst_flv_demux_push_src_event (demux, event);
2951 GST_DEBUG_OBJECT (demux, "received EOS");
2953 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2956 GST_DEBUG_OBJECT (demux, "committing index");
2957 gst_index_commit (index, demux->index_id);
2958 gst_object_unref (index);
2961 if (!demux->audio_pad && !demux->video_pad)
2962 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2963 ("Internal data stream error."), ("Got EOS before any data"));
2965 if (!demux->no_more_pads) {
2966 gst_element_no_more_pads (GST_ELEMENT (demux));
2967 demux->no_more_pads = TRUE;
2970 if (!gst_flv_demux_push_src_event (demux, event))
2971 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2976 case GST_EVENT_SEGMENT:
2978 GstSegment in_segment;
2980 GST_DEBUG_OBJECT (demux, "received new segment");
2982 gst_event_copy_segment (event, &in_segment);
2984 if (in_segment.format == GST_FORMAT_TIME) {
2985 /* time segment, this is perfect, copy over the values. */
2986 memcpy (&demux->segment, &in_segment, sizeof (in_segment));
2988 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
2992 ret = gst_flv_demux_push_src_event (demux, event);
2994 /* non-time format */
2995 demux->audio_need_segment = TRUE;
2996 demux->video_need_segment = TRUE;
2998 gst_event_unref (event);
2999 if (demux->new_seg_event) {
3000 gst_event_unref (demux->new_seg_event);
3001 demux->new_seg_event = NULL;
3007 ret = gst_flv_demux_push_src_event (demux, event);
3015 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
3018 gboolean ret = FALSE;
3020 demux = GST_FLV_DEMUX (parent);
3022 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3024 switch (GST_EVENT_TYPE (event)) {
3025 case GST_EVENT_SEEK:
3026 if (demux->random_access) {
3027 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
3029 ret = gst_flv_demux_handle_seek_push (demux, event);
3033 ret = gst_pad_push_event (demux->sinkpad, event);
3041 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
3043 gboolean res = TRUE;
3046 demux = GST_FLV_DEMUX (parent);
3048 switch (GST_QUERY_TYPE (query)) {
3049 case GST_QUERY_DURATION:
3053 gst_query_parse_duration (query, &format, NULL);
3055 /* duration is time only */
3056 if (format != GST_FORMAT_TIME) {
3057 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
3063 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3064 GST_TIME_ARGS (demux->duration));
3066 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3070 case GST_QUERY_POSITION:
3074 gst_query_parse_position (query, &format, NULL);
3076 /* position is time only */
3077 if (format != GST_FORMAT_TIME) {
3078 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3084 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3085 GST_TIME_ARGS (demux->segment.position));
3087 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3092 case GST_QUERY_SEEKING:{
3095 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3097 /* First ask upstream */
3098 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3101 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3108 /* FIXME, check index this way is not thread safe */
3109 if (fmt != GST_FORMAT_TIME || !demux->index) {
3110 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3111 } else if (demux->random_access) {
3112 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3115 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3116 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3119 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3120 gst_query_unref (peerquery);
3123 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3126 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3130 case GST_QUERY_LATENCY:
3132 res = gst_pad_query_default (pad, parent, query);
3141 static GstStateChangeReturn
3142 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3145 GstStateChangeReturn ret;
3147 demux = GST_FLV_DEMUX (element);
3149 switch (transition) {
3150 case GST_STATE_CHANGE_READY_TO_PAUSED:
3151 /* If this is our own index destroy it as the
3152 * old entries might be wrong for the new stream */
3153 if (demux->own_index) {
3154 gst_object_unref (demux->index);
3155 demux->index = NULL;
3156 demux->own_index = FALSE;
3159 /* If no index was created, generate one */
3160 if (G_UNLIKELY (!demux->index)) {
3161 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3163 demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3165 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3167 demux->own_index = TRUE;
3169 gst_flv_demux_cleanup (demux);
3175 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3176 if (ret == GST_STATE_CHANGE_FAILURE)
3179 switch (transition) {
3180 case GST_STATE_CHANGE_PAUSED_TO_READY:
3181 gst_flv_demux_cleanup (demux);
3192 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3194 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3195 GstIndex *old_index;
3197 GST_OBJECT_LOCK (demux);
3199 old_index = demux->index;
3202 demux->index = gst_object_ref (index);
3203 demux->own_index = FALSE;
3205 demux->index = NULL;
3208 gst_object_unref (demux->index);
3210 gst_object_ref (index);
3212 GST_OBJECT_UNLOCK (demux);
3214 /* object lock might be taken again */
3216 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3218 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3220 gst_object_unref (index);
3225 gst_flv_demux_get_index (GstElement * element)
3227 GstIndex *result = NULL;
3229 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3231 GST_OBJECT_LOCK (demux);
3233 result = gst_object_ref (demux->index);
3234 GST_OBJECT_UNLOCK (demux);
3240 gst_flv_demux_dispose (GObject * object)
3242 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3244 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3246 if (demux->adapter) {
3247 gst_adapter_clear (demux->adapter);
3248 g_object_unref (demux->adapter);
3249 demux->adapter = NULL;
3252 if (demux->taglist) {
3253 gst_tag_list_unref (demux->taglist);
3254 demux->taglist = NULL;
3257 if (demux->new_seg_event) {
3258 gst_event_unref (demux->new_seg_event);
3259 demux->new_seg_event = NULL;
3262 if (demux->audio_codec_data) {
3263 gst_buffer_unref (demux->audio_codec_data);
3264 demux->audio_codec_data = NULL;
3267 if (demux->video_codec_data) {
3268 gst_buffer_unref (demux->video_codec_data);
3269 demux->video_codec_data = NULL;
3272 if (demux->audio_pad) {
3273 gst_object_unref (demux->audio_pad);
3274 demux->audio_pad = NULL;
3277 if (demux->video_pad) {
3278 gst_object_unref (demux->video_pad);
3279 demux->video_pad = NULL;
3283 gst_object_unref (demux->index);
3284 demux->index = NULL;
3288 g_array_free (demux->times, TRUE);
3289 demux->times = NULL;
3292 if (demux->filepositions) {
3293 g_array_free (demux->filepositions, TRUE);
3294 demux->filepositions = NULL;
3297 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3301 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3303 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3304 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3306 gobject_class->dispose = gst_flv_demux_dispose;
3308 gstelement_class->change_state =
3309 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3312 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3313 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3316 gst_element_class_add_pad_template (gstelement_class,
3317 gst_static_pad_template_get (&flv_sink_template));
3318 gst_element_class_add_pad_template (gstelement_class,
3319 gst_static_pad_template_get (&audio_src_template));
3320 gst_element_class_add_pad_template (gstelement_class,
3321 gst_static_pad_template_get (&video_src_template));
3322 gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
3324 "Demux FLV feeds into digital streams",
3325 "Julien Moutte <julien@moutte.net>");
3329 gst_flv_demux_init (GstFlvDemux * demux)
3332 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3334 gst_pad_set_event_function (demux->sinkpad,
3335 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3336 gst_pad_set_chain_function (demux->sinkpad,
3337 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3338 gst_pad_set_activate_function (demux->sinkpad,
3339 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3340 gst_pad_set_activatemode_function (demux->sinkpad,
3341 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3343 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3345 demux->adapter = gst_adapter_new ();
3346 demux->taglist = gst_tag_list_new_empty ();
3347 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3349 demux->own_index = FALSE;
3351 GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3353 gst_flv_demux_cleanup (demux);
3357 plugin_init (GstPlugin * plugin)
3359 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3361 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3362 gst_flv_demux_get_type ()) ||
3363 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3364 gst_flv_mux_get_type ()))
3370 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3371 flv, "FLV muxing and demuxing plugin",
3372 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)