Skip to content

Commit c8b5e84

Browse files
filter: add scale_d3d11 support for MF encoders
1 parent 185645a commit c8b5e84

File tree

10 files changed

+185
-4
lines changed

10 files changed

+185
-4
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c
2+
index 9831f530c1..dac659ea9a 100644
3+
--- a/libavutil/hwcontext_d3d11va.c
4+
+++ b/libavutil/hwcontext_d3d11va.c
5+
@@ -85,6 +85,9 @@ typedef struct D3D11VAFramesContext {
6+
int nb_surfaces;
7+
int nb_surfaces_used;
8+
9+
+ int max_retries;
10+
+ int retries;
11+
+
12+
DXGI_FORMAT format;
13+
14+
ID3D11Texture2D *staging_texture;
15+
@@ -260,8 +263,10 @@ static AVBufferRef *d3d11va_pool_alloc(void *opaque, size_t size)
16+
ID3D11Texture2D_GetDesc(hwctx->texture, &texDesc);
17+
18+
if (s->nb_surfaces_used >= texDesc.ArraySize) {
19+
- av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n");
20+
- return NULL;
21+
+ if (s->retries >= s->max_retries) {
22+
+ av_log(ctx, AV_LOG_ERROR, "Static surface pool size exceeded.\n");
23+
+ }
24+
+ return NULL;
25+
}
26+
27+
ID3D11Texture2D_AddRef(hwctx->texture);
28+
@@ -343,20 +348,34 @@ static int d3d11va_frames_init(AVHWFramesContext *ctx)
29+
static int d3d11va_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
30+
{
31+
AVD3D11FrameDescriptor *desc;
32+
+ D3D11VAFramesContext *s = ctx->hwctx;
33+
+ s->retries = 0;
34+
+ s->max_retries = 50;
35+
36+
- frame->buf[0] = av_buffer_pool_get(ctx->pool);
37+
- if (!frame->buf[0])
38+
- return AVERROR(ENOMEM);
39+
-
40+
- desc = (AVD3D11FrameDescriptor *)frame->buf[0]->data;
41+
-
42+
- frame->data[0] = (uint8_t *)desc->texture;
43+
- frame->data[1] = (uint8_t *)desc->index;
44+
- frame->format = AV_PIX_FMT_D3D11;
45+
- frame->width = ctx->width;
46+
- frame->height = ctx->height;
47+
+ /**
48+
+ * Loop until a buffer becomes available from the pool.
49+
+ * In a full hardware pipeline, all buffers may be temporarily in use by
50+
+ * other modules (encoder/filter/decoder). Rather than immediately failing
51+
+ * with ENOMEM, we wait for a buffer to be released back to the pool, which
52+
+ * maintains pipeline flow and prevents unnecessary allocation failures
53+
+ * during normal operation.
54+
+ */
55+
+ while (s->retries < s->max_retries) {
56+
+ frame->buf[0] = av_buffer_pool_get(ctx->pool);
57+
+ if (frame->buf[0]) {
58+
+ desc = (AVD3D11FrameDescriptor *)frame->buf[0]->data;
59+
+ frame->data[0] = (uint8_t *)desc->texture;
60+
+ frame->data[1] = (uint8_t *)desc->index;
61+
+ frame->format = AV_PIX_FMT_D3D11;
62+
+ frame->width = ctx->width;
63+
+ frame->height = ctx->height;
64+
+ return 0;
65+
+ }
66+
67+
- return 0;
68+
+ av_usleep(1000);
69+
+ }
70+
+
71+
+ return AVERROR(ENOMEM);
72+
}
73+
74+
static int d3d11va_transfer_get_formats(AVHWFramesContext *ctx,

contrib/ffmpeg/module.defs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ FFMPEG.CONFIGURE.extra = \
6565
--enable-filter=crop \
6666
--enable-filter=scale \
6767
--enable-filter=zscale \
68+
--enable-filter=scale_d3d11 \
6869
--enable-filter=pad \
6970
--enable-filter=transpose \
7071
--enable-filter=hflip \

libhb/cropscale.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@ static int crop_scale_init(hb_filter_object_t * filter, hb_filter_init_t * init)
132132
hb_dict_set_string(avsettings, "format", av_get_pix_fmt_name(init->pix_fmt));
133133
hb_dict_set(avfilter, "scale_cuda", avsettings);
134134
}
135+
else if (init->hw_pix_fmt == AV_PIX_FMT_D3D11)
136+
{
137+
hb_dict_set_int(avsettings, "width", width);
138+
hb_dict_set_int(avsettings, "height", height);
139+
hb_dict_set(avfilter, "scale_d3d11", avsettings);
140+
}
135141
else if (hb_av_can_use_zscale(init->pix_fmt,
136142
init->geometry.width, init->geometry.height,
137143
width, height))

libhb/decavcodec.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,13 @@ int reinit_video_filters(hb_work_private_t * pv)
14691469
hb_dict_set(settings, "format", hb_value_string(av_get_pix_fmt_name(pv->job->input_pix_fmt)));
14701470
hb_avfilter_append_dict(filters, "scale_cuda", settings);
14711471
}
1472+
else if (pv->frame->hw_frames_ctx && pv->job->hw_pix_fmt == AV_PIX_FMT_D3D11)
1473+
{
1474+
hb_dict_set(settings, "width", hb_value_int(orig_width));
1475+
hb_dict_set(settings, "height", hb_value_int(orig_height));
1476+
hb_dict_set(settings, "format", hb_value_string(av_get_pix_fmt_name(pv->job->input_pix_fmt)));
1477+
hb_avfilter_append_dict(filters, "scale_d3d11", settings);
1478+
}
14721479
else if (hb_av_can_use_zscale(pv->frame->format,
14731480
pv->frame->width, pv->frame->height,
14741481
orig_width, orig_height))
@@ -1898,6 +1905,13 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
18981905
}
18991906
#endif
19001907

