fix brain-dead branching

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6750 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shatty
2004-02-26 08:16:53 +00:00
parent d836ffd41a
commit 4a673a0246
6 changed files with 0 additions and 1613 deletions
-238
View File
@@ -1,238 +0,0 @@
#include "OggCodecs.h"
#include <MediaFormats.h>
#include <stdio.h>
#define TRACE_THIS 0
#if TRACE_THIS
#define TRACE printf
#else
#define TRACE(a...) ((void)0)
#endif
/**
* Useful ogg_packet functions
*/
bool
BPrivate::media::findIdentifier(const ogg_packet & packet, const char * id, uint pos)
{
TRACE("findIdentifier\n");
uint length = strlen(id);
if ((unsigned)packet.bytes < pos+length) {
return false;
}
return !memcmp(&packet.packet[pos], id, length);
}
/**
* OggCodec implementations
*/
OggCodec::OggCodec()
: fCurrentFrame(-1),
fCurrentTime(0),
fOldFrame(-1),
fOldGranulePos(-1),
fInitCheck(B_NO_INIT),
fPacketData(NULL)
{
}
/* virtual */
OggCodec::~OggCodec()
{
delete fPacketData;
}
/* virtual */ bool
OggCodec::IsHeaderPacket(const ogg_packet & packet, uint packetno) const
{
return (packetno == 0);
}
/* virtual */ status_t
OggCodec::HandlePacket(const ogg_packet & packet)
{
TRACE("OggCodec::HandlePacket\n");
if (!IsHeaderPacket(packet, (fInitCheck == B_OK ? 1 : 0))) {
return B_BAD_VALUE;
}
if (!packet.b_o_s) {
TRACE("OggCodec::HandlePacket failed : not beginning of stream\n");
return B_ERROR; // first packet was not beginning of stream
}
// parse header packet
uint32 four_bytes = *(uint32*)(&packet);
// get the format for the description
media_format_description description;
description.family = B_MISC_FORMAT_FAMILY;
description.u.misc.file_format = 'OggS';
description.u.misc.codec = four_bytes;
BMediaFormats formats;
if (formats.InitCheck() == B_OK) {
formats.GetFormatFor(description, &fMediaFormat);
}
// fill out format from header packet
fMediaFormat.user_data_type = B_CODEC_TYPE_INFO;
strncpy((char*)fMediaFormat.user_data, (char*)(&packet), 4);
fPacketData = new unsigned char[packet.bytes];
if (fPacketData == NULL) {
return B_NO_MEMORY;
}
memcpy(fPacketData, packet.packet, packet.bytes);
ogg_packet copy = packet;
copy.packet = fPacketData;
fMediaFormat.SetMetaData(&copy,sizeof(copy));
fInitCheck = B_OK;
return B_OK;
}
/* virtual */ status_t
OggCodec::GetFormat(media_format * format) const
{
if (format == 0) {
return B_BAD_VALUE;
}
if (fInitCheck != B_OK) {
return fInitCheck;
}
*format = fMediaFormat;
return B_OK;
}
/* virtual */ int64
OggCodec::GranulesToFrames(int64 granules) const
{
return granules;
}
/* virtual */ int64
OggCodec::FramesToGranules(int64 frames) const
{
return frames;
}
/* virtual */ status_t
OggCodec::GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
int result;
while ((result = ogg_stream_packetout(stream, &fChunkPacket)) < 0) {
// ignore previous packet fragments
}
if (result == 0) {
return B_BUFFER_NOT_AVAILABLE;
}
*chunkBuffer = &fChunkPacket;
*chunkSize = sizeof(fChunkPacket);
mediaHeader->start_time = fCurrentTime;
ogg_int64_t granulepos = fChunkPacket.granulepos;
if (streaming) {
if (granulepos < 0) {
fCurrentFrame = -1;
} else {
fCurrentFrame = fOldFrame + GranulesToFrames(granulepos)
- GranulesToFrames(fOldGranulePos);
fOldFrame = fCurrentFrame;
fOldGranulePos = granulepos;
}
} else {
debugger("explode");
}
// default (silly) 1 frame/sec
fCurrentTime = 1000000LL * fCurrentFrame;
return B_OK;
}
/**
* OggCodecTest implementations
*/
OggCodecTest::OggCodecTest()
{
TRACE("OggCodecTest::OggCodecTest\n");
OggCodecRoster * roster = OggCodecRoster::Roster();
if (roster != NULL) {
roster->AddCodecTest(this);
}
}
/* virtual */
OggCodecTest::~OggCodecTest()
{
TRACE("OggCodecTest::~OggCodecTest\n");
}
/**
* OggCodecRoster implementations
*/
/* static */ OggCodecRoster *
OggCodecRoster::Roster(status_t * outError)
{
TRACE("OggCodecRoster::Roster\n");
static OggCodecRoster * ogg_codec_roster = NULL;
if (ogg_codec_roster == NULL) {
ogg_codec_roster = new OggCodecRoster();
if ((ogg_codec_roster == NULL) && (outError != NULL)) {
*outError = B_NO_MEMORY;
}
}
return ogg_codec_roster;
}
status_t
OggCodecRoster::AddCodecTest(const OggCodecTest * test)
{
TRACE("OggCodecRoster::AddCodecTest\n");
fCodecs.push_back(test);
return B_OK;
}
OggCodec *
OggCodecRoster::CodecFor(const ogg_packet & packet) const
{
TRACE("OggCodecRoster::CodecFor\n");
std::vector<const OggCodecTest *>::const_iterator iter;
for(iter = fCodecs.begin() ; iter != fCodecs.end() ; iter++) {
const OggCodecTest * test = *iter;
if (test->RecognizesInitialPacket(packet)) {
return test->InstantiateCodec();
}
}
return NULL;
}
OggCodecRoster::OggCodecRoster()
{
TRACE("OggCodecRoster::OggCodecRoster\n");
}
OggCodecRoster::~OggCodecRoster()
{
TRACE("OggCodecRoster::~OggCodecRoster\n");
}
-93
View File
@@ -1,93 +0,0 @@
#ifndef _OGG_CODECS_H
#define _OGG_CODECS_H
#include <SupportDefs.h>
#include <MediaDefs.h>
#include "ogg/ogg.h"
#include <vector>
namespace BPrivate { namespace media {
/**
* Useful ogg_packet functions
*/
bool findIdentifier(const ogg_packet & packet, const char * id, uint pos);
/**
* OggCodec
*
* An OggCodec is instantiated to assist an OggTrack with interacting with the codecs.
* It helps with seeking, timing, and transforming the ogg_packets into chunks.
*/
class OggCodec {
public:
OggCodec();
virtual ~OggCodec();
virtual bool IsHeaderPacket(const ogg_packet & packet, uint packetno) const;
virtual status_t HandlePacket(const ogg_packet & packet);
virtual status_t GetFormat(media_format * format) const;
virtual int64 GranulesToFrames(int64 granules) const;
virtual int64 FramesToGranules(int64 frames) const;
virtual status_t GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader);
protected:
ogg_packet fChunkPacket;
int64 fCurrentFrame;
bigtime_t fCurrentTime;
int64 fOldFrame;
ogg_int64_t fOldGranulePos;
media_format fMediaFormat;
status_t fInitCheck;
private:
unsigned char * fPacketData;
};
/**
* OggCodecTest
*
* An OggCodecTest is capable of determining if an initial packet belongs to a
* particular codec. It can instantiate that particular codec.
*/
class OggCodecTest {
protected:
OggCodecTest();
public:
virtual ~OggCodecTest();
virtual bool RecognizesInitialPacket(const ogg_packet & packet) const = 0;
virtual OggCodec * InstantiateCodec() const = 0;
};
/**
* OggCodecRoster
*
* An OggCodecRoster provides a single location to register OggCodecTests
* and retrieve an appropriate OggCodec for an ogg_packet.
*/
class OggCodecRoster {
public:
static OggCodecRoster * Roster(status_t * outError = NULL);
status_t AddCodecTest(const OggCodecTest * wrapper);
OggCodec * CodecFor(const ogg_packet & packet) const;
private:
OggCodecRoster();
~OggCodecRoster();
std::vector<const OggCodecTest *> fCodecs;
};
} } // BPrivate::media
using namespace BPrivate::media;
#endif // _OGG_CODECS_H
@@ -1,228 +0,0 @@
#include "OggSpeexFormats.h"
#include "OggCodecs.h"
#include <stdio.h>
#define TRACE_THIS 1
#if TRACE_THIS
#define TRACE printf
#else
#define TRACE(a...) ((void)0)
#endif
inline size_t
AudioBufferSize(media_raw_audio_format * raf, bigtime_t buffer_duration = 50000 /* 50 ms */)
{
return (raf->format & 0xf) * (raf->channel_count)
* (size_t)((raf->frame_rate * buffer_duration) / 1000000.0);
}
/*
* speex header from libspeex/speex_header.h
* also documented at http://www.speex.org/manual/node7.html#SECTION00073000000000000000
*/
typedef struct SpeexHeader {
char speex_string[8]; /**< Identifies a Speex bit-stream, always set to "Speex " */
char speex_version[20]; /**< Speex version */
int speex_version_id; /**< Version for Speex (for checking compatibility) */
int header_size; /**< Total size of the header ( sizeof(SpeexHeader) ) */
int rate; /**< Sampling rate used */
int mode; /**< Mode used (0 for narrowband, 1 for wideband) */
int mode_bitstream_version; /**< Version ID of the bit-stream */
int nb_channels; /**< Number of channels encoded */
int bitrate; /**< Bit-rate used */
int frame_size; /**< Size of frames */
int vbr; /**< 1 for a VBR encoding, 0 otherwise */
int frames_per_packet; /**< Number of frames stored per Ogg packet */
int extra_headers; /**< Number of additional headers after the comments */
int reserved1; /**< Reserved for future use, must be zero */
int reserved2; /**< Reserved for future use, must be zero */
} SpeexHeader;
/*
* OggSpeexCodec implementations
*/
class OggSpeexCodec : public OggCodec {
public:
OggSpeexCodec();
virtual ~OggSpeexCodec();
virtual bool IsHeaderPacket(const ogg_packet & packet, uint packetno) const;
virtual status_t HandlePacket(const ogg_packet & packet);
virtual status_t GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader);
private:
std::vector<ogg_packet> fMetaDataPackets;
unsigned char * fHeaderPacketData;
unsigned char * fCommentPacketData;
std::vector<uchar *> fExtraPacketData;
unsigned int fPacketCount;
unsigned int fExtraHeadersField;
};
OggSpeexCodec::OggSpeexCodec()
{
TRACE("OggSpeexCodec::OggSpeexCodec\n");
fHeaderPacketData = NULL;
fCommentPacketData = NULL;
fPacketCount = 0;
}
OggSpeexCodec::~OggSpeexCodec()
{
TRACE("OggSpeexCodec::~OggSpeexCodec\n");
delete fHeaderPacketData;
delete fCommentPacketData;
std::vector<uchar *>::iterator iter;
for (iter = fExtraPacketData.begin() ; iter != fExtraPacketData.end() ; iter++) {
uchar * data = *iter;
delete data;
}
}
/* virtual */ bool
OggSpeexCodec::IsHeaderPacket(const ogg_packet & packet, uint packetno) const
{
if (packetno < 2) {
return true;
}
if (fPacketCount == 0) {
debugger("IsHeaderPacket called for packetno >= 2, before receiving the header packet");
return false;
}
return (packetno < 2 + fExtraHeadersField);
}
/* virtual */ status_t
OggSpeexCodec::HandlePacket(const ogg_packet & packet)
{
TRACE("OggSpeexCodec::HandlePacket\n");
if (!IsHeaderPacket(packet, fPacketCount)) {
return B_BAD_VALUE;
}
switch (fPacketCount) {
case 0: {
// header packet
if (!packet.b_o_s) {
return B_ERROR; // first packet was not beginning of stream
}
// parse header packet, check size against struct minus optional fields
if (packet.bytes < 1 + (signed)sizeof(SpeexHeader) - 2*(signed)sizeof(int)) {
return B_ERROR;
}
void * data = &(packet.packet[0]);
SpeexHeader * header = (SpeexHeader *)data;
// store how many extra header packets
fExtraHeadersField = header->extra_headers;
// get the format for the description
media_format_description description = speex_description();
BMediaFormats formats;
if ((formats.InitCheck() != B_OK) ||
(formats.GetFormatFor(description, &fMediaFormat) != B_OK)) {
fMediaFormat = speex_encoded_media_format();
}
// fill out format from header packet
if (header->bitrate > 0) {
fMediaFormat.u.encoded_audio.bit_rate = header->bitrate;
} else {
// TODO: manually compute it where possible
}
if (header->nb_channels == 1) {
fMediaFormat.u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT;
} else {
fMediaFormat.u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT;
}
fMediaFormat.u.encoded_audio.output.frame_rate = header->rate;
fMediaFormat.u.encoded_audio.output.channel_count = header->nb_channels;
// allocate buffer, round up to nearest speex output_length size
int buffer_size = AudioBufferSize(&fMediaFormat.u.encoded_audio.output);
int output_length = header->frame_size * header->nb_channels *
(fMediaFormat.u.encoded_audio.output.format & 0xf);
buffer_size = ((buffer_size - 1) / output_length + 1) * output_length;
fMediaFormat.u.encoded_audio.output.buffer_size = buffer_size;
fHeaderPacketData = new unsigned char[packet.bytes];
memcpy(fHeaderPacketData, packet.packet, packet.bytes);
fMetaDataPackets.push_back(packet);
fMetaDataPackets[fPacketCount].packet = fHeaderPacketData;
break;
}
case 1: {
// comment packet
fCommentPacketData = new unsigned char[packet.bytes];
memcpy(fCommentPacketData, packet.packet, packet.bytes);
fMetaDataPackets.push_back(packet);
fMetaDataPackets[fPacketCount].packet = fCommentPacketData;
break;
}
default:
// extra headers
uchar * extraHeaderData = new unsigned char[packet.bytes];
memcpy(extraHeaderData, packet.packet, packet.bytes);
fExtraPacketData.push_back(extraHeaderData);
fMetaDataPackets.push_back(packet);
fMetaDataPackets[fPacketCount].packet = extraHeaderData;
break;
}
if (fPacketCount == 1 + fExtraHeadersField) {
fMediaFormat.SetMetaData(&fMetaDataPackets,sizeof(fMetaDataPackets));
fInitCheck = B_OK;
}
fPacketCount++;
return B_OK;
}
/* virtual */ status_t
OggSpeexCodec::GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
if (fCurrentFrame == -1) {
fCurrentTime = -1;
} else {
fCurrentTime = (1000000LL * fCurrentFrame)
/ (long long)fMediaFormat.u.encoded_audio.output.frame_rate;
}
status_t result = OggCodec::GetChunk(stream, streaming, chunkBuffer, chunkSize, mediaHeader);
if (result != B_OK) {
return result;
}
*chunkBuffer = fChunkPacket.packet;
*chunkSize = fChunkPacket.bytes;
return B_OK;
}
/*
* OggSpeexCodecTest
*/
static class OggSpeexCodecTest : public OggCodecTest {
public:
OggSpeexCodecTest() {}
virtual ~OggSpeexCodecTest() {}
virtual bool RecognizesInitialPacket(const ogg_packet & packet) const
{
return findIdentifier(packet, "Speex ", 0);
}
virtual OggCodec * InstantiateCodec() const
{
return new OggSpeexCodec();
}
} ogg_speex_codec_test;
@@ -1,327 +0,0 @@
#include "OggTheoraFormats.h"
#include "OggCodecs.h"
#include <stdio.h>
#define TRACE_THIS 1
#if TRACE_THIS
#define TRACE printf
#else
#define TRACE(a...) ((void)0)
#endif
/*
* theora header parsing code from theora/theara.h
*/
typedef enum {
OC_CS_UNSPECIFIED,
OC_CS_ITU_REC_470M,
OC_CS_ITU_REC_470BG,
} theora_colorspace;
typedef struct {
ogg_uint32_t width;
ogg_uint32_t height;
ogg_uint32_t frame_width;
ogg_uint32_t frame_height;
ogg_uint32_t offset_x;
ogg_uint32_t offset_y;
ogg_uint32_t fps_numerator;
ogg_uint32_t fps_denominator;
ogg_uint32_t aspect_numerator;
ogg_uint32_t aspect_denominator;
theora_colorspace colorspace;
int target_bitrate;
int quality;
int quick_p; /* quick encode/decode */
/* decode only */
unsigned char version_major;
unsigned char version_minor;
unsigned char version_subminor;
void *codec_setup;
/* encode only */
int dropframes_p;
int keyframe_auto_p;
ogg_uint32_t keyframe_frequency;
ogg_uint32_t keyframe_frequency_force; /* also used for decode init to
get granpos shift correct */
ogg_uint32_t keyframe_data_target_bitrate;
ogg_int32_t keyframe_auto_threshold;
ogg_uint32_t keyframe_mindistance;
ogg_int32_t noise_sensitivity;
ogg_int32_t sharpness;
} theora_info;
typedef struct theora_comment{
char **user_comments;
int *comment_lengths;
int comments;
char *vendor;
} theora_comment;
// based on theora/lib/toplevel.c _theora_unpack_info
#define theora_read(x,y,z) ( *z = oggpackB_read(x,y) )
#define OC_BADHEADER -1
static int _theora_unpack_info(theora_info *ci, oggpack_buffer *opb){
long ret;
theora_read(opb,8,&ret);
ci->version_major=(unsigned char)ret;
theora_read(opb,8,&ret);
ci->version_minor=(unsigned char)ret;
theora_read(opb,8,&ret);
ci->version_subminor=(unsigned char)ret;
// if(ci->version_major!=VERSION_MAJOR)return(OC_VERSION);
// if(ci->version_minor>VERSION_MINOR)return(OC_VERSION);
theora_read(opb,16,&ret);
ci->width=ret<<4;
theora_read(opb,16,&ret);
ci->height=ret<<4;
theora_read(opb,24,&ret);
ci->frame_width=ret;
theora_read(opb,24,&ret);
ci->frame_height=ret;
theora_read(opb,8,&ret);
ci->offset_x=ret;
theora_read(opb,8,&ret);
ci->offset_y=ret;
theora_read(opb,32,&ret);
ci->fps_numerator=ret;
theora_read(opb,32,&ret);
ci->fps_denominator=ret;
theora_read(opb,24,&ret);
ci->aspect_numerator=ret;
theora_read(opb,24,&ret);
ci->aspect_denominator=ret;
theora_read(opb,8,&ret);
ci->colorspace=(theora_colorspace)ret;
theora_read(opb,24,&ret);
ci->target_bitrate=ret;
theora_read(opb,6,&ret);
ci->quality=ret=ret;
theora_read(opb,5,&ret);
ci->keyframe_frequency_force=1<<ret;
/* spare configuration bits */
if ( theora_read(opb,5,&ret) == -1 )
return (OC_BADHEADER);
return(0);
}
/*
* OggTheoraCodec
*/
class OggTheoraCodec : public OggCodec {
public:
OggTheoraCodec();
virtual ~OggTheoraCodec();
virtual bool IsHeaderPacket(const ogg_packet & packet, uint packetno) const;
virtual status_t HandlePacket(const ogg_packet & packet);
virtual status_t GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader);
private:
std::vector<ogg_packet> fMetaDataPackets;
unsigned char * fHeaderPacketData;
unsigned char * fCommentPacketData;
unsigned char * fCodecPacketData;
unsigned int fPacketCount;
};
OggTheoraCodec::OggTheoraCodec()
{
TRACE("OggTheoraCodec::OggTheoraCodec\n");
fHeaderPacketData = NULL;
fCommentPacketData = NULL;
fCodecPacketData = NULL;
fPacketCount = 0;
}
OggTheoraCodec::~OggTheoraCodec()
{
delete fHeaderPacketData;
delete fCommentPacketData;
delete fCodecPacketData;
}
/* virtual */ bool
OggTheoraCodec::IsHeaderPacket(const ogg_packet & packet, uint packetno) const
{
oggpack_buffer opb;
oggpackB_readinit(&opb, packet.packet, packet.bytes);
uint packtype = oggpackB_read(&opb, 8);
return (packetno == 0 && packtype == 0x80)
|| (packetno == 1 && packtype == 0x81)
|| (packetno == 2 && packtype == 0x82);
}
/* virtual */ status_t
OggTheoraCodec::HandlePacket(const ogg_packet & packet)
{
TRACE("OggTheoraCodec::HandlePacket\n");
if (!IsHeaderPacket(packet, fPacketCount)) {
return B_BAD_VALUE;
}
switch (fPacketCount) {
case 0: {
// header packet
if (!packet.b_o_s) {
return B_ERROR; // first packet was not beginning of stream
}
// parse header packet
// based on libvorbis/info.c vorbis_synthesis_headerin(...)
oggpack_buffer opb;
oggpackB_readinit(&opb, packet.packet, packet.bytes);
// discard packet type (already validated in IsHeaderPacket)
oggpackB_read(&opb, 8);
// discard theora string
for (uint i = 0 ; i < sizeof("theora") - 1 ; i++) {
oggpackB_read(&opb, 8);
}
theora_info info;
if (_theora_unpack_info(&info, &opb) != 0) {
return B_ERROR; // couldn't unpack info
}
// get the format for the description
media_format_description description = theora_description();
BMediaFormats formats;
if ((formats.InitCheck() != B_OK) ||
(formats.GetFormatFor(description, &fMediaFormat) != B_OK)) {
fMediaFormat = theora_encoded_media_format();
}
// fill out format from header packet
// sanity check
if (info.fps_denominator != 0) {
fMediaFormat.u.encoded_video.output.field_rate =
(double)info.fps_numerator / (double)info.fps_denominator;
}
fMediaFormat.u.encoded_video.output.first_active = info.offset_y;
fMediaFormat.u.encoded_video.output.last_active = info.offset_y + info.height;
fMediaFormat.u.encoded_video.output.pixel_width_aspect = info.aspect_numerator;
fMediaFormat.u.encoded_video.output.pixel_height_aspect = info.aspect_denominator;
fMediaFormat.u.encoded_video.output.display.line_width = info.frame_width;
fMediaFormat.u.encoded_video.output.display.line_count = info.frame_height;
fMediaFormat.u.encoded_video.avg_bit_rate = info.target_bitrate; // advisory only
fMediaFormat.u.encoded_video.frame_size = info.width * info.height;
// TODO: wring more info out of the headers
fHeaderPacketData = new unsigned char[packet.bytes];
memcpy(fHeaderPacketData, packet.packet, packet.bytes);
fMetaDataPackets.push_back(packet);
fMetaDataPackets[fPacketCount].packet = fHeaderPacketData;
break;
}
case 1: {
// comment packet
fCommentPacketData = new unsigned char[packet.bytes];
memcpy(fCommentPacketData, packet.packet, packet.bytes);
fMetaDataPackets.push_back(packet);
fMetaDataPackets[fPacketCount].packet = fCommentPacketData;
break;
}
case 2: {
// codec setup packet
fCodecPacketData = new unsigned char[packet.bytes];
memcpy(fCodecPacketData, packet.packet, packet.bytes);
fMetaDataPackets.push_back(packet);
fMetaDataPackets[fPacketCount].packet = fCodecPacketData;
fMediaFormat.SetMetaData(&fMetaDataPackets,sizeof(fMetaDataPackets));
fInitCheck = B_OK;
break;
}
default:
// huh?
break;
}
fPacketCount++;
return B_OK;
}
/* virtual */ status_t
OggTheoraCodec::GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
if (streaming) {
if (fChunkPacket.granulepos == -1) {
fCurrentTime = -1;
} else {
fCurrentTime = (bigtime_t) ((1000000LL * fCurrentFrame)
/ (fMediaFormat.u.encoded_video.output.field_rate *
fMediaFormat.u.encoded_video.output.interlace));
}
} else {
debugger("kaboom");
}
status_t result = OggCodec::GetChunk(stream, streaming, chunkBuffer, chunkSize, mediaHeader);
if (result != B_OK) {
return result;
}
oggpack_buffer opb;
oggpackB_readinit(&opb, fChunkPacket.packet, fChunkPacket.bytes);
// Read 1 bit. This must be 0 for all data packets.
uint packtype = oggpackB_read(&opb, 1);
if (packtype != 0) {
// packet was not a data packet
return B_ERROR;
}
// read 1 bit (frametype) this is 0 for keyframes, 1 for P frames.
uint keyframe = oggpackB_read(&opb, 1);
// read 6 bits (quality mask) this is the quality index for this frame.
// uint quality = oggpackB_read(&opb, 6);
/*
if the frametype is 0 (keyframe):
read 1 bit (keyframetype) this indicates the coding variety of the keyframe.
read 2 bits (spare) these bits are unused.
*/
mediaHeader->u.encoded_video.field_number = fCurrentFrame;
mediaHeader->u.encoded_video.field_flags = (keyframe == 1 ? B_MEDIA_KEY_FRAME : 0);
return result;
}
/*
* OggTheoraCodecWrapper
*/
static class OggTheoraCodecTest : public OggCodecTest {
public:
OggTheoraCodecTest() {}
virtual ~OggTheoraCodecTest() {}
virtual bool RecognizesInitialPacket(const ogg_packet & packet) const
{
return findIdentifier(packet, "theora", 1);
}
virtual OggCodec * InstantiateCodec() const
{
return new OggTheoraCodec();
}
} ogg_theora_codec_test;
@@ -1,465 +0,0 @@
#include "OggTobiasFormats.h"
#include "OggCodecs.h"
#include <stdio.h>
#define TRACE_THIS 1
#if TRACE_THIS
#define TRACE printf
#else
#define TRACE(a...) ((void)0)
#endif
/*
* tobias header structs from http://tobias.everwicked.com/packfmt.htm
*/
typedef struct tobias_stream_header_video
{
ogg_int32_t width;
ogg_int32_t height;
} tobias_stream_header_video;
typedef struct tobias_stream_header_audio
{
ogg_int16_t channels;
ogg_int16_t blockalign;
ogg_int32_t avgbytespersec;
} tobias_stream_header_audio;
typedef struct tobias_stream_header
{
char streamtype[8];
char subtype[4];
ogg_int32_t size; // size of the structure
ogg_int64_t time_unit; // in reference time (100 ns units)
ogg_int64_t samples_per_unit;
ogg_int32_t default_len; // in media time
ogg_int32_t buffersize;
ogg_int16_t bits_per_sample;
union {
// Video specific
tobias_stream_header_video video;
// Audio specific
tobias_stream_header_audio audio;
};
} tobias_stream_header;
/*
static int64
count_granules(const ogg_packet & packet)
{
// thanks to Marcus:
int lenbytes = ((packet.packet[0] & 0xc0) >> 6) | ((packet.packet[0] & 0x02) << 1);
if (lenbytes == 0) {
return 1;
}
int64 granules = 0;
int count = 0;
// fprintf(stderr, "lenbytes = %d, ", lenbytes);
while (lenbytes-- > 0) {
granules += ((uint8*)packet.packet)[count+1] * (1LL << 8 * count);
count++;
}
// fprintf(stderr, "granules = %lld\n", granules);
return granules;
}
*/
/*
* OggTobiasCodec
*/
class OggTobiasCodec : public OggCodec {
public:
OggTobiasCodec() {}
virtual ~OggTobiasCodec() {}
virtual bool IsHeaderPacket(const ogg_packet & packet, uint packetno) const;
virtual status_t HandlePacket(const ogg_packet & packet);
protected:
virtual status_t HeaderToFormat(const tobias_stream_header & header) = 0;
std::vector<ogg_packet> fMetaDataPackets;
unsigned char * fHeaderPacketData;
unsigned char * fCommentPacketData;
unsigned int fPacketCount;
};
/* virtual */ bool
OggTobiasCodec::IsHeaderPacket(const ogg_packet & packet, uint packetno) const
{
oggpack_buffer opb;
oggpack_readinit(&opb, packet.packet, packet.bytes);
uint packtype = oggpack_read(&opb, 8);
return (packetno == 0 && packtype == 0x01)
|| (packetno == 1 && packtype == 0x03);
}
/* virtual */ status_t
OggTobiasCodec::HandlePacket(const ogg_packet & packet)
{
TRACE("OggTobiasCodec::HandlePacket\n");
if (!IsHeaderPacket(packet, fPacketCount)) {
return B_ERROR;
}
switch (fPacketCount) {
case 0: {
if (!packet.b_o_s) {
return B_ERROR; // first packet was not beginning of stream
}
// parse header packet
if (packet.bytes < 1+(signed)sizeof(tobias_stream_header)) {
return B_ERROR;
}
void * data = &(packet.packet[1]);
tobias_stream_header * header = (tobias_stream_header *)data;
status_t result = HeaderToFormat(*header);
if (result != B_OK) {
return result;
}
// initialize codec info
fMediaFormat.user_data_type = B_CODEC_TYPE_INFO;
strncpy((char*)fMediaFormat.user_data, header->subtype, 4);
// save the header packet for use in meta data
fHeaderPacketData = new unsigned char[packet.bytes];
memcpy(fHeaderPacketData, packet.packet, packet.bytes);
fMetaDataPackets.push_back(packet);
fMetaDataPackets[fPacketCount].packet = fHeaderPacketData;
break;
}
case 1: {
// save the comment packet for use in meta data
fCommentPacketData = new unsigned char[packet.bytes];
memcpy(fCommentPacketData, packet.packet, packet.bytes);
fMetaDataPackets.push_back(packet);
fMetaDataPackets[fPacketCount].packet = fCommentPacketData;
// ready for showtime
fInitCheck = B_OK;
fMediaFormat.SetMetaData(&fMetaDataPackets,sizeof(fMetaDataPackets));
break;
}
default:
// huh?
break;
}
fPacketCount++;
return B_OK;
}
/*
* OggTobiasVideoCodec
*/
class OggTobiasVideoCodec : public OggTobiasCodec {
public:
OggTobiasVideoCodec();
virtual ~OggTobiasVideoCodec();
virtual status_t GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader);
protected:
virtual status_t HeaderToFormat(const tobias_stream_header & header);
};
OggTobiasVideoCodec::OggTobiasVideoCodec()
{
TRACE("OggTobiasVideoCodec::OggTobiasVideoCodec\n");
}
OggTobiasVideoCodec::~OggTobiasVideoCodec()
{
TRACE("OggTobiasVideoCodec::~OggTobiasVideoCodec\n");
}
/* virtual */ status_t
OggTobiasVideoCodec::HeaderToFormat(const tobias_stream_header & header)
{
TRACE("OggTobiasVideoCodec::HeaderToFormat\n");
// get the format for the description
media_format_description description = tobias_video_description();
description.u.avi.codec = header.subtype[3] << 24 | header.subtype[2] << 16
| header.subtype[1] << 8 | header.subtype[0];
BMediaFormats formats;
if ((formats.InitCheck() != B_OK) ||
(formats.GetFormatFor(description, &fMediaFormat) != B_OK)) {
fMediaFormat = tobias_video_encoded_media_format();
}
// fill out format from header packet
fMediaFormat.u.encoded_video.frame_size
= header.video.width * header.video.height;
fMediaFormat.u.encoded_video.output.field_rate = 10000000.0 / header.time_unit;
fMediaFormat.u.encoded_video.output.interlace = 1;
fMediaFormat.u.encoded_video.output.first_active = 0;
fMediaFormat.u.encoded_video.output.last_active = header.video.height - 1;
fMediaFormat.u.encoded_video.output.orientation = B_VIDEO_TOP_LEFT_RIGHT;
fMediaFormat.u.encoded_video.output.pixel_width_aspect = 1;
fMediaFormat.u.encoded_video.output.pixel_height_aspect = 1;
fMediaFormat.u.encoded_video.output.display.line_width = header.video.width;
fMediaFormat.u.encoded_video.output.display.line_count = header.video.height;
fMediaFormat.u.encoded_video.output.display.bytes_per_row = 0;
fMediaFormat.u.encoded_video.output.display.pixel_offset = 0;
fMediaFormat.u.encoded_video.output.display.line_offset = 0;
fMediaFormat.u.encoded_video.output.display.flags = 0;
// TODO: wring more info out of the headers?
return B_OK;
}
/* virtual */ status_t
OggTobiasVideoCodec::GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
status_t result = OggCodec::GetChunk(stream, streaming, chunkBuffer, chunkSize, mediaHeader);
if (result != B_OK) {
return result;
}
if (streaming) {
if (fChunkPacket.granulepos == -1) {
int new_granulepos = fOldGranulePos + 1;
fCurrentFrame = fOldFrame + GranulesToFrames(new_granulepos)
- GranulesToFrames(fOldGranulePos);
fOldFrame = fCurrentFrame;
fOldGranulePos = new_granulepos;
} else {
// fprintf(stderr, "granulepos: %lld ", fChunkPacket.granulepos);
// fprintf(stderr, "out: frame = %lld\n", fCurrentFrame);
}
} else {
debugger("kaboom");
}
fCurrentTime = (bigtime_t) ((1000000LL * fCurrentFrame)
/ (fMediaFormat.u.encoded_video.output.field_rate *
fMediaFormat.u.encoded_video.output.interlace));
// fprintf(stderr, "video in: frame = %lld time = %lld\n", fCurrentFrame, fCurrentTime);
int lenbytes = ((fChunkPacket.packet[0] & 0xc0) >> 6) | ((fChunkPacket.packet[0] & 0x02) << 1);
*chunkBuffer = (void*)&(fChunkPacket.packet[lenbytes+1]);
*chunkSize = fChunkPacket.bytes-(lenbytes+1);
bool keyframe = (fChunkPacket.packet[0] & (1 << 3));
mediaHeader->u.encoded_video.field_flags = (keyframe ? B_MEDIA_KEY_FRAME : 0);
return result;
}
// OggTobiasVideoCodecTest
static class OggTobiasVideoCodecTest : public OggCodecTest {
public:
OggTobiasVideoCodecTest() {}
virtual ~OggTobiasVideoCodecTest() {}
virtual bool RecognizesInitialPacket(const ogg_packet & packet) const
{
return findIdentifier(packet, "video", 1);
}
virtual OggCodec * InstantiateCodec() const
{
return new OggTobiasVideoCodec();
}
} ogg_tobias_video_test;
/*
* OggTobiasAudioCodec
*/
class OggTobiasAudioCodec : public OggTobiasCodec {
public:
OggTobiasAudioCodec();
virtual ~OggTobiasAudioCodec();
virtual status_t GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader);
protected:
virtual status_t HeaderToFormat(const tobias_stream_header & header);
};
OggTobiasAudioCodec::OggTobiasAudioCodec()
{
TRACE("OggTobiasAudioCodec::OggTobiasAudioCodec\n");
}
OggTobiasAudioCodec::~OggTobiasAudioCodec()
{
TRACE("OggTobiasAudioCodec::~OggTobiasAudioCodec\n");
}
/* virtual */ status_t
OggTobiasAudioCodec::HeaderToFormat(const tobias_stream_header & header)
{
TRACE("OggTobiasAudioCodec::HeaderToFormat\n");
debugger("get_audio_format");
return B_OK;
}
/* virtual */ status_t
OggTobiasAudioCodec::GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
if (fCurrentFrame == -1) {
fCurrentFrame = fOldFrame + 1;
fOldFrame = fCurrentFrame;
fOldGranulePos++;
}
fCurrentTime = (bigtime_t) (1000000LL * fCurrentFrame)
/ (long long)fMediaFormat.u.encoded_audio.output.frame_rate;
status_t result = OggCodec::GetChunk(stream, streaming, chunkBuffer, chunkSize, mediaHeader);
if (result != B_OK) {
return result;
}
int lenbytes = ((fChunkPacket.packet[0] & 0xc0) >> 6) | ((fChunkPacket.packet[0] & 0x02) << 1);
*chunkBuffer = (void*)&(fChunkPacket.packet[lenbytes+1]);
*chunkSize = fChunkPacket.bytes-(lenbytes+1);
return result;
}
// OggTobiasAudioCodecTest
static class OggTobiasAudioCodecTest : public OggCodecTest {
public:
OggTobiasAudioCodecTest() {}
virtual ~OggTobiasAudioCodecTest() {}
virtual bool RecognizesInitialPacket(const ogg_packet & packet) const
{
return findIdentifier(packet, "audio", 1);
}
virtual OggCodec * InstantiateCodec() const
{
return new OggTobiasAudioCodec();
}
} ogg_tobias_audio_test;
/*
* OggTobiasTextCodec
*/
class OggTobiasTextCodec : public OggTobiasCodec {
public:
OggTobiasTextCodec();
virtual ~OggTobiasTextCodec();
virtual status_t GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader);
protected:
virtual status_t HeaderToFormat(const tobias_stream_header & header);
};
OggTobiasTextCodec::OggTobiasTextCodec()
{
TRACE("OggTobiasTextCodec::OggTobiasTextCodec\n");
}
OggTobiasTextCodec::~OggTobiasTextCodec()
{
TRACE("OggTobiasTextCodec::~OggTobiasTextCodec\n");
}
/* virtual */ status_t
OggTobiasTextCodec::HeaderToFormat(const tobias_stream_header & header)
{
TRACE("OggTobiasTextCodec::HeaderToFormat\n");
// get the format for the description
media_format_description description = tobias_text_description();
BMediaFormats formats;
if ((formats.InitCheck() != B_OK) ||
(formats.GetFormatFor(description, &fMediaFormat) != B_OK)) {
fMediaFormat = tobias_text_encoded_media_format();
}
// fill out format from header packet
(void)header;
return B_OK;
}
/* virtual */ status_t
OggTobiasTextCodec::GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
if (fCurrentFrame == -1) {
fCurrentFrame = fOldFrame + 1;
fOldFrame = fCurrentFrame;
fOldGranulePos++;
}
fCurrentTime = (bigtime_t) (1000000LL * fCurrentFrame)
/ (long long)fMediaFormat.u.encoded_audio.output.frame_rate;
status_t result = OggCodec::GetChunk(stream, streaming, chunkBuffer, chunkSize, mediaHeader);
if (result != B_OK) {
return result;
}
// thanks to Marcus:
int lenbytes = ((fChunkPacket.packet[0] & 0xc0) >> 6) | ((fChunkPacket.packet[0] & 0x02) << 1);
*chunkBuffer = (void*)&(fChunkPacket.packet[lenbytes+1]);
*chunkSize = fChunkPacket.bytes-(lenbytes+1);
bool keyframe = (fChunkPacket.packet[0] & (1 << 3));
mediaHeader->u.encoded_video.field_flags = (keyframe ? B_MEDIA_KEY_FRAME : 0);
return result;
}
// OggTobiasTextCodecTest
static class OggTobiasTextCodecTest : public OggCodecTest {
public:
OggTobiasTextCodecTest() {}
virtual ~OggTobiasTextCodecTest() {}
virtual bool RecognizesInitialPacket(const ogg_packet & packet) const
{
return findIdentifier(packet,"text",1);
}
virtual OggCodec * InstantiateCodec() const
{
return new OggTobiasTextCodec();
}
} ogg_tobias_text_test;
@@ -1,262 +0,0 @@
#include "OggVorbisFormats.h"
#include "OggCodecs.h"
#include <stdio.h>
#define TRACE_THIS 1
#if TRACE_THIS
#define TRACE printf
#else
#define TRACE(a...) ((void)0)
#endif
inline size_t
AudioBufferSize(media_raw_audio_format * raf, bigtime_t buffer_duration = 50000 /* 50 ms */)
{
return (raf->format & 0xf) * (raf->channel_count)
* (size_t)((raf->frame_rate * buffer_duration) / 1000000.0);
}
/*
* vorbis header parsing code from libvorbis/info.c
*/
typedef struct vorbis_info{
int version;
int channels;
long rate;
/* The below bitrate declarations are *hints*.
Combinations of the three values carry the following implications:
all three set to the same value:
implies a fixed rate bitstream
only nominal set:
implies a VBR stream that averages the nominal bitrate. No hard
upper/lower limit
upper and or lower set:
implies a VBR bitstream that obeys the bitrate limits. nominal
may also be set to give a nominal rate.
none set:
the coder does not care to speculate.
*/
long bitrate_upper;
long bitrate_nominal;
long bitrate_lower;
long bitrate_window;
void *codec_setup;
} vorbis_info;
// based on libvorbis/info.c _vorbis_unpack_info
static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
vi->version = oggpack_read(opb, 32);
if (vi->version != 0) {
return -1;
}
vi->channels = oggpack_read(opb, 8);
vi->rate = oggpack_read(opb, 32);
vi->bitrate_upper = oggpack_read(opb, 32);
vi->bitrate_nominal = oggpack_read(opb, 32);
vi->bitrate_lower = oggpack_read(opb, 32);
long blocksizes0 = oggpack_read(opb, 4);
long blocksizes1 = oggpack_read(opb, 4);
if (vi->rate < 1) {
return -1;
}
if (vi->channels < 1) {
return -1;
}
if (blocksizes0 < 8) {
return -1;
}
if (blocksizes1 < blocksizes0) {
return -1;
}
if (oggpack_read(opb, 1) != 1) {
return -1;
} /* EOP check */
return 0;
}
/*
* OggVorbisCodec
*/
class OggVorbisCodec : public OggCodec {
public:
OggVorbisCodec();
virtual ~OggVorbisCodec();
virtual bool IsHeaderPacket(const ogg_packet & packet, uint packetno) const;
virtual status_t HandlePacket(const ogg_packet & packet);
virtual status_t GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader);
private:
std::vector<ogg_packet> fMetaDataPackets;
unsigned char * fHeaderPacketData;
unsigned char * fCommentPacketData;
unsigned char * fCodebookPacketData;
unsigned int fPacketCount;
};
OggVorbisCodec::OggVorbisCodec()
{
TRACE("OggVorbisCodec::OggVorbisCodec\n");
fHeaderPacketData = NULL;
fCommentPacketData = NULL;
fCodebookPacketData = NULL;
fPacketCount = 0;
}
OggVorbisCodec::~OggVorbisCodec()
{
delete fHeaderPacketData;
delete fCommentPacketData;
delete fCodebookPacketData;
}
/* virtual */ bool
OggVorbisCodec::IsHeaderPacket(const ogg_packet & packet, uint packetno) const
{
oggpack_buffer opb;
oggpack_readinit(&opb, packet.packet, packet.bytes);
uint packtype = oggpack_read(&opb, 8);
return (packetno == 0 && packtype == 0x01)
|| (packetno == 1 && packtype == 0x03)
|| (packetno == 2 && packtype == 0x05);
}
/* virtual */ status_t
OggVorbisCodec::HandlePacket(const ogg_packet & packet)
{
TRACE("OggVorbisCodec::HandlePacket\n");
if (!IsHeaderPacket(packet, fPacketCount)) {
return B_BAD_VALUE;
}
switch (fPacketCount) {
case 0: {
// header packet
if (!packet.b_o_s) {
return B_ERROR; // first packet was not beginning of stream
}
// parse header packet
// based on libvorbis/info.c vorbis_synthesis_headerin(...)
oggpack_buffer opb;
oggpack_readinit(&opb, packet.packet, packet.bytes);
// discard packet type (already validated in IsHeaderPacket)
oggpack_read(&opb, 8);
// discard vorbis string
for (uint i = 0 ; i < sizeof("vorbis") - 1 ; i++) {
oggpack_read(&opb, 8);
}
vorbis_info info;
if (_vorbis_unpack_info(&info, &opb) != 0) {
return B_ERROR; // couldn't unpack info
}
// get the format for the description
media_format_description description = vorbis_description();
BMediaFormats formats;
if ((formats.InitCheck() != B_OK) ||
(formats.GetFormatFor(description, &fMediaFormat) != B_OK)) {
fMediaFormat = vorbis_encoded_media_format();
}
// fill out format from header packet
if (info.bitrate_nominal > 0) {
fMediaFormat.u.encoded_audio.bit_rate = info.bitrate_nominal;
} else if (info.bitrate_upper > 0) {
fMediaFormat.u.encoded_audio.bit_rate = info.bitrate_upper;
} else if (info.bitrate_lower > 0) {
fMediaFormat.u.encoded_audio.bit_rate = info.bitrate_lower;
}
if (info.channels == 1) {
fMediaFormat.u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT;
} else {
fMediaFormat.u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT;
}
fMediaFormat.u.encoded_audio.output.frame_rate = (float)info.rate;
fMediaFormat.u.encoded_audio.output.channel_count = info.channels;
fMediaFormat.u.encoded_audio.output.buffer_size
= AudioBufferSize(&fMediaFormat.u.encoded_audio.output);
fHeaderPacketData = new unsigned char[packet.bytes];
memcpy(fHeaderPacketData, packet.packet, packet.bytes);
fMetaDataPackets.push_back(packet);
fMetaDataPackets[fPacketCount].packet = fHeaderPacketData;
break;
}
case 1: {
// comment packet
fCommentPacketData = new unsigned char[packet.bytes];
memcpy(fCommentPacketData, packet.packet, packet.bytes);
fMetaDataPackets.push_back(packet);
fMetaDataPackets[fPacketCount].packet = fCommentPacketData;
break;
}
case 2: {
// codebook packet
fCodebookPacketData = new unsigned char[packet.bytes];
memcpy(fCodebookPacketData, packet.packet, packet.bytes);
fMetaDataPackets.push_back(packet);
fMetaDataPackets[fPacketCount].packet = fCodebookPacketData;
fInitCheck = B_OK;
fMediaFormat.SetMetaData(&fMetaDataPackets,sizeof(fMetaDataPackets));
break;
}
default:
// huh?
break;
}
fPacketCount++;
return B_OK;
}
/* virtual */ status_t
OggVorbisCodec::GetChunk(ogg_stream_state * stream, bool streaming,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
if (fCurrentFrame == -1) {
fCurrentTime = -1;
} else {
fCurrentTime = (1000000LL * fCurrentFrame)
/ (long long)fMediaFormat.u.encoded_audio.output.frame_rate;
}
return OggCodec::GetChunk(stream, streaming, chunkBuffer, chunkSize, mediaHeader);
}
/*
* OggVorbisCodecTest
*/
static class OggVorbisCodecTest : public OggCodecTest {
public:
OggVorbisCodecTest() {}
virtual ~OggVorbisCodecTest() {}
virtual bool RecognizesInitialPacket(const ogg_packet & packet) const
{
return findIdentifier(packet, "vorbis", 1);
}
virtual OggCodec * InstantiateCodec() const
{
return new OggVorbisCodec();
}
} ogg_vorbis_codec_test;