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 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
38 * with newer GLib versions (>= 2.31.0) */
39 #define GLIB_DISABLE_DEPRECATION_WARNINGS
41 #include "gstflvdemux.h"
42 #include "gstflvmux.h"
45 #include <gst/base/gstbytereader.h>
46 #include <gst/pbutils/descriptions.h>
47 #include <gst/pbutils/pbutils.h>
49 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
52 GST_STATIC_CAPS ("video/x-flv")
55 static GstStaticPadTemplate audio_src_template =
56 GST_STATIC_PAD_TEMPLATE ("audio",
60 ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
61 "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
62 "audio/mpeg, mpegversion = (int) 4, stream-format = (string) raw, framed = (boolean) TRUE; "
63 "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
64 "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; "
65 "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; "
66 "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
67 "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
68 "audio/x-speex, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 };")
71 static GstStaticPadTemplate video_src_template =
72 GST_STATIC_PAD_TEMPLATE ("video",
75 GST_STATIC_CAPS ("video/x-flash-video; "
76 "video/x-flash-screen; "
77 "video/x-vp6-flash; " "video/x-vp6-alpha; "
78 "video/x-h264, stream-format=avc;")
81 GST_DEBUG_CATEGORY_STATIC (flvdemux_debug);
82 #define GST_CAT_DEFAULT flvdemux_debug
84 GST_BOILERPLATE (GstFlvDemux, gst_flv_demux, GstElement, GST_TYPE_ELEMENT);
86 /* 9 bytes of header + 4 bytes of first previous tag size */
87 #define FLV_HEADER_SIZE 13
88 /* 1 byte of tag type + 3 bytes of tag data size */
89 #define FLV_TAG_TYPE_SIZE 4
91 /* two seconds - consider pts are resynced to another base if this different */
92 #define RESYNC_THRESHOLD 2000
94 static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
96 static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
97 GstEvent * event, gboolean seeking);
99 static gboolean gst_flv_demux_query (GstPad * pad, GstQuery * query);
100 static gboolean gst_flv_demux_src_event (GstPad * pad, GstEvent * event);
102 static GstIndex *gst_flv_demux_get_index (GstElement * element);
105 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
106 guint64 pos, gboolean keyframe)
108 GstIndexAssociation associations[2];
110 GstIndexEntry *entry;
112 GST_LOG_OBJECT (demux,
113 "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
114 keyframe, GST_TIME_ARGS (ts), pos);
116 /* if upstream is not seekable there is no point in building an index */
117 if (!demux->upstream_seekable)
120 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
125 /* entry may already have been added before, avoid adding indefinitely */
126 entry = gst_index_get_assoc_entry (index, demux->index_id,
127 GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
130 #ifndef GST_DISABLE_GST_DEBUG
134 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
135 key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
136 GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
137 ", keyframe %d", GST_TIME_ARGS (time), key);
138 /* there is not really a way to delete the existing one */
139 if (time != ts || key != ! !keyframe)
140 GST_DEBUG_OBJECT (demux, "metadata mismatch");
142 gst_object_unref (index);
146 associations[0].format = GST_FORMAT_TIME;
147 associations[0].value = ts;
148 associations[1].format = GST_FORMAT_BYTES;
149 associations[1].value = pos;
151 gst_index_add_associationv (index, demux->index_id,
152 (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
153 GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
154 (const GstIndexAssociation *) &associations);
156 if (pos > demux->index_max_pos)
157 demux->index_max_pos = pos;
158 if (ts > demux->index_max_time)
159 demux->index_max_time = ts;
161 gst_object_unref (index);
165 FLV_GET_STRING (GstByteReader * reader)
167 guint16 string_size = 0;
168 gchar *string = NULL;
169 const guint8 *str = NULL;
171 g_return_val_if_fail (reader != NULL, NULL);
173 if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
176 if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
179 string = g_try_malloc0 (string_size + 1);
180 if (G_UNLIKELY (!string)) {
184 if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
189 memcpy (string, str, string_size);
190 if (!g_utf8_validate (string, string_size, NULL)) {
198 static const GstQueryType *
199 gst_flv_demux_query_types (GstPad * pad)
201 static const GstQueryType query_types[] = {
212 gst_flv_demux_check_seekability (GstFlvDemux * demux)
215 gint64 start = -1, stop = -1;
217 demux->upstream_seekable = FALSE;
219 query = gst_query_new_seeking (GST_FORMAT_BYTES);
220 if (!gst_pad_peer_query (demux->sinkpad, query)) {
221 GST_DEBUG_OBJECT (demux, "seeking query failed");
222 gst_query_unref (query);
226 gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
229 gst_query_unref (query);
231 /* try harder to query upstream size if we didn't get it the first time */
232 if (demux->upstream_seekable && stop == -1) {
233 GstFormat fmt = GST_FORMAT_BYTES;
235 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
236 gst_pad_query_peer_duration (demux->sinkpad, &fmt, &stop);
239 /* if upstream doesn't know the size, it's likely that it's not seekable in
240 * practice even if it technically may be seekable */
241 if (demux->upstream_seekable && (start != 0 || stop <= start)) {
242 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
243 demux->upstream_seekable = FALSE;
246 GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
250 parse_flv_demux_parse_date_string (GDate * date, const gchar * s)
252 g_date_set_parse (date, s);
253 if (g_date_valid (date))
256 /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
258 static const gchar *months[] = {
259 "Jan", "Feb", "Mar", "Apr",
260 "May", "Jun", "Jul", "Aug",
261 "Sep", "Oct", "Nov", "Dec"
263 gchar **tokens = g_strsplit (s, " ", -1);
268 if (g_strv_length (tokens) != 5)
271 if (strlen (tokens[1]) != 3)
273 for (i = 0; i < 12; i++) {
274 if (!strcmp (tokens[1], months[i])) {
280 g_date_set_month (date, i + 1);
282 d = g_ascii_strtoull (tokens[2], &endptr, 10);
283 if (d == 0 && *endptr != '\0')
286 g_date_set_day (date, d);
288 d = g_ascii_strtoull (tokens[4], &endptr, 10);
289 if (d == 0 && *endptr != '\0')
292 g_date_set_year (date, d);
301 gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
302 gboolean * end_marker)
304 gchar *tag_name = NULL;
307 /* Initialize the end_marker flag to FALSE */
310 /* Name of the tag */
311 tag_name = FLV_GET_STRING (reader);
312 if (G_UNLIKELY (!tag_name)) {
313 GST_WARNING_OBJECT (demux, "failed reading tag name");
317 /* What kind of object is that */
318 if (!gst_byte_reader_get_uint8 (reader, &tag_type))
321 GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
325 { /* Use a union to read the uint64 and then as a double */
328 if (!gst_byte_reader_get_float64_be (reader, &d))
331 GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
333 if (!strcmp (tag_name, "duration")) {
334 demux->duration = d * GST_SECOND;
336 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
337 GST_TAG_DURATION, demux->duration, NULL);
338 } else if (!strcmp (tag_name, "AspectRatioX")) {
340 demux->got_par = TRUE;
341 } else if (!strcmp (tag_name, "AspectRatioY")) {
343 demux->got_par = TRUE;
344 } else if (!strcmp (tag_name, "width")) {
346 } else if (!strcmp (tag_name, "height")) {
348 } else if (!strcmp (tag_name, "framerate")) {
349 demux->framerate = d;
351 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
360 if (!gst_byte_reader_get_uint8 (reader, &b))
363 GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
365 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
373 s = FLV_GET_STRING (reader);
377 GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
379 if (!strcmp (tag_name, "creationdate")) {
380 GDate *date = g_date_new ();
382 parse_flv_demux_parse_date_string (date, s);
383 if (!g_date_valid (date)) {
384 GST_DEBUG_OBJECT (demux, "Failed to parse string as date");
386 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
387 GST_TAG_DATE, date, NULL);
390 } else if (!strcmp (tag_name, "creator")) {
391 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
392 GST_TAG_ARTIST, s, NULL);
393 } else if (!strcmp (tag_name, "title")) {
394 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
395 GST_TAG_TITLE, s, NULL);
396 } else if (!strcmp (tag_name, "metadatacreator")) {
397 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
398 GST_TAG_ENCODER, s, NULL);
400 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
409 gboolean end_of_object_marker = FALSE;
411 while (!end_of_object_marker) {
412 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
413 &end_of_object_marker);
415 if (G_UNLIKELY (!ok)) {
416 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
423 case 8: // ECMA array
425 guint32 nb_elems = 0;
426 gboolean end_of_object_marker = FALSE;
428 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
431 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
434 while (!end_of_object_marker) {
435 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
436 &end_of_object_marker);
438 if (G_UNLIKELY (!ok)) {
439 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
446 case 9: // End marker
448 GST_DEBUG_OBJECT (demux, "end marker ?");
449 if (tag_name[0] == '\0') {
451 GST_DEBUG_OBJECT (demux, "end marker detected");
460 guint32 nb_elems = 0;
462 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
465 GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
467 if (!strcmp (tag_name, "times")) {
469 g_array_free (demux->times, TRUE);
471 demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
472 } else if (!strcmp (tag_name, "filepositions")) {
473 if (demux->filepositions) {
474 g_array_free (demux->filepositions, TRUE);
476 demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
480 guint8 elem_type = 0;
482 if (!gst_byte_reader_get_uint8 (reader, &elem_type))
490 if (!gst_byte_reader_get_float64_be (reader, &d))
493 GST_DEBUG_OBJECT (demux, "element is a double %f", d);
495 if (!strcmp (tag_name, "times") && demux->times) {
496 g_array_append_val (demux->times, d);
497 } else if (!strcmp (tag_name, "filepositions") &&
498 demux->filepositions) {
499 g_array_append_val (demux->filepositions, d);
504 GST_WARNING_OBJECT (demux, "unsupported array element type %d",
516 if (!gst_byte_reader_get_float64_be (reader, &d))
519 if (!gst_byte_reader_get_int16_be (reader, &i))
522 GST_DEBUG_OBJECT (demux,
523 "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
525 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
530 GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
544 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
546 GstFlowReturn ret = GST_FLOW_OK;
547 GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer);
550 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 7, GST_FLOW_ERROR);
552 gst_byte_reader_skip (&reader, 7);
554 GST_LOG_OBJECT (demux, "parsing a script tag");
556 if (!gst_byte_reader_get_uint8 (&reader, &type))
561 gchar *function_name;
564 function_name = FLV_GET_STRING (&reader);
566 GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
568 if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
569 gboolean end_marker = FALSE;
570 GST_DEBUG_OBJECT (demux, "we have a metadata script object");
572 if (!gst_byte_reader_get_uint8 (&reader, &type)) {
573 g_free (function_name);
580 guint32 nb_elems = 0;
583 if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
584 g_free (function_name);
588 /* The number of elements is just a hint, some files have
589 nb_elements == 0 and actually contain items. */
590 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
593 /* fallthrough to read data */
597 while (!end_marker) {
599 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
601 if (G_UNLIKELY (!ok)) {
602 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
609 GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
610 g_free (function_name);
614 demux->push_tags = TRUE;
617 g_free (function_name);
619 if (demux->times && demux->filepositions) {
622 /* If an index was found, insert associations */
623 num = MIN (demux->times->len, demux->filepositions->len);
624 for (i = 0; i < num; i++) {
625 guint64 time, fileposition;
627 time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
628 fileposition = g_array_index (demux->filepositions, gdouble, i);
629 gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
632 demux->indexed = TRUE;
640 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
641 guint32 rate, guint32 channels, guint32 width)
643 GstCaps *caps = NULL;
644 gchar *codec_name = NULL;
645 gboolean ret = FALSE;
646 guint adjusted_rate = rate;
650 caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
655 caps = gst_caps_new_simple ("audio/mpeg",
656 "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
657 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
661 /* Assuming little endian for 0 (aka endianness of the
662 * system on which the file was created) as most people
663 * are probably using little endian machines */
664 caps = gst_caps_new_simple ("audio/x-raw-int",
665 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
666 "signed", G_TYPE_BOOLEAN, (width == 8) ? FALSE : TRUE,
667 "width", G_TYPE_INT, width, "depth", G_TYPE_INT, width, NULL);
672 caps = gst_caps_new_simple ("audio/x-nellymoser", NULL);
676 /* use codec-data to extract and verify samplerate */
677 if (demux->audio_codec_data &&
678 GST_BUFFER_SIZE (demux->audio_codec_data) >= 2) {
682 ((GST_READ_UINT16_BE (GST_BUFFER_DATA (demux->audio_codec_data))));
683 freq_index = (freq_index & 0x0780) >> 7;
685 gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
687 if (adjusted_rate && (rate != adjusted_rate)) {
688 GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
691 adjusted_rate = rate;
694 caps = gst_caps_new_simple ("audio/mpeg",
695 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
696 "stream-format", G_TYPE_STRING, "raw", NULL);
700 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
703 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
706 caps = gst_caps_new_simple ("audio/x-speex", NULL);
709 GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
712 if (G_UNLIKELY (!caps)) {
713 GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
717 gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
718 "channels", G_TYPE_INT, channels, NULL);
720 if (demux->audio_codec_data) {
721 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
722 demux->audio_codec_data, NULL);
725 ret = gst_pad_set_caps (demux->audio_pad, caps);
727 if (G_LIKELY (ret)) {
728 /* Store the caps we got from tags */
729 demux->audio_codec_tag = codec_tag;
731 demux->channels = channels;
732 demux->width = width;
734 codec_name = gst_pb_utils_get_codec_description (caps);
737 if (demux->taglist == NULL)
738 demux->taglist = gst_tag_list_new ();
739 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
740 GST_TAG_AUDIO_CODEC, codec_name, NULL);
744 GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
745 GST_PTR_FORMAT, caps);
747 GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
748 GST_PTR_FORMAT, caps);
751 gst_caps_unref (caps);
758 gst_flv_demux_push_tags (GstFlvDemux * demux)
760 if (demux->has_audio && !demux->audio_pad) {
761 GST_DEBUG_OBJECT (demux,
762 "Waiting for audio stream pad to come up before we can push tags");
765 if (demux->has_video && !demux->video_pad) {
766 GST_DEBUG_OBJECT (demux,
767 "Waiting for video stream pad to come up before we can push tags");
770 if (demux->taglist) {
771 GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
773 gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
774 demux->taglist = gst_tag_list_new ();
775 demux->push_tags = FALSE;
780 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, gboolean discont,
781 guint32 * last, GstClockTime * offset)
783 gint32 dpts = pts - *last;
784 if (!discont && ABS (dpts) >= RESYNC_THRESHOLD) {
785 /* Theoretically, we should use substract the duration of the last buffer,
786 but this demuxer sends no durations on buffers, not sure if it cannot
787 know, or just does not care to calculate. */
788 *offset -= dpts * GST_MSECOND;
789 GST_WARNING_OBJECT (demux,
790 "Large pts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
791 GST_TIME_FORMAT "", dpts, GST_TIME_ARGS (*offset));
797 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
799 GstFlowReturn ret = GST_FLOW_OK;
800 guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
801 guint32 codec_data = 0, pts_ext = 0;
803 guint8 *data = GST_BUFFER_DATA (buffer);
806 GST_LOG_OBJECT (demux, "parsing an audio tag");
808 if (demux->no_more_pads && !demux->audio_pad) {
809 GST_WARNING_OBJECT (demux,
810 "Signaled no-more-pads already but had no audio pad -- ignoring");
814 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) == demux->tag_size,
817 /* Grab information about audio tag */
818 pts = GST_READ_UINT24_BE (data);
819 /* read the pts extension to 32 bits integer */
820 pts_ext = GST_READ_UINT8 (data + 3);
822 pts |= pts_ext << 24;
824 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
825 data[2], data[3], pts);
827 /* Error out on tags with too small headers */
828 if (GST_BUFFER_SIZE (buffer) < 11) {
829 GST_ERROR_OBJECT (demux, "Too small tag size (%d)",
830 GST_BUFFER_SIZE (buffer));
831 return GST_FLOW_ERROR;
834 /* Silently skip buffers with no data */
835 if (GST_BUFFER_SIZE (buffer) == 11)
838 /* Skip the stream id and go directly to the flags */
839 flags = GST_READ_UINT8 (data + 7);
850 if ((flags & 0x0C) == 0x0C) {
852 } else if ((flags & 0x0C) == 0x08) {
854 } else if ((flags & 0x0C) == 0x04) {
858 codec_tag = flags >> 4;
859 if (codec_tag == 10) { /* AAC has an extra byte for packet type */
865 /* codec tags with special rates */
866 if (codec_tag == 5 || codec_tag == 14)
868 else if (codec_tag == 4)
871 GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
872 "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
875 /* If we don't have our audio pad created, then create it. */
876 if (G_UNLIKELY (!demux->audio_pad)) {
879 gst_pad_new_from_template (gst_element_class_get_pad_template
880 (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
881 if (G_UNLIKELY (!demux->audio_pad)) {
882 GST_WARNING_OBJECT (demux, "failed creating audio pad");
883 ret = GST_FLOW_ERROR;
888 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
890 gst_object_unref (demux->audio_pad);
891 demux->audio_pad = NULL;
892 ret = GST_FLOW_ERROR;
896 GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
897 GST_PAD_CAPS (demux->audio_pad));
899 /* Set functions on the pad */
900 gst_pad_set_query_type_function (demux->audio_pad,
901 GST_DEBUG_FUNCPTR (gst_flv_demux_query_types));
902 gst_pad_set_query_function (demux->audio_pad,
903 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
904 gst_pad_set_event_function (demux->audio_pad,
905 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
907 gst_pad_use_fixed_caps (demux->audio_pad);
910 gst_pad_set_active (demux->audio_pad, TRUE);
912 /* We need to set caps before adding */
913 gst_element_add_pad (GST_ELEMENT (demux),
914 gst_object_ref (demux->audio_pad));
916 /* We only emit no more pads when we have audio and video. Indeed we can
917 * not trust the FLV header to tell us if there will be only audio or
918 * only video and we would just break discovery of some files */
919 if (demux->audio_pad && demux->video_pad) {
920 GST_DEBUG_OBJECT (demux, "emitting no more pads");
921 gst_element_no_more_pads (GST_ELEMENT (demux));
922 demux->no_more_pads = TRUE;
923 demux->push_tags = TRUE;
927 /* Check if caps have changed */
928 if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
929 codec_tag != demux->audio_codec_tag || width != demux->width)) {
930 GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
933 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
935 ret = GST_FLOW_ERROR;
940 /* Push taglist if present */
941 if (G_UNLIKELY (demux->push_tags))
942 gst_flv_demux_push_tags (demux);
944 /* Check if we have anything to push */
945 if (demux->tag_data_size <= codec_data) {
946 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
950 /* Create buffer from pad */
952 gst_buffer_create_sub (buffer, 7 + codec_data,
953 demux->tag_data_size - codec_data);
955 if (demux->audio_codec_tag == 10) {
956 guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
958 switch (aac_packet_type) {
961 /* AudioSpecificConfig data */
962 GST_LOG_OBJECT (demux, "got an AAC codec data packet");
963 if (demux->audio_codec_data) {
964 gst_buffer_unref (demux->audio_codec_data);
966 demux->audio_codec_data = outbuf;
967 /* Use that buffer data in the caps */
968 gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels, width);
974 GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
977 GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
982 /* detect (and deem to be resyncs) large pts gaps */
983 gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
984 &demux->last_audio_pts, &demux->audio_time_offset);
986 /* Fill buffer with data */
987 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
988 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
989 GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
990 GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
991 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (demux->audio_pad));
993 if (demux->duration == GST_CLOCK_TIME_NONE ||
994 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
995 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
997 /* Only add audio frames to the index if we have no video,
998 * and if the index is not yet complete */
999 if (!demux->has_video && !demux->indexed) {
1000 gst_flv_demux_parse_and_add_index_entry (demux,
1001 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
1004 if (G_UNLIKELY (demux->audio_need_discont)) {
1005 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1006 demux->audio_need_discont = FALSE;
1009 gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME,
1010 GST_BUFFER_TIMESTAMP (outbuf));
1012 /* Do we need a newsegment event ? */
1013 if (G_UNLIKELY (demux->audio_need_segment)) {
1014 if (demux->close_seg_event)
1015 gst_pad_push_event (demux->audio_pad,
1016 gst_event_ref (demux->close_seg_event));
1018 if (!demux->new_seg_event) {
1019 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1020 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1021 GST_TIME_ARGS (demux->segment.last_stop),
1022 GST_TIME_ARGS (demux->segment.stop));
1023 demux->new_seg_event =
1024 gst_event_new_new_segment (FALSE, demux->segment.rate,
1025 demux->segment.format, demux->segment.last_stop,
1026 demux->segment.stop, demux->segment.last_stop);
1028 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1031 gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1033 demux->audio_need_segment = FALSE;
1036 GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
1037 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1038 GST_BUFFER_SIZE (outbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1039 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1041 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1042 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1044 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1045 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1048 if (G_UNLIKELY (!demux->no_more_pads
1049 && (GST_CLOCK_DIFF (demux->audio_start,
1050 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1051 GST_DEBUG_OBJECT (demux,
1052 "Signalling no-more-pads because no video stream was found"
1053 " after 6 seconds of audio");
1054 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1055 demux->no_more_pads = TRUE;
1056 demux->push_tags = TRUE;
1059 /* Push downstream */
1060 ret = gst_pad_push (demux->audio_pad, outbuf);
1061 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1062 if (demux->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
1063 demux->segment.last_stop > demux->segment.stop) {
1064 /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
1065 * we are at the end of the segment, so we just need to jump
1066 * back to the previous section. */
1067 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1068 demux->audio_done = TRUE;
1071 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1072 " bytes audio buffer: %s", demux->tag_data_size,
1073 gst_flow_get_name (ret));
1074 if (ret == GST_FLOW_NOT_LINKED) {
1075 demux->audio_linked = FALSE;
1081 demux->audio_linked = TRUE;
1088 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1090 gboolean ret = FALSE;
1091 GstCaps *caps = NULL;
1092 gchar *codec_name = NULL;
1094 /* Generate caps for that pad */
1095 switch (codec_tag) {
1097 caps = gst_caps_new_simple ("video/x-flash-video", NULL);
1100 caps = gst_caps_new_simple ("video/x-flash-screen", NULL);
1103 caps = gst_caps_new_simple ("video/x-vp6-flash", NULL);
1106 caps = gst_caps_new_simple ("video/x-vp6-alpha", NULL);
1110 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1114 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1117 if (G_UNLIKELY (!caps)) {
1118 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1122 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1123 demux->par_x, demux->par_y, NULL);
1125 if (G_LIKELY (demux->w)) {
1126 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1129 if (G_LIKELY (demux->h)) {
1130 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1133 if (G_LIKELY (demux->framerate)) {
1134 gint num = 0, den = 0;
1136 gst_util_double_to_fraction (demux->framerate, &num, &den);
1137 GST_DEBUG_OBJECT (demux->video_pad,
1138 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1141 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1144 if (demux->video_codec_data) {
1145 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1146 demux->video_codec_data, NULL);
1149 ret = gst_pad_set_caps (demux->video_pad, caps);
1151 if (G_LIKELY (ret)) {
1152 /* Store the caps we have set */
1153 demux->video_codec_tag = codec_tag;
1155 codec_name = gst_pb_utils_get_codec_description (caps);
1158 if (demux->taglist == NULL)
1159 demux->taglist = gst_tag_list_new ();
1160 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1161 GST_TAG_VIDEO_CODEC, codec_name, NULL);
1162 g_free (codec_name);
1165 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1166 GST_PTR_FORMAT, caps);
1168 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1169 GST_PTR_FORMAT, caps);
1172 gst_caps_unref (caps);
1178 static GstFlowReturn
1179 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1181 GstFlowReturn ret = GST_FLOW_OK;
1182 guint32 pts = 0, codec_data = 1, pts_ext = 0;
1183 gboolean keyframe = FALSE;
1184 guint8 flags = 0, codec_tag = 0;
1185 guint8 *data = GST_BUFFER_DATA (buffer);
1188 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) == demux->tag_size,
1191 GST_LOG_OBJECT (demux, "parsing a video tag");
1194 if (demux->no_more_pads && !demux->video_pad) {
1195 GST_WARNING_OBJECT (demux,
1196 "Signaled no-more-pads already but had no audio pad -- ignoring");
1200 /* Grab information about video tag */
1201 pts = GST_READ_UINT24_BE (data);
1202 /* read the pts extension to 32 bits integer */
1203 pts_ext = GST_READ_UINT8 (data + 3);
1205 pts |= pts_ext << 24;
1207 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1208 data[2], data[3], pts);
1210 if (GST_BUFFER_SIZE (buffer) < 12) {
1211 GST_ERROR_OBJECT (demux, "Too small tag size");
1212 return GST_FLOW_ERROR;
1215 /* Skip the stream id and go directly to the flags */
1216 flags = GST_READ_UINT8 (data + 7);
1219 if ((flags >> 4) == 1) {
1223 codec_tag = flags & 0x0F;
1224 if (codec_tag == 4 || codec_tag == 5) {
1226 } else if (codec_tag == 7) {
1231 cts = GST_READ_UINT24_BE (data + 9);
1232 cts = (cts + 0xff800000) ^ 0xff800000;
1234 GST_LOG_OBJECT (demux, "got cts %d", cts);
1236 /* avoid negative overflow */
1237 if (cts >= 0 || pts >= -cts)
1241 GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1242 "(flags %02X)", codec_tag, keyframe, flags);
1244 /* If we don't have our video pad created, then create it. */
1245 if (G_UNLIKELY (!demux->video_pad)) {
1247 gst_pad_new_from_template (gst_element_class_get_pad_template
1248 (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1249 if (G_UNLIKELY (!demux->video_pad)) {
1250 GST_WARNING_OBJECT (demux, "failed creating video pad");
1251 ret = GST_FLOW_ERROR;
1255 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1256 gst_object_unref (demux->video_pad);
1257 demux->video_pad = NULL;
1258 ret = GST_FLOW_ERROR;
1262 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1263 * metadata tag that would come later and trigger a caps change */
1264 demux->got_par = FALSE;
1266 GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1267 GST_PAD_CAPS (demux->video_pad));
1269 /* Set functions on the pad */
1270 gst_pad_set_query_type_function (demux->video_pad,
1271 GST_DEBUG_FUNCPTR (gst_flv_demux_query_types));
1272 gst_pad_set_query_function (demux->video_pad,
1273 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1274 gst_pad_set_event_function (demux->video_pad,
1275 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1277 gst_pad_use_fixed_caps (demux->video_pad);
1279 /* Make it active */
1280 gst_pad_set_active (demux->video_pad, TRUE);
1282 /* We need to set caps before adding */
1283 gst_element_add_pad (GST_ELEMENT (demux),
1284 gst_object_ref (demux->video_pad));
1286 /* We only emit no more pads when we have audio and video. Indeed we can
1287 * not trust the FLV header to tell us if there will be only audio or
1288 * only video and we would just break discovery of some files */
1289 if (demux->audio_pad && demux->video_pad) {
1290 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1291 gst_element_no_more_pads (GST_ELEMENT (demux));
1292 demux->no_more_pads = TRUE;
1293 demux->push_tags = TRUE;
1297 /* Check if caps have changed */
1298 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1300 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1302 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1303 ret = GST_FLOW_ERROR;
1307 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1308 * metadata tag that would come later and trigger a caps change */
1309 demux->got_par = FALSE;
1312 /* Push taglist if present */
1313 if (G_UNLIKELY (demux->push_tags))
1314 gst_flv_demux_push_tags (demux);
1316 /* Check if we have anything to push */
1317 if (demux->tag_data_size <= codec_data) {
1318 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1322 /* Create buffer from pad */
1324 gst_buffer_create_sub (buffer, 7 + codec_data,
1325 demux->tag_data_size - codec_data);
1327 if (demux->video_codec_tag == 7) {
1328 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1330 switch (avc_packet_type) {
1333 /* AVCDecoderConfigurationRecord data */
1334 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1335 if (demux->video_codec_data) {
1336 gst_buffer_unref (demux->video_codec_data);
1338 demux->video_codec_data = outbuf;
1339 /* Use that buffer data in the caps */
1340 gst_flv_demux_video_negotiate (demux, codec_tag);
1345 /* H.264 NALU packet */
1346 GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1349 GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1354 /* detect (and deem to be resyncs) large pts gaps */
1355 gst_flv_demux_update_resync (demux, pts, demux->video_need_discont,
1356 &demux->last_video_pts, &demux->video_time_offset);
1358 /* Fill buffer with data */
1359 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
1360 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1361 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1362 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1363 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (demux->video_pad));
1365 if (demux->duration == GST_CLOCK_TIME_NONE ||
1366 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1367 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1370 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1372 if (!demux->indexed) {
1373 gst_flv_demux_parse_and_add_index_entry (demux,
1374 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1377 if (G_UNLIKELY (demux->video_need_discont)) {
1378 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1379 demux->video_need_discont = FALSE;
1382 gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME,
1383 GST_BUFFER_TIMESTAMP (outbuf));
1385 /* Do we need a newsegment event ? */
1386 if (G_UNLIKELY (demux->video_need_segment)) {
1387 if (demux->close_seg_event)
1388 gst_pad_push_event (demux->video_pad,
1389 gst_event_ref (demux->close_seg_event));
1391 if (!demux->new_seg_event) {
1392 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1393 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1394 GST_TIME_ARGS (demux->segment.last_stop),
1395 GST_TIME_ARGS (demux->segment.stop));
1396 demux->new_seg_event =
1397 gst_event_new_new_segment (FALSE, demux->segment.rate,
1398 demux->segment.format, demux->segment.last_stop,
1399 demux->segment.stop, demux->segment.last_stop);
1401 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1404 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1406 demux->video_need_segment = FALSE;
1409 GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
1410 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1411 ", keyframe (%d)", GST_BUFFER_SIZE (outbuf),
1412 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1413 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1416 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1417 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1419 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1420 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1423 if (G_UNLIKELY (!demux->no_more_pads
1424 && (GST_CLOCK_DIFF (demux->video_start,
1425 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1426 GST_DEBUG_OBJECT (demux,
1427 "Signalling no-more-pads because no audio stream was found"
1428 " after 6 seconds of video");
1429 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1430 demux->no_more_pads = TRUE;
1431 demux->push_tags = TRUE;
1434 /* Push downstream */
1435 ret = gst_pad_push (demux->video_pad, outbuf);
1437 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1438 if (demux->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
1439 demux->segment.last_stop > demux->segment.stop) {
1440 /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
1441 * we are at the end of the segment, so we just need to jump
1442 * back to the previous section. */
1443 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1444 demux->video_done = TRUE;
1447 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1448 " bytes video buffer: %s", demux->tag_data_size,
1449 gst_flow_get_name (ret));
1450 if (ret == GST_FLOW_NOT_LINKED) {
1451 demux->video_linked = FALSE;
1457 demux->video_linked = TRUE;
1464 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1465 GstBuffer * buffer, size_t * tag_size)
1467 guint32 pts = 0, pts_ext = 0;
1468 guint32 tag_data_size;
1470 gboolean keyframe = TRUE;
1472 guint8 *data = GST_BUFFER_DATA (buffer);
1474 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 12, GST_CLOCK_TIME_NONE);
1478 if (type != 9 && type != 8 && type != 18) {
1479 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1480 return GST_CLOCK_TIME_NONE;
1484 demux->has_video = TRUE;
1486 demux->has_audio = TRUE;
1488 tag_data_size = GST_READ_UINT24_BE (data + 1);
1490 if (GST_BUFFER_SIZE (buffer) >= tag_data_size + 11 + 4) {
1491 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1492 GST_WARNING_OBJECT (demux, "Invalid tag size");
1493 return GST_CLOCK_TIME_NONE;
1498 *tag_size = tag_data_size + 11 + 4;
1502 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
1505 /* Grab timestamp of tag tag */
1506 pts = GST_READ_UINT24_BE (data);
1507 /* read the pts extension to 32 bits integer */
1508 pts_ext = GST_READ_UINT8 (data + 3);
1510 pts |= pts_ext << 24;
1515 keyframe = ((data[0] >> 4) == 1);
1518 ret = pts * GST_MSECOND;
1519 GST_LOG_OBJECT (demux, "pts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1521 if (index && !demux->indexed && (type == 9 || (type == 8
1522 && !demux->has_video))) {
1523 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1527 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1528 demux->duration = ret;
1533 static GstFlowReturn
1534 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1536 GstFlowReturn ret = GST_FLOW_OK;
1537 guint8 tag_type = 0;
1538 guint8 *data = GST_BUFFER_DATA (buffer);
1540 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 4, GST_FLOW_ERROR);
1546 demux->state = FLV_STATE_TAG_VIDEO;
1547 demux->has_video = TRUE;
1550 demux->state = FLV_STATE_TAG_AUDIO;
1551 demux->has_audio = TRUE;
1554 demux->state = FLV_STATE_TAG_SCRIPT;
1557 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1560 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1561 * 4 bytes of previous tag size */
1562 demux->tag_data_size = GST_READ_UINT24_BE (data + 1);
1563 demux->tag_size = demux->tag_data_size + 11;
1565 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1566 demux->tag_data_size);
1571 static GstFlowReturn
1572 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1574 GstFlowReturn ret = GST_FLOW_OK;
1575 guint8 *data = GST_BUFFER_DATA (buffer);
1577 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 9, GST_FLOW_ERROR);
1579 /* Check for the FLV tag */
1580 if (data[0] == 'F' && data[1] == 'L' && data[2] == 'V') {
1581 GST_DEBUG_OBJECT (demux, "FLV header detected");
1583 if (G_UNLIKELY (demux->strict)) {
1584 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1585 ret = GST_FLOW_UNEXPECTED;
1590 /* Jump over the 4 first bytes */
1593 /* Now look at audio/video flags */
1595 guint8 flags = data[0];
1597 demux->has_video = demux->has_audio = FALSE;
1600 GST_DEBUG_OBJECT (demux, "there is a video stream");
1601 demux->has_video = TRUE;
1604 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1605 demux->has_audio = TRUE;
1609 /* do a one-time seekability check */
1610 gst_flv_demux_check_seekability (demux);
1612 /* We don't care about the rest */
1613 demux->need_header = FALSE;
1621 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1623 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1625 gst_adapter_clear (demux->adapter);
1627 demux->audio_need_discont = TRUE;
1628 demux->video_need_discont = TRUE;
1630 demux->flushing = FALSE;
1632 /* Only in push mode and if we're not during a seek */
1633 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1634 /* After a flush we expect a tag_type */
1635 demux->state = FLV_STATE_TAG_TYPE;
1636 /* We reset the offset and will get one from first push */
1642 gst_flv_demux_cleanup (GstFlvDemux * demux)
1644 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1646 demux->state = FLV_STATE_HEADER;
1648 demux->flushing = FALSE;
1649 demux->need_header = TRUE;
1650 demux->audio_need_segment = TRUE;
1651 demux->video_need_segment = TRUE;
1652 demux->audio_need_discont = TRUE;
1653 demux->video_need_discont = TRUE;
1655 /* By default we consider them as linked */
1656 demux->audio_linked = TRUE;
1657 demux->video_linked = TRUE;
1659 demux->has_audio = FALSE;
1660 demux->has_video = FALSE;
1661 demux->push_tags = FALSE;
1662 demux->got_par = FALSE;
1664 demux->indexed = FALSE;
1665 demux->upstream_seekable = FALSE;
1666 demux->file_size = 0;
1668 demux->index_max_pos = 0;
1669 demux->index_max_time = 0;
1671 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1672 demux->last_audio_pts = demux->last_video_pts = 0;
1673 demux->audio_time_offset = demux->video_time_offset = 0;
1675 demux->no_more_pads = FALSE;
1677 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1679 demux->w = demux->h = 0;
1680 demux->framerate = 0.0;
1681 demux->par_x = demux->par_y = 1;
1682 demux->video_offset = 0;
1683 demux->audio_offset = 0;
1684 demux->offset = demux->cur_tag_offset = 0;
1685 demux->tag_size = demux->tag_data_size = 0;
1686 demux->duration = GST_CLOCK_TIME_NONE;
1688 if (demux->new_seg_event) {
1689 gst_event_unref (demux->new_seg_event);
1690 demux->new_seg_event = NULL;
1693 if (demux->close_seg_event) {
1694 gst_event_unref (demux->close_seg_event);
1695 demux->close_seg_event = NULL;
1698 gst_adapter_clear (demux->adapter);
1700 if (demux->audio_codec_data) {
1701 gst_buffer_unref (demux->audio_codec_data);
1702 demux->audio_codec_data = NULL;
1705 if (demux->video_codec_data) {
1706 gst_buffer_unref (demux->video_codec_data);
1707 demux->video_codec_data = NULL;
1710 if (demux->audio_pad) {
1711 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1712 gst_object_unref (demux->audio_pad);
1713 demux->audio_pad = NULL;
1716 if (demux->video_pad) {
1717 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1718 gst_object_unref (demux->video_pad);
1719 demux->video_pad = NULL;
1723 g_array_free (demux->times, TRUE);
1724 demux->times = NULL;
1727 if (demux->filepositions) {
1728 g_array_free (demux->filepositions, TRUE);
1729 demux->filepositions = NULL;
1734 * Create and push a flushing seek event upstream
1737 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1742 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1745 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1746 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1747 GST_SEEK_TYPE_NONE, -1);
1749 res = gst_pad_push_event (demux->sinkpad, event);
1752 demux->offset = offset;
1756 static GstFlowReturn
1757 gst_flv_demux_chain (GstPad * pad, GstBuffer * buffer)
1759 GstFlowReturn ret = GST_FLOW_OK;
1760 GstFlvDemux *demux = NULL;
1762 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
1764 GST_LOG_OBJECT (demux, "received buffer of %d bytes at offset %"
1765 G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer));
1767 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1768 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1769 demux->state = FLV_STATE_HEADER;
1773 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
1774 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
1775 demux->offset = GST_BUFFER_OFFSET (buffer);
1778 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1779 GST_DEBUG_OBJECT (demux, "Discontinuity");
1780 gst_adapter_clear (demux->adapter);
1783 gst_adapter_push (demux->adapter, buffer);
1785 if (demux->seeking) {
1786 demux->state = FLV_STATE_SEEK;
1787 GST_OBJECT_LOCK (demux);
1788 demux->seeking = FALSE;
1789 GST_OBJECT_UNLOCK (demux);
1793 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1794 if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
1795 || demux->video_linked)) {
1798 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
1803 if (G_UNLIKELY (demux->flushing)) {
1804 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
1805 ret = GST_FLOW_WRONG_STATE;
1809 switch (demux->state) {
1810 case FLV_STATE_HEADER:
1812 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
1815 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
1817 ret = gst_flv_demux_parse_header (demux, buffer);
1819 gst_buffer_unref (buffer);
1820 demux->offset += FLV_HEADER_SIZE;
1822 demux->state = FLV_STATE_TAG_TYPE;
1828 case FLV_STATE_TAG_TYPE:
1830 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
1833 /* Remember the tag offset in bytes */
1834 demux->cur_tag_offset = demux->offset;
1836 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
1838 ret = gst_flv_demux_parse_tag_type (demux, buffer);
1840 gst_buffer_unref (buffer);
1841 demux->offset += FLV_TAG_TYPE_SIZE;
1843 /* last tag is not an index => no index/don't know where the index is
1844 * seek back to the beginning */
1845 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
1853 case FLV_STATE_TAG_VIDEO:
1855 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1858 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1860 ret = gst_flv_demux_parse_tag_video (demux, buffer);
1862 gst_buffer_unref (buffer);
1863 demux->offset += demux->tag_size;
1865 demux->state = FLV_STATE_TAG_TYPE;
1871 case FLV_STATE_TAG_AUDIO:
1873 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1876 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1878 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
1880 gst_buffer_unref (buffer);
1881 demux->offset += demux->tag_size;
1883 demux->state = FLV_STATE_TAG_TYPE;
1889 case FLV_STATE_TAG_SCRIPT:
1891 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1894 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1896 ret = gst_flv_demux_parse_tag_script (demux, buffer);
1898 gst_buffer_unref (buffer);
1899 demux->offset += demux->tag_size;
1901 demux->state = FLV_STATE_TAG_TYPE;
1903 /* if there's a seek event we're here for the index so if we don't have it
1904 * we seek back to the beginning */
1905 if (demux->seek_event) {
1907 demux->state = FLV_STATE_SEEK;
1917 case FLV_STATE_SEEK:
1923 if (!demux->indexed) {
1924 if (demux->offset == demux->file_size - sizeof (guint32)) {
1926 gst_adapter_take_buffer (demux->adapter, sizeof (guint32));
1927 GstByteReader *reader = gst_byte_reader_new_from_buffer (buffer);
1928 guint64 seek_offset;
1930 if (!gst_adapter_available (demux->adapter) >= sizeof (guint32)) {
1935 demux->file_size - sizeof (guint32) -
1936 gst_byte_reader_peek_uint32_be_unchecked (reader);
1937 gst_byte_reader_free (reader);
1938 gst_buffer_unref (buffer);
1940 GST_INFO_OBJECT (demux,
1941 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
1943 demux->state = FLV_STATE_TAG_TYPE;
1944 flv_demux_seek_to_offset (demux, seek_offset);
1950 GST_OBJECT_LOCK (demux);
1951 event = demux->seek_event;
1952 demux->seek_event = NULL;
1953 GST_OBJECT_UNLOCK (demux);
1955 /* calculate and perform seek */
1956 if (!flv_demux_handle_seek_push (demux, event))
1959 gst_event_unref (event);
1960 demux->state = FLV_STATE_TAG_TYPE;
1964 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
1968 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
1969 /* If either audio or video is linked we return GST_FLOW_OK */
1970 if (demux->audio_linked || demux->video_linked) {
1975 gst_object_unref (demux);
1982 GST_OBJECT_LOCK (demux);
1983 demux->seeking = FALSE;
1984 gst_event_unref (demux->seek_event);
1985 demux->seek_event = NULL;
1986 GST_OBJECT_UNLOCK (demux);
1987 GST_WARNING_OBJECT (demux,
1988 "failed to find an index, seeking back to beginning");
1989 flv_demux_seek_to_offset (demux, 0);
1994 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
1995 return GST_FLOW_ERROR;
2000 static GstFlowReturn
2001 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2002 guint size, GstBuffer ** buffer)
2006 ret = gst_pad_pull_range (pad, offset, size, buffer);
2007 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2008 GST_WARNING_OBJECT (demux,
2009 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2010 size, offset, gst_flow_get_name (ret));
2015 if (G_UNLIKELY (*buffer && GST_BUFFER_SIZE (*buffer) != size)) {
2016 GST_WARNING_OBJECT (demux,
2017 "partial pull got %d when expecting %d from offset %" G_GUINT64_FORMAT,
2018 GST_BUFFER_SIZE (*buffer), size, offset);
2019 gst_buffer_unref (*buffer);
2020 ret = GST_FLOW_UNEXPECTED;
2028 static GstFlowReturn
2029 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2031 GstBuffer *buffer = NULL;
2032 GstFlowReturn ret = GST_FLOW_OK;
2034 /* Store tag offset */
2035 demux->cur_tag_offset = demux->offset;
2037 /* Get the first 4 bytes to identify tag type and size */
2038 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2039 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2042 /* Identify tag type */
2043 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2045 gst_buffer_unref (buffer);
2047 if (G_UNLIKELY (ret != GST_FLOW_OK))
2050 /* Jump over tag type + size */
2051 demux->offset += FLV_TAG_TYPE_SIZE;
2053 /* Pull the whole tag */
2054 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2055 demux->tag_size, &buffer)) != GST_FLOW_OK))
2058 switch (demux->state) {
2059 case FLV_STATE_TAG_VIDEO:
2060 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2062 case FLV_STATE_TAG_AUDIO:
2063 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2065 case FLV_STATE_TAG_SCRIPT:
2066 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2069 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2072 gst_buffer_unref (buffer);
2074 /* Jump over that part we've just parsed */
2075 demux->offset += demux->tag_size;
2077 /* Make sure we reinitialize the tag size */
2078 demux->tag_size = 0;
2080 /* Ready for the next tag */
2081 demux->state = FLV_STATE_TAG_TYPE;
2083 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2084 /* If either audio or video is linked we return GST_FLOW_OK */
2085 if (demux->audio_linked || demux->video_linked) {
2088 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2089 "neither video nor audio are linked");
2097 static GstFlowReturn
2098 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2100 GstBuffer *buffer = NULL;
2101 GstFlowReturn ret = GST_FLOW_OK;
2103 /* Get the first 9 bytes */
2104 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2105 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2108 ret = gst_flv_demux_parse_header (demux, buffer);
2110 gst_buffer_unref (buffer);
2112 /* Jump over the header now */
2113 demux->offset += FLV_HEADER_SIZE;
2114 demux->state = FLV_STATE_TAG_TYPE;
2121 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2124 demux->offset = offset;
2126 /* Tell all the stream we moved to a different position (discont) */
2127 demux->audio_need_discont = TRUE;
2128 demux->video_need_discont = TRUE;
2130 /* next section setup */
2131 demux->from_offset = -1;
2132 demux->audio_done = demux->video_done = FALSE;
2133 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2136 demux->from_offset = -1;
2137 demux->to_offset = G_MAXINT64;
2140 /* If we seeked at the beginning of the file parse the header again */
2141 if (G_UNLIKELY (!demux->offset)) {
2142 demux->state = FLV_STATE_HEADER;
2143 } else { /* or parse a tag */
2144 demux->state = FLV_STATE_TAG_TYPE;
2148 static GstFlowReturn
2149 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2151 GstFlowReturn ret = GST_FLOW_UNEXPECTED;
2153 GstIndexEntry *entry = NULL;
2155 GST_DEBUG_OBJECT (demux,
2156 "terminated section started at offset %" G_GINT64_FORMAT,
2157 demux->from_offset);
2159 /* we are done if we got all audio and video */
2160 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2161 demux->audio_first_ts < demux->segment.start) &&
2162 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2163 demux->video_first_ts < demux->segment.start))
2166 if (demux->from_offset <= 0)
2169 GST_DEBUG_OBJECT (demux, "locating previous position");
2171 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2173 /* locate index entry before previous start position */
2175 entry = gst_index_get_assoc_entry (index, demux->index_id,
2176 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2177 GST_FORMAT_BYTES, demux->from_offset - 1);
2182 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2183 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2185 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2186 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2187 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2189 /* setup for next section */
2190 demux->to_offset = demux->from_offset;
2191 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2195 gst_object_unref (index);
2204 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
2206 gboolean ret = TRUE;
2208 if (demux->audio_pad)
2209 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
2211 if (demux->video_pad)
2212 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
2214 gst_event_unref (event);
2219 static GstFlowReturn
2220 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2223 GstFormat fmt = GST_FORMAT_BYTES;
2227 GstClockTime tag_time;
2228 GstFlowReturn ret = GST_FLOW_OK;
2230 if (G_UNLIKELY (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &size) ||
2231 fmt != GST_FORMAT_BYTES))
2234 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2235 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2237 old_offset = demux->offset;
2238 demux->offset = pos;
2240 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2241 12, &buffer)) == GST_FLOW_OK) {
2243 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2245 gst_buffer_unref (buffer);
2247 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2250 demux->offset += tag_size;
2253 if (ret == GST_FLOW_UNEXPECTED) {
2254 /* file ran out, so mark we have complete index */
2255 demux->indexed = TRUE;
2260 demux->offset = old_offset;
2266 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2268 gint64 ret = 0, offset;
2269 GstFormat fmt = GST_FORMAT_BYTES;
2270 size_t tag_size, size;
2271 GstBuffer *buffer = NULL;
2273 if (G_UNLIKELY (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &offset)
2274 || fmt != GST_FORMAT_BYTES))
2278 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2279 if (G_UNLIKELY (offset < 4))
2283 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2287 tag_size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buffer));
2288 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2289 gst_buffer_unref (buffer);
2293 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2297 /* a consistency check */
2298 size = GST_READ_UINT24_BE (GST_BUFFER_DATA (buffer) + 1);
2299 if (size != tag_size - 11) {
2300 GST_DEBUG_OBJECT (demux,
2301 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2302 ", corrupt or truncated file", size, tag_size - 11);
2306 /* try to update duration with timestamp in any case */
2307 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2309 /* maybe get some more metadata */
2310 if (GST_BUFFER_DATA (buffer)[0] == 18) {
2311 gst_buffer_unref (buffer);
2313 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2315 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2317 gst_flv_demux_parse_tag_script (demux, buffer);
2322 gst_buffer_unref (buffer);
2328 gst_flv_demux_loop (GstPad * pad)
2330 GstFlvDemux *demux = NULL;
2331 GstFlowReturn ret = GST_FLOW_OK;
2333 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2336 switch (demux->state) {
2337 case FLV_STATE_TAG_TYPE:
2338 if (demux->from_offset == -1)
2339 demux->from_offset = demux->offset;
2340 ret = gst_flv_demux_pull_tag (pad, demux);
2341 /* if we have seen real data, we probably passed a possible metadata
2342 * header located at start. So if we do not yet have an index,
2343 * try to pick up metadata (index, duration) at the end */
2344 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2345 (demux->has_video || demux->has_audio)))
2346 demux->file_size = gst_flv_demux_get_metadata (demux);
2348 case FLV_STATE_DONE:
2349 ret = GST_FLOW_UNEXPECTED;
2351 case FLV_STATE_SEEK:
2352 /* seek issued with insufficient index;
2353 * scan for index in task thread from current maximum offset to
2354 * desired time and then perform seek */
2355 /* TODO maybe some buffering message or so to indicate scan progress */
2356 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2358 if (ret != GST_FLOW_OK)
2360 /* position and state arranged by seek,
2361 * also unrefs event */
2362 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2363 demux->seek_event = NULL;
2366 ret = gst_flv_demux_pull_header (pad, demux);
2367 /* index scans start after header */
2368 demux->index_max_pos = demux->offset;
2372 if (demux->segment.rate < 0.0) {
2373 /* check end of section */
2374 if ((gint64) demux->offset >= demux->to_offset ||
2375 demux->segment.last_stop >= demux->segment.stop + 2 * GST_SECOND ||
2376 (demux->audio_done && demux->video_done))
2377 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2379 /* check EOS condition */
2380 if ((demux->segment.stop != -1) &&
2381 (demux->segment.last_stop >= demux->segment.stop)) {
2382 ret = GST_FLOW_UNEXPECTED;
2386 /* pause if something went wrong or at end */
2387 if (G_UNLIKELY (ret != GST_FLOW_OK))
2390 gst_object_unref (demux);
2396 const gchar *reason = gst_flow_get_name (ret);
2398 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2399 gst_pad_pause_task (pad);
2401 if (ret == GST_FLOW_UNEXPECTED) {
2402 /* perform EOS logic */
2403 if (!demux->no_more_pads) {
2404 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2405 demux->no_more_pads = TRUE;
2408 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2411 /* for segment playback we need to post when (in stream time)
2412 * we stopped, this is either stop (when set) or the duration. */
2413 if ((stop = demux->segment.stop) == -1)
2414 stop = demux->segment.duration;
2416 if (demux->segment.rate >= 0) {
2417 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2418 gst_element_post_message (GST_ELEMENT_CAST (demux),
2419 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2420 GST_FORMAT_TIME, stop));
2421 } else { /* Reverse playback */
2422 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2424 gst_element_post_message (GST_ELEMENT_CAST (demux),
2425 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2426 GST_FORMAT_TIME, demux->segment.start));
2429 /* normal playback, send EOS to all linked pads */
2430 if (!demux->no_more_pads) {
2431 gst_element_no_more_pads (GST_ELEMENT (demux));
2432 demux->no_more_pads = TRUE;
2435 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2436 if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2437 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2439 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
2440 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2441 ("Internal data stream error."),
2442 ("stream stopped, reason %s", reason));
2443 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2445 gst_object_unref (demux);
2451 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2456 GstIndexEntry *entry;
2458 g_return_val_if_fail (segment != NULL, 0);
2460 time = segment->last_stop;
2462 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2465 /* Let's check if we have an index entry for that seek time */
2466 entry = gst_index_get_assoc_entry (index, demux->index_id,
2467 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2468 GST_FORMAT_TIME, time);
2471 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2472 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2474 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2475 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2476 GST_TIME_ARGS (segment->last_stop), GST_TIME_ARGS (time), bytes);
2478 /* Key frame seeking */
2479 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2480 /* Adjust the segment so that the keyframe fits in */
2481 if (time < segment->start) {
2482 segment->start = segment->time = time;
2484 segment->last_stop = time;
2487 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2488 GST_TIME_ARGS (segment->start));
2491 gst_object_unref (index);
2498 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2502 GstSeekType start_type, stop_type;
2505 gboolean update, flush, ret;
2506 GstSegment seeksegment;
2508 gst_event_parse_seek (event, &rate, &format, &flags,
2509 &start_type, &start, &stop_type, &stop);
2511 if (format != GST_FORMAT_TIME)
2514 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2515 /* FIXME : the keyframe flag is never used ! */
2517 /* Work on a copy until we are sure the seek succeeded. */
2518 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2520 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2523 /* Apply the seek to our segment */
2524 gst_segment_set_seek (&seeksegment, rate, format, flags,
2525 start_type, start, stop_type, stop, &update);
2527 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2530 if (flush || seeksegment.last_stop != demux->segment.last_stop) {
2531 /* Do the actual seeking */
2532 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2534 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2535 G_GUINT64_FORMAT, offset);
2536 ret = gst_pad_push_event (demux->sinkpad,
2537 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2538 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2539 offset, GST_SEEK_TYPE_NONE, 0));
2540 if (G_UNLIKELY (!ret)) {
2541 GST_WARNING_OBJECT (demux, "upstream seek failed");
2544 /* Tell all the stream we moved to a different position (discont) */
2545 demux->audio_need_discont = TRUE;
2546 demux->video_need_discont = TRUE;
2552 /* Ok seek succeeded, take the newly configured segment */
2553 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2555 /* Tell all the stream a new segment is needed */
2556 demux->audio_need_segment = TRUE;
2557 demux->video_need_segment = TRUE;
2558 /* Clean any potential newsegment event kept for the streams. The first
2559 * stream needing a new segment will create a new one. */
2560 if (G_UNLIKELY (demux->new_seg_event)) {
2561 gst_event_unref (demux->new_seg_event);
2562 demux->new_seg_event = NULL;
2564 gst_event_unref (event);
2566 ret = gst_pad_push_event (demux->sinkpad, event);
2574 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2575 gst_event_unref (event);
2581 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2585 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2587 if (format != GST_FORMAT_TIME) {
2588 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2589 gst_event_unref (event);
2593 /* First try upstream */
2594 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2595 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2596 gst_event_unref (event);
2600 if (!demux->indexed) {
2601 guint64 seek_offset = 0;
2602 gboolean building_index;
2605 GST_OBJECT_LOCK (demux);
2606 /* handle the seek in the chain function */
2607 demux->seeking = TRUE;
2608 demux->state = FLV_STATE_SEEK;
2610 /* copy the event */
2611 if (demux->seek_event)
2612 gst_event_unref (demux->seek_event);
2613 demux->seek_event = gst_event_ref (event);
2615 /* set the building_index flag so that only one thread can setup the
2616 * structures for index seeking. */
2617 building_index = demux->building_index;
2618 if (!building_index) {
2619 demux->building_index = TRUE;
2620 fmt = GST_FORMAT_BYTES;
2621 if (!demux->file_size
2622 && !gst_pad_query_peer_duration (demux->sinkpad, &fmt,
2623 &demux->file_size)) {
2624 GST_WARNING_OBJECT (demux,
2625 "Cannot obtain file size - %" G_GINT64_FORMAT ", format %u",
2626 demux->file_size, fmt);
2627 GST_OBJECT_UNLOCK (demux);
2631 /* we hope the last tag is a scriptdataobject containing an index
2632 * the size of the last tag is given in the last guint32 bits
2633 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2634 seek_offset = demux->file_size - sizeof (guint32);
2635 GST_DEBUG_OBJECT (demux,
2636 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2638 GST_OBJECT_UNLOCK (demux);
2640 if (!building_index) {
2641 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2643 return flv_demux_seek_to_offset (demux, seek_offset);
2646 /* FIXME: we have to always return true so that we don't block the seek
2648 * Note: maybe it is OK to return true if we're still building the index */
2652 return flv_demux_handle_seek_push (demux, event);
2656 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2661 GstSeekType start_type, stop_type;
2664 gboolean update, flush, ret = FALSE;
2665 GstSegment seeksegment;
2667 gst_event_parse_seek (event, &rate, &format, &flags,
2668 &start_type, &start, &stop_type, &stop);
2670 if (format != GST_FORMAT_TIME)
2673 /* mark seeking thread entering flushing/pausing */
2674 GST_OBJECT_LOCK (demux);
2676 demux->seeking = seeking;
2677 GST_OBJECT_UNLOCK (demux);
2679 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2680 /* FIXME : the keyframe flag is never used */
2683 /* Flush start up and downstream to make sure data flow and loops are
2685 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2686 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2688 /* Pause the pulling task */
2689 gst_pad_pause_task (demux->sinkpad);
2692 /* Take the stream lock */
2693 GST_PAD_STREAM_LOCK (demux->sinkpad);
2696 /* Stop flushing upstream we need to pull */
2697 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
2700 /* Work on a copy until we are sure the seek succeeded. */
2701 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2703 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2706 /* Apply the seek to our segment */
2707 gst_segment_set_seek (&seeksegment, rate, format, flags,
2708 start_type, start, stop_type, stop, &update);
2710 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2713 if (flush || seeksegment.last_stop != demux->segment.last_stop) {
2714 /* Do the actual seeking */
2715 /* index is reliable if it is complete or we do not go to far ahead */
2716 if (seeking && !demux->indexed &&
2717 seeksegment.last_stop > demux->index_max_time + 10 * GST_SECOND) {
2718 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2719 " index only up to %" GST_TIME_FORMAT,
2720 GST_TIME_ARGS (demux->index_max_time));
2721 /* stop flushing for now */
2723 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop ());
2724 /* delegate scanning and index building to task thread to avoid
2725 * occupying main (UI) loop */
2726 if (demux->seek_event)
2727 gst_event_unref (demux->seek_event);
2728 demux->seek_event = gst_event_ref (event);
2729 demux->seek_time = seeksegment.last_stop;
2730 demux->state = FLV_STATE_SEEK;
2731 /* do not know about succes yet, but we did care and handled it */
2735 /* now index should be as reliable as it can be for current purpose */
2736 gst_flv_demux_move_to_offset (demux,
2737 gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2743 if (G_UNLIKELY (demux->close_seg_event)) {
2744 gst_event_unref (demux->close_seg_event);
2745 demux->close_seg_event = NULL;
2749 /* Stop flushing, the sinks are at time 0 now */
2750 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop ());
2752 GST_DEBUG_OBJECT (demux, "closing running segment %" GST_SEGMENT_FORMAT,
2755 /* Close the current segment for a linear playback */
2756 if (demux->segment.rate >= 0) {
2757 /* for forward playback, we played from start to last_stop */
2758 demux->close_seg_event = gst_event_new_new_segment (TRUE,
2759 demux->segment.rate, demux->segment.format,
2760 demux->segment.start, demux->segment.last_stop, demux->segment.time);
2764 if ((stop = demux->segment.stop) == -1)
2765 stop = demux->segment.duration;
2767 /* for reverse playback, we played from stop to last_stop. */
2768 demux->close_seg_event = gst_event_new_new_segment (TRUE,
2769 demux->segment.rate, demux->segment.format,
2770 demux->segment.last_stop, stop, demux->segment.last_stop);
2775 /* Ok seek succeeded, take the newly configured segment */
2776 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2778 /* Notify about the start of a new segment */
2779 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2780 gst_element_post_message (GST_ELEMENT (demux),
2781 gst_message_new_segment_start (GST_OBJECT (demux),
2782 demux->segment.format, demux->segment.last_stop));
2785 /* Tell all the stream a new segment is needed */
2786 demux->audio_need_segment = TRUE;
2787 demux->video_need_segment = TRUE;
2788 /* Clean any potential newsegment event kept for the streams. The first
2789 * stream needing a new segment will create a new one. */
2790 if (G_UNLIKELY (demux->new_seg_event)) {
2791 gst_event_unref (demux->new_seg_event);
2792 demux->new_seg_event = NULL;
2794 if (demux->segment.rate < 0.0) {
2795 /* we can't generate a segment by locking on
2796 * to the first timestamp we see */
2797 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2798 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2799 GST_TIME_ARGS (demux->segment.start),
2800 GST_TIME_ARGS (demux->segment.stop));
2801 demux->new_seg_event =
2802 gst_event_new_new_segment (FALSE, demux->segment.rate,
2803 demux->segment.format, demux->segment.start,
2804 demux->segment.stop, demux->segment.start);
2809 GST_OBJECT_LOCK (demux);
2810 seeking = demux->seeking && !seeking;
2811 demux->seeking = FALSE;
2812 GST_OBJECT_UNLOCK (demux);
2814 /* if we detect an external seek having started (and possibly already having
2815 * flushed), do not restart task to give it a chance.
2816 * Otherwise external one's flushing will take care to pause task */
2818 gst_pad_pause_task (demux->sinkpad);
2820 gst_pad_start_task (demux->sinkpad,
2821 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
2824 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2826 gst_event_unref (event);
2832 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2833 gst_event_unref (event);
2838 /* If we can pull that's prefered */
2840 gst_flv_demux_sink_activate (GstPad * sinkpad)
2842 if (gst_pad_check_pull_range (sinkpad)) {
2843 return gst_pad_activate_pull (sinkpad, TRUE);
2845 return gst_pad_activate_push (sinkpad, TRUE);
2849 /* This function gets called when we activate ourselves in push mode.
2850 * We cannot seek (ourselves) in the stream */
2852 gst_flv_demux_sink_activate_push (GstPad * sinkpad, gboolean active)
2856 demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
2858 demux->random_access = FALSE;
2860 gst_object_unref (demux);
2865 /* this function gets called when we activate ourselves in pull mode.
2866 * We can perform random access to the resource and we start a task
2867 * to start reading */
2869 gst_flv_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
2873 demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
2876 demux->random_access = TRUE;
2877 gst_object_unref (demux);
2878 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
2881 demux->random_access = FALSE;
2882 gst_object_unref (demux);
2883 return gst_pad_stop_task (sinkpad);
2888 gst_flv_demux_sink_event (GstPad * pad, GstEvent * event)
2891 gboolean ret = FALSE;
2893 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2895 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2897 switch (GST_EVENT_TYPE (event)) {
2898 case GST_EVENT_FLUSH_START:
2899 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
2900 demux->flushing = TRUE;
2901 ret = gst_flv_demux_push_src_event (demux, event);
2903 case GST_EVENT_FLUSH_STOP:
2904 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
2905 gst_flv_demux_flush (demux, TRUE);
2906 ret = gst_flv_demux_push_src_event (demux, event);
2912 GST_DEBUG_OBJECT (demux, "received EOS");
2914 index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2917 GST_DEBUG_OBJECT (demux, "committing index");
2918 gst_index_commit (index, demux->index_id);
2919 gst_object_unref (index);
2921 if (!demux->no_more_pads) {
2922 gst_element_no_more_pads (GST_ELEMENT (demux));
2923 demux->no_more_pads = TRUE;
2926 if (!gst_flv_demux_push_src_event (demux, event))
2927 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2931 case GST_EVENT_NEWSEGMENT:
2935 gint64 start, stop, time;
2938 GST_DEBUG_OBJECT (demux, "received new segment");
2940 gst_event_parse_new_segment (event, &update, &rate, &format, &start,
2943 if (format == GST_FORMAT_TIME) {
2944 /* time segment, this is perfect, copy over the values. */
2945 gst_segment_set_newsegment (&demux->segment, update, rate, format,
2948 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
2952 ret = gst_flv_demux_push_src_event (demux, event);
2954 /* non-time format */
2955 demux->audio_need_segment = TRUE;
2956 demux->video_need_segment = TRUE;
2958 gst_event_unref (event);
2963 ret = gst_flv_demux_push_src_event (demux, event);
2967 gst_object_unref (demux);
2973 gst_flv_demux_src_event (GstPad * pad, GstEvent * event)
2976 gboolean ret = FALSE;
2978 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2980 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2982 switch (GST_EVENT_TYPE (event)) {
2983 case GST_EVENT_SEEK:
2984 if (demux->random_access) {
2985 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
2987 ret = gst_flv_demux_handle_seek_push (demux, event);
2991 ret = gst_pad_push_event (demux->sinkpad, event);
2995 gst_object_unref (demux);
3001 gst_flv_demux_query (GstPad * pad, GstQuery * query)
3003 gboolean res = TRUE;
3006 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
3008 switch (GST_QUERY_TYPE (query)) {
3009 case GST_QUERY_DURATION:
3013 gst_query_parse_duration (query, &format, NULL);
3015 /* duration is time only */
3016 if (format != GST_FORMAT_TIME) {
3017 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
3023 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3024 GST_TIME_ARGS (demux->duration));
3026 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3030 case GST_QUERY_POSITION:
3034 gst_query_parse_position (query, &format, NULL);
3036 /* position is time only */
3037 if (format != GST_FORMAT_TIME) {
3038 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3044 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3045 GST_TIME_ARGS (demux->segment.last_stop));
3047 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.last_stop);
3052 case GST_QUERY_SEEKING:{
3055 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3057 /* First ask upstream */
3058 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3061 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3068 /* FIXME, check index this way is not thread safe */
3069 if (fmt != GST_FORMAT_TIME || !demux->index) {
3070 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3071 } else if (demux->random_access) {
3072 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3075 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3076 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3079 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3080 gst_query_unref (peerquery);
3083 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3086 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3090 case GST_QUERY_LATENCY:
3095 if ((peer = gst_pad_get_peer (demux->sinkpad))) {
3096 /* query latency on peer pad */
3097 res = gst_pad_query (peer, query);
3098 gst_object_unref (peer);
3100 /* no peer, we don't know */
3108 gst_object_unref (demux);
3113 static GstStateChangeReturn
3114 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3117 GstStateChangeReturn ret;
3119 demux = GST_FLV_DEMUX (element);
3121 switch (transition) {
3122 case GST_STATE_CHANGE_READY_TO_PAUSED:
3123 /* If this is our own index destroy it as the
3124 * old entries might be wrong for the new stream */
3125 if (demux->own_index) {
3126 gst_object_unref (demux->index);
3127 demux->index = NULL;
3128 demux->own_index = FALSE;
3131 /* If no index was created, generate one */
3132 if (G_UNLIKELY (!demux->index)) {
3133 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3135 demux->index = gst_index_factory_make ("memindex");
3137 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3139 demux->own_index = TRUE;
3141 gst_flv_demux_cleanup (demux);
3147 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3148 if (ret == GST_STATE_CHANGE_FAILURE)
3151 switch (transition) {
3152 case GST_STATE_CHANGE_PAUSED_TO_READY:
3153 gst_flv_demux_cleanup (demux);
3163 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3165 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3166 GstIndex *old_index;
3168 GST_OBJECT_LOCK (demux);
3170 old_index = demux->index;
3173 demux->index = gst_object_ref (index);
3174 demux->own_index = FALSE;
3176 demux->index = NULL;
3179 gst_object_unref (demux->index);
3181 gst_object_ref (index);
3183 GST_OBJECT_UNLOCK (demux);
3185 /* object lock might be taken again */
3187 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3189 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3191 gst_object_unref (index);
3195 gst_flv_demux_get_index (GstElement * element)
3197 GstIndex *result = NULL;
3199 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3201 GST_OBJECT_LOCK (demux);
3203 result = gst_object_ref (demux->index);
3204 GST_OBJECT_UNLOCK (demux);
3210 gst_flv_demux_dispose (GObject * object)
3212 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3214 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3216 if (demux->adapter) {
3217 gst_adapter_clear (demux->adapter);
3218 g_object_unref (demux->adapter);
3219 demux->adapter = NULL;
3222 if (demux->taglist) {
3223 gst_tag_list_free (demux->taglist);
3224 demux->taglist = NULL;
3227 if (demux->new_seg_event) {
3228 gst_event_unref (demux->new_seg_event);
3229 demux->new_seg_event = NULL;
3232 if (demux->close_seg_event) {
3233 gst_event_unref (demux->close_seg_event);
3234 demux->close_seg_event = NULL;
3237 if (demux->audio_codec_data) {
3238 gst_buffer_unref (demux->audio_codec_data);
3239 demux->audio_codec_data = NULL;
3242 if (demux->video_codec_data) {
3243 gst_buffer_unref (demux->video_codec_data);
3244 demux->video_codec_data = NULL;
3247 if (demux->audio_pad) {
3248 gst_object_unref (demux->audio_pad);
3249 demux->audio_pad = NULL;
3252 if (demux->video_pad) {
3253 gst_object_unref (demux->video_pad);
3254 demux->video_pad = NULL;
3258 gst_object_unref (demux->index);
3259 demux->index = NULL;
3263 g_array_free (demux->times, TRUE);
3264 demux->times = NULL;
3267 if (demux->filepositions) {
3268 g_array_free (demux->filepositions, TRUE);
3269 demux->filepositions = NULL;
3272 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3276 gst_flv_demux_base_init (gpointer g_class)
3278 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
3280 gst_element_class_add_static_pad_template (element_class, &flv_sink_template);
3281 gst_element_class_add_static_pad_template (element_class,
3282 &audio_src_template);
3283 gst_element_class_add_static_pad_template (element_class,
3284 &video_src_template);
3285 gst_element_class_set_details_simple (element_class, "FLV Demuxer",
3287 "Demux FLV feeds into digital streams",
3288 "Julien Moutte <julien@moutte.net>");
3292 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3294 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3295 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3297 gobject_class->dispose = gst_flv_demux_dispose;
3299 gstelement_class->change_state =
3300 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3301 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3302 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3306 gst_flv_demux_init (GstFlvDemux * demux, GstFlvDemuxClass * g_class)
3309 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3311 gst_pad_set_event_function (demux->sinkpad,
3312 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3313 gst_pad_set_chain_function (demux->sinkpad,
3314 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3315 gst_pad_set_activate_function (demux->sinkpad,
3316 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3317 gst_pad_set_activatepull_function (demux->sinkpad,
3318 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_pull));
3319 gst_pad_set_activatepush_function (demux->sinkpad,
3320 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_push));
3322 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3324 demux->adapter = gst_adapter_new ();
3325 demux->taglist = gst_tag_list_new ();
3326 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3328 demux->own_index = FALSE;
3330 gst_flv_demux_cleanup (demux);
3334 plugin_init (GstPlugin * plugin)
3336 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3338 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3339 gst_flv_demux_get_type ()) ||
3340 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3341 gst_flv_mux_get_type ()))
3347 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3348 "flv", "FLV muxing and demuxing plugin",
3349 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)