annotate data/fileio/OggVorbisFileReader.cpp @ 299:576be0d0d218

* Merge transform directory from sv-match-alignment branch (the previous comment included notes for this stuff, but I missed it in the actual merge) * Fix crash when a transform fails to create an output model and the thread that created the transform then deletes its input model thinking it's no longer needed, even though the transform run thread is still using it -- fix is to wait() on the transform before returning the null output model
author Chris Cannam
date Fri, 28 Sep 2007 16:15:06 +0000
parents c022976d18e8
children 3a6725f285d6
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@290 35 OggVorbisFileReader::OggVorbisFileReader(QString path,
Chris@263 36 DecodeMode decodeMode,
Chris@297 37 CacheMode mode,
Chris@297 38 size_t targetRate) :
Chris@297 39 CodedAudioFileReader(mode, targetRate),
Chris@148 40 m_path(path),
Chris@148 41 m_progress(0),
Chris@148 42 m_fileSize(0),
Chris@148 43 m_bytesRead(0),
Chris@271 44 m_commentsRead(false),
Chris@263 45 m_cancelled(false),
Chris@265 46 m_completion(0),
Chris@263 47 m_decodeThread(0)
Chris@148 48 {
Chris@148 49 m_channelCount = 0;
Chris@297 50 m_fileRate = 0;
Chris@148 51
Chris@290 52 std::cerr << "OggVorbisFileReader::OggVorbisFileReader(" << path.toLocal8Bit().data() << "): now have " << (++instances) << " instances" << std::endl;
Chris@148 53
Chris@148 54 Profiler profiler("OggVorbisFileReader::OggVorbisFileReader", true);
Chris@148 55
Chris@290 56 QFileInfo info(path);
Chris@148 57 m_fileSize = info.size();
Chris@148 58
Chris@290 59 if (!(m_oggz = oggz_open(path.toLocal8Bit().data(), OGGZ_READ))) {
Chris@290 60 m_error = QString("File %1 is not an OGG file.").arg(path);
Chris@148 61 return;
Chris@148 62 }
Chris@148 63
Chris@148 64 FishSoundInfo fsinfo;
Chris@148 65 m_fishSound = fish_sound_new(FISH_SOUND_DECODE, &fsinfo);
Chris@148 66
Chris@148 67 fish_sound_set_decoded_callback(m_fishSound, acceptFrames, this);
Chris@263 68 oggz_set_read_callback(m_oggz, -1, readPacket, this);
Chris@148 69
Chris@263 70 if (decodeMode == DecodeAtOnce) {
Chris@263 71
Chris@148 72 m_progress = new QProgressDialog
Chris@290 73 (QObject::tr("Decoding %1...").arg(QFileInfo(path).fileName()),
Chris@148 74 QObject::tr("Stop"), 0, 100);
Chris@148 75 m_progress->hide();
Chris@148 76
Chris@263 77 while (oggz_read(m_oggz, 1024) > 0);
Chris@263 78
Chris@263 79 fish_sound_delete(m_fishSound);
Chris@263 80 m_fishSound = 0;
Chris@263 81 oggz_close(m_oggz);
Chris@263 82 m_oggz = 0;
Chris@148 83
Chris@263 84 if (isDecodeCacheInitialised()) finishDecodeCache();
Chris@148 85
Chris@281 86 delete m_progress;
Chris@281 87 m_progress = 0;
Chris@148 88
Chris@263 89 } else {
Chris@263 90
Chris@263 91 while (oggz_read(m_oggz, 1024) > 0 &&
Chris@263 92 m_channelCount == 0);
Chris@263 93
Chris@263 94 if (m_channelCount > 0) {
Chris@263 95 m_decodeThread = new DecodeThread(this);
Chris@263 96 m_decodeThread->start();
Chris@263 97 }
Chris@148 98 }
Chris@148 99 }
Chris@148 100
Chris@148 101 OggVorbisFileReader::~OggVorbisFileReader()
Chris@148 102 {
Chris@290 103 std::cerr << "OggVorbisFileReader::~OggVorbisFileReader(" << m_path.toLocal8Bit().data() << "): now have " << (--instances) << " instances" << std::endl;
Chris@263 104 if (m_decodeThread) {
Chris@265 105 m_cancelled = true;
Chris@263 106 m_decodeThread->wait();
Chris@263 107 delete m_decodeThread;
Chris@263 108 }
Chris@148 109 }
Chris@148 110
Chris@263 111 void
Chris@263 112 OggVorbisFileReader::DecodeThread::run()
Chris@263 113 {
Chris@297 114 if (m_reader->m_cacheMode == CacheInTemporaryFile) {
Chris@297 115 m_reader->m_completion = 1;
Chris@297 116 m_reader->startSerialised("OggVorbisFileReader::Decode");
Chris@297 117 }
Chris@297 118
Chris@263 119 while (oggz_read(m_reader->m_oggz, 1024) > 0);
Chris@263 120
Chris@263 121 fish_sound_delete(m_reader->m_fishSound);
Chris@263 122 m_reader->m_fishSound = 0;
Chris@263 123 oggz_close(m_reader->m_oggz);
Chris@263 124 m_reader->m_oggz = 0;
Chris@263 125
Chris@263 126 if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
Chris@265 127 m_reader->m_completion = 100;
Chris@297 128
Chris@297 129 m_reader->endSerialised();
Chris@263 130 }
Chris@263 131
Chris@148 132 int
Chris@148 133 OggVorbisFileReader::readPacket(OGGZ *, ogg_packet *packet, long, void *data)
Chris@148 134 {
Chris@148 135 OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
Chris@148 136 FishSound *fs = reader->m_fishSound;
Chris@148 137
Chris@148 138 fish_sound_prepare_truncation(fs, packet->granulepos, packet->e_o_s);
Chris@148 139 fish_sound_decode(fs, packet->packet, packet->bytes);
Chris@148 140
Chris@148 141 reader->m_bytesRead += packet->bytes;
Chris@265 142
Chris@265 143 // The number of bytes read by this function is smaller than
Chris@265 144 // the file size because of the packet headers
Chris@265 145 int progress = lrint(double(reader->m_bytesRead) * 114 /
Chris@265 146 double(reader->m_fileSize));
Chris@265 147 if (progress > 99) progress = 99;
Chris@265 148 reader->m_completion = progress;
Chris@148 149
Chris@148 150 if (reader->m_fileSize > 0 && reader->m_progress) {
Chris@148 151 if (progress > reader->m_progress->value()) {
Chris@148 152 reader->m_progress->setValue(progress);
Chris@148 153 reader->m_progress->show();
Chris@148 154 reader->m_progress->raise();
Chris@148 155 qApp->processEvents();
Chris@148 156 if (reader->m_progress->wasCanceled()) {
Chris@148 157 reader->m_cancelled = true;
Chris@148 158 }
Chris@148 159 }
Chris@265 160 }
Chris@148 161
Chris@148 162 if (reader->m_cancelled) return 1;
Chris@148 163 return 0;
Chris@148 164 }
Chris@148 165
Chris@148 166 int
Chris@148 167 OggVorbisFileReader::acceptFrames(FishSound *fs, float **frames, long nframes,
Chris@148 168 void *data)
Chris@148 169 {
Chris@148 170 OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
Chris@148 171
Chris@271 172 if (!reader->m_commentsRead) {
Chris@271 173 const FishSoundComment *comment = fish_sound_comment_first_byname
Chris@271 174 (fs, "TITLE");
Chris@271 175 if (comment && comment->value) {
Chris@290 176 reader->m_title = QString::fromUtf8(comment->value);
Chris@271 177 }
Chris@271 178 reader->m_commentsRead = true;
Chris@271 179 }
Chris@271 180
Chris@148 181 if (reader->m_channelCount == 0) {
Chris@148 182 FishSoundInfo fsinfo;
Chris@148 183 fish_sound_command(fs, FISH_SOUND_GET_INFO,
Chris@148 184 &fsinfo, sizeof(FishSoundInfo));
Chris@297 185 reader->m_fileRate = fsinfo.samplerate;
Chris@148 186 reader->m_channelCount = fsinfo.channels;
Chris@148 187 reader->initialiseDecodeCache();
Chris@148 188 }
Chris@148 189
Chris@148 190 if (nframes > 0) {
Chris@297 191 reader->addSamplesToDecodeCache(frames, nframes);
Chris@148 192 }
Chris@148 193
Chris@148 194 if (reader->m_cancelled) return 1;
Chris@148 195 return 0;
Chris@148 196 }
Chris@148 197
Chris@157 198 void
Chris@290 199 OggVorbisFileReader::getSupportedExtensions(std::set<QString> &extensions)
Chris@157 200 {
Chris@157 201 extensions.insert("ogg");
Chris@157 202 }
Chris@157 203
Chris@148 204 #endif
Chris@148 205 #endif