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