annotate data/fileio/OggVorbisFileReader.cpp @ 1346:75ad55315db4 3.0-integration

More work on getting tests (especially file encoding ones) running on Windows. Various problems here to do with interaction with test filenames in Hg repos
author Chris Cannam
date Fri, 06 Jan 2017 15:44:55 +0000
parents c380e56c95f5
children 1c9bbbb6116a
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 <fcntl.h>
Chris@148 28 #include <cmath>
Chris@148 29
Chris@148 30 #include <QFileInfo>
Chris@148 31
Chris@524 32 //static int instances = 0;
Chris@148 33
Chris@317 34 OggVorbisFileReader::OggVorbisFileReader(FileSource source,
Chris@263 35 DecodeMode decodeMode,
Chris@297 36 CacheMode mode,
Chris@1040 37 sv_samplerate_t targetRate,
Chris@920 38 bool normalised,
Chris@392 39 ProgressReporter *reporter) :
Chris@920 40 CodedAudioFileReader(mode, targetRate, normalised),
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@1279 51 SVDEBUG << "OggVorbisFileReader: local path: \"" << m_path
Chris@1279 52 << "\", decode mode: " << decodeMode << " ("
Chris@1279 53 << (decodeMode == DecodeAtOnce ? "DecodeAtOnce" : "DecodeThreaded")
Chris@1279 54 << ")" << endl;
Chris@1279 55
Chris@148 56 m_channelCount = 0;
Chris@297 57 m_fileRate = 0;
Chris@148 58
Chris@845 59 // SVDEBUG << "OggVorbisFileReader::OggVorbisFileReader(" << m_path << "): now have " << (++instances) << " instances" << endl;
Chris@148 60
Chris@1295 61 Profiler profiler("OggVorbisFileReader::OggVorbisFileReader");
Chris@148 62
Chris@316 63 QFileInfo info(m_path);
Chris@148 64 m_fileSize = info.size();
Chris@148 65
Chris@316 66 if (!(m_oggz = oggz_open(m_path.toLocal8Bit().data(), OGGZ_READ))) {
Chris@1343 67 m_error = QString("File %1 is not an OGG file.").arg(m_path);
Chris@1343 68 return;
Chris@148 69 }
Chris@148 70
Chris@148 71 FishSoundInfo fsinfo;
Chris@148 72 m_fishSound = fish_sound_new(FISH_SOUND_DECODE, &fsinfo);
Chris@148 73
Chris@148 74 fish_sound_set_decoded_callback(m_fishSound, acceptFrames, this);
Chris@620 75 oggz_set_read_callback(m_oggz, -1, (OggzReadPacket)readPacket, this);
Chris@148 76
Chris@263 77 if (decodeMode == DecodeAtOnce) {
Chris@263 78
Chris@392 79 if (m_reporter) {
Chris@392 80 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
Chris@392 81 m_reporter->setMessage
Chris@392 82 (tr("Decoding %1...").arg(QFileInfo(m_path).fileName()));
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@398 93 endSerialised();
Chris@148 94
Chris@392 95 } else {
Chris@148 96
Chris@392 97 if (m_reporter) m_reporter->setProgress(100);
Chris@263 98
Chris@263 99 while (oggz_read(m_oggz, 1024) > 0 &&
Chris@386 100 (m_channelCount == 0 || m_fileRate == 0 || m_sampleRate == 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@845 111 // SVDEBUG << "OggVorbisFileReader::~OggVorbisFileReader(" << m_path << "): now have " << (--instances) << " instances" << 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@392 120 OggVorbisFileReader::cancelled()
Chris@392 121 {
Chris@392 122 m_cancelled = true;
Chris@392 123 }
Chris@392 124
Chris@392 125 void
Chris@263 126 OggVorbisFileReader::DecodeThread::run()
Chris@263 127 {
Chris@297 128 if (m_reader->m_cacheMode == CacheInTemporaryFile) {
Chris@297 129 m_reader->m_completion = 1;
Chris@297 130 m_reader->startSerialised("OggVorbisFileReader::Decode");
Chris@297 131 }
Chris@297 132
Chris@263 133 while (oggz_read(m_reader->m_oggz, 1024) > 0);
Chris@263 134
Chris@263 135 fish_sound_delete(m_reader->m_fishSound);
Chris@263 136 m_reader->m_fishSound = 0;
Chris@263 137 oggz_close(m_reader->m_oggz);
Chris@263 138 m_reader->m_oggz = 0;
Chris@263 139
Chris@263 140 if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
Chris@265 141 m_reader->m_completion = 100;
Chris@297 142
Chris@297 143 m_reader->endSerialised();
Chris@263 144 }
Chris@263 145
Chris@148 146 int
Chris@620 147 OggVorbisFileReader::readPacket(OGGZ *, ogg_packet *packet, long, void *data)
Chris@148 148 {
Chris@148 149 OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
Chris@148 150 FishSound *fs = reader->m_fishSound;
Chris@148 151
Chris@1043 152 fish_sound_prepare_truncation(fs, packet->granulepos, int(packet->e_o_s));
Chris@620 153 fish_sound_decode(fs, packet->packet, packet->bytes);
Chris@148 154
Chris@620 155 reader->m_bytesRead += packet->bytes;
Chris@265 156
Chris@265 157 // The number of bytes read by this function is smaller than
Chris@265 158 // the file size because of the packet headers
Chris@1043 159 int p = int(lrint(double(reader->m_bytesRead) * 114 /
Chris@1043 160 double(reader->m_fileSize)));
Chris@357 161 if (p > 99) p = 99;
Chris@357 162 reader->m_completion = p;
Chris@357 163 reader->progress(p);
Chris@357 164
Chris@392 165 if (reader->m_fileSize > 0 && reader->m_reporter) {
Chris@392 166 reader->m_reporter->setProgress(p);
Chris@265 167 }
Chris@148 168
Chris@148 169 if (reader->m_cancelled) return 1;
Chris@148 170 return 0;
Chris@148 171 }
Chris@148 172
Chris@148 173 int
Chris@148 174 OggVorbisFileReader::acceptFrames(FishSound *fs, float **frames, long nframes,
Chris@1343 175 void *data)
Chris@148 176 {
Chris@148 177 OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
Chris@148 178
Chris@271 179 if (!reader->m_commentsRead) {
Chris@633 180 const FishSoundComment *comment;
Chris@1029 181 comment = fish_sound_comment_first_byname(fs, (char *)"TITLE");
Chris@633 182 if (comment && comment->value) {
Chris@633 183 reader->m_title = QString::fromUtf8(comment->value);
Chris@333 184 }
Chris@1029 185 comment = fish_sound_comment_first_byname(fs, (char *)"ARTIST");
Chris@633 186 if (comment && comment->value) {
Chris@633 187 reader->m_maker = QString::fromUtf8(comment->value);
Chris@633 188 }
Chris@633 189 comment = fish_sound_comment_first(fs);
Chris@633 190 while (comment) {
Chris@634 191 reader->m_tags[QString::fromUtf8(comment->name).toUpper()] =
Chris@633 192 QString::fromUtf8(comment->value);
Chris@633 193 comment = fish_sound_comment_next(fs, comment);
Chris@271 194 }
Chris@271 195 reader->m_commentsRead = true;
Chris@271 196 }
Chris@271 197
Chris@148 198 if (reader->m_channelCount == 0) {
Chris@1343 199 FishSoundInfo fsinfo;
Chris@1343 200 fish_sound_command(fs, FISH_SOUND_GET_INFO,
Chris@1343 201 &fsinfo, sizeof(FishSoundInfo));
Chris@1343 202 reader->m_fileRate = fsinfo.samplerate;
Chris@1343 203 reader->m_channelCount = fsinfo.channels;
Chris@148 204 reader->initialiseDecodeCache();
Chris@148 205 }
Chris@148 206
Chris@148 207 if (nframes > 0) {
Chris@297 208 reader->addSamplesToDecodeCache(frames, nframes);
Chris@148 209 }
Chris@148 210
Chris@148 211 if (reader->m_cancelled) return 1;
Chris@148 212 return 0;
Chris@148 213 }
Chris@148 214
Chris@157 215 void
Chris@290 216 OggVorbisFileReader::getSupportedExtensions(std::set<QString> &extensions)
Chris@157 217 {
Chris@157 218 extensions.insert("ogg");
Chris@571 219 extensions.insert("oga");
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