如何使用gstreamer板条箱从BufferRef中提取GL纹理ID?

问题描述

我正在研究使用GL将视频中的帧渲染到纹理映射的网格上的工具。我已经有一个使用单个图像(PNG)的GL应用程序。现在,我正在尝试使用gstreamer解码视频。

我从appsink example开始。

我已经尽力将解码后的视频通过glupload传送到一个应用程序接收器中。现在,我需要将从BufferRef获得的appsink.pull_sample().get_buffer()转换为GL纹理ID(一个u32),以便可以将其传递给gl::BindTexture(gl::TEXTURE_2D,tex)之类的GL函数。我在appsink上使用了set_caps(),以确保缓冲区具有功能memory:GLMemory,因此最好是纹理而不是在GPU之外。

如何使用Rust的BufferRefgstreamer板条箱从gstreamer-*提取GL纹理ID?

解决方法

要从C中的GstGLMemory检索纹理,需要使用特殊的GstGLMemory标志来映射GST_MAP_GL本身。该用于映射OpenGL纹理的特定接口目前还没有生锈的类似物。 https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/581内的相关领域中有一些工作可以帮助改善锈迹中使用GStreamer OpenGL的情况。

如果仅需要对纹理的可读访问,则VideoFrameGLExt上有一个扩展特征VideoFrame,可以使您访问OpenGL纹理。 https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/blob/master/examples/src/bin/glupload.rs提供的VideoFrameGLExt存储库中的glupload示例中有gstreamer-rs的用法。 VideoFrameGLExt特性目前在https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/blob/master/gstreamer-gl/src/gl_video_frame.rs

中实现

对于只读访问,应执行以下操作:

// buffer: gst::Buffer
// info: gst::VideoInfo
if let Ok(frame) = gst_video::VideoFrame::from_buffer_readable_gl(buffer,&info) {
    if let Some(texture) = frame.get_texture_id(0) {
        // use texture somehow
    }
}

如果相反,您还需要写入纹理,则该纹理目前尚未公开,因此需要编写手动绑定。

,

我最终使用的代码是

fn get_gl_memory(bref: &BufferRef,idx: u32) -> Option<*mut GstGLMemory> {
    unsafe {
        let n = gst_sys::gst_buffer_n_memory(bref.as_ptr() as *mut _);
        if idx >= n {
            return None;
        }

        let mem = gst_sys::gst_buffer_peek_memory(bref.as_ptr() as *mut _,idx);
        if 0 != gst_gl_sys::gst_is_gl_memory(mem) {
            Some(mem as *mut _)
        } else {
            None
        }
    }
}

//

let gl_mem = get_gl_memory(buffer,0).unwrap();
let gl_mem = unsafe { &*gl_mem };
let tex_id = gl_mem.tex_id;

尽管如果您可以方便地访问gst::VideoInfo,则ystreet00的解决方案非常有用。