|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* This file is part of libbluray
|
|
Packit |
5e46da |
* Copyright (C) 2010 hpi1
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* This library is free software; you can redistribute it and/or
|
|
Packit |
5e46da |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
5e46da |
* License as published by the Free Software Foundation; either
|
|
Packit |
5e46da |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
5e46da |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
5e46da |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
5e46da |
* Lesser General Public License for more details.
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
5e46da |
* License along with this library. If not, see
|
|
Packit |
5e46da |
* <http://www.gnu.org/licenses/>.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#if HAVE_CONFIG_H
|
|
Packit |
5e46da |
#include "config.h"
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "sound_parse.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "disc/disc.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "file/file.h"
|
|
Packit |
5e46da |
#include "util/bits.h"
|
|
Packit |
5e46da |
#include "util/logging.h"
|
|
Packit |
5e46da |
#include "util/macro.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include <stdlib.h>
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#define BCLK_SIG1 ('B' << 24 | 'C' << 16 | 'L' << 8 | 'K')
|
|
Packit |
5e46da |
#define BCLK_SIG2A ('0' << 24 | '2' << 16 | '0' << 8 | '0')
|
|
Packit |
5e46da |
#define BCLK_SIG2B ('0' << 24 | '1' << 16 | '0' << 8 | '0')
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _bclk_parse_header(BITSTREAM *bs, uint32_t *data_start, uint32_t *extension_data_start)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint32_t sig1, sig2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_seek_byte(bs, 0) < 0) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
sig1 = bs_read(bs, 32);
|
|
Packit |
5e46da |
sig2 = bs_read(bs, 32);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (sig1 != BCLK_SIG1 ||
|
|
Packit |
5e46da |
(sig2 != BCLK_SIG2A &&
|
|
Packit |
5e46da |
sig2 != BCLK_SIG2B)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV, "sound.bdmv failed signature match: expected BCLK0100 got %8.8s\n", bs->buf);
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
*data_start = bs_read(bs, 32);
|
|
Packit |
5e46da |
*extension_data_start = bs_read(bs, 32);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _sound_parse_attributes(BITSTREAM *bs, SOUND_OBJECT *obj)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int i;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
switch (i = bs_read(bs, 4)) {
|
|
Packit |
5e46da |
default: BD_DEBUG(DBG_NAV, "unknown channel configuration code %d\n", i);
|
|
Packit |
5e46da |
/* fall thru */
|
|
Packit |
5e46da |
case 1: obj->num_channels = 1;
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
case 3: obj->num_channels = 2;
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
};
|
|
Packit |
5e46da |
switch (i = bs_read(bs, 4)) {
|
|
Packit |
5e46da |
default: BD_DEBUG(DBG_NAV, "unknown sample rate code %d\n", i);
|
|
Packit |
5e46da |
/* fall thru */
|
|
Packit |
5e46da |
case 1: obj->sample_rate = 48000;
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
};
|
|
Packit |
5e46da |
switch (i = bs_read(bs, 2)) {
|
|
Packit |
5e46da |
default: BD_DEBUG(DBG_NAV, "unknown bits per sample code %d\n", i);
|
|
Packit |
5e46da |
/* fall thru */
|
|
Packit |
5e46da |
case 1: obj->bits_per_sample = 16;
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
};
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_skip(bs, 6); /* padding */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _sound_parse_index(BITSTREAM *bs, uint32_t *sound_data_index, SOUND_OBJECT *obj)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (!_sound_parse_attributes(bs, obj))
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
*sound_data_index = bs_read(bs, 32);
|
|
Packit |
5e46da |
obj->num_frames = bs_read(bs, 32);
|
|
Packit |
5e46da |
obj->num_frames /= (obj->bits_per_sample / 8) * obj->num_channels;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _sound_read_samples(BITSTREAM *bs, SOUND_OBJECT *obj)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint32_t n;
|
|
Packit |
5e46da |
uint32_t num_samples = obj->num_frames * obj->num_channels;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!num_samples) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_avail(bs)/16 < num_samples) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_HDMV|DBG_CRIT, "sound.bdmv: unexpected EOF\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
obj->samples = calloc(num_samples, sizeof(uint16_t));
|
|
Packit |
5e46da |
if (!obj->samples) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (n = 0; n < num_samples; n++) {
|
|
Packit |
5e46da |
obj->samples[n] = bs_read(bs, 16);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void sound_free(SOUND_DATA **p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p && *p) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if ((*p)->sounds) {
|
|
Packit |
5e46da |
unsigned i;
|
|
Packit |
5e46da |
for (i = 0 ; i < (*p)->num_sounds; i++) {
|
|
Packit |
5e46da |
X_FREE((*p)->sounds[i].samples);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
X_FREE((*p)->sounds);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(*p);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static SOUND_DATA *_sound_parse(BD_FILE_H *fp)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BITSTREAM bs;
|
|
Packit |
5e46da |
SOUND_DATA *data = NULL;
|
|
Packit |
5e46da |
uint16_t num_sounds;
|
|
Packit |
5e46da |
uint32_t data_len;
|
|
Packit |
5e46da |
int i;
|
|
Packit |
5e46da |
uint32_t data_start, extension_data_start;
|
|
Packit |
5e46da |
uint32_t *data_offsets = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_init(&bs, fp) < 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV, "sound.bdmv: read error\n");
|
|
Packit |
5e46da |
goto error;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!_bclk_parse_header(&bs, &data_start, &extension_data_start)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "invalid header\n");
|
|
Packit |
5e46da |
goto error;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_seek_byte(&bs, 40) < 0) {
|
|
Packit |
5e46da |
goto error;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
data_len = bs_read(&bs, 32);
|
|
Packit |
5e46da |
bs_skip(&bs, 8); /* reserved */
|
|
Packit |
5e46da |
num_sounds = bs_read(&bs, 8);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (data_len < 1 || num_sounds < 1) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "empty database\n");
|
|
Packit |
5e46da |
goto error;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
data_offsets = calloc(num_sounds, sizeof(uint32_t));
|
|
Packit |
5e46da |
data = calloc(1, sizeof(SOUND_DATA));
|
|
Packit |
5e46da |
if (!data_offsets || !data) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
goto error;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
data->num_sounds = num_sounds;
|
|
Packit |
5e46da |
data->sounds = calloc(num_sounds, sizeof(SOUND_OBJECT));
|
|
Packit |
5e46da |
if (!data->sounds) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
goto error;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* parse headers */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (i = 0; i < data->num_sounds; i++) {
|
|
Packit |
5e46da |
if (!_sound_parse_index(&bs, data_offsets + i, &data->sounds[i])) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing sound %d attributes\n", i);
|
|
Packit |
5e46da |
goto error;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* read samples */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (i = 0; i < data->num_sounds; i++) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_seek_byte(&bs, data_start + data_offsets[i]) < 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error reading samples for sound %d\n", i);
|
|
Packit |
5e46da |
data->sounds[i].num_frames = 0;
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!_sound_read_samples(&bs, &data->sounds[i])) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error reading samples for sound %d\n", i);
|
|
Packit |
5e46da |
goto error;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
X_FREE(data_offsets);
|
|
Packit |
5e46da |
return data;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
error:
|
|
Packit |
5e46da |
sound_free(&data);
|
|
Packit |
5e46da |
X_FREE(data_offsets);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
SOUND_DATA *sound_get(BD_DISC *disc)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BD_FILE_H *fp;
|
|
Packit |
5e46da |
SOUND_DATA *p;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* there's no no backup copy for sound.bdmv */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
fp = disc_open_path(disc, "BDMV" DIR_SEP "AUXDATA" DIR_SEP "sound.bdmv");
|
|
Packit |
5e46da |
if (!fp) {
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p = _sound_parse(fp);
|
|
Packit |
5e46da |
file_close(fp);
|
|
Packit |
5e46da |
return p;
|
|
Packit |
5e46da |
}
|