[Scummvm-git-logs] scummvm master -> 5c441f9420409fc222f6678bd3bcf50ac2b9fb88

sev- sev at scummvm.org
Wed Sep 23 23:23:53 UTC 2020


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
5c441f9420 VIDEO: Added support for seeking BINK streams


Commit: 5c441f9420409fc222f6678bd3bcf50ac2b9fb88
    https://github.com/scummvm/scummvm/commit/5c441f9420409fc222f6678bd3bcf50ac2b9fb88
Author: Paweł Kołodziejski (aquadran at users.sourceforge.net)
Date: 2020-09-24T01:23:50+02:00

Commit Message:
VIDEO: Added support for seeking BINK streams

Changed paths:
    video/bink_decoder.cpp
    video/bink_decoder.h


diff --git a/video/bink_decoder.cpp b/video/bink_decoder.cpp
index 69cc88d750..090ecaa171 100644
--- a/video/bink_decoder.cpp
+++ b/video/bink_decoder.cpp
@@ -332,11 +332,142 @@ BinkDecoder::BinkVideoTrack::~BinkVideoTrack() {
 	_surface.free();
 }
 
+/**
+ * An AudioStream that just returns silent samples and runs infinitely.
+ */
+class SilentAudioStream : public Audio::AudioStream {
+public:
+	SilentAudioStream(int rate, bool stereo) : _rate(rate), _isStereo(stereo) {}
+
+	int readBuffer(int16 *buffer, const int numSamples) {
+		memset(buffer, 0, numSamples * 2);
+		return numSamples;
+	}
+
+	bool endOfData() const { return false; } // it never ends!
+	bool isStereo() const { return _isStereo; }
+	int getRate() const { return _rate; }
+
+private:
+	int _rate;
+	bool _isStereo;
+};
+
 Common::Rational BinkDecoder::getFrameRate() {
 	BinkVideoTrack *videoTrack = (BinkVideoTrack *)getTrack(0);
 
 	return videoTrack->getFrameRate();
 }
