xref: /third_party/ffmpeg/libavcodec/dxva2.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * DXVA2 HW acceleration.
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * copyright (c) 2010 Laurent Aimar
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * This file is part of FFmpeg.
7cabdff1aSopenharmony_ci *
8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
12cabdff1aSopenharmony_ci *
13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16cabdff1aSopenharmony_ci * Lesser General Public License for more details.
17cabdff1aSopenharmony_ci *
18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21cabdff1aSopenharmony_ci */
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include <assert.h>
24cabdff1aSopenharmony_ci#include <string.h>
25cabdff1aSopenharmony_ci#include <initguid.h>
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_ci#include "libavutil/common.h"
28cabdff1aSopenharmony_ci#include "libavutil/log.h"
29cabdff1aSopenharmony_ci#include "libavutil/time.h"
30cabdff1aSopenharmony_ci
31cabdff1aSopenharmony_ci#include "avcodec.h"
32cabdff1aSopenharmony_ci#include "decode.h"
33cabdff1aSopenharmony_ci#include "dxva2_internal.h"
34cabdff1aSopenharmony_ci
35cabdff1aSopenharmony_ci/* define all the GUIDs used directly here,
36cabdff1aSopenharmony_ci to avoid problems with inconsistent dxva2api.h versions in mingw-w64 and different MSVC version */
37cabdff1aSopenharmony_ciDEFINE_GUID(ff_DXVA2_ModeMPEG2_VLD,      0xee27417f, 0x5e28,0x4e65,0xbe,0xea,0x1d,0x26,0xb5,0x08,0xad,0xc9);
38cabdff1aSopenharmony_ciDEFINE_GUID(ff_DXVA2_ModeMPEG2and1_VLD,  0x86695f12, 0x340e,0x4f04,0x9f,0xd3,0x92,0x53,0xdd,0x32,0x74,0x60);
39cabdff1aSopenharmony_ciDEFINE_GUID(ff_DXVA2_ModeH264_E,         0x1b81be68, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
40cabdff1aSopenharmony_ciDEFINE_GUID(ff_DXVA2_ModeH264_F,         0x1b81be69, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
41cabdff1aSopenharmony_ciDEFINE_GUID(ff_DXVADDI_Intel_ModeH264_E, 0x604F8E68, 0x4951,0x4C54,0x88,0xFE,0xAB,0xD2,0x5C,0x15,0xB3,0xD6);
42cabdff1aSopenharmony_ciDEFINE_GUID(ff_DXVA2_ModeVC1_D,          0x1b81beA3, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
43cabdff1aSopenharmony_ciDEFINE_GUID(ff_DXVA2_ModeVC1_D2010,      0x1b81beA4, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
44cabdff1aSopenharmony_ciDEFINE_GUID(ff_DXVA2_ModeHEVC_VLD_Main,  0x5b11d51b, 0x2f4c,0x4452,0xbc,0xc3,0x09,0xf2,0xa1,0x16,0x0c,0xc0);
45cabdff1aSopenharmony_ciDEFINE_GUID(ff_DXVA2_ModeHEVC_VLD_Main10,0x107af0e0, 0xef1a,0x4d19,0xab,0xa8,0x67,0xa1,0x63,0x07,0x3d,0x13);
46cabdff1aSopenharmony_ciDEFINE_GUID(ff_DXVA2_ModeVP9_VLD_Profile0,0x463707f8,0xa1d0,0x4585,0x87,0x6d,0x83,0xaa,0x6d,0x60,0xb8,0x9e);
47cabdff1aSopenharmony_ciDEFINE_GUID(ff_DXVA2_ModeVP9_VLD_10bit_Profile2,0xa4c749ef,0x6ecf,0x48aa,0x84,0x48,0x50,0xa7,0xa1,0x16,0x5f,0xf7);
48cabdff1aSopenharmony_ciDEFINE_GUID(ff_DXVA2_ModeAV1_VLD_Profile0,0xb8be4ccb,0xcf53,0x46ba,0x8d,0x59,0xd6,0xb8,0xa6,0xda,0x5d,0x2a);
49cabdff1aSopenharmony_ciDEFINE_GUID(ff_DXVA2_NoEncrypt,          0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
50cabdff1aSopenharmony_ciDEFINE_GUID(ff_GUID_NULL,                0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
51cabdff1aSopenharmony_ciDEFINE_GUID(ff_IID_IDirectXVideoDecoderService, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02);
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_citypedef struct dxva_mode {
54cabdff1aSopenharmony_ci    const GUID     *guid;
55cabdff1aSopenharmony_ci    enum AVCodecID codec;
56cabdff1aSopenharmony_ci    // List of supported profiles, terminated by a FF_PROFILE_UNKNOWN entry.
57cabdff1aSopenharmony_ci    // If NULL, don't check profile.
58cabdff1aSopenharmony_ci    const int      *profiles;
59cabdff1aSopenharmony_ci} dxva_mode;
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_cistatic const int prof_mpeg2_main[]   = {FF_PROFILE_MPEG2_SIMPLE,
62cabdff1aSopenharmony_ci                                        FF_PROFILE_MPEG2_MAIN,
63cabdff1aSopenharmony_ci                                        FF_PROFILE_UNKNOWN};
64cabdff1aSopenharmony_cistatic const int prof_h264_high[]    = {FF_PROFILE_H264_CONSTRAINED_BASELINE,
65cabdff1aSopenharmony_ci                                        FF_PROFILE_H264_MAIN,
66cabdff1aSopenharmony_ci                                        FF_PROFILE_H264_HIGH,
67cabdff1aSopenharmony_ci                                        FF_PROFILE_UNKNOWN};
68cabdff1aSopenharmony_cistatic const int prof_hevc_main[]    = {FF_PROFILE_HEVC_MAIN,
69cabdff1aSopenharmony_ci                                        FF_PROFILE_UNKNOWN};
70cabdff1aSopenharmony_cistatic const int prof_hevc_main10[]  = {FF_PROFILE_HEVC_MAIN_10,
71cabdff1aSopenharmony_ci                                        FF_PROFILE_UNKNOWN};
72cabdff1aSopenharmony_cistatic const int prof_vp9_profile0[] = {FF_PROFILE_VP9_0,
73cabdff1aSopenharmony_ci                                        FF_PROFILE_UNKNOWN};
74cabdff1aSopenharmony_cistatic const int prof_vp9_profile2[] = {FF_PROFILE_VP9_2,
75cabdff1aSopenharmony_ci                                        FF_PROFILE_UNKNOWN};
76cabdff1aSopenharmony_cistatic const int prof_av1_profile0[] = {FF_PROFILE_AV1_MAIN,
77cabdff1aSopenharmony_ci                                        FF_PROFILE_UNKNOWN};
78cabdff1aSopenharmony_ci
79cabdff1aSopenharmony_cistatic const dxva_mode dxva_modes[] = {
80cabdff1aSopenharmony_ci    /* MPEG-2 */
81cabdff1aSopenharmony_ci    { &ff_DXVA2_ModeMPEG2_VLD,       AV_CODEC_ID_MPEG2VIDEO, prof_mpeg2_main },
82cabdff1aSopenharmony_ci    { &ff_DXVA2_ModeMPEG2and1_VLD,   AV_CODEC_ID_MPEG2VIDEO, prof_mpeg2_main },
83cabdff1aSopenharmony_ci
84cabdff1aSopenharmony_ci    /* H.264 */
85cabdff1aSopenharmony_ci    { &ff_DXVA2_ModeH264_F,          AV_CODEC_ID_H264, prof_h264_high },
86cabdff1aSopenharmony_ci    { &ff_DXVA2_ModeH264_E,          AV_CODEC_ID_H264, prof_h264_high },
87cabdff1aSopenharmony_ci    /* Intel specific H.264 mode */
88cabdff1aSopenharmony_ci    { &ff_DXVADDI_Intel_ModeH264_E,  AV_CODEC_ID_H264, prof_h264_high },
89cabdff1aSopenharmony_ci
90cabdff1aSopenharmony_ci    /* VC-1 / WMV3 */
91cabdff1aSopenharmony_ci    { &ff_DXVA2_ModeVC1_D2010,       AV_CODEC_ID_VC1 },
92cabdff1aSopenharmony_ci    { &ff_DXVA2_ModeVC1_D2010,       AV_CODEC_ID_WMV3 },
93cabdff1aSopenharmony_ci    { &ff_DXVA2_ModeVC1_D,           AV_CODEC_ID_VC1 },
94cabdff1aSopenharmony_ci    { &ff_DXVA2_ModeVC1_D,           AV_CODEC_ID_WMV3 },
95cabdff1aSopenharmony_ci
96cabdff1aSopenharmony_ci    /* HEVC/H.265 */
97cabdff1aSopenharmony_ci    { &ff_DXVA2_ModeHEVC_VLD_Main10, AV_CODEC_ID_HEVC, prof_hevc_main10 },
98cabdff1aSopenharmony_ci    { &ff_DXVA2_ModeHEVC_VLD_Main,   AV_CODEC_ID_HEVC, prof_hevc_main },
99cabdff1aSopenharmony_ci
100cabdff1aSopenharmony_ci    /* VP8/9 */
101cabdff1aSopenharmony_ci    { &ff_DXVA2_ModeVP9_VLD_Profile0,       AV_CODEC_ID_VP9, prof_vp9_profile0 },
102cabdff1aSopenharmony_ci    { &ff_DXVA2_ModeVP9_VLD_10bit_Profile2, AV_CODEC_ID_VP9, prof_vp9_profile2 },
103cabdff1aSopenharmony_ci
104cabdff1aSopenharmony_ci    /* AV1 */
105cabdff1aSopenharmony_ci    { &ff_DXVA2_ModeAV1_VLD_Profile0,       AV_CODEC_ID_AV1, prof_av1_profile0 },
106cabdff1aSopenharmony_ci
107cabdff1aSopenharmony_ci    { NULL,                          0 },
108cabdff1aSopenharmony_ci};
109cabdff1aSopenharmony_ci
110cabdff1aSopenharmony_cistatic int dxva_get_decoder_configuration(AVCodecContext *avctx,
111cabdff1aSopenharmony_ci                                          const void *cfg_list,
112cabdff1aSopenharmony_ci                                          unsigned cfg_count)
113cabdff1aSopenharmony_ci{
114cabdff1aSopenharmony_ci    FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx);
115cabdff1aSopenharmony_ci    unsigned i, best_score = 0;
116cabdff1aSopenharmony_ci    int best_cfg = -1;
117cabdff1aSopenharmony_ci
118cabdff1aSopenharmony_ci    for (i = 0; i < cfg_count; i++) {
119cabdff1aSopenharmony_ci        unsigned score;
120cabdff1aSopenharmony_ci        UINT ConfigBitstreamRaw;
121cabdff1aSopenharmony_ci        GUID guidConfigBitstreamEncryption;
122cabdff1aSopenharmony_ci
123cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
124cabdff1aSopenharmony_ci        if (sctx->pix_fmt == AV_PIX_FMT_D3D11) {
125cabdff1aSopenharmony_ci            D3D11_VIDEO_DECODER_CONFIG *cfg = &((D3D11_VIDEO_DECODER_CONFIG *)cfg_list)[i];
126cabdff1aSopenharmony_ci            ConfigBitstreamRaw = cfg->ConfigBitstreamRaw;
127cabdff1aSopenharmony_ci            guidConfigBitstreamEncryption = cfg->guidConfigBitstreamEncryption;
128cabdff1aSopenharmony_ci        }
129cabdff1aSopenharmony_ci#endif
130cabdff1aSopenharmony_ci#if CONFIG_DXVA2
131cabdff1aSopenharmony_ci        if (sctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
132cabdff1aSopenharmony_ci            DXVA2_ConfigPictureDecode *cfg = &((DXVA2_ConfigPictureDecode *)cfg_list)[i];
133cabdff1aSopenharmony_ci            ConfigBitstreamRaw = cfg->ConfigBitstreamRaw;
134cabdff1aSopenharmony_ci            guidConfigBitstreamEncryption = cfg->guidConfigBitstreamEncryption;
135cabdff1aSopenharmony_ci        }
136cabdff1aSopenharmony_ci#endif
137cabdff1aSopenharmony_ci
138cabdff1aSopenharmony_ci        if (ConfigBitstreamRaw == 1)
139cabdff1aSopenharmony_ci            score = 1;
140cabdff1aSopenharmony_ci        else if (avctx->codec_id == AV_CODEC_ID_H264 && ConfigBitstreamRaw == 2)
141cabdff1aSopenharmony_ci            score = 2;
142cabdff1aSopenharmony_ci        else
143cabdff1aSopenharmony_ci            continue;
144cabdff1aSopenharmony_ci        if (IsEqualGUID(&guidConfigBitstreamEncryption, &ff_DXVA2_NoEncrypt))
145cabdff1aSopenharmony_ci            score += 16;
146cabdff1aSopenharmony_ci        if (score > best_score) {
147cabdff1aSopenharmony_ci            best_score = score;
148cabdff1aSopenharmony_ci            best_cfg = i;
149cabdff1aSopenharmony_ci        }
150cabdff1aSopenharmony_ci    }
151cabdff1aSopenharmony_ci
152cabdff1aSopenharmony_ci    if (!best_score) {
153cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_VERBOSE, "No valid decoder configuration available\n");
154cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
155cabdff1aSopenharmony_ci    }
156cabdff1aSopenharmony_ci
157cabdff1aSopenharmony_ci    return best_cfg;
158cabdff1aSopenharmony_ci}
159cabdff1aSopenharmony_ci
160cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
161cabdff1aSopenharmony_cistatic int d3d11va_validate_output(void *service, GUID guid, const void *surface_format)
162cabdff1aSopenharmony_ci{
163cabdff1aSopenharmony_ci    HRESULT hr;
164cabdff1aSopenharmony_ci    BOOL is_supported = FALSE;
165cabdff1aSopenharmony_ci    hr = ID3D11VideoDevice_CheckVideoDecoderFormat((ID3D11VideoDevice *)service,
166cabdff1aSopenharmony_ci                                                   &guid,
167cabdff1aSopenharmony_ci                                                   *(DXGI_FORMAT *)surface_format,
168cabdff1aSopenharmony_ci                                                   &is_supported);
169cabdff1aSopenharmony_ci    return SUCCEEDED(hr) && is_supported;
170cabdff1aSopenharmony_ci}
171cabdff1aSopenharmony_ci#endif
172cabdff1aSopenharmony_ci
173cabdff1aSopenharmony_ci#if CONFIG_DXVA2
174cabdff1aSopenharmony_cistatic int dxva2_validate_output(void *decoder_service, GUID guid, const void *surface_format)
175cabdff1aSopenharmony_ci{
176cabdff1aSopenharmony_ci    HRESULT hr;
177cabdff1aSopenharmony_ci    int ret = 0;
178cabdff1aSopenharmony_ci    unsigned j, target_count;
179cabdff1aSopenharmony_ci    D3DFORMAT *target_list;
180cabdff1aSopenharmony_ci    hr = IDirectXVideoDecoderService_GetDecoderRenderTargets((IDirectXVideoDecoderService *)decoder_service, &guid, &target_count, &target_list);
181cabdff1aSopenharmony_ci    if (SUCCEEDED(hr)) {
182cabdff1aSopenharmony_ci        for (j = 0; j < target_count; j++) {
183cabdff1aSopenharmony_ci            const D3DFORMAT format = target_list[j];
184cabdff1aSopenharmony_ci            if (format == *(D3DFORMAT *)surface_format) {
185cabdff1aSopenharmony_ci                ret = 1;
186cabdff1aSopenharmony_ci                break;
187cabdff1aSopenharmony_ci            }
188cabdff1aSopenharmony_ci        }
189cabdff1aSopenharmony_ci        CoTaskMemFree(target_list);
190cabdff1aSopenharmony_ci    }
191cabdff1aSopenharmony_ci    return ret;
192cabdff1aSopenharmony_ci}
193cabdff1aSopenharmony_ci#endif
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_cistatic int dxva_check_codec_compatibility(AVCodecContext *avctx, const dxva_mode *mode)
196cabdff1aSopenharmony_ci{
197cabdff1aSopenharmony_ci    if (mode->codec != avctx->codec_id)
198cabdff1aSopenharmony_ci            return 0;
199cabdff1aSopenharmony_ci
200cabdff1aSopenharmony_ci    if (mode->profiles && !(avctx->hwaccel_flags & AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH)) {
201cabdff1aSopenharmony_ci        int i, found = 0;
202cabdff1aSopenharmony_ci        for (i = 0; mode->profiles[i] != FF_PROFILE_UNKNOWN; i++) {
203cabdff1aSopenharmony_ci            if (avctx->profile == mode->profiles[i]) {
204cabdff1aSopenharmony_ci                found = 1;
205cabdff1aSopenharmony_ci                break;
206cabdff1aSopenharmony_ci            }
207cabdff1aSopenharmony_ci        }
208cabdff1aSopenharmony_ci        if (!found)
209cabdff1aSopenharmony_ci            return 0;
210cabdff1aSopenharmony_ci    }
211cabdff1aSopenharmony_ci
212cabdff1aSopenharmony_ci    return 1;
213cabdff1aSopenharmony_ci}
214cabdff1aSopenharmony_ci
215cabdff1aSopenharmony_cistatic void dxva_list_guids_debug(AVCodecContext *avctx, void *service,
216cabdff1aSopenharmony_ci                                 unsigned guid_count, const GUID *guid_list)
217cabdff1aSopenharmony_ci{
218cabdff1aSopenharmony_ci    FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx);
219cabdff1aSopenharmony_ci    int i;
220cabdff1aSopenharmony_ci
221cabdff1aSopenharmony_ci    av_log(avctx, AV_LOG_VERBOSE, "Decoder GUIDs reported as supported:\n");
222cabdff1aSopenharmony_ci
223cabdff1aSopenharmony_ci    for (i = 0; i < guid_count; i++) {
224cabdff1aSopenharmony_ci        const GUID *guid = &guid_list[i];
225cabdff1aSopenharmony_ci
226cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_VERBOSE,
227cabdff1aSopenharmony_ci             "{%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x}",
228cabdff1aSopenharmony_ci             (unsigned) guid->Data1, guid->Data2, guid->Data3,
229cabdff1aSopenharmony_ci             guid->Data4[0], guid->Data4[1],
230cabdff1aSopenharmony_ci             guid->Data4[2], guid->Data4[3],
231cabdff1aSopenharmony_ci             guid->Data4[4], guid->Data4[5],
232cabdff1aSopenharmony_ci             guid->Data4[6], guid->Data4[7]);
233cabdff1aSopenharmony_ci
234cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
235cabdff1aSopenharmony_ci        if (sctx->pix_fmt == AV_PIX_FMT_D3D11) {
236cabdff1aSopenharmony_ci            DXGI_FORMAT format;
237cabdff1aSopenharmony_ci            // We don't know the maximum valid DXGI_FORMAT, so use 200 as
238cabdff1aSopenharmony_ci            // arbitrary upper bound (that could become outdated).
239cabdff1aSopenharmony_ci            for (format = 0; format < 200; format++) {
240cabdff1aSopenharmony_ci                if (d3d11va_validate_output(service, *guid, &format))
241cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_VERBOSE, " %d", (int)format);
242cabdff1aSopenharmony_ci            }
243cabdff1aSopenharmony_ci        }
244cabdff1aSopenharmony_ci#endif
245cabdff1aSopenharmony_ci#if CONFIG_DXVA2
246cabdff1aSopenharmony_ci        if (sctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
247cabdff1aSopenharmony_ci            const D3DFORMAT formats[] = {MKTAG('N', 'V', '1', '2'),
248cabdff1aSopenharmony_ci                                         MKTAG('P', '0', '1', '0')};
249cabdff1aSopenharmony_ci            int i;
250cabdff1aSopenharmony_ci            for (i = 0; i < FF_ARRAY_ELEMS(formats); i++) {
251cabdff1aSopenharmony_ci                if (dxva2_validate_output(service, *guid, &formats[i]))
252cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_VERBOSE, " %d", i);
253cabdff1aSopenharmony_ci            }
254cabdff1aSopenharmony_ci        }
255cabdff1aSopenharmony_ci#endif
256cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_VERBOSE, "\n");
257cabdff1aSopenharmony_ci    }
258cabdff1aSopenharmony_ci}
259cabdff1aSopenharmony_ci
260cabdff1aSopenharmony_cistatic int dxva_get_decoder_guid(AVCodecContext *avctx, void *service, void *surface_format,
261cabdff1aSopenharmony_ci                                 unsigned guid_count, const GUID *guid_list, GUID *decoder_guid)
262cabdff1aSopenharmony_ci{
263cabdff1aSopenharmony_ci    FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx);
264cabdff1aSopenharmony_ci    unsigned i, j;
265cabdff1aSopenharmony_ci
266cabdff1aSopenharmony_ci    dxva_list_guids_debug(avctx, service, guid_count, guid_list);
267cabdff1aSopenharmony_ci
268cabdff1aSopenharmony_ci    *decoder_guid = ff_GUID_NULL;
269cabdff1aSopenharmony_ci    for (i = 0; dxva_modes[i].guid; i++) {
270cabdff1aSopenharmony_ci        const dxva_mode *mode = &dxva_modes[i];
271cabdff1aSopenharmony_ci        int validate;
272cabdff1aSopenharmony_ci        if (!dxva_check_codec_compatibility(avctx, mode))
273cabdff1aSopenharmony_ci            continue;
274cabdff1aSopenharmony_ci
275cabdff1aSopenharmony_ci        for (j = 0; j < guid_count; j++) {
276cabdff1aSopenharmony_ci            if (IsEqualGUID(mode->guid, &guid_list[j]))
277cabdff1aSopenharmony_ci                break;
278cabdff1aSopenharmony_ci        }
279cabdff1aSopenharmony_ci        if (j == guid_count)
280cabdff1aSopenharmony_ci            continue;
281cabdff1aSopenharmony_ci
282cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
283cabdff1aSopenharmony_ci        if (sctx->pix_fmt == AV_PIX_FMT_D3D11)
284cabdff1aSopenharmony_ci            validate = d3d11va_validate_output(service, *mode->guid, surface_format);
285cabdff1aSopenharmony_ci#endif
286cabdff1aSopenharmony_ci#if CONFIG_DXVA2
287cabdff1aSopenharmony_ci        if (sctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
288cabdff1aSopenharmony_ci            validate = dxva2_validate_output(service, *mode->guid, surface_format);
289cabdff1aSopenharmony_ci#endif
290cabdff1aSopenharmony_ci        if (validate) {
291cabdff1aSopenharmony_ci            *decoder_guid = *mode->guid;
292cabdff1aSopenharmony_ci            break;
293cabdff1aSopenharmony_ci        }
294cabdff1aSopenharmony_ci    }
295cabdff1aSopenharmony_ci
296cabdff1aSopenharmony_ci    if (IsEqualGUID(decoder_guid, &ff_GUID_NULL)) {
297cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_VERBOSE, "No decoder device for codec found\n");
298cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
299cabdff1aSopenharmony_ci    }
300cabdff1aSopenharmony_ci
301cabdff1aSopenharmony_ci    if (IsEqualGUID(decoder_guid, &ff_DXVADDI_Intel_ModeH264_E))
302cabdff1aSopenharmony_ci        sctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;
303cabdff1aSopenharmony_ci
304cabdff1aSopenharmony_ci    return 0;
305cabdff1aSopenharmony_ci}
306cabdff1aSopenharmony_ci
307cabdff1aSopenharmony_cistatic void bufref_free_interface(void *opaque, uint8_t *data)
308cabdff1aSopenharmony_ci{
309cabdff1aSopenharmony_ci    IUnknown_Release((IUnknown *)opaque);
310cabdff1aSopenharmony_ci}
311cabdff1aSopenharmony_ci
312cabdff1aSopenharmony_cistatic AVBufferRef *bufref_wrap_interface(IUnknown *iface)
313cabdff1aSopenharmony_ci{
314cabdff1aSopenharmony_ci    return av_buffer_create((uint8_t*)iface, 1, bufref_free_interface, iface, 0);
315cabdff1aSopenharmony_ci}
316cabdff1aSopenharmony_ci
317cabdff1aSopenharmony_ci#if CONFIG_DXVA2
318cabdff1aSopenharmony_ci
319cabdff1aSopenharmony_cistatic int dxva2_get_decoder_configuration(AVCodecContext *avctx, const GUID *device_guid,
320cabdff1aSopenharmony_ci                                           const DXVA2_VideoDesc *desc,
321cabdff1aSopenharmony_ci                                           DXVA2_ConfigPictureDecode *config)
322cabdff1aSopenharmony_ci{
323cabdff1aSopenharmony_ci    FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx);
324cabdff1aSopenharmony_ci    unsigned cfg_count;
325cabdff1aSopenharmony_ci    DXVA2_ConfigPictureDecode *cfg_list;
326cabdff1aSopenharmony_ci    HRESULT hr;
327cabdff1aSopenharmony_ci    int ret;
328cabdff1aSopenharmony_ci
329cabdff1aSopenharmony_ci    hr = IDirectXVideoDecoderService_GetDecoderConfigurations(sctx->dxva2_service, device_guid, desc, NULL, &cfg_count, &cfg_list);
330cabdff1aSopenharmony_ci    if (FAILED(hr)) {
331cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Unable to retrieve decoder configurations\n");
332cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
333cabdff1aSopenharmony_ci    }
334cabdff1aSopenharmony_ci
335cabdff1aSopenharmony_ci    ret = dxva_get_decoder_configuration(avctx, cfg_list, cfg_count);
336cabdff1aSopenharmony_ci    if (ret >= 0)
337cabdff1aSopenharmony_ci        *config = cfg_list[ret];
338cabdff1aSopenharmony_ci    CoTaskMemFree(cfg_list);
339cabdff1aSopenharmony_ci    return ret;
340cabdff1aSopenharmony_ci}
341cabdff1aSopenharmony_ci
342cabdff1aSopenharmony_cistatic int dxva2_create_decoder(AVCodecContext *avctx)
343cabdff1aSopenharmony_ci{
344cabdff1aSopenharmony_ci    FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx);
345cabdff1aSopenharmony_ci    GUID *guid_list;
346cabdff1aSopenharmony_ci    unsigned guid_count;
347cabdff1aSopenharmony_ci    GUID device_guid;
348cabdff1aSopenharmony_ci    D3DFORMAT surface_format = avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ?
349cabdff1aSopenharmony_ci                               MKTAG('P', '0', '1', '0') : MKTAG('N', 'V', '1', '2');
350cabdff1aSopenharmony_ci    DXVA2_VideoDesc desc = { 0 };
351cabdff1aSopenharmony_ci    DXVA2_ConfigPictureDecode config;
352cabdff1aSopenharmony_ci    HRESULT hr;
353cabdff1aSopenharmony_ci    int ret;
354cabdff1aSopenharmony_ci    HANDLE device_handle;
355cabdff1aSopenharmony_ci    AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
356cabdff1aSopenharmony_ci    AVDXVA2FramesContext *frames_hwctx = frames_ctx->hwctx;
357cabdff1aSopenharmony_ci    AVDXVA2DeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
358cabdff1aSopenharmony_ci
359cabdff1aSopenharmony_ci    hr = IDirect3DDeviceManager9_OpenDeviceHandle(device_hwctx->devmgr,
360cabdff1aSopenharmony_ci                                                  &device_handle);
361cabdff1aSopenharmony_ci    if (FAILED(hr)) {
362cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to open a device handle\n");
363cabdff1aSopenharmony_ci        goto fail;
364cabdff1aSopenharmony_ci    }
365cabdff1aSopenharmony_ci
366cabdff1aSopenharmony_ci    hr = IDirect3DDeviceManager9_GetVideoService(device_hwctx->devmgr, device_handle,
367cabdff1aSopenharmony_ci                                                 &ff_IID_IDirectXVideoDecoderService,
368cabdff1aSopenharmony_ci                                                 (void **)&sctx->dxva2_service);
369cabdff1aSopenharmony_ci    IDirect3DDeviceManager9_CloseDeviceHandle(device_hwctx->devmgr, device_handle);
370cabdff1aSopenharmony_ci    if (FAILED(hr)) {
371cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to create IDirectXVideoDecoderService\n");
372cabdff1aSopenharmony_ci        goto fail;
373cabdff1aSopenharmony_ci    }
374cabdff1aSopenharmony_ci
375cabdff1aSopenharmony_ci    hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(sctx->dxva2_service, &guid_count, &guid_list);
376cabdff1aSopenharmony_ci    if (FAILED(hr)) {
377cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to retrieve decoder device GUIDs\n");
378cabdff1aSopenharmony_ci        goto fail;
379cabdff1aSopenharmony_ci    }
380cabdff1aSopenharmony_ci
381cabdff1aSopenharmony_ci    ret = dxva_get_decoder_guid(avctx, sctx->dxva2_service, &surface_format,
382cabdff1aSopenharmony_ci                                guid_count, guid_list, &device_guid);
383cabdff1aSopenharmony_ci    CoTaskMemFree(guid_list);
384cabdff1aSopenharmony_ci    if (ret < 0) {
385cabdff1aSopenharmony_ci        goto fail;
386cabdff1aSopenharmony_ci    }
387cabdff1aSopenharmony_ci
388cabdff1aSopenharmony_ci    desc.SampleWidth  = avctx->coded_width;
389cabdff1aSopenharmony_ci    desc.SampleHeight = avctx->coded_height;
390cabdff1aSopenharmony_ci    desc.Format       = surface_format;
391cabdff1aSopenharmony_ci
392cabdff1aSopenharmony_ci    ret = dxva2_get_decoder_configuration(avctx, &device_guid, &desc, &config);
393cabdff1aSopenharmony_ci    if (ret < 0) {
394cabdff1aSopenharmony_ci        goto fail;
395cabdff1aSopenharmony_ci    }
396cabdff1aSopenharmony_ci
397cabdff1aSopenharmony_ci    hr = IDirectXVideoDecoderService_CreateVideoDecoder(sctx->dxva2_service, &device_guid,
398cabdff1aSopenharmony_ci                                                        &desc, &config, frames_hwctx->surfaces,
399cabdff1aSopenharmony_ci                                                        frames_hwctx->nb_surfaces, &sctx->dxva2_decoder);
400cabdff1aSopenharmony_ci    if (FAILED(hr)) {
401cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to create DXVA2 video decoder\n");
402cabdff1aSopenharmony_ci        goto fail;
403cabdff1aSopenharmony_ci    }
404cabdff1aSopenharmony_ci
405cabdff1aSopenharmony_ci    sctx->dxva2_config = config;
406cabdff1aSopenharmony_ci
407cabdff1aSopenharmony_ci    sctx->decoder_ref = bufref_wrap_interface((IUnknown *)sctx->dxva2_decoder);
408cabdff1aSopenharmony_ci    if (!sctx->decoder_ref)
409cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
410cabdff1aSopenharmony_ci
411cabdff1aSopenharmony_ci    return 0;
412cabdff1aSopenharmony_cifail:
413cabdff1aSopenharmony_ci    return AVERROR(EINVAL);
414cabdff1aSopenharmony_ci}
415cabdff1aSopenharmony_ci
416cabdff1aSopenharmony_ci#endif
417cabdff1aSopenharmony_ci
418cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
419cabdff1aSopenharmony_ci
420cabdff1aSopenharmony_cistatic int d3d11va_get_decoder_configuration(AVCodecContext *avctx,
421cabdff1aSopenharmony_ci                                             ID3D11VideoDevice *video_device,
422cabdff1aSopenharmony_ci                                             const D3D11_VIDEO_DECODER_DESC *desc,
423cabdff1aSopenharmony_ci                                             D3D11_VIDEO_DECODER_CONFIG *config)
424cabdff1aSopenharmony_ci{
425cabdff1aSopenharmony_ci    unsigned cfg_count = 0;
426cabdff1aSopenharmony_ci    D3D11_VIDEO_DECODER_CONFIG *cfg_list = NULL;
427cabdff1aSopenharmony_ci    HRESULT hr;
428cabdff1aSopenharmony_ci    int i, ret;
429cabdff1aSopenharmony_ci
430cabdff1aSopenharmony_ci    hr = ID3D11VideoDevice_GetVideoDecoderConfigCount(video_device, desc, &cfg_count);
431cabdff1aSopenharmony_ci    if (FAILED(hr)) {
432cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Unable to retrieve decoder configurations\n");
433cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
434cabdff1aSopenharmony_ci    }
435cabdff1aSopenharmony_ci
436cabdff1aSopenharmony_ci    cfg_list = av_malloc_array(cfg_count, sizeof(D3D11_VIDEO_DECODER_CONFIG));
437cabdff1aSopenharmony_ci    if (cfg_list == NULL)
438cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
439cabdff1aSopenharmony_ci    for (i = 0; i < cfg_count; i++) {
440cabdff1aSopenharmony_ci        hr = ID3D11VideoDevice_GetVideoDecoderConfig(video_device, desc, i, &cfg_list[i]);
441cabdff1aSopenharmony_ci        if (FAILED(hr)) {
442cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Unable to retrieve decoder configurations. (hr=0x%lX)\n", hr);
443cabdff1aSopenharmony_ci            av_free(cfg_list);
444cabdff1aSopenharmony_ci            return AVERROR(EINVAL);
445cabdff1aSopenharmony_ci        }
446cabdff1aSopenharmony_ci    }
447cabdff1aSopenharmony_ci
448cabdff1aSopenharmony_ci    ret = dxva_get_decoder_configuration(avctx, cfg_list, cfg_count);
449cabdff1aSopenharmony_ci    if (ret >= 0)
450cabdff1aSopenharmony_ci        *config = cfg_list[ret];
451cabdff1aSopenharmony_ci    av_free(cfg_list);
452cabdff1aSopenharmony_ci    return ret;
453cabdff1aSopenharmony_ci}
454cabdff1aSopenharmony_ci
455cabdff1aSopenharmony_cistatic DXGI_FORMAT d3d11va_map_sw_to_hw_format(enum AVPixelFormat pix_fmt)
456cabdff1aSopenharmony_ci{
457cabdff1aSopenharmony_ci    switch (pix_fmt) {
458cabdff1aSopenharmony_ci    case AV_PIX_FMT_NV12:       return DXGI_FORMAT_NV12;
459cabdff1aSopenharmony_ci    case AV_PIX_FMT_P010:       return DXGI_FORMAT_P010;
460cabdff1aSopenharmony_ci    case AV_PIX_FMT_YUV420P:    return DXGI_FORMAT_420_OPAQUE;
461cabdff1aSopenharmony_ci    default:                    return DXGI_FORMAT_UNKNOWN;
462cabdff1aSopenharmony_ci    }
463cabdff1aSopenharmony_ci}
464cabdff1aSopenharmony_ci
465cabdff1aSopenharmony_cistatic int d3d11va_create_decoder(AVCodecContext *avctx)
466cabdff1aSopenharmony_ci{
467cabdff1aSopenharmony_ci    FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx);
468cabdff1aSopenharmony_ci    GUID *guid_list;
469cabdff1aSopenharmony_ci    unsigned guid_count, i;
470cabdff1aSopenharmony_ci    GUID decoder_guid;
471cabdff1aSopenharmony_ci    D3D11_VIDEO_DECODER_DESC desc = { 0 };
472cabdff1aSopenharmony_ci    D3D11_VIDEO_DECODER_CONFIG config;
473cabdff1aSopenharmony_ci    AVHWFramesContext *frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data;
474cabdff1aSopenharmony_ci    AVD3D11VADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
475cabdff1aSopenharmony_ci    AVD3D11VAFramesContext *frames_hwctx = frames_ctx->hwctx;
476cabdff1aSopenharmony_ci    DXGI_FORMAT surface_format = d3d11va_map_sw_to_hw_format(frames_ctx->sw_format);
477cabdff1aSopenharmony_ci    D3D11_TEXTURE2D_DESC texdesc;
478cabdff1aSopenharmony_ci    HRESULT hr;
479cabdff1aSopenharmony_ci    int ret;
480cabdff1aSopenharmony_ci
481cabdff1aSopenharmony_ci    if (!frames_hwctx->texture) {
482cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "AVD3D11VAFramesContext.texture not set.\n");
483cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
484cabdff1aSopenharmony_ci    }
485cabdff1aSopenharmony_ci    ID3D11Texture2D_GetDesc(frames_hwctx->texture, &texdesc);
486cabdff1aSopenharmony_ci
487cabdff1aSopenharmony_ci    guid_count = ID3D11VideoDevice_GetVideoDecoderProfileCount(device_hwctx->video_device);
488cabdff1aSopenharmony_ci    guid_list = av_malloc_array(guid_count, sizeof(*guid_list));
489cabdff1aSopenharmony_ci    if (guid_list == NULL || guid_count == 0) {
490cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to get the decoder GUIDs\n");
491cabdff1aSopenharmony_ci        av_free(guid_list);
492cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
493cabdff1aSopenharmony_ci    }
494cabdff1aSopenharmony_ci    for (i = 0; i < guid_count; i++) {
495cabdff1aSopenharmony_ci        hr = ID3D11VideoDevice_GetVideoDecoderProfile(device_hwctx->video_device, i, &guid_list[i]);
496cabdff1aSopenharmony_ci        if (FAILED(hr)) {
497cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Failed to retrieve decoder GUID %d\n", i);
498cabdff1aSopenharmony_ci            av_free(guid_list);
499cabdff1aSopenharmony_ci            return AVERROR(EINVAL);
500cabdff1aSopenharmony_ci        }
501cabdff1aSopenharmony_ci    }
502cabdff1aSopenharmony_ci
503cabdff1aSopenharmony_ci    ret = dxva_get_decoder_guid(avctx, device_hwctx->video_device, &surface_format,
504cabdff1aSopenharmony_ci                                guid_count, guid_list, &decoder_guid);
505cabdff1aSopenharmony_ci    av_free(guid_list);
506cabdff1aSopenharmony_ci    if (ret < 0)
507cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
508cabdff1aSopenharmony_ci
509cabdff1aSopenharmony_ci    desc.SampleWidth  = avctx->coded_width;
510cabdff1aSopenharmony_ci    desc.SampleHeight = avctx->coded_height;
511cabdff1aSopenharmony_ci    desc.OutputFormat = surface_format;
512cabdff1aSopenharmony_ci    desc.Guid         = decoder_guid;
513cabdff1aSopenharmony_ci
514cabdff1aSopenharmony_ci    ret = d3d11va_get_decoder_configuration(avctx, device_hwctx->video_device, &desc, &config);
515cabdff1aSopenharmony_ci    if (ret < 0)
516cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
517cabdff1aSopenharmony_ci
518cabdff1aSopenharmony_ci    sctx->d3d11_views = av_calloc(texdesc.ArraySize, sizeof(sctx->d3d11_views[0]));
519cabdff1aSopenharmony_ci    if (!sctx->d3d11_views)
520cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
521cabdff1aSopenharmony_ci    sctx->nb_d3d11_views = texdesc.ArraySize;
522cabdff1aSopenharmony_ci
523cabdff1aSopenharmony_ci    for (i = 0; i < sctx->nb_d3d11_views; i++) {
524cabdff1aSopenharmony_ci        D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc = {
525cabdff1aSopenharmony_ci            .DecodeProfile = decoder_guid,
526cabdff1aSopenharmony_ci            .ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D,
527cabdff1aSopenharmony_ci            .Texture2D = {
528cabdff1aSopenharmony_ci                .ArraySlice = i,
529cabdff1aSopenharmony_ci            }
530cabdff1aSopenharmony_ci        };
531cabdff1aSopenharmony_ci        hr = ID3D11VideoDevice_CreateVideoDecoderOutputView(device_hwctx->video_device,
532cabdff1aSopenharmony_ci                                                            (ID3D11Resource*) frames_hwctx->texture,
533cabdff1aSopenharmony_ci                                                            &viewDesc,
534cabdff1aSopenharmony_ci                                                            (ID3D11VideoDecoderOutputView**) &sctx->d3d11_views[i]);
535cabdff1aSopenharmony_ci        if (FAILED(hr)) {
536cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Could not create the decoder output view %d\n", i);
537cabdff1aSopenharmony_ci            return AVERROR_UNKNOWN;
538cabdff1aSopenharmony_ci        }
539cabdff1aSopenharmony_ci    }
540cabdff1aSopenharmony_ci
541cabdff1aSopenharmony_ci    hr = ID3D11VideoDevice_CreateVideoDecoder(device_hwctx->video_device, &desc,
542cabdff1aSopenharmony_ci                                              &config, &sctx->d3d11_decoder);
543cabdff1aSopenharmony_ci    if (FAILED(hr)) {
544cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to create D3D11VA video decoder\n");
545cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
546cabdff1aSopenharmony_ci    }
547cabdff1aSopenharmony_ci
548cabdff1aSopenharmony_ci    sctx->d3d11_config = config;
549cabdff1aSopenharmony_ci    sctx->d3d11_texture = frames_hwctx->texture;
550cabdff1aSopenharmony_ci
551cabdff1aSopenharmony_ci    sctx->decoder_ref = bufref_wrap_interface((IUnknown *)sctx->d3d11_decoder);
552cabdff1aSopenharmony_ci    if (!sctx->decoder_ref)
553cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
554cabdff1aSopenharmony_ci
555cabdff1aSopenharmony_ci    return 0;
556cabdff1aSopenharmony_ci}
557cabdff1aSopenharmony_ci
558cabdff1aSopenharmony_ci#endif
559cabdff1aSopenharmony_ci
560cabdff1aSopenharmony_cistatic void ff_dxva2_lock(AVCodecContext *avctx)
561cabdff1aSopenharmony_ci{
562cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
563cabdff1aSopenharmony_ci    if (ff_dxva2_is_d3d11(avctx)) {
564cabdff1aSopenharmony_ci        FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx);
565cabdff1aSopenharmony_ci        AVDXVAContext *ctx = DXVA_CONTEXT(avctx);
566cabdff1aSopenharmony_ci        if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
567cabdff1aSopenharmony_ci            WaitForSingleObjectEx(D3D11VA_CONTEXT(ctx)->context_mutex, INFINITE, FALSE);
568cabdff1aSopenharmony_ci        if (sctx->device_ctx) {
569cabdff1aSopenharmony_ci            AVD3D11VADeviceContext *hwctx = sctx->device_ctx->hwctx;
570cabdff1aSopenharmony_ci            hwctx->lock(hwctx->lock_ctx);
571cabdff1aSopenharmony_ci        }
572cabdff1aSopenharmony_ci    }
573cabdff1aSopenharmony_ci#endif
574cabdff1aSopenharmony_ci}
575cabdff1aSopenharmony_ci
576cabdff1aSopenharmony_cistatic void ff_dxva2_unlock(AVCodecContext *avctx)
577cabdff1aSopenharmony_ci{
578cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
579cabdff1aSopenharmony_ci    if (ff_dxva2_is_d3d11(avctx)) {
580cabdff1aSopenharmony_ci        FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx);
581cabdff1aSopenharmony_ci        AVDXVAContext *ctx = DXVA_CONTEXT(avctx);
582cabdff1aSopenharmony_ci        if (D3D11VA_CONTEXT(ctx)->context_mutex != INVALID_HANDLE_VALUE)
583cabdff1aSopenharmony_ci            ReleaseMutex(D3D11VA_CONTEXT(ctx)->context_mutex);
584cabdff1aSopenharmony_ci        if (sctx->device_ctx) {
585cabdff1aSopenharmony_ci            AVD3D11VADeviceContext *hwctx = sctx->device_ctx->hwctx;
586cabdff1aSopenharmony_ci            hwctx->unlock(hwctx->lock_ctx);
587cabdff1aSopenharmony_ci        }
588cabdff1aSopenharmony_ci    }
589cabdff1aSopenharmony_ci#endif
590cabdff1aSopenharmony_ci}
591cabdff1aSopenharmony_ci
592cabdff1aSopenharmony_ciint ff_dxva2_common_frame_params(AVCodecContext *avctx,
593cabdff1aSopenharmony_ci                                 AVBufferRef *hw_frames_ctx)
594cabdff1aSopenharmony_ci{
595cabdff1aSopenharmony_ci    AVHWFramesContext *frames_ctx = (AVHWFramesContext *)hw_frames_ctx->data;
596cabdff1aSopenharmony_ci    AVHWDeviceContext *device_ctx = frames_ctx->device_ctx;
597cabdff1aSopenharmony_ci    int surface_alignment, num_surfaces;
598cabdff1aSopenharmony_ci
599cabdff1aSopenharmony_ci    if (device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) {
600cabdff1aSopenharmony_ci        frames_ctx->format = AV_PIX_FMT_DXVA2_VLD;
601cabdff1aSopenharmony_ci    } else if (device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) {
602cabdff1aSopenharmony_ci        frames_ctx->format = AV_PIX_FMT_D3D11;
603cabdff1aSopenharmony_ci    } else {
604cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
605cabdff1aSopenharmony_ci    }
606cabdff1aSopenharmony_ci
607cabdff1aSopenharmony_ci    /* decoding MPEG-2 requires additional alignment on some Intel GPUs,
608cabdff1aSopenharmony_ci    but it causes issues for H.264 on certain AMD GPUs..... */
609cabdff1aSopenharmony_ci    if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
610cabdff1aSopenharmony_ci        surface_alignment = 32;
611cabdff1aSopenharmony_ci    /* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure
612cabdff1aSopenharmony_ci    all coding features have enough room to work with */
613cabdff1aSopenharmony_ci    else if (avctx->codec_id == AV_CODEC_ID_HEVC || avctx->codec_id == AV_CODEC_ID_AV1)
614cabdff1aSopenharmony_ci        surface_alignment = 128;
615cabdff1aSopenharmony_ci    else
616cabdff1aSopenharmony_ci        surface_alignment = 16;
617cabdff1aSopenharmony_ci
618cabdff1aSopenharmony_ci    /* 1 base work surface */
619cabdff1aSopenharmony_ci    num_surfaces = 1;
620cabdff1aSopenharmony_ci
621cabdff1aSopenharmony_ci    /* add surfaces based on number of possible refs */
622cabdff1aSopenharmony_ci    if (avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_HEVC)
623cabdff1aSopenharmony_ci        num_surfaces += 16;
624cabdff1aSopenharmony_ci    else if (avctx->codec_id == AV_CODEC_ID_VP9 || avctx->codec_id == AV_CODEC_ID_AV1)
625cabdff1aSopenharmony_ci        num_surfaces += 8;
626cabdff1aSopenharmony_ci    else
627cabdff1aSopenharmony_ci        num_surfaces += 2;
628cabdff1aSopenharmony_ci
629cabdff1aSopenharmony_ci    frames_ctx->sw_format = avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ?
630cabdff1aSopenharmony_ci                            AV_PIX_FMT_P010 : AV_PIX_FMT_NV12;
631cabdff1aSopenharmony_ci    frames_ctx->width = FFALIGN(avctx->coded_width, surface_alignment);
632cabdff1aSopenharmony_ci    frames_ctx->height = FFALIGN(avctx->coded_height, surface_alignment);
633cabdff1aSopenharmony_ci    frames_ctx->initial_pool_size = num_surfaces;
634cabdff1aSopenharmony_ci
635cabdff1aSopenharmony_ci
636cabdff1aSopenharmony_ci#if CONFIG_DXVA2
637cabdff1aSopenharmony_ci    if (frames_ctx->format == AV_PIX_FMT_DXVA2_VLD) {
638cabdff1aSopenharmony_ci        AVDXVA2FramesContext *frames_hwctx = frames_ctx->hwctx;
639cabdff1aSopenharmony_ci
640cabdff1aSopenharmony_ci        frames_hwctx->surface_type = DXVA2_VideoDecoderRenderTarget;
641cabdff1aSopenharmony_ci    }
642cabdff1aSopenharmony_ci#endif
643cabdff1aSopenharmony_ci
644cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
645cabdff1aSopenharmony_ci    if (frames_ctx->format == AV_PIX_FMT_D3D11) {
646cabdff1aSopenharmony_ci        AVD3D11VAFramesContext *frames_hwctx = frames_ctx->hwctx;
647cabdff1aSopenharmony_ci
648cabdff1aSopenharmony_ci        frames_hwctx->BindFlags |= D3D11_BIND_DECODER;
649cabdff1aSopenharmony_ci    }
650cabdff1aSopenharmony_ci#endif
651cabdff1aSopenharmony_ci
652cabdff1aSopenharmony_ci    return 0;
653cabdff1aSopenharmony_ci}
654cabdff1aSopenharmony_ci
655cabdff1aSopenharmony_ciint ff_dxva2_decode_init(AVCodecContext *avctx)
656cabdff1aSopenharmony_ci{
657cabdff1aSopenharmony_ci    FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx);
658cabdff1aSopenharmony_ci    AVHWFramesContext *frames_ctx;
659cabdff1aSopenharmony_ci    enum AVHWDeviceType dev_type = avctx->hwaccel->pix_fmt == AV_PIX_FMT_DXVA2_VLD
660cabdff1aSopenharmony_ci                            ? AV_HWDEVICE_TYPE_DXVA2 : AV_HWDEVICE_TYPE_D3D11VA;
661cabdff1aSopenharmony_ci    int ret = 0;
662cabdff1aSopenharmony_ci
663cabdff1aSopenharmony_ci    // Old API.
664cabdff1aSopenharmony_ci    if (avctx->hwaccel_context)
665cabdff1aSopenharmony_ci        return 0;
666cabdff1aSopenharmony_ci
667cabdff1aSopenharmony_ci    // (avctx->pix_fmt is not updated yet at this point)
668cabdff1aSopenharmony_ci    sctx->pix_fmt = avctx->hwaccel->pix_fmt;
669cabdff1aSopenharmony_ci
670cabdff1aSopenharmony_ci    ret = ff_decode_get_hw_frames_ctx(avctx, dev_type);
671cabdff1aSopenharmony_ci    if (ret < 0)
672cabdff1aSopenharmony_ci        return ret;
673cabdff1aSopenharmony_ci
674cabdff1aSopenharmony_ci    frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
675cabdff1aSopenharmony_ci    sctx->device_ctx = frames_ctx->device_ctx;
676cabdff1aSopenharmony_ci
677cabdff1aSopenharmony_ci    if (frames_ctx->format != sctx->pix_fmt) {
678cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Invalid pixfmt for hwaccel!\n");
679cabdff1aSopenharmony_ci        ret = AVERROR(EINVAL);
680cabdff1aSopenharmony_ci        goto fail;
681cabdff1aSopenharmony_ci    }
682cabdff1aSopenharmony_ci
683cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
684cabdff1aSopenharmony_ci    if (sctx->pix_fmt == AV_PIX_FMT_D3D11) {
685cabdff1aSopenharmony_ci        AVD3D11VADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx;
686cabdff1aSopenharmony_ci        AVD3D11VAContext *d3d11_ctx = &sctx->ctx.d3d11va;
687cabdff1aSopenharmony_ci
688cabdff1aSopenharmony_ci        ff_dxva2_lock(avctx);
689cabdff1aSopenharmony_ci        ret = d3d11va_create_decoder(avctx);
690cabdff1aSopenharmony_ci        ff_dxva2_unlock(avctx);
691cabdff1aSopenharmony_ci        if (ret < 0)
692cabdff1aSopenharmony_ci            goto fail;
693cabdff1aSopenharmony_ci
694cabdff1aSopenharmony_ci        d3d11_ctx->decoder       = sctx->d3d11_decoder;
695cabdff1aSopenharmony_ci        d3d11_ctx->video_context = device_hwctx->video_context;
696cabdff1aSopenharmony_ci        d3d11_ctx->cfg           = &sctx->d3d11_config;
697cabdff1aSopenharmony_ci        d3d11_ctx->surface_count = sctx->nb_d3d11_views;
698cabdff1aSopenharmony_ci        d3d11_ctx->surface       = sctx->d3d11_views;
699cabdff1aSopenharmony_ci        d3d11_ctx->workaround    = sctx->workaround;
700cabdff1aSopenharmony_ci        d3d11_ctx->context_mutex = INVALID_HANDLE_VALUE;
701cabdff1aSopenharmony_ci    }
702cabdff1aSopenharmony_ci#endif
703cabdff1aSopenharmony_ci
704cabdff1aSopenharmony_ci#if CONFIG_DXVA2
705cabdff1aSopenharmony_ci    if (sctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
706cabdff1aSopenharmony_ci        AVDXVA2FramesContext *frames_hwctx = frames_ctx->hwctx;
707cabdff1aSopenharmony_ci        struct dxva_context *dxva_ctx = &sctx->ctx.dxva2;
708cabdff1aSopenharmony_ci
709cabdff1aSopenharmony_ci        ff_dxva2_lock(avctx);
710cabdff1aSopenharmony_ci        ret = dxva2_create_decoder(avctx);
711cabdff1aSopenharmony_ci        ff_dxva2_unlock(avctx);
712cabdff1aSopenharmony_ci        if (ret < 0)
713cabdff1aSopenharmony_ci            goto fail;
714cabdff1aSopenharmony_ci
715cabdff1aSopenharmony_ci        dxva_ctx->decoder       = sctx->dxva2_decoder;
716cabdff1aSopenharmony_ci        dxva_ctx->cfg           = &sctx->dxva2_config;
717cabdff1aSopenharmony_ci        dxva_ctx->surface       = frames_hwctx->surfaces;
718cabdff1aSopenharmony_ci        dxva_ctx->surface_count = frames_hwctx->nb_surfaces;
719cabdff1aSopenharmony_ci        dxva_ctx->workaround    = sctx->workaround;
720cabdff1aSopenharmony_ci    }
721cabdff1aSopenharmony_ci#endif
722cabdff1aSopenharmony_ci
723cabdff1aSopenharmony_ci    return 0;
724cabdff1aSopenharmony_ci
725cabdff1aSopenharmony_cifail:
726cabdff1aSopenharmony_ci    ff_dxva2_decode_uninit(avctx);
727cabdff1aSopenharmony_ci    return ret;
728cabdff1aSopenharmony_ci}
729cabdff1aSopenharmony_ci
730cabdff1aSopenharmony_ciint ff_dxva2_decode_uninit(AVCodecContext *avctx)
731cabdff1aSopenharmony_ci{
732cabdff1aSopenharmony_ci    FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx);
733cabdff1aSopenharmony_ci    int i;
734cabdff1aSopenharmony_ci
735cabdff1aSopenharmony_ci    av_buffer_unref(&sctx->decoder_ref);
736cabdff1aSopenharmony_ci
737cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
738cabdff1aSopenharmony_ci    for (i = 0; i < sctx->nb_d3d11_views; i++) {
739cabdff1aSopenharmony_ci        if (sctx->d3d11_views[i])
740cabdff1aSopenharmony_ci            ID3D11VideoDecoderOutputView_Release(sctx->d3d11_views[i]);
741cabdff1aSopenharmony_ci    }
742cabdff1aSopenharmony_ci    av_freep(&sctx->d3d11_views);
743cabdff1aSopenharmony_ci#endif
744cabdff1aSopenharmony_ci
745cabdff1aSopenharmony_ci#if CONFIG_DXVA2
746cabdff1aSopenharmony_ci    if (sctx->dxva2_service)
747cabdff1aSopenharmony_ci        IDirectXVideoDecoderService_Release(sctx->dxva2_service);
748cabdff1aSopenharmony_ci#endif
749cabdff1aSopenharmony_ci
750cabdff1aSopenharmony_ci    return 0;
751cabdff1aSopenharmony_ci}
752cabdff1aSopenharmony_ci
753cabdff1aSopenharmony_cistatic void *get_surface(const AVCodecContext *avctx, const AVFrame *frame)
754cabdff1aSopenharmony_ci{
755cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
756cabdff1aSopenharmony_ci    if (frame->format == AV_PIX_FMT_D3D11) {
757cabdff1aSopenharmony_ci        FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx);
758cabdff1aSopenharmony_ci        intptr_t index = (intptr_t)frame->data[1];
759cabdff1aSopenharmony_ci        if (index < 0 || index >= sctx->nb_d3d11_views ||
760cabdff1aSopenharmony_ci            sctx->d3d11_texture != (ID3D11Texture2D *)frame->data[0]) {
761cabdff1aSopenharmony_ci            av_log((void *)avctx, AV_LOG_ERROR, "get_buffer frame is invalid!\n");
762cabdff1aSopenharmony_ci            return NULL;
763cabdff1aSopenharmony_ci        }
764cabdff1aSopenharmony_ci        return sctx->d3d11_views[index];
765cabdff1aSopenharmony_ci    }
766cabdff1aSopenharmony_ci#endif
767cabdff1aSopenharmony_ci    return frame->data[3];
768cabdff1aSopenharmony_ci}
769cabdff1aSopenharmony_ci
770cabdff1aSopenharmony_ciunsigned ff_dxva2_get_surface_index(const AVCodecContext *avctx,
771cabdff1aSopenharmony_ci                                    const AVDXVAContext *ctx,
772cabdff1aSopenharmony_ci                                    const AVFrame *frame)
773cabdff1aSopenharmony_ci{
774cabdff1aSopenharmony_ci    void *surface = get_surface(avctx, frame);
775cabdff1aSopenharmony_ci    unsigned i;
776cabdff1aSopenharmony_ci
777cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
778cabdff1aSopenharmony_ci    if (avctx->pix_fmt == AV_PIX_FMT_D3D11)
779cabdff1aSopenharmony_ci        return (intptr_t)frame->data[1];
780cabdff1aSopenharmony_ci    if (avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD) {
781cabdff1aSopenharmony_ci        D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
782cabdff1aSopenharmony_ci        ID3D11VideoDecoderOutputView_GetDesc((ID3D11VideoDecoderOutputView*) surface, &viewDesc);
783cabdff1aSopenharmony_ci        return viewDesc.Texture2D.ArraySlice;
784cabdff1aSopenharmony_ci    }
785cabdff1aSopenharmony_ci#endif
786cabdff1aSopenharmony_ci#if CONFIG_DXVA2
787cabdff1aSopenharmony_ci    for (i = 0; i < DXVA_CONTEXT_COUNT(avctx, ctx); i++) {
788cabdff1aSopenharmony_ci        if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD && ctx->dxva2.surface[i] == surface)
789cabdff1aSopenharmony_ci            return i;
790cabdff1aSopenharmony_ci    }
791cabdff1aSopenharmony_ci#endif
792cabdff1aSopenharmony_ci
793cabdff1aSopenharmony_ci    assert(0);
794cabdff1aSopenharmony_ci    return 0;
795cabdff1aSopenharmony_ci}
796cabdff1aSopenharmony_ci
797cabdff1aSopenharmony_ciint ff_dxva2_commit_buffer(AVCodecContext *avctx,
798cabdff1aSopenharmony_ci                           AVDXVAContext *ctx,
799cabdff1aSopenharmony_ci                           DECODER_BUFFER_DESC *dsc,
800cabdff1aSopenharmony_ci                           unsigned type, const void *data, unsigned size,
801cabdff1aSopenharmony_ci                           unsigned mb_count)
802cabdff1aSopenharmony_ci{
803cabdff1aSopenharmony_ci    void     *dxva_data = NULL;
804cabdff1aSopenharmony_ci    unsigned dxva_size;
805cabdff1aSopenharmony_ci    int      result;
806cabdff1aSopenharmony_ci    HRESULT hr = 0;
807cabdff1aSopenharmony_ci
808cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
809cabdff1aSopenharmony_ci    if (ff_dxva2_is_d3d11(avctx))
810cabdff1aSopenharmony_ci        hr = ID3D11VideoContext_GetDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context,
811cabdff1aSopenharmony_ci                                                 D3D11VA_CONTEXT(ctx)->decoder,
812cabdff1aSopenharmony_ci                                                 type,
813cabdff1aSopenharmony_ci                                                 &dxva_size, &dxva_data);
814cabdff1aSopenharmony_ci#endif
815cabdff1aSopenharmony_ci#if CONFIG_DXVA2
816cabdff1aSopenharmony_ci    if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
817cabdff1aSopenharmony_ci        hr = IDirectXVideoDecoder_GetBuffer(DXVA2_CONTEXT(ctx)->decoder, type,
818cabdff1aSopenharmony_ci                                            &dxva_data, &dxva_size);
819cabdff1aSopenharmony_ci#endif
820cabdff1aSopenharmony_ci    if (FAILED(hr)) {
821cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to get a buffer for %u: 0x%x\n",
822cabdff1aSopenharmony_ci               type, (unsigned)hr);
823cabdff1aSopenharmony_ci        return -1;
824cabdff1aSopenharmony_ci    }
825cabdff1aSopenharmony_ci    if (dxva_data && size <= dxva_size) {
826cabdff1aSopenharmony_ci        memcpy(dxva_data, data, size);
827cabdff1aSopenharmony_ci
828cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
829cabdff1aSopenharmony_ci        if (ff_dxva2_is_d3d11(avctx)) {
830cabdff1aSopenharmony_ci            D3D11_VIDEO_DECODER_BUFFER_DESC *dsc11 = dsc;
831cabdff1aSopenharmony_ci            memset(dsc11, 0, sizeof(*dsc11));
832cabdff1aSopenharmony_ci            dsc11->BufferType           = type;
833cabdff1aSopenharmony_ci            dsc11->DataSize             = size;
834cabdff1aSopenharmony_ci            dsc11->NumMBsInBuffer       = mb_count;
835cabdff1aSopenharmony_ci        }
836cabdff1aSopenharmony_ci#endif
837cabdff1aSopenharmony_ci#if CONFIG_DXVA2
838cabdff1aSopenharmony_ci        if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
839cabdff1aSopenharmony_ci            DXVA2_DecodeBufferDesc *dsc2 = dsc;
840cabdff1aSopenharmony_ci            memset(dsc2, 0, sizeof(*dsc2));
841cabdff1aSopenharmony_ci            dsc2->CompressedBufferType = type;
842cabdff1aSopenharmony_ci            dsc2->DataSize             = size;
843cabdff1aSopenharmony_ci            dsc2->NumMBsInBuffer       = mb_count;
844cabdff1aSopenharmony_ci        }
845cabdff1aSopenharmony_ci#endif
846cabdff1aSopenharmony_ci
847cabdff1aSopenharmony_ci        result = 0;
848cabdff1aSopenharmony_ci    } else {
849cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Buffer for type %u was too small\n", type);
850cabdff1aSopenharmony_ci        result = -1;
851cabdff1aSopenharmony_ci    }
852cabdff1aSopenharmony_ci
853cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
854cabdff1aSopenharmony_ci    if (ff_dxva2_is_d3d11(avctx))
855cabdff1aSopenharmony_ci        hr = ID3D11VideoContext_ReleaseDecoderBuffer(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder, type);
856cabdff1aSopenharmony_ci#endif
857cabdff1aSopenharmony_ci#if CONFIG_DXVA2
858cabdff1aSopenharmony_ci    if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
859cabdff1aSopenharmony_ci        hr = IDirectXVideoDecoder_ReleaseBuffer(DXVA2_CONTEXT(ctx)->decoder, type);
860cabdff1aSopenharmony_ci#endif
861cabdff1aSopenharmony_ci    if (FAILED(hr)) {
862cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
863cabdff1aSopenharmony_ci               "Failed to release buffer type %u: 0x%x\n",
864cabdff1aSopenharmony_ci               type, (unsigned)hr);
865cabdff1aSopenharmony_ci        result = -1;
866cabdff1aSopenharmony_ci    }
867cabdff1aSopenharmony_ci    return result;
868cabdff1aSopenharmony_ci}
869cabdff1aSopenharmony_ci
870cabdff1aSopenharmony_cistatic int frame_add_buf(AVFrame *frame, AVBufferRef *ref)
871cabdff1aSopenharmony_ci{
872cabdff1aSopenharmony_ci    int i;
873cabdff1aSopenharmony_ci
874cabdff1aSopenharmony_ci    for (i = 0; i < AV_NUM_DATA_POINTERS; i++) {
875cabdff1aSopenharmony_ci        if (!frame->buf[i]) {
876cabdff1aSopenharmony_ci            frame->buf[i] = av_buffer_ref(ref);
877cabdff1aSopenharmony_ci            return frame->buf[i] ? 0 : AVERROR(ENOMEM);
878cabdff1aSopenharmony_ci        }
879cabdff1aSopenharmony_ci    }
880cabdff1aSopenharmony_ci
881cabdff1aSopenharmony_ci    // For now we expect that the caller does not use more than
882cabdff1aSopenharmony_ci    // AV_NUM_DATA_POINTERS-1 buffers if the user uses a custom pool.
883cabdff1aSopenharmony_ci    return AVERROR(EINVAL);
884cabdff1aSopenharmony_ci}
885cabdff1aSopenharmony_ci
886cabdff1aSopenharmony_ciint ff_dxva2_common_end_frame(AVCodecContext *avctx, AVFrame *frame,
887cabdff1aSopenharmony_ci                              const void *pp, unsigned pp_size,
888cabdff1aSopenharmony_ci                              const void *qm, unsigned qm_size,
889cabdff1aSopenharmony_ci                              int (*commit_bs_si)(AVCodecContext *,
890cabdff1aSopenharmony_ci                                                  DECODER_BUFFER_DESC *bs,
891cabdff1aSopenharmony_ci                                                  DECODER_BUFFER_DESC *slice))
892cabdff1aSopenharmony_ci{
893cabdff1aSopenharmony_ci    AVDXVAContext *ctx = DXVA_CONTEXT(avctx);
894cabdff1aSopenharmony_ci    unsigned               buffer_count = 0;
895cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
896cabdff1aSopenharmony_ci    D3D11_VIDEO_DECODER_BUFFER_DESC buffer11[4];
897cabdff1aSopenharmony_ci#endif
898cabdff1aSopenharmony_ci#if CONFIG_DXVA2
899cabdff1aSopenharmony_ci    DXVA2_DecodeBufferDesc          buffer2[4];
900cabdff1aSopenharmony_ci#endif
901cabdff1aSopenharmony_ci    DECODER_BUFFER_DESC             *buffer = NULL, *buffer_slice = NULL;
902cabdff1aSopenharmony_ci    int result, runs = 0;
903cabdff1aSopenharmony_ci    HRESULT hr;
904cabdff1aSopenharmony_ci    unsigned type;
905cabdff1aSopenharmony_ci    FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx);
906cabdff1aSopenharmony_ci
907cabdff1aSopenharmony_ci    if (sctx->decoder_ref) {
908cabdff1aSopenharmony_ci        result = frame_add_buf(frame, sctx->decoder_ref);
909cabdff1aSopenharmony_ci        if (result < 0)
910cabdff1aSopenharmony_ci            return result;
911cabdff1aSopenharmony_ci    }
912cabdff1aSopenharmony_ci
913cabdff1aSopenharmony_ci    do {
914cabdff1aSopenharmony_ci        ff_dxva2_lock(avctx);
915cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
916cabdff1aSopenharmony_ci        if (ff_dxva2_is_d3d11(avctx))
917cabdff1aSopenharmony_ci            hr = ID3D11VideoContext_DecoderBeginFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder,
918cabdff1aSopenharmony_ci                                                      get_surface(avctx, frame),
919cabdff1aSopenharmony_ci                                                      0, NULL);
920cabdff1aSopenharmony_ci#endif
921cabdff1aSopenharmony_ci#if CONFIG_DXVA2
922cabdff1aSopenharmony_ci        if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
923cabdff1aSopenharmony_ci            hr = IDirectXVideoDecoder_BeginFrame(DXVA2_CONTEXT(ctx)->decoder,
924cabdff1aSopenharmony_ci                                                 get_surface(avctx, frame),
925cabdff1aSopenharmony_ci                                                 NULL);
926cabdff1aSopenharmony_ci#endif
927cabdff1aSopenharmony_ci        if (hr != E_PENDING || ++runs > 50)
928cabdff1aSopenharmony_ci            break;
929cabdff1aSopenharmony_ci        ff_dxva2_unlock(avctx);
930cabdff1aSopenharmony_ci        av_usleep(2000);
931cabdff1aSopenharmony_ci    } while(1);
932cabdff1aSopenharmony_ci
933cabdff1aSopenharmony_ci    if (FAILED(hr)) {
934cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to begin frame: 0x%x\n", (unsigned)hr);
935cabdff1aSopenharmony_ci        ff_dxva2_unlock(avctx);
936cabdff1aSopenharmony_ci        return -1;
937cabdff1aSopenharmony_ci    }
938cabdff1aSopenharmony_ci
939cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
940cabdff1aSopenharmony_ci    if (ff_dxva2_is_d3d11(avctx)) {
941cabdff1aSopenharmony_ci        buffer = &buffer11[buffer_count];
942cabdff1aSopenharmony_ci        type = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
943cabdff1aSopenharmony_ci    }
944cabdff1aSopenharmony_ci#endif
945cabdff1aSopenharmony_ci#if CONFIG_DXVA2
946cabdff1aSopenharmony_ci    if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
947cabdff1aSopenharmony_ci        buffer = &buffer2[buffer_count];
948cabdff1aSopenharmony_ci        type = DXVA2_PictureParametersBufferType;
949cabdff1aSopenharmony_ci    }
950cabdff1aSopenharmony_ci#endif
951cabdff1aSopenharmony_ci    result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
952cabdff1aSopenharmony_ci                                    type,
953cabdff1aSopenharmony_ci                                    pp, pp_size, 0);
954cabdff1aSopenharmony_ci    if (result) {
955cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
956cabdff1aSopenharmony_ci               "Failed to add picture parameter buffer\n");
957cabdff1aSopenharmony_ci        goto end;
958cabdff1aSopenharmony_ci    }
959cabdff1aSopenharmony_ci    buffer_count++;
960cabdff1aSopenharmony_ci
961cabdff1aSopenharmony_ci    if (qm_size > 0) {
962cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
963cabdff1aSopenharmony_ci        if (ff_dxva2_is_d3d11(avctx)) {
964cabdff1aSopenharmony_ci            buffer = &buffer11[buffer_count];
965cabdff1aSopenharmony_ci            type = D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX;
966cabdff1aSopenharmony_ci        }
967cabdff1aSopenharmony_ci#endif
968cabdff1aSopenharmony_ci#if CONFIG_DXVA2
969cabdff1aSopenharmony_ci        if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
970cabdff1aSopenharmony_ci            buffer = &buffer2[buffer_count];
971cabdff1aSopenharmony_ci            type = DXVA2_InverseQuantizationMatrixBufferType;
972cabdff1aSopenharmony_ci        }
973cabdff1aSopenharmony_ci#endif
974cabdff1aSopenharmony_ci        result = ff_dxva2_commit_buffer(avctx, ctx, buffer,
975cabdff1aSopenharmony_ci                                        type,
976cabdff1aSopenharmony_ci                                        qm, qm_size, 0);
977cabdff1aSopenharmony_ci        if (result) {
978cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
979cabdff1aSopenharmony_ci                   "Failed to add inverse quantization matrix buffer\n");
980cabdff1aSopenharmony_ci            goto end;
981cabdff1aSopenharmony_ci        }
982cabdff1aSopenharmony_ci        buffer_count++;
983cabdff1aSopenharmony_ci    }
984cabdff1aSopenharmony_ci
985cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
986cabdff1aSopenharmony_ci    if (ff_dxva2_is_d3d11(avctx)) {
987cabdff1aSopenharmony_ci        buffer       = &buffer11[buffer_count + 0];
988cabdff1aSopenharmony_ci        buffer_slice = &buffer11[buffer_count + 1];
989cabdff1aSopenharmony_ci    }
990cabdff1aSopenharmony_ci#endif
991cabdff1aSopenharmony_ci#if CONFIG_DXVA2
992cabdff1aSopenharmony_ci    if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
993cabdff1aSopenharmony_ci        buffer       = &buffer2[buffer_count + 0];
994cabdff1aSopenharmony_ci        buffer_slice = &buffer2[buffer_count + 1];
995cabdff1aSopenharmony_ci    }
996cabdff1aSopenharmony_ci#endif
997cabdff1aSopenharmony_ci
998cabdff1aSopenharmony_ci    result = commit_bs_si(avctx,
999cabdff1aSopenharmony_ci                          buffer,
1000cabdff1aSopenharmony_ci                          buffer_slice);
1001cabdff1aSopenharmony_ci    if (result) {
1002cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
1003cabdff1aSopenharmony_ci               "Failed to add bitstream or slice control buffer\n");
1004cabdff1aSopenharmony_ci        goto end;
1005cabdff1aSopenharmony_ci    }
1006cabdff1aSopenharmony_ci    buffer_count += 2;
1007cabdff1aSopenharmony_ci
1008cabdff1aSopenharmony_ci    /* TODO Film Grain when possible */
1009cabdff1aSopenharmony_ci
1010cabdff1aSopenharmony_ci    assert(buffer_count == 1 + (qm_size > 0) + 2);
1011cabdff1aSopenharmony_ci
1012cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
1013cabdff1aSopenharmony_ci    if (ff_dxva2_is_d3d11(avctx))
1014cabdff1aSopenharmony_ci        hr = ID3D11VideoContext_SubmitDecoderBuffers(D3D11VA_CONTEXT(ctx)->video_context,
1015cabdff1aSopenharmony_ci                                                     D3D11VA_CONTEXT(ctx)->decoder,
1016cabdff1aSopenharmony_ci                                                     buffer_count, buffer11);
1017cabdff1aSopenharmony_ci#endif
1018cabdff1aSopenharmony_ci#if CONFIG_DXVA2
1019cabdff1aSopenharmony_ci    if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD) {
1020cabdff1aSopenharmony_ci        DXVA2_DecodeExecuteParams exec = {
1021cabdff1aSopenharmony_ci            .NumCompBuffers     = buffer_count,
1022cabdff1aSopenharmony_ci            .pCompressedBuffers = buffer2,
1023cabdff1aSopenharmony_ci            .pExtensionData     = NULL,
1024cabdff1aSopenharmony_ci        };
1025cabdff1aSopenharmony_ci        hr = IDirectXVideoDecoder_Execute(DXVA2_CONTEXT(ctx)->decoder, &exec);
1026cabdff1aSopenharmony_ci    }
1027cabdff1aSopenharmony_ci#endif
1028cabdff1aSopenharmony_ci    if (FAILED(hr)) {
1029cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to execute: 0x%x\n", (unsigned)hr);
1030cabdff1aSopenharmony_ci        result = -1;
1031cabdff1aSopenharmony_ci    }
1032cabdff1aSopenharmony_ci
1033cabdff1aSopenharmony_ciend:
1034cabdff1aSopenharmony_ci#if CONFIG_D3D11VA
1035cabdff1aSopenharmony_ci    if (ff_dxva2_is_d3d11(avctx))
1036cabdff1aSopenharmony_ci        hr = ID3D11VideoContext_DecoderEndFrame(D3D11VA_CONTEXT(ctx)->video_context, D3D11VA_CONTEXT(ctx)->decoder);
1037cabdff1aSopenharmony_ci#endif
1038cabdff1aSopenharmony_ci#if CONFIG_DXVA2
1039cabdff1aSopenharmony_ci    if (avctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD)
1040cabdff1aSopenharmony_ci        hr = IDirectXVideoDecoder_EndFrame(DXVA2_CONTEXT(ctx)->decoder, NULL);
1041cabdff1aSopenharmony_ci#endif
1042cabdff1aSopenharmony_ci    ff_dxva2_unlock(avctx);
1043cabdff1aSopenharmony_ci    if (FAILED(hr)) {
1044cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to end frame: 0x%x\n", (unsigned)hr);
1045cabdff1aSopenharmony_ci        result = -1;
1046cabdff1aSopenharmony_ci    }
1047cabdff1aSopenharmony_ci
1048cabdff1aSopenharmony_ci    return result;
1049cabdff1aSopenharmony_ci}
1050cabdff1aSopenharmony_ci
1051cabdff1aSopenharmony_ciint ff_dxva2_is_d3d11(const AVCodecContext *avctx)
1052cabdff1aSopenharmony_ci{
1053cabdff1aSopenharmony_ci    if (CONFIG_D3D11VA)
1054cabdff1aSopenharmony_ci        return avctx->pix_fmt == AV_PIX_FMT_D3D11VA_VLD ||
1055cabdff1aSopenharmony_ci               avctx->pix_fmt == AV_PIX_FMT_D3D11;
1056cabdff1aSopenharmony_ci    else
1057cabdff1aSopenharmony_ci        return 0;
1058cabdff1aSopenharmony_ci}
1059