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