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