+
+bool BinkDecoder::seekIntern(const Audio::Timestamp &time) {
+	BinkVideoTrack *videoTrack = (BinkVideoTrack *)getTrack(0);
+
+	uint32 frame = videoTrack->getFrameAtTime(time);
+
+	// Track down the keyframe
+	uint32 keyFrame = findKeyFrame(frame);
+	videoTrack->setCurFrame(keyFrame - 1);
+
+	// Adjust the video track to use for seeking
+	findNextVideoTrack();
+
+	if (frame == keyFrame) {
+		// We're already good, no need to go further
+		return true;
+	}
+
+	// Seek the audio tracks
+	for (uint32 i = 0; i < _audioTracks.size(); i++) {
+		BinkAudioTrack *audioTrack = (BinkAudioTrack *)getTrack(i + 1);
+		audioTrack->seek(videoTrack->getFrameTime(keyFrame));
+	}
+
+	while (getCurFrame() < (int32)frame - 1)
+		decodeNextFrame();
+
+	// Skip decoded audio between the keyframe and the target frame
+	for (uint32 i = 0; i < _audioTracks.size(); i++) {
+		BinkAudioTrack *audioTrack = (BinkAudioTrack *)getTrack(i + 1);
+		int rate = audioTrack->getRate();
+
+		Audio::Timestamp delay = videoTrack->getFrameTime(frame - 1).convertToFramerate(rate)
+				- videoTrack->getFrameTime(keyFrame).convertToFramerate(rate);
+
+		audioTrack->skipSamples(delay);
+	}
+
+	return true;
+}
+
+uint32 BinkDecoder::findKeyFrame(uint32 frame) const {
+	assert(frame < _frames.size());
+
+	for (int i = frame; i >= 0; i--) {
+		if (_frames[i].keyFrame)
+			return i;
+	}
+
+	// If none found, we'll assume the requested frame is a key frame
+	return frame;
+}
+
+int BinkDecoder::BinkAudioTrack::getRate() {
+	return _audioStream->getRate();
+}
+
+void BinkDecoder::BinkAudioTrack::skipSamples(const Audio::Timestamp &length) {
+	int32 sampleCount = length.totalNumberOfFrames();
+
+	if (sampleCount <= 0)
+		return;
+
+	if (_audioStream->isStereo())
+		sampleCount *= 2;
+
+	int16 *tempBuffer = new int16[sampleCount];
+	_audioStream->readBuffer(tempBuffer, sampleCount);
+	delete[] tempBuffer;
+}
+
+bool BinkDecoder::BinkAudioTrack::seek(const Audio::Timestamp &time) {
+	// Don't window the output with the previous frame -- there is no output from the previous frame
+	_audioInfo->first = true;
+
+	if (time != Audio::Timestamp(0)) {
+		// The first frame of the file contains an audio prebuffer of about 750ms.
+		// When seeking to a later frame, the audio stream needs to be prefilled with some data
+		// amounting to 750ms, otherwise the audio stream will underrun and / or the audio and video
+		// streams will be out of sync.
+		// For now, we do as the official Bink decoder up to version 1.2j. The stream is prefilled
+		// with silence.
+		// The official bink decoder behavior is documented here:
+		// http://www.radgametools.com/bnkhist.htm#Changes from 1.2i to 1.2J (02-18-2002)
+		SilentAudioStream *silence = new SilentAudioStream(_audioInfo->outSampleRate, _audioInfo->outChannels == 2);
+		Audio::AudioStream *prebuffer = Audio::makeLimitingAudioStream(silence, Audio::Timestamp(750));
+		_audioStream->queueAudioStream(prebuffer);
+	}
+
+	return true;
+}
+
+bool BinkDecoder::BinkVideoTrack::rewind() {
+	if (!VideoTrack::rewind()) {
+		return false;
+	}
+
+	_curFrame = -1;
+
+	// Re-initialize the video with solid green
+	memset(_curPlanes[0],   0, _yBlockWidth  * 8 * _yBlockHeight  * 8);
+	memset(_curPlanes[1],   0, _uvBlockWidth * 8 * _uvBlockHeight * 8);
+	memset(_curPlanes[2],   0, _uvBlockWidth * 8 * _uvBlockHeight * 8);
+	memset(_oldPlanes[0],   0, _yBlockWidth  * 8 * _yBlockHeight  * 8);
+	memset(_oldPlanes[1],   0, _uvBlockWidth * 8 * _uvBlockHeight * 8);
+	memset(_oldPlanes[2],   0, _uvBlockWidth * 8 * _uvBlockHeight * 8);
+
+	return true;
+}
+
 void BinkDecoder::BinkVideoTrack::decodePacket(VideoFrame &frame) {
 	assert(frame.bits);
 
diff --git a/video/bink_decoder.h b/video/bink_decoder.h
index 686dca3db1..57dc4bb85d 100644
--- a/video/bink_decoder.h
+++ b/video/bink_decoder.h
@@ -79,6 +79,8 @@ protected:
 	void readNextPacket();
 	bool supportsAudioTrackSwitching() const { return true; }
 	AudioTrack *getAudioTrack(int index);
+	bool seekIntern(const Audio::Timestamp &time);
+	uint32 findKeyFrame(uint32 frame) const;
 
 private:
 	static const int kAudioChannelsMax  = 2;
@@ -153,6 +155,10 @@ private:
 		int getCurFrame() const { return _curFrame; }
 		int getFrameCount() const { return _frameCount; }
 		const Graphics::Surface *decodeNextFrame() { return &_surface; }
+		bool isSeekable() const { return true; }
+		bool seek(const Audio::Timestamp &time) { return true; }
+		bool rewind() override;
+		void setCurFrame(uint32 frame) { _curFrame = frame; }
 
 		/** Decode a video packet. */
 		void decodePacket(VideoFrame &frame);
@@ -333,6 +339,11 @@ private:
 		/** Decode an audio packet. */
 		void decodePacket();
 
+		bool seek(const Audio::Timestamp &time);
+		bool isSeekable() const { return true; }
+		void skipSamples(const Audio::Timestamp &length);
+		int getRate();
+
 	protected:
 		Audio::AudioStream *getAudioStream() const;
 




More information about the Scummvm-git-logs mailing list