[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