mirror of
https://github.com/libretro/scummvm.git
synced 2024-11-27 11:20:40 +00:00
VIDEO: Separate AVI video and audio track reading
Relying on the videos to have 'initial frames' for audio tracks is not the best way to handle AVI videos. Now videos without initial frames (or broken interleaving) will buffer properly.
This commit is contained in:
parent
3f7566c7b1
commit
dfc3bcae20
@ -319,8 +319,25 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Seek back to the start of the MOVI list
|
||||
_fileStream->seek(_movieListStart);
|
||||
// Create the status entries
|
||||
uint32 index = 0;
|
||||
for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, index++) {
|
||||
TrackStatus status;
|
||||
status.track = *it;
|
||||
status.index = index;
|
||||
status.chunkSearchOffset = _movieListStart;
|
||||
|
||||
if ((*it)->getTrackType() == Track::kTrackTypeVideo)
|
||||
_videoTracks.push_back(status);
|
||||
else
|
||||
_audioTracks.push_back(status);
|
||||
}
|
||||
|
||||
if (_videoTracks.size() != 1) {
|
||||
warning("Unhandled AVI video track count: %d", _videoTracks.size());
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if this is a special Duck Truemotion video
|
||||
checkTruemotion1();
|
||||
@ -340,79 +357,138 @@ void AVIDecoder::close() {
|
||||
|
||||
_indexEntries.clear();
|
||||
memset(&_header, 0, sizeof(_header));
|
||||
|
||||
_videoTracks.clear();
|
||||
_audioTracks.clear();
|
||||
}
|
||||
|
||||
void AVIDecoder::readNextPacket() {
|
||||
if ((uint32)_fileStream->pos() >= _movieListEnd) {
|
||||
// Ugh, reached the end premature.
|
||||
forceVideoEnd();
|
||||
// Shouldn't get this unless called on a non-open video
|
||||
if (_videoTracks.empty())
|
||||
return;
|
||||
|
||||
// Get the video frame first
|
||||
handleNextPacket(_videoTracks[0]);
|
||||
|
||||
// Handle audio tracks next
|
||||
for (uint32 i = 0; i < _audioTracks.size(); i++)
|
||||
handleNextPacket(_audioTracks[i]);
|
||||
}
|
||||
|
||||
void AVIDecoder::handleNextPacket(TrackStatus &status) {
|
||||
// If there's no more to search, bail out
|
||||
if (status.chunkSearchOffset + 8 >= _movieListEnd) {
|
||||
if (status.track->getTrackType() == Track::kTrackTypeVideo) {
|
||||
// Horrible AVI video has a premature end
|
||||
// Force the frame to be the last frame
|
||||
debug(0, "Forcing end of AVI video");
|
||||
((AVIVideoTrack *)status.track)->forceTrackEnd();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 nextTag = _fileStream->readUint32BE();
|
||||
uint32 size = _fileStream->readUint32LE();
|
||||
|
||||
if (_fileStream->eos()) {
|
||||
// Also premature end.
|
||||
forceVideoEnd();
|
||||
// See if audio needs to be buffered and break out if not
|
||||
if (status.track->getTrackType() == Track::kTrackTypeAudio && !shouldQueueAudio(status))
|
||||
return;
|
||||
}
|
||||
|
||||
if (nextTag == ID_LIST) {
|
||||
// A list of audio/video chunks
|
||||
int32 startPos = _fileStream->pos();
|
||||
// Seek to where we shall start searching
|
||||
_fileStream->seek(status.chunkSearchOffset);
|
||||
|
||||
if (_fileStream->readUint32BE() != ID_REC)
|
||||
error("Expected 'rec ' LIST");
|
||||
for (;;) {
|
||||
// If there's no more to search, bail out
|
||||
if ((uint32)_fileStream->pos() + 8 >= _movieListEnd) {
|
||||
if (status.track->getTrackType() == Track::kTrackTypeVideo) {
|
||||
// Horrible AVI video has a premature end
|
||||
// Force the frame to be the last frame
|
||||
debug(0, "Forcing end of AVI video");
|
||||
((AVIVideoTrack *)status.track)->forceTrackEnd();
|
||||
}
|
||||
|
||||
size -= 4; // subtract list type
|
||||
break;
|
||||
}
|
||||
|
||||
// Decode chunks in the list
|
||||
while (_fileStream->pos() < startPos + (int32)size)
|
||||
readNextPacket();
|
||||
uint32 nextTag = _fileStream->readUint32BE();
|
||||
uint32 size = _fileStream->readUint32LE();
|
||||
|
||||
return;
|
||||
} else if (nextTag == ID_JUNK || nextTag == ID_IDX1) {
|
||||
skipChunk(size);
|
||||
return;
|
||||
}
|
||||
if (nextTag == ID_LIST) {
|
||||
// A list of audio/video chunks
|
||||
if (_fileStream->readUint32BE() != ID_REC)
|
||||
error("Expected 'rec ' LIST");
|
||||
|
||||
Track *track = getTrack(getStreamIndex(nextTag));
|
||||
continue;
|
||||
} else if (nextTag == ID_JUNK || nextTag == ID_IDX1) {
|
||||
skipChunk(size);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!track)
|
||||
error("Cannot get track from tag '%s'", tag2str(nextTag));
|
||||
// Only accept chunks for this stream
|
||||
uint32 streamIndex = getStreamIndex(nextTag);
|
||||
if (streamIndex != status.index) {
|
||||
skipChunk(size);
|
||||
continue;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *chunk = 0;
|
||||
Common::SeekableReadStream *chunk = 0;
|
||||
|
||||
if (size != 0) {
|
||||
chunk = _fileStream->readStream(size);
|
||||
_fileStream->skip(size & 1);
|
||||
}
|
||||
if (size != 0) {
|
||||
chunk = _fileStream->readStream(size);
|
||||
_fileStream->skip(size & 1);
|
||||
}
|
||||
|
||||
if (track->getTrackType() == Track::kTrackTypeAudio) {
|
||||
if (getStreamType(nextTag) != kStreamTypeAudio)
|
||||
error("Invalid audio track tag '%s'", tag2str(nextTag));
|
||||
if (status.track->getTrackType() == Track::kTrackTypeAudio) {
|
||||
if (getStreamType(nextTag) != kStreamTypeAudio)
|
||||
error("Invalid audio track tag '%s'", tag2str(nextTag));
|
||||
|
||||
assert(chunk);
|
||||
((AVIAudioTrack *)track)->queueSound(chunk);
|
||||
} else {
|
||||
AVIVideoTrack *videoTrack = (AVIVideoTrack *)track;
|
||||
assert(chunk);
|
||||
((AVIAudioTrack *)status.track)->queueSound(chunk);
|
||||
|
||||
if (getStreamType(nextTag) == kStreamTypePaletteChange) {
|
||||
// Palette Change
|
||||
videoTrack->loadPaletteFromChunk(chunk);
|
||||
// Break out if we have enough audio
|
||||
if (!shouldQueueAudio(status))
|
||||
break;
|
||||
} else {
|
||||
// Otherwise, assume it's a compressed frame
|
||||
videoTrack->decodeFrame(chunk);
|
||||
AVIVideoTrack *videoTrack = (AVIVideoTrack *)status.track;
|
||||
|
||||
if (getStreamType(nextTag) == kStreamTypePaletteChange) {
|
||||
// Palette Change
|
||||
videoTrack->loadPaletteFromChunk(chunk);
|
||||
} else {
|
||||
// Otherwise, assume it's a compressed frame
|
||||
videoTrack->decodeFrame(chunk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start us off in this position next time
|
||||
status.chunkSearchOffset = _fileStream->pos();
|
||||
}
|
||||
|
||||
bool AVIDecoder::shouldQueueAudio(TrackStatus& status) {
|
||||
// Sanity check:
|
||||
if (status.track->getTrackType() != Track::kTrackTypeAudio)
|
||||
return false;
|
||||
|
||||
// If video is done, make sure that the rest of the audio is queued
|
||||
// (I guess this is also really a sanity check)
|
||||
AVIVideoTrack *videoTrack = (AVIVideoTrack *)_videoTracks[0].track;
|
||||
if (videoTrack->endOfTrack())
|
||||
return true;
|
||||
|
||||
// Being three frames ahead should be enough for any video.
|
||||
return ((AVIAudioTrack *)status.track)->getCurChunk() < (uint32)(videoTrack->getCurFrame() + 3);
|
||||
}
|
||||
|
||||
bool AVIDecoder::rewind() {
|
||||
if (!VideoDecoder::rewind())
|
||||
return false;
|
||||
|
||||
_fileStream->seek(_movieListStart);
|
||||
for (uint32 i = 0; i < _videoTracks.size(); i++)
|
||||
_videoTracks[i].chunkSearchOffset = _movieListStart;
|
||||
|
||||
for (uint32 i = 0; i < _audioTracks.size(); i++)
|
||||
_audioTracks[i].chunkSearchOffset = _movieListStart;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -421,29 +497,9 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
|
||||
if (time > getDuration())
|
||||
return false;
|
||||
|
||||
// Track down our video track.
|
||||
// We only support seeking with one video track right now.
|
||||
AVIVideoTrack *videoTrack = 0;
|
||||
int videoIndex = -1;
|
||||
uint trackID = 0;
|
||||
|
||||
for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, trackID++) {
|
||||
if ((*it)->getTrackType() == Track::kTrackTypeVideo) {
|
||||
if (videoTrack) {
|
||||
// Already have one
|
||||
// -> Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
videoTrack = (AVIVideoTrack *)*it;
|
||||
videoIndex = trackID;
|
||||
}
|
||||
}
|
||||
|
||||
// Need a video track to go forwards
|
||||
// If there isn't a video track, why would anyone be using AVI then?
|
||||
if (!videoTrack)
|
||||
return false;
|
||||
// Get our video
|
||||
AVIVideoTrack *videoTrack = (AVIVideoTrack *)_videoTracks[0].track;
|
||||
uint32 videoIndex = _videoTracks[0].index;
|
||||
|
||||
// If we seek directly to the end, just mark the tracks as over
|
||||
if (time == getDuration()) {
|
||||
@ -464,7 +520,6 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
|
||||
|
||||
int lastKeyFrame = -1;
|
||||
int frameIndex = -1;
|
||||
int lastRecord = -1;
|
||||
uint curFrame = 0;
|
||||
|
||||
// Go through and figure out where we should be
|
||||
@ -472,40 +527,40 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
|
||||
for (uint32 i = 0; i < _indexEntries.size(); i++) {
|
||||
const OldIndex &index = _indexEntries[i];
|
||||
|
||||
if (index.id == ID_REC) {
|
||||
// Keep track of any records we find
|
||||
lastRecord = i;
|
||||
// We don't care about RECs
|
||||
if (index.id == ID_REC)
|
||||
continue;
|
||||
|
||||
// We're only looking at entries for this track
|
||||
if (getStreamIndex(index.id) != videoIndex)
|
||||
continue;
|
||||
|
||||
uint16 streamType = getStreamType(index.id);
|
||||
|
||||
if (streamType == kStreamTypePaletteChange) {
|
||||
// We need to handle any palette change we see since there's no
|
||||
// flag to tell if this is a "key" palette.
|
||||
// Decode the palette
|
||||
_fileStream->seek(_indexEntries[i].offset + 8);
|
||||
Common::SeekableReadStream *chunk = 0;
|
||||
|
||||
if (_indexEntries[i].size != 0)
|
||||
chunk = _fileStream->readStream(_indexEntries[i].size);
|
||||
|
||||
videoTrack->loadPaletteFromChunk(chunk);
|
||||
} else {
|
||||
if (getStreamIndex(index.id) != videoIndex)
|
||||
continue;
|
||||
// Check to see if this is a keyframe
|
||||
// The first frame has to be a keyframe
|
||||
if ((_indexEntries[i].flags & AVIIF_INDEX) || curFrame == 0)
|
||||
lastKeyFrame = i;
|
||||
|
||||
uint16 streamType = getStreamType(index.id);
|
||||
|
||||
if (streamType == kStreamTypePaletteChange) {
|
||||
// We need to handle any palette change we see since there's no
|
||||
// flag to tell if this is a "key" palette.
|
||||
// Decode the palette
|
||||
_fileStream->seek(_indexEntries[i].offset + 8);
|
||||
Common::SeekableReadStream *chunk = 0;
|
||||
|
||||
if (_indexEntries[i].size != 0)
|
||||
chunk = _fileStream->readStream(_indexEntries[i].size);
|
||||
|
||||
videoTrack->loadPaletteFromChunk(chunk);
|
||||
} else {
|
||||
// Check to see if this is a keyframe
|
||||
// The first frame has to be a keyframe
|
||||
if ((_indexEntries[i].flags & AVIIF_INDEX) || curFrame == 0)
|
||||
lastKeyFrame = i;
|
||||
|
||||
// Did we find the target frame?
|
||||
if (frame == curFrame) {
|
||||
frameIndex = i;
|
||||
break;
|
||||
}
|
||||
|
||||
curFrame++;
|
||||
// Did we find the target frame?
|
||||
if (frame == curFrame) {
|
||||
frameIndex = i;
|
||||
break;
|
||||
}
|
||||
|
||||
curFrame++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -513,57 +568,36 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
|
||||
return false;
|
||||
|
||||
// Update all the audio tracks
|
||||
uint audioIndex = 0;
|
||||
|
||||
for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, audioIndex++) {
|
||||
if ((*it)->getTrackType() != Track::kTrackTypeAudio)
|
||||
continue;
|
||||
|
||||
AVIAudioTrack *audioTrack = (AVIAudioTrack *)*it;
|
||||
|
||||
// We need to find where the start of audio should be.
|
||||
// Which is exactly 'initialFrames' audio chunks back from where
|
||||
// our found frame is.
|
||||
for (uint32 i = 0; i < _audioTracks.size(); i++) {
|
||||
AVIAudioTrack *audioTrack = (AVIAudioTrack *)_audioTracks[i].track;
|
||||
|
||||
// Recreate the audio stream
|
||||
audioTrack->resetStream();
|
||||
|
||||
uint framesNeeded = _header.initialFrames;
|
||||
if (framesNeeded == 0)
|
||||
framesNeeded = 1;
|
||||
// Set the chunk index for the track
|
||||
audioTrack->setCurChunk(frame);
|
||||
|
||||
uint startAudioChunk = 0;
|
||||
int startAudioSearch = (lastRecord < 0) ? (frameIndex - 1) : (lastRecord - 1);
|
||||
uint32 chunksFound = 0;
|
||||
for (uint32 j = 0; j < _indexEntries.size(); j++) {
|
||||
const OldIndex &index = _indexEntries[j];
|
||||
|
||||
for (int i = startAudioSearch; i >= 0; i--) {
|
||||
if (getStreamIndex(_indexEntries[i].id) != audioIndex)
|
||||
// Continue ignoring RECs
|
||||
if (index.id == ID_REC)
|
||||
continue;
|
||||
|
||||
assert(getStreamType(_indexEntries[i].id) == kStreamTypeAudio);
|
||||
if (getStreamIndex(index.id) == _audioTracks[i].index) {
|
||||
if (chunksFound == frame) {
|
||||
_fileStream->seek(index.offset + 8);
|
||||
Common::SeekableReadStream *audioChunk = _fileStream->readStream(index.size);
|
||||
audioTrack->queueSound(audioChunk);
|
||||
_audioTracks[i].chunkSearchOffset = (j == _indexEntries.size() - 1) ? _movieListEnd : _indexEntries[j + 1].offset;
|
||||
break;
|
||||
}
|
||||
|
||||
framesNeeded--;
|
||||
|
||||
if (framesNeeded == 0) {
|
||||
startAudioChunk = i;
|
||||
break;
|
||||
chunksFound++;
|
||||
}
|
||||
}
|
||||
|
||||
// Now go forward and queue them all
|
||||
for (int i = startAudioChunk; i <= startAudioSearch; i++) {
|
||||
if (_indexEntries[i].id == ID_REC)
|
||||
continue;
|
||||
|
||||
if (getStreamIndex(_indexEntries[i].id) != audioIndex)
|
||||
continue;
|
||||
|
||||
assert(getStreamType(_indexEntries[i].id) == kStreamTypeAudio);
|
||||
|
||||
_fileStream->seek(_indexEntries[i].offset + 8);
|
||||
Common::SeekableReadStream *chunk = _fileStream->readStream(_indexEntries[i].size);
|
||||
audioTrack->queueSound(chunk);
|
||||
}
|
||||
|
||||
// Skip any audio to bring us to the right time
|
||||
audioTrack->skipAudio(time, videoTrack->getFrameTime(frame));
|
||||
}
|
||||
@ -592,15 +626,11 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
|
||||
videoTrack->decodeFrame(chunk);
|
||||
}
|
||||
|
||||
// Seek to the right spot
|
||||
// To the beginning of the last record, or frame if that doesn't exist
|
||||
if (lastRecord >= 0)
|
||||
_fileStream->seek(_indexEntries[lastRecord].offset);
|
||||
else
|
||||
_fileStream->seek(_indexEntries[frameIndex].offset);
|
||||
|
||||
// Set the video track's frame
|
||||
videoTrack->setCurFrame((int)frame - 1);
|
||||
|
||||
// Set the video track's search offset to the right spot
|
||||
_videoTracks[0].chunkSearchOffset = _indexEntries[frameIndex].offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -654,45 +684,22 @@ void AVIDecoder::readOldIndex(uint32 size) {
|
||||
}
|
||||
}
|
||||
|
||||
void AVIDecoder::forceVideoEnd() {
|
||||
// Horrible AVI video has a premature end
|
||||
// Force the frame to be the last frame
|
||||
debug(0, "Forcing end of AVI video");
|
||||
|
||||
for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++)
|
||||
if ((*it)->getTrackType() == Track::kTrackTypeVideo)
|
||||
((AVIVideoTrack *)*it)->forceTrackEnd();
|
||||
}
|
||||
|
||||
void AVIDecoder::checkTruemotion1() {
|
||||
AVIVideoTrack *track = 0;
|
||||
// If we got here from loadStream(), we know the track is valid
|
||||
assert(!_videoTracks.empty());
|
||||
|
||||
for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) {
|
||||
if ((*it)->getTrackType() == Track::kTrackTypeVideo) {
|
||||
if (track) {
|
||||
// Multiple tracks; isn't going to be truemotion 1
|
||||
return;
|
||||
}
|
||||
|
||||
track = (AVIVideoTrack *)*it;
|
||||
}
|
||||
}
|
||||
|
||||
// No track found?
|
||||
if (!track)
|
||||
return;
|
||||
TrackStatus &status = _videoTracks[0];
|
||||
AVIVideoTrack *track = (AVIVideoTrack *)status.track;
|
||||
|
||||
// Ignore non-truemotion tracks
|
||||
if (!track->isTruemotion1())
|
||||
return;
|
||||
|
||||
// Search for a non-empty frame
|
||||
const Graphics::Surface *frame = 0;
|
||||
for (int i = 0; i < 10 && !frame; i++)
|
||||
frame = decodeNextFrame();
|
||||
// Read the next video packet
|
||||
handleNextPacket(status);
|
||||
|
||||
const Graphics::Surface *frame = track->decodeNextFrame();
|
||||
if (!frame) {
|
||||
// Probably shouldn't happen
|
||||
rewind();
|
||||
return;
|
||||
}
|
||||
@ -809,7 +816,7 @@ void AVIDecoder::AVIVideoTrack::forceTrackEnd() {
|
||||
}
|
||||
|
||||
AVIDecoder::AVIAudioTrack::AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType)
|
||||
: _audsHeader(streamHeader), _wvInfo(waveFormat), _soundType(soundType) {
|
||||
: _audsHeader(streamHeader), _wvInfo(waveFormat), _soundType(soundType), _curChunk(0) {
|
||||
_audStream = createAudioStream();
|
||||
}
|
||||
|
||||
@ -836,12 +843,12 @@ void AVIDecoder::AVIAudioTrack::queueSound(Common::SeekableReadStream *stream) {
|
||||
_audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMMSIma, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
|
||||
} else if (_wvInfo.tag == kWaveFormatDK3) {
|
||||
_audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES);
|
||||
} else if (_wvInfo.tag == kWaveFormatMP3) {
|
||||
warning("AVI: MP3 audio stream is not supported");
|
||||
}
|
||||
} else {
|
||||
delete stream;
|
||||
}
|
||||
|
||||
_curChunk++;
|
||||
}
|
||||
|
||||
void AVIDecoder::AVIAudioTrack::skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime) {
|
||||
@ -862,6 +869,7 @@ void AVIDecoder::AVIAudioTrack::skipAudio(const Audio::Timestamp &time, const Au
|
||||
void AVIDecoder::AVIAudioTrack::resetStream() {
|
||||
delete _audStream;
|
||||
_audStream = createAudioStream();
|
||||
_curChunk = 0;
|
||||
}
|
||||
|
||||
bool AVIDecoder::AVIAudioTrack::rewind() {
|
||||
@ -874,12 +882,17 @@ Audio::AudioStream *AVIDecoder::AVIAudioTrack::getAudioStream() const {
|
||||
}
|
||||
|
||||
Audio::QueuingAudioStream *AVIDecoder::AVIAudioTrack::createAudioStream() {
|
||||
if (_wvInfo.tag == kWaveFormatPCM || _wvInfo.tag == kWaveFormatMSADPCM || _wvInfo.tag == kWaveFormatMSIMAADPCM || _wvInfo.tag == kWaveFormatDK3 || _wvInfo.tag == kWaveFormatMP3)
|
||||
if (_wvInfo.tag == kWaveFormatPCM || _wvInfo.tag == kWaveFormatMSADPCM || _wvInfo.tag == kWaveFormatMSIMAADPCM || _wvInfo.tag == kWaveFormatDK3)
|
||||
return Audio::makeQueuingAudioStream(_wvInfo.samplesPerSec, _wvInfo.channels == 2);
|
||||
else if (_wvInfo.tag == kWaveFormatMP3)
|
||||
warning("Unsupported AVI MP3 tracks");
|
||||
else if (_wvInfo.tag != kWaveFormatNone) // No sound
|
||||
warning("Unsupported AVI audio format %d", _wvInfo.tag);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AVIDecoder::TrackStatus::TrackStatus() : track(0), chunkSearchOffset(0) {
|
||||
}
|
||||
|
||||
} // End of namespace Video
|
||||
|
@ -216,6 +216,8 @@ protected:
|
||||
Audio::Mixer::SoundType getSoundType() const { return _soundType; }
|
||||
void skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime);
|
||||
void resetStream();
|
||||
uint32 getCurChunk() const { return _curChunk; }
|
||||
void setCurChunk(uint32 chunk) { _curChunk = chunk; }
|
||||
|
||||
bool isRewindable() const { return true; }
|
||||
bool rewind();
|
||||
@ -238,6 +240,15 @@ protected:
|
||||
Audio::Mixer::SoundType _soundType;
|
||||
Audio::QueuingAudioStream *_audStream;
|
||||
Audio::QueuingAudioStream *createAudioStream();
|
||||
uint32 _curChunk;
|
||||
};
|
||||
|
||||
struct TrackStatus {
|
||||
TrackStatus();
|
||||
|
||||
Track *track;
|
||||
uint32 index;
|
||||
uint32 chunkSearchOffset;
|
||||
};
|
||||
|
||||
AVIHeader _header;
|
||||
@ -260,9 +271,12 @@ protected:
|
||||
void handleStreamHeader(uint32 size);
|
||||
uint16 getStreamType(uint32 tag) const { return tag & 0xFFFF; }
|
||||
byte getStreamIndex(uint32 tag) const;
|
||||
void forceVideoEnd();
|
||||
void checkTruemotion1();
|
||||
|
||||
void handleNextPacket(TrackStatus& status);
|
||||
bool shouldQueueAudio(TrackStatus& status);
|
||||
Common::Array<TrackStatus> _videoTracks, _audioTracks;
|
||||
|
||||
public:
|
||||
virtual AVIAudioTrack *createAudioTrack(AVIStreamHeader sHeader, PCMWaveFormat wvInfo);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user