Camera Preview Using Surface Texture

KillaKem

I am trying to use a SurfaceTexture to display a camera preview from the back camera of my device but I keep getting the error

bindTextureImage : error binding external texture image 0x2:0x502

Looking at the line that says

SurfaceTexture.UpdateTexImage()

Looking at the android documentation, it seems as though this might be caused by calling UpdateTexImage on the SurfaceTexture.OnFrameAvailableListener's OnFrameAvailable method.According to the documentation "the callback (SurfaceTexture.OnFrameAvailableListener) may be called on an arbitrary thread, so it is not safe to call updateTexImage() without first binding the OpenGL ES context to the thread invoking the callback".

How do I "bind the OpenGL ES context" to the thread invoking the callback?

I have just been trying to closely follow the "Texture from Camera" activity from the Grafika project to try and get clues on how I can achieve this task.Any help is appreciated.

My Full Code is pasted below:

public class CameraPreviewFromTextureActivity extends Activity 
{
private static String TAG = "CameraPreviewFromTexture";

private static SurfaceHolder mySurfaceHolder = null;    
private SurfaceTexture mCameraTexture = null;   
private Camera mCamera = null;  
private EglCore mEglCore;
private WindowSurface mWindowSurface;
private int mWindowSurfaceWidth;
private int mWindowSurfaceHeight;
private int mCameraPreviewWidth, mCameraPreviewHeight;
private float mCameraPreviewFps;
private Texture2dProgram mTexProgram;

@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_camera_preview_from_texture);

    mySurfaceHolder = ((SurfaceView)this.findViewById(R.id.surfaceView)).getHolder();
    mySurfaceHolder.addCallback(mySurfaceHolderCallback);

    //Run Thread Methods
    mEglCore = new EglCore(null, 0);
    openCamera(328, 288, 30);
}

private SurfaceHolder.Callback mySurfaceHolderCallback = new SurfaceHolder.Callback() 
{

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) 
    {
        releaseGl();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) 
    {
        surfaceAvailable(holder, true);         
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) 
    {
         Log.d(TAG, "SurfaceChanged " + width + "x" + height);

         mWindowSurfaceWidth = width;
         mWindowSurfaceHeight = height;
         finishSurfaceSetup();
    }
};


 private void surfaceAvailable(SurfaceHolder holder, boolean newSurface) 
 {
     Surface surface = holder.getSurface();
     mWindowSurface = new WindowSurface(mEglCore, surface, false);
     mWindowSurface.makeCurrent();

     // Create and configure the SurfaceTexture, which will receive frames from the
     // camera.  We set the textured rect's program to render from it.
     mTexProgram = new Texture2dProgram(Texture2dProgram.ProgramType.TEXTURE_EXT);
     int textureId = mTexProgram.createTextureObject();
     mCameraTexture = new SurfaceTexture(textureId);
     //mRect.setTexture(textureId);

     if (!newSurface) {
         // This Surface was established on a previous run, so no surfaceChanged()
         // message is forthcoming.  Finish the surface setup now.
         //
         // We could also just call this unconditionally, and perhaps do an unnecessary
         // bit of reallocating if a surface-changed message arrives.
         mWindowSurfaceWidth = mWindowSurface.getWidth();
         mWindowSurfaceHeight = mWindowSurface.getHeight();
         finishSurfaceSetup();
     }

     mCameraTexture.setOnFrameAvailableListener(myOnFrameListner);
 }

 private SurfaceTexture.OnFrameAvailableListener myOnFrameListner = new SurfaceTexture.OnFrameAvailableListener() 
 {  
    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) 
    {           
        surfaceTexture.updateTexImage();  //Problem Occurs Here
        draw();
    }
};

