📄 swfdec_sound.c
字号:
/* Swfdec * Copyright (C) 2003-2006 David Schleef <ds@schleef.org> * 2005-2006 Eric Anholt <eric@anholt.net> * 2006-2007 Benjamin Otte <otte@gnome.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <string.h>#include "swfdec_audio_internal.h"#include "swfdec_sound.h"#include "swfdec_bits.h"#include "swfdec_buffer.h"#include "swfdec_button.h"#include "swfdec_debug.h"#include "swfdec_sprite.h"#include "swfdec_swf_decoder.h"G_DEFINE_TYPE (SwfdecSound, swfdec_sound, SWFDEC_TYPE_CACHED)static voidswfdec_sound_unload (SwfdecCached *cached){ SwfdecSound * sound = SWFDEC_SOUND (cached); if (sound->decoded) { swfdec_buffer_unref (sound->decoded); sound->decoded = NULL; }}static voidswfdec_sound_dispose (GObject *object){ SwfdecSound * sound = SWFDEC_SOUND (object); if (sound->encoded) swfdec_buffer_unref (sound->encoded); G_OBJECT_CLASS (swfdec_sound_parent_class)->dispose (object);}static voidswfdec_sound_class_init (SwfdecSoundClass * g_class){ GObjectClass *object_class = G_OBJECT_CLASS (g_class); SwfdecCachedClass *cached_class = SWFDEC_CACHED_CLASS (g_class); object_class->dispose = swfdec_sound_dispose; cached_class->unload = swfdec_sound_unload;}static voidswfdec_sound_init (SwfdecSound * sound){}inttag_func_sound_stream_block (SwfdecSwfDecoder * s, guint tag){ SwfdecSound *sound; SwfdecBuffer *chunk; int n_samples; int skip; sound = SWFDEC_SOUND (s->parse_sprite->frames[s->parse_sprite->parse_frame].sound_head); if (!sound) { SWFDEC_WARNING ("no streaming sound block"); return SWFDEC_STATUS_OK; } n_samples = swfdec_bits_get_u16 (&s->b); if (sound->format == SWFDEC_AUDIO_FORMAT_MP3) { skip = swfdec_bits_get_s16 (&s->b); } else { skip = 0; } if (swfdec_bits_left (&s->b) == 0) { SWFDEC_DEBUG ("empty sound block n_samples=%d skip=%d", n_samples, skip); chunk = NULL; return SWFDEC_STATUS_OK; } else { chunk = swfdec_bits_get_buffer (&s->b, -1); if (chunk == NULL) { SWFDEC_ERROR ("empty sound chunk"); return SWFDEC_STATUS_OK; } SWFDEC_LOG ("got a buffer with %u samples, %d skip and %u bytes mp3 data", n_samples, skip, chunk->length); /* use this to write out the stream data to stdout - nice way to get an mp3 file :) */ //write (1, (void *) chunk->data, chunk->length); } swfdec_sprite_add_sound_chunk (s->parse_sprite, s->parse_sprite->parse_frame, chunk, skip, n_samples); return SWFDEC_STATUS_OK;}inttag_func_define_sound (SwfdecSwfDecoder * s, guint tag){ SwfdecBits *b = &s->b; int id; int format; int rate; int size; int type; int n_samples; SwfdecSound *sound; id = swfdec_bits_get_u16 (b); format = swfdec_bits_getbits (b, 4); rate = swfdec_bits_getbits (b, 2); size = swfdec_bits_getbits (b, 1); type = swfdec_bits_getbits (b, 1); n_samples = swfdec_bits_get_u32 (b); sound = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_SOUND); if (!sound) return SWFDEC_STATUS_OK; sound->width = size; rate = 1 << (3 - rate); sound->original_format = SWFDEC_AUDIO_OUT_GET (type ? 2 : 1, 44100 / rate); sound->n_samples = n_samples; SWFDEC_DEBUG ("%u samples, %sLE, %uch, %ukHz", n_samples, size ? "S16" : "U8", SWFDEC_AUDIO_OUT_N_CHANNELS (sound->original_format), SWFDEC_AUDIO_OUT_RATE (sound->original_format)); switch (format) { case 0: if (size == 1) SWFDEC_WARNING ("undefined endianness for s16 sound"); /* just assume LE and hope it works (FIXME: want a switch for this?) */ /* fall through */ case 3: sound->format = SWFDEC_AUDIO_FORMAT_UNCOMPRESSED; sound->encoded = swfdec_bits_get_buffer (&s->b, -1); break; case 2: sound->format = SWFDEC_AUDIO_FORMAT_MP3; sound->skip = swfdec_bits_get_u16 (b); sound->encoded = swfdec_bits_get_buffer (&s->b, -1); break; case 1: case 5: case 6: sound->format = format; sound->encoded = swfdec_bits_get_buffer (&s->b, -1); break; default: SWFDEC_WARNING ("unknown format %d", format); sound->format = format; } sound->n_samples *= rate; return SWFDEC_STATUS_OK;}static SwfdecBuffer *swfdec_sound_get_decoded (SwfdecSound *sound, SwfdecAudioOut *format){ gpointer decoder; SwfdecBuffer *tmp; SwfdecBufferQueue *queue; guint sample_bytes; g_return_val_if_fail (SWFDEC_IS_SOUND (sound), NULL); g_return_val_if_fail (format != NULL, NULL); if (sound->decoded) { swfdec_cached_use (SWFDEC_CACHED (sound)); *format = sound->decoded_format; return sound->decoded; } if (sound->encoded == NULL) return NULL; decoder = swfdec_audio_decoder_new (sound->format, sound->width, sound->original_format); if (decoder == NULL) return NULL; sound->decoded_format = swfdec_audio_decoder_get_format (decoder); sample_bytes = 2 * SWFDEC_AUDIO_OUT_N_CHANNELS (sound->decoded_format); /* FIXME: The size is only a guess */ swfdec_cached_load (SWFDEC_CACHED (sound), sound->n_samples * sample_bytes); swfdec_audio_decoder_push (decoder, sound->encoded); swfdec_audio_decoder_push (decoder, NULL); queue = swfdec_buffer_queue_new (); while ((tmp = swfdec_audio_decoder_pull (decoder))) swfdec_buffer_queue_push (queue, tmp); swfdec_audio_decoder_free (decoder); tmp = swfdec_buffer_queue_pull (queue, swfdec_buffer_queue_get_depth (queue)); swfdec_buffer_queue_unref (queue); SWFDEC_LOG ("after decoding, got %u samples, should get %u and skip %u", tmp->length / sample_bytes, sound->n_samples, sound->skip); if (sound->skip) { SwfdecBuffer *tmp2 = swfdec_buffer_new_subbuffer (tmp, sound->skip * sample_bytes, tmp->length - sound->skip * sample_bytes); swfdec_buffer_unref (tmp); tmp = tmp2; } /* sound buffer may be bigger due to mp3 not having sample boundaries */ if (tmp->length * SWFDEC_AUDIO_OUT_GRANULARITY (sound->decoded_format) > sound->n_samples * sample_bytes) { SwfdecBuffer *tmp2 = swfdec_buffer_new_subbuffer (tmp, 0, sound->n_samples * sample_bytes / SWFDEC_AUDIO_OUT_GRANULARITY (sound->decoded_format)); swfdec_buffer_unref (tmp); tmp = tmp2; } if (tmp->length * SWFDEC_AUDIO_OUT_GRANULARITY (sound->decoded_format) < sound->n_samples * sample_bytes) { /* we handle this case in swfdec_sound_render */ /* FIXME: this message is important when writing new codecs, so I made it a warning. * It's probably not worth more than INFO for the usual case though */ SWFDEC_WARNING ("%u samples in %u bytes should be available, but only %u bytes are", sound->n_samples / SWFDEC_AUDIO_OUT_GRANULARITY (sound->decoded_format), sound->n_samples * sample_bytes / SWFDEC_AUDIO_OUT_GRANULARITY (sound->decoded_format), tmp->length); } /* only assign here, the decoding code checks this variable */ sound->decoded = tmp; *format = sound->decoded_format; return sound->decoded;}inttag_func_sound_stream_head (SwfdecSwfDecoder * s, guint tag){ SwfdecBits *b = &s->b; int format; int rate; int size; int type; int n_samples; int latency; SwfdecSound *sound; /* we don't care about playback suggestions */ swfdec_bits_getbits (b, 8); format = swfdec_bits_getbits (b, 4); rate = swfdec_bits_getbits (b, 2); size = swfdec_bits_getbits (b, 1); type = swfdec_bits_getbits (b, 1); n_samples = swfdec_bits_get_u16 (b); sound = g_object_new (SWFDEC_TYPE_SOUND, NULL); if (s->parse_sprite->frames[s->parse_sprite->parse_frame].sound_head) g_object_unref (s->parse_sprite->frames[s->parse_sprite->parse_frame].sound_head); s->parse_sprite->frames[s->parse_sprite->parse_frame].sound_head = sound; sound->width = size; sound->original_format = SWFDEC_AUDIO_OUT_GET (type ? 2 : 1, 44100 / (1 << (3 - rate))); switch (format) { case 0: if (size == 1) SWFDEC_WARNING ("undefined endianness for s16 sound"); /* just assume LE and hope it works (FIXME: want a switch for this?) */ /* fall through */ case 3: sound->format = SWFDEC_AUDIO_FORMAT_UNCOMPRESSED; break; case 1: sound->format = SWFDEC_AUDIO_FORMAT_ADPCM; break; case 2: sound->format = SWFDEC_AUDIO_FORMAT_MP3; /* latency seek */ latency = swfdec_bits_get_s16 (b); break; case 6: sound->format = SWFDEC_AUDIO_FORMAT_NELLYMOSER; break; default: SWFDEC_WARNING ("unknown format %d", format); sound->format = format; } return SWFDEC_STATUS_OK;}void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -