aboutsummaryrefslogtreecommitdiff
path: root/graphics/video/avi_decoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/video/avi_decoder.cpp')
-rw-r--r--graphics/video/avi_decoder.cpp459
1 files changed, 0 insertions, 459 deletions
diff --git a/graphics/video/avi_decoder.cpp b/graphics/video/avi_decoder.cpp
deleted file mode 100644
index ed0b063147..0000000000
--- a/graphics/video/avi_decoder.cpp
+++ /dev/null
@@ -1,459 +0,0 @@
-/* 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.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "common/endian.h"
-#include "common/file.h"
-#include "common/stream.h"
-#include "common/events.h"
-
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
-
-#include "graphics/video/avi_decoder.h"
-
-// Audio Codecs
-#include "sound/decoders/adpcm.h"
-#include "sound/decoders/raw.h"
-
-// Video Codecs
-#include "graphics/video/codecs/cinepak.h"
-#include "graphics/video/codecs/indeo3.h"
-#include "graphics/video/codecs/msvideo1.h"
-#include "graphics/video/codecs/msrle.h"
-#include "graphics/video/codecs/truemotion1.h"
-
-namespace Graphics {
-
-/*
-static byte char2num(char c) {
- return (c >= 48 && c <= 57) ? c - 48 : 0;
-}
-
-static byte getStreamNum(uint32 tag) {
- return char2num((char)(tag >> 24)) * 16 + char2num((char)(tag >> 16));
-}
-*/
-
-static uint16 getStreamType(uint32 tag) {
- return tag & 0xffff;
-}
-
-AviDecoder::AviDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : _mixer(mixer) {
- _soundType = soundType;
-
- _videoCodec = NULL;
- _decodedHeader = false;
- _audStream = NULL;
- _fileStream = NULL;
- _audHandle = new Audio::SoundHandle();
- _dirtyPalette = false;
- memset(_palette, 0, sizeof(_palette));
- memset(&_wvInfo, 0, sizeof(PCMWAVEFORMAT));
- memset(&_bmInfo, 0, sizeof(BITMAPINFOHEADER));
- memset(&_vidsHeader, 0, sizeof(AVIStreamHeader));
- memset(&_audsHeader, 0, sizeof(AVIStreamHeader));
- memset(&_ixInfo, 0, sizeof(AVIOLDINDEX));
-}
-
-AviDecoder::~AviDecoder() {
- close();
- delete _audHandle;
-}
-
-void AviDecoder::runHandle(uint32 tag) {
- assert (_fileStream);
- if (_fileStream->eos())
- return;
-
- debug (3, "Decoding tag %s", tag2str(tag));
-
- switch (tag) {
- case ID_RIFF:
- /*_filesize = */_fileStream->readUint32LE();
- if (_fileStream->readUint32BE() != ID_AVI)
- error("RIFF file is not an AVI video");
- break;
- case ID_LIST:
- handleList();
- break;
- case ID_AVIH:
- _header.size = _fileStream->readUint32LE();
- _header.microSecondsPerFrame = _fileStream->readUint32LE();
- _header.maxBytesPerSecond = _fileStream->readUint32LE();
- _header.padding = _fileStream->readUint32LE();
- _header.flags = _fileStream->readUint32LE();
- _header.totalFrames = _fileStream->readUint32LE();
- _header.initialFrames = _fileStream->readUint32LE();
- _header.streams = _fileStream->readUint32LE();
- _header.bufferSize = _fileStream->readUint32LE();
- _header.width = _fileStream->readUint32LE();
- _header.height = _fileStream->readUint32LE();
- //Ignore 16 bytes of reserved data
- _fileStream->skip(16);
- break;
- case ID_STRH:
- handleStreamHeader();
- break;
- case ID_STRD: // Extra stream info, safe to ignore
- case ID_VEDT: // Unknown, safe to ignore
- case ID_JUNK: // Alignment bytes, should be ignored
- {
- uint32 junkSize = _fileStream->readUint32LE();
- _fileStream->skip(junkSize + (junkSize & 1)); // Alignment
- } break;
- case ID_IDX1:
- _ixInfo.size = _fileStream->readUint32LE();
- _ixInfo.indices = new AVIOLDINDEX::Index[_ixInfo.size / 16];
- debug (0, "%d Indices", (_ixInfo.size / 16));
- for (uint32 i = 0; i < (_ixInfo.size / 16); i++) {
- _ixInfo.indices[i].id = _fileStream->readUint32BE();
- _ixInfo.indices[i].flags = _fileStream->readUint32LE();
- _ixInfo.indices[i].offset = _fileStream->readUint32LE();
- _ixInfo.indices[i].size = _fileStream->readUint32LE();
- debug (0, "Index %d == Tag \'%s\', Offset = %d, Size = %d", i, tag2str(_ixInfo.indices[i].id), _ixInfo.indices[i].offset, _ixInfo.indices[i].size);
- }
- break;
- default:
- error ("Unknown tag \'%s\' found", tag2str(tag));
- }
-}
-
-void AviDecoder::handleList() {
- uint32 listSize = _fileStream->readUint32LE() - 4; // Subtract away listType's 4 bytes
- uint32 listType = _fileStream->readUint32BE();
- uint32 curPos = _fileStream->pos();
-
- debug (0, "Found LIST of type %s", tag2str(listType));
-
- while ((_fileStream->pos() - curPos) < listSize)
- runHandle(_fileStream->readUint32BE());
-
- // We now have all the header data
- if (listType == ID_HDRL)
- _decodedHeader = true;
-}
-
-void AviDecoder::handleStreamHeader() {
- AVIStreamHeader sHeader;
- sHeader.size = _fileStream->readUint32LE();
- sHeader.streamType = _fileStream->readUint32BE();
- if (sHeader.streamType == ID_MIDS || sHeader.streamType == ID_TXTS)
- error ("Unhandled MIDI/Text stream");
- sHeader.streamHandler = _fileStream->readUint32BE();
- sHeader.flags = _fileStream->readUint32LE();
- sHeader.priority = _fileStream->readUint16LE();
- sHeader.language = _fileStream->readUint16LE();
- sHeader.initialFrames = _fileStream->readUint32LE();
- sHeader.scale = _fileStream->readUint32LE();
- sHeader.rate = _fileStream->readUint32LE();
- sHeader.start = _fileStream->readUint32LE();
- sHeader.length = _fileStream->readUint32LE();
- sHeader.bufferSize = _fileStream->readUint32LE();
- sHeader.quality = _fileStream->readUint32LE();
- sHeader.sampleSize = _fileStream->readUint32LE();
-
- _fileStream->skip(sHeader.size - 48); // Skip over the remainder of the chunk (frame)
-
- if (_fileStream->readUint32BE() != ID_STRF)
- error("Could not find STRF tag");
- uint32 strfSize = _fileStream->readUint32LE();
- uint32 startPos = _fileStream->pos();
-
- if (sHeader.streamType == ID_VIDS) {
- _vidsHeader = sHeader;
-
- _bmInfo.size = _fileStream->readUint32LE();
- _bmInfo.width = _fileStream->readUint32LE();
- assert (_header.width == _bmInfo.width);
- _bmInfo.height = _fileStream->readUint32LE();
- assert (_header.height == _bmInfo.height);
- _bmInfo.planes = _fileStream->readUint16LE();
- _bmInfo.bitCount = _fileStream->readUint16LE();
- _bmInfo.compression = _fileStream->readUint32BE();
- _bmInfo.sizeImage = _fileStream->readUint32LE();
- _bmInfo.xPelsPerMeter = _fileStream->readUint32LE();
- _bmInfo.yPelsPerMeter = _fileStream->readUint32LE();
- _bmInfo.clrUsed = _fileStream->readUint32LE();
- _bmInfo.clrImportant = _fileStream->readUint32LE();
-
- if (_bmInfo.bitCount == 8) {
- if (_bmInfo.clrUsed == 0)
- _bmInfo.clrUsed = 256;
-
- for (uint32 i = 0; i < _bmInfo.clrUsed; i++) {
- _palette[i * 3 + 2] = _fileStream->readByte();
- _palette[i * 3 + 1] = _fileStream->readByte();
- _palette[i * 3] = _fileStream->readByte();
- _fileStream->readByte();
- }
-
- _dirtyPalette = true;
- }
-
- if (!_vidsHeader.streamHandler)
- _vidsHeader.streamHandler = _bmInfo.compression;
- } else if (sHeader.streamType == ID_AUDS) {
- _audsHeader = sHeader;
-
- _wvInfo.tag = _fileStream->readUint16LE();
- _wvInfo.channels = _fileStream->readUint16LE();
- _wvInfo.samplesPerSec = _fileStream->readUint32LE();
- _wvInfo.avgBytesPerSec = _fileStream->readUint32LE();
- _wvInfo.blockAlign = _fileStream->readUint16LE();
- _wvInfo.size = _fileStream->readUint16LE();
-
- // AVI seems to treat the sampleSize as including the second
- // channel as well, so divide for our sake.
- if (_wvInfo.channels == 2)
- _audsHeader.sampleSize /= 2;
- }
-
- // Ensure that we're at the end of the chunk
- _fileStream->seek(startPos + strfSize);
-}
-
-bool AviDecoder::load(Common::SeekableReadStream *stream) {
- close();
-
- _fileStream = stream;
- _decodedHeader = false;
-
- // Read chunks until we have decoded the header
- while (!_decodedHeader)
- runHandle(_fileStream->readUint32BE());
-
- uint32 nextTag = _fileStream->readUint32BE();
-
- // Throw out any JUNK section
- if (nextTag == ID_JUNK) {
- runHandle(ID_JUNK);
- nextTag = _fileStream->readUint32BE();
- }
-
- // Ignore the 'movi' LIST
- if (nextTag == ID_LIST) {
- _fileStream->readUint32BE(); // Skip size
- if (_fileStream->readUint32BE() != ID_MOVI)
- error ("Expected 'movi' LIST");
- } else
- error ("Expected 'movi' LIST");
-
- // Now, create the codec
- _videoCodec = createCodec();
-
- // Initialize the video stuff too
- _audStream = createAudioStream();
- if (_audStream)
- _mixer->playStream(_soundType, _audHandle, _audStream);
-
- debug (0, "Frames = %d, Dimensions = %d x %d", _header.totalFrames, _header.width, _header.height);
- debug (0, "Frame Rate = %d", _vidsHeader.rate / _vidsHeader.scale);
- if (_wvInfo.samplesPerSec != 0)
- debug (0, "Sound Rate = %d", _wvInfo.samplesPerSec);
- debug (0, "Video Codec = \'%s\'", tag2str(_vidsHeader.streamHandler));
-
- if (!_videoCodec)
- return false;
-
- return true;
-}
-
-void AviDecoder::close() {
- if (!_fileStream)
- return;
-
- delete _fileStream;
- _fileStream = 0;
-
- // Deinitialize sound
- _mixer->stopHandle(*_audHandle);
- _audStream = 0;
-
- _decodedHeader = false;
-
- delete _videoCodec;
- _videoCodec = 0;
-
- delete[] _ixInfo.indices;
- _ixInfo.indices = 0;
-
- memset(_palette, 0, sizeof(_palette));
- memset(&_wvInfo, 0, sizeof(PCMWAVEFORMAT));
- memset(&_bmInfo, 0, sizeof(BITMAPINFOHEADER));
- memset(&_vidsHeader, 0, sizeof(AVIStreamHeader));
- memset(&_audsHeader, 0, sizeof(AVIStreamHeader));
- memset(&_ixInfo, 0, sizeof(AVIOLDINDEX));
-
- reset();
-}
-
-uint32 AviDecoder::getElapsedTime() const {
- if (_audStream)
- return _mixer->getSoundElapsedTime(*_audHandle);
-
- return VideoDecoder::getElapsedTime();
-}
-
-const Surface *AviDecoder::decodeNextFrame() {
- uint32 nextTag = _fileStream->readUint32BE();
-
- if (_fileStream->eos())
- return NULL;
-
- if (_curFrame == -1)
- _startTime = g_system->getMillis();
-
- if (nextTag == ID_LIST) {
- // A list of audio/video chunks
- uint32 listSize = _fileStream->readUint32LE() - 4;
- int32 startPos = _fileStream->pos();
-
- if (_fileStream->readUint32BE() != ID_REC)
- error ("Expected 'rec ' LIST");
-
- // Decode chunks in the list and see if we get a frame
- const Surface *frame = NULL;
- while (_fileStream->pos() < startPos + (int32)listSize) {
- const Surface *temp = decodeNextFrame();
- if (temp)
- frame = temp;
- }
-
- return frame;
- } else if (getStreamType(nextTag) == 'wb') {
- // Audio Chunk
- uint32 chunkSize = _fileStream->readUint32LE();
- queueAudioBuffer(chunkSize);
- _fileStream->skip(chunkSize & 1); // Alignment
- } else if (getStreamType(nextTag) == 'dc' || getStreamType(nextTag) == 'id' ||
- getStreamType(nextTag) == 'AM' || getStreamType(nextTag) == '32') {
- // Compressed Frame
- _curFrame++;
- uint32 chunkSize = _fileStream->readUint32LE();
-
- if (chunkSize == 0) // Keep last frame on screen
- return NULL;
-
- Common::SeekableReadStream *frameData = _fileStream->readStream(chunkSize);
- const Graphics::Surface *surface = _videoCodec->decodeImage(frameData);
- delete frameData;
- _fileStream->skip(chunkSize & 1); // Alignment
- return surface;
- } else if (getStreamType(nextTag) == 'pc') {
- // Palette Change
- _fileStream->readUint32LE(); // Chunk size, not needed here
- byte firstEntry = _fileStream->readByte();
- uint16 numEntries = _fileStream->readByte();
- _fileStream->readUint16LE(); // Reserved
-
- // 0 entries means all colors are going to be changed
- if (numEntries == 0)
- numEntries = 256;
-
- for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) {
- _palette[i * 3] = _fileStream->readByte();
- _palette[i * 3 + 1] = _fileStream->readByte();
- _palette[i * 3 + 2] = _fileStream->readByte();
- _fileStream->readByte(); // Flags that don't serve us any purpose
- }
-
- _dirtyPalette = true;
-
- // No alignment necessary. It's always even.
- } else if (nextTag == ID_JUNK) {
- runHandle(ID_JUNK);
- } else if (nextTag == ID_IDX1) {
- runHandle(ID_IDX1);
- } else
- error("Tag = \'%s\', %d", tag2str(nextTag), _fileStream->pos());
-
- return NULL;
-}
-
-Codec *AviDecoder::createCodec() {
- switch (_vidsHeader.streamHandler) {
- case ID_CRAM:
- case ID_MSVC:
- case ID_WHAM:
- return new MSVideo1Decoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount);
- case ID_RLE:
- return new MSRLEDecoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount);
- case ID_CVID:
- return new CinepakDecoder(_bmInfo.bitCount);
-#ifdef USE_INDEO3
- case ID_IV32:
- return new Indeo3Decoder(_bmInfo.width, _bmInfo.height);
-#endif
-#ifdef GRAPHICS_TRUEMOTION1_H
- case ID_DUCK:
- return new TrueMotion1Decoder(_bmInfo.width, _bmInfo.height);
-#endif
- default:
- warning ("Unknown/Unhandled compression format \'%s\'", tag2str(_vidsHeader.streamHandler));
- }
-
- return NULL;
-}
-
-PixelFormat AviDecoder::getPixelFormat() const {
- assert(_videoCodec);
- return _videoCodec->getPixelFormat();
-}
-
-Audio::QueuingAudioStream *AviDecoder::createAudioStream() {
- if (_wvInfo.tag == kWaveFormatPCM || _wvInfo.tag == kWaveFormatDK3)
- return Audio::makeQueuingAudioStream(_wvInfo.samplesPerSec, _wvInfo.channels == 2);
- else if (_wvInfo.tag != kWaveFormatNone) // No sound
- warning("Unsupported AVI audio format %d", _wvInfo.tag);
-
- return NULL;
-}
-
-void AviDecoder::queueAudioBuffer(uint32 chunkSize) {
- // Return if we haven't created the queue (unsupported audio format)
- if (!_audStream) {
- _fileStream->skip(chunkSize);
- return;
- }
-
- Common::SeekableReadStream *stream = _fileStream->readStream(chunkSize);
-
- if (_wvInfo.tag == kWaveFormatPCM) {
- byte flags = 0;
- if (_audsHeader.sampleSize == 2)
- flags |= Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
- else
- flags |= Audio::FLAG_UNSIGNED;
-
- if (_wvInfo.channels == 2)
- flags |= Audio::FLAG_STEREO;
-
- _audStream->queueAudioStream(Audio::makeRawStream(stream, _wvInfo.samplesPerSec, flags, DisposeAfterUse::YES), DisposeAfterUse::YES);
- } else if (_wvInfo.tag == kWaveFormatDK3) {
- _audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, chunkSize, Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
- }
-}
-
-} // End of namespace Graphics