ogg reader plugin based on mp3

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5663 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shatty 2003-12-13 20:12:32 +00:00
parent 0380884167
commit 1c828415cf
10 changed files with 3480 additions and 0 deletions

View File

@ -0,0 +1,14 @@
SubDir OBOS_TOP src add-ons media plugins ogg ;
UsePrivateHeaders media ;
SubDirHdrs $(SUBDIR) libogg ogg ;
Addon ogg : media plugins :
OggReaderPlugin.cpp
: false : libogg.a
;
LinkSharedOSLibs ogg : be libmedia.so ;
SubInclude OBOS_TOP src add-ons media plugins ogg libogg ;

View File

@ -0,0 +1,874 @@
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <DataIO.h>
#include <ByteOrder.h>
#include <InterfaceDefs.h>
#include <MediaFormats.h>
#include "OggReaderPlugin.h"
#define TRACE_THIS 1
#if TRACE_THIS
#define TRACE printf
#else
#define TRACE ((void)0)
#endif
// bit_rate_table[mpeg_version_index][layer_index][bitrate_index]
static const int bit_rate_table[4][4][16] =
{
{ // mpeg version 2.5
{ }, // undefined layer
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // layer 3
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // layer 2
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 } // layer 1
},
{ // undefined version
{ },
{ },
{ },
{ }
},
{ // mpeg version 2
{ },
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 },
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 },
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }
},
{ // mpeg version 1
{ },
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 },
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 },
{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0}
}
};
// b_mpeg_id_table[mpeg_version_index][layer_index]
static const int32 b_mpeg_id_table[4][4] =
{
{ 0, B_MPEG_2_5_AUDIO_LAYER_3, B_MPEG_2_5_AUDIO_LAYER_2, B_MPEG_2_5_AUDIO_LAYER_1 },
{ 0, 0, 0, 0 },
{ 0, B_MPEG_2_AUDIO_LAYER_3, B_MPEG_2_AUDIO_LAYER_2, B_MPEG_2_AUDIO_LAYER_1 },
{ 0, B_MPEG_1_AUDIO_LAYER_3, B_MPEG_1_AUDIO_LAYER_2, B_MPEG_1_AUDIO_LAYER_1 },
};
// frame_rate_table[mpeg_version_index][sampling_rate_index]
static const int frame_rate_table[4][4] =
{
{ 11025, 12000, 8000, 0}, // mpeg version 2.5
{ 0, 0, 0, 0 },
{ 22050, 24000, 16000, 0}, // mpeg version 2
{ 44100, 48000, 32000, 0} // mpeg version 1
};
// name_table[mpeg_version_index][layer_index]
static const char * name_table[4][4] =
{
{ 0, "MPEG 2.5 Audio Layer 3", "MPEG 2.5 Audio Layer 2", "MPEG 2.5 Audio Layer 1" },
{ 0, 0, 0, 0 },
{ 0, "MPEG 2 Audio Layer 3", "MPEG 2 Audio Layer 2", "MPEG 2 Audio Layer 1" },
{ 0, "MPEG 1 Audio Layer 3", "MPEG 1 Audio Layer 2", "MPEG 1 Audio Layer 1" },
};
// frame_sample_count_table[layer_index]
static const int frame_sample_count_table[4] = { 0, 1152, 1152, 384 };
static const int MAX_CHUNK_SIZE = 5200;
struct mp3data
{
int64 position;
char * chunkBuffer;
int64 duration; // usec
int32 framesPerFrame; // PCM frames in each mpeg frame
int64 frameCount; // PCM frames
int32 frameRate;
int64 framePosition;
media_format format;
};
struct oggReader::xing_vbr_info
{
int32 frameRate;
int64 encodedFramesCount;
int64 byteCount;
int32 vbrScale;
bool hasSeekpoints;
uint8 seekpoints[100];
int64 duration; // usec
int64 frameCount; // PCM frames
};
struct oggReader::fhg_vbr_info
{
};
oggReader::oggReader()
: fXingVbrInfo(0),
fFhgVbrInfo(0)
{
TRACE("oggReader::oggReader\n");
}
oggReader::~oggReader()
{
delete fXingVbrInfo;
delete fFhgVbrInfo;
}
const char *
oggReader::Copyright()
{
return "mp3 reader, " B_UTF8_COPYRIGHT " by Marcus Overhagen";
}
status_t
oggReader::Sniff(int32 *streamCount)
{
TRACE("oggReader::Sniff\n");
fSeekableSource = dynamic_cast<BPositionIO *>(Reader::Source());
if (!fSeekableSource) {
TRACE("oggReader::Sniff: non seekable sources not supported\n");
return B_ERROR;
}
fFileSize = Source()->Seek(0, SEEK_END);
TRACE("oggReader::Sniff: file size is %Ld bytes\n", fFileSize);
if (!IsMp3File()) {
TRACE("oggReader::Sniff: non recognized as mp3 file\n");
return B_ERROR;
}
TRACE("oggReader::Sniff: looks like an mp3 file\n");
if (!ParseFile()) {
TRACE("oggReader::Sniff: parsing file failed\n");
return B_ERROR;
}
*streamCount = 1;
return B_OK;
}
void
oggReader::GetFileFormatInfo(media_file_format *mff)
{
mff->capabilities = media_file_format::B_READABLE
| media_file_format::B_KNOWS_ENCODED_AUDIO
| media_file_format::B_IMPERFECTLY_SEEKABLE;
mff->family = B_MPEG_FORMAT_FAMILY;
mff->version = 100;
strcpy(mff->mime_type, "audio/mpeg");
strcpy(mff->file_extension, "mp3");
uint8 header[4];
Source()->ReadAt(fDataStart, header, sizeof(header));
int mpeg_version_index = (header[1] >> 3) & 0x03;
int layer_index = (header[1] >> 1) & 0x03;
strcpy(mff->short_name, name_table[mpeg_version_index][layer_index]);
strcpy(mff->pretty_name, name_table[mpeg_version_index][layer_index]);
}
status_t
oggReader::AllocateCookie(int32 streamNumber, void **cookie)
{
TRACE("oggReader::AllocateCookie\n");
mp3data *data = new mp3data;
data->chunkBuffer = new char[MAX_CHUNK_SIZE];
data->position = 0;
uint8 header[4];
Source()->ReadAt(fDataStart, header, sizeof(header));
int mpeg_version_index = (header[1] >> 3) & 0x03;
int layer_index = (header[1] >> 1) & 0x03;
int bit_rate;
int frame_size;
if (fXingVbrInfo && fXingVbrInfo->frameCount != -1 && fXingVbrInfo->duration != -1) {
TRACE("oggReader::AllocateCookie: using timing info from VBR header\n");
bit_rate = (fXingVbrInfo->byteCount * 8 * 1000000) / fXingVbrInfo->duration; // average bit rate
frame_size = fXingVbrInfo->byteCount / fXingVbrInfo->encodedFramesCount; // average frame size
data->duration = fXingVbrInfo->duration;
data->frameCount = fXingVbrInfo->frameCount;
data->frameRate = fXingVbrInfo->frameRate;
} else {
TRACE("oggReader::AllocateCookie: assuming CBR, calculating timing info from file\n");
int sampling_rate_index = (header[2] >> 2) & 0x03;
int bitrate_index = (header[2] >> 4) & 0x0f;
int samples_per_chunk = frame_sample_count_table[layer_index];
bit_rate = 1000 * bit_rate_table[mpeg_version_index][layer_index][bitrate_index];
frame_size = GetFrameLength(header);
data->frameRate = frame_rate_table[mpeg_version_index][sampling_rate_index];
data->frameCount = samples_per_chunk * (fDataSize / frame_size);
data->duration = (data->frameCount * 1000000) / data->frameRate;
}
TRACE("oggReader::AllocateCookie: frameRate %ld, frameCount %Ld, duration %.6f\n",
data->frameRate, data->frameCount, data->duration / 1000000.0);
data->framePosition = 0;
data->framesPerFrame = frame_sample_count_table[layer_index];
// BMediaFormats formats;
media_format_description description;
description.family = B_MPEG_FORMAT_FAMILY;
description.u.mpeg.id = b_mpeg_id_table[mpeg_version_index][layer_index];
// formats.GetFormatFor(description, &data->format);
_get_format_for_description(&data->format, description);
// data->format.u.encoded_audio.encoding = media_encoded_audio_format::B_ANY;
data->format.u.encoded_audio.bit_rate = bit_rate;
data->format.u.encoded_audio.frame_size = frame_size;
// data->format.u.encoded_audio.output.frame_rate = data->frameRate;
// data->format.u.encoded_audio.output.channel_count = 2;
// store the cookie
*cookie = data;
return B_OK;
}
status_t
oggReader::FreeCookie(void *cookie)
{
TRACE("oggReader::FreeCookie\n");
mp3data *data = reinterpret_cast<mp3data *>(cookie);
delete [] data->chunkBuffer;
delete data;
return B_OK;
}
status_t
oggReader::GetStreamInfo(void *cookie, int64 *frameCount, bigtime_t *duration,
media_format *format, void **infoBuffer, int32 *infoSize)
{
mp3data *data = reinterpret_cast<mp3data *>(cookie);
*frameCount = data->frameCount;
*duration = data->duration;
*format = data->format;
*infoBuffer = 0;
*infoSize = 0;
return B_OK;
}
status_t
oggReader::Seek(void *cookie,
uint32 seekTo,
int64 *frame, bigtime_t *time)
{
if (!fSeekableSource)
return B_ERROR;
mp3data *data = reinterpret_cast<mp3data *>(cookie);
int64 pos;
// this isn't very accurate
if (seekTo & B_MEDIA_SEEK_TO_FRAME) {
pos = fXingVbrInfo ? XingSeekPoint(100.0 * *frame / (float)data->frameCount) : -1;
if (pos < 0)
pos = (*frame * fDataSize) / data->frameCount;
TRACE("oggReader::Seek to frame %Ld, pos %Ld\n", *frame, pos);
*time = (*frame * data->duration) / data->frameCount;
TRACE("oggReader::Seek newtime %Ld\n", *time);
} else if (seekTo & B_MEDIA_SEEK_TO_TIME) {
pos = fXingVbrInfo ? XingSeekPoint(100.0 * *time / (float)data->duration) : -1;
if (pos < 0)
pos = (*time * fDataSize) / data->duration;
TRACE("oggReader::Seek to time %Ld, pos %Ld\n", *time, pos);
*frame = (*time * data->frameCount) / data->duration;
TRACE("oggReader::Seek newframe %Ld\n", *frame);
} else {
return B_ERROR;
}
// We ignore B_MEDIA_SEEK_CLOSEST_FORWARD, B_MEDIA_SEEK_CLOSEST_BACKWARD
uint8 buffer[16000];
if (pos > fDataSize - 16000)
pos = fDataSize - 16000;
if (pos < 0)
pos = 0;
int64 size = fDataSize - pos;
if (size > 16000)
size = 16000;
if (size != Source()->ReadAt(fDataStart + pos, buffer, size)) {
TRACE("oggReader::Seek: unexpected read error\n");
return B_ERROR;
}
int32 end = size - 4;
int32 ofs;
for (ofs = 0; ofs < end; ofs++) {
if (buffer[ofs] != 0xff) // quick check
continue;
if (IsValidStream(&buffer[ofs], size - ofs))
break;
}
if (ofs == end) {
TRACE("oggReader::Seek: couldn't synchronize\n");
return B_ERROR;
}
data->position = pos + ofs;
data->framePosition = *frame; // this is not exact
TRACE("oggReader::Seek: synchronized at position %Ld\n", data->position);
return B_OK;
}
status_t
oggReader::GetNextChunk(void *cookie,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
mp3data *data = reinterpret_cast<mp3data *>(cookie);
int64 maxbytes = fDataSize - data->position;
if (maxbytes < 4)
return B_ERROR;
mediaHeader->start_time = (data->framePosition * 1000000) / data->frameRate;
mediaHeader->file_pos = data->position;
if (4 != Source()->ReadAt(fDataStart + data->position, data->chunkBuffer, 4)) {
TRACE("oggReader::GetNextChunk: unexpected read error\n");
return B_ERROR;
}
data->position += 4;
maxbytes -= 4;
int size = GetFrameLength(data->chunkBuffer) - 4;
if (size <= 0) {
TRACE("oggReader::GetNextChunk: invalid frame encountered\n");
// try to synchronize again here!
return B_ERROR;
}
if (size > maxbytes)
size = maxbytes;
if (size != Source()->ReadAt(fDataStart + data->position, data->chunkBuffer + 4, size)) {
TRACE("oggReader::GetNextChunk: unexpected read error\n");
return B_ERROR;
}
data->position += size;
data->framePosition += data->framesPerFrame;
*chunkBuffer = data->chunkBuffer;
*chunkSize = size + 4;
if (*chunkSize > MAX_CHUNK_SIZE) {
printf("oggReader: chunk buffer overrun, read %ld bytes into %d bytes buffer\n", *chunkSize, MAX_CHUNK_SIZE);
exit(1);
}
return B_OK;
}
bool
oggReader::ParseFile()
{
// Since we already know that this is an mp3 file,
// detect the real (mp3 audio) data start and end
// and find VBR or other headers and tags
const int32 search_size = 16384;
const int32 padding_size = 128; // Get???Length() functions need some bytes to look into
int64 offset;
int32 size;
uint8 buf[search_size];
fDataStart = -1;
for (offset = 0; offset < fFileSize; ) {
int64 maxsize = fFileSize - offset;
size = (search_size < maxsize) ? search_size : maxsize;
if (size != Source()->ReadAt(offset, buf, size)) {
TRACE("oggReaderPlugin::ParseFile reading %ld bytes at offset %Ld failed\n", size, offset);
return false;
}
int skip_bytes = 0;
// since the various Get???Length() functions need to check a few bytes
// (10 for ID3V2, about 40 for VBR), we stop searching before buffer end
int32 end = size - padding_size;
for (int32 pos = 0; pos < end; ) {
int hdr_length;
// A Xing or Fraunhofer VBR header is embedded into a valid
// mp3 frame that contains silence. We need to first check
// for these headers before we can search for the start of a stream.
hdr_length = GetXingVbrLength(&buf[pos]);
if (hdr_length > 0) {
TRACE("oggReaderPlugin::ParseFile found a Xing VBR header of %d bytes at position %Ld\n", hdr_length, offset + pos);
ParseXingVbrHeader(offset + pos);
goto skip_header;
}
hdr_length = GetInfoCbrLength(&buf[pos]);
if (hdr_length > 0) {
TRACE("oggReaderPlugin::ParseFile found a Info CBR header of %d bytes at position %Ld\n", hdr_length, offset + pos);
goto skip_header;
}
hdr_length = GetFraunhoferVbrLength(&buf[pos]);
if (hdr_length > 0) {
TRACE("oggReaderPlugin::ParseFile found a Fraunhofer VBR header of %d bytes at position %Ld\n", hdr_length, offset + pos);
ParseFraunhoferVbrHeader(offset + pos);
goto skip_header;
}
hdr_length = GetLameVbrLength(&buf[pos]);
if (hdr_length > 0) {
TRACE("oggReaderPlugin::ParseFile found a Lame VBR header of %d bytes at position %Ld\n", hdr_length, offset + pos);
goto skip_header;
}
hdr_length = GetId3v2Length(&buf[pos]);
if (hdr_length > 0) {
TRACE("oggReaderPlugin::ParseFile found a ID3V2 header of %d bytes at position %Ld\n", hdr_length, offset + pos);
goto skip_header;
}
if (IsValidStream(&buf[pos], size - pos)) {
fDataStart = offset + pos;
break;
}
pos++;
continue;
skip_header:
int skip_max = end - pos;
skip_bytes = (skip_max < hdr_length) ? skip_max : hdr_length;
pos += skip_bytes;
skip_bytes = hdr_length - skip_bytes;
}
if (fDataStart != -1)
break;
if (skip_bytes) {
offset += skip_bytes;
skip_bytes = 0;
} else {
offset += (search_size - padding_size);
}
}
fDataSize = fFileSize - fDataStart;
TRACE("found mp3 audio data at file position %Ld, maximum data length is %Ld\n", fDataStart, fDataSize);
// search for a ID3 V1 tag
offset = fFileSize - 128;
size = 128;
if (offset > 0) {
if (size != Source()->ReadAt(offset, buf, size)) {
TRACE("oggReaderPlugin::ParseFile reading %ld bytes at offset %Ld failed\n", size, offset);
return false;
}
if (buf[0] == 'T'&& buf[1] == 'A' && buf[2] == 'G') {
TRACE("oggReaderPlugin::ParseFile found a ID3V1 header of 128 bytes at position %Ld\n", offset);
fDataSize -= 128;
}
}
// search for a lyrics tag
// maximum size is 5100 bytes, and a 128 byte ID3V1 tag is always appended
// starts with "LYRICSBEGIN", end with "LYRICS200" or "LYRICSEND"
offset = fFileSize - 5300;
size = 5300;
if (offset < 0) {
offset = 0;
size = fFileSize;
}
if (size != Source()->ReadAt(offset, buf, size)) {
TRACE("oggReaderPlugin::ParseFile reading %ld bytes at offset %Ld failed\n", size, offset);
return false;
}
for (int pos = 0; pos < size; pos++) {
if (buf[pos] != 'L')
continue;
if (0 == memcmp(&buf[pos], "LYRICSBEGIN", 11)) {
TRACE("oggReaderPlugin::ParseFile found a Lyrics header at position %Ld\n", offset + pos);
fDataSize = offset + pos + fDataStart;
}
}
// might search for APE tags, too
TRACE("found mp3 audio data at file position %Ld, data length is %Ld\n", fDataStart, fDataSize);
return true;
}
int
oggReader::GetXingVbrLength(uint8 *header)
{
int h_id = (header[1] >> 3) & 1;
int h_mode = (header[3] >> 6) & 3;
uint8 *xing_header;
// determine offset of header
if(h_id) // mpeg1
xing_header = (h_mode != 3) ? (header + 36) : (header + 21);
else // mpeg2
xing_header = (h_mode != 3) ? (header + 21) : (header + 13);
if (xing_header[0] != 'X') return -1;
if (xing_header[1] != 'i') return -1;
if (xing_header[2] != 'n') return -1;
if (xing_header[3] != 'g') return -1;
return GetFrameLength(header);
}
int
oggReader::GetInfoCbrLength(uint8 *header)
{
int h_id = (header[1] >> 3) & 1;
int h_mode = (header[3] >> 6) & 3;
uint8 *info_header;
// determine offset of header
if(h_id) // mpeg1
info_header = (h_mode != 3) ? (header + 36) : (header + 21);
else // mpeg2
info_header = (h_mode != 3) ? (header + 21) : (header + 13);
if (info_header[0] != 'I') return -1;
if (info_header[1] != 'n') return -1;
if (info_header[2] != 'f') return -1;
if (info_header[3] != 'o') return -1;
return GetFrameLength(header);
}
void
oggReader::ParseXingVbrHeader(int64 pos)
{
static const int sr_table[2][4] = { { 22050, 24000, 16000, 0 }, { 44100, 48000, 32000, 0 } };
static const int FRAMES_FLAG = 0x0001;
static const int BYTES_FLAG = 0x0002;
static const int TOC_FLAG = 0x0004;
static const int VBR_SCALE_FLAG = 0x0008;
uint8 header[200];
uint8 *xing_header;
Source()->ReadAt(pos, header, sizeof(header));
int layer_index = (header[1] >> 1) & 3;
int h_id = (header[1] >> 3) & 1;
int h_sr_index = (header[2] >> 2) & 3;
int h_mode = (header[3] >> 6) & 3;
// determine offset of header
if(h_id) // mpeg1
xing_header = (h_mode != 3) ? (header + 36) : (header + 21);
else // mpeg2
xing_header = (h_mode != 3) ? (header + 21) : (header + 13);
xing_header += 4; // skip ID
int flags = B_BENDIAN_TO_HOST_INT32(*(uint32 *)xing_header);
xing_header += 4;
if (fXingVbrInfo) {
TRACE("oggReader::ParseXingVbrHeader: Error, already found a header\n");
return;
}
fXingVbrInfo = new xing_vbr_info;
fXingVbrInfo->frameRate = sr_table[h_id][h_sr_index];
if (flags & FRAMES_FLAG) {
fXingVbrInfo->encodedFramesCount = (int64)(uint32)B_BENDIAN_TO_HOST_INT32(*(uint32 *)xing_header);
xing_header += 4;
} else {
fXingVbrInfo->encodedFramesCount = -1;
}
if (flags & BYTES_FLAG) {
fXingVbrInfo->byteCount = (int64)(uint32)B_BENDIAN_TO_HOST_INT32(*(uint32 *)xing_header);
xing_header += 4;
} else {
fXingVbrInfo->byteCount = -1;
}
if (flags & TOC_FLAG) {
fXingVbrInfo->hasSeekpoints = true;
memcpy(fXingVbrInfo->seekpoints, xing_header, 100);
xing_header += 100;
} else {
fXingVbrInfo->hasSeekpoints = false;
}
if (flags & VBR_SCALE_FLAG) {
fXingVbrInfo->vbrScale = B_BENDIAN_TO_HOST_INT32(*(uint32 *)xing_header);
xing_header += 4;
} else {
fXingVbrInfo->vbrScale = -1;
}
// mpeg frame (chunk) size is is constant and always 384 samples (frames) for
// Layer I and 1152 samples for Layer II and Layer III
if (fXingVbrInfo->encodedFramesCount != -1) {
fXingVbrInfo->frameCount = fXingVbrInfo->encodedFramesCount * frame_sample_count_table[layer_index];
fXingVbrInfo->duration = (fXingVbrInfo->frameCount * 1000000) / fXingVbrInfo->frameRate;
} else {
fXingVbrInfo->duration = -1;
fXingVbrInfo->frameCount = -1;
}
TRACE("oggReader::ParseXingVbrHeader: %Ld encoded frames, %Ld bytes, %s seekpoints, vbrscale %ld\n",
fXingVbrInfo->encodedFramesCount, fXingVbrInfo->byteCount,
fXingVbrInfo->hasSeekpoints ? "has" : "no", fXingVbrInfo->vbrScale);
TRACE("oggReader::ParseXingVbrHeader: frameRate %ld, frameCount %Ld, duration %.6f\n",
fXingVbrInfo->frameRate, fXingVbrInfo->frameCount, fXingVbrInfo->duration / 1000000.0);
}
int64
oggReader::XingSeekPoint(float percent)
{
if (!fXingVbrInfo || !fXingVbrInfo->hasSeekpoints || fXingVbrInfo->byteCount == -1)
return -1;
int a;
int64 point;
float fa, fb, fx;
if (percent < 0.0f)
percent = 0.0f;
if (percent > 100.0f)
percent = 100.0f;
a = (int)percent;
if (a > 99)
a = 99;
fa = fXingVbrInfo->seekpoints[a];
if (a < 99)
fb = fXingVbrInfo->seekpoints[a + 1];
else
fb = 256.0f;
fx = fa + (fb - fa) * (percent - a);
point = (int64)((1.0f / 256.0f) * fx * fXingVbrInfo->byteCount);
TRACE("oggReader::XingSeekPoint for %.8f%% is %Ld\n", percent, point);
return point;
}
int
oggReader::GetLameVbrLength(uint8 *header)
{
return -1;
}
int
oggReader::GetFraunhoferVbrLength(uint8 *header)
{
if (header[0] != 0xff) return -1;
if (header[36] != 'V') return -1;
if (header[37] != 'B') return -1;
if (header[38] != 'R') return -1;
if (header[39] != 'I') return -1;
return GetFrameLength(header);
}
void
oggReader::ParseFraunhoferVbrHeader(int64 pos)
{
}
int
oggReader::GetId3v2Length(uint8 *buffer)
{
if ((buffer[0] == 'I') && /* magic */
(buffer[1] == 'D') &&
(buffer[2] == '3') &&
(buffer[3] != 0xff) && (buffer[4] != 0xff) && /* version */
/* flags */
(!(buffer[6] & 0x80)) && (!(buffer[7] & 0x80)) && /* the MSB in each byte in size is 0, to avoid */
(!(buffer[8] & 0x80)) && (!(buffer[9] & 0x80))) { /* making a buggy mpeg header */
return ((buffer[6] << 21)|(buffer[7] << 14)|(buffer[8] << 7)|(buffer[9])) + 10;
}
return B_ENTRY_NOT_FOUND;
}
bool
oggReader::IsMp3File()
{
// avoid detecting mp3 in a container format like AVI or mov
// To detect an mp3 file, we seek into the middle,
// and search for a valid sequence of 3 frame headers.
// A mp3 frame has a maximum length of 2881 bytes, we
// load a block of 16kB and use it to search.
const int32 search_size = 16384;
int64 offset;
int32 size;
uint8 buf[search_size];
size = 8;
offset = 0;
if (size != Source()->ReadAt(offset, buf, size)) {
TRACE("oggReaderPlugin::IsMp3File reading %ld bytes at offset %Ld failed\n", size, offset);
return false;
}
// avoid reading some common formats that might have an embedded mp3 stream
// RIFF, AVI or WAV
if (buf[0] == 'R' && buf[1] == 'I' && buf[2] == 'F' && buf[3] == 'F')
return false;
// Ogg Vorbis
if (buf[0] == 'O' && buf[1] == 'g' && buf[2] == 'g' && buf[3] == 'S')
return false;
// Real Media
if (buf[0] == '.' && buf[1] == 'R' && buf[2] == 'M' && buf[3] == 'F')
return false;
// Quicktime
if (buf[4] == 'm' && buf[5] == 'o' && buf[6] == 'o' && buf[7] == 'v')
return false;
// ASF 1 (first few bytes of GUID)
if (buf[0] == 0x30 && buf[1] == 0x26 && buf[2] == 0xb2 && buf[3] == 0x75
&& buf[4] == 0x8e && buf[5] == 0x66 && buf[6] == 0xcf && buf[7] == 0x11)
return false;
// ASF 2.0 (first few bytes of GUID)
if (buf[0] == 0xd1 && buf[1] == 0x29 && buf[2] == 0xe2 && buf[3] == 0xd6
&& buf[4] == 0xda && buf[5] == 0x35 && buf[6] == 0xd1 && buf[7] == 0x11)
return false;
// search for a valid mpeg audio frame header
// sequence in the middle of the file
size = search_size;
offset = fFileSize / 2 - search_size / 2;
if (size > fFileSize) {
size = fFileSize;
offset = 0;
}
TRACE("searching for mp3 frame headers at %Ld in %ld bytes\n", offset, size);
if (size != Source()->ReadAt(offset, buf, size)) {
TRACE("oggReaderPlugin::IsMp3File reading %ld bytes at offset %Ld failed\n", size, offset);
return false;
}
int32 end = size - 4;
for (int32 pos = 0; pos < end; pos++) {
if (buf[pos] != 0xff) // quick check
continue;
if (IsValidStream(&buf[pos], size - pos))
return true;
}
return false;
}
bool
oggReader::IsValidStream(uint8 *buffer, int size)
{
// check 3 consecutive frame headers to make sure
// that the length encoded in the header is correct,
// and also that mpeg version and layer do not change
int length1 = GetFrameLength(buffer);
if (length1 < 0 || (length1 + 4) > size)
return false;
int version_index1 = (buffer[1] >> 3) & 0x03;
int layer_index1 = (buffer[1] >> 1) & 0x03;
int length2 = GetFrameLength(buffer + length1);
if (length2 < 0 || (length1 + length2 + 4) > size)
return false;
int version_index2 = (buffer[length1 + 1] >> 3) & 0x03;
int layer_index2 = (buffer[length1 + 1] >> 1) & 0x03;
if (version_index1 != version_index2 || layer_index1 != layer_index1)
return false;
int length3 = GetFrameLength(buffer + length1 + length2);
if (length3 < 0)
return false;
int version_index3 = (buffer[length1 + length2 + 1] >> 3) & 0x03;
int layer_index3 = (buffer[length1 + length2 + 1] >> 1) & 0x03;
if (version_index2 != version_index3 || layer_index2 != layer_index3)
return false;
return true;
}
int
oggReader::GetFrameLength(void *header)
{
uint8 *h = (uint8 *)header;
if (h[0] != 0xff)
return -1;
if ((h[1] & 0xe0) != 0xe0)
return -1;
int mpeg_version_index = (h[1] >> 3) & 0x03;
int layer_index = (h[1] >> 1) & 0x03;
int bitrate_index = (h[2] >> 4) & 0x0f;
int sampling_rate_index = (h[2] >> 2) & 0x03;
int padding = (h[2] >> 1) & 0x01;
/* no interested in the other bits */
int bitrate = bit_rate_table[mpeg_version_index][layer_index][bitrate_index];
int framerate = frame_rate_table[mpeg_version_index][sampling_rate_index];
if (!bitrate || !framerate)
return -1;
int length;
if (layer_index == 3) // layer 1
length = ((144 * 1000 * bitrate) / framerate) + (padding * 4);
else // layer 2 & 3
length = ((144 * 1000 * bitrate) / framerate) + padding;
#if 0
TRACE("%s %s, %s crc, bit rate %d, frame rate %d, padding %d, frame length %d\n",
mpeg_version_index == 0 ? "mpeg 2.5" : (mpeg_version_index == 2 ? "mpeg 2" : "mpeg 1"),
layer_index == 3 ? "layer 1" : (layer_index == 2 ? "layer 2" : "layer 3"),
(h[1] & 0x01) ? "no" : "has",
bitrate, framerate, padding, length);
#endif
return length;
}
Reader *
oggReaderPlugin::NewReader()
{
return new oggReader;
}
MediaPlugin *
instantiate_plugin()
{
return new oggReaderPlugin;
}

