From aa2c55e1057c0c220a1eb37c99d2c251bfe850ab Mon Sep 17 00:00:00 2001 From: Michael Giacomelli Date: Fri, 28 Nov 2014 22:25:23 +0100 Subject: 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 --- lib/rbcodec/codecs/libasf/asf.c | 14 ++++++++++---- lib/rbcodec/codecs/libasf/asf.h | 2 +- lib/rbcodec/metadata/asf.c | 30 ++++++++++++++++++++++-------- 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) int asf_seek(int ms, asf_waveformatex_t* wfx) { int time, duration, delta, temp, count=0; + int bitrate = ci->id3->bitrate*1000/8; /*estimate packet number from bitrate*/ int initial_packet = ci->curpos/wfx->packet_size; - int packet_num = (((int64_t)ms)*(wfx->bitrate>>3))/wfx->packet_size/1000; - int last_packet = ci->id3->filesize / wfx->packet_size; + int packet_num = (((int64_t)ms)*(bitrate))/wfx->packet_size/1000; + /*subtract header size in case theres a lot of metadata*/ + int last_packet = (ci->id3->filesize-ci->id3->first_frame_offset) / wfx->packet_size; + + /* + DEBUGF("bitrate: %d\n", bitrate); + 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);*/ if (packet_num > last_packet) { packet_num = last_packet; @@ -409,7 +415,7 @@ int asf_seek(int ms, asf_waveformatex_t* wfx) /*check the time stamp of our packet*/ time = asf_get_timestamp(&duration); - /*DEBUGF("seeked to %d ms with duration %d\n", time, duration);*/ + /*DEBUGF("seeked to %d ms (%d) with duration %d\n", time,packet_num, duration);*/ if (time < 0) { /*unknown error, try to recover*/ @@ -427,7 +433,7 @@ int asf_seek(int ms, asf_waveformatex_t* wfx) delta = ms-time; /*estimate new packet number from bitrate and our current position*/ temp += delta; - packet_num = ((temp/1000)*(wfx->bitrate>>3) - (wfx->packet_size>>1))/wfx->packet_size; //round down! + packet_num = ((temp/1000)*(bitrate) - (wfx->packet_size<<1))/wfx->packet_size; //round down! packet_offset = packet_num*wfx->packet_size; ci->seek_buffer(ci->id3->first_frame_offset+packet_offset); } 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 { uint16_t blockalign; uint16_t bitspersample; uint16_t datalen; - uint16_t numpackets; + uint64_t numpackets; uint8_t data[46]; }; typedef 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, fileprop = 1; - /* Get the number of logical packets - uint16_t at offset 31 - * (Big endian byte order) */ - lseek(fd, 31, SEEK_CUR); - read_uint16be(fd, &wfx->numpackets); + /* Get the number of logical packets - uint64_t at offset 32 + * (little endian byte order) */ + lseek(fd, 32, SEEK_CUR); + read_uint64le(fd, &wfx->numpackets); + //DEBUGF("read packets: %llx %lld\n", wfx->numpackets, wfx->numpackets); /* Now get the play duration - uint64_t at offset 40 */ - lseek(fd, 7, SEEK_CUR); + //lseek(fd, 4, SEEK_CUR); read_uint64le(fd, &play_duration); id3->length = play_duration / 10000; - //DEBUGF("****** length = %lums\n", id3->length); /* Read the packet size - uint32_t at offset 68 */ @@ -338,8 +338,22 @@ static int asf_parse_header(int fd, struct mp3entry* id3, read_uint16le(fd, &wfx->bitspersample); read_uint16le(fd, &wfx->datalen); - /* Round bitrate to the nearest kbit */ - id3->bitrate = (wfx->bitrate + 500) / 1000; + /*sanity check the included bitrate by comparing to file size and length*/ + unsigned int estimated_bitrate = (wfx->packet_size*wfx->numpackets)/id3->length*8000; + + /*in theory we could just use the estimated bitrate always, + but its safer to underestimate*/ + if( wfx->bitrate > estimated_bitrate) + { + /* Round bitrate to the nearest kbit */ + id3->bitrate = (estimated_bitrate + 500) / 1000; + } + else + { + /* Round bitrate to the nearest kbit */ + id3->bitrate = (wfx->bitrate + 500) / 1000; + } + /*DEBUGF("bitrate: %d estimated: %d\n", wfx->bitrate, estimated_bitrate);*/ id3->frequency = wfx->rate; if (wfx->codec_id == ASF_CODEC_ID_WMAV1) { -- cgit v1.2.3