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