#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <AppKit.h>
#include <InterfaceKit.h>
#include <MediaKit.h>
#include <SupportKit.h>
#include <media/Buffer.h>
#include <media/BufferGroup.h>
#include <media/MediaDecoder.h>
#include <media/Sound.h>
#include <media/SoundPlayer.h>
#include <storage/File.h>
#include <support/Errors.h>
extern "C" {
#include "avcodec.h"
#ifdef DEBUG
const uint8_t ff_log2_tab[256] = {0};
#endif
}
const char* kTestAudioFilename = "./AVCodecTestMp3AudioStreamRaw";
class FileDecoder : public BMediaDecoder {
private:
BFile* sourceFile;
public:
FileDecoder(BFile* file) : BMediaDecoder() {
sourceFile = file;
}
protected:
virtual status_t GetNextChunk(const void** chunkData, size_t* chunkLen,
media_header* mh) {
static const uint kReadSizeInBytes = 4096;
memset(mh, 0, sizeof(media_header));
void* fileData = malloc(kReadSizeInBytes);
ssize_t readLength = this->sourceFile->Read(fileData,
kReadSizeInBytes);
if (readLength < 0)
return B_ERROR;
if (readLength == 0)
return B_LAST_BUFFER_ERROR;
*chunkData = fileData;
*chunkLen = readLength;
return B_OK;
}
};
typedef struct cookie_decode {
BFile* inputFile;
BMediaDecoder* decoder;
BBufferGroup* decodedDataGroup;
uint32 decodedDataBufferSizeMax;
pthread_cond_t playingFinishedCondition;
} cookie_decode;
status_t InitializeMp3DecodingCookie(cookie_decode* cookie);
void FreeMp3DecodingCookie(cookie_decode* cookie);
media_format* CreateMp3MediaFormat();
media_format CreateRawMediaFormat();
void Mp3Decoding(void* cookie, void* buffer, size_t bufferSize,
const media_raw_audio_format& format);
int
main(int argc, char* argv[])
{
BApplication app("application/x-vnd.mp3-decoder-test");
cookie_decode decodingCookie;
if (InitializeMp3DecodingCookie(&decodingCookie) != B_OK)
exit(1);
media_format rawAudioFormat = CreateRawMediaFormat();
media_raw_audio_format* audioOutputFormat
= &rawAudioFormat.u.raw_audio;
BSoundPlayer player(audioOutputFormat, "wave_player", Mp3Decoding,
NULL, &decodingCookie);
player.Start();
player.SetHasData(true);
player.SetVolume(0.5);
pthread_mutex_t playingFinishedMutex;
pthread_mutex_init(&playingFinishedMutex, NULL);
pthread_mutex_lock(&playingFinishedMutex);
pthread_cond_wait(&decodingCookie.playingFinishedCondition,
&playingFinishedMutex);
player.SetHasData(false);
player.Stop();
FreeMp3DecodingCookie(&decodingCookie);
pthread_mutex_destroy(&playingFinishedMutex);
}
status_t
InitializeMp3DecodingCookie(cookie_decode* cookie)
{
cookie->inputFile = new BFile(kTestAudioFilename, O_RDONLY);
cookie->decoder = new FileDecoder(cookie->inputFile);
media_format* mp3MediaFormat = CreateMp3MediaFormat();
cookie->decoder->SetTo(mp3MediaFormat);
status_t settingDecoderStatus = cookie->decoder->InitCheck();
if (settingDecoderStatus < B_OK)
return B_ERROR;
media_format rawMediaFormat = CreateRawMediaFormat();
status_t settingDecoderOutputStatus
= cookie->decoder->SetOutputFormat(&rawMediaFormat);
if (settingDecoderOutputStatus < B_OK)
return B_ERROR;
cookie->decodedDataBufferSizeMax
= rawMediaFormat.u.raw_audio.buffer_size * 3;
cookie->decodedDataGroup
= new BBufferGroup(cookie->decodedDataBufferSizeMax, 25);
if (pthread_cond_init(&cookie->playingFinishedCondition, NULL) < 0)
return B_ERROR;
return B_OK;
}
void
FreeMp3DecodingCookie(cookie_decode* cookie)
{
pthread_cond_destroy(&cookie->playingFinishedCondition);
cookie->decodedDataGroup->ReclaimAllBuffers();
free(cookie->decodedDataGroup);
free(cookie->decoder);
free(cookie->inputFile);
}
media_format*
CreateMp3MediaFormat()
{
status_t status;
media_format_description desc;
desc.family = B_MISC_FORMAT_FAMILY;
desc.u.misc.file_format = 'ffmp';
desc.u.misc.codec = CODEC_ID_MP3;
static media_format* sNoMp3MediaFormat = NULL;
BMediaFormats formats;
status = formats.InitCheck();
if (status < B_OK) {
printf("formats.InitCheck failed, error %lu\n", status);
return sNoMp3MediaFormat;
}
media_format* mp3MediaFormat
= static_cast<media_format*>(malloc(sizeof(media_format)));
memset(mp3MediaFormat, 0, sizeof(media_format));
status = formats.GetFormatFor(desc, mp3MediaFormat);
if (status < B_OK) {
printf("formats.GetFormatFor failed, error %lu\n", status);
return sNoMp3MediaFormat;
}
return mp3MediaFormat;
}
media_format
CreateRawMediaFormat()
{
media_format rawMediaFormat;
memset(&rawMediaFormat, 0, sizeof(media_format));
rawMediaFormat.type = B_MEDIA_RAW_AUDIO;
rawMediaFormat.u.raw_audio.frame_rate = 48000;
rawMediaFormat.u.raw_audio.channel_count = 2;
rawMediaFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT;
rawMediaFormat.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
rawMediaFormat.u.raw_audio.buffer_size = 32768;
return rawMediaFormat;
}
void
Mp3Decoding(void* cookie, void* buffer, size_t bufferSize,
const media_raw_audio_format& format)
{
cookie_decode* decodingCookie = static_cast<cookie_decode*>(cookie);
int64 rawAudioFrameCount = 0;
media_header mh;
status_t decodingAudioFramesStatus
= decodingCookie->decoder->Decode(buffer, &rawAudioFrameCount, &mh,
NULL);
if (decodingAudioFramesStatus < B_OK) {
sleep(2);
pthread_cond_signal(&decodingCookie->playingFinishedCondition);
}
}