pass a wave structure as meta data. avcodec needs it
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28077 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -31,19 +31,24 @@
|
|||||||
#include "WavReaderPlugin.h"
|
#include "WavReaderPlugin.h"
|
||||||
#include "RawFormats.h"
|
#include "RawFormats.h"
|
||||||
|
|
||||||
//#define TRACE_WAVE_READER
|
#define TRACE_WAVE_READER
|
||||||
#ifdef TRACE_WAVE_READER
|
#ifdef TRACE_WAVE_READER
|
||||||
#define TRACE printf
|
#define TRACE printf
|
||||||
#else
|
#else
|
||||||
#define TRACE(a...)
|
#define TRACE(a...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define ERROR(a...) fprintf(stderr, a)
|
||||||
|
|
||||||
#define BUFFER_SIZE 16384 // must be > 5200 for mp3 decoder to work
|
#define BUFFER_SIZE 16384 // must be > 5200 for mp3 decoder to work
|
||||||
|
|
||||||
#define FOURCC(a,b,c,d) ((((uint32)(d)) << 24) | (((uint32)(c)) << 16) | (((uint32)(b)) << 8) | ((uint32)(a)))
|
#define FOURCC(a,b,c,d) ((((uint32)(d)) << 24) | (((uint32)(c)) << 16) | (((uint32)(b)) << 8) | ((uint32)(a)))
|
||||||
#define UINT16(a) ((uint16)B_LENDIAN_TO_HOST_INT16((a)))
|
#define UINT16(a) ((uint16)B_LENDIAN_TO_HOST_INT16((a)))
|
||||||
#define UINT32(a) ((uint32)B_LENDIAN_TO_HOST_INT32((a)))
|
#define UINT32(a) ((uint32)B_LENDIAN_TO_HOST_INT32((a)))
|
||||||
|
|
||||||
|
// This Reader only deals with CBR audio
|
||||||
|
// My understanding is that no WAV file will have VBR audio anyway
|
||||||
|
|
||||||
struct wavdata
|
struct wavdata
|
||||||
{
|
{
|
||||||
int64 position;
|
int64 position;
|
||||||
@@ -144,25 +149,25 @@ WavReader::Sniff(int32 *streamCount)
|
|||||||
while (pos + sizeof(chunk_struct) <= fFileSize) {
|
while (pos + sizeof(chunk_struct) <= fFileSize) {
|
||||||
chunk_struct chunk;
|
chunk_struct chunk;
|
||||||
if (sizeof(chunk) != Source()->ReadAt(pos, &chunk, sizeof(chunk))) {
|
if (sizeof(chunk) != Source()->ReadAt(pos, &chunk, sizeof(chunk))) {
|
||||||
TRACE("WavReader::Sniff: chunk header reading failed\n");
|
ERROR("WavReader::Sniff: chunk header reading failed\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
pos += sizeof(chunk);
|
pos += sizeof(chunk);
|
||||||
if (UINT32(chunk.len) == 0) {
|
if (UINT32(chunk.len) == 0) {
|
||||||
TRACE("WavReader::Sniff: Error: chunk of size 0 found\n");
|
ERROR("WavReader::Sniff: Error: chunk of size 0 found\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
switch (UINT32(chunk.fourcc)) {
|
switch (UINT32(chunk.fourcc)) {
|
||||||
case FOURCC('f','m','t',' '):
|
case FOURCC('f','m','t',' '):
|
||||||
if (UINT32(chunk.len) >= sizeof(format)) {
|
if (UINT32(chunk.len) >= sizeof(format)) {
|
||||||
if (sizeof(format) != Source()->ReadAt(pos, &format, sizeof(format))) {
|
if (sizeof(format) != Source()->ReadAt(pos, &format, sizeof(format))) {
|
||||||
TRACE("WavReader::Sniff: format chunk reading failed\n");
|
ERROR("WavReader::Sniff: format chunk reading failed\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
foundFmt = true;
|
foundFmt = true;
|
||||||
if (UINT32(chunk.len) >= sizeof(format_ext) && UINT16(format.format_tag) == 0xfffe) {
|
if (UINT32(chunk.len) >= sizeof(format_ext) && UINT16(format.format_tag) == 0xfffe) {
|
||||||
if (sizeof(format_ext) != Source()->ReadAt(pos, &format_ext, sizeof(format_ext))) {
|
if (sizeof(format_ext) != Source()->ReadAt(pos, &format_ext, sizeof(format_ext))) {
|
||||||
TRACE("WavReader::Sniff: format extensible chunk reading failed\n");
|
ERROR("WavReader::Sniff: format extensible chunk reading failed\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
foundFmtExt = true;
|
foundFmtExt = true;
|
||||||
@@ -172,7 +177,7 @@ WavReader::Sniff(int32 *streamCount)
|
|||||||
case FOURCC('f','a','c','t'):
|
case FOURCC('f','a','c','t'):
|
||||||
if (UINT32(chunk.len) >= sizeof(fact)) {
|
if (UINT32(chunk.len) >= sizeof(fact)) {
|
||||||
if (sizeof(fact) != Source()->ReadAt(pos, &fact, sizeof(fact))) {
|
if (sizeof(fact) != Source()->ReadAt(pos, &fact, sizeof(fact))) {
|
||||||
TRACE("WavReader::Sniff: fact chunk reading failed\n");
|
ERROR("WavReader::Sniff: fact chunk reading failed\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
foundFact = true;
|
foundFact = true;
|
||||||
@@ -201,11 +206,11 @@ WavReader::Sniff(int32 *streamCount)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!foundFmt) {
|
if (!foundFmt) {
|
||||||
TRACE("WavReader::Sniff: couldn't find format chunk\n");
|
ERROR("WavReader::Sniff: couldn't find format chunk\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
if (!foundData) {
|
if (!foundData) {
|
||||||
TRACE("WavReader::Sniff: couldn't find data chunk\n");
|
ERROR("WavReader::Sniff: couldn't find data chunk\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,38 +232,39 @@ WavReader::Sniff(int32 *streamCount)
|
|||||||
TRACE(" sample_length %ld\n", UINT32(fact.sample_length));
|
TRACE(" sample_length %ld\n", UINT32(fact.sample_length));
|
||||||
}
|
}
|
||||||
|
|
||||||
fChannelCount = UINT16(format.channels);
|
fMetaData.extra_size = 0;
|
||||||
fSampleRate = UINT32(format.samples_per_sec);
|
fMetaData.channels = UINT16(format.channels);
|
||||||
fBlockAlign = UINT16(format.block_align);
|
fMetaData.samples_per_sec = UINT32(format.samples_per_sec);
|
||||||
fBitsPerSample = UINT16(format.bits_per_sample);
|
fMetaData.block_align = UINT16(format.block_align);
|
||||||
if (fBitsPerSample == 0) {
|
fMetaData.bits_per_sample = UINT16(format.bits_per_sample);
|
||||||
printf("WavReader::Sniff: Error, bits_per_sample = 0 calculating\n");
|
if (fMetaData.bits_per_sample == 0) {
|
||||||
fBitsPerSample = fBlockAlign * 8 / fChannelCount;
|
fMetaData.bits_per_sample = fMetaData.block_align * 8 / fMetaData.channels;
|
||||||
|
ERROR("WavReader::Sniff: Error, bits_per_sample = 0 calculating as %d\n",fMetaData.bits_per_sample);
|
||||||
}
|
}
|
||||||
fFrameRate = fSampleRate * fChannelCount;
|
fFrameRate = fMetaData.samples_per_sec * fMetaData.channels;
|
||||||
|
|
||||||
fAvgBytesPerSec = format.avg_bytes_per_sec;
|
fMetaData.avg_bytes_per_sec = format.avg_bytes_per_sec;
|
||||||
|
|
||||||
// fact.sample_length is really no of samples for all channels
|
// fact.sample_length is really no of samples for all channels
|
||||||
fFrameCount = foundFact ? UINT32(fact.sample_length) / fChannelCount : 0;
|
fFrameCount = foundFact ? UINT32(fact.sample_length) / fMetaData.channels : 0;
|
||||||
fFormatCode = UINT16(format.format_tag);
|
fMetaData.format_tag = UINT16(format.format_tag);
|
||||||
if (fFormatCode == 0xfffe && foundFmtExt)
|
if (fMetaData.format_tag == 0xfffe && foundFmtExt)
|
||||||
fFormatCode = (format_ext.guid[1] << 8) | format_ext.guid[0];
|
fMetaData.format_tag = (format_ext.guid[1] << 8) | format_ext.guid[0];
|
||||||
|
|
||||||
int min_align = (fFormatCode == 0x0001) ? (fBitsPerSample * fChannelCount + 7) / 8 : 1;
|
int min_align = (fMetaData.format_tag == 0x0001) ? (fMetaData.bits_per_sample * fMetaData.channels + 7) / 8 : 1;
|
||||||
if (fBlockAlign < min_align)
|
if (fMetaData.block_align < min_align)
|
||||||
fBlockAlign = min_align;
|
fMetaData.block_align = min_align;
|
||||||
|
|
||||||
TRACE(" fDataStart %Ld\n", fDataStart);
|
TRACE(" fDataStart %Ld\n", fDataStart);
|
||||||
TRACE(" fDataSize %Ld\n", fDataSize);
|
TRACE(" fDataSize %Ld\n", fDataSize);
|
||||||
TRACE(" fChannelCount %ld\n", fChannelCount);
|
TRACE(" Channels %d\n", fMetaData.channels);
|
||||||
TRACE(" fSampleRate %ld\n", fSampleRate);
|
TRACE(" SampleRate %ld\n", fMetaData.samples_per_sec);
|
||||||
TRACE(" fFrameRate %ld\n", fFrameRate);
|
TRACE(" fFrameRate %ld\n", fFrameRate);
|
||||||
TRACE(" fFrameCount %Ld\n", fFrameCount);
|
TRACE(" fFrameCount %Ld\n", fFrameCount);
|
||||||
TRACE(" fBitsPerSample %d\n", fBitsPerSample);
|
TRACE(" BitsPerSample %d\n", fMetaData.bits_per_sample);
|
||||||
TRACE(" fBlockAlign %d\n", fBlockAlign);
|
TRACE(" BlockAlign %d\n", fMetaData.block_align);
|
||||||
TRACE(" min_align %d\n", min_align);
|
TRACE(" min_align %d\n", min_align);
|
||||||
TRACE(" fFormatCode 0x%04x\n", fFormatCode);
|
TRACE(" Format 0x%04x\n", fMetaData.format_tag);
|
||||||
|
|
||||||
// XXX fact.sample_length contains duration of encoded files?
|
// XXX fact.sample_length contains duration of encoded files?
|
||||||
|
|
||||||
@@ -291,18 +297,18 @@ WavReader::AllocateCookie(int32 streamNumber, void **cookie)
|
|||||||
|
|
||||||
data->position = 0;
|
data->position = 0;
|
||||||
data->datasize = fDataSize;
|
data->datasize = fDataSize;
|
||||||
data->fps = fSampleRate;
|
data->fps = fMetaData.samples_per_sec;
|
||||||
data->buffersize = (BUFFER_SIZE / fBlockAlign) * fBlockAlign;
|
data->buffersize = (BUFFER_SIZE / fMetaData.block_align) * fMetaData.block_align;
|
||||||
data->buffer = malloc(data->buffersize);
|
data->buffer = malloc(data->buffersize);
|
||||||
data->framecount = fFrameCount ? fFrameCount : (8 * fDataSize) / (fChannelCount * fBitsPerSample);
|
data->framecount = fFrameCount ? fFrameCount : (8 * fDataSize) / (fMetaData.channels * fMetaData.bits_per_sample);
|
||||||
data->raw = fFormatCode == 0x0001;
|
data->raw = fMetaData.format_tag == 0x0001;
|
||||||
|
|
||||||
if (!fAvgBytesPerSec) {
|
if (!fMetaData.avg_bytes_per_sec) {
|
||||||
fAvgBytesPerSec = fSampleRate * fBlockAlign;
|
fMetaData.avg_bytes_per_sec = fMetaData.samples_per_sec * fMetaData.block_align;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->duration = (data->datasize * 1000000LL) / fAvgBytesPerSec;
|
data->duration = (data->datasize * 1000000LL) / fMetaData.avg_bytes_per_sec;
|
||||||
data->bitrate = fAvgBytesPerSec * 8;
|
data->bitrate = fMetaData.avg_bytes_per_sec * 8;
|
||||||
|
|
||||||
TRACE(" raw %s\n", data->raw ? "true" : "false");
|
TRACE(" raw %s\n", data->raw ? "true" : "false");
|
||||||
TRACE(" framecount %Ld\n", data->framecount);
|
TRACE(" framecount %Ld\n", data->framecount);
|
||||||
@@ -312,16 +318,16 @@ WavReader::AllocateCookie(int32 streamNumber, void **cookie)
|
|||||||
TRACE(" buffersize %ld\n", data->buffersize);
|
TRACE(" buffersize %ld\n", data->buffersize);
|
||||||
|
|
||||||
BMediaFormats formats;
|
BMediaFormats formats;
|
||||||
if (fFormatCode == 0x0001) {
|
if (fMetaData.format_tag == 0x0001) {
|
||||||
// a raw PCM format
|
// a raw PCM format
|
||||||
media_format_description description;
|
media_format_description description;
|
||||||
description.family = B_BEOS_FORMAT_FAMILY;
|
description.family = B_BEOS_FORMAT_FAMILY;
|
||||||
description.u.beos.format = B_BEOS_FORMAT_RAW_AUDIO;
|
description.u.beos.format = B_BEOS_FORMAT_RAW_AUDIO;
|
||||||
formats.GetFormatFor(description, &data->format);
|
formats.GetFormatFor(description, &data->format);
|
||||||
// Really SampleRate
|
// Really SampleRate
|
||||||
data->format.u.raw_audio.frame_rate = fSampleRate;
|
data->format.u.raw_audio.frame_rate = fMetaData.samples_per_sec;
|
||||||
data->format.u.raw_audio.channel_count = fChannelCount;
|
data->format.u.raw_audio.channel_count = fMetaData.channels;
|
||||||
switch (fBitsPerSample) {
|
switch (fMetaData.bits_per_sample) {
|
||||||
case 8:
|
case 8:
|
||||||
data->format.u.raw_audio.format = B_AUDIO_FORMAT_UINT8;
|
data->format.u.raw_audio.format = B_AUDIO_FORMAT_UINT8;
|
||||||
break;
|
break;
|
||||||
@@ -335,7 +341,8 @@ WavReader::AllocateCookie(int32 streamNumber, void **cookie)
|
|||||||
data->format.u.raw_audio.format = B_AUDIO_FORMAT_INT32;
|
data->format.u.raw_audio.format = B_AUDIO_FORMAT_INT32;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TRACE("WavReader::AllocateCookie: unhandled bits per sample %d\n", fBitsPerSample);
|
ERROR("WavReader::AllocateCookie: unhandled bits per sample %d\n", fMetaData.bits_per_sample);
|
||||||
|
delete data;
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
data->format.u.raw_audio.format |= B_AUDIO_FORMAT_CHANNEL_ORDER_WAVE;
|
data->format.u.raw_audio.format |= B_AUDIO_FORMAT_CHANNEL_ORDER_WAVE;
|
||||||
@@ -345,13 +352,22 @@ WavReader::AllocateCookie(int32 streamNumber, void **cookie)
|
|||||||
// some encoded format
|
// some encoded format
|
||||||
media_format_description description;
|
media_format_description description;
|
||||||
description.family = B_WAV_FORMAT_FAMILY;
|
description.family = B_WAV_FORMAT_FAMILY;
|
||||||
description.u.wav.codec = fFormatCode;
|
description.u.wav.codec = fMetaData.format_tag;
|
||||||
formats.GetFormatFor(description, &data->format);
|
formats.GetFormatFor(description, &data->format);
|
||||||
// Really SampleRate
|
// Really SampleRate
|
||||||
data->format.u.encoded_audio.output.frame_rate = fSampleRate;
|
data->format.u.encoded_audio.bit_rate = data->bitrate;
|
||||||
data->format.u.encoded_audio.output.channel_count = fChannelCount;
|
data->format.u.encoded_audio.output.frame_rate = fMetaData.samples_per_sec;
|
||||||
|
data->format.u.encoded_audio.output.channel_count = fMetaData.channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("SetMetaData called with size %ld\n",sizeof(wave_format_ex));
|
||||||
|
|
||||||
|
if (data->format.SetMetaData(&fMetaData, sizeof(wave_format_ex)) != B_OK) {
|
||||||
|
ERROR("WavReader::Failed to SetMetaData\n");
|
||||||
|
delete data;
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
// store the cookie
|
// store the cookie
|
||||||
*cookie = data;
|
*cookie = data;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -380,8 +396,8 @@ WavReader::GetStreamInfo(void *cookie, int64 *frameCount, bigtime_t *duration,
|
|||||||
*frameCount = data->framecount;
|
*frameCount = data->framecount;
|
||||||
*duration = data->duration;
|
*duration = data->duration;
|
||||||
*format = data->format;
|
*format = data->format;
|
||||||
*infoBuffer = 0;
|
*infoBuffer = &fMetaData;
|
||||||
*infoSize = 0;
|
*infoSize = sizeof(wave_format_ex);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,7 +420,7 @@ WavReader::CalculateNewPosition(void *cookie,
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
*position = (*position / fBlockAlign) * fBlockAlign; // round down to a block start
|
*position = (*position / fMetaData.block_align) * fMetaData.block_align; // round down to a block start
|
||||||
|
|
||||||
TRACE(", position %Ld ", *position);
|
TRACE(", position %Ld ", *position);
|
||||||
|
|
||||||
@@ -415,7 +431,7 @@ WavReader::CalculateNewPosition(void *cookie,
|
|||||||
TRACE("newframe %Ld\n", *frame);
|
TRACE("newframe %Ld\n", *frame);
|
||||||
|
|
||||||
if (*position < 0 || *position > data->datasize) {
|
if (*position < 0 || *position > data->datasize) {
|
||||||
printf("WavReader::CalculateNewPosition invalid position %Ld\n", *position);
|
ERROR("WavReader::CalculateNewPosition invalid position %Ld\n", *position);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,12 +492,12 @@ WavReader::GetNextChunk(void *cookie,
|
|||||||
if (maxreadsize < readsize)
|
if (maxreadsize < readsize)
|
||||||
readsize = maxreadsize;
|
readsize = maxreadsize;
|
||||||
if (readsize == 0) {
|
if (readsize == 0) {
|
||||||
printf("WavReader::GetNextChunk: LAST BUFFER ERROR at time %9Ld\n",mediaHeader->start_time);
|
ERROR("WavReader::GetNextChunk: LAST BUFFER ERROR at time %9Ld\n",mediaHeader->start_time);
|
||||||
return B_LAST_BUFFER_ERROR;
|
return B_LAST_BUFFER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readsize != Source()->ReadAt(fDataStart + data->position, data->buffer, readsize)) {
|
if (readsize != Source()->ReadAt(fDataStart + data->position, data->buffer, readsize)) {
|
||||||
printf("WavReader::GetNextChunk: unexpected read error at position %9Ld\n",fDataStart + data->position);
|
ERROR("WavReader::GetNextChunk: unexpected read error at position %9Ld\n",fDataStart + data->position);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,15 +66,11 @@ private:
|
|||||||
int64 fFileSize;
|
int64 fFileSize;
|
||||||
int64 fDataStart;
|
int64 fDataStart;
|
||||||
int64 fDataSize;
|
int64 fDataSize;
|
||||||
|
|
||||||
|
wave_format_ex fMetaData;
|
||||||
|
|
||||||
int64 fFrameCount;
|
int64 fFrameCount;
|
||||||
int32 fChannelCount;
|
|
||||||
int32 fFrameRate;
|
int32 fFrameRate;
|
||||||
int32 fSampleRate;
|
|
||||||
uint16 fBitsPerSample;
|
|
||||||
uint16 fFormatCode;
|
|
||||||
uint16 fBlockAlign;
|
|
||||||
uint32 fAvgBytesPerSec;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,16 @@ struct format_struct
|
|||||||
uint16 bits_per_sample;
|
uint16 bits_per_sample;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wave_format_ex {
|
||||||
|
uint16 format_tag;
|
||||||
|
uint16 channels;
|
||||||
|
uint32 samples_per_sec;
|
||||||
|
uint32 avg_bytes_per_sec;
|
||||||
|
uint16 block_align;
|
||||||
|
uint16 bits_per_sample;
|
||||||
|
uint16 extra_size;
|
||||||
|
} _PACKED;
|
||||||
|
|
||||||
struct format_struct_extensible
|
struct format_struct_extensible
|
||||||
{
|
{
|
||||||
uint16 format_tag; // 0xfffe for extensible format
|
uint16 format_tag; // 0xfffe for extensible format
|
||||||
|
|||||||
Reference in New Issue
Block a user