summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
Diffstat (limited to 'video')
-rw-r--r--video/decode/d3d.c343
-rw-r--r--video/decode/d3d.h37
-rw-r--r--video/decode/hw_d3d11va.c562
-rw-r--r--video/decode/hw_dxva2.c524
-rw-r--r--video/fmt-conversion.c4
-rw-r--r--video/gpu_memcpy.c135
-rw-r--r--video/gpu_memcpy.h8
-rw-r--r--video/mp_image.c32
-rw-r--r--video/mp_image.h3
-rw-r--r--video/out/opengl/hwdec_d3d11egl.c1
-rw-r--r--video/vaapi.c4
11 files changed, 9 insertions, 1644 deletions
diff --git a/video/decode/d3d.c b/video/decode/d3d.c
index 36d914d545..a5408f2133 100644
--- a/video/decode/d3d.c
+++ b/video/decode/d3d.c
@@ -17,9 +17,16 @@
#include <pthread.h>
+#include "config.h"
+
#include <libavcodec/avcodec.h>
-#include "config.h"
+#include <libavutil/hwcontext.h>
+#include <libavutil/hwcontext_d3d11va.h>
+
+#if HAVE_D3D9_HWACCEL
+#include <libavutil/hwcontext_dxva2.h>
+#endif
#include "lavc.h"
#include "common/common.h"
@@ -31,81 +38,6 @@
#include "d3d.h"
-#if !HAVE_D3D_HWACCEL_NEW
-
-// define all the GUIDs used directly here, to avoid problems with inconsistent
-// dxva2api.h versions in mingw-w64 and different MSVC version
-#include <guiddef.h>
-#include <cguid.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(DXVA_ModeH264_VLD_WithFMOASO_NoFGT, 0xd5f04ff9, 0x3418, 0x45d8, 0x95, 0x61, 0x32, 0xa7, 0x6a, 0xae, 0x2d, 0xdd);
-DEFINE_GUID(DXVA_Intel_H264_NoFGT_ClearVideo, 0x604F8E68, 0x4951, 0x4c54, 0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6);
-DEFINE_GUID(DXVA_ModeH264_VLD_NoFGT_Flash, 0x4245F676, 0x2BBC, 0x4166, 0xa0, 0xBB, 0x54, 0xE7, 0xB8, 0x49, 0xC3, 0x80);
-
-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); // August 2010 update
-
-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);
-
-static const int PROF_MPEG2_MAIN[] = {FF_PROFILE_MPEG2_SIMPLE,
- FF_PROFILE_MPEG2_MAIN, 0};
-static const int PROF_H264_HIGH[] = {FF_PROFILE_H264_CONSTRAINED_BASELINE,
- FF_PROFILE_H264_MAIN,
- FF_PROFILE_H264_HIGH, 0};
-static const int PROF_HEVC_MAIN[] = {FF_PROFILE_HEVC_MAIN, 0};
-static const int PROF_HEVC_MAIN10[] = {FF_PROFILE_HEVC_MAIN,
- FF_PROFILE_HEVC_MAIN_10, 0};
-
-struct d3dva_mode {
- const GUID *guid;
- const char *name;
- enum AVCodecID codec;
- const int *profiles; // NULL or ends with 0
-};
-
-#define MODE2(id) &MP_CONCAT(DXVA2_Mode, id), # id
-#define MODE(id) &MP_CONCAT(DXVA_, id), # id
-// Preferred modes must come first
-static const struct d3dva_mode d3dva_modes[] = {
- // MPEG-1/2
- {MODE2(MPEG2_VLD), AV_CODEC_ID_MPEG2VIDEO, PROF_MPEG2_MAIN},
- {MODE2(MPEG2and1_VLD), AV_CODEC_ID_MPEG2VIDEO, PROF_MPEG2_MAIN},
- {MODE2(MPEG2and1_VLD), AV_CODEC_ID_MPEG1VIDEO},
-
- // H.264
- {MODE2(H264_F), AV_CODEC_ID_H264, PROF_H264_HIGH},
- {MODE2(H264_E), AV_CODEC_ID_H264, PROF_H264_HIGH},
- {MODE (Intel_H264_NoFGT_ClearVideo), AV_CODEC_ID_H264, PROF_H264_HIGH},
- {MODE (ModeH264_VLD_WithFMOASO_NoFGT), AV_CODEC_ID_H264, PROF_H264_HIGH},
- {MODE (ModeH264_VLD_NoFGT_Flash), AV_CODEC_ID_H264, PROF_H264_HIGH},
-
- // VC-1 / WMV3
- {MODE2(VC1_D), AV_CODEC_ID_VC1},
- {MODE2(VC1_D), AV_CODEC_ID_WMV3},
- {MODE2(VC1_D2010), AV_CODEC_ID_VC1},
- {MODE2(VC1_D2010), AV_CODEC_ID_WMV3},
-
- // HEVC
- {MODE2(HEVC_VLD_Main), AV_CODEC_ID_HEVC, PROF_HEVC_MAIN},
- {MODE2(HEVC_VLD_Main10), AV_CODEC_ID_HEVC, PROF_HEVC_MAIN10},
-
- // VP9
- {MODE2(VP9_VLD_Profile0), AV_CODEC_ID_VP9},
-};
-#undef MODE
-#undef MODE2
-
-#endif
-
HMODULE d3d11_dll, d3d9_dll, dxva2_dll;
PFN_D3D11_CREATE_DEVICE d3d11_D3D11CreateDevice;
@@ -136,7 +68,6 @@ void d3d_load_dlls(void)
pthread_once(&d3d_load_once, d3d_do_load);
}
-
// Test if Direct3D11 can be used by us. Basically, this prevents trying to use
// D3D11 on Win7, and then failing somewhere in the process.
bool d3d11_check_decoding(ID3D11Device *dev)
@@ -149,254 +80,6 @@ bool d3d11_check_decoding(ID3D11Device *dev)
return !FAILED(hr) && (supported & D3D11_BIND_DECODER);
}
-#if !HAVE_D3D_HWACCEL_NEW
-
-int d3d_probe_codec(const char *codec)
-{
- enum AVCodecID codecid = mp_codec_to_av_codec_id(codec);
- for (int i = 0; i < MP_ARRAY_SIZE(d3dva_modes); i++) {
- const struct d3dva_mode *mode = &d3dva_modes[i];
- if (mode->codec == codecid)
- return 0;
- }
- return HWDEC_ERR_NO_CODEC;
-}
-
-static bool profile_compatible(const struct d3dva_mode *mode, int profile)
-{
- if (!mode->profiles)
- return true;
-
- for (int i = 0; mode->profiles[i]; i++){
- if(mode->profiles[i] == profile)
- return true;
- }
- return false;
-}
-
-static bool mode_supported(const struct d3dva_mode *mode,
- const GUID *device_modes, UINT n_modes)
-{
- for (int i = 0; i < n_modes; i++) {
- if (IsEqualGUID(mode->guid, &device_modes[i]))
- return true;
- }
- return false;
-}
-
-struct d3d_decoder_fmt d3d_select_decoder_mode(
- struct lavc_ctx *s, const GUID *device_guids, UINT n_guids,
- const struct d3d_decoded_format *formats, int n_formats,
- bool (*test_fmt_cb)(struct lavc_ctx *s, const GUID *guid,
- const struct d3d_decoded_format *fmt))
-{
- struct d3d_decoder_fmt fmt = {
- .guid = &GUID_NULL,
- .format = NULL,
- };
-
- // this has the right bit-depth, but is unfortunately not the native format
- int sw_img_fmt = pixfmt2imgfmt(s->avctx->sw_pix_fmt);
- if (sw_img_fmt == IMGFMT_NONE)
- return fmt;
-
- int depth = IMGFMT_RGB_DEPTH(sw_img_fmt);
-
- for (int i = 0; i < MP_ARRAY_SIZE(d3dva_modes); i++) {
- const struct d3dva_mode *mode = &d3dva_modes[i];
- if (mode->codec == s->avctx->codec_id &&
- profile_compatible(mode, s->avctx->profile) &&
- mode_supported(mode, device_guids, n_guids)) {
-
- for (int n = 0; n < n_formats; n++) {
- const struct d3d_decoded_format *format = &formats[n];
-
- if (depth <= format->depth && test_fmt_cb(s, mode->guid, format))
- {
- MP_VERBOSE(s, "Selecting %s ",
- d3d_decoder_guid_to_desc(mode->guid));
- if (format->dxfmt >= (1 << 16)) {
- MP_VERBOSE(s, "%s\n", mp_tag_str(format->dxfmt));
- } else {
- MP_VERBOSE(s, "%d\n", (int)format->dxfmt);
- }
-
- fmt.guid = mode->guid;
- fmt.format = format;
- return fmt;
- }
- }
- }
- }
- return fmt;
-}
-
-char *d3d_decoder_guid_to_desc_buf(char *buf, size_t buf_size,
- const GUID *mode_guid)
-{
- const char *name = "<unknown>";
- for (int i = 0; i < MP_ARRAY_SIZE(d3dva_modes); i++) {
- const struct d3dva_mode *mode = &d3dva_modes[i];
- if (IsEqualGUID(mode->guid, mode_guid)) {
- name = mode->name;
- break;
- }
- }
- snprintf(buf, buf_size, "%s %s", mp_GUID_to_str(mode_guid), name);
- return buf;
-}
-
-void d3d_surface_align(struct lavc_ctx *s, int *w, int *h)
-{
- int alignment = 16;
- switch (s->avctx->codec_id) {
- // decoding MPEG-2 requires additional alignment on some Intel GPUs, but it
- // causes issues for H.264 on certain AMD GPUs.....
- case AV_CODEC_ID_MPEG2VIDEO:
- alignment = 32;
- break;
- // the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure
- // all coding features have enough room to work with
- case AV_CODEC_ID_HEVC:
- alignment = 128;
- break;
- }
- *w = FFALIGN(*w, alignment);
- *h = FFALIGN(*h, alignment);
-}
-
-unsigned d3d_decoder_config_score(struct lavc_ctx *s,
- GUID *guidConfigBitstreamEncryption,
- UINT ConfigBitstreamRaw)
-{
- unsigned score = 0;
- if (ConfigBitstreamRaw == 1) {
- score = 1;
- } else if (s->avctx->codec_id == AV_CODEC_ID_H264
- && ConfigBitstreamRaw == 2) {
- score = 2;
- } else {
- return 0;
- }
-
- if (IsEqualGUID(guidConfigBitstreamEncryption, &DXVA2_NoEncrypt))
- score += 16;
-
- return score;
-}
-
-BOOL is_clearvideo(const GUID *mode_guid)
-{
- return IsEqualGUID(mode_guid, &DXVA_Intel_H264_NoFGT_ClearVideo);
-}
-
-void copy_nv12(struct mp_image *dest, uint8_t *src_bits,
- unsigned src_pitch, unsigned surf_height)
-{
- struct mp_image buf = {0};
- mp_image_setfmt(&buf, dest->imgfmt);
- mp_image_set_size(&buf, dest->w, dest->h);
-
- buf.planes[0] = src_bits;
- buf.stride[0] = src_pitch;
- buf.planes[1] = src_bits + src_pitch * surf_height;
- buf.stride[1] = src_pitch;
- mp_image_copy_gpu(dest, &buf);
-}
-
-static int get_dxgi_mpfmt(DWORD dxgi_fmt)
-{
- switch (dxgi_fmt) {
- case DXGI_FORMAT_NV12: return IMGFMT_NV12;
- case DXGI_FORMAT_P010: return IMGFMT_P010;
- case DXGI_FORMAT_P016: return IMGFMT_P010;
- }
- return 0;
-}
-
-struct mp_image *d3d11_download_image(struct mp_hwdec_ctx *ctx,
- struct mp_image *mpi,
- struct mp_image_pool *swpool)
-{
- HRESULT hr;
- ID3D11Device *device = ctx->ctx;
-
- if (mpi->imgfmt != IMGFMT_D3D11VA && mpi->imgfmt != IMGFMT_D3D11NV12)
- return NULL;
-
- ID3D11Texture2D *texture = (void *)mpi->planes[0];
- int subindex = (intptr_t)mpi->planes[1];
- if (!texture)
- return NULL;
-
- D3D11_TEXTURE2D_DESC tex_desc;
- ID3D11Texture2D_GetDesc(texture, &tex_desc);
- int mpfmt = get_dxgi_mpfmt(tex_desc.Format);
- if (!mpfmt)
- return NULL;
-
- // create staging texture shared with the CPU with mostly the same
- // parameters as the source texture
- tex_desc.MipLevels = 1;
- tex_desc.MiscFlags = 0;
- tex_desc.ArraySize = 1;
- tex_desc.Usage = D3D11_USAGE_STAGING;
- tex_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
- tex_desc.BindFlags = 0;
- ID3D11Texture2D *staging = NULL;
- hr = ID3D11Device_CreateTexture2D(device, &tex_desc, NULL, &staging);
- if (FAILED(hr))
- return NULL;
-
- bool ok = false;
- struct mp_image *sw_img = NULL;
- ID3D11DeviceContext *device_ctx = NULL;
- ID3D11Device_GetImmediateContext(device, &device_ctx);
-
- // copy to the staging texture
- ID3D11DeviceContext_CopySubresourceRegion(
- device_ctx,
- (ID3D11Resource *)staging, 0, 0, 0, 0,
- (ID3D11Resource *)texture, subindex, NULL);
-
- sw_img = mp_image_pool_get(swpool, mpfmt, tex_desc.Width, tex_desc.Height);
- if (!sw_img)
- goto done;
-
- // copy staging texture to the cpu mp_image
- D3D11_MAPPED_SUBRESOURCE lock;
- hr = ID3D11DeviceContext_Map(device_ctx, (ID3D11Resource *)staging,
- 0, D3D11_MAP_READ, 0, &lock);
- if (FAILED(hr))
- goto done;
- copy_nv12(sw_img, lock.pData, lock.RowPitch, tex_desc.Height);
- ID3D11DeviceContext_Unmap(device_ctx, (ID3D11Resource *)staging, 0);
-
- mp_image_set_size(sw_img, mpi->w, mpi->h);
- mp_image_copy_attributes(sw_img, mpi);
- ok = true;
-
-done:
- ID3D11Texture2D_Release(staging);
- ID3D11DeviceContext_Release(device_ctx);
- if (!ok)
- mp_image_unrefp(&sw_img);
- return sw_img;
-}
-
-// Dummies for simpler compat.
-AVBufferRef *d3d11_wrap_device_ref(ID3D11Device *device) { return NULL; }
-AVBufferRef *d3d9_wrap_device_ref(struct IDirect3DDevice9 *device) { return NULL; }
-
-#else /* !HAVE_D3D_HWACCEL_NEW */
-
-#include <libavutil/hwcontext.h>
-#include <libavutil/hwcontext_d3d11va.h>
-
-#if HAVE_D3D9_HWACCEL
-#include <libavutil/hwcontext_dxva2.h>
-#endif
-
void d3d_hwframes_refine(struct lavc_ctx *ctx, AVBufferRef *hw_frames_ctx)
{
AVHWFramesContext *fctx = (void *)hw_frames_ctx->data;
@@ -449,13 +132,3 @@ AVBufferRef *d3d11_wrap_device_ref(ID3D11Device *device)
return device_ref;
}
-
-// Dummy for simpler compat.
-struct mp_image *d3d11_download_image(struct mp_hwdec_ctx *ctx,
- struct mp_image *mpi,
- struct mp_image_pool *swpool)
-{
- return NULL;
-}
-
-#endif /* else !HAVE_D3D_HWACCEL_NEW */
diff --git a/video/decode/d3d.h b/video/decode/d3d.h
index 8ae244c585..efac35dd76 100644
--- a/video/decode/d3d.h
+++ b/video/decode/d3d.h
@@ -24,21 +24,8 @@
#include <stdbool.h>
#include <inttypes.h>
-struct mp_image;
struct lavc_ctx;
-struct d3d_decoded_format {
- DWORD dxfmt; // D3DFORMAT or DXGI_FORMAT
- const char *name; // informational string repr. of dxfmt_decoded
- int depth; // significant bits (not full size)
- int mpfmt; // IMGFMT_ with compatible memory layout and semantics
-};
-
-struct d3d_decoder_fmt {
- const GUID *guid;
- const struct d3d_decoded_format *format;
-};
-
// Must call d3d_load_dlls() before accessing. Once this is done, the DLLs
// remain loaded forever.
extern HMODULE d3d11_dll, d3d9_dll, dxva2_dll;
@@ -46,32 +33,8 @@ extern PFN_D3D11_CREATE_DEVICE d3d11_D3D11CreateDevice;
void d3d_load_dlls(void);
-int d3d_probe_codec(const char *codec);
-
-struct d3d_decoder_fmt d3d_select_decoder_mode(
- struct lavc_ctx *s, const GUID *device_guids, UINT n_guids,
- const struct d3d_decoded_format *formats, int n_formats,
- bool (*test_fmt_cb)(struct lavc_ctx *s, const GUID *guid,
- const struct d3d_decoded_format *fmt));
-
-char *d3d_decoder_guid_to_desc_buf(char *buf, size_t buf_size,
- const GUID *mode_guid);
-#define d3d_decoder_guid_to_desc(guid) d3d_decoder_guid_to_desc_buf((char[256]){0}, 256, (guid))
-
-void d3d_surface_align(struct lavc_ctx *s, int *w, int *h);
-unsigned d3d_decoder_config_score(struct lavc_ctx *s,
- GUID *guidConfigBitstreamEncryption,
- UINT ConfigBitstreamRaw);
-BOOL is_clearvideo(const GUID *mode_guid);
-void copy_nv12(struct mp_image *dest, uint8_t *src_bits,
- unsigned src_pitch, unsigned surf_height);
-
bool d3d11_check_decoding(ID3D11Device *dev);
-struct mp_image *d3d11_download_image(struct mp_hwdec_ctx *ctx,
- struct mp_image *mpi,
- struct mp_image_pool *swpool);
-
struct AVBufferRef;
struct IDirect3DDevice9;
diff --git a/video/decode/hw_d3d11va.c b/video/decode/hw_d3d11va.c
index d191c955f9..108f4f5720 100644
--- a/video/decode/hw_d3d11va.c
+++ b/video/decode/hw_d3d11va.c
@@ -30,566 +30,6 @@
#include "d3d.h"
-#if !HAVE_D3D_HWACCEL_NEW
-
-#define ADDITIONAL_SURFACES HWDEC_EXTRA_SURFACES
-
-struct d3d11va_decoder {
- ID3D11VideoDecoder *decoder;
- struct mp_image_pool *pool;
- ID3D11Texture2D *staging;
- int mpfmt_decoded;
-};
-
-struct priv {
- struct mp_log *log;
-
- ID3D11Device *device;
- ID3D11DeviceContext *device_ctx;
- ID3D11VideoDevice *video_dev;
- ID3D11VideoContext *video_ctx;
-
- struct d3d11va_decoder *decoder;
- struct mp_image_pool *sw_pool;
-};
-
-struct d3d11va_surface {
- ID3D11Texture2D *texture;
- ID3D11VideoDecoderOutputView *surface;
-};
-
-static void d3d11va_release_img(void *arg)
-{
- struct d3d11va_surface *surface = arg;
- if (surface->surface)
- ID3D11VideoDecoderOutputView_Release(surface->surface);
-
- if (surface->texture)
- ID3D11Texture2D_Release(surface->texture);
-
- talloc_free(surface);
-}
-
-static struct mp_image *d3d11va_new_ref(ID3D11VideoDecoderOutputView *view,
- int w, int h)
-{
- if (!view)
- return NULL;
- struct d3d11va_surface *surface = talloc_zero(NULL, struct d3d11va_surface);
-
- surface->surface = view;
- ID3D11VideoDecoderOutputView_AddRef(surface->surface);
- ID3D11VideoDecoderOutputView_GetResource(
- surface->surface, (ID3D11Resource **)&surface->texture);
-
- D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC surface_desc;
- ID3D11VideoDecoderOutputView_GetDesc(surface->surface, &surface_desc);
-
- struct mp_image *mpi =
- mp_image_new_custom_ref(NULL, surface, d3d11va_release_img);
- if (!mpi)
- abort();
-
- mp_image_setfmt(mpi, IMGFMT_D3D11VA);
- mp_image_set_size(mpi, w, h);
- mpi->planes[0] = (void *)surface->texture;
- mpi->planes[1] = (void *)(intptr_t)surface_desc.Texture2D.ArraySlice;
- mpi->planes[2] = NULL;
- mpi->planes[3] = (void *)surface->surface;
-
- return mpi;
-}
-
-static struct mp_image *d3d11va_allocate_image(struct lavc_ctx *s, int w, int h)
-{
- struct priv *p = s->hwdec_priv;
- struct mp_image *img = mp_image_pool_get_no_alloc(p->decoder->pool,
- IMGFMT_D3D11VA, w, h);
- if (!img)
- MP_ERR(p, "Failed to get free D3D11VA surface\n");
- return img;
-}
-
-static struct mp_image *d3d11va_retrieve_image(struct lavc_ctx *s,
- struct mp_image *img)
-{
- HRESULT hr;
- struct priv *p = s->hwdec_priv;
- ID3D11Texture2D *staging = p->decoder->staging;
-
- if (img->imgfmt != IMGFMT_D3D11VA)
- return img;
-
- ID3D11Texture2D *texture = (void *)img->planes[0];
- int subindex = (intptr_t)img->planes[1];
-
- if (!texture) {
- MP_ERR(p, "Failed to get Direct3D texture and surface from mp_image\n");
- return img;
- }
-
- D3D11_TEXTURE2D_DESC texture_desc;
- ID3D11Texture2D_GetDesc(texture, &texture_desc);
- if (texture_desc.Width < img->w || texture_desc.Height < img->h) {
- MP_ERR(p, "Direct3D11 texture smaller than mp_image dimensions\n");
- return img;
- }
-
- // copy to the staging texture
- ID3D11DeviceContext_CopySubresourceRegion(
- p->device_ctx,
- (ID3D11Resource *)staging, 0, 0, 0, 0,
- (ID3D11Resource *)texture, subindex, NULL);
-
- struct mp_image *sw_img = mp_image_pool_get(p->sw_pool,
- p->decoder->mpfmt_decoded,
- texture_desc.Width,
- texture_desc.Height);
- if (!sw_img) {
- MP_ERR(p, "Failed to get %s surface from CPU pool\n",
- mp_imgfmt_to_name(p->decoder->mpfmt_decoded));
- return img;
- }
-
- // copy staging texture to the cpu mp_image
- D3D11_MAPPED_SUBRESOURCE lock;
- hr = ID3D11DeviceContext_Map(p->device_ctx, (ID3D11Resource *)staging,
- 0, D3D11_MAP_READ, 0, &lock);
- if (FAILED(hr)) {
- MP_ERR(p, "Failed to map D3D11 surface: %s\n", mp_HRESULT_to_str(hr));
- talloc_free(sw_img);
- return img;
- }
- copy_nv12(sw_img, lock.pData, lock.RowPitch, texture_desc.Height);
- ID3D11DeviceContext_Unmap(p->device_ctx, (ID3D11Resource *)staging, 0);
-
- mp_image_set_size(sw_img, img->w, img->h);
- mp_image_copy_attributes(sw_img, img);
- talloc_free(img);
- return sw_img;
-}
-
-#define DFMT(name) MP_CONCAT(DXGI_FORMAT_, name), # name
-static const struct d3d_decoded_format d3d11_formats[] = {
- {DFMT(NV12), 8, IMGFMT_NV12},
- {DFMT(P010), 10, IMGFMT_P010},
- {DFMT(P016), 16, IMGFMT_P010},
-};
-#undef DFMT
-
-// Update hw_subfmt to the underlying format. Needed because AVFrame does not
-// have such an attribute, so it can't be passed through, and is updated here
-// instead. (But in the future, AVHWFramesContext could be used.)
-static struct mp_image *d3d11va_update_image_attribs(struct lavc_ctx *s,
- struct mp_image *img)
-{
- ID3D11Texture2D *texture = (void *)img->planes[0];
-
- if (!texture)
- return img;
-
- D3D11_TEXTURE2D_DESC texture_desc;
- ID3D11Texture2D_GetDesc(texture, &texture_desc);
- for (int n = 0; n < MP_ARRAY_SIZE(d3d11_formats); n++) {
- if (d3d11_formats[n].dxfmt == texture_desc.Format) {
- img->params.hw_subfmt = d3d11_formats[n].mpfmt;
- break;
- }
- }
-
- if (img->params.hw_subfmt == IMGFMT_NV12)
- mp_image_setfmt(img, IMGFMT_D3D11NV12);
-
- return img;
-}
-
-static bool d3d11_format_supported(struct lavc_ctx *s, const GUID *guid,
- const struct d3d_decoded_format *format)
-{
- struct priv *p = s->hwdec_priv;
- BOOL is_supported = FALSE;
- HRESULT hr = ID3D11VideoDevice_CheckVideoDecoderFormat(
- p->video_dev, guid, format->dxfmt, &is_supported);
- if (FAILED(hr)) {
- MP_ERR(p, "Check decoder output format %s for decoder %s: %s\n",
- format->name, d3d_decoder_guid_to_desc(guid),
- mp_HRESULT_to_str(hr));
- }
- return is_supported;
-}
-
-static void dump_decoder_info(struct lavc_ctx *s, const GUID *guid)
-{
- struct priv *p = s->hwdec_priv;
- char fmts[256] = {0};
- for (int i = 0; i < MP_ARRAY_SIZE(d3d11_formats); i++) {
- const struct d3d_decoded_format *format = &d3d11_formats[i];
- if (d3d11_format_supported(s, guid, format))
- mp_snprintf_cat(fmts, sizeof(fmts), " %s", format->name);
- }
- MP_VERBOSE(p, "%s %s\n", d3d_decoder_guid_to_desc(guid), fmts);
-}
-
-static void d3d11va_destroy_decoder(void *arg)
-{
- struct d3d11va_decoder *decoder = arg;
-
- if (decoder->decoder)
- ID3D11VideoDecoder_Release(decoder->decoder);
-
- if (decoder->staging)
- ID3D11Texture2D_Release(decoder->staging);
-}
-
-static int d3d11va_init_decoder(struct lavc_ctx *s, int w, int h)
-{
- HRESULT hr;
- int ret = -1;
- struct priv *p = s->hwdec_priv;
- TA_FREEP(&p->decoder);
-
- ID3D11Texture2D *texture = NULL;
- void *tmp = talloc_new(NULL);
-
- UINT n_guids = ID3D11VideoDevice_GetVideoDecoderProfileCount(p->video_dev);
- GUID *device_guids = talloc_array(tmp, GUID, n_guids);
- for (UINT i = 0; i < n_guids; i++) {
- GUID *guid = &device_guids[i];
- hr = ID3D11VideoDevice_GetVideoDecoderProfile(p->video_dev, i, guid);
- if (FAILED(hr)) {
- MP_ERR(p, "Failed to get VideoDecoderProfile %d: %s\n",
- i, mp_HRESULT_to_str(hr));
- goto done;
- }
- dump_decoder_info(s, guid);
- }
-
- struct d3d_decoder_fmt fmt =
- d3d_select_decoder_mode(s, device_guids, n_guids,
- d3d11_formats, MP_ARRAY_SIZE(d3d11_formats),
- d3d11_format_supported);
- if (!fmt.format) {
- MP_ERR(p, "Failed to find a suitable decoder\n");
- goto done;
- }
-
- struct d3d11va_decoder *decoder = talloc_zero(tmp, struct d3d11va_decoder);
- talloc_set_destructor(decoder, d3d11va_destroy_decoder);
- decoder->mpfmt_decoded = fmt.format->mpfmt;
-
- int n_surfaces = hwdec_get_max_refs(s) + ADDITIONAL_SURFACES;
- int w_align = w, h_align = h;
- d3d_surface_align(s, &w_align, &h_align);
-
- D3D11_TEXTURE2D_DESC tex_desc = {
- .Width = w_align,
- .Height = h_align,
- .MipLevels = 1,
- .Format = fmt.format->dxfmt,
- .SampleDesc.Count = 1,
- .MiscFlags = 0,
- .ArraySize = n_surfaces,
- .Usage = D3D11_USAGE_DEFAULT,
- .BindFlags = D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE,
- .CPUAccessFlags = 0,
- };
- hr = ID3D11Device_CreateTexture2D(p->device, &tex_desc, NULL, &texture);
- if (FAILED(hr)) {
- MP_ERR(p, "Failed to create Direct3D11 texture with %d surfaces: %s\n",
- n_surfaces, mp_HRESULT_to_str(hr));
- goto done;
- }
-
- if (s->hwdec->type == HWDEC_D3D11VA_COPY) {
- // create staging texture shared with the CPU with mostly the same
- // parameters as the above decoder-bound texture
- ID3D11Texture2D_GetDesc(texture, &tex_desc);
- tex_desc.MipLevels = 1;
- tex_desc.MiscFlags = 0;
- tex_desc.ArraySize = 1;
- tex_desc.Usage = D3D11_USAGE_STAGING;
- tex_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
- tex_desc.BindFlags = 0;
- hr = ID3D11Device_CreateTexture2D(p->device, &tex_desc, NULL,
- &decoder->staging);
- if (FAILED(hr)) {
- MP_ERR(p, "Failed to create staging texture: %s\n",
- mp_HRESULT_to_str(hr));
- goto done;
- }
- }
-
- // pool to hold the mp_image wrapped surfaces
- decoder->pool = talloc_steal(decoder, mp_image_pool_new(n_surfaces));
- // array of the same surfaces (needed by ffmpeg)
- ID3D11VideoDecoderOutputView **surfaces =
- talloc_array_ptrtype(decoder->pool, surfaces, n_surfaces);
-
- D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC view_desc = {
- .DecodeProfile = *fmt.guid,
- .ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D,
- };
- for (int i = 0; i < n_surfaces; i++) {
- ID3D11VideoDecoderOutputView **surface = &surfaces[i];
- view_desc.Texture2D.ArraySlice = i;
- hr = ID3D11VideoDevice_CreateVideoDecoderOutputView(
- p->video_dev, (ID3D11Resource *)texture, &view_desc, surface);
- if (FAILED(hr)) {
- MP_ERR(p, "Failed getting decoder output view %d: %s\n",
- i, mp_HRESULT_to_str(hr));
- goto done;
- }
- struct mp_image *img = d3d11va_new_ref(*surface, w, h);
- ID3D11VideoDecoderOutputView_Release(*surface); // transferred to img
- if (!img) {
- MP_ERR(p, "Failed to create D3D11VA image %d\n", i);
- goto done;
- }
- mp_image_pool_add(decoder->pool, img); // transferred to pool
- }
-
- D3D11_VIDEO_DECODER_DESC decoder_desc = {
- .Guid = *fmt.guid,
- .SampleWidth = w,
- .SampleHeight = h,
- .OutputFormat = fmt.format->dxfmt,
- };
- UINT n_cfg;
- hr = ID3D11VideoDevice_GetVideoDecoderConfigCount(p->video_dev,
- &decoder_desc, &n_cfg);
- if (FAILED(hr)) {
- MP_ERR(p, "Failed to get number of decoder configurations: %s)",
- mp_HRESULT_to_str(hr));
- goto done;
- }
-
- // pick the config with the highest score
- D3D11_VIDEO_DECODER_CONFIG *decoder_config =
- talloc_zero(decoder, D3D11_VIDEO_DECODER_CONFIG);
- unsigned max_score = 0;
- for (UINT i = 0; i < n_cfg; i++) {
- D3D11_VIDEO_DECODER_CONFIG cfg;
- hr = ID3D11VideoDevice_GetVideoDecoderConfig(p->video_dev,
- &decoder_desc,
- i, &cfg);
- if (FAILED(hr)) {
- MP_ERR(p, "Failed to get decoder config %d: %s\n",
- i, mp_HRESULT_to_str(hr));
- goto done;
- }
- unsigned score = d3d_decoder_config_score(
- s, &cfg.guidConfigBitstreamEncryption, cfg.ConfigBitstreamRaw);
- if (score > max_score) {
- max_score = score;
- *decoder_config = cfg;
- }
- }
- if (!max_score) {
- MP_ERR(p, "Failed to find a suitable decoder configuration\n");
- goto done;
- }
-
- hr = ID3D11VideoDevice_CreateVideoDecoder(p->video_dev, &decoder_desc,
- decoder_config,
- &decoder->decoder);
- if (FAILED(hr)) {
- MP_ERR(p, "Failed to create video decoder: %s\n",
- mp_HRESULT_to_str(hr));
- goto done;
- }
-
- struct AVD3D11VAContext *avd3d11va_ctx = s->avctx->hwaccel_context;
- avd3d11va_ctx->decoder = decoder->decoder;
- avd3d11va_ctx->video_context = p->video_ctx;
- avd3d11va_ctx->cfg = decoder_config;
- avd3d11va_ctx->surface_count = n_surfaces;
- avd3d11va_ctx->surface = surfaces;
- avd3d11va_ctx->workaround = is_clearvideo(fmt.guid) ?
- FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO : 0;
-
- p->decoder = talloc_steal(NULL, decoder);
- ret = 0;
-done:
- // still referenced by pool images / surfaces
- if (texture)
- ID3D11Texture2D_Release(texture);
-
- talloc_free(tmp);
- return ret;
-}
-
-static void destroy_device(struct lavc_ctx *s)
-{
- struct priv *p = s->hwdec_priv;
-
- if (p->device)
- ID3D11Device_Release(p->device);
-
- if (p->device_ctx)
- ID3D11DeviceContext_Release(p->device_ctx);
-}
-
-static bool create_device(struct lavc_ctx *s, BOOL thread_safe)
-{
- HRESULT hr;
- struct priv *p = s->hwdec_priv;
-
- if (!d3d11_dll) {
- MP_ERR(p, "Failed to load D3D11 library\n");
- return false;
- }
-
- PFN_D3D11_CREATE_DEVICE CreateDevice =
- (void *)GetProcAddress(d3d11_dll, "D3D11CreateDevice");
- if (!CreateDevice) {
- MP_ERR(p, "Failed to get D3D11CreateDevice symbol from DLL: %s\n",
- mp_LastError_to_str());
- return false;
- }
-
- hr = CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL,
- D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0,
- D3D11_SDK_VERSION, &p->device, NULL, &p->device_ctx);
- if (FAILED(hr)) {
- MP_ERR(p, "Failed to create D3D11 Device: %s\n",
- mp_HRESULT_to_str(hr));
- return false;
- }
-
- ID3D10Multithread *multithread;
- hr = ID3D11Device_QueryInterface(p->device, &IID_ID3D10Multithread,
- (void **)&multithread);
- if (FAILED(hr)) {
- MP_ERR(p, "Failed to get Multithread interface: %s\n",
- mp_HRESULT_to_str(hr));
- return false;
- }
- ID3D10Multithread_SetMultithreadProtected(multithread, thread_safe);
- ID3D10Multithread_Release(multithread);
- return true;
-}
-
-static void d3d11va_uninit(struct lavc_ctx *s)
-{
- struct priv *p = s->hwdec_priv;
- if (!p)
- return;
-
- talloc_free(p->decoder);
- av_freep(&s->avctx->hwaccel_context);
-
- if (p->video_dev)
- ID3D11VideoDevice_Release(p->video_dev);
-
- if (p->video_ctx)
- ID3D11VideoContext_Release(p->video_ctx);
-
- destroy_device(s);
-
- TA_FREEP(&s->hwdec_priv);
-}
-
-static int d3d11va_init(struct lavc_ctx *s)
-{
- HRESULT hr;
- struct priv *p = talloc_zero(NULL, struct priv);
- if (!p)
- return -1;
-
- // Unconditionally load Direct3D DLLs, even when using a VO-supplied D3D11
- // device. This prevents a crash that occurs at least with NVIDIA drivers,
- // where D3D objects are accessed after ANGLE unloads d3d11.dll.
- d3d_load_dlls();
-
- s->hwdec_priv = p;
- p->log = mp_log_new(s, s->log, "d3d11va");
- if (s->hwdec->type == HWDEC_D3D11VA_COPY) {
- mp_check_gpu_memcpy(p->log, NULL);
- p->sw_pool = talloc_steal(p, mp_image_pool_new(17));
- }
-
- p->device = hwdec_devices_load(s->hwdec_devs, s->hwdec->type);
- if (p->device) {
- ID3D11Device_AddRef(p->device);
- ID3D11Device_GetImmediateContext(p->device, &p->device_ctx);
- if (!p->device_ctx)
- goto fail;
- MP_VERBOSE(p, "Using VO-supplied device %p.\n", p->device);
- } else if (s->hwdec->type == HWDEC_D3D11VA) {
- MP_ERR(p, "No Direct3D device provided for native d3d11 decoding\n");
- goto fail;
- } else {
- if (!create_device(s, FALSE))
- goto fail;
- }
-
- hr = ID3D11DeviceContext_QueryInterface(p->device_ctx,
- &IID_ID3D11VideoContext,
-