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"