On Tue, 3 Jan 2017 17:35:00 +0100 Steve Lhomme <rob...@videolabs.io> wrote:
> From: Steve Lhomme <rob...@gmail.com> > > avconv_dxva.h has to be included and misc. typedefs have to be set to use the > proper DXVA2 structures. > > initguid.h is included in avconv_dxva.h so any includes after that will also > define GUIDs locally. > --- > avconv_dxva2.c | 277 ++++++++--------------------------------------- > avconv_dxva_template.c | 289 > +++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 335 insertions(+), 231 deletions(-) > create mode 100644 avconv_dxva_template.c > > diff --git a/avconv_dxva2.c b/avconv_dxva2.c > index 7578c3f..442a0bd 100644 > --- a/avconv_dxva2.c > +++ b/avconv_dxva2.c > @@ -43,52 +43,6 @@ > #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 <initguid.h> > -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_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 }, > - > - { NULL, 0 }, > -}; > - > typedef struct DXVA2Context { > IDirectXVideoDecoder *decoder; > > @@ -102,55 +56,24 @@ typedef struct DXVA2Context { > AVBufferRef *hw_frames_ctx; > } DXVA2Context; > > +typedef DXVA2_ConfigPictureDecode DXVA_DECODER_CONFIG; > +typedef D3DFORMAT DXVA_SURFACE_FORMAT; > +typedef DXVA2Context DXVA_CONTEXT; > +typedef struct dxva_context DXVA_AV_CONTEXT; > +typedef IDirectXVideoDecoderService *DXVA_DECODER_SERVICE; > +#include "avconv_dxva_template.c" > + > +DEFINE_GUID(IID_IDirectXVideoDecoderService, > 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02); > + > 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; > + dxva_uninit(s); > } > > static int dxva2_alloc(AVCodecContext *s) > @@ -163,21 +86,11 @@ static int dxva2_alloc(AVCodecContext *s) > > 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); > + int ret = dxva_alloc(s, AV_HWDEVICE_TYPE_DXVA2); > if (ret < 0) > - goto fail; > + return ret; > + > + ctx = ist->hwaccel_ctx; > device_ctx = (AVHWDeviceContext*)ctx->hw_device_ctx->data; > device_hwctx = device_ctx->hwctx; > > @@ -196,18 +109,11 @@ static int dxva2_alloc(AVCodecContext *s) > 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; > + ist->hwaccel_uninit = dxva2_uninit; > > return 0; > fail: > - dxva2_uninit(s); > + dxva_uninit(s); > return AVERROR(EINVAL); > } > > @@ -218,11 +124,10 @@ static int > dxva2_get_decoder_configuration(AVCodecContext *s, const GUID *device > 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; > + unsigned cfg_count = 0; > DXVA2_ConfigPictureDecode *cfg_list = NULL; > - DXVA2_ConfigPictureDecode best_cfg = {{0}}; > HRESULT hr; > - int i; > + int ret; > > hr = > IDirectXVideoDecoderService_GetDecoderConfigurations(ctx->decoder_service, > device_guid, desc, NULL, &cfg_count, &cfg_list); > if (FAILED(hr)) { > @@ -230,32 +135,29 @@ static int > dxva2_get_decoder_configuration(AVCodecContext *s, const GUID *device > 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; > - } > - } > + ret = dxva_get_decoder_configuration(s, cfg_list, cfg_count, config); > CoTaskMemFree(cfg_list); > + return ret; > +} > > - if (!best_score) { > - av_log(NULL, loglevel, "No valid decoder configuration available\n"); > - return AVERROR(EINVAL); > +static int dxva2_validate_output(IDirectXVideoDecoderService > *decoder_service, GUID guid, D3DFORMAT surface_format) > +{ > + HRESULT hr; > + int ret = 0; > + unsigned j, target_count = 0; > + D3DFORMAT *target_list; > + hr = > IDirectXVideoDecoderService_GetDecoderRenderTargets(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 == surface_format) { > + ret = 1; > + break; > + } > + } > + CoTaskMemFree(target_list); > } > - > - *config = best_cfg; > - return 0; > + return ret; > } > > static int dxva2_create_decoder(AVCodecContext *s) > @@ -265,15 +167,13 @@ static int dxva2_create_decoder(AVCodecContext *s) > DXVA2Context *ctx = ist->hwaccel_ctx; > struct dxva_context *dxva_ctx = s->hwaccel_context; > GUID *guid_list = NULL; > - unsigned guid_count = 0, i, j; > + unsigned guid_count = 0; > 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; > @@ -285,77 +185,22 @@ static int dxva2_create_decoder(AVCodecContext *s) > 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; > - } > - } > + ret = dxva_get_decoder_guid(s, ctx->decoder_service, surface_format, > dxva2_validate_output, > + guid_count, guid_list, &device_guid); > CoTaskMemFree(guid_list); > - > - if (IsEqualGUID(&device_guid, &GUID_NULL)) { > - av_log(NULL, loglevel, "No decoder device for codec found\n"); > + if (ret < 0) { > goto fail; > } > > desc.SampleWidth = s->coded_width; > desc.SampleHeight = s->coded_height; > - desc.Format = target_format; > + desc.Format = surface_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 > - 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; > @@ -363,14 +208,10 @@ static int dxva2_create_decoder(AVCodecContext *s) > frames_hwctx = frames_ctx->hwctx; > > frames_ctx->format = AV_PIX_FMT_DXVA2_VLD; > - frames_ctx->sw_format = s->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ? > - 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; > > + dxva_adjust_decoder(s); > + > ret = av_hwframe_ctx_init(ctx->hw_frames_ctx); > if (ret < 0) { > av_log(NULL, loglevel, "Failed to initialize the HW frames > context\n"); > @@ -393,9 +234,6 @@ static int dxva2_create_decoder(AVCodecContext *s) > 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); > @@ -405,8 +243,6 @@ fail: > 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) { > @@ -414,27 +250,6 @@ int dxva2_init(AVCodecContext *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; > + return dxva_init(s, dxva2_create_decoder); > } > diff --git a/avconv_dxva_template.c b/avconv_dxva_template.c > new file mode 100644 > index 0000000..c6bd0c5 > --- /dev/null > +++ b/avconv_dxva_template.c > @@ -0,0 +1,289 @@ > +/* > + * 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 > + */ > + > +/* define all the GUIDs used directly here, > + to avoid problems with inconsistent dxva2api.h versions in mingw-w64 and > different MSVC version */ > +#include <initguid.h> > +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_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 dxva_mode { > + const GUID *guid; > + enum AVCodecID codec; > +} dxva_mode; > + > +static const dxva_mode dxva_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 }, > + > + { NULL, 0 }, > +}; > + > +static int dxva_get_decoder_configuration(AVCodecContext *s, > + const DXVA_DECODER_CONFIG > *cfg_list, > + unsigned cfg_count, > + DXVA_DECODER_CONFIG *config) > +{ > + InputStream *ist = s->opaque; > + int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : > AV_LOG_ERROR; > + unsigned i, best_score = 0; > + DXVA_DECODER_CONFIG best_cfg = { { 0 } }; > + > + for (i = 0; i < cfg_count; i++) { > + const DXVA_DECODER_CONFIG *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; > + } > + } > + > + if (!best_score) { > + av_log(NULL, loglevel, "No valid decoder configuration available\n"); > + return AVERROR(EINVAL); > + } > + > + *config = best_cfg; > + return 0; > +} > + > + > +static int dxva_get_decoder_guid(AVCodecContext *s, DXVA_DECODER_SERVICE > service, DXVA_SURFACE_FORMAT surface_format, > + int (*validate)(DXVA_DECODER_SERVICE > service, GUID guid, DXVA_SURFACE_FORMAT surface_format), > + unsigned guid_count, const GUID *guid_list, > GUID *decoder_guid) > +{ > + InputStream *ist = s->opaque; > + DXVA_AV_CONTEXT *dxva_ctx = ist->hwaccel_ctx; > + int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : > AV_LOG_ERROR; > + unsigned i, j; > + > + *decoder_guid = GUID_NULL; > + for (i = 0; dxva_modes[i].guid; i++) { > + const dxva_mode *mode = &dxva_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; > + > + if (validate(service, *mode->guid, surface_format)) { > + *decoder_guid = *mode->guid; > + break; > + } > + } > + > + if (IsEqualGUID(decoder_guid, &GUID_NULL)) { > + av_log(NULL, loglevel, "No decoder device for codec found\n"); > + return AVERROR(EINVAL); > + } > + > + if (IsEqualGUID(decoder_guid, &DXVADDI_Intel_ModeH264_E)) > + dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO; > + > + return 0; > +} > + > +static void dxva_adjust_decoder(AVCodecContext *s) > +{ > + InputStream *ist = s->opaque; > + AVHWFramesContext *frames_ctx; > + DXVA_CONTEXT *ctx = ist->hwaccel_ctx; > + int surface_alignment, num_surfaces; > + > + /* 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 > + num_surfaces += 2; > + > + /* add extra surfaces for frame threading */ > + if (s->active_thread_type & FF_THREAD_FRAME) > + num_surfaces += s->thread_count; > + > + frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data; > + > + frames_ctx->sw_format = s->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ? > + 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; > +} > + > +static int dxva_init(AVCodecContext *s, int (*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; > + int ret; > + > + 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 DXVA 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 DXVA HWAccel: > %d\n", s->profile); > + return AVERROR(EINVAL); > + } > + > + av_buffer_unref(&ctx->hw_frames_ctx); > + > + ret = create_decoder(s); > + if (ret < 0) > + av_log(NULL, loglevel, "Error creating the DXVA decoder\n"); > + > + return ret; > +} > + > +static int dxva_get_buffer(AVCodecContext *s, AVFrame *frame, int flags) > +{ > + InputStream *ist = s->opaque; > + DXVA_CONTEXT *ctx = ist->hwaccel_ctx; > + > + return av_hwframe_get_buffer(ctx->hw_frames_ctx, frame, 0); > +} > + > +static int dxva_retrieve_data(AVCodecContext *s, AVFrame *frame) > +{ > + InputStream *ist = s->opaque; > + DXVA_CONTEXT *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 void dxva_uninit(AVCodecContext *s) > +{ > + InputStream *ist = s->opaque; > + DXVA_CONTEXT *ctx = ist->hwaccel_ctx; > + > + ist->hwaccel_uninit = NULL; > + ist->hwaccel_get_buffer = NULL; > + ist->hwaccel_retrieve_data = NULL; > + > + 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 dxva_alloc(AVCodecContext *s, enum AVHWDeviceType type) > +{ > + InputStream *ist = s->opaque; > + DXVA_CONTEXT *ctx; > + > + int ret; > + > + ctx = av_mallocz(sizeof(*ctx)); > + if (!ctx) > + return AVERROR(ENOMEM); > + > + ist->hwaccel_ctx = ctx; > + ist->hwaccel_uninit = dxva_uninit; > + ist->hwaccel_get_buffer = dxva_get_buffer; > + ist->hwaccel_retrieve_data = dxva_retrieve_data; > + > + ret = av_hwdevice_ctx_create(&ctx->hw_device_ctx, type, > + ist->hwaccel_device, NULL, 0); > + if (ret < 0) > + goto fail; > + > + ctx->tmp_frame = av_frame_alloc(); > + if (!ctx->tmp_frame) > + goto fail; > + > + s->hwaccel_context = av_mallocz(sizeof(DXVA_AV_CONTEXT)); > + if (!s->hwaccel_context) > + goto fail; > + > + return 0; > +fail: > + dxva_uninit(s); > + return AVERROR(EINVAL); > +} I still don't like the "template" method very much, but it's probably not a blocker. _______________________________________________ libav-devel mailing list libav-devel@libav.org https://lists.libav.org/mailman/listinfo/libav-devel