1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-12 08:04:09 +02:00

FMV decoders optimization

This commit is contained in:
XProger
2018-12-15 05:24:25 +03:00
parent b66e68dbf0
commit 26c7815abf
4 changed files with 192 additions and 142 deletions

View File

@@ -168,7 +168,6 @@ struct ShaderCache {
#undef SD_ADD #undef SD_ADD
LOG("shader: %s(%d) %s%s%s\n", Core::passNames[pass], type, (fx & FX_UNDERWATER) ? "u" : "", (fx & FX_ALPHA_TEST) ? "a" : "", (fx & FX_CLIP_PLANE) ? "c" : "");
return shaders[pass][type][fx] = new Shader(pass, type, def, defCount); return shaders[pass][type][fx] = new Shader(pass, type, def, defCount);
#else #else
return NULL; return NULL;

View File

@@ -158,7 +158,7 @@ namespace Sound {
int channels, freq, offset; int channels, freq, offset;
Frame prevFrame; Frame prevFrame;
Decoder(Stream *stream, int channels, int freq) : stream(stream), channels(channels), freq(freq), offset(stream->pos) { Decoder(Stream *stream, int channels, int freq) : stream(stream), channels(channels), freq(freq), offset(stream ? stream->pos : 0) {
memset(&prevFrame, 0, sizeof(prevFrame)); memset(&prevFrame, 0, sizeof(prevFrame));
} }

View File

@@ -1283,7 +1283,7 @@ char cacheDir[255];
char saveDir[255]; char saveDir[255];
char contentDir[255]; char contentDir[255];
#define STREAM_BUFFER_SIZE (8 * 1024) #define STREAM_BUFFER_SIZE (16 * 1024)
struct Stream { struct Stream {
typedef void (Callback)(Stream *stream, void *userData); typedef void (Callback)(Stream *stream, void *userData);
@@ -1343,10 +1343,10 @@ struct Stream {
#endif #endif
} else { } else {
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
fpos = (int32)ftell(f); size = (int32)ftell(f);
size = fpos; fseek(f, 0, SEEK_SET);
fpos = 0;
buffer = new char[STREAM_BUFFER_SIZE];
bufferIndex = -1; bufferIndex = -1;
if (name) { if (name) {
@@ -1400,34 +1400,71 @@ struct Stream {
if (f) { if (f) {
uint8 *ptr = (uint8*)data; uint8 *ptr = (uint8*)data;
while (count > 0) { while (count > 0) {
int bIndex = pos / STREAM_BUFFER_SIZE; int bIndex = pos / STREAM_BUFFER_SIZE;
int bPos = pos % STREAM_BUFFER_SIZE;
int delta = min(STREAM_BUFFER_SIZE - bPos, count);
if (bufferIndex != bIndex) { if (bufferIndex != bIndex) {
bufferIndex = bIndex; bufferIndex = bIndex;
int readed, part;
if (fpos == pos) {
part = min(count / STREAM_BUFFER_SIZE * STREAM_BUFFER_SIZE, size - fpos);
if (part > STREAM_BUFFER_SIZE) {
readed = fread(ptr, 1, part, f);
#ifdef TEST_SLOW_FIO
LOG("%s read %d + %d\n", name, fpos, readed);
Sleep(5);
#endif
ASSERT(part == readed);
count -= readed;
fpos += readed;
pos += readed;
ptr += readed;
if (count <= 0) {
bufferIndex = -1;
break;
}
bufferIndex = pos / STREAM_BUFFER_SIZE;
}
}
if (fpos != bufferIndex * STREAM_BUFFER_SIZE) { if (fpos != bufferIndex * STREAM_BUFFER_SIZE) {
fpos = bufferIndex * STREAM_BUFFER_SIZE; fpos = bufferIndex * STREAM_BUFFER_SIZE;
fseek(f, fpos, SEEK_SET); fseek(f, fpos, SEEK_SET);
#ifdef TEST_SLOW_FIO #ifdef TEST_SLOW_FIO
LOG("seek %d\n", bufferIndex * STREAM_BUFFER_SIZE); LOG("%s seek %d\n", name, fpos);
Sleep(5); Sleep(5);
#endif #endif
} }
int readed = fread(buffer, 1, min(STREAM_BUFFER_SIZE, size - bufferIndex * STREAM_BUFFER_SIZE), f); if (!buffer) {
ASSERT(readed > 0); buffer = new char[STREAM_BUFFER_SIZE];
fpos += readed; }
part = min(STREAM_BUFFER_SIZE, size - fpos);
readed = fread(buffer, 1, part, f);
#ifdef TEST_SLOW_FIO #ifdef TEST_SLOW_FIO
LOG("read %d + %d\n", bufferIndex * STREAM_BUFFER_SIZE, readed); LOG("%s read %d + %d\n", name, fpos, readed);
Sleep(5); Sleep(5);
#endif #endif
ASSERT(part == readed);
fpos += readed;
} }
ASSERT(buffer);
int bPos = pos % STREAM_BUFFER_SIZE;
int delta = min(STREAM_BUFFER_SIZE - bPos, count);
memcpy(ptr, buffer + bPos, delta); memcpy(ptr, buffer + bPos, delta);
count -= delta; count -= delta;
pos += delta; pos += delta;

View File

@@ -186,9 +186,10 @@ struct Video {
uint8 *prevFrame, *nextFrame, *lumaFrame; uint8 *prevFrame, *nextFrame, *lumaFrame;
struct Chunk { struct Chunk {
int offset; int32 offset;
int videoSize; int32 videoSize;
int audioSize; int32 audioSize;
uint8 *data;
} *chunks; } *chunks;
union MacroBlock { union MacroBlock {
@@ -234,6 +235,7 @@ struct Video {
chunks[i].offset = readValue(); chunks[i].offset = readValue();
chunks[i].videoSize = readValue(); chunks[i].videoSize = readValue();
chunks[i].audioSize = readValue(); chunks[i].audioSize = readValue();
chunks[i].data = NULL;
} }
switch (vfmt) { switch (vfmt) {
@@ -260,24 +262,29 @@ struct Video {
codebook[1].blocks = codebook[1].blocks =
codebook[2].blocks = NULL; codebook[2].blocks = NULL;
curVideoPos = curVideoChunk = 0; curVideoPos = curAudioPos = 0;
curAudioPos = curAudioChunk = 0; curVideoChunk = curAudioChunk = 0;
nextChunk(0, 0);
if (sfmt == 1) if (sfmt == 1)
audioDecoder = new Sound::PCM(stream, channels, rate, 0, bps); // TR2 audioDecoder = new Sound::PCM(NULL, channels, rate, 0x7FFFFF, bps); // TR2
else if (sfmt == 101) { else if (sfmt == 101) {
if (bps == 8) if (bps == 8)
audioDecoder = new Sound::PCM(stream, channels, rate, 0, bps); // TR1 audioDecoder = new Sound::PCM(NULL, channels, rate, 0x7FFFFF, bps); // TR1
else else
audioDecoder = new Sound::IMA(stream, channels, rate); // TR3 audioDecoder = new Sound::IMA(NULL, channels, rate); // TR3
} }
} }
virtual ~Escape() { virtual ~Escape() {
if (audioDecoder) { {
OS_LOCK(Sound::lock);
audioDecoder->stream = NULL; audioDecoder->stream = NULL;
delete audioDecoder; delete audioDecoder;
} }
for (int i = 0; i < chunksCount; i++)
delete[] chunks[i].data;
delete[] chunks; delete[] chunks;
delete[] codebook[0].blocks; delete[] codebook[0].blocks;
delete[] codebook[1].blocks; delete[] codebook[1].blocks;
@@ -363,9 +370,23 @@ struct Video {
dst[9] = mb.pixels[3]; dst[9] = mb.pixels[3];
} }
virtual bool decodeVideo(Color32 *pixels) { void nextChunk(int from, int to) {
OS_LOCK(Sound::lock); OS_LOCK(Sound::lock);
if (from < curVideoChunk && from < curAudioChunk) {
delete[] chunks[from].data;
chunks[from].data = NULL;
}
Chunk &chunk = chunks[to];
if (chunk.data)
return;
chunk.data = new uint8[chunk.videoSize + chunk.audioSize];
stream->setPos(chunk.offset);
stream->raw(chunk.data, chunk.videoSize + chunk.audioSize);
}
virtual bool decodeVideo(Color32 *pixels) {
if (curVideoChunk >= chunksCount) if (curVideoChunk >= chunksCount)
return false; return false;
@@ -374,22 +395,26 @@ struct Video {
curVideoPos = 0; curVideoPos = 0;
if (curVideoChunk >= chunksCount) if (curVideoChunk >= chunksCount)
return false; return false;
nextChunk(curVideoChunk - 1, curVideoChunk);
} }
stream->setPos(chunks[curVideoChunk].offset + curVideoPos);
uint8 *data = chunks[curVideoChunk].data + curVideoPos;
switch (vfmt) { switch (vfmt) {
case 124 : return decode124(pixels); case 124 : return decode124(data, pixels);
case 130 : return decode130(pixels); case 130 : return decode130(data, pixels);
default : ASSERT(false); default : ASSERT(false);
} }
return false; return false;
} }
bool decode124(Color32 *pixels) { bool decode124(uint8 *data, Color32 *pixels) {
uint32 flags, size; uint32 flags, size;
stream->read(flags); memcpy(&flags, data + 0, 4);
stream->read(size); memcpy(&size, data + 4, 4);
data += 8;
curVideoPos += size; curVideoPos += size;
@@ -402,8 +427,6 @@ struct Video {
// read data into bit stream // read data into bit stream
size -= (sizeof(flags) + sizeof(size)); size -= (sizeof(flags) + sizeof(size));
uint8 *data = new uint8[size];
stream->raw(data, size);
BitStream bs(data, size); BitStream bs(data, size);
// read codebook changes // read codebook changes
@@ -447,10 +470,10 @@ struct Video {
} }
} }
static const uint16 maskMatrix[] = { 0x1, 0x2, 0x10, 0x20, static const uint16 maskMatrix[] = { 0x0001, 0x0002, 0x0010, 0x0020,
0x4, 0x8, 0x40, 0x80, 0x0004, 0x0008, 0x0040, 0x0080,
0x100, 0x200, 0x1000, 0x2000, 0x0100, 0x0200, 0x1000, 0x2000,
0x400, 0x800, 0x4000, 0x8000}; 0x0400, 0x0800, 0x4000, 0x8000};
SuperBlock sb; SuperBlock sb;
MacroBlock mb; MacroBlock mb;
@@ -504,15 +527,13 @@ struct Video {
skip--; skip--;
} }
delete[] data;
memcpy(pixels, nextFrame, width * height * 4); memcpy(pixels, nextFrame, width * height * 4);
swap(prevFrame, nextFrame); swap(prevFrame, nextFrame);
return true; return true;
} }
bool decode130(Color32 *pixels) { bool decode130(uint8 *data, Color32 *pixels) {
static const uint8 offsetLUT[] = { static const uint8 offsetLUT[] = {
2, 4, 10, 20 2, 4, 10, 20
@@ -553,10 +574,9 @@ struct Video {
172, 180, 188, 196, 204, 212, 220, 228 172, 180, 188, 196, 204, 212, 220, 228
}; };
Chunk &chunk = chunks[curVideoChunk++]; Chunk &chunk = chunks[curVideoChunk];
curVideoPos = chunk.videoSize;
uint8 *data = new uint8[chunk.videoSize];
stream->raw(data, chunk.videoSize);
BitStream bs(data, chunk.videoSize); BitStream bs(data, chunk.videoSize);
bs.data += 16; // skip 16 bytes (frame size, version, gamma/linear chroma flags etc.) bs.data += 16; // skip 16 bytes (frame size, version, gamma/linear chroma flags etc.)
@@ -636,8 +656,6 @@ struct Video {
skip--; skip--;
} }
delete[] data;
nY = nextFrame; nY = nextFrame;
nU = nY + width * height; nU = nY + width * height;
nV = nU + width * height / 4; nV = nU + width * height / 4;
@@ -666,6 +684,7 @@ struct Video {
if (!audioDecoder) return 0; if (!audioDecoder) return 0;
if (bps != 4 && abs(curAudioChunk - curVideoChunk) > 1) { // sync with video chunk, doesn't work for IMA if (bps != 4 && abs(curAudioChunk - curVideoChunk) > 1) { // sync with video chunk, doesn't work for IMA
nextChunk(curAudioChunk, curVideoChunk);
curAudioChunk = curVideoChunk; curAudioChunk = curVideoChunk;
curAudioPos = 0; curAudioPos = 0;
} }
@@ -682,22 +701,23 @@ struct Video {
if (curAudioPos >= chunk->audioSize) { if (curAudioPos >= chunk->audioSize) {
curAudioPos = 0; curAudioPos = 0;
curAudioChunk++; curAudioChunk++;
nextChunk(curAudioChunk - 1, curAudioChunk);
continue; continue;
} }
stream->setPos(chunk->offset + chunk->videoSize + curAudioPos);
int part = min(count - i, (chunk->audioSize - curAudioPos) / (channels * bps / 8)); int part = min(count - i, (chunk->audioSize - curAudioPos) / (channels * bps / 8));
int pos = stream->pos; Stream *memStream = new Stream(NULL, chunk->data + chunk->videoSize + curAudioPos, chunk->audioSize - curAudioPos);
audioDecoder->stream = memStream;
while (part > 0) { while (part > 0) {
int res = audioDecoder->decode(&frames[i], part); int res = audioDecoder->decode(&frames[i], part);
i += res; i += res;
part -= res; part -= res;
} }
curAudioPos += memStream->pos;
curAudioPos += stream->pos - pos; delete memStream;
} }
return count; return count;
@@ -709,16 +729,12 @@ struct Video {
enum { enum {
MAGIC_STR = 0x80010160, MAGIC_STR = 0x80010160,
SECTOR_SIZE = 2352,
VIDEO_CHUNK_SIZE = 2016, VIDEO_SECTOR_SIZE = 2016,
VIDEO_MAX_CHUNKS = 16, VIDEO_SECTOR_MAX = 16,
VIDEO_MAX_FRAMES = 4, AUDIO_SECTOR_SIZE = (16 + 112) * 18, // XA ADPCM data block size
AUDIO_CHUNK_SIZE = (16 + 112) * 18, // XA ADPCM data block size MAX_CHUNKS = 4,
AUDIO_MAX_FRAMES = 8,
BLOCK_EOD = 0xFE00,
}; };
struct SyncHeader { struct SyncHeader {
@@ -749,28 +765,31 @@ struct Video {
uint32 unk2; uint32 unk2;
}; };
struct VideoFrame { struct VideoChunk {
uint8 data[VIDEO_CHUNK_SIZE * VIDEO_MAX_CHUNKS];
int size; int size;
uint16 width; uint16 width;
uint16 height; uint16 height;
uint32 qscale; uint32 qscale;
uint8 data[VIDEO_SECTOR_SIZE * VIDEO_SECTOR_MAX];
}; };
struct AudioFrame { struct AudioChunk {
int pos; int size;
int size; uint8 data[AUDIO_SECTOR_SIZE];
}; };
uint8 AC_LUT_1[256]; uint8 AC_LUT_1[256];
uint8 AC_LUT_6[256]; uint8 AC_LUT_6[256];
uint8 AC_LUT_9[256]; uint8 AC_LUT_9[256];
VideoFrame vFrames[VIDEO_MAX_FRAMES]; VideoChunk videoChunks[MAX_CHUNKS];
AudioFrame aFrames[AUDIO_MAX_FRAMES]; AudioChunk audioChunks[MAX_CHUNKS];
int vFrameIndex; int videoChunksCount;
int aFrameIndex; int audioChunksCount;
int curVideoChunk;
int curAudioChunk;
Sound::Decoder *audioDecoder; Sound::Decoder *audioDecoder;
@@ -779,13 +798,9 @@ struct Video {
uint8 length; uint8 length;
} vlc[176]; } vlc[176];
int curAudioPos;
int curAudioFrame;
bool hasSyncHeader; bool hasSyncHeader;
STR(Stream *stream) : Decoder(stream), vFrameIndex(-1), aFrameIndex(-1), audioDecoder(NULL) { STR(Stream *stream) : Decoder(stream), videoChunksCount(0), audioChunksCount(0), curVideoChunk(-1), curAudioChunk(-1), audioDecoder(NULL) {
curAudioFrame = 0;
if (stream->pos >= stream->size) { if (stream->pos >= stream->size) {
LOG("Can't load STR format \"%s\"\n", stream->name); LOG("Can't load STR format \"%s\"\n", stream->name);
@@ -801,35 +816,38 @@ struct Video {
buildLUT(AC_LUT_6, 22, 62, 6); buildLUT(AC_LUT_6, 22, 62, 6);
buildLUT(AC_LUT_9, 62, 110, 9); buildLUT(AC_LUT_9, 62, 110, 9);
int pos = stream->pos;
uint32 syncMagic[3]; uint32 syncMagic[3];
stream->raw(syncMagic, sizeof(syncMagic)); stream->raw(syncMagic, sizeof(syncMagic));
stream->seek(-12); stream->seek(-(int)sizeof(syncMagic));
hasSyncHeader = syncMagic[0] == 0xFFFFFF00 && syncMagic[1] == 0xFFFFFFFF && syncMagic[2] == 0x00FFFFFF; hasSyncHeader = syncMagic[0] == 0xFFFFFF00 && syncMagic[1] == 0xFFFFFFFF && syncMagic[2] == 0x00FFFFFF;
nextFrame(); if (!hasSyncHeader) {
LOG("! No sync header found, please use jpsxdec tool to extract FMVs\n");
}
VideoFrame &frame = vFrames[vFrameIndex]; for (int i = 0; i < MAX_CHUNKS; i++) {
width = (frame.width + 15) / 16 * 16; videoChunks[i].size = 0;
height = (frame.height + 15) / 16 * 16; audioChunks[i].size = 0;
fps = 150 / (frame.size / VIDEO_CHUNK_SIZE); }
fps = (fps < 20) ? 15 : 30;
stream->setPos(pos); nextChunk();
vFrameIndex = aFrameIndex = -1; VideoChunk &chunk = videoChunks[0];
memset(aFrames, 0, sizeof(aFrames)); width = (chunk.width + 15) / 16 * 16;
height = (chunk.height + 15) / 16 * 16;
fps = 150 / (chunk.size / VIDEO_SECTOR_SIZE);
fps = (fps < 20) ? 15 : 30;
channels = 2;
freq = 37800;
audioDecoder = new Sound::XA(stream); audioDecoder = new Sound::XA(NULL);
} }
virtual ~STR() { virtual ~STR() {
if (audioDecoder) { OS_LOCK(Sound::lock);
audioDecoder->stream = NULL; audioDecoder->stream = NULL;
delete audioDecoder; delete audioDecoder;
}
} }
void buildLUT(uint8 *LUT, int start, int end, int shift) { void buildLUT(uint8 *LUT, int start, int end, int shift) {
@@ -842,10 +860,14 @@ struct Video {
} }
} }
bool nextFrame() { bool nextChunk() {
OS_LOCK(Sound::lock); OS_LOCK(Sound::lock);
VideoFrame *vFrame = vFrames + vFrameIndex; if (stream->pos >= stream->size)
return false;
bool readingVideo = false;
while (stream->pos < stream->size) { while (stream->pos < stream->size) {
if (hasSyncHeader) if (hasSyncHeader)
@@ -855,39 +877,44 @@ struct Video {
stream->raw(&sector, sizeof(Sector)); stream->raw(&sector, sizeof(Sector));
if (sector.magic == MAGIC_STR) { if (sector.magic == MAGIC_STR) {
VideoChunk *chunk = videoChunks + (videoChunksCount % MAX_CHUNKS);
if (sector.chunkIndex == 0) { if (sector.chunkIndex == 0) {
vFrameIndex = (vFrameIndex + 1) % VIDEO_MAX_FRAMES; readingVideo = true;
vFrame = vFrames + vFrameIndex; chunk->size = 0;
vFrame->size = 0; chunk->width = sector.width;
vFrame->width = sector.width; chunk->height = sector.height;
vFrame->height = sector.height; chunk->qscale = sector.qscale;
vFrame->qscale = sector.qscale;
} }
ASSERT(vFrame->size + VIDEO_CHUNK_SIZE < sizeof(vFrame->data)); ASSERT(chunk->size + VIDEO_SECTOR_SIZE < sizeof(chunk->data));
stream->raw(vFrame->data + vFrame->size, VIDEO_CHUNK_SIZE); stream->raw(chunk->data + chunk->size, VIDEO_SECTOR_SIZE);
vFrame->size += VIDEO_CHUNK_SIZE; chunk->size += VIDEO_SECTOR_SIZE;
if (hasSyncHeader) if (hasSyncHeader)
stream->seek(280); stream->seek(280);
if (sector.chunkIndex == sector.chunksCount - 1) if (sector.chunkIndex == sector.chunksCount - 1) {
videoChunksCount++;
LOG("video %d\n", videoChunksCount);
return true; return true;
}
} else { } else {
channels = 2; AudioChunk *chunk = audioChunks + (audioChunksCount++ % MAX_CHUNKS);
freq = 37800;
aFrameIndex = (aFrameIndex + 1) % AUDIO_MAX_FRAMES; memcpy(chunk->data, &sector, sizeof(sector)); // audio chunk has no sector header (just XA data)
AudioFrame *aFrame = aFrames + aFrameIndex; stream->raw(chunk->data + sizeof(sector), AUDIO_SECTOR_SIZE - sizeof(sector)); // !!! MUST BE 2304 !!! most of CD image tools copy only 2048 per sector, so "clicks" will be there
aFrame->pos = stream->pos - sizeof(sector); chunk->size = AUDIO_SECTOR_SIZE;
aFrame->size = AUDIO_CHUNK_SIZE; // !!! MUST BE 2304 !!! most of CD image tools copy only 2048 per sector, so "clicks" will be there stream->seek(24);
stream->seek(2048 - sizeof(sector)); LOG("audio %d\n", audioChunksCount);
if (hasSyncHeader) if (!hasSyncHeader)
stream->seek(280); stream->seek(2048 - (AUDIO_SECTOR_SIZE + 24));
if (!readingVideo)
return true;
}; };
} }
return false; return false;
@@ -977,12 +1004,16 @@ struct Video {
} }
virtual bool decodeVideo(Color32 *pixels) { virtual bool decodeVideo(Color32 *pixels) {
if (!nextFrame()) curVideoChunk++;
return false; while (curVideoChunk >= videoChunksCount) {
if (!nextChunk()) {
return false;
}
}
VideoFrame *frame = vFrames + vFrameIndex; VideoChunk *chunk = videoChunks + (curVideoChunk % MAX_CHUNKS);
BitStream bs(frame->data + 8, frame->size - 8); // make bitstream without frame header BitStream bs(chunk->data + 8, chunk->size - 8); // make bitstream without frame header
int16 block[6][64]; // Cr, Cb, YTL, YTR, YBL, YBR int16 block[6][64]; // Cr, Cb, YTL, YTR, YBL, YBR
for (int bX = 0; bX < width / 16; bX++) for (int bX = 0; bX < width / 16; bX++)
@@ -1007,7 +1038,7 @@ struct Video {
index += 1 + skip; index += 1 + skip;
ASSERT(index < 64); ASSERT(index < 64);
int zIndex = STR_ZIG_ZAG[index]; int zIndex = STR_ZIG_ZAG[index];
channel[zIndex] = (ac * STR_QUANTIZATION[zIndex] * frame->qscale + 4) >> 3; channel[zIndex] = (ac * STR_QUANTIZATION[zIndex] * chunk->qscale + 4) >> 3;
nonZero = true; nonZero = true;
} }
@@ -1036,47 +1067,30 @@ struct Video {
virtual int decode(Sound::Frame *frames, int count) { virtual int decode(Sound::Frame *frames, int count) {
if (!audioDecoder) return 0; if (!audioDecoder) return 0;
int oldPos = stream->pos;
Sound::XA *xa = (Sound::XA*)audioDecoder; Sound::XA *xa = (Sound::XA*)audioDecoder;
int i = 0; int i = 0;
while (i < count) { while (i < count) {
if (xa->pos >= COUNT(xa->buffer)) { if (xa->pos >= COUNT(xa->buffer)) {
if (aFrames[curAudioFrame].size == 0) { curAudioChunk++;
curAudioFrame = (curAudioFrame + 1) % AUDIO_MAX_FRAMES; while (curAudioChunk >= audioChunksCount) {
if (!nextChunk()) {
if (aFrames[curAudioFrame].size == 0) { memset(frames, 0, count * sizeof(Sound::Frame));
// check next 3 frames for audio frame return count;
stream->setPos(oldPos);
for (int j = 0; j < 3; j++) {
nextFrame();
curAudioFrame = aFrameIndex;
if (curAudioFrame != -1 && aFrames[curAudioFrame].size != 0)
break;
}
if (curAudioFrame == -1) { // no audio frames found!
ASSERT(false);
memset(frames, 0, count * sizeof(Sound::Frame));
return count;
}
oldPos = stream->pos;
} }
} }
} }
stream->setPos(aFrames[curAudioFrame].pos);
AudioChunk *chunk = audioChunks + (curAudioChunk % MAX_CHUNKS);
ASSERT(chunk->size > 0);
Stream *memStream = new Stream(NULL, chunk->data, AUDIO_SECTOR_SIZE);
audioDecoder->stream = memStream;
i += audioDecoder->decode(&frames[i], count - i); i += audioDecoder->decode(&frames[i], count - i);
if (xa->pos >= COUNT(xa->buffer)) delete memStream;
aFrames[curAudioFrame].size = 0;
} }
stream->setPos(oldPos);
return count; return count;
} }
}; };