20 */ |
20 */ |
21 |
21 |
22 /** |
22 /** |
23 * SECTION:element-wavparse |
23 * SECTION:element-wavparse |
24 * |
24 * |
|
25 * Parse a .wav file into raw or compressed audio. |
|
26 * |
|
27 * Wavparse supports both push and pull mode operations, making it possible to |
|
28 * stream from a network source. |
|
29 * |
25 * <refsect2> |
30 * <refsect2> |
26 * <para> |
|
27 * Parse a .wav file into raw or compressed audio. |
|
28 * </para> |
|
29 * <para> |
|
30 * This element currently only supports pull based scheduling. |
|
31 * </para> |
|
32 * <title>Example launch line</title> |
31 * <title>Example launch line</title> |
33 * <para> |
32 * |[ |
34 * <programlisting> |
|
35 * gst-launch filesrc location=sine.wav ! wavparse ! audioconvert ! alsasink |
33 * gst-launch filesrc location=sine.wav ! wavparse ! audioconvert ! alsasink |
36 * </programlisting> |
34 * ]| Read a wav file and output to the soundcard using the ALSA element. The |
37 * Read a wav file and output to the soundcard using the ALSA element. The |
|
38 * wav file is assumed to contain raw uncompressed samples. |
35 * wav file is assumed to contain raw uncompressed samples. |
39 * </para> |
36 * |[ |
40 * <para> |
|
41 * <programlisting> |
|
42 * gst-launch gnomevfssrc location=http://www.example.org/sine.wav ! queue ! wavparse ! audioconvert ! alsasink |
37 * gst-launch gnomevfssrc location=http://www.example.org/sine.wav ! queue ! wavparse ! audioconvert ! alsasink |
43 * </programlisting> |
38 * ]| Stream data from a network url. |
44 * Stream data from |
|
45 * </para> |
|
46 * </refsect2> |
39 * </refsect2> |
47 * |
40 * |
48 * Last reviewed on 2006-03-03 (0.10.3) |
41 * Last reviewed on 2007-02-14 (0.10.6) |
|
42 */ |
|
43 |
|
44 /* |
|
45 * TODO: |
|
46 * http://replaygain.hydrogenaudio.org/file_format_wav.html |
49 */ |
47 */ |
50 |
48 |
51 #ifdef HAVE_CONFIG_H |
49 #ifdef HAVE_CONFIG_H |
52 #include "config.h" |
50 #include "config.h" |
53 #endif |
51 #endif |
54 |
52 #include <string.h> |
55 #include "string.h" |
53 #include <math.h> |
|
54 |
56 #include "gstwavparse.h" |
55 #include "gstwavparse.h" |
57 #include <gst/riff/riff-ids.h> |
56 #include "gst/riff/riff-ids.h" |
58 #include <gst/riff/riff-media.h> |
57 #include "gst/riff/riff-media.h" |
59 #include <gst/riff/riff-read.h> |
|
60 |
|
61 #ifndef __SYMBIAN32__ |
|
62 #include <gst/gst-i18n-plugin.h> |
58 #include <gst/gst-i18n-plugin.h> |
63 #else |
|
64 #include "gst/gst-i18n-plugin.h" |
|
65 #endif |
|
66 |
|
67 #ifdef __SYMBIAN32__ |
|
68 #include <gst/gstinfo.h> |
|
69 #endif |
|
70 |
|
71 #ifndef G_MAXUINT32 |
|
72 #define G_MAXUINT32 0xffffffff |
|
73 #endif |
|
74 |
59 |
75 GST_DEBUG_CATEGORY_STATIC (wavparse_debug); |
60 GST_DEBUG_CATEGORY_STATIC (wavparse_debug); |
76 #define GST_CAT_DEFAULT (wavparse_debug) |
61 #define GST_CAT_DEFAULT (wavparse_debug) |
77 |
62 |
78 static void gst_wavparse_base_init (gpointer g_class); |
|
79 static void gst_wavparse_class_init (GstWavParseClass * klass); |
|
80 static void gst_wavparse_init (GstWavParse * wavparse); |
|
81 static void gst_wavparse_dispose (GObject * object); |
63 static void gst_wavparse_dispose (GObject * object); |
82 |
64 |
83 static gboolean gst_wavparse_sink_activate (GstPad * sinkpad); |
65 static gboolean gst_wavparse_sink_activate (GstPad * sinkpad); |
84 static gboolean gst_wavparse_sink_activate_pull (GstPad * sinkpad, |
66 static gboolean gst_wavparse_sink_activate_pull (GstPad * sinkpad, |
85 gboolean active); |
67 gboolean active); |
86 static gboolean gst_wavparse_send_event (GstElement * element, |
68 static gboolean gst_wavparse_send_event (GstElement * element, |
87 GstEvent * event); |
69 GstEvent * event); |
88 static GstFlowReturn gst_wavparse_chain (GstPad * pad, GstBuffer * buf); |
|
89 static GstStateChangeReturn gst_wavparse_change_state (GstElement * element, |
70 static GstStateChangeReturn gst_wavparse_change_state (GstElement * element, |
90 GstStateChange transition); |
71 GstStateChange transition); |
91 |
72 |
|
73 static const GstQueryType *gst_wavparse_get_query_types (GstPad * pad); |
92 static gboolean gst_wavparse_pad_query (GstPad * pad, GstQuery * query); |
74 static gboolean gst_wavparse_pad_query (GstPad * pad, GstQuery * query); |
93 static const GstQueryType *gst_wavparse_get_query_types (GstPad * pad); |
|
94 static gboolean gst_wavparse_pad_convert (GstPad * pad, |
75 static gboolean gst_wavparse_pad_convert (GstPad * pad, |
95 GstFormat src_format, |
76 GstFormat src_format, |
96 gint64 src_value, GstFormat * dest_format, gint64 * dest_value); |
77 gint64 src_value, GstFormat * dest_format, gint64 * dest_value); |
97 |
78 |
|
79 static GstFlowReturn gst_wavparse_chain (GstPad * pad, GstBuffer * buf); |
|
80 static gboolean gst_wavparse_sink_event (GstPad * pad, GstEvent * event); |
98 static void gst_wavparse_loop (GstPad * pad); |
81 static void gst_wavparse_loop (GstPad * pad); |
99 static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event); |
82 static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event); |
100 static void gst_wavparse_get_property (GObject * object, guint prop_id, |
|
101 GValue * value, GParamSpec * pspec); |
|
102 |
83 |
103 static const GstElementDetails gst_wavparse_details = |
84 static const GstElementDetails gst_wavparse_details = |
104 GST_ELEMENT_DETAILS ("WAV audio demuxer", |
85 GST_ELEMENT_DETAILS ("WAV audio demuxer", |
105 "Codec/Demuxer/Audio", |
86 "Codec/Demuxer/Audio", |
106 "Parse a .wav file into raw audio", |
87 "Parse a .wav file into raw audio", |
107 "Erik Walthinsen <omega@cse.ogi.edu>"); |
88 "Erik Walthinsen <omega@cse.ogi.edu>"); |
108 |
89 |
109 static GstStaticPadTemplate sink_template_factory = |
90 static GstStaticPadTemplate sink_template_factory = |
110 //GST_STATIC_PAD_TEMPLATE ("wavparse_sink", |
91 GST_STATIC_PAD_TEMPLATE ("wavparse_sink", |
111 GST_STATIC_PAD_TEMPLATE ("sink", |
|
112 GST_PAD_SINK, |
92 GST_PAD_SINK, |
113 GST_PAD_ALWAYS, |
93 GST_PAD_ALWAYS, |
114 GST_STATIC_CAPS ("audio/x-wav") |
94 GST_STATIC_CAPS ("audio/x-wav") |
115 ); |
95 ); |
116 |
96 |
117 /* the pad is marked a sometimes and is added to the element when the |
97 #define DEBUG_INIT(bla) \ |
118 * exact type is known. This makes it much easier for a static autoplugger |
98 GST_DEBUG_CATEGORY_INIT (wavparse_debug, "wavparse", 0, "WAV parser"); |
119 * to connect the right decoder when needed. |
99 |
120 */ |
100 GST_BOILERPLATE_FULL (GstWavParse, gst_wavparse, GstElement, |
121 static GstStaticPadTemplate src_template_factory = |
101 GST_TYPE_ELEMENT, DEBUG_INIT); |
122 // GST_STATIC_PAD_TEMPLATE ("wavparse_src", |
|
123 GST_STATIC_PAD_TEMPLATE ("src", |
|
124 GST_PAD_SRC, |
|
125 GST_PAD_SOMETIMES, |
|
126 GST_STATIC_CAPS ("audio/x-raw-int, " |
|
127 "endianness = (int) little_endian, " |
|
128 "signed = (boolean) { true, false }, " |
|
129 "width = (int) { 8, 16, 24, 32 }, " |
|
130 "depth = (int) { 8, 16, 24, 32 }, " |
|
131 "rate = (int) [ 8000, 96000 ], " |
|
132 "channels = (int) [ 1, 8 ]; " |
|
133 "audio/mpeg, " |
|
134 "mpegversion = (int) 1, " |
|
135 "layer = (int) [ 1, 3 ], " |
|
136 "rate = (int) [ 8000, 48000 ], " |
|
137 "channels = (int) [ 1, 2 ]; " |
|
138 "audio/x-alaw, " |
|
139 "rate = (int) [ 8000, 48000 ], " |
|
140 "channels = (int) [ 1, 2 ]; " |
|
141 "audio/x-mulaw, " |
|
142 "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ];" |
|
143 "audio/x-adpcm, " |
|
144 "layout = (string) microsoft, " |
|
145 "block_align = (int) [ 1, 8192 ], " |
|
146 "rate = (int) [ 8000, 48000 ], " |
|
147 "channels = (int) [ 1, 2 ]; " |
|
148 "audio/x-adpcm, " |
|
149 "layout = (string) dvi, " |
|
150 "block_align = (int) [ 1, 8192 ], " |
|
151 "rate = (int) [ 8000, 48000 ], " "channels = (int) [ 1, 2 ];" |
|
152 "audio/x-vnd.sony.atrac3;" |
|
153 "audio/x-dts;" "audio/x-wma, " "wmaversion = (int) [ 1, 2 ]") |
|
154 ); |
|
155 |
|
156 |
|
157 static GstElementClass *parent_class = NULL; |
|
158 |
|
159 GType |
|
160 gst_wavparse_get_type (void) |
|
161 { |
|
162 static GType wavparse_type = 0; |
|
163 |
|
164 if (!wavparse_type) { |
|
165 static const GTypeInfo wavparse_info = { |
|
166 sizeof (GstWavParseClass), |
|
167 gst_wavparse_base_init, |
|
168 NULL, |
|
169 (GClassInitFunc) gst_wavparse_class_init, |
|
170 NULL, |
|
171 NULL, |
|
172 sizeof (GstWavParse), |
|
173 0, |
|
174 (GInstanceInitFunc) gst_wavparse_init, |
|
175 }; |
|
176 |
|
177 wavparse_type = |
|
178 g_type_register_static (GST_TYPE_ELEMENT, "GstWavParse", |
|
179 &wavparse_info, 0); |
|
180 } |
|
181 return wavparse_type; |
|
182 } |
|
183 |
|
184 |
102 |
185 static void |
103 static void |
186 gst_wavparse_base_init (gpointer g_class) |
104 gst_wavparse_base_init (gpointer g_class) |
187 { |
105 { |
188 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); |
106 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); |
189 |
107 GstPadTemplate *src_template; |
190 /* register src pads */ |
108 |
|
109 /* register pads */ |
191 gst_element_class_add_pad_template (element_class, |
110 gst_element_class_add_pad_template (element_class, |
192 gst_static_pad_template_get (&sink_template_factory)); |
111 gst_static_pad_template_get (&sink_template_factory)); |
193 gst_element_class_add_pad_template (element_class, |
112 |
194 gst_static_pad_template_get (&src_template_factory)); |
113 src_template = gst_pad_template_new ("wavparse_src", GST_PAD_SRC, |
|
114 GST_PAD_SOMETIMES, gst_riff_create_audio_template_caps ()); |
|
115 gst_element_class_add_pad_template (element_class, src_template); |
|
116 gst_object_unref (src_template); |
|
117 |
195 gst_element_class_set_details (element_class, &gst_wavparse_details); |
118 gst_element_class_set_details (element_class, &gst_wavparse_details); |
196 } |
119 } |
197 |
120 |
198 static void |
121 static void |
199 gst_wavparse_class_init (GstWavParseClass * klass) |
122 gst_wavparse_class_init (GstWavParseClass * klass) |
579 gst_wavparse_fmt (GstWavParse * wav) |
519 gst_wavparse_fmt (GstWavParse * wav) |
580 { |
520 { |
581 gst_riff_strf_auds *header = NULL; |
521 gst_riff_strf_auds *header = NULL; |
582 GstCaps *caps; |
522 GstCaps *caps; |
583 |
523 |
584 if (!gst_riff_read_strf_auds (wav, &header)) { |
524 if (!gst_riff_read_strf_auds (wav, &header)) |
585 g_warning ("Not fmt"); |
525 goto no_fmt; |
586 return FALSE; |
|
587 } |
|
588 |
526 |
589 wav->format = header->format; |
527 wav->format = header->format; |
590 wav->rate = header->rate; |
528 wav->rate = header->rate; |
591 wav->channels = header->channels; |
529 wav->channels = header->channels; |
592 if (wav->channels == 0) { |
530 if (wav->channels == 0) |
|
531 goto no_channels; |
|
532 |
|
533 wav->blockalign = header->blockalign; |
|
534 wav->width = (header->blockalign * 8) / header->channels; |
|
535 wav->depth = header->size; |
|
536 wav->bps = header->av_bps; |
|
537 if (wav->bps <= 0) |
|
538 goto no_bps; |
|
539 |
|
540 /* Note: gst_riff_create_audio_caps might need to fix values in |
|
541 * the header header depending on the format, so call it first */ |
|
542 caps = gst_riff_create_audio_caps (header->format, NULL, header, NULL); |
|
543 g_free (header); |
|
544 |
|
545 if (caps == NULL) |
|
546 goto no_caps; |
|
547 |
|
548 gst_wavparse_create_sourcepad (wav); |
|
549 gst_pad_use_fixed_caps (wav->srcpad); |
|
550 gst_pad_set_active (wav->srcpad, TRUE); |
|
551 gst_pad_set_caps (wav->srcpad, caps); |
|
552 gst_caps_free (caps); |
|
553 gst_element_add_pad (GST_ELEMENT_CAST (wav), wav->srcpad); |
|
554 gst_element_no_more_pads (GST_ELEMENT_CAST (wav)); |
|
555 |
|
556 GST_DEBUG ("frequency %d, channels %d", wav->rate, wav->channels); |
|
557 |
|
558 return TRUE; |
|
559 |
|
560 /* ERRORS */ |
|
561 no_fmt: |
|
562 { |
|
563 GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL), |
|
564 ("No FMT tag found")); |
|
565 return FALSE; |
|
566 } |
|
567 no_channels: |
|
568 { |
593 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), |
569 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), |
594 ("Stream claims to contain zero channels - invalid data")); |
570 ("Stream claims to contain zero channels - invalid data")); |
595 g_free (header); |
571 g_free (header); |
596 return FALSE; |
572 return FALSE; |
597 } |
573 } |
598 wav->blockalign = header->blockalign; |
574 no_bps: |
599 wav->width = (header->blockalign * 8) / header->channels; |
575 { |
600 wav->depth = header->size; |
|
601 wav->bps = header->av_bps; |
|
602 if (wav->bps <= 0) { |
|
603 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), |
576 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), |
604 ("Stream claims to bitrate of <= zero - invalid data")); |
577 ("Stream claims to bitrate of <= zero - invalid data")); |
605 g_free (header); |
578 g_free (header); |
606 return FALSE; |
579 return FALSE; |
607 } |
580 } |
608 |
581 no_caps: |
609 /* Note: gst_riff_create_audio_caps might nedd to fix values in |
582 { |
610 * the header header depending on the format, so call it first */ |
|
611 caps = gst_riff_create_audio_caps (header->format, NULL, header, NULL); |
|
612 |
|
613 g_free (header); |
|
614 |
|
615 if (caps) { |
|
616 gst_wavparse_create_sourcepad (wav); |
|
617 gst_pad_use_fixed_caps (wav->srcpad); |
|
618 gst_pad_set_active (wav->srcpad, TRUE); |
|
619 gst_pad_set_caps (wav->srcpad, caps); |
|
620 gst_caps_free (caps); |
|
621 gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad); |
|
622 gst_element_no_more_pads (GST_ELEMENT (wav)); |
|
623 GST_DEBUG ("frequency %d, channels %d", wav->rate, wav->channels); |
|
624 } else { |
|
625 GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL), (NULL)); |
583 GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL), (NULL)); |
626 return FALSE; |
584 return FALSE; |
627 } |
585 } |
628 |
|
629 return TRUE; |
|
630 } |
586 } |
631 |
587 |
632 static gboolean |
588 static gboolean |
633 gst_wavparse_other (GstWavParse * wav) |
589 gst_wavparse_other (GstWavParse * wav) |
634 { |
590 { |
789 static gboolean |
767 static gboolean |
790 gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event) |
768 gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event) |
791 { |
769 { |
792 gboolean res; |
770 gboolean res; |
793 gdouble rate; |
771 gdouble rate; |
794 GstEvent *newsegment; |
772 GstFormat format, bformat; |
795 GstFormat format; |
|
796 GstSeekFlags flags; |
773 GstSeekFlags flags; |
797 GstSeekType cur_type, stop_type; |
774 GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type; |
798 gint64 cur, stop; |
775 gint64 cur, stop, upstream_size; |
799 gboolean flush; |
776 gboolean flush; |
800 gboolean update; |
777 gboolean update; |
801 GstSegment seeksegment; |
778 GstSegment seeksegment = { 0, }; |
|
779 gint64 last_stop; |
802 |
780 |
803 if (event) { |
781 if (event) { |
804 GST_DEBUG_OBJECT (wav, "doing seek with event"); |
782 GST_DEBUG_OBJECT (wav, "doing seek with event"); |
805 |
783 |
806 gst_event_parse_seek (event, &rate, &format, &flags, |
784 gst_event_parse_seek (event, &rate, &format, &flags, |
807 &cur_type, &cur, &stop_type, &stop); |
785 &cur_type, &cur, &stop_type, &stop); |
808 |
786 |
809 /* we have to have a format as the segment format. Try to convert |
787 /* no negative rates yet */ |
810 * if not. */ |
788 if (rate < 0.0) |
811 if (format != GST_FORMAT_TIME) { |
789 goto negative_rate; |
812 GstFormat fmt; |
790 |
813 |
791 if (format != wav->segment.format) { |
814 fmt = GST_FORMAT_TIME; |
792 GST_INFO_OBJECT (wav, "converting seek-event from %s to %s", |
|
793 gst_format_get_name (format), |
|
794 gst_format_get_name (wav->segment.format)); |
815 res = TRUE; |
795 res = TRUE; |
816 if (cur_type != GST_SEEK_TYPE_NONE) |
796 if (cur_type != GST_SEEK_TYPE_NONE) |
817 res = gst_pad_query_convert (wav->srcpad, format, cur, &fmt, &cur); |
797 res = |
|
798 gst_pad_query_convert (wav->srcpad, format, cur, |
|
799 &wav->segment.format, &cur); |
818 if (res && stop_type != GST_SEEK_TYPE_NONE) |
800 if (res && stop_type != GST_SEEK_TYPE_NONE) |
819 res = gst_pad_query_convert (wav->srcpad, format, stop, &fmt, &stop); |
801 res = |
|
802 gst_pad_query_convert (wav->srcpad, format, stop, |
|
803 &wav->segment.format, &stop); |
820 if (!res) |
804 if (!res) |
821 goto no_format; |
805 goto no_format; |
822 |
806 |
823 format = fmt; |
807 format = wav->segment.format; |
824 } |
808 } |
825 } else { |
809 } else { |
826 GST_DEBUG_OBJECT (wav, "doing seek without event"); |
810 GST_DEBUG_OBJECT (wav, "doing seek without event"); |
827 flags = 0; |
811 flags = 0; |
828 } |
812 rate = 1.0; |
829 |
813 cur_type = GST_SEEK_TYPE_SET; |
|
814 stop_type = GST_SEEK_TYPE_SET; |
|
815 } |
|
816 |
|
817 /* in push mode, we must delegate to upstream */ |
|
818 if (wav->streaming) { |
|
819 gboolean res = FALSE; |
|
820 |
|
821 /* if streaming not yet started; only prepare initial newsegment */ |
|
822 if (!event || wav->state != GST_WAVPARSE_DATA) { |
|
823 if (wav->start_segment) |
|
824 gst_event_unref (wav->start_segment); |
|
825 wav->start_segment = |
|
826 gst_event_new_new_segment (FALSE, wav->segment.rate, |
|
827 wav->segment.format, wav->segment.last_stop, wav->segment.duration, |
|
828 wav->segment.last_stop); |
|
829 res = TRUE; |
|
830 } else { |
|
831 /* convert seek positions to byte positions in data sections */ |
|
832 if (format == GST_FORMAT_TIME) { |
|
833 /* should not fail */ |
|
834 if (!gst_wavparse_time_to_bytepos (wav, cur, &cur)) |
|
835 goto no_position; |
|
836 if (!gst_wavparse_time_to_bytepos (wav, stop, &stop)) |
|
837 goto no_position; |
|
838 } |
|
839 /* mind sample boundary and header */ |
|
840 if (cur >= 0) { |
|
841 cur -= (cur % wav->bytes_per_sample); |
|
842 cur += wav->datastart; |
|
843 } |
|
844 if (stop >= 0) { |
|
845 stop -= (stop % wav->bytes_per_sample); |
|
846 stop += wav->datastart; |
|
847 } |
|
848 GST_DEBUG_OBJECT (wav, "Pushing BYTE seek rate %g, " |
|
849 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, |
|
850 stop); |
|
851 /* BYTE seek event */ |
|
852 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur, |
|
853 stop_type, stop); |
|
854 res = gst_pad_push_event (wav->sinkpad, event); |
|
855 } |
|
856 return res; |
|
857 } |
|
858 |
|
859 /* get flush flag */ |
830 flush = flags & GST_SEEK_FLAG_FLUSH; |
860 flush = flags & GST_SEEK_FLAG_FLUSH; |
831 |
861 |
832 if (flush && wav->srcpad) { |
862 /* now we need to make sure the streaming thread is stopped. We do this by |
833 GST_DEBUG_OBJECT (wav, "sending flush start"); |
863 * either sending a FLUSH_START event downstream which will cause the |
834 gst_pad_push_event (wav->srcpad, gst_event_new_flush_start ()); |
864 * streaming thread to stop with a WRONG_STATE. |
|
865 * For a non-flushing seek we simply pause the task, which will happen as soon |
|
866 * as it completes one iteration (and thus might block when the sink is |
|
867 * blocking in preroll). */ |
|
868 if (flush) { |
|
869 if (wav->srcpad) { |
|
870 GST_DEBUG_OBJECT (wav, "sending flush start"); |
|
871 gst_pad_push_event (wav->srcpad, gst_event_new_flush_start ()); |
|
872 } |
835 } else { |
873 } else { |
836 gst_pad_pause_task (wav->sinkpad); |
874 gst_pad_pause_task (wav->sinkpad); |
837 } |
875 } |
838 |
876 |
|
877 /* we should now be able to grab the streaming thread because we stopped it |
|
878 * with the above flush/pause code */ |
839 GST_PAD_STREAM_LOCK (wav->sinkpad); |
879 GST_PAD_STREAM_LOCK (wav->sinkpad); |
|
880 |
|
881 /* save current position */ |
|
882 last_stop = wav->segment.last_stop; |
|
883 |
|
884 GST_DEBUG_OBJECT (wav, "stopped streaming at %" G_GINT64_FORMAT, last_stop); |
840 |
885 |
841 /* copy segment, we need this because we still need the old |
886 /* copy segment, we need this because we still need the old |
842 * segment when we close the current segment. */ |
887 * segment when we close the current segment. */ |
843 memcpy (&seeksegment, &wav->segment, sizeof (GstSegment)); |
888 memcpy (&seeksegment, &wav->segment, sizeof (GstSegment)); |
844 |
889 |
|
890 /* configure the seek parameters in the seeksegment. We will then have the |
|
891 * right values in the segment to perform the seek */ |
845 if (event) { |
892 if (event) { |
846 GST_DEBUG_OBJECT (wav, "configuring seek"); |
893 GST_DEBUG_OBJECT (wav, "configuring seek"); |
847 gst_segment_set_seek (&seeksegment, rate, format, flags, |
894 gst_segment_set_seek (&seeksegment, rate, format, flags, |
848 cur_type, cur, stop_type, stop, &update); |
895 cur_type, cur, stop_type, stop, &update); |
849 } |
896 } |
850 |
897 |
|
898 /* figure out the last position we need to play. If it's configured (stop != |
|
899 * -1), use that, else we play until the total duration of the file */ |
851 if ((stop = seeksegment.stop) == -1) |
900 if ((stop = seeksegment.stop) == -1) |
852 stop = seeksegment.duration; |
901 stop = seeksegment.duration; |
853 |
902 |
854 if (cur_type != GST_SEEK_TYPE_NONE) { |
903 GST_DEBUG_OBJECT (wav, "cur_type =%d", cur_type); |
855 wav->offset = |
904 if ((cur_type != GST_SEEK_TYPE_NONE)) { |
856 gst_util_uint64_scale_int (seeksegment.last_stop, wav->bps, GST_SECOND); |
905 /* bring offset to bytes, if the bps is 0, we have the segment in BYTES and |
857 wav->offset -= wav->offset % wav->bytes_per_sample; |
906 * we can just copy the last_stop. If not, we use the bps to convert TIME to |
|
907 * bytes. */ |
|
908 if (!gst_wavparse_time_to_bytepos (wav, seeksegment.last_stop, |
|
909 (gint64 *) & wav->offset)) |
|
910 wav->offset = seeksegment.last_stop; |
|
911 GST_LOG_OBJECT (wav, "offset=%" G_GUINT64_FORMAT, wav->offset); |
|
912 wav->offset -= (wav->offset % wav->bytes_per_sample); |
|
913 GST_LOG_OBJECT (wav, "offset=%" G_GUINT64_FORMAT, wav->offset); |
858 wav->offset += wav->datastart; |
914 wav->offset += wav->datastart; |
859 } |
915 GST_LOG_OBJECT (wav, "offset=%" G_GUINT64_FORMAT, wav->offset); |
860 |
916 } else { |
861 if (stop != -1) { |
917 GST_LOG_OBJECT (wav, "continue from offset=%" G_GUINT64_FORMAT, |
862 wav->end_offset = gst_util_uint64_scale_int (stop, wav->bps, GST_SECOND); |
918 wav->offset); |
863 wav->end_offset += |
919 } |
864 wav->bytes_per_sample - (wav->end_offset % wav->bytes_per_sample); |
920 |
|
921 if (stop_type != GST_SEEK_TYPE_NONE) { |
|
922 if (!gst_wavparse_time_to_bytepos (wav, stop, (gint64 *) & wav->end_offset)) |
|
923 wav->end_offset = stop; |
|
924 GST_LOG_OBJECT (wav, "end_offset=%" G_GUINT64_FORMAT, wav->end_offset); |
|
925 wav->end_offset -= (wav->end_offset % wav->bytes_per_sample); |
|
926 GST_LOG_OBJECT (wav, "end_offset=%" G_GUINT64_FORMAT, wav->end_offset); |
865 wav->end_offset += wav->datastart; |
927 wav->end_offset += wav->datastart; |
|
928 GST_LOG_OBJECT (wav, "end_offset=%" G_GUINT64_FORMAT, wav->end_offset); |
866 } else { |
929 } else { |
867 wav->end_offset = wav->datasize + wav->datastart; |
930 GST_LOG_OBJECT (wav, "continue to end_offset=%" G_GUINT64_FORMAT, |
868 } |
931 wav->end_offset); |
|
932 } |
|
933 |
|
934 /* make sure filesize is not exceeded due to rounding errors or so, |
|
935 * same precaution as in _stream_headers */ |
|
936 bformat = GST_FORMAT_BYTES; |
|
937 if (gst_pad_query_peer_duration (wav->sinkpad, &bformat, &upstream_size)) |
|
938 wav->end_offset = MIN (wav->end_offset, upstream_size); |
|
939 |
|
940 /* this is the range of bytes we will use for playback */ |
869 wav->offset = MIN (wav->offset, wav->end_offset); |
941 wav->offset = MIN (wav->offset, wav->end_offset); |
870 wav->dataleft = wav->end_offset - wav->offset; |
942 wav->dataleft = wav->end_offset - wav->offset; |
871 |
943 |
872 GST_DEBUG_OBJECT (wav, |
944 GST_DEBUG_OBJECT (wav, |
873 "seek: offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT ", segment %" |
945 "seek: rate %lf, offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT |
874 GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, wav->offset, wav->end_offset, |
946 ", segment %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, rate, wav->offset, |
875 GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (stop)); |
947 wav->end_offset, GST_TIME_ARGS (seeksegment.start), GST_TIME_ARGS (stop)); |
876 |
948 |
877 /* prepare for streaming again */ |
949 /* prepare for streaming again */ |
878 if (wav->srcpad) { |
950 if (wav->srcpad) { |
879 if (flush) { |
951 if (flush) { |
|
952 /* if we sent a FLUSH_START, we now send a FLUSH_STOP */ |
880 GST_DEBUG_OBJECT (wav, "sending flush stop"); |
953 GST_DEBUG_OBJECT (wav, "sending flush stop"); |
881 gst_pad_push_event (wav->srcpad, gst_event_new_flush_stop ()); |
954 gst_pad_push_event (wav->srcpad, gst_event_new_flush_stop ()); |
882 } else if (wav->segment_running) { |
955 } else if (wav->segment_running) { |
883 /* we are running the current segment and doing a non-flushing seek, |
956 /* we are running the current segment and doing a non-flushing seek, |
884 * close the segment first based on the last_stop. */ |
957 * close the segment first based on the previous last_stop. */ |
885 GST_DEBUG_OBJECT (wav, "closing running segment %" G_GINT64_FORMAT |
958 GST_DEBUG_OBJECT (wav, "closing running segment %" G_GINT64_FORMAT |
886 " to %" G_GINT64_FORMAT, wav->segment.start, wav->segment.last_stop); |
959 " to %" G_GINT64_FORMAT, wav->segment.accum, wav->segment.last_stop); |
887 |
960 |
888 gst_pad_push_event (wav->srcpad, |
961 /* queue the segment for sending in the stream thread */ |
889 gst_event_new_new_segment (TRUE, |
962 if (wav->close_segment) |
890 wav->segment.rate, wav->segment.format, |
963 gst_event_unref (wav->close_segment); |
891 wav->segment.start, wav->segment.last_stop, wav->segment.time)); |
964 wav->close_segment = gst_event_new_new_segment (TRUE, |
892 } |
965 wav->segment.rate, wav->segment.format, |
893 } |
966 wav->segment.accum, wav->segment.last_stop, wav->segment.accum); |
894 |
967 |
|
968 /* keep track of our last_stop */ |
|
969 seeksegment.accum = wav->segment.last_stop; |
|
970 } |
|
971 } |
|
972 |
|
973 /* now we did the seek and can activate the new segment values */ |
895 memcpy (&wav->segment, &seeksegment, sizeof (GstSegment)); |
974 memcpy (&wav->segment, &seeksegment, sizeof (GstSegment)); |
896 |
975 |
|
976 /* if we're doing a segment seek, post a SEGMENT_START message */ |
897 if (wav->segment.flags & GST_SEEK_FLAG_SEGMENT) { |
977 if (wav->segment.flags & GST_SEEK_FLAG_SEGMENT) { |
898 gst_element_post_message (GST_ELEMENT (wav), |
978 gst_element_post_message (GST_ELEMENT_CAST (wav), |
899 gst_message_new_segment_start (GST_OBJECT (wav), |
979 gst_message_new_segment_start (GST_OBJECT_CAST (wav), |
900 wav->segment.format, wav->segment.last_stop)); |
980 wav->segment.format, wav->segment.last_stop)); |
901 } |
981 } |
902 |
982 |
903 /* now send the newsegment */ |
983 /* now create the newsegment */ |
904 GST_DEBUG_OBJECT (wav, "Sending newsegment from %" G_GINT64_FORMAT |
984 GST_DEBUG_OBJECT (wav, "Creating newsegment from %" G_GINT64_FORMAT |
905 " to %" G_GINT64_FORMAT, wav->segment.start, stop); |
985 " to %" G_GINT64_FORMAT, wav->segment.last_stop, stop); |
906 |
986 |
907 newsegment = |
987 /* store the newsegment event so it can be sent from the streaming thread. */ |
|
988 if (wav->start_segment) |
|
989 gst_event_unref (wav->start_segment); |
|
990 wav->start_segment = |
908 gst_event_new_new_segment (FALSE, wav->segment.rate, |
991 gst_event_new_new_segment (FALSE, wav->segment.rate, |
909 wav->segment.format, wav->segment.last_stop, stop, wav->segment.time); |
992 wav->segment.format, wav->segment.last_stop, stop, |
910 |
993 wav->segment.last_stop); |
911 if (wav->srcpad) { |
994 |
912 gst_pad_push_event (wav->srcpad, newsegment); |
995 /* mark discont if we are going to stream from another position. */ |
913 } else { |
996 if (last_stop != wav->segment.last_stop) { |
914 /* send later when we actually create the source pad */ |
997 GST_DEBUG_OBJECT (wav, "mark DISCONT, we did a seek to another position"); |
915 g_assert (wav->newsegment == NULL); |
998 wav->discont = TRUE; |
916 wav->newsegment = newsegment; |
999 } |
917 } |
1000 |
918 |
1001 /* and start the streaming task again */ |
919 wav->segment_running = TRUE; |
1002 wav->segment_running = TRUE; |
920 if (!wav->streaming) { |
1003 if (!wav->streaming) { |
921 gst_pad_start_task (wav->sinkpad, (GstTaskFunction) gst_wavparse_loop, |
1004 gst_pad_start_task (wav->sinkpad, (GstTaskFunction) gst_wavparse_loop, |
922 wav->sinkpad); |
1005 wav->sinkpad); |
923 } |
1006 } |
967 * @tag holder for tag |
1062 * @tag holder for tag |
968 * @size holder for tag size |
1063 * @size holder for tag size |
969 * |
1064 * |
970 * Peek enough data for one full chunk |
1065 * Peek enough data for one full chunk |
971 * |
1066 * |
972 * Returns: %TRUE when one chunk has been got |
1067 * Returns: %TRUE when the full chunk is available |
973 */ |
1068 */ |
974 static gboolean |
1069 static gboolean |
975 gst_wavparse_peek_chunk (GstWavParse * wav, guint32 * tag, guint32 * size) |
1070 gst_wavparse_peek_chunk (GstWavParse * wav, guint32 * tag, guint32 * size) |
976 { |
1071 { |
977 guint32 peek_size = 0; |
1072 guint32 peek_size = 0; |
978 |
1073 guint available; |
979 gst_wavparse_peek_chunk_info (wav, tag, size); |
1074 |
|
1075 if (!gst_wavparse_peek_chunk_info (wav, tag, size)) |
|
1076 return FALSE; |
|
1077 |
980 GST_DEBUG ("Need to peek chunk of %d bytes", *size); |
1078 GST_DEBUG ("Need to peek chunk of %d bytes", *size); |
981 peek_size = (*size + 1) & ~1; |
1079 peek_size = (*size + 1) & ~1; |
982 |
1080 |
983 if (gst_adapter_available (wav->adapter) >= (8 + peek_size)) { |
1081 available = gst_adapter_available (wav->adapter); |
|
1082 if (available >= (8 + peek_size)) { |
984 return TRUE; |
1083 return TRUE; |
985 } else { |
1084 } else { |
|
1085 GST_LOG ("but only %u bytes available now", available); |
986 return FALSE; |
1086 return FALSE; |
987 } |
1087 } |
988 } |
1088 } |
989 |
1089 |
|
1090 /* |
|
1091 * gst_wavparse_calculate_duration: |
|
1092 * @wav: wavparse object |
|
1093 * |
|
1094 * Calculate duration on demand and store in @wav. Prefer bps, but use fact as a |
|
1095 * fallback. |
|
1096 * |
|
1097 * Returns: %TRUE if duration is available. |
|
1098 */ |
990 static gboolean |
1099 static gboolean |
991 gst_wavparse_get_upstream_size (GstWavParse * wav, gint64 * len) |
1100 gst_wavparse_calculate_duration (GstWavParse * wav) |
992 { |
1101 { |
993 gboolean res = FALSE; |
1102 if (wav->duration > 0) |
994 GstFormat fmt = GST_FORMAT_BYTES; |
1103 return TRUE; |
995 GstPad *peer; |
1104 |
996 |
1105 if (wav->bps > 0) { |
997 if ((peer = gst_pad_get_peer (wav->sinkpad))) { |
1106 GST_INFO_OBJECT (wav, "Got datasize %" G_GUINT64_FORMAT, wav->datasize); |
998 res = gst_pad_query_duration (peer, &fmt, len); |
1107 wav->duration = |
999 gst_object_unref (peer); |
1108 uint64_ceiling_scale (wav->datasize, GST_SECOND, (guint64) wav->bps); |
1000 } |
1109 GST_INFO_OBJECT (wav, "Got duration (bps) %" GST_TIME_FORMAT, |
1001 |
1110 GST_TIME_ARGS (wav->duration)); |
1002 return res; |
1111 return TRUE; |
|
1112 } else if (wav->fact) { |
|
1113 wav->duration = uint64_ceiling_scale_int (GST_SECOND, wav->fact, wav->rate); |
|
1114 GST_INFO_OBJECT (wav, "Got duration (fact) %" GST_TIME_FORMAT, |
|
1115 GST_TIME_ARGS (wav->duration)); |
|
1116 return TRUE; |
|
1117 } |
|
1118 return FALSE; |
|
1119 } |
|
1120 |
|
1121 static void |
|
1122 gst_waveparse_ignore_chunk (GstWavParse * wav, GstBuffer * buf, guint32 tag, |
|
1123 guint32 size) |
|
1124 { |
|
1125 guint flush; |
|
1126 |
|
1127 if (wav->streaming) { |
|
1128 if (!gst_wavparse_peek_chunk (wav, &tag, &size)) |
|
1129 return; |
|
1130 } |
|
1131 GST_DEBUG_OBJECT (wav, "Ignoring tag %" GST_FOURCC_FORMAT, |
|
1132 GST_FOURCC_ARGS (tag)); |
|
1133 flush = 8 + ((size + 1) & ~1); |
|
1134 wav->offset += flush; |
|
1135 if (wav->streaming) { |
|
1136 gst_adapter_flush (wav->adapter, flush); |
|
1137 } else { |
|
1138 gst_buffer_unref (buf); |
|
1139 } |
1003 } |
1140 } |
1004 |
1141 |
1005 static GstFlowReturn |
1142 static GstFlowReturn |
1006 gst_wavparse_stream_headers (GstWavParse * wav) |
1143 gst_wavparse_stream_headers (GstWavParse * wav) |
1007 { |
1144 { |
1009 GstBuffer *buf; |
1146 GstBuffer *buf; |
1010 gst_riff_strf_auds *header = NULL; |
1147 gst_riff_strf_auds *header = NULL; |
1011 guint32 tag, size; |
1148 guint32 tag, size; |
1012 gboolean gotdata = FALSE; |
1149 gboolean gotdata = FALSE; |
1013 GstCaps *caps; |
1150 GstCaps *caps; |
1014 gint64 duration; |
|
1015 gchar *codec_name = NULL; |
1151 gchar *codec_name = NULL; |
1016 GstEvent **event_p; |
1152 GstEvent **event_p; |
1017 |
1153 GstFormat bformat; |
1018 |
1154 gint64 upstream_size = 0; |
1019 if (!wav->got_fmt) { |
1155 |
|
1156 /* search for "_fmt" chunk, which should be first */ |
|
1157 while (!wav->got_fmt) { |
1020 GstBuffer *extra; |
1158 GstBuffer *extra; |
1021 |
1159 |
1022 /* The header start with a 'fmt ' tag */ |
1160 /* The header starts with a 'fmt ' tag */ |
1023 |
|
1024 if (wav->streaming) { |
1161 if (wav->streaming) { |
1025 if (!gst_wavparse_peek_chunk (wav, &tag, &size)) |
1162 if (!gst_wavparse_peek_chunk (wav, &tag, &size)) |
1026 return GST_FLOW_OK; |
1163 return GST_FLOW_OK; |
1027 |
1164 |
1028 buf = gst_buffer_new (); |
|
1029 gst_buffer_ref (buf); |
|
1030 gst_adapter_flush (wav->adapter, 8); |
1165 gst_adapter_flush (wav->adapter, 8); |
1031 wav->offset += 8; |
1166 wav->offset += 8; |
1032 GST_BUFFER_DATA (buf) = (guint8 *) gst_adapter_peek (wav->adapter, size); |
1167 |
1033 GST_BUFFER_SIZE (buf) = size; |
1168 buf = gst_adapter_take_buffer (wav->adapter, size); |
1034 |
|
1035 } else { |
1169 } else { |
1036 if ((res = gst_riff_read_chunk (GST_ELEMENT (wav), wav->sinkpad, |
1170 if ((res = gst_riff_read_chunk (GST_ELEMENT_CAST (wav), wav->sinkpad, |
1037 &wav->offset, &tag, &buf)) != GST_FLOW_OK) |
1171 &wav->offset, &tag, &buf)) != GST_FLOW_OK) |
1038 return res; |
1172 return res; |
1039 } |
1173 } |
1040 |
1174 |
|
1175 if (tag == GST_RIFF_TAG_JUNK || tag == GST_RIFF_TAG_bext || |
|
1176 tag == GST_RIFF_TAG_BEXT || tag == GST_RIFF_TAG_LIST) { |
|
1177 GST_DEBUG_OBJECT (wav, "skipping %" GST_FOURCC_FORMAT " chunk", |
|
1178 GST_FOURCC_ARGS (tag)); |
|
1179 gst_buffer_unref (buf); |
|
1180 buf = NULL; |
|
1181 continue; |
|
1182 } |
|
1183 |
1041 if (tag != GST_RIFF_TAG_fmt) |
1184 if (tag != GST_RIFF_TAG_fmt) |
1042 goto invalid_wav; |
1185 goto invalid_wav; |
1043 |
1186 |
1044 if (!(gst_riff_parse_strf_auds (GST_ELEMENT (wav), buf, &header, &extra))) |
1187 if (!(gst_riff_parse_strf_auds (GST_ELEMENT_CAST (wav), buf, &header, |
|
1188 &extra))) |
1045 goto parse_header_error; |
1189 goto parse_header_error; |
1046 |
1190 |
1047 if (wav->streaming) { |
1191 buf = NULL; /* parse_strf_auds() took ownership of buffer */ |
1048 gst_adapter_flush (wav->adapter, size); |
1192 |
1049 wav->offset += size; |
1193 /* do sanity checks of header fields */ |
1050 GST_BUFFER_DATA (buf) = NULL; |
1194 if (header->channels == 0) |
1051 gst_buffer_unref (buf); |
1195 goto no_channels; |
1052 } |
1196 if (header->rate == 0) |
1053 |
1197 goto no_rate; |
1054 /* Note: gst_riff_create_audio_caps might nedd to fix values in |
1198 |
|
1199 GST_DEBUG_OBJECT (wav, "creating the caps"); |
|
1200 |
|
1201 /* Note: gst_riff_create_audio_caps might need to fix values in |
1055 * the header header depending on the format, so call it first */ |
1202 * the header header depending on the format, so call it first */ |
1056 caps = |
1203 caps = gst_riff_create_audio_caps (header->format, NULL, header, extra, |
1057 gst_riff_create_audio_caps (header->format, NULL, header, extra, |
|
1058 NULL, &codec_name); |
1204 NULL, &codec_name); |
1059 |
1205 |
1060 if (extra) |
1206 if (extra) |
1061 gst_buffer_unref (extra); |
1207 gst_buffer_unref (extra); |
1062 |
1208 |
|
1209 if (!caps) |
|
1210 goto unknown_format; |
|
1211 |
|
1212 /* do more sanity checks of header fields |
|
1213 * (these can be sanitized by gst_riff_create_audio_caps() |
|
1214 */ |
1063 wav->format = header->format; |
1215 wav->format = header->format; |
1064 wav->rate = header->rate; |
1216 wav->rate = header->rate; |
1065 wav->channels = header->channels; |
1217 wav->channels = header->channels; |
1066 |
|
1067 if (wav->channels == 0) |
|
1068 goto no_channels; |
|
1069 |
|
1070 wav->blockalign = header->blockalign; |
1218 wav->blockalign = header->blockalign; |
1071 wav->width = (header->blockalign * 8) / header->channels; |
|
1072 wav->depth = header->size; |
1219 wav->depth = header->size; |
1073 wav->bps = header->av_bps; |
1220 wav->av_bps = header->av_bps; |
1074 |
1221 wav->vbr = FALSE; |
1075 if (wav->bps <= 0) |
1222 |
1076 goto no_bitrate; |
1223 g_free (header); |
1077 |
1224 header = NULL; |
|
1225 |
|
1226 /* do format specific handling */ |
|
1227 switch (wav->format) { |
|
1228 case GST_RIFF_WAVE_FORMAT_MPEGL12: |
|
1229 case GST_RIFF_WAVE_FORMAT_MPEGL3: |
|
1230 { |
|
1231 /* Note: workaround for mp2/mp3 embedded in wav, that relies on the |
|
1232 * bitrate inside the mpeg stream */ |
|
1233 GST_INFO ("resetting bps from %d to 0 for mp2/3", wav->av_bps); |
|
1234 wav->bps = 0; |
|
1235 break; |
|
1236 } |
|
1237 case GST_RIFF_WAVE_FORMAT_PCM: |
|
1238 if (wav->blockalign > wav->channels * (guint) ceil (wav->depth / 8.0)) |
|
1239 goto invalid_blockalign; |
|
1240 /* fall through */ |
|
1241 default: |
|
1242 if (wav->av_bps > wav->blockalign * wav->rate) |
|
1243 goto invalid_bps; |
|
1244 /* use the configured bps */ |
|
1245 wav->bps = wav->av_bps; |
|
1246 break; |
|
1247 } |
|
1248 |
|
1249 wav->width = (wav->blockalign * 8) / wav->channels; |
1078 wav->bytes_per_sample = wav->channels * wav->width / 8; |
1250 wav->bytes_per_sample = wav->channels * wav->width / 8; |
|
1251 |
1079 if (wav->bytes_per_sample <= 0) |
1252 if (wav->bytes_per_sample <= 0) |
1080 goto no_bytes_per_sample; |
1253 goto no_bytes_per_sample; |
1081 |
|
1082 g_free (header); |
|
1083 |
|
1084 if (!caps) |
|
1085 goto unknown_format; |
|
1086 |
1254 |
1087 GST_DEBUG_OBJECT (wav, "blockalign = %u", (guint) wav->blockalign); |
1255 GST_DEBUG_OBJECT (wav, "blockalign = %u", (guint) wav->blockalign); |
1088 GST_DEBUG_OBJECT (wav, "width = %u", (guint) wav->width); |
1256 GST_DEBUG_OBJECT (wav, "width = %u", (guint) wav->width); |
1089 GST_DEBUG_OBJECT (wav, "depth = %u", (guint) wav->depth); |
1257 GST_DEBUG_OBJECT (wav, "depth = %u", (guint) wav->depth); |
|
1258 GST_DEBUG_OBJECT (wav, "av_bps = %u", (guint) wav->av_bps); |
|
1259 GST_DEBUG_OBJECT (wav, "frequency = %u", (guint) wav->rate); |
|
1260 GST_DEBUG_OBJECT (wav, "channels = %u", (guint) wav->channels); |
|
1261 GST_DEBUG_OBJECT (wav, "bytes_per_sample = %u", wav->bytes_per_sample); |
|
1262 |
|
1263 /* bps can be 0 when we don't have a valid bitrate (mostly for compressed |
|
1264 * formats). This will make the element output a BYTE format segment and |
|
1265 * will not timestamp the outgoing buffers. |
|
1266 */ |
1090 GST_DEBUG_OBJECT (wav, "bps = %u", (guint) wav->bps); |
1267 GST_DEBUG_OBJECT (wav, "bps = %u", (guint) wav->bps); |
|
1268 |
|
1269 GST_DEBUG_OBJECT (wav, "caps = %" GST_PTR_FORMAT, caps); |
1091 |
1270 |
1092 /* create pad later so we can sniff the first few bytes |
1271 /* create pad later so we can sniff the first few bytes |
1093 * of the real data and correct our caps if necessary */ |
1272 * of the real data and correct our caps if necessary */ |
1094 gst_caps_replace (&wav->caps, caps); |
1273 gst_caps_replace (&wav->caps, caps); |
1095 gst_caps_replace (&caps, NULL); |
1274 gst_caps_replace (&caps, NULL); |
1122 goto header_read_error; |
1303 goto header_read_error; |
1123 tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); |
1304 tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); |
1124 size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4); |
1305 size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4); |
1125 } |
1306 } |
1126 |
1307 |
1127 /* |
1308 GST_INFO_OBJECT (wav, |
1128 wav is a st00pid format, we don't know for sure where data starts. |
1309 "Got TAG: %" GST_FOURCC_FORMAT ", offset %" G_GUINT64_FORMAT, |
1129 So we have to go bit by bit until we find the 'data' header |
1310 GST_FOURCC_ARGS (tag), wav->offset); |
|
1311 |
|
1312 /* wav is a st00pid format, we don't know for sure where data starts. |
|
1313 * So we have to go bit by bit until we find the 'data' header |
1130 */ |
1314 */ |
1131 |
|
1132 switch (tag) { |
1315 switch (tag) { |
1133 /* TODO : Implement the various cases */ |
|
1134 case GST_RIFF_TAG_data:{ |
1316 case GST_RIFF_TAG_data:{ |
1135 gint64 upstream_size; |
|
1136 |
|
1137 GST_DEBUG_OBJECT (wav, "Got 'data' TAG, size : %d", size); |
1317 GST_DEBUG_OBJECT (wav, "Got 'data' TAG, size : %d", size); |
1138 gotdata = TRUE; |
|
1139 if (wav->streaming) { |
1318 if (wav->streaming) { |
1140 gst_adapter_flush (wav->adapter, 8); |
1319 gst_adapter_flush (wav->adapter, 8); |
|
1320 gotdata = TRUE; |
1141 } else { |
1321 } else { |
1142 gst_buffer_unref (buf); |
1322 gst_buffer_unref (buf); |
1143 } |
1323 } |
1144 wav->offset += 8; |
1324 wav->offset += 8; |
1145 wav->datastart = wav->offset; |
1325 wav->datastart = wav->offset; |
1146 /* file might be truncated */ |
1326 /* file might be truncated */ |
1147 if (gst_wavparse_get_upstream_size (wav, &upstream_size)) { |
1327 if (upstream_size) { |
1148 size = MIN (size, (upstream_size - wav->datastart)); |
1328 size = MIN (size, (upstream_size - wav->datastart)); |
1149 } |
1329 } |
1150 wav->datasize = size; |
1330 wav->datasize = (guint64) size; |
1151 wav->dataleft = size; |
1331 wav->dataleft = (guint64) size; |
1152 wav->end_offset = size + wav->datastart; |
1332 wav->end_offset = size + wav->datastart; |
|
1333 if (!wav->streaming) { |
|
1334 /* We will continue parsing tags 'till end */ |
|
1335 wav->offset += size; |
|
1336 } |
|
1337 GST_DEBUG_OBJECT (wav, "datasize = %d", size); |
1153 break; |
1338 break; |
1154 } |
1339 } |
1155 default: |
1340 case GST_RIFF_TAG_fact:{ |
|
1341 if (wav->format != GST_RIFF_WAVE_FORMAT_MPEGL12 && |
|
1342 wav->format != GST_RIFF_WAVE_FORMAT_MPEGL3) { |
|
1343 const guint data_size = 4; |
|
1344 |
|
1345 /* number of samples (for compressed formats) */ |
|
1346 if (wav->streaming) { |
|
1347 const guint8 *data = NULL; |
|
1348 |
|
1349 if (gst_adapter_available (wav->adapter) < 8 + data_size) { |
|
1350 return GST_FLOW_OK; |
|
1351 } |
|
1352 gst_adapter_flush (wav->adapter, 8); |
|
1353 data = gst_adapter_peek (wav->adapter, data_size); |
|
1354 wav->fact = GST_READ_UINT32_LE (data); |
|
1355 gst_adapter_flush (wav->adapter, data_size); |
|
1356 } else { |
|
1357 gst_buffer_unref (buf); |
|
1358 if ((res = |
|
1359 gst_pad_pull_range (wav->sinkpad, wav->offset + 8, |
|
1360 data_size, &buf)) != GST_FLOW_OK) |
|
1361 goto header_read_error; |
|
1362 wav->fact = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); |
|
1363 gst_buffer_unref (buf); |
|
1364 } |
|
1365 GST_DEBUG_OBJECT (wav, "have fact %u", wav->fact); |
|
1366 wav->offset += 8 + data_size; |
|
1367 break; |
|
1368 } else { |
|
1369 gst_waveparse_ignore_chunk (wav, buf, tag, size); |
|
1370 } |
|
1371 break; |
|
1372 } |
|
1373 case GST_RIFF_TAG_acid:{ |
|
1374 const gst_riff_acid *acid = NULL; |
|
1375 const guint data_size = sizeof (gst_riff_acid); |
|
1376 |
1156 if (wav->streaming) { |
1377 if (wav->streaming) { |
1157 if (!gst_wavparse_peek_chunk (wav, &tag, &size)) |
1378 if (gst_adapter_available (wav->adapter) < 8 + data_size) { |
1158 return GST_FLOW_OK; |
1379 return GST_FLOW_OK; |
1159 } |
1380 } |
1160 GST_DEBUG_OBJECT (wav, "Ignoring tag %" GST_FOURCC_FORMAT, |
1381 gst_adapter_flush (wav->adapter, 8); |
1161 GST_FOURCC_ARGS (tag)); |
1382 acid = (const gst_riff_acid *) gst_adapter_peek (wav->adapter, |
1162 wav->offset += 8 + ((size + 1) & ~1); |
1383 data_size); |
1163 if (wav->streaming) { |
|
1164 gst_adapter_flush (wav->adapter, 8 + ((size + 1) & ~1)); |
|
1165 } else { |
1384 } else { |
1166 gst_buffer_unref (buf); |
1385 gst_buffer_unref (buf); |
|
1386 if ((res = |
|
1387 gst_pad_pull_range (wav->sinkpad, wav->offset + 8, |
|
1388 data_size, &buf)) != GST_FLOW_OK) |
|
1389 goto header_read_error; |
|
1390 acid = (const gst_riff_acid *) GST_BUFFER_DATA (buf); |
1167 } |
1391 } |
|
1392 GST_INFO_OBJECT (wav, "Have acid chunk"); |
|
1393 /* send data as tags */ |
|
1394 if (!wav->tags) |
|
1395 wav->tags = gst_tag_list_new (); |
|
1396 gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE, |
|
1397 GST_TAG_BEATS_PER_MINUTE, acid->tempo, NULL); |
|
1398 |
|
1399 if (wav->streaming) { |
|
1400 gst_adapter_flush (wav->adapter, data_size); |
|
1401 } else { |
|
1402 gst_buffer_unref (buf); |
|
1403 wav->offset += 8 + data_size; |
|
1404 } |
|
1405 break; |
|
1406 } |
|
1407 /* FIXME: all list tags after data are ignored in streaming mode */ |
|
1408 case GST_RIFF_TAG_LIST:{ |
|
1409 guint32 ltag; |
|
1410 |
|
1411 if (wav->streaming) { |
|
1412 const guint8 *data = NULL; |
|
1413 |
|
1414 if (gst_adapter_available (wav->adapter) < 12) { |
|
1415 return GST_FLOW_OK; |
|
1416 } |
|
1417 data = gst_adapter_peek (wav->adapter, 12); |
|
1418 ltag = GST_READ_UINT32_LE (data + 8); |
|
1419 } else { |
|
1420 gst_buffer_unref (buf); |
|
1421 if ((res = |
|
1422 gst_pad_pull_range (wav->sinkpad, wav->offset, 12, |
|
1423 &buf)) != GST_FLOW_OK) |
|
1424 goto header_read_error; |
|
1425 ltag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 8); |
|
1426 } |
|
1427 switch (ltag) { |
|
1428 case GST_RIFF_LIST_INFO:{ |
|
1429 const guint data_size = size - 4; |
|
1430 GstTagList *new; |
|
1431 |
|
1432 GST_INFO_OBJECT (wav, "Have LIST chunk INFO size %u", data_size); |
|
1433 if (wav->streaming) { |
|
1434 gst_adapter_flush (wav->adapter, 12); |
|
1435 if (gst_adapter_available (wav->adapter) < data_size) { |
|
1436 return GST_FLOW_OK; |
|
1437 } |
|
1438 gst_buffer_unref (buf); |
|
1439 if (data_size > 0) |
|
1440 buf = gst_adapter_take_buffer (wav->adapter, data_size); |
|
1441 } else { |
|
1442 wav->offset += 12; |
|
1443 gst_buffer_unref (buf); |
|
1444 if (data_size > 0) { |
|
1445 if ((res = |
|
1446 gst_pad_pull_range (wav->sinkpad, wav->offset, |
|
1447 data_size, &buf)) != GST_FLOW_OK) |
|
1448 goto header_read_error; |
|
1449 } |
|
1450 } |
|
1451 if (data_size > 0) { |
|
1452 /* parse tags */ |
|
1453 gst_riff_parse_info (GST_ELEMENT (wav), buf, &new); |
|
1454 if (new) { |
|
1455 GstTagList *old = wav->tags; |
|
1456 wav->tags = |
|
1457 gst_tag_list_merge (old, new, GST_TAG_MERGE_REPLACE); |
|
1458 if (old) |
|
1459 gst_tag_list_free (old); |
|
1460 gst_tag_list_free (new); |
|
1461 } |
|
1462 if (wav->streaming) { |
|
1463 gst_adapter_flush (wav->adapter, data_size); |
|
1464 } else { |
|
1465 gst_buffer_unref (buf); |
|
1466 wav->offset += data_size; |
|
1467 } |
|
1468 } |
|
1469 break; |
|
1470 } |
|
1471 default: |
|
1472 GST_INFO_OBJECT (wav, "Ignoring LIST chunk %" GST_FOURCC_FORMAT, |
|
1473 GST_FOURCC_ARGS (ltag)); |
|
1474 gst_waveparse_ignore_chunk (wav, buf, tag, size); |
|
1475 break; |
|
1476 } |
|
1477 break; |
|
1478 } |
|
1479 default: |
|
1480 gst_waveparse_ignore_chunk (wav, buf, tag, size); |
|
1481 } |
|
1482 |
|
1483 if (upstream_size && (wav->offset >= upstream_size)) { |
|
1484 /* Now we are gone through the whole file */ |
|
1485 gotdata = TRUE; |
1168 } |
1486 } |
1169 } |
1487 } |
1170 |
1488 |
1171 GST_DEBUG_OBJECT (wav, "Finished parsing headers"); |
1489 GST_DEBUG_OBJECT (wav, "Finished parsing headers"); |
1172 |
1490 |
1173 duration = gst_util_uint64_scale_int (wav->datasize, GST_SECOND, wav->bps); |
1491 if (wav->bps <= 0 && wav->fact) { |
1174 GST_DEBUG_OBJECT (wav, "Got duration %" GST_TIME_FORMAT, |
1492 #if 0 |
1175 GST_TIME_ARGS (duration)); |
1493 /* not a good idea, as for embedded mp2/mp3 we set bps to 0 earlier */ |
1176 gst_segment_set_duration (&wav->segment, GST_FORMAT_TIME, duration); |
1494 wav->bps = |
|
1495 (guint32) gst_util_uint64_scale ((guint64) wav->rate, wav->datasize, |
|
1496 (guint64) wav->fact); |
|
1497 GST_INFO_OBJECT (wav, "calculated bps : %d, enabling VBR", wav->bps); |
|
1498 #endif |
|
1499 wav->vbr = TRUE; |
|
1500 } |
|
1501 |
|
1502 if (gst_wavparse_calculate_duration (wav)) { |
|
1503 gst_segment_init (&wav->segment, GST_FORMAT_TIME); |
|
1504 gst_segment_set_duration (&wav->segment, GST_FORMAT_TIME, wav->duration); |
|
1505 } else { |
|
1506 /* no bitrate, let downstream peer do the math, we'll feed it bytes. */ |
|
1507 gst_segment_init (&wav->segment, GST_FORMAT_BYTES); |
|
1508 gst_segment_set_duration (&wav->segment, GST_FORMAT_BYTES, wav->datasize); |
|
1509 } |
1177 |
1510 |
1178 /* now we have all the info to perform a pending seek if any, if no |
1511 /* now we have all the info to perform a pending seek if any, if no |
1179 * event, this will still do the right thing and it will also send |
1512 * event, this will still do the right thing and it will also send |
1180 * the right newsegment event downstream. */ |
1513 * the right newsegment event downstream. */ |
1181 gst_wavparse_perform_seek (wav, wav->seek_event); |
1514 gst_wavparse_perform_seek (wav, wav->seek_event); |
1182 /* remove pending event */ |
1515 /* remove pending event */ |
1183 event_p = &wav->seek_event; |
1516 event_p = &wav->seek_event; |
1184 gst_event_replace (event_p, NULL); |
1517 gst_event_replace (event_p, NULL); |
1185 |
1518 |
|
1519 /* we just started, we are discont */ |
|
1520 wav->discont = TRUE; |
|
1521 |
1186 wav->state = GST_WAVPARSE_DATA; |
1522 wav->state = GST_WAVPARSE_DATA; |
1187 |
1523 |
1188 return GST_FLOW_OK; |
1524 return GST_FLOW_OK; |
1189 |
1525 |
1190 /* ERROR */ |
1526 /* ERROR */ |
1191 invalid_wav: |
1527 invalid_wav: |
1192 { |
1528 { |
1193 GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), |
1529 GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL), |
1194 ("Invalid WAV header (no fmt at start): %" |
1530 ("Invalid WAV header (no fmt at start): %" |
1195 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag))); |
1531 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag))); |
1196 g_free (codec_name); |
1532 g_free (codec_name); |
1197 |
|
1198 return GST_FLOW_ERROR; |
1533 return GST_FLOW_ERROR; |
1199 } |
1534 } |
1200 parse_header_error: |
1535 parse_header_error: |
1201 { |
1536 { |
1202 GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), |
1537 GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), |
1203 ("Couldn't parse audio header")); |
1538 ("Couldn't parse audio header")); |
1204 gst_buffer_unref (buf); |
|
1205 g_free (codec_name); |
1539 g_free (codec_name); |
1206 |
|
1207 return GST_FLOW_ERROR; |
1540 return GST_FLOW_ERROR; |
1208 } |
1541 } |
1209 no_channels: |
1542 no_channels: |
1210 { |
1543 { |
1211 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), |
1544 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), |
1212 ("Stream claims to contain no channels - invalid data")); |
1545 ("Stream claims to contain no channels - invalid data")); |
1213 g_free (header); |
1546 g_free (header); |
1214 g_free (codec_name); |
1547 g_free (codec_name); |
1215 return GST_FLOW_ERROR; |
1548 return GST_FLOW_ERROR; |
1216 } |
1549 } |
1217 no_bitrate: |
1550 no_rate: |
1218 { |
1551 { |
1219 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), |
1552 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), |
1220 ("Stream claims to have a bitrate of <= zero - invalid data")); |
1553 ("Stream with sample_rate == 0 - invalid data")); |
1221 g_free (header); |
1554 g_free (header); |
1222 g_free (codec_name); |
1555 g_free (codec_name); |
1223 return GST_FLOW_ERROR; |
1556 return GST_FLOW_ERROR; |
1224 } |
1557 } |
|
1558 invalid_blockalign: |
|
1559 { |
|
1560 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), |
|
1561 ("Stream claims blockalign = %u, which is more than %u - invalid data", |
|
1562 wav->blockalign, wav->channels * (guint) ceil (wav->depth / 8.0))); |
|
1563 g_free (codec_name); |
|
1564 return GST_FLOW_ERROR; |
|
1565 } |
|
1566 invalid_bps: |
|
1567 { |
|
1568 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), |
|
1569 ("Stream claims av_bsp = %u, which is more than %u - invalid data", |
|
1570 wav->av_bps, wav->blockalign * wav->rate)); |
|
1571 g_free (codec_name); |
|
1572 return GST_FLOW_ERROR; |
|
1573 } |
1225 no_bytes_per_sample: |
1574 no_bytes_per_sample: |
1226 { |
1575 { |
1227 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), |
1576 GST_ELEMENT_ERROR (wav, STREAM, FAILED, (NULL), |
1228 ("could not caluclate bytes per sample - invalid data")); |
1577 ("Could not caluclate bytes per sample - invalid data")); |
1229 g_free (header); |
|
1230 g_free (codec_name); |
1578 g_free (codec_name); |
1231 return GST_FLOW_ERROR; |
1579 return GST_FLOW_ERROR; |
1232 } |
1580 } |
1233 unknown_format: |
1581 unknown_format: |
1234 { |
1582 { |
1235 GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL), |
1583 GST_ELEMENT_ERROR (wav, STREAM, TYPE_NOT_FOUND, (NULL), |
1236 ("No caps found for format 0x%x, %d channels, %d Hz", |
1584 ("No caps found for format 0x%x, %d channels, %d Hz", |
1237 wav->format, wav->channels, wav->rate)); |
1585 wav->format, wav->channels, wav->rate)); |
|
1586 g_free (header); |
1238 g_free (codec_name); |
1587 g_free (codec_name); |
1239 return GST_FLOW_ERROR; |
1588 return GST_FLOW_ERROR; |
1240 } |
1589 } |
1241 header_read_error: |
1590 header_read_error: |
1242 { |
1591 { |
1243 GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), ("Couldn't read in header")); |
1592 GST_ELEMENT_ERROR (wav, STREAM, DEMUX, (NULL), |
|
1593 ("Couldn't read in header %d (%s)", res, gst_flow_get_name (res))); |
1244 g_free (codec_name); |
1594 g_free (codec_name); |
1245 return GST_FLOW_ERROR; |
1595 return GST_FLOW_ERROR; |
1246 } |
1596 } |
1247 } |
1597 } |
1248 |
1598 |
1249 |
1599 /* |
1250 /* |
|
1251 * Read WAV file tag when streaming |
1600 * Read WAV file tag when streaming |
1252 */ |
1601 */ |
1253 static GstFlowReturn |
1602 static GstFlowReturn |
1254 gst_wavparse_parse_stream_init (GstWavParse * wav) |
1603 gst_wavparse_parse_stream_init (GstWavParse * wav) |
1255 { |
1604 { |
1256 if (gst_adapter_available (wav->adapter) >= 12) { |
1605 if (gst_adapter_available (wav->adapter) >= 12) { |
1257 GstBuffer *tmp = gst_buffer_new (); |
1606 GstBuffer *tmp; |
1258 |
1607 |
1259 /* _take flushes the data */ |
1608 /* _take flushes the data */ |
1260 GST_BUFFER_DATA (tmp) = gst_adapter_take (wav->adapter, 12); |
1609 tmp = gst_adapter_take_buffer (wav->adapter, 12); |
1261 GST_BUFFER_SIZE (tmp) = 12; |
|
1262 |
1610 |
1263 GST_DEBUG ("Parsing wav header"); |
1611 GST_DEBUG ("Parsing wav header"); |
1264 if (!gst_wavparse_parse_file_header (GST_ELEMENT (wav), tmp)) { |
1612 if (!gst_wavparse_parse_file_header (GST_ELEMENT_CAST (wav), tmp)) |
1265 return GST_FLOW_ERROR; |
1613 return GST_FLOW_ERROR; |
1266 } |
|
1267 |
1614 |
1268 wav->offset += 12; |
1615 wav->offset += 12; |
1269 /* Go to next state */ |
1616 /* Go to next state */ |
1270 wav->state = GST_WAVPARSE_HEADER; |
1617 wav->state = GST_WAVPARSE_HEADER; |
1271 } |
1618 } |
1320 gst_wavparse_add_src_pad (GstWavParse * wav, GstBuffer * buf) |
1667 gst_wavparse_add_src_pad (GstWavParse * wav, GstBuffer * buf) |
1321 { |
1668 { |
1322 GstStructure *s; |
1669 GstStructure *s; |
1323 const guint8 dts_marker[] = { 0xFF, 0x1F, 0x00, 0xE8, 0xF1, 0x07 }; |
1670 const guint8 dts_marker[] = { 0xFF, 0x1F, 0x00, 0xE8, 0xF1, 0x07 }; |
1324 |
1671 |
1325 |
1672 GST_DEBUG_OBJECT (wav, "adding src pad"); |
1326 s = gst_caps_get_structure (wav->caps, 0); |
1673 |
1327 if (gst_structure_has_name (s, "audio/x-raw-int") && |
1674 if (wav->caps) { |
1328 GST_BUFFER_SIZE (buf) > 6 && |
1675 s = gst_caps_get_structure (wav->caps, 0); |
1329 memcmp (GST_BUFFER_DATA (buf), dts_marker, 6) == 0) { |
1676 if (s && gst_structure_has_name (s, "audio/x-raw-int") && buf && |
1330 |
1677 GST_BUFFER_SIZE (buf) > 6 && |
1331 GST_WARNING_OBJECT (wav, "Found DTS marker in file marked as raw PCM"); |
1678 memcmp (GST_BUFFER_DATA (buf), dts_marker, 6) == 0) { |
1332 gst_caps_unref (wav->caps); |
1679 |
1333 wav->caps = gst_caps_from_string ("audio/x-dts"); |
1680 GST_WARNING_OBJECT (wav, "Found DTS marker in file marked as raw PCM"); |
1334 |
1681 gst_caps_unref (wav->caps); |
1335 gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE, |
1682 wav->caps = gst_caps_from_string ("audio/x-dts"); |
1336 GST_TAG_AUDIO_CODEC, "dts", NULL); |
1683 |
1337 |
1684 gst_tag_list_add (wav->tags, GST_TAG_MERGE_REPLACE, |
|
1685 GST_TAG_AUDIO_CODEC, "dts", NULL); |
|
1686 } |
1338 } |
1687 } |
1339 |
1688 |
1340 gst_wavparse_create_sourcepad (wav); |
1689 gst_wavparse_create_sourcepad (wav); |
1341 gst_pad_set_active (wav->srcpad, TRUE); |
1690 gst_pad_set_active (wav->srcpad, TRUE); |
1342 gst_pad_set_caps (wav->srcpad, wav->caps); |
1691 gst_pad_set_caps (wav->srcpad, wav->caps); |
1343 gst_caps_replace (&wav->caps, NULL); |
1692 gst_caps_replace (&wav->caps, NULL); |
1344 |
1693 |
1345 gst_element_add_pad (GST_ELEMENT (wav), wav->srcpad); |
1694 gst_element_add_pad (GST_ELEMENT_CAST (wav), wav->srcpad); |
1346 |
1695 gst_element_no_more_pads (GST_ELEMENT_CAST (wav)); |
1347 |
1696 |
1348 gst_element_no_more_pads (GST_ELEMENT (wav)); |
1697 if (wav->close_segment) { |
1349 |
1698 GST_DEBUG_OBJECT (wav, "Send close segment event on newpad"); |
1350 GST_DEBUG_OBJECT (wav, "Send newsegment event on newpad"); |
1699 gst_pad_push_event (wav->srcpad, wav->close_segment); |
1351 gst_pad_push_event (wav->srcpad, wav->newsegment); |
1700 wav->close_segment = NULL; |
1352 wav->newsegment = NULL; |
1701 } |
1353 |
1702 if (wav->start_segment) { |
1354 |
1703 GST_DEBUG_OBJECT (wav, "Send start segment event on newpad"); |
|
1704 gst_pad_push_event (wav->srcpad, wav->start_segment); |
|
1705 wav->start_segment = NULL; |
|
1706 } |
|
1707 |
1355 if (wav->tags) { |
1708 if (wav->tags) { |
1356 gst_element_found_tags_for_pad (GST_ELEMENT (wav), wav->srcpad, wav->tags); |
1709 gst_element_found_tags_for_pad (GST_ELEMENT_CAST (wav), wav->srcpad, |
|
1710 wav->tags); |
1357 wav->tags = NULL; |
1711 wav->tags = NULL; |
1358 } |
1712 } |
1359 |
|
1360 } |
1713 } |
1361 |
1714 |
1362 #define MAX_BUFFER_SIZE 4096 |
1715 #define MAX_BUFFER_SIZE 4096 |
1363 |
1716 |
1364 static GstFlowReturn |
1717 static GstFlowReturn |
1365 gst_wavparse_stream_data (GstWavParse * wav) |
1718 gst_wavparse_stream_data (GstWavParse * wav) |
1366 { |
1719 { |
1367 GstBuffer *buf = NULL; |
1720 GstBuffer *buf = NULL; |
1368 GstFlowReturn res = GST_FLOW_OK; |
1721 GstFlowReturn res = GST_FLOW_OK; |
1369 guint64 desired, obtained; |
1722 guint64 desired, obtained; |
1370 GstClockTime timestamp, next_timestamp; |
1723 GstClockTime timestamp, next_timestamp, duration; |
1371 guint64 pos, nextpos; |
1724 guint64 pos, nextpos; |
1372 |
1725 |
1373 |
|
1374 iterate_adapter: |
1726 iterate_adapter: |
1375 GST_LOG_OBJECT (wav, |
1727 GST_LOG_OBJECT (wav, |
1376 "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT " , dataleft: %" |
1728 "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT " , dataleft: %" |
1377 G_GINT64_FORMAT, wav->offset, wav->end_offset, wav->dataleft); |
1729 G_GINT64_FORMAT, wav->offset, wav->end_offset, wav->dataleft); |
1378 |
1730 |
1382 |
1734 |
1383 /* scale the amount of data by the segment rate so we get equal |
1735 /* scale the amount of data by the segment rate so we get equal |
1384 * amounts of data regardless of the playback rate */ |
1736 * amounts of data regardless of the playback rate */ |
1385 desired = |
1737 desired = |
1386 MIN (gst_guint64_to_gdouble (wav->dataleft), |
1738 MIN (gst_guint64_to_gdouble (wav->dataleft), |
1387 MAX_BUFFER_SIZE * ABS (wav->segment.rate)); |
1739 MAX_BUFFER_SIZE * wav->segment.abs_rate); |
|
1740 |
1388 if (desired >= wav->blockalign && wav->blockalign > 0) |
1741 if (desired >= wav->blockalign && wav->blockalign > 0) |
1389 desired -= (desired % wav->blockalign); |
1742 desired -= (desired % wav->blockalign); |
1390 |
1743 |
1391 |
|
1392 GST_LOG_OBJECT (wav, "Fetching %" G_GINT64_FORMAT " bytes of data " |
1744 GST_LOG_OBJECT (wav, "Fetching %" G_GINT64_FORMAT " bytes of data " |
1393 "from the sinkpad", desired); |
1745 "from the sinkpad", desired); |
1394 |
1746 |
1395 if (wav->streaming) { |
1747 if (wav->streaming) { |
1396 guint avail = gst_adapter_available (wav->adapter); |
1748 guint avail = gst_adapter_available (wav->adapter); |
1397 |
1749 guint extra; |
|
1750 |
|
1751 /* flush some bytes if evil upstream sends segment that starts |
|
1752 * before data or does is not send sample aligned segment */ |
|
1753 if (G_LIKELY (wav->offset >= wav->datastart)) { |
|
1754 extra = (wav->offset - wav->datastart) % wav->bytes_per_sample; |
|
1755 } else { |
|
1756 extra = wav->datastart - wav->offset; |
|
1757 } |
|
1758 |
|
1759 if (G_UNLIKELY (extra)) { |
|
1760 extra = wav->bytes_per_sample - extra; |
|
1761 if (extra <= avail) { |
|
1762 GST_DEBUG_OBJECT (wav, "flushing %d bytes to sample boundary", extra); |
|
1763 gst_adapter_flush (wav->adapter, extra); |
|
1764 wav->offset += extra; |
|
1765 wav->dataleft -= extra; |
|
1766 goto iterate_adapter; |
|
1767 } else { |
|
1768 GST_DEBUG_OBJECT (wav, "flushing %d bytes", avail); |
|
1769 gst_adapter_clear (wav->adapter); |
|
1770 wav->offset += avail; |
|
1771 wav->dataleft -= avail; |
|
1772 return GST_FLOW_OK; |
|
1773 } |
|
1774 } |
|
1775 |
1398 if (avail < desired) { |
1776 if (avail < desired) { |
1399 |
|
1400 GST_LOG_OBJECT (wav, "Got only %d bytes of data from the sinkpad", avail); |
1777 GST_LOG_OBJECT (wav, "Got only %d bytes of data from the sinkpad", avail); |
1401 return GST_FLOW_OK; |
1778 return GST_FLOW_OK; |
1402 } |
1779 } |
1403 |
1780 |
1404 buf = gst_buffer_new (); |
1781 buf = gst_adapter_take_buffer (wav->adapter, desired); |
1405 GST_BUFFER_DATA (buf) = gst_adapter_take (wav->adapter, desired); |
|
1406 GST_BUFFER_SIZE (buf) = desired; |
|
1407 |
|
1408 |
|
1409 } else { |
1782 } else { |
1410 if ((res = gst_pad_pull_range (wav->sinkpad, wav->offset, |
1783 if ((res = gst_pad_pull_range (wav->sinkpad, wav->offset, |
1411 desired, &buf)) != GST_FLOW_OK) |
1784 desired, &buf)) != GST_FLOW_OK) |
1412 { |
|
1413 |
|
1414 goto pull_error; |
1785 goto pull_error; |
1415 } |
|
1416 |
|
1417 } |
1786 } |
1418 |
1787 |
1419 /* first chunk of data? create the source pad. We do this only here so |
1788 /* first chunk of data? create the source pad. We do this only here so |
1420 * we can detect broken .wav files with dts disguised as raw PCM (sigh) */ |
1789 * we can detect broken .wav files with dts disguised as raw PCM (sigh) */ |
1421 if (G_UNLIKELY (wav->first)) { |
1790 if (G_UNLIKELY (wav->first)) { |
1422 wav->first = FALSE; |
1791 wav->first = FALSE; |
1423 |
1792 /* this will also push the segment events */ |
1424 gst_wavparse_add_src_pad (wav, buf); |
1793 gst_wavparse_add_src_pad (wav, buf); |
|
1794 } else { |
|
1795 /* If we have a pending close/start segment, send it now. */ |
|
1796 if (G_UNLIKELY (wav->close_segment != NULL)) { |
|
1797 gst_pad_push_event (wav->srcpad, wav->close_segment); |
|
1798 wav->close_segment = NULL; |
|
1799 } |
|
1800 if (G_UNLIKELY (wav->start_segment != NULL)) { |
|
1801 gst_pad_push_event (wav->srcpad, wav->start_segment); |
|
1802 wav->start_segment = NULL; |
|
1803 } |
1425 } |
1804 } |
1426 |
1805 |
1427 obtained = GST_BUFFER_SIZE (buf); |
1806 obtained = GST_BUFFER_SIZE (buf); |
1428 |
1807 |
1429 /* our positions */ |
1808 /* our positions in bytes */ |
1430 pos = wav->offset - wav->datastart; |
1809 pos = wav->offset - wav->datastart; |
1431 nextpos = pos + obtained; |
1810 nextpos = pos + obtained; |
1432 |
1811 |
1433 /* update offsets, does not overflow. */ |
1812 /* update offsets, does not overflow. */ |
1434 GST_BUFFER_OFFSET (buf) = pos / wav->bytes_per_sample; |
1813 GST_BUFFER_OFFSET (buf) = pos / wav->bytes_per_sample; |
1435 GST_BUFFER_OFFSET_END (buf) = nextpos / wav->bytes_per_sample; |
1814 GST_BUFFER_OFFSET_END (buf) = nextpos / wav->bytes_per_sample; |
1436 |
1815 |
1437 /* and timestamps, be carefull for overflows */ |
1816 if (wav->bps > 0) { |
1438 timestamp = gst_util_uint64_scale_int (pos, GST_SECOND, wav->bps); |
1817 /* and timestamps if we have a bitrate, be careful for overflows */ |
1439 next_timestamp = gst_util_uint64_scale_int (nextpos, GST_SECOND, wav->bps); |
1818 timestamp = uint64_ceiling_scale (pos, GST_SECOND, (guint64) wav->bps); |
|
1819 next_timestamp = |
|
1820 uint64_ceiling_scale (nextpos, GST_SECOND, (guint64) wav->bps); |
|
1821 duration = next_timestamp - timestamp; |
|
1822 |
|
1823 /* update current running segment position */ |
|
1824 gst_segment_set_last_stop (&wav->segment, GST_FORMAT_TIME, next_timestamp); |
|
1825 } else if (wav->fact) { |
|
1826 guint64 bps = |
|
1827 gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact); |
|
1828 /* and timestamps if we have a bitrate, be careful for overflows */ |
|
1829 timestamp = uint64_ceiling_scale (pos, GST_SECOND, bps); |
|
1830 next_timestamp = uint64_ceiling_scale (nextpos, GST_SECOND, bps); |
|
1831 duration = next_timestamp - timestamp; |
|
1832 } else { |
|
1833 /* no bitrate, all we know is that the first sample has timestamp 0, all |
|
1834 * other positions and durations have unknown timestamp. */ |
|
1835 if (pos == 0) |
|
1836 timestamp = 0; |
|
1837 else |
|
1838 timestamp = GST_CLOCK_TIME_NONE; |
|
1839 duration = GST_CLOCK_TIME_NONE; |
|
1840 /* update current running segment position with byte offset */ |
|
1841 gst_segment_set_last_stop (&wav->segment, GST_FORMAT_BYTES, nextpos); |
|
1842 } |
|
1843 if ((pos > 0) && wav->vbr) { |
|
1844 /* don't set timestamps for VBR files if it's not the first buffer */ |
|
1845 timestamp = GST_CLOCK_TIME_NONE; |
|
1846 duration = GST_CLOCK_TIME_NONE; |
|
1847 } |
|
1848 if (wav->discont) { |
|
1849 GST_DEBUG_OBJECT (wav, "marking DISCONT"); |
|
1850 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); |
|
1851 wav->discont = FALSE; |
|
1852 } |
1440 |
1853 |
1441 GST_BUFFER_TIMESTAMP (buf) = timestamp; |
1854 GST_BUFFER_TIMESTAMP (buf) = timestamp; |
1442 GST_BUFFER_DURATION (buf) = next_timestamp - timestamp; |
1855 GST_BUFFER_DURATION (buf) = duration; |
1443 |
|
1444 /* update current running segment position */ |
|
1445 gst_segment_set_last_stop (&wav->segment, GST_FORMAT_TIME, next_timestamp); |
|
1446 |
1856 |
1447 /* don't forget to set the caps on the buffer */ |
1857 /* don't forget to set the caps on the buffer */ |
1448 gst_buffer_set_caps (buf, GST_PAD_CAPS (wav->srcpad)); |
1858 gst_buffer_set_caps (buf, GST_PAD_CAPS (wav->srcpad)); |
1449 |
1859 |
1450 GST_LOG_OBJECT (wav, |
1860 GST_LOG_OBJECT (wav, |
1451 "Got buffer. timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT |
1861 "Got buffer. timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT |
1452 ", size:%u", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), |
1862 ", size:%u", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration), |
1453 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_SIZE (buf)); |
1863 GST_BUFFER_SIZE (buf)); |
1454 |
1864 |
1455 |
|
1456 if ((res = gst_pad_push (wav->srcpad, buf)) != GST_FLOW_OK) |
1865 if ((res = gst_pad_push (wav->srcpad, buf)) != GST_FLOW_OK) |
1457 { |
|
1458 |
|
1459 goto push_error; |
1866 goto push_error; |
1460 } |
1867 |
1461 |
|
1462 |
|
1463 if (obtained < wav->dataleft) { |
1868 if (obtained < wav->dataleft) { |
|
1869 wav->offset += obtained; |
1464 wav->dataleft -= obtained; |
1870 wav->dataleft -= obtained; |
1465 } else { |
1871 } else { |
|
1872 wav->offset += wav->dataleft; |
1466 wav->dataleft = 0; |
1873 wav->dataleft = 0; |
1467 } |
1874 } |
1468 wav->offset += obtained; |
1875 |
1469 /* Iterate until need more data, so adapter size won't grow */ |
1876 /* Iterate until need more data, so adapter size won't grow */ |
1470 if (wav->streaming) { |
1877 if (wav->streaming) { |
1471 GST_LOG_OBJECT (wav, |
1878 GST_LOG_OBJECT (wav, |
1472 "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT, wav->offset, |
1879 "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT, wav->offset, |
1473 wav->end_offset); |
1880 wav->end_offset); |
1474 |
|
1475 goto iterate_adapter; |
1881 goto iterate_adapter; |
1476 } |
1882 } |
1477 |
|
1478 return res; |
1883 return res; |
1479 |
1884 |
1480 /* ERROR */ |
1885 /* ERROR */ |
1481 found_eos: |
1886 found_eos: |
1482 { |
1887 { |
1483 |
|
1484 GST_DEBUG_OBJECT (wav, "found EOS"); |
1888 GST_DEBUG_OBJECT (wav, "found EOS"); |
1485 /* we completed the segment */ |
1889 return GST_FLOW_UNEXPECTED; |
1486 wav->segment_running = FALSE; |
|
1487 if (wav->segment.flags & GST_SEEK_FLAG_SEGMENT) { |
|
1488 GstClockTime stop; |
|
1489 |
|
1490 if ((stop = wav->segment.stop) == -1) |
|
1491 stop = wav->segment.duration; |
|
1492 |
|
1493 gst_element_post_message (GST_ELEMENT (wav), |
|
1494 gst_message_new_segment_done (GST_OBJECT (wav), GST_FORMAT_TIME, |
|
1495 stop)); |
|
1496 |
|
1497 } else { |
|
1498 gst_pad_push_event (wav->srcpad, gst_event_new_eos ()); |
|
1499 |
|
1500 } |
|
1501 return GST_FLOW_WRONG_STATE; |
|
1502 } |
1890 } |
1503 pull_error: |
1891 pull_error: |
1504 { |
1892 { |
1505 |
1893 /* check if we got EOS */ |
1506 GST_DEBUG_OBJECT (wav, "Error getting %" G_GINT64_FORMAT " bytes from the " |
1894 if (res == GST_FLOW_UNEXPECTED) |
|
1895 goto found_eos; |
|
1896 |
|
1897 GST_WARNING_OBJECT (wav, |
|
1898 "Error getting %" G_GINT64_FORMAT " bytes from the " |
1507 "sinkpad (dataleft = %" G_GINT64_FORMAT ")", desired, wav->dataleft); |
1899 "sinkpad (dataleft = %" G_GINT64_FORMAT ")", desired, wav->dataleft); |
1508 return res; |
1900 return res; |
1509 } |
1901 } |
1510 push_error: |
1902 push_error: |
1511 { |
1903 { |
1512 |
1904 GST_INFO_OBJECT (wav, |
1513 GST_DEBUG_OBJECT (wav, "Error pushing on srcpad"); |
1905 "Error pushing on srcpad %s:%s, reason %s, is linked? = %d", |
|
1906 GST_DEBUG_PAD_NAME (wav->srcpad), gst_flow_get_name (res), |
|
1907 gst_pad_is_linked (wav->srcpad)); |
1514 return res; |
1908 return res; |
1515 } |
1909 } |
1516 } |
1910 } |
1517 |
1911 |
1518 static void |
1912 static void |
1523 |
1917 |
1524 GST_LOG_OBJECT (wav, "process data"); |
1918 GST_LOG_OBJECT (wav, "process data"); |
1525 |
1919 |
1526 switch (wav->state) { |
1920 switch (wav->state) { |
1527 case GST_WAVPARSE_START: |
1921 case GST_WAVPARSE_START: |
1528 GST_DEBUG_OBJECT (wav, "GST_WAVPARSE_START"); |
1922 GST_INFO_OBJECT (wav, "GST_WAVPARSE_START"); |
1529 if ((ret = gst_wavparse_stream_init (wav)) != GST_FLOW_OK) |
1923 if ((ret = gst_wavparse_stream_init (wav)) != GST_FLOW_OK) |
1530 goto pause; |
1924 goto pause; |
1531 |
1925 |
1532 wav->state = GST_WAVPARSE_HEADER; |
1926 wav->state = GST_WAVPARSE_HEADER; |
1533 /* fall-through */ |
1927 /* fall-through */ |
1534 |
1928 |
1535 case GST_WAVPARSE_HEADER: |
1929 case GST_WAVPARSE_HEADER: |
1536 GST_DEBUG_OBJECT (wav, "GST_WAVPARSE_HEADER"); |
1930 GST_INFO_OBJECT (wav, "GST_WAVPARSE_HEADER"); |
1537 if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK) |
1931 if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK) |
1538 goto pause; |
1932 goto pause; |
1539 |
1933 |
1540 wav->state = GST_WAVPARSE_DATA; |
1934 wav->state = GST_WAVPARSE_DATA; |
|
1935 GST_INFO_OBJECT (wav, "GST_WAVPARSE_DATA"); |
1541 /* fall-through */ |
1936 /* fall-through */ |
1542 |
1937 |
1543 case GST_WAVPARSE_DATA: |
1938 case GST_WAVPARSE_DATA: |
1544 if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK) |
1939 if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK) |
1545 { |
|
1546 |
|
1547 goto pause; |
1940 goto pause; |
1548 } |
1941 break; |
1549 |
|
1550 break; |
|
1551 default: |
1942 default: |
1552 g_assert_not_reached (); |
1943 g_assert_not_reached (); |
1553 } |
1944 } |
1554 |
|
1555 return; |
1945 return; |
1556 |
1946 |
1557 /* ERRORS */ |
1947 /* ERRORS */ |
1558 pause: |
1948 pause: |
1559 GST_LOG_OBJECT (wav, "pausing task %d", ret); |
1949 { |
1560 gst_pad_pause_task (wav->sinkpad); |
1950 const gchar *reason = gst_flow_get_name (ret); |
1561 if (GST_FLOW_IS_FATAL (ret)) { |
1951 |
1562 |
1952 GST_DEBUG_OBJECT (wav, "pausing task, reason %s", reason); |
1563 |
1953 wav->segment_running = FALSE; |
1564 /* for fatal errors we post an error message */ |
1954 gst_pad_pause_task (pad); |
1565 GST_ELEMENT_ERROR (wav, STREAM, FAILED, |
1955 |
1566 (_("Internal data stream error.")), |
1956 if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) { |
1567 ("streaming stopped, reason %s", gst_flow_get_name (ret))); |
1957 if (ret == GST_FLOW_UNEXPECTED) { |
1568 if (wav->srcpad != NULL) |
1958 /* add pad before we perform EOS */ |
1569 { |
1959 if (G_UNLIKELY (wav->first)) { |
1570 gst_pad_push_event (wav->srcpad, gst_event_new_eos ()); |
1960 wav->first = FALSE; |
1571 } |
1961 gst_wavparse_add_src_pad (wav, NULL); |
1572 } |
1962 } |
1573 |
1963 /* perform EOS logic */ |
|
1964 if (wav->segment.flags & GST_SEEK_FLAG_SEGMENT) { |
|
1965 GstClockTime stop; |
|
1966 |
|
1967 if ((stop = wav->segment.stop) == -1) |
|
1968 stop = wav->segment.duration; |
|
1969 |
|
1970 gst_element_post_message (GST_ELEMENT_CAST (wav), |
|
1971 gst_message_new_segment_done (GST_OBJECT_CAST (wav), |
|
1972 wav->segment.format, stop)); |
|
1973 } else { |
|
1974 if (wav->srcpad != NULL) |
|
1975 gst_pad_push_event (wav->srcpad, gst_event_new_eos ()); |
|
1976 } |
|
1977 } else { |
|
1978 /* for fatal errors we post an error message, post the error |
|
1979 * first so the app knows about the error first. */ |
|
1980 GST_ELEMENT_ERROR (wav, STREAM, FAILED, |
|
1981 (_("Internal data flow error.")), |
|
1982 ("streaming task paused, reason %s (%d)", reason, ret)); |
|
1983 if (wav->srcpad != NULL) |
|
1984 gst_pad_push_event (wav->srcpad, gst_event_new_eos ()); |
|
1985 } |
|
1986 } |
|
1987 return; |
|
1988 } |
1574 } |
1989 } |
1575 |
1990 |
1576 static GstFlowReturn |
1991 static GstFlowReturn |
1577 gst_wavparse_chain (GstPad * pad, GstBuffer * buf) |
1992 gst_wavparse_chain (GstPad * pad, GstBuffer * buf) |
1578 { |
1993 { |
1579 GstFlowReturn ret; |
1994 GstFlowReturn ret; |
1580 GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad)); |
1995 GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad)); |
1581 GST_LOG_OBJECT (wav, "adapter_push %" G_GINT64_FORMAT " bytes", |
1996 |
1582 GST_BUFFER_SIZE (buf)); |
1997 GST_LOG_OBJECT (wav, "adapter_push %u bytes", GST_BUFFER_SIZE (buf)); |
1583 |
1998 |
1584 gst_adapter_push (wav->adapter, buf); |
1999 gst_adapter_push (wav->adapter, buf); |
|
2000 |
1585 switch (wav->state) { |
2001 switch (wav->state) { |
1586 case GST_WAVPARSE_START: |
2002 case GST_WAVPARSE_START: |
1587 GST_DEBUG_OBJECT (wav, "GST_WAVPARSE_START"); |
2003 GST_INFO_OBJECT (wav, "GST_WAVPARSE_START"); |
1588 if ((ret = gst_wavparse_parse_stream_init (wav)) != GST_FLOW_OK) |
2004 if ((ret = gst_wavparse_parse_stream_init (wav)) != GST_FLOW_OK) |
1589 { |
2005 goto done; |
1590 |
2006 |
1591 goto pause; |
2007 if (wav->state != GST_WAVPARSE_HEADER) |
1592 } |
2008 break; |
1593 |
2009 |
1594 wav->state = GST_WAVPARSE_HEADER; |
2010 /* otherwise fall-through */ |
|
2011 case GST_WAVPARSE_HEADER: |
|
2012 GST_INFO_OBJECT (wav, "GST_WAVPARSE_HEADER"); |
|
2013 if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK) |
|
2014 goto done; |
|
2015 |
|
2016 if (!wav->got_fmt || wav->datastart == 0) |
|
2017 break; |
|
2018 |
|
2019 wav->state = GST_WAVPARSE_DATA; |
|
2020 GST_INFO_OBJECT (wav, "GST_WAVPARSE_DATA"); |
|
2021 |
1595 /* fall-through */ |
2022 /* fall-through */ |
1596 |
2023 case GST_WAVPARSE_DATA: |
1597 case GST_WAVPARSE_HEADER: |
2024 if (buf && GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) |
1598 GST_DEBUG_OBJECT (wav, "GST_WAVPARSE_HEADER"); |
2025 wav->discont = TRUE; |
1599 if ((ret = gst_wavparse_stream_headers (wav)) != GST_FLOW_OK) |
2026 if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK) |
1600 goto pause; |
2027 goto done; |
1601 |
2028 break; |
1602 wav->state = GST_WAVPARSE_DATA; |
2029 default: |
|
2030 g_return_val_if_reached (GST_FLOW_ERROR); |
|
2031 } |
|
2032 done: |
|
2033 return ret; |
|
2034 } |
|
2035 |
|
2036 static GstFlowReturn |
|
2037 gst_wavparse_flush_data (GstWavParse * wav) |
|
2038 { |
|
2039 GstFlowReturn ret = GST_FLOW_OK; |
|
2040 guint av; |
|
2041 |
|
2042 if ((av = gst_adapter_available (wav->adapter)) > 0) { |
|
2043 wav->dataleft = av; |
|
2044 wav->end_offset = wav->offset + av; |
|
2045 ret = gst_wavparse_stream_data (wav); |
|
2046 } |
|
2047 |
|
2048 return ret; |
|
2049 } |
|
2050 |
|
2051 static gboolean |
|
2052 gst_wavparse_sink_event (GstPad * pad, GstEvent * event) |
|
2053 { |
|
2054 GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad)); |
|
2055 gboolean ret = TRUE; |
|
2056 |
|
2057 GST_LOG_OBJECT (wav, "handling %s event", GST_EVENT_TYPE_NAME (event)); |
|
2058 |
|
2059 switch (GST_EVENT_TYPE (event)) { |
|
2060 case GST_EVENT_NEWSEGMENT: |
|
2061 { |
|
2062 GstFormat format; |
|
2063 gdouble rate, arate; |
|
2064 gint64 start, stop, time, offset = 0, end_offset = -1; |
|
2065 gboolean update; |
|
2066 GstSegment segment; |
|
2067 |
|
2068 /* some debug output */ |
|
2069 gst_segment_init (&segment, GST_FORMAT_UNDEFINED); |
|
2070 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, |
|
2071 &start, &stop, &time); |
|
2072 gst_segment_set_newsegment_full (&segment, update, rate, arate, format, |
|
2073 start, stop, time); |
|
2074 GST_DEBUG_OBJECT (wav, |
|
2075 "received format %d newsegment %" GST_SEGMENT_FORMAT, format, |
|
2076 &segment); |
|
2077 |
|
2078 if (wav->state != GST_WAVPARSE_DATA) { |
|
2079 GST_DEBUG_OBJECT (wav, "still starting, eating event"); |
|
2080 goto exit; |
|
2081 } |
|
2082 |
|
2083 /* now we are either committed to TIME or BYTE format, |
|
2084 * and we only expect a BYTE segment, e.g. following a seek */ |
|
2085 if (format == GST_FORMAT_BYTES) { |
|
2086 if (start > 0) { |
|
2087 offset = start; |
|
2088 start -= wav->datastart; |
|
2089 start = MAX (start, 0); |
|
2090 } |
|
2091 if (stop > 0) { |
|
2092 end_offset = stop; |
|
2093 stop -= wav->datastart; |
|
2094 stop = MAX (stop, 0); |
|
2095 } |
|
2096 if (wav->segment.format == GST_FORMAT_TIME) { |
|
2097 guint64 bps = wav->bps; |
|
2098 |
|
2099 /* operating in format TIME, so we can convert */ |
|
2100 if (!bps && wav->fact) |
|
2101 bps = |
|
2102 gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact); |
|
2103 if (bps) { |
|
2104 if (start >= 0) |
|
2105 start = |
|
2106 uint64_ceiling_scale (start, GST_SECOND, (guint64) wav->bps); |
|
2107 if (stop >= 0) |
|
2108 stop = |
|
2109 uint64_ceiling_scale (stop, GST_SECOND, (guint64) wav->bps); |
|
2110 } |
|
2111 } |
|
2112 } else { |
|
2113 GST_DEBUG_OBJECT (wav, "unsupported segment format, ignoring"); |
|
2114 goto exit; |
|
2115 } |
|
2116 |
|
2117 /* accept upstream's notion of segment and distribute along */ |
|
2118 gst_segment_set_newsegment_full (&wav->segment, update, rate, arate, |
|
2119 wav->segment.format, start, stop, start); |
|
2120 /* also store the newsegment event for the streaming thread */ |
|
2121 if (wav->start_segment) |
|
2122 gst_event_unref (wav->start_segment); |
|
2123 wav->start_segment = |
|
2124 gst_event_new_new_segment_full (update, rate, arate, |
|
2125 wav->segment.format, start, stop, start); |
|
2126 GST_DEBUG_OBJECT (wav, "Pushing newseg update %d, rate %g, " |
|
2127 "applied rate %g, format %d, start %" G_GINT64_FORMAT ", " |
|
2128 "stop %" G_GINT64_FORMAT, update, rate, arate, wav->segment.format, |
|
2129 start, stop); |
|
2130 |
|
2131 /* stream leftover data in current segment */ |
|
2132 gst_wavparse_flush_data (wav); |
|
2133 /* and set up streaming thread for next one */ |
|
2134 wav->offset = offset; |
|
2135 wav->end_offset = end_offset; |
|
2136 if (wav->end_offset > 0) { |
|
2137 wav->dataleft = wav->end_offset - wav->offset; |
|
2138 } else { |
|
2139 /* infinity; upstream will EOS when done */ |
|
2140 wav->dataleft = G_MAXUINT64; |
|
2141 } |
|
2142 exit: |
|
2143 gst_event_unref (event); |
|
2144 break; |
|
2145 } |
|
2146 case GST_EVENT_EOS: |
|
2147 /* stream leftover data in current segment */ |
|
2148 gst_wavparse_flush_data (wav); |
1603 /* fall-through */ |
2149 /* fall-through */ |
1604 |
2150 case GST_EVENT_FLUSH_STOP: |
1605 case GST_WAVPARSE_DATA: |
2151 gst_adapter_clear (wav->adapter); |
1606 if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK) |
2152 wav->discont = TRUE; |
1607 { |
2153 /* fall-through */ |
1608 |
|
1609 goto pause; |
|
1610 } |
|
1611 |
|
1612 break; |
|
1613 |
|
1614 default: |
2154 default: |
1615 g_assert_not_reached (); |
2155 ret = gst_pad_event_default (wav->sinkpad, event); |
1616 } |
2156 break; |
1617 |
|
1618 return ret; |
|
1619 |
|
1620 pause: |
|
1621 |
|
1622 GST_LOG_OBJECT (wav, "pausing task %d", ret); |
|
1623 gst_pad_pause_task (wav->sinkpad); |
|
1624 if (GST_FLOW_IS_FATAL (ret)) { |
|
1625 /* for fatal errors we post an error message */ |
|
1626 |
|
1627 GST_ELEMENT_ERROR (wav, STREAM, FAILED, |
|
1628 (_("Internal data stream error.")), |
|
1629 ("streaming stopped, reason %s", gst_flow_get_name (ret))); |
|
1630 if (wav->srcpad != NULL) |
|
1631 { |
|
1632 gst_pad_push_event (wav->srcpad, gst_event_new_eos ()); |
|
1633 |
|
1634 } |
|
1635 } |
2157 } |
1636 |
2158 |
1637 return ret; |
2159 return ret; |
1638 } |
2160 } |
1639 |
2161 |
1659 GstFormat * dest_format, gint64 * dest_value) |
2181 GstFormat * dest_format, gint64 * dest_value) |
1660 { |
2182 { |
1661 GstWavParse *wavparse; |
2183 GstWavParse *wavparse; |
1662 gboolean res = TRUE; |
2184 gboolean res = TRUE; |
1663 |
2185 |
1664 wavparse = GST_WAVPARSE (gst_pad_get_parent (pad)); |
2186 wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad)); |
1665 |
2187 |
1666 if (wavparse->bytes_per_sample == 0) |
2188 if (*dest_format == src_format) { |
1667 goto no_bytes_per_sample; |
2189 *dest_value = src_value; |
1668 |
2190 return TRUE; |
1669 if (wavparse->bps == 0) |
2191 } |
1670 goto no_bps; |
2192 |
|
2193 if ((wavparse->bps == 0) && !wavparse->fact) |
|
2194 goto no_bps_fact; |
|
2195 |
|
2196 GST_INFO_OBJECT (wavparse, "converting value from %s to %s", |
|
2197 gst_format_get_name (src_format), gst_format_get_name (*dest_format)); |
1671 |
2198 |
1672 switch (src_format) { |
2199 switch (src_format) { |
1673 case GST_FORMAT_BYTES: |
2200 case GST_FORMAT_BYTES: |
1674 switch (*dest_format) { |
2201 switch (*dest_format) { |
1675 case GST_FORMAT_DEFAULT: |
2202 case GST_FORMAT_DEFAULT: |
1676 *dest_value = src_value / wavparse->bytes_per_sample; |
2203 *dest_value = src_value / wavparse->bytes_per_sample; |
|
2204 /* make sure we end up on a sample boundary */ |
|
2205 *dest_value -= *dest_value % wavparse->bytes_per_sample; |
1677 break; |
2206 break; |
1678 case GST_FORMAT_TIME: |
2207 case GST_FORMAT_TIME: |
1679 *dest_value = |
2208 /* src_value + datastart = offset */ |
1680 gst_util_uint64_scale_int (src_value, GST_SECOND, wavparse->bps); |
2209 GST_INFO_OBJECT (wavparse, |
|
2210 "src=%" G_GINT64_FORMAT ", offset=%" G_GINT64_FORMAT, src_value, |
|
2211 wavparse->offset); |
|
2212 if (wavparse->bps > 0) |
|
2213 *dest_value = uint64_ceiling_scale (src_value, GST_SECOND, |
|
2214 (guint64) wavparse->bps); |
|
2215 else if (wavparse->fact) { |
|
2216 guint64 bps = uint64_ceiling_scale_int (wavparse->datasize, |
|
2217 wavparse->rate, wavparse->fact); |
|
2218 |
|
2219 *dest_value = uint64_ceiling_scale_int (src_value, GST_SECOND, bps); |
|
2220 } else { |
|
2221 res = FALSE; |
|
2222 } |
1681 break; |
2223 break; |
1682 default: |
2224 default: |
1683 res = FALSE; |
2225 res = FALSE; |
1684 goto done; |
2226 goto done; |
1685 } |
2227 } |
1686 *dest_value -= *dest_value % wavparse->bytes_per_sample; |
|
1687 break; |
2228 break; |
1688 |
2229 |
1689 case GST_FORMAT_DEFAULT: |
2230 case GST_FORMAT_DEFAULT: |
1690 switch (*dest_format) { |
2231 switch (*dest_format) { |
1691 case GST_FORMAT_BYTES: |
2232 case GST_FORMAT_BYTES: |
1692 *dest_value = src_value * wavparse->bytes_per_sample; |
2233 *dest_value = src_value * wavparse->bytes_per_sample; |
1693 break; |
2234 break; |
1694 case GST_FORMAT_TIME: |
2235 case GST_FORMAT_TIME: |
1695 *dest_value = |
2236 *dest_value = gst_util_uint64_scale (src_value, GST_SECOND, |
1696 gst_util_uint64_scale_int (src_value, GST_SECOND, wavparse->rate); |
2237 (guint64) wavparse->rate); |
1697 break; |
2238 break; |
1698 default: |
2239 default: |
1699 res = FALSE; |
2240 res = FALSE; |
1700 goto done; |
2241 goto done; |
1701 } |
2242 } |
1702 break; |
2243 break; |
1703 |
2244 |
1704 case GST_FORMAT_TIME: |
2245 case GST_FORMAT_TIME: |
1705 switch (*dest_format) { |
2246 switch (*dest_format) { |
1706 case GST_FORMAT_BYTES: |
2247 case GST_FORMAT_BYTES: |
|
2248 if (wavparse->bps > 0) |
|
2249 *dest_value = gst_util_uint64_scale (src_value, |
|
2250 (guint64) wavparse->bps, GST_SECOND); |
|
2251 else { |
|
2252 guint64 bps = gst_util_uint64_scale_int (wavparse->datasize, |
|
2253 wavparse->rate, wavparse->fact); |
|
2254 |
|
2255 *dest_value = gst_util_uint64_scale (src_value, bps, GST_SECOND); |
|
2256 } |
1707 /* make sure we end up on a sample boundary */ |
2257 /* make sure we end up on a sample boundary */ |
1708 *dest_value = |
|
1709 gst_util_uint64_scale_int (src_value, wavparse->bps, GST_SECOND); |
|
1710 *dest_value -= *dest_value % wavparse->blockalign; |
2258 *dest_value -= *dest_value % wavparse->blockalign; |
1711 break; |
2259 break; |
1712 case GST_FORMAT_DEFAULT: |
2260 case GST_FORMAT_DEFAULT: |
1713 *dest_value = |
2261 *dest_value = gst_util_uint64_scale (src_value, |
1714 gst_util_uint64_scale_int (src_value, wavparse->rate, GST_SECOND); |
2262 (guint64) wavparse->rate, GST_SECOND); |
1715 break; |
2263 break; |
1716 default: |
2264 default: |
1717 res = FALSE; |
2265 res = FALSE; |
1718 goto done; |
2266 goto done; |
1719 } |
2267 } |
1796 gst_query_set_position (query, format, cur); |
2339 gst_query_set_position (query, format, cur); |
1797 break; |
2340 break; |
1798 } |
2341 } |
1799 case GST_QUERY_DURATION: |
2342 case GST_QUERY_DURATION: |
1800 { |
2343 { |
1801 gint64 endb; |
2344 gint64 duration = 0; |
1802 gint64 end; |
|
1803 GstFormat format; |
2345 GstFormat format; |
1804 gboolean res = TRUE; |
2346 |
1805 |
|
1806 endb = wav->datasize; |
|
1807 gst_query_parse_duration (query, &format, NULL); |
2347 gst_query_parse_duration (query, &format, NULL); |
1808 |
2348 |
1809 switch (format) { |
2349 switch (format) { |
1810 case GST_FORMAT_TIME: |
2350 case GST_FORMAT_TIME:{ |
1811 res &= |
2351 if ((res = gst_wavparse_calculate_duration (wav))) { |
1812 gst_wavparse_pad_convert (pad, GST_FORMAT_BYTES, endb, |
2352 duration = wav->duration; |
1813 &format, &end); |
2353 } |
1814 break; |
2354 break; |
|
2355 } |
1815 default: |
2356 default: |
1816 format = GST_FORMAT_BYTES; |
2357 format = GST_FORMAT_BYTES; |
1817 end = endb; |
2358 duration = wav->datasize; |
1818 break; |
2359 break; |
1819 } |
2360 } |
1820 if (res) |
2361 gst_query_set_duration (query, format, duration); |
1821 gst_query_set_duration (query, format, end); |
|
1822 break; |
2362 break; |
1823 } |
2363 } |
1824 case GST_QUERY_CONVERT: |
2364 case GST_QUERY_CONVERT: |
1825 { |
2365 { |
1826 gint64 srcvalue, dstvalue; |
2366 gint64 srcvalue, dstvalue; |
1827 GstFormat srcformat, dstformat; |
2367 GstFormat srcformat, dstformat; |
1828 |
2368 |
1829 gst_query_parse_convert (query, &srcformat, &srcvalue, |
2369 gst_query_parse_convert (query, &srcformat, &srcvalue, |
1830 &dstformat, &dstvalue); |
2370 &dstformat, &dstvalue); |
1831 res &= |
2371 res = gst_wavparse_pad_convert (pad, srcformat, srcvalue, |
1832 gst_wavparse_pad_convert (pad, srcformat, srcvalue, |
|
1833 &dstformat, &dstvalue); |
2372 &dstformat, &dstvalue); |
1834 if (res) |
2373 if (res) |
1835 gst_query_set_convert (query, srcformat, srcvalue, dstformat, dstvalue); |
2374 gst_query_set_convert (query, srcformat, srcvalue, dstformat, dstvalue); |
1836 break; |
2375 break; |
1837 } |
2376 } |
|
2377 case GST_QUERY_SEEKING:{ |
|
2378 GstFormat fmt; |
|
2379 gboolean seekable = FALSE; |
|
2380 |
|
2381 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL); |
|
2382 if (fmt == wav->segment.format) { |
|
2383 if (wav->streaming) { |
|
2384 GstQuery *q; |
|
2385 |
|
2386 q = gst_query_new_seeking (GST_FORMAT_BYTES); |
|
2387 if ((res = gst_pad_peer_query (wav->sinkpad, q))) { |
|
2388 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL); |
|
2389 GST_LOG_OBJECT (wav, "upstream BYTE seekable %d", seekable); |
|
2390 } |
|
2391 gst_query_unref (q); |
|
2392 } else { |
|
2393 GST_LOG_OBJECT (wav, "looping => seekable"); |
|
2394 seekable = TRUE; |
|
2395 res = TRUE; |
|
2396 } |
|
2397 } else if (fmt == GST_FORMAT_TIME) { |
|
2398 res = TRUE; |
|
2399 } |
|
2400 if (res) { |
|
2401 gst_query_set_seeking (query, fmt, seekable, 0, wav->segment.duration); |
|
2402 } |
|
2403 break; |
|
2404 } |
1838 default: |
2405 default: |
1839 res = gst_pad_query_default (pad, query); |
2406 res = gst_pad_query_default (pad, query); |
1840 break; |
2407 break; |
1841 } |
2408 } |
|
2409 gst_object_unref (wav); |
1842 return res; |
2410 return res; |
1843 } |
2411 } |
1844 |
2412 |
1845 static gboolean |
2413 static gboolean |
1846 gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event) |
2414 gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event) |
1847 { |
2415 { |
1848 GstWavParse *wavparse = GST_WAVPARSE (GST_PAD_PARENT (pad)); |
2416 GstWavParse *wavparse = GST_WAVPARSE (gst_pad_get_parent (pad)); |
1849 gboolean res = TRUE; |
2417 gboolean res = FALSE; |
1850 |
2418 |
1851 GST_DEBUG_OBJECT (wavparse, "event %d, %s", GST_EVENT_TYPE (event), |
2419 GST_DEBUG_OBJECT (wavparse, "%s event", GST_EVENT_TYPE_NAME (event)); |
1852 GST_EVENT_TYPE_NAME (event)); |
|
1853 |
|
1854 /* can only handle events when we are in the data state */ |
|
1855 if (wavparse->state != GST_WAVPARSE_DATA) |
|
1856 return FALSE; |
|
1857 |
2420 |
1858 switch (GST_EVENT_TYPE (event)) { |
2421 switch (GST_EVENT_TYPE (event)) { |
1859 case GST_EVENT_SEEK: |
2422 case GST_EVENT_SEEK: |
1860 { |
2423 /* can only handle events when we are in the data state */ |
1861 res = gst_wavparse_perform_seek (wavparse, event); |
2424 if (wavparse->state == GST_WAVPARSE_DATA) { |
1862 break; |
2425 res = gst_wavparse_perform_seek (wavparse, event); |
1863 } |
2426 } |
|
2427 gst_event_unref (event); |
|
2428 break; |
1864 default: |
2429 default: |
1865 res = FALSE; |
2430 res = gst_pad_push_event (wavparse->sinkpad, event); |
1866 break; |
2431 break; |
1867 } |
2432 } |
1868 |
2433 gst_object_unref (wavparse); |
1869 gst_event_unref (event); |
|
1870 |
|
1871 return res; |
2434 return res; |
1872 } |
2435 } |
1873 |
2436 |
1874 static gboolean |
2437 static gboolean |
1875 gst_wavparse_sink_activate (GstPad * sinkpad) |
2438 gst_wavparse_sink_activate (GstPad * sinkpad) |
1876 { |
2439 { |
1877 GstWavParse *wav = GST_WAVPARSE (gst_pad_get_parent (sinkpad)); |
2440 GstWavParse *wav = GST_WAVPARSE (gst_pad_get_parent (sinkpad)); |
1878 gboolean res; |
2441 gboolean res; |
|
2442 |
|
2443 if (wav->adapter) |
|
2444 gst_object_unref (wav->adapter); |
1879 |
2445 |
1880 if (gst_pad_check_pull_range (sinkpad)) { |
2446 if (gst_pad_check_pull_range (sinkpad)) { |
1881 GST_DEBUG ("going to pull mode"); |
2447 GST_DEBUG ("going to pull mode"); |
1882 wav->streaming = FALSE; |
2448 wav->streaming = FALSE; |
|
2449 if (wav->adapter) { |
|
2450 gst_adapter_clear (wav->adapter); |
|
2451 g_object_unref (wav->adapter); |
|
2452 } |
1883 wav->adapter = NULL; |
2453 wav->adapter = NULL; |
1884 res = gst_pad_activate_pull (sinkpad, TRUE); |
2454 res = gst_pad_activate_pull (sinkpad, TRUE); |
1885 } else { |
2455 } else { |
1886 GST_DEBUG ("going to push (streaming) mode"); |
2456 GST_DEBUG ("going to push (streaming) mode"); |
1887 wav->streaming = TRUE; |
2457 wav->streaming = TRUE; |
1888 wav->adapter = gst_adapter_new (); |
2458 if (wav->adapter == NULL) |
|
2459 wav->adapter = gst_adapter_new (); |
1889 res = gst_pad_activate_push (sinkpad, TRUE); |
2460 res = gst_pad_activate_push (sinkpad, TRUE); |
1890 } |
2461 } |
1891 gst_object_unref (wav); |
2462 gst_object_unref (wav); |
1892 return res; |
2463 return res; |
1893 } |
2464 } |
1894 |
2465 |
1895 |
2466 |
1896 static gboolean |
2467 static gboolean |
1897 gst_wavparse_sink_activate_pull (GstPad * sinkpad, gboolean active) |
2468 gst_wavparse_sink_activate_pull (GstPad * sinkpad, gboolean active) |
1898 { |
2469 { |
1899 GstWavParse *wav = GST_WAVPARSE (gst_pad_get_parent (sinkpad)); |
2470 GstWavParse *wav = GST_WAVPARSE (GST_OBJECT_PARENT (sinkpad)); |
1900 |
|
1901 GST_DEBUG_OBJECT (wav, "activating pull"); |
|
1902 |
2471 |
1903 if (active) { |
2472 if (active) { |
1904 /* if we have a scheduler we can start the task */ |
2473 /* if we have a scheduler we can start the task */ |
1905 wav->segment_running = TRUE; |
2474 wav->segment_running = TRUE; |
1906 gst_pad_start_task (sinkpad, (GstTaskFunction) gst_wavparse_loop, sinkpad); |
2475 return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_wavparse_loop, |
|
2476 sinkpad); |
1907 } else { |
2477 } else { |
1908 gst_pad_stop_task (sinkpad); |
2478 wav->segment_running = FALSE; |
1909 } |
2479 return gst_pad_stop_task (sinkpad); |
1910 gst_object_unref (wav); |
2480 } |
1911 |
2481 }; |
1912 return TRUE; |
|
1913 } |
|
1914 |
2482 |
1915 static GstStateChangeReturn |
2483 static GstStateChangeReturn |
1916 gst_wavparse_change_state (GstElement * element, GstStateChange transition) |
2484 gst_wavparse_change_state (GstElement * element, GstStateChange transition) |
1917 { |
2485 { |
1918 GstStateChangeReturn ret; |
2486 GstStateChangeReturn ret; |
1919 GstWavParse *wav = GST_WAVPARSE (element); |
2487 GstWavParse *wav = GST_WAVPARSE (element); |
1920 |
2488 |
1921 GST_DEBUG_OBJECT (wav, "changing state %s - %s", |
|
1922 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)), |
|
1923 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition))); |
|
1924 |
|
1925 switch (transition) { |
2489 switch (transition) { |
1926 case GST_STATE_CHANGE_NULL_TO_READY: |
2490 case GST_STATE_CHANGE_NULL_TO_READY: |
1927 break; |
2491 break; |
1928 case GST_STATE_CHANGE_READY_TO_PAUSED: |
2492 case GST_STATE_CHANGE_READY_TO_PAUSED: |
1929 gst_wavparse_reset (wav); |
2493 gst_wavparse_reset (wav); |