Skip to content

Commit d70725b

Browse files
committed
Move QCamera off the UI thread.
1 parent db6505c commit d70725b

File tree

7 files changed

+126
-23
lines changed

7 files changed

+126
-23
lines changed

SerialPrograms/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,7 @@ file(GLOB MAIN_SOURCES
485485
Source/CommonFramework/VideoPipeline/Backends/CameraWidgetQt6.h
486486
Source/CommonFramework/VideoPipeline/Backends/MediaServicesQt6.cpp
487487
Source/CommonFramework/VideoPipeline/Backends/MediaServicesQt6.h
488+
Source/CommonFramework/VideoPipeline/Backends/QCameraThread.h
488489
Source/CommonFramework/VideoPipeline/Backends/QVideoFrameCache.h
489490
Source/CommonFramework/VideoPipeline/Backends/SnapshotManager.cpp
490491
Source/CommonFramework/VideoPipeline/Backends/SnapshotManager.h

SerialPrograms/Source/CommonFramework/VideoPipeline/Backends/CameraWidgetQt6.5.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ CameraVideoSource::~CameraVideoSource(){
8282
m_logger.log("Stopping Camera...");
8383
}catch (...){}
8484

85-
m_camera->stop();
85+
// m_camera->stop();
8686
m_capture_session.reset();
8787
m_camera.reset();
8888
}
@@ -147,12 +147,15 @@ CameraVideoSource::CameraVideoSource(
147147
m_resolution = Resolution(size.width(), size.height());
148148
m_logger.log("Resolution: " + m_resolution.to_string());
149149

150-
m_camera.reset(new QCamera(*device));
151-
m_camera->setCameraFormat(*format);
150+
m_camera.reset(new QCameraThread(m_logger, *device, *format));
151+
// m_camera.reset(new QCamera(*device));
152+
// m_camera->setCameraFormat(*format);
152153

153154
m_capture_session.reset(new QMediaCaptureSession());
154-
m_capture_session->setCamera(m_camera.get());
155+
// m_capture_session->setCamera(m_camera.get());
156+
m_capture_session->setCamera(&m_camera->camera());
155157

158+
#if 0
156159
connect(m_camera.get(), &QCamera::errorOccurred, this, [&](){
157160
if (m_camera->error() == QCamera::NoError){
158161
return;
@@ -161,6 +164,8 @@ CameraVideoSource::CameraVideoSource(
161164
});
162165

163166
m_camera->start();
167+
#endif
168+
164169
}
165170

166171

@@ -175,18 +180,16 @@ void CameraVideoSource::set_video_output(QGraphicsVideoItem& item){
175180

176181
connect(
177182
item.videoSink(), &QVideoSink::videoFrameChanged,
178-
m_camera.get(), [&](const QVideoFrame& frame){
179-
// This will be on the main thread. So we waste as little time as
180-
// possible. Shallow-copy the frame, update the listeners, and
181-
// return immediately to unblock the main thread.
183+
&m_camera->camera(), [&](const QVideoFrame& frame){
184+
// This runs on the QCamera's thread. So it is off the critical path.
182185

183186
WallClock now = current_time();
184187
if (!m_last_frame.push_frame(frame, now)){
185188
return;
186189
}
187190
report_source_frame(std::make_shared<VideoFrame>(now, frame));
188-
},
189-
Qt::DirectConnection
191+
}//,
192+
// Qt::DirectConnection
190193
);
191194
}
192195

SerialPrograms/Source/CommonFramework/VideoPipeline/Backends/CameraWidgetQt6.5.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#if QT_VERSION_MAJOR == 6
1212

1313
//#include <set>
14-
#include <mutex>
14+
//#include <mutex>
1515
#include <QCameraDevice>
1616
#include <QMediaCaptureSession>
1717
#include <QVideoFrame>
@@ -23,6 +23,7 @@
2323
#include "CommonFramework/Tools/StatAccumulator.h"
2424
#include "CommonFramework/VideoPipeline/VideoSource.h"
2525
#include "CommonFramework/VideoPipeline/CameraInfo.h"
26+
#include "QCameraThread.h"
2627
#include "QVideoFrameCache.h"
2728
#include "SnapshotManager.h"
2829
#include "CameraImplementations.h"
@@ -126,7 +127,8 @@ class CameraVideoSource : public QObject, public VideoSource{
126127
Logger& m_logger;
127128
Resolution m_resolution;
128129

129-
std::unique_ptr<QCamera> m_camera;
130+
// std::unique_ptr<QCamera> m_camera;
131+
std::unique_ptr<QCameraThread> m_camera;
130132
std::unique_ptr<QVideoSink> m_video_sink;
131133
std::unique_ptr<QMediaCaptureSession> m_capture_session;
132134

SerialPrograms/Source/CommonFramework/VideoPipeline/Backends/CameraWidgetQt6.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ CameraVideoSource::~CameraVideoSource(){
7474
m_logger.log("Stopping Camera...");
7575
}catch (...){}
7676

77-
m_camera->stop();
77+
// m_camera->stop();
7878
m_capture.reset();
7979
m_video_sink.reset();
8080
m_camera.reset();
@@ -139,24 +139,26 @@ CameraVideoSource::CameraVideoSource(
139139
m_resolution = Resolution(size.width(), size.height());
140140
m_logger.log("Resolution: " + m_resolution.to_string());
141141

142-
m_camera.reset(new QCamera(*device));
143-
m_camera->setCameraFormat(*format);
142+
m_camera.reset(new QCameraThread(m_logger, *device, *format));
143+
// m_camera.reset(new QCamera(*device));
144+
// m_camera->setCameraFormat(*format);
144145
m_video_sink.reset(new QVideoSink());
145146
m_capture.reset(new QMediaCaptureSession());
146-
m_capture->setCamera(m_camera.get());
147+
// m_capture->setCamera(m_camera.get());
148+
m_capture->setCamera(&m_camera->camera());
147149
m_capture->setVideoSink(m_video_sink.get());
148150

151+
#if 0
149152
connect(m_camera.get(), &QCamera::errorOccurred, this, [&](){
150153
if (m_camera->error() != QCamera::NoError){
151154
m_logger.log("QCamera error: " + m_camera->errorString().toStdString());
152155
}
153156
});
157+
#endif
154158
connect(
155159
m_video_sink.get(), &QVideoSink::videoFrameChanged,
156-
m_camera.get(), [&](const QVideoFrame& frame){
157-
// This will be on the main thread. So we waste as little time as
158-
// possible. Shallow-copy the frame, update the listeners, and
159-
// return immediately to unblock the main thread.
160+
&m_camera->camera(), [&](const QVideoFrame& frame){
161+
// This runs on the QCamera's thread. So it is off the critical path.
160162

161163
WallClock now = current_time();
162164
if (!m_last_frame.push_frame(frame, now)){
@@ -166,7 +168,7 @@ CameraVideoSource::CameraVideoSource(
166168
}
167169
);
168170

169-
m_camera->start();
171+
// m_camera->start();
170172
}
171173

172174

SerialPrograms/Source/CommonFramework/VideoPipeline/Backends/CameraWidgetQt6.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "CommonFramework/Tools/StatAccumulator.h"
1919
#include "CommonFramework/VideoPipeline/VideoSource.h"
2020
#include "CommonFramework/VideoPipeline/CameraInfo.h"
21+
#include "QCameraThread.h"
2122
#include "QVideoFrameCache.h"
2223
#include "SnapshotManager.h"
2324
#include "CameraImplementations.h"
@@ -85,7 +86,8 @@ class CameraVideoSource : public QObject, public VideoSource{
8586

8687
std::mutex m_snapshot_lock;
8788

88-
std::unique_ptr<QCamera> m_camera;
89+
// std::unique_ptr<QCamera> m_camera;
90+
std::unique_ptr<QCameraThread> m_camera;
8991
std::unique_ptr<QVideoSink> m_video_sink;
9092
std::unique_ptr<QMediaCaptureSession> m_capture;
9193

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/* QCameraThread
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#ifndef PokemonAutomation_VideoPipeline_QCameraThread_H
8+
#define PokemonAutomation_VideoPipeline_QCameraThread_H
9+
10+
#include <QThread>
11+
#include <QCamera>
12+
#include "Common/Cpp/AbstractLogger.h"
13+
14+
//#include <iostream>
15+
//using std::cout;
16+
//using std::endl;
17+
18+
namespace PokemonAutomation{
19+
20+
21+
class QCameraThread : public QThread{
22+
Q_OBJECT
23+
24+
public:
25+
QCameraThread(
26+
Logger& logger,
27+
QCameraDevice device,
28+
QCameraFormat format
29+
)
30+
: m_logger(logger)
31+
, m_device(std::move(device))
32+
, m_format(std::move(format))
33+
, m_camera(nullptr)
34+
{
35+
start();
36+
37+
std::unique_lock<std::mutex> lg(m_lock);
38+
m_cv.wait(lg, [this]{ return m_camera != nullptr; });
39+
}
40+
~QCameraThread(){
41+
quit();
42+
wait();
43+
}
44+
45+
QCamera& camera() const{
46+
return *m_camera;
47+
}
48+
49+
50+
private:
51+
virtual void run() override{
52+
QCamera camera(m_device);
53+
m_camera = &camera;
54+
camera.setCameraFormat(m_format);
55+
56+
connect(&camera, &QCamera::errorOccurred, this, [&](){
57+
if (camera.error() == QCamera::NoError){
58+
return;
59+
}
60+
m_logger.log("QCamera error: " + camera.errorString().toStdString(), COLOR_RED);
61+
});
62+
63+
camera.start();
64+
65+
{
66+
std::lock_guard<std::mutex> lg(m_lock);
67+
}
68+
m_cv.notify_all();
69+
70+
// cout << "start" << endl;
71+
exec();
72+
// cout << "end" << endl;
73+
74+
m_camera = nullptr;
75+
}
76+
77+
78+
private:
79+
Logger& m_logger;
80+
QCameraDevice m_device;
81+
QCameraFormat m_format;
82+
QCamera* m_camera;
83+
84+
std::mutex m_lock;
85+
std::condition_variable m_cv;
86+
};
87+
88+
89+
90+
}
91+
#endif

SerialPrograms/Source/PokemonSV/Programs/TeraRaids/PokemonSV_TeraMultiFarmer.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,9 @@ bool TeraMultiFarmer::start_sequence_host(
412412

413413
uint8_t hosts = (uint8_t)env.consoles.size();
414414
uint8_t players = waiter.last_known_players();
415-
stats.m_joiners += players - hosts;
415+
if (players > hosts){
416+
stats.m_joiners += players - hosts;
417+
}
416418
if (players == 4){
417419
stats.m_full++;
418420
}else if (players == hosts){

0 commit comments

Comments
 (0)