5856e7ac5b5894879d6b8ecb4347852b5d7a24ba
[platform/upstream/gstreamer.git] / gst / flv / gstflvdemux.c
1 /* GStreamer
2  * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:element-flvdemux
22  *
23  * flvdemux demuxes an FLV file into the different contained streams.
24  *
25  * <refsect2>
26  * <title>Example launch line</title>
27  * |[
28  * gst-launch -v filesrc location=/path/to/flv ! flvdemux ! audioconvert ! autoaudiosink
29  * ]| This pipeline demuxes an FLV file and outputs the contained raw audio streams.
30  * </refsect2>
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include "gstflvdemux.h"
38 #include "gstflvparse.h"
39 #include "gstflvmux.h"
40
41 #include <string.h>
42
43 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
44     GST_PAD_SINK,
45     GST_PAD_ALWAYS,
46     GST_STATIC_CAPS ("video/x-flv")
47     );
48
49 static GstStaticPadTemplate audio_src_template =
50 GST_STATIC_PAD_TEMPLATE ("audio",
51     GST_PAD_SRC,
52     GST_PAD_SOMETIMES,
53     GST_STATIC_CAPS_ANY);
54
55 static GstStaticPadTemplate video_src_template =
56 GST_STATIC_PAD_TEMPLATE ("video",
57     GST_PAD_SRC,
58     GST_PAD_SOMETIMES,
59     GST_STATIC_CAPS_ANY);
60
61 GST_DEBUG_CATEGORY (flvdemux_debug);
62 #define GST_CAT_DEFAULT flvdemux_debug
63
64 GST_BOILERPLATE (GstFLVDemux, gst_flv_demux, GstElement, GST_TYPE_ELEMENT);
65
66 /* 9 bytes of header + 4 bytes of first previous tag size */
67 #define FLV_HEADER_SIZE 13
68 /* 1 byte of tag type + 3 bytes of tag data size */
69 #define FLV_TAG_TYPE_SIZE 4
70
71 static void
72 gst_flv_demux_flush (GstFLVDemux * demux, gboolean discont)
73 {
74   GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
75
76   gst_adapter_clear (demux->adapter);
77
78   demux->audio_need_discont = TRUE;
79   demux->video_need_discont = TRUE;
80
81   demux->flushing = FALSE;
82
83   /* Only in push mode */
84   if (!demux->random_access) {
85     /* After a flush we expect a tag_type */
86     demux->state = FLV_STATE_TAG_TYPE;
87     /* We reset the offset and will get one from first push */
88     demux->offset = 0;
89   }
90 }
91
92 static void
93 gst_flv_demux_cleanup (GstFLVDemux * demux)
94 {
95   GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
96
97   demux->state = FLV_STATE_HEADER;
98
99   demux->flushing = FALSE;
100   demux->need_header = TRUE;
101   demux->audio_need_segment = TRUE;
102   demux->video_need_segment = TRUE;
103   demux->audio_need_discont = TRUE;
104   demux->video_need_discont = TRUE;
105
106   /* By default we consider them as linked */
107   demux->audio_linked = TRUE;
108   demux->video_linked = TRUE;
109
110   demux->has_audio = FALSE;
111   demux->has_video = FALSE;
112   demux->push_tags = FALSE;
113   demux->got_par = FALSE;
114
115   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
116
117   demux->w = demux->h = 0;
118   demux->par_x = demux->par_y = 1;
119   demux->video_offset = 0;
120   demux->audio_offset = 0;
121   demux->offset = demux->cur_tag_offset = 0;
122   demux->tag_size = demux->tag_data_size = 0;
123   demux->duration = GST_CLOCK_TIME_NONE;
124
125   if (demux->new_seg_event) {
126     gst_event_unref (demux->new_seg_event);
127     demux->new_seg_event = NULL;
128   }
129
130   if (demux->close_seg_event) {
131     gst_event_unref (demux->close_seg_event);
132     demux->close_seg_event = NULL;
133   }
134
135   gst_adapter_clear (demux->adapter);
136
137   if (demux->audio_codec_data) {
138     gst_buffer_unref (demux->audio_codec_data);
139     demux->audio_codec_data = NULL;
140   }
141
142   if (demux->video_codec_data) {
143     gst_buffer_unref (demux->video_codec_data);
144     demux->video_codec_data = NULL;
145   }
146
147   if (demux->audio_pad) {
148     gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
149     gst_object_unref (demux->audio_pad);
150     demux->audio_pad = NULL;
151   }
152
153   if (demux->video_pad) {
154     gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
155     gst_object_unref (demux->video_pad);
156     demux->video_pad = NULL;
157   }
158
159   if (demux->times) {
160     g_array_free (demux->times, TRUE);
161     demux->times = NULL;
162   }
163
164   if (demux->filepositions) {
165     g_array_free (demux->filepositions, TRUE);
166     demux->filepositions = NULL;
167   }
168 }
169
170 static GstFlowReturn
171 gst_flv_demux_chain (GstPad * pad, GstBuffer * buffer)
172 {
173   GstFlowReturn ret = GST_FLOW_OK;
174   GstFLVDemux *demux = NULL;
175
176   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
177
178   GST_LOG_OBJECT (demux, "received buffer of %d bytes at offset %"
179       G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer));
180
181   if (G_UNLIKELY (GST_BUFFER_OFFSET (buffer) == 0)) {
182     GST_DEBUG_OBJECT (demux, "beginning of file, expect header");
183     demux->state = FLV_STATE_HEADER;
184     demux->offset = 0;
185   }
186
187   if (G_UNLIKELY (demux->offset == 0 && GST_BUFFER_OFFSET (buffer) != 0)) {
188     GST_DEBUG_OBJECT (demux, "offset was zero, synchronizing with buffer's");
189     demux->offset = GST_BUFFER_OFFSET (buffer);
190   }
191
192   gst_adapter_push (demux->adapter, buffer);
193
194 parse:
195   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
196     if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
197             || demux->video_linked)) {
198       ret = GST_FLOW_OK;
199     } else {
200       GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
201       goto beach;
202     }
203   }
204
205   if (G_UNLIKELY (demux->flushing)) {
206     GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
207     ret = GST_FLOW_WRONG_STATE;
208     goto beach;
209   }
210
211   switch (demux->state) {
212     case FLV_STATE_HEADER:
213     {
214       if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
215         GstBuffer *buffer;
216
217         buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
218
219         ret = gst_flv_parse_header (demux, buffer);
220
221         gst_buffer_unref (buffer);
222         demux->offset += FLV_HEADER_SIZE;
223
224         demux->state = FLV_STATE_TAG_TYPE;
225         goto parse;
226       } else {
227         goto beach;
228       }
229     }
230     case FLV_STATE_TAG_TYPE:
231     {
232       if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
233         GstBuffer *buffer;
234
235         /* Remember the tag offset in bytes */
236         demux->cur_tag_offset = demux->offset;
237
238         buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
239
240         ret = gst_flv_parse_tag_type (demux, buffer);
241
242         gst_buffer_unref (buffer);
243         demux->offset += FLV_TAG_TYPE_SIZE;
244
245         goto parse;
246       } else {
247         goto beach;
248       }
249     }
250     case FLV_STATE_TAG_VIDEO:
251     {
252       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
253         GstBuffer *buffer;
254
255         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
256
257         ret = gst_flv_parse_tag_video (demux, buffer);
258
259         gst_buffer_unref (buffer);
260         demux->offset += demux->tag_size;
261
262         demux->state = FLV_STATE_TAG_TYPE;
263         goto parse;
264       } else {
265         goto beach;
266       }
267     }
268     case FLV_STATE_TAG_AUDIO:
269     {
270       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
271         GstBuffer *buffer;
272
273         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
274
275         ret = gst_flv_parse_tag_audio (demux, buffer);
276
277         gst_buffer_unref (buffer);
278         demux->offset += demux->tag_size;
279
280         demux->state = FLV_STATE_TAG_TYPE;
281         goto parse;
282       } else {
283         goto beach;
284       }
285     }
286     case FLV_STATE_TAG_SCRIPT:
287     {
288       if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
289         GstBuffer *buffer;
290
291         buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
292
293         ret = gst_flv_parse_tag_script (demux, buffer);
294
295         gst_buffer_unref (buffer);
296         demux->offset += demux->tag_size;
297
298         demux->state = FLV_STATE_TAG_TYPE;
299         goto parse;
300       } else {
301         goto beach;
302       }
303     }
304     default:
305       GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
306   }
307
308 beach:
309   if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
310     /* If either audio or video is linked we return GST_FLOW_OK */
311     if (demux->audio_linked || demux->video_linked) {
312       ret = GST_FLOW_OK;
313     }
314   }
315
316   gst_object_unref (demux);
317
318   return ret;
319 }
320
321 static GstFlowReturn
322 gst_flv_demux_pull_range (GstFLVDemux * demux, GstPad * pad, guint64 offset,
323     guint size, GstBuffer ** buffer)
324 {
325   GstFlowReturn ret;
326
327   ret = gst_pad_pull_range (pad, offset, size, buffer);
328   if (G_UNLIKELY (ret != GST_FLOW_OK)) {
329     GST_WARNING_OBJECT (demux,
330         "failed when pulling %d bytes from offset %" G_GUINT64_FORMAT ": %s",
331         size, offset, gst_flow_get_name (ret));
332     *buffer = NULL;
333     return ret;
334   }
335
336   if (G_UNLIKELY (*buffer && GST_BUFFER_SIZE (*buffer) != size)) {
337     GST_WARNING_OBJECT (demux,
338         "partial pull got %d when expecting %d from offset %" G_GUINT64_FORMAT,
339         GST_BUFFER_SIZE (*buffer), size, offset);
340     gst_buffer_unref (*buffer);
341     ret = GST_FLOW_UNEXPECTED;
342     *buffer = NULL;
343     return ret;
344   }
345
346   return ret;
347 }
348
349 static GstFlowReturn
350 gst_flv_demux_pull_tag (GstPad * pad, GstFLVDemux * demux)
351 {
352   GstBuffer *buffer = NULL;
353   GstFlowReturn ret = GST_FLOW_OK;
354
355   /* Store tag offset */
356   demux->cur_tag_offset = demux->offset;
357
358   /* Get the first 4 bytes to identify tag type and size */
359   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
360                   FLV_TAG_TYPE_SIZE, &buffer)) != GST_FLOW_OK))
361     goto beach;
362
363   /* Identify tag type */
364   ret = gst_flv_parse_tag_type (demux, buffer);
365
366   gst_buffer_unref (buffer);
367
368   if (G_UNLIKELY (ret != GST_FLOW_OK))
369     goto beach;
370
371   /* Jump over tag type + size */
372   demux->offset += FLV_TAG_TYPE_SIZE;
373
374   /* Pull the whole tag */
375   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
376                   demux->tag_size, &buffer)) != GST_FLOW_OK))
377     goto beach;
378
379   switch (demux->state) {
380     case FLV_STATE_TAG_VIDEO:
381       ret = gst_flv_parse_tag_video (demux, buffer);
382       break;
383     case FLV_STATE_TAG_AUDIO:
384       ret = gst_flv_parse_tag_audio (demux, buffer);
385       break;
386     case FLV_STATE_TAG_SCRIPT:
387       ret = gst_flv_parse_tag_script (demux, buffer);
388       break;
389     default:
390       GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
391   }
392
393   gst_buffer_unref (buffer);
394
395   /* Jump over that part we've just parsed */
396   demux->offset += demux->tag_size;
397
398   /* Make sure we reinitialize the tag size */
399   demux->tag_size = 0;
400
401   /* Ready for the next tag */
402   demux->state = FLV_STATE_TAG_TYPE;
403
404   if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
405     /* If either audio or video is linked we return GST_FLOW_OK */
406     if (demux->audio_linked || demux->video_linked) {
407       ret = GST_FLOW_OK;
408     } else {
409       GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
410           "neither video nor audio are linked");
411     }
412   }
413
414 beach:
415   return ret;
416 }
417
418 static GstFlowReturn
419 gst_flv_demux_pull_header (GstPad * pad, GstFLVDemux * demux)
420 {
421   GstBuffer *buffer = NULL;
422   GstFlowReturn ret = GST_FLOW_OK;
423
424   /* Get the first 9 bytes */
425   if (G_UNLIKELY ((ret = gst_flv_demux_pull_range (demux, pad, demux->offset,
426                   FLV_HEADER_SIZE, &buffer)) != GST_FLOW_OK))
427     goto beach;
428
429   ret = gst_flv_parse_header (demux, buffer);
430
431   gst_buffer_unref (buffer);
432
433   /* Jump over the header now */
434   demux->offset += FLV_HEADER_SIZE;
435   demux->state = FLV_STATE_TAG_TYPE;
436
437 beach:
438   return ret;
439 }
440
441 static GstFlowReturn
442 gst_flv_demux_seek_to_prev_keyframe (GstFLVDemux * demux)
443 {
444   return GST_FLOW_OK;
445 }
446
447 static gboolean
448 gst_flv_demux_push_src_event (GstFLVDemux * demux, GstEvent * event)
449 {
450   gboolean ret = TRUE;
451
452   if (demux->audio_pad)
453     ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
454
455   if (demux->video_pad)
456     ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
457
458   gst_event_unref (event);
459
460   return ret;
461 }
462
463 static void
464 gst_flv_demux_create_index (GstFLVDemux * demux)
465 {
466   gint64 size;
467   GstFormat fmt = GST_FORMAT_BYTES;
468   size_t tag_size;
469   guint64 old_offset;
470   GstBuffer *buffer;
471   GstFlowReturn ret;
472
473   if (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &size) ||
474       fmt != GST_FORMAT_BYTES)
475     return;
476
477   old_offset = demux->offset;
478
479   while ((ret =
480           gst_flv_demux_pull_range (demux, demux->sinkpad, demux->offset, 12,
481               &buffer)) == GST_FLOW_OK) {
482     if (gst_flv_parse_tag_timestamp (demux, buffer,
483             &tag_size) == GST_CLOCK_TIME_NONE) {
484       gst_buffer_unref (buffer);
485       break;
486     }
487
488     gst_buffer_unref (buffer);
489     demux->offset += tag_size;
490   }
491
492   demux->offset = old_offset;
493 }
494
495 static void
496 gst_flv_demux_loop (GstPad * pad)
497 {
498   GstFLVDemux *demux = NULL;
499   GstFlowReturn ret = GST_FLOW_OK;
500
501   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
502
503   if (demux->segment.rate >= 0) {
504     /* pull in data */
505     switch (demux->state) {
506       case FLV_STATE_TAG_TYPE:
507         ret = gst_flv_demux_pull_tag (pad, demux);
508         break;
509       case FLV_STATE_DONE:
510         ret = GST_FLOW_UNEXPECTED;
511         break;
512       default:
513         ret = gst_flv_demux_pull_header (pad, demux);
514         if (ret == GST_FLOW_OK)
515           gst_flv_demux_create_index (demux);
516
517     }
518
519     /* pause if something went wrong */
520     if (G_UNLIKELY (ret != GST_FLOW_OK))
521       goto pause;
522
523     /* check EOS condition */
524     if ((demux->segment.flags & GST_SEEK_FLAG_SEGMENT) &&
525         (demux->segment.stop != -1) &&
526         (demux->segment.last_stop >= demux->segment.stop)) {
527       ret = GST_FLOW_UNEXPECTED;
528       goto pause;
529     }
530   } else {                      /* Reverse playback */
531     /* pull in data */
532     switch (demux->state) {
533       case FLV_STATE_TAG_TYPE:
534         ret = gst_flv_demux_pull_tag (pad, demux);
535         /* When packet parsing returns UNEXPECTED that means we ve reached the
536            point where we want to go to the previous keyframe. This is either
537            the last FLV tag or the keyframe we used last time */
538         if (ret == GST_FLOW_UNEXPECTED) {
539           ret = gst_flv_demux_seek_to_prev_keyframe (demux);
540           demux->state = FLV_STATE_TAG_TYPE;
541         }
542         break;
543       default:
544         ret = gst_flv_demux_pull_header (pad, demux);
545         if (ret == GST_FLOW_OK)
546           gst_flv_demux_create_index (demux);
547     }
548
549     /* pause if something went wrong */
550     if (G_UNLIKELY (ret != GST_FLOW_OK))
551       goto pause;
552
553     /* check EOS condition */
554     if (demux->segment.last_stop <= demux->segment.start) {
555       ret = GST_FLOW_UNEXPECTED;
556       goto pause;
557     }
558   }
559
560   gst_object_unref (demux);
561
562   return;
563
564 pause:
565   {
566     const gchar *reason = gst_flow_get_name (ret);
567
568     GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
569     gst_pad_pause_task (pad);
570
571     if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
572       if (ret == GST_FLOW_UNEXPECTED) {
573         /* perform EOS logic */
574         gst_element_no_more_pads (GST_ELEMENT_CAST (demux));
575         if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
576           gint64 stop;
577
578           /* for segment playback we need to post when (in stream time)
579            * we stopped, this is either stop (when set) or the duration. */
580           if ((stop = demux->segment.stop) == -1)
581             stop = demux->segment.duration;
582
583           if (demux->segment.rate >= 0) {
584             GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
585             gst_element_post_message (GST_ELEMENT_CAST (demux),
586                 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
587                     GST_FORMAT_TIME, stop));
588           } else {              /* Reverse playback */
589             GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
590                 "segment");
591             gst_element_post_message (GST_ELEMENT_CAST (demux),
592                 gst_message_new_segment_done (GST_OBJECT_CAST (demux),
593                     GST_FORMAT_TIME, demux->segment.start));
594           }
595         } else {
596           /* normal playback, send EOS to all linked pads */
597           gst_element_no_more_pads (GST_ELEMENT (demux));
598           GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
599           if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
600             GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
601         }
602       } else {
603         GST_ELEMENT_ERROR (demux, STREAM, FAILED,
604             ("Internal data stream error."),
605             ("stream stopped, reason %s", reason));
606         gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
607       }
608     }
609     gst_object_unref (demux);
610     return;
611   }
612 }
613
614 static guint64
615 gst_flv_demux_find_offset (GstFLVDemux * demux, GstSegment * segment)
616 {
617   gint64 bytes = 0;
618   gint64 time = 0;
619   GstIndexEntry *entry;
620
621   g_return_val_if_fail (segment != NULL, 0);
622
623   time = segment->start;
624
625   if (demux->index) {
626     /* Let's check if we have an index entry for that seek time */
627     entry = gst_index_get_assoc_entry (demux->index, demux->index_id,
628         GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT,
629         GST_FORMAT_TIME, time);
630
631     if (entry) {
632       gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
633       gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
634
635       GST_DEBUG_OBJECT (demux, "found index entry for %" GST_TIME_FORMAT
636           " at %" GST_TIME_FORMAT ", seeking to %" G_GINT64_FORMAT,
637           GST_TIME_ARGS (segment->start), GST_TIME_ARGS (time), bytes);
638
639       /* Key frame seeking */
640       if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
641         /* Adjust the segment so that the keyframe fits in */
642         if (time < segment->start) {
643           segment->start = segment->time = time;
644         }
645         segment->last_stop = time;
646       }
647     } else {
648       GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
649           GST_TIME_ARGS (segment->start));
650     }
651   }
652
653   return bytes;
654 }
655
656 static gboolean
657 gst_flv_demux_handle_seek_push (GstFLVDemux * demux, GstEvent * event)
658 {
659   GstFormat format;
660   GstSeekFlags flags;
661   GstSeekType start_type, stop_type;
662   gint64 start, stop;
663   gdouble rate;
664   gboolean update, flush, keyframe, ret;
665   GstSegment seeksegment;
666
667   gst_event_parse_seek (event, &rate, &format, &flags,
668       &start_type, &start, &stop_type, &stop);
669
670   if (format != GST_FORMAT_TIME)
671     goto wrong_format;
672
673   flush = !!(flags & GST_SEEK_FLAG_FLUSH);
674   keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT);
675
676   /* Work on a copy until we are sure the seek succeeded. */
677   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
678
679   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
680       &demux->segment);
681
682   /* Apply the seek to our segment */
683   gst_segment_set_seek (&seeksegment, rate, format, flags,
684       start_type, start, stop_type, stop, &update);
685
686   GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
687       &seeksegment);
688
689   if (flush || seeksegment.last_stop != demux->segment.last_stop) {
690     /* Do the actual seeking */
691     guint64 offset = gst_flv_demux_find_offset (demux, &seeksegment);
692
693     GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
694         G_GUINT64_FORMAT, offset);
695     ret = gst_pad_push_event (demux->sinkpad,
696         gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
697             seeksegment.flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
698             offset, GST_SEEK_TYPE_NONE, 0));
699     if (G_UNLIKELY (!ret)) {
700       GST_WARNING_OBJECT (demux, "upstream seek failed");
701     }
702
703     /* Tell all the stream we moved to a different position (discont) */
704     demux->audio_need_discont = TRUE;
705     demux->video_need_discont = TRUE;
706   } else {
707     ret = TRUE;
708   }
709
710   if (ret) {
711     /* Ok seek succeeded, take the newly configured segment */
712     memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
713
714     /* Tell all the stream a new segment is needed */
715     demux->audio_need_segment = TRUE;
716     demux->video_need_segment = TRUE;
717     /* Clean any potential newsegment event kept for the streams. The first
718      * stream needing a new segment will create a new one. */
719     if (G_UNLIKELY (demux->new_seg_event)) {
720       gst_event_unref (demux->new_seg_event);
721       demux->new_seg_event = NULL;
722     }
723     gst_event_unref (event);
724   } else {
725     ret = gst_pad_push_event (demux->sinkpad, event);
726   }
727
728   return ret;
729
730 /* ERRORS */
731 wrong_format:
732   {
733     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
734     return gst_pad_push_event (demux->sinkpad, event);
735   }
736 }
737
738 static gboolean
739 gst_flv_demux_handle_seek_pull (GstFLVDemux * demux, GstEvent * event)
740 {
741   GstFormat format;
742   GstSeekFlags flags;
743   GstSeekType start_type, stop_type;
744   gint64 start, stop;
745   gdouble rate;
746   gboolean update, flush, keyframe, ret;
747   GstSegment seeksegment;
748
749   gst_event_parse_seek (event, &rate, &format, &flags,
750       &start_type, &start, &stop_type, &stop);
751
752   gst_event_unref (event);
753
754   if (format != GST_FORMAT_TIME)
755     goto wrong_format;
756
757   flush = !!(flags & GST_SEEK_FLAG_FLUSH);
758   keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT);
759
760   if (flush) {
761     /* Flush start up and downstream to make sure data flow and loops are
762        idle */
763     gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
764     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
765   } else {
766     /* Pause the pulling task */
767     gst_pad_pause_task (demux->sinkpad);
768   }
769
770   /* Take the stream lock */
771   GST_PAD_STREAM_LOCK (demux->sinkpad);
772
773   if (flush) {
774     /* Stop flushing upstream we need to pull */
775     gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
776   }
777
778   /* Work on a copy until we are sure the seek succeeded. */
779   memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
780
781   GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
782       &demux->segment);
783
784   /* Apply the seek to our segment */
785   gst_segment_set_seek (&seeksegment, rate, format, flags,
786       start_type, start, stop_type, stop, &update);
787
788   GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
789       &seeksegment);
790
791   if (flush || seeksegment.last_stop != demux->segment.last_stop) {
792     /* Do the actual seeking */
793     demux->offset = gst_flv_demux_find_offset (demux, &seeksegment);
794
795     /* Tell all the stream we moved to a different position (discont) */
796     demux->audio_need_discont = TRUE;
797     demux->video_need_discont = TRUE;
798
799     /* If we seeked at the beginning of the file parse the header again */
800     if (G_UNLIKELY (!demux->offset)) {
801       demux->state = FLV_STATE_HEADER;
802     } else {                    /* or parse a tag */
803       demux->state = FLV_STATE_TAG_TYPE;
804     }
805     ret = TRUE;
806   } else {
807     ret = TRUE;
808   }
809
810   if (G_UNLIKELY (demux->close_seg_event)) {
811     gst_event_unref (demux->close_seg_event);
812     demux->close_seg_event = NULL;
813   }
814
815   if (flush) {
816     /* Stop flushing, the sinks are at time 0 now */
817     gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop ());
818   } else {
819     GST_DEBUG_OBJECT (demux, "closing running segment %" GST_SEGMENT_FORMAT,
820         &demux->segment);
821
822     /* Close the current segment for a linear playback */
823     if (demux->segment.rate >= 0) {
824       /* for forward playback, we played from start to last_stop */
825       demux->close_seg_event = gst_event_new_new_segment (TRUE,
826           demux->segment.rate, demux->segment.format,
827           demux->segment.start, demux->segment.last_stop, demux->segment.time);
828     } else {
829       gint64 stop;
830
831       if ((stop = demux->segment.stop) == -1)
832         stop = demux->segment.duration;
833
834       /* for reverse playback, we played from stop to last_stop. */
835       demux->close_seg_event = gst_event_new_new_segment (TRUE,
836           demux->segment.rate, demux->segment.format,
837           demux->segment.last_stop, stop, demux->segment.last_stop);
838     }
839   }
840
841   if (ret) {
842     /* Ok seek succeeded, take the newly configured segment */
843     memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
844
845     /* Notify about the start of a new segment */
846     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
847       gst_element_post_message (GST_ELEMENT (demux),
848           gst_message_new_segment_start (GST_OBJECT (demux),
849               demux->segment.format, demux->segment.last_stop));
850     }
851
852     /* Tell all the stream a new segment is needed */
853     demux->audio_need_segment = TRUE;
854     demux->video_need_segment = TRUE;
855     /* Clean any potential newsegment event kept for the streams. The first
856      * stream needing a new segment will create a new one. */
857     if (G_UNLIKELY (demux->new_seg_event)) {
858       gst_event_unref (demux->new_seg_event);
859       demux->new_seg_event = NULL;
860     }
861   }
862
863   gst_pad_start_task (demux->sinkpad,
864       (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
865
866   GST_PAD_STREAM_UNLOCK (demux->sinkpad);
867
868   return ret;
869
870   /* ERRORS */
871 wrong_format:
872   {
873     GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
874     return FALSE;
875   }
876 }
877
878 /* If we can pull that's prefered */
879 static gboolean
880 gst_flv_demux_sink_activate (GstPad * sinkpad)
881 {
882   if (gst_pad_check_pull_range (sinkpad)) {
883     return gst_pad_activate_pull (sinkpad, TRUE);
884   } else {
885     return gst_pad_activate_push (sinkpad, TRUE);
886   }
887 }
888
889 /* This function gets called when we activate ourselves in push mode.
890  * We cannot seek (ourselves) in the stream */
891 static gboolean
892 gst_flv_demux_sink_activate_push (GstPad * sinkpad, gboolean active)
893 {
894   GstFLVDemux *demux;
895
896   demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
897
898   demux->random_access = FALSE;
899
900   gst_object_unref (demux);
901
902   return TRUE;
903 }
904
905 /* this function gets called when we activate ourselves in pull mode.
906  * We can perform  random access to the resource and we start a task
907  * to start reading */
908 static gboolean
909 gst_flv_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
910 {
911   GstFLVDemux *demux;
912
913   demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
914
915   if (active) {
916     demux->random_access = TRUE;
917     gst_object_unref (demux);
918     return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
919         sinkpad);
920   } else {
921     demux->random_access = FALSE;
922     gst_object_unref (demux);
923     return gst_pad_stop_task (sinkpad);
924   }
925 }
926
927 static gboolean
928 gst_flv_demux_sink_event (GstPad * pad, GstEvent * event)
929 {
930   GstFLVDemux *demux;
931   gboolean ret = FALSE;
932
933   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
934
935   GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
936
937   switch (GST_EVENT_TYPE (event)) {
938     case GST_EVENT_FLUSH_START:
939       GST_DEBUG_OBJECT (demux, "trying to force chain function to exit");
940       demux->flushing = TRUE;
941       ret = gst_flv_demux_push_src_event (demux, event);
942       break;
943     case GST_EVENT_FLUSH_STOP:
944       GST_DEBUG_OBJECT (demux, "flushing FLV demuxer");
945       gst_flv_demux_flush (demux, TRUE);
946       ret = gst_flv_demux_push_src_event (demux, event);
947       break;
948     case GST_EVENT_EOS:
949       GST_DEBUG_OBJECT (demux, "received EOS");
950       if (demux->index) {
951         GST_DEBUG_OBJECT (demux, "committing index");
952         gst_index_commit (demux->index, demux->index_id);
953       }
954       gst_element_no_more_pads (GST_ELEMENT (demux));
955       if (!gst_flv_demux_push_src_event (demux, event))
956         GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
957       ret = TRUE;
958       break;
959     case GST_EVENT_NEWSEGMENT:
960     {
961       GstFormat format;
962       gdouble rate;
963       gint64 start, stop, time;
964       gboolean update;
965
966       GST_DEBUG_OBJECT (demux, "received new segment");
967
968       gst_event_parse_new_segment (event, &update, &rate, &format, &start,
969           &stop, &time);
970
971       if (format == GST_FORMAT_TIME) {
972         /* time segment, this is perfect, copy over the values. */
973         gst_segment_set_newsegment (&demux->segment, update, rate, format,
974             start, stop, time);
975
976         GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
977             &demux->segment);
978
979         /* and forward */
980         ret = gst_flv_demux_push_src_event (demux, event);
981       } else {
982         /* non-time format */
983         demux->audio_need_segment = TRUE;
984         demux->video_need_segment = TRUE;
985         ret = TRUE;
986         gst_event_unref (event);
987       }
988       break;
989     }
990     default:
991       ret = gst_flv_demux_push_src_event (demux, event);
992       break;
993   }
994
995   gst_object_unref (demux);
996
997   return ret;
998 }
999
1000 gboolean
1001 gst_flv_demux_src_event (GstPad * pad, GstEvent * event)
1002 {
1003   GstFLVDemux *demux;
1004   gboolean ret = FALSE;
1005
1006   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
1007
1008   GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
1009
1010   switch (GST_EVENT_TYPE (event)) {
1011     case GST_EVENT_SEEK:
1012       if (demux->random_access) {
1013         ret = gst_flv_demux_handle_seek_pull (demux, event);
1014       } else {
1015         ret = gst_flv_demux_handle_seek_push (demux, event);
1016       }
1017       break;
1018     default:
1019       ret = gst_pad_push_event (demux->sinkpad, event);
1020       break;
1021   }
1022
1023   gst_object_unref (demux);
1024
1025   return ret;
1026 }
1027
1028 gboolean
1029 gst_flv_demux_query (GstPad * pad, GstQuery * query)
1030 {
1031   gboolean res = TRUE;
1032   GstFLVDemux *demux;
1033
1034   demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
1035
1036   switch (GST_QUERY_TYPE (query)) {
1037     case GST_QUERY_DURATION:
1038     {
1039       GstFormat format;
1040
1041       gst_query_parse_duration (query, &format, NULL);
1042
1043       /* duration is time only */
1044       if (format != GST_FORMAT_TIME) {
1045         GST_DEBUG_OBJECT (demux, "duration query only supported for time "
1046             "format");
1047         res = FALSE;
1048         goto beach;
1049       }
1050
1051       GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
1052           GST_TIME_ARGS (demux->duration));
1053
1054       gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
1055
1056       break;
1057     }
1058     case GST_QUERY_POSITION:
1059     {
1060       GstFormat format;
1061
1062       gst_query_parse_position (query, &format, NULL);
1063
1064       /* position is time only */
1065       if (format != GST_FORMAT_TIME) {
1066         GST_DEBUG_OBJECT (demux, "position query only supported for time "
1067             "format");
1068         res = FALSE;
1069         goto beach;
1070       }
1071
1072       GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
1073           GST_TIME_ARGS (demux->segment.last_stop));
1074
1075       gst_query_set_duration (query, GST_FORMAT_TIME, demux->segment.last_stop);
1076
1077       break;
1078     }
1079
1080     case GST_QUERY_LATENCY:
1081     default:
1082     {
1083       GstPad *peer;
1084
1085       if ((peer = gst_pad_get_peer (demux->sinkpad))) {
1086         /* query latency on peer pad */
1087         res = gst_pad_query (peer, query);
1088         gst_object_unref (peer);
1089       } else {
1090         /* no peer, we don't know */
1091         res = FALSE;
1092       }
1093       break;
1094     }
1095   }
1096
1097 beach:
1098   gst_object_unref (demux);
1099
1100   return res;
1101 }
1102
1103 static GstStateChangeReturn
1104 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
1105 {
1106   GstFLVDemux *demux;
1107   GstStateChangeReturn ret;
1108
1109   demux = GST_FLV_DEMUX (element);
1110
1111   switch (transition) {
1112     case GST_STATE_CHANGE_READY_TO_PAUSED:
1113       /* If this is our own index destroy it as the
1114        * old entries might be wrong for the new stream */
1115       if (demux->own_index) {
1116         gst_object_unref (demux->index);
1117         demux->index = NULL;
1118         demux->own_index = FALSE;
1119       }
1120
1121       /* If no index was created, generate one */
1122       if (G_UNLIKELY (!demux->index)) {
1123         GST_DEBUG_OBJECT (demux, "no index provided creating our own");
1124
1125         demux->index = gst_index_factory_make ("memindex");
1126
1127         gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
1128             &demux->index_id);
1129         demux->own_index = TRUE;
1130       }
1131       gst_flv_demux_cleanup (demux);
1132       break;
1133     default:
1134       break;
1135   }
1136
1137   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1138   if (ret == GST_STATE_CHANGE_FAILURE)
1139     return ret;
1140
1141   switch (transition) {
1142     case GST_STATE_CHANGE_PAUSED_TO_READY:
1143       gst_flv_demux_cleanup (demux);
1144       break;
1145     default:
1146       break;
1147   }
1148
1149   return ret;
1150 }
1151
1152 static void
1153 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
1154 {
1155   GstFLVDemux *demux = GST_FLV_DEMUX (element);
1156
1157   GST_OBJECT_LOCK (demux);
1158   if (demux->index)
1159     gst_object_unref (demux->index);
1160   demux->index = gst_object_ref (index);
1161   GST_OBJECT_UNLOCK (demux);
1162
1163   gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1164   demux->own_index = FALSE;
1165 }
1166
1167 static GstIndex *
1168 gst_flv_demux_get_index (GstElement * element)
1169 {
1170   GstIndex *result = NULL;
1171
1172   GstFLVDemux *demux = GST_FLV_DEMUX (element);
1173
1174   GST_OBJECT_LOCK (demux);
1175   if (demux->index)
1176     result = gst_object_ref (demux->index);
1177   GST_OBJECT_UNLOCK (demux);
1178
1179   return result;
1180 }
1181
1182 static void
1183 gst_flv_demux_dispose (GObject * object)
1184 {
1185   GstFLVDemux *demux = GST_FLV_DEMUX (object);
1186
1187   GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
1188
1189   if (demux->adapter) {
1190     gst_adapter_clear (demux->adapter);
1191     g_object_unref (demux->adapter);
1192     demux->adapter = NULL;
1193   }
1194
1195   if (demux->taglist) {
1196     gst_tag_list_free (demux->taglist);
1197     demux->taglist = NULL;
1198   }
1199
1200   if (demux->new_seg_event) {
1201     gst_event_unref (demux->new_seg_event);
1202     demux->new_seg_event = NULL;
1203   }
1204
1205   if (demux->close_seg_event) {
1206     gst_event_unref (demux->close_seg_event);
1207     demux->close_seg_event = NULL;
1208   }
1209
1210   if (demux->audio_codec_data) {
1211     gst_buffer_unref (demux->audio_codec_data);
1212     demux->audio_codec_data = NULL;
1213   }
1214
1215   if (demux->video_codec_data) {
1216     gst_buffer_unref (demux->video_codec_data);
1217     demux->video_codec_data = NULL;
1218   }
1219
1220   if (demux->audio_pad) {
1221     gst_object_unref (demux->audio_pad);
1222     demux->audio_pad = NULL;
1223   }
1224
1225   if (demux->video_pad) {
1226     gst_object_unref (demux->video_pad);
1227     demux->video_pad = NULL;
1228   }
1229
1230   if (demux->index) {
1231     gst_object_unref (demux->index);
1232     demux->index = NULL;
1233   }
1234
1235   if (demux->times) {
1236     g_array_free (demux->times, TRUE);
1237     demux->times = NULL;
1238   }
1239
1240   if (demux->filepositions) {
1241     g_array_free (demux->filepositions, TRUE);
1242     demux->filepositions = NULL;
1243   }
1244
1245   GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
1246 }
1247
1248 static void
1249 gst_flv_demux_base_init (gpointer g_class)
1250 {
1251   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
1252
1253   gst_element_class_add_pad_template (element_class,
1254       gst_static_pad_template_get (&flv_sink_template));
1255   gst_element_class_add_pad_template (element_class,
1256       gst_static_pad_template_get (&audio_src_template));
1257   gst_element_class_add_pad_template (element_class,
1258       gst_static_pad_template_get (&video_src_template));
1259   gst_element_class_set_details_simple (element_class, "FLV Demuxer",
1260       "Codec/Demuxer",
1261       "Demux FLV feeds into digital streams",
1262       "Julien Moutte <julien@moutte.net>");
1263 }
1264
1265 static void
1266 gst_flv_demux_class_init (GstFLVDemuxClass * klass)
1267 {
1268   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1269   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1270
1271   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_flv_demux_dispose);
1272
1273   gstelement_class->change_state =
1274       GST_DEBUG_FUNCPTR (gst_flv_demux_change_state);
1275   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_flv_demux_set_index);
1276   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_flv_demux_get_index);
1277 }
1278
1279 static void
1280 gst_flv_demux_init (GstFLVDemux * demux, GstFLVDemuxClass * g_class)
1281 {
1282   demux->sinkpad =
1283       gst_pad_new_from_static_template (&flv_sink_template, "sink");
1284
1285   gst_pad_set_event_function (demux->sinkpad,
1286       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_event));
1287   gst_pad_set_chain_function (demux->sinkpad,
1288       GST_DEBUG_FUNCPTR (gst_flv_demux_chain));
1289   gst_pad_set_activate_function (demux->sinkpad,
1290       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate));
1291   gst_pad_set_activatepull_function (demux->sinkpad,
1292       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_pull));
1293   gst_pad_set_activatepush_function (demux->sinkpad,
1294       GST_DEBUG_FUNCPTR (gst_flv_demux_sink_activate_push));
1295
1296   gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
1297
1298   demux->adapter = gst_adapter_new ();
1299   demux->taglist = gst_tag_list_new ();
1300   gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1301
1302   demux->own_index = FALSE;
1303
1304   gst_flv_demux_cleanup (demux);
1305 }
1306
1307 static gboolean
1308 plugin_init (GstPlugin * plugin)
1309 {
1310   GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
1311
1312   if (!gst_element_register (plugin, "flvdemux", GST_RANK_PRIMARY,
1313           gst_flv_demux_get_type ()) ||
1314       !gst_element_register (plugin, "flvmux", GST_RANK_PRIMARY,
1315           gst_flv_mux_get_type ()))
1316     return FALSE;
1317
1318   return TRUE;
1319 }
1320
1321 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
1322     "flv", "FLV muxing and demuxing plugin",
1323     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)