Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  interop_dxva2.c   Sprache: C

 

/*****************************************************************************
 * direct3d9.c: Windows Direct3D9 video output module
 *****************************************************************************
 * Copyright (C) 2006-2014 VLC authors and VideoLAN
 *
 * Authors: Martell Malone <martellmalone@gmail.com>,
 *          Damien Fouilleul <damienf@videolan.org>,
 *          Sasha Koruga <skoruga@gmail.com>,
 *          Felix Abecassis <felix.abecassis@gmail.com>
 *
 * This program 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.
 *
 * This program 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 this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


/*****************************************************************************
 * Preamble:
 *
 * This plugin will use YUV surface if supported, using YUV will result in
 * the best video quality (hardware filtering when rescaling the picture)
 * and the fastest display as it requires less processing.
 *
 * If YUV overlay is not supported this plugin will use RGB offscreen video
 * surfaces that will be blitted onto the primary surface (display) to
 * effectively display the pictures.
 *
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_vout_display.h>

#include <windows.h>
#include <d3d9.h>
#include "../../video_chroma/d3d9_fmt.h"
#include <dxvahd.h>

#include "../opengl/interop.h"
#include "../opengl/renderer.h"
#include <GL/glew.h>
#include <GL/wglew.h>

struct wgl_vt {
    PFNWGLGETEXTENSIONSSTRINGEXTPROC     GetExtensionsStringEXT;
    PFNWGLGETEXTENSIONSSTRINGARBPROC     GetExtensionsStringARB;
    PFNWGLDXSETRESOURCESHAREHANDLENVPROC DXSetResourceShareHandleNV;
    PFNWGLDXOPENDEVICENVPROC             DXOpenDeviceNV;
    PFNWGLDXCLOSEDEVICENVPROC            DXCloseDeviceNV;
    PFNWGLDXREGISTEROBJECTNVPROC         DXRegisterObjectNV;
    PFNWGLDXUNREGISTEROBJECTNVPROC       DXUnregisterObjectNV;
    PFNWGLDXLOCKOBJECTSNVPROC            DXLockObjectsNV;
    PFNWGLDXUNLOCKOBJECTSNVPROC          DXUnlockObjectsNV;
};
struct glpriv
{
    struct wgl_vt vt;
    HANDLE gl_handle_d3d;
    HANDLE gl_render;
    IDirect3DSurface9 *dx_render;

    D3DFORMAT OutputFormat;

    /* range converter */
    struct {
        IDXVAHD_VideoProcessor *proc;
    } processor;
};

