summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2018-12-22 20:18:06 -0500
committerSolomon Peachy <pizza@shaftnet.org>2021-02-28 16:11:54 +0000
commit670812a44a3aed7f142548c2cfa5a5b36381b1a8 (patch)
tree2973316f3618520ad721ff8cec751bffdb264e3a
parent13c7f482ce9614012312e8189b91be0fee65f2d9 (diff)
downloadrockbox-670812a44a3aed7f142548c2cfa5a5b36381b1a8.tar.gz
rockbox-670812a44a3aed7f142548c2cfa5a5b36381b1a8.zip
Support MP3 audiostreams embedded in ASF containers.
Full credit to Igor Poretsky Change-Id: I54769e33665cada1e1e0ef3a5511b56c8e1b859a
-rw-r--r--lib/rbcodec/codecs/codecs.make2
-rw-r--r--lib/rbcodec/codecs/libasf/asf.h1
-rw-r--r--lib/rbcodec/codecs/mpa.c162
-rw-r--r--lib/rbcodec/metadata/asf.c5
-rw-r--r--lib/rbcodec/metadata/metadata.h3
5 files changed, 151 insertions, 22 deletions
diff --git a/lib/rbcodec/codecs/codecs.make b/lib/rbcodec/codecs/codecs.make
index 187987ca3c..2c56d6da3f 100644
--- a/lib/rbcodec/codecs/codecs.make
+++ b/lib/rbcodec/codecs/codecs.make
@@ -155,7 +155,7 @@ $(CODECLINK_LDS): $(CODEC_LDS) $(CONFIGFILE)
155 155
156# codec/library dependencies 156# codec/library dependencies
157$(CODECDIR)/spc.codec : $(CODECDIR)/libspc.a 157$(CODECDIR)/spc.codec : $(CODECDIR)/libspc.a
158$(CODECDIR)/mpa.codec : $(CODECDIR)/libmad.a 158$(CODECDIR)/mpa.codec : $(CODECDIR)/libmad.a $(CODECDIR)/libasf.a
159$(CODECDIR)/a52.codec : $(CODECDIR)/liba52.a 159$(CODECDIR)/a52.codec : $(CODECDIR)/liba52.a
160$(CODECDIR)/flac.codec : $(CODECDIR)/libffmpegFLAC.a 160$(CODECDIR)/flac.codec : $(CODECDIR)/libffmpegFLAC.a
161$(CODECDIR)/vorbis.codec : $(CODECDIR)/libtremor.a $(TLSFLIB) $(SETJMPLIB) 161$(CODECDIR)/vorbis.codec : $(CODECDIR)/libtremor.a $(TLSFLIB) $(SETJMPLIB)
diff --git a/lib/rbcodec/codecs/libasf/asf.h b/lib/rbcodec/codecs/libasf/asf.h
index 2398a44eab..ab5de3c6c6 100644
--- a/lib/rbcodec/codecs/libasf/asf.h
+++ b/lib/rbcodec/codecs/libasf/asf.h
@@ -8,6 +8,7 @@
8#define ASF_CODEC_ID_WMAV2 0x161 8#define ASF_CODEC_ID_WMAV2 0x161
9#define ASF_CODEC_ID_WMAPRO 0x162 9#define ASF_CODEC_ID_WMAPRO 0x162
10#define ASF_CODEC_ID_WMAVOICE 0x00A 10#define ASF_CODEC_ID_WMAVOICE 0x00A
11#define ASF_CODEC_ID_MP3 0x055
11 12
12enum asf_error_e { 13enum asf_error_e {
13 ASF_ERROR_INTERNAL = -1, /* incorrect input to API calls */ 14 ASF_ERROR_INTERNAL = -1, /* incorrect input to API calls */
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;
56static int mpeg_latency[3] = { 0, 481, 529 }; 57static int mpeg_latency[3] = { 0, 481, 529 };
57static int mpeg_framesize[3] = {384, 1152, 1152}; 58static int mpeg_framesize[3] = {384, 1152, 1152};
58 59
60static unsigned char stream_buffer[INPUT_CHUNK_SIZE] IBSS_ATTR;
61static unsigned char *stream_data_start;
62static unsigned char *stream_data_end;
63static unsigned char *packetdata;
64static int stream_data_available;
65static int packetlength;
66static int packetdatasize;
67static int packetrest;
68static unsigned char *lastpacketpos;
69
70static 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
80static 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
136static 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
59static void init_mad(void) 145static 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
diff --git a/lib/rbcodec/metadata/asf.c b/lib/rbcodec/metadata/asf.c
index 0d115099ec..9a74ada453 100644
--- a/lib/rbcodec/metadata/asf.c
+++ b/lib/rbcodec/metadata/asf.c
@@ -375,6 +375,11 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
375 lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR); 375 lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR);
376 wfx->audiostream = flags&0x7f; 376 wfx->audiostream = flags&0x7f;
377 id3->codectype = AFMT_WMAVOICE; 377 id3->codectype = AFMT_WMAVOICE;
378 } else if (wfx->codec_id == ASF_CODEC_ID_MP3) {
379 lseek(fd,current.size - 24 - 72,SEEK_CUR);
380 wfx->audiostream = flags&0x7f;
381 id3->codectype = AFMT_MPA_L3;
382 id3->is_asf_stream = true;
378 } else { 383 } else {
379 DEBUGF("Unsupported WMA codec (Lossless, Voice, etc)\n"); 384 DEBUGF("Unsupported WMA codec (Lossless, Voice, etc)\n");
380 lseek(fd,current.size - 24 - 72,SEEK_CUR); 385 lseek(fd,current.size - 24 - 72,SEEK_CUR);
diff --git a/lib/rbcodec/metadata/metadata.h b/lib/rbcodec/metadata/metadata.h
index fc9c1d062c..768e62d3b0 100644
--- a/lib/rbcodec/metadata/metadata.h
+++ b/lib/rbcodec/metadata/metadata.h
@@ -316,6 +316,9 @@ struct mp3entry {
316 316
317 /* Musicbrainz Track ID */ 317 /* Musicbrainz Track ID */
318 char* mb_track_id; 318 char* mb_track_id;
319
320 /* For ASF files with MP3 audio stream */
321 bool is_asf_stream;
319}; 322};
320 323
321unsigned int probe_file_format(const char *filename); 324unsigned int probe_file_format(const char *filename);