fix brain-dead branching

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6751 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shatty
2004-02-26 08:22:48 +00:00
parent 4a673a0246
commit f870bff890
14 changed files with 1730 additions and 0 deletions
@@ -0,0 +1,196 @@
#include "OggSpeexFormats.h"
#include "OggSpeexSeekable.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;
/*
* OggSpeexSeekable implementations
*/
/* static */ bool
OggSpeexSeekable::IsValidHeader(const ogg_packet & packet)
{
return findIdentifier(packet,"Speex ",0);
}
OggSpeexSeekable::OggSpeexSeekable(long serialno)
: OggSeekable(serialno)
{
TRACE("OggSpeexSeekable::OggSpeexSeekable\n");
}
OggSpeexSeekable::~OggSpeexSeekable()
{
}
status_t
OggSpeexSeekable::GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format)
{
TRACE("OggSpeexSeekable::GetStreamInfo\n");
status_t result = B_OK;
ogg_packet packet;
// get header packet
if (GetHeaderPackets().size() < 1) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
packet = GetHeaderPackets()[0];
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;
// get the format for the description
media_format_description description = speex_description();
BMediaFormats formats;
result = formats.InitCheck();
if (result == B_OK) {
result = formats.GetFormatFor(description, format);
}
if (result != B_OK) {
*format = speex_encoded_media_format();
// ignore error, allow user to use ReadChunk interface
}
// fill out format from header packet
if (header->bitrate > 0) {
format->u.encoded_audio.bit_rate = header->bitrate;
} else {
// TODO: manually compute it where possible
}
if (header->nb_channels == 1) {
format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT;
} else {
format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT;
}
fFrameRate = format->u.encoded_audio.output.frame_rate = header->rate;
format->u.encoded_audio.output.channel_count = header->nb_channels;
// allocate buffer, round up to nearest speex output_length size
int buffer_size = AudioBufferSize(&format->u.encoded_audio.output);
int output_length = header->frame_size * header->nb_channels *
(format->u.encoded_audio.output.format & 0xf);
buffer_size = ((buffer_size - 1) / output_length + 1) * output_length;
format->u.encoded_audio.output.buffer_size = buffer_size;
// get comment packet
if (GetHeaderPackets().size() < 2) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
// get extra headers
while ((signed)GetHeaderPackets().size() < header->extra_headers) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
format->SetMetaData((void*)&GetHeaderPackets(),sizeof(GetHeaderPackets()));
// TODO: count the frames in the first page.. somehow.. :-/
int64 frames = 0;
ogg_page page;
// read the first page
result = ReadPage(&page);
if (result != B_OK) {
return result;
}
int64 fFirstGranulepos = ogg_page_granulepos(&page);
TRACE("OggVorbisSeekable::GetStreamInfo: first granulepos: %lld\n", fFirstGranulepos);
// read our last page
off_t last = inherited::Seek(GetLastPagePosition(), SEEK_SET);
if (last < 0) {
return last;
}
result = ReadPage(&page);
if (result != B_OK) {
return result;
}
int64 last_granulepos = ogg_page_granulepos(&page);
// seek back to the start
int64 frame = 0;
bigtime_t time = 0;
result = Seek(B_MEDIA_SEEK_TO_TIME, &frame, &time);
if (result != B_OK) {
return result;
}
// compute frame count and duration from sample count
frames = last_granulepos - fFirstGranulepos;
*frameCount = frames;
*duration = (1000000LL * frames) / (long long)fFrameRate;
return B_OK;
}
status_t
OggSpeexSeekable::GetNextChunk(void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
status_t result = inherited::GetNextChunk(chunkBuffer, chunkSize, mediaHeader);
if (result != B_OK) {
TRACE("OggSpeexSeekable::GetNextChunk failed: GetNextChunk = %s\n", strerror(result));
return result;
}
*chunkSize = ((ogg_packet*)*chunkBuffer)->bytes;
*chunkBuffer = ((ogg_packet*)*chunkBuffer)->packet;
return B_OK;
}
@@ -0,0 +1,28 @@
#ifndef _OGG_SPEEX_SEEKABLE_H
#define _OGG_SPEEX_SEEKABLE_H
#include "OggSeekable.h"
namespace BPrivate { namespace media {
class OggSpeexSeekable : public OggSeekable {
private:
typedef OggSeekable inherited;
public:
static bool IsValidHeader(const ogg_packet & packet);
public:
OggSpeexSeekable(long serialno);
virtual ~OggSpeexSeekable();
virtual status_t GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format);
virtual status_t GetNextChunk(void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader);
};
} } // namespace BPrivate::media
using namespace BPrivate::media;
#endif // _OGG_SPEEX_SEEKABLE_H
@@ -0,0 +1,161 @@
#include "OggSpeexFormats.h"
#include "OggSpeexStream.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;
/*
* OggSpeexStream implementations
*/
/* static */ bool
OggSpeexStream::IsValidHeader(const ogg_packet & packet)
{
return findIdentifier(packet,"Speex ",0);
}
OggSpeexStream::OggSpeexStream(long serialno)
: OggStream(serialno)
{
TRACE("OggSpeexStream::OggSpeexStream\n");
}
OggSpeexStream::~OggSpeexStream()
{
}
status_t
OggSpeexStream::GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format)
{
TRACE("OggSpeexStream::GetStreamInfo\n");
status_t result = B_OK;
ogg_packet packet;
// get header packet
if (GetHeaderPackets().size() < 1) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
packet = GetHeaderPackets()[0];
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;
// get the format for the description
media_format_description description = speex_description();
BMediaFormats formats;
result = formats.InitCheck();
if (result == B_OK) {
result = formats.GetFormatFor(description, format);
}
if (result != B_OK) {
*format = speex_encoded_media_format();
// ignore error, allow user to use ReadChunk interface
}
// fill out format from header packet
if (header->bitrate > 0) {
format->u.encoded_audio.bit_rate = header->bitrate;
} else {
// TODO: manually compute it where possible
}
if (header->nb_channels == 1) {
format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT;
} else {
format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT;
}
format->u.encoded_audio.output.frame_rate = header->rate;
format->u.encoded_audio.output.channel_count = header->nb_channels;
// allocate buffer, round up to nearest speex output_length size
int buffer_size = AudioBufferSize(&format->u.encoded_audio.output);
int output_length = header->frame_size * header->nb_channels *
(format->u.encoded_audio.output.format & 0xf);
buffer_size = ((buffer_size - 1) / output_length + 1) * output_length;
format->u.encoded_audio.output.buffer_size = buffer_size;
// get comment packet
if (GetHeaderPackets().size() < 2) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
// get extra headers
while ((signed)GetHeaderPackets().size() < header->extra_headers) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
format->SetMetaData((void*)&GetHeaderPackets(),sizeof(GetHeaderPackets()));
*duration = 100000000;
*frameCount = 60000;
return B_OK;
}
status_t
OggSpeexStream::GetNextChunk(void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
status_t result = GetPacket(&fChunkPacket);
if (result != B_OK) {
TRACE("OggSpeexStream::GetNextChunk failed: GetPacket = %s\n", strerror(result));
return result;
}
*chunkBuffer = fChunkPacket.packet;
*chunkSize = fChunkPacket.bytes;
return B_OK;
}
@@ -0,0 +1,26 @@
#ifndef _OGG_SPEEX_STREAM_H
#define _OGG_SPEEX_STREAM_H
#include "OggStream.h"
namespace BPrivate { namespace media {
class OggSpeexStream : public OggStream {
public:
static bool IsValidHeader(const ogg_packet & packet);
public:
OggSpeexStream(long serialno);
virtual ~OggSpeexStream();
virtual status_t GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format);
virtual status_t GetNextChunk(void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader);
};
} } // namespace BPrivate::media
using namespace BPrivate::media;
#endif // _OGG_SPEEX_STREAM_H
@@ -0,0 +1,206 @@
#include "OggTheoraFormats.h"
#include "OggTheoraStream.h"
#include <ogg/ogg.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);
}
/*
* 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;
// based on theora/lib/toplevel.c _theora_unpack_info
#define theora_read(x,y,z) ( *z = oggpack_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);
}
/*
* OggTheoraStream implementations
*/
/* static */ bool
OggTheoraStream::IsValidHeader(const ogg_packet & packet)
{
return findIdentifier(packet,"theora",1);
}
OggTheoraStream::OggTheoraStream(long serialno)
: OggStream(serialno)
{
TRACE("OggTheoraStream::OggTheoraStream\n");
}
OggTheoraStream::~OggTheoraStream()
{
}
status_t
OggTheoraStream::GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format)
{
TRACE("OggTheoraStream::GetStreamInfo\n");
status_t result = B_OK;
ogg_packet packet;
// get header packet
if (GetHeaderPackets().size() < 1) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
packet = GetHeaderPackets()[0];
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);
int typeflag = oggpack_read(&opb, 8);
if (typeflag != 0x80) {
return B_ERROR; // first packet was not an info packet
}
// discard theora string
for (uint i = 0 ; i < sizeof("theora") - 1 ; i++) {
oggpack_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;
result = formats.InitCheck();
if (result == B_OK) {
result = formats.GetFormatFor(description, format);
}
if (result != B_OK) {
*format = theora_encoded_media_format();
// ignore error, allow user to use ReadChunk interface
}
// fill out format from header packet
format->u.encoded_video.frame_size = info.frame_width * info.frame_height ;
format->u.encoded_video.output.display.line_width = info.frame_width;
format->u.encoded_video.output.display.line_count = info.frame_height;
// TODO: wring more info out of the headers
format->SetMetaData((void*)&GetHeaderPackets(),sizeof(GetHeaderPackets()));
*duration = 80000000;
*frameCount = 60000;
return B_OK;
}
@@ -0,0 +1,23 @@
#ifndef _OGG_THEORA_STREAM_H
#define _OGG_THEORA_STREAM_H
#include "OggStream.h"
namespace BPrivate { namespace media {
class OggTheoraStream : public OggStream {
public:
static bool IsValidHeader(const ogg_packet & packet);
public:
OggTheoraStream(long serialno);
virtual ~OggTheoraStream();
virtual status_t GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format);
};
} } // namespace BPrivate::media
using namespace BPrivate::media;
#endif // _OGG_THEORA_STREAM_H
@@ -0,0 +1,287 @@
#include "OggTobiasFormats.h"
#include "OggTobiasSeekable.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);
}
/*
* 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;
/*
* OggTobiasSeekable implementations
*/
/* static */ bool
OggTobiasSeekable::IsValidHeader(const ogg_packet & packet)
{
return findIdentifier(packet,"video",1)
|| findIdentifier(packet,"audio",1)
|| findIdentifier(packet,"text",1);
}
OggTobiasSeekable::OggTobiasSeekable(long serialno)
: OggSeekable(serialno)
{
TRACE("OggTobiasSeekable::OggTobiasSeekable\n");
fMicrosecPerFrame = 0;
}
OggTobiasSeekable::~OggTobiasSeekable()
{
TRACE("OggTobiasSeekable::~OggTobiasSeekable\n");
}
static status_t
get_video_format(tobias_stream_header * header, media_format * format)
{
TRACE(" get_video_format\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;
status_t result = formats.InitCheck();
if (result == B_OK) {
result = formats.GetFormatFor(description, format);
}
if (result != B_OK) {
*format = tobias_video_encoded_media_format();
// ignore error, allow user to use ReadChunk interface
}
// fill out format from header packet
format->user_data_type = B_CODEC_TYPE_INFO;
strncpy((char*)format->user_data, header->subtype, 4);
format->u.encoded_video.frame_size
= header->video.width * header->video.height;
format->u.encoded_video.output.field_rate = 10000000.0 / header->time_unit;
format->u.encoded_video.output.interlace = 1;
format->u.encoded_video.output.first_active = 0;
format->u.encoded_video.output.last_active = header->video.height - 1;
format->u.encoded_video.output.orientation = B_VIDEO_TOP_LEFT_RIGHT;
format->u.encoded_video.output.pixel_width_aspect = 1;
format->u.encoded_video.output.pixel_height_aspect = 1;
format->u.encoded_video.output.display.line_width = header->video.width;
format->u.encoded_video.output.display.line_count = header->video.height;
format->u.encoded_video.output.display.bytes_per_row = 0;
format->u.encoded_video.output.display.pixel_offset = 0;
format->u.encoded_video.output.display.line_offset = 0;
format->u.encoded_video.output.display.flags = 0;
// TODO: wring more info out of the headers
return B_OK;
}
static status_t
get_audio_format(tobias_stream_header * header, media_format * format)
{
TRACE(" get_audio_format\n");
debugger("get_audio_format");
return B_UNSUPPORTED;
}
static status_t
get_text_format(tobias_stream_header * header, media_format * format)
{
TRACE(" get_text_format\n");
// get the format for the description
media_format_description description = tobias_text_description();
BMediaFormats formats;
status_t result = formats.InitCheck();
if (result == B_OK) {
result = formats.GetFormatFor(description, format);
}
if (result != B_OK) {
*format = tobias_text_encoded_media_format();
// ignore error, allow user to use ReadChunk interface
}
// fill out format from header packet
return B_OK;
}
status_t
OggTobiasSeekable::GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format)
{
TRACE("OggTobiasSeekable::GetStreamInfo\n");
status_t result = B_OK;
ogg_packet packet;
// get header packet
if (GetHeaderPackets().size() < 1) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
packet = GetHeaderPackets()[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;
if (strcmp(header->streamtype, "video") == 0) {
result = get_video_format(header, format);
if (result != B_OK) {
return result;
}
} else if (strcmp(header->streamtype, "audio") == 0) {
result = get_audio_format(header, format);
if (result != B_OK) {
return result;
}
} else if (strcmp(header->streamtype, "text") == 0) {
result = get_text_format(header, format);
if (result != B_OK) {
return result;
}
} else {
*frameCount = 0;
// unknown streamtype
return B_BAD_VALUE;
}
// get comment packet
if (GetHeaderPackets().size() < 2) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
format->SetMetaData((void*)&GetHeaderPackets(),sizeof(GetHeaderPackets()));
fMediaFormat = *format;
fMicrosecPerFrame = header->time_unit / 10.0;
fFrameRate = 1000000.0 / fMicrosecPerFrame;
// TODO: count the frames in the first page.. somehow.. :-/
int64 frames = 0;
ogg_page page;
// read the first page
result = ReadPage(&page);
if (result != B_OK) {
return result;
}
int64 fFirstGranulepos = ogg_page_granulepos(&page);
TRACE("OggVorbisSeekable::GetStreamInfo: first granulepos: %lld\n", fFirstGranulepos);
// read our last page
off_t last = inherited::Seek(GetLastPagePosition(), SEEK_SET);
if (last < 0) {
return last;
}
result = ReadPage(&page);
if (result != B_OK) {
return result;
}
int64 last_granulepos = ogg_page_granulepos(&page);
// seek back to the start
int64 frame = 0;
bigtime_t time = 0;
result = Seek(B_MEDIA_SEEK_TO_TIME, &frame, &time);
if (result != B_OK) {
return result;
}
// compute frame count and duration from sample count
frames = last_granulepos - fFirstGranulepos;
*frameCount = frames;
*duration = (1000000LL * frames) / (long long)fFrameRate;
return B_OK;
}
status_t
OggTobiasSeekable::GetNextChunk(void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
status_t result = inherited::GetNextChunk(chunkBuffer, chunkSize, mediaHeader);
if (result != B_OK) {
TRACE("OggTobiasSeekable::GetNextChunk failed: GetNextChunk = %s\n", strerror(result));
return result;
}
*chunkSize = ((ogg_packet*)*chunkBuffer)->bytes;
*chunkBuffer = ((ogg_packet*)*chunkBuffer)->packet;
bool keyframe = ((uint*)chunkBuffer)[0] & (1 << 3); // ??
if (fMediaFormat.type == B_MEDIA_ENCODED_VIDEO) {
mediaHeader->type = fMediaFormat.type;
mediaHeader->u.encoded_video.field_flags = (keyframe ? B_MEDIA_KEY_FRAME : 0);
mediaHeader->u.encoded_video.first_active_line
= fMediaFormat.u.encoded_video.output.first_active;
mediaHeader->u.encoded_video.line_count
= fMediaFormat.u.encoded_video.output.display.line_count;
}
if (mediaHeader->start_time < 0) {
fCurrentFrame++;
fCurrentTime = (bigtime_t)((fCurrentFrame * 1000000LL) / fFrameRate);
mediaHeader->start_time = fCurrentTime;
}
// fprintf(stderr, "current frame = %lld, time = %lld\n", fCurrentFrame, fCurrentTime);
return B_OK;
}
@@ -0,0 +1,31 @@
#ifndef _OGG_TOBIAS_SEEKABLE_H
#define _OGG_TOBIAS_SEEKABLE_H
#include "OggSeekable.h"
namespace BPrivate { namespace media {
class OggTobiasSeekable : public OggSeekable {
private:
typedef OggSeekable inherited;
public:
static bool IsValidHeader(const ogg_packet & packet);
public:
OggTobiasSeekable(long serialno);
virtual ~OggTobiasSeekable();
virtual status_t GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format);
virtual status_t GetNextChunk(void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader);
private:
media_format fMediaFormat;
double fMicrosecPerFrame;
};
} } // namespace BPrivate::media
using namespace BPrivate::media;
#endif // _OGG_TOBIAS_SEEKABLE_H
@@ -0,0 +1,266 @@
#include "OggTobiasFormats.h"
#include "OggTobiasStream.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);
}
/*
* 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;
/*
* OggTobiasStream implementations
*/
/* static */ bool
OggTobiasStream::IsValidHeader(const ogg_packet & packet)
{
return findIdentifier(packet,"video",1)
|| findIdentifier(packet,"audio",1)
|| findIdentifier(packet,"text",1);
}
OggTobiasStream::OggTobiasStream(long serialno)
: OggStream(serialno)
{
TRACE("OggTobiasStream::OggTobiasStream\n");
fMicrosecPerFrame = 0;
}
OggTobiasStream::~OggTobiasStream()
{
TRACE("OggTobiasStream::~OggTobiasStream\n");
}
static status_t
get_video_format(tobias_stream_header * header, media_format * format)
{
TRACE(" get_video_format\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;
status_t result = formats.InitCheck();
if (result == B_OK) {
result = formats.GetFormatFor(description, format);
}
if (result != B_OK) {
*format = tobias_video_encoded_media_format();
// ignore error, allow user to use ReadChunk interface
}
// fill out format from header packet
format->user_data_type = B_CODEC_TYPE_INFO;
strncpy((char*)format->user_data, header->subtype, 4);
format->u.encoded_video.frame_size
= header->video.width * header->video.height;
format->u.encoded_video.output.field_rate = 10000000.0 / header->time_unit;
format->u.encoded_video.output.interlace = 1;
format->u.encoded_video.output.first_active = 0;
format->u.encoded_video.output.last_active = header->video.height - 1;
format->u.encoded_video.output.orientation = B_VIDEO_TOP_LEFT_RIGHT;
format->u.encoded_video.output.pixel_width_aspect = 1;
format->u.encoded_video.output.pixel_height_aspect = 1;
format->u.encoded_video.output.display.line_width = header->video.width;
format->u.encoded_video.output.display.line_count = header->video.height;
format->u.encoded_video.output.display.bytes_per_row = 0;
format->u.encoded_video.output.display.pixel_offset = 0;
format->u.encoded_video.output.display.line_offset = 0;
format->u.encoded_video.output.display.flags = 0;
// TODO: wring more info out of the headers
return B_OK;
}
static status_t
get_audio_format(tobias_stream_header * header, media_format * format)
{
TRACE(" get_audio_format\n");
debugger("get_audio_format");
return B_UNSUPPORTED;
}
static status_t
get_text_format(tobias_stream_header * header, media_format * format)
{
TRACE(" get_text_format\n");
// get the format for the description
media_format_description description = tobias_text_description();
BMediaFormats formats;
status_t result = formats.InitCheck();
if (result == B_OK) {
result = formats.GetFormatFor(description, format);
}
if (result != B_OK) {
*format = tobias_text_encoded_media_format();
// ignore error, allow user to use ReadChunk interface
}
// fill out format from header packet
return B_OK;
}
status_t
OggTobiasStream::GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format)
{
TRACE("OggTobiasStream::GetStreamInfo\n");
status_t result = B_OK;
ogg_packet packet;
// get header packet
if (GetHeaderPackets().size() < 1) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
packet = GetHeaderPackets()[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;
if (strcmp(header->streamtype, "video") == 0) {
result = get_video_format(header, format);
if (result != B_OK) {
return result;
}
*frameCount = (bigtime_t)(3 * 3600 * format->u.encoded_video.output.field_rate);
} else if (strcmp(header->streamtype, "audio") == 0) {
result = get_audio_format(header, format);
if (result != B_OK) {
return result;
}
*frameCount = 2000000;
} else if (strcmp(header->streamtype, "text") == 0) {
result = get_text_format(header, format);
if (result != B_OK) {
return result;
}
*frameCount = 2000000;
} else {
*frameCount = 0;
// unknown streamtype
return B_BAD_VALUE;
}
// get comment packet
if (GetHeaderPackets().size() < 2) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
format->SetMetaData((void*)&GetHeaderPackets(),sizeof(GetHeaderPackets()));
fMediaFormat = *format;
fMicrosecPerFrame = header->time_unit / 10.0;
*duration = (bigtime_t)(*frameCount * fMicrosecPerFrame);
return B_OK;
}
status_t
OggTobiasStream::GetNextChunk(void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
status_t result = GetPacket(&fChunkPacket);
if (result != B_OK) {
TRACE("OggTobiasStream::GetNextChunk failed: GetPacket = %s\n", strerror(result));
return result;
}
*chunkBuffer = fChunkPacket.packet;
*chunkSize = fChunkPacket.bytes;
bool keyframe = fChunkPacket.packet[0] & (1 << 3); // ??
if (fMediaFormat.type == B_MEDIA_ENCODED_VIDEO) {
mediaHeader->type = fMediaFormat.type;
mediaHeader->start_time = fCurrentTime;
mediaHeader->u.encoded_video.field_flags = (keyframe ? B_MEDIA_KEY_FRAME : 0);
mediaHeader->u.encoded_video.first_active_line
= fMediaFormat.u.encoded_video.output.first_active;
mediaHeader->u.encoded_video.line_count
= fMediaFormat.u.encoded_video.output.display.line_count;
}
fCurrentFrame++;
fCurrentTime = (bigtime_t)(fCurrentFrame * fMicrosecPerFrame);
return B_OK;
}
status_t
OggTobiasStream::AddPage(off_t position, const ogg_page & page)
{
status_t status = OggStream::AddPage(position, page);
if (fMediaFormat.type == B_MEDIA_HTML) {
ogg_packet packet;
GetPacket(&packet);
if (packet.bytes > 4) {
fprintf(stderr, "%s\n", &(packet.packet[3]));
}
}
return status;
}
@@ -0,0 +1,32 @@
#ifndef _OGG_TOBIAS_STREAM_H
#define _OGG_TOBIAS_STREAM_H
#include "OggStream.h"
namespace BPrivate { namespace media {
class OggTobiasStream : public OggStream {
public:
static bool IsValidHeader(const ogg_packet & packet);
public:
OggTobiasStream(long serialno);
virtual ~OggTobiasStream();
virtual status_t GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format);
virtual status_t GetNextChunk(void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader);
// reader push input function
virtual status_t AddPage(off_t position, const ogg_page & page);
private:
media_format fMediaFormat;
double fMicrosecPerFrame;
};
} } // namespace BPrivate::media
using namespace BPrivate::media;
#endif // _OGG_TOBIAS_STREAM_H
@@ -0,0 +1,230 @@
#include "OggVorbisFormats.h"
#include "OggVorbisSeekable.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;
}
/*
* OggVorbisSeekable implementations
*/
/* static */ bool
OggVorbisSeekable::IsValidHeader(const ogg_packet & packet)
{
return findIdentifier(packet,"vorbis",1);
}
OggVorbisSeekable::OggVorbisSeekable(long serialno)
: OggSeekable(serialno)
{
TRACE("OggVorbisSeekable::OggVorbisSeekable\n");
}
OggVorbisSeekable::~OggVorbisSeekable()
{
TRACE("OggVorbisSeekable::~OggVorbisSeekable\n");
}
status_t
OggVorbisSeekable::GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format)
{
TRACE("OggVorbisSeekable::GetStreamInfo\n");
status_t result = B_OK;
ogg_packet packet;
// get header packet
if (GetHeaderPackets().size() < 1) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
packet = GetHeaderPackets()[0];
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);
int packtype = oggpack_read(&opb, 8);
if (packtype != 0x01) {
return B_ERROR; // first packet was not an info packet
}
// 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;
result = formats.InitCheck();
if (result == B_OK) {
result = formats.GetFormatFor(description, format);
}
if (result != B_OK) {
*format = vorbis_encoded_media_format();
// ignore error, allow user to use ReadChunk interface
}
// fill out format from header packet
if (info.bitrate_nominal > 0) {
format->u.encoded_audio.bit_rate = info.bitrate_nominal;
} else if (info.bitrate_upper > 0) {
format->u.encoded_audio.bit_rate = info.bitrate_upper;
} else if (info.bitrate_lower > 0) {
format->u.encoded_audio.bit_rate = info.bitrate_lower;
}
if (info.channels == 1) {
format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT;
} else {
format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT;
}
fFrameRate = format->u.encoded_audio.output.frame_rate = (float)info.rate;
format->u.encoded_audio.output.channel_count = info.channels;
format->u.encoded_audio.output.buffer_size
= AudioBufferSize(&format->u.encoded_audio.output);
// get comment packet
if (GetHeaderPackets().size() < 2) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
// get codebook packet
if (GetHeaderPackets().size() < 3) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
format->SetMetaData((void*)&GetHeaderPackets(),sizeof(GetHeaderPackets()));
// TODO: count the frames in the first page.. somehow.. :-/
int64 frames = 0;
ogg_page page;
// read the first page
result = ReadPage(&page);
if (result != B_OK) {
return result;
}
int64 fFirstGranulepos = ogg_page_granulepos(&page);
TRACE("OggVorbisSeekable::GetStreamInfo: first granulepos: %lld\n", fFirstGranulepos);
// read our last page
off_t last = inherited::Seek(GetLastPagePosition(), SEEK_SET);
if (last < 0) {
return last;
}
result = ReadPage(&page);
if (result != B_OK) {
return result;
}
int64 last_granulepos = ogg_page_granulepos(&page);
// seek back to the start
int64 frame = 0;
bigtime_t time = 0;
result = Seek(B_MEDIA_SEEK_TO_TIME, &frame, &time);
if (result != B_OK) {
return result;
}
// compute frame count and duration from sample count
frames = last_granulepos - fFirstGranulepos;
*frameCount = frames;
*duration = (1000000LL * frames) / (long long)fFrameRate;
return B_OK;
}
@@ -0,0 +1,25 @@
#ifndef _OGG_VORBIS_SEEKABLE_H
#define _OGG_VORBIS_SEEKABLE_H
#include "OggSeekable.h"
namespace BPrivate { namespace media {
class OggVorbisSeekable : public OggSeekable {
private:
typedef OggSeekable inherited;
public:
static bool IsValidHeader(const ogg_packet & packet);
public:
OggVorbisSeekable(long serialno);
virtual ~OggVorbisSeekable();
virtual status_t GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format);
};
} } // namespace BPrivate::media
using namespace BPrivate::media;
#endif // _OGG_VORBIS_SEEKABLE_H
@@ -0,0 +1,196 @@
#include "OggVorbisFormats.h"
#include "OggVorbisStream.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;
}
/*
* OggVorbisStream implementations
*/
/* static */ bool
OggVorbisStream::IsValidHeader(const ogg_packet & packet)
{
return findIdentifier(packet,"vorbis",1);
}
OggVorbisStream::OggVorbisStream(long serialno)
: OggStream(serialno)
{
TRACE("OggVorbisStream::OggVorbisStream\n");
}
OggVorbisStream::~OggVorbisStream()
{
TRACE("OggVorbisStream::~OggVorbisStream\n");
}
status_t
OggVorbisStream::GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format)
{
TRACE("OggVorbisStream::GetStreamInfo\n");
status_t result = B_OK;
ogg_packet packet;
// get header packet
if (GetHeaderPackets().size() < 1) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
packet = GetHeaderPackets()[0];
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);
int packtype = oggpack_read(&opb, 8);
if (packtype != 0x01) {
return B_ERROR; // first packet was not an info packet
}
// 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;
result = formats.InitCheck();
if (result == B_OK) {
result = formats.GetFormatFor(description, format);
}
if (result != B_OK) {
*format = vorbis_encoded_media_format();
// ignore error, allow user to use ReadChunk interface
}
// fill out format from header packet
if (info.bitrate_nominal > 0) {
format->u.encoded_audio.bit_rate = info.bitrate_nominal;
} else if (info.bitrate_upper > 0) {
format->u.encoded_audio.bit_rate = info.bitrate_upper;
} else if (info.bitrate_lower > 0) {
format->u.encoded_audio.bit_rate = info.bitrate_lower;
}
if (info.channels == 1) {
format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT;
} else {
format->u.encoded_audio.multi_info.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT;
}
format->u.encoded_audio.output.frame_rate = (float)info.rate;
format->u.encoded_audio.output.channel_count = info.channels;
format->u.encoded_audio.output.buffer_size
= AudioBufferSize(&format->u.encoded_audio.output);
// get comment packet
if (GetHeaderPackets().size() < 2) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
// get codebook packet
if (GetHeaderPackets().size() < 3) {
result = GetPacket(&packet);
if (result != B_OK) {
return result;
}
SaveHeaderPacket(packet);
}
format->SetMetaData((void*)&GetHeaderPackets(),sizeof(GetHeaderPackets()));
// compute frame count and duration from sample count
*duration = 5 * 60 * 1000000;
*frameCount = *duration * (long long)format->u.encoded_audio.output.frame_rate;
return B_OK;
}
@@ -0,0 +1,23 @@
#ifndef _OGG_VORBIS_STREAM_H
#define _OGG_VORBIS_STREAM_H
#include "OggStream.h"
namespace BPrivate { namespace media {
class OggVorbisStream : public OggStream {
public:
static bool IsValidHeader(const ogg_packet & packet);
public:
OggVorbisStream(long serialno);
virtual ~OggVorbisStream();
virtual status_t GetStreamInfo(int64 *frameCount, bigtime_t *duration,
media_format *format);
};
} } // namespace BPrivate::media
using namespace BPrivate::media;
#endif // _OGG_VORBIS_STREAM_H