1908+
#if HB_PROJECT_FEATURE_MF
1909+
if (w->hw_accel && w->hw_accel->type == AV_HWDEVICE_TYPE_D3D11VA)
1910+
{
1911+
pv->context->extra_hw_frames = 30;
1912+
}
1913+
#endif
1914+
19011915
if ( hb_avcodec_open( pv->context, pv->codec, &av_opts, pv->threads ) )
19021916
{
19031917
av_dict_free( &av_opts );

libhb/format.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ static int format_init(hb_filter_object_t *filter, hb_filter_init_t *init)
6565
hb_dict_set(avfilter, "vpp_qsv", avsettings);
6666
}
6767
else
68+
#elif HB_PROJECT_FEATURE_MF
69+
if (init->hw_pix_fmt == AV_PIX_FMT_D3D11)
70+
{
71+
hb_dict_set_string(avsettings, "format", format);
72+
hb_dict_set(avfilter, "scale_d3d11", avsettings);
73+
}
74+
else
6875
#endif
6976
{
7077
if (init->hw_pix_fmt == AV_PIX_FMT_CUDA)

libhb/handbrake/common.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,10 @@ struct hb_encoder_s
237237

238238
#ifdef __LIBHB__
239239

240-
#define HB_HWACCEL_CAP_SCAN 0x1
241-
#define HB_HWACCEL_CAP_ROTATE 0x2
240+
#define HB_HWACCEL_CAP_SCAN 0x01
241+
#define HB_HWACCEL_CAP_ROTATE 0x02
242+
#define HB_HWACCEL_CAP_FORMAT_REQUIRED 0x04
243+
242244

243245
struct hb_hwaccel_s
244246
{

libhb/handbrake/mf_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@ int hb_mf_h264_available();
3434
int hb_mf_h265_available();
3535
int hb_mf_av1_available();
3636
int hb_check_mf_available();
37+
int hb_mf_are_filters_supported(hb_list_t *filters);
3738

3839
#endif // HANDBRAKE_MF_COMMON_H

libhb/hbavfilter.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,22 @@ void hb_avfilter_combine( hb_list_t * list)
335335
}
336336
}
337337
else
338+
#endif
339+
#if HB_PROJECT_FEATURE_MF
340+
// Concat d3d11 settings as one scale_d3d11 filter to optimize pipeline
341+
hb_dict_t * avfilter_settings_dict = hb_value_array_get(avfilter->settings, 0);
342+
hb_dict_t * cur_settings_dict = hb_value_array_get(settings, 0);
343+
if (cur_settings_dict && avfilter_settings_dict && hb_dict_get(avfilter_settings_dict, "scale_d3d11"))
344+
{
345+
hb_dict_t *avfilter_settings_dict_d3d11 = hb_dict_get(avfilter_settings_dict, "scale_d3d11");
346+
hb_dict_t *cur_settings_dict_d3d11 = hb_dict_get(cur_settings_dict, "scale_d3d11");
347+
if (avfilter_settings_dict_d3d11 && cur_settings_dict_d3d11)
348+
{
349+
hb_dict_merge(avfilter_settings_dict_d3d11, cur_settings_dict_d3d11);
350+
351+
}
352+
}
353+
else
338354
#endif
339355
{
340356
hb_value_array_concat(avfilter->settings, settings);

libhb/mf_common.c

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,64 @@ int hb_directx_available()
223223
return 1;
224224
}
225225

