added added au (Sun audio file) format reader

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5734 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper 2003-12-22 23:46:49 +00:00
parent f7f27fcb79
commit 228c585f82
5 changed files with 473 additions and 0 deletions

View File

@ -1,5 +1,6 @@
SubDir OBOS_TOP src add-ons media plugins ;
SubInclude OBOS_TOP src add-ons media plugins au_reader ;
SubInclude OBOS_TOP src add-ons media plugins avi_reader ;
SubInclude OBOS_TOP src add-ons media plugins mp3_reader ;
SubInclude OBOS_TOP src add-ons media plugins wav_reader ;

View File

@ -0,0 +1,9 @@
SubDir OBOS_TOP src add-ons media plugins au_reader ;
UsePrivateHeaders media ;
Addon au_reader : media plugins :
au_reader.cpp
;
LinkSharedOSLibs au_reader : be libmedia.so ;

View File

@ -0,0 +1,51 @@
#ifndef _AU_H
#define _AU_H
struct snd_header {
uint32 magic; // magic number '.snd'
uint32 data_start; // offset to the data
uint32 data_size; // number of bytes of data
uint32 data_format; // data format code
uint32 sampling_rate; // sampling rate
uint32 channel_count; // number of channels
char info[4]; // optional text information, NULL termintated, at least 4 bytes
};
enum {
SND_FORMAT_UNSPECIFIED = 0, // unspecified format
SND_FORMAT_MULAW_8 = 1, // 8-bit mu-law samples
SND_FORMAT_LINEAR_8 = 2, // 8-bit linear samples
SND_FORMAT_LINEAR_16 = 3, // 16-bit linear samples
SND_FORMAT_LINEAR_24 = 4, // 24-bit linear samples
SND_FORMAT_LINEAR_32 = 5, // 32-bit linear samples
SND_FORMAT_FLOAT = 6, // 32-bit IEEE floating-point samples
SND_FORMAT_DOUBLE = 7, // 64-bit IEEE floating-point samples
SND_FORMAT_INDIRECT = 8, // fragmented sampled data
SND_FORMAT_NESTED = 9,
SND_FORMAT_DSP_CORE = 10, // DSP program
SND_FORMAT_DSP_DATA_8 = 11, // 8-bit fixed-point samples
SND_FORMAT_DSP_DATA_16 = 12,// 16-bit fixed-point samples
SND_FORMAT_DSP_DATA_24 = 13,// 24-bit fixed-point samples
SND_FORMAT_DSP_DATA_32 = 14,// 32-bit fixed-point samples
SND_FORMAT_15 = 15,
SND_FORMAT_DISPLAY = 16, // non-audio display data
SND_FORMAT_MULAW_SQUELCH = 17,
SND_FORMAT_EMPHASIZED = 18, // 16-bit linear with emphasis
SND_FORMAT_COMPRESSED = 19, // 16-bit linear with compression
SND_FORMAT_COMPRESSED_EMPHASIZED = 20, // A combination of the two above
SND_FORMAT_DSP_COMMANDS = 21,// Music Kit DSP commands
SND_FORMAT_DSP_COMMANDS_SAMPLES = 22,
SND_FORMAT_ADPCM_G721 = 23,
SND_FORMAT_ADPCM_G722 = 24,
SND_FORMAT_ADPCM_G723_3 = 25,
SND_FORMAT_ADPCM_G723_5 = 26,
SND_FORMAT_ALAW_8 = 27,
};
#define SND_RATE_8012 8012.821 // CODEC input
#define SND_RATE_22050 22050.0 // low sampling rate output
#define SND_RATE_44100 44100.0 // high sampling rate output
#define SND_MAGIC 0x2e736e64 // '.snd'
#endif

View File

