diff --git a/headers/private/media/ReaderPlugin.h b/headers/private/media/ReaderPlugin.h index 38d6b7b254..2fe640736d 100644 --- a/headers/private/media/ReaderPlugin.h +++ b/headers/private/media/ReaderPlugin.h @@ -21,6 +21,8 @@ public: 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 FreeCookie(void *cookie) = 0; diff --git a/src/add-ons/media/plugins/mp3_decoder/mp3DecoderPlugin.cpp b/src/add-ons/media/plugins/mp3_decoder/mp3DecoderPlugin.cpp index 0d167ac38e..fe7125a208 100644 --- a/src/add-ons/media/plugins/mp3_decoder/mp3DecoderPlugin.cpp +++ b/src/add-ons/media/plugins/mp3_decoder/mp3DecoderPlugin.cpp @@ -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.channel_mask = B_CHANNEL_LEFT | B_CHANNEL_RIGHT; fFrameSize = 4; + fFps = 44100; return B_OK; } @@ -67,6 +68,9 @@ mp3Decoder::Decode(void *buffer, int64 *frameCount, uint8 * out_buffer = static_cast(buffer); 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) { if (fResidualBytes) { int32 bytes = min_c(fResidualBytes, out_bytes_needed); @@ -75,32 +79,51 @@ mp3Decoder::Decode(void *buffer, int64 *frameCount, fResidualBytes -= bytes; out_buffer += bytes; out_bytes_needed -= bytes; + + fStartTime += (1000000LL * (bytes / fFrameSize)) / fFps; + + //TRACE("mp3Decoder: fStartTime inc'd to %.6f\n", fStartTime / 1000000.0); continue; } - void *chunkBuffer; - int32 chunkSize; - 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; + if (B_OK != DecodeNextChunk()) + break; } - *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; } diff --git a/src/add-ons/media/plugins/mp3_decoder/mp3DecoderPlugin.h b/src/add-ons/media/plugins/mp3_decoder/mp3DecoderPlugin.h index ad443ad47e..130eebe3b4 100644 --- a/src/add-ons/media/plugins/mp3_decoder/mp3DecoderPlugin.h +++ b/src/add-ons/media/plugins/mp3_decoder/mp3DecoderPlugin.h @@ -18,12 +18,17 @@ public: status_t Decode(void *buffer, int64 *frameCount, media_header *mediaHeader, media_decode_info *info); + + status_t DecodeNextChunk(); + private: struct mpstr fMpgLibPrivate; int32 fResidualBytes; uint8 * fResidualBuffer; uint8 * fDecodeBuffer; - int32 fFrameSize; + int32 fFrameSize; + int32 fFps; + bigtime_t fStartTime; }; diff --git a/src/add-ons/media/plugins/mp3_reader/MP3ReaderPlugin.cpp b/src/add-ons/media/plugins/mp3_reader/MP3ReaderPlugin.cpp index 40f72541bc..c76c3a05d4 100644 --- a/src/add-ons/media/plugins/mp3_reader/MP3ReaderPlugin.cpp +++ b/src/add-ons/media/plugins/mp3_reader/MP3ReaderPlugin.cpp @@ -69,6 +69,15 @@ static const int frame_rate_table[4][4] = { 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] static const int frame_sample_count_table[4] = { 0, 1152, 1152, 384 }; @@ -106,6 +115,7 @@ struct mp3Reader::fhg_vbr_info { }; + mp3Reader::mp3Reader() : fXingVbrInfo(0), fFhgVbrInfo(0) @@ -113,11 +123,13 @@ mp3Reader::mp3Reader() TRACE("mp3Reader::mp3Reader\n"); } + mp3Reader::~mp3Reader() { delete fXingVbrInfo; delete fFhgVbrInfo; } + const char * mp3Reader::Copyright() @@ -125,7 +137,7 @@ mp3Reader::Copyright() return "mp3 reader, " B_UTF8_COPYRIGHT " by Marcus Overhagen"; } - + status_t mp3Reader::Sniff(int32 *streamCount) { @@ -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 mp3Reader::AllocateCookie(int32 streamNumber, void **cookie) { @@ -306,6 +338,8 @@ mp3Reader::Seek(void *cookie, } data->position = pos + ofs; + data->framePosition = *frame; // this is not exact + TRACE("mp3Reader::Seek: synchronized at position %Ld\n", data->position); return B_OK; } @@ -322,7 +356,7 @@ mp3Reader::GetNextChunk(void *cookie, if (maxbytes < 4) return B_ERROR; - mediaHeader->start_time = (data->framePosition * 1000000) / data->frameCount; + mediaHeader->start_time = (data->framePosition * 1000000) / data->frameRate; mediaHeader->file_pos = data->position; if (4 != Source()->ReadAt(fDataStart + data->position, data->chunkBuffer, 4)) { diff --git a/src/add-ons/media/plugins/mp3_reader/MP3ReaderPlugin.h b/src/add-ons/media/plugins/mp3_reader/MP3ReaderPlugin.h index c5199b024e..051bd88375 100644 --- a/src/add-ons/media/plugins/mp3_reader/MP3ReaderPlugin.h +++ b/src/add-ons/media/plugins/mp3_reader/MP3ReaderPlugin.h @@ -15,6 +15,8 @@ public: status_t Sniff(int32 *streamCount); + void GetFileFormatInfo(media_file_format *mff); + status_t AllocateCookie(int32 streamNumber, void **cookie); status_t FreeCookie(void *cookie); diff --git a/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.cpp b/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.cpp index d9ba1404df..8650da1a1d 100644 --- a/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.cpp +++ b/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.cpp @@ -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 WavReader::AllocateCookie(int32 streamNumber, void **cookie) { diff --git a/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.h b/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.h index b7c555ae30..05707ef911 100644 --- a/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.h +++ b/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.h @@ -11,6 +11,8 @@ public: status_t Sniff(int32 *streamCount); + void GetFileFormatInfo(media_file_format *mff); + status_t AllocateCookie(int32 streamNumber, void **cookie); status_t FreeCookie(void *cookie); diff --git a/src/kits/media/MediaFile.cpp b/src/kits/media/MediaFile.cpp index a6daffc6ce..8987c22dda 100644 --- a/src/kits/media/MediaFile.cpp +++ b/src/kits/media/MediaFile.cpp @@ -96,7 +96,7 @@ const char * BMediaFile::Copyright(void) const { UNIMPLEMENTED(); - return "BMediaFile::Copyright"; + return ""; } int32 diff --git a/src/kits/media/PluginManager.cpp b/src/kits/media/PluginManager.cpp index f745a22257..af8f24e077 100644 --- a/src/kits/media/PluginManager.cpp +++ b/src/kits/media/PluginManager.cpp @@ -40,6 +40,8 @@ _CreateReader(Reader **reader, int32 *streamCount, media_file_format *mff, BData return B_ERROR; } + (*reader)->GetFileFormatInfo(mff); + printf("_CreateReader leave\n"); return B_OK; @@ -71,6 +73,9 @@ _CreateDecoder(Decoder **decoder, media_codec_info *mci, const media_format *for return B_ERROR; } + strcpy(mci->short_name, " mci short_name"); + strcpy(mci->pretty_name, " mci pretty_name"); + printf("_CreateDecoder leave\n"); return B_OK;