aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Hoops2011-04-07 19:29:49 -0400
committerMatthew Hoops2011-04-07 19:40:07 -0400
commit8cf73e3fb4e44567a7afa527a0705acb90033a78 (patch)
treefa33a05454d837ebe357399071b10344608722d3
parentd40874d6f4bce278b4ab3b0ef6fb34d35466b852 (diff)
downloadscummvm-rg350-8cf73e3fb4e44567a7afa527a0705acb90033a78.tar.gz
scummvm-rg350-8cf73e3fb4e44567a7afa527a0705acb90033a78.tar.bz2
scummvm-rg350-8cf73e3fb4e44567a7afa527a0705acb90033a78.zip
AUDIO: Split QuickTime audio into a new class
Standalone QuickTime files can now be played as an AudioStream
-rw-r--r--audio/decoders/qdm2.cpp (renamed from video/codecs/qdm2.cpp)14
-rw-r--r--audio/decoders/qdm2.h (renamed from video/codecs/qdm2.h)14
-rw-r--r--audio/decoders/qdm2data.h (renamed from video/codecs/qdm2data.h)8
-rw-r--r--audio/decoders/quicktime.cpp311
-rw-r--r--audio/decoders/quicktime.h96
-rw-r--r--audio/module.mk2
-rw-r--r--video/module.mk1
-rw-r--r--video/qt_decoder.cpp215
-rw-r--r--video/qt_decoder.h19
9 files changed, 444 insertions, 236 deletions
diff --git a/video/codecs/qdm2.cpp b/audio/decoders/qdm2.cpp
index 762f56b3d7..2bbb608754 100644
--- a/video/codecs/qdm2.cpp
+++ b/audio/decoders/qdm2.cpp
@@ -26,18 +26,18 @@
// Based off ffmpeg's QDM2 decoder
#include "common/scummsys.h"
-#include "video/codecs/qdm2.h"
+#include "audio/decoders/qdm2.h"
-#ifdef VIDEO_CODECS_QDM2_H
+#ifdef AUDIO_QDM2_H
#include "audio/audiostream.h"
-#include "video/codecs/qdm2data.h"
+#include "audio/decoders/qdm2data.h"
#include "common/array.h"
#include "common/stream.h"
#include "common/system.h"
-namespace Video {
+namespace Audio {
enum {
SOFTCLIP_THRESHOLD = 27600,
@@ -152,7 +152,7 @@ struct RDFTContext {
FFTContext fft;
};
-class QDM2Stream : public Audio::AudioStream {
+class QDM2Stream : public AudioStream {
public:
QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData);
~QDM2Stream();
@@ -3272,10 +3272,10 @@ int QDM2Stream::readBuffer(int16 *buffer, const int numSamples) {
return decodedSamples;
}
-Audio::AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData) {
+AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData) {
return new QDM2Stream(stream, extraData);
}
-} // End of namespace Video
+} // End of namespace Audio
#endif
diff --git a/video/codecs/qdm2.h b/audio/decoders/qdm2.h
index a6acf3a83e..3d4b542de1 100644
--- a/video/codecs/qdm2.h
+++ b/audio/decoders/qdm2.h
@@ -26,18 +26,16 @@
// Only compile if Mohawk is enabled or if we're building dynamic modules
#if defined(ENABLE_MOHAWK) || defined(DYNAMIC_MODULES)
-#ifndef VIDEO_CODECS_QDM2_H
-#define VIDEO_CODECS_QDM2_H
+#ifndef AUDIO_QDM2_H
+#define AUDIO_QDM2_H
namespace Common {
class SeekableReadStream;
}
namespace Audio {
- class AudioStream;
-}
-namespace Video {
+class AudioStream;
/**
* Create a new AudioStream from the QDM2 data in the given stream.
@@ -46,9 +44,9 @@ namespace Video {
* @param extraData the QuickTime extra data stream
* @return a new AudioStream, or NULL, if an error occurred
*/
-Audio::AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData);
+AudioStream *makeQDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadStream *extraData);
-} // End of namespace Video
+} // End of namespace Audio
-#endif // VIDEO_CODECS_QDM2_H
+#endif // AUDIO_QDM2_H
#endif // Mohawk/Plugins guard
diff --git a/video/codecs/qdm2data.h b/audio/decoders/qdm2data.h
index e1a690bd2b..cfe1a3d10e 100644
--- a/video/codecs/qdm2data.h
+++ b/audio/decoders/qdm2data.h
@@ -23,12 +23,12 @@
*
*/
-#ifndef VIDEO_CODECS_QDM2DATA_H
-#define VIDEO_CODECS_QDM2DATA_H
+#ifndef AUDIO_QDM2DATA_H
+#define AUDIO_QDM2DATA_H
#include "common/scummsys.h"
-namespace Video {
+namespace Audio {
/// VLC TABLES
@@ -526,6 +526,6 @@ static const float type34_delta[10] = { // FIXME: covers 8 entries..
0.138071194291115f,0.333333343267441f,0.60947573184967f,1.0f,0.0f,
};
-} // End of namespace Video
+} // End of namespace Audio
#endif
diff --git a/audio/decoders/quicktime.cpp b/audio/decoders/quicktime.cpp
new file mode 100644
index 0000000000..af59d8803f
--- /dev/null
+++ b/audio/decoders/quicktime.cpp
@@ -0,0 +1,311 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/debug.h"
+#include "common/util.h"
+#include "common/memstream.h"
+#include "common/stream.h"
+
+#include "audio/audiostream.h"
+#include "audio/decoders/quicktime.h"
+
+// Codecs
+#include "audio/decoders/adpcm.h"
+#include "audio/decoders/qdm2.h"
+#include "audio/decoders/raw.h"
+
+namespace Audio {
+
+QuickTimeAudioDecoder::QuickTimeAudioDecoder() : Common::QuickTimeParser() {
+ _audStream = 0;
+}
+
+QuickTimeAudioDecoder::~QuickTimeAudioDecoder() {
+}
+
+bool QuickTimeAudioDecoder::loadFile(const Common::String &filename) {
+ if (!Common::QuickTimeParser::loadFile(filename))
+ return false;
+
+ init();
+ return true;
+}
+
+bool QuickTimeAudioDecoder::loadStream(Common::SeekableReadStream *stream) {
+ if (!Common::QuickTimeParser::loadStream(stream))
+ return false;
+
+ init();
+ return true;
+}
+
+void QuickTimeAudioDecoder::init() {
+ Common::QuickTimeParser::init();
+
+ _audioStreamIndex = -1;
+
+ // Find an audio stream
+ for (uint32 i = 0; i < _numStreams; i++)
+ if (_streams[i]->codec_type == CODEC_TYPE_AUDIO && _audioStreamIndex < 0)
+ _audioStreamIndex = i;
+
+ // Initialize audio, if present
+ if (_audioStreamIndex >= 0) {
+ AudioSampleDesc *entry = (AudioSampleDesc *)_streams[_audioStreamIndex]->sampleDescs[0];
+
+ if (checkAudioCodecSupport(entry->codecTag)) {
+ _audStream = makeQueuingAudioStream(entry->sampleRate, entry->channels == 2);
+ _curAudioChunk = 0;
+
+ // Make sure the bits per sample transfers to the sample size
+ if (entry->codecTag == MKID_BE('raw ') || entry->codecTag == MKID_BE('twos'))
+ _streams[_audioStreamIndex]->sample_size = (entry->bitsPerSample / 8) * entry->channels;
+ }
+ }
+}
+
+Common::QuickTimeParser::SampleDesc *QuickTimeAudioDecoder::readSampleDesc(MOVStreamContext *st, uint32 format) {
+ if (st->codec_type == CODEC_TYPE_AUDIO) {
+ debug(0, "Audio Codec FourCC: \'%s\'", tag2str(format));
+
+ AudioSampleDesc *entry = new AudioSampleDesc();
+ entry->codecTag = format;
+
+ uint16 stsdVersion = _fd->readUint16BE();
+ _fd->readUint16BE(); // revision level
+ _fd->readUint32BE(); // vendor
+
+ entry->channels = _fd->readUint16BE(); // channel count
+ entry->bitsPerSample = _fd->readUint16BE(); // sample size
+
+ _fd->readUint16BE(); // compression id = 0
+ _fd->readUint16BE(); // packet size = 0
+
+ entry->sampleRate = (_fd->readUint32BE() >> 16);
+
+ debug(0, "stsd version =%d", stsdVersion);
+ if (stsdVersion == 0) {
+ // Not used, except in special cases. See below.
+ entry->samplesPerFrame = entry->bytesPerFrame = 0;
+ } else if (stsdVersion == 1) {
+ // Read QT version 1 fields. In version 0 these dont exist.
+ entry->samplesPerFrame = _fd->readUint32BE();
+ debug(0, "stsd samples_per_frame =%d",entry->samplesPerFrame);
+ _fd->readUint32BE(); // bytes per packet
+ entry->bytesPerFrame = _fd->readUint32BE();
+ debug(0, "stsd bytes_per_frame =%d", entry->bytesPerFrame);
+ _fd->readUint32BE(); // bytes per sample
+ } else {
+ warning("Unsupported QuickTime STSD audio version %d", stsdVersion);
+ delete entry;
+ return 0;
+ }
+
+ // Version 0 videos (such as the Riven ones) don't have this set,
+ // but we need it later on. Add it in here.
+ if (format == MKID_BE('ima4')) {
+ entry->samplesPerFrame = 64;
+ entry->bytesPerFrame = 34 * entry->channels;
+ }
+
+ if (entry->sampleRate == 0 && st->time_scale > 1)
+ entry->sampleRate = st->time_scale;
+
+ return entry;
+ }
+
+ return 0;
+}
+
+bool QuickTimeAudioDecoder::checkAudioCodecSupport(uint32 tag) {
+ // Check if the codec is a supported codec
+ if (tag == MKID_BE('twos') || tag == MKID_BE('raw ') || tag == MKID_BE('ima4'))
+ return true;
+
+#ifdef AUDIO_QDM2_H
+ if (tag == MKID_BE('QDM2'))
+ return true;
+#endif
+
+ if (tag == MKID_BE('mp4a'))
+ warning("No MPEG-4 audio (AAC) support");
+ else
+ warning("Audio Codec Not Supported: \'%s\'", tag2str(tag));
+
+ return false;
+}
+
+AudioStream *QuickTimeAudioDecoder::createAudioStream(Common::SeekableReadStream *stream) {
+ if (!stream || _audioStreamIndex < 0)
+ return NULL;
+
+ AudioSampleDesc *entry = (AudioSampleDesc *)_streams[_audioStreamIndex]->sampleDescs[0];
+
+ if (entry->codecTag == MKID_BE('twos') || entry->codecTag == MKID_BE('raw ')) {
+ // Fortunately, most of the audio used in Myst videos is raw...
+ uint16 flags = 0;
+ if (entry->codecTag == MKID_BE('raw '))
+ flags |= FLAG_UNSIGNED;
+ if (entry->channels == 2)
+ flags |= FLAG_STEREO;
+ if (entry->bitsPerSample == 16)
+ flags |= FLAG_16BITS;
+ uint32 dataSize = stream->size();
+ byte *data = (byte *)malloc(dataSize);
+ stream->read(data, dataSize);
+ delete stream;
+ return makeRawStream(data, dataSize, entry->sampleRate, flags);
+ } else if (entry->codecTag == MKID_BE('ima4')) {
+ // Riven uses this codec (as do some Myst ME videos)
+ return makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), kADPCMApple, entry->sampleRate, entry->channels, 34);
+#ifdef AUDIO_QDM2_H
+ } else if (entry->codecTag == MKID_BE('QDM2')) {
+ // Myst ME uses this codec for many videos
+ return makeQDM2Stream(stream, _streams[_audioStreamIndex]->extradata);
+#endif
+ }
+
+ error("Unsupported audio codec");
+
+ return NULL;
+}
+
+uint32 QuickTimeAudioDecoder::getAudioChunkSampleCount(uint chunk) {
+ if (_audioStreamIndex < 0)
+ return 0;
+
+ uint32 sampleCount = 0;
+
+ for (uint32 j = 0; j < _streams[_audioStreamIndex]->sample_to_chunk_sz; j++)
+ if (chunk >= _streams[_audioStreamIndex]->sample_to_chunk[j].first)
+ sampleCount = _streams[_audioStreamIndex]->sample_to_chunk[j].count;
+
+ return sampleCount;
+}
+
+void QuickTimeAudioDecoder::queueNextAudioChunk() {
+ AudioSampleDesc *entry = (AudioSampleDesc *)_streams[_audioStreamIndex]->sampleDescs[0];
+ Common::MemoryWriteStreamDynamic *wStream = new Common::MemoryWriteStreamDynamic();
+
+ _fd->seek(_streams[_audioStreamIndex]->chunk_offsets[_curAudioChunk]);
+
+ // First, we have to get the sample count
+ uint32 sampleCount = getAudioChunkSampleCount(_curAudioChunk);
+ assert(sampleCount);
+
+ // Then calculate the right sizes
+ while (sampleCount > 0) {
+ uint32 samples = 0, size = 0;
+
+ if (entry->samplesPerFrame >= 160) {
+ samples = entry->samplesPerFrame;
+ size = entry->bytesPerFrame;
+ } else if (entry->samplesPerFrame > 1) {
+ samples = MIN<uint32>((1024 / entry->samplesPerFrame) * entry->samplesPerFrame, sampleCount);
+ size = (samples / entry->samplesPerFrame) * entry->bytesPerFrame;
+ } else {
+ samples = MIN<uint32>(1024, sampleCount);
+ size = samples * _streams[_audioStreamIndex]->sample_size;
+ }
+
+ // Now, we read in the data for this data and output it
+ byte *data = (byte *)malloc(size);
+ _fd->read(data, size);
+ wStream->write(data, size);
+ free(data);
+ sampleCount -= samples;
+ }
+
+ // Now queue the buffer
+ _audStream->queueAudioStream(createAudioStream(new Common::MemoryReadStream(wStream->getData(), wStream->size(), DisposeAfterUse::YES)));
+ delete wStream;
+
+ _curAudioChunk++;
+}
+
+QuickTimeAudioDecoder::AudioSampleDesc::AudioSampleDesc() : Common::QuickTimeParser::SampleDesc() {
+ channels = 0;
+ sampleRate = 0;
+ samplesPerFrame = 0;
+ bytesPerFrame = 0;
+}
+
+/**
+ * A wrapper around QuickTimeAudioDecoder that implements the RewindableAudioStream API
+ */
+class QuickTimeAudioStream : public RewindableAudioStream, public QuickTimeAudioDecoder {
+public:
+ QuickTimeAudioStream() {}
+
+ ~QuickTimeAudioStream() {
+ delete _audStream;
+ }
+
+ bool loadFile(const Common::String &filename) {
+ return QuickTimeAudioDecoder::loadFile(filename) && _audioStreamIndex >= 0 && _audStream;
+ }
+
+ // AudioStream API
+ int readBuffer(int16 *buffer, const int numSamples) {
+ int samples = 0;
+
+ while (samples < numSamples && !endOfData()) {
+ if (_audStream->numQueuedStreams() == 0)
+ queueNextAudioChunk();
+
+ samples += _audStream->readBuffer(buffer + samples, numSamples - samples);
+ }
+
+ return samples;
+ }
+
+ bool isStereo() const { return _audStream->isStereo(); }
+ int getRate() const { return _audStream->getRate(); }
+ bool endOfData() const { return _curAudioChunk >= _streams[_audioStreamIndex]->chunk_count && _audStream->endOfData(); }
+
+ // RewindableAudioStream API
+ bool rewind() {
+ // Reset our parent stream
+ _curAudioChunk = 0;
+ delete _audStream;
+
+ AudioSampleDesc *entry = (AudioSampleDesc *)_streams[_audioStreamIndex]->sampleDescs[0];
+ _audStream = makeQueuingAudioStream(entry->sampleRate, entry->channels == 2);
+ return true;
+ }
+};
+
+RewindableAudioStream *makeQuickTimeStream(const Common::String &filename) {
+ QuickTimeAudioStream *audioStream = new QuickTimeAudioStream();
+
+ if (!audioStream->loadFile(filename)) {
+ delete audioStream;
+ return 0;
+ }
+
+ return audioStream;
+}
+
+} // End of namespace Audio
diff --git a/audio/decoders/quicktime.h b/audio/decoders/quicktime.h
new file mode 100644
index 0000000000..eb0f791748
--- /dev/null
+++ b/audio/decoders/quicktime.h
@@ -0,0 +1,96 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef AUDIO_QUICKTIME_H
+#define AUDIO_QUICKTIME_H
+
+#include "common/quicktime.h"
+#include "common/scummsys.h"
+#include "common/types.h"
+
+namespace Common {
+ class SeekableReadStream;
+ class String;
+}
+
+namespace Audio {
+
+class AudioStream;
+class RewindableAudioStream;
+class QueuingAudioStream;
+
+class QuickTimeAudioDecoder : public Common::QuickTimeParser {
+public:
+ QuickTimeAudioDecoder();
+ virtual ~QuickTimeAudioDecoder();
+
+ /**
+ * Load a QuickTime audio file
+ * @param filename the filename to load
+ */
+ bool loadFile(const Common::String &filename);
+
+ /**
+ * Load a QuickTime audio file from a SeekableReadStream
+ * @param stream the stream to load
+ */
+ bool loadStream(Common::SeekableReadStream *stream);
+
+protected:
+ struct AudioSampleDesc : public Common::QuickTimeParser::SampleDesc {
+ AudioSampleDesc();
+
+ uint16 channels;
+ uint32 sampleRate;
+ uint32 samplesPerFrame;
+ uint32 bytesPerFrame;
+ };
+
+ // Common::QuickTimeParser API
+ virtual Common::QuickTimeParser::SampleDesc *readSampleDesc(MOVStreamContext *st, uint32 format);
+
+ AudioStream *createAudioStream(Common::SeekableReadStream *stream);
+ bool checkAudioCodecSupport(uint32 tag);
+ void init();
+
+ void queueNextAudioChunk();
+ uint32 getAudioChunkSampleCount(uint chunk);
+ int8 _audioStreamIndex;
+ uint _curAudioChunk;
+ QueuingAudioStream *_audStream;
+};
+
+/**
+ * Try to load a QuickTime sound file from the given file name and create a RewindableAudioStream
+ * from that data.
+ *
+ * @param filename the filename of the file from which to read the data
+ * @return a new RewindableAudioStream, or NULL, if an error occurred
+ */
+RewindableAudioStream *makeQuickTimeStream(const Common::String &filename);
+
+} // End of namespace Audio
+
+#endif
diff --git a/audio/module.mk b/audio/module.mk
index a9d9bfc869..a13eb49bb1 100644
--- a/audio/module.mk
+++ b/audio/module.mk
@@ -19,6 +19,8 @@ MODULE_OBJS := \
decoders/iff_sound.o \
decoders/mac_snd.o \
decoders/mp3.o \
+ decoders/qdm2.o \
+ decoders/quicktime.o \
decoders/raw.o \
decoders/vag.o \
decoders/voc.o \
diff --git a/video/module.mk b/video/module.mk
index 0172482dfa..308b344a75 100644
--- a/video/module.mk
+++ b/video/module.mk
@@ -15,7 +15,6 @@ MODULE_OBJS := \
codecs/mjpeg.o \
codecs/msrle.o \
codecs/msvideo1.o \
- codecs/qdm2.o \
codecs/qtrle.o \
codecs/rpza.o \
codecs/smc.o \
diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index c25b76a5f2..71f31d6415 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -38,11 +38,6 @@
#include "common/memstream.h"
#include "common/util.h"
-// Audio codecs
-#include "audio/decoders/adpcm.h"
-#include "audio/decoders/raw.h"
-#include "video/codecs/qdm2.h"
-
// Video codecs
#include "video/codecs/cinepak.h"
#include "video/codecs/mjpeg.h"
@@ -58,7 +53,6 @@ namespace Video {
////////////////////////////////////////////
QuickTimeDecoder::QuickTimeDecoder() {
- _audStream = NULL;
_curFrame = -1;
_startTime = _nextFrameStartTime = 0;
_audHandle = Audio::SoundHandle();
@@ -175,7 +169,7 @@ void QuickTimeDecoder::seekToFrame(uint32 frame) {
_audioStartOffset = curVideoTime;
// Re-create the audio stream
- AudioSampleDesc *entry = (AudioSampleDesc *)_streams[_audioStreamIndex]->sampleDescs[0];
+ Audio::QuickTimeAudioDecoder::AudioSampleDesc *entry = (Audio::QuickTimeAudioDecoder::AudioSampleDesc *)_streams[_audioStreamIndex]->sampleDescs[0];
_audStream = Audio::makeQueuingAudioStream(entry->sampleRate, entry->channels == 2);
// First, we need to track down what audio sample we need
@@ -216,7 +210,7 @@ void QuickTimeDecoder::seekToFrame(uint32 frame) {
}
// Reposition the audio stream
- readNextAudioChunk();
+ queueNextAudioChunk();
if (sample != totalSamples) {
// HACK: Skip a certain amount of samples from the stream
// (There's got to be a better way to do this!)
@@ -232,7 +226,7 @@ void QuickTimeDecoder::seekToFrame(uint32 frame) {
}
void QuickTimeDecoder::seekToTime(Audio::Timestamp time) {
- // TODO: Audio-only seeking (or really, have QuickTime sounds)
+ // Use makeQuickTimeStream() instead
if (_videoStreamIndex < 0)
error("Audio-only seeking not supported");
@@ -404,10 +398,7 @@ bool QuickTimeDecoder::loadFile(const Common::String &filename) {
if (!Common::QuickTimeParser::loadFile(filename))
return false;
- _videoStreamIndex = _audioStreamIndex = -1;
- _startTime = 0;
init();
-
return true;
}
@@ -415,39 +406,24 @@ bool QuickTimeDecoder::loadStream(Common::SeekableReadStream *stream) {
if (!Common::QuickTimeParser::loadStream(stream))
return false;
- _videoStreamIndex = _audioStreamIndex = -1;
- _startTime = 0;
init();
-
return true;
}
void QuickTimeDecoder::init() {
- Common::QuickTimeParser::init();
+ Audio::QuickTimeAudioDecoder::init();
+
+ _videoStreamIndex = -1;
+ _startTime = 0;
- // Find audio/video streams
- for (uint32 i = 0; i < _numStreams; i++) {
+ // Find video streams
+ for (uint32 i = 0; i < _numStreams; i++)
if (_streams[i]->codec_type == CODEC_TYPE_VIDEO && _videoStreamIndex < 0)
_videoStreamIndex = i;
- else if (_streams[i]->codec_type == CODEC_TYPE_AUDIO && _audioStreamIndex < 0)
- _audioStreamIndex = i;
- }
-
- // Initialize audio, if present
- if (_audioStreamIndex >= 0) {
- AudioSampleDesc *entry = (AudioSampleDesc *)_streams[_audioStreamIndex]->sampleDescs[0];
-
- if (checkAudioCodecSupport(entry->codecTag)) {
- _audStream = Audio::makeQueuingAudioStream(entry->sampleRate, entry->channels == 2);
- _curAudioChunk = 0;
-
- // Make sure the bits per sample transfers to the sample size
- if (entry->codecTag == MKID_BE('raw ') || entry->codecTag == MKID_BE('twos'))
- _streams[_audioStreamIndex]->sample_size = (entry->bitsPerSample / 8) * entry->channels;
-
- startAudio();
- }
+ // Start the audio codec if we've got one that we can handle
+ if (_audStream) {
+ startAudio();
_audioStartOffset = Audio::Timestamp(0);
}
@@ -559,56 +535,10 @@ Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(MOVStreamC
}
return entry;
- } else if (st->codec_type == CODEC_TYPE_AUDIO) {
- debug(0, "Audio Codec FourCC: \'%s\'", tag2str(format));
-
- AudioSampleDesc *entry = new AudioSampleDesc();
- entry->codecTag = format;
-
- uint16 stsdVersion = _fd->readUint16BE();
- _fd->readUint16BE(); // revision level
- _fd->readUint32BE(); // vendor
-
- entry->channels = _fd->readUint16BE(); // channel count
- entry->bitsPerSample = _fd->readUint16BE(); // sample size
-
- _fd->readUint16BE(); // compression id = 0
- _fd->readUint16BE(); // packet size = 0
-
- entry->sampleRate = (_fd->readUint32BE() >> 16);
-
- debug(0, "stsd version =%d", stsdVersion);
- if (stsdVersion == 0) {
- // Not used, except in special cases. See below.
- entry->samplesPerFrame = entry->bytesPerFrame = 0;
- } else if (stsdVersion == 1) {
- // Read QT version 1 fields. In version 0 these dont exist.
- entry->samplesPerFrame = _fd->readUint32BE();
- debug(0, "stsd samples_per_frame =%d",entry->samplesPerFrame);
- _fd->readUint32BE(); // bytes per packet
- entry->bytesPerFrame = _fd->readUint32BE();
- debug(0, "stsd bytes_per_frame =%d", entry->bytesPerFrame);
- _fd->readUint32BE(); // bytes per sample
- } else {
- warning("Unsupported QuickTime STSD audio version %d", stsdVersion);
- delete entry;
- return 0;
- }
-
- // Version 0 videos (such as the Riven ones) don't have this set,
- // but we need it later on. Add it in here.
- if (format == MKID_BE('ima4')) {
- entry->samplesPerFrame = 64;
- entry->bytesPerFrame = 34 * entry->channels;
- }
-
- if (entry->sampleRate == 0 && st->time_scale > 1)
- entry->sampleRate = st->time_scale;
-
- return entry;
}
- return 0;
+ // Pass it on up
+ return Audio::QuickTimeAudioDecoder::readSampleDesc(st, format);
}
void QuickTimeDecoder::close() {
@@ -681,112 +611,6 @@ Common::SeekableReadStream *QuickTimeDecoder::getNextFramePacket(uint32 &descId)
return _fd->readStream(_streams[_videoStreamIndex]->sample_sizes[getCurFrame()]);
}
-bool QuickTimeDecoder::checkAudioCodecSupport(uint32 tag) {
- // Check if the codec is a supported codec
- if (tag == MKID_BE('twos') || tag == MKID_BE('raw ') || tag == MKID_BE('ima4'))
- return true;
-
-#ifdef VIDEO_CODECS_QDM2_H
- if (tag == MKID_BE('QDM2'))
- return true;
-#endif
-
- if (tag == MKID_BE('mp4a'))
- warning("No MPEG-4 audio (AAC) support");
- else
- warning("Audio Codec Not Supported: \'%s\'", tag2str(tag));
-
- return false;
-}
-
-Audio::AudioStream *QuickTimeDecoder::createAudioStream(Common::SeekableReadStream *stream) {
- if (!stream || _audioStreamIndex < 0)
- return NULL;
-
- AudioSampleDesc *entry = (AudioSampleDesc *)_streams[_audioStreamIndex]->sampleDescs[0];
-
- if (entry->codecTag == MKID_BE('twos') || entry->codecTag == MKID_BE('raw ')) {
- // Fortunately, most of the audio used in Myst videos is raw...
- uint16 flags = 0;
- if (entry->codecTag == MKID_BE('raw '))
- flags |= Audio::FLAG_UNSIGNED;
- if (entry->channels == 2)
- flags |= Audio::FLAG_STEREO;
- if (entry->bitsPerSample == 16)
- flags |= Audio::FLAG_16BITS;
- uint32 dataSize = stream->size();
- byte *data = (byte *)malloc(dataSize);
- stream->read(data, dataSize);
- delete stream;
- return Audio::makeRawStream(data, dataSize, entry->sampleRate, flags);
- } else if (entry->codecTag == MKID_BE('ima4')) {
- // Riven uses this codec (as do some Myst ME videos)
- return Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMApple, entry->sampleRate, entry->channels, 34);
-#ifdef VIDEO_CODECS_QDM2_H
- } else if (entry->codecTag == MKID_BE('QDM2')) {
- // Several Myst ME videos use this codec
- return makeQDM2Stream(stream, _streams[_audioStreamIndex]->extradata);
-#endif
- }
-
- error("Unsupported audio codec");
-
- return NULL;
-}
-
-uint32 QuickTimeDecoder::getAudioChunkSampleCount(uint chunk) {
- if (_audioStreamIndex < 0)
- return 0;
-
- uint32 sampleCount = 0;
-
- for (uint32 j = 0; j < _streams[_audioStreamIndex]->sample_to_chunk_sz; j++)
- if (chunk >= _streams[_audioStreamIndex]->sample_to_chunk[j].first)
- sampleCount = _streams[_audioStreamIndex]->sample_to_chunk[j].count;
-
- return sampleCount;
-}
-
-void QuickTimeDecoder::readNextAudioChunk() {
- AudioSampleDesc *entry = (AudioSampleDesc *)_streams[_audioStreamIndex]->sampleDescs[0];
- Common::MemoryWriteStreamDynamic *wStream = new Common::MemoryWriteStreamDynamic();
-
- _fd->seek(_streams[_audioStreamIndex]->chunk_offsets[_curAudioChunk]);
-
- // First, we have to get the sample count
- uint32 sampleCount = getAudioChunkSampleCount(_curAudioChunk);
- assert(sampleCount);
-
- // Then calculate the right sizes
- while (sampleCount > 0) {
- uint32 samples = 0, size = 0;
-
- if (entry->samplesPerFrame >= 160) {
- samples = entry->samplesPerFrame;
- size = entry->bytesPerFrame;
- } else if (entry->samplesPerFrame > 1) {
- samples = MIN<uint32>((1024 / entry->samplesPerFrame) * entry->samplesPerFrame, sampleCount);
- size = (samples / entry->samplesPerFrame) * entry->bytesPerFrame;
- } else {
- samples = MIN<uint32>(1024, sampleCount);
- size = samples * _streams[_audioStreamIndex]->sample_size;
- }
-
- // Now, we read in the data for this data and output it
- byte *data = (byte *)malloc(size);
- _fd->read(data, size);
- wStream->write(data, size);
- free(data);
- sampleCount -= samples;
- }
-
- // Now queue the buffer
- _audStream->queueAudioStream(createAudioStream(new Common::MemoryReadStream(wStream->getData(), wStream->size(), DisposeAfterUse::YES)));
- delete wStream;
-
- _curAudioChunk++;
-}
-
void QuickTimeDecoder::updateAudioBuffer() {
if (!_audStream)
return;
@@ -797,7 +621,7 @@ void QuickTimeDecoder::updateAudioBuffer() {
// If we're on the last frame, make sure all audio remaining is buffered
numberOfChunksNeeded = _streams[_audioStreamIndex]->chunk_count;
} else {
- AudioSampleDesc *entry = (AudioSampleDesc *)_streams[_audioStreamIndex]->sampleDescs[0];
+ Audio::QuickTimeAudioDecoder::AudioSampleDesc *entry = (Audio::QuickTimeAudioDecoder::AudioSampleDesc *)_streams[_audioStreamIndex]->sampleDescs[0];
// Calculate the amount of chunks we need in memory until the next frame
uint32 timeToNextFrame = getTimeToNextFrame();
@@ -817,7 +641,7 @@ void QuickTimeDecoder::updateAudioBuffer() {
// Keep three streams in buffer so that if/when the first two end, it goes right into the next
while (_audStream->numQueuedStreams() < numberOfChunksNeeded && _curAudioChunk < _streams[_audioStreamIndex]->chunk_count)
- readNextAudioChunk();
+ queueNextAudioChunk();
}
QuickTimeDecoder::VideoSampleDesc::VideoSampleDesc() : Common::QuickTimeParser::SampleDesc() {
@@ -832,11 +656,4 @@ QuickTimeDecoder::VideoSampleDesc::~VideoSampleDesc() {
delete videoCodec;
}
-QuickTimeDecoder::AudioSampleDesc::AudioSampleDesc() : Common::QuickTimeParser::SampleDesc() {
- channels = 0;
- sampleRate = 0;
- samplesPerFrame = 0;
- bytesPerFrame = 0;
-}
-
} // End of namespace Video
diff --git a/video/qt_decoder.h b/video/qt_decoder.h
index 65ade40c93..b9c4b9b41d 100644
--- a/video/qt_decoder.h
+++ b/video/qt_decoder.h
@@ -34,7 +34,6 @@
#ifndef VIDEO_QT_DECODER_H
#define VIDEO_QT_DECODER_H
-#include "common/quicktime.h"
#include "common/scummsys.h"
#include "video/video_decoder.h"
@@ -42,6 +41,7 @@
#include "audio/audiostream.h"
#include "audio/mixer.h"
+#include "audio/decoders/quicktime.h"
namespace Common {
class MacResManager;
@@ -56,7 +56,7 @@ namespace Video {
* - mohawk
* - sci
*/
-class QuickTimeDecoder : public SeekableVideoDecoder, public Common::QuickTimeParser {
+class QuickTimeDecoder : public SeekableVideoDecoder, public Audio::QuickTimeAudioDecoder {
public:
QuickTimeDecoder();
virtual ~QuickTimeDecoder();
@@ -126,32 +126,17 @@ protected:
Codec *videoCodec;
};
- struct AudioSampleDesc : public Common::QuickTimeParser::SampleDesc {
- AudioSampleDesc();
-
- uint16 channels;
- uint32 sampleRate;
- uint32 samplesPerFrame;
- uint32 bytesPerFrame;
- };
-
Common::QuickTimeParser::SampleDesc *readSampleDesc(MOVStreamContext *st, uint32 format);
private:
- Audio::AudioStream *createAudioStream(Common::SeekableReadStream *stream);
- bool checkAudioCodecSupport(uint32 tag);
Common::SeekableReadStream *getNextFramePacket(uint32 &descId);
uint32 getFrameDuration();
void init();
- Audio::QueuingAudioStream *_audStream;
void startAudio();
void stopAudio();
void updateAudioBuffer();
void readNextAudioChunk();
- uint32 getAudioChunkSampleCount(uint chunk);
- int8 _audioStreamIndex;
- uint _curAudioChunk;
Audio::SoundHandle _audHandle;
Audio::Timestamp _audioStartOffset;