svcore  1.9
MP3FileReader.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #ifdef HAVE_MAD
00017 
00018 #include "MP3FileReader.h"
00019 #include "base/ProgressReporter.h"
00020 
00021 #include "system/System.h"
00022 
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 #include <fcntl.h>
00026 
00027 #include <iostream>
00028 
00029 #include <cstdlib>
00030 #include <unistd.h>
00031 
00032 #ifdef HAVE_ID3TAG
00033 #include <id3tag.h>
00034 #endif
00035 //#define DEBUG_ID3TAG 1
00036 
00037 #include <QFileInfo>
00038 
00039 MP3FileReader::MP3FileReader(FileSource source, DecodeMode decodeMode, 
00040                              CacheMode mode, int targetRate,
00041                              bool normalised,
00042                              ProgressReporter *reporter) :
00043     CodedAudioFileReader(mode, targetRate, normalised),
00044     m_source(source),
00045     m_path(source.getLocalFilename()),
00046     m_decodeThread(0)
00047 {
00048     m_channelCount = 0;
00049     m_fileRate = 0;
00050     m_fileSize = 0;
00051     m_bitrateNum = 0;
00052     m_bitrateDenom = 0;
00053     m_cancelled = false;
00054     m_completion = 0;
00055     m_done = false;
00056     m_reporter = reporter;
00057 
00058     struct stat stat;
00059     if (::stat(m_path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) {
00060         m_error = QString("File %1 does not exist.").arg(m_path);
00061         return;
00062     }
00063 
00064     m_fileSize = stat.st_size;
00065 
00066     m_filebuffer = 0;
00067     m_samplebuffer = 0;
00068     m_samplebuffersize = 0;
00069 
00070     int fd = -1;
00071     if ((fd = ::open(m_path.toLocal8Bit().data(), O_RDONLY
00072 #ifdef _WIN32
00073                      | O_BINARY
00074 #endif
00075                      , 0)) < 0) {
00076         m_error = QString("Failed to open file %1 for reading.").arg(m_path);
00077         return;
00078     }   
00079 
00080     try {
00081         m_filebuffer = new unsigned char[m_fileSize];
00082     } catch (...) {
00083         m_error = QString("Out of memory");
00084         ::close(fd);
00085         return;
00086     }
00087     
00088     ssize_t sz = 0;
00089     int offset = 0;
00090     while (offset < m_fileSize) {
00091         sz = ::read(fd, m_filebuffer + offset, m_fileSize - offset);
00092         if (sz < 0) {
00093             m_error = QString("Read error for file %1 (after %2 bytes)")
00094                 .arg(m_path).arg(offset);
00095             delete[] m_filebuffer;
00096             ::close(fd);
00097             return;
00098         } else if (sz == 0) {
00099             cerr << QString("MP3FileReader::MP3FileReader: Warning: reached EOF after only %1 of %2 bytes")
00100                 .arg(offset).arg(m_fileSize) << endl;
00101             m_fileSize = offset;
00102             break;
00103         }
00104         offset += sz;
00105     }
00106 
00107     ::close(fd);
00108 
00109     loadTags();
00110 
00111     if (decodeMode == DecodeAtOnce) {
00112 
00113         if (m_reporter) {
00114             connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
00115             m_reporter->setMessage
00116                 (tr("Decoding %1...").arg(QFileInfo(m_path).fileName()));
00117         }
00118 
00119         if (!decode(m_filebuffer, m_fileSize)) {
00120             m_error = QString("Failed to decode file %1.").arg(m_path);
00121         }
00122         
00123         delete[] m_filebuffer;
00124         m_filebuffer = 0;
00125 
00126         if (isDecodeCacheInitialised()) finishDecodeCache();
00127         endSerialised();
00128 
00129     } else {
00130 
00131         if (m_reporter) m_reporter->setProgress(100);
00132 
00133         m_decodeThread = new DecodeThread(this);
00134         m_decodeThread->start();
00135 
00136         while ((m_channelCount == 0 || m_fileRate == 0 || m_sampleRate == 0)
00137                && !m_done) {
00138             usleep(10);
00139         }
00140         
00141         cerr << "MP3FileReader ctor: exiting with file rate = " << m_fileRate << endl;
00142     }
00143 
00144     if (m_error != "") {
00145         cerr << "MP3FileReader::MP3FileReader(\"" << m_path << "\"): ERROR: " << m_error << endl;
00146     }
00147 }
00148 
00149 MP3FileReader::~MP3FileReader()
00150 {
00151     if (m_decodeThread) {
00152         m_cancelled = true;
00153         m_decodeThread->wait();
00154         delete m_decodeThread;
00155     }
00156 }
00157 
00158 void
00159 MP3FileReader::cancelled()
00160 {
00161     m_cancelled = true;
00162 }
00163 
00164 void
00165 MP3FileReader::loadTags()
00166 {
00167     m_title = "";
00168 
00169 #ifdef HAVE_ID3TAG
00170 
00171     id3_file *file = id3_file_open(m_path.toLocal8Bit().data(),
00172                                    ID3_FILE_MODE_READONLY);
00173     if (!file) return;
00174 
00175     // We can do this a lot more elegantly, but we'll leave that for
00176     // when we implement support for more than just the one tag!
00177     
00178     id3_tag *tag = id3_file_tag(file);
00179     if (!tag) {
00180 #ifdef DEBUG_ID3TAG
00181         SVDEBUG << "MP3FileReader::loadTags: No ID3 tag found" << endl;
00182 #endif
00183         id3_file_close(file);
00184         return;
00185     }
00186 
00187     m_title = loadTag(tag, "TIT2"); // work title
00188     if (m_title == "") m_title = loadTag(tag, "TIT1");
00189 
00190     m_maker = loadTag(tag, "TPE1"); // "lead artist"
00191     if (m_maker == "") m_maker = loadTag(tag, "TPE2");
00192 
00193     for (unsigned int i = 0; i < tag->nframes; ++i) {
00194         if (tag->frames[i]) {
00195             QString value = loadTag(tag, tag->frames[i]->id);
00196             if (value != "") m_tags[tag->frames[i]->id] = value;
00197         }
00198     }
00199 
00200     id3_file_close(file);
00201 
00202 #else
00203 #ifdef DEBUG_ID3TAG
00204     SVDEBUG << "MP3FileReader::loadTags: ID3 tag support not compiled in"
00205               << endl;
00206 #endif
00207 #endif
00208 }
00209 
00210 QString
00211 MP3FileReader::loadTag(void *vtag, const char *name)
00212 {
00213 #ifdef HAVE_ID3TAG
00214     id3_tag *tag = (id3_tag *)vtag;
00215 
00216     id3_frame *frame = id3_tag_findframe(tag, name, 0);
00217     if (!frame) {
00218 #ifdef DEBUG_ID3TAG
00219         SVDEBUG << "MP3FileReader::loadTags: No \"" << name << "\" in ID3 tag" << endl;
00220 #endif
00221         return "";
00222     }
00223         
00224     if (frame->nfields < 2) {
00225         SVDEBUG << "MP3FileReader::loadTags: WARNING: Not enough fields (" << frame->nfields << ") for \"" << name << "\" in ID3 tag" << endl;
00226         return "";
00227     }
00228 
00229     unsigned int nstrings = id3_field_getnstrings(&frame->fields[1]);
00230     if (nstrings == 0) {
00231 #ifdef DEBUG_ID3TAG
00232         SVDEBUG << "MP3FileReader::loadTags: No strings for \"" << name << "\" in ID3 tag" << endl;
00233 #endif
00234         return "";
00235     }
00236 
00237     id3_ucs4_t const *ustr = id3_field_getstrings(&frame->fields[1], 0);
00238     if (!ustr) {
00239 #ifdef DEBUG_ID3TAG
00240         SVDEBUG << "MP3FileReader::loadTags: Invalid or absent data for \"" << name << "\" in ID3 tag" << endl;
00241 #endif
00242         return "";
00243     }
00244         
00245     id3_utf8_t *u8str = id3_ucs4_utf8duplicate(ustr);
00246     if (!u8str) {
00247         cerr << "MP3FileReader::loadTags: ERROR: Internal error: Failed to convert UCS4 to UTF8 in ID3 title" << endl;
00248         return "";
00249     }
00250         
00251     QString rv = QString::fromUtf8((const char *)u8str);
00252     free(u8str);
00253 
00254 #ifdef DEBUG_ID3TAG
00255         SVDEBUG << "MP3FileReader::loadTags: tag \"" << name << "\" -> \""
00256         << rv << "\"" << endl;
00257 #endif
00258 
00259 
00260     return rv;
00261 
00262 #else
00263     return "";
00264 #endif
00265 }
00266 
00267 void
00268 MP3FileReader::DecodeThread::run()
00269 {
00270     if (!m_reader->decode(m_reader->m_filebuffer, m_reader->m_fileSize)) {
00271         m_reader->m_error = QString("Failed to decode file %1.").arg(m_reader->m_path);
00272     }
00273 
00274     delete[] m_reader->m_filebuffer;
00275     m_reader->m_filebuffer = 0;
00276 
00277     if (m_reader->m_samplebuffer) {
00278         for (int c = 0; c < m_reader->m_channelCount; ++c) {
00279             delete[] m_reader->m_samplebuffer[c];
00280         }
00281         delete[] m_reader->m_samplebuffer;
00282         m_reader->m_samplebuffer = 0;
00283     }
00284 
00285     if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
00286 
00287     m_reader->m_done = true;
00288     m_reader->m_completion = 100;
00289 
00290     m_reader->endSerialised();
00291 } 
00292 
00293 bool
00294 MP3FileReader::decode(void *mm, int sz)
00295 {
00296     DecoderData data;
00297     struct mad_decoder decoder;
00298 
00299     data.start = (unsigned char const *)mm;
00300     data.length = (unsigned long)sz;
00301     data.reader = this;
00302 
00303     mad_decoder_init(&decoder, &data, input, 0, 0, output, error, 0);
00304     mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
00305     mad_decoder_finish(&decoder);
00306 
00307     m_done = true;
00308     return true;
00309 }
00310 
00311 enum mad_flow
00312 MP3FileReader::input(void *dp, struct mad_stream *stream)
00313 {
00314     DecoderData *data = (DecoderData *)dp;
00315 
00316     if (!data->length) return MAD_FLOW_STOP;
00317 
00318     unsigned char const *start = data->start;
00319     unsigned long length = data->length;
00320 
00321 #ifdef HAVE_ID3TAG
00322     if (length > ID3_TAG_QUERYSIZE) {
00323         int taglen = id3_tag_query(start, ID3_TAG_QUERYSIZE);
00324         if (taglen > 0) {
00325 //            cerr << "ID3 tag length to skip: " << taglen << endl;
00326             start += taglen;
00327             length -= taglen;
00328         }
00329     }
00330 #endif
00331 
00332     mad_stream_buffer(stream, start, length);
00333     data->length = 0;
00334 
00335     return MAD_FLOW_CONTINUE;
00336 }
00337 
00338 enum mad_flow
00339 MP3FileReader::output(void *dp,
00340                       struct mad_header const *header,
00341                       struct mad_pcm *pcm)
00342 {
00343     DecoderData *data = (DecoderData *)dp;
00344     return data->reader->accept(header, pcm);
00345 }
00346 
00347 enum mad_flow
00348 MP3FileReader::accept(struct mad_header const *header,
00349                       struct mad_pcm *pcm)
00350 {
00351     int channels = pcm->channels;
00352     int frames = pcm->length;
00353 
00354     if (header) {
00355         m_bitrateNum += header->bitrate;
00356         m_bitrateDenom ++;
00357     }
00358 
00359     if (frames < 1) return MAD_FLOW_CONTINUE;
00360 
00361     if (m_channelCount == 0) {
00362 
00363         m_fileRate = pcm->samplerate;
00364         m_channelCount = channels;
00365 
00366         initialiseDecodeCache();
00367 
00368         if (m_cacheMode == CacheInTemporaryFile) {
00369 //            SVDEBUG << "MP3FileReader::accept: channel count " << m_channelCount << ", file rate " << m_fileRate << ", about to start serialised section" << endl;
00370             startSerialised("MP3FileReader::Decode");
00371         }
00372     }
00373     
00374     if (m_bitrateDenom > 0) {
00375         double bitrate = m_bitrateNum / m_bitrateDenom;
00376         double duration = double(m_fileSize * 8) / bitrate;
00377         double elapsed = double(m_frameCount) / m_sampleRate;
00378         double percent = 100;
00379         if (duration > 0.0) percent = ((elapsed * 100.0) / duration);
00380         int p = int(percent);
00381         if (p < 1) p = 1;
00382         if (p > 99) p = 99;
00383         if (m_completion != p && m_reporter) {
00384             m_completion = p;
00385             m_reporter->setProgress(m_completion);
00386         }
00387     }
00388 
00389     if (m_cancelled) return MAD_FLOW_STOP;
00390 
00391     if (!isDecodeCacheInitialised()) {
00392         initialiseDecodeCache();
00393     }
00394 
00395     if (int(m_samplebuffersize) < frames) {
00396         if (!m_samplebuffer) {
00397             m_samplebuffer = new float *[channels];
00398             for (int c = 0; c < channels; ++c) {
00399                 m_samplebuffer[c] = 0;
00400             }
00401         }
00402         for (int c = 0; c < channels; ++c) {
00403             delete[] m_samplebuffer[c];
00404             m_samplebuffer[c] = new float[frames];
00405         }
00406         m_samplebuffersize = frames;
00407     }
00408 
00409     int activeChannels = int(sizeof(pcm->samples) / sizeof(pcm->samples[0]));
00410 
00411     for (int ch = 0; ch < channels; ++ch) {
00412 
00413         for (int i = 0; i < frames; ++i) {
00414 
00415             mad_fixed_t sample = 0;
00416             if (ch < activeChannels) {
00417                 sample = pcm->samples[ch][i];
00418             }
00419             float fsample = float(sample) / float(MAD_F_ONE);
00420             
00421             m_samplebuffer[ch][i] = fsample;
00422         }
00423     }
00424 
00425     addSamplesToDecodeCache(m_samplebuffer, frames);
00426 
00427     return MAD_FLOW_CONTINUE;
00428 }
00429 
00430 enum mad_flow
00431 MP3FileReader::error(void * /* dp */,
00432                      struct mad_stream * /* stream */,
00433                      struct mad_frame *)
00434 {
00435 //    DecoderData *data = (DecoderData *)dp;
00436 
00437 //    fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %lu\n",
00438 //          stream->error, mad_stream_errorstr(stream),
00439 //          (unsigned long)(stream->this_frame - data->start));
00440 
00441     return MAD_FLOW_CONTINUE;
00442 }
00443 
00444 void
00445 MP3FileReader::getSupportedExtensions(std::set<QString> &extensions)
00446 {
00447     extensions.insert("mp3");
00448 }
00449 
00450 bool
00451 MP3FileReader::supportsExtension(QString extension)
00452 {
00453     std::set<QString> extensions;
00454     getSupportedExtensions(extensions);
00455     return (extensions.find(extension.toLower()) != extensions.end());
00456 }
00457 
00458 bool
00459 MP3FileReader::supportsContentType(QString type)
00460 {
00461     return (type == "audio/mpeg");
00462 }
00463 
00464 bool
00465 MP3FileReader::supports(FileSource &source)
00466 {
00467     return (supportsExtension(source.getExtension()) ||
00468             supportsContentType(source.getContentType()));
00469 }
00470 
00471 
00472 #endif