1
0
Fork 0
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:
Dave Chapman 2007-07-10 13:37:16 +00:00
parent 830f4fcc8a
commit 47e969278b

View file

@ -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,23 +192,34 @@ 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);
for (i=0; i<payload_count; i++) {
stream_id = datap[0]&0x7f;
datap++;
bytesread++; bytesread++;
if ((tmp8 & 0x7f) != wfx->audiostream) {
/* Not interested in this packet, just skip it */
ci->advance_buffer(length - bytesread);
return 0;
} 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) +
GETLEN2b((packet_property >> 4) & 0x03); GETLEN2b((packet_property >> 4) & 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,21 +267,37 @@ 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 */
enum codec_status codec_main(void) enum codec_status codec_main(void)
@ -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;