android– 使用表面纹理的相机预览

android– 使用表面纹理的相机预览,第1张

概述我正在尝试使用SurfaceTexture从我的设备的后置摄像头显示摄像头预览,但我一直收到错误bindTextureImage:errorbindingexternaltextureimage0x2:0x502看着说的那条线SurfaceTexture.UpdateTexImage()看看android文档,似乎这可能是由于在SurfaceTexture.OnFrameAvai

我正在尝试使用SurfaceTexture从我的设备的后置摄像头显示摄像头预览,但我一直收到错误

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

看着说的那条线

SurfaceTexture.UpdateTexImage()

看看androID文档,似乎这可能是由于在SurfaceTexture.OnFrameAvailableListener的OnFrameAvailable方法上调用UpdateTexImage引起的.根据文档“可以在任意线程上调用回调(SurfaceTexture.OnFrameAvailableListener),所以它不安全调用updateTexImage()而不先将OpenGL ES上下文绑定到调用回调的线程“.

如何“将OpenGL ES上下文绑定”到调用回调的线程?

我一直在努力密切关注Grafika项目中的“相机纹理”活动,试图找到我如何能够完成这项任务的线索.非常感谢.

我的完整代码粘贴在下面:

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;@OverrIDeprotected 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;    }@OverrIDepublic 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;}@OverrIDepublic 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");     } }@OverrIDepublic voID onDestroy(){    releaseCamera();    releaseGl();    mEglCore.release();}}

解决方法:

每个线程都有一个“当前”EGL上下文,由GLES驱动程序通过线程本地存储引用.您发出的任何GLES命令(包括纹理绑定)都在此上下文中运行.

快速查看代码表明您正在尝试在UI线程上执行所有 *** 作.如果您创建并创建当前自己的上下文,它将与UI代码作斗争,UI代码将具有自己的EGL上下文,用于硬件加速的VIEw渲染.如果你创建一个单独的线程,让你的EGL上下文在那里流动,然后不管它,生活会有点简单.

你可以看到“相机纹理”活动的框架可用处理程序只是:

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

因为帧可用消息可以到达任意线程,所以你不知道那里的EGL上下文是什么(或者线程是否会有一个).你可以调用eglMakeCurrent()(通过EglCore#makeCurrent())使你的当前,但你不允许从多个线程使用相同的EGL上下文,所以如果它在同一时间的其他地方你可能有一个问题.因此,将帧可用消息转发到您知道EGL上下文是最新的线程更容易.

FWIW,0x0502是GL_INVALID_OPERATION.

总结

以上是内存溢出为你收集整理的android – 使用表面纹理的相机预览全部内容,希望文章能够帮你解决android – 使用表面纹理的相机预览所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1107730.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-28
下一篇 2022-05-28

发表评论

登录后才能评论

评论列表(0条)

保存