qzxing/examples/QZXingLive/QZXingFilter.h
Milian Wolff c882465649 Improve performance of rgb(a) reading, convert directly to greyscale
This again leads to a noticeable performance improvement of the
QZXingFilter example, as we get rid of one full copy of the image
data by converting directly into greyscale, instead of first
converting to RGB and then converting to greyscale.
2017-01-10 13:17:54 +01:00

109 lines
3.2 KiB
C++

#ifndef QZXingFilter_H
#define QZXingFilter_H
#include <QObject>
#include <QAbstractVideoFilter>
#include <QZXing.h>
///
/// References:
///
/// https://blog.qt.io/blog/2015/03/20/introducing-video-filters-in-qt-multimedia/
/// http://doc.qt.io/qt-5/qabstractvideofilter.html
/// http://doc.qt.io/qt-5/qml-qtmultimedia-videooutput.html#filters-prop
/// http://doc.qt.io/qt-5/qvideofilterrunnable.html
/// http://doc.qt.io/qt-5/qtconcurrent-runfunction-main-cpp.html
///
/// This is used to store a QVideoFrame info while we are searching the image for QRCodes.
struct SimpleVideoFrame
{
QByteArray data;
QSize size;
QVideoFrame::PixelFormat pixelFormat;
SimpleVideoFrame()
: size{0,0}
, pixelFormat{QVideoFrame::Format_Invalid}
{}
SimpleVideoFrame(QVideoFrame & frame)
{
copyData(frame);
}
void copyData(QVideoFrame & frame)
{
frame.map(QAbstractVideoBuffer::ReadOnly);
/// Copy video frame bytes to this.data
/// This is made to try to get a better performance (less memory allocation, faster unmap)
/// Any other task is performed in a QFuture task, as we want to leave the UI thread asap
if(data.size() != frame.mappedBytes())
{
qDebug() << "needed to resize";
data.resize(frame.mappedBytes());
}
memcpy(data.data(), frame.bits(), frame.mappedBytes());
size = frame.size();
pixelFormat = frame.pixelFormat();
frame.unmap();
}
};
/// Video filter is the filter that has to be registered in C++, instantiated and attached in QML
class QZXingFilter : public QAbstractVideoFilter
{
friend class QZXingFilterRunnable;
Q_OBJECT
Q_PROPERTY(bool decoding READ isDecoding NOTIFY isDecodingChanged)
Q_PROPERTY(QZXing* decoder READ getDecoder)
Q_PROPERTY(QRectF captureRect MEMBER captureRect NOTIFY captureRectChanged)
signals:
void isDecodingChanged();
void decodingFinished(bool succeeded, int decodeTime);
void decodingStarted();
void captureRectChanged();
private slots:
void handleDecodingStarted();
void handleDecodingFinished(bool succeeded);
private: /// Attributes
QZXing decoder;
bool decoding;
QRectF captureRect;
SimpleVideoFrame frame;
QFuture<void> processThread;
public: /// Methods
explicit QZXingFilter(QObject *parent = 0);
virtual ~QZXingFilter();
bool isDecoding() {return decoding; }
QZXing* getDecoder() { return &decoder; }
QVideoFilterRunnable * createFilterRunnable();
};
/// A new Runnable is created everytime the filter gets a new frame
class QZXingFilterRunnable : public QObject, public QVideoFilterRunnable
{
Q_OBJECT
public:
explicit QZXingFilterRunnable(QZXingFilter * filter);
/// This method is called whenever we get a new frame. It runs in the UI thread.
QVideoFrame run(QVideoFrame * input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags);
void processVideoFrameProbed(SimpleVideoFrame & videoFrame, const QRect& captureRect);
private:
QZXingFilter * filter;
};
#endif // QZXingFilter_H