diff options
Diffstat (limited to 'video/filter/vf_d3d11vpp.c')
-rw-r--r-- | video/filter/vf_d3d11vpp.c | 318 |
1 files changed, 155 insertions, 163 deletions
diff --git a/video/filter/vf_d3d11vpp.c b/video/filter/vf_d3d11vpp.c index 3be49ede80..fb96a44e65 100644 --- a/video/filter/vf_d3d11vpp.c +++ b/video/filter/vf_d3d11vpp.c @@ -25,9 +25,13 @@ #include "common/common.h" #include "osdep/timer.h" #include "osdep/windows_utils.h" -#include "vf.h" +#include "filters/f_autoconvert.h" +#include "filters/filter.h" +#include "filters/filter_internal.h" +#include "filters/user_filters.h" #include "refqueue.h" #include "video/hwdec.h" +#include "video/mp_image.h" #include "video/mp_image_pool.h" // missing in MinGW @@ -38,8 +42,17 @@ #define D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_INVERSE_TELECINE 0x10 #define D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_FRAME_RATE_CONVERSION 0x20 -struct vf_priv_s { +struct opts { + int deint_enabled; + int interlaced_only; + int mode; +}; + +struct priv { + struct opts *opts; + ID3D11Device *vo_dev; + const int *vo_formats; ID3D11DeviceContext *device_ctx; ID3D11VideoDevice *video_dev; @@ -61,10 +74,6 @@ struct vf_priv_s { struct mp_image_pool *pool; struct mp_refqueue *queue; - - int deint_enabled; - int interlaced_only; - int mode; }; static void release_tex(void *arg) @@ -76,8 +85,8 @@ static void release_tex(void *arg) static struct mp_image *alloc_pool(void *pctx, int fmt, int w, int h) { - struct vf_instance *vf = pctx; - struct vf_priv_s *p = vf->priv; + struct mp_filter *vf = pctx; + struct priv *p = vf->priv; HRESULT hr; ID3D11Texture2D *texture = NULL; @@ -100,7 +109,7 @@ static struct mp_image *alloc_pool(void *pctx, int fmt, int w, int h) if (!mpi) abort(); - mp_image_setfmt(mpi, p->out_params.imgfmt); + mp_image_setfmt(mpi, IMGFMT_D3D11); mp_image_set_size(mpi, w, h); mpi->params.hw_subfmt = p->out_params.hw_subfmt; @@ -110,29 +119,15 @@ static struct mp_image *alloc_pool(void *pctx, int fmt, int w, int h) return mpi; } -static void flush_frames(struct vf_instance *vf) +static void flush_frames(struct mp_filter *vf) { - struct vf_priv_s *p = vf->priv; + struct priv *p = vf->priv; mp_refqueue_flush(p->queue); } -static int filter_ext(struct vf_instance *vf, struct mp_image *in) -{ - struct vf_priv_s *p = vf->priv; - - mp_refqueue_set_refs(p->queue, 0, 0); - mp_refqueue_set_mode(p->queue, - (p->deint_enabled ? MP_MODE_DEINT : 0) | - MP_MODE_OUTPUT_FIELDS | - (p->interlaced_only ? MP_MODE_INTERLACED_ONLY : 0)); - - mp_refqueue_add_input(p->queue, in); - return 0; -} - -static void destroy_video_proc(struct vf_instance *vf) +static void destroy_video_proc(struct mp_filter *vf) { - struct vf_priv_s *p = vf->priv; + struct priv *p = vf->priv; if (p->video_proc) ID3D11VideoProcessor_Release(p->video_proc); @@ -143,9 +138,9 @@ static void destroy_video_proc(struct vf_instance *vf) p->vp_enum = NULL; } -static int recreate_video_proc(struct vf_instance *vf) +static int recreate_video_proc(struct mp_filter *vf) { - struct vf_priv_s *p = vf->priv; + struct priv *p = vf->priv; HRESULT hr; destroy_video_proc(vf); @@ -168,7 +163,7 @@ static int recreate_video_proc(struct vf_instance *vf) goto fail; MP_VERBOSE(vf, "Found %d rate conversion caps. Looking for caps=0x%x.\n", - (int)caps.RateConversionCapsCount, p->mode); + (int)caps.RateConversionCapsCount, p->opts->mode); int rindex = -1; for (int n = 0; n < caps.RateConversionCapsCount; n++) { @@ -178,7 +173,7 @@ static int recreate_video_proc(struct vf_instance *vf) if (FAILED(hr)) goto fail; MP_VERBOSE(vf, " - %d: 0x%08x\n", n, (unsigned)rcaps.ProcessorCaps); - if (rcaps.ProcessorCaps & p->mode) { + if (rcaps.ProcessorCaps & p->opts->mode) { MP_VERBOSE(vf, " (matching)\n"); if (rindex < 0) rindex = n; @@ -248,17 +243,19 @@ fail: return -1; } -static int render(struct vf_instance *vf) +static struct mp_image *render(struct mp_filter *vf) { - struct vf_priv_s *p = vf->priv; + struct priv *p = vf->priv; int res = -1; HRESULT hr; ID3D11VideoProcessorInputView *in_view = NULL; ID3D11VideoProcessorOutputView *out_view = NULL; struct mp_image *in = NULL, *out = NULL; - out = mp_image_pool_get(p->pool, p->out_params.imgfmt, p->params.w, p->params.h); - if (!out) + out = mp_image_pool_get(p->pool, IMGFMT_D3D11, p->params.w, p->params.h); + if (!out) { + MP_WARN(vf, "failed to allocate frame\n"); goto cleanup; + } ID3D11Texture2D *d3d_out_tex = (void *)out->planes[0]; @@ -325,8 +322,10 @@ static int render(struct vf_instance *vf) (ID3D11Resource *)d3d_out_tex, p->vp_enum, &outdesc, &out_view); - if (FAILED(hr)) + if (FAILED(hr)) { + MP_ERR(vf, "Could not create ID3D11VideoProcessorOutputView\n"); goto cleanup; + } D3D11_VIDEO_PROCESSOR_STREAM stream = { .Enable = TRUE, @@ -346,87 +345,73 @@ cleanup: ID3D11VideoProcessorInputView_Release(in_view); if (out_view) ID3D11VideoProcessorOutputView_Release(out_view); - if (res >= 0) { - vf_add_output_frame(vf, out); - } else { - talloc_free(out); - } - mp_refqueue_next_field(p->queue); - return res; + if (res < 0) + TA_FREEP(&out); + return out; } -static int filter_out(struct vf_instance *vf) +static bool vo_supports(struct priv *p, int subfmt) { - struct vf_priv_s *p = vf->priv; - - if (!mp_refqueue_has_output(p->queue)) - return 0; - - // no filtering - if (!mp_refqueue_should_deint(p->queue) && !p->require_filtering) { - struct mp_image *in = mp_image_new_ref(mp_refqueue_get(p->queue, 0)); - if (!in) - return -1; - mp_image_set_params(in, &p->out_params); - vf_add_output_frame(vf, in); - mp_refqueue_next(p->queue); - return 0; + for (int n = 0; p->vo_formats && p->vo_formats[n]; n++) { + if (p->vo_formats[n] == subfmt) + return true; } - - return render(vf); + return false; } -static int reconfig(struct vf_instance *vf, struct mp_image_params *in, - struct mp_image_params *out) +static void vf_d3d11vpp_process(struct mp_filter *vf) { - struct vf_priv_s *p = vf->priv; - - flush_frames(vf); - talloc_free(p->pool); - p->pool = NULL; + struct priv *p = vf->priv; + + struct mp_image *in_fmt = mp_refqueue_execute_reinit(p->queue); + if (in_fmt) { + mp_image_pool_clear(p->pool); + + destroy_video_proc(vf); + + p->params = in_fmt->params; + p->out_params = p->params; + + if (vo_supports(p, IMGFMT_NV12)) { + p->out_params.hw_subfmt = IMGFMT_NV12; + p->out_format = DXGI_FORMAT_NV12; + p->out_shared = false; + p->out_rgb = false; + } else { + p->out_params.hw_subfmt = IMGFMT_RGB0; + p->out_format = DXGI_FORMAT_B8G8R8A8_UNORM; + p->out_shared = true; + p->out_rgb = true; + } + p->out_params.hw_flags = 0; - destroy_video_proc(vf); + p->require_filtering = p->params.hw_subfmt != p->out_params.hw_subfmt; + } - *out = *in; + if (!mp_refqueue_can_output(p->queue)) + return; - if (vf_next_query_format(vf, IMGFMT_D3D11VA) || - vf_next_query_format(vf, IMGFMT_D3D11NV12)) - { - out->imgfmt = vf_next_query_format(vf, IMGFMT_D3D11VA) - ? IMGFMT_D3D11VA : IMGFMT_D3D11NV12; - out->hw_subfmt = IMGFMT_NV12; - p->out_format = DXGI_FORMAT_NV12; - p->out_shared = false; - p->out_rgb = false; + if (!mp_refqueue_should_deint(p->queue) && !p->require_filtering) { + // no filtering + struct mp_image *in = mp_image_new_ref(mp_refqueue_get(p->queue, 0)); + if (!in) { + mp_filter_internal_mark_failed(vf); + return; + } + mp_refqueue_write_out_pin(p->queue, in); } else { - out->imgfmt = IMGFMT_D3D11RGB; - out->hw_subfmt = IMGFMT_RGB0; - p->out_format = DXGI_FORMAT_B8G8R8A8_UNORM; - p->out_shared = true; - p->out_rgb = true; + mp_refqueue_write_out_pin(p->queue, render(vf)); } - out->hw_flags = 0; - - p->require_filtering = in->hw_subfmt != out->hw_subfmt; - - p->params = *in; - p->out_params = *out; - - p->pool = mp_image_pool_new(vf); - mp_image_pool_set_allocator(p->pool, alloc_pool, vf); - mp_image_pool_set_lru(p->pool); - - return 0; } -static void uninit(struct vf_instance *vf) +static void uninit(struct mp_filter *vf) { - struct vf_priv_s *p = vf->priv; + struct priv *p = vf->priv; destroy_video_proc(vf); flush_frames(vf); - mp_refqueue_free(p->queue); + talloc_free(p->queue); talloc_free(p->pool); if (p->video_ctx) @@ -442,69 +427,55 @@ static void uninit(struct vf_instance *vf) ID3D11Device_Release(p->vo_dev); } -static int query_format(struct vf_instance *vf, unsigned int imgfmt) +static const struct mp_filter_info vf_d3d11vpp_filter = { + .name = "d3d11vpp", + .process = vf_d3d11vpp_process, + .reset = flush_frames, + .destroy = uninit, + .priv_size = sizeof(struct priv), +}; + +static struct mp_filter *vf_d3d11vpp_create(struct mp_filter *parent, + void *options) { - if (imgfmt == IMGFMT_D3D11VA || - imgfmt == IMGFMT_D3D11NV12 || - imgfmt == IMGFMT_D3D11RGB) - { - return vf_next_query_format(vf, IMGFMT_D3D11VA) || - vf_next_query_format(vf, IMGFMT_D3D11NV12) || - vf_next_query_format(vf, IMGFMT_D3D11RGB); + struct mp_filter *f = mp_filter_create(parent, &vf_d3d11vpp_filter); + if (!f) { + talloc_free(options); + return NULL; } - return 0; -} -static bool test_conversion(int in, int out) -{ - return (in == IMGFMT_D3D11VA || - in == IMGFMT_D3D11NV12 || - in == IMGFMT_D3D11RGB) && - (out == IMGFMT_D3D11VA || - out == IMGFMT_D3D11NV12 || - out == IMGFMT_D3D11RGB); -} + mp_filter_add_pin(f, MP_PIN_IN, "in"); + mp_filter_add_pin(f, MP_PIN_OUT, "out"); -static int control(struct vf_instance *vf, int request, void* data) -{ - switch (request){ - case VFCTRL_SEEK_RESET: - flush_frames(vf); - return true; - default: - return CONTROL_UNKNOWN; - } -} + struct priv *p = f->priv; + p->opts = talloc_steal(p, options); -static int vf_open(vf_instance_t *vf) -{ - struct vf_priv_s *p = vf->priv; + // Special path for vf_d3d11_create_outconv(): disable all processing except + // possibly surface format conversions. + if (!p->opts) { + static const struct opts opts = {0}; + p->opts = (struct opts *)&opts; + } - if (!vf->hwdec_devs) - return 0; + p->queue = mp_refqueue_alloc(f); - vf->reconfig = reconfig; - vf->filter_ext = filter_ext; - vf->filter_out = filter_out; - vf->query_format = query_format; - vf->uninit = uninit; - vf->control = control; + struct mp_stream_info *info = mp_filter_find_stream_info(f); + if (!info || !info->hwdec_devs) + goto fail; - hwdec_devices_request_all(vf->hwdec_devs); - AVBufferRef *ref = - hwdec_devices_get_lavc(vf->hwdec_devs, AV_HWDEVICE_TYPE_D3D11VA); - if (!ref) - return 0; + hwdec_devices_request_all(info->hwdec_devs); - AVHWDeviceContext *hwctx = (void *)ref->data; - AVD3D11VADeviceContext *d3dctx = hwctx->hwctx; + struct mp_hwdec_ctx *hwctx = + hwdec_devices_get_by_lavc(info->hwdec_devs, AV_HWDEVICE_TYPE_D3D11VA); + if (!hwctx || !hwctx->av_device_ref) + goto fail; + AVHWDeviceContext *avhwctx = (void *)hwctx->av_device_ref->data; + AVD3D11VADeviceContext *d3dctx = avhwctx->hwctx; p->vo_dev = d3dctx->device; ID3D11Device_AddRef(p->vo_dev); - av_buffer_unref(&ref); - - p->queue = mp_refqueue_alloc(); + p->vo_formats = hwctx->supported_formats; HRESULT hr; @@ -521,14 +492,26 @@ static int vf_open(vf_instance_t *vf) if (FAILED(hr)) goto fail; - return 1; + p->pool = mp_image_pool_new(f); + mp_image_pool_set_allocator(p->pool, alloc_pool, f); + mp_image_pool_set_lru(p->pool); + + mp_refqueue_add_in_format(p->queue, IMGFMT_D3D11, 0); + + mp_refqueue_set_refs(p->queue, 0, 0); + mp_refqueue_set_mode(p->queue, + (p->opts->deint_enabled ? MP_MODE_DEINT : 0) | + MP_MODE_OUTPUT_FIELDS | + (p->opts->interlaced_only ? MP_MODE_INTERLACED_ONLY : 0)); + + return f; fail: - uninit(vf); - return 0; + talloc_free(f); + return NULL; } -#define OPT_BASE_STRUCT struct vf_priv_s +#define OPT_BASE_STRUCT struct opts static const m_option_t vf_opts_fields[] = { OPT_FLAG("deint", deint_enabled, 0), OPT_FLAG("interlaced-only", interlaced_only, 0), @@ -542,16 +525,25 @@ static const m_option_t vf_opts_fields[] = { {0} }; -const vf_info_t vf_info_d3d11vpp = { - .description = "D3D11 Video Post-Process Filter", - .name = "d3d11vpp", - .test_conversion = test_conversion, - .open = vf_open, - .priv_size = sizeof(struct vf_priv_s), - .priv_defaults = &(const struct vf_priv_s) { - .deint_enabled = 1, - .interlaced_only = 1, - .mode = D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BOB, +const struct mp_user_filter_entry vf_d3d11vpp = { + .desc = { + .description = "D3D11 Video Post-Process Filter", + .name = "d3d11vpp", + .priv_size = sizeof(OPT_BASE_STRUCT), + .priv_defaults = &(const OPT_BASE_STRUCT) { + .deint_enabled = 1, + .interlaced_only = 1, + .mode = D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BOB, + }, + .options = vf_opts_fields, }, - .options = vf_opts_fields, + .create = vf_d3d11vpp_create, }; + +// Create a filter for the purpose of converting the sub-format for hwdec +// interops which are incapable of handling some formats (ANGLE). +struct mp_filter *vf_d3d11_create_outconv(struct mp_filter *parent) +{ + // options==NULL is normally not allowed, and specially handled. + return vf_d3d11vpp_create(parent, NULL); +} |