+
+#ifdef USE_LIBFLAC
+/*****************************************************************************
+ * encoder_sys_t : flac encoder descriptor
+ *****************************************************************************/
+struct encoder_sys_t
+{
+ /*
+ * Input properties
+ */
+ int i_headers;
+
+ int i_samples_delay;
+ int i_channels;
+
+ FLAC__int32 *p_buffer;
+ unsigned int i_buffer;
+
+ block_t *p_chain;
+
+ /*
+ * FLAC properties
+ */
+ FLAC__StreamEncoder *p_flac;
+ FLAC__StreamMetadata_StreamInfo stream_info;
+
+ /*
+ * Common properties
+ */
+ mtime_t i_pts;
+};
+
+#define STREAMINFO_SIZE 38
+
+static block_t *Encode( encoder_t *, aout_buffer_t * );
+
+static FLAC__StreamEncoderWriteStatus
+EncoderWriteCallback( const FLAC__StreamEncoder *encoder,
+ const FLAC__byte buffer[],
+ unsigned bytes, unsigned samples,
+ unsigned current_frame, void *client_data );
+
+static void EncoderMetadataCallback( const FLAC__StreamEncoder *encoder,
+ const FLAC__StreamMetadata *metadata,
+ void *client_data );
+
+/*****************************************************************************
+ * OpenEncoder: probe the encoder and return score
+ *****************************************************************************/
+static int OpenEncoder( vlc_object_t *p_this )
+{
+ encoder_t *p_enc = (encoder_t *)p_this;
+ encoder_sys_t *p_sys;
+
+ if( p_enc->fmt_out.i_codec != VLC_FOURCC('f','l','a','c') &&
+ !p_enc->b_force )
+ {
+ return VLC_EGENERIC;
+ }
+
+ /* Allocate the memory needed to store the decoder's structure */
+ if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL )
+ return VLC_ENOMEM;
+ p_enc->p_sys = p_sys;
+ p_enc->pf_encode_audio = Encode;
+ p_enc->fmt_out.i_codec = VLC_FOURCC('f','l','a','c');
+
+ p_sys->i_headers = 0;
+ p_sys->p_buffer = 0;
+ p_sys->i_buffer = 0;
+ p_sys->i_samples_delay = 0;
+
+ /* Create flac encoder */
+ if( !(p_sys->p_flac = FLAC__stream_encoder_new()) )
+ {
+ msg_Err( p_enc, "FLAC__stream_encoder_new() failed" );
+ free( p_sys );
+ return VLC_EGENERIC;
+ }
+
+ FLAC__stream_encoder_set_streamable_subset( p_sys->p_flac, 1 );
+ FLAC__stream_encoder_set_channels( p_sys->p_flac,
+ p_enc->fmt_in.audio.i_channels );
+ FLAC__stream_encoder_set_sample_rate( p_sys->p_flac,
+ p_enc->fmt_in.audio.i_rate );
+ FLAC__stream_encoder_set_bits_per_sample( p_sys->p_flac, 16 );
+ p_enc->fmt_in.i_codec = AOUT_FMT_S16_NE;
+
+ /* Get and store the STREAMINFO metadata block as a p_extra */
+ p_sys->p_chain = 0;
+
+#ifdef USE_NEW_FLAC_API
+ if( FLAC__stream_encoder_init_stream( p_sys->p_flac,
+ EncoderWriteCallback,
+ NULL,
+ NULL,
+ EncoderMetadataCallback,
+ p_enc )
+ != FLAC__STREAM_ENCODER_INIT_STATUS_OK )
+ {
+ msg_Err( p_enc, "FLAC__stream_encoder_init_stream() failed" );
+ FLAC__stream_encoder_delete( p_sys->p_flac );
+ free( p_sys );
+ return VLC_EGENERIC;
+ }
+#else
+ FLAC__stream_encoder_set_write_callback( p_sys->p_flac,
+ EncoderWriteCallback );
+ FLAC__stream_encoder_set_metadata_callback( p_sys->p_flac,
+ EncoderMetadataCallback );
+ FLAC__stream_encoder_set_client_data( p_sys->p_flac, p_enc );
+
+ FLAC__stream_encoder_init( p_sys->p_flac );
+#endif
+
+ return VLC_SUCCESS;
+}
+
+/****************************************************************************
+ * Encode: the whole thing
+ ****************************************************************************
+ * This function spits out ogg packets.
+ ****************************************************************************/
+static block_t *Encode( encoder_t *p_enc, aout_buffer_t *p_aout_buf )
+{
+ encoder_sys_t *p_sys = p_enc->p_sys;
+ block_t *p_chain;
+ unsigned int i;
+
+ p_sys->i_pts = p_aout_buf->start_date -
+ (mtime_t)1000000 * (mtime_t)p_sys->i_samples_delay /
+ (mtime_t)p_enc->fmt_in.audio.i_rate;
+
+ p_sys->i_samples_delay += p_aout_buf->i_nb_samples;
+
+ /* Convert samples to FLAC__int32 */
+ if( p_sys->i_buffer < p_aout_buf->i_nb_bytes * 2 )
+ {
+ p_sys->p_buffer =
+ realloc( p_sys->p_buffer, p_aout_buf->i_nb_bytes * 2 );
+ p_sys->i_buffer = p_aout_buf->i_nb_bytes * 2;
+ }
+
+ for( i = 0 ; i < p_aout_buf->i_nb_bytes / 2 ; i++ )
+ {
+ p_sys->p_buffer[i]= ((int16_t *)p_aout_buf->p_buffer)[i];
+ }
+
+ FLAC__stream_encoder_process_interleaved( p_sys->p_flac, p_sys->p_buffer,
+ p_aout_buf->i_nb_samples );
+
+ p_chain = p_sys->p_chain;
+ p_sys->p_chain = 0;
+
+ return p_chain;
+}
+
+/*****************************************************************************
+ * CloseEncoder: encoder destruction
+ *****************************************************************************/
+static void CloseEncoder( vlc_object_t *p_this )
+{
+ encoder_t *p_enc = (encoder_t *)p_this;
+ encoder_sys_t *p_sys = p_enc->p_sys;
+
+ FLAC__stream_encoder_delete( p_sys->p_flac );
+
+ free( p_sys->p_buffer );
+ free( p_sys );
+}
+
+/*****************************************************************************
+ * EncoderMetadataCallback: called by libflac to output metadata
+ *****************************************************************************/
+static void EncoderMetadataCallback( const FLAC__StreamEncoder *encoder,
+ const FLAC__StreamMetadata *metadata,
+ void *client_data )
+{
+ VLC_UNUSED(encoder);
+ encoder_t *p_enc = (encoder_t *)client_data;
+
+ msg_Err( p_enc, "MetadataCallback: %i", metadata->type );
+ return;
+}
+
+/*****************************************************************************
+ * EncoderWriteCallback: called by libflac to output encoded samples
+ *****************************************************************************/
+static FLAC__StreamEncoderWriteStatus
+EncoderWriteCallback( const FLAC__StreamEncoder *encoder,
+ const FLAC__byte buffer[],
+ unsigned bytes, unsigned samples,
+ unsigned current_frame, void *client_data )
+{
+ VLC_UNUSED(encoder); VLC_UNUSED(current_frame);
+ encoder_t *p_enc = (encoder_t *)client_data;
+ encoder_sys_t *p_sys = p_enc->p_sys;
+ block_t *p_block;
+
+ if( samples == 0 )
+ {
+ if( p_sys->i_headers == 1 )
+ {
+ msg_Dbg( p_enc, "Writing STREAMINFO: %i", bytes );
+
+ /* Backup the STREAMINFO metadata block */
+ p_enc->fmt_out.i_extra = STREAMINFO_SIZE + 4;
+ p_enc->fmt_out.p_extra = malloc( STREAMINFO_SIZE + 4 );
+ memcpy( p_enc->fmt_out.p_extra, "fLaC", 4 );
+ memcpy( ((uint8_t *)p_enc->fmt_out.p_extra) + 4, buffer,
+ STREAMINFO_SIZE );
+
+ /* Fake this as the last metadata block */
+ ((uint8_t*)p_enc->fmt_out.p_extra)[4] |= 0x80;
+ }
+ p_sys->i_headers++;
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+ }
+
+ p_block = block_New( p_enc, bytes );
+ memcpy( p_block->p_buffer, buffer, bytes );
+
+ p_block->i_dts = p_block->i_pts = p_sys->i_pts;
+
+ p_sys->i_samples_delay -= samples;
+
+ p_block->i_length = (mtime_t)1000000 *
+ (mtime_t)samples / (mtime_t)p_enc->fmt_in.audio.i_rate;
+
+ /* Update pts */
+ p_sys->i_pts += p_block->i_length;
+
+ block_ChainAppend( &p_sys->p_chain, p_block );
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+#endif