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