2 * Copyright (C) 2003, 2008 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
24 #include "swfdec_load_sound.h"
25 #include "swfdec_access.h"
26 #include "swfdec_as_strings.h"
27 #include "swfdec_audio_decoder.h"
28 #include "swfdec_audio_internal.h"
29 #include "swfdec_audio_load.h"
30 #include "swfdec_bits.h"
31 #include "swfdec_buffer.h"
32 #include "swfdec_debug.h"
33 #include "swfdec_loader_internal.h"
34 #include "swfdec_player_internal.h"
35 #include "swfdec_sandbox.h"
36 #include "swfdec_sound_provider.h"
37 #include "swfdec_stream_target.h"
39 /*** SWFDEC_SOUND_PROVIDER ***/
42 swfdec_load_sound_sound_provider_start (SwfdecSoundProvider
*provider
,
43 SwfdecActor
*actor
, gsize samples_offset
, guint loops
)
45 SwfdecLoadSound
*sound
= SWFDEC_LOAD_SOUND (provider
);
48 swfdec_audio_remove (sound
->audio
);
49 g_object_unref (sound
->audio
);
51 if (samples_offset
> 0 || loops
> 1) {
52 SWFDEC_FIXME ("implement starting at offset %"G_GSIZE_FORMAT
" with %u loops",
53 samples_offset
, loops
);
55 sound
->audio
= swfdec_audio_load_new (SWFDEC_PLAYER (swfdec_gc_object_get_context (actor
)), sound
);
56 swfdec_audio_set_matrix (sound
->audio
, &sound
->sound_matrix
);
60 swfdec_load_sound_sound_provider_stop (SwfdecSoundProvider
*provider
, SwfdecActor
*actor
)
62 SwfdecLoadSound
*sound
= SWFDEC_LOAD_SOUND (provider
);
64 if (sound
->audio
== NULL
)
67 swfdec_audio_set_matrix (sound
->audio
, NULL
);
68 swfdec_audio_remove (sound
->audio
);
69 g_object_unref (sound
->audio
);
73 static SwfdecSoundMatrix
*
74 swfdec_load_sound_sound_provider_get_matrix (SwfdecSoundProvider
*provider
)
76 SwfdecLoadSound
*sound
= SWFDEC_LOAD_SOUND (provider
);
78 return &sound
->sound_matrix
;
82 swfdec_load_sound_sound_provider_init (SwfdecSoundProviderInterface
*iface
)
84 iface
->start
= swfdec_load_sound_sound_provider_start
;
85 iface
->stop
= swfdec_load_sound_sound_provider_stop
;
86 iface
->get_matrix
= swfdec_load_sound_sound_provider_get_matrix
;
89 /*** SWFDEC_STREAM_TARGET ***/
92 swfdec_load_sound_stream_target_get_player (SwfdecStreamTarget
*target
)
94 return SWFDEC_PLAYER (swfdec_gc_object_get_context (SWFDEC_LOAD_SOUND (target
)->target
));
98 swfdec_load_sound_mp3_parse_id3v2 (SwfdecLoadSound
*sound
, SwfdecBufferQueue
*queue
)
100 SwfdecBuffer
*buffer
;
105 buffer
= swfdec_buffer_queue_peek (queue
, 10);
108 swfdec_bits_init (&bits
, buffer
);
109 if (swfdec_bits_get_u8 (&bits
) != 'I' ||
110 swfdec_bits_get_u8 (&bits
) != 'D' ||
111 swfdec_bits_get_u8 (&bits
) != '3')
113 /* version = */ swfdec_bits_get_u16 (&bits
);
114 /* flags = */ swfdec_bits_getbits (&bits
, 3);
115 footer
= swfdec_bits_getbit (&bits
);
116 /* reserved = */ swfdec_bits_getbits (&bits
, 4);
117 size
= swfdec_bits_get_bu32 (&bits
);
118 if (size
& 0x80808080)
120 size
= ((size
& 0xFF000000) >> 3) |
121 ((size
& 0xFF0000) >> 2) |
122 ((size
& 0xFF00) >> 1) | (size
& 0xFF);
123 swfdec_buffer_unref (buffer
);
125 buffer
= swfdec_buffer_queue_pull (queue
, 10 + size
+ (footer
? 10 : 0));
128 SWFDEC_FIXME ("implement ID3v2 parsing");
129 SWFDEC_LOG ("%"G_GSIZE_FORMAT
" bytes ID3v2", buffer
->length
);
130 swfdec_buffer_unref (buffer
);
134 swfdec_buffer_unref (buffer
);
135 swfdec_buffer_queue_flush (queue
, 1);
140 swfdec_load_sound_mp3_parse_id3v1 (SwfdecLoadSound
*sound
, SwfdecBufferQueue
*queue
)
142 SwfdecBuffer
*buffer
;
144 buffer
= swfdec_buffer_queue_pull (queue
, 128);
148 if (buffer
->data
[0] != 'T' ||
149 buffer
->data
[1] != 'A' ||
150 buffer
->data
[2] != 'G') {
151 swfdec_buffer_unref (buffer
);
152 swfdec_buffer_queue_flush (queue
, 1);
155 SWFDEC_FIXME ("implement ID3v1 parsing");
156 swfdec_buffer_unref (buffer
);
161 swfdec_load_sound_mp3_parse_frame (SwfdecLoadSound
*sound
, SwfdecBufferQueue
*queue
)
163 static const guint mp3types_bitrates
[2][3][16] = {
164 { {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, },
165 {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, },
166 {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, }},
167 { {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, },
168 {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, },
169 {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, }}
171 static const guint mp3types_freqs
[3][3] = {
172 { 11025, 12000, 8000 },
173 { 22050, 24000, 16000 },
174 { 44100, 48000, 32000 }
177 SwfdecBuffer
*buffer
;
179 guint version
, layer
, bitrate
, samplerate
, length
, channels
;
181 buffer
= swfdec_buffer_queue_peek (queue
, 4);
185 swfdec_bits_init (&bits
, buffer
);
186 if (swfdec_bits_getbits (&bits
, 11) != 0x7FF)
189 version
= swfdec_bits_getbits (&bits
, 2);
192 layer
= 4 - swfdec_bits_getbits (&bits
, 2);
195 /* has_crc = */ swfdec_bits_getbit (&bits
);
196 bitrate
= swfdec_bits_getbits (&bits
, 4);
197 if (bitrate
== 0 || bitrate
== 15) {
199 SWFDEC_FIXME ("need to support free frame length?");
203 samplerate
= swfdec_bits_getbits (&bits
, 2);
206 length
= swfdec_bits_getbits (&bits
, 1);
207 /* unused = */ swfdec_bits_getbits (&bits
, 1);
208 channels
= swfdec_bits_getbits (&bits
, 2) == 3 ? 1 : 2;
210 samplerate
= mp3types_freqs
[version
> 0 ? version
- 1 : 0][samplerate
];
211 bitrate
= mp3types_bitrates
[version
== 3 ? 0 : 1][layer
- 1][bitrate
];
213 length
= ((12000 * bitrate
/ samplerate
) + length
) * 4;
215 length
+= ((layer
== 3 && version
!= 3) ? 72000 : 144000)
216 * bitrate
/ samplerate
;
218 swfdec_buffer_unref (buffer
);
220 SWFDEC_LOG ("adding %u bytes mp3 frame", length
);
221 buffer
= swfdec_buffer_queue_pull (queue
, length
);
225 g_ptr_array_add (sound
->frames
, buffer
);
229 swfdec_buffer_unref (buffer
);
230 swfdec_buffer_queue_flush (queue
, 1);
235 swfdec_load_sound_stream_target_parse (SwfdecStreamTarget
*target
,
236 SwfdecStream
*stream
)
238 SwfdecLoadSound
*sound
= SWFDEC_LOAD_SOUND (target
);
239 SwfdecBufferQueue
*queue
;
240 SwfdecBuffer
*buffer
;
242 gboolean go_on
= TRUE
;
244 /* decode MP3 into frames, ID3 tags and crap */
245 queue
= swfdec_stream_get_queue (stream
);
248 buffer
= swfdec_buffer_queue_peek_buffer (queue
);
251 for (i
= 0; i
< buffer
->length
; i
++) {
252 if (buffer
->data
[i
] == 'I' || buffer
->data
[i
] == 'T' || buffer
->data
[i
] == 0xFF)
256 SWFDEC_LOG ("sync: flushing %u bytes", i
);
258 swfdec_buffer_queue_flush (queue
, i
);
259 if (i
== buffer
->length
) {
260 swfdec_buffer_unref (buffer
);
264 switch (buffer
->data
[i
]) {
267 go_on
= swfdec_load_sound_mp3_parse_id3v2 (sound
, queue
);
271 go_on
= swfdec_load_sound_mp3_parse_id3v1 (sound
, queue
);
275 go_on
= swfdec_load_sound_mp3_parse_frame (sound
, queue
);
278 /* skip - and yes, the continue refers to the for loop */
281 swfdec_buffer_unref (buffer
);
287 swfdec_load_sound_stream_target_error (SwfdecStreamTarget
*target
,
288 SwfdecStream
*stream
)
290 SwfdecLoadSound
*sound
= SWFDEC_LOAD_SOUND (target
);
293 SWFDEC_AS_VALUE_SET_BOOLEAN (&val
, FALSE
);
294 swfdec_sandbox_use (sound
->sandbox
);
295 swfdec_as_object_call (sound
->target
, SWFDEC_AS_STR_onLoad
, 1, &val
, NULL
);
296 swfdec_sandbox_unuse (sound
->sandbox
);
298 swfdec_stream_set_target (stream
, NULL
);
299 g_object_unref (stream
);
300 sound
->stream
= NULL
;
304 swfdec_load_sound_stream_target_close (SwfdecStreamTarget
*target
,
305 SwfdecStream
*stream
)
307 SwfdecLoadSound
*sound
= SWFDEC_LOAD_SOUND (target
);
310 swfdec_stream_set_target (stream
, NULL
);
311 g_object_unref (stream
);
312 sound
->stream
= NULL
;
314 SWFDEC_AS_VALUE_SET_BOOLEAN (&val
, TRUE
);
315 swfdec_sandbox_use (sound
->sandbox
);
316 swfdec_as_object_call (sound
->target
, SWFDEC_AS_STR_onLoad
, 1, &val
, NULL
);
317 swfdec_sandbox_unuse (sound
->sandbox
);
321 swfdec_load_sound_stream_target_init (SwfdecStreamTargetInterface
*iface
)
323 iface
->get_player
= swfdec_load_sound_stream_target_get_player
;
324 iface
->parse
= swfdec_load_sound_stream_target_parse
;
325 iface
->close
= swfdec_load_sound_stream_target_close
;
326 iface
->error
= swfdec_load_sound_stream_target_error
;
329 /*** SWFDEC_LOAD_SOUND ***/
331 G_DEFINE_TYPE_WITH_CODE (SwfdecLoadSound
, swfdec_load_sound
, G_TYPE_OBJECT
,
332 G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_STREAM_TARGET
, swfdec_load_sound_stream_target_init
);
333 G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_SOUND_PROVIDER
, swfdec_load_sound_sound_provider_init
))
336 swfdec_load_sound_dispose (GObject
*object
)
338 SwfdecLoadSound
*sound
= SWFDEC_LOAD_SOUND (object
);
340 g_ptr_array_foreach (sound
->frames
, (GFunc
) swfdec_buffer_unref
, NULL
);
341 g_ptr_array_free (sound
->frames
, TRUE
);
343 swfdec_stream_set_target (sound
->stream
, NULL
);
344 g_object_unref (sound
->stream
);
345 sound
->stream
= NULL
;
349 swfdec_audio_set_matrix (sound
->audio
, NULL
);
350 swfdec_audio_remove (sound
->audio
);
351 g_object_unref (sound
->audio
);
355 G_OBJECT_CLASS (swfdec_load_sound_parent_class
)->dispose (object
);
359 swfdec_load_sound_class_init (SwfdecLoadSoundClass
*klass
)
361 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
363 object_class
->dispose
= swfdec_load_sound_dispose
;
367 swfdec_load_sound_init (SwfdecLoadSound
*sound
)
369 sound
->frames
= g_ptr_array_new ();
371 swfdec_sound_matrix_init_identity (&sound
->sound_matrix
);
375 swfdec_load_sound_load (SwfdecPlayer
*player
, gboolean allow
, gpointer data
)
377 SwfdecLoadSound
*sound
= data
;
382 SWFDEC_WARNING ("SECURITY: no access to %s from Sound.loadSound",
384 SWFDEC_AS_VALUE_SET_BOOLEAN (&val
, FALSE
);
388 sound
->stream
= SWFDEC_STREAM (swfdec_player_load (player
, sound
->url
, NULL
));
389 swfdec_stream_set_target (sound
->stream
, SWFDEC_STREAM_TARGET (sound
));
392 static const SwfdecAccessMatrix swfdec_load_sound_matrix
= {
393 { SWFDEC_ACCESS_NO
, SWFDEC_ACCESS_NO
, SWFDEC_ACCESS_NO
},
394 { SWFDEC_ACCESS_NO
, SWFDEC_ACCESS_YES
, SWFDEC_ACCESS_YES
},
395 { SWFDEC_ACCESS_YES
, SWFDEC_ACCESS_NO
, SWFDEC_ACCESS_NO
},
396 { SWFDEC_ACCESS_YES
, SWFDEC_ACCESS_YES
, SWFDEC_ACCESS_YES
},
397 { SWFDEC_ACCESS_YES
, SWFDEC_ACCESS_YES
, SWFDEC_ACCESS_YES
}
401 swfdec_load_sound_new (SwfdecAsObject
*target
, const char *url
)
403 SwfdecLoadSound
*sound
;
404 SwfdecAsContext
*context
;
407 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (target
), NULL
);
408 g_return_val_if_fail (url
!= NULL
, NULL
);
410 context
= swfdec_gc_object_get_context (target
);
411 sound
= g_object_new (SWFDEC_TYPE_LOAD_SOUND
, NULL
);
412 sound
->target
= target
;
413 sound
->sandbox
= SWFDEC_SANDBOX (context
->global
);
414 sound
->url
= g_strdup (url
);
415 g_assert (sound
->sandbox
);
416 swfdec_player_allow_by_matrix (SWFDEC_PLAYER (context
), sound
->sandbox
,
417 url
, swfdec_load_sound_matrix
, swfdec_load_sound_load
, sound
);
418 /* tell missing plugins stuff we want MP3 */
420 swfdec_audio_decoder_prepare (SWFDEC_AUDIO_CODEC_MP3
,
421 swfdec_audio_format_new (44100, 2, TRUE
), &missing
);
423 swfdec_player_add_missing_plugin (SWFDEC_PLAYER (context
),