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