VaAPI曲面到OpenGL纹理

mbjcgjjk  于 2022-09-26  发布在  其他
关注(0)|答案(1)|浏览(669)

我用Vaapi/ffmpeg把视频帧解码成了VASurace。现在,我想使用OpenGL纹理来渲染它们。我能够将帧加载到软件中(使用vaDeriveImagevaMapBuffer),并使用收到的数据更新纹理。但那真的很慢,这不是我在这里的目标。然后我发现EGL在其他一些报告中使用了。

所以我找到了this repo,据我所知,它确实完全使用EGL渲染了帧。这不是我想要的。我需要它的质地,以便以后使用。

然后我遇到了fmor's demo program。在我看来,这真的像是魔术。在初始化上有两个步骤,然后他就可以毫无问题地使用纹理了。

//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的情况下重现这一切?

我最怀疑的是,使用eglImage创建的EGL_LINUX_DMA_BUF_EXT参数,有一些正在进行的直接内存访问。Vaapi在这里渲染到OpenGL纹理中了吗?

另外,这里使用的是vaExportSurfaceHandle,我真的不知道它在做什么。

**编辑:**我现在阅读了很多关于EGL的帖子。我想我现在明白多了一点。但当我再次看fmor's demo program时,我感到困惑。有几次调用eglGetCurrentDisplay(),但我找不到这个显示设置在哪里,所以我可以复制它。会不会是Glew在幕后做了什么,或者我错过了什么?

即使是eglInitialze()也从未调用过一次。

当我尝试使用eglGetDisplay(native_display)自己示例化一个EGLDisplay时,就像在ffvademo中所做的那样,我应该为Native_Display放入什么?在ffvademo中有X11显示屏或DRM显示屏(?)已插入。据我所知,两者都是用来渲染到屏幕上的,还是没有?此外,我认为在这里插入Vaapi显示器将不是正确的事情。我真的需要一些帮助伙计们..。

ajsxfq5m

ajsxfq5m1#

好的,我找到了。GLFW正在做所有需要的事情。我想我会通读那段代码来找出答案。

相关问题