2010-06-03 23:47:59 +03:00
/*
* Copyright ( c ) 2010 , Google , Inc .
*
* 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 FFmpeg ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
/**
* @ file
2016-07-21 05:41:55 +02:00
* VP8 / 9 encoder support via libvpx
2010-06-03 23:47:59 +03:00
*/
2022-02-23 14:56:49 +02:00
# include "config_components.h"
2010-06-03 23:47:59 +03:00
# define VPX_DISABLE_CTRL_TYPECHECKS 1
# define VPX_CODEC_DISABLE_COMPAT 1
# include <vpx/vpx_encoder.h>
# include <vpx/vp8cx.h>
# include "avcodec.h"
2022-03-16 19:18:28 +02:00
# include "codec_internal.h"
2021-04-25 01:43:26 +02:00
# include "encode.h"
2012-07-25 22:35:48 +03:00
# include "libavutil/avassert.h"
2024-03-25 02:30:37 +02:00
# include "libavutil/mem.h"
2013-11-16 01:28:30 +03:00
# include "libvpx.h"
2020-06-02 23:38:33 +02:00
# include "packet_internal.h"
2016-01-01 17:25:01 +02:00
# include "profiles.h"
2018-11-14 22:56:31 +02:00
# include "libavutil/avstring.h"
2010-06-03 23:47:59 +03:00
# include "libavutil/base64.h"
2012-08-06 16:49:32 +03:00
# include "libavutil/common.h"
2021-06-12 22:10:11 +02:00
# include "libavutil/cpu.h"
2022-05-09 22:30:11 +02:00
# include "libavutil/fifo.h"
2015-12-16 21:48:45 +02:00
# include "libavutil/internal.h"
2013-05-09 02:59:33 +03:00
# include "libavutil/intreadwrite.h"
2011-07-04 09:44:49 +03:00
# include "libavutil/mathematics.h"
2011-09-26 11:22:38 +03:00
# include "libavutil/opt.h"
2020-07-20 19:43:47 +02:00
# include "libavutil/pixdesc.h"
2010-06-03 23:47:59 +03:00
2024-03-26 18:31:06 +02:00
# define IS_VP9(avctx) (CONFIG_LIBVPX_VP9_ENCODER && avctx->codec_id == AV_CODEC_ID_VP9)
# define IS_VP8(avctx) (CONFIG_LIBVPX_VP8_ENCODER && avctx->codec_id == AV_CODEC_ID_VP8)
2010-06-03 23:47:59 +03:00
/**
* Portion of struct vpx_codec_cx_pkt from vpx_encoder . h .
* One encoded frame returned from the library .
*/
struct FrameListData {
2010-08-02 10:25:25 +03:00
void * buf ; /**< compressed data buffer */
size_t sz ; /**< length of compressed data */
int64_t pts ; /**< time stamp to show frame
2010-06-03 23:47:59 +03:00
( in timebase units ) */
2010-08-02 10:25:25 +03:00
uint32_t flags ; /**< flags for this frame */
2013-03-01 01:14:46 +03:00
uint64_t sse [ 4 ] ;
int have_sse ; /**< true if we have pending sse[] */
2010-06-03 23:47:59 +03:00
struct FrameListData * next ;
} ;
2023-02-28 12:39:36 +02:00
typedef struct FrameData {
2021-06-18 07:20:44 +02:00
int64_t pts ;
2023-02-28 13:20:39 +02:00
int64_t duration ;
void * frame_opaque ;
AVBufferRef * frame_opaque_ref ;
2021-06-18 07:20:44 +02:00
AVBufferRef * hdr10_plus ;
2023-02-28 12:39:36 +02:00
} FrameData ;
2021-06-18 07:20:44 +02:00
2016-07-21 05:41:55 +02:00
typedef struct VPxEncoderContext {
2011-10-02 21:38:38 +03:00
AVClass * class ;
2010-06-03 23:47:59 +03:00
struct vpx_codec_ctx encoder ;
struct vpx_image rawimg ;
2013-05-09 02:59:33 +03:00
struct vpx_codec_ctx encoder_alpha ;
struct vpx_image rawimg_alpha ;
uint8_t is_alpha ;
2010-06-03 23:47:59 +03:00
struct vpx_fixed_buf twopass_stats ;
2022-08-24 01:20:10 +02:00
unsigned twopass_stats_size ;
2011-05-26 21:20:36 +03:00
int deadline ; //i.e., RT/GOOD/BEST
2013-03-01 01:14:46 +03:00
uint64_t sse [ 4 ] ;
int have_sse ; /**< true if we have pending sse[] */
2010-06-03 23:47:59 +03:00
struct FrameListData * coded_frame_list ;
2022-08-21 18:08:04 +02:00
struct FrameListData * alpha_coded_frame_list ;
2011-05-26 21:20:36 +03:00
2011-10-02 21:38:38 +03:00
int cpu_used ;
2018-12-21 20:36:03 +02:00
int sharpness ;
2012-01-06 01:24:26 +03:00
/**
* VP8 specific flags , see VP8F_ * below .
*/
int flags ;
# define VP8F_ERROR_RESILIENT 0x00000001 ///< Enable measures appropriate for streaming over lossy links
# define VP8F_AUTO_ALT_REF 0x00000002 ///< Enable automatic alternate reference frame generation
2011-10-04 04:01:06 +03:00
int auto_alt_ref ;
2011-05-26 21:20:36 +03:00
int arnr_max_frames ;
int arnr_strength ;
int arnr_type ;
2011-09-08 05:14:33 +03:00
2015-12-17 05:53:14 +02:00
int tune ;
2011-10-02 21:38:38 +03:00
int lag_in_frames ;
2011-10-04 04:01:06 +03:00
int error_resilient ;
2011-09-08 05:14:37 +03:00
int crf ;
2014-10-08 13:49:11 +03:00
int static_thresh ;
2012-06-10 00:40:51 +03:00
int max_intra_rate ;
2015-06-06 19:10:56 +02:00
int rc_undershoot_pct ;
2015-06-06 19:24:44 +02:00
int rc_overshoot_pct ;
2013-11-03 02:20:19 +03:00
2020-02-03 20:02:01 +02:00
AVDictionary * vpx_ts_parameters ;
int * ts_layer_flags ;
int current_temporal_idx ;
2018-11-14 22:56:31 +02:00
2024-02-13 08:34:08 +02:00
// VP8-only
int screen_content_mode ;
2013-11-03 02:20:19 +03:00
// VP9-only
int lossless ;
int tile_columns ;
int tile_rows ;
int frame_parallel ;
2014-08-26 03:17:39 +03:00
int aq_mode ;
2015-09-11 03:30:38 +02:00
int drop_threshold ;
2015-09-13 23:45:24 +02:00
int noise_sensitivity ;
2016-02-19 22:06:26 +02:00
int vpx_cs ;
2016-11-18 23:55:45 +02:00
float level ;
2017-03-02 20:19:09 +02:00
int row_mt ;
2017-11-14 01:19:07 +02:00
int tune_content ;
2017-11-21 03:32:23 +02:00
int corpus_complexity ;
2018-11-03 22:30:34 +02:00
int tpl_model ;
2022-09-14 02:23:53 +02:00
int min_gf_interval ;
2023-02-28 12:39:36 +02:00
// This FIFO is used to propagate various properties from frames to packets.
AVFifo * fifo ;
2019-09-12 12:25:21 +02:00
/**
* If the driver does not support ROI then warn the first time we
* encounter a frame with ROI side data .
*/
int roi_warned ;
2021-01-09 01:33:29 +02:00
# if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_CTRL_VP9E_SET_MAX_INTER_BITRATE_PCT)
vpx_svc_ref_frame_config_t ref_frame_config ;
# endif
2016-07-21 05:41:55 +02:00
} VPxContext ;
2010-06-03 23:47:59 +03:00
/** String mappings for enum vp8e_enc_control_id */
2012-02-20 11:42:33 +03:00
static const char * const ctlidstr [ ] = {
2010-06-03 23:47:59 +03:00
[ VP8E_SET_CPUUSED ] = " VP8E_SET_CPUUSED " ,
[ VP8E_SET_ENABLEAUTOALTREF ] = " VP8E_SET_ENABLEAUTOALTREF " ,
[ VP8E_SET_NOISE_SENSITIVITY ] = " VP8E_SET_NOISE_SENSITIVITY " ,
[ VP8E_SET_STATIC_THRESHOLD ] = " VP8E_SET_STATIC_THRESHOLD " ,
[ VP8E_SET_TOKEN_PARTITIONS ] = " VP8E_SET_TOKEN_PARTITIONS " ,
[ VP8E_SET_ARNR_MAXFRAMES ] = " VP8E_SET_ARNR_MAXFRAMES " ,
[ VP8E_SET_ARNR_STRENGTH ] = " VP8E_SET_ARNR_STRENGTH " ,
[ VP8E_SET_ARNR_TYPE ] = " VP8E_SET_ARNR_TYPE " ,
2015-12-17 05:53:14 +02:00
[ VP8E_SET_TUNING ] = " VP8E_SET_TUNING " ,
2011-04-12 03:00:35 +03:00
[ VP8E_SET_CQ_LEVEL ] = " VP8E_SET_CQ_LEVEL " ,
2012-06-10 00:40:51 +03:00
[ VP8E_SET_MAX_INTRA_BITRATE_PCT ] = " VP8E_SET_MAX_INTRA_BITRATE_PCT " ,
2018-12-21 20:36:03 +02:00
[ VP8E_SET_SHARPNESS ] = " VP8E_SET_SHARPNESS " ,
2020-02-03 20:02:01 +02:00
[ VP8E_SET_TEMPORAL_LAYER_ID ] = " VP8E_SET_TEMPORAL_LAYER_ID " ,
2024-02-13 08:34:08 +02:00
[ VP8E_SET_SCREEN_CONTENT_MODE ] = " VP8E_SET_SCREEN_CONTENT_MODE " ,
2013-11-03 02:20:19 +03:00
# if CONFIG_LIBVPX_VP9_ENCODER
[ VP9E_SET_LOSSLESS ] = " VP9E_SET_LOSSLESS " ,
[ VP9E_SET_TILE_COLUMNS ] = " VP9E_SET_TILE_COLUMNS " ,
[ VP9E_SET_TILE_ROWS ] = " VP9E_SET_TILE_ROWS " ,
[ VP9E_SET_FRAME_PARALLEL_DECODING ] = " VP9E_SET_FRAME_PARALLEL_DECODING " ,
2014-08-26 03:17:39 +03:00
[ VP9E_SET_AQ_MODE ] = " VP9E_SET_AQ_MODE " ,
2015-06-13 21:27:48 +02:00
[ VP9E_SET_COLOR_SPACE ] = " VP9E_SET_COLOR_SPACE " ,
2020-02-03 20:02:01 +02:00
[ VP9E_SET_SVC_LAYER_ID ] = " VP9E_SET_SVC_LAYER_ID " ,
# if VPX_ENCODER_ABI_VERSION >= 12
[ VP9E_SET_SVC_PARAMETERS ] = " VP9E_SET_SVC_PARAMETERS " ,
2021-01-09 01:33:29 +02:00
[ VP9E_SET_SVC_REF_FRAME_CONFIG ] = " VP9E_SET_SVC_REF_FRAME_CONFIG " ,
2020-02-03 20:02:01 +02:00
# endif
[ VP9E_SET_SVC ] = " VP9E_SET_SVC " ,
2016-01-09 17:48:49 +02:00
# if VPX_ENCODER_ABI_VERSION >= 11
[ VP9E_SET_COLOR_RANGE ] = " VP9E_SET_COLOR_RANGE " ,
# endif
2016-11-18 23:55:45 +02:00
# if VPX_ENCODER_ABI_VERSION >= 12
[ VP9E_SET_TARGET_LEVEL ] = " VP9E_SET_TARGET_LEVEL " ,
2016-11-18 23:56:32 +02:00
[ VP9E_GET_LEVEL ] = " VP9E_GET_LEVEL " ,
2016-11-18 23:55:45 +02:00
# endif
2017-03-02 20:19:09 +02:00
# ifdef VPX_CTRL_VP9E_SET_ROW_MT
[ VP9E_SET_ROW_MT ] = " VP9E_SET_ROW_MT " ,
# endif
2017-11-14 01:19:07 +02:00
# ifdef VPX_CTRL_VP9E_SET_TUNE_CONTENT
[ VP9E_SET_TUNE_CONTENT ] = " VP9E_SET_TUNE_CONTENT " ,
# endif
2018-11-03 22:30:34 +02:00
# ifdef VPX_CTRL_VP9E_SET_TPL
[ VP9E_SET_TPL ] = " VP9E_SET_TPL " ,
# endif
2022-09-14 02:23:53 +02:00
# ifdef VPX_CTRL_VP9E_SET_MIN_GF_INTERVAL
[ VP9E_SET_MIN_GF_INTERVAL ] = " VP9E_SET_MIN_GF_INTERVAL " ,
# endif
2013-11-03 02:20:19 +03:00
# endif
2010-06-03 23:47:59 +03:00
} ;
static av_cold void log_encoder_error ( AVCodecContext * avctx , const char * desc )
{
2016-07-21 05:41:55 +02:00
VPxContext * ctx = avctx - > priv_data ;
2010-06-03 23:47:59 +03:00
const char * error = vpx_codec_error ( & ctx - > encoder ) ;
const char * detail = vpx_codec_error_detail ( & ctx - > encoder ) ;
av_log ( avctx , AV_LOG_ERROR , " %s: %s \n " , desc , error ) ;
if ( detail )
av_log ( avctx , AV_LOG_ERROR , " Additional information: %s \n " , detail ) ;
}
static av_cold void dump_enc_cfg ( AVCodecContext * avctx ,
2021-06-14 20:20:52 +02:00
const struct vpx_codec_enc_cfg * cfg ,
int level )
2010-06-03 23:47:59 +03:00
{
int width = - 30 ;
2018-11-14 22:56:31 +02:00
int i ;
2010-06-03 23:47:59 +03:00
av_log ( avctx , level , " vpx_codec_enc_cfg \n " ) ;
av_log ( avctx , level , " generic settings \n "
" %*s%u \n %*s%u \n %*s%u \n %*s%u \n %*s%u \n "
2017-11-18 03:25:40 +02:00
# if CONFIG_LIBVPX_VP9_ENCODER
2015-03-26 02:10:16 +02:00
" %*s%u \n %*s%u \n "
# endif
2010-06-03 23:47:59 +03:00
" %*s{%u/%u} \n %*s%u \n %*s%d \n %*s%u \n " ,
width , " g_usage: " , cfg - > g_usage ,
width , " g_threads: " , cfg - > g_threads ,
width , " g_profile: " , cfg - > g_profile ,
width , " g_w: " , cfg - > g_w ,
width , " g_h: " , cfg - > g_h ,
2017-11-18 03:25:40 +02:00
# if CONFIG_LIBVPX_VP9_ENCODER
2015-03-26 02:10:16 +02:00
width , " g_bit_depth: " , cfg - > g_bit_depth ,
width , " g_input_bit_depth: " , cfg - > g_input_bit_depth ,
# endif
2010-06-03 23:47:59 +03:00
width , " g_timebase: " , cfg - > g_timebase . num , cfg - > g_timebase . den ,
width , " g_error_resilient: " , cfg - > g_error_resilient ,
width , " g_pass: " , cfg - > g_pass ,
width , " g_lag_in_frames: " , cfg - > g_lag_in_frames ) ;
av_log ( avctx , level , " rate control settings \n "
" %*s%u \n %*s%u \n %*s%u \n %*s%u \n "
2014-04-24 19:01:30 +03:00
" %*s%d \n %*s%p(% " SIZE_SPECIFIER " ) \n %*s%u \n " ,
2010-06-03 23:47:59 +03:00
width , " rc_dropframe_thresh: " , cfg - > rc_dropframe_thresh ,
width , " rc_resize_allowed: " , cfg - > rc_resize_allowed ,
width , " rc_resize_up_thresh: " , cfg - > rc_resize_up_thresh ,
width , " rc_resize_down_thresh: " , cfg - > rc_resize_down_thresh ,
width , " rc_end_usage: " , cfg - > rc_end_usage ,
width , " rc_twopass_stats_in: " , cfg - > rc_twopass_stats_in . buf , cfg - > rc_twopass_stats_in . sz ,
width , " rc_target_bitrate: " , cfg - > rc_target_bitrate ) ;
av_log ( avctx , level , " quantizer settings \n "
" %*s%u \n %*s%u \n " ,
width , " rc_min_quantizer: " , cfg - > rc_min_quantizer ,
width , " rc_max_quantizer: " , cfg - > rc_max_quantizer ) ;
av_log ( avctx , level , " bitrate tolerance \n "
" %*s%u \n %*s%u \n " ,
width , " rc_undershoot_pct: " , cfg - > rc_undershoot_pct ,
width , " rc_overshoot_pct: " , cfg - > rc_overshoot_pct ) ;
2018-11-14 22:56:31 +02:00
av_log ( avctx , level , " temporal layering settings \n "
" %*s%u \n " , width , " ts_number_layers: " , cfg - > ts_number_layers ) ;
2020-02-03 20:02:01 +02:00
if ( avctx - > codec_id = = AV_CODEC_ID_VP8 ) {
av_log ( avctx , level ,
" \n %*s " , width , " ts_target_bitrate: " ) ;
for ( i = 0 ; i < VPX_TS_MAX_LAYERS ; i + + )
av_log ( avctx , level ,
" %u " , cfg - > ts_target_bitrate [ i ] ) ;
}
# if (VPX_ENCODER_ABI_VERSION >= 12) && CONFIG_LIBVPX_VP9_ENCODER
if ( avctx - > codec_id = = AV_CODEC_ID_VP9 ) {
av_log ( avctx , level ,
" \n %*s " , width , " layer_target_bitrate: " ) ;
for ( i = 0 ; i < VPX_TS_MAX_LAYERS ; i + + )
av_log ( avctx , level ,
" %u " , cfg - > layer_target_bitrate [ i ] ) ;
}
# endif
2018-11-14 22:56:31 +02:00
av_log ( avctx , level , " \n " ) ;
av_log ( avctx , level ,
" \n %*s " , width , " ts_rate_decimator: " ) ;
for ( i = 0 ; i < VPX_TS_MAX_LAYERS ; i + + )
av_log ( avctx , level , " %u " , cfg - > ts_rate_decimator [ i ] ) ;
av_log ( avctx , level , " \n " ) ;
av_log ( avctx , level ,
" \n %*s%u \n " , width , " ts_periodicity: " , cfg - > ts_periodicity ) ;
av_log ( avctx , level ,
" \n %*s " , width , " ts_layer_id: " ) ;
for ( i = 0 ; i < VPX_TS_MAX_PERIODICITY ; i + + )
av_log ( avctx , level , " %u " , cfg - > ts_layer_id [ i ] ) ;
av_log ( avctx , level , " \n " ) ;
2010-06-03 23:47:59 +03:00
av_log ( avctx , level , " decoder buffer model \n "
" %*s%u \n %*s%u \n %*s%u \n " ,
width , " rc_buf_sz: " , cfg - > rc_buf_sz ,
width , " rc_buf_initial_sz: " , cfg - > rc_buf_initial_sz ,
width , " rc_buf_optimal_sz: " , cfg - > rc_buf_optimal_sz ) ;
av_log ( avctx , level , " 2 pass rate control settings \n "
" %*s%u \n %*s%u \n %*s%u \n " ,
width , " rc_2pass_vbr_bias_pct: " , cfg - > rc_2pass_vbr_bias_pct ,
width , " rc_2pass_vbr_minsection_pct: " , cfg - > rc_2pass_vbr_minsection_pct ,
width , " rc_2pass_vbr_maxsection_pct: " , cfg - > rc_2pass_vbr_maxsection_pct ) ;
2017-11-21 03:32:23 +02:00
# if VPX_ENCODER_ABI_VERSION >= 14
av_log ( avctx , level , " %*s%u \n " ,
width , " rc_2pass_vbr_corpus_complexity: " , cfg - > rc_2pass_vbr_corpus_complexity ) ;
# endif
2010-06-03 23:47:59 +03:00
av_log ( avctx , level , " keyframing settings \n "
" %*s%d \n %*s%u \n %*s%u \n " ,
width , " kf_mode: " , cfg - > kf_mode ,
width , " kf_min_dist: " , cfg - > kf_min_dist ,
width , " kf_max_dist: " , cfg - > kf_max_dist ) ;
av_log ( avctx , level , " \n " ) ;
}
static void coded_frame_add ( void * list , struct FrameListData * cx_frame )
{
struct FrameListData * * p = list ;
2014-08-14 23:31:25 +03:00
while ( * p )
2010-06-03 23:47:59 +03:00
p = & ( * p ) - > next ;
* p = cx_frame ;
cx_frame - > next = NULL ;
}
static av_cold void free_coded_frame ( struct FrameListData * cx_frame )
{
av_freep ( & cx_frame - > buf ) ;
av_freep ( & cx_frame ) ;
}
static av_cold void free_frame_list ( struct FrameListData * list )
{
struct FrameListData * p = list ;
while ( p ) {
list = list - > next ;
free_coded_frame ( p ) ;
p = list ;
}
}
2023-02-28 13:20:39 +02:00
static void frame_data_uninit ( FrameData * fd )
{
av_buffer_unref ( & fd - > frame_opaque_ref ) ;
av_buffer_unref ( & fd - > hdr10_plus ) ;
}
2023-02-28 12:39:36 +02:00
static av_cold void fifo_free ( AVFifo * * fifo )
2021-06-18 07:20:44 +02:00
{
2023-02-28 12:39:36 +02:00
FrameData fd ;
while ( av_fifo_read ( * fifo , & fd , 1 ) > = 0 )
2023-02-28 13:20:39 +02:00
frame_data_uninit ( & fd ) ;
2022-01-06 17:46:13 +02:00
av_fifo_freep2 ( fifo ) ;
2021-06-18 07:20:44 +02:00
}
2023-02-28 13:20:39 +02:00
static int frame_data_submit ( AVCodecContext * avctx , AVFifo * fifo ,
const AVFrame * frame )
{
VPxContext * ctx = avctx - > priv_data ;
const struct vpx_codec_enc_cfg * enccfg = ctx - > encoder . config . enc ;
FrameData fd = { . pts = frame - > pts } ;
int ret ;
2024-03-26 18:31:06 +02:00
if ( IS_VP9 ( avctx ) & &
2024-03-26 17:26:13 +02:00
// Keep HDR10+ if it has bit depth higher than 8 and
// it has PQ trc (SMPTE2084).
2023-02-28 13:20:39 +02:00
enccfg - > g_bit_depth > 8 & & avctx - > color_trc = = AVCOL_TRC_SMPTE2084 ) {
2024-03-26 17:26:13 +02:00
const AVFrameSideData * sd = av_frame_get_side_data ( frame , AV_FRAME_DATA_DYNAMIC_HDR_PLUS ) ;
if ( sd ) {
fd . hdr10_plus = av_buffer_ref ( sd - > buf ) ;
if ( ! fd . hdr10_plus )
return AVERROR ( ENOMEM ) ;
}
2023-02-28 13:20:39 +02:00
}
fd . duration = frame - > duration ;
fd . frame_opaque = frame - > opaque ;
if ( avctx - > flags & AV_CODEC_FLAG_COPY_OPAQUE & & frame - > opaque_ref ) {
ret = av_buffer_replace ( & fd . frame_opaque_ref , frame - > opaque_ref ) ;
if ( ret < 0 )
goto fail ;
}
ret = av_fifo_write ( fifo , & fd , 1 ) ;
if ( ret < 0 )
goto fail ;
return 0 ;
fail :
frame_data_uninit ( & fd ) ;
return ret ;
}
static int frame_data_apply ( AVCodecContext * avctx , AVFifo * fifo , AVPacket * pkt )
2021-06-18 07:20:44 +02:00
{
2023-02-28 12:39:36 +02:00
FrameData fd ;
2021-06-18 07:20:44 +02:00
uint8_t * data ;
2023-02-28 13:53:35 +02:00
int ret = 0 ;
2023-02-28 13:20:39 +02:00
if ( av_fifo_peek ( fifo , & fd , 1 , 0 ) < 0 )
2021-06-18 07:20:44 +02:00
return 0 ;
2023-02-28 13:53:35 +02:00
if ( fd . pts ! = pkt - > pts ) {
av_log ( avctx , AV_LOG_WARNING ,
" Mismatching timestamps: libvpx % " PRId64 " queued % " PRId64 " ; "
" this is a bug, please report it \n " , pkt - > pts , fd . pts ) ;
goto skip ;
}
2021-06-18 07:20:44 +02:00
2023-02-28 13:20:39 +02:00
pkt - > duration = fd . duration ;
if ( avctx - > flags & AV_CODEC_FLAG_COPY_OPAQUE ) {
pkt - > opaque = fd . frame_opaque ;
pkt - > opaque_ref = fd . frame_opaque_ref ;
fd . frame_opaque_ref = NULL ;
}
if ( fd . hdr10_plus ) {
data = av_packet_new_side_data ( pkt , AV_PKT_DATA_DYNAMIC_HDR10_PLUS , fd . hdr10_plus - > size ) ;
if ( ! data ) {
2023-02-28 13:53:35 +02:00
ret = AVERROR ( ENOMEM ) ;
goto skip ;
2023-02-28 13:20:39 +02:00
}
memcpy ( data , fd . hdr10_plus - > data , fd . hdr10_plus - > size ) ;
2021-06-18 07:20:44 +02:00
}
2023-02-28 13:53:35 +02:00
skip :
av_fifo_drain2 ( fifo , 1 ) ;
frame_data_uninit ( & fd ) ;
return ret ;
2021-06-18 07:20:44 +02:00
}
2010-06-03 23:47:59 +03:00
static av_cold int codecctl_int ( AVCodecContext * avctx ,
enum vp8e_enc_control_id id , int val )
{
2016-07-21 05:41:55 +02:00
VPxContext * ctx = avctx - > priv_data ;
2010-06-03 23:47:59 +03:00
char buf [ 80 ] ;
int width = - 30 ;
int res ;
snprintf ( buf , sizeof ( buf ) , " %s: " , ctlidstr [ id ] ) ;
av_log ( avctx , AV_LOG_DEBUG , " %*s%d \n " , width , buf , val ) ;
res = vpx_codec_control ( & ctx - > encoder , id , val ) ;
if ( res ! = VPX_CODEC_OK ) {
snprintf ( buf , sizeof ( buf ) , " Failed to set %s codec control " ,
ctlidstr [ id ] ) ;
log_encoder_error ( avctx , buf ) ;
2021-09-03 10:32:06 +02:00
return AVERROR ( EINVAL ) ;
2010-06-03 23:47:59 +03:00
}
2021-09-03 10:32:06 +02:00
if ( ctx - > is_alpha ) {
int res_alpha = vpx_codec_control ( & ctx - > encoder_alpha , id , val ) ;
if ( res_alpha ! = VPX_CODEC_OK ) {
snprintf ( buf , sizeof ( buf ) , " Failed to set %s alpha codec control " ,
ctlidstr [ id ] ) ;
log_encoder_error ( avctx , buf ) ;
return AVERROR ( EINVAL ) ;
}
}
return 0 ;
2010-06-03 23:47:59 +03:00
}
2016-11-18 23:56:32 +02:00
# if VPX_ENCODER_ABI_VERSION >= 12
static av_cold int codecctl_intp ( AVCodecContext * avctx ,
enum vp8e_enc_control_id id , int * val )
{
VPxContext * ctx = avctx - > priv_data ;
char buf [ 80 ] ;
int width = - 30 ;
int res ;
snprintf ( buf , sizeof ( buf ) , " %s: " , ctlidstr [ id ] ) ;
av_log ( avctx , AV_LOG_DEBUG , " %*s%d \n " , width , buf , * val ) ;
res = vpx_codec_control ( & ctx - > encoder , id , val ) ;
if ( res ! = VPX_CODEC_OK ) {
snprintf ( buf , sizeof ( buf ) , " Failed to set %s codec control " ,
ctlidstr [ id ] ) ;
log_encoder_error ( avctx , buf ) ;
2021-09-03 10:32:06 +02:00
return AVERROR ( EINVAL ) ;
2016-11-18 23:56:32 +02:00
}
2021-09-03 10:32:06 +02:00
if ( ctx - > is_alpha ) {
int res_alpha = vpx_codec_control ( & ctx - > encoder_alpha , id , val ) ;
if ( res_alpha ! = VPX_CODEC_OK ) {
snprintf ( buf , sizeof ( buf ) , " Failed to set %s alpha codec control " ,
ctlidstr [ id ] ) ;
log_encoder_error ( avctx , buf ) ;
return AVERROR ( EINVAL ) ;
}
}
return 0 ;
2016-11-18 23:56:32 +02:00
}
# endif
2016-07-21 05:41:55 +02:00
static av_cold int vpx_free ( AVCodecContext * avctx )
2010-06-03 23:47:59 +03:00
{
2016-07-21 05:41:55 +02:00
VPxContext * ctx = avctx - > priv_data ;
2010-06-03 23:47:59 +03:00
2016-11-18 23:56:32 +02:00
# if VPX_ENCODER_ABI_VERSION >= 12
2016-12-12 22:07:05 +02:00
if ( avctx - > codec_id = = AV_CODEC_ID_VP9 & & ctx - > level > = 0 & &
! ( avctx - > flags & AV_CODEC_FLAG_PASS1 ) ) {
2016-11-18 23:56:32 +02:00
int level_out = 0 ;
if ( ! codecctl_intp ( avctx , VP9E_GET_LEVEL , & level_out ) )
av_log ( avctx , AV_LOG_INFO , " Encoded level %.1f \n " , level_out * 0.1 ) ;
}
# endif
2020-02-03 20:02:01 +02:00
av_freep ( & ctx - > ts_layer_flags ) ;
2010-06-03 23:47:59 +03:00
vpx_codec_destroy ( & ctx - > encoder ) ;
2019-11-02 18:20:21 +02:00
if ( ctx - > is_alpha ) {
2013-05-09 02:59:33 +03:00
vpx_codec_destroy ( & ctx - > encoder_alpha ) ;
2019-11-02 18:20:21 +02:00
av_freep ( & ctx - > rawimg_alpha . planes [ VPX_PLANE_U ] ) ;
av_freep ( & ctx - > rawimg_alpha . planes [ VPX_PLANE_V ] ) ;
}
2010-06-03 23:47:59 +03:00
av_freep ( & ctx - > twopass_stats . buf ) ;
av_freep ( & avctx - > stats_out ) ;
free_frame_list ( ctx - > coded_frame_list ) ;
2022-08-21 18:08:04 +02:00
free_frame_list ( ctx - > alpha_coded_frame_list ) ;
2023-02-28 12:39:36 +02:00
if ( ctx - > fifo )
fifo_free ( & ctx - > fifo ) ;
2010-06-03 23:47:59 +03:00
return 0 ;
}
2018-11-14 22:56:31 +02:00
static void vp8_ts_parse_int_array ( int * dest , char * value , size_t value_len , int max_entries )
{
int dest_idx = 0 ;
char * saveptr = NULL ;
char * token = av_strtok ( value , " , " , & saveptr ) ;
2018-11-19 21:36:36 +02:00
while ( token & & dest_idx < max_entries ) {
2018-11-14 22:56:31 +02:00
dest [ dest_idx + + ] = strtoul ( token , NULL , 10 ) ;
token = av_strtok ( NULL , " , " , & saveptr ) ;
}
}
2021-01-09 01:33:29 +02:00
# if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_CTRL_VP9E_SET_MAX_INTER_BITRATE_PCT)
static void vp8_ts_parse_int64_array ( int64_t * dest , char * value , size_t value_len , int max_entries )
{
int dest_idx = 0 ;
char * saveptr = NULL ;
char * token = av_strtok ( value , " , " , & saveptr ) ;
while ( token & & dest_idx < max_entries ) {
dest [ dest_idx + + ] = strtoull ( token , NULL , 10 ) ;
token = av_strtok ( NULL , " , " , & saveptr ) ;
}
}
# endif
2020-02-03 20:02:01 +02:00
static void set_temporal_layer_pattern ( int layering_mode , vpx_codec_enc_cfg_t * cfg ,
int * layer_flags , int * flag_periodicity )
{
switch ( layering_mode ) {
case 2 : {
/**
* 2 - layers , 2 - frame period .
*/
static const int ids [ 2 ] = { 0 , 1 } ;
cfg - > ts_periodicity = 2 ;
* flag_periodicity = 2 ;
cfg - > ts_number_layers = 2 ;
cfg - > ts_rate_decimator [ 0 ] = 2 ;
cfg - > ts_rate_decimator [ 1 ] = 1 ;
memcpy ( cfg - > ts_layer_id , ids , sizeof ( ids ) ) ;
layer_flags [ 0 ] =
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF ;
layer_flags [ 1 ] =
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_LAST |
VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_GF ;
break ;
}
case 3 : {
/**
* 3 - layers structure with one reference frame .
* This works same as temporal_layering_mode 3.
*
* 3 - layers , 4 - frame period .
*/
static const int ids [ 4 ] = { 0 , 2 , 1 , 2 } ;
cfg - > ts_periodicity = 4 ;
* flag_periodicity = 4 ;
cfg - > ts_number_layers = 3 ;
cfg - > ts_rate_decimator [ 0 ] = 4 ;
cfg - > ts_rate_decimator [ 1 ] = 2 ;
cfg - > ts_rate_decimator [ 2 ] = 1 ;
memcpy ( cfg - > ts_layer_id , ids , sizeof ( ids ) ) ;
/**
* 0 = L , 1 = GF , 2 = ARF ,
* Intra - layer prediction disabled .
*/
layer_flags [ 0 ] =
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF ;
layer_flags [ 1 ] =
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF ;
layer_flags [ 2 ] =
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST ;
layer_flags [ 3 ] =
VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF ;
break ;
}
case 4 : {
/**
* 3 - layers structure .
* added dependency between the two TL2 frames ( on top of case 3 ) .
* 3 - layers , 4 - frame period .
*/
static const int ids [ 4 ] = { 0 , 2 , 1 , 2 } ;
cfg - > ts_periodicity = 4 ;
* flag_periodicity = 4 ;
cfg - > ts_number_layers = 3 ;
cfg - > ts_rate_decimator [ 0 ] = 4 ;
cfg - > ts_rate_decimator [ 1 ] = 2 ;
cfg - > ts_rate_decimator [ 2 ] = 1 ;
memcpy ( cfg - > ts_layer_id , ids , sizeof ( ids ) ) ;
/**
* 0 = L , 1 = GF , 2 = ARF , Intra - layer prediction disabled .
*/
layer_flags [ 0 ] =
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF ;
layer_flags [ 1 ] =
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF ;
layer_flags [ 2 ] =
VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF |
VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_NO_UPD_LAST ;
layer_flags [ 3 ] =
VP8_EFLAG_NO_REF_LAST |
VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF |
VP8_EFLAG_NO_UPD_ARF ;
break ;
}
default :
/**
* do not change the layer_flags or the flag_periodicity in this case ;
* it might be that the code is using external flags to be used .
*/
break ;
}
}
static int vpx_ts_param_parse ( VPxContext * ctx , struct vpx_codec_enc_cfg * enccfg ,
char * key , char * value , enum AVCodecID codec_id )
2018-11-14 22:56:31 +02:00
{
size_t value_len = strlen ( value ) ;
2020-02-03 20:02:01 +02:00
int ts_layering_mode = 0 ;
2018-11-14 22:56:31 +02:00
if ( ! value_len )
return - 1 ;
if ( ! strcmp ( key , " ts_number_layers " ) )
enccfg - > ts_number_layers = strtoul ( value , & value , 10 ) ;
2020-02-03 20:02:01 +02:00
else if ( ! strcmp ( key , " ts_target_bitrate " ) ) {
if ( codec_id = = AV_CODEC_ID_VP8 )
vp8_ts_parse_int_array ( enccfg - > ts_target_bitrate , value , value_len , VPX_TS_MAX_LAYERS ) ;
# if (VPX_ENCODER_ABI_VERSION >= 12) && CONFIG_LIBVPX_VP9_ENCODER
if ( codec_id = = AV_CODEC_ID_VP9 )
vp8_ts_parse_int_array ( enccfg - > layer_target_bitrate , value , value_len , VPX_TS_MAX_LAYERS ) ;
# endif
} else if ( ! strcmp ( key , " ts_rate_decimator " ) ) {
vp8_ts_parse_int_array ( enccfg - > ts_rate_decimator , value , value_len , VPX_TS_MAX_LAYERS ) ;
} else if ( ! strcmp ( key , " ts_periodicity " ) ) {
2018-11-14 22:56:31 +02:00
enccfg - > ts_periodicity = strtoul ( value , & value , 10 ) ;
2020-02-03 20:02:01 +02:00
} else if ( ! strcmp ( key , " ts_layer_id " ) ) {
2018-11-14 22:56:31 +02:00
vp8_ts_parse_int_array ( enccfg - > ts_layer_id , value , value_len , VPX_TS_MAX_PERIODICITY ) ;
2020-02-03 20:02:01 +02:00
} else if ( ! strcmp ( key , " ts_layering_mode " ) ) {
/* option for pre-defined temporal structures in function set_temporal_layer_pattern. */
2024-05-16 08:10:36 +02:00
ts_layering_mode = strtoul ( value , & value , 10 ) ;
2020-02-03 20:02:01 +02:00
}
# if (VPX_ENCODER_ABI_VERSION >= 12) && CONFIG_LIBVPX_VP9_ENCODER
enccfg - > temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS ; // only bypass mode is supported for now.
enccfg - > ss_number_layers = 1 ; // TODO: add spatial scalability support.
# endif
if ( ts_layering_mode ) {
// make sure the ts_layering_mode comes at the end of the ts_parameter string to ensure that
// correct configuration is done.
ctx - > ts_layer_flags = av_malloc_array ( VPX_TS_MAX_PERIODICITY , sizeof ( * ctx - > ts_layer_flags ) ) ;
set_temporal_layer_pattern ( ts_layering_mode , enccfg , ctx - > ts_layer_flags , & enccfg - > ts_periodicity ) ;
}
2018-11-14 22:56:31 +02:00
return 0 ;
}
2021-01-09 01:33:29 +02:00
# if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_CTRL_VP9E_SET_MAX_INTER_BITRATE_PCT)
2021-02-18 21:01:31 +02:00
static int vpx_ref_frame_config_set_value ( vpx_svc_ref_frame_config_t * ref_frame_config ,
int ss_number_layers , char * key , char * value )
2021-01-09 01:33:29 +02:00
{
size_t value_len = strlen ( value ) ;
if ( ! value_len )
2021-02-18 21:01:31 +02:00
return AVERROR ( EINVAL ) ;
2021-01-09 01:33:29 +02:00
if ( ! strcmp ( key , " rfc_update_buffer_slot " ) ) {
vp8_ts_parse_int_array ( ref_frame_config - > update_buffer_slot , value , value_len , ss_number_layers ) ;
} else if ( ! strcmp ( key , " rfc_update_last " ) ) {
vp8_ts_parse_int_array ( ref_frame_config - > update_last , value , value_len , ss_number_layers ) ;
} else if ( ! strcmp ( key , " rfc_update_golden " ) ) {
vp8_ts_parse_int_array ( ref_frame_config - > update_golden , value , value_len , ss_number_layers ) ;
} else if ( ! strcmp ( key , " rfc_update_alt_ref " ) ) {
vp8_ts_parse_int_array ( ref_frame_config - > update_alt_ref , value , value_len , ss_number_layers ) ;
} else if ( ! strcmp ( key , " rfc_lst_fb_idx " ) ) {
vp8_ts_parse_int_array ( ref_frame_config - > lst_fb_idx , value , value_len , ss_number_layers ) ;
} else if ( ! strcmp ( key , " rfc_gld_fb_idx " ) ) {
vp8_ts_parse_int_array ( ref_frame_config - > gld_fb_idx , value , value_len , ss_number_layers ) ;
} else if ( ! strcmp ( key , " rfc_alt_fb_idx " ) ) {
vp8_ts_parse_int_array ( ref_frame_config - > alt_fb_idx , value , value_len , ss_number_layers ) ;
} else if ( ! strcmp ( key , " rfc_reference_last " ) ) {
vp8_ts_parse_int_array ( ref_frame_config - > reference_last , value , value_len , ss_number_layers ) ;
} else if ( ! strcmp ( key , " rfc_reference_golden " ) ) {
vp8_ts_parse_int_array ( ref_frame_config - > reference_golden , value , value_len , ss_number_layers ) ;
} else if ( ! strcmp ( key , " rfc_reference_alt_ref " ) ) {
vp8_ts_parse_int_array ( ref_frame_config - > reference_alt_ref , value , value_len , ss_number_layers ) ;
} else if ( ! strcmp ( key , " rfc_reference_duration " ) ) {
vp8_ts_parse_int64_array ( ref_frame_config - > duration , value , value_len , ss_number_layers ) ;
}
return 0 ;
}
2021-02-18 21:01:31 +02:00
static int vpx_parse_ref_frame_config_element ( vpx_svc_ref_frame_config_t * ref_frame_config ,
int ss_number_layers , const char * * buf )
{
const char key_val_sep [ ] = " = " ;
const char pairs_sep [ ] = " : " ;
char * key = av_get_token ( buf , key_val_sep ) ;
char * val = NULL ;
int ret ;
if ( key & & * key & & strspn ( * buf , key_val_sep ) ) {
( * buf ) + + ;
val = av_get_token ( buf , pairs_sep ) ;
}
if ( key & & * key & & val & & * val )
ret = vpx_ref_frame_config_set_value ( ref_frame_config , ss_number_layers , key , val ) ;
else
ret = AVERROR ( EINVAL ) ;
av_freep ( & key ) ;
av_freep ( & val ) ;
return ret ;
}
static int vpx_parse_ref_frame_config ( vpx_svc_ref_frame_config_t * ref_frame_config ,
int ss_number_layers , const char * str )
{
int ret = 0 ;
while ( * str ) {
ret =
vpx_parse_ref_frame_config_element ( ref_frame_config , ss_number_layers , & str ) ;
if ( ret < 0 )
return ret ;
if ( * str )
str + + ;
}
return ret ;
}
2021-01-09 01:33:29 +02:00
# endif
2015-03-26 02:10:16 +02:00
# if CONFIG_LIBVPX_VP9_ENCODER
static int set_pix_fmt ( AVCodecContext * avctx , vpx_codec_caps_t codec_caps ,
struct vpx_codec_enc_cfg * enccfg , vpx_codec_flags_t * flags ,
2015-04-22 23:16:06 +02:00
vpx_img_fmt_t * img_fmt )
{
2024-03-26 18:35:09 +02:00
VPxContext * ctx = avctx - > priv_data ;
2020-07-20 19:43:47 +02:00
const AVPixFmtDescriptor * desc = av_pix_fmt_desc_get ( avctx - > pix_fmt ) ;
enccfg - > g_bit_depth = enccfg - > g_input_bit_depth = desc - > comp [ 0 ] . depth ;
2015-03-26 02:10:16 +02:00
switch ( avctx - > pix_fmt ) {
case AV_PIX_FMT_YUV420P :
2016-07-01 01:16:31 +02:00
case AV_PIX_FMT_YUVA420P :
2015-03-26 02:10:16 +02:00
enccfg - > g_profile = 0 ;
* img_fmt = VPX_IMG_FMT_I420 ;
return 0 ;
case AV_PIX_FMT_YUV422P :
2015-05-20 22:52:47 +02:00
enccfg - > g_profile = 1 ;
* img_fmt = VPX_IMG_FMT_I422 ;
return 0 ;
case AV_PIX_FMT_YUV440P :
enccfg - > g_profile = 1 ;
* img_fmt = VPX_IMG_FMT_I440 ;
return 0 ;
2016-02-19 22:06:26 +02:00
case AV_PIX_FMT_GBRP :
ctx - > vpx_cs = VPX_CS_SRGB ;
2015-03-26 02:10:16 +02:00
case AV_PIX_FMT_YUV444P :
enccfg - > g_profile = 1 ;
2015-05-20 22:52:47 +02:00
* img_fmt = VPX_IMG_FMT_I444 ;
2015-03-26 02:10:16 +02:00
return 0 ;
2016-02-19 22:02:42 +02:00
case AV_PIX_FMT_YUV420P10 :
case AV_PIX_FMT_YUV420P12 :
2015-03-26 02:10:16 +02:00
if ( codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH ) {
enccfg - > g_profile = 2 ;
* img_fmt = VPX_IMG_FMT_I42016 ;
* flags | = VPX_CODEC_USE_HIGHBITDEPTH ;
return 0 ;
}
break ;
2016-02-19 22:02:42 +02:00
case AV_PIX_FMT_YUV422P10 :
case AV_PIX_FMT_YUV422P12 :
2015-03-26 02:10:16 +02:00
if ( codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH ) {
enccfg - > g_profile = 3 ;
* img_fmt = VPX_IMG_FMT_I42216 ;
* flags | = VPX_CODEC_USE_HIGHBITDEPTH ;
return 0 ;
}
break ;
2016-02-19 22:02:42 +02:00
case AV_PIX_FMT_YUV440P10 :
case AV_PIX_FMT_YUV440P12 :
2015-05-20 22:52:47 +02:00
if ( codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH ) {
enccfg - > g_profile = 3 ;
* img_fmt = VPX_IMG_FMT_I44016 ;
* flags | = VPX_CODEC_USE_HIGHBITDEPTH ;
return 0 ;
}
break ;
2016-02-19 22:06:26 +02:00
case AV_PIX_FMT_GBRP10 :
case AV_PIX_FMT_GBRP12 :
ctx - > vpx_cs = VPX_CS_SRGB ;
2016-02-19 22:02:42 +02:00
case AV_PIX_FMT_YUV444P10 :
case AV_PIX_FMT_YUV444P12 :
2015-03-26 02:10:16 +02:00
if ( codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH ) {
enccfg - > g_profile = 3 ;
* img_fmt = VPX_IMG_FMT_I44416 ;
* flags | = VPX_CODEC_USE_HIGHBITDEPTH ;
return 0 ;
}
break ;
default :
break ;
}
av_log ( avctx , AV_LOG_ERROR , " Unsupported pixel format. \n " ) ;
return AVERROR_INVALIDDATA ;
}
2015-06-13 21:27:48 +02:00
static void set_colorspace ( AVCodecContext * avctx )
{
enum vpx_color_space vpx_cs ;
2016-07-21 05:41:55 +02:00
VPxContext * ctx = avctx - > priv_data ;
2015-06-13 21:27:48 +02:00
2016-02-19 22:06:26 +02:00
if ( ctx - > vpx_cs ) {
vpx_cs = ctx - > vpx_cs ;
} else {
2016-02-19 22:11:56 +02:00
switch ( avctx - > colorspace ) {
case AVCOL_SPC_RGB : vpx_cs = VPX_CS_SRGB ; break ;
case AVCOL_SPC_BT709 : vpx_cs = VPX_CS_BT_709 ; break ;
case AVCOL_SPC_UNSPECIFIED : vpx_cs = VPX_CS_UNKNOWN ; break ;
case AVCOL_SPC_RESERVED : vpx_cs = VPX_CS_RESERVED ; break ;
case AVCOL_SPC_BT470BG : vpx_cs = VPX_CS_BT_601 ; break ;
case AVCOL_SPC_SMPTE170M : vpx_cs = VPX_CS_SMPTE_170 ; break ;
case AVCOL_SPC_SMPTE240M : vpx_cs = VPX_CS_SMPTE_240 ; break ;
case AVCOL_SPC_BT2020_NCL : vpx_cs = VPX_CS_BT_2020 ; break ;
default :
av_log ( avctx , AV_LOG_WARNING , " Unsupported colorspace (%d) \n " ,
avctx - > colorspace ) ;
return ;
}
2016-02-19 22:06:26 +02:00
}
2015-06-13 21:27:48 +02:00
codecctl_int ( avctx , VP9E_SET_COLOR_SPACE , vpx_cs ) ;
}
2016-01-09 17:48:49 +02:00
# if VPX_ENCODER_ABI_VERSION >= 11
static void set_color_range ( AVCodecContext * avctx )
{
enum vpx_color_range vpx_cr ;
switch ( avctx - > color_range ) {
case AVCOL_RANGE_UNSPECIFIED :
case AVCOL_RANGE_MPEG : vpx_cr = VPX_CR_STUDIO_RANGE ; break ;
case AVCOL_RANGE_JPEG : vpx_cr = VPX_CR_FULL_RANGE ; break ;
default :
av_log ( avctx , AV_LOG_WARNING , " Unsupported color range (%d) \n " ,
avctx - > color_range ) ;
return ;
}
codecctl_int ( avctx , VP9E_SET_COLOR_RANGE , vpx_cr ) ;
}
# endif
2015-03-26 02:10:16 +02:00
# endif
2019-09-25 01:24:13 +02:00
/**
* Set the target bitrate to VPX library default . Also set CRF to 32 if needed .
*/
static void set_vp8_defaults ( AVCodecContext * avctx ,
struct vpx_codec_enc_cfg * enccfg )
{
VPxContext * ctx = avctx - > priv_data ;
av_assert0 ( ! avctx - > bit_rate ) ;
avctx - > bit_rate = enccfg - > rc_target_bitrate * 1000 ;
if ( enccfg - > rc_end_usage = = VPX_CQ ) {
av_log ( avctx , AV_LOG_WARNING ,
" Bitrate not specified for constrained quality mode, using default of %dkbit/sec \n " ,
enccfg - > rc_target_bitrate ) ;
} else {
enccfg - > rc_end_usage = VPX_CQ ;
ctx - > crf = 32 ;
av_log ( avctx , AV_LOG_WARNING ,
" Neither bitrate nor constrained quality specified, using default CRF of %d and bitrate of %dkbit/sec \n " ,
ctx - > crf , enccfg - > rc_target_bitrate ) ;
}
}
# if CONFIG_LIBVPX_VP9_ENCODER
/**
* Keep the target bitrate at 0 to engage constant quality mode . If CRF is not
* set , use 32.
*/
static void set_vp9_defaults ( AVCodecContext * avctx ,
struct vpx_codec_enc_cfg * enccfg )
{
VPxContext * ctx = avctx - > priv_data ;
av_assert0 ( ! avctx - > bit_rate ) ;
if ( enccfg - > rc_end_usage ! = VPX_Q & & ctx - > lossless < 0 ) {
enccfg - > rc_end_usage = VPX_Q ;
ctx - > crf = 32 ;
av_log ( avctx , AV_LOG_WARNING ,
" Neither bitrate nor constrained quality specified, using default CRF of %d \n " ,
ctx - > crf ) ;
}
}
# endif
/**
* Called when the bitrate is not set . It sets appropriate default values for
* bitrate and CRF .
*/
static void set_vpx_defaults ( AVCodecContext * avctx ,
struct vpx_codec_enc_cfg * enccfg )
{
av_assert0 ( ! avctx - > bit_rate ) ;
# if CONFIG_LIBVPX_VP9_ENCODER
if ( avctx - > codec_id = = AV_CODEC_ID_VP9 ) {
set_vp9_defaults ( avctx , enccfg ) ;
return ;
}
# endif
set_vp8_defaults ( avctx , enccfg ) ;
}
2012-12-20 19:22:06 +03:00
static av_cold int vpx_init ( AVCodecContext * avctx ,
const struct vpx_codec_iface * iface )
2010-06-03 23:47:59 +03:00
{
2016-07-21 05:41:55 +02:00
VPxContext * ctx = avctx - > priv_data ;
2015-06-11 16:56:31 +02:00
struct vpx_codec_enc_cfg enccfg = { 0 } ;
2013-05-09 02:59:33 +03:00
struct vpx_codec_enc_cfg enccfg_alpha ;
2015-07-27 21:14:31 +02:00
vpx_codec_flags_t flags = ( avctx - > flags & AV_CODEC_FLAG_PSNR ) ? VPX_CODEC_USE_PSNR : 0 ;
2015-10-03 15:19:10 +02:00
AVCPBProperties * cpb_props ;
2010-06-03 23:47:59 +03:00
int res ;
2015-03-26 02:10:16 +02:00
vpx_img_fmt_t img_fmt = VPX_IMG_FMT_I420 ;
# if CONFIG_LIBVPX_VP9_ENCODER
vpx_codec_caps_t codec_caps = vpx_codec_get_caps ( iface ) ;
2020-02-03 20:02:01 +02:00
vpx_svc_extra_cfg_t svc_params ;
2015-03-26 02:10:16 +02:00
# endif
2022-11-26 16:46:22 +02:00
const AVDictionaryEntry * en = NULL ;
2010-06-03 23:47:59 +03:00
av_log ( avctx , AV_LOG_INFO , " %s \n " , vpx_codec_version_str ( ) ) ;
av_log ( avctx , AV_LOG_VERBOSE , " %s \n " , vpx_codec_build_config ( ) ) ;
2013-05-09 02:59:33 +03:00
if ( avctx - > pix_fmt = = AV_PIX_FMT_YUVA420P )
ctx - > is_alpha = 1 ;
2010-06-03 23:47:59 +03:00
if ( ( res = vpx_codec_enc_config_default ( iface , & enccfg , 0 ) ) ! = VPX_CODEC_OK ) {
av_log ( avctx , AV_LOG_ERROR , " Failed to get config: %s \n " ,
vpx_codec_err_to_string ( res ) ) ;
return AVERROR ( EINVAL ) ;
}
2012-08-16 17:59:42 +03:00
2023-02-28 13:20:39 +02:00
ctx - > fifo = av_fifo_alloc2 ( 1 , sizeof ( FrameData ) , AV_FIFO_FLAG_AUTO_GROW ) ;
if ( ! ctx - > fifo )
return AVERROR ( ENOMEM ) ;
2015-03-26 02:10:16 +02:00
# if CONFIG_LIBVPX_VP9_ENCODER
if ( avctx - > codec_id = = AV_CODEC_ID_VP9 ) {
if ( set_pix_fmt ( avctx , codec_caps , & enccfg , & flags , & img_fmt ) )
return AVERROR ( EINVAL ) ;
}
# endif
2012-08-16 17:59:42 +03:00
if ( ! avctx - > bit_rate )
if ( avctx - > rc_max_rate | | avctx - > rc_buffer_size | | avctx - > rc_initial_buffer_occupancy ) {
av_log ( avctx , AV_LOG_ERROR , " Rate control parameters set without a bitrate \n " ) ;
return AVERROR ( EINVAL ) ;
}
2021-06-14 20:20:52 +02:00
dump_enc_cfg ( avctx , & enccfg , AV_LOG_DEBUG ) ;
2010-06-03 23:47:59 +03:00
enccfg . g_w = avctx - > width ;
enccfg . g_h = avctx - > height ;
enccfg . g_timebase . num = avctx - > time_base . num ;
enccfg . g_timebase . den = avctx - > time_base . den ;
2018-11-15 20:51:32 +02:00
enccfg . g_threads =
2022-10-06 15:49:59 +02:00
FFMIN ( avctx - > thread_count ? avctx - > thread_count : av_cpu_count ( ) , MAX_VPX_THREADS ) ;
2011-10-02 21:38:38 +03:00
enccfg . g_lag_in_frames = ctx - > lag_in_frames ;
2010-06-03 23:47:59 +03:00
2015-06-29 21:59:37 +02:00
if ( avctx - > flags & AV_CODEC_FLAG_PASS1 )
2010-06-03 23:47:59 +03:00
enccfg . g_pass = VPX_RC_FIRST_PASS ;
2015-06-29 21:59:37 +02:00
else if ( avctx - > flags & AV_CODEC_FLAG_PASS2 )
2010-06-03 23:47:59 +03:00
enccfg . g_pass = VPX_RC_LAST_PASS ;
else
enccfg . g_pass = VPX_RC_ONE_PASS ;
if ( avctx - > rc_min_rate = = avctx - > rc_max_rate & &
2014-08-27 23:04:08 +03:00
avctx - > rc_min_rate = = avctx - > bit_rate & & avctx - > bit_rate ) {
2010-06-03 23:47:59 +03:00
enccfg . rc_end_usage = VPX_CBR ;
2014-08-27 23:04:08 +03:00
} else if ( ctx - > crf > = 0 ) {
2011-04-12 03:00:35 +03:00
enccfg . rc_end_usage = VPX_CQ ;
2014-08-27 23:04:08 +03:00
# if CONFIG_LIBVPX_VP9_ENCODER
if ( ! avctx - > bit_rate & & avctx - > codec_id = = AV_CODEC_ID_VP9 )
enccfg . rc_end_usage = VPX_Q ;
# endif
}
2012-08-17 18:34:30 +03:00
if ( avctx - > bit_rate ) {
enccfg . rc_target_bitrate = av_rescale_rnd ( avctx - > bit_rate , 1 , 1000 ,
2014-08-27 23:04:08 +03:00
AV_ROUND_NEAR_INF ) ;
2020-02-03 20:02:01 +02:00
# if CONFIG_LIBVPX_VP9_ENCODER
enccfg . ss_target_bitrate [ 0 ] = enccfg . rc_target_bitrate ;
# endif
2012-08-17 18:34:30 +03:00
} else {
2019-09-25 01:24:13 +02:00
// Set bitrate to default value. Also sets CRF to default if needed.
set_vpx_defaults ( avctx , & enccfg ) ;
2012-08-17 18:34:30 +03:00
}
2015-03-20 17:40:43 +02:00
if ( avctx - > codec_id = = AV_CODEC_ID_VP9 & & ctx - > lossless = = 1 ) {
enccfg . rc_min_quantizer =
enccfg . rc_max_quantizer = 0 ;
} else {
if ( avctx - > qmin > = 0 )
enccfg . rc_min_quantizer = avctx - > qmin ;
if ( avctx - > qmax > = 0 )
enccfg . rc_max_quantizer = avctx - > qmax ;
}
2013-02-25 21:23:55 +03:00
2014-08-27 23:04:08 +03:00
if ( enccfg . rc_end_usage = = VPX_CQ
# if CONFIG_LIBVPX_VP9_ENCODER
| | enccfg . rc_end_usage = = VPX_Q
# endif
2015-04-22 23:16:06 +02:00
) {
2013-02-25 21:23:55 +03:00
if ( ctx - > crf < enccfg . rc_min_quantizer | | ctx - > crf > enccfg . rc_max_quantizer ) {
2015-04-22 23:16:06 +02:00
av_log ( avctx , AV_LOG_ERROR ,
" CQ level %d must be between minimum and maximum quantizer value (%d-%d) \n " ,
ctx - > crf , enccfg . rc_min_quantizer , enccfg . rc_max_quantizer ) ;
return AVERROR ( EINVAL ) ;
2013-02-25 21:23:55 +03:00
}
}
2015-09-11 03:30:38 +02:00
enccfg . rc_dropframe_thresh = ctx - > drop_threshold ;
2010-06-03 23:47:59 +03:00
2010-07-22 15:35:32 +03:00
//0-100 (0 => CBR, 100 => VBR)
2015-12-16 21:48:45 +02:00
enccfg . rc_2pass_vbr_bias_pct = lrint ( avctx - > qcompress * 100 ) ;
2012-08-16 17:58:59 +03:00
if ( avctx - > bit_rate )
2015-04-22 23:16:06 +02:00
enccfg . rc_2pass_vbr_minsection_pct =
2012-08-16 17:58:59 +03:00
avctx - > rc_min_rate * 100LL / avctx - > bit_rate ;
2010-07-22 15:35:32 +03:00
if ( avctx - > rc_max_rate )
enccfg . rc_2pass_vbr_maxsection_pct =
2010-12-12 18:27:32 +02:00
avctx - > rc_max_rate * 100LL / avctx - > bit_rate ;
2017-11-21 03:32:23 +02:00
# if CONFIG_LIBVPX_VP9_ENCODER
if ( avctx - > codec_id = = AV_CODEC_ID_VP9 ) {
# if VPX_ENCODER_ABI_VERSION >= 14
if ( ctx - > corpus_complexity > = 0 )
enccfg . rc_2pass_vbr_corpus_complexity = ctx - > corpus_complexity ;
# endif
}
# endif
2010-07-22 15:35:32 +03:00
2010-07-28 11:02:35 +03:00
if ( avctx - > rc_buffer_size )
enccfg . rc_buf_sz =
2010-12-12 18:27:32 +02:00
avctx - > rc_buffer_size * 1000LL / avctx - > bit_rate ;
2010-07-28 11:02:35 +03:00
if ( avctx - > rc_initial_buffer_occupancy )
enccfg . rc_buf_initial_sz =
2010-12-12 18:27:32 +02:00
avctx - > rc_initial_buffer_occupancy * 1000LL / avctx - > bit_rate ;
2010-07-28 11:02:35 +03:00
enccfg . rc_buf_optimal_sz = enccfg . rc_buf_sz * 5 / 6 ;
2015-06-06 19:10:56 +02:00
if ( ctx - > rc_undershoot_pct > = 0 )
enccfg . rc_undershoot_pct = ctx - > rc_undershoot_pct ;
2015-06-06 19:24:44 +02:00
if ( ctx - > rc_overshoot_pct > = 0 )
enccfg . rc_overshoot_pct = ctx - > rc_overshoot_pct ;
2010-07-28 11:02:35 +03:00
2010-06-08 11:47:50 +03:00
//_enc_init() will balk if kf_min_dist differs from max w/VPX_KF_AUTO
2011-09-30 13:15:59 +03:00
if ( avctx - > keyint_min > = 0 & & avctx - > keyint_min = = avctx - > gop_size )
2010-06-03 23:47:59 +03:00
enccfg . kf_min_dist = avctx - > keyint_min ;
2011-09-30 13:15:59 +03:00
if ( avctx - > gop_size > = 0 )
enccfg . kf_max_dist = avctx - > gop_size ;
2010-06-03 23:47:59 +03:00
if ( enccfg . g_pass = = VPX_RC_FIRST_PASS )
enccfg . g_lag_in_frames = 0 ;
else if ( enccfg . g_pass = = VPX_RC_LAST_PASS ) {
2015-03-08 23:08:16 +02:00
int decode_size , ret ;
2010-06-03 23:47:59 +03:00
if ( ! avctx - > stats_in ) {
av_log ( avctx , AV_LOG_ERROR , " No stats file for second pass \n " ) ;
return AVERROR_INVALIDDATA ;
}
ctx - > twopass_stats . sz = strlen ( avctx - > stats_in ) * 3 / 4 ;
2015-03-08 23:08:16 +02:00
ret = av_reallocp ( & ctx - > twopass_stats . buf , ctx - > twopass_stats . sz ) ;
if ( ret < 0 ) {
2010-06-03 23:47:59 +03:00
av_log ( avctx , AV_LOG_ERROR ,
2014-04-24 19:01:30 +03:00
" Stat buffer alloc (% " SIZE_SPECIFIER " bytes) failed \n " ,
2010-06-03 23:47:59 +03:00
ctx - > twopass_stats . sz ) ;
2015-03-09 22:17:45 +02:00
ctx - > twopass_stats . sz = 0 ;
2015-03-08 23:08:16 +02:00
return ret ;
2010-06-03 23:47:59 +03:00
}
decode_size = av_base64_decode ( ctx - > twopass_stats . buf , avctx - > stats_in ,
ctx - > twopass_stats . sz ) ;
if ( decode_size < 0 ) {
av_log ( avctx , AV_LOG_ERROR , " Stat buffer decode failed \n " ) ;
return AVERROR_INVALIDDATA ;
}
ctx - > twopass_stats . sz = decode_size ;
enccfg . rc_twopass_stats_in = ctx - > twopass_stats ;
}
2010-07-11 20:46:44 +03:00
/* 0-3: For non-zero values the encoder increasingly optimizes for reduced
complexity playback on low powered devices at the expense of encode
quality . */
2023-09-02 14:57:41 +02:00
if ( avctx - > profile ! = AV_PROFILE_UNKNOWN )
2015-04-22 23:16:06 +02:00
enccfg . g_profile = avctx - > profile ;
2010-06-03 23:47:59 +03:00
2012-01-06 01:24:26 +03:00
enccfg . g_error_resilient = ctx - > error_resilient | | ctx - > flags & VP8F_ERROR_RESILIENT ;
2011-05-26 21:20:36 +03:00
2022-11-26 16:46:22 +02:00
while ( ( en = av_dict_iterate ( ctx - > vpx_ts_parameters , en ) ) ) {
2020-02-03 20:02:01 +02:00
if ( vpx_ts_param_parse ( ctx , & enccfg , en - > key , en - > value , avctx - > codec_id ) < 0 )
av_log ( avctx , AV_LOG_WARNING ,
" Error parsing option '%s = %s'. \n " ,
en - > key , en - > value ) ;
2018-11-14 22:56:31 +02:00
}
2010-06-03 23:47:59 +03:00
/* Construct Encoder Context */
2013-03-01 01:14:46 +03:00
res = vpx_codec_enc_init ( & ctx - > encoder , iface , & enccfg , flags ) ;
2010-06-03 23:47:59 +03:00
if ( res ! = VPX_CODEC_OK ) {
2021-06-14 20:20:52 +02:00
dump_enc_cfg ( avctx , & enccfg , AV_LOG_WARNING ) ;
2010-06-03 23:47:59 +03:00
log_encoder_error ( avctx , " Failed to initialize encoder " ) ;
return AVERROR ( EINVAL ) ;
}
2021-06-14 20:20:52 +02:00
dump_enc_cfg ( avctx , & enccfg , AV_LOG_DEBUG ) ;
2020-02-03 20:02:01 +02:00
# if CONFIG_LIBVPX_VP9_ENCODER
if ( avctx - > codec_id = = AV_CODEC_ID_VP9 & & enccfg . ts_number_layers > 1 ) {
memset ( & svc_params , 0 , sizeof ( svc_params ) ) ;
for ( int i = 0 ; i < enccfg . ts_number_layers ; + + i ) {
svc_params . max_quantizers [ i ] = enccfg . rc_max_quantizer ;
svc_params . min_quantizers [ i ] = enccfg . rc_min_quantizer ;
}
svc_params . scaling_factor_num [ 0 ] = enccfg . g_h ;
svc_params . scaling_factor_den [ 0 ] = enccfg . g_h ;
# if VPX_ENCODER_ABI_VERSION >= 12
codecctl_int ( avctx , VP9E_SET_SVC , 1 ) ;
codecctl_intp ( avctx , VP9E_SET_SVC_PARAMETERS , ( int * ) & svc_params ) ;
# endif
}
# endif
2013-05-09 02:59:33 +03:00
if ( ctx - > is_alpha ) {
enccfg_alpha = enccfg ;
res = vpx_codec_enc_init ( & ctx - > encoder_alpha , iface , & enccfg_alpha , flags ) ;
if ( res ! = VPX_CODEC_OK ) {
log_encoder_error ( avctx , " Failed to initialize alpha encoder " ) ;
return AVERROR ( EINVAL ) ;
}
}
2010-06-03 23:47:59 +03:00
//codec control failures are currently treated only as warnings
av_log ( avctx , AV_LOG_DEBUG , " vpx_codec_control \n " ) ;
2014-06-06 22:21:20 +03:00
codecctl_int ( avctx , VP8E_SET_CPUUSED , ctx - > cpu_used ) ;
2012-01-06 01:24:26 +03:00
if ( ctx - > flags & VP8F_AUTO_ALT_REF )
ctx - > auto_alt_ref = 1 ;
2011-10-04 04:01:06 +03:00
if ( ctx - > auto_alt_ref > = 0 )
2016-10-20 17:31:38 +02:00
codecctl_int ( avctx , VP8E_SET_ENABLEAUTOALTREF ,
avctx - > codec_id = = AV_CODEC_ID_VP8 ? ! ! ctx - > auto_alt_ref : ctx - > auto_alt_ref ) ;
2011-10-04 04:01:06 +03:00
if ( ctx - > arnr_max_frames > = 0 )
codecctl_int ( avctx , VP8E_SET_ARNR_MAXFRAMES , ctx - > arnr_max_frames ) ;
if ( ctx - > arnr_strength > = 0 )
codecctl_int ( avctx , VP8E_SET_ARNR_STRENGTH , ctx - > arnr_strength ) ;
if ( ctx - > arnr_type > = 0 )
codecctl_int ( avctx , VP8E_SET_ARNR_TYPE , ctx - > arnr_type ) ;
2015-12-17 05:53:14 +02:00
if ( ctx - > tune > = 0 )
codecctl_int ( avctx , VP8E_SET_TUNING , ctx - > tune ) ;
2015-06-16 03:48:00 +02:00
2016-09-16 14:21:09 +02:00
if ( ctx - > auto_alt_ref & & ctx - > is_alpha & & avctx - > codec_id = = AV_CODEC_ID_VP8 ) {
av_log ( avctx , AV_LOG_ERROR , " Transparency encoding with auto_alt_ref does not work \n " ) ;
return AVERROR ( EINVAL ) ;
}
2018-12-21 20:36:03 +02:00
if ( ctx - > sharpness > = 0 )
codecctl_int ( avctx , VP8E_SET_SHARPNESS , ctx - > sharpness ) ;
2015-06-21 21:07:10 +02:00
if ( CONFIG_LIBVPX_VP8_ENCODER & & avctx - > codec_id = = AV_CODEC_ID_VP8 ) {
2015-09-13 23:45:24 +02:00
codecctl_int ( avctx , VP8E_SET_NOISE_SENSITIVITY , ctx - > noise_sensitivity ) ;
2013-12-07 22:33:58 +03:00
codecctl_int ( avctx , VP8E_SET_TOKEN_PARTITIONS , av_log2 ( avctx - > slices ) ) ;
2015-04-21 09:03:00 +02:00
}
2014-10-08 13:49:11 +03:00
codecctl_int ( avctx , VP8E_SET_STATIC_THRESHOLD , ctx - > static_thresh ) ;
2014-08-27 23:04:08 +03:00
if ( ctx - > crf > = 0 )
codecctl_int ( avctx , VP8E_SET_CQ_LEVEL , ctx - > crf ) ;
2012-06-10 00:40:51 +03:00
if ( ctx - > max_intra_rate > = 0 )
codecctl_int ( avctx , VP8E_SET_MAX_INTRA_BITRATE_PCT , ctx - > max_intra_rate ) ;
2011-05-26 21:20:36 +03:00
2013-11-03 02:20:19 +03:00
# if CONFIG_LIBVPX_VP9_ENCODER
if ( avctx - > codec_id = = AV_CODEC_ID_VP9 ) {
if ( ctx - > lossless > = 0 )
codecctl_int ( avctx , VP9E_SET_LOSSLESS , ctx - > lossless ) ;
if ( ctx - > tile_columns > = 0 )
codecctl_int ( avctx , VP9E_SET_TILE_COLUMNS , ctx - > tile_columns ) ;
if ( ctx - > tile_rows > = 0 )
codecctl_int ( avctx , VP9E_SET_TILE_ROWS , ctx - > tile_rows ) ;
if ( ctx - > frame_parallel > = 0 )
codecctl_int ( avctx , VP9E_SET_FRAME_PARALLEL_DECODING , ctx - > frame_parallel ) ;
2014-08-26 03:17:39 +03:00
if ( ctx - > aq_mode > = 0 )
codecctl_int ( avctx , VP9E_SET_AQ_MODE , ctx - > aq_mode ) ;
2015-06-13 21:27:48 +02:00
set_colorspace ( avctx ) ;
2016-01-09 17:48:49 +02:00
# if VPX_ENCODER_ABI_VERSION >= 11
set_color_range ( avctx ) ;
2016-11-18 23:55:45 +02:00
# endif
# if VPX_ENCODER_ABI_VERSION >= 12
codecctl_int ( avctx , VP9E_SET_TARGET_LEVEL , ctx - > level < 0 ? 255 : lrint ( ctx - > level * 10 ) ) ;
2017-03-02 20:19:09 +02:00
# endif
# ifdef VPX_CTRL_VP9E_SET_ROW_MT
if ( ctx - > row_mt > = 0 )
codecctl_int ( avctx , VP9E_SET_ROW_MT , ctx - > row_mt ) ;
2017-11-14 01:19:07 +02:00
# endif
# ifdef VPX_CTRL_VP9E_SET_TUNE_CONTENT
if ( ctx - > tune_content > = 0 )
codecctl_int ( avctx , VP9E_SET_TUNE_CONTENT , ctx - > tune_content ) ;
2018-11-03 22:30:34 +02:00
# endif
# ifdef VPX_CTRL_VP9E_SET_TPL
if ( ctx - > tpl_model > = 0 )
codecctl_int ( avctx , VP9E_SET_TPL , ctx - > tpl_model ) ;
2022-09-14 02:23:53 +02:00
# endif
# ifdef VPX_CTRL_VP9E_SET_MIN_GF_INTERVAL
if ( ctx - > min_gf_interval > = 0 )
codecctl_int ( avctx , VP9E_SET_MIN_GF_INTERVAL , ctx - > min_gf_interval ) ;
2015-06-13 21:27:48 +02:00
# endif
2013-11-03 02:20:19 +03:00
}
# endif
2024-02-13 08:34:08 +02:00
if ( avctx - > codec_id = = AV_CODEC_ID_VP8 & & ctx - > screen_content_mode > = 0 ) {
if ( ctx - > screen_content_mode = = 2 & & ctx - > is_alpha ) {
av_log ( avctx , AV_LOG_ERROR ,
" Transparency encoding with screen mode with aggressive rate control not supported \n " ) ;
return AVERROR ( EINVAL ) ;
}
codecctl_int ( avctx , VP8E_SET_SCREEN_CONTENT_MODE , ctx - > screen_content_mode ) ;
}
2013-11-03 02:20:19 +03:00
2011-05-26 21:20:36 +03:00
av_log ( avctx , AV_LOG_DEBUG , " Using deadline: %d \n " , ctx - > deadline ) ;
2010-06-03 23:47:59 +03:00
//provide dummy value to initialize wrapper, values will be updated each _encode()
2015-03-26 02:10:16 +02:00
vpx_img_wrap ( & ctx - > rawimg , img_fmt , avctx - > width , avctx - > height , 1 ,
2010-06-03 23:47:59 +03:00
( unsigned char * ) 1 ) ;
2017-11-18 03:25:40 +02:00
# if CONFIG_LIBVPX_VP9_ENCODER
2015-03-26 02:10:16 +02:00
if ( avctx - > codec_id = = AV_CODEC_ID_VP9 & & ( codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH ) )
ctx - > rawimg . bit_depth = enccfg . g_bit_depth ;
# endif
2010-06-03 23:47:59 +03:00
2023-09-04 14:39:07 +02:00
cpb_props = ff_encode_add_cpb_side_data ( avctx ) ;
2015-10-03 15:19:10 +02:00
if ( ! cpb_props )
return AVERROR ( ENOMEM ) ;
if ( enccfg . rc_end_usage = = VPX_CBR | |
enccfg . g_pass ! = VPX_RC_ONE_PASS ) {
cpb_props - > max_bitrate = avctx - > rc_max_rate ;
cpb_props - > min_bitrate = avctx - > rc_min_rate ;
cpb_props - > avg_bitrate = avctx - > bit_rate ;
}
cpb_props - > buffer_size = avctx - > rc_buffer_size ;
2010-06-03 23:47:59 +03:00
return 0 ;
}
static inline void cx_pktcpy ( struct FrameListData * dst ,
2013-03-01 01:14:46 +03:00
const struct vpx_codec_cx_pkt * src ,
2016-07-21 05:41:55 +02:00
VPxContext * ctx )
2010-06-03 23:47:59 +03:00
{
dst - > pts = src - > data . frame . pts ;
dst - > flags = src - > data . frame . flags ;
dst - > sz = src - > data . frame . sz ;
dst - > buf = src - > data . frame . buf ;
2013-03-01 01:14:46 +03:00
dst - > have_sse = 0 ;
2023-02-28 12:30:48 +02:00
/* For alt-ref frame, don't store PSNR */
2013-03-01 01:14:46 +03:00
if ( ! ( dst - > flags & VPX_FRAME_IS_INVISIBLE ) ) {
dst - > have_sse = ctx - > have_sse ;
if ( ctx - > have_sse ) {
/* associate last-seen SSE to the frame. */
/* Transfers ownership from ctx to dst. */
/* WARNING! This makes the assumption that PSNR_PKT comes
just before the frame it refers to ! */
memcpy ( dst - > sse , ctx - > sse , sizeof ( dst - > sse ) ) ;
ctx - > have_sse = 0 ;
}
}
2010-06-03 23:47:59 +03:00
}
/**
2012-02-22 09:38:13 +03:00
* Store coded frame information in format suitable for return from encode2 ( ) .
2010-06-03 23:47:59 +03:00
*
2012-02-22 09:38:13 +03:00
* Write information from @ a cx_frame to @ a pkt
* @ return packet data size on success
* @ return a negative AVERROR on error
2010-06-03 23:47:59 +03:00
*/
static int storeframe ( AVCodecContext * avctx , struct FrameListData * cx_frame ,
2022-08-21 18:08:04 +02:00
struct FrameListData * alpha_cx_frame , AVPacket * pkt )
2010-06-03 23:47:59 +03:00
{
2022-04-05 16:20:46 +02:00
VPxContext * ctx = avctx - > priv_data ;
2021-04-25 01:43:26 +02:00
int ret = ff_get_encode_buffer ( avctx , pkt , cx_frame - > sz , 0 ) ;
2013-05-09 02:59:33 +03:00
uint8_t * side_data ;
2021-04-28 00:06:36 +02:00
int pict_type ;
2022-04-05 16:20:46 +02:00
int quality ;
2013-03-01 01:14:46 +03:00
2021-04-28 00:06:36 +02:00
if ( ret < 0 )
return ret ;
2015-07-29 07:59:42 +02:00
2021-04-28 00:06:36 +02:00
memcpy ( pkt - > data , cx_frame - > buf , pkt - > size ) ;
pkt - > pts = pkt - > dts = cx_frame - > pts ;
if ( ! ! ( cx_frame - > flags & VPX_FRAME_IS_KEY ) ) {
pict_type = AV_PICTURE_TYPE_I ;
pkt - > flags | = AV_PKT_FLAG_KEY ;
2010-06-03 23:47:59 +03:00
} else {
2021-04-28 00:06:36 +02:00
pict_type = AV_PICTURE_TYPE_P ;
}
2022-04-05 16:20:46 +02:00
ret = vpx_codec_control ( & ctx - > encoder , VP8E_GET_LAST_QUANTIZER_64 , & quality ) ;
if ( ret ! = VPX_CODEC_OK )
quality = 0 ;
ff_side_data_set_encoder_stats ( pkt , quality * FF_QP2LAMBDA , cx_frame - > sse + 1 ,
2021-04-28 00:06:36 +02:00
cx_frame - > have_sse ? 3 : 0 , pict_type ) ;
if ( cx_frame - > have_sse ) {
/* Beware of the Y/U/V/all order! */
for ( int i = 0 ; i < 3 ; + + i )
avctx - > error [ i ] + = cx_frame - > sse [ i + 1 ] ;
cx_frame - > have_sse = 0 ;
}
2022-08-21 18:08:04 +02:00
if ( alpha_cx_frame ) {
2021-04-28 00:06:36 +02:00
side_data = av_packet_new_side_data ( pkt ,
AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL ,
2022-08-21 18:08:04 +02:00
alpha_cx_frame - > sz + 8 ) ;
2021-04-28 00:06:36 +02:00
if ( ! side_data ) {
av_packet_unref ( pkt ) ;
return AVERROR ( ENOMEM ) ;
}
AV_WB64 ( side_data , 1 ) ;
2022-08-21 18:08:04 +02:00
memcpy ( side_data + 8 , alpha_cx_frame - > buf , alpha_cx_frame - > sz ) ;
2010-06-03 23:47:59 +03:00
}
2023-02-28 13:20:39 +02:00
ret = frame_data_apply ( avctx , ctx - > fifo , pkt ) ;
if ( ret < 0 )
return ret ;
2021-06-18 07:20:44 +02:00
2012-02-22 09:38:13 +03:00
return pkt - > size ;
2010-06-03 23:47:59 +03:00
}
/**
* Queue multiple output frames from the encoder , returning the front - most .
* In cases where vpx_codec_get_cx_data ( ) returns more than 1 frame append
* the frame queue . Return the head frame if available .
* @ return Stored frame size
* @ return AVERROR ( EINVAL ) on output size error
* @ return AVERROR ( ENOMEM ) on coded frame queue data allocation error
*/
2022-08-21 18:08:04 +02:00
static int queue_frames ( AVCodecContext * avctx , struct vpx_codec_ctx * encoder ,
struct FrameListData * * frame_list , AVPacket * pkt_out )
2010-06-03 23:47:59 +03:00
{
2016-07-21 05:41:55 +02:00
VPxContext * ctx = avctx - > priv_data ;
2010-06-03 23:47:59 +03:00
const struct vpx_codec_cx_pkt * pkt ;
const void * iter = NULL ;
int size = 0 ;
2022-08-21 18:08:04 +02:00
if ( ! ctx - > is_alpha & & * frame_list ) {
struct FrameListData * cx_frame = * frame_list ;
2010-06-03 23:47:59 +03:00
/* return the leading frame if we've already begun queueing */
2022-08-21 18:08:04 +02:00
size = storeframe ( avctx , cx_frame , NULL , pkt_out ) ;
2010-06-03 23:47:59 +03:00
if ( size < 0 )
2012-02-22 09:38:13 +03:00
return size ;
2022-08-21 18:08:04 +02:00
* frame_list = cx_frame - > next ;
2010-06-03 23:47:59 +03:00
free_coded_frame ( cx_frame ) ;
}
/* consume all available output from the encoder before returning. buffers
are only good through the next vpx_codec call */
2022-08-21 18:08:04 +02:00
while ( pkt = vpx_codec_get_cx_data ( encoder , & iter ) ) {
2010-06-03 23:47:59 +03:00
switch ( pkt - > kind ) {
case VPX_CODEC_CX_FRAME_PKT :
2022-08-21 18:08:04 +02:00
if ( ! ctx - > is_alpha & & ! size ) {
2010-06-03 23:47:59 +03:00
struct FrameListData cx_frame ;
/* avoid storing the frame when the list is empty and we haven't yet
provided a frame for output */
2012-07-25 22:35:48 +03:00
av_assert0 ( ! ctx - > coded_frame_list ) ;
2022-08-21 18:08:04 +02:00
cx_pktcpy ( & cx_frame , pkt , ctx ) ;
size = storeframe ( avctx , & cx_frame , NULL , pkt_out ) ;
2010-06-03 23:47:59 +03:00
if ( size < 0 )
2012-02-22 09:38:13 +03:00
return size ;
2010-06-03 23:47:59 +03:00
} else {
2020-01-04 01:01:43 +02:00
struct FrameListData * cx_frame = av_malloc ( sizeof ( * cx_frame ) ) ;
2010-06-03 23:47:59 +03:00
if ( ! cx_frame ) {
av_log ( avctx , AV_LOG_ERROR ,
" Frame queue element alloc failed \n " ) ;
return AVERROR ( ENOMEM ) ;
}
2022-08-21 18:08:04 +02:00
cx_pktcpy ( cx_frame , pkt , ctx ) ;
2010-06-03 23:47:59 +03:00
cx_frame - > buf = av_malloc ( cx_frame - > sz ) ;
if ( ! cx_frame - > buf ) {
av_log ( avctx , AV_LOG_ERROR ,
2014-04-24 19:01:30 +03:00
" Data buffer alloc (% " SIZE_SPECIFIER " bytes) failed \n " ,
2010-06-03 23:47:59 +03:00
cx_frame - > sz ) ;
2014-11-17 01:22:28 +02:00
av_freep ( & cx_frame ) ;
2010-06-03 23:47:59 +03:00
return AVERROR ( ENOMEM ) ;
}
memcpy ( cx_frame - > buf , pkt - > data . frame . buf , pkt - > data . frame . sz ) ;
2022-08-21 18:08:04 +02:00
coded_frame_add ( frame_list , cx_frame ) ;
2010-06-03 23:47:59 +03:00
}
break ;
case VPX_CODEC_STATS_PKT : {
struct vpx_fixed_buf * stats = & ctx - > twopass_stats ;
2022-08-24 01:20:10 +02:00
uint8_t * tmp ;
2022-08-21 18:08:04 +02:00
if ( ! pkt_out )
break ;
2022-08-24 01:20:10 +02:00
tmp = av_fast_realloc ( stats - > buf ,
& ctx - > twopass_stats_size ,
stats - > sz +
pkt - > data . twopass_stats . sz ) ;
if ( ! tmp ) {
av_freep ( & stats - > buf ) ;
2013-12-06 15:44:17 +03:00
stats - > sz = 0 ;
2010-06-03 23:47:59 +03:00
av_log ( avctx , AV_LOG_ERROR , " Stat buffer realloc failed \n " ) ;
2022-08-24 01:20:10 +02:00
return AVERROR ( ENOMEM ) ;
2010-06-03 23:47:59 +03:00
}
2022-08-24 01:20:10 +02:00
stats - > buf = tmp ;
2010-06-03 23:47:59 +03:00
memcpy ( ( uint8_t * ) stats - > buf + stats - > sz ,
pkt - > data . twopass_stats . buf , pkt - > data . twopass_stats . sz ) ;
stats - > sz + = pkt - > data . twopass_stats . sz ;
break ;
}
2013-03-01 01:14:46 +03:00
case VPX_CODEC_PSNR_PKT :
2022-08-21 18:08:04 +02:00
if ( ! pkt_out )
break ;
2013-03-01 01:14:46 +03:00
av_assert0 ( ! ctx - > have_sse ) ;
ctx - > sse [ 0 ] = pkt - > data . psnr . sse [ 0 ] ;
ctx - > sse [ 1 ] = pkt - > data . psnr . sse [ 1 ] ;
ctx - > sse [ 2 ] = pkt - > data . psnr . sse [ 2 ] ;
ctx - > sse [ 3 ] = pkt - > data . psnr . sse [ 3 ] ;
ctx - > have_sse = 1 ;
break ;
2010-06-03 23:47:59 +03:00
case VPX_CODEC_CUSTOM_PKT :
//ignore unsupported/unrecognized packet types
break ;
}
}
return size ;
}
2019-09-12 12:25:21 +02:00
static int set_roi_map ( AVCodecContext * avctx , const AVFrameSideData * sd , int frame_width , int frame_height ,
vpx_roi_map_t * roi_map , int block_size , int segment_cnt )
{
/**
* range of vpx_roi_map_t . delta_q [ i ] is [ - 63 , 63 ]
*/
# define MAX_DELTA_Q 63
const AVRegionOfInterest * roi = NULL ;
int nb_rois ;
uint32_t self_size ;
int segment_id ;
/* record the mapping from delta_q to "segment id + 1" in segment_mapping[].
* the range of delta_q is [ - MAX_DELTA_Q , MAX_DELTA_Q ] ,
* and its corresponding array index is [ 0 , 2 * MAX_DELTA_Q ] ,
* and so the length of the mapping array is 2 * MAX_DELTA_Q + 1.
* " segment id + 1 " , so we can say there ' s no mapping if the value of array element is zero .
*/
int segment_mapping [ 2 * MAX_DELTA_Q + 1 ] = { 0 } ;
memset ( roi_map , 0 , sizeof ( * roi_map ) ) ;
/* segment id 0 in roi_map is reserved for the areas not covered by AVRegionOfInterest.
* segment id 0 in roi_map is also for the areas with AVRegionOfInterest . qoffset near 0.
* ( delta_q of segment id 0 is 0 ) .
*/
segment_mapping [ MAX_DELTA_Q ] = 1 ;
segment_id = 1 ;
roi = ( const AVRegionOfInterest * ) sd - > data ;
self_size = roi - > self_size ;
if ( ! self_size | | sd - > size % self_size ) {
av_log ( avctx , AV_LOG_ERROR , " Invalid AVRegionOfInterest.self_size. \n " ) ;
return AVERROR ( EINVAL ) ;
}
nb_rois = sd - > size / self_size ;
/* This list must be iterated from zero because regions are
* defined in order of decreasing importance . So discard less
* important areas if they exceed the segment count .
*/
for ( int i = 0 ; i < nb_rois ; i + + ) {
int delta_q ;
int mapping_index ;
roi = ( const AVRegionOfInterest * ) ( sd - > data + self_size * i ) ;
if ( ! roi - > qoffset . den ) {
av_log ( avctx , AV_LOG_ERROR , " AVRegionOfInterest.qoffset.den must not be zero. \n " ) ;
return AVERROR ( EINVAL ) ;
}
delta_q = ( int ) ( roi - > qoffset . num * 1.0f / roi - > qoffset . den * MAX_DELTA_Q ) ;
delta_q = av_clip ( delta_q , - MAX_DELTA_Q , MAX_DELTA_Q ) ;
mapping_index = delta_q + MAX_DELTA_Q ;
if ( ! segment_mapping [ mapping_index ] ) {
if ( segment_id = = segment_cnt ) {
av_log ( avctx , AV_LOG_WARNING ,
" ROI only supports %d segments (and segment 0 is reserved for non-ROIs), skipping the left ones. \n " ,
segment_cnt ) ;
break ;
}
segment_mapping [ mapping_index ] = segment_id + 1 ;
roi_map - > delta_q [ segment_id ] = delta_q ;
segment_id + + ;
}
}
roi_map - > rows = ( frame_height + block_size - 1 ) / block_size ;
roi_map - > cols = ( frame_width + block_size - 1 ) / block_size ;
2021-09-14 21:31:53 +02:00
roi_map - > roi_map = av_calloc ( roi_map - > rows * roi_map - > cols , sizeof ( * roi_map - > roi_map ) ) ;
2019-09-12 12:25:21 +02:00
if ( ! roi_map - > roi_map ) {
av_log ( avctx , AV_LOG_ERROR , " roi_map alloc failed. \n " ) ;
return AVERROR ( ENOMEM ) ;
}
/* This list must be iterated in reverse, so for the case that
* two regions are overlapping , the more important area takes effect .
*/
for ( int i = nb_rois - 1 ; i > = 0 ; i - - ) {
int delta_q ;
int mapping_value ;
int starty , endy , startx , endx ;
roi = ( const AVRegionOfInterest * ) ( sd - > data + self_size * i ) ;
starty = av_clip ( roi - > top / block_size , 0 , roi_map - > rows ) ;
endy = av_clip ( ( roi - > bottom + block_size - 1 ) / block_size , 0 , roi_map - > rows ) ;
startx = av_clip ( roi - > left / block_size , 0 , roi_map - > cols ) ;
endx = av_clip ( ( roi - > right + block_size - 1 ) / block_size , 0 , roi_map - > cols ) ;
delta_q = ( int ) ( roi - > qoffset . num * 1.0f / roi - > qoffset . den * MAX_DELTA_Q ) ;
delta_q = av_clip ( delta_q , - MAX_DELTA_Q , MAX_DELTA_Q ) ;
mapping_value = segment_mapping [ delta_q + MAX_DELTA_Q ] ;
if ( mapping_value ) {
for ( int y = starty ; y < endy ; y + + )
for ( int x = startx ; x < endx ; x + + )
roi_map - > roi_map [ x + y * roi_map - > cols ] = mapping_value - 1 ;
}
}
return 0 ;
}
static int vp9_encode_set_roi ( AVCodecContext * avctx , int frame_width , int frame_height , const AVFrameSideData * sd )
{
VPxContext * ctx = avctx - > priv_data ;
# ifdef VPX_CTRL_VP9E_SET_ROI_MAP
int version = vpx_codec_version ( ) ;
int major = VPX_VERSION_MAJOR ( version ) ;
int minor = VPX_VERSION_MINOR ( version ) ;
int patch = VPX_VERSION_PATCH ( version ) ;
if ( major > 1 | | ( major = = 1 & & minor > 8 ) | | ( major = = 1 & & minor = = 8 & & patch > = 1 ) ) {
vpx_roi_map_t roi_map ;
const int segment_cnt = 8 ;
const int block_size = 8 ;
int ret ;
if ( ctx - > aq_mode > 0 | | ctx - > cpu_used < 5 | | ctx - > deadline ! = VPX_DL_REALTIME ) {
if ( ! ctx - > roi_warned ) {
ctx - > roi_warned = 1 ;
av_log ( avctx , AV_LOG_WARNING , " ROI is only enabled when aq_mode is 0, cpu_used >= 5 "
" and deadline is REALTIME, so skipping ROI. \n " ) ;
return AVERROR ( EINVAL ) ;
}
}
ret = set_roi_map ( avctx , sd , frame_width , frame_height , & roi_map , block_size , segment_cnt ) ;
if ( ret ) {
log_encoder_error ( avctx , " Failed to set_roi_map. \n " ) ;
return ret ;
}
memset ( roi_map . ref_frame , - 1 , sizeof ( roi_map . ref_frame ) ) ;
if ( vpx_codec_control ( & ctx - > encoder , VP9E_SET_ROI_MAP , & roi_map ) ) {
log_encoder_error ( avctx , " Failed to set VP9E_SET_ROI_MAP codec control. \n " ) ;
ret = AVERROR_INVALIDDATA ;
}
av_freep ( & roi_map . roi_map ) ;
return ret ;
}
# endif
if ( ! ctx - > roi_warned ) {
ctx - > roi_warned = 1 ;
av_log ( avctx , AV_LOG_WARNING , " ROI is not supported, please upgrade libvpx to version >= 1.8.1. "
" You may need to rebuild ffmpeg. \n " ) ;
}
return 0 ;
}
static int vp8_encode_set_roi ( AVCodecContext * avctx , int frame_width , int frame_height , const AVFrameSideData * sd )
{
vpx_roi_map_t roi_map ;
const int segment_cnt = 4 ;
const int block_size = 16 ;
VPxContext * ctx = avctx - > priv_data ;
int ret = set_roi_map ( avctx , sd , frame_width , frame_height , & roi_map , block_size , segment_cnt ) ;
if ( ret ) {
log_encoder_error ( avctx , " Failed to set_roi_map. \n " ) ;
return ret ;
}
if ( vpx_codec_control ( & ctx - > encoder , VP8E_SET_ROI_MAP , & roi_map ) ) {
log_encoder_error ( avctx , " Failed to set VP8E_SET_ROI_MAP codec control. \n " ) ;
ret = AVERROR_INVALIDDATA ;
}
av_freep ( & roi_map . roi_map ) ;
return ret ;
}
2019-11-02 18:20:21 +02:00
static int realloc_alpha_uv ( AVCodecContext * avctx , int width , int height )
{
VPxContext * ctx = avctx - > priv_data ;
struct vpx_image * rawimg_alpha = & ctx - > rawimg_alpha ;
unsigned char * * planes = rawimg_alpha - > planes ;
int * stride = rawimg_alpha - > stride ;
if ( ! planes [ VPX_PLANE_U ] | |
! planes [ VPX_PLANE_V ] | |
width ! = ( int ) rawimg_alpha - > d_w | |
height ! = ( int ) rawimg_alpha - > d_h ) {
av_freep ( & planes [ VPX_PLANE_U ] ) ;
av_freep ( & planes [ VPX_PLANE_V ] ) ;
vpx_img_wrap ( rawimg_alpha , VPX_IMG_FMT_I420 , width , height , 1 ,
( unsigned char * ) 1 ) ;
planes [ VPX_PLANE_U ] = av_malloc_array ( stride [ VPX_PLANE_U ] , height ) ;
planes [ VPX_PLANE_V ] = av_malloc_array ( stride [ VPX_PLANE_V ] , height ) ;
if ( ! planes [ VPX_PLANE_U ] | | ! planes [ VPX_PLANE_V ] )
return AVERROR ( ENOMEM ) ;
memset ( planes [ VPX_PLANE_U ] , 0x80 , stride [ VPX_PLANE_U ] * height ) ;
memset ( planes [ VPX_PLANE_V ] , 0x80 , stride [ VPX_PLANE_V ] * height ) ;
}
return 0 ;
}
2016-07-21 05:41:55 +02:00
static int vpx_encode ( AVCodecContext * avctx , AVPacket * pkt ,
2012-02-22 09:38:13 +03:00
const AVFrame * frame , int * got_packet )
2010-06-03 23:47:59 +03:00
{
2016-07-21 05:41:55 +02:00
VPxContext * ctx = avctx - > priv_data ;
2010-06-03 23:47:59 +03:00
struct vpx_image * rawimg = NULL ;
2013-05-09 02:59:33 +03:00
struct vpx_image * rawimg_alpha = NULL ;
2010-06-03 23:47:59 +03:00
int64_t timestamp = 0 ;
int res , coded_size ;
2012-12-05 18:17:20 +03:00
vpx_enc_frame_flags_t flags = 0 ;
2020-02-03 20:02:01 +02:00
const struct vpx_codec_enc_cfg * enccfg = ctx - > encoder . config . enc ;
vpx_svc_layer_id_t layer_id ;
int layer_id_valid = 0 ;
2023-05-04 11:35:31 +02:00
unsigned long duration = 0 ;
2010-06-03 23:47:59 +03:00
2022-03-30 20:24:32 +02:00
if ( avctx - > qmax > = 0 & & enccfg - > rc_max_quantizer ! = avctx - > qmax ) {
struct vpx_codec_enc_cfg cfg = * enccfg ;
cfg . rc_max_quantizer = avctx - > qmax ;
res = vpx_codec_enc_config_set ( & ctx - > encoder , & cfg ) ;
if ( res ! = VPX_CODEC_OK ) {
log_encoder_error ( avctx , " Error reconfiguring encoder " ) ;
return AVERROR_INVALIDDATA ;
}
}
2010-06-03 23:47:59 +03:00
if ( frame ) {
2019-09-12 12:25:21 +02:00
const AVFrameSideData * sd = av_frame_get_side_data ( frame , AV_FRAME_DATA_REGIONS_OF_INTEREST ) ;
2010-06-03 23:47:59 +03:00
rawimg = & ctx - > rawimg ;
rawimg - > planes [ VPX_PLANE_Y ] = frame - > data [ 0 ] ;
rawimg - > planes [ VPX_PLANE_U ] = frame - > data [ 1 ] ;
rawimg - > planes [ VPX_PLANE_V ] = frame - > data [ 2 ] ;
rawimg - > stride [ VPX_PLANE_Y ] = frame - > linesize [ 0 ] ;
rawimg - > stride [ VPX_PLANE_U ] = frame - > linesize [ 1 ] ;
rawimg - > stride [ VPX_PLANE_V ] = frame - > linesize [ 2 ] ;
2013-05-09 02:59:33 +03:00
if ( ctx - > is_alpha ) {
rawimg_alpha = & ctx - > rawimg_alpha ;
2019-11-02 18:20:21 +02:00
res = realloc_alpha_uv ( avctx , frame - > width , frame - > height ) ;
if ( res < 0 )
return res ;
2013-05-09 02:59:33 +03:00
rawimg_alpha - > planes [ VPX_PLANE_Y ] = frame - > data [ 3 ] ;
2019-10-27 19:10:31 +02:00
rawimg_alpha - > stride [ VPX_PLANE_Y ] = frame - > linesize [ 3 ] ;
2013-05-09 02:59:33 +03:00
}
2010-06-03 23:47:59 +03:00
timestamp = frame - > pts ;
2016-07-22 09:33:04 +02:00
# if VPX_IMAGE_ABI_VERSION >= 4
switch ( frame - > color_range ) {
case AVCOL_RANGE_MPEG :
rawimg - > range = VPX_CR_STUDIO_RANGE ;
break ;
case AVCOL_RANGE_JPEG :
rawimg - > range = VPX_CR_FULL_RANGE ;
break ;
}
# endif
2012-12-05 18:17:20 +03:00
if ( frame - > pict_type = = AV_PICTURE_TYPE_I )
flags | = VPX_EFLAG_FORCE_KF ;
2020-02-10 20:30:09 +02:00
if ( frame - > metadata ) {
2018-11-14 22:56:31 +02:00
AVDictionaryEntry * en = av_dict_get ( frame - > metadata , " vp8-flags " , NULL , 0 ) ;
if ( en ) {
flags | = strtoul ( en - > value , NULL , 10 ) ;
}
2020-02-10 20:30:09 +02:00
memset ( & layer_id , 0 , sizeof ( layer_id ) ) ;
en = av_dict_get ( frame - > metadata , " temporal_id " , NULL , 0 ) ;
if ( en ) {
layer_id . temporal_layer_id = strtoul ( en - > value , NULL , 10 ) ;
# ifdef VPX_CTRL_VP9E_SET_MAX_INTER_BITRATE_PCT
layer_id . temporal_layer_id_per_spatial [ 0 ] = layer_id . temporal_layer_id ;
# endif
layer_id_valid = 1 ;
}
2021-01-09 01:33:29 +02:00
# if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_CTRL_VP9E_SET_MAX_INTER_BITRATE_PCT)
en = av_dict_get ( frame - > metadata , " ref-frame-config " , NULL , 0 ) ;
if ( en ) {
if ( avctx - > codec_id = = AV_CODEC_ID_VP9 ) {
2021-02-18 21:01:31 +02:00
int ret = vpx_parse_ref_frame_config ( & ctx - > ref_frame_config ,
enccfg - > ss_number_layers , en - > value ) ;
if ( ret < 0 ) {
av_log ( avctx , AV_LOG_WARNING ,
" Error parsing ref_frame_config option %s. \n " , en - > value ) ;
return ret ;
2021-01-09 01:33:29 +02:00
}
codecctl_intp ( avctx , VP9E_SET_SVC_REF_FRAME_CONFIG , ( int * ) & ctx - > ref_frame_config ) ;
} else {
av_log ( avctx , AV_LOG_WARNING ,
2021-02-18 21:01:31 +02:00
" Ignoring ref-frame-config for a non-VP9 codec \n " ) ;
2021-01-09 01:33:29 +02:00
}
}
# endif
2018-11-14 22:56:31 +02:00
}
2019-09-12 12:25:21 +02:00
if ( sd ) {
if ( avctx - > codec_id = = AV_CODEC_ID_VP8 ) {
vp8_encode_set_roi ( avctx , frame - > width , frame - > height , sd ) ;
} else {
vp9_encode_set_roi ( avctx , frame - > width , frame - > height , sd ) ;
}
}
2021-06-18 07:20:44 +02:00
2023-07-07 23:31:03 +02:00
if ( ! ( avctx - > flags & AV_CODEC_FLAG_PASS1 ) ) {
res = frame_data_submit ( avctx , ctx - > fifo , frame ) ;
if ( res < 0 )
return res ;
}
2010-06-03 23:47:59 +03:00
}
2020-02-03 20:02:01 +02:00
// this is for encoding with preset temporal layering patterns defined in
// set_temporal_layer_pattern function.
if ( enccfg - > ts_number_layers > 1 & & ctx - > ts_layer_flags ) {
if ( flags & VPX_EFLAG_FORCE_KF ) {
// keyframe, reset temporal layering.
ctx - > current_temporal_idx = 0 ;
flags = VPX_EFLAG_FORCE_KF ;
} else {
flags = 0 ;
}
/* get the flags from the temporal layer configuration. */
flags | = ctx - > ts_layer_flags [ ctx - > current_temporal_idx ] ;
memset ( & layer_id , 0 , sizeof ( layer_id ) ) ;
# if VPX_ENCODER_ABI_VERSION >= 12
layer_id . spatial_layer_id = 0 ;
# endif
layer_id . temporal_layer_id = enccfg - > ts_layer_id [ ctx - > current_temporal_idx ] ;
# ifdef VPX_CTRL_VP9E_SET_MAX_INTER_BITRATE_PCT
layer_id . temporal_layer_id_per_spatial [ 0 ] = layer_id . temporal_layer_id ;
# endif
layer_id_valid = 1 ;
}
if ( layer_id_valid ) {
if ( avctx - > codec_id = = AV_CODEC_ID_VP8 ) {
codecctl_int ( avctx , VP8E_SET_TEMPORAL_LAYER_ID , layer_id . temporal_layer_id ) ;
}
# if CONFIG_LIBVPX_VP9_ENCODER && VPX_ENCODER_ABI_VERSION >= 12
else if ( avctx - > codec_id = = AV_CODEC_ID_VP9 ) {
codecctl_intp ( avctx , VP9E_SET_SVC_LAYER_ID , ( int * ) & layer_id ) ;
}
# endif
}
2023-05-04 11:35:31 +02:00
if ( frame & & frame - > duration > ULONG_MAX ) {
av_log ( avctx , AV_LOG_WARNING ,
" Frame duration too large: % " PRId64 " \n " , frame - > duration ) ;
} else if ( frame & & frame - > duration )
duration = frame - > duration ;
else if ( avctx - > framerate . num > 0 & & avctx - > framerate . den > 0 )
duration = av_rescale_q ( 1 , av_inv_q ( avctx - > framerate ) , avctx - > time_base ) ;
2023-07-22 19:24:15 +02:00
else {
2023-05-04 11:50:48 +02:00
FF_DISABLE_DEPRECATION_WARNINGS
duration =
# if FF_API_TICKS_PER_FRAME
avctx - > ticks_per_frame ? avctx - > ticks_per_frame :
# endif
1 ;
FF_ENABLE_DEPRECATION_WARNINGS
2023-07-22 19:24:15 +02:00
}
2023-05-04 11:35:31 +02:00
2010-06-03 23:47:59 +03:00
res = vpx_codec_encode ( & ctx - > encoder , rawimg , timestamp ,
2023-05-04 11:35:31 +02:00
duration , flags , ctx - > deadline ) ;
2010-06-03 23:47:59 +03:00
if ( res ! = VPX_CODEC_OK ) {
log_encoder_error ( avctx , " Error encoding frame " ) ;
return AVERROR_INVALIDDATA ;
}
2013-05-09 02:59:33 +03:00
if ( ctx - > is_alpha ) {
res = vpx_codec_encode ( & ctx - > encoder_alpha , rawimg_alpha , timestamp ,
2023-05-04 11:35:31 +02:00
duration , flags , ctx - > deadline ) ;
2013-05-09 02:59:33 +03:00
if ( res ! = VPX_CODEC_OK ) {
log_encoder_error ( avctx , " Error encoding alpha frame " ) ;
return AVERROR_INVALIDDATA ;
}
}
2022-08-21 18:08:04 +02:00
coded_size = queue_frames ( avctx , & ctx - > encoder , & ctx - > coded_frame_list , pkt ) ;
if ( ctx - > is_alpha ) {
queue_frames ( avctx , & ctx - > encoder_alpha , & ctx - > alpha_coded_frame_list , NULL ) ;
if ( ctx - > coded_frame_list & & ctx - > alpha_coded_frame_list ) {
struct FrameListData * cx_frame = ctx - > coded_frame_list ;
struct FrameListData * alpha_cx_frame = ctx - > alpha_coded_frame_list ;
av_assert0 ( ! coded_size ) ;
/* return the leading frame if we've already begun queueing */
coded_size = storeframe ( avctx , cx_frame , alpha_cx_frame , pkt ) ;
if ( coded_size < 0 )
return coded_size ;
ctx - > coded_frame_list = cx_frame - > next ;
ctx - > alpha_coded_frame_list = alpha_cx_frame - > next ;
free_coded_frame ( cx_frame ) ;
free_coded_frame ( alpha_cx_frame ) ;
}
}
2010-06-03 23:47:59 +03:00
2015-06-29 21:59:37 +02:00
if ( ! frame & & avctx - > flags & AV_CODEC_FLAG_PASS1 ) {
2010-06-08 00:34:56 +03:00
unsigned int b64_size = AV_BASE64_SIZE ( ctx - > twopass_stats . sz ) ;
2010-06-03 23:47:59 +03:00
avctx - > stats_out = av_malloc ( b64_size ) ;
if ( ! avctx - > stats_out ) {
av_log ( avctx , AV_LOG_ERROR , " Stat buffer alloc (%d bytes) failed \n " ,
b64_size ) ;
return AVERROR ( ENOMEM ) ;
}
av_base64_encode ( avctx - > stats_out , b64_size , ctx - > twopass_stats . buf ,
ctx - > twopass_stats . sz ) ;
2020-02-03 20:02:01 +02:00
} else if ( enccfg - > ts_number_layers > 1 & & ctx - > ts_layer_flags ) {
ctx - > current_temporal_idx = ( ctx - > current_temporal_idx + 1 ) % enccfg - > ts_periodicity ;
2010-06-03 23:47:59 +03:00
}
2012-02-22 09:38:13 +03:00
* got_packet = ! ! coded_size ;
return 0 ;
2010-06-03 23:47:59 +03:00
}
2016-07-21 05:41:55 +02:00
# define OFFSET(x) offsetof(VPxContext, x)
2011-10-02 21:38:38 +03:00
# define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
2013-11-02 22:09:01 +03:00
# define COMMON_OPTIONS \
{ " lag-in-frames " , " Number of frames to look ahead for " \
" alternate reference frame selection " , OFFSET ( lag_in_frames ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , VE } , \
{ " arnr-maxframes " , " altref noise reduction max frame count " , OFFSET ( arnr_max_frames ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , VE } , \
{ " arnr-strength " , " altref noise reduction filter strength " , OFFSET ( arnr_strength ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , VE } , \
2024-02-11 16:41:05 +02:00
{ " arnr-type " , " altref noise reduction filter type " , OFFSET ( arnr_type ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , VE , . unit = " arnr_type " } , \
{ " backward " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 1 } , 0 , 0 , VE , . unit = " arnr_type " } , \
{ " forward " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 2 } , 0 , 0 , VE , . unit = " arnr_type " } , \
{ " centered " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = 3 } , 0 , 0 , VE , . unit = " arnr_type " } , \
{ " tune " , " Tune the encoding to a specific scenario " , OFFSET ( tune ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , VE , . unit = " tune " } , \
{ " psnr " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = VP8_TUNE_PSNR } , 0 , 0 , VE , . unit = " tune " } , \
{ " ssim " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = VP8_TUNE_SSIM } , 0 , 0 , VE , . unit = " tune " } , \
{ " deadline " , " Time to spend encoding, in microseconds. " , OFFSET ( deadline ) , AV_OPT_TYPE_INT , { . i64 = VPX_DL_GOOD_QUALITY } , INT_MIN , INT_MAX , VE , . unit = " quality " } , \
{ " best " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = VPX_DL_BEST_QUALITY } , 0 , 0 , VE , . unit = " quality " } , \
{ " good " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = VPX_DL_GOOD_QUALITY } , 0 , 0 , VE , . unit = " quality " } , \
{ " realtime " , NULL , 0 , AV_OPT_TYPE_CONST , { . i64 = VPX_DL_REALTIME } , 0 , 0 , VE , . unit = " quality " } , \
{ " error-resilient " , " Error resilience configuration " , OFFSET ( error_resilient ) , AV_OPT_TYPE_FLAGS , { . i64 = 0 } , INT_MIN , INT_MAX , VE , . unit = " er " } , \
2013-11-02 22:09:01 +03:00
{ " max-intra-rate " , " Maximum I-frame bitrate (pct) 0=unlimited " , OFFSET ( max_intra_rate ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , VE } , \
2024-02-11 16:41:05 +02:00
{ " default " , " Improve resiliency against losses of whole frames " , 0 , AV_OPT_TYPE_CONST , { . i64 = VPX_ERROR_RESILIENT_DEFAULT } , 0 , 0 , VE , . unit = " er " } , \
2013-11-02 22:09:01 +03:00
{ " partitions " , " The frame partitions are independently decodable " \
" by the bool decoder, meaning that partitions can be decoded even " \
2019-11-09 03:48:29 +02:00
" though earlier partitions have been lost. Note that intra prediction " \
2024-02-11 16:41:05 +02:00
" is still done over the partition boundary. " , 0 , AV_OPT_TYPE_CONST , { . i64 = VPX_ERROR_RESILIENT_PARTITIONS } , 0 , 0 , VE , . unit = " er " } , \
2016-07-21 05:41:55 +02:00
{ " crf " , " Select the quality for constant quality mode " , offsetof ( VPxContext , crf ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 63 , VE } , \
2014-10-18 16:33:57 +03:00
{ " static-thresh " , " A change threshold on blocks below which they will be skipped by the encoder " , OFFSET ( static_thresh ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , INT_MAX , VE } , \
2016-07-21 05:41:55 +02:00
{ " drop-threshold " , " Frame drop threshold " , offsetof ( VPxContext , drop_threshold ) , AV_OPT_TYPE_INT , { . i64 = 0 } , INT_MIN , INT_MAX , VE } , \
2016-01-28 18:38:04 +02:00
{ " noise-sensitivity " , " Noise sensitivity " , OFFSET ( noise_sensitivity ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , 4 , VE } , \
2015-06-06 19:10:56 +02:00
{ " undershoot-pct " , " Datarate undershoot (min) target (%) " , OFFSET ( rc_undershoot_pct ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 100 , VE } , \
2015-06-06 19:24:44 +02:00
{ " overshoot-pct " , " Datarate overshoot (max) target (%) " , OFFSET ( rc_overshoot_pct ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 1000 , VE } , \
2020-02-03 20:02:01 +02:00
{ " ts-parameters " , " Temporal scaling configuration using a :-separated list of key=value parameters " , OFFSET ( vpx_ts_parameters ) , AV_OPT_TYPE_DICT , { . str = NULL } , 0 , 0 , VE } , \
2013-11-02 22:09:01 +03:00
# define LEGACY_OPTIONS \
2016-07-21 05:41:55 +02:00
{ " speed " , " " , offsetof ( VPxContext , cpu_used ) , AV_OPT_TYPE_INT , { . i64 = 1 } , - 16 , 16 , VE } , \
2024-02-11 16:41:05 +02:00
{ " quality " , " " , offsetof ( VPxContext , deadline ) , AV_OPT_TYPE_INT , { . i64 = VPX_DL_GOOD_QUALITY } , INT_MIN , INT_MAX , VE , . unit = " quality " } , \
{ " vp8flags " , " " , offsetof ( VPxContext , flags ) , AV_OPT_TYPE_FLAGS , { . i64 = 0 } , 0 , UINT_MAX , VE , . unit = " flags " } , \
{ " error_resilient " , " enable error resilience " , 0 , AV_OPT_TYPE_CONST , { . i64 = VP8F_ERROR_RESILIENT } , INT_MIN , INT_MAX , VE , . unit = " flags " } , \
{ " altref " , " enable use of alternate reference frames (VP8/2-pass only) " , 0 , AV_OPT_TYPE_CONST , { . i64 = VP8F_AUTO_ALT_REF } , INT_MIN , INT_MAX , VE , . unit = " flags " } , \
2016-07-21 05:41:55 +02:00
{ " arnr_max_frames " , " altref noise reduction max frame count " , offsetof ( VPxContext , arnr_max_frames ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , 15 , VE } , \
{ " arnr_strength " , " altref noise reduction filter strength " , offsetof ( VPxContext , arnr_strength ) , AV_OPT_TYPE_INT , { . i64 = 3 } , 0 , 6 , VE } , \
{ " arnr_type " , " altref noise reduction filter type " , offsetof ( VPxContext , arnr_type ) , AV_OPT_TYPE_INT , { . i64 = 3 } , 1 , 3 , VE } , \
{ " rc_lookahead " , " Number of frames to look ahead for alternate reference frame selection " , offsetof ( VPxContext , lag_in_frames ) , AV_OPT_TYPE_INT , { . i64 = 25 } , 0 , 25 , VE } , \
2018-12-21 20:36:03 +02:00
{ " sharpness " , " Increase sharpness at the expense of lower PSNR " , offsetof ( VPxContext , sharpness ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 7 , VE } ,
2013-11-02 22:09:01 +03:00
# if CONFIG_LIBVPX_VP8_ENCODER
static const AVOption vp8_options [ ] = {
COMMON_OPTIONS
2018-11-03 22:50:32 +02:00
{ " auto-alt-ref " , " Enable use of alternate reference "
" frames (2-pass only) " , OFFSET ( auto_alt_ref ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 2 , VE } ,
2016-01-09 11:53:22 +02:00
{ " cpu-used " , " Quality/Speed ratio modifier " , OFFSET ( cpu_used ) , AV_OPT_TYPE_INT , { . i64 = 1 } , - 16 , 16 , VE } ,
2024-02-13 08:34:08 +02:00
{ " screen-content-mode " , " Encoder screen content mode " , OFFSET ( screen_content_mode ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 2 , VE } ,
2013-11-02 22:09:01 +03:00
LEGACY_OPTIONS
2011-09-26 11:22:38 +03:00
{ NULL }
} ;
2013-11-02 22:09:01 +03:00
# endif
# if CONFIG_LIBVPX_VP9_ENCODER
static const AVOption vp9_options [ ] = {
COMMON_OPTIONS
2018-11-03 22:50:32 +02:00
{ " auto-alt-ref " , " Enable use of alternate reference "
" frames (2-pass only) " , OFFSET ( auto_alt_ref ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 6 , VE } ,
2016-01-09 11:53:22 +02:00
{ " cpu-used " , " Quality/Speed ratio modifier " , OFFSET ( cpu_used ) , AV_OPT_TYPE_INT , { . i64 = 1 } , - 8 , 8 , VE } ,
2013-11-03 02:20:19 +03:00
{ " lossless " , " Lossless mode " , OFFSET ( lossless ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 1 , VE } ,
{ " tile-columns " , " Number of tile columns to use, log2 " , OFFSET ( tile_columns ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 6 , VE } ,
{ " tile-rows " , " Number of tile rows to use, log2 " , OFFSET ( tile_rows ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 2 , VE } ,
2015-11-21 23:04:39 +02:00
{ " frame-parallel " , " Enable frame parallel decodability features " , OFFSET ( frame_parallel ) , AV_OPT_TYPE_BOOL , { . i64 = - 1 } , - 1 , 1 , VE } ,
2017-04-14 03:26:44 +02:00
# if VPX_ENCODER_ABI_VERSION >= 12
2024-02-11 16:41:05 +02:00
{ " aq-mode " , " adaptive quantization mode " , OFFSET ( aq_mode ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 4 , VE , . unit = " aq_mode " } ,
2017-04-14 03:26:44 +02:00
# else
2024-02-11 16:41:05 +02:00
{ " aq-mode " , " adaptive quantization mode " , OFFSET ( aq_mode ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 3 , VE , . unit = " aq_mode " } ,
2017-04-14 03:26:44 +02:00
# endif
2024-02-11 16:41:05 +02:00
{ " none " , " Aq not used " , 0 , AV_OPT_TYPE_CONST , { . i64 = 0 } , 0 , 0 , VE , . unit = " aq_mode " } ,
{ " variance " , " Variance based Aq " , 0 , AV_OPT_TYPE_CONST , { . i64 = 1 } , 0 , 0 , VE , . unit = " aq_mode " } ,
{ " complexity " , " Complexity based Aq " , 0 , AV_OPT_TYPE_CONST , { . i64 = 2 } , 0 , 0 , VE , . unit = " aq_mode " } ,
{ " cyclic " , " Cyclic Refresh Aq " , 0 , AV_OPT_TYPE_CONST , { . i64 = 3 } , 0 , 0 , VE , . unit = " aq_mode " } ,
2016-11-18 23:55:45 +02:00
# if VPX_ENCODER_ABI_VERSION >= 12
2024-02-11 16:41:05 +02:00
{ " equator360 " , " 360 video Aq " , 0 , AV_OPT_TYPE_CONST , { . i64 = 4 } , 0 , 0 , VE , . unit = " aq_mode " } ,
2016-11-18 23:55:45 +02:00
{ " level " , " Specify level " , OFFSET ( level ) , AV_OPT_TYPE_FLOAT , { . dbl = - 1 } , - 1 , 6.2 , VE } ,
2017-03-02 20:19:09 +02:00
# endif
# ifdef VPX_CTRL_VP9E_SET_ROW_MT
{ " row-mt " , " Row based multi-threading " , OFFSET ( row_mt ) , AV_OPT_TYPE_BOOL , { . i64 = - 1 } , - 1 , 1 , VE } ,
2017-11-14 01:19:07 +02:00
# endif
# ifdef VPX_CTRL_VP9E_SET_TUNE_CONTENT
# if VPX_ENCODER_ABI_VERSION >= 14
2024-02-11 16:41:05 +02:00
{ " tune-content " , " Tune content type " , OFFSET ( tune_content ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 2 , VE , . unit = " tune_content " } ,
2017-11-14 01:19:07 +02:00
# else
2024-02-11 16:41:05 +02:00
{ " tune-content " , " Tune content type " , OFFSET ( tune_content ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 1 , VE , . unit = " tune_content " } ,
2017-11-14 01:19:07 +02:00
# endif
2024-02-11 16:41:05 +02:00
{ " default " , " Regular video content " , 0 , AV_OPT_TYPE_CONST , { . i64 = 0 } , 0 , 0 , VE , . unit = " tune_content " } ,
{ " screen " , " Screen capture content " , 0 , AV_OPT_TYPE_CONST , { . i64 = 1 } , 0 , 0 , VE , . unit = " tune_content " } ,
2017-11-14 01:19:07 +02:00
# if VPX_ENCODER_ABI_VERSION >= 14
2024-02-11 16:41:05 +02:00
{ " film " , " Film content; improves grain retention " , 0 , AV_OPT_TYPE_CONST , { . i64 = 2 } , 0 , 0 , VE , . unit = " tune_content " } ,
2017-11-14 01:19:07 +02:00
# endif
2017-11-21 03:32:23 +02:00
# endif
# if VPX_ENCODER_ABI_VERSION >= 14
{ " corpus-complexity " , " corpus vbr complexity midpoint " , OFFSET ( corpus_complexity ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , 10000 , VE } ,
2018-11-03 22:30:34 +02:00
# endif
# ifdef VPX_CTRL_VP9E_SET_TPL
{ " enable-tpl " , " Enable temporal dependency model " , OFFSET ( tpl_model ) , AV_OPT_TYPE_BOOL , { . i64 = - 1 } , - 1 , 1 , VE } ,
2022-09-14 02:23:53 +02:00
# endif
# ifdef VPX_CTRL_VP9E_SET_MIN_GF_INTERVAL
{ " min-gf-interval " , " Minimum golden/alternate reference frame interval " , OFFSET ( min_gf_interval ) , AV_OPT_TYPE_INT , { . i64 = - 1 } , - 1 , INT_MAX , VE } ,
2016-11-18 23:55:45 +02:00
# endif
2013-11-02 22:09:01 +03:00
LEGACY_OPTIONS
{ NULL }
} ;
# endif
# undef COMMON_OPTIONS
# undef LEGACY_OPTIONS
2011-09-26 11:22:38 +03:00
2022-03-16 22:26:11 +02:00
static const FFCodecDefault defaults [ ] = {
2019-09-25 01:24:13 +02:00
{ " b " , " 0 " } ,
2011-09-30 13:15:59 +03:00
{ " qmin " , " -1 " } ,
{ " qmax " , " -1 " } ,
{ " g " , " -1 " } ,
{ " keyint_min " , " -1 " } ,
{ NULL } ,
} ;
2012-12-30 21:40:20 +03:00
# if CONFIG_LIBVPX_VP8_ENCODER
static av_cold int vp8_init ( AVCodecContext * avctx )
{
2015-01-10 13:19:08 +02:00
return vpx_init ( avctx , vpx_codec_vp8_cx ( ) ) ;
2012-12-30 21:40:20 +03:00
}
static const AVClass class_vp8 = {
2013-07-09 03:57:05 +03:00
. class_name = " libvpx-vp8 encoder " ,
2024-01-19 14:33:28 +02:00
. item_name = av_default_item_name ,
2013-11-02 22:09:01 +03:00
. option = vp8_options ,
2012-12-30 21:40:20 +03:00
. version = LIBAVUTIL_VERSION_INT ,
} ;
2022-03-16 22:09:54 +02:00
const FFCodec ff_libvpx_vp8_encoder = {
. p . name = " libvpx " ,
2022-08-29 13:38:02 +02:00
CODEC_LONG_NAME ( " libvpx VP8 " ) ,
2022-03-16 22:09:54 +02:00
. p . type = AVMEDIA_TYPE_VIDEO ,
. p . id = AV_CODEC_ID_VP8 ,
. p . capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
2023-02-28 13:20:39 +02:00
AV_CODEC_CAP_OTHER_THREADS |
AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE ,
2016-07-21 05:41:55 +02:00
. priv_data_size = sizeof ( VPxContext ) ,
2011-07-17 13:54:31 +03:00
. init = vp8_init ,
2022-03-30 23:28:24 +02:00
FF_CODEC_ENCODE_CB ( vpx_encode ) ,
2016-07-21 05:41:55 +02:00
. close = vpx_free ,
2022-07-09 22:25:41 +02:00
. caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
FF_CODEC_CAP_AUTO_THREADS ,
2022-03-16 22:09:54 +02:00
. p . pix_fmts = ( const enum AVPixelFormat [ ] ) { AV_PIX_FMT_YUV420P , AV_PIX_FMT_YUVA420P , AV_PIX_FMT_NONE } ,
. p . priv_class = & class_vp8 ,
2011-09-30 13:15:59 +03:00
. defaults = defaults ,
2022-03-16 22:09:54 +02:00
. p . wrapper_name = " libvpx " ,
2010-06-03 23:47:59 +03:00
} ;
2012-12-30 21:40:20 +03:00
# endif /* CONFIG_LIBVPX_VP8_ENCODER */
2012-12-20 19:22:06 +03:00
2012-12-30 21:40:20 +03:00
# if CONFIG_LIBVPX_VP9_ENCODER
2012-12-20 19:22:06 +03:00
static av_cold int vp9_init ( AVCodecContext * avctx )
{
2015-01-10 13:19:08 +02:00
return vpx_init ( avctx , vpx_codec_vp9_cx ( ) ) ;
2012-12-20 19:22:06 +03:00
}
2023-02-27 15:38:22 +02:00
static const enum AVPixelFormat vp9_pix_fmts_highcol [ ] = {
AV_PIX_FMT_YUV420P ,
AV_PIX_FMT_YUVA420P ,
AV_PIX_FMT_YUV422P ,
AV_PIX_FMT_YUV440P ,
AV_PIX_FMT_YUV444P ,
AV_PIX_FMT_GBRP ,
AV_PIX_FMT_NONE
} ;
static const enum AVPixelFormat vp9_pix_fmts_highbd [ ] = {
AV_PIX_FMT_YUV420P ,
AV_PIX_FMT_YUVA420P ,
AV_PIX_FMT_YUV422P ,
AV_PIX_FMT_YUV440P ,
AV_PIX_FMT_YUV444P ,
AV_PIX_FMT_YUV420P10 ,
AV_PIX_FMT_YUV422P10 ,
AV_PIX_FMT_YUV440P10 ,
AV_PIX_FMT_YUV444P10 ,
AV_PIX_FMT_YUV420P12 ,
AV_PIX_FMT_YUV422P12 ,
AV_PIX_FMT_YUV440P12 ,
AV_PIX_FMT_YUV444P12 ,
AV_PIX_FMT_GBRP ,
AV_PIX_FMT_GBRP10 ,
AV_PIX_FMT_GBRP12 ,
AV_PIX_FMT_NONE
} ;
static av_cold void vp9_init_static ( FFCodec * codec )
{
vpx_codec_caps_t codec_caps = vpx_codec_get_caps ( vpx_codec_vp9_cx ( ) ) ;
if ( codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH )
codec - > p . pix_fmts = vp9_pix_fmts_highbd ;
else
codec - > p . pix_fmts = vp9_pix_fmts_highcol ;
}
2012-12-20 19:22:06 +03:00
static const AVClass class_vp9 = {
2013-07-09 03:57:05 +03:00
. class_name = " libvpx-vp9 encoder " ,
2024-01-19 14:33:28 +02:00
. item_name = av_default_item_name ,
2013-11-02 22:09:01 +03:00
. option = vp9_options ,
2012-12-20 19:22:06 +03:00
. version = LIBAVUTIL_VERSION_INT ,
} ;
2022-03-16 22:09:54 +02:00
FFCodec ff_libvpx_vp9_encoder = {
. p . name = " libvpx-vp9 " ,
2022-08-29 13:38:02 +02:00
CODEC_LONG_NAME ( " libvpx VP9 " ) ,
2022-03-16 22:09:54 +02:00
. p . type = AVMEDIA_TYPE_VIDEO ,
. p . id = AV_CODEC_ID_VP9 ,
. p . capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
2023-02-28 13:20:39 +02:00
AV_CODEC_CAP_OTHER_THREADS |
AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE ,
2022-03-16 22:09:54 +02:00
. p . profiles = NULL_IF_CONFIG_SMALL ( ff_vp9_profiles ) ,
. p . priv_class = & class_vp9 ,
. p . wrapper_name = " libvpx " ,
2016-07-21 05:41:55 +02:00
. priv_data_size = sizeof ( VPxContext ) ,
2012-12-20 19:22:06 +03:00
. init = vp9_init ,
2022-03-30 23:28:24 +02:00
FF_CODEC_ENCODE_CB ( vpx_encode ) ,
2016-07-21 05:41:55 +02:00
. close = vpx_free ,
2022-07-09 22:25:41 +02:00
. caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
FF_CODEC_CAP_AUTO_THREADS ,
2011-09-30 13:15:59 +03:00
. defaults = defaults ,
2023-02-27 15:38:22 +02:00
. init_static_data = vp9_init_static ,
2010-06-03 23:47:59 +03:00
} ;
2012-12-30 21:40:20 +03:00
# endif /* CONFIG_LIBVPX_VP9_ENCODER */