fixed timing information returned in media_header
added GetFileFormatInfo to reader api git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5595 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -21,6 +21,8 @@ public:
|
|||||||
|
|
||||||
virtual status_t Sniff(int32 *streamCount) = 0;
|
virtual status_t Sniff(int32 *streamCount) = 0;
|
||||||
|
|
||||||
|
virtual void GetFileFormatInfo(media_file_format *mff) = 0;
|
||||||
|
|
||||||
virtual status_t AllocateCookie(int32 streamNumber, void **cookie) = 0;
|
virtual status_t AllocateCookie(int32 streamNumber, void **cookie) = 0;
|
||||||
virtual status_t FreeCookie(void *cookie) = 0;
|
virtual status_t FreeCookie(void *cookie) = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ mp3Decoder::Setup(media_format *ioEncodedFormat, media_format *ioDecodedFormat,
|
|||||||
ioDecodedFormat->u.raw_audio.buffer_size = OUTPUT_BUFFER_SIZE;
|
ioDecodedFormat->u.raw_audio.buffer_size = OUTPUT_BUFFER_SIZE;
|
||||||
ioDecodedFormat->u.raw_audio.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT;
|
ioDecodedFormat->u.raw_audio.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT;
|
||||||
fFrameSize = 4;
|
fFrameSize = 4;
|
||||||
|
fFps = 44100;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +68,9 @@ mp3Decoder::Decode(void *buffer, int64 *frameCount,
|
|||||||
uint8 * out_buffer = static_cast<uint8 *>(buffer);
|
uint8 * out_buffer = static_cast<uint8 *>(buffer);
|
||||||
int32 out_bytes_needed = OUTPUT_BUFFER_SIZE;
|
int32 out_bytes_needed = OUTPUT_BUFFER_SIZE;
|
||||||
|
|
||||||
|
mediaHeader->start_time = fStartTime;
|
||||||
|
//TRACE("mp3Decoder: Decoding start time %.6f\n", fStartTime / 1000000.0);
|
||||||
|
|
||||||
while (out_bytes_needed > 0) {
|
while (out_bytes_needed > 0) {
|
||||||
if (fResidualBytes) {
|
if (fResidualBytes) {
|
||||||
int32 bytes = min_c(fResidualBytes, out_bytes_needed);
|
int32 bytes = min_c(fResidualBytes, out_bytes_needed);
|
||||||
@@ -75,31 +79,50 @@ mp3Decoder::Decode(void *buffer, int64 *frameCount,
|
|||||||
fResidualBytes -= bytes;
|
fResidualBytes -= bytes;
|
||||||
out_buffer += bytes;
|
out_buffer += bytes;
|
||||||
out_bytes_needed -= bytes;
|
out_bytes_needed -= bytes;
|
||||||
|
|
||||||
|
fStartTime += (1000000LL * (bytes / fFrameSize)) / fFps;
|
||||||
|
|
||||||
|
//TRACE("mp3Decoder: fStartTime inc'd to %.6f\n", fStartTime / 1000000.0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *chunkBuffer;
|
if (B_OK != DecodeNextChunk())
|
||||||
int32 chunkSize;
|
break;
|
||||||
if (B_OK != GetNextChunk(&chunkBuffer, &chunkSize, mediaHeader)) {
|
|
||||||
TRACE("mp3Decoder::Decode: GetNextChunk failed\n");
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
int outsize;
|
|
||||||
int result;
|
|
||||||
result = decodeMP3(&fMpgLibPrivate, (char *)chunkBuffer, chunkSize, (char *)fDecodeBuffer, DECODE_BUFFER_SIZE, &outsize);
|
|
||||||
if (result == MP3_ERR) {
|
|
||||||
TRACE("mp3Decoder::Decode: decodeMP3 returned MP3_ERR\n");
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
//printf("mp3Decoder::Decode: decoded %d bytes into %d bytes\n",chunkSize, outsize);
|
|
||||||
|
|
||||||
fResidualBuffer = fDecodeBuffer;
|
|
||||||
fResidualBytes = outsize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*frameCount = OUTPUT_BUFFER_SIZE / fFrameSize;
|
*frameCount = (OUTPUT_BUFFER_SIZE - out_bytes_needed) / fFrameSize;
|
||||||
|
|
||||||
|
// XXX this doesn't guarantee that we always return B_LAST_BUFFER_ERROR bofore returning B_ERROR
|
||||||
|
return (out_bytes_needed == 0) ? B_OK : (out_bytes_needed == OUTPUT_BUFFER_SIZE) ? B_ERROR : B_LAST_BUFFER_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
mp3Decoder::DecodeNextChunk()
|
||||||
|
{
|
||||||
|
void *chunkBuffer;
|
||||||
|
int32 chunkSize;
|
||||||
|
media_header mh;
|
||||||
|
if (B_OK != GetNextChunk(&chunkBuffer, &chunkSize, &mh)) {
|
||||||
|
TRACE("mp3Decoder::Decode: GetNextChunk failed\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
fStartTime = mh.start_time;
|
||||||
|
|
||||||
|
//TRACE("mp3Decoder: fStartTime reset to %.6f\n", fStartTime / 1000000.0);
|
||||||
|
|
||||||
|
int outsize;
|
||||||
|
int result;
|
||||||
|
result = decodeMP3(&fMpgLibPrivate, (char *)chunkBuffer, chunkSize, (char *)fDecodeBuffer, DECODE_BUFFER_SIZE, &outsize);
|
||||||
|
if (result == MP3_ERR) {
|
||||||
|
TRACE("mp3Decoder::Decode: decodeMP3 returned MP3_ERR\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("mp3Decoder::Decode: decoded %d bytes into %d bytes\n",chunkSize, outsize);
|
||||||
|
|
||||||
|
fResidualBuffer = fDecodeBuffer;
|
||||||
|
fResidualBytes = outsize;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,12 +18,17 @@ public:
|
|||||||
|
|
||||||
status_t Decode(void *buffer, int64 *frameCount,
|
status_t Decode(void *buffer, int64 *frameCount,
|
||||||
media_header *mediaHeader, media_decode_info *info);
|
media_header *mediaHeader, media_decode_info *info);
|
||||||
|
|
||||||
|
status_t DecodeNextChunk();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct mpstr fMpgLibPrivate;
|
struct mpstr fMpgLibPrivate;
|
||||||
int32 fResidualBytes;
|
int32 fResidualBytes;
|
||||||
uint8 * fResidualBuffer;
|
uint8 * fResidualBuffer;
|
||||||
uint8 * fDecodeBuffer;
|
uint8 * fDecodeBuffer;
|
||||||
int32 fFrameSize;
|
int32 fFrameSize;
|
||||||
|
int32 fFps;
|
||||||
|
bigtime_t fStartTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,15 @@ static const int frame_rate_table[4][4] =
|
|||||||
{ 44100, 48000, 32000, 0} // mpeg version 1
|
{ 44100, 48000, 32000, 0} // mpeg version 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// name_table[mpeg_version_index][layer_index]
|
||||||
|
static const char * name_table[4][4] =
|
||||||
|
{
|
||||||
|
{ 0, "MPEG 2.5 Audio Layer 3", "MPEG 2.5 Audio Layer 2", "MPEG 2.5 Audio Layer 1" },
|
||||||
|
{ 0, 0, 0, 0 },
|
||||||
|
{ 0, "MPEG 2 Audio Layer 3", "MPEG 2 Audio Layer 2", "MPEG 2 Audio Layer 1" },
|
||||||
|
{ 0, "MPEG 1 Audio Layer 3", "MPEG 1 Audio Layer 2", "MPEG 1 Audio Layer 1" },
|
||||||
|
};
|
||||||
|
|
||||||
// frame_sample_count_table[layer_index]
|
// frame_sample_count_table[layer_index]
|
||||||
static const int frame_sample_count_table[4] = { 0, 1152, 1152, 384 };
|
static const int frame_sample_count_table[4] = { 0, 1152, 1152, 384 };
|
||||||
|
|
||||||
@@ -106,6 +115,7 @@ struct mp3Reader::fhg_vbr_info
|
|||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
mp3Reader::mp3Reader()
|
mp3Reader::mp3Reader()
|
||||||
: fXingVbrInfo(0),
|
: fXingVbrInfo(0),
|
||||||
fFhgVbrInfo(0)
|
fFhgVbrInfo(0)
|
||||||
@@ -113,12 +123,14 @@ mp3Reader::mp3Reader()
|
|||||||
TRACE("mp3Reader::mp3Reader\n");
|
TRACE("mp3Reader::mp3Reader\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mp3Reader::~mp3Reader()
|
mp3Reader::~mp3Reader()
|
||||||
{
|
{
|
||||||
delete fXingVbrInfo;
|
delete fXingVbrInfo;
|
||||||
delete fFhgVbrInfo;
|
delete fFhgVbrInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
mp3Reader::Copyright()
|
mp3Reader::Copyright()
|
||||||
{
|
{
|
||||||
@@ -158,6 +170,26 @@ mp3Reader::Sniff(int32 *streamCount)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
mp3Reader::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_MPEG_FORMAT_FAMILY;
|
||||||
|
mff->version = 100;
|
||||||
|
strcpy(mff->mime_type, "audio/mpeg");
|
||||||
|
strcpy(mff->file_extension, "mp3");
|
||||||
|
|
||||||
|
uint8 header[4];
|
||||||
|
Source()->ReadAt(fDataStart, header, sizeof(header));
|
||||||
|
int mpeg_version_index = (header[1] >> 3) & 0x03;
|
||||||
|
int layer_index = (header[1] >> 1) & 0x03;
|
||||||
|
strcpy(mff->short_name, name_table[mpeg_version_index][layer_index]);
|
||||||
|
strcpy(mff->pretty_name, name_table[mpeg_version_index][layer_index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
mp3Reader::AllocateCookie(int32 streamNumber, void **cookie)
|
mp3Reader::AllocateCookie(int32 streamNumber, void **cookie)
|
||||||
{
|
{
|
||||||
@@ -306,6 +338,8 @@ mp3Reader::Seek(void *cookie,
|
|||||||
}
|
}
|
||||||
data->position = pos + ofs;
|
data->position = pos + ofs;
|
||||||
|
|
||||||
|
data->framePosition = *frame; // this is not exact
|
||||||
|
|
||||||
TRACE("mp3Reader::Seek: synchronized at position %Ld\n", data->position);
|
TRACE("mp3Reader::Seek: synchronized at position %Ld\n", data->position);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -322,7 +356,7 @@ mp3Reader::GetNextChunk(void *cookie,
|
|||||||
if (maxbytes < 4)
|
if (maxbytes < 4)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
mediaHeader->start_time = (data->framePosition * 1000000) / data->frameCount;
|
mediaHeader->start_time = (data->framePosition * 1000000) / data->frameRate;
|
||||||
mediaHeader->file_pos = data->position;
|
mediaHeader->file_pos = data->position;
|
||||||
|
|
||||||
if (4 != Source()->ReadAt(fDataStart + data->position, data->chunkBuffer, 4)) {
|
if (4 != Source()->ReadAt(fDataStart + data->position, data->chunkBuffer, 4)) {
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ public:
|
|||||||
|
|
||||||
status_t Sniff(int32 *streamCount);
|
status_t Sniff(int32 *streamCount);
|
||||||
|
|
||||||
|
void GetFileFormatInfo(media_file_format *mff);
|
||||||
|
|
||||||
status_t AllocateCookie(int32 streamNumber, void **cookie);
|
status_t AllocateCookie(int32 streamNumber, void **cookie);
|
||||||
status_t FreeCookie(void *cookie);
|
status_t FreeCookie(void *cookie);
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,21 @@ WavReader::Sniff(int32 *streamCount)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WavReader::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_WAV_FORMAT_FAMILY;
|
||||||
|
mff->version = 100;
|
||||||
|
strcpy(mff->mime_type, "audio/x-wav");
|
||||||
|
strcpy(mff->file_extension, "wav");
|
||||||
|
strcpy(mff->short_name, "RIFF WAV audio");
|
||||||
|
strcpy(mff->pretty_name, "RIFF WAV audio");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
WavReader::AllocateCookie(int32 streamNumber, void **cookie)
|
WavReader::AllocateCookie(int32 streamNumber, void **cookie)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ public:
|
|||||||
|
|
||||||
status_t Sniff(int32 *streamCount);
|
status_t Sniff(int32 *streamCount);
|
||||||
|
|
||||||
|
void GetFileFormatInfo(media_file_format *mff);
|
||||||
|
|
||||||
status_t AllocateCookie(int32 streamNumber, void **cookie);
|
status_t AllocateCookie(int32 streamNumber, void **cookie);
|
||||||
status_t FreeCookie(void *cookie);
|
status_t FreeCookie(void *cookie);
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ const char *
|
|||||||
BMediaFile::Copyright(void) const
|
BMediaFile::Copyright(void) const
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
return "BMediaFile::Copyright";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
int32
|
int32
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ _CreateReader(Reader **reader, int32 *streamCount, media_file_format *mff, BData
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(*reader)->GetFileFormatInfo(mff);
|
||||||
|
|
||||||
printf("_CreateReader leave\n");
|
printf("_CreateReader leave\n");
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -71,6 +73,9 @@ _CreateDecoder(Decoder **decoder, media_codec_info *mci, const media_format *for
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strcpy(mci->short_name, " mci short_name");
|
||||||
|
strcpy(mci->pretty_name, " mci pretty_name");
|
||||||
|
|
||||||
printf("_CreateDecoder leave\n");
|
printf("_CreateDecoder leave\n");
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|||||||
Reference in New Issue
Block a user