From adef12d993e9b92f4dbf97b12355063619173fcb Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Wed, 1 Mar 2023 20:23:39 +0000 Subject: [PATCH] VIDEO: Implement setOutputPixelFormat() for BinkDecoder --- engines/grim/movie/bink.cpp | 6 ++-- engines/icb/movie_pc.cpp | 4 ++- engines/icb/options_manager_pc.cpp | 4 +-- engines/myst3/inventory.cpp | 2 +- engines/myst3/menu.cpp | 2 +- engines/myst3/movie.cpp | 2 +- engines/myst3/puzzles.cpp | 4 +-- engines/myst3/subtitles.cpp | 2 +- engines/scumm/he/animation_he.cpp | 6 ++-- engines/stark/ui/world/fmvscreen.cpp | 2 +- engines/stark/visual/smacker.cpp | 4 +-- video/bink_decoder.cpp | 49 ++++++++++++++++++---------- video/bink_decoder.h | 16 +++++---- 13 files changed, 62 insertions(+), 41 deletions(-) diff --git a/engines/grim/movie/bink.cpp b/engines/grim/movie/bink.cpp index 9e42b2b80e5..9279d8a1dec 100644 --- a/engines/grim/movie/bink.cpp +++ b/engines/grim/movie/bink.cpp @@ -44,7 +44,6 @@ MoviePlayer *CreateBinkPlayer(bool demo) { BinkPlayer::BinkPlayer(bool demo) : MoviePlayer(), _demo(demo) { _videoDecoder = new Video::BinkDecoder(); - _videoDecoder->setDefaultHighColorFormat(Graphics::PixelFormat(4, 8, 8, 8, 0, 8, 16, 24, 0)); _subtitleIndex = _subtitles.begin(); } @@ -205,7 +204,10 @@ bool BinkPlayer::loadFile(const Common::String &filename) { Common::SeekableReadStream *bink = nullptr; bink = new Common::SeekableSubReadStream(stream, startBinkPos, stream->size(), DisposeAfterUse::YES); - return _videoDecoder->loadStream(bink); + if (!_videoDecoder->loadStream(bink)) + return false; + _videoDecoder->setOutputPixelFormat(Graphics::PixelFormat(4, 8, 8, 8, 0, 8, 16, 24, 0)); + return true; } } // end of namespace Grim diff --git a/engines/icb/movie_pc.cpp b/engines/icb/movie_pc.cpp index 0dabe6e06d5..884de097fb0 100644 --- a/engines/icb/movie_pc.cpp +++ b/engines/icb/movie_pc.cpp @@ -65,7 +65,6 @@ bool MovieManager::registerMovie(const char *fileName, bool8 fade, bool8 loop) { g_theMusicManager->StopMusic(); _binkDecoder = new Video::BinkDecoder(); - _binkDecoder->setDefaultHighColorFormat(Graphics::PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 24)); Common::SeekableReadStream *stream = openDiskFileForBinaryStreamRead(fileName); if (!stream) { @@ -74,6 +73,9 @@ bool MovieManager::registerMovie(const char *fileName, bool8 fade, bool8 loop) { if (!_binkDecoder->loadStream(stream)) { return false; } + + _binkDecoder->setOutputPixelFormat(Graphics::PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 24)); + if (_binkDecoder->getWidth() != SCREEN_WIDTH) { _x = (SCREEN_WIDTH / 2) - (_binkDecoder->getWidth() / 2); } diff --git a/engines/icb/options_manager_pc.cpp b/engines/icb/options_manager_pc.cpp index 218f37725d7..8dd845e6c76 100644 --- a/engines/icb/options_manager_pc.cpp +++ b/engines/icb/options_manager_pc.cpp @@ -6182,8 +6182,6 @@ void OptionsManager::DrawSlideShow() { // This slide is bink compressed Video::BinkDecoder *binkDecoder = new Video::BinkDecoder(); - binkDecoder->setDefaultHighColorFormat(Graphics::PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 24)); - Common::MemoryReadStream *stream = new Common::MemoryReadStream((byte *)slideptr, slideLen); if (!stream) { Fatal_error("Failed open bink file"); @@ -6192,6 +6190,8 @@ void OptionsManager::DrawSlideShow() { Fatal_error("Failed open bink file"); } + binkDecoder->setOutputPixelFormat(Graphics::PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 24)); + // Verify image dimensions if (binkDecoder->getWidth() > SCREEN_WIDTH || binkDecoder->getHeight() > SCREEN_DEPTH) Fatal_error("Slide image is too large to fit screen!"); diff --git a/engines/myst3/inventory.cpp b/engines/myst3/inventory.cpp index 15933c6cea5..51e008bf0ef 100644 --- a/engines/myst3/inventory.cpp +++ b/engines/myst3/inventory.cpp @@ -338,8 +338,8 @@ DragItem::DragItem(Myst3Engine *vm, uint id): // Load the movie _movieStream = movieDesc.getData(); - _bink.setDefaultHighColorFormat(Texture::getRGBAPixelFormat()); _bink.loadStream(_movieStream); + _bink.setOutputPixelFormat(Texture::getRGBAPixelFormat()); _bink.start(); const Graphics::Surface *frame = _bink.decodeNextFrame(); diff --git a/engines/myst3/menu.cpp b/engines/myst3/menu.cpp index 958cc816b38..4817142ade7 100644 --- a/engines/myst3/menu.cpp +++ b/engines/myst3/menu.cpp @@ -57,8 +57,8 @@ Dialog::Dialog(Myst3Engine *vm, uint id): // Load the movie Common::SeekableReadStream *movieStream = movieDesc.getData(); - _bink.setDefaultHighColorFormat(Texture::getRGBAPixelFormat()); _bink.loadStream(movieStream); + _bink.setOutputPixelFormat(Texture::getRGBAPixelFormat()); _bink.start(); const Graphics::Surface *frame = _bink.decodeNextFrame(); diff --git a/engines/myst3/movie.cpp b/engines/myst3/movie.cpp index 78d6d8af6a3..5be07da80d8 100644 --- a/engines/myst3/movie.cpp +++ b/engines/myst3/movie.cpp @@ -73,9 +73,9 @@ Movie::Movie(Myst3Engine *vm, uint16 id) : loadPosition(binkDesc.getVideoData()); Common::SeekableReadStream *binkStream = binkDesc.getData(); - _bink.setDefaultHighColorFormat(Texture::getRGBAPixelFormat()); _bink.setSoundType(Audio::Mixer::kSFXSoundType); _bink.loadStream(binkStream); + _bink.setOutputPixelFormat(Texture::getRGBAPixelFormat()); if (binkDesc.getType() == Archive::kMultitrackMovie || binkDesc.getType() == Archive::kDialogMovie) { uint language = ConfMan.getInt("audio_language"); diff --git a/engines/myst3/puzzles.cpp b/engines/myst3/puzzles.cpp index 05485522328..29e1ed18cfb 100644 --- a/engines/myst3/puzzles.cpp +++ b/engines/myst3/puzzles.cpp @@ -1527,8 +1527,8 @@ void Puzzles::projectorLoadBitmap(uint16 bitmap) { // Rebuild the complete background image from the frames of the bink movie Common::SeekableReadStream *movieStream = movieDesc.getData(); Video::BinkDecoder bink; - bink.setDefaultHighColorFormat(Texture::getRGBAPixelFormat()); bink.loadStream(movieStream); + bink.setOutputPixelFormat(Texture::getRGBAPixelFormat()); bink.start(); for (uint i = 0; i < 1024; i += 256) { @@ -1554,8 +1554,8 @@ void Puzzles::projectorAddSpotItem(uint16 bitmap, uint16 x, uint16 y) { // Rebuild the complete background image from the frames of the bink movie Common::SeekableReadStream *movieStream = movieDesc.getData(); Video::BinkDecoder bink; - bink.setDefaultHighColorFormat(Texture::getRGBAPixelFormat()); bink.loadStream(movieStream); + bink.setOutputPixelFormat(Texture::getRGBAPixelFormat()); bink.start(); const Graphics::Surface *frame = bink.decodeNextFrame(); diff --git a/engines/myst3/subtitles.cpp b/engines/myst3/subtitles.cpp index ae41f93a109..75b210b81e8 100644 --- a/engines/myst3/subtitles.cpp +++ b/engines/myst3/subtitles.cpp @@ -360,8 +360,8 @@ bool MovieSubtitles::loadSubtitles(int32 id) { // Load the movie Common::SeekableReadStream *movieStream = movie.getData(); - _bink.setDefaultHighColorFormat(Texture::getRGBAPixelFormat()); _bink.loadStream(movieStream); + _bink.setOutputPixelFormat(Texture::getRGBAPixelFormat()); _bink.start(); return true; diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp index 59e9996fee9..a60796544cc 100644 --- a/engines/scumm/he/animation_he.cpp +++ b/engines/scumm/he/animation_he.cpp @@ -65,14 +65,14 @@ int MoviePlayer::load(const Common::String &filename, int flags, int image) { if (_video->isVideoLoaded()) _video->close(); - // Ensure that Bink will use our PixelFormat - _video->setDefaultHighColorFormat(g_system->getScreenFormat()); - if (!_video->loadFile(filename)) { warning("Failed to load video file %s", filename.c_str()); return -1; } + // Ensure that Bink will use our PixelFormat + _video->setOutputPixelFormat(g_system->getScreenFormat()); + _video->start(); debug(1, "Playing video %s", filename.c_str()); diff --git a/engines/stark/ui/world/fmvscreen.cpp b/engines/stark/ui/world/fmvscreen.cpp index fc1a97ea210..fa4bd7fbf8f 100644 --- a/engines/stark/ui/world/fmvscreen.cpp +++ b/engines/stark/ui/world/fmvscreen.cpp @@ -41,7 +41,6 @@ FMVScreen::FMVScreen(Gfx::Driver *gfx, Cursor *cursor) : _bitmap->setSamplingFilter(StarkSettings->getImageSamplingFilter()); _decoder = new Video::BinkDecoder(); - _decoder->setDefaultHighColorFormat(_bitmap->getBestPixelFormat()); _decoder->setSoundType(Audio::Mixer::kSFXSoundType); _surfaceRenderer = _gfx->createSurfaceRenderer(); @@ -82,6 +81,7 @@ void FMVScreen::play(const Common::String &name) { if (!_decoder->isVideoLoaded()) { error("Could not open %s", name.c_str()); } + _decoder->setOutputPixelFormat(_bitmap->getBestPixelFormat()); _decoder->start(); } diff --git a/engines/stark/visual/smacker.cpp b/engines/stark/visual/smacker.cpp index 72db7c8f5a5..06ca3607421 100644 --- a/engines/stark/visual/smacker.cpp +++ b/engines/stark/visual/smacker.cpp @@ -72,9 +72,9 @@ void VisualSmacker::loadBink(Common::SeekableReadStream *stream) { _decoder = new Video::BinkDecoder(); _decoder->setSoundType(Audio::Mixer::kSFXSoundType); - // We need a format with alpha transparency, so we can't use _bitmap->getBestPixelFormat() here. - _decoder->setDefaultHighColorFormat(Gfx::Driver::getRGBAPixelFormat()); _decoder->loadStream(stream); + // We need a format with alpha transparency, so we can't use _bitmap->getBestPixelFormat() here. + _decoder->setOutputPixelFormat(Gfx::Driver::getRGBAPixelFormat()); init(); } diff --git a/video/bink_decoder.cpp b/video/bink_decoder.cpp index 30de3d478dc..0c371d6447c 100644 --- a/video/bink_decoder.cpp +++ b/video/bink_decoder.cpp @@ -102,7 +102,7 @@ bool BinkDecoder::loadStream(Common::SeekableReadStream *stream) { uint32 videoFlags = _bink->readUint32LE(); // BIKh and BIKi swap the chroma planes - addTrack(new BinkVideoTrack(width, height, getDefaultHighColorFormat(), frameCount, + addTrack(new BinkVideoTrack(width, height, frameCount, Common::Rational(frameRateNum, frameRateDen), (id == kBIKhID || id == kBIKiID), videoFlags & kVideoFlagAlpha, id)); uint32 audioTrackCount = _bink->readUint32LE(); @@ -242,8 +242,8 @@ BinkDecoder::AudioInfo::~AudioInfo() { delete dct; } -BinkDecoder::BinkVideoTrack::BinkVideoTrack(uint32 width, uint32 height, const Graphics::PixelFormat &format, uint32 frameCount, const Common::Rational &frameRate, bool swapPlanes, bool hasAlpha, uint32 id) : - _frameCount(frameCount), _frameRate(frameRate), _swapPlanes(swapPlanes), _hasAlpha(hasAlpha), _id(id) { +BinkDecoder::BinkVideoTrack::BinkVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, bool swapPlanes, bool hasAlpha, uint32 id) : + _frameCount(frameCount), _frameRate(frameRate), _swapPlanes(swapPlanes), _hasAlpha(hasAlpha), _id(id), _surface(nullptr) { _curFrame = -1; for (int i = 0; i < 16; i++) @@ -269,8 +269,8 @@ BinkDecoder::BinkVideoTrack::BinkVideoTrack(uint32 width, uint32 height, const G } // Make the surface even-sized: - _surfaceHeight = height; - _surfaceWidth = width; + _surfaceHeight = _height = height; + _surfaceWidth = _width = width; if (height & 1) { _surfaceHeight++; @@ -279,12 +279,11 @@ BinkDecoder::BinkVideoTrack::BinkVideoTrack(uint32 width, uint32 height, const G _surfaceWidth++; } - _surface.create(_surfaceWidth, _surfaceHeight, format); - // Since we over-allocate to make surfaces even-sized - // we need to set the actual VIDEO size back into the - // surface. - _surface.h = height; - _surface.w = width; + _pixelFormat = g_system->getScreenFormat(); + + // Default to a 32bpp format, if in 8bpp mode + if (_pixelFormat.bytesPerPixel == 1) + _pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0); // Compute the video dimensions in blocks _yBlockWidth = (width + 7) >> 3; @@ -323,7 +322,11 @@ BinkDecoder::BinkVideoTrack::~BinkVideoTrack() { _huffman[i] = 0; } - _surface.free(); + if (_surface) { + _surface->free(); + delete _surface; + _surface = nullptr; + } } Common::Rational BinkDecoder::getFrameRate() { @@ -446,6 +449,16 @@ bool BinkDecoder::BinkVideoTrack::rewind() { void BinkDecoder::BinkVideoTrack::decodePacket(VideoFrame &frame) { assert(frame.bits); + if (!_surface) { + _surface = new Graphics::Surface(); + _surface->create(_surfaceWidth, _surfaceHeight, _pixelFormat); + // Since we over-allocate to make surfaces even-sized + // we need to set the actual VIDEO size back into the + // surface. + _surface->h = _height; + _surface->w = _width; + } + if (_hasAlpha) { if (_id == kBIKiID) frame.bits->skip(32); @@ -470,11 +483,11 @@ void BinkDecoder::BinkVideoTrack::decodePacket(VideoFrame &frame) { // to allow for odd-sized videos. if (_hasAlpha) { assert(_curPlanes[0] && _curPlanes[1] && _curPlanes[2] && _curPlanes[3]); - YUVToRGBMan.convert420Alpha(&_surface, Graphics::YUVToRGBManager::kScaleITU, _curPlanes[0], _curPlanes[1], _curPlanes[2], _curPlanes[3], + YUVToRGBMan.convert420Alpha(_surface, Graphics::YUVToRGBManager::kScaleITU, _curPlanes[0], _curPlanes[1], _curPlanes[2], _curPlanes[3], _surfaceWidth, _surfaceHeight, _yBlockWidth * 8, _uvBlockWidth * 8); } else { assert(_curPlanes[0] && _curPlanes[1] && _curPlanes[2]); - YUVToRGBMan.convert420(&_surface, Graphics::YUVToRGBManager::kScaleITU, _curPlanes[0], _curPlanes[1], _curPlanes[2], + YUVToRGBMan.convert420(_surface, Graphics::YUVToRGBManager::kScaleITU, _curPlanes[0], _curPlanes[1], _curPlanes[2], _surfaceWidth, _surfaceHeight, _yBlockWidth * 8, _uvBlockWidth * 8); } @@ -675,8 +688,8 @@ void BinkDecoder::BinkVideoTrack::mergeHuffmanSymbols(VideoFrame &video, byte *d } void BinkDecoder::BinkVideoTrack::initBundles() { - uint32 bw = (_surface.w + 7) >> 3; - uint32 bh = (_surface.h + 7) >> 3; + uint32 bw = (_width + 7) >> 3; + uint32 bh = (_height + 7) >> 3; uint32 blocks = bw * bh; for (int i = 0; i < kSourceMAX; i++) { @@ -684,8 +697,8 @@ void BinkDecoder::BinkVideoTrack::initBundles() { _bundles[i].dataEnd = _bundles[i].data + blocks * 64; } - uint32 cbw[2] = { (uint32)((_surface.w + 7) >> 3), (uint32)((_surface.w + 15) >> 4) }; - uint32 cw [2] = { (uint32)( _surface.w ), (uint32)( _surface.w >> 1) }; + uint32 cbw[2] = { (uint32)((_width + 7) >> 3), (uint32)((_width + 15) >> 4) }; + uint32 cw [2] = { (uint32)( _width ), (uint32)( _width >> 1) }; // Calculate the lengths of an element count in bits for (int i = 0; i < 2; i++) { diff --git a/video/bink_decoder.h b/video/bink_decoder.h index e21d6777a7f..e71c9d2fff1 100644 --- a/video/bink_decoder.h +++ b/video/bink_decoder.h @@ -147,15 +147,16 @@ private: class BinkVideoTrack : public FixedRateVideoTrack { public: - BinkVideoTrack(uint32 width, uint32 height, const Graphics::PixelFormat &format, uint32 frameCount, const Common::Rational &frameRate, bool swapPlanes, bool hasAlpha, uint32 id); + BinkVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, bool swapPlanes, bool hasAlpha, uint32 id); ~BinkVideoTrack(); - uint16 getWidth() const override { return _surface.w; } - uint16 getHeight() const override{ return _surface.h; } - Graphics::PixelFormat getPixelFormat() const override { return _surface.format; } + uint16 getWidth() const override { return _width; } + uint16 getHeight() const override{ return _height; } + Graphics::PixelFormat getPixelFormat() const override { return _pixelFormat; } + bool setOutputPixelFormat(const Graphics::PixelFormat &format) { _pixelFormat = format; return true; } int getCurFrame() const override { return _curFrame; } int getFrameCount() const override { return _frameCount; } - const Graphics::Surface *decodeNextFrame() override { return &_surface; } + const Graphics::Surface *decodeNextFrame() override { return _surface; } bool isSeekable() const override{ return true; } bool seek(const Audio::Timestamp &time) override { return true; } bool rewind() override; @@ -243,7 +244,10 @@ private: int _curFrame; int _frameCount; - Graphics::Surface _surface; + Graphics::Surface *_surface; + Graphics::PixelFormat _pixelFormat; + uint16 _width; + uint16 _height; int _surfaceWidth; ///< The actual surface width int _surfaceHeight; ///< The actual surface height