diff options
Diffstat (limited to 'src/decoder/vorbis_decoder_plugin.c')
-rw-r--r-- | src/decoder/vorbis_decoder_plugin.c | 115 |
1 files changed, 76 insertions, 39 deletions
diff --git a/src/decoder/vorbis_decoder_plugin.c b/src/decoder/vorbis_decoder_plugin.c index 15cdc0ca9..f180a6559 100644 --- a/src/decoder/vorbis_decoder_plugin.c +++ b/src/decoder/vorbis_decoder_plugin.c @@ -19,7 +19,7 @@ #include "config.h" #include "vorbis_comments.h" -#include "_ogg_common.h" +#include "ogg_codec.h" #include "audio_check.h" #include "uri.h" #include "tag_handler.h" @@ -48,12 +48,11 @@ #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "vorbis" -#define OGG_CHUNK_SIZE 4096 #if G_BYTE_ORDER == G_BIG_ENDIAN -#define OGG_DECODE_USE_BIGENDIAN 1 +#define VORBIS_BIG_ENDIAN true #else -#define OGG_DECODE_USE_BIGENDIAN 0 +#define VORBIS_BIG_ENDIAN false #endif struct vorbis_input_stream { @@ -66,9 +65,8 @@ struct vorbis_input_stream { static size_t ogg_read_cb(void *ptr, size_t size, size_t nmemb, void *data) { struct vorbis_input_stream *vis = data; - size_t ret; - - ret = decoder_read(vis->decoder, vis->input_stream, ptr, size * nmemb); + size_t ret = decoder_read(vis->decoder, vis->input_stream, + ptr, size * nmemb); errno = 0; @@ -155,9 +153,7 @@ static void vorbis_send_comments(struct decoder *decoder, struct input_stream *is, char **comments) { - struct tag *tag; - - tag = vorbis_comments_to_tag(comments); + struct tag *tag = vorbis_comments_to_tag(comments); if (!tag) return; @@ -165,55 +161,79 @@ vorbis_send_comments(struct decoder *decoder, struct input_stream *is, tag_free(tag); } +#ifndef HAVE_TREMOR +static void +vorbis_interleave(float *dest, const float *const*src, + unsigned nframes, unsigned channels) +{ + for (const float *const*src_end = src + channels; + src != src_end; ++src, ++dest) { + float *d = dest; + for (const float *s = *src, *s_end = s + nframes; + s != s_end; ++s, d += channels) + *d = *s; + } +} +#endif + /* public */ static void vorbis_stream_decode(struct decoder *decoder, struct input_stream *input_stream) { GError *error = NULL; - OggVorbis_File vf; - struct vorbis_input_stream vis; - struct audio_format audio_format; - float total_time; - int current_section; - int prev_section = -1; - long ret; - char chunk[OGG_CHUNK_SIZE]; - long bitRate = 0; - long test; - const vorbis_info *vi; - enum decoder_command cmd = DECODE_COMMAND_NONE; - - if (ogg_stream_type_detect(input_stream) != VORBIS) + + if (ogg_codec_detect(decoder, input_stream) != OGG_CODEC_VORBIS) return; - /* rewind the stream, because ogg_stream_type_detect() has + /* rewind the stream, because ogg_codec_detect() has moved it */ input_stream_lock_seek(input_stream, 0, SEEK_SET, NULL); + struct vorbis_input_stream vis; + OggVorbis_File vf; if (!vorbis_is_open(&vis, &vf, decoder, input_stream)) return; - vi = ov_info(&vf, -1); + const vorbis_info *vi = ov_info(&vf, -1); if (vi == NULL) { g_warning("ov_info() has failed"); return; } + struct audio_format audio_format; if (!audio_format_init_checked(&audio_format, vi->rate, +#ifdef HAVE_TREMOR SAMPLE_FORMAT_S16, +#else + SAMPLE_FORMAT_FLOAT, +#endif vi->channels, &error)) { g_warning("%s", error->message); g_error_free(error); return; } - total_time = ov_time_total(&vf, -1); + float total_time = ov_time_total(&vf, -1); if (total_time < 0) total_time = 0; decoder_initialized(decoder, &audio_format, vis.seekable, total_time); + enum decoder_command cmd = decoder_get_command(decoder); + +#ifdef HAVE_TREMOR + char buffer[4096]; +#else + float buffer[2048]; + const int frames_per_buffer = + G_N_ELEMENTS(buffer) / audio_format.channels; + const unsigned frame_size = sizeof(buffer[0]) * audio_format.channels; +#endif + + int prev_section = -1; + unsigned kbit_rate = 0; + do { if (cmd == DECODE_COMMAND_SEEK) { double seek_where = decoder_seek_where(decoder); @@ -223,17 +243,33 @@ vorbis_stream_decode(struct decoder *decoder, decoder_seek_error(decoder); } - ret = ov_read(&vf, chunk, sizeof(chunk), - OGG_DECODE_USE_BIGENDIAN, 2, 1, ¤t_section); - if (ret == OV_HOLE) /* bad packet */ - ret = 0; - else if (ret <= 0) + int current_section; + +#ifdef HAVE_TREMOR + long nbytes = ov_read(&vf, buffer, sizeof(buffer), + VORBIS_BIG_ENDIAN, 2, 1, + ¤t_section); +#else + float **per_channel; + long nframes = ov_read_float(&vf, &per_channel, + frames_per_buffer, + ¤t_section); + long nbytes = nframes; + if (nframes > 0) { + vorbis_interleave(buffer, + (const float*const*)per_channel, + nframes, audio_format.channels); + nbytes *= frame_size; + } +#endif + + if (nbytes == OV_HOLE) /* bad packet */ + nbytes = 0; + else if (nbytes <= 0) /* break on EOF or other error */ break; if (current_section != prev_section) { - char **comments; - vi = ov_info(&vf, -1); if (vi == NULL) { g_warning("ov_info() has failed"); @@ -248,7 +284,7 @@ vorbis_stream_decode(struct decoder *decoder, break; } - comments = ov_comment(&vf, -1)->user_comments; + char **comments = ov_comment(&vf, -1)->user_comments; vorbis_send_comments(decoder, input_stream, comments); struct replay_gain_info rgi; @@ -258,12 +294,13 @@ vorbis_stream_decode(struct decoder *decoder, prev_section = current_section; } - if ((test = ov_bitrate_instant(&vf)) > 0) - bitRate = test / 1000; + long test = ov_bitrate_instant(&vf); + if (test > 0) + kbit_rate = test / 1000; cmd = decoder_data(decoder, input_stream, - chunk, ret, - bitRate); + buffer, nbytes, + kbit_rate); } while (cmd != DECODE_COMMAND_STOP); ov_clear(&vf); |