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