flvdemux: Don't use static variables to hold index associations
[platform/upstream/gst-plugins-good.git] / gst / flv / gstflvdemux.c
1 /* GStreamer
2  * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:element-flvdemux
22  *
23  * flvdemux demuxes an FLV file into the different contained streams.
24  *
25  * <refsect2>
26  * <title>Example launch line</title>
27  * |[
28  * gst-launch -v filesrc location=/path/to/flv ! flvdemux ! audioconvert ! autoaudiosink
29  * ]| This pipeline demuxes an FLV file and outputs the contained raw audio streams.
30  * </refsect2>
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "gstflvdemux.h"
38 #include "gstflvmux.h"
39
40 #include <string.h>
41 #include <gst/base/gstbytereader.h>
42 #include <gst/pbutils/descriptions.h>
43 #include <gst/pbutils/pbutils.h>
44 #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, stream-format = (string) raw, 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   GstIndexAssociation associations[2];
114   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   buffer = NULL;
2084   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2085                   demux->tag_size, &buffer)) != GST_FLOW_OK))
2086     goto beach;
2087
2088   switch (demux->state) {
2089     case FLV_STATE_TAG_VIDEO:
2090       ret = gst_flv_demux_parse_tag_video (demux, buffer);
2091       break;
2092     case FLV_STATE_TAG_AUDIO:
2093       ret = gst_flv_demux_parse_tag_audio (demux, buffer);
2094       break;
2095     case FLV_STATE_TAG_SCRIPT:
2096       ret = gst_flv_demux_parse_tag_script (demux, buffer);
2097       break;
2098     default:
2099       GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
2100   }
2101
2102   gst_buffer_unref (buffer);
2103
2104   /* Jump over that part we've just parsed */
2105   demux->offset += demux->tag_size;
2106
2107   /* Make sure we reinitialize the tag size */
2108   demux->tag_size = 0;
2109
2110   /* Ready for the next tag */
2111   demux->state = FLV_STATE_TAG_TYPE;
2112
2113   if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
2114     /* If either audio or video is linked we return GST_FLOW_OK */
2115     if (demux->audio_linked || demux->video_linked) {
2116       ret = GST_FLOW_OK;
2117     } else {
2118       GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
2119           "neither video nor audio are linked");
2120     }
2121   }
2122
2123 beach:
2124   return ret;
2125 }
2126
2127 static GstFlowReturn
2128 gst_flv_demux_pull_header (GstPad * pad, GstFlvDemux * demux)
2129 {
2130   GstBuffer *buffer = NULL;
2131   GstFlowReturn ret = GST_FLOW_OK;
2132
2133   /* Get the first 9 bytes */
2134   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
2135                   FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
2136     goto beach;
2137
2138   ret = gst_flv_demux_parse_header (demux, buffer);
2139
2140   gst_buffer_unref (buffer);
2141
2142   /* Jump over the header now */
2143   demux->offset += FLV_HEADER_SIZE;
2144   demux->state = FLV_STATE_TAG_TYPE;
2145
2146 beach:
2147   return ret;
2148 }
2149
2150 static void
2151 gst_flv_demux_move_to_offset (GstFlvDemux * demux, gint64 offset,
2152     gboolean reset)
2153 {
2154   demux->offset = offset;
2155
2156   /* Tell all the stream we moved to a different position (discont) */
2157   demux->audio_need_discont = TRUE;
2158   demux->video_need_discont = TRUE;
2159
2160   /* next section setup */
2161   demux->from_offset = -1;
2162   demux->audio_done = demux->video_done = FALSE;
2163   demux->audio_first_ts = demux->video_first_ts = GST_CLOCK_TIME_NONE;
2164
2165   if (reset) {
2166     demux->from_offset = -1;
2167     demux->to_offset = G_MAXINT64;
2168   }
2169
2170   /* If we seeked at the beginning of the file parse the header again */
2171   if (G_UNLIKELY (!demux->offset)) {
2172     demux->state = FLV_STATE_HEADER;
2173   } else {                      /* or parse a tag */
2174     demux->state = FLV_STATE_TAG_TYPE;
2175   }
2176 }
2177
2178 static GstFlowReturn
2179 gst_flv_demux_seek_to_prev_keyframe (GstFlvDemux * demux)
2180 {
2181   GstFlowReturn ret = GST_FLOW_EOS;
2182   GstIndexEntry *entry = NULL;
2183
2184   GST_DEBUG_OBJECT (demux,
2185       "terminated section started at offset %" G_GINT64_FORMAT,
2186       demux->from_offset);
2187
2188   /* we are done if we got all audio and video */
2189   if ((!GST_CLOCK_TIME_IS_VALID (demux->audio_first_ts) ||
2190           demux->audio_first_ts < demux->segment.start) &&
2191       (!GST_CLOCK_TIME_IS_VALID (demux->video_first_ts) ||
2192           demux->video_first_ts < demux->segment.start))
2193     goto done;
2194
2195   if (demux->from_offset <= 0)
2196     goto done;
2197
2198   GST_DEBUG_OBJECT (demux, "locating previous position");
2199
2200   /* locate index entry before previous start position */
2201   if (demux->index)
2202     entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2203         GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2204         GST_FORMAT_BYTES, demux->from_offset - 1);
2205
2206   if (entry) {
2207     gint64 bytes = 0, time = 0;
2208
2209     gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2210     gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2211
2212     GST_DEBUG_OBJECT (demux, "found index entry for %" G_GINT64_FORMAT
2213         " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2214         demux->offset - 1, GST_TIME_ARGS (time), bytes);
2215
2216     /* setup for next section */
2217     demux->to_offset = demux->from_offset;
2218     gst_flv_demux_move_to_offset (demux, bytes, FALSE);
2219     ret = GST_FLOW_OK;
2220   }
2221
2222 done:
2223   return ret;
2224 }
2225
2226 static GstFlowReturn
2227 gst_flv_demux_create_index (GstFlvDemux * demux, gint64 pos, GstClockTime ts)
2228 {
2229   gint64 size;
2230   size_t tag_size;
2231   guint64 old_offset;
2232   GstBuffer *buffer;
2233   GstClockTime tag_time;
2234   GstFlowReturn ret = GST_FLOW_OK;
2235
2236   if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &size))
2237     return GST_FLOW_OK;
2238
2239   GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
2240       " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
2241
2242   old_offset = demux->offset;
2243   demux->offset = pos;
2244
2245   buffer = NULL;
2246   while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
2247               12, &buffer)) == GST_FLOW_OK) {
2248     tag_time =
2249         gst_flv_demux_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
2250
2251     gst_buffer_unref (buffer);
2252     buffer = NULL;
2253
2254     if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
2255       goto exit;
2256
2257     demux->offset += tag_size;
2258   }
2259
2260   if (ret == GST_FLOW_EOS) {
2261     /* file ran out, so mark we have complete index */
2262     demux->indexed = TRUE;
2263     ret = GST_FLOW_OK;
2264   }
2265
2266 exit:
2267   demux->offset = old_offset;
2268
2269   return ret;
2270 }
2271
2272 static gint64
2273 gst_flv_demux_get_metadata (GstFlvDemux * demux)
2274 {
2275   gint64 ret = 0, offset;
2276   size_t tag_size, size;
2277   GstBuffer *buffer = NULL;
2278   GstMapInfo map;
2279
2280   if (!gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &offset))
2281     goto exit;
2282
2283   ret = offset;
2284   GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
2285   if (G_UNLIKELY (offset < 4))
2286     goto exit;
2287
2288   offset -= 4;
2289   if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2290           4, &buffer))
2291     goto exit;
2292
2293   gst_buffer_map (buffer, &map, GST_MAP_READ);
2294   tag_size = GST_READ_UINT32_BE (map.data);
2295   gst_buffer_unmap (buffer, &map);
2296   GST_DEBUG_OBJECT (demux, "last tag size: %" G_GSIZE_FORMAT, tag_size);
2297   gst_buffer_unref (buffer);
2298   buffer = NULL;
2299
2300   offset -= tag_size;
2301   if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2302           12, &buffer))
2303     goto exit;
2304
2305   /* a consistency check */
2306   gst_buffer_map (buffer, &map, GST_MAP_READ);
2307   size = GST_READ_UINT24_BE (map.data + 1);
2308   if (size != tag_size - 11) {
2309     gst_buffer_unmap (buffer, &map);
2310     GST_DEBUG_OBJECT (demux,
2311         "tag size %" G_GSIZE_FORMAT ", expected %" G_GSIZE_FORMAT
2312         ", corrupt or truncated file", size, tag_size - 11);
2313     goto exit;
2314   }
2315
2316   /* try to update duration with timestamp in any case */
2317   gst_flv_demux_parse_tag_timestamp (demux, FALSE, buffer, &size);
2318
2319   /* maybe get some more metadata */
2320   if (map.data[0] == 18) {
2321     gst_buffer_unmap (buffer, &map);
2322     gst_buffer_unref (buffer);
2323     buffer = NULL;
2324     GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
2325     offset += 4;
2326     if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
2327             tag_size, &buffer))
2328       gst_flv_demux_parse_tag_script (demux, buffer);
2329   } else {
2330     gst_buffer_unmap (buffer, &map);
2331   }
2332
2333 exit:
2334   if (buffer)
2335     gst_buffer_unref (buffer);
2336
2337   return ret;
2338 }
2339
2340 static void
2341 gst_flv_demux_loop (GstPad * pad)
2342 {
2343   GstFlvDemux *demux = NULL;
2344   GstFlowReturn ret = GST_FLOW_OK;
2345
2346   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
2347
2348   /* pull in data */
2349   switch (demux->state) {
2350     case FLV_STATE_TAG_TYPE:
2351       if (demux->from_offset == -1)
2352         demux->from_offset = demux->offset;
2353       ret = gst_flv_demux_pull_tag (pad, demux);
2354       /* if we have seen real data, we probably passed a possible metadata
2355        * header located at start.  So if we do not yet have an index,
2356        * try to pick up metadata (index, duration) at the end */
2357       if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
2358               (demux->has_video || demux->has_audio)))
2359         demux->file_size = gst_flv_demux_get_metadata (demux);
2360       break;
2361     case FLV_STATE_DONE:
2362       ret = GST_FLOW_EOS;
2363       break;
2364     case FLV_STATE_SEEK:
2365       /* seek issued with insufficient index;
2366        * scan for index in task thread from current maximum offset to
2367        * desired time and then perform seek */
2368       /* TODO maybe some buffering message or so to indicate scan progress */
2369       ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
2370           demux->seek_time);
2371       if (ret != GST_FLOW_OK)
2372         goto pause;
2373       /* position and state arranged by seek,
2374        * also unrefs event */
2375       gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
2376       demux->seek_event = NULL;
2377       break;
2378     default:
2379       ret = gst_flv_demux_pull_header (pad, demux);
2380       /* index scans start after header */
2381       demux->index_max_pos = demux->offset;
2382       break;
2383   }
2384
2385   if (demux->segment.rate < 0.0) {
2386     /* check end of section */
2387     if ((gint64) demux->offset >= demux->to_offset ||
2388         demux->segment.position >= demux->segment.stop + 2 * GST_SECOND ||
2389         (demux->audio_done && demux->video_done))
2390       ret = gst_flv_demux_seek_to_prev_keyframe (demux);
2391   } else {
2392     /* check EOS condition */
2393     if ((demux->segment.stop != -1) &&
2394         (demux->segment.position >= demux->segment.stop)) {
2395       ret = GST_FLOW_EOS;
2396     }
2397   }
2398
2399   /* pause if something went wrong or at end */
2400   if (G_UNLIKELY (ret != GST_FLOW_OK))
2401     goto pause;
2402
2403   gst_object_unref (demux);
2404
2405   return;
2406
2407 pause:
2408   {
2409     const gchar *reason = gst_flow_get_name (ret);
2410
2411     GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
2412     gst_pad_pause_task (pad);
2413
2414     if (ret == GST_FLOW_EOS) {
2415       /* handle end-of-stream/segment */
2416       /* so align our position with the end of it, if there is one
2417        * this ensures a subsequent will arrive at correct base/acc time */
2418       if (demux->segment.rate > 0.0 &&
2419           GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
2420         demux->segment.position = demux->segment.stop;
2421       else if (demux->segment.rate < 0.0)
2422         demux->segment.position = demux->segment.start;
2423
2424       /* perform EOS logic */
2425       if (!demux->no_more_pads) {
2426         gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
2427         demux->no_more_pads = TRUE;
2428       }
2429
2430       if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2431         gint64 stop;
2432
2433         /* for segment playback we need to post when (in stream time)
2434          * we stopped, this is either stop (when set) or the duration. */
2435         if ((stop = demux->segment.stop) == -1)
2436           stop = demux->segment.duration;
2437
2438         if (demux->segment.rate >= 0) {
2439           GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
2440           gst_element_post_message (GST_ELEMENT_CAST (demux),
2441               gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2442                   GST_FORMAT_TIME, stop));
2443         } else {                /* Reverse playback */
2444           GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
2445               "segment");
2446           gst_element_post_message (GST_ELEMENT_CAST (demux),
2447               gst_message_new_segment_done (GST_OBJECT_CAST (demux),
2448                   GST_FORMAT_TIME, demux->segment.start));
2449         }
2450       } else {
2451         /* normal playback, send EOS to all linked pads */
2452         if (!demux->no_more_pads) {
2453           gst_element_no_more_pads (GST_ELEMENT (demux));
2454           demux->no_more_pads = TRUE;
2455         }
2456
2457         GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
2458         if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
2459           GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2460       }
2461     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
2462       GST_ELEMENT_ERROR (demux, STREAM, FAILED,
2463           ("Internal data stream error."),
2464           ("stream stopped, reason %s", reason));
2465       gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
2466     }
2467     gst_object_unref (demux);
2468     return;
2469   }
2470 }
2471
2472 static guint64
2473 gst_flv_demux_find_offset (GstFlvDemux * demux, GstSegment * segment)
2474 {
2475   gint64 bytes = 0;
2476   gint64 time = 0;
2477   GstIndexEntry *entry;
2478
2479   g_return_val_if_fail (segment != NULL, 0);
2480
2481   time = segment->position;
2482
2483   if (demux->index) {
2484     /* Let's check if we have an index entry for that seek time */
2485     entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
2486         GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
2487         GST_FORMAT_TIME, time);
2488
2489     if (entry) {
2490       gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
2491       gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
2492
2493       GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
2494           " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
2495           GST_TIME_ARGS (segment->position), GST_TIME_ARGS (time), bytes);
2496
2497       /* Key frame seeking */
2498       if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
2499         /* Adjust the segment so that the keyframe fits in */
2500         if (time < segment->start) {
2501           segment->start = segment->time = time;
2502         }
2503         segment->position = time;
2504       }
2505     } else {
2506       GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
2507           GST_TIME_ARGS (segment->start));
2508     }
2509   }
2510
2511   return bytes;
2512 }
2513
2514 static gboolean
2515 flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2516 {
2517   GstFormat format;
2518   GstSeekFlags flags;
2519   GstSeekType start_type, stop_type;
2520   gint64 start, stop;
2521   gdouble rate;
2522   gboolean update, flush, ret;
2523   GstSegment seeksegment;
2524
2525   gst_event_parse_seek (event, &rate, &format, &flags,
2526       &start_type, &start, &stop_type, &stop);
2527
2528   if (format != GST_FORMAT_TIME)
2529     goto wrong_format;
2530
2531   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2532   /* FIXME : the keyframe flag is never used ! */
2533
2534   /* Work on a copy until we are sure the seek succeeded. */
2535   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2536
2537   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2538       &demux->segment);
2539
2540   /* Apply the seek to our segment */
2541   gst_segment_do_seek (&seeksegment, rate, format, flags,
2542       start_type, start, stop_type, stop, &update);
2543
2544   GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2545       &seeksegment);
2546
2547   if (flush || seeksegment.position != demux->segment.position) {
2548     /* Do the actual seeking */
2549     guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
2550
2551     GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
2552         G_GUINT64_FORMAT, offset);
2553     ret = gst_pad_push_event (demux->sinkpad,
2554         gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
2555             seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
2556             offset, GST_SEEK_TYPE_NONE, 0));
2557     if (G_UNLIKELY (!ret)) {
2558       GST_WARNING_OBJECT (demux, "upstream seek failed");
2559     }
2560
2561     /* Tell all the stream we moved to a different position (discont) */
2562     demux->audio_need_discont = TRUE;
2563     demux->video_need_discont = TRUE;
2564   } else {
2565     ret = TRUE;
2566   }
2567
2568   if (ret) {
2569     /* Ok seek succeeded, take the newly configured segment */
2570     memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2571
2572     /* Tell all the stream a new segment is needed */
2573     demux->audio_need_segment = TRUE;
2574     demux->video_need_segment = TRUE;
2575     /* Clean any potential newsegment event kept for the streams. The first
2576      * stream needing a new segment will create a new one. */
2577     if (G_UNLIKELY (demux->new_seg_event)) {
2578       gst_event_unref (demux->new_seg_event);
2579       demux->new_seg_event = NULL;
2580     }
2581     gst_event_unref (event);
2582   } else {
2583     ret = gst_pad_push_event (demux->sinkpad, event);
2584   }
2585
2586   return ret;
2587
2588 /* ERRORS */
2589 wrong_format:
2590   {
2591     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2592     gst_event_unref (event);
2593     return FALSE;
2594   }
2595 }
2596
2597 static gboolean
2598 gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
2599 {
2600   GstFormat format;
2601
2602   gst_event_parse_seek (event, NULL, &format, NULL, NULL, NULL, NULL, NULL);
2603
2604   if (format != GST_FORMAT_TIME) {
2605     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2606     gst_event_unref (event);
2607     return FALSE;
2608   }
2609
2610   /* First try upstream */
2611   if (gst_pad_push_event (demux->sinkpad, gst_event_ref (event))) {
2612     GST_DEBUG_OBJECT (demux, "Upstream successfully seeked");
2613     gst_event_unref (event);
2614     return TRUE;
2615   }
2616
2617   if (!demux->indexed) {
2618     guint64 seek_offset = 0;
2619     gboolean building_index;
2620
2621     GST_OBJECT_LOCK (demux);
2622     /* handle the seek in the chain function */
2623     demux->seeking = TRUE;
2624     demux->state = FLV_STATE_SEEK;
2625
2626     /* copy the event */
2627     if (demux->seek_event)
2628       gst_event_unref (demux->seek_event);
2629     demux->seek_event = gst_event_ref (event);
2630
2631     /* set the building_index flag so that only one thread can setup the
2632      * structures for index seeking. */
2633     building_index = demux->building_index;
2634     if (!building_index) {
2635       demux->building_index = TRUE;
2636       if (!demux->file_size
2637           && !gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES,
2638               &demux->file_size)) {
2639         GST_WARNING_OBJECT (demux, "Failed to query upstream file size");
2640         GST_OBJECT_UNLOCK (demux);
2641         return FALSE;
2642       }
2643
2644       /* we hope the last tag is a scriptdataobject containing an index
2645        * the size of the last tag is given in the last guint32 bits
2646        * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
2647       seek_offset = demux->file_size - sizeof (guint32);
2648       GST_DEBUG_OBJECT (demux,
2649           "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
2650     }
2651     GST_OBJECT_UNLOCK (demux);
2652
2653     if (!building_index) {
2654       GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
2655           seek_offset);
2656       return flv_demux_seek_to_offset (demux, seek_offset);
2657     }
2658
2659     /* FIXME: we have to always return true so that we don't block the seek
2660      * thread.
2661      * Note: maybe it is OK to return true if we're still building the index */
2662     return TRUE;
2663   }
2664
2665   return flv_demux_handle_seek_push (demux, event);
2666 }
2667
2668 static gboolean
2669 gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
2670     gboolean seeking)
2671 {
2672   GstFormat format;
2673   GstSeekFlags flags;
2674   GstSeekType start_type, stop_type;
2675   gint64 start, stop;
2676   gdouble rate;
2677   gboolean update, flush, ret = FALSE;
2678   GstSegment seeksegment;
2679
2680   gst_event_parse_seek (event, &rate, &format, &flags,
2681       &start_type, &start, &stop_type, &stop);
2682
2683   if (format != GST_FORMAT_TIME)
2684     goto wrong_format;
2685
2686   /* mark seeking thread entering flushing/pausing */
2687   GST_OBJECT_LOCK (demux);
2688   if (seeking)
2689     demux->seeking = seeking;
2690   GST_OBJECT_UNLOCK (demux);
2691
2692   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
2693   /* FIXME : the keyframe flag is never used */
2694
2695   if (flush) {
2696     /* Flush start up and downstream to make sure data flow and loops are
2697        idle */
2698     gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
2699     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
2700   } else {
2701     /* Pause the pulling task */
2702     gst_pad_pause_task (demux->sinkpad);
2703   }
2704
2705   /* Take the stream lock */
2706   GST_PAD_STREAM_LOCK (demux->sinkpad);
2707
2708   if (flush) {
2709     /* Stop flushing upstream we need to pull */
2710     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
2711   }
2712
2713   /* Work on a copy until we are sure the seek succeeded. */
2714   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
2715
2716   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
2717       &demux->segment);
2718
2719   /* Apply the seek to our segment */
2720   gst_segment_do_seek (&seeksegment, rate, format, flags,
2721       start_type, start, stop_type, stop, &update);
2722
2723   GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
2724       &seeksegment);
2725
2726   if (flush || seeksegment.position != demux->segment.position) {
2727     /* Do the actual seeking */
2728     /* index is reliable if it is complete or we do not go to far ahead */
2729     if (seeking && !demux->indexed &&
2730         seeksegment.position > demux->index_max_time + 10 * GST_SECOND) {
2731       GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
2732           " index only up to %" GST_TIME_FORMAT,
2733           GST_TIME_ARGS (demux->index_max_time));
2734       /* stop flushing for now */
2735       if (flush)
2736         gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2737       /* delegate scanning and index building to task thread to avoid
2738        * occupying main (UI) loop */
2739       if (demux->seek_event)
2740         gst_event_unref (demux->seek_event);
2741       demux->seek_event = gst_event_ref (event);
2742       demux->seek_time = seeksegment.position;
2743       demux->state = FLV_STATE_SEEK;
2744       /* do not know about succes yet, but we did care and handled it */
2745       ret = TRUE;
2746       goto exit;
2747     }
2748     /* now index should be as reliable as it can be for current purpose */
2749     gst_flv_demux_move_to_offset (demux,
2750         gst_flv_demux_find_offset (demux, &seeksegment), TRUE);
2751     ret = TRUE;
2752   } else {
2753     ret = TRUE;
2754   }
2755
2756   if (flush) {
2757     /* Stop flushing, the sinks are at time 0 now */
2758     gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
2759   }
2760
2761   if (ret) {
2762     /* Ok seek succeeded, take the newly configured segment */
2763     memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
2764
2765     /* Notify about the start of a new segment */
2766     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
2767       gst_element_post_message (GST_ELEMENT (demux),
2768           gst_message_new_segment_start (GST_OBJECT (demux),
2769               demux->segment.format, demux->segment.position));
2770     }
2771
2772     /* Tell all the stream a new segment is needed */
2773     demux->audio_need_segment = TRUE;
2774     demux->video_need_segment = TRUE;
2775     /* Clean any potential newsegment event kept for the streams. The first
2776      * stream needing a new segment will create a new one. */
2777     if (G_UNLIKELY (demux->new_seg_event)) {
2778       gst_event_unref (demux->new_seg_event);
2779       demux->new_seg_event = NULL;
2780     }
2781     if (demux->segment.rate < 0.0) {
2782       /* we can't generate a segment by locking on
2783        * to the first timestamp we see */
2784       GST_DEBUG_OBJECT (demux, "preparing newsegment from %"
2785           GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
2786           GST_TIME_ARGS (demux->segment.start),
2787           GST_TIME_ARGS (demux->segment.stop));
2788       demux->new_seg_event = gst_event_new_segment (&demux->segment);
2789     }
2790   }
2791
2792 exit:
2793   GST_OBJECT_LOCK (demux);
2794   seeking = demux->seeking && !seeking;
2795   demux->seeking = FALSE;
2796   GST_OBJECT_UNLOCK (demux);
2797
2798   /* if we detect an external seek having started (and possibly already having
2799    * flushed), do not restart task to give it a chance.
2800    * Otherwise external one's flushing will take care to pause task */
2801   if (seeking) {
2802     gst_pad_pause_task (demux->sinkpad);
2803   } else {
2804     gst_pad_start_task (demux->sinkpad,
2805         (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
2806   }
2807
2808   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
2809
2810   gst_event_unref (event);
2811   return ret;
2812
2813   /* ERRORS */
2814 wrong_format:
2815   {
2816     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
2817     gst_event_unref (event);
2818     return ret;
2819   }
2820 }
2821
2822 /* If we can pull that's prefered */
2823 static gboolean
2824 gst_flv_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
2825 {
2826   GstQuery *query;
2827   gboolean pull_mode;
2828
2829   query = gst_query_new_scheduling ();
2830
2831   if (!gst_pad_peer_query (sinkpad, query)) {
2832     gst_query_unref (query);
2833     goto activate_push;
2834   }
2835
2836   pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
2837   gst_query_unref (query);
2838
2839   if (!pull_mode)
2840     goto activate_push;
2841
2842   GST_DEBUG_OBJECT (sinkpad, "activating pull");
2843   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
2844
2845 activate_push:
2846   {
2847     GST_DEBUG_OBJECT (sinkpad, "activating push");
2848     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
2849   }
2850 }
2851
2852 static gboolean
2853 gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
2854     GstPadMode mode, gboolean active)
2855 {
2856   gboolean res;
2857   GstFlvDemux *demux;
2858
2859   demux = GST_FLV_DEMUX (parent);
2860
2861   switch (mode) {
2862     case GST_PAD_MODE_PUSH:
2863       demux->random_access = FALSE;
2864       res = TRUE;
2865       break;
2866     case GST_PAD_MODE_PULL:
2867       if (active) {
2868         demux->random_access = TRUE;
2869         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
2870             sinkpad);
2871       } else {
2872         demux->random_access = FALSE;
2873         res = gst_pad_stop_task (sinkpad);
2874       }
2875       break;
2876     default:
2877       res = FALSE;
2878       break;
2879   }
2880   return res;
2881 }
2882
2883 static gboolean
2884 gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
2885 {
2886   GstFlvDemux *demux;
2887   gboolean ret = FALSE;
2888
2889   demux = GST_FLV_DEMUX (parent);
2890
2891   GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2892
2893   switch (GST_EVENT_TYPE (event)) {
2894     case GST_EVENT_FLUSH_START:
2895       GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
2896       demux->flushing = TRUE;
2897       ret = gst_flv_demux_push_src_event (demux, event);
2898       break;
2899     case GST_EVENT_FLUSH_STOP:
2900       GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
2901       gst_flv_demux_flush (demux, TRUE);
2902       ret = gst_flv_demux_push_src_event (demux, event);
2903       break;
2904     case GST_EVENT_EOS:
2905       GST_DEBUG_OBJECT (demux, "received EOS");
2906       if (demux->index) {
2907         GST_DEBUG_OBJECT (demux, "committing index");
2908         gst_index_commit (demux->index, demux->index_id);
2909       }
2910       if (!demux->no_more_pads) {
2911         gst_element_no_more_pads (GST_ELEMENT (demux));
2912         demux->no_more_pads = TRUE;
2913       }
2914
2915       if (!gst_flv_demux_push_src_event (demux, event))
2916         GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
2917       ret = TRUE;
2918       break;
2919     case GST_EVENT_SEGMENT:
2920     {
2921       GstSegment in_segment;
2922
2923       GST_DEBUG_OBJECT (demux, "received new segment");
2924
2925       gst_event_copy_segment (event, &in_segment);
2926
2927       if (in_segment.format == GST_FORMAT_TIME) {
2928         /* time segment, this is perfect, copy over the values. */
2929         memcpy (&demux->segment, &in_segment, sizeof (in_segment));
2930
2931         GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
2932             &demux->segment);
2933
2934         /* and forward */
2935         ret = gst_flv_demux_push_src_event (demux, event);
2936       } else {
2937         /* non-time format */
2938         demux->audio_need_segment = TRUE;
2939         demux->video_need_segment = TRUE;
2940         ret = TRUE;
2941         gst_event_unref (event);
2942       }
2943       break;
2944     }
2945     default:
2946       ret = gst_flv_demux_push_src_event (demux, event);
2947       break;
2948   }
2949
2950   return ret;
2951 }
2952
2953 static gboolean
2954 gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
2955 {
2956   GstFlvDemux *demux;
2957   gboolean ret = FALSE;
2958
2959   demux = GST_FLV_DEMUX (parent);
2960
2961   GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
2962
2963   switch (GST_EVENT_TYPE (event)) {
2964     case GST_EVENT_SEEK:
2965       if (demux->random_access) {
2966         ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
2967       } else {
2968         ret = gst_flv_demux_handle_seek_push (demux, event);
2969       }
2970       break;
2971     default:
2972       ret = gst_pad_push_event (demux->sinkpad, event);
2973       break;
2974   }
2975
2976   return ret;
2977 }
2978
2979 static gboolean
2980 gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
2981 {
2982   gboolean res = TRUE;
2983   GstFlvDemux *demux;
2984
2985   demux = GST_FLV_DEMUX (parent);
2986
2987   switch (GST_QUERY_TYPE (query)) {
2988     case GST_QUERY_DURATION:
2989     {
2990       GstFormat format;
2991
2992       gst_query_parse_duration (query, &format, NULL);
2993
2994       /* duration is time only */
2995       if (format != GST_FORMAT_TIME) {
2996         GST_DEBUG_OBJECT (demux, "duration query only supported for time "
2997             "format");
2998         res = FALSE;
2999         goto beach;
3000       }
3001
3002       GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
3003           GST_TIME_ARGS (demux->duration));
3004
3005       gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
3006
3007       break;
3008     }
3009     case GST_QUERY_POSITION:
3010     {
3011       GstFormat format;
3012
3013       gst_query_parse_position (query, &format, NULL);
3014
3015       /* position is time only */
3016       if (format != GST_FORMAT_TIME) {
3017         GST_DEBUG_OBJECT (demux, "position query only supported for time "
3018             "format");
3019         res = FALSE;
3020         goto beach;
3021       }
3022
3023       GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
3024           GST_TIME_ARGS (demux->segment.position));
3025
3026       gst_query_set_position (query, GST_FORMAT_TIME, demux->segment.position);
3027
3028       break;
3029     }
3030
3031     case GST_QUERY_SEEKING:{
3032       GstFormat fmt;
3033
3034       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
3035
3036       /* First ask upstream */
3037       if (fmt == GST_FORMAT_TIME && gst_pad_peer_query (demux->sinkpad, query)) {
3038         gboolean seekable;
3039
3040         gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
3041         if (seekable) {
3042           res = TRUE;
3043           break;
3044         }
3045       }
3046       res = TRUE;
3047       if (fmt != GST_FORMAT_TIME || !demux->index) {
3048         gst_query_set_seeking (query, fmt, FALSE, -1, -1);
3049       } else if (demux->random_access) {
3050         gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
3051             demux->duration);
3052       } else {
3053         GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
3054         gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
3055
3056         if (seekable)
3057           gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
3058         gst_query_unref (peerquery);
3059
3060         if (seekable)
3061           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
3062               demux->duration);
3063         else
3064           gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
3065       }
3066       break;
3067     }
3068     case GST_QUERY_LATENCY:
3069     default:
3070       res = gst_pad_query_default (pad, parent, query);
3071       break;
3072   }
3073
3074 beach:
3075
3076   return res;
3077 }
3078
3079 static GstStateChangeReturn
3080 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
3081 {
3082   GstFlvDemux *demux;
3083   GstStateChangeReturn ret;
3084
3085   demux = GST_FLV_DEMUX (element);
3086
3087   switch (transition) {
3088     case GST_STATE_CHANGE_READY_TO_PAUSED:
3089       /* If this is our own index destroy it as the
3090        * old entries might be wrong for the new stream */
3091       if (demux->own_index) {
3092         gst_object_unref (demux->index);
3093         demux->index = NULL;
3094         demux->own_index = FALSE;
3095       }
3096
3097       /* If no index was created, generate one */
3098       if (G_UNLIKELY (!demux->index)) {
3099         GST_DEBUG_OBJECT (demux, "no index provided creating our own");
3100
3101         demux->index = g_object_new (gst_mem_index_get_type (), NULL);
3102
3103         gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
3104             &demux->index_id);
3105         demux->own_index = TRUE;
3106       }
3107       gst_flv_demux_cleanup (demux);
3108       break;
3109     default:
3110       break;
3111   }
3112
3113   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3114   if (ret == GST_STATE_CHANGE_FAILURE)
3115     return ret;
3116
3117   switch (transition) {
3118     case GST_STATE_CHANGE_PAUSED_TO_READY:
3119       gst_flv_demux_cleanup (demux);
3120       break;
3121     default:
3122       break;
3123   }
3124
3125   return ret;
3126 }
3127
3128 #if 0
3129 static void
3130 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
3131 {
3132   GstFlvDemux *demux = GST_FLV_DEMUX (element);
3133
3134   GST_OBJECT_LOCK (demux);
3135   if (demux->index)
3136     gst_object_unref (demux->index);
3137   if (index) {
3138     demux->index = gst_object_ref (index);
3139     demux->own_index = FALSE;
3140   } else
3141     demux->index = NULL;
3142
3143   GST_OBJECT_UNLOCK (demux);
3144   /* object lock might be taken again */
3145   if (index)
3146     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
3147   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT, demux->index);
3148
3149 }
3150
3151 static GstIndex *
3152 gst_flv_demux_get_index (GstElement * element)
3153 {
3154   GstIndex *result = NULL;
3155
3156   GstFlvDemux *demux = GST_FLV_DEMUX (element);
3157
3158   GST_OBJECT_LOCK (demux);
3159   if (demux->index)
3160     result = gst_object_ref (demux->index);
3161   GST_OBJECT_UNLOCK (demux);
3162
3163   return result;
3164 }
3165 #endif
3166
3167 static void
3168 gst_flv_demux_dispose (GObject * object)
3169 {
3170   GstFlvDemux *demux = GST_FLV_DEMUX (object);
3171
3172   GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
3173
3174   if (demux->adapter) {
3175     gst_adapter_clear (demux->adapter);
3176     g_object_unref (demux->adapter);
3177     demux->adapter = NULL;
3178   }
3179
3180   if (demux->taglist) {
3181     gst_tag_list_free (demux->taglist);
3182     demux->taglist = NULL;
3183   }
3184
3185   if (demux->new_seg_event) {
3186     gst_event_unref (demux->new_seg_event);
3187     demux->new_seg_event = NULL;
3188   }
3189
3190   if (demux->audio_codec_data) {
3191     gst_buffer_unref (demux->audio_codec_data);
3192     demux->audio_codec_data = NULL;
3193   }
3194
3195   if (demux->video_codec_data) {
3196     gst_buffer_unref (demux->video_codec_data);
3197     demux->video_codec_data = NULL;
3198   }
3199
3200   if (demux->audio_pad) {
3201     gst_object_unref (demux->audio_pad);
3202     demux->audio_pad = NULL;
3203   }
3204
3205   if (demux->video_pad) {
3206     gst_object_unref (demux->video_pad);
3207     demux->video_pad = NULL;
3208   }
3209
3210   if (demux->index) {
3211     gst_object_unref (demux->index);
3212     demux->index = NULL;
3213   }
3214
3215   if (demux->times) {
3216     g_array_free (demux->times, TRUE);
3217     demux->times = NULL;
3218   }
3219
3220   if (demux->filepositions) {
3221     g_array_free (demux->filepositions, TRUE);
3222     demux->filepositions = NULL;
3223   }
3224
3225   GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
3226 }
3227
3228 static void
3229 gst_flv_demux_class_init (GstFlvDemuxClass * klass)
3230 {
3231   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
3232   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
3233
3234   gobject_class->dispose = gst_flv_demux_dispose;
3235
3236   gstelement_class->change_state =
3237       GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
3238
3239 #if 0
3240   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
3241   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
3242 #endif
3243
3244   gst_element_class_add_pad_template (gstelement_class,
3245       gst_static_pad_template_get (&flv_sink_template));
3246   gst_element_class_add_pad_template (gstelement_class,
3247       gst_static_pad_template_get (&audio_src_template));
3248   gst_element_class_add_pad_template (gstelement_class,
3249       gst_static_pad_template_get (&video_src_template));
3250   gst_element_class_set_details_simple (gstelement_class, "FLV Demuxer",
3251       "Codec/Demuxer",
3252       "Demux FLV feeds into digital streams",
3253       "Julien Moutte <julien@moutte.net>");
3254 }
3255
3256 static void
3257 gst_flv_demux_init (GstFlvDemux * demux)
3258 {
3259   demux->sinkpad =
3260       gst_pad_new_from_static_template (&flv_sink_template, "sink");
3261
3262   gst_pad_set_event_function (demux->sinkpad,
3263       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
3264   gst_pad_set_chain_function (demux->sinkpad,
3265       GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
3266   gst_pad_set_activate_function (demux->sinkpad,
3267       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
3268   gst_pad_set_activatemode_function (demux->sinkpad,
3269       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_mode));
3270
3271   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
3272
3273   demux->adapter = gst_adapter_new ();
3274   demux->taglist = gst_tag_list_new_empty ();
3275   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
3276
3277   demux->own_index = FALSE;
3278
3279   GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE);
3280
3281   gst_flv_demux_cleanup (demux);
3282 }
3283
3284 static gboolean
3285 plugin_init (GstPlugin * plugin)
3286 {
3287   GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
3288
3289   if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
3290           gst_flv_demux_get_type ()) ||
3291       !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
3292           gst_flv_mux_get_type ()))
3293     return FALSE;
3294
3295   return TRUE;
3296 }
3297
3298 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
3299     flv, "FLV muxing and demuxing plugin",
3300     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)