Я пытаюсь использовать функциональность QCamera QT для сканирования штрих-кодов. Мое устройство - устройство без головы, которое использует Wayland. Я использую QT 5.9.1 и gstreamer 1.0 - v1.14. На моем устройстве есть плагин camerabin2, и я могу использовать gstreamer для записи видео / фотографий в одиночку. Ранее я делал снимок с помощью отдельного конвейера gstreamer, собирал файл и передавал изображение в QZXing для обработки, но это было довольно медленно. Я хотел посмотреть, смогу ли я повысить производительность от использования QCamera напрямую с QZXing, но, к сожалению, я сталкиваюсь с некоторыми ошибками gstreamer.
Вот мой код:
#include <QFile>
#include <QZXing.h>
#include <QCamera>
#include <QCameraInfo>
#include <QCameraImageCapture>
#include <QCameraViewfinder>
#include <QRegularExpressionMatch>
#include "wirelesscontrollermain.hpp"
#include "barcodereader.hpp"
#include "calibrationhandler.hpp"
#include "jsonhelper.hpp"
namespace
{
const int BARCODE_TIMEOUT_15S = 15000;
QZXing* mDecoder;
QCamera* mCamera;
QCameraImageCapture* mImageCapture;
QCameraViewfinder* mViewFinder;
}
BarcodeReader::BarcodeReader(WirelessControllerMain &parent)
: mParent(parent)
, mIsScanningActive(false)
, mTimeoutExpired(false)
, mScanningTimeout(this)
{
mScanningTimeout.setInterval(BARCODE_TIMEOUT_15S);
mScanningTimeout.setSingleShot(true);
QObject::connect(&mScanningTimeout, SIGNAL(timeout()), this, SLOT(onBarcodeFailureTimeout()));
}
BarcodeReader::~BarcodeReader()
{
delete mDecoder;
mDecoder = NULL;
delete mCamera;
mCamera = NULL;
delete mImageCapture;
mImageCapture = NULL;
}
void BarcodeReader::init()
{
if(QCameraInfo::availableCameras().count() > 0)
{
qWarning() << "we have cameras";
const QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
for (const QCameraInfo &cameraInfo : cameras)
{
qCritical() << cameraInfo.deviceName();
}
}
mCamera = new QCamera(QCameraInfo::defaultCamera());
mImageCapture = new QCameraImageCapture(mCamera);
QObject::connect(mImageCapture, SIGNAL(imageCaptured(int,QImage)), this, SLOT(pictureReady(int,QImage)));
QObject::connect(mImageCapture, SIGNAL(imageAvailable(int,QVideoFrame)), this, SLOT(pictureReady(int,QVideoFrame)));
QObject::connect(mImageCapture, SIGNAL(error(int,QCameraImageCapture::Error,QString)), this, SLOT(onImgCapError(int, QCameraImageCapture::Error, QString)));
QObject::connect(mImageCapture, SIGNAL(readyForCaptureChanged(bool)), this, SLOT(onReadyForCapture(bool)));
QObject::connect(mCamera, SIGNAL(lockStatusChanged(QCamera::LockStatus,QCamera::LockChangeReason)), this, SLOT(onLockStatusChange(QCamera::LockStatus, QCamera::LockChangeReason)));
mCamera->setCaptureMode(QCamera::CaptureStillImage);
mCamera->start();
mViewFinder = new QCameraViewfinder();
mViewFinder->show();
mCamera->setViewfinder(mViewFinder);
}
void BarcodeReader::onReadyForCapture(bool isReadyForCapture)
{
if(isReadyForCapture)
{
qCritical() << "ready for capture";
}
else
{
qCritical() << "not ready for capture";
}
}
void BarcodeReader::onImgCapError(int value, QCameraImageCapture::Error error, QString string)
{
qWarning() << "integer: " <<value << "error:" << error << "string:" << string;
}
void BarcodeReader::onLockStatusChange(QCamera::LockStatus lockstatus, QCamera::LockChangeReason reason)
{
qWarning() << "lock status: " << lockstatus << "reason: " << reason;
}
/*!
* \brief BarcodeReader::startBarcodeScan
* called when the barcode scan button has been pressed
*/
void BarcodeReader::startBarcodeScan()
{
if(!mIsScanningActive)
{
qDebug() << "start barcode scan";
qWarning() <<"is capture mode supported?" << mCamera->isCaptureModeSupported(QCamera::CaptureStillImage);
if(mDecoder != NULL)
{
delete mDecoder;
mDecoder = NULL;
}
mDecoder = new QZXing();
QObject::connect(mDecoder, SIGNAL(error(QString)), this, SLOT(decodeError(QString)));
mDecoder->setDecoder(QZXing::DecoderFormat_EAN_8 | QZXing::DecoderFormat_EAN_13 | QZXing::DecoderFormat_QR_CODE | QZXing::DecoderFormat_DATA_MATRIX);
mIsScanningActive = true;
mCurrentBarcodeValue.clear();
mScanningTimeout.stop();
mScanningTimeout.start();
qCritical() << "camera state: " << mCamera->state();
qCritical() << "camera availability" << mCamera->availability();
if(mImageCapture->isReadyForCapture())
{
mImageCapture->capture();
}
else
{
qWarning() << "not ready for capture";
}
}
else
{
qWarning() << "barcode scanning already active";
}
}
void BarcodeReader::pictureReady(int id, const QVideoFrame &preview)
{
qWarning() << "PICTURE READY - videoframe";
}
void BarcodeReader::pictureReady(int id, const QImage &preview)
{
qWarning() << "PICTURE READY";
QString result = mDecoder->decodeImage(preview);
if(result.isEmpty())
{
if(mTimeoutExpired)
{
//if the timeout expired while we were waiting for a picture to be taken
//process the last image and then call it quits
endBarcodeScan();
}
else
{
qWarning() << "try another barcode pic";
mCamera->start();
//take a new picture and hope for the best
if(mImageCapture->isReadyForCapture())
{
mImageCapture->capture();
mCamera->unlock();
}
else
{
qWarning() << "not ready for capture";
}
}
}
}
/*!
* \brief BarcodeReader::decodeError
* \param err - gets called when QZXing encounters a scan error
*/
void BarcodeReader::decodeError(QString err)
{
qWarning() << "Decode Error: " << err;
}
/*!
* \brief BarcodeReader::onBarcodeFailureTimeout
* if weve been scanning for barcodes for X time and havent found anything,
* this function gets called by the timer
*/
void BarcodeReader::onBarcodeFailureTimeout()
{
qWarning() << "Could not find barcode: timeout expired";
mTimeoutExpired = true;
}
и вот соответствующие выходные данные отладки приложения QT
BarcodeReader::init - we have cameras
BarcodeReader::init - "/dev/video0"
BarcodeReader::init - "/dev/video1"
(qWirelessController:29981): GStreamer-CRITICAL **: gst_element_link_pads_full: assertion 'GST_IS_ELEMENT (src)' failed
(qWirelessController:29981): GStreamer-CRITICAL **: gst_object_unref: assertion 'object != NULL' failed
- CameraBin error: "GStreamer error: negotiation problem."
- Unable to query the parameter info: "Invalid argument"
- Unable to query the parameter info: "Invalid argument"
- Unable to query the parameter info: "Invalid argument"
- Unable to query the parameter info: "Invalid argument"
- Unable to query the parameter info: "Invalid argument"
- Unable to query the parameter info: "Invalid argument"
BarcodeReader::startBarcodeScan - start barcode scan
BarcodeReader::startBarcodeScan - is capture mode supported? true
BarcodeReader::startBarcodeScan - camera state: QCamera::ActiveState
BarcodeReader::startBarcodeScan - camera availability 0
BarcodeReader::startBarcodeScan - not ready for capture
BarcodeReader::onBarcodeFailureTimeout - Could not find barcode: timeout expired
и вот небольшая часть вывода gst_debug = 4, где происходит ошибка
:00:28.200701097 19677 0x1722a00 INFO viewfinderbin gstviewfinderbin.c:312:gst_viewfinder_bin_set_video_sink:<vf-bin> Setting video sink to <qgstvideorenderersink0>
0:00:28.218930847 19677 0x1722a00 INFO wrappercamerabinsrc gstwrappercamerabinsrc.c:995:set_capsfilter_caps:<camera_source> new_caps:ANY
0:00:28.233847264 19677 0x1722a00 INFO wrappercamerabinsrc gstwrappercamerabinsrc.c:884:gst_wrapper_camera_bin_src_set_zoom:<camera_source> setting zoom 1.000000
0:00:28.251089431 19677 0x1722a00 INFO wrappercamerabinsrc gstwrappercamerabinsrc.c:890:gst_wrapper_camera_bin_src_set_zoom:<camera_source> zoom set using digitalzoom
0:00:28.268826264 19677 0x1722a00 INFO GST_EVENT gstevent.c:1517:gst_event_new_reconfigure: creating reconfigure event
0:00:28.283702722 19677 0x1722a00 INFO GST_EVENT gstevent.c:1517:gst_event_new_reconfigure: creating reconfigure event
0:00:28.298587347 19677 0x1722a00 INFO wrappercamerabinsrc gstwrappercamerabinsrc.c:1003:set_capsfilter_caps:<camera_source> updated
0:00:28.313344514 19677 0x1722a00 INFO GST_STATES gstbin.c:2089:gst_bin_get_state_func:<preview-pipeline> getting state
0:00:28.328236139 19677 0x1722a00 INFO GST_ELEMENT_PADS gstpad.c:2134:gst_pad_unlink: unlinking preview-appsrc:src(0x18ced98) and preview-vscale:sink(0x18d2460)
0:00:28.346451306 19677 0x1722a00 INFO GST_ELEMENT_PADS gstpad.c:2188:gst_pad_unlink: unlinked preview-appsrc:src and preview-vscale:sink
0:00:28.362642306 19677 0x1722a00 INFO GST_ELEMENT_PADS gstutils.c:1774:gst_element_link_pads_full: trying to link element preview-appsrc:src to element preview-vscale:sink
0:00:28.381914181 19677 0x1722a00 INFO GST_ELEMENT_PADS gstelement.c:920:gst_element_get_static_pad: found pad preview-appsrc:src
0:00:28.397408972 19677 0x1722a00 INFO GST_ELEMENT_PADS gstelement.c:920:gst_element_get_static_pad: found pad preview-vscale:sink
0:00:28.412992139 19677 0x1722a00 INFO GST_PADS gstutils.c:1588:prepare_link_maybe_ghosting: preview-appsrc and preview-vscale in same bin, no need for ghost pads
0:00:28.432092806 19677 0x1722a00 INFO GST_PADS gstpad.c:2378:gst_pad_link_prepare: trying to link preview-appsrc:src and preview-vscale:sink
0:00:28.449303764 19677 0x1722a00 INFO GST_PADS gstpad.c:2586:gst_pad_link_full: linked preview-appsrc:src and preview-vscale:sink, successful
0:00:28.466614764 19677 0x1722a00 INFO GST_EVENT gstevent.c:1517:gst_event_new_reconfigure: creating reconfigure event
0:00:28.481535556 19677 0x1722a00 INFO GST_EVENT gstpad.c:5808:gst_pad_send_event_unchecked:<preview-appsrc:src> Received event on flushing pad. Discarding
0:00:28.499853681 19677 0x1722a00 INFO GST_STATES gstbin.c:2954:gst_bin_change_state_func:<camerabin> child 'imagebin-filesink' changed state to 2(READY) successfully
0:00:28.518643139 19677 0x1722a00 INFO GST_STATES gstbin.c:2954:gst_bin_change_state_func:<camerabin> child 'videobin-filesink' changed state to 2(READY) successfully
0:00:28.537619556 19677 0x1722a00 INFO GST_STATES gstbin.c:2506:gst_bin_element_set_state:<vf-bin> current NULL pending VOID_PENDING, desired next READY
0:00:28.555408306 19677 0x1722a00 INFO GST_ELEMENT_PADS gstpad.c:2134:gst_pad_unlink: unlinking vfbin->videoscale:src(0x196f780) and fakesink0:sink(0x18d2868)
0:00:28.573421056 19677 0x1722a00 INFO GST_ELEMENT_PADS gstpad.c:2188:gst_pad_unlink: unlinked vfbin->videoscale:src and fakesink0:sink
0:00:28.589460389 19677 0x1722a00 INFO GST_PARENTAGE gstbin.c:1801:gst_bin_remove_func:<vf-bin> removed child "fakesink0"
0:00:28.604571931 19677 0x1722a00 INFO GST_PARENTAGE gstbin.c:4468:gst_bin_get_by_name: [vf-bin]: looking up child element vfbin-videscale
(qWirelessController:19677): GStreamer-CRITICAL **: gst_element_link_pads_full: assertion 'GST_IS_ELEMENT (src)' failed
0:00:28.632689764 19677 0x1722a00 WARN viewfinderbin gstviewfinderbin.c:237:gst_viewfinder_bin_create_elements:<vf-bin> error: linking videoscale and viewfindersink failed
0:00:28.651664431 19677 0x1722a00 INFO GST_ERROR_SYSTEM gstelement.c:2145:gst_element_message_full_with_details:<vf-bin> posting message: GStreamer error: negotiation problem.
0:00:28.671232931 19677 0x1722a00 INFO GST_ERROR_SYSTEM gstelement.c:2172:gst_element_message_full_with_details:<vf-bin> posted error message: GStreamer error: negotiation problem.
(qWirelessController:19677): GStreamer-CRITICAL **: gst_object_unref: assertion 'object != NULL' failed
0:00:28.701280723 19677 0x1722a00 INFO GST_STATES gstbin.c:2506:gst_bin_element_set_state:<qgstvideorenderersink0> current NULL pending VOID_PENDING, desired next READY
0:00:28.720489598 19677 0x1722a00 INFO GST_STATES gstelement.c:2676:gst_element_continue_state:<qgstvideorenderersink0> completed state change to READY
0:00:28.738063973 19677 0x1722a00 INFO GST_STATES gstelement.c:2579:_priv_gst_element_state_changed:<qgstvideorenderersink0> notifying about state-changed NULL to READY (VOID_PENDING pending)
Кто-нибудь знает, что является причиной этой ошибки? Я могу предоставить полные журналы, если кто-то считает это полезным.