Unsolved JNI Android camera. bindTextureImage: clearing GL error
-
Hello everyone.
Help me about correct work with OpenGL texture.
I use classes for JNI Android camera working by https://zarubond.com/android-camera/
Author did not provide a way to work with the camera and I added by myself.
I'm not sure how to create and clean the texture.
Example below works on Samsung Galaxy J7, but occurs:
W GLConsumer: [SurfaceTexture-1-20202-0] bindTextureImage: clearing GL error: 0x500,
-- on Samsung S4.framegrabber.cpp
#include "framegrabber.h" #include <QDebug> FrameGrabber::FrameGrabber(QScreen *screen) : QWindow(screen), m_vSize(1920, 1080) { m_iCameraFrameRate = 0; setSurfaceType(OpenGLSurface); create(); // Create an OpenGL context m_pContext = new QOpenGLContext; m_pContext->create(); m_pContext->makeCurrent(this); initializeOpenGLFunctions(); QObject::connect(&m_camera, &Camera::frameAvailable, this, &FrameGrabber::processFrame); connect(&m_timer, &QTimer::timeout, this, &FrameGrabber::updateCameraFrameRate); m_timer.start(1000); } void FrameGrabber::startCamera() { glGenTextures(1, &m_textureId); glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_textureId); m_camera.start(m_vSize.width(), m_vSize.height(), m_textureId); } void FrameGrabber::processFrame() { QImage img(m_vSize.width(), m_vSize.height(), QImage::Format_RGBA8888); GLuint fbo; glGenFramebuffers(1, &fbo); GLuint prevFbo; glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_EXTERNAL_OES/*GL_TEXTURE_2D*/, m_textureId, 0); glReadPixels(0, 0, m_vSize.width(), m_vSize.height(), GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); // glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); /* App works on Samsung Galaxy J7, but on Galaxy S4 it produces an error */ // W GLConsumer: [SurfaceTexture-1-20202-0] bindTextureImage: clearing GL error: 0x500 emit signalShowFrame(img); m_iCameraFrameRate++; m_camera.updateFrame(); } void FrameGrabber::updateCameraFrameRate() { emit signalCameraFrameRate(m_iCameraFrameRate); m_iCameraFrameRate = 0; }
framegrabber.h
#ifndef SOMECLASS_H #define SOMECLASS_H #include "camera.h" #include <QWindow> #include <QOpenGLWidget> #include <QOpenGLFunctions> #include <qopengl.h> #include <QTimer> #include <QObject> class FrameGrabber : public QWindow, protected QOpenGLFunctions { Q_OBJECT public: FrameGrabber(QScreen *screen = 0); void startCamera(); public slots: void processFrame(); void updateCameraFrameRate(); signals: void signalCameraFrameRate(int iFPS); void signalShowFrame(QImage imgFrame); private: Camera m_camera; QSize m_vSize; GLuint m_textureId; QOpenGLContext* m_pContext; QTimer m_timer; int m_iCameraFrameRate; }; #endif // SOMECLASS_H
camera.h
#ifndef CAMERA_H #define CAMERA_H #include <QtCore> #include <QAndroidJniEnvironment> #include <QAndroidJniObject> #include <QOpenGLFunctions> class Camera: public QObject { Q_OBJECT public: Camera(); ~Camera(); void start(int width, int height, GLuint textureId); void updateFrame(); void stop(); void close(); signals: void frameAvailable(); private: static void onFrameAvailable(JNIEnv*, jobject); private: QAndroidJniObject* m_pJavaBackend; static Camera* m_pSelf; }; #endif // CAMERA_H
camera.cpp
#include "camera.h" Camera* Camera::m_pSelf = NULL; Camera::Camera() { m_pSelf = this; JNINativeMethod methods[] { {"frameAvailable", "()V", reinterpret_cast<void *>(Camera::onFrameAvailable)}}; if (QAndroidJniObject::isClassAvailable("com/zarubond/lookingglass/CameraBackend")) { m_pJavaBackend=new QAndroidJniObject("com/zarubond/lookingglass/CameraBackend","()V"); if(m_pJavaBackend->isValid()) { QAndroidJniEnvironment env; jclass objectClass = env->GetObjectClass(m_pJavaBackend->object<jobject>()); env->RegisterNatives(objectClass, methods, sizeof(methods) / sizeof(methods[0])); env->DeleteLocalRef(objectClass); } } } Camera::~Camera() { close(); delete m_pJavaBackend; } void Camera::start(int width, int height, GLuint textureId) { m_pJavaBackend->callMethod<void>("startPreview", "(III)V",(jint)width, (jint)height, (jint) textureId); } void Camera::updateFrame() { m_pJavaBackend->callMethod<void>("updateFrame", "()V"); } void Camera::stop() { close(); } void Camera::close() { m_pJavaBackend->callMethod<void>("stopPreview", "()V"); } void Camera::onFrameAvailable(JNIEnv*, jobject) { emit m_pSelf->frameAvailable(); }
CameraBackend.java
package com.zarubond.lookingglass; import android.hardware.Camera; import android.hardware.Camera.PreviewCallback; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.graphics.SurfaceTexture; import android.widget.FrameLayout; import android.view.ViewGroup.LayoutParams; import java.io.IOException; import android.app.Activity; import java.util.List; public class CameraBackend implements SurfaceTexture.OnFrameAvailableListener { private Camera camera; private static SurfaceTexture surface; public CameraBackend(){ } public void startPreview (int width, int height, int textureId) { surface=new SurfaceTexture(textureId); camera = Camera.open(); surface.setOnFrameAvailableListener(this); try { camera.setPreviewTexture(surface); } catch (IOException e) { camera.release(); return; } Camera.Parameters parameters = camera.getParameters(); parameters.setRecordingHint(true); parameters.setPreviewFpsRange(30000, 30000); android.hardware.Camera.Size preferredPreviewSize = parameters.getPreferredPreviewSizeForVideo (); parameters.setPreviewSize(width, height); camera.setParameters(parameters); camera.startPreview(); } public void stopPreview () { camera.stopPreview(); camera.setPreviewCallbackWithBuffer(null); camera.release(); surface.release(); camera = null; } public void onFrameAvailable (SurfaceTexture surfaceTexture) { frameAvailable(); } public void updateFrame() { synchronized(this) { surface.updateTexImage(); } } public static native void frameAvailable(); }
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include "framegrabber.h" #include "FramePlayer.h" #include <QQmlContext> int main(int argc, char *argv[]) { qmlRegisterType<FramePlayer>("ska.lpr_mobile", 1, 0, "FramePlayer"); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; FrameGrabber frameGrabber; frameGrabber.startCamera(); engine.rootContext()->setContextProperty("frameGrabber", &frameGrabber); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }