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, stream-format = (string) raw, 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 GstIndexAssociation associations[2];
114 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 */
2084 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2085 demux->tag_size, &buffer)) != GST_FLOW_OK))
2088 switch (demux->state) {
2089 case FLV_STATE_TAG_VIDEO:
2090 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2092 case FLV_STATE_TAG_AUDIO:
2093 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2095 case FLV_STATE_TAG_SCRIPT:
2096 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2099 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2102 gst_buffer_unref (buffer);
2104 /* Jump over that part we've just parsed */
2105 demux->offset += demux->tag_size;
2107 /* Make sure we reinitialize the tag size */
2108 demux->tag_size = 0;
2110 /* Ready for the next tag */
2111 demux->state = FLV_STATE_TAG_TYPE;
2113 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2114 /* If either audio or video is linked we return GST_FLOW_OK */
2115 if (demux->audio_linked || demux->video_linked) {
2118 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2119 "neither video nor audio are linked");
2127 static GstFlowReturn
2128 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2130 GstBuffer *buffer = NULL;
2131 GstFlowReturn ret = GST_FLOW_OK;
2133 /* Get the first 9 bytes */
2134 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2135 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2138 ret = gst_flv_demux_parse_header (demux, buffer);
2140 gst_buffer_unref (buffer);
2142 /* Jump over the header now */
2143 demux->offset += FLV_HEADER_SIZE;
2144 demux->state = FLV_STATE_TAG_TYPE;
2151 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2154 demux->offset = offset;
2156 /* Tell all the stream we moved to a different position (discont) */
2157 demux->audio_need_discont = TRUE;
2158 demux->video_need_discont = TRUE;
2160 /* next section setup */
2161 demux->from_offset = -1;
2162 demux->audio_done = demux->video_done = FALSE;
2163 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2166 demux->from_offset = -1;
2167 demux->to_offset = G_MAXINT64;
2170 /* If we seeked at the beginning of the file parse the header again */
2171 if (G_UNLIKELY (!demux->offset)) {
2172 demux->state = FLV_STATE_HEADER;
2173 } else { /* or parse a tag */
2174 demux->state = FLV_STATE_TAG_TYPE;
2178 static GstFlowReturn
2179 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2181 GstFlowReturn ret = GST_FLOW_EOS;
2182 GstIndexEntry *entry = NULL;
2184 GST_DEBUG_OBJECT (demux,
2185 "terminated section started at offset %" G_GINT64_FORMAT,
2186 demux->from_offset);
2188 /* we are done if we got all audio and video */
2189 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2190 demux->audio_first_ts < demux->segment.start) &&
2191 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2192 demux->video_first_ts < demux->segment.start))
2195 if (demux->from_offset <= 0)
2198 GST_DEBUG_OBJECT (demux, "locating previous position");
2200 /* locate index entry before previous start position */
2202 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2203 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2204 GST_FORMAT_BYTES, demux->from_offset - 1);
2207 gint64 bytes = 0, time = 0;
2209 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2210 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2212 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2213 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2214 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2216 /* setup for next section */
2217 demux->to_offset = demux->from_offset;
2218 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2226 static GstFlowReturn
2227 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2233 GstClockTime tag_time;
2234 GstFlowReturn ret = GST_FLOW_OK;
2236 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2239 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2240 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2242 old_offset = demux->offset;
2243 demux->offset = pos;
2246 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2247 12, &buffer)) == GST_FLOW_OK) {
2249 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2251 gst_buffer_unref (buffer);
2254 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2257 demux->offset += tag_size;
2260 if (ret == GST_FLOW_EOS) {
2261 /* file ran out, so mark we have complete index */
2262 demux->indexed = TRUE;
2267 demux->offset = old_offset;
2273 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2275 gint64 ret = 0, offset;
2276 size_t tag_size, size;
2277 GstBuffer *buffer = NULL;
2280 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2284 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2285 if (G_UNLIKELY (offset < 4))
2289 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2293 gst_buffer_map (buffer, &map, GST_MAP_READ);
2294 tag_size = GST_READ_UINT32_BE (map.data);
2295 gst_buffer_unmap (buffer, &map);
2296 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2297 gst_buffer_unref (buffer);
2301 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2305 /* a consistency check */
2306 gst_buffer_map (buffer, &map, GST_MAP_READ);
2307 size = GST_READ_UINT24_BE (map.data + 1);
2308 if (size != tag_size - 11) {
2309 gst_buffer_unmap (buffer, &map);
2310 GST_DEBUG_OBJECT (demux,
2311 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2312 ", corrupt or truncated file", size, tag_size - 11);
2316 /* try to update duration with timestamp in any case */
2317 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2319 /* maybe get some more metadata */
2320 if (map.data[0] == 18) {
2321 gst_buffer_unmap (buffer, &map);
2322 gst_buffer_unref (buffer);
2324 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2326 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2328 gst_flv_demux_parse_tag_script (demux, buffer);
2330 gst_buffer_unmap (buffer, &map);
2335 gst_buffer_unref (buffer);
2341 gst_flv_demux_loop (GstPad * pad)
2343 GstFlvDemux *demux = NULL;
2344 GstFlowReturn ret = GST_FLOW_OK;
2346 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2349 switch (demux->state) {
2350 case FLV_STATE_TAG_TYPE:
2351 if (demux->from_offset == -1)
2352 demux->from_offset = demux->offset;
2353 ret = gst_flv_demux_pull_tag (pad, demux);
2354 /* if we have seen real data, we probably passed a possible metadata
2355 * header located at start. So if we do not yet have an index,
2356 * try to pick up metadata (index, duration) at the end */
2357 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2358 (demux->has_video || demux->has_audio)))
2359 demux->file_size = gst_flv_demux_get_metadata (demux);
2361 case FLV_STATE_DONE:
2364 case FLV_STATE_SEEK:
2365 /* seek issued with insufficient index;
2366 * scan for index in task thread from current maximum offset to
2367 * desired time and then perform seek */
2368 /* TODO maybe some buffering message or so to indicate scan progress */
2369 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2371 if (ret != GST_FLOW_OK)
2373 /* position and state arranged by seek,
2374 * also unrefs event */
2375 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2376 demux->seek_event = NULL;
2379 ret = gst_flv_demux_pull_header (pad, demux);
2380 /* index scans start after header */
2381 demux->index_max_pos = demux->offset;
2385 if (demux->segment.rate < 0.0) {
2386 /* check end of section */
2387 if ((gint64) demux->offset >= demux->to_offset ||
2388 demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2389 (demux->audio_done && demux->video_done))
2390 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2392 /* check EOS condition */
2393 if ((demux->segment.stop != -1) &&
2394 (demux->segment.position >= demux->segment.stop)) {
2399 /* pause if something went wrong or at end */
2400 if (G_UNLIKELY (ret != GST_FLOW_OK))
2403 gst_object_unref (demux);
2409 const gchar *reason = gst_flow_get_name (ret);
2411 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2412 gst_pad_pause_task (pad);
2414 if (ret == GST_FLOW_EOS) {
2415 /* handle end-of-stream/segment */
2416 /* so align our position with the end of it, if there is one
2417 * this ensures a subsequent will arrive at correct base/acc time */
2418 if (demux->segment.rate > 0.0 &&
2419 GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2420 demux->segment.position = demux->segment.stop;
2421 else if (demux->segment.rate < 0.0)
2422 demux->segment.position = demux->segment.start;
2424 /* perform EOS logic */
2425 if (!demux->no_more_pads) {
2426 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2427 demux->no_more_pads = TRUE;
2430 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2433 /* for segment playback we need to post when (in stream time)
2434 * we stopped, this is either stop (when set) or the duration. */
2435 if ((stop = demux->segment.stop) == -1)
2436 stop = demux->segment.duration;
2438 if (demux->segment.rate >= 0) {
2439 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2440 gst_element_post_message (GST_ELEMENT_CAST (demux),
2441 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2442 GST_FORMAT_TIME, stop));
2443 } else { /* Reverse playback */
2444 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2446 gst_element_post_message (GST_ELEMENT_CAST (demux),
2447 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2448 GST_FORMAT_TIME, demux->segment.start));
2451 /* normal playback, send EOS to all linked pads */
2452 if (!demux->no_more_pads) {
2453 gst_element_no_more_pads (GST_ELEMENT (demux));
2454 demux->no_more_pads = TRUE;
2457 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2458 if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2459 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2461 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2462 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2463 ("Internal data stream error."),
2464 ("stream stopped, reason %s", reason));
2465 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2467 gst_object_unref (demux);
2473 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2477 GstIndexEntry *entry;
2479 g_return_val_if_fail (segment != NULL, 0);
2481 time = segment->position;
2484 /* Let's check if we have an index entry for that seek time */
2485 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2486 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2487 GST_FORMAT_TIME, time);
2490 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2491 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2493 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2494 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2495 GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2497 /* Key frame seeking */
2498 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2499 /* Adjust the segment so that the keyframe fits in */
2500 if (time < segment->start) {
2501 segment->start = segment->time = time;
2503 segment->position = time;
2506 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2507 GST_TIME_ARGS (segment->start));
2515 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2519 GstSeekType start_type, stop_type;
2522 gboolean update, flush, ret;
2523 GstSegment seeksegment;
2525 gst_event_parse_seek (event, &rate, &format, &flags,
2526 &start_type, &start, &stop_type, &stop);
2528 if (format != GST_FORMAT_TIME)
2531 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2532 /* FIXME : the keyframe flag is never used ! */
2534 /* Work on a copy until we are sure the seek succeeded. */
2535 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2537 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2540 /* Apply the seek to our segment */
2541 gst_segment_do_seek (&seeksegment, rate, format, flags,
2542 start_type, start, stop_type, stop, &update);
2544 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2547 if (flush || seeksegment.position != demux->segment.position) {
2548 /* Do the actual seeking */
2549 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2551 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2552 G_GUINT64_FORMAT, offset);
2553 ret = gst_pad_push_event (demux->sinkpad,
2554 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2555 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2556 offset, GST_SEEK_TYPE_NONE, 0));
2557 if (G_UNLIKELY (!ret)) {
2558 GST_WARNING_OBJECT (demux, "upstream seek failed");
2561 /* Tell all the stream we moved to a different position (discont) */
2562 demux->audio_need_discont = TRUE;
2563 demux->video_need_discont = TRUE;
2569 /* Ok seek succeeded, take the newly configured segment */
2570 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2572 /* Tell all the stream a new segment is needed */
2573 demux->audio_need_segment = TRUE;
2574 demux->video_need_segment = TRUE;
2575 /* Clean any potential newsegment event kept for the streams. The first
2576 * stream needing a new segment will create a new one. */
2577 if (G_UNLIKELY (demux->new_seg_event)) {
2578 gst_event_unref (demux->new_seg_event);
2579 demux->new_seg_event = NULL;
2581 gst_event_unref (event);
2583 ret = gst_pad_push_event (demux->sinkpad, event);
2591 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2592 gst_event_unref (event);
2598 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2602 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2604 if (format != GST_FORMAT_TIME) {
2605 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2606 gst_event_unref (event);
2610 /* First try upstream */
2611 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2612 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2613 gst_event_unref (event);
2617 if (!demux->indexed) {
2618 guint64 seek_offset = 0;
2619 gboolean building_index;
2621 GST_OBJECT_LOCK (demux);
2622 /* handle the seek in the chain function */
2623 demux->seeking = TRUE;
2624 demux->state = FLV_STATE_SEEK;
2626 /* copy the event */
2627 if (demux->seek_event)
2628 gst_event_unref (demux->seek_event);
2629 demux->seek_event = gst_event_ref (event);
2631 /* set the building_index flag so that only one thread can setup the
2632 * structures for index seeking. */
2633 building_index = demux->building_index;
2634 if (!building_index) {
2635 demux->building_index = TRUE;
2636 if (!demux->file_size
2637 && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2638 &demux->file_size)) {
2639 GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2640 GST_OBJECT_UNLOCK (demux);
2644 /* we hope the last tag is a scriptdataobject containing an index
2645 * the size of the last tag is given in the last guint32 bits
2646 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2647 seek_offset = demux->file_size - sizeof (guint32);
2648 GST_DEBUG_OBJECT (demux,
2649 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2651 GST_OBJECT_UNLOCK (demux);
2653 if (!building_index) {
2654 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2656 return flv_demux_seek_to_offset (demux, seek_offset);
2659 /* FIXME: we have to always return true so that we don't block the seek
2661 * Note: maybe it is OK to return true if we're still building the index */
2665 return flv_demux_handle_seek_push (demux, event);
2669 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2674 GstSeekType start_type, stop_type;
2677 gboolean update, flush, ret = FALSE;
2678 GstSegment seeksegment;
2680 gst_event_parse_seek (event, &rate, &format, &flags,
2681 &start_type, &start, &stop_type, &stop);
2683 if (format != GST_FORMAT_TIME)
2686 /* mark seeking thread entering flushing/pausing */
2687 GST_OBJECT_LOCK (demux);
2689 demux->seeking = seeking;
2690 GST_OBJECT_UNLOCK (demux);
2692 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2693 /* FIXME : the keyframe flag is never used */
2696 /* Flush start up and downstream to make sure data flow and loops are
2698 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2699 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2701 /* Pause the pulling task */
2702 gst_pad_pause_task (demux->sinkpad);
2705 /* Take the stream lock */
2706 GST_PAD_STREAM_LOCK (demux->sinkpad);
2709 /* Stop flushing upstream we need to pull */
2710 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2713 /* Work on a copy until we are sure the seek succeeded. */
2714 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2716 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2719 /* Apply the seek to our segment */
2720 gst_segment_do_seek (&seeksegment, rate, format, flags,
2721 start_type, start, stop_type, stop, &update);
2723 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2726 if (flush || seeksegment.position != demux->segment.position) {
2727 /* Do the actual seeking */
2728 /* index is reliable if it is complete or we do not go to far ahead */
2729 if (seeking && !demux->indexed &&
2730 seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2731 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2732 " index only up to %" GST_TIME_FORMAT,
2733 GST_TIME_ARGS (demux->index_max_time));
2734 /* stop flushing for now */
2736 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2737 /* delegate scanning and index building to task thread to avoid
2738 * occupying main (UI) loop */
2739 if (demux->seek_event)
2740 gst_event_unref (demux->seek_event);
2741 demux->seek_event = gst_event_ref (event);
2742 demux->seek_time = seeksegment.position;
2743 demux->state = FLV_STATE_SEEK;
2744 /* do not know about succes yet, but we did care and handled it */
2748 /* now index should be as reliable as it can be for current purpose */
2749 gst_flv_demux_move_to_offset (demux,
2750 gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2757 /* Stop flushing, the sinks are at time 0 now */
2758 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2762 /* Ok seek succeeded, take the newly configured segment */
2763 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2765 /* Notify about the start of a new segment */
2766 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2767 gst_element_post_message (GST_ELEMENT (demux),
2768 gst_message_new_segment_start (GST_OBJECT (demux),
2769 demux->segment.format, demux->segment.position));
2772 /* Tell all the stream a new segment is needed */
2773 demux->audio_need_segment = TRUE;
2774 demux->video_need_segment = TRUE;
2775 /* Clean any potential newsegment event kept for the streams. The first
2776 * stream needing a new segment will create a new one. */
2777 if (G_UNLIKELY (demux->new_seg_event)) {
2778 gst_event_unref (demux->new_seg_event);
2779 demux->new_seg_event = NULL;
2781 if (demux->segment.rate < 0.0) {
2782 /* we can't generate a segment by locking on
2783 * to the first timestamp we see */
2784 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2785 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2786 GST_TIME_ARGS (demux->segment.start),
2787 GST_TIME_ARGS (demux->segment.stop));
2788 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2793 GST_OBJECT_LOCK (demux);
2794 seeking = demux->seeking && !seeking;
2795 demux->seeking = FALSE;
2796 GST_OBJECT_UNLOCK (demux);
2798 /* if we detect an external seek having started (and possibly already having
2799 * flushed), do not restart task to give it a chance.
2800 * Otherwise external one's flushing will take care to pause task */
2802 gst_pad_pause_task (demux->sinkpad);
2804 gst_pad_start_task (demux->sinkpad,
2805 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
2808 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2810 gst_event_unref (event);
2816 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2817 gst_event_unref (event);
2822 /* If we can pull that's prefered */
2824 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
2829 query = gst_query_new_scheduling ();
2831 if (!gst_pad_peer_query (sinkpad, query)) {
2832 gst_query_unref (query);
2836 pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
2837 gst_query_unref (query);
2842 GST_DEBUG_OBJECT (sinkpad, "activating pull");
2843 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
2847 GST_DEBUG_OBJECT (sinkpad, "activating push");
2848 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
2853 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
2854 GstPadMode mode, gboolean active)
2859 demux = GST_FLV_DEMUX (parent);
2862 case GST_PAD_MODE_PUSH:
2863 demux->random_access = FALSE;
2866 case GST_PAD_MODE_PULL:
2868 demux->random_access = TRUE;
2869 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
2872 demux->random_access = FALSE;
2873 res = gst_pad_stop_task (sinkpad);
2884 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
2887 gboolean ret = FALSE;
2889 demux = GST_FLV_DEMUX (parent);
2891 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2893 switch (GST_EVENT_TYPE (event)) {
2894 case GST_EVENT_FLUSH_START:
2895 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
2896 demux->flushing = TRUE;
2897 ret = gst_flv_demux_push_src_event (demux, event);
2899 case GST_EVENT_FLUSH_STOP:
2900 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
2901 gst_flv_demux_flush (demux, TRUE);
2902 ret = gst_flv_demux_push_src_event (demux, event);
2905 GST_DEBUG_OBJECT (demux, "received EOS");
2907 GST_DEBUG_OBJECT (demux, "committing index");
2908 gst_index_commit (demux->index, demux->index_id);
2910 if (!demux->no_more_pads) {
2911 gst_element_no_more_pads (GST_ELEMENT (demux));
2912 demux->no_more_pads = TRUE;
2915 if (!gst_flv_demux_push_src_event (demux, event))
2916 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2919 case GST_EVENT_SEGMENT:
2921 GstSegment in_segment;
2923 GST_DEBUG_OBJECT (demux, "received new segment");
2925 gst_event_copy_segment (event, &in_segment);
2927 if (in_segment.format == GST_FORMAT_TIME) {
2928 /* time segment, this is perfect, copy over the values. */
2929 memcpy (&demux->segment, &in_segment, sizeof (in_segment));
2931 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
2935 ret = gst_flv_demux_push_src_event (demux, event);
2937 /* non-time format */
2938 demux->audio_need_segment = TRUE;
2939 demux->video_need_segment = TRUE;
2941 gst_event_unref (event);
2946 ret = gst_flv_demux_push_src_event (demux, event);
2954 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
2957 gboolean ret = FALSE;
2959 demux = GST_FLV_DEMUX (parent);
2961 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2963 switch (GST_EVENT_TYPE (event)) {
2964 case GST_EVENT_SEEK:
2965 if (demux->random_access) {
2966 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
2968 ret = gst_flv_demux_handle_seek_push (demux, event);
2972 ret = gst_pad_push_event (demux->sinkpad, event);
2980 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
2982 gboolean res = TRUE;
2985 demux = GST_FLV_DEMUX (parent);
2987 switch (GST_QUERY_TYPE (query)) {
2988 case GST_QUERY_DURATION:
2992 gst_query_parse_duration (query, &format, NULL);
2994 /* duration is time only */
2995 if (format != GST_FORMAT_TIME) {
2996 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
3002 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3003 GST_TIME_ARGS (demux->duration));
3005 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3009 case GST_QUERY_POSITION:
3013 gst_query_parse_position (query, &format, NULL);
3015 /* position is time only */
3016 if (format != GST_FORMAT_TIME) {
3017 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3023 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3024 GST_TIME_ARGS (demux->segment.position));
3026 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3031 case GST_QUERY_SEEKING:{
3034 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3036 /* First ask upstream */
3037 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3040 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3047 if (fmt != GST_FORMAT_TIME || !demux->index) {
3048 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3049 } else if (demux->random_access) {
3050 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3053 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3054 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3057 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3058 gst_query_unref (peerquery);
3061 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3064 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3068 case GST_QUERY_LATENCY:
3070 res = gst_pad_query_default (pad, parent, query);
3079 static GstStateChangeReturn
3080 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3083 GstStateChangeReturn ret;
3085 demux = GST_FLV_DEMUX (element);
3087 switch (transition) {
3088 case GST_STATE_CHANGE_READY_TO_PAUSED:
3089 /* If this is our own index destroy it as the
3090 * old entries might be wrong for the new stream */
3091 if (demux->own_index) {
3092 gst_object_unref (demux->index);
3093 demux->index = NULL;
3094 demux->own_index = FALSE;
3097 /* If no index was created, generate one */
3098 if (G_UNLIKELY (!demux->index)) {
3099 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3101 demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3103 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3105 demux->own_index = TRUE;
3107 gst_flv_demux_cleanup (demux);
3113 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3114 if (ret == GST_STATE_CHANGE_FAILURE)
3117 switch (transition) {
3118 case GST_STATE_CHANGE_PAUSED_TO_READY:
3119 gst_flv_demux_cleanup (demux);
3130 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3132 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3134 GST_OBJECT_LOCK (demux);
3136 gst_object_unref (demux->index);
3138 demux->index = gst_object_ref (index);
3139 demux->own_index = FALSE;
3141 demux->index = NULL;
3143 GST_OBJECT_UNLOCK (demux);
3144 /* object lock might be taken again */
3146 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3147 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3152 gst_flv_demux_get_index (GstElement * element)
3154 GstIndex *result = NULL;
3156 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3158 GST_OBJECT_LOCK (demux);
3160 result = gst_object_ref (demux->index);
3161 GST_OBJECT_UNLOCK (demux);
3168 gst_flv_demux_dispose (GObject * object)
3170 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3172 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3174 if (demux->adapter) {
3175 gst_adapter_clear (demux->adapter);
3176 g_object_unref (demux->adapter);
3177 demux->adapter = NULL;
3180 if (demux->taglist) {
3181 gst_tag_list_free (demux->taglist);
3182 demux->taglist = NULL;
3185 if (demux->new_seg_event) {
3186 gst_event_unref (demux->new_seg_event);
3187 demux->new_seg_event = NULL;
3190 if (demux->audio_codec_data) {
3191 gst_buffer_unref (demux->audio_codec_data);
3192 demux->audio_codec_data = NULL;
3195 if (demux->video_codec_data) {
3196 gst_buffer_unref (demux->video_codec_data);
3197 demux->video_codec_data = NULL;
3200 if (demux->audio_pad) {
3201 gst_object_unref (demux->audio_pad);
3202 demux->audio_pad = NULL;
3205 if (demux->video_pad) {
3206 gst_object_unref (demux->video_pad);
3207 demux->video_pad = NULL;
3211 gst_object_unref (demux->index);
3212 demux->index = NULL;
3216 g_array_free (demux->times, TRUE);
3217 demux->times = NULL;
3220 if (demux->filepositions) {
3221 g_array_free (demux->filepositions, TRUE);
3222 demux->filepositions = NULL;
3225 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3229 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3231 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3232 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3234 gobject_class->dispose = gst_flv_demux_dispose;
3236 gstelement_class->change_state =
3237 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3240 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3241 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3244 gst_element_class_add_pad_template (gstelement_class,
3245 gst_static_pad_template_get (&flv_sink_template));
3246 gst_element_class_add_pad_template (gstelement_class,
3247 gst_static_pad_template_get (&audio_src_template));
3248 gst_element_class_add_pad_template (gstelement_class,
3249 gst_static_pad_template_get (&video_src_template));
3250 gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
3252 "Demux FLV feeds into digital streams",
3253 "Julien Moutte <julien@moutte.net>");
3257 gst_flv_demux_init (GstFlvDemux * demux)
3260 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3262 gst_pad_set_event_function (demux->sinkpad,
3263 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3264 gst_pad_set_chain_function (demux->sinkpad,
3265 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3266 gst_pad_set_activate_function (demux->sinkpad,
3267 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3268 gst_pad_set_activatemode_function (demux->sinkpad,
3269 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3271 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3273 demux->adapter = gst_adapter_new ();
3274 demux->taglist = gst_tag_list_new_empty ();
3275 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3277 demux->own_index = FALSE;
3279 GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3281 gst_flv_demux_cleanup (demux);
3285 plugin_init (GstPlugin * plugin)
3287 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3289 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3290 gst_flv_demux_get_type ()) ||
3291 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3292 gst_flv_mux_get_type ()))
3298 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3299 flv, "FLV muxing and demuxing plugin",
3300 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)