Prototype: need to introduce an interface for the frame data feed
Since I want to segregate the code according to the domain, several methods must be provided to the video display to conduct a properly synchronised handover of video pixel data; by using `Glib::Dispatcher` as base class, all aspects of feed synchronisation can be packaged into a single connection interface, without having to share implementation details between the video display and player.
This commit is contained in:
parent
4699ae8f03
commit
2a61def8a4
4 changed files with 174 additions and 47 deletions
|
|
@ -1057,7 +1057,7 @@
|
||||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#520f69" CREATED="1783904751803" ID="ID_648202546" MODIFIED="1783904801052" TEXT="lasse mir von Claude zwei Code-Templates generieren">
|
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#520f69" CREATED="1783904751803" ID="ID_648202546" MODIFIED="1783904801052" TEXT="lasse mir von Claude zwei Code-Templates generieren">
|
||||||
<icon BUILTIN="edit"/>
|
<icon BUILTIN="edit"/>
|
||||||
<node CREATED="1783904765875" ID="ID_1730135150" MODIFIED="1783904774302" TEXT="die C-Lösung mit g_idle_add()"/>
|
<node CREATED="1783904765875" ID="ID_1730135150" MODIFIED="1783904774302" TEXT="die C-Lösung mit g_idle_add()"/>
|
||||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783904774961" ID="ID_795180608" MODIFIED="1783984701307" STYLE="fork" TEXT="die Gtkmm-Lösung mit dem Glib::Dispatcher">
|
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783904774961" ID="ID_795180608" MODIFIED="1784136111537" STYLE="fork" TEXT="die Gtkmm-Lösung mit dem Glib::Dispatcher">
|
||||||
<richcontent TYPE="NOTE"><html>
|
<richcontent TYPE="NOTE"><html>
|
||||||
<head/>
|
<head/>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -1083,6 +1083,7 @@
|
||||||
</html></richcontent>
|
</html></richcontent>
|
||||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||||
<icon BUILTIN="wizard"/>
|
<icon BUILTIN="wizard"/>
|
||||||
|
<icon BUILTIN="edit"/>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
|
|
@ -1249,7 +1250,7 @@
|
||||||
<icon BUILTIN="yes"/>
|
<icon BUILTIN="yes"/>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1783956516487" ID="ID_1971249448" MODIFIED="1783956541623" TEXT="Claude schreibt mir drei Code-Snippets">
|
<node CREATED="1783956516487" ID="ID_1971249448" MODIFIED="1783956541623" TEXT="Claude schreibt mir drei Code-Snippets">
|
||||||
<node CREATED="1783956542891" ID="ID_922011151" MODIFIED="1783956927430" TEXT="Setup von Uring und Timer + initiales Befüllen">
|
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783956542891" ID="ID_922011151" MODIFIED="1784136111537" STYLE="fork" TEXT="Setup von Uring und Timer + initiales Befüllen">
|
||||||
<richcontent TYPE="NOTE"><html>
|
<richcontent TYPE="NOTE"><html>
|
||||||
<head/>
|
<head/>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -1312,8 +1313,11 @@
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html></richcontent>
|
</html></richcontent>
|
||||||
|
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||||
|
<icon BUILTIN="wizard"/>
|
||||||
|
<icon BUILTIN="edit"/>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1783956564734" ID="ID_519769608" MODIFIED="1783956917195" TEXT="Skelett der Proactor-Loop">
|
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783956564734" ID="ID_519769608" MODIFIED="1784136111536" STYLE="fork" TEXT="Skelett der Proactor-Loop">
|
||||||
<richcontent TYPE="NOTE"><html>
|
<richcontent TYPE="NOTE"><html>
|
||||||
<head/>
|
<head/>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -1355,15 +1359,41 @@
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html></richcontent>
|
</html></richcontent>
|
||||||
|
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||||
|
<icon BUILTIN="wizard"/>
|
||||||
|
<icon BUILTIN="edit"/>
|
||||||
</node>
|
</node>
|
||||||
<node CREATED="1783956594083" ID="ID_1956714359" MODIFIED="1783956898511" TEXT="onTick + follow-up">
|
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783956594083" ID="ID_1956714359" MODIFIED="1784136509799" STYLE="fork" TEXT="onTick + follow-up">
|
||||||
<richcontent TYPE="NOTE"><html>
|
<richcontent TYPE="NOTE"><html>
|
||||||
<head/>
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
<body>
|
<body>
|
||||||
void onTick() { if (slots[nextExpected % N].state == Ready) { frameReady.emit(); // GUI thread will draw slots[nextExpected % N] ++nextExpected; // GUI marks the slot Empty once it's done drawing } // else: do nothing — this frame slips one tick later. Not dropped, just delayed. while (slots[nextToSubmit % N].state == Empty) { submitRead(nextToSubmit); // io_uring_prep_read + set_data64(nextToSubmit) ++nextToSubmit; } io_uring_submit(&ring); }
|
<pre>void onTick()
|
||||||
|
  {
|
||||||
|
    if (slots[nextExpected % N].state == Ready)
|
||||||
|
      {
|
||||||
|
         frameReady.emit(); // GUI thread will draw slots[nextExpected % N]
|
||||||
|
        ++nextExpected; // GUI marks the slot Empty once it's done drawing
|
||||||
|
      }
|
||||||
|
 // else: do nothing — this frame slips one tick later. Not dropped, just delayed.
|
||||||
|
|
||||||
|
while (slots[nextToSubmit % N].state == Empty)
|
||||||
|
  {
|
||||||
|
     submitRead(nextToSubmit); // io_uring_prep_read + set_data64(nextToSubmit)
|
||||||
|
++nextToSubmit;
|
||||||
|
   }
|
||||||
|
io_uring_submit(&ring);
|
||||||
|
}
|
||||||
|
|
||||||
|
</pre>
|
||||||
</body>
|
</body>
|
||||||
</html></richcontent>
|
</html>
|
||||||
<node CREATED="1783956613435" ID="ID_121998302" MODIFIED="1783956875196" TEXT="Claude erläutert dazu....">
|
</richcontent>
|
||||||
|
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||||
|
<icon BUILTIN="wizard"/>
|
||||||
|
<icon BUILTIN="edit"/>
|
||||||
|
<node CREATED="1783956613435" ID="ID_121998302" MODIFIED="1784136083060" TEXT="Claude erläutert dazu....">
|
||||||
<richcontent TYPE="NOTE"><html>
|
<richcontent TYPE="NOTE"><html>
|
||||||
<head/>
|
<head/>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -1376,7 +1406,7 @@
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783957483612" ID="ID_918051178" MODIFIED="1783957589661" STYLE="fork" TEXT="a Zuckerl: Chrono-to-Kernel-Timespec">
|
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783957483612" ID="ID_918051178" MODIFIED="1784136111534" STYLE="fork" TEXT="a Zuckerl: Chrono-to-Kernel-Timespec">
|
||||||
<richcontent TYPE="NOTE"><html>
|
<richcontent TYPE="NOTE"><html>
|
||||||
<head/>
|
<head/>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -1435,6 +1465,7 @@
|
||||||
</html></richcontent>
|
</html></richcontent>
|
||||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||||
<icon BUILTIN="wizard"/>
|
<icon BUILTIN="wizard"/>
|
||||||
|
<icon BUILTIN="edit"/>
|
||||||
</node>
|
</node>
|
||||||
<node BACKGROUND_COLOR="#e9c7a3" COLOR="#440099" CREATED="1783964845540" ID="ID_784995591" MODIFIED="1783964898453" TEXT="schließe eine allgemeine Überlegung an btr. Lumiera-Engine">
|
<node BACKGROUND_COLOR="#e9c7a3" COLOR="#440099" CREATED="1783964845540" ID="ID_784995591" MODIFIED="1783964898453" TEXT="schließe eine allgemeine Überlegung an btr. Lumiera-Engine">
|
||||||
<icon BUILTIN="back"/>
|
<icon BUILTIN="back"/>
|
||||||
|
|
@ -2056,7 +2087,7 @@
|
||||||
<node CREATED="1784082547951" ID="ID_1261536746" MODIFIED="1784082582921" TEXT="ist ein std::array aus 8bit-Pixeln"/>
|
<node CREATED="1784082547951" ID="ID_1261536746" MODIFIED="1784082582921" TEXT="ist ein std::array aus 8bit-Pixeln"/>
|
||||||
<node COLOR="#5b280f" CREATED="1784082595689" ID="ID_1135557355" MODIFIED="1784132191641" TEXT="verwende diese Typedef aber auch als »Buffer«-Abstraktion">
|
<node COLOR="#5b280f" CREATED="1784082595689" ID="ID_1135557355" MODIFIED="1784132191641" TEXT="verwende diese Typedef aber auch als »Buffer«-Abstraktion">
|
||||||
<icon BUILTIN="stop-sign"/>
|
<icon BUILTIN="stop-sign"/>
|
||||||
<node CREATED="1784132084657" ID="ID_845039951" MODIFIED="1784132129048" TEXT="hier beginnt der Knoten">
|
<node CREATED="1784132084657" HGAP="24" ID="ID_845039951" MODIFIED="1784132637445" TEXT="hier beginnt der Knoten" VSHIFT="7">
|
||||||
<arrowlink COLOR="#b92b54" DESTINATION="ID_1404935910" ENDARROW="Default" ENDINCLINATION="101;8;" ID="Arrow_ID_1619759457" STARTARROW="None" STARTINCLINATION="53;82;"/>
|
<arrowlink COLOR="#b92b54" DESTINATION="ID_1404935910" ENDARROW="Default" ENDINCLINATION="101;8;" ID="Arrow_ID_1619759457" STARTARROW="None" STARTINCLINATION="53;82;"/>
|
||||||
<icon BUILTIN="broken-line"/>
|
<icon BUILTIN="broken-line"/>
|
||||||
</node>
|
</node>
|
||||||
|
|
@ -2100,6 +2131,21 @@
|
||||||
<node CREATED="1784131484193" ID="ID_169121010" MODIFIED="1784131533952" TEXT="Zugriff als Funktion darstellen ⟹ λ">
|
<node CREATED="1784131484193" ID="ID_169121010" MODIFIED="1784131533952" TEXT="Zugriff als Funktion darstellen ⟹ λ">
|
||||||
<linktarget COLOR="#5a94d9" DESTINATION="ID_169121010" ENDARROW="Default" ENDINCLINATION="135;0;" ID="Arrow_ID_84801803" SOURCE="ID_1267317279" STARTARROW="None" STARTINCLINATION="76;6;"/>
|
<linktarget COLOR="#5a94d9" DESTINATION="ID_169121010" ENDARROW="Default" ENDINCLINATION="135;0;" ID="Arrow_ID_84801803" SOURCE="ID_1267317279" STARTARROW="None" STARTINCLINATION="76;6;"/>
|
||||||
</node>
|
</node>
|
||||||
|
<node CREATED="1784136965047" ID="ID_1744030854" MODIFIED="1784137036831" TEXT="zu kurz gedacht: es ist eine Zugriffs-Klammer">
|
||||||
|
<richcontent TYPE="NOTE"><html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
Eine Operation zum Zugriff und eine Operation um den abgeschlossenen Zugriff zu markieren; zudem gibt es auch noch den Dispatcher.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</richcontent>
|
||||||
|
<icon BUILTIN="messagebox_warning"/>
|
||||||
|
</node>
|
||||||
|
<node CREATED="1784137038242" ID="ID_1199476075" MODIFIED="1784137051164" TEXT="dann doch ein klassisches OO-Callback-Interface"/>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
</node>
|
</node>
|
||||||
|
|
|
||||||
|
|
@ -29,5 +29,17 @@ __FAIL (string msg)
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker class: any copy and copy construction prohibited
|
||||||
|
*/
|
||||||
|
class NonCopyable
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
~NonCopyable() = default;
|
||||||
|
NonCopyable() = default;
|
||||||
|
NonCopyable (NonCopyable const&) = delete;
|
||||||
|
NonCopyable& operator= (NonCopyable const&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif /*COMMONS_H*/
|
#endif /*COMMONS_H*/
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,10 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
using std::unique_ptr;
|
using std::unique_ptr;
|
||||||
|
using std::make_unique;
|
||||||
|
|
||||||
//-----------------hard-coded-config--
|
//-----------------hard-coded-config--
|
||||||
const size_t RING_SIZ = 5;
|
const size_t RING_SIZ = 5;
|
||||||
|
|
@ -29,56 +31,105 @@ const uint VIDEO_HEIGHT = 240;
|
||||||
|
|
||||||
|
|
||||||
class UringVideoPlayer
|
class UringVideoPlayer
|
||||||
|
: NonCopyable
|
||||||
{
|
{
|
||||||
using VideoDisplay = EglDisplay<uint8_t, VIDEO_WIDTH,VIDEO_HEIGHT>;
|
using VideoDisplay = EglDisplay<uint8_t, VIDEO_WIDTH,VIDEO_HEIGHT>;
|
||||||
using Buffer = VideoDisplay::Buffer;
|
using Buffer = VideoDisplay::Buffer;
|
||||||
|
|
||||||
Glib::Dispatcher dispatchFrame_;
|
enum BuffState { FREE, READ, SHOW };
|
||||||
|
using AtomicBuffState = std::atomic<BuffState>;
|
||||||
|
|
||||||
|
using BufferAlloc = unique_ptr<Buffer[]>;
|
||||||
|
using BuffStateAlloc = unique_ptr<AtomicBuffState[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connector to the VideoDisplay for dispatching video data.
|
||||||
|
* @note inherits from Glib::Dispatcher -> signal frame readiness
|
||||||
|
* @remark the callback functions allow the VideoDisplay to interact
|
||||||
|
* with the buffer data and state in a threadsafe manner
|
||||||
|
*/
|
||||||
|
class BufferDispatcher
|
||||||
|
: public VideoDisplay::PixelFeed
|
||||||
|
{
|
||||||
|
Buffer* retrieveFrame() override;
|
||||||
|
void completedFrame() override;
|
||||||
|
|
||||||
|
UringVideoPlayer& player_;
|
||||||
|
public:
|
||||||
|
BufferDispatcher (UringVideoPlayer& player)
|
||||||
|
: player_{player}
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t nextRead_{0};
|
||||||
|
size_t nextShow_{0};
|
||||||
|
BufferAlloc buffer_{};
|
||||||
|
BuffStateAlloc buffState_{};
|
||||||
|
std::atomic_bool playing_{false};
|
||||||
|
BufferDispatcher dispatchFrame_;
|
||||||
VideoDisplay videoDisplayer_;
|
VideoDisplay videoDisplayer_;
|
||||||
std::thread proactorThread_;
|
std::thread proactorThread_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UringVideoPlayer (Gtk::Window& appWindow)
|
UringVideoPlayer (Gtk::Window& appWindow)
|
||||||
: videoDisplayer_{appWindow, dispatchFrame_, [this]{ return retrieveCurrFrame(); }}
|
: dispatchFrame_{*this}
|
||||||
|
, videoDisplayer_{appWindow, dispatchFrame_}
|
||||||
, proactorThread_{[this]{ playVideo(); }}
|
, proactorThread_{[this]{ playVideo(); }}
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void terminate();
|
void terminate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void
|
void playVideo();
|
||||||
playVideo()
|
};
|
||||||
{
|
|
||||||
// allocate buffer data structure
|
|
||||||
|
/**
|
||||||
|
* Logic of the »Proactor Thread«:
|
||||||
|
* - maintain the working buffers
|
||||||
|
* - open the raw video file to retrieve data
|
||||||
|
* - establish an IO_URING connection for reading
|
||||||
|
* - periodic processing to fill and hand-off buffers
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
UringVideoPlayer::playVideo()
|
||||||
|
{
|
||||||
|
buffer_ = make_unique<Buffer[]> (RING_SIZ);
|
||||||
|
buffState_ = make_unique<AtomicBuffState[]> (RING_SIZ);
|
||||||
// initialise URing
|
// initialise URing
|
||||||
// ++ proactor-loop ++
|
// ++ proactor-loop ++
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer*
|
|
||||||
retrieveCurrFrame()
|
UringVideoPlayer::Buffer*
|
||||||
{
|
UringVideoPlayer::BufferDispatcher::retrieveFrame()
|
||||||
|
{
|
||||||
///////OOO threadsafe hand-over of current frame data
|
///////OOO threadsafe hand-over of current frame data
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UringVideoPlayer::BufferDispatcher::completedFrame()
|
||||||
|
{
|
||||||
|
///////OOO mark end of buffer access
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UringVideoPlayer::terminate()
|
||||||
|
{
|
||||||
|
playing_.store (false, std::memory_order_release);
|
||||||
|
proactorThread_.join();
|
||||||
|
videoDisplayer_.cleanUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unique_ptr<UringVideoPlayer>
|
unique_ptr<UringVideoPlayer>
|
||||||
launchPlayer (Gtk::Window& appWindow)
|
launchPlayer (Gtk::Window& appWindow)
|
||||||
{
|
{
|
||||||
appWindow.resize (VIDEO_WIDTH, VIDEO_HEIGHT);
|
appWindow.resize (VIDEO_WIDTH, VIDEO_HEIGHT);
|
||||||
|
return std::make_unique<UringVideoPlayer> (appWindow);
|
||||||
auto player = std::make_unique<UringVideoPlayer> (appWindow);
|
|
||||||
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
UringVideoPlayer::terminate()
|
|
||||||
{
|
|
||||||
///// signal stop to proactor
|
|
||||||
videoDisplayer_.cleanUp();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,20 +38,35 @@ using std::string;
|
||||||
*/
|
*/
|
||||||
template<typename PIX, uint WIDTH, uint HEIGHT>
|
template<typename PIX, uint WIDTH, uint HEIGHT>
|
||||||
class EglDisplay
|
class EglDisplay
|
||||||
|
: NonCopyable
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using Buffer = std::array<PIX, WIDTH*HEIGHT * 3 >;
|
using Buffer = std::array<PIX, WIDTH*HEIGHT * 3 >;
|
||||||
using PixFeed = std::function<Buffer*()>;
|
|
||||||
|
|
||||||
EglDisplay(Gtk::Window& appWindow
|
/**
|
||||||
,Glib::Dispatcher& dispatchFrame
|
* Interface retrieve pixel data for video frames to display.
|
||||||
,PixFeed frameCallback
|
* - this is a Glib::Dispatcher, and the attached slot shall be
|
||||||
)
|
* triggered whenever data for a new frame is available
|
||||||
: retrieveFrame_{frameCallback}
|
* - pixel data is accessed (threadsafe) by invoking #retrieveFrame()
|
||||||
|
* - when processing is complete and the data will no longer be needed,
|
||||||
|
* access to the pixel buffer is yielded by invoking #completedFrame()
|
||||||
|
*/
|
||||||
|
class PixelFeed
|
||||||
|
: public Glib::Dispatcher
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~PixelFeed() { }; ///< this is an interface
|
||||||
|
virtual Buffer* retrieveFrame() =0;
|
||||||
|
virtual void completedFrame() =0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
EglDisplay (Gtk::Window& appWindow, PixelFeed& pixelFeed)
|
||||||
|
: pixelFeed_{pixelFeed}
|
||||||
{
|
{
|
||||||
openDisplay (appWindow);
|
openDisplay (appWindow);
|
||||||
dispatchFrame.connect([this]{ displayFrame(); });
|
pixelFeed_.connect([this]{ displayFrame(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanUp();
|
void cleanUp();
|
||||||
|
|
@ -71,7 +86,7 @@ class EglDisplay
|
||||||
float scaleY_{1};
|
float scaleY_{1};
|
||||||
|
|
||||||
/** Callback functor to access current pixel data */
|
/** Callback functor to access current pixel data */
|
||||||
PixFeed retrieveFrame_{};
|
PixelFeed& pixelFeed_{};
|
||||||
|
|
||||||
void openDisplay (Gtk::Window&);
|
void openDisplay (Gtk::Window&);
|
||||||
void displayFrame();
|
void displayFrame();
|
||||||
|
|
@ -321,7 +336,7 @@ void
|
||||||
EglDisplay<PIX,WIDTH,HEIGHT>::displayFrame()
|
EglDisplay<PIX,WIDTH,HEIGHT>::displayFrame()
|
||||||
{
|
{
|
||||||
|
|
||||||
auto currFrame = retrieveFrame_();
|
auto currFrame = pixelFeed_.retrieveFrame();
|
||||||
if (not currFrame) return;
|
if (not currFrame) return;
|
||||||
|
|
||||||
// pick up current buffer with RGB data
|
// pick up current buffer with RGB data
|
||||||
|
|
@ -340,6 +355,9 @@ EglDisplay<PIX,WIDTH,HEIGHT>::displayFrame()
|
||||||
|
|
||||||
// double-buffer flip, automatically invokes glFlush()
|
// double-buffer flip, automatically invokes glFlush()
|
||||||
eglSwapBuffers (display_, surface_);
|
eglSwapBuffers (display_, surface_);
|
||||||
|
|
||||||
|
// signal that processing of this frame is complete
|
||||||
|
pixelFeed_.completedFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue