@ -38,6 +38,7 @@ typedef struct LibopusEncOpts {
float frame_duration ;
int packet_size ;
int max_bandwidth ;
int mapping_family ;
} LibopusEncOpts ;
typedef struct LibopusEncContext {
@ -47,6 +48,7 @@ typedef struct LibopusEncContext {
uint8_t * samples ;
LibopusEncOpts opts ;
AudioFrameQueue afq ;
const uint8_t * encoder_channel_map ;
} LibopusEncContext ;
static const uint8_t opus_coupled_streams [ 8 ] = {
@ -93,13 +95,11 @@ static void libopus_write_header(AVCodecContext *avctx, int stream_count,
bytestream_put_le16 ( & p , 0 ) ; /* Gain of 0dB is recommended. */
/* Channel mapping */
if ( channels > 2 ) {
bytestream_put_byte ( & p , mapping_family ) ;
bytestream_put_byte ( & p , mapping_family ) ;
if ( mapping_family ! = 0 ) {
bytestream_put_byte ( & p , stream_count ) ;
bytestream_put_byte ( & p , coupled_stream_count ) ;
bytestream_put_buffer ( & p , channel_mapping , channels ) ;
} else {
bytestream_put_byte ( & p , 0 ) ;
}
}
@ -157,13 +157,92 @@ static int libopus_configure_encoder(AVCodecContext *avctx, OpusMSEncoder *enc,
return OPUS_OK ;
}
static int libopus_check_max_channels ( AVCodecContext * avctx ,
int max_channels ) {
if ( avctx - > channels > max_channels ) {
av_log ( avctx , AV_LOG_ERROR , " Opus mapping family undefined for %d channels. \n " ,
avctx - > channels ) ;
return AVERROR ( EINVAL ) ;
}
return 0 ;
}
static int libopus_check_vorbis_layout ( AVCodecContext * avctx , int mapping_family ) {
av_assert2 ( avctx - > channels < FF_ARRAY_ELEMS ( ff_vorbis_channel_layouts ) ) ;
if ( ! avctx - > channel_layout ) {
av_log ( avctx , AV_LOG_WARNING ,
" No channel layout specified. Opus encoder will use Vorbis "
" channel layout for %d channels. \n " , avctx - > channels ) ;
} else if ( avctx - > channel_layout ! = ff_vorbis_channel_layouts [ avctx - > channels - 1 ] ) {
char name [ 32 ] ;
av_get_channel_layout_string ( name , sizeof ( name ) , avctx - > channels ,
avctx - > channel_layout ) ;
av_log ( avctx , AV_LOG_ERROR ,
" Invalid channel layout %s for specified mapping family %d. \n " ,
name , mapping_family ) ;
return AVERROR ( EINVAL ) ;
}
return 0 ;
}
static int libopus_validate_layout_and_get_channel_map (
AVCodecContext * avctx ,
int mapping_family ,
const uint8_t * * channel_map_result )
{
const uint8_t * channel_map = NULL ;
int ret ;
switch ( mapping_family ) {
case - 1 :
ret = libopus_check_max_channels ( avctx , 8 ) ;
if ( ret = = 0 ) {
ret = libopus_check_vorbis_layout ( avctx , mapping_family ) ;
/* Channels do not need to be reordered. */
}
break ;
case 0 :
ret = libopus_check_max_channels ( avctx , 2 ) ;
if ( ret = = 0 ) {
ret = libopus_check_vorbis_layout ( avctx , mapping_family ) ;
}
break ;
case 1 :
/* Opus expects channels to be in Vorbis order. */
ret = libopus_check_max_channels ( avctx , 8 ) ;
if ( ret = = 0 ) {
ret = libopus_check_vorbis_layout ( avctx , mapping_family ) ;
channel_map = ff_vorbis_channel_layout_offsets [ avctx - > channels - 1 ] ;
}
break ;
case 255 :
ret = libopus_check_max_channels ( avctx , 254 ) ;
break ;
default :
av_log ( avctx , AV_LOG_WARNING ,
" Unknown channel mapping family %d. Output channel layout may be invalid. \n " ,
mapping_family ) ;
ret = 0 ;
}
* channel_map_result = channel_map ;
return ret ;
}
static av_cold int libopus_encode_init ( AVCodecContext * avctx )
{
LibopusEncContext * opus = avctx - > priv_data ;
OpusMSEncoder * enc ;
uint8_t libopus_channel_mapping [ 255 ] ;
int ret = OPUS_OK ;
int av_ret ;
int coupled_stream_count , header_size , frame_size ;
int mapping_family ;
frame_size = opus - > opts . frame_duration * 48000 / 1000 ;
switch ( frame_size ) {
@ -226,26 +305,40 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
}
}
/* FIXME: Opus can handle up to 255 channels. However, the mapping for
* anything greater than 8 is undefined . */
if ( avctx - > channels > 8 ) {
av_log ( avctx , AV_LOG_ERROR ,
" Channel layout undefined for %d channels. \n " , avctx - > channels ) ;
return AVERROR_PATCHWELCOME ;
/* Channels may need to be reordered to match opus mapping. */
av_ret = libopus_validate_layout_and_get_channel_map ( avctx , opus - > opts . mapping_family ,
& opus - > encoder_channel_map ) ;
if ( av_ret ) {
return av_ret ;
}
coupled_stream_count = opus_coupled_streams [ avctx - > channels - 1 ] ;
opus - > stream_count = avctx - > channels - coupled_stream_count ;
memcpy ( libopus_channel_mapping ,
opus_vorbis_channel_map [ avctx - > channels - 1 ] ,
avctx - > channels * sizeof ( * libopus_channel_mapping ) ) ;
enc = opus_multistream_encoder_create (
avctx - > sample_rate , avctx - > channels , opus - > stream_count ,
coupled_stream_count ,
libavcodec_libopus_channel_map [ avctx - > channels - 1 ] ,
opus - > opts . application , & ret ) ;
if ( opus - > opts . mapping_family = = - 1 ) {
/* By default, use mapping family 1 for the header but use the older
* libopus multistream API to avoid surround masking . */
/* Set the mapping family so that the value is correct in the header */
mapping_family = avctx - > channels > 2 ? 1 : 0 ;
coupled_stream_count = opus_coupled_streams [ avctx - > channels - 1 ] ;
opus - > stream_count = avctx - > channels - coupled_stream_count ;
memcpy ( libopus_channel_mapping ,
opus_vorbis_channel_map [ avctx - > channels - 1 ] ,
avctx - > channels * sizeof ( * libopus_channel_mapping ) ) ;
enc = opus_multistream_encoder_create (
avctx - > sample_rate , avctx - > channels , opus - > stream_count ,
coupled_stream_count ,
libavcodec_libopus_channel_map [ avctx - > channels - 1 ] ,
opus - > opts . application , & ret ) ;
} else {
/* Use the newer multistream API. The encoder will set the channel
* mapping and coupled stream counts to its internal defaults and will
* use surround masking analysis to save bits . */
mapping_family = opus - > opts . mapping_family ;
enc = opus_multistream_surround_encoder_create (
avctx - > sample_rate , avctx - > channels , mapping_family ,
& opus - > stream_count , & coupled_stream_count , libopus_channel_mapping ,
opus - > opts . application , & ret ) ;
}
if ( ret ! = OPUS_OK ) {
av_log ( avctx , AV_LOG_ERROR ,
@ -275,7 +368,8 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
goto fail ;
}
header_size = 19 + ( avctx - > channels > 2 ? 2 + avctx - > channels : 0 ) ;
/* Header includes channel mapping table if and only if mapping family is 0 */
header_size = 19 + ( mapping_family = = 0 ? 0 : 2 + avctx - > channels ) ;
avctx - > extradata = av_malloc ( header_size + AV_INPUT_BUFFER_PADDING_SIZE ) ;
if ( ! avctx - > extradata ) {
av_log ( avctx , AV_LOG_ERROR , " Failed to allocate extradata. \n " ) ;
@ -299,7 +393,7 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
opus_strerror ( ret ) ) ;
libopus_write_header ( avctx , opus - > stream_count , coupled_stream_count ,
avctx - > channels < = 8 ? 1 : 255 , libopus_channel_mapping ) ;
mapping_family , libopus_channel_mapping ) ;
ff_af_queue_init ( avctx , & opus - > afq ) ;
@ -313,6 +407,20 @@ fail:
return ret ;
}
static void libopus_copy_samples_with_channel_map (
uint8_t * dst , const uint8_t * src , const uint8_t * channel_map ,
int nb_channels , int nb_samples , int bytes_per_sample ) {
int sample , channel ;
for ( sample = 0 ; sample < nb_samples ; + + sample ) {
for ( channel = 0 ; channel < nb_channels ; + + channel ) {
const size_t src_pos = bytes_per_sample * ( nb_channels * sample + channel ) ;
const size_t dst_pos = bytes_per_sample * ( nb_channels * sample + channel_map [ channel ] ) ;
memcpy ( & dst [ dst_pos ] , & src [ src_pos ] , bytes_per_sample ) ;
}
}
}
static int libopus_encode ( AVCodecContext * avctx , AVPacket * avpkt ,
const AVFrame * frame , int * got_packet_ptr )
{
@ -327,7 +435,12 @@ static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt,
ret = ff_af_queue_add ( & opus - > afq , frame ) ;
if ( ret < 0 )
return ret ;
if ( frame - > nb_samples < opus - > opts . packet_size ) {
if ( opus - > encoder_channel_map ! = NULL ) {
audio = opus - > samples ;
libopus_copy_samples_with_channel_map (
audio , frame - > data [ 0 ] , opus - > encoder_channel_map ,
avctx - > channels , frame - > nb_samples , bytes_per_sample ) ;
} else if ( frame - > nb_samples < opus - > opts . packet_size ) {
audio = opus - > samples ;
memcpy ( audio , frame - > data [ 0 ] , frame - > nb_samples * sample_size ) ;
} else
@ -416,6 +529,7 @@ static const AVOption libopus_options[] = {
{ " off " , " Use constant bit rate " , 0 , AV_OPT_TYPE_CONST , { . i64 = 0 } , 0 , 0 , FLAGS , " vbr " } ,
{ " on " , " Use variable bit rate " , 0 , AV_OPT_TYPE_CONST , { . i64 = 1 } , 0 , 0 , FLAGS , " vbr " } ,
{ " constrained " , " Use constrained VBR " , 0 , AV_OPT_TYPE_CONST , { . i64 = 2 } , 0 , 0 , FLAGS , " vbr " } ,
{ " mapping_family " , " Channel Mapping Family " , OFFSET ( mapping_family ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 255 , FLAGS , " mapping_family " } ,
{ NULL } ,
} ;
@ -449,7 +563,6 @@ AVCodec ff_libopus_encoder = {
. sample_fmts = ( const enum AVSampleFormat [ ] ) { AV_SAMPLE_FMT_S16 ,
AV_SAMPLE_FMT_FLT ,
AV_SAMPLE_FMT_NONE } ,
. channel_layouts = ff_vorbis_channel_layouts ,
. supported_samplerates = libopus_sample_rates ,
. priv_class = & libopus_class ,
. defaults = libopus_defaults ,