summaryrefslogtreecommitdiff
path: root/vdr_decoder_flac.c
diff options
context:
space:
mode:
Diffstat (limited to 'vdr_decoder_flac.c')
-rw-r--r--vdr_decoder_flac.c572
1 files changed, 265 insertions, 307 deletions
diff --git a/vdr_decoder_flac.c b/vdr_decoder_flac.c
index 6ecc6a5..3aa2f43 100644
--- a/vdr_decoder_flac.c
+++ b/vdr_decoder_flac.c
@@ -1,6 +1,6 @@
/*! \file vdr_decoder_flac.c
* \ingroup vdr
- *
+ *
* The file implements a decoder which is used by the player to decode flac audio files.
*
* Based on code from
@@ -27,358 +27,316 @@
#include <mad.h>
-
using namespace std;
static const unsigned MAX_RES_SIZE = 16384;
// --- mgFlacDecoder -------------------------------------------------------------
-mgFlacDecoder::mgFlacDecoder( mgItemGd *item )
- : mgDecoder( item ), FLAC::Decoder::File()
-{
- mgLog lg( "mgFlacDecoder::mgFlacDecoder" );
+mgFlacDecoder::mgFlacDecoder( mgItemGd *item )
+: mgDecoder( item ), FLAC::Decoder::File() {
- m_filename = item->getSourceFile();
- m_pcm = 0;
- m_reservoir = 0;
+ m_filename = item->getSourceFile();
+ m_pcm = 0;
+ m_reservoir = 0;
- initialize();
+ initialize();
}
-mgFlacDecoder::~mgFlacDecoder()
-{
- mgLog lg( "mgFlacDecoder::~mgFlacDecoder" );
- clean();
+mgFlacDecoder::~mgFlacDecoder() {
+ clean();
}
-bool mgFlacDecoder::valid()
-{
- // how to check whether this is a valid flac file?
- return is_valid();
+bool mgFlacDecoder::valid() {
+ // how to check whether this is a valid flac file?
+ return is_valid();
}
-mgPlayInfo *mgFlacDecoder::playInfo(void)
-{
- return 0;
+mgPlayInfo *mgFlacDecoder::playInfo(void) {
+ return 0;
}
-bool mgFlacDecoder::initialize()
-{
- mgLog lg( "mgFlacDecoder::initialize" );
- bool state = true;
-
- clean();
-
- // set_metadata_ignore_all();
- set_metadata_respond( FLAC__METADATA_TYPE_STREAMINFO );
-
- m_first = true;
- m_reservoir_count = 0;
- m_current_time_ms = 0;
- m_len_decoded = 0;
- m_index = 0;
- m_pcm = new struct mad_pcm;
-
- // init reservoir buffer; this should be according to the maximum
- // frame/sample size that we can probably obtain from metadata
- m_reservoir = new FLAC__int32*[2];
- m_reservoir[0] = new FLAC__int32[MAX_RES_SIZE];
- m_reservoir[1] = new FLAC__int32[MAX_RES_SIZE];
-
- // TODO: check init() return value
+bool mgFlacDecoder::initialize() {
+ bool state = true;
+
+ clean();
+
+ // set_metadata_ignore_all();
+ set_metadata_respond( FLAC__METADATA_TYPE_STREAMINFO );
+
+ m_first = true;
+ m_reservoir_count = 0;
+ m_current_time_ms = 0;
+ m_len_decoded = 0;
+ m_index = 0;
+ m_pcm = new struct mad_pcm;
+
+ // init reservoir buffer; this should be according to the maximum
+ // frame/sample size that we can probably obtain from metadata
+ m_reservoir = new FLAC__int32*[2];
+ m_reservoir[0] = new FLAC__int32[MAX_RES_SIZE];
+ m_reservoir[1] = new FLAC__int32[MAX_RES_SIZE];
+
+ // TODO: check init() return value
#ifdef LEGACY_FLAC
- set_filename( m_filename.c_str() );
- /*FLAC::Decoder::File::State d =*/ init();
+ set_filename( m_filename.c_str() );
+ /*FLAC::Decoder::File::State d =*/ init();
#else
- /*FLAC__StreamDecoderInitStatus d =*/ init( m_filename.c_str() );
+ /*FLAC__StreamDecoderInitStatus d =*/ init( m_filename.c_str() );
#endif
- process_until_end_of_metadata(); // basically just skip metadata
+ // basically just skip metadata
+ process_until_end_of_metadata();
- return state;
+ return state;
}
-bool mgFlacDecoder::clean()
-{
- mgLog lg( "mgFlacDecoder::clean" );
- m_playing = false;
-
- delete m_pcm;
- m_pcm = 0;
-
- if( m_reservoir )
- {
- delete[] m_reservoir[0];
- delete[] m_reservoir[1];
- }
- delete[] m_reservoir;
- m_reservoir = 0;
-
- // why false? true?
- return true;
+bool mgFlacDecoder::clean() {
+ m_playing = false;
+
+ delete m_pcm;
+ m_pcm = 0;
+
+ if( m_reservoir ) {
+ delete[] m_reservoir[0];
+ delete[] m_reservoir[1];
+ }
+ delete[] m_reservoir;
+ m_reservoir = 0;
+
+ // why false? true?
+ return true;
}
-bool mgFlacDecoder::start()
-{
- MGLOG( "mgFlacDecoder::start" );
- bool res = false;
- lock(true);
-
- // can FLAC handle more than 2 channels anyway?
- if( m_item->getChannels() <= 2 )
- {
- m_playing = true;
- res = true;
- }
- else
- {
- mgError( "ERROR: cannot play flac file %s: more than 2 channels", m_filename.c_str() );
- clean();
- }
-
- unlock();
- return res;
+bool mgFlacDecoder::start() {
+ bool res = false;
+ lock(true);
+
+ // can FLAC handle more than 2 channels anyway?
+ if( m_item->getChannels() <= 2 ) {
+ m_playing = true;
+ res = true;
+ }
+ else {
+ mgError( "ERROR: cannot play flac file %s: more than 2 channels", m_filename.c_str() );
+ clean();
+ }
+
+ unlock();
+ return res;
}
-bool mgFlacDecoder::stop(void)
-{
- MGLOG( "mgFlacDecoder::stop" );
- lock();
- finish();
+bool mgFlacDecoder::stop(void) {
+ lock();
+ finish();
- if( m_playing )
- {
- clean();
- }
- unlock();
+ if( m_playing ) {
+ clean();
+ }
+ unlock();
- return true;
+ return true;
}
-struct mgDecode *mgFlacDecoder::done( eDecodeStatus status )
-{
- m_ds.status = status;
- m_ds.index = m_index;
- m_ds.pcm = m_pcm;
+struct mgDecode *mgFlacDecoder::done( eDecodeStatus status ) {
+ m_ds.status = status;
+ m_ds.index = m_index;
+ m_ds.pcm = m_pcm;
- unlock(); // release the lock from Decode() !
+ unlock(); // release the lock from Decode() !
- return &m_ds;
+ return &m_ds;
}
-struct mgDecode *mgFlacDecoder::decode()
-{
- // mgLog lg( "mgFlacDecoder::decode" );
- m_decode_status = dsPlay;
-
- const unsigned SF_SAMPLES = (sizeof(m_pcm->samples[0])/sizeof(mad_fixed_t));
-
- lock(true); // this is released in done()
-
- if( m_playing )
- {
- m_pcm->samplerate = m_item->getSampleRate(); // from database
- m_pcm->channels = m_item->getChannels(); // from database
-
- // if there is enough data in the reservoir, don't start decoding
- // PROBLEM: but we need a first time!
- bool finished;
- if( m_first )
- {
- finished = false;
- m_first = false;
- }
- else
- {
- finished = m_reservoir_count >= SF_SAMPLES;
- }
-
- while( !finished )
- { // decode single frames until m_reservoir_count >= SF_SAMPLES or eof/error
- m_first = false;
-
- // decode a single sample into reservoir_buffer (done by the write callback)
- process_single();
+struct mgDecode *mgFlacDecoder::decode() {
+ m_decode_status = dsPlay;
+
+ const unsigned SF_SAMPLES = (sizeof(m_pcm->samples[0])/sizeof(mad_fixed_t));
+
+ lock(true); // this is released in done()
+
+ if( m_playing ) {
+ // from database
+ m_pcm->samplerate = m_item->getSampleRate();
+ // from database
+ m_pcm->channels = m_item->getChannels();
+
+ // if there is enough data in the reservoir, don't start decoding
+ // PROBLEM: but we need a first time!
+ bool finished;
+ if( m_first ) {
+ finished = false;
+ m_first = false;
+ }
+ else {
+ finished = m_reservoir_count >= SF_SAMPLES;
+ }
+
+ while( !finished ) {
+ // decode single frames until m_reservoir_count >= SF_SAMPLES or eof/error
+ m_first = false;
+
+ // decode a single sample into reservoir_buffer (done by the write callback)
+ process_single();
#ifdef LEGACY_FLAC
- if (get_stream_decoder_state()==FLAC__STREAM_DECODER_END_OF_STREAM)
+ if (get_stream_decoder_state()==FLAC__STREAM_DECODER_END_OF_STREAM)
#else
- if (get_state()==FLAC__STREAM_DECODER_END_OF_STREAM)
+ if (get_state()==FLAC__STREAM_DECODER_END_OF_STREAM)
#endif
- {
- m_decode_status = dsEof;
- finished = true;
- }
-
- // check termination criterion
- finished |= m_reservoir_count >= SF_SAMPLES || m_len_decoded == 0; // or error?
- }
-
- // transfer min( SF_SAMPLES, m_reservoir_count ) to pcm buffer
-
- int n = ( SF_SAMPLES <= m_reservoir_count )? SF_SAMPLES: m_reservoir_count;
-
- m_pcm->length = n;
- m_index = m_current_time_ms;
-
- // fill pcm container from reservoir buffer
- FLAC__int32 *data0 = m_reservoir[0];
- FLAC__int32 *data1 = m_reservoir[1];
-
- mad_fixed_t *sam0 = m_pcm->samples[0];
- mad_fixed_t *sam1 = m_pcm->samples[1];
-
- // determine shift value for mad_fixed conversion
- // TODO -- check for real bitsize and shit accordingly (left/right)
- const int s = MAD_F_FRACBITS + 1 - ( sizeof(short)*8 );
- // const int s = ( sizeof(int)*8 ) - 1 - MAD_F_FRACBITS; // from libsoundfile decoder
-
- if( m_pcm->channels > 1 )
- {
- for( int j=n; j > 0 ; j-- )
- {
- // copy buffer and transform (cf. libsoundfile decoder)
- *sam0++ = (*data0++) << s;
- *sam1++ = (*data1++) << s;
- }
- // "delete" transferred samples from reservoir buffer
- memmove( m_reservoir[0], m_reservoir[0] + n, (m_reservoir_count - n)*sizeof(FLAC__int32) );
- memmove( m_reservoir[1], m_reservoir[1] + n, (m_reservoir_count - n)*sizeof(FLAC__int32) );
- }
- else
- {
- for( int j=n; j > 0 ; j--)
- {
- *sam0++ = (*data0++) << s;
- }
- memmove( m_reservoir[0], m_reservoir[0] + n, (m_reservoir_count - n)*sizeof(FLAC__int32) );
- }
- m_reservoir_count -= n;
-
- // and return, indicating that playing will continue (unless an error has occurred)
- return done( m_decode_status );
- }
-
- return done(dsError);
+ {
+ m_decode_status = dsEof;
+ finished = true;
+ }
+
+ // check termination criterion
+ // or error?
+ finished |= m_reservoir_count >= SF_SAMPLES || m_len_decoded == 0;
+ }
+
+ // transfer min( SF_SAMPLES, m_reservoir_count ) to pcm buffer
+
+ int n = ( SF_SAMPLES <= m_reservoir_count )? SF_SAMPLES: m_reservoir_count;
+
+ m_pcm->length = n;
+ m_index = m_current_time_ms;
+
+ // fill pcm container from reservoir buffer
+ FLAC__int32 *data0 = m_reservoir[0];
+ FLAC__int32 *data1 = m_reservoir[1];
+
+ mad_fixed_t *sam0 = m_pcm->samples[0];
+ mad_fixed_t *sam1 = m_pcm->samples[1];
+
+ // determine shift value for mad_fixed conversion
+ // TODO -- check for real bitsize and shit accordingly (left/right)
+ const int s = MAD_F_FRACBITS + 1 - ( sizeof(short)*8 );
+ // const int s = ( sizeof(int)*8 ) - 1 - MAD_F_FRACBITS; // from libsoundfile decoder
+
+ if( m_pcm->channels > 1 ) {
+ for( int j=n; j > 0 ; j-- ) {
+ // copy buffer and transform (cf. libsoundfile decoder)
+ *sam0++ = (*data0++) << s;
+ *sam1++ = (*data1++) << s;
+ }
+ // "delete" transferred samples from reservoir buffer
+ memmove( m_reservoir[0], m_reservoir[0] + n, (m_reservoir_count - n)*sizeof(FLAC__int32) );
+ memmove( m_reservoir[1], m_reservoir[1] + n, (m_reservoir_count - n)*sizeof(FLAC__int32) );
+ }
+ else {
+ for( int j=n; j > 0 ; j--) {
+ *sam0++ = (*data0++) << s;
+ }
+ memmove( m_reservoir[0], m_reservoir[0] + n, (m_reservoir_count - n)*sizeof(FLAC__int32) );
+ }
+ m_reservoir_count -= n;
+
+ // and return, indicating that playing will continue (unless an error has occurred)
+ return done( m_decode_status );
+ }
+
+ return done(dsError);
}
-::FLAC__StreamDecoderWriteStatus
+::FLAC__StreamDecoderWriteStatus
mgFlacDecoder::write_callback(const ::FLAC__Frame *frame,
- const FLAC__int32 * const buffer[])
-{
- // mgLog lg( "mgFlacDecoder::write_callback" );
-
- // add decoded buffer to reservoir
- m_len_decoded = frame->header.blocksize;
- m_current_samples += m_len_decoded;
- m_current_time_ms += (m_len_decoded*1000) / m_pcm->samplerate; // in milliseconds
-
-
- // append buffer to m_reservoir
- if( m_len_decoded > 0 )
- {
- memmove( m_reservoir[0] + m_reservoir_count, buffer[0], m_len_decoded*sizeof(FLAC__int32) );
-
- if( m_pcm->channels > 1 )
- {
- memmove( m_reservoir[1] + m_reservoir_count, buffer[1], m_len_decoded*sizeof(FLAC__int32) );
- }
-
- m_reservoir_count += m_len_decoded;
- }
- else
- {
- m_decode_status = dsEof;
- }
-
- return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
-}
+const FLAC__int32 * const buffer[]) {
+
+ // add decoded buffer to reservoir
+ m_len_decoded = frame->header.blocksize;
+ m_current_samples += m_len_decoded;
+ // in milliseconds
+ m_current_time_ms += (m_len_decoded*1000) / m_pcm->samplerate;
+
+ // append buffer to m_reservoir
+ if( m_len_decoded > 0 ) {
+ memmove( m_reservoir[0] + m_reservoir_count, buffer[0], m_len_decoded*sizeof(FLAC__int32) );
-void mgFlacDecoder::metadata_callback( const ::FLAC__StreamMetadata *metadata )
-{
- // not needed since metadata is ignored!?
- mgLog lg( "mgFlacDecoder::metadata_callback" );
-
- if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
- {
- m_nTotalSamples = (long)(metadata->data.stream_info.total_samples & 0xfffffffful);
- m_nBitsPerSample = metadata->data.stream_info.bits_per_sample;
- m_nCurrentChannels = metadata->data.stream_info.channels;
- m_nCurrentSampleRate = metadata->data.stream_info.sample_rate;
- m_nFrameSize = metadata->data.stream_info.max_framesize;
- m_nBlockSize = metadata->data.stream_info.max_blocksize;
-
- // m_nCurrentSampleRate = (int)get_sample_rate();
- m_nCurrentChannels = (int)get_channels();
- m_nCurrentBitsPerSample = (int)get_bits_per_sample();
- m_nBlockAlign = (m_nBitsPerSample / 8) * m_nCurrentChannels;
- m_nLengthMS = m_nTotalSamples / m_nCurrentSampleRate;
- m_nLengthMS *= 1000;
-
- // m_nAverageBitRate = ((m_pReader->GetLength() * 8) / (m_nLengthMS / 1000) / 1000);
- // m_nCurrentBitrate = m_nAverageBitRate;
- }
+ if( m_pcm->channels > 1 ) {
+ memmove( m_reservoir[1] + m_reservoir_count, buffer[1], m_len_decoded*sizeof(FLAC__int32) );
+ }
+
+ m_reservoir_count += m_len_decoded;
+ }
+ else {
+ m_decode_status = dsEof;
+ }
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
-void mgFlacDecoder::error_callback( ::FLAC__StreamDecoderErrorStatus status )
-{
- mgLog lg( "mgFlacDecoder::error_callback" );
-
- // check status and return
- switch( status )
- {
- case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
- {
- m_error = "An error in the stream caused the decoder to lose synchronization";
- } break;
- case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
- {
- m_error = "The decoder encountered a corrupted frame header.";
- } break;
- case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
- {
- m_error = "The frame's data did not match the CRC in the footer.";
- };
- default:
- {
- m_error = "Unknown error occurred.";
- }
- }
-
- // cout << "Error occured: " << m_error << endl;
- m_decode_status = dsError;
+void mgFlacDecoder::metadata_callback( const ::FLAC__StreamMetadata *metadata ) {
+ // TODO not needed since metadata is ignored!?
+
+ if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ m_nTotalSamples = (long)(metadata->data.stream_info.total_samples & 0xfffffffful);
+ m_nBitsPerSample = metadata->data.stream_info.bits_per_sample;
+ m_nCurrentChannels = metadata->data.stream_info.channels;
+ m_nCurrentSampleRate = metadata->data.stream_info.sample_rate;
+ m_nFrameSize = metadata->data.stream_info.max_framesize;
+ m_nBlockSize = metadata->data.stream_info.max_blocksize;
+
+ // m_nCurrentSampleRate = (int)get_sample_rate();
+ m_nCurrentChannels = (int)get_channels();
+ m_nCurrentBitsPerSample = (int)get_bits_per_sample();
+ m_nBlockAlign = (m_nBitsPerSample / 8) * m_nCurrentChannels;
+ m_nLengthMS = m_nTotalSamples / m_nCurrentSampleRate;
+ m_nLengthMS *= 1000;
+
+ // m_nAverageBitRate = ((m_pReader->GetLength() * 8) / (m_nLengthMS / 1000) / 1000);
+ // m_nCurrentBitrate = m_nAverageBitRate;
+ }
}
-bool mgFlacDecoder::skip(int seconds, int avail, int rate)
-{
- lock();
- bool res = false;
-
- if( m_playing )
- {
- float bufsecs = (float) avail / (float) (rate * (16 / 8 * 2));
-
- const long target_time_ms = ( ( seconds - (int)bufsecs ) * 1000) + m_current_time_ms;
- const double distance = target_time_ms / (double)m_nLengthMS;
- const long target_sample = (unsigned)(distance * (double)m_nTotalSamples);
-
- if( target_sample > 0 )
- {
- if( seek_absolute( (FLAC__uint64)target_sample) )
- {
- m_current_time_ms = target_time_ms;
- }
- else
- {
- seek_absolute( 0 );
- m_current_time_ms = 0;
- }
- res = true;
+void mgFlacDecoder::error_callback( ::FLAC__StreamDecoderErrorStatus status ) {
+
+ // check status and return
+ switch( status ) {
+ case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
+ {
+ m_error = "An error in the stream caused the decoder to lose synchronization";
+ } break;
+ case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
+ {
+ m_error = "The decoder encountered a corrupted frame header.";
+ } break;
+ case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
+ {
+ m_error = "The frame's data did not match the CRC in the footer.";
+ };
+ default:
+ {
+ m_error = "Unknown error occurred.";
+ }
}
- }
-
- unlock();
- return res;
+
+ // cout << "Error occured: " << m_error << endl;
+ m_decode_status = dsError;
}
-#endif //HAVE_FLAC
+bool mgFlacDecoder::skip(int seconds, int avail, int rate) {
+ lock();
+ bool res = false;
+
+ if( m_playing ) {
+ float bufsecs = (float) avail / (float) (rate * (16 / 8 * 2));
+
+ const long target_time_ms = ( ( seconds - (int)bufsecs ) * 1000) + m_current_time_ms;
+ const double distance = target_time_ms / (double)m_nLengthMS;
+ const long target_sample = (unsigned)(distance * (double)m_nTotalSamples);
+
+ if( target_sample > 0 ) {
+ if( seek_absolute( (FLAC__uint64)target_sample) ) {
+ m_current_time_ms = target_time_ms;
+ }
+ else {
+ seek_absolute( 0 );
+ m_current_time_ms = 0;
+ }
+ res = true;
+ }
+ }
+
+ unlock();
+ return res;
+}
+#endif //HAVE_FLAC