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