File indexing completed on 2024-05-12 04:01:32
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 QVideoSink *m_sink = nullptr; 0023 VideoScannerThread m_thread; 0024 VideoScannerWorker m_worker; 0025 QByteArray m_frameDataBuffer; // reused memory when we have to copy frame data 0026 ScanResult m_result; 0027 QVariant m_previousContent; 0028 Format::BarcodeFormats m_formats = Format::NoFormat; 0029 bool m_workerBusy = false; 0030 }; 0031 } 0032 0033 void VideoScannerPrivate::newFrame(const QVideoFrame &videoFrame, bool verticallyFlipped) 0034 { 0035 // NOTE: this runs in the render thread 0036 if (!m_workerBusy && videoFrame.isValid()) { 0037 m_workerBusy = true; 0038 0039 VideoScannerFrame frame(videoFrame, verticallyFlipped, m_formats); 0040 // check if we are only allowed to access this in the render thread 0041 if (frame.copyRequired()) { 0042 frame.map(); 0043 if (frame.needsConversion()) { 0044 frame.convertToImage(); 0045 } else { 0046 frame.copyFrameData(m_frameDataBuffer); 0047 } 0048 frame.unmap(); 0049 } 0050 0051 Q_EMIT m_worker.scanFrameRequest(frame); 0052 } 0053 } 0054 0055 void VideoScannerPrivate::setResult(VideoScanner *q, const ScanResult &result) 0056 { 0057 m_workerBusy = false; 0058 if (m_result == result) { 0059 return; 0060 } 0061 0062 m_result = result; 0063 Q_EMIT q->resultChanged(result); 0064 0065 if (m_previousContent == result.content()) { 0066 return; 0067 } 0068 m_previousContent = result.content(); 0069 Q_EMIT q->resultContentChanged(result); 0070 } 0071 0072 VideoScanner::VideoScanner(QObject *parent) 0073 : QObject(parent) 0074 , d(new VideoScannerPrivate) 0075 { 0076 d->m_worker.moveToThread(&d->m_thread); 0077 connect( 0078 &d->m_worker, 0079 &VideoScannerWorker::result, 0080 this, 0081 [this](const ScanResult &result) { 0082 d->setResult(this, result); 0083 }, 0084 Qt::QueuedConnection); 0085 0086 d->m_thread.setObjectName(QStringLiteral("Prison Barcode Scanner Worker")); 0087 d->m_thread.start(); 0088 } 0089 0090 VideoScanner::~VideoScanner() 0091 { 0092 d->m_thread.quit(); 0093 d->m_thread.wait(); 0094 } 0095 0096 ScanResult VideoScanner::result() const 0097 { 0098 return d->m_result; 0099 } 0100 0101 Format::BarcodeFormats VideoScanner::formats() const 0102 { 0103 return d->m_formats; 0104 } 0105 0106 void VideoScanner::setFormats(Format::BarcodeFormats formats) 0107 { 0108 if (d->m_formats == formats) { 0109 return; 0110 } 0111 0112 d->m_formats = formats; 0113 Q_EMIT formatsChanged(); 0114 } 0115 0116 QVideoSink *VideoScanner::videoSink() const 0117 { 0118 return d->m_sink; 0119 } 0120 0121 void VideoScanner::setVideoSink(QVideoSink *sink) 0122 { 0123 if (d->m_sink == sink) { 0124 return; 0125 } 0126 0127 if (d->m_sink) { 0128 disconnect(d->m_sink, nullptr, this, nullptr); 0129 } 0130 d->m_sink = sink; 0131 connect(d->m_sink, &QVideoSink::videoFrameChanged, this, [this](const QVideoFrame &frame) { 0132 d->newFrame(frame, frame.surfaceFormat().scanLineDirection() == QVideoFrameFormat::BottomToTop); 0133 }); 0134 Q_EMIT videoSinkChanged(); 0135 } 0136 0137 #include "moc_videoscanner.cpp"