summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/codecs/wma.c206
1 files changed, 187 insertions, 19 deletions
diff --git a/apps/codecs/wma.c b/apps/codecs/wma.c
index 958cf1525b..629194c5e2 100644
--- a/apps/codecs/wma.c
+++ b/apps/codecs/wma.c
@@ -23,6 +23,8 @@
23 23
24CODEC_HEADER 24CODEC_HEADER
25 25
26int packet_count=0;
27
26/* The output buffer containing the decoded samples (channels 0 and 1) 28/* The output buffer containing the decoded samples (channels 0 and 1)
27 BLOCK_MAX_SIZE is 2048 (samples) and MAX_CHANNELS is 2. 29 BLOCK_MAX_SIZE is 2048 (samples) and MAX_CHANNELS is 2.
28 */ 30 */
@@ -91,6 +93,7 @@ static int asf_read_packet(uint8_t** audiobuf, int* audiobufsize, int* packetlen
91 uint8_t* buf; 93 uint8_t* buf;
92 size_t bufsize; 94 size_t bufsize;
93 int i; 95 int i;
96 DEBUGF("Reading new packet at %d bytes ", (int)ci->curpos);
94 97
95 if (ci->read_filebuf(&tmp8, 1) == 0) { 98 if (ci->read_filebuf(&tmp8, 1) == 0) {
96 return ASF_ERROR_EOF; 99 return ASF_ERROR_EOF;
@@ -99,7 +102,10 @@ static int asf_read_packet(uint8_t** audiobuf, int* audiobufsize, int* packetlen
99 102
100 //DEBUGF("tmp8=0x%02x\n",tmp8); 103 //DEBUGF("tmp8=0x%02x\n",tmp8);
101 /* TODO: We need a better way to detect endofstream */ 104 /* TODO: We need a better way to detect endofstream */
102 if (tmp8 != 0x82) { return -1; } 105 if (tmp8 != 0x82) {
106 DEBUGF("Read failed: packet did not sync\n");
107 return -1;
108 }
103 109
104 110
105 if (tmp8 & 0x80) { 111 if (tmp8 & 0x80) {
@@ -152,6 +158,7 @@ static int asf_read_packet(uint8_t** audiobuf, int* audiobufsize, int* packetlen
152 datap += 4; 158 datap += 4;
153 duration = get_short_le(datap); 159 duration = get_short_le(datap);
154 datap += 2; 160 datap += 2;
161 DEBUGF("and duration %d ms\n", duration);
155 162
156 /* this is really idiotic, packet length can (and often will) be 163 /* this is really idiotic, packet length can (and often will) be
157 * undefined and we just have to use the header packet size as the size 164 * undefined and we just have to use the header packet size as the size
@@ -252,6 +259,7 @@ static int asf_read_packet(uint8_t** audiobuf, int* audiobufsize, int* packetlen
252 259
253 multiple = packet_flags & 0x01; 260 multiple = packet_flags & 0x01;
254 261
262
255 if (multiple) { 263 if (multiple) {
256 int x; 264 int x;
257 265
@@ -300,10 +308,140 @@ static int asf_read_packet(uint8_t** audiobuf, int* audiobufsize, int* packetlen
300 return 0; 308 return 0;
301} 309}
302 310
311
312 static int get_timestamp(int *duration){
313
314 uint8_t tmp8, packet_flags, packet_property;
315 //int stream_id;
316 int ec_length, opaque_data, ec_length_type;
317 int datalen;
318 uint8_t data[18];
319 uint8_t* datap;
320 uint32_t length;
321 uint32_t padding_length;
322 uint32_t send_time;
323
324 //uint16_t payload_count;
325 uint32_t bytesread = 0;
326 packet_count++;
327 if (ci->read_filebuf(&tmp8, 1) == 0) {
328 DEBUGF("ASF ERROR (EOF?)\n");
329 return ASF_ERROR_EOF;
330 }
331 bytesread++;
332
333 /* TODO: We need a better way to detect endofstream */
334 if (tmp8 != 0x82) {
335 DEBUGF("Get timestamp: Detected end of stream\n");
336
337 return ASF_ERROR_EOF; }
338
339
340 if (tmp8 & 0x80) {
341 ec_length = tmp8 & 0x0f;
342 opaque_data = (tmp8 >> 4) & 0x01;
343 ec_length_type = (tmp8 >> 5) & 0x03;
344
345 if (ec_length_type != 0x00 || opaque_data != 0 || ec_length != 0x02) {
346 DEBUGF("incorrect error correction flags\n");
347 return ASF_ERROR_INVALID_VALUE;
348 }
349
350 /* Skip ec_data */
351 ci->advance_buffer(ec_length);
352 bytesread += ec_length;
353 } else {
354 ec_length = 0;
355 }
356
357 if (ci->read_filebuf(&packet_flags, 1) == 0) { DEBUGF("Detected end of stream 2\n"); return ASF_ERROR_EOF; }
358 if (ci->read_filebuf(&packet_property, 1) == 0) {DEBUGF("Detected end of stream3\n"); return ASF_ERROR_EOF; }
359 bytesread += 2;
360
361 datalen = GETLEN2b((packet_flags >> 1) & 0x03) +
362 GETLEN2b((packet_flags >> 3) & 0x03) +
363 GETLEN2b((packet_flags >> 5) & 0x03) + 6;
364
365 if (ci->read_filebuf(data, datalen) == 0) {
366 DEBUGF("Detected end of stream4\n");
367 return ASF_ERROR_EOF;
368 }
369
370 bytesread += datalen;
371
372 datap = data;
373 length = GETVALUE2b((packet_flags >> 5) & 0x03, datap);
374 datap += GETLEN2b((packet_flags >> 5) & 0x03);
375 /* sequence value is not used */
376 GETVALUE2b((packet_flags >> 1) & 0x03, datap);
377 datap += GETLEN2b((packet_flags >> 1) & 0x03);
378 padding_length = GETVALUE2b((packet_flags >> 3) & 0x03, datap);
379 datap += GETLEN2b((packet_flags >> 3) & 0x03);
380 send_time = get_long_le(datap);
381 datap += 4;
382 *duration = get_short_le(datap);
383
384 return send_time;
385 }
386
387/*entry point for seeks*/
388 static int seek(int ms, asf_waveformatex_t* wfx){
389 int time, duration, delta, temp;
390
391 /*estimate packet number from bitrate*/
392 int initial_packet = ci->curpos/wfx->packet_size;
393 int packet_num = (ms*(wfx->bitrate>>3))/wfx->packet_size/1000;
394 int last_packet = ci->id3->filesize / wfx->packet_size;
395
396 if(packet_num > last_packet){
397 packet_num = last_packet;
398 }
399
400 /*calculate byte address of the start of that packet*/
401 int packet_offset = packet_num*wfx->packet_size;
402
403 /*seek to estimated packet*/
404 ci->seek_buffer(ci->id3->first_frame_offset+packet_offset);
405 temp = ms;
406 while(1){
407
408 /*check the time stamp of our packet*/
409 time = get_timestamp(&duration);
410 DEBUGF("seeked to %d ms with duration %d\n", time, duration);
411
412 if(time < 0){
413 /*unknown error, try to recover*/
414 DEBUGF("UKNOWN SEEK ERROR\n");
415 ci->seek_buffer(ci->id3->first_frame_offset+initial_packet*wfx->packet_size);
416 return ms;
417 }
418
419 if(time+duration>=ms && time<=ms){
420 /*the get_timestamp function advances us 12 bytes past the packet start*/
421 ci->seek_buffer(ci->curpos-12);
422 DEBUGF("Found our packet! Now at %d packet\n", packet_num);
423 return time;
424 }else {
425 /*seek again*/
426 delta = ms-time;
427 DEBUGF("delta is %d ms\n", delta);
428
429 /*estimate new packet number from bitrate and our current position*/
430 temp += delta;
431 packet_num = (temp*(wfx->bitrate>>3)/1000 - (wfx->packet_size>>1))/wfx->packet_size; //round down!
432 DEBUGF("updated Packet_num is %d\n", packet_num);
433 packet_offset = packet_num*wfx->packet_size;
434
435 ci->seek_buffer(ci->id3->first_frame_offset+packet_offset);
436 }
437 }
438 }
439
440
441
303/* this is the codec entry point */ 442/* this is the codec entry point */
304enum codec_status codec_main(void) 443enum codec_status codec_main(void)
305{ 444{
306 uint32_t samplesdone;
307 uint32_t elapsedtime; 445 uint32_t elapsedtime;
308 int retval; 446 int retval;
309 asf_waveformatex_t wfx; 447 asf_waveformatex_t wfx;
@@ -314,6 +452,7 @@ enum codec_status codec_main(void)
314 uint8_t* audiobuf; 452 uint8_t* audiobuf;
315 int audiobufsize; 453 int audiobufsize;
316 int packetlength; 454 int packetlength;
455 int errcount = 0;
317 456
318 /* Generic codec initialisation */ 457 /* Generic codec initialisation */
319 ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512); 458 ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
@@ -359,7 +498,7 @@ next_track:
359 /* The main decoding loop */ 498 /* The main decoding loop */
360 499
361 currentframe = 0; 500 currentframe = 0;
362 samplesdone = 0; 501 elapsedtime = 0;
363 502
364 DEBUGF("**************** IN WMA.C ******************\n"); 503 DEBUGF("**************** IN WMA.C ******************\n");
365 wma_decode_init(&wmadec,&wfx); 504 wma_decode_init(&wmadec,&wfx);
@@ -373,18 +512,44 @@ next_track:
373 } 512 }
374 513
375 /* Deal with any pending seek requests */ 514 /* Deal with any pending seek requests */
376 if (ci->seek_time) 515 if (ci->seek_time){
377 { 516
378 /* Ignore all seeks for now, unless for the start of the track */
379 if (ci->seek_time == 1) { 517 if (ci->seek_time == 1) {
380 ci->seek_complete(); 518 ci->seek_complete();
381 goto next_track; /* Pretend you never saw this... */ 519 goto next_track; /* Pretend you never saw this... */
382 } 520 }
383 ci->seek_complete();
384 }
385 521
522 elapsedtime = seek(ci->seek_time, &wfx);
523 if(elapsedtime < 1){
524 ci->seek_complete();
525 goto next_track;
526 }
527 ci->set_elapsed(elapsedtime);
528
529 /*flush the wma decoder state*/
530 wmadec.last_superframe_len = 0;
531 wmadec.last_bitoffset = 0;
532 ci->seek_complete();
533 }
534 errcount = 0;
535new_packet:
386 res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx); 536 res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx);
387 if (res > 0) { 537 if(res < 0){
538
539 /* We'll try to recover from a parse error a certain number of
540 * times. If we succeed, the error counter will be reset.
541 */
542
543 errcount++;
544 DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount);
545 if (errcount > 5) {
546 goto done;
547 } else {
548 ci->advance_buffer(packetlength);
549 goto new_packet;
550 }
551
552 }else if (res > 0) {
388 wma_decode_superframe_init(&wmadec, 553 wma_decode_superframe_init(&wmadec,
389 audiobuf, audiobufsize); 554 audiobuf, audiobufsize);
390 555
@@ -393,20 +558,24 @@ next_track:
393 wmares = wma_decode_superframe_frame(&wmadec, 558 wmares = wma_decode_superframe_frame(&wmadec,
394 decoded, 559 decoded,
395 audiobuf, audiobufsize); 560 audiobuf, audiobufsize);
396
397 ci->yield (); 561 ci->yield ();
398 562
399 if (wmares < 0) 563 if (wmares < 0){
400 { 564 /* Do the above, but for errors in decode.*/
401 LOGF("WMA decode error %d\n",wmares); 565 errcount++;
402 goto done; 566 DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount);
567 if (errcount > 5) {
568 goto done;
569 } else {
570 ci->advance_buffer(packetlength);
571 goto new_packet;
572 }
403 } else if (wmares > 0) { 573 } else if (wmares > 0) {
404 ci->pcmbuf_insert(decoded, NULL, wmares); 574 ci->pcmbuf_insert(decoded, NULL, wmares);
405 samplesdone += wmares; 575 elapsedtime += (wmares*10)/(wfx.rate/100);
406 elapsedtime = (samplesdone*10)/(wfx.rate/100);
407 ci->set_elapsed(elapsedtime); 576 ci->set_elapsed(elapsedtime);
408 } 577 }
409 ci->yield (); 578 ci->yield();
410 } 579 }
411 } 580 }
412 581
@@ -415,11 +584,10 @@ next_track:
415 retval = CODEC_OK; 584 retval = CODEC_OK;
416 585
417done: 586done:
418 LOGF("WMA: Decoded %ld samples\n",samplesdone); 587 LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);
419 588
420 if (ci->request_next_track()) 589 if (ci->request_next_track())
421 goto next_track; 590 goto next_track;
422
423exit: 591exit:
424 return retval; 592 return retval;
425} 593}