簡體   English   中英

vaapi 表面到 openGl 紋理

[英]vaapi Surface to openGl texture

我將使用 vaapi/ffmpeg 解碼的視頻幀轉換為 VASurface。 現在我想使用 OpenGL 紋理來渲染它們。 我能夠將幀加載到軟件中(使用vaDeriveImagevaMapBuffer )並使用接收到的數據更新紋理。 但這真的很慢,這不是我的目標。 然后我發現 EGL 在其他一些存儲庫中使用。

所以我找到了這個 repo ,據我所知,它確實完全使用 EGL 渲染幀。 這不是我想要的。 我需要它的質地供以后使用。

然后我遇到了fmor 的演示程序 這對我來說真的很神奇。 init 有 2 個步驟,然后他可以毫無問題地使用紋理。

//in player.c before the decoding happens:
egl_image = egl_create_image_from_va( &surface, player->video_va_display, player->video_cc->width, player->video_cc->height );
    if( egl_image == EGL_NO_IMAGE )
        goto LBL_FAILED;

    glGenTextures( 1, &player->video_texture );
    glBindTexture( GL_TEXTURE_2D, player->video_texture );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glEGLImageTargetTexture2DOES( GL_TEXTURE_2D, egl_image  );

//in util.c:
EGLImage egl_create_image_from_va(VASurfaceID* _va_surface, VADisplay va_display, int width, int height)
{
    EGLImage egl_image;
    VASurfaceID va_surface;
    VASurfaceAttrib va_surface_attrib;
    VADRMPRIMESurfaceDescriptor va_surface_descriptor;
    int r;

    egl_image = EGL_NO_IMAGE;
    va_surface = VA_INVALID_SURFACE;

    va_surface_attrib.type = VASurfaceAttribPixelFormat;
    va_surface_attrib.flags = VA_SURFACE_ATTRIB_SETTABLE;
    va_surface_attrib.value.type = VAGenericValueTypeInteger;
    va_surface_attrib.value.value.i = VA_FOURCC_RGBA;

    r = vaCreateSurfaces( va_display, VA_RT_FORMAT_RGB32, width, height, &va_surface, 1, &va_surface_attrib, 1 );
    if( r != VA_STATUS_SUCCESS )
        goto LBL_FAILED;

    r = vaExportSurfaceHandle( va_display, va_surface, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, VA_EXPORT_SURFACE_READ_ONLY, &va_surface_descriptor );
    if( r != 0 )
        goto LBL_FAILED;

    EGLAttrib egl_img_attributes[] = {
        EGL_LINUX_DRM_FOURCC_EXT, va_surface_descriptor.layers[0].drm_format,
        EGL_WIDTH, va_surface_descriptor.width,
        EGL_HEIGHT, va_surface_descriptor.height,
        EGL_DMA_BUF_PLANE0_FD_EXT, va_surface_descriptor.objects[va_surface_descriptor.layers[0].object_index[0]].fd,
        EGL_DMA_BUF_PLANE0_OFFSET_EXT, va_surface_descriptor.layers[0].offset[0],
        EGL_DMA_BUF_PLANE0_PITCH_EXT, va_surface_descriptor.layers[0].pitch[0],
        EGL_NONE
    };
    egl_image = eglCreateImage( eglGetCurrentDisplay(), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, egl_img_attributes );
    if( egl_image == EGL_NO_IMAGE )
        goto LBL_FAILED;


    *_va_surface = va_surface;
    return egl_image;
LBL_FAILED:
    if( va_surface != VA_INVALID_SURFACE )
        vaDestroySurfaces( va_display, &va_surface, 1 );
    return EGL_NO_IMAGE;
}

有人能告訴我這里發生了什么嗎? 以及如何在不使用 glew 的情況下重現它?

我最難猜的是,使用 EGL_LINUX_DMA_BUF_EXT 參數創建 eglImage 時,有一些直接的 memory 正在訪問。 vaapi 是否在此處直接渲染到 OpenGL 紋理中?

這里也使用了vaExportSurfaceHandle ,我真的不明白這是在做什么。

編輯:我現在閱讀了很多與 EGL 相關的帖子。 我想我現在明白了一點。 但是當我再次查看fmor 的演示程序時,我感到困惑。 有幾個eglGetCurrentDisplay()調用,但我找不到這個 Display 的設置位置,所以我可以重現它。 可能是,那個 glew 正在幕后做某事,還是我錯過了其他東西?

甚至eglInitialze()也不會被調用一次。

當我嘗試使用eglGetDisplay(native_display)自己實例化 EGLDisplay 時,就像在 ffvademo 中所做的那樣,我應該為 native_display 輸入什么? 在 ffvademo 中插入了 X11 顯示器或 DRM 顯示器(?)。 據我所知,兩者都用於渲染到屏幕上,或者不是? 另外我認為在這里插入 vaapi Display 是不正確的。 我真的可以在這里使用一些幫助......

好的,我找到了。 GLFW 正在做所有需要的事情。 我想通讀該代碼以找到我的答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM