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