add FLAC format to audio decoders

git-svn-id: file:///home/bas/coolstream_public_svn/THIRDPARTY/applications/neutrino-experimental@1539 e54a6e83-5905-42d5-8d5c-058d10e6a962


Origin commit data
------------------
Branch: ni/coolstream
Commit: 4dc844298e
Author: Stefan Seyfried <seife@tuxbox-git.slipkontur.de>
Date: 2011-06-13 (Mon, 13 Jun 2011)



------------------
This commit was generated by Migit
This commit is contained in:
Stefan Seyfried
2011-06-13 15:25:38 +00:00
parent 1a56a8ed0d
commit 5a5c3b458f
2 changed files with 734 additions and 0 deletions

View File

@@ -0,0 +1,657 @@
/*
Neutrino-GUI - DBoxII-Project
flac audio decoder
uses flac library
License: GPL
ported from tuxbox-CVS flacdec.cpp CVS rev 1.2
Neutrino-HD port and fixes for non-ppc architectures are:
(C) 2011 Stefan Seyfried, B1 Systems GmbH, Vohburg, Germany
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <flacdec.h>
#include <linux/soundcard.h>
#include <algorithm>
#include <sstream>
#include <driver/netfile.h>
#include <zapit/include/audio.h>
extern cAudio *audioDecoder;
#define ProgName "FlacDec"
// nr of msecs to skip in ff/rev mode
#define MSECS_TO_SKIP 3000
// nr of msecs to play in ff/rev mode
#define MSECS_TO_PLAY 200
#define MAX_OUTPUT_SAMPLES 1022 /* AVIA_GT_PCM_MAX_SAMPLES-1 */
/* at first, define our own callback functions used in */
/* tremor to access the data. These functions are simple mappers */
FLAC__StreamDecoderReadStatus flac_read(const FLAC__StreamDecoder *, FLAC__byte buffer[], size_t *bytes, void *client_data)
{
CFlacDec * flacdec = (CFlacDec *)client_data;
if(*bytes > 0) {
*bytes = fread(buffer, sizeof(FLAC__byte), *bytes, flacdec->mIn);
if(ferror(flacdec->mIn))
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
else if(*bytes == 0)
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
else
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
else
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
}
FLAC__StreamDecoderSeekStatus flac_seek(const FLAC__StreamDecoder *, FLAC__uint64 absolute_byte_offset, void *client_data)
{
CFlacDec * flacdec = (CFlacDec *)client_data;
if(flacdec->mIn == stdin)
return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
else if(fseek(flacdec->mIn, (off_t)absolute_byte_offset, SEEK_SET) < 0)
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
else
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
}
int flac_close(void *)
{
return 0;
}
FLAC__StreamDecoderTellStatus flac_tell(const FLAC__StreamDecoder *, FLAC__uint64 *absolute_byte_offset, void *client_data)
{
CFlacDec * flacdec = (CFlacDec *)client_data;
off_t pos;
if(flacdec->mIn == stdin)
return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
else if((pos = ftell(flacdec->mIn)) < 0)
return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
else {
*absolute_byte_offset = (FLAC__uint64)pos;
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
}
}
FLAC__StreamDecoderLengthStatus flac_length(const FLAC__StreamDecoder *, FLAC__uint64 *stream_length, void *client_data)
{
struct stat filestats;
CFlacDec * flacdec = (CFlacDec *)client_data;
if(flacdec->mIn == stdin)
return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
else if(fstat(fileno(flacdec->mIn), &filestats) != 0)
return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
else {
*stream_length = (FLAC__uint64)filestats.st_size;
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
}
}
FLAC__bool flac_eof(const FLAC__StreamDecoder *, void *client_data)
{
return feof(((CFlacDec *)client_data)->mIn)? true : false;
}
FLAC__StreamDecoderWriteStatus flac_write(const FLAC__StreamDecoder * /*vf*/, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
{
CFlacDec * flacdec = (CFlacDec *)client_data;
FLAC__uint32 test = 1;
bool is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true;
if (flacdec->mFrameCount == 0) {
int fmt;
flacdec->mChannels = frame->header.channels;
flacdec->mSampleRate = frame->header.sample_rate;
flacdec->mBps = frame->header.bits_per_sample;
flacdec->mBuffersize = MAX_OUTPUT_SAMPLES * flacdec->mChannels * flacdec->mBps / 8;
switch(flacdec->mBps)
{
case 8 : fmt = AFMT_U8;
break;
// TODO:
case 16 :
fmt = is_big_endian_host_ ? AFMT_S16_BE : AFMT_S16_LE;
break;
default:
printf("Flacdecoder: wrong bits per sample (%d)\n", flacdec->mBps);
flacdec->Status=CFlacDec::DSPSET_ERR;
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
printf("SetDSP: mBps=%d, fmt = %d, Sample rate = %d, channels = %d\n", flacdec->mBps, fmt, flacdec->mSampleRate, flacdec->mChannels);
audioDecoder->PrepareClipPlay(flacdec->mChannels, flacdec->mSampleRate, flacdec->mBps, fmt == AFMT_S16_LE ? 1 : 0);
#if 0
#ifdef DBOX
if (flacdec->SetDSP(flacdec->mOutputFd, fmt, flacdec->mSampleRate, flacdec->mChannels)) //FLAC__stream_decoder_get_channels (vf)))
#else
if (flacdec->SetDSP(flacdec->mOutputFd, AFMT_S16_NE, flacdec->mSampleRate, flacdec->mChannels))
#endif
{
flacdec->Status=CFlacDec::DSPSET_ERR;
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
#endif
}
const unsigned bps = frame->header.bits_per_sample, channels = frame->header.channels;
const unsigned shift = ((bps%8)? 8-(bps%8): 0);
FLAC__bool is_big_endian = false;
FLAC__bool is_unsigned_samples = bps<=8;
unsigned wide_samples = frame->header.blocksize, wide_sample, sample, channel, byte;
// unsigned frame_bytes = 0;
static FLAC__int8 s8buffer[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(FLAC__int32)]; /* WATCHOUT: can be up to 2 megs */
FLAC__uint8 *u8buffer = (FLAC__uint8 *)s8buffer;
FLAC__int16 *s16buffer = (FLAC__int16 *)s8buffer;
FLAC__uint16 *u16buffer = (FLAC__uint16 *)s8buffer;
FLAC__int32 *s32buffer = (FLAC__int32 *)s8buffer;
FLAC__uint32 *u32buffer = (FLAC__uint32 *)s8buffer;
size_t bytes_to_write = 0;
/* sanity-check the bits-per-sample */
if(flacdec->mBps) {
if(bps != flacdec->mBps) {
if(flacdec->mFrameCount)
printf("ERROR, bits-per-sample is %u in frame but %u in STREAMINFO\n", bps, flacdec->mBps);
else
printf("ERROR, bits-per-sample is %u in this frame but %u in previous frames\n", bps, flacdec->mBps);
}
}
/* sanity-check the #channels */
if(flacdec->mChannels) {
if(channels != flacdec->mChannels) {
if(flacdec->mFrameCount)
printf("ERROR, channels is %u in frame but %u in STREAMINFO\n", channels, flacdec->mChannels);
else
printf("ERROR, channels is %u in this frame but %u in previous frames\n", channels, flacdec->mChannels);
}
}
/* sanity-check the sample rate */
if(flacdec->mSampleRate) {
if(frame->header.sample_rate != flacdec->mSampleRate) {
if(flacdec->mFrameCount)
printf("ERROR, sample rate is %u in frame but %u in STREAMINFO\n", frame->header.sample_rate, flacdec->mSampleRate);
else
printf("ERROR, sample rate is %u in this frame but %u in previous frames\n", frame->header.sample_rate, flacdec->mSampleRate);
}
}
if(wide_samples > 0) {
flacdec->mSamplesProcessed += wide_samples;
flacdec->mFrameCount++;
// ripped from libFLAC examples/plugins
if(shift)/* && !decoder_session->replaygain.apply) */{
for(wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++)
((FLAC__int32**)buffer)[channel][wide_sample] <<= shift;/*@@@@@@un-const'ing the buffer is hacky but safe*/
}
/* first some special code for common cases */
if(is_big_endian == is_big_endian_host_ && !is_unsigned_samples && channels == 2 && bps+shift == 16) {
FLAC__int16 *buf1_ = s16buffer + 1;
if(is_big_endian)
memcpy(s16buffer, ((FLAC__byte*)(buffer[0]))+2, sizeof(FLAC__int32) * wide_samples - 2);
else
memcpy(s16buffer, buffer[0], sizeof(FLAC__int32) * wide_samples);
for(sample = 0; sample < wide_samples; sample++, buf1_+=2)
*buf1_ = (FLAC__int16)buffer[1][sample];
bytes_to_write = 4 * sample;
}
else if(is_big_endian == is_big_endian_host_ && !is_unsigned_samples && channels == 1 && bps+shift == 16) {
FLAC__int16 *buf1_ = s16buffer;
for(sample = 0; sample < wide_samples; sample++)
*buf1_++ = (FLAC__int16)buffer[0][sample];
bytes_to_write = 2 * sample;
}
/* generic code for the rest */
else if(bps+shift == 16) {
if(is_unsigned_samples) {
if(channels == 2) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
u16buffer[sample++] = (FLAC__uint16)(buffer[0][wide_sample] + 0x8000);
u16buffer[sample++] = (FLAC__uint16)(buffer[1][wide_sample] + 0x8000);
}
}
else if(channels == 1) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
u16buffer[sample++] = (FLAC__uint16)(buffer[0][wide_sample] + 0x8000);
}
else { /* works for any 'channels' but above flavors are faster for 1 and 2 */
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
u16buffer[sample] = (FLAC__uint16)(buffer[channel][wide_sample] + 0x8000);
}
}
else {
if(channels == 2) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
s16buffer[sample++] = (FLAC__int16)(buffer[0][wide_sample]);
s16buffer[sample++] = (FLAC__int16)(buffer[1][wide_sample]);
}
}
else if(channels == 1) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
s16buffer[sample++] = (FLAC__int16)(buffer[0][wide_sample]);
}
else { /* works for any 'channels' but above flavors are faster for 1 and 2 */
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
s16buffer[sample] = (FLAC__int16)(buffer[channel][wide_sample]);
}
}
if(is_big_endian != is_big_endian_host_) {
unsigned char tmp;
const unsigned bytes = sample * 2;
for(byte = 0; byte < bytes; byte += 2) {
tmp = u8buffer[byte];
u8buffer[byte] = u8buffer[byte+1];
u8buffer[byte+1] = tmp;
}
}
bytes_to_write = 2 * sample;
}
else if(bps+shift == 24) {
if(is_unsigned_samples) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
u32buffer[sample] = buffer[channel][wide_sample] + 0x800000;
}
else {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
s32buffer[sample] = buffer[channel][wide_sample];
}
if(is_big_endian != is_big_endian_host_) {
unsigned char tmp;
const unsigned bytes = sample * 4;
for(byte = 0; byte < bytes; byte += 4) {
tmp = u8buffer[byte];
u8buffer[byte] = u8buffer[byte+3];
u8buffer[byte+3] = tmp;
tmp = u8buffer[byte+1];
u8buffer[byte+1] = u8buffer[byte+2];
u8buffer[byte+2] = tmp;
}
}
if(is_big_endian) {
unsigned lbyte;
const unsigned bytes = sample * 4;
for(lbyte = byte = 0; byte < bytes; ) {
byte++;
u8buffer[lbyte++] = u8buffer[byte++];
u8buffer[lbyte++] = u8buffer[byte++];
u8buffer[lbyte++] = u8buffer[byte++];
}
}
else {
unsigned lbyte;
const unsigned bytes = sample * 4;
for(lbyte = byte = 0; byte < bytes; ) {
u8buffer[lbyte++] = u8buffer[byte++];
u8buffer[lbyte++] = u8buffer[byte++];
u8buffer[lbyte++] = u8buffer[byte++];
byte++;
}
}
bytes_to_write = 3 * sample;
}
else if(bps+shift == 8) {
if(is_unsigned_samples) {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
u8buffer[sample] = (FLAC__uint8)(buffer[channel][wide_sample] + 0x80);
}
else {
for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
for(channel = 0; channel < channels; channel++, sample++)
s8buffer[sample] = (FLAC__int8)(buffer[channel][wide_sample]);
}
bytes_to_write = sample;
}
else {
// FLAC__ASSERT(0);
/* double protection */
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
}
if(bytes_to_write > 0) {
ssize_t cnt;
unsigned int j=0;
while (j<bytes_to_write) {
if (j+flacdec->mBuffersize > bytes_to_write)
cnt = bytes_to_write - j;
else
cnt = flacdec->mBuffersize;
//if (write(flacdec->mOutputFd, &u8buffer[j], cnt) != (ssize_t)cnt)
if (audioDecoder->WriteClip(&u8buffer[j], cnt) != cnt)
{
/* if a pipe closed when writing to stdout, we let it go without an error message */
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
j += cnt;
}
}
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
void flac_metadata(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *metadata, void *client_data)
{
CFlacDec * flacdec = (CFlacDec *)client_data;
switch (metadata->type) {
case FLAC__METADATA_TYPE_STREAMINFO:
{
printf("STREAMINFO block received\n");
flacdec->mTotalSamples = metadata->data.stream_info.total_samples;
flacdec->mBps = metadata->data.stream_info.bits_per_sample;
flacdec->mChannels = metadata->data.stream_info.channels;
flacdec->mSampleRate = metadata->data.stream_info.sample_rate;
{
/* with VC++ you have to spoon feed it the casting from uint64->int64->double */
FLAC__uint64 l = (FLAC__uint64)((flacdec->mTotalSamples * 1000ULL) / flacdec->mSampleRate);
if (l > INT_MAX)
l = INT_MAX;
flacdec->mLengthInMsec = (int)l;
}
break;
}
case FLAC__METADATA_TYPE_PADDING: printf("PADDING block received\n"); break;
case FLAC__METADATA_TYPE_APPLICATION: printf("APPLICATION block received\n"); break;
case FLAC__METADATA_TYPE_SEEKTABLE: printf("SEEKTABLE block received\n"); break;
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
{
printf("VORBISCOMMENT block (a.k.a. FLAC tags) received\n");
// if there is an old metadata -> clear it
if (flacdec->mMetadata != NULL)
FLAC__metadata_object_delete(flacdec->mMetadata);
flacdec->mMetadata = FLAC__metadata_object_clone(metadata);
break;
}
case FLAC__METADATA_TYPE_CUESHEET: printf("CUESHEET block received\n"); break;
case FLAC__METADATA_TYPE_PICTURE: printf("PICTURE block received\n"); break;
case FLAC__METADATA_TYPE_UNDEFINED:
default: printf("Undefined block received\n"); break;
}
}
void flac_error(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus, void *)
{
}
CBaseDec::RetCode CFlacDec::Decoder(FILE *in, const int /*OutputFd*/, State* const state, CAudioMetaData* meta_data, time_t* const time_played, unsigned int* const secondsToSkip)
{
int rval;
// FLAC__uint64 jumptime=0;
Status = OK;
mState = state;
mTimePlayed = time_played;
mFrameCount = 0;
mSamplesProcessed = 0;
mFlacDec = FLAC__stream_decoder_new();
if (!Open(in, mFlacDec))
{
Status=DATA_ERR;
return Status;
}
/* up and away ... */
mSlotSize = MAX_OUTPUT_SAMPLES * 2 * FLAC__stream_decoder_get_channels(mFlacDec);
// State oldstate=*state;
int jumppos=0;
int actSecsToSkip = (*secondsToSkip != 0) ? *secondsToSkip : MSECS_TO_SKIP / 1000;
int bytes_to_skip = (int) (1.0 * actSecsToSkip * meta_data->bitrate / 8);
int bytes_to_play = (int) (1.0 * MSECS_TO_PLAY / 1000 * meta_data->bitrate / 8);
unsigned int oldSecsToSkip = *secondsToSkip;
// FLAC__uint64 position;
do
{
while(*state==PAUSE)
usleep(10000);
if(*state==FF || *state==REV)
{
if (oldSecsToSkip != *secondsToSkip)
{
actSecsToSkip = (*secondsToSkip != 0) ? *secondsToSkip : MSECS_TO_SKIP / 1000;
bytes_to_skip = (int) (1.0 * actSecsToSkip * meta_data->bitrate / 8);
oldSecsToSkip = *secondsToSkip;
}
printf("skipping %d secs and %d bytes\n",actSecsToSkip,bytes_to_skip);
if(std::abs(ftell(in)-jumppos) > bytes_to_play)
{
if(*state==FF)
{
fseek(in, bytes_to_skip, SEEK_CUR);
jumppos=ftell(in);
}
else
{
if(ftell(in) < bytes_to_skip)
{
fseek(in, 0, SEEK_SET);
*state=PLAY;
}
else
{
fseek(in, -bytes_to_skip, SEEK_CUR);
jumppos=ftell(in);
}
}
}
// if a custom value was set we only jump once
if (*secondsToSkip != 0) {
*state=PLAY;
}
}
if (FLAC__stream_decoder_get_state(mFlacDec) == FLAC__STREAM_DECODER_END_OF_STREAM) {
rval = false;
break;
}
rval = FLAC__stream_decoder_process_single(mFlacDec);
// TODO: calculate time_played from the actual file position so that REW/FF actions will be included
*time_played = (mSamplesProcessed * (mLengthInMsec/1000)) / mTotalSamples;
} while (rval && *state != STOP_REQ && Status == OK);
// let buffer run dry
printf("let buffer run dry\n");
while (rval == true && *state != STOP_REQ && Status == OK /* && mReadSlot != mWriteSlot*/)
{
printf("...drying - *state=%x, Status=%x\n", *state, Status);
usleep(100000);
}
/* clean up the junk from the party */
if (mMetadata)
FLAC__metadata_object_delete(mMetadata);
mMetadata = NULL;
FLAC__stream_decoder_finish(mFlacDec);
FLAC__stream_decoder_delete(mFlacDec);
mFlacDec = NULL;
audioDecoder->StopClip();
/* and drive home ;) */
return Status;
}
bool CFlacDec::GetMetaData(FILE *in, const bool /*nice*/, CAudioMetaData* m)
{
FLAC__StreamDecoder *vf;
vf = FLAC__stream_decoder_new();
FLAC__stream_decoder_set_metadata_ignore_all(vf);
// we need streaminfo (default on) and FLAC__METADATA_TYPE_VORBIS_COMMENT (default off) for ID3 tags
FLAC__stream_decoder_set_metadata_respond(vf, FLAC__METADATA_TYPE_STREAMINFO);
FLAC__stream_decoder_set_metadata_respond(vf, FLAC__METADATA_TYPE_VORBIS_COMMENT);
if (!Open(in, vf))
{
return false;
}
if (FLAC__stream_decoder_process_until_end_of_metadata(vf)) {
// if the metadata callback was called mMetadata should be filled with infos
if (mMetadata) {
SetMetaData(mMetadata, m);
}
}
// clean up stuff, the mMetadata may be used later again so let the decoder free it
FLAC__stream_decoder_finish(vf);
FLAC__stream_decoder_delete(vf);
return true;
}
CFlacDec* CFlacDec::getInstance()
{
static CFlacDec* FlacDec = NULL;
if(FlacDec == NULL)
{
FlacDec = new CFlacDec();
}
return FlacDec;
}
void CFlacDec::ParseUserComments(FLAC__StreamMetadata_VorbisComment* vc, CAudioMetaData* m)
{
if(vc->vendor_string.entry)
printf("vendor_string = %d: %s\n", vc->vendor_string.length, vc->vendor_string.entry);
printf("num_comments = %u\n", vc->num_comments);
for(unsigned int i = 0; i < vc->num_comments; i++) {
if(vc->comments[i].entry) {
printf("comments[%u] = %d: %s\n", i, vc->comments[i].length, vc->comments[i].entry);
const char *search;
if((search=strstr((const char*)vc->comments[i].entry,"Artist"))!=NULL ||
(search=strstr((const char*)vc->comments[i].entry,"ARTIST"))!=NULL)
m->artist = search+7;
else if((search=strstr((const char*)vc->comments[i].entry,"Album"))!=NULL ||
(search=strstr((const char*)vc->comments[i].entry,"ALBUM"))!=NULL)
m->album = search+6;
else if((search=strstr((const char*)vc->comments[i].entry,"Title"))!=NULL ||
(search=strstr((const char*)vc->comments[i].entry,"TITLE"))!=NULL)
m->title = search+6;
else if((search=strstr((const char*)vc->comments[i].entry,"Genre"))!=NULL ||
(search=strstr((const char*)vc->comments[i].entry,"GENRE"))!=NULL)
m->genre = search+6;
else if((search=strstr((const char*)vc->comments[i].entry,"Date"))!=NULL ||
(search=strstr((const char*)vc->comments[i].entry,"DATE"))!=NULL)
m->date = search+5;
else if((search=strstr((const char*)vc->comments[i].entry,"TrackNumber"))!=NULL ||
(search=strstr((const char*)vc->comments[i].entry,"TRACKNUMBER"))!=NULL)
m->track = search+12;
}
}
}
void CFlacDec::SetMetaData(FLAC__StreamMetadata *metadata, CAudioMetaData* m)
{
/* Set Metadata */
m->type = CAudioMetaData::FLAC;
m->bitrate = mBps * mSampleRate;
m->samplerate = mSampleRate;
m->total_time = (time_t) mLengthInMsec / 1000;
std::stringstream ss;
ss << "FLAC V." << FLAC__VERSION_STRING << " / " << mChannels << "channel(s)";
m->type_info = ss.str();
ParseUserComments((FLAC__StreamMetadata_VorbisComment*)&(metadata->data.vorbis_comment), m);
m->changed=true;
}
bool CFlacDec::Open(FILE* in, FLAC__StreamDecoder* vf)
{
FLAC__StreamDecoderInitStatus rval;
mIn = in;
/* we need to use our own functions, because we have */
/* the netfile layer hooked in here. If we would not */
/* provide callbacks, the tremor lib and the netfile */
/* layer would clash and steal each other the data */
/* from the stream ! */
/* test the dope ... */
rval = FLAC__stream_decoder_init_stream(vf,
flac_read,
flac_seek,
flac_tell,
flac_length,
flac_eof,
flac_write,
flac_metadata,
flac_error,
(void *)this);
/* and tell our friends about the quality of the stuff */
// initialize the sound device here
if(rval<0)
{
switch(rval)
{
/* err_txt from netfile.cpp */
case FLAC__STREAM_DECODER_INIT_STATUS_OK: sprintf(err_txt, "Initialization was successful"); break;
case FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER: sprintf(err_txt, "The library was not compiled with support for the given container format"); break;
case FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS: sprintf(err_txt, "A required callback was not supplied"); break;
case FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR: sprintf(err_txt, "An error occurred allocating memory"); break;
case FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE: sprintf(err_txt, "fopen() failed in FLAC__stream_decoder_init_file() or FLAC__stream_decoder_init_ogg_file()"); break;
case FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED: sprintf(err_txt, "FLAC__stream_decoder_init_*() was called when the decoder was already initialized, usually because FLAC__stream_decoder_finish() was not called"); break;
default: sprintf(err_txt, "unknown error, code: %d", rval);
}
// fprintf(stderr,"%s: %s\n", ProgName, err_txt);
printf("%s: %s\n", ProgName, err_txt);
return false;
}
/* finish the opening and ignite the joint */
// mSeekable = true;
mSeekable = false;
return true;
}

View File

@@ -0,0 +1,77 @@
/*
Neutrino-GUI - DBoxII-Project
FLAC audio decoder
License: GPL
ported from tuxbox-CVS flacdec.h CVS rev 1.1
Neutrino-HD port is:
(C) 2011 Stefan Seyfried, B1 Systems GmbH, Vohburg, Germany
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
*/
#ifndef __FLAC_DEC__
#define __FLAC_DEC__
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <basedec.h>
#include <driver/audiometadata.h>
#include <FLAC/all.h>
#define DECODE_SLOTS 30
class CFlacDec : public CBaseDec
{
public:
static CFlacDec* getInstance();
virtual RetCode Decoder(FILE *, const int, State* const, CAudioMetaData*, time_t* const, unsigned int* const);
bool GetMetaData(FILE *in, const bool nice, CAudioMetaData* m);
CFlacDec(){ mMetadata = NULL; };
int mWriteSlot;
int mReadSlot;
int mSlotSize;
unsigned long mFrameCount;
unsigned int mChannels;
unsigned int mSampleRate;
unsigned long mBytes;
unsigned int mBps;
unsigned int mSamplesProcessed;
unsigned int mBuffersize;
unsigned long mTotalSamples;
unsigned int mLengthInMsec;
FLAC__StreamDecoder *mFlacDec;
FILE* mIn;
char* mPcmSlots[DECODE_SLOTS];
FLAC__uint64 mSlotTime[DECODE_SLOTS];
RetCode Status;
FLAC__StreamMetadata *mMetadata;
private:
void ParseUserComments(FLAC__StreamMetadata_VorbisComment*, CAudioMetaData*);
bool Open(FILE*, FLAC__StreamDecoder*);
void SetMetaData(FLAC__StreamMetadata*, CAudioMetaData*);
State* mState;
bool mSeekable;
time_t* mTimePlayed;
};
#endif