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

avi_decoder.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM 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/stream.h"
00024 #include "common/system.h"
00025 #include "common/textconsole.h"
00026 
00027 #include "audio/audiostream.h"
00028 #include "audio/mixer.h"
00029 
00030 #include "video/avi_decoder.h"
00031 
00032 // Audio Codecs
00033 #include "audio/decoders/adpcm.h"
00034 #include "audio/decoders/mp3.h"
00035 #include "audio/decoders/raw.h"
00036 
00037 // Video Codecs
00038 #include "image/codecs/codec.h"
00039 
00040 namespace Video {
00041 
00042 #define UNKNOWN_HEADER(a) error("Unknown header found -- \'%s\'", tag2str(a))
00043 
00044 // IDs used throughout the AVI files
00045 // that will be handled by this player
00046 #define ID_RIFF MKTAG('R','I','F','F')
00047 #define ID_AVI  MKTAG('A','V','I',' ')
00048 #define ID_LIST MKTAG('L','I','S','T')
00049 #define ID_HDRL MKTAG('h','d','r','l')
00050 #define ID_AVIH MKTAG('a','v','i','h')
00051 #define ID_STRL MKTAG('s','t','r','l')
00052 #define ID_STRH MKTAG('s','t','r','h')
00053 #define ID_VIDS MKTAG('v','i','d','s')
00054 #define ID_AUDS MKTAG('a','u','d','s')
00055 #define ID_MIDS MKTAG('m','i','d','s')
00056 #define ID_TXTS MKTAG('t','x','t','s')
00057 #define ID_JUNK MKTAG('J','U','N','K')
00058 #define ID_JUNQ MKTAG('J','U','N','Q')
00059 #define ID_DMLH MKTAG('d','m','l','h')
00060 #define ID_STRF MKTAG('s','t','r','f')
00061 #define ID_MOVI MKTAG('m','o','v','i')
00062 #define ID_REC  MKTAG('r','e','c',' ')
00063 #define ID_VEDT MKTAG('v','e','d','t')
00064 #define ID_IDX1 MKTAG('i','d','x','1')
00065 #define ID_STRD MKTAG('s','t','r','d')
00066 #define ID_INFO MKTAG('I','N','F','O')
00067 #define ID_ISFT MKTAG('I','S','F','T')
00068 #define ID_DISP MKTAG('D','I','S','P')
00069 #define ID_PRMI MKTAG('P','R','M','I')
00070 #define ID_STRN MKTAG('s','t','r','n')
00071 
00072 // Stream Types
00073 enum {
00074     kStreamTypePaletteChange = MKTAG16('p', 'c'),
00075     kStreamTypeAudio         = MKTAG16('w', 'b')
00076 };
00077 
00078 
00079 AVIDecoder::AVIDecoder() :
00080         _frameRateOverride(0) {
00081     initCommon();
00082 }
00083 
00084 AVIDecoder::AVIDecoder(const Common::Rational &frameRateOverride) :
00085         _frameRateOverride(frameRateOverride) {
00086     initCommon();
00087 }
00088 
00089 AVIDecoder::~AVIDecoder() {
00090     close();
00091 }
00092 
00093 AVIDecoder::AVIAudioTrack *AVIDecoder::createAudioTrack(AVIStreamHeader sHeader, PCMWaveFormat wvInfo) {
00094     return new AVIAudioTrack(sHeader, wvInfo, getSoundType());
00095 }
00096 
00097 bool AVIDecoder::seekToFrame(uint frame) {
00098     if (!isSeekable())
00099         return false;
00100 
00101     // If we didn't find a video track, we can't seek by frame (of course)
00102     if (_videoTracks.empty())
00103         return false;
00104 
00105     AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_videoTracks.front().track);
00106     Audio::Timestamp time = track->getFrameTime(frame);
00107 
00108     if (time < 0)
00109         return false;
00110 
00111     return seek(time);
00112 }
00113 
00114 void AVIDecoder::initCommon() {
00115     _decodedHeader = false;
00116     _foundMovieList = false;
00117     _movieListStart = 0;
00118     _movieListEnd = 0;
00119     _fileStream = 0;
00120     _videoTrackCounter = _audioTrackCounter = 0;
00121     _lastAddedTrack = nullptr;
00122     memset(&_header, 0, sizeof(_header));
00123     _transparencyTrack.track = nullptr;
00124 }
00125 
00126 bool AVIDecoder::isSeekable() const {
00127     // Only videos with an index can seek
00128     // Anyone else who wants to seek is crazy.
00129     return isVideoLoaded() && !_indexEntries.empty();
00130 }
00131 
00132 const Graphics::Surface *AVIDecoder::decodeNextFrame() {
00133     AVIVideoTrack *track = nullptr;
00134     bool isReversed = false;
00135     int frameNum = 0;
00136 
00137     // Check whether the video is playing in revese
00138     for (int idx = _videoTracks.size() - 1; idx >= 0; --idx) {
00139         track = static_cast<AVIVideoTrack *>(_videoTracks[idx].track);
00140         isReversed |= track->isReversed();
00141     }
00142 
00143     if (isReversed) {
00144         // For reverse mode we need to keep seeking to just before the
00145         // desired frame prior to actually decoding a frame
00146         frameNum = getCurFrame();
00147         seekIntern(track->getFrameTime(frameNum));
00148     }
00149 
00150     // Decode the next frame
00151     const Graphics::Surface *frame = VideoDecoder::decodeNextFrame();
00152 
00153     if (isReversed) {
00154         // In reverse mode, set next frame to be the prior frame number
00155         for (int idx = _videoTracks.size() - 1; idx >= 0; --idx) {
00156             track = static_cast<AVIVideoTrack *>(_videoTracks[idx].track);
00157             track->setCurFrame(frameNum - 1);
00158             findNextVideoTrack();
00159         }
00160     }
00161 
00162     return frame;
00163 }
00164 
00165 const Graphics::Surface *AVIDecoder::decodeNextTransparency() {
00166     if (!_transparencyTrack.track)
00167         return nullptr;
00168 
00169     AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_transparencyTrack.track);
00170     return track->decodeNextFrame();
00171 }
00172 
00173 bool AVIDecoder::parseNextChunk() {
00174     uint32 tag = _fileStream->readUint32BE();
00175     uint32 size = _fileStream->readUint32LE();
00176 
00177     if (_fileStream->eos())
00178         return false;
00179 
00180     debug(6, "Decoding tag %s", tag2str(tag));
00181 
00182     switch (tag) {
00183     case ID_LIST:
00184         handleList(size);
00185         break;
00186     case ID_AVIH:
00187         _header.size = size;
00188         _header.microSecondsPerFrame = _fileStream->readUint32LE();
00189         _header.maxBytesPerSecond = _fileStream->readUint32LE();
00190         _header.padding = _fileStream->readUint32LE();
00191         _header.flags = _fileStream->readUint32LE();
00192         _header.totalFrames = _fileStream->readUint32LE();
00193         _header.initialFrames = _fileStream->readUint32LE();
00194         _header.streams = _fileStream->readUint32LE();
00195         _header.bufferSize = _fileStream->readUint32LE();
00196         _header.width = _fileStream->readUint32LE();
00197         _header.height = _fileStream->readUint32LE();
00198         // Ignore 16 bytes of reserved data
00199         _fileStream->skip(16);
00200         break;
00201     case ID_STRH:
00202         handleStreamHeader(size);
00203         break;
00204     case ID_HDRL: // Header list.. what's it doing here? Probably ok to ignore?
00205     case ID_STRD: // Extra stream info, safe to ignore
00206     case ID_VEDT: // Unknown, safe to ignore
00207     case ID_JUNK: // Alignment bytes, should be ignored
00208     case ID_JUNQ: // Same as JUNK, safe to ignore
00209     case ID_ISFT: // Metadata, safe to ignore
00210     case ID_DISP: // Metadata, should be safe to ignore
00211     case ID_DMLH: // OpenDML extension, contains an extra total frames field, safe to ignore
00212         skipChunk(size);
00213         break;
00214     case ID_STRN: // Metadata, safe to ignore
00215         readStreamName(size);
00216         break;
00217     case ID_IDX1:
00218         readOldIndex(size);
00219         break;
00220     default:
00221         error("Unknown tag \'%s\' found", tag2str(tag));
00222     }
00223 
00224     return true;
00225 }
00226 
00227 void AVIDecoder::skipChunk(uint32 size) {
00228     // Make sure we're aligned on a word boundary
00229     _fileStream->skip(size + (size & 1));
00230 }
00231 
00232 void AVIDecoder::handleList(uint32 listSize) {
00233     uint32 listType = _fileStream->readUint32BE();
00234     listSize -= 4; // Subtract away listType's 4 bytes
00235     uint32 curPos = _fileStream->pos();
00236 
00237     debug(7, "Found LIST of type %s", tag2str(listType));
00238 
00239     switch (listType) {
00240     case ID_MOVI: // Movie List
00241         // We found the movie block
00242         _foundMovieList = true;
00243         _movieListStart = curPos;
00244         _movieListEnd = _movieListStart + listSize + (listSize & 1);
00245         _fileStream->skip(listSize);
00246         return;
00247     case ID_HDRL: // Header List
00248         // Mark the header as decoded
00249         _decodedHeader = true;
00250         break;
00251     case ID_INFO: // Metadata
00252     case ID_PRMI: // Adobe Premiere metadata, safe to ignore
00253         // Ignore metadata
00254         _fileStream->skip(listSize);
00255         return;
00256     case ID_STRL: // Stream list
00257     default:      // (Just hope we can parse it!)
00258         break;
00259     }
00260 
00261     while ((_fileStream->pos() - curPos) < listSize)
00262         parseNextChunk();
00263 }
00264 
00265 void AVIDecoder::handleStreamHeader(uint32 size) {
00266     AVIStreamHeader sHeader;
00267     sHeader.size = size;
00268     sHeader.streamType = _fileStream->readUint32BE();
00269 
00270     if (sHeader.streamType == ID_MIDS)
00271         error("Unhandled MIDI/Text stream");
00272 
00273     if (sHeader.streamType == ID_TXTS)
00274         warning("Unsupported Text stream detected");
00275 
00276     sHeader.streamHandler = _fileStream->readUint32BE();
00277     sHeader.flags = _fileStream->readUint32LE();
00278     sHeader.priority = _fileStream->readUint16LE();
00279     sHeader.language = _fileStream->readUint16LE();
00280     sHeader.initialFrames = _fileStream->readUint32LE();
00281     sHeader.scale = _fileStream->readUint32LE();
00282     sHeader.rate = _fileStream->readUint32LE();
00283     sHeader.start = _fileStream->readUint32LE();
00284     sHeader.length = _fileStream->readUint32LE();
00285     sHeader.bufferSize = _fileStream->readUint32LE();
00286     sHeader.quality = _fileStream->readUint32LE();
00287     sHeader.sampleSize = _fileStream->readUint32LE();
00288 
00289     _fileStream->skip(sHeader.size - 48); // Skip over the remainder of the chunk (frame)
00290 
00291     if (_fileStream->readUint32BE() != ID_STRF)
00292         error("Could not find STRF tag");
00293 
00294     uint32 strfSize = _fileStream->readUint32LE();
00295     uint32 startPos = _fileStream->pos();
00296 
00297     if (sHeader.streamType == ID_VIDS) {
00298         if (_frameRateOverride != 0) {
00299             sHeader.rate = _frameRateOverride.getNumerator();
00300             sHeader.scale = _frameRateOverride.getDenominator();
00301         }
00302 
00303         BitmapInfoHeader bmInfo;
00304         bmInfo.size = _fileStream->readUint32LE();
00305         bmInfo.width = _fileStream->readUint32LE();
00306         bmInfo.height = _fileStream->readUint32LE();
00307         bmInfo.planes = _fileStream->readUint16LE();
00308         bmInfo.bitCount = _fileStream->readUint16LE();
00309         bmInfo.compression = _fileStream->readUint32BE();
00310         bmInfo.sizeImage = _fileStream->readUint32LE();
00311         bmInfo.xPelsPerMeter = _fileStream->readUint32LE();
00312         bmInfo.yPelsPerMeter = _fileStream->readUint32LE();
00313         bmInfo.clrUsed = _fileStream->readUint32LE();
00314         bmInfo.clrImportant = _fileStream->readUint32LE();
00315 
00316         if (bmInfo.clrUsed == 0)
00317             bmInfo.clrUsed = 256;
00318 
00319         byte *initialPalette = 0;
00320 
00321         if (bmInfo.bitCount == 8) {
00322             initialPalette = new byte[256 * 3];
00323             memset(initialPalette, 0, 256 * 3);
00324 
00325             byte *palette = initialPalette;
00326             for (uint32 i = 0; i < bmInfo.clrUsed; i++) {
00327                 palette[i * 3 + 2] = _fileStream->readByte();
00328                 palette[i * 3 + 1] = _fileStream->readByte();
00329                 palette[i * 3] = _fileStream->readByte();
00330                 _fileStream->readByte();
00331             }
00332         }
00333 
00334         addTrack(new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo, initialPalette));
00335     } else if (sHeader.streamType == ID_AUDS) {
00336         PCMWaveFormat wvInfo;
00337         wvInfo.tag = _fileStream->readUint16LE();
00338         wvInfo.channels = _fileStream->readUint16LE();
00339         wvInfo.samplesPerSec = _fileStream->readUint32LE();
00340         wvInfo.avgBytesPerSec = _fileStream->readUint32LE();
00341         wvInfo.blockAlign = _fileStream->readUint16LE();
00342         wvInfo.size = _fileStream->readUint16LE();
00343 
00344         // AVI seems to treat the sampleSize as including the second
00345         // channel as well, so divide for our sake.
00346         if (wvInfo.channels == 2)
00347             sHeader.sampleSize /= 2;
00348 
00349         AVIAudioTrack *track = createAudioTrack(sHeader, wvInfo);
00350         track->createAudioStream();
00351         addTrack(track);
00352     }
00353 
00354     // Ensure that we're at the end of the chunk
00355     _fileStream->seek(startPos + strfSize);
00356 }
00357 
00358 void AVIDecoder::addTrack(Track *track, bool isExternal) {
00359     VideoDecoder::addTrack(track, isExternal);
00360     _lastAddedTrack = track;
00361 }
00362 
00363 void AVIDecoder::readStreamName(uint32 size) {
00364     if (!_lastAddedTrack) {
00365         skipChunk(size);
00366     } else {
00367         // Get in the name
00368         assert(size > 0 && size < 64);
00369         char buffer[64];
00370         _fileStream->read(buffer, size);
00371         if (size & 1)
00372             _fileStream->skip(1);
00373 
00374         // Apply it to the most recently read stream
00375         assert(_lastAddedTrack);
00376         AVIVideoTrack *vidTrack = dynamic_cast<AVIVideoTrack *>(_lastAddedTrack);
00377         AVIAudioTrack *audTrack = dynamic_cast<AVIAudioTrack *>(_lastAddedTrack);
00378         if (vidTrack)
00379             vidTrack->getName() = Common::String(buffer);
00380         else if (audTrack)
00381             audTrack->getName() = Common::String(buffer);
00382     }
00383 }
00384 
00385 bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) {
00386     close();
00387 
00388     uint32 riffTag = stream->readUint32BE();
00389     if (riffTag != ID_RIFF) {
00390         warning("Failed to find RIFF header");
00391         return false;
00392     }
00393 
00394     int32 fileSize = stream->readUint32LE();
00395     uint32 riffType = stream->readUint32BE();
00396 
00397     if (riffType != ID_AVI) {
00398         warning("RIFF not an AVI file");
00399         return false;
00400     }
00401 
00402     _fileStream = stream;
00403 
00404     // Go through all chunks in the file
00405     while (_fileStream->pos() < fileSize && parseNextChunk())
00406         ;
00407 
00408     if (!_decodedHeader) {
00409         warning("Failed to parse AVI header");
00410         close();
00411         return false;
00412     }
00413 
00414     if (!_foundMovieList) {
00415         warning("Failed to find 'MOVI' list");
00416         close();
00417         return false;
00418     }
00419 
00420     // Create the status entries
00421     uint32 index = 0;
00422     for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, index++) {
00423         TrackStatus status;
00424         status.track = *it;
00425         status.index = index;
00426         status.chunkSearchOffset = _movieListStart;
00427 
00428         if ((*it)->getTrackType() == Track::kTrackTypeAudio) {
00429             _audioTracks.push_back(status);
00430         } else if (_videoTracks.empty()) {
00431             _videoTracks.push_back(status);
00432         } else {
00433             // Secondary video track. For now we assume it will always be a
00434             // transparency information track
00435             status.chunkSearchOffset = getVideoTrackOffset(index);
00436             assert(!_transparencyTrack.track);
00437             assert(status.chunkSearchOffset != 0);
00438 
00439             // Copy the track status information into the transparency track field
00440             _transparencyTrack = status;
00441         }
00442     }
00443 
00444     // If there is a transparency track, remove it from the video decoder's track list.
00445     // This is to stop it being included in calls like getFrameCount
00446     if (_transparencyTrack.track)
00447         eraseTrack(_transparencyTrack.track);
00448 
00449     // Check if this is a special Duck Truemotion video
00450     checkTruemotion1();
00451 
00452     return true;
00453 }
00454 
00455 void AVIDecoder::close() {
00456     VideoDecoder::close();
00457 
00458     delete _fileStream;
00459     _fileStream = 0;
00460     _decodedHeader = false;
00461     _foundMovieList = false;
00462     _movieListStart = 0;
00463     _movieListEnd = 0;
00464 
00465     _indexEntries.clear();
00466     memset(&_header, 0, sizeof(_header));
00467 
00468     _videoTracks.clear();
00469     _audioTracks.clear();
00470 
00471     delete _transparencyTrack.track;
00472     _transparencyTrack.track = nullptr;
00473 }
00474 
00475 void AVIDecoder::readNextPacket() {
00476     // Shouldn't get this unless called on a non-open video
00477     if (_videoTracks.empty())
00478         return;
00479 
00480     // Handle the video first
00481     for (uint idx = 0; idx < _videoTracks.size(); ++idx)
00482         handleNextPacket(_videoTracks[idx]);
00483 
00484     // Handle any transparency track
00485     if (_transparencyTrack.track)
00486         handleNextPacket(_transparencyTrack);
00487 
00488     // Handle audio tracks next
00489     for (uint idx = 0; idx < _audioTracks.size(); ++idx)
00490         handleNextPacket(_audioTracks[idx]);
00491 }
00492 
00493 void AVIDecoder::handleNextPacket(TrackStatus &status) {
00494     // If there's no more to search, bail out
00495     if (status.chunkSearchOffset + 8 >= _movieListEnd) {
00496         if (status.track->getTrackType() == Track::kTrackTypeVideo) {
00497             // Horrible AVI video has a premature end
00498             // Force the frame to be the last frame
00499             debug(7, "Forcing end of AVI video");
00500             ((AVIVideoTrack *)status.track)->forceTrackEnd();
00501         }
00502 
00503         return;
00504     }
00505 
00506     // See if audio needs to be buffered and break out if not
00507     if (status.track->getTrackType() == Track::kTrackTypeAudio && !shouldQueueAudio(status))
00508         return;
00509 
00510     // Seek to where we shall start searching
00511     _fileStream->seek(status.chunkSearchOffset);
00512     bool isReversed = false;
00513     AVIVideoTrack *videoTrack = nullptr;
00514 
00515     for (;;) {
00516         // If there's no more to search, bail out
00517         if ((uint32)_fileStream->pos() + 8 >= _movieListEnd) {
00518             if (status.track->getTrackType() == Track::kTrackTypeVideo) {
00519                 // Horrible AVI video has a premature end
00520                 // Force the frame to be the last frame
00521                 debug(7, "Forcing end of AVI video");
00522                 ((AVIVideoTrack *)status.track)->forceTrackEnd();
00523             }
00524 
00525             break;
00526         }
00527 
00528         uint32 nextTag = _fileStream->readUint32BE();
00529         uint32 size = _fileStream->readUint32LE();
00530 
00531         if (nextTag == ID_LIST) {
00532             // A list of audio/video chunks
00533             if (_fileStream->readUint32BE() != ID_REC)
00534                 error("Expected 'rec ' LIST");
00535 
00536             continue;
00537         } else if (nextTag == ID_JUNK || nextTag == ID_IDX1) {
00538             skipChunk(size);
00539             continue;
00540         }
00541 
00542         // Only accept chunks for this stream
00543         uint32 streamIndex = getStreamIndex(nextTag);
00544         if (streamIndex != status.index) {
00545             skipChunk(size);
00546             continue;
00547         }
00548 
00549         Common::SeekableReadStream *chunk = 0;
00550 
00551         if (size != 0) {
00552             chunk = _fileStream->readStream(size);
00553             _fileStream->skip(size & 1);
00554         }
00555 
00556         if (status.track->getTrackType() == Track::kTrackTypeAudio) {
00557             if (getStreamType(nextTag) != kStreamTypeAudio)
00558                 error("Invalid audio track tag '%s'", tag2str(nextTag));
00559 
00560             assert(chunk);
00561             ((AVIAudioTrack *)status.track)->queueSound(chunk);
00562 
00563             // Break out if we have enough audio
00564             if (!shouldQueueAudio(status))
00565                 break;
00566         } else {
00567             videoTrack = (AVIVideoTrack *)status.track;
00568             isReversed = videoTrack->isReversed();
00569 
00570             if (getStreamType(nextTag) == kStreamTypePaletteChange) {
00571                 // Palette Change
00572                 videoTrack->loadPaletteFromChunk(chunk);
00573             } else {
00574                 // Otherwise, assume it's a compressed frame
00575                 videoTrack->decodeFrame(chunk);
00576                 break;
00577             }
00578         }
00579     }
00580 
00581     if (!isReversed) {
00582         // Start us off in this position next time
00583         status.chunkSearchOffset = _fileStream->pos();
00584     }
00585 }
00586 
00587 bool AVIDecoder::shouldQueueAudio(TrackStatus& status) {
00588     // Sanity check:
00589     if (status.track->getTrackType() != Track::kTrackTypeAudio)
00590         return false;
00591 
00592     // If video is done, make sure that the rest of the audio is queued
00593     // (I guess this is also really a sanity check)
00594     AVIVideoTrack *videoTrack = (AVIVideoTrack *)_videoTracks[0].track;
00595     if (videoTrack->endOfTrack())
00596         return true;
00597 
00598     // Being three frames ahead should be enough for any video.
00599     return ((AVIAudioTrack *)status.track)->getCurChunk() < (uint32)(videoTrack->getCurFrame() + 3);
00600 }
00601 
00602 bool AVIDecoder::rewind() {
00603     if (!VideoDecoder::rewind())
00604         return false;
00605 
00606     for (uint32 i = 0; i < _videoTracks.size(); i++)
00607         _videoTracks[i].chunkSearchOffset = getVideoTrackOffset(_videoTracks[i].index);
00608 
00609     for (uint32 i = 0; i < _audioTracks.size(); i++)
00610         _audioTracks[i].chunkSearchOffset = _movieListStart;
00611 
00612     return true;
00613 }
00614 
00615 uint AVIDecoder::getVideoTrackOffset(uint trackIndex, uint frameNumber) {
00616     if (trackIndex == _videoTracks.front().index && frameNumber == 0)
00617         return _movieListStart;
00618 
00619     OldIndex *entry = _indexEntries.find(trackIndex, frameNumber);
00620     assert(entry);
00621     return entry->offset;
00622 }
00623 
00624 bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
00625     uint frame;
00626 
00627     // Can't seek beyond the end
00628     if (time > getDuration())
00629         return false;
00630 
00631     // Get our video
00632     AVIVideoTrack *videoTrack = (AVIVideoTrack *)_videoTracks[0].track;
00633     uint32 videoIndex = _videoTracks[0].index;
00634 
00635     if (time == getDuration()) {
00636         videoTrack->setCurFrame(videoTrack->getFrameCount() - 1);
00637 
00638         if (!videoTrack->isReversed()) {
00639             // Since we're at the end, just mark the tracks as over
00640             for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++)
00641                 if ((*it)->getTrackType() == Track::kTrackTypeAudio)
00642                     ((AVIAudioTrack *)*it)->resetStream();
00643 
00644             return true;
00645         }
00646 
00647         frame = videoTrack->getFrameCount() - 1;
00648     } else {
00649         // Get the frame we should be on at this time
00650         frame = videoTrack->getFrameAtTime(time);
00651     }
00652 
00653     // Reset any palette, if necessary
00654     videoTrack->useInitialPalette();
00655 
00656     int lastKeyFrame = -1;
00657     int frameIndex = -1;
00658     uint curFrame = 0;
00659 
00660     // Go through and figure out where we should be
00661     // If there's a palette, we need to find the palette too
00662     for (uint32 i = 0; i < _indexEntries.size(); i++) {
00663         const OldIndex &index = _indexEntries[i];
00664 
00665         // We don't care about RECs
00666         if (index.id == ID_REC)
00667             continue;
00668 
00669         // We're only looking at entries for this track
00670         if (getStreamIndex(index.id) != videoIndex)
00671             continue;
00672 
00673         uint16 streamType = getStreamType(index.id);
00674 
00675         if (streamType == kStreamTypePaletteChange) {
00676             // We need to handle any palette change we see since there's no
00677             // flag to tell if this is a "key" palette.
00678             // Decode the palette
00679             _fileStream->seek(_indexEntries[i].offset + 8);
00680             Common::SeekableReadStream *chunk = 0;
00681 
00682             if (_indexEntries[i].size != 0)
00683                 chunk = _fileStream->readStream(_indexEntries[i].size);
00684 
00685             videoTrack->loadPaletteFromChunk(chunk);
00686         } else {
00687             // Check to see if this is a keyframe
00688             // The first frame has to be a keyframe
00689             if ((_indexEntries[i].flags & AVIIF_INDEX) || curFrame == 0)
00690                 lastKeyFrame = i;
00691 
00692             // Did we find the target frame?
00693             if (frame == curFrame) {
00694                 frameIndex = i;
00695                 break;
00696             }
00697 
00698             curFrame++;
00699         }
00700     }
00701 
00702     if (frameIndex < 0) // This shouldn't happen.
00703         return false;
00704 
00705     // Update all the audio tracks
00706     for (uint32 i = 0; i < _audioTracks.size(); i++) {
00707         AVIAudioTrack *audioTrack = (AVIAudioTrack *)_audioTracks[i].track;
00708 
00709         // Recreate the audio stream
00710         audioTrack->resetStream();
00711 
00712         // Set the chunk index for the track
00713         audioTrack->setCurChunk(frame);
00714 
00715         uint32 chunksFound = 0;
00716         for (uint32 j = 0; j < _indexEntries.size(); j++) {
00717             const OldIndex &index = _indexEntries[j];
00718 
00719             // Continue ignoring RECs
00720             if (index.id == ID_REC)
00721                 continue;
00722 
00723             if (getStreamIndex(index.id) == _audioTracks[i].index) {
00724                 if (chunksFound == frame) {
00725                     _fileStream->seek(index.offset + 8);
00726                     Common::SeekableReadStream *audioChunk = _fileStream->readStream(index.size);
00727                     audioTrack->queueSound(audioChunk);
00728                     _audioTracks[i].chunkSearchOffset = (j == _indexEntries.size() - 1) ? _movieListEnd : _indexEntries[j + 1].offset;
00729                     break;
00730                 }
00731 
00732                 chunksFound++;
00733             }
00734         }
00735 
00736         // Skip any audio to bring us to the right time
00737         audioTrack->skipAudio(time, videoTrack->getFrameTime(frame));
00738     }
00739 
00740     // Decode from keyFrame to curFrame - 1
00741     for (int i = lastKeyFrame; i < frameIndex; i++) {
00742         if (_indexEntries[i].id == ID_REC)
00743             continue;
00744 
00745         if (getStreamIndex(_indexEntries[i].id) != videoIndex)
00746             continue;
00747 
00748         uint16 streamType = getStreamType(_indexEntries[i].id);
00749 
00750         // Ignore palettes, they were already handled
00751         if (streamType == kStreamTypePaletteChange)
00752             continue;
00753 
00754         // Frame, hopefully
00755         _fileStream->seek(_indexEntries[i].offset + 8);
00756         Common::SeekableReadStream *chunk = 0;
00757 
00758         if (_indexEntries[i].size != 0)
00759             chunk = _fileStream->readStream(_indexEntries[i].size);
00760 
00761         videoTrack->decodeFrame(chunk);
00762     }
00763 
00764     // Update any transparency track if present
00765     if (_transparencyTrack.track)
00766         seekTransparencyFrame(frame);
00767 
00768     // Set the video track's frame
00769     videoTrack->setCurFrame(frame - 1);
00770 
00771     // Set the video track's search offset to the right spot
00772     _videoTracks[0].chunkSearchOffset = _indexEntries[frameIndex].offset;
00773     return true;
00774 }
00775 
00776 void AVIDecoder::seekTransparencyFrame(int frame) {
00777     TrackStatus &status = _transparencyTrack;
00778     AVIVideoTrack *transTrack = static_cast<AVIVideoTrack *>(status.track);
00779 
00780     // Find the index entry for the frame
00781     int indexFrame = frame;
00782     OldIndex *entry = nullptr;
00783     do {
00784         entry = _indexEntries.find(status.index, indexFrame);
00785     } while (!entry && indexFrame-- > 0);
00786     assert(entry);
00787 
00788     // Set it's frame number
00789     transTrack->setCurFrame(indexFrame - 1);
00790 
00791     // Read in the frame
00792     Common::SeekableReadStream *chunk = nullptr;
00793     _fileStream->seek(entry->offset + 8);
00794     status.chunkSearchOffset = entry->offset;
00795 
00796     if (entry->size != 0)
00797         chunk = _fileStream->readStream(entry->size);
00798     transTrack->decodeFrame(chunk);
00799 
00800     if (indexFrame < (int)frame) {
00801         while (status.chunkSearchOffset < _movieListEnd && indexFrame++ < (int)frame) {
00802             // There was no index entry for the desired frame, so an earlier one was decoded.
00803             // We now have to sequentially skip frames until we get to the desired frame
00804             _fileStream->readUint32BE();
00805             uint32 size = _fileStream->readUint32LE() - 8;
00806             _fileStream->skip(size & 1);
00807             status.chunkSearchOffset = _fileStream->pos();
00808         }
00809     }
00810 
00811     transTrack->setCurFrame(frame - 1);
00812 }
00813 
00814 byte AVIDecoder::getStreamIndex(uint32 tag) {
00815     char string[3];
00816     WRITE_BE_UINT16(string, tag >> 16);
00817     string[2] = 0;
00818     return strtol(string, 0, 16);
00819 }
00820 
00821 void AVIDecoder::readOldIndex(uint32 size) {
00822     uint32 entryCount = size / 16;
00823 
00824     debug(7, "Old Index: %d entries", entryCount);
00825 
00826     if (entryCount == 0)
00827         return;
00828 
00829     // Read the first index separately
00830     OldIndex firstEntry;
00831     firstEntry.id = _fileStream->readUint32BE();
00832     firstEntry.flags = _fileStream->readUint32LE();
00833     firstEntry.offset = _fileStream->readUint32LE();
00834     firstEntry.size = _fileStream->readUint32LE();
00835 
00836     // Check if the offset is already absolute
00837     // If it's absolute, the offset will equal the start of the movie list
00838     bool isAbsolute = firstEntry.offset == _movieListStart;
00839 
00840     debug(6, "Old index is %s", isAbsolute ? "absolute" : "relative");
00841 
00842     if (!isAbsolute)
00843         firstEntry.offset += _movieListStart - 4;
00844 
00845     debug(7, "Index 0: Tag '%s', Offset = %d, Size = %d (Flags = %d)", tag2str(firstEntry.id), firstEntry.offset, firstEntry.size, firstEntry.flags);
00846     _indexEntries.push_back(firstEntry);
00847 
00848     for (uint32 i = 1; i < entryCount; i++) {
00849         OldIndex indexEntry;
00850         indexEntry.id = _fileStream->readUint32BE();
00851         indexEntry.flags = _fileStream->readUint32LE();
00852         indexEntry.offset = _fileStream->readUint32LE();
00853         indexEntry.size = _fileStream->readUint32LE();
00854 
00855         // Adjust to absolute, if necessary
00856         if (!isAbsolute)
00857             indexEntry.offset += _movieListStart - 4;
00858 
00859         _indexEntries.push_back(indexEntry);
00860         debug(7, "Index %d: Tag '%s', Offset = %d, Size = %d (Flags = %d)", i, tag2str(indexEntry.id), indexEntry.offset, indexEntry.size, indexEntry.flags);
00861     }
00862 }
00863 
00864 void AVIDecoder::checkTruemotion1() {
00865     // If we got here from loadStream(), we know the track is valid
00866     assert(!_videoTracks.empty());
00867 
00868     TrackStatus &status = _videoTracks[0];
00869     AVIVideoTrack *track = (AVIVideoTrack *)status.track;
00870 
00871     // Ignore non-truemotion tracks
00872     if (!track->isTruemotion1())
00873         return;
00874 
00875     // Read the next video packet
00876     handleNextPacket(status);
00877 
00878     const Graphics::Surface *frame = track->decodeNextFrame();
00879     if (!frame) {
00880         rewind();
00881         return;
00882     }
00883 
00884     // Fill in the width/height based on the frame's width/height
00885     _header.width = frame->w;
00886     _header.height = frame->h;
00887     track->forceDimensions(frame->w, frame->h);
00888 
00889     // Rewind us back to the beginning
00890     rewind();
00891 }
00892 
00893 VideoDecoder::AudioTrack *AVIDecoder::getAudioTrack(int index) {
00894     // AVI audio track indexes are relative to the first track
00895     Track *track = getTrack(index);
00896 
00897     if (!track || track->getTrackType() != Track::kTrackTypeAudio)
00898         return 0;
00899 
00900     return (AudioTrack *)track;
00901 }
00902 
00903 AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader, byte *initialPalette)
00904         : _frameCount(frameCount), _vidsHeader(streamHeader), _bmInfo(bitmapInfoHeader), _initialPalette(initialPalette) {
00905     _videoCodec = createCodec();
00906     _lastFrame = 0;
00907     _curFrame = -1;
00908     _reversed = false;
00909 
00910     useInitialPalette();
00911 }
00912 
00913 AVIDecoder::AVIVideoTrack::~AVIVideoTrack() {
00914     delete _videoCodec;
00915     delete[] _initialPalette;
00916 }
00917 
00918 void AVIDecoder::AVIVideoTrack::decodeFrame(Common::SeekableReadStream *stream) {
00919     if (stream) {
00920         if (_videoCodec)
00921             _lastFrame = _videoCodec->decodeFrame(*stream);
00922     } else {
00923         // Empty frame
00924         _lastFrame = 0;
00925     }
00926 
00927     delete stream;
00928 
00929     if (!_reversed) {
00930         _curFrame++;
00931     } else {
00932         _curFrame--;
00933     }
00934 }
00935 
00936 Graphics::PixelFormat AVIDecoder::AVIVideoTrack::getPixelFormat() const {
00937     if (_videoCodec)
00938         return _videoCodec->getPixelFormat();
00939 
00940     return Graphics::PixelFormat();
00941 }
00942 
00943 void AVIDecoder::AVIVideoTrack::loadPaletteFromChunk(Common::SeekableReadStream *chunk) {
00944     assert(chunk);
00945     byte firstEntry = chunk->readByte();
00946     uint16 numEntries = chunk->readByte();
00947     chunk->readUint16LE(); // Reserved
00948 
00949     // 0 entries means all colors are going to be changed
00950     if (numEntries == 0)
00951         numEntries = 256;
00952 
00953     for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) {
00954         _palette[i * 3] = chunk->readByte();
00955         _palette[i * 3 + 1] = chunk->readByte();
00956         _palette[i * 3 + 2] = chunk->readByte();
00957         chunk->readByte(); // Flags that don't serve us any purpose
00958     }
00959 
00960     delete chunk;
00961     _dirtyPalette = true;
00962 }
00963 
00964 void AVIDecoder::AVIVideoTrack::useInitialPalette() {
00965     _dirtyPalette = false;
00966 
00967     if (_initialPalette) {
00968         memcpy(_palette, _initialPalette, sizeof(_palette));
00969         _dirtyPalette = true;
00970     }
00971 }
00972 
00973 bool AVIDecoder::AVIVideoTrack::isTruemotion1() const {
00974     return _bmInfo.compression == MKTAG('D', 'U', 'C', 'K') || _bmInfo.compression == MKTAG('d', 'u', 'c', 'k');
00975 }
00976 
00977 void AVIDecoder::AVIVideoTrack::forceDimensions(uint16 width, uint16 height) {
00978     _bmInfo.width = width;
00979     _bmInfo.height = height;
00980 }
00981 
00982 bool AVIDecoder::AVIVideoTrack::rewind() {
00983     _curFrame = -1;
00984 
00985     useInitialPalette();
00986 
00987     delete _videoCodec;
00988     _videoCodec = createCodec();
00989     _lastFrame = 0;
00990     return true;
00991 }
00992 
00993 Image::Codec *AVIDecoder::AVIVideoTrack::createCodec() {
00994     return Image::createBitmapCodec(_bmInfo.compression, _vidsHeader.streamHandler, _bmInfo.width,
00995                                     _bmInfo.height, _bmInfo.bitCount);
00996 }
00997 
00998 void AVIDecoder::AVIVideoTrack::forceTrackEnd() {
00999     _curFrame = _frameCount - 1;
01000 }
01001 
01002 const byte *AVIDecoder::AVIVideoTrack::getPalette() const {
01003     if (_videoCodec && _videoCodec->containsPalette())
01004         return _videoCodec->getPalette();
01005 
01006     _dirtyPalette = false;
01007     return _palette;
01008 }
01009 
01010 bool AVIDecoder::AVIVideoTrack::hasDirtyPalette() const {
01011     if (_videoCodec && _videoCodec->containsPalette())
01012         return _videoCodec->hasDirtyPalette();
01013 
01014     return _dirtyPalette;
01015 }
01016 
01017 bool AVIDecoder::AVIVideoTrack::setReverse(bool reverse) {
01018     if (isRewindable()) {
01019         // Track is rewindable, so reversing is allowed
01020         _reversed = reverse;
01021         return true;
01022     }
01023 
01024     return !reverse;
01025 }
01026 
01027 bool AVIDecoder::AVIVideoTrack::endOfTrack() const {
01028     if (_reversed)
01029         return _curFrame < -1;
01030 
01031     return _curFrame >= (getFrameCount() - 1);
01032 }
01033 
01034 bool AVIDecoder::AVIVideoTrack::canDither() const {
01035     return _videoCodec && _videoCodec->canDither(Image::Codec::kDitherTypeVFW);
01036 }
01037 
01038 void AVIDecoder::AVIVideoTrack::setDither(const byte *palette) {
01039     assert(_videoCodec);
01040     _videoCodec->setDither(Image::Codec::kDitherTypeVFW, palette);
01041 }
01042 
01043 AVIDecoder::AVIAudioTrack::AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType) :
01044         AudioTrack(soundType),
01045         _audsHeader(streamHeader),
01046         _wvInfo(waveFormat),
01047         _audioStream(0),
01048         _packetStream(0),
01049         _curChunk(0) {
01050 }
01051 
01052 AVIDecoder::AVIAudioTrack::~AVIAudioTrack() {
01053     delete _audioStream;
01054 }
01055 
01056 void AVIDecoder::AVIAudioTrack::queueSound(Common::SeekableReadStream *stream) {
01057     if (_packetStream)
01058         _packetStream->queuePacket(stream);
01059     else
01060         delete stream;
01061 
01062     _curChunk++;
01063 }
01064 
01065 void AVIDecoder::AVIAudioTrack::skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime) {
01066     Audio::Timestamp timeDiff = time.convertToFramerate(_wvInfo.samplesPerSec) - frameTime.convertToFramerate(_wvInfo.samplesPerSec);
01067     int skipFrames = timeDiff.totalNumberOfFrames();
01068 
01069     if (skipFrames <= 0)
01070         return;
01071 
01072     Audio::AudioStream *audioStream = getAudioStream();
01073     if (!audioStream)
01074         return;
01075 
01076     if (audioStream->isStereo())
01077         skipFrames *= 2;
01078 
01079     int16 *tempBuffer = new int16[skipFrames];
01080     audioStream->readBuffer(tempBuffer, skipFrames);
01081     delete[] tempBuffer;
01082 }
01083 
01084 void AVIDecoder::AVIAudioTrack::resetStream() {
01085     delete _audioStream;
01086     createAudioStream();
01087     _curChunk = 0;
01088 }
01089 
01090 bool AVIDecoder::AVIAudioTrack::rewind() {
01091     resetStream();
01092     return true;
01093 }
01094 
01095 void AVIDecoder::AVIAudioTrack::createAudioStream() {
01096     _packetStream = 0;
01097 
01098     switch (_wvInfo.tag) {
01099     case kWaveFormatPCM: {
01100         byte flags = 0;
01101         if (_audsHeader.sampleSize == 2)
01102             flags |= Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
01103         else
01104             flags |= Audio::FLAG_UNSIGNED;
01105 
01106         if (_wvInfo.channels == 2)
01107             flags |= Audio::FLAG_STEREO;
01108 
01109         _packetStream = Audio::makePacketizedRawStream(_wvInfo.samplesPerSec, flags);
01110         break;
01111     }
01112     case kWaveFormatMSADPCM:
01113         _packetStream = Audio::makePacketizedADPCMStream(Audio::kADPCMMS, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign);
01114         break;
01115     case kWaveFormatMSIMAADPCM:
01116         _packetStream = Audio::makePacketizedADPCMStream(Audio::kADPCMMSIma, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign);
01117         break;
01118     case kWaveFormatDK3:
01119         _packetStream = Audio::makePacketizedADPCMStream(Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign);
01120         break;
01121     case kWaveFormatMP3:
01122 #ifdef USE_MAD
01123         _packetStream = Audio::makePacketizedMP3Stream(_wvInfo.channels, _wvInfo.samplesPerSec);
01124 #else
01125         warning("AVI MP3 stream found, but no libmad support compiled in");
01126 #endif
01127         break;
01128     case kWaveFormatNone:
01129         break;
01130     default:
01131         warning("Unsupported AVI audio format %d", _wvInfo.tag);
01132         break;
01133     }
01134 
01135     if (_packetStream)
01136         _audioStream = _packetStream;
01137     else
01138         _audioStream = Audio::makeNullAudioStream();
01139 }
01140 
01141 AVIDecoder::TrackStatus::TrackStatus() : track(0), chunkSearchOffset(0) {
01142 }
01143 
01144 AVIDecoder::OldIndex *AVIDecoder::IndexEntries::find(uint index, uint frameNumber) {
01145     for (uint idx = 0, frameCtr = 0; idx < size(); ++idx) {
01146         if ((*this)[idx].id != ID_REC &&
01147                 AVIDecoder::getStreamIndex((*this)[idx].id) == index) {
01148             if (frameCtr++ == frameNumber)
01149                 return &(*this)[idx];
01150         }
01151     }
01152 
01153     return nullptr;
01154 }
01155 
01156 } // End of namespace Video


Generated on Sat Jul 4 2020 05:01:42 for ResidualVM by doxygen 1.7.1
curved edge   curved edge