1
0
Fork 0
forked from len0rd/rockbox

Major change to musepack decoder: Import v1.3.0 (r458 from svn.musepack.net) to rockbox. Several adaptions in the musepack decoder were made to get the library work and perform fast under rockbox on several targets. With this change mpc sv8 is supported, including seek, replay gain and metadata support. The decoding speed is a 1-4% lower than the last implementation. Reason for this is main restructuring in the bitstream demuxer.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25056 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Andree Buschmann 2010-03-07 19:34:44 +00:00
parent ce92b8bf34
commit b3d9578c27
36 changed files with 3204 additions and 2807 deletions

View file

@ -20,79 +20,81 @@
****************************************************************************/
#include "codeclib.h"
#include <codecs/libmusepack/musepack.h>
#include <codecs/libmusepack/mpcdec.h>
#include <codecs/libmusepack/internal.h>
CODEC_HEADER
mpc_decoder decoder IBSS_ATTR;
MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH] IBSS_ATTR;
/* Our implementations of the mpc_reader callback functions. */
static mpc_int32_t read_impl(void *data, void *ptr, mpc_int32_t size)
static mpc_int32_t read_impl(mpc_reader *reader, void *ptr, mpc_int32_t size)
{
struct codec_api *ci = (struct codec_api *)data;
struct codec_api *ci = (struct codec_api *)(reader->data);
return ((mpc_int32_t)(ci->read_filebuf(ptr, size)));
}
static mpc_bool_t seek_impl(void *data, mpc_int32_t offset)
static mpc_bool_t seek_impl(mpc_reader *reader, mpc_int32_t offset)
{
struct codec_api *ci = (struct codec_api *)data;
struct codec_api *ci = (struct codec_api *)(reader->data);
/* WARNING: assumes we don't need to skip too far into the past,
this might not be supported by the buffering layer yet */
return ci->seek_buffer(offset);
}
static mpc_int32_t tell_impl(void *data)
static mpc_int32_t tell_impl(mpc_reader *reader)
{
struct codec_api *ci = (struct codec_api *)data;
struct codec_api *ci = (struct codec_api *)(reader->data);
return ci->curpos;
}
static mpc_int32_t get_size_impl(void *data)
static mpc_int32_t get_size_impl(mpc_reader *reader)
{
struct codec_api *ci = (struct codec_api *)data;
struct codec_api *ci = (struct codec_api *)(reader->data);
return ci->filesize;
}
static mpc_bool_t canseek_impl(void *data)
static mpc_bool_t canseek_impl(mpc_reader *reader)
{
(void)data;
(void)reader;
/* doesn't much matter, libmusepack ignores this anyway */
return true;
}
MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH]
IBSS_ATTR_MPC_SAMPLE_BUF;
/* this is the codec entry point */
enum codec_status codec_main(void)
{
mpc_int64_t samplesdone;
uint32_t frequency; /* 0.1 kHz accuracy */
uint32_t elapsed_time; /* milliseconds */
unsigned status;
mpc_status status;
mpc_reader reader;
mpc_streaminfo info;
mpc_frame_info frame;
mpc_demux *demux = NULL;
int retval = CODEC_OK;
frame.buffer = sample_buffer;
/* musepack's sample representation is 18.14
* DSP_SET_SAMPLE_DEPTH = 14 (FRACT) + 16 (NATIVE) - 1 (SIGN) = 29 */
ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
/* Create a decoder instance */
reader.read = read_impl;
reader.seek = seek_impl;
reader.tell = tell_impl;
reader.read = read_impl;
reader.seek = seek_impl;
reader.tell = tell_impl;
reader.get_size = get_size_impl;
reader.canseek = canseek_impl;
reader.data = ci;
reader.canseek = canseek_impl;
reader.data = ci;
next_track:
if (codec_init()) {
if (codec_init())
{
retval = CODEC_ERROR;
goto exit;
}
@ -102,42 +104,45 @@ next_track:
samplesdone = ci->id3->offset;
/* read file's streaminfo data */
mpc_streaminfo_init(&info);
if (mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) {
/* initialize demux/decoder */
demux = mpc_demux_init(&reader);
if (NULL == demux)
{
retval = CODEC_ERROR;
goto done;
}
/* read file's streaminfo data */
mpc_demux_get_info(demux, &info);
frequency = info.sample_freq / 100; /* 0.1 kHz accuracy */
ci->configure(DSP_SWITCH_FREQUENCY, info.sample_freq);
/* set playback engine up for correct number of channels */
/* NOTE: current musepack format only allows for stereo files
but code is here to handle other configurations anyway */
if (info.channels == 2)
if (info.channels == 2)
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
else if (info.channels == 1)
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
else {
else
{
retval = CODEC_ERROR;
goto done;
}
codec_set_replaygain(ci->id3);
/* instantiate a decoder with our file reader */
mpc_decoder_setup(&decoder, &reader);
if (!mpc_decoder_initialize(&decoder, &info)) {
retval = CODEC_ERROR;
goto done;
}
/* Resume to saved sample offset. */
if (samplesdone > 0) {
/* hack to improve seek time if filebuf goes empty */
if (mpc_decoder_seek_sample(&decoder, samplesdone)) {
if (mpc_demux_seek_sample(demux, samplesdone) == MPC_STATUS_OK)
{
elapsed_time = (samplesdone*10)/frequency;
ci->set_elapsed(elapsed_time);
} else {
}
else
{
samplesdone = 0;
}
/* reset chunksize */
@ -146,10 +151,12 @@ next_track:
/* This is the decoding loop. */
do {
/* Complete seek handler. */
if (ci->seek_time) {
if (ci->seek_time)
{
/* hack to improve seek time if filebuf goes empty */
mpc_int64_t new_offset = ((ci->seek_time - 1)/10)*frequency;
if (mpc_decoder_seek_sample(&decoder, new_offset)) {
if (mpc_demux_seek_sample(demux, new_offset) == MPC_STATUS_OK)
{
samplesdone = new_offset;
ci->set_elapsed(ci->seek_time);
}
@ -159,24 +166,24 @@ next_track:
if (ci->stop_codec || ci->new_track)
break;
status = mpc_decoder_decode(&decoder, sample_buffer, NULL, NULL);
status = mpc_demux_decode(demux, &frame);
ci->yield();
if (status == 0) /* end of file reached */
if (frame.bits == -1) /* decoding stopped */
{
retval = (status == MPC_STATUS_OK) ? CODEC_OK : CODEC_ERROR;
goto done;
if (status == (unsigned)(-1)) { /* decode error */
retval = CODEC_ERROR;
goto done;
} else {
ci->pcmbuf_insert(sample_buffer,
sample_buffer + MPC_FRAME_LENGTH,
status);
samplesdone += status;
}
else
{
ci->pcmbuf_insert(frame.buffer,
frame.buffer + MPC_FRAME_LENGTH,
frame.samples);
samplesdone += frame.samples;
elapsed_time = (samplesdone*10)/frequency;
ci->set_elapsed(elapsed_time);
ci->set_offset(samplesdone);
}
} while (status != 0);
retval = CODEC_OK;
} while (true);
done:
if (ci->request_next_track())