annotate data/fileio/OggVorbisFileReader.cpp @ 360:ac300d385ab2

* Various fixes to object lifetime management, particularly in the spectrum layer and for notification of main model deletion. The main purpose of this is to improve the behaviour of the spectrum, but I think it may also help with #1840922 Various crashes in Layer Summary window.
author Chris Cannam
date Wed, 23 Jan 2008 15:43:27 +0000
parents b92513201610
children e6d11871e4c9
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 #include "ProgressPrinter.h"
Chris@357 21
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 <QApplication>
Chris@148 32 #include <QFileInfo>
Chris@148 33 #include <QProgressDialog>
Chris@148 34
Chris@148 35 static int instances = 0;
Chris@148 36
Chris@317 37 OggVorbisFileReader::OggVorbisFileReader(FileSource source,
Chris@263 38 DecodeMode decodeMode,
Chris@297 39 CacheMode mode,
Chris@297 40 size_t targetRate) :
Chris@297 41 CodedAudioFileReader(mode, targetRate),
Chris@316 42 m_source(source),
Chris@316 43 m_path(source.getLocalFilename()),
Chris@148 44 m_progress(0),
Chris@148 45 m_fileSize(0),
Chris@148 46 m_bytesRead(0),
Chris@271 47 m_commentsRead(false),
Chris@263 48 m_cancelled(false),
Chris@265 49 m_completion(0),
Chris@263 50 m_decodeThread(0)
Chris@148 51 {
Chris@148 52 m_channelCount = 0;
Chris@297 53 m_fileRate = 0;
Chris@148 54
Chris@316 55 std::cerr << "OggVorbisFileReader::OggVorbisFileReader(" << m_path.toLocal8Bit().data() << "): now have " << (++instances) << " instances" << std::endl;
Chris@148 56
Chris@148 57 Profiler profiler("OggVorbisFileReader::OggVorbisFileReader", true);
Chris@148 58
Chris@316 59 QFileInfo info(m_path);
Chris@148 60 m_fileSize = info.size();
Chris@148 61
Chris@316 62 if (!(m_oggz = oggz_open(m_path.toLocal8Bit().data(), OGGZ_READ))) {
Chris@316 63 m_error = QString("File %1 is not an OGG file.").arg(m_path);
Chris@148 64 return;
Chris@148 65 }
Chris@148 66
Chris@148 67 FishSoundInfo fsinfo;
Chris@148 68 m_fishSound = fish_sound_new(FISH_SOUND_DECODE, &fsinfo);
Chris@148 69
Chris@148 70 fish_sound_set_decoded_callback(m_fishSound, acceptFrames, this);
Chris@263 71 oggz_set_read_callback(m_oggz, -1, readPacket, this);
Chris@148 72
Chris@263 73 if (decodeMode == DecodeAtOnce) {
Chris@263 74
Chris@327 75 if (dynamic_cast<QApplication *>(QCoreApplication::instance())) {
Chris@327 76 m_progress = new QProgressDialog
Chris@327 77 (QObject::tr("Decoding %1...").arg(QFileInfo(m_path).fileName()),
Chris@327 78 QObject::tr("Stop"), 0, 100);
Chris@327 79 m_progress->hide();
Chris@357 80 } else {
Chris@357 81 ProgressPrinter *pp = new ProgressPrinter(tr("Decoding..."), this);
Chris@357 82 connect(this, SIGNAL(progress(int)), pp, SLOT(progress(int)));
Chris@327 83 }
Chris@148 84
Chris@263 85 while (oggz_read(m_oggz, 1024) > 0);
Chris@263 86
Chris@263 87 fish_sound_delete(m_fishSound);
Chris@263 88 m_fishSound = 0;
Chris@263 89 oggz_close(m_oggz);
Chris@263 90 m_oggz = 0;
Chris@148 91
Chris@263 92 if (isDecodeCacheInitialised()) finishDecodeCache();
Chris@148 93
Chris@281 94 delete m_progress;
Chris@281 95 m_progress = 0;
Chris@148 96
Chris@263 97 } else {
Chris@263 98
Chris@263 99 while (oggz_read(m_oggz, 1024) > 0 &&
Chris@263 100 m_channelCount == 0);
Chris@263 101
Chris@263 102 if (m_channelCount > 0) {
Chris@263 103 m_decodeThread = new DecodeThread(this);
Chris@263 104 m_decodeThread->start();
Chris@263 105 }
Chris@148 106 }
Chris@148 107 }
Chris@148 108
Chris@148 109 OggVorbisFileReader::~OggVorbisFileReader()
Chris@148 110 {
Chris@290 111 std::cerr << "OggVorbisFileReader::~OggVorbisFileReader(" << m_path.toLocal8Bit().data() << "): now have " << (--instances) << " instances" << std::endl;
Chris@263 112 if (m_decodeThread) {
Chris@265 113 m_cancelled = true;
Chris@263 114 m_decodeThread->wait();
Chris@263 115 delete m_decodeThread;
Chris@263 116 }
Chris@148 117 }
Chris@148 118
Chris@263 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@148 159 if (reader->m_fileSize > 0 && reader->m_progress) {
Chris@357 160 if (p > reader->m_progress->value()) {
Chris@357 161 reader->m_progress->setValue(p);
Chris@148 162 reader->m_progress->show();
Chris@148 163 reader->m_progress->raise();
Chris@148 164 qApp->processEvents();
Chris@148 165 if (reader->m_progress->wasCanceled()) {
Chris@148 166 reader->m_cancelled = true;
Chris@148 167 }
Chris@148 168 }
Chris@265 169 }
Chris@148 170
Chris@148 171 if (reader->m_cancelled) return 1;
Chris@148 172 return 0;
Chris@148 173 }
Chris@148 174
Chris@148 175 int
Chris@148 176 OggVorbisFileReader::acceptFrames(FishSound *fs, float **frames, long nframes,
Chris@148 177 void *data)
Chris@148 178 {
Chris@148 179 OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
Chris@148 180
Chris@271 181 if (!reader->m_commentsRead) {
Chris@333 182 {
Chris@333 183 const FishSoundComment *comment = fish_sound_comment_first_byname
Chris@333 184 (fs, "TITLE");
Chris@333 185 if (comment && comment->value) {
Chris@333 186 reader->m_title = QString::fromUtf8(comment->value);
Chris@333 187 }
Chris@333 188 }
Chris@333 189 {
Chris@333 190 const FishSoundComment *comment = fish_sound_comment_first_byname
Chris@333 191 (fs, "ARTIST");
Chris@333 192 if (comment && comment->value) {
Chris@333 193 reader->m_maker = QString::fromUtf8(comment->value);
Chris@333 194 }
Chris@271 195 }
Chris@271 196 reader->m_commentsRead = true;
Chris@271 197 }
Chris@271 198
Chris@148 199 if (reader->m_channelCount == 0) {
Chris@148 200 FishSoundInfo fsinfo;
Chris@148 201 fish_sound_command(fs, FISH_SOUND_GET_INFO,
Chris@148 202 &fsinfo, sizeof(FishSoundInfo));
Chris@297 203 reader->m_fileRate = fsinfo.samplerate;
Chris@148 204 reader->m_channelCount = fsinfo.channels;
Chris@148 205 reader->initialiseDecodeCache();
Chris@148 206 }
Chris@148 207
Chris@148 208 if (nframes > 0) {
Chris@297 209 reader->addSamplesToDecodeCache(frames, nframes);
Chris@148 210 }
Chris@148 211
Chris@148 212 if (reader->m_cancelled) return 1;
Chris@148 213 return 0;
Chris@148 214 }
Chris@148 215
Chris@157 216 void
Chris@290 217 OggVorbisFileReader::getSupportedExtensions(std::set<QString> &extensions)
Chris@157 218 {
Chris@157 219 extensions.insert("ogg");
Chris@157 220 }
Chris@157 221
Chris@316 222 bool
Chris@316 223 OggVorbisFileReader::supportsExtension(QString extension)
Chris@316 224 {
Chris@316 225 std::set<QString> extensions;
Chris@316 226 getSupportedExtensions(extensions);
Chris@316 227 return (extensions.find(extension.toLower()) != extensions.end());
Chris@316 228 }
Chris@316 229
Chris@316 230 bool
Chris@316 231 OggVorbisFileReader::supportsContentType(QString type)
Chris@316 232 {
Chris@316 233 return (type == "application/ogg");
Chris@316 234 }
Chris@316 235
Chris@316 236 bool
Chris@317 237 OggVorbisFileReader::supports(FileSource &source)
Chris@316 238 {
Chris@316 239 return (supportsExtension(source.getExtension()) ||
Chris@316 240 supportsContentType(source.getContentType()));
Chris@316 241 }
Chris@316 242
Chris@148 243 #endif
Chris@148 244 #endif