From a2d4b152f3c831daed4ddf61640c697afec664c3 Mon Sep 17 00:00:00 2001 From: Harishankar Kumar Date: Fri, 23 Jun 2023 18:54:21 +0530 Subject: [PATCH] VIDEO: Implement non 0/1 rate with audio Uses Mixer's setRate() function implemented in pr #4965 to set video playback rates of movies that are not 0 or 1. `undome` of 'mediaband' required this feature where the video can have playback rates other than 0 or 1. --- video/video_decoder.cpp | 42 +++++++++++++++++++++++++++++++++++++---- video/video_decoder.h | 21 ++++++++++++++++++--- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index ebbc23599b5..e7d84497a7b 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -280,7 +280,7 @@ uint32 VideoDecoder::getTime() const { if (useAudioSync()) { for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) { if ((*it)->getTrackType() == Track::kTrackTypeAudio && !(*it)->endOfTrack()) { - uint32 time = ((const AudioTrack *)*it)->getRunningTime(); + uint32 time = (((const AudioTrack *)*it)->getRunningTime() * _playbackRate).toInt(); if (time != 0) return time + _lastTimeChange.msecs(); @@ -471,13 +471,14 @@ void VideoDecoder::setRate(const Common::Rational &rate) { if (rate == 0) { stop(); return; - } else if (rate != 1 && hasAudio()) { - warning("Cannot set custom rate in videos with audio"); - return; } Common::Rational targetRate = rate; + if (hasAudio()) { + setAudioRate(targetRate); + } + // Attempt to set the reverse if (!setReverse(rate < 0)) { assert(rate < 0); // We shouldn't fail for forward. @@ -633,6 +634,7 @@ Audio::Timestamp VideoDecoder::FixedRateVideoTrack::getDuration() const { VideoDecoder::AudioTrack::AudioTrack(Audio::Mixer::SoundType soundType) : _volume(Audio::Mixer::kMaxChannelVolume), _soundType(soundType), + _rate(0), _balance(0), _muted(false) { } @@ -649,6 +651,23 @@ void VideoDecoder::AudioTrack::setVolume(byte volume) { g_system->getMixer()->setChannelVolume(_handle, _muted ? 0 : _volume); } +void VideoDecoder::AudioTrack::setRate(uint32 rate) { + _rate = rate; + + if (g_system->getMixer()->isSoundHandleActive(_handle)) + g_system->getMixer()->setChannelRate(_handle, _rate); +} + +void VideoDecoder::AudioTrack::setRate(Common::Rational rate) { + Audio::AudioStream *stream = getAudioStream(); + assert(stream); + + // Convert rational rate to audio rate + uint32 convertedRate = (stream->getRate() * rate).toInt(); + + setRate(convertedRate); +} + void VideoDecoder::AudioTrack::setBalance(int8 balance) { _balance = balance; @@ -664,6 +683,10 @@ void VideoDecoder::AudioTrack::start() { g_system->getMixer()->playStream(_soundType, &_handle, stream, -1, _muted ? 0 : getVolume(), getBalance(), DisposeAfterUse::NO); + // Set rate of audio + if (_rate != 0) + g_system->getMixer()->setChannelRate(_handle, _rate); + // Pause the audio again if we're still paused if (isPaused()) g_system->getMixer()->pauseHandle(_handle, true); @@ -683,6 +706,10 @@ void VideoDecoder::AudioTrack::start(const Audio::Timestamp &limit) { g_system->getMixer()->playStream(_soundType, &_handle, stream, -1, _muted ? 0 : getVolume(), getBalance(), DisposeAfterUse::YES); + // Set rate of audio + if (_rate != 0) + g_system->getMixer()->setChannelRate(_handle, _rate); + // Pause the audio again if we're still paused if (isPaused()) g_system->getMixer()->pauseHandle(_handle, true); @@ -958,6 +985,13 @@ void VideoDecoder::stopAudio() { ((AudioTrack *)*it)->stop(); } +void VideoDecoder::setAudioRate(Common::Rational rate) { + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeAudio) { + ((AudioTrack *)*it)->setRate(rate); + } +} + void VideoDecoder::startAudioLimit(const Audio::Timestamp &limit) { for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) if ((*it)->getTrackType() == Track::kTrackTypeAudio) diff --git a/video/video_decoder.h b/video/video_decoder.h index 379e7429f4f..bd9585cce17 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -120,9 +120,6 @@ public: * would play the video normally. Passing 2 to this function would * play the video at twice the normal speed. * - * @note This function does not work for non-0/1 rates on videos that - * have audio tracks. - * * @todo This currently does not implement backwards playback, but will * be implemented soon. */ @@ -720,6 +717,22 @@ protected: */ void setVolume(byte volume); + /** + * Get audio rate for this track (in Hz) + */ + uint32 getRate() const { return _rate; } + + /** + * Set audio rate for this track + */ + void setRate(uint32 rate); + + /** + * Set audio rate using relative playback rate wrt original rate + * ie a rate of 2.0 will play the audio at twice the original rate + */ + void setRate(Common::Rational rate); + /** * Get the balance for this track */ @@ -763,6 +776,7 @@ protected: Audio::SoundHandle _handle; Audio::Mixer::SoundType _soundType; byte _volume; + uint32 _rate; int8 _balance; bool _muted; }; @@ -968,6 +982,7 @@ private: protected: // Internal helper functions void stopAudio(); + void setAudioRate(Common::Rational rate); void startAudio(); void startAudioLimit(const Audio::Timestamp &limit); bool hasFramesLeft() const;