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