aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Hoops2011-04-08 10:50:16 -0400
committerMatthew Hoops2011-04-08 10:54:13 -0400
commit88ebf13077a072ac0b3100e54f2949db46960e5e (patch)
tree14f3acc5e71404beebbb7f6ded56cc532a203814
parent5c4d7baa06530cb17d7fdf91eb1c93d62274827a (diff)
downloadscummvm-rg350-88ebf13077a072ac0b3100e54f2949db46960e5e.tar.gz
scummvm-rg350-88ebf13077a072ac0b3100e54f2949db46960e5e.tar.bz2
scummvm-rg350-88ebf13077a072ac0b3100e54f2949db46960e5e.zip
AUDIO: Allow for seeking in a QuickTimeAudioStream
-rw-r--r--audio/decoders/quicktime.cpp84
-rw-r--r--audio/decoders/quicktime.h8
-rw-r--r--video/qt_decoder.cpp66
3 files changed, 82 insertions, 76 deletions
diff --git a/audio/decoders/quicktime.cpp b/audio/decoders/quicktime.cpp
index af59d8803f..53cce30125 100644
--- a/audio/decoders/quicktime.cpp
+++ b/audio/decoders/quicktime.cpp
@@ -43,6 +43,7 @@ QuickTimeAudioDecoder::QuickTimeAudioDecoder() : Common::QuickTimeParser() {
}
QuickTimeAudioDecoder::~QuickTimeAudioDecoder() {
+ delete _audStream;
}
bool QuickTimeAudioDecoder::loadFile(const Common::String &filename) {
@@ -245,6 +246,64 @@ void QuickTimeAudioDecoder::queueNextAudioChunk() {
_curAudioChunk++;
}
+void QuickTimeAudioDecoder::setAudioStreamPos(const Timestamp &where) {
+ if (!_audStream)
+ return;
+
+ // Re-create the audio stream
+ delete _audStream;
+ 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
+ Audio::Timestamp curAudioTime(0, _streams[_audioStreamIndex]->time_scale);
+ uint sample = 0;
+ bool done = false;
+ for (int32 i = 0; i < _streams[_audioStreamIndex]->stts_count && !done; i++) {
+ for (int32 j = 0; j < _streams[_audioStreamIndex]->stts_data[i].count; j++) {
+ curAudioTime = curAudioTime.addFrames(_streams[_audioStreamIndex]->stts_data[i].duration);
+
+ if (curAudioTime > where) {
+ done = true;
+ break;
+ }
+
+ sample++;
+ }
+ }
+
+ // Now to track down what chunk it's in
+ _curAudioChunk = 0;
+ uint32 totalSamples = 0;
+ for (uint32 i = 0; i < _streams[_audioStreamIndex]->chunk_count; i++, _curAudioChunk++) {
+ int sampleToChunkIndex = -1;
+
+ for (uint32 j = 0; j < _streams[_audioStreamIndex]->sample_to_chunk_sz; j++)
+ if (i >= _streams[_audioStreamIndex]->sample_to_chunk[j].first)
+ sampleToChunkIndex = j;
+
+ assert(sampleToChunkIndex >= 0);
+
+ totalSamples += _streams[_audioStreamIndex]->sample_to_chunk[sampleToChunkIndex].count;
+
+ if (sample < totalSamples) {
+ totalSamples -= _streams[_audioStreamIndex]->sample_to_chunk[sampleToChunkIndex].count;
+ break;
+ }
+ }
+
+ // Reposition the audio stream
+ 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!)
+ int16 *tempBuffer = new int16[sample - totalSamples];
+ _audStream->readBuffer(tempBuffer, sample - totalSamples);
+ delete[] tempBuffer;
+ debug(3, "Skipping %d audio samples", sample - totalSamples);
+ }
+}
+
QuickTimeAudioDecoder::AudioSampleDesc::AudioSampleDesc() : Common::QuickTimeParser::SampleDesc() {
channels = 0;
sampleRate = 0;
@@ -255,13 +314,10 @@ QuickTimeAudioDecoder::AudioSampleDesc::AudioSampleDesc() : Common::QuickTimePar
/**
* A wrapper around QuickTimeAudioDecoder that implements the RewindableAudioStream API
*/
-class QuickTimeAudioStream : public RewindableAudioStream, public QuickTimeAudioDecoder {
+class QuickTimeAudioStream : public SeekableAudioStream, public QuickTimeAudioDecoder {
public:
QuickTimeAudioStream() {}
-
- ~QuickTimeAudioStream() {
- delete _audStream;
- }
+ ~QuickTimeAudioStream() {}
bool loadFile(const Common::String &filename) {
return QuickTimeAudioDecoder::loadFile(filename) && _audioStreamIndex >= 0 && _audStream;
@@ -285,19 +341,21 @@ public:
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;
+ // SeekableAudioStream API
+ bool seek(const Timestamp &where) {
+ if (where > getLength())
+ return false;
- AudioSampleDesc *entry = (AudioSampleDesc *)_streams[_audioStreamIndex]->sampleDescs[0];
- _audStream = makeQueuingAudioStream(entry->sampleRate, entry->channels == 2);
+ setAudioStreamPos(where);
return true;
}
+
+ Timestamp getLength() const {
+ return Timestamp(0, _streams[_audioStreamIndex]->duration, _streams[_audioStreamIndex]->time_scale);
+ }
};
-RewindableAudioStream *makeQuickTimeStream(const Common::String &filename) {
+SeekableAudioStream *makeQuickTimeStream(const Common::String &filename) {
QuickTimeAudioStream *audioStream = new QuickTimeAudioStream();
if (!audioStream->loadFile(filename)) {
diff --git a/audio/decoders/quicktime.h b/audio/decoders/quicktime.h
index eb0f791748..9e2e95b705 100644
--- a/audio/decoders/quicktime.h
+++ b/audio/decoders/quicktime.h
@@ -80,16 +80,18 @@ protected:
int8 _audioStreamIndex;
uint _curAudioChunk;
QueuingAudioStream *_audStream;
+
+ void setAudioStreamPos(const Timestamp &where);
};
/**
- * Try to load a QuickTime sound file from the given file name and create a RewindableAudioStream
+ * Try to load a QuickTime sound file from the given file name and create a SeekableAudioStream
* 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
+ * @return a new SeekableAudioStream, or NULL, if an error occurred
*/
-RewindableAudioStream *makeQuickTimeStream(const Common::String &filename);
+SeekableAudioStream *makeQuickTimeStream(const Common::String &filename);
} // End of namespace Audio
diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index 71f31d6415..de4a284ec9 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -168,58 +168,9 @@ void QuickTimeDecoder::seekToFrame(uint32 frame) {
if (_audioStreamIndex >= 0) {
_audioStartOffset = curVideoTime;
- // Re-create the audio stream
- 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
- Audio::Timestamp curAudioTime(0, _streams[_audioStreamIndex]->time_scale);
- uint sample = 0;
- bool done = false;
- for (int32 i = 0; i < _streams[_audioStreamIndex]->stts_count && !done; i++) {
- for (int32 j = 0; j < _streams[_audioStreamIndex]->stts_data[i].count; j++) {
- curAudioTime = curAudioTime.addFrames(_streams[_audioStreamIndex]->stts_data[i].duration);
-
- if (curAudioTime > curVideoTime) {
- done = true;
- break;
- }
-
- sample++;
- }
- }
+ // Seek to the new audio location
+ setAudioStreamPos(_audioStartOffset);
- // Now to track down what chunk it's in
- _curAudioChunk = 0;
- uint32 totalSamples = 0;
- for (uint32 i = 0; i < _streams[_audioStreamIndex]->chunk_count; i++, _curAudioChunk++) {
- int sampleToChunkIndex = -1;
-
- for (uint32 j = 0; j < _streams[_audioStreamIndex]->sample_to_chunk_sz; j++)
- if (i >= _streams[_audioStreamIndex]->sample_to_chunk[j].first)
- sampleToChunkIndex = j;
-
- assert(sampleToChunkIndex >= 0);
-
- totalSamples += _streams[_audioStreamIndex]->sample_to_chunk[sampleToChunkIndex].count;
-
- if (sample < totalSamples) {
- totalSamples -= _streams[_audioStreamIndex]->sample_to_chunk[sampleToChunkIndex].count;
- break;
- }
- }
-
- // Reposition the audio stream
- 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!)
- int16 *tempBuffer = new int16[sample - totalSamples];
- _audStream->readBuffer(tempBuffer, sample - totalSamples);
- delete[] tempBuffer;
- debug(3, "Skipping %d audio samples", sample - totalSamples);
- }
-
// Restart the audio
startAudio();
}
@@ -282,17 +233,15 @@ Codec *QuickTimeDecoder::createCodec(uint32 codecTag, byte bitsPerPixel) {
}
void QuickTimeDecoder::startAudio() {
- if (_audStream) { // No audio/audio not supported
+ if (_audStream) {
updateAudioBuffer();
- g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audHandle, _audStream);
- }
+ g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audHandle, _audStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
+ } // else no audio or the audio compression is not supported
}
void QuickTimeDecoder::stopAudio() {
- if (_audStream) {
+ if (_audStream)
g_system->getMixer()->stopHandle(_audHandle);
- _audStream = NULL; // the mixer automatically frees the stream
- }
}
void QuickTimeDecoder::pauseVideoIntern(bool pause) {
@@ -550,9 +499,6 @@ void QuickTimeDecoder::close() {
_scaledSurface = 0;
}
- // The audio stream is deleted automatically
- _audStream = NULL;
-
Common::QuickTimeParser::close();
SeekableVideoDecoder::reset();
}