2 * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * SECTION:element-flvdemux
23 * flvdemux demuxes an FLV file into the different contained streams.
26 * <title>Example launch line</title>
28 * gst-launch -v filesrc location=/path/to/flv ! flvdemux ! audioconvert ! autoaudiosink
29 * ]| This pipeline demuxes an FLV file and outputs the contained raw audio streams.
37 #include "gstflvdemux.h"
38 #include "gstflvmux.h"
41 #include <gst/base/gstbytereader.h>
42 #include <gst/pbutils/descriptions.h>
43 #include <gst/pbutils/pbutils.h>
45 /* FIXME: don't rely on own GstIndex */
47 #include "gstmemindex.c"
48 #define GST_ASSOCIATION_FLAG_NONE GST_INDEX_ASSOCIATION_FLAG_NONE
49 #define GST_ASSOCIATION_FLAG_KEY_UNIT GST_INDEX_ASSOCIATION_FLAG_KEY_UNIT
50 #define GST_ASSOCIATION_FLAG_DELTA_UNIT GST_INDEX_ASSOCIATION_FLAG_DELTA_UNIT
52 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
55 GST_STATIC_CAPS ("video/x-flv")
58 static GstStaticPadTemplate audio_src_template =
59 GST_STATIC_PAD_TEMPLATE ("audio",
63 ("audio/x-adpcm, layout = (string) swf, channels = (int) { 1, 2 }, rate = (int) { 5512, 11025, 22050, 44100 }; "
64 "audio/mpeg, mpegversion = (int) 1, layer = (int) 3, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 22050, 44100 }, parsed = (boolean) TRUE; "
65 "audio/mpeg, mpegversion = (int) 4, framed = (boolean) TRUE; "
66 "audio/x-nellymoser, channels = (int) { 1, 2 }, rate = (int) { 5512, 8000, 11025, 16000, 22050, 44100 }; "
67 "audio/x-raw-int, endianness = (int) LITTLE_ENDIAN, channels = (int) { 1, 2 }, width = (int) 8, depth = (int) 8, rate = (int) { 5512, 11025, 22050, 44100 }, signed = (boolean) FALSE; "
68 "audio/x-raw-int, endianness = (int) LITTLE_ENDIAN, channels = (int) { 1, 2 }, width = (int) 16, depth = (int) 16, rate = (int) { 5512, 11025, 22050, 44100 }, signed = (boolean) TRUE; "
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);
649 /* Assuming little endian for 0 (aka endianness of the
650 * system on which the file was created) as most people
651 * are probably using little endian machines */
652 caps = gst_caps_new_simple ("audio/x-raw-int",
653 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
654 "signed", G_TYPE_BOOLEAN, (width == 8) ? FALSE : TRUE,
655 "width", G_TYPE_INT, width, "depth", G_TYPE_INT, width, NULL);
660 caps = gst_caps_new_empty_simple ("audio/x-nellymoser");
664 if (demux->audio_codec_data) {
667 gst_buffer_map (demux->audio_codec_data, &map, GST_MAP_READ);
669 /* use codec-data to extract and verify samplerate */
673 freq_index = GST_READ_UINT16_BE (map.data);
674 freq_index = (freq_index & 0x0780) >> 7;
676 gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
678 if (adjusted_rate && (rate != adjusted_rate)) {
679 GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
682 adjusted_rate = rate;
685 gst_buffer_unmap (demux->audio_codec_data, &map);
688 caps = gst_caps_new_simple ("audio/mpeg",
689 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
690 "stream-format", G_TYPE_STRING, "raw", NULL);
694 caps = gst_caps_new_empty_simple ("audio/x-alaw");
697 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
700 caps = gst_caps_new_empty_simple ("audio/x-speex");
703 GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
706 if (G_UNLIKELY (!caps)) {
707 GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
711 gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
712 "channels", G_TYPE_INT, channels, NULL);
714 if (demux->audio_codec_data) {
715 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
716 demux->audio_codec_data, NULL);
719 ret = gst_pad_set_caps (demux->audio_pad, caps);
721 if (G_LIKELY (ret)) {
722 /* Store the caps we got from tags */
723 demux->audio_codec_tag = codec_tag;
725 demux->channels = channels;
726 demux->width = width;
728 codec_name = gst_pb_utils_get_codec_description (caps);
731 if (demux->taglist == NULL)
732 demux->taglist = gst_tag_list_new_empty ();
733 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
734 GST_TAG_AUDIO_CODEC, codec_name, NULL);
738 GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
739 GST_PTR_FORMAT, caps);
741 GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
742 GST_PTR_FORMAT, caps);
745 gst_caps_unref (caps);
752 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
756 if (demux->audio_pad)
757 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
759 if (demux->video_pad)
760 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
762 gst_event_unref (event);
768 gst_flv_demux_push_tags (GstFlvDemux * demux)
770 if (demux->has_audio && !demux->audio_pad) {
771 GST_DEBUG_OBJECT (demux,
772 "Waiting for audio stream pad to come up before we can push tags");
775 if (demux->has_video && !demux->video_pad) {
776 GST_DEBUG_OBJECT (demux,
777 "Waiting for video stream pad to come up before we can push tags");
780 if (demux->taglist) {
781 GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
783 gst_flv_demux_push_src_event (demux, gst_event_new_tag (demux->taglist));
784 demux->taglist = gst_tag_list_new_empty ();
785 demux->push_tags = FALSE;
790 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, gboolean discont,
791 guint32 * last, GstClockTime * offset)
793 gint32 dpts = pts - *last;
794 if (!discont && ABS (dpts) >= RESYNC_THRESHOLD) {
795 /* Theoretically, we should use substract the duration of the last buffer,
796 but this demuxer sends no durations on buffers, not sure if it cannot
797 know, or just does not care to calculate. */
798 *offset -= dpts * GST_MSECOND;
799 GST_WARNING_OBJECT (demux,
800 "Large pts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
801 GST_TIME_FORMAT "", dpts, GST_TIME_ARGS (*offset));
807 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
809 GstFlowReturn ret = GST_FLOW_OK;
810 guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
811 guint32 codec_data = 0, pts_ext = 0;
817 GST_LOG_OBJECT (demux, "parsing an audio tag");
819 if (demux->no_more_pads && !demux->audio_pad) {
820 GST_WARNING_OBJECT (demux,
821 "Signaled no-more-pads already but had no audio pad -- ignoring");
825 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
828 /* Error out on tags with too small headers */
829 if (gst_buffer_get_size (buffer) < 11) {
830 GST_ERROR_OBJECT (demux, "Too small tag size (%" G_GSIZE_FORMAT ")",
831 gst_buffer_get_size (buffer));
832 return GST_FLOW_ERROR;
835 gst_buffer_map (buffer, &map, GST_MAP_READ);
838 /* Grab information about audio tag */
839 pts = GST_READ_UINT24_BE (data);
840 /* read the pts extension to 32 bits integer */
841 pts_ext = GST_READ_UINT8 (data + 3);
843 pts |= pts_ext << 24;
845 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
846 data[2], data[3], pts);
848 /* Skip the stream id and go directly to the flags */
849 flags = GST_READ_UINT8 (data + 7);
851 /* Silently skip buffers with no data */
864 if ((flags & 0x0C) == 0x0C) {
866 } else if ((flags & 0x0C) == 0x08) {
868 } else if ((flags & 0x0C) == 0x04) {
872 codec_tag = flags >> 4;
873 if (codec_tag == 10) { /* AAC has an extra byte for packet type */
879 /* codec tags with special rates */
880 if (codec_tag == 5 || codec_tag == 14)
882 else if (codec_tag == 4)
885 GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
886 "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
889 /* If we don't have our audio pad created, then create it. */
890 if (G_UNLIKELY (!demux->audio_pad)) {
893 gst_pad_new_from_template (gst_element_class_get_pad_template
894 (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
895 if (G_UNLIKELY (!demux->audio_pad)) {
896 GST_WARNING_OBJECT (demux, "failed creating audio pad");
897 ret = GST_FLOW_ERROR;
901 /* Set functions on the pad */
902 gst_pad_set_query_function (demux->audio_pad,
903 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
904 gst_pad_set_event_function (demux->audio_pad,
905 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
907 gst_pad_use_fixed_caps (demux->audio_pad);
910 gst_pad_set_active (demux->audio_pad, TRUE);
913 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
915 gst_object_unref (demux->audio_pad);
916 demux->audio_pad = NULL;
917 ret = GST_FLOW_ERROR;
920 #ifndef GST_DISABLE_GST_DEBUG
924 caps = gst_pad_get_current_caps (demux->audio_pad);
925 GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
928 gst_caps_unref (caps);
932 /* We need to set caps before adding */
933 gst_element_add_pad (GST_ELEMENT (demux),
934 gst_object_ref (demux->audio_pad));
936 /* We only emit no more pads when we have audio and video. Indeed we can
937 * not trust the FLV header to tell us if there will be only audio or
938 * only video and we would just break discovery of some files */
939 if (demux->audio_pad && demux->video_pad) {
940 GST_DEBUG_OBJECT (demux, "emitting no more pads");
941 gst_element_no_more_pads (GST_ELEMENT (demux));
942 demux->no_more_pads = TRUE;
943 demux->push_tags = TRUE;
947 /* Check if caps have changed */
948 if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
949 codec_tag != demux->audio_codec_tag || width != demux->width)) {
950 GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
953 if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
955 ret = GST_FLOW_ERROR;
960 /* Push taglist if present */
961 if (G_UNLIKELY (demux->push_tags))
962 gst_flv_demux_push_tags (demux);
964 /* Check if we have anything to push */
965 if (demux->tag_data_size <= codec_data) {
966 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
970 /* Create buffer from pad */
971 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
972 7 + codec_data, demux->tag_data_size - codec_data);
974 if (demux->audio_codec_tag == 10) {
975 guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
977 switch (aac_packet_type) {
980 /* AudioSpecificConfig data */
981 GST_LOG_OBJECT (demux, "got an AAC codec data packet");
982 if (demux->audio_codec_data) {
983 gst_buffer_unref (demux->audio_codec_data);
985 demux->audio_codec_data = outbuf;
986 /* Use that buffer data in the caps */
987 gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels, width);
993 GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
996 GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
1001 /* detect (and deem to be resyncs) large pts gaps */
1002 gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
1003 &demux->last_audio_pts, &demux->audio_time_offset);
1005 /* Fill buffer with data */
1006 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
1007 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1008 GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
1009 GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
1011 if (demux->duration == GST_CLOCK_TIME_NONE ||
1012 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1013 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1015 /* Only add audio frames to the index if we have no video,
1016 * and if the index is not yet complete */
1017 if (!demux->has_video && demux->index && !demux->indexed) {
1018 gst_flv_demux_parse_and_add_index_entry (demux,
1019 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
1022 if (G_UNLIKELY (demux->audio_need_discont)) {
1023 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1024 demux->audio_need_discont = FALSE;
1027 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1029 /* Do we need a newsegment event ? */
1030 if (G_UNLIKELY (demux->audio_need_segment)) {
1031 if (!demux->new_seg_event) {
1032 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1033 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1034 GST_TIME_ARGS (demux->segment.position),
1035 GST_TIME_ARGS (demux->segment.stop));
1036 demux->segment.start = demux->segment.time = demux->segment.position;
1037 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1039 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1042 gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1044 demux->audio_need_segment = FALSE;
1047 GST_LOG_OBJECT (demux,
1048 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1049 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1050 gst_buffer_get_size (outbuf),
1051 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1052 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1054 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1055 demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1057 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1058 demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1061 if (G_UNLIKELY (!demux->no_more_pads
1062 && (GST_CLOCK_DIFF (demux->audio_start,
1063 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1064 GST_DEBUG_OBJECT (demux,
1065 "Signalling no-more-pads because no video stream was found"
1066 " after 6 seconds of audio");
1067 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1068 demux->no_more_pads = TRUE;
1069 demux->push_tags = TRUE;
1072 /* Push downstream */
1073 ret = gst_pad_push (demux->audio_pad, outbuf);
1074 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1075 if (demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1076 demux->segment.position > demux->segment.stop) {
1077 /* In reverse playback we can get a GST_FLOW_EOS when
1078 * we are at the end of the segment, so we just need to jump
1079 * back to the previous section. */
1080 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1081 demux->audio_done = TRUE;
1084 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1085 " bytes audio buffer: %s", demux->tag_data_size,
1086 gst_flow_get_name (ret));
1087 if (ret == GST_FLOW_NOT_LINKED) {
1088 demux->audio_linked = FALSE;
1094 demux->audio_linked = TRUE;
1097 gst_buffer_unmap (buffer, &map);
1103 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1105 gboolean ret = FALSE;
1106 GstCaps *caps = NULL;
1107 gchar *codec_name = NULL;
1109 /* Generate caps for that pad */
1110 switch (codec_tag) {
1112 caps = gst_caps_new_empty_simple ("video/x-flash-video");
1115 caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1118 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1121 caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1125 gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1129 GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1132 if (G_UNLIKELY (!caps)) {
1133 GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1137 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1138 demux->par_x, demux->par_y, NULL);
1140 if (G_LIKELY (demux->w)) {
1141 gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1144 if (G_LIKELY (demux->h)) {
1145 gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1148 if (G_LIKELY (demux->framerate)) {
1149 gint num = 0, den = 0;
1151 gst_util_double_to_fraction (demux->framerate, &num, &den);
1152 GST_DEBUG_OBJECT (demux->video_pad,
1153 "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1156 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1159 if (demux->video_codec_data) {
1160 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1161 demux->video_codec_data, NULL);
1164 ret = gst_pad_set_caps (demux->video_pad, caps);
1166 if (G_LIKELY (ret)) {
1167 /* Store the caps we have set */
1168 demux->video_codec_tag = codec_tag;
1170 codec_name = gst_pb_utils_get_codec_description (caps);
1173 if (demux->taglist == NULL)
1174 demux->taglist = gst_tag_list_new_empty ();
1175 gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1176 GST_TAG_VIDEO_CODEC, codec_name, NULL);
1177 g_free (codec_name);
1180 GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1181 GST_PTR_FORMAT, caps);
1183 GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1184 GST_PTR_FORMAT, caps);
1187 gst_caps_unref (caps);
1193 static GstFlowReturn
1194 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1196 GstFlowReturn ret = GST_FLOW_OK;
1197 guint32 pts = 0, codec_data = 1, pts_ext = 0;
1198 gboolean keyframe = FALSE;
1199 guint8 flags = 0, codec_tag = 0;
1204 g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1207 GST_LOG_OBJECT (demux, "parsing a video tag");
1209 if (demux->no_more_pads && !demux->video_pad) {
1210 GST_WARNING_OBJECT (demux,
1211 "Signaled no-more-pads already but had no audio pad -- ignoring");
1215 if (gst_buffer_get_size (buffer) < 12) {
1216 GST_ERROR_OBJECT (demux, "Too small tag size");
1217 return GST_FLOW_ERROR;
1220 gst_buffer_map (buffer, &map, GST_MAP_READ);
1223 /* Grab information about video tag */
1224 pts = GST_READ_UINT24_BE (data);
1225 /* read the pts extension to 32 bits integer */
1226 pts_ext = GST_READ_UINT8 (data + 3);
1228 pts |= pts_ext << 24;
1230 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1231 data[2], data[3], pts);
1233 /* Skip the stream id and go directly to the flags */
1234 flags = GST_READ_UINT8 (data + 7);
1237 if ((flags >> 4) == 1) {
1241 codec_tag = flags & 0x0F;
1242 if (codec_tag == 4 || codec_tag == 5) {
1244 } else if (codec_tag == 7) {
1249 cts = GST_READ_UINT24_BE (data + 9);
1250 cts = (cts + 0xff800000) ^ 0xff800000;
1252 GST_LOG_OBJECT (demux, "got cts %d", cts);
1254 /* avoid negative overflow */
1255 if (cts >= 0 || pts >= -cts)
1259 GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1260 "(flags %02X)", codec_tag, keyframe, flags);
1262 /* If we don't have our video pad created, then create it. */
1263 if (G_UNLIKELY (!demux->video_pad)) {
1265 gst_pad_new_from_template (gst_element_class_get_pad_template
1266 (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1267 if (G_UNLIKELY (!demux->video_pad)) {
1268 GST_WARNING_OBJECT (demux, "failed creating video pad");
1269 ret = GST_FLOW_ERROR;
1273 /* Set functions on the pad */
1274 gst_pad_set_query_function (demux->video_pad,
1275 GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1276 gst_pad_set_event_function (demux->video_pad,
1277 GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1279 gst_pad_use_fixed_caps (demux->video_pad);
1281 /* Make it active */
1282 gst_pad_set_active (demux->video_pad, TRUE);
1284 /* Needs to be active before setting caps */
1285 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1286 gst_object_unref (demux->video_pad);
1287 demux->video_pad = NULL;
1288 ret = GST_FLOW_ERROR;
1292 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1293 * metadata tag that would come later and trigger a caps change */
1294 demux->got_par = FALSE;
1296 #ifndef GST_DISABLE_GST_DEBUG
1300 caps = gst_pad_get_current_caps (demux->video_pad);
1301 GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1304 gst_caps_unref (caps);
1308 /* We need to set caps before adding */
1309 gst_element_add_pad (GST_ELEMENT (demux),
1310 gst_object_ref (demux->video_pad));
1312 /* We only emit no more pads when we have audio and video. Indeed we can
1313 * not trust the FLV header to tell us if there will be only audio or
1314 * only video and we would just break discovery of some files */
1315 if (demux->audio_pad && demux->video_pad) {
1316 GST_DEBUG_OBJECT (demux, "emitting no more pads");
1317 gst_element_no_more_pads (GST_ELEMENT (demux));
1318 demux->no_more_pads = TRUE;
1319 demux->push_tags = TRUE;
1323 /* Check if caps have changed */
1324 if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1326 GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1328 if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1329 ret = GST_FLOW_ERROR;
1333 /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1334 * metadata tag that would come later and trigger a caps change */
1335 demux->got_par = FALSE;
1338 /* Push taglist if present */
1339 if (G_UNLIKELY (demux->push_tags))
1340 gst_flv_demux_push_tags (demux);
1342 /* Check if we have anything to push */
1343 if (demux->tag_data_size <= codec_data) {
1344 GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1348 /* Create buffer from pad */
1349 outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1350 7 + codec_data, demux->tag_data_size - codec_data);
1352 if (demux->video_codec_tag == 7) {
1353 guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1355 switch (avc_packet_type) {
1358 /* AVCDecoderConfigurationRecord data */
1359 GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1360 if (demux->video_codec_data) {
1361 gst_buffer_unref (demux->video_codec_data);
1363 demux->video_codec_data = outbuf;
1364 /* Use that buffer data in the caps */
1365 gst_flv_demux_video_negotiate (demux, codec_tag);
1370 /* H.264 NALU packet */
1371 GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1374 GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1379 /* detect (and deem to be resyncs) large pts gaps */
1380 gst_flv_demux_update_resync (demux, pts, demux->video_need_discont,
1381 &demux->last_video_pts, &demux->video_time_offset);
1383 /* Fill buffer with data */
1384 GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
1385 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1386 GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1387 GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1389 if (demux->duration == GST_CLOCK_TIME_NONE ||
1390 demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1391 demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1394 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1396 if (!demux->indexed && demux->index) {
1397 gst_flv_demux_parse_and_add_index_entry (demux,
1398 GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1401 if (G_UNLIKELY (demux->video_need_discont)) {
1402 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1403 demux->video_need_discont = FALSE;
1406 demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1408 /* Do we need a newsegment event ? */
1409 if (G_UNLIKELY (demux->video_need_segment)) {
1410 if (!demux->new_seg_event) {
1411 GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1412 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1413 GST_TIME_ARGS (demux->segment.position),
1414 GST_TIME_ARGS (demux->segment.stop));
1415 demux->segment.start = demux->segment.time = demux->segment.position;
1416 demux->new_seg_event = gst_event_new_segment (&demux->segment);
1418 GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1421 gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1423 demux->video_need_segment = FALSE;
1426 GST_LOG_OBJECT (demux,
1427 "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1428 " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1429 ", keyframe (%d)", gst_buffer_get_size (outbuf),
1430 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1431 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1434 if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1435 demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1437 if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1438 demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1441 if (G_UNLIKELY (!demux->no_more_pads
1442 && (GST_CLOCK_DIFF (demux->video_start,
1443 GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1444 GST_DEBUG_OBJECT (demux,
1445 "Signalling no-more-pads because no audio stream was found"
1446 " after 6 seconds of video");
1447 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1448 demux->no_more_pads = TRUE;
1449 demux->push_tags = TRUE;
1452 /* Push downstream */
1453 ret = gst_pad_push (demux->video_pad, outbuf);
1455 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1456 if (demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1457 demux->segment.position > demux->segment.stop) {
1458 /* In reverse playback we can get a GST_FLOW_EOS when
1459 * we are at the end of the segment, so we just need to jump
1460 * back to the previous section. */
1461 GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1462 demux->video_done = TRUE;
1465 GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1466 " bytes video buffer: %s", demux->tag_data_size,
1467 gst_flow_get_name (ret));
1468 if (ret == GST_FLOW_NOT_LINKED) {
1469 demux->video_linked = FALSE;
1475 demux->video_linked = TRUE;
1478 gst_buffer_unmap (buffer, &map);
1483 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1484 GstBuffer * buffer, size_t * tag_size)
1486 guint32 pts = 0, pts_ext = 0;
1487 guint32 tag_data_size;
1489 gboolean keyframe = TRUE;
1490 GstClockTime ret = GST_CLOCK_TIME_NONE;
1495 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1496 GST_CLOCK_TIME_NONE);
1498 gst_buffer_map (buffer, &map, GST_MAP_READ);
1504 if (type != 9 && type != 8 && type != 18) {
1505 GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1510 demux->has_video = TRUE;
1512 demux->has_audio = TRUE;
1514 tag_data_size = GST_READ_UINT24_BE (data + 1);
1516 if (size >= tag_data_size + 11 + 4) {
1517 if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1518 GST_WARNING_OBJECT (demux, "Invalid tag size");
1524 *tag_size = tag_data_size + 11 + 4;
1528 GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
1531 /* Grab timestamp of tag tag */
1532 pts = GST_READ_UINT24_BE (data);
1533 /* read the pts extension to 32 bits integer */
1534 pts_ext = GST_READ_UINT8 (data + 3);
1536 pts |= pts_ext << 24;
1541 keyframe = ((data[0] >> 4) == 1);
1544 ret = pts * GST_MSECOND;
1545 GST_LOG_OBJECT (demux, "pts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1547 if (index && demux->index && !demux->indexed && (type == 9 || (type == 8
1548 && !demux->has_video))) {
1549 gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1553 if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1554 demux->duration = ret;
1557 gst_buffer_unmap (buffer, &map);
1561 static GstFlowReturn
1562 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1564 GstFlowReturn ret = GST_FLOW_OK;
1565 guint8 tag_type = 0;
1568 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1570 gst_buffer_map (buffer, &map, GST_MAP_READ);
1572 tag_type = map.data[0];
1576 demux->state = FLV_STATE_TAG_VIDEO;
1577 demux->has_video = TRUE;
1580 demux->state = FLV_STATE_TAG_AUDIO;
1581 demux->has_audio = TRUE;
1584 demux->state = FLV_STATE_TAG_SCRIPT;
1587 GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1590 /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1591 * 4 bytes of previous tag size */
1592 demux->tag_data_size = GST_READ_UINT24_BE (map.data + 1);
1593 demux->tag_size = demux->tag_data_size + 11;
1595 GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1596 demux->tag_data_size);
1598 gst_buffer_unmap (buffer, &map);
1603 static GstFlowReturn
1604 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1606 GstFlowReturn ret = GST_FLOW_OK;
1609 g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1611 gst_buffer_map (buffer, &map, GST_MAP_READ);
1613 /* Check for the FLV tag */
1614 if (map.data[0] == 'F' && map.data[1] == 'L' && map.data[2] == 'V') {
1615 GST_DEBUG_OBJECT (demux, "FLV header detected");
1617 if (G_UNLIKELY (demux->strict)) {
1618 GST_WARNING_OBJECT (demux, "invalid header tag detected");
1624 /* Now look at audio/video flags */
1626 guint8 flags = map.data[4];
1628 demux->has_video = demux->has_audio = FALSE;
1631 GST_DEBUG_OBJECT (demux, "there is a video stream");
1632 demux->has_video = TRUE;
1635 GST_DEBUG_OBJECT (demux, "there is an audio stream");
1636 demux->has_audio = TRUE;
1640 /* do a one-time seekability check */
1641 gst_flv_demux_check_seekability (demux);
1643 /* We don't care about the rest */
1644 demux->need_header = FALSE;
1647 gst_buffer_unmap (buffer, &map);
1653 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1655 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1657 gst_adapter_clear (demux->adapter);
1659 demux->audio_need_discont = TRUE;
1660 demux->video_need_discont = TRUE;
1662 demux->flushing = FALSE;
1664 /* Only in push mode and if we're not during a seek */
1665 if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1666 /* After a flush we expect a tag_type */
1667 demux->state = FLV_STATE_TAG_TYPE;
1668 /* We reset the offset and will get one from first push */
1674 gst_flv_demux_cleanup (GstFlvDemux * demux)
1676 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1678 demux->state = FLV_STATE_HEADER;
1680 demux->flushing = FALSE;
1681 demux->need_header = TRUE;
1682 demux->audio_need_segment = TRUE;
1683 demux->video_need_segment = TRUE;
1684 demux->audio_need_discont = TRUE;
1685 demux->video_need_discont = TRUE;
1687 /* By default we consider them as linked */
1688 demux->audio_linked = TRUE;
1689 demux->video_linked = TRUE;
1691 demux->has_audio = FALSE;
1692 demux->has_video = FALSE;
1693 demux->push_tags = FALSE;
1694 demux->got_par = FALSE;
1696 demux->indexed = FALSE;
1697 demux->upstream_seekable = FALSE;
1698 demux->file_size = 0;
1700 demux->index_max_pos = 0;
1701 demux->index_max_time = 0;
1703 demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1704 demux->last_audio_pts = demux->last_video_pts = 0;
1705 demux->audio_time_offset = demux->video_time_offset = 0;
1707 demux->no_more_pads = FALSE;
1709 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1711 demux->w = demux->h = 0;
1712 demux->framerate = 0.0;
1713 demux->par_x = demux->par_y = 1;
1714 demux->video_offset = 0;
1715 demux->audio_offset = 0;
1716 demux->offset = demux->cur_tag_offset = 0;
1717 demux->tag_size = demux->tag_data_size = 0;
1718 demux->duration = GST_CLOCK_TIME_NONE;
1720 if (demux->new_seg_event) {
1721 gst_event_unref (demux->new_seg_event);
1722 demux->new_seg_event = NULL;
1725 gst_adapter_clear (demux->adapter);
1727 if (demux->audio_codec_data) {
1728 gst_buffer_unref (demux->audio_codec_data);
1729 demux->audio_codec_data = NULL;
1732 if (demux->video_codec_data) {
1733 gst_buffer_unref (demux->video_codec_data);
1734 demux->video_codec_data = NULL;
1737 if (demux->audio_pad) {
1738 gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1739 gst_object_unref (demux->audio_pad);
1740 demux->audio_pad = NULL;
1743 if (demux->video_pad) {
1744 gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1745 gst_object_unref (demux->video_pad);
1746 demux->video_pad = NULL;
1750 g_array_free (demux->times, TRUE);
1751 demux->times = NULL;
1754 if (demux->filepositions) {
1755 g_array_free (demux->filepositions, TRUE);
1756 demux->filepositions = NULL;
1761 * Create and push a flushing seek event upstream
1764 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1769 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1772 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1773 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1774 GST_SEEK_TYPE_NONE, -1);
1776 res = gst_pad_push_event (demux->sinkpad, event);
1779 demux->offset = offset;
1783 static GstFlowReturn
1784 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1786 GstFlowReturn ret = GST_FLOW_OK;
1787 GstFlvDemux *demux = NULL;
1789 demux = GST_FLV_DEMUX (parent);
1791 GST_LOG_OBJECT (demux,
1792 "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
1793 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
1794 GST_BUFFER_OFFSET (buffer));
1796 if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1797 GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1798 demux->state = FLV_STATE_HEADER;
1802 if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
1803 GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
1804 demux->offset = GST_BUFFER_OFFSET (buffer);
1807 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1808 GST_DEBUG_OBJECT (demux, "Discontinuity");
1809 gst_adapter_clear (demux->adapter);
1812 gst_adapter_push (demux->adapter, buffer);
1814 if (demux->seeking) {
1815 demux->state = FLV_STATE_SEEK;
1816 GST_OBJECT_LOCK (demux);
1817 demux->seeking = FALSE;
1818 GST_OBJECT_UNLOCK (demux);
1822 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1823 if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
1824 || demux->video_linked)) {
1827 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
1832 if (G_UNLIKELY (demux->flushing)) {
1833 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
1834 ret = GST_FLOW_WRONG_STATE;
1838 switch (demux->state) {
1839 case FLV_STATE_HEADER:
1841 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
1844 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
1846 ret = gst_flv_demux_parse_header (demux, buffer);
1848 gst_buffer_unref (buffer);
1849 demux->offset += FLV_HEADER_SIZE;
1851 demux->state = FLV_STATE_TAG_TYPE;
1857 case FLV_STATE_TAG_TYPE:
1859 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
1862 /* Remember the tag offset in bytes */
1863 demux->cur_tag_offset = demux->offset;
1865 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
1867 ret = gst_flv_demux_parse_tag_type (demux, buffer);
1869 gst_buffer_unref (buffer);
1870 demux->offset += FLV_TAG_TYPE_SIZE;
1872 /* last tag is not an index => no index/don't know where the index is
1873 * seek back to the beginning */
1874 if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
1882 case FLV_STATE_TAG_VIDEO:
1884 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1887 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1889 ret = gst_flv_demux_parse_tag_video (demux, buffer);
1891 gst_buffer_unref (buffer);
1892 demux->offset += demux->tag_size;
1894 demux->state = FLV_STATE_TAG_TYPE;
1900 case FLV_STATE_TAG_AUDIO:
1902 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1905 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1907 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
1909 gst_buffer_unref (buffer);
1910 demux->offset += demux->tag_size;
1912 demux->state = FLV_STATE_TAG_TYPE;
1918 case FLV_STATE_TAG_SCRIPT:
1920 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1923 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1925 ret = gst_flv_demux_parse_tag_script (demux, buffer);
1927 gst_buffer_unref (buffer);
1928 demux->offset += demux->tag_size;
1930 demux->state = FLV_STATE_TAG_TYPE;
1932 /* if there's a seek event we're here for the index so if we don't have it
1933 * we seek back to the beginning */
1934 if (demux->seek_event) {
1936 demux->state = FLV_STATE_SEEK;
1946 case FLV_STATE_SEEK:
1952 if (!demux->indexed) {
1953 if (demux->offset == demux->file_size - sizeof (guint32)) {
1954 guint64 seek_offset;
1957 data = gst_adapter_take (demux->adapter, 4);
1961 seek_offset = demux->file_size - sizeof (guint32) -
1962 GST_READ_UINT32_BE (data);
1965 GST_INFO_OBJECT (demux,
1966 "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
1968 demux->state = FLV_STATE_TAG_TYPE;
1969 flv_demux_seek_to_offset (demux, seek_offset);
1975 GST_OBJECT_LOCK (demux);
1976 event = demux->seek_event;
1977 demux->seek_event = NULL;
1978 GST_OBJECT_UNLOCK (demux);
1980 /* calculate and perform seek */
1981 if (!flv_demux_handle_seek_push (demux, event))
1984 gst_event_unref (event);
1985 demux->state = FLV_STATE_TAG_TYPE;
1989 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
1993 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
1994 /* If either audio or video is linked we return GST_FLOW_OK */
1995 if (demux->audio_linked || demux->video_linked) {
2005 GST_OBJECT_LOCK (demux);
2006 demux->seeking = FALSE;
2007 gst_event_unref (demux->seek_event);
2008 demux->seek_event = NULL;
2009 GST_OBJECT_UNLOCK (demux);
2010 GST_WARNING_OBJECT (demux,
2011 "failed to find an index, seeking back to beginning");
2012 flv_demux_seek_to_offset (demux, 0);
2017 GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2018 return GST_FLOW_ERROR;
2023 static GstFlowReturn
2024 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2025 guint size, GstBuffer ** buffer)
2029 ret = gst_pad_pull_range (pad, offset, size, buffer);
2030 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2031 GST_WARNING_OBJECT (demux,
2032 "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2033 size, offset, gst_flow_get_name (ret));
2038 if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2039 GST_WARNING_OBJECT (demux,
2040 "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
2041 G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
2042 gst_buffer_unref (*buffer);
2051 static GstFlowReturn
2052 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2054 GstBuffer *buffer = NULL;
2055 GstFlowReturn ret = GST_FLOW_OK;
2057 /* Store tag offset */
2058 demux->cur_tag_offset = demux->offset;
2060 /* Get the first 4 bytes to identify tag type and size */
2061 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2062 FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2065 /* Identify tag type */
2066 ret = gst_flv_demux_parse_tag_type (demux, buffer);
2068 gst_buffer_unref (buffer);
2070 if (G_UNLIKELY (ret != GST_FLOW_OK))
2073 /* Jump over tag type + size */
2074 demux->offset += FLV_TAG_TYPE_SIZE;
2076 /* Pull the whole tag */
2077 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2078 demux->tag_size, &buffer)) != GST_FLOW_OK))
2081 switch (demux->state) {
2082 case FLV_STATE_TAG_VIDEO:
2083 ret = gst_flv_demux_parse_tag_video (demux, buffer);
2085 case FLV_STATE_TAG_AUDIO:
2086 ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2088 case FLV_STATE_TAG_SCRIPT:
2089 ret = gst_flv_demux_parse_tag_script (demux, buffer);
2092 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2095 gst_buffer_unref (buffer);
2097 /* Jump over that part we've just parsed */
2098 demux->offset += demux->tag_size;
2100 /* Make sure we reinitialize the tag size */
2101 demux->tag_size = 0;
2103 /* Ready for the next tag */
2104 demux->state = FLV_STATE_TAG_TYPE;
2106 if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2107 /* If either audio or video is linked we return GST_FLOW_OK */
2108 if (demux->audio_linked || demux->video_linked) {
2111 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2112 "neither video nor audio are linked");
2120 static GstFlowReturn
2121 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2123 GstBuffer *buffer = NULL;
2124 GstFlowReturn ret = GST_FLOW_OK;
2126 /* Get the first 9 bytes */
2127 if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2128 FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2131 ret = gst_flv_demux_parse_header (demux, buffer);
2133 gst_buffer_unref (buffer);
2135 /* Jump over the header now */
2136 demux->offset += FLV_HEADER_SIZE;
2137 demux->state = FLV_STATE_TAG_TYPE;
2144 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2147 demux->offset = offset;
2149 /* Tell all the stream we moved to a different position (discont) */
2150 demux->audio_need_discont = TRUE;
2151 demux->video_need_discont = TRUE;
2153 /* next section setup */
2154 demux->from_offset = -1;
2155 demux->audio_done = demux->video_done = FALSE;
2156 demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2159 demux->from_offset = -1;
2160 demux->to_offset = G_MAXINT64;
2163 /* If we seeked at the beginning of the file parse the header again */
2164 if (G_UNLIKELY (!demux->offset)) {
2165 demux->state = FLV_STATE_HEADER;
2166 } else { /* or parse a tag */
2167 demux->state = FLV_STATE_TAG_TYPE;
2171 static GstFlowReturn
2172 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2174 GstFlowReturn ret = GST_FLOW_EOS;
2175 GstIndexEntry *entry = NULL;
2177 GST_DEBUG_OBJECT (demux,
2178 "terminated section started at offset %" G_GINT64_FORMAT,
2179 demux->from_offset);
2181 /* we are done if we got all audio and video */
2182 if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2183 demux->audio_first_ts < demux->segment.start) &&
2184 (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2185 demux->video_first_ts < demux->segment.start))
2188 if (demux->from_offset <= 0)
2191 GST_DEBUG_OBJECT (demux, "locating previous position");
2193 /* locate index entry before previous start position */
2195 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2196 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2197 GST_FORMAT_BYTES, demux->from_offset - 1);
2202 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2203 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2205 GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2206 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2207 demux->offset - 1, GST_TIME_ARGS (time), bytes);
2209 /* setup for next section */
2210 demux->to_offset = demux->from_offset;
2211 gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2219 static GstFlowReturn
2220 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2226 GstClockTime tag_time;
2227 GstFlowReturn ret = GST_FLOW_OK;
2229 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2232 GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2233 " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2235 old_offset = demux->offset;
2236 demux->offset = pos;
2238 while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2239 12, &buffer)) == GST_FLOW_OK) {
2241 gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2243 gst_buffer_unref (buffer);
2245 if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2248 demux->offset += tag_size;
2251 if (ret == GST_FLOW_EOS) {
2252 /* file ran out, so mark we have complete index */
2253 demux->indexed = TRUE;
2258 demux->offset = old_offset;
2264 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2266 gint64 ret = 0, offset;
2267 size_t tag_size, size;
2268 GstBuffer *buffer = NULL;
2271 if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2275 GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2276 if (G_UNLIKELY (offset < 4))
2280 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2284 gst_buffer_map (buffer, &map, GST_MAP_READ);
2285 tag_size = GST_READ_UINT32_BE (map.data);
2286 gst_buffer_unmap (buffer, &map);
2287 GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2288 gst_buffer_unref (buffer);
2292 if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2296 /* a consistency check */
2297 gst_buffer_map (buffer, &map, GST_MAP_READ);
2298 size = GST_READ_UINT24_BE (map.data + 1);
2299 if (size != tag_size - 11) {
2300 gst_buffer_unmap (buffer, &map);
2301 GST_DEBUG_OBJECT (demux,
2302 "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2303 ", corrupt or truncated file", size, tag_size - 11);
2307 /* try to update duration with timestamp in any case */
2308 gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2310 /* maybe get some more metadata */
2311 if (map.data[0] == 18) {
2312 gst_buffer_unmap (buffer, &map);
2313 gst_buffer_unref (buffer);
2315 GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2317 if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2319 gst_flv_demux_parse_tag_script (demux, buffer);
2321 gst_buffer_unmap (buffer, &map);
2326 gst_buffer_unref (buffer);
2332 gst_flv_demux_loop (GstPad * pad)
2334 GstFlvDemux *demux = NULL;
2335 GstFlowReturn ret = GST_FLOW_OK;
2337 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2340 switch (demux->state) {
2341 case FLV_STATE_TAG_TYPE:
2342 if (demux->from_offset == -1)
2343 demux->from_offset = demux->offset;
2344 ret = gst_flv_demux_pull_tag (pad, demux);
2345 /* if we have seen real data, we probably passed a possible metadata
2346 * header located at start. So if we do not yet have an index,
2347 * try to pick up metadata (index, duration) at the end */
2348 if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2349 (demux->has_video || demux->has_audio)))
2350 demux->file_size = gst_flv_demux_get_metadata (demux);
2352 case FLV_STATE_DONE:
2355 case FLV_STATE_SEEK:
2356 /* seek issued with insufficient index;
2357 * scan for index in task thread from current maximum offset to
2358 * desired time and then perform seek */
2359 /* TODO maybe some buffering message or so to indicate scan progress */
2360 ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2362 if (ret != GST_FLOW_OK)
2364 /* position and state arranged by seek,
2365 * also unrefs event */
2366 gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2367 demux->seek_event = NULL;
2370 ret = gst_flv_demux_pull_header (pad, demux);
2371 /* index scans start after header */
2372 demux->index_max_pos = demux->offset;
2376 if (demux->segment.rate < 0.0) {
2377 /* check end of section */
2378 if ((gint64) demux->offset >= demux->to_offset ||
2379 demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2380 (demux->audio_done && demux->video_done))
2381 ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2383 /* check EOS condition */
2384 if ((demux->segment.stop != -1) &&
2385 (demux->segment.position >= demux->segment.stop)) {
2390 /* pause if something went wrong or at end */
2391 if (G_UNLIKELY (ret != GST_FLOW_OK))
2394 gst_object_unref (demux);
2400 const gchar *reason = gst_flow_get_name (ret);
2402 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2403 gst_pad_pause_task (pad);
2405 if (ret == GST_FLOW_EOS) {
2406 /* handle end-of-stream/segment */
2407 /* so align our position with the end of it, if there is one
2408 * this ensures a subsequent will arrive at correct base/acc time */
2409 if (demux->segment.rate > 0.0 &&
2410 GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2411 demux->segment.position = demux->segment.stop;
2412 else if (demux->segment.rate < 0.0)
2413 demux->segment.position = demux->segment.start;
2415 /* perform EOS logic */
2416 if (!demux->no_more_pads) {
2417 gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2418 demux->no_more_pads = TRUE;
2421 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2424 /* for segment playback we need to post when (in stream time)
2425 * we stopped, this is either stop (when set) or the duration. */
2426 if ((stop = demux->segment.stop) == -1)
2427 stop = demux->segment.duration;
2429 if (demux->segment.rate >= 0) {
2430 GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2431 gst_element_post_message (GST_ELEMENT_CAST (demux),
2432 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2433 GST_FORMAT_TIME, stop));
2434 } else { /* Reverse playback */
2435 GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2437 gst_element_post_message (GST_ELEMENT_CAST (demux),
2438 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2439 GST_FORMAT_TIME, demux->segment.start));
2442 /* normal playback, send EOS to all linked pads */
2443 if (!demux->no_more_pads) {
2444 gst_element_no_more_pads (GST_ELEMENT (demux));
2445 demux->no_more_pads = TRUE;
2448 GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2449 if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2450 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2452 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2453 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2454 ("Internal data stream error."),
2455 ("stream stopped, reason %s", reason));
2456 gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2458 gst_object_unref (demux);
2464 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2468 GstIndexEntry *entry;
2470 g_return_val_if_fail (segment != NULL, 0);
2472 time = segment->position;
2475 /* Let's check if we have an index entry for that seek time */
2476 entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2477 GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2478 GST_FORMAT_TIME, time);
2481 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2482 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2484 GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2485 " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2486 GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2488 /* Key frame seeking */
2489 if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2490 /* Adjust the segment so that the keyframe fits in */
2491 if (time < segment->start) {
2492 segment->start = segment->time = time;
2494 segment->position = time;
2497 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2498 GST_TIME_ARGS (segment->start));
2506 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2510 GstSeekType start_type, stop_type;
2513 gboolean update, flush, ret;
2514 GstSegment seeksegment;
2516 gst_event_parse_seek (event, &rate, &format, &flags,
2517 &start_type, &start, &stop_type, &stop);
2519 if (format != GST_FORMAT_TIME)
2522 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2523 /* FIXME : the keyframe flag is never used ! */
2525 /* Work on a copy until we are sure the seek succeeded. */
2526 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2528 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2531 /* Apply the seek to our segment */
2532 gst_segment_do_seek (&seeksegment, rate, format, flags,
2533 start_type, start, stop_type, stop, &update);
2535 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2538 if (flush || seeksegment.position != demux->segment.position) {
2539 /* Do the actual seeking */
2540 guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2542 GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2543 G_GUINT64_FORMAT, offset);
2544 ret = gst_pad_push_event (demux->sinkpad,
2545 gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2546 seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2547 offset, GST_SEEK_TYPE_NONE, 0));
2548 if (G_UNLIKELY (!ret)) {
2549 GST_WARNING_OBJECT (demux, "upstream seek failed");
2552 /* Tell all the stream we moved to a different position (discont) */
2553 demux->audio_need_discont = TRUE;
2554 demux->video_need_discont = TRUE;
2560 /* Ok seek succeeded, take the newly configured segment */
2561 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2563 /* Tell all the stream a new segment is needed */
2564 demux->audio_need_segment = TRUE;
2565 demux->video_need_segment = TRUE;
2566 /* Clean any potential newsegment event kept for the streams. The first
2567 * stream needing a new segment will create a new one. */
2568 if (G_UNLIKELY (demux->new_seg_event)) {
2569 gst_event_unref (demux->new_seg_event);
2570 demux->new_seg_event = NULL;
2572 gst_event_unref (event);
2574 ret = gst_pad_push_event (demux->sinkpad, event);
2582 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2583 gst_event_unref (event);
2589 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2593 gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2595 if (format != GST_FORMAT_TIME) {
2596 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2597 gst_event_unref (event);
2601 /* First try upstream */
2602 if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2603 GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2604 gst_event_unref (event);
2608 if (!demux->indexed) {
2609 guint64 seek_offset = 0;
2610 gboolean building_index;
2612 GST_OBJECT_LOCK (demux);
2613 /* handle the seek in the chain function */
2614 demux->seeking = TRUE;
2615 demux->state = FLV_STATE_SEEK;
2617 /* copy the event */
2618 if (demux->seek_event)
2619 gst_event_unref (demux->seek_event);
2620 demux->seek_event = gst_event_ref (event);
2622 /* set the building_index flag so that only one thread can setup the
2623 * structures for index seeking. */
2624 building_index = demux->building_index;
2625 if (!building_index) {
2626 demux->building_index = TRUE;
2627 if (!demux->file_size
2628 && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2629 &demux->file_size)) {
2630 GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2631 GST_OBJECT_UNLOCK (demux);
2635 /* we hope the last tag is a scriptdataobject containing an index
2636 * the size of the last tag is given in the last guint32 bits
2637 * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2638 seek_offset = demux->file_size - sizeof (guint32);
2639 GST_DEBUG_OBJECT (demux,
2640 "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2642 GST_OBJECT_UNLOCK (demux);
2644 if (!building_index) {
2645 GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2647 return flv_demux_seek_to_offset (demux, seek_offset);
2650 /* FIXME: we have to always return true so that we don't block the seek
2652 * Note: maybe it is OK to return true if we're still building the index */
2656 return flv_demux_handle_seek_push (demux, event);
2660 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2665 GstSeekType start_type, stop_type;
2668 gboolean update, flush, ret = FALSE;
2669 GstSegment seeksegment;
2671 gst_event_parse_seek (event, &rate, &format, &flags,
2672 &start_type, &start, &stop_type, &stop);
2674 if (format != GST_FORMAT_TIME)
2677 /* mark seeking thread entering flushing/pausing */
2678 GST_OBJECT_LOCK (demux);
2680 demux->seeking = seeking;
2681 GST_OBJECT_UNLOCK (demux);
2683 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2684 /* FIXME : the keyframe flag is never used */
2687 /* Flush start up and downstream to make sure data flow and loops are
2689 gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2690 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2692 /* Pause the pulling task */
2693 gst_pad_pause_task (demux->sinkpad);
2696 /* Take the stream lock */
2697 GST_PAD_STREAM_LOCK (demux->sinkpad);
2700 /* Stop flushing upstream we need to pull */
2701 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2704 /* Work on a copy until we are sure the seek succeeded. */
2705 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2707 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2710 /* Apply the seek to our segment */
2711 gst_segment_do_seek (&seeksegment, rate, format, flags,
2712 start_type, start, stop_type, stop, &update);
2714 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2717 if (flush || seeksegment.position != demux->segment.position) {
2718 /* Do the actual seeking */
2719 /* index is reliable if it is complete or we do not go to far ahead */
2720 if (seeking && !demux->indexed &&
2721 seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2722 GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2723 " index only up to %" GST_TIME_FORMAT,
2724 GST_TIME_ARGS (demux->index_max_time));
2725 /* stop flushing for now */
2727 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2728 /* delegate scanning and index building to task thread to avoid
2729 * occupying main (UI) loop */
2730 if (demux->seek_event)
2731 gst_event_unref (demux->seek_event);
2732 demux->seek_event = gst_event_ref (event);
2733 demux->seek_time = seeksegment.position;
2734 demux->state = FLV_STATE_SEEK;
2735 /* do not know about succes yet, but we did care and handled it */
2739 /* now index should be as reliable as it can be for current purpose */
2740 gst_flv_demux_move_to_offset (demux,
2741 gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2748 /* Stop flushing, the sinks are at time 0 now */
2749 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2753 /* Ok seek succeeded, take the newly configured segment */
2754 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2756 /* Notify about the start of a new segment */
2757 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2758 gst_element_post_message (GST_ELEMENT (demux),
2759 gst_message_new_segment_start (GST_OBJECT (demux),
2760 demux->segment.format, demux->segment.position));
2763 /* Tell all the stream a new segment is needed */
2764 demux->audio_need_segment = TRUE;
2765 demux->video_need_segment = TRUE;
2766 /* Clean any potential newsegment event kept for the streams. The first
2767 * stream needing a new segment will create a new one. */
2768 if (G_UNLIKELY (demux->new_seg_event)) {
2769 gst_event_unref (demux->new_seg_event);
2770 demux->new_seg_event = NULL;
2772 if (demux->segment.rate < 0.0) {
2773 /* we can't generate a segment by locking on
2774 * to the first timestamp we see */
2775 GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2776 GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2777 GST_TIME_ARGS (demux->segment.start),
2778 GST_TIME_ARGS (demux->segment.stop));
2779 demux->new_seg_event = gst_event_new_segment (&demux->segment);
2784 GST_OBJECT_LOCK (demux);
2785 seeking = demux->seeking && !seeking;
2786 demux->seeking = FALSE;
2787 GST_OBJECT_UNLOCK (demux);
2789 /* if we detect an external seek having started (and possibly already having
2790 * flushed), do not restart task to give it a chance.
2791 * Otherwise external one's flushing will take care to pause task */
2793 gst_pad_pause_task (demux->sinkpad);
2795 gst_pad_start_task (demux->sinkpad,
2796 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
2799 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2801 gst_event_unref (event);
2807 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2808 gst_event_unref (event);
2813 /* If we can pull that's prefered */
2815 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
2820 query = gst_query_new_scheduling ();
2822 if (!gst_pad_peer_query (sinkpad, query)) {
2823 gst_query_unref (query);
2827 pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
2828 gst_query_unref (query);
2833 GST_DEBUG_OBJECT (sinkpad, "activating pull");
2834 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
2838 GST_DEBUG_OBJECT (sinkpad, "activating push");
2839 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
2844 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
2845 GstPadMode mode, gboolean active)
2850 demux = GST_FLV_DEMUX (parent);
2853 case GST_PAD_MODE_PUSH:
2854 demux->random_access = FALSE;
2857 case GST_PAD_MODE_PULL:
2859 demux->random_access = TRUE;
2860 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
2863 demux->random_access = FALSE;
2864 res = gst_pad_stop_task (sinkpad);
2875 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
2878 gboolean ret = FALSE;
2880 demux = GST_FLV_DEMUX (parent);
2882 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2884 switch (GST_EVENT_TYPE (event)) {
2885 case GST_EVENT_FLUSH_START:
2886 GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
2887 demux->flushing = TRUE;
2888 ret = gst_flv_demux_push_src_event (demux, event);
2890 case GST_EVENT_FLUSH_STOP:
2891 GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
2892 gst_flv_demux_flush (demux, TRUE);
2893 ret = gst_flv_demux_push_src_event (demux, event);
2896 GST_DEBUG_OBJECT (demux, "received EOS");
2898 GST_DEBUG_OBJECT (demux, "committing index");
2899 gst_index_commit (demux->index, demux->index_id);
2901 if (!demux->no_more_pads) {
2902 gst_element_no_more_pads (GST_ELEMENT (demux));
2903 demux->no_more_pads = TRUE;
2906 if (!gst_flv_demux_push_src_event (demux, event))
2907 GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2910 case GST_EVENT_SEGMENT:
2912 GstSegment in_segment;
2914 GST_DEBUG_OBJECT (demux, "received new segment");
2916 gst_event_copy_segment (event, &in_segment);
2918 if (in_segment.format == GST_FORMAT_TIME) {
2919 /* time segment, this is perfect, copy over the values. */
2920 memcpy (&demux->segment, &in_segment, sizeof (in_segment));
2922 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
2926 ret = gst_flv_demux_push_src_event (demux, event);
2928 /* non-time format */
2929 demux->audio_need_segment = TRUE;
2930 demux->video_need_segment = TRUE;
2932 gst_event_unref (event);
2937 ret = gst_flv_demux_push_src_event (demux, event);
2945 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
2948 gboolean ret = FALSE;
2950 demux = GST_FLV_DEMUX (parent);
2952 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2954 switch (GST_EVENT_TYPE (event)) {
2955 case GST_EVENT_SEEK:
2956 if (demux->random_access) {
2957 ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
2959 ret = gst_flv_demux_handle_seek_push (demux, event);
2963 ret = gst_pad_push_event (demux->sinkpad, event);
2971 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
2973 gboolean res = TRUE;
2976 demux = GST_FLV_DEMUX (parent);
2978 switch (GST_QUERY_TYPE (query)) {
2979 case GST_QUERY_DURATION:
2983 gst_query_parse_duration (query, &format, NULL);
2985 /* duration is time only */
2986 if (format != GST_FORMAT_TIME) {
2987 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
2993 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
2994 GST_TIME_ARGS (demux->duration));
2996 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3000 case GST_QUERY_POSITION:
3004 gst_query_parse_position (query, &format, NULL);
3006 /* position is time only */
3007 if (format != GST_FORMAT_TIME) {
3008 GST_DEBUG_OBJECT (demux, "position query only supported for time "
3014 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3015 GST_TIME_ARGS (demux->segment.position));
3017 gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3022 case GST_QUERY_SEEKING:{
3025 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3027 /* First ask upstream */
3028 if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3031 gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3038 if (fmt != GST_FORMAT_TIME || !demux->index) {
3039 gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3040 } else if (demux->random_access) {
3041 gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3044 GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3045 gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3048 gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3049 gst_query_unref (peerquery);
3052 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3055 gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3059 case GST_QUERY_LATENCY:
3061 res = gst_pad_peer_query (demux->sinkpad, query);
3070 static GstStateChangeReturn
3071 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3074 GstStateChangeReturn ret;
3076 demux = GST_FLV_DEMUX (element);
3078 switch (transition) {
3079 case GST_STATE_CHANGE_READY_TO_PAUSED:
3080 /* If this is our own index destroy it as the
3081 * old entries might be wrong for the new stream */
3082 if (demux->own_index) {
3083 gst_object_unref (demux->index);
3084 demux->index = NULL;
3085 demux->own_index = FALSE;
3088 /* If no index was created, generate one */
3089 if (G_UNLIKELY (!demux->index)) {
3090 GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3092 demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3094 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3096 demux->own_index = TRUE;
3098 gst_flv_demux_cleanup (demux);
3104 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3105 if (ret == GST_STATE_CHANGE_FAILURE)
3108 switch (transition) {
3109 case GST_STATE_CHANGE_PAUSED_TO_READY:
3110 gst_flv_demux_cleanup (demux);
3121 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3123 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3125 GST_OBJECT_LOCK (demux);
3127 gst_object_unref (demux->index);
3129 demux->index = gst_object_ref (index);
3130 demux->own_index = FALSE;
3132 demux->index = NULL;
3134 GST_OBJECT_UNLOCK (demux);
3135 /* object lock might be taken again */
3137 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3138 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3143 gst_flv_demux_get_index (GstElement * element)
3145 GstIndex *result = NULL;
3147 GstFlvDemux *demux = GST_FLV_DEMUX (element);
3149 GST_OBJECT_LOCK (demux);
3151 result = gst_object_ref (demux->index);
3152 GST_OBJECT_UNLOCK (demux);
3159 gst_flv_demux_dispose (GObject * object)
3161 GstFlvDemux *demux = GST_FLV_DEMUX (object);
3163 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3165 if (demux->adapter) {
3166 gst_adapter_clear (demux->adapter);
3167 g_object_unref (demux->adapter);
3168 demux->adapter = NULL;
3171 if (demux->taglist) {
3172 gst_tag_list_free (demux->taglist);
3173 demux->taglist = NULL;
3176 if (demux->new_seg_event) {
3177 gst_event_unref (demux->new_seg_event);
3178 demux->new_seg_event = NULL;
3181 if (demux->audio_codec_data) {
3182 gst_buffer_unref (demux->audio_codec_data);
3183 demux->audio_codec_data = NULL;
3186 if (demux->video_codec_data) {
3187 gst_buffer_unref (demux->video_codec_data);
3188 demux->video_codec_data = NULL;
3191 if (demux->audio_pad) {
3192 gst_object_unref (demux->audio_pad);
3193 demux->audio_pad = NULL;
3196 if (demux->video_pad) {
3197 gst_object_unref (demux->video_pad);
3198 demux->video_pad = NULL;
3202 gst_object_unref (demux->index);
3203 demux->index = NULL;
3207 g_array_free (demux->times, TRUE);
3208 demux->times = NULL;
3211 if (demux->filepositions) {
3212 g_array_free (demux->filepositions, TRUE);
3213 demux->filepositions = NULL;
3216 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3220 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3222 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3223 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3225 gobject_class->dispose = gst_flv_demux_dispose;
3227 gstelement_class->change_state =
3228 GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3231 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3232 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3235 gst_element_class_add_pad_template (gstelement_class,
3236 gst_static_pad_template_get (&flv_sink_template));
3237 gst_element_class_add_pad_template (gstelement_class,
3238 gst_static_pad_template_get (&audio_src_template));
3239 gst_element_class_add_pad_template (gstelement_class,
3240 gst_static_pad_template_get (&video_src_template));
3241 gst_element_class_set_details_simple (gstelement_class, "FLV Demuxer",
3243 "Demux FLV feeds into digital streams",
3244 "Julien Moutte <julien@moutte.net>");
3248 gst_flv_demux_init (GstFlvDemux * demux)
3251 gst_pad_new_from_static_template (&flv_sink_template, "sink");
3253 gst_pad_set_event_function (demux->sinkpad,
3254 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3255 gst_pad_set_chain_function (demux->sinkpad,
3256 GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3257 gst_pad_set_activate_function (demux->sinkpad,
3258 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3259 gst_pad_set_activatemode_function (demux->sinkpad,
3260 GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3262 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3264 demux->adapter = gst_adapter_new ();
3265 demux->taglist = gst_tag_list_new_empty ();
3266 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3268 demux->own_index = FALSE;
3270 GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3272 gst_flv_demux_cleanup (demux);
3276 plugin_init (GstPlugin * plugin)
3278 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3280 if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3281 gst_flv_demux_get_type ()) ||
3282 !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3283 gst_flv_mux_get_type ()))
3289 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3290 "flv", "FLV muxing and demuxing plugin",
3291 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)