2 * Copyright (C) <2007> Julien Moutte <julien@moutte.net>
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.
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.
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.
21 * SECTION:element-flvdemux
23 * flvdemux demuxes an FLV file into the different contained streams.
26 * <title>Example launch line</title>
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.
37 #include "gstflvdemux.h"
38 #include "gstflvparse.h"
39 #include "gstflvmux.h"
43 static GstStaticPadTemplate flv_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
46 GST_STATIC_CAPS ("video/x-flv")
49 static GstStaticPadTemplate audio_src_template =
50 GST_STATIC_PAD_TEMPLATE ("audio",
55 static GstStaticPadTemplate video_src_template =
56 GST_STATIC_PAD_TEMPLATE ("video",
61 GST_DEBUG_CATEGORY (flvdemux_debug);
62 #define GST_CAT_DEFAULT flvdemux_debug
64 GST_BOILERPLATE (GstFLVDemux, gst_flv_demux, GstElement, GST_TYPE_ELEMENT);
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
72 gst_flv_demux_flush (GstFLVDemux * demux, gboolean discont)
74 GST_DEBUG_OBJECT (demux, "flushing queued data in the FLV demuxer");
76 gst_adapter_clear (demux->adapter);
78 demux->audio_need_discont = TRUE;
79 demux->video_need_discont = TRUE;
81 demux->flushing = FALSE;
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 */
93 gst_flv_demux_cleanup (GstFLVDemux * demux)
95 GST_DEBUG_OBJECT (demux, "cleaning up FLV demuxer");
97 demux->state = FLV_STATE_HEADER;
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;
106 /* By default we consider them as linked */
107 demux->audio_linked = TRUE;
108 demux->video_linked = TRUE;
110 demux->has_audio = FALSE;
111 demux->has_video = FALSE;
112 demux->push_tags = FALSE;
113 demux->got_par = FALSE;
115 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
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;
125 if (demux->new_seg_event) {
126 gst_event_unref (demux->new_seg_event);
127 demux->new_seg_event = NULL;
130 if (demux->close_seg_event) {
131 gst_event_unref (demux->close_seg_event);
132 demux->close_seg_event = NULL;
135 gst_adapter_clear (demux->adapter);
137 if (demux->audio_codec_data) {
138 gst_buffer_unref (demux->audio_codec_data);
139 demux->audio_codec_data = NULL;
142 if (demux->video_codec_data) {
143 gst_buffer_unref (demux->video_codec_data);
144 demux->video_codec_data = NULL;
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;
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;
160 g_array_free (demux->times, TRUE);
164 if (demux->filepositions) {
165 g_array_free (demux->filepositions, TRUE);
166 demux->filepositions = NULL;
171 gst_flv_demux_chain (GstPad * pad, GstBuffer * buffer)
173 GstFlowReturn ret = GST_FLOW_OK;
174 GstFLVDemux *demux = NULL;
176 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
178 GST_LOG_OBJECT (demux, "received buffer of %d bytes at offset %"
179 G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer), GST_BUFFER_OFFSET (buffer));
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;
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);
192 gst_adapter_push (demux->adapter, buffer);
195 if (G_UNLIKELY (ret != GST_FLOW_OK)) {
196 if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
197 || demux->video_linked)) {
200 GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
205 if (G_UNLIKELY (demux->flushing)) {
206 GST_DEBUG_OBJECT (demux, "we are now flushing, exiting parser loop");
207 ret = GST_FLOW_WRONG_STATE;
211 switch (demux->state) {
212 case FLV_STATE_HEADER:
214 if (gst_adapter_available (demux->adapter) >= FLV_HEADER_SIZE) {
217 buffer = gst_adapter_take_buffer (demux->adapter, FLV_HEADER_SIZE);
219 ret = gst_flv_parse_header (demux, buffer);
221 gst_buffer_unref (buffer);
222 demux->offset += FLV_HEADER_SIZE;
224 demux->state = FLV_STATE_TAG_TYPE;
230 case FLV_STATE_TAG_TYPE:
232 if (gst_adapter_available (demux->adapter) >= FLV_TAG_TYPE_SIZE) {
235 /* Remember the tag offset in bytes */
236 demux->cur_tag_offset = demux->offset;
238 buffer = gst_adapter_take_buffer (demux->adapter, FLV_TAG_TYPE_SIZE);
240 ret = gst_flv_parse_tag_type (demux, buffer);
242 gst_buffer_unref (buffer);
243 demux->offset += FLV_TAG_TYPE_SIZE;
250 case FLV_STATE_TAG_VIDEO:
252 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
255 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
257 ret = gst_flv_parse_tag_video (demux, buffer);
259 gst_buffer_unref (buffer);
260 demux->offset += demux->tag_size;
262 demux->state = FLV_STATE_TAG_TYPE;
268 case FLV_STATE_TAG_AUDIO:
270 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
273 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
275 ret = gst_flv_parse_tag_audio (demux, buffer);
277 gst_buffer_unref (buffer);
278 demux->offset += demux->tag_size;
280 demux->state = FLV_STATE_TAG_TYPE;
286 case FLV_STATE_TAG_SCRIPT:
288 if (gst_adapter_available (demux->adapter) >= demux->tag_size) {
291 buffer = gst_adapter_take_buffer (demux->adapter, demux->tag_size);
293 ret = gst_flv_parse_tag_script (demux, buffer);
295 gst_buffer_unref (buffer);
296 demux->offset += demux->tag_size;
298 demux->state = FLV_STATE_TAG_TYPE;
305 GST_DEBUG_OBJECT (demux, "unexpected demuxer state");
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) {
316 gst_object_unref (demux);
322 gst_flv_demux_pull_range (GstFLVDemux * demux, GstPad * pad, guint64 offset,
323 guint size, GstBuffer ** buffer)
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));
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;
350 gst_flv_demux_pull_tag (GstPad * pad, GstFLVDemux * demux)
352 GstBuffer *buffer = NULL;
353 GstFlowReturn ret = GST_FLOW_OK;
355 /* Store tag offset */
356 demux->cur_tag_offset = demux->offset;
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))
363 /* Identify tag type */
364 ret = gst_flv_parse_tag_type (demux, buffer);
366 gst_buffer_unref (buffer);
368 if (G_UNLIKELY (ret != GST_FLOW_OK))
371 /* Jump over tag type + size */
372 demux->offset += FLV_TAG_TYPE_SIZE;
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))
379 switch (demux->state) {
380 case FLV_STATE_TAG_VIDEO:
381 ret = gst_flv_parse_tag_video (demux, buffer);
383 case FLV_STATE_TAG_AUDIO:
384 ret = gst_flv_parse_tag_audio (demux, buffer);
386 case FLV_STATE_TAG_SCRIPT:
387 ret = gst_flv_parse_tag_script (demux, buffer);
390 GST_WARNING_OBJECT (demux, "unexpected state %d", demux->state);
393 gst_buffer_unref (buffer);
395 /* Jump over that part we've just parsed */
396 demux->offset += demux->tag_size;
398 /* Make sure we reinitialize the tag size */
401 /* Ready for the next tag */
402 demux->state = FLV_STATE_TAG_TYPE;
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) {
409 GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
410 "neither video nor audio are linked");
419 gst_flv_demux_pull_header (GstPad * pad, GstFLVDemux * demux)
421 GstBuffer *buffer = NULL;
422 GstFlowReturn ret = GST_FLOW_OK;
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))
429 ret = gst_flv_parse_header (demux, buffer);
431 gst_buffer_unref (buffer);
433 /* Jump over the header now */
434 demux->offset += FLV_HEADER_SIZE;
435 demux->state = FLV_STATE_TAG_TYPE;
442 gst_flv_demux_seek_to_prev_keyframe (GstFLVDemux * demux)
448 gst_flv_demux_push_src_event (GstFLVDemux * demux, GstEvent * event)
452 if (demux->audio_pad)
453 ret |= gst_pad_push_event (demux->audio_pad, gst_event_ref (event));
455 if (demux->video_pad)
456 ret |= gst_pad_push_event (demux->video_pad, gst_event_ref (event));
458 gst_event_unref (event);
464 gst_flv_demux_create_index (GstFLVDemux * demux)
467 GstFormat fmt = GST_FORMAT_BYTES;
473 if (!gst_pad_query_peer_duration (demux->sinkpad, &fmt, &size) ||
474 fmt != GST_FORMAT_BYTES)
477 old_offset = demux->offset;
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);
488 gst_buffer_unref (buffer);
489 demux->offset += tag_size;
492 demux->offset = old_offset;
496 gst_flv_demux_loop (GstPad * pad)
498 GstFLVDemux *demux = NULL;
499 GstFlowReturn ret = GST_FLOW_OK;
501 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
503 if (demux->segment.rate >= 0) {
505 switch (demux->state) {
506 case FLV_STATE_TAG_TYPE:
507 ret = gst_flv_demux_pull_tag (pad, demux);
510 ret = GST_FLOW_UNEXPECTED;
513 ret = gst_flv_demux_pull_header (pad, demux);
514 if (ret == GST_FLOW_OK)
515 gst_flv_demux_create_index (demux);
519 /* pause if something went wrong */
520 if (G_UNLIKELY (ret != GST_FLOW_OK))
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;
530 } else { /* Reverse playback */
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;
544 ret = gst_flv_demux_pull_header (pad, demux);
545 if (ret == GST_FLOW_OK)
546 gst_flv_demux_create_index (demux);
549 /* pause if something went wrong */
550 if (G_UNLIKELY (ret != GST_FLOW_OK))
553 /* check EOS condition */
554 if (demux->segment.last_stop <= demux->segment.start) {
555 ret = GST_FLOW_UNEXPECTED;
560 gst_object_unref (demux);
566 const gchar *reason = gst_flow_get_name (ret);
568 GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
569 gst_pad_pause_task (pad);
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) {
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;
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 "
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));
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");
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 ());
609 gst_object_unref (demux);
615 gst_flv_demux_find_offset (GstFLVDemux * demux, GstSegment * segment)
619 GstIndexEntry *entry;
621 g_return_val_if_fail (segment != NULL, 0);
623 time = segment->start;
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);
632 gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &bytes);
633 gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
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);
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;
645 segment->last_stop = time;
648 GST_DEBUG_OBJECT (demux, "no index entry found for %" GST_TIME_FORMAT,
649 GST_TIME_ARGS (segment->start));
657 gst_flv_demux_handle_seek_push (GstFLVDemux * demux, GstEvent * event)
661 GstSeekType start_type, stop_type;
664 gboolean update, flush, keyframe, ret;
665 GstSegment seeksegment;
667 gst_event_parse_seek (event, &rate, &format, &flags,
668 &start_type, &start, &stop_type, &stop);
670 if (format != GST_FORMAT_TIME)
673 flush = !!(flags & GST_SEEK_FLAG_FLUSH);
674 keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT);
676 /* Work on a copy until we are sure the seek succeeded. */
677 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
679 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
682 /* Apply the seek to our segment */
683 gst_segment_set_seek (&seeksegment, rate, format, flags,
684 start_type, start, stop_type, stop, &update);
686 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
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);
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");
703 /* Tell all the stream we moved to a different position (discont) */
704 demux->audio_need_discont = TRUE;
705 demux->video_need_discont = TRUE;
711 /* Ok seek succeeded, take the newly configured segment */
712 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
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;
723 gst_event_unref (event);
725 ret = gst_pad_push_event (demux->sinkpad, event);
733 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
734 return gst_pad_push_event (demux->sinkpad, event);
739 gst_flv_demux_handle_seek_pull (GstFLVDemux * demux, GstEvent * event)
743 GstSeekType start_type, stop_type;
746 gboolean update, flush, keyframe, ret;
747 GstSegment seeksegment;
749 gst_event_parse_seek (event, &rate, &format, &flags,
750 &start_type, &start, &stop_type, &stop);
752 gst_event_unref (event);
754 if (format != GST_FORMAT_TIME)
757 flush = !!(flags & GST_SEEK_FLAG_FLUSH);
758 keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT);
761 /* Flush start up and downstream to make sure data flow and loops are
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 ());
766 /* Pause the pulling task */
767 gst_pad_pause_task (demux->sinkpad);
770 /* Take the stream lock */
771 GST_PAD_STREAM_LOCK (demux->sinkpad);
774 /* Stop flushing upstream we need to pull */
775 gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop ());
778 /* Work on a copy until we are sure the seek succeeded. */
779 memcpy (&seeksegment, &demux->segment, sizeof (GstSegment));
781 GST_DEBUG_OBJECT (demux, "segment before configure %" GST_SEGMENT_FORMAT,
784 /* Apply the seek to our segment */
785 gst_segment_set_seek (&seeksegment, rate, format, flags,
786 start_type, start, stop_type, stop, &update);
788 GST_DEBUG_OBJECT (demux, "segment configured %" GST_SEGMENT_FORMAT,
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);
795 /* Tell all the stream we moved to a different position (discont) */
796 demux->audio_need_discont = TRUE;
797 demux->video_need_discont = TRUE;
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;
810 if (G_UNLIKELY (demux->close_seg_event)) {
811 gst_event_unref (demux->close_seg_event);
812 demux->close_seg_event = NULL;
816 /* Stop flushing, the sinks are at time 0 now */
817 gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop ());
819 GST_DEBUG_OBJECT (demux, "closing running segment %" GST_SEGMENT_FORMAT,
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);
831 if ((stop = demux->segment.stop) == -1)
832 stop = demux->segment.duration;
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);
842 /* Ok seek succeeded, take the newly configured segment */
843 memcpy (&demux->segment, &seeksegment, sizeof (GstSegment));
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));
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;
863 gst_pad_start_task (demux->sinkpad,
864 (GstTaskFunction) gst_flv_demux_loop, demux->sinkpad);
866 GST_PAD_STREAM_UNLOCK (demux->sinkpad);
873 GST_WARNING_OBJECT (demux, "we only support seeking in TIME format");
878 /* If we can pull that's prefered */
880 gst_flv_demux_sink_activate (GstPad * sinkpad)
882 if (gst_pad_check_pull_range (sinkpad)) {
883 return gst_pad_activate_pull (sinkpad, TRUE);
885 return gst_pad_activate_push (sinkpad, TRUE);
889 /* This function gets called when we activate ourselves in push mode.
890 * We cannot seek (ourselves) in the stream */
892 gst_flv_demux_sink_activate_push (GstPad * sinkpad, gboolean active)
896 demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
898 demux->random_access = FALSE;
900 gst_object_unref (demux);
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 */
909 gst_flv_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
913 demux = GST_FLV_DEMUX (gst_pad_get_parent (sinkpad));
916 demux->random_access = TRUE;
917 gst_object_unref (demux);
918 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
921 demux->random_access = FALSE;
922 gst_object_unref (demux);
923 return gst_pad_stop_task (sinkpad);
928 gst_flv_demux_sink_event (GstPad * pad, GstEvent * event)
931 gboolean ret = FALSE;
933 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
935 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
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);
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);
949 GST_DEBUG_OBJECT (demux, "received EOS");
951 GST_DEBUG_OBJECT (demux, "committing index");
952 gst_index_commit (demux->index, demux->index_id);
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");
959 case GST_EVENT_NEWSEGMENT:
963 gint64 start, stop, time;
966 GST_DEBUG_OBJECT (demux, "received new segment");
968 gst_event_parse_new_segment (event, &update, &rate, &format, &start,
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,
976 GST_DEBUG_OBJECT (demux, "NEWSEGMENT: %" GST_SEGMENT_FORMAT,
980 ret = gst_flv_demux_push_src_event (demux, event);
982 /* non-time format */
983 demux->audio_need_segment = TRUE;
984 demux->video_need_segment = TRUE;
986 gst_event_unref (event);
991 ret = gst_flv_demux_push_src_event (demux, event);
995 gst_object_unref (demux);
1001 gst_flv_demux_src_event (GstPad * pad, GstEvent * event)
1004 gboolean ret = FALSE;
1006 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
1008 GST_DEBUG_OBJECT (demux, "handling event %s", GST_EVENT_TYPE_NAME (event));
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);
1015 ret = gst_flv_demux_handle_seek_push (demux, event);
1019 ret = gst_pad_push_event (demux->sinkpad, event);
1023 gst_object_unref (demux);
1029 gst_flv_demux_query (GstPad * pad, GstQuery * query)
1031 gboolean res = TRUE;
1034 demux = GST_FLV_DEMUX (gst_pad_get_parent (pad));
1036 switch (GST_QUERY_TYPE (query)) {
1037 case GST_QUERY_DURATION:
1041 gst_query_parse_duration (query, &format, NULL);
1043 /* duration is time only */
1044 if (format != GST_FORMAT_TIME) {
1045 GST_DEBUG_OBJECT (demux, "duration query only supported for time "
1051 GST_DEBUG_OBJECT (pad, "duration query, replying %" GST_TIME_FORMAT,
1052 GST_TIME_ARGS (demux->duration));
1054 gst_query_set_duration (query, GST_FORMAT_TIME, demux->duration);
1058 case GST_QUERY_POSITION:
1062 gst_query_parse_position (query, &format, NULL);
1064 /* position is time only */
1065 if (format != GST_FORMAT_TIME) {
1066 GST_DEBUG_OBJECT (demux, "position query only supported for time "
1072 GST_DEBUG_OBJECT (pad, "position query, replying %" GST_TIME_FORMAT,
1073 GST_TIME_ARGS (demux->segment.last_stop));
1075 gst_query_set_duration (query, GST_FORMAT_TIME, demux->segment.last_stop);
1080 case GST_QUERY_LATENCY:
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);
1090 /* no peer, we don't know */
1098 gst_object_unref (demux);
1103 static GstStateChangeReturn
1104 gst_flv_demux_change_state (GstElement * element, GstStateChange transition)
1107 GstStateChangeReturn ret;
1109 demux = GST_FLV_DEMUX (element);
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;
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");
1125 demux->index = gst_index_factory_make ("memindex");
1127 gst_index_get_writer_id (demux->index, GST_OBJECT (demux),
1129 demux->own_index = TRUE;
1131 gst_flv_demux_cleanup (demux);
1137 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1138 if (ret == GST_STATE_CHANGE_FAILURE)
1141 switch (transition) {
1142 case GST_STATE_CHANGE_PAUSED_TO_READY:
1143 gst_flv_demux_cleanup (demux);
1153 gst_flv_demux_set_index (GstElement * element, GstIndex * index)
1155 GstFLVDemux *demux = GST_FLV_DEMUX (element);
1157 GST_OBJECT_LOCK (demux);
1159 gst_object_unref (demux->index);
1160 demux->index = gst_object_ref (index);
1161 GST_OBJECT_UNLOCK (demux);
1163 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
1164 demux->own_index = FALSE;
1168 gst_flv_demux_get_index (GstElement * element)
1170 GstIndex *result = NULL;
1172 GstFLVDemux *demux = GST_FLV_DEMUX (element);
1174 GST_OBJECT_LOCK (demux);
1176 result = gst_object_ref (demux->index);
1177 GST_OBJECT_UNLOCK (demux);
1183 gst_flv_demux_dispose (GObject * object)
1185 GstFLVDemux *demux = GST_FLV_DEMUX (object);
1187 GST_DEBUG_OBJECT (demux, "disposing FLV demuxer");
1189 if (demux->adapter) {
1190 gst_adapter_clear (demux->adapter);
1191 g_object_unref (demux->adapter);
1192 demux->adapter = NULL;
1195 if (demux->taglist) {
1196 gst_tag_list_free (demux->taglist);
1197 demux->taglist = NULL;
1200 if (demux->new_seg_event) {
1201 gst_event_unref (demux->new_seg_event);
1202 demux->new_seg_event = NULL;
1205 if (demux->close_seg_event) {
1206 gst_event_unref (demux->close_seg_event);
1207 demux->close_seg_event = NULL;
1210 if (demux->audio_codec_data) {
1211 gst_buffer_unref (demux->audio_codec_data);
1212 demux->audio_codec_data = NULL;
1215 if (demux->video_codec_data) {
1216 gst_buffer_unref (demux->video_codec_data);
1217 demux->video_codec_data = NULL;
1220 if (demux->audio_pad) {
1221 gst_object_unref (demux->audio_pad);
1222 demux->audio_pad = NULL;
1225 if (demux->video_pad) {
1226 gst_object_unref (demux->video_pad);
1227 demux->video_pad = NULL;
1231 gst_object_unref (demux->index);
1232 demux->index = NULL;
1236 g_array_free (demux->times, TRUE);
1237 demux->times = NULL;
1240 if (demux->filepositions) {
1241 g_array_free (demux->filepositions, TRUE);
1242 demux->filepositions = NULL;
1245 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
1249 gst_flv_demux_base_init (gpointer g_class)
1251 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
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",
1261 "Demux FLV feeds into digital streams",
1262 "Julien Moutte <julien@moutte.net>");
1266 gst_flv_demux_class_init (GstFLVDemuxClass * klass)
1268 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
1269 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1271 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_flv_demux_dispose);
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);
1280 gst_flv_demux_init (GstFLVDemux * demux, GstFLVDemuxClass * g_class)
1283 gst_pad_new_from_static_template (&flv_sink_template, "sink");
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));
1296 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
1298 demux->adapter = gst_adapter_new ();
1299 demux->taglist = gst_tag_list_new ();
1300 gst_segment_init (&demux->segment, GST_FORMAT_TIME);
1302 demux->own_index = FALSE;
1304 gst_flv_demux_cleanup (demux);
1308 plugin_init (GstPlugin * plugin)
1310 GST_DEBUG_CATEGORY_INIT (flvdemux_debug, "flvdemux", 0, "FLV demuxer");
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 ()))
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)