diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2018-12-22 20:18:06 -0500 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2021-02-28 16:11:54 +0000 |
commit | 670812a44a3aed7f142548c2cfa5a5b36381b1a8 (patch) | |
tree | 2973316f3618520ad721ff8cec751bffdb264e3a /lib/rbcodec/codecs/mpa.c | |
parent | 13c7f482ce9614012312e8189b91be0fee65f2d9 (diff) | |
download | rockbox-670812a44a3aed7f142548c2cfa5a5b36381b1a8.tar.gz rockbox-670812a44a3aed7f142548c2cfa5a5b36381b1a8.zip |
Support MP3 audiostreams embedded in ASF containers.
Full credit to Igor Poretsky
Change-Id: I54769e33665cada1e1e0ef3a5511b56c8e1b859a
Diffstat (limited to 'lib/rbcodec/codecs/mpa.c')
-rw-r--r-- | lib/rbcodec/codecs/mpa.c | 162 |
1 files changed, 141 insertions, 21 deletions
diff --git a/lib/rbcodec/codecs/mpa.c b/lib/rbcodec/codecs/mpa.c index e6662ddcbe..d6bcc04910 100644 --- a/lib/rbcodec/codecs/mpa.c +++ b/lib/rbcodec/codecs/mpa.c | |||
@@ -20,6 +20,7 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | #include "codeclib.h" | 22 | #include "codeclib.h" |
23 | #include "libasf/asf.h" | ||
23 | #include <codecs/libmad/mad.h> | 24 | #include <codecs/libmad/mad.h> |
24 | #include <inttypes.h> | 25 | #include <inttypes.h> |
25 | 26 | ||
@@ -56,6 +57,91 @@ static unsigned char mad_main_data[MAD_BUFFER_MDLEN] IBSS_ATTR; | |||
56 | static int mpeg_latency[3] = { 0, 481, 529 }; | 57 | static int mpeg_latency[3] = { 0, 481, 529 }; |
57 | static int mpeg_framesize[3] = {384, 1152, 1152}; | 58 | static int mpeg_framesize[3] = {384, 1152, 1152}; |
58 | 59 | ||
60 | static unsigned char stream_buffer[INPUT_CHUNK_SIZE] IBSS_ATTR; | ||
61 | static unsigned char *stream_data_start; | ||
62 | static unsigned char *stream_data_end; | ||
63 | static unsigned char *packetdata; | ||
64 | static int stream_data_available; | ||
65 | static int packetlength; | ||
66 | static int packetdatasize; | ||
67 | static int packetrest; | ||
68 | static unsigned char *lastpacketpos; | ||
69 | |||
70 | static void reset_stream_buffer(void) | ||
71 | { | ||
72 | stream_data_start = stream_buffer; | ||
73 | stream_data_end = stream_buffer; | ||
74 | stream_data_available = 1; | ||
75 | packetdatasize = 0; | ||
76 | packetrest = 0; | ||
77 | lastpacketpos = stream_buffer; | ||
78 | } | ||
79 | |||
80 | static inline unsigned char *get_stream_data(size_t *realsize, size_t reqsize) | ||
81 | { | ||
82 | static int errcount = 0; | ||
83 | size_t datasize = stream_data_end - stream_data_start; | ||
84 | if (!ci->id3->is_asf_stream) | ||
85 | return ci->request_buffer(realsize, reqsize); | ||
86 | else if (datasize < INPUT_CHUNK_SIZE / 2) | ||
87 | { | ||
88 | if (stream_data_start < stream_data_end && stream_data_start > stream_buffer) | ||
89 | { | ||
90 | lastpacketpos -= stream_data_start - stream_buffer; | ||
91 | memmove(stream_buffer, stream_data_start, datasize); | ||
92 | stream_data_start = stream_buffer; | ||
93 | stream_data_end = stream_buffer + datasize; | ||
94 | } | ||
95 | while (datasize < INPUT_CHUNK_SIZE && (packetrest || stream_data_available > 0)) | ||
96 | { | ||
97 | if (packetrest && packetdata) | ||
98 | { | ||
99 | datasize = INPUT_CHUNK_SIZE - datasize; | ||
100 | if (datasize > (size_t)packetrest) | ||
101 | datasize = packetrest; | ||
102 | memcpy(stream_data_end, packetdata, datasize); | ||
103 | packetrest -= datasize; | ||
104 | stream_data_end += datasize; | ||
105 | if (packetrest) | ||
106 | packetdata += datasize; | ||
107 | else | ||
108 | { | ||
109 | ci->advance_buffer(packetlength); | ||
110 | lastpacketpos = stream_data_end; | ||
111 | } | ||
112 | datasize = stream_data_end - stream_data_start; | ||
113 | } | ||
114 | else | ||
115 | { | ||
116 | asf_waveformatex_t *wfx = (asf_waveformatex_t *)(ci->id3->toc); | ||
117 | int res = asf_read_packet(&packetdata, &packetdatasize, &packetlength, wfx); | ||
118 | if (res < 0) | ||
119 | { | ||
120 | if (res == ASF_ERROR_EOF) | ||
121 | stream_data_available = 0; | ||
122 | else if (++errcount > 5) | ||
123 | stream_data_available = -1; | ||
124 | } | ||
125 | else errcount = 0; | ||
126 | packetrest = packetdatasize; | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | if (packetdatasize && lastpacketpos > stream_data_start) | ||
131 | ci->set_offset(ci->curpos - ((lastpacketpos - stream_data_start) / packetdatasize + 1) * packetlength); | ||
132 | *realsize = (datasize > reqsize) ? reqsize : datasize; | ||
133 | return stream_data_start; | ||
134 | } | ||
135 | |||
136 | static void advance_stream_buffer(size_t size) | ||
137 | { | ||
138 | if (!ci->id3->is_asf_stream) | ||
139 | ci->advance_buffer(size); | ||
140 | else if (stream_data_start + size > stream_data_end) | ||
141 | stream_data_start = stream_data_end; | ||
142 | else stream_data_start += size; | ||
143 | } | ||
144 | |||
59 | static void init_mad(void) | 145 | static void init_mad(void) |
60 | { | 146 | { |
61 | ci->memset(&stream, 0, sizeof(struct mad_stream)); | 147 | ci->memset(&stream, 0, sizeof(struct mad_stream)); |
@@ -346,14 +432,26 @@ enum codec_status codec_run(void) | |||
346 | current_frequency = ci->id3->frequency; | 432 | current_frequency = ci->id3->frequency; |
347 | codec_set_replaygain(ci->id3); | 433 | codec_set_replaygain(ci->id3); |
348 | 434 | ||
349 | if (!ci->id3->offset && ci->id3->elapsed) { | 435 | if (!ci->id3->is_asf_stream && !ci->id3->offset && ci->id3->elapsed) { |
350 | /* Have elapsed time but not offset */ | 436 | /* Have elapsed time but not offset */ |
351 | ci->id3->offset = get_file_pos(ci->id3->elapsed); | 437 | ci->id3->offset = get_file_pos(ci->id3->elapsed); |
352 | } | 438 | } |
353 | 439 | ||
354 | if (ci->id3->offset) { | 440 | if (ci->id3->offset) { |
355 | ci->seek_buffer(ci->id3->offset); | 441 | |
356 | set_elapsed(ci->id3); | 442 | if (ci->id3->is_asf_stream) { |
443 | asf_waveformatex_t *wfx = (asf_waveformatex_t *)(ci->id3->toc); | ||
444 | int packet_offset = ((ci->id3->offset > ci->id3->first_frame_offset) ? | ||
445 | (ci->id3->offset - ci->id3->first_frame_offset) : 0) | ||
446 | % wfx->packet_size; | ||
447 | ci->seek_buffer(ci->id3->offset - packet_offset); | ||
448 | ci->id3->elapsed = asf_get_timestamp(&packet_offset); | ||
449 | ci->set_elapsed(ci->id3->elapsed); | ||
450 | } | ||
451 | else { | ||
452 | ci->seek_buffer(ci->id3->offset); | ||
453 | set_elapsed(ci->id3); | ||
454 | } | ||
357 | } | 455 | } |
358 | else | 456 | else |
359 | ci->seek_buffer(ci->id3->first_frame_offset); | 457 | ci->seek_buffer(ci->id3->first_frame_offset); |
@@ -388,6 +486,8 @@ enum codec_status codec_run(void) | |||
388 | else | 486 | else |
389 | samples_to_skip = start_skip; | 487 | samples_to_skip = start_skip; |
390 | 488 | ||
489 | if (ci->id3->is_asf_stream) | ||
490 | reset_stream_buffer(); | ||
391 | framelength = 0; | 491 | framelength = 0; |
392 | 492 | ||
393 | /* This is the decoding loop. */ | 493 | /* This is the decoding loop. */ |
@@ -398,39 +498,59 @@ enum codec_status codec_run(void) | |||
398 | break; | 498 | break; |
399 | 499 | ||
400 | if (action == CODEC_ACTION_SEEK_TIME) { | 500 | if (action == CODEC_ACTION_SEEK_TIME) { |
401 | int newpos; | ||
402 | |||
403 | /*make sure the synth thread is idle before seeking - MT only*/ | 501 | /*make sure the synth thread is idle before seeking - MT only*/ |
404 | mad_synth_thread_wait_pcm(); | 502 | mad_synth_thread_wait_pcm(); |
405 | mad_synth_thread_unwait_pcm(); | 503 | mad_synth_thread_unwait_pcm(); |
406 | 504 | ||
407 | samplesdone = ((int64_t)param)*current_frequency/1000; | ||
408 | |||
409 | if (param == 0) { | 505 | if (param == 0) { |
410 | newpos = ci->id3->first_frame_offset; | ||
411 | samples_to_skip = start_skip; | 506 | samples_to_skip = start_skip; |
412 | } else { | 507 | } else { |
413 | newpos = get_file_pos(param); | ||
414 | samples_to_skip = 0; | 508 | samples_to_skip = 0; |
415 | } | 509 | } |
416 | 510 | ||
417 | if (!ci->seek_buffer(newpos)) | 511 | if (ci->id3->is_asf_stream) { |
418 | { | 512 | asf_waveformatex_t *wfx = (asf_waveformatex_t *)(ci->id3->toc); |
513 | int elapsedtime = asf_seek(param, wfx); | ||
514 | |||
515 | samplesdone = (elapsedtime > 0) ? | ||
516 | (((int64_t)elapsedtime)*current_frequency/1000) : 0; | ||
517 | |||
518 | if (elapsedtime < 1) { | ||
519 | ci->set_elapsed(0); | ||
520 | ci->seek_complete(); | ||
521 | break; | ||
522 | } else { | ||
523 | ci->set_elapsed(elapsedtime); | ||
524 | ci->seek_complete(); | ||
525 | reset_stream_buffer(); | ||
526 | } | ||
527 | } else { | ||
528 | int newpos = param ? get_file_pos(param) : (int)(ci->id3->first_frame_offset); | ||
529 | |||
530 | samplesdone = ((int64_t)param)*current_frequency/1000; | ||
531 | |||
532 | if (!ci->seek_buffer(newpos)) | ||
533 | { | ||
534 | ci->seek_complete(); | ||
535 | break; | ||
536 | } | ||
537 | |||
538 | ci->set_elapsed((samplesdone * 1000LL) / current_frequency); | ||
419 | ci->seek_complete(); | 539 | ci->seek_complete(); |
420 | break; | ||
421 | } | 540 | } |
422 | 541 | ||
423 | ci->set_elapsed((samplesdone * 1000LL) / current_frequency); | ||
424 | ci->seek_complete(); | ||
425 | init_mad(); | 542 | init_mad(); |
426 | framelength = 0; | 543 | framelength = 0; |
427 | } | 544 | } |
428 | 545 | ||
429 | /* Lock buffers */ | 546 | /* Lock buffers */ |
430 | if (stream.error == 0) { | 547 | if (stream.error == 0) { |
431 | inputbuffer = ci->request_buffer(&size, INPUT_CHUNK_SIZE); | 548 | inputbuffer = get_stream_data(&size, INPUT_CHUNK_SIZE); |
432 | if (size == 0 || inputbuffer == NULL) | 549 | if (size == 0 || inputbuffer == NULL) { |
550 | if (ci->id3->is_asf_stream && stream_data_available < 0) | ||
551 | return CODEC_ERROR; | ||
433 | break; | 552 | break; |
553 | } | ||
434 | mad_stream_buffer(&stream, (unsigned char *)inputbuffer, | 554 | mad_stream_buffer(&stream, (unsigned char *)inputbuffer, |
435 | size + padding); | 555 | size + padding); |
436 | } | 556 | } |
@@ -443,9 +563,9 @@ enum codec_status codec_run(void) | |||
443 | 563 | ||
444 | /* Fill the buffer */ | 564 | /* Fill the buffer */ |
445 | if (stream.next_frame) | 565 | if (stream.next_frame) |
446 | ci->advance_buffer(stream.next_frame - stream.buffer); | 566 | advance_stream_buffer(stream.next_frame - stream.buffer); |
447 | else | 567 | else |
448 | ci->advance_buffer(size); | 568 | advance_stream_buffer(size); |
449 | stream.error = 0; /* Must get new inputbuffer next time */ | 569 | stream.error = 0; /* Must get new inputbuffer next time */ |
450 | file_end++; | 570 | file_end++; |
451 | continue; | 571 | continue; |
@@ -454,7 +574,7 @@ enum codec_status codec_run(void) | |||
454 | continue; | 574 | continue; |
455 | } else { | 575 | } else { |
456 | /* Some other unrecoverable error */ | 576 | /* Some other unrecoverable error */ |
457 | return CODEC_ERROR; | 577 | return CODEC_ERROR; |
458 | } | 578 | } |
459 | } | 579 | } |
460 | 580 | ||
@@ -495,9 +615,9 @@ enum codec_status codec_run(void) | |||
495 | } | 615 | } |
496 | 616 | ||
497 | if (stream.next_frame) | 617 | if (stream.next_frame) |
498 | ci->advance_buffer(stream.next_frame - stream.buffer); | 618 | advance_stream_buffer(stream.next_frame - stream.buffer); |
499 | else | 619 | else |
500 | ci->advance_buffer(size); | 620 | advance_stream_buffer(size); |
501 | stream.error = 0; /* Must get new inputbuffer next time */ | 621 | stream.error = 0; /* Must get new inputbuffer next time */ |
502 | file_end = 0; | 622 | file_end = 0; |
503 | 623 | ||