[Scummvm-git-logs] scummvm master -> 0c178b00f43a09166eb96f02788edaf9fbb4363d
lephilousophe
noreply at scummvm.org
Wed Jan 12 08:11:03 UTC 2022
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
dec0427eda VIDEO: Fix HNM audio desynchronization
0c178b00f4 VIDEO: Make unsigned -1 looking better
Commit: dec0427eda173036278f0f1af01777bfb2496c28
https://github.com/scummvm/scummvm/commit/dec0427eda173036278f0f1af01777bfb2496c28
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2022-01-12T09:10:40+01:00
Commit Message:
VIDEO: Fix HNM audio desynchronization
Changed paths:
video/hnm_decoder.cpp
video/hnm_decoder.h
diff --git a/video/hnm_decoder.cpp b/video/hnm_decoder.cpp
index cdb5ea18bec..186b37b516d 100644
--- a/video/hnm_decoder.cpp
+++ b/video/hnm_decoder.cpp
@@ -34,7 +34,7 @@
namespace Video {
// When no sound display a frame every 80ms
-HNMDecoder::HNMDecoder(bool loop, byte *initialPalette) : _regularFrameDelay(80),
+HNMDecoder::HNMDecoder(bool loop, byte *initialPalette) : _regularFrameDelayMs(80),
_videoTrack(nullptr), _audioTrack(nullptr), _stream(nullptr),
_loop(loop), _initialPalette(initialPalette), _dataBuffer(nullptr), _dataBufferAlloc(0) {
}
@@ -82,30 +82,35 @@ bool HNMDecoder::loadStream(Common::SeekableReadStream *stream) {
frameCount = 0;
}
+ // When no audio use a factor of 1 for audio timestamp
+ uint32 audioSampleRate = 1;
+
_videoTrack = nullptr;
_audioTrack = nullptr;
if (tag == MKTAG('H', 'N', 'M', '4')) {
- _videoTrack = new HNM4VideoTrack(width, height, frameSize, frameCount, _regularFrameDelay,
- _initialPalette);
if (soundFormat == 2 && soundBits != 0) {
// HNM4 is Mono 22050Hz
_audioTrack = new DPCMAudioTrack(soundFormat, soundBits, 22050, false, getSoundType());
+ audioSampleRate = 22050;
}
- } else if (tag == MKTAG('U', 'B', 'B', '2')) {
- _videoTrack = new HNM5VideoTrack(width, height, frameSize, frameCount, _regularFrameDelay,
+ _videoTrack = new HNM4VideoTrack(width, height, frameSize, frameCount,
+ _regularFrameDelayMs, audioSampleRate,
_initialPalette);
+ } else if (tag == MKTAG('U', 'B', 'B', '2')) {
if (soundFormat == 2 && soundBits == 0) {
// UBB2 is Stereo 22050Hz
_audioTrack = new DPCMAudioTrack(soundFormat, 16, 22050, true, getSoundType());
+ audioSampleRate = 22050;
}
+ _videoTrack = new HNM5VideoTrack(width, height, frameSize, frameCount,
+ _regularFrameDelayMs, audioSampleRate,
+ _initialPalette);
} else {
// We should never be here
close();
return false;
}
- if (_videoTrack) {
- addTrack(_videoTrack);
- }
+ addTrack(_videoTrack);
if (_audioTrack) {
addTrack(_audioTrack);
}
@@ -158,6 +163,9 @@ void HNMDecoder::readNextPacket() {
error("Not enough data in file");
}
+ // We use -1 here to discrimate a possibly empty sound frame
+ uint32 audioNumSamples = -1;
+
byte *data_p = _dataBuffer;
while (superchunkRemaining > 0) {
if (superchunkRemaining < 8) {
@@ -177,8 +185,7 @@ void HNMDecoder::readNextPacket() {
if (chunkType == MKTAG16('S', 'D')) {
if (_audioTrack) {
- Audio::Timestamp duration = _audioTrack->decodeSound(data_p, chunkSize - 8);
- _videoTrack->setFrameDelay(duration.msecs());
+ audioNumSamples = _audioTrack->decodeSound(data_p, chunkSize - 8);
} else {
warning("Got audio data without an audio track");
}
@@ -189,27 +196,40 @@ void HNMDecoder::readNextPacket() {
data_p += (chunkSize - 8);
superchunkRemaining -= chunkSize;
}
+ _videoTrack->newFrame(audioNumSamples);
}
-HNMDecoder::HNMVideoTrack::HNMVideoTrack(uint32 frameCount, uint32 regularFrameDelay) :
- _frameCount(frameCount), _curFrame(-1),
- _regularFrameDelay(regularFrameDelay), _nextFrameStartTime(0) {
+HNMDecoder::HNMVideoTrack::HNMVideoTrack(uint32 frameCount,
+ uint32 regularFrameDelayMs, uint32 audioSampleRate) :
+ _frameCount(frameCount), _curFrame(-1), _regularFrameDelayMs(regularFrameDelayMs),
+ _nextFrameStartTime(0, audioSampleRate) {
restart();
}
-void HNMDecoder::HNMVideoTrack::setFrameDelay(uint32 frameDelay) {
- if (_nextFrameDelay == uint32(-1)) {
- _nextFrameDelay = frameDelay;
- } else if (_nextNextFrameDelay == uint32(-1)) {
- _nextNextFrameDelay = frameDelay;
- } else {
- _nextNextFrameDelay += frameDelay;
+void HNMDecoder::HNMVideoTrack::newFrame(uint32 frameDelay) {
+ // Frame done
+ _curFrame++;
+
+ // Add frameDelay if we had no sound
+ // We can't rely on a detection in the header as some soundless HNM indicate they have
+ if (frameDelay == uint32(-1)) {
+ _nextFrameStartTime = _nextFrameStartTime.addMsecs(_regularFrameDelayMs);
}
+
+ // HNM decoders use sound double buffering to pace the frames
+ // First frame is loaded in first buffer, second frame in second buffer
+ // It's only for third frame that we wait for the first buffer to be free
+ // It's presentation time is then delayed by the number of sound samples in the first frame
+ if (_lastFrameDelaySamps) {
+ _nextFrameStartTime = _nextFrameStartTime.addFrames(_lastFrameDelaySamps);
+ }
+ _lastFrameDelaySamps = frameDelay;
}
HNMDecoder::HNM45VideoTrack::HNM45VideoTrack(uint32 width, uint32 height, uint32 frameSize,
- uint32 frameCount, uint32 regularFrameDelay, const byte *initialPalette) :
- HNMVideoTrack(frameCount, regularFrameDelay) {
+ uint32 frameCount, uint32 regularFrameDelayMs, uint32 audioSampleRate,
+ const byte *initialPalette) :
+ HNMVideoTrack(frameCount, regularFrameDelayMs, audioSampleRate) {
// Get the currently loaded palette for undefined colors
if (initialPalette) {
@@ -281,8 +301,10 @@ void HNMDecoder::HNM45VideoTrack::decodePalette(byte *data, uint32 size) {
}
HNMDecoder::HNM4VideoTrack::HNM4VideoTrack(uint32 width, uint32 height, uint32 frameSize,
- uint32 frameCount, uint32 regularFrameDelay, const byte *initialPalette) :
- HNM45VideoTrack(width, height, frameSize, frameCount, regularFrameDelay, initialPalette) {
+ uint32 frameCount, uint32 regularFrameDelayMs, uint32 audioSampleRate,
+ const byte *initialPalette) :
+ HNM45VideoTrack(width, height, frameSize, frameCount,
+ regularFrameDelayMs, audioSampleRate, initialPalette) {
_frameBufferF = new byte[frameSize]();
}
@@ -564,12 +586,6 @@ void HNMDecoder::HNM4VideoTrack::presentFrame(uint16 flags) {
} else {
error("HNMDecoder::HNM4VideoTrack::postprocess(%x): Unexpected width: %d", flags, width);
}
-
- // Frame done
- _curFrame++;
- _nextFrameStartTime += _nextFrameDelay != uint32(-1) ? _nextFrameDelay : _regularFrameDelay;
- _nextFrameDelay = _nextNextFrameDelay;
- _nextNextFrameDelay = uint32(-1);
}
void HNMDecoder::HNM5VideoTrack::decodeChunk(byte *data, uint32 size,
@@ -953,13 +969,6 @@ void HNMDecoder::HNM5VideoTrack::decodeFrame(byte *data, uint32 size) {
}
_surface.setPixels(_frameBufferC);
-
- // Frame done
- _curFrame++;
- _nextFrameStartTime += _nextFrameDelay != uint32(-1) ? _nextFrameDelay : _regularFrameDelay;
- _nextFrameDelay = _nextNextFrameDelay;
- _nextNextFrameDelay = uint32(-1);
-
}
HNMDecoder::DPCMAudioTrack::DPCMAudioTrack(uint16 format, uint16 bits, uint sampleRate, bool stereo,
@@ -979,8 +988,7 @@ HNMDecoder::DPCMAudioTrack::~DPCMAudioTrack() {
delete _audioStream;
}
-Audio::Timestamp HNMDecoder::DPCMAudioTrack::decodeSound(
- byte *data, uint32 size) {
+uint32 HNMDecoder::DPCMAudioTrack::decodeSound(byte *data, uint32 size) {
if (!_gotLUT) {
if (size < 256 * sizeof(*_lut)) {
error("Invalid first sound chunk");
@@ -997,21 +1005,25 @@ Audio::Timestamp HNMDecoder::DPCMAudioTrack::decodeSound(
}
if (size == 0) {
- return Audio::Timestamp(0, 0, _sampleRate);
+ return 0;
}
uint16 *out = (uint16 *)malloc(size * sizeof(*out));
uint16 *p = out;
+ uint32 numSamples = size;
+
byte flags = Audio::FLAG_16BITS;
#ifdef SCUMM_LITTLE_ENDIAN
flags |= Audio::FLAG_LITTLE_ENDIAN;
#endif
if (_audioStream->isStereo()) {
+ numSamples /= 2;
+
uint16 sampleL = _lastSampleL;
uint16 sampleR = _lastSampleR;
byte deltaId;
- for (uint32 i = 0; i < size / 2; i++, p += 2) {
+ for (uint32 i = 0; i < numSamples; i++, p += 2) {
deltaId = *(data++);
sampleL += _lut[deltaId];
deltaId = *(data++);
@@ -1026,7 +1038,7 @@ Audio::Timestamp HNMDecoder::DPCMAudioTrack::decodeSound(
} else {
uint16 sample = _lastSampleL;
byte deltaId;
- for (uint32 i = 0; i < size; i++, p++) {
+ for (uint32 i = 0; i < numSamples; i++, p++) {
deltaId = *(data++);
sample += _lut[deltaId];
*p = sample;
@@ -1035,7 +1047,7 @@ Audio::Timestamp HNMDecoder::DPCMAudioTrack::decodeSound(
}
_audioStream->queueBuffer((byte *)out, size * sizeof(*out), DisposeAfterUse::YES, flags);
- return Audio::Timestamp(0, _audioStream->isStereo() ? size / 2 : size, _sampleRate);
+ return numSamples;
}
} // End of namespace Video
diff --git a/video/hnm_decoder.h b/video/hnm_decoder.h
index 80218e4ed80..b69f83f28a0 100644
--- a/video/hnm_decoder.h
+++ b/video/hnm_decoder.h
@@ -49,30 +49,29 @@ public:
void readNextPacket() override;
void close() override;
- void setRegularFrameDelay(uint32 regularFrameDelay) { _regularFrameDelay = regularFrameDelay; }
+ void setRegularFrameDelay(uint32 regularFrameDelay) { _regularFrameDelayMs = regularFrameDelay; }
private:
class HNMVideoTrack : public VideoTrack {
public:
- HNMVideoTrack(uint32 frameCount, uint32 regularFrameDelay);
+ HNMVideoTrack(uint32 frameCount, uint32 regularFrameDelayMs, uint32 audioSampleRate);
// When _frameCount is 0, it means we are looping
bool endOfTrack() const override { return (_frameCount == 0) ? false : VideoTrack::endOfTrack(); }
int getCurFrame() const override { return _curFrame; }
int getFrameCount() const override { return _frameCount; }
- uint32 getNextFrameStartTime() const override { return _nextFrameStartTime; }
+ uint32 getNextFrameStartTime() const override { return _nextFrameStartTime.msecs(); }
- void restart() { _nextFrameDelay = uint32(-1); _nextNextFrameDelay = uint32(-1); }
- void setFrameDelay(uint32 frameDelay);
+ void restart() { _lastFrameDelaySamps = 0; }
+ void newFrame(uint32 frameDelay);
virtual void decodeChunk(byte *data, uint32 size,
uint16 chunkType, uint16 flags) = 0;
protected:
- uint32 _regularFrameDelay;
- uint32 _nextFrameDelay;
- uint32 _nextNextFrameDelay;
- uint32 _nextFrameStartTime;
+ uint32 _regularFrameDelayMs;
+ uint32 _lastFrameDelaySamps;
+ Audio::Timestamp _nextFrameStartTime;
uint32 _frameCount;
int _curFrame;
@@ -90,7 +89,8 @@ private:
protected:
HNM45VideoTrack(uint32 width, uint32 height, uint32 frameSize, uint32 frameCount,
- uint32 regularFrameDelay, const byte *initialPalette = nullptr);
+ uint32 regularFrameDelayMs, uint32 audioSampleRate,
+ const byte *initialPalette = nullptr);
~HNM45VideoTrack() override;
/** Decode a video chunk. */
@@ -108,7 +108,8 @@ private:
class HNM4VideoTrack : public HNM45VideoTrack {
public:
HNM4VideoTrack(uint32 width, uint32 height, uint32 frameSize, uint32 frameCount,
- uint32 regularFrameDelay, const byte *initialPalette = nullptr);
+ uint32 regularFrameDelayMs, uint32 audioSampleRate,
+ const byte *initialPalette = nullptr);
~HNM4VideoTrack() override;
/** Decode a video chunk. */
@@ -128,8 +129,10 @@ private:
class HNM5VideoTrack : public HNM45VideoTrack {
public:
HNM5VideoTrack(uint32 width, uint32 height, uint32 frameSize, uint32 frameCount,
- uint32 regularFrameDelay, const byte *initialPalette = nullptr) :
- HNM45VideoTrack(width, height, frameSize, frameCount, regularFrameDelay, initialPalette) {}
+ uint32 regularFrameDelayMs, uint32 audioSampleRate,
+ const byte *initialPalette = nullptr) :
+ HNM45VideoTrack(width, height, frameSize, frameCount, regularFrameDelayMs, audioSampleRate,
+ initialPalette) {}
/** Decode a video chunk. */
void decodeChunk(byte *data, uint32 size,
uint16 chunkType, uint16 flags) override;
@@ -145,7 +148,7 @@ private:
Audio::Mixer::SoundType soundType);
~DPCMAudioTrack() override;
- Audio::Timestamp decodeSound(byte *data, uint32 size);
+ uint32 decodeSound(byte *data, uint32 size);
protected:
Audio::AudioStream *getAudioStream() const override { return _audioStream; }
private:
@@ -161,7 +164,7 @@ private:
bool _loop;
byte *_initialPalette;
- uint32 _regularFrameDelay;
+ uint32 _regularFrameDelayMs;
// These two pointer are owned by VideoDecoder
HNMVideoTrack *_videoTrack;
DPCMAudioTrack *_audioTrack;
Commit: 0c178b00f43a09166eb96f02788edaf9fbb4363d
https://github.com/scummvm/scummvm/commit/0c178b00f43a09166eb96f02788edaf9fbb4363d
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2022-01-12T09:10:40+01:00
Commit Message:
VIDEO: Make unsigned -1 looking better
Changed paths:
video/hnm_decoder.cpp
diff --git a/video/hnm_decoder.cpp b/video/hnm_decoder.cpp
index 186b37b516d..20620cba390 100644
--- a/video/hnm_decoder.cpp
+++ b/video/hnm_decoder.cpp
@@ -843,8 +843,8 @@ void HNMDecoder::HNM5VideoTrack::decodeFrame(byte *data, uint32 size) {
uint16 pitch = _surface.pitch;
bool eop = false;
- byte height = (byte)-1;
- byte currentMode = (byte)-1;
+ byte height = -1;
+ byte currentMode = -1;
uint32 currentPos = 0;
while (!eop) {
@@ -856,7 +856,7 @@ void HNMDecoder::HNM5VideoTrack::decodeFrame(byte *data, uint32 size) {
size -= 1;
if (opcode == 0x20) {
- assert(height != (byte)-1);
+ assert(height != byte(-1));
if (size < 1) {
error("Not enough data for opcode 0x20");
}
@@ -869,7 +869,7 @@ void HNMDecoder::HNM5VideoTrack::decodeFrame(byte *data, uint32 size) {
currentPos += width;
} else if (opcode == 0x60) {
// Maximal pixels height is 4
- assert(height != (byte)-1 && height <= 4);
+ assert(height != byte(-1) && height <= 4);
if (size < height) {
error("Not enough data for opcode 0x60");
}
@@ -879,7 +879,7 @@ void HNMDecoder::HNM5VideoTrack::decodeFrame(byte *data, uint32 size) {
size -= height;
currentPos += 1;
} else if (opcode == 0xA0) {
- assert(height != (byte)-1);
+ assert(height != byte(-1));
if (size < 1) {
error("Not enough data for opcode 0x20");
}
@@ -905,7 +905,7 @@ void HNMDecoder::HNM5VideoTrack::decodeFrame(byte *data, uint32 size) {
size -= 1;
if (subop == 0x00) {
- assert(height != (byte)-1);
+ assert(height != byte(-1));
if (size < 2) {
error("Not enough data for opcode 0xE0 0x00");
}
@@ -920,7 +920,7 @@ void HNMDecoder::HNM5VideoTrack::decodeFrame(byte *data, uint32 size) {
}
currentPos += width;
} else if (subop == 0x01) {
- if (height != (byte)-1) {
+ if (height != byte(-1)) {
currentPos += (height - 1) * pitch;
}
@@ -930,7 +930,7 @@ void HNMDecoder::HNM5VideoTrack::decodeFrame(byte *data, uint32 size) {
assert((currentPos % pitch) == 0);
assert(subop < 48);
- if (height != (byte)-1) {
+ if (height != byte(-1)) {
currentPos += (height - 1) * pitch;
}
@@ -951,7 +951,7 @@ void HNMDecoder::HNM5VideoTrack::decodeFrame(byte *data, uint32 size) {
}
} else {
- assert(height != (byte)-1);
+ assert(height != byte(-1));
assert(2 <= height && height <= 4);
byte index = opcode & 0x1f;
byte copyMode = (opcode >> 5) & 0x7;
More information about the Scummvm-git-logs
mailing list