diff options
Diffstat (limited to 'vdr_decoder_flac.c')
| -rw-r--r-- | vdr_decoder_flac.c | 572 |
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 |
