#pragma once // Qt includes #include // util includes #include #include // Determine the cmake options #include // Turbo JPEG decoder #ifdef HAVE_TURBO_JPEG #include #endif /// Encoder thread for USB devices class EncoderThread : public QObject { Q_OBJECT public: explicit EncoderThread(); ~EncoderThread(); void setup( PixelFormat pixelFormat, uint8_t* sharedData, int size, int width, int height, int lineLength, unsigned cropLeft, unsigned cropTop, unsigned cropBottom, unsigned cropRight, VideoMode videoMode, FlipMode flipMode, int pixelDecimation); void process(); bool isBusy() { return _busy; } QAtomicInt _busy = false; signals: void newFrame(const Image& data); private: PixelFormat _pixelFormat; uint8_t* _localData, *_flipBuffer; int _scalingFactorsCount, _width, _height, _lineLength, _currentFrame, _pixelDecimation; unsigned long _size; unsigned _cropLeft, _cropTop, _cropBottom, _cropRight; FlipMode _flipMode; ImageResampler _imageResampler; #ifdef HAVE_TURBO_JPEG tjhandle _transform, _decompress; tjscalingfactor* _scalingFactors; tjtransform* _xform; void processImageMjpeg(); #endif }; template class Thread : public QThread { public: TThread *_thread; explicit Thread(TThread *thread, QObject *parent = nullptr) : QThread(parent) , _thread(thread) { _thread->moveToThread(this); start(); } ~Thread() { quit(); wait(); } EncoderThread* thread() const { return qobject_cast(_thread); } void setup( PixelFormat pixelFormat, uint8_t* sharedData, int size, int width, int height, int lineLength, unsigned cropLeft, unsigned cropTop, unsigned cropBottom, unsigned cropRight, VideoMode videoMode, FlipMode flipMode, int pixelDecimation) { auto encThread = qobject_cast(_thread); if (encThread != nullptr) encThread->setup(pixelFormat, sharedData, size, width, height, lineLength, cropLeft, cropTop, cropBottom, cropRight, videoMode, flipMode, pixelDecimation); } bool isBusy() { auto encThread = qobject_cast(_thread); if (encThread != nullptr) return encThread->isBusy(); return true; } void process() { auto encThread = qobject_cast(_thread); if (encThread != nullptr) encThread->process(); } protected: void run() override { QThread::run(); delete _thread; } }; class EncoderThreadManager : public QObject { Q_OBJECT public: explicit EncoderThreadManager(QObject *parent = nullptr) : QObject(parent) , _threadCount(qMax(QThread::idealThreadCount(), 1)) , _threads(nullptr) { _threads = new Thread*[_threadCount]; for (int i = 0; i < _threadCount; i++) { _threads[i] = new Thread(new EncoderThread, this); _threads[i]->setObjectName("Encoder " + QString::number(i)); } } ~EncoderThreadManager() { if (_threads != nullptr) { for(int i = 0; i < _threadCount; i++) { _threads[i]->deleteLater(); _threads[i] = nullptr; } delete[] _threads; _threads = nullptr; } } void start() { if (_threads != nullptr) for (int i = 0; i < _threadCount; i++) connect(_threads[i]->thread(), &EncoderThread::newFrame, this, &EncoderThreadManager::newFrame); } void stop() { if (_threads != nullptr) for(int i = 0; i < _threadCount; i++) disconnect(_threads[i]->thread(), nullptr, nullptr, nullptr); } int _threadCount; Thread** _threads; signals: void newFrame(const Image& data); };