@ -0,0 +1,348 @@
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <DataIO.h>
#include <ByteOrder.h>
#include <InterfaceDefs.h>
#include "au_reader.h"
#define TRACE_THIS 1
#if TRACE_THIS
#define TRACE printf
#else
#define TRACE(a...)
#endif
#define BUFFER_SIZE 16384
#define UINT32(a) ((uint32)B_BENDIAN_TO_HOST_INT32((a)))
auReader::auReader()
{
TRACE("auReader::auReader\n");
fBuffer = 0;
}
auReader::~auReader()
{
if (fBuffer)
free(fBuffer);
}
const char *
auReader::Copyright()
{
return ".au & .snd reader, " B_UTF8_COPYRIGHT " by Marcus Overhagen";
}
status_t
auReader::Sniff(int32 *streamCount)
{
TRACE("auReader::Sniff\n");
fSource = dynamic_cast<BPositionIO *>(Reader::Source());
if (!fSource) {
TRACE("auReader::Sniff: not a BPositionIO\n");
return B_ERROR;
}
int64 filesize = Source()->Seek(0, SEEK_END);
if (filesize < 28) {
TRACE("auReader::Sniff: File too small\n");
return B_ERROR;
}
snd_header header;
if (sizeof(header) != Source()->ReadAt(0, &header, sizeof(header))) {
TRACE("auReader::Sniff: header reading failed\n");
return B_ERROR;
}
if (UINT32(header.magic) != SND_MAGIC) {
TRACE("auReader::Sniff: header not recognized\n");
return B_ERROR;
}
TRACE("auReader::Sniff: we found something that looks like:\n");
TRACE(" data_start %ld\n", UINT32(header.data_start));
TRACE(" data_size %ld\n", UINT32(header.data_size));
TRACE(" data_format %ld\n", UINT32(header.data_format));
TRACE(" sampling_rate %ld\n", UINT32(header.sampling_rate));
TRACE(" channel_count %ld\n", UINT32(header.channel_count));
fDataStart = 28 + UINT32(header.data_start);
fDataSize = UINT32(header.data_size);
fChannelCount = UINT32(header.channel_count);
fFrameRate = UINT32(header.sampling_rate);
fFormatCode = UINT32(header.data_format);
switch (fFormatCode) {
case SND_FORMAT_UNSPECIFIED: TRACE("SND_FORMAT_UNSPECIFIED\n"); break;
case SND_FORMAT_MULAW_8: TRACE("SND_FORMAT_MULAW_8\n"); break;
case SND_FORMAT_LINEAR_8: TRACE("SND_FORMAT_LINEAR_8\n"); break;
case SND_FORMAT_LINEAR_16: TRACE("SND_FORMAT_LINEAR_16\n"); break;
case SND_FORMAT_LINEAR_24: TRACE("SND_FORMAT_LINEAR_24\n"); break;
case SND_FORMAT_LINEAR_32: TRACE("SND_FORMAT_LINEAR_32\n"); break;
case SND_FORMAT_FLOAT: TRACE("SND_FORMAT_FLOAT\n"); break;
case SND_FORMAT_DOUBLE: TRACE("SND_FORMAT_DOUBLE\n"); break;
case SND_FORMAT_INDIRECT: TRACE("SND_FORMAT_INDIRECT\n"); break;
case SND_FORMAT_NESTED: TRACE("SND_FORMAT_NESTED\n"); break;
case SND_FORMAT_DSP_CORE: TRACE("SND_FORMAT_DSP_CORE\n"); break;
case SND_FORMAT_DSP_DATA_8: TRACE("SND_FORMAT_DSP_DATA_8\n"); break;
case SND_FORMAT_DSP_DATA_16: TRACE("SND_FORMAT_DSP_DATA_16\n"); break;
case SND_FORMAT_DSP_DATA_24: TRACE("SND_FORMAT_DSP_DATA_24\n"); break;
case SND_FORMAT_DSP_DATA_32: TRACE("SND_FORMAT_DSP_DATA_32\n"); break;
case SND_FORMAT_DISPLAY: TRACE("SND_FORMAT_DISPLAY\n"); break;
case SND_FORMAT_MULAW_SQUELCH: TRACE("SND_FORMAT_MULAW_SQUELCH\n"); break;
case SND_FORMAT_EMPHASIZED: TRACE("SND_FORMAT_EMPHASIZED\n"); break;
case SND_FORMAT_COMPRESSED: TRACE("SND_FORMAT_COMPRESSED\n"); break;
case SND_FORMAT_COMPRESSED_EMPHASIZED: TRACE("SND_FORMAT_COMPRESSED_EMPHASIZED\n"); break;
case SND_FORMAT_DSP_COMMANDS: TRACE("SND_FORMAT_DSP_COMMANDS\n"); break;
case SND_FORMAT_DSP_COMMANDS_SAMPLES: TRACE("SND_FORMAT_DSP_COMMANDS_SAMPLES\n"); break;
case SND_FORMAT_ADPCM_G721: TRACE("SND_FORMAT_ADPCM_G721\n"); break;
case SND_FORMAT_ADPCM_G722: TRACE("SND_FORMAT_ADPCM_G722\n"); break;
case SND_FORMAT_ADPCM_G723_3: TRACE("SND_FORMAT_ADPCM_G723_3\n"); break;
case SND_FORMAT_ADPCM_G723_5: TRACE("SND_FORMAT_ADPCM_G723_5\n"); break;
case SND_FORMAT_ALAW_8: TRACE("SND_FORMAT_ALAW_8\n"); break;
}
switch (fFormatCode) {
case SND_FORMAT_MULAW_8:
fBitsPerSample = 8; fRaw = false; break;
case SND_FORMAT_LINEAR_8:
fBitsPerSample = 8; fRaw = true; break;
case SND_FORMAT_LINEAR_16:
fBitsPerSample = 16; fRaw = true; break;
case SND_FORMAT_LINEAR_24:
fBitsPerSample = 24; fRaw = true; break;
case SND_FORMAT_LINEAR_32:
fBitsPerSample = 32; fRaw = true; break;
case SND_FORMAT_FLOAT:
fBitsPerSample = 32; fRaw = true; break;
case SND_FORMAT_DOUBLE:
fBitsPerSample = 64; fRaw = true; break;
case SND_FORMAT_ADPCM_G721:
fBitsPerSample = 4; fRaw = false; break;
case SND_FORMAT_ADPCM_G722:
fBitsPerSample = 8; fRaw = false; break;
case SND_FORMAT_ADPCM_G723_3:
fBitsPerSample = 3; fRaw = false; break;
case SND_FORMAT_ADPCM_G723_5:
fBitsPerSample = 5; fRaw = false; break;
case SND_FORMAT_ALAW_8:
fBitsPerSample = 8; fRaw = false; break;
default:
fBitsPerSample = 0; break;
}
if (fBitsPerSample == 0) {
TRACE("auReader::Sniff: sample format not recognized\n");
return B_ERROR;
}
fFrameCount = fDataSize / (fChannelCount * fBitsPerSample);
fDuration = (1000000LL * fFrameCount) / fFrameRate;
fBitsPerFrame = fChannelCount * fBitsPerSample;
fBlockAlign = fBitsPerFrame;
while (fBlockAlign % 8 && fBlockAlign < 1000)
fBlockAlign += fBlockAlign;
if (fBlockAlign % 8) {
TRACE("auReader::Sniff: can't find block alignment, fChannelCount %d, fBitsPerSample %d\n", fChannelCount, fBitsPerSample);
return B_ERROR;
}
fBlockAlign /= 8;
fPosition = 0;
fBufferSize = (BUFFER_SIZE / fBlockAlign) * fBlockAlign;
fBuffer = malloc(fBufferSize);
TRACE(" fDataStart %Ld\n", fDataStart);
TRACE(" fDataSize %Ld\n", fDataSize);
TRACE(" fFrameCount %Ld\n", fFrameCount);
TRACE(" fDuration %Ld\n", fDuration);
TRACE(" fChannelCount %d\n", fChannelCount);
TRACE(" fFrameRate %ld\n", fFrameRate);
TRACE(" fBitsPerSample %d\n", fBitsPerSample);
TRACE(" fBlockAlign %d\n", fBlockAlign);
TRACE(" fFormatCode %ld\n", fFormatCode);
TRACE(" fRaw %d\n", fRaw);
BMediaFormats formats;
if (fRaw) {
// a raw PCM format
media_format_description description;
description.family = B_BEOS_FORMAT_FAMILY;
description.u.beos.format = B_BEOS_FORMAT_RAW_AUDIO;
formats.GetFormatFor(description, &fFormat);
fFormat.u.raw_audio.frame_rate = (fFrameRate == 8012) ? SND_RATE_8012 : fFrameRate;
fFormat.u.raw_audio.channel_count = fChannelCount;
switch (fFormatCode) {
case SND_FORMAT_LINEAR_8:
fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_UCHAR;
break;
case SND_FORMAT_LINEAR_16:
fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT;
break;
case SND_FORMAT_LINEAR_24:
fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_INT;
break;
case SND_FORMAT_LINEAR_32:
fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_INT;
break;
case SND_FORMAT_FLOAT:
fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
break;
case SND_FORMAT_DOUBLE:
fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
break;
}
fFormat.u.raw_audio.byte_order = B_MEDIA_BIG_ENDIAN;
fFormat.u.raw_audio.buffer_size = fBufferSize;
} else {
// some encoded format
media_format_description description;
description.family = B_MISC_FORMAT_FAMILY;
description.u.misc.file_format = 'au';
description.u.misc.codec = fFormatCode;
formats.GetFormatFor(description, &fFormat);
fFormat.u.encoded_audio.output.frame_rate = fFrameRate;
fFormat.u.encoded_audio.output.channel_count = fChannelCount;
}
*streamCount = 1;
return B_OK;
}
void
auReader::GetFileFormatInfo(media_file_format *mff)
{
mff->capabilities = media_file_format::B_READABLE
| media_file_format::B_KNOWS_ENCODED_AUDIO
| media_file_format::B_IMPERFECTLY_SEEKABLE;
mff->family = B_MISC_FORMAT_FAMILY;
mff->version = 100;
strcpy(mff->mime_type, "audio/x-au");
strcpy(mff->file_extension, "au");
strcpy(mff->short_name, "Sun audio file");
strcpy(mff->pretty_name, "Sun audio file");
}
status_t
auReader::AllocateCookie(int32 streamNumber, void **cookie)
{
return B_OK;
}
status_t
auReader::FreeCookie(void *cookie)
{
return B_OK;
}
status_t
auReader::GetStreamInfo(void *cookie, int64 *frameCount, bigtime_t *duration,
media_format *format, void **infoBuffer, int32 *infoSize)
{
*frameCount = fFrameCount;
*duration = fDuration;
*format = fFormat;
*infoBuffer = 0;
*infoSize = 0;
return B_OK;
}
status_t
auReader::Seek(void *cookie,
uint32 seekTo,
int64 *frame, bigtime_t *time)
{
int64 pos;
if (seekTo & B_MEDIA_SEEK_TO_FRAME) {
if (fRaw)
pos = (*frame * fBitsPerFrame) / 8;
else
pos = (*frame * fDataSize) / fFrameCount;
pos = (pos / fBlockAlign) * fBlockAlign; // round down to a block start
TRACE("auReader::Seek to frame %Ld, pos %Ld\n", *frame, pos);
} else if (seekTo & B_MEDIA_SEEK_TO_TIME) {
if (fRaw)
pos = (*time * fFrameRate * fBitsPerFrame) / (1000000LL * 8);
else
pos = (*time * fDataSize) / fDuration;
pos = (pos / fBlockAlign) * fBlockAlign; // round down to a block start
TRACE("auReader::Seek to time %Ld, pos %Ld\n", *time, pos);
} else {
return B_ERROR;
}
if (fRaw)
*frame = (8 * pos) / fBitsPerFrame;
else
*frame = (pos * fFrameCount) / fDataSize;
*time = (*frame * 1000000LL) / fFrameRate;
TRACE("auReader::Seek newtime %Ld\n", *time);
TRACE("auReader::Seek newframe %Ld\n", *frame);
if (pos < 0 || pos > fDataSize) {
TRACE("auReader::Seek invalid position %Ld\n", pos);
return B_ERROR;
}
fPosition = pos;
return B_OK;
}
status_t
auReader::GetNextChunk(void *cookie,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader)
{
// XXX it might be much better to not return any start_time information for encoded formats here,
// XXX and instead use the last time returned from seek and count forward after decoding.
mediaHeader->start_time = (((8 * fPosition) / fBitsPerFrame) * 1000000LL) / fFrameRate;
mediaHeader->file_pos = fDataStart + fPosition;
int64 maxreadsize = fDataSize - fPosition;
int32 readsize = fBufferSize;
if (maxreadsize < readsize)
readsize = maxreadsize;
if (readsize == 0)
return B_LAST_BUFFER_ERROR;
if (readsize != Source()->ReadAt(fDataStart + fPosition, fBuffer, readsize)) {
TRACE("auReader::GetNextChunk: unexpected read error\n");
return B_ERROR;
}
// XXX if the stream has more than two channels, we need to reorder channel data here
fPosition += readsize;
*chunkBuffer = fBuffer;
*chunkSize = readsize;
return B_OK;
}
Reader *
auReaderPlugin::NewReader()
{
return new auReader;
}
MediaPlugin *instantiate_plugin()
{
return new auReaderPlugin;
}

