diff options
Diffstat (limited to 'lib/rbcodec')
-rw-r--r-- | lib/rbcodec/codecs/libm4a/demux.c | 31 | ||||
-rw-r--r-- | lib/rbcodec/codecs/libm4a/m4a.c | 148 | ||||
-rw-r--r-- | lib/rbcodec/codecs/libm4a/m4a.h | 1 | ||||
-rw-r--r-- | lib/rbcodec/dsp/tdspeed.c | 9 | ||||
-rw-r--r-- | lib/rbcodec/dsp/tdspeed.h | 1 | ||||
-rw-r--r-- | lib/rbcodec/metadata/aac.c | 2 | ||||
-rw-r--r-- | lib/rbcodec/metadata/asap.c | 19 | ||||
-rw-r--r-- | lib/rbcodec/metadata/asf.c | 81 | ||||
-rw-r--r-- | lib/rbcodec/metadata/id3tags.c | 15 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata.c | 38 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata.h | 1 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata_common.c | 90 | ||||
-rw-r--r-- | lib/rbcodec/metadata/metadata_common.h | 4 | ||||
-rw-r--r-- | lib/rbcodec/metadata/mp4.c | 21 | ||||
-rw-r--r-- | lib/rbcodec/metadata/replaygain.c | 31 |
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); } } |