diff options
Diffstat (limited to 'src/decoder/VorbisDecoderPlugin.cxx')
-rw-r--r-- | src/decoder/VorbisDecoderPlugin.cxx | 352 |
1 files changed, 0 insertions, 352 deletions
diff --git a/src/decoder/VorbisDecoderPlugin.cxx b/src/decoder/VorbisDecoderPlugin.cxx deleted file mode 100644 index 4d3e48528..000000000 --- a/src/decoder/VorbisDecoderPlugin.cxx +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (C) 2003-2013 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "VorbisDecoderPlugin.h" -#include "VorbisComments.hxx" -#include "VorbisDomain.hxx" -#include "DecoderAPI.hxx" -#include "InputStream.hxx" -#include "OggCodec.hxx" -#include "util/Error.hxx" -#include "util/UriUtil.hxx" -#include "util/Macros.hxx" -#include "system/ByteOrder.hxx" -#include "CheckAudioFormat.hxx" -#include "tag/TagHandler.hxx" -#include "Log.hxx" - -#ifndef HAVE_TREMOR -#define OV_EXCLUDE_STATIC_CALLBACKS -#include <vorbis/vorbisfile.h> -#else -#include <tremor/ivorbisfile.h> -/* Macros to make Tremor's API look like libogg. Tremor always - returns host-byte-order 16-bit signed data, and uses integer - milliseconds where libogg uses double seconds. -*/ -#define ov_read(VF, BUFFER, LENGTH, BIGENDIANP, WORD, SGNED, BITSTREAM) \ - ov_read(VF, BUFFER, LENGTH, BITSTREAM) -#define ov_time_total(VF, I) ((double)ov_time_total(VF, I)/1000) -#define ov_time_tell(VF) ((double)ov_time_tell(VF)/1000) -#define ov_time_seek_page(VF, S) (ov_time_seek_page(VF, (S)*1000)) -#endif /* HAVE_TREMOR */ - -#include <assert.h> -#include <errno.h> - -struct vorbis_input_stream { - Decoder *decoder; - - InputStream *input_stream; - bool seekable; -}; - -static size_t ogg_read_cb(void *ptr, size_t size, size_t nmemb, void *data) -{ - struct vorbis_input_stream *vis = (struct vorbis_input_stream *)data; - size_t ret = decoder_read(vis->decoder, *vis->input_stream, - ptr, size * nmemb); - - errno = 0; - - return ret / size; -} - -static int ogg_seek_cb(void *data, ogg_int64_t offset, int whence) -{ - struct vorbis_input_stream *vis = (struct vorbis_input_stream *)data; - - Error error; - return vis->seekable && - (vis->decoder == nullptr || - decoder_get_command(*vis->decoder) != DecoderCommand::STOP) && - vis->input_stream->LockSeek(offset, whence, error) - ? 0 : -1; -} - -/* TODO: check Ogg libraries API and see if we can just not have this func */ -static int ogg_close_cb(gcc_unused void *data) -{ - return 0; -} - -static long ogg_tell_cb(void *data) -{ - struct vorbis_input_stream *vis = (struct vorbis_input_stream *)data; - - return (long)vis->input_stream->offset; -} - -static const ov_callbacks vorbis_is_callbacks = { - ogg_read_cb, - ogg_seek_cb, - ogg_close_cb, - ogg_tell_cb, -}; - -static const char * -vorbis_strerror(int code) -{ - switch (code) { - case OV_EREAD: - return "read error"; - - case OV_ENOTVORBIS: - return "not vorbis stream"; - - case OV_EVERSION: - return "vorbis version mismatch"; - - case OV_EBADHEADER: - return "invalid vorbis header"; - - case OV_EFAULT: - return "internal logic error"; - - default: - return "unknown error"; - } -} - -static bool -vorbis_is_open(struct vorbis_input_stream *vis, OggVorbis_File *vf, - Decoder *decoder, InputStream &input_stream) -{ - vis->decoder = decoder; - vis->input_stream = &input_stream; - vis->seekable = input_stream.CheapSeeking(); - - int ret = ov_open_callbacks(vis, vf, nullptr, 0, vorbis_is_callbacks); - if (ret < 0) { - if (decoder == nullptr || - decoder_get_command(*decoder) == DecoderCommand::NONE) - FormatWarning(vorbis_domain, - "Failed to open Ogg Vorbis stream: %s", - vorbis_strerror(ret)); - return false; - } - - return true; -} - -static void -vorbis_send_comments(Decoder &decoder, InputStream &is, - char **comments) -{ - Tag *tag = vorbis_comments_to_tag(comments); - if (!tag) - return; - - decoder_tag(decoder, is, std::move(*tag)); - delete 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(Decoder &decoder, - InputStream &input_stream) -{ - if (ogg_codec_detect(&decoder, input_stream) != OGG_CODEC_VORBIS) - return; - - /* rewind the stream, because ogg_codec_detect() has - moved it */ - input_stream.LockRewind(IgnoreError()); - - struct vorbis_input_stream vis; - OggVorbis_File vf; - if (!vorbis_is_open(&vis, &vf, &decoder, input_stream)) - return; - - const vorbis_info *vi = ov_info(&vf, -1); - if (vi == nullptr) { - LogWarning(vorbis_domain, "ov_info() has failed"); - return; - } - - Error error; - AudioFormat audio_format; - if (!audio_format_init_checked(audio_format, vi->rate, -#ifdef HAVE_TREMOR - SampleFormat::S16, -#else - SampleFormat::FLOAT, -#endif - vi->channels, error)) { - LogError(error); - return; - } - - float total_time = ov_time_total(&vf, -1); - if (total_time < 0) - total_time = 0; - - decoder_initialized(decoder, audio_format, vis.seekable, total_time); - -#ifdef HAVE_TREMOR - char buffer[4096]; -#else - float buffer[2048]; - const int frames_per_buffer = - ARRAY_SIZE(buffer) / audio_format.channels; - const unsigned frame_size = sizeof(buffer[0]) * audio_format.channels; -#endif - - int prev_section = -1; - unsigned kbit_rate = 0; - - DecoderCommand cmd = decoder_get_command(decoder); - do { - if (cmd == DecoderCommand::SEEK) { - double seek_where = decoder_seek_where(decoder); - if (0 == ov_time_seek_page(&vf, seek_where)) { - decoder_command_finished(decoder); - } else - decoder_seek_error(decoder); - } - - int current_section; - -#ifdef HAVE_TREMOR - long nbytes = ov_read(&vf, buffer, sizeof(buffer), - IsBigEndian(), 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) { - vi = ov_info(&vf, -1); - if (vi == nullptr) { - LogWarning(vorbis_domain, - "ov_info() has failed"); - break; - } - - if (vi->rate != (long)audio_format.sample_rate || - vi->channels != (int)audio_format.channels) { - /* we don't support audio format - change yet */ - LogWarning(vorbis_domain, - "audio format change, stopping here"); - break; - } - - char **comments = ov_comment(&vf, -1)->user_comments; - vorbis_send_comments(decoder, input_stream, comments); - - ReplayGainInfo rgi; - if (vorbis_comments_to_replay_gain(rgi, comments)) - decoder_replay_gain(decoder, &rgi); - - prev_section = current_section; - } - - long test = ov_bitrate_instant(&vf); - if (test > 0) - kbit_rate = test / 1000; - - cmd = decoder_data(decoder, input_stream, - buffer, nbytes, - kbit_rate); - } while (cmd != DecoderCommand::STOP); - - ov_clear(&vf); -} - -static bool -vorbis_scan_stream(InputStream &is, - const struct tag_handler *handler, void *handler_ctx) -{ - struct vorbis_input_stream vis; - OggVorbis_File vf; - - if (!vorbis_is_open(&vis, &vf, nullptr, is)) - return false; - - tag_handler_invoke_duration(handler, handler_ctx, - (int)(ov_time_total(&vf, -1) + 0.5)); - - vorbis_comments_scan(ov_comment(&vf, -1)->user_comments, - handler, handler_ctx); - - ov_clear(&vf); - return true; -} - -static const char *const vorbis_suffixes[] = { - "ogg", "oga", nullptr -}; - -static const char *const vorbis_mime_types[] = { - "application/ogg", - "application/x-ogg", - "audio/ogg", - "audio/vorbis", - "audio/vorbis+ogg", - "audio/x-ogg", - "audio/x-vorbis", - "audio/x-vorbis+ogg", - nullptr -}; - -const struct DecoderPlugin vorbis_decoder_plugin = { - "vorbis", - nullptr, - nullptr, - vorbis_stream_decode, - nullptr, - nullptr, - vorbis_scan_stream, - nullptr, - vorbis_suffixes, - vorbis_mime_types -}; |