2 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
25 #include "swfdec_audio_flv.h"
26 #include "swfdec_debug.h"
27 #include "swfdec_sound.h"
30 G_DEFINE_TYPE (SwfdecAudioFlv
, swfdec_audio_flv
, SWFDEC_TYPE_AUDIO
)
33 swfdec_audio_flv_dispose (GObject
*object
)
35 SwfdecAudioFlv
*flv
= SWFDEC_AUDIO_FLV (object
);
37 if (flv
->decoder
!= NULL
) {
38 g_object_unref (flv
->decoder
);
41 g_queue_foreach (flv
->playback_queue
, (GFunc
) swfdec_buffer_unref
, NULL
);
42 g_queue_free (flv
->playback_queue
);
43 g_object_unref (flv
->flvdecoder
);
45 G_OBJECT_CLASS (swfdec_audio_flv_parent_class
)->dispose (object
);
49 swfdec_audio_flv_decode_one (SwfdecAudioFlv
*flv
)
56 if (g_queue_is_empty (flv
->playback_queue
)) {
59 swfdec_flv_decoder_get_audio (flv
->flvdecoder
,
60 SWFDEC_TICKS_TO_MSECS (flv
->timestamp
),
61 NULL
, NULL
, &last
, NULL
);
62 flv
->playback_skip
= SWFDEC_TICKS_TO_SAMPLES (
63 flv
->timestamp
- SWFDEC_MSECS_TO_TICKS (last
));
64 flv
->next_timestamp
= last
;
65 SWFDEC_DEBUG ("syncing to %ums: next timestamp to decode is %ums, skipping %u samples",
66 (guint
) SWFDEC_TICKS_TO_MSECS (flv
->timestamp
),
67 flv
->next_timestamp
, flv
->playback_skip
);
70 buffer
= swfdec_audio_decoder_pull (flv
->decoder
);
73 while (buffer
== NULL
) {
74 if (flv
->decoder
&& flv
->next_timestamp
== 0)
76 buffer
= swfdec_flv_decoder_get_audio (flv
->flvdecoder
, flv
->next_timestamp
,
77 &format
, &in
, &now
, &soon
);
79 if (flv
->next_timestamp
!= now
) {
80 /* FIXME: do sync on first frame here */
81 SWFDEC_WARNING ("FIXME: didn't get requested timestamp - still loading?");
83 /* FIXME FIXME FIXME: This avoids decoding the last frame forever, however it ensures sync */
86 flv
->next_timestamp
= soon
;
90 g_object_unref (flv
->decoder
);
95 flv
->decoder
= swfdec_audio_decoder_new (flv
->format
, flv
->in
);
96 if (flv
->decoder
== NULL
)
98 } else if (format
!= flv
->format
||
100 SWFDEC_ERROR ("FIXME: format change not implemented");
102 } else if (flv
->decoder
== NULL
) {
105 swfdec_audio_decoder_push (flv
->decoder
, buffer
);
106 if (flv
->next_timestamp
== 0)
107 swfdec_audio_decoder_push (flv
->decoder
, NULL
);
108 buffer
= swfdec_audio_decoder_pull (flv
->decoder
);
111 g_queue_push_tail (flv
->playback_queue
, buffer
);
116 swfdec_audio_flv_render (SwfdecAudio
*audio
, gint16
* dest
,
117 gsize start
, gsize n_samples
)
119 SwfdecAudioFlv
*flv
= SWFDEC_AUDIO_FLV (audio
);
121 gsize samples
, rendered
;
122 SwfdecBuffer
*buffer
;
124 g_assert (start
< G_MAXINT
);
125 start
+= flv
->playback_skip
;
126 SWFDEC_LOG ("flv %p rendering offset %"G_GSIZE_FORMAT
", samples %"G_GSIZE_FORMAT
,
127 flv
, start
, n_samples
);
128 walk
= g_queue_peek_head_link (flv
->playback_queue
);
129 for (rendered
= 0; rendered
< n_samples
;) {
134 buffer
= swfdec_audio_flv_decode_one (flv
);
138 samples
= swfdec_sound_buffer_get_n_samples (buffer
,
139 swfdec_audio_format_new (44100, 2, TRUE
));
141 if (samples
<= start
) {
146 SWFDEC_LOG ("rendering %"G_GSIZE_FORMAT
" samples, skipping %"G_GSIZE_FORMAT
,
149 SWFDEC_LOG ("rendering %"G_GSIZE_FORMAT
" samples", samples
);
151 samples
= MIN (samples
, n_samples
- rendered
);
152 swfdec_sound_buffer_render (dest
, buffer
, start
, samples
);
161 swfdec_audio_flv_iterate (SwfdecAudio
*audio
, gsize remove
)
163 SwfdecAudioFlv
*flv
= SWFDEC_AUDIO_FLV (audio
);
164 SwfdecBuffer
*buffer
;
167 flv
->playback_skip
+= remove
;
168 buffer
= g_queue_peek_head (flv
->playback_queue
);
169 while (buffer
&& flv
->playback_skip
>=
170 swfdec_sound_buffer_get_n_samples (buffer
, swfdec_audio_format_new (44100, 2, TRUE
))
171 + swfdec_audio_format_get_granularity (swfdec_audio_format_new (44100, 2, TRUE
))) {
172 buffer
= g_queue_pop_head (flv
->playback_queue
);
173 SWFDEC_LOG ("removing buffer with %u samples",
174 swfdec_sound_buffer_get_n_samples (buffer
, swfdec_audio_format_new (44100, 2, TRUE
)));
175 flv
->playback_skip
-= swfdec_sound_buffer_get_n_samples (buffer
,
176 swfdec_audio_format_new (44100, 2, TRUE
));
177 swfdec_buffer_unref (buffer
);
178 buffer
= g_queue_peek_head (flv
->playback_queue
);
180 flv
->timestamp
+= SWFDEC_SAMPLES_TO_TICKS (remove
);
182 if (!g_queue_is_empty (flv
->playback_queue
))
184 swfdec_flv_decoder_get_audio (flv
->flvdecoder
,
185 SWFDEC_TICKS_TO_MSECS (flv
->timestamp
),
186 NULL
, NULL
, NULL
, &next
);
187 return next
? G_MAXUINT
: 0;
191 swfdec_audio_flv_class_init (SwfdecAudioFlvClass
*klass
)
193 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
194 SwfdecAudioClass
*audio_class
= SWFDEC_AUDIO_CLASS (klass
);
196 object_class
->dispose
= swfdec_audio_flv_dispose
;
198 audio_class
->iterate
= swfdec_audio_flv_iterate
;
199 audio_class
->render
= swfdec_audio_flv_render
;
203 swfdec_audio_flv_init (SwfdecAudioFlv
*flv
)
205 flv
->playback_queue
= g_queue_new ();
209 swfdec_audio_flv_new (SwfdecPlayer
*player
, SwfdecFlvDecoder
*decoder
, guint timestamp
)
213 flv
= g_object_new (SWFDEC_TYPE_AUDIO_FLV
, NULL
);
215 SWFDEC_DEBUG ("new audio flv for decoder %p, starting at %ums",
217 g_object_ref (decoder
);
218 flv
->flvdecoder
= decoder
;
219 flv
->timestamp
= SWFDEC_MSECS_TO_TICKS (timestamp
);
220 swfdec_audio_add (SWFDEC_AUDIO (flv
), player
);
222 return SWFDEC_AUDIO (flv
);