View File

@ -0,0 +1,82 @@
#ifndef _OGG_READER_PLUGIN_H
#define _OGG_READER_PLUGIN_H
#include "ReaderPlugin.h"
namespace BPrivate { namespace media {
class oggReader : public Reader
{
public:
oggReader();
~oggReader();
const char *Copyright();
status_t Sniff(int32 *streamCount);
void GetFileFormatInfo(media_file_format *mff);
status_t AllocateCookie(int32 streamNumber, void **cookie);
status_t FreeCookie(void *cookie);
status_t GetStreamInfo(void *cookie, int64 *frameCount, bigtime_t *duration,
media_format *format, void **infoBuffer, int32 *infoSize);
status_t Seek(void *cookie,
uint32 seekTo,
int64 *frame, bigtime_t *time);
status_t GetNextChunk(void *cookie,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader);
BPositionIO *Source() { return fSeekableSource; }
private:
bool ParseFile();
bool IsMp3File();
// checks if the buffer contains a valid ogg stream, length should be
bool IsValidStream(uint8 *buffer, int size);
int GetFrameLength(void *header);
int GetXingVbrLength(uint8 *header);
int GetFraunhoferVbrLength(uint8 *header);
int GetLameVbrLength(uint8 *header);
int GetId3v2Length(uint8 *header);
int GetInfoCbrLength(uint8 *header);
bool FindData();
void ParseXingVbrHeader(int64 pos);
void ParseFraunhoferVbrHeader(int64 pos);
int64 XingSeekPoint(float percent);
private:
BPositionIO * fSeekableSource;
int64 fFileSize;
int64 fDataStart;
int64 fDataSize;
struct xing_vbr_info;
struct fhg_vbr_info;
xing_vbr_info * fXingVbrInfo;
fhg_vbr_info * fFhgVbrInfo;
};
class oggReaderPlugin : public ReaderPlugin
{
public:
Reader *NewReader();
};
} } // namespace BPrivate::media
using namespace BPrivate::media;
#endif