static int
GLConvUpdate(const struct vlc_gl_interop *interop, uint32_t textures[],
             const int32_t tex_width[], const int32_t tex_height[],
             picture_t *pic, const size_t *plane_offset)
{
    VLC_UNUSED(textures); VLC_UNUSED(tex_width); VLC_UNUSED(tex_height); VLC_UNUSED(plane_offset);
    struct glpriv *priv = interop->priv;
    HRESULT hr;

    picture_sys_d3d9_t *picsys = ActiveD3D9PictureSys(pic);
    if (unlikely(!picsys || !priv->gl_render))
        return VLC_EGENERIC;

    if (!priv->vt.DXUnlockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render))
    {
        msg_Warn(interop->gl, "DXUnlockObjectsNV failed");
        return VLC_EGENERIC;
    }

    d3d9_decoder_device_t *d3d9_decoder = GetD3D9OpaqueContext(interop->vctx);

    if (priv->processor.proc)
    {
        DXVAHD_STREAM_DATA inputStream = { 0 };
        inputStream.Enable = TRUE;
        inputStream.pInputSurface = picsys->surface;
        hr = IDXVAHD_VideoProcessor_VideoProcessBltHD( priv->processor.proc, priv->dx_render, 0, 1, &inputStream );
        if (FAILED(hr)) {
            D3DSURFACE_DESC srcDesc, dstDesc;
            IDirect3DSurface9_GetDesc(picsys->surface, &srcDesc);
            IDirect3DSurface9_GetDesc(priv->dx_render, &dstDesc);

            msg_Dbg(interop->gl, "Failed VideoProcessBltHD src:%4.4s (%d) dst:%4.4s (%d) (hr=0x%lX)",
                    (const char*)&srcDesc.Format, srcDesc.Format,
                    (const char*)&dstDesc.Format, dstDesc.Format, hr);
            return VLC_EGENERIC;
        }

        hr = IDirect3DDevice9Ex_PresentEx(d3d9_decoder->d3ddev.devex, NULL, NULL, NULL, NULL, D3DPRESENT_INTERVAL_IMMEDIATE);
        if (FAILED(hr))
        {
            msg_Warn(interop->gl, "IDirect3DDevice9_Present failed. (0x%lX)", hr);
            return VLC_EGENERIC;
        }
    }
    else
    {
        const RECT rect = {
            .left = 0,
            .top = 0,
            .right = pic->format.i_visible_width,
            .bottom = pic->format.i_visible_height
        };
        hr = IDirect3DDevice9Ex_StretchRect(d3d9_decoder->d3ddev.devex, picsys->surface,
                                            &rect, priv->dx_render, NULL, D3DTEXF_NONE);
        if (FAILED(hr))
        {
            msg_Warn(interop->gl, "IDirect3DDevice9Ex_StretchRect failed. (0x%lX)", hr);
            return VLC_EGENERIC;
        }
    }

    if (!priv->vt.DXLockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render))
    {
        msg_Warn(interop->gl, "DXLockObjectsNV failed");
        priv->vt.DXUnregisterObjectNV(priv->gl_handle_d3d, priv->gl_render);
        priv->gl_render = NULL;
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}

static int
GLConvAllocateTextures(const struct vlc_gl_interop *interop, uint32_t textures[],
                       const int32_t tex_width[], const int32_t tex_height[])
{
    VLC_UNUSED(tex_width); VLC_UNUSED(tex_height);
    struct glpriv *priv = interop->priv;

    priv->gl_render =
        priv->vt.DXRegisterObjectNV(priv->gl_handle_d3d, priv->dx_render,
                                    textures[0], GL_TEXTURE_2D, WGL_ACCESS_WRITE_DISCARD_NV);
    if (!priv->gl_render)
    {
        msg_Warn(interop->gl, "DXRegisterObjectNV failed: %lu", GetLastError());
        return VLC_EGENERIC;
    }

    if (!priv->vt.DXLockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render))
    {
        msg_Warn(interop->gl, "DXLockObjectsNV failed");
        priv->vt.DXUnregisterObjectNV(priv->gl_handle_d3d, priv->gl_render);
        priv->gl_render = NULL;
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}

static void
GLConvDeallocateTextures(const struct vlc_gl_interop *interop, uint32_t textures[])
{
    (void)textures;
    struct glpriv *priv = interop->priv;

    if (priv->gl_handle_d3d && priv->gl_render)
    {
        priv->vt.DXUnlockObjectsNV(priv->gl_handle_d3d, 1, &priv->gl_render);
        priv->vt.DXUnregisterObjectNV(priv->gl_handle_d3d, priv->gl_render);
        priv->gl_render = NULL;
    }
}

static void
GLConvClose(struct vlc_gl_interop *interop)
{
    struct glpriv *priv = interop->priv;

    if (priv->gl_handle_d3d)
    {
        priv->vt.DXCloseDeviceNV(priv->gl_handle_d3d);
    }
    if (priv->processor.proc)
    {
        IDXVAHD_VideoProcessor_Release(priv->processor.proc);
    }

    if (priv->dx_render)
        IDirect3DSurface9_Release(priv->dx_render);

    free(priv);
}

