summaryrefslogtreecommitdiff
path: root/lib/rbcodec
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 /lib/rbcodec
parent13c7f482ce9614012312e8189b91be0fee65f2d9 (diff)
Support MP3 audiostreams embedded in ASF containers.
Full credit to Igor Poretsky Change-Id: I54769e33665cada1e1e0ef3a5511b56c8e1b859a
Diffstat (limited to 'lib/rbcodec')
-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)
# codec/library dependencies
$(CODECDIR)/spc.codec : $(CODECDIR)/libspc.a
-$(CODECDIR)/mpa.codec : $(CODECDIR)/libmad.a
+$(CODECDIR)/mpa.codec : $(CODECDIR)/libmad.a $(CODECDIR)/libasf.a
$(CODECDIR)/a52.codec : $(CODECDIR)/liba52.a
$(CODECDIR)/flac.codec : $(CODECDIR)/libffmpegFLAC.a
$(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 @@
#define ASF_CODEC_ID_WMAV2 0x161
#define ASF_CODEC_ID_WMAPRO 0x162
#define ASF_CODEC_ID_WMAVOICE 0x00A
+#define ASF_CODEC_ID_MP3 0x055
enum asf_error_e {
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 @@
****************************************************************************/
#include "codeclib.h"
+#include "libasf/asf.h"
#include <codecs/libmad/mad.h>
#include <inttypes.h>
@@ -56,6 +57,91 @@ static unsigned char mad_main_data[MAD_BUFFER_MDLEN] IBSS_ATTR;
static int mpeg_latency[3] = { 0, 481, 529 };
static int mpeg_framesize[3] = {384, 1152, 1152};
+static unsigned char stream_buffer[INPUT_CHUNK_SIZE] IBSS_ATTR;
+static unsigned char *stream_data_start;
+static unsigned char *stream_data_end;
+static unsigned char *packetdata;
+static int stream_data_available;
+static int packetlength;
+static int packetdatasize;
+static int packetrest;
+static unsigned char *lastpacketpos;
+
+static void reset_stream_buffer(void)
+{
+ stream_data_start = stream_buffer;
+ stream_data_end = stream_buffer;
+ stream_data_available = 1;
+ packetdatasize = 0;
+ packetrest = 0;
+ lastpacketpos = stream_buffer;
+}
+
+static inline unsigned char *get_stream_data(size_t *realsize, size_t reqsize)
+{
+ static int errcount = 0;
+ size_t datasize = stream_data_end - stream_data_start;
+ if (!ci->id3->is_asf_stream)
+ return ci->request_buffer(realsize, reqsize);
+ else if (datasize < INPUT_CHUNK_SIZE / 2)
+ {
+ if (stream_data_start < stream_data_end && stream_data_start > stream_buffer)
+ {
+ lastpacketpos -= stream_data_start - stream_buffer;
+ memmove(stream_buffer, stream_data_start, datasize);
+ stream_data_start = stream_buffer;
+ stream_data_end = stream_buffer + datasize;
+ }
+ while (datasize < INPUT_CHUNK_SIZE && (packetrest || stream_data_available > 0))
+ {
+ if (packetrest && packetdata)
+ {
+ datasize = INPUT_CHUNK_SIZE - datasize;
+ if (datasize > (size_t)packetrest)
+ datasize = packetrest;
+ memcpy(stream_data_end, packetdata, datasize);
+ packetrest -= datasize;
+ stream_data_end += datasize;
+ if (packetrest)
+ packetdata += datasize;
+ else
+ {
+ ci->advance_buffer(packetlength);
+ lastpacketpos = stream_data_end;
+ }
+ datasize = stream_data_end - stream_data_start;
+ }
+ else
+ {
+ asf_waveformatex_t *wfx = (asf_waveformatex_t *)(ci->id3->toc);
+ int res = asf_read_packet(&packetdata, &packetdatasize, &packetlength, wfx);
+ if (res < 0)
+ {
+ if (res == ASF_ERROR_EOF)
+ stream_data_available = 0;
+ else if (++errcount > 5)
+ stream_data_available = -1;
+ }
+ else errcount = 0;
+ packetrest = packetdatasize;
+ }
+ }
+ }
+ if (packetdatasize && lastpacketpos > stream_data_start)
+ ci->set_offset(ci->curpos - ((lastpacketpos - stream_data_start) / packetdatasize + 1) * packetlength);
+ *realsize = (datasize > reqsize) ? reqsize : datasize;
+ return stream_data_start;
+}
+
+static void advance_stream_buffer(size_t size)
+{
+ if (!ci->id3->is_asf_stream)
+ ci->advance_buffer(size);
+ else if (stream_data_start + size > stream_data_end)
+ stream_data_start = stream_data_end;
+ else stream_data_start += size;
+}
+
static void init_mad(void)
{
ci->memset(&stream, 0, sizeof(struct mad_stream));
@@ -346,14 +432,26 @@ enum codec_status codec_run(void)
current_frequency = ci->id3->frequency;
codec_set_replaygain(ci->id3);
- if (!ci->id3->offset && ci->id3->elapsed) {
+ if (!ci->id3->is_asf_stream && !ci->id3->offset && ci->id3->elapsed) {
/* Have elapsed time but not offset */
ci->id3->offset = get_file_pos(ci->id3->elapsed);
}
if (ci->id3->offset) {
- ci->seek_buffer(ci->id3->offset);
- set_elapsed(ci->id3);
+
+ if (ci->id3->is_asf_stream) {
+ asf_waveformatex_t *wfx = (asf_waveformatex_t *)(ci->id3->toc);
+ int packet_offset = ((ci->id3->offset > ci->id3->first_frame_offset) ?
+ (ci->id3->offset - ci->id3->first_frame_offset) : 0)
+ % wfx->packet_size;
+ ci->seek_buffer(ci->id3->offset - packet_offset);
+ ci->id3->elapsed = asf_get_timestamp(&packet_offset);
+ ci->set_elapsed(ci->id3->elapsed);
+ }
+ else {
+ ci->seek_buffer(ci->id3->offset);
+ set_elapsed(ci->id3);
+ }
}
else
ci->seek_buffer(ci->id3->first_frame_offset);
@@ -388,6 +486,8 @@ enum codec_status codec_run(void)
else
samples_to_skip = start_skip;
+ if (ci->id3->is_asf_stream)
+ reset_stream_buffer();
framelength = 0;
/* This is the decoding loop. */
@@ -398,39 +498,59 @@ enum codec_status codec_run(void)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
- int newpos;
-
/*make sure the synth thread is idle before seeking - MT only*/
mad_synth_thread_wait_pcm();
mad_synth_thread_unwait_pcm();
- samplesdone = ((int64_t)param)*current_frequency/1000;
-
if (param == 0) {
- newpos = ci->id3->first_frame_offset;
samples_to_skip = start_skip;
} else {
- newpos = get_file_pos(param);
samples_to_skip = 0;
}
- if (!ci->seek_buffer(newpos))
- {
+ if (ci->id3->is_asf_stream) {
+ asf_waveformatex_t *wfx = (asf_waveformatex_t *)(ci->id3->toc);
+ int elapsedtime = asf_seek(param, wfx);
+
+ samplesdone = (elapsedtime > 0) ?
+ (((int64_t)elapsedtime)*current_frequency/1000) : 0;
+
+ if (elapsedtime < 1) {
+ ci->set_elapsed(0);
+ ci->seek_complete();
+ break;
+ } else {
+ ci->set_elapsed(elapsedtime);
+ ci->seek_complete();
+ reset_stream_buffer();
+ }
+ } else {
+ int newpos = param ? get_file_pos(param) : (int)(ci->id3->first_frame_offset);
+
+ samplesdone = ((int64_t)param)*current_frequency/1000;
+
+ if (!ci->seek_buffer(newpos))
+ {
+ ci->seek_complete();
+ break;
+ }
+
+ ci->set_elapsed((samplesdone * 1000LL) / current_frequency);
ci->seek_complete();
- break;
}
- ci->set_elapsed((samplesdone * 1000LL) / current_frequency);
- ci->seek_complete();
init_mad();
framelength = 0;
}
/* Lock buffers */
if (stream.error == 0) {
- inputbuffer = ci->request_buffer(&size, INPUT_CHUNK_SIZE);
- if (size == 0 || inputbuffer == NULL)
+ inputbuffer = get_stream_data(&size, INPUT_CHUNK_SIZE);
+ if (size == 0 || inputbuffer == NULL) {
+ if (ci->id3->is_asf_stream && stream_data_available < 0)
+ return CODEC_ERROR;
break;
+ }
mad_stream_buffer(&stream, (unsigned char *)inputbuffer,
size + padding);
}
@@ -443,9 +563,9 @@ enum codec_status codec_run(void)
/* Fill the buffer */
if (stream.next_frame)
- ci->advance_buffer(stream.next_frame - stream.buffer);
+ advance_stream_buffer(stream.next_frame - stream.buffer);
else
- ci->advance_buffer(size);
+ advance_stream_buffer(size);
stream.error = 0; /* Must get new inputbuffer next time */
file_end++;
continue;
@@ -454,7 +574,7 @@ enum codec_status codec_run(void)
continue;
} else {
/* Some other unrecoverable error */
- return CODEC_ERROR;
+ return CODEC_ERROR;
}
}
@@ -495,9 +615,9 @@ enum codec_status codec_run(void)
}
if (stream.next_frame)
- ci->advance_buffer(stream.next_frame - stream.buffer);
+ advance_stream_buffer(stream.next_frame - stream.buffer);
else
- ci->advance_buffer(size);
+ advance_stream_buffer(size);
stream.error = 0; /* Must get new inputbuffer next time */
file_end = 0;
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,
lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR);
wfx->audiostream = flags&0x7f;
id3->codectype = AFMT_WMAVOICE;
+ } else if (wfx->codec_id == ASF_CODEC_ID_MP3) {
+ lseek(fd,current.size - 24 - 72,SEEK_CUR);
+ wfx->audiostream = flags&0x7f;
+ id3->codectype = AFMT_MPA_L3;
+ id3->is_asf_stream = true;
} else {
DEBUGF("Unsupported WMA codec (Lossless, Voice, etc)\n");
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 {
/* Musicbrainz Track ID */
char* mb_track_id;
+
+ /* For ASF files with MP3 audio stream */
+ bool is_asf_stream;
};
unsigned int probe_file_format(const char *filename);