需要帮助将Camera预览数据作为SurfaceTexture从TextureView中使用openGL处理

时间:2014-09-17 04:07:25

标签: android opengl-es android-camera textureview

搜索了整整3天,发现了很多相关信息,但由于我对计算机图形缺乏了解,所以没有一个是准确的。我只是想在这里问一个问题。

要说清楚,

1)我有FrameLayout

2)我添加了一个TextureView

3)我将LayoutParams设置为FrameLayout为一种squre形状,因此不管怎么样,TextureView也会根据它调整大小,变成一个方形,这不是很混乱

4)Camera Previewing工作和TextureView显示工作之间的所有工作都很好但是

4!)正如我们都知道的那样,在SurfaceView时代。如果我们强制将相机预览数据绘制到一个非常适合相机预览大小的视图中,最终结果就会被拉伸。

4。)我的意思是我知道如何调整FrameLayout / TextureView的大小以使它成为4:3 / ~16:9(Landscap或Portrait)的程序,但我需要它是sqaure,真的,当然不会拉伸

5?)我想我应该通过openGL thins预处理SurfaceTexture数据。 (我认为这很明显但是我不太确定,如果你有一种完全不同的方式来实现结果。也将不胜感激。

5)关于预备工作。我有很多这样做的样本,但只有普通的SurfaceView或GLSurfaceView。因为我不熟悉原始的openGL编程。当我尝试将代码转换为我的项目时,我遭受了痛苦

5+)不,我必须使用TextureView。如果你怀疑是因为谷歌将他们的Camera样本转移到使用TextureView,所以我认为我必须学习处理TextureView + openGL组合。无论如何,TextureView进入舞台只是为了让它更简单,只有生活一个视图,并配合轻量级的openGL处理​​,没有划痕不是

6)我真的无法将这些在线样本移植到我的。即使用SurfaceTexture(omg)

来附加openGL上下文,我也遇到了麻烦

7)是的我有类似骨架的代码结构,除了drawFrame impl之外,一切都有效。我该怎么办呢?

活动

public class MainActivity extends ActionBarActivity {

private ImageView imageView;
private TextView textView;

private Camera mCamera;
private MirrorScope mScope;

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

    imageView = (ImageView) findViewById(R.id.qrCode);
    textView = (TextView) findViewById(R.id.title);

    // Create an instance of Camera
    mCamera = getCameraInstance();

    // Create our Preview view and set it as the content of our activity.
    mScope = new MirrorScope(this, mCamera);
    mScope.setSurfaceTextureListener(mScope);
    FrameLayout scopeDrawer = (FrameLayout) findViewById(R.id.camera_preview);
    scopeDrawer.setLayoutParams(new LinearLayout.LayoutParams(700,700));

    scopeDrawer.addView(mScope);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {

    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, 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);
}


/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        // this device has a camera
        return true;
    } else {
        // no camera on this device
        return false;
    }
}

/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
    Camera c = null;
    try {
        c = Camera.open(); // attempt to get a Camera instance
    }
    catch (Exception e){
        // Camera is not available (in use or does not exist)
    }
    return c; // returns null if camera is unavailable
}

}

TextureView

    public class MirrorScope extends TextureView  implements TextureView.SurfaceTextureListener {

    private Camera mCamera;  
    private Context mContext;
    private TextureView mTextureView;  
    private ScopeGLThread renderer;

    public MirrorScope(Context context , Camera camera) {  
        super(context);  
        mCamera = camera;  
        // TODO Auto-generated constructor stub  
    }  
    @Override  
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,  
            int height) {  
//        mCamera = Camera.open();  
        try {  
            mCamera.setPreviewTexture(surface);  
            mCamera.startPreview();  
        } catch (IOException ioe) {  
            // Something bad happened  
        }  
        renderer = new ScopeGLThread(surface);
        renderer.start();
    }  

    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width,  
            int height) {  
        // Ignored, Camera does all the work for us  
    }  

    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {  
        renderer = null;  
        mCamera.stopPreview();  
        mCamera.release();  
        return true;  
    }  

    public void onSurfaceTextureUpdated(SurfaceTexture surface) {  
        // Invoked every time there's a new Camera preview frame 
        //renderer.notify();

    }  

}  

