diff options
Diffstat (limited to 'video/decode')
-rw-r--r-- | video/decode/d3d.c | 57 | ||||
-rw-r--r-- | video/decode/d3d.h | 21 | ||||
-rw-r--r-- | video/decode/d3d11va.c | 184 | ||||
-rw-r--r-- | video/decode/dec_video.h | 2 | ||||
-rw-r--r-- | video/decode/dxva2.c | 134 | ||||
-rw-r--r-- | video/decode/lavc.h | 12 | ||||
-rw-r--r-- | video/decode/mediacodec.c | 68 | ||||
-rw-r--r-- | video/decode/rpi.c | 71 | ||||
-rw-r--r-- | video/decode/vaapi.c | 57 | ||||
-rw-r--r-- | video/decode/vd_lavc.c | 186 | ||||
-rw-r--r-- | video/decode/vdpau.c | 21 | ||||
-rw-r--r-- | video/decode/videotoolbox.c | 9 |
12 files changed, 459 insertions, 363 deletions
diff --git a/video/decode/d3d.c b/video/decode/d3d.c index 35d1af9243..b978472723 100644 --- a/video/decode/d3d.c +++ b/video/decode/d3d.c @@ -15,6 +15,8 @@ * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ +#include <pthread.h> + #include <libavcodec/avcodec.h> #include "lavc.h" @@ -48,7 +50,6 @@ DEFINE_GUID(DXVA2_ModeVP9_VLD_Profile0, 0x463707f8, 0xa1d0, 0x4585, 0x87 DEFINE_GUID(DXVA2_NoEncrypt, 0x1b81beD0, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5); -static const int PROF_MPEG2_SIMPLE[] = {FF_PROFILE_MPEG2_SIMPLE, 0}; 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, @@ -70,14 +71,14 @@ struct d3dva_mode { // Prefered modes must come first static const struct d3dva_mode d3dva_modes[] = { // MPEG-1/2 - {MODE2(MPEG2_VLD), AV_CODEC_ID_MPEG2VIDEO, PROF_MPEG2_SIMPLE}, + {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}, - {MODE (Intel_H264_NoFGT_ClearVideo), 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}, @@ -97,6 +98,22 @@ static const struct d3dva_mode d3dva_modes[] = { #undef MODE #undef MODE2 +HMODULE d3d11_dll, d3d9_dll, dxva2_dll; + +static pthread_once_t d3d_load_once = PTHREAD_ONCE_INIT; + +static void d3d_do_load(void) +{ + d3d11_dll = LoadLibrary(L"d3d11.dll"); + d3d9_dll = LoadLibrary(L"d3d9.dll"); + dxva2_dll = LoadLibrary(L"dxva2.dll"); +} + +void d3d_load_dlls(void) +{ + pthread_once(&d3d_load_once, d3d_do_load); +} + int d3d_probe_codec(const char *codec) { enum AVCodecID codecid = mp_codec_to_av_codec_id(codec); @@ -132,12 +149,13 @@ static bool mode_supported(const struct d3dva_mode *mode, struct d3d_decoder_fmt d3d_select_decoder_mode( struct lavc_ctx *s, const GUID *device_guids, UINT n_guids, - DWORD (*get_dxfmt_cb)(struct lavc_ctx *s, const GUID *guid, int depth)) + 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, - .mpfmt_decoded = IMGFMT_NONE, - .dxfmt_decoded = 0, + .guid = &GUID_NULL, + .format = NULL, }; // this has the right bit-depth, but is unfortunately not the native format @@ -146,8 +164,6 @@ struct d3d_decoder_fmt d3d_select_decoder_mode( return fmt; int depth = IMGFMT_RGB_DEPTH(sw_img_fmt); - int p010 = mp_imgfmt_find(1, 1, 2, 10, MP_IMGFLAG_YUV_NV); - int mpfmt_decoded = depth <= 8 ? IMGFMT_NV12 : p010; for (int i = 0; i < MP_ARRAY_SIZE(d3dva_modes); i++) { const struct d3dva_mode *mode = &d3dva_modes[i]; @@ -155,12 +171,23 @@ struct d3d_decoder_fmt d3d_select_decoder_mode( profile_compatible(mode, s->avctx->profile) && mode_supported(mode, device_guids, n_guids)) { - DWORD dxfmt_decoded = get_dxfmt_cb(s, mode->guid, depth); - if (dxfmt_decoded) { - fmt.guid = mode->guid; - fmt.mpfmt_decoded = mpfmt_decoded; - fmt.dxfmt_decoded = dxfmt_decoded; - return fmt; + 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; + } } } } diff --git a/video/decode/d3d.h b/video/decode/d3d.h index bbd6bdfd2a..15c423ab8c 100644 --- a/video/decode/d3d.h +++ b/video/decode/d3d.h @@ -24,16 +24,31 @@ 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; - int mpfmt_decoded; - DWORD dxfmt_decoded; // D3DFORMAT or DXGI_FORMAT + 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; + +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, - DWORD (*get_dxfmt_cb)(struct lavc_ctx *s, const GUID *guid, int depth)); + 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); diff --git a/video/decode/d3d11va.c b/video/decode/d3d11va.c index 622a28981d..d929e1e70f 100644 --- a/video/decode/d3d11va.c +++ b/video/decode/d3d11va.c @@ -15,6 +15,7 @@ * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ +#include <initguid.h> #include <libavcodec/d3d11va.h> #include "lavc.h" @@ -25,7 +26,6 @@ #include "video/mp_image_pool.h" #include "video/hwdec.h" -#include "video/d3d11va.h" #include "d3d.h" #define ADDITIONAL_SURFACES (4 + HWDEC_DELAY_QUEUE_COUNT) @@ -40,7 +40,6 @@ struct d3d11va_decoder { struct priv { struct mp_log *log; - HMODULE d3d11_dll; ID3D11Device *device; ID3D11DeviceContext *device_ctx; ID3D11VideoDevice *video_dev; @@ -50,6 +49,53 @@ struct priv { 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] = NULL; + mpi->planes[1] = (void *)surface->texture; + mpi->planes[2] = (void *)(intptr_t)surface_desc.Texture2D.ArraySlice; + 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; @@ -66,10 +112,14 @@ static struct mp_image *d3d11va_retrieve_image(struct lavc_ctx *s, HRESULT hr; struct priv *p = s->hwdec_priv; ID3D11Texture2D *staging = p->decoder->staging; - ID3D11Texture2D *texture = d3d11_texture_in_mp_image(img); - ID3D11VideoDecoderOutputView *surface = d3d11_surface_in_mp_image(img); - if (!texture || !surface) { + if (img->imgfmt != IMGFMT_D3D11VA) + return img; + + ID3D11Texture2D *texture = (void *)img->planes[1]; + int subindex = (intptr_t)img->planes[2]; + + if (!texture) { MP_ERR(p, "Failed to get Direct3D texture and surface from mp_image\n"); return img; } @@ -82,12 +132,10 @@ static struct mp_image *d3d11va_retrieve_image(struct lavc_ctx *s, } // copy to the staging texture - D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC surface_desc; - ID3D11VideoDecoderOutputView_GetDesc(surface, &surface_desc); ID3D11DeviceContext_CopySubresourceRegion( p->device_ctx, (ID3D11Resource *)staging, 0, 0, 0, 0, - (ID3D11Resource *)texture, surface_desc.Texture2D.ArraySlice, NULL); + (ID3D11Resource *)texture, subindex, NULL); struct mp_image *sw_img = mp_image_pool_get(p->sw_pool, p->decoder->mpfmt_decoded, @@ -117,27 +165,47 @@ static struct mp_image *d3d11va_retrieve_image(struct lavc_ctx *s, return sw_img; } -struct d3d11_format { - DXGI_FORMAT format; - const char *name; - int depth; -}; - #define DFMT(name) MP_CONCAT(DXGI_FORMAT_, name), # name -static const struct d3d11_format d3d11_formats[] = { - {DFMT(NV12), 8}, - {DFMT(P010), 10}, - {DFMT(P016), 16}, +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 -static BOOL d3d11_format_supported(struct lavc_ctx *s, const GUID *guid, - const struct d3d11_format *format) +// 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[1]; + + 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->format, &is_supported); + 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), @@ -151,25 +219,13 @@ 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 d3d11_format *format = &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 DWORD get_dxfmt_cb(struct lavc_ctx *s, const GUID *guid, int depth) -{ - for (int i = 0; i < MP_ARRAY_SIZE(d3d11_formats); i++) { - const struct d3d11_format *format = &d3d11_formats[i]; - if (depth <= format->depth && - d3d11_format_supported(s, guid, format)) { - return format->format; - } - } - return 0; -} - static void d3d11va_destroy_decoder(void *arg) { struct d3d11va_decoder *decoder = arg; @@ -188,6 +244,7 @@ static int d3d11va_init_decoder(struct lavc_ctx *s, int w, int h) 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); @@ -204,31 +261,32 @@ static int d3d11va_init_decoder(struct lavc_ctx *s, int w, int h) } struct d3d_decoder_fmt fmt = - d3d_select_decoder_mode(s, device_guids, n_guids, get_dxfmt_cb); - if (fmt.mpfmt_decoded == IMGFMT_NONE) { + 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.mpfmt_decoded; + 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); - ID3D11Texture2D *texture = NULL; D3D11_TEXTURE2D_DESC tex_desc = { .Width = w_align, .Height = h_align, .MipLevels = 1, - .Format = fmt.dxfmt_decoded, + .Format = fmt.format->dxfmt, .SampleDesc.Count = 1, .MiscFlags = 0, .ArraySize = n_surfaces, .Usage = D3D11_USAGE_DEFAULT, - .BindFlags = D3D11_BIND_DECODER, + .BindFlags = D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE, .CPUAccessFlags = 0, }; hr = ID3D11Device_CreateTexture2D(p->device, &tex_desc, NULL, &texture); @@ -290,7 +348,7 @@ static int d3d11va_init_decoder(struct lavc_ctx *s, int w, int h) .Guid = *fmt.guid, .SampleWidth = w, .SampleHeight = h, - .OutputFormat = fmt.dxfmt_decoded, + .OutputFormat = fmt.format->dxfmt, }; UINT n_cfg; hr = ID3D11VideoDevice_GetVideoDecoderConfigCount(p->video_dev, @@ -365,9 +423,6 @@ static void destroy_device(struct lavc_ctx *s) if (p->device_ctx) ID3D11DeviceContext_Release(p->device_ctx); - - if (p->d3d11_dll) - FreeLibrary(p->d3d11_dll); } static bool create_device(struct lavc_ctx *s, BOOL thread_safe) @@ -375,14 +430,14 @@ static bool create_device(struct lavc_ctx *s, BOOL thread_safe) HRESULT hr; struct priv *p = s->hwdec_priv; - p->d3d11_dll = LoadLibrary(L"d3d11.dll"); - if (!p->d3d11_dll) { + d3d_load_dlls(); + if (!d3d11_dll) { MP_ERR(p, "Failed to load D3D11 library\n"); return false; } PFN_D3D11_CREATE_DEVICE CreateDevice = - (void *)GetProcAddress(p->d3d11_dll, "D3D11CreateDevice"); + (void *)GetProcAddress(d3d11_dll, "D3D11CreateDevice"); if (!CreateDevice) { MP_ERR(p, "Failed to get D3D11CreateDevice symbol from DLL: %s\n", mp_LastError_to_str()); @@ -445,8 +500,20 @@ static int d3d11va_init(struct lavc_ctx *s) p->sw_pool = talloc_steal(p, mp_image_pool_new(17)); } - if (!create_device(s, FALSE)) + 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, @@ -478,16 +545,31 @@ fail: return -1; } -static int d3d11va_probe(struct vd_lavc_hwdec *hwdec, - struct mp_hwdec_info *info, +static int d3d11va_probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, const char *codec) { - hwdec_request_api(info, "d3d11va"); + // d3d11va-copy can do without external context; dxva2 requires it. + if (hwdec->type != HWDEC_D3D11VA_COPY) { + if (!hwdec_devices_load(ctx->hwdec_devs, HWDEC_D3D11VA)) + return HWDEC_ERR_NO_CTX; + } return d3d_probe_codec(codec); } +const struct vd_lavc_hwdec mp_vd_lavc_d3d11va = { + .type = HWDEC_D3D11VA, + .image_format = IMGFMT_D3D11VA, + .probe = d3d11va_probe, + .init = d3d11va_init, + .uninit = d3d11va_uninit, + .init_decoder = d3d11va_init_decoder, + .allocate_image = d3d11va_allocate_image, + .process_image = d3d11va_update_image_attribs, +}; + const struct vd_lavc_hwdec mp_vd_lavc_d3d11va_copy = { .type = HWDEC_D3D11VA_COPY, + .copying = true, .image_format = IMGFMT_D3D11VA, .probe = d3d11va_probe, .init = d3d11va_init, diff --git a/video/decode/dec_video.h b/video/decode/dec_video.h index f4646a97d0..1030973e1c 100644 --- a/video/decode/dec_video.h +++ b/video/decode/dec_video.h @@ -32,7 +32,7 @@ struct dec_video { struct mpv_global *global; struct MPOpts *opts; const struct vd_functions *vd_driver; - struct mp_hwdec_info *hwdec_info; // video output hwdec handles + struct mp_hwdec_devices *hwdec_devs; // video output hwdec handles struct sh_stream *header; struct mp_codec_params *codec; diff --git a/video/decode/dxva2.c b/video/decode/dxva2.c index c90fa76885..fc52aca03b 100644 --- a/video/decode/dxva2.c +++ b/video/decode/dxva2.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <initguid.h> + #define DXVA2API_USE_BITFIELDS #include <libavcodec/dxva2.h> @@ -30,8 +32,6 @@ #include "video/mp_image_pool.h" #include "video/hwdec.h" -#include "video/d3d.h" -#include "video/dxva2.h" #include "d3d.h" #define ADDITIONAL_SURFACES (4 + HWDEC_DELAY_QUEUE_COUNT) @@ -39,8 +39,6 @@ struct priv { struct mp_log *log; - HMODULE d3d9_dll; - HMODULE dxva2_dll; IDirect3D9 *d3d9; IDirect3DDevice9 *device; HANDLE device_handle; @@ -52,6 +50,47 @@ struct priv { int mpfmt_decoded; }; +struct dxva2_surface { + IDirectXVideoDecoder *decoder; + IDirect3DSurface9 *surface; +}; + +static void dxva2_release_img(void *arg) +{ + struct dxva2_surface *surface = arg; + if (surface->surface) + IDirect3DSurface9_Release(surface->surface); + + if (surface->decoder) + IDirectXVideoDecoder_Release(surface->decoder); + + talloc_free(surface); +} + +static struct mp_image *dxva2_new_ref(IDirectXVideoDecoder *decoder, + IDirect3DSurface9 *d3d9_surface, + int w, int h) +{ + if (!decoder || !d3d9_surface) + return NULL; + struct dxva2_surface *surface = talloc_zero(NULL, struct dxva2_surface); + + surface->surface = d3d9_surface; + IDirect3DSurface9_AddRef(surface->surface); + surface->decoder = decoder; + IDirectXVideoDecoder_AddRef(surface->decoder); + + struct mp_image *mpi = + mp_image_new_custom_ref(NULL, surface, dxva2_release_img); + if (!mpi) + abort(); + + mp_image_setfmt(mpi, IMGFMT_DXVA2); + mp_image_set_size(mpi, w, h); + mpi->planes[3] = (void *)surface->surface; + return mpi; +} + static struct mp_image *dxva2_allocate_image(struct lavc_ctx *s, int w, int h) { struct priv *p = s->hwdec_priv; @@ -67,7 +106,8 @@ static struct mp_image *dxva2_retrieve_image(struct lavc_ctx *s, { HRESULT hr; struct priv *p = s->hwdec_priv; - IDirect3DSurface9 *surface = d3d9_surface_in_mp_image(img); + IDirect3DSurface9 *surface = img->imgfmt == IMGFMT_DXVA2 ? + (IDirect3DSurface9 *)img->planes[3] : NULL; if (!surface) { MP_ERR(p, "Failed to get Direct3D surface from mp_image\n"); @@ -108,15 +148,10 @@ static struct mp_image *dxva2_retrieve_image(struct lavc_ctx *s, return sw_img; } -struct d3d9_format { - D3DFORMAT format; - int depth; -}; - -static const struct d3d9_format d3d9_formats[] = { - {MKTAG('N','V','1','2'), 8}, - {MKTAG('P','0','1','0'), 10}, - {MKTAG('P','0','1','6'), 16}, +static const struct d3d_decoded_format d3d9_formats[] = { + {MKTAG('N','V','1','2'), "NV12", 8, IMGFMT_NV12}, + {MKTAG('P','0','1','0'), "P010", 10, IMGFMT_P010}, + {MKTAG('P','0','1','6'), "P016", 16, IMGFMT_P010}, }; static void dump_decoder_info(struct lavc_ctx *s, @@ -133,7 +168,7 @@ static void dump_decoder_info(struct lavc_ctx *s, HRESULT hr = IDirectXVideoDecoderService_GetDecoderRenderTargets( p->decoder_service, guid, &n_formats, &formats); if (FAILED(hr)) { - MP_ERR(p, "Failed to get render targets for decoder %s:%s", + MP_ERR(p, "Failed to get render targets for decoder %s:%s\n", description, mp_HRESULT_to_str(hr)); } @@ -148,9 +183,10 @@ static void dump_decoder_info(struct lavc_ctx *s, } } -static DWORD get_dxfmt_cb(struct lavc_ctx *s, const GUID *guid, int depth) +static bool dxva2_format_supported(struct lavc_ctx *s, const GUID *guid, + const struct d3d_decoded_format *format) { - DWORD ret = 0; + bool ret = false; struct priv *p = s->hwdec_priv; D3DFORMAT *formats = NULL; UINT n_formats = 0; @@ -162,19 +198,12 @@ static DWORD get_dxfmt_cb(struct lavc_ctx *s, const GUID *guid, int depth) return 0; } - for (int i = 0; i < MP_ARRAY_SIZE(d3d9_formats); i++) { - const struct d3d9_format *d3d9_fmt = &d3d9_formats[i]; - if (d3d9_fmt->depth < depth) - continue; - - for (UINT j = 0; j < n_formats; j++) { - if (formats[i] == d3d9_fmt->format) { - ret = formats[i]; - goto done; - } - } + for (int i = 0; i < n_formats; i++) { + ret = formats[i] == format->dxfmt; + if (ret) + break; } -done: + CoTaskMemFree(formats); return ret; } @@ -204,14 +233,16 @@ static int dxva2_init_decoder(struct lavc_ctx *s, int w, int h) dump_decoder_info(s, device_guids, n_guids); struct d3d_decoder_fmt fmt = - d3d_select_decoder_mode(s, device_guids, n_guids, get_dxfmt_cb); + d3d_select_decoder_mode(s, device_guids, n_guids, + d3d9_formats, MP_ARRAY_SIZE(d3d9_formats), + dxva2_format_supported); CoTaskMemFree(device_guids); - if (fmt.mpfmt_decoded == IMGFMT_NONE) { + if (!fmt.format) { MP_ERR(p, "Failed to find a suitable decoder\n"); goto done; } - p->mpfmt_decoded = fmt.mpfmt_decoded; + p->mpfmt_decoded = fmt.format->mpfmt; struct mp_image_pool *decoder_pool = talloc_steal(tmp, mp_image_pool_new(n_surfaces)); DXVA2_ConfigPictureDecode *decoder_config = @@ -222,7 +253,7 @@ static int dxva2_init_decoder(struct lavc_ctx *s, int w, int h) DXVA2_VideoDesc video_desc ={ .SampleWidth = w, .SampleHeight = h, - .Format = fmt.dxfmt_decoded, + .Format = fmt.format->dxfmt, }; UINT n_configs = 0; DXVA2_ConfigPictureDecode *configs = NULL; @@ -255,7 +286,7 @@ static int dxva2_init_decoder(struct lavc_ctx *s, int w, int h) hr = IDirectXVideoDecoderService_CreateSurface( p->decoder_service, w_align, h_align, - n_surfaces - 1, fmt.dxfmt_decoded, D3DPOOL_DEFAULT, 0, + n_surfaces - 1, fmt.format->dxfmt, D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget, surfaces, NULL); if (FAILED(hr)) { MP_ERR(p, "Failed to create %d video surfaces: %s\n", @@ -316,25 +347,20 @@ static void destroy_device(struct lavc_ctx *s) if (p->d3d9) IDirect3D9_Release(p->d3d9); - - if (p->d3d9_dll) - FreeLibrary(p->d3d9_dll); - - if (p->dxva2_dll) - FreeLibrary(p->dxva2_dll); } static bool create_device(struct lavc_ctx *s) { struct priv *p = s->hwdec_priv; - p->d3d9_dll = LoadLibrary(L"d3d9.dll"); - if (!p->d3d9_dll) { + + d3d_load_dlls(); + if (!d3d9_dll) { MP_ERR(p, "Failed to load D3D9 library\n"); return false; } IDirect3D9* (WINAPI *Direct3DCreate9)(UINT) = - (void *)GetProcAddress(p->d3d9_dll, "Direct3DCreate9"); + (void *)GetProcAddress(d3d9_dll, "Direct3DCreate9"); if (!Direct3DCreate9) { MP_ERR(p, "Failed to locate Direct3DCreate9\n"); return false; @@ -413,9 +439,7 @@ static int dxva2_init(struct lavc_ctx *s) p->sw_pool = talloc_steal(p, mp_image_pool_new(17)); } - if (s->hwdec_info && s->hwdec_info->hwctx && s->hwdec_info->hwctx->d3d_ctx) - p->device = s->hwdec_info->hwctx->d3d_ctx->d3d9_device; - + p->device = hwdec_devices_load(s->hwdec_devs, s->hwdec->type); if (p->device) { IDirect3D9_AddRef(p->device); MP_VERBOSE(p, "Using VO-supplied device %p.\n", p->device); @@ -427,15 +451,14 @@ static int dxva2_init(struct lavc_ctx *s) goto fail; } - p->dxva2_dll = LoadLibrary(L"dxva2.dll"); - if (!p->dxva2_dll) { + d3d_load_dlls(); + if (!dxva2_dll) { MP_ERR(p, "Failed to load DXVA2 library\n"); goto fail; } HRESULT (WINAPI *CreateDeviceManager9)(UINT *, IDirect3DDeviceManager9 **) = - (void *)GetProcAddress(p->dxva2_dll, - "DXVA2CreateDirect3DDeviceManager9"); + (void *)GetProcAddress(dxva2_dll, "DXVA2CreateDirect3DDeviceManager9"); if (!CreateDeviceManager9) { MP_ERR(p, "Failed to locate DXVA2CreateDirect3DDeviceManager9\n"); goto fail; @@ -484,15 +507,15 @@ fail: return -1; } -static int dxva2_probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info, +static int dxva2_probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, const char *codec) { - hwdec_request_api(info, "dxva2"); // dxva2-copy can do without external context; dxva2 requires it. - if (hwdec->type != HWDEC_DXVA2_COPY) { - if (!info || !info->hwctx || !info->hwctx->d3d_ctx || - info->hwctx->type == HWDEC_DXVA2_COPY) + if (hwdec->type == HWDEC_DXVA2) { + if (!hwdec_devices_load(ctx->hwdec_devs, HWDEC_DXVA2)) return HWDEC_ERR_NO_CTX; + } else { + hwdec_devices_load(ctx->hwdec_devs, HWDEC_DXVA2_COPY); } return d3d_probe_codec(codec); } @@ -509,6 +532,7 @@ const struct vd_lavc_hwdec mp_vd_lavc_dxva2 = { const struct vd_lavc_hwdec mp_vd_lavc_dxva2_copy = { .type = HWDEC_DXVA2_COPY, + .copying = true, .image_format = IMGFMT_DXVA2, .probe = dxva2_probe, .init = dxva2_init, diff --git a/video/decode/lavc.h b/video/decode/lavc.h index 826edbff83..689222d872 100644 --- a/video/decode/lavc.h +++ b/video/decode/lavc.h @@ -30,7 +30,7 @@ typedef struct lavc_ctx { int max_delay_queue; // From VO - struct mp_hwdec_info *hwdec_info; + struct mp_hwdec_devices *hwdec_devs; // For free use by hwdec implementation void *hwdec_priv; @@ -49,12 +49,14 @@ struct vd_lavc_hwdec { // If not-0: the IMGFMT_ format that should be accepted in the libavcodec // get_format callback. int image_format; + // Always returns a non-hwaccel image format. + bool copying; // Setting this will queue the given number of frames before calling // process_image() or returning them to the renderer. This can increase // efficiency by not blocking on the hardware pipeline by reading back // immediately after decoding. int delay_queue; - int (*probe)(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info, + int (*probe)(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, const char *codec); int (*init)(struct lavc_ctx *ctx); int (*init_decoder)(struct lavc_ctx *ctx, int w, int h); @@ -69,6 +71,10 @@ struct vd_lavc_hwdec { void (*unlock)(struct lavc_ctx *ctx); // Optional; if a special hardware decoder is needed (instead of "hwaccel"). const char *(*get_codec)(struct lavc_ctx *ctx, const char *codec); + // Suffix for libavcodec decoder. If non-NULL, get_codec() is overridden + // with hwdec_find_decoder. + // Intuitively, this will force the corresponding wrapper decoder. + const char *lavc_suffix; }; enum { @@ -89,4 +95,6 @@ bool hwdec_check_codec_support(const char *codec, const struct hwdec_profile_entry *table); int hwdec_get_max_refs(struct lavc_ctx *ctx); +const char *hwdec_find_decoder(const char *codec, const char *suffix); + #endif diff --git a/video/decode/mediacodec.c b/video/decode/mediacodec.c deleted file mode 100644 index 37ce1b8a2f..0000000000 --- a/video/decode/mediacodec.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * mpv is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with mpv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "lavc.h" -#include "common/common.h" - -static const char *const codecs[][2] = { - {"h264", "h264_mediacodec"}, - {0} -}; - -static const char *map_codec(const char *c) -{ - for (int n = 0; codecs[n][0]; n++) { - if (c && strcmp(codecs[n][0], c) == 0) - return codecs[n][1]; - } - return NULL; -} - -static int init_decoder(struct lavc_ctx *ctx, int w, int h) -{ - return 0; -} - -static void uninit(struct lavc_ctx *ctx) -{ -} - -static int init(struct lavc_ctx *ctx) -{ - return 0; -} - -static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info, - const char *decoder) -{ - return map_codec(decoder) ? 0 : HWDEC_ERR_NO_CODEC; -} - -static const char *get_codec(struct lavc_ctx *ctx, const char *codec) -{ - return map_codec(codec); -} - -const struct vd_lavc_hwdec mp_vd_lavc_mediacodec = { - .type |