annotate data/fileio/OggVorbisFileReader.cpp @ 392:183ee2a55fc7

* More work to abstract out interactive components used in the data library, so that it does not need to depend on QtGui.
author Chris Cannam
date Fri, 14 Mar 2008 17:14:21 +0000
parents e6d11871e4c9
children be49bf95d4a5
rev   line source
Chris@148 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@148 2
Chris@148 3 /*
Chris@148 4 Sonic Visualiser
Chris@148 5 An audio file viewer and annotation editor.
Chris@148 6 Centre for Digital Music, Queen Mary, University of London.
Chris@148 7 This file copyright 2006 Chris Cannam.
Chris@148 8
Chris@148 9 This program is free software; you can redistribute it and/or
Chris@148 10 modify it under the terms of the GNU General Public License as
Chris@148 11 published by the Free Software Foundation; either version 2 of the
Chris@148 12 License, or (at your option) any later version. See the file
Chris@148 13 COPYING included with this distribution for more information.
Chris@148 14 */
Chris@148 15
Chris@148 16 #ifdef HAVE_OGGZ
Chris@148 17 #ifdef HAVE_FISHSOUND
Chris@148 18
Chris@148 19 #include "OggVorbisFileReader.h"
Chris@357 20
Chris@392 21 #include "base/ProgressReporter.h"
Chris@148 22 #include "base/Profiler.h"
Chris@150 23 #include "system/System.h"
Chris@148 24
Chris@148 25 #include <sys/types.h>
Chris@148 26 #include <sys/stat.h>
Chris@148 27 #include <sys/mman.h>
Chris@148 28 #include <fcntl.h>
Chris@148 29 #include <cmath>
Chris@148 30
Chris@148 31 #include <QFileInfo>
Chris@148 32
Chris@148 33 static int instances = 0;
Chris@148 34
Chris@317 35 OggVorbisFileReader::OggVorbisFileReader(FileSource source,
Chris@263 36 DecodeMode decodeMode,
Chris@297 37 CacheMode mode,
Chris@392 38 size_t targetRate,
Chris@392 39 ProgressReporter *reporter) :
Chris@297 40 CodedAudioFileReader(mode, targetRate),
Chris@316 41 m_source(source),
Chris@316 42 m_path(source.getLocalFilename()),
Chris@392 43 m_reporter(reporter),
Chris@148 44 m_fileSize(0),
Chris@148 45 m_bytesRead(0),
Chris@271 46 m_commentsRead(false),
Chris@263 47 m_cancelled(false),
Chris@265 48 m_completion(0),
Chris@263 49 m_decodeThread(0)
Chris@148 50 {
Chris@148 51 m_channelCount = 0;
Chris@297 52 m_fileRate = 0;
Chris@148 53
Chris@316 54 std::cerr << "OggVorbisFileReader::OggVorbisFileReader(" << m_path.toLocal8Bit().data() << "): now have " << (++instances) << " instances" << std::endl;
Chris@148 55
Chris@148 56 Profiler profiler("OggVorbisFileReader::OggVorbisFileReader", true);
Chris@148 57
Chris@316 58 QFileInfo info(m_path);
Chris@148 59 m_fileSize = info.size();
Chris@148 60
Chris@316 61 if (!(m_oggz = oggz_open(m_path.toLocal8Bit().data(), OGGZ_READ))) {
Chris@316 62 m_error = QString("File %1 is not an OGG file.").arg(m_path);
Chris@148 63 return;
Chris@148 64 }
Chris@148 65
Chris@148 66 FishSoundInfo fsinfo;
Chris@148 67 m_fishSound = fish_sound_new(FISH_SOUND_DECODE, &fsinfo);
Chris@148 68
Chris@148 69 fish_sound_set_decoded_callback(m_fishSound, acceptFrames, this);
Chris@263 70 oggz_set_read_callback(m_oggz, -1, readPacket, this);
Chris@148 71
Chris@263 72 if (decodeMode == DecodeAtOnce) {
Chris@263 73
Chris@392 74 if (m_reporter) {
Chris@392 75 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
Chris@392 76 m_reporter->setMessage
Chris@392 77 (tr("Decoding %1...").arg(QFileInfo(m_path).fileName()));
Chris@327 78 }
Chris@148 79
Chris@263 80 while (oggz_read(m_oggz, 1024) > 0);
Chris@263 81
Chris@263 82 fish_sound_delete(m_fishSound);
Chris@263 83 m_fishSound = 0;
Chris@263 84 oggz_close(m_oggz);
Chris@263 85 m_oggz = 0;
Chris@148 86
Chris@263 87 if (isDecodeCacheInitialised()) finishDecodeCache();
Chris@148 88
Chris@392 89 } else {
Chris@148 90
Chris@392 91 if (m_reporter) m_reporter->setProgress(100);
Chris@263 92
Chris@263 93 while (oggz_read(m_oggz, 1024) > 0 &&
Chris@386 94 (m_channelCount == 0 || m_fileRate == 0 || m_sampleRate == 0));
Chris@263 95
Chris@263 96 if (m_channelCount > 0) {
Chris@263 97 m_decodeThread = new DecodeThread(this);
Chris@263 98 m_decodeThread->start();
Chris@263 99 }
Chris@148 100 }
Chris@148 101 }
Chris@148 102
Chris@148 103 OggVorbisFileReader::~OggVorbisFileReader()
Chris@148 104 {
Chris@290 105 std::cerr << "OggVorbisFileReader::~OggVorbisFileReader(" << m_path.toLocal8Bit().data() << "): now have " << (--instances) << " instances" << std::endl;
Chris@263 106 if (m_decodeThread) {
Chris@265 107 m_cancelled = true;
Chris@263 108 m_decodeThread->wait();
Chris@263 109 delete m_decodeThread;
Chris@263 110 }
Chris@148 111 }
Chris@148 112
Chris@263 113 void
Chris@392 114 OggVorbisFileReader::cancelled()
Chris@392 115 {
Chris@392 116 m_cancelled = true;
Chris@392 117 }
Chris@392 118
Chris@392 119 void
Chris@263 120 OggVorbisFileReader::DecodeThread::run()
Chris@263 121 {
Chris@297 122 if (m_reader->m_cacheMode == CacheInTemporaryFile) {
Chris@297 123 m_reader->m_completion = 1;
Chris@297 124 m_reader->startSerialised("OggVorbisFileReader::Decode");
Chris@297 125 }
Chris@297 126
Chris@263 127 while (oggz_read(m_reader->m_oggz, 1024) > 0);
Chris@263 128
Chris@263 129 fish_sound_delete(m_reader->m_fishSound);
Chris@263 130 m_reader->m_fishSound = 0;
Chris@263 131 oggz_close(m_reader->m_oggz);
Chris@263 132 m_reader->m_oggz = 0;
Chris@263 133
Chris@263 134 if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
Chris@265 135 m_reader->m_completion = 100;
Chris@297 136
Chris@297 137 m_reader->endSerialised();
Chris@263 138 }
Chris@263 139
Chris@148 140 int
Chris@148 141 OggVorbisFileReader::readPacket(OGGZ *, ogg_packet *packet, long, void *data)
Chris@148 142 {
Chris@148 143 OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
Chris@148 144 FishSound *fs = reader->m_fishSound;
Chris@148 145
Chris@148 146 fish_sound_prepare_truncation(fs, packet->granulepos, packet->e_o_s);
Chris@148 147 fish_sound_decode(fs, packet->packet, packet->bytes);
Chris@148 148
Chris@148 149 reader->m_bytesRead += packet->bytes;
Chris@265 150
Chris@265 151 // The number of bytes read by this function is smaller than
Chris@265 152 // the file size because of the packet headers
Chris@357 153 int p = lrint(double(reader->m_bytesRead) * 114 /
Chris@357 154 double(reader->m_fileSize));
Chris@357 155 if (p > 99) p = 99;
Chris@357 156 reader->m_completion = p;
Chris@357 157 reader->progress(p);
Chris@357 158
Chris@392 159 if (reader->m_fileSize > 0 && reader->m_reporter) {
Chris@392 160 reader->m_reporter->setProgress(p);
Chris@265 161 }
Chris@148 162
Chris@148 163 if (reader->m_cancelled) return 1;
Chris@148 164 return 0;
Chris@148 165 }
Chris@148 166
Chris@148 167 int
Chris@148 168 OggVorbisFileReader::acceptFrames(FishSound *fs, float **frames, long nframes,
Chris@148 169 void *data)
Chris@148 170 {
Chris@148 171 OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
Chris@148 172
Chris@271 173 if (!reader->m_commentsRead) {
Chris@333 174 {
Chris@333 175 const FishSoundComment *comment = fish_sound_comment_first_byname
Chris@333 176 (fs, "TITLE");
Chris@333 177 if (comment && comment->value) {
Chris@333 178 reader->m_title = QString::fromUtf8(comment->value);
Chris@333 179 }
Chris@333 180 }
Chris@333 181 {
Chris@333 182 const FishSoundComment *comment = fish_sound_comment_first_byname
Chris@333 183 (fs, "ARTIST");
Chris@333 184 if (comment && comment->value) {
Chris@333 185 reader->m_maker = QString::fromUtf8(comment->value);
Chris@333 186 }
Chris@271 187 }
Chris@271 188 reader->m_commentsRead = true;
Chris@271 189 }
Chris@271 190
Chris@148 191 if (reader->m_channelCount == 0) {
Chris@148 192 FishSoundInfo fsinfo;
Chris@148 193 fish_sound_command(fs, FISH_SOUND_GET_INFO,
Chris@148 194 &fsinfo, sizeof(FishSoundInfo));
Chris@297 195 reader->m_fileRate = fsinfo.samplerate;
Chris@148 196 reader->m_channelCount = fsinfo.channels;
Chris@148 197 reader->initialiseDecodeCache();
Chris@148 198 }
Chris@148 199
Chris@148 200 if (nframes > 0) {
Chris@297 201 reader->addSamplesToDecodeCache(frames, nframes);
Chris@148 202 }
Chris@148 203
Chris@148 204 if (reader->m_cancelled) return 1;
Chris@148 205 return 0;
Chris@148 206 }
Chris@148 207
Chris@157 208 void
Chris@290 209 OggVorbisFileReader::getSupportedExtensions(std::set<QString> &extensions)
Chris@157 210 {
Chris@157 211 extensions.insert("ogg");
Chris@157 212 }
Chris@157 213
Chris@316 214 bool
Chris@316 215 OggVorbisFileReader::supportsExtension(QString extension)
Chris@316 216 {
Chris@316 217 std::set<QString> extensions;
Chris@316 218 getSupportedExtensions(extensions);
Chris@316 219 return (extensions.find(extension.toLower()) != extensions.end());
Chris@316 220 }
Chris@316 221
Chris@316 222 bool
Chris@316 223 OggVorbisFileReader::supportsContentType(QString type)
Chris@316 224 {
Chris@316 225 return (type == "application/ogg");
Chris@316 226 }
Chris@316 227
Chris@316 228 bool
Chris@317 229 OggVorbisFileReader::supports(FileSource &source)
Chris@316 230 {
Chris@316 231 return (supportsExtension(source.getExtension()) ||
Chris@316 232 supportsContentType(source.getContentType()));
Chris@316 233 }
Chris@316 234
Chris@148 235 #endif
Chris@148 236 #endif