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 ++++++++++++++++++++++++++++++++------------ 1 file changed, 81 insertions(+), 28 deletions(-) (limited to 'lib/rbcodec/codecs/a52_rm.c') 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; -- cgit v1.2.3