+static void CloseDecoder( vlc_object_t *p_this )
+{
+ decoder_t *p_dec = (decoder_t *)p_this;
+ decoder_sys_t *p_sys = p_dec->p_sys;
+
+ if( !p_sys->b_packetizer && p_sys->i_headers > 3 )
+ {
+ vorbis_block_clear( &p_sys->vb );
+ vorbis_dsp_clear( &p_sys->vd );
+ }
+
+ vorbis_comment_clear( &p_sys->vc );
+ vorbis_info_clear( &p_sys->vi ); /* must be called last */
+
+ free( p_sys );
+}
+
+#if defined(HAVE_VORBIS_VORBISENC_H) && !defined(MODULE_NAME_IS_tremor)
+
+/*****************************************************************************
+ * encoder_sys_t : vorbis encoder descriptor
+ *****************************************************************************/
+struct encoder_sys_t
+{
+ /*
+ * Vorbis properties
+ */
+ vorbis_info vi; /* struct that stores all the static vorbis bitstream
+ settings */
+ vorbis_comment vc; /* struct that stores all the bitstream user
+ * comments */
+ vorbis_dsp_state vd; /* central working state for the packet->PCM
+ * decoder */
+ vorbis_block vb; /* local working space for packet->PCM decode */
+
+ int i_last_block_size;
+ int i_samples_delay;
+ int i_channels;
+
+ /*
+ * Common properties
+ */
+ mtime_t i_pts;
+
+ /*
+ ** Channel reordering
+ */
+ int pi_chan_table[AOUT_CHAN_MAX];
+
+};
+
+/*****************************************************************************
+ * 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;
+ int i_quality, i_min_bitrate, i_max_bitrate, i;
+ ogg_packet header[3];
+ vlc_value_t val;
+ uint8_t *p_extra;
+
+ if( p_enc->fmt_out.i_codec != VLC_FOURCC('v','o','r','b') &&
+ !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 )
+ {
+ msg_Err( p_enc, "out of memory" );
+ return VLC_EGENERIC;
+ }
+ 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');
+
+ sout_CfgParse( 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, VLC_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 )