Index: apps/codecs/wma.c =================================================================== --- apps/codecs/wma.c (revision 15704) +++ apps/codecs/wma.c (working copy) @@ -23,6 +23,8 @@ CODEC_HEADER +int packet_count=0; + /* The output buffer containing the decoded samples (channels 0 and 1) BLOCK_MAX_SIZE is 2048 (samples) and MAX_CHANNELS is 2. */ @@ -91,6 +93,7 @@ uint8_t* buf; size_t bufsize; int i; + DEBUGF("Reading new packet at %d bytes ", (int)ci->curpos); if (ci->read_filebuf(&tmp8, 1) == 0) { return ASF_ERROR_EOF; @@ -99,7 +102,10 @@ //DEBUGF("tmp8=0x%02x\n",tmp8); /* TODO: We need a better way to detect endofstream */ - if (tmp8 != 0x82) { return -1; } + if (tmp8 != 0x82) { + DEBUGF("Read failed: packet did not sync\n"); + return -1; + } if (tmp8 & 0x80) { @@ -152,6 +158,7 @@ datap += 4; duration = get_short_le(datap); datap += 2; + DEBUGF("and duration %d ms\n", duration); /* this is really idiotic, packet length can (and often will) be * undefined and we just have to use the header packet size as the size @@ -252,6 +259,7 @@ multiple = packet_flags & 0x01; + if (multiple) { int x; @@ -300,6 +308,141 @@ return 0; } + + static int get_timestamp(int *duration){ + + uint8_t tmp8, packet_flags, packet_property; + //int stream_id; + int ec_length, opaque_data, ec_length_type; + int datalen; + uint8_t data[18]; + uint8_t* datap; + uint32_t length; + uint32_t padding_length; + uint32_t send_time; + + //uint16_t payload_count; + uint32_t bytesread = 0; + packet_count++; + if (ci->read_filebuf(&tmp8, 1) == 0) { + DEBUGF("ASF ERROR (EOF?)\n"); + return ASF_ERROR_EOF; + } + bytesread++; + + //DEBUGF("tmp8=0x%02x\n",tmp8); + /* TODO: We need a better way to detect endofstream */ + if (tmp8 != 0x82) { + DEBUGF("Get timestamp: Detected end of stream\n"); + + return ASF_ERROR_EOF; } + + + if (tmp8 & 0x80) { + ec_length = tmp8 & 0x0f; + opaque_data = (tmp8 >> 4) & 0x01; + ec_length_type = (tmp8 >> 5) & 0x03; + + if (ec_length_type != 0x00 || opaque_data != 0 || ec_length != 0x02) { + DEBUGF("incorrect error correction flags\n"); + return ASF_ERROR_INVALID_VALUE; + } + + /* Skip ec_data */ + ci->advance_buffer(ec_length); + bytesread += ec_length; + } else { + ec_length = 0; + } + + if (ci->read_filebuf(&packet_flags, 1) == 0) { DEBUGF("Detected end of stream 2\n"); return ASF_ERROR_EOF; } + if (ci->read_filebuf(&packet_property, 1) == 0) {DEBUGF("Detected end of stream3\n"); return ASF_ERROR_EOF; } + bytesread += 2; + + datalen = GETLEN2b((packet_flags >> 1) & 0x03) + + GETLEN2b((packet_flags >> 3) & 0x03) + + GETLEN2b((packet_flags >> 5) & 0x03) + 6; + + if (ci->read_filebuf(data, datalen) == 0) { + DEBUGF("Detected end of stream4\n"); + return ASF_ERROR_EOF; + } + + bytesread += datalen; + + datap = data; + length = GETVALUE2b((packet_flags >> 5) & 0x03, datap); + datap += GETLEN2b((packet_flags >> 5) & 0x03); + /* sequence value is not used */ + GETVALUE2b((packet_flags >> 1) & 0x03, datap); + datap += GETLEN2b((packet_flags >> 1) & 0x03); + padding_length = GETVALUE2b((packet_flags >> 3) & 0x03, datap); + datap += GETLEN2b((packet_flags >> 3) & 0x03); + send_time = get_long_le(datap); + datap += 4; + *duration = get_short_le(datap); + + return send_time; + } + +/*entry point for seeks*/ + static int seek(int ms, asf_waveformatex_t* wfx){ + int time, duration, delta, temp; + + /*estimate packet number from bitrate*/ + int initial_packet = ci->curpos/wfx->packet_size; + int packet_num = (ms*(wfx->bitrate>>3))/wfx->packet_size/1000; + int last_packet = ci->id3->filesize / wfx->packet_size; + + if(packet_num > last_packet){ + packet_num = last_packet; + } + + /*calculate byte address of the start of that packet*/ + int packet_offset = packet_num*wfx->packet_size; + + /*seek to estimated packet*/ + ci->seek_buffer(ci->id3->first_frame_offset+packet_offset); + temp = ms; + while(1){ + + /*check the time stamp of our packet*/ + time = get_timestamp(&duration); + DEBUGF("seeked to %d ms with duration %d\n", time, duration); + /*make sure we didn't just seek past the EOF*/ + //TODO: Need some way to figure out when we've hit the EOF. Current way doesn't seem to work. + + + if(time < 0){ + /*unknown error, try to recover*/ + DEBUGF("UKNOWN SEEK ERROR\n"); + ci->seek_buffer(ci->id3->first_frame_offset+initial_packet*wfx->packet_size); + return ms; + } + + if(time+duration>=ms && time<=ms){ + /*the get_timestamp function advances us 12 bytes past the packet start*/ + ci->seek_buffer(ci->curpos-12); + DEBUGF("Found our packet! Now at %d packet\n", packet_num); + return time; + }else { + /*seek again*/ + delta = ms-time; + DEBUGF("delta is %d ms\n", delta); + + /*estimate new packet number from bitrate and our current position*/ + temp += delta; + packet_num = (temp*(wfx->bitrate>>3)/1000 - (wfx->packet_size>>1))/wfx->packet_size; //round down! + DEBUGF("updated Packet_num is %d\n", packet_num); + packet_offset = packet_num*wfx->packet_size; + + ci->seek_buffer(ci->id3->first_frame_offset+packet_offset); + } + } + } + + + /* this is the codec entry point */ enum codec_status codec_main(void) { @@ -375,16 +518,31 @@ /* Deal with any pending seek requests */ if (ci->seek_time) { - /* Ignore all seeks for now, unless for the start of the track */ - if (ci->seek_time == 1) { - ci->seek_complete(); - goto next_track; /* Pretend you never saw this... */ - } - ci->seek_complete(); + int time; + + if (ci->seek_time == 1) { + ci->seek_complete(); + goto next_track; /* Pretend you never saw this... */ + } + + DEBUGF("\n\n\n######seeking\n"); + elapsedtime = seek(ci->seek_time, &wfx); + if(time < 1){ + ci->seek_complete(); + goto next_track; + } + DEBUGF("Seek returned %d\n", time); + ci->set_elapsed(elapsedtime); + + /*flush the wma decoder state*/ + wmadec.last_superframe_len = 0; + wmadec.last_bitoffset = 0; + ci->seek_complete(); } res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx); - if (res > 0) { + + if (res > 0) { wma_decode_superframe_init(&wmadec, audiobuf, audiobufsize); @@ -398,12 +556,12 @@ if (wmares < 0) { - LOGF("WMA decode error %d\n",wmares); + DEBUGF("WMA decode error %d\n",wmares); goto done; } else if (wmares > 0) { ci->pcmbuf_insert(decoded, NULL, wmares); - samplesdone += wmares; - elapsedtime = (samplesdone*10)/(wfx.rate/100); + samplesdone = wmares; + elapsedtime += (samplesdone*10)/(wfx.rate/100); ci->set_elapsed(elapsedtime); } ci->yield (); @@ -419,7 +577,6 @@ if (ci->request_next_track()) goto next_track; - exit: return retval; }