static void SetupProcessorInput(struct vlc_gl_interop *interop, const video_format_t *fmt, D3DFORMAT src_format)
{
    struct glpriv *sys = interop->priv;
    DXVAHD_STREAM_STATE_D3DFORMAT_DATA d3dformat = { src_format };
    IDXVAHD_VideoProcessor_SetVideoProcessStreamState( sys->processor.proc, 0, DXVAHD_STREAM_STATE_D3DFORMAT, sizeof(d3dformat), &d3dformat );

    DXVAHD_STREAM_STATE_FRAME_FORMAT_DATA frame_format = { DXVAHD_FRAME_FORMAT_PROGRESSIVE };
    IDXVAHD_VideoProcessor_SetVideoProcessStreamState( sys->processor.proc, 0, DXVAHD_STREAM_STATE_FRAME_FORMAT, sizeof(frame_format), &frame_format );

    DXVAHD_STREAM_STATE_INPUT_COLOR_SPACE_DATA colorspace = {
        .Type = 0, // video, not graphics
        .RGB_Range = fmt->color_range == COLOR_RANGE_FULL ? 0 : 1,
        .YCbCr_xvYCC = fmt->color_range == COLOR_RANGE_FULL ? 1 : 0,
        .YCbCr_Matrix = fmt->space == COLOR_SPACE_BT601 ? 0 : 1,
    };
    IDXVAHD_VideoProcessor_SetVideoProcessStreamState( sys->processor.proc, 0, DXVAHD_STREAM_STATE_INPUT_COLOR_SPACE, sizeof(colorspace), &colorspace );

    DXVAHD_STREAM_STATE_SOURCE_RECT_DATA srcRect;
    srcRect.Enable = TRUE;
    srcRect.SourceRect = (RECT) {
        .left   = interop->fmt_in.i_x_offset,
        .right  = interop->fmt_in.i_x_offset + interop->fmt_in.i_visible_width,
        .top    = interop->fmt_in.i_y_offset,
        .bottom = interop->fmt_in.i_y_offset + interop->fmt_in.i_visible_height,
    };
    IDXVAHD_VideoProcessor_SetVideoProcessStreamState( sys->processor.proc, 0, DXVAHD_STREAM_STATE_SOURCE_RECT, sizeof(srcRect), &srcRect );

    DXVAHD_BLT_STATE_TARGET_RECT_DATA dstRect;
    dstRect.Enable = TRUE;
    dstRect.TargetRect = (RECT) {
        .left   = 0,
        .right  = interop->fmt_in.i_visible_width,
        .top    = 0,
        .bottom = interop->fmt_in.i_visible_height,
    };
    IDXVAHD_VideoProcessor_SetVideoProcessBltState( sys->processor.proc, DXVAHD_BLT_STATE_TARGET_RECT, sizeof(dstRect), &dstRect);
}

static void GetFrameRate(DXVAHD_RATIONAL *r, const video_format_t *fmt)
{
    if (fmt->i_frame_rate && fmt->i_frame_rate_base)
    {
        r->Numerator   = fmt->i_frame_rate;
        r->Denominator = fmt->i_frame_rate_base;
    }
    else
    {
        r->Numerator   = 0;
        r->Denominator = 0;
    }
}

