From f40bfc9267b13b54e6379dfe7539447662879d24 Mon Sep 17 00:00:00 2001 From: Sean Bartell Date: Sat, 25 Jun 2011 21:32:25 -0400 Subject: Add codecs to librbcodec. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97 Reviewed-on: http://gerrit.rockbox.org/137 Reviewed-by: Nils Wallménius Tested-by: Nils Wallménius --- lib/rbcodec/codecs/libmusepack/mpc_demux.c | 730 +++++++++++++++++++++++++++++ 1 file changed, 730 insertions(+) create mode 100644 lib/rbcodec/codecs/libmusepack/mpc_demux.c (limited to 'lib/rbcodec/codecs/libmusepack/mpc_demux.c') diff --git a/lib/rbcodec/codecs/libmusepack/mpc_demux.c b/lib/rbcodec/codecs/libmusepack/mpc_demux.c new file mode 100644 index 0000000000..9523163c0e --- /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 +#include +#include "streaminfo.h" +#include "mpcdec.h" +#include "internal.h" +#include "decoder.h" +#include "huffman.h" +#include "mpc_bits_reader.h" + +#include + +/// 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); +} +*/ -- cgit v1.2.3