summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Giacomelli <giac2000@hotmail.com>2014-11-28 22:25:23 +0100
committerMichael Giacomelli <giac2000@hotmail.com>2014-11-28 22:30:05 +0100
commitaa2c55e1057c0c220a1eb37c99d2c251bfe850ab (patch)
tree0e69f0d611b2d343a9545719fda5913ef69747a4
parent0cd9e4e6bc9e485bb527ccd5bdfe7ce74445949d (diff)
downloadrockbox-aa2c55e1057c0c220a1eb37c99d2c251bfe850ab.tar.gz
rockbox-aa2c55e1057c0c220a1eb37c99d2c251bfe850ab.zip
Fix FS#13009.
This file revealed several problems with our ASF parser: 1) The packet count in the ASF was actually a 64 bit value, leading to overflow in very long files. 2) Seeking blindly trusted the bitrate listed in the ASF header rather than computing it from the packet size and number of packets. Fix these problems and fix a few minor issues. Change-Id: Ie0f68734e6423e837757528ddb155f3bdcc979f3
-rw-r--r--lib/rbcodec/codecs/libasf/asf.c14
-rw-r--r--lib/rbcodec/codecs/libasf/asf.h2
-rw-r--r--lib/rbcodec/metadata/asf.c30
3 files changed, 33 insertions, 13 deletions
diff --git a/lib/rbcodec/codecs/libasf/asf.c b/lib/rbcodec/codecs/libasf/asf.c
index 4e3235a422..5f6456a2cb 100644
--- a/lib/rbcodec/codecs/libasf/asf.c
+++ b/lib/rbcodec/codecs/libasf/asf.c
@@ -386,11 +386,17 @@ int asf_get_timestamp(int *duration)
386int asf_seek(int ms, asf_waveformatex_t* wfx) 386int asf_seek(int ms, asf_waveformatex_t* wfx)
387{ 387{
388 int time, duration, delta, temp, count=0; 388 int time, duration, delta, temp, count=0;
389 int bitrate = ci->id3->bitrate*1000/8;
389 390
390 /*estimate packet number from bitrate*/ 391 /*estimate packet number from bitrate*/
391 int initial_packet = ci->curpos/wfx->packet_size; 392 int initial_packet = ci->curpos/wfx->packet_size;
392 int packet_num = (((int64_t)ms)*(wfx->bitrate>>3))/wfx->packet_size/1000; 393 int packet_num = (((int64_t)ms)*(bitrate))/wfx->packet_size/1000;
393 int last_packet = ci->id3->filesize / wfx->packet_size; 394 /*subtract header size in case theres a lot of metadata*/
395 int last_packet = (ci->id3->filesize-ci->id3->first_frame_offset) / wfx->packet_size;
396
397 /*
398 DEBUGF("bitrate: %d\n", bitrate);
399 DEBUGF("attempting seek to: %d ms, initialp: %d, lastp: %d, estimating packet: %d, packet size: %d\n", ms, initial_packet, last_packet, packet_num, wfx->packet_size);*/
394 400
395 if (packet_num > last_packet) { 401 if (packet_num > last_packet) {
396 packet_num = last_packet; 402 packet_num = last_packet;
@@ -409,7 +415,7 @@ int asf_seek(int ms, asf_waveformatex_t* wfx)
409 415
410 /*check the time stamp of our packet*/ 416 /*check the time stamp of our packet*/
411 time = asf_get_timestamp(&duration); 417 time = asf_get_timestamp(&duration);
412 /*DEBUGF("seeked to %d ms with duration %d\n", time, duration);*/ 418 /*DEBUGF("seeked to %d ms (%d) with duration %d\n", time,packet_num, duration);*/
413 419
414 if (time < 0) { 420 if (time < 0) {
415 /*unknown error, try to recover*/ 421 /*unknown error, try to recover*/
@@ -427,7 +433,7 @@ int asf_seek(int ms, asf_waveformatex_t* wfx)
427 delta = ms-time; 433 delta = ms-time;
428 /*estimate new packet number from bitrate and our current position*/ 434 /*estimate new packet number from bitrate and our current position*/
429 temp += delta; 435 temp += delta;
430 packet_num = ((temp/1000)*(wfx->bitrate>>3) - (wfx->packet_size>>1))/wfx->packet_size; //round down! 436 packet_num = ((temp/1000)*(bitrate) - (wfx->packet_size<<1))/wfx->packet_size; //round down!
431 packet_offset = packet_num*wfx->packet_size; 437 packet_offset = packet_num*wfx->packet_size;
432 ci->seek_buffer(ci->id3->first_frame_offset+packet_offset); 438 ci->seek_buffer(ci->id3->first_frame_offset+packet_offset);
433 } 439 }
diff --git a/lib/rbcodec/codecs/libasf/asf.h b/lib/rbcodec/codecs/libasf/asf.h
index a7d384cf3d..2398a44eab 100644
--- a/lib/rbcodec/codecs/libasf/asf.h
+++ b/lib/rbcodec/codecs/libasf/asf.h
@@ -33,7 +33,7 @@ struct asf_waveformatex_s {
33 uint16_t blockalign; 33 uint16_t blockalign;
34 uint16_t bitspersample; 34 uint16_t bitspersample;
35 uint16_t datalen; 35 uint16_t datalen;
36 uint16_t numpackets; 36 uint64_t numpackets;
37 uint8_t data[46]; 37 uint8_t data[46];
38}; 38};
39typedef struct asf_waveformatex_s asf_waveformatex_t; 39typedef struct asf_waveformatex_s asf_waveformatex_t;
diff --git a/lib/rbcodec/metadata/asf.c b/lib/rbcodec/metadata/asf.c
index 469a5739d2..50e021b6a4 100644
--- a/lib/rbcodec/metadata/asf.c
+++ b/lib/rbcodec/metadata/asf.c
@@ -275,16 +275,16 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
275 275
276 fileprop = 1; 276 fileprop = 1;
277 277
278 /* Get the number of logical packets - uint16_t at offset 31 278 /* Get the number of logical packets - uint64_t at offset 32
279 * (Big endian byte order) */ 279 * (little endian byte order) */
280 lseek(fd, 31, SEEK_CUR); 280 lseek(fd, 32, SEEK_CUR);
281 read_uint16be(fd, &wfx->numpackets); 281 read_uint64le(fd, &wfx->numpackets);
282 //DEBUGF("read packets: %llx %lld\n", wfx->numpackets, wfx->numpackets);
282 283
283 /* Now get the play duration - uint64_t at offset 40 */ 284 /* Now get the play duration - uint64_t at offset 40 */
284 lseek(fd, 7, SEEK_CUR); 285 //lseek(fd, 4, SEEK_CUR);
285 read_uint64le(fd, &play_duration); 286 read_uint64le(fd, &play_duration);
286 id3->length = play_duration / 10000; 287 id3->length = play_duration / 10000;
287
288 //DEBUGF("****** length = %lums\n", id3->length); 288 //DEBUGF("****** length = %lums\n", id3->length);
289 289
290 /* Read the packet size - uint32_t at offset 68 */ 290 /* Read the packet size - uint32_t at offset 68 */
@@ -338,8 +338,22 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
338 read_uint16le(fd, &wfx->bitspersample); 338 read_uint16le(fd, &wfx->bitspersample);
339 read_uint16le(fd, &wfx->datalen); 339 read_uint16le(fd, &wfx->datalen);
340 340
341 /* Round bitrate to the nearest kbit */ 341 /*sanity check the included bitrate by comparing to file size and length*/
342 id3->bitrate = (wfx->bitrate + 500) / 1000; 342 unsigned int estimated_bitrate = (wfx->packet_size*wfx->numpackets)/id3->length*8000;
343
344 /*in theory we could just use the estimated bitrate always,
345 but its safer to underestimate*/
346 if( wfx->bitrate > estimated_bitrate)
347 {
348 /* Round bitrate to the nearest kbit */
349 id3->bitrate = (estimated_bitrate + 500) / 1000;
350 }
351 else
352 {
353 /* Round bitrate to the nearest kbit */
354 id3->bitrate = (wfx->bitrate + 500) / 1000;
355 }
356 /*DEBUGF("bitrate: %d estimated: %d\n", wfx->bitrate, estimated_bitrate);*/
343 id3->frequency = wfx->rate; 357 id3->frequency = wfx->rate;
344 358
345 if (wfx->codec_id == ASF_CODEC_ID_WMAV1) { 359 if (wfx->codec_id == ASF_CODEC_ID_WMAV1) {