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>
44 #include <gst/audio/audio.h>
46 /* FIXME: don't rely on own GstIndex */
48 #include "gstmemindex.c"
49 #define GST_ASSOCIATION_FLAG_NONE GST_INDEX_ASSOCIATION_FLAG_NONE
50 #define GST_ASSOCIATION_FLAG_KEY_UNIT GST_INDEX_ASSOCIATION_FLAG_KEY_UNIT
51 #define GST_ASSOCIATION_FLAG_DELTA_UNIT GST_INDEX_ASSOCIATION_FLAG_DELTA_UNIT
53 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
56 GST_STATIC_CAPS ("video/x-flv")
59 static GstStaticPadTemplate audio_src_template =
60 GST_STATIC_PAD_TEMPLATE ("audio",
64 ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
65 "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
66 "audio/mpeg, mpegversion = (int) 4, framed = (boolean) TRUE; "
67 "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
68 "audio/x-raw, format = (string) { U8, S16LE }, layout = (string) interleaved, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
69 "audio/x-alaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
70 "audio/x-mulaw, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
71 "audio/x-speex, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 };")
74 static GstStaticPadTemplate video_src_template =
75 GST_STATIC_PAD_TEMPLATE ("video",
78 GST_STATIC_CAPS ("video/x-flash-video; "
79 "video/x-flash-screen; "
80 "video/x-vp6-flash; " "video/x-vp6-alpha; "
81 "video/x-h264, stream-format=avc;")
84 GST_DEBUG_CATEGORY_STATIC (flvdemux_debug);
85 #define GST_CAT_DEFAULT flvdemux_debug
87 #define gst_flv_demux_parent_class parent_class
88 G_DEFINE_TYPE (GstFlvDemux, gst_flv_demux, GST_TYPE_ELEMENT);
90 /* 9 bytes of header + 4 bytes of first previous tag size */
91 #define FLV_HEADER_SIZE 13
92 /* 1 byte of tag type + 3 bytes of tag data size */
93 #define FLV_TAG_TYPE_SIZE 4
95 /* two seconds - consider pts are resynced to another base if this different */
96 #define RESYNC_THRESHOLD 2000
98 static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
100 static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
101 GstEvent * event, gboolean seeking);
103 static gboolean gst_flv_demux_query (GstPad * pad, GstObject * parent,
105 static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent,
110 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
111 guint64 pos, gboolean keyframe)
113 static GstIndexAssociation associations[2];
114 static GstIndexEntry *entry;
116 GST_LOG_OBJECT (demux,
117 "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
118 keyframe, GST_TIME_ARGS (ts), pos);
120 /* if upstream is not seekable there is no point in building an index */
121 if (!demux->upstream_seekable)
124 /* entry may already have been added before, avoid adding indefinitely */
125 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
126 GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
129 #ifndef GST_DISABLE_GST_DEBUG
133 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
134 key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
135 GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
136 ", keyframe %d", GST_TIME_ARGS (time), key);
137 /* there is not really a way to delete the existing one */
138 if (time != ts || key != ! !keyframe)
139 GST_DEBUG_OBJECT (demux, "metadata mismatch");
144 associations[0].format = GST_FORMAT_TIME;
145 associations[0].value = ts;
146 associations[1].format = GST_FORMAT_BYTES;
147 associations[1].value = pos;
149 gst_index_add_associationv (demux->index, demux->index_id,
150 (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
151 GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
152 (const GstIndexAssociation *) &associations);
154 if (pos > demux->index_max_pos)
155 demux->index_max_pos = pos;
156 if (ts > demux->index_max_time)
157 demux->index_max_time = ts;
161 FLV_GET_STRING (GstByteReader * reader)
163 guint16 string_size = 0;
164 gchar *string = NULL;
165 const guint8 *str = NULL;
167 g_return_val_if_fail (reader != NULL, NULL);
169 if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
172 if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
175 string = g_try_malloc0 (string_size + 1);
176 if (G_UNLIKELY (!string)) {
180 if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
185 memcpy (string, str, string_size);
186 if (!g_utf8_validate (string, string_size, NULL)) {
195 gst_flv_demux_check_seekability (GstFlvDemux * demux)
198 gint64 start = -1, stop = -1;
200 demux->upstream_seekable = FALSE;
202 query = gst_query_new_seeking (GST_FORMAT_BYTES);
203 if (!gst_pad_peer_query (demux->sinkpad, query)) {
204 GST_DEBUG_OBJECT (demux, "seeking query failed");
205 gst_query_unref (query);
209 gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
212 gst_query_unref (query);
214 /* try harder to query upstream size if we didn't get it the first time */
215 if (demux->upstream_seekable && stop == -1) {
216 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
217 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
220 /* if upstream doesn't know the size, it's likely that it's not seekable in
221 * practice even if it technically may be seekable */
222 if (demux->upstream_seekable && (start != 0 || stop <= start)) {
223 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
224 demux->upstream_seekable = FALSE;
227 GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
231 parse_flv_demux_parse_date_string (GDate * date, const gchar * s)
233 g_date_set_parse (date, s);
234 if (g_date_valid (date))
237 /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
239 static const gchar *months[] = {
240 "Jan", "Feb", "Mar", "Apr",
241 "May", "Jun", "Jul", "Aug",
242 "Sep", "Oct", "Nov", "Dec"
244 gchar **tokens = g_strsplit (s, " ", -1);
249 if (g_strv_length (tokens) != 5)
252 if (strlen (tokens[1]) != 3)
254 for (i = 0; i < 12; i++) {
255 if (!strcmp (tokens[1], months[i])) {
261 g_date_set_month (date, i + 1);
263 d = g_ascii_strtoull (tokens[2], &endptr, 10);
264 if (d == 0 && *endptr != '\0')
267 g_date_set_day (date, d);
269 d = g_ascii_strtoull (tokens[4], &endptr, 10);
270 if (d == 0 && *endptr != '\0')
273 g_date_set_year (date, d);
282 gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
283 gboolean * end_marker)
285 gchar *tag_name = NULL;
288 /* Initialize the end_marker flag to FALSE */
291 /* Name of the tag */
292 tag_name = FLV_GET_STRING (reader);
293 if (G_UNLIKELY (!tag_name)) {
294 GST_WARNING_OBJECT (demux, "failed reading tag name");
298 /* What kind of object is that */
299 if (!gst_byte_reader_get_uint8 (reader, &tag_type))
302 GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
306 { /* Use a union to read the uint64 and then as a double */
309 if (!gst_byte_reader_get_float64_be (reader, &d))
312 GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
314 if (!strcmp (tag_name, "duration")) {
315 demux->duration = d * GST_SECOND;
317 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
318 GST_TAG_DURATION, demux->duration, NULL);
319 } else if (!strcmp (tag_name, "AspectRatioX")) {
321 demux->got_par = TRUE;
322 } else if (!strcmp (tag_name, "AspectRatioY")) {
324 demux->got_par = TRUE;
325 } else if (!strcmp (tag_name, "width")) {
327 } else if (!strcmp (tag_name, "height")) {
329 } else if (!strcmp (tag_name, "framerate")) {
330 demux->framerate = d;
332 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
341 if (!gst_byte_reader_get_uint8 (reader, &b))
344 GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
346 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
354 s = FLV_GET_STRING (reader);
358 GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
360 if (!strcmp (tag_name, "creationdate")) {
361 GDate *date = g_date_new ();
363 parse_flv_demux_parse_date_string (date, s);
364 if (!g_date_valid (date)) {
365 GST_DEBUG_OBJECT (demux, "Failed to parse string as date");
367 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
368 GST_TAG_DATE, date, NULL);
371 } else if (!strcmp (tag_name, "creator")) {
372 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
373 GST_TAG_ARTIST, s, NULL);
374 } else if (!strcmp (tag_name, "title")) {
375 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
376 GST_TAG_TITLE, s, NULL);
377 } else if (!strcmp (tag_name, "metadatacreator")) {
378 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
379 GST_TAG_ENCODER, s, NULL);
381 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
390 gboolean end_of_object_marker = FALSE;
392 while (!end_of_object_marker) {
393 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
394 &end_of_object_marker);
396 if (G_UNLIKELY (!ok)) {
397 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
404 case 8: // ECMA array
406 guint32 nb_elems = 0;
407 gboolean end_of_object_marker = FALSE;
409 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
412 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
415 while (!end_of_object_marker) {
416 gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
417 &end_of_object_marker);
419 if (G_UNLIKELY (!ok)) {
420 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
427 case 9: // End marker
429 GST_DEBUG_OBJECT (demux, "end marker ?");
430 if (tag_name[0] == '\0') {
432 GST_DEBUG_OBJECT (demux, "end marker detected");
441 guint32 nb_elems = 0;
443 if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
446 GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
448 if (!strcmp (tag_name, "times")) {
450 g_array_free (demux->times, TRUE);
452 demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
453 } else if (!strcmp (tag_name, "filepositions")) {
454 if (demux->filepositions) {
455 g_array_free (demux->filepositions, TRUE);
457 demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
461 guint8 elem_type = 0;
463 if (!gst_byte_reader_get_uint8 (reader, &elem_type))
471 if (!gst_byte_reader_get_float64_be (reader, &d))
474 GST_DEBUG_OBJECT (demux, "element is a double %f", d);
476 if (!strcmp (tag_name, "times") && demux->times) {
477 g_array_append_val (demux->times, d);
478 } else if (!strcmp (tag_name, "filepositions") &&
479 demux->filepositions) {
480 g_array_append_val (demux->filepositions, d);
485 GST_WARNING_OBJECT (demux, "unsupported array element type %d",
497 if (!gst_byte_reader_get_float64_be (reader, &d))
500 if (!gst_byte_reader_get_int16_be (reader, &i))
503 GST_DEBUG_OBJECT (demux,
504 "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
506 GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
511 GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
525 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
527 GstFlowReturn ret = GST_FLOW_OK;
528 GstByteReader reader;
532 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 7, GST_FLOW_ERROR);
534 gst_buffer_map (buffer, &map, GST_MAP_READ);
535 gst_byte_reader_init (&reader, map.data, map.size);
537 gst_byte_reader_skip (&reader, 7);
539 GST_LOG_OBJECT (demux, "parsing a script tag");
541 if (!gst_byte_reader_get_uint8 (&reader, &type))
546 gchar *function_name;
549 function_name = FLV_GET_STRING (&reader);
551 GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
553 if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
554 gboolean end_marker = FALSE;
555 GST_DEBUG_OBJECT (demux, "we have a metadata script object");
557 if (!gst_byte_reader_get_uint8 (&reader, &type)) {
558 g_free (function_name);
565 guint32 nb_elems = 0;
568 if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
569 g_free (function_name);
573 /* The number of elements is just a hint, some files have
574 nb_elements == 0 and actually contain items. */
575 GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
578 /* fallthrough to read data */
582 while (!end_marker) {
584 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
586 if (G_UNLIKELY (!ok)) {
587 GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
594 GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
595 g_free (function_name);
599 demux->push_tags = TRUE;
602 g_free (function_name);
604 if (demux->index && demux->times && demux->filepositions) {
607 /* If an index was found, insert associations */
608 num = MIN (demux->times->len, demux->filepositions->len);
609 for (i = 0; i < num; i++) {
610 guint64 time, fileposition;
612 time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
613 fileposition = g_array_index (demux->filepositions, gdouble, i);
614 gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
617 demux->indexed = TRUE;
622 gst_buffer_unmap (buffer, &map);
628 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
629 guint32 rate, guint32 channels, guint32 width)
631 GstCaps *caps = NULL;
632 gchar *codec_name = NULL;
633 gboolean ret = FALSE;
634 guint adjusted_rate = rate;
638 caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
643 caps = gst_caps_new_simple ("audio/mpeg",
644 "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
645 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
650 GstAudioFormat format;
652 /* Assuming little endian for 0 (aka endianness of the
653 * system on which the file was created) as most people
654 * are probably using little endian machines */
655 format = gst_audio_format_build_integer ((width == 8) ? FALSE : TRUE,
656 G_LITTLE_ENDIAN, width, width);
658 caps = gst_caps_new_simple ("audio/x-raw",
659 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
660 "layout", G_TYPE_STRING, "interleaved", NULL);
666 caps = gst_caps_new_empty_simple ("audio/x-nellymoser");
670 if (demux->audio_codec_data) {
673 gst_buffer_map (demux->audio_codec_data, &map, GST_MAP_READ);
675 /* use codec-data to extract and verify samplerate */
679 freq_index = GST_READ_UINT16_BE (map.data);
680 freq_index = (freq_index & 0x0780) >> 7;
682 gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
684 if (adjusted_rate && (rate != adjusted_rate)) {
685 GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
688 adjusted_rate = rate;
691 gst_buffer_unmap (demux->audio_codec_data, &map);
694 caps = gst_caps_new_simple ("audio/mpeg",
695 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
696 "stream-format", G_TYPE_STRING, "raw", NULL);
700 caps = gst_caps_new_empty_simple ("audio/x-alaw");
703 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
706 caps = gst_caps_new_empty_simple ("audio/x-speex");
709 GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
712 if (G_UNLIKELY (!caps)) {
713 GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
717 gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
718 "channels", G_TYPE_INT, channels, NULL);
720 if (demux->audio_codec_data) {
721 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
722 demux->audio_codec_data, NULL);
725 ret = gst_pad_set_caps (demux->audio_pad, caps);
727 if (G_LIKELY (ret)) {
728 /* Store the caps we got from tags */
729 demux->audio_codec_tag = codec_tag;
731 demux->channels = channels;
732 demux->width = width;
734 codec_name = gst_pb_utils_get_codec_description (caps);
737 if (demux->taglist == NULL)
738 demux->taglist = gst_tag_list_new_empty ();
739 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
740 GST_TAG_AUDIO_CODEC, codec_name, NULL);
744 GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
745 GST_PTR_FORMAT, caps);
747 GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
748 GST_PTR_FORMAT, caps);
751 gst_caps_unref (caps);
758 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
762 if (demux->audio_pad)
763 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
765 if (demux->video_pad)
766 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
768 gst_event_unref (event);
774 gst_flv_demux_push_tags (GstFlvDemux * demux)
776 if (demux->has_audio && !demux->audio_pad) {
777 GST_DEBUG_OBJECT (demux,
778 "Waiting for audio stream pad to come up before we can push tags");
781 if (demux->has_video && !demux->video_pad) {
782 GST_DEBUG_OBJECT (demux,
783 "Waiting for video stream pad to come up before we can push tags");
786 if (demux->taglist) {
787 GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
789 gst_flv_demux_push_src_event (demux, gst_event_new_tag (demux->taglist));
790 demux->taglist = gst_tag_list_new_empty ();
791 demux->push_tags = FALSE;
796 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, gboolean discont,
797 guint32 * last, GstClockTime * offset)
799 gint32 dpts = pts - *last;
800 if (!discont && ABS (dpts) >= RESYNC_THRESHOLD) {
801 /* Theoretically, we should use substract the duration of the last buffer,
802 but this demuxer sends no durations on buffers, not sure if it cannot
803 know, or just does not care to calculate. */
804 *offset -= dpts * GST_MSECOND;
805 GST_WARNING_OBJECT (demux,
806 "Large pts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
807 GST_TIME_FORMAT "", dpts, GST_TIME_ARGS (*offset));
813 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
815 GstFlowReturn ret = GST_FLOW_OK;
816 guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
817 guint32 codec_data = 0, pts_ext = 0;
823 GST_LOG_OBJECT (demux, "parsing an audio tag");
825 if (demux->no_more_pads && !demux->audio_pad) {
826 GST_WARNING_OBJECT (demux,
827 "Signaled no-more-pads already but had no audio pad -- ignoring");
831 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
834 /* Error out on tags with too small headers */
835 if (gst_buffer_get_size (buffer) < 11) {
836 GST_ERROR_OBJECT (demux, "Too small tag size (%" G_GSIZE_FORMAT ")",
837 gst_buffer_get_size (buffer));
838 return GST_FLOW_ERROR;
841 gst_buffer_map (buffer, &map, GST_MAP_READ);
844 /* Grab information about audio tag */
845 pts = GST_READ_UINT24_BE (data);
846 /* read the pts extension to 32 bits integer */
847 pts_ext = GST_READ_UINT8 (data + 3);
849 pts |= pts_ext << 24;
851 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
852 data[2], data[3], pts);
854 /* Skip the stream id and go directly to the flags */
855 flags = GST_READ_UINT8 (data + 7);
857 /* Silently skip buffers with no data */
870 if ((flags & 0x0C) == 0x0C) {
872 } else if ((flags & 0x0C) == 0x08) {
874 } else if ((flags & 0x0C) == 0x04) {
878 codec_tag = flags >> 4;
879 if (codec_tag == 10) { /* AAC has an extra byte for packet type */
885 /* codec tags with special rates */
886 if (codec_tag == 5 || codec_tag == 14)
888 else if (codec_tag == 4)
891 GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
892 "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
895 /* If we don't have our audio pad created, then create it. */
896 if (G_UNLIKELY (!demux->audio_pad)) {
899 gst_pad_new_from_template (gst_element_class_get_pad_template
900 (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
901 if (G_UNLIKELY (!demux->audio_pad)) {
902 GST_WARNING_OBJECT (demux, "failed creating audio pad");
903 ret = GST_FLOW_ERROR;
907 /* Set functions on the pad */
908 gst_pad_set_query_function (demux->audio_pad,
909 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
910 gst_pad_set_event_function (demux->audio_pad,
911 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
913 gst_pad_use_fixed_caps (demux->audio_pad);
916 gst_pad_set_active (demux->audio_pad, TRUE);
919 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
921 gst_object_unref (demux->audio_pad);
922 demux->audio_pad = NULL;
923 ret = GST_FLOW_ERROR;
926 #ifndef GST_DISABLE_GST_DEBUG
930 caps = gst_pad_get_current_caps (demux->audio_pad);
931 GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
934 gst_caps_unref (caps);
938 /* We need to set caps before adding */
939 gst_element_add_pad (GST_ELEMENT (demux),
940 gst_object_ref (demux->audio_pad));
942 /* We only emit no more pads when we have audio and video. Indeed we can
943 * not trust the FLV header to tell us if there will be only audio or
944 * only video and we would just break discovery of some files */
945 if (demux->audio_pad && demux->video_pad) {
946 GST_DEBUG_OBJECT (demux, "emitting no more pads");
947 gst_element_no_more_pads (GST_ELEMENT (demux));
948 demux->no_more_pads = TRUE;
949 demux->push_tags = TRUE;
953 /* Check if caps have changed */
954 if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
955 codec_tag != demux->audio_codec_tag || width != demux->width)) {
956 GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
959 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
961 ret = GST_FLOW_ERROR;
966 /* Push taglist if present */
967 if (G_UNLIKELY (demux->push_tags))
968 gst_flv_demux_push_tags (demux);
970 /* Check if we have anything to push */
971 if (demux->tag_data_size <= codec_data) {
972 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
976 /* Create buffer from pad */
977 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
978 7 + codec_data, demux->tag_data_size - codec_data);
980 if (demux->audio_codec_tag == 10) {
981 guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
983 switch (aac_packet_type) {
986 /* AudioSpecificConfig data */
987 GST_LOG_OBJECT (demux, "got an AAC codec data packet");
988 if (demux->audio_codec_data) {
989 gst_buffer_unref (demux->audio_codec_data);
991 demux->audio_codec_data = outbuf;
992 /* Use that buffer data in the caps */
993 gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels, width);
999 GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
1002 GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
1007 /* detect (and deem to be resyncs) large pts gaps */
1008 gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
1009 &demux->last_audio_pts, &demux->audio_time_offset);
1011 /* Fill buffer with data */
1012 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
1013 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1014 GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
1015 GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
1017 if (demux->duration == GST_CLOCK_TIME_NONE ||
1018 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1019 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1021 /* Only add audio frames to the index if we have no video,
1022 * and if the index is not yet complete */
1023 if (!demux->has_video && demux->index && !demux->indexed) {
1024 gst_flv_demux_parse_and_add_index_entry (demux,
1025 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
1028 if (G_UNLIKELY (demux->audio_need_discont)) {
1029 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1030 demux->audio_need_discont = FALSE;
1033 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1035 /* Do we need a newsegment event ? */
1036 if (G_UNLIKELY (demux->audio_need_segment)) {
1037 if (!demux->new_seg_event) {
1038 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1039 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1040 GST_TIME_ARGS (demux->segment.position),
1041 GST_TIME_ARGS (demux->segment.stop));
1042 demux->segment.start = demux->segment.time = demux->segment.position;
1043 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1045 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1048 gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1050 demux->audio_need_segment = FALSE;
1053 GST_LOG_OBJECT (demux,
1054 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1055 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1056 gst_buffer_get_size (outbuf),
1057 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1058 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1060 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1061 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1063 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1064 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1067 if (G_UNLIKELY (!demux->no_more_pads
1068 && (GST_CLOCK_DIFF (demux->audio_start,
1069 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1070 GST_DEBUG_OBJECT (demux,
1071 "Signalling no-more-pads because no video stream was found"
1072 " after 6 seconds of audio");
1073 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1074 demux->no_more_pads = TRUE;
1075 demux->push_tags = TRUE;
1078 /* Push downstream */
1079 ret = gst_pad_push (demux->audio_pad, outbuf);
1080 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1081 if (demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1082 demux->segment.position > demux->segment.stop) {
1083 /* In reverse playback we can get a GST_FLOW_EOS when
1084 * we are at the end of the segment, so we just need to jump
1085 * back to the previous section. */
1086 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1087 demux->audio_done = TRUE;
1090 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1091 " bytes audio buffer: %s", demux->tag_data_size,
1092 gst_flow_get_name (ret));
1093 if (ret == GST_FLOW_NOT_LINKED) {
1094 demux->audio_linked = FALSE;
1100 demux->audio_linked = TRUE;
1103 gst_buffer_unmap (buffer, &map);
1109 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1111 gboolean ret = FALSE;
1112 GstCaps *caps = NULL;
1113 gchar *codec_name = NULL;
1115 /* Generate caps for that pad */
1116 switch (codec_tag) {
1118 caps = gst_caps_new_empty_simple ("video/x-flash-video");
1121 caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1124 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1127 caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1131 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1135 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1138 if (G_UNLIKELY (!caps)) {
1139 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1143 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1144 demux->par_x, demux->par_y, NULL);
1146 if (G_LIKELY (demux->w)) {
1147 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1150 if (G_LIKELY (demux->h)) {
1151 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1154 if (G_LIKELY (demux->framerate)) {
1155 gint num = 0, den = 0;
1157 gst_util_double_to_fraction (demux->framerate, &num, &den);
1158 GST_DEBUG_OBJECT (demux->video_pad,
1159 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1162 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1165 if (demux->video_codec_data) {
1166 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1167 demux->video_codec_data, NULL);
1170 ret = gst_pad_set_caps (demux->video_pad, caps);
1172 if (G_LIKELY (ret)) {
1173 /* Store the caps we have set */
1174 demux->video_codec_tag = codec_tag;
1176 codec_name = gst_pb_utils_get_codec_description (caps);
1179 if (demux->taglist == NULL)
1180 demux->taglist = gst_tag_list_new_empty ();
1181 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1182 GST_TAG_VIDEO_CODEC, codec_name, NULL);
1183 g_free (codec_name);
1186 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1187 GST_PTR_FORMAT, caps);
1189 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1190 GST_PTR_FORMAT, caps);
1193 gst_caps_unref (caps);
1199 static GstFlowReturn
1200 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1202 GstFlowReturn ret = GST_FLOW_OK;
1203 guint32 pts = 0, codec_data = 1, pts_ext = 0;
1204 gboolean keyframe = FALSE;
1205 guint8 flags = 0, codec_tag = 0;
1210 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1213 GST_LOG_OBJECT (demux, "parsing a video tag");
1215 if (demux->no_more_pads && !demux->video_pad) {
1216 GST_WARNING_OBJECT (demux,
1217 "Signaled no-more-pads already but had no audio pad -- ignoring");
1221 if (gst_buffer_get_size (buffer) < 12) {
1222 GST_ERROR_OBJECT (demux, "Too small tag size");
1223 return GST_FLOW_ERROR;
1226 gst_buffer_map (buffer, &map, GST_MAP_READ);
1229 /* Grab information about video tag */
1230 pts = GST_READ_UINT24_BE (data);
1231 /* read the pts extension to 32 bits integer */
1232 pts_ext = GST_READ_UINT8 (data + 3);
1234 pts |= pts_ext << 24;
1236 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1237 data[2], data[3], pts);
1239 /* Skip the stream id and go directly to the flags */
1240 flags = GST_READ_UINT8 (data + 7);
1243 if ((flags >> 4) == 1) {
1247 codec_tag = flags & 0x0F;
1248 if (codec_tag == 4 || codec_tag == 5) {
1250 } else if (codec_tag == 7) {
1255 cts = GST_READ_UINT24_BE (data + 9);
1256 cts = (cts + 0xff800000) ^ 0xff800000;
1258 GST_LOG_OBJECT (demux, "got cts %d", cts);
1260 /* avoid negative overflow */
1261 if (cts >= 0 || pts >= -cts)
1265 GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1266 "(flags %02X)", codec_tag, keyframe, flags);
1268 /* If we don't have our video pad created, then create it. */
1269 if (G_UNLIKELY (!demux->video_pad)) {
1271 gst_pad_new_from_template (gst_element_class_get_pad_template
1272 (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1273 if (G_UNLIKELY (!demux->video_pad)) {
1274 GST_WARNING_OBJECT (demux, "failed creating video pad");
1275 ret = GST_FLOW_ERROR;
1279 /* Set functions on the pad */
1280 gst_pad_set_query_function (demux->video_pad,
1281 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1282 gst_pad_set_event_function (demux->video_pad,
1283 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1285 gst_pad_use_fixed_caps (demux->video_pad);
1287 /* Make it active */
1288 gst_pad_set_active (demux->video_pad, TRUE);
1290 /* Needs to be active before setting caps */
1291 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1292 gst_object_unref (demux->video_pad);
1293 demux->video_pad = NULL;
1294 ret = GST_FLOW_ERROR;
1298 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1299 * metadata tag that would come later and trigger a caps change */
1300 demux->got_par = FALSE;
1302 #ifndef GST_DISABLE_GST_DEBUG
1306 caps = gst_pad_get_current_caps (demux->video_pad);
1307 GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1310 gst_caps_unref (caps);
1314 /* We need to set caps before adding */
1315 gst_element_add_pad (GST_ELEMENT (demux),
1316 gst_object_ref (demux->video_pad));
1318 /* We only emit no more pads when we have audio and video. Indeed we can
1319 * not trust the FLV header to tell us if there will be only audio or
1320 * only video and we would just break discovery of some files */
1321 if (demux->audio_pad && demux->video_pad) {
1322 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1323 gst_element_no_more_pads (GST_ELEMENT (demux));
1324 demux->no_more_pads = TRUE;
1325 demux->push_tags = TRUE;
1329 /* Check if caps have changed */
1330 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1332 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1334 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1335 ret = GST_FLOW_ERROR;
1339 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1340 * metadata tag that would come later and trigger a caps change */
1341 demux->got_par = FALSE;
1344 /* Push taglist if present */
1345 if (G_UNLIKELY (demux->push_tags))
1346 gst_flv_demux_push_tags (demux);
1348 /* Check if we have anything to push */
1349 if (demux->tag_data_size <= codec_data) {
1350 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1354 /* Create buffer from pad */
1355 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1356 7 + codec_data, demux->tag_data_size - codec_data);
1358 if (demux->video_codec_tag == 7) {
1359 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1361 switch (avc_packet_type) {
1364 /* AVCDecoderConfigurationRecord data */
1365 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1366 if (demux->video_codec_data) {
1367 gst_buffer_unref (demux->video_codec_data);
1369 demux->video_codec_data = outbuf;
1370 /* Use that buffer data in the caps */
1371 gst_flv_demux_video_negotiate (demux, codec_tag);
1376 /* H.264 NALU packet */
1377 GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1380 GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1385 /* detect (and deem to be resyncs) large pts gaps */
1386 gst_flv_demux_update_resync (demux, pts, demux->video_need_discont,
1387 &demux->last_video_pts, &demux->video_time_offset);
1389 /* Fill buffer with data */
1390 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
1391 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1392 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1393 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1395 if (demux->duration == GST_CLOCK_TIME_NONE ||
1396 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1397 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1400 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1402 if (!demux->indexed && demux->index) {
1403 gst_flv_demux_parse_and_add_index_entry (demux,
1404 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1407 if (G_UNLIKELY (demux->video_need_discont)) {
1408 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1409 demux->video_need_discont = FALSE;
1412 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1414 /* Do we need a newsegment event ? */
1415 if (G_UNLIKELY (demux->video_need_segment)) {
1416 if (!demux->new_seg_event) {
1417 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1418 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1419 GST_TIME_ARGS (demux->segment.position),
1420 GST_TIME_ARGS (demux->segment.stop));
1421 demux->segment.start = demux->segment.time = demux->segment.position;
1422 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1424 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1427 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1429 demux->video_need_segment = FALSE;
1432 GST_LOG_OBJECT (demux,
1433 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1434 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1435 ", keyframe (%d)", gst_buffer_get_size (outbuf),
1436 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1437 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1440 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1441 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1443 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1444 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1447 if (G_UNLIKELY (!demux->no_more_pads
1448 && (GST_CLOCK_DIFF (demux->video_start,
1449 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1450 GST_DEBUG_OBJECT (demux,
1451 "Signalling no-more-pads because no audio stream was found"
1452 " after 6 seconds of video");
1453 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1454 demux->no_more_pads = TRUE;
1455 demux->push_tags = TRUE;
1458 /* Push downstream */
1459 ret = gst_pad_push (demux->video_pad, outbuf);
1461 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1462 if (demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1463 demux->segment.position > demux->segment.stop) {
1464 /* In reverse playback we can get a GST_FLOW_EOS when
1465 * we are at the end of the segment, so we just need to jump
1466 * back to the previous section. */
1467 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1468 demux->video_done = TRUE;
1471 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1472 " bytes video buffer: %s", demux->tag_data_size,
1473 gst_flow_get_name (ret));
1474 if (ret == GST_FLOW_NOT_LINKED) {
1475 demux->video_linked = FALSE;
1481 demux->video_linked = TRUE;
1484 gst_buffer_unmap (buffer, &map);
1489 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1490 GstBuffer * buffer, size_t * tag_size)
1492 guint32 pts = 0, pts_ext = 0;
1493 guint32 tag_data_size;
1495 gboolean keyframe = TRUE;
1496 GstClockTime ret = GST_CLOCK_TIME_NONE;
1501 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1502 GST_CLOCK_TIME_NONE);
1504 gst_buffer_map (buffer, &map, GST_MAP_READ);
1510 if (type != 9 && type != 8 && type != 18) {
1511 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1516 demux->has_video = TRUE;
1518 demux->has_audio = TRUE;
1520 tag_data_size = GST_READ_UINT24_BE (data + 1);
1522 if (size >= tag_data_size + 11 + 4) {
1523 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1524 GST_WARNING_OBJECT (demux, "Invalid tag size");
1530 *tag_size = tag_data_size + 11 + 4;
1534 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
1537 /* Grab timestamp of tag tag */
1538 pts = GST_READ_UINT24_BE (data);
1539 /* read the pts extension to 32 bits integer */
1540 pts_ext = GST_READ_UINT8 (data + 3);
1542 pts |= pts_ext << 24;
1547 keyframe = ((data[0] >> 4) == 1);
1550 ret = pts * GST_MSECOND;
1551 GST_LOG_OBJECT (demux, "pts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1553 if (index && demux->index && !demux->indexed && (type == 9 || (type == 8
1554 && !demux->has_video))) {
1555 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1559 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1560 demux->duration = ret;
1563 gst_buffer_unmap (buffer, &map);
1567 static GstFlowReturn
1568 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1570 GstFlowReturn ret = GST_FLOW_OK;
1571 guint8 tag_type = 0;
1574 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1576 gst_buffer_map (buffer, &map, GST_MAP_READ);
1578 tag_type = map.data[0];
1582 demux->state = FLV_STATE_TAG_VIDEO;
1583 demux->has_video = TRUE;
1586 demux->state = FLV_STATE_TAG_AUDIO;
1587 demux->has_audio = TRUE;
1590 demux->state = FLV_STATE_TAG_SCRIPT;
1593 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1596 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1597 * 4 bytes of previous tag size */
1598 demux->tag_data_size = GST_READ_UINT24_BE (map.data + 1);
1599 demux->tag_size = demux->tag_data_size + 11;
1601 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1602 demux->tag_data_size);
1604 gst_buffer_unmap (buffer, &map);
1609 static GstFlowReturn
1610 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1612 GstFlowReturn ret = GST_FLOW_OK;
1615 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1617 gst_buffer_map (buffer, &map, GST_MAP_READ);
1619 /* Check for the FLV tag */
1620 if (map.data[0] == 'F' && map.data[1] == 'L' && map.data[2] == 'V') {
1621 GST_DEBUG_OBJECT (demux, "FLV header detected");
1623 if (G_UNLIKELY (demux->strict)) {
1624 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1630 /* Now look at audio/video flags */
1632 guint8 flags = map.data[4];
1634 demux->has_video = demux->has_audio = FALSE;
1637 GST_DEBUG_OBJECT (demux, "there is a video stream");
1638 demux->has_video = TRUE;
1641 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1642 demux->has_audio = TRUE;
1646 /* do a one-time seekability check */
1647 gst_flv_demux_check_seekability (demux);
1649 /* We don't care about the rest */
1650 demux->need_header = FALSE;
1653 gst_buffer_unmap (buffer, &map);
1659 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1661 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1663 gst_adapter_clear (demux->adapter);
1665 demux->audio_need_discont = TRUE;
1666 demux->video_need_discont = TRUE;
1668 demux->flushing = FALSE;
1670 /* Only in push mode and if we're not during a seek */
1671 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1672 /* After a flush we expect a tag_type */
1673 demux->state = FLV_STATE_TAG_TYPE;
1674 /* We reset the offset and will get one from first push */
1680 gst_flv_demux_cleanup (GstFlvDemux * demux)
1682 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1684 demux->state = FLV_STATE_HEADER;
1686 demux->flushing = FALSE;
1687 demux->need_header = TRUE;
1688 demux->audio_need_segment = TRUE;
1689 demux->video_need_segment = TRUE;
1690 demux->audio_need_discont = TRUE;
1691 demux->video_need_discont = TRUE;
1693 /* By default we consider them as linked */
1694 demux->audio_linked = TRUE;
1695 demux->video_linked = TRUE;
1697 demux->has_audio = FALSE;
1698 demux->has_video = FALSE;
1699 demux->push_tags = FALSE;
1700 demux->got_par = FALSE;
1702 demux->indexed = FALSE;
1703 demux->upstream_seekable = FALSE;
1704 demux->file_size = 0;
1706 demux->index_max_pos = 0;
1707 demux->index_max_time = 0;
1709 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1710 demux->last_audio_pts = demux->last_video_pts = 0;
1711 demux->audio_time_offset = demux->video_time_offset = 0;
1713 demux->no_more_pads = FALSE;
1715 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1717 demux->w = demux->h = 0;
1718 demux->framerate = 0.0;
1719 demux->par_x = demux->par_y = 1;
1720 demux->video_offset = 0;
1721 demux->audio_offset = 0;
1722 demux->offset = demux->cur_tag_offset = 0;
1723 demux->tag_size = demux->tag_data_size = 0;
1724 demux->duration = GST_CLOCK_TIME_NONE;
1726 if (demux->new_seg_event) {
1727 gst_event_unref (demux->new_seg_event);
1728 demux->new_seg_event = NULL;
1731 gst_adapter_clear (demux->adapter);
1733 if (demux->audio_codec_data) {
1734 gst_buffer_unref (demux->audio_codec_data);
1735 demux->audio_codec_data = NULL;
1738 if (demux->video_codec_data) {
1739 gst_buffer_unref (demux->video_codec_data);
1740 demux->video_codec_data = NULL;
1743 if (demux->audio_pad) {
1744 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1745 gst_object_unref (demux->audio_pad);
1746 demux->audio_pad = NULL;
1749 if (demux->video_pad) {
1750 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1751 gst_object_unref (demux->video_pad);
1752 demux->video_pad = NULL;
1756 g_array_free (demux->times, TRUE);
1757 demux->times = NULL;
1760 if (demux->filepositions) {
1761 g_array_free (demux->filepositions, TRUE);
1762 demux->filepositions = NULL;
1767 * Create and push a flushing seek event upstream
1770 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1775 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1778 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1779 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1780 GST_SEEK_TYPE_NONE, -1);
1782 res = gst_pad_push_event (demux->sinkpad, event);
1785 demux->offset = offset;
1789 static GstFlowReturn
1790 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1792 GstFlowReturn ret = GST_FLOW_OK;
1793 GstFlvDemux *demux = NULL;
1795 demux = GST_FLV_DEMUX (parent);
1797 GST_LOG_OBJECT (demux,
1798 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
1799 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
1800 GST_BUFFER_OFFSET (buffer));
1802 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1803 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1804 demux->state = FLV_STATE_HEADER;
1808 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
1809 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
1810 demux->offset = GST_BUFFER_OFFSET (buffer);
1813 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1814 GST_DEBUG_OBJECT (demux, "Discontinuity");
1815 gst_adapter_clear (demux->adapter);
1818 gst_adapter_push (demux->adapter, buffer);
1820 if (demux->seeking) {
1821 demux->state = FLV_STATE_SEEK;
1822 GST_OBJECT_LOCK (demux);
1823 demux->seeking = FALSE;
1824 GST_OBJECT_UNLOCK (demux);
1828 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1829 if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
1830 || demux->video_linked)) {
1833 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
1838 if (G_UNLIKELY (demux->flushing)) {
1839 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
1840 ret = GST_FLOW_FLUSHING;
1844 switch (demux->state) {
1845 case FLV_STATE_HEADER:
1847 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
1850 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
1852 ret = gst_flv_demux_parse_header (demux, buffer);
1854 gst_buffer_unref (buffer);
1855 demux->offset += FLV_HEADER_SIZE;
1857 demux->state = FLV_STATE_TAG_TYPE;
1863 case FLV_STATE_TAG_TYPE:
1865 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
1868 /* Remember the tag offset in bytes */
1869 demux->cur_tag_offset = demux->offset;
1871 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
1873 ret = gst_flv_demux_parse_tag_type (demux, buffer);
1875 gst_buffer_unref (buffer);
1876 demux->offset += FLV_TAG_TYPE_SIZE;
1878 /* last tag is not an index => no index/don't know where the index is
1879 * seek back to the beginning */
1880 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
1888 case FLV_STATE_TAG_VIDEO:
1890 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1893 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1895 ret = gst_flv_demux_parse_tag_video (demux, buffer);
1897 gst_buffer_unref (buffer);
1898 demux->offset += demux->tag_size;
1900 demux->state = FLV_STATE_TAG_TYPE;
1906 case FLV_STATE_TAG_AUDIO:
1908 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1911 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1913 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
1915 gst_buffer_unref (buffer);
1916 demux->offset += demux->tag_size;
1918 demux->state = FLV_STATE_TAG_TYPE;
1924 case FLV_STATE_TAG_SCRIPT:
1926 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1929 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1931 ret = gst_flv_demux_parse_tag_script (demux, buffer);
1933 gst_buffer_unref (buffer);
1934 demux->offset += demux->tag_size;
1936 demux->state = FLV_STATE_TAG_TYPE;
1938 /* if there's a seek event we're here for the index so if we don't have it
1939 * we seek back to the beginning */
1940 if (demux->seek_event) {
1942 demux->state = FLV_STATE_SEEK;
1952 case FLV_STATE_SEEK:
1958 if (!demux->indexed) {
1959 if (demux->offset == demux->file_size - sizeof (guint32)) {
1960 guint64 seek_offset;
1963 data = gst_adapter_take (demux->adapter, 4);
1967 seek_offset = demux->file_size - sizeof (guint32) -
1968 GST_READ_UINT32_BE (data);
1971 GST_INFO_OBJECT (demux,
1972 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
1974 demux->state = FLV_STATE_TAG_TYPE;
1975 flv_demux_seek_to_offset (demux, seek_offset);
1981 GST_OBJECT_LOCK (demux);
1982 event = demux->seek_event;
1983 demux->seek_event = NULL;
1984 GST_OBJECT_UNLOCK (demux);
1986 /* calculate and perform seek */
1987 if (!flv_demux_handle_seek_push (demux, event))
1990 gst_event_unref (event);
1991 demux->state = FLV_STATE_TAG_TYPE;
1995 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
1999 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2000 /* If either audio or video is linked we return GST_FLOW_OK */
2001 if (demux->audio_linked || demux->video_linked) {
2011 GST_OBJECT_LOCK (demux);
2012 demux->seeking = FALSE;
2013 gst_event_unref (demux->seek_event);
2014 demux->seek_event = NULL;
2015 GST_OBJECT_UNLOCK (demux);
2016 GST_WARNING_OBJECT (demux,
2017 "failed to find an index, seeking back to beginning");
2018 flv_demux_seek_to_offset (demux, 0);
2023 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2024 return GST_FLOW_ERROR;
2029 static GstFlowReturn
2030 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2031 guint size, GstBuffer ** buffer)
2035 ret = gst_pad_pull_range (pad, offset, size, buffer);
2036 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2037 GST_WARNING_OBJECT (demux,
2038 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2039 size, offset, gst_flow_get_name (ret));
2044 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2045 GST_WARNING_OBJECT (demux,
2046 "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
2047 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
2048 gst_buffer_unref (*buffer);
2057 static GstFlowReturn
2058 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2060 GstBuffer *buffer = NULL;
2061 GstFlowReturn ret = GST_FLOW_OK;
2063 /* Store tag offset */
2064 demux->cur_tag_offset = demux->offset;
2066 /* Get the first 4 bytes to identify tag type and size */
2067 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2068 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2071 /* Identify tag type */
2072 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2074 gst_buffer_unref (buffer);
2076 if (G_UNLIKELY (ret != GST_FLOW_OK))
2079 /* Jump over tag type + size */
2080 demux->offset += FLV_TAG_TYPE_SIZE;
2082 /* Pull the whole tag */
2083 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2084 demux->tag_size, &buffer)) != GST_FLOW_OK))
2087 switch (demux->state) {
2088 case FLV_STATE_TAG_VIDEO:
2089 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2091 case FLV_STATE_TAG_AUDIO:
2092 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2094 case FLV_STATE_TAG_SCRIPT:
2095 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2098 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2101 gst_buffer_unref (buffer);
2103 /* Jump over that part we've just parsed */
2104 demux->offset += demux->tag_size;
2106 /* Make sure we reinitialize the tag size */
2107 demux->tag_size = 0;
2109 /* Ready for the next tag */
2110 demux->state = FLV_STATE_TAG_TYPE;
2112 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2113 /* If either audio or video is linked we return GST_FLOW_OK */
2114 if (demux->audio_linked || demux->video_linked) {
2117 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2118 "neither video nor audio are linked");
2126 static GstFlowReturn
2127 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2129 GstBuffer *buffer = NULL;
2130 GstFlowReturn ret = GST_FLOW_OK;
2132 /* Get the first 9 bytes */
2133 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2134 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2137 ret = gst_flv_demux_parse_header (demux, buffer);
2139 gst_buffer_unref (buffer);
2141 /* Jump over the header now */
2142 demux->offset += FLV_HEADER_SIZE;
2143 demux->state = FLV_STATE_TAG_TYPE;
2150 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2153 demux->offset = offset;
2155 /* Tell all the stream we moved to a different position (discont) */
2156 demux->audio_need_discont = TRUE;
2157 demux->video_need_discont = TRUE;
2159 /* next section setup */
2160 demux->from_offset = -1;
2161 demux->audio_done = demux->video_done = FALSE;
2162 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2165 demux->from_offset = -1;
2166 demux->to_offset = G_MAXINT64;
2169 /* If we seeked at the beginning of the file parse the header again */
2170 if (G_UNLIKELY (!demux->offset)) {
2171 demux->state = FLV_STATE_HEADER;
2172 } else { /* or parse a tag */
2173 demux->state = FLV_STATE_TAG_TYPE;
2177 static GstFlowReturn
2178 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2180 GstFlowReturn ret = GST_FLOW_EOS;
2181 GstIndexEntry *entry = NULL;
2183 GST_DEBUG_OBJECT (demux,
2184 "terminated section started at offset %" G_GINT64_FORMAT,
2185 demux->from_offset);
2187 /* we are done if we got all audio and video */
2188 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2189 demux->audio_first_ts < demux->segment.start) &&
2190 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2191 demux->video_first_ts < demux->segment.start))
2194 if (demux->from_offset <= 0)
2197 GST_DEBUG_OBJECT (demux, "locating previous position");
2199 /* locate index entry before previous start position */
2201 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2202 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2203 GST_FORMAT_BYTES, demux->from_offset - 1);
2206 gint64 bytes = 0, time = 0;
2208 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2209 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2211 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2212 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2213 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2215 /* setup for next section */
2216 demux->to_offset = demux->from_offset;
2217 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2225 static GstFlowReturn
2226 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2232 GstClockTime tag_time;
2233 GstFlowReturn ret = GST_FLOW_OK;
2235 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2238 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2239 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2241 old_offset = demux->offset;
2242 demux->offset = pos;
2244 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2245 12, &buffer)) == GST_FLOW_OK) {
2247 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2249 gst_buffer_unref (buffer);
2251 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2254 demux->offset += tag_size;
2257 if (ret == GST_FLOW_EOS) {
2258 /* file ran out, so mark we have complete index */
2259 demux->indexed = TRUE;
2264 demux->offset = old_offset;
2270 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2272 gint64 ret = 0, offset;
2273 size_t tag_size, size;
2274 GstBuffer *buffer = NULL;
2277 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2281 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2282 if (G_UNLIKELY (offset < 4))
2286 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2290 gst_buffer_map (buffer, &map, GST_MAP_READ);
2291 tag_size = GST_READ_UINT32_BE (map.data);
2292 gst_buffer_unmap (buffer, &map);
2293 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2294 gst_buffer_unref (buffer);
2298 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2302 /* a consistency check */
2303 gst_buffer_map (buffer, &map, GST_MAP_READ);
2304 size = GST_READ_UINT24_BE (map.data + 1);
2305 if (size != tag_size - 11) {
2306 gst_buffer_unmap (buffer, &map);
2307 GST_DEBUG_OBJECT (demux,
2308 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2309 ", corrupt or truncated file", size, tag_size - 11);
2313 /* try to update duration with timestamp in any case */
2314 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2316 /* maybe get some more metadata */
2317 if (map.data[0] == 18) {
2318 gst_buffer_unmap (buffer, &map);
2319 gst_buffer_unref (buffer);
2321 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2323 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2325 gst_flv_demux_parse_tag_script (demux, buffer);
2327 gst_buffer_unmap (buffer, &map);
2332 gst_buffer_unref (buffer);
2338 gst_flv_demux_loop (GstPad * pad)
2340 GstFlvDemux *demux = NULL;
2341 GstFlowReturn ret = GST_FLOW_OK;
2343 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2346 switch (demux->state) {
2347 case FLV_STATE_TAG_TYPE:
2348 if (demux->from_offset == -1)
2349 demux->from_offset = demux->offset;
2350 ret = gst_flv_demux_pull_tag (pad, demux);
2351 /* if we have seen real data, we probably passed a possible metadata
2352 * header located at start. So if we do not yet have an index,
2353 * try to pick up metadata (index, duration) at the end */
2354 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2355 (demux->has_video || demux->has_audio)))
2356 demux->file_size = gst_flv_demux_get_metadata (demux);
2358 case FLV_STATE_DONE:
2361 case FLV_STATE_SEEK:
2362 /* seek issued with insufficient index;
2363 * scan for index in task thread from current maximum offset to
2364 * desired time and then perform seek */
2365 /* TODO maybe some buffering message or so to indicate scan progress */
2366 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2368 if (ret != GST_FLOW_OK)
2370 /* position and state arranged by seek,
2371 * also unrefs event */
2372 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2373 demux->seek_event = NULL;
2376 ret = gst_flv_demux_pull_header (pad, demux);
2377 /* index scans start after header */
2378 demux->index_max_pos = demux->offset;
2382 if (demux->segment.rate < 0.0) {
2383 /* check end of section */
2384 if ((gint64) demux->offset >= demux->to_offset ||
2385 demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2386 (demux->audio_done && demux->video_done))
2387 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2389 /* check EOS condition */
2390 if ((demux->segment.stop != -1) &&
2391 (demux->segment.position >= demux->segment.stop)) {
2396 /* pause if something went wrong or at end */
2397 if (G_UNLIKELY (ret != GST_FLOW_OK))
2400 gst_object_unref (demux);
2406 const gchar *reason = gst_flow_get_name (ret);
2408 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2409 gst_pad_pause_task (pad);
2411 if (ret == GST_FLOW_EOS) {
2412 /* handle end-of-stream/segment */
2413 /* so align our position with the end of it, if there is one
2414 * this ensures a subsequent will arrive at correct base/acc time */
2415 if (demux->segment.rate > 0.0 &&
2416 GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2417 demux->segment.position = demux->segment.stop;
2418 else if (demux->segment.rate < 0.0)
2419 demux->segment.position = demux->segment.start;
2421 /* perform EOS logic */
2422 if (!demux->no_more_pads) {
2423 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2424 demux->no_more_pads = TRUE;
2427 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2430 /* for segment playback we need to post when (in stream time)
2431 * we stopped, this is either stop (when set) or the duration. */
2432 if ((stop = demux->segment.stop) == -1)
2433 stop = demux->segment.duration;
2435 if (demux->segment.rate >= 0) {
2436 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2437 gst_element_post_message (GST_ELEMENT_CAST (demux),
2438 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2439 GST_FORMAT_TIME, stop));
2440 } else { /* Reverse playback */
2441 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2443 gst_element_post_message (GST_ELEMENT_CAST (demux),
2444 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2445 GST_FORMAT_TIME, demux->segment.start));
2448 /* normal playback, send EOS to all linked pads */
2449 if (!demux->no_more_pads) {
2450 gst_element_no_more_pads (GST_ELEMENT (demux));
2451 demux->no_more_pads = TRUE;
2454 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2455 if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2456 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2458 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2459 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2460 ("Internal data stream error."),
2461 ("stream stopped, reason %s", reason));
2462 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2464 gst_object_unref (demux);
2470 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2474 GstIndexEntry *entry;
2476 g_return_val_if_fail (segment != NULL, 0);
2478 time = segment->position;
2481 /* Let's check if we have an index entry for that seek time */
2482 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2483 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2484 GST_FORMAT_TIME, time);
2487 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2488 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2490 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2491 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2492 GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2494 /* Key frame seeking */
2495 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2496 /* Adjust the segment so that the keyframe fits in */
2497 if (time < segment->start) {
2498 segment->start = segment->time = time;
2500 segment->position = time;
2503 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2504 GST_TIME_ARGS (segment->start));
2512 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2516 GstSeekType start_type, stop_type;
2519 gboolean update, flush, ret;
2520 GstSegment seeksegment;
2522 gst_event_parse_seek (event, &rate, &format, &flags,
2523 &start_type, &start, &stop_type, &stop);
2525 if (format != GST_FORMAT_TIME)
2528 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2529 /* FIXME : the keyframe flag is never used ! */
2531 /* Work on a copy until we are sure the seek succeeded. */
2532 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2534 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2537 /* Apply the seek to our segment */
2538 gst_segment_do_seek (&seeksegment, rate, format, flags,
2539 start_type, start, stop_type, stop, &update);
2541 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2544 if (flush || seeksegment.position != demux->segment.position) {
2545 /* Do the actual seeking */
2546 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2548 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2549 G_GUINT64_FORMAT, offset);
2550 ret = gst_pad_push_event (demux->sinkpad,
2551 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2552 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2553 offset, GST_SEEK_TYPE_NONE, 0));
2554 if (G_UNLIKELY (!ret)) {
2555 GST_WARNING_OBJECT (demux, "upstream seek failed");
2558 /* Tell all the stream we moved to a different position (discont) */
2559 demux->audio_need_discont = TRUE;
2560 demux->video_need_discont = TRUE;
2566 /* Ok seek succeeded, take the newly configured segment */
2567 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2569 /* Tell all the stream a new segment is needed */
2570 demux->audio_need_segment = TRUE;
2571 demux->video_need_segment = TRUE;
2572 /* Clean any potential newsegment event kept for the streams. The first
2573 * stream needing a new segment will create a new one. */
2574 if (G_UNLIKELY (demux->new_seg_event)) {
2575 gst_event_unref (demux->new_seg_event);
2576 demux->new_seg_event = NULL;
2578 gst_event_unref (event);
2580 ret = gst_pad_push_event (demux->sinkpad, event);
2588 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2589 gst_event_unref (event);
2595 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2599 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2601 if (format != GST_FORMAT_TIME) {
2602 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2603 gst_event_unref (event);
2607 /* First try upstream */
2608 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2609 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2610 gst_event_unref (event);
2614 if (!demux->indexed) {
2615 guint64 seek_offset = 0;
2616 gboolean building_index;
2618 GST_OBJECT_LOCK (demux);
2619 /* handle the seek in the chain function */
2620 demux->seeking = TRUE;
2621 demux->state = FLV_STATE_SEEK;
2623 /* copy the event */
2624 if (demux->seek_event)
2625 gst_event_unref (demux->seek_event);
2626 demux->seek_event = gst_event_ref (event);
2628 /* set the building_index flag so that only one thread can setup the
2629 * structures for index seeking. */
2630 building_index = demux->building_index;
2631 if (!building_index) {
2632 demux->building_index = TRUE;
2633 if (!demux->file_size
2634 && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2635 &demux->file_size)) {
2636 GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2637 GST_OBJECT_UNLOCK (demux);
2641 /* we hope the last tag is a scriptdataobject containing an index
2642 * the size of the last tag is given in the last guint32 bits
2643 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2644 seek_offset = demux->file_size - sizeof (guint32);
2645 GST_DEBUG_OBJECT (demux,
2646 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2648 GST_OBJECT_UNLOCK (demux);
2650 if (!building_index) {
2651 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2653 return flv_demux_seek_to_offset (demux, seek_offset);
2656 /* FIXME: we have to always return true so that we don't block the seek
2658 * Note: maybe it is OK to return true if we're still building the index */
2662 return flv_demux_handle_seek_push (demux, event);
2666 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2671 GstSeekType start_type, stop_type;
2674 gboolean update, flush, ret = FALSE;
2675 GstSegment seeksegment;
2677 gst_event_parse_seek (event, &rate, &format, &flags,
2678 &start_type, &start, &stop_type, &stop);
2680 if (format != GST_FORMAT_TIME)
2683 /* mark seeking thread entering flushing/pausing */
2684 GST_OBJECT_LOCK (demux);
2686 demux->seeking = seeking;
2687 GST_OBJECT_UNLOCK (demux);
2689 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2690 /* FIXME : the keyframe flag is never used */
2693 /* Flush start up and downstream to make sure data flow and loops are
2695 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2696 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2698 /* Pause the pulling task */
2699 gst_pad_pause_task (demux->sinkpad);
2702 /* Take the stream lock */
2703 GST_PAD_STREAM_LOCK (demux->sinkpad);
2706 /* Stop flushing upstream we need to pull */
2707 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2710 /* Work on a copy until we are sure the seek succeeded. */
2711 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2713 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2716 /* Apply the seek to our segment */
2717 gst_segment_do_seek (&seeksegment, rate, format, flags,
2718 start_type, start, stop_type, stop, &update);
2720 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2723 if (flush || seeksegment.position != demux->segment.position) {
2724 /* Do the actual seeking */
2725 /* index is reliable if it is complete or we do not go to far ahead */
2726 if (seeking && !demux->indexed &&
2727 seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2728 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2729 " index only up to %" GST_TIME_FORMAT,
2730 GST_TIME_ARGS (demux->index_max_time));
2731 /* stop flushing for now */
2733 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2734 /* delegate scanning and index building to task thread to avoid
2735 * occupying main (UI) loop */
2736 if (demux->seek_event)
2737 gst_event_unref (demux->seek_event);
2738 demux->seek_event = gst_event_ref (event);
2739 demux->seek_time = seeksegment.position;
2740 demux->state = FLV_STATE_SEEK;
2741 /* do not know about succes yet, but we did care and handled it */
2745 /* now index should be as reliable as it can be for current purpose */
2746 gst_flv_demux_move_to_offset (demux,
2747 gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2754 /* Stop flushing, the sinks are at time 0 now */
2755 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2759 /* Ok seek succeeded, take the newly configured segment */
2760 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2762 /* Notify about the start of a new segment */
2763 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2764 gst_element_post_message (GST_ELEMENT (demux),
2765 gst_message_new_segment_start (GST_OBJECT (demux),
2766 demux->segment.format, demux->segment.position));
2769 /* Tell all the stream a new segment is needed */
2770 demux->audio_need_segment = TRUE;
2771 demux->video_need_segment = TRUE;
2772 /* Clean any potential newsegment event kept for the streams. The first
2773 * stream needing a new segment will create a new one. */
2774 if (G_UNLIKELY (demux->new_seg_event)) {
2775 gst_event_unref (demux->new_seg_event);
2776 demux->new_seg_event = NULL;
2778 if (demux->segment.rate < 0.0) {
2779 /* we can't generate a segment by locking on
2780 * to the first timestamp we see */
2781 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2782 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2783 GST_TIME_ARGS (demux->segment.start),
2784 GST_TIME_ARGS (demux->segment.stop));
2785 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2790 GST_OBJECT_LOCK (demux);
2791 seeking = demux->seeking && !seeking;
2792 demux->seeking = FALSE;
2793 GST_OBJECT_UNLOCK (demux);
2795 /* if we detect an external seek having started (and possibly already having
2796 * flushed), do not restart task to give it a chance.
2797 * Otherwise external one's flushing will take care to pause task */
2799 gst_pad_pause_task (demux->sinkpad);
2801 gst_pad_start_task (demux->sinkpad,
2802 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
2805 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2807 gst_event_unref (event);
2813 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2814 gst_event_unref (event);
2819 /* If we can pull that's prefered */
2821 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
2826 query = gst_query_new_scheduling ();
2828 if (!gst_pad_peer_query (sinkpad, query)) {
2829 gst_query_unref (query);
2833 pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
2834 gst_query_unref (query);
2839 GST_DEBUG_OBJECT (sinkpad, "activating pull");
2840 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
2844 GST_DEBUG_OBJECT (sinkpad, "activating push");
2845 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
2850 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
2851 GstPadMode mode, gboolean active)
2856 demux = GST_FLV_DEMUX (parent);
2859 case GST_PAD_MODE_PUSH:
2860 demux->random_access = FALSE;
2863 case GST_PAD_MODE_PULL:
2865 demux->random_access = TRUE;
2866 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
2869 demux->random_access = FALSE;
2870 res = gst_pad_stop_task (sinkpad);
2881 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
2884 gboolean ret = FALSE;
2886 demux = GST_FLV_DEMUX (parent);
2888 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2890 switch (GST_EVENT_TYPE (event)) {
2891 case GST_EVENT_FLUSH_START:
2892 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
2893 demux->flushing = TRUE;
2894 ret = gst_flv_demux_push_src_event (demux, event);
2896 case GST_EVENT_FLUSH_STOP:
2897 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
2898 gst_flv_demux_flush (demux, TRUE);
2899 ret = gst_flv_demux_push_src_event (demux, event);
2902 GST_DEBUG_OBJECT (demux, "received EOS");
2904 GST_DEBUG_OBJECT (demux, "committing index");
2905 gst_index_commit (demux->index, demux->index_id);
2907 if (!demux->no_more_pads) {
2908 gst_element_no_more_pads (GST_ELEMENT (demux));
2909 demux->no_more_pads = TRUE;
2912 if (!gst_flv_demux_push_src_event (demux, event))
2913 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2916 case GST_EVENT_SEGMENT:
2918 GstSegment in_segment;
2920 GST_DEBUG_OBJECT (demux, "received new segment");
2922 gst_event_copy_segment (event, &in_segment);
2924 if (in_segment.format == GST_FORMAT_TIME) {
2925 /* time segment, this is perfect, copy over the values. */
2926 memcpy (&demux->segment, &in_segment, sizeof (in_segment));
2928 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
2932 ret = gst_flv_demux_push_src_event (demux, event);
2934 /* non-time format */
2935 demux->audio_need_segment = TRUE;
2936 demux->video_need_segment = TRUE;
2938 gst_event_unref (event);
2943 ret = gst_flv_demux_push_src_event (demux, event);
2951 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
2954 gboolean ret = FALSE;
2956 demux = GST_FLV_DEMUX (parent);
2958 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2960 switch (GST_EVENT_TYPE (event)) {
2961 case GST_EVENT_SEEK:
2962 if (demux->random_access) {
2963 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
2965 ret = gst_flv_demux_handle_seek_push (demux, event);
2969 ret = gst_pad_push_event (demux->sinkpad, event);
2977 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
2979 gboolean res = TRUE;
2982 demux = GST_FLV_DEMUX (parent);
2984 switch (GST_QUERY_TYPE (query)) {
2985 case GST_QUERY_DURATION:
2989 gst_query_parse_duration (query, &format, NULL);
2991 /* duration is time only */
2992 if (format != GST_FORMAT_TIME) {
2993 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
2999 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3000 GST_TIME_ARGS (demux->duration));
3002 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3006 case GST_QUERY_POSITION:
3010 gst_query_parse_position (query, &format, NULL);
3012 /* position is time only */
3013 if (format != GST_FORMAT_TIME) {
3014 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3020 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3021 GST_TIME_ARGS (demux->segment.position));
3023 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3028 case GST_QUERY_SEEKING:{
3031 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3033 /* First ask upstream */
3034 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3037 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3044 if (fmt != GST_FORMAT_TIME || !demux->index) {
3045 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3046 } else if (demux->random_access) {
3047 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3050 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3051 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3054 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3055 gst_query_unref (peerquery);
3058 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3061 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3065 case GST_QUERY_LATENCY:
3067 res = gst_pad_query_default (pad, parent, query);
3076 static GstStateChangeReturn
3077 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3080 GstStateChangeReturn ret;
3082 demux = GST_FLV_DEMUX (element);
3084 switch (transition) {
3085 case GST_STATE_CHANGE_READY_TO_PAUSED:
3086 /* If this is our own index destroy it as the
3087 * old entries might be wrong for the new stream */
3088 if (demux->own_index) {
3089 gst_object_unref (demux->index);
3090 demux->index = NULL;
3091 demux->own_index = FALSE;
3094 /* If no index was created, generate one */
3095 if (G_UNLIKELY (!demux->index)) {
3096 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3098 demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3100 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3102 demux->own_index = TRUE;
3104 gst_flv_demux_cleanup (demux);
3110 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3111 if (ret == GST_STATE_CHANGE_FAILURE)
3114 switch (transition) {
3115 case GST_STATE_CHANGE_PAUSED_TO_READY:
3116 gst_flv_demux_cleanup (demux);
3127 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3129 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3131 GST_OBJECT_LOCK (demux);
3133 gst_object_unref (demux->index);
3135 demux->index = gst_object_ref (index);
3136 demux->own_index = FALSE;
3138 demux->index = NULL;
3140 GST_OBJECT_UNLOCK (demux);
3141 /* object lock might be taken again */
3143 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3144 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3149 gst_flv_demux_get_index (GstElement * element)
3151 GstIndex *result = NULL;
3153 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3155 GST_OBJECT_LOCK (demux);
3157 result = gst_object_ref (demux->index);
3158 GST_OBJECT_UNLOCK (demux);
3165 gst_flv_demux_dispose (GObject * object)
3167 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3169 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3171 if (demux->adapter) {
3172 gst_adapter_clear (demux->adapter);
3173 g_object_unref (demux->adapter);
3174 demux->adapter = NULL;
3177 if (demux->taglist) {
3178 gst_tag_list_free (demux->taglist);
3179 demux->taglist = NULL;
3182 if (demux->new_seg_event) {
3183 gst_event_unref (demux->new_seg_event);
3184 demux->new_seg_event = NULL;
3187 if (demux->audio_codec_data) {
3188 gst_buffer_unref (demux->audio_codec_data);
3189 demux->audio_codec_data = NULL;
3192 if (demux->video_codec_data) {
3193 gst_buffer_unref (demux->video_codec_data);
3194 demux->video_codec_data = NULL;
3197 if (demux->audio_pad) {
3198 gst_object_unref (demux->audio_pad);
3199 demux->audio_pad = NULL;
3202 if (demux->video_pad) {
3203 gst_object_unref (demux->video_pad);
3204 demux->video_pad = NULL;
3208 gst_object_unref (demux->index);
3209 demux->index = NULL;
3213 g_array_free (demux->times, TRUE);
3214 demux->times = NULL;
3217 if (demux->filepositions) {
3218 g_array_free (demux->filepositions, TRUE);
3219 demux->filepositions = NULL;
3222 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3226 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3228 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3229 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3231 gobject_class->dispose = gst_flv_demux_dispose;
3233 gstelement_class->change_state =
3234 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3237 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3238 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3241 gst_element_class_add_pad_template (gstelement_class,
3242 gst_static_pad_template_get (&flv_sink_template));
3243 gst_element_class_add_pad_template (gstelement_class,
3244 gst_static_pad_template_get (&audio_src_template));
3245 gst_element_class_add_pad_template (gstelement_class,
3246 gst_static_pad_template_get (&video_src_template));
3247 gst_element_class_set_details_simple (gstelement_class, "FLV Demuxer",
3249 "Demux FLV feeds into digital streams",
3250 "Julien Moutte <julien@moutte.net>");
3254 gst_flv_demux_init (GstFlvDemux * demux)
3257 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3259 gst_pad_set_event_function (demux->sinkpad,
3260 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3261 gst_pad_set_chain_function (demux->sinkpad,
3262 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3263 gst_pad_set_activate_function (demux->sinkpad,
3264 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3265 gst_pad_set_activatemode_function (demux->sinkpad,
3266 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3268 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3270 demux->adapter = gst_adapter_new ();
3271 demux->taglist = gst_tag_list_new_empty ();
3272 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3274 demux->own_index = FALSE;
3276 GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3278 gst_flv_demux_cleanup (demux);
3282 plugin_init (GstPlugin * plugin)
3284 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3286 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3287 gst_flv_demux_get_type ()) ||
3288 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3289 gst_flv_mux_get_type ()))
3295 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3296 "flv", "FLV muxing and demuxing plugin",
3297 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)