View File

@ -0,0 +1,28 @@
Copyright (c) 2002, Xiph.Org Foundation
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.Org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,6 @@
SubDir OBOS_TOP src add-ons media plugins ogg libogg ;
StaticLibrary ogg :
bitwise.c
framing.c
;

View File

@ -0,0 +1,452 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
function: packing variable sized words into an octet stream
last mod: $Id: bitwise.c,v 1.1 2003/12/13 20:12:32 shatty Exp $
********************************************************************/
/* We're 'LSb' endian; if we write a word but read individual bits,
then we'll read the lsb first */
#include <string.h>
#include <stdlib.h>
#include <ogg/ogg.h>
#define BUFFER_INCREMENT 256
static unsigned long mask[]=
{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f,
0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff,
0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff,
0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff,
0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff,
0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff,
0x3fffffff,0x7fffffff,0xffffffff };
void oggpack_writeinit(oggpack_buffer *b){
memset(b,0,sizeof(*b));
b->ptr=b->buffer=_ogg_malloc(BUFFER_INCREMENT);
b->buffer[0]='\0';
b->storage=BUFFER_INCREMENT;
}
void oggpack_writetrunc(oggpack_buffer *b,long bits){
long bytes=bits>>3;
bits-=bytes*8;
b->ptr=b->buffer+bytes;
b->endbit=bits;
b->endbyte=bytes;
*b->ptr|=mask[bits];
}
void oggpack_writealign(oggpack_buffer *b){
int bits=8-b->endbit;
if(bits<8)
oggpack_write(b,0,bits);
}
void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){
unsigned char *ptr=(unsigned char *)source;
long bytes=bits/8;
bits-=bytes*8;
if(b->endbit){
int i;
/* unaligned copy. Do it the hard way. */
for(i=0;i<bytes;i++)
oggpack_write(b,(long)(ptr[i]),8);
}else{
/* aligned block copy */
if(b->endbyte+bytes+1>=b->storage){
b->storage=b->endbyte+bytes+BUFFER_INCREMENT;
b->buffer=_ogg_realloc(b->buffer,b->storage);
b->ptr=b->buffer+b->endbyte;
}
memmove(b->ptr,source,bytes);
b->ptr+=bytes;
b->buffer+=bytes;
*b->ptr=0;
}
if(bits)
oggpack_write(b,(long)(ptr[bytes]),bits);
}
void oggpack_reset(oggpack_buffer *b){
b->ptr=b->buffer;
b->buffer[0]=0;
b->endbit=b->endbyte=0;
}
void oggpack_writeclear(oggpack_buffer *b){
_ogg_free(b->buffer);
memset(b,0,sizeof(*b));
}
void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){
memset(b,0,sizeof(*b));
b->buffer=b->ptr=buf;
b->storage=bytes;
}
/* Takes only up to 32 bits. */
void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){
if(b->endbyte+4>=b->storage){
b->buffer=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT);
b->storage+=BUFFER_INCREMENT;
b->ptr=b->buffer+b->endbyte;
}
value&=mask[bits];
bits+=b->endbit;
b->ptr[0]|=value<<b->endbit;
if(bits>=8){
b->ptr[1]=value>>(8-b->endbit);
if(bits>=16){
b->ptr[2]=value>>(16-b->endbit);
if(bits>=24){
b->ptr[3]=value>>(24-b->endbit);
if(bits>=32){
if(b->endbit)
b->ptr[4]=value>>(32-b->endbit);
else
b->ptr[4]=0;
}
}
}
}
b->endbyte+=bits/8;
b->ptr+=bits/8;
b->endbit=bits&7;
}
/* Read in bits without advancing the bitptr; bits <= 32 */
long oggpack_look(oggpack_buffer *b,int bits){
unsigned long ret;
unsigned long m=mask[bits];
bits+=b->endbit;
if(b->endbyte+4>=b->storage){
/* not the main path */
if(b->endbyte*8+bits>b->storage*8)return(-1);
}
ret=b->ptr[0]>>b->endbit;
if(bits>8){
ret|=b->ptr[1]<<(8-b->endbit);
if(bits>16){
ret|=b->ptr[2]<<(16-b->endbit);
if(bits>24){
ret|=b->ptr[3]<<(24-b->endbit);
if(bits>32 && b->endbit)
ret|=b->ptr[4]<<(32-b->endbit);
}
}
}
return(m&ret);
}
long oggpack_look1(oggpack_buffer *b){
if(b->endbyte>=b->storage)return(-1);
return((b->ptr[0]>>b->endbit)&1);
}
void oggpack_adv(oggpack_buffer *b,int bits){
bits+=b->endbit;
b->ptr+=bits/8;
b->endbyte+=bits/8;
b->endbit=bits&7;
}
void oggpack_adv1(oggpack_buffer *b){
if(++(b->endbit)>7){
b->endbit=0;
b->ptr++;
b->endbyte++;
}
}
/* bits <= 32 */
long oggpack_read(oggpack_buffer *b,int bits){
unsigned long ret;
unsigned long m=mask[bits];
bits+=b->endbit;
if(b->endbyte+4>=b->storage){
/* not the main path */
ret=-1UL;
if(b->endbyte*8+bits>b->storage*8)goto overflow;
}
ret=b->ptr[0]>>b->endbit;
if(bits>8){
ret|=b->ptr[1]<<(8-b->endbit);
if(bits>16){
ret|=b->ptr[2]<<(16-b->endbit);
if(bits>24){
ret|=b->ptr[3]<<(24-b->endbit);
if(bits>32 && b->endbit){
ret|=b->ptr[4]<<(32-b->endbit);
}
}
}
}
ret&=m;
overflow:
b->ptr+=bits/8;
b->endbyte+=bits/8;
b->endbit=bits&7;
return(ret);
}
long oggpack_read1(oggpack_buffer *b){
unsigned long ret;
if(b->endbyte>=b->storage){
/* not the main path */
ret=-1UL;
goto overflow;
}
ret=(b->ptr[0]>>b->endbit)&1;
overflow:
b->endbit++;
if(b->endbit>7){
b->endbit=0;
b->ptr++;
b->endbyte++;
}
return(ret);
}
long oggpack_bytes(oggpack_buffer *b){
return(b->endbyte+(b->endbit+7)/8);
}
long oggpack_bits(oggpack_buffer *b){
return(b->endbyte*8+b->endbit);
}
unsigned char *oggpack_get_buffer(oggpack_buffer *b){
return(b->buffer);
}
/* Self test of the bitwise routines; everything else is based on
them, so they damned well better be solid. */
#ifdef _V_SELFTEST
#include <stdio.h>
static int ilog(unsigned int v){
int ret=0;
while(v){
ret++;
v>>=1;
}
return(ret);
}
oggpack_buffer o;
oggpack_buffer r;
void report(char *in){
fprintf(stderr,"%s",in);
exit(1);
}
void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){
long bytes,i;
unsigned char *buffer;
oggpack_reset(&o);
for(i=0;i<vals;i++)
oggpack_write(&o,b[i],bits?bits:ilog(b[i]));
buffer=oggpack_get_buffer(&o);
bytes=oggpack_bytes(&o);
if(bytes!=compsize)report("wrong number of bytes!\n");
for(i=0;i<bytes;i++)if(buffer[i]!=comp[i]){
for(i=0;i<bytes;i++)fprintf(stderr,"%x %x\n",(int)buffer[i],(int)comp[i]);
report("wrote incorrect value!\n");
}
oggpack_readinit(&r,buffer,bytes);
for(i=0;i<vals;i++){
int tbit=bits?bits:ilog(b[i]);
if(oggpack_look(&r,tbit)==-1)
report("out of data!\n");
if(oggpack_look(&r,tbit)!=(b[i]&mask[tbit]))
report("looked at incorrect value!\n");
if(tbit==1)
if(oggpack_look1(&r)!=(b[i]&mask[tbit]))
report("looked at single bit incorrect value!\n");
if(tbit==1){
if(oggpack_read1(&r)!=(b[i]&mask[tbit]))
report("read incorrect single bit value!\n");
}else{
if(oggpack_read(&r,tbit)!=(b[i]&mask[tbit]))
report("read incorrect value!\n");
}
}
if(oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n");
}
int main(void){
unsigned char *buffer;
long bytes,i;
static unsigned long testbuffer1[]=
{18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7,
567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4};
int test1size=43;
static unsigned long testbuffer2[]=
{216531625L,1237861823,56732452,131,3212421,12325343,34547562,12313212,
1233432,534,5,346435231,14436467,7869299,76326614,167548585,
85525151,0,12321,1,349528352};
int test2size=21;
static unsigned long large[]=
{2136531625L,2137861823,56732452,131,3212421,12325343,34547562,12313212,
1233432,534,5,2146435231,14436467,7869299,76326614,167548585,
85525151,0,12321,1,2146528352};
static unsigned long testbuffer3[]=
{1,0,14,0,1,0,12,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,1,1,0,0,1,
0,1,30,1,1,1,0,0,1,0,0,0,12,0,11,0,1,0,0,1};
int test3size=56;
int onesize=33;
static int one[]={146,25,44,151,195,15,153,176,233,131,196,65,85,172,47,40,
34,242,223,136,35,222,211,86,171,50,225,135,214,75,172,
223,4};
int twosize=6;
static int two[]={61,255,255,251,231,29};
int threesize=54;
static int three[]={169,2,232,252,91,132,156,36,89,13,123,176,144,32,254,
142,224,85,59,121,144,79,124,23,67,90,90,216,79,23,83,
58,135,196,61,55,129,183,54,101,100,170,37,127,126,10,
100,52,4,14,18,86,77,1};
int foursize=38;
static int four[]={18,6,163,252,97,194,104,131,32,1,7,82,137,42,129,11,72,
132,60,220,112,8,196,109,64,179,86,9,137,195,208,122,169,
28,2,133,0,1};
int fivesize=45;
static int five[]={169,2,126,139,144,172,30,4,80,72,240,59,130,218,73,62,
241,24,210,44,4,20,0,248,116,49,135,100,110,130,181,169,
84,75,159,2,1,0,132,192,8,0,0,18,22};
int sixsize=7;
static int six[]={17,177,170,242,169,19,148};
/* Test read/write together */
/* Later we test against pregenerated bitstreams */
oggpack_writeinit(&o);
fprintf(stderr,"\nSmall preclipped packing: ");
cliptest(testbuffer1,test1size,0,one,onesize);
fprintf(stderr,"ok.");
fprintf(stderr,"\nNull bit call: ");
cliptest(testbuffer3,test3size,0,two,twosize);
fprintf(stderr,"ok.");
fprintf(stderr,"\nLarge preclipped packing: ");
cliptest(testbuffer2,test2size,0,three,threesize);
fprintf(stderr,"ok.");
fprintf(stderr,"\n32 bit preclipped packing: ");
oggpack_reset(&o);
for(i=0;i<test2size;i++)
oggpack_write(&o,large[i],32);
buffer=oggpack_get_buffer(&o);
bytes=oggpack_bytes(&o);
oggpack_readinit(&r,buffer,bytes);
for(i=0;i<test2size;i++){
if(oggpack_look(&r,32)==-1)report("out of data. failed!");
if(oggpack_look(&r,32)!=large[i]){
fprintf(stderr,"%ld != %ld (%lx!=%lx):",oggpack_look(&r,32),large[i],
oggpack_look(&r,32),large[i]);
report("read incorrect value!\n");
}
oggpack_adv(&r,32);
}
if(oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n");
fprintf(stderr,"ok.");
fprintf(stderr,"\nSmall unclipped packing: ");
cliptest(testbuffer1,test1size,7,four,foursize);
fprintf(stderr,"ok.");
fprintf(stderr,"\nLarge unclipped packing: ");
cliptest(testbuffer2,test2size,17,five,fivesize);
fprintf(stderr,"ok.");
fprintf(stderr,"\nSingle bit unclipped packing: ");
cliptest(testbuffer3,test3size,1,six,sixsize);
fprintf(stderr,"ok.");
fprintf(stderr,"\nTesting read past end: ");
oggpack_readinit(&r,"\0\0\0\0\0\0\0\0",8);
for(i=0;i<64;i++){
if(oggpack_read(&r,1)!=0){
fprintf(stderr,"failed; got -1 prematurely.\n");
exit(1);
}
}
if(oggpack_look(&r,1)!=-1 ||
oggpack_read(&r,1)!=-1){
fprintf(stderr,"failed; read past end without -1.\n");
exit(1);
}
oggpack_readinit(&r,"\0\0\0\0\0\0\0\0",8);
if(oggpack_read(&r,30)!=0 || oggpack_read(&r,16)!=0){
fprintf(stderr,"failed 2; got -1 prematurely.\n");
exit(1);
}
if(oggpack_look(&r,18)!=0 ||
oggpack_look(&r,18)!=0){
fprintf(stderr,"failed 3; got -1 prematurely.\n");
exit(1);
}
if(oggpack_look(&r,19)!=-1 ||
oggpack_look(&r,19)!=-1){
fprintf(stderr,"failed; read past end without -1.\n");
exit(1);
}
if(oggpack_look(&r,32)!=-1 ||
oggpack_look(&r,32)!=-1){
fprintf(stderr,"failed; read past end without -1.\n");
exit(1);
}
fprintf(stderr,"ok.\n\n");
return(0);
}
#endif /* _V_SELFTEST */
#undef BUFFER_INCREMENT

View File

@ -0,0 +1,10 @@
#ifndef __CONFIG_TYPES_H__
#define __CONFIG_TYPES_H__
/* these are filled in by configure */
typedef int16_t ogg_int16_t;
typedef int32_t ogg_int32_t;
typedef uint32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,184 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
function: toplevel libogg include
last mod: $Id: ogg.h,v 1.1 2003/12/13 20:12:32 shatty Exp $
********************************************************************/
#ifndef _OGG_H
#define _OGG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ogg/os_types.h>
typedef struct {
long endbyte;
int endbit;
unsigned char *buffer;
unsigned char *ptr;
long storage;
} oggpack_buffer;
/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
typedef struct {
unsigned char *header;
long header_len;
unsigned char *body;
long body_len;
} ogg_page;
/* ogg_stream_state contains the current encode/decode state of a logical
Ogg bitstream **********************************************************/
typedef struct {
unsigned char *body_data; /* bytes from packet bodies */
long body_storage; /* storage elements allocated */
long body_fill; /* elements stored; fill mark */
long body_returned; /* elements of fill returned */
int *lacing_vals; /* The values that will go to the segment table */
ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
this way, but it is simple coupled to the
lacing fifo */
long lacing_storage;
long lacing_fill;
long lacing_packet;
long lacing_returned;
unsigned char header[282]; /* working space for header encode */
int header_fill;
int e_o_s; /* set when we have buffered the last packet in the
logical bitstream */
int b_o_s; /* set after we've written the initial page
of a logical bitstream */
long serialno;
long pageno;
ogg_int64_t packetno; /* sequence number for decode; the framing
knows where there's a hole in the data,
but we need coupling so that the codec
(which is in a seperate abstraction
layer) also knows about the gap */
ogg_int64_t granulepos;
} ogg_stream_state;
/* ogg_packet is used to encapsulate the data and metadata belonging
to a single raw Ogg/Vorbis packet *************************************/
typedef struct {
unsigned char *packet;
long bytes;
long b_o_s;
long e_o_s;
ogg_int64_t granulepos;
ogg_int64_t packetno; /* sequence number for decode; the framing
knows where there's a hole in the data,
but we need coupling so that the codec
(which is in a seperate abstraction
layer) also knows about the gap */
} ogg_packet;
typedef struct {
unsigned char *data;
int storage;
int fill;
int returned;
int unsynced;
int headerbytes;
int bodybytes;
} ogg_sync_state;
/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/
extern void oggpack_writeinit(oggpack_buffer *b);
extern void oggpack_writetrunc(oggpack_buffer *b,long bits);
extern void oggpack_writealign(oggpack_buffer *b);
extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits);
extern void oggpack_reset(oggpack_buffer *b);
extern void oggpack_writeclear(oggpack_buffer *b);
extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits);
extern long oggpack_look(oggpack_buffer *b,int bits);
extern long oggpack_look1(oggpack_buffer *b);
extern void oggpack_adv(oggpack_buffer *b,int bits);
extern void oggpack_adv1(oggpack_buffer *b);
extern long oggpack_read(oggpack_buffer *b,int bits);
extern long oggpack_read1(oggpack_buffer *b);
extern long oggpack_bytes(oggpack_buffer *b);
extern long oggpack_bits(oggpack_buffer *b);
extern unsigned char *oggpack_get_buffer(oggpack_buffer *b);
/* Ogg BITSTREAM PRIMITIVES: encoding **************************/
extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op);
extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);
extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og);
/* Ogg BITSTREAM PRIMITIVES: decoding **************************/
extern int ogg_sync_init(ogg_sync_state *oy);
extern int ogg_sync_clear(ogg_sync_state *oy);
extern int ogg_sync_reset(ogg_sync_state *oy);
extern int ogg_sync_destroy(ogg_sync_state *oy);
extern char *ogg_sync_buffer(ogg_sync_state *oy, long size);
extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes);
extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
/* Ogg BITSTREAM PRIMITIVES: general ***************************/
extern int ogg_stream_init(ogg_stream_state *os,int serialno);
extern int ogg_stream_clear(ogg_stream_state *os);
extern int ogg_stream_reset(ogg_stream_state *os);
extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
extern int ogg_stream_destroy(ogg_stream_state *os);
extern int ogg_stream_eos(ogg_stream_state *os);
extern void ogg_page_checksum_set(ogg_page *og);
extern int ogg_page_version(ogg_page *og);
extern int ogg_page_continued(ogg_page *og);
extern int ogg_page_bos(ogg_page *og);
extern int ogg_page_eos(ogg_page *og);
extern ogg_int64_t ogg_page_granulepos(ogg_page *og);
extern int ogg_page_serialno(ogg_page *og);
extern long ogg_page_pageno(ogg_page *og);
extern int ogg_page_packets(ogg_page *og);
extern void ogg_packet_clear(ogg_packet *op);
#ifdef __cplusplus
}
#endif
#endif /* _OGG_H */

