1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
|
/* 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.
*
*/
#ifndef VIDEO_AVI_DECODER_H
#define VIDEO_AVI_DECODER_H
#include "common/array.h"
#include "common/rational.h"
#include "common/rect.h"
#include "common/str.h"
#include "video/video_decoder.h"
#include "audio/mixer.h"
namespace Audio {
class AudioStream;
class PacketizedAudioStream;
}
namespace Common {
class SeekableReadStream;
}
namespace Graphics {
struct PixelFormat;
}
namespace Image {
class Codec;
}
namespace Video {
/**
* Decoder for AVI videos.
*
* Video decoder used in engines:
* - sci
* - sword1
* - sword2
* - titanic
* - zvision
*/
class AVIDecoder : public VideoDecoder {
public:
AVIDecoder();
AVIDecoder(const Common::Rational &frameRateOverride);
virtual ~AVIDecoder();
bool loadStream(Common::SeekableReadStream *stream);
void close();
uint16 getWidth() const { return _header.width; }
uint16 getHeight() const { return _header.height; }
bool rewind();
bool isRewindable() const { return true; }
bool isSeekable() const;
/**
* Decode the next frame into a surface and return the latter.
*
* A subclass may override this, but must still call this function. As an
* example, a subclass may do this to apply some global video scale to
* individual track's frame.
*
* Note that this will call readNextPacket() internally first before calling
* the next video track's decodeNextFrame() function.
*
* @return a surface containing the decoded frame, or 0
* @note Ownership of the returned surface stays with the VideoDecoder,
* hence the caller must *not* free it.
* @note this may return 0, in which case the last frame should be kept on screen
*/
virtual const Graphics::Surface *decodeNextFrame();
/**
* Decodes the next transparency track frame
*/
const Graphics::Surface *decodeNextTransparency();
protected:
// VideoDecoder API
void readNextPacket();
bool seekIntern(const Audio::Timestamp &time);
bool supportsAudioTrackSwitching() const { return true; }
AudioTrack *getAudioTrack(int index);
/**
* Define a track to be used by this class.
*
* The pointer is then owned by this base class.
*
* @param track The track to add
* @param isExternal Is this an external track not found by loadStream()?
*/
void addTrack(Track *track, bool isExternal = false);
struct BitmapInfoHeader {
uint32 size;
uint32 width;
uint32 height;
uint16 planes;
uint16 bitCount;
uint32 compression;
uint32 sizeImage;
uint32 xPelsPerMeter;
uint32 yPelsPerMeter;
uint32 clrUsed;
uint32 clrImportant;
};
struct WaveFormat {
uint16 tag;
uint16 channels;
uint32 samplesPerSec;
uint32 avgBytesPerSec;
uint16 blockAlign;
};
struct PCMWaveFormat : public WaveFormat {
uint16 size;
};
struct WaveFormatEX : public WaveFormat {
uint16 bitsPerSample;
uint16 size;
};
struct OldIndex {
uint32 id;
uint32 flags;
uint32 offset;
uint32 size;
};
// Index Flags
enum IndexFlags {
AVIIF_INDEX = 0x10
};
struct AVIHeader {
uint32 size;
uint32 microSecondsPerFrame;
uint32 maxBytesPerSecond;
uint32 padding;
uint32 flags;
uint32 totalFrames;
uint32 initialFrames;
uint32 streams;
uint32 bufferSize;
uint32 width;
uint32 height;
};
// Flags from the AVIHeader
enum AVIFlags {
AVIF_HASINDEX = 0x00000010,
AVIF_MUSTUSEINDEX = 0x00000020,
AVIF_ISINTERLEAVED = 0x00000100,
AVIF_TRUSTCKTYPE = 0x00000800,
AVIF_WASCAPTUREFILE = 0x00010000,
AVIF_WASCOPYRIGHTED = 0x00020000
};
struct AVIStreamHeader {
uint32 size;
uint32 streamType;
uint32 streamHandler;
uint32 flags;
uint16 priority;
uint16 language;
uint32 initialFrames;
uint32 scale;
uint32 rate;
uint32 start;
uint32 length;
uint32 bufferSize;
uint32 quality;
uint32 sampleSize;
Common::Rect frame;
Common::String name;
};
class AVIVideoTrack : public FixedRateVideoTrack {
public:
AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader, byte *initialPalette = 0);
~AVIVideoTrack();
void decodeFrame(Common::SeekableReadStream *stream);
void forceTrackEnd();
uint16 getWidth() const { return _bmInfo.width; }
uint16 getHeight() const { return _bmInfo.height; }
uint16 getBitCount() const { return _bmInfo.bitCount; }
Graphics::PixelFormat getPixelFormat() const;
int getCurFrame() const { return _curFrame; }
int getFrameCount() const { return _frameCount; }
Common::String &getName() { return _vidsHeader.name; }
const Graphics::Surface *decodeNextFrame() { return _lastFrame; }
const byte *getPalette() const;
bool hasDirtyPalette() const;
void setCurFrame(int frame) { _curFrame = frame; }
void loadPaletteFromChunk(Common::SeekableReadStream *chunk);
void useInitialPalette();
bool canDither() const;
void setDither(const byte *palette);
bool isTruemotion1() const;
void forceDimensions(uint16 width, uint16 height);
bool isRewindable() const { return true; }
bool rewind();
/**
* Set the video track to play in reverse or forward.
*
* By default, a VideoTrack must decode forward.
*
* @param reverse true for reverse, false for forward
* @return true for success, false for failure
*/
virtual bool setReverse(bool reverse);
/**
* Is the video track set to play in reverse?
*/
virtual bool isReversed() const { return _reversed; }
/**
* Returns true if at the end of the video track
*/
virtual bool endOfTrack() const;
/**
* Get track frame rate
*/
Common::Rational getFrameRate() const { return Common::Rational(_vidsHeader.rate, _vidsHeader.scale); }
/**
* Force sets a new frame rate
*/
void setFrameRate(const Common::Rational &r) {
_vidsHeader.rate = r.getNumerator();
_vidsHeader.scale = r.getDenominator();
}
private:
AVIStreamHeader _vidsHeader;
BitmapInfoHeader _bmInfo;
byte _palette[3 * 256];
byte *_initialPalette;
mutable bool _dirtyPalette;
int _frameCount, _curFrame;
bool _reversed;
Image::Codec *_videoCodec;
const Graphics::Surface *_lastFrame;
Image::Codec *createCodec();
};
class AVIAudioTrack : public AudioTrack {
public:
AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType);
~AVIAudioTrack();
virtual void createAudioStream();
virtual void queueSound(Common::SeekableReadStream *stream);
void skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime);
virtual void resetStream();
uint32 getCurChunk() const { return _curChunk; }
Common::String &getName() { return _audsHeader.name; }
void setCurChunk(uint32 chunk) { _curChunk = chunk; }
bool isRewindable() const { return true; }
bool rewind();
protected:
Audio::AudioStream *getAudioStream() const { return _audioStream; }
// Audio Codecs
enum {
kWaveFormatNone = 0,
kWaveFormatPCM = 1,
kWaveFormatMSADPCM = 2,
kWaveFormatMSIMAADPCM = 17,
kWaveFormatMP3 = 85,
kWaveFormatDK3 = 98 // rogue format number
};
AVIStreamHeader _audsHeader;
PCMWaveFormat _wvInfo;
Audio::AudioStream *_audioStream;
Audio::PacketizedAudioStream *_packetStream;
uint32 _curChunk;
};
struct TrackStatus {
TrackStatus();
Track *track;
uint32 index;
uint32 chunkSearchOffset;
};
class IndexEntries : public Common::Array<OldIndex> {
public:
OldIndex *find(uint index, uint frameNumber);
};
AVIHeader _header;
void readOldIndex(uint32 size);
IndexEntries _indexEntries;
Common::SeekableReadStream *_fileStream;
bool _decodedHeader;
bool _foundMovieList;
uint32 _movieListStart, _movieListEnd;
Common::Rational _frameRateOverride;
int _videoTrackCounter, _audioTrackCounter;
Track *_lastAddedTrack;
void initCommon();
bool parseNextChunk();
void skipChunk(uint32 size);
void handleList(uint32 listSize);
void handleStreamHeader(uint32 size);
void readStreamName(uint32 size);
uint16 getStreamType(uint32 tag) const { return tag & 0xFFFF; }
static byte getStreamIndex(uint32 tag);
void checkTruemotion1();
uint getVideoTrackOffset(uint trackIndex, uint frameNumber = 0);
void handleNextPacket(TrackStatus& status);
bool shouldQueueAudio(TrackStatus& status);
void seekTransparencyFrame(int frame);
Common::Array<TrackStatus> _videoTracks, _audioTracks;
TrackStatus _transparencyTrack;
public:
virtual AVIAudioTrack *createAudioTrack(AVIStreamHeader sHeader, PCMWaveFormat wvInfo);
/**
* Seek to a given frame.
*
* This only works when the video track(s) supports getFrameTime().
* This calls seek() internally.
*/
virtual bool seekToFrame(uint frame);
};
} // End of namespace Video
#endif
|