1

Searched for 3 whole days and lots of related information found, but none is accurate enough and due to my lack of knowledge in computer graphic. I just dicide to ask a question here.

To make it clear,

1) I have FrameLayout

2) I added a TextureView to it

3) I set the LayoutParams to the FrameLayout to a kind of squre shape thus somehow the TextureView is resized according to that too, becoming a square, which is not very confusing

4) Everything between the Camera Previewing work and TextureView displaying work works fine BUT

4!) As we all know just like in SurfaceView days. If we force drawing Camera preview data into an not-quite-suit-the-camera-preview-size-view, the final result just get stretched.

4.) I mean I know how to resize the FrameLayout/TextureView to make it 4:3/~16:9 (Landscap or Portrait) programmely, but I need it to be sqaure, really, and not stretched of course

5?) I think I should preprocess the SurfaceTexture data via openGL thins. (I think this is quite obvious but I'm not so sure so if you have a completely different way to acheive the result. It will also be appreciated.

5) About the preAsking jobs. I got plenty of sample of doing this but only with a plain SurfaceView or GLSurfaceView. Since I am not so familar with original openGL programming. I suffered when I try to morph the code into my project

5+) No, I have to use TextureView. If you doubt the reason that is because Google transfered their Camera sample into using TextureView so I do think I have to learn dealing with TextureView+openGL combo. Anyway TextureView comes on to the stage just to make it simpler to bahave like and only life a View and cooperate with light-weighted openGL processing without a scratch isn't it

6) I really cannot port those online samples to mine. I have trouble even in attatching openGL context with the SurfaceTexture (omg)

7) Yes I have a skeleton-like code structure and everything works except for the drawFrame impl. What the hell should I put into it

The Activity

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
}

}

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

    }  

}  

The openGL Thread

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


}

how should I get a gl instance? I find it confused when some of the sample uses gl (from nowhere... or a argument), others using EGL14.blahblah things. I mean... omg I don't really know openGL and the khronos package reference on Android.com is VOID...)

Tutorial of solving the exact problem step-by-step is really needed but if you explain it clearly in text form that'll also be great. When I need square I think we can make it the simplest by just cropping the left-top squre of Camera preview data. That would be very helpful. And yes I may need to add some kind of filter function so don't hack the square-problem. I insist doing this via openGL, quite.

BTW, Google samples are not accessible due to the network situation of my Country. I can but do not very satisfying preasking-searching-work and I apology for that.

genpfault
  • 51,148
  • 11
  • 85
  • 139
user977289
  • 57
  • 1
  • 7
  • The "texture from camera" activity in Grafika (https://github.com/google/grafika) may be relevant. (Various examples there use GLSurfaceView, SurfaceView, and TextureView.) If you're rendering with GLES you can do the scaling / cropping with GL, rather than by manipulating the TextureView; this is more complicated but gives you more flexibility. – fadden Sep 17 '14 at 15:51

2 Answers2

0

Please see my tiny sample at GitHub. I chose not to extend android.view.TextureView at all; your mileage may differ.

The answer is in the TextureView.SurfaceTextureListener.onSurfaceTextureAvailable() callback tha twe override. Look at transform Matrix. When you want to compensate for different aspect ratio, you simply play with transform.setScale() until you are satisfied with the result. The oficial documentation says,

Some transforms might prevent the content from drawing all the pixels contained within this view's bounds. In such situations, make sure this texture view is not marked opaque.

I must confess that I don't fully understand what they are speaking about, but the experiments show that buy choosing the right Matrix you can achieve effective cropping of the camera preview, if you want to.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
0

You can get the most of the code you want in Grafika. Just refer to the this Activity:https://github.com/google/grafika/blob/master/src/com/android/grafika/ContinuousCaptureActivity.java, the opengl codes are all ready for you.

The demo is very useful for you. First it connect the camera to an OES SurfaceTexture, so camera frames (16:9 or 4:3) are sent to this texture. Then draw the frame in the texture to textureview or somewhere.

What you need to do is cutting off some parts of every frame in the texture to make the frame 1:1. You can achieve the cutting through modifying the texture coordinate of opengl. Take a look at this question and you will get it. (Crop video before encoding with MediaCodec for Grafika's "Continuous Capture" Activity)

Community
  • 1
  • 1
dragonfly
  • 1,151
  • 14
  • 35