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