![](/img/trans.png)
[英]Rendering video in QT/OpenGL using updatePaintNode: new frame only appears when I resize screen
[英]Rendering texture (video) in OpenGL in a blocking way so my received video frame won't get replaced by new one while rendering
我認為不需要此代碼的GTK細節即可了解正在發生的事情。 glDraw()
函數從Frame frame
執行OpenGL渲染,該Frame frame
是從decodedFramesFifo
-safe雙端隊列decodedFramesFifo
檢索的。
.h文件
class OpenGLArea2 : public Gtk::Window
{
public:
OpenGLArea2();
~OpenGLArea2() override;
public:
Gtk::Box m_VBox{Gtk::ORIENTATION_VERTICAL, false};
Gtk::GLArea glArea;
virtual bool render(const Glib::RefPtr<Gdk::GLContext> &context){};
};
然后是cpp文件:
OpenGLArea2::OpenGLArea2()
{
set_default_size(640, 360);
add(m_VBox);
glArea.set_hexpand(true);
glArea.set_vexpand(true);
glArea.set_auto_render(true);
m_VBox.add(glArea);
glArea.signal_render().connect(sigc::mem_fun(*this, &OpenGLArea2::render), false);
glArea.show();
m_VBox.show();
}
glFlush
bool OpenGLArea2::render(const Glib::RefPtr<Gdk::GLContext> &context)
{
try
{
glArea.throw_if_error();
glFlush glDraw();
glFlush();
}
catch (const Gdk::GLError &gle)
{
std::cerr << "An error occurred in the render callback of the GLArea" << std::endl;
return false;glFlush
}
}
void OpenGLArea2::run()
{
while (true)
{
//Important: if decodedFramesFifo does not have any data, it blocks until it has
Frame frame = decodedFramesFifo->pop_front();
this->frame = std::move(frame);
if (!firstFrameReceived)
firstFrameReceived = true;
queue_draw();
}
}
這是glDraw()的示意圖:
void OpenGLArea2::run()
{
//Creates shader programs
//Generate buffers and pixel buffer object to render from
glBufferData(GL_PIXEL_UNPACK_BUFFER, textureSize, frame.buffer(j), GL_STREAM_DRAW);
//calls glTexSubImage2D to do rendering
}
問題是我有時會遇到細分錯誤。 我嘗試使用gdb和valgrind進行調試,但是在gdb中,它不會顯示調用堆棧,而僅顯示發生錯誤的地方(有些記憶怪異的東西),而在valgrind中,它會將應用程序的速度減慢到1 fps,而根本不會遇到分段錯誤,因為我認為在新數據到達之前有足夠的時間渲染數據。
我懷疑queue_draw()
沒有阻塞,因此,它只是標記要渲染的窗口並返回。 然后,窗口調用render()
。 如果render()
足夠快,可以在while循環上到達新幀之前進行渲染,則不會發生數據爭用。 但是,如果render()
花費更多的時間,則會到達一個新frame
並將其寫入在渲染中間的舊幀的位置
所以問題是 :如何以阻塞方式渲染? 也就是說,不是直接調用queue_draw()
,而是直接調用glDraw()
並等待其返回? 我是否可以相信glBufferData()
和glTexSubImage2D()
都以阻塞的方式使用frame
數據,而不是簡單地將其標記為稍后發送給GPU?
ps:我發現無效的Gtk :: GLArea :: queue_render和無效的Gtk :: GLArea :: set_auto_render(bool auto_render = true),但我認為queue_render()
也立即返回。
更新:
有人說我應該使用glFinish
。 問題在於,在渲染器循環中, queue_draw()
立即返回,因此該線程根本沒有被阻塞。 如何不使用queue_draw()
進行渲染?
更新:
我在while循環的開頭添加了:
std::unique_lock<std::mutex> lock{mutex};
在while循環的結尾:
conditionVariable.wait(lock);
現在我的渲染函數是這樣的:
glArea.throw_if_error();
glDraw();
glFinish();
conditionVariable.notify_one();
conidition變量使while循環在渲染完成之前等待,因此它可以安全地刪除接收到的幀(因為它超出范圍)。 但是我仍然收到段錯誤。 我在某些行中添加了日志記錄,發現在等待期間發生了段錯誤。 可能是什么原因?
我認為這是最有問題的部分:
Frame frame = decodedFramesFifo->pop_front();
this->frame = std::move(frame);
由於pop_front阻塞並等待幀。 如果在渲染之前得到第二幀,則第一幀將被破壞:
this->frame = std::move(frame); // this->frame now contains second frame, first frame is destroyed
您應該鎖定對此->框架的訪問
void ...::run()
{
while (true)
{
Frame frame = decodedFramesFifo->pop_front();
std::unique_lock<std::mutex> lk{mutex};
this->frame = std::move(frame);
lk.unlock();
if (!firstFrameReceived)
firstFrameReceived = true;
queue_draw();
}
}
void ...::render()
{
std::unique_lock<std::mutex> lk{mutex};
// draw 'this->frame'
}
如果可以std :: move移出幀,並且每幀最大只能渲染一次,則可以:
void ...::render()
{
std::unique_lock<std::mutex> lk{mutex};
Frame frame = std::move(this->frame);
lk.unlock();
// draw 'frame'
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.