From 9b9b30bd547c829157f3f83c71378f0bbd43241d Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Sat, 22 Dec 2018 20:04:28 -0500 Subject: Realmedia related codecs fixes and enhancements * More tolerance to the file format variations. * AC3 coded files in realaudio format are now playable Full credit to Igor Poretsky Change-Id: Id24e94bc00623e89fb8c80403efa92f69ab1e5d7 --- lib/rbcodec/codecs/a52_rm.c | 109 ++++++++++++++++++++++++++++++----------- lib/rbcodec/codecs/atrac3_rm.c | 91 ++++++++++++++++++++++------------ lib/rbcodec/codecs/cook.c | 106 +++++++++++++++++++++++++-------------- lib/rbcodec/codecs/librm/rm.c | 59 ++++++++++++++-------- lib/rbcodec/codecs/librm/rm.h | 5 ++ lib/rbcodec/codecs/raac.c | 3 +- 6 files changed, 255 insertions(+), 118 deletions(-) (limited to 'lib/rbcodec/codecs') diff --git a/lib/rbcodec/codecs/a52_rm.c b/lib/rbcodec/codecs/a52_rm.c index bbfd1c735f..e5204762f4 100644 --- a/lib/rbcodec/codecs/a52_rm.c +++ b/lib/rbcodec/codecs/a52_rm.c @@ -44,6 +44,14 @@ static void init_rm(RMContext *rmctx) /* used outside liba52 */ static uint8_t buf[3840] IBSS_ATTR; +static uint8_t *bufptr = buf; +static uint8_t *bufpos = buf + 7; + +static void a52_decoder_reset(void) +{ + bufptr = buf; + bufpos = buf + 7; +} /* The following two functions, a52_decode_data and output_audio are taken from a52.c */ static inline void output_audio(sample_t *samples) @@ -52,10 +60,8 @@ static inline void output_audio(sample_t *samples) ci->pcmbuf_insert(&samples[0], &samples[256], 256); } -static void a52_decode_data(uint8_t *start, uint8_t *end) +static size_t a52_decode_data(uint8_t *start, uint8_t *end) { - static uint8_t *bufptr = buf; - static uint8_t *bufpos = buf + 7; /* * sample_rate and flags are static because this routine could * exit between the a52_syncinfo() and the ao_setup(), and we want @@ -65,6 +71,7 @@ static void a52_decode_data(uint8_t *start, uint8_t *end) static int flags; int bit_rate; int len; + size_t consumed = 0; while (1) { len = end - start; @@ -75,6 +82,7 @@ static void a52_decode_data(uint8_t *start, uint8_t *end) memcpy(bufptr, start, len); bufptr += len; start += len; + consumed += len; if (bufptr == bufpos) { if (bufpos == buf + 7) { int length; @@ -114,7 +122,7 @@ static void a52_decode_data(uint8_t *start, uint8_t *end) ci->set_elapsed(samplesdone/(frequency/1000)); bufptr = buf; bufpos = buf + 7; - continue; + break; error: //logf("Error decoding A52 stream\n"); bufptr = buf; @@ -122,6 +130,7 @@ static void a52_decode_data(uint8_t *start, uint8_t *end) } } } + return consumed; } /* this is the codec entry point */ @@ -143,11 +152,13 @@ enum codec_status codec_main(enum codec_entry_call_reason reason) /* this is called for each file to process */ enum codec_status codec_run(void) { - size_t n; + size_t consumed = 0, n = 0; uint8_t *filebuf; - int consumed, packet_offset; + int packet_offset; int playback_on = -1; size_t resume_offset; + size_t data_offset; + size_t packet_size; long action; intptr_t param; @@ -162,21 +173,28 @@ enum codec_status codec_run(void) ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); - ci->seek_buffer(ci->id3->first_frame_offset); + ci->seek_buffer(0); - /* Intializations */ + /* Initializations */ state = a52_init(0); ci->memset(&rmctx,0,sizeof(RMContext)); ci->memset(&pkt,0,sizeof(RMPacket)); init_rm(&rmctx); + data_offset = rmctx.data_offset + + ((rmctx.flags & RM_RAW_DATASTREAM) ? 0 : DATA_HEADER_SIZE); + packet_size = rmctx.block_align + + ((rmctx.flags & RM_RAW_DATASTREAM) ? + 0 : + (PACKET_HEADER_SIZE + + ((rmctx.flags & RM_PKT_V1) ? 1 : 0))); samplesdone = 0; /* check for a mid-track resume and force a seek time accordingly */ if (resume_offset) { - resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); + resume_offset -= MIN(resume_offset, data_offset); /* put number of subpackets to skip in resume_offset */ - resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); + resume_offset /= packet_size; param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); } @@ -186,11 +204,11 @@ enum codec_status codec_run(void) else { /* Seek to the first packet */ ci->set_elapsed(0); - ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE ); + ci->advance_buffer(data_offset); } /* The main decoding loop */ - while((unsigned)rmctx.audio_pkt_cnt < rmctx.nb_packets) { + while ((rmctx.flags & RM_RAW_DATASTREAM) || (unsigned)rmctx.audio_pkt_cnt < rmctx.nb_packets) { if (action == CODEC_ACTION_NULL) action = ci->get_command(¶m); @@ -198,34 +216,69 @@ enum codec_status codec_run(void) break; if (action == CODEC_ACTION_SEEK_TIME) { + /* Do not allow seeking beyond the file's length */ + if ((unsigned) param > ci->id3->length) { + ci->set_elapsed(ci->id3->length); + ci->seek_complete(); + break; + } + + if (n) + rm_ac3_swap_bytes(filebuf, (rmctx.flags & RM_RAW_DATASTREAM) ? n : rmctx.block_align); packet_offset = param / ((rmctx.block_align*8*1000)/rmctx.bit_rate); - ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + - packet_offset*(rmctx.block_align + PACKET_HEADER_SIZE)); + ci->seek_buffer(data_offset + packet_offset * packet_size); rmctx.audio_pkt_cnt = packet_offset; - samplesdone = (rmctx.sample_rate/1000 * param); - ci->set_elapsed(samplesdone/(frequency/1000)); + samplesdone = packet_offset * A52_SAMPLESPERFRAME; + ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); ci->seek_complete(); + a52_decoder_reset(); + consumed = 0; + n = 0; } action = CODEC_ACTION_NULL; - filebuf = ci->request_buffer(&n, rmctx.block_align + PACKET_HEADER_SIZE); - consumed = rm_get_packet(&filebuf, &rmctx, &pkt); - - if(consumed < 0 && playback_on != 0) { - if(playback_on == -1) { - /* Error only if packet-parsing failed and playback hadn't started */ - DEBUGF("rm_get_packet failed\n"); - return CODEC_ERROR; + if (rmctx.flags & RM_RAW_DATASTREAM) { + if (n > consumed) { + consumed += a52_decode_data(filebuf + consumed, filebuf + n); + ci->set_offset(ci->curpos + consumed); } else { - break; + if (n) { + rm_ac3_swap_bytes(filebuf, n); + ci->advance_buffer(n); + } + filebuf = ci->request_buffer(&n, BUFFER_SIZE); + if (n == 0) + break; + rm_ac3_swap_bytes(filebuf, n); + consumed = 0; } } + else { + filebuf = ci->request_buffer(&n, packet_size); + + if (n == 0) + break; + + if (rm_get_packet(&filebuf, &rmctx, &pkt) < 0 && playback_on != 0) { + if(playback_on == -1) { + /* Error only if packet-parsing failed and playback hadn't started */ + DEBUGF("rm_get_packet failed\n"); + return CODEC_ERROR; + } + else { + break; + } + } - playback_on = 1; - a52_decode_data(filebuf, filebuf + rmctx.block_align); - ci->advance_buffer(pkt.length); + playback_on = 1; + consumed = 0; + while (consumed < rmctx.block_align) + consumed += a52_decode_data(filebuf + consumed, filebuf + rmctx.block_align); + rm_ac3_swap_bytes(filebuf, rmctx.block_align); + ci->advance_buffer(pkt.length); + } } return CODEC_OK; diff --git a/lib/rbcodec/codecs/atrac3_rm.c b/lib/rbcodec/codecs/atrac3_rm.c index 59dbd29cad..af38b79fc4 100644 --- a/lib/rbcodec/codecs/atrac3_rm.c +++ b/lib/rbcodec/codecs/atrac3_rm.c @@ -21,7 +21,6 @@ #include -#include "logf.h" #include "codeclib.h" #include "inttypes.h" #include "libatrac/atrac3.h" @@ -37,10 +36,26 @@ static void init_rm(RMContext *rmctx) /* initialize the RMContext */ memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext)); - /* and atrac3 expects extadata in id3v2buf, so we shall give it that */ + /* and atrac3 expects extradata in id3v2buf, so we shall give it that */ memcpy(ci->id3->id3v2buf, (char*)rmctx->codec_extradata, rmctx->extradata_size*sizeof(char)); } +static int request_packet(int size) +{ + int consumed = 0; + while (1) + { + uint8_t *buffer = ci->request_buffer((size_t *)(&consumed), size); + if (!consumed) + break; + consumed = rm_get_packet(&buffer, &rmctx, &pkt); + if (consumed < 0 || consumed == size) + break; + ci->advance_buffer(size); + } + return consumed; +} + /* this is the codec entry point */ enum codec_status codec_main(enum codec_entry_call_reason reason) { @@ -52,12 +67,10 @@ enum codec_status codec_main(enum codec_entry_call_reason reason) /* this is called for each file to process */ enum codec_status codec_run(void) { - static size_t buff_size; int datasize, res, consumed, i, time_offset; - uint8_t *bit_buffer; uint16_t fs,sps,h; uint32_t packet_count; - int scrambling_unit_size, num_units, elapsed; + int spn, packet_header_size, scrambling_unit_size, num_units, elapsed; int playback_on = -1; size_t resume_offset; intptr_t param; @@ -85,14 +98,17 @@ enum codec_status codec_run(void) ci->configure(DSP_SET_STEREO_MODE, rmctx.nb_channels == 1 ? STEREO_MONO : STEREO_NONINTERLEAVED); + packet_header_size = PACKET_HEADER_SIZE + + ((rmctx.flags & RM_PKT_V1) ? 1 : 0); packet_count = rmctx.nb_packets; rmctx.audio_framesize = rmctx.block_align; rmctx.block_align = rmctx.sub_packet_size; fs = rmctx.audio_framesize; sps= rmctx.block_align; h = rmctx.sub_packet_h; - scrambling_unit_size = h * (fs + PACKET_HEADER_SIZE); - + scrambling_unit_size = h * (fs + packet_header_size); + spn = h * fs / sps; + res = atrac3_decode_init(&q, ci->id3); if(res < 0) { DEBUGF("failed to initialize RM atrac decoder\n"); @@ -102,10 +118,10 @@ enum codec_status codec_run(void) /* check for a mid-track resume and force a seek time accordingly */ if(resume_offset) { resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); - num_units = (int)resume_offset / scrambling_unit_size; - /* put number of subpackets to skip in resume_offset */ - resume_offset /= (sps + PACKET_HEADER_SIZE); - elapsed = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); + num_units = (int)resume_offset / scrambling_unit_size; + /* put number of packets to skip in resume_offset */ + resume_offset = num_units * h; + elapsed = (int)resume_offset * ((8000LL * fs)/rmctx.bit_rate); } if (elapsed > 0) { @@ -123,8 +139,9 @@ enum codec_status codec_run(void) seek_start : while((unsigned)elapsed < rmctx.duration) { - bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); - consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); + consumed = request_packet(scrambling_unit_size); + if (!consumed) + break; if(consumed < 0 && playback_on != 0) { if(playback_on == -1) { /* Error only if packet-parsing failed and playback hadn't started */ @@ -135,7 +152,7 @@ seek_start : return CODEC_OK; } - for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++) + for (i = 0; i < spn; i++) { if (action == CODEC_ACTION_NULL) action = ci->get_command(¶m); @@ -164,10 +181,11 @@ seek_start : action = CODEC_ACTION_NULL; goto seek_start; } - num_units = (param/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps)); - ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * num_units); - bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); - consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); + num_units = (param/(sps*1000*8/rmctx.bit_rate))/spn; + ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + scrambling_unit_size * num_units); + consumed = request_packet(scrambling_unit_size); + if (!consumed) + return CODEC_OK; if(consumed < 0 && playback_on != 0) { if(playback_on == -1) { /* Error only if packet-parsing failed and playback hadn't started */ @@ -178,19 +196,32 @@ seek_start : return CODEC_OK; } - packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units; + packet_count = rmctx.nb_packets - h * num_units; rmctx.frame_number = (param/(sps*1000*8/rmctx.bit_rate)); - while(rmctx.audiotimestamp > (unsigned) param) { + while (rmctx.audiotimestamp > (unsigned)param && num_units-- > 0) { rmctx.audio_pkt_cnt = 0; - ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * (num_units-1)); - bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); - consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); - packet_count += rmctx.audio_pkt_cnt; - num_units--; + ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + scrambling_unit_size * num_units); + consumed = request_packet(scrambling_unit_size); + if (!consumed) + return CODEC_OK; + if(consumed < 0 && playback_on != 0) { + if(playback_on == -1) { + /* Error only if packet-parsing failed and playback hadn't started */ + DEBUGF("rm_get_packet failed\n"); + return CODEC_ERROR; + } + else + return CODEC_OK; + } + + packet_count += h; } + + if (num_units < 0) + rmctx.audiotimestamp = 0; time_offset = param - rmctx.audiotimestamp; i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate)); - elapsed = rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i; + elapsed = param; ci->set_elapsed(elapsed); ci->seek_complete(); } @@ -198,11 +229,11 @@ seek_start : action = CODEC_ACTION_NULL; if(pkt.length) - res = atrac3_decode_frame(rmctx.block_align, &q, &datasize, pkt.frames[i], rmctx.block_align); + res = atrac3_decode_frame(sps, &q, &datasize, pkt.frames[i], sps); else /* indicates that there are no remaining frames */ return CODEC_OK; - if(res != rmctx.block_align) { + if (res != sps) { DEBUGF("codec error\n"); return CODEC_ERROR; } @@ -214,9 +245,9 @@ seek_start : ci->set_elapsed(elapsed); rmctx.frame_number++; } - packet_count -= rmctx.audio_pkt_cnt; + packet_count -= h; rmctx.audio_pkt_cnt = 0; - ci->advance_buffer(consumed); + ci->advance_buffer(scrambling_unit_size); } return CODEC_OK; diff --git a/lib/rbcodec/codecs/cook.c b/lib/rbcodec/codecs/cook.c index af1f5e1a87..254e71f576 100644 --- a/lib/rbcodec/codecs/cook.c +++ b/lib/rbcodec/codecs/cook.c @@ -21,7 +21,6 @@ #include -#include "logf.h" #include "codeclib.h" #include "inttypes.h" #include "libcook/cook.h" @@ -38,6 +37,22 @@ static void init_rm(RMContext *rmctx) memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext)); } +static int request_packet(int size) +{ + int consumed = 0; + while (1) + { + uint8_t *buffer = ci->request_buffer((size_t *)(&consumed), size); + if (!consumed) + break; + consumed = rm_get_packet(&buffer, &rmctx, &pkt); + if (consumed < 0 || consumed == size) + break; + ci->advance_buffer(size); + } + return consumed; +} + /* this is the codec entry point */ enum codec_status codec_main(enum codec_entry_call_reason reason) { @@ -49,12 +64,10 @@ enum codec_status codec_main(enum codec_entry_call_reason reason) /* this is called for each file to process */ enum codec_status codec_run(void) { - static size_t buff_size; int datasize, res, consumed, i, time_offset; - uint8_t *bit_buffer; uint16_t fs,sps,h; uint32_t packet_count; - int scrambling_unit_size, num_units; + int spn, packet_header_size, scrambling_unit_size, num_units; size_t resume_offset; intptr_t param; long action; @@ -84,14 +97,17 @@ enum codec_status codec_run(void) ci->configure(DSP_SET_STEREO_MODE, rmctx.nb_channels == 1 ? STEREO_MONO : STEREO_NONINTERLEAVED); + packet_header_size = PACKET_HEADER_SIZE + + ((rmctx.flags & RM_PKT_V1) ? 1 : 0); packet_count = rmctx.nb_packets; rmctx.audio_framesize = rmctx.block_align; rmctx.block_align = rmctx.sub_packet_size; fs = rmctx.audio_framesize; sps= rmctx.block_align; h = rmctx.sub_packet_h; - scrambling_unit_size = h * (fs + PACKET_HEADER_SIZE); - + scrambling_unit_size = h * (fs + packet_header_size); + spn = h * fs / sps; + res =cook_decode_init(&rmctx, &q); if(res < 0) { DEBUGF("failed to initialize cook decoder\n"); @@ -101,10 +117,10 @@ enum codec_status codec_run(void) /* check for a mid-track resume and force a seek time accordingly */ if(resume_offset) { resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); - num_units = (int)resume_offset / scrambling_unit_size; - /* put number of subpackets to skip in resume_offset */ - resume_offset /= (sps + PACKET_HEADER_SIZE); - param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); + num_units = (int)resume_offset / scrambling_unit_size; + /* put number of packets to skip in resume_offset */ + resume_offset = num_units * h; + param = (int)resume_offset * ((8000LL * fs)/rmctx.bit_rate); } if (param) { @@ -120,14 +136,15 @@ enum codec_status codec_run(void) seek_start : while(packet_count) { - bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); - consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); + consumed = request_packet(scrambling_unit_size); + if (!consumed) + break; if(consumed < 0) { DEBUGF("rm_get_packet failed\n"); return CODEC_ERROR; } - - for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++) + + for (i = 0; i < spn; i++) { if (action == CODEC_ACTION_NULL) action = ci->get_command(¶m); @@ -155,52 +172,65 @@ seek_start : action = CODEC_ACTION_NULL; goto seek_start; } - num_units = (param/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps)); - ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * num_units); - bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); - consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); + num_units = (param/(sps*1000*8/rmctx.bit_rate))/spn; + ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + scrambling_unit_size * num_units); + consumed = request_packet(scrambling_unit_size); + if (!consumed) { + ci->seek_complete(); + return CODEC_OK; + } if(consumed < 0) { - DEBUGF("rm_get_packet failed\n"); + DEBUGF("rm_get_packet failed\n"); ci->seek_complete(); return CODEC_ERROR; } - packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units; + + packet_count = rmctx.nb_packets - h * num_units; rmctx.frame_number = (param/(sps*1000*8/rmctx.bit_rate)); - while(rmctx.audiotimestamp > (unsigned) param) { + while(rmctx.audiotimestamp > (unsigned)param && num_units-- > 0) { rmctx.audio_pkt_cnt = 0; - ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * (num_units-1)); - bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); - consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); - packet_count += rmctx.audio_pkt_cnt; - num_units--; + ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + scrambling_unit_size * num_units); + consumed = request_packet(scrambling_unit_size); + if (!consumed) { + ci->seek_complete(); + return CODEC_OK; + } + if(consumed < 0) { + ci->seek_complete(); + DEBUGF("rm_get_packet failed\n"); + return CODEC_ERROR; + } + + packet_count += h; } + + if (num_units < 0) + rmctx.audiotimestamp = 0; time_offset = param - rmctx.audiotimestamp; i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate)); - ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i); + ci->set_elapsed(param); ci->seek_complete(); } action = CODEC_ACTION_NULL; - res = cook_decode_frame(&rmctx,&q, rm_outbuf, &datasize, pkt.frames[i], rmctx.block_align); - rmctx.frame_number++; - - /* skip the first two frames; no valid audio */ - if(rmctx.frame_number < 3) continue; + res = cook_decode_frame(&rmctx,&q, rm_outbuf, &datasize, pkt.frames[i], sps); - if(res != rmctx.block_align) { + if (res != sps) { DEBUGF("codec error\n"); return CODEC_ERROR; } - ci->pcmbuf_insert(rm_outbuf, - rm_outbuf+q.samples_per_channel, - q.samples_per_channel); + if(datasize) + ci->pcmbuf_insert(rm_outbuf, + rm_outbuf+q.samples_per_channel, + q.samples_per_channel); ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i); + rmctx.frame_number++; } - packet_count -= rmctx.audio_pkt_cnt; + packet_count -= h; rmctx.audio_pkt_cnt = 0; - ci->advance_buffer(consumed); + ci->advance_buffer(scrambling_unit_size); } return CODEC_OK; diff --git a/lib/rbcodec/codecs/librm/rm.c b/lib/rbcodec/codecs/librm/rm.c index eabbe5d92a..e499961a7f 100644 --- a/lib/rbcodec/codecs/librm/rm.c +++ b/lib/rbcodec/codecs/librm/rm.c @@ -27,8 +27,6 @@ #include "codeclib.h" #endif -#define SWAP(a, b) do{uint8_t SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) - #ifdef TEST #include #include @@ -500,17 +498,33 @@ void rm_get_packet_fd(int fd,RMContext *rmctx, RMPacket *pkt) } #endif /*TEST*/ +void rm_ac3_swap_bytes(uint8_t *buf, int bufsize) +{ + uint8_t *bufptr; + for (bufptr = buf; bufptr < buf + bufsize - 1; bufptr += 2) + { + bufptr[0] ^= bufptr[1]; + bufptr[1] ^= bufptr[0]; + bufptr[0] ^= bufptr[1]; + } +} + int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt) { int consumed = 0; + int headerlen; /* rockbox: comment 'set but unused' variables uint8_t unknown; */ - uint16_t x, place; + uint16_t x; uint16_t sps = rmctx->sub_packet_size; uint16_t h = rmctx->sub_packet_h; - uint16_t y = rmctx->sub_packet_cnt; + uint16_t y = 0; uint16_t w = rmctx->audio_framesize; + + rmctx->sub_packet_cnt = 0; + rmctx->audio_pkt_cnt = 0; + do { y = rmctx->sub_packet_cnt; @@ -523,6 +537,7 @@ int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt) return -1; } + headerlen = PACKET_HEADER_SIZE + (pkt->version ? 1 : 0); pkt->length = rm_get_uint16be(*src+2); pkt->stream_number = rm_get_uint16be(*src+4); pkt->timestamp = rm_get_uint32be(*src+6); @@ -534,25 +549,27 @@ int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt) pkt->flags = rm_get_uint8(*src+11); if(pkt->version == 1) - /* unknown = */ rm_get_uint8(*src+10); + /* unknown = */ rm_get_uint8(*src+12); - if (pkt->flags & 2) /* keyframe */ - y = rmctx->sub_packet_cnt = 0; + if (pkt->flags & 2) { /* keyframe */ + if (y) + return consumed; + y = 0; + } if (!y) rmctx->audiotimestamp = pkt->timestamp; - + /* Skip packet header */ - advance_buffer(src, PACKET_HEADER_SIZE); - consumed += PACKET_HEADER_SIZE; + advance_buffer(src, headerlen); + consumed += headerlen; if (rmctx->codec_type == CODEC_COOK || rmctx->codec_type == CODEC_ATRAC) { for(x = 0 ; x < w/sps; x++) { - place = sps*(h*x+((h+1)/2)*(y&1)+(y>>1)); - pkt->frames[place/sps] = *src; + pkt->frames[h*x+((h+1)/2)*(y&1)+(y>>1)] = *src; advance_buffer(src,sps); consumed += sps; } - } + } else if (rmctx->codec_type == CODEC_AAC) { rmctx->sub_packet_cnt = (rm_get_uint16be(*src) & 0xf0) >> 4; advance_buffer(src, 2); @@ -563,22 +580,22 @@ int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt) advance_buffer(src, 2); consumed += 2; } - rmctx->audio_pkt_cnt = --rmctx->sub_packet_cnt; + rmctx->audio_pkt_cnt = rmctx->sub_packet_cnt; } + break; } else if (rmctx->codec_type == CODEC_AC3) { /* The byte order of the data is reversed from standard AC3 */ - for(x = 0; x < pkt->length - PACKET_HEADER_SIZE; x+=2) { - SWAP((*src)[0], (*src)[1]); - *src += 2; - } - *src -= x; + rm_ac3_swap_bytes(*src, pkt->length - headerlen); + break; } + else return -1; /* invalid codec type */ + rmctx->audio_pkt_cnt++; }while(++(rmctx->sub_packet_cnt) < h); -return consumed; + return consumed; } #ifdef DEBUG @@ -587,6 +604,6 @@ void dump_rm_context(RMContext *rmctx) DEBUGF("block_align = %d\n", rmctx->block_align); DEBUGF("nb_channels = %d\n", rmctx->nb_channels); DEBUGF("sample_rate = %d\n", rmctx->sample_rate); - DEBUGF("bit_rate = %d\n", rmctx->bit_rate ); + DEBUGF("bit_rate = %ld\n", rmctx->bit_rate ); } #endif diff --git a/lib/rbcodec/codecs/librm/rm.h b/lib/rbcodec/codecs/librm/rm.h index c4a4e3a77e..47ea559f2e 100644 --- a/lib/rbcodec/codecs/librm/rm.h +++ b/lib/rbcodec/codecs/librm/rm.h @@ -25,6 +25,9 @@ #include #include "bytestream.h" +#define RM_RAW_DATASTREAM 0x0100 +#define RM_PKT_V1 0x0200 + #define MAX_EXTRADATA_SIZE 16 #define DATA_HEADER_SIZE 18 #define PACKET_HEADER_SIZE 12 @@ -86,6 +89,8 @@ typedef struct rm_context int real_parse_header(int fd, RMContext *rmctx); +void rm_ac3_swap_bytes(uint8_t *buf, int bufsize); + /* Get a (sub_packet_h*frames_per_packet) number of audio frames from a memory buffer */ int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt); diff --git a/lib/rbcodec/codecs/raac.c b/lib/rbcodec/codecs/raac.c index e77d432680..6856afc52e 100644 --- a/lib/rbcodec/codecs/raac.c +++ b/lib/rbcodec/codecs/raac.c @@ -109,7 +109,8 @@ enum codec_status codec_run(void) if (resume_offset) { resume_offset -= MIN(resume_offset, rmctx.data_offset + DATA_HEADER_SIZE); /* put number of subpackets to skip in resume_offset */ - resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); + resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE + + ((rmctx.flags & RM_PKT_V1) ? 1 : 0)); param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); } -- cgit