openGL线程

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;

import android.graphics.SurfaceTexture;
import android.opengl.EGL14;
import android.util.Log;

public class ScopeGLThread extends Thread {

    SurfaceTexture mSurface;
    EGL10 mEgl;
    EGLDisplay mEglDisplay;
    EGLConfig mEglConfig;
    EGLContext mEglContext;
    EGLSurface mEglSurface;

    public ScopeGLThread(SurfaceTexture surface) {
        mSurface = surface;
    }

    @Override
    public void run() {
        initGL();

        while(true) {
            drawFrame();
            Log.v("omg","oooomg"); //this do print thus I think the main loop is kidda work-ful
            //wait(); //however this hurts even with try/catch bloack it kills my app
        }
    }

    private void initGL() {
        mEgl = (EGL10)EGLContext.getEGL();
        mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

        int versions[] = new int[2];
        mEgl.eglInitialize(mEglDisplay, versions);

        int configsCount[] = new int[1];
        EGLConfig configs[] = new EGLConfig[1];
        int configSpec[] = new int[]{
            EGL10.EGL_RENDERABLE_TYPE, 
            EGL14.EGL_OPENGL_ES2_BIT,
            EGL10.EGL_RED_SIZE, 8,
            EGL10.EGL_GREEN_SIZE, 8,
            EGL10.EGL_BLUE_SIZE, 8,
            EGL10.EGL_ALPHA_SIZE, 8,
            EGL10.EGL_DEPTH_SIZE, 0,
            EGL10.EGL_STENCIL_SIZE, 0,
            EGL10.EGL_NONE };
        mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount);
        mEglConfig = configs[0];

        int contextSpec[] = new int[]{
                EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
                EGL10.EGL_NONE };
        mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig, EGL10.EGL_NO_CONTEXT, contextSpec);

        mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, null);

        mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
    }

    private void drawFrame() {
        //mSurface.attachToGLContext(1);
        //mSurface.detachFromGLContext();
        //mEgl..glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        //mSurface.updateTexImage();
    // everything I put here kills everything ( and some deleted other kind of trying)
    }


}

我该如何获得gl实例?当一些样本使用gl(从无处...或参数)时,我发现它很困惑,其他人使用EGL14.blahblah的东西。我的意思是... omg我真的不知道openGL,Android.com上的khronos包参考是VOID ......)

确实需要逐步解决确切问题的教程,但如果你以文本形式清楚地解释它也会很棒。 当我需要方形时,我认为我们可以通过裁剪相机预览数据的左上方squre来使其变得最简单。这将非常有帮助。 是的,我可能需要添加某种过滤功能,所以不要破解方形问题。我坚持通过openGL这样做。

顺便说一下,由于我国的网络情况,Google无法访问Google样本。我可以但不能非常满意地进行搜索工作,并为此道歉。

2 个答案:

答案 0 :(得分:0)

请在GitHub上看到我的小sample。我根本没有选择 扩展 android.view.TextureView;你的里程可能不同。

答案在TextureView.SurfaceTextureListener.onSurfaceTextureAvailable()回调中。查看转换 Matrix。当您想要补偿不同的宽高比时,只需使用transform.setScale(),直到您对结果感到满意为止。官方文件说,

  

某些转换可能会阻止内容绘制所有像素   包含在此视图的范围内。在这种情况下,请确保此纹理视图未标记为不透明。

我必须承认我并不完全理解他们所说的内容,但实验表明,如果你愿意,选择合适的Matrix你可以实现相机预览的有效裁剪。

答案 1 :(得分:0)

您可以在Grafika中获得所需的大部分代码。 请参阅此活动:https://github.com/google/grafika/blob/master/src/com/android/grafika/ContinuousCaptureActivity.java,opengl代码已准备就绪。

该演示对您非常有用。首先,它将相机连接到OES SurfaceTexture,因此相机帧(16:9或4:3)将被发送到此纹理。然后将纹理中的框架绘制到纹理视图或某处。

您需要做的是剪掉纹理中每个帧的某些部分,使帧1:1。您可以通过修改opengl的纹理坐标来实现切割。看看这个问题,你会得到它。 (Crop video before encoding with MediaCodec for Grafika's "Continuous Capture" Activity