|
Packit |
3ae693 |
/*-*- Mode: C; c-basic-offset: 8 -*-*/
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/***
|
|
Packit |
3ae693 |
This file is part of libcanberra.
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
Copyright 2008 Lennart Poettering
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
libcanberra is free software; you can redistribute it and/or modify
|
|
Packit |
3ae693 |
it under the terms of the GNU Lesser General Public License as
|
|
Packit |
3ae693 |
published by the Free Software Foundation, either version 2.1 of the
|
|
Packit |
3ae693 |
License, or (at your option) any later version.
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
libcanberra is distributed in the hope that it will be useful, but
|
|
Packit |
3ae693 |
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
3ae693 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
3ae693 |
Lesser General Public License for more details.
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
3ae693 |
License along with libcanberra. If not, see
|
|
Packit |
3ae693 |
<http://www.gnu.org/licenses/>.
|
|
Packit |
3ae693 |
***/
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
3ae693 |
#include <config.h>
|
|
Packit |
3ae693 |
#endif
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#include <vorbis/vorbisfile.h>
|
|
Packit |
3ae693 |
#include <vorbis/codec.h>
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#include "canberra.h"
|
|
Packit |
3ae693 |
#include "read-vorbis.h"
|
|
Packit |
3ae693 |
#include "macro.h"
|
|
Packit |
3ae693 |
#include "malloc.h"
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#define FILE_SIZE_MAX ((off_t) (64U*1024U*1024U))
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
struct ca_vorbis {
|
|
Packit |
3ae693 |
OggVorbis_File ovf;
|
|
Packit |
3ae693 |
off_t size;
|
|
Packit |
3ae693 |
ca_channel_position_t channel_map[8];
|
|
Packit |
3ae693 |
};
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static int convert_error(int or) {
|
|
Packit |
3ae693 |
switch (or) {
|
|
Packit |
3ae693 |
case OV_ENOSEEK:
|
|
Packit |
3ae693 |
case OV_EBADPACKET:
|
|
Packit |
3ae693 |
case OV_EBADLINK:
|
|
Packit |
3ae693 |
case OV_EFAULT:
|
|
Packit |
3ae693 |
case OV_EREAD:
|
|
Packit |
3ae693 |
case OV_HOLE:
|
|
Packit |
3ae693 |
return CA_ERROR_IO;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
case OV_EIMPL:
|
|
Packit |
3ae693 |
case OV_EVERSION:
|
|
Packit |
3ae693 |
case OV_ENOTAUDIO:
|
|
Packit |
3ae693 |
return CA_ERROR_NOTSUPPORTED;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
case OV_ENOTVORBIS:
|
|
Packit |
3ae693 |
case OV_EBADHEADER:
|
|
Packit |
3ae693 |
case OV_EOF:
|
|
Packit |
3ae693 |
return CA_ERROR_CORRUPT;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
case OV_EINVAL:
|
|
Packit |
3ae693 |
return CA_ERROR_INVALID;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
default:
|
|
Packit |
3ae693 |
return CA_ERROR_IO;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
int ca_vorbis_open(ca_vorbis **_v, FILE *f) {
|
|
Packit |
3ae693 |
int ret, or;
|
|
Packit |
3ae693 |
ca_vorbis *v;
|
|
Packit |
3ae693 |
int64_t n;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(_v, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(f, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(v = ca_new0(ca_vorbis, 1)))
|
|
Packit |
3ae693 |
return CA_ERROR_OOM;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((or = ov_open(f, &v->ovf, NULL, 0)) < 0) {
|
|
Packit |
3ae693 |
ret = convert_error(or);
|
|
Packit |
3ae693 |
goto fail;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((n = ov_pcm_total(&v->ovf, -1)) < 0) {
|
|
Packit |
3ae693 |
ret = convert_error(or);
|
|
Packit |
3ae693 |
ov_clear(&v->ovf);
|
|
Packit |
3ae693 |
goto fail;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (((off_t) n * (off_t) sizeof(int16_t)) > FILE_SIZE_MAX) {
|
|
Packit |
3ae693 |
ret = CA_ERROR_TOOBIG;
|
|
Packit |
3ae693 |
ov_clear(&v->ovf);
|
|
Packit |
3ae693 |
goto fail;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
v->size = (off_t) n * (off_t) sizeof(int16_t) * ca_vorbis_get_nchannels(v);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
*_v = v;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return CA_SUCCESS;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
fail:
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_free(v);
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
void ca_vorbis_close(ca_vorbis *v) {
|
|
Packit |
3ae693 |
ca_assert(v);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ov_clear(&v->ovf);
|
|
Packit |
3ae693 |
ca_free(v);
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
unsigned ca_vorbis_get_nchannels(ca_vorbis *v) {
|
|
Packit |
3ae693 |
const vorbis_info *vi;
|
|
Packit |
3ae693 |
ca_assert(v);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert_se(vi = ov_info(&v->ovf, -1));
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return (unsigned) vi->channels;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
unsigned ca_vorbis_get_rate(ca_vorbis *v) {
|
|
Packit |
3ae693 |
const vorbis_info *vi;
|
|
Packit |
3ae693 |
ca_assert(v);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert_se(vi = ov_info(&v->ovf, -1));
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return (unsigned) vi->rate;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
const ca_channel_position_t* ca_vorbis_get_channel_map(ca_vorbis *v) {
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* See http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9 */
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
switch (ca_vorbis_get_nchannels(v)) {
|
|
Packit |
3ae693 |
case 8:
|
|
Packit |
3ae693 |
v->channel_map[0] = CA_CHANNEL_FRONT_LEFT;
|
|
Packit |
3ae693 |
v->channel_map[1] = CA_CHANNEL_FRONT_CENTER;
|
|
Packit |
3ae693 |
v->channel_map[2] = CA_CHANNEL_FRONT_RIGHT;
|
|
Packit |
3ae693 |
v->channel_map[3] = CA_CHANNEL_SIDE_LEFT;
|
|
Packit |
3ae693 |
v->channel_map[4] = CA_CHANNEL_SIDE_RIGHT;
|
|
Packit |
3ae693 |
v->channel_map[5] = CA_CHANNEL_REAR_LEFT;
|
|
Packit |
3ae693 |
v->channel_map[6] = CA_CHANNEL_REAR_RIGHT;
|
|
Packit |
3ae693 |
v->channel_map[7] = CA_CHANNEL_LFE;
|
|
Packit |
3ae693 |
return v->channel_map;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
case 7:
|
|
Packit |
3ae693 |
v->channel_map[0] = CA_CHANNEL_FRONT_LEFT;
|
|
Packit |
3ae693 |
v->channel_map[1] = CA_CHANNEL_FRONT_CENTER;
|
|
Packit |
3ae693 |
v->channel_map[2] = CA_CHANNEL_FRONT_RIGHT;
|
|
Packit |
3ae693 |
v->channel_map[3] = CA_CHANNEL_SIDE_LEFT;
|
|
Packit |
3ae693 |
v->channel_map[4] = CA_CHANNEL_SIDE_RIGHT;
|
|
Packit |
3ae693 |
v->channel_map[5] = CA_CHANNEL_REAR_CENTER;
|
|
Packit |
3ae693 |
v->channel_map[6] = CA_CHANNEL_LFE;
|
|
Packit |
3ae693 |
return v->channel_map;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
case 6:
|
|
Packit |
3ae693 |
v->channel_map[5] = CA_CHANNEL_LFE;
|
|
Packit |
3ae693 |
/* fall through */
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
case 5:
|
|
Packit |
3ae693 |
v->channel_map[3] = CA_CHANNEL_REAR_LEFT;
|
|
Packit |
3ae693 |
v->channel_map[4] = CA_CHANNEL_REAR_RIGHT;
|
|
Packit |
3ae693 |
/* fall through */
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
case 3:
|
|
Packit |
3ae693 |
v->channel_map[0] = CA_CHANNEL_FRONT_LEFT;
|
|
Packit |
3ae693 |
v->channel_map[1] = CA_CHANNEL_FRONT_CENTER;
|
|
Packit |
3ae693 |
v->channel_map[2] = CA_CHANNEL_FRONT_RIGHT;
|
|
Packit |
3ae693 |
return v->channel_map;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
case 4:
|
|
Packit |
3ae693 |
v->channel_map[2] = CA_CHANNEL_REAR_LEFT;
|
|
Packit |
3ae693 |
v->channel_map[3] = CA_CHANNEL_REAR_RIGHT;
|
|
Packit |
3ae693 |
/* fall through */
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
case 2:
|
|
Packit |
3ae693 |
v->channel_map[0] = CA_CHANNEL_FRONT_LEFT;
|
|
Packit |
3ae693 |
v->channel_map[1] = CA_CHANNEL_FRONT_RIGHT;
|
|
Packit |
3ae693 |
return v->channel_map;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
case 1:
|
|
Packit |
3ae693 |
v->channel_map[0] = CA_CHANNEL_MONO;
|
|
Packit |
3ae693 |
return v->channel_map;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return NULL;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
int ca_vorbis_read_s16ne(ca_vorbis *v, int16_t *d, size_t *n){
|
|
Packit |
3ae693 |
long r;
|
|
Packit |
3ae693 |
int section;
|
|
Packit |
3ae693 |
int length;
|
|
Packit |
3ae693 |
size_t n_read = 0;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(v, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(d, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(n, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
length = (int) (*n * sizeof(int16_t));
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
do {
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
r = ov_read(&v->ovf, (char*) d, length,
|
|
Packit |
3ae693 |
#ifdef WORDS_BIGENDIAN
|
|
Packit |
3ae693 |
1,
|
|
Packit |
3ae693 |
#else
|
|
Packit |
3ae693 |
0,
|
|
Packit |
3ae693 |
#endif
|
|
Packit |
3ae693 |
2, 1, §ion);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (r < 0)
|
|
Packit |
3ae693 |
return convert_error((int) r);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (r == 0)
|
|
Packit |
3ae693 |
break;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* We only read the first section */
|
|
Packit |
3ae693 |
if (section != 0)
|
|
Packit |
3ae693 |
break;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
length -= (int) r;
|
|
Packit |
3ae693 |
d += r/sizeof(int16_t);
|
|
Packit |
3ae693 |
n_read += (size_t) r;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
} while (length >= 4096);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert(v->size >= (off_t) n_read);
|
|
Packit |
3ae693 |
v->size -= (off_t) n_read;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
*n = n_read/sizeof(int16_t);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return CA_SUCCESS;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
off_t ca_vorbis_get_size(ca_vorbis *v) {
|
|
Packit |
3ae693 |
ca_return_val_if_fail(v, (off_t) -1);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return v->size;
|
|
Packit |
3ae693 |
}
|