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"