2019-01-18 04:11:38 +02:00
/*
* Scalable Video Technology for AV1 encoder library plugin
*
* Copyright ( c ) 2018 Intel Corporation
*
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* FFmpeg is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include <stdint.h>
# include <EbSvtAv1ErrorCodes.h>
# include <EbSvtAv1Enc.h>
# include "libavutil/common.h"
# include "libavutil/frame.h"
# include "libavutil/imgutils.h"
# include "libavutil/opt.h"
# include "libavutil/pixdesc.h"
# include "libavutil/avassert.h"
2022-03-16 19:18:28 +02:00
# include "codec_internal.h"
2019-01-18 04:11:38 +02:00
# include "internal.h"
# include "encode.h"
# include "packet_internal.h"
# include "avcodec.h"
# include "profiles.h"
typedef enum eos_status {
EOS_NOT_REACHED = 0 ,
EOS_SENT ,
EOS_RECEIVED
} EOS_STATUS ;
typedef struct SvtContext {
const AVClass * class ;
EbSvtAv1EncConfiguration enc_params ;
EbComponentType * svt_handle ;
EbBufferHeaderType * in_buf ;
int raw_size ;
int max_tu_size ;
AVFrame * frame ;
AVBufferPool * pool ;
EOS_STATUS eos_flag ;
// User options.
2022-02-16 15:37:02 +02:00
AVDictionary * svtav1_opts ;
2022-03-13 20:16:29 +02:00
# if FF_API_SVTAV1_OPTS
2019-01-18 04:11:38 +02:00
int hierarchical_level ;
int la_depth ;
int scd ;
int tier ;
int tile_columns ;
int tile_rows ;
2022-03-13 20:16:29 +02:00
# endif
int enc_mode ;
int crf ;
int qp ;
2019-01-18 04:11:38 +02:00
} SvtContext ;
static const struct {
EbErrorType eb_err ;
int av_err ;
const char * desc ;
} svt_errors [ ] = {
{ EB_ErrorNone , 0 , " success " } ,
{ EB_ErrorInsufficientResources , AVERROR ( ENOMEM ) , " insufficient resources " } ,
{ EB_ErrorUndefined , AVERROR ( EINVAL ) , " undefined error " } ,
{ EB_ErrorInvalidComponent , AVERROR ( EINVAL ) , " invalid component " } ,
{ EB_ErrorBadParameter , AVERROR ( EINVAL ) , " bad parameter " } ,
{ EB_ErrorDestroyThreadFailed , AVERROR_EXTERNAL , " failed to destroy thread " } ,
{ EB_ErrorSemaphoreUnresponsive , AVERROR_EXTERNAL , " semaphore unresponsive " } ,
2020-08-01 06:34:29 +02:00
{ EB_ErrorDestroySemaphoreFailed , AVERROR_EXTERNAL , " failed to destroy semaphore " } ,
2019-01-18 04:11:38 +02:00
{ EB_ErrorCreateMutexFailed , AVERROR_EXTERNAL , " failed to create mutex " } ,
{ EB_ErrorMutexUnresponsive , AVERROR_EXTERNAL , " mutex unresponsive " } ,
{ EB_ErrorDestroyMutexFailed , AVERROR_EXTERNAL , " failed to destroy mutex " } ,
{ EB_NoErrorEmptyQueue , AVERROR ( EAGAIN ) , " empty queue " } ,
} ;
static int svt_map_error ( EbErrorType eb_err , const char * * desc )
{
int i ;
av_assert0 ( desc ) ;
for ( i = 0 ; i < FF_ARRAY_ELEMS ( svt_errors ) ; i + + ) {
if ( svt_errors [ i ] . eb_err = = eb_err ) {
* desc = svt_errors [ i ] . desc ;
return svt_errors [ i ] . av_err ;
}
}
* desc = " unknown error " ;
return AVERROR_UNKNOWN ;
}
static int svt_print_error ( void * log_ctx , EbErrorType err ,
const char * error_string )
{
const char * desc ;
int ret = svt_map_error ( err , & desc ) ;
av_log ( log_ctx , AV_LOG_ERROR , " %s: %s (0x%x) \n " , error_string , desc , err ) ;
return ret ;
}
static int alloc_buffer ( EbSvtAv1EncConfiguration * config , SvtContext * svt_enc )
{
2022-10-21 05:55:27 +02:00
const size_t luma_size = config - > source_width * config - > source_height *
( config - > encoder_bit_depth > 8 ? 2 : 1 ) ;
2019-01-18 04:11:38 +02:00
EbSvtIOFormat * in_data ;
2022-10-21 05:55:27 +02:00
svt_enc - > raw_size = luma_size * 3 / 2 ;
2019-01-18 04:11:38 +02:00
// allocate buffer for in and out
svt_enc - > in_buf = av_mallocz ( sizeof ( * svt_enc - > in_buf ) ) ;
if ( ! svt_enc - > in_buf )
return AVERROR ( ENOMEM ) ;
svt_enc - > in_buf - > p_buffer = av_mallocz ( sizeof ( * in_data ) ) ;
if ( ! svt_enc - > in_buf - > p_buffer )
return AVERROR ( ENOMEM ) ;
svt_enc - > in_buf - > size = sizeof ( * svt_enc - > in_buf ) ;
return 0 ;
}
static int config_enc_params ( EbSvtAv1EncConfiguration * param ,
AVCodecContext * avctx )
{
SvtContext * svt_enc = avctx - > priv_data ;
const AVPixFmtDescriptor * desc ;
2022-02-16 15:37:02 +02:00
AVDictionaryEntry * en = NULL ;
// Update param from options
2022-03-13 20:16:29 +02:00
# if FF_API_SVTAV1_OPTS
2022-11-29 23:35:27 +02:00
if ( svt_enc - > hierarchical_level > = 0 )
param - > hierarchical_levels = svt_enc - > hierarchical_level ;
if ( svt_enc - > tier > = 0 )
param - > tier = svt_enc - > tier ;
if ( svt_enc - > scd > = 0 )
param - > scene_change_detection = svt_enc - > scd ;
if ( svt_enc - > tile_columns > = 0 )
param - > tile_columns = svt_enc - > tile_columns ;
if ( svt_enc - > tile_rows > = 0 )
param - > tile_rows = svt_enc - > tile_rows ;
2022-03-13 20:16:29 +02:00
if ( svt_enc - > la_depth > = 0 )
2022-11-29 23:35:27 +02:00
param - > look_ahead_distance = svt_enc - > la_depth ;
2022-03-13 20:16:29 +02:00
# endif
2022-02-25 01:36:46 +02:00
if ( svt_enc - > enc_mode > = 0 )
param - > enc_mode = svt_enc - > enc_mode ;
if ( avctx - > bit_rate ) {
param - > target_bit_rate = avctx - > bit_rate ;
if ( avctx - > rc_max_rate ! = avctx - > bit_rate )
param - > rate_control_mode = 1 ;
else
param - > rate_control_mode = 2 ;
2022-03-28 01:06:51 +02:00
param - > max_qp_allowed = avctx - > qmax ;
param - > min_qp_allowed = avctx - > qmin ;
2022-02-25 01:36:46 +02:00
}
param - > max_bit_rate = avctx - > rc_max_rate ;
2023-03-09 20:27:06 +02:00
if ( ( avctx - > bit_rate > 0 | | avctx - > rc_max_rate > 0 ) & & avctx - > rc_buffer_size )
param - > maximum_buffer_size_ms =
avctx - > rc_buffer_size * 1000LL /
FFMAX ( avctx - > bit_rate , avctx - > rc_max_rate ) ;
2022-02-25 01:36:46 +02:00
if ( svt_enc - > crf > 0 ) {
param - > qp = svt_enc - > crf ;
param - > rate_control_mode = 0 ;
} else if ( svt_enc - > qp > 0 ) {
param - > qp = svt_enc - > qp ;
param - > rate_control_mode = 0 ;
2022-03-13 20:17:40 +02:00
param - > enable_adaptive_quantization = 0 ;
2022-02-25 01:36:46 +02:00
}
2022-02-16 15:37:02 +02:00
2022-03-28 01:06:51 +02:00
desc = av_pix_fmt_desc_get ( avctx - > pix_fmt ) ;
param - > color_primaries = avctx - > color_primaries ;
param - > matrix_coefficients = ( desc - > flags & AV_PIX_FMT_FLAG_RGB ) ?
AVCOL_SPC_RGB : avctx - > colorspace ;
param - > transfer_characteristics = avctx - > color_trc ;
if ( avctx - > color_range ! = AVCOL_RANGE_UNSPECIFIED )
param - > color_range = avctx - > color_range = = AVCOL_RANGE_JPEG ;
else
param - > color_range = ! ! ( desc - > flags & AV_PIX_FMT_FLAG_RGB ) ;
2022-04-25 22:35:17 +02:00
# if SVT_AV1_CHECK_VERSION(1, 0, 0)
if ( avctx - > chroma_sample_location ! = AVCHROMA_LOC_UNSPECIFIED ) {
const char * name =
av_chroma_location_name ( avctx - > chroma_sample_location ) ;
switch ( avctx - > chroma_sample_location ) {
case AVCHROMA_LOC_LEFT :
param - > chroma_sample_position = EB_CSP_VERTICAL ;
break ;
case AVCHROMA_LOC_TOPLEFT :
param - > chroma_sample_position = EB_CSP_COLOCATED ;
break ;
default :
if ( ! name )
break ;
av_log ( avctx , AV_LOG_WARNING ,
" Specified chroma sample location %s is unsupported "
" on the AV1 bit stream level. Usage of a container that "
" allows passing this information - such as Matroska - "
" is recommended. \n " ,
name ) ;
break ;
}
}
# endif
2022-03-28 01:06:51 +02:00
if ( avctx - > profile ! = FF_PROFILE_UNKNOWN )
param - > profile = avctx - > profile ;
if ( avctx - > level ! = FF_LEVEL_UNKNOWN )
param - > level = avctx - > level ;
if ( avctx - > gop_size > 0 )
param - > intra_period_length = avctx - > gop_size - 1 ;
if ( avctx - > framerate . num > 0 & & avctx - > framerate . den > 0 ) {
param - > frame_rate_numerator = avctx - > framerate . num ;
param - > frame_rate_denominator = avctx - > framerate . den ;
} else {
param - > frame_rate_numerator = avctx - > time_base . den ;
param - > frame_rate_denominator = avctx - > time_base . num * avctx - > ticks_per_frame ;
}
/* 2 = IDR, closed GOP, 1 = CRA, open GOP */
param - > intra_refresh_type = avctx - > flags & AV_CODEC_FLAG_CLOSED_GOP ? 2 : 1 ;
2022-02-16 15:37:02 +02:00
# if SVT_AV1_CHECK_VERSION(0, 9, 1)
while ( ( en = av_dict_get ( svt_enc - > svtav1_opts , " " , en , AV_DICT_IGNORE_SUFFIX ) ) ) {
EbErrorType ret = svt_av1_enc_parse_parameter ( param , en - > key , en - > value ) ;
if ( ret ! = EB_ErrorNone ) {
int level = ( avctx - > err_recognition & AV_EF_EXPLODE ) ? AV_LOG_ERROR : AV_LOG_WARNING ;
av_log ( avctx , level , " Error parsing option %s: %s. \n " , en - > key , en - > value ) ;
if ( avctx - > err_recognition & AV_EF_EXPLODE )
return AVERROR ( EINVAL ) ;
}
}
# else
if ( ( en = av_dict_get ( svt_enc - > svtav1_opts , " " , NULL , AV_DICT_IGNORE_SUFFIX ) ) ) {
int level = ( avctx - > err_recognition & AV_EF_EXPLODE ) ? AV_LOG_ERROR : AV_LOG_WARNING ;
av_log ( avctx , level , " svt-params needs libavcodec to be compiled with SVT-AV1 "
" headers >= 0.9.1. \n " ) ;
if ( avctx - > err_recognition & AV_EF_EXPLODE )
return AVERROR ( ENOSYS ) ;
}
# endif
2019-01-18 04:11:38 +02:00
param - > source_width = avctx - > width ;
param - > source_height = avctx - > height ;
param - > encoder_bit_depth = desc - > comp [ 0 ] . depth ;
if ( desc - > log2_chroma_w = = 1 & & desc - > log2_chroma_h = = 1 )
param - > encoder_color_format = EB_YUV420 ;
else if ( desc - > log2_chroma_w = = 1 & & desc - > log2_chroma_h = = 0 )
param - > encoder_color_format = EB_YUV422 ;
else if ( ! desc - > log2_chroma_w & & ! desc - > log2_chroma_h )
param - > encoder_color_format = EB_YUV444 ;
else {
av_log ( avctx , AV_LOG_ERROR , " Unsupported pixel format \n " ) ;
return AVERROR ( EINVAL ) ;
}
if ( ( param - > encoder_color_format = = EB_YUV422 | | param - > encoder_bit_depth > 10 )
& & param - > profile ! = FF_PROFILE_AV1_PROFESSIONAL ) {
av_log ( avctx , AV_LOG_WARNING , " Forcing Professional profile \n " ) ;
param - > profile = FF_PROFILE_AV1_PROFESSIONAL ;
} else if ( param - > encoder_color_format = = EB_YUV444 & & param - > profile ! = FF_PROFILE_AV1_HIGH ) {
av_log ( avctx , AV_LOG_WARNING , " Forcing High profile \n " ) ;
param - > profile = FF_PROFILE_AV1_HIGH ;
}
2022-05-09 20:29:44 +02:00
avctx - > bit_rate = param - > rate_control_mode > 0 ?
param - > target_bit_rate : 0 ;
avctx - > rc_max_rate = param - > max_bit_rate ;
2023-03-09 20:27:06 +02:00
avctx - > rc_buffer_size = param - > maximum_buffer_size_ms *
FFMAX ( avctx - > bit_rate , avctx - > rc_max_rate ) / 1000LL ;
2022-05-09 20:29:44 +02:00
if ( avctx - > bit_rate | | avctx - > rc_max_rate | | avctx - > rc_buffer_size ) {
AVCPBProperties * cpb_props = ff_add_cpb_side_data ( avctx ) ;
if ( ! cpb_props )
return AVERROR ( ENOMEM ) ;
cpb_props - > buffer_size = avctx - > rc_buffer_size ;
cpb_props - > max_bitrate = avctx - > rc_max_rate ;
cpb_props - > avg_bitrate = avctx - > bit_rate ;
}
2019-01-18 04:11:38 +02:00
return 0 ;
}
static int read_in_data ( EbSvtAv1EncConfiguration * param , const AVFrame * frame ,
EbBufferHeaderType * header_ptr )
{
EbSvtIOFormat * in_data = ( EbSvtIOFormat * ) header_ptr - > p_buffer ;
ptrdiff_t linesizes [ 4 ] ;
size_t sizes [ 4 ] ;
int bytes_shift = param - > encoder_bit_depth > 8 ? 1 : 0 ;
int ret , frame_size ;
for ( int i = 0 ; i < 4 ; i + + )
linesizes [ i ] = frame - > linesize [ i ] ;
ret = av_image_fill_plane_sizes ( sizes , frame - > format , frame - > height ,
linesizes ) ;
if ( ret < 0 )
return ret ;
frame_size = 0 ;
for ( int i = 0 ; i < 4 ; i + + ) {
if ( sizes [ i ] > INT_MAX - frame_size )
return AVERROR ( EINVAL ) ;
frame_size + = sizes [ i ] ;
}
in_data - > luma = frame - > data [ 0 ] ;
in_data - > cb = frame - > data [ 1 ] ;
in_data - > cr = frame - > data [ 2 ] ;
in_data - > y_stride = AV_CEIL_RSHIFT ( frame - > linesize [ 0 ] , bytes_shift ) ;
in_data - > cb_stride = AV_CEIL_RSHIFT ( frame - > linesize [ 1 ] , bytes_shift ) ;
in_data - > cr_stride = AV_CEIL_RSHIFT ( frame - > linesize [ 2 ] , bytes_shift ) ;
header_ptr - > n_filled_len = frame_size ;
return 0 ;
}
static av_cold int eb_enc_init ( AVCodecContext * avctx )
{
SvtContext * svt_enc = avctx - > priv_data ;
EbErrorType svt_ret ;
int ret ;
svt_enc - > eos_flag = EOS_NOT_REACHED ;
svt_ret = svt_av1_enc_init_handle ( & svt_enc - > svt_handle , svt_enc , & svt_enc - > enc_params ) ;
if ( svt_ret ! = EB_ErrorNone ) {
return svt_print_error ( avctx , svt_ret , " Error initializing encoder handle " ) ;
}
ret = config_enc_params ( & svt_enc - > enc_params , avctx ) ;
if ( ret < 0 ) {
av_log ( avctx , AV_LOG_ERROR , " Error configuring encoder parameters \n " ) ;
return ret ;
}
svt_ret = svt_av1_enc_set_parameter ( svt_enc - > svt_handle , & svt_enc - > enc_params ) ;
if ( svt_ret ! = EB_ErrorNone ) {
return svt_print_error ( avctx , svt_ret , " Error setting encoder parameters " ) ;
}
svt_ret = svt_av1_enc_init ( svt_enc - > svt_handle ) ;
if ( svt_ret ! = EB_ErrorNone ) {
return svt_print_error ( avctx , svt_ret , " Error initializing encoder " ) ;
}
if ( avctx - > flags & AV_CODEC_FLAG_GLOBAL_HEADER ) {
EbBufferHeaderType * headerPtr = NULL ;
svt_ret = svt_av1_enc_stream_header ( svt_enc - > svt_handle , & headerPtr ) ;
if ( svt_ret ! = EB_ErrorNone ) {
return svt_print_error ( avctx , svt_ret , " Error building stream header " ) ;
}
avctx - > extradata_size = headerPtr - > n_filled_len ;
avctx - > extradata = av_mallocz ( avctx - > extradata_size + AV_INPUT_BUFFER_PADDING_SIZE ) ;
if ( ! avctx - > extradata ) {
av_log ( avctx , AV_LOG_ERROR ,
" Cannot allocate AV1 header of size %d. \n " , avctx - > extradata_size ) ;
return AVERROR ( ENOMEM ) ;
}
memcpy ( avctx - > extradata , headerPtr - > p_buffer , avctx - > extradata_size ) ;
svt_ret = svt_av1_enc_stream_header_release ( headerPtr ) ;
if ( svt_ret ! = EB_ErrorNone ) {
return svt_print_error ( avctx , svt_ret , " Error freeing stream header " ) ;
}
}
svt_enc - > frame = av_frame_alloc ( ) ;
if ( ! svt_enc - > frame )
return AVERROR ( ENOMEM ) ;
return alloc_buffer ( & svt_enc - > enc_params , svt_enc ) ;
}
static int eb_send_frame ( AVCodecContext * avctx , const AVFrame * frame )
{
SvtContext * svt_enc = avctx - > priv_data ;
EbBufferHeaderType * headerPtr = svt_enc - > in_buf ;
int ret ;
if ( ! frame ) {
EbBufferHeaderType headerPtrLast ;
if ( svt_enc - > eos_flag = = EOS_SENT )
return 0 ;
2022-08-22 05:05:02 +02:00
memset ( & headerPtrLast , 0 , sizeof ( headerPtrLast ) ) ;
headerPtrLast . pic_type = EB_AV1_INVALID_PICTURE ;
2019-01-18 04:11:38 +02:00
headerPtrLast . flags = EB_BUFFERFLAG_EOS ;
svt_av1_enc_send_picture ( svt_enc - > svt_handle , & headerPtrLast ) ;
svt_enc - > eos_flag = EOS_SENT ;
return 0 ;
}
ret = read_in_data ( & svt_enc - > enc_params , frame , headerPtr ) ;
if ( ret < 0 )
return ret ;
headerPtr - > flags = 0 ;
headerPtr - > p_app_private = NULL ;
headerPtr - > pts = frame - > pts ;
2022-04-26 00:54:38 +02:00
switch ( frame - > pict_type ) {
case AV_PICTURE_TYPE_I :
headerPtr - > pic_type = EB_AV1_KEY_PICTURE ;
break ;
default :
// Actually means auto, or default.
headerPtr - > pic_type = EB_AV1_INVALID_PICTURE ;
break ;
}
2019-01-18 04:11:38 +02:00
svt_av1_enc_send_picture ( svt_enc - > svt_handle , headerPtr ) ;
return 0 ;
}
static AVBufferRef * get_output_ref ( AVCodecContext * avctx , SvtContext * svt_enc , int filled_len )
{
if ( filled_len > svt_enc - > max_tu_size ) {
const int max_frames = 8 ;
int max_tu_size ;
if ( filled_len > svt_enc - > raw_size * max_frames ) {
av_log ( avctx , AV_LOG_ERROR , " TU size > %d raw frame size. \n " , max_frames ) ;
return NULL ;
}
max_tu_size = 1 < < av_ceil_log2 ( filled_len ) ;
av_buffer_pool_uninit ( & svt_enc - > pool ) ;
svt_enc - > pool = av_buffer_pool_init ( max_tu_size + AV_INPUT_BUFFER_PADDING_SIZE , NULL ) ;
if ( ! svt_enc - > pool )
return NULL ;
svt_enc - > max_tu_size = max_tu_size ;
}
av_assert0 ( svt_enc - > pool ) ;
return av_buffer_pool_get ( svt_enc - > pool ) ;
}
static int eb_receive_packet ( AVCodecContext * avctx , AVPacket * pkt )
{
SvtContext * svt_enc = avctx - > priv_data ;
EbBufferHeaderType * headerPtr ;
AVFrame * frame = svt_enc - > frame ;
EbErrorType svt_ret ;
AVBufferRef * ref ;
int ret = 0 , pict_type ;
if ( svt_enc - > eos_flag = = EOS_RECEIVED )
return AVERROR_EOF ;
ret = ff_encode_get_frame ( avctx , frame ) ;
if ( ret < 0 & & ret ! = AVERROR_EOF )
return ret ;
if ( ret = = AVERROR_EOF )
frame = NULL ;
ret = eb_send_frame ( avctx , frame ) ;
if ( ret < 0 )
return ret ;
av_frame_unref ( svt_enc - > frame ) ;
svt_ret = svt_av1_enc_get_packet ( svt_enc - > svt_handle , & headerPtr , svt_enc - > eos_flag ) ;
if ( svt_ret = = EB_NoErrorEmptyQueue )
return AVERROR ( EAGAIN ) ;
ref = get_output_ref ( avctx , svt_enc , headerPtr - > n_filled_len ) ;
if ( ! ref ) {
av_log ( avctx , AV_LOG_ERROR , " Failed to allocate output packet. \n " ) ;
svt_av1_enc_release_out_buffer ( & headerPtr ) ;
return AVERROR ( ENOMEM ) ;
}
pkt - > buf = ref ;
pkt - > data = ref - > data ;
memcpy ( pkt - > data , headerPtr - > p_buffer , headerPtr - > n_filled_len ) ;
memset ( pkt - > data + headerPtr - > n_filled_len , 0 , AV_INPUT_BUFFER_PADDING_SIZE ) ;
pkt - > size = headerPtr - > n_filled_len ;
pkt - > pts = headerPtr - > pts ;
pkt - > dts = headerPtr - > dts ;
switch ( headerPtr - > pic_type ) {
case EB_AV1_KEY_PICTURE :
pkt - > flags | = AV_PKT_FLAG_KEY ;
// fall-through
case EB_AV1_INTRA_ONLY_PICTURE :
pict_type = AV_PICTURE_TYPE_I ;
break ;
case EB_AV1_INVALID_PICTURE :
pict_type = AV_PICTURE_TYPE_NONE ;
break ;
default :
pict_type = AV_PICTURE_TYPE_P ;
break ;
}
if ( headerPtr - > pic_type = = EB_AV1_NON_REF_PICTURE )
pkt - > flags | = AV_PKT_FLAG_DISPOSABLE ;
if ( headerPtr - > flags & EB_BUFFERFLAG_EOS )
svt_enc - > eos_flag = EOS_RECEIVED ;
ff_side_data_set_encoder_stats ( pkt , headerPtr - > qp * FF_QP2LAMBDA , NULL , 0 , pict_type ) ;
svt_av1_enc_release_out_buffer ( & headerPtr ) ;
return 0 ;
}
static av_cold int eb_enc_close ( AVCodecContext * avctx )
{
SvtContext * svt_enc = avctx - > priv_data ;
if ( svt_enc - > svt_handle ) {
svt_av1_enc_deinit ( svt_enc - > svt_handle ) ;
svt_av1_enc_deinit_handle ( svt_enc - > svt_handle ) ;
}
if ( svt_enc - > in_buf ) {
av_free ( svt_enc - > in_buf - > p_buffer ) ;
av_freep ( & svt_enc - > in_buf ) ;
}
av_buffer_pool_uninit ( & svt_enc - > pool ) ;
av_frame_free ( & svt_enc - > frame ) ;
return 0 ;
}
# define OFFSET(x) offsetof(SvtContext, x)
# define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options [ ] = {
2022-03-13 20:16:29 +02:00
# if FF_API_SVTAV1_OPTS
{ " hielevel " , " Hierarchical prediction levels setting (Deprecated, use svtav1-params) " , OFFSET ( hierarchical_level ) ,
2022-11-29 23:35:27 +02:00
AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 4 , VE | AV_OPT_FLAG_DEPRECATED , " hielevel " } ,
2019-01-18 04:11:38 +02:00
{ " 3level " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 3 } , INT_MIN , INT_MAX , VE , " hielevel " } ,
{ " 4level " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 4 } , INT_MIN , INT_MAX , VE , " hielevel " } ,
2022-03-13 20:16:29 +02:00
{ " la_depth " , " Look ahead distance [0, 120] (Deprecated, use svtav1-params) " , OFFSET ( la_depth ) ,
AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 120 , VE | AV_OPT_FLAG_DEPRECATED } ,
2019-01-18 04:11:38 +02:00
2022-03-13 20:16:29 +02:00
{ " tier " , " Set operating point tier (Deprecated, use svtav1-params) " , OFFSET ( tier ) ,
2022-11-29 23:35:27 +02:00
AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 1 , VE | AV_OPT_FLAG_DEPRECATED , " tier " } ,
2019-01-18 04:11:38 +02:00
{ " main " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 0 } , 0 , 0 , VE , " tier " } ,
{ " high " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 1 } , 0 , 0 , VE , " tier " } ,
2022-03-13 20:16:29 +02:00
# endif
{ " preset " , " Encoding preset " ,
OFFSET ( enc_mode ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , MAX_ENC_PRESET , VE } ,
2019-01-18 04:11:38 +02:00
FF_AV1_PROFILE_OPTS
# define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
{ . i64 = value } , 0 , 0 , VE , " avctx.level "
{ LEVEL ( " 2.0 " , 20 ) } ,
{ LEVEL ( " 2.1 " , 21 ) } ,
{ LEVEL ( " 2.2 " , 22 ) } ,
{ LEVEL ( " 2.3 " , 23 ) } ,
{ LEVEL ( " 3.0 " , 30 ) } ,
{ LEVEL ( " 3.1 " , 31 ) } ,
{ LEVEL ( " 3.2 " , 32 ) } ,
{ LEVEL ( " 3.3 " , 33 ) } ,
{ LEVEL ( " 4.0 " , 40 ) } ,
{ LEVEL ( " 4.1 " , 41 ) } ,
{ LEVEL ( " 4.2 " , 42 ) } ,
{ LEVEL ( " 4.3 " , 43 ) } ,
{ LEVEL ( " 5.0 " , 50 ) } ,
{ LEVEL ( " 5.1 " , 51 ) } ,
{ LEVEL ( " 5.2 " , 52 ) } ,
{ LEVEL ( " 5.3 " , 53 ) } ,
{ LEVEL ( " 6.0 " , 60 ) } ,
{ LEVEL ( " 6.1 " , 61 ) } ,
{ LEVEL ( " 6.2 " , 62 ) } ,
{ LEVEL ( " 6.3 " , 63 ) } ,
{ LEVEL ( " 7.0 " , 70 ) } ,
{ LEVEL ( " 7.1 " , 71 ) } ,
{ LEVEL ( " 7.2 " , 72 ) } ,
{ LEVEL ( " 7.3 " , 73 ) } ,
# undef LEVEL
2022-02-25 01:36:46 +02:00
{ " crf " , " Constant Rate Factor value " , OFFSET ( crf ) ,
AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , 63 , VE } ,
{ " qp " , " Initial Quantizer level value " , OFFSET ( qp ) ,
AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , 63 , VE } ,
2022-03-13 20:16:29 +02:00
# if FF_API_SVTAV1_OPTS
{ " sc_detection " , " Scene change detection (Deprecated, use svtav1-params) " , OFFSET ( scd ) ,
2022-11-29 23:35:27 +02:00
AV_OPT_TYPE_BOOL , { . i64 = - 1 } , - 1 , 1 , VE | AV_OPT_FLAG_DEPRECATED } ,
2019-01-18 04:11:38 +02:00
2022-11-29 23:35:27 +02:00
{ " tile_columns " , " Log2 of number of tile columns to use (Deprecated, use svtav1-params) " , OFFSET ( tile_columns ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 4 , VE | AV_OPT_FLAG_DEPRECATED } ,
{ " tile_rows " , " Log2 of number of tile rows to use (Deprecated, use svtav1-params) " , OFFSET ( tile_rows ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 6 , VE | AV_OPT_FLAG_DEPRECATED } ,
2022-03-13 20:16:29 +02:00
# endif
2019-01-18 04:11:38 +02:00
2022-02-16 15:37:02 +02:00
{ " svtav1-params " , " Set the SVT-AV1 configuration using a :-separated list of key=value parameters " , OFFSET ( svtav1_opts ) , AV_OPT_TYPE_DICT , { 0 } , 0 , 0 , VE } ,
2019-01-18 04:11:38 +02:00
{ NULL } ,
} ;
static const AVClass class = {
2020-07-30 23:31:58 +02:00
. class_name = " libsvtav1 " ,
2019-01-18 04:11:38 +02:00
. item_name = av_default_item_name ,
. option = options ,
. version = LIBAVUTIL_VERSION_INT ,
} ;
2022-03-16 22:26:11 +02:00
static const FFCodecDefault eb_enc_defaults [ ] = {
2022-02-25 01:36:46 +02:00
{ " b " , " 0 " } ,
2021-09-17 04:02:02 +02:00
{ " flags " , " +cgop " } ,
2019-01-18 04:11:38 +02:00
{ " g " , " -1 " } ,
2022-02-25 01:36:46 +02:00
{ " qmin " , " 1 " } ,
2019-01-18 04:11:38 +02:00
{ " qmax " , " 63 " } ,
{ NULL } ,
} ;
2022-03-16 22:09:54 +02:00
const FFCodec ff_libsvtav1_encoder = {
. p . name = " libsvtav1 " ,
2022-08-29 13:38:02 +02:00
CODEC_LONG_NAME ( " SVT-AV1(Scalable Video Technology for AV1) encoder " ) ,
2019-01-18 04:11:38 +02:00
. priv_data_size = sizeof ( SvtContext ) ,
2022-03-16 22:09:54 +02:00
. p . type = AVMEDIA_TYPE_VIDEO ,
. p . id = AV_CODEC_ID_AV1 ,
2019-01-18 04:11:38 +02:00
. init = eb_enc_init ,
2022-03-30 23:28:24 +02:00
FF_CODEC_RECEIVE_PACKET_CB ( eb_receive_packet ) ,
2019-01-18 04:11:38 +02:00
. close = eb_enc_close ,
2022-03-16 22:09:54 +02:00
. p . capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS ,
2022-07-09 22:25:41 +02:00
. caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP ,
2022-03-16 22:09:54 +02:00
. p . pix_fmts = ( const enum AVPixelFormat [ ] ) { AV_PIX_FMT_YUV420P ,
2019-01-18 04:11:38 +02:00
AV_PIX_FMT_YUV420P10 ,
AV_PIX_FMT_NONE } ,
2022-03-16 22:09:54 +02:00
. p . priv_class = & class ,
2019-01-18 04:11:38 +02:00
. defaults = eb_enc_defaults ,
2022-03-16 22:09:54 +02:00
. p . wrapper_name = " libsvtav1 " ,
2019-01-18 04:11:38 +02:00
} ;