private void draw() 
{
    GlUtil.checkGlError("draw start");

    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    //mRect.draw(mTexProgram, mDisplayProjectionMatrix);
    mWindowSurface.swapBuffers();

    GlUtil.checkGlError("draw done");
}
 private void finishSurfaceSetup() 
 {
     int width = mWindowSurfaceWidth;
     int height = mWindowSurfaceHeight;

     // Use full window.
     GLES20.glViewport(0, 0, width, height);

     // Ready to go, start the camera.
     Log.d(TAG, "starting camera preview");
     try {
         mCamera.setPreviewTexture(mCameraTexture);
     } catch (IOException ioe) {
         throw new RuntimeException(ioe);
     }
     mCamera.startPreview();
 }

 private void openCamera(int desiredWidth, int desiredHeight, int desiredFps) 
 {
     if (mCamera != null) 
     {
         throw new RuntimeException("camera already initialized");
     }

     Camera.CameraInfo info = new Camera.CameraInfo();

    try
    {
        mCamera = Camera.open();
    }
    catch(Exception ex)
    {
        ex.printStackTrace();
    }

     Camera.Parameters parms = mCamera.getParameters();

     // Try to set the frame rate to a constant value.
     int thousandFps = chooseFixedPreviewFps(parms, desiredFps * 1000);

     // Give the camera a hint that we're recording video.  This can have a big
     // impact on frame rate.
     parms.setRecordingHint(true);

     mCamera.setParameters(parms);

     int[] fpsRange = new int[2];
     Camera.Size mCameraPreviewSize = parms.getPreviewSize();
     parms.getPreviewFpsRange(fpsRange);
     String previewFacts = mCameraPreviewSize.width + "x" + mCameraPreviewSize.height;
     if (fpsRange[0] == fpsRange[1]) {
         previewFacts += " @" + (fpsRange[0] / 1000.0) + "fps";
     } else {
         previewFacts += " @[" + (fpsRange[0] / 1000.0) +
                 " - " + (fpsRange[1] / 1000.0) + "] fps";
     }
     Log.i(TAG, "Camera config: " + previewFacts);

     mCameraPreviewWidth = mCameraPreviewSize.width;
     mCameraPreviewHeight = mCameraPreviewSize.height;
     mCameraPreviewFps = desiredFps;
 }


 public static int chooseFixedPreviewFps(Camera.Parameters parms, int desiredThousandFps) 
 {
        List<int[]> supported = parms.getSupportedPreviewFpsRange();

        for (int[] entry : supported) {
            //Log.d(TAG, "entry: " + entry[0] + " - " + entry[1]);
            if ((entry[0] == entry[1]) && (entry[0] == desiredThousandFps)) {
                parms.setPreviewFpsRange(entry[0], entry[1]);
                return entry[0];
            }
        }

        int[] tmp = new int[2];
        parms.getPreviewFpsRange(tmp);
        int guess;
        if (tmp[0] == tmp[1]) {
            guess = tmp[0];
        } else {
            guess = tmp[1] / 2;     // shrug
        }

        Log.d(TAG, "Couldn't find match for " + desiredThousandFps + ", using " + guess);
        return guess;
    }


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.camera_preview_from_texture, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

 private void releaseGl() {
     GlUtil.checkGlError("releaseGl start");

     if (mWindowSurface != null) {
         mWindowSurface.release();
         mWindowSurface = null;
     }
     if (mTexProgram != null) {
         mTexProgram.release();
         mTexProgram = null;
     }
     GlUtil.checkGlError("releaseGl done");

     mEglCore.makeNothingCurrent();
 }

 private void releaseCamera() {
     if (mCamera != null) {
         mCamera.stopPreview();
         mCamera.release();
         mCamera = null;
         Log.d(TAG, "releaseCamera -- done");
     }
 }

@Override
public void onDestroy()
{
    releaseCamera();
    releaseGl();
    mEglCore.release();
}

}
fadden

Each thread has a "current" EGL context, referenced by the GLES driver through thread-local storage. Any GLES commands you issue, including binding of textures, operate in this context.

A quick look through your code suggests that you're trying to do everything on the UI thread. If you create and make-current your own context, it will be fighting with the UI code, which is going to have its own EGL context for hardware-accelerated View rendering. Life is a bit simpler if you create a separate thread, make your EGL context current there, and then just leave it alone.

You can see that the "texture from camera" activity's frame-available handler is just:

    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
        mHandler.sendFrameAvailable();
    }

