flvdemux: Fix unitialized variables
[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 "gstflvparse.h"
39 #include "gstflvmux.h"
40
41 #include <string.h>
42 #include <gst/base/gstbytereader.h>
43
44 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
45     GST_PAD_SINK,
46     GST_PAD_ALWAYS,
47     GST_STATIC_CAPS ("video/x-flv")
48     );
49
50 static GstStaticPadTemplate audio_src_template =
51 GST_STATIC_PAD_TEMPLATE ("audio",
52     GST_PAD_SRC,
53     GST_PAD_SOMETIMES,
54     GST_STATIC_CAPS_ANY);
55
56 static GstStaticPadTemplate video_src_template =
57 GST_STATIC_PAD_TEMPLATE ("video",
58     GST_PAD_SRC,
59     GST_PAD_SOMETIMES,
60     GST_STATIC_CAPS_ANY);
61
62 GST_DEBUG_CATEGORY (flvdemux_debug);
63 #define GST_CAT_DEFAULT flvdemux_debug
64
65 GST_BOILERPLATE (GstFLVDemux, gst_flv_demux, GstElement, GST_TYPE_ELEMENT);
66
67 /* 9 bytes of header + 4 bytes of first previous tag size */
68 #define FLV_HEADER_SIZE 13
69 /* 1 byte of tag type + 3 bytes of tag data size */
70 #define FLV_TAG_TYPE_SIZE 4
71
72 static gboolean flv_demux_handle_seek_push (GstFLVDemux * demux,
73     GstEvent * event);
74 static gboolean gst_flv_demux_handle_seek_pull (GstFLVDemux * demux,
75     GstEvent * event, gboolean seeking);
76
77 static void
78 gst_flv_demux_flush (GstFLVDemux * demux, gboolean discont)
79 {
80   GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
81
82   gst_adapter_clear (demux->adapter);
83
84   demux->audio_need_discont = TRUE;
85   demux->video_need_discont = TRUE;
86
87   demux->flushing = FALSE;
88
89   /* Only in push mode and if we're not during a seek */
90   if (!demux->random_access && demux->state != FLV_STATE_SEEK) {
91     /* After a flush we expect a tag_type */
92     demux->state = FLV_STATE_TAG_TYPE;
93     /* We reset the offset and will get one from first push */
94     demux->offset = 0;
95   }
96 }
97
98 static void
99 gst_flv_demux_cleanup (GstFLVDemux * demux)
100 {
101   GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
102
103   demux->state = FLV_STATE_HEADER;
104
105   demux->flushing = FALSE;
106   demux->need_header = TRUE;
107   demux->audio_need_segment = TRUE;
108   demux->video_need_segment = TRUE;
109   demux->audio_need_discont = TRUE;
110   demux->video_need_discont = TRUE;
111
112   /* By default we consider them as linked */
113   demux->audio_linked = TRUE;
114   demux->video_linked = TRUE;
115
116   demux->has_audio = FALSE;
117   demux->has_video = FALSE;
118   demux->push_tags = FALSE;
119   demux->got_par = FALSE;
120
121   demux->indexed = FALSE;
122   demux->file_size = 0;
123
124   demux->index_max_pos = 0;
125   demux->index_max_time = 0;
126
127   demux->audio_start = demux->video_start = GST_CLOCK_TIME_NONE;
128
129   demux->no_more_pads = FALSE;
130
131   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
132
133   demux->w = demux->h = 0;
134   demux->par_x = demux->par_y = 1;
135   demux->video_offset = 0;
136   demux->audio_offset = 0;
137   demux->offset = demux->cur_tag_offset = 0;
138   demux->tag_size = demux->tag_data_size = 0;
139   demux->duration = GST_CLOCK_TIME_NONE;
140
141   if (demux->new_seg_event) {
142     gst_event_unref (demux->new_seg_event);
143     demux->new_seg_event = NULL;
144   }
145
146   if (demux->close_seg_event) {
147     gst_event_unref (demux->close_seg_event);
148     demux->close_seg_event = NULL;
149   }
150
151   gst_adapter_clear (demux->adapter);
152
153   if (demux->audio_codec_data) {
154     gst_buffer_unref (demux->audio_codec_data);
155     demux->audio_codec_data = NULL;
156   }
157
158   if (demux->video_codec_data) {
159     gst_buffer_unref (demux->video_codec_data);
160     demux->video_codec_data = NULL;
161   }
162
163   if (demux->audio_pad) {
164     gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
165     gst_object_unref (demux->audio_pad);
166     demux->audio_pad = NULL;
167   }
168
169   if (demux->video_pad) {
170     gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
171     gst_object_unref (demux->video_pad);
172     demux->video_pad = NULL;
173   }
174
175   if (demux->times) {
176     g_array_free (demux->times, TRUE);
177     demux->times = NULL;
178   }
179
180   if (demux->filepositions) {
181     g_array_free (demux->filepositions, TRUE);
182     demux->filepositions = NULL;
183   }
184 }
185
186 /*
187  * Create and push a flushing seek event upstream
188  */
189 static gboolean
190 flv_demux_seek_to_offset (GstFLVDemux * demux, guint64 offset)
191 {
192   GstEvent *event;
193   gboolean res = 0;
194
195   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
196
197   event =
198       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
199       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
200       GST_SEEK_TYPE_NONE, -1);
201
202   res = gst_pad_push_event (demux->sinkpad, event);
203
204   if (res)
205     demux->offset = offset;
206   return res;
207 }
208
209 static GstFlowReturn
210 gst_flv_demux_chain (GstPad * pad, GstBuffer * buffer)
211 {
212   GstFlowReturn ret = GST_FLOW_OK;
213   GstFLVDemux *demux = NULL;
214
215   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
216
217   GST_LOG_OBJECT (demux, "received buffer of %d bytes at offset %"
218       G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer));
219
220   if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
221     GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
222     demux->state = FLV_STATE_HEADER;
223     demux->offset = 0;
224   }
225
226   if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
227     GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
228     demux->offset = GST_BUFFER_OFFSET (buffer);
229   }
230
231   gst_adapter_push (demux->adapter, buffer);
232
233   if (demux->seeking) {
234     demux->state = FLV_STATE_SEEK;
235     GST_OBJECT_LOCK (demux);
236     demux->seeking = FALSE;
237     GST_OBJECT_UNLOCK (demux);
238   }
239
240 parse:
241   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
242     if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
243             || demux->video_linked)) {
244       ret = GST_FLOW_OK;
245     } else {
246       GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
247       goto beach;
248     }
249   }
250
251   if (G_UNLIKELY (demux->flushing)) {
252     GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
253     ret = GST_FLOW_WRONG_STATE;
254     goto beach;
255   }
256
257   switch (demux->state) {
258     case FLV_STATE_HEADER:
259     {
260       if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
261         GstBuffer *buffer;
262
263         buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
264
265         ret = gst_flv_parse_header (demux, buffer);
266
267         gst_buffer_unref (buffer);
268         demux->offset += FLV_HEADER_SIZE;
269
270         demux->state = FLV_STATE_TAG_TYPE;
271         goto parse;
272       } else {
273         goto beach;
274       }
275     }
276     case FLV_STATE_TAG_TYPE:
277     {
278       if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
279         GstBuffer *buffer;
280
281         /* Remember the tag offset in bytes */
282         demux->cur_tag_offset = demux->offset;
283
284         buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
285
286         ret = gst_flv_parse_tag_type (demux, buffer);
287
288         gst_buffer_unref (buffer);
289         demux->offset += FLV_TAG_TYPE_SIZE;
290
291         /* last tag is not an index => no index/don't know where the index is
292          * seek back to the beginning */
293         if (demux->seek_event && demux->state != FLV_STATE_TAG_SCRIPT)
294           goto no_index;
295
296         goto parse;
297       } else {
298         goto beach;
299       }
300     }
301     case FLV_STATE_TAG_VIDEO:
302     {
303       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
304         GstBuffer *buffer;
305
306         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
307
308         ret = gst_flv_parse_tag_video (demux, buffer);
309
310         gst_buffer_unref (buffer);
311         demux->offset += demux->tag_size;
312
313         demux->state = FLV_STATE_TAG_TYPE;
314         goto parse;
315       } else {
316         goto beach;
317       }
318     }
319     case FLV_STATE_TAG_AUDIO:
320     {
321       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
322         GstBuffer *buffer;
323
324         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
325
326         ret = gst_flv_parse_tag_audio (demux, buffer);
327
328         gst_buffer_unref (buffer);
329         demux->offset += demux->tag_size;
330
331         demux->state = FLV_STATE_TAG_TYPE;
332         goto parse;
333       } else {
334         goto beach;
335       }
336     }
337     case FLV_STATE_TAG_SCRIPT:
338     {
339       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
340         GstBuffer *buffer;
341
342         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
343
344         ret = gst_flv_parse_tag_script (demux, buffer);
345
346         gst_buffer_unref (buffer);
347         demux->offset += demux->tag_size;
348
349         demux->state = FLV_STATE_TAG_TYPE;
350
351         /* if there's a seek event we're here for the index so if we don't have it
352          * we seek back to the beginning */
353         if (demux->seek_event) {
354           if (demux->indexed)
355             demux->state = FLV_STATE_SEEK;
356           else
357             goto no_index;
358         }
359
360         goto parse;
361       } else {
362         goto beach;
363       }
364     }
365     case FLV_STATE_SEEK:
366     {
367       GstEvent *event;
368
369       ret = GST_FLOW_OK;
370
371       if (!demux->indexed) {
372         if (demux->offset == demux->file_size - sizeof (guint32)) {
373           GstBuffer *buffer =
374               gst_adapter_take_buffer (demux->adapter, sizeof (guint32));
375           GstByteReader *reader = gst_byte_reader_new_from_buffer (buffer);
376           guint64 seek_offset;
377
378           if (!gst_adapter_available (demux->adapter) >= sizeof (guint32)) {
379             /* error */
380           }
381
382           seek_offset =
383               demux->file_size - sizeof (guint32) -
384               gst_byte_reader_peek_uint32_be_unchecked (reader);
385           gst_byte_reader_free (reader);
386           gst_buffer_unref (buffer);
387
388           GST_INFO_OBJECT (demux,
389               "Seeking to beginning of last tag at %" G_GUINT64_FORMAT,
390               seek_offset);
391           demux->state = FLV_STATE_TAG_TYPE;
392           flv_demux_seek_to_offset (demux, seek_offset);
393           goto beach;
394         } else
395           goto no_index;
396       }
397
398       GST_OBJECT_LOCK (demux);
399       event = demux->seek_event;
400       demux->seek_event = NULL;
401       GST_OBJECT_UNLOCK (demux);
402
403       /* calculate and perform seek */
404       if (!flv_demux_handle_seek_push (demux, event))
405         goto seek_failed;
406
407       gst_event_unref (event);
408       demux->state = FLV_STATE_TAG_TYPE;
409       goto beach;
410     }
411     default:
412       GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
413   }
414
415 beach:
416   if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
417     /* If either audio or video is linked we return GST_FLOW_OK */
418     if (demux->audio_linked || demux->video_linked) {
419       ret = GST_FLOW_OK;
420     }
421   }
422
423   gst_object_unref (demux);
424
425   return ret;
426
427 /* ERRORS */
428 no_index:
429   {
430     GST_OBJECT_LOCK (demux);
431     demux->seeking = FALSE;
432     gst_event_unref (demux->seek_event);
433     demux->seek_event = NULL;
434     GST_OBJECT_UNLOCK (demux);
435     GST_WARNING_OBJECT (demux,
436         "failed to find an index, seeking back to beginning");
437     flv_demux_seek_to_offset (demux, 0);
438     return GST_FLOW_OK;
439   }
440 seek_failed:
441   {
442     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("seek failed"));
443     return GST_FLOW_ERROR;
444   }
445
446 }
447
448 static GstFlowReturn
449 gst_flv_demux_pull_range (GstFLVDemux * demux, GstPad * pad, guint64 offset,
450     guint size, GstBuffer ** buffer)
451 {
452   GstFlowReturn ret;
453
454   ret = gst_pad_pull_range (pad, offset, size, buffer);
455   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
456     GST_WARNING_OBJECT (demux,
457         "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
458         size, offset, gst_flow_get_name (ret));
459     *buffer = NULL;
460     return ret;
461   }
462
463   if (G_UNLIKELY (*buffer && GST_BUFFER_SIZE (*buffer) != size)) {
464     GST_WARNING_OBJECT (demux,
465         "partial pull got %d when expecting %d from offset %" G_GUINT64_FORMAT,
466         GST_BUFFER_SIZE (*buffer), size, offset);
467     gst_buffer_unref (*buffer);
468     ret = GST_FLOW_UNEXPECTED;
469     *buffer = NULL;
470     return ret;
471   }
472
473   return ret;
474 }
475
476 static GstFlowReturn
477 gst_flv_demux_pull_tag (GstPad * pad, GstFLVDemux * demux)
478 {
479   GstBuffer *buffer = NULL;
480   GstFlowReturn ret = GST_FLOW_OK;
481
482   /* Store tag offset */
483   demux->cur_tag_offset = demux->offset;
484
485   /* Get the first 4 bytes to identify tag type and size */
486   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
487                   FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
488     goto beach;
489
490   /* Identify tag type */
491   ret = gst_flv_parse_tag_type (demux, buffer);
492
493   gst_buffer_unref (buffer);
494
495   if (G_UNLIKELY (ret != GST_FLOW_OK))
496     goto beach;
497
498   /* Jump over tag type + size */
499   demux->offset += FLV_TAG_TYPE_SIZE;
500
501   /* Pull the whole tag */
502   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
503                   demux->tag_size, &buffer)) != GST_FLOW_OK))
504     goto beach;
505
506   switch (demux->state) {
507     case FLV_STATE_TAG_VIDEO:
508       ret = gst_flv_parse_tag_video (demux, buffer);
509       break;
510     case FLV_STATE_TAG_AUDIO:
511       ret = gst_flv_parse_tag_audio (demux, buffer);
512       break;
513     case FLV_STATE_TAG_SCRIPT:
514       ret = gst_flv_parse_tag_script (demux, buffer);
515       break;
516     default:
517       GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
518   }
519
520   gst_buffer_unref (buffer);
521
522   /* Jump over that part we've just parsed */
523   demux->offset += demux->tag_size;
524
525   /* Make sure we reinitialize the tag size */
526   demux->tag_size = 0;
527
528   /* Ready for the next tag */
529   demux->state = FLV_STATE_TAG_TYPE;
530
531   if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
532     /* If either audio or video is linked we return GST_FLOW_OK */
533     if (demux->audio_linked || demux->video_linked) {
534       ret = GST_FLOW_OK;
535     } else {
536       GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
537           "neither video nor audio are linked");
538     }
539   }
540
541 beach:
542   return ret;
543 }
544
545 static GstFlowReturn
546 gst_flv_demux_pull_header (GstPad * pad, GstFLVDemux * demux)
547 {
548   GstBuffer *buffer = NULL;
549   GstFlowReturn ret = GST_FLOW_OK;
550
551   /* Get the first 9 bytes */
552   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
553                   FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
554     goto beach;
555
556   ret = gst_flv_parse_header (demux, buffer);
557
558   gst_buffer_unref (buffer);
559
560   /* Jump over the header now */
561   demux->offset += FLV_HEADER_SIZE;
562   demux->state = FLV_STATE_TAG_TYPE;
563
564 beach:
565   return ret;
566 }
567
568 static GstFlowReturn
569 gst_flv_demux_seek_to_prev_keyframe (GstFLVDemux * demux)
570 {
571   return GST_FLOW_OK;
572 }
573
574 static gboolean
575 gst_flv_demux_push_src_event (GstFLVDemux * demux, GstEvent * event)
576 {
577   gboolean ret = TRUE;
578
579   if (demux->audio_pad)
580     ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
581
582   if (demux->video_pad)
583     ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
584
585   gst_event_unref (event);
586
587   return ret;
588 }
589
590 static GstFlowReturn
591 gst_flv_demux_create_index (GstFLVDemux * demux, gint64 pos, GstClockTime ts)
592 {
593   gint64 size;
594   GstFormat fmt = GST_FORMAT_BYTES;
595   size_t tag_size;
596   guint64 old_offset;
597   GstBuffer *buffer;
598   GstClockTime tag_time;
599   GstFlowReturn ret = GST_FLOW_OK;
600
601   if (G_UNLIKELY (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &size) ||
602           fmt != GST_FORMAT_BYTES))
603     return GST_FLOW_OK;
604
605   GST_DEBUG_OBJECT (demux, "building index at %" G_GINT64_FORMAT
606       " looking for time %" GST_TIME_FORMAT, pos, GST_TIME_ARGS (ts));
607
608   old_offset = demux->offset;
609   demux->offset = pos;
610
611   while ((ret = gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset,
612               12, &buffer)) == GST_FLOW_OK) {
613     tag_time = gst_flv_parse_tag_timestamp (demux, TRUE, buffer, &tag_size);
614
615     gst_buffer_unref (buffer);
616
617     if (G_UNLIKELY (tag_time == GST_CLOCK_TIME_NONE || tag_time > ts))
618       goto exit;
619
620     demux->offset += tag_size;
621   }
622
623   if (ret == GST_FLOW_UNEXPECTED) {
624     /* file ran out, so mark we have complete index */
625     demux->indexed = TRUE;
626     ret = GST_FLOW_OK;
627   }
628
629 exit:
630   demux->offset = old_offset;
631
632   return ret;
633 }
634
635 static gint64
636 gst_flv_demux_get_metadata (GstFLVDemux * demux)
637 {
638   gint64 ret = 0, offset;
639   GstFormat fmt = GST_FORMAT_BYTES;
640   size_t tag_size, size;
641   GstBuffer *buffer = NULL;
642
643   if (G_UNLIKELY (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &offset)
644           || fmt != GST_FORMAT_BYTES))
645     goto exit;
646
647   ret = offset;
648   GST_DEBUG_OBJECT (demux, "upstream size: %" G_GINT64_FORMAT, offset);
649   if (G_UNLIKELY (offset < 4))
650     goto exit;
651
652   offset -= 4;
653   if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
654           4, &buffer))
655     goto exit;
656
657   tag_size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buffer));
658   GST_DEBUG_OBJECT (demux, "last tag size: %d", tag_size);
659   gst_buffer_unref (buffer);
660   buffer = NULL;
661
662   offset -= tag_size;
663   if (GST_FLOW_OK != gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
664           12, &buffer))
665     goto exit;
666
667   /* a consistency check */
668   size = GST_READ_UINT24_BE (GST_BUFFER_DATA (buffer) + 1);
669   if (size != tag_size - 11) {
670     GST_DEBUG_OBJECT (demux, "tag size %d, expected %d, ",
671         "corrupt or truncated file", size, tag_size - 11);
672     goto exit;
673   }
674
675   /* try to update duration with timestamp in any case */
676   gst_flv_parse_tag_timestamp (demux, FALSE, buffer, &size);
677
678   /* maybe get some more metadata */
679   if (GST_BUFFER_DATA (buffer)[0] == 18) {
680     gst_buffer_unref (buffer);
681     buffer = NULL;
682     GST_DEBUG_OBJECT (demux, "script tag, pulling it to parse");
683     offset += 4;
684     if (GST_FLOW_OK == gst_flv_demux_pull_range (demux, demux->sinkpad, offset,
685             tag_size, &buffer))
686       gst_flv_parse_tag_script (demux, buffer);
687   }
688
689 exit:
690   if (buffer)
691     gst_buffer_unref (buffer);
692
693   return ret;
694 }
695
696 static void
697 gst_flv_demux_loop (GstPad * pad)
698 {
699   GstFLVDemux *demux = NULL;
700   GstFlowReturn ret = GST_FLOW_OK;
701
702   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
703
704   if (demux->segment.rate >= 0) {
705     /* pull in data */
706     switch (demux->state) {
707       case FLV_STATE_TAG_TYPE:
708         ret = gst_flv_demux_pull_tag (pad, demux);
709         /* if we have seen real data, we probably passed a possible metadata
710          * header located at start.  So if we do not yet have an index,
711          * try to pick up metadata (index, duration) at the end */
712         if (G_UNLIKELY (!demux->file_size && !demux->indexed &&
713                 (demux->has_video || demux->has_audio)))
714           demux->file_size = gst_flv_demux_get_metadata (demux);
715         break;
716       case FLV_STATE_DONE:
717         ret = GST_FLOW_UNEXPECTED;
718         break;
719       case FLV_STATE_SEEK:
720         /* seek issued with insufficient index;
721          * scan for index in task thread from current maximum offset to
722          * desired time and then perform seek */
723         /* TODO maybe some buffering message or so to indicate scan progress */
724         ret = gst_flv_demux_create_index (demux, demux->index_max_pos,
725             demux->seek_time);
726         if (ret != GST_FLOW_OK)
727           goto pause;
728         /* position and state arranged by seek,
729          * also unrefs event */
730         gst_flv_demux_handle_seek_pull (demux, demux->seek_event, FALSE);
731         demux->seek_event = NULL;
732         break;
733       default:
734         ret = gst_flv_demux_pull_header (pad, demux);
735         /* index scans start after header */
736         demux->index_max_pos = demux->offset;
737         break;
738     }
739
740     /* pause if something went wrong */
741     if (G_UNLIKELY (ret != GST_FLOW_OK))
742       goto pause;
743
744     /* check EOS condition */
745     if ((demux->segment.flags & GST_SEEK_FLAG_SEGMENT) &&
746         (demux->segment.stop != -1) &&
747         (demux->segment.last_stop >= demux->segment.stop)) {
748       ret = GST_FLOW_UNEXPECTED;
749       goto pause;
750     }
751   } else {                      /* Reverse playback */
752     /* pull in data */
753     switch (demux->state) {
754       case FLV_STATE_TAG_TYPE:
755         ret = gst_flv_demux_pull_tag (pad, demux);
756         /* When packet parsing returns UNEXPECTED that means we ve reached the
757            point where we want to go to the previous keyframe. This is either
758            the last FLV tag or the keyframe we used last time */
759         if (ret == GST_FLOW_UNEXPECTED) {
760           ret = gst_flv_demux_seek_to_prev_keyframe (demux);
761           demux->state = FLV_STATE_TAG_TYPE;
762         }
763         break;
764       default:
765         ret = gst_flv_demux_pull_header (pad, demux);
766         if (ret == GST_FLOW_OK)
767           gst_flv_demux_create_index (demux, demux->offset, G_MAXINT64);
768     }
769
770     /* pause if something went wrong */
771     if (G_UNLIKELY (ret != GST_FLOW_OK))
772       goto pause;
773
774     /* check EOS condition */
775     if (demux->segment.last_stop <= demux->segment.start) {
776       ret = GST_FLOW_UNEXPECTED;
777       goto pause;
778     }
779   }
780
781   gst_object_unref (demux);
782
783   return;
784
785 pause:
786   {
787     const gchar *reason = gst_flow_get_name (ret);
788
789     GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
790     gst_pad_pause_task (pad);
791
792     if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
793       if (ret == GST_FLOW_UNEXPECTED) {
794         /* perform EOS logic */
795         if (!demux->no_more_pads) {
796           gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
797           demux->no_more_pads = TRUE;
798         }
799
800         if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
801           gint64 stop;
802
803           /* for segment playback we need to post when (in stream time)
804            * we stopped, this is either stop (when set) or the duration. */
805           if ((stop = demux->segment.stop) == -1)
806             stop = demux->segment.duration;
807
808           if (demux->segment.rate >= 0) {
809             GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
810             gst_element_post_message (GST_ELEMENT_CAST (demux),
811                 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
812                     GST_FORMAT_TIME, stop));
813           } else {              /* Reverse playback */
814             GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
815                 "segment");
816             gst_element_post_message (GST_ELEMENT_CAST (demux),
817                 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
818                     GST_FORMAT_TIME, demux->segment.start));
819           }
820         } else {
821           /* normal playback, send EOS to all linked pads */
822           if (!demux->no_more_pads) {
823             gst_element_no_more_pads (GST_ELEMENT (demux));
824             demux->no_more_pads = TRUE;
825           }
826
827           GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
828           if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
829             GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
830         }
831       } else {
832         GST_ELEMENT_ERROR (demux, STREAM, FAILED,
833             ("Internal data stream error."),
834             ("stream stopped, reason %s", reason));
835         gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
836       }
837     }
838     gst_object_unref (demux);
839     return;
840   }
841 }
842
843 static guint64
844 gst_flv_demux_find_offset (GstFLVDemux * demux, GstSegment * segment)
845 {
846   gint64 bytes = 0;
847   gint64 time = 0;
848   GstIndexEntry *entry;
849
850   g_return_val_if_fail (segment != NULL, 0);
851
852   time = segment->start;
853
854   if (demux->index) {
855     /* Let's check if we have an index entry for that seek time */
856     entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
857         GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
858         GST_FORMAT_TIME, time);
859
860     if (entry) {
861       gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
862       gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
863
864       GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
865           " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
866           GST_TIME_ARGS (segment->start), GST_TIME_ARGS (time), bytes);
867
868       /* Key frame seeking */
869       if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
870         /* Adjust the segment so that the keyframe fits in */
871         if (time < segment->start) {
872           segment->start = segment->time = time;
873         }
874         segment->last_stop = time;
875       }
876     } else {
877       GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
878           GST_TIME_ARGS (segment->start));
879     }
880   }
881
882   return bytes;
883 }
884
885 static gboolean
886 flv_demux_handle_seek_push (GstFLVDemux * demux, GstEvent * event)
887 {
888   GstFormat format;
889   GstSeekFlags flags;
890   GstSeekType start_type, stop_type;
891   gint64 start, stop;
892   gdouble rate;
893   gboolean update, flush, keyframe, ret;
894   GstSegment seeksegment;
895
896   gst_event_parse_seek (event, &rate, &format, &flags,
897       &start_type, &start, &stop_type, &stop);
898
899   if (format != GST_FORMAT_TIME)
900     goto wrong_format;
901
902   flush = !!(flags & GST_SEEK_FLAG_FLUSH);
903   /* FIXME : the keyframe flag is never used ! */
904   keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT);
905
906   /* Work on a copy until we are sure the seek succeeded. */
907   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
908
909   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
910       &demux->segment);
911
912   /* Apply the seek to our segment */
913   gst_segment_set_seek (&seeksegment, rate, format, flags,
914       start_type, start, stop_type, stop, &update);
915
916   GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
917       &seeksegment);
918
919   if (flush || seeksegment.last_stop != demux->segment.last_stop) {
920     /* Do the actual seeking */
921     guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
922
923     GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
924         G_GUINT64_FORMAT, offset);
925     ret = gst_pad_push_event (demux->sinkpad,
926         gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
927             seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
928             offset, GST_SEEK_TYPE_NONE, 0));
929     if (G_UNLIKELY (!ret)) {
930       GST_WARNING_OBJECT (demux, "upstream seek failed");
931     }
932
933     /* Tell all the stream we moved to a different position (discont) */
934     demux->audio_need_discont = TRUE;
935     demux->video_need_discont = TRUE;
936   } else {
937     ret = TRUE;
938   }
939
940   if (ret) {
941     /* Ok seek succeeded, take the newly configured segment */
942     memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
943
944     /* Tell all the stream a new segment is needed */
945     demux->audio_need_segment = TRUE;
946     demux->video_need_segment = TRUE;
947     /* Clean any potential newsegment event kept for the streams. The first
948      * stream needing a new segment will create a new one. */
949     if (G_UNLIKELY (demux->new_seg_event)) {
950       gst_event_unref (demux->new_seg_event);
951       demux->new_seg_event = NULL;
952     }
953     gst_event_unref (event);
954   } else {
955     ret = gst_pad_push_event (demux->sinkpad, event);
956   }
957
958   return ret;
959
960 /* ERRORS */
961 wrong_format:
962   {
963     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
964     return gst_pad_push_event (demux->sinkpad, event);
965   }
966 }
967
968 static gboolean
969 gst_flv_demux_handle_seek_push (GstFLVDemux * demux, GstEvent * event)
970 {
971   if (!demux->indexed) {
972     guint64 seek_offset = 0;
973     gboolean building_index;
974     GstFormat fmt;
975
976     GST_OBJECT_LOCK (demux);
977     /* handle the seek in the chain function */
978     demux->seeking = TRUE;
979     demux->state = FLV_STATE_SEEK;
980
981     /* copy the event */
982     if (demux->seek_event)
983       gst_event_unref (demux->seek_event);
984     demux->seek_event = gst_event_ref (event);
985
986     /* set the building_index flag so that only one thread can setup the
987      * structures for index seeking. */
988     building_index = demux->building_index;
989     if (!building_index) {
990       demux->building_index = TRUE;
991       fmt = GST_FORMAT_BYTES;
992       if (!demux->file_size
993           && !gst_pad_query_peer_duration (demux->sinkpad, &fmt,
994               &demux->file_size)) {
995         GST_WARNING_OBJECT (demux,
996             "Cannot obtain file size - %" G_GINT64_FORMAT ", format %u",
997             demux->file_size, fmt);
998         GST_OBJECT_UNLOCK (demux);
999         return FALSE;
1000       }
1001
1002       /* we hope the last tag is a scriptdataobject containing an index
1003        * the size of the last tag is given in the last guint32 bits
1004        * then we seek to the beginning of the tag, parse it and hopefully obtain an index */
1005       seek_offset = demux->file_size - sizeof (guint32);
1006       GST_DEBUG_OBJECT (demux,
1007           "File size obtained, seeking to %" G_GUINT64_FORMAT, seek_offset);
1008     }
1009     GST_OBJECT_UNLOCK (demux);
1010
1011     if (!building_index) {
1012       GST_INFO_OBJECT (demux, "Seeking to last 4 bytes at %" G_GUINT64_FORMAT,
1013           seek_offset);
1014       return flv_demux_seek_to_offset (demux, seek_offset);
1015     }
1016
1017     /* FIXME: we have to always return true so that we don't block the seek
1018      * thread.
1019      * Note: maybe it is OK to return true if we're still building the index */
1020     return TRUE;
1021   }
1022
1023   return flv_demux_handle_seek_push (demux, event);
1024 }
1025
1026 static gboolean
1027 gst_flv_demux_handle_seek_pull (GstFLVDemux * demux, GstEvent * event,
1028     gboolean seeking)
1029 {
1030   GstFormat format;
1031   GstSeekFlags flags;
1032   GstSeekType start_type, stop_type;
1033   gint64 start, stop;
1034   gdouble rate;
1035   gboolean update, flush, keyframe, ret = FALSE;
1036   GstSegment seeksegment;
1037
1038   gst_event_parse_seek (event, &rate, &format, &flags,
1039       &start_type, &start, &stop_type, &stop);
1040
1041   if (format != GST_FORMAT_TIME)
1042     goto wrong_format;
1043
1044   /* mark seeking thread entering flushing/pausing */
1045   GST_OBJECT_LOCK (demux);
1046   if (seeking)
1047     demux->seeking = seeking;
1048   GST_OBJECT_UNLOCK (demux);
1049
1050   flush = !!(flags & GST_SEEK_FLAG_FLUSH);
1051   /* FIXME : the keyframe flag is never used */
1052   keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT);
1053
1054   if (flush) {
1055     /* Flush start up and downstream to make sure data flow and loops are
1056        idle */
1057     gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
1058     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
1059   } else {
1060     /* Pause the pulling task */
1061     gst_pad_pause_task (demux->sinkpad);
1062   }
1063
1064   /* Take the stream lock */
1065   GST_PAD_STREAM_LOCK (demux->sinkpad);
1066
1067   if (flush) {
1068     /* Stop flushing upstream we need to pull */
1069     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
1070   }
1071
1072   /* Work on a copy until we are sure the seek succeeded. */
1073   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
1074
1075   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
1076       &demux->segment);
1077
1078   /* Apply the seek to our segment */
1079   gst_segment_set_seek (&seeksegment, rate, format, flags,
1080       start_type, start, stop_type, stop, &update);
1081
1082   GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
1083       &seeksegment);
1084
1085   if (flush || seeksegment.last_stop != demux->segment.last_stop) {
1086     /* Do the actual seeking */
1087     /* index is reliable if it is complete or we do not go to far ahead */
1088     if (seeking && !demux->indexed &&
1089         seeksegment.last_stop > demux->index_max_time + 10 * GST_SECOND) {
1090       GST_DEBUG_OBJECT (demux, "delaying seek to post-scan; "
1091           " index only up to %" GST_TIME_FORMAT,
1092           GST_TIME_ARGS (demux->index_max_time));
1093       /* stop flushing for now */
1094       if (flush)
1095         gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop ());
1096       /* delegate scanning and index building to task thread to avoid
1097        * occupying main (UI) loop */
1098       if (demux->seek_event)
1099         gst_event_unref (demux->seek_event);
1100       demux->seek_event = gst_event_ref (event);
1101       demux->seek_time = seeksegment.last_stop;
1102       demux->state = FLV_STATE_SEEK;
1103       goto exit;
1104     }
1105     /* now index should be as reliable as it can be for current purpose */
1106     demux->offset = gst_flv_demux_find_offset (demux, &seeksegment);
1107
1108     /* Tell all the stream we moved to a different position (discont) */
1109     demux->audio_need_discont = TRUE;
1110     demux->video_need_discont = TRUE;
1111
1112     /* If we seeked at the beginning of the file parse the header again */
1113     if (G_UNLIKELY (!demux->offset)) {
1114       demux->state = FLV_STATE_HEADER;
1115     } else {                    /* or parse a tag */
1116       demux->state = FLV_STATE_TAG_TYPE;
1117     }
1118     ret = TRUE;
1119   } else {
1120     ret = TRUE;
1121   }
1122
1123   if (G_UNLIKELY (demux->close_seg_event)) {
1124     gst_event_unref (demux->close_seg_event);
1125     demux->close_seg_event = NULL;
1126   }
1127
1128   if (flush) {
1129     /* Stop flushing, the sinks are at time 0 now */
1130     gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop ());
1131   } else {
1132     GST_DEBUG_OBJECT (demux, "closing running segment %" GST_SEGMENT_FORMAT,
1133         &demux->segment);
1134
1135     /* Close the current segment for a linear playback */
1136     if (demux->segment.rate >= 0) {
1137       /* for forward playback, we played from start to last_stop */
1138       demux->close_seg_event = gst_event_new_new_segment (TRUE,
1139           demux->segment.rate, demux->segment.format,
1140           demux->segment.start, demux->segment.last_stop, demux->segment.time);
1141     } else {
1142       gint64 stop;
1143
1144       if ((stop = demux->segment.stop) == -1)
1145         stop = demux->segment.duration;
1146
1147       /* for reverse playback, we played from stop to last_stop. */
1148       demux->close_seg_event = gst_event_new_new_segment (TRUE,
1149           demux->segment.rate, demux->segment.format,
1150           demux->segment.last_stop, stop, demux->segment.last_stop);
1151     }
1152   }
1153
1154   if (ret) {
1155     /* Ok seek succeeded, take the newly configured segment */
1156     memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
1157
1158     /* Notify about the start of a new segment */
1159     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1160       gst_element_post_message (GST_ELEMENT (demux),
1161           gst_message_new_segment_start (GST_OBJECT (demux),
1162               demux->segment.format, demux->segment.last_stop));
1163     }
1164
1165     /* Tell all the stream a new segment is needed */
1166     demux->audio_need_segment = TRUE;
1167     demux->video_need_segment = TRUE;
1168     /* Clean any potential newsegment event kept for the streams. The first
1169      * stream needing a new segment will create a new one. */
1170     if (G_UNLIKELY (demux->new_seg_event)) {
1171       gst_event_unref (demux->new_seg_event);
1172       demux->new_seg_event = NULL;
1173     }
1174   }
1175
1176 exit:
1177   GST_OBJECT_LOCK (demux);
1178   seeking = demux->seeking && !seeking;
1179   demux->seeking = FALSE;
1180   GST_OBJECT_UNLOCK (demux);
1181
1182   /* if we detect an external seek having started (and possibly already having
1183    * flushed), do not restart task to give it a chance.
1184    * Otherwise external one's flushing will take care to pause task */
1185   if (seeking) {
1186     gst_pad_pause_task (demux->sinkpad);
1187   } else {
1188     gst_pad_start_task (demux->sinkpad,
1189         (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
1190   }
1191
1192   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
1193
1194   gst_event_unref (event);
1195   return ret;
1196
1197   /* ERRORS */
1198 wrong_format:
1199   {
1200     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
1201     gst_event_unref (event);
1202     return ret;
1203   }
1204 }
1205
1206 /* If we can pull that's prefered */
1207 static gboolean
1208 gst_flv_demux_sink_activate (GstPad * sinkpad)
1209 {
1210   if (gst_pad_check_pull_range (sinkpad)) {
1211     return gst_pad_activate_pull (sinkpad, TRUE);
1212   } else {
1213     return gst_pad_activate_push (sinkpad, TRUE);
1214   }
1215 }
1216
1217 /* This function gets called when we activate ourselves in push mode.
1218  * We cannot seek (ourselves) in the stream */
1219 static gboolean
1220 gst_flv_demux_sink_activate_push (GstPad * sinkpad, gboolean active)
1221 {
1222   GstFLVDemux *demux;
1223
1224   demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
1225
1226   demux->random_access = FALSE;
1227
1228   gst_object_unref (demux);
1229
1230   return TRUE;
1231 }
1232
1233 /* this function gets called when we activate ourselves in pull mode.
1234  * We can perform  random access to the resource and we start a task
1235  * to start reading */
1236 static gboolean
1237 gst_flv_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
1238 {
1239   GstFLVDemux *demux;
1240
1241   demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
1242
1243   if (active) {
1244     demux->random_access = TRUE;
1245     gst_object_unref (demux);
1246     return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
1247         sinkpad);
1248   } else {
1249     demux->random_access = FALSE;
1250     gst_object_unref (demux);
1251     return gst_pad_stop_task (sinkpad);
1252   }
1253 }
1254
1255 static gboolean
1256 gst_flv_demux_sink_event (GstPad * pad, GstEvent * event)
1257 {
1258   GstFLVDemux *demux;
1259   gboolean ret = FALSE;
1260
1261   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
1262
1263   GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
1264
1265   switch (GST_EVENT_TYPE (event)) {
1266     case GST_EVENT_FLUSH_START:
1267       GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
1268       demux->flushing = TRUE;
1269       ret = gst_flv_demux_push_src_event (demux, event);
1270       break;
1271     case GST_EVENT_FLUSH_STOP:
1272       GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
1273       gst_flv_demux_flush (demux, TRUE);
1274       ret = gst_flv_demux_push_src_event (demux, event);
1275       break;
1276     case GST_EVENT_EOS:
1277       GST_DEBUG_OBJECT (demux, "received EOS");
1278       if (demux->index) {
1279         GST_DEBUG_OBJECT (demux, "committing index");
1280         gst_index_commit (demux->index, demux->index_id);
1281       }
1282       if (!demux->no_more_pads) {
1283         gst_element_no_more_pads (GST_ELEMENT (demux));
1284         demux->no_more_pads = TRUE;
1285       }
1286
1287       if (!gst_flv_demux_push_src_event (demux, event))
1288         GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
1289       ret = TRUE;
1290       break;
1291     case GST_EVENT_NEWSEGMENT:
1292     {
1293       GstFormat format;
1294       gdouble rate;
1295       gint64 start, stop, time;
1296       gboolean update;
1297
1298       GST_DEBUG_OBJECT (demux, "received new segment");
1299
1300       gst_event_parse_new_segment (event, &update, &rate, &format, &start,
1301           &stop, &time);
1302
1303       if (format == GST_FORMAT_TIME) {
1304         /* time segment, this is perfect, copy over the values. */
1305         gst_segment_set_newsegment (&demux->segment, update, rate, format,
1306             start, stop, time);
1307
1308         GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
1309             &demux->segment);
1310
1311         /* and forward */
1312         ret = gst_flv_demux_push_src_event (demux, event);
1313       } else {
1314         /* non-time format */
1315         demux->audio_need_segment = TRUE;
1316         demux->video_need_segment = TRUE;
1317         ret = TRUE;
1318         gst_event_unref (event);
1319       }
1320       break;
1321     }
1322     default:
1323       ret = gst_flv_demux_push_src_event (demux, event);
1324       break;
1325   }
1326
1327   gst_object_unref (demux);
1328
1329   return ret;
1330 }
1331
1332 gboolean
1333 gst_flv_demux_src_event (GstPad * pad, GstEvent * event)
1334 {
1335   GstFLVDemux *demux;
1336   gboolean ret = FALSE;
1337
1338   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
1339
1340   GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
1341
1342   switch (GST_EVENT_TYPE (event)) {
1343     case GST_EVENT_SEEK:
1344       if (demux->random_access) {
1345         ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
1346       } else {
1347         ret = gst_flv_demux_handle_seek_push (demux, event);
1348       }
1349       break;
1350     default:
1351       ret = gst_pad_push_event (demux->sinkpad, event);
1352       break;
1353   }
1354
1355   gst_object_unref (demux);
1356
1357   return ret;
1358 }
1359
1360 gboolean
1361 gst_flv_demux_query (GstPad * pad, GstQuery * query)
1362 {
1363   gboolean res = TRUE;
1364   GstFLVDemux *demux;
1365
1366   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
1367
1368   switch (GST_QUERY_TYPE (query)) {
1369     case GST_QUERY_DURATION:
1370     {
1371       GstFormat format;
1372
1373       gst_query_parse_duration (query, &format, NULL);
1374
1375       /* duration is time only */
1376       if (format != GST_FORMAT_TIME) {
1377         GST_DEBUG_OBJECT (demux, "duration query only supported for time "
1378             "format");
1379         res = FALSE;
1380         goto beach;
1381       }
1382
1383       GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
1384           GST_TIME_ARGS (demux->duration));
1385
1386       gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
1387
1388       break;
1389     }
1390     case GST_QUERY_POSITION:
1391     {
1392       GstFormat format;
1393
1394       gst_query_parse_position (query, &format, NULL);
1395
1396       /* position is time only */
1397       if (format != GST_FORMAT_TIME) {
1398         GST_DEBUG_OBJECT (demux, "position query only supported for time "
1399             "format");
1400         res = FALSE;
1401         goto beach;
1402       }
1403
1404       GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
1405           GST_TIME_ARGS (demux->segment.last_stop));
1406
1407       gst_query_set_duration (query, GST_FORMAT_TIME, demux->segment.last_stop);
1408
1409       break;
1410     }
1411
1412     case GST_QUERY_SEEKING:{
1413       GstFormat fmt;
1414
1415       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
1416       res = TRUE;
1417       if (fmt != GST_FORMAT_TIME || !demux->index) {
1418         gst_query_set_seeking (query, fmt, FALSE, -1, -1);
1419       } else if (demux->random_access) {
1420         gst_query_set_seeking (query, GST_FORMAT_TIME, TRUE, 0,
1421             demux->duration);
1422       } else {
1423         GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
1424         gboolean seekable = gst_pad_peer_query (demux->sinkpad, peerquery);
1425
1426         if (seekable)
1427           gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
1428         gst_query_unref (peerquery);
1429
1430         if (seekable)
1431           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0,
1432               demux->duration);
1433         else
1434           gst_query_set_seeking (query, GST_FORMAT_TIME, FALSE, -1, -1);
1435       }
1436       break;
1437     }
1438     case GST_QUERY_LATENCY:
1439     default:
1440     {
1441       GstPad *peer;
1442
1443       if ((peer = gst_pad_get_peer (demux->sinkpad))) {
1444         /* query latency on peer pad */
1445         res = gst_pad_query (peer, query);
1446         gst_object_unref (peer);
1447       } else {
1448         /* no peer, we don't know */
1449         res = FALSE;
1450       }
1451       break;
1452     }
1453   }
1454
1455 beach:
1456   gst_object_unref (demux);
1457
1458   return res;
1459 }
1460
1461 static GstStateChangeReturn
1462 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
1463 {
1464   GstFLVDemux *demux;
1465   GstStateChangeReturn ret;
1466
1467   demux = GST_FLV_DEMUX (element);
1468
1469   switch (transition) {
1470     case GST_STATE_CHANGE_READY_TO_PAUSED:
1471       /* If this is our own index destroy it as the
1472        * old entries might be wrong for the new stream */
1473       if (demux->own_index) {
1474         gst_object_unref (demux->index);
1475         demux->index = NULL;
1476         demux->own_index = FALSE;
1477       }
1478
1479       /* If no index was created, generate one */
1480       if (G_UNLIKELY (!demux->index)) {
1481         GST_DEBUG_OBJECT (demux, "no index provided creating our own");
1482
1483         demux->index = gst_index_factory_make ("memindex");
1484
1485         gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
1486             &demux->index_id);
1487         demux->own_index = TRUE;
1488       }
1489       gst_flv_demux_cleanup (demux);
1490       break;
1491     default:
1492       break;
1493   }
1494
1495   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1496   if (ret == GST_STATE_CHANGE_FAILURE)
1497     return ret;
1498
1499   switch (transition) {
1500     case GST_STATE_CHANGE_PAUSED_TO_READY:
1501       gst_flv_demux_cleanup (demux);
1502       break;
1503     default:
1504       break;
1505   }
1506
1507   return ret;
1508 }
1509
1510 static void
1511 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
1512 {
1513   GstFLVDemux *demux = GST_FLV_DEMUX (element);
1514
1515   GST_OBJECT_LOCK (demux);
1516   if (demux->index)
1517     gst_object_unref (demux->index);
1518   if (index) {
1519     demux->index = gst_object_ref (index);
1520     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1521     demux->own_index = FALSE;
1522   } else
1523     demux->index = NULL;
1524
1525   GST_OBJECT_UNLOCK (demux);
1526 }
1527
1528 static GstIndex *
1529 gst_flv_demux_get_index (GstElement * element)
1530 {
1531   GstIndex *result = NULL;
1532
1533   GstFLVDemux *demux = GST_FLV_DEMUX (element);
1534
1535   GST_OBJECT_LOCK (demux);
1536   if (demux->index)
1537     result = gst_object_ref (demux->index);
1538   GST_OBJECT_UNLOCK (demux);
1539
1540   return result;
1541 }
1542
1543 static void
1544 gst_flv_demux_dispose (GObject * object)
1545 {
1546   GstFLVDemux *demux = GST_FLV_DEMUX (object);
1547
1548   GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
1549
1550   if (demux->adapter) {
1551     gst_adapter_clear (demux->adapter);
1552     g_object_unref (demux->adapter);
1553     demux->adapter = NULL;
1554   }
1555
1556   if (demux->taglist) {
1557     gst_tag_list_free (demux->taglist);
1558     demux->taglist = NULL;
1559   }
1560
1561   if (demux->new_seg_event) {
1562     gst_event_unref (demux->new_seg_event);
1563     demux->new_seg_event = NULL;
1564   }
1565
1566   if (demux->close_seg_event) {
1567     gst_event_unref (demux->close_seg_event);
1568     demux->close_seg_event = NULL;
1569   }
1570
1571   if (demux->audio_codec_data) {
1572     gst_buffer_unref (demux->audio_codec_data);
1573     demux->audio_codec_data = NULL;
1574   }
1575
1576   if (demux->video_codec_data) {
1577     gst_buffer_unref (demux->video_codec_data);
1578     demux->video_codec_data = NULL;
1579   }
1580
1581   if (demux->audio_pad) {
1582     gst_object_unref (demux->audio_pad);
1583     demux->audio_pad = NULL;
1584   }
1585
1586   if (demux->video_pad) {
1587     gst_object_unref (demux->video_pad);
1588     demux->video_pad = NULL;
1589   }
1590
1591   if (demux->index) {
1592     gst_object_unref (demux->index);
1593     demux->index = NULL;
1594   }
1595
1596   if (demux->times) {
1597     g_array_free (demux->times, TRUE);
1598     demux->times = NULL;
1599   }
1600
1601   if (demux->filepositions) {
1602     g_array_free (demux->filepositions, TRUE);
1603     demux->filepositions = NULL;
1604   }
1605
1606   GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
1607 }
1608
1609 static void
1610 gst_flv_demux_base_init (gpointer g_class)
1611 {
1612   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1613
1614   gst_element_class_add_pad_template (element_class,
1615       gst_static_pad_template_get (&flv_sink_template));
1616   gst_element_class_add_pad_template (element_class,
1617       gst_static_pad_template_get (&audio_src_template));
1618   gst_element_class_add_pad_template (element_class,
1619       gst_static_pad_template_get (&video_src_template));
1620   gst_element_class_set_details_simple (element_class, "FLV Demuxer",
1621       "Codec/Demuxer",
1622       "Demux FLV feeds into digital streams",
1623       "Julien Moutte <julien@moutte.net>");
1624 }
1625
1626 static void
1627 gst_flv_demux_class_init (GstFLVDemuxClass * klass)
1628 {
1629   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1630   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1631
1632   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_flv_demux_dispose);
1633
1634   gstelement_class->change_state =
1635       GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
1636   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
1637   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
1638 }
1639
1640 static void
1641 gst_flv_demux_init (GstFLVDemux * demux, GstFLVDemuxClass * g_class)
1642 {
1643   demux->sinkpad =
1644       gst_pad_new_from_static_template (&flv_sink_template, "sink");
1645
1646   gst_pad_set_event_function (demux->sinkpad,
1647       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
1648   gst_pad_set_chain_function (demux->sinkpad,
1649       GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
1650   gst_pad_set_activate_function (demux->sinkpad,
1651       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
1652   gst_pad_set_activatepull_function (demux->sinkpad,
1653       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_pull));
1654   gst_pad_set_activatepush_function (demux->sinkpad,
1655       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_push));
1656
1657   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
1658
1659   demux->adapter = gst_adapter_new ();
1660   demux->taglist = gst_tag_list_new ();
1661   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1662
1663   demux->own_index = FALSE;
1664
1665   gst_flv_demux_cleanup (demux);
1666 }
1667
1668 static gboolean
1669 plugin_init (GstPlugin * plugin)
1670 {
1671   GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
1672
1673   if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
1674           gst_flv_demux_get_type ()) ||
1675       !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
1676           gst_flv_mux_get_type ()))
1677     return FALSE;
1678
1679   return TRUE;
1680 }
1681
1682 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
1683     "flv", "FLV muxing and demuxing plugin",
1684     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)