summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libmusepack/mpc_demux.c
diff options
context:
space:
mode:
authorSean Bartell <wingedtachikoma@gmail.com>2011-06-25 21:32:25 -0400
committerNils Wallménius <nils@rockbox.org>2012-04-25 22:13:20 +0200
commitf40bfc9267b13b54e6379dfe7539447662879d24 (patch)
tree9b20069d5e62809ff434061ad730096836f916f2 /lib/rbcodec/codecs/libmusepack/mpc_demux.c
parenta0009907de7a0107d49040d8a180f140e2eff299 (diff)
downloadrockbox-f40bfc9267b13b54e6379dfe7539447662879d24.zip
rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.tar.gz
rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.tar.bz2
rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.tar.xz
Add codecs to librbcodec.
Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97 Reviewed-on: http://gerrit.rockbox.org/137 Reviewed-by: Nils Wallménius <nils@rockbox.org> Tested-by: Nils Wallménius <nils@rockbox.org>
Diffstat (limited to 'lib/rbcodec/codecs/libmusepack/mpc_demux.c')
-rw-r--r--lib/rbcodec/codecs/libmusepack/mpc_demux.c730
1 files changed, 730 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libmusepack/mpc_demux.c b/lib/rbcodec/codecs/libmusepack/mpc_demux.c
new file mode 100644
index 0000000..9523163
--- /dev/null
+++ b/lib/rbcodec/codecs/libmusepack/mpc_demux.c
@@ -0,0 +1,730 @@
+/*
+ Copyright (c) 2005-2009, The Musepack Development Team
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ * Neither the name of the The Musepack Development Team nor the
+ names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <math.h>
+#include <string.h>
+#include "streaminfo.h"
+#include "mpcdec.h"
+#include "internal.h"
+#include "decoder.h"
+#include "huffman.h"
+#include "mpc_bits_reader.h"
+
+#include <codeclib.h>
+
+/// maximum number of seek points in the table. The distance between points will
+/// be adapted so this value is never exceeded.
+#define MAX_SEEK_TABLE_SIZE 8192
+
+// defines
+#define MAX_BUFFER_SIZE (DEMUX_BUFFER_SIZE + MAX_FRAME_SIZE)
+
+// globals
+static mpc_uint8_t g_buffer[MAX_BUFFER_SIZE] IBSS_ATTR_MPC_BITBUFFER;
+static mpc_seek_t g_seek_table[MAX_SEEK_TABLE_SIZE];
+static mpc_demux g_mpc_demux IBSS_ATTR;
+
+enum {
+ MPC_BUFFER_SWAP = 1,
+ MPC_BUFFER_FULL = 2,
+};
+
+static void mpc_demux_clear_buff(mpc_demux * d)
+{
+ d->bytes_total = 0;
+ d->bits_reader.buff = d->buffer;
+ d->bits_reader.count = 8;
+ d->bits_reader.buffered_addr = 0;
+ d->bits_reader.buffered_code = 0;
+ d->block_bits = 0;
+ d->block_frames = 0;
+ memset(d->buffer, 0, sizeof(g_buffer));
+}
+
+static mpc_uint32_t
+mpc_demux_fill(mpc_demux * d, mpc_uint32_t min_bytes, int flags)
+{
+ mpc_uint32_t unread_bytes = d->bytes_total + d->buffer - d->bits_reader.buff
+ - ((8 - d->bits_reader.count) >> 3);
+ mpc_int32_t offset = 0;
+
+ if (min_bytes == 0 || min_bytes > MAX_BUFFER_SIZE ||
+ (unread_bytes < min_bytes && flags & MPC_BUFFER_FULL))
+ min_bytes = MAX_BUFFER_SIZE;
+
+ if (unread_bytes < min_bytes) {
+ mpc_uint32_t bytes2read = min_bytes - unread_bytes;
+ mpc_uint32_t bytes_free = MAX_BUFFER_SIZE - d->bytes_total;
+
+ if (flags & MPC_BUFFER_SWAP) {
+ bytes2read &= -1 << 2;
+ offset = (unread_bytes + 3) & ( -1 << 2);
+ offset -= unread_bytes;
+ }
+
+ if (bytes2read > bytes_free) {
+ if (d->bits_reader.count == 0) {
+ d->bits_reader.count = 8;
+ d->bits_reader.buff++;
+ }
+ memmove(d->buffer + offset, d->bits_reader.buff, unread_bytes);
+ d->bits_reader.buff = d->buffer + offset;
+ d->bytes_total = unread_bytes + offset;
+ /* reset Coldfire optimized read when rebuffering */
+ d->bits_reader.buffered_addr = 0;
+ d->bits_reader.buffered_code = 0;
+ }
+ bytes2read = d->r->read(d->r, d->buffer + d->bytes_total, bytes2read);
+ if (flags & MPC_BUFFER_SWAP){
+ unsigned int i, * tmp = (unsigned int *) (d->buffer + d->bytes_total);
+ for(i = 0 ;i < (bytes2read >> 2); i++)
+ tmp[i] = swap32(tmp[i]);
+ }
+ d->bytes_total += bytes2read;
+ return bytes2read;
+ }
+
+ return (mpc_uint32_t) -1;
+}
+
+/**
+ * seek to a bit position in the stream
+ * @param d demuxer context
+ * @param fpos position in the stream in bits from the beginning of mpc datas
+ * @param min_bytes number of bytes to load after seeking
+ */
+static mpc_status
+mpc_demux_seek(mpc_demux * d, mpc_seek_t fpos, mpc_uint32_t min_bytes) {
+ // d->bits_reader.buff - d->buffer = current byte position within buffer
+ // d->bytes_total = buffer is filled with bytes_total bytes
+ // fpos = desired file position in bit (not byte)
+ // buf_fpos = desired byte position within buffer
+ mpc_seek_t next_pos = fpos>>3;
+ mpc_int_t buf_fpos = next_pos - d->r->tell(d->r) + d->bytes_total;
+
+ // is desired byte position within lower and upper boundaries of buffer?
+ if (buf_fpos >= 0 && buf_fpos + min_bytes <= d->bytes_total) {
+ // desired bytes are available in current buffer
+ d->bits_reader.buff += buf_fpos - (d->bits_reader.buff - d->buffer);
+ d->bits_reader.count = 8 - (fpos & 7);
+ } else {
+ // buffer needs to be refilled
+ if (d->si.stream_version == 7)
+ next_pos = ((next_pos - d->si.header_position) & (-1 << 2)) + d->si.header_position;
+ buf_fpos = fpos - (next_pos << 3);
+ if (!d->r->seek(d->r, (mpc_int32_t) next_pos))
+ return MPC_STATUS_FAIL;
+ mpc_demux_clear_buff(d);
+ if (d->si.stream_version == 7)
+ mpc_demux_fill(d, MAX_BUFFER_SIZE, MPC_BUFFER_FULL | MPC_BUFFER_SWAP);
+ else
+ mpc_demux_fill(d, MAX_BUFFER_SIZE, MPC_BUFFER_FULL);
+ d->bits_reader.buff += buf_fpos >> 3;
+ d->bits_reader.count = 8 - (buf_fpos & 7);
+ }
+
+ return MPC_STATUS_OK;
+}
+
+/**
+ * return the current position in the stream (in bits) from the beginning
+ * of the file
+ * @param d demuxer context
+ * @return current stream position in bits
+ */
+static mpc_seek_t mpc_demux_pos(mpc_demux * d)
+{
+ return (((mpc_seek_t)(d->r->tell(d->r)) - d->bytes_total +
+ d->bits_reader.buff - d->buffer) << 3) + 8 - d->bits_reader.count;
+}
+
+/**
+ * Searches for a ID3v2-tag and reads the length (in bytes) of it.
+ *
+ * @param d demuxer context
+ * @return size of tag, in bytes
+ * @return MPC_STATUS_FAIL on errors of any kind
+ */
+static mpc_int32_t mpc_demux_skip_id3v2(mpc_demux * d)
+{
+ mpc_uint8_t tmp [4];
+ mpc_bool_t footerPresent; // ID3v2.4-flag
+ mpc_int32_t size;
+
+ // we must be at the beginning of the stream
+ mpc_demux_fill(d, 3, 0);
+
+ // check id3-tag
+ if ( 0 != memcmp( d->bits_reader.buff, "ID3", 3 ) )
+ return 0;
+
+ mpc_demux_fill(d, 10, 0);
+
+ mpc_bits_read(&d->bits_reader, 24); // read ID3
+ mpc_bits_read(&d->bits_reader, 16); // read tag version
+
+ tmp[0] = mpc_bits_read(&d->bits_reader, 8); // read flags
+ footerPresent = tmp[0] & 0x10;
+ if ( tmp[0] & 0x0F )
+ return MPC_STATUS_FAIL; // not (yet???) allowed
+
+ tmp[0] = mpc_bits_read(&d->bits_reader, 8); // read size
+ tmp[1] = mpc_bits_read(&d->bits_reader, 8); // read size
+ tmp[2] = mpc_bits_read(&d->bits_reader, 8); // read size
+ tmp[3] = mpc_bits_read(&d->bits_reader, 8); // read size
+
+ if ( (tmp[0] | tmp[1] | tmp[2] | tmp[3]) & 0x80 )
+ return MPC_STATUS_FAIL; // not allowed
+
+ // read headerSize (syncsave: 4 * $0xxxxxxx = 28 significant bits)
+ size = tmp[0] << 21;
+ size |= tmp[1] << 14;
+ size |= tmp[2] << 7;
+ size |= tmp[3];
+
+ size += 10; //header
+
+ if ( footerPresent ) size += 10;
+
+ // This is called before file headers get read, streamversion etc isn't yet known, demuxing isn't properly initialized and we can't call mpc_demux_seek() from here.
+ mpc_demux_clear_buff(d);
+ if (!d->r->seek(d->r, size))
+ return MPC_STATUS_FAIL;
+
+ return size;
+}
+
+static mpc_status mpc_demux_seek_init(mpc_demux * d)
+{
+ size_t seek_table_size;
+ if (d->seek_table != 0)
+ return MPC_STATUS_OK;
+
+ d->seek_pwr = 6;
+ if (d->si.block_pwr > d->seek_pwr)
+ d->seek_pwr = d->si.block_pwr;
+ seek_table_size = (2 + d->si.samples / (MPC_FRAME_LENGTH << d->seek_pwr));
+ while (seek_table_size > MAX_SEEK_TABLE_SIZE) {
+ d->seek_pwr++;
+ seek_table_size = (2 + d->si.samples / (MPC_FRAME_LENGTH << d->seek_pwr));
+ }
+ d->seek_table = g_seek_table;
+ if (d->seek_table == 0)
+ return MPC_STATUS_FAIL;
+ d->seek_table[0] = (mpc_seek_t)mpc_demux_pos(d);
+ d->seek_table_size = 1;
+
+ return MPC_STATUS_OK;
+}
+
+/* rockbox: do not use
+static mpc_status mpc_demux_ST(mpc_demux * d)
+{
+ mpc_uint64_t tmp;
+ mpc_seek_t * table, last[2];
+ mpc_bits_reader r = d->bits_reader;
+ mpc_uint_t i, diff_pwr = 0, mask;
+ mpc_uint32_t file_table_size;
+
+ if (d->seek_table != 0)
+ return MPC_STATUS_OK;
+
+ mpc_bits_get_size(&r, &tmp);
+ file_table_size = (mpc_seek_t) tmp;
+ d->seek_pwr = d->si.block_pwr + mpc_bits_read(&r, 4);
+
+ tmp = 2 + d->si.samples / (MPC_FRAME_LENGTH << d->seek_pwr);
+ while (tmp > MAX_SEEK_TABLE_SIZE) {
+ d->seek_pwr++;
+ diff_pwr++;
+ tmp = 2 + d->si.samples / (MPC_FRAME_LENGTH << d->seek_pwr);
+ }
+ if ((file_table_size >> diff_pwr) > tmp)
+ file_table_size = tmp << diff_pwr;
+ d->seek_table = g_seek_table;
+ d->seek_table_size = (file_table_size + ((1 << diff_pwr) - 1)) >> diff_pwr;
+
+ table = d->seek_table;
+ mpc_bits_get_size(&r, &tmp);
+ table[0] = last[0] = (mpc_seek_t) (tmp + d->si.header_position) * 8;
+
+ if (d->seek_table_size == 1)
+ return MPC_STATUS_OK;
+
+ mpc_bits_get_size(&r, &tmp);
+ last[1] = (mpc_seek_t) (tmp + d->si.header_position) * 8;
+ if (diff_pwr == 0) table[1] = last[1];
+
+ mask = (1 << diff_pwr) - 1;
+ for (i = 2; i < file_table_size; i++) {
+ int code = mpc_bits_golomb_dec(&r, 12);
+ if (code & 1)
+ code = -(code & (-1 << 1));
+ code <<= 2;
+ last[i & 1] = code + 2 * last[(i-1) & 1] - last[i & 1];
+ if ((i & mask) == 0)
+ table[i >> diff_pwr] = last[i & 1];
+ }
+ return MPC_STATUS_OK;
+}
+
+static mpc_status mpc_demux_SP(mpc_demux * d, int size, int block_size)
+{
+ mpc_seek_t cur;
+ mpc_uint64_t ptr;
+ mpc_block b;
+ int st_head_size;
+
+ cur = mpc_demux_pos(d);
+ mpc_bits_get_size(&d->bits_reader, &ptr);
+ MPC_AUTO_FAIL( mpc_demux_seek(d, (ptr - size) * 8 + cur, 11) );
+ st_head_size = mpc_bits_get_block(&d->bits_reader, &b);
+ if (memcmp(b.key, "ST", 2) == 0) {
+ d->chap_pos = (ptr - size + b.size + st_head_size) * 8 + cur;
+ d->chap_nb = -1;
+ if (mpc_demux_fill(d, (mpc_uint32_t) b.size, 0) < b.size)
+ return MPC_STATUS_FAIL;
+ MPC_AUTO_FAIL( mpc_demux_ST(d) );
+ }
+ return mpc_demux_seek(d, cur, 11 + block_size);
+}
+*/
+/* rockbox: not used
+static void mpc_demux_chap_empty(mpc_demux * d) {
+ free(d->chap); d->chap = 0;
+ d->chap_nb = 0; // -1 for undefined, 0 for no chapters
+ d->chap_pos = 0;
+}
+*/
+/* rockbox: not used
+static mpc_status mpc_demux_chap_find_inner(mpc_demux * d)
+{
+ mpc_block b;
+ int tag_size = 0, chap_size = 0, size, i = 0;
+
+ d->chap_nb = 0;
+
+ if (d->si.stream_version < 8)
+ return MPC_STATUS_OK;
+
+ if (d->chap_pos == 0) {
+ mpc_uint64_t cur_pos = (d->si.header_position + 4) * 8;
+ MPC_AUTO_FAIL( mpc_demux_seek(d, cur_pos, 11) ); // seek to the beginning of the stream
+ size = mpc_bits_get_block(&d->bits_reader, &b);
+ while (memcmp(b.key, "SE", 2) != 0) {
+ mpc_uint64_t new_pos = cur_pos + (size + b.size) * 8;
+ MPC_AUTO_FAIL(mpc_check_key(b.key));
+
+ if (memcmp(b.key, "CT", 2) == 0) {
+ if (d->chap_pos == 0) d->chap_pos = cur_pos;
+ } else {
+ d->chap_pos = 0;
+ }
+ if (new_pos <= cur_pos)
+ return MPC_STATUS_FAIL;
+ cur_pos = new_pos;
+
+ MPC_AUTO_FAIL( mpc_demux_seek(d, cur_pos, 11) );
+ size = mpc_bits_get_block(&d->bits_reader, &b);
+ }
+ if (d->chap_pos == 0)
+ d->chap_pos = cur_pos;
+ }
+
+ mpc_demux_seek(d, d->chap_pos, 20);
+ size = mpc_bits_get_block(&d->bits_reader, &b);
+ while (memcmp(b.key, "CT", 2) == 0) {
+ mpc_uint64_t chap_sample;
+ d->chap_nb++;
+ chap_size += size;
+ size = mpc_bits_get_size(&d->bits_reader, &chap_sample) + 4;
+ chap_size += size;
+ tag_size += b.size - size;
+ MPC_AUTO_FAIL( mpc_demux_seek(d, d->chap_pos + (chap_size + tag_size) * 8, 20) );
+ size = mpc_bits_get_block(&d->bits_reader, &b);
+ }
+
+ if (d->chap_nb > 0) {
+ char * ptag;
+ d->chap = malloc(sizeof(mpc_chap_info) * d->chap_nb + tag_size);
+ if (d->chap == 0)
+ return MPC_STATUS_FAIL;
+
+ ptag = (char*)(d->chap + d->chap_nb);
+
+ MPC_AUTO_FAIL( mpc_demux_seek(d, d->chap_pos, 11) );
+ size = mpc_bits_get_block(&d->bits_reader, &b);
+ while (memcmp(b.key, "CT", 2) == 0) {
+ mpc_uint_t tmp_size;
+ char * tmp_ptag = ptag;
+ if (mpc_demux_fill(d, 11 + (mpc_uint32_t) b.size, 0) < b.size)
+ return MPC_STATUS_FAIL;
+ size = mpc_bits_get_size(&d->bits_reader, &d->chap[i].sample) + 4;
+ d->chap[i].gain = (mpc_uint16_t) mpc_bits_read(&d->bits_reader, 16);
+ d->chap[i].peak = (mpc_uint16_t) mpc_bits_read(&d->bits_reader, 16);
+
+ tmp_size = b.size - size;
+ do {
+ mpc_uint_t rd_size = tmp_size;
+ mpc_uint8_t * tmp_buff = d->bits_reader.buff + ((8 - d->bits_reader.count) >> 3);
+ mpc_uint32_t avail_bytes = d->bytes_total + d->buffer - tmp_buff;
+ rd_size = mini(rd_size, avail_bytes);
+ memcpy(tmp_ptag, tmp_buff, rd_size);
+ tmp_size -= rd_size;
+ tmp_ptag += rd_size;
+ d->bits_reader.buff += rd_size;
+ mpc_demux_fill(d, tmp_size, 0);
+ } while (tmp_size > 0);
+
+ d->chap[i].tag_size = b.size - size;
+ d->chap[i].tag = ptag;
+ ptag += b.size - size;
+ i++;
+ size = mpc_bits_get_block(&d->bits_reader, &b);
+ }
+ }
+
+ d->bits_reader.buff -= size;
+ return MPC_STATUS_OK;
+}
+*/
+/* rockbox: not used
+static mpc_status mpc_demux_chap_find(mpc_demux * d) {
+ mpc_status s = mpc_demux_chap_find_inner(d);
+ if (MPC_IS_FAILURE(s))
+ mpc_demux_chap_empty(d);
+ return s;
+}
+*/
+/**
+ * Gets the number of chapters in the stream
+ * @param d pointer to a musepack demuxer
+ * @return the number of chapters found in the stream
+ */
+/* rockbox: not used
+mpc_int_t mpc_demux_chap_nb(mpc_demux * d)
+{
+ if (d->chap_nb == -1)
+ mpc_demux_chap_find(d);
+ return d->chap_nb;
+}
+*/
+/**
+ * Gets datas associated to a given chapter
+ * The chapter tag is an APEv2 tag without the preamble
+ * @param d pointer to a musepack demuxer
+ * @param chap_nb chapter number you want datas (from 0 to mpc_demux_chap_nb(d) - 1)
+ * @return the chapter information structure
+ */
+/* rockbox: not used
+mpc_chap_info const * mpc_demux_chap(mpc_demux * d, int chap_nb)
+{
+ if (d->chap_nb == -1)
+ mpc_demux_chap_find(d);
+ if (chap_nb >= d->chap_nb || chap_nb < 0)
+ return 0;
+ return &d->chap[chap_nb];
+}
+*/
+
+static mpc_status mpc_demux_header(mpc_demux * d)
+{
+ char magic[4];
+
+ d->si.pns = 0xFF;
+/* rockbox: not used
+ d->si.profile_name = "n.a.";
+*/
+ // get header position
+ d->si.header_position = mpc_demux_skip_id3v2(d);
+ if(d->si.header_position < 0)
+ return MPC_STATUS_FAIL;
+
+ d->si.tag_offset = d->si.total_file_length = d->r->get_size(d->r);
+
+ mpc_demux_fill(d, 4, 0);
+ magic[0] = mpc_bits_read(&d->bits_reader, 8);
+ magic[1] = mpc_bits_read(&d->bits_reader, 8);
+ magic[2] = mpc_bits_read(&d->bits_reader, 8);
+ magic[3] = mpc_bits_read(&d->bits_reader, 8);
+
+ if (memcmp(magic, "MP+", 3) == 0) {
+ d->si.stream_version = magic[3] & 15;
+ d->si.pns = magic[3] >> 4;
+ if (d->si.stream_version != 7)
+ return MPC_STATUS_FAIL;
+ if (mpc_demux_fill(d, 6 * 4, MPC_BUFFER_SWAP) < 6 * 4) // header block size + endian convertion
+ return MPC_STATUS_FAIL;
+ MPC_AUTO_FAIL( streaminfo_read_header_sv7(&d->si, &d->bits_reader) );
+ } else if (memcmp(magic, "MPCK", 4) == 0) {
+ mpc_block b;
+ int size;
+ mpc_demux_fill(d, 11, 0); // max header block size
+ size = mpc_bits_get_block(&d->bits_reader, &b);
+ while( memcmp(b.key, "AP", 2) != 0 ){ // scan all blocks until audio
+ if (mpc_check_key(b.key) != MPC_STATUS_OK)
+ return MPC_STATUS_FAIL;
+ if (b.size > (mpc_uint64_t) MAX_BUFFER_SIZE - 11)
+ return MPC_STATUS_FAIL;
+
+ if (mpc_demux_fill(d, 11 + (mpc_uint32_t) b.size, 0) <= b.size)
+ return MPC_STATUS_FAIL;
+
+ if (memcmp(b.key, "SH", 2) == 0) {
+ MPC_AUTO_FAIL( streaminfo_read_header_sv8(&d->si, &d->bits_reader, (mpc_uint32_t) b.size) );
+ } else if (memcmp(b.key, "RG", 2) == 0) {
+ streaminfo_gain(&d->si, &d->bits_reader);
+ } else if (memcmp(b.key, "EI", 2) == 0) {
+ streaminfo_encoder_info(&d->si, &d->bits_reader);
+/* rockbox: do not use
+ } else if (memcmp(b.key, "SO", 2) == 0) {
+ MPC_AUTO_FAIL( mpc_demux_SP(d, size, (mpc_uint32_t) b.size) );
+ } else if (memcmp(b.key, "ST", 2) == 0) {
+ MPC_AUTO_FAIL( mpc_demux_ST(d) );
+*/
+ }
+ d->bits_reader.buff += b.size;
+ size = mpc_bits_get_block(&d->bits_reader, &b);
+ }
+ d->bits_reader.buff -= size;
+ if (d->si.stream_version == 0) // si not initialized !!!
+ return MPC_STATUS_FAIL;
+ } else {
+ return MPC_STATUS_FAIL;
+ }
+
+ return MPC_STATUS_OK;
+}
+
+mpc_demux * mpc_demux_init(mpc_reader * p_reader)
+{
+ mpc_demux* p_tmp = &g_mpc_demux;
+
+ if (p_tmp != 0) {
+ memset(p_tmp, 0, sizeof(mpc_demux));
+ p_tmp->buffer = g_buffer;
+ p_tmp->r = p_reader;
+/* rockbox: not used
+ p_tmp->chap_nb = -1;
+*/
+ mpc_demux_clear_buff(p_tmp);
+ if (mpc_demux_header(p_tmp) == MPC_STATUS_OK &&
+ mpc_demux_seek_init(p_tmp) == MPC_STATUS_OK) {
+ p_tmp->d = mpc_decoder_init(&p_tmp->si);
+ } else {
+ if (p_tmp->seek_table)
+ memset(p_tmp->seek_table, 0, sizeof(g_seek_table));
+ p_tmp = 0;
+ }
+ }
+
+ return p_tmp;
+}
+
+/* rockbox: not used
+void mpc_demux_exit(mpc_demux * d)
+{
+ mpc_decoder_exit(d->d);
+ memset(d->seek_table, 0, sizeof(g_seek_table));
+}
+*/
+
+void mpc_demux_get_info(mpc_demux * d, mpc_streaminfo * i)
+{
+ memcpy(i, &d->si, sizeof d->si);
+}
+
+static mpc_status mpc_demux_decode_inner(mpc_demux * d, mpc_frame_info * i)
+{
+ mpc_bits_reader r;
+ if (d->si.stream_version >= 8) {
+ i->is_key_frame = MPC_FALSE;
+
+ if (d->block_frames == 0) {
+ mpc_block b = {{0,0},0};
+ d->bits_reader.count &= -8;
+ if (d->d->decoded_samples == (d->seek_table_size << d->seek_pwr) * MPC_FRAME_LENGTH) {
+ d->seek_table[d->seek_table_size] = (mpc_seek_t) mpc_demux_pos(d);
+ d->seek_table_size ++;
+ }
+ mpc_demux_fill(d, 11, MPC_BUFFER_FULL); // max header block size
+ mpc_bits_get_block(&d->bits_reader, &b);
+ while( memcmp(b.key, "AP", 2) != 0 ) { // scan all blocks until audio
+ MPC_AUTO_FAIL( mpc_check_key(b.key) );
+
+ if (memcmp(b.key, "SE", 2) == 0) { // end block
+ i->bits = -1;
+ return MPC_STATUS_OK;
+ }
+
+ if (mpc_demux_fill(d, 11 + (mpc_uint32_t) b.size, MPC_BUFFER_FULL) < b.size)
+ return MPC_STATUS_FAIL;
+
+ d->bits_reader.buff += b.size;
+ mpc_bits_get_block(&d->bits_reader, &b);
+ }
+ d->block_bits = (mpc_uint32_t) b.size * 8;
+ d->block_frames = 1 << d->si.block_pwr;
+ i->is_key_frame = MPC_TRUE;
+ }
+ mpc_demux_fill(d, MAX_FRAME_SIZE, MPC_BUFFER_FULL);
+ r = d->bits_reader;
+ mpc_decoder_decode_frame(d->d, &d->bits_reader, i);
+ d->block_bits -= ((d->bits_reader.buff - r.buff) << 3) + r.count - d->bits_reader.count;
+ d->block_frames--;
+ if (d->block_bits < 0 || (d->block_frames == 0 && d->block_bits > 7))
+ return MPC_STATUS_FAIL;
+ } else {
+ if (d->d->decoded_samples == (d->seek_table_size << d->seek_pwr) * MPC_FRAME_LENGTH) {
+ d->seek_table[d->seek_table_size] = (mpc_seek_t) mpc_demux_pos(d);
+ d->seek_table_size ++;
+ }
+ mpc_demux_fill(d, MAX_FRAME_SIZE, MPC_BUFFER_FULL | MPC_BUFFER_SWAP);
+ d->block_bits = (mpc_int_t) mpc_bits_read(&d->bits_reader, 20); // read frame size
+ if (MPC_FRAME_LENGTH > d->d->samples - d->d->decoded_samples - 1) d->block_bits += 11; // we will read last frame size
+ r = d->bits_reader;
+ mpc_decoder_decode_frame(d->d, &d->bits_reader, i);
+ if (i->bits != -1 && d->block_bits != (mpc_int32_t)(((d->bits_reader.buff - r.buff) << 3) + r.count - d->bits_reader.count))
+ return MPC_STATUS_FAIL;
+ }
+ if (i->bits != -1 && d->buffer + d->bytes_total < d->bits_reader.buff + ((8 - d->bits_reader.count) >> 3))
+ return MPC_STATUS_FAIL;
+
+ return MPC_STATUS_OK;
+}
+
+mpc_status mpc_demux_decode(mpc_demux * d, mpc_frame_info * i) {
+ mpc_status s = mpc_demux_decode_inner(d, i);
+ if (MPC_IS_FAILURE(s))
+ i->bits = -1; // we pretend it's end of file
+ return s;
+}
+
+/* rockbox: not used
+mpc_status mpc_demux_seek_second(mpc_demux * d, double seconds)
+{
+ return mpc_demux_seek_sample(d, (mpc_int64_t)(seconds * (double)d->si.sample_freq + 0.5));
+}
+*/
+
+mpc_status mpc_demux_seek_sample(mpc_demux * d, mpc_uint64_t destsample)
+{
+ mpc_uint32_t fwd, samples_to_skip, i;
+ mpc_uint32_t block_samples = MPC_FRAME_LENGTH << d->si.block_pwr;
+ mpc_seek_t fpos;
+
+ destsample += d->si.beg_silence;
+ if (destsample > d->si.samples) destsample = d->si.samples;
+ fwd = (mpc_uint32_t) (destsample / block_samples);
+ samples_to_skip = MPC_DECODER_SYNTH_DELAY +
+ (mpc_uint32_t) (destsample % block_samples);
+ if (d->si.stream_version == 7) {
+ if (fwd > 32) {
+ fwd -= 32;
+ samples_to_skip += MPC_FRAME_LENGTH * 32;
+ } else {
+ samples_to_skip += MPC_FRAME_LENGTH * fwd;
+ fwd = 0;
+ }
+ }
+
+ i = fwd >> (d->seek_pwr - d->si.block_pwr);
+ if (i >= d->seek_table_size)
+ i = d->seek_table_size - 1;
+ fpos = d->seek_table[i];
+ i <<= d->seek_pwr - d->si.block_pwr;
+ d->d->decoded_samples = i * block_samples;
+
+ if (d->si.stream_version >= 8) {
+ mpc_block b;
+ int size;
+ mpc_demux_seek(d, fpos, 11);
+ size = mpc_bits_get_block(&d->bits_reader, &b);
+ while(i < fwd) {
+ if (memcmp(b.key, "AP", 2) == 0) {
+ if (d->d->decoded_samples == (d->seek_table_size << d->seek_pwr) * MPC_FRAME_LENGTH) {
+ d->seek_table[d->seek_table_size] = (mpc_seek_t) mpc_demux_pos(d) - 8 * size;
+ d->seek_table_size ++;
+ }
+ d->d->decoded_samples += block_samples;
+ i++;
+ }
+ fpos += ((mpc_uint32_t)b.size + size) * 8;
+ mpc_demux_seek(d, fpos, 11);
+ size = mpc_bits_get_block(&d->bits_reader, &b);
+ }
+ d->bits_reader.buff -= size;
+ } else {
+ mpc_decoder_reset_scf(d->d, fwd != 0);
+ mpc_demux_seek(d, fpos, 4);
+ for( ; i < fwd; i++){
+ if (d->d->decoded_samples == (d->seek_table_size << d->seek_pwr) * MPC_FRAME_LENGTH) {
+ d->seek_table[d->seek_table_size] = (mpc_seek_t) mpc_demux_pos(d);
+ d->seek_table_size ++;
+ }
+ d->d->decoded_samples += block_samples;
+ fpos += mpc_bits_read(&d->bits_reader, 20) + 20;
+ mpc_demux_seek(d, fpos, 4);
+ }
+ }
+ d->d->samples_to_skip = samples_to_skip;
+ return MPC_STATUS_OK;
+}
+
+/* rockbox: not used
+void mpc_set_replay_level(mpc_demux * d, float level, mpc_bool_t use_gain,
+ mpc_bool_t use_title, mpc_bool_t clip_prevention)
+{
+ float peak = (float) ( use_title ? d->si.peak_title : d->si.peak_album );
+ float gain = (float) ( use_title ? d->si.gain_title : d->si.gain_album );
+
+ if(!use_gain && !clip_prevention)
+ return;
+
+ if(!peak)
+ peak = 1.;
+ else
+ peak = (float) ( (1 << 15) / pow(10, peak / (20 * 256)) );
+
+ if(!gain)
+ gain = 1.;
+ else
+ gain = (float) pow(10, (level - gain / 256) / 20);
+
+ if(clip_prevention && (peak < gain || !use_gain))
+ gain = peak;
+
+ mpc_decoder_scale_output(d->d, gain);
+}
+*/