annotate data/fileio/OggVorbisFileReader.cpp @ 263:71dfc6ab3b54

* Threaded mp3/ogg file reading. Not activated yet, as it doesn't work in context (SV needs to know the duration of its main model at the outset)
author Chris Cannam
date Thu, 24 May 2007 16:20:22 +0000
parents 06ad01f3e553
children e08f486e8d8c
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@263 35 OggVorbisFileReader::OggVorbisFileReader(QString path,
Chris@263 36 DecodeMode decodeMode,
Chris@148 37 CacheMode mode) :
Chris@148 38 CodedAudioFileReader(mode),
Chris@148 39 m_path(path),
Chris@148 40 m_progress(0),
Chris@148 41 m_fileSize(0),
Chris@148 42 m_bytesRead(0),
Chris@263 43 m_cancelled(false),
Chris@263 44 m_decodeThread(0)
Chris@148 45 {
Chris@148 46 m_frameCount = 0;
Chris@148 47 m_channelCount = 0;
Chris@148 48 m_sampleRate = 0;
Chris@148 49
Chris@148 50 std::cerr << "OggVorbisFileReader::OggVorbisFileReader(" << path.toLocal8Bit().data() << "): now have " << (++instances) << " instances" << std::endl;
Chris@148 51
Chris@148 52 Profiler profiler("OggVorbisFileReader::OggVorbisFileReader", true);
Chris@148 53
Chris@148 54 QFileInfo info(path);
Chris@148 55 m_fileSize = info.size();
Chris@148 56
Chris@263 57 if (!(m_oggz = oggz_open(path.toLocal8Bit().data(), OGGZ_READ))) {
Chris@148 58 m_error = QString("File %1 is not an OGG file.").arg(path);
Chris@148 59 return;
Chris@148 60 }
Chris@148 61
Chris@148 62 FishSoundInfo fsinfo;
Chris@148 63 m_fishSound = fish_sound_new(FISH_SOUND_DECODE, &fsinfo);
Chris@148 64
Chris@148 65 fish_sound_set_decoded_callback(m_fishSound, acceptFrames, this);
Chris@263 66 oggz_set_read_callback(m_oggz, -1, readPacket, this);
Chris@148 67
Chris@263 68 if (decodeMode == DecodeAtOnce) {
Chris@263 69
Chris@148 70 m_progress = new QProgressDialog
Chris@186 71 (QObject::tr("Decoding %1...").arg(QFileInfo(path).fileName()),
Chris@148 72 QObject::tr("Stop"), 0, 100);
Chris@148 73 m_progress->hide();
Chris@148 74
Chris@263 75 while (oggz_read(m_oggz, 1024) > 0);
Chris@263 76
Chris@263 77 fish_sound_delete(m_fishSound);
Chris@263 78 m_fishSound = 0;
Chris@263 79 oggz_close(m_oggz);
Chris@263 80 m_oggz = 0;
Chris@148 81
Chris@263 82 if (isDecodeCacheInitialised()) finishDecodeCache();
Chris@148 83
Chris@263 84 if (decodeMode == DecodeAtOnce) {
Chris@263 85 delete m_progress;
Chris@263 86 m_progress = 0;
Chris@263 87 }
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@148 103 std::cerr << "OggVorbisFileReader::~OggVorbisFileReader(" << m_path.toLocal8Bit().data() << "): now have " << (--instances) << " instances" << std::endl;
Chris@263 104 if (m_decodeThread) {
Chris@263 105 m_decodeThread->wait();
Chris@263 106 delete m_decodeThread;
Chris@263 107 }
Chris@148 108 }
Chris@148 109
Chris@263 110 void
Chris@263 111 OggVorbisFileReader::DecodeThread::run()
Chris@263 112 {
Chris@263 113 while (oggz_read(m_reader->m_oggz, 1024) > 0);
Chris@263 114
Chris@263 115 fish_sound_delete(m_reader->m_fishSound);
Chris@263 116 m_reader->m_fishSound = 0;
Chris@263 117 oggz_close(m_reader->m_oggz);
Chris@263 118 m_reader->m_oggz = 0;
Chris@263 119
Chris@263 120 if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
Chris@263 121 }
Chris@263 122
Chris@148 123 int
Chris@148 124 OggVorbisFileReader::readPacket(OGGZ *, ogg_packet *packet, long, void *data)
Chris@148 125 {
Chris@148 126 OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
Chris@148 127 FishSound *fs = reader->m_fishSound;
Chris@148 128
Chris@148 129 fish_sound_prepare_truncation(fs, packet->granulepos, packet->e_o_s);
Chris@148 130 fish_sound_decode(fs, packet->packet, packet->bytes);
Chris@148 131
Chris@148 132 reader->m_bytesRead += packet->bytes;
Chris@148 133
Chris@148 134 if (reader->m_fileSize > 0 && reader->m_progress) {
Chris@148 135 // The number of bytes read by this function is smaller than
Chris@148 136 // the file size because of the packet headers
Chris@148 137 int progress = lrint(double(reader->m_bytesRead) * 114 /
Chris@148 138 double(reader->m_fileSize));
Chris@148 139 if (progress > 99) progress = 99;
Chris@148 140 if (progress > reader->m_progress->value()) {
Chris@148 141 reader->m_progress->setValue(progress);
Chris@148 142 reader->m_progress->show();
Chris@148 143 reader->m_progress->raise();
Chris@148 144 qApp->processEvents();
Chris@148 145 if (reader->m_progress->wasCanceled()) {
Chris@148 146 reader->m_cancelled = true;
Chris@148 147 }
Chris@148 148 }
Chris@148 149 }
Chris@148 150
Chris@148 151 if (reader->m_cancelled) return 1;
Chris@148 152 return 0;
Chris@148 153 }
Chris@148 154
Chris@148 155 int
Chris@148 156 OggVorbisFileReader::acceptFrames(FishSound *fs, float **frames, long nframes,
Chris@148 157 void *data)
Chris@148 158 {
Chris@148 159 OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
Chris@148 160
Chris@148 161 if (reader->m_channelCount == 0) {
Chris@148 162 FishSoundInfo fsinfo;
Chris@148 163 fish_sound_command(fs, FISH_SOUND_GET_INFO,
Chris@148 164 &fsinfo, sizeof(FishSoundInfo));
Chris@148 165 reader->m_channelCount = fsinfo.channels;
Chris@148 166 reader->m_sampleRate = fsinfo.samplerate;
Chris@148 167 reader->initialiseDecodeCache();
Chris@148 168 }
Chris@148 169
Chris@148 170 if (nframes > 0) {
Chris@148 171
Chris@148 172 reader->m_frameCount += nframes;
Chris@148 173
Chris@148 174 for (long i = 0; i < nframes; ++i) {
Chris@148 175 for (size_t c = 0; c < reader->m_channelCount; ++c) {
Chris@148 176 reader->addSampleToDecodeCache(frames[c][i]);
Chris@148 177 }
Chris@148 178 }
Chris@148 179
Chris@148 180 MUNLOCK_SAMPLEBLOCK(reader->m_data);
Chris@148 181 }
Chris@148 182
Chris@148 183 if (reader->m_cancelled) return 1;
Chris@148 184 return 0;
Chris@148 185 }
Chris@148 186
Chris@157 187 void
Chris@157 188 OggVorbisFileReader::getSupportedExtensions(std::set<QString> &extensions)
Chris@157 189 {
Chris@157 190 extensions.insert("ogg");
Chris@157 191 }
Chris@157 192
Chris@148 193 #endif
Chris@148 194 #endif