问题描述
我正在研究使用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的BufferRef
和gstreamer
板条箱从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的解决方案非常有用。