00001
00002
00003
00004
00005
00006
00007 #include <string.h>
00008 #include "input_mp3.h"
00009 #include "utility.h"
00010 #include "debug.h"
00011
00012
00013 namespace audiere {
00014
00015
00016 MP3InputStream::MP3InputStream() {
00017 m_eof = false;
00018
00019 m_channel_count = 2;
00020 m_sample_rate = 44100;
00021 m_sample_format = SF_S16;
00022
00023 m_context = 0;
00024
00025 m_input_position = 0;
00026 m_input_length = 0;
00027 m_decode_buffer = 0;
00028 m_first_frame = true;
00029
00030 m_seekable = false;
00031 m_length = 0;
00032 m_position = 0;
00033 }
00034
00035
00036 MP3InputStream::~MP3InputStream() {
00037 delete[] m_decode_buffer;
00038 if (m_context) {
00039 mpaudec_clear(m_context);
00040 delete m_context;
00041 }
00042 }
00043
00044
00045 bool
00046 MP3InputStream::initialize(FilePtr file) {
00047 m_file = file;
00048 m_seekable = m_file->seek(0, File::END);
00049 readID3v1Tags();
00050 readID3v2Tags();
00051 m_file->seek(0, File::BEGIN);
00052 m_eof = false;
00053
00054 m_context = new MPAuDecContext;
00055 if (!m_context)
00056 return false;
00057 if (mpaudec_init(m_context) < 0) {
00058 delete m_context;
00059 m_context = 0;
00060 return false;
00061 }
00062
00063 m_input_position = 0;
00064 m_input_length = 0;
00065 m_decode_buffer = new u8[MPAUDEC_MAX_AUDIO_FRAME_SIZE];
00066 if (!m_decode_buffer)
00067 return false;
00068 m_first_frame = true;
00069
00070 if (m_seekable) {
00071
00072 m_context->parse_only = 1;
00073 while (!m_eof) {
00074 if (!decodeFrame())
00075 return false;
00076 if (!m_eof)
00077 m_frame_sizes.push_back(m_context->frame_size);
00078 int frame_offset = m_file->tell() -
00079 (m_input_length - m_input_position) -
00080 m_context->coded_frame_size;
00081 m_frame_offsets.push_back(frame_offset);
00082 m_length += m_context->frame_size;
00083 }
00084 reset();
00085 }
00086
00087
00088 return decodeFrame();
00089 }
00090
00091 bool
00092 MP3InputStream::isSeekable() {
00093 return m_seekable;
00094 }
00095
00096 int
00097 MP3InputStream::getPosition() {
00098 return m_position;
00099 }
00100
00101 void
00102 MP3InputStream::setPosition(int position) {
00103 if (!m_seekable || position > m_length)
00104 return;
00105 int scan_position = 0;
00106 int target_frame = 0;
00107 int frame_count = m_frame_sizes.size();
00108 while (target_frame < frame_count) {
00109 int frame_size = m_frame_sizes[target_frame];
00110 if (position <= scan_position + frame_size)
00111 break;
00112 else {
00113 scan_position += frame_size;
00114 target_frame++;
00115 }
00116 }
00117
00118
00119
00120 const int MAX_FRAME_DEPENDENCY = 10;
00121 target_frame = std::max(0, target_frame - MAX_FRAME_DEPENDENCY);
00122 reset();
00123 m_file->seek(m_frame_offsets[target_frame], File::BEGIN);
00124 int i;
00125 for (i = 0; i < target_frame; i++) {
00126 m_position += m_frame_sizes[i];
00127 }
00128 if (!decodeFrame() || m_eof) {
00129 reset();
00130 return;
00131 }
00132 int frames_to_consume = position - m_position;
00133 if (frames_to_consume > 0) {
00134 u8 *buf = new u8[frames_to_consume * GetFrameSize(this)];
00135 doRead(frames_to_consume, buf);
00136 delete[] buf;
00137 }
00138 }
00139
00140 int
00141 MP3InputStream::getLength() {
00142 return m_length;
00143 }
00144
00145 void
00146 MP3InputStream::getFormat(
00147 int& channel_count,
00148 int& sample_rate,
00149 SampleFormat& sample_format)
00150 {
00151 channel_count = m_channel_count;
00152 sample_rate = m_sample_rate;
00153 sample_format = m_sample_format;
00154 }
00155
00156
00157 int
00158 MP3InputStream::doRead(int frame_count, void* samples) {
00159 ADR_GUARD("MP3InputStream::doRead");
00160
00161 const int frame_size = GetFrameSize(this);
00162
00163 int frames_read = 0;
00164 u8* out = (u8*)samples;
00165
00166 while (frames_read < frame_count) {
00167
00168
00169 if (m_buffer.getSize() < frame_size) {
00170 if (!decodeFrame() || m_eof) {
00171
00172 return frames_read;
00173 }
00174
00175
00176 if (m_buffer.getSize() < frame_size) {
00177 return frames_read;
00178 }
00179 }
00180
00181 const int frames_left = frame_count - frames_read;
00182 const int frames_to_read = std::min(
00183 frames_left,
00184 m_buffer.getSize() / frame_size);
00185
00186 m_buffer.read(out, frames_to_read * frame_size);
00187 out += frames_to_read * frame_size;
00188 frames_read += frames_to_read;
00189 m_position += frames_to_read;
00190 }
00191
00192 return frames_read;
00193 }
00194
00195
00196 void
00197 MP3InputStream::reset() {
00198 ADR_GUARD("MP3InputStream::reset");
00199
00200 m_file->seek(0, File::BEGIN);
00201 m_eof = false;
00202
00203 m_buffer.clear();
00204
00205 mpaudec_clear(m_context);
00206 mpaudec_init(m_context);
00207
00208 m_input_position = 0;
00209 m_input_length = 0;
00210 m_position = 0;
00211 }
00212
00213
00214 bool
00215 MP3InputStream::decodeFrame() {
00216 int output_size = 0;
00217 while (output_size == 0) {
00218 if (m_input_position == m_input_length) {
00219 m_input_position = 0;
00220 m_input_length = m_file->read(m_input_buffer, INPUT_BUFFER_SIZE);
00221 if (m_input_length == 0) {
00222 m_eof = true;
00223 return true;
00224 }
00225 }
00226 int rv = mpaudec_decode_frame(
00227 m_context, (s16*)m_decode_buffer,
00228 &output_size,
00229 (unsigned char*)m_input_buffer + m_input_position,
00230 m_input_length - m_input_position);
00231 if (rv < 0)
00232 return false;
00233 m_input_position += rv;
00234 }
00235 if (m_first_frame) {
00236 m_channel_count = m_context->channels;
00237 m_sample_rate = m_context->sample_rate;
00238 m_sample_format = SF_S16;
00239 m_first_frame = false;
00240 } else if (m_context->channels != m_channel_count ||
00241 m_context->sample_rate != m_sample_rate) {
00242
00243 return false;
00244 }
00245 if (!m_context->parse_only) {
00246 if (output_size < 0) {
00247
00248
00249 output_size = m_context->frame_size;
00250 memset(m_decode_buffer, 0, output_size * GetFrameSize(this));
00251 }
00252 m_buffer.write(m_decode_buffer, output_size);
00253 }
00254 return true;
00255 }
00256
00257
00258 const char* getGenre(u8 code) {
00259 const char* genres[] = {
00260
00261
00262 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
00263 "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other",
00264 "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", "Industrial",
00265 "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack",
00266 "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
00267 "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House",
00268 "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
00269 "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
00270 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
00271 "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance",
00272 "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
00273 "Christian Rap", "Pop/Funk", "Jungle", "Native American",
00274 "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes",
00275 "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka",
00276 "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk-Rock",
00277 "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival",
00278 "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock",
00279 "Progressive Rock", "Psychedelic Rock", "Symphonic Rock",
00280 "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic",
00281 "Humour", "Speech", "Chanson", "Opera", "Chamber Music", "Sonata",
00282 "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire",
00283 "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad",
00284 "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock",
00285 "Drum Solo", "Acapella", "Euro-House", "Dance Hall",
00286
00287
00288
00289 "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie",
00290 "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta",
00291 "Heavy Metal", "Black Metal", "Crossover", "Contemporary C",
00292 "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime",
00293 "JPop", "SynthPop",
00294 };
00295 const int genre_count = sizeof(genres) / sizeof(*genres);
00296
00297 return (code < genre_count ? genres[code] : "");
00298 }
00299
00300
00301
00302
00303 std::string getString(u8* buffer, int maxlen) {
00304 char* begin = reinterpret_cast<char*>(buffer);
00305 int end = 0;
00306 for (; end < maxlen && begin[end]; ++end) {
00307 }
00308 return std::string(begin, begin + end);
00309 }
00310
00311
00312 void
00313 MP3InputStream::readID3v1Tags() {
00314
00315
00316 if (!m_file->seek(-128, File::END)) {
00317 return;
00318 }
00319
00320 u8 buffer[128];
00321 if (m_file->read(buffer, 128) != 128) {
00322 return;
00323 }
00324
00325
00326 if (memcmp(buffer + 0, "TAG", 3) != 0) {
00327 return;
00328 }
00329
00330 std::string title = getString(buffer + 3, 30);
00331 std::string artist = getString(buffer + 33, 30);
00332 std::string album = getString(buffer + 63, 30);
00333 std::string year = getString(buffer + 93, 4);
00334 std::string comment = getString(buffer + 97, 30);
00335 std::string genre = getGenre(buffer[127]);
00336
00337 addTag("title", title, "ID3v1");
00338 addTag("artist", artist, "ID3v1");
00339 addTag("album", album, "ID3v1");
00340 addTag("year", year, "ID3v1");
00341 addTag("comment", comment, "ID3v1");
00342 addTag("genre", genre, "ID3v1");
00343
00344
00345 if (buffer[97 + 28] == 0 && buffer[97 + 29] != 0) {
00346 char track[20];
00347 sprintf(track, "%d", int(buffer[97 + 29]));
00348 addTag("track", track, "ID3v1.1");
00349 }
00350 }
00351
00352
00353 void
00354 MP3InputStream::readID3v2Tags() {
00355
00356 }
00357
00358 }