ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

bink.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/archive.h"
00024 #include "common/memstream.h"
00025 #include "common/stream.h"
00026 #include "common/substream.h"
00027 #include "engines/grim/grim.h"
00028 #include "engines/grim/localize.h"
00029 #include "engines/grim/textobject.h"
00030 #include "engines/grim/textsplit.h"
00031 #include "graphics/surface.h"
00032 #include "video/bink_decoder.h"
00033 
00034 #include "engines/grim/movie/bink.h"
00035 
00036 #ifdef USE_BINK
00037 
00038 namespace Grim {
00039 
00040 MoviePlayer *CreateBinkPlayer(bool demo) {
00041     return new BinkPlayer(demo);
00042 }
00043 
00044 BinkPlayer::BinkPlayer(bool demo) : MoviePlayer(), _demo(demo) {
00045     _videoDecoder = new Video::BinkDecoder();
00046     _videoDecoder->setDefaultHighColorFormat(Graphics::PixelFormat(4, 8, 8, 8, 0, 8, 16, 24, 0));
00047     _subtitleIndex = _subtitles.begin();
00048 }
00049 
00050 bool BinkPlayer::bikCheck(Common::SeekableReadStream *stream, uint32 pos) {
00051     stream->seek(pos);
00052     uint32 tag = stream->readUint32BE();
00053     return (tag & 0xFFFFFF00) == MKTAG('B', 'I', 'K', 0);
00054 }
00055 
00056 void BinkPlayer::deinit() {
00057     g_grim->setMovieSubtitle(nullptr);
00058     MoviePlayer::deinit();
00059 }
00060 
00061 void BinkPlayer::handleFrame() {
00062     MoviePlayer::handleFrame();
00063 
00064     if (!_showSubtitles || _subtitleIndex == _subtitles.end())
00065         return;
00066 
00067     unsigned int startFrame, endFrame, curFrame;
00068     startFrame = _subtitleIndex->_startFrame;
00069     endFrame = _subtitleIndex->_endFrame;
00070     curFrame = _videoDecoder->getCurFrame();
00071     if (startFrame <= curFrame && curFrame <= endFrame) {
00072         if (!_subtitleIndex->active) {
00073             TextObject *textObject = new TextObject();
00074             textObject->setDefaults(&g_grim->_sayLineDefaults);
00075             Color c(255, 255, 255);
00076             textObject->setFGColor(c);
00077             textObject->setIsSpeech();
00078             if (g_grim->getMode() == GrimEngine::SmushMode) {
00079                 // TODO: How to center exactly and put the text exactly
00080                 // at the bottom  even if there are multiple lines?
00081                 textObject->setX(640 / 2);
00082                 textObject->setY(40);
00083             }
00084             textObject->setText(g_localizer->localize(_subtitleIndex->_textId.c_str()), false);
00085             g_grim->setMovieSubtitle(textObject);
00086             _subtitleIndex->active = true;
00087         }
00088     } else if (endFrame < curFrame) {
00089         if (_subtitleIndex->active) {
00090             g_grim->setMovieSubtitle(nullptr);
00091             _subtitleIndex->active = false;
00092             _subtitleIndex++;
00093         }
00094     }
00095 }
00096 
00097 bool BinkPlayer::loadFile(const Common::String &filename) {
00098     _fname = filename;
00099 
00100     if (_demo) {
00101         // The demo uses a .lab suffix
00102         _fname += ".lab";
00103         return MoviePlayer::loadFile(_fname);
00104     }
00105 
00106     _fname += ".m4b";
00107 
00108     Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(_fname);
00109     if (!stream) {
00110         warning("BinkPlayer::loadFile(): Can't create stream for: %s", _fname.c_str());
00111         return false;
00112     }
00113 
00114     // set the default start of the bink video in case there is no SMUSH header
00115     uint32 startBinkPos = 0x0;
00116 
00117     // clear existing subtitles
00118     _subtitles.clear();
00119 
00120     char header[6];
00121     // read the first 5 bytes of the header
00122     stream->read(header, 5);
00123     header[5] = 0;
00124 
00125     if (!strcmp(header, "SMUSH")) {
00126         // handle SMUSH header
00127         unsigned char smushHeader[0x2000];
00128 
00129         // read the first part
00130         uint32 consumed = 16;
00131         stream->read(smushHeader, consumed);
00132 
00133         // decode the first part
00134         for (unsigned int i = 0; i < consumed; i++) {
00135             smushHeader[i] ^= 0xd2;
00136         }
00137 
00138         Common::MemoryReadStream msStart(smushHeader, consumed);
00139         TextSplitter tsStart("", &msStart);
00140 
00141         // extract the length / the start of the following BINK header
00142         tsStart.scanString("%d", 1, &startBinkPos);
00143 
00144         assert(startBinkPos < sizeof(smushHeader));
00145 
00146         // read the rest (5 bytes less because of the string "SMUSH" at the beginning)
00147         stream->read(smushHeader+consumed, startBinkPos - consumed - 5);
00148 
00149         // decode the reset
00150         for (unsigned int i = consumed; i < startBinkPos - 5; i++) {
00151             smushHeader[i] ^= 0xd2;
00152         }
00153         consumed = startBinkPos - 5;
00154 
00155         Common::MemoryReadStream msSmush(smushHeader, consumed);
00156         TextSplitter tsSmush("", &msSmush);
00157 
00158         // skip the first line which contains the length
00159         tsSmush.nextLine();
00160 
00161         tsSmush.expectString("BEGINDATA");
00162         while (!tsSmush.checkString("ENDOFDATA")) {
00163             unsigned int start, end;
00164             char textId[256];
00165 
00166             // extract single subtitle entry
00167             tsSmush.scanString("%d\t%d\t%s", 3, &start, &end, textId);
00168 
00169             Subtitle st(start, end, textId);
00170             _subtitles.push_back(st);
00171         }
00172         tsSmush.expectString("ENDOFDATA");
00173     }
00174 
00175     // set current subtitle index to the first subtitle
00176     _subtitleIndex = _subtitles.begin();
00177 
00178     if (!bikCheck(stream, startBinkPos)) {
00179         warning("BinkPlayer::loadFile(): Could not find BINK header for: %s", _fname.c_str());
00180         delete stream;
00181         return false;
00182     }
00183 
00184     Common::SeekableReadStream *bink = nullptr;
00185     bink = new Common::SeekableSubReadStream(stream, startBinkPos, stream->size(), DisposeAfterUse::YES);
00186     return _videoDecoder->loadStream(bink);
00187 }
00188 
00189 } // end of namespace Grim
00190 
00191 #endif // USE_BINK


Generated on Sat May 18 2019 05:00:56 for ResidualVM by doxygen 1.7.1
curved edge   curved edge