@@ -68,6 +68,13 @@ static int hwdec_opt_help(struct mp_log *log, const m_option_t *opt,
6868#define HWDEC_DELAY_QUEUE_COUNT 2
6969#define HWDEC_WAIT_KEYFRAME_COUNT 96
7070
71+ // Fallback number of extra surfaces for fixed-size hw frame pools, if the
72+ // actual requirement cannot be determined.
73+ #define HWDEC_EXTRA_FRAMES 6
74+
75+ // Surfaces referenced outside of libavcodec on top of what the VO declares
76+ #define HWDEC_EXTRA_INFLIGHT_FRAMES 3
77+
7178#define OPT_BASE_STRUCT struct vd_lavc_params
7279
7380struct vd_lavc_params {
@@ -151,8 +158,8 @@ const struct m_sub_options hwdec_conf = {
151158 .flags = M_OPT_OPTIONAL_PARAM | M_OPT_ALLOW_NO | UPDATE_HWDEC },
152159 {"hwdec-codecs" , OPT_STRING (hwdec_codecs ),
153160 .flags = UPDATE_HWDEC },
154- {"hwdec-extra-frames" , OPT_INT (hwdec_extra_frames ), M_RANGE ( 0 , 256 ),
155- .flags = UPDATE_VD },
161+ {"hwdec-extra-frames" , OPT_CHOICE (hwdec_extra_frames , { "auto" , -1 } ),
162+ M_RANGE ( 0 , 256 ), .flags = UPDATE_VD },
156163 {"hwdec-image-format" , OPT_IMAGEFORMAT (hwdec_image_format ),
157164 .flags = UPDATE_VO },
158165 {"hwdec-software-fallback" , OPT_CHOICE (software_fallback ,
@@ -167,11 +174,7 @@ const struct m_sub_options hwdec_conf = {
167174 .software_fallback = 3 ,
168175 .hwdec_api = (char * []){"no" , NULL ,},
169176 .hwdec_codecs = "h264,vc1,hevc,vp8,vp9,av1,prores,prores_raw,ffv1,dpx,apv" ,
170- // Maximum number of surfaces the player wants to buffer. This number
171- // might require adjustment depending on whatever the player does;
172- // for example, if vo_gpu increases the number of reference surfaces for
173- // interpolation, this value has to be increased too.
174- .hwdec_extra_frames = 6 ,
177+ .hwdec_extra_frames = -1 ,
175178 .hwdec_threads = 4 ,
176179 },
177180};
@@ -946,6 +949,24 @@ static void uninit_avctx(struct mp_filter *vd)
946949 ctx -> use_hwdec = false;
947950}
948951
952+ // Number of extra surfaces to allocate on top of what libavcodec computed
953+ // for the codec itself, i.e. how many frames the rest of the player may hold
954+ // on to at any given time.
955+ static int hwdec_get_extra_frames (vd_ffmpeg_ctx * ctx )
956+ {
957+ int extra = ctx -> hwdec_opts -> hwdec_extra_frames ;
958+ if (extra >= 0 )
959+ return extra ;
960+
961+ extra = HWDEC_EXTRA_FRAMES ;
962+ // With native hwdec, every frame queued towards or retained by the VO
963+ // pins a surface from the fixed pool. Copying wrappers release surfaces
964+ // right after download, the fallback is enough for them.
965+ if (!ctx -> hwdec .copying && ctx -> vo )
966+ extra = MPMAX (extra , vo_get_num_frame_refs (ctx -> vo ) + HWDEC_EXTRA_INFLIGHT_FRAMES );
967+ return extra ;
968+ }
969+
949970static int init_generic_hwaccel (struct AVCodecContext * avctx , enum AVPixelFormat hw_fmt )
950971{
951972 struct mp_filter * vd = avctx -> opaque ;
@@ -975,7 +996,7 @@ static int init_generic_hwaccel(struct AVCodecContext *avctx, enum AVPixelFormat
975996 // 1 surface is already included by libavcodec. The field is 0 if the
976997 // hwaccel supports dynamic surface allocation.
977998 if (new_fctx -> initial_pool_size )
978- new_fctx -> initial_pool_size += ctx -> hwdec_opts -> hwdec_extra_frames - 1 ;
999+ new_fctx -> initial_pool_size += hwdec_get_extra_frames ( ctx ) - 1 ;
9791000
9801001 const struct hwcontext_fns * fns =
9811002 hwdec_get_hwcontext_fns (new_fctx -> device_ctx -> type );
@@ -1001,6 +1022,11 @@ static int init_generic_hwaccel(struct AVCodecContext *avctx, enum AVPixelFormat
10011022 goto error ;
10021023 }
10031024
1025+ if (new_fctx -> initial_pool_size ) {
1026+ MP_VERBOSE (ctx , "Allocated a fixed pool of %d hw surfaces.\n" ,
1027+ new_fctx -> initial_pool_size );
1028+ }
1029+
10041030 ctx -> cached_hw_frames_ctx = new_frames_ctx ;
10051031 new_frames_ctx = NULL ;
10061032 }
0 commit comments