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();
    }
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.