static void dump_decoder_info(struct lavc_ctx *s, GUID *device_guids, UINT n_guids) { struct priv *p = s->hwdec_priv; MP_VERBOSE(p, "%u decoder devices:\n", (unsigned)n_guids); for (UINT i = 0; i < n_guids; i++) { GUID *guid = &device_guids[i]; char *description = d3d_decoder_guid_to_desc(guid); D3DFORMAT *formats = NULL; UINT n_formats = 0; 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\n", description, mp_HRESULT_to_str(hr)); } char fmts[256] = {0}; for (UINT j = 0; j < n_formats; j++) { mp_snprintf_cat(fmts, sizeof(fmts), " %s", mp_tag_str(formats[j])); } CoTaskMemFree(formats); MP_VERBOSE(p, "%s %s\n", description, fmts); } }
static DWORD get_dxfmt_cb(struct lavc_ctx *s, const GUID *guid, int depth) { DWORD ret = 0; struct priv *p = s->hwdec_priv; D3DFORMAT *formats = NULL; UINT n_formats = 0; HRESULT hr = IDirectXVideoDecoderService_GetDecoderRenderTargets( p->decoder_service, guid, &n_formats, &formats); if (FAILED(hr)) { MP_ERR(p, "Callback failed to get render targets for decoder %s: %s", d3d_decoder_guid_to_desc(guid), mp_HRESULT_to_str(hr)); 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]; MP_VERBOSE(p, "Selecting %s %s\n", d3d_decoder_guid_to_desc(guid), mp_tag_str(ret)); goto done; } } } done: CoTaskMemFree(formats); return ret; }
static int dxva2_create_decoder(struct lavc_ctx *s, int w, int h, enum AVCodecID codec_id, int profile) { DXVA2Context *ctx = s->hwdec_priv; struct dxva_context *dxva_ctx = s->avctx->hwaccel_context; GUID *guid_list = NULL; unsigned guid_count = 0, i, j; GUID device_guid = GUID_NULL; D3DFORMAT target_format = 0; DXVA2_VideoDesc desc = { 0 }; DXVA2_ConfigPictureDecode config; HRESULT hr; int surface_alignment; int ret; hr = IDirectXVideoDecoderService_GetDecoderDeviceGuids(ctx->decoder_service, &guid_count, &guid_list); if (FAILED(hr)) { MP_ERR(ctx, "Failed to retrieve decoder device GUIDs\n"); goto fail; } // dump all decoder info MP_VERBOSE(ctx, "%d decoder devices:\n", (int)guid_count); for (j = 0; j < guid_count; j++) { GUID *guid = &guid_list[j]; const char *name = "<unknown>"; for (i = 0; dxva2_modes[i].guid; i++) { if (IsEqualGUID(dxva2_modes[i].guid, guid)) name = dxva2_modes[i].name; } D3DFORMAT *target_list = NULL; unsigned target_count = 0; hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx->decoder_service, guid, &target_count, &target_list); if (FAILED(hr)) continue; char fmts[256] = {0}; for (i = 0; i < target_count; i++) mp_snprintf_cat(fmts, sizeof(fmts), " %s", mp_tag_str(target_list[i])); CoTaskMemFree(target_list); MP_VERBOSE(ctx, "%s %s %s\n", mp_GUID_to_str(guid), name, fmts); } // find a suitable decoder for (i = 0; dxva2_modes[i].guid; i++) { D3DFORMAT *target_list = NULL; unsigned target_count = 0; const dxva2_mode *mode = &dxva2_modes[i]; if (mode->codec != codec_id) continue; for (j = 0; j < guid_count; j++) { if (IsEqualGUID(mode->guid, &guid_list[j])) break; } if (j == guid_count) continue; hr = IDirectXVideoDecoderService_GetDecoderRenderTargets(ctx->decoder_service, mode->guid, &target_count, &target_list); if (FAILED(hr)) { continue; } for (j = 0; j < target_count; j++) { const D3DFORMAT format = target_list[j]; if (format == MKTAG('N','V','1','2')) { target_format = format; break; } } CoTaskMemFree(target_list); if (target_format) { device_guid = *mode->guid; break; } } CoTaskMemFree(guid_list); if (IsEqualGUID(&device_guid, &GUID_NULL)) { MP_ERR(ctx, "No decoder device for codec found\n"); goto fail; } desc.SampleWidth = w; desc.SampleHeight = h; desc.Format = target_format; ret = dxva2_get_decoder_configuration(s, codec_id, &device_guid, &desc, &config); if (ret < 0) { goto fail; } /* decoding MPEG-2 requires additional alignment on some Intel GPUs, but it causes issues for H.264 on certain AMD GPUs..... */ if (codec_id == AV_CODEC_ID_MPEG2VIDEO) surface_alignment = 32; /* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure all coding features have enough room to work with */ else if (codec_id == AV_CODEC_ID_HEVC) surface_alignment = 128; else surface_alignment = 16; /* 4 base work surfaces */ ctx->num_surfaces = 4 + ADDTIONAL_SURFACES; /* add surfaces based on number of possible refs */ if (codec_id == AV_CODEC_ID_H264 || codec_id == AV_CODEC_ID_HEVC) ctx->num_surfaces += 16; else ctx->num_surfaces += 2; ctx->surfaces = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surfaces)); ctx->surface_infos = av_mallocz(ctx->num_surfaces * sizeof(*ctx->surface_infos)); if (!ctx->surfaces || !ctx->surface_infos) { MP_ERR(ctx, "Unable to allocate surface arrays\n"); goto fail; } hr = IDirectXVideoDecoderService_CreateSurface(ctx->decoder_service, FFALIGN(w, surface_alignment), FFALIGN(h, surface_alignment), ctx->num_surfaces - 1, target_format, D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget, ctx->surfaces, NULL); if (FAILED(hr)) { MP_ERR(ctx, "Failed to create %d video surfaces\n", ctx->num_surfaces); goto fail; } hr = IDirectXVideoDecoderService_CreateVideoDecoder(ctx->decoder_service, &device_guid, &desc, &config, ctx->surfaces, ctx->num_surfaces, &ctx->decoder); if (FAILED(hr)) { MP_ERR(ctx, "Failed to create DXVA2 video decoder\n"); goto fail; } ctx->decoder_guid = device_guid; ctx->decoder_config = config; dxva_ctx->cfg = &ctx->decoder_config; dxva_ctx->decoder = ctx->decoder; dxva_ctx->surface = ctx->surfaces; dxva_ctx->surface_count = ctx->num_surfaces; if (IsEqualGUID(&ctx->decoder_guid, &DXVADDI_Intel_ModeH264_E)) dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO; return 0; fail: dxva2_destroy_decoder(s); return -1; }
static int map_image(struct gl_hwdec *hw, struct mp_image *hw_image, GLuint *out_textures) { struct priv *p = hw->priv; GL *gl = hw->gl; VAStatus status; VAImage *va_image = &p->current_image; unref_image(hw); mp_image_setrefp(&p->current_ref, hw_image); va_lock(p->ctx); status = vaDeriveImage(p->display, va_surface_id(hw_image), va_image); if (!CHECK_VA_STATUS(p, "vaDeriveImage()")) goto err; int mpfmt = va_fourcc_to_imgfmt(va_image->format.fourcc); if (mpfmt != IMGFMT_NV12 && mpfmt != IMGFMT_420P) { MP_FATAL(p, "unsupported VA image format %s\n", mp_tag_str(va_image->format.fourcc)); goto err; } if (!hw->converted_imgfmt) { MP_VERBOSE(p, "format: %s %s\n", mp_tag_str(va_image->format.fourcc), mp_imgfmt_to_name(mpfmt)); hw->converted_imgfmt = mpfmt; } if (hw->converted_imgfmt != mpfmt) { MP_FATAL(p, "mid-stream hwdec format change (%s -> %s) not supported\n", mp_imgfmt_to_name(hw->converted_imgfmt), mp_imgfmt_to_name(mpfmt)); goto err; } VABufferInfo buffer_info = {.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME}; status = vaAcquireBufferHandle(p->display, va_image->buf, &buffer_info); if (!CHECK_VA_STATUS(p, "vaAcquireBufferHandle()")) goto err; p->buffer_acquired = true; struct mp_image layout = {0}; mp_image_set_params(&layout, &hw_image->params); mp_image_setfmt(&layout, mpfmt); // (it would be nice if we could use EGL_IMAGE_INTERNAL_FORMAT_EXT) int drm_fmts[4] = {MP_FOURCC('R', '8', ' ', ' '), // DRM_FORMAT_R8 MP_FOURCC('G', 'R', '8', '8'), // DRM_FORMAT_GR88 MP_FOURCC('R', 'G', '2', '4'), // DRM_FORMAT_RGB888 MP_FOURCC('R', 'A', '2', '4')}; // DRM_FORMAT_RGBA8888 for (int n = 0; n < layout.num_planes; n++) { int attribs[20] = {EGL_NONE}; int num_attribs = 0; ADD_ATTRIB(EGL_LINUX_DRM_FOURCC_EXT, drm_fmts[layout.fmt.bytes[n] - 1]); ADD_ATTRIB(EGL_WIDTH, mp_image_plane_w(&layout, n)); ADD_ATTRIB(EGL_HEIGHT, mp_image_plane_h(&layout, n)); ADD_ATTRIB(EGL_DMA_BUF_PLANE0_FD_EXT, buffer_info.handle); ADD_ATTRIB(EGL_DMA_BUF_PLANE0_OFFSET_EXT, va_image->offsets[n]); ADD_ATTRIB(EGL_DMA_BUF_PLANE0_PITCH_EXT, va_image->pitches[n]); p->images[n] = p->CreateImageKHR(eglGetCurrentDisplay(), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs); if (!p->images[n]) goto err; gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[n]); p->EGLImageTargetTexture2DOES(GL_TEXTURE_2D, p->images[n]); out_textures[n] = p->gl_textures[n]; } gl->BindTexture(GL_TEXTURE_2D, 0); if (va_image->format.fourcc == VA_FOURCC_YV12) MPSWAP(GLuint, out_textures[1], out_textures[2]); va_unlock(p->ctx); return 0; err: va_unlock(p->ctx); MP_FATAL(p, "mapping VAAPI EGL image failed\n"); unref_image(hw); return -1; }