annotate data/fileio/OggVorbisFileReader.cpp @ 316:3a6725f285d6

* Make RemoteFile far more pervasive, and use it for local files as well so that we can handle both transparently. Make it shallow copy with reference counting, so it can be used by value without having to worry about the cache file lifetime. Use RemoteFile for MainWindow file-open functions, etc
author Chris Cannam
date Thu, 18 Oct 2007 15:31:20 +0000
parents c022976d18e8
children c324d410b096
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@148 20 #include "base/Profiler.h"
Chris@150 21 #include "system/System.h"
Chris@148 22
Chris@148 23 #include <sys/types.h>
Chris@148 24 #include <sys/stat.h>
Chris@148 25 #include <sys/mman.h>
Chris@148 26 #include <fcntl.h>
Chris@148 27 #include <cmath>
Chris@148 28
Chris@148 29 #include <QApplication>
Chris@148 30 #include <QFileInfo>
Chris@148 31 #include <QProgressDialog>
Chris@148 32
Chris@148 33 static int instances = 0;
Chris@148 34
Chris@316 35 OggVorbisFileReader::OggVorbisFileReader(RemoteFile source,
Chris@263 36 DecodeMode decodeMode,
Chris@297 37 CacheMode mode,
Chris@297 38 size_t targetRate) :
Chris@297 39 CodedAudioFileReader(mode, targetRate),
Chris@316 40 m_source(source),
Chris@316 41 m_path(source.getLocalFilename()),
Chris@148 42 m_progress(0),
Chris@148 43 m_fileSize(0),
Chris@148 44 m_bytesRead(0),
Chris@271 45 m_commentsRead(false),
Chris@263 46 m_cancelled(false),
Chris@265 47 m_completion(0),
Chris@263 48 m_decodeThread(0)
Chris@148 49 {
Chris@148 50 m_channelCount = 0;
Chris@297 51 m_fileRate = 0;
Chris@148 52
Chris@316 53 std::cerr << "OggVorbisFileReader::OggVorbisFileReader(" << m_path.toLocal8Bit().data() << "): now have " << (++instances) << " instances" << std::endl;
Chris@148 54
Chris@148 55 Profiler profiler("OggVorbisFileReader::OggVorbisFileReader", true);
Chris@148 56
Chris@316 57 QFileInfo info(m_path);
Chris@148 58 m_fileSize = info.size();
Chris@148 59
Chris@316 60 if (!(m_oggz = oggz_open(m_path.toLocal8Bit().data(), OGGZ_READ))) {
Chris@316 61 m_error = QString("File %1 is not an OGG file.").arg(m_path);
Chris@148 62 return;
Chris@148 63 }
Chris@148 64
Chris@148 65 FishSoundInfo fsinfo;
Chris@148 66 m_fishSound = fish_sound_new(FISH_SOUND_DECODE, &fsinfo);
Chris@148 67
Chris@148 68 fish_sound_set_decoded_callback(m_fishSound, acceptFrames, this);
Chris@263 69 oggz_set_read_callback(m_oggz, -1, readPacket, this);
Chris@148 70
Chris@263 71 if (decodeMode == DecodeAtOnce) {
Chris@263 72
Chris@148 73 m_progress = new QProgressDialog
Chris@316 74 (QObject::tr("Decoding %1...").arg(QFileInfo(m_path).fileName()),
Chris@148 75 QObject::tr("Stop"), 0, 100);
Chris@148 76 m_progress->hide();
Chris@148 77
Chris@263 78 while (oggz_read(m_oggz, 1024) > 0);
Chris@263 79
Chris@263 80 fish_sound_delete(m_fishSound);
Chris@263 81 m_fishSound = 0;
Chris@263 82 oggz_close(m_oggz);
Chris@263 83 m_oggz = 0;
Chris@148 84
Chris@263 85 if (isDecodeCacheInitialised()) finishDecodeCache();
Chris@148 86
Chris@281 87 delete m_progress;
Chris@281 88 m_progress = 0;
Chris@148 89
Chris@263 90 } else {
Chris@263 91
Chris@263 92 while (oggz_read(m_oggz, 1024) > 0 &&
Chris@263 93 m_channelCount == 0);
Chris@263 94
Chris@263 95 if (m_channelCount > 0) {
Chris@263 96 m_decodeThread = new DecodeThread(this);
Chris@263 97 m_decodeThread->start();
Chris@263 98 }
Chris@148 99 }
Chris@148 100 }
Chris@148 101
Chris@148 102 OggVorbisFileReader::~OggVorbisFileReader()
Chris@148 103 {
Chris@290 104 std::cerr << "OggVorbisFileReader::~OggVorbisFileReader(" << m_path.toLocal8Bit().data() << "): now have " << (--instances) << " instances" << std::endl;
Chris@263 105 if (m_decodeThread) {
Chris@265 106 m_cancelled = true;
Chris@263 107 m_decodeThread->wait();
Chris@263 108 delete m_decodeThread;
Chris@263 109 }
Chris@148 110 }
Chris@148 111
Chris@263 112 void
Chris@263 113 OggVorbisFileReader::DecodeThread::run()
Chris@263 114 {
Chris@297 115 if (m_reader->m_cacheMode == CacheInTemporaryFile) {
Chris@297 116 m_reader->m_completion = 1;
Chris@297 117 m_reader->startSerialised("OggVorbisFileReader::Decode");
Chris@297 118 }
Chris@297 119
Chris@263 120 while (oggz_read(m_reader->m_oggz, 1024) > 0);
Chris@263 121
Chris@263 122 fish_sound_delete(m_reader->m_fishSound);
Chris@263 123 m_reader->m_fishSound = 0;
Chris@263 124 oggz_close(m_reader->m_oggz);
Chris@263 125 m_reader->m_oggz = 0;
Chris@263 126
Chris@263 127 if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
Chris@265 128 m_reader->m_completion = 100;
Chris@297 129
Chris@297 130 m_reader->endSerialised();
Chris@263 131 }
Chris@263 132
Chris@148 133 int
Chris@148 134 OggVorbisFileReader::readPacket(OGGZ *, ogg_packet *packet, long, void *data)
Chris@148 135 {
Chris@148 136 OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
Chris@148 137 FishSound *fs = reader->m_fishSound;
Chris@148 138
Chris@148 139 fish_sound_prepare_truncation(fs, packet->granulepos, packet->e_o_s);
Chris@148 140 fish_sound_decode(fs, packet->packet, packet->bytes);
Chris@148 141
Chris@148 142 reader->m_bytesRead += packet->bytes;
Chris@265 143
Chris@265 144 // The number of bytes read by this function is smaller than
Chris@265 145 // the file size because of the packet headers
Chris@265 146 int progress = lrint(double(reader->m_bytesRead) * 114 /
Chris@265 147 double(reader->m_fileSize));
Chris@265 148 if (progress > 99) progress = 99;
Chris@265 149 reader->m_completion = progress;
Chris@148 150
Chris@148 151 if (reader->m_fileSize > 0 && reader->m_progress) {
Chris@148 152 if (progress > reader->m_progress->value()) {
Chris@148 153 reader->m_progress->setValue(progress);
Chris@148 154 reader->m_progress->show();
Chris@148 155 reader->m_progress->raise();
Chris@148 156 qApp->processEvents();
Chris@148 157 if (reader->m_progress->wasCanceled()) {
Chris@148 158 reader->m_cancelled = true;
Chris@148 159 }
Chris@148 160 }
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@271 174 const FishSoundComment *comment = fish_sound_comment_first_byname
Chris@271 175 (fs, "TITLE");
Chris@271 176 if (comment && comment->value) {
Chris@290 177 reader->m_title = QString::fromUtf8(comment->value);
Chris@271 178 }
Chris@271 179 reader->m_commentsRead = true;
Chris@271 180 }
Chris@271 181
Chris@148 182 if (reader->m_channelCount == 0) {
Chris@148 183 FishSoundInfo fsinfo;
Chris@148 184 fish_sound_command(fs, FISH_SOUND_GET_INFO,
Chris@148 185 &fsinfo, sizeof(FishSoundInfo));
Chris@297 186 reader->m_fileRate = fsinfo.samplerate;
Chris@148 187 reader->m_channelCount = fsinfo.channels;
Chris@148 188 reader->initialiseDecodeCache();
Chris@148 189 }
Chris@148 190
Chris@148 191 if (nframes > 0) {
Chris@297 192 reader->addSamplesToDecodeCache(frames, nframes);
Chris@148 193 }
Chris@148 194
Chris@148 195 if (reader->m_cancelled) return 1;
Chris@148 196 return 0;
Chris@148 197 }
Chris@148 198
Chris@157 199 void
Chris@290 200 OggVorbisFileReader::getSupportedExtensions(std::set<QString> &extensions)
Chris@157 201 {
Chris@157 202 extensions.insert("ogg");
Chris@157 203 }
Chris@157 204
Chris@316 205 bool
Chris@316 206 OggVorbisFileReader::supportsExtension(QString extension)
Chris@316 207 {
Chris@316 208 std::set<QString> extensions;
Chris@316 209 getSupportedExtensions(extensions);
Chris@316 210 return (extensions.find(extension.toLower()) != extensions.end());
Chris@316 211 }
Chris@316 212
Chris@316 213 bool
Chris@316 214 OggVorbisFileReader::supportsContentType(QString type)
Chris@316 215 {
Chris@316 216 return (type == "application/ogg");
Chris@316 217 }
Chris@316 218
Chris@316 219 bool
Chris@316 220 OggVorbisFileReader::supports(RemoteFile &source)
Chris@316 221 {
Chris@316 222 return (supportsExtension(source.getExtension()) ||
Chris@316 223 supportsContentType(source.getContentType()));
Chris@316 224 }
Chris@316 225
Chris@148 226 #endif
Chris@148 227 #endif