00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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
00152
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