OggVorbisFileReader.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_OGGZ
00017 #ifdef HAVE_FISHSOUND
00018 
00019 #include "OggVorbisFileReader.h"
00020 #include "ProgressPrinter.h"
00021 
00022 #include "base/Profiler.h"
00023 #include "system/System.h"
00024 
00025 #include <sys/types.h>
00026 #include <sys/stat.h>
00027 #include <sys/mman.h>
00028 #include <fcntl.h>
00029 #include <cmath>
00030 
00031 #include <QApplication>
00032 #include <QFileInfo>
00033 #include <QProgressDialog>
00034 
00035 static int instances = 0;
00036 
00037 OggVorbisFileReader::OggVorbisFileReader(FileSource source,
00038                                          DecodeMode decodeMode,
00039                                          CacheMode mode,
00040                                          size_t targetRate) :
00041     CodedAudioFileReader(mode, targetRate),
00042     m_source(source),
00043     m_path(source.getLocalFilename()),
00044     m_progress(0),
00045     m_fileSize(0),
00046     m_bytesRead(0),
00047     m_commentsRead(false),
00048     m_cancelled(false),
00049     m_completion(0),
00050     m_decodeThread(0)
00051 {
00052     m_channelCount = 0;
00053     m_fileRate = 0;
00054 
00055     std::cerr << "OggVorbisFileReader::OggVorbisFileReader(" << m_path.toLocal8Bit().data() << "): now have " << (++instances) << " instances" << std::endl;
00056 
00057     Profiler profiler("OggVorbisFileReader::OggVorbisFileReader", true);
00058 
00059     QFileInfo info(m_path);
00060     m_fileSize = info.size();
00061 
00062     if (!(m_oggz = oggz_open(m_path.toLocal8Bit().data(), OGGZ_READ))) {
00063         m_error = QString("File %1 is not an OGG file.").arg(m_path);
00064         return;
00065     }
00066 
00067     FishSoundInfo fsinfo;
00068     m_fishSound = fish_sound_new(FISH_SOUND_DECODE, &fsinfo);
00069 
00070     fish_sound_set_decoded_callback(m_fishSound, acceptFrames, this);
00071     oggz_set_read_callback(m_oggz, -1, readPacket, this);
00072 
00073     if (decodeMode == DecodeAtOnce) {
00074 
00075         if (dynamic_cast<QApplication *>(QCoreApplication::instance())) {
00076             m_progress = new QProgressDialog
00077                 (QObject::tr("Decoding %1...").arg(QFileInfo(m_path).fileName()),
00078                  QObject::tr("Stop"), 0, 100);
00079             m_progress->hide();
00080         } else {
00081             ProgressPrinter *pp = new ProgressPrinter(tr("Decoding..."), this);
00082             connect(this, SIGNAL(progress(int)), pp, SLOT(progress(int)));
00083         }
00084 
00085         while (oggz_read(m_oggz, 1024) > 0);
00086         
00087         fish_sound_delete(m_fishSound);
00088         m_fishSound = 0;
00089         oggz_close(m_oggz);
00090         m_oggz = 0;
00091 
00092         if (isDecodeCacheInitialised()) finishDecodeCache();
00093 
00094         delete m_progress;
00095         m_progress = 0;
00096 
00097     } else {
00098 
00099         while (oggz_read(m_oggz, 1024) > 0 &&
00100                m_channelCount == 0);
00101 
00102         if (m_channelCount > 0) {
00103             m_decodeThread = new DecodeThread(this);
00104             m_decodeThread->start();
00105         }
00106     }
00107 }
00108 
00109 OggVorbisFileReader::~OggVorbisFileReader()
00110 {
00111     std::cerr << "OggVorbisFileReader::~OggVorbisFileReader(" << m_path.toLocal8Bit().data() << "): now have " << (--instances) << " instances" << std::endl;
00112     if (m_decodeThread) {
00113         m_cancelled = true;
00114         m_decodeThread->wait();
00115         delete m_decodeThread;
00116     }
00117 }
00118 
00119 void
00120 OggVorbisFileReader::DecodeThread::run()
00121 {
00122     if (m_reader->m_cacheMode == CacheInTemporaryFile) {
00123         m_reader->m_completion = 1;
00124         m_reader->startSerialised("OggVorbisFileReader::Decode");
00125     }
00126 
00127     while (oggz_read(m_reader->m_oggz, 1024) > 0);
00128         
00129     fish_sound_delete(m_reader->m_fishSound);
00130     m_reader->m_fishSound = 0;
00131     oggz_close(m_reader->m_oggz);
00132     m_reader->m_oggz = 0;
00133     
00134     if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
00135     m_reader->m_completion = 100;
00136 
00137     m_reader->endSerialised();
00138 } 
00139 
00140 int
00141 OggVorbisFileReader::readPacket(OGGZ *, ogg_packet *packet, long, void *data)
00142 {
00143     OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
00144     FishSound *fs = reader->m_fishSound;
00145 
00146     fish_sound_prepare_truncation(fs, packet->granulepos, packet->e_o_s);
00147     fish_sound_decode(fs, packet->packet, packet->bytes);
00148 
00149     reader->m_bytesRead += packet->bytes;
00150 
00151     // The number of bytes read by this function is smaller than
00152     // the file size because of the packet headers
00153     int p = lrint(double(reader->m_bytesRead) * 114 /
00154                   double(reader->m_fileSize));
00155     if (p > 99) p = 99;
00156     reader->m_completion = p;
00157     reader->progress(p);
00158 
00159     if (reader->m_fileSize > 0 && reader->m_progress) {
00160         if (p > reader->m_progress->value()) {
00161             reader->m_progress->setValue(p);
00162             reader->m_progress->show();
00163             reader->m_progress->raise();
00164             qApp->processEvents();
00165             if (reader->m_progress->wasCanceled()) {
00166                 reader->m_cancelled = true;
00167             }
00168         }
00169     }
00170 
00171     if (reader->m_cancelled) return 1;
00172     return 0;
00173 }
00174 
00175 int
00176 OggVorbisFileReader::acceptFrames(FishSound *fs, float **frames, long nframes,
00177                                   void *data)
00178 {
00179     OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
00180 
00181     if (!reader->m_commentsRead) {
00182         {
00183             const FishSoundComment *comment = fish_sound_comment_first_byname
00184                 (fs, "TITLE");
00185             if (comment && comment->value) {
00186                 reader->m_title = QString::fromUtf8(comment->value);
00187             }
00188         }
00189         {
00190             const FishSoundComment *comment = fish_sound_comment_first_byname
00191                 (fs, "ARTIST");
00192             if (comment && comment->value) {
00193                 reader->m_maker = QString::fromUtf8(comment->value);
00194             }
00195         }
00196         reader->m_commentsRead = true;
00197     }
00198 
00199     if (reader->m_channelCount == 0) {
00200         FishSoundInfo fsinfo;
00201         fish_sound_command(fs, FISH_SOUND_GET_INFO,
00202                            &fsinfo, sizeof(FishSoundInfo));
00203         reader->m_fileRate = fsinfo.samplerate;
00204         reader->m_channelCount = fsinfo.channels;
00205         reader->initialiseDecodeCache();
00206     }
00207 
00208     if (nframes > 0) {
00209         reader->addSamplesToDecodeCache(frames, nframes);
00210     }
00211 
00212     if (reader->m_cancelled) return 1;
00213     return 0;
00214 }
00215 
00216 void
00217 OggVorbisFileReader::getSupportedExtensions(std::set<QString> &extensions)
00218 {
00219     extensions.insert("ogg");
00220 }
00221 
00222 bool
00223 OggVorbisFileReader::supportsExtension(QString extension)
00224 {
00225     std::set<QString> extensions;
00226     getSupportedExtensions(extensions);
00227     return (extensions.find(extension.toLower()) != extensions.end());
00228 }
00229 
00230 bool
00231 OggVorbisFileReader::supportsContentType(QString type)
00232 {
00233     return (type == "application/ogg");
00234 }
00235 
00236 bool
00237 OggVorbisFileReader::supports(FileSource &source)
00238 {
00239     return (supportsExtension(source.getExtension()) ||
00240             supportsContentType(source.getContentType()));
00241 }
00242 
00243 #endif
00244 #endif

Generated on Wed Feb 20 15:45:27 2008 for SonicVisualiser by  doxygen 1.5.1