summaryrefslogtreecommitdiffstats
path: root/pica-client/videodevice.h
diff options
context:
space:
mode:
authorAnton <anton@picapica.im>2026-10-03 20:33:04 +0400
committerAnton <anton@picapica.im>2026-10-03 20:33:04 +0400
commit835b124bd871afecd88c1e5e9105e3af4d4c5b27 (patch)
tree42ee00cb6f37472fe36c802530cdc9a288ba87bd /pica-client/videodevice.h
parent76225a538e1e960eda9e31a34846f4bc62adef87 (diff)
downloadpica-pica-835b124bd871afecd88c1e5e9105e3af4d4c5b27.tar.gz
pica-pica-835b124bd871afecd88c1e5e9105e3af4d4c5b27.zip
pica-client: callwindow layout, video resize
Diffstat (limited to 'pica-client/videodevice.h')
-rw-r--r--pica-client/videodevice.h42
1 files changed, 40 insertions, 2 deletions
diff --git a/pica-client/videodevice.h b/pica-client/videodevice.h
index fe218ec..f65895d 100644
--- a/pica-client/videodevice.h
+++ b/pica-client/videodevice.h
@@ -26,6 +26,7 @@
#include <QQueue>
#include <QMutex>
#include <QWaitCondition>
+#include <QSize>
#include <QAtomicInt>
// Reassembles the fragments of one encoded video frame, as carried by 0x77
@@ -155,12 +156,29 @@ public:
void setMaxFragmentSize(int size);
// Stops keeping decoded frames in GPU memory, for when the renderer that
- // was to draw them turns out not to be able to: decoding carries on, but
+ // was to draw them turns out to not be able to: decoding carries on, but
// frames come back through system memory and are emitted by frameReady()
// from then on. Safe to call from any thread, and called directly rather
// than queued for the same reason enqueueFrame() is.
void disableHardwareRendering();
+ // The size of the area the decoded frames are going to be drawn in, so
+ // that Play() can produce them at that size directly. A decoded frame has
+ // to be resized to the window either way, and doing it inside the colour
+ // conversion the decode loop already runs costs far less than a second
+ // pass over the picture afterwards - between 1.1 and 4.6 times less over
+ // the whole pipeline, see tests/test_videoscaler.
+ //
+ // Frames keep their aspect ratio: this is the area to fit inside, not the
+ // size to produce. An empty size means the display size is not known and
+ // frames come back at their own resolution.
+ //
+ // Changes while a call is running, on every window resize, and is safe to
+ // call from any thread. Called directly rather than queued for the same
+ // reason enqueueFrame() is - the decode loop it affects is already
+ // running.
+ void setDisplaySize(QSize size);
+
public slots:
// Blocking capture+encode loop: opens the configured camera, encodes
// captured frames, and emits packetReady() for each encoded frame, split
@@ -189,7 +207,16 @@ signals:
// onto the 0x77 sequence number's last fragment marker bit.
void packetReady(QByteArray data, bool isLastFragment);
- // One decoded picture from the remote side, ready to be displayed.
+ // One decoded picture from the remote side, ready to be displayed, as a
+ // Format_RGB32 image - the format a widget draws without converting it
+ // first.
+ //
+ // Already scaled to fit the area last given to setDisplaySize(), keeping
+ // its aspect ratio, so the receiver can draw it as it stands. At the
+ // frame's own resolution while no display size has been set. A receiver
+ // still has to cope with the occasional frame at another size: the ones
+ // already decoded or in flight when the window is resized arrive at the
+ // size that was current when they were converted.
void frameReady(QImage frame);
#ifdef HAVE_VAAPI
@@ -248,6 +275,13 @@ private:
// capture loop is running.
QAtomicInt m_maxFragmentSize;
+ // Likewise set from another thread, by setDisplaySize(), while the decode
+ // loop is running. Both dimensions live in the one atomic - width in the
+ // upper half, height in the lower - so that the decode loop cannot read a
+ // new width against an old height and scale one frame to a wrong aspect
+ // ratio. Zero means not known yet.
+ QAtomicInt m_displaySize;
+
QMutex m_queueMutex;
QWaitCondition m_queueCond;
QQueue<QByteArray> m_frameQueue;
@@ -272,6 +306,10 @@ private:
// packets, hence atomic.
QAtomicInt m_decoderStarted;
+ // What setDisplaySize() was last given, unpacked; an empty size if it has
+ // not been called. Read by the decode loop, once per frame.
+ QSize displaySize() const;
+
// Sends one encoded frame out as one or more protocol sized fragments.
void emitFragments(const unsigned char *data, int size);