summaryrefslogtreecommitdiffstats
path: root/lib/rbcodec/codecs/a52_rm.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/a52_rm.c')
-rw-r--r--lib/rbcodec/codecs/a52_rm.c109
1 files changed, 81 insertions, 28 deletions
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(&param);
@@ -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;