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
diff --git a/lib/rbcodec/codecs/a52_rm.c b/lib/rbcodec/codecs/a52_rm.c
index bbfd1c7..e520476 100644
--- a/lib/rbcodec/codecs/a52_rm.c
+++ b/lib/rbcodec/codecs/a52_rm.c
@@ -44,6 +44,14 @@
/* 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 @@
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 int flags;
int bit_rate;
int len;
+ size_t consumed = 0;
while (1) {
len = end - start;
@@ -75,6 +82,7 @@
memcpy(bufptr, start, len);
bufptr += len;
start += len;
+ consumed += len;
if (bufptr == bufpos) {
if (bufpos == buf + 7) {
int length;
@@ -114,7 +122,7 @@
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 @@
}
}
}
+ return consumed;
}
/* this is the codec entry point */
@@ -143,11 +152,13 @@
/* 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 @@
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 @@
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 @@
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);
- playback_on = 1;
- a52_decode_data(filebuf, filebuf + rmctx.block_align);
- ci->advance_buffer(pkt.length);
+ 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;
+ 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 59dbd29..af38b79 100644
--- a/lib/rbcodec/codecs/atrac3_rm.c
+++ b/lib/rbcodec/codecs/atrac3_rm.c
@@ -21,7 +21,6 @@
#include <string.h>
-#include "logf.h"
#include "codeclib.h"
#include "inttypes.h"
#include "libatrac/atrac3.h"
@@ -37,10 +36,26 @@
/* 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 @@
/* 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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 af1f5e1..254e71f 100644
--- a/lib/rbcodec/codecs/cook.c
+++ b/lib/rbcodec/codecs/cook.c
@@ -21,7 +21,6 @@
#include <string.h>
-#include "logf.h"
#include "codeclib.h"
#include "inttypes.h"
#include "libcook/cook.h"
@@ -38,6 +37,22 @@
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 @@
/* 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 @@
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 @@
/* 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 @@
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 @@
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++;
+ res = cook_decode_frame(&rmctx,&q, rm_outbuf, &datasize, pkt.frames[i], sps);
- /* skip the first two frames; no valid audio */
- if(rmctx.frame_number < 3) continue;
-
- 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 eabbe5d..e499961 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 <fcntl.h>
#include <unistd.h>
@@ -500,17 +498,33 @@
}
#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 @@
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 @@
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 @@
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 @@
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 c4a4e3a..47ea559 100644
--- a/lib/rbcodec/codecs/librm/rm.h
+++ b/lib/rbcodec/codecs/librm/rm.h
@@ -25,6 +25,9 @@
#include <inttypes.h>
#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 @@
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 e77d432..6856afc 100644
--- a/lib/rbcodec/codecs/raac.c
+++ b/lib/rbcodec/codecs/raac.c
@@ -109,7 +109,8 @@
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);
}
diff --git a/lib/rbcodec/metadata/metadata.c b/lib/rbcodec/metadata/metadata.c
index 87ea922..7ca4b1a 100644
--- a/lib/rbcodec/metadata/metadata.c
+++ b/lib/rbcodec/metadata/metadata.c
@@ -444,13 +444,13 @@
/* Load codec specific track tag information and confirm the codec type. */
if (!entry->parse_func)
{
- DEBUGF("nothing to parse for %s (format %s)", trackname, entry->label);
+ DEBUGF("nothing to parse for %s (format %s)\n", trackname, entry->label);
return false;
}
if (!entry->parse_func(fd, id3))
{
- DEBUGF("parsing %s failed (format: %s)", trackname, entry->label);
+ DEBUGF("parsing %s failed (format: %s)\n", trackname, entry->label);
return false;
}
diff --git a/lib/rbcodec/metadata/rm.c b/lib/rbcodec/metadata/rm.c
index 2a5a289..1e33f0b 100644
--- a/lib/rbcodec/metadata/rm.c
+++ b/lib/rbcodec/metadata/rm.c
@@ -89,7 +89,7 @@
}
#endif
-static inline int real_read_audio_stream_info(int fd, RMContext *rmctx)
+static int real_read_audio_stream_info(int fd, RMContext *rmctx)
{
int skipped = 0;
uint32_t version;
@@ -111,6 +111,7 @@
DEBUGF(" version=0x%04lx\n",((version >> 16) & 0xff));
if (((version >> 16) & 0xff) == 3) {
/* Very old version */
+ return -1;
} else {
#ifdef SIMULATOR
real_read_object_header(fd, &obj);
@@ -218,7 +219,7 @@
return skipped;
}
-static int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3)
+static inline int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3)
{
struct real_object_t obj;
int res;
@@ -242,6 +243,7 @@
uint32_t max_bitrate;
uint16_t num_streams;
uint32_t next_data_off;
+ uint16_t pkt_version;
uint8_t header_end;
memset(&obj,0,sizeof(obj));
@@ -250,6 +252,35 @@
if (obj.fourcc == FOURCC('.','r','a',0xfd))
{
+ lseek(fd, 4, SEEK_SET);
+ skipped = real_read_audio_stream_info(fd, rmctx);
+ if (skipped > 0 && rmctx->codec_type == CODEC_AC3)
+ {
+ read_uint8(fd,&len);
+ skipped += (int)read_string(fd, id3->id3v1buf[0], sizeof(id3->id3v1buf[0]), '\0', len);
+ read_uint8(fd,&len);
+ skipped += (int)read_string(fd, id3->id3v1buf[1], sizeof(id3->id3v1buf[1]), '\0', len);
+ read_uint8(fd,&len);
+ skipped += (int)read_string(fd, id3->id3v1buf[2], sizeof(id3->id3v1buf[2]), '\0', len);
+ read_uint8(fd,&len);
+ skipped += (int)read_string(fd, id3->id3v1buf[3], sizeof(id3->id3v1buf[3]), '\0', len);
+ rmctx->data_offset = skipped + 8;
+ rmctx->bit_rate = rmctx->block_align * rmctx->sample_rate / 192;
+ if (rmctx->block_align)
+ rmctx->nb_packets = (filesize(fd) - rmctx->data_offset) / rmctx->block_align;
+ if (rmctx->sample_rate)
+ rmctx->duration = (uint32_t)(256LL * 6 * 1000 * rmctx->nb_packets / rmctx->sample_rate);
+ rmctx->flags |= RM_RAW_DATASTREAM;
+
+ DEBUGF(" data_offset = %ld\n",rmctx->data_offset);
+ DEBUGF(" avg_bitrate = %ld\n",rmctx->bit_rate);
+ DEBUGF(" duration = %ld\n",rmctx->duration);
+ DEBUGF(" title=\"%s\"\n",id3->id3v1buf[0]);
+ DEBUGF(" author=\"%s\"\n",id3->id3v1buf[1]);
+ DEBUGF(" copyright=\"%s\"\n",id3->id3v1buf[2]);
+ DEBUGF(" comment=\"%s\"\n",id3->id3v1buf[3]);
+ return 0;
+ }
/* Very old .ra format - not yet supported */
return -1;
}
@@ -305,6 +336,8 @@
DEBUGF(" data_offset = %ld\n",rmctx->data_offset);
DEBUGF(" num_streams = %d\n",num_streams);
DEBUGF(" flags=0x%04x\n",rmctx->flags);
+
+ rmctx->flags &= 0x00FF;
break;
case FOURCC('C','O','N','T'):
@@ -409,7 +442,22 @@
DEBUGF(" data_nb_packets = %ld\n",rmctx->nb_packets);
DEBUGF(" next DATA offset = %ld\n",next_data_off);
- header_end = 1;
+
+ if (!next_data_off)
+ {
+ if (rmctx->duration == 0 && rmctx->bit_rate != 0)
+ {
+ rmctx->duration = (uint32_t)(8000LL * rmctx->nb_packets * rmctx->block_align / rmctx->bit_rate);
+ DEBUGF(" estimated duration = %ld\n",rmctx->duration);
+ }
+ read_uint16be(fd, &pkt_version);
+ skipped += 2;
+ DEBUGF(" pkt_version=0x%04x\n", pkt_version);
+ if (pkt_version)
+ rmctx->flags |= RM_PKT_V1;
+ rmctx->data_offset = curpos;
+ header_end = 1;
+ }
break;
}
if(header_end) break;
@@ -456,7 +504,7 @@
id3->channels = rmctx->nb_channels;
id3->extradata_size = rmctx->extradata_size;
- id3->bitrate = rmctx->bit_rate / 1000;
+ id3->bitrate = (rmctx->bit_rate + 500) / 1000;
id3->frequency = rmctx->sample_rate;
id3->length = rmctx->duration;
id3->filesize = filesize(fd);