[vlc-devel] [PATCH] avcodec:multichannel encoding support
Rémi Denis-Courmont
remi at remlab.net
Wed Mar 5 11:47:06 CET 2014
On Wed, 5 Mar 2014 12:43:53 +0200, ileoo at videolan.org wrote:
> From: Ilkka Ollakka <ileoo at videolan.org>
>
> Make some assumptions on channels, like 6 channels is 5.1 etc.
> ---
> modules/codec/avcodec/encoder.c | 97
> ++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 96 insertions(+), 1 deletion(-)
>
> diff --git a/modules/codec/avcodec/encoder.c
> b/modules/codec/avcodec/encoder.c
> index c51fd19..339b961 100644
> --- a/modules/codec/avcodec/encoder.c
> +++ b/modules/codec/avcodec/encoder.c
> @@ -41,6 +41,7 @@
> #include <vlc_cpu.h>
>
> #include <libavcodec/avcodec.h>
> +#include <libavutil/audioconvert.h>
>
> #include "avcodec.h"
> #include "avcommon.h"
> @@ -122,6 +123,10 @@ struct encoder_sys_t
> mtime_t i_pts;
> date_t buffer_date;
>
> + /* Multichannel (>2) channel reordering */
> + uint8_t i_channels_to_reorder;
> + uint8_t pi_reorder_layout[AOUT_CHAN_MAX];
> +
> /* Encoding settings */
> int i_key_int;
> int i_b_frames;
> @@ -148,6 +153,43 @@ struct encoder_sys_t
> AVFrame *frame;
> };
>
> +static const uint64_t pi_channels_map[][2] =
> +{
> + { AV_CH_FRONT_LEFT, AOUT_CHAN_LEFT },
> + { AV_CH_FRONT_RIGHT, AOUT_CHAN_RIGHT },
> + { AV_CH_FRONT_CENTER, AOUT_CHAN_CENTER },
> + { AV_CH_LOW_FREQUENCY, AOUT_CHAN_LFE },
> + { AV_CH_BACK_LEFT, AOUT_CHAN_REARLEFT },
> + { AV_CH_BACK_RIGHT, AOUT_CHAN_REARRIGHT },
> + { AV_CH_FRONT_LEFT_OF_CENTER, 0 },
> + { AV_CH_FRONT_RIGHT_OF_CENTER, 0 },
> + { AV_CH_BACK_CENTER, AOUT_CHAN_REARCENTER },
> + { AV_CH_SIDE_LEFT, AOUT_CHAN_MIDDLELEFT },
> + { AV_CH_SIDE_RIGHT, AOUT_CHAN_MIDDLERIGHT },
> + { AV_CH_TOP_CENTER, 0 },
> + { AV_CH_TOP_FRONT_LEFT, 0 },
> + { AV_CH_TOP_FRONT_CENTER, 0 },
> + { AV_CH_TOP_FRONT_RIGHT, 0 },
> + { AV_CH_TOP_BACK_LEFT, 0 },
> + { AV_CH_TOP_BACK_CENTER, 0 },
> + { AV_CH_TOP_BACK_RIGHT, 0 },
> + { AV_CH_STEREO_LEFT, 0 },
> + { AV_CH_STEREO_RIGHT, 0 },
> +};
> +
> +static const uint32_t channel_mask[][2] = {
> + {0,0},
> + {AOUT_CHAN_CENTER, AV_CH_LAYOUT_MONO},
> + {AOUT_CHANS_STEREO, AV_CH_LAYOUT_STEREO},
> + {AOUT_CHANS_2_1, AV_CH_LAYOUT_2POINT1},
> + {AOUT_CHANS_4_0, AV_CH_LAYOUT_4POINT0},
> + {AOUT_CHANS_4_1, AV_CH_LAYOUT_4POINT1},
> + {AOUT_CHANS_5_1, AV_CH_LAYOUT_5POINT1_BACK},
> + {AOUT_CHANS_7_0, AV_CH_LAYOUT_7POINT0},
> + {AOUT_CHANS_7_1, AV_CH_LAYOUT_7POINT1},
> + {AOUT_CHANS_8_1, AV_CH_LAYOUT_OCTAGONAL},
> +};
> +
> static const char *const ppsz_enc_options[] = {
> "keyint", "bframes", "vt", "qmin", "qmax", "codec", "hq",
> "rc-buffer-size", "rc-buffer-aggressivity", "pre-me", "hurry-up",
> @@ -654,7 +696,52 @@ int OpenEncoder( vlc_object_t *p_this )
> p_context->time_base.den = p_context->sample_rate;
> p_context->channels = p_enc->fmt_out.audio.i_channels;
> #if LIBAVUTIL_VERSION_CHECK( 52, 2, 6, 0, 0)
> - p_context->channel_layout = av_get_default_channel_layout(
> p_context->channels );
> + p_context->channel_layout =
channel_mask[p_context->channels][1];
> +
> + /* Setup Channel ordering for multichannel audio
> + * as VLC channel order isn't same as libavcodec expects
> + */
> +
> + p_sys->i_channels_to_reorder = 0;
> +
> + /* Specified order
> + * Copied from audio.c
> + */
> + const unsigned i_order_max = 8 *
> sizeof(p_context->channel_layout);
> + uint32_t pi_order_dst[AOUT_CHAN_MAX];
> + int i_channels_src = 0;
> +
> + if( p_context->channel_layout )
> + {
> + msg_Info( p_enc, "Creating channel order for reordering");
> + for( unsigned i = 0; i <
> sizeof(pi_channels_map)/sizeof(*pi_channels_map); i++ )
> + {
> + if( p_context->channel_layout & pi_channels_map[i][0] )
> + {
> + msg_Info( p_enc, "%d %x mapped to %x",
> i_channels_src, pi_channels_map[i][0], pi_channels_map[i][1]);
> + pi_order_dst[i_channels_src++] =
> pi_channels_map[i][1];
> + }
> + }
> + }
> + else
> + {
> + msg_Info( p_enc, "Creating default channel order for
> reordering");
> + /* Create default order */
> + for( unsigned int i = 0; i < __MIN( i_order_max,
> (unsigned)p_sys->p_context->channels ); i++ )
> + {
> + if( i <
sizeof(pi_channels_map)/sizeof(*pi_channels_map) )
> + {
> + msg_Info( p_enc, "%d channel is %x",
i_channels_src,
> pi_channels_map[i][1]);
> + pi_order_dst[i_channels_src++] =
> pi_channels_map[i][1];
> + }
> + }
> + }
> + if( i_channels_src != p_context->channels )
> + msg_Err( p_enc, "Channel layout not understood" );
> +
> + p_sys->i_channels_to_reorder = aout_CheckChannelReorder( NULL,
> pi_order_dst,
> + channel_mask[p_context->channels][0],
> p_sys->pi_reorder_layout );
> + msg_Info( p_enc,"Channel reordering %d",
> p_sys->i_channels_to_reorder);
> #endif
>
> if ( p_enc->fmt_out.i_codec == VLC_CODEC_MP4A )
> @@ -1237,6 +1324,14 @@ static block_t *EncodeAudio( encoder_t *p_enc,
> block_t *p_aout_buf )
> if( p_sys->i_samples_delay > 0 )
> date_Decrement( &p_sys->buffer_date, p_sys->i_samples_delay
);
> }
> + /* Handle reordering here so we have p_sys->p_buffer always in
correct
> + * order already */
> + if( p_aout_buf && p_sys->i_channels_to_reorder > 0 )
> + {
> + aout_ChannelReorder( p_aout_buf->p_buffer,
p_aout_buf->i_buffer,
> + p_sys->i_channels_to_reorder, p_sys->pi_reorder_layout,
> + p_enc->fmt_in.i_codec );
> + }
With planar audio anyway, does libavcodec not support arbitrary orders?
Why do we need this?
>
> // Check if we have enough samples in delay_buffer and current
> p_aout_buf to fill frame
> // Or if we are cleaning up
--
Rémi Denis-Courmont
Sent from my collocated server
More information about the vlc-devel
mailing list