#include "sysconfig.h" #include "sysdeps.h" #include "zfile.h" #include "mp3decoder.h" #include "cda_play.h" #include #define MP3_BLOCK_SIZE 522 #define RAW_BLOCK_SIZE 32768 static int mp3_bitrates[] = { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1, 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1, 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1, 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1, 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }; static int mp3_frequencies[] = { 44100, 48000, 32000, 0, 22050, 24000, 16000, 0, 11025, 12000, 8000, 0 }; static int mp3_samplesperframe[] = { 384, 384, 384, 1152, 1152, 1152, 1152, 576, 576 }; mp3decoder::~mp3decoder() { } mp3decoder::mp3decoder() { } uae_u8 *mp3decoder::get (struct zfile *zf, uae_u8 *outbuf, int maxsize) { int outoffset = 0; unsigned char mp3buf[MP3_BLOCK_SIZE]; unsigned char rawbuf[RAW_BLOCK_SIZE]; write_log(_T("MP3: decoding '%s'..\n"), zfile_getname(zf)); if(mpg123_init() != MPG123_OK) { write_log("MP3: failed to init mpeg123\n"); return NULL; } const char** decoders = mpg123_decoders(); if(decoders == NULL || decoders[0] == NULL) { write_log("MP3: no mp3 decoder available\n"); mpg123_exit(); return NULL; } mpg123_handle *mh = mpg123_new(NULL, NULL); // Open default decoder if(mh == NULL) { write_log("MP3: failed to init default decoder\n"); mpg123_exit(); return NULL; } if(mpg123_open_feed(mh) == MPG123_OK) { zfile_fseek(zf, 0, SEEK_SET); for (; outoffset < maxsize; ) { int count = zfile_fread(mp3buf, 1, MP3_BLOCK_SIZE, zf); if (count != MP3_BLOCK_SIZE) break; size_t decoded = 0; int ret = mpg123_decode(mh, mp3buf, MP3_BLOCK_SIZE, rawbuf, RAW_BLOCK_SIZE, &decoded); if(ret != MPG123_ERR && decoded != 0) { if(outoffset + decoded > maxsize) decoded = maxsize - outoffset; memcpy(outbuf + outoffset, rawbuf, decoded); outoffset += decoded; } while(ret != MPG123_ERR && ret != MPG123_NEED_MORE && outoffset < maxsize) { ret = mpg123_decode(mh, NULL, 0, rawbuf, RAW_BLOCK_SIZE, &decoded); if(ret != MPG123_ERR && decoded != 0) { if(outoffset + decoded > maxsize) decoded = maxsize - outoffset; memcpy(outbuf + outoffset, rawbuf, decoded); outoffset += decoded; } } if(ret == MPG123_ERR) { write_log("MP3: error while decoding\n"); outbuf = NULL; break; } } mpg123_close(mh); } mpg123_delete(mh); mpg123_exit(); return outbuf; } uae_u32 mp3decoder::getsize (struct zfile *zf) { uae_u32 size; int frames, sameframes; int firstframe; int oldbitrate; int timelen = -1; firstframe = -1; oldbitrate = -1; sameframes = -1; frames = 0; size = 0; uae_u8 id3[10]; if (zfile_fread(id3, sizeof id3, 1, zf) != 1) return 0; if (id3[0] == 'I' && id3[1] == 'D' && id3[2] == '3' && id3[3] == 3 && id3[4] != 0xff && id3[6] < 0x80 && id3[7] < 0x80 && id3[8] < 0x80 && id3[9] < 0x80) { int unsync = id3[5] & 0x80; int exthead = id3[5] & 0x40; int len = (id3[9] << 0) | (id3[8] << 7) | (id3[7] << 14) | (id3[6] << 21); len &= 0x0fffffff; uae_u8 *tag = xmalloc (uae_u8, len + 1); if (zfile_fread (tag, len, 1, zf) != 1) { xfree (tag); return 0; } uae_u8 *p = tag; if (exthead) { int size = (p[4] << 21) | (p[5] << 14) | (p[6] << 7); size &= 0x0fffffff; p += size; len -= size; } while (len > 0) { int size = unsync ? (p[4] << 21) | (p[5] << 14) | (p[6] << 7) | (p[7] << 0) : (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | (p[7] << 0); size &= 0x0fffffff; if (size > len) break; int compr = p[9] & 0x80; int enc = p[9] & 0x40; if (compr == 0 && enc == 0) { if (!memcmp (p, "TLEN", 4)) { uae_u8 *data = p + 10; data[size] = 0; if (data[0] == 0) timelen = atol ((char*)(data + 1)); else timelen = _tstol ((char*)(data + 1)); } } size += 10; p += size; len -= size; } xfree (tag); } else { zfile_fseek(zf, -(int)sizeof id3, SEEK_CUR); } for (;;) { int ver, layer, bitrate, freq, padding, bitindex, iscrc; int samplerate, framelen, bitrateidx, channelmode; int isstereo; uae_u8 header[4]; if (zfile_fread(header, sizeof header, 1, zf) != 1) return size; if (header[0] != 0xff || ((header[1] & (0x80 | 0x40 | 0x20)) != (0x80 | 0x40 | 0x20))) { zfile_fseek (zf, -3, SEEK_CUR); continue; } if (firstframe < 0) firstframe = zfile_ftell (zf); ver = (header[1] >> 3) & 3; if (ver == 1) { write_log (_T("MP3: ver==1?!\n")); return 0; } if (ver == 0) ver = 2; else if (ver == 2) ver = 1; else if (ver == 3) ver = 0; layer = 4 - ((header[1] >> 1) & 3); if (layer == 4) { write_log (_T("MP3: layer==4?!\n")); return 0; } iscrc = ((header[1] >> 0) & 1) ? 0 : 2; bitrateidx = (header[2] >> 4) & 15; freq = mp3_frequencies[(header[2] >> 2) & 3]; if (!freq) { write_log (_T("MP3: reserved frequency?!\n")); return 0; } channelmode = (header[3] >> 6) & 3; isstereo = channelmode != 3; if (ver == 0) { bitindex = layer - 1; } else { if (layer == 1) bitindex = 3; else bitindex = 4; } bitrate = mp3_bitrates[bitindex * 16 + bitrateidx] * 1000; if (bitrate <= 0) { write_log (_T("MP3: reserved bitrate?!\n")); return 0; } padding = (header[2] >> 1) & 1; samplerate = mp3_samplesperframe[(layer - 1) * 3 + ver]; framelen = ((samplerate / 8 * bitrate) / freq) + padding; if (framelen <= 4) { write_log (_T("MP3: too small frame size?!\n")); return 0; } zfile_fseek(zf, framelen - 4, SEEK_CUR); frames++; if (timelen > 0) { size = ((uae_u64)timelen * freq * 2 * (isstereo ? 2 : 1)) / 1000; break; } size += samplerate * 2 * (isstereo ? 2 : 1); if (bitrate != oldbitrate) { oldbitrate = bitrate; sameframes++; } if (sameframes == 0 && frames > 100) { // assume this is CBR MP3 size = samplerate * 2 * (isstereo ? 2 : 1) * ((zfile_size (zf) - firstframe) / ((samplerate / 8 * bitrate) / freq)); break; } } return size; }