ext, gst: only activate in pull mode if upstream is seekable
[platform/upstream/gst-plugins-good.git] / gst / flv / gstflvdemux.c
1 /* GStreamer
2  * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /**
21  * SECTION:element-flvdemux
22  *
23  * flvdemux demuxes an FLV file into the different contained streams.
24  *
25  * <refsect2>
26  * <title>Example launch line</title>
27  * |[
28  * gst-launch-1.0 -v filesrc location=/path/to/flv ! flvdemux ! audioconvert ! autoaudiosink
29  * ]| This pipeline demuxes an FLV file and outputs the contained raw audio streams.
30  * </refsect2>
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "gstflvdemux.h"
38 #include "gstflvmux.h"
39
40 #include <string.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>
45
46 /* FIXME: don't rely on own GstIndex */
47 #include "gstindex.c"
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
52
53 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
54     GST_PAD_SINK,
55     GST_PAD_ALWAYS,
56     GST_STATIC_CAPS ("video/x-flv")
57     );
58
59 static GstStaticPadTemplate audio_src_template =
60     GST_STATIC_PAD_TEMPLATE ("audio",
61     GST_PAD_SRC,
62     GST_PAD_SOMETIMES,
63     GST_STATIC_CAPS
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 };")
72     );
73
74 static GstStaticPadTemplate video_src_template =
75     GST_STATIC_PAD_TEMPLATE ("video",
76     GST_PAD_SRC,
77     GST_PAD_SOMETIMES,
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;")
82     );
83
84 GST_DEBUG_CATEGORY_STATIC (flvdemux_debug);
85 #define GST_CAT_DEFAULT flvdemux_debug
86
87 #define gst_flv_demux_parent_class parent_class
88 G_DEFINE_TYPE (GstFlvDemux, gst_flv_demux, GST_TYPE_ELEMENT);
89
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
94
95 /* two seconds - consider pts are resynced to another base if this different */
96 #define RESYNC_THRESHOLD 2000
97
98 static gboolean flv_demux_handle_seek_push (GstFlvDemux * demux,
99     GstEvent * event);
100 static gboolean gst_flv_demux_handle_seek_pull (GstFlvDemux * demux,
101     GstEvent * event, gboolean seeking);
102
103 static gboolean gst_flv_demux_query (GstPad * pad, GstObject * parent,
104     GstQuery * query);
105 static gboolean gst_flv_demux_src_event (GstPad * pad, GstObject * parent,
106     GstEvent * event);
107
108 static GstIndex *gst_flv_demux_get_index (GstElement * element);
109
110 static void
111 gst_flv_demux_parse_and_add_index_entry (GstFlvDemux * demux, GstClockTime ts,
112     guint64 pos, gboolean keyframe)
113 {
114   GstIndexAssociation associations[2];
115   GstIndex *index;
116   GstIndexEntry *entry;
117
118   GST_LOG_OBJECT (demux,
119       "adding key=%d association %" GST_TIME_FORMAT "-> %" G_GUINT64_FORMAT,
120       keyframe, GST_TIME_ARGS (ts), pos);
121
122   /* if upstream is not seekable there is no point in building an index */
123   if (!demux->upstream_seekable)
124     return;
125
126   index = gst_flv_demux_get_index (GST_ELEMENT (demux));
127
128   if (!index)
129     return;
130
131   /* entry may already have been added before, avoid adding indefinitely */
132   entry = gst_index_get_assoc_entry (index, demux->index_id,
133       GST_INDEX_LOOKUP_EXACT, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, pos);
134
135   if (entry) {
136 #ifndef GST_DISABLE_GST_DEBUG
137     gint64 time = 0;
138     gboolean key;
139
140     gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
141     key = ! !(GST_INDEX_ASSOC_FLAGS (entry) & GST_ASSOCIATION_FLAG_KEY_UNIT);
142     GST_LOG_OBJECT (demux, "position already mapped to time %" GST_TIME_FORMAT
143         ", keyframe %d", GST_TIME_ARGS (time), key);
144     /* there is not really a way to delete the existing one */
145     if (time != ts || key != ! !keyframe)
146       GST_DEBUG_OBJECT (demux, "metadata mismatch");
147 #endif
148     gst_object_unref (index);
149     return;
150   }
151
152   associations[0].format = GST_FORMAT_TIME;
153   associations[0].value = ts;
154   associations[1].format = GST_FORMAT_BYTES;
155   associations[1].value = pos;
156
157   gst_index_add_associationv (index, demux->index_id,
158       (keyframe) ? GST_ASSOCIATION_FLAG_KEY_UNIT :
159       GST_ASSOCIATION_FLAG_DELTA_UNIT, 2,
160       (const GstIndexAssociation *) &associations);
161
162   if (pos > demux->index_max_pos)
163     demux->index_max_pos = pos;
164   if (ts > demux->index_max_time)
165     demux->index_max_time = ts;
166
167   gst_object_unref (index);
168 }
169
170 static gchar *
171 FLV_GET_STRING (GstByteReader * reader)
172 {
173   guint16 string_size = 0;
174   gchar *string = NULL;
175   const guint8 *str = NULL;
176
177   g_return_val_if_fail (reader != NULL, NULL);
178
179   if (G_UNLIKELY (!gst_byte_reader_get_uint16_be (reader, &string_size)))
180     return NULL;
181
182   if (G_UNLIKELY (string_size > gst_byte_reader_get_remaining (reader)))
183     return NULL;
184
185   string = g_try_malloc0 (string_size + 1);
186   if (G_UNLIKELY (!string)) {
187     return NULL;
188   }
189
190   if (G_UNLIKELY (!gst_byte_reader_get_data (reader, string_size, &str))) {
191     g_free (string);
192     return NULL;
193   }
194
195   memcpy (string, str, string_size);
196   if (!g_utf8_validate (string, string_size, NULL)) {
197     g_free (string);
198     return NULL;
199   }
200
201   return string;
202 }
203
204 static void
205 gst_flv_demux_check_seekability (GstFlvDemux * demux)
206 {
207   GstQuery *query;
208   gint64 start = -1, stop = -1;
209
210   demux->upstream_seekable = FALSE;
211
212   query = gst_query_new_seeking (GST_FORMAT_BYTES);
213   if (!gst_pad_peer_query (demux->sinkpad, query)) {
214     GST_DEBUG_OBJECT (demux, "seeking query failed");
215     gst_query_unref (query);
216     return;
217   }
218
219   gst_query_parse_seeking (query, NULL, &demux->upstream_seekable,
220       &start, &stop);
221
222   gst_query_unref (query);
223
224   /* try harder to query upstream size if we didn't get it the first time */
225   if (demux->upstream_seekable && stop == -1) {
226     GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
227     gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
228   }
229
230   /* if upstream doesn't know the size, it's likely that it's not seekable in
231    * practice even if it technically may be seekable */
232   if (demux->upstream_seekable && (start != 0 || stop <= start)) {
233     GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
234     demux->upstream_seekable = FALSE;
235   }
236
237   GST_DEBUG_OBJECT (demux, "upstream seekable: %d", demux->upstream_seekable);
238 }
239
240 static void
241 parse_flv_demux_parse_date_string (GDate * date, const gchar * s)
242 {
243   g_date_set_parse (date, s);
244   if (g_date_valid (date))
245     return;
246
247   /* "Fri Oct 15 15:13:16 2004" needs to be parsed */
248   {
249     static const gchar *months[] = {
250       "Jan", "Feb", "Mar", "Apr",
251       "May", "Jun", "Jul", "Aug",
252       "Sep", "Oct", "Nov", "Dec"
253     };
254     gchar **tokens = g_strsplit (s, " ", -1);
255     guint64 d;
256     gchar *endptr;
257     gint i;
258
259     if (g_strv_length (tokens) != 5)
260       goto out;
261
262     if (strlen (tokens[1]) != 3)
263       goto out;
264     for (i = 0; i < 12; i++) {
265       if (!strcmp (tokens[1], months[i])) {
266         break;
267       }
268     }
269     if (i == 12)
270       goto out;
271     g_date_set_month (date, i + 1);
272
273     d = g_ascii_strtoull (tokens[2], &endptr, 10);
274     if (d == 0 && *endptr != '\0')
275       goto out;
276
277     g_date_set_day (date, d);
278
279     d = g_ascii_strtoull (tokens[4], &endptr, 10);
280     if (d == 0 && *endptr != '\0')
281       goto out;
282
283     g_date_set_year (date, d);
284
285   out:
286     if (tokens)
287       g_strfreev (tokens);
288   }
289 }
290
291 static gboolean
292 gst_flv_demux_parse_metadata_item (GstFlvDemux * demux, GstByteReader * reader,
293     gboolean * end_marker)
294 {
295   gchar *tag_name = NULL;
296   guint8 tag_type = 0;
297
298   /* Initialize the end_marker flag to FALSE */
299   *end_marker = FALSE;
300
301   /* Name of the tag */
302   tag_name = FLV_GET_STRING (reader);
303   if (G_UNLIKELY (!tag_name)) {
304     GST_WARNING_OBJECT (demux, "failed reading tag name");
305     return FALSE;
306   }
307
308   /* What kind of object is that */
309   if (!gst_byte_reader_get_uint8 (reader, &tag_type))
310     goto error;
311
312   GST_DEBUG_OBJECT (demux, "tag name %s, tag type %d", tag_name, tag_type);
313
314   switch (tag_type) {
315     case 0:                    /* Double */
316     {                           /* Use a union to read the uint64 and then as a double */
317       gdouble d = 0;
318
319       if (!gst_byte_reader_get_float64_be (reader, &d))
320         goto error;
321
322       GST_DEBUG_OBJECT (demux, "%s => (double) %f", tag_name, d);
323
324       if (!strcmp (tag_name, "duration")) {
325         demux->duration = d * GST_SECOND;
326
327         gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
328             GST_TAG_DURATION, demux->duration, NULL);
329       } else if (!strcmp (tag_name, "AspectRatioX")) {
330         demux->par_x = d;
331         demux->got_par = TRUE;
332       } else if (!strcmp (tag_name, "AspectRatioY")) {
333         demux->par_y = d;
334         demux->got_par = TRUE;
335       } else if (!strcmp (tag_name, "width")) {
336         demux->w = d;
337       } else if (!strcmp (tag_name, "height")) {
338         demux->h = d;
339       } else if (!strcmp (tag_name, "framerate")) {
340         demux->framerate = d;
341       } else {
342         GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
343       }
344
345       break;
346     }
347     case 1:                    /* Boolean */
348     {
349       guint8 b = 0;
350
351       if (!gst_byte_reader_get_uint8 (reader, &b))
352         goto error;
353
354       GST_DEBUG_OBJECT (demux, "%s => (boolean) %d", tag_name, b);
355
356       GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
357
358       break;
359     }
360     case 2:                    /* String */
361     {
362       gchar *s = NULL;
363
364       s = FLV_GET_STRING (reader);
365       if (s == NULL)
366         goto error;
367
368       GST_DEBUG_OBJECT (demux, "%s => (string) %s", tag_name, s);
369
370       if (!strcmp (tag_name, "creationdate")) {
371         GDate *date = g_date_new ();
372
373         parse_flv_demux_parse_date_string (date, s);
374         if (!g_date_valid (date)) {
375           GST_DEBUG_OBJECT (demux, "Failed to parse string as date");
376         } else {
377           gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
378               GST_TAG_DATE, date, NULL);
379         }
380         g_date_free (date);
381       } else if (!strcmp (tag_name, "creator")) {
382         gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
383             GST_TAG_ARTIST, s, NULL);
384       } else if (!strcmp (tag_name, "title")) {
385         gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
386             GST_TAG_TITLE, s, NULL);
387       } else if (!strcmp (tag_name, "metadatacreator")) {
388         gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
389             GST_TAG_ENCODER, s, NULL);
390       } else {
391         GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
392       }
393
394       g_free (s);
395
396       break;
397     }
398     case 3:                    /* Object */
399     {
400       gboolean end_of_object_marker = FALSE;
401
402       while (!end_of_object_marker) {
403         gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
404             &end_of_object_marker);
405
406         if (G_UNLIKELY (!ok)) {
407           GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
408           goto error;
409         }
410       }
411
412       break;
413     }
414     case 8:                    /* ECMA array */
415     {
416       guint32 nb_elems = 0;
417       gboolean end_of_object_marker = FALSE;
418
419       if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
420         goto error;
421
422       GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
423           nb_elems);
424
425       while (!end_of_object_marker) {
426         gboolean ok = gst_flv_demux_parse_metadata_item (demux, reader,
427             &end_of_object_marker);
428
429         if (G_UNLIKELY (!ok)) {
430           GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
431           goto error;
432         }
433       }
434
435       break;
436     }
437     case 9:                    /* End marker */
438     {
439       GST_DEBUG_OBJECT (demux, "end marker ?");
440       if (tag_name[0] == '\0') {
441
442         GST_DEBUG_OBJECT (demux, "end marker detected");
443
444         *end_marker = TRUE;
445       }
446
447       break;
448     }
449     case 10:                   /* Array */
450     {
451       guint32 nb_elems = 0;
452
453       if (!gst_byte_reader_get_uint32_be (reader, &nb_elems))
454         goto error;
455
456       GST_DEBUG_OBJECT (demux, "array has %d elements", nb_elems);
457
458       if (!strcmp (tag_name, "times")) {
459         if (demux->times) {
460           g_array_free (demux->times, TRUE);
461         }
462         demux->times = g_array_new (FALSE, TRUE, sizeof (gdouble));
463       } else if (!strcmp (tag_name, "filepositions")) {
464         if (demux->filepositions) {
465           g_array_free (demux->filepositions, TRUE);
466         }
467         demux->filepositions = g_array_new (FALSE, TRUE, sizeof (gdouble));
468       }
469
470       while (nb_elems--) {
471         guint8 elem_type = 0;
472
473         if (!gst_byte_reader_get_uint8 (reader, &elem_type))
474           goto error;
475
476         switch (elem_type) {
477           case 0:
478           {
479             gdouble d;
480
481             if (!gst_byte_reader_get_float64_be (reader, &d))
482               goto error;
483
484             GST_DEBUG_OBJECT (demux, "element is a double %f", d);
485
486             if (!strcmp (tag_name, "times") && demux->times) {
487               g_array_append_val (demux->times, d);
488             } else if (!strcmp (tag_name, "filepositions") &&
489                 demux->filepositions) {
490               g_array_append_val (demux->filepositions, d);
491             }
492             break;
493           }
494           default:
495             GST_WARNING_OBJECT (demux, "unsupported array element type %d",
496                 elem_type);
497         }
498       }
499
500       break;
501     }
502     case 11:                   /* Date */
503     {
504       gdouble d = 0;
505       gint16 i = 0;
506
507       if (!gst_byte_reader_get_float64_be (reader, &d))
508         goto error;
509
510       if (!gst_byte_reader_get_int16_be (reader, &i))
511         goto error;
512
513       GST_DEBUG_OBJECT (demux,
514           "%s => (date as a double) %f, timezone offset %d", tag_name, d, i);
515
516       GST_INFO_OBJECT (demux, "Tag \'%s\' not handled", tag_name);
517
518       break;
519     }
520     default:
521       GST_WARNING_OBJECT (demux, "unsupported tag type %d", tag_type);
522   }
523
524   g_free (tag_name);
525
526   return TRUE;
527
528 error:
529   g_free (tag_name);
530
531   return FALSE;
532 }
533
534 static GstFlowReturn
535 gst_flv_demux_parse_tag_script (GstFlvDemux * demux, GstBuffer * buffer)
536 {
537   GstFlowReturn ret = GST_FLOW_OK;
538   GstByteReader reader;
539   guint8 type = 0;
540   GstMapInfo map;
541
542   g_return_val_if_fail (gst_buffer_get_size (buffer) >= 7, GST_FLOW_ERROR);
543
544   gst_buffer_map (buffer, &map, GST_MAP_READ);
545   gst_byte_reader_init (&reader, map.data, map.size);
546
547   gst_byte_reader_skip_unchecked (&reader, 7);
548
549   GST_LOG_OBJECT (demux, "parsing a script tag");
550
551   if (!gst_byte_reader_get_uint8 (&reader, &type))
552     goto cleanup;
553
554   /* Must be string */
555   if (type == 2) {
556     gchar *function_name;
557     guint i;
558
559     function_name = FLV_GET_STRING (&reader);
560
561     GST_LOG_OBJECT (demux, "function name is %s", GST_STR_NULL (function_name));
562
563     if (function_name != NULL && strcmp (function_name, "onMetaData") == 0) {
564       gboolean end_marker = FALSE;
565       GST_DEBUG_OBJECT (demux, "we have a metadata script object");
566
567       if (!gst_byte_reader_get_uint8 (&reader, &type)) {
568         g_free (function_name);
569         goto cleanup;
570       }
571
572       switch (type) {
573         case 8:
574         {
575           guint32 nb_elems = 0;
576
577           /* ECMA array */
578           if (!gst_byte_reader_get_uint32_be (&reader, &nb_elems)) {
579             g_free (function_name);
580             goto cleanup;
581           }
582
583           /* The number of elements is just a hint, some files have
584              nb_elements == 0 and actually contain items. */
585           GST_DEBUG_OBJECT (demux, "there are approx. %d elements in the array",
586               nb_elems);
587         }
588           /* fallthrough to read data */
589         case 3:
590         {
591           /* Object */
592           while (!end_marker) {
593             gboolean ok =
594                 gst_flv_demux_parse_metadata_item (demux, &reader, &end_marker);
595
596             if (G_UNLIKELY (!ok)) {
597               GST_WARNING_OBJECT (demux, "failed reading a tag, skipping");
598               break;
599             }
600           }
601         }
602           break;
603         default:
604           GST_DEBUG_OBJECT (demux, "Unhandled script data type : %d", type);
605           g_free (function_name);
606           goto cleanup;
607       }
608
609       demux->push_tags = TRUE;
610     }
611
612     g_free (function_name);
613
614     if (demux->times && demux->filepositions) {
615       guint num;
616
617       /* If an index was found, insert associations */
618       num = MIN (demux->times->len, demux->filepositions->len);
619       for (i = 0; i < num; i++) {
620         guint64 time, fileposition;
621
622         time = g_array_index (demux->times, gdouble, i) * GST_SECOND;
623         fileposition = g_array_index (demux->filepositions, gdouble, i);
624         gst_flv_demux_parse_and_add_index_entry (demux, time, fileposition,
625             TRUE);
626       }
627       demux->indexed = TRUE;
628     }
629   }
630
631 cleanup:
632   gst_buffer_unmap (buffer, &map);
633
634   return ret;
635 }
636
637 static gboolean
638 gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
639     guint32 rate, guint32 channels, guint32 width)
640 {
641   GstCaps *caps = NULL;
642   gchar *codec_name = NULL;
643   gboolean ret = FALSE;
644   guint adjusted_rate = rate;
645   gchar *stream_id;
646
647   switch (codec_tag) {
648     case 1:
649       caps = gst_caps_new_simple ("audio/x-adpcm", "layout", G_TYPE_STRING,
650           "swf", NULL);
651       break;
652     case 2:
653     case 14:
654       caps = gst_caps_new_simple ("audio/mpeg",
655           "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
656           "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
657       break;
658     case 0:
659     case 3:
660     {
661       GstAudioFormat format;
662
663       /* Assuming little endian for 0 (aka endianness of the
664        * system on which the file was created) as most people
665        * are probably using little endian machines */
666       format = gst_audio_format_build_integer ((width == 8) ? FALSE : TRUE,
667           G_LITTLE_ENDIAN, width, width);
668
669       caps = gst_caps_new_simple ("audio/x-raw",
670           "format", G_TYPE_STRING, gst_audio_format_to_string (format),
671           "layout", G_TYPE_STRING, "interleaved", NULL);
672       break;
673     }
674     case 4:
675     case 5:
676     case 6:
677       caps = gst_caps_new_empty_simple ("audio/x-nellymoser");
678       break;
679     case 10:
680     {
681       if (demux->audio_codec_data) {
682         GstMapInfo map;
683
684         gst_buffer_map (demux->audio_codec_data, &map, GST_MAP_READ);
685
686         /* use codec-data to extract and verify samplerate */
687         if (map.size >= 2) {
688           gint freq_index;
689
690           freq_index = GST_READ_UINT16_BE (map.data);
691           freq_index = (freq_index & 0x0780) >> 7;
692           adjusted_rate =
693               gst_codec_utils_aac_get_sample_rate_from_index (freq_index);
694
695           if (adjusted_rate && (rate != adjusted_rate)) {
696             GST_LOG_OBJECT (demux, "Ajusting AAC sample rate %d -> %d", rate,
697                 adjusted_rate);
698           } else {
699             adjusted_rate = rate;
700           }
701         }
702         gst_buffer_unmap (demux->audio_codec_data, &map);
703       }
704
705       caps = gst_caps_new_simple ("audio/mpeg",
706           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
707           "stream-format", G_TYPE_STRING, "raw", NULL);
708       break;
709     }
710     case 7:
711       caps = gst_caps_new_empty_simple ("audio/x-alaw");
712       break;
713     case 8:
714       caps = gst_caps_new_empty_simple ("audio/x-mulaw");
715       break;
716     case 11:
717       caps = gst_caps_new_empty_simple ("audio/x-speex");
718       break;
719     default:
720       GST_WARNING_OBJECT (demux, "unsupported audio codec tag %u", codec_tag);
721   }
722
723   if (G_UNLIKELY (!caps)) {
724     GST_WARNING_OBJECT (demux, "failed creating caps for audio pad");
725     goto beach;
726   }
727
728   gst_caps_set_simple (caps, "rate", G_TYPE_INT, adjusted_rate,
729       "channels", G_TYPE_INT, channels, NULL);
730
731   if (demux->audio_codec_data) {
732     gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
733         demux->audio_codec_data, NULL);
734   }
735
736   stream_id =
737       gst_pad_create_stream_id (demux->audio_pad, GST_ELEMENT_CAST (demux),
738       "audio");
739   gst_pad_push_event (demux->audio_pad, gst_event_new_stream_start (stream_id));
740   g_free (stream_id);
741   ret = gst_pad_set_caps (demux->audio_pad, caps);
742
743   if (G_LIKELY (ret)) {
744     /* Store the caps we got from tags */
745     demux->audio_codec_tag = codec_tag;
746     demux->rate = rate;
747     demux->channels = channels;
748     demux->width = width;
749
750     codec_name = gst_pb_utils_get_codec_description (caps);
751
752     if (codec_name) {
753       if (demux->taglist == NULL)
754         demux->taglist = gst_tag_list_new_empty ();
755       gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
756           GST_TAG_AUDIO_CODEC, codec_name, NULL);
757       g_free (codec_name);
758     }
759
760     GST_DEBUG_OBJECT (demux->audio_pad, "successfully negotiated caps %"
761         GST_PTR_FORMAT, caps);
762   } else {
763     GST_WARNING_OBJECT (demux->audio_pad, "failed negotiating caps %"
764         GST_PTR_FORMAT, caps);
765   }
766
767   gst_caps_unref (caps);
768
769 beach:
770   return ret;
771 }
772
773 static gboolean
774 gst_flv_demux_push_src_event (GstFlvDemux * demux, GstEvent * event)
775 {
776   gboolean ret = TRUE;
777
778   if (demux->audio_pad)
779     ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
780
781   if (demux->video_pad)
782     ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
783
784   gst_event_unref (event);
785
786   return ret;
787 }
788
789 static void
790 gst_flv_demux_push_tags (GstFlvDemux * demux)
791 {
792   if (demux->has_audio && !demux->audio_pad) {
793     GST_DEBUG_OBJECT (demux,
794         "Waiting for audio stream pad to come up before we can push tags");
795     return;
796   }
797   if (demux->has_video && !demux->video_pad) {
798     GST_DEBUG_OBJECT (demux,
799         "Waiting for video stream pad to come up before we can push tags");
800     return;
801   }
802   if (demux->taglist) {
803     GST_DEBUG_OBJECT (demux, "pushing tags out %" GST_PTR_FORMAT,
804         demux->taglist);
805     gst_tag_list_set_scope (demux->taglist, GST_TAG_SCOPE_GLOBAL);
806     gst_flv_demux_push_src_event (demux, gst_event_new_tag (demux->taglist));
807     demux->taglist = gst_tag_list_new_empty ();
808     demux->push_tags = FALSE;
809   }
810 }
811
812 static void
813 gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, gboolean discont,
814     guint32 * last, GstClockTime * offset)
815 {
816   gint32 dpts = pts - *last;
817   if (!discont && ABS (dpts) >= RESYNC_THRESHOLD) {
818     /* Theoretically, we should use substract the duration of the last buffer,
819        but this demuxer sends no durations on buffers, not sure if it cannot
820        know, or just does not care to calculate. */
821     *offset -= dpts * GST_MSECOND;
822     GST_WARNING_OBJECT (demux,
823         "Large pts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
824         GST_TIME_FORMAT "", dpts, GST_TIME_ARGS (*offset));
825   }
826   *last = pts;
827 }
828
829 static GstFlowReturn
830 gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
831 {
832   GstFlowReturn ret = GST_FLOW_OK;
833   guint32 pts = 0, codec_tag = 0, rate = 5512, width = 8, channels = 1;
834   guint32 codec_data = 0, pts_ext = 0;
835   guint8 flags = 0;
836   GstMapInfo map;
837   GstBuffer *outbuf;
838   guint8 *data;
839
840   GST_LOG_OBJECT (demux, "parsing an audio tag");
841
842   if (demux->no_more_pads && !demux->audio_pad) {
843     GST_WARNING_OBJECT (demux,
844         "Signaled no-more-pads already but had no audio pad -- ignoring");
845     return GST_FLOW_OK;
846   }
847
848   g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
849       GST_FLOW_ERROR);
850
851   /* Error out on tags with too small headers */
852   if (gst_buffer_get_size (buffer) < 11) {
853     GST_ERROR_OBJECT (demux, "Too small tag size (%" G_GSIZE_FORMAT ")",
854         gst_buffer_get_size (buffer));
855     return GST_FLOW_ERROR;
856   }
857
858   gst_buffer_map (buffer, &map, GST_MAP_READ);
859   data = map.data;
860
861   /* Grab information about audio tag */
862   pts = GST_READ_UINT24_BE (data);
863   /* read the pts extension to 32 bits integer */
864   pts_ext = GST_READ_UINT8 (data + 3);
865   /* Combine them */
866   pts |= pts_ext << 24;
867
868   GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
869       data[2], data[3], pts);
870
871   /* Skip the stream id and go directly to the flags */
872   flags = GST_READ_UINT8 (data + 7);
873
874   /* Silently skip buffers with no data */
875   if (map.size == 11)
876     goto beach;
877
878   /* Channels */
879   if (flags & 0x01) {
880     channels = 2;
881   }
882   /* Width */
883   if (flags & 0x02) {
884     width = 16;
885   }
886   /* Sampling rate */
887   if ((flags & 0x0C) == 0x0C) {
888     rate = 44100;
889   } else if ((flags & 0x0C) == 0x08) {
890     rate = 22050;
891   } else if ((flags & 0x0C) == 0x04) {
892     rate = 11025;
893   }
894   /* Codec tag */
895   codec_tag = flags >> 4;
896   if (codec_tag == 10) {        /* AAC has an extra byte for packet type */
897     codec_data = 2;
898   } else {
899     codec_data = 1;
900   }
901
902   /* codec tags with special rates */
903   if (codec_tag == 5 || codec_tag == 14)
904     rate = 8000;
905   else if (codec_tag == 4)
906     rate = 16000;
907
908   GST_LOG_OBJECT (demux, "audio tag with %d channels, %dHz sampling rate, "
909       "%d bits width, codec tag %u (flags %02X)", channels, rate, width,
910       codec_tag, flags);
911
912   /* If we don't have our audio pad created, then create it. */
913   if (G_UNLIKELY (!demux->audio_pad)) {
914
915     demux->audio_pad =
916         gst_pad_new_from_template (gst_element_class_get_pad_template
917         (GST_ELEMENT_GET_CLASS (demux), "audio"), "audio");
918     if (G_UNLIKELY (!demux->audio_pad)) {
919       GST_WARNING_OBJECT (demux, "failed creating audio pad");
920       ret = GST_FLOW_ERROR;
921       goto beach;
922     }
923
924     /* Set functions on the pad */
925     gst_pad_set_query_function (demux->audio_pad,
926         GST_DEBUG_FUNCPTR (gst_flv_demux_query));
927     gst_pad_set_event_function (demux->audio_pad,
928         GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
929
930     gst_pad_use_fixed_caps (demux->audio_pad);
931
932     /* Make it active */
933     gst_pad_set_active (demux->audio_pad, TRUE);
934
935     /* Negotiate caps */
936     if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
937             width)) {
938       gst_object_unref (demux->audio_pad);
939       demux->audio_pad = NULL;
940       ret = GST_FLOW_ERROR;
941       goto beach;
942     }
943 #ifndef GST_DISABLE_GST_DEBUG
944     {
945       GstCaps *caps;
946
947       caps = gst_pad_get_current_caps (demux->audio_pad);
948       GST_DEBUG_OBJECT (demux, "created audio pad with caps %" GST_PTR_FORMAT,
949           caps);
950       if (caps)
951         gst_caps_unref (caps);
952     }
953 #endif
954
955     /* We need to set caps before adding */
956     gst_element_add_pad (GST_ELEMENT (demux),
957         gst_object_ref (demux->audio_pad));
958
959     /* We only emit no more pads when we have audio and video. Indeed we can
960      * not trust the FLV header to tell us if there will be only audio or
961      * only video and we would just break discovery of some files */
962     if (demux->audio_pad && demux->video_pad) {
963       GST_DEBUG_OBJECT (demux, "emitting no more pads");
964       gst_element_no_more_pads (GST_ELEMENT (demux));
965       demux->no_more_pads = TRUE;
966       demux->push_tags = TRUE;
967     }
968   }
969
970   /* Check if caps have changed */
971   if (G_UNLIKELY (rate != demux->rate || channels != demux->channels ||
972           codec_tag != demux->audio_codec_tag || width != demux->width)) {
973     GST_DEBUG_OBJECT (demux, "audio settings have changed, changing caps");
974
975     /* Negotiate caps */
976     if (!gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels,
977             width)) {
978       ret = GST_FLOW_ERROR;
979       goto beach;
980     }
981   }
982
983   /* Push taglist if present */
984   if (G_UNLIKELY (demux->push_tags))
985     gst_flv_demux_push_tags (demux);
986
987   /* Check if we have anything to push */
988   if (demux->tag_data_size <= codec_data) {
989     GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
990     goto beach;
991   }
992
993   /* Create buffer from pad */
994   outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
995       7 + codec_data, demux->tag_data_size - codec_data);
996
997   if (demux->audio_codec_tag == 10) {
998     guint8 aac_packet_type = GST_READ_UINT8 (data + 8);
999
1000     switch (aac_packet_type) {
1001       case 0:
1002       {
1003         /* AudioSpecificConfig data */
1004         GST_LOG_OBJECT (demux, "got an AAC codec data packet");
1005         if (demux->audio_codec_data) {
1006           gst_buffer_unref (demux->audio_codec_data);
1007         }
1008         demux->audio_codec_data = outbuf;
1009         /* Use that buffer data in the caps */
1010         gst_flv_demux_audio_negotiate (demux, codec_tag, rate, channels, width);
1011         goto beach;
1012         break;
1013       }
1014       case 1:
1015         /* AAC raw packet */
1016         GST_LOG_OBJECT (demux, "got a raw AAC audio packet");
1017         break;
1018       default:
1019         GST_WARNING_OBJECT (demux, "invalid AAC packet type %u",
1020             aac_packet_type);
1021     }
1022   }
1023
1024   /* detect (and deem to be resyncs)  large pts gaps */
1025   gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
1026       &demux->last_audio_pts, &demux->audio_time_offset);
1027
1028   /* Fill buffer with data */
1029   GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
1030   GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1031   GST_BUFFER_OFFSET (outbuf) = demux->audio_offset++;
1032   GST_BUFFER_OFFSET_END (outbuf) = demux->audio_offset;
1033
1034   if (demux->duration == GST_CLOCK_TIME_NONE ||
1035       demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1036     demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1037
1038   /* Only add audio frames to the index if we have no video,
1039    * and if the index is not yet complete */
1040   if (!demux->has_video && !demux->indexed) {
1041     gst_flv_demux_parse_and_add_index_entry (demux,
1042         GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, TRUE);
1043   }
1044
1045   if (G_UNLIKELY (demux->audio_need_discont)) {
1046     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1047     demux->audio_need_discont = FALSE;
1048   }
1049
1050   demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1051
1052   /* Do we need a newsegment event ? */
1053   if (G_UNLIKELY (demux->audio_need_segment)) {
1054     if (!demux->new_seg_event) {
1055       GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1056           GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1057           GST_TIME_ARGS (demux->segment.position),
1058           GST_TIME_ARGS (demux->segment.stop));
1059       demux->segment.start = demux->segment.time = demux->segment.position;
1060       demux->new_seg_event = gst_event_new_segment (&demux->segment);
1061     } else {
1062       GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1063     }
1064
1065     gst_pad_push_event (demux->audio_pad, gst_event_ref (demux->new_seg_event));
1066
1067     demux->audio_need_segment = FALSE;
1068   }
1069
1070   GST_LOG_OBJECT (demux,
1071       "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1072       " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1073       gst_buffer_get_size (outbuf),
1074       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1075       GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1076
1077   if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1078     demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1079   }
1080   if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1081     demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1082   }
1083
1084   if (G_UNLIKELY (!demux->no_more_pads
1085           && (GST_CLOCK_DIFF (demux->audio_start,
1086                   GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1087     GST_DEBUG_OBJECT (demux,
1088         "Signalling no-more-pads because no video stream was found"
1089         " after 6 seconds of audio");
1090     gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1091     demux->no_more_pads = TRUE;
1092     demux->push_tags = TRUE;
1093   }
1094
1095   /* Push downstream */
1096   ret = gst_pad_push (demux->audio_pad, outbuf);
1097   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1098     if (demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1099         demux->segment.position > demux->segment.stop) {
1100       /* In reverse playback we can get a GST_FLOW_EOS when
1101        * we are at the end of the segment, so we just need to jump
1102        * back to the previous section. */
1103       GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1104       demux->audio_done = TRUE;
1105       ret = GST_FLOW_OK;
1106     } else {
1107       GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1108           " bytes audio buffer: %s", demux->tag_data_size,
1109           gst_flow_get_name (ret));
1110       if (ret == GST_FLOW_NOT_LINKED) {
1111         demux->audio_linked = FALSE;
1112       }
1113       goto beach;
1114     }
1115   }
1116
1117   demux->audio_linked = TRUE;
1118
1119 beach:
1120   gst_buffer_unmap (buffer, &map);
1121
1122   return ret;
1123 }
1124
1125 static gboolean
1126 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1127 {
1128   gboolean ret = FALSE;
1129   GstCaps *caps = NULL;
1130   gchar *codec_name = NULL;
1131   gchar *stream_id;
1132
1133   /* Generate caps for that pad */
1134   switch (codec_tag) {
1135     case 2:
1136       caps = gst_caps_new_empty_simple ("video/x-flash-video");
1137       break;
1138     case 3:
1139       caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1140       break;
1141     case 4:
1142       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1143       break;
1144     case 5:
1145       caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1146       break;
1147     case 7:
1148       caps =
1149           gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1150           "avc", NULL);
1151       break;
1152     default:
1153       GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1154   }
1155
1156   if (G_UNLIKELY (!caps)) {
1157     GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1158     goto beach;
1159   }
1160
1161   gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1162       demux->par_x, demux->par_y, NULL);
1163
1164   if (G_LIKELY (demux->w)) {
1165     gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1166   }
1167
1168   if (G_LIKELY (demux->h)) {
1169     gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1170   }
1171
1172   if (G_LIKELY (demux->framerate)) {
1173     gint num = 0, den = 0;
1174
1175     gst_util_double_to_fraction (demux->framerate, &num, &den);
1176     GST_DEBUG_OBJECT (demux->video_pad,
1177         "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1178         num, den);
1179
1180     gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1181   }
1182
1183   if (demux->video_codec_data) {
1184     gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1185         demux->video_codec_data, NULL);
1186   }
1187
1188   stream_id =
1189       gst_pad_create_stream_id (demux->video_pad, GST_ELEMENT_CAST (demux),
1190       "video");
1191   gst_pad_push_event (demux->video_pad, gst_event_new_stream_start (stream_id));
1192   ret = gst_pad_set_caps (demux->video_pad, caps);
1193
1194   if (G_LIKELY (ret)) {
1195     /* Store the caps we have set */
1196     demux->video_codec_tag = codec_tag;
1197
1198     codec_name = gst_pb_utils_get_codec_description (caps);
1199
1200     if (codec_name) {
1201       if (demux->taglist == NULL)
1202         demux->taglist = gst_tag_list_new_empty ();
1203       gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1204           GST_TAG_VIDEO_CODEC, codec_name, NULL);
1205       g_free (codec_name);
1206     }
1207
1208     GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1209         GST_PTR_FORMAT, caps);
1210   } else {
1211     GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1212         GST_PTR_FORMAT, caps);
1213   }
1214
1215   gst_caps_unref (caps);
1216
1217 beach:
1218   return ret;
1219 }
1220
1221 static GstFlowReturn
1222 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1223 {
1224   GstFlowReturn ret = GST_FLOW_OK;
1225   guint32 pts = 0, codec_data = 1, pts_ext = 0;
1226   gboolean keyframe = FALSE;
1227   guint8 flags = 0, codec_tag = 0;
1228   GstBuffer *outbuf;
1229   GstMapInfo map;
1230   guint8 *data;
1231
1232   g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1233       GST_FLOW_ERROR);
1234
1235   GST_LOG_OBJECT (demux, "parsing a video tag");
1236
1237   if (demux->no_more_pads && !demux->video_pad) {
1238     GST_WARNING_OBJECT (demux,
1239         "Signaled no-more-pads already but had no audio pad -- ignoring");
1240     return GST_FLOW_OK;
1241   }
1242
1243   if (gst_buffer_get_size (buffer) < 12) {
1244     GST_ERROR_OBJECT (demux, "Too small tag size");
1245     return GST_FLOW_ERROR;
1246   }
1247
1248   gst_buffer_map (buffer, &map, GST_MAP_READ);
1249   data = map.data;
1250
1251   /* Grab information about video tag */
1252   pts = GST_READ_UINT24_BE (data);
1253   /* read the pts extension to 32 bits integer */
1254   pts_ext = GST_READ_UINT8 (data + 3);
1255   /* Combine them */
1256   pts |= pts_ext << 24;
1257
1258   GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1259       data[2], data[3], pts);
1260
1261   /* Skip the stream id and go directly to the flags */
1262   flags = GST_READ_UINT8 (data + 7);
1263
1264   /* Keyframe */
1265   if ((flags >> 4) == 1) {
1266     keyframe = TRUE;
1267   }
1268   /* Codec tag */
1269   codec_tag = flags & 0x0F;
1270   if (codec_tag == 4 || codec_tag == 5) {
1271     codec_data = 2;
1272   } else if (codec_tag == 7) {
1273     gint32 cts;
1274
1275     codec_data = 5;
1276
1277     cts = GST_READ_UINT24_BE (data + 9);
1278     cts = (cts + 0xff800000) ^ 0xff800000;
1279
1280     GST_LOG_OBJECT (demux, "got cts %d", cts);
1281
1282     /* avoid negative overflow */
1283     if (cts >= 0 || pts >= -cts)
1284       pts += cts;
1285   }
1286
1287   GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1288       "(flags %02X)", codec_tag, keyframe, flags);
1289
1290   /* If we don't have our video pad created, then create it. */
1291   if (G_UNLIKELY (!demux->video_pad)) {
1292     demux->video_pad =
1293         gst_pad_new_from_template (gst_element_class_get_pad_template
1294         (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1295     if (G_UNLIKELY (!demux->video_pad)) {
1296       GST_WARNING_OBJECT (demux, "failed creating video pad");
1297       ret = GST_FLOW_ERROR;
1298       goto beach;
1299     }
1300
1301     /* Set functions on the pad */
1302     gst_pad_set_query_function (demux->video_pad,
1303         GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1304     gst_pad_set_event_function (demux->video_pad,
1305         GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1306
1307     gst_pad_use_fixed_caps (demux->video_pad);
1308
1309     /* Make it active */
1310     gst_pad_set_active (demux->video_pad, TRUE);
1311
1312     /* Needs to be active before setting caps */
1313     if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1314       gst_object_unref (demux->video_pad);
1315       demux->video_pad = NULL;
1316       ret = GST_FLOW_ERROR;
1317       goto beach;
1318     }
1319
1320     /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1321      * metadata tag that would come later and trigger a caps change */
1322     demux->got_par = FALSE;
1323
1324 #ifndef GST_DISABLE_GST_DEBUG
1325     {
1326       GstCaps *caps;
1327
1328       caps = gst_pad_get_current_caps (demux->video_pad);
1329       GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1330           caps);
1331       if (caps)
1332         gst_caps_unref (caps);
1333     }
1334 #endif
1335
1336     /* We need to set caps before adding */
1337     gst_element_add_pad (GST_ELEMENT (demux),
1338         gst_object_ref (demux->video_pad));
1339
1340     /* We only emit no more pads when we have audio and video. Indeed we can
1341      * not trust the FLV header to tell us if there will be only audio or
1342      * only video and we would just break discovery of some files */
1343     if (demux->audio_pad && demux->video_pad) {
1344       GST_DEBUG_OBJECT (demux, "emitting no more pads");
1345       gst_element_no_more_pads (GST_ELEMENT (demux));
1346       demux->no_more_pads = TRUE;
1347       demux->push_tags = TRUE;
1348     }
1349   }
1350
1351   /* Check if caps have changed */
1352   if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1353
1354     GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1355
1356     if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1357       ret = GST_FLOW_ERROR;
1358       goto beach;
1359     }
1360
1361     /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1362      * metadata tag that would come later and trigger a caps change */
1363     demux->got_par = FALSE;
1364   }
1365
1366   /* Push taglist if present */
1367   if (G_UNLIKELY (demux->push_tags))
1368     gst_flv_demux_push_tags (demux);
1369
1370   /* Check if we have anything to push */
1371   if (demux->tag_data_size <= codec_data) {
1372     GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1373     goto beach;
1374   }
1375
1376   /* Create buffer from pad */
1377   outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1378       7 + codec_data, demux->tag_data_size - codec_data);
1379
1380   if (demux->video_codec_tag == 7) {
1381     guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1382
1383     switch (avc_packet_type) {
1384       case 0:
1385       {
1386         /* AVCDecoderConfigurationRecord data */
1387         GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1388         if (demux->video_codec_data) {
1389           gst_buffer_unref (demux->video_codec_data);
1390         }
1391         demux->video_codec_data = outbuf;
1392         /* Use that buffer data in the caps */
1393         gst_flv_demux_video_negotiate (demux, codec_tag);
1394         goto beach;
1395         break;
1396       }
1397       case 1:
1398         /* H.264 NALU packet */
1399         GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1400         break;
1401       default:
1402         GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1403             avc_packet_type);
1404     }
1405   }
1406
1407   /* detect (and deem to be resyncs)  large pts gaps */
1408   gst_flv_demux_update_resync (demux, pts, demux->video_need_discont,
1409       &demux->last_video_pts, &demux->video_time_offset);
1410
1411   /* Fill buffer with data */
1412   GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
1413   GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1414   GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1415   GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1416
1417   if (demux->duration == GST_CLOCK_TIME_NONE ||
1418       demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1419     demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1420
1421   if (!keyframe)
1422     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1423
1424   if (!demux->indexed) {
1425     gst_flv_demux_parse_and_add_index_entry (demux,
1426         GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1427   }
1428
1429   if (G_UNLIKELY (demux->video_need_discont)) {
1430     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1431     demux->video_need_discont = FALSE;
1432   }
1433
1434   demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1435
1436   /* Do we need a newsegment event ? */
1437   if (G_UNLIKELY (demux->video_need_segment)) {
1438     if (!demux->new_seg_event) {
1439       GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1440           GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1441           GST_TIME_ARGS (demux->segment.position),
1442           GST_TIME_ARGS (demux->segment.stop));
1443       demux->segment.start = demux->segment.time = demux->segment.position;
1444       demux->new_seg_event = gst_event_new_segment (&demux->segment);
1445     } else {
1446       GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1447     }
1448
1449     gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1450
1451     demux->video_need_segment = FALSE;
1452   }
1453
1454   GST_LOG_OBJECT (demux,
1455       "pushing %" G_GSIZE_FORMAT " bytes buffer at pts %" GST_TIME_FORMAT
1456       " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1457       ", keyframe (%d)", gst_buffer_get_size (outbuf),
1458       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1459       GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1460       keyframe);
1461
1462   if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1463     demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1464   }
1465   if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1466     demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1467   }
1468
1469   if (G_UNLIKELY (!demux->no_more_pads
1470           && (GST_CLOCK_DIFF (demux->video_start,
1471                   GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1472     GST_DEBUG_OBJECT (demux,
1473         "Signalling no-more-pads because no audio stream was found"
1474         " after 6 seconds of video");
1475     gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1476     demux->no_more_pads = TRUE;
1477     demux->push_tags = TRUE;
1478   }
1479
1480   /* Push downstream */
1481   ret = gst_pad_push (demux->video_pad, outbuf);
1482
1483   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1484     if (demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
1485         demux->segment.position > demux->segment.stop) {
1486       /* In reverse playback we can get a GST_FLOW_EOS when
1487        * we are at the end of the segment, so we just need to jump
1488        * back to the previous section. */
1489       GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1490       demux->video_done = TRUE;
1491       ret = GST_FLOW_OK;
1492     } else {
1493       GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1494           " bytes video buffer: %s", demux->tag_data_size,
1495           gst_flow_get_name (ret));
1496       if (ret == GST_FLOW_NOT_LINKED) {
1497         demux->video_linked = FALSE;
1498       }
1499       goto beach;
1500     }
1501   }
1502
1503   demux->video_linked = TRUE;
1504
1505 beach:
1506   gst_buffer_unmap (buffer, &map);
1507   return ret;
1508 }
1509
1510 static GstClockTime
1511 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1512     GstBuffer * buffer, size_t * tag_size)
1513 {
1514   guint32 pts = 0, pts_ext = 0;
1515   guint32 tag_data_size;
1516   guint8 type;
1517   gboolean keyframe = TRUE;
1518   GstClockTime ret = GST_CLOCK_TIME_NONE;
1519   GstMapInfo map;
1520   guint8 *data;
1521   gsize size;
1522
1523   g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1524       GST_CLOCK_TIME_NONE);
1525
1526   gst_buffer_map (buffer, &map, GST_MAP_READ);
1527   data = map.data;
1528   size = map.size;
1529
1530   type = data[0];
1531
1532   if (type != 9 && type != 8 && type != 18) {
1533     GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1534     goto exit;
1535   }
1536
1537   if (type == 9)
1538     demux->has_video = TRUE;
1539   else if (type == 8)
1540     demux->has_audio = TRUE;
1541
1542   tag_data_size = GST_READ_UINT24_BE (data + 1);
1543
1544   if (size >= tag_data_size + 11 + 4) {
1545     if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1546       GST_WARNING_OBJECT (demux, "Invalid tag size");
1547       goto exit;
1548     }
1549   }
1550
1551   if (tag_size)
1552     *tag_size = tag_data_size + 11 + 4;
1553
1554   data += 4;
1555
1556   GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
1557       data[2], data[3]);
1558
1559   /* Grab timestamp of tag tag */
1560   pts = GST_READ_UINT24_BE (data);
1561   /* read the pts extension to 32 bits integer */
1562   pts_ext = GST_READ_UINT8 (data + 3);
1563   /* Combine them */
1564   pts |= pts_ext << 24;
1565
1566   if (type == 9) {
1567     data += 7;
1568
1569     keyframe = ((data[0] >> 4) == 1);
1570   }
1571
1572   ret = pts * GST_MSECOND;
1573   GST_LOG_OBJECT (demux, "pts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1574
1575   if (index && !demux->indexed && (type == 9 || (type == 8
1576               && !demux->has_video))) {
1577     gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1578         keyframe);
1579   }
1580
1581   if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1582     demux->duration = ret;
1583
1584 exit:
1585   gst_buffer_unmap (buffer, &map);
1586   return ret;
1587 }
1588
1589 static GstFlowReturn
1590 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1591 {
1592   GstFlowReturn ret = GST_FLOW_OK;
1593   guint8 tag_type = 0;
1594   GstMapInfo map;
1595
1596   g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1597
1598   gst_buffer_map (buffer, &map, GST_MAP_READ);
1599
1600   tag_type = map.data[0];
1601
1602   switch (tag_type) {
1603     case 9:
1604       demux->state = FLV_STATE_TAG_VIDEO;
1605       demux->has_video = TRUE;
1606       break;
1607     case 8:
1608       demux->state = FLV_STATE_TAG_AUDIO;
1609       demux->has_audio = TRUE;
1610       break;
1611     case 18:
1612       demux->state = FLV_STATE_TAG_SCRIPT;
1613       break;
1614     default:
1615       GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1616   }
1617
1618   /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1619    * 4 bytes of previous tag size */
1620   demux->tag_data_size = GST_READ_UINT24_BE (map.data + 1);
1621   demux->tag_size = demux->tag_data_size + 11;
1622
1623   GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1624       demux->tag_data_size);
1625
1626   gst_buffer_unmap (buffer, &map);
1627
1628   return ret;
1629 }
1630
1631 static GstFlowReturn
1632 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1633 {
1634   GstFlowReturn ret = GST_FLOW_OK;
1635   GstMapInfo map;
1636
1637   g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1638
1639   gst_buffer_map (buffer, &map, GST_MAP_READ);
1640
1641   /* Check for the FLV tag */
1642   if (map.data[0] == 'F' && map.data[1] == 'L' && map.data[2] == 'V') {
1643     GST_DEBUG_OBJECT (demux, "FLV header detected");
1644   } else {
1645     if (G_UNLIKELY (demux->strict)) {
1646       GST_WARNING_OBJECT (demux, "invalid header tag detected");
1647       ret = GST_FLOW_EOS;
1648       goto beach;
1649     }
1650   }
1651
1652   /* Now look at audio/video flags */
1653   {
1654     guint8 flags = map.data[4];
1655
1656     demux->has_video = demux->has_audio = FALSE;
1657
1658     if (flags & 1) {
1659       GST_DEBUG_OBJECT (demux, "there is a video stream");
1660       demux->has_video = TRUE;
1661     }
1662     if (flags & 4) {
1663       GST_DEBUG_OBJECT (demux, "there is an audio stream");
1664       demux->has_audio = TRUE;
1665     }
1666   }
1667
1668   /* do a one-time seekability check */
1669   gst_flv_demux_check_seekability (demux);
1670
1671   /* We don't care about the rest */
1672   demux->need_header = FALSE;
1673
1674 beach:
1675   gst_buffer_unmap (buffer, &map);
1676   return ret;
1677 }
1678
1679
1680 static void
1681 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1682 {
1683   GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1684
1685   gst_adapter_clear (demux->adapter);
1686
1687   demux->audio_need_discont = TRUE;
1688   demux->video_need_discont = TRUE;
1689
1690   demux->flushing = FALSE;
1691
1692   /* Only in push mode and if we're not during a seek */
1693   if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1694     /* After a flush we expect a tag_type */
1695     demux->state = FLV_STATE_TAG_TYPE;
1696     /* We reset the offset and will get one from first push */
1697     demux->offset = 0;
1698   }
1699 }
1700
1701 static void
1702 gst_flv_demux_cleanup (GstFlvDemux * demux)
1703 {
1704   GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1705
1706   demux->state = FLV_STATE_HEADER;
1707
1708   demux->flushing = FALSE;
1709   demux->need_header = TRUE;
1710   demux->audio_need_segment = TRUE;
1711   demux->video_need_segment = TRUE;
1712   demux->audio_need_discont = TRUE;
1713   demux->video_need_discont = TRUE;
1714
1715   /* By default we consider them as linked */
1716   demux->audio_linked = TRUE;
1717   demux->video_linked = TRUE;
1718
1719   demux->has_audio = FALSE;
1720   demux->has_video = FALSE;
1721   demux->push_tags = FALSE;
1722   demux->got_par = FALSE;
1723
1724   demux->indexed = FALSE;
1725   demux->upstream_seekable = FALSE;
1726   demux->file_size = 0;
1727
1728   demux->index_max_pos = 0;
1729   demux->index_max_time = 0;
1730
1731   demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1732   demux->last_audio_pts = demux->last_video_pts = 0;
1733   demux->audio_time_offset = demux->video_time_offset = 0;
1734
1735   demux->no_more_pads = FALSE;
1736
1737   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1738
1739   demux->w = demux->h = 0;
1740   demux->framerate = 0.0;
1741   demux->par_x = demux->par_y = 1;
1742   demux->video_offset = 0;
1743   demux->audio_offset = 0;
1744   demux->offset = demux->cur_tag_offset = 0;
1745   demux->tag_size = demux->tag_data_size = 0;
1746   demux->duration = GST_CLOCK_TIME_NONE;
1747
1748   if (demux->new_seg_event) {
1749     gst_event_unref (demux->new_seg_event);
1750     demux->new_seg_event = NULL;
1751   }
1752
1753   gst_adapter_clear (demux->adapter);
1754
1755   if (demux->audio_codec_data) {
1756     gst_buffer_unref (demux->audio_codec_data);
1757     demux->audio_codec_data = NULL;
1758   }
1759
1760   if (demux->video_codec_data) {
1761     gst_buffer_unref (demux->video_codec_data);
1762     demux->video_codec_data = NULL;
1763   }
1764
1765   if (demux->audio_pad) {
1766     gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1767     gst_object_unref (demux->audio_pad);
1768     demux->audio_pad = NULL;
1769   }
1770
1771   if (demux->video_pad) {
1772     gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1773     gst_object_unref (demux->video_pad);
1774     demux->video_pad = NULL;
1775   }
1776
1777   if (demux->times) {
1778     g_array_free (demux->times, TRUE);
1779     demux->times = NULL;
1780   }
1781
1782   if (demux->filepositions) {
1783     g_array_free (demux->filepositions, TRUE);
1784     demux->filepositions = NULL;
1785   }
1786 }
1787
1788 /*
1789  * Create and push a flushing seek event upstream
1790  */
1791 static gboolean
1792 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1793 {
1794   GstEvent *event;
1795   gboolean res = 0;
1796
1797   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1798
1799   event =
1800       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1801       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1802       GST_SEEK_TYPE_NONE, -1);
1803
1804   res = gst_pad_push_event (demux->sinkpad, event);
1805
1806   if (res)
1807     demux->offset = offset;
1808   return res;
1809 }
1810
1811 static GstFlowReturn
1812 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1813 {
1814   GstFlowReturn ret = GST_FLOW_OK;
1815   GstFlvDemux *demux = NULL;
1816
1817   demux = GST_FLV_DEMUX (parent);
1818
1819   GST_LOG_OBJECT (demux,
1820       "received buffer of %" G_GSIZE_FORMAT " bytes at offset %"
1821       G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
1822       GST_BUFFER_OFFSET (buffer));
1823
1824   if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1825     GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1826     demux->state = FLV_STATE_HEADER;
1827     demux->offset = 0;
1828   }
1829
1830   if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
1831     GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
1832     demux->offset = GST_BUFFER_OFFSET (buffer);
1833   }
1834
1835   if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1836     GST_DEBUG_OBJECT (demux, "Discontinuity");
1837     gst_adapter_clear (demux->adapter);
1838   }
1839
1840   gst_adapter_push (demux->adapter, buffer);
1841
1842   if (demux->seeking) {
1843     demux->state = FLV_STATE_SEEK;
1844     GST_OBJECT_LOCK (demux);
1845     demux->seeking = FALSE;
1846     GST_OBJECT_UNLOCK (demux);
1847   }
1848
1849 parse:
1850   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1851     if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
1852             || demux->video_linked)) {
1853       ret = GST_FLOW_OK;
1854     } else {
1855       GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
1856       goto beach;
1857     }
1858   }
1859
1860   if (G_UNLIKELY (demux->flushing)) {
1861     GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
1862     ret = GST_FLOW_FLUSHING;
1863     goto beach;
1864   }
1865
1866   switch (demux->state) {
1867     case FLV_STATE_HEADER:
1868     {
1869       if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
1870         GstBuffer *buffer;
1871
1872         buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
1873
1874         ret = gst_flv_demux_parse_header (demux, buffer);
1875
1876         gst_buffer_unref (buffer);
1877         demux->offset += FLV_HEADER_SIZE;
1878
1879         demux->state = FLV_STATE_TAG_TYPE;
1880         goto parse;
1881       } else {
1882         goto beach;
1883       }
1884     }
1885     case FLV_STATE_TAG_TYPE:
1886     {
1887       if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
1888         GstBuffer *buffer;
1889
1890         /* Remember the tag offset in bytes */
1891         demux->cur_tag_offset = demux->offset;
1892
1893         buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
1894
1895         ret = gst_flv_demux_parse_tag_type (demux, buffer);
1896
1897         gst_buffer_unref (buffer);
1898         demux->offset += FLV_TAG_TYPE_SIZE;
1899
1900         /* last tag is not an index => no index/don't know where the index is
1901          * seek back to the beginning */
1902         if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
1903           goto no_index;
1904
1905         goto parse;
1906       } else {
1907         goto beach;
1908       }
1909     }
1910     case FLV_STATE_TAG_VIDEO:
1911     {
1912       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1913         GstBuffer *buffer;
1914
1915         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1916
1917         ret = gst_flv_demux_parse_tag_video (demux, buffer);
1918
1919         gst_buffer_unref (buffer);
1920         demux->offset += demux->tag_size;
1921
1922         demux->state = FLV_STATE_TAG_TYPE;
1923         goto parse;
1924       } else {
1925         goto beach;
1926       }
1927     }
1928     case FLV_STATE_TAG_AUDIO:
1929     {
1930       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1931         GstBuffer *buffer;
1932
1933         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1934
1935         ret = gst_flv_demux_parse_tag_audio (demux, buffer);
1936
1937         gst_buffer_unref (buffer);
1938         demux->offset += demux->tag_size;
1939
1940         demux->state = FLV_STATE_TAG_TYPE;
1941         goto parse;
1942       } else {
1943         goto beach;
1944       }
1945     }
1946     case FLV_STATE_TAG_SCRIPT:
1947     {
1948       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1949         GstBuffer *buffer;
1950
1951         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1952
1953         ret = gst_flv_demux_parse_tag_script (demux, buffer);
1954
1955         gst_buffer_unref (buffer);
1956         demux->offset += demux->tag_size;
1957
1958         demux->state = FLV_STATE_TAG_TYPE;
1959
1960         /* if there's a seek event we're here for the index so if we don't have it
1961          * we seek back to the beginning */
1962         if (demux->seek_event) {
1963           if (demux->indexed)
1964             demux->state = FLV_STATE_SEEK;
1965           else
1966             goto no_index;
1967         }
1968
1969         goto parse;
1970       } else {
1971         goto beach;
1972       }
1973     }
1974     case FLV_STATE_SEEK:
1975     {
1976       GstEvent *event;
1977
1978       ret = GST_FLOW_OK;
1979
1980       if (!demux->indexed) {
1981         if (demux->offset == demux->file_size - sizeof (guint32)) {
1982           guint64 seek_offset;
1983           guint8 *data;
1984
1985           data = gst_adapter_take (demux->adapter, 4);
1986           if (!data)
1987             goto no_index;
1988
1989           seek_offset = demux->file_size - sizeof (guint32) -
1990               GST_READ_UINT32_BE (data);
1991           g_free (data);
1992
1993           GST_INFO_OBJECT (demux,
1994               "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
1995               seek_offset);
1996           demux->state = FLV_STATE_TAG_TYPE;
1997           flv_demux_seek_to_offset (demux, seek_offset);
1998           goto beach;
1999         } else
2000           goto no_index;
2001       }
2002
2003       GST_OBJECT_LOCK (demux);
2004       event = demux->seek_event;
2005       demux->seek_event = NULL;
2006       GST_OBJECT_UNLOCK (demux);
2007
2008       /* calculate and perform seek */
2009       if (!flv_demux_handle_seek_push (demux, event))
2010         goto seek_failed;
2011
2012       gst_event_unref (event);
2013       demux->state = FLV_STATE_TAG_TYPE;
2014       goto beach;
2015     }
2016     default:
2017       GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
2018   }
2019
2020 beach:
2021   if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2022     /* If either audio or video is linked we return GST_FLOW_OK */
2023     if (demux->audio_linked || demux->video_linked) {
2024       ret = GST_FLOW_OK;
2025     }
2026   }
2027
2028   return ret;
2029
2030 /* ERRORS */
2031 no_index:
2032   {
2033     GST_OBJECT_LOCK (demux);
2034     demux->seeking = FALSE;
2035     gst_event_unref (demux->seek_event);
2036     demux->seek_event = NULL;
2037     GST_OBJECT_UNLOCK (demux);
2038     GST_WARNING_OBJECT (demux,
2039         "failed to find an index, seeking back to beginning");
2040     flv_demux_seek_to_offset (demux, 0);
2041     return GST_FLOW_OK;
2042   }
2043 seek_failed:
2044   {
2045     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2046     return GST_FLOW_ERROR;
2047   }
2048
2049 }
2050
2051 static GstFlowReturn
2052 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2053     guint size, GstBuffer ** buffer)
2054 {
2055   GstFlowReturn ret;
2056
2057   ret = gst_pad_pull_range (pad, offset, size, buffer);
2058   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2059     GST_WARNING_OBJECT (demux,
2060         "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2061         size, offset, gst_flow_get_name (ret));
2062     *buffer = NULL;
2063     return ret;
2064   }
2065
2066   if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2067     GST_WARNING_OBJECT (demux,
2068         "partial pull got %" G_GSIZE_FORMAT " when expecting %d from offset %"
2069         G_GUINT64_FORMAT, gst_buffer_get_size (*buffer), size, offset);
2070     gst_buffer_unref (*buffer);
2071     ret = GST_FLOW_EOS;
2072     *buffer = NULL;
2073     return ret;
2074   }
2075
2076   return ret;
2077 }
2078
2079 static GstFlowReturn
2080 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2081 {
2082   GstBuffer *buffer = NULL;
2083   GstFlowReturn ret = GST_FLOW_OK;
2084
2085   /* Store tag offset */
2086   demux->cur_tag_offset = demux->offset;
2087
2088   /* Get the first 4 bytes to identify tag type and size */
2089   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2090                   FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2091     goto beach;
2092
2093   /* Identify tag type */
2094   ret = gst_flv_demux_parse_tag_type (demux, buffer);
2095
2096   gst_buffer_unref (buffer);
2097
2098   if (G_UNLIKELY (ret != GST_FLOW_OK))
2099     goto beach;
2100
2101   /* Jump over tag type + size */
2102   demux->offset += FLV_TAG_TYPE_SIZE;
2103
2104   /* Pull the whole tag */
2105   buffer = NULL;
2106   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2107                   demux->tag_size, &buffer)) != GST_FLOW_OK))
2108     goto beach;
2109
2110   switch (demux->state) {
2111     case FLV_STATE_TAG_VIDEO:
2112       ret = gst_flv_demux_parse_tag_video (demux, buffer);
2113       break;
2114     case FLV_STATE_TAG_AUDIO:
2115       ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2116       break;
2117     case FLV_STATE_TAG_SCRIPT:
2118       ret = gst_flv_demux_parse_tag_script (demux, buffer);
2119       break;
2120     default:
2121       GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2122   }
2123
2124   gst_buffer_unref (buffer);
2125
2126   /* Jump over that part we've just parsed */
2127   demux->offset += demux->tag_size;
2128
2129   /* Make sure we reinitialize the tag size */
2130   demux->tag_size = 0;
2131
2132   /* Ready for the next tag */
2133   demux->state = FLV_STATE_TAG_TYPE;
2134
2135   if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2136     /* If either audio or video is linked we return GST_FLOW_OK */
2137     if (demux->audio_linked || demux->video_linked) {
2138       ret = GST_FLOW_OK;
2139     } else {
2140       GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2141           "neither video nor audio are linked");
2142     }
2143   }
2144
2145 beach:
2146   return ret;
2147 }
2148
2149 static GstFlowReturn
2150 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2151 {
2152   GstBuffer *buffer = NULL;
2153   GstFlowReturn ret = GST_FLOW_OK;
2154
2155   /* Get the first 9 bytes */
2156   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2157                   FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2158     goto beach;
2159
2160   ret = gst_flv_demux_parse_header (demux, buffer);
2161
2162   gst_buffer_unref (buffer);
2163
2164   /* Jump over the header now */
2165   demux->offset += FLV_HEADER_SIZE;
2166   demux->state = FLV_STATE_TAG_TYPE;
2167
2168 beach:
2169   return ret;
2170 }
2171
2172 static void
2173 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2174     gboolean reset)
2175 {
2176   demux->offset = offset;
2177
2178   /* Tell all the stream we moved to a different position (discont) */
2179   demux->audio_need_discont = TRUE;
2180   demux->video_need_discont = TRUE;
2181
2182   /* next section setup */
2183   demux->from_offset = -1;
2184   demux->audio_done = demux->video_done = FALSE;
2185   demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2186
2187   if (reset) {
2188     demux->from_offset = -1;
2189     demux->to_offset = G_MAXINT64;
2190   }
2191
2192   /* If we seeked at the beginning of the file parse the header again */
2193   if (G_UNLIKELY (!demux->offset)) {
2194     demux->state = FLV_STATE_HEADER;
2195   } else {                      /* or parse a tag */
2196     demux->state = FLV_STATE_TAG_TYPE;
2197   }
2198 }
2199
2200 static GstFlowReturn
2201 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2202 {
2203   GstFlowReturn ret = GST_FLOW_EOS;
2204   GstIndex *index;
2205   GstIndexEntry *entry = NULL;
2206
2207   GST_DEBUG_OBJECT (demux,
2208       "terminated section started at offset %" G_GINT64_FORMAT,
2209       demux->from_offset);
2210
2211   /* we are done if we got all audio and video */
2212   if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2213           demux->audio_first_ts < demux->segment.start) &&
2214       (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2215           demux->video_first_ts < demux->segment.start))
2216     goto done;
2217
2218   if (demux->from_offset <= 0)
2219     goto done;
2220
2221   GST_DEBUG_OBJECT (demux, "locating previous position");
2222
2223   index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2224
2225   /* locate index entry before previous start position */
2226   if (index) {
2227     entry = gst_index_get_assoc_entry (index, demux->index_id,
2228         GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2229         GST_FORMAT_BYTES, demux->from_offset - 1);
2230
2231     if (entry) {
2232       gint64 bytes = 0, time = 0;
2233
2234       gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2235       gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2236
2237       GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2238           " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2239           demux->offset - 1, GST_TIME_ARGS (time), bytes);
2240
2241       /* setup for next section */
2242       demux->to_offset = demux->from_offset;
2243       gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2244       ret = GST_FLOW_OK;
2245     }
2246
2247     gst_object_unref (index);
2248   }
2249
2250
2251 done:
2252   return ret;
2253 }
2254
2255 static GstFlowReturn
2256 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2257 {
2258   gint64 size;
2259   size_t tag_size;
2260   guint64 old_offset;
2261   GstBuffer *buffer;
2262   GstClockTime tag_time;
2263   GstFlowReturn ret = GST_FLOW_OK;
2264
2265   if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2266     return GST_FLOW_OK;
2267
2268   GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2269       " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2270
2271   old_offset = demux->offset;
2272   demux->offset = pos;
2273
2274   buffer = NULL;
2275   while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2276               12, &buffer)) == GST_FLOW_OK) {
2277     tag_time =
2278         gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2279
2280     gst_buffer_unref (buffer);
2281     buffer = NULL;
2282
2283     if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2284       goto exit;
2285
2286     demux->offset += tag_size;
2287   }
2288
2289   if (ret == GST_FLOW_EOS) {
2290     /* file ran out, so mark we have complete index */
2291     demux->indexed = TRUE;
2292     ret = GST_FLOW_OK;
2293   }
2294
2295 exit:
2296   demux->offset = old_offset;
2297
2298   return ret;
2299 }
2300
2301 static gint64
2302 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2303 {
2304   gint64 ret = 0, offset;
2305   size_t tag_size, size;
2306   GstBuffer *buffer = NULL;
2307   GstMapInfo map;
2308
2309   if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2310     goto exit;
2311
2312   ret = offset;
2313   GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2314   if (G_UNLIKELY (offset < 4))
2315     goto exit;
2316
2317   offset -= 4;
2318   if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2319           4, &buffer))
2320     goto exit;
2321
2322   gst_buffer_map (buffer, &map, GST_MAP_READ);
2323   tag_size = GST_READ_UINT32_BE (map.data);
2324   gst_buffer_unmap (buffer, &map);
2325   GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2326   gst_buffer_unref (buffer);
2327   buffer = NULL;
2328
2329   offset -= tag_size;
2330   if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2331           12, &buffer))
2332     goto exit;
2333
2334   /* a consistency check */
2335   gst_buffer_map (buffer, &map, GST_MAP_READ);
2336   size = GST_READ_UINT24_BE (map.data + 1);
2337   if (size != tag_size - 11) {
2338     gst_buffer_unmap (buffer, &map);
2339     GST_DEBUG_OBJECT (demux,
2340         "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2341         ", corrupt or truncated file", size, tag_size - 11);
2342     goto exit;
2343   }
2344
2345   /* try to update duration with timestamp in any case */
2346   gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2347
2348   /* maybe get some more metadata */
2349   if (map.data[0] == 18) {
2350     gst_buffer_unmap (buffer, &map);
2351     gst_buffer_unref (buffer);
2352     buffer = NULL;
2353     GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2354     offset += 4;
2355     if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2356             tag_size, &buffer))
2357       gst_flv_demux_parse_tag_script (demux, buffer);
2358   } else {
2359     gst_buffer_unmap (buffer, &map);
2360   }
2361
2362 exit:
2363   if (buffer)
2364     gst_buffer_unref (buffer);
2365
2366   return ret;
2367 }
2368
2369 static void
2370 gst_flv_demux_loop (GstPad * pad)
2371 {
2372   GstFlvDemux *demux = NULL;
2373   GstFlowReturn ret = GST_FLOW_OK;
2374
2375   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2376
2377   /* pull in data */
2378   switch (demux->state) {
2379     case FLV_STATE_TAG_TYPE:
2380       if (demux->from_offset == -1)
2381         demux->from_offset = demux->offset;
2382       ret = gst_flv_demux_pull_tag (pad, demux);
2383       /* if we have seen real data, we probably passed a possible metadata
2384        * header located at start.  So if we do not yet have an index,
2385        * try to pick up metadata (index, duration) at the end */
2386       if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2387               (demux->has_video || demux->has_audio)))
2388         demux->file_size = gst_flv_demux_get_metadata (demux);
2389       break;
2390     case FLV_STATE_DONE:
2391       ret = GST_FLOW_EOS;
2392       break;
2393     case FLV_STATE_SEEK:
2394       /* seek issued with insufficient index;
2395        * scan for index in task thread from current maximum offset to
2396        * desired time and then perform seek */
2397       /* TODO maybe some buffering message or so to indicate scan progress */
2398       ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2399           demux->seek_time);
2400       if (ret != GST_FLOW_OK)
2401         goto pause;
2402       /* position and state arranged by seek,
2403        * also unrefs event */
2404       gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2405       demux->seek_event = NULL;
2406       break;
2407     default:
2408       ret = gst_flv_demux_pull_header (pad, demux);
2409       /* index scans start after header */
2410       demux->index_max_pos = demux->offset;
2411       break;
2412   }
2413
2414   if (demux->segment.rate < 0.0) {
2415     /* check end of section */
2416     if ((gint64) demux->offset >= demux->to_offset ||
2417         demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2418         (demux->audio_done && demux->video_done))
2419       ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2420   } else {
2421     /* check EOS condition */
2422     if ((demux->segment.stop != -1) &&
2423         (demux->segment.position >= demux->segment.stop)) {
2424       ret = GST_FLOW_EOS;
2425     }
2426   }
2427
2428   /* pause if something went wrong or at end */
2429   if (G_UNLIKELY (ret != GST_FLOW_OK))
2430     goto pause;
2431
2432   gst_object_unref (demux);
2433
2434   return;
2435
2436 pause:
2437   {
2438     const gchar *reason = gst_flow_get_name (ret);
2439
2440     GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2441     gst_pad_pause_task (pad);
2442
2443     if (ret == GST_FLOW_EOS) {
2444       /* handle end-of-stream/segment */
2445       /* so align our position with the end of it, if there is one
2446        * this ensures a subsequent will arrive at correct base/acc time */
2447       if (demux->segment.rate > 0.0 &&
2448           GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2449         demux->segment.position = demux->segment.stop;
2450       else if (demux->segment.rate < 0.0)
2451         demux->segment.position = demux->segment.start;
2452
2453       /* perform EOS logic */
2454       if (!demux->no_more_pads) {
2455         gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2456         demux->no_more_pads = TRUE;
2457       }
2458
2459       if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2460         gint64 stop;
2461
2462         /* for segment playback we need to post when (in stream time)
2463          * we stopped, this is either stop (when set) or the duration. */
2464         if ((stop = demux->segment.stop) == -1)
2465           stop = demux->segment.duration;
2466
2467         if (demux->segment.rate >= 0) {
2468           GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2469           gst_element_post_message (GST_ELEMENT_CAST (demux),
2470               gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2471                   GST_FORMAT_TIME, stop));
2472           gst_flv_demux_push_src_event (demux,
2473               gst_event_new_segment_done (GST_FORMAT_TIME, stop));
2474         } else {                /* Reverse playback */
2475           GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2476               "segment");
2477           gst_element_post_message (GST_ELEMENT_CAST (demux),
2478               gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2479                   GST_FORMAT_TIME, demux->segment.start));
2480           gst_flv_demux_push_src_event (demux,
2481               gst_event_new_segment_done (GST_FORMAT_TIME,
2482                   demux->segment.start));
2483         }
2484       } else {
2485         /* normal playback, send EOS to all linked pads */
2486         if (!demux->no_more_pads) {
2487           gst_element_no_more_pads (GST_ELEMENT (demux));
2488           demux->no_more_pads = TRUE;
2489         }
2490
2491         GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2492         if (!demux->audio_pad && !demux->video_pad)
2493           GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2494               ("Internal data stream error."), ("Got EOS before any data"));
2495         else if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2496           GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2497       }
2498     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2499       GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2500           ("Internal data stream error."),
2501           ("stream stopped, reason %s", reason));
2502       gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2503     }
2504     gst_object_unref (demux);
2505     return;
2506   }
2507 }
2508
2509 static guint64
2510 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2511 {
2512   gint64 bytes = 0;
2513   gint64 time = 0;
2514   GstIndex *index;
2515   GstIndexEntry *entry;
2516
2517   g_return_val_if_fail (segment != NULL, 0);
2518
2519   time = segment->position;
2520
2521   index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2522
2523   if (index) {
2524     /* Let's check if we have an index entry for that seek time */
2525     entry = gst_index_get_assoc_entry (index, demux->index_id,
2526         GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2527         GST_FORMAT_TIME, time);
2528
2529     if (entry) {
2530       gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2531       gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2532
2533       GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2534           " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2535           GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2536
2537       /* Key frame seeking */
2538       if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2539         /* Adjust the segment so that the keyframe fits in */
2540         if (time < segment->start) {
2541           segment->start = segment->time = time;
2542         }
2543         segment->position = time;
2544       }
2545     } else {
2546       GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2547           GST_TIME_ARGS (segment->start));
2548     }
2549
2550     gst_object_unref (index);
2551   }
2552
2553   return bytes;
2554 }
2555
2556 static gboolean
2557 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2558 {
2559   GstFormat format;
2560   GstSeekFlags flags;
2561   GstSeekType start_type, stop_type;
2562   gint64 start, stop;
2563   gdouble rate;
2564   gboolean update, flush, ret;
2565   GstSegment seeksegment;
2566
2567   gst_event_parse_seek (event, &rate, &format, &flags,
2568       &start_type, &start, &stop_type, &stop);
2569
2570   if (format != GST_FORMAT_TIME)
2571     goto wrong_format;
2572
2573   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2574   /* FIXME : the keyframe flag is never used ! */
2575
2576   /* Work on a copy until we are sure the seek succeeded. */
2577   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2578
2579   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2580       &demux->segment);
2581
2582   /* Apply the seek to our segment */
2583   gst_segment_do_seek (&seeksegment, rate, format, flags,
2584       start_type, start, stop_type, stop, &update);
2585
2586   GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2587       &seeksegment);
2588
2589   if (flush || seeksegment.position != demux->segment.position) {
2590     /* Do the actual seeking */
2591     guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2592
2593     GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2594         G_GUINT64_FORMAT, offset);
2595     ret = gst_pad_push_event (demux->sinkpad,
2596         gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2597             seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2598             offset, GST_SEEK_TYPE_NONE, 0));
2599     if (G_UNLIKELY (!ret)) {
2600       GST_WARNING_OBJECT (demux, "upstream seek failed");
2601     }
2602
2603     /* Tell all the stream we moved to a different position (discont) */
2604     demux->audio_need_discont = TRUE;
2605     demux->video_need_discont = TRUE;
2606   } else {
2607     ret = TRUE;
2608   }
2609
2610   if (ret) {
2611     /* Ok seek succeeded, take the newly configured segment */
2612     memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2613
2614     /* Tell all the stream a new segment is needed */
2615     demux->audio_need_segment = TRUE;
2616     demux->video_need_segment = TRUE;
2617     /* Clean any potential newsegment event kept for the streams. The first
2618      * stream needing a new segment will create a new one. */
2619     if (G_UNLIKELY (demux->new_seg_event)) {
2620       gst_event_unref (demux->new_seg_event);
2621       demux->new_seg_event = NULL;
2622     }
2623     gst_event_unref (event);
2624   } else {
2625     ret = gst_pad_push_event (demux->sinkpad, event);
2626   }
2627
2628   return ret;
2629
2630 /* ERRORS */
2631 wrong_format:
2632   {
2633     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2634     gst_event_unref (event);
2635     return FALSE;
2636   }
2637 }
2638
2639 static gboolean
2640 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2641 {
2642   GstFormat format;
2643
2644   gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2645
2646   if (format != GST_FORMAT_TIME) {
2647     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2648     gst_event_unref (event);
2649     return FALSE;
2650   }
2651
2652   /* First try upstream */
2653   if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2654     GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2655     gst_event_unref (event);
2656     return TRUE;
2657   }
2658
2659   if (!demux->indexed) {
2660     guint64 seek_offset = 0;
2661     gboolean building_index;
2662
2663     GST_OBJECT_LOCK (demux);
2664     /* handle the seek in the chain function */
2665     demux->seeking = TRUE;
2666     demux->state = FLV_STATE_SEEK;
2667
2668     /* copy the event */
2669     if (demux->seek_event)
2670       gst_event_unref (demux->seek_event);
2671     demux->seek_event = gst_event_ref (event);
2672
2673     /* set the building_index flag so that only one thread can setup the
2674      * structures for index seeking. */
2675     building_index = demux->building_index;
2676     if (!building_index) {
2677       demux->building_index = TRUE;
2678       if (!demux->file_size
2679           && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2680               &demux->file_size)) {
2681         GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2682         GST_OBJECT_UNLOCK (demux);
2683         return FALSE;
2684       }
2685
2686       /* we hope the last tag is a scriptdataobject containing an index
2687        * the size of the last tag is given in the last guint32 bits
2688        * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2689       seek_offset = demux->file_size - sizeof (guint32);
2690       GST_DEBUG_OBJECT (demux,
2691           "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2692     }
2693     GST_OBJECT_UNLOCK (demux);
2694
2695     if (!building_index) {
2696       GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2697           seek_offset);
2698       return flv_demux_seek_to_offset (demux, seek_offset);
2699     }
2700
2701     /* FIXME: we have to always return true so that we don't block the seek
2702      * thread.
2703      * Note: maybe it is OK to return true if we're still building the index */
2704     return TRUE;
2705   }
2706
2707   return flv_demux_handle_seek_push (demux, event);
2708 }
2709
2710 static gboolean
2711 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2712     gboolean seeking)
2713 {
2714   GstFormat format;
2715   GstSeekFlags flags;
2716   GstSeekType start_type, stop_type;
2717   gint64 start, stop;
2718   gdouble rate;
2719   gboolean update, flush, ret = FALSE;
2720   GstSegment seeksegment;
2721
2722   gst_event_parse_seek (event, &rate, &format, &flags,
2723       &start_type, &start, &stop_type, &stop);
2724
2725   if (format != GST_FORMAT_TIME)
2726     goto wrong_format;
2727
2728   /* mark seeking thread entering flushing/pausing */
2729   GST_OBJECT_LOCK (demux);
2730   if (seeking)
2731     demux->seeking = seeking;
2732   GST_OBJECT_UNLOCK (demux);
2733
2734   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2735   /* FIXME : the keyframe flag is never used */
2736
2737   if (flush) {
2738     /* Flush start up and downstream to make sure data flow and loops are
2739        idle */
2740     gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2741     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2742   } else {
2743     /* Pause the pulling task */
2744     gst_pad_pause_task (demux->sinkpad);
2745   }
2746
2747   /* Take the stream lock */
2748   GST_PAD_STREAM_LOCK (demux->sinkpad);
2749
2750   if (flush) {
2751     /* Stop flushing upstream we need to pull */
2752     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2753   }
2754
2755   /* Work on a copy until we are sure the seek succeeded. */
2756   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2757
2758   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2759       &demux->segment);
2760
2761   /* Apply the seek to our segment */
2762   gst_segment_do_seek (&seeksegment, rate, format, flags,
2763       start_type, start, stop_type, stop, &update);
2764
2765   GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2766       &seeksegment);
2767
2768   if (flush || seeksegment.position != demux->segment.position) {
2769     /* Do the actual seeking */
2770     /* index is reliable if it is complete or we do not go to far ahead */
2771     if (seeking && !demux->indexed &&
2772         seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2773       GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2774           " index only up to %" GST_TIME_FORMAT,
2775           GST_TIME_ARGS (demux->index_max_time));
2776       /* stop flushing for now */
2777       if (flush)
2778         gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2779       /* delegate scanning and index building to task thread to avoid
2780        * occupying main (UI) loop */
2781       if (demux->seek_event)
2782         gst_event_unref (demux->seek_event);
2783       demux->seek_event = gst_event_ref (event);
2784       demux->seek_time = seeksegment.position;
2785       demux->state = FLV_STATE_SEEK;
2786       /* do not know about succes yet, but we did care and handled it */
2787       ret = TRUE;
2788       goto exit;
2789     }
2790     /* now index should be as reliable as it can be for current purpose */
2791     gst_flv_demux_move_to_offset (demux,
2792         gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2793     ret = TRUE;
2794   } else {
2795     ret = TRUE;
2796   }
2797
2798   if (flush) {
2799     /* Stop flushing, the sinks are at time 0 now */
2800     gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2801   }
2802
2803   if (ret) {
2804     /* Ok seek succeeded, take the newly configured segment */
2805     memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2806
2807     /* Notify about the start of a new segment */
2808     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2809       gst_element_post_message (GST_ELEMENT (demux),
2810           gst_message_new_segment_start (GST_OBJECT (demux),
2811               demux->segment.format, demux->segment.position));
2812     }
2813
2814     /* Tell all the stream a new segment is needed */
2815     demux->audio_need_segment = TRUE;
2816     demux->video_need_segment = TRUE;
2817     /* Clean any potential newsegment event kept for the streams. The first
2818      * stream needing a new segment will create a new one. */
2819     if (G_UNLIKELY (demux->new_seg_event)) {
2820       gst_event_unref (demux->new_seg_event);
2821       demux->new_seg_event = NULL;
2822     }
2823     if (demux->segment.rate < 0.0) {
2824       /* we can't generate a segment by locking on
2825        * to the first timestamp we see */
2826       GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2827           GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2828           GST_TIME_ARGS (demux->segment.start),
2829           GST_TIME_ARGS (demux->segment.stop));
2830       demux->new_seg_event = gst_event_new_segment (&demux->segment);
2831     }
2832   }
2833
2834 exit:
2835   GST_OBJECT_LOCK (demux);
2836   seeking = demux->seeking && !seeking;
2837   demux->seeking = FALSE;
2838   GST_OBJECT_UNLOCK (demux);
2839
2840   /* if we detect an external seek having started (and possibly already having
2841    * flushed), do not restart task to give it a chance.
2842    * Otherwise external one's flushing will take care to pause task */
2843   if (seeking) {
2844     gst_pad_pause_task (demux->sinkpad);
2845   } else {
2846     gst_pad_start_task (demux->sinkpad,
2847         (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad, NULL);
2848   }
2849
2850   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2851
2852   gst_event_unref (event);
2853   return ret;
2854
2855   /* ERRORS */
2856 wrong_format:
2857   {
2858     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2859     gst_event_unref (event);
2860     return ret;
2861   }
2862 }
2863
2864 /* If we can pull that's prefered */
2865 static gboolean
2866 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
2867 {
2868   GstQuery *query;
2869   gboolean pull_mode;
2870
2871   query = gst_query_new_scheduling ();
2872
2873   if (!gst_pad_peer_query (sinkpad, query)) {
2874     gst_query_unref (query);
2875     goto activate_push;
2876   }
2877
2878   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
2879       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
2880   gst_query_unref (query);
2881
2882   if (!pull_mode)
2883     goto activate_push;
2884
2885   GST_DEBUG_OBJECT (sinkpad, "activating pull");
2886   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
2887
2888 activate_push:
2889   {
2890     GST_DEBUG_OBJECT (sinkpad, "activating push");
2891     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
2892   }
2893 }
2894
2895 static gboolean
2896 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
2897     GstPadMode mode, gboolean active)
2898 {
2899   gboolean res;
2900   GstFlvDemux *demux;
2901
2902   demux = GST_FLV_DEMUX (parent);
2903
2904   switch (mode) {
2905     case GST_PAD_MODE_PUSH:
2906       demux->random_access = FALSE;
2907       res = TRUE;
2908       break;
2909     case GST_PAD_MODE_PULL:
2910       if (active) {
2911         demux->random_access = TRUE;
2912         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
2913             sinkpad, NULL);
2914       } else {
2915         demux->random_access = FALSE;
2916         res = gst_pad_stop_task (sinkpad);
2917       }
2918       break;
2919     default:
2920       res = FALSE;
2921       break;
2922   }
2923   return res;
2924 }
2925
2926 static gboolean
2927 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
2928 {
2929   GstFlvDemux *demux;
2930   gboolean ret = FALSE;
2931
2932   demux = GST_FLV_DEMUX (parent);
2933
2934   GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2935
2936   switch (GST_EVENT_TYPE (event)) {
2937     case GST_EVENT_FLUSH_START:
2938       GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
2939       demux->flushing = TRUE;
2940       ret = gst_flv_demux_push_src_event (demux, event);
2941       break;
2942     case GST_EVENT_FLUSH_STOP:
2943       GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
2944       gst_flv_demux_flush (demux, TRUE);
2945       ret = gst_flv_demux_push_src_event (demux, event);
2946       break;
2947     case GST_EVENT_EOS:
2948     {
2949       GstIndex *index;
2950
2951       GST_DEBUG_OBJECT (demux, "received EOS");
2952
2953       index = gst_flv_demux_get_index (GST_ELEMENT (demux));
2954
2955       if (index) {
2956         GST_DEBUG_OBJECT (demux, "committing index");
2957         gst_index_commit (index, demux->index_id);
2958         gst_object_unref (index);
2959       }
2960
2961       if (!demux->audio_pad && !demux->video_pad)
2962         GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2963             ("Internal data stream error."), ("Got EOS before any data"));
2964       else {
2965         if (!demux->no_more_pads) {
2966           gst_element_no_more_pads (GST_ELEMENT (demux));
2967           demux->no_more_pads = TRUE;
2968         }
2969
2970         if (!gst_flv_demux_push_src_event (demux, event))
2971           GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2972       }
2973       ret = TRUE;
2974       break;
2975     }
2976     case GST_EVENT_SEGMENT:
2977     {
2978       GstSegment in_segment;
2979
2980       GST_DEBUG_OBJECT (demux, "received new segment");
2981
2982       gst_event_copy_segment (event, &in_segment);
2983
2984       if (in_segment.format == GST_FORMAT_TIME) {
2985         /* time segment, this is perfect, copy over the values. */
2986         memcpy (&demux->segment, &in_segment, sizeof (in_segment));
2987
2988         GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
2989             &demux->segment);
2990
2991         /* and forward */
2992         ret = gst_flv_demux_push_src_event (demux, event);
2993       } else {
2994         /* non-time format */
2995         demux->audio_need_segment = TRUE;
2996         demux->video_need_segment = TRUE;
2997         ret = TRUE;
2998         gst_event_unref (event);
2999         if (demux->new_seg_event) {
3000           gst_event_unref (demux->new_seg_event);
3001           demux->new_seg_event = NULL;
3002         }
3003       }
3004       break;
3005     }
3006     default:
3007       ret = gst_flv_demux_push_src_event (demux, event);
3008       break;
3009   }
3010
3011   return ret;
3012 }
3013
3014 static gboolean
3015 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
3016 {
3017   GstFlvDemux *demux;
3018   gboolean ret = FALSE;
3019
3020   demux = GST_FLV_DEMUX (parent);
3021
3022   GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
3023
3024   switch (GST_EVENT_TYPE (event)) {
3025     case GST_EVENT_SEEK:
3026       if (demux->random_access) {
3027         ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
3028       } else {
3029         ret = gst_flv_demux_handle_seek_push (demux, event);
3030       }
3031       break;
3032     default:
3033       ret = gst_pad_push_event (demux->sinkpad, event);
3034       break;
3035   }
3036
3037   return ret;
3038 }
3039
3040 static gboolean
3041 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
3042 {
3043   gboolean res = TRUE;
3044   GstFlvDemux *demux;
3045
3046   demux = GST_FLV_DEMUX (parent);
3047
3048   switch (GST_QUERY_TYPE (query)) {
3049     case GST_QUERY_DURATION:
3050     {
3051       GstFormat format;
3052
3053       gst_query_parse_duration (query, &format, NULL);
3054
3055       /* duration is time only */
3056       if (format != GST_FORMAT_TIME) {
3057         GST_DEBUG_OBJECT (demux, "duration query only supported for time "
3058             "format");
3059         res = FALSE;
3060         goto beach;
3061       }
3062
3063       GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3064           GST_TIME_ARGS (demux->duration));
3065
3066       gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3067
3068       break;
3069     }
3070     case GST_QUERY_POSITION:
3071     {
3072       GstFormat format;
3073
3074       gst_query_parse_position (query, &format, NULL);
3075
3076       /* position is time only */
3077       if (format != GST_FORMAT_TIME) {
3078         GST_DEBUG_OBJECT (demux, "position query only supported for time "
3079             "format");
3080         res = FALSE;
3081         goto beach;
3082       }
3083
3084       GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3085           GST_TIME_ARGS (demux->segment.position));
3086
3087       gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3088
3089       break;
3090     }
3091
3092     case GST_QUERY_SEEKING:{
3093       GstFormat fmt;
3094
3095       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3096
3097       /* First ask upstream */
3098       if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3099         gboolean seekable;
3100
3101         gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3102         if (seekable) {
3103           res = TRUE;
3104           break;
3105         }
3106       }
3107       res = TRUE;
3108       /* FIXME, check index this way is not thread safe */
3109       if (fmt != GST_FORMAT_TIME || !demux->index) {
3110         gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3111       } else if (demux->random_access) {
3112         gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3113             demux->duration);
3114       } else {
3115         GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3116         gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3117
3118         if (seekable)
3119           gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3120         gst_query_unref (peerquery);
3121
3122         if (seekable)
3123           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3124               demux->duration);
3125         else
3126           gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3127       }
3128       break;
3129     }
3130     case GST_QUERY_LATENCY:
3131     default:
3132       res = gst_pad_query_default (pad, parent, query);
3133       break;
3134   }
3135
3136 beach:
3137
3138   return res;
3139 }
3140
3141 static GstStateChangeReturn
3142 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3143 {
3144   GstFlvDemux *demux;
3145   GstStateChangeReturn ret;
3146
3147   demux = GST_FLV_DEMUX (element);
3148
3149   switch (transition) {
3150     case GST_STATE_CHANGE_READY_TO_PAUSED:
3151       /* If this is our own index destroy it as the
3152        * old entries might be wrong for the new stream */
3153       if (demux->own_index) {
3154         gst_object_unref (demux->index);
3155         demux->index = NULL;
3156         demux->own_index = FALSE;
3157       }
3158
3159       /* If no index was created, generate one */
3160       if (G_UNLIKELY (!demux->index)) {
3161         GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3162
3163         demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3164
3165         gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3166             &demux->index_id);
3167         demux->own_index = TRUE;
3168       }
3169       gst_flv_demux_cleanup (demux);
3170       break;
3171     default:
3172       break;
3173   }
3174
3175   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3176   if (ret == GST_STATE_CHANGE_FAILURE)
3177     return ret;
3178
3179   switch (transition) {
3180     case GST_STATE_CHANGE_PAUSED_TO_READY:
3181       gst_flv_demux_cleanup (demux);
3182       break;
3183     default:
3184       break;
3185   }
3186
3187   return ret;
3188 }
3189
3190 #if 0
3191 static void
3192 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3193 {
3194   GstFlvDemux *demux = GST_FLV_DEMUX (element);
3195   GstIndex *old_index;
3196
3197   GST_OBJECT_LOCK (demux);
3198
3199   old_index = demux->index;
3200
3201   if (index) {
3202     demux->index = gst_object_ref (index);
3203     demux->own_index = FALSE;
3204   } else
3205     demux->index = NULL;
3206
3207   if (old_index)
3208     gst_object_unref (demux->index);
3209
3210   gst_object_ref (index);
3211
3212   GST_OBJECT_UNLOCK (demux);
3213
3214   /* object lock might be taken again */
3215   if (index)
3216     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3217
3218   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3219
3220   gst_object_unref (index);
3221 }
3222 #endif
3223
3224 static GstIndex *
3225 gst_flv_demux_get_index (GstElement * element)
3226 {
3227   GstIndex *result = NULL;
3228
3229   GstFlvDemux *demux = GST_FLV_DEMUX (element);
3230
3231   GST_OBJECT_LOCK (demux);
3232   if (demux->index)
3233     result = gst_object_ref (demux->index);
3234   GST_OBJECT_UNLOCK (demux);
3235
3236   return result;
3237 }
3238
3239 static void
3240 gst_flv_demux_dispose (GObject * object)
3241 {
3242   GstFlvDemux *demux = GST_FLV_DEMUX (object);
3243
3244   GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3245
3246   if (demux->adapter) {
3247     gst_adapter_clear (demux->adapter);
3248     g_object_unref (demux->adapter);
3249     demux->adapter = NULL;
3250   }
3251
3252   if (demux->taglist) {
3253     gst_tag_list_unref (demux->taglist);
3254     demux->taglist = NULL;
3255   }
3256
3257   if (demux->new_seg_event) {
3258     gst_event_unref (demux->new_seg_event);
3259     demux->new_seg_event = NULL;
3260   }
3261
3262   if (demux->audio_codec_data) {
3263     gst_buffer_unref (demux->audio_codec_data);
3264     demux->audio_codec_data = NULL;
3265   }
3266
3267   if (demux->video_codec_data) {
3268     gst_buffer_unref (demux->video_codec_data);
3269     demux->video_codec_data = NULL;
3270   }
3271
3272   if (demux->audio_pad) {
3273     gst_object_unref (demux->audio_pad);
3274     demux->audio_pad = NULL;
3275   }
3276
3277   if (demux->video_pad) {
3278     gst_object_unref (demux->video_pad);
3279     demux->video_pad = NULL;
3280   }
3281
3282   if (demux->index) {
3283     gst_object_unref (demux->index);
3284     demux->index = NULL;
3285   }
3286
3287   if (demux->times) {
3288     g_array_free (demux->times, TRUE);
3289     demux->times = NULL;
3290   }
3291
3292   if (demux->filepositions) {
3293     g_array_free (demux->filepositions, TRUE);
3294     demux->filepositions = NULL;
3295   }
3296
3297   GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3298 }
3299
3300 static void
3301 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3302 {
3303   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3304   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3305
3306   gobject_class->dispose = gst_flv_demux_dispose;
3307
3308   gstelement_class->change_state =
3309       GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3310
3311 #if 0
3312   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3313   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3314 #endif
3315
3316   gst_element_class_add_pad_template (gstelement_class,
3317       gst_static_pad_template_get (&flv_sink_template));
3318   gst_element_class_add_pad_template (gstelement_class,
3319       gst_static_pad_template_get (&audio_src_template));
3320   gst_element_class_add_pad_template (gstelement_class,
3321       gst_static_pad_template_get (&video_src_template));
3322   gst_element_class_set_static_metadata (gstelement_class, "FLV Demuxer",
3323       "Codec/Demuxer",
3324       "Demux FLV feeds into digital streams",
3325       "Julien Moutte <julien@moutte.net>");
3326 }
3327
3328 static void
3329 gst_flv_demux_init (GstFlvDemux * demux)
3330 {
3331   demux->sinkpad =
3332       gst_pad_new_from_static_template (&flv_sink_template, "sink");
3333
3334   gst_pad_set_event_function (demux->sinkpad,
3335       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3336   gst_pad_set_chain_function (demux->sinkpad,
3337       GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3338   gst_pad_set_activate_function (demux->sinkpad,
3339       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3340   gst_pad_set_activatemode_function (demux->sinkpad,
3341       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3342
3343   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3344
3345   demux->adapter = gst_adapter_new ();
3346   demux->taglist = gst_tag_list_new_empty ();
3347   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3348
3349   demux->own_index = FALSE;
3350
3351   GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3352
3353   gst_flv_demux_cleanup (demux);
3354 }
3355
3356 static gboolean
3357 plugin_init (GstPlugin * plugin)
3358 {
3359   GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3360
3361   if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3362           gst_flv_demux_get_type ()) ||
3363       !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3364           gst_flv_mux_get_type ()))
3365     return FALSE;
3366
3367   return TRUE;
3368 }
3369
3370 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3371     flv, "FLV muxing and demuxing plugin",
3372     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)