diff options
| author | Sean Bartell <wingedtachikoma@gmail.com> | 2011-06-24 01:25:21 -0400 |
|---|---|---|
| committer | Nils Wallménius <nils@rockbox.org> | 2012-03-18 12:00:39 +0100 |
| commit | b5716df4cb2837bbbc42195cf1aefcf03e21d6a6 (patch) | |
| tree | 130cd712e2e00893b6df9959a375a8d9523a1aca /apps/metadata | |
| parent | 24bd9d5393dbe39a5c6194877bc00ede669b1d5d (diff) | |
| download | rockbox-b5716df4cb2837bbbc42195cf1aefcf03e21d6a6.zip rockbox-b5716df4cb2837bbbc42195cf1aefcf03e21d6a6.tar.gz rockbox-b5716df4cb2837bbbc42195cf1aefcf03e21d6a6.tar.bz2 rockbox-b5716df4cb2837bbbc42195cf1aefcf03e21d6a6.tar.xz | |
Build librbcodec with DSP and metadata.
All associated files are moved to /lib/rbcodec.
Change-Id: I572ddd2b8a996aae1e98c081d06b1ed356dce222
Diffstat (limited to 'apps/metadata')
35 files changed, 0 insertions, 8297 deletions
diff --git a/apps/metadata/a52.c b/apps/metadata/a52.c deleted file mode 100644 index a8aad3f..0000000 --- a/apps/metadata/a52.c +++ /dev/null @@ -1,103 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include <stdio.h> -#include "metadata.h" -#include "logf.h" - -#include "metadata_parsers.h" - -static const unsigned short a52_bitrates[] = -{ - 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, - 192, 224, 256, 320, 384, 448, 512, 576, 640 -}; - -/* Only store frame sizes for 44.1KHz - others are simply multiples - of the bitrate */ -static const unsigned short a52_441framesizes[] = -{ - 69 * 2, 70 * 2, 87 * 2, 88 * 2, 104 * 2, 105 * 2, 121 * 2, - 122 * 2, 139 * 2, 140 * 2, 174 * 2, 175 * 2, 208 * 2, 209 * 2, - 243 * 2, 244 * 2, 278 * 2, 279 * 2, 348 * 2, 349 * 2, 417 * 2, - 418 * 2, 487 * 2, 488 * 2, 557 * 2, 558 * 2, 696 * 2, 697 * 2, - 835 * 2, 836 * 2, 975 * 2, 976 * 2, 1114 * 2, 1115 * 2, 1253 * 2, - 1254 * 2, 1393 * 2, 1394 * 2 -}; - -bool get_a52_metadata(int fd, struct mp3entry *id3) -{ - /* Use the trackname part of the id3 structure as a temporary buffer */ - unsigned char* buf = (unsigned char *)id3->path; - unsigned long totalsamples; - int i; - - if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 5) < 5)) - { - return false; - } - - if ((buf[0] != 0x0b) || (buf[1] != 0x77)) - { - logf("not an A52/AC3 file\n"); - return false; - } - - i = buf[4] & 0x3e; - - if (i > 36) - { - logf("A52: Invalid frmsizecod: %d\n",i); - return false; - } - - id3->bitrate = a52_bitrates[i >> 1]; - id3->vbr = false; - id3->filesize = filesize(fd); - - switch (buf[4] & 0xc0) - { - case 0x00: - id3->frequency = 48000; - id3->bytesperframe=id3->bitrate * 2 * 2; - break; - - case 0x40: - id3->frequency = 44100; - id3->bytesperframe = a52_441framesizes[i]; - break; - - case 0x80: - id3->frequency = 32000; - id3->bytesperframe = id3->bitrate * 3 * 2; - break; - - default: - logf("A52: Invalid samplerate code: 0x%02x\n", buf[4] & 0xc0); - return false; - break; - } - - /* One A52 frame contains 6 blocks, each containing 256 samples */ - totalsamples = id3->filesize / id3->bytesperframe * 6 * 256; - id3->length = totalsamples / id3->frequency * 1000; - return true; -} diff --git a/apps/metadata/adx.c b/apps/metadata/adx.c deleted file mode 100644 index 7c341b4..0000000 --- a/apps/metadata/adx.c +++ /dev/null @@ -1,124 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "debug.h" - -bool get_adx_metadata(int fd, struct mp3entry* id3) -{ - /* Use the trackname part of the id3 structure as a temporary buffer */ - unsigned char * buf = (unsigned char *)id3->path; - int chanstart, channels; - int looping = 0, start_adr = 0, end_adr = 0; - - /* try to get the basic header */ - if ((lseek(fd, 0, SEEK_SET) < 0) - || (read(fd, buf, 0x38) < 0x38)) - { - DEBUGF("lseek or read failed\n"); - return false; - } - - /* ADX starts with 0x80 */ - if (buf[0] != 0x80) { - DEBUGF("get_adx_metadata: wrong first byte %c\n",buf[0]); - return false; - } - - /* check for a reasonable offset */ - chanstart = ((buf[2] << 8) | buf[3]) + 4; - if (chanstart > 4096) { - DEBUGF("get_adx_metadata: bad chanstart %i\n", chanstart); - return false; - } - - /* check for a workable number of channels */ - channels = buf[7]; - if (channels != 1 && channels != 2) { - DEBUGF("get_adx_metadata: bad channel count %i\n",channels); - return false; - } - - id3->frequency = get_long_be(&buf[8]); - /* 32 samples per 18 bytes */ - id3->bitrate = id3->frequency * channels * 18 * 8 / 32 / 1000; - id3->length = get_long_be(&buf[12]) / id3->frequency * 1000; - id3->vbr = false; - id3->filesize = filesize(fd); - - /* get loop info */ - if (!memcmp(buf+0x10,"\x01\xF4\x03",3)) { - /* Soul Calibur 2 style (type 03) */ - DEBUGF("get_adx_metadata: type 03 found\n"); - /* check if header is too small for loop data */ - if (chanstart-6 < 0x2c) looping=0; - else { - looping = get_long_be(&buf[0x18]); - end_adr = get_long_be(&buf[0x28]); - start_adr = get_long_be(&buf[0x1c])/32*channels*18+chanstart; - } - } else if (!memcmp(buf+0x10,"\x01\xF4\x04",3)) { - /* Standard (type 04) */ - DEBUGF("get_adx_metadata: type 04 found\n"); - /* check if header is too small for loop data */ - if (chanstart-6 < 0x38) looping=0; - else { - looping = get_long_be(&buf[0x24]); - end_adr = get_long_be(&buf[0x34]); - start_adr = get_long_be(&buf[0x28])/32*channels*18+chanstart; - } - } else { - DEBUGF("get_adx_metadata: error, couldn't determine ADX type\n"); - return false; - } - - /* is file using encryption */ - if (buf[0x13]==0x08) { - DEBUGF("get_adx_metadata: error, encrypted ADX not supported\n"); - return false; - } - - if (looping) { - /* 2 loops, 10 second fade */ - id3->length = (start_adr-chanstart + 2*(end_adr-start_adr)) - *8 / id3->bitrate + 10000; - } - - /* try to get the channel header */ - if ((lseek(fd, chanstart-6, SEEK_SET) < 0) - || (read(fd, buf, 6) < 6)) - { - return false; - } - - /* check channel header */ - if (memcmp(buf, "(c)CRI", 6) != 0) return false; - - return true; -} diff --git a/apps/metadata/aiff.c b/apps/metadata/aiff.c deleted file mode 100644 index 654f37c..0000000 --- a/apps/metadata/aiff.c +++ /dev/null @@ -1,108 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" - -#include "debug.h" - -/* compressionType: AIFC QuickTime IMA ADPCM */ -#define AIFC_FORMAT_QT_IMA_ADPCM "ima4" - -bool get_aiff_metadata(int fd, struct mp3entry* id3) -{ - unsigned char buf[512]; - unsigned long numChannels = 0; - unsigned long numSampleFrames = 0; - unsigned long numbytes = 0; - bool is_aifc = false; - - if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, &buf[0], 12) < 12) || - (memcmp(&buf[0], "FORM", 4) != 0) || (memcmp(&buf[8], "AIF", 3) != 0) || - (!(is_aifc = (buf[11] == 'C')) && buf[11] != 'F')) - { - return false; - } - - while (read(fd, &buf[0], 8) == 8) - { - size_t size = get_long_be(&buf[4]); /* chunkSize */ - - if (memcmp(&buf[0], "SSND", 4) == 0) - { - numbytes = size - 8; - break; /* assume COMM was already read */ - } - - /* odd chunk sizes must be padded */ - size += size & 1; - - if (size > sizeof(buf)) - { - DEBUGF("AIFF \"%4.4s\" chunk too large (%zd > %zd)", - (char*) &buf[0], size, sizeof(buf)); - } - - if (memcmp(&buf[0], "COMM", 4) == 0) - { - if (size > sizeof(buf) || read(fd, &buf[0], size) != (ssize_t)size) - return false; - - numChannels = ((buf[0]<<8)|buf[1]); - - numSampleFrames = get_long_be(&buf[2]); - - /* sampleRate */ - id3->frequency = get_long_be(&buf[10]); - id3->frequency >>= (16+14-buf[9]); - - /* save format infos */ - id3->bitrate = ((buf[6]<<8)|buf[7]) * numChannels * id3->frequency; - id3->bitrate /= 1000; - - if (!is_aifc || memcmp(&buf[18], AIFC_FORMAT_QT_IMA_ADPCM, 4) != 0) - id3->length = ((int64_t) numSampleFrames * 1000) / id3->frequency; - else - { - /* QuickTime IMA ADPCM is 1block = 64 data for each channel */ - id3->length = ((int64_t) numSampleFrames * 64000LL) / id3->frequency; - } - - id3->vbr = false; /* AIFF files are CBR */ - id3->filesize = filesize(fd); - } - else - { - /* skip chunk */ - if (lseek(fd, size, SEEK_CUR) < 0) - return false; - } - } - - return numbytes && numChannels; -} diff --git a/apps/metadata/ape.c b/apps/metadata/ape.c deleted file mode 100644 index 0bd2477..0000000 --- a/apps/metadata/ape.c +++ /dev/null @@ -1,182 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "structec.h" - -#define APETAG_HEADER_LENGTH 32 -#define APETAG_HEADER_FORMAT "8llll8" -#define APETAG_ITEM_HEADER_FORMAT "ll" -#define APETAG_ITEM_TYPE_MASK 3 - -#ifdef HAVE_ALBUMART -/* The AA header consists of the pseudo filename "Album Cover (Front).ext" - * whereas ".ext" is the file extension. For now ".jpg" and ".png" are - * supported by this APE metadata parser. Therefore the length is 22. */ -#define APETAG_AA_HEADER_LENGTH 22 -#endif - -struct apetag_header -{ - char id[8]; - long version; - long length; - long item_count; - long flags; - char reserved[8]; -}; - -struct apetag_item_header -{ - long length; - long flags; -}; - -/* Read the items in an APEV2 tag. Only looks for a tag at the end of a - * file. Returns true if a tag was found and fully read, false otherwise. - */ -bool read_ape_tags(int fd, struct mp3entry* id3) -{ - struct apetag_header header; - - if ((lseek(fd, -APETAG_HEADER_LENGTH, SEEK_END) < 0) - || (ecread(fd, &header, 1, APETAG_HEADER_FORMAT, IS_BIG_ENDIAN) - != APETAG_HEADER_LENGTH) - || (memcmp(header.id, "APETAGEX", sizeof(header.id)))) - { - return false; - } - - if ((header.version == 2000) && (header.item_count > 0) - && (header.length > APETAG_HEADER_LENGTH)) - { - char *buf = id3->id3v2buf; - unsigned int buf_remaining = sizeof(id3->id3v2buf) - + sizeof(id3->id3v1buf); - unsigned int tag_remaining = header.length - APETAG_HEADER_LENGTH; - int i; - - if (lseek(fd, -header.length, SEEK_END) < 0) - { - return false; - } - - for (i = 0; i < header.item_count; i++) - { - struct apetag_item_header item; - char name[TAG_NAME_LENGTH]; - char value[TAG_VALUE_LENGTH]; - long r; - - if (tag_remaining < sizeof(item)) - { - break; - } - - if (ecread(fd, &item, 1, APETAG_ITEM_HEADER_FORMAT, IS_BIG_ENDIAN) - < (long) sizeof(item)) - { - return false; - } - - tag_remaining -= sizeof(item); - r = read_string(fd, name, sizeof(name), 0, tag_remaining); - - if (r == -1) - { - return false; - } - - tag_remaining -= r + item.length; - - if ((item.flags & APETAG_ITEM_TYPE_MASK) == 0) - { - long len; - - if (read_string(fd, value, sizeof(value), -1, item.length) - != item.length) - { - return false; - } - - len = parse_tag(name, value, id3, buf, buf_remaining, - TAGTYPE_APE); - buf += len; - buf_remaining -= len; - } - else - { -#ifdef HAVE_ALBUMART - if (strcasecmp(name, "cover art (front)") == 0) - { - /* Allow to read at least APETAG_AA_HEADER_LENGTH bytes. */ - r = read_string(fd, name, sizeof(name), 0, APETAG_AA_HEADER_LENGTH); - if (r == -1) - { - return false; - } - - /* Gather the album art format from the pseudo file name's ending. */ - strcpy(name, name + strlen(name) - 4); - id3->albumart.type = AA_TYPE_UNKNOWN; - if (strcasecmp(name, ".jpg") == 0) - { - id3->albumart.type = AA_TYPE_JPG; - } - else if (strcasecmp(name, ".png") == 0) - { - id3->albumart.type = AA_TYPE_PNG; - } - - /* Set the album art size and position. */ - if (id3->albumart.type != AA_TYPE_UNKNOWN) - { - id3->albumart.pos = lseek(fd, 0, SEEK_CUR); - id3->albumart.size = item.length - r; - id3->has_embedded_albumart = true; - } - - /* Seek back to this APE items begin. */ - if (lseek(fd, -r, SEEK_CUR) < 0) - { - return false; - } - } -#endif - /* Seek to the next APE item. */ - if (lseek(fd, item.length, SEEK_CUR) < 0) - { - return false; - } - } - } - } - - return true; -} diff --git a/apps/metadata/asap.c b/apps/metadata/asap.c deleted file mode 100644 index 9e7f227..0000000 --- a/apps/metadata/asap.c +++ /dev/null @@ -1,254 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2008 Dominik Wenger - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "rbunicode.h" -#include "debug.h" - -#define MAX_SONGS 32 - -static bool parse_dec(int *retval, const char *p, int minval, int maxval) -{ - int r = 0; - do { - char c = *p; - if (c >= '0' && c <= '9') - r = 10 * r + c - '0'; - else - return false; - if (r > maxval) - return false; - } while (*++p != '\0'); - if (r < minval) - return false; - *retval = r; - return true; -} - -static bool parse_text(char *retval, const char *p) -{ - int i; - if (*p != '"') - return false; - p++; - if (p[0] == '<' && p[1] == '?' && p[2] == '>' && p[3] == '"') - return true; - i = 0; - while (*p != '"') { - if (i >= 127) - return false; - if (*p == '\0') - return false; - retval[i++] = *p++; - } - retval[i] = '\0'; - return true; -} - -static int ASAP_ParseDuration(const char *s) -{ - int r; - if (*s < '0' || *s > '9') - return -1; - r = *s++ - '0'; - if (*s >= '0' && *s <= '9') - r = 10 * r + *s++ - '0'; - if (*s == ':') { - s++; - if (*s < '0' || *s > '5') - return -1; - r = 60 * r + (*s++ - '0') * 10; - if (*s < '0' || *s > '9') - return -1; - r += *s++ - '0'; - } - r *= 1000; - if (*s != '.') - return r; - s++; - if (*s < '0' || *s > '9') - return r; - r += 100 * (*s++ - '0'); - if (*s < '0' || *s > '9') - return r; - r += 10 * (*s++ - '0'); - if (*s < '0' || *s > '9') - return r; - r += *s - '0'; - return r; -} - -static bool read_asap_string(char* source, char** buf, char** buffer_end, char** dest) -{ - if(parse_text(*buf,source) == false) - return false; - - /* set dest pointer */ - *dest = *buf; - - /* move buf ptr */ - *buf += strlen(*buf)+1; - - /* check size */ - if(*buf >= *buffer_end) - { - DEBUGF("Buffer full\n"); - return false; - } - return true; -} - -static bool parse_sap_header(int fd, struct mp3entry* id3, int file_len) -{ - int module_index = 0; - int sap_signature = -1; - int duration_index = 0; - unsigned char cur_char = 0; - int i; - - /* set defaults */ - int numSongs = 1; - int defSong = 0; - int durations[MAX_SONGS]; - for (i = 0; i < MAX_SONGS; i++) - durations[i] = -1; - - /* use id3v2 buffer for our strings */ - char* buffer = id3->id3v2buf; - char* buffer_end = id3->id3v2buf + ID3V2_BUF_SIZE; - - /* parse file */ - while (1) - { - char line[256]; - char *p; - - if (module_index + 8 >= file_len) - return false; - /* read a char */ - read(fd,&cur_char,1); - /* end of header */ - if (cur_char == 0xff) - break; - - i = 0; - while (cur_char != 0x0d) - { - line[i++] = cur_char; - module_index++; - if (module_index >= file_len || (unsigned)i >= sizeof(line) - 1) - return false; - /* read a char */ - read(fd,&cur_char,1); - } - if (++module_index >= file_len ) - return false; - /* read a char */ - read(fd,&cur_char,1); - if ( cur_char != 0x0a) - return false; - - line[i] = '\0'; - for (p = line; *p != '\0'; p++) { - if (*p == ' ') { - *p++ = '\0'; - break; - } - } - - /* parse tags */ - if(strcmp(line, "SAP") == 0) - sap_signature = 1; - if (sap_signature == -1) - return false; - if (strcmp(line, "AUTHOR") == 0) - { - if(read_asap_string(p, &buffer, &buffer_end, &id3->artist) == false) - return false; - } - else if(strcmp(line, "NAME") == 0) - { - if(read_asap_string(p, &buffer, &buffer_end, &id3->title) == false) - return false; - } - else if(strcmp(line, "DATE") == 0) - { - if(read_asap_string(p, &buffer, &buffer_end, &id3->year_string) == false) - return false; - } - else if (strcmp(line, "SONGS") == 0) - { - if (parse_dec(&numSongs, p, 1, MAX_SONGS) == false ) - return false; - } - else if (strcmp(line, "DEFSONG") == 0) - { - if (parse_dec(&defSong, p, 0, MAX_SONGS) == false) - return false; - } - else if (strcmp(line, "TIME") == 0) - { - int durationTemp = ASAP_ParseDuration(p); - if (durationTemp < 0 || duration_index >= MAX_SONGS) - return false; - durations[duration_index++] = durationTemp; - } - } - - /* set length: */ - int length = durations[defSong]; - if (length < 0) - length = 180 * 1000; - id3->length = length; - - lseek(fd, 0, SEEK_SET); - return true; -} - - -bool get_asap_metadata(int fd, struct mp3entry* id3) -{ - - int filelength = filesize(fd); - - if(parse_sap_header(fd, id3, filelength) == false) - { - DEBUGF("parse sap header failed.\n"); - return false; - } - - id3->bitrate = 706; - id3->frequency = 44100; - - id3->vbr = false; - id3->filesize = filelength; - id3->genre_string = id3_get_num_genre(36); - - return true; -} diff --git a/apps/metadata/asf.c b/apps/metadata/asf.c deleted file mode 100644 index b815c09..0000000 --- a/apps/metadata/asf.c +++ /dev/null @@ -1,591 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * - * $Id$ - * - * Copyright (C) 2007 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "metadata.h" -#include "replaygain.h" -#include "debug.h" -#include "rbunicode.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "system.h" -#include <codecs/libasf/asf.h> - -/* TODO: Just read the GUIDs into a 16-byte array, and use memcmp to compare */ -struct guid_s { - uint32_t v1; - uint16_t v2; - uint16_t v3; - uint8_t v4[8]; -}; -typedef struct guid_s guid_t; - -struct asf_object_s { - guid_t guid; - uint64_t size; - uint64_t datalen; -}; -typedef struct asf_object_s asf_object_t; - -static const guid_t asf_guid_null = -{0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - -/* top level object guids */ - -static const guid_t asf_guid_header = -{0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}}; - -static const guid_t asf_guid_data = -{0x75B22636, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}}; - -static const guid_t asf_guid_index = -{0x33000890, 0xE5B1, 0x11CF, {0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}}; - -/* header level object guids */ - -static const guid_t asf_guid_file_properties = -{0x8cabdca1, 0xa947, 0x11cf, {0x8E, 0xe4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}}; - -static const guid_t asf_guid_stream_properties = -{0xB7DC0791, 0xA9B7, 0x11CF, {0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}}; - -static const guid_t asf_guid_content_description = -{0x75B22633, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}}; - -static const guid_t asf_guid_extended_content_description = -{0xD2D0A440, 0xE307, 0x11D2, {0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50}}; - -static const guid_t asf_guid_content_encryption = -{0x2211b3fb, 0xbd23, 0x11d2, {0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e}}; - -static const guid_t asf_guid_extended_content_encryption = -{0x298ae614, 0x2622, 0x4c17, {0xb9, 0x35, 0xda, 0xe0, 0x7e, 0xe9, 0x28, 0x9c}}; - -/* stream type guids */ - -static const guid_t asf_guid_stream_type_audio = -{0xF8699E40, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}}; - -static int asf_guid_match(const guid_t *guid1, const guid_t *guid2) -{ - if((guid1->v1 != guid2->v1) || - (guid1->v2 != guid2->v2) || - (guid1->v3 != guid2->v3) || - (memcmp(guid1->v4, guid2->v4, 8))) { - return 0; - } - - return 1; -} - -/* Read the 16 byte GUID from a file */ -static void asf_readGUID(int fd, guid_t* guid) -{ - read_uint32le(fd, &guid->v1); - read_uint16le(fd, &guid->v2); - read_uint16le(fd, &guid->v3); - read(fd, guid->v4, 8); -} - -static void asf_read_object_header(asf_object_t *obj, int fd) -{ - asf_readGUID(fd, &obj->guid); - read_uint64le(fd, &obj->size); - obj->datalen = 0; -} - -/* Parse an integer from the extended content object - we always - convert to an int, regardless of native format. -*/ -static int asf_intdecode(int fd, int type, int length) -{ - uint16_t tmp16; - uint32_t tmp32; - uint64_t tmp64; - - if (type == 3) { - read_uint32le(fd, &tmp32); - lseek(fd,length - 4,SEEK_CUR); - return (int)tmp32; - } else if (type == 4) { - read_uint64le(fd, &tmp64); - lseek(fd,length - 8,SEEK_CUR); - return (int)tmp64; - } else if (type == 5) { - read_uint16le(fd, &tmp16); - lseek(fd,length - 2,SEEK_CUR); - return (int)tmp16; - } - - return 0; -} - -/* Decode a LE utf16 string from a disk buffer into a fixed-sized - utf8 buffer. -*/ - -static void asf_utf16LEdecode(int fd, - uint16_t utf16bytes, - unsigned char **utf8, - int* utf8bytes - ) -{ - unsigned long ucs; - int n; - unsigned char utf16buf[256]; - unsigned char* utf16 = utf16buf; - unsigned char* newutf8; - - n = read(fd, utf16buf, MIN(sizeof(utf16buf), utf16bytes)); - utf16bytes -= n; - - while (n > 0) { - /* Check for a surrogate pair */ - if (utf16[1] >= 0xD8 && utf16[1] < 0xE0) { - if (n < 4) { - /* Run out of utf16 bytes, read some more */ - utf16buf[0] = utf16[0]; - utf16buf[1] = utf16[1]; - - n = read(fd, utf16buf + 2, MIN(sizeof(utf16buf)-2, utf16bytes)); - utf16 = utf16buf; - utf16bytes -= n; - n += 2; - } - - if (n < 4) { - /* Truncated utf16 string, abort */ - break; - } - ucs = 0x10000 + ((utf16[0] << 10) | ((utf16[1] - 0xD8) << 18) - | utf16[2] | ((utf16[3] - 0xDC) << 8)); - utf16 += 4; - n -= 4; - } else { - ucs = (utf16[0] | (utf16[1] << 8)); - utf16 += 2; - n -= 2; - } - - if (*utf8bytes > 6) { - newutf8 = utf8encode(ucs, *utf8); - *utf8bytes -= (newutf8 - *utf8); - *utf8 += (newutf8 - *utf8); - } - - /* We have run out of utf16 bytes, read more if available */ - if ((n == 0) && (utf16bytes > 0)) { - n = read(fd, utf16buf, MIN(sizeof(utf16buf), utf16bytes)); - utf16 = utf16buf; - utf16bytes -= n; - } - } - - *utf8[0] = 0; - --*utf8bytes; - - if (utf16bytes > 0) { - /* Skip any remaining bytes */ - lseek(fd, utf16bytes, SEEK_CUR); - } - return; -} - -static int asf_parse_header(int fd, struct mp3entry* id3, - asf_waveformatex_t* wfx) -{ - asf_object_t current; - asf_object_t header; - uint64_t datalen; - int i; - int fileprop = 0; - uint64_t play_duration; - uint16_t flags; - uint32_t subobjects; - uint8_t utf8buf[512]; - int id3buf_remaining = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf); - unsigned char* id3buf = (unsigned char*)id3->id3v2buf; - - asf_read_object_header((asf_object_t *) &header, fd); - - //DEBUGF("header.size=%d\n",(int)header.size); - if (header.size < 30) { - /* invalid size for header object */ - return ASF_ERROR_OBJECT_SIZE; - } - - read_uint32le(fd, &subobjects); - - /* Two reserved bytes - do we need to read them? */ - lseek(fd, 2, SEEK_CUR); - - //DEBUGF("Read header - size=%d, subobjects=%d\n",(int)header.size, (int)subobjects); - - if (subobjects > 0) { - header.datalen = header.size - 30; - - /* TODO: Check that we have datalen bytes left in the file */ - datalen = header.datalen; - - for (i=0; i<(int)subobjects; i++) { - //DEBUGF("Parsing header object %d - datalen=%d\n",i,(int)datalen); - if (datalen < 24) { - //DEBUGF("not enough data for reading object\n"); - break; - } - - asf_read_object_header(¤t, fd); - - if (current.size > datalen || current.size < 24) { - //DEBUGF("invalid object size - current.size=%d, datalen=%d\n",(int)current.size,(int)datalen); - break; - } - - if (asf_guid_match(¤t.guid, &asf_guid_file_properties)) { - if (current.size < 104) - return ASF_ERROR_OBJECT_SIZE; - - if (fileprop) { - /* multiple file properties objects not allowed */ - return ASF_ERROR_INVALID_OBJECT; - } - - fileprop = 1; - - /* Get the number of logical packets - uint16_t at offset 31 - * (Big endian byte order) */ - lseek(fd, 31, SEEK_CUR); - read_uint16be(fd, &wfx->numpackets); - - /* Now get the play duration - uint64_t at offset 40 */ - lseek(fd, 7, SEEK_CUR); - read_uint64le(fd, &play_duration); - id3->length = play_duration / 10000; - - //DEBUGF("****** length = %lums\n", id3->length); - - /* Read the packet size - uint32_t at offset 68 */ - lseek(fd, 20, SEEK_CUR); - read_uint32le(fd, &wfx->packet_size); - - /* Skip bytes remaining in object */ - lseek(fd, current.size - 24 - 72, SEEK_CUR); - } else if (asf_guid_match(¤t.guid, &asf_guid_stream_properties)) { - guid_t guid; - uint32_t propdatalen; - - if (current.size < 78) - return ASF_ERROR_OBJECT_SIZE; - -#if 0 - asf_byteio_getGUID(&guid, current->data); - datalen = asf_byteio_getDWLE(current->data + 40); - flags = asf_byteio_getWLE(current->data + 48); -#endif - - asf_readGUID(fd, &guid); - - lseek(fd, 24, SEEK_CUR); - read_uint32le(fd, &propdatalen); - lseek(fd, 4, SEEK_CUR); - read_uint16le(fd, &flags); - - if (!asf_guid_match(&guid, &asf_guid_stream_type_audio)) { - //DEBUGF("Found stream properties for non audio stream, skipping\n"); - lseek(fd,current.size - 24 - 50,SEEK_CUR); - } else if (wfx->audiostream == -1) { - lseek(fd, 4, SEEK_CUR); - //DEBUGF("Found stream properties for audio stream %d\n",flags&0x7f); - - if (propdatalen < 18) { - return ASF_ERROR_INVALID_LENGTH; - } - -#if 0 - if (asf_byteio_getWLE(data + 16) > datalen - 16) { - return ASF_ERROR_INVALID_LENGTH; - } -#endif - read_uint16le(fd, &wfx->codec_id); - read_uint16le(fd, &wfx->channels); - read_uint32le(fd, &wfx->rate); - read_uint32le(fd, &wfx->bitrate); - wfx->bitrate *= 8; - read_uint16le(fd, &wfx->blockalign); - read_uint16le(fd, &wfx->bitspersample); - read_uint16le(fd, &wfx->datalen); - - /* Round bitrate to the nearest kbit */ - id3->bitrate = (wfx->bitrate + 500) / 1000; - id3->frequency = wfx->rate; - - if (wfx->codec_id == ASF_CODEC_ID_WMAV1) { - read(fd, wfx->data, 4); - lseek(fd,current.size - 24 - 72 - 4,SEEK_CUR); - wfx->audiostream = flags&0x7f; - } else if (wfx->codec_id == ASF_CODEC_ID_WMAV2) { - read(fd, wfx->data, 6); - lseek(fd,current.size - 24 - 72 - 6,SEEK_CUR); - wfx->audiostream = flags&0x7f; - } else if (wfx->codec_id == ASF_CODEC_ID_WMAPRO) { - /* wma pro decoder needs the extra-data */ - read(fd, wfx->data, wfx->datalen); - lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR); - wfx->audiostream = flags&0x7f; - /* Correct codectype to redirect playback to the proper .codec */ - id3->codectype = AFMT_WMAPRO; - } else if (wfx->codec_id == ASF_CODEC_ID_WMAVOICE) { - read(fd, wfx->data, wfx->datalen); - lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR); - wfx->audiostream = flags&0x7f; - id3->codectype = AFMT_WMAVOICE; - } else { - DEBUGF("Unsupported WMA codec (Lossless, Voice, etc)\n"); - lseek(fd,current.size - 24 - 72,SEEK_CUR); - } - - } - } else if (asf_guid_match(¤t.guid, &asf_guid_content_description)) { - /* Object contains five 16-bit string lengths, followed by the five strings: - title, artist, copyright, description, rating - */ - uint16_t strlength[5]; - int i; - - //DEBUGF("Found GUID_CONTENT_DESCRIPTION - size=%d\n",(int)(current.size - 24)); - - /* Read the 5 string lengths - number of bytes included trailing zero */ - for (i=0; i<5; i++) { - read_uint16le(fd, &strlength[i]); - //DEBUGF("strlength = %u\n",strlength[i]); - } - - if (strlength[0] > 0) { /* 0 - Title */ - id3->title = id3buf; - asf_utf16LEdecode(fd, strlength[0], &id3buf, &id3buf_remaining); - } - - if (strlength[1] > 0) { /* 1 - Artist */ - id3->artist = id3buf; - asf_utf16LEdecode(fd, strlength[1], &id3buf, &id3buf_remaining); - } - - lseek(fd, strlength[2], SEEK_CUR); /* 2 - copyright */ - - if (strlength[3] > 0) { /* 3 - description */ - id3->comment = id3buf; - asf_utf16LEdecode(fd, strlength[3], &id3buf, &id3buf_remaining); - } - - lseek(fd, strlength[4], SEEK_CUR); /* 4 - rating */ - } else if (asf_guid_match(¤t.guid, &asf_guid_extended_content_description)) { - uint16_t count; - int i; - int bytesleft = current.size - 24; - //DEBUGF("Found GUID_EXTENDED_CONTENT_DESCRIPTION\n"); - - read_uint16le(fd, &count); - bytesleft -= 2; - //DEBUGF("extended metadata count = %u\n",count); - - for (i=0; i < count; i++) { - uint16_t length, type; - unsigned char* utf8 = utf8buf; - int utf8length = 512; - - read_uint16le(fd, &length); - asf_utf16LEdecode(fd, length, &utf8, &utf8length); - bytesleft -= 2 + length; - - read_uint16le(fd, &type); - read_uint16le(fd, &length); - - if (!strcmp("WM/TrackNumber",utf8buf)) { - if (type == 0) { - id3->track_string = id3buf; - asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining); - id3->tracknum = atoi(id3->track_string); - } else if ((type >=2) && (type <= 5)) { - id3->tracknum = asf_intdecode(fd, type, length); - } else { - lseek(fd, length, SEEK_CUR); - } - } else if ((!strcmp("WM/Genre", utf8buf)) && (type == 0)) { - id3->genre_string = id3buf; - asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining); - } else if ((!strcmp("WM/AlbumTitle", utf8buf)) && (type == 0)) { - id3->album = id3buf; - asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining); - } else if ((!strcmp("WM/AlbumArtist", utf8buf)) && (type == 0)) { - id3->albumartist = id3buf; - asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining); - } else if ((!strcmp("WM/Composer", utf8buf)) && (type == 0)) { - id3->composer = id3buf; - asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining); - } else if (!strcmp("WM/Year", utf8buf)) { - if (type == 0) { - id3->year_string = id3buf; - asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining); - id3->year = atoi(id3->year_string); - } else if ((type >=2) && (type <= 5)) { - id3->year = asf_intdecode(fd, type, length); - } 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)) { - id3->mb_track_id = id3buf; - asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining); -#ifdef HAVE_ALBUMART - } else if (!strcmp("WM/Picture", utf8buf)) { - uint32_t datalength, strlength; - /* Expected is either "01 00 xx xx 03 yy yy yy yy" or - * "03 yy yy yy yy". xx is the size of the WM/Picture - * container in bytes. yy equals the raw data length of - * the embedded image. */ - lseek(fd, -4, SEEK_CUR); - read(fd, &type, 1); - if (type == 1) { - lseek(fd, 3, SEEK_CUR); - read(fd, &type, 1); - /* In case the parsing will fail in the next step we - * might at least be able to skip the whole section. */ - datalength = length - 1; - } - if (type == 3) { - /* Read the raw data length of the embedded image. */ - read_uint32le(fd, &datalength); - - /* Reset utf8 buffer */ - utf8 = utf8buf; - utf8length = 512; - - /* Gather the album art format, this string has a - * double zero-termination. */ - asf_utf16LEdecode(fd, 32, &utf8, &utf8length); - strlength = (strlen(utf8buf) + 2) * 2; - lseek(fd, strlength-32, SEEK_CUR); - if (!strcmp("image/jpeg", utf8buf)) { - id3->albumart.type = AA_TYPE_JPG; - } else if (!strcmp("image/png", utf8buf)) { - id3->albumart.type = AA_TYPE_PNG; - } else { - id3->albumart.type = AA_TYPE_UNKNOWN; - } - - /* Set the album art size and position. */ - if (id3->albumart.type != AA_TYPE_UNKNOWN) { - id3->albumart.pos = lseek(fd, 0, SEEK_CUR); - id3->albumart.size = datalength; - id3->has_embedded_albumart = true; - } - } - - lseek(fd, datalength, SEEK_CUR); -#endif - } else { - lseek(fd, length, SEEK_CUR); - } - bytesleft -= 4 + length; - } - - lseek(fd, bytesleft, SEEK_CUR); - } else if (asf_guid_match(¤t.guid, &asf_guid_content_encryption) - || asf_guid_match(¤t.guid, &asf_guid_extended_content_encryption)) { - //DEBUGF("File is encrypted\n"); - return ASF_ERROR_ENCRYPTED; - } else { - //DEBUGF("Skipping %d bytes of object\n",(int)(current.size - 24)); - lseek(fd,current.size - 24,SEEK_CUR); - } - - //DEBUGF("Parsed object - size = %d\n",(int)current.size); - datalen -= current.size; - } - - if (i != (int)subobjects || datalen != 0) { - //DEBUGF("header data doesn't match given subobject count\n"); - return ASF_ERROR_INVALID_VALUE; - } - - //DEBUGF("%d subobjects read successfully\n", i); - } - -#if 0 - tmp = asf_parse_header_validate(file, &header); - if (tmp < 0) { - /* header read ok but doesn't validate correctly */ - return tmp; - } -#endif - - //DEBUGF("header validated correctly\n"); - - return 0; -} - -bool get_asf_metadata(int fd, struct mp3entry* id3) -{ - int res; - asf_object_t obj; - asf_waveformatex_t wfx; - - wfx.audiostream = -1; - - res = asf_parse_header(fd, id3, &wfx); - - if (res < 0) { - DEBUGF("ASF: parsing error - %d\n",res); - return false; - } - - if (wfx.audiostream == -1) { - DEBUGF("ASF: No WMA streams found\n"); - return false; - } - - asf_read_object_header(&obj, fd); - - if (!asf_guid_match(&obj.guid, &asf_guid_data)) { - DEBUGF("ASF: No data object found\n"); - return false; - } - - /* Store the current file position - no need to parse the header - again in the codec. The +26 skips the rest of the data object - header. - */ - id3->first_frame_offset = lseek(fd, 0, SEEK_CUR) + 26; - id3->filesize = filesize(fd); - /* We copy the wfx struct to the MP3 TOC field in the id3 struct so - the codec doesn't need to parse the header object again */ - memcpy(id3->toc, &wfx, sizeof(wfx)); - - return true; -} diff --git a/apps/metadata/au.c b/apps/metadata/au.c deleted file mode 100644 index 94e7453..0000000 --- a/apps/metadata/au.c +++ /dev/null @@ -1,105 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2010 Yoshihisa Uchida - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "logf.h" - -static const unsigned char bitspersamples[9] = { - 0, /* encoding */ - 8, /* 1: G.711 MULAW */ - 8, /* 2: Linear PCM 8bit */ - 16, /* 3: Linear PCM 16bit */ - 24, /* 4: Linear PCM 24bit */ - 32, /* 5: Linear PCM 32bit */ - 32, /* 6: IEEE float 32bit */ - 64, /* 7: IEEE float 64bit */ - /* encoding 8 - 26 unsupported. */ - 8, /* 27: G.711 ALAW */ -}; - -static inline unsigned char get_au_bitspersample(unsigned int encoding) -{ - if (encoding < 8) - return bitspersamples[encoding]; - else if (encoding == 27) - return bitspersamples[8]; - - return 0; -} - -bool get_au_metadata(int fd, struct mp3entry* id3) -{ - /* temporary buffer */ - unsigned char* buf = (unsigned char *)id3->path; - unsigned long numbytes = 0; - int offset; - - id3->vbr = false; /* All Sun audio files are CBR */ - id3->filesize = filesize(fd); - id3->length = 0; - - lseek(fd, 0, SEEK_SET); - if ((read(fd, buf, 24) < 24) || (memcmp(buf, ".snd", 4) != 0)) - { - /* - * no header - * - * frequency: 8000 Hz - * bits per sample: 8 bit - * channel: mono - */ - numbytes = id3->filesize; - id3->frequency = 8000; - id3->bitrate = 8; - } - else - { - /* parse header */ - - /* data offset */ - offset = get_long_be(buf + 4); - if (offset < 24) - { - DEBUGF("CODEC_ERROR: sun audio offset size is small: %d\n", offset); - return false; - } - /* data size */ - numbytes = get_long_be(buf + 8); - if (numbytes == (uint32_t)0xffffffff) - numbytes = id3->filesize - offset; - - id3->frequency = get_long_be(buf + 16); - id3->bitrate = get_au_bitspersample(get_long_be(buf + 12)) * get_long_be(buf + 20) - * id3->frequency / 1000; - } - - /* Calculate track length [ms] */ - if (id3->bitrate) - id3->length = (numbytes << 3) / id3->bitrate; - - return true; -} diff --git a/apps/metadata/ay.c b/apps/metadata/ay.c deleted file mode 100644 index 5d00264..0000000 --- a/apps/metadata/ay.c +++ /dev/null @@ -1,148 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "rbunicode.h" - -/* Taken from blargg's Game_Music_Emu library */ - -typedef unsigned char byte; - -/* AY file header */ -enum { header_size = 0x14 }; -struct header_t -{ - byte tag[8]; - byte vers; - byte player; - byte unused[2]; - byte author[2]; - byte comment[2]; - byte max_track; - byte first_track; - byte track_info[2]; -}; - -struct file_t { - struct header_t const* header; - byte const* tracks; - byte const* end; /* end of file data */ -}; - -static int get_be16( const void *a ) -{ - return get_short_be( (void*) a ); -} - -/* Given pointer to 2-byte offset of data, returns pointer to data, or NULL if - * offset is 0 or there is less than min_size bytes of data available. */ -static byte const* get_data( struct file_t const* file, byte const ptr [], int min_size ) -{ - int offset = (int16_t) get_be16( ptr ); - int pos = ptr - (byte const*) file->header; - int size = file->end - (byte const*) file->header; - int limit = size - min_size; - if ( limit < 0 || !offset || (unsigned) (pos + offset) > (unsigned) limit ) - return NULL; - return ptr + offset; -} - -static const char *parse_header( byte const in [], int size, struct file_t* out ) -{ - if ( size < header_size ) - return "wrong file type"; - - out->header = (struct header_t const*) in; - out->end = in + size; - struct header_t const* h = (struct header_t const*) in; - if ( memcmp( h->tag, "ZXAYEMUL", 8 ) ) - return "wrong file type"; - - out->tracks = get_data( out, h->track_info, (h->max_track + 1) * 4 ); - if ( !out->tracks ) - return "missing track data"; - - return 0; -} - -static void copy_ay_fields( struct file_t const* file, struct mp3entry* id3, int track ) -{ - int track_count = file->header->max_track + 1; - - /* calculate track length based on number of subtracks */ - if (track_count > 1) { - id3->length = file->header->max_track * 1000; - } else { - byte const* track_info = get_data( file, file->tracks + track * 4 + 2, 6 ); - if (track_info) - id3->length = get_be16( track_info + 4 ) * (1000 / 50); /* frames to msec */ - else id3->length = 120 * 1000; - } - - if ( id3->length <= 0 ) - id3->length = 120 * 1000; /* 2 minutes */ - - /* If meta info was found in the m3u skip next step */ - if (id3->title && id3->title[0]) return; - - /* If file has more than one track will - use file name as title */ - char * tmp; - if (track_count <= 1) { - tmp = (char *) get_data( file, file->tracks + track * 4, 1 ); - if ( tmp ) id3->title = tmp; - } - - /* Author */ - tmp = (char *) get_data( file, file->header->author, 1 ); - if (tmp) id3->artist = tmp; - - /* Comment */ - tmp = (char *) get_data( file, file->header->comment, 1 ); - if (tmp) id3->comment = tmp; -} - -static bool parse_ay_header(int fd, struct mp3entry *id3) -{ - /* Use the trackname part of the id3 structure as a temporary buffer */ - unsigned char* buf = (unsigned char *)id3->id3v2buf; - struct file_t file; - int read_bytes; - - lseek(fd, 0, SEEK_SET); - if ((read_bytes = read(fd, buf, ID3V2_BUF_SIZE)) < header_size) - return false; - - buf [ID3V2_BUF_SIZE] = '\0'; - if ( parse_header( buf, read_bytes, &file ) ) - return false; - - copy_ay_fields( &file, id3, 0 ); - return true; -} - -bool get_ay_metadata(int fd, struct mp3entry* id3) -{ - char ay_type[8]; - if ((lseek(fd, 0, SEEK_SET) < 0) || - read(fd, ay_type, 8) < 8) - return false; - - id3->vbr = false; - id3->filesize = filesize(fd); - - id3->bitrate = 706; - id3->frequency = 44100; - - /* Make sure this is a ZX Ay file */ - if (memcmp( ay_type, "ZXAYEMUL", 8 ) != 0) - return false; - - return parse_ay_header(fd, id3); -} diff --git a/apps/metadata/flac.c b/apps/metadata/flac.c deleted file mode 100644 index 2993717..0000000 --- a/apps/metadata/flac.c +++ /dev/null @@ -1,127 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "logf.h" - -bool get_flac_metadata(int fd, struct mp3entry* id3) -{ - /* A simple parser to read vital metadata from a FLAC file - length, - * frequency, bitrate etc. This code should either be moved to a - * seperate file, or discarded in favour of the libFLAC code. - * The FLAC stream specification can be found at - * http://flac.sourceforge.net/format.html#stream - */ - - /* Use the trackname part of the id3 structure as a temporary buffer */ - unsigned char* buf = (unsigned char *)id3->path; - bool last_metadata = false; - bool rc = false; - - if (!skip_id3v2(fd, id3) || (read(fd, buf, 4) < 4)) - { - return rc; - } - - if (memcmp(buf, "fLaC", 4) != 0) - { - return rc; - } - - while (!last_metadata) - { - unsigned long i; - int type; - - if (read(fd, buf, 4) < 0) - { - return rc; - } - - last_metadata = buf[0] & 0x80; - type = buf[0] & 0x7f; - /* The length of the block */ - i = (buf[1] << 16) | (buf[2] << 8) | buf[3]; - - if (type == 0) /* 0 is the STREAMINFO block */ - { - unsigned long totalsamples; - - if (i >= sizeof(id3->path) || read(fd, buf, i) < 0) - { - return rc; - } - - id3->vbr = true; /* All FLAC files are VBR */ - id3->filesize = filesize(fd); - id3->frequency = (buf[10] << 12) | (buf[11] << 4) - | ((buf[12] & 0xf0) >> 4); - rc = true; /* Got vital metadata */ - - /* totalsamples is a 36-bit field, but we assume <= 32 bits are used */ - totalsamples = get_long_be(&buf[14]); - - if(totalsamples > 0) - { - /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */ - id3->length = ((int64_t) totalsamples * 1000) / id3->frequency; - id3->bitrate = (id3->filesize * 8) / id3->length; - } - else if (totalsamples == 0) - { - id3->length = 0; - id3->bitrate = 0; - } - else - { - logf("flac length invalid!"); - return false; - } - - } - else if (type == 4) /* 4 is the VORBIS_COMMENT block */ - { - /* The next i bytes of the file contain the VORBIS COMMENTS. */ - if (read_vorbis_tags(fd, id3, i) == 0) - { - return rc; - } - } - else if (!last_metadata) - { - /* Skip to next metadata block */ - if (lseek(fd, i, SEEK_CUR) < 0) - { - return rc; - } - } - } - - return true; -} diff --git a/apps/metadata/gbs.c b/apps/metadata/gbs.c deleted file mode 100644 index 68f2b2a..0000000 --- a/apps/metadata/gbs.c +++ /dev/null @@ -1,65 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "rbunicode.h" - -static bool parse_gbs_header(int fd, struct mp3entry* id3) -{ - /* Use the trackname part of the id3 structure as a temporary buffer */ - unsigned char* buf = (unsigned char *)id3->path; - lseek(fd, 0, SEEK_SET); - if (read(fd, buf, 112) < 112) - return false; - - /* Calculate track length with number of subtracks */ - id3->length = buf[4] * 1000; - - /* If meta info was found in the m3u skip next step */ - if (id3->title && id3->title[0]) return true; - - char *p = id3->id3v2buf; - - /* Some metadata entries have 32 bytes length */ - /* Game */ - memcpy(p, &buf[16], 32); *(p + 33) = '\0'; - id3->title = p; - p += strlen(p)+1; - - /* Artist */ - memcpy(p, &buf[48], 32); *(p + 33) = '\0'; - id3->artist = p; - p += strlen(p)+1; - - /* Copyright */ - memcpy(p, &buf[80], 32); *(p + 33) = '\0'; - id3->album = p; - - return true; -} - -bool get_gbs_metadata(int fd, struct mp3entry* id3) -{ - char gbs_type[3]; - if ((lseek(fd, 0, SEEK_SET) < 0) || - (read(fd, gbs_type, 3) < 3)) - return false; - - id3->vbr = false; - id3->filesize = filesize(fd); - /* we only render 16 bits, 44.1KHz, Stereo */ - id3->bitrate = 706; - id3->frequency = 44100; - - /* Check for GBS magic */ - if (memcmp( gbs_type, "GBS", 3 ) != 0) - return false; - - return parse_gbs_header(fd, id3); -} diff --git a/apps/metadata/hes.c b/apps/metadata/hes.c deleted file mode 100644 index 6d99d52..0000000 --- a/apps/metadata/hes.c +++ /dev/null @@ -1,39 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "rbunicode.h" -#include "plugin.h" - -bool get_hes_metadata(int fd, struct mp3entry* id3) -{ - /* Use the id3v2 buffer part of the id3 structure as a temporary buffer */ - unsigned char* buf = (unsigned char *)id3->id3v2buf; - int read_bytes; - - if ((lseek(fd, 0, SEEK_SET) < 0) - || ((read_bytes = read(fd, buf, 4)) < 4)) - return false; - - /* Verify this is a HES file */ - if (memcmp(buf,"HESM",4) != 0) - return false; - - id3->vbr = false; - id3->filesize = filesize(fd); - /* we only render 16 bits, 44.1KHz, Stereo */ - id3->bitrate = 706; - id3->frequency = 44100; - - /* Set default track count (length)*/ - id3->length = 255 * 1000; - - return true; -} - diff --git a/apps/metadata/id3tags.c b/apps/metadata/id3tags.c deleted file mode 100644 index 2dd1c66..0000000 --- a/apps/metadata/id3tags.c +++ /dev/null @@ -1,1199 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 by Daniel Stenberg - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -/* - * Parts of this code has been stolen from the Ample project and was written - * by David H�deman. It has since been extended and enhanced pretty much by - * all sorts of friendly Rockbox people. - * - */ - - /* tagResolver and associated code copyright 2003 Thomas Paul Diffenbach - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <stdbool.h> -#include <stddef.h> -#include <ctype.h> -#include "string-extra.h" -#include "config.h" -#include "file.h" -#include "logf.h" -#include "system.h" -#include "replaygain.h" -#include "rbunicode.h" - -#include "metadata.h" -#include "mp3data.h" -#if CONFIG_CODEC == SWCODEC -#include "metadata_common.h" -#endif -#include "metadata_parsers.h" -#include "misc.h" - -static unsigned long unsync(unsigned long b0, - unsigned long b1, - unsigned long b2, - unsigned long b3) -{ - return (((long)(b0 & 0x7F) << (3*7)) | - ((long)(b1 & 0x7F) << (2*7)) | - ((long)(b2 & 0x7F) << (1*7)) | - ((long)(b3 & 0x7F) << (0*7))); -} - -static const char* const genres[] = { - "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", - "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", - "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", - "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", - "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", - "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", - "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", - "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", - "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", - "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", - "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", - "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", - "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", - - /* winamp extensions */ - "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", - "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", - "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", - "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", - "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", - "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", - "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", - "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall", - "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie", - "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap", - "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian", - "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "Jpop", - "Synthpop" -}; - -#if CONFIG_CODEC != SWCODEC -static -#endif -char* id3_get_num_genre(unsigned int genre_num) -{ - if (genre_num < ARRAYLEN(genres)) - return (char*)genres[genre_num]; - return NULL; -} - -/* - HOW TO ADD ADDITIONAL ID3 VERSION 2 TAGS - Code and comments by Thomas Paul Diffenbach - - To add another ID3v2 Tag, do the following: - 1. add a char* named for the tag to struct mp3entry in id3.h, - (I (tpd) prefer to use char* rather than ints, even for what seems like - numerical values, for cases where a number won't do, e.g., - YEAR: "circa 1765", "1790/1977" (composed/performed), "28 Feb 1969" - TRACK: "1/12", "1 of 12", GENRE: "Freeform genre name" - Text is more flexible, and as the main use of id3 data is to - display it, converting it to an int just means reconverting to - display it, at a runtime cost.) - - 2. If any special processing beyond copying the tag value from the Id3 - block to the struct mp3entry is rrequired (such as converting to an - int), write a function to perform this special processing. - - This function's prototype must match that of - typedef tagPostProcessFunc, that is it must be: - int func( struct mp3entry*, char* tag, int bufferpos ) - the first argument is a pointer to the current mp3entry structure the - second argument is a pointer to the null terminated string value of the - tag found the third argument is the offset of the next free byte in the - mp3entry's buffer your function should return the corrected offset; if - you don't lengthen or shorten the tag string, you can return the third - argument unchanged. - - Unless you have a good reason no to, make the function static. - TO JUST COPY THE TAG NO SPECIAL PROCESSING FUNCTION IS NEEDED. - - 3. add one or more entries to the tagList array, using the format: - char* ID3 Tag symbolic name -- see the ID3 specification for these, - sizeof() that name minus 1, - offsetof( struct mp3entry, variable_name_in_struct_mp3entry ), - pointer to your special processing function or NULL - if you need no special processing - flag indicating if this tag is binary or textual - Many ID3 symbolic names come in more than one form. You can add both - forms, each referencing the same variable in struct mp3entry. - If both forms are present, the last found will be used. - Note that the offset can be zero, in which case no entry will be set - in the mp3entry struct; the frame is still read into the buffer and - the special processing function is called (several times, if there - are several frames with the same name). - - 4. Alternately, use the TAG_LIST_ENTRY macro with - ID3 tag symbolic name, - variable in struct mp3entry, - special processing function address - - 5. Add code to wps-display.c function get_tag to assign a printf-like - format specifier for the tag */ - -/* Structure for ID3 Tag extraction information */ -struct tag_resolver { - const char* tag; - int tag_length; - size_t offset; - int (*ppFunc)(struct mp3entry*, char* tag, int bufferpos); - bool binary; -}; - -static bool global_ff_found; - -static int unsynchronize(char* tag, int len, bool *ff_found) -{ - int i; - unsigned char c; - unsigned char *rp, *wp; - - wp = rp = (unsigned char *)tag; - - rp = (unsigned char *)tag; - for(i = 0;i < len;i++) { - /* Read the next byte and write it back, but don't increment the - write pointer */ - c = *rp++; - *wp = c; - if(*ff_found) { - /* Increment the write pointer if it isn't an unsynch pattern */ - if(c != 0) - wp++; - *ff_found = false; - } else { - if(c == 0xff) - *ff_found = true; - wp++; - } - } - return (long)wp - (long)tag; -} - -static int unsynchronize_frame(char* tag, int len) -{ - bool ff_found = false; - - return unsynchronize(tag, len, &ff_found); -} - -static int read_unsynched(int fd, void *buf, int len) -{ - int i; - int rc; - int remaining = len; - char *wp; - char *rp; - - wp = buf; - - while(remaining) { - rp = wp; - rc = read(fd, rp, remaining); - if(rc <= 0) - return rc; - - i = unsynchronize(wp, remaining, &global_ff_found); - remaining -= i; - wp += i; - } - - return len; -} - -static int skip_unsynched(int fd, int len) -{ - int rc; - int remaining = len; - int rlen; - char buf[32]; - - while(remaining) { - rlen = MIN(sizeof(buf), (unsigned int)remaining); - rc = read(fd, buf, rlen); - if(rc <= 0) - return rc; - - remaining -= unsynchronize(buf, rlen, &global_ff_found); - } - - return len; -} - -/* parse numeric value from string */ -static int parsetracknum( struct mp3entry* entry, char* tag, int bufferpos ) -{ - entry->tracknum = atoi( tag ); - return bufferpos; -} - -/* parse numeric value from string */ -static int parsediscnum( struct mp3entry* entry, char* tag, int bufferpos ) -{ - entry->discnum = atoi( tag ); - return bufferpos; -} - -/* parse numeric value from string */ -static int parseyearnum( struct mp3entry* entry, char* tag, int bufferpos ) -{ - entry->year = atoi( tag ); - return bufferpos; -} - -/* parse numeric genre from string, version 2.2 and 2.3 */ -static int parsegenre( struct mp3entry* entry, char* tag, int bufferpos ) -{ - /* Use bufferpos to hold current position in entry->id3v2buf. */ - bufferpos = tag - entry->id3v2buf; - - if(entry->id3version >= ID3_VER_2_4) { - /* In version 2.4 and up, there are no parentheses, and the genre frame - is a list of strings, either numbers or text. */ - - /* Is it a number? */ - if(isdigit(tag[0])) { - entry->genre_string = id3_get_num_genre(atoi( tag )); - return bufferpos; - } else { - entry->genre_string = tag; - return bufferpos + strlen(tag) + 1; - } - } else { - if( tag[0] == '(' && tag[1] != '(' ) { - entry->genre_string = id3_get_num_genre(atoi( tag + 1 )); - return bufferpos; - } - else { - entry->genre_string = tag; - return bufferpos + strlen(tag) + 1; - } - } -} - -#ifdef HAVE_ALBUMART -/* parse embed albumart */ -static int parsealbumart( struct mp3entry* entry, char* tag, int bufferpos ) -{ - entry->has_embedded_albumart = false; - - /* we currently don't support unsynchronizing albumart */ - if (entry->albumart.type == AA_TYPE_UNSYNC) - return bufferpos; - - entry->albumart.type = AA_TYPE_UNKNOWN; - - char *start = tag; - /* skip text encoding */ - tag += 1; - - if (memcmp(tag, "image/", 6) == 0) - { - /* ID3 v2.3+ */ - tag += 6; - if (strcmp(tag, "jpeg") == 0) - { - entry->albumart.type = AA_TYPE_JPG; - tag += 5; - } - else if (strcmp(tag, "png") == 0) - { - entry->albumart.type = AA_TYPE_PNG; - tag += 4; - } - } - else - { - /* ID3 v2.2 */ - if (memcmp(tag, "JPG", 3) == 0) - entry->albumart.type = AA_TYPE_JPG; - else if (memcmp(tag, "PNG", 3) == 0) - entry->albumart.type = AA_TYPE_PNG; - tag += 3; - } - - if (entry->albumart.type != AA_TYPE_UNKNOWN) - { - /* skip picture type */ - tag += 1; - /* skip description */ - tag = strchr(tag, '\0') + 1; - /* fixup offset&size for image data */ - entry->albumart.pos += tag - start; - entry->albumart.size -= tag - start; - entry->has_embedded_albumart = true; - } - /* return bufferpos as we didn't store anything in id3v2buf */ - return bufferpos; -} -#endif - -/* parse user defined text, looking for album artist and replaygain - * information. - */ -static int parseuser( struct mp3entry* entry, char* tag, int bufferpos ) -{ - char* value = NULL; - int desc_len = strlen(tag); - int length = 0; - - if ((tag - entry->id3v2buf + desc_len + 2) < bufferpos) { - /* At least part of the value was read, so we can safely try to - * parse it */ - value = tag + desc_len + 1; - - if (!strcasecmp(tag, "ALBUM ARTIST")) { - length = strlen(value) + 1; - strlcpy(tag, value, length); - entry->albumartist = tag; -#if CONFIG_CODEC == SWCODEC - } else { - /* Call parse_replaygain(). */ - parse_replaygain(tag, value, entry); -#endif - } - } - - return tag - entry->id3v2buf + length; -} - -#if CONFIG_CODEC == SWCODEC -/* parse RVA2 binary data and convert to replaygain information. */ -static int parserva2( struct mp3entry* entry, char* tag, int bufferpos) -{ - int desc_len = strlen(tag); - int start_pos = tag - entry->id3v2buf; - int end_pos = start_pos + desc_len + 5; - unsigned char* value = tag + desc_len + 1; - - /* Only parse RVA2 replaygain tags if tag version == 2.4 and channel - * type is master volume. - */ - if (entry->id3version == ID3_VER_2_4 && end_pos < bufferpos - && *value++ == 1) { - long gain = 0; - long peak = 0; - long peakbits; - long peakbytes; - bool album = false; - - /* The RVA2 specification is unclear on some things (id string and - * peak volume), but this matches how Quod Libet use them. - */ - - gain = (int16_t) ((value[0] << 8) | value[1]); - value += 2; - peakbits = *value++; - peakbytes = (peakbits + 7) / 8; - - /* Only use the topmost 24 bits for peak volume */ - if (peakbytes > 3) { - peakbytes = 3; - } - - /* Make sure the peak bits were read */ - if (end_pos + peakbytes < bufferpos) { - long shift = ((8 - (peakbits & 7)) & 7) + (3 - peakbytes) * 8; - - for ( ; peakbytes; peakbytes--) { - peak <<= 8; - peak += *value++; - } - - peak <<= shift; - - if (peakbits > 24) { - peak += *value >> (8 - shift); - } - } - - if (strcasecmp(tag, "album") == 0) { - album = true; - } else if (strcasecmp(tag, "track") != 0) { - /* Only accept non-track values if we don't have any previous - * value. - */ - if (entry->track_gain != 0) { - return start_pos; - } - } - - parse_replaygain_int(album, gain, peak * 2, entry); - } - - return start_pos; -} -#endif - -static int parsembtid( struct mp3entry* entry, char* tag, int bufferpos ) -{ - char* value = NULL; - int desc_len = strlen(tag); - /*DEBUGF("MBID len: %d\n", desc_len);*/ - /* Musicbrainz track IDs are always 36 chars long */ - const size_t mbtid_len = 36; - - if ((tag - entry->id3v2buf + desc_len + 2) < bufferpos) - { - value = tag + desc_len + 1; - - if (strcasecmp(tag, "http://musicbrainz.org") == 0) - { - if (mbtid_len == strlen(value)) - { - entry->mb_track_id = value; - return bufferpos + mbtid_len + 1; - } - } - } - - return bufferpos; -} - -static const struct tag_resolver taglist[] = { - { "TPE1", 4, offsetof(struct mp3entry, artist), NULL, false }, - { "TP1", 3, offsetof(struct mp3entry, artist), NULL, false }, - { "TIT2", 4, offsetof(struct mp3entry, title), NULL, false }, - { "TT2", 3, offsetof(struct mp3entry, title), NULL, false }, - { "TALB", 4, offsetof(struct mp3entry, album), NULL, false }, - { "TAL", 3, offsetof(struct mp3entry, album), NULL, false }, - { "TRK", 3, offsetof(struct mp3entry, track_string), &parsetracknum, false }, - { "TPOS", 4, offsetof(struct mp3entry, disc_string), &parsediscnum, false }, - { "TPA", 3, offsetof(struct mp3entry, disc_string), &parsediscnum, false }, - { "TRCK", 4, offsetof(struct mp3entry, track_string), &parsetracknum, false }, - { "TDRC", 4, offsetof(struct mp3entry, year_string), &parseyearnum, false }, - { "TYER", 4, offsetof(struct mp3entry, year_string), &parseyearnum, false }, - { "TYE", 3, offsetof(struct mp3entry, year_string), &parseyearnum, false }, - { "TCOM", 4, offsetof(struct mp3entry, composer), NULL, false }, - { "TCM", 3, offsetof(struct mp3entry, composer), NULL, false }, - { "TPE2", 4, offsetof(struct mp3entry, albumartist), NULL, false }, - { "TP2", 3, offsetof(struct mp3entry, albumartist), NULL, false }, - { "TIT1", 4, offsetof(struct mp3entry, grouping), NULL, false }, - { "TT1", 3, offsetof(struct mp3entry, grouping), NULL, false }, - { "COMM", 4, offsetof(struct mp3entry, comment), NULL, false }, - { "COM", 3, offsetof(struct mp3entry, comment), NULL, false }, - { "TCON", 4, offsetof(struct mp3entry, genre_string), &parsegenre, false }, - { "TCO", 3, offsetof(struct mp3entry, genre_string), &parsegenre, false }, -#ifdef HAVE_ALBUMART - { "APIC", 4, 0, &parsealbumart, true }, - { "PIC", 3, 0, &parsealbumart, true }, -#endif - { "TXXX", 4, 0, &parseuser, false }, -#if CONFIG_CODEC == SWCODEC - { "RVA2", 4, 0, &parserva2, true }, -#endif - { "UFID", 4, 0, &parsembtid, false }, -}; - -#define TAGLIST_SIZE ((int)ARRAYLEN(taglist)) - -/* Get the length of an ID3 string in the given encoding. Returns the length - * in bytes, including end nil, or -1 if the encoding is unknown. - */ -static int unicode_len(char encoding, const void* string) -{ - int len = 0; - - if (encoding == 0x01 || encoding == 0x02) { - char first; - const char *s = string; - /* string might be unaligned, so using short* can crash on ARM and SH1 */ - do { - first = *s++; - } while ((first | *s++) != 0); - - len = s - (const char*) string; - } else { - len = strlen((char*) string) + 1; - } - - return len; -} - -/* Checks to see if the passed in string is a 16-bit wide Unicode v2 - string. If it is, we convert it to a UTF-8 string. If it's not unicode, - we convert from the default codepage */ -static int unicode_munge(char* string, char* utf8buf, int *len) { - long tmp; - bool le = false; - int i = 0; - unsigned char *str = (unsigned char *)string; - int templen = 0; - unsigned char* utf8 = (unsigned char *)utf8buf; - - switch (str[0]) { - case 0x00: /* Type 0x00 is ordinary ISO 8859-1 */ - str++; - (*len)--; - utf8 = iso_decode(str, utf8, -1, *len); - *utf8 = 0; - *len = (unsigned long)utf8 - (unsigned long)utf8buf; - break; - - case 0x01: /* Unicode with or without BOM */ - case 0x02: - (*len)--; - str++; - - /* Handle frames with more than one string - (needed for TXXX frames).*/ - do { - tmp = bytes2int(0, 0, str[0], str[1]); - - /* Now check if there is a BOM - (zero-width non-breaking space, 0xfeff) - and if it is in little or big endian format */ - if(tmp == 0xfffe) { /* Little endian? */ - le = true; - str += 2; - (*len)-=2; - } else if(tmp == 0xfeff) { /* Big endian? */ - str += 2; - (*len)-=2; - } else - /* If there is no BOM (which is a specification violation), - let's try to guess it. If one of the bytes is 0x00, it is - probably the most significant one. */ - if(str[1] == 0) - le = true; - - while ((i < *len) && (str[0] || str[1])) { - if(le) - utf8 = utf16LEdecode(str, utf8, 1); - else - utf8 = utf16BEdecode(str, utf8, 1); - - str+=2; - i += 2; - } - - *utf8++ = 0; /* Terminate the string */ - templen += (strlen(&utf8buf[templen]) + 1); - str += 2; - i+=2; - } while(i < *len); - *len = templen - 1; - break; - - case 0x03: /* UTF-8 encoded string */ - for(i=0; i < *len; i++) - utf8[i] = str[i+1]; - (*len)--; - break; - - default: /* Plain old string */ - utf8 = iso_decode(str, utf8, -1, *len); - *utf8 = 0; - *len = (unsigned long)utf8 - (unsigned long)utf8buf; - break; - } - return 0; -} - -/* - * Sets the title of an MP3 entry based on its ID3v1 tag. - * - * Arguments: file - the MP3 file to scen for a ID3v1 tag - * entry - the entry to set the title in - * - * Returns: true if a title was found and created, else false - */ -bool setid3v1title(int fd, struct mp3entry *entry) -{ - unsigned char buffer[128]; - static const char offsets[] = {3, 33, 63, 97, 93, 125, 127}; - int i, j; - unsigned char* utf8; - - if (-1 == lseek(fd, -128, SEEK_END)) - return false; - - if (read(fd, buffer, sizeof buffer) != sizeof buffer) - return false; - - if (strncmp((char *)buffer, "TAG", 3)) - return false; - - entry->id3v1len = 128; - entry->id3version = ID3_VER_1_0; - - for (i=0; i < (int)sizeof offsets; i++) { - unsigned char* ptr = (unsigned char *)buffer + offsets[i]; - - switch(i) { - case 0: - case 1: - case 2: - /* kill trailing space in strings */ - for (j=29; j && (ptr[j]==0 || ptr[j]==' '); j--) - ptr[j] = 0; - /* convert string to utf8 */ - utf8 = (unsigned char *)entry->id3v1buf[i]; - utf8 = iso_decode(ptr, utf8, -1, 30); - /* make sure string is terminated */ - *utf8 = 0; - break; - - case 3: - /* kill trailing space in strings */ - for (j=27; j && (ptr[j]==0 || ptr[j]==' '); j--) - ptr[j] = 0; - /* convert string to utf8 */ - utf8 = (unsigned char *)entry->id3v1buf[3]; - utf8 = iso_decode(ptr, utf8, -1, 28); - /* make sure string is terminated */ - *utf8 = 0; - break; - - case 4: - ptr[4] = 0; - entry->year = atoi((char *)ptr); - break; - - case 5: - /* id3v1.1 uses last two bytes of comment field for track - number: first must be 0 and second is track num */ - if (!ptr[0] && ptr[1]) { - entry->tracknum = ptr[1]; - entry->id3version = ID3_VER_1_1; - } - break; - - case 6: - /* genre */ - entry->genre_string = id3_get_num_genre(ptr[0]); - break; - } - } - - entry->title = entry->id3v1buf[0]; - entry->artist = entry->id3v1buf[1]; - entry->album = entry->id3v1buf[2]; - entry->comment = entry->id3v1buf[3]; - - return true; -} - - -/* - * Sets the title of an MP3 entry based on its ID3v2 tag. - * - * Arguments: file - the MP3 file to scan for a ID3v2 tag - * entry - the entry to set the title in - * - * Returns: true if a title was found and created, else false - */ -void setid3v2title(int fd, struct mp3entry *entry) -{ - int minframesize; - int size; - long bufferpos = 0, totframelen, framelen; - char header[10]; - char tmp[4]; - unsigned char version; - char *buffer = entry->id3v2buf; - int bytesread = 0; - int buffersize = sizeof(entry->id3v2buf); - unsigned char global_flags; - int flags; - bool global_unsynch = false; - bool unsynch = false; - int i, j; - int rc; -#if CONFIG_CODEC == SWCODEC - bool itunes_gapless = false; -#endif - - global_ff_found = false; - - /* Bail out if the tag is shorter than 10 bytes */ - if(entry->id3v2len < 10) - return; - - /* Read the ID3 tag version from the header */ - lseek(fd, 0, SEEK_SET); - if(10 != read(fd, header, 10)) - return; - - /* Get the total ID3 tag size */ - size = entry->id3v2len - 10; - - version = header[3]; - switch ( version ) { - case 2: - version = ID3_VER_2_2; - minframesize = 8; - break; - - case 3: - version = ID3_VER_2_3; - minframesize = 12; - break; - - case 4: - version = ID3_VER_2_4; - minframesize = 12; - break; - - default: - /* unsupported id3 version */ - return; - } - entry->id3version = version; - entry->tracknum = entry->year = entry->discnum = 0; - entry->title = entry->artist = entry->album = NULL; /* FIXME incomplete */ - - global_flags = header[5]; - - /* Skip the extended header if it is present */ - if(global_flags & 0x40) { - if(version == ID3_VER_2_3) { - if(10 != read(fd, header, 10)) - return; - /* The 2.3 extended header size doesn't include the header size - field itself. Also, it is not unsynched. */ - framelen = - bytes2int(header[0], header[1], header[2], header[3]) + 4; - - /* Skip the rest of the header */ - lseek(fd, framelen - 10, SEEK_CUR); - } - - if(version >= ID3_VER_2_4) { - if(4 != read(fd, header, 4)) - return; - - /* The 2.4 extended header size does include the entire header, - so here we can just skip it. This header is unsynched. */ - framelen = unsync(header[0], header[1], - header[2], header[3]); - - lseek(fd, framelen - 4, SEEK_CUR); - } - } - - /* Is unsynchronization applied? */ - if(global_flags & 0x80) { - global_unsynch = true; - } - - /* - * We must have at least minframesize bytes left for the - * remaining frames to be interesting - */ - while (size >= minframesize && bufferpos < buffersize - 1) { - flags = 0; - - /* Read frame header and check length */ - if(version >= ID3_VER_2_3) { - if(global_unsynch && version <= ID3_VER_2_3) - rc = read_unsynched(fd, header, 10); - else - rc = read(fd, header, 10); - if(rc != 10) - return; - /* Adjust for the 10 bytes we read */ - size -= 10; - - flags = bytes2int(0, 0, header[8], header[9]); - - if (version >= ID3_VER_2_4) { - framelen = unsync(header[4], header[5], - header[6], header[7]); - } else { - /* version .3 files don't use synchsafe ints for - * size */ - framelen = bytes2int(header[4], header[5], - header[6], header[7]); - } - } else { - if(6 != read(fd, header, 6)) - return; - /* Adjust for the 6 bytes we read */ - size -= 6; - - framelen = bytes2int(0, header[3], header[4], header[5]); - } - - logf("framelen = %ld, flags = 0x%04x", framelen, flags); - if(framelen == 0){ - if (header[0] == 0 && header[1] == 0 && header[2] == 0) - return; - else - continue; - } - - unsynch = false; - - if(flags) - { - if (version >= ID3_VER_2_4) { - if(flags & 0x0040) { /* Grouping identity */ - lseek(fd, 1, SEEK_CUR); /* Skip 1 byte */ - framelen--; - } - } else { - if(flags & 0x0020) { /* Grouping identity */ - lseek(fd, 1, SEEK_CUR); /* Skip 1 byte */ - framelen--; - } - } - - if(flags & 0x000c) /* Compression or encryption */ - { - /* Skip it */ - size -= framelen; - lseek(fd, framelen, SEEK_CUR); - continue; - } - - if(flags & 0x0002) /* Unsynchronization */ - unsynch = true; - - if (version >= ID3_VER_2_4) { - if(flags & 0x0001) { /* Data length indicator */ - if(4 != read(fd, tmp, 4)) - return; - - /* We don't need the data length */ - framelen -= 4; - } - } - } - - if (framelen == 0) - continue; - - if (framelen < 0) - return; - - /* Keep track of the remaining frame size */ - totframelen = framelen; - - /* If the frame is larger than the remaining buffer space we try - to read as much as would fit in the buffer */ - if(framelen >= buffersize - bufferpos) - framelen = buffersize - bufferpos - 1; - - /* Limit the maximum length of an id3 data item to ID3V2_MAX_ITEM_SIZE - bytes. This reduces the chance that the available buffer is filled - by single metadata items like large comments. */ - if (ID3V2_MAX_ITEM_SIZE < framelen) - framelen = ID3V2_MAX_ITEM_SIZE; - - logf("id3v2 frame: %.4s", header); - - /* Check for certain frame headers - - 'size' is the amount of frame bytes remaining. We decrement it by - the amount of bytes we read. If we fail to read as many bytes as - we expect, we assume that we can't read from this file, and bail - out. - - For each frame. we will iterate over the list of supported tags, - and read the tag into entry's buffer. All tags will be kept as - strings, for cases where a number won't do, e.g., YEAR: "circa - 1765", "1790/1977" (composed/performed), "28 Feb 1969" TRACK: - "1/12", "1 of 12", GENRE: "Freeform genre name" Text is more - flexible, and as the main use of id3 data is to display it, - converting it to an int just means reconverting to display it, at a - runtime cost. - - For tags that the current code does convert to ints, a post - processing function will be called via a pointer to function. */ - - for (i=0; i<TAGLIST_SIZE; i++) { - const struct tag_resolver* tr = &taglist[i]; - char** ptag = tr->offset ? (char**) (((char*)entry) + tr->offset) - : NULL; - char* tag; - - /* Only ID3_VER_2_2 uses frames with three-character names. */ - if (((version == ID3_VER_2_2) && (tr->tag_length != 3)) - || ((version > ID3_VER_2_2) && (tr->tag_length != 4))) { - continue; - } - - if( !memcmp( header, tr->tag, tr->tag_length ) ) { - - /* found a tag matching one in tagList, and not yet filled */ - tag = buffer + bufferpos; - - if(global_unsynch && version <= ID3_VER_2_3) - bytesread = read_unsynched(fd, tag, framelen); - else - bytesread = read(fd, tag, framelen); - - if( bytesread != framelen ) - return; - - size -= bytesread; - - if(unsynch || (global_unsynch && version >= ID3_VER_2_4)) - bytesread = unsynchronize_frame(tag, bytesread); - - /* the COMM frame has a 3 char field to hold an ISO-639-1 - * language string and an optional short description; - * remove them so unicode_munge can work correctly - */ - - if((tr->tag_length == 4 && !memcmp( header, "COMM", 4)) || - (tr->tag_length == 3 && !memcmp( header, "COM", 3))) { - int offset; - if(bytesread >= 8 && !strncmp(tag+4, "iTun", 4)) { -#if CONFIG_CODEC == SWCODEC - /* check for iTunes gapless information */ - if(bytesread >= 12 && !strncmp(tag+4, "iTunSMPB", 8)) - itunes_gapless = true; - else -#endif - /* ignore other with iTunes tags */ - break; - } - - offset = 3 + unicode_len(*tag, tag + 4); - if(bytesread > offset) { - bytesread -= offset; - memmove(tag + 1, tag + 1 + offset, bytesread - 1); - } - } - - /* Attempt to parse Unicode string only if the tag contents - aren't binary */ - if(!tr->binary) { - /* UTF-8 could potentially be 3 times larger */ - /* so we need to create a new buffer */ - char utf8buf[(3 * bytesread) + 1]; - - unicode_munge( tag, utf8buf, &bytesread ); - - if(bytesread >= buffersize - bufferpos) - bytesread = buffersize - bufferpos - 1; - - if ( /* Is it an embedded cuesheet? */ - (tr->tag_length == 4 && !memcmp(header, "TXXX", 4)) && - (bytesread >= 14 && !strncmp(utf8buf, "CUESHEET", 8)) - ) { - unsigned char char_enc = 0; - /* [enc type]+"CUESHEET\0" = 10 */ - unsigned char cuesheet_offset = 10; - switch (tag[0]) { - case 0x00: - char_enc = CHAR_ENC_ISO_8859_1; - break; - case 0x01: - tag++; - if (!memcmp(tag, - BOM_UTF_16_BE, BOM_UTF_16_SIZE)) { - char_enc = CHAR_ENC_UTF_16_BE; - } else if (!memcmp(tag, - BOM_UTF_16_LE, BOM_UTF_16_SIZE)) { - char_enc = CHAR_ENC_UTF_16_LE; - } - /* \1 + BOM(2) + C0U0E0S0H0E0E0T000 = 21 */ - cuesheet_offset = 21; - break; - case 0x02: - char_enc = CHAR_ENC_UTF_16_BE; - /* \2 + 0C0U0E0S0H0E0E0T00 = 19 */ - cuesheet_offset = 19; - break; - case 0x03: - char_enc = CHAR_ENC_UTF_8; - break; - } - if (char_enc > 0) { - entry->has_embedded_cuesheet = true; - entry->embedded_cuesheet.pos = lseek(fd, 0, SEEK_CUR) - - framelen + cuesheet_offset; - entry->embedded_cuesheet.size = totframelen - - cuesheet_offset; - entry->embedded_cuesheet.encoding = char_enc; - } - break; - } - - for (j = 0; j < bytesread; j++) - tag[j] = utf8buf[j]; - - /* remove trailing spaces */ - while ( bytesread > 0 && isspace(tag[bytesread-1])) - bytesread--; - } - - if(bytesread == 0) - /* Skip empty frames */ - break; - - tag[bytesread] = 0; - bufferpos += bytesread + 1; - -#if CONFIG_CODEC == SWCODEC - /* parse the tag if it contains iTunes gapless info */ - if (itunes_gapless) - { - itunes_gapless = false; - entry->lead_trim = get_itunes_int32(tag, 1); - entry->tail_trim = get_itunes_int32(tag, 2); - } -#endif - - /* Note that parser functions sometimes set *ptag to NULL, so - * the "!*ptag" check here doesn't always have the desired - * effect. Should the parser functions (parsegenre in - * particular) be updated to handle the case of being called - * multiple times, or should the "*ptag" check be removed? - */ - if (ptag && !*ptag) - *ptag = tag; - -#ifdef HAVE_ALBUMART - /* albumart */ - if ((!entry->has_embedded_albumart) && - ((tr->tag_length == 4 && !memcmp( header, "APIC", 4)) || - (tr->tag_length == 3 && !memcmp( header, "PIC" , 3)))) - { - if (unsynch || (global_unsynch && version <= ID3_VER_2_3)) - entry->albumart.type = AA_TYPE_UNSYNC; - else - { - entry->albumart.pos = lseek(fd, 0, SEEK_CUR) - framelen; - entry->albumart.size = totframelen; - entry->albumart.type = AA_TYPE_UNKNOWN; - } - } -#endif - if( tr->ppFunc ) - bufferpos = tr->ppFunc(entry, tag, bufferpos); - break; - } - } - - if( i == TAGLIST_SIZE ) { - /* no tag in tagList was found, or it was a repeat. - skip it using the total size */ - - if(global_unsynch && version <= ID3_VER_2_3) { - size -= skip_unsynched(fd, totframelen); - } else { - size -= totframelen; - if( lseek(fd, totframelen, SEEK_CUR) == -1 ) - return; - } - } else { - /* Seek to the next frame */ - if(framelen < totframelen) - lseek(fd, totframelen - framelen, SEEK_CUR); - } - } -} - -/* - * Calculates the size of the ID3v2 tag. - * - * Arguments: file - the file to search for a tag. - * - * Returns: the size of the tag or 0 if none was found - */ -int getid3v2len(int fd) -{ - char buf[6]; - int offset; - - /* Make sure file has a ID3 tag */ - if((-1 == lseek(fd, 0, SEEK_SET)) || - (read(fd, buf, 6) != 6) || - (strncmp(buf, "ID3", strlen("ID3")) != 0)) - offset = 0; - - /* Now check what the ID3v2 size field says */ - else - if(read(fd, buf, 4) != 4) - offset = 0; - else - offset = unsync(buf[0], buf[1], buf[2], buf[3]) + 10; - - logf("ID3V2 Length: 0x%x", offset); - return offset; -} - -#ifdef DEBUG_STANDALONE - -char *secs2str(int ms) -{ - static char buffer[32]; - int secs = ms/1000; - ms %= 1000; - snprintf(buffer, sizeof(buffer), "%d:%02d.%d", secs/60, secs%60, ms/100); - return buffer; -} - -int main(int argc, char **argv) -{ - int i; - for(i=1; i<argc; i++) { - struct mp3entry mp3; - mp3.album = "Bogus"; - if(mp3info(&mp3, argv[i], false)) { - printf("Failed to get %s\n", argv[i]); - return 0; - } - - printf("****** File: %s\n" - " Title: %s\n" - " Artist: %s\n" - " Album: %s\n" - " Genre: %s (%d) \n" - " Composer: %s\n" - " Year: %s (%d)\n" - " Track: %s (%d)\n" - " Length: %s / %d s\n" - " Bitrate: %d\n" - " Frequency: %d\n", - argv[i], - mp3.title?mp3.title:"<blank>", - mp3.artist?mp3.artist:"<blank>", - mp3.album?mp3.album:"<blank>", - mp3.genre_string?mp3.genre_string:"<blank>", - mp3.genre, - mp3.composer?mp3.composer:"<blank>", - mp3.year_string?mp3.year_string:"<blank>", - mp3.year, - mp3.track_string?mp3.track_string:"<blank>", - mp3.tracknum, - secs2str(mp3.length), - mp3.length/1000, - mp3.bitrate, - mp3.frequency); - } - - return 0; -} - -#endif diff --git a/apps/metadata/kss.c b/apps/metadata/kss.c deleted file mode 100644 index 2ae0cf5..0000000 --- a/apps/metadata/kss.c +++ /dev/null @@ -1,53 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "rbunicode.h" - -static bool parse_kss_header(int fd, struct mp3entry* id3) -{ - /* Use the trackname part of the id3 structure as a temporary buffer */ - unsigned char* buf = (unsigned char *)id3->path; - - lseek(fd, 0, SEEK_SET); - if (read(fd, buf, 0x20) < 0x20) - return false; - - /* calculate track length with number of tracks */ - id3->length = 0; - if (buf[14] == 0x10) { - id3->length = (get_short_le((void *)(buf + 26)) + 1) * 1000; - } - - if (id3->length <= 0) - id3->length = 255 * 1000; /* 255 tracks */ - - return true; -} - - -bool get_kss_metadata(int fd, struct mp3entry* id3) -{ - uint32_t kss_type; - if ((lseek(fd, 0, SEEK_SET) < 0) || - read_uint32be(fd, &kss_type) != (int)sizeof(kss_type)) - return false; - - id3->vbr = false; - id3->filesize = filesize(fd); - /* we only render 16 bits, 44.1KHz, Stereo */ - id3->bitrate = 706; - id3->frequency = 44100; - - /* Make sure this is an SGC file */ - if (kss_type != FOURCC('K','S','C','C') && kss_type != FOURCC('K','S','S','X')) - return false; - - return parse_kss_header(fd, id3); -} diff --git a/apps/metadata/metadata_common.c b/apps/metadata/metadata_common.c deleted file mode 100644 index e861644..0000000 --- a/apps/metadata/metadata_common.c +++ /dev/null @@ -1,374 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include "string-extra.h" -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "replaygain.h" - -/* Read a string from the file. Read up to size bytes, or, if eos != -1, - * until the eos character is found (eos is not stored in buf, unless it is - * nil). Writes up to buf_size chars to buf, always terminating with a nil. - * Returns number of chars read or -1 on read error. - */ -long read_string(int fd, char* buf, long buf_size, int eos, long size) -{ - long read_bytes = 0; - char c; - - while (size != 0) - { - if (read(fd, &c, 1) != 1) - { - read_bytes = -1; - break; - } - - read_bytes++; - size--; - - if ((eos != -1) && (eos == (unsigned char) c)) - { - break; - } - - if (buf_size > 1) - { - *buf++ = c; - buf_size--; - } - } - - *buf = 0; - return read_bytes; -} -/* Read an unsigned 8-bit integer from a file. */ -int read_uint8(int fd, uint8_t* buf) -{ - size_t n; - - n = read(fd, (char*) buf, 1); - return n; -} - -#ifdef ROCKBOX_LITTLE_ENDIAN -/* Read an unsigned 16-bit integer from a big-endian file. */ -int read_uint16be(int fd, uint16_t* buf) -{ - size_t n; - - n = read(fd, (char*) buf, 2); - *buf = betoh16(*buf); - return n; -} -/* Read an unsigned 32-bit integer from a big-endian file. */ -int read_uint32be(int fd, uint32_t* buf) -{ - size_t n; - - n = read(fd, (char*) buf, 4); - *buf = betoh32(*buf); - return n; -} -/* Read an unsigned 64-bit integer from a big-endian file. */ -int read_uint64be(int fd, uint64_t* buf) -{ - size_t n; - uint8_t data[8]; - int i; - - n = read(fd, data, 8); - - for (i=0, *buf=0; i<=7; i++) { - *buf <<= 8; - *buf |= data[i]; - } - return n; -} -#else -/* Read unsigned integers from a little-endian file. */ -int read_uint16le(int fd, uint16_t* buf) -{ - size_t n; - - n = read(fd, (char*) buf, 2); - *buf = letoh16(*buf); - return n; -} -int read_uint32le(int fd, uint32_t* buf) -{ - size_t n; - - n = read(fd, (char*) buf, 4); - *buf = letoh32(*buf); - return n; -} -int read_uint64le(int fd, uint64_t* buf) -{ - size_t n; - uint8_t data[8]; - int i; - - n = read(fd, data, 8); - - for (i=7, *buf=0; i>=0; i--) { - *buf <<= 8; - *buf |= data[i]; - } - - return n; -} -#endif - -/* Read an unaligned 64-bit little endian unsigned integer from buffer. */ -uint64_t get_uint64_le(void* buf) -{ - unsigned char* p = (unsigned char*) buf; - - return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24) | ((uint64_t)p[4] << 32) | - ((uint64_t)p[5] << 40) | ((uint64_t)p[6] << 48) | ((uint64_t)p[7] << 56); -} - -/* Read an unaligned 32-bit little endian long from buffer. */ -uint32_t get_long_le(void* buf) -{ - unsigned char* p = (unsigned char*) buf; - - return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); -} - -/* Read an unaligned 16-bit little endian short from buffer. */ -uint16_t get_short_le(void* buf) -{ - unsigned char* p = (unsigned char*) buf; - - return p[0] | (p[1] << 8); -} - -/* Read an unaligned 32-bit big endian long from buffer. */ -uint32_t get_long_be(void* buf) -{ - unsigned char* p = (unsigned char*) buf; - - return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; -} - -/* Read an unaligned 16-bit little endian short from buffer. */ -uint16_t get_short_be(void* buf) -{ - unsigned char* p = (unsigned char*) buf; - - return (p[0] << 8) | p[1]; -} - -/* Read an unaligned 32-bit little endian long from buffer. */ -int32_t get_slong(void* buf) -{ - unsigned char* p = (unsigned char*) buf; - - return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); -} - -uint32_t get_itunes_int32(char* value, int count) -{ - static const char hexdigits[] = "0123456789ABCDEF"; - const char* c; - int r = 0; - - while (count-- > 0) - { - while (isspace(*value)) - { - value++; - } - - while (*value && !isspace(*value)) - { - value++; - } - } - - while (isspace(*value)) - { - value++; - } - - while (*value && ((c = strchr(hexdigits, toupper(*value))) != NULL)) - { - r = (r << 4) | (c - hexdigits); - value++; - } - - return r; -} - -/* Skip an ID3v2 tag if it can be found. We assume the tag is located at the - * start of the file, which should be true in all cases where we need to skip it. - * Returns true if successfully skipped or not skipped, and false if - * something went wrong while skipping. - */ -bool skip_id3v2(int fd, struct mp3entry *id3) -{ - char buf[4]; - - read(fd, buf, 4); - if (memcmp(buf, "ID3", 3) == 0) - { - /* We have found an ID3v2 tag at the start of the file - find its - length and then skip it. */ - if ((id3->first_frame_offset = getid3v2len(fd)) == 0) - return false; - - if ((lseek(fd, id3->first_frame_offset, SEEK_SET) < 0)) - return false; - - return true; - } else { - lseek(fd, 0, SEEK_SET); - id3->first_frame_offset = 0; - return true; - } -} - -/* 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). - */ -long parse_tag(const char* name, char* value, struct mp3entry* id3, - char* buf, long buf_remaining, enum tagtype type) -{ - long len = 0; - char** p; - - if ((((strcasecmp(name, "track") == 0) && (type == TAGTYPE_APE))) - || ((strcasecmp(name, "tracknumber") == 0) && (type == TAGTYPE_VORBIS))) - { - id3->tracknum = atoi(value); - p = &(id3->track_string); - } - else if (strcasecmp(name, "discnumber") == 0 || strcasecmp(name, "disc") == 0) - { - id3->discnum = atoi(value); - p = &(id3->disc_string); - } - else if (((strcasecmp(name, "year") == 0) && (type == TAGTYPE_APE)) - || ((strcasecmp(name, "date") == 0) && (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 - * of the tag as a number, we should get the year. If we get crap, - * then act like we never parsed it. - */ - id3->year = atoi(value); - if (id3->year < 1900) - { /* yeah, not likely */ - id3->year = 0; - } - p = &(id3->year_string); - } - else if (strcasecmp(name, "title") == 0) - { - p = &(id3->title); - } - else if (strcasecmp(name, "artist") == 0) - { - p = &(id3->artist); - } - else if (strcasecmp(name, "album") == 0) - { - p = &(id3->album); - } - else if (strcasecmp(name, "genre") == 0) - { - p = &(id3->genre_string); - } - else if (strcasecmp(name, "composer") == 0) - { - p = &(id3->composer); - } - else if (strcasecmp(name, "comment") == 0) - { - p = &(id3->comment); - } - else if (strcasecmp(name, "albumartist") == 0) - { - p = &(id3->albumartist); - } - else if (strcasecmp(name, "album artist") == 0) - { - 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) - { - p = &(id3->grouping); - } - else if (strcasecmp(name, "musicbrainz_trackid") == 0 - || strcasecmp(name, "http://musicbrainz.org") == 0 ) - { - p = &(id3->mb_track_id); - } - else - { - parse_replaygain(name, value, id3); - p = NULL; - } - - /* Do not overwrite already available metadata. Especially when reading - * tags with e.g. multiple genres / artists. This way only the first - * of multiple entries is used, all following are dropped. */ - if (p!=NULL && *p==NULL) - { - len = strlen(value); - len = MIN(len, buf_remaining - 1); - len = MIN(len, ID3V2_MAX_ITEM_SIZE); /* Limit max. item size. */ - - if (len > 0) - { - len++; - strlcpy(buf, value, len); - *p = buf; - } - else - { - len = 0; - } - } - - return len; -} diff --git a/apps/metadata/metadata_common.h b/apps/metadata/metadata_common.h deleted file mode 100644 index db91729..0000000 --- a/apps/metadata/metadata_common.h +++ /dev/null @@ -1,69 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <inttypes.h> -#include "metadata.h" - -#ifdef ROCKBOX_BIG_ENDIAN -#define IS_BIG_ENDIAN 1 -#else -#define IS_BIG_ENDIAN 0 -#endif - -#define TAG_NAME_LENGTH 32 -#define TAG_VALUE_LENGTH 128 - -#define FOURCC(a,b,c,d) (((a)<<24) | ((b) << 16) | ((c) << 8) | (d)) - -enum tagtype { TAGTYPE_APE = 1, TAGTYPE_VORBIS }; - -bool read_ape_tags(int fd, struct mp3entry* id3); -long read_vorbis_tags(int fd, struct mp3entry *id3, - long tag_remaining); - -bool skip_id3v2(int fd, struct mp3entry *id3); -long read_string(int fd, char* buf, long buf_size, int eos, long size); - -int read_uint8(int fd, uint8_t* buf); -#ifdef ROCKBOX_BIG_ENDIAN -#define read_uint16be(fd,buf) read((fd), (buf), 2) -#define read_uint32be(fd,buf) read((fd), (buf), 4) -#define read_uint64be(fd,buf) read((fd), (buf), 8) -int read_uint16le(int fd, uint16_t* buf); -int read_uint32le(int fd, uint32_t* buf); -int read_uint64le(int fd, uint64_t* buf); -#else -int read_uint16be(int fd, uint16_t* buf); -int read_uint32be(int fd, uint32_t* buf); -int read_uint64be(int fd, uint64_t* buf); -#define read_uint16le(fd,buf) read((fd), (buf), 2) -#define read_uint32le(fd,buf) read((fd), (buf), 4) -#define read_uint64le(fd,buf) read((fd), (buf), 8) -#endif - -uint64_t get_uint64_le(void* buf); -uint32_t get_long_le(void* buf); -uint16_t get_short_le(void* buf); -uint32_t get_long_be(void* buf); -uint16_t get_short_be(void* buf); -int32_t get_slong(void* buf); -uint32_t get_itunes_int32(char* value, int count); -long parse_tag(const char* name, char* value, struct mp3entry* id3, - char* buf, long buf_remaining, enum tagtype type); diff --git a/apps/metadata/metadata_parsers.h b/apps/metadata/metadata_parsers.h deleted file mode 100644 index 304e393..0000000 --- a/apps/metadata/metadata_parsers.h +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#if CONFIG_CODEC == SWCODEC -char* id3_get_num_genre(unsigned int genre_num); -#endif -int getid3v2len(int fd); -bool setid3v1title(int fd, struct mp3entry *entry); -void setid3v2title(int fd, struct mp3entry *entry); -bool get_mp3_metadata(int fd, struct mp3entry* id3); -#if CONFIG_CODEC == SWCODEC -bool get_adx_metadata(int fd, struct mp3entry* id3); -bool get_aiff_metadata(int fd, struct mp3entry* id3); -bool get_flac_metadata(int fd, struct mp3entry* id3); -bool get_mp4_metadata(int fd, struct mp3entry* id3); -bool get_monkeys_metadata(int fd, struct mp3entry* id3); -bool get_musepack_metadata(int fd, struct mp3entry *id3); -bool get_sid_metadata(int fd, struct mp3entry* id3); -bool get_mod_metadata(int fd, struct mp3entry* id3); -bool get_spc_metadata(int fd, struct mp3entry* id3); -bool get_ogg_metadata(int fd, struct mp3entry* id3); -bool get_wave_metadata(int fd, struct mp3entry* id3); -bool get_wavpack_metadata(int fd, struct mp3entry* id3); -bool get_a52_metadata(int fd, struct mp3entry* id3); -bool get_asf_metadata(int fd, struct mp3entry* id3); -bool get_asap_metadata(int fd, struct mp3entry* id3); -bool get_rm_metadata(int fd, struct mp3entry* id3); -bool get_nsf_metadata(int fd, struct mp3entry* id3); -bool get_oma_metadata(int fd, struct mp3entry* id3); -bool get_smaf_metadata(int fd, struct mp3entry* id3); -bool get_au_metadata(int fd, struct mp3entry* id3); -bool get_vox_metadata(int fd, struct mp3entry* id3); -bool get_wave64_metadata(int fd, struct mp3entry* id3); -bool get_tta_metadata(int fd, struct mp3entry* id3); -bool get_ay_metadata(int fd, struct mp3entry* id3); -bool get_gbs_metadata(int fd, struct mp3entry* id3); -bool get_hes_metadata(int fd, struct mp3entry* id3); -bool get_sgc_metadata(int fd, struct mp3entry* id3); -bool get_vgm_metadata(int fd, struct mp3entry* id3); -bool get_kss_metadata(int fd, struct mp3entry* id3); -#endif /* CONFIG_CODEC == SWCODEC */ diff --git a/apps/metadata/mod.c b/apps/metadata/mod.c deleted file mode 100644 index de76823..0000000 --- a/apps/metadata/mod.c +++ /dev/null @@ -1,103 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include <string-extra.h> -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "rbunicode.h" - -#define MODULEHEADERSIZE 0x438 - -bool get_mod_metadata(int fd, struct mp3entry* id3) -{ - /* Use the trackname part of the id3 structure as a temporary buffer */ - unsigned char *buf = id3->id3v2buf; - unsigned char id[4]; - bool is_mod_file = false; - - /* Seek to file begin */ - if (lseek(fd, 0, SEEK_SET) < 0) - return false; - /* Use id3v2buf as buffer for the track name */ - if (read(fd, buf, sizeof(id3->id3v2buf)) < (ssize_t)sizeof(id3->id3v2buf)) - return false; - /* Seek to MOD ID position */ - if (lseek(fd, MODULEHEADERSIZE, SEEK_SET) < 0) - return false; - /* Read MOD ID */ - if (read(fd, id, sizeof(id)) < (ssize_t)sizeof(id)) - return false; - - /* Mod type checking based on MikMod */ - /* Protracker and variants */ - if ((!memcmp(id, "M.K.", 4)) || (!memcmp(id, "M!K!", 4))) { - is_mod_file = true; - } - - /* Star Tracker */ - if (((!memcmp(id, "FLT", 3)) || (!memcmp(id, "EXO", 3))) && - (isdigit(id[3]))) { - char numchn = id[3] - '0'; - if (numchn == 4 || numchn == 8) - is_mod_file = true; - } - - /* Oktalyzer (Amiga) */ - if (!memcmp(id, "OKTA", 4)) { - is_mod_file = true; - } - - /* Oktalyser (Atari) */ - if (!memcmp(id, "CD81", 4)) { - is_mod_file = true; - } - - /* Fasttracker */ - if ((!memcmp(id + 1, "CHN", 3)) && (isdigit(id[0]))) { - is_mod_file = true; - } - /* Fasttracker or Taketracker */ - if (((!memcmp(id + 2, "CH", 2)) || (!memcmp(id + 2, "CN", 2))) - && (isdigit(id[0])) && (isdigit(id[1]))) { - is_mod_file = true; - } - - /* Don't try to play if we can't find a known mod type - * (there are mod files which have nothing to do with music) */ - if (!is_mod_file) - return false; - - id3->title = id3->id3v2buf; /* Point title to previous read ID3 buffer. */ - id3->bitrate = filesize(fd)/1024; /* size in kb */ - id3->frequency = 44100; - id3->length = 120*1000; - id3->vbr = false; - id3->filesize = filesize(fd); - - return true; -} - diff --git a/apps/metadata/monkeys.c b/apps/metadata/monkeys.c deleted file mode 100644 index 4aff141..0000000 --- a/apps/metadata/monkeys.c +++ /dev/null @@ -1,97 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2007 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" - -bool get_monkeys_metadata(int fd, struct mp3entry* id3) -{ - /* Use the trackname part of the id3 structure as a temporary buffer */ - unsigned char* buf = (unsigned char *)id3->path; - unsigned char* header; - bool rc = false; - uint32_t descriptorlength; - uint32_t totalsamples; - uint32_t blocksperframe, finalframeblocks, totalframes; - int fileversion; - - lseek(fd, 0, SEEK_SET); - - if (read(fd, buf, 4) < 4) - { - return rc; - } - - if (memcmp(buf, "MAC ", 4) != 0) - { - return rc; - } - - read(fd, buf + 4, MAX_PATH - 4); - - fileversion = get_short_le(buf+4); - if (fileversion < 3970) - { - /* Not supported */ - return false; - } - - if (fileversion >= 3980) - { - descriptorlength = get_long_le(buf+8); - - header = buf + descriptorlength; - - blocksperframe = get_long_le(header+4); - finalframeblocks = get_long_le(header+8); - totalframes = get_long_le(header+12); - id3->frequency = get_long_le(header+20); - } - else - { - /* v3.95 and later files all have a fixed framesize */ - blocksperframe = 73728 * 4; - - finalframeblocks = get_long_le(buf+28); - totalframes = get_long_le(buf+24); - id3->frequency = get_long_le(buf+12); - } - - id3->vbr = true; /* All APE files are VBR */ - id3->filesize = filesize(fd); - - totalsamples = finalframeblocks; - if (totalframes > 1) - totalsamples += blocksperframe * (totalframes-1); - - id3->length = ((int64_t) totalsamples * 1000) / id3->frequency; - id3->bitrate = (id3->filesize * 8) / id3->length; - - read_ape_tags(fd, id3); - return true; -} diff --git a/apps/metadata/mp3.c b/apps/metadata/mp3.c deleted file mode 100644 index feb1a52..0000000 --- a/apps/metadata/mp3.c +++ /dev/null @@ -1,193 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 by Daniel Stenberg - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -/* - * Parts of this code has been stolen from the Ample project and was written - * by David H�deman. It has since been extended and enhanced pretty much by - * all sorts of friendly Rockbox people. - * - */ - - /* tagResolver and associated code copyright 2003 Thomas Paul Diffenbach - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdbool.h> -#include "string-extra.h" -#include "config.h" -#include "file.h" -#include "logf.h" - -#include "system.h" -#include "metadata.h" -#include "mp3data.h" -#include "metadata_common.h" -#include "metadata_parsers.h" - -/* - * Calculates the length (in milliseconds) of an MP3 file. - * - * Modified to only use integers. - * - * Arguments: file - the file to calculate the length upon - * entry - the entry to update with the length - * - * Returns: the song length in milliseconds, - * 0 means that it couldn't be calculated - */ -static int getsonglength(int fd, struct mp3entry *entry) -{ - unsigned long filetime = 0; - struct mp3info info; - long bytecount; - - /* Start searching after ID3v2 header */ - if(-1 == lseek(fd, entry->id3v2len, SEEK_SET)) - return 0; - - bytecount = get_mp3file_info(fd, &info); - - logf("Space between ID3V2 tag and first audio frame: 0x%lx bytes", - bytecount); - - if(bytecount < 0) - return -1; - - bytecount += entry->id3v2len; - - /* Validate byte count, in case the file has been edited without - * updating the header. - */ - if (info.byte_count) - { - const unsigned long expected = entry->filesize - entry->id3v1len - - entry->id3v2len; - const unsigned long diff = MAX(10240, info.byte_count / 20); - - if ((info.byte_count > expected + diff) - || (info.byte_count < expected - diff)) - { - logf("Note: info.byte_count differs from expected value by " - "%ld bytes", labs((long) (expected - info.byte_count))); - info.byte_count = 0; - info.frame_count = 0; - info.file_time = 0; - info.enc_padding = 0; - - /* Even if the bitrate was based on "known bad" values, it - * should still be better for VBR files than using the bitrate - * of the first audio frame. - */ - } - } - - entry->bitrate = info.bitrate; - entry->frequency = info.frequency; - entry->layer = info.layer; - switch(entry->layer) { -#if CONFIG_CODEC==SWCODEC - case 0: - entry->codectype=AFMT_MPA_L1; - break; -#endif - case 1: - entry->codectype=AFMT_MPA_L2; - break; - case 2: - entry->codectype=AFMT_MPA_L3; - break; - } - - /* If the file time hasn't been established, this may be a fixed - rate MP3, so just use the default formula */ - - filetime = info.file_time; - - if(filetime == 0) - { - /* Prevent a division by zero */ - if (info.bitrate < 8) - filetime = 0; - else - filetime = (entry->filesize - bytecount) / (info.bitrate / 8); - /* bitrate is in kbps so this delivers milliseconds. Doing bitrate / 8 - * instead of filesize * 8 is exact, because mpeg audio bitrates are - * always multiples of 8, and it avoids overflows. */ - } - - entry->frame_count = info.frame_count; - - entry->vbr = info.is_vbr; - entry->has_toc = info.has_toc; - -#if CONFIG_CODEC==SWCODEC - if (!entry->lead_trim) - entry->lead_trim = info.enc_delay; - if (!entry->tail_trim) - entry->tail_trim = info.enc_padding; -#endif - - memcpy(entry->toc, info.toc, sizeof(info.toc)); - - /* Update the seek point for the first playable frame */ - entry->first_frame_offset = bytecount; - logf("First frame is at %lx", entry->first_frame_offset); - - return filetime; -} - -/* - * Checks all relevant information (such as ID3v1 tag, ID3v2 tag, length etc) - * about an MP3 file and updates it's entry accordingly. - * - Note, that this returns true for successful, false for error! */ -bool get_mp3_metadata(int fd, struct mp3entry *entry) -{ - entry->title = NULL; - entry->filesize = filesize(fd); - entry->id3v2len = getid3v2len(fd); - entry->tracknum = 0; - entry->discnum = 0; - - if (entry->id3v2len) - setid3v2title(fd, entry); - int len = getsonglength(fd, entry); - if (len < 0) - return false; - entry->length = len; - - /* Subtract the meta information from the file size to get - the true size of the MP3 stream */ - entry->filesize -= entry->first_frame_offset; - - /* only seek to end of file if no id3v2 tags were found */ - if (!entry->id3v2len) { - setid3v1title(fd, entry); - } - - if(!entry->length || (entry->filesize < 8 )) - /* no song length or less than 8 bytes is hereby considered to be an - invalid mp3 and won't be played by us! */ - return false; - - return true; -} diff --git a/apps/metadata/mp4.c b/apps/metadata/mp4.c deleted file mode 100644 index df16443..0000000 --- a/apps/metadata/mp4.c +++ /dev/null @@ -1,842 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Magnus Holmgren - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "errno.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "logf.h" -#include "debug.h" -#include "replaygain.h" - -#ifdef DEBUGF -#undef DEBUGF -#define DEBUGF(...) -#endif - -#define MP4_3gp6 FOURCC('3', 'g', 'p', '6') -#define MP4_aART FOURCC('a', 'A', 'R', 'T') -#define MP4_alac FOURCC('a', 'l', 'a', 'c') -#define MP4_calb FOURCC(0xa9, 'a', 'l', 'b') -#define MP4_cART FOURCC(0xa9, 'A', 'R', 'T') -#define MP4_cgrp FOURCC(0xa9, 'g', 'r', 'p') -#define MP4_cgen FOURCC(0xa9, 'g', 'e', 'n') -#define MP4_chpl FOURCC('c', 'h', 'p', 'l') -#define MP4_cnam FOURCC(0xa9, 'n', 'a', 'm') -#define MP4_cwrt FOURCC(0xa9, 'w', 'r', 't') -#define MP4_ccmt FOURCC(0xa9, 'c', 'm', 't') -#define MP4_cday FOURCC(0xa9, 'd', 'a', 'y') -#define MP4_covr FOURCC('c', 'o', 'v', 'r') -#define MP4_disk FOURCC('d', 'i', 's', 'k') -#define MP4_esds FOURCC('e', 's', 'd', 's') -#define MP4_ftyp FOURCC('f', 't', 'y', 'p') -#define MP4_gnre FOURCC('g', 'n', 'r', 'e') -#define MP4_hdlr FOURCC('h', 'd', 'l', 'r') -#define MP4_ilst FOURCC('i', 'l', 's', 't') -#define MP4_isom FOURCC('i', 's', 'o', 'm') -#define MP4_M4A FOURCC('M', '4', 'A', ' ') -#define MP4_m4a FOURCC('m', '4', 'a', ' ') /*technically its "M4A "*/ -#define MP4_M4B FOURCC('M', '4', 'B', ' ') /*but files exist with lower case*/ -#define MP4_mdat FOURCC('m', 'd', 'a', 't') -#define MP4_mdia FOURCC('m', 'd', 'i', 'a') -#define MP4_mdir FOURCC('m', 'd', 'i', 'r') -#define MP4_meta FOURCC('m', 'e', 't', 'a') -#define MP4_minf FOURCC('m', 'i', 'n', 'f') -#define MP4_moov FOURCC('m', 'o', 'o', 'v') -#define MP4_mp4a FOURCC('m', 'p', '4', 'a') -#define MP4_mp42 FOURCC('m', 'p', '4', '2') -#define MP4_qt FOURCC('q', 't', ' ', ' ') -#define MP4_soun FOURCC('s', 'o', 'u', 'n') -#define MP4_stbl FOURCC('s', 't', 'b', 'l') -#define MP4_stsd FOURCC('s', 't', 's', 'd') -#define MP4_stts FOURCC('s', 't', 't', 's') -#define MP4_trak FOURCC('t', 'r', 'a', 'k') -#define MP4_trkn FOURCC('t', 'r', 'k', 'n') -#define MP4_udta FOURCC('u', 'd', 't', 'a') -#define MP4_extra FOURCC('-', '-', '-', '-') - -/* Read the tag data from an MP4 file, storing up to buffer_size bytes in - * buffer. - */ -static unsigned long read_mp4_tag(int fd, unsigned int size_left, char* buffer, - unsigned int buffer_left) -{ - unsigned int bytes_read = 0; - - if (buffer_left == 0) - { - lseek(fd, size_left, SEEK_CUR); /* Skip everything */ - } - else - { - /* Skip the data tag header - maybe we should parse it properly? */ - lseek(fd, 16, SEEK_CUR); - size_left -= 16; - - if (size_left > buffer_left) - { - read(fd, buffer, buffer_left); - lseek(fd, size_left - buffer_left, SEEK_CUR); - bytes_read = buffer_left; - } - else - { - read(fd, buffer, size_left); - bytes_read = size_left; - } - } - - return bytes_read; -} - -/* Read a string tag from an MP4 file */ -static unsigned int read_mp4_tag_string(int fd, int size_left, char** buffer, - unsigned int* buffer_left, char** dest) -{ - unsigned int bytes_read = read_mp4_tag(fd, size_left, *buffer, - *buffer_left > 0 ? *buffer_left - 1 : 0); - unsigned int length = 0; - - if (bytes_read) - { - /* Do not overwrite already available metadata. Especially when reading - * tags with e.g. multiple genres / artists. This way only the first - * of multiple entries is used, all following are dropped. */ - if (*dest == NULL) - { - (*buffer)[bytes_read] = 0; /* zero-terminate for correct strlen().*/ - length = strlen(*buffer) + 1; - length = MIN(length, ID3V2_MAX_ITEM_SIZE); /* Limit item size. */ - - *dest = *buffer; - (*buffer)[length-1] = 0; /* zero-terminate buffer. */ - *buffer_left -= length; - *buffer += length; - } - } - else - { - *dest = NULL; - } - - return length; -} - -static unsigned int read_mp4_atom(int fd, uint32_t* size, - uint32_t* type, uint32_t size_left) -{ - read_uint32be(fd, size); - read_uint32be(fd, type); - - if (*size == 1) - { - /* FAT32 doesn't support files this big, so something seems to - * be wrong. (64-bit sizes should only be used when required.) - */ - errno = EFBIG; - *type = 0; - return 0; - } - - if (*size > 0) - { - if (*size > size_left) - { - size_left = 0; - } - else - { - size_left -= *size; - } - - *size -= 8; - } - else - { - *size = size_left; - size_left = 0; - } - - return size_left; -} - -static unsigned int read_mp4_length(int fd, uint32_t* size) -{ - unsigned int length = 0; - int bytes = 0; - unsigned char c; - - do - { - read(fd, &c, 1); - bytes++; - (*size)--; - length = (length << 7) | (c & 0x7F); - } - while ((c & 0x80) && (bytes < 4) && (*size > 0)); - - return length; -} - -static bool read_mp4_esds(int fd, struct mp3entry* id3, uint32_t* size) -{ - unsigned char buf[8]; - bool sbr = false; - - lseek(fd, 4, SEEK_CUR); /* Version and flags. */ - read(fd, buf, 1); /* Verify ES_DescrTag. */ - *size -= 5; - - if (*buf == 3) - { - /* read length */ - if (read_mp4_length(fd, size) < 20) - { - return sbr; - } - - lseek(fd, 3, SEEK_CUR); - *size -= 3; - } - else - { - lseek(fd, 2, SEEK_CUR); - *size -= 2; - } - - read(fd, buf, 1); /* Verify DecoderConfigDescrTab. */ - *size -= 1; - - if (*buf != 4) - { - return sbr; - } - - if (read_mp4_length(fd, size) < 13) - { - return sbr; - } - - lseek(fd, 13, SEEK_CUR); /* Skip audio type, bit rates, etc. */ - read(fd, buf, 1); - *size -= 14; - - if (*buf != 5) /* Verify DecSpecificInfoTag. */ - { - return sbr; - } - - { - static const int sample_rates[] = - { - 96000, 88200, 64000, 48000, 44100, 32000, - 24000, 22050, 16000, 12000, 11025, 8000 - }; - unsigned long bits; - unsigned int length; - unsigned int index; - unsigned int type; - - /* Read the (leading part of the) decoder config. */ - length = read_mp4_length(fd, size); - length = MIN(length, *size); - length = MIN(length, sizeof(buf)); - memset(buf, 0, sizeof(buf)); - read(fd, buf, length); - *size -= length; - - /* Maybe time to write a simple read_bits function... */ - - /* Decoder config format: - * Object type - 5 bits - * Frequency index - 4 bits - * Channel configuration - 4 bits - */ - bits = get_long_be(buf); - type = bits >> 27; /* Object type - 5 bits */ - index = (bits >> 23) & 0xf; /* Frequency index - 4 bits */ - - if (index < (sizeof(sample_rates) / sizeof(*sample_rates))) - { - id3->frequency = sample_rates[index]; - } - - if (type == 5) - { - unsigned int old_index = index; - - sbr = true; - index = (bits >> 15) & 0xf; /* Frequency index - 4 bits */ - - if (index == 15) - { - /* 17 bits read so far... */ - bits = get_long_be(&buf[2]); - id3->frequency = (bits >> 7) & 0x00ffffff; - } - else if (index < (sizeof(sample_rates) / sizeof(*sample_rates))) - { - id3->frequency = sample_rates[index]; - } - - if (old_index == index) - { - /* Downsampled SBR */ - id3->frequency *= 2; - } - } - /* Skip 13 bits from above, plus 3 bits, then read 11 bits */ - else if ((length >= 4) && (((bits >> 5) & 0x7ff) == 0x2b7)) - { - /* We found an extensionAudioObjectType */ - type = bits & 0x1f; /* Object type - 5 bits*/ - bits = get_long_be(&buf[4]); - - if (type == 5) - { - sbr = bits >> 31; - - if (sbr) - { - unsigned int old_index = index; - - /* 1 bit read so far */ - index = (bits >> 27) & 0xf; /* Frequency index - 4 bits */ - - if (index == 15) - { - /* 5 bits read so far */ - id3->frequency = (bits >> 3) & 0x00ffffff; - } - else if (index < (sizeof(sample_rates) / sizeof(*sample_rates))) - { - id3->frequency = sample_rates[index]; - } - - if (old_index == index) - { - /* Downsampled SBR */ - id3->frequency *= 2; - } - } - } - } - - if (!sbr && (id3->frequency <= 24000) && (length <= 2)) - { - /* Double the frequency for low-frequency files without a "long" - * DecSpecificConfig header. The file may or may not contain SBR, - * but here we guess it does if the header is short. This can - * fail on some files, but it's the best we can do, short of - * decoding (parts of) the file. - */ - id3->frequency *= 2; - sbr = true; - } - } - - return sbr; -} - -static bool read_mp4_tags(int fd, struct mp3entry* id3, - uint32_t size_left) -{ - uint32_t size; - uint32_t type; - unsigned int buffer_left = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf); - char* buffer = id3->id3v2buf; - bool cwrt = false; - - do - { - size_left = read_mp4_atom(fd, &size, &type, size_left); - - /* DEBUGF("Tag atom: '%c%c%c%c' (%d bytes left)\n", type >> 24 & 0xff, - type >> 16 & 0xff, type >> 8 & 0xff, type & 0xff, size); */ - - switch (type) - { - case MP4_cnam: - read_mp4_tag_string(fd, size, &buffer, &buffer_left, - &id3->title); - break; - - case MP4_cART: - read_mp4_tag_string(fd, size, &buffer, &buffer_left, - &id3->artist); - break; - - case MP4_aART: - read_mp4_tag_string(fd, size, &buffer, &buffer_left, - &id3->albumartist); - break; - - case MP4_cgrp: - read_mp4_tag_string(fd, size, &buffer, &buffer_left, - &id3->grouping); - break; - - case MP4_calb: - read_mp4_tag_string(fd, size, &buffer, &buffer_left, - &id3->album); - break; - - case MP4_cwrt: - read_mp4_tag_string(fd, size, &buffer, &buffer_left, - &id3->composer); - cwrt = false; - break; - - case MP4_ccmt: - read_mp4_tag_string(fd, size, &buffer, &buffer_left, - &id3->comment); - break; - - case MP4_cday: - read_mp4_tag_string(fd, size, &buffer, &buffer_left, - &id3->year_string); - - /* Try to parse it as a year, for the benefit of the database. - */ - if(id3->year_string) - { - id3->year = atoi(id3->year_string); - if (id3->year < 1900) - { - id3->year = 0; - } - } - else - id3->year = 0; - - break; - - case MP4_gnre: - { - unsigned short genre; - - read_mp4_tag(fd, size, (char*) &genre, sizeof(genre)); - id3->genre_string = id3_get_num_genre(betoh16(genre) - 1); - } - break; - - case MP4_cgen: - read_mp4_tag_string(fd, size, &buffer, &buffer_left, - &id3->genre_string); - break; - - case MP4_disk: - { - unsigned short n[2]; - - read_mp4_tag(fd, size, (char*) &n, sizeof(n)); - id3->discnum = betoh16(n[1]); - } - break; - - case MP4_trkn: - { - unsigned short n[2]; - - read_mp4_tag(fd, size, (char*) &n, sizeof(n)); - id3->tracknum = betoh16(n[1]); - } - break; - -#ifdef HAVE_ALBUMART - case MP4_covr: - { - int pos = lseek(fd, 0, SEEK_CUR) + 16; - - read_mp4_tag(fd, size, buffer, 8); - id3->albumart.type = AA_TYPE_UNKNOWN; - if (memcmp(buffer, "\xff\xd8\xff\xe0", 4) == 0) - { - id3->albumart.type = AA_TYPE_JPG; - } - else if (memcmp(buffer, "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8) == 0) - { - id3->albumart.type = AA_TYPE_PNG; - } - - if (id3->albumart.type != AA_TYPE_UNKNOWN) - { - id3->albumart.pos = pos; - id3->albumart.size = size - 16; - id3->has_embedded_albumart = true; - } - } - break; -#endif - - case MP4_extra: - { - char tag_name[TAG_NAME_LENGTH]; - uint32_t sub_size; - - /* "mean" atom */ - read_uint32be(fd, &sub_size); - size -= sub_size; - lseek(fd, sub_size - 4, SEEK_CUR); - /* "name" atom */ - read_uint32be(fd, &sub_size); - size -= sub_size; - lseek(fd, 8, SEEK_CUR); - sub_size -= 12; - - if (sub_size > sizeof(tag_name) - 1) - { - read(fd, tag_name, sizeof(tag_name) - 1); - lseek(fd, sub_size - (sizeof(tag_name) - 1), SEEK_CUR); - tag_name[sizeof(tag_name) - 1] = 0; - } - else - { - read(fd, tag_name, sub_size); - tag_name[sub_size] = 0; - } - - if ((strcasecmp(tag_name, "composer") == 0) && !cwrt) - { - read_mp4_tag_string(fd, size, &buffer, &buffer_left, - &id3->composer); - } - else if (strcasecmp(tag_name, "iTunSMPB") == 0) - { - char value[TAG_VALUE_LENGTH]; - char* value_p = value; - char* any; - unsigned int length = sizeof(value); - - read_mp4_tag_string(fd, size, &value_p, &length, &any); - id3->lead_trim = get_itunes_int32(value, 1); - id3->tail_trim = get_itunes_int32(value, 2); - DEBUGF("AAC: lead_trim %d, tail_trim %d\n", - id3->lead_trim, id3->tail_trim); - } - else if (strcasecmp(tag_name, "musicbrainz track id") == 0) - { - read_mp4_tag_string(fd, size, &buffer, &buffer_left, - &id3->mb_track_id); - } - else if ((strcasecmp(tag_name, "album artist") == 0)) - { - read_mp4_tag_string(fd, size, &buffer, &buffer_left, - &id3->albumartist); - } - else - { - char* any = NULL; - unsigned int length = read_mp4_tag_string(fd, size, - &buffer, &buffer_left, &any); - - if (length > 0) - { - /* Re-use the read buffer as the dest buffer... */ - buffer -= length; - buffer_left += length; - - parse_replaygain(tag_name, buffer, id3); - } - } - } - break; - - default: - lseek(fd, size, SEEK_CUR); - break; - } - } - while ((size_left > 0) && (errno == 0)); - - return true; -} - -static bool read_mp4_container(int fd, struct mp3entry* id3, - uint32_t size_left) -{ - uint32_t size = 0; - uint32_t type = 0; - uint32_t handler = 0; - bool rc = true; - bool done = false; - - do - { - size_left = read_mp4_atom(fd, &size, &type, size_left); - - /* DEBUGF("Atom: '%c%c%c%c' (0x%08lx, %lu bytes left)\n", - (int) ((type >> 24) & 0xff), (int) ((type >> 16) & 0xff), - (int) ((type >> 8) & 0xff), (int) (type & 0xff), - type, size); */ - - switch (type) - { - case MP4_ftyp: - { - uint32_t id; - - read_uint32be(fd, &id); - size -= 4; - - if ((id != MP4_M4A) && (id != MP4_M4B) && (id != MP4_mp42) - && (id != MP4_qt) && (id != MP4_3gp6) && (id != MP4_m4a) - && (id != MP4_isom)) - { - DEBUGF("Unknown MP4 file type: '%c%c%c%c'\n", - (int)(id >> 24 & 0xff), (int)(id >> 16 & 0xff), - (int)(id >> 8 & 0xff), (int)(id & 0xff)); - return false; - } - } - break; - - case MP4_meta: - lseek(fd, 4, SEEK_CUR); /* Skip version */ - size -= 4; - /* Fall through */ - - case MP4_moov: - case MP4_udta: - case MP4_mdia: - case MP4_stbl: - case MP4_trak: - rc = read_mp4_container(fd, id3, size); - size = 0; - break; - - case MP4_ilst: - /* We need at least a size of 8 to read the next atom. */ - if (handler == MP4_mdir && size>8) - { - rc = read_mp4_tags(fd, id3, size); - size = 0; - } - break; - - case MP4_minf: - if (handler == MP4_soun) - { - rc = read_mp4_container(fd, id3, size); - size = 0; - } - break; - - case MP4_stsd: - lseek(fd, 8, SEEK_CUR); - size -= 8; - rc = read_mp4_container(fd, id3, size); - size = 0; - break; - - case MP4_hdlr: - lseek(fd, 8, SEEK_CUR); - read_uint32be(fd, &handler); - size -= 12; - /* DEBUGF(" Handler '%c%c%c%c'\n", handler >> 24 & 0xff, - handler >> 16 & 0xff, handler >> 8 & 0xff,handler & 0xff); */ - break; - - case MP4_stts: - { - uint32_t entries; - unsigned int i; - - /* Reset to false. */ - id3->needs_upsampling_correction = false; - - lseek(fd, 4, SEEK_CUR); - read_uint32be(fd, &entries); - id3->samples = 0; - - for (i = 0; i < entries; i++) - { - uint32_t n; - uint32_t l; - - read_uint32be(fd, &n); - read_uint32be(fd, &l); - - /* Some AAC file use HE profile. In this case the number - * of output samples is doubled to a maximum of 2048 - * samples per frame. This means that files which already - * report a frame size of 2048 in their header will not - * need any further special handling. */ - if (id3->codectype==AFMT_MP4_AAC_HE && l<=1024) - { - id3->samples += n * l * 2; - id3->needs_upsampling_correction = true; - } - else - { - id3->samples += n * l; - } - } - - size = 0; - } - break; - - case MP4_mp4a: - { - uint32_t subsize; - uint32_t subtype; - - /* Move to the next expected mp4 atom. */ - lseek(fd, 28, SEEK_CUR); - read_mp4_atom(fd, &subsize, &subtype, size); - size -= 36; - - if (subtype == MP4_esds) - { - /* Read esds metadata and return if AAC-HE/SBR is used. */ - if (read_mp4_esds(fd, id3, &size)) - id3->codectype = AFMT_MP4_AAC_HE; - else - id3->codectype = AFMT_MP4_AAC; - } - } - break; - - case MP4_alac: - { - uint32_t frequency; - uint32_t subsize; - uint32_t subtype; - - /* Move to the next expected mp4 atom. */ - lseek(fd, 28, SEEK_CUR); - read_mp4_atom(fd, &subsize, &subtype, size); - size -= 36; -#if 0 - /* We might need to parse for the alac metadata atom. */ - while (!((subsize==28) && (subtype==MP4_alac)) && (size>0)) - { - lseek(fd, -7, SEEK_CUR); - read_mp4_atom(fd, &subsize, &subtype, size); - size -= 1; - errno = 0; /* will most likely be set while parsing */ - } -#endif - if (subtype == MP4_alac) - { - lseek(fd, 24, SEEK_CUR); - read_uint32be(fd, &frequency); - size -= 28; - id3->frequency = frequency; - id3->codectype = AFMT_MP4_ALAC; - } - } - break; - - case MP4_mdat: - /* Some AAC files appear to contain additional empty mdat chunks. - Ignore them. */ - if(size == 0) - break; - id3->filesize = size; - if(id3->samples > 0) { - /* We've already seen the moov chunk. */ - done = true; - } - break; - - case MP4_chpl: - { - /* ADDME: add support for real chapters. Right now it's only - * used for Nero's gapless hack */ - uint8_t chapters; - uint64_t timestamp; - - lseek(fd, 8, SEEK_CUR); - read_uint8(fd, &chapters); - size -= 9; - - /* the first chapter will be used as the lead_trim */ - if (chapters > 0) { - read_uint64be(fd, ×tamp); - id3->lead_trim = (timestamp * id3->frequency) / 10000000; - size -= 8; - } - } - break; - - default: - break; - } - - /* Skip final seek. */ - if (!done) - { - lseek(fd, size, SEEK_CUR); - } - } while (rc && (size_left > 0) && (errno == 0) && !done); - - return rc; -} - -bool get_mp4_metadata(int fd, struct mp3entry* id3) -{ - id3->codectype = AFMT_UNKNOWN; - id3->filesize = 0; - errno = 0; - - if (read_mp4_container(fd, id3, filesize(fd)) && (errno == 0) - && (id3->samples > 0) && (id3->frequency > 0) - && (id3->filesize > 0)) - { - if (id3->codectype == AFMT_UNKNOWN) - { - logf("Not an ALAC or AAC file"); - return false; - } - - id3->length = ((int64_t) id3->samples * 1000) / id3->frequency; - - id3->vbr = true; /* ALAC is native VBR, AAC very unlikely is CBR. */ - - if (id3->length <= 0) - { - logf("mp4 length invalid!"); - return false; - } - - id3->bitrate = ((int64_t) id3->filesize * 8) / id3->length; - DEBUGF("MP4 bitrate %d, frequency %ld Hz, length %ld ms\n", - id3->bitrate, id3->frequency, id3->length); - } - else - { - logf("MP4 metadata error"); - DEBUGF("MP4 metadata error. errno %d, samples %ld, frequency %ld, " - "filesize %ld\n", errno, id3->samples, id3->frequency, - id3->filesize); - return false; - } - - return true; -} diff --git a/apps/metadata/mpc.c b/apps/metadata/mpc.c deleted file mode 100644 index 0b75ed0..0000000 --- a/apps/metadata/mpc.c +++ /dev/null @@ -1,220 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Thom Johansen - * Copyright (C) 2010 Andree Buschmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include <string.h> -#include <stdio.h> -#include <inttypes.h> -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "logf.h" -#include "replaygain.h" -#include "fixedpoint.h" - -/* Needed for replay gain and clipping prevention of SV8 files. */ -#define SV8_TO_SV7_CONVERT_GAIN (6482) /* 64.82 * 100, MPC_OLD_GAIN_REF */ -#define SV8_TO_SV7_CONVERT_PEAK (23119) /* 256 * 20 * log10(32768) */ - -static int set_replaygain_sv7(struct mp3entry* id3, - bool album, - long value, - long used) -{ - long gain = (int16_t) ((value >> 16) & 0xffff); - long peak = (uint16_t) (value & 0xffff); - - /* We use a peak value of 0 to indicate a given gain type isn't used. */ - if (peak != 0) { - /* Save the ReplayGain data to id3-structure for further processing. */ - parse_replaygain_int(album, gain * 512 / 100, peak << 9, id3); - } - - return used; -} - -static int set_replaygain_sv8(struct mp3entry* id3, - bool album, - long gain, - long peak, - long used) -{ - gain = (long)(SV8_TO_SV7_CONVERT_GAIN - ((gain*100)/256)); - - /* Transform SV8's logarithmic peak representation to the desired linear - * representation: linear = pow(10, peak/256/20). - * - * FP_BITS = 24 bits = desired fp representation for dsp routines - * FRAC_BITS = 12 bits = resolution used for fp_bits - * fp_factor(peak*(1<<FRAC_BITS)/256, FRAC_BITS) << (FP_BITS-FRAC_BITS) - **/ - peak = (fp_factor((peak-SV8_TO_SV7_CONVERT_PEAK)*16, 12) << 12); - - /* We use a peak value of 0 to indicate a given gain type isn't used. */ - if (peak != 0) { - /* Save the ReplayGain data to id3-structure for further processing. */ - parse_replaygain_int(album, gain * 512 / 100, peak, id3); - } - - return used; -} - -static int sv8_get_size(uint8_t *buffer, int index, uint64_t *p_size) -{ - unsigned char tmp; - uint64_t size = 0; - - do { - tmp = buffer[index++]; - size = (size << 7) | (tmp & 0x7F); - } while((tmp & 0x80)); - - *p_size = size; - return index; -} - -bool get_musepack_metadata(int fd, struct mp3entry *id3) -{ - static const int32_t sfreqs[4] = { 44100, 48000, 37800, 32000 }; - uint32_t header[8]; - uint64_t samples = 0; - int i; - - if (!skip_id3v2(fd, id3)) - return false; - if (read(fd, header, 4*8) != 4*8) return false; - /* Musepack files are little endian, might need swapping */ - for (i = 1; i < 8; i++) - header[i] = letoh32(header[i]); - if (!memcmp(header, "MP+", 3)) { /* Compare to sig "MP+" */ - unsigned int streamversion; - header[0] = letoh32(header[0]); - streamversion = (header[0] >> 24) & 15; - if (streamversion == 7) { - unsigned int gapless = (header[5] >> 31) & 0x0001; - unsigned int last_frame_samples = (header[5] >> 20) & 0x07ff; - unsigned int bufused = 0; - - id3->frequency = sfreqs[(header[2] >> 16) & 0x0003]; - samples = (uint64_t)header[1]*1152; /* 1152 is mpc frame size */ - if (gapless) - samples -= 1152 - last_frame_samples; - else - samples -= 481; /* Musepack subband synth filter delay */ - - bufused = set_replaygain_sv7(id3, false, header[3], bufused); - bufused = set_replaygain_sv7(id3, true , header[4], bufused); - - id3->codectype = AFMT_MPC_SV7; - } else { - return false; /* only SV7 is allowed within a "MP+" signature */ - } - } else if (!memcmp(header, "MPCK", 4)) { /* Compare to sig "MPCK" */ - uint8_t sv8_header[32]; - /* 4 bytes 'MPCK' */ - lseek(fd, 4, SEEK_SET); - if (read(fd, sv8_header, 2) != 2) return false; /* read frame ID */ - if (!memcmp(sv8_header, "SH", 2)) { /* Stream Header ID */ - int32_t k = 0; - uint32_t streamversion; - uint64_t size = 0; /* tag size */ - uint64_t dummy = 0; /* used to dummy read data from header */ - - /* 4 bytes 'MPCK' + 2 'SH' */ - lseek(fd, 6, SEEK_SET); - if (read(fd, sv8_header, 32) != 32) return false; - - /* Read the size of 'SH'-tag */ - k = sv8_get_size(sv8_header, k, &size); - - /* Skip crc32 */ - k += 4; - - /* Read stream version */ - streamversion = sv8_header[k++]; - if (streamversion != 8) return false; /* Only SV8 is allowed. */ - - /* Number of samples */ - k = sv8_get_size(sv8_header, k, &samples); - - /* Number of leading zero-samples */ - k = sv8_get_size(sv8_header, k, &dummy); - - /* Sampling frequency */ - id3->frequency = sfreqs[(sv8_header[k++] >> 5) & 0x0003]; - - /* Number of channels */ - id3->channels = (sv8_header[k++] >> 4) + 1; - - /* Skip to next tag: k = size -2 */ - k = size - 2; - - if (!memcmp(sv8_header+k, "RG", 2)) { /* Replay Gain ID */ - long peak, gain; - int bufused = 0; - - k += 2; /* 2 bytes 'RG' */ - - /* sv8_get_size must be called to skip the right amount of - * bits within the header data. */ - k = sv8_get_size(sv8_header, k, &size); - - /* Read and set replay gain */ - if (sv8_header[k++] == 1) { - /* Title's peak and gain */ - gain = (int16_t) ((sv8_header[k]<<8) + sv8_header[k+1]); k += 2; - peak = (uint16_t)((sv8_header[k]<<8) + sv8_header[k+1]); k += 2; - bufused += set_replaygain_sv8(id3, false, gain, peak, bufused); - - /* Album's peak and gain */ - gain = (int16_t) ((sv8_header[k]<<8) + sv8_header[k+1]); k += 2; - peak = (uint16_t)((sv8_header[k]<<8) + sv8_header[k+1]); k += 2; - bufused += set_replaygain_sv8(id3, true , gain, peak, bufused); - } - } - - id3->codectype = AFMT_MPC_SV8; - } else { - /* No sv8 stream header found */ - return false; - } - } else { - return false; /* SV4-6 is not supported anymore */ - } - - id3->vbr = true; - /* Estimate bitrate, we should probably subtract the various header sizes - here for super-accurate results */ - id3->length = ((int64_t) samples * 1000) / id3->frequency; - - if (id3->length <= 0) - { - logf("mpc length invalid!"); - return false; - } - - id3->filesize = filesize(fd); - id3->bitrate = id3->filesize * 8 / id3->length; - - read_ape_tags(fd, id3); - return true; -} diff --git a/apps/metadata/nsf.c b/apps/metadata/nsf.c deleted file mode 100644 index 2fa6f36..0000000 --- a/apps/metadata/nsf.c +++ /dev/null @@ -1,278 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "rbunicode.h" -#include "string-extra.h" - -/* NOTE: This file was modified to work properly with the new nsf codec based - on Game_Music_Emu */ - -struct NESM_HEADER -{ - uint32_t nHeader; - uint8_t nHeaderExtra; - uint8_t nVersion; - uint8_t nTrackCount; - uint8_t nInitialTrack; - uint16_t nLoadAddress; - uint16_t nInitAddress; - uint16_t nPlayAddress; - uint8_t szGameTitle[32]; - uint8_t szArtist[32]; - uint8_t szCopyright[32]; - uint16_t nSpeedNTSC; - uint8_t nBankSwitch[8]; - uint16_t nSpeedPAL; - uint8_t nNTSC_PAL; - uint8_t nExtraChip; - uint8_t nExpansion[4]; -} __attribute__((packed)); - -struct NSFE_INFOCHUNK -{ - uint16_t nLoadAddress; - uint16_t nInitAddress; - uint16_t nPlayAddress; - uint8_t nIsPal; - uint8_t nExt; - uint8_t nTrackCount; - uint8_t nStartingTrack; -} __attribute__((packed)); - - -#define CHAR4_CONST(a, b, c, d) FOURCC(a, b, c, d) -#define CHUNK_INFO 0x0001 -#define CHUNK_DATA 0x0002 -#define CHUNK_NEND 0x0004 -#define CHUNK_plst 0x0008 -#define CHUNK_time 0x0010 -#define CHUNK_fade 0x0020 -#define CHUNK_tlbl 0x0040 -#define CHUNK_auth 0x0080 -#define CHUNK_BANK 0x0100 - -static bool parse_nsfe(int fd, struct mp3entry *id3) -{ - unsigned int chunks_found = 0; - long track_count = 0; - long playlist_count = 0; - - struct NSFE_INFOCHUNK info; - memset(&info, 0, sizeof(struct NSFE_INFOCHUNK)); - - /* default values */ - info.nTrackCount = 1; - id3->length = 150 * 1000; - - /* begin reading chunks */ - while (!(chunks_found & CHUNK_NEND)) - { - uint32_t chunk_size, chunk_type; - - if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t)) - return false; - - if (read_uint32be(fd, &chunk_type) != (int)sizeof(uint32_t)) - return false; - - switch (chunk_type) - { - /* first three types are mandatory (but don't worry about NEND - anyway) */ - case CHAR4_CONST('I', 'N', 'F', 'O'): - { - if (chunks_found & CHUNK_INFO) - return false; /* only one info chunk permitted */ - - chunks_found |= CHUNK_INFO; - - /* minimum size */ - if (chunk_size < 8) - return false; - - ssize_t size = MIN(sizeof(struct NSFE_INFOCHUNK), chunk_size); - - if (read(fd, &info, size) != size) - return false; - - if (size >= 9) - track_count = info.nTrackCount; - - chunk_size -= size; - break; - } - - case CHAR4_CONST('D', 'A', 'T', 'A'): - { - if (!(chunks_found & CHUNK_INFO)) - return false; - - if (chunks_found & CHUNK_DATA) - return false; /* only one may exist */ - - if (chunk_size < 1) - return false; - - chunks_found |= CHUNK_DATA; - break; - } - - case CHAR4_CONST('N', 'E', 'N', 'D'): - { - /* just end parsing regardless of whether or not this really is the - last chunk/data (but it _should_ be) */ - chunks_found |= CHUNK_NEND; - continue; - } - - /* remaining types are optional */ - - case CHAR4_CONST('a', 'u', 't', 'h'): - { - if (chunks_found & CHUNK_auth) - return false; /* only one may exist */ - - chunks_found |= CHUNK_auth; - - /* szGameTitle, szArtist, szCopyright */ - char ** const ar[] = { &id3->title, &id3->artist, &id3->album }; - - char *p = id3->id3v2buf; - long buf_rem = sizeof (id3->id3v2buf); - unsigned int i; - - for (i = 0; i < ARRAYLEN(ar) && chunk_size && buf_rem; i++) - { - long len = read_string(fd, p, buf_rem, '\0', chunk_size); - - if (len < 0) - return false; - - *ar[i] = p; - p += len; - buf_rem -= len; - - if (chunk_size >= (uint32_t)len) - chunk_size -= len; - else - chunk_size = 0; - } - - break; - } - - case CHAR4_CONST('p', 'l', 's', 't'): - { - if (chunks_found & CHUNK_plst) - return false; /* only one may exist */ - - chunks_found |= CHUNK_plst; - - /* each byte is the index of one track */ - playlist_count = chunk_size; - break; - } - - case CHAR4_CONST('t', 'i', 'm', 'e'): - case CHAR4_CONST('f', 'a', 'd', 'e'): - case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */ - { - /* don't care how many of these there are even though there should - be only one */ - if (!(chunks_found & CHUNK_INFO)) - return false; - - case CHAR4_CONST('B', 'A', 'N', 'K'): - break; - } - - default: /* unknown chunk */ - { - /* check the first byte */ - chunk_type = (uint8_t)chunk_type; - - /* chunk is vital... don't continue */ - if(chunk_type >= 'A' && chunk_type <= 'Z') - return false; - - /* otherwise, just skip it */ - break; - } - } /* end switch */ - - lseek(fd, chunk_size, SEEK_CUR); - } /* end while */ - - if (track_count | playlist_count) - id3->length = MAX(track_count, playlist_count)*1000; - - /* Single subtrack files will be treated differently - by gme's nsf codec */ - if (id3->length <= 1000) id3->length = 150 * 1000; - - /* - * if we exited the while loop without a 'return', we must have hit an NEND - * chunk if this is the case, the file was layed out as it was expected. - * now.. make sure we found both an info chunk, AND a data chunk... since - * these are minimum requirements for a valid NSFE file - */ - return (chunks_found & (CHUNK_INFO | CHUNK_DATA)) == - (CHUNK_INFO | CHUNK_DATA); -} - -static bool parse_nesm(int fd, struct mp3entry *id3) -{ - struct NESM_HEADER hdr; - char *p = id3->id3v2buf; - - lseek(fd, 0, SEEK_SET); - if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) - return false; - - /* Length */ - id3->length = (hdr.nTrackCount > 1 ? hdr.nTrackCount : 150) * 1000; - - /* Title */ - id3->title = p; - p += strlcpy(p, hdr.szGameTitle, 32) + 1; - - /* Artist */ - id3->artist = p; - p += strlcpy(p, hdr.szArtist, 32) + 1; - - /* Copyright (per codec) */ - id3->album = p; - strlcpy(p, hdr.szCopyright, 32); - - return true; -} - -bool get_nsf_metadata(int fd, struct mp3entry* id3) -{ - uint32_t nsf_type; - if (lseek(fd, 0, SEEK_SET) < 0 || - read_uint32be(fd, &nsf_type) != (int)sizeof(nsf_type)) - return false; - - id3->vbr = false; - id3->filesize = filesize(fd); - /* we only render 16 bits, 44.1KHz, Mono */ - id3->bitrate = 706; - id3->frequency = 44100; - - if (nsf_type == CHAR4_CONST('N', 'S', 'F', 'E')) - return parse_nsfe(fd, id3); - else if (nsf_type == CHAR4_CONST('N', 'E', 'S', 'M')) - return parse_nesm(fd, id3); - - /* not a valid format*/ - return false; -} - diff --git a/apps/metadata/ogg.c b/apps/metadata/ogg.c deleted file mode 100644 index 3a3cb29..0000000 --- a/apps/metadata/ogg.c +++ /dev/null @@ -1,215 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "logf.h" - -/* A simple parser to read vital metadata from an Ogg Vorbis file. - * Can also handle parsing Ogg Speex files for metadata. Returns - * false if metadata needed by the codec couldn't be read. - */ -bool get_ogg_metadata(int fd, struct mp3entry* id3) -{ - /* An Ogg File is split into pages, each starting with the string - * "OggS". Each page has a timestamp (in PCM samples) referred to as - * the "granule position". - * - * An Ogg Vorbis has the following structure: - * 1) Identification header (containing samplerate, numchannels, etc) - * 2) Comment header - containing the Vorbis Comments - * 3) Setup header - containing codec setup information - * 4) Many audio packets... - * - * An Ogg Speex has the following structure: - * 1) Identification header (containing samplerate, numchannels, etc) - * Described in this page: (http://www.speex.org/manual2/node7.html) - * 2) Comment header - containing the Vorbis Comments - * 3) Many audio packets. - */ - - /* Use the path name of the id3 structure as a temporary buffer. */ - unsigned char* buf = (unsigned char *)id3->path; - long comment_size; - long remaining = 0; - long last_serial = 0; - long serial, r; - int segments, header_size; - int i; - bool eof = false; - - /* 92 bytes is enough for both Vorbis and Speex headers */ - if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 92) < 92)) - { - return false; - } - - /* All Ogg streams start with OggS */ - if (memcmp(buf, "OggS", 4) != 0) - { - return false; - } - - /* Check for format magic and then get metadata */ - if (memcmp(&buf[29], "vorbis", 6) == 0) - { - id3->codectype = AFMT_OGG_VORBIS; - id3->frequency = get_long_le(&buf[40]); - id3->vbr = true; - - /* Comments are in second Ogg page (byte 58 onwards for Vorbis) */ - if (lseek(fd, 58, SEEK_SET) < 0) - { - return false; - } - } - else if (memcmp(&buf[28], "Speex ", 8) == 0) - { - id3->codectype = AFMT_SPEEX; - id3->frequency = get_slong(&buf[64]); - id3->vbr = get_long_le(&buf[88]); - - header_size = get_long_le(&buf[60]); - - /* Comments are in second Ogg page (byte 108 onwards for Speex) */ - if (lseek(fd, 28 + header_size, SEEK_SET) < 0) - { - return false; - } - } - else - { - /* Unsupported format, try to print the marker, catches Ogg/FLAC at least */ - DEBUGF("Usupported format in Ogg stream: %16s\n", &buf[28]); - return false; - } - - id3->filesize = filesize(fd); - - /* We need to ensure the serial number from this page is the same as the - * one from the last page (since we only support a single bitstream). - */ - serial = get_long_le(&buf[14]); - comment_size = read_vorbis_tags(fd, id3, remaining); - - /* We now need to search for the last page in the file - identified by - * by ('O','g','g','S',0) and retrieve totalsamples. - */ - - /* A page is always < 64 kB */ - if (lseek(fd, -(MIN(64 * 1024, id3->filesize)), SEEK_END) < 0) - { - return false; - } - - remaining = 0; - - while (!eof) - { - r = read(fd, &buf[remaining], MAX_PATH - remaining); - - if (r <= 0) - { - eof = true; - } - else - { - remaining += r; - } - - /* Inefficient (but simple) search */ - i = 0; - - while (i < (remaining - 3)) - { - if ((buf[i] == 'O') && (memcmp(&buf[i], "OggS", 4) == 0)) - { - if (i < (remaining - 17)) - { - /* Note that this only reads the low 32 bits of a - * 64 bit value. - */ - id3->samples = get_long_le(&buf[i + 6]); - last_serial = get_long_le(&buf[i + 14]); - - /* If this page is very small the beginning of the next - * header could be in buffer. Jump near end of this header - * and continue */ - i += 27; - } - else - { - break; - } - } - else - { - i++; - } - } - - if (i < remaining) - { - /* Move the remaining bytes to start of buffer. - * Reuse var 'segments' as it is no longer needed */ - segments = 0; - while (i < remaining) - { - buf[segments++] = buf[i++]; - } - remaining = segments; - } - else - { - /* Discard the rest of the buffer */ - remaining = 0; - } - } - - /* This file has mutiple vorbis bitstreams (or is corrupt). */ - /* FIXME we should display an error here. */ - if (serial != last_serial) - { - logf("serialno mismatch"); - logf("%ld", serial); - logf("%ld", last_serial); - return false; - } - - id3->length = ((int64_t) id3->samples * 1000) / id3->frequency; - if (id3->length <= 0) - { - logf("ogg length invalid!"); - return false; - } - - id3->bitrate = (((int64_t) id3->filesize - comment_size) * 8) / id3->length; - - return true; -} - diff --git a/apps/metadata/oma.c b/apps/metadata/oma.c deleted file mode 100644 index b82c0a4..0000000 --- a/apps/metadata/oma.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Sony OpenMG (OMA) demuxer - * - * Copyright (c) 2008 Maxim Poliakovski - * 2008 Benjamin Larsson - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file oma.c - * This is a demuxer for Sony OpenMG Music files - * - * Known file extensions: ".oma", "aa3" - * The format of such files consists of three parts: - * - "ea3" header carrying overall info and metadata. - * - "EA3" header is a Sony-specific header containing information about - * the OpenMG file: codec type (usually ATRAC, can also be MP3 or WMA), - * codec specific info (packet size, sample rate, channels and so on) - * and DRM related info (file encryption, content id). - * - Sound data organized in packets follow the EA3 header - * (can be encrypted using the Sony DRM!). - * - * LIMITATIONS: This version supports only plain (unencrypted) OMA files. - * If any DRM-protected (encrypted) file is encountered you will get the - * corresponding error message. Try to remove the encryption using any - * Sony software (for example SonicStage). - * CODEC SUPPORT: Only ATRAC3 codec is currently supported! - */ - -#include <stdio.h> -#include <stdlib.h> -#include <inttypes.h> -#include <string.h> -#include "metadata.h" -#include "metadata_parsers.h" - -#define EA3_HEADER_SIZE 96 - -#if 0 -#define DEBUGF printf -#else -#define DEBUGF(...) -#endif - -/* Various helper macros taken from ffmpeg for reading * - * and writing buffers with a specified endianess. */ -# define AV_RB16(x) \ - ((((const uint8_t*)(x))[0] << 8) | \ - ((const uint8_t*)(x))[1]) -# define AV_RB24(x) \ - ((((const uint8_t*)(x))[0] << 16) | \ - (((const uint8_t*)(x))[1] << 8) | \ - ((const uint8_t*)(x))[2]) -# define AV_RB32(x) \ - ((((const uint8_t*)(x))[0] << 24) | \ - (((const uint8_t*)(x))[1] << 16) | \ - (((const uint8_t*)(x))[2] << 8) | \ - ((const uint8_t*)(x))[3]) -# define AV_WL32(p, d) do { \ - ((uint8_t*)(p))[0] = (d); \ - ((uint8_t*)(p))[1] = (d)>>8; \ - ((uint8_t*)(p))[2] = (d)>>16; \ - ((uint8_t*)(p))[3] = (d)>>24; \ - } while(0) -# define AV_WL16(p, d) do { \ - ((uint8_t*)(p))[0] = (d); \ - ((uint8_t*)(p))[1] = (d)>>8; \ - } while(0) - -/* Different codecs that could be present in a Sony OMA * - * container file. */ -enum { - OMA_CODECID_ATRAC3 = 0, - OMA_CODECID_ATRAC3P = 1, - OMA_CODECID_MP3 = 3, - OMA_CODECID_LPCM = 4, - OMA_CODECID_WMA = 5, -}; - -/* FIXME: This functions currently read different file * - * parameters required for decoding. It still * - * does not read the metadata - which should be * - * present in the ea3 (first) header. The * - * metadata in ea3 is stored as a variation of * - * the ID3v2 metadata format. */ -static int oma_read_header(int fd, struct mp3entry* id3) -{ - static const uint16_t srate_tab[6] = {320,441,480,882,960,0}; - int ret, ea3_taglen, EA3_pos, jsflag; - uint32_t codec_params; - int16_t eid; - uint8_t buf[EA3_HEADER_SIZE]; - - ret = read(fd, buf, 10); - if (ret != 10) - return -1; - - ea3_taglen = ((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f); - - EA3_pos = ea3_taglen + 10; - if (buf[5] & 0x10) - EA3_pos += 10; - - lseek(fd, EA3_pos, SEEK_SET); - ret = read(fd, buf, EA3_HEADER_SIZE); - if (ret != EA3_HEADER_SIZE) - return -1; - - if (memcmp(buf, ((const uint8_t[]){'E', 'A', '3'}),3) || buf[4] != 0 || buf[5] != EA3_HEADER_SIZE) { - DEBUGF("Couldn't find the EA3 header !\n"); - return -1; - } - - eid = AV_RB16(&buf[6]); - if (eid != -1 && eid != -128) { - DEBUGF("Encrypted file! Eid: %d\n", eid); - return -1; - } - - codec_params = AV_RB24(&buf[33]); - - switch (buf[32]) { - case OMA_CODECID_ATRAC3: - id3->frequency = srate_tab[(codec_params >> 13) & 7]*100; - if (id3->frequency != 44100) { - DEBUGF("Unsupported sample rate, send sample file to developers: %d\n", id3->frequency); - return -1; - } - - id3->bytesperframe = (codec_params & 0x3FF) * 8; - id3->codectype = AFMT_OMA_ATRAC3; - jsflag = (codec_params >> 17) & 1; /* get stereo coding mode, 1 for joint-stereo */ - - id3->bitrate = id3->frequency * id3->bytesperframe * 8 / (1024 * 1000); - - /* fake the atrac3 extradata (wav format, makes stream copy to wav work) */ - /* ATRAC3 expects and extra-data size of 14 bytes for wav format, and * - * looks for that in the id3v2buf. */ - id3->extradata_size = 14; - AV_WL16(&id3->id3v2buf[0], 1); // always 1 - AV_WL32(&id3->id3v2buf[2], id3->frequency); // samples rate - AV_WL16(&id3->id3v2buf[6], jsflag); // coding mode - AV_WL16(&id3->id3v2buf[8], jsflag); // coding mode - AV_WL16(&id3->id3v2buf[10], 1); // always 1 - AV_WL16(&id3->id3v2buf[12], 0); // always 0 - - id3->channels = 2; - DEBUGF("sample_rate = %d\n", id3->frequency); - DEBUGF("frame_size = %d\n", id3->bytesperframe); - DEBUGF("stereo_coding_mode = %d\n", jsflag); - break; - default: - DEBUGF("Unsupported codec %d!\n",buf[32]); - return -1; - break; - } - - /* Store the the offset of the first audio frame, to be able to seek to it * - * directly in atrac3_oma.codec. */ - id3->first_frame_offset = EA3_pos + EA3_HEADER_SIZE; - return 0; -} - -bool get_oma_metadata(int fd, struct mp3entry* id3) -{ - if(oma_read_header(fd, id3) < 0) - return false; - - /* Currently, there's no means of knowing the duration * - * directly from the the file so we calculate it. */ - id3->filesize = filesize(fd); - id3->length = ((id3->filesize - id3->first_frame_offset) * 8) / id3->bitrate; - return true; -} diff --git a/apps/metadata/rm.c b/apps/metadata/rm.c deleted file mode 100644 index 27f541c..0000000 --- a/apps/metadata/rm.c +++ /dev/null @@ -1,464 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2009 Mohamed Tarek - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include <codecs/librm/rm.h> -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "logf.h" - -/* Uncomment the following line for debugging */ -//#define DEBUG_RM -#ifndef DEBUG_RM -#undef DEBUGF -#define DEBUGF(...) -#endif - -#define ID3V1_OFFSET -128 -#define METADATA_FOOTER_OFFSET -140 - -static inline void print_cook_extradata(RMContext *rmctx) { - - DEBUGF(" cook_version = 0x%08lx\n", rm_get_uint32be(rmctx->codec_extradata)); - DEBUGF(" samples_per_frame_per_channel = %d\n", rm_get_uint16be(&rmctx->codec_extradata[4])); - DEBUGF(" number_of_subbands_in_freq_domain = %d\n", rm_get_uint16be(&rmctx->codec_extradata[6])); - if(rmctx->extradata_size == 16) { - DEBUGF(" joint_stereo_subband_start = %d\n",rm_get_uint16be(&rmctx->codec_extradata[12])); - DEBUGF(" joint_stereo_vlc_bits = %d\n", rm_get_uint16be(&rmctx->codec_extradata[14])); - } -} - - -struct real_object_t -{ - uint32_t fourcc; - uint32_t size; - uint16_t version; -}; - -static int real_read_object_header(int fd, struct real_object_t* obj) -{ - int n; - - if ((n = read_uint32be(fd, &obj->fourcc)) <= 0) - return n; - if ((n = read_uint32be(fd, &obj->size)) <= 0) - return n; - if ((n = read_uint16be(fd, &obj->version)) <= 0) - return n; - - return 1; -} - -#if (defined(SIMULATOR) && defined(DEBUG_RM)) -static char* fourcc2str(uint32_t f) -{ - static char res[5]; - - res[0] = (f & 0xff000000) >> 24; - res[1] = (f & 0xff0000) >> 16; - res[2] = (f & 0xff00) >> 8; - res[3] = (f & 0xff); - res[4] = 0; - - return res; -} -#endif - -static inline int real_read_audio_stream_info(int fd, RMContext *rmctx) -{ - int skipped = 0; - uint32_t version; - struct real_object_t obj; -#ifdef SIMULATOR - uint32_t header_size; - uint16_t flavor; - uint32_t coded_framesize; - uint8_t interleaver_id_length; - uint8_t fourcc_length; -#endif - uint32_t interleaver_id; - uint32_t fourcc = 0; - - memset(&obj,0,sizeof(obj)); - read_uint32be(fd, &version); - skipped += 4; - - DEBUGF(" version=0x%04lx\n",((version >> 16) & 0xff)); - if (((version >> 16) & 0xff) == 3) { - /* Very old version */ - } else { -#ifdef SIMULATOR - real_read_object_header(fd, &obj); - read_uint32be(fd, &header_size); - /* obj.size will be filled with an unknown value, replaced with header_size */ - DEBUGF(" Object: %s, size: %ld bytes, version: 0x%04x\n",fourcc2str(obj.fourcc),header_size,obj.version); - - read_uint16be(fd, &flavor); - read_uint32be(fd, &coded_framesize); -#else - lseek(fd, 20, SEEK_CUR); -#endif - lseek(fd, 12, SEEK_CUR); /* unknown */ - read_uint16be(fd, &rmctx->sub_packet_h); - read_uint16be(fd, &rmctx->block_align); - read_uint16be(fd, &rmctx->sub_packet_size); - lseek(fd, 2, SEEK_CUR); /* unknown */ - skipped += 40; - if (((version >> 16) & 0xff) == 5) - { - lseek(fd, 6, SEEK_CUR); /* unknown */ - skipped += 6; - } - read_uint16be(fd, &rmctx->sample_rate); - lseek(fd, 4, SEEK_CUR); /* unknown */ - read_uint16be(fd, &rmctx->nb_channels); - skipped += 8; - if (((version >> 16) & 0xff) == 4) - { -#ifdef SIMULATOR - read_uint8(fd, &interleaver_id_length); - read_uint32be(fd, &interleaver_id); - read_uint8(fd, &fourcc_length); -#else - lseek(fd, 6, SEEK_CUR); -#endif - read_uint32be(fd, &fourcc); - skipped += 10; - } - if (((version >> 16) & 0xff) == 5) - { - read_uint32be(fd, &interleaver_id); - read_uint32be(fd, &fourcc); - skipped += 8; - } - lseek(fd, 3, SEEK_CUR); /* unknown */ - skipped += 3; - if (((version >> 16) & 0xff) == 5) - { - lseek(fd, 1, SEEK_CUR); /* unknown */ - skipped += 1; - } - - switch(fourcc) { - case FOURCC('c','o','o','k'): - rmctx->codec_type = CODEC_COOK; - read_uint32be(fd, &rmctx->extradata_size); - skipped += 4; - read(fd, rmctx->codec_extradata, rmctx->extradata_size); - skipped += rmctx->extradata_size; - break; - - case FOURCC('r','a','a','c'): - case FOURCC('r','a','c','p'): - rmctx->codec_type = CODEC_AAC; - read_uint32be(fd, &rmctx->extradata_size); - skipped += 4; - read(fd, rmctx->codec_extradata, rmctx->extradata_size); - skipped += rmctx->extradata_size; - break; - - case FOURCC('d','n','e','t'): - rmctx->codec_type = CODEC_AC3; - break; - - case FOURCC('a','t','r','c'): - rmctx->codec_type = CODEC_ATRAC; - read_uint32be(fd, &rmctx->extradata_size); - skipped += 4; - read(fd, rmctx->codec_extradata, rmctx->extradata_size); - skipped += rmctx->extradata_size; - break; - - default: /* Not a supported codec */ - return -1; - } - - DEBUGF(" flavor = %d\n",flavor); - DEBUGF(" coded_frame_size = %ld\n",coded_framesize); - DEBUGF(" sub_packet_h = %d\n",rmctx->sub_packet_h); - DEBUGF(" frame_size = %d\n",rmctx->block_align); - DEBUGF(" sub_packet_size = %d\n",rmctx->sub_packet_size); - DEBUGF(" sample_rate= %d\n",rmctx->sample_rate); - DEBUGF(" channels= %d\n",rmctx->nb_channels); - DEBUGF(" fourcc = %s\n",fourcc2str(fourcc)); - DEBUGF(" codec_extra_data_length = %ld\n",rmctx->extradata_size); - DEBUGF(" codec_extradata :\n"); - if(rmctx->codec_type == CODEC_COOK) { - DEBUGF(" cook_extradata :\n"); - print_cook_extradata(rmctx); - } - - } - - return skipped; -} - -static int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3) -{ - struct real_object_t obj; - int res; - int skipped; - off_t curpos __attribute__((unused)); - uint8_t len; /* Holds a string_length, which is then passed to read_string() */ - -#ifdef SIMULATOR - uint32_t avg_bitrate = 0; - uint32_t max_packet_size; - uint32_t avg_packet_size; - uint32_t packet_count; - uint32_t duration; - uint32_t preroll; - uint32_t index_offset; - uint16_t stream_id; - uint32_t start_time; - uint32_t codec_data_size; -#endif - uint32_t v; - uint32_t max_bitrate; - uint16_t num_streams; - uint32_t next_data_off; - uint8_t header_end; - - memset(&obj,0,sizeof(obj)); - curpos = lseek(fd, 0, SEEK_SET); - res = real_read_object_header(fd, &obj); - - if (obj.fourcc == FOURCC('.','r','a',0xfd)) - { - /* Very old .ra format - not yet supported */ - return -1; - } - else if (obj.fourcc != FOURCC('.','R','M','F')) - { - return -1; - } - - lseek(fd, 8, SEEK_CUR); /* unknown */ - - DEBUGF("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos); - - res = real_read_object_header(fd, &obj); - header_end = 0; - while(res) - { - DEBUGF("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos); - skipped = 10; - if(obj.fourcc == FOURCC('I','N','D','X')) - break; - switch (obj.fourcc) - { - case FOURCC('P','R','O','P'): /* File properties */ - read_uint32be(fd, &max_bitrate); - read_uint32be(fd, &rmctx->bit_rate); /*avg bitrate*/ -#ifdef SIMULATOR - read_uint32be(fd, &max_packet_size); - read_uint32be(fd, &avg_packet_size); - read_uint32be(fd, &packet_count); -#else - lseek(fd, 3*sizeof(uint32_t), SEEK_CUR); -#endif - read_uint32be(fd, &rmctx->duration); -#ifdef SIMULATOR - read_uint32be(fd, &preroll); - read_uint32be(fd, &index_offset); -#else - lseek(fd, 2*sizeof(uint32_t), SEEK_CUR); -#endif - read_uint32be(fd, &rmctx->data_offset); - read_uint16be(fd, &num_streams); - read_uint16be(fd, &rmctx->flags); - skipped += 40; - - DEBUGF(" max_bitrate = %ld\n",max_bitrate); - DEBUGF(" avg_bitrate = %ld\n",rmctx->bit_rate); - DEBUGF(" max_packet_size = %ld\n",max_packet_size); - DEBUGF(" avg_packet_size = %ld\n",avg_packet_size); - DEBUGF(" packet_count = %ld\n",packet_count); - DEBUGF(" duration = %ld\n",rmctx->duration); - DEBUGF(" preroll = %ld\n",preroll); - DEBUGF(" index_offset = %ld\n",index_offset); - DEBUGF(" data_offset = %ld\n",rmctx->data_offset); - DEBUGF(" num_streams = %d\n",num_streams); - DEBUGF(" flags=0x%04x\n",rmctx->flags); - break; - - case FOURCC('C','O','N','T'): - /* Four strings - Title, Author, Copyright, Comment */ - read_uint8(fd,&len); - skipped += (int)read_string(fd, id3->id3v1buf[0], sizeof(id3->id3v1buf[0]), '\0', len); - read_uint8(fd,&len); - skipped += (int)read_string(fd, id3->id3v1buf[1], sizeof(id3->id3v1buf[1]), '\0', len); - read_uint8(fd,&len); - skipped += (int)read_string(fd, id3->id3v1buf[2], sizeof(id3->id3v1buf[2]), '\0', len); - read_uint8(fd,&len); - skipped += (int)read_string(fd, id3->id3v1buf[3], sizeof(id3->id3v1buf[3]), '\0', len); - skipped += 4; - - DEBUGF(" title=\"%s\"\n",id3->id3v1buf[0]); - DEBUGF(" author=\"%s\"\n",id3->id3v1buf[1]); - DEBUGF(" copyright=\"%s\"\n",id3->id3v1buf[2]); - DEBUGF(" comment=\"%s\"\n",id3->id3v1buf[3]); - break; - - case FOURCC('M','D','P','R'): /* Media properties */ -#ifdef SIMULATOR - read_uint16be(fd,&stream_id); - read_uint32be(fd,&max_bitrate); - read_uint32be(fd,&avg_bitrate); - read_uint32be(fd,&max_packet_size); - read_uint32be(fd,&avg_packet_size); - read_uint32be(fd,&start_time); - read_uint32be(fd,&preroll); - read_uint32be(fd,&duration); -#else - lseek(fd, 30, SEEK_CUR); -#endif - skipped += 30; - read_uint8(fd,&len); - skipped += 1; - lseek(fd, len, SEEK_CUR); /* desc */ - skipped += len; - read_uint8(fd,&len); - skipped += 1; -#ifdef SIMULATOR - lseek(fd, len, SEEK_CUR); /* mimetype */ - read_uint32be(fd,&codec_data_size); -#else - lseek(fd, len + 4, SEEK_CUR); -#endif - skipped += len + 4; - read_uint32be(fd,&v); - skipped += 4; - - DEBUGF(" stream_id = 0x%04x\n",stream_id); - DEBUGF(" max_bitrate = %ld\n",max_bitrate); - DEBUGF(" avg_bitrate = %ld\n",avg_bitrate); - DEBUGF(" max_packet_size = %ld\n",max_packet_size); - DEBUGF(" avg_packet_size = %ld\n",avg_packet_size); - DEBUGF(" start_time = %ld\n",start_time); - DEBUGF(" preroll = %ld\n",preroll); - DEBUGF(" duration = %ld\n",duration); - DEBUGF(" codec_data_size = %ld\n",codec_data_size); - DEBUGF(" v=\"%s\"\n", fourcc2str(v)); - - if (v == FOURCC('.','r','a',0xfd)) - { - int temp; - temp= real_read_audio_stream_info(fd, rmctx); - if(temp < 0) - return -1; - else - skipped += temp; - } - else if (v == FOURCC('L','S','D',':')) - { - DEBUGF("Real audio lossless is not supported."); - return -1; - } - else - { - /* We shall not abort with -1 here. *.rm file often seem - * to have a second media properties header that contains - * other metadata. */ - DEBUGF("Unknown header signature :\"%s\"\n", fourcc2str(v)); - } - - - break; - - case FOURCC('D','A','T','A'): - read_uint32be(fd,&rmctx->nb_packets); - skipped += 4; - read_uint32be(fd,&next_data_off); - skipped += 4; - - /*** - * nb_packets correction : - * in some samples, number of packets may not exactly form - * an integer number of scrambling units. This is corrected - * by constructing a partially filled unit out of the few - * remaining samples at the end of decoding. - ***/ - if(rmctx->nb_packets % rmctx->sub_packet_h) - rmctx->nb_packets += rmctx->sub_packet_h - (rmctx->nb_packets % rmctx->sub_packet_h); - - DEBUGF(" data_nb_packets = %ld\n",rmctx->nb_packets); - DEBUGF(" next DATA offset = %ld\n",next_data_off); - header_end = 1; - break; - } - if(header_end) break; - curpos = lseek(fd, obj.size - skipped, SEEK_CUR); - res = real_read_object_header(fd, &obj); - } - - - return 0; -} - - -bool get_rm_metadata(int fd, struct mp3entry* id3) -{ - RMContext *rmctx = (RMContext*) (( (intptr_t)id3->id3v2buf + 3 ) &~ 3); - memset(rmctx,0,sizeof(RMContext)); - if(rm_parse_header(fd, rmctx, id3) < 0) - return false; - - if (!setid3v1title(fd, id3)) { - /* file has no id3v1 tags, use the tags from CONT chunk */ - id3->title = id3->id3v1buf[0]; - id3->artist = id3->id3v1buf[1]; - id3->comment= id3->id3v1buf[3]; - } - - switch(rmctx->codec_type) - { - case CODEC_COOK: - /* Already set, do nothing */ - break; - case CODEC_AAC: - id3->codectype = AFMT_RM_AAC; - break; - - case CODEC_AC3: - id3->codectype = AFMT_RM_AC3; - break; - - case CODEC_ATRAC: - id3->codectype = AFMT_RM_ATRAC3; - break; - } - - id3->channels = rmctx->nb_channels; - id3->extradata_size = rmctx->extradata_size; - id3->bitrate = rmctx->bit_rate / 1000; - id3->frequency = rmctx->sample_rate; - id3->length = rmctx->duration; - id3->filesize = filesize(fd); - return true; -} diff --git a/apps/metadata/sgc.c b/apps/metadata/sgc.c deleted file mode 100644 index 78cacb9..0000000 --- a/apps/metadata/sgc.c +++ /dev/null @@ -1,67 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "rbunicode.h" - -static bool parse_sgc_header(int fd, struct mp3entry* id3) -{ - /* Use the trackname part of the id3 structure as a temporary buffer */ - unsigned char* buf = (unsigned char *)id3->path; - - lseek(fd, 0, SEEK_SET); - if (read(fd, buf, 0xA0) < 0xA0) - return false; - - /* calculate track length with number of tracks */ - id3->length = buf[37] * 1000; - - /* If meta info was found in the m3u skip next step */ - if (id3->title && id3->title[0]) return true; - - char *p = id3->id3v2buf; - - /* Some metadata entries have 32 bytes length */ - /* Game */ - memcpy(p, &buf[64], 32); *(p + 33) = '\0'; - id3->title = p; - p += strlen(p)+1; - - /* Artist */ - memcpy(p, &buf[96], 32); *(p + 33) = '\0'; - id3->artist = p; - p += strlen(p)+1; - - /* Copyright */ - memcpy(p, &buf[128], 32); *(p + 33) = '\0'; - id3->album = p; - p += strlen(p)+1; - return true; -} - - -bool get_sgc_metadata(int fd, struct mp3entry* id3) -{ - uint32_t sgc_type; - if ((lseek(fd, 0, SEEK_SET) < 0) || - read_uint32be(fd, &sgc_type) != (int)sizeof(sgc_type)) - return false; - - id3->vbr = false; - id3->filesize = filesize(fd); - /* we only render 16 bits, 44.1KHz, Stereo */ - id3->bitrate = 706; - id3->frequency = 44100; - - /* Make sure this is an SGC file */ - if (sgc_type != FOURCC('S','G','C',0x1A)) - return false; - - return parse_sgc_header(fd, id3); -} diff --git a/apps/metadata/sid.c b/apps/metadata/sid.c deleted file mode 100644 index 50b879b..0000000 --- a/apps/metadata/sid.c +++ /dev/null @@ -1,89 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "rbunicode.h" - -/* PSID metadata info is available here: - http://www.unusedino.de/ec64/technical/formats/sidplay.html */ -bool get_sid_metadata(int fd, struct mp3entry* id3) -{ - /* Use the trackname part of the id3 structure as a temporary buffer */ - unsigned char* buf = (unsigned char *)id3->path; - char *p; - - - if ((lseek(fd, 0, SEEK_SET) < 0) - || (read(fd, buf, 0x80) < 0x80)) - { - return false; - } - - if ((memcmp(buf, "PSID", 4) != 0)) - { - return false; - } - - p = id3->id3v2buf; - - /* Copy Title (assumed max 0x1f letters + 1 zero byte) */ - id3->title = p; - buf[0x16+0x1f] = 0; - p = iso_decode(&buf[0x16], p, 0, strlen(&buf[0x16])+1); - - /* Copy Artist (assumed max 0x1f letters + 1 zero byte) */ - id3->artist = p; - buf[0x36+0x1f] = 0; - p = iso_decode(&buf[0x36], p, 0, strlen(&buf[0x36])+1); - - /* Copy Year (assumed max 4 letters + 1 zero byte) */ - buf[0x56+0x4] = 0; - id3->year = atoi(&buf[0x56]); - - /* Copy Album (assumed max 0x1f-0x05 letters + 1 zero byte) */ - id3->album = p; - buf[0x56+0x1f] = 0; - iso_decode(&buf[0x5b], p, 0, strlen(&buf[0x5b])+1); - - id3->bitrate = 706; - id3->frequency = 44100; - /* New idea as posted by Marco Alanen (ravon): - * Set the songlength in seconds to the number of subsongs - * so every second represents a subsong. - * Users can then skip the current subsong by seeking - * - * Note: the number of songs is a 16bit value at 0xE, so this code only - * uses the lower 8 bits of the counter. - */ - id3->length = (buf[0xf]-1)*1000; - id3->vbr = false; - id3->filesize = filesize(fd); - - return true; -} diff --git a/apps/metadata/smaf.c b/apps/metadata/smaf.c deleted file mode 100644 index 1b745d3..0000000 --- a/apps/metadata/smaf.c +++ /dev/null @@ -1,470 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2010 Yoshihisa Uchida - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <inttypes.h> -#include <stdio.h> - -#include "string-extra.h" -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "rbunicode.h" -#include "logf.h" - -static const int basebits[4] = { 4, 8, 12, 16 }; - -static const int frequency[5] = { 4000, 8000, 11025, 22050, 44100 }; - -static const int support_codepages[5] = { -#ifdef HAVE_LCD_BITMAP - SJIS, ISO_8859_1, -1, GB_2312, BIG_5, -#else - -1, ISO_8859_1, -1, -1, -1, -#endif -}; - -/* extra codepage */ -#define UCS2 (NUM_CODEPAGES + 1) - -/* support id3 tag */ -#define TAG_TITLE (('S'<<8)|'T') -#define TAG_ARTIST (('A'<<8)|'N') -#define TAG_COMPOSER (('S'<<8)|'W') - -/* convert functions */ -#define CONVERT_SMAF_CHANNELS(c) (((c) >> 7) + 1) - - -static inline int convert_smaf_audio_basebit(unsigned int basebit) -{ - if (basebit > 3) - return 0; - return basebits[basebit]; -} - -static inline int convert_smaf_audio_frequency(unsigned int freq) -{ - if (freq > 4) - return 0; - return frequency[freq]; -} - -static int convert_smaf_codetype(unsigned int codetype) -{ - if (codetype < 5) - return support_codepages[codetype]; - else if (codetype == 0x20 || codetype == 0x24) /* In Rockbox, UCS2 and UTF-16 are same. */ - return UCS2; - else if (codetype == 0x23) - return UTF_8; - else if (codetype == 0xff) - return ISO_8859_1; - return -1; -} - -static void set_length(struct mp3entry *id3, unsigned int ch, unsigned int basebit, - unsigned int numbytes) -{ - int bitspersample = convert_smaf_audio_basebit(basebit); - - if (bitspersample != 0 && id3->frequency != 0) - { - /* Calculate track length [ms] and bitrate [kbit/s] */ - id3->length = (uint64_t)numbytes * 8000LL - / (bitspersample * CONVERT_SMAF_CHANNELS(ch) * id3->frequency); - id3->bitrate = bitspersample * id3->frequency / 1000; - } - - /* output contents/wave data/id3 info (for debug) */ - DEBUGF("contents info ----\n"); - DEBUGF(" TITLE: %s\n", (id3->title)? id3->title : "(NULL)"); - DEBUGF(" ARTIST: %s\n", (id3->artist)? id3->artist : "(NULL)"); - DEBUGF(" COMPOSER: %s\n", (id3->composer)? id3->composer : "(NULL)"); - DEBUGF("wave data info ----\n"); - DEBUGF(" channels: %u\n", CONVERT_SMAF_CHANNELS(ch)); - DEBUGF(" bitspersample: %d\n", bitspersample); - DEBUGF(" numbytes; %u\n", numbytes); - DEBUGF("id3 info ----\n"); - DEBUGF(" frquency: %u\n", (unsigned int)id3->frequency); - DEBUGF(" bitrate: %d\n", id3->bitrate); - DEBUGF(" length: %u\n", (unsigned int)id3->length); -} - -/* contents parse functions */ - -/* Note: - * 1) When the codepage is UTF-8 or UCS2, contents data do not start BOM. - * 2) The byte order of contents data is big endian. - */ - -static void decode2utf8(const unsigned char *src, unsigned char **dst, - int srcsize, int *dstsize, int codepage) -{ - unsigned char tmpbuf[srcsize * 3 + 1]; - unsigned char *p; - int utf8size; - - if (codepage < NUM_CODEPAGES) - p = iso_decode(src, tmpbuf, codepage, srcsize); - else /* codepage == UCS2 */ - p = utf16BEdecode(src, tmpbuf, srcsize); - - *p = '\0'; - - strlcpy(*dst, tmpbuf, *dstsize); - utf8size = (p - tmpbuf) + 1; - if (utf8size > *dstsize) - { - DEBUGF("metadata warning: data length: %d > contents store buffer size: %d\n", - utf8size, *dstsize); - utf8size = *dstsize; - } - *dst += utf8size; - *dstsize -= utf8size; -} - -static int read_audio_track_contets(int fd, int codepage, unsigned char **dst, - int *dstsize) -{ - /* value length <= 256 bytes */ - unsigned char buf[256]; - unsigned char *p = buf; - unsigned char *q = buf; - int datasize; - - read(fd, buf, 256); - - while (p - buf < 256 && *p != ',') - { - /* skip yen mark */ - if (codepage != UCS2) - { - if (*p == '\\') - p++; - } - else if (*p == '\0' && *(p+1) == '\\') - p += 2; - - if (*p > 0x7f) - { - if (codepage == UTF_8) - { - while ((*p & MASK) != COMP) - *q++ = *p++; - } -#ifdef HAVE_LCD_BITMAP - else if (codepage == SJIS) - { - if (*p <= 0xa0 || *p >= 0xe0) - *q++ = *p++; - } -#endif - } - - *q++ = *p++; - if (codepage == UCS2) - *q++ = *p++; - } - datasize = p - buf + 1; - lseek(fd, datasize - 256, SEEK_CUR); - - if (dst != NULL) - decode2utf8(buf, dst, q - buf, dstsize, codepage); - - return datasize; -} - -static void read_score_track_contets(int fd, int codepage, int datasize, - unsigned char **dst, int *dstsize) -{ - unsigned char buf[datasize]; - - read(fd, buf, datasize); - decode2utf8(buf, dst, datasize, dstsize, codepage); -} - -/* traverse chunk functions */ - -static unsigned int search_chunk(int fd, const unsigned char *name, int nlen) -{ - unsigned char buf[8]; - unsigned int chunksize; - - while (read(fd, buf, 8) > 0) - { - chunksize = get_long_be(buf + 4); - if (memcmp(buf, name, nlen) == 0) - return chunksize; - - lseek(fd, chunksize, SEEK_CUR); - } - DEBUGF("metadata error: missing '%s' chunk\n", name); - return 0; -} - -static bool parse_smaf_audio_track(int fd, struct mp3entry *id3, unsigned int datasize) -{ - /* temporary buffer */ - unsigned char *tmp = (unsigned char*)id3->path; - /* contents stored buffer */ - unsigned char *buf = id3->id3v2buf; - int bufsize = sizeof(id3->id3v2buf); - - unsigned int chunksize = datasize; - int valsize; - - int codepage; - - /* parse contents info */ - read(fd, tmp, 5); - codepage = convert_smaf_codetype(tmp[2]); - if (codepage < 0) - { - DEBUGF("metadata error: smaf unsupport codetype: %d\n", tmp[2]); - return false; - } - - datasize -= 5; - while ((id3->title == NULL || id3->artist == NULL || id3->composer == NULL) - && (datasize > 0 && bufsize > 0)) - { - if (read(fd, tmp, 3) <= 0) - return false; - - if (tmp[2] != ':') - { - DEBUGF("metadata error: illegal tag: %c%c%c\n", tmp[0], tmp[1], tmp[2]); - return false; - } - switch ((tmp[0]<<8)|tmp[1]) - { - case TAG_TITLE: - id3->title = buf; - valsize = read_audio_track_contets(fd, codepage, &buf, &bufsize); - break; - case TAG_ARTIST: - id3->artist = buf; - valsize = read_audio_track_contets(fd, codepage, &buf, &bufsize); - break; - case TAG_COMPOSER: - id3->composer = buf; - valsize = read_audio_track_contets(fd, codepage, &buf, &bufsize); - break; - default: - valsize = read_audio_track_contets(fd, codepage, NULL, &bufsize); - break; - } - datasize -= (valsize + 3); - } - - /* search PCM Audio Track Chunk */ - lseek(fd, 16 + chunksize, SEEK_SET); - - chunksize = search_chunk(fd, "ATR", 3); - if (chunksize == 0) - { - DEBUGF("metadata error: missing PCM Audio Track Chunk\n"); - return false; - } - - /* - * get format - * tmp - * +0: Format Type - * +1: Sequence Type - * +2: bit 7 0:mono/1:stereo, bit 4-6 format, bit 0-3: frequency - * +3: bit 4-7: base bit - * +4: TimeBase_D - * +5: TimeBase_G - * - * Note: If PCM Audio Track does not include Sequence Data Chunk, - * tmp+6 is the start position of Wave Data Chunk. - */ - read(fd, tmp, 6); - - /* search Wave Data Chunk */ - chunksize = search_chunk(fd, "Awa", 3); - if (chunksize == 0) - { - DEBUGF("metadata error: missing Wave Data Chunk\n"); - return false; - } - - /* set track length and bitrate */ - id3->frequency = convert_smaf_audio_frequency(tmp[2] & 0x0f); - set_length(id3, tmp[2], tmp[3] >> 4, chunksize); - return true; -} - -static bool parse_smaf_score_track(int fd, struct mp3entry *id3) -{ - /* temporary buffer */ - unsigned char *tmp = (unsigned char*)id3->path; - unsigned char *p = tmp; - /* contents stored buffer */ - unsigned char *buf = id3->id3v2buf; - int bufsize = sizeof(id3->id3v2buf); - - unsigned int chunksize; - unsigned int datasize; - int valsize; - - int codepage; - - /* parse Optional Data Chunk */ - read(fd, tmp, 21); - if (memcmp(tmp + 5, "OPDA", 4) != 0) - { - DEBUGF("metadata error: missing Optional Data Chunk\n"); - return false; - } - - /* Optional Data Chunk size */ - chunksize = get_long_be(tmp + 9); - - /* parse Data Chunk */ - if (memcmp(tmp + 13, "Dch", 3) != 0) - { - DEBUGF("metadata error: missing Data Chunk\n"); - return false; - } - - codepage = convert_smaf_codetype(tmp[16]); - if (codepage < 0) - { - DEBUGF("metadata error: smaf unsupport codetype: %d\n", tmp[16]); - return false; - } - - /* Data Chunk size */ - datasize = get_long_be(tmp + 17); - while ((id3->title == NULL || id3->artist == NULL || id3->composer == NULL) - && (datasize > 0 && bufsize > 0)) - { - if (read(fd, tmp, 4) <= 0) - return false; - - valsize = (tmp[2] << 8) | tmp[3]; - datasize -= (valsize + 4); - switch ((tmp[0]<<8)|tmp[1]) - { - case TAG_TITLE: - id3->title = buf; - read_score_track_contets(fd, codepage, valsize, &buf, &bufsize); - break; - case TAG_ARTIST: - id3->artist = buf; - read_score_track_contets(fd, codepage, valsize, &buf, &bufsize); - break; - case TAG_COMPOSER: - id3->composer = buf; - read_score_track_contets(fd, codepage, valsize, &buf, &bufsize); - break; - default: - lseek(fd, valsize, SEEK_CUR); - break; - } - } - - /* search Score Track Chunk */ - lseek(fd, 29 + chunksize, SEEK_SET); - - if (search_chunk(fd, "MTR", 3) == 0) - { - DEBUGF("metadata error: missing Score Track Chunk\n"); - return false; - } - - /* - * search next chunk - * usually, next chunk ('M***') found within 40 bytes. - */ - chunksize = 40; - read(fd, tmp, chunksize); - - tmp[chunksize] = 'M'; /* stopper */ - while (*p != 'M') - p++; - - chunksize -= (p - tmp); - if (chunksize == 0) - { - DEBUGF("metadata error: missing Score Track Stream PCM Data Chunk"); - return false; - } - - /* search Score Track Stream PCM Data Chunk */ - lseek(fd, -chunksize, SEEK_CUR); - if (search_chunk(fd, "Mtsp", 4) == 0) - { - DEBUGF("metadata error: missing Score Track Stream PCM Data Chunk\n"); - return false; - } - - /* - * parse Score Track Stream Wave Data Chunk - * tmp - * +4-7: chunk size (WaveType(3bytes) + wave data count) - * +8: bit 7 0:mono/1:stereo, bit 4-6 format, bit 0-3: base bit - * +9: frequency (MSB) - * +10: frequency (LSB) - */ - read(fd, tmp, 11); - if (memcmp(tmp, "Mwa", 3) != 0) - { - DEBUGF("metadata error: missing Score Track Stream Wave Data Chunk\n"); - return false; - } - - /* set track length and bitrate */ - id3->frequency = (tmp[9] << 8) | tmp[10]; - set_length(id3, tmp[8], tmp[8] & 0x0f, get_long_be(tmp + 4) - 3); - return true; -} - -bool get_smaf_metadata(int fd, struct mp3entry* id3) -{ - /* temporary buffer */ - unsigned char *tmp = (unsigned char *)id3->path; - unsigned int chunksize; - - id3->title = NULL; - id3->artist = NULL; - id3->composer = NULL; - - id3->vbr = false; /* All SMAF files are CBR */ - id3->filesize = filesize(fd); - - /* check File Chunk and Contents Info Chunk */ - lseek(fd, 0, SEEK_SET); - read(fd, tmp, 16); - if ((memcmp(tmp, "MMMD", 4) != 0) || (memcmp(tmp + 8, "CNTI", 4) != 0)) - { - DEBUGF("metadata error: does not smaf format\n"); - return false; - } - - chunksize = get_long_be(tmp + 12); - if (chunksize > 5) - return parse_smaf_audio_track(fd, id3, chunksize); - - return parse_smaf_score_track(fd, id3); -} diff --git a/apps/metadata/spc.c b/apps/metadata/spc.c deleted file mode 100644 index 1c02062..0000000 --- a/apps/metadata/spc.c +++ /dev/null @@ -1,130 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "debug.h" -#include "rbunicode.h" - -bool get_spc_metadata(int fd, struct mp3entry* id3) -{ - /* Use the trackname part of the id3 structure as a temporary buffer */ - unsigned char * buf = (unsigned char *)id3->path; - char * p; - - unsigned long length; - unsigned long fade; - bool isbinary = true; - int i; - - /* try to get the ID666 tag */ - if ((lseek(fd, 0x2e, SEEK_SET) < 0) - || (read(fd, buf, 0xD2) < 0xD2)) - { - DEBUGF("lseek or read failed\n"); - return false; - } - - p = id3->id3v2buf; - - id3->title = p; - buf[31] = 0; - p = iso_decode(buf, p, 0, 32); - buf += 32; - - id3->album = p; - buf[31] = 0; - p = iso_decode(buf, p, 0, 32); - buf += 48; - - id3->comment = p; - buf[31] = 0; - p = iso_decode(buf, p, 0, 32); - buf += 32; - - /* Date check */ - if(buf[2] == '/' && buf[5] == '/') - isbinary = false; - - /* Reserved bytes check */ - if(buf[0xD2 - 0x2E - 112] >= '0' && - buf[0xD2 - 0x2E - 112] <= '9' && - buf[0xD3 - 0x2E - 112] == 0x00) - isbinary = false; - - /* is length & fade only digits? */ - for (i=0;i<8 && ( - (buf[0xA9 - 0x2E - 112+i]>='0'&&buf[0xA9 - 0x2E - 112+i]<='9') || - buf[0xA9 - 0x2E - 112+i]=='\0'); - i++); - if (i==8) isbinary = false; - - if(isbinary) { - id3->year = buf[0] | (buf[1]<<8); - buf += 11; - - length = (buf[0] | (buf[1]<<8) | (buf[2]<<16)) * 1000; - buf += 3; - - fade = (buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24)); - buf += 4; - } else { - char tbuf[6]; - - buf += 6; - buf[4] = 0; - id3->year = atoi(buf); - buf += 5; - - memcpy(tbuf, buf, 3); - tbuf[3] = 0; - length = atoi(tbuf) * 1000; - buf += 3; - - memcpy(tbuf, buf, 5); - tbuf[5] = 0; - fade = atoi(tbuf); - buf += 5; - } - - id3->artist = p; - buf[31] = 0; - iso_decode(buf, p, 0, 32); - - if (length==0) { - length=3*60*1000; /* 3 minutes */ - fade=5*1000; /* 5 seconds */ - } - - id3->length = length+fade; - - id3->filesize = filesize(fd); - id3->genre_string = id3_get_num_genre(36); - - return true; -} diff --git a/apps/metadata/tta.c b/apps/metadata/tta.c deleted file mode 100644 index 1d3d95f..0000000 --- a/apps/metadata/tta.c +++ /dev/null @@ -1,123 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2010 Yoshihisa Uchida - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "logf.h" - -#define TTA1_SIGN 0x31415454 - -#define TTA_HEADER_ID 0 -#define TTA_HEADER_AUDIO_FORMAT (TTA_HEADER_ID + sizeof(unsigned int)) -#define TTA_HEADER_NUM_CHANNELS (TTA_HEADER_AUDIO_FORMAT + sizeof(unsigned short)) -#define TTA_HEADER_BITS_PER_SAMPLE (TTA_HEADER_NUM_CHANNELS + sizeof(unsigned short)) -#define TTA_HEADER_SAMPLE_RATE (TTA_HEADER_BITS_PER_SAMPLE + sizeof(unsigned short)) -#define TTA_HEADER_DATA_LENGTH (TTA_HEADER_SAMPLE_RATE + sizeof(unsigned int)) -#define TTA_HEADER_CRC32 (TTA_HEADER_DATA_LENGTH + sizeof(unsigned int)) -#define TTA_HEADER_SIZE (TTA_HEADER_CRC32 + sizeof(unsigned int)) - -#define TTA_HEADER_GETTER_ID(x) get_long_le(x) -#define TTA_HEADER_GETTER_AUDIO_FORMAT(x) get_short_le(x) -#define TTA_HEADER_GETTER_NUM_CHANNELS(x) get_short_le(x) -#define TTA_HEADER_GETTER_BITS_PER_SAMPLE(x) get_short_le(x) -#define TTA_HEADER_GETTER_SAMPLE_RATE(x) get_long_le(x) -#define TTA_HEADER_GETTER_DATA_LENGTH(x) get_long_le(x) -#define TTA_HEADER_GETTER_CRC32(x) get_long_le(x) - -#define GET_HEADER(x, tag) TTA_HEADER_GETTER_ ## tag((x) + TTA_HEADER_ ## tag) - -static void read_id3_tags(int fd, struct mp3entry* id3) -{ - id3->title = NULL; - id3->filesize = filesize(fd); - id3->id3v2len = getid3v2len(fd); - id3->tracknum = 0; - id3->discnum = 0; - id3->vbr = false; /* All TTA files are CBR */ - - /* first get id3v2 tags. if no id3v2 tags ware found, get id3v1 tags */ - if (id3->id3v2len) - { - setid3v2title(fd, id3); - id3->first_frame_offset = id3->id3v2len; - return; - } - setid3v1title(fd, id3); -} - -bool get_tta_metadata(int fd, struct mp3entry* id3) -{ - unsigned char ttahdr[TTA_HEADER_SIZE]; - unsigned int datasize; - unsigned int origsize; - int bps; - - lseek(fd, 0, SEEK_SET); - - /* read id3 tags */ - read_id3_tags(fd, id3); - lseek(fd, id3->id3v2len, SEEK_SET); - - /* read TTA header */ - if (read(fd, ttahdr, TTA_HEADER_SIZE) < 0) - return false; - - /* check for TTA3 signature */ - if ((GET_HEADER(ttahdr, ID)) != TTA1_SIGN) - return false; - - /* skip check CRC */ - - id3->channels = (GET_HEADER(ttahdr, NUM_CHANNELS)); - id3->frequency = (GET_HEADER(ttahdr, SAMPLE_RATE)); - id3->length = ((GET_HEADER(ttahdr, DATA_LENGTH)) / id3->frequency) * 1000LL; - bps = (GET_HEADER(ttahdr, BITS_PER_SAMPLE)); - - datasize = id3->filesize - id3->first_frame_offset; - origsize = (GET_HEADER(ttahdr, DATA_LENGTH)) * ((bps + 7) / 8) * id3->channels; - - id3->bitrate = (int) ((uint64_t) datasize * id3->frequency * id3->channels * bps - / (origsize * 1000LL)); - - /* output header info (for debug) */ - DEBUGF("TTA header info ----\n"); - DEBUGF("id: %x\n", (unsigned int)(GET_HEADER(ttahdr, ID))); - DEBUGF("channels: %d\n", id3->channels); - DEBUGF("frequency: %ld\n", id3->frequency); - DEBUGF("length: %ld\n", id3->length); - DEBUGF("bitrate: %d\n", id3->bitrate); - DEBUGF("bits per sample: %d\n", bps); - DEBUGF("compressed size: %d\n", datasize); - DEBUGF("original size: %d\n", origsize); - DEBUGF("id3----\n"); - DEBUGF("artist: %s\n", id3->artist); - DEBUGF("title: %s\n", id3->title); - DEBUGF("genre: %s\n", id3->genre_string); - - return true; -} diff --git a/apps/metadata/vgm.c b/apps/metadata/vgm.c deleted file mode 100644 index 9ea95b3..0000000 --- a/apps/metadata/vgm.c +++ /dev/null @@ -1,195 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "rbunicode.h" - -/* Ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */ - -typedef unsigned char byte; - -enum { header_size = 0x40 }; -enum { max_field = 64 }; - -struct header_t -{ - char tag [4]; - byte data_size [4]; - byte version [4]; - byte psg_rate [4]; - byte ym2413_rate [4]; - byte gd3_offset [4]; - byte track_duration [4]; - byte loop_offset [4]; - byte loop_duration [4]; - byte frame_rate [4]; - byte noise_feedback [2]; - byte noise_width; - byte unused1; - byte ym2612_rate [4]; - byte ym2151_rate [4]; - byte data_offset [4]; - byte unused2 [8]; -}; - -static byte const* skip_gd3_str( byte const* in, byte const* end ) -{ - while ( end - in >= 2 ) - { - in += 2; - if ( !(in [-2] | in [-1]) ) - break; - } - return in; -} - -static byte const* get_gd3_str( byte const* in, byte const* end, char* field ) -{ - byte const* mid = skip_gd3_str( in, end ); - int len = (mid - in) / 2 - 1; - if ( field && len > 0 ) - { - len = len < (int) max_field ? len : (int) max_field; - - field [len] = 0; - /* Conver to utf8 */ - utf16LEdecode( in, field, len ); - - /* Copy string back to id3v2buf */ - strcpy( (char*) in, field ); - } - return mid; -} - -static byte const* get_gd3_pair( byte const* in, byte const* end, char* field ) -{ - return skip_gd3_str( get_gd3_str( in, end, field ), end ); -} - -static void parse_gd3( byte const* in, byte const* end, struct mp3entry* id3 ) -{ - char* p = id3->path; - id3->title = (char *) in; - in = get_gd3_pair( in, end, p ); /* Song */ - - id3->album = (char *) in; - in = get_gd3_pair( in, end, p ); /* Game */ - - in = get_gd3_pair( in, end, NULL ); /* System */ - - id3->artist = (char *) in; - in = get_gd3_pair( in, end, p ); /* Author */ - -#if MEMORYSIZE > 2 - in = get_gd3_str ( in, end, NULL ); /* Copyright */ - in = get_gd3_pair( in, end, NULL ); /* Dumper */ - - id3->comment = (char *) in; - in = get_gd3_str ( in, end, p ); /* Comment */ -#endif -} - -int const gd3_header_size = 12; - -static long check_gd3_header( byte* h, long remain ) -{ - if ( remain < gd3_header_size ) return 0; - if ( memcmp( h, "Gd3 ", 4 ) ) return 0; - if ( get_long_le( h + 4 ) >= 0x200 ) return 0; - - long gd3_size = get_long_le( h + 8 ); - if ( gd3_size > remain - gd3_header_size ) - gd3_size = remain - gd3_header_size; - - return gd3_size; -} - -static void get_vgm_length( struct header_t* h, struct mp3entry* id3 ) -{ - long length = get_long_le( h->track_duration ) * 10 / 441; - if ( length > 0 ) - { - long loop_length = 0, intro_length = 0; - long loop = get_long_le( h->loop_duration ); - if ( loop > 0 && get_long_le( h->loop_offset ) ) - { - loop_length = loop * 10 / 441; - intro_length = length - loop_length; - } - else - { - intro_length = length; /* make it clear that track is no longer than length */ - loop_length = 0; - } - - id3->length = intro_length + 2 * loop_length; /* intro + 2 loops */ - return; - } - - id3->length = 150 * 1000; /* 2.5 minutes */ -} - -bool get_vgm_metadata(int fd, struct mp3entry* id3) -{ - /* Use the id3v2 part of the id3 structure as a temporary buffer */ - unsigned char* buf = (unsigned char *)id3->id3v2buf; - int read_bytes; - - memset(buf, 0, ID3V2_BUF_SIZE); - if ((lseek(fd, 0, SEEK_SET) < 0) - || ((read_bytes = read(fd, buf, header_size)) < header_size)) - { - return false; - } - - id3->vbr = false; - id3->filesize = filesize(fd); - - id3->bitrate = 706; - id3->frequency = 44100; - - /* If file is gzipped, will get metadata later */ - if (memcmp(buf, "Vgm ", 4)) - { - /* We must set a default song length here because - the codec can't do it anymore */ - id3->length = 150 * 1000; /* 2.5 minutes */ - return true; - } - - /* Get song length from header */ - struct header_t* header = (struct header_t*) buf; - get_vgm_length( header, id3 ); - - long gd3_offset = get_long_le( header->gd3_offset ) - 0x2C; - - /* No gd3 tag found */ - if ( gd3_offset < 0 ) - return true; - - /* Seek to gd3 offset and read as - many bytes posible */ - gd3_offset = id3->filesize - (header_size + gd3_offset); - if ((lseek(fd, -gd3_offset, SEEK_END) < 0) - || ((read_bytes = read(fd, buf, ID3V2_BUF_SIZE)) <= 0)) - return true; - - byte* gd3 = buf; - long gd3_size = check_gd3_header( gd3, read_bytes ); - - /* GD3 tag is zero */ - if ( gd3_size == 0 ) - return true; - - /* Finally, parse gd3 tag */ - if ( gd3 ) - parse_gd3( gd3 + gd3_header_size, gd3 + read_bytes, id3 ); - - return true; -} diff --git a/apps/metadata/vorbis.c b/apps/metadata/vorbis.c deleted file mode 100644 index 58bd781..0000000 --- a/apps/metadata/vorbis.c +++ /dev/null @@ -1,381 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "structec.h" - -/* Define LOGF_ENABLE to enable logf output in this file */ -/*#define LOGF_ENABLE*/ -#include "logf.h" - -struct file -{ - int fd; - bool packet_ended; - long packet_remaining; -}; - - -/* Read an Ogg page header. file->packet_remaining is set to the size of the - * first packet on the page; file->packet_ended is set to true if the packet - * ended on the current page. Returns true if the page header was - * successfully read. - */ -static bool file_read_page_header(struct file* file) -{ - unsigned char buffer[64]; - ssize_t table_left; - - /* Size of page header without segment table */ - if (read(file->fd, buffer, 27) != 27) - { - return false; - } - - if (memcmp("OggS", buffer, 4)) - { - return false; - } - - /* Skip pattern (4), version (1), flags (1), granule position (8), - * serial (4), pageno (4), checksum (4) - */ - table_left = buffer[26]; - file->packet_remaining = 0; - - /* Read segment table for the first packet */ - do - { - ssize_t count = MIN(sizeof(buffer), (size_t) table_left); - int i; - - if (read(file->fd, buffer, count) < count) - { - return false; - } - - table_left -= count; - - for (i = 0; i < count; i++) - { - file->packet_remaining += buffer[i]; - - if (buffer[i] < 255) - { - file->packet_ended = true; - - /* Skip remainder of the table */ - if (lseek(file->fd, table_left, SEEK_CUR) < 0) - { - return false; - } - - table_left = 0; - break; - } - } - } - while (table_left > 0); - - return true; -} - - -/* Read (up to) buffer_size of data from the file. If buffer is NULL, just - * skip ahead buffer_size bytes (like lseek). Returns number of bytes read, - * 0 if there is no more data to read (in the packet or the file), < 0 if a - * read error occurred. - */ -static ssize_t file_read(struct file* file, void* buffer, size_t buffer_size) -{ - ssize_t done = 0; - ssize_t count = -1; - - do - { - if (file->packet_remaining <= 0) - { - if (file->packet_ended) - { - break; - } - - if (!file_read_page_header(file)) - { - count = -1; - break; - } - } - - count = MIN(buffer_size, (size_t) file->packet_remaining); - - if (buffer) - { - count = read(file->fd, buffer, count); - } - else - { - if (lseek(file->fd, count, SEEK_CUR) < 0) - { - count = -1; - } - } - - if (count <= 0) - { - break; - } - - if (buffer) - { - buffer += count; - } - - buffer_size -= count; - done += count; - file->packet_remaining -= count; - } - while (buffer_size > 0); - - return (count < 0 ? count : done); -} - - -/* Read an int32 from file. Returns false if a read error occurred. - */ -static bool file_read_int32(struct file* file, int32_t* value) -{ - char buf[sizeof(int32_t)]; - - if (file_read(file, buf, sizeof(buf)) < (ssize_t) sizeof(buf)) - { - return false; - } - - *value = get_long_le(buf); - return true; -} - - -/* Read a string from the file. Read up to buffer_size bytes, or, if eos - * != -1, until the eos character is found (eos is not stored in buf, - * unless it is nil). Writes up to buffer_size chars to buf, always - * terminating with a nil. Returns number of chars read or < 0 if a read - * error occurred. - * - * Unfortunately this is a slightly modified copy of read_string() in - * metadata_common.c... - */ -static long file_read_string(struct file* file, char* buffer, - long buffer_size, int eos, long size) -{ - long read_bytes = 0; - - while (size > 0) - { - char c; - - if (file_read(file, &c, 1) != 1) - { - read_bytes = -1; - break; - } - - read_bytes++; - size--; - - if ((eos != -1) && (eos == (unsigned char) c)) - { - break; - } - - if (buffer_size > 1) - { - *buffer++ = c; - buffer_size--; - } - else if (eos == -1) - { - /* No point in reading any more, skip remaining data */ - if (file_read(file, NULL, size) < 0) - { - read_bytes = -1; - } - else - { - read_bytes += size; - } - - break; - } - } - - *buffer = 0; - return read_bytes; -} - - -/* Init struct file for reading from fd. type is the AFMT_* codec type of - * the file, and determines if Ogg pages are to be read. remaining is the - * max amount to read if codec type is FLAC; it is ignored otherwise. - * Returns true if the file was successfully initialized. - */ -static bool file_init(struct file* file, int fd, int type, int remaining) -{ - memset(file, 0, sizeof(*file)); - file->fd = fd; - - if (type == AFMT_OGG_VORBIS || type == AFMT_SPEEX) - { - if (!file_read_page_header(file)) - { - return false; - } - } - - if (type == AFMT_OGG_VORBIS) - { - char buffer[7]; - - /* Read packet header (type and id string) */ - if (file_read(file, buffer, sizeof(buffer)) < (ssize_t) sizeof(buffer)) - { - return false; - } - - /* The first byte of a packet is the packet type; comment packets - * are type 3. - */ - if (buffer[0] != 3) - { - return false; - } - } - else if (type == AFMT_FLAC) - { - file->packet_remaining = remaining; - file->packet_ended = true; - } - - return true; -} - - -/* Read the items in a Vorbis comment packet. For Ogg files, the file must - * be located on a page start, for other files, the beginning of the comment - * data (i.e., the vendor string length). Returns total size of the - * comments, or 0 if there was a read error. - */ -long read_vorbis_tags(int fd, struct mp3entry *id3, - long tag_remaining) -{ - struct file file; - char *buf = id3->id3v2buf; - int32_t comment_count; - int32_t len; - long comment_size = 0; - int buf_remaining = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf); - int i; - - if (!file_init(&file, fd, id3->codectype, tag_remaining)) - { - return 0; - } - - /* Skip vendor string */ - - if (!file_read_int32(&file, &len) || (file_read(&file, NULL, len) < 0)) - { - return 0; - } - - if (!file_read_int32(&file, &comment_count)) - { - return 0; - } - - comment_size += 4 + len + 4; - - for (i = 0; i < comment_count && file.packet_remaining > 0; i++) - { - char name[TAG_NAME_LENGTH]; - int32_t read_len; - - if (!file_read_int32(&file, &len)) - { - return 0; - } - - comment_size += 4 + len; - read_len = file_read_string(&file, name, sizeof(name), '=', len); - - if (read_len < 0) - { - return 0; - } - - len -= read_len; - read_len = file_read_string(&file, id3->path, sizeof(id3->path), -1, len); - - if (read_len < 0) - { - return 0; - } - - logf("Vorbis comment %d: %s=%s", i, name, id3->path); - - /* Is it an embedded cuesheet? */ - if (!strcasecmp(name, "CUESHEET")) - { - id3->has_embedded_cuesheet = true; - id3->embedded_cuesheet.pos = lseek(file.fd, 0, SEEK_CUR) - read_len; - id3->embedded_cuesheet.size = len; - id3->embedded_cuesheet.encoding = CHAR_ENC_UTF_8; - } - else - { - len = parse_tag(name, id3->path, id3, buf, buf_remaining, - TAGTYPE_VORBIS); - } - - buf += len; - buf_remaining -= len; - } - - /* Skip to the end of the block (needed by FLAC) */ - if (file.packet_remaining) - { - if (file_read(&file, NULL, file.packet_remaining) < 0) - { - return 0; - } - } - - return comment_size; -} diff --git a/apps/metadata/vox.c b/apps/metadata/vox.c deleted file mode 100644 index f6bc849..0000000 --- a/apps/metadata/vox.c +++ /dev/null @@ -1,49 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2010 Yoshihisa Uchida - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "logf.h" - -bool get_vox_metadata(int fd, struct mp3entry* id3) -{ - /* - * vox is headerless format - * - * frequency: 8000 Hz - * channels: mono - * bitspersample: 4 - */ - id3->frequency = 8000; - id3->bitrate = 8000 * 4 / 1000; - id3->vbr = false; /* All VOX files are CBR */ - id3->filesize = filesize(fd); - id3->length = id3->filesize >> 2; - - return true; -} diff --git a/apps/metadata/wave.c b/apps/metadata/wave.c deleted file mode 100644 index 45acea1..0000000 --- a/apps/metadata/wave.c +++ /dev/null @@ -1,432 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2005 Dave Chapman - * Copyright (C) 2010 Yoshihisa Uchida - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "rbunicode.h" -#include "logf.h" - -#ifdef DEBUGF -#undef DEBUGF -#define DEBUGF(...) -#endif - -/* Wave(RIFF)/Wave64 format */ - - -# define AV_WL32(p, d) do { \ - ((uint8_t*)(p))[0] = (d); \ - ((uint8_t*)(p))[1] = (d)>>8; \ - ((uint8_t*)(p))[2] = (d)>>16; \ - ((uint8_t*)(p))[3] = (d)>>24; \ - } while(0) -# define AV_WL16(p, d) do { \ - ((uint8_t*)(p))[0] = (d); \ - ((uint8_t*)(p))[1] = (d)>>8; \ - } while(0) - -enum { - RIFF_CHUNK = 0, - WAVE_CHUNK, - FMT_CHUNK, - FACT_CHUNK, - DATA_CHUNK, - LIST_CHUNK, -}; - -/* Wave chunk names */ -#define WAVE_CHUNKNAME_LENGTH 4 -#define WAVE_CHUNKSIZE_LENGTH 4 - -static const unsigned char * const wave_chunklist - = "RIFF" - "WAVE" - "fmt " - "fact" - "data" - "LIST"; - -/* Wave64 GUIDs */ -#define WAVE64_CHUNKNAME_LENGTH 16 -#define WAVE64_CHUNKSIZE_LENGTH 8 - -static const unsigned char * const wave64_chunklist - = "riff\x2e\x91\xcf\x11\xa5\xd6\x28\xdb\x04\xc1\x00\x00" - "wave\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a" - "fmt \xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a" - "fact\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a" - "data\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a" - "\xbc\x94\x5f\x92\x5a\x52\xd2\x11\x86\xdc\x00\xc0\x4f\x8e\xdb\x8a"; - -/* list/info chunk */ - -struct info_chunk { - const unsigned char* tag; - size_t offset; -}; - -/* info chunk names are common wave/wave64 */ -static const struct info_chunk info_chunks[] = { - { "INAM", offsetof(struct mp3entry, title), }, /* title */ - { "IART", offsetof(struct mp3entry, artist), }, /* artist */ - { "ISBJ", offsetof(struct mp3entry, albumartist), }, /* albumartist */ - { "IPRD", offsetof(struct mp3entry, album), }, /* album */ - { "IWRI", offsetof(struct mp3entry, composer), }, /* composer */ - { "ICMT", offsetof(struct mp3entry, comment), }, /* comment */ - { "ISRF", offsetof(struct mp3entry, grouping), }, /* grouping */ - { "IGNR", offsetof(struct mp3entry, genre_string), }, /* genre */ - { "ICRD", offsetof(struct mp3entry, year_string), }, /* date */ - { "IPRT", offsetof(struct mp3entry, track_string), }, /* track/trackcount */ - { "IFRM", offsetof(struct mp3entry, disc_string), }, /* disc/disccount */ -}; - -#define INFO_CHUNK_COUNT ((int)ARRAYLEN(info_chunks)) - -/* support formats */ -enum -{ - WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM Format */ - WAVE_FORMAT_ADPCM = 0x0002, /* Microsoft ADPCM Format */ - WAVE_FORMAT_IEEE_FLOAT = 0x0003, /* IEEE Float */ - WAVE_FORMAT_ALAW = 0x0006, /* Microsoft ALAW */ - WAVE_FORMAT_MULAW = 0x0007, /* Microsoft MULAW */ - WAVE_FORMAT_DVI_ADPCM = 0x0011, /* Intel's DVI ADPCM */ - WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 0x0017, /* Dialogic OKI ADPCM */ - WAVE_FORMAT_YAMAHA_ADPCM = 0x0020, /* Yamaha ADPCM */ - WAVE_FORMAT_XBOX_ADPCM = 0x0069, /* XBOX ADPCM */ - IBM_FORMAT_MULAW = 0x0101, /* same as WAVE_FORMAT_MULAW */ - IBM_FORMAT_ALAW = 0x0102, /* same as WAVE_FORMAT_ALAW */ - WAVE_FORMAT_ATRAC3 = 0x0270, /* Atrac3 stream */ - WAVE_FORMAT_SWF_ADPCM = 0x5346, /* Adobe SWF ADPCM */ - WAVE_FORMAT_EXTENSIBLE = 0xFFFE, -}; - -struct wave_fmt { - unsigned int formattag; - unsigned int channels; - unsigned int blockalign; - unsigned int bitspersample; - unsigned int samplesperblock; - uint32_t totalsamples; - uint64_t numbytes; -}; - -static unsigned char *convert_utf8(const unsigned char *src, unsigned char *dst, - int size, bool is_64) -{ - if (is_64) - { - /* Note: wave64: metadata codepage is UTF-16 only */ - return utf16LEdecode(src, dst, size); - } - return iso_decode(src, dst, -1, size); -} - -static void set_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3) -{ - switch (fmt->formattag) - { - case WAVE_FORMAT_PCM: - case WAVE_FORMAT_IEEE_FLOAT: - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - case IBM_FORMAT_ALAW: - case IBM_FORMAT_MULAW: - fmt->blockalign = fmt->bitspersample * fmt->channels >> 3; - fmt->samplesperblock = 1; - break; - case WAVE_FORMAT_YAMAHA_ADPCM: - if (id3->channels != 0) - { - fmt->samplesperblock = - (fmt->blockalign == ((id3->frequency / 60) + 4) * fmt->channels)? - id3->frequency / 30 : (fmt->blockalign << 1) / fmt->channels; - } - break; - case WAVE_FORMAT_DIALOGIC_OKI_ADPCM: - fmt->blockalign = 1; - fmt->samplesperblock = 2; - break; - case WAVE_FORMAT_SWF_ADPCM: - if (fmt->bitspersample != 0 && id3->channels != 0) - { - fmt->samplesperblock - = (((fmt->blockalign << 3) - 2) / fmt->channels - 22) - / fmt->bitspersample + 1; - } - break; - default: - break; - } - - if (fmt->blockalign != 0) - fmt->totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock; -} - -static void parse_riff_format(unsigned char* buf, int fmtsize, struct wave_fmt *fmt, - struct mp3entry* id3) -{ - /* wFormatTag */ - fmt->formattag = buf[0] | (buf[1] << 8); - /* wChannels */ - fmt->channels = buf[2] | (buf[3] << 8); - /* dwSamplesPerSec */ - id3->frequency = get_long_le(&buf[4]); - /* dwAvgBytesPerSec */ - id3->bitrate = (get_long_le(&buf[8]) * 8) / 1000; - /* wBlockAlign */ - fmt->blockalign = buf[12] | (buf[13] << 8); - /* wBitsPerSample */ - fmt->bitspersample = buf[14] | (buf[15] << 8); - - if (fmt->formattag != WAVE_FORMAT_EXTENSIBLE) - { - if (fmtsize > 19) - { - /* wSamplesPerBlock */ - fmt->samplesperblock = buf[18] | (buf[19] << 8); - } - } - else if (fmtsize > 25) - { - /* wValidBitsPerSample */ - fmt->bitspersample = buf[18] | (buf[19] << 8); - /* SubFormat */ - fmt->formattag = buf[24] | (buf[25] << 8); - } - - /* Check for ATRAC3 stream */ - if (fmt->formattag == WAVE_FORMAT_ATRAC3) - { - int jsflag = 0; - if(id3->bitrate == 66 || id3->bitrate == 94) - jsflag = 1; - - id3->extradata_size = 14; - id3->channels = 2; - id3->codectype = AFMT_OMA_ATRAC3; - id3->bytesperframe = fmt->blockalign; - - /* Store the extradata for the codec */ - AV_WL16(&id3->id3v2buf[0], 1); // always 1 - AV_WL32(&id3->id3v2buf[2], id3->frequency);// samples rate - AV_WL16(&id3->id3v2buf[6], jsflag); // coding mode - AV_WL16(&id3->id3v2buf[8], jsflag); // coding mode - AV_WL16(&id3->id3v2buf[10], 1); // always 1 - AV_WL16(&id3->id3v2buf[12], 0); // always 0 - } -} - -static void parse_list_chunk(int fd, struct mp3entry* id3, int chunksize, bool is_64) -{ - unsigned char tmpbuf[ID3V2_BUF_SIZE]; - unsigned char *bp = tmpbuf; - unsigned char *endp; - unsigned char *data_pos; - unsigned char *tag_pos = id3->id3v2buf; - int datasize; - int infosize; - int remain; - int i; - - if (is_64) - lseek(fd, 4, SEEK_CUR); - else if (read(fd, bp, 4) < 4 || memcmp(bp, "INFO", 4)) - return; - - /* decrease skip bytes */ - chunksize -= 4; - - infosize = read(fd, bp, (ID3V2_BUF_SIZE > chunksize)? chunksize : ID3V2_BUF_SIZE); - if (infosize <= 8) - return; - - endp = bp + infosize; - while (bp < endp) - { - datasize = get_long_le(bp + 4); - data_pos = bp + 8; - remain = ID3V2_BUF_SIZE - (tag_pos - (unsigned char*)id3->id3v2buf); - if (remain < 1) - break; - - for (i = 0; i < INFO_CHUNK_COUNT; i++) - { - if (memcmp(bp, info_chunks[i].tag, 4) == 0) - { - *((char **)(((char*)id3) + info_chunks[i].offset)) = tag_pos; - tag_pos = convert_utf8(data_pos, tag_pos, - (datasize + 1 >= remain )? remain - 1 : datasize, - is_64); - *tag_pos++ = 0; - break; - } - } - bp = data_pos + datasize + (datasize & 1); - }; -} - -static bool read_header(int fd, struct mp3entry* id3, const unsigned char *chunknames, - bool is_64) -{ - /* Use the temporary buffer */ - unsigned char* buf = (unsigned char *)id3->path; - - struct wave_fmt fmt; - - const unsigned int namelen = (is_64)? WAVE64_CHUNKNAME_LENGTH : WAVE_CHUNKNAME_LENGTH; - const unsigned int sizelen = (is_64)? WAVE64_CHUNKSIZE_LENGTH : WAVE_CHUNKSIZE_LENGTH; - const unsigned int len = namelen + sizelen; - uint64_t chunksize; - uint64_t offset = len + namelen; - int read_data; - - memset(&fmt, 0, sizeof(struct wave_fmt)); - - id3->vbr = false; /* All Wave/Wave64 files are CBR */ - id3->filesize = filesize(fd); - - /* get RIFF chunk header */ - lseek(fd, 0, SEEK_SET); - read(fd, buf, offset); - - if ((memcmp(buf, chunknames + RIFF_CHUNK * namelen, namelen) != 0) || - (memcmp(buf + len, chunknames + WAVE_CHUNK * namelen, namelen) != 0)) - { - DEBUGF("metadata error: missing riff header.\n"); - return false; - } - - /* iterate over WAVE chunks until 'data' chunk */ - while (read(fd, buf, len) > 0) - { - offset += len; - - /* get chunk size (when the header is wave64, chunksize includes GUID and data length) */ - chunksize = (is_64) ? get_uint64_le(buf + namelen) - len : - get_long_le(buf + namelen); - - read_data = 0; - if (memcmp(buf, chunknames + FMT_CHUNK * namelen, namelen) == 0) - { - DEBUGF("find 'fmt ' chunk\n"); - - if (chunksize < 16) - { - DEBUGF("metadata error: 'fmt ' chunk is too small: %d\n", (int)chunksize); - return false; - } - - /* get and parse format */ - read_data = (chunksize > 25)? 26 : chunksize; - - read(fd, buf, read_data); - parse_riff_format(buf, read_data, &fmt, id3); - } - else if (memcmp(buf, chunknames + FACT_CHUNK * namelen, namelen) == 0) - { - DEBUGF("find 'fact' chunk\n"); - - /* dwSampleLength */ - if (chunksize >= sizelen) - { - /* get totalsamples */ - read_data = sizelen; - read(fd, buf, read_data); - fmt.totalsamples = (is_64)? get_uint64_le(buf) : get_long_le(buf); - } - } - else if (memcmp(buf, chunknames + DATA_CHUNK * namelen, namelen) == 0) - { - DEBUGF("find 'data' chunk\n"); - fmt.numbytes = chunksize; - if (fmt.formattag == WAVE_FORMAT_ATRAC3) - id3->first_frame_offset = offset; - } - else if (memcmp(buf, chunknames + LIST_CHUNK * namelen, namelen) == 0) - { - DEBUGF("find 'LIST' chunk\n"); - parse_list_chunk(fd, id3, chunksize, is_64); - lseek(fd, offset, SEEK_SET); - } - - /* padded to next chunk */ - chunksize += ((is_64)? ((1 + ~chunksize) & 0x07) : (chunksize & 1)); - - offset += chunksize; - if (offset >= id3->filesize) - break; - - lseek(fd, chunksize - read_data, SEEK_CUR); - } - - if (fmt.numbytes == 0) - { - DEBUGF("metadata error: read error or missing 'data' chunk.\n"); - return false; - } - - if (fmt.totalsamples == 0) - set_totalsamples(&fmt, id3); - - if (id3->frequency == 0 || id3->bitrate == 0) - { - DEBUGF("metadata error: frequency or bitrate is 0\n"); - return false; - } - - /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */ - id3->length = (fmt.formattag != WAVE_FORMAT_ATRAC3)? - (uint64_t)fmt.totalsamples * 1000 / id3->frequency : - ((id3->filesize - id3->first_frame_offset) * 8) / id3->bitrate; - - /* output header/id3 info (for debug) */ - DEBUGF("%s header info ----\n", (is_64)? "wave64" : "wave"); - DEBUGF(" format: %04x\n", (int)fmt.formattag); - DEBUGF(" channels: %u\n", fmt.channels); - DEBUGF(" blockalign: %u\n", fmt.blockalign); - DEBUGF(" bitspersample: %u\n", fmt.bitspersample); - DEBUGF(" samplesperblock: %u\n", fmt.samplesperblock); - DEBUGF(" totalsamples: %u\n", (unsigned int)fmt.totalsamples); - DEBUGF(" numbytes: %u\n", (unsigned int)fmt.numbytes); - DEBUGF("id3 info ----\n"); - DEBUGF(" frequency: %u\n", (unsigned int)id3->frequency); - DEBUGF(" bitrate: %d\n", id3->bitrate); - DEBUGF(" length: %u\n", (unsigned int)id3->length); - - return true; -} - -bool get_wave_metadata(int fd, struct mp3entry* id3) -{ - return read_header(fd, id3, wave_chunklist, false); -} - -bool get_wave64_metadata(int fd, struct mp3entry* id3) -{ - return read_header(fd, id3, wave64_chunklist, true); -} diff --git a/apps/metadata/wavpack.c b/apps/metadata/wavpack.c deleted file mode 100644 index f2811df..0000000 --- a/apps/metadata/wavpack.c +++ /dev/null @@ -1,160 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2007 David Bryant - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include <inttypes.h> - -#include "system.h" -#include "metadata.h" -#include "metadata_common.h" -#include "metadata_parsers.h" -#include "logf.h" - -#define ID_UNIQUE 0x3f -#define ID_LARGE 0x80 -#define ID_SAMPLE_RATE 0x27 - -#define MONO_FLAG 4 -#define HYBRID_FLAG 8 - -static const long wavpack_sample_rates [] = -{ - 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, - 32000, 44100, 48000, 64000, 88200, 96000, 192000 -}; - -/* A simple parser to read basic information from a WavPack file. This - * now works with self-extrating WavPack files and also will scan the - * metadata for non-standard sampling rates. This no longer fails on - * WavPack files containing floating-point audio data because these are - * now converted to standard Rockbox format in the decoder, and also - * handles the case where up to 15 non-audio blocks might occur at the - * beginning of the file. - */ - -bool get_wavpack_metadata(int fd, struct mp3entry* id3) -{ - /* Use the trackname part of the id3 structure as a temporary buffer */ - unsigned char* buf = (unsigned char *)id3->path; - uint32_t totalsamples = (uint32_t) -1; - int i; - - for (i = 0; i < 256; ++i) { - - /* at every 256 bytes into file, try to read a WavPack header */ - - if ((lseek(fd, i * 256, SEEK_SET) < 0) || (read(fd, buf, 32) < 32)) - return false; - - /* if valid WavPack 4 header version, break */ - - if (memcmp (buf, "wvpk", 4) == 0 && buf [9] == 4 && - (buf [8] >= 2 && buf [8] <= 0x10)) - break; - } - - if (i == 256) { - logf ("Not a WavPack file"); - return false; - } - - id3->vbr = true; /* All WavPack files are VBR */ - id3->filesize = filesize (fd); - - /* check up to 16 headers before we give up finding one with audio */ - - for (i = 0; i < 16; ++i) { - uint32_t meta_bytes = get_long_le(&buf [4]) - 24; - uint32_t trial_totalsamples = get_long_le(&buf[12]); - uint32_t blockindex = get_long_le(&buf[16]); - uint32_t blocksamples = get_long_le(&buf[20]); - uint32_t flags = get_long_le(&buf[24]); - - if (totalsamples == (uint32_t) -1 && blockindex == 0) - totalsamples = trial_totalsamples; - - if (blocksamples) { - int srindx = ((buf [26] >> 7) & 1) + ((buf [27] << 1) & 14); - - if (srindx == 15) { - uint32_t meta_size; - - id3->frequency = 44100; - - while (meta_bytes >= 6) { - if (read(fd, buf, 2) < 2) - break; - - if (buf [0] & ID_LARGE) { - if (read(fd, buf + 2, 2) < 2) - break; - - meta_size = (buf [1] << 1) + (buf [2] << 9) + (buf [3] << 17); - meta_bytes -= meta_size + 4; - } - else { - meta_size = buf [1] << 1; - meta_bytes -= meta_size + 2; - - if ((buf [0] & ID_UNIQUE) == ID_SAMPLE_RATE) { - if (meta_size == 4 && read(fd, buf + 2, 4) == 4) - id3->frequency = buf [2] + (buf [3] << 8) + (buf [4] << 16); - - break; - } - } - - if (meta_size > 0 && lseek(fd, meta_size, SEEK_CUR) < 0) - break; - } - } - else - id3->frequency = wavpack_sample_rates[srindx]; - - /* if the total number of samples is still unknown, make a guess on the high side (for now) */ - - if (totalsamples == (uint32_t) -1) { - totalsamples = id3->filesize * 3; - - if (!(flags & HYBRID_FLAG)) - totalsamples /= 2; - - if (!(flags & MONO_FLAG)) - totalsamples /= 2; - } - - id3->length = ((int64_t) totalsamples * 1000) / id3->frequency; - id3->bitrate = id3->filesize / (id3->length / 8); - - read_ape_tags(fd, id3); - return true; - } - else { /* block did not contain audio, so seek to the end and see if there's another */ - if ((meta_bytes > 0 && lseek(fd, meta_bytes, SEEK_CUR) < 0) || - read(fd, buf, 32) < 32 || memcmp (buf, "wvpk", 4) != 0) - break; - } - } - - return false; -} |