+
+ /* 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_in.i_codec = VLC_FOURCC('f','l','3','2');
+ p_enc->fmt_out.i_codec = VLC_FOURCC('v','o','r','b');
+
+ config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
+
+ var_Get( p_enc, ENC_CFG_PREFIX "quality", &val );
+ i_quality = val.i_int;
+ if( i_quality > 10 ) i_quality = 10;
+ if( i_quality < 0 ) i_quality = 0;
+ var_Get( p_enc, ENC_CFG_PREFIX "cbr", &val );
+ if( val.b_bool ) i_quality = 0;
+ var_Get( p_enc, ENC_CFG_PREFIX "max-bitrate", &val );
+ i_max_bitrate = val.i_int;
+ var_Get( p_enc, ENC_CFG_PREFIX "min-bitrate", &val );
+ i_min_bitrate = val.i_int;
+
+ /* Initialize vorbis encoder */
+ vorbis_info_init( &p_sys->vi );
+
+ if( i_quality > 0 )
+ {
+ /* VBR mode */
+ if( vorbis_encode_setup_vbr( &p_sys->vi,
+ p_enc->fmt_in.audio.i_channels, p_enc->fmt_in.audio.i_rate,
+ i_quality * 0.1 ) )
+ {
+ vorbis_info_clear( &p_sys->vi );
+ free( p_enc->p_sys );
+ msg_Err( p_enc, "VBR mode initialisation failed" );
+ return VLC_EGENERIC;
+ }
+
+ /* Do we have optional hard quality restrictions? */
+ if( i_max_bitrate > 0 || i_min_bitrate > 0 )
+ {
+ struct ovectl_ratemanage_arg ai;
+ vorbis_encode_ctl( &p_sys->vi, OV_ECTL_RATEMANAGE_GET, &ai );
+
+ ai.bitrate_hard_min = i_min_bitrate;
+ ai.bitrate_hard_max = i_max_bitrate;
+ ai.management_active = 1;
+
+ vorbis_encode_ctl( &p_sys->vi, OV_ECTL_RATEMANAGE_SET, &ai );
+
+ }
+ else
+ {
+ /* Turn off management entirely */
+ vorbis_encode_ctl( &p_sys->vi, OV_ECTL_RATEMANAGE_SET, NULL );
+ }
+ }
+ else
+ {
+ if( vorbis_encode_setup_managed( &p_sys->vi,
+ p_enc->fmt_in.audio.i_channels, p_enc->fmt_in.audio.i_rate,
+ i_min_bitrate > 0 ? i_min_bitrate * 1000: -1,
+ p_enc->fmt_out.i_bitrate,
+ i_max_bitrate > 0 ? i_max_bitrate * 1000: -1 ) )
+ {
+ vorbis_info_clear( &p_sys->vi );
+ msg_Err( p_enc, "CBR mode initialisation failed" );
+ free( p_enc->p_sys );
+ return VLC_EGENERIC;
+ }
+ }
+
+ vorbis_encode_setup_init( &p_sys->vi );
+
+ /* Add a comment */
+ vorbis_comment_init( &p_sys->vc);
+ vorbis_comment_add_tag( &p_sys->vc, "ENCODER", "VLC media player");
+
+ /* Set up the analysis state and auxiliary encoding storage */
+ vorbis_analysis_init( &p_sys->vd, &p_sys->vi );
+ vorbis_block_init( &p_sys->vd, &p_sys->vb );
+
+ /* Create and store headers */
+ vorbis_analysis_headerout( &p_sys->vd, &p_sys->vc,
+ &header[0], &header[1], &header[2]);
+ p_enc->fmt_out.i_extra = 3 * 2 + header[0].bytes +
+ header[1].bytes + header[2].bytes;
+ p_extra = p_enc->fmt_out.p_extra = malloc( p_enc->fmt_out.i_extra );
+ for( i = 0; i < 3; i++ )
+ {
+ *(p_extra++) = header[i].bytes >> 8;
+ *(p_extra++) = header[i].bytes & 0xFF;
+ memcpy( p_extra, header[i].packet, header[i].bytes );
+ p_extra += header[i].bytes;
+ }
+
+ p_sys->i_channels = p_enc->fmt_in.audio.i_channels;
+ p_sys->i_last_block_size = 0;
+ p_sys->i_samples_delay = 0;
+ p_sys->i_pts = 0;
+
+ ConfigureChannelOrder(p_sys->pi_chan_table, p_sys->vi.channels,
+ p_enc->fmt_in.audio.i_physical_channels, true);
+
+ 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;
+ ogg_packet oggpacket;
+ block_t *p_block, *p_chain = NULL;
+ float **buffer;
+ int i;
+ unsigned int j;
+
+ 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;
+
+ buffer = vorbis_analysis_buffer( &p_sys->vd, p_aout_buf->i_nb_samples );
+
+ /* convert samples to float and uninterleave */
+ for( i = 0; i < p_sys->i_channels; i++ )
+ {
+ for( j = 0 ; j < p_aout_buf->i_nb_samples ; j++ )
+ {
+ buffer[i][j]= ((float *)p_aout_buf->p_buffer)
+ [j * p_sys->i_channels + p_sys->pi_chan_table[i]];
+ }
+ }
+
+ vorbis_analysis_wrote( &p_sys->vd, p_aout_buf->i_nb_samples );
+
+ while( vorbis_analysis_blockout( &p_sys->vd, &p_sys->vb ) == 1 )
+ {
+ int i_samples;
+
+ vorbis_analysis( &p_sys->vb, NULL );
+ vorbis_bitrate_addblock( &p_sys->vb );
+
+ while( vorbis_bitrate_flushpacket( &p_sys->vd, &oggpacket ) )
+ {
+ int i_block_size;
+ p_block = block_New( p_enc, oggpacket.bytes );
+ memcpy( p_block->p_buffer, oggpacket.packet, oggpacket.bytes );
+
+ i_block_size = vorbis_packet_blocksize( &p_sys->vi, &oggpacket );
+
+ if( i_block_size < 0 ) i_block_size = 0;
+ i_samples = ( p_sys->i_last_block_size + i_block_size ) >> 2;
+ p_sys->i_last_block_size = i_block_size;
+
+ p_block->i_length = (mtime_t)1000000 *
+ (mtime_t)i_samples / (mtime_t)p_enc->fmt_in.audio.i_rate;
+
+ p_block->i_dts = p_block->i_pts = p_sys->i_pts;
+
+ p_sys->i_samples_delay -= i_samples;
+
+ /* Update pts */
+ p_sys->i_pts += p_block->i_length;
+ block_ChainAppend( &p_chain, p_block );
+ }
+ }
+
+ return p_chain;