2 * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * SECTION:element-flvdemux
23 * flvdemux demuxes an FLV file into the different contained streams.
26 * <title>Example launch line</title>
28 * gst-launch -v filesrc location=/path/to/flv ! flvdemux ! audioconvert ! autoaudiosink
29 * ]| This pipeline demuxes an FLV file and outputs the contained raw audio streams.
37 #include "gstflvdemux.h"
38 #include "gstflvmux.h"
41 #include <gst/base/gstbytereader.h>
42 #include <gst/pbutils/descriptions.h>
43 #include <gst/pbutils/pbutils.h>
45 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
48 GST_STATIC_CAPS ("video/x-flv")
51 static GstStaticPadTemplate audio_src_template =
52 GST_STATIC_PAD_TEMPLATE ("audio",
56 ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
57 "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
58 "audio/mpeg, mpegversion = (int) 4, framed = (boolean) TRUE; "
59 "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
60 "audio/x-raw-int, endianness = (int) LITTLE_ENDIAN, channels = (int) { 1, 2 }, width = (int) 8, depth = (int) 8, rate = (int) { 5512, 11025, 22050, 44100 }, signed = (boolean) FALSE; "
61 "audio/x-raw-int, endianness = (int) LITTLE_ENDIAN, channels = (int) { 1, 2 }, width = (int) 16, depth = (int) 16, rate = (int) { 5512, 11025, 22050, 44100 }, signed = (boolean) TRUE; "
62 "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
63 "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
64 "audio/x-speex, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 };")
67 static GstStaticPadTemplate video_src_template =
68 GST_STATIC_PAD_TEMPLATE ("video",
71 GST_STATIC_CAPS ("video/x-flash-video; "
72 "video/x-flash-screen; "
73 "video/x-vp6-flash; " "video/x-vp6-alpha; "
74 "video/x-h264, stream-format=avc;")
77 GST_DEBUG_CATEGORY_STATIC (flvdemux_debug);
78 #define GST_CAT_DEFAULT flvdemux_debug
80 #define gst_flv_demux_parent_class parent_class
81 G_DEFINE_TYPE (GstFlvDemux, gst_flv_demux, GST_TYPE_ELEMENT);
83 /* 9 bytes of header + 4 bytes of first previous tag size */
84 #define FLV_HEADER_SIZE 13
85 /* 1 byte of tag type + 3 bytes of tag data size */
86 #define FLV_TAG_TYPE_SIZE 4
88 /* two seconds - consider pts are resynced to another base if this different */
89 #define RESYNC_THRESHOLD 2000
91 static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
93 static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
94 GstEvent * event, gboolean seeking);
96 static gboolean gst_flv_demux_query (GstPad * pad, GstObject * parent,
98 static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent,
103 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
104 guint64 pos, gboolean keyframe)
106 static GstIndexAssociation associations[2];
107 static GstIndexEntry *entry;
109 GST_LOG_OBJECT (demux,
110 "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
111 keyframe, GST_TIME_ARGS (ts), pos);
113 /* if upstream is not seekable there is no point in building an index */
114 if (!demux->upstream_seekable)
117 /* entry may already have been added before, avoid adding indefinitely */
118 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
119 GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
122 #ifndef GST_DISABLE_GST_DEBUG
126 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
127 key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
128 GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
129 ", keyframe %d", GST_TIME_ARGS (time), key);
130 /* there is not really a way to delete the existing one */
131 if (time != ts || key != ! !keyframe)
132 GST_DEBUG_OBJECT (demux, "metadata mismatch");
137 associations[0].format = GST_FORMAT_TIME;
138 associations[0].value = ts;
139 associations[1].format = GST_FORMAT_BYTES;
140 associations[1].value = pos;
142 gst_index_add_associationv (demux->index, demux->index_id,
143 (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
144 GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
145 (const GstIndexAssociation *) &associations);
147 if (pos > demux->index_max_pos)
148 demux->index_max_pos = pos;
149 if (ts > demux->index_max_time)
150 demux->index_max_time = ts;
154 FLV_GET_STRING (GstByteReader * reader)
156 guint16 string_size = 0;
157 gchar *string = NULL;
158 const guint8 *str = NULL;
160 g_return_val_if_fail (reader != NULL, NULL);
162 if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
165 if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
168 string = g_try_malloc0 (string_size + 1);
169 if (G_UNLIKELY (!string)) {
173 if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
178 memcpy (string, str, string_size);
179 if (!g_utf8_validate (string, string_size, NULL)) {
188 gst_flv_demux_check_seekability (GstFlvDemux * demux)
191 gint64 start = -1, stop = -1;
193 demux->upstream_seekable = FALSE;
195 query = gst_query_new_seeking (GST_FORMAT_BYTES);
196 if (!gst_pad_peer_query (demux->sinkpad, query)) {
197 GST_DEBUG_OBJECT (demux, "seeking query failed");
198 gst_query_unref (query);
202 gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
205 gst_query_unref (query);
207 /* try harder to query upstream size if we didn't get it the first time */
208 if (demux->upstream_seekable && stop == -1) {
209 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
210 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
213 /* if upstream doesn't know the size, it's likely that it's not seekable in
214 * practice even if it technically may be seekable */
215 if (demux->upstream_seekable && (start != 0 || stop <= start)) {
216 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
217 demux->upstream_seekable = FALSE;
220 GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
224 parse_flv_demux_parse_date_string (GDate * date, const gchar * s)
226 g_date_set_parse (date, s);
227 if (g_date_valid (date))
230 /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
232 static const gchar *months[] = {
233 "Jan", "Feb", "Mar", "Apr",
234 "May", "Jun", "Jul", "Aug",
235 "Sep", "Oct", "Nov", "Dec"
237 gchar **tokens = g_strsplit (s, " ", -1);
242 if (g_strv_length (tokens) != 5)
245 if (strlen (tokens[1]) != 3)
247 for (i = 0; i < 12; i++) {
248 if (!strcmp (tokens[1], months[i])) {
254 g_date_set_month (date, i + 1);
256 d = g_ascii_strtoull (tokens[2], &endptr, 10);
257 if (d == 0 && *endptr != '\0')
260 g_date_set_day (date, d);
262 d = g_ascii_strtoull (tokens[4], &endptr, 10);
263 if (d == 0 && *endptr != '\0')
266 g_date_set_year (date, d);
275 gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
276 gboolean * end_marker)
278 gchar *tag_name = NULL;
281 /* Initialize the end_marker flag to FALSE */
284 /* Name of the tag */
285 tag_name = FLV_GET_STRING (reader);
286 if (G_UNLIKELY (!tag_name)) {
287 GST_WARNING_OBJECT (demux, "failed reading tag name");
291 /* What kind of object is that */
292 if (!gst_byte_reader_get_uint8 (reader, &tag_type))
295 GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
299 { /* Use a union to read the uint64 and then as a double */
302 if (!gst_byte_reader_get_float64_be (reader, &d))
305 GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
307 if (!strcmp (tag_name, "duration")) {
308 demux->duration = d * GST_SECOND;
310 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
311 GST_TAG_DURATION, demux->duration, NULL);
312 } else if (!strcmp (tag_name, "AspectRatioX")) {
314 demux->got_par = TRUE;
315 } else if (!strcmp (tag_name, "AspectRatioY")) {
317 demux->got_par = TRUE;
318 } else if (!strcmp (tag_name, "width")) {
320 } else if (!strcmp (tag_name, "height")) {
322 } else if (!strcmp (tag_name, "framerate")) {
323 demux->framerate = d;
325 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
334 if (!gst_byte_reader_get_uint8 (reader, &b))
337 GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
339 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
347 s = FLV_GET_STRING (reader);
351 GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
353 if (!strcmp (tag_name, "creationdate")) {
354 GDate *date = g_date_new ();
356 parse_flv_demux_parse_date_string (date, s);
357 if (!g_date_valid (date)) {
358 GST_DEBUG_OBJECT (demux, "Failed to parse string as date");
360 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
361 GST_TAG_DATE, date, NULL);
364 } else if (!strcmp (tag_name, "creator")) {
365 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
366 GST_TAG_ARTIST, s, NULL);
367 } else if (!strcmp (tag_name, "title")) {
368 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
369 GST_TAG_TITLE, s, NULL);
370 } else if (!strcmp (tag_name, "metadatacreator")) {
371 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
372 GST_TAG_ENCODER, s, NULL);
374 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
383 gboolean end_of_object_marker = FALSE;
385 while (!end_of_object_marker) {
386 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
387 &end_of_object_marker);
389 if (G_UNLIKELY (!ok)) {
390 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
397 case 8: // ECMA array
399 guint32 nb_elems = 0;
400 gboolean end_of_object_marker = FALSE;
402 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
405 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
408 while (!end_of_object_marker) {
409 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
410 &end_of_object_marker);
412 if (G_UNLIKELY (!ok)) {
413 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
420 case 9: // End marker
422 GST_DEBUG_OBJECT (demux, "end marker ?");
423 if (tag_name[0] == '\0') {
425 GST_DEBUG_OBJECT (demux, "end marker detected");
434 guint32 nb_elems = 0;
436 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
439 GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
441 if (!strcmp (tag_name, "times")) {
443 g_array_free (demux->times, TRUE);
445 demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
446 } else if (!strcmp (tag_name, "filepositions")) {
447 if (demux->filepositions) {
448 g_array_free (demux->filepositions, TRUE);
450 demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
454 guint8 elem_type = 0;
456 if (!gst_byte_reader_get_uint8 (reader, &elem_type))
464 if (!gst_byte_reader_get_float64_be (reader, &d))
467 GST_DEBUG_OBJECT (demux, "element is a double %f", d);
469 if (!strcmp (tag_name, "times") && demux->times) {
470 g_array_append_val (demux->times, d);
471 } else if (!strcmp (tag_name, "filepositions") &&
472 demux->filepositions) {
473 g_array_append_val (demux->filepositions, d);
478 GST_WARNING_OBJECT (demux, "unsupported array element type %d",
490 if (!gst_byte_reader_get_float64_be (reader, &d))
493 if (!gst_byte_reader_get_int16_be (reader, &i))
496 GST_DEBUG_OBJECT (demux,
497 "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
499 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
504 GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
518 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
520 GstFlowReturn ret = GST_FLOW_OK;
521 GstByteReader reader;
526 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 7, GST_FLOW_ERROR);
528 data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
529 gst_byte_reader_init (&reader, data, size);
531 gst_byte_reader_skip (&reader, 7);
533 GST_LOG_OBJECT (demux, "parsing a script tag");
535 if (!gst_byte_reader_get_uint8 (&reader, &type))
540 gchar *function_name;
543 function_name = FLV_GET_STRING (&reader);
545 GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
547 if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
548 gboolean end_marker = FALSE;
549 GST_DEBUG_OBJECT (demux, "we have a metadata script object");
551 if (!gst_byte_reader_get_uint8 (&reader, &type)) {
552 g_free (function_name);
559 guint32 nb_elems = 0;
562 if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
563 g_free (function_name);
567 /* The number of elements is just a hint, some files have
568 nb_elements == 0 and actually contain items. */
569 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
572 /* fallthrough to read data */
576 while (!end_marker) {
578 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
580 if (G_UNLIKELY (!ok)) {
581 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
588 GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
589 g_free (function_name);
593 demux->push_tags = TRUE;
596 g_free (function_name);
598 if (demux->index && demux->times && demux->filepositions) {
601 /* If an index was found, insert associations */
602 num = MIN (demux->times->len, demux->filepositions->len);
603 for (i = 0; i < num; i++) {
604 guint64 time, fileposition;
606 time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
607 fileposition = g_array_index (demux->filepositions, gdouble, i);
608 gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
611 demux->indexed = TRUE;
616 gst_buffer_unmap (buffer, data, -1);
622 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
623 guint32 rate, guint32 channels, guint32 width)
625 GstCaps *caps = NULL;
626 gchar *codec_name = NULL;
627 gboolean ret = FALSE;
628 guint adjusted_rate = rate;
632 caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
637 caps = gst_caps_new_simple ("audio/mpeg",
638 "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
639 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
643 /* Assuming little endian for 0 (aka endianness of the
644 * system on which the file was created) as most people
645 * are probably using little endian machines */
646 caps = gst_caps_new_simple ("audio/x-raw-int",
647 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
648 "signed", G_TYPE_BOOLEAN, (width == 8) ? FALSE : TRUE,
649 "width", G_TYPE_INT, width, "depth", G_TYPE_INT, width, NULL);
654 caps = gst_caps_new_empty_simple ("audio/x-nellymoser");
661 if (demux->audio_codec_data)
662 data = gst_buffer_map (demux->audio_codec_data, &size, NULL,
664 /* use codec-data to extract and verify samplerate */
665 if (demux->audio_codec_data && size >= 2) {
668 freq_index = GST_READ_UINT16_BE (data);
669 freq_index = (freq_index & 0x0780) >> 7;
671 gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
673 if (adjusted_rate && (rate != adjusted_rate)) {
674 GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
677 adjusted_rate = rate;
681 gst_buffer_unmap (demux->audio_codec_data, data, -1);
682 caps = gst_caps_new_simple ("audio/mpeg",
683 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
684 "stream-format", G_TYPE_STRING, "raw", NULL);
688 caps = gst_caps_new_empty_simple ("audio/x-alaw");
691 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
694 caps = gst_caps_new_empty_simple ("audio/x-speex");
697 GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
700 if (G_UNLIKELY (!caps)) {
701 GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
705 gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
706 "channels", G_TYPE_INT, channels, NULL);
708 if (demux->audio_codec_data) {
709 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
710 demux->audio_codec_data, NULL);
713 ret = gst_pad_set_caps (demux->audio_pad, caps);
715 if (G_LIKELY (ret)) {
716 /* Store the caps we got from tags */
717 demux->audio_codec_tag = codec_tag;
719 demux->channels = channels;
720 demux->width = width;
722 codec_name = gst_pb_utils_get_codec_description (caps);
725 if (demux->taglist == NULL)
726 demux->taglist = gst_tag_list_new_empty ();
727 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
728 GST_TAG_AUDIO_CODEC, codec_name, NULL);
732 GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
733 GST_PTR_FORMAT, caps);
735 GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
736 GST_PTR_FORMAT, caps);
739 gst_caps_unref (caps);
746 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
750 if (demux->audio_pad)
751 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
753 if (demux->video_pad)
754 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
756 gst_event_unref (event);
762 gst_flv_demux_push_tags (GstFlvDemux * demux)
764 if (demux->has_audio && !demux->audio_pad) {
765 GST_DEBUG_OBJECT (demux,
766 "Waiting for audio stream pad to come up before we can push tags");
769 if (demux->has_video && !demux->video_pad) {
770 GST_DEBUG_OBJECT (demux,
771 "Waiting for video stream pad to come up before we can push tags");
774 if (demux->taglist) {
775 GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
777 gst_flv_demux_push_src_event (demux, gst_event_new_tag (demux->taglist));
778 demux->taglist = gst_tag_list_new_empty ();
779 demux->push_tags = FALSE;
784 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, gboolean discont,
785 guint32 * last, GstClockTime * offset)
787 if (!discont && ABS (pts - *last) >= RESYNC_THRESHOLD) {
788 /* Theoretically, we should use substract the duration of the last buffer,
789 but this demuxer sends no durations on buffers, not sure if it cannot
790 know, or just does not care to calculate. */
791 gint32 dpts = pts - *last;
792 *offset -= dpts * GST_MSECOND;
793 GST_WARNING_OBJECT (demux,
794 "Large pts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
795 GST_TIME_FORMAT "", dpts, GST_TIME_ARGS (*offset));
801 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
803 GstFlowReturn ret = GST_FLOW_OK;
804 guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
805 guint32 codec_data = 0, pts_ext = 0;
811 GST_LOG_OBJECT (demux, "parsing an audio tag");
813 if (demux->no_more_pads && !demux->audio_pad) {
814 GST_WARNING_OBJECT (demux,
815 "Signaled no-more-pads already but had no audio pad -- ignoring");
819 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
822 /* Error out on tags with too small headers */
823 if (gst_buffer_get_size (buffer) < 11) {
824 GST_ERROR_OBJECT (demux, "Too small tag size (%" G_GSIZE_FORMAT ")",
825 gst_buffer_get_size (buffer));
826 return GST_FLOW_ERROR;
829 data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
831 /* Grab information about audio tag */
832 pts = GST_READ_UINT24_BE (data);
833 /* read the pts extension to 32 bits integer */
834 pts_ext = GST_READ_UINT8 (data + 3);
836 pts |= pts_ext << 24;
838 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
839 data[2], data[3], pts);
841 /* Skip the stream id and go directly to the flags */
842 flags = GST_READ_UINT8 (data + 7);
844 /* Silently skip buffers with no data */
857 if ((flags & 0x0C) == 0x0C) {
859 } else if ((flags & 0x0C) == 0x08) {
861 } else if ((flags & 0x0C) == 0x04) {
865 codec_tag = flags >> 4;
866 if (codec_tag == 10) { /* AAC has an extra byte for packet type */
872 /* codec tags with special rates */
873 if (codec_tag == 5 || codec_tag == 14)
875 else if (codec_tag == 4)
878 GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
879 "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
882 /* If we don't have our audio pad created, then create it. */
883 if (G_UNLIKELY (!demux->audio_pad)) {
886 gst_pad_new_from_template (gst_element_class_get_pad_template
887 (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
888 if (G_UNLIKELY (!demux->audio_pad)) {
889 GST_WARNING_OBJECT (demux, "failed creating audio pad");
890 ret = GST_FLOW_ERROR;
895 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
897 gst_object_unref (demux->audio_pad);
898 demux->audio_pad = NULL;
899 ret = GST_FLOW_ERROR;
902 #ifndef GST_DISABLE_GST_DEBUG
906 caps = gst_pad_get_current_caps (demux->audio_pad);
907 GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
910 gst_caps_unref (caps);
914 /* Set functions on the pad */
915 gst_pad_set_query_function (demux->audio_pad,
916 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
917 gst_pad_set_event_function (demux->audio_pad,
918 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
920 gst_pad_use_fixed_caps (demux->audio_pad);
923 gst_pad_set_active (demux->audio_pad, TRUE);
925 /* We need to set caps before adding */
926 gst_element_add_pad (GST_ELEMENT (demux),
927 gst_object_ref (demux->audio_pad));
929 /* We only emit no more pads when we have audio and video. Indeed we can
930 * not trust the FLV header to tell us if there will be only audio or
931 * only video and we would just break discovery of some files */
932 if (demux->audio_pad && demux->video_pad) {
933 GST_DEBUG_OBJECT (demux, "emitting no more pads");
934 gst_element_no_more_pads (GST_ELEMENT (demux));
935 demux->no_more_pads = TRUE;
936 demux->push_tags = TRUE;
940 /* Check if caps have changed */
941 if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
942 codec_tag != demux->audio_codec_tag || width != demux->width)) {
943 GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
946 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
948 ret = GST_FLOW_ERROR;
953 /* Push taglist if present */
954 if (G_UNLIKELY (demux->push_tags))
955 gst_flv_demux_push_tags (demux);
957 /* Check if we have anything to push */
958 if (demux->tag_data_size <= codec_data) {
959 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
963 /* Create buffer from pad */
964 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
965 7 + codec_data, demux->tag_data_size - codec_data);
967 if (demux->audio_codec_tag == 10) {
968 guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
970 switch (aac_packet_type) {
973 /* AudioSpecificConfig data */
974 GST_LOG_OBJECT (demux, "got an AAC codec data packet");
975 if (demux->audio_codec_data) {
976 gst_buffer_unref (demux->audio_codec_data);
978 demux->audio_codec_data = outbuf;
979 /* Use that buffer data in the caps */
980 gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels, width);
986 GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
989 GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
994 /* detect (and deem to be resyncs) large pts gaps */
995 gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
996 &demux->last_audio_pts, &demux->audio_time_offset);
998 /* Fill buffer with data */
999 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
1000 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1001 GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
1002 GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
1004 if (demux->duration == GST_CLOCK_TIME_NONE ||
1005 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1006 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1008 /* Only add audio frames to the index if we have no video,
1009 * and if the index is not yet complete */
1010 if (!demux->has_video && demux->index && !demux->indexed) {
1011 gst_flv_demux_parse_and_add_index_entry (demux,
1012 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
1015 if (G_UNLIKELY (demux->audio_need_discont)) {
1016 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1017 demux->audio_need_discont = FALSE;
1020 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1022 /* Do we need a newsegment event ? */
1023 if (G_UNLIKELY (demux->audio_need_segment)) {
1024 /* FIXME need one segment sent for all stream to maintain a/v sync */
1025 if (!demux->new_seg_event) {
1026 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1027 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1028 GST_TIME_ARGS (demux->segment.position),
1029 GST_TIME_ARGS (demux->segment.stop));
1030 demux->segment.start = demux->segment.time = demux->segment.position;
1031 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1033 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1036 gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1038 demux->audio_need_segment = FALSE;
1041 GST_LOG_OBJECT (demux,
1042 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1043 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1044 gst_buffer_get_size (outbuf),
1045 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1046 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1048 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1049 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1051 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1052 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1055 if (G_UNLIKELY (!demux->no_more_pads
1056 && (GST_CLOCK_DIFF (demux->audio_start,
1057 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1058 GST_DEBUG_OBJECT (demux,
1059 "Signalling no-more-pads because no video stream was found"
1060 " after 6 seconds of audio");
1061 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1062 demux->no_more_pads = TRUE;
1063 demux->push_tags = TRUE;
1066 /* Push downstream */
1067 ret = gst_pad_push (demux->audio_pad, outbuf);
1068 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1069 if (demux->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
1070 demux->segment.position > demux->segment.stop) {
1071 /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
1072 * we are at the end of the segment, so we just need to jump
1073 * back to the previous section. */
1074 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1075 demux->audio_done = TRUE;
1078 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1079 " bytes audio buffer: %s", demux->tag_data_size,
1080 gst_flow_get_name (ret));
1081 if (ret == GST_FLOW_NOT_LINKED) {
1082 demux->audio_linked = FALSE;
1088 demux->audio_linked = TRUE;
1091 gst_buffer_unmap (buffer, data, -1);
1097 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1099 gboolean ret = FALSE;
1100 GstCaps *caps = NULL;
1101 gchar *codec_name = NULL;
1103 /* Generate caps for that pad */
1104 switch (codec_tag) {
1106 caps = gst_caps_new_empty_simple ("video/x-flash-video");
1109 caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1112 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1115 caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1119 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1123 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1126 if (G_UNLIKELY (!caps)) {
1127 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1131 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1132 demux->par_x, demux->par_y, NULL);
1134 if (G_LIKELY (demux->w)) {
1135 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1138 if (G_LIKELY (demux->h)) {
1139 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1142 if (G_LIKELY (demux->framerate)) {
1143 gint num = 0, den = 0;
1145 gst_util_double_to_fraction (demux->framerate, &num, &den);
1146 GST_DEBUG_OBJECT (demux->video_pad,
1147 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1150 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1153 if (demux->video_codec_data) {
1154 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1155 demux->video_codec_data, NULL);
1158 ret = gst_pad_set_caps (demux->video_pad, caps);
1160 if (G_LIKELY (ret)) {
1161 /* Store the caps we have set */
1162 demux->video_codec_tag = codec_tag;
1164 codec_name = gst_pb_utils_get_codec_description (caps);
1167 if (demux->taglist == NULL)
1168 demux->taglist = gst_tag_list_new_empty ();
1169 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1170 GST_TAG_VIDEO_CODEC, codec_name, NULL);
1171 g_free (codec_name);
1174 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1175 GST_PTR_FORMAT, caps);
1177 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1178 GST_PTR_FORMAT, caps);
1181 gst_caps_unref (caps);
1187 static GstFlowReturn
1188 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1190 GstFlowReturn ret = GST_FLOW_OK;
1191 guint32 pts = 0, codec_data = 1, pts_ext = 0;
1192 gboolean keyframe = FALSE;
1193 guint8 flags = 0, codec_tag = 0;
1198 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1201 GST_LOG_OBJECT (demux, "parsing a video tag");
1203 if (demux->no_more_pads && !demux->video_pad) {
1204 GST_WARNING_OBJECT (demux,
1205 "Signaled no-more-pads already but had no audio pad -- ignoring");
1209 if (gst_buffer_get_size (buffer) < 12) {
1210 GST_ERROR_OBJECT (demux, "Too small tag size");
1211 return GST_FLOW_ERROR;
1214 data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
1216 /* Grab information about video tag */
1217 pts = GST_READ_UINT24_BE (data);
1218 /* read the pts extension to 32 bits integer */
1219 pts_ext = GST_READ_UINT8 (data + 3);
1221 pts |= pts_ext << 24;
1223 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1224 data[2], data[3], pts);
1226 /* Skip the stream id and go directly to the flags */
1227 flags = GST_READ_UINT8 (data + 7);
1230 if ((flags >> 4) == 1) {
1234 codec_tag = flags & 0x0F;
1235 if (codec_tag == 4 || codec_tag == 5) {
1237 } else if (codec_tag == 7) {
1242 cts = GST_READ_UINT24_BE (data + 9);
1243 cts = (cts + 0xff800000) ^ 0xff800000;
1245 GST_LOG_OBJECT (demux, "got cts %d", cts);
1247 /* avoid negative overflow */
1248 if (cts >= 0 || pts >= -cts)
1252 GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1253 "(flags %02X)", codec_tag, keyframe, flags);
1255 /* If we don't have our video pad created, then create it. */
1256 if (G_UNLIKELY (!demux->video_pad)) {
1258 gst_pad_new_from_template (gst_element_class_get_pad_template
1259 (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1260 if (G_UNLIKELY (!demux->video_pad)) {
1261 GST_WARNING_OBJECT (demux, "failed creating video pad");
1262 ret = GST_FLOW_ERROR;
1266 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1267 gst_object_unref (demux->video_pad);
1268 demux->video_pad = NULL;
1269 ret = GST_FLOW_ERROR;
1273 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1274 * metadata tag that would come later and trigger a caps change */
1275 demux->got_par = FALSE;
1277 #ifndef GST_DISABLE_GST_DEBUG
1281 caps = gst_pad_get_current_caps (demux->video_pad);
1282 GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1285 gst_caps_unref (caps);
1289 /* Set functions on the pad */
1290 gst_pad_set_query_function (demux->video_pad,
1291 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1292 gst_pad_set_event_function (demux->video_pad,
1293 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1295 gst_pad_use_fixed_caps (demux->video_pad);
1297 /* Make it active */
1298 gst_pad_set_active (demux->video_pad, TRUE);
1300 /* We need to set caps before adding */
1301 gst_element_add_pad (GST_ELEMENT (demux),
1302 gst_object_ref (demux->video_pad));
1304 /* We only emit no more pads when we have audio and video. Indeed we can
1305 * not trust the FLV header to tell us if there will be only audio or
1306 * only video and we would just break discovery of some files */
1307 if (demux->audio_pad && demux->video_pad) {
1308 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1309 gst_element_no_more_pads (GST_ELEMENT (demux));
1310 demux->no_more_pads = TRUE;
1311 demux->push_tags = TRUE;
1315 /* Check if caps have changed */
1316 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1318 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1320 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1321 ret = GST_FLOW_ERROR;
1325 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1326 * metadata tag that would come later and trigger a caps change */
1327 demux->got_par = FALSE;
1330 /* Push taglist if present */
1331 if (G_UNLIKELY (demux->push_tags))
1332 gst_flv_demux_push_tags (demux);
1334 /* Check if we have anything to push */
1335 if (demux->tag_data_size <= codec_data) {
1336 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1340 /* Create buffer from pad */
1341 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1342 7 + codec_data, demux->tag_data_size - codec_data);
1344 if (demux->video_codec_tag == 7) {
1345 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1347 switch (avc_packet_type) {
1350 /* AVCDecoderConfigurationRecord data */
1351 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1352 if (demux->video_codec_data) {
1353 gst_buffer_unref (demux->video_codec_data);
1355 demux->video_codec_data = outbuf;
1356 /* Use that buffer data in the caps */
1357 gst_flv_demux_video_negotiate (demux, codec_tag);
1362 /* H.264 NALU packet */
1363 GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1366 GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1371 /* detect (and deem to be resyncs) large pts gaps */
1372 gst_flv_demux_update_resync (demux, pts, demux->video_need_discont,
1373 &demux->last_video_pts, &demux->video_time_offset);
1375 /* Fill buffer with data */
1376 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
1377 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1378 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1379 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1381 if (demux->duration == GST_CLOCK_TIME_NONE ||
1382 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1383 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1386 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1388 if (!demux->indexed && demux->index) {
1389 gst_flv_demux_parse_and_add_index_entry (demux,
1390 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1393 if (G_UNLIKELY (demux->video_need_discont)) {
1394 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1395 demux->video_need_discont = FALSE;
1398 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1400 /* Do we need a newsegment event ? */
1401 if (G_UNLIKELY (demux->video_need_segment)) {
1402 /* FIXME need one segment sent for all stream to maintain a/v sync */
1403 if (!demux->new_seg_event) {
1404 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1405 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1406 GST_TIME_ARGS (demux->segment.position),
1407 GST_TIME_ARGS (demux->segment.stop));
1408 demux->segment.start = demux->segment.time = demux->segment.position;
1409 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1411 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1414 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1416 demux->video_need_segment = FALSE;
1419 GST_LOG_OBJECT (demux,
1420 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1421 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1422 ", keyframe (%d)", gst_buffer_get_size (outbuf),
1423 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1424 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1427 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1428 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1430 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1431 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1434 if (G_UNLIKELY (!demux->no_more_pads
1435 && (GST_CLOCK_DIFF (demux->video_start,
1436 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1437 GST_DEBUG_OBJECT (demux,
1438 "Signalling no-more-pads because no audio stream was found"
1439 " after 6 seconds of video");
1440 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1441 demux->no_more_pads = TRUE;
1442 demux->push_tags = TRUE;
1445 /* Push downstream */
1446 ret = gst_pad_push (demux->video_pad, outbuf);
1448 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1449 if (demux->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
1450 demux->segment.position > demux->segment.stop) {
1451 /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
1452 * we are at the end of the segment, so we just need to jump
1453 * back to the previous section. */
1454 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1455 demux->video_done = TRUE;
1458 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1459 " bytes video buffer: %s", demux->tag_data_size,
1460 gst_flow_get_name (ret));
1461 if (ret == GST_FLOW_NOT_LINKED) {
1462 demux->video_linked = FALSE;
1468 demux->video_linked = TRUE;
1471 gst_buffer_unmap (buffer, data, -1);
1476 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1477 GstBuffer * buffer, size_t * tag_size)
1479 guint32 pts = 0, pts_ext = 0;
1480 guint32 tag_data_size;
1482 gboolean keyframe = TRUE;
1483 GstClockTime ret = GST_CLOCK_TIME_NONE;
1484 guint8 *data, *bdata;
1487 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1488 GST_CLOCK_TIME_NONE);
1490 data = bdata = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
1494 if (type != 9 && type != 8 && type != 18) {
1495 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1500 demux->has_video = TRUE;
1502 demux->has_audio = TRUE;
1504 tag_data_size = GST_READ_UINT24_BE (data + 1);
1506 if (size >= tag_data_size + 11 + 4) {
1507 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1508 GST_WARNING_OBJECT (demux, "Invalid tag size");
1514 *tag_size = tag_data_size + 11 + 4;
1518 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
1521 /* Grab timestamp of tag tag */
1522 pts = GST_READ_UINT24_BE (data);
1523 /* read the pts extension to 32 bits integer */
1524 pts_ext = GST_READ_UINT8 (data + 3);
1526 pts |= pts_ext << 24;
1531 keyframe = ((data[0] >> 4) == 1);
1534 ret = pts * GST_MSECOND;
1535 GST_LOG_OBJECT (demux, "pts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1537 if (index && demux->index && !demux->indexed && (type == 9 || (type == 8
1538 && !demux->has_video))) {
1539 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1543 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1544 demux->duration = ret;
1547 gst_buffer_unmap (buffer, bdata, -1);
1551 static GstFlowReturn
1552 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1554 GstFlowReturn ret = GST_FLOW_OK;
1555 guint8 tag_type = 0;
1558 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1560 data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_READ);
1566 demux->state = FLV_STATE_TAG_VIDEO;
1567 demux->has_video = TRUE;
1570 demux->state = FLV_STATE_TAG_AUDIO;
1571 demux->has_audio = TRUE;
1574 demux->state = FLV_STATE_TAG_SCRIPT;
1577 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1580 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1581 * 4 bytes of previous tag size */
1582 demux->tag_data_size = GST_READ_UINT24_BE (data + 1);
1583 demux->tag_size = demux->tag_data_size + 11;
1585 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1586 demux->tag_data_size);
1588 gst_buffer_unmap (buffer, data, -1);
1593 static GstFlowReturn
1594 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1596 GstFlowReturn ret = GST_FLOW_OK;
1599 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1601 data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_READ);
1603 /* Check for the FLV tag */
1604 if (data[0] == 'F' && data[1] == 'L' && data[2] == 'V') {
1605 GST_DEBUG_OBJECT (demux, "FLV header detected");
1607 if (G_UNLIKELY (demux->strict)) {
1608 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1609 ret = GST_FLOW_UNEXPECTED;
1614 /* Now look at audio/video flags */
1616 guint8 flags = data[4];
1618 demux->has_video = demux->has_audio = FALSE;
1621 GST_DEBUG_OBJECT (demux, "there is a video stream");
1622 demux->has_video = TRUE;
1625 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1626 demux->has_audio = TRUE;
1630 /* do a one-time seekability check */
1631 gst_flv_demux_check_seekability (demux);
1633 /* We don't care about the rest */
1634 demux->need_header = FALSE;
1637 gst_buffer_unmap (buffer, data, -1);
1643 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1645 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1647 gst_adapter_clear (demux->adapter);
1649 demux->audio_need_discont = TRUE;
1650 demux->video_need_discont = TRUE;
1652 demux->flushing = FALSE;
1654 /* Only in push mode and if we're not during a seek */
1655 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1656 /* After a flush we expect a tag_type */
1657 demux->state = FLV_STATE_TAG_TYPE;
1658 /* We reset the offset and will get one from first push */
1664 gst_flv_demux_cleanup (GstFlvDemux * demux)
1666 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1668 demux->state = FLV_STATE_HEADER;
1670 demux->flushing = FALSE;
1671 demux->need_header = TRUE;
1672 demux->audio_need_segment = TRUE;
1673 demux->video_need_segment = TRUE;
1674 demux->audio_need_discont = TRUE;
1675 demux->video_need_discont = TRUE;
1677 /* By default we consider them as linked */
1678 demux->audio_linked = TRUE;
1679 demux->video_linked = TRUE;
1681 demux->has_audio = FALSE;
1682 demux->has_video = FALSE;
1683 demux->push_tags = FALSE;
1684 demux->got_par = FALSE;
1686 demux->indexed = FALSE;
1687 demux->upstream_seekable = FALSE;
1688 demux->file_size = 0;
1690 demux->index_max_pos = 0;
1691 demux->index_max_time = 0;
1693 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1694 demux->last_audio_pts = demux->last_video_pts = 0;
1695 demux->audio_time_offset = demux->video_time_offset = 0;
1697 demux->no_more_pads = FALSE;
1699 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1701 demux->w = demux->h = 0;
1702 demux->framerate = 0.0;
1703 demux->par_x = demux->par_y = 1;
1704 demux->video_offset = 0;
1705 demux->audio_offset = 0;
1706 demux->offset = demux->cur_tag_offset = 0;
1707 demux->tag_size = demux->tag_data_size = 0;
1708 demux->duration = GST_CLOCK_TIME_NONE;
1710 if (demux->new_seg_event) {
1711 gst_event_unref (demux->new_seg_event);
1712 demux->new_seg_event = NULL;
1715 gst_adapter_clear (demux->adapter);
1717 if (demux->audio_codec_data) {
1718 gst_buffer_unref (demux->audio_codec_data);
1719 demux->audio_codec_data = NULL;
1722 if (demux->video_codec_data) {
1723 gst_buffer_unref (demux->video_codec_data);
1724 demux->video_codec_data = NULL;
1727 if (demux->audio_pad) {
1728 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1729 gst_object_unref (demux->audio_pad);
1730 demux->audio_pad = NULL;
1733 if (demux->video_pad) {
1734 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1735 gst_object_unref (demux->video_pad);
1736 demux->video_pad = NULL;
1740 g_array_free (demux->times, TRUE);
1741 demux->times = NULL;
1744 if (demux->filepositions) {
1745 g_array_free (demux->filepositions, TRUE);
1746 demux->filepositions = NULL;
1751 * Create and push a flushing seek event upstream
1754 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1759 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1762 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1763 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1764 GST_SEEK_TYPE_NONE, -1);
1766 res = gst_pad_push_event (demux->sinkpad, event);
1769 demux->offset = offset;
1773 static GstFlowReturn
1774 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1776 GstFlowReturn ret = GST_FLOW_OK;
1777 GstFlvDemux *demux = NULL;
1779 demux = GST_FLV_DEMUX (parent);
1781 GST_LOG_OBJECT (demux,
1782 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
1783 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
1784 GST_BUFFER_OFFSET (buffer));
1786 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1787 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1788 demux->state = FLV_STATE_HEADER;
1792 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
1793 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
1794 demux->offset = GST_BUFFER_OFFSET (buffer);
1797 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1798 GST_DEBUG_OBJECT (demux, "Discontinuity");
1799 gst_adapter_clear (demux->adapter);
1802 gst_adapter_push (demux->adapter, buffer);
1804 if (demux->seeking) {
1805 demux->state = FLV_STATE_SEEK;
1806 GST_OBJECT_LOCK (demux);
1807 demux->seeking = FALSE;
1808 GST_OBJECT_UNLOCK (demux);
1812 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1813 if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
1814 || demux->video_linked)) {
1817 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
1822 if (G_UNLIKELY (demux->flushing)) {
1823 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
1824 ret = GST_FLOW_WRONG_STATE;
1828 switch (demux->state) {
1829 case FLV_STATE_HEADER:
1831 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
1834 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
1836 ret = gst_flv_demux_parse_header (demux, buffer);
1838 gst_buffer_unref (buffer);
1839 demux->offset += FLV_HEADER_SIZE;
1841 demux->state = FLV_STATE_TAG_TYPE;
1847 case FLV_STATE_TAG_TYPE:
1849 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
1852 /* Remember the tag offset in bytes */
1853 demux->cur_tag_offset = demux->offset;
1855 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
1857 ret = gst_flv_demux_parse_tag_type (demux, buffer);
1859 gst_buffer_unref (buffer);
1860 demux->offset += FLV_TAG_TYPE_SIZE;
1862 /* last tag is not an index => no index/don't know where the index is
1863 * seek back to the beginning */
1864 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
1872 case FLV_STATE_TAG_VIDEO:
1874 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1877 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1879 ret = gst_flv_demux_parse_tag_video (demux, buffer);
1881 gst_buffer_unref (buffer);
1882 demux->offset += demux->tag_size;
1884 demux->state = FLV_STATE_TAG_TYPE;
1890 case FLV_STATE_TAG_AUDIO:
1892 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1895 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1897 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
1899 gst_buffer_unref (buffer);
1900 demux->offset += demux->tag_size;
1902 demux->state = FLV_STATE_TAG_TYPE;
1908 case FLV_STATE_TAG_SCRIPT:
1910 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1913 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1915 ret = gst_flv_demux_parse_tag_script (demux, buffer);
1917 gst_buffer_unref (buffer);
1918 demux->offset += demux->tag_size;
1920 demux->state = FLV_STATE_TAG_TYPE;
1922 /* if there's a seek event we're here for the index so if we don't have it
1923 * we seek back to the beginning */
1924 if (demux->seek_event) {
1926 demux->state = FLV_STATE_SEEK;
1936 case FLV_STATE_SEEK:
1942 if (!demux->indexed) {
1943 if (demux->offset == demux->file_size - sizeof (guint32)) {
1944 guint64 seek_offset;
1947 data = gst_adapter_take (demux->adapter, 4);
1951 seek_offset = demux->file_size - sizeof (guint32) -
1952 GST_READ_UINT32_BE (data);
1955 GST_INFO_OBJECT (demux,
1956 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
1958 demux->state = FLV_STATE_TAG_TYPE;
1959 flv_demux_seek_to_offset (demux, seek_offset);
1965 GST_OBJECT_LOCK (demux);
1966 event = demux->seek_event;
1967 demux->seek_event = NULL;
1968 GST_OBJECT_UNLOCK (demux);
1970 /* calculate and perform seek */
1971 if (!flv_demux_handle_seek_push (demux, event))
1974 gst_event_unref (event);
1975 demux->state = FLV_STATE_TAG_TYPE;
1979 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
1983 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
1984 /* If either audio or video is linked we return GST_FLOW_OK */
1985 if (demux->audio_linked || demux->video_linked) {
1995 GST_OBJECT_LOCK (demux);
1996 demux->seeking = FALSE;
1997 gst_event_unref (demux->seek_event);
1998 demux->seek_event = NULL;
1999 GST_OBJECT_UNLOCK (demux);
2000 GST_WARNING_OBJECT (demux,
2001 "failed to find an index, seeking back to beginning");
2002 flv_demux_seek_to_offset (demux, 0);
2007 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2008 return GST_FLOW_ERROR;
2013 static GstFlowReturn
2014 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2015 guint size, GstBuffer ** buffer)
2019 ret = gst_pad_pull_range (pad, offset, size, buffer);
2020 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2021 GST_WARNING_OBJECT (demux,
2022 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2023 size, offset, gst_flow_get_name (ret));
2028 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2029 GST_WARNING_OBJECT (demux,
2030 "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
2031 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
2032 gst_buffer_unref (*buffer);
2033 ret = GST_FLOW_UNEXPECTED;
2041 static GstFlowReturn
2042 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2044 GstBuffer *buffer = NULL;
2045 GstFlowReturn ret = GST_FLOW_OK;
2047 /* Store tag offset */
2048 demux->cur_tag_offset = demux->offset;
2050 /* Get the first 4 bytes to identify tag type and size */
2051 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2052 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2055 /* Identify tag type */
2056 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2058 gst_buffer_unref (buffer);
2060 if (G_UNLIKELY (ret != GST_FLOW_OK))
2063 /* Jump over tag type + size */
2064 demux->offset += FLV_TAG_TYPE_SIZE;
2066 /* Pull the whole tag */
2067 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2068 demux->tag_size, &buffer)) != GST_FLOW_OK))
2071 switch (demux->state) {
2072 case FLV_STATE_TAG_VIDEO:
2073 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2075 case FLV_STATE_TAG_AUDIO:
2076 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2078 case FLV_STATE_TAG_SCRIPT:
2079 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2082 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2085 gst_buffer_unref (buffer);
2087 /* Jump over that part we've just parsed */
2088 demux->offset += demux->tag_size;
2090 /* Make sure we reinitialize the tag size */
2091 demux->tag_size = 0;
2093 /* Ready for the next tag */
2094 demux->state = FLV_STATE_TAG_TYPE;
2096 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2097 /* If either audio or video is linked we return GST_FLOW_OK */
2098 if (demux->audio_linked || demux->video_linked) {
2101 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2102 "neither video nor audio are linked");
2110 static GstFlowReturn
2111 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2113 GstBuffer *buffer = NULL;
2114 GstFlowReturn ret = GST_FLOW_OK;
2116 /* Get the first 9 bytes */
2117 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2118 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2121 ret = gst_flv_demux_parse_header (demux, buffer);
2123 gst_buffer_unref (buffer);
2125 /* Jump over the header now */
2126 demux->offset += FLV_HEADER_SIZE;
2127 demux->state = FLV_STATE_TAG_TYPE;
2134 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2137 demux->offset = offset;
2139 /* Tell all the stream we moved to a different position (discont) */
2140 demux->audio_need_discont = TRUE;
2141 demux->video_need_discont = TRUE;
2143 /* next section setup */
2144 demux->from_offset = -1;
2145 demux->audio_done = demux->video_done = FALSE;
2146 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2149 demux->from_offset = -1;
2150 demux->to_offset = G_MAXINT64;
2153 /* If we seeked at the beginning of the file parse the header again */
2154 if (G_UNLIKELY (!demux->offset)) {
2155 demux->state = FLV_STATE_HEADER;
2156 } else { /* or parse a tag */
2157 demux->state = FLV_STATE_TAG_TYPE;
2161 static GstFlowReturn
2162 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2164 GstFlowReturn ret = GST_FLOW_UNEXPECTED;
2165 GstIndexEntry *entry = NULL;
2167 GST_DEBUG_OBJECT (demux,
2168 "terminated section started at offset %" G_GINT64_FORMAT,
2169 demux->from_offset);
2171 /* we are done if we got all audio and video */
2172 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2173 demux->audio_first_ts < demux->segment.start) &&
2174 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2175 demux->video_first_ts < demux->segment.start))
2178 if (demux->from_offset <= 0)
2181 GST_DEBUG_OBJECT (demux, "locating previous position");
2183 /* locate index entry before previous start position */
2185 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2186 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2187 GST_FORMAT_BYTES, demux->from_offset - 1);
2192 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2193 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2195 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2196 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2197 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2199 /* setup for next section */
2200 demux->to_offset = demux->from_offset;
2201 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2209 static GstFlowReturn
2210 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2216 GstClockTime tag_time;
2217 GstFlowReturn ret = GST_FLOW_OK;
2219 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2222 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2223 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2225 old_offset = demux->offset;
2226 demux->offset = pos;
2228 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2229 12, &buffer)) == GST_FLOW_OK) {
2231 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2233 gst_buffer_unref (buffer);
2235 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2238 demux->offset += tag_size;
2241 if (ret == GST_FLOW_UNEXPECTED) {
2242 /* file ran out, so mark we have complete index */
2243 demux->indexed = TRUE;
2248 demux->offset = old_offset;
2254 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2256 gint64 ret = 0, offset;
2257 size_t tag_size, size;
2258 GstBuffer *buffer = NULL;
2261 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2265 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2266 if (G_UNLIKELY (offset < 4))
2270 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2274 data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_READ);
2275 tag_size = GST_READ_UINT32_BE (data);
2276 gst_buffer_unmap (buffer, data, -1);
2277 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2278 gst_buffer_unref (buffer);
2282 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2286 /* a consistency check */
2287 data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_READ);
2288 size = GST_READ_UINT24_BE (data + 1);
2289 if (size != tag_size - 11) {
2290 gst_buffer_unmap (buffer, data, -1);
2291 GST_DEBUG_OBJECT (demux,
2292 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2293 ", corrupt or truncated file", size, tag_size - 11);
2297 /* try to update duration with timestamp in any case */
2298 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2300 /* maybe get some more metadata */
2301 if (data[0] == 18) {
2302 gst_buffer_unmap (buffer, data, -1);
2303 gst_buffer_unref (buffer);
2305 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2307 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2309 gst_flv_demux_parse_tag_script (demux, buffer);
2311 gst_buffer_unmap (buffer, data, -1);
2316 gst_buffer_unref (buffer);
2322 gst_flv_demux_loop (GstPad * pad)
2324 GstFlvDemux *demux = NULL;
2325 GstFlowReturn ret = GST_FLOW_OK;
2327 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2330 switch (demux->state) {
2331 case FLV_STATE_TAG_TYPE:
2332 if (demux->from_offset == -1)
2333 demux->from_offset = demux->offset;
2334 ret = gst_flv_demux_pull_tag (pad, demux);
2335 /* if we have seen real data, we probably passed a possible metadata
2336 * header located at start. So if we do not yet have an index,
2337 * try to pick up metadata (index, duration) at the end */
2338 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2339 (demux->has_video || demux->has_audio)))
2340 demux->file_size = gst_flv_demux_get_metadata (demux);
2342 case FLV_STATE_DONE:
2343 ret = GST_FLOW_UNEXPECTED;
2345 case FLV_STATE_SEEK:
2346 /* seek issued with insufficient index;
2347 * scan for index in task thread from current maximum offset to
2348 * desired time and then perform seek */
2349 /* TODO maybe some buffering message or so to indicate scan progress */
2350 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2352 if (ret != GST_FLOW_OK)
2354 /* position and state arranged by seek,
2355 * also unrefs event */
2356 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2357 demux->seek_event = NULL;
2360 ret = gst_flv_demux_pull_header (pad, demux);
2361 /* index scans start after header */
2362 demux->index_max_pos = demux->offset;
2366 if (demux->segment.rate < 0.0) {
2367 /* check end of section */
2368 if ((gint64) demux->offset >= demux->to_offset ||
2369 demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2370 (demux->audio_done && demux->video_done))
2371 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2373 /* check EOS condition */
2374 if ((demux->segment.stop != -1) &&
2375 (demux->segment.position >= demux->segment.stop)) {
2376 ret = GST_FLOW_UNEXPECTED;
2380 /* pause if something went wrong or at end */
2381 if (G_UNLIKELY (ret != GST_FLOW_OK))
2384 gst_object_unref (demux);
2390 const gchar *reason = gst_flow_get_name (ret);
2392 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2393 gst_pad_pause_task (pad);
2395 if (ret == GST_FLOW_UNEXPECTED) {
2396 /* handle end-of-stream/segment */
2397 /* so align our position with the end of it, if there is one
2398 * this ensures a subsequent will arrive at correct base/acc time */
2399 if (demux->segment.rate > 0.0 &&
2400 GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2401 demux->segment.position = demux->segment.stop;
2402 else if (demux->segment.rate < 0.0)
2403 demux->segment.position = demux->segment.start;
2405 /* perform EOS logic */
2406 if (!demux->no_more_pads) {
2407 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2408 demux->no_more_pads = TRUE;
2411 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2414 /* for segment playback we need to post when (in stream time)
2415 * we stopped, this is either stop (when set) or the duration. */
2416 if ((stop = demux->segment.stop) == -1)
2417 stop = demux->segment.duration;
2419 if (demux->segment.rate >= 0) {
2420 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2421 gst_element_post_message (GST_ELEMENT_CAST (demux),
2422 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2423 GST_FORMAT_TIME, stop));
2424 } else { /* Reverse playback */
2425 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2427 gst_element_post_message (GST_ELEMENT_CAST (demux),
2428 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2429 GST_FORMAT_TIME, demux->segment.start));
2432 /* normal playback, send EOS to all linked pads */
2433 if (!demux->no_more_pads) {
2434 gst_element_no_more_pads (GST_ELEMENT (demux));
2435 demux->no_more_pads = TRUE;
2438 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2439 if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2440 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2442 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
2443 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2444 ("Internal data stream error."),
2445 ("stream stopped, reason %s", reason));
2446 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2448 gst_object_unref (demux);
2454 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2458 GstIndexEntry *entry;
2460 g_return_val_if_fail (segment != NULL, 0);
2462 time = segment->position;
2465 /* Let's check if we have an index entry for that seek time */
2466 entry = gst_index_get_assoc_entry (demux->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->position), 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->position = time;
2487 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2488 GST_TIME_ARGS (segment->start));
2496 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2500 GstSeekType start_type, stop_type;
2503 gboolean update, flush, ret;
2504 GstSegment seeksegment;
2506 gst_event_parse_seek (event, &rate, &format, &flags,
2507 &start_type, &start, &stop_type, &stop);
2509 if (format != GST_FORMAT_TIME)
2512 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2513 /* FIXME : the keyframe flag is never used ! */
2515 /* Work on a copy until we are sure the seek succeeded. */
2516 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2518 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2521 /* Apply the seek to our segment */
2522 gst_segment_do_seek (&seeksegment, rate, format, flags,
2523 start_type, start, stop_type, stop, &update);
2525 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2528 if (flush || seeksegment.position != demux->segment.position) {
2529 /* Do the actual seeking */
2530 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2532 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2533 G_GUINT64_FORMAT, offset);
2534 ret = gst_pad_push_event (demux->sinkpad,
2535 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2536 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2537 offset, GST_SEEK_TYPE_NONE, 0));
2538 if (G_UNLIKELY (!ret)) {
2539 GST_WARNING_OBJECT (demux, "upstream seek failed");
2542 /* Tell all the stream we moved to a different position (discont) */
2543 demux->audio_need_discont = TRUE;
2544 demux->video_need_discont = TRUE;
2550 /* Ok seek succeeded, take the newly configured segment */
2551 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2553 /* Tell all the stream a new segment is needed */
2554 demux->audio_need_segment = TRUE;
2555 demux->video_need_segment = TRUE;
2556 /* Clean any potential newsegment event kept for the streams. The first
2557 * stream needing a new segment will create a new one. */
2558 if (G_UNLIKELY (demux->new_seg_event)) {
2559 gst_event_unref (demux->new_seg_event);
2560 demux->new_seg_event = NULL;
2562 gst_event_unref (event);
2564 ret = gst_pad_push_event (demux->sinkpad, event);
2572 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2573 gst_event_unref (event);
2579 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2583 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2585 if (format != GST_FORMAT_TIME) {
2586 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2587 gst_event_unref (event);
2591 /* First try upstream */
2592 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2593 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2594 gst_event_unref (event);
2598 if (!demux->indexed) {
2599 guint64 seek_offset = 0;
2600 gboolean building_index;
2602 GST_OBJECT_LOCK (demux);
2603 /* handle the seek in the chain function */
2604 demux->seeking = TRUE;
2605 demux->state = FLV_STATE_SEEK;
2607 /* copy the event */
2608 if (demux->seek_event)
2609 gst_event_unref (demux->seek_event);
2610 demux->seek_event = gst_event_ref (event);
2612 /* set the building_index flag so that only one thread can setup the
2613 * structures for index seeking. */
2614 building_index = demux->building_index;
2615 if (!building_index) {
2616 demux->building_index = TRUE;
2617 if (!demux->file_size
2618 && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2619 &demux->file_size)) {
2620 GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2621 GST_OBJECT_UNLOCK (demux);
2625 /* we hope the last tag is a scriptdataobject containing an index
2626 * the size of the last tag is given in the last guint32 bits
2627 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2628 seek_offset = demux->file_size - sizeof (guint32);
2629 GST_DEBUG_OBJECT (demux,
2630 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2632 GST_OBJECT_UNLOCK (demux);
2634 if (!building_index) {
2635 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2637 return flv_demux_seek_to_offset (demux, seek_offset);
2640 /* FIXME: we have to always return true so that we don't block the seek
2642 * Note: maybe it is OK to return true if we're still building the index */
2646 return flv_demux_handle_seek_push (demux, event);
2650 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2655 GstSeekType start_type, stop_type;
2658 gboolean update, flush, ret = FALSE;
2659 GstSegment seeksegment;
2661 gst_event_parse_seek (event, &rate, &format, &flags,
2662 &start_type, &start, &stop_type, &stop);
2664 if (format != GST_FORMAT_TIME)
2667 /* mark seeking thread entering flushing/pausing */
2668 GST_OBJECT_LOCK (demux);
2670 demux->seeking = seeking;
2671 GST_OBJECT_UNLOCK (demux);
2673 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2674 /* FIXME : the keyframe flag is never used */
2677 /* Flush start up and downstream to make sure data flow and loops are
2679 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2680 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2682 /* Pause the pulling task */
2683 gst_pad_pause_task (demux->sinkpad);
2686 /* Take the stream lock */
2687 GST_PAD_STREAM_LOCK (demux->sinkpad);
2690 /* Stop flushing upstream we need to pull */
2691 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2694 /* Work on a copy until we are sure the seek succeeded. */
2695 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2697 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2700 /* Apply the seek to our segment */
2701 gst_segment_do_seek (&seeksegment, rate, format, flags,
2702 start_type, start, stop_type, stop, &update);
2704 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2707 if (flush || seeksegment.position != demux->segment.position) {
2708 /* Do the actual seeking */
2709 /* index is reliable if it is complete or we do not go to far ahead */
2710 if (seeking && !demux->indexed &&
2711 seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2712 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2713 " index only up to %" GST_TIME_FORMAT,
2714 GST_TIME_ARGS (demux->index_max_time));
2715 /* stop flushing for now */
2717 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2718 /* delegate scanning and index building to task thread to avoid
2719 * occupying main (UI) loop */
2720 if (demux->seek_event)
2721 gst_event_unref (demux->seek_event);
2722 demux->seek_event = gst_event_ref (event);
2723 demux->seek_time = seeksegment.position;
2724 demux->state = FLV_STATE_SEEK;
2725 /* do not know about succes yet, but we did care and handled it */
2729 /* now index should be as reliable as it can be for current purpose */
2730 gst_flv_demux_move_to_offset (demux,
2731 gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2738 /* Stop flushing, the sinks are at time 0 now */
2739 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2743 /* Ok seek succeeded, take the newly configured segment */
2744 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2746 /* Notify about the start of a new segment */
2747 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2748 gst_element_post_message (GST_ELEMENT (demux),
2749 gst_message_new_segment_start (GST_OBJECT (demux),
2750 demux->segment.format, demux->segment.position));
2753 /* Tell all the stream a new segment is needed */
2754 demux->audio_need_segment = TRUE;
2755 demux->video_need_segment = TRUE;
2756 /* Clean any potential newsegment event kept for the streams. The first
2757 * stream needing a new segment will create a new one. */
2758 if (G_UNLIKELY (demux->new_seg_event)) {
2759 gst_event_unref (demux->new_seg_event);
2760 demux->new_seg_event = NULL;
2762 if (demux->segment.rate < 0.0) {
2763 /* we can't generate a segment by locking on
2764 * to the first timestamp we see */
2765 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2766 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2767 GST_TIME_ARGS (demux->segment.start),
2768 GST_TIME_ARGS (demux->segment.stop));
2769 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2774 GST_OBJECT_LOCK (demux);
2775 seeking = demux->seeking && !seeking;
2776 demux->seeking = FALSE;
2777 GST_OBJECT_UNLOCK (demux);
2779 /* if we detect an external seek having started (and possibly already having
2780 * flushed), do not restart task to give it a chance.
2781 * Otherwise external one's flushing will take care to pause task */
2783 gst_pad_pause_task (demux->sinkpad);
2785 gst_pad_start_task (demux->sinkpad,
2786 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
2789 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2791 gst_event_unref (event);
2797 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2798 gst_event_unref (event);
2803 /* If we can pull that's prefered */
2805 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
2810 query = gst_query_new_scheduling ();
2812 if (!gst_pad_peer_query (sinkpad, query)) {
2813 gst_query_unref (query);
2817 pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
2818 gst_query_unref (query);
2823 GST_DEBUG_OBJECT (sinkpad, "activating pull");
2824 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
2828 GST_DEBUG_OBJECT (sinkpad, "activating push");
2829 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
2834 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
2835 GstPadMode mode, gboolean active)
2840 demux = GST_FLV_DEMUX (parent);
2843 case GST_PAD_MODE_PUSH:
2844 demux->random_access = FALSE;
2847 case GST_PAD_MODE_PULL:
2849 demux->random_access = TRUE;
2850 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
2853 demux->random_access = FALSE;
2854 res = gst_pad_stop_task (sinkpad);
2865 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
2868 gboolean ret = FALSE;
2870 demux = GST_FLV_DEMUX (parent);
2872 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2874 switch (GST_EVENT_TYPE (event)) {
2875 case GST_EVENT_FLUSH_START:
2876 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
2877 demux->flushing = TRUE;
2878 ret = gst_flv_demux_push_src_event (demux, event);
2880 case GST_EVENT_FLUSH_STOP:
2881 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
2882 gst_flv_demux_flush (demux, TRUE);
2883 ret = gst_flv_demux_push_src_event (demux, event);
2886 GST_DEBUG_OBJECT (demux, "received EOS");
2888 GST_DEBUG_OBJECT (demux, "committing index");
2889 gst_index_commit (demux->index, demux->index_id);
2891 if (!demux->no_more_pads) {
2892 gst_element_no_more_pads (GST_ELEMENT (demux));
2893 demux->no_more_pads = TRUE;
2896 if (!gst_flv_demux_push_src_event (demux, event))
2897 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2900 case GST_EVENT_SEGMENT:
2902 GstSegment in_segment;
2904 GST_DEBUG_OBJECT (demux, "received new segment");
2906 gst_event_copy_segment (event, &in_segment);
2908 if (in_segment.format == GST_FORMAT_TIME) {
2909 /* time segment, this is perfect, copy over the values. */
2910 memcpy (&demux->segment, &in_segment, sizeof (in_segment));
2912 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
2916 ret = gst_flv_demux_push_src_event (demux, event);
2918 /* non-time format */
2919 demux->audio_need_segment = TRUE;
2920 demux->video_need_segment = TRUE;
2922 gst_event_unref (event);
2927 ret = gst_flv_demux_push_src_event (demux, event);
2935 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
2938 gboolean ret = FALSE;
2940 demux = GST_FLV_DEMUX (parent);
2942 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2944 switch (GST_EVENT_TYPE (event)) {
2945 case GST_EVENT_SEEK:
2946 if (demux->random_access) {
2947 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
2949 ret = gst_flv_demux_handle_seek_push (demux, event);
2953 ret = gst_pad_push_event (demux->sinkpad, event);
2961 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
2963 gboolean res = TRUE;
2966 demux = GST_FLV_DEMUX (parent);
2968 switch (GST_QUERY_TYPE (query)) {
2969 case GST_QUERY_DURATION:
2973 gst_query_parse_duration (query, &format, NULL);
2975 /* duration is time only */
2976 if (format != GST_FORMAT_TIME) {
2977 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
2983 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
2984 GST_TIME_ARGS (demux->duration));
2986 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
2990 case GST_QUERY_POSITION:
2994 gst_query_parse_position (query, &format, NULL);
2996 /* position is time only */
2997 if (format != GST_FORMAT_TIME) {
2998 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3004 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3005 GST_TIME_ARGS (demux->segment.position));
3007 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3012 case GST_QUERY_SEEKING:{
3015 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3017 /* First ask upstream */
3018 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3021 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3028 if (fmt != GST_FORMAT_TIME || !demux->index) {
3029 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3030 } else if (demux->random_access) {
3031 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3034 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3035 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3038 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3039 gst_query_unref (peerquery);
3042 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3045 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3049 case GST_QUERY_LATENCY:
3051 res = gst_pad_peer_query (demux->sinkpad, query);
3060 static GstStateChangeReturn
3061 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3064 GstStateChangeReturn ret;
3066 demux = GST_FLV_DEMUX (element);
3068 switch (transition) {
3069 case GST_STATE_CHANGE_READY_TO_PAUSED:
3070 /* If this is our own index destroy it as the
3071 * old entries might be wrong for the new stream */
3072 if (demux->own_index) {
3073 gst_object_unref (demux->index);
3074 demux->index = NULL;
3075 demux->own_index = FALSE;
3078 /* If no index was created, generate one */
3079 if (G_UNLIKELY (!demux->index)) {
3080 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3082 demux->index = gst_index_factory_make ("memindex");
3084 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3086 demux->own_index = TRUE;
3088 gst_flv_demux_cleanup (demux);
3094 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3095 if (ret == GST_STATE_CHANGE_FAILURE)
3098 switch (transition) {
3099 case GST_STATE_CHANGE_PAUSED_TO_READY:
3100 gst_flv_demux_cleanup (demux);
3110 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3112 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3114 GST_OBJECT_LOCK (demux);
3116 gst_object_unref (demux->index);
3118 demux->index = gst_object_ref (index);
3119 demux->own_index = FALSE;
3121 demux->index = NULL;
3123 GST_OBJECT_UNLOCK (demux);
3124 /* object lock might be taken again */
3126 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3127 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3132 gst_flv_demux_get_index (GstElement * element)
3134 GstIndex *result = NULL;
3136 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3138 GST_OBJECT_LOCK (demux);
3140 result = gst_object_ref (demux->index);
3141 GST_OBJECT_UNLOCK (demux);
3147 gst_flv_demux_dispose (GObject * object)
3149 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3151 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3153 if (demux->adapter) {
3154 gst_adapter_clear (demux->adapter);
3155 g_object_unref (demux->adapter);
3156 demux->adapter = NULL;
3159 if (demux->taglist) {
3160 gst_tag_list_free (demux->taglist);
3161 demux->taglist = NULL;
3164 if (demux->new_seg_event) {
3165 gst_event_unref (demux->new_seg_event);
3166 demux->new_seg_event = NULL;
3169 if (demux->audio_codec_data) {
3170 gst_buffer_unref (demux->audio_codec_data);
3171 demux->audio_codec_data = NULL;
3174 if (demux->video_codec_data) {
3175 gst_buffer_unref (demux->video_codec_data);
3176 demux->video_codec_data = NULL;
3179 if (demux->audio_pad) {
3180 gst_object_unref (demux->audio_pad);
3181 demux->audio_pad = NULL;
3184 if (demux->video_pad) {
3185 gst_object_unref (demux->video_pad);
3186 demux->video_pad = NULL;
3190 gst_object_unref (demux->index);
3191 demux->index = NULL;
3195 g_array_free (demux->times, TRUE);
3196 demux->times = NULL;
3199 if (demux->filepositions) {
3200 g_array_free (demux->filepositions, TRUE);
3201 demux->filepositions = NULL;
3204 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3208 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3210 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3211 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3213 gobject_class->dispose = gst_flv_demux_dispose;
3215 gstelement_class->change_state =
3216 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3217 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3218 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3220 gst_element_class_add_pad_template (gstelement_class,
3221 gst_static_pad_template_get (&flv_sink_template));
3222 gst_element_class_add_pad_template (gstelement_class,
3223 gst_static_pad_template_get (&audio_src_template));
3224 gst_element_class_add_pad_template (gstelement_class,
3225 gst_static_pad_template_get (&video_src_template));
3226 gst_element_class_set_details_simple (gstelement_class, "FLV Demuxer",
3228 "Demux FLV feeds into digital streams",
3229 "Julien Moutte <julien@moutte.net>");
3233 gst_flv_demux_init (GstFlvDemux * demux)
3236 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3238 gst_pad_set_event_function (demux->sinkpad,
3239 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3240 gst_pad_set_chain_function (demux->sinkpad,
3241 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3242 gst_pad_set_activate_function (demux->sinkpad,
3243 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3244 gst_pad_set_activatemode_function (demux->sinkpad,
3245 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3247 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3249 demux->adapter = gst_adapter_new ();
3250 demux->taglist = gst_tag_list_new_empty ();
3251 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3253 demux->own_index = FALSE;
3255 GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3257 gst_flv_demux_cleanup (demux);
3261 plugin_init (GstPlugin * plugin)
3263 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3265 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3266 gst_flv_demux_get_type ()) ||
3267 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3268 gst_flv_mux_get_type ()))
3274 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3275 "flv", "FLV muxing and demuxing plugin",
3276 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)