static int InitRangeProcessor(struct vlc_gl_interop *interop, IDirect3DDevice9Ex *devex, D3DFORMAT src_format)
{
    struct glpriv *sys = interop->priv;

    HRESULT hr;

    D3DFORMAT *formatsList = NULL;
    DXVAHD_VPCAPS *capsList = NULL;
    IDXVAHD_Device *hd_device = NULL;

    DXVAHD_CONTENT_DESC desc;
    desc.InputFrameFormat = DXVAHD_FRAME_FORMAT_PROGRESSIVE;
    GetFrameRate( &desc.InputFrameRate, &interop->fmt_in );
    desc.InputWidth       = interop->fmt_in.i_visible_width;
    desc.InputHeight      = interop->fmt_in.i_visible_height;
    desc.OutputFrameRate  = desc.InputFrameRate;
    desc.OutputWidth      = interop->fmt_in.i_visible_width;
    desc.OutputHeight     = interop->fmt_in.i_visible_height;

    hr = DXVAHD_CreateDevice(devex, &desc, DXVAHD_DEVICE_USAGE_PLAYBACK_NORMAL, NULL, &hd_device);
    if (FAILED(hr))
    {
        msg_Dbg(interop, "Failed to create the device (error 0x%lX)", hr);
        goto error;
    }

    DXVAHD_VPDEVCAPS devcaps = { 0 };
    hr = IDXVAHD_Device_GetVideoProcessorDeviceCaps( hd_device, &devcaps );
    if (unlikely(FAILED(hr)))
    {
        msg_Err(interop, "Failed to get the device capabilities (error 0x%lX)", hr);
        goto error;
    }
    if (devcaps.VideoProcessorCount == 0)
    {
        msg_Warn(interop, "No good video processor found for range conversion");
        goto error;
    }

    formatsList = vlc_alloc(devcaps.InputFormatCount, sizeof(*formatsList));
    if (unlikely(formatsList == NULL))
    {
        msg_Dbg(interop, "Failed to allocate %u input formats", devcaps.InputFormatCount);
        goto error;
    }

    hr = IDXVAHD_Device_GetVideoProcessorInputFormats( hd_device, devcaps.InputFormatCount, formatsList);
    UINT i;
    for (i=0; i<devcaps.InputFormatCount; i++)
    {
        if (formatsList[i] == src_format)
            break;
    }
    if (i == devcaps.InputFormatCount)
    {
        msg_Warn(interop, "Input format %4.4s not supported for range conversion", (const char*)&src_format);
        goto error;
    }

    free(formatsList);
    formatsList = vlc_alloc(devcaps.OutputFormatCount, sizeof(*formatsList));
    if (unlikely(formatsList == NULL))
    {
        msg_Dbg(interop, "Failed to allocate %u output formats", devcaps.OutputFormatCount);
        goto error;
    }

    hr = IDXVAHD_Device_GetVideoProcessorOutputFormats( hd_device, devcaps.OutputFormatCount, formatsList);
    for (i=0; i<devcaps.OutputFormatCount; i++)
    {
        if (formatsList[i] == sys->OutputFormat)
            break;
    }
    if (i == devcaps.OutputFormatCount)
    {
        msg_Warn(interop, "Output format %d not supported for range conversion", sys->OutputFormat);
        goto error;
    }

    capsList = vlc_alloc(devcaps.VideoProcessorCount, sizeof(*capsList));
    if (unlikely(capsList == NULL))
    {
        msg_Dbg(interop, "Failed to allocate %u video processors", devcaps.VideoProcessorCount);
        goto error;
    }
    hr = IDXVAHD_Device_GetVideoProcessorCaps( hd_device, devcaps.VideoProcessorCount, capsList);
    if (FAILED(hr))
    {
        msg_Dbg(interop, "Failed to get the processor caps (error 0x%lX)", hr);
        goto error;
    }

    hr = IDXVAHD_Device_CreateVideoProcessor( hd_device, &capsList->VPGuid, &sys->processor.proc );
    if (FAILED(hr))
    {
        msg_Dbg(interop, "Failed to create the processor (error 0x%lX)", hr);
        goto error;
    }

    free(capsList);
    free(formatsList);
    IDXVAHD_Device_Release( hd_device );

    SetupProcessorInput(interop, &interop->fmt_in, src_format);

    DXVAHD_BLT_STATE_OUTPUT_COLOR_SPACE_DATA colorspace = {
        .Usage = 0, // playback
        .RGB_Range = /* full range */true ? 0 : 1,
        .YCbCr_xvYCC = /* full range */true ? 1 : 0,
        .YCbCr_Matrix = /* BT601 colorspace */ false ? 0 : 1,
    };
    hr = IDXVAHD_VideoProcessor_SetVideoProcessBltState( sys->processor.proc, DXVAHD_BLT_STATE_OUTPUT_COLOR_SPACE, sizeof(colorspace), &colorspace);

    return VLC_SUCCESS;

error:
    free(capsList);
    free(formatsList);
    if (hd_device)
        IDXVAHD_Device_Release(hd_device);
    return VLC_EGENERIC;
}