226+
int hb_mf_are_filters_supported(hb_list_t *filters)
227+
{
228+
if (filters == NULL || hb_list_count(filters) == 0)
229+
{
230+
hb_log("D3D11: No filters to process");
231+
return 1;
232+
}
233+
234+
for (int i = 0; i < hb_list_count(filters); i++)
235+
{
236+
hb_filter_object_t *filter = hb_list_item(filters, i);
237+
if (filter == NULL)
238+
{
239+
hb_log("D3D11: Null filter object encountered");
240+
return 0;
241+
}
242+
243+
switch (filter->id)
244+
{
245+
case HB_FILTER_CROP_SCALE:
246+
hb_log("D3D11: Scaling filter supported");
247+
break;
248+
case HB_FILTER_FORMAT:
249+
hb_log("D3D11: Format supported");
250+
break;
251+
252+
case HB_FILTER_AVFILTER:
253+
hb_log("D3D11: AVFilter filter supported");
254+
break;
255+
256+
case HB_FILTER_VFR:
257+
{
258+
int mode = hb_dict_get_int(filter->settings, "mode");
259+
hb_log("Checking VFR mode: %d", mode);
260+
if (mode == 2)
261+
{
262+
hb_log("D3D11: Unsupported VFR mode %d detected", mode);
263+
return 0;
264+
}
265+
hb_log("D3D11: VFR mode %d supported", mode);
266+
continue;
267+
}
268+
269+
default:
270+
hb_log("D3D11: Unsupported filter %s (id: %d)", filter->name, filter->id);
271+
return 0;
272+
}
273+
}
274+
275+
hb_log("D3D11: All filters are supported");
276+
return 1;
277+
}
278+
226279
static const int mf_encoders[] =
227280
{
281+
HB_VCODEC_FFMPEG_MF_H264,
282+
HB_VCODEC_FFMPEG_MF_H265,
283+
HB_VCODEC_FFMPEG_MF_AV1,
228284
HB_VCODEC_INVALID
229285
};
230286

@@ -235,7 +291,8 @@ hb_hwaccel_t hb_hwaccel_mf =
235291
.encoders = mf_encoders,
236292
.type = AV_HWDEVICE_TYPE_D3D11VA,
237293
.hw_pix_fmt = AV_PIX_FMT_D3D11,
238-
.caps = HB_HWACCEL_CAP_SCAN
294+
.can_filter = hb_mf_are_filters_supported,
295+
.caps = HB_HWACCEL_CAP_SCAN | HB_HWACCEL_CAP_FORMAT_REQUIRED
239296
};
240297

241298
#else // HB_PROJECT_FEATURE_MF

libhb/work.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1455,7 +1455,10 @@ static void sanitize_filter_list_post(hb_job_t *job)
14551455
}
14561456
#endif
14571457

1458-
if (hb_video_encoder_pix_fmt_is_supported(job->vcodec, job->input_pix_fmt, job->encoder_profile) == 0)
1458+
hb_hwaccel_t *hwaccel = hb_get_hwaccel(job->hw_decode);
1459+
1460+
if (hb_video_encoder_pix_fmt_is_supported(job->vcodec, job->input_pix_fmt, job->encoder_profile) == 0 ||
1461+
(job->hw_pix_fmt != AV_PIX_FMT_NONE && hwaccel && (hwaccel->caps & HB_HWACCEL_CAP_FORMAT_REQUIRED)))
14591462
{
14601463
// Some encoders require a specific input pixel format
14611464
// that could be different from the current pipeline format.

0 commit comments

Comments
 (0)