On Tue, 3 Jan 2017 17:35:03 +0100 Steve Lhomme <[email protected]> wrote:
> From: Steve Lhomme <[email protected]> > > The code is similar to avconv_dxva2. The decoded output needs to be copied > into > a staging texture that can be accessed by the CPU as the decoder texture can't > be accessed by the CPU. > > edit: move the actual GUID definitions in a shared C file > --- > Changelog | 1 + > Makefile | 1 + > avconv.h | 2 + > avconv_d3d11va.c | 213 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > avconv_dxva.c | 28 ++++++++ > avconv_opt.c | 3 + > configure | 6 ++ > 7 files changed, 254 insertions(+) > create mode 100644 avconv_d3d11va.c > create mode 100644 avconv_dxva.c > > diff --git a/Changelog b/Changelog > index e17ef20..6aa3f03 100644 > --- a/Changelog > +++ b/Changelog > @@ -6,6 +6,7 @@ version <next>: > - Intel QSV-accelerated VP8 and VC-1 decoding > - VAAPI-accelerated VP8 and HEVC decoding > - VAAPI-accelerated deinterlacing > +- support for decoding through D3D11VA in avconv > > > version 12: > diff --git a/Makefile b/Makefile > index 26c296f..6040131 100644 > --- a/Makefile > +++ b/Makefile > @@ -85,6 +85,7 @@ OBJS-avconv += avconv_opt.o > avconv_filter.o > OBJS-avconv-$(CONFIG_LIBMFX) += avconv_qsv.o > OBJS-avconv-$(CONFIG_VAAPI) += avconv_vaapi.o > OBJS-avconv-$(CONFIG_VDA) += avconv_vda.o > +OBJS-avconv-$(HAVE_D3D11VA_LIB) += avconv_d3d11va.o avconv_guid.o > OBJS-avconv-$(HAVE_DXVA2_LIB) += avconv_dxva2.o avconv_guid.o > OBJS-avconv-$(HAVE_VDPAU_X11) += avconv_vdpau.o > > diff --git a/avconv.h b/avconv.h > index 6360f76..1919c66 100644 > --- a/avconv.h > +++ b/avconv.h > @@ -56,6 +56,7 @@ enum HWAccelID { > HWACCEL_VDA, > HWACCEL_QSV, > HWACCEL_VAAPI, > + HWACCEL_D3D11VA, > }; > > typedef struct HWAccel { > @@ -498,6 +499,7 @@ int ifilter_parameters_from_frame(InputFilter *ifilter, > const AVFrame *frame); > int avconv_parse_options(int argc, char **argv); > > int vdpau_init(AVCodecContext *s); > +int d3d11va_init(AVCodecContext *s); > int dxva2_init(AVCodecContext *s); > int vda_init(AVCodecContext *s); > int qsv_init(AVCodecContext *s); > diff --git a/avconv_d3d11va.c b/avconv_d3d11va.c > new file mode 100644 > index 0000000..d7ec558 > --- /dev/null > +++ b/avconv_d3d11va.c > @@ -0,0 +1,213 @@ > +/* > + * This file is part of Libav. > + * > + * Libav 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. > + * > + * Libav 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 Libav; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + */ > + > +#include <windows.h> > + > +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600 > +#undef _WIN32_WINNT > +#define _WIN32_WINNT 0x0600 > +#endif > +#define COBJMACROS > + > +#include <stdint.h> > + > +#include <d3d11.h> > + > +#include "avconv.h" > + > +#include "libavcodec/d3d11va.h" > + > +#include "libavutil/avassert.h" > +#include "libavutil/buffer.h" > +#include "libavutil/frame.h" > +#include "libavutil/imgutils.h" > +#include "libavutil/pixfmt.h" > + > +#include "libavutil/hwcontext.h" > +#include "libavutil/hwcontext_d3d11va.h" > + > +typedef struct D3D11VAContext { > + D3D11_VIDEO_DECODER_CONFIG decoder_config; > + > + AVFrame *tmp_frame; > + > + AVBufferRef *hw_device_ctx; > + AVBufferRef *hw_frames_ctx; > +} D3D11VAContext; > + > +typedef D3D11_VIDEO_DECODER_CONFIG DXVA_DECODER_CONFIG; > +typedef DXGI_FORMAT DXVA_SURFACE_FORMAT; > +typedef D3D11VAContext DXVA_CONTEXT; > +typedef AVD3D11VAContext DXVA_AV_CONTEXT; > +typedef ID3D11VideoDevice *DXVA_DECODER_SERVICE; > +#include "avconv_dxva_template.c" > + > +static int d3d11va_get_decoder_configuration(AVCodecContext *s, > + const D3D11_VIDEO_DECODER_DESC > *desc, > + DXVA_DECODER_CONFIG *config) > +{ > + InputStream *ist = s->opaque; > + int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : > AV_LOG_ERROR; > + unsigned cfg_count = 0; > + DXVA_DECODER_CONFIG *cfg_list = NULL; > + HRESULT hr; > + int i, ret; > + > + DXVA_CONTEXT *ctx = ist->hwaccel_ctx; > + AVHWDeviceContext *device_ctx = > (AVHWDeviceContext*)ctx->hw_device_ctx->data; > + AVD3D11VADeviceContext *device_hwctx = device_ctx->hwctx; > + > + hr = > ID3D11VideoDevice_GetVideoDecoderConfigCount(device_hwctx->video_device, > desc, &cfg_count); > + if (FAILED(hr)) { > + av_log(NULL, loglevel, "Unable to retrieve decoder > configurations\n"); > + return AVERROR(EINVAL); > + } > + > + cfg_list = av_malloc(cfg_count * sizeof(DXVA_DECODER_CONFIG)); av_malloc_array() or so? > + if (cfg_list == NULL) > + return AVERROR(ENOMEM); > + for (i = 0; i < cfg_count; i++) { > + hr = > ID3D11VideoDevice_GetVideoDecoderConfig(device_hwctx->video_device, desc, i, > &cfg_list[i]); > + if (FAILED(hr)) { > + av_log(NULL, loglevel, "Unable to retrieve decoder > configurations. (hr=0x%lX)\n", hr); > + free(cfg_list); > + return AVERROR(EINVAL); > + } > + } > + > + ret = dxva_get_decoder_configuration(s, cfg_list, cfg_count, config); > + av_free(cfg_list); > + return ret; > +} > + > +static int d3d11va_validate_output(DXVA_DECODER_SERVICE service, GUID guid, > DXVA_SURFACE_FORMAT surface_format) > +{ > + HRESULT hr; > + BOOL is_supported = FALSE; > + hr = ID3D11VideoDevice_CheckVideoDecoderFormat(service, &guid, > surface_format, &is_supported); > + return SUCCEEDED(hr) && is_supported; > +} > + > +static int d3d11va_create_decoder(AVCodecContext *s) > +{ > + InputStream *ist = s->opaque; > + int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : > AV_LOG_ERROR; > + DXVA_CONTEXT *ctx = ist->hwaccel_ctx; > + DXVA_AV_CONTEXT *dxva_ctx = s->hwaccel_context; > + GUID *guid_list; > + unsigned guid_count, i; > + GUID decoder_guid; > + const DXVA_SURFACE_FORMAT surface_format = s->sw_pix_fmt == > AV_PIX_FMT_YUV420P10 ? > + DXGI_FORMAT_P010 : > DXGI_FORMAT_NV12; I might not have the total overview here, but I though dxva_adjust_decoder() does this already? Although it appears to be "too late" to do that. Still, is there avoidable duplication? At least the messy 10 bit handling (which can only get messier if possibly other bit depths are added) seems like a good candidate for this. > + D3D11_VIDEO_DECODER_DESC desc = { 0 }; > + DXVA_DECODER_CONFIG config; > + HRESULT hr; > + int ret; > + > + AVD3D11VAFramesContext *frames_hwctx; > + AVHWFramesContext *frames_ctx; > + > + AVHWDeviceContext *device_ctx; > + AVD3D11VADeviceContext *device_hwctx; > + device_ctx = (AVHWDeviceContext*)ctx->hw_device_ctx->data; > + device_hwctx = device_ctx->hwctx; > + > + guid_count = > ID3D11VideoDevice_GetVideoDecoderProfileCount(device_hwctx->video_device); > + guid_list = av_malloc(sizeof(*guid_list) * guid_count); Again, av_malloc_array, maybe. > + if (guid_list==NULL) { > + av_log(NULL, loglevel, "Failed to get the decoder GUIDs\n"); > + goto fail; > + } > + for (i=0; i<guid_count; i++) { > + hr = > ID3D11VideoDevice_GetVideoDecoderProfile(device_hwctx->video_device, i, > &guid_list[i]); > + if (FAILED(hr)) { > + av_log(NULL, loglevel, "Failed to retrieve decoder GUID %d\n", > i); > + av_free(guid_list); > + goto fail; > + } > + } > + > + ret = dxva_get_decoder_guid(s, device_hwctx->video_device, > surface_format, d3d11va_validate_output, > + guid_count, guid_list, &decoder_guid); > + av_free(guid_list); > + if (ret < 0) { > + goto fail; > + } > + > + desc.SampleWidth = s->coded_width; > + desc.SampleHeight = s->coded_height; > + desc.OutputFormat = surface_format; > + desc.Guid = decoder_guid; > + > + ret = d3d11va_get_decoder_configuration(s, &desc, &config); > + if (ret < 0) { > + goto fail; > + } > + > + ctx->hw_frames_ctx = av_hwframe_ctx_alloc(ctx->hw_device_ctx); > + if (!ctx->hw_frames_ctx) > + goto fail; > + frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data; > + frames_hwctx = frames_ctx->hwctx; > + frames_ctx->format = AV_PIX_FMT_D3D11VA_VLD; > + > + dxva_adjust_decoder(s); > + > + hr = ID3D11VideoDevice_CreateVideoDecoder(device_hwctx->video_device, > &desc, > + &config, > &frames_hwctx->video_decoder); > + if (FAILED(hr)) { > + av_log(NULL, loglevel, "Failed to create D3D11VA video decoder\n"); > + goto fail; > + } > + > + ret = av_hwframe_ctx_init(ctx->hw_frames_ctx); > + if (ret < 0) { > + av_log(NULL, loglevel, "Failed to initialize the HW frames > context\n"); > + goto fail; > + } > + > + ctx->decoder_config = config; > + > + dxva_ctx->cfg = &ctx->decoder_config; > + dxva_ctx->surface = frames_hwctx->surfaces; > + dxva_ctx->surface_count = frames_hwctx->nb_surfaces; > + dxva_ctx->decoder = frames_hwctx->video_decoder; > + dxva_ctx->video_context = device_hwctx->video_context; > + dxva_ctx->context_mutex = device_hwctx->dev_ctx_mutex; > + > + return 0; > +fail: > + if (frames_hwctx->video_decoder) > + ID3D11VideoDecoder_Release(frames_hwctx->video_decoder); > + av_buffer_unref(&ctx->hw_frames_ctx); > + return AVERROR(EINVAL); > +} > + > +int d3d11va_init(AVCodecContext *s) > +{ > + InputStream *ist = s->opaque; > + int ret; > + > + if (!ist->hwaccel_ctx) { > + ret = dxva_alloc(s, AV_HWDEVICE_TYPE_D3D11VA); > + if (ret < 0) > + return ret; > + } > + > + return dxva_init(s, d3d11va_create_decoder); > +} > diff --git a/avconv_dxva.c b/avconv_dxva.c > new file mode 100644 > index 0000000..9a3fa83 > --- /dev/null > +++ b/avconv_dxva.c > @@ -0,0 +1,28 @@ > +/* > + * This file is part of Libav. > + * > + * Libav 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. > + * > + * Libav 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 Libav; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + */ > + > +#include "libavcodec/avcodec.h" > + > +typedef void DXVA_DECODER_CONFIG; > +typedef void DXVA_SURFACE_FORMAT; > +typedef void DXVA_CONTEXT; > +typedef void DXVA_AV_CONTEXT; > +typedef void *DXVA_DECODER_SERVICE; > + > +#include <initguid.h> > +#include "avconv_dxva.h" > diff --git a/avconv_opt.c b/avconv_opt.c > index 4d7140d..7f79dc1 100644 > --- a/avconv_opt.c > +++ b/avconv_opt.c > @@ -59,6 +59,9 @@ const HWAccel hwaccels[] = { > #if HAVE_VDPAU_X11 > { "vdpau", vdpau_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU }, > #endif > +#if HAVE_D3D11VA_LIB > + { "d3d11va", d3d11va_init, HWACCEL_D3D11VA, AV_PIX_FMT_D3D11VA_VLD }, > +#endif > #if HAVE_DXVA2_LIB > { "dxva2", dxva2_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD }, > #endif > diff --git a/configure b/configure > index 9cd4fe6..47f0c4f 100755 > --- a/configure > +++ b/configure > @@ -1682,6 +1682,7 @@ HAVE_LIST=" > $THREADS_LIST > $TOOLCHAIN_FEATURES > $TYPES_LIST > + d3d11va_lib > dos_paths > dxva2_lib > libc_msvcrt > @@ -2134,6 +2135,7 @@ zmbv_encoder_deps="zlib" > > # hardware accelerators > d3d11va_deps="d3d11_h dxva_h ID3D11VideoDecoder" > +d3d11va_lib_deps="d3d11va" > dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode" > dxva2_lib_deps="dxva2" > vda_deps="VideoDecodeAcceleration_VDADecoder_h pthreads" > @@ -4787,6 +4789,10 @@ if enabled libxcb; then > add_extralibs "$xcb_shape_extralibs $xcb_shm_extralibs > $xcb_xfixes_extralibs" > fi > > +enabled d3d11va && > + check_type "windows.h d3d11.h" ID3D11VideoDevice && > + enable d3d11va_lib > + > enabled dxva2 && > check_lib dxva2_lib windows.h CoTaskMemFree -lole32 > _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
