diff options
Diffstat (limited to 'lib/rbcodec')
-rw-r--r-- | lib/rbcodec/codecs/codecs.make | 2 | ||||
-rw-r--r-- | lib/rbcodec/codecs/libasf/asf.h | 1 | ||||
-rw-r--r-- | lib/rbcodec/codecs/mpa.c | 162 | ||||
-rw-r--r-- | lib/rbcodec/metadata/asf.c | 5 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata.h | 3 |
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 | ||
12 | enum asf_error_e { | 13 | enum 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; | |||
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 | ||
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 | ||
321 | unsigned int probe_file_format(const char *filename); | 324 | unsigned int probe_file_format(const char *filename); |