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