File indexing completed on 2024-05-12 15:49:09
0001 /* 0002 SPDX-FileCopyrightText: 2022 Volker Krause <vkrause@kde.org> 0003 SPDX-License-Identifier: MIT 0004 */ 0005 0006 #include "videoscanner.h" 0007 #include "videoscannerframe_p.h" 0008 #include "videoscannerworker_p.h" 0009 0010 #include <QDebug> 0011 0012 using namespace Prison; 0013 0014 namespace Prison 0015 { 0016 class VideoScannerPrivate 0017 { 0018 public: 0019 void newFrame(const QVideoFrame &videoFrame, bool verticallyFlipped); 0020 void setResult(VideoScanner *q, const ScanResult &result); 0021 0022 VideoScannerThread m_thread; 0023 VideoScannerWorker m_worker; 0024 QByteArray m_frameDataBuffer; // reused memory when we have to copy frame data 0025 ScanResult m_result; 0026 QVariant m_previousContent; 0027 Format::BarcodeFormats m_formats = Format::NoFormat; 0028 bool m_workerBusy = false; 0029 }; 0030 0031 class VideoScannerFilterRunnable : public QVideoFilterRunnable 0032 { 0033 public: 0034 VideoScannerFilterRunnable(VideoScannerPrivate *dd); 0035 QVideoFrame run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, QVideoFilterRunnable::RunFlags flags) override; 0036 0037 private: 0038 VideoScannerPrivate *d = nullptr; 0039 }; 0040 } 0041 0042 void VideoScannerPrivate::newFrame(const QVideoFrame &videoFrame, bool verticallyFlipped) 0043 { 0044 // NOTE: this runs in the render thread 0045 if (!m_workerBusy && videoFrame.isValid()) { 0046 m_workerBusy = true; 0047 0048 VideoScannerFrame frame(videoFrame, verticallyFlipped, m_formats); 0049 // check if we are only allowed to access this in the render thread 0050 if (frame.copyRequired()) { 0051 frame.map(); 0052 if (frame.needsConversion()) { 0053 frame.convertToImage(); 0054 } else { 0055 frame.copyFrameData(m_frameDataBuffer); 0056 } 0057 frame.unmap(); 0058 } 0059 0060 Q_EMIT m_worker.scanFrameRequest(frame); 0061 } 0062 } 0063 0064 void VideoScannerPrivate::setResult(VideoScanner *q, const ScanResult &result) 0065 { 0066 m_workerBusy = false; 0067 if (m_result == result) { 0068 return; 0069 } 0070 0071 m_result = result; 0072 Q_EMIT q->resultChanged(result); 0073 0074 if (m_previousContent == result.content()) { 0075 return; 0076 } 0077 m_previousContent = result.content(); 0078 Q_EMIT q->resultContentChanged(result); 0079 } 0080 0081 VideoScannerFilterRunnable::VideoScannerFilterRunnable(VideoScannerPrivate *dd) 0082 : d(dd) 0083 { 0084 } 0085 0086 QVideoFrame VideoScannerFilterRunnable::run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, QVideoFilterRunnable::RunFlags /* flags */) 0087 { 0088 d->newFrame(*input, surfaceFormat.scanLineDirection() == QVideoSurfaceFormat::BottomToTop); 0089 return *input; 0090 } 0091 0092 VideoScanner::VideoScanner(QObject *parent) 0093 : QAbstractVideoFilter(parent) 0094 , d(new VideoScannerPrivate) 0095 { 0096 d->m_worker.moveToThread(&d->m_thread); 0097 connect( 0098 &d->m_worker, 0099 &VideoScannerWorker::result, 0100 this, 0101 [this](const ScanResult &result) { 0102 d->setResult(this, result); 0103 }, 0104 Qt::QueuedConnection); 0105 0106 d->m_thread.setObjectName(QStringLiteral("Prison Barcode Scanner Worker")); 0107 d->m_thread.start(); 0108 } 0109 0110 VideoScanner::~VideoScanner() 0111 { 0112 d->m_thread.quit(); 0113 d->m_thread.wait(); 0114 } 0115 0116 QVideoFilterRunnable *VideoScanner::createFilterRunnable() 0117 { 0118 return new VideoScannerFilterRunnable(d.get()); 0119 } 0120 0121 ScanResult VideoScanner::result() const 0122 { 0123 return d->m_result; 0124 } 0125 0126 Format::BarcodeFormats VideoScanner::formats() const 0127 { 0128 return d->m_formats; 0129 } 0130 0131 void VideoScanner::setFormats(Format::BarcodeFormats formats) 0132 { 0133 if (d->m_formats == formats) { 0134 return; 0135 } 0136 0137 d->m_formats = formats; 0138 Q_EMIT formatsChanged(); 0139 } 0140 0141 #include "moc_videoscanner.cpp"