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 -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>
45 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
48 GST_STATIC_CAPS ("video/x-flv")
51 static GstStaticPadTemplate audio_src_template =
52 GST_STATIC_PAD_TEMPLATE ("audio",
56 ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
57 "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
58 "audio/mpeg, mpegversion = (int) 4, framed = (boolean) TRUE; "
59 "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
60 "audio/x-raw-int, endianness = (int) LITTLE_ENDIAN, channels = (int) { 1, 2 }, width = (int) 8, depth = (int) 8, rate = (int) { 5512, 11025, 22050, 44100 }, signed = (boolean) FALSE; "
61 "audio/x-raw-int, endianness = (int) LITTLE_ENDIAN, channels = (int) { 1, 2 }, width = (int) 16, depth = (int) 16, rate = (int) { 5512, 11025, 22050, 44100 }, signed = (boolean) TRUE; "
62 "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
63 "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
64 "audio/x-speex, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 };")
67 static GstStaticPadTemplate video_src_template =
68 GST_STATIC_PAD_TEMPLATE ("video",
71 GST_STATIC_CAPS ("video/x-flash-video; "
72 "video/x-flash-screen; "
73 "video/x-vp6-flash; " "video/x-vp6-alpha; "
74 "video/x-h264, stream-format=avc;")
77 GST_DEBUG_CATEGORY_STATIC (flvdemux_debug);
78 #define GST_CAT_DEFAULT flvdemux_debug
80 GST_BOILERPLATE (GstFlvDemux, gst_flv_demux, GstElement, GST_TYPE_ELEMENT);
82 /* 9 bytes of header + 4 bytes of first previous tag size */
83 #define FLV_HEADER_SIZE 13
84 /* 1 byte of tag type + 3 bytes of tag data size */
85 #define FLV_TAG_TYPE_SIZE 4
87 /* two seconds - consider pts are resynced to another base if this different */
88 #define RESYNC_THRESHOLD 2000
90 static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
92 static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
93 GstEvent * event, gboolean seeking);
95 static gboolean gst_flv_demux_query (GstPad * pad, GstQuery * query);
96 static gboolean gst_flv_demux_src_event (GstPad * pad, GstEvent * event);
100 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
101 guint64 pos, gboolean keyframe)
103 static GstIndexAssociation associations[2];
104 static GstIndexEntry *entry;
106 GST_LOG_OBJECT (demux,
107 "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
108 keyframe, GST_TIME_ARGS (ts), pos);
110 /* if upstream is not seekable there is no point in building an index */
111 if (!demux->upstream_seekable)
114 /* entry may already have been added before, avoid adding indefinitely */
115 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
116 GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
119 #ifndef GST_DISABLE_GST_DEBUG
123 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
124 key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
125 GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
126 ", keyframe %d", GST_TIME_ARGS (time), key);
127 /* there is not really a way to delete the existing one */
128 if (time != ts || key != ! !keyframe)
129 GST_DEBUG_OBJECT (demux, "metadata mismatch");
134 associations[0].format = GST_FORMAT_TIME;
135 associations[0].value = ts;
136 associations[1].format = GST_FORMAT_BYTES;
137 associations[1].value = pos;
139 gst_index_add_associationv (demux->index, demux->index_id,
140 (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
141 GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
142 (const GstIndexAssociation *) &associations);
144 if (pos > demux->index_max_pos)
145 demux->index_max_pos = pos;
146 if (ts > demux->index_max_time)
147 demux->index_max_time = ts;
151 FLV_GET_STRING (GstByteReader * reader)
153 guint16 string_size = 0;
154 gchar *string = NULL;
155 const guint8 *str = NULL;
157 g_return_val_if_fail (reader != NULL, NULL);
159 if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
162 if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
165 string = g_try_malloc0 (string_size + 1);
166 if (G_UNLIKELY (!string)) {
170 if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
175 memcpy (string, str, string_size);
176 if (!g_utf8_validate (string, string_size, NULL)) {
184 static const GstQueryType *
185 gst_flv_demux_query_types (GstPad * pad)
187 static const GstQueryType query_types[] = {
198 gst_flv_demux_check_seekability (GstFlvDemux * demux)
201 gint64 start = -1, stop = -1;
203 demux->upstream_seekable = FALSE;
205 query = gst_query_new_seeking (GST_FORMAT_BYTES);
206 if (!gst_pad_peer_query (demux->sinkpad, query)) {
207 GST_DEBUG_OBJECT (demux, "seeking query failed");
208 gst_query_unref (query);
212 gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
215 gst_query_unref (query);
217 /* try harder to query upstream size if we didn't get it the first time */
218 if (demux->upstream_seekable && stop == -1) {
219 GstFormat fmt = GST_FORMAT_BYTES;
221 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
222 gst_pad_query_peer_duration (demux->sinkpad, &fmt, &stop);
225 /* if upstream doesn't know the size, it's likely that it's not seekable in
226 * practice even if it technically may be seekable */
227 if (demux->upstream_seekable && (start != 0 || stop <= start)) {
228 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
229 demux->upstream_seekable = FALSE;
232 GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
236 parse_flv_demux_parse_date_string (GDate * date, const gchar * s)
238 g_date_set_parse (date, s);
239 if (g_date_valid (date))
242 /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
244 static const gchar *months[] = {
245 "Jan", "Feb", "Mar", "Apr",
246 "May", "Jun", "Jul", "Aug",
247 "Sep", "Oct", "Nov", "Dec"
249 gchar **tokens = g_strsplit (s, " ", -1);
254 if (g_strv_length (tokens) != 5)
257 if (strlen (tokens[1]) != 3)
259 for (i = 0; i < 12; i++) {
260 if (!strcmp (tokens[1], months[i])) {
266 g_date_set_month (date, i + 1);
268 d = g_ascii_strtoull (tokens[2], &endptr, 10);
269 if (d == 0 && *endptr != '\0')
272 g_date_set_day (date, d);
274 d = g_ascii_strtoull (tokens[4], &endptr, 10);
275 if (d == 0 && *endptr != '\0')
278 g_date_set_year (date, d);
287 gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
288 gboolean * end_marker)
290 gchar *tag_name = NULL;
293 /* Initialize the end_marker flag to FALSE */
296 /* Name of the tag */
297 tag_name = FLV_GET_STRING (reader);
298 if (G_UNLIKELY (!tag_name)) {
299 GST_WARNING_OBJECT (demux, "failed reading tag name");
303 /* What kind of object is that */
304 if (!gst_byte_reader_get_uint8 (reader, &tag_type))
307 GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
311 { /* Use a union to read the uint64 and then as a double */
314 if (!gst_byte_reader_get_float64_be (reader, &d))
317 GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
319 if (!strcmp (tag_name, "duration")) {
320 demux->duration = d * GST_SECOND;
322 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
323 GST_TAG_DURATION, demux->duration, NULL);
324 } else if (!strcmp (tag_name, "AspectRatioX")) {
326 demux->got_par = TRUE;
327 } else if (!strcmp (tag_name, "AspectRatioY")) {
329 demux->got_par = TRUE;
330 } else if (!strcmp (tag_name, "width")) {
332 } else if (!strcmp (tag_name, "height")) {
334 } else if (!strcmp (tag_name, "framerate")) {
335 demux->framerate = d;
337 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
346 if (!gst_byte_reader_get_uint8 (reader, &b))
349 GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
351 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
359 s = FLV_GET_STRING (reader);
363 GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
365 if (!strcmp (tag_name, "creationdate")) {
366 GDate *date = g_date_new ();
368 parse_flv_demux_parse_date_string (date, s);
369 if (!g_date_valid (date)) {
370 GST_DEBUG_OBJECT (demux, "Failed to parse string as date");
372 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
373 GST_TAG_DATE, date, NULL);
376 } else if (!strcmp (tag_name, "creator")) {
377 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
378 GST_TAG_ARTIST, s, NULL);
379 } else if (!strcmp (tag_name, "title")) {
380 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
381 GST_TAG_TITLE, s, NULL);
382 } else if (!strcmp (tag_name, "metadatacreator")) {
383 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
384 GST_TAG_ENCODER, s, NULL);
386 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
395 gboolean end_of_object_marker = FALSE;
397 while (!end_of_object_marker) {
398 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
399 &end_of_object_marker);
401 if (G_UNLIKELY (!ok)) {
402 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
409 case 8: // ECMA array
411 guint32 nb_elems = 0;
412 gboolean end_of_object_marker = FALSE;
414 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
417 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
420 while (!end_of_object_marker) {
421 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
422 &end_of_object_marker);
424 if (G_UNLIKELY (!ok)) {
425 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
432 case 9: // End marker
434 GST_DEBUG_OBJECT (demux, "end marker ?");
435 if (tag_name[0] == '\0') {
437 GST_DEBUG_OBJECT (demux, "end marker detected");
446 guint32 nb_elems = 0;
448 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
451 GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
453 if (!strcmp (tag_name, "times")) {
455 g_array_free (demux->times, TRUE);
457 demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
458 } else if (!strcmp (tag_name, "filepositions")) {
459 if (demux->filepositions) {
460 g_array_free (demux->filepositions, TRUE);
462 demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
466 guint8 elem_type = 0;
468 if (!gst_byte_reader_get_uint8 (reader, &elem_type))
476 if (!gst_byte_reader_get_float64_be (reader, &d))
479 GST_DEBUG_OBJECT (demux, "element is a double %f", d);
481 if (!strcmp (tag_name, "times") && demux->times) {
482 g_array_append_val (demux->times, d);
483 } else if (!strcmp (tag_name, "filepositions") &&
484 demux->filepositions) {
485 g_array_append_val (demux->filepositions, d);
490 GST_WARNING_OBJECT (demux, "unsupported array element type %d",
502 if (!gst_byte_reader_get_float64_be (reader, &d))
505 if (!gst_byte_reader_get_int16_be (reader, &i))
508 GST_DEBUG_OBJECT (demux,
509 "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
511 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
516 GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
530 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
532 GstFlowReturn ret = GST_FLOW_OK;
533 GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer);
536 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 7, GST_FLOW_ERROR);
538 gst_byte_reader_skip (&reader, 7);
540 GST_LOG_OBJECT (demux, "parsing a script tag");
542 if (!gst_byte_reader_get_uint8 (&reader, &type))
547 gchar *function_name;
550 function_name = FLV_GET_STRING (&reader);
552 GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
554 if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
555 gboolean end_marker = FALSE;
556 GST_DEBUG_OBJECT (demux, "we have a metadata script object");
558 if (!gst_byte_reader_get_uint8 (&reader, &type)) {
559 g_free (function_name);
566 guint32 nb_elems = 0;
569 if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
570 g_free (function_name);
574 /* The number of elements is just a hint, some files have
575 nb_elements == 0 and actually contain items. */
576 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
579 /* fallthrough to read data */
583 while (!end_marker) {
585 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
587 if (G_UNLIKELY (!ok)) {
588 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
595 GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
596 g_free (function_name);
600 demux->push_tags = TRUE;
603 g_free (function_name);
605 if (demux->index && demux->times && demux->filepositions) {
608 /* If an index was found, insert associations */
609 num = MIN (demux->times->len, demux->filepositions->len);
610 for (i = 0; i < num; i++) {
611 guint64 time, fileposition;
613 time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
614 fileposition = g_array_index (demux->filepositions, gdouble, i);
615 gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
618 demux->indexed = TRUE;
626 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
627 guint32 rate, guint32 channels, guint32 width)
629 GstCaps *caps = NULL;
630 gchar *codec_name = NULL;
631 gboolean ret = FALSE;
632 guint adjusted_rate = rate;
636 caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
641 caps = gst_caps_new_simple ("audio/mpeg",
642 "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
643 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
647 /* Assuming little endian for 0 (aka endianness of the
648 * system on which the file was created) as most people
649 * are probably using little endian machines */
650 caps = gst_caps_new_simple ("audio/x-raw-int",
651 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
652 "signed", G_TYPE_BOOLEAN, (width == 8) ? FALSE : TRUE,
653 "width", G_TYPE_INT, width, "depth", G_TYPE_INT, width, NULL);
658 caps = gst_caps_new_simple ("audio/x-nellymoser", NULL);
662 /* use codec-data to extract and verify samplerate */
663 if (demux->audio_codec_data &&
664 GST_BUFFER_SIZE (demux->audio_codec_data) >= 2) {
668 ((GST_READ_UINT16_BE (GST_BUFFER_DATA (demux->audio_codec_data))));
669 freq_index = (freq_index & 0x0780) >> 7;
671 gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
673 if (adjusted_rate && (rate != adjusted_rate)) {
674 GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
677 adjusted_rate = rate;
680 caps = gst_caps_new_simple ("audio/mpeg",
681 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
682 "stream-format", G_TYPE_STRING, "raw", NULL);
686 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
689 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
692 caps = gst_caps_new_simple ("audio/x-speex", NULL);
695 GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
698 if (G_UNLIKELY (!caps)) {
699 GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
703 gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
704 "channels", G_TYPE_INT, channels, NULL);
706 if (demux->audio_codec_data) {
707 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
708 demux->audio_codec_data, NULL);
711 ret = gst_pad_set_caps (demux->audio_pad, caps);
713 if (G_LIKELY (ret)) {
714 /* Store the caps we got from tags */
715 demux->audio_codec_tag = codec_tag;
717 demux->channels = channels;
718 demux->width = width;
720 codec_name = gst_pb_utils_get_codec_description (caps);
723 if (demux->taglist == NULL)
724 demux->taglist = gst_tag_list_new ();
725 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
726 GST_TAG_AUDIO_CODEC, codec_name, NULL);
730 GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
731 GST_PTR_FORMAT, caps);
733 GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
734 GST_PTR_FORMAT, caps);
737 gst_caps_unref (caps);
744 gst_flv_demux_push_tags (GstFlvDemux * demux)
746 if (demux->has_audio && !demux->audio_pad) {
747 GST_DEBUG_OBJECT (demux,
748 "Waiting for audio stream pad to come up before we can push tags");
751 if (demux->has_video && !demux->video_pad) {
752 GST_DEBUG_OBJECT (demux,
753 "Waiting for video stream pad to come up before we can push tags");
756 if (demux->taglist) {
757 GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
759 gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
760 demux->taglist = gst_tag_list_new ();
761 demux->push_tags = FALSE;
766 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, gboolean discont,
767 guint32 * last, GstClockTime * offset)
769 if (!discont && ABS (pts - *last) >= RESYNC_THRESHOLD) {
770 /* Theoretically, we should use substract the duration of the last buffer,
771 but this demuxer sends no durations on buffers, not sure if it cannot
772 know, or just does not care to calculate. */
773 gint32 dpts = pts - *last;
774 *offset -= dpts * GST_MSECOND;
775 GST_WARNING_OBJECT (demux,
776 "Large pts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
777 GST_TIME_FORMAT "", dpts, GST_TIME_ARGS (*offset));
783 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
785 GstFlowReturn ret = GST_FLOW_OK;
786 guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
787 guint32 codec_data = 0, pts_ext = 0;
789 guint8 *data = GST_BUFFER_DATA (buffer);
792 GST_LOG_OBJECT (demux, "parsing an audio tag");
794 if (demux->no_more_pads && !demux->audio_pad) {
795 GST_WARNING_OBJECT (demux,
796 "Signaled no-more-pads already but had no audio pad -- ignoring");
800 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) == demux->tag_size,
803 /* Grab information about audio tag */
804 pts = GST_READ_UINT24_BE (data);
805 /* read the pts extension to 32 bits integer */
806 pts_ext = GST_READ_UINT8 (data + 3);
808 pts |= pts_ext << 24;
810 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
811 data[2], data[3], pts);
813 /* Error out on tags with too small headers */
814 if (GST_BUFFER_SIZE (buffer) < 11) {
815 GST_ERROR_OBJECT (demux, "Too small tag size (%d)",
816 GST_BUFFER_SIZE (buffer));
817 return GST_FLOW_ERROR;
820 /* Silently skip buffers with no data */
821 if (GST_BUFFER_SIZE (buffer) == 11)
824 /* Skip the stream id and go directly to the flags */
825 flags = GST_READ_UINT8 (data + 7);
836 if ((flags & 0x0C) == 0x0C) {
838 } else if ((flags & 0x0C) == 0x08) {
840 } else if ((flags & 0x0C) == 0x04) {
844 codec_tag = flags >> 4;
845 if (codec_tag == 10) { /* AAC has an extra byte for packet type */
851 /* codec tags with special rates */
852 if (codec_tag == 5 || codec_tag == 14)
854 else if (codec_tag == 4)
857 GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
858 "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
861 /* If we don't have our audio pad created, then create it. */
862 if (G_UNLIKELY (!demux->audio_pad)) {
865 gst_pad_new_from_template (gst_element_class_get_pad_template
866 (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
867 if (G_UNLIKELY (!demux->audio_pad)) {
868 GST_WARNING_OBJECT (demux, "failed creating audio pad");
869 ret = GST_FLOW_ERROR;
874 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
876 gst_object_unref (demux->audio_pad);
877 demux->audio_pad = NULL;
878 ret = GST_FLOW_ERROR;
882 GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
883 GST_PAD_CAPS (demux->audio_pad));
885 /* Set functions on the pad */
886 gst_pad_set_query_type_function (demux->audio_pad,
887 GST_DEBUG_FUNCPTR (gst_flv_demux_query_types));
888 gst_pad_set_query_function (demux->audio_pad,
889 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
890 gst_pad_set_event_function (demux->audio_pad,
891 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
893 gst_pad_use_fixed_caps (demux->audio_pad);
896 gst_pad_set_active (demux->audio_pad, TRUE);
898 /* We need to set caps before adding */
899 gst_element_add_pad (GST_ELEMENT (demux),
900 gst_object_ref (demux->audio_pad));
902 /* We only emit no more pads when we have audio and video. Indeed we can
903 * not trust the FLV header to tell us if there will be only audio or
904 * only video and we would just break discovery of some files */
905 if (demux->audio_pad && demux->video_pad) {
906 GST_DEBUG_OBJECT (demux, "emitting no more pads");
907 gst_element_no_more_pads (GST_ELEMENT (demux));
908 demux->no_more_pads = TRUE;
909 demux->push_tags = TRUE;
913 /* Check if caps have changed */
914 if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
915 codec_tag != demux->audio_codec_tag || width != demux->width)) {
916 GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
919 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
921 ret = GST_FLOW_ERROR;
926 /* Push taglist if present */
927 if (G_UNLIKELY (demux->push_tags))
928 gst_flv_demux_push_tags (demux);
930 /* Check if we have anything to push */
931 if (demux->tag_data_size <= codec_data) {
932 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
936 /* Create buffer from pad */
938 gst_buffer_create_sub (buffer, 7 + codec_data,
939 demux->tag_data_size - codec_data);
941 if (demux->audio_codec_tag == 10) {
942 guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
944 switch (aac_packet_type) {
947 /* AudioSpecificConfig data */
948 GST_LOG_OBJECT (demux, "got an AAC codec data packet");
949 if (demux->audio_codec_data) {
950 gst_buffer_unref (demux->audio_codec_data);
952 demux->audio_codec_data = outbuf;
953 /* Use that buffer data in the caps */
954 gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels, width);
960 GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
963 GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
968 /* detect (and deem to be resyncs) large pts gaps */
969 gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
970 &demux->last_audio_pts, &demux->audio_time_offset);
972 /* Fill buffer with data */
973 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
974 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
975 GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
976 GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
977 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (demux->audio_pad));
979 if (demux->duration == GST_CLOCK_TIME_NONE ||
980 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
981 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
983 /* Only add audio frames to the index if we have no video,
984 * and if the index is not yet complete */
985 if (!demux->has_video && demux->index && !demux->indexed) {
986 gst_flv_demux_parse_and_add_index_entry (demux,
987 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
990 if (G_UNLIKELY (demux->audio_need_discont)) {
991 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
992 demux->audio_need_discont = FALSE;
995 gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME,
996 GST_BUFFER_TIMESTAMP (outbuf));
998 /* Do we need a newsegment event ? */
999 if (G_UNLIKELY (demux->audio_need_segment)) {
1000 if (demux->close_seg_event)
1001 gst_pad_push_event (demux->audio_pad,
1002 gst_event_ref (demux->close_seg_event));
1004 if (!demux->new_seg_event) {
1005 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1006 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1007 GST_TIME_ARGS (demux->segment.last_stop),
1008 GST_TIME_ARGS (demux->segment.stop));
1009 demux->new_seg_event =
1010 gst_event_new_new_segment (FALSE, demux->segment.rate,
1011 demux->segment.format, demux->segment.last_stop,
1012 demux->segment.stop, demux->segment.last_stop);
1014 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1017 gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1019 demux->audio_need_segment = FALSE;
1022 GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
1023 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1024 GST_BUFFER_SIZE (outbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1025 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1027 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1028 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1030 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1031 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1034 if (G_UNLIKELY (!demux->no_more_pads
1035 && (GST_CLOCK_DIFF (demux->audio_start,
1036 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1037 GST_DEBUG_OBJECT (demux,
1038 "Signalling no-more-pads because no video stream was found"
1039 " after 6 seconds of audio");
1040 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1041 demux->no_more_pads = TRUE;
1042 demux->push_tags = TRUE;
1045 /* Push downstream */
1046 ret = gst_pad_push (demux->audio_pad, outbuf);
1047 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1048 if (demux->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
1049 demux->segment.last_stop > demux->segment.stop) {
1050 /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
1051 * we are at the end of the segment, so we just need to jump
1052 * back to the previous section. */
1053 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1054 demux->audio_done = TRUE;
1057 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1058 " bytes audio buffer: %s", demux->tag_data_size,
1059 gst_flow_get_name (ret));
1060 if (ret == GST_FLOW_NOT_LINKED) {
1061 demux->audio_linked = FALSE;
1067 demux->audio_linked = TRUE;
1074 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1076 gboolean ret = FALSE;
1077 GstCaps *caps = NULL;
1078 gchar *codec_name = NULL;
1080 /* Generate caps for that pad */
1081 switch (codec_tag) {
1083 caps = gst_caps_new_simple ("video/x-flash-video", NULL);
1086 caps = gst_caps_new_simple ("video/x-flash-screen", NULL);
1089 caps = gst_caps_new_simple ("video/x-vp6-flash", NULL);
1092 caps = gst_caps_new_simple ("video/x-vp6-alpha", NULL);
1096 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1100 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1103 if (G_UNLIKELY (!caps)) {
1104 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1108 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1109 demux->par_x, demux->par_y, NULL);
1111 if (G_LIKELY (demux->w)) {
1112 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1115 if (G_LIKELY (demux->h)) {
1116 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1119 if (G_LIKELY (demux->framerate)) {
1120 gint num = 0, den = 0;
1122 gst_util_double_to_fraction (demux->framerate, &num, &den);
1123 GST_DEBUG_OBJECT (demux->video_pad,
1124 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1127 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1130 if (demux->video_codec_data) {
1131 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1132 demux->video_codec_data, NULL);
1135 ret = gst_pad_set_caps (demux->video_pad, caps);
1137 if (G_LIKELY (ret)) {
1138 /* Store the caps we have set */
1139 demux->video_codec_tag = codec_tag;
1141 codec_name = gst_pb_utils_get_codec_description (caps);
1144 if (demux->taglist == NULL)
1145 demux->taglist = gst_tag_list_new ();
1146 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1147 GST_TAG_VIDEO_CODEC, codec_name, NULL);
1148 g_free (codec_name);
1151 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1152 GST_PTR_FORMAT, caps);
1154 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1155 GST_PTR_FORMAT, caps);
1158 gst_caps_unref (caps);
1164 static GstFlowReturn
1165 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1167 GstFlowReturn ret = GST_FLOW_OK;
1168 guint32 pts = 0, codec_data = 1, pts_ext = 0;
1169 gboolean keyframe = FALSE;
1170 guint8 flags = 0, codec_tag = 0;
1171 guint8 *data = GST_BUFFER_DATA (buffer);
1174 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) == demux->tag_size,
1177 GST_LOG_OBJECT (demux, "parsing a video tag");
1180 if (demux->no_more_pads && !demux->video_pad) {
1181 GST_WARNING_OBJECT (demux,
1182 "Signaled no-more-pads already but had no audio pad -- ignoring");
1186 /* Grab information about video tag */
1187 pts = GST_READ_UINT24_BE (data);
1188 /* read the pts extension to 32 bits integer */
1189 pts_ext = GST_READ_UINT8 (data + 3);
1191 pts |= pts_ext << 24;
1193 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1194 data[2], data[3], pts);
1196 if (GST_BUFFER_SIZE (buffer) < 12) {
1197 GST_ERROR_OBJECT (demux, "Too small tag size");
1198 return GST_FLOW_ERROR;
1201 /* Skip the stream id and go directly to the flags */
1202 flags = GST_READ_UINT8 (data + 7);
1205 if ((flags >> 4) == 1) {
1209 codec_tag = flags & 0x0F;
1210 if (codec_tag == 4 || codec_tag == 5) {
1212 } else if (codec_tag == 7) {
1217 cts = GST_READ_UINT24_BE (data + 9);
1218 cts = (cts + 0xff800000) ^ 0xff800000;
1220 GST_LOG_OBJECT (demux, "got cts %d", cts);
1222 /* avoid negative overflow */
1223 if (cts >= 0 || pts >= -cts)
1227 GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1228 "(flags %02X)", codec_tag, keyframe, flags);
1230 /* If we don't have our video pad created, then create it. */
1231 if (G_UNLIKELY (!demux->video_pad)) {
1233 gst_pad_new_from_template (gst_element_class_get_pad_template
1234 (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1235 if (G_UNLIKELY (!demux->video_pad)) {
1236 GST_WARNING_OBJECT (demux, "failed creating video pad");
1237 ret = GST_FLOW_ERROR;
1241 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1242 gst_object_unref (demux->video_pad);
1243 demux->video_pad = NULL;
1244 ret = GST_FLOW_ERROR;
1248 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1249 * metadata tag that would come later and trigger a caps change */
1250 demux->got_par = FALSE;
1252 GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1253 GST_PAD_CAPS (demux->video_pad));
1255 /* Set functions on the pad */
1256 gst_pad_set_query_type_function (demux->video_pad,
1257 GST_DEBUG_FUNCPTR (gst_flv_demux_query_types));
1258 gst_pad_set_query_function (demux->video_pad,
1259 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1260 gst_pad_set_event_function (demux->video_pad,
1261 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1263 gst_pad_use_fixed_caps (demux->video_pad);
1265 /* Make it active */
1266 gst_pad_set_active (demux->video_pad, TRUE);
1268 /* We need to set caps before adding */
1269 gst_element_add_pad (GST_ELEMENT (demux),
1270 gst_object_ref (demux->video_pad));
1272 /* We only emit no more pads when we have audio and video. Indeed we can
1273 * not trust the FLV header to tell us if there will be only audio or
1274 * only video and we would just break discovery of some files */
1275 if (demux->audio_pad && demux->video_pad) {
1276 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1277 gst_element_no_more_pads (GST_ELEMENT (demux));
1278 demux->no_more_pads = TRUE;
1279 demux->push_tags = TRUE;
1283 /* Check if caps have changed */
1284 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1286 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1288 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1289 ret = GST_FLOW_ERROR;
1293 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1294 * metadata tag that would come later and trigger a caps change */
1295 demux->got_par = FALSE;
1298 /* Push taglist if present */
1299 if (G_UNLIKELY (demux->push_tags))
1300 gst_flv_demux_push_tags (demux);
1302 /* Check if we have anything to push */
1303 if (demux->tag_data_size <= codec_data) {
1304 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1308 /* Create buffer from pad */
1310 gst_buffer_create_sub (buffer, 7 + codec_data,
1311 demux->tag_data_size - codec_data);
1313 if (demux->video_codec_tag == 7) {
1314 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1316 switch (avc_packet_type) {
1319 /* AVCDecoderConfigurationRecord data */
1320 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1321 if (demux->video_codec_data) {
1322 gst_buffer_unref (demux->video_codec_data);
1324 demux->video_codec_data = outbuf;
1325 /* Use that buffer data in the caps */
1326 gst_flv_demux_video_negotiate (demux, codec_tag);
1331 /* H.264 NALU packet */
1332 GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1335 GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1340 /* detect (and deem to be resyncs) large pts gaps */
1341 gst_flv_demux_update_resync (demux, pts, demux->video_need_discont,
1342 &demux->last_video_pts, &demux->video_time_offset);
1344 /* Fill buffer with data */
1345 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
1346 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1347 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1348 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1349 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (demux->video_pad));
1351 if (demux->duration == GST_CLOCK_TIME_NONE ||
1352 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1353 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1356 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1358 if (!demux->indexed && demux->index) {
1359 gst_flv_demux_parse_and_add_index_entry (demux,
1360 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1363 if (G_UNLIKELY (demux->video_need_discont)) {
1364 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1365 demux->video_need_discont = FALSE;
1368 gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME,
1369 GST_BUFFER_TIMESTAMP (outbuf));
1371 /* Do we need a newsegment event ? */
1372 if (G_UNLIKELY (demux->video_need_segment)) {
1373 if (demux->close_seg_event)
1374 gst_pad_push_event (demux->video_pad,
1375 gst_event_ref (demux->close_seg_event));
1377 if (!demux->new_seg_event) {
1378 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1379 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1380 GST_TIME_ARGS (demux->segment.last_stop),
1381 GST_TIME_ARGS (demux->segment.stop));
1382 demux->new_seg_event =
1383 gst_event_new_new_segment (FALSE, demux->segment.rate,
1384 demux->segment.format, demux->segment.last_stop,
1385 demux->segment.stop, demux->segment.last_stop);
1387 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1390 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1392 demux->video_need_segment = FALSE;
1395 GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
1396 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1397 ", keyframe (%d)", GST_BUFFER_SIZE (outbuf),
1398 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1399 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1402 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1403 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1405 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1406 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1409 if (G_UNLIKELY (!demux->no_more_pads
1410 && (GST_CLOCK_DIFF (demux->video_start,
1411 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1412 GST_DEBUG_OBJECT (demux,
1413 "Signalling no-more-pads because no audio stream was found"
1414 " after 6 seconds of video");
1415 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1416 demux->no_more_pads = TRUE;
1417 demux->push_tags = TRUE;
1420 /* Push downstream */
1421 ret = gst_pad_push (demux->video_pad, outbuf);
1423 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1424 if (demux->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
1425 demux->segment.last_stop > demux->segment.stop) {
1426 /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
1427 * we are at the end of the segment, so we just need to jump
1428 * back to the previous section. */
1429 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1430 demux->video_done = TRUE;
1433 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1434 " bytes video buffer: %s", demux->tag_data_size,
1435 gst_flow_get_name (ret));
1436 if (ret == GST_FLOW_NOT_LINKED) {
1437 demux->video_linked = FALSE;
1443 demux->video_linked = TRUE;
1450 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1451 GstBuffer * buffer, size_t * tag_size)
1453 guint32 pts = 0, pts_ext = 0;
1454 guint32 tag_data_size;
1456 gboolean keyframe = TRUE;
1458 guint8 *data = GST_BUFFER_DATA (buffer);
1460 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 12, GST_CLOCK_TIME_NONE);
1464 if (type != 9 && type != 8 && type != 18) {
1465 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1466 return GST_CLOCK_TIME_NONE;
1470 demux->has_video = TRUE;
1472 demux->has_audio = TRUE;
1474 tag_data_size = GST_READ_UINT24_BE (data + 1);
1476 if (GST_BUFFER_SIZE (buffer) >= tag_data_size + 11 + 4) {
1477 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1478 GST_WARNING_OBJECT (demux, "Invalid tag size");
1479 return GST_CLOCK_TIME_NONE;
1484 *tag_size = tag_data_size + 11 + 4;
1488 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
1491 /* Grab timestamp of tag tag */
1492 pts = GST_READ_UINT24_BE (data);
1493 /* read the pts extension to 32 bits integer */
1494 pts_ext = GST_READ_UINT8 (data + 3);
1496 pts |= pts_ext << 24;
1501 keyframe = ((data[0] >> 4) == 1);
1504 ret = pts * GST_MSECOND;
1505 GST_LOG_OBJECT (demux, "pts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1507 if (index && demux->index && !demux->indexed && (type == 9 || (type == 8
1508 && !demux->has_video))) {
1509 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1513 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1514 demux->duration = ret;
1519 static GstFlowReturn
1520 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1522 GstFlowReturn ret = GST_FLOW_OK;
1523 guint8 tag_type = 0;
1524 guint8 *data = GST_BUFFER_DATA (buffer);
1526 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 4, GST_FLOW_ERROR);
1532 demux->state = FLV_STATE_TAG_VIDEO;
1533 demux->has_video = TRUE;
1536 demux->state = FLV_STATE_TAG_AUDIO;
1537 demux->has_audio = TRUE;
1540 demux->state = FLV_STATE_TAG_SCRIPT;
1543 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1546 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1547 * 4 bytes of previous tag size */
1548 demux->tag_data_size = GST_READ_UINT24_BE (data + 1);
1549 demux->tag_size = demux->tag_data_size + 11;
1551 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1552 demux->tag_data_size);
1557 static GstFlowReturn
1558 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1560 GstFlowReturn ret = GST_FLOW_OK;
1561 guint8 *data = GST_BUFFER_DATA (buffer);
1563 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 9, GST_FLOW_ERROR);
1565 /* Check for the FLV tag */
1566 if (data[0] == 'F' && data[1] == 'L' && data[2] == 'V') {
1567 GST_DEBUG_OBJECT (demux, "FLV header detected");
1569 if (G_UNLIKELY (demux->strict)) {
1570 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1571 ret = GST_FLOW_UNEXPECTED;
1576 /* Jump over the 4 first bytes */
1579 /* Now look at audio/video flags */
1581 guint8 flags = data[0];
1583 demux->has_video = demux->has_audio = FALSE;
1586 GST_DEBUG_OBJECT (demux, "there is a video stream");
1587 demux->has_video = TRUE;
1590 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1591 demux->has_audio = TRUE;
1595 /* do a one-time seekability check */
1596 gst_flv_demux_check_seekability (demux);
1598 /* We don't care about the rest */
1599 demux->need_header = FALSE;
1607 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1609 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1611 gst_adapter_clear (demux->adapter);
1613 demux->audio_need_discont = TRUE;
1614 demux->video_need_discont = TRUE;
1616 demux->flushing = FALSE;
1618 /* Only in push mode and if we're not during a seek */
1619 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1620 /* After a flush we expect a tag_type */
1621 demux->state = FLV_STATE_TAG_TYPE;
1622 /* We reset the offset and will get one from first push */
1628 gst_flv_demux_cleanup (GstFlvDemux * demux)
1630 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1632 demux->state = FLV_STATE_HEADER;
1634 demux->flushing = FALSE;
1635 demux->need_header = TRUE;
1636 demux->audio_need_segment = TRUE;
1637 demux->video_need_segment = TRUE;
1638 demux->audio_need_discont = TRUE;
1639 demux->video_need_discont = TRUE;
1641 /* By default we consider them as linked */
1642 demux->audio_linked = TRUE;
1643 demux->video_linked = TRUE;
1645 demux->has_audio = FALSE;
1646 demux->has_video = FALSE;
1647 demux->push_tags = FALSE;
1648 demux->got_par = FALSE;
1650 demux->indexed = FALSE;
1651 demux->upstream_seekable = FALSE;
1652 demux->file_size = 0;
1654 demux->index_max_pos = 0;
1655 demux->index_max_time = 0;
1657 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1658 demux->last_audio_pts = demux->last_video_pts = 0;
1659 demux->audio_time_offset = demux->video_time_offset = 0;
1661 demux->no_more_pads = FALSE;
1663 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1665 demux->w = demux->h = 0;
1666 demux->framerate = 0.0;
1667 demux->par_x = demux->par_y = 1;
1668 demux->video_offset = 0;
1669 demux->audio_offset = 0;
1670 demux->offset = demux->cur_tag_offset = 0;
1671 demux->tag_size = demux->tag_data_size = 0;
1672 demux->duration = GST_CLOCK_TIME_NONE;
1674 if (demux->new_seg_event) {
1675 gst_event_unref (demux->new_seg_event);
1676 demux->new_seg_event = NULL;
1679 if (demux->close_seg_event) {
1680 gst_event_unref (demux->close_seg_event);
1681 demux->close_seg_event = NULL;
1684 gst_adapter_clear (demux->adapter);
1686 if (demux->audio_codec_data) {
1687 gst_buffer_unref (demux->audio_codec_data);
1688 demux->audio_codec_data = NULL;
1691 if (demux->video_codec_data) {
1692 gst_buffer_unref (demux->video_codec_data);
1693 demux->video_codec_data = NULL;
1696 if (demux->audio_pad) {
1697 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1698 gst_object_unref (demux->audio_pad);
1699 demux->audio_pad = NULL;
1702 if (demux->video_pad) {
1703 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1704 gst_object_unref (demux->video_pad);
1705 demux->video_pad = NULL;
1709 g_array_free (demux->times, TRUE);
1710 demux->times = NULL;
1713 if (demux->filepositions) {
1714 g_array_free (demux->filepositions, TRUE);
1715 demux->filepositions = NULL;
1720 * Create and push a flushing seek event upstream
1723 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1728 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1731 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1732 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1733 GST_SEEK_TYPE_NONE, -1);
1735 res = gst_pad_push_event (demux->sinkpad, event);
1738 demux->offset = offset;
1742 static GstFlowReturn
1743 gst_flv_demux_chain (GstPad * pad, GstBuffer * buffer)
1745 GstFlowReturn ret = GST_FLOW_OK;
1746 GstFlvDemux *demux = NULL;
1748 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
1750 GST_LOG_OBJECT (demux, "received buffer of %d bytes at offset %"
1751 G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer));
1753 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1754 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1755 demux->state = FLV_STATE_HEADER;
1759 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
1760 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
1761 demux->offset = GST_BUFFER_OFFSET (buffer);
1764 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1765 GST_DEBUG_OBJECT (demux, "Discontinuity");
1766 gst_adapter_clear (demux->adapter);
1769 gst_adapter_push (demux->adapter, buffer);
1771 if (demux->seeking) {
1772 demux->state = FLV_STATE_SEEK;
1773 GST_OBJECT_LOCK (demux);
1774 demux->seeking = FALSE;
1775 GST_OBJECT_UNLOCK (demux);
1779 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1780 if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
1781 || demux->video_linked)) {
1784 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
1789 if (G_UNLIKELY (demux->flushing)) {
1790 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
1791 ret = GST_FLOW_WRONG_STATE;
1795 switch (demux->state) {
1796 case FLV_STATE_HEADER:
1798 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
1801 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
1803 ret = gst_flv_demux_parse_header (demux, buffer);
1805 gst_buffer_unref (buffer);
1806 demux->offset += FLV_HEADER_SIZE;
1808 demux->state = FLV_STATE_TAG_TYPE;
1814 case FLV_STATE_TAG_TYPE:
1816 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
1819 /* Remember the tag offset in bytes */
1820 demux->cur_tag_offset = demux->offset;
1822 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
1824 ret = gst_flv_demux_parse_tag_type (demux, buffer);
1826 gst_buffer_unref (buffer);
1827 demux->offset += FLV_TAG_TYPE_SIZE;
1829 /* last tag is not an index => no index/don't know where the index is
1830 * seek back to the beginning */
1831 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
1839 case FLV_STATE_TAG_VIDEO:
1841 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1844 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1846 ret = gst_flv_demux_parse_tag_video (demux, buffer);
1848 gst_buffer_unref (buffer);
1849 demux->offset += demux->tag_size;
1851 demux->state = FLV_STATE_TAG_TYPE;
1857 case FLV_STATE_TAG_AUDIO:
1859 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1862 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1864 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
1866 gst_buffer_unref (buffer);
1867 demux->offset += demux->tag_size;
1869 demux->state = FLV_STATE_TAG_TYPE;
1875 case FLV_STATE_TAG_SCRIPT:
1877 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1880 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1882 ret = gst_flv_demux_parse_tag_script (demux, buffer);
1884 gst_buffer_unref (buffer);
1885 demux->offset += demux->tag_size;
1887 demux->state = FLV_STATE_TAG_TYPE;
1889 /* if there's a seek event we're here for the index so if we don't have it
1890 * we seek back to the beginning */
1891 if (demux->seek_event) {
1893 demux->state = FLV_STATE_SEEK;
1903 case FLV_STATE_SEEK:
1909 if (!demux->indexed) {
1910 if (demux->offset == demux->file_size - sizeof (guint32)) {
1912 gst_adapter_take_buffer (demux->adapter, sizeof (guint32));
1913 GstByteReader *reader = gst_byte_reader_new_from_buffer (buffer);
1914 guint64 seek_offset;
1916 if (!gst_adapter_available (demux->adapter) >= sizeof (guint32)) {
1921 demux->file_size - sizeof (guint32) -
1922 gst_byte_reader_peek_uint32_be_unchecked (reader);
1923 gst_byte_reader_free (reader);
1924 gst_buffer_unref (buffer);
1926 GST_INFO_OBJECT (demux,
1927 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
1929 demux->state = FLV_STATE_TAG_TYPE;
1930 flv_demux_seek_to_offset (demux, seek_offset);
1936 GST_OBJECT_LOCK (demux);
1937 event = demux->seek_event;
1938 demux->seek_event = NULL;
1939 GST_OBJECT_UNLOCK (demux);
1941 /* calculate and perform seek */
1942 if (!flv_demux_handle_seek_push (demux, event))
1945 gst_event_unref (event);
1946 demux->state = FLV_STATE_TAG_TYPE;
1950 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
1954 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
1955 /* If either audio or video is linked we return GST_FLOW_OK */
1956 if (demux->audio_linked || demux->video_linked) {
1961 gst_object_unref (demux);
1968 GST_OBJECT_LOCK (demux);
1969 demux->seeking = FALSE;
1970 gst_event_unref (demux->seek_event);
1971 demux->seek_event = NULL;
1972 GST_OBJECT_UNLOCK (demux);
1973 GST_WARNING_OBJECT (demux,
1974 "failed to find an index, seeking back to beginning");
1975 flv_demux_seek_to_offset (demux, 0);
1980 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
1981 return GST_FLOW_ERROR;
1986 static GstFlowReturn
1987 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
1988 guint size, GstBuffer ** buffer)
1992 ret = gst_pad_pull_range (pad, offset, size, buffer);
1993 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1994 GST_WARNING_OBJECT (demux,
1995 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
1996 size, offset, gst_flow_get_name (ret));
2001 if (G_UNLIKELY (*buffer && GST_BUFFER_SIZE (*buffer) != size)) {
2002 GST_WARNING_OBJECT (demux,
2003 "partial pull got %d when expecting %d from offset %" G_GUINT64_FORMAT,
2004 GST_BUFFER_SIZE (*buffer), size, offset);
2005 gst_buffer_unref (*buffer);
2006 ret = GST_FLOW_UNEXPECTED;
2014 static GstFlowReturn
2015 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2017 GstBuffer *buffer = NULL;
2018 GstFlowReturn ret = GST_FLOW_OK;
2020 /* Store tag offset */
2021 demux->cur_tag_offset = demux->offset;
2023 /* Get the first 4 bytes to identify tag type and size */
2024 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2025 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2028 /* Identify tag type */
2029 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2031 gst_buffer_unref (buffer);
2033 if (G_UNLIKELY (ret != GST_FLOW_OK))
2036 /* Jump over tag type + size */
2037 demux->offset += FLV_TAG_TYPE_SIZE;
2039 /* Pull the whole tag */
2040 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2041 demux->tag_size, &buffer)) != GST_FLOW_OK))
2044 switch (demux->state) {
2045 case FLV_STATE_TAG_VIDEO:
2046 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2048 case FLV_STATE_TAG_AUDIO:
2049 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2051 case FLV_STATE_TAG_SCRIPT:
2052 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2055 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2058 gst_buffer_unref (buffer);
2060 /* Jump over that part we've just parsed */
2061 demux->offset += demux->tag_size;
2063 /* Make sure we reinitialize the tag size */
2064 demux->tag_size = 0;
2066 /* Ready for the next tag */
2067 demux->state = FLV_STATE_TAG_TYPE;
2069 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2070 /* If either audio or video is linked we return GST_FLOW_OK */
2071 if (demux->audio_linked || demux->video_linked) {
2074 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2075 "neither video nor audio are linked");
2083 static GstFlowReturn
2084 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2086 GstBuffer *buffer = NULL;
2087 GstFlowReturn ret = GST_FLOW_OK;
2089 /* Get the first 9 bytes */
2090 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2091 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2094 ret = gst_flv_demux_parse_header (demux, buffer);
2096 gst_buffer_unref (buffer);
2098 /* Jump over the header now */
2099 demux->offset += FLV_HEADER_SIZE;
2100 demux->state = FLV_STATE_TAG_TYPE;
2107 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2110 demux->offset = offset;
2112 /* Tell all the stream we moved to a different position (discont) */
2113 demux->audio_need_discont = TRUE;
2114 demux->video_need_discont = TRUE;
2116 /* next section setup */
2117 demux->from_offset = -1;
2118 demux->audio_done = demux->video_done = FALSE;
2119 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2122 demux->from_offset = -1;
2123 demux->to_offset = G_MAXINT64;
2126 /* If we seeked at the beginning of the file parse the header again */
2127 if (G_UNLIKELY (!demux->offset)) {
2128 demux->state = FLV_STATE_HEADER;
2129 } else { /* or parse a tag */
2130 demux->state = FLV_STATE_TAG_TYPE;
2134 static GstFlowReturn
2135 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2137 GstFlowReturn ret = GST_FLOW_UNEXPECTED;
2138 GstIndexEntry *entry = NULL;
2140 GST_DEBUG_OBJECT (demux,
2141 "terminated section started at offset %" G_GINT64_FORMAT,
2142 demux->from_offset);
2144 /* we are done if we got all audio and video */
2145 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2146 demux->audio_first_ts < demux->segment.start) &&
2147 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2148 demux->video_first_ts < demux->segment.start))
2151 if (demux->from_offset <= 0)
2154 GST_DEBUG_OBJECT (demux, "locating previous position");
2156 /* locate index entry before previous start position */
2158 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2159 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2160 GST_FORMAT_BYTES, demux->from_offset - 1);
2165 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2166 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2168 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2169 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2170 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2172 /* setup for next section */
2173 demux->to_offset = demux->from_offset;
2174 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2183 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
2185 gboolean ret = TRUE;
2187 if (demux->audio_pad)
2188 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
2190 if (demux->video_pad)
2191 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
2193 gst_event_unref (event);
2198 static GstFlowReturn
2199 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2202 GstFormat fmt = GST_FORMAT_BYTES;
2206 GstClockTime tag_time;
2207 GstFlowReturn ret = GST_FLOW_OK;
2209 if (G_UNLIKELY (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &size) ||
2210 fmt != GST_FORMAT_BYTES))
2213 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2214 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2216 old_offset = demux->offset;
2217 demux->offset = pos;
2219 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2220 12, &buffer)) == GST_FLOW_OK) {
2222 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2224 gst_buffer_unref (buffer);
2226 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2229 demux->offset += tag_size;
2232 if (ret == GST_FLOW_UNEXPECTED) {
2233 /* file ran out, so mark we have complete index */
2234 demux->indexed = TRUE;
2239 demux->offset = old_offset;
2245 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2247 gint64 ret = 0, offset;
2248 GstFormat fmt = GST_FORMAT_BYTES;
2249 size_t tag_size, size;
2250 GstBuffer *buffer = NULL;
2252 if (G_UNLIKELY (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &offset)
2253 || fmt != GST_FORMAT_BYTES))
2257 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2258 if (G_UNLIKELY (offset < 4))
2262 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2266 tag_size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buffer));
2267 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2268 gst_buffer_unref (buffer);
2272 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2276 /* a consistency check */
2277 size = GST_READ_UINT24_BE (GST_BUFFER_DATA (buffer) + 1);
2278 if (size != tag_size - 11) {
2279 GST_DEBUG_OBJECT (demux,
2280 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2281 ", corrupt or truncated file", size, tag_size - 11);
2285 /* try to update duration with timestamp in any case */
2286 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2288 /* maybe get some more metadata */
2289 if (GST_BUFFER_DATA (buffer)[0] == 18) {
2290 gst_buffer_unref (buffer);
2292 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2294 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2296 gst_flv_demux_parse_tag_script (demux, buffer);
2301 gst_buffer_unref (buffer);
2307 gst_flv_demux_loop (GstPad * pad)
2309 GstFlvDemux *demux = NULL;
2310 GstFlowReturn ret = GST_FLOW_OK;
2312 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2315 switch (demux->state) {
2316 case FLV_STATE_TAG_TYPE:
2317 if (demux->from_offset == -1)
2318 demux->from_offset = demux->offset;
2319 ret = gst_flv_demux_pull_tag (pad, demux);
2320 /* if we have seen real data, we probably passed a possible metadata
2321 * header located at start. So if we do not yet have an index,
2322 * try to pick up metadata (index, duration) at the end */
2323 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2324 (demux->has_video || demux->has_audio)))
2325 demux->file_size = gst_flv_demux_get_metadata (demux);
2327 case FLV_STATE_DONE:
2328 ret = GST_FLOW_UNEXPECTED;
2330 case FLV_STATE_SEEK:
2331 /* seek issued with insufficient index;
2332 * scan for index in task thread from current maximum offset to
2333 * desired time and then perform seek */
2334 /* TODO maybe some buffering message or so to indicate scan progress */
2335 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2337 if (ret != GST_FLOW_OK)
2339 /* position and state arranged by seek,
2340 * also unrefs event */
2341 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2342 demux->seek_event = NULL;
2345 ret = gst_flv_demux_pull_header (pad, demux);
2346 /* index scans start after header */
2347 demux->index_max_pos = demux->offset;
2351 if (demux->segment.rate < 0.0) {
2352 /* check end of section */
2353 if ((gint64) demux->offset >= demux->to_offset ||
2354 demux->segment.last_stop >= demux->segment.stop + 2 * GST_SECOND ||
2355 (demux->audio_done && demux->video_done))
2356 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2358 /* check EOS condition */
2359 if ((demux->segment.stop != -1) &&
2360 (demux->segment.last_stop >= demux->segment.stop)) {
2361 ret = GST_FLOW_UNEXPECTED;
2365 /* pause if something went wrong or at end */
2366 if (G_UNLIKELY (ret != GST_FLOW_OK))
2369 gst_object_unref (demux);
2375 const gchar *reason = gst_flow_get_name (ret);
2377 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2378 gst_pad_pause_task (pad);
2380 if (ret == GST_FLOW_UNEXPECTED) {
2381 /* perform EOS logic */
2382 if (!demux->no_more_pads) {
2383 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2384 demux->no_more_pads = TRUE;
2387 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2390 /* for segment playback we need to post when (in stream time)
2391 * we stopped, this is either stop (when set) or the duration. */
2392 if ((stop = demux->segment.stop) == -1)
2393 stop = demux->segment.duration;
2395 if (demux->segment.rate >= 0) {
2396 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2397 gst_element_post_message (GST_ELEMENT_CAST (demux),
2398 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2399 GST_FORMAT_TIME, stop));
2400 } else { /* Reverse playback */
2401 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2403 gst_element_post_message (GST_ELEMENT_CAST (demux),
2404 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2405 GST_FORMAT_TIME, demux->segment.start));
2408 /* normal playback, send EOS to all linked pads */
2409 if (!demux->no_more_pads) {
2410 gst_element_no_more_pads (GST_ELEMENT (demux));
2411 demux->no_more_pads = TRUE;
2414 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2415 if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2416 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2418 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
2419 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2420 ("Internal data stream error."),
2421 ("stream stopped, reason %s", reason));
2422 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2424 gst_object_unref (demux);
2430 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2434 GstIndexEntry *entry;
2436 g_return_val_if_fail (segment != NULL, 0);
2438 time = segment->last_stop;
2441 /* Let's check if we have an index entry for that seek time */
2442 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2443 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2444 GST_FORMAT_TIME, time);
2447 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2448 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2450 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2451 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2452 GST_TIME_ARGS (segment->last_stop), GST_TIME_ARGS (time), bytes);
2454 /* Key frame seeking */
2455 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2456 /* Adjust the segment so that the keyframe fits in */
2457 if (time < segment->start) {
2458 segment->start = segment->time = time;
2460 segment->last_stop = time;
2463 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2464 GST_TIME_ARGS (segment->start));
2472 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2476 GstSeekType start_type, stop_type;
2479 gboolean update, flush, ret;
2480 GstSegment seeksegment;
2482 gst_event_parse_seek (event, &rate, &format, &flags,
2483 &start_type, &start, &stop_type, &stop);
2485 if (format != GST_FORMAT_TIME)
2488 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2489 /* FIXME : the keyframe flag is never used ! */
2491 /* Work on a copy until we are sure the seek succeeded. */
2492 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2494 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2497 /* Apply the seek to our segment */
2498 gst_segment_set_seek (&seeksegment, rate, format, flags,
2499 start_type, start, stop_type, stop, &update);
2501 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2504 if (flush || seeksegment.last_stop != demux->segment.last_stop) {
2505 /* Do the actual seeking */
2506 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2508 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2509 G_GUINT64_FORMAT, offset);
2510 ret = gst_pad_push_event (demux->sinkpad,
2511 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2512 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2513 offset, GST_SEEK_TYPE_NONE, 0));
2514 if (G_UNLIKELY (!ret)) {
2515 GST_WARNING_OBJECT (demux, "upstream seek failed");
2518 /* Tell all the stream we moved to a different position (discont) */
2519 demux->audio_need_discont = TRUE;
2520 demux->video_need_discont = TRUE;
2526 /* Ok seek succeeded, take the newly configured segment */
2527 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2529 /* Tell all the stream a new segment is needed */
2530 demux->audio_need_segment = TRUE;
2531 demux->video_need_segment = TRUE;
2532 /* Clean any potential newsegment event kept for the streams. The first
2533 * stream needing a new segment will create a new one. */
2534 if (G_UNLIKELY (demux->new_seg_event)) {
2535 gst_event_unref (demux->new_seg_event);
2536 demux->new_seg_event = NULL;
2538 gst_event_unref (event);
2540 ret = gst_pad_push_event (demux->sinkpad, event);
2548 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2549 gst_event_unref (event);
2555 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2559 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2561 if (format != GST_FORMAT_TIME) {
2562 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2563 gst_event_unref (event);
2567 /* First try upstream */
2568 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2569 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2570 gst_event_unref (event);
2574 if (!demux->indexed) {
2575 guint64 seek_offset = 0;
2576 gboolean building_index;
2579 GST_OBJECT_LOCK (demux);
2580 /* handle the seek in the chain function */
2581 demux->seeking = TRUE;
2582 demux->state = FLV_STATE_SEEK;
2584 /* copy the event */
2585 if (demux->seek_event)
2586 gst_event_unref (demux->seek_event);
2587 demux->seek_event = gst_event_ref (event);
2589 /* set the building_index flag so that only one thread can setup the
2590 * structures for index seeking. */
2591 building_index = demux->building_index;
2592 if (!building_index) {
2593 demux->building_index = TRUE;
2594 fmt = GST_FORMAT_BYTES;
2595 if (!demux->file_size
2596 && !gst_pad_query_peer_duration (demux->sinkpad, &fmt,
2597 &demux->file_size)) {
2598 GST_WARNING_OBJECT (demux,
2599 "Cannot obtain file size - %" G_GINT64_FORMAT ", format %u",
2600 demux->file_size, fmt);
2601 GST_OBJECT_UNLOCK (demux);
2605 /* we hope the last tag is a scriptdataobject containing an index
2606 * the size of the last tag is given in the last guint32 bits
2607 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2608 seek_offset = demux->file_size - sizeof (guint32);
2609 GST_DEBUG_OBJECT (demux,
2610 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2612 GST_OBJECT_UNLOCK (demux);
2614 if (!building_index) {
2615 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2617 return flv_demux_seek_to_offset (demux, seek_offset);
2620 /* FIXME: we have to always return true so that we don't block the seek
2622 * Note: maybe it is OK to return true if we're still building the index */
2626 return flv_demux_handle_seek_push (demux, event);
2630 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2635 GstSeekType start_type, stop_type;
2638 gboolean update, flush, ret = FALSE;
2639 GstSegment seeksegment;
2641 gst_event_parse_seek (event, &rate, &format, &flags,
2642 &start_type, &start, &stop_type, &stop);
2644 if (format != GST_FORMAT_TIME)
2647 /* mark seeking thread entering flushing/pausing */
2648 GST_OBJECT_LOCK (demux);
2650 demux->seeking = seeking;
2651 GST_OBJECT_UNLOCK (demux);
2653 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2654 /* FIXME : the keyframe flag is never used */
2657 /* Flush start up and downstream to make sure data flow and loops are
2659 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2660 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2662 /* Pause the pulling task */
2663 gst_pad_pause_task (demux->sinkpad);
2666 /* Take the stream lock */
2667 GST_PAD_STREAM_LOCK (demux->sinkpad);
2670 /* Stop flushing upstream we need to pull */
2671 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
2674 /* Work on a copy until we are sure the seek succeeded. */
2675 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2677 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2680 /* Apply the seek to our segment */
2681 gst_segment_set_seek (&seeksegment, rate, format, flags,
2682 start_type, start, stop_type, stop, &update);
2684 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2687 if (flush || seeksegment.last_stop != demux->segment.last_stop) {
2688 /* Do the actual seeking */
2689 /* index is reliable if it is complete or we do not go to far ahead */
2690 if (seeking && !demux->indexed &&
2691 seeksegment.last_stop > demux->index_max_time + 10 * GST_SECOND) {
2692 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2693 " index only up to %" GST_TIME_FORMAT,
2694 GST_TIME_ARGS (demux->index_max_time));
2695 /* stop flushing for now */
2697 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop ());
2698 /* delegate scanning and index building to task thread to avoid
2699 * occupying main (UI) loop */
2700 if (demux->seek_event)
2701 gst_event_unref (demux->seek_event);
2702 demux->seek_event = gst_event_ref (event);
2703 demux->seek_time = seeksegment.last_stop;
2704 demux->state = FLV_STATE_SEEK;
2705 /* do not know about succes yet, but we did care and handled it */
2709 /* now index should be as reliable as it can be for current purpose */
2710 gst_flv_demux_move_to_offset (demux,
2711 gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2717 if (G_UNLIKELY (demux->close_seg_event)) {
2718 gst_event_unref (demux->close_seg_event);
2719 demux->close_seg_event = NULL;
2723 /* Stop flushing, the sinks are at time 0 now */
2724 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop ());
2726 GST_DEBUG_OBJECT (demux, "closing running segment %" GST_SEGMENT_FORMAT,
2729 /* Close the current segment for a linear playback */
2730 if (demux->segment.rate >= 0) {
2731 /* for forward playback, we played from start to last_stop */
2732 demux->close_seg_event = gst_event_new_new_segment (TRUE,
2733 demux->segment.rate, demux->segment.format,
2734 demux->segment.start, demux->segment.last_stop, demux->segment.time);
2738 if ((stop = demux->segment.stop) == -1)
2739 stop = demux->segment.duration;
2741 /* for reverse playback, we played from stop to last_stop. */
2742 demux->close_seg_event = gst_event_new_new_segment (TRUE,
2743 demux->segment.rate, demux->segment.format,
2744 demux->segment.last_stop, stop, demux->segment.last_stop);
2749 /* Ok seek succeeded, take the newly configured segment */
2750 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2752 /* Notify about the start of a new segment */
2753 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2754 gst_element_post_message (GST_ELEMENT (demux),
2755 gst_message_new_segment_start (GST_OBJECT (demux),
2756 demux->segment.format, demux->segment.last_stop));
2759 /* Tell all the stream a new segment is needed */
2760 demux->audio_need_segment = TRUE;
2761 demux->video_need_segment = TRUE;
2762 /* Clean any potential newsegment event kept for the streams. The first
2763 * stream needing a new segment will create a new one. */
2764 if (G_UNLIKELY (demux->new_seg_event)) {
2765 gst_event_unref (demux->new_seg_event);
2766 demux->new_seg_event = NULL;
2768 if (demux->segment.rate < 0.0) {
2769 /* we can't generate a segment by locking on
2770 * to the first timestamp we see */
2771 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2772 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2773 GST_TIME_ARGS (demux->segment.start),
2774 GST_TIME_ARGS (demux->segment.stop));
2775 demux->new_seg_event =
2776 gst_event_new_new_segment (FALSE, demux->segment.rate,
2777 demux->segment.format, demux->segment.start,
2778 demux->segment.stop, demux->segment.start);
2783 GST_OBJECT_LOCK (demux);
2784 seeking = demux->seeking && !seeking;
2785 demux->seeking = FALSE;
2786 GST_OBJECT_UNLOCK (demux);
2788 /* if we detect an external seek having started (and possibly already having
2789 * flushed), do not restart task to give it a chance.
2790 * Otherwise external one's flushing will take care to pause task */
2792 gst_pad_pause_task (demux->sinkpad);
2794 gst_pad_start_task (demux->sinkpad,
2795 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
2798 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2800 gst_event_unref (event);
2806 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2807 gst_event_unref (event);
2812 /* If we can pull that's prefered */
2814 gst_flv_demux_sink_activate (GstPad * sinkpad)
2816 if (gst_pad_check_pull_range (sinkpad)) {
2817 return gst_pad_activate_pull (sinkpad, TRUE);
2819 return gst_pad_activate_push (sinkpad, TRUE);
2823 /* This function gets called when we activate ourselves in push mode.
2824 * We cannot seek (ourselves) in the stream */
2826 gst_flv_demux_sink_activate_push (GstPad * sinkpad, gboolean active)
2830 demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
2832 demux->random_access = FALSE;
2834 gst_object_unref (demux);
2839 /* this function gets called when we activate ourselves in pull mode.
2840 * We can perform random access to the resource and we start a task
2841 * to start reading */
2843 gst_flv_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
2847 demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
2850 demux->random_access = TRUE;
2851 gst_object_unref (demux);
2852 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
2855 demux->random_access = FALSE;
2856 gst_object_unref (demux);
2857 return gst_pad_stop_task (sinkpad);
2862 gst_flv_demux_sink_event (GstPad * pad, GstEvent * event)
2865 gboolean ret = FALSE;
2867 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2869 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2871 switch (GST_EVENT_TYPE (event)) {
2872 case GST_EVENT_FLUSH_START:
2873 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
2874 demux->flushing = TRUE;
2875 ret = gst_flv_demux_push_src_event (demux, event);
2877 case GST_EVENT_FLUSH_STOP:
2878 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
2879 gst_flv_demux_flush (demux, TRUE);
2880 ret = gst_flv_demux_push_src_event (demux, event);
2883 GST_DEBUG_OBJECT (demux, "received EOS");
2885 GST_DEBUG_OBJECT (demux, "committing index");
2886 gst_index_commit (demux->index, demux->index_id);
2888 if (!demux->no_more_pads) {
2889 gst_element_no_more_pads (GST_ELEMENT (demux));
2890 demux->no_more_pads = TRUE;
2893 if (!gst_flv_demux_push_src_event (demux, event))
2894 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2897 case GST_EVENT_NEWSEGMENT:
2901 gint64 start, stop, time;
2904 GST_DEBUG_OBJECT (demux, "received new segment");
2906 gst_event_parse_new_segment (event, &update, &rate, &format, &start,
2909 if (format == GST_FORMAT_TIME) {
2910 /* time segment, this is perfect, copy over the values. */
2911 gst_segment_set_newsegment (&demux->segment, update, rate, format,
2914 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
2918 ret = gst_flv_demux_push_src_event (demux, event);
2920 /* non-time format */
2921 demux->audio_need_segment = TRUE;
2922 demux->video_need_segment = TRUE;
2924 gst_event_unref (event);
2929 ret = gst_flv_demux_push_src_event (demux, event);
2933 gst_object_unref (demux);
2939 gst_flv_demux_src_event (GstPad * pad, GstEvent * event)
2942 gboolean ret = FALSE;
2944 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2946 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2948 switch (GST_EVENT_TYPE (event)) {
2949 case GST_EVENT_SEEK:
2950 if (demux->random_access) {
2951 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
2953 ret = gst_flv_demux_handle_seek_push (demux, event);
2957 ret = gst_pad_push_event (demux->sinkpad, event);
2961 gst_object_unref (demux);
2967 gst_flv_demux_query (GstPad * pad, GstQuery * query)
2969 gboolean res = TRUE;
2972 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2974 switch (GST_QUERY_TYPE (query)) {
2975 case GST_QUERY_DURATION:
2979 gst_query_parse_duration (query, &format, NULL);
2981 /* duration is time only */
2982 if (format != GST_FORMAT_TIME) {
2983 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
2989 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
2990 GST_TIME_ARGS (demux->duration));
2992 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
2996 case GST_QUERY_POSITION:
3000 gst_query_parse_position (query, &format, NULL);
3002 /* position is time only */
3003 if (format != GST_FORMAT_TIME) {
3004 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3010 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3011 GST_TIME_ARGS (demux->segment.last_stop));
3013 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.last_stop);
3018 case GST_QUERY_SEEKING:{
3021 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3023 /* First ask upstream */
3024 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3027 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3034 if (fmt != GST_FORMAT_TIME || !demux->index) {
3035 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3036 } else if (demux->random_access) {
3037 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3040 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3041 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3044 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3045 gst_query_unref (peerquery);
3048 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3051 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3055 case GST_QUERY_LATENCY:
3060 if ((peer = gst_pad_get_peer (demux->sinkpad))) {
3061 /* query latency on peer pad */
3062 res = gst_pad_query (peer, query);
3063 gst_object_unref (peer);
3065 /* no peer, we don't know */
3073 gst_object_unref (demux);
3078 static GstStateChangeReturn
3079 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3082 GstStateChangeReturn ret;
3084 demux = GST_FLV_DEMUX (element);
3086 switch (transition) {
3087 case GST_STATE_CHANGE_READY_TO_PAUSED:
3088 /* If this is our own index destroy it as the
3089 * old entries might be wrong for the new stream */
3090 if (demux->own_index) {
3091 gst_object_unref (demux->index);
3092 demux->index = NULL;
3093 demux->own_index = FALSE;
3096 /* If no index was created, generate one */
3097 if (G_UNLIKELY (!demux->index)) {
3098 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3100 demux->index = gst_index_factory_make ("memindex");
3102 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3104 demux->own_index = TRUE;
3106 gst_flv_demux_cleanup (demux);
3112 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3113 if (ret == GST_STATE_CHANGE_FAILURE)
3116 switch (transition) {
3117 case GST_STATE_CHANGE_PAUSED_TO_READY:
3118 gst_flv_demux_cleanup (demux);
3128 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3130 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3132 GST_OBJECT_LOCK (demux);
3134 gst_object_unref (demux->index);
3136 demux->index = gst_object_ref (index);
3137 demux->own_index = FALSE;
3139 demux->index = NULL;
3141 GST_OBJECT_UNLOCK (demux);
3142 /* object lock might be taken again */
3144 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3145 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3150 gst_flv_demux_get_index (GstElement * element)
3152 GstIndex *result = NULL;
3154 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3156 GST_OBJECT_LOCK (demux);
3158 result = gst_object_ref (demux->index);
3159 GST_OBJECT_UNLOCK (demux);
3165 gst_flv_demux_dispose (GObject * object)
3167 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3169 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3171 if (demux->adapter) {
3172 gst_adapter_clear (demux->adapter);
3173 g_object_unref (demux->adapter);
3174 demux->adapter = NULL;
3177 if (demux->taglist) {
3178 gst_tag_list_free (demux->taglist);
3179 demux->taglist = NULL;
3182 if (demux->new_seg_event) {
3183 gst_event_unref (demux->new_seg_event);
3184 demux->new_seg_event = NULL;
3187 if (demux->close_seg_event) {
3188 gst_event_unref (demux->close_seg_event);
3189 demux->close_seg_event = NULL;
3192 if (demux->audio_codec_data) {
3193 gst_buffer_unref (demux->audio_codec_data);
3194 demux->audio_codec_data = NULL;
3197 if (demux->video_codec_data) {
3198 gst_buffer_unref (demux->video_codec_data);
3199 demux->video_codec_data = NULL;
3202 if (demux->audio_pad) {
3203 gst_object_unref (demux->audio_pad);
3204 demux->audio_pad = NULL;
3207 if (demux->video_pad) {
3208 gst_object_unref (demux->video_pad);
3209 demux->video_pad = NULL;
3213 gst_object_unref (demux->index);
3214 demux->index = NULL;
3218 g_array_free (demux->times, TRUE);
3219 demux->times = NULL;
3222 if (demux->filepositions) {
3223 g_array_free (demux->filepositions, TRUE);
3224 demux->filepositions = NULL;
3227 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3231 gst_flv_demux_base_init (gpointer g_class)
3233 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
3235 gst_element_class_add_static_pad_template (element_class,
3236 &flv_sink_template);
3237 gst_element_class_add_static_pad_template (element_class,
3238 &audio_src_template);
3239 gst_element_class_add_static_pad_template (element_class,
3240 &video_src_template);
3241 gst_element_class_set_details_simple (element_class, "FLV Demuxer",
3243 "Demux FLV feeds into digital streams",
3244 "Julien Moutte <julien@moutte.net>");
3248 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3250 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3251 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3253 gobject_class->dispose = gst_flv_demux_dispose;
3255 gstelement_class->change_state =
3256 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3257 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3258 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3262 gst_flv_demux_init (GstFlvDemux * demux, GstFlvDemuxClass * g_class)
3265 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3267 gst_pad_set_event_function (demux->sinkpad,
3268 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3269 gst_pad_set_chain_function (demux->sinkpad,
3270 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3271 gst_pad_set_activate_function (demux->sinkpad,
3272 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3273 gst_pad_set_activatepull_function (demux->sinkpad,
3274 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_pull));
3275 gst_pad_set_activatepush_function (demux->sinkpad,
3276 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_push));
3278 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3280 demux->adapter = gst_adapter_new ();
3281 demux->taglist = gst_tag_list_new ();
3282 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3284 demux->own_index = FALSE;
3286 gst_flv_demux_cleanup (demux);
3290 plugin_init (GstPlugin * plugin)
3292 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3294 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3295 gst_flv_demux_get_type ()) ||
3296 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3297 gst_flv_mux_get_type ()))
3303 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3304 "flv", "FLV muxing and demuxing plugin",
3305 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)