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