Because the frame-available message can arrive on an arbitrary thread, you don't know what EGL context will be current there (or if the thread will have one at all). You can call eglMakeCurrent() (via EglCore#makeCurrent()) to make yours current, but you aren't allowed to use the same EGL context from more than one thread, so if it's current somewhere else at the same time you could have a problem. So it's easier to just forward the frame-available message to the thread where you know your EGL context is current.

FWIW, 0x0502 is GL_INVALID_OPERATION​.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

How to create camera preview using API 21 android?

From Dev

Displaying camera preview using DirectX Texture2D causes oscillation on Windows Phone 8

From Dev

Android Camera Preview Stretched

From Dev

How to pass Camera preview to the Surface created by MediaCodec.createInputSurface()?

From Dev

show camera surface in service

From Dev

Camera Preview does not fill entire screen when using Fragment

From Dev

Android Camera preview in a fragment

From Dev

Capture picture without preview using camera2 API

From Dev

Dark Google Tango camera surface when using depth information

From Dev

Render camera preview on a Texture with target GL_TEXTURE_2D

From Dev

Looping a texture on a surface

From Dev

Textureview/Surface view for Camera preview - Android

From Dev

Camera Preview and OCR

From Dev

Camera preview is black when using getExternalStorageDirectory to save the video

From Dev

Tango Camera Preview for RGBIR

From Dev

Camera2 would not show preview using AutoFitTextureView

From Dev

Run another python file that shows camera preview using Tkinter window

From Dev

openGL texture from SDL Surface

From Dev

How to decode a barcode from camera preview using zxing library in android?

From Dev

Surface View Camera Preview

From Dev

Render camera preview in Chrome using Native Client SDK

From Dev

How to create a square camera preview aligned with the top of the rectangular camera frame in iOS8 using Swift

From Dev

Textureview/Surface view for Camera preview - Android

From Dev

Android runtime exception thrown when setting camera with null surface texture

From Dev

Luminance 'y' value of surface texture

From Dev

How to know camera preview successful or ready to snapshot using Directshow

From Dev

How to crop image from camera preview (surface view) and save it instead of actual image captured bt camera like instagram app?

From Dev

Camera Using custom Camera Preview Renderer is not clear

From Dev

Vuforia with Vive Camera texture

Related Related

  1. 1

    How to create camera preview using API 21 android?

  2. 2

    Displaying camera preview using DirectX Texture2D causes oscillation on Windows Phone 8

  3. 3

    Android Camera Preview Stretched

  4. 4

    How to pass Camera preview to the Surface created by MediaCodec.createInputSurface()?

  5. 5

    show camera surface in service

  6. 6

    Camera Preview does not fill entire screen when using Fragment

  7. 7

    Android Camera preview in a fragment

  8. 8

    Capture picture without preview using camera2 API

  9. 9

    Dark Google Tango camera surface when using depth information

  10. 10

    Render camera preview on a Texture with target GL_TEXTURE_2D

  11. 11

    Looping a texture on a surface

  12. 12

    Textureview/Surface view for Camera preview - Android

  13. 13

    Camera Preview and OCR

  14. 14

    Camera preview is black when using getExternalStorageDirectory to save the video

  15. 15

    Tango Camera Preview for RGBIR

  16. 16

    Camera2 would not show preview using AutoFitTextureView

  17. 17

    Run another python file that shows camera preview using Tkinter window

  18. 18

    openGL texture from SDL Surface

  19. 19

    How to decode a barcode from camera preview using zxing library in android?

  20. 20

    Surface View Camera Preview

  21. 21

    Render camera preview in Chrome using Native Client SDK

  22. 22

    How to create a square camera preview aligned with the top of the rectangular camera frame in iOS8 using Swift

  23. 23

    Textureview/Surface view for Camera preview - Android

  24. 24

    Android runtime exception thrown when setting camera with null surface texture

  25. 25

    Luminance 'y' value of surface texture

  26. 26

    How to know camera preview successful or ready to snapshot using Directshow

  27. 27

    How to crop image from camera preview (surface view) and save it instead of actual image captured bt camera like instagram app?

  28. 28

    Camera Using custom Camera Preview Renderer is not clear

  29. 29

    Vuforia with Vive Camera texture

HotTag

Archive