VideoFormat::PixelFormat pixelFormatFromFourcc(int format) { const d3d_format_t *fmt = D3dFindFormat(format); if (fmt) return fmt->pixfmt; return VideoFormat::Format_Invalid; }
// hwaccel_context bool VideoDecoderDXVAPrivate::setup(void **hwctx, AVPixelFormat *chroma, int w, int h) { if (w <= 0 || h <= 0) return false; if (!decoder || ((width != w || height != h) && (surface_width != FFALIGN(w, 16) || surface_height != FFALIGN(h, 16))//) )) { DxDestroyVideoConversion(); DxDestroyVideoDecoder(); *hwctx = NULL; *chroma = QTAV_PIX_FMT_C(NONE); /* FIXME transmit a video_format_t by VaSetup directly */ if (!DxCreateVideoDecoder(codec_ctx->codec_id, w, h)) return false; hw.decoder = decoder; hw.cfg = &cfg; hw.surface_count = surface_count; hw.surface = hw_surfaces; memset(hw_surfaces, 0, sizeof(hw_surfaces)); for (unsigned i = 0; i < surface_count; i++) hw.surface[i] = surfaces[i].d3d; DxCreateVideoConversion(); } *hwctx = &hw; const d3d_format_t *outfmt = D3dFindFormat(output); *chroma = outfmt ? outfmt->codec : QTAV_PIX_FMT_C(NONE); return true; }
VideoFrame VideoDecoderDXVA::frame() { DPTR_D(VideoDecoderDXVA); if (!d.frame->opaque || !d.frame->data[0]) return VideoFrame(); if (d.width <= 0 || d.height <= 0 || !d.codec_ctx) return VideoFrame(); class ScopedD3DLock { public: ScopedD3DLock(IDirect3DSurface9* d3d, D3DLOCKED_RECT *rect) : mpD3D(d3d) { if (FAILED(mpD3D->LockRect(rect, NULL, D3DLOCK_READONLY))) { qWarning("Failed to lock surface"); mpD3D = 0; } } ~ScopedD3DLock() { if (mpD3D) mpD3D->UnlockRect(); } private: IDirect3DSurface9 *mpD3D; }; IDirect3DSurface9 *d3d = (IDirect3DSurface9*)(uintptr_t)d.frame->data[3]; //picth >= desc.Width //D3DSURFACE_DESC desc; //d3d->GetDesc(&desc); D3DLOCKED_RECT lock; ScopedD3DLock(d3d, &lock); if (lock.Pitch == 0) { return VideoFrame(); } const VideoFormat fmt = VideoFormat((int)D3dFindFormat(d.render)->avpixfmt); if (!fmt.isValid()) { qWarning("unsupported dxva pixel format: %#x", d.render); return VideoFrame(); } //YV12 need swap, not imc3? // imc3 U V pitch == Y pitch, but half of the U/V plane is space. we convert to yuv420p here // nv12 bpp(1)==1 // 3rd plane is not used for nv12 int pitch[3] = { lock.Pitch, 0, 0}; //compute chroma later uint8_t *src[] = { (uint8_t*)lock.pBits, 0, 0}; //compute chroma later const bool swap_uv = d.render == MAKEFOURCC('I','M','C','3'); return copyToFrame(fmt, d.surface_height, src, pitch, swap_uv); }
static int DxSetupOutput(vlc_va_t *va, const GUID *input, const video_format_t *fmt) { VLC_UNUSED(fmt); int err = VLC_EGENERIC; UINT output_count = 0; D3DFORMAT *output_list = NULL; if (FAILED(IDirectXVideoDecoderService_GetDecoderRenderTargets(va->sys->dx_sys.d3ddec, input, &output_count, &output_list))) { msg_Err(va, "IDirectXVideoDecoderService_GetDecoderRenderTargets failed"); return VLC_EGENERIC; } for (unsigned j = 0; j < output_count; j++) { const D3DFORMAT f = output_list[j]; const d3d_format_t *format = D3dFindFormat(f); if (format) { msg_Dbg(va, "%s is supported for output", format->name); } else { msg_Dbg(va, "%d is supported for output (%4.4s)", f, (const char*)&f); } } /* */ for (unsigned pass = 0; pass < 2 && err != VLC_SUCCESS; ++pass) { for (unsigned j = 0; d3d_formats[j].name; j++) { const d3d_format_t *format = &d3d_formats[j]; /* */ bool is_supported = false; for (unsigned k = 0; !is_supported && k < output_count; k++) { is_supported = format->format == output_list[k]; } if (!is_supported) continue; if (pass == 0 && format->format != va->sys->render) continue; /* We have our solution */ msg_Dbg(va, "Using decoder output '%s'", format->name); va->sys->render = format->format; err = VLC_SUCCESS; break; } } CoTaskMemFree(output_list); return err; }
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; }
const d3d_format_t* VideoDecoderD3DPrivate::getFormat(const AVCodecContext *avctx, const QVector<GUID> &guids, GUID* selected) const { foreach (const GUID& g, guids) { const dxva2_mode_t *mode = Dxva2FindMode(&g); if (mode) { qDebug("- '%s' is supported by hardware", mode->name); } else { qDebug("- Unknown GUID = %08X-%04x-%04x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x", (unsigned)g.Data1, g.Data2, g.Data3 , g.Data4[0], g.Data4[1] , g.Data4[2], g.Data4[3], g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]); } } /* Try all supported mode by our priority */ const dxva2_mode_t *mode = dxva2_modes; for (; mode->name; ++mode) { if (!mode->codec || mode->codec != avctx->codec_id) { qDebug("codec does not match to %s: %s", avcodec_get_name(avctx->codec_id), avcodec_get_name((AVCodecID)mode->codec)); continue; } qDebug("D3D found codec: %s. Check runtime support for the codec.", mode->name); bool is_supported = false; //TODO: find_if foreach (const GUID& g, guids) { if (IsEqualGUID(*mode->guid, g)) { is_supported = true; break; } } if (is_supported) { qDebug("Check profile support: %s", AVDecoderPrivate::getProfileName(avctx)); is_supported = checkProfile(mode, avctx->profile); } if (!is_supported) continue; int dxfmt = fourccFor(mode->guid); if (!dxfmt) continue; if (selected) *selected = *mode->guid; return D3dFindFormat(dxfmt); } return NULL; }
int getSupportedFourcc(int *formats, UINT nb_formats) { for (const int *f = formats; f < &formats[nb_formats]; ++f) { const d3d_format_t *format = D3dFindFormat(*f); if (format) { qDebug("%s is supported for output", format->name); } else { qDebug("%d is supported for output (%4.4s)", *f, (const char*)f); } } for (const d3d_format_t *format = d3d_formats; format->name; ++format) { bool is_supported = false; for (unsigned k = 0; !is_supported && k < nb_formats; k++) { if (format->fourcc == formats[k]) return format->fourcc; } } return 0; }
static int Setup(vlc_va_t *va, void **hw, vlc_fourcc_t *chroma, int width, int height) { vlc_va_sys_t *sys = va->sys; if (sys->width == width && sys->height == height && sys->decoder) goto ok; /* */ DxDestroyVideoConversion(sys); DxDestroyVideoDecoder(sys); *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, sys->codec_id, &fmt)) return VLC_EGENERIC; /* */ sys->hw.decoder = sys->decoder; sys->hw.cfg = &sys->cfg; sys->hw.surface_count = sys->surface_count; sys->hw.surface = sys->hw_surface; /* */ DxCreateVideoConversion(sys); /* */ ok: *hw = &sys->hw; const d3d_format_t *output = D3dFindFormat(sys->output); *chroma = output->codec; return VLC_SUCCESS; }
/** * Find the best suited decoder mode GUID and render format. */ static int DxFindVideoServiceConversion(vlc_va_dxva2_t *va, GUID *input, D3DFORMAT *output) { /* Retreive supported modes from the decoder service */ UINT input_count = 0; GUID *input_list = NULL; if (FAILED(IDirectXVideoDecoderService_GetDecoderDeviceGuids(va->vs, &input_count, &input_list))) { msg_Err(va->log, "IDirectXVideoDecoderService_GetDecoderDeviceGuids failed"); return VLC_EGENERIC; } for (unsigned i = 0; i < input_count; i++) { const GUID *g = &input_list[i]; const dxva2_mode_t *mode = Dxva2FindMode(g); if (mode) { msg_Dbg(va->log, "- '%s' is supported by hardware", mode->name); } else { msg_Warn(va->log, "- Unknown GUID = %08X-%04x-%04x-XXXX", (unsigned)g->Data1, g->Data2, g->Data3); } } /* Try all supported mode by our priority */ for (unsigned i = 0; dxva2_modes[i].name; i++) { const dxva2_mode_t *mode = &dxva2_modes[i]; if (!mode->codec || mode->codec != va->codec_id) continue; /* */ bool is_suported = false; for (const GUID *g = &input_list[0]; !is_suported && g < &input_list[input_count]; g++) { is_suported = IsEqualGUID(mode->guid, g); } if (!is_suported) continue; /* */ msg_Dbg(va->log, "Trying to use '%s' as input", mode->name); UINT output_count = 0; D3DFORMAT *output_list = NULL; if (FAILED(IDirectXVideoDecoderService_GetDecoderRenderTargets(va->vs, mode->guid, &output_count, &output_list))) { msg_Err(va->log, "IDirectXVideoDecoderService_GetDecoderRenderTargets failed"); continue; } for (unsigned j = 0; j < output_count; j++) { const D3DFORMAT f = output_list[j]; const d3d_format_t *format = D3dFindFormat(f); if (format) { msg_Dbg(va->log, "%s is supported for output", format->name); } else { msg_Dbg(va->log, "%d is supported for output (%4.4s)", f, (const char*)&f); } } /* */ for (unsigned j = 0; d3d_formats[j].name; j++) { const d3d_format_t *format = &d3d_formats[j]; /* */ bool is_suported = false; for (unsigned k = 0; !is_suported && k < output_count; k++) { is_suported = format->format == output_list[k]; } if (!is_suported) continue; /* We have our solution */ msg_Dbg(va->log, "Using '%s' to decode to '%s'", mode->name, format->name); *input = *mode->guid; *output = format->format; CoTaskMemFree(output_list); CoTaskMemFree(input_list); return VLC_SUCCESS; } CoTaskMemFree(output_list); } CoTaskMemFree(input_list); return VLC_EGENERIC; }
/** * Find the best suited decoder mode GUID and render format. */ bool VideoDecoderDXVAPrivate::DxFindVideoServiceConversion(GUID *input, D3DFORMAT *output) { /* Retreive supported modes from the decoder service */ UINT input_count = 0; GUID *input_list = NULL; if (FAILED(vs->GetDecoderDeviceGuids(&input_count, &input_list))) { qWarning("IDirectXVideoDecoderService_GetDecoderDeviceGuids failed"); return false; } for (unsigned i = 0; i < input_count; i++) { const GUID &g = input_list[i]; const dxva2_mode_t *mode = Dxva2FindMode(&g); if (mode) { qDebug("- '%s' is supported by hardware", mode->name); } else { qWarning("- Unknown GUID = %08X-%04x-%04x-XXXX", (unsigned)g.Data1, g.Data2, g.Data3); } } /* Try all supported mode by our priority */ for (unsigned i = 0; dxva2_modes[i].name; i++) { const dxva2_mode_t *mode = &dxva2_modes[i]; if (!mode->codec || mode->codec != codec_ctx->codec_id) continue; bool is_suported = false; for (unsigned count = 0; !is_suported && count < input_count; count++) { const GUID &g = input_list[count]; is_suported = IsEqualGUID(*mode->guid, g); /// } if (!is_suported) continue; qDebug("Trying to use '%s' as input", mode->name); UINT output_count = 0; D3DFORMAT *output_list = NULL; if (FAILED(vs->GetDecoderRenderTargets(*mode->guid, &output_count, &output_list))) { qWarning("IDirectXVideoDecoderService_GetDecoderRenderTargets failed"); continue; } for (unsigned j = 0; j < output_count; j++) { const D3DFORMAT f = output_list[j]; const d3d_format_t *format = D3dFindFormat(f); if (format) { qDebug("%s is supported for output", format->name); } else { qDebug("%d is supported for output (%4.4s)", f, (const char*)&f); } } for (unsigned j = 0; d3d_formats[j].name; j++) { const d3d_format_t *format = &d3d_formats[j]; bool is_suported = false; for (unsigned k = 0; !is_suported && k < output_count; k++) { is_suported = format->format == output_list[k]; } if (!is_suported) continue; /* We have our solution */ qDebug("Using '%s' to decode to '%s'", mode->name, format->name); *input = *mode->guid; *output = format->format; CoTaskMemFree(output_list); CoTaskMemFree(input_list); return true; } CoTaskMemFree(output_list); } CoTaskMemFree(input_list); return false; }
/** * Find the best suited decoder mode GUID and render format. */ bool VideoDecoderDXVAPrivate::DxFindVideoServiceConversion(GUID *input, D3DFORMAT *output) { /* Retreive supported modes from the decoder service */ UINT input_count = 0; GUID *input_list = NULL; DX_ENSURE_OK(vs->GetDecoderDeviceGuids(&input_count, &input_list), false); for (unsigned i = 0; i < input_count; i++) { const GUID &g = input_list[i]; const dxva2_mode_t *mode = Dxva2FindMode(&g); if (mode) { qDebug("- '%s' is supported by hardware", mode->name); } else { qDebug("- Unknown GUID = %08X-%04x-%04x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x", (unsigned)g.Data1, g.Data2, g.Data3 , g.Data4[0], g.Data4[1] , g.Data4[2], g.Data4[3], g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]); } } /* Try all supported mode by our priority */ const dxva2_mode_t *mode = dxva2_modes; for (; mode->name; ++mode) { if (!mode->codec || mode->codec != codec_ctx->codec_id) { qDebug("codec does not match to %s: %s", avcodec_get_name(codec_ctx->codec_id), avcodec_get_name((AVCodecID)mode->codec)); continue; } qDebug("DXVA found codec: %s. Check runtime support for the codec.", mode->name); bool is_supported = false; for (const GUID *g = &input_list[0]; !is_supported && g < &input_list[input_count]; g++) { is_supported = IsEqualGUID(*mode->guid, *g); } if (is_supported) { qDebug("Check profile support: %s", AVDecoderPrivate::getProfileName(codec_ctx)); is_supported = !mode->profiles || !mode->profiles[0] || codec_ctx->profile <= 0; if (!is_supported) { for (const int *profile = &mode->profiles[0]; *profile; ++profile) { if (*profile == codec_ctx->profile) { is_supported = true; break; } } } } if (!is_supported) continue; UINT output_count = 0; D3DFORMAT *output_list = NULL; if (FAILED(vs->GetDecoderRenderTargets(*mode->guid, &output_count, &output_list))) { qWarning("IDirectXVideoDecoderService_GetDecoderRenderTargets failed"); continue; } qDebug("supprted output count: %d", output_count); for (const D3DFORMAT *f = output_list; f < &output_list[output_count]; ++f) { const d3d_format_t *format = D3dFindFormat(*f); if (format) { qDebug("%s is supported for output", format->name); } else { qDebug("%d is supported for output (%4.4s)", *f, (const char*)f); } } for (const d3d_format_t *format = d3d_formats; format->name; ++format) { bool is_supported = false; for (unsigned k = 0; !is_supported && k < output_count; k++) { is_supported = format->format == output_list[k]; } if (!is_supported) continue; /* We have our solution */ qDebug("Using '%s' to decode to '%s'", mode->name, format->name); *input = *mode->guid; *output = format->format; CoTaskMemFree(output_list); CoTaskMemFree(input_list); return true; } CoTaskMemFree(output_list); } CoTaskMemFree(input_list); return false; }
/** * Find the best suited decoder mode GUID and render format. */ bool VideoDecoderDXVAPrivate::DxFindVideoServiceConversion(GUID *input, D3DFORMAT *output) { /* Retreive supported modes from the decoder service */ UINT input_count = 0; GUID *input_list = NULL; DX_ENSURE_OK(vs->GetDecoderDeviceGuids(&input_count, &input_list), false); for (unsigned i = 0; i < input_count; i++) { const GUID &g = input_list[i]; const dxva2_mode_t *mode = Dxva2FindMode(&g); if (mode) { qDebug("- '%s' is supported by hardware", mode->name); } else { qDebug("- Unknown GUID = %08X-%04x-%04x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x", (unsigned)g.Data1, g.Data2, g.Data3 , g->Data4[0], g->Data4[1] , g->Data4[2], g->Data4[3], g->Data4[4], g->Data4[5], g->Data4[6], g->Data4[7]); } } /* Try all supported mode by our priority */ for (unsigned i = 0; dxva2_modes[i].name; i++) { const dxva2_mode_t *mode = &dxva2_modes[i]; if (!mode->codec || mode->codec != codec_ctx->codec_id) { qDebug("codec does not match to %s: %s", avcodec_get_name(codec_ctx->codec_id), avcodec_get_name((AVCodecID)mode->codec)); continue; } if (codec_ctx->profile == FF_PROFILE_HEVC_MAIN_10 && !IsEqualGUID(*mode->guid, DXVA_ModeHEVC_VLD_Main10)) { qDebug("profile (%s) does not match to HEVC 10-bit", mode->name); continue; } qDebug("DXVA found codec: %s. Check support for the codec.", mode->name); bool is_suported = false; for (unsigned count = 0; !is_suported && count < input_count; count++) { const GUID &g = input_list[count]; is_suported = IsEqualGUID(*mode->guid, g); /// } if (!is_suported) continue; UINT output_count = 0; D3DFORMAT *output_list = NULL; if (FAILED(vs->GetDecoderRenderTargets(*mode->guid, &output_count, &output_list))) { qWarning("IDirectXVideoDecoderService_GetDecoderRenderTargets failed"); continue; } qDebug("supprted output count: %d", output_count); for (unsigned j = 0; j < output_count; j++) { const D3DFORMAT f = output_list[j]; const d3d_format_t *format = D3dFindFormat(f); if (format) { qDebug("%s is supported for output", format->name); } else { qDebug("%d is supported for output (%4.4s)", f, (const char*)&f); } } for (unsigned j = 0; d3d_formats[j].name; j++) { const d3d_format_t *format = &d3d_formats[j]; bool is_suported = false; for (unsigned k = 0; !is_suported && k < output_count; k++) { is_suported = format->format == output_list[k]; } if (!is_suported) continue; /* We have our solution */ qDebug("Using '%s' to decode to '%s'", mode->name, format->name); *input = *mode->guid; *output = format->format; CoTaskMemFree(output_list); CoTaskMemFree(input_list); return true; } CoTaskMemFree(output_list); } CoTaskMemFree(input_list); return false; }