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