Я пытаюсь получить изображения с камеры, используя QCamera.
Я подумал, что должен извлечь из QAbstractVideoSurface
и реализовать present()
, где QVideoFrame
, представляющий текущее изображение, снятое камерой, отправляется в качестве параметра.
Поскольку мне нужно выполнить некоторую обработку, я попытался map()
мой кадр, получить данные с помощью bits()
, сделать все, что мне нужно, затем unmap()
. Однако у меня сбой на map()
Вот ошибки, которые я получаю:
W libTest.so: (null):0 ((null)): Unsupported viewfinder pixel format
D SensorManager: registerListener :: 6, LSM6DSL Acceleration Sensor, 200000, 0,
E libEGL : call to OpenGL ES API with no current context (logged once per thread)
E GLConsumer: [SurfaceTexture-0-546-0] attachToContext: invalid current EGLDisplay
F libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x4 in tid 663 (qtMainLoopThrea)
Что я делаю не так?
Вот полный код приложения:
///////////////////////////////////////////////
//main.cpp
///////////////////////////////////////////////
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "camera_engine.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
CameraEngine camEngine;
engine.rootContext()->setContextProperty("cameraEngine", &camEngine);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
///////////////////////////////////////////////
//camera_engine.h
///////////////////////////////////////////////
#ifndef __CAMERA_ENGINE_H__
#define __CAMERA_ENGINE_H__
#include <QCamera>
#include "image_reader.h"
class CameraEngine : public QObject {
Q_OBJECT
public:
explicit CameraEngine(QCamera::Position pos = QCamera::BackFace);
~CameraEngine();
public slots:
void start();
private:
QCamera mCamera;
ImageReader mImageReader;
};
#endif // __CAMERA_ENGINE_H__
///////////////////////////////////////////////
//camera_engine.cpp
///////////////////////////////////////////////
#include "camera_engine.h"
CameraEngine::CameraEngine(QCamera::Position pos) : mCamera(pos)
{
mCamera.setViewfinder(&mImageReader);
QCameraViewfinderSettings viewFinderSettings;
viewFinderSettings.setResolution(640, 480);
viewFinderSettings.setMinimumFrameRate(30);
viewFinderSettings.setMaximumFrameRate(30);
viewFinderSettings.setPixelFormat(QVideoFrame::Format_RGB24);
mCamera.setViewfinderSettings(viewFinderSettings);
}
CameraEngine::~CameraEngine()
{
if (mCamera.state() == QCamera::ActiveState) {
mCamera.stop();
}
}
void CameraEngine::start()
{
mCamera.start();
}
///////////////////////////////////////////////
//image_reader.h
///////////////////////////////////////////////
#ifndef CAMERA_IMAGE_READER_H
#define CAMERA_IMAGE_READER_H
#include <QAbstractVideoSurface>
class ImageReader : public QAbstractVideoSurface {
Q_OBJECT
public:
ImageReader() = default;
~ImageReader() = default;
virtual bool present(const QVideoFrame& frame);
virtual QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const;
};
#endif // CAMERA_IMAGE_READER_H
///////////////////////////////////////////////
//image_reader.cpp
///////////////////////////////////////////////
#include "image_reader.h"
#include <QDebug>
bool ImageReader::present(const QVideoFrame &frame)
{
QVideoFrame currentFrame = frame;
currentFrame.map(QAbstractVideoBuffer::ReadOnly); //crashes here
// Do something
currentFrame.unmap();
return true;
}
QList<QVideoFrame::PixelFormat> ImageReader::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const
{
Q_UNUSED(type)
return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_RGB24;
}
///////////////////////////////////////////////
//main.qml
///////////////////////////////////////////////
import QtQuick 2.11
import QtQuick.Controls 2.2
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
Component.onCompleted: cameraEngine.start()
}
Редактировать: Итак, я думаю, что это может быть потому, что мой QVideoFrame хранится в виде текстуры OpenGL, а моя функция present()
может не работать в потоке OpenGL, таким образом, не находя контекст ES OpenGL.
Есть ли способ убедиться, что он работает в нужном потоке?
Edit2: я нашел это: http://doc.qt.io/qt-5/qtquick-scenegraph-openglunderqml-example.html
Может быть, я смогу адаптировать этот код, чтобы получить действительный контекст OpenGL ES. К сожалению, у меня нет времени, чтобы сделать это сейчас. Я попробую в этот понедельник, если у кого-то не будет лучшего предложения, и расскажу вам результаты.
Edit3: Так что, видимо, мое решение было не лучшим, я получаю сбой (SIGSEGV) на initializeOpenGLFunctions();
Я видел ответ Антонио Диаса, используя VideoOutput
с функцией grabToImage
, попробовал его, и он, кажется, работает, но, если я правильно понимаю, grabToImage
"рисует" VideoOutput
в CPU памяти, и я теряю некоторые метаданные, которые планировал получить с помощью QMediaMetaData
в процессе.
Я также пытался использовать NDK напрямую, но для камеры требуется уровень API не менее 24, и даже после установки всех соответствующих настроек, которые я обнаружил, он, похоже, не использует его.
Edit4: я на самом деле не знаю, что я сделал, но моя программа закончила с использованием правильного уровня API, поэтому сейчас я перейду к решению NDK.