diff options
| author | Yoshihisa Uchida <uchida@rockbox.org> | 2010-02-20 02:04:56 +0000 |
|---|---|---|
| committer | Yoshihisa Uchida <uchida@rockbox.org> | 2010-02-20 02:04:56 +0000 |
| commit | 3716abba9274f544dd31cdf4e6c83a845bf2a801 (patch) | |
| tree | 07bca7cdd3e40bb176e938fcb5ea8eb2f7c3e9cb /apps/metadata | |
| parent | 93caf52db5e0afe826278c148936bdfa563724f1 (diff) | |
| download | rockbox-3716abba9274f544dd31cdf4e6c83a845bf2a801.zip rockbox-3716abba9274f544dd31cdf4e6c83a845bf2a801.tar.gz rockbox-3716abba9274f544dd31cdf4e6c83a845bf2a801.tar.bz2 rockbox-3716abba9274f544dd31cdf4e6c83a845bf2a801.tar.xz | |
commit FS#10424 and FS#10425
- wav(RIFF) supports Microsoft ADPCM, Dialogic OKI ADPCM, YAMAHA ADPCM, Adobe SWF ADPCM.
- AIFF supports QuickTime IMA ADPCM.
- DVI ADPCM(IMA ADPCM) reworks.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24782 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/metadata')
| -rw-r--r-- | apps/metadata/aiff.c | 23 | ||||
| -rw-r--r-- | apps/metadata/wave.c | 138 |
2 files changed, 132 insertions, 29 deletions
diff --git a/apps/metadata/aiff.c b/apps/metadata/aiff.c index 67fb43b..aba327f 100644 --- a/apps/metadata/aiff.c +++ b/apps/metadata/aiff.c @@ -29,6 +29,9 @@ #include "metadata_common.h" #include "metadata_parsers.h" +/* compressionType: AIFC QuickTime IMA ADPCM */ +#define AIFC_FORMAT_QT_IMA_ADPCM "ima4" + bool get_aiff_metadata(int fd, struct mp3entry* id3) { /* Use the trackname part of the id3 structure as a temporary buffer */ @@ -40,6 +43,7 @@ bool get_aiff_metadata(int fd, struct mp3entry* id3) unsigned long numbytes = 0; int read_bytes; int i; + bool is_aifc = false; if ((lseek(fd, 0, SEEK_SET) < 0) || ((read_bytes = read(fd, buf, sizeof(id3->path))) < 54)) @@ -47,10 +51,15 @@ bool get_aiff_metadata(int fd, struct mp3entry* id3) return false; } - if ((memcmp(buf, "FORM",4) != 0) - || ((memcmp(&buf[8], "AIFF", 4) !=0) && (memcmp(&buf[8], "AIFC", 4) !=0))) - { + if (memcmp(buf, "FORM",4) != 0) return false; + + if (memcmp(&buf[8], "AIFF", 4) != 0) + { + if (memcmp(&buf[8], "AIFC", 4) != 0) + return false; + + is_aifc = true; } buf += 12; @@ -75,7 +84,13 @@ bool get_aiff_metadata(int fd, struct mp3entry* id3) /* save format infos */ id3->bitrate = (sampleSize * numChannels * sampleRate) / 1000; id3->frequency = sampleRate; - id3->length = ((int64_t) numSampleFrames * 1000) / id3->frequency; + if (!is_aifc || memcmp(&buf[26], 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); diff --git a/apps/metadata/wave.c b/apps/metadata/wave.c index acef32d..79bb817 100644 --- a/apps/metadata/wave.c +++ b/apps/metadata/wave.c @@ -28,6 +28,7 @@ #include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" +#include "logf.h" # define AV_WL32(p, d) do { \ ((uint8_t*)(p))[0] = (d); \ @@ -40,29 +41,101 @@ ((uint8_t*)(p))[1] = (d)>>8; \ } while(0) +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 */ +}; + +struct wave_fmt { + unsigned int formattag; + unsigned long channels; + unsigned int blockalign; + unsigned long bitspersample; + unsigned int samplesperblock; + unsigned long numbytes; +}; + +static unsigned long get_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3) +{ + unsigned long totalsamples = 0; + + 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: + totalsamples = + fmt->numbytes / ((((fmt->bitspersample - 1) / 8) + 1) * fmt->channels); + break; + case WAVE_FORMAT_ADPCM: + case WAVE_FORMAT_DVI_ADPCM: + case WAVE_FORMAT_XBOX_ADPCM: + totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock; + break; + case WAVE_FORMAT_YAMAHA_ADPCM: + if (fmt->samplesperblock == 0) + { + if (fmt->blockalign == ((id3->frequency / 60) + 4) * fmt->channels) + fmt->samplesperblock = id3->frequency / 30; + else + fmt->samplesperblock = fmt->blockalign * 2 / fmt->channels; + } + totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock; + break; + case WAVE_FORMAT_DIALOGIC_OKI_ADPCM: + totalsamples = 2 * fmt->numbytes; + break; + case WAVE_FORMAT_SWF_ADPCM: + if (fmt->samplesperblock == 0) + fmt->samplesperblock = (((fmt->blockalign << 3) - 2) / fmt->channels - 22) + / fmt->bitspersample; + + totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock; + break; + default: + totalsamples = 0; + break; + } + return totalsamples; +} + bool get_wave_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; + struct wave_fmt fmt; unsigned long totalsamples = 0; - unsigned long channels = 0; - unsigned long bitspersample = 0; - unsigned long numbytes = 0; unsigned long offset = 0; int read_bytes; int i; + memset(&fmt, 0, sizeof(struct wave_fmt)); + /* get RIFF chunk header */ - if ((lseek(fd, 0, SEEK_SET) < 0) - || ((read_bytes = read(fd, buf, 12)) < 12)) + if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 12) < 12)) { return false; } offset += 12; - if ((memcmp(buf, "RIFF",4) != 0) - || (memcmp(&buf[8], "WAVE", 4) !=0 )) + if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) { + DEBUGF("metadata error: missing riff header.\n"); return false; } @@ -70,7 +143,7 @@ bool get_wave_metadata(int fd, struct mp3entry* id3) while (true) { /* get chunk header */ - if ((read_bytes = read(fd, buf, 8)) < 8) + if (read(fd, buf, 8) < 8) return false; offset += 8; @@ -80,26 +153,41 @@ bool get_wave_metadata(int fd, struct mp3entry* id3) if (memcmp(buf, "fmt ", 4) == 0) { /* get rest of chunk */ - if ((read_bytes = read(fd, buf, 16)) < 16) + if (i < 16) return false; - offset += 16; - i -= 16; + read_bytes = 16; + if (i > 19) + read_bytes = 20; - /* skipping wFormatTag */ + if (read(fd, buf, read_bytes) != read_bytes) + return false; + + offset += read_bytes; + i -= read_bytes; + + /* wFormatTag */ + fmt.formattag = buf[0] | (buf[1] << 8); /* wChannels */ - channels = buf[2] | (buf[3] << 8); + 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 */ - id3->bytesperframe = buf[12] | (buf[13] << 8); + fmt.blockalign = buf[12] | (buf[13] << 8); + id3->bytesperframe = fmt.blockalign; /* wBitsPerSample */ - bitspersample = buf[14] | (buf[15] << 8); + fmt.bitspersample = buf[14] | (buf[15] << 8); + if (read_bytes > 19) + { + /* wSamplesPerBlock */ + fmt.samplesperblock = buf[18] | (buf[19] << 8); + } + /* Check for ATRAC3 stream */ - if((buf[0] | (buf[1] << 8)) == 0x0270) - { + if (fmt.formattag == WAVE_FORMAT_ATRAC3) + { int jsflag = 0; if(id3->bitrate == 66 || id3->bitrate == 94) jsflag = 1; @@ -107,7 +195,7 @@ bool get_wave_metadata(int fd, struct mp3entry* id3) id3->extradata_size = 14; id3->channels = 2; id3->codectype = AFMT_OMA_ATRAC3; - /* Store the extradata for the codec */ + /* 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 @@ -118,8 +206,9 @@ bool get_wave_metadata(int fd, struct mp3entry* id3) } else if (memcmp(buf, "data", 4) == 0) { - numbytes = i; - id3->first_frame_offset = offset; + fmt.numbytes = i; + if (fmt.formattag == WAVE_FORMAT_ATRAC3) + id3->first_frame_offset = offset; break; } else if (memcmp(buf, "fact", 4) == 0) @@ -128,7 +217,7 @@ bool get_wave_metadata(int fd, struct mp3entry* id3) if (i >= 4) { /* get rest of chunk */ - if ((read_bytes = read(fd, buf, 4)) < 4) + if (read(fd, buf, 4) < 4) return false; offset += 4; i -= 4; @@ -145,16 +234,15 @@ bool get_wave_metadata(int fd, struct mp3entry* id3) offset += i; } - if ((numbytes == 0) || (channels == 0)) + if ((fmt.numbytes == 0) || (fmt.channels == 0) || (fmt.blockalign == 0)) { + DEBUGF("metadata error: numbytes, channels, or blockalign is 0.\n"); return false; } if (totalsamples == 0) { - /* for PCM only */ - totalsamples = numbytes - / ((((bitspersample - 1) / 8) + 1) * channels); + totalsamples = get_totalsamples(&fmt, id3); } id3->vbr = false; /* All WAV files are CBR */ |