aboutsummaryrefslogtreecommitdiff
path: root/engines/wintermute/video/video_player.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/wintermute/video/video_player.cpp')
-rw-r--r--engines/wintermute/video/video_player.cpp470
1 files changed, 470 insertions, 0 deletions
diff --git a/engines/wintermute/video/video_player.cpp b/engines/wintermute/video/video_player.cpp
new file mode 100644
index 0000000000..49d1c6c50f
--- /dev/null
+++ b/engines/wintermute/video/video_player.cpp
@@ -0,0 +1,470 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This file is based on WME Lite.
+ * http://dead-code.org/redir.php?target=wmelite
+ * Copyright (c) 2011 Jan Nedoma
+ */
+
+
+#include "engines/wintermute/dcgf.h"
+#include "engines/wintermute/video/video_player.h"
+
+//#pragma comment(lib, "vfw32.lib")
+
+namespace WinterMute {
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////
+CVidPlayer::CVidPlayer(CBGame *inGame): CBBase(inGame) {
+ SetDefaults();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CVidPlayer::SetDefaults() {
+ _playing = false;
+
+ /* _aviFile = NULL;
+
+ _audioStream = NULL;
+ _audioFormat = NULL;
+
+ _videoStream = NULL;
+ _videoFormat = NULL;
+ _videoPGF = NULL;*/
+ _videoEndTime = 0;
+
+ //_sound = NULL;
+ _soundAvailable = false;
+
+ //_vidRenderer = NULL;
+
+ _startTime = 0;
+ _totalVideoTime = 0;
+
+ //_lastSample = -1;
+
+ //_targetFormat = NULL;
+
+ _playPosX = _playPosY = 0;
+ _playZoom = 0.0f;
+
+ _filename = NULL;
+
+ _slowRendering = false;
+
+ _currentSubtitle = 0;
+ _showSubtitle = false;
+
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CVidPlayer::~CVidPlayer() {
+ cleanup();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CVidPlayer::cleanup() {
+#if 0
+ if (_sound) _sound->Stop();
+ if (_videoPGF) AVIStreamGetFrameClose(_videoPGF);
+ _videoPGF = NULL;
+
+ _playing = false;
+
+
+ if (_aviFile) AVIFileRelease(m_AviFile);
+
+ if (_audioStream) AVIStreamRelease(m_AudioStream);
+ if (_videoStream) AVIStreamRelease(m_VideoStream);
+
+ if (_audioFormat) delete [](byte *)m_AudioFormat;
+ if (_videoFormat) delete [](byte *)m_VideoFormat;
+ if (_targetFormat) delete [](byte *)m_TargetFormat;
+
+ SAFE_DELETE(_sound);
+ SAFE_DELETE(_vidRenderer);
+
+ SAFE_DELETE_ARRAY(_filename);
+
+ for (int i = 0; i < _subtitles.getSize(); i++) delete _subtitles[i];
+ _subtitles.removeAll();
+
+ return SetDefaults();
+#endif
+ return 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CVidPlayer::initialize(const char *inFilename, const char *SubtitleFile) {
+#if 0
+ cleanup();
+
+ char Filename[MAX_PATH_LENGTH];
+ _gameRef->_fileManager->GetFullPath(inFilename, filename);
+
+ // open file
+ if (AVIFileOpen(&_aviFile, Filename, OF_READ, NULL) != 0) {
+ _gameRef->LOG(0, "Error opening AVI file '%s'", filename);
+ return STATUS_FAILED;
+ }
+
+ // get video stream
+ if (AVIFileGetStream(_aviFile, &_videoStream, streamtypeVIDEO, 0) != 0) {
+ _gameRef->LOG(0, "Error finding video stream in AVI file '%s'", filename);
+ return STATUS_FAILED;
+ }
+ _totalVideoTime = AVIStreamEndTime(_videoStream);
+
+ // get audio stream
+ if (_gameRef->m_SoundMgr->_soundAvailable && AVIFileGetStream(_aviFile, &_audioStream, streamtypeAUDIO, 0) == 0)
+ _soundAvailable = true;
+ else
+ _soundAvailable = false;
+
+
+ LONG Size;
+
+ // get video format
+ if (AVIStreamReadFormat(m_VideoStream, 0, NULL, &Size)) {
+ _gameRef->LOG(0, "Error obtaining video stream format in AVI file '%s'", filename);
+ return STATUS_FAILED;
+ }
+ _videoFormat = (LPBITMAPINFO)new BYTE[Size];
+ AVIStreamReadFormat(m_VideoStream, 0, m_VideoFormat, &Size);
+
+ // initialize optimal target format
+ m_TargetFormat = (LPBITMAPV4HEADER)new BYTE[max(Size, sizeof(BITMAPV4HEADER))];
+ memset(m_TargetFormat, 0, sizeof(BITMAPV4HEADER));
+ memcpy(m_TargetFormat, m_VideoFormat, Size);
+ m_TargetFormat->bV4Size = max(Size, sizeof(BITMAPV4HEADER));
+
+ m_TargetFormat->bV4BitCount = 24;
+ m_TargetFormat->bV4V4Compression = BI_RGB;
+
+ if (_gameRef->m_UseD3D)
+ m_VidRenderer = new CVidRendererD3D(_gameRef);
+ else
+ m_VidRenderer = new CVidRendererDD(_gameRef);
+
+ if (!m_VidRenderer || DID_FAIL(m_VidRenderer->Initialize(m_VideoFormat, m_TargetFormat))) {
+ _gameRef->LOG(0, "Error initializing video renderer for AVI file '%s'", filename);
+ SAFE_DELETE(m_VidRenderer);
+ return STATUS_FAILED;
+ }
+
+
+ // create sound buffer
+ bool res;
+
+ if (_soundAvailable) {
+ _sound = new CBSoundAVI(_gameRef);
+ if (DID_FAIL(res = _sound->InitializeBuffer(_audioStream))) {
+ SAFE_DELETE(_sound);
+ _soundAvailable = false;
+ _gameRef->LOG(res, "Error initializing sound buffer for AVI file '%s'", filename);
+ }
+ }
+
+ if (_gameRef->_videoSubtitles) LoadSubtitles(inFilename, SubtitleFile);
+
+ _filename = new char[strlen(filename) + 1];
+ if (_filename) strcpy(_filename, filename);
+#endif
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CVidPlayer::update() {
+#if 0
+ if (!m_Playing) return STATUS_OK;
+
+ bool res;
+
+ if (_soundAvailable && m_Sound) {
+ res = _sound->update();
+ if (DID_FAIL(res)) return res;
+ }
+
+
+ DWORD CurrentTime; // current playing time (in ms)
+ /*
+ if(m_SoundAvailable && m_Sound){
+ CurrentTime = m_Sound->GetPosition(); // in samples
+ CurrentTime /= (m_Sound->m_Format.wf.nSamplesPerSec / 1000);
+
+ if(!m_Sound->IsPlaying()) CurrentTime = m_TotalVideoTime;
+ }
+ else
+ CurrentTime = timeGetTime() - m_StartTime;
+ */
+ CurrentTime = timeGetTime() - _startTime;
+
+ if (CurrentTime >= _totalVideoTime) {
+ Stop();
+ return STATUS_OK;
+ }
+
+
+ // get and render frame
+ DWORD sample = AVIStreamTimeToSample(_videoStream, CurrentTime);
+ if (sample != _lastSample) {
+ _lastSample = sample;
+
+ // process subtitles
+ _showSubtitle = false;
+ while (_currentSubtitle < _subtitles.getSize()) {
+ int End = _subtitles[_currentSubtitle]->m_EndFrame;
+
+ bool NextFrameOK = (_currentSubtitle < _subtitles.getSize() - 1 && _subtitles[_currentSubtitle + 1]->_startFrame <= sample);
+
+ if (sample > End) {
+ if (NextFrameOK) {
+ _currentSubtitle++;
+ } else {
+ _showSubtitle = (End == 0);
+ break;
+ }
+ } else {
+ _showSubtitle = true;
+ break;
+ }
+ }
+
+
+ // render frame
+ LPBITMAPINFOHEADER FrameData = (LPBITMAPINFOHEADER)AVIStreamGetFrame(m_VideoPGF, sample);
+ if (FrameData) {
+ if (_slowRendering) return _vidRenderer->ProcessFrameSlow(FrameData);
+ else return _vidRenderer->ProcessFrame(FrameData);
+ } else return STATUS_FAILED;
+ } else return STATUS_OK;
+#endif
+ return 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CVidPlayer::display() {
+#if 0
+ if (!m_Playing) return STATUS_OK;
+
+ bool res;
+ if (_vidRenderer) res = _vidRenderer->display(m_PlayPosX, m_PlayPosY, m_PlayZoom);
+ else res = STATUS_FAILED;
+
+ // display subtitle
+ if (m_ShowSubtitle) {
+ CBFont *font = _gameRef->_videoFont ? _gameRef->_videoFont : _gameRef->_systemFont;
+ int Height = font->GetTextHeight((BYTE *)m_Subtitles[_currentSubtitle]->_text, _gameRef->_renderer->_width);
+ font->drawText((byte *)_subtitles[m_CurrentSubtitle]->_text, 0, _gameRef->_renderer->_height - Height - 5, _gameRef->_renderer->_width, TAL_CENTER);
+ }
+
+ return res;
+#endif
+ return 0;
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CVidPlayer::play(TVideoPlayback Type, int X, int Y, bool FreezeMusic) {
+#if 0
+ if (!_videoStream || !_vidRenderer) return STATUS_FAILED;
+
+ switch (Type) {
+ case VID_PLAY_POS:
+ _playZoom = 100.0f;
+ _playPosX = X;
+ _playPosY = Y;
+ break;
+
+ case VID_PLAY_STRETCH: {
+ float ZoomX = (float)((float)_gameRef->_renderer->m_Width / (float)_videoFormat->bmiHeader.biWidth * 100);
+ float ZoomY = (float)((float)_gameRef->_renderer->m_Height / (float)_videoFormat->bmiHeader.biHeight * 100);
+ _playZoom = min(ZoomX, ZoomY);
+ _playPosX = (_gameRef->_renderer->_width - _videoFormat->bmiHeader.biWidth * (_playZoom / 100)) / 2;
+ _playPosY = (_gameRef->_renderer->_height - _videoFormat->bmiHeader.biHeight * (_playZoom / 100)) / 2;
+ }
+ break;
+
+ case VID_PLAY_CENTER:
+ _playZoom = 100.0f;
+ _playPosX = (_gameRef->_renderer->_width - _videoFormat->bmiHeader.biWidth) / 2;
+ _playPosY = (_gameRef->_renderer->_height - _videoFormat->bmiHeader.biHeight) / 2;
+ break;
+ }
+
+ _targetFormat->bV4BitCount = 24;
+ _targetFormat->bV4V4Compression = BI_RGB;
+
+
+ _videoPGF = AVIStreamGetFrameOpen(_videoStream, (LPBITMAPINFOHEADER)m_TargetFormat);
+ if (!_videoPGF) {
+ _videoPGF = AVIStreamGetFrameOpen(_videoStream, NULL);
+ if (!_videoPGF) {
+ _gameRef->LOG(0, "Error: Unsupported AVI format (file '%s')", m_Filename);
+ cleanup();
+ return STATUS_FAILED;
+ } else {
+ _gameRef->LOG(0, "Performance warning: non-optimal AVI format, using generic (i.e. slow) rendering routines (file '%s')", m_Filename);
+ _slowRendering = true;
+ }
+ } else _slowRendering = false;
+
+ // HACK!!!
+ _slowRendering = true;
+
+
+ _currentSubtitle = 0;
+
+ _gameRef->Freeze(FreezeMusic);
+
+ _playing = true;
+ if (_sound) _sound->Play();
+ _startTime = timeGetTime();
+#endif
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CVidPlayer::stop() {
+#if 0
+ if (!_playing) return STATUS_OK;
+
+ cleanup();
+
+ _gameRef->Unfreeze();
+#endif
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CVidPlayer::isPlaying() {
+ return _playing;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CVidPlayer::loadSubtitles(const char *filename, const char *SubtitleFile) {
+#if 0
+ if (!Filename) return STATUS_OK;
+
+ char NewFile[MAX_PATH_LENGTH];
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+
+ if (SubtitleFile) {
+ strcpy(NewFile, SubtitleFile);
+ } else {
+ _splitpath(filename, drive, dir, fname, NULL);
+ _makepath(NewFile, drive, dir, fname, ".SUB");
+ }
+
+ DWORD Size;
+ BYTE *Buffer = _gameRef->m_FileManager->readWholeFile(NewFile, &Size, false);
+ if (Buffer == NULL) return STATUS_OK; // no subtitles
+
+
+ LONG Start, End;
+ bool InToken;
+ char *TokenStart;
+ int TokenLength;
+ int TokenPos;
+ int TextLength;
+
+ int Pos = 0;
+ int LineLength = 0;
+ while (Pos < Size) {
+ Start = End = -1;
+ InToken = false;
+ TokenPos = -1;
+ TextLength = 0;
+
+ LineLength = 0;
+ while (Pos + LineLength < Size && Buffer[Pos + LineLength] != '\n' && Buffer[Pos + LineLength] != '\0') LineLength++;
+
+ int RealLength = LineLength - (Pos + LineLength >= Size ? 0 : 1);
+ char *Text = new char[RealLength + 1];
+ char *line = (char *)&Buffer[Pos];
+
+ for (int i = 0; i < RealLength; i++) {
+ if (line[i] == '{') {
+ if (!InToken) {
+ InToken = true;
+ TokenStart = line + i + 1;
+ TokenLength = 0;
+ TokenPos++;
+ } else TokenLength++;
+ } else if (line[i] == '}') {
+ if (InToken) {
+ InToken = false;
+ char *Token = new char[TokenLength + 1];
+ strncpy(Token, TokenStart, TokenLength);
+ Token[TokenLength] = '\0';
+ if (TokenPos == 0) Start = atoi(Token);
+ else if (TokenPos == 1) End = atoi(Token);
+
+ delete [] Token;
+ } else {
+ Text[TextLength] = line[i];
+ TextLength++;
+ }
+ } else {
+ if (InToken) {
+ TokenLength++;
+ } else {
+ Text[TextLength] = line[i];
+ if (Text[TextLength] == '|') Text[TextLength] = '\n';
+ TextLength++;
+ }
+ }
+ }
+ Text[TextLength] = '\0';
+
+ if (Start != -1 && TextLength > 0) _subtitles.add(new CVidSubtitle(_gameRef, Text, Start, End));
+
+ delete [] Text;
+
+ Pos += LineLength + 1;
+ }
+
+ delete [] Buffer;
+#endif
+ return STATUS_OK;
+}
+
+} // end of namespace WinterMute