separate out codec id and properties into a different file, add identification and format setup for tobias video (typically mpeg4) and speex codec (by observation, not spec)

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6175 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
shatty
2004-01-20 04:03:23 +00:00
parent dd82cdacbb
commit c084ed96f3
4 changed files with 235 additions and 59 deletions
+1
View File
@@ -6,6 +6,7 @@ SubDirHdrs [ FDirName $(SUBDIR) libogg ] ;
Addon ogg : media plugins :
OggReaderPlugin.cpp
OggReaderPluginCodecs.cpp
: false : libogg.a
;
@@ -15,24 +15,6 @@
#define TRACE(a...) ((void)0)
#endif
// codec identification
static bool isVorbisPacket(ogg_packet * packet) {
static const char * vorbis = "vorbis";
if ((unsigned)packet->bytes < (sizeof(vorbis)+1)) {
return false;
}
return !memcmp(&packet->packet[1], vorbis, sizeof(vorbis));
}
// codec-dependent packet gobbling for extra header packets
static int getPacketsLeft(ogg_packet * packet) {
if (isVorbisPacket(packet)) {
return 2;
}
return 0;
}
oggReader::oggReader()
{
TRACE("oggReader::oggReader\n");
@@ -187,7 +169,7 @@ oggReader::Sniff(int32 *streamCount)
memcpy(buffer, packet.packet, packet.bytes);
packet.packet = buffer;
fHeaderPackets[serialno].push_back(packet);
fHeaderPacketsLeft[serialno] = getPacketsLeft(&packet);
fHeaderPacketsLeft[serialno] = GetExtraHeaderPacketCount(&packet);
if (GetPage(&page) != B_OK) {
return B_ERROR;
}
@@ -272,22 +254,6 @@ oggReader::FreeCookie(void *cookie)
return B_OK;
}
// estimate: 1 frame = 256 bytes
int filePositionToFrame(int position) {
return position/256;
}
int frameToFilePosition(int frame) {
return frame*256;
}
// estimate: 1 second = 8 bytes
int filePositionToTime(int position) {
return position*1000/8;
}
int timeToFilePosition(int duration) {
return duration*8/1000;
}
status_t
oggReader::GetStreamInfo(void *cookie, int64 *frameCount, bigtime_t *duration,
media_format *format, void **infoBuffer, int32 *infoSize)
@@ -295,28 +261,9 @@ oggReader::GetStreamInfo(void *cookie, int64 *frameCount, bigtime_t *duration,
TRACE("oggReader::GetStreamInfo\n");
ogg_stream_state * stream = static_cast<ogg_stream_state *>(cookie);
memset(format, 0, sizeof(*format));
if (fSeekable) {
off_t input_length;
{
off_t current_position = fSeekable->Seek(0,SEEK_CUR);
input_length = fSeekable->Seek(0,SEEK_END)-fPostSniffPosition;
fSeekable->Seek(current_position,SEEK_SET);
}
*frameCount = filePositionToFrame(input_length);
*duration = filePositionToTime(input_length);
} else {
assert(sizeof(bigtime_t)==sizeof(uint64_t));
// if the input is not seekable, we return really large sizes
*frameCount = INT64_MAX;
*duration = INT64_MAX;
}
std::vector<ogg_packet> * ogg_packets = &fHeaderPackets[stream->serialno];
format->SetMetaData((void*)ogg_packets,sizeof(ogg_packets));
if (isVorbisPacket(&(*ogg_packets)[0])) {
format->type = B_MEDIA_ENCODED_AUDIO;
format->u.encoded_audio.encoding
= (media_encoded_audio_format::audio_encoding)'vorb';
}
GetCodecStreamInfo(stream,frameCount,duration,format);
*infoBuffer = 0;
*infoSize = 0;
return B_OK;
@@ -336,9 +283,9 @@ oggReader::Seek(void *cookie,
ogg_stream_state * stream = static_cast<ogg_stream_state *>(cookie);
int position;
if (seekTo & B_MEDIA_SEEK_TO_FRAME) {
position = fPostSniffPosition+frameToFilePosition(*frame);
position = fPostSniffPosition+frameToPosition(stream,*frame);
} else if (seekTo & B_MEDIA_SEEK_TO_TIME) {
position = fPostSniffPosition+timeToFilePosition(*time);
position = fPostSniffPosition+timeToPosition(stream,*time);
} else {
return B_ERROR;
}
@@ -391,8 +338,8 @@ synced:
return B_ERROR;
}
// output the values from where we regained sync
*frame = filePositionToFrame(position);
*time = filePositionToTime(position);
*frame = positionToFrame(stream,position);
*time = positionToTime(stream,position);
return B_OK;
}
@@ -42,6 +42,15 @@ public:
private:
status_t GetPage(ogg_page * page, int read_size = 4*B_PAGE_SIZE,
bool short_page = false);
int GetExtraHeaderPacketCount(ogg_packet * packet);
status_t GetCodecStreamInfo(ogg_stream_state * stream,
int64 *frameCount, bigtime_t *duration,
media_format *format);
int64 positionToFrame(ogg_stream_state * stream, off_t position);
off_t frameToPosition(ogg_stream_state * stream, int64 frame);
bigtime_t positionToTime(ogg_stream_state * stream, off_t position);
off_t timeToPosition(ogg_stream_state * stream, bigtime_t time);
BPositionIO * fSeekable;
off_t fPostSniffPosition;
@@ -0,0 +1,219 @@
#include <unistd.h>
#include "OggReaderPlugin.h"
#define TRACE_THIS 1
#if TRACE_THIS
#define TRACE printf
#else
#define TRACE(a...) ((void)0)
#endif
// codec identification
static bool
findIdentifier(ogg_packet * packet, const char * id, uint location)
{
uint length = strlen(id);
if ((unsigned)packet->bytes < location+length) {
return false;
}
return !memcmp(&packet->packet[location], id, length);
}
/*---- vorbis ----*/
static bool
isVorbisPacket(ogg_packet * packet)
{
return findIdentifier(packet,"vorbis",1);
}
static const int vorbis_extra_packet_count = 2;
static status_t
GetVorbisCodecStreamInfo(std::vector<ogg_packet> * packets,
int64 *frameCount, bigtime_t *duration,
media_format *format)
{
format->type = B_MEDIA_ENCODED_AUDIO;
format->u.encoded_audio.encoding
= (media_encoded_audio_format::audio_encoding)'vorb';
return B_OK;
}
/*---- speex ----*/
static bool
isSpeexPacket(ogg_packet * packet)
{
return findIdentifier(packet,"Speex",0);
}
static const int speex_extra_packet_count = 2;
static status_t
GetSpeexCodecStreamInfo(std::vector<ogg_packet> * packets,
int64 *frameCount, bigtime_t *duration,
media_format *format)
{
format->type = B_MEDIA_ENCODED_AUDIO;
format->u.encoded_audio.encoding
= (media_encoded_audio_format::audio_encoding)'Spee';
return B_OK;
}
/*---- tobias ----*/
// 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
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 bool
isTobiasPacket(ogg_packet * packet)
{
return findIdentifier(packet,"video",1);
}
static const int tobias_extra_packet_count = 1;
static status_t
GetTobiasCodecStreamInfo(std::vector<ogg_packet> * packets,
int64 *frameCount, bigtime_t *duration,
media_format *format)
{
ogg_packet * packet = &((*packets)[0]);
if (packet->bytes < (signed)sizeof(tobias_stream_header)) {
return B_ERROR;
}
void * data = &(packet->packet[1]);
tobias_stream_header * header = (tobias_stream_header *)data;
format->type = B_MEDIA_ENCODED_VIDEO;
int32 encoding = header->subtype[3] << 24 | header->subtype[2] << 16
| header->subtype[1] << 8 | header->subtype[0];
format->u.encoded_video.encoding
= (media_encoded_video_format::video_encoding)encoding;
format->u.encoded_video.frame_size
= header->video.width * header->video.height;
format->u.encoded_video.output.display.line_width = header->video.width;
format->u.encoded_video.output.display.line_count = header->video.height;
// TODO: wring more info out of the headers
return B_OK;
}
/*---- generic routines ----*/
int
oggReader::GetExtraHeaderPacketCount(ogg_packet * packet)
{
if (isVorbisPacket(packet)) {
return vorbis_extra_packet_count;
}
if (isTobiasPacket(packet)) {
return tobias_extra_packet_count;
}
if (isSpeexPacket(packet)) {
return speex_extra_packet_count;
}
return 0;
}
status_t
oggReader::GetCodecStreamInfo(ogg_stream_state * stream,
int64 *frameCount, bigtime_t *duration,
media_format *format)
{
std::vector<ogg_packet> * packets = &fHeaderPackets[stream->serialno];
if (fSeekable) {
off_t input_length;
{
off_t current_position = fSeekable->Seek(0,SEEK_CUR);
input_length = fSeekable->Seek(0,SEEK_END)-fPostSniffPosition;
fSeekable->Seek(current_position,SEEK_SET);
}
*frameCount = positionToFrame(stream,input_length);
*duration = positionToTime(stream,input_length);
} else {
assert(sizeof(bigtime_t)==sizeof(uint64_t));
// if the input is not seekable, we return really large sizes
*frameCount = INT64_MAX;
*duration = INT64_MAX;
}
if (!packets || packets->size() < 1) {
return B_BAD_VALUE;
}
ogg_packet * packet = &((*packets)[0]);
if (isVorbisPacket(packet)) {
return GetVorbisCodecStreamInfo(packets,frameCount,duration,format);
}
if (isTobiasPacket(packet)) {
return GetTobiasCodecStreamInfo(packets,frameCount,duration,format);
}
if (isSpeexPacket(packet)) {
return GetSpeexCodecStreamInfo(packets,frameCount,duration,format);
}
return B_OK;
}
// estimate: 1 frame = 256 bytes
int64
oggReader::positionToFrame(ogg_stream_state * stream, off_t position)
{
return position/256;
}
off_t
oggReader::frameToPosition(ogg_stream_state * stream, int64 frame)
{
return frame*256;
}
bigtime_t
oggReader::positionToTime(ogg_stream_state * stream, off_t position)
{
return position*1000/8;
}
off_t
oggReader::timeToPosition(ogg_stream_state * stream, bigtime_t time)
{
return time*8/1000;
}