static int
GLConvOpen(struct vlc_gl_interop *interop)
{
    if (interop->fmt_in.i_chroma != VLC_CODEC_D3D9_OPAQUE
     && interop->fmt_in.i_chroma != VLC_CODEC_D3D9_OPAQUE_10B)
        return VLC_EGENERIC;

    d3d9_video_context_t *vctx_sys = GetD3D9ContextPrivate( interop->vctx );
    d3d9_decoder_device_t *d3d9_decoder = GetD3D9OpaqueContext(interop->vctx);
    if ( vctx_sys == NULL || d3d9_decoder == NULL )
        return VLC_EGENERIC;

    if (!d3d9_decoder->hd3d.use_ex)
    {
        msg_Warn(interop, "DX/GL interrop only working on d3d9x");
        return VLC_EGENERIC;
    }
    HGLRC hGLRC = wglGetCurrentContext();
    if (hGLRC == NULL)
        return VLC_EGENERIC;

    struct wgl_vt vt;

#define LOAD_EXT(name, type) do { \
    vt.name = (type) vlc_gl_GetProcAddress(interop->gl, "wgl" #name); \
    if (!vt.name) { \
        msg_Warn(interop, "'wgl " #name "' could not be loaded"); \
        return VLC_EGENERIC; \
    } \
} while(0)

    LOAD_EXT(GetExtensionsStringEXT, PFNWGLGETEXTENSIONSSTRINGEXTPROC);
    LOAD_EXT(GetExtensionsStringARB, PFNWGLGETEXTENSIONSSTRINGARBPROC);

    const char *wglExt = NULL;
    if (vt.GetExtensionsStringEXT)
    {
        wglExt = vt.GetExtensionsStringEXT();
    }
    else if (vt.GetExtensionsStringARB)
    {
        HDC hGLDC = wglGetCurrentDC();
        if (hGLDC == NULL)
            return VLC_EGENERIC;
        wglExt = vt.GetExtensionsStringARB(hGLDC);
    }

    if (wglExt == NULL || !vlc_gl_StrHasToken(wglExt, "WGL_NV_DX_interop"))
        return VLC_EGENERIC;
    LOAD_EXT(DXSetResourceShareHandleNV, PFNWGLDXSETRESOURCESHAREHANDLENVPROC);
    LOAD_EXT(DXOpenDeviceNV, PFNWGLDXOPENDEVICENVPROC);
    LOAD_EXT(DXCloseDeviceNV, PFNWGLDXCLOSEDEVICENVPROC);
    LOAD_EXT(DXRegisterObjectNV, PFNWGLDXREGISTEROBJECTNVPROC);
    LOAD_EXT(DXUnregisterObjectNV, PFNWGLDXUNREGISTEROBJECTNVPROC);
    LOAD_EXT(DXLockObjectsNV, PFNWGLDXLOCKOBJECTSNVPROC);
    LOAD_EXT(DXUnlockObjectsNV, PFNWGLDXUNLOCKOBJECTSNVPROC);

    struct glpriv *priv = calloc(1, sizeof(struct glpriv));
    if (!priv)
        return VLC_ENOMEM;
    interop->priv = priv;
    priv->OutputFormat = D3DFMT_A8R8G8B8;
    priv->vt = vt;

    HRESULT hr;
    bool force_dxva_hd = var_InheritBool(interop, "direct3d9-dxvahd");
    if (force_dxva_hd || (interop->fmt_in.color_range != COLOR_RANGE_FULL &&
                          d3d9_decoder->d3ddev.identifier.VendorId == GPU_MANUFACTURER_NVIDIA))
    {
        // NVIDIA bug, YUV to RGB internal conversion in StretchRect always converts from limited to limited range
        msg_Dbg(interop->gl, "init DXVA-HD processor from %4.4s to RGB", (const char*)&vctx_sys->format);
        int err = InitRangeProcessor(interop, d3d9_decoder->d3ddev.devex, vctx_sys->format);
        if (err != VLC_SUCCESS)
            force_dxva_hd = false;
    }
    if (!force_dxva_hd)
    {
        // test whether device can perform color-conversion from that format to target format
        hr = IDirect3D9_CheckDeviceFormatConversion(d3d9_decoder->hd3d.obj,
                                                    d3d9_decoder->d3ddev.adapterId,
                                                    D3DDEVTYPE_HAL,
                                                    vctx_sys->format, priv->OutputFormat);
        if (FAILED(hr))
        {
            msg_Dbg(interop->gl, "Unsupported conversion from %4.4s to RGB", (const char*)&vctx_sys->format );
            goto error;
        }
        msg_Dbg(interop->gl, "using StrecthRect from %4.4s to RGB", (const char*)&vctx_sys->format );
    }

    HANDLE shared_handle = NULL;
    hr = IDirect3DDevice9Ex_CreateRenderTarget(d3d9_decoder->d3ddev.devex,
                                               interop->fmt_in.i_visible_width,
                                               interop->fmt_in.i_visible_height,
                                               priv->OutputFormat,
                                               D3DMULTISAMPLE_NONE, 0, FALSE,
                                               &priv->dx_render, &shared_handle);
    if (FAILED(hr))
    {
        msg_Warn(interop, "IDirect3DDevice9Ex_CreateRenderTarget failed");
        goto error;
    }

   if (shared_handle)
        priv->vt.DXSetResourceShareHandleNV(priv->dx_render, shared_handle);

    priv->gl_handle_d3d = priv->vt.DXOpenDeviceNV(d3d9_decoder->d3ddev.devex);
    if (!priv->gl_handle_d3d)
    {
        msg_Warn(interop, "DXOpenDeviceNV failed: %lu", GetLastError());
        goto error;
    }

    static const struct vlc_gl_interop_ops ops = {
        .allocate_textures = GLConvAllocateTextures,
        .deallocate_textures = GLConvDeallocateTextures,
        .update_textures = GLConvUpdate,
        .close = GLConvClose,
    };
    interop->ops = &ops;

    /* The pictures are uploaded upside-down */
    video_format_TransformBy(&interop->fmt_out, TRANSFORM_VFLIP);

    interop->tex_target = GL_TEXTURE_2D;
    interop->fmt_out.i_chroma = VLC_CODEC_BGRA;
    interop->fmt_out.space = COLOR_SPACE_UNDEF;

    interop->tex_count = 1;
    interop->texs[0] = (struct vlc_gl_tex_cfg) {
        .w = {1, 1},
        .h = {1, 1},
        .internal = GL_RGBA,
        .format = GL_BGRA,
        .type = GL_UNSIGNED_BYTE,
    };

    return VLC_SUCCESS;

error:
    GLConvClose(interop);
    return VLC_EGENERIC;
}

vlc_module_begin ()
    set_shortname("dxva2")
    set_subcategory(SUBCAT_VIDEO_VOUT)
    set_description("DXVA2 surface converter")
    set_capability("glinterop", 1)
    set_callback(GLConvOpen)

    add_bool("direct3d9-dxvahd", true, DXVAHD_TEXT, NULL)
vlc_module_end ()

Messung
CHZG
81919087

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104856
#Domains=417808