View File

@ -0,0 +1,84 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
* by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
function: #ifdef jail to whip a few platforms into the UNIX ideal.
last mod: $Id: os_types.h,v 1.1 2003/12/13 20:12:32 shatty Exp $
********************************************************************/
#ifndef _OS_TYPES_H
#define _OS_TYPES_H
/* make it easy on the folks that want to compile the libs with a
different malloc than stdlib */
#define _ogg_malloc malloc
#define _ogg_calloc calloc
#define _ogg_realloc realloc
#define _ogg_free free
#ifdef _WIN32
# ifndef __GNUC__
/* MSVC/Borland */
typedef __int64 ogg_int64_t;
typedef __int32 ogg_int32_t;
typedef unsigned __int32 ogg_uint32_t;
typedef __int16 ogg_int16_t;
# else
/* Cygwin */
#include <_G_config.h>
typedef _G_int64_t ogg_int64_t;
typedef _G_int32_t ogg_int32_t;
typedef _G_uint32_t ogg_uint32_t;
typedef _G_int16_t ogg_int16_t;
# endif
#elif defined(__MACOS__)
# include <sys/types.h>
typedef SInt16 ogg_int16_t;
typedef SInt32 ogg_int32_t;
typedef UInt32 ogg_uint32_t;
typedef SInt64 ogg_int64_t;
#elif defined(__MACOSX__) /* MacOS X Framework build */
# include <sys/types.h>
typedef int16_t ogg_int16_t;
typedef int32_t ogg_int32_t;
typedef u_int32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
#elif defined(__BEOS__)
/* Be */
# include <inttypes.h>
typedef int16_t ogg_int16_t;
typedef int32_t ogg_int32_t;
typedef u_int32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
#elif defined (__EMX__)
/* OS/2 GCC */
typedef short ogg_int16_t;
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long ogg_int64_t;
#else
# include <sys/types.h>
# include <ogg/config_types.h>
#endif
#endif /* _OS_TYPES_H */