Implement Ogg reading specically, instead of trying to derive from Stream

This commit is contained in:
UnknownShadow200 2020-02-16 17:06:18 +11:00
parent 4770170cb3
commit f0dd11a35d
4 changed files with 81 additions and 60 deletions

View File

@ -744,8 +744,7 @@ static cc_result Music_Buffer(int i, cc_int16* data, int maxSamples, struct Vorb
} }
static cc_result Music_PlayOgg(struct Stream* source) { static cc_result Music_PlayOgg(struct Stream* source) {
cc_uint8 buffer[OGG_BUFFER_SIZE]; struct OggState ogg;
struct Stream stream;
struct VorbisState vorbis = { 0 }; struct VorbisState vorbis = { 0 };
struct AudioFormat fmt; struct AudioFormat fmt;
@ -755,8 +754,8 @@ static cc_result Music_PlayOgg(struct Stream* source) {
int i, next; int i, next;
cc_result res; cc_result res;
Ogg_MakeStream(&stream, buffer, source); Ogg_Init(&ogg, source);
vorbis.source = &stream; vorbis.source = &ogg;
if ((res = Vorbis_DecodeHeaders(&vorbis))) goto cleanup; if ((res = Vorbis_DecodeHeaders(&vorbis))) goto cleanup;
fmt.Channels = vorbis.channels; fmt.Channels = vorbis.channels;

View File

@ -667,8 +667,8 @@ static void SoundPatcher_DecodeAudio(struct Stream* s, struct VorbisState* ctx)
static void SoundPatcher_Save(const char* name, struct HttpRequest* req) { static void SoundPatcher_Save(const char* name, struct HttpRequest* req) {
String path; char pathBuffer[STRING_SIZE]; String path; char pathBuffer[STRING_SIZE];
cc_uint8 buffer[OGG_BUFFER_SIZE]; struct OggState ogg;
struct Stream src, ogg, dst; struct Stream src, dst;
struct VorbisState ctx = { 0 }; struct VorbisState ctx = { 0 };
cc_result res; cc_result res;
@ -679,7 +679,7 @@ static void SoundPatcher_Save(const char* name, struct HttpRequest* req) {
res = Stream_CreateFile(&dst, &path); res = Stream_CreateFile(&dst, &path);
if (res) { Logger_Warn(res, "creating .wav file"); return; } if (res) { Logger_Warn(res, "creating .wav file"); return; }
Ogg_MakeStream(&ogg, buffer, &src); Ogg_Init(&ogg, &src);
ctx.source = &ogg; ctx.source = &ogg;
SoundPatcher_DecodeAudio(&dst, &ctx); SoundPatcher_DecodeAudio(&dst, &ctx);

View File

@ -12,7 +12,7 @@
*-------------------------------------------------------Ogg stream--------------------------------------------------------* *-------------------------------------------------------Ogg stream--------------------------------------------------------*
*#########################################################################################################################*/ *#########################################################################################################################*/
#define OGG_FourCC(a, b, c, d) (((cc_uint32)a << 24) | ((cc_uint32)b << 16) | ((cc_uint32)c << 8) | (cc_uint32)d) #define OGG_FourCC(a, b, c, d) (((cc_uint32)a << 24) | ((cc_uint32)b << 16) | ((cc_uint32)c << 8) | (cc_uint32)d)
static cc_result Ogg_NextPage(struct Stream* stream) { static cc_result Ogg_NextPage(struct OggState* ctx) {
cc_uint8 header[27]; cc_uint8 header[27];
struct Stream* source; struct Stream* source;
cc_uint32 sig, size; cc_uint32 sig, size;
@ -32,7 +32,7 @@ static cc_result Ogg_NextPage(struct Stream* stream) {
* [number of segments] number of bytes in each segment * [number of segments] number of bytes in each segment
* [sum of bytes in each segment] page data * [sum of bytes in each segment] page data
*/ */
source = stream->Meta.Ogg.Source; source = ctx->source;
if ((res = Stream_Read(source, header, sizeof(header)))) return res; if ((res = Stream_Read(source, header, sizeof(header)))) return res;
sig = Stream_GetU32_BE(&header[0]); sig = Stream_GetU32_BE(&header[0]);
@ -44,52 +44,68 @@ static cc_result Ogg_NextPage(struct Stream* stream) {
if ((res = Stream_Read(source, segments, numSegments))) return res; if ((res = Stream_Read(source, segments, numSegments))) return res;
for (i = 0; i < numSegments; i++) size += segments[i]; for (i = 0; i < numSegments; i++) size += segments[i];
if ((res = Stream_Read(source, stream->Meta.Ogg.Base, size))) return res; if ((res = Stream_Read(source, ctx->buffer, size))) return res;
stream->Meta.Ogg.Cur = stream->Meta.Ogg.Base; ctx->cur = ctx->buffer;
stream->Meta.Ogg.Left = size; ctx->left = size;
stream->Meta.Ogg.Last = header[5] & 4; ctx->last = header[5] & 4;
return 0; return 0;
} }
static cc_result Ogg_Read(struct Stream* stream, cc_uint8* data, cc_uint32 count, cc_uint32* modified) { static cc_result Ogg_Read(struct OggState* ctx, cc_uint8* data, cc_uint32 count) {
cc_uint32 left = count;
cc_result res; cc_result res;
for (;;) { while (left) {
if (stream->Meta.Ogg.Left) { if (ctx->left) {
count = min(count, stream->Meta.Ogg.Left); count = min(left, ctx->left);
Mem_Copy(data, stream->Meta.Ogg.Cur, count); Mem_Copy(data, ctx->cur, count);
*modified = count; ctx->cur += count;
stream->Meta.Ogg.Cur += count; ctx->left -= count;
stream->Meta.Ogg.Left -= count; left -= count;
} else {
if (ctx->last) return ERR_END_OF_STREAM;
if ((res = Ogg_NextPage(ctx))) return res;
}
}
return 0; return 0;
} }
/* try again with data from next page */ static cc_result Ogg_Skip(struct OggState* ctx, cc_uint32 count) {
*modified = 0; cc_uint8 tmp[3584]; /* not quite 4 KB to avoid chkstk call */
if (stream->Meta.Ogg.Last) return 0; cc_uint32 left = count;
if ((res = Ogg_NextPage(stream))) return res; cc_result res;
}
}
static cc_result Ogg_ReadU8(struct Stream* stream, cc_uint8* data) { /* TODO: Should Ogg_Read be duplicated here to avoid Mem_Copy call? */
if (!stream->Meta.Ogg.Left) return Stream_DefaultReadU8(stream, data); /* Probably not worth it considering how small comments are */
while (left) {
*data = *stream->Meta.Ogg.Cur; count = min(left, sizeof(tmp));
stream->Meta.Ogg.Cur++; if ((res = Ogg_Read(ctx, tmp, count))) return res;
stream->Meta.Ogg.Left--; left -= count;
}
return 0; return 0;
} }
void Ogg_MakeStream(struct Stream* stream, cc_uint8* buffer, struct Stream* source) { static cc_result Ogg_ReadU8(struct OggState* ctx, cc_uint8* data) {
Stream_Init(stream); /* The fast path below almost always gets used */
stream->Read = Ogg_Read; if (!ctx->left) return Ogg_Read(ctx, data, 1);
stream->ReadU8 = Ogg_ReadU8;
stream->Meta.Ogg.Cur = buffer; *data = *ctx->cur;
stream->Meta.Ogg.Base = buffer; ctx->cur++;
stream->Meta.Ogg.Left = 0; ctx->left--;
stream->Meta.Ogg.Last = 0; return 0;
stream->Meta.Ogg.Source = source; }
static cc_result Ogg_ReadU32(struct OggState* ctx, cc_uint32* value) {
cc_uint8 data[4]; cc_result res;
if ((res = Ogg_Read(ctx, data, 4))) return res;
*value = Stream_GetU32_LE(data); return 0;
}
void Ogg_Init(struct OggState* ctx, struct Stream* source) {
ctx->cur = ctx->buffer;
ctx->left = 0;
ctx->last = 0;
ctx->source = source;
} }
@ -109,7 +125,7 @@ static cc_uint32 Vorbis_ReadBits(struct VorbisState* ctx, cc_uint32 bitsCount) {
cc_result res; cc_result res;
while (ctx->NumBits < bitsCount) { while (ctx->NumBits < bitsCount) {
res = ctx->source->ReadU8(ctx->source, &portion); res = Ogg_ReadU8(ctx->source, &portion);
if (res) { Logger_Abort2(res, "Failed to read byte for vorbis"); } if (res) { Logger_Abort2(res, "Failed to read byte for vorbis"); }
Vorbis_PushByte(ctx, portion); Vorbis_PushByte(ctx, portion);
} }
@ -123,7 +139,7 @@ static cc_result Vorbis_TryReadBits(struct VorbisState* ctx, cc_uint32 bitsCount
cc_result res; cc_result res;
while (ctx->NumBits < bitsCount) { while (ctx->NumBits < bitsCount) {
res = ctx->source->ReadU8(ctx->source, &portion); res = Ogg_ReadU8(ctx->source, &portion);
if (res) return res; if (res) return res;
Vorbis_PushByte(ctx, portion); Vorbis_PushByte(ctx, portion);
} }
@ -138,7 +154,7 @@ static cc_uint32 Vorbis_ReadBit(struct VorbisState* ctx) {
cc_result res; cc_result res;
if (!ctx->NumBits) { if (!ctx->NumBits) {
res = ctx->source->ReadU8(ctx->source, &portion); res = Ogg_ReadU8(ctx->source, &portion);
if (res) { Logger_Abort2(res, "Failed to read byte for vorbis"); } if (res) { Logger_Abort2(res, "Failed to read byte for vorbis"); }
Vorbis_PushByte(ctx, portion); Vorbis_PushByte(ctx, portion);
} }
@ -1131,7 +1147,7 @@ static cc_result Vorbis_CheckHeader(struct VorbisState* ctx, cc_uint8 type) {
cc_bool OK; cc_bool OK;
cc_result res; cc_result res;
if ((res = Stream_Read(ctx->source, header, sizeof(header)))) return res; if ((res = Ogg_Read(ctx->source, header, sizeof(header)))) return res;
if (header[0] != type) return VORBIS_ERR_WRONG_HEADER; if (header[0] != type) return VORBIS_ERR_WRONG_HEADER;
OK = OK =
@ -1145,7 +1161,7 @@ static cc_result Vorbis_DecodeIdentifier(struct VorbisState* ctx) {
cc_uint32 version; cc_uint32 version;
cc_result res; cc_result res;
if ((res = Stream_Read(ctx->source, header, sizeof(header)))) return res; if ((res = Ogg_Read(ctx->source, header, sizeof(header)))) return res;
version = Stream_GetU32_LE(&header[0]); version = Stream_GetU32_LE(&header[0]);
if (version != 0) return VORBIS_ERR_VERSION; if (version != 0) return VORBIS_ERR_VERSION;
@ -1168,21 +1184,21 @@ static cc_result Vorbis_DecodeComments(struct VorbisState* ctx) {
cc_uint32 i, len, comments; cc_uint32 i, len, comments;
cc_uint8 flag; cc_uint8 flag;
cc_result res; cc_result res;
struct Stream* stream = ctx->source; struct OggState* source = ctx->source;
/* vendor name, followed by comments */ /* vendor name, followed by comments */
if ((res = Stream_ReadU32_LE(stream, &len))) return res; if ((res = Ogg_ReadU32(source, &len))) return res;
if ((res = stream->Skip(stream, len))) return res; if ((res = Ogg_Skip(source, len))) return res;
if ((res = Stream_ReadU32_LE(stream, &comments))) return res; if ((res = Ogg_ReadU32(source, &comments))) return res;
for (i = 0; i < comments; i++) { for (i = 0; i < comments; i++) {
/* comments such as artist, year, etc */ /* comments such as artist, year, etc */
if ((res = Stream_ReadU32_LE(stream, &len))) return res; if ((res = Ogg_ReadU32(source, &len))) return res;
if ((res = stream->Skip(stream, len))) return res; if ((res = Ogg_Skip(source, len))) return res;
} }
/* check framing flag */ /* check framing flag */
if ((res = stream->ReadU8(stream, &flag))) return res; if ((res = Ogg_ReadU8(source, &flag))) return res;
return (flag & 1) ? 0 : VORBIS_ERR_FRAMING; return (flag & 1) ? 0 : VORBIS_ERR_FRAMING;
} }

View File

@ -9,9 +9,15 @@ struct Stream;
#define VORBIS_MAX_BLOCK_SIZE 8192 #define VORBIS_MAX_BLOCK_SIZE 8192
#define OGG_BUFFER_SIZE (255 * 256) #define OGG_BUFFER_SIZE (255 * 256)
/* Wraps an OGG container stream around an existing stream. */ struct OggState {
/* NOTE: buffer must be of size OGG_BUFFER_SIZE at least. */ cc_uint8* cur;
void Ogg_MakeStream(struct Stream* stream, cc_uint8* buffer, struct Stream* source); cc_uint32 left, last;
struct Stream* source;
cc_uint8 buffer[OGG_BUFFER_SIZE];
};
/* Wraps an OGG container around an existing stream. */
void Ogg_Init(struct OggState* ctx, struct Stream* source);
struct Codebook; struct Floor; struct Residue; struct Mapping; struct Mode; struct Codebook; struct Floor; struct Residue; struct Mapping; struct Mode;
struct imdct_state { struct imdct_state {
@ -26,7 +32,7 @@ struct VorbisWindow { float* Prev; float* Cur; };
struct VorbisState { struct VorbisState {
cc_uint32 Bits; /* Holds bits across byte boundaries*/ cc_uint32 Bits; /* Holds bits across byte boundaries*/
cc_uint32 NumBits; /* Number of bits in Bits buffer*/ cc_uint32 NumBits; /* Number of bits in Bits buffer*/
struct Stream* source; /* Source for filling Input buffer */ struct OggState* source; /* Source for filling Input buffer */
cc_uint8 channels, modeNumBits; cc_uint8 channels, modeNumBits;
cc_uint16 curBlockSize, prevBlockSize, dataSize, numCodebooks; cc_uint16 curBlockSize, prevBlockSize, dataSize, numCodebooks;