diff --git a/Changelog b/Changelog index 24d2255183..a8726c6736 100644 --- a/Changelog +++ b/Changelog @@ -25,6 +25,7 @@ version : - The x86 assembler default switched from yasm to nasm, pass --x86asmexe=yasm to configure to restore the old behavior. - additional frame format support for Interplay MVE movies +- support for decoding through D3D11VA in ffmpeg version 3.3: - CrystalHD decoder moved to new decode API diff --git a/Makefile b/Makefile index aef18185d4..29870d7710 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,6 @@ ifndef CONFIG_VIDEOTOOLBOX OBJS-ffmpeg-$(CONFIG_VDA) += ffmpeg_videotoolbox.o endif OBJS-ffmpeg-$(CONFIG_CUVID) += ffmpeg_cuvid.o -OBJS-ffmpeg-$(HAVE_DXVA2_LIB) += ffmpeg_dxva2.o OBJS-ffserver += ffserver_config.o TESTTOOLS = audiogen videogen rotozoom tiny_psnr tiny_ssim base64 audiomatch diff --git a/configure b/configure index 6ca919be4a..aebd5d5da5 100755 --- a/configure +++ b/configure @@ -2056,8 +2056,6 @@ HAVE_LIST=" alsa atomics_native dos_paths - dxva2_lib - dxva2api_cobj jack libc_msvcrt makeinfo @@ -2594,9 +2592,8 @@ crystalhd_deps="libcrystalhd_libcrystalhd_if_h" cuda_deps_any="dlopen LoadLibrary" cuvid_deps="cuda" d3d11va_deps="d3d11_h dxva_h ID3D11VideoDecoder ID3D11VideoContext" -dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode" +dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32" dxva2_extralibs="-luser32" -dxva2_lib_deps="dxva2" vda_framework_deps="VideoDecodeAcceleration_VDADecoder_h blocks_extension" vda_framework_extralibs="-framework VideoDecodeAcceleration" vda_deps="vda_framework pthreads" @@ -2613,6 +2610,8 @@ h264_cuvid_hwaccel_deps="cuda cuvid" h264_cuvid_hwaccel_select="h264_cuvid_decoder" h264_d3d11va_hwaccel_deps="d3d11va" h264_d3d11va_hwaccel_select="h264_decoder" +h264_d3d11va2_hwaccel_deps="d3d11va" +h264_d3d11va2_hwaccel_select="h264_decoder" h264_dxva2_hwaccel_deps="dxva2" h264_dxva2_hwaccel_select="h264_decoder" h264_mediacodec_hwaccel_deps="mediacodec" @@ -2633,6 +2632,8 @@ hevc_cuvid_hwaccel_select="hevc_cuvid_decoder" hevc_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_HEVC" hevc_d3d11va_hwaccel_select="hevc_decoder" hevc_mediacodec_hwaccel_deps="mediacodec" +hevc_d3d11va2_hwaccel_deps="d3d11va DXVA_PicParams_HEVC" +hevc_d3d11va2_hwaccel_select="hevc_decoder" hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_HEVC" hevc_dxva2_hwaccel_select="hevc_decoder" hevc_qsv_hwaccel_deps="libmfx" @@ -2656,6 +2657,8 @@ mpeg2_cuvid_hwaccel_deps="cuda cuvid" mpeg2_cuvid_hwaccel_select="mpeg2_cuvid_decoder" mpeg2_d3d11va_hwaccel_deps="d3d11va" mpeg2_d3d11va_hwaccel_select="mpeg2video_decoder" +mpeg2_d3d11va2_hwaccel_deps="d3d11va" +mpeg2_d3d11va2_hwaccel_select="mpeg2video_decoder" mpeg2_dxva2_hwaccel_deps="dxva2" mpeg2_dxva2_hwaccel_select="mpeg2video_decoder" mpeg2_mediacodec_hwaccel_deps="mediacodec" @@ -2684,6 +2687,8 @@ vc1_cuvid_hwaccel_deps="cuda cuvid" vc1_cuvid_hwaccel_select="vc1_cuvid_decoder" vc1_d3d11va_hwaccel_deps="d3d11va" vc1_d3d11va_hwaccel_select="vc1_decoder" +vc1_d3d11va2_hwaccel_deps="d3d11va" +vc1_d3d11va2_hwaccel_select="vc1_decoder" vc1_dxva2_hwaccel_deps="dxva2" vc1_dxva2_hwaccel_select="vc1_decoder" vc1_mmal_hwaccel_deps="mmal" @@ -2701,12 +2706,15 @@ vp8_mediacodec_hwaccel_deps="mediacodec" vp8_qsv_hwaccel_deps="libmfx" vp9_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_VP9" vp9_d3d11va_hwaccel_select="vp9_decoder" +vp9_d3d11va2_hwaccel_deps="d3d11va DXVA_PicParams_VP9" +vp9_d3d11va2_hwaccel_select="vp9_decoder" vp9_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_VP9" vp9_dxva2_hwaccel_select="vp9_decoder" vp9_mediacodec_hwaccel_deps="mediacodec" vp9_vaapi_hwaccel_deps="vaapi VADecPictureParameterBufferVP9_bit_depth" vp9_vaapi_hwaccel_select="vp9_decoder" wmv3_d3d11va_hwaccel_select="vc1_d3d11va_hwaccel" +wmv3_d3d11va2_hwaccel_select="vc1_d3d11va2_hwaccel" wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel" wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel" wmv3_vdpau_hwaccel_select="vc1_vdpau_hwaccel" @@ -5705,6 +5713,7 @@ check_header asm/types.h # so we also check that atomics actually work here check_builtin stdatomic_h stdatomic.h "atomic_int foo, bar = ATOMIC_VAR_INIT(-1); atomic_store(&foo, 0)" +check_lib ole32 "windows.h" CoTaskMemFree -lole32 check_lib shell32 "windows.h shellapi.h" CommandLineToArgvW -lshell32 check_lib wincrypt "windows.h wincrypt.h" CryptGenRandom -ladvapi32 check_lib psapi "windows.h psapi.h" GetProcessMemoryInfo -lpsapi @@ -6111,19 +6120,6 @@ fi check_func_headers "windows.h" CreateDIBSection "$gdigrab_indev_extralibs" -enabled dxva2api_h && - check_cc < -#include -#include -int main(void) { IDirectXVideoDecoder *o = NULL; IDirectXVideoDecoder_Release(o); return 0; } -EOF - -enabled dxva2 && - check_lib dxva2_lib windows.h CoTaskMemFree -lole32 - enabled vaapi && check_lib vaapi va/va.h vaInitialize -lva diff --git a/doc/APIchanges b/doc/APIchanges index 857d44402d..69f876e6c3 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -15,6 +15,12 @@ libavutil: 2015-08-28 API changes, most recent first: +2017-xx-xx - xxxxxxx - lavc 57.100.100 - avcodec.h + DXVA2 and D3D11 hardware accelerated decoding now supports the new hwaccel API, + which can create the decoder context and allocate hardware frame automatically. + See AVCodecContext.hw_device_ctx and AVCodecContext.hw_frames_ctx. For D3D11, + the new AV_PIX_FMT_D3D11 pixfmt must be used with the new API. + 2017-xx-xx - xxxxxxx - lavu 56.67.100 - hwcontext.h Add AV_HWDEVICE_TYPE_D3D11VA and AV_PIX_FMT_D3D11. diff --git a/ffmpeg.h b/ffmpeg.h index c3854bcb4a..d2deb432b7 100644 --- a/ffmpeg.h +++ b/ffmpeg.h @@ -68,6 +68,7 @@ enum HWAccelID { HWACCEL_QSV, HWACCEL_VAAPI, HWACCEL_CUVID, + HWACCEL_D3D11VA, }; typedef struct HWAccel { @@ -661,7 +662,6 @@ int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame); int ffmpeg_parse_options(int argc, char **argv); -int dxva2_init(AVCodecContext *s); int vda_init(AVCodecContext *s); int videotoolbox_init(AVCodecContext *s); int qsv_init(AVCodecContext *s); diff --git a/ffmpeg_dxva2.c b/ffmpeg_dxva2.c deleted file mode 100644 index 1a391f82f3..0000000000 --- a/ffmpeg_dxva2.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - * 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 - */ - -#include - -#ifdef _WIN32_WINNT -#undef _WIN32_WINNT -#endif -#define _WIN32_WINNT 0x0600 -#define DXVA2API_USE_BITFIELDS -#define COBJMACROS - -#include - -#include -#include - -#include "ffmpeg.h" - -#include "libavcodec/dxva2.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_dxva2.h" - -/* define all the GUIDs used directly here, - to avoid problems with inconsistent dxva2api.h versions in mingw-w64 and different MSVC version */ -#include -DEFINE_GUID(IID_IDirectXVideoDecoderService, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02); - -DEFINE_GUID(DXVA2_ModeMPEG2_VLD, 0xee27417f, 0x5e28,0x4e65,0xbe,0xea,0x1d,0x26,0xb5,0x08,0xad,0xc9); -DEFINE_GUID(DXVA2_ModeMPEG2and1_VLD, 0x86695f12, 0x340e,0x4f04,0x9f,0xd3,0x92,0x53,0xdd,0x32,0x74,0x60); -DEFINE_GUID(DXVA2_ModeH264_E, 0x1b81be68, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); -DEFINE_GUID(DXVA2_ModeH264_F, 0x1b81be69, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); -DEFINE_GUID(DXVADDI_Intel_ModeH264_E, 0x604F8E68, 0x4951,0x4C54,0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6); -DEFINE_GUID(DXVA2_ModeVC1_D, 0x1b81beA3, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); -DEFINE_GUID(DXVA2_ModeVC1_D2010, 0x1b81beA4, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); -DEFINE_GUID(DXVA2_ModeHEVC_VLD_Main, 0x5b11d51b, 0x2f4c,0x4452,0xbc,0xc3,0x09,0xf2,0xa1,0x16,0x0c,0xc0); -DEFINE_GUID(DXVA2_ModeHEVC_VLD_Main10,0x107af0e0, 0xef1a,0x4d19,0xab,0xa8,0x67,0xa1,0x63,0x07,0x3d,0x13); -DEFINE_GUID(DXVA2_ModeVP9_VLD_Profile0, 0x463707f8, 0xa1d0,0x4585,0x87,0x6d,0x83,0xaa,0x6d,0x60,0xb8,0x9e); -DEFINE_GUID(DXVA2_NoEncrypt, 0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); -DEFINE_GUID(GUID_NULL, 0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00); - -typedef struct dxva2_mode { - const GUID *guid; - enum AVCodecID codec; -} dxva2_mode; - -static const dxva2_mode dxva2_modes[] = { - /* MPEG-2 */ - { &DXVA2_ModeMPEG2_VLD, AV_CODEC_ID_MPEG2VIDEO }, - { &DXVA2_ModeMPEG2and1_VLD, AV_CODEC_ID_MPEG2VIDEO }, - - /* H.264 */ - { &DXVA2_ModeH264_F, AV_CODEC_ID_H264 }, - { &DXVA2_ModeH264_E, AV_CODEC_ID_H264 }, - /* Intel specific H.264 mode */ - { &DXVADDI_Intel_ModeH264_E, AV_CODEC_ID_H264 }, - - /* VC-1 / WMV3 */ - { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_VC1 }, - { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_WMV3 }, - { &DXVA2_ModeVC1_D, AV_CODEC_ID_VC1 }, - { &DXVA2_ModeVC1_D, AV_CODEC_ID_WMV3 }, - - /* HEVC/H.265 */ - { &DXVA2_ModeHEVC_VLD_Main, AV_CODEC_ID_HEVC }, - { &DXVA2_ModeHEVC_VLD_Main10,AV_CODEC_ID_HEVC }, - - /* VP8/9 */ - { &DXVA2_ModeVP9_VLD_Profile0, AV_CODEC_ID_VP9 }, - - { NULL, 0 }, -}; - -typedef struct DXVA2Context { - IDirectXVideoDecoder *decoder; - - GUID decoder_guid; - DXVA2_ConfigPictureDecode decoder_config; - IDirectXVideoDecoderService *decoder_service; - - AVFrame *tmp_frame; - - AVBufferRef *hw_device_ctx; - AVBufferRef *hw_frames_ctx; -} DXVA2Context; - -static void dxva2_uninit(AVCodecContext *s) -{ - InputStream *ist = s->opaque; - DXVA2Context *ctx = ist->hwaccel_ctx; - - ist->hwaccel_uninit = NULL; - ist->hwaccel_get_buffer = NULL; - ist->hwaccel_retrieve_data = NULL; - - if (ctx->decoder_service) - IDirectXVideoDecoderService_Release(ctx->decoder_service); - - av_buffer_unref(&ctx->hw_frames_ctx); - av_buffer_unref(&ctx->hw_device_ctx); - - av_frame_free(&ctx->tmp_frame); - - av_freep(&ist->hwaccel_ctx); - av_freep(&s->hwaccel_context); -} - -static int dxva2_get_buffer(AVCodecContext *s, AVFrame *frame, int flags) -{ - InputStream *ist = s->opaque; - DXVA2Context *ctx = ist->hwaccel_ctx; - - return av_hwframe_get_buffer(ctx->hw_frames_ctx, frame, 0); -} - -static int dxva2_retrieve_data(AVCodecContext *s, AVFrame *frame) -{ - InputStream *ist = s->opaque; - DXVA2Context *ctx = ist->hwaccel_ctx; - int ret; - - ret = av_hwframe_transfer_data(ctx->tmp_frame, frame, 0); - if (ret < 0) - return ret; - - ret = av_frame_copy_props(ctx->tmp_frame, frame); - if (ret < 0) { - av_frame_unref(ctx->tmp_frame); - return ret; - } - - av_frame_unref(frame); - av_frame_move_ref(frame, ctx->tmp_frame); - - return 0; -} - -static int dxva2_alloc(AVCodecContext *s) -{ - InputStream *ist = s->opaque; - int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; - DXVA2Context *ctx; - HANDLE device_handle; - HRESULT hr; - - AVHWDeviceContext *device_ctx; - AVDXVA2DeviceContext *device_hwctx; - int ret; - - ctx = av_mallocz(sizeof(*ctx)); - if (!ctx) - return AVERROR(ENOMEM); - - ist->hwaccel_ctx = ctx; - ist->hwaccel_uninit = dxva2_uninit; - ist->hwaccel_get_buffer = dxva2_get_buffer; - ist->hwaccel_retrieve_data = dxva2_retrieve_data; - - ret = av_hwdevice_ctx_create(&ctx->hw_device_ctx, AV_HWDEVICE_TYPE_DXVA2, - ist->hwaccel_device, NULL, 0); - if (ret < 0) - goto fail; - device_ctx = (AVHWDeviceContext*)ctx->hw_device_ctx->data; - device_hwctx = device_ctx->hwctx; - - hr = IDirect3DDeviceManager9_OpenDeviceHandle(device_hwctx->devmgr, - &device_handle); - if (FAILED(hr)) { - av_log(NULL, loglevel, "Failed to open a device handle\n"); - goto fail; - } - - hr = IDirect3DDeviceManager9_GetVideoService(device_hwctx->devmgr, device_handle, - &IID_IDirectXVideoDecoderService, - (void **)&ctx->decoder_service); - IDirect3DDeviceManager9_CloseDeviceHandle(device_hwctx->devmgr, device_handle); - if (FAILED(hr)) { - av_log(NULL, loglevel, "Failed to create IDirectXVideoDecoderService\n"); - goto fail; - } - - ctx->tmp_frame = av_frame_alloc(); - if (!ctx->tmp_frame) - goto fail; - - s->hwaccel_context = av_mallocz(sizeof(struct dxva_context)); - if (!s->hwaccel_context) - goto fail; - - return 0; -fail: - dxva2_uninit(s); - return AVERROR(EINVAL); -} - -static int dxva2_get_decoder_configuration(AVCodecContext *s, const GUID *device_guid, - const DXVA2_VideoDesc *desc, - DXVA2_ConfigPictureDecode *config) -{ - InputStream *ist = s->opaque; - int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; - DXVA2Context *ctx = ist->hwaccel_ctx; - unsigned cfg_count = 0, best_score = 0; - DXVA2_ConfigPictureDecode *cfg_list = NULL; - DXVA2_ConfigPictureDecode best_cfg = {{0}}; - HRESULT hr; - int i; - - hr = IDirectXVideoDecoderService_GetDecoderConfigurations(ctx->decoder_service, device_guid, desc, NULL, &cfg_count, &cfg_list); - if (FAILED(hr)) { - av_log(NULL, loglevel, "Unable to retrieve decoder configurations\n"); - return AVERROR(EINVAL); - } - - for (i = 0; i < cfg_count; i++) { - DXVA2_ConfigPictureDecode *cfg = &cfg_list[i]; - - unsigned score; - if (cfg->ConfigBitstreamRaw == 1) - score = 1; - else if (s->codec_id == AV_CODEC_ID_H264 && cfg->ConfigBitstreamRaw == 2) - score = 2; - else - continue; - if (IsEqualGUID(&cfg->guidConfigBitstreamEncryption, &DXVA2_NoEncrypt)) - score += 16; - if (score > best_score) { - best_score = score; - best_cfg = *cfg; - } - } - CoTaskMemFree(cfg_list); - - if (!best_score) { - av_log(NULL, loglevel, "No valid decoder configuration available\n"); - return AVERROR(EINVAL); - } - - *config = best_cfg; - return 0; -} - -static int dxva2_create_decoder(AVCodecContext *s) -{ - InputStream *ist = s->opaque; - int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; - DXVA2Context *ctx = ist->hwaccel_ctx; - struct dxva_context *dxva_ctx = s->hwaccel_context; - GUID *guid_list = NULL; - unsigned guid_count = 0, i, j; - GUID device_guid = GUID_NULL; - const D3DFORMAT surface_format = (s->sw_pix_fmt == AV_PIX_FMT_YUV420P10) ? MKTAG('P','0','1','0') : MKTAG('N','V','1','2'); - D3DFORMAT target_format = 0; - DXVA2_VideoDesc desc = { 0 }; - DXVA2_ConfigPictureDecode config; - HRESULT hr; - int surface_alignment, num_surfaces; - int ret; - - AVDXVA2FramesContext *frames_hwctx; - AVHWFramesContext *frames_ctx; - - hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx->decoder_service, &guid_count, &guid_list); - if (FAILED(hr)) { - av_log(NULL, loglevel, "Failed to retrieve decoder device GUIDs\n"); - goto fail; - } - - for (i = 0; dxva2_modes[i].guid; i++) { - D3DFORMAT *target_list = NULL; - unsigned target_count = 0; - const dxva2_mode *mode = &dxva2_modes[i]; - if (mode->codec != s->codec_id) - continue; - - for (j = 0; j < guid_count; j++) { - if (IsEqualGUID(mode->guid, &guid_list[j])) - break; - } - if (j == guid_count) - continue; - - hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx->decoder_service, mode->guid, &target_count, &target_list); - if (FAILED(hr)) { - continue; - } - for (j = 0; j < target_count; j++) { - const D3DFORMAT format = target_list[j]; - if (format == surface_format) { - target_format = format; - break; - } - } - CoTaskMemFree(target_list); - if (target_format) { - device_guid = *mode->guid; - break; - } - } - CoTaskMemFree(guid_list); - - if (IsEqualGUID(&device_guid, &GUID_NULL)) { - av_log(NULL, loglevel, "No decoder device for codec found\n"); - goto fail; - } - - desc.SampleWidth = s->coded_width; - desc.SampleHeight = s->coded_height; - desc.Format = target_format; - - ret = dxva2_get_decoder_configuration(s, &device_guid, &desc, &config); - if (ret < 0) { - goto fail; - } - - /* decoding MPEG-2 requires additional alignment on some Intel GPUs, - but it causes issues for H.264 on certain AMD GPUs..... */ - if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO) - surface_alignment = 32; - /* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure - all coding features have enough room to work with */ - else if (s->codec_id == AV_CODEC_ID_HEVC) - surface_alignment = 128; - else - surface_alignment = 16; - - /* 4 base work surfaces */ - num_surfaces = 4; - - /* add surfaces based on number of possible refs */ - if (s->codec_id == AV_CODEC_ID_H264 || s->codec_id == AV_CODEC_ID_HEVC) - num_surfaces += 16; - else if (s->codec_id == AV_CODEC_ID_VP9) - num_surfaces += 8; - else - num_surfaces += 2; - - /* add extra surfaces for frame threading */ - if (s->active_thread_type & FF_THREAD_FRAME) - num_surfaces += s->thread_count; - - 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_DXVA2_VLD; - frames_ctx->sw_format = (target_format == MKTAG('P','0','1','0') ? AV_PIX_FMT_P010 : AV_PIX_FMT_NV12); - frames_ctx->width = FFALIGN(s->coded_width, surface_alignment); - frames_ctx->height = FFALIGN(s->coded_height, surface_alignment); - frames_ctx->initial_pool_size = num_surfaces; - - frames_hwctx->surface_type = DXVA2_VideoDecoderRenderTarget; - - 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; - } - - hr = IDirectXVideoDecoderService_CreateVideoDecoder(ctx->decoder_service, &device_guid, - &desc, &config, frames_hwctx->surfaces, - frames_hwctx->nb_surfaces, &frames_hwctx->decoder_to_release); - if (FAILED(hr)) { - av_log(NULL, loglevel, "Failed to create DXVA2 video decoder\n"); - goto fail; - } - - ctx->decoder_guid = device_guid; - ctx->decoder_config = config; - - dxva_ctx->cfg = &ctx->decoder_config; - dxva_ctx->decoder = frames_hwctx->decoder_to_release; - dxva_ctx->surface = frames_hwctx->surfaces; - dxva_ctx->surface_count = frames_hwctx->nb_surfaces; - - if (IsEqualGUID(&ctx->decoder_guid, &DXVADDI_Intel_ModeH264_E)) - dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO; - - return 0; -fail: - av_buffer_unref(&ctx->hw_frames_ctx); - return AVERROR(EINVAL); -} - -int dxva2_init(AVCodecContext *s) -{ - InputStream *ist = s->opaque; - int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR; - DXVA2Context *ctx; - int ret; - - if (!ist->hwaccel_ctx) { - ret = dxva2_alloc(s); - if (ret < 0) - return ret; - } - ctx = ist->hwaccel_ctx; - - if (s->codec_id == AV_CODEC_ID_H264 && - (s->profile & ~FF_PROFILE_H264_CONSTRAINED) > FF_PROFILE_H264_HIGH) { - av_log(NULL, loglevel, "Unsupported H.264 profile for DXVA2 HWAccel: %d\n", s->profile); - return AVERROR(EINVAL); - } - - if (s->codec_id == AV_CODEC_ID_HEVC && - s->profile != FF_PROFILE_HEVC_MAIN && s->profile != FF_PROFILE_HEVC_MAIN_10) { - av_log(NULL, loglevel, "Unsupported HEVC profile for DXVA2 HWAccel: %d\n", s->profile); - return AVERROR(EINVAL); - } - - av_buffer_unref(&ctx->hw_frames_ctx); - - ret = dxva2_create_decoder(s); - if (ret < 0) { - av_log(NULL, loglevel, "Error creating the DXVA2 decoder\n"); - return ret; - } - - return 0; -} diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c index bb6001f534..9b7e8c74b9 100644 --- a/ffmpeg_opt.c +++ b/ffmpeg_opt.c @@ -70,9 +70,13 @@ const HWAccel hwaccels[] = { { "vdpau", hwaccel_decode_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU, AV_HWDEVICE_TYPE_VDPAU }, #endif -#if HAVE_DXVA2_LIB - { "dxva2", dxva2_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD, - AV_HWDEVICE_TYPE_NONE }, +#if CONFIG_D3D11VA + { "d3d11va", hwaccel_decode_init, HWACCEL_D3D11VA, AV_PIX_FMT_D3D11, + AV_HWDEVICE_TYPE_D3D11VA }, +#endif +#if CONFIG_DXVA2 + { "dxva2", hwaccel_decode_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD, + AV_HWDEVICE_TYPE_DXVA2 }, #endif #if CONFIG_VDA { "vda", videotoolbox_init, HWACCEL_VDA, AV_PIX_FMT_VDA, diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 54a9e8c42e..0243f47358 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -66,6 +66,7 @@ static void register_all(void) REGISTER_HWACCEL(H263_VIDEOTOOLBOX, h263_videotoolbox); REGISTER_HWACCEL(H264_CUVID, h264_cuvid); REGISTER_HWACCEL(H264_D3D11VA, h264_d3d11va); + REGISTER_HWACCEL(H264_D3D11VA2, h264_d3d11va2); REGISTER_HWACCEL(H264_DXVA2, h264_dxva2); REGISTER_HWACCEL(H264_MEDIACODEC, h264_mediacodec); REGISTER_HWACCEL(H264_MMAL, h264_mmal); @@ -77,6 +78,7 @@ static void register_all(void) REGISTER_HWACCEL(H264_VIDEOTOOLBOX, h264_videotoolbox); REGISTER_HWACCEL(HEVC_CUVID, hevc_cuvid); REGISTER_HWACCEL(HEVC_D3D11VA, hevc_d3d11va); + REGISTER_HWACCEL(HEVC_D3D11VA2, hevc_d3d11va2); REGISTER_HWACCEL(HEVC_DXVA2, hevc_dxva2); REGISTER_HWACCEL(HEVC_MEDIACODEC, hevc_mediacodec); REGISTER_HWACCEL(HEVC_QSV, hevc_qsv); @@ -90,6 +92,7 @@ static void register_all(void) REGISTER_HWACCEL(MPEG2_CUVID, mpeg2_cuvid); REGISTER_HWACCEL(MPEG2_XVMC, mpeg2_xvmc); REGISTER_HWACCEL(MPEG2_D3D11VA, mpeg2_d3d11va); + REGISTER_HWACCEL(MPEG2_D3D11VA2, mpeg2_d3d11va2); REGISTER_HWACCEL(MPEG2_DXVA2, mpeg2_dxva2); REGISTER_HWACCEL(MPEG2_MMAL, mpeg2_mmal); REGISTER_HWACCEL(MPEG2_QSV, mpeg2_qsv); @@ -105,6 +108,7 @@ static void register_all(void) REGISTER_HWACCEL(MPEG4_VIDEOTOOLBOX, mpeg4_videotoolbox); REGISTER_HWACCEL(VC1_CUVID, vc1_cuvid); REGISTER_HWACCEL(VC1_D3D11VA, vc1_d3d11va); + REGISTER_HWACCEL(VC1_D3D11VA2, vc1_d3d11va2); REGISTER_HWACCEL(VC1_DXVA2, vc1_dxva2); REGISTER_HWACCEL(VC1_VAAPI, vc1_vaapi); REGISTER_HWACCEL(VC1_VDPAU, vc1_vdpau); @@ -115,10 +119,12 @@ static void register_all(void) REGISTER_HWACCEL(VP8_QSV, vp8_qsv); REGISTER_HWACCEL(VP9_CUVID, vp9_cuvid); REGISTER_HWACCEL(VP9_D3D11VA, vp9_d3d11va); + REGISTER_HWACCEL(VP9_D3D11VA2, vp9_d3d11va2); REGISTER_HWACCEL(VP9_DXVA2, vp9_dxva2); REGISTER_HWACCEL(VP9_MEDIACODEC, vp9_mediacodec); REGISTER_HWACCEL(VP9_VAAPI, vp9_vaapi); REGISTER_HWACCEL(WMV3_D3D11VA, wmv3_d3d11va); + REGISTER_HWACCEL(WMV3_D3D11VA2, wmv3_d3d11va2); REGISTER_HWACCEL(WMV3_DXVA2, wmv3_dxva2); REGISTER_HWACCEL(WMV3_VAAPI, wmv3_vaapi); REGISTER_HWACCEL(WMV3_VDPAU, wmv3_vdpau); diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c index 9138216745..efb5328dcd 100644 --- a/libavcodec/dxva2.c +++ b/libavcodec/dxva2.c @@ -22,20 +22,450 @@ #include #include +#include +#include "libavutil/common.h" #include "libavutil/log.h" #include "libavutil/time.h" #include "avcodec.h" #include "dxva2_internal.h" +/* define all the GUIDs used directly here, + to avoid problems with inconsistent dxva2api.h versions in mingw-w64 and different MSVC version */ +DEFINE_GUID(ff_DXVA2_ModeMPEG2_VLD, 0xee27417f, 0x5e28,0x4e65,0xbe,0xea,0x1d,0x26,0xb5,0x08,0xad,0xc9); +DEFINE_GUID(ff_DXVA2_ModeMPEG2and1_VLD, 0x86695f12, 0x340e,0x4f04,0x9f,0xd3,0x92,0x53,0xdd,0x32,0x74,0x60); +DEFINE_GUID(ff_DXVA2_ModeH264_E, 0x1b81be68, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); +DEFINE_GUID(ff_DXVA2_ModeH264_F, 0x1b81be69, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); +DEFINE_GUID(ff_DXVADDI_Intel_ModeH264_E, 0x604F8E68, 0x4951,0x4C54,0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6); +DEFINE_GUID(ff_DXVA2_ModeVC1_D, 0x1b81beA3, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); +DEFINE_GUID(ff_DXVA2_ModeVC1_D2010, 0x1b81beA4, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); +DEFINE_GUID(ff_DXVA2_ModeHEVC_VLD_Main, 0x5b11d51b, 0x2f4c,0x4452,0xbc,0xc3,0x09,0xf2,0xa1,0x16,0x0c,0xc0); +DEFINE_GUID(ff_DXVA2_ModeHEVC_VLD_Main10,0x107af0e0, 0xef1a,0x4d19,0xab,0xa8,0x67,0xa1,0x63,0x07,0x3d,0x13); +DEFINE_GUID(ff_DXVA2_ModeVP9_VLD_Profile0,0x463707f8,0xa1d0,0x4585,0x87,0x6d,0x83,0xaa,0x6d,0x60,0xb8,0x9e); +DEFINE_GUID(ff_DXVA2_NoEncrypt, 0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); +DEFINE_GUID(ff_GUID_NULL, 0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00); +DEFINE_GUID(ff_IID_IDirectXVideoDecoderService, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02); + +typedef struct dxva_mode { + const GUID *guid; + enum AVCodecID codec; +} dxva_mode; + +static const dxva_mode dxva_modes[] = { + /* MPEG-2 */ + { &ff_DXVA2_ModeMPEG2_VLD, AV_CODEC_ID_MPEG2VIDEO }, + { &ff_DXVA2_ModeMPEG2and1_VLD, AV_CODEC_ID_MPEG2VIDEO }, + + /* H.264 */ + { &ff_DXVA2_ModeH264_F, AV_CODEC_ID_H264 }, + { &ff_DXVA2_ModeH264_E, AV_CODEC_ID_H264 }, + /* Intel specific H.264 mode */ + { &ff_DXVADDI_Intel_ModeH264_E, AV_CODEC_ID_H264 }, + + /* VC-1 / WMV3 */ + { &ff_DXVA2_ModeVC1_D2010, AV_CODEC_ID_VC1 }, + { &ff_DXVA2_ModeVC1_D2010, AV_CODEC_ID_WMV3 }, + { &ff_DXVA2_ModeVC1_D, AV_CODEC_ID_VC1 }, + { &ff_DXVA2_ModeVC1_D, AV_CODEC_ID_WMV3 }, + + /* HEVC/H.265 */ + { &ff_DXVA2_ModeHEVC_VLD_Main, AV_CODEC_ID_HEVC }, + { &ff_DXVA2_ModeHEVC_VLD_Main10, AV_CODEC_ID_HEVC }, + + /* VP8/9 */ + { &ff_DXVA2_ModeVP9_VLD_Profile0,AV_CODEC_ID_VP9 }, + + { NULL, 0 }, +}; + +static int dxva_get_decoder_configuration(AVCodecContext *avctx, + const void *cfg_list, + unsigned cfg_count) +{ + FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); + unsigned i, best_score = 0; + int best_cfg = -1; + + for (i = 0; i < cfg_count; i++) { + unsigned score; + UINT ConfigBitstreamRaw; + GUID guidConfigBitstreamEncryption; + +#if CONFIG_D3D11VA + if (sctx->pix_fmt == AV_PIX_FMT_D3D11) { + D3D11_VIDEO_DECODER_CONFIG *cfg = &((D3D11_VIDEO_DECODER_CONFIG *)cfg_list)[i]; + ConfigBitstreamRaw = cfg->ConfigBitstreamRaw; + guidConfigBitstreamEncryption = cfg->guidConfigBitstreamEncryption; + } +#endif +#if CONFIG_DXVA2 + if (sctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) { + DXVA2_ConfigPictureDecode *cfg = &((DXVA2_ConfigPictureDecode *)cfg_list)[i]; + ConfigBitstreamRaw = cfg->ConfigBitstreamRaw; + guidConfigBitstreamEncryption = cfg->guidConfigBitstreamEncryption; + } +#endif + + if (ConfigBitstreamRaw == 1) + score = 1; + else if (avctx->codec_id == AV_CODEC_ID_H264 && ConfigBitstreamRaw == 2) + score = 2; + else + continue; + if (IsEqualGUID(&guidConfigBitstreamEncryption, &ff_DXVA2_NoEncrypt)) + score += 16; + if (score > best_score) { + best_score = score; + best_cfg = i; + } + } + + if (!best_score) { + av_log(avctx, AV_LOG_VERBOSE, "No valid decoder configuration available\n"); + return AVERROR(EINVAL); + } + + return best_cfg; +} + +#if CONFIG_D3D11VA +static int d3d11va_validate_output(void *service, GUID guid, const void *surface_format) +{ + HRESULT hr; + BOOL is_supported = FALSE; + hr = ID3D11VideoDevice_CheckVideoDecoderFormat((ID3D11VideoDevice *)service, + &guid, + *(DXGI_FORMAT *)surface_format, + &is_supported); + return SUCCEEDED(hr) && is_supported; +} +#endif + +#if CONFIG_DXVA2 +static int dxva2_validate_output(void *decoder_service, GUID guid, const void *surface_format) +{ + HRESULT hr; + int ret = 0; + unsigned j, target_count; + D3DFORMAT *target_list; + hr = IDirectXVideoDecoderService_GetDecoderRenderTargets((IDirectXVideoDecoderService *)decoder_service, &guid, &target_count, &target_list); + if (SUCCEEDED(hr)) { + for (j = 0; j < target_count; j++) { + const D3DFORMAT format = target_list[j]; + if (format == *(D3DFORMAT *)surface_format) { + ret = 1; + break; + } + } + CoTaskMemFree(target_list); + } + return ret; +} +#endif + +static int dxva_get_decoder_guid(AVCodecContext *avctx, void *service, void *surface_format, + unsigned guid_count, const GUID *guid_list, GUID *decoder_guid) +{ + FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); + unsigned i, j; + + *decoder_guid = ff_GUID_NULL; + for (i = 0; dxva_modes[i].guid; i++) { + const dxva_mode *mode = &dxva_modes[i]; + int validate; + if (mode->codec != avctx->codec_id) + continue; + + for (j = 0; j < guid_count; j++) { + if (IsEqualGUID(mode->guid, &guid_list[j])) + break; + } + if (j == guid_count) + continue; + +#if CONFIG_D3D11VA + if (sctx->pix_fmt == AV_PIX_FMT_D3D11) + validate = d3d11va_validate_output(service, *mode->guid, surface_format); +#endif +#if CONFIG_DXVA2 + if (sctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) + validate = dxva2_validate_output(service, *mode->guid, surface_format); +#endif + if (validate) { + *decoder_guid = *mode->guid; + break; + } + } + + if (IsEqualGUID(decoder_guid, &ff_GUID_NULL)) { + av_log(avctx, AV_LOG_VERBOSE, "No decoder device for codec found\n"); + return AVERROR(EINVAL); + } + + if (IsEqualGUID(decoder_guid, &ff_DXVADDI_Intel_ModeH264_E)) + sctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO; + + return 0; +} + +static void bufref_free_interface(void *opaque, uint8_t *data) +{ + IUnknown_Release((IUnknown *)opaque); +} + +static AVBufferRef *bufref_wrap_interface(IUnknown *iface) +{ + return av_buffer_create((uint8_t*)iface, 1, bufref_free_interface, iface, 0); +} + +#if CONFIG_DXVA2 + +static int dxva2_get_decoder_configuration(AVCodecContext *avctx, const GUID *device_guid, + const DXVA2_VideoDesc *desc, + DXVA2_ConfigPictureDecode *config) +{ + FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); + unsigned cfg_count; + DXVA2_ConfigPictureDecode *cfg_list; + HRESULT hr; + int ret; + + hr = IDirectXVideoDecoderService_GetDecoderConfigurations(sctx->dxva2_service, device_guid, desc, NULL, &cfg_count, &cfg_list); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Unable to retrieve decoder configurations\n"); + return AVERROR(EINVAL); + } + + ret = dxva_get_decoder_configuration(avctx, cfg_list, cfg_count); + if (ret >= 0) + *config = cfg_list[ret]; + CoTaskMemFree(cfg_list); + return ret; +} + +static int dxva2_create_decoder(AVCodecContext *avctx) +{ + FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); + GUID *guid_list; + unsigned guid_count; + GUID device_guid; + D3DFORMAT surface_format = avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ? + MKTAG('P', '0', '1', '0') : MKTAG('N', 'V', '1', '2'); + DXVA2_VideoDesc desc = { 0 }; + DXVA2_ConfigPictureDecode config; + HRESULT hr; + int ret; + HANDLE device_handle; + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + AVDXVA2FramesContext *frames_hwctx = frames_ctx->hwctx; + AVDXVA2DeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; + + hr = IDirect3DDeviceManager9_OpenDeviceHandle(device_hwctx->devmgr, + &device_handle); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to open a device handle\n"); + goto fail; + } + + hr = IDirect3DDeviceManager9_GetVideoService(device_hwctx->devmgr, device_handle, + &ff_IID_IDirectXVideoDecoderService, + (void **)&sctx->dxva2_service); + IDirect3DDeviceManager9_CloseDeviceHandle(device_hwctx->devmgr, device_handle); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create IDirectXVideoDecoderService\n"); + goto fail; + } + + hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(sctx->dxva2_service, &guid_count, &guid_list); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to retrieve decoder device GUIDs\n"); + goto fail; + } + + ret = dxva_get_decoder_guid(avctx, sctx->dxva2_service, &surface_format, + guid_count, guid_list, &device_guid); + CoTaskMemFree(guid_list); + if (ret < 0) { + goto fail; + } + + desc.SampleWidth = avctx->coded_width; + desc.SampleHeight = avctx->coded_height; + desc.Format = surface_format; + + ret = dxva2_get_decoder_configuration(avctx, &device_guid, &desc, &config); + if (ret < 0) { + goto fail; + } + + hr = IDirectXVideoDecoderService_CreateVideoDecoder(sctx->dxva2_service, &device_guid, + &desc, &config, frames_hwctx->surfaces, + frames_hwctx->nb_surfaces, &sctx->dxva2_decoder); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create DXVA2 video decoder\n"); + goto fail; + } + + sctx->dxva2_config = config; + + sctx->decoder_ref = bufref_wrap_interface((IUnknown *)sctx->dxva2_decoder); + if (!sctx->decoder_ref) + return AVERROR(ENOMEM); + + return 0; +fail: + return AVERROR(EINVAL); +} + +#endif + +#if CONFIG_D3D11VA + +static int d3d11va_get_decoder_configuration(AVCodecContext *avctx, + ID3D11VideoDevice *video_device, + const D3D11_VIDEO_DECODER_DESC *desc, + D3D11_VIDEO_DECODER_CONFIG *config) +{ + FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); + unsigned cfg_count = 0; + D3D11_VIDEO_DECODER_CONFIG *cfg_list = NULL; + HRESULT hr; + int i, ret; + + hr = ID3D11VideoDevice_GetVideoDecoderConfigCount(video_device, desc, &cfg_count); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Unable to retrieve decoder configurations\n"); + return AVERROR(EINVAL); + } + + cfg_list = av_malloc_array(cfg_count, sizeof(D3D11_VIDEO_DECODER_CONFIG)); + if (cfg_list == NULL) + return AVERROR(ENOMEM); + for (i = 0; i < cfg_count; i++) { + hr = ID3D11VideoDevice_GetVideoDecoderConfig(video_device, desc, i, &cfg_list[i]); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Unable to retrieve decoder configurations. (hr=0x%lX)\n", hr); + av_free(cfg_list); + return AVERROR(EINVAL); + } + } + + ret = dxva_get_decoder_configuration(avctx, cfg_list, cfg_count); + if (ret >= 0) + *config = cfg_list[ret]; + av_free(cfg_list); + return ret; +} + +static int d3d11va_create_decoder(AVCodecContext *avctx) +{ + FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); + GUID *guid_list; + unsigned guid_count, i; + GUID decoder_guid; + DXGI_FORMAT surface_format = avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ? + DXGI_FORMAT_P010 : DXGI_FORMAT_NV12; + D3D11_VIDEO_DECODER_DESC desc = { 0 }; + D3D11_VIDEO_DECODER_CONFIG config; + AVHWFramesContext *frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + AVD3D11VADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; + AVD3D11VAFramesContext *frames_hwctx = frames_ctx->hwctx; + D3D11_TEXTURE2D_DESC texdesc; + HRESULT hr; + int ret; + + if (!frames_hwctx->texture) { + av_log(avctx, AV_LOG_ERROR, "AVD3D11VAFramesContext.texture not set.\n"); + return AVERROR(EINVAL); + } + ID3D11Texture2D_GetDesc(frames_hwctx->texture, &texdesc); + + guid_count = ID3D11VideoDevice_GetVideoDecoderProfileCount(device_hwctx->video_device); + guid_list = av_malloc_array(guid_count, sizeof(*guid_list)); + if (guid_list == NULL || guid_count == 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to get the decoder GUIDs\n"); + av_free(guid_list); + return AVERROR(EINVAL); + } + for (i = 0; i < guid_count; i++) { + hr = ID3D11VideoDevice_GetVideoDecoderProfile(device_hwctx->video_device, i, &guid_list[i]); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to retrieve decoder GUID %d\n", i); + av_free(guid_list); + return AVERROR(EINVAL); + } + } + + ret = dxva_get_decoder_guid(avctx, device_hwctx->video_device, &surface_format, + guid_count, guid_list, &decoder_guid); + av_free(guid_list); + if (ret < 0) + return AVERROR(EINVAL); + + desc.SampleWidth = avctx->coded_width; + desc.SampleHeight = avctx->coded_height; + desc.OutputFormat = surface_format; + desc.Guid = decoder_guid; + + ret = d3d11va_get_decoder_configuration(avctx, device_hwctx->video_device, &desc, &config); + if (ret < 0) + return AVERROR(EINVAL); + + sctx->d3d11_views = av_mallocz_array(texdesc.ArraySize, sizeof(sctx->d3d11_views[0])); + if (!sctx->d3d11_views) + return AVERROR(ENOMEM); + sctx->nb_d3d11_views = texdesc.ArraySize; + + for (i = 0; i < sctx->nb_d3d11_views; i++) { + D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc = { + .DecodeProfile = decoder_guid, + .ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D, + .Texture2D = { + .ArraySlice = i, + } + }; + hr = ID3D11VideoDevice_CreateVideoDecoderOutputView(device_hwctx->video_device, + (ID3D11Resource*) frames_hwctx->texture, + &viewDesc, + (ID3D11VideoDecoderOutputView**) &sctx->d3d11_views[i]); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Could not create the decoder output view %d\n", i); + return AVERROR_UNKNOWN; + } + } + + hr = ID3D11VideoDevice_CreateVideoDecoder(device_hwctx->video_device, &desc, + &config, &sctx->d3d11_decoder); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to create D3D11VA video decoder\n"); + return AVERROR(EINVAL); + } + + sctx->d3d11_config = config; + sctx->d3d11_texture = frames_hwctx->texture; + + sctx->decoder_ref = bufref_wrap_interface((IUnknown *)sctx->d3d11_decoder); + if (!sctx->decoder_ref) + return AVERROR(ENOMEM); + + return 0; +} + +#endif + static void ff_dxva2_lock(AVCodecContext *avctx) { #if CONFIG_D3D11VA if (ff_dxva2_is_d3d11(avctx)) { + FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); AVDXVAContext *ctx = DXVA_CONTEXT(avctx); if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE) WaitForSingleObjectEx(D3D11VA_CONTEXT(ctx)->context_mutex, INFINITE, FALSE); + if (sctx->device_ctx) { + AVD3D11VADeviceContext *hwctx = sctx->device_ctx->hwctx; + hwctx->lock(hwctx->lock_ctx); + } } #endif } @@ -44,15 +474,218 @@ static void ff_dxva2_unlock(AVCodecContext *avctx) { #if CONFIG_D3D11VA if (ff_dxva2_is_d3d11(avctx)) { + FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); AVDXVAContext *ctx = DXVA_CONTEXT(avctx); if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE) ReleaseMutex(D3D11VA_CONTEXT(ctx)->context_mutex); + if (sctx->device_ctx) { + AVD3D11VADeviceContext *hwctx = sctx->device_ctx->hwctx; + hwctx->unlock(hwctx->lock_ctx); + } } #endif } -static void *get_surface(const AVFrame *frame) +// This must work before the decoder is created. +// This somehow needs to be exported to the user. +static void dxva_adjust_hwframes(AVCodecContext *avctx, AVHWFramesContext *frames_ctx) { + FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); + int surface_alignment, num_surfaces; + + frames_ctx->format = sctx->pix_fmt; + + /* decoding MPEG-2 requires additional alignment on some Intel GPUs, + but it causes issues for H.264 on certain AMD GPUs..... */ + if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO) + surface_alignment = 32; + /* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure + all coding features have enough room to work with */ + else if (avctx->codec_id == AV_CODEC_ID_HEVC) + surface_alignment = 128; + else + surface_alignment = 16; + + /* 4 base work surfaces */ + num_surfaces = 4; + + /* add surfaces based on number of possible refs */ + if (avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_HEVC) + num_surfaces += 16; + else if (avctx->codec_id == AV_CODEC_ID_VP9) + num_surfaces += 8; + else + num_surfaces += 2; + + /* add extra surfaces for frame threading */ + if (avctx->active_thread_type & FF_THREAD_FRAME) + num_surfaces += avctx->thread_count; + + frames_ctx->sw_format = avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ? + AV_PIX_FMT_P010 : AV_PIX_FMT_NV12; + frames_ctx->width = FFALIGN(avctx->coded_width, surface_alignment); + frames_ctx->height = FFALIGN(avctx->coded_height, surface_alignment); + frames_ctx->initial_pool_size = num_surfaces; + + +#if CONFIG_DXVA2 + if (frames_ctx->format == AV_PIX_FMT_DXVA2_VLD) { + AVDXVA2FramesContext *frames_hwctx = frames_ctx->hwctx; + + frames_hwctx->surface_type = DXVA2_VideoDecoderRenderTarget; + } +#endif + +#if CONFIG_D3D11VA + if (frames_ctx->format == AV_PIX_FMT_D3D11) { + AVD3D11VAFramesContext *frames_hwctx = frames_ctx->hwctx; + + frames_hwctx->BindFlags |= D3D11_BIND_DECODER; + } +#endif +} + +int ff_dxva2_decode_init(AVCodecContext *avctx) +{ + FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); + AVHWFramesContext *frames_ctx = NULL; + int ret = 0; + + // Old API. + if (avctx->hwaccel_context) + return 0; + + // (avctx->pix_fmt is not updated yet at this point) + sctx->pix_fmt = avctx->hwaccel->pix_fmt; + + if (avctx->codec_id == AV_CODEC_ID_H264 && + (avctx->profile & ~FF_PROFILE_H264_CONSTRAINED) > FF_PROFILE_H264_HIGH) { + av_log(avctx, AV_LOG_VERBOSE, "Unsupported H.264 profile for DXVA HWAccel: %d\n",avctx->profile); + return AVERROR(ENOTSUP); + } + + if (avctx->codec_id == AV_CODEC_ID_HEVC && + avctx->profile != FF_PROFILE_HEVC_MAIN && avctx->profile != FF_PROFILE_HEVC_MAIN_10) { + av_log(avctx, AV_LOG_VERBOSE, "Unsupported HEVC profile for DXVA HWAccel: %d\n", avctx->profile); + return AVERROR(ENOTSUP); + } + + if (!avctx->hw_frames_ctx && !avctx->hw_device_ctx) { + av_log(avctx, AV_LOG_ERROR, "Either a hw_frames_ctx or a hw_device_ctx needs to be set for hardware decoding.\n"); + return AVERROR(EINVAL); + } + + if (avctx->hw_frames_ctx) { + frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + } else { + avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx); + if (!avctx->hw_frames_ctx) + return AVERROR(ENOMEM); + + frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + + dxva_adjust_hwframes(avctx, frames_ctx); + + ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); + if (ret < 0) + goto fail; + } + + sctx->device_ctx = frames_ctx->device_ctx; + + if (frames_ctx->format != sctx->pix_fmt || + !((sctx->pix_fmt == AV_PIX_FMT_D3D11 && CONFIG_D3D11VA) || + (sctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD && CONFIG_DXVA2))) { + av_log(avctx, AV_LOG_ERROR, "Invalid pixfmt for hwaccel!\n"); + ret = AVERROR(EINVAL); + goto fail; + } + +#if CONFIG_D3D11VA + if (sctx->pix_fmt == AV_PIX_FMT_D3D11) { + AVD3D11VADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; + AVD3D11VAContext *d3d11_ctx = &sctx->ctx.d3d11va; + HRESULT hr; + + ff_dxva2_lock(avctx); + ret = d3d11va_create_decoder(avctx); + ff_dxva2_unlock(avctx); + if (ret < 0) + goto fail; + + d3d11_ctx->decoder = sctx->d3d11_decoder; + d3d11_ctx->video_context = device_hwctx->video_context; + d3d11_ctx->cfg = &sctx->d3d11_config; + d3d11_ctx->surface_count = sctx->nb_d3d11_views; + d3d11_ctx->surface = sctx->d3d11_views; + d3d11_ctx->workaround = sctx->workaround; + d3d11_ctx->context_mutex = INVALID_HANDLE_VALUE; + } +#endif + +#if CONFIG_DXVA2 + if (sctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) { + AVDXVA2FramesContext *frames_hwctx = frames_ctx->hwctx; + struct dxva_context *dxva_ctx = &sctx->ctx.dxva2; + + ff_dxva2_lock(avctx); + ret = dxva2_create_decoder(avctx); + ff_dxva2_unlock(avctx); + if (ret < 0) + goto fail; + + dxva_ctx->decoder = sctx->dxva2_decoder; + dxva_ctx->cfg = &sctx->dxva2_config; + dxva_ctx->surface = frames_hwctx->surfaces; + dxva_ctx->surface_count = frames_hwctx->nb_surfaces; + dxva_ctx->workaround = sctx->workaround; + } +#endif + + return 0; + +fail: + ff_dxva2_decode_uninit(avctx); + return ret; +} + +int ff_dxva2_decode_uninit(AVCodecContext *avctx) +{ + FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); + int i; + + av_buffer_unref(&sctx->decoder_ref); + +#if CONFIG_D3D11VA + for (i = 0; i < sctx->nb_d3d11_views; i++) { + if (sctx->d3d11_views[i]) + ID3D11VideoDecoderOutputView_Release(sctx->d3d11_views[i]); + } + av_freep(&sctx->d3d11_views); +#endif + +#if CONFIG_DXVA2 + if (sctx->dxva2_service) + IDirectXVideoDecoderService_Release(sctx->dxva2_service); +#endif + + return 0; +} + +static void *get_surface(AVCodecContext *avctx, const AVFrame *frame) +{ +#if CONFIG_D3D11VA + if (frame->format == AV_PIX_FMT_D3D11) { + FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); + intptr_t index = (intptr_t)frame->data[1]; + if (index < 0 || index >= sctx->nb_d3d11_views || + sctx->d3d11_texture != (ID3D11Texture2D *)frame->data[0]) { + av_log(avctx, AV_LOG_ERROR, "get_buffer frame is invalid!\n"); + return NULL; + } + return sctx->d3d11_views[index]; + } +#endif return frame->data[3]; } @@ -60,10 +693,12 @@ unsigned ff_dxva2_get_surface_index(const AVCodecContext *avctx, const AVDXVAContext *ctx, const AVFrame *frame) { - void *surface = get_surface(frame); + void *surface = get_surface(avctx, frame); unsigned i; #if CONFIG_D3D11VA + if (avctx->pix_fmt == AV_PIX_FMT_D3D11) + return (intptr_t)frame->data[1]; if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) { D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc; ID3D11VideoDecoderOutputView_GetDesc((ID3D11VideoDecoderOutputView*) surface, &viewDesc); @@ -154,6 +789,22 @@ int ff_dxva2_commit_buffer(AVCodecContext *avctx, return result; } +static int frame_add_buf(AVFrame *frame, AVBufferRef *ref) +{ + int i; + + for (i = 0; i < AV_NUM_DATA_POINTERS; i++) { + if (!frame->buf[i]) { + frame->buf[i] = av_buffer_ref(ref); + return frame->buf[i] ? 0 : AVERROR(ENOMEM); + } + } + + // For now we expect that the caller does not use more than + // AV_NUM_DATA_POINTERS-1 buffers if the user uses a custom pool. + return AVERROR(EINVAL); +} + int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame, const void *pp, unsigned pp_size, const void *qm, unsigned qm_size, @@ -173,19 +824,26 @@ int ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame, int result, runs = 0; HRESULT hr; unsigned type; + FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); + + if (sctx->decoder_ref) { + result = frame_add_buf(frame, sctx->decoder_ref); + if (result < 0) + return result; + } do { ff_dxva2_lock(avctx); #if CONFIG_D3D11VA if (ff_dxva2_is_d3d11(avctx)) hr = ID3D11VideoContext_DecoderBeginFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, - get_surface(frame), + get_surface(avctx, frame), 0, NULL); #endif #if CONFIG_DXVA2 if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) hr = IDirectXVideoDecoder_BeginFrame(DXVA2_CONTEXT(ctx)->decoder, - get_surface(frame), + get_surface(avctx, frame), NULL); #endif if (hr != E_PENDING || ++runs > 50) @@ -315,7 +973,8 @@ end: int ff_dxva2_is_d3d11(const AVCodecContext *avctx) { if (CONFIG_D3D11VA) - return avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD; + return avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD || + avctx->pix_fmt == AV_PIX_FMT_D3D11; else return 0; } diff --git a/libavcodec/dxva2_h264.c b/libavcodec/dxva2_h264.c index 6f5592807a..e3a3f7866e 100644 --- a/libavcodec/dxva2_h264.c +++ b/libavcodec/dxva2_h264.c @@ -523,10 +523,13 @@ AVHWAccel ff_h264_dxva2_hwaccel = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, .pix_fmt = AV_PIX_FMT_DXVA2_VLD, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_h264_start_frame, .decode_slice = dxva2_h264_decode_slice, .end_frame = dxva2_h264_end_frame, .frame_priv_data_size = sizeof(struct dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), }; #endif @@ -536,9 +539,28 @@ AVHWAccel ff_h264_d3d11va_hwaccel = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, .pix_fmt = AV_PIX_FMT_D3D11VA_VLD, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_h264_start_frame, .decode_slice = dxva2_h264_decode_slice, .end_frame = dxva2_h264_end_frame, .frame_priv_data_size = sizeof(struct dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), +}; +#endif + +#if CONFIG_H264_D3D11VA2_HWACCEL +AVHWAccel ff_h264_d3d11va2_hwaccel = { + .name = "h264_d3d11va2", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_H264, + .pix_fmt = AV_PIX_FMT_D3D11, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, + .start_frame = dxva2_h264_start_frame, + .decode_slice = dxva2_h264_decode_slice, + .end_frame = dxva2_h264_end_frame, + .frame_priv_data_size = sizeof(struct dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), }; #endif diff --git a/libavcodec/dxva2_hevc.c b/libavcodec/dxva2_hevc.c index 1752b78c3f..88f887a1b5 100644 --- a/libavcodec/dxva2_hevc.c +++ b/libavcodec/dxva2_hevc.c @@ -427,10 +427,13 @@ AVHWAccel ff_hevc_dxva2_hwaccel = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, .pix_fmt = AV_PIX_FMT_DXVA2_VLD, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_hevc_start_frame, .decode_slice = dxva2_hevc_decode_slice, .end_frame = dxva2_hevc_end_frame, .frame_priv_data_size = sizeof(struct hevc_dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), }; #endif @@ -440,9 +443,28 @@ AVHWAccel ff_hevc_d3d11va_hwaccel = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, .pix_fmt = AV_PIX_FMT_D3D11VA_VLD, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_hevc_start_frame, .decode_slice = dxva2_hevc_decode_slice, .end_frame = dxva2_hevc_end_frame, .frame_priv_data_size = sizeof(struct hevc_dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), +}; +#endif + +#if CONFIG_HEVC_D3D11VA2_HWACCEL +AVHWAccel ff_hevc_d3d11va2_hwaccel = { + .name = "hevc_d3d11va2", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HEVC, + .pix_fmt = AV_PIX_FMT_D3D11, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, + .start_frame = dxva2_hevc_start_frame, + .decode_slice = dxva2_hevc_decode_slice, + .end_frame = dxva2_hevc_end_frame, + .frame_priv_data_size = sizeof(struct hevc_dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), }; #endif diff --git a/libavcodec/dxva2_internal.h b/libavcodec/dxva2_internal.h index 9bd456119c..352a9db1ab 100644 --- a/libavcodec/dxva2_internal.h +++ b/libavcodec/dxva2_internal.h @@ -32,9 +32,11 @@ #if CONFIG_DXVA2 #include "dxva2.h" +#include "libavutil/hwcontext_dxva2.h" #endif #if CONFIG_D3D11VA #include "d3d11va.h" +#include "libavutil/hwcontext_d3d11va.h" #endif #if HAVE_DXVA_H /* When targeting WINAPI_FAMILY_PHONE_APP or WINAPI_FAMILY_APP, dxva.h @@ -46,7 +48,10 @@ #include #endif +#include "libavutil/hwcontext.h" + #include "avcodec.h" +#include "internal.h" typedef void DECODER_BUFFER_DESC; @@ -59,7 +64,39 @@ typedef union { #endif } AVDXVAContext; -#define DXVA_CONTEXT(avctx) ((AVDXVAContext *)(avctx)->hwaccel_context) +typedef struct FFDXVASharedContext { + AVBufferRef *decoder_ref; + + // FF_DXVA2_WORKAROUND_* flags + uint64_t workaround; + + // E.g. AV_PIX_FMT_D3D11 (same as AVCodecContext.pix_fmt, except during init) + enum AVPixelFormat pix_fmt; + + AVHWDeviceContext *device_ctx; + +#if CONFIG_D3D11VA + ID3D11VideoDecoder *d3d11_decoder; + D3D11_VIDEO_DECODER_CONFIG d3d11_config; + ID3D11VideoDecoderOutputView **d3d11_views; + int nb_d3d11_views; + ID3D11Texture2D *d3d11_texture; +#endif + +#if CONFIG_DXVA2 + IDirectXVideoDecoder *dxva2_decoder; + IDirectXVideoDecoderService *dxva2_service; + DXVA2_ConfigPictureDecode dxva2_config; +#endif + + // Legacy (but used by code outside of setup) + // In generic mode, DXVA_CONTEXT() will return a pointer to this. + AVDXVAContext ctx; +} FFDXVASharedContext; + +#define DXVA_SHARED_CONTEXT(avctx) ((FFDXVASharedContext *)((avctx)->internal->hwaccel_priv_data)) + +#define DXVA_CONTEXT(avctx) (AVDXVAContext *)((avctx)->hwaccel_context ? (avctx)->hwaccel_context : (&(DXVA_SHARED_CONTEXT(avctx)->ctx))) #define D3D11VA_CONTEXT(ctx) (&ctx->d3d11va) #define DXVA2_CONTEXT(ctx) (&ctx->dxva2) @@ -115,6 +152,10 @@ int ff_dxva2_common_end_frame(AVCodecContext *, AVFrame *, DECODER_BUFFER_DESC *bs, DECODER_BUFFER_DESC *slice)); +int ff_dxva2_decode_init(AVCodecContext *avctx); + +int ff_dxva2_decode_uninit(AVCodecContext *avctx); + int ff_dxva2_is_d3d11(const AVCodecContext *avctx); #endif /* AVCODEC_DXVA2_INTERNAL_H */ diff --git a/libavcodec/dxva2_mpeg2.c b/libavcodec/dxva2_mpeg2.c index 237c898977..b7c69378f0 100644 --- a/libavcodec/dxva2_mpeg2.c +++ b/libavcodec/dxva2_mpeg2.c @@ -322,10 +322,13 @@ AVHWAccel ff_mpeg2_dxva2_hwaccel = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, .pix_fmt = AV_PIX_FMT_DXVA2_VLD, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_mpeg2_start_frame, .decode_slice = dxva2_mpeg2_decode_slice, .end_frame = dxva2_mpeg2_end_frame, .frame_priv_data_size = sizeof(struct dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), }; #endif @@ -335,9 +338,28 @@ AVHWAccel ff_mpeg2_d3d11va_hwaccel = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, .pix_fmt = AV_PIX_FMT_D3D11VA_VLD, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_mpeg2_start_frame, .decode_slice = dxva2_mpeg2_decode_slice, .end_frame = dxva2_mpeg2_end_frame, .frame_priv_data_size = sizeof(struct dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), +}; +#endif + +#if CONFIG_MPEG2_D3D11VA2_HWACCEL +AVHWAccel ff_mpeg2_d3d11va2_hwaccel = { + .name = "mpeg2_d3d11va2", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MPEG2VIDEO, + .pix_fmt = AV_PIX_FMT_D3D11, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, + .start_frame = dxva2_mpeg2_start_frame, + .decode_slice = dxva2_mpeg2_decode_slice, + .end_frame = dxva2_mpeg2_end_frame, + .frame_priv_data_size = sizeof(struct dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), }; #endif diff --git a/libavcodec/dxva2_vc1.c b/libavcodec/dxva2_vc1.c index 43909b634c..e5353cdddc 100644 --- a/libavcodec/dxva2_vc1.c +++ b/libavcodec/dxva2_vc1.c @@ -383,10 +383,13 @@ AVHWAccel ff_wmv3_dxva2_hwaccel = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_WMV3, .pix_fmt = AV_PIX_FMT_DXVA2_VLD, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, .frame_priv_data_size = sizeof(struct dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), }; #endif @@ -396,10 +399,13 @@ AVHWAccel ff_vc1_dxva2_hwaccel = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VC1, .pix_fmt = AV_PIX_FMT_DXVA2_VLD, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, .frame_priv_data_size = sizeof(struct dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), }; #endif @@ -409,10 +415,29 @@ AVHWAccel ff_wmv3_d3d11va_hwaccel = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_WMV3, .pix_fmt = AV_PIX_FMT_D3D11VA_VLD, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, .frame_priv_data_size = sizeof(struct dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), +}; +#endif + +#if CONFIG_WMV3_D3D11VA2_HWACCEL +AVHWAccel ff_wmv3_d3d11va2_hwaccel = { + .name = "wmv3_d3d11va2", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_WMV3, + .pix_fmt = AV_PIX_FMT_D3D11, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, + .start_frame = dxva2_vc1_start_frame, + .decode_slice = dxva2_vc1_decode_slice, + .end_frame = dxva2_vc1_end_frame, + .frame_priv_data_size = sizeof(struct dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), }; #endif @@ -422,9 +447,28 @@ AVHWAccel ff_vc1_d3d11va_hwaccel = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VC1, .pix_fmt = AV_PIX_FMT_D3D11VA_VLD, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, .frame_priv_data_size = sizeof(struct dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), +}; +#endif + +#if CONFIG_VC1_D3D11VA2_HWACCEL +AVHWAccel ff_vc1_d3d11va2_hwaccel = { + .name = "vc1_d3d11va2", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_VC1, + .pix_fmt = AV_PIX_FMT_D3D11, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, + .start_frame = dxva2_vc1_start_frame, + .decode_slice = dxva2_vc1_decode_slice, + .end_frame = dxva2_vc1_end_frame, + .frame_priv_data_size = sizeof(struct dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), }; #endif diff --git a/libavcodec/dxva2_vp9.c b/libavcodec/dxva2_vp9.c index df098dc406..6d87fdd9f2 100644 --- a/libavcodec/dxva2_vp9.c +++ b/libavcodec/dxva2_vp9.c @@ -314,10 +314,13 @@ AVHWAccel ff_vp9_dxva2_hwaccel = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VP9, .pix_fmt = AV_PIX_FMT_DXVA2_VLD, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_vp9_start_frame, .decode_slice = dxva2_vp9_decode_slice, .end_frame = dxva2_vp9_end_frame, .frame_priv_data_size = sizeof(struct vp9_dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), }; #endif @@ -327,9 +330,28 @@ AVHWAccel ff_vp9_d3d11va_hwaccel = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VP9, .pix_fmt = AV_PIX_FMT_D3D11VA_VLD, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, .start_frame = dxva2_vp9_start_frame, .decode_slice = dxva2_vp9_decode_slice, .end_frame = dxva2_vp9_end_frame, .frame_priv_data_size = sizeof(struct vp9_dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), +}; +#endif + +#if CONFIG_VP9_D3D11VA2_HWACCEL +AVHWAccel ff_vp9_d3d11va2_hwaccel = { + .name = "vp9_d3d11va2", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_VP9, + .pix_fmt = AV_PIX_FMT_D3D11, + .init = ff_dxva2_decode_init, + .uninit = ff_dxva2_decode_uninit, + .start_frame = dxva2_vp9_start_frame, + .decode_slice = dxva2_vp9_decode_slice, + .end_frame = dxva2_vp9_end_frame, + .frame_priv_data_size = sizeof(struct vp9_dxva2_picture_context), + .priv_data_size = sizeof(FFDXVASharedContext), }; #endif diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 23ca32a39d..faa684c938 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -758,7 +758,7 @@ static void init_scan_tables(H264Context *h) static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) { #define HWACCEL_MAX (CONFIG_H264_DXVA2_HWACCEL + \ - CONFIG_H264_D3D11VA_HWACCEL + \ + (CONFIG_H264_D3D11VA_HWACCEL * 2) + \ CONFIG_H264_VAAPI_HWACCEL + \ (CONFIG_H264_VDA_HWACCEL * 2) + \ CONFIG_H264_VIDEOTOOLBOX_HWACCEL + \ @@ -834,6 +834,7 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) #endif #if CONFIG_H264_D3D11VA_HWACCEL *fmt++ = AV_PIX_FMT_D3D11VA_VLD; + *fmt++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_H264_VAAPI_HWACCEL *fmt++ = AV_PIX_FMT_VAAPI; diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c index 0f1469fc0f..f6bc5efa96 100644 --- a/libavcodec/hevcdec.c +++ b/libavcodec/hevcdec.c @@ -339,7 +339,7 @@ static void export_stream_params(AVCodecContext *avctx, const HEVCParamSets *ps, static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) { - #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + CONFIG_HEVC_D3D11VA_HWACCEL + CONFIG_HEVC_VAAPI_HWACCEL + CONFIG_HEVC_VDPAU_HWACCEL) + #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + CONFIG_HEVC_D3D11VA_HWACCEL * 2 + CONFIG_HEVC_VAAPI_HWACCEL + CONFIG_HEVC_VDPAU_HWACCEL) enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts; switch (sps->pix_fmt) { @@ -350,6 +350,7 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #endif #if CONFIG_HEVC_D3D11VA_HWACCEL *fmt++ = AV_PIX_FMT_D3D11VA_VLD; + *fmt++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_HEVC_VAAPI_HWACCEL *fmt++ = AV_PIX_FMT_VAAPI; @@ -364,6 +365,7 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #endif #if CONFIG_HEVC_D3D11VA_HWACCEL *fmt++ = AV_PIX_FMT_D3D11VA_VLD; + *fmt++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_HEVC_VAAPI_HWACCEL *fmt++ = AV_PIX_FMT_VAAPI; diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c index 58a5a20864..22c29c1505 100644 --- a/libavcodec/mpeg12dec.c +++ b/libavcodec/mpeg12dec.c @@ -1159,6 +1159,7 @@ static const enum AVPixelFormat mpeg2_hwaccel_pixfmt_list_420[] = { #endif #if CONFIG_MPEG2_D3D11VA_HWACCEL AV_PIX_FMT_D3D11VA_VLD, + AV_PIX_FMT_D3D11, #endif #if CONFIG_MPEG2_VAAPI_HWACCEL AV_PIX_FMT_VAAPI, diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c index 75d336583c..16c601e756 100644 --- a/libavcodec/vc1dec.c +++ b/libavcodec/vc1dec.c @@ -1150,6 +1150,7 @@ static const enum AVPixelFormat vc1_hwaccel_pixfmt_list_420[] = { #endif #if CONFIG_VC1_D3D11VA_HWACCEL AV_PIX_FMT_D3D11VA_VLD, + AV_PIX_FMT_D3D11, #endif #if CONFIG_VC1_VAAPI_HWACCEL AV_PIX_FMT_VAAPI, diff --git a/libavcodec/version.h b/libavcodec/version.h index 1eaaf832ca..06615268f3 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,7 +28,7 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 57 -#define LIBAVCODEC_VERSION_MINOR 99 +#define LIBAVCODEC_VERSION_MINOR 100 #define LIBAVCODEC_VERSION_MICRO 102 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c index 4d7310f6d4..7d8aced8c8 100644 --- a/libavcodec/vp9.c +++ b/libavcodec/vp9.c @@ -113,7 +113,7 @@ fail: static int update_size(AVCodecContext *avctx, int w, int h) { -#define HWACCEL_MAX (CONFIG_VP9_DXVA2_HWACCEL + CONFIG_VP9_D3D11VA_HWACCEL + CONFIG_VP9_VAAPI_HWACCEL) +#define HWACCEL_MAX (CONFIG_VP9_DXVA2_HWACCEL + CONFIG_VP9_D3D11VA_HWACCEL * 2 + CONFIG_VP9_VAAPI_HWACCEL) enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts; VP9Context *s = avctx->priv_data; uint8_t *p; @@ -132,6 +132,7 @@ static int update_size(AVCodecContext *avctx, int w, int h) #endif #if CONFIG_VP9_D3D11VA_HWACCEL *fmtp++ = AV_PIX_FMT_D3D11VA_VLD; + *fmtp++ = AV_PIX_FMT_D3D11; #endif #if CONFIG_VP9_VAAPI_HWACCEL *fmtp++ = AV_PIX_FMT_VAAPI; diff --git a/libavutil/hwcontext_dxva2.h b/libavutil/hwcontext_dxva2.h index 6c36cb4b6b..e1b79bc0de 100644 --- a/libavutil/hwcontext_dxva2.h +++ b/libavutil/hwcontext_dxva2.h @@ -65,6 +65,9 @@ typedef struct AVDXVA2FramesContext { * * If it is non-NULL, libavutil will call IDirectXVideoDecoder_Release() on * it just before the internal surface pool is freed. + * + * This is for convenience only. Some code uses other methods to manage the + * decoder reference. */ IDirectXVideoDecoder *decoder_to_release; } AVDXVA2FramesContext;