forked from len0rd/rockbox
ASF parser improvements - it now correctly handles files containing multiple payloads. i.e. files where the audio packets are split into multiple payloads, and streams where audio/video payloads are mixed within the same packet.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13840 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
830f4fcc8a
commit
47e969278b
1 changed files with 66 additions and 42 deletions
|
|
@ -67,9 +67,10 @@ static unsigned short get_short_le(void* buf)
|
||||||
(((bits) != 0x03) ? ((bits) != 0x02) ? ((bits) != 0x01) ? \
|
(((bits) != 0x03) ? ((bits) != 0x02) ? ((bits) != 0x01) ? \
|
||||||
0 : *(data) : get_short_le(data) : get_long_le(data))
|
0 : *(data) : get_short_le(data) : get_long_le(data))
|
||||||
|
|
||||||
static int asf_read_packet(int* padding, asf_waveformatex_t* wfx)
|
static int asf_read_packet(uint8_t** audiobuf, int* audiobufsize, int* packetlength, asf_waveformatex_t* wfx)
|
||||||
{
|
{
|
||||||
uint8_t tmp8, packet_flags, packet_property;
|
uint8_t tmp8, packet_flags, packet_property;
|
||||||
|
int stream_id;
|
||||||
int ec_length, opaque_data, ec_length_type;
|
int ec_length, opaque_data, ec_length_type;
|
||||||
int datalen;
|
int datalen;
|
||||||
uint8_t data[18];
|
uint8_t data[18];
|
||||||
|
|
@ -87,16 +88,19 @@ static int asf_read_packet(int* padding, asf_waveformatex_t* wfx)
|
||||||
uint32_t media_object_number;
|
uint32_t media_object_number;
|
||||||
uint32_t media_object_offset;
|
uint32_t media_object_offset;
|
||||||
uint32_t bytesread = 0;
|
uint32_t bytesread = 0;
|
||||||
|
uint8_t* buf;
|
||||||
|
size_t bufsize;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (ci->read_filebuf(&tmp8, 1) == 0) {
|
if (ci->read_filebuf(&tmp8, 1) == 0) {
|
||||||
return ASF_ERROR_EOF;
|
return ASF_ERROR_EOF;
|
||||||
}
|
}
|
||||||
bytesread++;
|
bytesread++;
|
||||||
|
|
||||||
|
//DEBUGF("tmp8=0x%02x\n",tmp8);
|
||||||
/* TODO: We need a better way to detect endofstream */
|
/* TODO: We need a better way to detect endofstream */
|
||||||
if (tmp8 != 0x82) { return -1; }
|
if (tmp8 != 0x82) { return -1; }
|
||||||
|
|
||||||
//DEBUGF("tmp8=0x%02x\n",tmp8);
|
|
||||||
|
|
||||||
if (tmp8 & 0x80) {
|
if (tmp8 & 0x80) {
|
||||||
ec_length = tmp8 & 0x0f;
|
ec_length = tmp8 & 0x0f;
|
||||||
|
|
@ -188,22 +192,33 @@ static int asf_read_packet(int* padding, asf_waveformatex_t* wfx)
|
||||||
return ASF_ERROR_INVALID_LENGTH;
|
return ASF_ERROR_INVALID_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ci->read_filebuf(&tmp8, 1) == 0) {
|
|
||||||
return ASF_ERROR_EOF;
|
/* We now parse the individual payloads, and move all payloads
|
||||||
|
belonging to our audio stream to a contiguous block, starting at
|
||||||
|
the location of the first payload.
|
||||||
|
*/
|
||||||
|
|
||||||
|
*audiobuf = NULL;
|
||||||
|
*audiobufsize = 0;
|
||||||
|
*packetlength = length - bytesread;
|
||||||
|
|
||||||
|
buf = ci->request_buffer(&bufsize, length);
|
||||||
|
datap = buf;
|
||||||
|
|
||||||
|
if (bufsize != length) {
|
||||||
|
/* This should only happen with packets larger than 32KB (the
|
||||||
|
guard buffer size). All the streams I've seen have
|
||||||
|
relatively small packets less than about 8KB), but I don't
|
||||||
|
know what is expected.
|
||||||
|
*/
|
||||||
|
DEBUGF("Could not read packet (%d bytes), aborting\n",(int)length);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
//DEBUGF("stream = %u\n",tmp8&0x7f);
|
|
||||||
bytesread++;
|
|
||||||
|
|
||||||
if ((tmp8 & 0x7f) != wfx->audiostream) {
|
for (i=0; i<payload_count; i++) {
|
||||||
/* Not interested in this packet, just skip it */
|
stream_id = datap[0]&0x7f;
|
||||||
ci->advance_buffer(length - bytesread);
|
datap++;
|
||||||
return 0;
|
bytesread++;
|
||||||
} else {
|
|
||||||
/* We are now at the data */
|
|
||||||
//DEBUGF("Read packet - length=%u, padding_length=%u, send_time=%u, duration=%u, payload_count=%d, bytesread=%d\n",length,padding_length,(int)send_time,duration,payload_count,bytesread);
|
|
||||||
|
|
||||||
/* TODO: Loop through all payloads in this packet - or do we
|
|
||||||
assume that audio streams only have one payload per packet? */
|
|
||||||
|
|
||||||
payload_hdrlen = GETLEN2b(packet_property & 0x03) +
|
payload_hdrlen = GETLEN2b(packet_property & 0x03) +
|
||||||
GETLEN2b((packet_property >> 2) & 0x03) +
|
GETLEN2b((packet_property >> 2) & 0x03) +
|
||||||
|
|
@ -221,12 +236,7 @@ static int asf_read_packet(int* padding, asf_waveformatex_t* wfx)
|
||||||
return ASF_ERROR_OUTOFMEM;
|
return ASF_ERROR_OUTOFMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ci->read_filebuf(data, payload_hdrlen) == 0) {
|
|
||||||
return ASF_ERROR_EOF;
|
|
||||||
}
|
|
||||||
bytesread += payload_hdrlen;
|
bytesread += payload_hdrlen;
|
||||||
|
|
||||||
datap = data;
|
|
||||||
media_object_number = GETVALUE2b((packet_property >> 4) & 0x03, datap);
|
media_object_number = GETVALUE2b((packet_property >> 4) & 0x03, datap);
|
||||||
datap += GETLEN2b((packet_property >> 4) & 0x03);
|
datap += GETLEN2b((packet_property >> 4) & 0x03);
|
||||||
media_object_offset = GETVALUE2b((packet_property >> 2) & 0x03, datap);
|
media_object_offset = GETVALUE2b((packet_property >> 2) & 0x03, datap);
|
||||||
|
|
@ -236,10 +246,9 @@ static int asf_read_packet(int* padding, asf_waveformatex_t* wfx)
|
||||||
|
|
||||||
/* TODO: Validate replicated_length */
|
/* TODO: Validate replicated_length */
|
||||||
/* TODO: Is the content of this important for us? */
|
/* TODO: Is the content of this important for us? */
|
||||||
ci->advance_buffer(replicated_length);
|
datap += replicated_length;
|
||||||
bytesread += replicated_length;
|
bytesread += replicated_length;
|
||||||
|
|
||||||
|
|
||||||
multiple = packet_flags & 0x01;
|
multiple = packet_flags & 0x01;
|
||||||
|
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
|
|
@ -258,20 +267,36 @@ static int asf_read_packet(int* padding, asf_waveformatex_t* wfx)
|
||||||
return ASF_ERROR_INVALID_LENGTH;
|
return ASF_ERROR_INVALID_LENGTH;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (ci->read_filebuf(&data, x) == 0) {
|
payload_datalen = GETVALUE2b(payload_length_type, datap);
|
||||||
return ASF_ERROR_EOF;
|
datap += x;
|
||||||
}
|
|
||||||
bytesread += x;
|
bytesread += x;
|
||||||
payload_datalen = GETVALUE2b(payload_length_type, data);
|
|
||||||
} else {
|
} else {
|
||||||
payload_datalen = length - bytesread;
|
payload_datalen = length - bytesread - padding_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
//DEBUGF("WE HAVE DATA - %d bytes\n", payload_datalen);
|
if (stream_id == wfx->audiostream)
|
||||||
// lseek(fd, payload_datalen, SEEK_CUR);
|
{
|
||||||
*padding = padding_length;
|
if (*audiobuf == NULL) {
|
||||||
return payload_datalen;
|
/* The first payload can stay where it is */
|
||||||
|
*audiobuf = datap;
|
||||||
|
*audiobufsize = payload_datalen;
|
||||||
|
} else {
|
||||||
|
/* The second and subsequent payloads in this packet
|
||||||
|
that belong to the audio stream need to be moved to be
|
||||||
|
contiguous with the first payload.
|
||||||
|
*/
|
||||||
|
memmove(*audiobuf + *audiobufsize, datap, payload_datalen);
|
||||||
|
*audiobufsize += payload_datalen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
datap += payload_datalen;
|
||||||
|
bytesread += payload_datalen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (*audiobuf != NULL)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this is the codec entry point */
|
/* this is the codec entry point */
|
||||||
|
|
@ -282,11 +307,12 @@ enum codec_status codec_main(void)
|
||||||
int retval;
|
int retval;
|
||||||
asf_waveformatex_t wfx;
|
asf_waveformatex_t wfx;
|
||||||
uint32_t currentframe;
|
uint32_t currentframe;
|
||||||
unsigned char* inbuffer;
|
|
||||||
size_t resume_offset;
|
size_t resume_offset;
|
||||||
size_t n;
|
|
||||||
int i;
|
int i;
|
||||||
int wmares, res, padding;
|
int wmares, res;
|
||||||
|
uint8_t* audiobuf;
|
||||||
|
int audiobufsize;
|
||||||
|
int packetlength;
|
||||||
|
|
||||||
/* Generic codec initialisation */
|
/* Generic codec initialisation */
|
||||||
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
|
ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
|
||||||
|
|
@ -348,18 +374,16 @@ enum codec_status codec_main(void)
|
||||||
ci->seek_complete();
|
ci->seek_complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
res = asf_read_packet(&padding, &wfx);
|
res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx);
|
||||||
if (res > 0) {
|
if (res > 0) {
|
||||||
inbuffer = ci->request_buffer(&n, res - padding);
|
|
||||||
|
|
||||||
wma_decode_superframe_init(&wmadec,
|
wma_decode_superframe_init(&wmadec,
|
||||||
inbuffer,res - padding);
|
audiobuf, audiobufsize);
|
||||||
|
|
||||||
for (i=0; i < wmadec.nb_frames; i++)
|
for (i=0; i < wmadec.nb_frames; i++)
|
||||||
{
|
{
|
||||||
wmares = wma_decode_superframe_frame(&wmadec,
|
wmares = wma_decode_superframe_frame(&wmadec,
|
||||||
decoded,
|
decoded,
|
||||||
inbuffer,res - padding);
|
audiobuf, audiobufsize);
|
||||||
|
|
||||||
ci->yield ();
|
ci->yield ();
|
||||||
|
|
||||||
|
|
@ -375,9 +399,9 @@ enum codec_status codec_main(void)
|
||||||
}
|
}
|
||||||
ci->yield ();
|
ci->yield ();
|
||||||
}
|
}
|
||||||
|
|
||||||
ci->advance_buffer(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ci->advance_buffer(packetlength);
|
||||||
}
|
}
|
||||||
retval = CODEC_OK;
|
retval = CODEC_OK;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue