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, guint32 * last,
785 GstClockTime * offset)
787 if (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 (%d)",
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->last_audio_pts,
996 &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, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
1042 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1043 gst_buffer_get_size (outbuf),
1044 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1045 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1047 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1048 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1050 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1051 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1054 if (G_UNLIKELY (!demux->no_more_pads
1055 && (GST_CLOCK_DIFF (demux->audio_start,
1056 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1057 GST_DEBUG_OBJECT (demux,
1058 "Signalling no-more-pads because no video stream was found"
1059 " after 6 seconds of audio");
1060 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1061 demux->no_more_pads = TRUE;
1062 demux->push_tags = TRUE;
1065 /* Push downstream */
1066 ret = gst_pad_push (demux->audio_pad, outbuf);
1067 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1068 if (demux->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
1069 demux->segment.position > demux->segment.stop) {
1070 /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
1071 * we are at the end of the segment, so we just need to jump
1072 * back to the previous section. */
1073 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1074 demux->audio_done = TRUE;
1077 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1078 " bytes audio buffer: %s", demux->tag_data_size,
1079 gst_flow_get_name (ret));
1080 if (ret == GST_FLOW_NOT_LINKED) {
1081 demux->audio_linked = FALSE;
1087 demux->audio_linked = TRUE;
1090 gst_buffer_unmap (buffer, data, -1);
1096 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1098 gboolean ret = FALSE;
1099 GstCaps *caps = NULL;
1100 gchar *codec_name = NULL;
1102 /* Generate caps for that pad */
1103 switch (codec_tag) {
1105 caps = gst_caps_new_empty_simple ("video/x-flash-video");
1108 caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1111 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1114 caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1118 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1122 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1125 if (G_UNLIKELY (!caps)) {
1126 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1130 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1131 demux->par_x, demux->par_y, NULL);
1133 if (G_LIKELY (demux->w)) {
1134 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1137 if (G_LIKELY (demux->h)) {
1138 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1141 if (G_LIKELY (demux->framerate)) {
1142 gint num = 0, den = 0;
1144 gst_util_double_to_fraction (demux->framerate, &num, &den);
1145 GST_DEBUG_OBJECT (demux->video_pad,
1146 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1149 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1152 if (demux->video_codec_data) {
1153 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1154 demux->video_codec_data, NULL);
1157 ret = gst_pad_set_caps (demux->video_pad, caps);
1159 if (G_LIKELY (ret)) {
1160 /* Store the caps we have set */
1161 demux->video_codec_tag = codec_tag;
1163 codec_name = gst_pb_utils_get_codec_description (caps);
1166 if (demux->taglist == NULL)
1167 demux->taglist = gst_tag_list_new_empty ();
1168 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1169 GST_TAG_VIDEO_CODEC, codec_name, NULL);
1170 g_free (codec_name);
1173 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1174 GST_PTR_FORMAT, caps);
1176 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1177 GST_PTR_FORMAT, caps);
1180 gst_caps_unref (caps);
1186 static GstFlowReturn
1187 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1189 GstFlowReturn ret = GST_FLOW_OK;
1190 guint32 pts = 0, codec_data = 1, pts_ext = 0;
1191 gboolean keyframe = FALSE;
1192 guint8 flags = 0, codec_tag = 0;
1197 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1200 GST_LOG_OBJECT (demux, "parsing a video tag");
1202 if (demux->no_more_pads && !demux->video_pad) {
1203 GST_WARNING_OBJECT (demux,
1204 "Signaled no-more-pads already but had no audio pad -- ignoring");
1208 if (gst_buffer_get_size (buffer) < 12) {
1209 GST_ERROR_OBJECT (demux, "Too small tag size");
1210 return GST_FLOW_ERROR;
1213 data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
1215 /* Grab information about video tag */
1216 pts = GST_READ_UINT24_BE (data);
1217 /* read the pts extension to 32 bits integer */
1218 pts_ext = GST_READ_UINT8 (data + 3);
1220 pts |= pts_ext << 24;
1222 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1223 data[2], data[3], pts);
1225 /* Skip the stream id and go directly to the flags */
1226 flags = GST_READ_UINT8 (data + 7);
1229 if ((flags >> 4) == 1) {
1233 codec_tag = flags & 0x0F;
1234 if (codec_tag == 4 || codec_tag == 5) {
1236 } else if (codec_tag == 7) {
1241 cts = GST_READ_UINT24_BE (data + 9);
1242 cts = (cts + 0xff800000) ^ 0xff800000;
1244 GST_LOG_OBJECT (demux, "got cts %d", cts);
1246 /* avoid negative overflow */
1247 if (cts >= 0 || pts >= -cts)
1251 GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1252 "(flags %02X)", codec_tag, keyframe, flags);
1254 /* If we don't have our video pad created, then create it. */
1255 if (G_UNLIKELY (!demux->video_pad)) {
1257 gst_pad_new_from_template (gst_element_class_get_pad_template
1258 (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1259 if (G_UNLIKELY (!demux->video_pad)) {
1260 GST_WARNING_OBJECT (demux, "failed creating video pad");
1261 ret = GST_FLOW_ERROR;
1265 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1266 gst_object_unref (demux->video_pad);
1267 demux->video_pad = NULL;
1268 ret = GST_FLOW_ERROR;
1272 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1273 * metadata tag that would come later and trigger a caps change */
1274 demux->got_par = FALSE;
1276 #ifndef GST_DISABLE_GST_DEBUG
1280 caps = gst_pad_get_current_caps (demux->video_pad);
1281 GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1284 gst_caps_unref (caps);
1288 /* Set functions on the pad */
1289 gst_pad_set_query_function (demux->video_pad,
1290 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1291 gst_pad_set_event_function (demux->video_pad,
1292 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1294 gst_pad_use_fixed_caps (demux->video_pad);
1296 /* Make it active */
1297 gst_pad_set_active (demux->video_pad, TRUE);
1299 /* We need to set caps before adding */
1300 gst_element_add_pad (GST_ELEMENT (demux),
1301 gst_object_ref (demux->video_pad));
1303 /* We only emit no more pads when we have audio and video. Indeed we can
1304 * not trust the FLV header to tell us if there will be only audio or
1305 * only video and we would just break discovery of some files */
1306 if (demux->audio_pad && demux->video_pad) {
1307 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1308 gst_element_no_more_pads (GST_ELEMENT (demux));
1309 demux->no_more_pads = TRUE;
1310 demux->push_tags = TRUE;
1314 /* Check if caps have changed */
1315 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1317 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1319 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1320 ret = GST_FLOW_ERROR;
1324 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1325 * metadata tag that would come later and trigger a caps change */
1326 demux->got_par = FALSE;
1329 /* Push taglist if present */
1330 if (G_UNLIKELY (demux->push_tags))
1331 gst_flv_demux_push_tags (demux);
1333 /* Check if we have anything to push */
1334 if (demux->tag_data_size <= codec_data) {
1335 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1339 /* Create buffer from pad */
1340 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1341 7 + codec_data, demux->tag_data_size - codec_data);
1343 if (demux->video_codec_tag == 7) {
1344 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1346 switch (avc_packet_type) {
1349 /* AVCDecoderConfigurationRecord data */
1350 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1351 if (demux->video_codec_data) {
1352 gst_buffer_unref (demux->video_codec_data);
1354 demux->video_codec_data = outbuf;
1355 /* Use that buffer data in the caps */
1356 gst_flv_demux_video_negotiate (demux, codec_tag);
1361 /* H.264 NALU packet */
1362 GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1365 GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1370 /* detect (and deem to be resyncs) large pts gaps */
1371 gst_flv_demux_update_resync (demux, pts, &demux->last_video_pts,
1372 &demux->video_time_offset);
1374 /* Fill buffer with data */
1375 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
1376 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1377 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1378 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1380 if (demux->duration == GST_CLOCK_TIME_NONE ||
1381 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1382 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1385 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1387 if (!demux->indexed && demux->index) {
1388 gst_flv_demux_parse_and_add_index_entry (demux,
1389 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1392 if (G_UNLIKELY (demux->video_need_discont)) {
1393 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1394 demux->video_need_discont = FALSE;
1397 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1399 /* Do we need a newsegment event ? */
1400 if (G_UNLIKELY (demux->video_need_segment)) {
1401 /* FIXME need one segment sent for all stream to maintain a/v sync */
1402 if (!demux->new_seg_event) {
1403 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1404 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1405 GST_TIME_ARGS (demux->segment.position),
1406 GST_TIME_ARGS (demux->segment.stop));
1407 demux->segment.start = demux->segment.time = demux->segment.position;
1408 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1410 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1413 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1415 demux->video_need_segment = FALSE;
1418 GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
1419 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1420 ", keyframe (%d)", gst_buffer_get_size (outbuf),
1421 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1422 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1425 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1426 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1428 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1429 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1432 if (G_UNLIKELY (!demux->no_more_pads
1433 && (GST_CLOCK_DIFF (demux->video_start,
1434 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1435 GST_DEBUG_OBJECT (demux,
1436 "Signalling no-more-pads because no audio stream was found"
1437 " after 6 seconds of video");
1438 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1439 demux->no_more_pads = TRUE;
1440 demux->push_tags = TRUE;
1443 /* Push downstream */
1444 ret = gst_pad_push (demux->video_pad, outbuf);
1446 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1447 if (demux->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
1448 demux->segment.position > demux->segment.stop) {
1449 /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
1450 * we are at the end of the segment, so we just need to jump
1451 * back to the previous section. */
1452 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1453 demux->video_done = TRUE;
1456 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1457 " bytes video buffer: %s", demux->tag_data_size,
1458 gst_flow_get_name (ret));
1459 if (ret == GST_FLOW_NOT_LINKED) {
1460 demux->video_linked = FALSE;
1466 demux->video_linked = TRUE;
1469 gst_buffer_unmap (buffer, data, -1);
1474 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1475 GstBuffer * buffer, size_t * tag_size)
1477 guint32 pts = 0, pts_ext = 0;
1478 guint32 tag_data_size;
1480 gboolean keyframe = TRUE;
1481 GstClockTime ret = GST_CLOCK_TIME_NONE;
1482 guint8 *data, *bdata;
1485 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1486 GST_CLOCK_TIME_NONE);
1488 data = bdata = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
1492 if (type != 9 && type != 8 && type != 18) {
1493 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1498 demux->has_video = TRUE;
1500 demux->has_audio = TRUE;
1502 tag_data_size = GST_READ_UINT24_BE (data + 1);
1504 if (size >= tag_data_size + 11 + 4) {
1505 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1506 GST_WARNING_OBJECT (demux, "Invalid tag size");
1512 *tag_size = tag_data_size + 11 + 4;
1516 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
1519 /* Grab timestamp of tag tag */
1520 pts = GST_READ_UINT24_BE (data);
1521 /* read the pts extension to 32 bits integer */
1522 pts_ext = GST_READ_UINT8 (data + 3);
1524 pts |= pts_ext << 24;
1529 keyframe = ((data[0] >> 4) == 1);
1532 ret = pts * GST_MSECOND;
1533 GST_LOG_OBJECT (demux, "pts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1535 if (index && demux->index && !demux->indexed && (type == 9 || (type == 8
1536 && !demux->has_video))) {
1537 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1541 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1542 demux->duration = ret;
1545 gst_buffer_unmap (buffer, bdata, -1);
1549 static GstFlowReturn
1550 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1552 GstFlowReturn ret = GST_FLOW_OK;
1553 guint8 tag_type = 0;
1556 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1558 data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_READ);
1564 demux->state = FLV_STATE_TAG_VIDEO;
1565 demux->has_video = TRUE;
1568 demux->state = FLV_STATE_TAG_AUDIO;
1569 demux->has_audio = TRUE;
1572 demux->state = FLV_STATE_TAG_SCRIPT;
1575 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1578 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1579 * 4 bytes of previous tag size */
1580 demux->tag_data_size = GST_READ_UINT24_BE (data + 1);
1581 demux->tag_size = demux->tag_data_size + 11;
1583 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1584 demux->tag_data_size);
1586 gst_buffer_unmap (buffer, data, -1);
1591 static GstFlowReturn
1592 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1594 GstFlowReturn ret = GST_FLOW_OK;
1597 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1599 data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_READ);
1601 /* Check for the FLV tag */
1602 if (data[0] == 'F' && data[1] == 'L' && data[2] == 'V') {
1603 GST_DEBUG_OBJECT (demux, "FLV header detected");
1605 if (G_UNLIKELY (demux->strict)) {
1606 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1607 ret = GST_FLOW_UNEXPECTED;
1612 /* Now look at audio/video flags */
1614 guint8 flags = data[4];
1616 demux->has_video = demux->has_audio = FALSE;
1619 GST_DEBUG_OBJECT (demux, "there is a video stream");
1620 demux->has_video = TRUE;
1623 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1624 demux->has_audio = TRUE;
1628 /* do a one-time seekability check */
1629 gst_flv_demux_check_seekability (demux);
1631 /* We don't care about the rest */
1632 demux->need_header = FALSE;
1635 gst_buffer_unmap (buffer, data, -1);
1641 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1643 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1645 gst_adapter_clear (demux->adapter);
1647 demux->audio_need_discont = TRUE;
1648 demux->video_need_discont = TRUE;
1650 demux->flushing = FALSE;
1652 /* Only in push mode and if we're not during a seek */
1653 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1654 /* After a flush we expect a tag_type */
1655 demux->state = FLV_STATE_TAG_TYPE;
1656 /* We reset the offset and will get one from first push */
1662 gst_flv_demux_cleanup (GstFlvDemux * demux)
1664 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1666 demux->state = FLV_STATE_HEADER;
1668 demux->flushing = FALSE;
1669 demux->need_header = TRUE;
1670 demux->audio_need_segment = TRUE;
1671 demux->video_need_segment = TRUE;
1672 demux->audio_need_discont = TRUE;
1673 demux->video_need_discont = TRUE;
1675 /* By default we consider them as linked */
1676 demux->audio_linked = TRUE;
1677 demux->video_linked = TRUE;
1679 demux->has_audio = FALSE;
1680 demux->has_video = FALSE;
1681 demux->push_tags = FALSE;
1682 demux->got_par = FALSE;
1684 demux->indexed = FALSE;
1685 demux->upstream_seekable = FALSE;
1686 demux->file_size = 0;
1688 demux->index_max_pos = 0;
1689 demux->index_max_time = 0;
1691 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1692 demux->last_audio_pts = demux->last_video_pts = 0;
1693 demux->audio_time_offset = demux->video_time_offset = 0;
1695 demux->no_more_pads = FALSE;
1697 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1699 demux->w = demux->h = 0;
1700 demux->framerate = 0.0;
1701 demux->par_x = demux->par_y = 1;
1702 demux->video_offset = 0;
1703 demux->audio_offset = 0;
1704 demux->offset = demux->cur_tag_offset = 0;
1705 demux->tag_size = demux->tag_data_size = 0;
1706 demux->duration = GST_CLOCK_TIME_NONE;
1708 if (demux->new_seg_event) {
1709 gst_event_unref (demux->new_seg_event);
1710 demux->new_seg_event = NULL;
1713 gst_adapter_clear (demux->adapter);
1715 if (demux->audio_codec_data) {
1716 gst_buffer_unref (demux->audio_codec_data);
1717 demux->audio_codec_data = NULL;
1720 if (demux->video_codec_data) {
1721 gst_buffer_unref (demux->video_codec_data);
1722 demux->video_codec_data = NULL;
1725 if (demux->audio_pad) {
1726 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1727 gst_object_unref (demux->audio_pad);
1728 demux->audio_pad = NULL;
1731 if (demux->video_pad) {
1732 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1733 gst_object_unref (demux->video_pad);
1734 demux->video_pad = NULL;
1738 g_array_free (demux->times, TRUE);
1739 demux->times = NULL;
1742 if (demux->filepositions) {
1743 g_array_free (demux->filepositions, TRUE);
1744 demux->filepositions = NULL;
1749 * Create and push a flushing seek event upstream
1752 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1757 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1760 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1761 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1762 GST_SEEK_TYPE_NONE, -1);
1764 res = gst_pad_push_event (demux->sinkpad, event);
1767 demux->offset = offset;
1771 static GstFlowReturn
1772 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1774 GstFlowReturn ret = GST_FLOW_OK;
1775 GstFlvDemux *demux = NULL;
1777 demux = GST_FLV_DEMUX (parent);
1779 GST_LOG_OBJECT (demux, "received buffer of %d bytes at offset %"
1780 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
1781 GST_BUFFER_OFFSET (buffer));
1783 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1784 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1785 demux->state = FLV_STATE_HEADER;
1789 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
1790 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
1791 demux->offset = GST_BUFFER_OFFSET (buffer);
1794 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1795 GST_DEBUG_OBJECT (demux, "Discontinuity");
1796 gst_adapter_clear (demux->adapter);
1799 gst_adapter_push (demux->adapter, buffer);
1801 if (demux->seeking) {
1802 demux->state = FLV_STATE_SEEK;
1803 GST_OBJECT_LOCK (demux);
1804 demux->seeking = FALSE;
1805 GST_OBJECT_UNLOCK (demux);
1809 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1810 if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
1811 || demux->video_linked)) {
1814 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
1819 if (G_UNLIKELY (demux->flushing)) {
1820 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
1821 ret = GST_FLOW_WRONG_STATE;
1825 switch (demux->state) {
1826 case FLV_STATE_HEADER:
1828 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
1831 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
1833 ret = gst_flv_demux_parse_header (demux, buffer);
1835 gst_buffer_unref (buffer);
1836 demux->offset += FLV_HEADER_SIZE;
1838 demux->state = FLV_STATE_TAG_TYPE;
1844 case FLV_STATE_TAG_TYPE:
1846 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
1849 /* Remember the tag offset in bytes */
1850 demux->cur_tag_offset = demux->offset;
1852 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
1854 ret = gst_flv_demux_parse_tag_type (demux, buffer);
1856 gst_buffer_unref (buffer);
1857 demux->offset += FLV_TAG_TYPE_SIZE;
1859 /* last tag is not an index => no index/don't know where the index is
1860 * seek back to the beginning */
1861 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
1869 case FLV_STATE_TAG_VIDEO:
1871 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1874 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1876 ret = gst_flv_demux_parse_tag_video (demux, buffer);
1878 gst_buffer_unref (buffer);
1879 demux->offset += demux->tag_size;
1881 demux->state = FLV_STATE_TAG_TYPE;
1887 case FLV_STATE_TAG_AUDIO:
1889 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1892 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1894 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
1896 gst_buffer_unref (buffer);
1897 demux->offset += demux->tag_size;
1899 demux->state = FLV_STATE_TAG_TYPE;
1905 case FLV_STATE_TAG_SCRIPT:
1907 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1910 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1912 ret = gst_flv_demux_parse_tag_script (demux, buffer);
1914 gst_buffer_unref (buffer);
1915 demux->offset += demux->tag_size;
1917 demux->state = FLV_STATE_TAG_TYPE;
1919 /* if there's a seek event we're here for the index so if we don't have it
1920 * we seek back to the beginning */
1921 if (demux->seek_event) {
1923 demux->state = FLV_STATE_SEEK;
1933 case FLV_STATE_SEEK:
1939 if (!demux->indexed) {
1940 if (demux->offset == demux->file_size - sizeof (guint32)) {
1941 guint64 seek_offset;
1944 data = gst_adapter_take (demux->adapter, 4);
1948 seek_offset = demux->file_size - sizeof (guint32) -
1949 GST_READ_UINT32_BE (data);
1952 GST_INFO_OBJECT (demux,
1953 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
1955 demux->state = FLV_STATE_TAG_TYPE;
1956 flv_demux_seek_to_offset (demux, seek_offset);
1962 GST_OBJECT_LOCK (demux);
1963 event = demux->seek_event;
1964 demux->seek_event = NULL;
1965 GST_OBJECT_UNLOCK (demux);
1967 /* calculate and perform seek */
1968 if (!flv_demux_handle_seek_push (demux, event))
1971 gst_event_unref (event);
1972 demux->state = FLV_STATE_TAG_TYPE;
1976 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
1980 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
1981 /* If either audio or video is linked we return GST_FLOW_OK */
1982 if (demux->audio_linked || demux->video_linked) {
1992 GST_OBJECT_LOCK (demux);
1993 demux->seeking = FALSE;
1994 gst_event_unref (demux->seek_event);
1995 demux->seek_event = NULL;
1996 GST_OBJECT_UNLOCK (demux);
1997 GST_WARNING_OBJECT (demux,
1998 "failed to find an index, seeking back to beginning");
1999 flv_demux_seek_to_offset (demux, 0);
2004 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2005 return GST_FLOW_ERROR;
2010 static GstFlowReturn
2011 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2012 guint size, GstBuffer ** buffer)
2016 ret = gst_pad_pull_range (pad, offset, size, buffer);
2017 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2018 GST_WARNING_OBJECT (demux,
2019 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2020 size, offset, gst_flow_get_name (ret));
2025 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2026 GST_WARNING_OBJECT (demux,
2027 "partial pull got %d when expecting %d from offset %" G_GUINT64_FORMAT,
2028 gst_buffer_get_size (*buffer), size, offset);
2029 gst_buffer_unref (*buffer);
2030 ret = GST_FLOW_UNEXPECTED;
2038 static GstFlowReturn
2039 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2041 GstBuffer *buffer = NULL;
2042 GstFlowReturn ret = GST_FLOW_OK;
2044 /* Store tag offset */
2045 demux->cur_tag_offset = demux->offset;
2047 /* Get the first 4 bytes to identify tag type and size */
2048 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2049 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2052 /* Identify tag type */
2053 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2055 gst_buffer_unref (buffer);
2057 if (G_UNLIKELY (ret != GST_FLOW_OK))
2060 /* Jump over tag type + size */
2061 demux->offset += FLV_TAG_TYPE_SIZE;
2063 /* Pull the whole tag */
2064 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2065 demux->tag_size, &buffer)) != GST_FLOW_OK))
2068 switch (demux->state) {
2069 case FLV_STATE_TAG_VIDEO:
2070 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2072 case FLV_STATE_TAG_AUDIO:
2073 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2075 case FLV_STATE_TAG_SCRIPT:
2076 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2079 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2082 gst_buffer_unref (buffer);
2084 /* Jump over that part we've just parsed */
2085 demux->offset += demux->tag_size;
2087 /* Make sure we reinitialize the tag size */
2088 demux->tag_size = 0;
2090 /* Ready for the next tag */
2091 demux->state = FLV_STATE_TAG_TYPE;
2093 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2094 /* If either audio or video is linked we return GST_FLOW_OK */
2095 if (demux->audio_linked || demux->video_linked) {
2098 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2099 "neither video nor audio are linked");
2107 static GstFlowReturn
2108 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2110 GstBuffer *buffer = NULL;
2111 GstFlowReturn ret = GST_FLOW_OK;
2113 /* Get the first 9 bytes */
2114 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2115 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2118 ret = gst_flv_demux_parse_header (demux, buffer);
2120 gst_buffer_unref (buffer);
2122 /* Jump over the header now */
2123 demux->offset += FLV_HEADER_SIZE;
2124 demux->state = FLV_STATE_TAG_TYPE;
2131 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2134 demux->offset = offset;
2136 /* Tell all the stream we moved to a different position (discont) */
2137 demux->audio_need_discont = TRUE;
2138 demux->video_need_discont = TRUE;
2140 /* next section setup */
2141 demux->from_offset = -1;
2142 demux->audio_done = demux->video_done = FALSE;
2143 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2146 demux->from_offset = -1;
2147 demux->to_offset = G_MAXINT64;
2150 /* If we seeked at the beginning of the file parse the header again */
2151 if (G_UNLIKELY (!demux->offset)) {
2152 demux->state = FLV_STATE_HEADER;
2153 } else { /* or parse a tag */
2154 demux->state = FLV_STATE_TAG_TYPE;
2158 static GstFlowReturn
2159 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2161 GstFlowReturn ret = GST_FLOW_UNEXPECTED;
2162 GstIndexEntry *entry = NULL;
2164 GST_DEBUG_OBJECT (demux,
2165 "terminated section started at offset %" G_GINT64_FORMAT,
2166 demux->from_offset);
2168 /* we are done if we got all audio and video */
2169 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2170 demux->audio_first_ts < demux->segment.start) &&
2171 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2172 demux->video_first_ts < demux->segment.start))
2175 if (demux->from_offset <= 0)
2178 GST_DEBUG_OBJECT (demux, "locating previous position");
2180 /* locate index entry before previous start position */
2182 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2183 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2184 GST_FORMAT_BYTES, demux->from_offset - 1);
2189 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2190 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2192 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2193 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2194 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2196 /* setup for next section */
2197 demux->to_offset = demux->from_offset;
2198 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2206 static GstFlowReturn
2207 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2213 GstClockTime tag_time;
2214 GstFlowReturn ret = GST_FLOW_OK;
2216 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2219 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2220 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2222 old_offset = demux->offset;
2223 demux->offset = pos;
2225 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2226 12, &buffer)) == GST_FLOW_OK) {
2228 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2230 gst_buffer_unref (buffer);
2232 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2235 demux->offset += tag_size;
2238 if (ret == GST_FLOW_UNEXPECTED) {
2239 /* file ran out, so mark we have complete index */
2240 demux->indexed = TRUE;
2245 demux->offset = old_offset;
2251 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2253 gint64 ret = 0, offset;
2254 size_t tag_size, size;
2255 GstBuffer *buffer = NULL;
2258 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2262 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2263 if (G_UNLIKELY (offset < 4))
2267 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2271 data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_READ);
2272 tag_size = GST_READ_UINT32_BE (data);
2273 gst_buffer_unmap (buffer, data, -1);
2274 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2275 gst_buffer_unref (buffer);
2279 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2283 /* a consistency check */
2284 data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_READ);
2285 size = GST_READ_UINT24_BE (data + 1);
2286 if (size != tag_size - 11) {
2287 gst_buffer_unmap (buffer, data, -1);
2288 GST_DEBUG_OBJECT (demux,
2289 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2290 ", corrupt or truncated file", size, tag_size - 11);
2294 /* try to update duration with timestamp in any case */
2295 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2297 /* maybe get some more metadata */
2298 if (data[0] == 18) {
2299 gst_buffer_unmap (buffer, data, -1);
2300 gst_buffer_unref (buffer);
2302 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2304 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2306 gst_flv_demux_parse_tag_script (demux, buffer);
2308 gst_buffer_unmap (buffer, data, -1);
2313 gst_buffer_unref (buffer);
2319 gst_flv_demux_loop (GstPad * pad)
2321 GstFlvDemux *demux = NULL;
2322 GstFlowReturn ret = GST_FLOW_OK;
2324 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2327 switch (demux->state) {
2328 case FLV_STATE_TAG_TYPE:
2329 if (demux->from_offset == -1)
2330 demux->from_offset = demux->offset;
2331 ret = gst_flv_demux_pull_tag (pad, demux);
2332 /* if we have seen real data, we probably passed a possible metadata
2333 * header located at start. So if we do not yet have an index,
2334 * try to pick up metadata (index, duration) at the end */
2335 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2336 (demux->has_video || demux->has_audio)))
2337 demux->file_size = gst_flv_demux_get_metadata (demux);
2339 case FLV_STATE_DONE:
2340 ret = GST_FLOW_UNEXPECTED;
2342 case FLV_STATE_SEEK:
2343 /* seek issued with insufficient index;
2344 * scan for index in task thread from current maximum offset to
2345 * desired time and then perform seek */
2346 /* TODO maybe some buffering message or so to indicate scan progress */
2347 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2349 if (ret != GST_FLOW_OK)
2351 /* position and state arranged by seek,
2352 * also unrefs event */
2353 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2354 demux->seek_event = NULL;
2357 ret = gst_flv_demux_pull_header (pad, demux);
2358 /* index scans start after header */
2359 demux->index_max_pos = demux->offset;
2363 if (demux->segment.rate < 0.0) {
2364 /* check end of section */
2365 if ((gint64) demux->offset >= demux->to_offset ||
2366 demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2367 (demux->audio_done && demux->video_done))
2368 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2370 /* check EOS condition */
2371 if ((demux->segment.stop != -1) &&
2372 (demux->segment.position >= demux->segment.stop)) {
2373 ret = GST_FLOW_UNEXPECTED;
2377 /* pause if something went wrong or at end */
2378 if (G_UNLIKELY (ret != GST_FLOW_OK))
2381 gst_object_unref (demux);
2387 const gchar *reason = gst_flow_get_name (ret);
2389 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2390 gst_pad_pause_task (pad);
2392 if (ret == GST_FLOW_UNEXPECTED) {
2393 /* handle end-of-stream/segment */
2394 /* so align our position with the end of it, if there is one
2395 * this ensures a subsequent will arrive at correct base/acc time */
2396 if (demux->segment.rate > 0.0 &&
2397 GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2398 demux->segment.position = demux->segment.stop;
2399 else if (demux->segment.rate < 0.0)
2400 demux->segment.position = demux->segment.start;
2402 /* perform EOS logic */
2403 if (!demux->no_more_pads) {
2404 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2405 demux->no_more_pads = TRUE;
2408 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2411 /* for segment playback we need to post when (in stream time)
2412 * we stopped, this is either stop (when set) or the duration. */
2413 if ((stop = demux->segment.stop) == -1)
2414 stop = demux->segment.duration;
2416 if (demux->segment.rate >= 0) {
2417 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2418 gst_element_post_message (GST_ELEMENT_CAST (demux),
2419 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2420 GST_FORMAT_TIME, stop));
2421 } else { /* Reverse playback */
2422 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2424 gst_element_post_message (GST_ELEMENT_CAST (demux),
2425 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2426 GST_FORMAT_TIME, demux->segment.start));
2429 /* normal playback, send EOS to all linked pads */
2430 if (!demux->no_more_pads) {
2431 gst_element_no_more_pads (GST_ELEMENT (demux));
2432 demux->no_more_pads = TRUE;
2435 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2436 if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2437 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2439 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
2440 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2441 ("Internal data stream error."),
2442 ("stream stopped, reason %s", reason));
2443 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2445 gst_object_unref (demux);
2451 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2455 GstIndexEntry *entry;
2457 g_return_val_if_fail (segment != NULL, 0);
2459 time = segment->position;
2462 /* Let's check if we have an index entry for that seek time */
2463 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2464 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2465 GST_FORMAT_TIME, time);
2468 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2469 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2471 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2472 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2473 GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2475 /* Key frame seeking */
2476 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2477 /* Adjust the segment so that the keyframe fits in */
2478 if (time < segment->start) {
2479 segment->start = segment->time = time;
2481 segment->position = time;
2484 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2485 GST_TIME_ARGS (segment->start));
2493 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2497 GstSeekType start_type, stop_type;
2500 gboolean update, flush, ret;
2501 GstSegment seeksegment;
2503 gst_event_parse_seek (event, &rate, &format, &flags,
2504 &start_type, &start, &stop_type, &stop);
2506 if (format != GST_FORMAT_TIME)
2509 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2510 /* FIXME : the keyframe flag is never used ! */
2512 /* Work on a copy until we are sure the seek succeeded. */
2513 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2515 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2518 /* Apply the seek to our segment */
2519 gst_segment_do_seek (&seeksegment, rate, format, flags,
2520 start_type, start, stop_type, stop, &update);
2522 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2525 if (flush || seeksegment.position != demux->segment.position) {
2526 /* Do the actual seeking */
2527 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2529 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2530 G_GUINT64_FORMAT, offset);
2531 ret = gst_pad_push_event (demux->sinkpad,
2532 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2533 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2534 offset, GST_SEEK_TYPE_NONE, 0));
2535 if (G_UNLIKELY (!ret)) {
2536 GST_WARNING_OBJECT (demux, "upstream seek failed");
2539 /* Tell all the stream we moved to a different position (discont) */
2540 demux->audio_need_discont = TRUE;
2541 demux->video_need_discont = TRUE;
2547 /* Ok seek succeeded, take the newly configured segment */
2548 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2550 /* Tell all the stream a new segment is needed */
2551 demux->audio_need_segment = TRUE;
2552 demux->video_need_segment = TRUE;
2553 /* Clean any potential newsegment event kept for the streams. The first
2554 * stream needing a new segment will create a new one. */
2555 if (G_UNLIKELY (demux->new_seg_event)) {
2556 gst_event_unref (demux->new_seg_event);
2557 demux->new_seg_event = NULL;
2559 gst_event_unref (event);
2561 ret = gst_pad_push_event (demux->sinkpad, event);
2569 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2570 gst_event_unref (event);
2576 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2580 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2582 if (format != GST_FORMAT_TIME) {
2583 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2584 gst_event_unref (event);
2588 /* First try upstream */
2589 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2590 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2591 gst_event_unref (event);
2595 if (!demux->indexed) {
2596 guint64 seek_offset = 0;
2597 gboolean building_index;
2599 GST_OBJECT_LOCK (demux);
2600 /* handle the seek in the chain function */
2601 demux->seeking = TRUE;
2602 demux->state = FLV_STATE_SEEK;
2604 /* copy the event */
2605 if (demux->seek_event)
2606 gst_event_unref (demux->seek_event);
2607 demux->seek_event = gst_event_ref (event);
2609 /* set the building_index flag so that only one thread can setup the
2610 * structures for index seeking. */
2611 building_index = demux->building_index;
2612 if (!building_index) {
2613 demux->building_index = TRUE;
2614 if (!demux->file_size
2615 && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2616 &demux->file_size)) {
2617 GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2618 GST_OBJECT_UNLOCK (demux);
2622 /* we hope the last tag is a scriptdataobject containing an index
2623 * the size of the last tag is given in the last guint32 bits
2624 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2625 seek_offset = demux->file_size - sizeof (guint32);
2626 GST_DEBUG_OBJECT (demux,
2627 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2629 GST_OBJECT_UNLOCK (demux);
2631 if (!building_index) {
2632 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2634 return flv_demux_seek_to_offset (demux, seek_offset);
2637 /* FIXME: we have to always return true so that we don't block the seek
2639 * Note: maybe it is OK to return true if we're still building the index */
2643 return flv_demux_handle_seek_push (demux, event);
2647 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2652 GstSeekType start_type, stop_type;
2655 gboolean update, flush, ret = FALSE;
2656 GstSegment seeksegment;
2658 gst_event_parse_seek (event, &rate, &format, &flags,
2659 &start_type, &start, &stop_type, &stop);
2661 if (format != GST_FORMAT_TIME)
2664 /* mark seeking thread entering flushing/pausing */
2665 GST_OBJECT_LOCK (demux);
2667 demux->seeking = seeking;
2668 GST_OBJECT_UNLOCK (demux);
2670 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2671 /* FIXME : the keyframe flag is never used */
2674 /* Flush start up and downstream to make sure data flow and loops are
2676 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2677 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2679 /* Pause the pulling task */
2680 gst_pad_pause_task (demux->sinkpad);
2683 /* Take the stream lock */
2684 GST_PAD_STREAM_LOCK (demux->sinkpad);
2687 /* Stop flushing upstream we need to pull */
2688 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2691 /* Work on a copy until we are sure the seek succeeded. */
2692 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2694 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2697 /* Apply the seek to our segment */
2698 gst_segment_do_seek (&seeksegment, rate, format, flags,
2699 start_type, start, stop_type, stop, &update);
2701 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2704 if (flush || seeksegment.position != demux->segment.position) {
2705 /* Do the actual seeking */
2706 /* index is reliable if it is complete or we do not go to far ahead */
2707 if (seeking && !demux->indexed &&
2708 seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2709 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2710 " index only up to %" GST_TIME_FORMAT,
2711 GST_TIME_ARGS (demux->index_max_time));
2712 /* stop flushing for now */
2714 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2715 /* delegate scanning and index building to task thread to avoid
2716 * occupying main (UI) loop */
2717 if (demux->seek_event)
2718 gst_event_unref (demux->seek_event);
2719 demux->seek_event = gst_event_ref (event);
2720 demux->seek_time = seeksegment.position;
2721 demux->state = FLV_STATE_SEEK;
2722 /* do not know about succes yet, but we did care and handled it */
2726 /* now index should be as reliable as it can be for current purpose */
2727 gst_flv_demux_move_to_offset (demux,
2728 gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2735 /* Stop flushing, the sinks are at time 0 now */
2736 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2740 /* Ok seek succeeded, take the newly configured segment */
2741 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2743 /* Notify about the start of a new segment */
2744 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2745 gst_element_post_message (GST_ELEMENT (demux),
2746 gst_message_new_segment_start (GST_OBJECT (demux),
2747 demux->segment.format, demux->segment.position));
2750 /* Tell all the stream a new segment is needed */
2751 demux->audio_need_segment = TRUE;
2752 demux->video_need_segment = TRUE;
2753 /* Clean any potential newsegment event kept for the streams. The first
2754 * stream needing a new segment will create a new one. */
2755 if (G_UNLIKELY (demux->new_seg_event)) {
2756 gst_event_unref (demux->new_seg_event);
2757 demux->new_seg_event = NULL;
2759 if (demux->segment.rate < 0.0) {
2760 /* we can't generate a segment by locking on
2761 * to the first timestamp we see */
2762 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2763 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2764 GST_TIME_ARGS (demux->segment.start),
2765 GST_TIME_ARGS (demux->segment.stop));
2766 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2771 GST_OBJECT_LOCK (demux);
2772 seeking = demux->seeking && !seeking;
2773 demux->seeking = FALSE;
2774 GST_OBJECT_UNLOCK (demux);
2776 /* if we detect an external seek having started (and possibly already having
2777 * flushed), do not restart task to give it a chance.
2778 * Otherwise external one's flushing will take care to pause task */
2780 gst_pad_pause_task (demux->sinkpad);
2782 gst_pad_start_task (demux->sinkpad,
2783 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
2786 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2788 gst_event_unref (event);
2794 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2795 gst_event_unref (event);
2800 /* If we can pull that's prefered */
2802 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
2807 query = gst_query_new_scheduling ();
2809 if (!gst_pad_peer_query (sinkpad, query)) {
2810 gst_query_unref (query);
2814 pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
2815 gst_query_unref (query);
2820 GST_DEBUG_OBJECT (sinkpad, "activating pull");
2821 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
2825 GST_DEBUG_OBJECT (sinkpad, "activating push");
2826 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
2831 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
2832 GstPadMode mode, gboolean active)
2837 demux = GST_FLV_DEMUX (parent);
2840 case GST_PAD_MODE_PUSH:
2841 demux->random_access = FALSE;
2844 case GST_PAD_MODE_PULL:
2846 demux->random_access = TRUE;
2847 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
2850 demux->random_access = FALSE;
2851 res = gst_pad_stop_task (sinkpad);
2862 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
2865 gboolean ret = FALSE;
2867 demux = GST_FLV_DEMUX (parent);
2869 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2871 switch (GST_EVENT_TYPE (event)) {
2872 case GST_EVENT_FLUSH_START:
2873 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
2874 demux->flushing = TRUE;
2875 ret = gst_flv_demux_push_src_event (demux, event);
2877 case GST_EVENT_FLUSH_STOP:
2878 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
2879 gst_flv_demux_flush (demux, TRUE);
2880 ret = gst_flv_demux_push_src_event (demux, event);
2883 GST_DEBUG_OBJECT (demux, "received EOS");
2885 GST_DEBUG_OBJECT (demux, "committing index");
2886 gst_index_commit (demux->index, demux->index_id);
2888 if (!demux->no_more_pads) {
2889 gst_element_no_more_pads (GST_ELEMENT (demux));
2890 demux->no_more_pads = TRUE;
2893 if (!gst_flv_demux_push_src_event (demux, event))
2894 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2897 case GST_EVENT_SEGMENT:
2899 GstSegment in_segment;
2901 GST_DEBUG_OBJECT (demux, "received new segment");
2903 gst_event_copy_segment (event, &in_segment);
2905 if (in_segment.format == GST_FORMAT_TIME) {
2906 /* time segment, this is perfect, copy over the values. */
2907 memcpy (&demux->segment, &in_segment, sizeof (in_segment));
2909 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
2913 ret = gst_flv_demux_push_src_event (demux, event);
2915 /* non-time format */
2916 demux->audio_need_segment = TRUE;
2917 demux->video_need_segment = TRUE;
2919 gst_event_unref (event);
2924 ret = gst_flv_demux_push_src_event (demux, event);
2932 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
2935 gboolean ret = FALSE;
2937 demux = GST_FLV_DEMUX (parent);
2939 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2941 switch (GST_EVENT_TYPE (event)) {
2942 case GST_EVENT_SEEK:
2943 if (demux->random_access) {
2944 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
2946 ret = gst_flv_demux_handle_seek_push (demux, event);
2950 ret = gst_pad_push_event (demux->sinkpad, event);
2958 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
2960 gboolean res = TRUE;
2963 demux = GST_FLV_DEMUX (parent);
2965 switch (GST_QUERY_TYPE (query)) {
2966 case GST_QUERY_DURATION:
2970 gst_query_parse_duration (query, &format, NULL);
2972 /* duration is time only */
2973 if (format != GST_FORMAT_TIME) {
2974 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
2980 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
2981 GST_TIME_ARGS (demux->duration));
2983 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
2987 case GST_QUERY_POSITION:
2991 gst_query_parse_position (query, &format, NULL);
2993 /* position is time only */
2994 if (format != GST_FORMAT_TIME) {
2995 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3001 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3002 GST_TIME_ARGS (demux->segment.position));
3004 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3009 case GST_QUERY_SEEKING:{
3012 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3014 /* First ask upstream */
3015 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3018 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3025 if (fmt != GST_FORMAT_TIME || !demux->index) {
3026 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3027 } else if (demux->random_access) {
3028 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3031 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3032 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3035 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3036 gst_query_unref (peerquery);
3039 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3042 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3046 case GST_QUERY_LATENCY:
3048 res = gst_pad_peer_query (demux->sinkpad, query);
3057 static GstStateChangeReturn
3058 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3061 GstStateChangeReturn ret;
3063 demux = GST_FLV_DEMUX (element);
3065 switch (transition) {
3066 case GST_STATE_CHANGE_READY_TO_PAUSED:
3067 /* If this is our own index destroy it as the
3068 * old entries might be wrong for the new stream */
3069 if (demux->own_index) {
3070 gst_object_unref (demux->index);
3071 demux->index = NULL;
3072 demux->own_index = FALSE;
3075 /* If no index was created, generate one */
3076 if (G_UNLIKELY (!demux->index)) {
3077 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3079 demux->index = gst_index_factory_make ("memindex");
3081 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3083 demux->own_index = TRUE;
3085 gst_flv_demux_cleanup (demux);
3091 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3092 if (ret == GST_STATE_CHANGE_FAILURE)
3095 switch (transition) {
3096 case GST_STATE_CHANGE_PAUSED_TO_READY:
3097 gst_flv_demux_cleanup (demux);
3107 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3109 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3111 GST_OBJECT_LOCK (demux);
3113 gst_object_unref (demux->index);
3115 demux->index = gst_object_ref (index);
3116 demux->own_index = FALSE;
3118 demux->index = NULL;
3120 GST_OBJECT_UNLOCK (demux);
3121 /* object lock might be taken again */
3123 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3124 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3129 gst_flv_demux_get_index (GstElement * element)
3131 GstIndex *result = NULL;
3133 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3135 GST_OBJECT_LOCK (demux);
3137 result = gst_object_ref (demux->index);
3138 GST_OBJECT_UNLOCK (demux);
3144 gst_flv_demux_dispose (GObject * object)
3146 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3148 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3150 if (demux->adapter) {
3151 gst_adapter_clear (demux->adapter);
3152 g_object_unref (demux->adapter);
3153 demux->adapter = NULL;
3156 if (demux->taglist) {
3157 gst_tag_list_free (demux->taglist);
3158 demux->taglist = NULL;
3161 if (demux->new_seg_event) {
3162 gst_event_unref (demux->new_seg_event);
3163 demux->new_seg_event = NULL;
3166 if (demux->audio_codec_data) {
3167 gst_buffer_unref (demux->audio_codec_data);
3168 demux->audio_codec_data = NULL;
3171 if (demux->video_codec_data) {
3172 gst_buffer_unref (demux->video_codec_data);
3173 demux->video_codec_data = NULL;
3176 if (demux->audio_pad) {
3177 gst_object_unref (demux->audio_pad);
3178 demux->audio_pad = NULL;
3181 if (demux->video_pad) {
3182 gst_object_unref (demux->video_pad);
3183 demux->video_pad = NULL;
3187 gst_object_unref (demux->index);
3188 demux->index = NULL;
3192 g_array_free (demux->times, TRUE);
3193 demux->times = NULL;
3196 if (demux->filepositions) {
3197 g_array_free (demux->filepositions, TRUE);
3198 demux->filepositions = NULL;
3201 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3205 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3207 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3208 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3210 gobject_class->dispose = gst_flv_demux_dispose;
3212 gstelement_class->change_state =
3213 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3214 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3215 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3217 gst_element_class_add_pad_template (gstelement_class,
3218 gst_static_pad_template_get (&flv_sink_template));
3219 gst_element_class_add_pad_template (gstelement_class,
3220 gst_static_pad_template_get (&audio_src_template));
3221 gst_element_class_add_pad_template (gstelement_class,
3222 gst_static_pad_template_get (&video_src_template));
3223 gst_element_class_set_details_simple (gstelement_class, "FLV Demuxer",
3225 "Demux FLV feeds into digital streams",
3226 "Julien Moutte <julien@moutte.net>");
3230 gst_flv_demux_init (GstFlvDemux * demux)
3233 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3235 gst_pad_set_event_function (demux->sinkpad,
3236 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3237 gst_pad_set_chain_function (demux->sinkpad,
3238 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3239 gst_pad_set_activate_function (demux->sinkpad,
3240 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3241 gst_pad_set_activatemode_function (demux->sinkpad,
3242 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3244 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3246 demux->adapter = gst_adapter_new ();
3247 demux->taglist = gst_tag_list_new_empty ();
3248 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3250 demux->own_index = FALSE;
3252 gst_flv_demux_cleanup (demux);
3256 plugin_init (GstPlugin * plugin)
3258 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3260 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3261 gst_flv_demux_get_type ()) ||
3262 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3263 gst_flv_mux_get_type ()))
3269 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3270 "flv", "FLV muxing and demuxing plugin",
3271 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)