static void Release(vlc_va_t *external, AVFrame *ff) { vlc_va_dxva2_t *va = vlc_va_dxva2_Get(external); LPDIRECT3DSURFACE9 d3d = (LPDIRECT3DSURFACE9)(uintptr_t)ff->data[3]; for (unsigned i = 0; i < va->surface_count; i++) { vlc_va_surface_t *surface = &va->surface[i]; if (surface->d3d == d3d) surface->refcount--; } }
static void Close(vlc_va_t *external) { vlc_va_dxva2_t *va = vlc_va_dxva2_Get(external); DxDestroyVideoConversion(va); DxDestroyVideoDecoder(va); DxDestroyVideoService(va); D3dDestroyDeviceManager(va); D3dDestroyDevice(va); if (va->hdxva2_dll) FreeLibrary(va->hdxva2_dll); if (va->hd3d9_dll) FreeLibrary(va->hd3d9_dll); free(external->description); free(va); }
/* FIXME it is nearly common with VAAPI */ static int Get(vlc_va_t *external, AVFrame *ff) { vlc_va_dxva2_t *va = vlc_va_dxva2_Get(external); /* Check the device */ HRESULT hr = IDirect3DDeviceManager9_TestDevice(va->devmng, va->device); if (hr == DXVA2_E_NEW_VIDEO_DEVICE) { if (DxResetVideoDecoder(va)) return VLC_EGENERIC; } else if (FAILED(hr)) { msg_Err(va->log, "IDirect3DDeviceManager9_TestDevice %u", (unsigned)hr); return VLC_EGENERIC; } /* Grab an unused surface, in case none are, try the oldest * XXX using the oldest is a workaround in case a problem happens with libavcodec */ unsigned i, old; for (i = 0, old = 0; i < va->surface_count; i++) { vlc_va_surface_t *surface = &va->surface[i]; if (!surface->refcount) break; if (surface->order < va->surface[old].order) old = i; } if (i >= va->surface_count) i = old; vlc_va_surface_t *surface = &va->surface[i]; surface->refcount = 1; surface->order = va->surface_order++; /* */ for (int i = 0; i < 4; i++) { ff->data[i] = NULL; ff->linesize[i] = 0; if (i == 0 || i == 3) ff->data[i] = (void*)surface->d3d;/* Yummie */ } return VLC_SUCCESS; }
static int Setup(vlc_va_t *external, void **hw, vlc_fourcc_t *chroma, int width, int height) { vlc_va_dxva2_t *va = vlc_va_dxva2_Get(external); if (va->width == width && va->height == height && va->decoder) goto ok; /* */ DxDestroyVideoConversion(va); DxDestroyVideoDecoder(va); *hw = NULL; *chroma = 0; if (width <= 0 || height <= 0) return VLC_EGENERIC; /* FIXME transmit a video_format_t by VaSetup directly */ video_format_t fmt; memset(&fmt, 0, sizeof(fmt)); fmt.i_width = width; fmt.i_height = height; if (DxCreateVideoDecoder(va, va->codec_id, &fmt)) return VLC_EGENERIC; /* */ va->hw.decoder = va->decoder; va->hw.cfg = &va->cfg; va->hw.surface_count = va->surface_count; va->hw.surface = va->hw_surface; for (unsigned i = 0; i < va->surface_count; i++) va->hw.surface[i] = va->surface[i].d3d; /* */ DxCreateVideoConversion(va); /* */ ok: *hw = &va->hw; const d3d_format_t *output = D3dFindFormat(va->output); *chroma = output->codec; return VLC_SUCCESS; }
static int Extract(vlc_va_t *external, picture_t *picture, AVFrame *ff) { vlc_va_dxva2_t *va = vlc_va_dxva2_Get(external); LPDIRECT3DSURFACE9 d3d = (LPDIRECT3DSURFACE9)(uintptr_t)ff->data[3]; if (!va->surface_cache.buffer) return VLC_EGENERIC; /* */ assert(va->output == MAKEFOURCC('Y','V','1','2')); /* */ D3DLOCKED_RECT lock; if (FAILED(IDirect3DSurface9_LockRect(d3d, &lock, NULL, D3DLOCK_READONLY))) { msg_Err(va->log, "Failed to lock surface"); return VLC_EGENERIC; } if (va->render == MAKEFOURCC('Y','V','1','2') || va->render == MAKEFOURCC('I','M','C','3')) { bool imc3 = va->render == MAKEFOURCC('I','M','C','3'); size_t chroma_pitch = imc3 ? lock.Pitch : (lock.Pitch / 2); size_t pitch[3] = { lock.Pitch, chroma_pitch, chroma_pitch, }; uint8_t *plane[3] = { (uint8_t*)lock.pBits, (uint8_t*)lock.pBits + pitch[0] * va->surface_height, (uint8_t*)lock.pBits + pitch[0] * va->surface_height + pitch[1] * va->surface_height / 2, }; if (imc3) { uint8_t *V = plane[1]; plane[1] = plane[2]; plane[2] = V; } CopyFromYv12(picture, plane, pitch, va->width, va->height, &va->surface_cache); } else { assert(va->render == MAKEFOURCC('N','V','1','2')); uint8_t *plane[2] = { lock.pBits, (uint8_t*)lock.pBits + lock.Pitch * va->surface_height }; size_t pitch[2] = { lock.Pitch, lock.Pitch, }; CopyFromNv12(picture, plane, pitch, va->width, va->height, &va->surface_cache); } /* */ IDirect3DSurface9_UnlockRect(d3d); return VLC_SUCCESS; }