diff options
| author | Matthew Hoops | 2011-04-08 10:50:16 -0400 | 
|---|---|---|
| committer | Matthew Hoops | 2011-04-08 10:54:13 -0400 | 
| commit | 88ebf13077a072ac0b3100e54f2949db46960e5e (patch) | |
| tree | 14f3acc5e71404beebbb7f6ded56cc532a203814 | |
| parent | 5c4d7baa06530cb17d7fdf91eb1c93d62274827a (diff) | |
| download | scummvm-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.cpp | 84 | ||||
| -rw-r--r-- | audio/decoders/quicktime.h | 8 | ||||
| -rw-r--r-- | video/qt_decoder.cpp | 66 | 
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();  }  | 
