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);
104 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
105 guint64 pos, gboolean keyframe)
107 static GstIndexAssociation associations[2];
108 static GstIndexEntry *entry;
110 GST_LOG_OBJECT (demux,
111 "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
112 keyframe, GST_TIME_ARGS (ts), pos);
114 /* if upstream is not seekable there is no point in building an index */
115 if (!demux->upstream_seekable)
118 /* entry may already have been added before, avoid adding indefinitely */
119 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
120 GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
123 #ifndef GST_DISABLE_GST_DEBUG
127 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
128 key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
129 GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
130 ", keyframe %d", GST_TIME_ARGS (time), key);
131 /* there is not really a way to delete the existing one */
132 if (time != ts || key != ! !keyframe)
133 GST_DEBUG_OBJECT (demux, "metadata mismatch");
138 associations[0].format = GST_FORMAT_TIME;
139 associations[0].value = ts;
140 associations[1].format = GST_FORMAT_BYTES;
141 associations[1].value = pos;
143 gst_index_add_associationv (demux->index, demux->index_id,
144 (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
145 GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
146 (const GstIndexAssociation *) &associations);
148 if (pos > demux->index_max_pos)
149 demux->index_max_pos = pos;
150 if (ts > demux->index_max_time)
151 demux->index_max_time = ts;
155 FLV_GET_STRING (GstByteReader * reader)
157 guint16 string_size = 0;
158 gchar *string = NULL;
159 const guint8 *str = NULL;
161 g_return_val_if_fail (reader != NULL, NULL);
163 if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
166 if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
169 string = g_try_malloc0 (string_size + 1);
170 if (G_UNLIKELY (!string)) {
174 if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
179 memcpy (string, str, string_size);
180 if (!g_utf8_validate (string, string_size, NULL)) {
188 static const GstQueryType *
189 gst_flv_demux_query_types (GstPad * pad)
191 static const GstQueryType query_types[] = {
202 gst_flv_demux_check_seekability (GstFlvDemux * demux)
205 gint64 start = -1, stop = -1;
207 demux->upstream_seekable = FALSE;
209 query = gst_query_new_seeking (GST_FORMAT_BYTES);
210 if (!gst_pad_peer_query (demux->sinkpad, query)) {
211 GST_DEBUG_OBJECT (demux, "seeking query failed");
212 gst_query_unref (query);
216 gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
219 gst_query_unref (query);
221 /* try harder to query upstream size if we didn't get it the first time */
222 if (demux->upstream_seekable && stop == -1) {
223 GstFormat fmt = GST_FORMAT_BYTES;
225 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
226 gst_pad_query_peer_duration (demux->sinkpad, &fmt, &stop);
229 /* if upstream doesn't know the size, it's likely that it's not seekable in
230 * practice even if it technically may be seekable */
231 if (demux->upstream_seekable && (start != 0 || stop <= start)) {
232 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
233 demux->upstream_seekable = FALSE;
236 GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
240 parse_flv_demux_parse_date_string (GDate * date, const gchar * s)
242 g_date_set_parse (date, s);
243 if (g_date_valid (date))
246 /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
248 static const gchar *months[] = {
249 "Jan", "Feb", "Mar", "Apr",
250 "May", "Jun", "Jul", "Aug",
251 "Sep", "Oct", "Nov", "Dec"
253 gchar **tokens = g_strsplit (s, " ", -1);
258 if (g_strv_length (tokens) != 5)
261 if (strlen (tokens[1]) != 3)
263 for (i = 0; i < 12; i++) {
264 if (!strcmp (tokens[1], months[i])) {
270 g_date_set_month (date, i + 1);
272 d = g_ascii_strtoull (tokens[2], &endptr, 10);
273 if (d == 0 && *endptr != '\0')
276 g_date_set_day (date, d);
278 d = g_ascii_strtoull (tokens[4], &endptr, 10);
279 if (d == 0 && *endptr != '\0')
282 g_date_set_year (date, d);
291 gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
292 gboolean * end_marker)
294 gchar *tag_name = NULL;
297 /* Initialize the end_marker flag to FALSE */
300 /* Name of the tag */
301 tag_name = FLV_GET_STRING (reader);
302 if (G_UNLIKELY (!tag_name)) {
303 GST_WARNING_OBJECT (demux, "failed reading tag name");
307 /* What kind of object is that */
308 if (!gst_byte_reader_get_uint8 (reader, &tag_type))
311 GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
315 { /* Use a union to read the uint64 and then as a double */
318 if (!gst_byte_reader_get_float64_be (reader, &d))
321 GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
323 if (!strcmp (tag_name, "duration")) {
324 demux->duration = d * GST_SECOND;
326 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
327 GST_TAG_DURATION, demux->duration, NULL);
328 } else if (!strcmp (tag_name, "AspectRatioX")) {
330 demux->got_par = TRUE;
331 } else if (!strcmp (tag_name, "AspectRatioY")) {
333 demux->got_par = TRUE;
334 } else if (!strcmp (tag_name, "width")) {
336 } else if (!strcmp (tag_name, "height")) {
338 } else if (!strcmp (tag_name, "framerate")) {
339 demux->framerate = d;
341 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
350 if (!gst_byte_reader_get_uint8 (reader, &b))
353 GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
355 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
363 s = FLV_GET_STRING (reader);
367 GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
369 if (!strcmp (tag_name, "creationdate")) {
370 GDate *date = g_date_new ();
372 parse_flv_demux_parse_date_string (date, s);
373 if (!g_date_valid (date)) {
374 GST_DEBUG_OBJECT (demux, "Failed to parse string as date");
376 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
377 GST_TAG_DATE, date, NULL);
380 } else if (!strcmp (tag_name, "creator")) {
381 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
382 GST_TAG_ARTIST, s, NULL);
383 } else if (!strcmp (tag_name, "title")) {
384 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
385 GST_TAG_TITLE, s, NULL);
386 } else if (!strcmp (tag_name, "metadatacreator")) {
387 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
388 GST_TAG_ENCODER, s, NULL);
390 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
399 gboolean end_of_object_marker = FALSE;
401 while (!end_of_object_marker) {
402 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
403 &end_of_object_marker);
405 if (G_UNLIKELY (!ok)) {
406 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
413 case 8: // ECMA array
415 guint32 nb_elems = 0;
416 gboolean end_of_object_marker = FALSE;
418 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
421 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
424 while (!end_of_object_marker) {
425 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
426 &end_of_object_marker);
428 if (G_UNLIKELY (!ok)) {
429 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
436 case 9: // End marker
438 GST_DEBUG_OBJECT (demux, "end marker ?");
439 if (tag_name[0] == '\0') {
441 GST_DEBUG_OBJECT (demux, "end marker detected");
450 guint32 nb_elems = 0;
452 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
455 GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
457 if (!strcmp (tag_name, "times")) {
459 g_array_free (demux->times, TRUE);
461 demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
462 } else if (!strcmp (tag_name, "filepositions")) {
463 if (demux->filepositions) {
464 g_array_free (demux->filepositions, TRUE);
466 demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
470 guint8 elem_type = 0;
472 if (!gst_byte_reader_get_uint8 (reader, &elem_type))
480 if (!gst_byte_reader_get_float64_be (reader, &d))
483 GST_DEBUG_OBJECT (demux, "element is a double %f", d);
485 if (!strcmp (tag_name, "times") && demux->times) {
486 g_array_append_val (demux->times, d);
487 } else if (!strcmp (tag_name, "filepositions") &&
488 demux->filepositions) {
489 g_array_append_val (demux->filepositions, d);
494 GST_WARNING_OBJECT (demux, "unsupported array element type %d",
506 if (!gst_byte_reader_get_float64_be (reader, &d))
509 if (!gst_byte_reader_get_int16_be (reader, &i))
512 GST_DEBUG_OBJECT (demux,
513 "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
515 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
520 GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
534 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
536 GstFlowReturn ret = GST_FLOW_OK;
537 GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer);
540 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 7, GST_FLOW_ERROR);
542 gst_byte_reader_skip (&reader, 7);
544 GST_LOG_OBJECT (demux, "parsing a script tag");
546 if (!gst_byte_reader_get_uint8 (&reader, &type))
551 gchar *function_name;
554 function_name = FLV_GET_STRING (&reader);
556 GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
558 if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
559 gboolean end_marker = FALSE;
560 GST_DEBUG_OBJECT (demux, "we have a metadata script object");
562 if (!gst_byte_reader_get_uint8 (&reader, &type)) {
563 g_free (function_name);
570 guint32 nb_elems = 0;
573 if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
574 g_free (function_name);
578 /* The number of elements is just a hint, some files have
579 nb_elements == 0 and actually contain items. */
580 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
583 /* fallthrough to read data */
587 while (!end_marker) {
589 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
591 if (G_UNLIKELY (!ok)) {
592 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
599 GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
600 g_free (function_name);
604 demux->push_tags = TRUE;
607 g_free (function_name);
609 if (demux->index && demux->times && demux->filepositions) {
612 /* If an index was found, insert associations */
613 num = MIN (demux->times->len, demux->filepositions->len);
614 for (i = 0; i < num; i++) {
615 guint64 time, fileposition;
617 time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
618 fileposition = g_array_index (demux->filepositions, gdouble, i);
619 gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
622 demux->indexed = TRUE;
630 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
631 guint32 rate, guint32 channels, guint32 width)
633 GstCaps *caps = NULL;
634 gchar *codec_name = NULL;
635 gboolean ret = FALSE;
636 guint adjusted_rate = rate;
640 caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
645 caps = gst_caps_new_simple ("audio/mpeg",
646 "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
647 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
651 /* Assuming little endian for 0 (aka endianness of the
652 * system on which the file was created) as most people
653 * are probably using little endian machines */
654 caps = gst_caps_new_simple ("audio/x-raw-int",
655 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
656 "signed", G_TYPE_BOOLEAN, (width == 8) ? FALSE : TRUE,
657 "width", G_TYPE_INT, width, "depth", G_TYPE_INT, width, NULL);
662 caps = gst_caps_new_simple ("audio/x-nellymoser", NULL);
666 /* use codec-data to extract and verify samplerate */
667 if (demux->audio_codec_data &&
668 GST_BUFFER_SIZE (demux->audio_codec_data) >= 2) {
672 ((GST_READ_UINT16_BE (GST_BUFFER_DATA (demux->audio_codec_data))));
673 freq_index = (freq_index & 0x0780) >> 7;
675 gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
677 if (adjusted_rate && (rate != adjusted_rate)) {
678 GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
681 adjusted_rate = rate;
684 caps = gst_caps_new_simple ("audio/mpeg",
685 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
686 "stream-format", G_TYPE_STRING, "raw", NULL);
690 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
693 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
696 caps = gst_caps_new_simple ("audio/x-speex", NULL);
699 GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
702 if (G_UNLIKELY (!caps)) {
703 GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
707 gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
708 "channels", G_TYPE_INT, channels, NULL);
710 if (demux->audio_codec_data) {
711 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
712 demux->audio_codec_data, NULL);
715 ret = gst_pad_set_caps (demux->audio_pad, caps);
717 if (G_LIKELY (ret)) {
718 /* Store the caps we got from tags */
719 demux->audio_codec_tag = codec_tag;
721 demux->channels = channels;
722 demux->width = width;
724 codec_name = gst_pb_utils_get_codec_description (caps);
727 if (demux->taglist == NULL)
728 demux->taglist = gst_tag_list_new ();
729 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
730 GST_TAG_AUDIO_CODEC, codec_name, NULL);
734 GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
735 GST_PTR_FORMAT, caps);
737 GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
738 GST_PTR_FORMAT, caps);
741 gst_caps_unref (caps);
748 gst_flv_demux_push_tags (GstFlvDemux * demux)
750 if (demux->has_audio && !demux->audio_pad) {
751 GST_DEBUG_OBJECT (demux,
752 "Waiting for audio stream pad to come up before we can push tags");
755 if (demux->has_video && !demux->video_pad) {
756 GST_DEBUG_OBJECT (demux,
757 "Waiting for video stream pad to come up before we can push tags");
760 if (demux->taglist) {
761 GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
763 gst_element_found_tags (GST_ELEMENT (demux), demux->taglist);
764 demux->taglist = gst_tag_list_new ();
765 demux->push_tags = FALSE;
770 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, gboolean discont,
771 guint32 * last, GstClockTime * offset)
773 gint32 dpts = pts - *last;
774 if (!discont && ABS (dpts) >= RESYNC_THRESHOLD) {
775 /* Theoretically, we should use substract the duration of the last buffer,
776 but this demuxer sends no durations on buffers, not sure if it cannot
777 know, or just does not care to calculate. */
778 *offset -= dpts * GST_MSECOND;
779 GST_WARNING_OBJECT (demux,
780 "Large pts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
781 GST_TIME_FORMAT "", dpts, GST_TIME_ARGS (*offset));
787 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
789 GstFlowReturn ret = GST_FLOW_OK;
790 guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
791 guint32 codec_data = 0, pts_ext = 0;
793 guint8 *data = GST_BUFFER_DATA (buffer);
796 GST_LOG_OBJECT (demux, "parsing an audio tag");
798 if (demux->no_more_pads && !demux->audio_pad) {
799 GST_WARNING_OBJECT (demux,
800 "Signaled no-more-pads already but had no audio pad -- ignoring");
804 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) == demux->tag_size,
807 /* Grab information about audio tag */
808 pts = GST_READ_UINT24_BE (data);
809 /* read the pts extension to 32 bits integer */
810 pts_ext = GST_READ_UINT8 (data + 3);
812 pts |= pts_ext << 24;
814 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
815 data[2], data[3], pts);
817 /* Error out on tags with too small headers */
818 if (GST_BUFFER_SIZE (buffer) < 11) {
819 GST_ERROR_OBJECT (demux, "Too small tag size (%d)",
820 GST_BUFFER_SIZE (buffer));
821 return GST_FLOW_ERROR;
824 /* Silently skip buffers with no data */
825 if (GST_BUFFER_SIZE (buffer) == 11)
828 /* Skip the stream id and go directly to the flags */
829 flags = GST_READ_UINT8 (data + 7);
840 if ((flags & 0x0C) == 0x0C) {
842 } else if ((flags & 0x0C) == 0x08) {
844 } else if ((flags & 0x0C) == 0x04) {
848 codec_tag = flags >> 4;
849 if (codec_tag == 10) { /* AAC has an extra byte for packet type */
855 /* codec tags with special rates */
856 if (codec_tag == 5 || codec_tag == 14)
858 else if (codec_tag == 4)
861 GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
862 "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
865 /* If we don't have our audio pad created, then create it. */
866 if (G_UNLIKELY (!demux->audio_pad)) {
869 gst_pad_new_from_template (gst_element_class_get_pad_template
870 (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
871 if (G_UNLIKELY (!demux->audio_pad)) {
872 GST_WARNING_OBJECT (demux, "failed creating audio pad");
873 ret = GST_FLOW_ERROR;
878 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
880 gst_object_unref (demux->audio_pad);
881 demux->audio_pad = NULL;
882 ret = GST_FLOW_ERROR;
886 GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
887 GST_PAD_CAPS (demux->audio_pad));
889 /* Set functions on the pad */
890 gst_pad_set_query_type_function (demux->audio_pad,
891 GST_DEBUG_FUNCPTR (gst_flv_demux_query_types));
892 gst_pad_set_query_function (demux->audio_pad,
893 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
894 gst_pad_set_event_function (demux->audio_pad,
895 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
897 gst_pad_use_fixed_caps (demux->audio_pad);
900 gst_pad_set_active (demux->audio_pad, TRUE);
902 /* We need to set caps before adding */
903 gst_element_add_pad (GST_ELEMENT (demux),
904 gst_object_ref (demux->audio_pad));
906 /* We only emit no more pads when we have audio and video. Indeed we can
907 * not trust the FLV header to tell us if there will be only audio or
908 * only video and we would just break discovery of some files */
909 if (demux->audio_pad && demux->video_pad) {
910 GST_DEBUG_OBJECT (demux, "emitting no more pads");
911 gst_element_no_more_pads (GST_ELEMENT (demux));
912 demux->no_more_pads = TRUE;
913 demux->push_tags = TRUE;
917 /* Check if caps have changed */
918 if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
919 codec_tag != demux->audio_codec_tag || width != demux->width)) {
920 GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
923 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
925 ret = GST_FLOW_ERROR;
930 /* Push taglist if present */
931 if (G_UNLIKELY (demux->push_tags))
932 gst_flv_demux_push_tags (demux);
934 /* Check if we have anything to push */
935 if (demux->tag_data_size <= codec_data) {
936 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
940 /* Create buffer from pad */
942 gst_buffer_create_sub (buffer, 7 + codec_data,
943 demux->tag_data_size - codec_data);
945 if (demux->audio_codec_tag == 10) {
946 guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
948 switch (aac_packet_type) {
951 /* AudioSpecificConfig data */
952 GST_LOG_OBJECT (demux, "got an AAC codec data packet");
953 if (demux->audio_codec_data) {
954 gst_buffer_unref (demux->audio_codec_data);
956 demux->audio_codec_data = outbuf;
957 /* Use that buffer data in the caps */
958 gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels, width);
964 GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
967 GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
972 /* detect (and deem to be resyncs) large pts gaps */
973 gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
974 &demux->last_audio_pts, &demux->audio_time_offset);
976 /* Fill buffer with data */
977 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
978 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
979 GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
980 GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
981 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (demux->audio_pad));
983 if (demux->duration == GST_CLOCK_TIME_NONE ||
984 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
985 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
987 /* Only add audio frames to the index if we have no video,
988 * and if the index is not yet complete */
989 if (!demux->has_video && demux->index && !demux->indexed) {
990 gst_flv_demux_parse_and_add_index_entry (demux,
991 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
994 if (G_UNLIKELY (demux->audio_need_discont)) {
995 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
996 demux->audio_need_discont = FALSE;
999 gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME,
1000 GST_BUFFER_TIMESTAMP (outbuf));
1002 /* Do we need a newsegment event ? */
1003 if (G_UNLIKELY (demux->audio_need_segment)) {
1004 if (demux->close_seg_event)
1005 gst_pad_push_event (demux->audio_pad,
1006 gst_event_ref (demux->close_seg_event));
1008 if (!demux->new_seg_event) {
1009 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1010 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1011 GST_TIME_ARGS (demux->segment.last_stop),
1012 GST_TIME_ARGS (demux->segment.stop));
1013 demux->new_seg_event =
1014 gst_event_new_new_segment (FALSE, demux->segment.rate,
1015 demux->segment.format, demux->segment.last_stop,
1016 demux->segment.stop, demux->segment.last_stop);
1018 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1021 gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1023 demux->audio_need_segment = FALSE;
1026 GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
1027 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1028 GST_BUFFER_SIZE (outbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1029 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1031 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1032 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1034 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1035 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1038 if (G_UNLIKELY (!demux->no_more_pads
1039 && (GST_CLOCK_DIFF (demux->audio_start,
1040 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1041 GST_DEBUG_OBJECT (demux,
1042 "Signalling no-more-pads because no video stream was found"
1043 " after 6 seconds of audio");
1044 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1045 demux->no_more_pads = TRUE;
1046 demux->push_tags = TRUE;
1049 /* Push downstream */
1050 ret = gst_pad_push (demux->audio_pad, outbuf);
1051 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1052 if (demux->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
1053 demux->segment.last_stop > demux->segment.stop) {
1054 /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
1055 * we are at the end of the segment, so we just need to jump
1056 * back to the previous section. */
1057 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1058 demux->audio_done = TRUE;
1061 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1062 " bytes audio buffer: %s", demux->tag_data_size,
1063 gst_flow_get_name (ret));
1064 if (ret == GST_FLOW_NOT_LINKED) {
1065 demux->audio_linked = FALSE;
1071 demux->audio_linked = TRUE;
1078 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1080 gboolean ret = FALSE;
1081 GstCaps *caps = NULL;
1082 gchar *codec_name = NULL;
1084 /* Generate caps for that pad */
1085 switch (codec_tag) {
1087 caps = gst_caps_new_simple ("video/x-flash-video", NULL);
1090 caps = gst_caps_new_simple ("video/x-flash-screen", NULL);
1093 caps = gst_caps_new_simple ("video/x-vp6-flash", NULL);
1096 caps = gst_caps_new_simple ("video/x-vp6-alpha", NULL);
1100 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1104 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1107 if (G_UNLIKELY (!caps)) {
1108 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1112 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1113 demux->par_x, demux->par_y, NULL);
1115 if (G_LIKELY (demux->w)) {
1116 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1119 if (G_LIKELY (demux->h)) {
1120 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1123 if (G_LIKELY (demux->framerate)) {
1124 gint num = 0, den = 0;
1126 gst_util_double_to_fraction (demux->framerate, &num, &den);
1127 GST_DEBUG_OBJECT (demux->video_pad,
1128 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1131 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1134 if (demux->video_codec_data) {
1135 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1136 demux->video_codec_data, NULL);
1139 ret = gst_pad_set_caps (demux->video_pad, caps);
1141 if (G_LIKELY (ret)) {
1142 /* Store the caps we have set */
1143 demux->video_codec_tag = codec_tag;
1145 codec_name = gst_pb_utils_get_codec_description (caps);
1148 if (demux->taglist == NULL)
1149 demux->taglist = gst_tag_list_new ();
1150 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1151 GST_TAG_VIDEO_CODEC, codec_name, NULL);
1152 g_free (codec_name);
1155 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1156 GST_PTR_FORMAT, caps);
1158 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1159 GST_PTR_FORMAT, caps);
1162 gst_caps_unref (caps);
1168 static GstFlowReturn
1169 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1171 GstFlowReturn ret = GST_FLOW_OK;
1172 guint32 pts = 0, codec_data = 1, pts_ext = 0;
1173 gboolean keyframe = FALSE;
1174 guint8 flags = 0, codec_tag = 0;
1175 guint8 *data = GST_BUFFER_DATA (buffer);
1178 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) == demux->tag_size,
1181 GST_LOG_OBJECT (demux, "parsing a video tag");
1184 if (demux->no_more_pads && !demux->video_pad) {
1185 GST_WARNING_OBJECT (demux,
1186 "Signaled no-more-pads already but had no audio pad -- ignoring");
1190 /* Grab information about video tag */
1191 pts = GST_READ_UINT24_BE (data);
1192 /* read the pts extension to 32 bits integer */
1193 pts_ext = GST_READ_UINT8 (data + 3);
1195 pts |= pts_ext << 24;
1197 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1198 data[2], data[3], pts);
1200 if (GST_BUFFER_SIZE (buffer) < 12) {
1201 GST_ERROR_OBJECT (demux, "Too small tag size");
1202 return GST_FLOW_ERROR;
1205 /* Skip the stream id and go directly to the flags */
1206 flags = GST_READ_UINT8 (data + 7);
1209 if ((flags >> 4) == 1) {
1213 codec_tag = flags & 0x0F;
1214 if (codec_tag == 4 || codec_tag == 5) {
1216 } else if (codec_tag == 7) {
1221 cts = GST_READ_UINT24_BE (data + 9);
1222 cts = (cts + 0xff800000) ^ 0xff800000;
1224 GST_LOG_OBJECT (demux, "got cts %d", cts);
1226 /* avoid negative overflow */
1227 if (cts >= 0 || pts >= -cts)
1231 GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1232 "(flags %02X)", codec_tag, keyframe, flags);
1234 /* If we don't have our video pad created, then create it. */
1235 if (G_UNLIKELY (!demux->video_pad)) {
1237 gst_pad_new_from_template (gst_element_class_get_pad_template
1238 (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1239 if (G_UNLIKELY (!demux->video_pad)) {
1240 GST_WARNING_OBJECT (demux, "failed creating video pad");
1241 ret = GST_FLOW_ERROR;
1245 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1246 gst_object_unref (demux->video_pad);
1247 demux->video_pad = NULL;
1248 ret = GST_FLOW_ERROR;
1252 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1253 * metadata tag that would come later and trigger a caps change */
1254 demux->got_par = FALSE;
1256 GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1257 GST_PAD_CAPS (demux->video_pad));
1259 /* Set functions on the pad */
1260 gst_pad_set_query_type_function (demux->video_pad,
1261 GST_DEBUG_FUNCPTR (gst_flv_demux_query_types));
1262 gst_pad_set_query_function (demux->video_pad,
1263 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1264 gst_pad_set_event_function (demux->video_pad,
1265 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1267 gst_pad_use_fixed_caps (demux->video_pad);
1269 /* Make it active */
1270 gst_pad_set_active (demux->video_pad, TRUE);
1272 /* We need to set caps before adding */
1273 gst_element_add_pad (GST_ELEMENT (demux),
1274 gst_object_ref (demux->video_pad));
1276 /* We only emit no more pads when we have audio and video. Indeed we can
1277 * not trust the FLV header to tell us if there will be only audio or
1278 * only video and we would just break discovery of some files */
1279 if (demux->audio_pad && demux->video_pad) {
1280 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1281 gst_element_no_more_pads (GST_ELEMENT (demux));
1282 demux->no_more_pads = TRUE;
1283 demux->push_tags = TRUE;
1287 /* Check if caps have changed */
1288 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1290 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1292 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1293 ret = GST_FLOW_ERROR;
1297 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1298 * metadata tag that would come later and trigger a caps change */
1299 demux->got_par = FALSE;
1302 /* Push taglist if present */
1303 if (G_UNLIKELY (demux->push_tags))
1304 gst_flv_demux_push_tags (demux);
1306 /* Check if we have anything to push */
1307 if (demux->tag_data_size <= codec_data) {
1308 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1312 /* Create buffer from pad */
1314 gst_buffer_create_sub (buffer, 7 + codec_data,
1315 demux->tag_data_size - codec_data);
1317 if (demux->video_codec_tag == 7) {
1318 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1320 switch (avc_packet_type) {
1323 /* AVCDecoderConfigurationRecord data */
1324 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1325 if (demux->video_codec_data) {
1326 gst_buffer_unref (demux->video_codec_data);
1328 demux->video_codec_data = outbuf;
1329 /* Use that buffer data in the caps */
1330 gst_flv_demux_video_negotiate (demux, codec_tag);
1335 /* H.264 NALU packet */
1336 GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1339 GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1344 /* detect (and deem to be resyncs) large pts gaps */
1345 gst_flv_demux_update_resync (demux, pts, demux->video_need_discont,
1346 &demux->last_video_pts, &demux->video_time_offset);
1348 /* Fill buffer with data */
1349 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
1350 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1351 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1352 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1353 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (demux->video_pad));
1355 if (demux->duration == GST_CLOCK_TIME_NONE ||
1356 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1357 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1360 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1362 if (!demux->indexed && demux->index) {
1363 gst_flv_demux_parse_and_add_index_entry (demux,
1364 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1367 if (G_UNLIKELY (demux->video_need_discont)) {
1368 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1369 demux->video_need_discont = FALSE;
1372 gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME,
1373 GST_BUFFER_TIMESTAMP (outbuf));
1375 /* Do we need a newsegment event ? */
1376 if (G_UNLIKELY (demux->video_need_segment)) {
1377 if (demux->close_seg_event)
1378 gst_pad_push_event (demux->video_pad,
1379 gst_event_ref (demux->close_seg_event));
1381 if (!demux->new_seg_event) {
1382 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1383 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1384 GST_TIME_ARGS (demux->segment.last_stop),
1385 GST_TIME_ARGS (demux->segment.stop));
1386 demux->new_seg_event =
1387 gst_event_new_new_segment (FALSE, demux->segment.rate,
1388 demux->segment.format, demux->segment.last_stop,
1389 demux->segment.stop, demux->segment.last_stop);
1391 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1394 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1396 demux->video_need_segment = FALSE;
1399 GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
1400 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1401 ", keyframe (%d)", GST_BUFFER_SIZE (outbuf),
1402 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1403 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1406 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1407 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1409 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1410 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1413 if (G_UNLIKELY (!demux->no_more_pads
1414 && (GST_CLOCK_DIFF (demux->video_start,
1415 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1416 GST_DEBUG_OBJECT (demux,
1417 "Signalling no-more-pads because no audio stream was found"
1418 " after 6 seconds of video");
1419 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1420 demux->no_more_pads = TRUE;
1421 demux->push_tags = TRUE;
1424 /* Push downstream */
1425 ret = gst_pad_push (demux->video_pad, outbuf);
1427 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1428 if (demux->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
1429 demux->segment.last_stop > demux->segment.stop) {
1430 /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
1431 * we are at the end of the segment, so we just need to jump
1432 * back to the previous section. */
1433 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1434 demux->video_done = TRUE;
1437 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1438 " bytes video buffer: %s", demux->tag_data_size,
1439 gst_flow_get_name (ret));
1440 if (ret == GST_FLOW_NOT_LINKED) {
1441 demux->video_linked = FALSE;
1447 demux->video_linked = TRUE;
1454 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1455 GstBuffer * buffer, size_t * tag_size)
1457 guint32 pts = 0, pts_ext = 0;
1458 guint32 tag_data_size;
1460 gboolean keyframe = TRUE;
1462 guint8 *data = GST_BUFFER_DATA (buffer);
1464 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 12, GST_CLOCK_TIME_NONE);
1468 if (type != 9 && type != 8 && type != 18) {
1469 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1470 return GST_CLOCK_TIME_NONE;
1474 demux->has_video = TRUE;
1476 demux->has_audio = TRUE;
1478 tag_data_size = GST_READ_UINT24_BE (data + 1);
1480 if (GST_BUFFER_SIZE (buffer) >= tag_data_size + 11 + 4) {
1481 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1482 GST_WARNING_OBJECT (demux, "Invalid tag size");
1483 return GST_CLOCK_TIME_NONE;
1488 *tag_size = tag_data_size + 11 + 4;
1492 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
1495 /* Grab timestamp of tag tag */
1496 pts = GST_READ_UINT24_BE (data);
1497 /* read the pts extension to 32 bits integer */
1498 pts_ext = GST_READ_UINT8 (data + 3);
1500 pts |= pts_ext << 24;
1505 keyframe = ((data[0] >> 4) == 1);
1508 ret = pts * GST_MSECOND;
1509 GST_LOG_OBJECT (demux, "pts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1511 if (index && demux->index && !demux->indexed && (type == 9 || (type == 8
1512 && !demux->has_video))) {
1513 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1517 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1518 demux->duration = ret;
1523 static GstFlowReturn
1524 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1526 GstFlowReturn ret = GST_FLOW_OK;
1527 guint8 tag_type = 0;
1528 guint8 *data = GST_BUFFER_DATA (buffer);
1530 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 4, GST_FLOW_ERROR);
1536 demux->state = FLV_STATE_TAG_VIDEO;
1537 demux->has_video = TRUE;
1540 demux->state = FLV_STATE_TAG_AUDIO;
1541 demux->has_audio = TRUE;
1544 demux->state = FLV_STATE_TAG_SCRIPT;
1547 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1550 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1551 * 4 bytes of previous tag size */
1552 demux->tag_data_size = GST_READ_UINT24_BE (data + 1);
1553 demux->tag_size = demux->tag_data_size + 11;
1555 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1556 demux->tag_data_size);
1561 static GstFlowReturn
1562 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1564 GstFlowReturn ret = GST_FLOW_OK;
1565 guint8 *data = GST_BUFFER_DATA (buffer);
1567 g_return_val_if_fail (GST_BUFFER_SIZE (buffer) >= 9, GST_FLOW_ERROR);
1569 /* Check for the FLV tag */
1570 if (data[0] == 'F' && data[1] == 'L' && data[2] == 'V') {
1571 GST_DEBUG_OBJECT (demux, "FLV header detected");
1573 if (G_UNLIKELY (demux->strict)) {
1574 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1575 ret = GST_FLOW_UNEXPECTED;
1580 /* Jump over the 4 first bytes */
1583 /* Now look at audio/video flags */
1585 guint8 flags = data[0];
1587 demux->has_video = demux->has_audio = FALSE;
1590 GST_DEBUG_OBJECT (demux, "there is a video stream");
1591 demux->has_video = TRUE;
1594 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1595 demux->has_audio = TRUE;
1599 /* do a one-time seekability check */
1600 gst_flv_demux_check_seekability (demux);
1602 /* We don't care about the rest */
1603 demux->need_header = FALSE;
1611 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1613 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1615 gst_adapter_clear (demux->adapter);
1617 demux->audio_need_discont = TRUE;
1618 demux->video_need_discont = TRUE;
1620 demux->flushing = FALSE;
1622 /* Only in push mode and if we're not during a seek */
1623 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1624 /* After a flush we expect a tag_type */
1625 demux->state = FLV_STATE_TAG_TYPE;
1626 /* We reset the offset and will get one from first push */
1632 gst_flv_demux_cleanup (GstFlvDemux * demux)
1634 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1636 demux->state = FLV_STATE_HEADER;
1638 demux->flushing = FALSE;
1639 demux->need_header = TRUE;
1640 demux->audio_need_segment = TRUE;
1641 demux->video_need_segment = TRUE;
1642 demux->audio_need_discont = TRUE;
1643 demux->video_need_discont = TRUE;
1645 /* By default we consider them as linked */
1646 demux->audio_linked = TRUE;
1647 demux->video_linked = TRUE;
1649 demux->has_audio = FALSE;
1650 demux->has_video = FALSE;
1651 demux->push_tags = FALSE;
1652 demux->got_par = FALSE;
1654 demux->indexed = FALSE;
1655 demux->upstream_seekable = FALSE;
1656 demux->file_size = 0;
1658 demux->index_max_pos = 0;
1659 demux->index_max_time = 0;
1661 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1662 demux->last_audio_pts = demux->last_video_pts = 0;
1663 demux->audio_time_offset = demux->video_time_offset = 0;
1665 demux->no_more_pads = FALSE;
1667 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1669 demux->w = demux->h = 0;
1670 demux->framerate = 0.0;
1671 demux->par_x = demux->par_y = 1;
1672 demux->video_offset = 0;
1673 demux->audio_offset = 0;
1674 demux->offset = demux->cur_tag_offset = 0;
1675 demux->tag_size = demux->tag_data_size = 0;
1676 demux->duration = GST_CLOCK_TIME_NONE;
1678 if (demux->new_seg_event) {
1679 gst_event_unref (demux->new_seg_event);
1680 demux->new_seg_event = NULL;
1683 if (demux->close_seg_event) {
1684 gst_event_unref (demux->close_seg_event);
1685 demux->close_seg_event = NULL;
1688 gst_adapter_clear (demux->adapter);
1690 if (demux->audio_codec_data) {
1691 gst_buffer_unref (demux->audio_codec_data);
1692 demux->audio_codec_data = NULL;
1695 if (demux->video_codec_data) {
1696 gst_buffer_unref (demux->video_codec_data);
1697 demux->video_codec_data = NULL;
1700 if (demux->audio_pad) {
1701 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1702 gst_object_unref (demux->audio_pad);
1703 demux->audio_pad = NULL;
1706 if (demux->video_pad) {
1707 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1708 gst_object_unref (demux->video_pad);
1709 demux->video_pad = NULL;
1713 g_array_free (demux->times, TRUE);
1714 demux->times = NULL;
1717 if (demux->filepositions) {
1718 g_array_free (demux->filepositions, TRUE);
1719 demux->filepositions = NULL;
1724 * Create and push a flushing seek event upstream
1727 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1732 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1735 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1736 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1737 GST_SEEK_TYPE_NONE, -1);
1739 res = gst_pad_push_event (demux->sinkpad, event);
1742 demux->offset = offset;
1746 static GstFlowReturn
1747 gst_flv_demux_chain (GstPad * pad, GstBuffer * buffer)
1749 GstFlowReturn ret = GST_FLOW_OK;
1750 GstFlvDemux *demux = NULL;
1752 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
1754 GST_LOG_OBJECT (demux, "received buffer of %d bytes at offset %"
1755 G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer));
1757 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1758 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1759 demux->state = FLV_STATE_HEADER;
1763 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
1764 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
1765 demux->offset = GST_BUFFER_OFFSET (buffer);
1768 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1769 GST_DEBUG_OBJECT (demux, "Discontinuity");
1770 gst_adapter_clear (demux->adapter);
1773 gst_adapter_push (demux->adapter, buffer);
1775 if (demux->seeking) {
1776 demux->state = FLV_STATE_SEEK;
1777 GST_OBJECT_LOCK (demux);
1778 demux->seeking = FALSE;
1779 GST_OBJECT_UNLOCK (demux);
1783 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1784 if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
1785 || demux->video_linked)) {
1788 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
1793 if (G_UNLIKELY (demux->flushing)) {
1794 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
1795 ret = GST_FLOW_WRONG_STATE;
1799 switch (demux->state) {
1800 case FLV_STATE_HEADER:
1802 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
1805 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
1807 ret = gst_flv_demux_parse_header (demux, buffer);
1809 gst_buffer_unref (buffer);
1810 demux->offset += FLV_HEADER_SIZE;
1812 demux->state = FLV_STATE_TAG_TYPE;
1818 case FLV_STATE_TAG_TYPE:
1820 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
1823 /* Remember the tag offset in bytes */
1824 demux->cur_tag_offset = demux->offset;
1826 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
1828 ret = gst_flv_demux_parse_tag_type (demux, buffer);
1830 gst_buffer_unref (buffer);
1831 demux->offset += FLV_TAG_TYPE_SIZE;
1833 /* last tag is not an index => no index/don't know where the index is
1834 * seek back to the beginning */
1835 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
1843 case FLV_STATE_TAG_VIDEO:
1845 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1848 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1850 ret = gst_flv_demux_parse_tag_video (demux, buffer);
1852 gst_buffer_unref (buffer);
1853 demux->offset += demux->tag_size;
1855 demux->state = FLV_STATE_TAG_TYPE;
1861 case FLV_STATE_TAG_AUDIO:
1863 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1866 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1868 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
1870 gst_buffer_unref (buffer);
1871 demux->offset += demux->tag_size;
1873 demux->state = FLV_STATE_TAG_TYPE;
1879 case FLV_STATE_TAG_SCRIPT:
1881 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1884 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1886 ret = gst_flv_demux_parse_tag_script (demux, buffer);
1888 gst_buffer_unref (buffer);
1889 demux->offset += demux->tag_size;
1891 demux->state = FLV_STATE_TAG_TYPE;
1893 /* if there's a seek event we're here for the index so if we don't have it
1894 * we seek back to the beginning */
1895 if (demux->seek_event) {
1897 demux->state = FLV_STATE_SEEK;
1907 case FLV_STATE_SEEK:
1913 if (!demux->indexed) {
1914 if (demux->offset == demux->file_size - sizeof (guint32)) {
1916 gst_adapter_take_buffer (demux->adapter, sizeof (guint32));
1917 GstByteReader *reader = gst_byte_reader_new_from_buffer (buffer);
1918 guint64 seek_offset;
1920 if (!gst_adapter_available (demux->adapter) >= sizeof (guint32)) {
1925 demux->file_size - sizeof (guint32) -
1926 gst_byte_reader_peek_uint32_be_unchecked (reader);
1927 gst_byte_reader_free (reader);
1928 gst_buffer_unref (buffer);
1930 GST_INFO_OBJECT (demux,
1931 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
1933 demux->state = FLV_STATE_TAG_TYPE;
1934 flv_demux_seek_to_offset (demux, seek_offset);
1940 GST_OBJECT_LOCK (demux);
1941 event = demux->seek_event;
1942 demux->seek_event = NULL;
1943 GST_OBJECT_UNLOCK (demux);
1945 /* calculate and perform seek */
1946 if (!flv_demux_handle_seek_push (demux, event))
1949 gst_event_unref (event);
1950 demux->state = FLV_STATE_TAG_TYPE;
1954 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
1958 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
1959 /* If either audio or video is linked we return GST_FLOW_OK */
1960 if (demux->audio_linked || demux->video_linked) {
1965 gst_object_unref (demux);
1972 GST_OBJECT_LOCK (demux);
1973 demux->seeking = FALSE;
1974 gst_event_unref (demux->seek_event);
1975 demux->seek_event = NULL;
1976 GST_OBJECT_UNLOCK (demux);
1977 GST_WARNING_OBJECT (demux,
1978 "failed to find an index, seeking back to beginning");
1979 flv_demux_seek_to_offset (demux, 0);
1984 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
1985 return GST_FLOW_ERROR;
1990 static GstFlowReturn
1991 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
1992 guint size, GstBuffer ** buffer)
1996 ret = gst_pad_pull_range (pad, offset, size, buffer);
1997 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1998 GST_WARNING_OBJECT (demux,
1999 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2000 size, offset, gst_flow_get_name (ret));
2005 if (G_UNLIKELY (*buffer && GST_BUFFER_SIZE (*buffer) != size)) {
2006 GST_WARNING_OBJECT (demux,
2007 "partial pull got %d when expecting %d from offset %" G_GUINT64_FORMAT,
2008 GST_BUFFER_SIZE (*buffer), size, offset);
2009 gst_buffer_unref (*buffer);
2010 ret = GST_FLOW_UNEXPECTED;
2018 static GstFlowReturn
2019 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2021 GstBuffer *buffer = NULL;
2022 GstFlowReturn ret = GST_FLOW_OK;
2024 /* Store tag offset */
2025 demux->cur_tag_offset = demux->offset;
2027 /* Get the first 4 bytes to identify tag type and size */
2028 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2029 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2032 /* Identify tag type */
2033 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2035 gst_buffer_unref (buffer);
2037 if (G_UNLIKELY (ret != GST_FLOW_OK))
2040 /* Jump over tag type + size */
2041 demux->offset += FLV_TAG_TYPE_SIZE;
2043 /* Pull the whole tag */
2044 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2045 demux->tag_size, &buffer)) != GST_FLOW_OK))
2048 switch (demux->state) {
2049 case FLV_STATE_TAG_VIDEO:
2050 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2052 case FLV_STATE_TAG_AUDIO:
2053 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2055 case FLV_STATE_TAG_SCRIPT:
2056 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2059 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2062 gst_buffer_unref (buffer);
2064 /* Jump over that part we've just parsed */
2065 demux->offset += demux->tag_size;
2067 /* Make sure we reinitialize the tag size */
2068 demux->tag_size = 0;
2070 /* Ready for the next tag */
2071 demux->state = FLV_STATE_TAG_TYPE;
2073 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2074 /* If either audio or video is linked we return GST_FLOW_OK */
2075 if (demux->audio_linked || demux->video_linked) {
2078 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2079 "neither video nor audio are linked");
2087 static GstFlowReturn
2088 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2090 GstBuffer *buffer = NULL;
2091 GstFlowReturn ret = GST_FLOW_OK;
2093 /* Get the first 9 bytes */
2094 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2095 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2098 ret = gst_flv_demux_parse_header (demux, buffer);
2100 gst_buffer_unref (buffer);
2102 /* Jump over the header now */
2103 demux->offset += FLV_HEADER_SIZE;
2104 demux->state = FLV_STATE_TAG_TYPE;
2111 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2114 demux->offset = offset;
2116 /* Tell all the stream we moved to a different position (discont) */
2117 demux->audio_need_discont = TRUE;
2118 demux->video_need_discont = TRUE;
2120 /* next section setup */
2121 demux->from_offset = -1;
2122 demux->audio_done = demux->video_done = FALSE;
2123 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2126 demux->from_offset = -1;
2127 demux->to_offset = G_MAXINT64;
2130 /* If we seeked at the beginning of the file parse the header again */
2131 if (G_UNLIKELY (!demux->offset)) {
2132 demux->state = FLV_STATE_HEADER;
2133 } else { /* or parse a tag */
2134 demux->state = FLV_STATE_TAG_TYPE;
2138 static GstFlowReturn
2139 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2141 GstFlowReturn ret = GST_FLOW_UNEXPECTED;
2142 GstIndexEntry *entry = NULL;
2144 GST_DEBUG_OBJECT (demux,
2145 "terminated section started at offset %" G_GINT64_FORMAT,
2146 demux->from_offset);
2148 /* we are done if we got all audio and video */
2149 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2150 demux->audio_first_ts < demux->segment.start) &&
2151 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2152 demux->video_first_ts < demux->segment.start))
2155 if (demux->from_offset <= 0)
2158 GST_DEBUG_OBJECT (demux, "locating previous position");
2160 /* locate index entry before previous start position */
2162 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2163 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2164 GST_FORMAT_BYTES, demux->from_offset - 1);
2169 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2170 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2172 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2173 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2174 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2176 /* setup for next section */
2177 demux->to_offset = demux->from_offset;
2178 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2187 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
2189 gboolean ret = TRUE;
2191 if (demux->audio_pad)
2192 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
2194 if (demux->video_pad)
2195 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
2197 gst_event_unref (event);
2202 static GstFlowReturn
2203 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2206 GstFormat fmt = GST_FORMAT_BYTES;
2210 GstClockTime tag_time;
2211 GstFlowReturn ret = GST_FLOW_OK;
2213 if (G_UNLIKELY (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &size) ||
2214 fmt != GST_FORMAT_BYTES))
2217 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2218 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2220 old_offset = demux->offset;
2221 demux->offset = pos;
2223 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2224 12, &buffer)) == GST_FLOW_OK) {
2226 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2228 gst_buffer_unref (buffer);
2230 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2233 demux->offset += tag_size;
2236 if (ret == GST_FLOW_UNEXPECTED) {
2237 /* file ran out, so mark we have complete index */
2238 demux->indexed = TRUE;
2243 demux->offset = old_offset;
2249 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2251 gint64 ret = 0, offset;
2252 GstFormat fmt = GST_FORMAT_BYTES;
2253 size_t tag_size, size;
2254 GstBuffer *buffer = NULL;
2256 if (G_UNLIKELY (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &offset)
2257 || fmt != GST_FORMAT_BYTES))
2261 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2262 if (G_UNLIKELY (offset < 4))
2266 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2270 tag_size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buffer));
2271 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2272 gst_buffer_unref (buffer);
2276 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2280 /* a consistency check */
2281 size = GST_READ_UINT24_BE (GST_BUFFER_DATA (buffer) + 1);
2282 if (size != tag_size - 11) {
2283 GST_DEBUG_OBJECT (demux,
2284 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2285 ", corrupt or truncated file", size, tag_size - 11);
2289 /* try to update duration with timestamp in any case */
2290 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2292 /* maybe get some more metadata */
2293 if (GST_BUFFER_DATA (buffer)[0] == 18) {
2294 gst_buffer_unref (buffer);
2296 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2298 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2300 gst_flv_demux_parse_tag_script (demux, buffer);
2305 gst_buffer_unref (buffer);
2311 gst_flv_demux_loop (GstPad * pad)
2313 GstFlvDemux *demux = NULL;
2314 GstFlowReturn ret = GST_FLOW_OK;
2316 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2319 switch (demux->state) {
2320 case FLV_STATE_TAG_TYPE:
2321 if (demux->from_offset == -1)
2322 demux->from_offset = demux->offset;
2323 ret = gst_flv_demux_pull_tag (pad, demux);
2324 /* if we have seen real data, we probably passed a possible metadata
2325 * header located at start. So if we do not yet have an index,
2326 * try to pick up metadata (index, duration) at the end */
2327 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2328 (demux->has_video || demux->has_audio)))
2329 demux->file_size = gst_flv_demux_get_metadata (demux);
2331 case FLV_STATE_DONE:
2332 ret = GST_FLOW_UNEXPECTED;
2334 case FLV_STATE_SEEK:
2335 /* seek issued with insufficient index;
2336 * scan for index in task thread from current maximum offset to
2337 * desired time and then perform seek */
2338 /* TODO maybe some buffering message or so to indicate scan progress */
2339 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2341 if (ret != GST_FLOW_OK)
2343 /* position and state arranged by seek,
2344 * also unrefs event */
2345 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2346 demux->seek_event = NULL;
2349 ret = gst_flv_demux_pull_header (pad, demux);
2350 /* index scans start after header */
2351 demux->index_max_pos = demux->offset;
2355 if (demux->segment.rate < 0.0) {
2356 /* check end of section */
2357 if ((gint64) demux->offset >= demux->to_offset ||
2358 demux->segment.last_stop >= demux->segment.stop + 2 * GST_SECOND ||
2359 (demux->audio_done && demux->video_done))
2360 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2362 /* check EOS condition */
2363 if ((demux->segment.stop != -1) &&
2364 (demux->segment.last_stop >= demux->segment.stop)) {
2365 ret = GST_FLOW_UNEXPECTED;
2369 /* pause if something went wrong or at end */
2370 if (G_UNLIKELY (ret != GST_FLOW_OK))
2373 gst_object_unref (demux);
2379 const gchar *reason = gst_flow_get_name (ret);
2381 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2382 gst_pad_pause_task (pad);
2384 if (ret == GST_FLOW_UNEXPECTED) {
2385 /* perform EOS logic */
2386 if (!demux->no_more_pads) {
2387 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2388 demux->no_more_pads = TRUE;
2391 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2394 /* for segment playback we need to post when (in stream time)
2395 * we stopped, this is either stop (when set) or the duration. */
2396 if ((stop = demux->segment.stop) == -1)
2397 stop = demux->segment.duration;
2399 if (demux->segment.rate >= 0) {
2400 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2401 gst_element_post_message (GST_ELEMENT_CAST (demux),
2402 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2403 GST_FORMAT_TIME, stop));
2404 } else { /* Reverse playback */
2405 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2407 gst_element_post_message (GST_ELEMENT_CAST (demux),
2408 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2409 GST_FORMAT_TIME, demux->segment.start));
2412 /* normal playback, send EOS to all linked pads */
2413 if (!demux->no_more_pads) {
2414 gst_element_no_more_pads (GST_ELEMENT (demux));
2415 demux->no_more_pads = TRUE;
2418 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2419 if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2420 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2422 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
2423 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2424 ("Internal data stream error."),
2425 ("stream stopped, reason %s", reason));
2426 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2428 gst_object_unref (demux);
2434 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2438 GstIndexEntry *entry;
2440 g_return_val_if_fail (segment != NULL, 0);
2442 time = segment->last_stop;
2445 /* Let's check if we have an index entry for that seek time */
2446 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2447 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2448 GST_FORMAT_TIME, time);
2451 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2452 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2454 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2455 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2456 GST_TIME_ARGS (segment->last_stop), GST_TIME_ARGS (time), bytes);
2458 /* Key frame seeking */
2459 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2460 /* Adjust the segment so that the keyframe fits in */
2461 if (time < segment->start) {
2462 segment->start = segment->time = time;
2464 segment->last_stop = time;
2467 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2468 GST_TIME_ARGS (segment->start));
2476 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2480 GstSeekType start_type, stop_type;
2483 gboolean update, flush, ret;
2484 GstSegment seeksegment;
2486 gst_event_parse_seek (event, &rate, &format, &flags,
2487 &start_type, &start, &stop_type, &stop);
2489 if (format != GST_FORMAT_TIME)
2492 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2493 /* FIXME : the keyframe flag is never used ! */
2495 /* Work on a copy until we are sure the seek succeeded. */
2496 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2498 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2501 /* Apply the seek to our segment */
2502 gst_segment_set_seek (&seeksegment, rate, format, flags,
2503 start_type, start, stop_type, stop, &update);
2505 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2508 if (flush || seeksegment.last_stop != demux->segment.last_stop) {
2509 /* Do the actual seeking */
2510 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2512 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2513 G_GUINT64_FORMAT, offset);
2514 ret = gst_pad_push_event (demux->sinkpad,
2515 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2516 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2517 offset, GST_SEEK_TYPE_NONE, 0));
2518 if (G_UNLIKELY (!ret)) {
2519 GST_WARNING_OBJECT (demux, "upstream seek failed");
2522 /* Tell all the stream we moved to a different position (discont) */
2523 demux->audio_need_discont = TRUE;
2524 demux->video_need_discont = TRUE;
2530 /* Ok seek succeeded, take the newly configured segment */
2531 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2533 /* Tell all the stream a new segment is needed */
2534 demux->audio_need_segment = TRUE;
2535 demux->video_need_segment = TRUE;
2536 /* Clean any potential newsegment event kept for the streams. The first
2537 * stream needing a new segment will create a new one. */
2538 if (G_UNLIKELY (demux->new_seg_event)) {
2539 gst_event_unref (demux->new_seg_event);
2540 demux->new_seg_event = NULL;
2542 gst_event_unref (event);
2544 ret = gst_pad_push_event (demux->sinkpad, event);
2552 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2553 gst_event_unref (event);
2559 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2563 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2565 if (format != GST_FORMAT_TIME) {
2566 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2567 gst_event_unref (event);
2571 /* First try upstream */
2572 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2573 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2574 gst_event_unref (event);
2578 if (!demux->indexed) {
2579 guint64 seek_offset = 0;
2580 gboolean building_index;
2583 GST_OBJECT_LOCK (demux);
2584 /* handle the seek in the chain function */
2585 demux->seeking = TRUE;
2586 demux->state = FLV_STATE_SEEK;
2588 /* copy the event */
2589 if (demux->seek_event)
2590 gst_event_unref (demux->seek_event);
2591 demux->seek_event = gst_event_ref (event);
2593 /* set the building_index flag so that only one thread can setup the
2594 * structures for index seeking. */
2595 building_index = demux->building_index;
2596 if (!building_index) {
2597 demux->building_index = TRUE;
2598 fmt = GST_FORMAT_BYTES;
2599 if (!demux->file_size
2600 && !gst_pad_query_peer_duration (demux->sinkpad, &fmt,
2601 &demux->file_size)) {
2602 GST_WARNING_OBJECT (demux,
2603 "Cannot obtain file size - %" G_GINT64_FORMAT ", format %u",
2604 demux->file_size, fmt);
2605 GST_OBJECT_UNLOCK (demux);
2609 /* we hope the last tag is a scriptdataobject containing an index
2610 * the size of the last tag is given in the last guint32 bits
2611 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2612 seek_offset = demux->file_size - sizeof (guint32);
2613 GST_DEBUG_OBJECT (demux,
2614 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2616 GST_OBJECT_UNLOCK (demux);
2618 if (!building_index) {
2619 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2621 return flv_demux_seek_to_offset (demux, seek_offset);
2624 /* FIXME: we have to always return true so that we don't block the seek
2626 * Note: maybe it is OK to return true if we're still building the index */
2630 return flv_demux_handle_seek_push (demux, event);
2634 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2639 GstSeekType start_type, stop_type;
2642 gboolean update, flush, ret = FALSE;
2643 GstSegment seeksegment;
2645 gst_event_parse_seek (event, &rate, &format, &flags,
2646 &start_type, &start, &stop_type, &stop);
2648 if (format != GST_FORMAT_TIME)
2651 /* mark seeking thread entering flushing/pausing */
2652 GST_OBJECT_LOCK (demux);
2654 demux->seeking = seeking;
2655 GST_OBJECT_UNLOCK (demux);
2657 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2658 /* FIXME : the keyframe flag is never used */
2661 /* Flush start up and downstream to make sure data flow and loops are
2663 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2664 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2666 /* Pause the pulling task */
2667 gst_pad_pause_task (demux->sinkpad);
2670 /* Take the stream lock */
2671 GST_PAD_STREAM_LOCK (demux->sinkpad);
2674 /* Stop flushing upstream we need to pull */
2675 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
2678 /* Work on a copy until we are sure the seek succeeded. */
2679 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2681 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2684 /* Apply the seek to our segment */
2685 gst_segment_set_seek (&seeksegment, rate, format, flags,
2686 start_type, start, stop_type, stop, &update);
2688 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2691 if (flush || seeksegment.last_stop != demux->segment.last_stop) {
2692 /* Do the actual seeking */
2693 /* index is reliable if it is complete or we do not go to far ahead */
2694 if (seeking && !demux->indexed &&
2695 seeksegment.last_stop > demux->index_max_time + 10 * GST_SECOND) {
2696 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2697 " index only up to %" GST_TIME_FORMAT,
2698 GST_TIME_ARGS (demux->index_max_time));
2699 /* stop flushing for now */
2701 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop ());
2702 /* delegate scanning and index building to task thread to avoid
2703 * occupying main (UI) loop */
2704 if (demux->seek_event)
2705 gst_event_unref (demux->seek_event);
2706 demux->seek_event = gst_event_ref (event);
2707 demux->seek_time = seeksegment.last_stop;
2708 demux->state = FLV_STATE_SEEK;
2709 /* do not know about succes yet, but we did care and handled it */
2713 /* now index should be as reliable as it can be for current purpose */
2714 gst_flv_demux_move_to_offset (demux,
2715 gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2721 if (G_UNLIKELY (demux->close_seg_event)) {
2722 gst_event_unref (demux->close_seg_event);
2723 demux->close_seg_event = NULL;
2727 /* Stop flushing, the sinks are at time 0 now */
2728 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop ());
2730 GST_DEBUG_OBJECT (demux, "closing running segment %" GST_SEGMENT_FORMAT,
2733 /* Close the current segment for a linear playback */
2734 if (demux->segment.rate >= 0) {
2735 /* for forward playback, we played from start to last_stop */
2736 demux->close_seg_event = gst_event_new_new_segment (TRUE,
2737 demux->segment.rate, demux->segment.format,
2738 demux->segment.start, demux->segment.last_stop, demux->segment.time);
2742 if ((stop = demux->segment.stop) == -1)
2743 stop = demux->segment.duration;
2745 /* for reverse playback, we played from stop to last_stop. */
2746 demux->close_seg_event = gst_event_new_new_segment (TRUE,
2747 demux->segment.rate, demux->segment.format,
2748 demux->segment.last_stop, stop, demux->segment.last_stop);
2753 /* Ok seek succeeded, take the newly configured segment */
2754 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2756 /* Notify about the start of a new segment */
2757 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2758 gst_element_post_message (GST_ELEMENT (demux),
2759 gst_message_new_segment_start (GST_OBJECT (demux),
2760 demux->segment.format, demux->segment.last_stop));
2763 /* Tell all the stream a new segment is needed */
2764 demux->audio_need_segment = TRUE;
2765 demux->video_need_segment = TRUE;
2766 /* Clean any potential newsegment event kept for the streams. The first
2767 * stream needing a new segment will create a new one. */
2768 if (G_UNLIKELY (demux->new_seg_event)) {
2769 gst_event_unref (demux->new_seg_event);
2770 demux->new_seg_event = NULL;
2772 if (demux->segment.rate < 0.0) {
2773 /* we can't generate a segment by locking on
2774 * to the first timestamp we see */
2775 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2776 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2777 GST_TIME_ARGS (demux->segment.start),
2778 GST_TIME_ARGS (demux->segment.stop));
2779 demux->new_seg_event =
2780 gst_event_new_new_segment (FALSE, demux->segment.rate,
2781 demux->segment.format, demux->segment.start,
2782 demux->segment.stop, demux->segment.start);
2787 GST_OBJECT_LOCK (demux);
2788 seeking = demux->seeking && !seeking;
2789 demux->seeking = FALSE;
2790 GST_OBJECT_UNLOCK (demux);
2792 /* if we detect an external seek having started (and possibly already having
2793 * flushed), do not restart task to give it a chance.
2794 * Otherwise external one's flushing will take care to pause task */
2796 gst_pad_pause_task (demux->sinkpad);
2798 gst_pad_start_task (demux->sinkpad,
2799 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
2802 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2804 gst_event_unref (event);
2810 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2811 gst_event_unref (event);
2816 /* If we can pull that's prefered */
2818 gst_flv_demux_sink_activate (GstPad * sinkpad)
2820 if (gst_pad_check_pull_range (sinkpad)) {
2821 return gst_pad_activate_pull (sinkpad, TRUE);
2823 return gst_pad_activate_push (sinkpad, TRUE);
2827 /* This function gets called when we activate ourselves in push mode.
2828 * We cannot seek (ourselves) in the stream */
2830 gst_flv_demux_sink_activate_push (GstPad * sinkpad, gboolean active)
2834 demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
2836 demux->random_access = FALSE;
2838 gst_object_unref (demux);
2843 /* this function gets called when we activate ourselves in pull mode.
2844 * We can perform random access to the resource and we start a task
2845 * to start reading */
2847 gst_flv_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
2851 demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
2854 demux->random_access = TRUE;
2855 gst_object_unref (demux);
2856 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
2859 demux->random_access = FALSE;
2860 gst_object_unref (demux);
2861 return gst_pad_stop_task (sinkpad);
2866 gst_flv_demux_sink_event (GstPad * pad, GstEvent * event)
2869 gboolean ret = FALSE;
2871 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2873 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2875 switch (GST_EVENT_TYPE (event)) {
2876 case GST_EVENT_FLUSH_START:
2877 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
2878 demux->flushing = TRUE;
2879 ret = gst_flv_demux_push_src_event (demux, event);
2881 case GST_EVENT_FLUSH_STOP:
2882 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
2883 gst_flv_demux_flush (demux, TRUE);
2884 ret = gst_flv_demux_push_src_event (demux, event);
2887 GST_DEBUG_OBJECT (demux, "received EOS");
2889 GST_DEBUG_OBJECT (demux, "committing index");
2890 gst_index_commit (demux->index, demux->index_id);
2892 if (!demux->no_more_pads) {
2893 gst_element_no_more_pads (GST_ELEMENT (demux));
2894 demux->no_more_pads = TRUE;
2897 if (!gst_flv_demux_push_src_event (demux, event))
2898 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2901 case GST_EVENT_NEWSEGMENT:
2905 gint64 start, stop, time;
2908 GST_DEBUG_OBJECT (demux, "received new segment");
2910 gst_event_parse_new_segment (event, &update, &rate, &format, &start,
2913 if (format == GST_FORMAT_TIME) {
2914 /* time segment, this is perfect, copy over the values. */
2915 gst_segment_set_newsegment (&demux->segment, update, rate, format,
2918 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
2922 ret = gst_flv_demux_push_src_event (demux, event);
2924 /* non-time format */
2925 demux->audio_need_segment = TRUE;
2926 demux->video_need_segment = TRUE;
2928 gst_event_unref (event);
2933 ret = gst_flv_demux_push_src_event (demux, event);
2937 gst_object_unref (demux);
2943 gst_flv_demux_src_event (GstPad * pad, GstEvent * event)
2946 gboolean ret = FALSE;
2948 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2950 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2952 switch (GST_EVENT_TYPE (event)) {
2953 case GST_EVENT_SEEK:
2954 if (demux->random_access) {
2955 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
2957 ret = gst_flv_demux_handle_seek_push (demux, event);
2961 ret = gst_pad_push_event (demux->sinkpad, event);
2965 gst_object_unref (demux);
2971 gst_flv_demux_query (GstPad * pad, GstQuery * query)
2973 gboolean res = TRUE;
2976 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2978 switch (GST_QUERY_TYPE (query)) {
2979 case GST_QUERY_DURATION:
2983 gst_query_parse_duration (query, &format, NULL);
2985 /* duration is time only */
2986 if (format != GST_FORMAT_TIME) {
2987 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
2993 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
2994 GST_TIME_ARGS (demux->duration));
2996 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3000 case GST_QUERY_POSITION:
3004 gst_query_parse_position (query, &format, NULL);
3006 /* position is time only */
3007 if (format != GST_FORMAT_TIME) {
3008 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3014 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3015 GST_TIME_ARGS (demux->segment.last_stop));
3017 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.last_stop);
3022 case GST_QUERY_SEEKING:{
3025 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3027 /* First ask upstream */
3028 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3031 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3038 if (fmt != GST_FORMAT_TIME || !demux->index) {
3039 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3040 } else if (demux->random_access) {
3041 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3044 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3045 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3048 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3049 gst_query_unref (peerquery);
3052 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3055 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3059 case GST_QUERY_LATENCY:
3064 if ((peer = gst_pad_get_peer (demux->sinkpad))) {
3065 /* query latency on peer pad */
3066 res = gst_pad_query (peer, query);
3067 gst_object_unref (peer);
3069 /* no peer, we don't know */
3077 gst_object_unref (demux);
3082 static GstStateChangeReturn
3083 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3086 GstStateChangeReturn ret;
3088 demux = GST_FLV_DEMUX (element);
3090 switch (transition) {
3091 case GST_STATE_CHANGE_READY_TO_PAUSED:
3092 /* If this is our own index destroy it as the
3093 * old entries might be wrong for the new stream */
3094 if (demux->own_index) {
3095 gst_object_unref (demux->index);
3096 demux->index = NULL;
3097 demux->own_index = FALSE;
3100 /* If no index was created, generate one */
3101 if (G_UNLIKELY (!demux->index)) {
3102 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3104 demux->index = gst_index_factory_make ("memindex");
3106 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3108 demux->own_index = TRUE;
3110 gst_flv_demux_cleanup (demux);
3116 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3117 if (ret == GST_STATE_CHANGE_FAILURE)
3120 switch (transition) {
3121 case GST_STATE_CHANGE_PAUSED_TO_READY:
3122 gst_flv_demux_cleanup (demux);
3132 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3134 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3136 GST_OBJECT_LOCK (demux);
3138 gst_object_unref (demux->index);
3140 demux->index = gst_object_ref (index);
3141 demux->own_index = FALSE;
3143 demux->index = NULL;
3145 GST_OBJECT_UNLOCK (demux);
3146 /* object lock might be taken again */
3148 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3149 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3154 gst_flv_demux_get_index (GstElement * element)
3156 GstIndex *result = NULL;
3158 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3160 GST_OBJECT_LOCK (demux);
3162 result = gst_object_ref (demux->index);
3163 GST_OBJECT_UNLOCK (demux);
3169 gst_flv_demux_dispose (GObject * object)
3171 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3173 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3175 if (demux->adapter) {
3176 gst_adapter_clear (demux->adapter);
3177 g_object_unref (demux->adapter);
3178 demux->adapter = NULL;
3181 if (demux->taglist) {
3182 gst_tag_list_free (demux->taglist);
3183 demux->taglist = NULL;
3186 if (demux->new_seg_event) {
3187 gst_event_unref (demux->new_seg_event);
3188 demux->new_seg_event = NULL;
3191 if (demux->close_seg_event) {
3192 gst_event_unref (demux->close_seg_event);
3193 demux->close_seg_event = NULL;
3196 if (demux->audio_codec_data) {
3197 gst_buffer_unref (demux->audio_codec_data);
3198 demux->audio_codec_data = NULL;
3201 if (demux->video_codec_data) {
3202 gst_buffer_unref (demux->video_codec_data);
3203 demux->video_codec_data = NULL;
3206 if (demux->audio_pad) {
3207 gst_object_unref (demux->audio_pad);
3208 demux->audio_pad = NULL;
3211 if (demux->video_pad) {
3212 gst_object_unref (demux->video_pad);
3213 demux->video_pad = NULL;
3217 gst_object_unref (demux->index);
3218 demux->index = NULL;
3222 g_array_free (demux->times, TRUE);
3223 demux->times = NULL;
3226 if (demux->filepositions) {
3227 g_array_free (demux->filepositions, TRUE);
3228 demux->filepositions = NULL;
3231 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3235 gst_flv_demux_base_init (gpointer g_class)
3237 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
3239 gst_element_class_add_static_pad_template (element_class,
3240 &flv_sink_template);
3241 gst_element_class_add_static_pad_template (element_class,
3242 &audio_src_template);
3243 gst_element_class_add_static_pad_template (element_class,
3244 &video_src_template);
3245 gst_element_class_set_details_simple (element_class, "FLV Demuxer",
3247 "Demux FLV feeds into digital streams",
3248 "Julien Moutte <julien@moutte.net>");
3252 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3254 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3255 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3257 gobject_class->dispose = gst_flv_demux_dispose;
3259 gstelement_class->change_state =
3260 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3261 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3262 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3266 gst_flv_demux_init (GstFlvDemux * demux, GstFlvDemuxClass * g_class)
3269 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3271 gst_pad_set_event_function (demux->sinkpad,
3272 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3273 gst_pad_set_chain_function (demux->sinkpad,
3274 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3275 gst_pad_set_activate_function (demux->sinkpad,
3276 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3277 gst_pad_set_activatepull_function (demux->sinkpad,
3278 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_pull));
3279 gst_pad_set_activatepush_function (demux->sinkpad,
3280 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_push));
3282 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3284 demux->adapter = gst_adapter_new ();
3285 demux->taglist = gst_tag_list_new ();
3286 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3288 demux->own_index = FALSE;
3290 gst_flv_demux_cleanup (demux);
3294 plugin_init (GstPlugin * plugin)
3296 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3298 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3299 gst_flv_demux_get_type ()) ||
3300 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3301 gst_flv_mux_get_type ()))
3307 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3308 "flv", "FLV muxing and demuxing plugin",
3309 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)