View File

@ -0,0 +1,64 @@
#include "ReaderPlugin.h"
#include "au.h"
class auReader : public Reader
{
public:
auReader();
~auReader();
const char *Copyright();
status_t Sniff(int32 *streamCount);
void GetFileFormatInfo(media_file_format *mff);
status_t AllocateCookie(int32 streamNumber, void **cookie);
status_t FreeCookie(void *cookie);
status_t GetStreamInfo(void *cookie, int64 *frameCount, bigtime_t *duration,
media_format *format, void **infoBuffer, int32 *infoSize);
status_t Seek(void *cookie,
uint32 seekTo,
int64 *frame, bigtime_t *time);
status_t GetNextChunk(void *cookie,
void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader);
BPositionIO *Source() { return fSource; }
private:
BPositionIO * fSource;
media_format fFormat;
int64 fDataStart;
int64 fDataSize;
int64 fFrameCount;
bigtime_t fDuration;
bool fRaw;
int64 fPosition;
int fChannelCount;
int32 fFrameRate;
int fBitsPerSample;
int fBitsPerFrame;
int fBlockAlign;
uint32 fFormatCode;
void * fBuffer;
int32 fBufferSize;
};
class auReaderPlugin : public ReaderPlugin
{
public:
Reader *NewReader();
};
MediaPlugin *instantiate_plugin();