Blame src/read-vorbis.c

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, &section);
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
}