From b915c5e0e795123a4158b920943160136f8ef06c Mon Sep 17 00:00:00 2001 From: Lev Zelenskiy Date: Thu, 19 Jul 2012 14:55:52 +1000 Subject: [PATCH] Player example histogram: Process frames on a separate thread Change-Id: I6989f9ea9cb6e45c54ed75079a5b5748e15ee0d8 Reviewed-by: Dmytro Poplavskiy Reviewed-by: Michael Goddard --- examples/player/histogramwidget.cpp | 127 +++++++++++++++++----------- examples/player/histogramwidget.h | 16 ++++ 2 files changed, 93 insertions(+), 50 deletions(-) diff --git a/examples/player/histogramwidget.cpp b/examples/player/histogramwidget.cpp index cf7ae6ff..d9327519 100644 --- a/examples/player/histogramwidget.cpp +++ b/examples/player/histogramwidget.cpp @@ -44,63 +44,34 @@ HistogramWidget::HistogramWidget(QWidget *parent) : QWidget(parent) , m_levels(128) + , m_isBusy(false) { + m_processor.moveToThread(&m_processorThread); + qRegisterMetaType >("QVector"); + connect(&m_processor, SIGNAL(histogramReady(QVector)), SLOT(setHistogram(QVector))); + m_processorThread.start(QThread::LowestPriority); +} + +HistogramWidget::~HistogramWidget() +{ + m_processorThread.quit(); + m_processorThread.wait(10000); } void HistogramWidget::processFrame(QVideoFrame frame) { - m_histogram.clear(); + if (m_isBusy) + return; //drop frame - do { - if (!m_levels) - break; - - if (!frame.map(QAbstractVideoBuffer::ReadOnly)) - break; - - m_histogram.resize(m_levels); - - if (frame.pixelFormat() == QVideoFrame::Format_YUV420P) { - // Process YUV420P data - uchar *b = frame.bits(); - for (int y = 0; y < frame.height(); y++) { - uchar *lastPixel = b + frame.width(); - for (uchar *curPixel = b; curPixel < lastPixel; curPixel++) - m_histogram[(*curPixel * m_levels) / 256] += 1.0; - b += frame.bytesPerLine(); - } - } else { - QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat()); - if (imageFormat != QImage::Format_Invalid) { - // Process RGB data - QImage image(frame.bits(), frame.width(), frame.height(), imageFormat); - image = image.convertToFormat(QImage::Format_RGB32); - - const QRgb* b = (const QRgb*)image.bits(); - for (int y = 0; y < image.height(); y++) { - const QRgb *lastPixel = b + frame.width(); - for (const QRgb *curPixel = b; curPixel < lastPixel; curPixel++) - m_histogram[(qGray(*curPixel) * m_levels) / 256] += 1.0; - b = (const QRgb*)((uchar*)b + image.bytesPerLine()); - } - } - } - - // find maximum value - qreal maxValue = 0.0; - for (int i = 0; i < m_histogram.size(); i++) { - if (m_histogram[i] > maxValue) - maxValue = m_histogram[i]; - } - - if (maxValue > 0.0) { - for (int i = 0; i < m_histogram.size(); i++) - m_histogram[i] /= maxValue; - } - - frame.unmap(); - } while (false); + m_isBusy = true; + QMetaObject::invokeMethod(&m_processor, "processFrame", + Qt::QueuedConnection, Q_ARG(QVideoFrame, frame), Q_ARG(int, m_levels)); +} +void HistogramWidget::setHistogram(QVector histogram) +{ + m_isBusy = false; + m_histogram = histogram; update(); } @@ -125,3 +96,59 @@ void HistogramWidget::paintEvent(QPaintEvent *event) painter.fillRect(barWidth * i, 0, barWidth * (i + 1), height() - h, Qt::black); } } + +void FrameProcessor::processFrame(QVideoFrame frame, int levels) +{ + QVector histogram(levels); + + do { + if (!levels) + break; + + if (!frame.map(QAbstractVideoBuffer::ReadOnly)) + break; + + if (frame.pixelFormat() == QVideoFrame::Format_YUV420P || + frame.pixelFormat() == QVideoFrame::Format_NV12) { + // Process YUV data + uchar *b = frame.bits(); + for (int y = 0; y < frame.height(); y++) { + uchar *lastPixel = b + frame.width(); + for (uchar *curPixel = b; curPixel < lastPixel; curPixel++) + histogram[(*curPixel * levels) >> 8] += 1.0; + b += frame.bytesPerLine(); + } + } else { + QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat()); + if (imageFormat != QImage::Format_Invalid) { + // Process RGB data + QImage image(frame.bits(), frame.width(), frame.height(), imageFormat); + image = image.convertToFormat(QImage::Format_RGB32); + + const QRgb* b = (const QRgb*)image.bits(); + for (int y = 0; y < image.height(); y++) { + const QRgb *lastPixel = b + frame.width(); + for (const QRgb *curPixel = b; curPixel < lastPixel; curPixel++) + histogram[(qGray(*curPixel) * levels) >> 8] += 1.0; + b = (const QRgb*)((uchar*)b + image.bytesPerLine()); + } + } + } + + // find maximum value + qreal maxValue = 0.0; + for (int i = 0; i < histogram.size(); i++) { + if (histogram[i] > maxValue) + maxValue = histogram[i]; + } + + if (maxValue > 0.0) { + for (int i = 0; i < histogram.size(); i++) + histogram[i] /= maxValue; + } + + frame.unmap(); + } while (false); + + emit histogramReady(histogram); +} diff --git a/examples/player/histogramwidget.h b/examples/player/histogramwidget.h index 2d1883ff..d15b8411 100644 --- a/examples/player/histogramwidget.h +++ b/examples/player/histogramwidget.h @@ -43,18 +43,31 @@ #include #include +#include QT_USE_NAMESPACE +class FrameProcessor: public QObject { + Q_OBJECT + +public slots: + void processFrame(QVideoFrame frame, int levels); + +signals: + void histogramReady(QVector histogram); +}; + class HistogramWidget : public QWidget { Q_OBJECT public: explicit HistogramWidget(QWidget *parent = 0); + ~HistogramWidget(); void setLevels(int levels) { m_levels = levels; } public slots: void processFrame(QVideoFrame frame); + void setHistogram(QVector histogram); protected: void paintEvent(QPaintEvent *event); @@ -62,6 +75,9 @@ protected: private: QVector m_histogram; int m_levels; + FrameProcessor m_processor; + QThread m_processorThread; + bool m_isBusy; }; #endif // HISTOGRAMWIDGET_H