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