mp3 decoding and seeking works now

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5581 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper
2003-12-05 22:11:52 +00:00
parent b65a0ac50e
commit d0b86c0f31
7 changed files with 99 additions and 46 deletions
@@ -8,19 +8,26 @@
#if TRACE_THIS #if TRACE_THIS
#define TRACE printf #define TRACE printf
#else #else
#define TRACE ((void)0) #define TRACE(a...)
#endif #endif
#define OUTPUT_BUFFER_SIZE 32768 #define OUTPUT_BUFFER_SIZE (8 * 1024)
#define DECODE_BUFFER_SIZE (32 * 1024)
mp3Decoder::mp3Decoder() mp3Decoder::mp3Decoder()
{ {
InitMP3(&fMpgLibPrivate); InitMP3(&fMpgLibPrivate);
fResidualBytes = 0;
fResidualBuffer = 0;
fDecodeBuffer = new uint8 [DECODE_BUFFER_SIZE];
fFrameSize = 0;
} }
mp3Decoder::~mp3Decoder() mp3Decoder::~mp3Decoder()
{ {
ExitMP3(&fMpgLibPrivate); ExitMP3(&fMpgLibPrivate);
delete [] fDecodeBuffer;
} }
@@ -36,9 +43,11 @@ mp3Decoder::Setup(media_format *ioEncodedFormat, media_format *ioDecodedFormat,
ioDecodedFormat->u.raw_audio.byte_order = B_MEDIA_LITTLE_ENDIAN; ioDecodedFormat->u.raw_audio.byte_order = B_MEDIA_LITTLE_ENDIAN;
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;
return B_OK; return B_OK;
} }
status_t status_t
mp3Decoder::Seek(uint32 seekTo, mp3Decoder::Seek(uint32 seekTo,
int64 seekFrame, int64 *frame, int64 seekFrame, int64 *frame,
@@ -54,6 +63,20 @@ status_t
mp3Decoder::Decode(void *buffer, int64 *frameCount, mp3Decoder::Decode(void *buffer, int64 *frameCount,
media_header *mediaHeader, media_decode_info *info /* = 0 */) media_header *mediaHeader, media_decode_info *info /* = 0 */)
{ {
uint8 * out_buffer = static_cast<uint8 *>(buffer);
int32 out_bytes_needed = OUTPUT_BUFFER_SIZE;
while (out_bytes_needed > 0) {
if (fResidualBytes) {
int32 bytes = min_c(fResidualBytes, out_bytes_needed);
memcpy(out_buffer, fResidualBuffer, bytes);
fResidualBuffer += bytes;
fResidualBytes -= bytes;
out_buffer += bytes;
out_bytes_needed -= bytes;
continue;
}
void *chunkBuffer; void *chunkBuffer;
int32 chunkSize; int32 chunkSize;
if (B_OK != GetNextChunk(&chunkBuffer, &chunkSize, mediaHeader)) { if (B_OK != GetNextChunk(&chunkBuffer, &chunkSize, mediaHeader)) {
@@ -61,33 +84,26 @@ mp3Decoder::Decode(void *buffer, int64 *frameCount,
return B_ERROR; return B_ERROR;
} }
int availsize;
int outsize; int outsize;
int result; int result;
result = decodeMP3(&fMpgLibPrivate, (char *)chunkBuffer, chunkSize, (char *)fDecodeBuffer, DECODE_BUFFER_SIZE, &outsize);
availsize = OUTPUT_BUFFER_SIZE;
result = decodeMP3(&fMpgLibPrivate, (char *)chunkBuffer, chunkSize, (char *)buffer, availsize, &outsize);
if (result == MP3_ERR) { if (result == MP3_ERR) {
TRACE("mp3Decoder::Decode: decodeMP3 returned MP3_ERR\n"); TRACE("mp3Decoder::Decode: decodeMP3 returned MP3_ERR\n");
return B_ERROR; return B_ERROR;
} }
buffer = (char *)buffer + outsize;
availsize -= outsize;
do { //printf("mp3Decoder::Decode: decoded %d bytes into %d bytes\n",chunkSize, outsize);
result = decodeMP3(&fMpgLibPrivate, 0, 0, (char *)buffer, availsize, &outsize);
buffer = (char *)buffer + outsize; fResidualBuffer = fDecodeBuffer;
availsize -= outsize; fResidualBytes = outsize;
if (availsize < 0) {
TRACE("mp3Decoder::Decode: decoded to much\n");
exit(1);
} }
} while (result == MP3_OK);
*frameCount = (OUTPUT_BUFFER_SIZE - availsize) / 4; *frameCount = OUTPUT_BUFFER_SIZE / fFrameSize;
return B_OK; return B_OK;
} }
Decoder * Decoder *
mp3DecoderPlugin::NewDecoder() mp3DecoderPlugin::NewDecoder()
{ {
@@ -102,6 +118,7 @@ mp3DecoderPlugin::NewDecoder()
return new mp3Decoder; return new mp3Decoder;
} }
status_t status_t
mp3DecoderPlugin::RegisterPlugin() mp3DecoderPlugin::RegisterPlugin()
{ {
@@ -20,6 +20,10 @@ public:
media_header *mediaHeader, media_decode_info *info); media_header *mediaHeader, media_decode_info *info);
private: private:
struct mpstr fMpgLibPrivate; struct mpstr fMpgLibPrivate;
int32 fResidualBytes;
uint8 * fResidualBuffer;
uint8 * fDecodeBuffer;
int32 fFrameSize;
}; };
@@ -225,7 +225,7 @@ mp3Reader::FreeCookie(void *cookie)
{ {
TRACE("mp3Reader::FreeCookie\n"); TRACE("mp3Reader::FreeCookie\n");
mp3data *data = reinterpret_cast<mp3data *>(cookie); mp3data *data = reinterpret_cast<mp3data *>(cookie);
delete data->chunkBuffer; delete [] data->chunkBuffer;
delete data; delete data;
return B_OK; return B_OK;
@@ -261,14 +261,14 @@ mp3Reader::Seek(void *cookie,
// this isn't very accurate // this isn't very accurate
if (seekTo & B_MEDIA_SEEK_TO_FRAME) { if (seekTo & B_MEDIA_SEEK_TO_FRAME) {
pos = fXingVbrInfo ? XingSeekPoint(*frame / (float)data->frameCount) : -1; pos = fXingVbrInfo ? XingSeekPoint(100.0 * *frame / (float)data->frameCount) : -1;
if (pos < 0) if (pos < 0)
pos = (*frame * fDataSize) / data->frameCount; pos = (*frame * fDataSize) / data->frameCount;
TRACE("mp3Reader::Seek to frame %Ld, pos %Ld\n", *frame, pos); TRACE("mp3Reader::Seek to frame %Ld, pos %Ld\n", *frame, pos);
*time = (*frame * data->duration) / data->frameCount; *time = (*frame * data->duration) / data->frameCount;
TRACE("mp3Reader::Seek newtime %Ld\n", *time); TRACE("mp3Reader::Seek newtime %Ld\n", *time);
} else if (seekTo & B_MEDIA_SEEK_TO_TIME) { } else if (seekTo & B_MEDIA_SEEK_TO_TIME) {
pos = fXingVbrInfo ? XingSeekPoint(*time / (float)data->duration) : -1; pos = fXingVbrInfo ? XingSeekPoint(100.0 * *time / (float)data->duration) : -1;
if (pos < 0) if (pos < 0)
pos = (*time * fDataSize) / data->duration; pos = (*time * fDataSize) / data->duration;
TRACE("mp3Reader::Seek to time %Ld, pos %Ld\n", *time, pos); TRACE("mp3Reader::Seek to time %Ld, pos %Ld\n", *time, pos);
@@ -353,6 +353,11 @@ mp3Reader::GetNextChunk(void *cookie,
*chunkBuffer = data->chunkBuffer; *chunkBuffer = data->chunkBuffer;
*chunkSize = size + 4; *chunkSize = size + 4;
if (*chunkSize > MAX_CHUNK_SIZE) {
printf("mp3Reader: chunk buffer overrun, read %ld bytes into %d bytes buffer\n", *chunkSize, MAX_CHUNK_SIZE);
exit(1);
}
return B_OK; return B_OK;
} }
+4 -3
View File
@@ -61,7 +61,7 @@ MediaExtractor::MediaExtractor(BDataIO * source, int32 flags)
fStreamInfo[i].encodedFormat.u.encoded_audio.output.channel_count = 2; fStreamInfo[i].encodedFormat.u.encoded_audio.output.channel_count = 2;
fStreamInfo[i].encodedFormat.u.encoded_audio.output.format = 2; fStreamInfo[i].encodedFormat.u.encoded_audio.output.format = 2;
fStreamInfo[i].encodedFormat.u.encoded_audio.output.byte_order = B_MEDIA_LITTLE_ENDIAN; fStreamInfo[i].encodedFormat.u.encoded_audio.output.byte_order = B_MEDIA_LITTLE_ENDIAN;
fStreamInfo[i].encodedFormat.u.encoded_audio.output.buffer_size = 8 * 1024; fStreamInfo[i].encodedFormat.u.encoded_audio.output.buffer_size = 4 * 1024;
string_for_format(fStreamInfo[i].encodedFormat, sz, sizeof(sz)); string_for_format(fStreamInfo[i].encodedFormat, sz, sizeof(sz));
printf("MediaExtractor::MediaExtractor: stream %d has new format %s\n", i, sz); printf("MediaExtractor::MediaExtractor: stream %d has new format %s\n", i, sz);
} }
@@ -70,6 +70,7 @@ MediaExtractor::MediaExtractor(BDataIO * source, int32 flags)
MediaExtractor::~MediaExtractor() MediaExtractor::~MediaExtractor()
{ {
CALLED(); CALLED();
// free all stream cookies // free all stream cookies
for (int32 i = 0; i < fStreamCount; i++) { for (int32 i = 0; i < fStreamCount; i++) {
if (fStreamInfo[i].cookie) if (fStreamInfo[i].cookie)
@@ -79,7 +80,7 @@ MediaExtractor::~MediaExtractor()
if (fReader) if (fReader)
_DestroyReader(fReader); _DestroyReader(fReader);
delete fStreamInfo; delete [] fStreamInfo;
delete fSource; delete fSource;
} }
@@ -171,7 +172,7 @@ MediaExtractor::GetNextChunk(int32 stream,
void **chunkBuffer, int32 *chunkSize, void **chunkBuffer, int32 *chunkSize,
media_header *mediaHeader) media_header *mediaHeader)
{ {
CALLED(); //CALLED();
// get buffered chunk // get buffered chunk
// XXX this should be done in a different thread, and double buffered for each stream // XXX this should be done in a different thread, and double buffered for each stream
+6 -1
View File
@@ -114,8 +114,11 @@ BMediaFile::TrackAt(int32 index)
CALLED(); CALLED();
if (!fTrackList || !fExtractor || index < 0 || index >= fTrackNum) if (!fTrackList || !fExtractor || index < 0 || index >= fTrackNum)
return 0; return 0;
if (!fTrackList[index]) if (!fTrackList[index]) {
TRACE("BMediaFile::TrackAt, creating new track for index %ld\n", index);
fTrackList[index] = new BMediaTrack(fExtractor, index); fTrackList[index] = new BMediaTrack(fExtractor, index);
TRACE("BMediaFile::TrackAt, new track is %p\n", fTrackList[index]);
}
return fTrackList[index]; return fTrackList[index];
} }
@@ -132,6 +135,7 @@ BMediaFile::ReleaseTrack(BMediaTrack *track)
return B_ERROR; return B_ERROR;
for (int32 i = 0; i < fTrackNum; i++) { for (int32 i = 0; i < fTrackNum; i++) {
if (fTrackList[i] == track) { if (fTrackList[i] == track) {
TRACE("BMediaFile::ReleaseTrack, releasing track %p with index %ld\n", track, i);
delete track; delete track;
fTrackList[i] = 0; fTrackList[i] = 0;
return B_OK; return B_OK;
@@ -149,6 +153,7 @@ BMediaFile::ReleaseAllTracks(void)
return B_ERROR; return B_ERROR;
for (int32 i = 0; i < fTrackNum; i++) { for (int32 i = 0; i < fTrackNum; i++) {
if (fTrackList[i]) { if (fTrackList[i]) {
TRACE("BMediaFile::ReleaseAllTracks, releasing track %p with index %ld\n", fTrackList[i], i);
delete fTrackList[i]; delete fTrackList[i];
fTrackList[i] = 0; fTrackList[i] = 0;
} }
+23 -7
View File
@@ -118,7 +118,7 @@ BMediaTrack::ReadFrames(void *out_buffer,
media_header *mh /* = 0 */, media_header *mh /* = 0 */,
media_decode_info *info /* = 0 */) media_decode_info *info /* = 0 */)
{ {
CALLED(); // CALLED();
if (!fDecoder) if (!fDecoder)
return B_NO_INIT; return B_NO_INIT;
if (!out_buffer || !out_frameCount) if (!out_buffer || !out_frameCount)
@@ -158,9 +158,11 @@ BMediaTrack::SeekToTime(bigtime_t *inout_time,
CALLED(); CALLED();
if (!fDecoder || !fExtractor) if (!fDecoder || !fExtractor)
return B_NO_INIT; return B_NO_INIT;
if (!inout_time || !(flags & B_MEDIA_SEEK_DIRECTION_MASK)) if (!inout_time)
return B_BAD_VALUE; return B_BAD_VALUE;
bigtime_t request = *inout_time;
status_t result; status_t result;
uint32 seekTo; uint32 seekTo;
bigtime_t seekTime; bigtime_t seekTime;
@@ -173,17 +175,23 @@ BMediaTrack::SeekToTime(bigtime_t *inout_time,
time = seekTime; time = seekTime;
result = fExtractor->Seek(fStream, seekTo, &frame, &time); result = fExtractor->Seek(fStream, seekTo, &frame, &time);
if (result != B_OK) if (result != B_OK) {
TRACE("BMediaTrack::SeekToTime: extractor seek failed\n");
return result; return result;
}
result = fDecoder->Seek(seekTo, 0, &frame, seekTime, &time); result = fDecoder->Seek(seekTo, 0, &frame, seekTime, &time);
if (result != B_OK) if (result != B_OK) {
TRACE("BMediaTrack::SeekToTime: decoder seek failed\n");
return result; return result;
}
*inout_time = time; *inout_time = time;
fCurFrame = frame; fCurFrame = frame;
fCurTime = time; fCurTime = time;
printf("BMediaTrack::SeekToTime finished, requested %.6f, result %.6f\n", request / 1000000.0, *inout_time / 1000000.0);
return B_OK; return B_OK;
} }
@@ -195,9 +203,11 @@ BMediaTrack::SeekToFrame(int64 *inout_frame,
CALLED(); CALLED();
if (!fDecoder || !fExtractor) if (!fDecoder || !fExtractor)
return B_NO_INIT; return B_NO_INIT;
if (!inout_frame || !(flags & B_MEDIA_SEEK_DIRECTION_MASK)) if (!inout_frame)
return B_BAD_VALUE; return B_BAD_VALUE;
int64 request = *inout_frame;
status_t result; status_t result;
uint32 seekTo; uint32 seekTo;
int64 seekFrame; int64 seekFrame;
@@ -210,17 +220,23 @@ BMediaTrack::SeekToFrame(int64 *inout_frame,
frame = seekFrame; frame = seekFrame;
result = fExtractor->Seek(fStream, seekTo, &frame, &time); result = fExtractor->Seek(fStream, seekTo, &frame, &time);
if (result != B_OK) if (result != B_OK) {
TRACE("BMediaTrack::SeekToFrame: extractor seek failed\n");
return result; return result;
}
result = fDecoder->Seek(seekTo, seekFrame, &frame, 0, &time); result = fDecoder->Seek(seekTo, seekFrame, &frame, 0, &time);
if (result != B_OK) if (result != B_OK) {
return result; return result;
TRACE("BMediaTrack::SeekToFrame: decoder seek failed\n");
}
*inout_frame = frame; *inout_frame = frame;
fCurFrame = frame; fCurFrame = frame;
fCurTime = time; fCurTime = time;
printf("BMediaTrack::SeekToTime SeekToFrame, requested %Ld, result %Ld\n", request, *inout_frame);
return B_OK; return B_OK;
} }
+5
View File
@@ -3,6 +3,7 @@
#include <string.h> #include <string.h>
#include "PluginManager.h" #include "PluginManager.h"
#include "debug.h"
PluginManager _plugin_manager; PluginManager _plugin_manager;
@@ -79,11 +80,13 @@ _CreateDecoder(Decoder **decoder, media_codec_info *mci, const media_format *for
void void
_DestroyReader(Reader *reader) _DestroyReader(Reader *reader)
{ {
delete reader;
} }
void void
_DestroyDecoder(Decoder *decoder) _DestroyDecoder(Decoder *decoder)
{ {
delete decoder;
} }
status_t status_t
@@ -103,6 +106,7 @@ _PublishDecoder(DecoderPlugin *decoderplugin,
PluginManager::PluginManager() PluginManager::PluginManager()
{ {
CALLED();
fLocker = new BLocker; fLocker = new BLocker;
fPluginList = new List<plugin_info>; fPluginList = new List<plugin_info>;
} }
@@ -110,6 +114,7 @@ PluginManager::PluginManager()
PluginManager::~PluginManager() PluginManager::~PluginManager()
{ {
CALLED();
while (!fPluginList->IsEmpty()) { while (!fPluginList->IsEmpty()) {
plugin_info *info; plugin_info *info;
fPluginList->Get(fPluginList->CountItems() - 1, &info); fPluginList->Get(fPluginList->CountItems() - 1, &info);