update for activation changes
[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, guint32 * last,
785     GstClockTime * offset)
786 {
787   if (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 (%d)",
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->last_audio_pts,
996       &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, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
1042       " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT,
1043       gst_buffer_get_size (outbuf),
1044       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1045       GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf));
1046
1047   if (!GST_CLOCK_TIME_IS_VALID (demux->audio_start)) {
1048     demux->audio_start = GST_BUFFER_TIMESTAMP (outbuf);
1049   }
1050   if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1051     demux->audio_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1052   }
1053
1054   if (G_UNLIKELY (!demux->no_more_pads
1055           && (GST_CLOCK_DIFF (demux->audio_start,
1056                   GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1057     GST_DEBUG_OBJECT (demux,
1058         "Signalling no-more-pads because no video stream was found"
1059         " after 6 seconds of audio");
1060     gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1061     demux->no_more_pads = TRUE;
1062     demux->push_tags = TRUE;
1063   }
1064
1065   /* Push downstream */
1066   ret = gst_pad_push (demux->audio_pad, outbuf);
1067   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1068     if (demux->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
1069         demux->segment.position > demux->segment.stop) {
1070       /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
1071        * we are at the end of the segment, so we just need to jump
1072        * back to the previous section. */
1073       GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1074       demux->audio_done = TRUE;
1075       ret = GST_FLOW_OK;
1076     } else {
1077       GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1078           " bytes audio buffer: %s", demux->tag_data_size,
1079           gst_flow_get_name (ret));
1080       if (ret == GST_FLOW_NOT_LINKED) {
1081         demux->audio_linked = FALSE;
1082       }
1083       goto beach;
1084     }
1085   }
1086
1087   demux->audio_linked = TRUE;
1088
1089 beach:
1090   gst_buffer_unmap (buffer, data, -1);
1091
1092   return ret;
1093 }
1094
1095 static gboolean
1096 gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
1097 {
1098   gboolean ret = FALSE;
1099   GstCaps *caps = NULL;
1100   gchar *codec_name = NULL;
1101
1102   /* Generate caps for that pad */
1103   switch (codec_tag) {
1104     case 2:
1105       caps = gst_caps_new_empty_simple ("video/x-flash-video");
1106       break;
1107     case 3:
1108       caps = gst_caps_new_empty_simple ("video/x-flash-screen");
1109       break;
1110     case 4:
1111       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
1112       break;
1113     case 5:
1114       caps = gst_caps_new_empty_simple ("video/x-vp6-alpha");
1115       break;
1116     case 7:
1117       caps =
1118           gst_caps_new_simple ("video/x-h264", "stream-format", G_TYPE_STRING,
1119           "avc", NULL);
1120       break;
1121     default:
1122       GST_WARNING_OBJECT (demux, "unsupported video codec tag %u", codec_tag);
1123   }
1124
1125   if (G_UNLIKELY (!caps)) {
1126     GST_WARNING_OBJECT (demux, "failed creating caps for video pad");
1127     goto beach;
1128   }
1129
1130   gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1131       demux->par_x, demux->par_y, NULL);
1132
1133   if (G_LIKELY (demux->w)) {
1134     gst_caps_set_simple (caps, "width", G_TYPE_INT, demux->w, NULL);
1135   }
1136
1137   if (G_LIKELY (demux->h)) {
1138     gst_caps_set_simple (caps, "height", G_TYPE_INT, demux->h, NULL);
1139   }
1140
1141   if (G_LIKELY (demux->framerate)) {
1142     gint num = 0, den = 0;
1143
1144     gst_util_double_to_fraction (demux->framerate, &num, &den);
1145     GST_DEBUG_OBJECT (demux->video_pad,
1146         "fps to be used on caps %f (as a fraction = %d/%d)", demux->framerate,
1147         num, den);
1148
1149     gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, num, den, NULL);
1150   }
1151
1152   if (demux->video_codec_data) {
1153     gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER,
1154         demux->video_codec_data, NULL);
1155   }
1156
1157   ret = gst_pad_set_caps (demux->video_pad, caps);
1158
1159   if (G_LIKELY (ret)) {
1160     /* Store the caps we have set */
1161     demux->video_codec_tag = codec_tag;
1162
1163     codec_name = gst_pb_utils_get_codec_description (caps);
1164
1165     if (codec_name) {
1166       if (demux->taglist == NULL)
1167         demux->taglist = gst_tag_list_new_empty ();
1168       gst_tag_list_add (demux->taglist, GST_TAG_MERGE_REPLACE,
1169           GST_TAG_VIDEO_CODEC, codec_name, NULL);
1170       g_free (codec_name);
1171     }
1172
1173     GST_DEBUG_OBJECT (demux->video_pad, "successfully negotiated caps %"
1174         GST_PTR_FORMAT, caps);
1175   } else {
1176     GST_WARNING_OBJECT (demux->video_pad, "failed negotiating caps %"
1177         GST_PTR_FORMAT, caps);
1178   }
1179
1180   gst_caps_unref (caps);
1181
1182 beach:
1183   return ret;
1184 }
1185
1186 static GstFlowReturn
1187 gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
1188 {
1189   GstFlowReturn ret = GST_FLOW_OK;
1190   guint32 pts = 0, codec_data = 1, pts_ext = 0;
1191   gboolean keyframe = FALSE;
1192   guint8 flags = 0, codec_tag = 0;
1193   guint8 *data;
1194   GstBuffer *outbuf;
1195   gsize size;
1196
1197   g_return_val_if_fail (gst_buffer_get_size (buffer) == demux->tag_size,
1198       GST_FLOW_ERROR);
1199
1200   GST_LOG_OBJECT (demux, "parsing a video tag");
1201
1202   if (demux->no_more_pads && !demux->video_pad) {
1203     GST_WARNING_OBJECT (demux,
1204         "Signaled no-more-pads already but had no audio pad -- ignoring");
1205     return GST_FLOW_OK;
1206   }
1207
1208   if (gst_buffer_get_size (buffer) < 12) {
1209     GST_ERROR_OBJECT (demux, "Too small tag size");
1210     return GST_FLOW_ERROR;
1211   }
1212
1213   data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
1214
1215   /* Grab information about video tag */
1216   pts = GST_READ_UINT24_BE (data);
1217   /* read the pts extension to 32 bits integer */
1218   pts_ext = GST_READ_UINT8 (data + 3);
1219   /* Combine them */
1220   pts |= pts_ext << 24;
1221
1222   GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X (%d)", data[0], data[1],
1223       data[2], data[3], pts);
1224
1225   /* Skip the stream id and go directly to the flags */
1226   flags = GST_READ_UINT8 (data + 7);
1227
1228   /* Keyframe */
1229   if ((flags >> 4) == 1) {
1230     keyframe = TRUE;
1231   }
1232   /* Codec tag */
1233   codec_tag = flags & 0x0F;
1234   if (codec_tag == 4 || codec_tag == 5) {
1235     codec_data = 2;
1236   } else if (codec_tag == 7) {
1237     gint32 cts;
1238
1239     codec_data = 5;
1240
1241     cts = GST_READ_UINT24_BE (data + 9);
1242     cts = (cts + 0xff800000) ^ 0xff800000;
1243
1244     GST_LOG_OBJECT (demux, "got cts %d", cts);
1245
1246     /* avoid negative overflow */
1247     if (cts >= 0 || pts >= -cts)
1248       pts += cts;
1249   }
1250
1251   GST_LOG_OBJECT (demux, "video tag with codec tag %u, keyframe (%d) "
1252       "(flags %02X)", codec_tag, keyframe, flags);
1253
1254   /* If we don't have our video pad created, then create it. */
1255   if (G_UNLIKELY (!demux->video_pad)) {
1256     demux->video_pad =
1257         gst_pad_new_from_template (gst_element_class_get_pad_template
1258         (GST_ELEMENT_GET_CLASS (demux), "video"), "video");
1259     if (G_UNLIKELY (!demux->video_pad)) {
1260       GST_WARNING_OBJECT (demux, "failed creating video pad");
1261       ret = GST_FLOW_ERROR;
1262       goto beach;
1263     }
1264
1265     if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1266       gst_object_unref (demux->video_pad);
1267       demux->video_pad = NULL;
1268       ret = GST_FLOW_ERROR;
1269       goto beach;
1270     }
1271
1272     /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1273      * metadata tag that would come later and trigger a caps change */
1274     demux->got_par = FALSE;
1275
1276 #ifndef GST_DISABLE_GST_DEBUG
1277     {
1278       GstCaps *caps;
1279
1280       caps = gst_pad_get_current_caps (demux->video_pad);
1281       GST_DEBUG_OBJECT (demux, "created video pad with caps %" GST_PTR_FORMAT,
1282           caps);
1283       if (caps)
1284         gst_caps_unref (caps);
1285     }
1286 #endif
1287
1288     /* Set functions on the pad */
1289     gst_pad_set_query_function (demux->video_pad,
1290         GST_DEBUG_FUNCPTR (gst_flv_demux_query));
1291     gst_pad_set_event_function (demux->video_pad,
1292         GST_DEBUG_FUNCPTR (gst_flv_demux_src_event));
1293
1294     gst_pad_use_fixed_caps (demux->video_pad);
1295
1296     /* Make it active */
1297     gst_pad_set_active (demux->video_pad, TRUE);
1298
1299     /* We need to set caps before adding */
1300     gst_element_add_pad (GST_ELEMENT (demux),
1301         gst_object_ref (demux->video_pad));
1302
1303     /* We only emit no more pads when we have audio and video. Indeed we can
1304      * not trust the FLV header to tell us if there will be only audio or
1305      * only video and we would just break discovery of some files */
1306     if (demux->audio_pad && demux->video_pad) {
1307       GST_DEBUG_OBJECT (demux, "emitting no more pads");
1308       gst_element_no_more_pads (GST_ELEMENT (demux));
1309       demux->no_more_pads = TRUE;
1310       demux->push_tags = TRUE;
1311     }
1312   }
1313
1314   /* Check if caps have changed */
1315   if (G_UNLIKELY (codec_tag != demux->video_codec_tag || demux->got_par)) {
1316
1317     GST_DEBUG_OBJECT (demux, "video settings have changed, changing caps");
1318
1319     if (!gst_flv_demux_video_negotiate (demux, codec_tag)) {
1320       ret = GST_FLOW_ERROR;
1321       goto beach;
1322     }
1323
1324     /* When we ve set pixel-aspect-ratio we use that boolean to detect a
1325      * metadata tag that would come later and trigger a caps change */
1326     demux->got_par = FALSE;
1327   }
1328
1329   /* Push taglist if present */
1330   if (G_UNLIKELY (demux->push_tags))
1331     gst_flv_demux_push_tags (demux);
1332
1333   /* Check if we have anything to push */
1334   if (demux->tag_data_size <= codec_data) {
1335     GST_LOG_OBJECT (demux, "Nothing left in this tag, returning");
1336     goto beach;
1337   }
1338
1339   /* Create buffer from pad */
1340   outbuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_MEMORY,
1341       7 + codec_data, demux->tag_data_size - codec_data);
1342
1343   if (demux->video_codec_tag == 7) {
1344     guint8 avc_packet_type = GST_READ_UINT8 (data + 8);
1345
1346     switch (avc_packet_type) {
1347       case 0:
1348       {
1349         /* AVCDecoderConfigurationRecord data */
1350         GST_LOG_OBJECT (demux, "got an H.264 codec data packet");
1351         if (demux->video_codec_data) {
1352           gst_buffer_unref (demux->video_codec_data);
1353         }
1354         demux->video_codec_data = outbuf;
1355         /* Use that buffer data in the caps */
1356         gst_flv_demux_video_negotiate (demux, codec_tag);
1357         goto beach;
1358         break;
1359       }
1360       case 1:
1361         /* H.264 NALU packet */
1362         GST_LOG_OBJECT (demux, "got a H.264 NALU video packet");
1363         break;
1364       default:
1365         GST_WARNING_OBJECT (demux, "invalid video packet type %u",
1366             avc_packet_type);
1367     }
1368   }
1369
1370   /* detect (and deem to be resyncs)  large pts gaps */
1371   gst_flv_demux_update_resync (demux, pts, &demux->last_video_pts,
1372       &demux->video_time_offset);
1373
1374   /* Fill buffer with data */
1375   GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
1376   GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1377   GST_BUFFER_OFFSET (outbuf) = demux->video_offset++;
1378   GST_BUFFER_OFFSET_END (outbuf) = demux->video_offset;
1379
1380   if (demux->duration == GST_CLOCK_TIME_NONE ||
1381       demux->duration < GST_BUFFER_TIMESTAMP (outbuf))
1382     demux->duration = GST_BUFFER_TIMESTAMP (outbuf);
1383
1384   if (!keyframe)
1385     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1386
1387   if (!demux->indexed && demux->index) {
1388     gst_flv_demux_parse_and_add_index_entry (demux,
1389         GST_BUFFER_TIMESTAMP (outbuf), demux->cur_tag_offset, keyframe);
1390   }
1391
1392   if (G_UNLIKELY (demux->video_need_discont)) {
1393     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1394     demux->video_need_discont = FALSE;
1395   }
1396
1397   demux->segment.position = GST_BUFFER_TIMESTAMP (outbuf);
1398
1399   /* Do we need a newsegment event ? */
1400   if (G_UNLIKELY (demux->video_need_segment)) {
1401     /* FIXME need one segment sent for all stream to maintain a/v sync */
1402     if (!demux->new_seg_event) {
1403       GST_DEBUG_OBJECT (demux, "pushing newsegment from %"
1404           GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
1405           GST_TIME_ARGS (demux->segment.position),
1406           GST_TIME_ARGS (demux->segment.stop));
1407       demux->segment.start = demux->segment.time = demux->segment.position;
1408       demux->new_seg_event = gst_event_new_segment (&demux->segment);
1409     } else {
1410       GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
1411     }
1412
1413     gst_pad_push_event (demux->video_pad, gst_event_ref (demux->new_seg_event));
1414
1415     demux->video_need_segment = FALSE;
1416   }
1417
1418   GST_LOG_OBJECT (demux, "pushing %d bytes buffer at pts %" GST_TIME_FORMAT
1419       " with duration %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
1420       ", keyframe (%d)", gst_buffer_get_size (outbuf),
1421       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1422       GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
1423       keyframe);
1424
1425   if (!GST_CLOCK_TIME_IS_VALID (demux->video_start)) {
1426     demux->video_start = GST_BUFFER_TIMESTAMP (outbuf);
1427   }
1428   if (!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts)) {
1429     demux->video_first_ts = GST_BUFFER_TIMESTAMP (outbuf);
1430   }
1431
1432   if (G_UNLIKELY (!demux->no_more_pads
1433           && (GST_CLOCK_DIFF (demux->video_start,
1434                   GST_BUFFER_TIMESTAMP (outbuf)) > 6 * GST_SECOND))) {
1435     GST_DEBUG_OBJECT (demux,
1436         "Signalling no-more-pads because no audio stream was found"
1437         " after 6 seconds of video");
1438     gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
1439     demux->no_more_pads = TRUE;
1440     demux->push_tags = TRUE;
1441   }
1442
1443   /* Push downstream */
1444   ret = gst_pad_push (demux->video_pad, outbuf);
1445
1446   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1447     if (demux->segment.rate < 0.0 && ret == GST_FLOW_UNEXPECTED &&
1448         demux->segment.position > demux->segment.stop) {
1449       /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
1450        * we are at the end of the segment, so we just need to jump
1451        * back to the previous section. */
1452       GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
1453       demux->video_done = TRUE;
1454       ret = GST_FLOW_OK;
1455     } else {
1456       GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
1457           " bytes video buffer: %s", demux->tag_data_size,
1458           gst_flow_get_name (ret));
1459       if (ret == GST_FLOW_NOT_LINKED) {
1460         demux->video_linked = FALSE;
1461       }
1462       goto beach;
1463     }
1464   }
1465
1466   demux->video_linked = TRUE;
1467
1468 beach:
1469   gst_buffer_unmap (buffer, data, -1);
1470   return ret;
1471 }
1472
1473 static GstClockTime
1474 gst_flv_demux_parse_tag_timestamp (GstFlvDemux * demux, gboolean index,
1475     GstBuffer * buffer, size_t * tag_size)
1476 {
1477   guint32 pts = 0, pts_ext = 0;
1478   guint32 tag_data_size;
1479   guint8 type;
1480   gboolean keyframe = TRUE;
1481   GstClockTime ret = GST_CLOCK_TIME_NONE;
1482   guint8 *data, *bdata;
1483   gsize size;
1484
1485   g_return_val_if_fail (gst_buffer_get_size (buffer) >= 12,
1486       GST_CLOCK_TIME_NONE);
1487
1488   data = bdata = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
1489
1490   type = data[0];
1491
1492   if (type != 9 && type != 8 && type != 18) {
1493     GST_WARNING_OBJECT (demux, "Unsupported tag type %u", data[0]);
1494     goto exit;
1495   }
1496
1497   if (type == 9)
1498     demux->has_video = TRUE;
1499   else if (type == 8)
1500     demux->has_audio = TRUE;
1501
1502   tag_data_size = GST_READ_UINT24_BE (data + 1);
1503
1504   if (size >= tag_data_size + 11 + 4) {
1505     if (GST_READ_UINT32_BE (data + tag_data_size + 11) != tag_data_size + 11) {
1506       GST_WARNING_OBJECT (demux, "Invalid tag size");
1507       goto exit;
1508     }
1509   }
1510
1511   if (tag_size)
1512     *tag_size = tag_data_size + 11 + 4;
1513
1514   data += 4;
1515
1516   GST_LOG_OBJECT (demux, "pts bytes %02X %02X %02X %02X", data[0], data[1],
1517       data[2], data[3]);
1518
1519   /* Grab timestamp of tag tag */
1520   pts = GST_READ_UINT24_BE (data);
1521   /* read the pts extension to 32 bits integer */
1522   pts_ext = GST_READ_UINT8 (data + 3);
1523   /* Combine them */
1524   pts |= pts_ext << 24;
1525
1526   if (type == 9) {
1527     data += 7;
1528
1529     keyframe = ((data[0] >> 4) == 1);
1530   }
1531
1532   ret = pts * GST_MSECOND;
1533   GST_LOG_OBJECT (demux, "pts: %" GST_TIME_FORMAT, GST_TIME_ARGS (ret));
1534
1535   if (index && demux->index && !demux->indexed && (type == 9 || (type == 8
1536               && !demux->has_video))) {
1537     gst_flv_demux_parse_and_add_index_entry (demux, ret, demux->offset,
1538         keyframe);
1539   }
1540
1541   if (demux->duration == GST_CLOCK_TIME_NONE || demux->duration < ret)
1542     demux->duration = ret;
1543
1544 exit:
1545   gst_buffer_unmap (buffer, bdata, -1);
1546   return ret;
1547 }
1548
1549 static GstFlowReturn
1550 gst_flv_demux_parse_tag_type (GstFlvDemux * demux, GstBuffer * buffer)
1551 {
1552   GstFlowReturn ret = GST_FLOW_OK;
1553   guint8 tag_type = 0;
1554   guint8 *data;
1555
1556   g_return_val_if_fail (gst_buffer_get_size (buffer) >= 4, GST_FLOW_ERROR);
1557
1558   data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_READ);
1559
1560   tag_type = data[0];
1561
1562   switch (tag_type) {
1563     case 9:
1564       demux->state = FLV_STATE_TAG_VIDEO;
1565       demux->has_video = TRUE;
1566       break;
1567     case 8:
1568       demux->state = FLV_STATE_TAG_AUDIO;
1569       demux->has_audio = TRUE;
1570       break;
1571     case 18:
1572       demux->state = FLV_STATE_TAG_SCRIPT;
1573       break;
1574     default:
1575       GST_WARNING_OBJECT (demux, "unsupported tag type %u", tag_type);
1576   }
1577
1578   /* Tag size is 1 byte of type + 3 bytes of size + 7 bytes + tag data size +
1579    * 4 bytes of previous tag size */
1580   demux->tag_data_size = GST_READ_UINT24_BE (data + 1);
1581   demux->tag_size = demux->tag_data_size + 11;
1582
1583   GST_LOG_OBJECT (demux, "tag data size is %" G_GUINT64_FORMAT,
1584       demux->tag_data_size);
1585
1586   gst_buffer_unmap (buffer, data, -1);
1587
1588   return ret;
1589 }
1590
1591 static GstFlowReturn
1592 gst_flv_demux_parse_header (GstFlvDemux * demux, GstBuffer * buffer)
1593 {
1594   GstFlowReturn ret = GST_FLOW_OK;
1595   guint8 *data;
1596
1597   g_return_val_if_fail (gst_buffer_get_size (buffer) >= 9, GST_FLOW_ERROR);
1598
1599   data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_READ);
1600
1601   /* Check for the FLV tag */
1602   if (data[0] == 'F' && data[1] == 'L' && data[2] == 'V') {
1603     GST_DEBUG_OBJECT (demux, "FLV header detected");
1604   } else {
1605     if (G_UNLIKELY (demux->strict)) {
1606       GST_WARNING_OBJECT (demux, "invalid header tag detected");
1607       ret = GST_FLOW_UNEXPECTED;
1608       goto beach;
1609     }
1610   }
1611
1612   /* Now look at audio/video flags */
1613   {
1614     guint8 flags = data[4];
1615
1616     demux->has_video = demux->has_audio = FALSE;
1617
1618     if (flags & 1) {
1619       GST_DEBUG_OBJECT (demux, "there is a video stream");
1620       demux->has_video = TRUE;
1621     }
1622     if (flags & 4) {
1623       GST_DEBUG_OBJECT (demux, "there is an audio stream");
1624       demux->has_audio = TRUE;
1625     }
1626   }
1627
1628   /* do a one-time seekability check */
1629   gst_flv_demux_check_seekability (demux);
1630
1631   /* We don't care about the rest */
1632   demux->need_header = FALSE;
1633
1634 beach:
1635   gst_buffer_unmap (buffer, data, -1);
1636   return ret;
1637 }
1638
1639
1640 static void
1641 gst_flv_demux_flush (GstFlvDemux * demux, gboolean discont)
1642 {
1643   GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
1644
1645   gst_adapter_clear (demux->adapter);
1646
1647   demux->audio_need_discont = TRUE;
1648   demux->video_need_discont = TRUE;
1649
1650   demux->flushing = FALSE;
1651
1652   /* Only in push mode and if we're not during a seek */
1653   if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
1654     /* After a flush we expect a tag_type */
1655     demux->state = FLV_STATE_TAG_TYPE;
1656     /* We reset the offset and will get one from first push */
1657     demux->offset = 0;
1658   }
1659 }
1660
1661 static void
1662 gst_flv_demux_cleanup (GstFlvDemux * demux)
1663 {
1664   GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
1665
1666   demux->state = FLV_STATE_HEADER;
1667
1668   demux->flushing = FALSE;
1669   demux->need_header = TRUE;
1670   demux->audio_need_segment = TRUE;
1671   demux->video_need_segment = TRUE;
1672   demux->audio_need_discont = TRUE;
1673   demux->video_need_discont = TRUE;
1674
1675   /* By default we consider them as linked */
1676   demux->audio_linked = TRUE;
1677   demux->video_linked = TRUE;
1678
1679   demux->has_audio = FALSE;
1680   demux->has_video = FALSE;
1681   demux->push_tags = FALSE;
1682   demux->got_par = FALSE;
1683
1684   demux->indexed = FALSE;
1685   demux->upstream_seekable = FALSE;
1686   demux->file_size = 0;
1687
1688   demux->index_max_pos = 0;
1689   demux->index_max_time = 0;
1690
1691   demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
1692   demux->last_audio_pts = demux->last_video_pts = 0;
1693   demux->audio_time_offset = demux->video_time_offset = 0;
1694
1695   demux->no_more_pads = FALSE;
1696
1697   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1698
1699   demux->w = demux->h = 0;
1700   demux->framerate = 0.0;
1701   demux->par_x = demux->par_y = 1;
1702   demux->video_offset = 0;
1703   demux->audio_offset = 0;
1704   demux->offset = demux->cur_tag_offset = 0;
1705   demux->tag_size = demux->tag_data_size = 0;
1706   demux->duration = GST_CLOCK_TIME_NONE;
1707
1708   if (demux->new_seg_event) {
1709     gst_event_unref (demux->new_seg_event);
1710     demux->new_seg_event = NULL;
1711   }
1712
1713   gst_adapter_clear (demux->adapter);
1714
1715   if (demux->audio_codec_data) {
1716     gst_buffer_unref (demux->audio_codec_data);
1717     demux->audio_codec_data = NULL;
1718   }
1719
1720   if (demux->video_codec_data) {
1721     gst_buffer_unref (demux->video_codec_data);
1722     demux->video_codec_data = NULL;
1723   }
1724
1725   if (demux->audio_pad) {
1726     gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
1727     gst_object_unref (demux->audio_pad);
1728     demux->audio_pad = NULL;
1729   }
1730
1731   if (demux->video_pad) {
1732     gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
1733     gst_object_unref (demux->video_pad);
1734     demux->video_pad = NULL;
1735   }
1736
1737   if (demux->times) {
1738     g_array_free (demux->times, TRUE);
1739     demux->times = NULL;
1740   }
1741
1742   if (demux->filepositions) {
1743     g_array_free (demux->filepositions, TRUE);
1744     demux->filepositions = NULL;
1745   }
1746 }
1747
1748 /*
1749  * Create and push a flushing seek event upstream
1750  */
1751 static gboolean
1752 flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
1753 {
1754   GstEvent *event;
1755   gboolean res = 0;
1756
1757   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1758
1759   event =
1760       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1761       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1762       GST_SEEK_TYPE_NONE, -1);
1763
1764   res = gst_pad_push_event (demux->sinkpad, event);
1765
1766   if (res)
1767     demux->offset = offset;
1768   return res;
1769 }
1770
1771 static GstFlowReturn
1772 gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
1773 {
1774   GstFlowReturn ret = GST_FLOW_OK;
1775   GstFlvDemux *demux = NULL;
1776
1777   demux = GST_FLV_DEMUX (parent);
1778
1779   GST_LOG_OBJECT (demux, "received buffer of %d bytes at offset %"
1780       G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
1781       GST_BUFFER_OFFSET (buffer));
1782
1783   if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
1784     GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
1785     demux->state = FLV_STATE_HEADER;
1786     demux->offset = 0;
1787   }
1788
1789   if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
1790     GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
1791     demux->offset = GST_BUFFER_OFFSET (buffer);
1792   }
1793
1794   if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
1795     GST_DEBUG_OBJECT (demux, "Discontinuity");
1796     gst_adapter_clear (demux->adapter);
1797   }
1798
1799   gst_adapter_push (demux->adapter, buffer);
1800
1801   if (demux->seeking) {
1802     demux->state = FLV_STATE_SEEK;
1803     GST_OBJECT_LOCK (demux);
1804     demux->seeking = FALSE;
1805     GST_OBJECT_UNLOCK (demux);
1806   }
1807
1808 parse:
1809   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
1810     if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
1811             || demux->video_linked)) {
1812       ret = GST_FLOW_OK;
1813     } else {
1814       GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
1815       goto beach;
1816     }
1817   }
1818
1819   if (G_UNLIKELY (demux->flushing)) {
1820     GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
1821     ret = GST_FLOW_WRONG_STATE;
1822     goto beach;
1823   }
1824
1825   switch (demux->state) {
1826     case FLV_STATE_HEADER:
1827     {
1828       if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
1829         GstBuffer *buffer;
1830
1831         buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
1832
1833         ret = gst_flv_demux_parse_header (demux, buffer);
1834
1835         gst_buffer_unref (buffer);
1836         demux->offset += FLV_HEADER_SIZE;
1837
1838         demux->state = FLV_STATE_TAG_TYPE;
1839         goto parse;
1840       } else {
1841         goto beach;
1842       }
1843     }
1844     case FLV_STATE_TAG_TYPE:
1845     {
1846       if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
1847         GstBuffer *buffer;
1848
1849         /* Remember the tag offset in bytes */
1850         demux->cur_tag_offset = demux->offset;
1851
1852         buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
1853
1854         ret = gst_flv_demux_parse_tag_type (demux, buffer);
1855
1856         gst_buffer_unref (buffer);
1857         demux->offset += FLV_TAG_TYPE_SIZE;
1858
1859         /* last tag is not an index => no index/don't know where the index is
1860          * seek back to the beginning */
1861         if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
1862           goto no_index;
1863
1864         goto parse;
1865       } else {
1866         goto beach;
1867       }
1868     }
1869     case FLV_STATE_TAG_VIDEO:
1870     {
1871       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1872         GstBuffer *buffer;
1873
1874         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1875
1876         ret = gst_flv_demux_parse_tag_video (demux, buffer);
1877
1878         gst_buffer_unref (buffer);
1879         demux->offset += demux->tag_size;
1880
1881         demux->state = FLV_STATE_TAG_TYPE;
1882         goto parse;
1883       } else {
1884         goto beach;
1885       }
1886     }
1887     case FLV_STATE_TAG_AUDIO:
1888     {
1889       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1890         GstBuffer *buffer;
1891
1892         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1893
1894         ret = gst_flv_demux_parse_tag_audio (demux, buffer);
1895
1896         gst_buffer_unref (buffer);
1897         demux->offset += demux->tag_size;
1898
1899         demux->state = FLV_STATE_TAG_TYPE;
1900         goto parse;
1901       } else {
1902         goto beach;
1903       }
1904     }
1905     case FLV_STATE_TAG_SCRIPT:
1906     {
1907       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
1908         GstBuffer *buffer;
1909
1910         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
1911
1912         ret = gst_flv_demux_parse_tag_script (demux, buffer);
1913
1914         gst_buffer_unref (buffer);
1915         demux->offset += demux->tag_size;
1916
1917         demux->state = FLV_STATE_TAG_TYPE;
1918
1919         /* if there's a seek event we're here for the index so if we don't have it
1920          * we seek back to the beginning */
1921         if (demux->seek_event) {
1922           if (demux->indexed)
1923             demux->state = FLV_STATE_SEEK;
1924           else
1925             goto no_index;
1926         }
1927
1928         goto parse;
1929       } else {
1930         goto beach;
1931       }
1932     }
1933     case FLV_STATE_SEEK:
1934     {
1935       GstEvent *event;
1936
1937       ret = GST_FLOW_OK;
1938
1939       if (!demux->indexed) {
1940         if (demux->offset == demux->file_size - sizeof (guint32)) {
1941           guint64 seek_offset;
1942           guint8 *data;
1943
1944           data = gst_adapter_take (demux->adapter, 4);
1945           if (!data)
1946             goto no_index;
1947
1948           seek_offset = demux->file_size - sizeof (guint32) -
1949               GST_READ_UINT32_BE (data);
1950           g_free (data);
1951
1952           GST_INFO_OBJECT (demux,
1953               "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
1954               seek_offset);
1955           demux->state = FLV_STATE_TAG_TYPE;
1956           flv_demux_seek_to_offset (demux, seek_offset);
1957           goto beach;
1958         } else
1959           goto no_index;
1960       }
1961
1962       GST_OBJECT_LOCK (demux);
1963       event = demux->seek_event;
1964       demux->seek_event = NULL;
1965       GST_OBJECT_UNLOCK (demux);
1966
1967       /* calculate and perform seek */
1968       if (!flv_demux_handle_seek_push (demux, event))
1969         goto seek_failed;
1970
1971       gst_event_unref (event);
1972       demux->state = FLV_STATE_TAG_TYPE;
1973       goto beach;
1974     }
1975     default:
1976       GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
1977   }
1978
1979 beach:
1980   if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
1981     /* If either audio or video is linked we return GST_FLOW_OK */
1982     if (demux->audio_linked || demux->video_linked) {
1983       ret = GST_FLOW_OK;
1984     }
1985   }
1986
1987   return ret;
1988
1989 /* ERRORS */
1990 no_index:
1991   {
1992     GST_OBJECT_LOCK (demux);
1993     demux->seeking = FALSE;
1994     gst_event_unref (demux->seek_event);
1995     demux->seek_event = NULL;
1996     GST_OBJECT_UNLOCK (demux);
1997     GST_WARNING_OBJECT (demux,
1998         "failed to find an index, seeking back to beginning");
1999     flv_demux_seek_to_offset (demux, 0);
2000     return GST_FLOW_OK;
2001   }
2002 seek_failed:
2003   {
2004     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
2005     return GST_FLOW_ERROR;
2006   }
2007
2008 }
2009
2010 static GstFlowReturn
2011 gst_flv_demux_pull_range (GstFlvDemux * demux, GstPad * pad, guint64 offset,
2012     guint size, GstBuffer ** buffer)
2013 {
2014   GstFlowReturn ret;
2015
2016   ret = gst_pad_pull_range (pad, offset, size, buffer);
2017   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
2018     GST_WARNING_OBJECT (demux,
2019         "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
2020         size, offset, gst_flow_get_name (ret));
2021     *buffer = NULL;
2022     return ret;
2023   }
2024
2025   if (G_UNLIKELY (*buffer && gst_buffer_get_size (*buffer) != size)) {
2026     GST_WARNING_OBJECT (demux,
2027         "partial pull got %d when expecting %d from offset %" G_GUINT64_FORMAT,
2028         gst_buffer_get_size (*buffer), size, offset);
2029     gst_buffer_unref (*buffer);
2030     ret = GST_FLOW_UNEXPECTED;
2031     *buffer = NULL;
2032     return ret;
2033   }
2034
2035   return ret;
2036 }
2037
2038 static GstFlowReturn
2039 gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
2040 {
2041   GstBuffer *buffer = NULL;
2042   GstFlowReturn ret = GST_FLOW_OK;
2043
2044   /* Store tag offset */
2045   demux->cur_tag_offset = demux->offset;
2046
2047   /* Get the first 4 bytes to identify tag type and size */
2048   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2049                   FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
2050     goto beach;
2051
2052   /* Identify tag type */
2053   ret = gst_flv_demux_parse_tag_type (demux, buffer);
2054
2055   gst_buffer_unref (buffer);
2056
2057   if (G_UNLIKELY (ret != GST_FLOW_OK))
2058     goto beach;
2059
2060   /* Jump over tag type + size */
2061   demux->offset += FLV_TAG_TYPE_SIZE;
2062
2063   /* Pull the whole tag */
2064   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2065                   demux->tag_size, &buffer)) != GST_FLOW_OK))
2066     goto beach;
2067
2068   switch (demux->state) {
2069     case FLV_STATE_TAG_VIDEO:
2070       ret = gst_flv_demux_parse_tag_video (demux, buffer);
2071       break;
2072     case FLV_STATE_TAG_AUDIO:
2073       ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2074       break;
2075     case FLV_STATE_TAG_SCRIPT:
2076       ret = gst_flv_demux_parse_tag_script (demux, buffer);
2077       break;
2078     default:
2079       GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2080   }
2081
2082   gst_buffer_unref (buffer);
2083
2084   /* Jump over that part we've just parsed */
2085   demux->offset += demux->tag_size;
2086
2087   /* Make sure we reinitialize the tag size */
2088   demux->tag_size = 0;
2089
2090   /* Ready for the next tag */
2091   demux->state = FLV_STATE_TAG_TYPE;
2092
2093   if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2094     /* If either audio or video is linked we return GST_FLOW_OK */
2095     if (demux->audio_linked || demux->video_linked) {
2096       ret = GST_FLOW_OK;
2097     } else {
2098       GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2099           "neither video nor audio are linked");
2100     }
2101   }
2102
2103 beach:
2104   return ret;
2105 }
2106
2107 static GstFlowReturn
2108 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2109 {
2110   GstBuffer *buffer = NULL;
2111   GstFlowReturn ret = GST_FLOW_OK;
2112
2113   /* Get the first 9 bytes */
2114   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2115                   FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2116     goto beach;
2117
2118   ret = gst_flv_demux_parse_header (demux, buffer);
2119
2120   gst_buffer_unref (buffer);
2121
2122   /* Jump over the header now */
2123   demux->offset += FLV_HEADER_SIZE;
2124   demux->state = FLV_STATE_TAG_TYPE;
2125
2126 beach:
2127   return ret;
2128 }
2129
2130 static void
2131 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2132     gboolean reset)
2133 {
2134   demux->offset = offset;
2135
2136   /* Tell all the stream we moved to a different position (discont) */
2137   demux->audio_need_discont = TRUE;
2138   demux->video_need_discont = TRUE;
2139
2140   /* next section setup */
2141   demux->from_offset = -1;
2142   demux->audio_done = demux->video_done = FALSE;
2143   demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2144
2145   if (reset) {
2146     demux->from_offset = -1;
2147     demux->to_offset = G_MAXINT64;
2148   }
2149
2150   /* If we seeked at the beginning of the file parse the header again */
2151   if (G_UNLIKELY (!demux->offset)) {
2152     demux->state = FLV_STATE_HEADER;
2153   } else {                      /* or parse a tag */
2154     demux->state = FLV_STATE_TAG_TYPE;
2155   }
2156 }
2157
2158 static GstFlowReturn
2159 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2160 {
2161   GstFlowReturn ret = GST_FLOW_UNEXPECTED;
2162   GstIndexEntry *entry = NULL;
2163
2164   GST_DEBUG_OBJECT (demux,
2165       "terminated section started at offset %" G_GINT64_FORMAT,
2166       demux->from_offset);
2167
2168   /* we are done if we got all audio and video */
2169   if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2170           demux->audio_first_ts < demux->segment.start) &&
2171       (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2172           demux->video_first_ts < demux->segment.start))
2173     goto done;
2174
2175   if (demux->from_offset <= 0)
2176     goto done;
2177
2178   GST_DEBUG_OBJECT (demux, "locating previous position");
2179
2180   /* locate index entry before previous start position */
2181   if (demux->index)
2182     entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2183         GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2184         GST_FORMAT_BYTES, demux->from_offset - 1);
2185
2186   if (entry) {
2187     gint64 bytes, time;
2188
2189     gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2190     gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2191
2192     GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2193         " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2194         demux->offset - 1, GST_TIME_ARGS (time), bytes);
2195
2196     /* setup for next section */
2197     demux->to_offset = demux->from_offset;
2198     gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2199     ret = GST_FLOW_OK;
2200   }
2201
2202 done:
2203   return ret;
2204 }
2205
2206 static GstFlowReturn
2207 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2208 {
2209   gint64 size;
2210   size_t tag_size;
2211   guint64 old_offset;
2212   GstBuffer *buffer;
2213   GstClockTime tag_time;
2214   GstFlowReturn ret = GST_FLOW_OK;
2215
2216   if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2217     return GST_FLOW_OK;
2218
2219   GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2220       " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2221
2222   old_offset = demux->offset;
2223   demux->offset = pos;
2224
2225   while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2226               12, &buffer)) == GST_FLOW_OK) {
2227     tag_time =
2228         gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2229
2230     gst_buffer_unref (buffer);
2231
2232     if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2233       goto exit;
2234
2235     demux->offset += tag_size;
2236   }
2237
2238   if (ret == GST_FLOW_UNEXPECTED) {
2239     /* file ran out, so mark we have complete index */
2240     demux->indexed = TRUE;
2241     ret = GST_FLOW_OK;
2242   }
2243
2244 exit:
2245   demux->offset = old_offset;
2246
2247   return ret;
2248 }
2249
2250 static gint64
2251 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2252 {
2253   gint64 ret = 0, offset;
2254   size_t tag_size, size;
2255   GstBuffer *buffer = NULL;
2256   guint8 *data;
2257
2258   if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2259     goto exit;
2260
2261   ret = offset;
2262   GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2263   if (G_UNLIKELY (offset < 4))
2264     goto exit;
2265
2266   offset -= 4;
2267   if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2268           4, &buffer))
2269     goto exit;
2270
2271   data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_READ);
2272   tag_size = GST_READ_UINT32_BE (data);
2273   gst_buffer_unmap (buffer, data, -1);
2274   GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2275   gst_buffer_unref (buffer);
2276   buffer = NULL;
2277
2278   offset -= tag_size;
2279   if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2280           12, &buffer))
2281     goto exit;
2282
2283   /* a consistency check */
2284   data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_READ);
2285   size = GST_READ_UINT24_BE (data + 1);
2286   if (size != tag_size - 11) {
2287     gst_buffer_unmap (buffer, data, -1);
2288     GST_DEBUG_OBJECT (demux,
2289         "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2290         ", corrupt or truncated file", size, tag_size - 11);
2291     goto exit;
2292   }
2293
2294   /* try to update duration with timestamp in any case */
2295   gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2296
2297   /* maybe get some more metadata */
2298   if (data[0] == 18) {
2299     gst_buffer_unmap (buffer, data, -1);
2300     gst_buffer_unref (buffer);
2301     buffer = NULL;
2302     GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2303     offset += 4;
2304     if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2305             tag_size, &buffer))
2306       gst_flv_demux_parse_tag_script (demux, buffer);
2307   } else {
2308     gst_buffer_unmap (buffer, data, -1);
2309   }
2310
2311 exit:
2312   if (buffer)
2313     gst_buffer_unref (buffer);
2314
2315   return ret;
2316 }
2317
2318 static void
2319 gst_flv_demux_loop (GstPad * pad)
2320 {
2321   GstFlvDemux *demux = NULL;
2322   GstFlowReturn ret = GST_FLOW_OK;
2323
2324   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2325
2326   /* pull in data */
2327   switch (demux->state) {
2328     case FLV_STATE_TAG_TYPE:
2329       if (demux->from_offset == -1)
2330         demux->from_offset = demux->offset;
2331       ret = gst_flv_demux_pull_tag (pad, demux);
2332       /* if we have seen real data, we probably passed a possible metadata
2333        * header located at start.  So if we do not yet have an index,
2334        * try to pick up metadata (index, duration) at the end */
2335       if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2336               (demux->has_video || demux->has_audio)))
2337         demux->file_size = gst_flv_demux_get_metadata (demux);
2338       break;
2339     case FLV_STATE_DONE:
2340       ret = GST_FLOW_UNEXPECTED;
2341       break;
2342     case FLV_STATE_SEEK:
2343       /* seek issued with insufficient index;
2344        * scan for index in task thread from current maximum offset to
2345        * desired time and then perform seek */
2346       /* TODO maybe some buffering message or so to indicate scan progress */
2347       ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2348           demux->seek_time);
2349       if (ret != GST_FLOW_OK)
2350         goto pause;
2351       /* position and state arranged by seek,
2352        * also unrefs event */
2353       gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2354       demux->seek_event = NULL;
2355       break;
2356     default:
2357       ret = gst_flv_demux_pull_header (pad, demux);
2358       /* index scans start after header */
2359       demux->index_max_pos = demux->offset;
2360       break;
2361   }
2362
2363   if (demux->segment.rate < 0.0) {
2364     /* check end of section */
2365     if ((gint64) demux->offset >= demux->to_offset ||
2366         demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2367         (demux->audio_done && demux->video_done))
2368       ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2369   } else {
2370     /* check EOS condition */
2371     if ((demux->segment.stop != -1) &&
2372         (demux->segment.position >= demux->segment.stop)) {
2373       ret = GST_FLOW_UNEXPECTED;
2374     }
2375   }
2376
2377   /* pause if something went wrong or at end */
2378   if (G_UNLIKELY (ret != GST_FLOW_OK))
2379     goto pause;
2380
2381   gst_object_unref (demux);
2382
2383   return;
2384
2385 pause:
2386   {
2387     const gchar *reason = gst_flow_get_name (ret);
2388
2389     GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2390     gst_pad_pause_task (pad);
2391
2392     if (ret == GST_FLOW_UNEXPECTED) {
2393       /* handle end-of-stream/segment */
2394       /* so align our position with the end of it, if there is one
2395        * this ensures a subsequent will arrive at correct base/acc time */
2396       if (demux->segment.rate > 0.0 &&
2397           GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2398         demux->segment.position = demux->segment.stop;
2399       else if (demux->segment.rate < 0.0)
2400         demux->segment.position = demux->segment.start;
2401
2402       /* perform EOS logic */
2403       if (!demux->no_more_pads) {
2404         gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2405         demux->no_more_pads = TRUE;
2406       }
2407
2408       if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2409         gint64 stop;
2410
2411         /* for segment playback we need to post when (in stream time)
2412          * we stopped, this is either stop (when set) or the duration. */
2413         if ((stop = demux->segment.stop) == -1)
2414           stop = demux->segment.duration;
2415
2416         if (demux->segment.rate >= 0) {
2417           GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2418           gst_element_post_message (GST_ELEMENT_CAST (demux),
2419               gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2420                   GST_FORMAT_TIME, stop));
2421         } else {                /* Reverse playback */
2422           GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2423               "segment");
2424           gst_element_post_message (GST_ELEMENT_CAST (demux),
2425               gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2426                   GST_FORMAT_TIME, demux->segment.start));
2427         }
2428       } else {
2429         /* normal playback, send EOS to all linked pads */
2430         if (!demux->no_more_pads) {
2431           gst_element_no_more_pads (GST_ELEMENT (demux));
2432           demux->no_more_pads = TRUE;
2433         }
2434
2435         GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2436         if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2437           GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2438       }
2439     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) {
2440       GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2441           ("Internal data stream error."),
2442           ("stream stopped, reason %s", reason));
2443       gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2444     }
2445     gst_object_unref (demux);
2446     return;
2447   }
2448 }
2449
2450 static guint64
2451 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2452 {
2453   gint64 bytes = 0;
2454   gint64 time = 0;
2455   GstIndexEntry *entry;
2456
2457   g_return_val_if_fail (segment != NULL, 0);
2458
2459   time = segment->position;
2460
2461   if (demux->index) {
2462     /* Let's check if we have an index entry for that seek time */
2463     entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2464         GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2465         GST_FORMAT_TIME, time);
2466
2467     if (entry) {
2468       gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2469       gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2470
2471       GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2472           " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2473           GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2474
2475       /* Key frame seeking */
2476       if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2477         /* Adjust the segment so that the keyframe fits in */
2478         if (time < segment->start) {
2479           segment->start = segment->time = time;
2480         }
2481         segment->position = time;
2482       }
2483     } else {
2484       GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2485           GST_TIME_ARGS (segment->start));
2486     }
2487   }
2488
2489   return bytes;
2490 }
2491
2492 static gboolean
2493 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2494 {
2495   GstFormat format;
2496   GstSeekFlags flags;
2497   GstSeekType start_type, stop_type;
2498   gint64 start, stop;
2499   gdouble rate;
2500   gboolean update, flush, ret;
2501   GstSegment seeksegment;
2502
2503   gst_event_parse_seek (event, &rate, &format, &flags,
2504       &start_type, &start, &stop_type, &stop);
2505
2506   if (format != GST_FORMAT_TIME)
2507     goto wrong_format;
2508
2509   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2510   /* FIXME : the keyframe flag is never used ! */
2511
2512   /* Work on a copy until we are sure the seek succeeded. */
2513   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2514
2515   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2516       &demux->segment);
2517
2518   /* Apply the seek to our segment */
2519   gst_segment_do_seek (&seeksegment, rate, format, flags,
2520       start_type, start, stop_type, stop, &update);
2521
2522   GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2523       &seeksegment);
2524
2525   if (flush || seeksegment.position != demux->segment.position) {
2526     /* Do the actual seeking */
2527     guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2528
2529     GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2530         G_GUINT64_FORMAT, offset);
2531     ret = gst_pad_push_event (demux->sinkpad,
2532         gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2533             seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2534             offset, GST_SEEK_TYPE_NONE, 0));
2535     if (G_UNLIKELY (!ret)) {
2536       GST_WARNING_OBJECT (demux, "upstream seek failed");
2537     }
2538
2539     /* Tell all the stream we moved to a different position (discont) */
2540     demux->audio_need_discont = TRUE;
2541     demux->video_need_discont = TRUE;
2542   } else {
2543     ret = TRUE;
2544   }
2545
2546   if (ret) {
2547     /* Ok seek succeeded, take the newly configured segment */
2548     memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2549
2550     /* Tell all the stream a new segment is needed */
2551     demux->audio_need_segment = TRUE;
2552     demux->video_need_segment = TRUE;
2553     /* Clean any potential newsegment event kept for the streams. The first
2554      * stream needing a new segment will create a new one. */
2555     if (G_UNLIKELY (demux->new_seg_event)) {
2556       gst_event_unref (demux->new_seg_event);
2557       demux->new_seg_event = NULL;
2558     }
2559     gst_event_unref (event);
2560   } else {
2561     ret = gst_pad_push_event (demux->sinkpad, event);
2562   }
2563
2564   return ret;
2565
2566 /* ERRORS */
2567 wrong_format:
2568   {
2569     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2570     gst_event_unref (event);
2571     return FALSE;
2572   }
2573 }
2574
2575 static gboolean
2576 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2577 {
2578   GstFormat format;
2579
2580   gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2581
2582   if (format != GST_FORMAT_TIME) {
2583     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2584     gst_event_unref (event);
2585     return FALSE;
2586   }
2587
2588   /* First try upstream */
2589   if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2590     GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2591     gst_event_unref (event);
2592     return TRUE;
2593   }
2594
2595   if (!demux->indexed) {
2596     guint64 seek_offset = 0;
2597     gboolean building_index;
2598
2599     GST_OBJECT_LOCK (demux);
2600     /* handle the seek in the chain function */
2601     demux->seeking = TRUE;
2602     demux->state = FLV_STATE_SEEK;
2603
2604     /* copy the event */
2605     if (demux->seek_event)
2606       gst_event_unref (demux->seek_event);
2607     demux->seek_event = gst_event_ref (event);
2608
2609     /* set the building_index flag so that only one thread can setup the
2610      * structures for index seeking. */
2611     building_index = demux->building_index;
2612     if (!building_index) {
2613       demux->building_index = TRUE;
2614       if (!demux->file_size
2615           && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2616               &demux->file_size)) {
2617         GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2618         GST_OBJECT_UNLOCK (demux);
2619         return FALSE;
2620       }
2621
2622       /* we hope the last tag is a scriptdataobject containing an index
2623        * the size of the last tag is given in the last guint32 bits
2624        * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2625       seek_offset = demux->file_size - sizeof (guint32);
2626       GST_DEBUG_OBJECT (demux,
2627           "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2628     }
2629     GST_OBJECT_UNLOCK (demux);
2630
2631     if (!building_index) {
2632       GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2633           seek_offset);
2634       return flv_demux_seek_to_offset (demux, seek_offset);
2635     }
2636
2637     /* FIXME: we have to always return true so that we don't block the seek
2638      * thread.
2639      * Note: maybe it is OK to return true if we're still building the index */
2640     return TRUE;
2641   }
2642
2643   return flv_demux_handle_seek_push (demux, event);
2644 }
2645
2646 static gboolean
2647 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2648     gboolean seeking)
2649 {
2650   GstFormat format;
2651   GstSeekFlags flags;
2652   GstSeekType start_type, stop_type;
2653   gint64 start, stop;
2654   gdouble rate;
2655   gboolean update, flush, ret = FALSE;
2656   GstSegment seeksegment;
2657
2658   gst_event_parse_seek (event, &rate, &format, &flags,
2659       &start_type, &start, &stop_type, &stop);
2660
2661   if (format != GST_FORMAT_TIME)
2662     goto wrong_format;
2663
2664   /* mark seeking thread entering flushing/pausing */
2665   GST_OBJECT_LOCK (demux);
2666   if (seeking)
2667     demux->seeking = seeking;
2668   GST_OBJECT_UNLOCK (demux);
2669
2670   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2671   /* FIXME : the keyframe flag is never used */
2672
2673   if (flush) {
2674     /* Flush start up and downstream to make sure data flow and loops are
2675        idle */
2676     gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2677     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2678   } else {
2679     /* Pause the pulling task */
2680     gst_pad_pause_task (demux->sinkpad);
2681   }
2682
2683   /* Take the stream lock */
2684   GST_PAD_STREAM_LOCK (demux->sinkpad);
2685
2686   if (flush) {
2687     /* Stop flushing upstream we need to pull */
2688     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2689   }
2690
2691   /* Work on a copy until we are sure the seek succeeded. */
2692   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2693
2694   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2695       &demux->segment);
2696
2697   /* Apply the seek to our segment */
2698   gst_segment_do_seek (&seeksegment, rate, format, flags,
2699       start_type, start, stop_type, stop, &update);
2700
2701   GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2702       &seeksegment);
2703
2704   if (flush || seeksegment.position != demux->segment.position) {
2705     /* Do the actual seeking */
2706     /* index is reliable if it is complete or we do not go to far ahead */
2707     if (seeking && !demux->indexed &&
2708         seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2709       GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2710           " index only up to %" GST_TIME_FORMAT,
2711           GST_TIME_ARGS (demux->index_max_time));
2712       /* stop flushing for now */
2713       if (flush)
2714         gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2715       /* delegate scanning and index building to task thread to avoid
2716        * occupying main (UI) loop */
2717       if (demux->seek_event)
2718         gst_event_unref (demux->seek_event);
2719       demux->seek_event = gst_event_ref (event);
2720       demux->seek_time = seeksegment.position;
2721       demux->state = FLV_STATE_SEEK;
2722       /* do not know about succes yet, but we did care and handled it */
2723       ret = TRUE;
2724       goto exit;
2725     }
2726     /* now index should be as reliable as it can be for current purpose */
2727     gst_flv_demux_move_to_offset (demux,
2728         gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2729     ret = TRUE;
2730   } else {
2731     ret = TRUE;
2732   }
2733
2734   if (flush) {
2735     /* Stop flushing, the sinks are at time 0 now */
2736     gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2737   }
2738
2739   if (ret) {
2740     /* Ok seek succeeded, take the newly configured segment */
2741     memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2742
2743     /* Notify about the start of a new segment */
2744     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2745       gst_element_post_message (GST_ELEMENT (demux),
2746           gst_message_new_segment_start (GST_OBJECT (demux),
2747               demux->segment.format, demux->segment.position));
2748     }
2749
2750     /* Tell all the stream a new segment is needed */
2751     demux->audio_need_segment = TRUE;
2752     demux->video_need_segment = TRUE;
2753     /* Clean any potential newsegment event kept for the streams. The first
2754      * stream needing a new segment will create a new one. */
2755     if (G_UNLIKELY (demux->new_seg_event)) {
2756       gst_event_unref (demux->new_seg_event);
2757       demux->new_seg_event = NULL;
2758     }
2759     if (demux->segment.rate < 0.0) {
2760       /* we can't generate a segment by locking on
2761        * to the first timestamp we see */
2762       GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2763           GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2764           GST_TIME_ARGS (demux->segment.start),
2765           GST_TIME_ARGS (demux->segment.stop));
2766       demux->new_seg_event = gst_event_new_segment (&demux->segment);
2767     }
2768   }
2769
2770 exit:
2771   GST_OBJECT_LOCK (demux);
2772   seeking = demux->seeking && !seeking;
2773   demux->seeking = FALSE;
2774   GST_OBJECT_UNLOCK (demux);
2775
2776   /* if we detect an external seek having started (and possibly already having
2777    * flushed), do not restart task to give it a chance.
2778    * Otherwise external one's flushing will take care to pause task */
2779   if (seeking) {
2780     gst_pad_pause_task (demux->sinkpad);
2781   } else {
2782     gst_pad_start_task (demux->sinkpad,
2783         (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
2784   }
2785
2786   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2787
2788   gst_event_unref (event);
2789   return ret;
2790
2791   /* ERRORS */
2792 wrong_format:
2793   {
2794     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2795     gst_event_unref (event);
2796     return ret;
2797   }
2798 }
2799
2800 /* If we can pull that's prefered */
2801 static gboolean
2802 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
2803 {
2804   GstQuery *query;
2805   gboolean pull_mode;
2806
2807   query = gst_query_new_scheduling ();
2808
2809   if (!gst_pad_peer_query (sinkpad, query)) {
2810     gst_query_unref (query);
2811     goto activate_push;
2812   }
2813
2814   pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
2815   gst_query_unref (query);
2816
2817   if (!pull_mode)
2818     goto activate_push;
2819
2820   GST_DEBUG_OBJECT (sinkpad, "activating pull");
2821   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
2822
2823 activate_push:
2824   {
2825     GST_DEBUG_OBJECT (sinkpad, "activating push");
2826     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
2827   }
2828 }
2829
2830 static gboolean
2831 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
2832     GstPadMode mode, gboolean active)
2833 {
2834   gboolean res;
2835   GstFlvDemux *demux;
2836
2837   demux = GST_FLV_DEMUX (parent);
2838
2839   switch (mode) {
2840     case GST_PAD_MODE_PUSH:
2841       demux->random_access = FALSE;
2842       res = TRUE;
2843       break;
2844     case GST_PAD_MODE_PULL:
2845       if (active) {
2846         demux->random_access = TRUE;
2847         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
2848             sinkpad);
2849       } else {
2850         demux->random_access = FALSE;
2851         res = gst_pad_stop_task (sinkpad);
2852       }
2853       break;
2854     default:
2855       res = FALSE;
2856       break;
2857   }
2858   return res;
2859 }
2860
2861 static gboolean
2862 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
2863 {
2864   GstFlvDemux *demux;
2865   gboolean ret = FALSE;
2866
2867   demux = GST_FLV_DEMUX (parent);
2868
2869   GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2870
2871   switch (GST_EVENT_TYPE (event)) {
2872     case GST_EVENT_FLUSH_START:
2873       GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
2874       demux->flushing = TRUE;
2875       ret = gst_flv_demux_push_src_event (demux, event);
2876       break;
2877     case GST_EVENT_FLUSH_STOP:
2878       GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
2879       gst_flv_demux_flush (demux, TRUE);
2880       ret = gst_flv_demux_push_src_event (demux, event);
2881       break;
2882     case GST_EVENT_EOS:
2883       GST_DEBUG_OBJECT (demux, "received EOS");
2884       if (demux->index) {
2885         GST_DEBUG_OBJECT (demux, "committing index");
2886         gst_index_commit (demux->index, demux->index_id);
2887       }
2888       if (!demux->no_more_pads) {
2889         gst_element_no_more_pads (GST_ELEMENT (demux));
2890         demux->no_more_pads = TRUE;
2891       }
2892
2893       if (!gst_flv_demux_push_src_event (demux, event))
2894         GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2895       ret = TRUE;
2896       break;
2897     case GST_EVENT_SEGMENT:
2898     {
2899       GstSegment in_segment;
2900
2901       GST_DEBUG_OBJECT (demux, "received new segment");
2902
2903       gst_event_copy_segment (event, &in_segment);
2904
2905       if (in_segment.format == GST_FORMAT_TIME) {
2906         /* time segment, this is perfect, copy over the values. */
2907         memcpy (&demux->segment, &in_segment, sizeof (in_segment));
2908
2909         GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
2910             &demux->segment);
2911
2912         /* and forward */
2913         ret = gst_flv_demux_push_src_event (demux, event);
2914       } else {
2915         /* non-time format */
2916         demux->audio_need_segment = TRUE;
2917         demux->video_need_segment = TRUE;
2918         ret = TRUE;
2919         gst_event_unref (event);
2920       }
2921       break;
2922     }
2923     default:
2924       ret = gst_flv_demux_push_src_event (demux, event);
2925       break;
2926   }
2927
2928   return ret;
2929 }
2930
2931 static gboolean
2932 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
2933 {
2934   GstFlvDemux *demux;
2935   gboolean ret = FALSE;
2936
2937   demux = GST_FLV_DEMUX (parent);
2938
2939   GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2940
2941   switch (GST_EVENT_TYPE (event)) {
2942     case GST_EVENT_SEEK:
2943       if (demux->random_access) {
2944         ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
2945       } else {
2946         ret = gst_flv_demux_handle_seek_push (demux, event);
2947       }
2948       break;
2949     default:
2950       ret = gst_pad_push_event (demux->sinkpad, event);
2951       break;
2952   }
2953
2954   return ret;
2955 }
2956
2957 static gboolean
2958 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
2959 {
2960   gboolean res = TRUE;
2961   GstFlvDemux *demux;
2962
2963   demux = GST_FLV_DEMUX (parent);
2964
2965   switch (GST_QUERY_TYPE (query)) {
2966     case GST_QUERY_DURATION:
2967     {
2968       GstFormat format;
2969
2970       gst_query_parse_duration (query, &format, NULL);
2971
2972       /* duration is time only */
2973       if (format != GST_FORMAT_TIME) {
2974         GST_DEBUG_OBJECT (demux, "duration query only supported for time "
2975             "format");
2976         res = FALSE;
2977         goto beach;
2978       }
2979
2980       GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
2981           GST_TIME_ARGS (demux->duration));
2982
2983       gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
2984
2985       break;
2986     }
2987     case GST_QUERY_POSITION:
2988     {
2989       GstFormat format;
2990
2991       gst_query_parse_position (query, &format, NULL);
2992
2993       /* position is time only */
2994       if (format != GST_FORMAT_TIME) {
2995         GST_DEBUG_OBJECT (demux, "position query only supported for time "
2996             "format");
2997         res = FALSE;
2998         goto beach;
2999       }
3000
3001       GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3002           GST_TIME_ARGS (demux->segment.position));
3003
3004       gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3005
3006       break;
3007     }
3008
3009     case GST_QUERY_SEEKING:{
3010       GstFormat fmt;
3011
3012       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3013
3014       /* First ask upstream */
3015       if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3016         gboolean seekable;
3017
3018         gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3019         if (seekable) {
3020           res = TRUE;
3021           break;
3022         }
3023       }
3024       res = TRUE;
3025       if (fmt != GST_FORMAT_TIME || !demux->index) {
3026         gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3027       } else if (demux->random_access) {
3028         gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3029             demux->duration);
3030       } else {
3031         GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3032         gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3033
3034         if (seekable)
3035           gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3036         gst_query_unref (peerquery);
3037
3038         if (seekable)
3039           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3040               demux->duration);
3041         else
3042           gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3043       }
3044       break;
3045     }
3046     case GST_QUERY_LATENCY:
3047     default:
3048       res = gst_pad_peer_query (demux->sinkpad, query);
3049       break;
3050   }
3051
3052 beach:
3053
3054   return res;
3055 }
3056
3057 static GstStateChangeReturn
3058 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3059 {
3060   GstFlvDemux *demux;
3061   GstStateChangeReturn ret;
3062
3063   demux = GST_FLV_DEMUX (element);
3064
3065   switch (transition) {
3066     case GST_STATE_CHANGE_READY_TO_PAUSED:
3067       /* If this is our own index destroy it as the
3068        * old entries might be wrong for the new stream */
3069       if (demux->own_index) {
3070         gst_object_unref (demux->index);
3071         demux->index = NULL;
3072         demux->own_index = FALSE;
3073       }
3074
3075       /* If no index was created, generate one */
3076       if (G_UNLIKELY (!demux->index)) {
3077         GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3078
3079         demux->index = gst_index_factory_make ("memindex");
3080
3081         gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3082             &demux->index_id);
3083         demux->own_index = TRUE;
3084       }
3085       gst_flv_demux_cleanup (demux);
3086       break;
3087     default:
3088       break;
3089   }
3090
3091   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3092   if (ret == GST_STATE_CHANGE_FAILURE)
3093     return ret;
3094
3095   switch (transition) {
3096     case GST_STATE_CHANGE_PAUSED_TO_READY:
3097       gst_flv_demux_cleanup (demux);
3098       break;
3099     default:
3100       break;
3101   }
3102
3103   return ret;
3104 }
3105
3106 static void
3107 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3108 {
3109   GstFlvDemux *demux = GST_FLV_DEMUX (element);
3110
3111   GST_OBJECT_LOCK (demux);
3112   if (demux->index)
3113     gst_object_unref (demux->index);
3114   if (index) {
3115     demux->index = gst_object_ref (index);
3116     demux->own_index = FALSE;
3117   } else
3118     demux->index = NULL;
3119
3120   GST_OBJECT_UNLOCK (demux);
3121   /* object lock might be taken again */
3122   if (index)
3123     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3124   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3125
3126 }
3127
3128 static GstIndex *
3129 gst_flv_demux_get_index (GstElement * element)
3130 {
3131   GstIndex *result = NULL;
3132
3133   GstFlvDemux *demux = GST_FLV_DEMUX (element);
3134
3135   GST_OBJECT_LOCK (demux);
3136   if (demux->index)
3137     result = gst_object_ref (demux->index);
3138   GST_OBJECT_UNLOCK (demux);
3139
3140   return result;
3141 }
3142
3143 static void
3144 gst_flv_demux_dispose (GObject * object)
3145 {
3146   GstFlvDemux *demux = GST_FLV_DEMUX (object);
3147
3148   GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3149
3150   if (demux->adapter) {
3151     gst_adapter_clear (demux->adapter);
3152     g_object_unref (demux->adapter);
3153     demux->adapter = NULL;
3154   }
3155
3156   if (demux->taglist) {
3157     gst_tag_list_free (demux->taglist);
3158     demux->taglist = NULL;
3159   }
3160
3161   if (demux->new_seg_event) {
3162     gst_event_unref (demux->new_seg_event);
3163     demux->new_seg_event = NULL;
3164   }
3165
3166   if (demux->audio_codec_data) {
3167     gst_buffer_unref (demux->audio_codec_data);
3168     demux->audio_codec_data = NULL;
3169   }
3170
3171   if (demux->video_codec_data) {
3172     gst_buffer_unref (demux->video_codec_data);
3173     demux->video_codec_data = NULL;
3174   }
3175
3176   if (demux->audio_pad) {
3177     gst_object_unref (demux->audio_pad);
3178     demux->audio_pad = NULL;
3179   }
3180
3181   if (demux->video_pad) {
3182     gst_object_unref (demux->video_pad);
3183     demux->video_pad = NULL;
3184   }
3185
3186   if (demux->index) {
3187     gst_object_unref (demux->index);
3188     demux->index = NULL;
3189   }
3190
3191   if (demux->times) {
3192     g_array_free (demux->times, TRUE);
3193     demux->times = NULL;
3194   }
3195
3196   if (demux->filepositions) {
3197     g_array_free (demux->filepositions, TRUE);
3198     demux->filepositions = NULL;
3199   }
3200
3201   GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3202 }
3203
3204 static void
3205 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3206 {
3207   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3208   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3209
3210   gobject_class->dispose = gst_flv_demux_dispose;
3211
3212   gstelement_class->change_state =
3213       GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3214   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3215   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3216
3217   gst_element_class_add_pad_template (gstelement_class,
3218       gst_static_pad_template_get (&flv_sink_template));
3219   gst_element_class_add_pad_template (gstelement_class,
3220       gst_static_pad_template_get (&audio_src_template));
3221   gst_element_class_add_pad_template (gstelement_class,
3222       gst_static_pad_template_get (&video_src_template));
3223   gst_element_class_set_details_simple (gstelement_class, "FLV Demuxer",
3224       "Codec/Demuxer",
3225       "Demux FLV feeds into digital streams",
3226       "Julien Moutte <julien@moutte.net>");
3227 }
3228
3229 static void
3230 gst_flv_demux_init (GstFlvDemux * demux)
3231 {
3232   demux->sinkpad =
3233       gst_pad_new_from_static_template (&flv_sink_template, "sink");
3234
3235   gst_pad_set_event_function (demux->sinkpad,
3236       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3237   gst_pad_set_chain_function (demux->sinkpad,
3238       GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3239   gst_pad_set_activate_function (demux->sinkpad,
3240       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3241   gst_pad_set_activatemode_function (demux->sinkpad,
3242       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3243
3244   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3245
3246   demux->adapter = gst_adapter_new ();
3247   demux->taglist = gst_tag_list_new_empty ();
3248   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3249
3250   demux->own_index = FALSE;
3251
3252   gst_flv_demux_cleanup (demux);
3253 }
3254
3255 static gboolean
3256 plugin_init (GstPlugin * plugin)
3257 {
3258   GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3259
3260   if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3261           gst_flv_demux_get_type ()) ||
3262       !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3263           gst_flv_mux_get_type ()))
3264     return FALSE;
3265
3266   return TRUE;
3267 }
3268
3269 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3270     "flv", "FLV muxing and demuxing plugin",
3271     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)