summaryrefslogtreecommitdiffstats
path: root/lib/rbcodec
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec')
-rw-r--r--lib/rbcodec/codecs/libm4a/demux.c31
-rw-r--r--lib/rbcodec/codecs/libm4a/m4a.c148
-rw-r--r--lib/rbcodec/codecs/libm4a/m4a.h1
-rw-r--r--lib/rbcodec/dsp/tdspeed.c9
-rw-r--r--lib/rbcodec/dsp/tdspeed.h1
-rw-r--r--lib/rbcodec/metadata/aac.c2
-rw-r--r--lib/rbcodec/metadata/asap.c19
-rw-r--r--lib/rbcodec/metadata/asf.c81
-rw-r--r--lib/rbcodec/metadata/id3tags.c15
-rw-r--r--lib/rbcodec/metadata/metadata.c38
-rw-r--r--lib/rbcodec/metadata/metadata.h1
-rw-r--r--lib/rbcodec/metadata/metadata_common.c90
-rw-r--r--lib/rbcodec/metadata/metadata_common.h4
-rw-r--r--lib/rbcodec/metadata/mp4.c21
-rw-r--r--lib/rbcodec/metadata/replaygain.c31
15 files changed, 302 insertions, 190 deletions
diff --git a/lib/rbcodec/codecs/libm4a/demux.c b/lib/rbcodec/codecs/libm4a/demux.c
index 3bf46efec6..e29ecb8339 100644
--- a/lib/rbcodec/codecs/libm4a/demux.c
+++ b/lib/rbcodec/codecs/libm4a/demux.c
@@ -349,6 +349,7 @@ static bool read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len)
static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
{
size_t size_remaining = chunk_len - 8;
+ uint32_t numsizes, i;
/* version */
stream_read_uint8(qtmovie->stream);
@@ -369,9 +370,37 @@ static bool read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len)
}
size_remaining -= 4;
- qtmovie->res->num_sample_byte_sizes = stream_read_uint32(qtmovie->stream);
+ numsizes = stream_read_uint32(qtmovie->stream);
size_remaining -= 4;
+ /* Because this table can be really large and is only used to improve seek
+ * accuracy, it's optional. In that case the seek code will fall back to a
+ * less accurate seek method. */
+ qtmovie->res->num_sample_byte_sizes = numsizes;
+ if (numsizes * sizeof(uint32_t) < CODEC_SIZE * 1 / 2)
+ qtmovie->res->sample_byte_sizes = malloc(numsizes * sizeof(uint32_t));
+ else
+ qtmovie->res->sample_byte_sizes = NULL;
+
+ if (qtmovie->res->sample_byte_sizes)
+ {
+ for (i = 0; i < numsizes; ++i)
+ {
+ qtmovie->res->sample_byte_sizes[i] =
+ stream_read_uint32(qtmovie->stream);
+ size_remaining -= 4;
+ }
+
+ if (size_remaining)
+ {
+ DEBUGF("extra bytes after stsz\n");
+ }
+ }
+ else
+ {
+ DEBUGF("stsz too large, ignoring it\n");
+ }
+
if (size_remaining)
{
stream_skip(qtmovie->stream, size_remaining);
diff --git a/lib/rbcodec/codecs/libm4a/m4a.c b/lib/rbcodec/codecs/libm4a/m4a.c
index 5fe778ac03..b967e15e7a 100644
--- a/lib/rbcodec/codecs/libm4a/m4a.c
+++ b/lib/rbcodec/codecs/libm4a/m4a.c
@@ -23,6 +23,13 @@
#include <inttypes.h>
#include "m4a.h"
+#undef DEBUGF
+#if defined(DEBUG)
+#define DEBUGF stream->ci->debugf
+#else
+#define DEBUGF(...)
+#endif
+
/* Implementation of the stream.h functions used by libalac */
#define _Swap32(v) do { \
@@ -127,76 +134,113 @@ int m4a_check_sample_offset(demux_res_t *demux_res, uint32_t frame, uint32_t *st
return demux_res->lookup_table[i].offset;
}
-/* Find the exact or preceding frame in lookup_table[]. Return both frame
- * and byte position of this match. */
-static void gather_offset(demux_res_t *demux_res, uint32_t *frame, uint32_t *offset)
-{
- uint32_t i = 0;
- for (i=0; i<demux_res->num_lookup_table; ++i)
- {
- if (demux_res->lookup_table[i].offset == 0)
- break;
- if (demux_res->lookup_table[i].sample > *frame)
- break;
- }
- i = (i>0) ? i-1 : 0; /* We want the last chunk _before_ *frame. */
- *frame = demux_res->lookup_table[i].sample;
- *offset = demux_res->lookup_table[i].offset;
-}
-
/* Seek to desired sound sample location. Return 1 on success (and modify
- * sound_samples_done and current_sample), 0 if failed.
- *
- * Find the sample (=frame) that contains the given sound sample, find a best
- * fit for this sample in the lookup_table[], seek to the byte position. */
+ * sound_samples_done and current_sample), 0 if failed. */
unsigned int m4a_seek(demux_res_t* demux_res, stream_t* stream,
uint32_t sound_sample_loc, uint32_t* sound_samples_done,
int* current_sample)
{
- uint32_t i = 0;
- uint32_t tmp_var, tmp_cnt, tmp_dur;
- uint32_t new_sample = 0; /* Holds the amount of chunks/frames. */
- uint32_t new_sound_sample = 0; /* Sums up total amount of samples. */
- uint32_t new_pos; /* Holds the desired chunk/frame index. */
-
- /* First check we have the appropriate metadata - we should always
- * have it.
- */
+ uint32_t i, sample_i, sound_sample_i;
+ uint32_t time, time_cnt, time_dur;
+ uint32_t chunk, chunk_first_sample;
+ uint32_t offset;
+ time_to_sample_t *tts_tab = demux_res->time_to_sample;
+ sample_offset_t *tco_tab = demux_res->lookup_table;
+ uint32_t *tsz_tab = demux_res->sample_byte_sizes;
+
+ /* First check we have the required metadata - we should always have it. */
if (!demux_res->num_time_to_samples || !demux_res->num_sample_byte_sizes)
- {
- return 0;
+ {
+ return 0;
}
- /* Find the destination block from time_to_sample array */
- time_to_sample_t *tab = demux_res->time_to_sample;
- while (i < demux_res->num_time_to_samples)
+ /* The 'sound_sample_loc' we have is PCM-based and not directly usable.
+ * We need to convert it to an MP4 sample number 'sample_i' first. */
+ sample_i = sound_sample_i = 0;
+ for (time = 0; time < demux_res->num_time_to_samples; ++time)
{
- tmp_cnt = tab[i].sample_count;
- tmp_dur = tab[i].sample_duration;
- tmp_var = tmp_cnt * tmp_dur;
- if (sound_sample_loc <= new_sound_sample + tmp_var)
+ time_cnt = tts_tab[time].sample_count;
+ time_dur = tts_tab[time].sample_duration;
+ uint32_t time_var = time_cnt * time_dur;
+
+ if (sound_sample_loc < sound_sample_i + time_var)
{
- tmp_var = (sound_sample_loc - new_sound_sample);
- new_sample += tmp_var / tmp_dur;
- new_sound_sample += tmp_var;
+ time_var = sound_sample_loc - sound_sample_i;
+ sample_i += time_var / time_dur;
break;
}
- new_sample += tmp_cnt;
- new_sound_sample += tmp_var;
- ++i;
+
+ sample_i += time_cnt;
+ sound_sample_i += time_var;
+ }
+
+ /* Find the chunk after 'sample_i'. */
+ for (chunk = 1; chunk < demux_res->num_lookup_table; ++chunk)
+ {
+ if (tco_tab[chunk].offset == 0)
+ break;
+ if (tco_tab[chunk].sample > sample_i)
+ break;
}
- /* We know the new sample (=frame), now calculate the file position. */
- gather_offset(demux_res, &new_sample, &new_pos);
+ /* The preceding chunk is the one that contains 'sample_i'. */
+ chunk--;
+ chunk_first_sample = tco_tab[chunk].sample;
+ offset = tco_tab[chunk].offset;
- /* We know the new file position, so let's try to seek to it */
- if (stream->ci->seek_buffer(new_pos))
+ /* Compute the PCM sample number of the chunk's first sample
+ * to get an accurate base for sound_sample_i. */
+ i = sound_sample_i = 0;
+ for (time = 0; time < demux_res->num_time_to_samples; ++time)
{
- *sound_samples_done = new_sound_sample;
- *current_sample = new_sample;
+ time_cnt = tts_tab[time].sample_count;
+ time_dur = tts_tab[time].sample_duration;
+
+ if (chunk_first_sample < i + time_cnt)
+ {
+ sound_sample_i += (chunk_first_sample - i) * time_dur;
+ break;
+ }
+
+ i += time_cnt;
+ sound_sample_i += time_cnt * time_dur;
+ }
+
+ DEBUGF("seek chunk=%lu, sample=%lu, soundsample=%lu, offset=%lu\n",
+ (unsigned long)chunk, (unsigned long)chunk_first_sample,
+ (unsigned long)sound_sample_i, (unsigned long)offset);
+
+ if (tsz_tab) {
+ /* We have a sample-to-bytes table available so we can do accurate
+ * seeking. Move one sample at a time and update the file offset and
+ * PCM sample offset as we go. */
+ for (i = chunk_first_sample;
+ i < sample_i && i < demux_res->num_sample_byte_sizes; ++i)
+ {
+ /* this could be unnecessary */
+ if (time_cnt == 0 && ++time < demux_res->num_time_to_samples)
+ {
+ time_cnt = tts_tab[time].sample_count;
+ time_dur = tts_tab[time].sample_duration;
+ }
+
+ offset += tsz_tab[i];
+ sound_sample_i += time_dur;
+ time_cnt--;
+ }
+ } else {
+ /* No sample-to-bytes table available so we can only seek to the
+ * start of a chunk, which is often much lower resolution. */
+ sample_i = chunk_first_sample;
+ }
+
+ if (stream->ci->seek_buffer(offset))
+ {
+ *sound_samples_done = sound_sample_i;
+ *current_sample = sample_i;
return 1;
}
-
+
return 0;
}
diff --git a/lib/rbcodec/codecs/libm4a/m4a.h b/lib/rbcodec/codecs/libm4a/m4a.h
index aa8e768045..81b10c3a27 100644
--- a/lib/rbcodec/codecs/libm4a/m4a.h
+++ b/lib/rbcodec/codecs/libm4a/m4a.h
@@ -80,6 +80,7 @@ typedef struct
time_to_sample_t *time_to_sample;
uint32_t num_time_to_samples;
+ uint32_t *sample_byte_sizes;
uint32_t num_sample_byte_sizes;
uint32_t codecdata_len;
diff --git a/lib/rbcodec/dsp/tdspeed.c b/lib/rbcodec/dsp/tdspeed.c
index 21585eb78e..64cbaf5e12 100644
--- a/lib/rbcodec/dsp/tdspeed.c
+++ b/lib/rbcodec/dsp/tdspeed.c
@@ -41,7 +41,6 @@
#define MAX_INPUTCOUNT 512 /* Max input count so dst doesn't overflow */
#define FIXED_BUFCOUNT 3072 /* 48KHz factor 3.0 */
#define FIXED_OUTBUFCOUNT 4096
-#define NBUFFERS 4
enum tdspeed_ops
{
@@ -65,9 +64,9 @@ static struct tdspeed_state_s
int32_t *ovl_buff[2]; /* overlap buffer (L+R) */
} tdspeed_state;
-static int32_t *buffers[NBUFFERS] = { NULL, NULL, NULL, NULL };
+static int32_t *buffers[TDSPEED_NBUFFERS] = { NULL, NULL, NULL, NULL };
-static const int buffer_sizes[NBUFFERS] =
+static const int buffer_sizes[TDSPEED_NBUFFERS] =
{
FIXED_BUFCOUNT * sizeof(int32_t),
FIXED_BUFCOUNT * sizeof(int32_t),
@@ -552,7 +551,7 @@ static intptr_t tdspeed_configure(struct dsp_proc_entry *this,
break;
case DSP_PROC_INIT:
- if (!tdspeed_alloc_buffers(buffers, buffer_sizes, NBUFFERS))
+ if (!tdspeed_alloc_buffers(buffers, buffer_sizes, TDSPEED_NBUFFERS))
return -1; /* fail the init */
st->this = this;
@@ -564,7 +563,7 @@ static intptr_t tdspeed_configure(struct dsp_proc_entry *this,
st->this = NULL;
st->factor = PITCH_SPEED_100;
dsp_outbuf.remcount = 0;
- tdspeed_free_buffers(buffers, NBUFFERS);
+ tdspeed_free_buffers(buffers, TDSPEED_NBUFFERS);
break;
case DSP_PROC_NEW_FORMAT:
diff --git a/lib/rbcodec/dsp/tdspeed.h b/lib/rbcodec/dsp/tdspeed.h
index 2949c1bee9..84920ac7c2 100644
--- a/lib/rbcodec/dsp/tdspeed.h
+++ b/lib/rbcodec/dsp/tdspeed.h
@@ -34,6 +34,7 @@
#define STRETCH_MAX (250L * PITCH_SPEED_PRECISION) /* 250% */
#define STRETCH_MIN (35L * PITCH_SPEED_PRECISION) /* 35% */
+#define TDSPEED_NBUFFERS 4
void dsp_timestretch_enable(bool enable);
void dsp_set_timestretch(int32_t percent);
diff --git a/lib/rbcodec/metadata/aac.c b/lib/rbcodec/metadata/aac.c
index 82adeacbde..358b2de079 100644
--- a/lib/rbcodec/metadata/aac.c
+++ b/lib/rbcodec/metadata/aac.c
@@ -41,7 +41,7 @@ static const int sample_rates[] =
static bool check_adts_syncword(int fd)
{
- uint16_t syncword;
+ uint16_t syncword = 0;
read_uint16be(fd, &syncword);
return (syncword & 0xFFF6) == 0xFFF0;
diff --git a/lib/rbcodec/metadata/asap.c b/lib/rbcodec/metadata/asap.c
index 47eb2a3d50..db23dd69fa 100644
--- a/lib/rbcodec/metadata/asap.c
+++ b/lib/rbcodec/metadata/asap.c
@@ -185,38 +185,41 @@ static bool parse_sap_header(int fd, struct mp3entry* id3, int file_len)
break;
}
}
-
+ static const char *tg_options[] = {"SAP", "AUTHOR", "NAME", "DATE",
+ "SONGS", "DEFSONG", "TIME", NULL};
/* parse tags */
- if(strcmp(line, "SAP") == 0)
+ int tg_op = string_option(line, tg_options, false);
+ if (tg_op == 0) /*SAP*/
sap_signature = 1;
if (sap_signature == -1)
return false;
- if (strcmp(line, "AUTHOR") == 0)
+
+ if (tg_op == 1) /*AUTHOR*/
{
if(read_asap_string(p, &buffer, &buffer_end, &id3->artist) == false)
return false;
}
- else if(strcmp(line, "NAME") == 0)
+ else if(tg_op == 2) /*NAME*/
{
if(read_asap_string(p, &buffer, &buffer_end, &id3->title) == false)
return false;
}
- else if(strcmp(line, "DATE") == 0)
+ else if(tg_op == 3) /*DATE*/
{
if(read_asap_string(p, &buffer, &buffer_end, &id3->year_string) == false)
return false;
}
- else if (strcmp(line, "SONGS") == 0)
+ else if (tg_op == 4) /*SONGS*/
{
if (parse_dec(&numSongs, p, 1, MAX_SONGS) == false )
return false;
}
- else if (strcmp(line, "DEFSONG") == 0)
+ else if (tg_op == 5) /*DEFSONG*/
{
if (parse_dec(&defSong, p, 0, MAX_SONGS) == false)
return false;
}
- else if (strcmp(line, "TIME") == 0)
+ else if (tg_op == 6) /*TIME*/
{
int durationTemp = ASAP_ParseDuration(p);
if (durationTemp < 0 || duration_index >= MAX_SONGS)
diff --git a/lib/rbcodec/metadata/asf.c b/lib/rbcodec/metadata/asf.c
index d90487b36b..82c418cc73 100644
--- a/lib/rbcodec/metadata/asf.c
+++ b/lib/rbcodec/metadata/asf.c
@@ -129,19 +129,21 @@ static int asf_intdecode(int fd, int type, int length)
{
int bytes = 0;
int ret;
- uint16_t tmp16;
- uint32_t tmp32;
- uint64_t tmp64;
+ union {
+ uint16_t tmp16;
+ uint32_t tmp32;
+ uint64_t tmp64;
+ } uu = {0};
if (type == 3) {
- bytes = read_uint32le(fd, &tmp32);
- ret = (int)tmp32;
+ bytes = read_uint32le(fd, &uu.tmp32);
+ ret = (int)uu.tmp32;
} else if (type == 4) {
- bytes = read_uint64le(fd, &tmp64);
- ret = (int)tmp64;
+ bytes = read_uint64le(fd, &uu.tmp64);
+ ret = (int)uu.tmp64;
} else if (type == 5) {
- bytes = read_uint16le(fd, &tmp16);
- ret = (int)tmp16;
+ bytes = read_uint16le(fd, &uu.tmp16);
+ ret = (int)uu.tmp16;
}
if (bytes > 0)
@@ -437,6 +439,25 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
read_uint16le(fd, &count);
bytesleft -= 2;
//DEBUGF("extended metadata count = %u\n",count);
+ enum
+ {
+ eWM_TrackNumber, eWM_Genre, eWM_AlbumTitle,
+ eWM_AlbumArtist, eWM_Composer, eWM_Year,
+ eWM_MusicBrainz_Track_Id, eWM_Picture,
+ eWM_COUNT_TAG_COUNT
+ };
+
+ static const char *tagops[eWM_COUNT_TAG_COUNT + 1] =
+ { [eWM_TrackNumber] = "WM/TrackNumber",
+ [eWM_Genre] = "WM/Genre",
+ [eWM_AlbumTitle] = "WM/AlbumTitle",
+ [eWM_AlbumArtist] = "WM/AlbumArtist",
+ [eWM_Composer] = "WM/Composer",
+ [eWM_Year] = "WM/Year",
+ [eWM_MusicBrainz_Track_Id]"MusicBrainz/Track Id",
+ [eWM_Picture]"WM/Picture",
+ [eWM_COUNT_TAG_COUNT] = NULL
+ };
for (i=0; i < count; i++) {
uint16_t length, type;
@@ -450,7 +471,9 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
read_uint16le(fd, &type);
read_uint16le(fd, &length);
- if (!strcmp("WM/TrackNumber",utf8buf)) {
+ int itag = string_option(utf8buf, tagops, false);
+
+ if (itag == eWM_TrackNumber) {
if (type == 0) {
id3->track_string = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
@@ -460,19 +483,19 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
} else {
lseek(fd, length, SEEK_CUR);
}
- } else if ((!strcmp("WM/Genre", utf8buf)) && (type == 0)) {
+ } else if ((itag == eWM_Genre) && (type == 0)) {
id3->genre_string = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
- } else if ((!strcmp("WM/AlbumTitle", utf8buf)) && (type == 0)) {
+ } else if ((itag == eWM_AlbumTitle) && (type == 0)) {
id3->album = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
- } else if ((!strcmp("WM/AlbumArtist", utf8buf)) && (type == 0)) {
+ } else if ((itag == eWM_AlbumArtist) && (type == 0)) {
id3->albumartist = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
- } else if ((!strcmp("WM/Composer", utf8buf)) && (type == 0)) {
+ } else if ((itag == eWM_Composer) && (type == 0)) {
id3->composer = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
- } else if (!strcmp("WM/Year", utf8buf)) {
+ } else if (itag == eWM_Year) {
if (type == 0) {
id3->year_string = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
@@ -482,15 +505,11 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
} else {
lseek(fd, length, SEEK_CUR);
}
- } else if (!strncmp("replaygain_", utf8buf, 11)) {
- char *value = id3buf;
- asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
- parse_replaygain(utf8buf, value, id3);
- } else if (!strcmp("MusicBrainz/Track Id", utf8buf)) {
+ } else if (itag == eWM_MusicBrainz_Track_Id) {
id3->mb_track_id = id3buf;
asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
#ifdef HAVE_ALBUMART
- } else if (!strcmp("WM/Picture", utf8buf)) {
+ } else if (itag == eWM_Picture) {
uint32_t datalength = 0;
uint32_t strlength;
/* Expected is either "01 00 xx xx 03 yy yy yy yy" or
@@ -521,13 +540,23 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
asf_utf16LEdecode(fd, 32, &utf8, &utf8length);
strlength = (strlen(utf8buf) + 2) * 2;
lseek(fd, strlength-32, SEEK_CUR);
- if (!strcmp("image/jpeg", utf8buf)) {
+
+ static const char *aa_options[] = {"image/jpeg",
+ "image/jpg","image/png", NULL};
+ int aa_op = string_option(utf8buf, aa_options, false);
+
+ if (aa_op == 0) /*image/jpeg*/
+ {
id3->albumart.type = AA_TYPE_JPG;
- } else if (!strcmp("image/jpg", utf8buf)) {
+ }
+ else if (aa_op == 1) /*image/jpg*/
+ {
/* image/jpg is technically invalid,
* but it does occur in the wild */
id3->albumart.type = AA_TYPE_JPG;
- } else if (!strcmp("image/png", utf8buf)) {
+ }
+ else if (aa_op == 2) /*image/png*/
+ {
id3->albumart.type = AA_TYPE_PNG;
} else {
id3->albumart.type = AA_TYPE_UNKNOWN;
@@ -543,6 +572,10 @@ static int asf_parse_header(int fd, struct mp3entry* id3,
lseek(fd, datalength, SEEK_CUR);
#endif
+ } else if (!strncmp("replaygain_", utf8buf, 11)) {
+ char *value = id3buf;
+ asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
+ parse_replaygain(utf8buf, value, id3);
} else {
lseek(fd, length, SEEK_CUR);
}
diff --git a/lib/rbcodec/metadata/id3tags.c b/lib/rbcodec/metadata/id3tags.c
index 458e24cf61..ba7695d569 100644
--- a/lib/rbcodec/metadata/id3tags.c
+++ b/lib/rbcodec/metadata/id3tags.c
@@ -308,24 +308,27 @@ static int parsealbumart( struct mp3entry* entry, char* tag, int bufferpos )
char *start = tag;
/* skip text encoding */
tag += 1;
+ static const char *img_options[] = {"jpeg", "jpg", "png", NULL};
if (memcmp(tag, "image/", 6) == 0)
{
/* ID3 v2.3+ */
tag += 6;
- if (strcmp(tag, "jpeg") == 0)
+ int tg_op = string_option(tag, img_options, false);
+
+ if (tg_op == 0) /*jpeg*/
{
entry->albumart.type = AA_TYPE_JPG;
tag += 5;
}
- else if (strcmp(tag, "jpg") == 0)
+ else if (tg_op == 1) /*jpg*/
{
/* image/jpg is technically invalid, but it does occur in
* the wild */
entry->albumart.type = AA_TYPE_JPG;
tag += 4;
}
- else if (strcmp(tag, "png") == 0)
+ else if (tg_op == 2) /*png*/
{
entry->albumart.type = AA_TYPE_PNG;
tag += 4;
@@ -434,9 +437,11 @@ static int parserva2( struct mp3entry* entry, char* tag, int bufferpos)
}
}
- if (strcasecmp(tag, "album") == 0) {
+ static const char *tg_options[] = {"album", "track", NULL};
+ int tg_op = string_option(tag, tg_options, true);
+ if (tg_op == 0) { /*album*/
album = true;
- } else if (strcasecmp(tag, "track") != 0) {
+ } else if (tg_op != 1) { /*!track*/
/* Only accept non-track values if we don't have any previous
* value.
*/
diff --git a/lib/rbcodec/metadata/metadata.c b/lib/rbcodec/metadata/metadata.c
index aec72db97f..19147ccdb3 100644
--- a/lib/rbcodec/metadata/metadata.c
+++ b/lib/rbcodec/metadata/metadata.c
@@ -458,44 +458,6 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname)
return true;
}
-#ifndef __PCTOOL__
-void strip_tags(int handle_id)
-{
- static const unsigned char tag[] = "TAG";
- static const unsigned char apetag[] = "APETAGEX";
- size_t len, version;
- void *tail;
-
- if (bufgettail(handle_id, 128, &tail) != 128)
- return;
-
- if (memcmp(tail, tag, 3) == 0)
- {
- /* Skip id3v1 tag */
- logf("Cutting off ID3v1 tag");
- bufcuttail(handle_id, 128);
- }
-
- /* Get a new tail, as the old one may have been cut */
- if (bufgettail(handle_id, 32, &tail) != 32)
- return;
-
- /* Check for APE tag (look for the APE tag footer) */
- if (memcmp(tail, apetag, 8) != 0)
- return;
-
- /* Read the version and length from the footer */
- version = get_long_le(&((unsigned char *)tail)[8]);
- len = get_long_le(&((unsigned char *)tail)[12]);
- if (version == 2000)
- len += 32; /* APEv2 has a 32 byte header */
-
- /* Skip APE tag */
- logf("Cutting off APE tag (%ldB)", len);
- bufcuttail(handle_id, len);
-}
-#endif /* ! __PCTOOL__ */
-
#define MOVE_ENTRY(x) if (x) x += offset;
void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig)
diff --git a/lib/rbcodec/metadata/metadata.h b/lib/rbcodec/metadata/metadata.h
index 50fd5bac86..1a205a08eb 100644
--- a/lib/rbcodec/metadata/metadata.h
+++ b/lib/rbcodec/metadata/metadata.h
@@ -333,7 +333,6 @@ void wipe_mp3entry(struct mp3entry *id3);
void fill_metadata_from_path(struct mp3entry *id3, const char *trackname);
int get_audio_base_codec_type(int type);
-void strip_tags(int handle_id);
bool rbcodec_format_is_atomic(int afmt);
bool format_buffers_with_offset(int afmt);
diff --git a/lib/rbcodec/metadata/metadata_common.c b/lib/rbcodec/metadata/metadata_common.c
index 6fc50e9a9d..8eec16a877 100644
--- a/lib/rbcodec/metadata/metadata_common.c
+++ b/lib/rbcodec/metadata/metadata_common.c
@@ -252,6 +252,26 @@ bool skip_id3v2(int fd, struct mp3entry *id3)
return success;
}
+#if !defined(ROCKBOX) || defined(WARBLE) /*codecs can be built without rockbox */
+/* returns match index from option list
+ * returns -1 if option was not found
+ * option list is array of char pointers with the final item set to null
+ * ex - const char *option[] = { "op_a", "op_b", "op_c", NULL}
+ */
+int string_option(const char *option, const char *const oplist[], bool ignore_case)
+{
+ const char *op;
+ int (*cmp_fn)(const char*, const char*) = &strcasecmp;
+ if (!ignore_case)
+ cmp_fn = strcmp;
+ for (int i=0; (op=oplist[i]) != NULL; i++)
+ {
+ if (cmp_fn(op, option) == 0)
+ return i;
+ }
+ return -1;
+}
+#endif
/* Parse the tag (the name-value pair) and fill id3 and buffer accordingly.
* String values to keep are written to buf. Returns number of bytes written
* to buf (including end nil).
@@ -262,19 +282,44 @@ long parse_tag(const char* name, char* value, struct mp3entry* id3,
long len = 0;
char** p;
- if ((((strcasecmp(name, "track") == 0) && (type == TAGTYPE_APE)))
- || ((strcasecmp(name, "tracknumber") == 0) && (type == TAGTYPE_VORBIS)))
+ enum
+ {
+ eTRACK = 0, eTRACKNUMBER, eDISCNUMBER, eDISC,
+ eYEAR, eDATE, eTITLE, eARTIST, eALBUM, eGENRE,
+ eCOMPOSER, eCOMMENT, eALBUMARTIST, eALBUM_ARTIST,
+ eENSEMBLE, eGROUPING, eCONTENTGROUP, eCONTENT_GROUP,
+ eMUSICBRAINZ1, eMUSICBRAINZ2, e_COUNT_TAG_COUNT
+ };
+
+ static const char *tagops[e_COUNT_TAG_COUNT + 1] =
+ { [eTRACK] = "track", [eTRACKNUMBER] = "tracknumber",
+ [eDISCNUMBER] = "discnumber", [eDISC] = "disc",
+ [eYEAR] = "year", [eDATE] = "date", [eTITLE] = "title",
+ [eARTIST] = "artist", [eALBUM] = "album", [eGENRE] = "genre",
+ [eCOMPOSER] = "composer", [eCOMMENT] = "comment",
+ [eALBUMARTIST] = "albumartist", [eALBUM_ARTIST] ="album artist",
+ [eENSEMBLE] = "ensemble", [eGROUPING] = "grouping",
+ [eCONTENTGROUP] = "contentgroup", [eCONTENT_GROUP] = "content group",
+ [eMUSICBRAINZ1] = "musicbrainz_trackid",
+ [eMUSICBRAINZ2] = "http://musicbrainz.org",
+ [e_COUNT_TAG_COUNT] = NULL
+ };
+
+ int item = string_option(name, tagops, true);
+
+ if (((item == eTRACK && (type == TAGTYPE_APE)))
+ || (item == eTRACKNUMBER && (type == TAGTYPE_VORBIS)))
{
id3->tracknum = atoi(value);
p = &(id3->track_string);
}
- else if (strcasecmp(name, "discnumber") == 0 || strcasecmp(name, "disc") == 0)
+ else if (item == eDISCNUMBER || item == eDISC)
{
id3->discnum = atoi(value);
p = &(id3->disc_string);
}
- else if (((strcasecmp(name, "year") == 0) && (type == TAGTYPE_APE))
- || ((strcasecmp(name, "date") == 0) && (type == TAGTYPE_VORBIS)))
+ else if ((item == eYEAR && (type == TAGTYPE_APE))
+ || (item == eDATE && (type == TAGTYPE_VORBIS)))
{
/* Date's can be in any format in Vorbis. However most of them
* are in ISO8601 format so if we try and parse the first part
@@ -288,56 +333,39 @@ long parse_tag(const char* name, char* value, struct mp3entry* id3,
}
p = &(id3->year_string);
}
- else if (strcasecmp(name, "title") == 0)
+ else if (item == eTITLE)
{
p = &(id3->title);
}
- else if (strcasecmp(name, "artist") == 0)
+ else if (item == eARTIST)
{
p = &(id3->artist);
}
- else if (strcasecmp(name, "album") == 0)
+ else if (item == eALBUM)
{
p = &(id3->album);
}
- else if (strcasecmp(name, "genre") == 0)
+ else if (item == eGENRE)
{
p = &(id3->genre_string);
}
- else if (strcasecmp(name, "composer") == 0)
+ else if (item == eCOMPOSER)
{
p = &(id3->composer);
}
- else if (strcasecmp(name, "comment") == 0)
+ else if (item == eCOMMENT)
{
p = &(id3->comment);
}
- else if (strcasecmp(name, "albumartist") == 0)
- {
- p = &(id3->albumartist);
- }
- else if (strcasecmp(name, "album artist") == 0)
+ else if (item == eALBUMARTIST || item == eALBUM_ARTIST || item == eENSEMBLE)
{
p = &(id3->albumartist);
}
- else if (strcasecmp(name, "ensemble") == 0)
- {
- p = &(id3->albumartist);
- }
- else if (strcasecmp(name, "grouping") == 0)
- {
- p = &(id3->grouping);
- }
- else if (strcasecmp(name, "content group") == 0)
- {
- p = &(id3->grouping);
- }
- else if (strcasecmp(name, "contentgroup") == 0)
+ else if (item == eGROUPING || item == eCONTENTGROUP || item == eCONTENT_GROUP)
{
p = &(id3->grouping);
}
- else if (strcasecmp(name, "musicbrainz_trackid") == 0
- || strcasecmp(name, "http://musicbrainz.org") == 0 )
+ else if (item == eMUSICBRAINZ1 || item == eMUSICBRAINZ2)
{
p = &(id3->mb_track_id);
}
diff --git a/lib/rbcodec/metadata/metadata_common.h b/lib/rbcodec/metadata/metadata_common.h
index db91729de4..0f6fcb279c 100644
--- a/lib/rbcodec/metadata/metadata_common.h
+++ b/lib/rbcodec/metadata/metadata_common.h
@@ -30,7 +30,8 @@
#define TAG_NAME_LENGTH 32
#define TAG_VALUE_LENGTH 128
-#define FOURCC(a,b,c,d) (((a)<<24) | ((b) << 16) | ((c) << 8) | (d))
+#define FOURCC(a,b,c,d) ((((unsigned long)(a)) << 24) | (((unsigned long)(b)) << 16) | \
+ (((unsigned long)(c)) << 8) | ((unsigned long)(d)))
enum tagtype { TAGTYPE_APE = 1, TAGTYPE_VORBIS };
@@ -38,6 +39,7 @@ bool read_ape_tags(int fd, struct mp3entry* id3);
long read_vorbis_tags(int fd, struct mp3entry *id3,
long tag_remaining);
+int string_option(const char *option, const char *const oplist[], bool ignore_case);
bool skip_id3v2(int fd, struct mp3entry *id3);
long read_string(int fd, char* buf, long buf_size, int eos, long size);
diff --git a/lib/rbcodec/metadata/mp4.c b/lib/rbcodec/metadata/mp4.c
index 41f38480b1..19e6b515c7 100644
--- a/lib/rbcodec/metadata/mp4.c
+++ b/lib/rbcodec/metadata/mp4.c
@@ -195,7 +195,7 @@ static unsigned int read_mp4_length(int fd, uint32_t* size)
{
unsigned int length = 0;
int bytes = 0;
- unsigned char c;
+ unsigned char c = '\0';
do
{
@@ -211,7 +211,7 @@ static unsigned int read_mp4_length(int fd, uint32_t* size)
static bool read_mp4_esds(int fd, struct mp3entry* id3, uint32_t* size)
{
- unsigned char buf[8];
+ unsigned char buf[8] = {0};
bool sbr = false;
lseek(fd, 4, SEEK_CUR); /* Version and flags. */
@@ -533,13 +533,18 @@ static bool read_mp4_tags(int fd, struct mp3entry* id3,
rd_ret = 0;
tag_name[rd_ret] = 0;
+ static const char *tn_options[] = {"composer", "iTunSMPB",
+ "musicbrainz track id", "album artist", NULL};
- if ((strcasecmp(tag_name, "composer") == 0) && !cwrt)
+ int tn_op = string_option(tag_name, tn_options, true);
+
+
+ if (tn_op == 0 && !cwrt) /*composer*/
{
read_mp4_tag_string(fd, size, &buffer, &buffer_left,
&id3->composer);
}
- else if (strcasecmp(tag_name, "iTunSMPB") == 0)
+ else if (tn_op == 1) /*iTunSMPB*/
{
char value[TAG_VALUE_LENGTH];
char* value_p = value;
@@ -552,12 +557,12 @@ static bool read_mp4_tags(int fd, struct mp3entry* id3,
DEBUGF("AAC: lead_trim %d, tail_trim %d\n",
id3->lead_trim, id3->tail_trim);
}
- else if (strcasecmp(tag_name, "musicbrainz track id") == 0)
+ else if (tn_op == 2) /*musicbrainz track id*/
{
read_mp4_tag_string(fd, size, &buffer, &buffer_left,
&id3->mb_track_id);
}
- else if ((strcasecmp(tag_name, "album artist") == 0))
+ else if (tn_op == 3) /*album artist*/
{
read_mp4_tag_string(fd, size, &buffer, &buffer_left,
&id3->albumartist);
@@ -784,8 +789,8 @@ static bool read_mp4_container(int fd, struct mp3entry* id3,
{
/* ADDME: add support for real chapters. Right now it's only
* used for Nero's gapless hack */
- uint8_t chapters;
- uint64_t timestamp;
+ uint8_t chapters = 0;
+ uint64_t timestamp = 0;
lseek(fd, 8, SEEK_CUR);
read_uint8(fd, &chapters);
diff --git a/lib/rbcodec/metadata/replaygain.c b/lib/rbcodec/metadata/replaygain.c
index 7aa77cfedd..eb98bbc342 100644
--- a/lib/rbcodec/metadata/replaygain.c
+++ b/lib/rbcodec/metadata/replaygain.c
@@ -32,6 +32,7 @@
#include "debug.h"
#include "replaygain.h"
#include "fixedpoint.h"
+#include "metadata_common.h"
#define FP_BITS (12)
#define FP_ONE (1 << FP_BITS)
@@ -167,29 +168,29 @@ long get_replaygain_int(long int_gain)
void parse_replaygain(const char* key, const char* value,
struct mp3entry* entry)
{
- if (((strcasecmp(key, "replaygain_track_gain") == 0) ||
- (strcasecmp(key, "rg_radio") == 0)) &&
- !entry->track_gain)
- {
+ static const char *rg_options[] = {"replaygain_track_gain", "rg_radio",
+ "replaygain_album_gain", "rg_audiophile",
+ "replaygain_track_peak", "rg_peak",
+ "replaygain_album_peak", NULL};
+
+ int rg_op = string_option(key, rg_options, true);
+
+ if ((rg_op == 0 || rg_op == 1) && !entry->track_gain)
+ { /*replaygain_track_gain||rg_radio*/
entry->track_level = get_replaygain(value);
entry->track_gain = convert_gain(entry->track_level);
}
- else if (((strcasecmp(key, "replaygain_album_gain") == 0) ||
- (strcasecmp(key, "rg_audiophile") == 0)) &&
- !entry->album_gain)
- {
+ else if ((rg_op == 2 || rg_op == 3) && !entry->album_gain)
+ { /*replaygain_album_gain||rg_audiophile*/
entry->album_level = get_replaygain(value);
entry->album_gain = convert_gain(entry->album_level);
}
- else if (((strcasecmp(key, "replaygain_track_peak") == 0) ||
- (strcasecmp(key, "rg_peak") == 0)) &&
- !entry->track_peak)
- {
+ else if ((rg_op == 4 || rg_op == 5) && !entry->track_peak)
+ { /*replaygain_track_peak||rg_peak*/
entry->track_peak = get_replaypeak(value);
}
- else if ((strcasecmp(key, "replaygain_album_peak") == 0) &&
- !entry->album_peak)
- {
+ else if ((rg_op == 6) && !entry->album_peak)
+ { /*replaygain_album_peak*/
entry->album_peak = get_replaypeak(value);
}
}