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 /* This is a hack that ensures AAC codec data is always present, even if
99 * the decoder gets initialized in the middle of the stream */
100 if (format
== SWFDEC_AUDIO_CODEC_AAC
) {
101 SwfdecBuffer
*tmp
= swfdec_flv_decoder_get_audio (flv
->flvdecoder
,
102 0, &format
, NULL
, NULL
, NULL
);
103 if (format
== SWFDEC_AUDIO_CODEC_AAC
&& tmp
->data
[0] == 0 &&
105 tmp
= swfdec_buffer_new_subbuffer (tmp
, 1, tmp
->length
- 1);
106 swfdec_audio_decoder_set_codec_data (flv
->decoder
, tmp
);
107 swfdec_buffer_unref (tmp
);
110 } else if (format
!= flv
->format
||
112 SWFDEC_ERROR ("FIXME: format change not implemented");
114 } else if (flv
->decoder
== NULL
) {
117 if (format
== SWFDEC_AUDIO_CODEC_AAC
) {
121 swfdec_bits_init (&bits
, buffer
);
122 type
= swfdec_bits_get_u8 (&bits
);
125 data
= swfdec_bits_get_buffer (&bits
, -1);
127 swfdec_audio_decoder_set_codec_data (flv
->decoder
, data
);
128 swfdec_buffer_unref (data
);
132 data
= swfdec_bits_get_buffer (&bits
, -1);
134 swfdec_audio_decoder_push (flv
->decoder
, data
);
135 swfdec_buffer_unref (data
);
137 SWFDEC_ERROR ("no data in AAC data buffer?");
141 SWFDEC_FIXME ("handle AAC type %u", type
);
145 swfdec_audio_decoder_push (flv
->decoder
, buffer
);
147 if (flv
->next_timestamp
== 0)
148 swfdec_audio_decoder_push (flv
->decoder
, NULL
);
149 buffer
= swfdec_audio_decoder_pull (flv
->decoder
);
152 g_queue_push_tail (flv
->playback_queue
, buffer
);
157 swfdec_audio_flv_render (SwfdecAudio
*audio
, gint16
* dest
,
158 gsize start
, gsize n_samples
)
160 SwfdecAudioFlv
*flv
= SWFDEC_AUDIO_FLV (audio
);
162 gsize samples
, rendered
;
163 SwfdecBuffer
*buffer
;
165 g_assert (start
< G_MAXINT
);
166 start
+= flv
->playback_skip
;
167 SWFDEC_LOG ("flv %p rendering offset %"G_GSIZE_FORMAT
", samples %"G_GSIZE_FORMAT
,
168 flv
, start
, n_samples
);
169 walk
= g_queue_peek_head_link (flv
->playback_queue
);
170 for (rendered
= 0; rendered
< n_samples
;) {
175 buffer
= swfdec_audio_flv_decode_one (flv
);
179 samples
= swfdec_sound_buffer_get_n_samples (buffer
,
180 swfdec_audio_format_new (44100, 2, TRUE
));
182 if (samples
<= start
) {
187 SWFDEC_LOG ("rendering %"G_GSIZE_FORMAT
" samples, skipping %"G_GSIZE_FORMAT
,
190 SWFDEC_LOG ("rendering %"G_GSIZE_FORMAT
" samples", samples
);
192 samples
= MIN (samples
, n_samples
- rendered
);
193 swfdec_sound_buffer_render (dest
, buffer
, start
, samples
);
202 swfdec_audio_flv_iterate (SwfdecAudio
*audio
, gsize remove
)
204 SwfdecAudioFlv
*flv
= SWFDEC_AUDIO_FLV (audio
);
205 SwfdecBuffer
*buffer
;
208 flv
->playback_skip
+= remove
;
209 buffer
= g_queue_peek_head (flv
->playback_queue
);
210 while (buffer
&& flv
->playback_skip
>=
211 swfdec_sound_buffer_get_n_samples (buffer
, swfdec_audio_format_new (44100, 2, TRUE
))
212 + swfdec_audio_format_get_granularity (swfdec_audio_format_new (44100, 2, TRUE
))) {
213 buffer
= g_queue_pop_head (flv
->playback_queue
);
214 SWFDEC_LOG ("removing buffer with %u samples",
215 swfdec_sound_buffer_get_n_samples (buffer
, swfdec_audio_format_new (44100, 2, TRUE
)));
216 flv
->playback_skip
-= swfdec_sound_buffer_get_n_samples (buffer
,
217 swfdec_audio_format_new (44100, 2, TRUE
));
218 swfdec_buffer_unref (buffer
);
219 buffer
= g_queue_peek_head (flv
->playback_queue
);
221 flv
->timestamp
+= SWFDEC_SAMPLES_TO_TICKS (remove
);
223 if (!g_queue_is_empty (flv
->playback_queue
))
225 swfdec_flv_decoder_get_audio (flv
->flvdecoder
,
226 SWFDEC_TICKS_TO_MSECS (flv
->timestamp
),
227 NULL
, NULL
, NULL
, &next
);
228 return next
? G_MAXUINT
: 0;
232 swfdec_audio_flv_class_init (SwfdecAudioFlvClass
*klass
)
234 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
235 SwfdecAudioClass
*audio_class
= SWFDEC_AUDIO_CLASS (klass
);
237 object_class
->dispose
= swfdec_audio_flv_dispose
;
239 audio_class
->iterate
= swfdec_audio_flv_iterate
;
240 audio_class
->render
= swfdec_audio_flv_render
;
244 swfdec_audio_flv_init (SwfdecAudioFlv
*flv
)
246 flv
->playback_queue
= g_queue_new ();
250 swfdec_audio_flv_new (SwfdecPlayer
*player
, SwfdecFlvDecoder
*decoder
, guint timestamp
)
254 flv
= g_object_new (SWFDEC_TYPE_AUDIO_FLV
, NULL
);
256 SWFDEC_DEBUG ("new audio flv for decoder %p, starting at %ums",
258 g_object_ref (decoder
);
259 flv
->flvdecoder
= decoder
;
260 flv
->timestamp
= SWFDEC_MSECS_TO_TICKS (timestamp
);
261 swfdec_audio_add (SWFDEC_AUDIO (flv
), player
);
263 return SWFDEC_AUDIO (flv
);