John Pod
John Pod

Reputation: 13

Android Camera two preview from single camera

I want to build application android about camera two preview from a single camera enter image description here

I tried build app,I using SurfaceView in Android Studio but I have problem, enter image description here

I want example code, Can you help me please? Thank you so much.


I tried app.

AndroidSurfaceviewExample.java

package th.in.cybernoi.cardboardview;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;


public class AndroidSurfaceviewExample extends Activity implements SurfaceHolder.Callback  {
    TextView testView;

    Camera camera;
    SurfaceView surfaceView;
    SurfaceHolder surfaceHolder;

    PictureCallback rawCallback;
    ShutterCallback shutterCallback;
    PictureCallback jpegCallback;


    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
        surfaceHolder = surfaceView.getHolder();

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        surfaceHolder.addCallback(this);

        // deprecated setting, but required on Android versions prior to 3.0
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        jpegCallback = new PictureCallback() {
            public void onPictureTaken(byte[] data, Camera camera) {
                FileOutputStream outStream = null;
                try {
                    outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
                    outStream.write(data);
                    outStream.close();
                    Log.d("Log", "onPictureTaken - wrote bytes: " + data.length);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                }
                Toast.makeText(getApplicationContext(), "Picture Saved", 2000).show();
                refreshCamera();
            }
        };
    }



    //Surfacrview
    public void captureImage(View v) throws IOException {
        //take the picture
        camera.takePicture(null, null, jpegCallback);
    }

    public void refreshCamera() {
        if (surfaceHolder.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            camera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here
        // start preview with new settings
        try {
            camera.setPreviewDisplay(surfaceHolder);
            camera.startPreview();
        } catch (Exception e) {

        }
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // Now that the size is known, set up the camera parameters and begin
        // the preview.
        refreshCamera();
    }

    public void surfaceCreated(SurfaceHolder holder) {
        try {
            // open the camera
            camera = Camera.open();
        } catch (RuntimeException e) {
            // check for exceptions
            System.err.println(e);
            return;
        }
        Camera.Parameters param;
        param = camera.getParameters();

        // modify parameter
        param.setPreviewSize(352, 288);
        camera.setParameters(param);
        try {
            // The Surface has been created, now tell the camera where to draw
            // the preview.
            camera.setPreviewDisplay(surfaceHolder);
            camera.startPreview();
        } catch (Exception e) {
            // check for exceptions
            System.err.println(e);
            return;
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // stop preview and release camera
        camera.stopPreview();
        camera.release();
        camera = null;
    }

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    tools:context="th.in.cybernoi.cardboardview.MainActivity">

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

</LinearLayout>


Update Edit code Now :9/02/16

  1. edit to AndroidSurfaceviewExample.java
    • add public void onPreviewFrame()

    public class AndroidSurfaceviewExample extends Activity implements SurfaceHolder.Callback {
    TextView testView;

    Camera camera;
    SurfaceHolder camera01;
    SurfaceHolder camera02;

    SurfaceView surfaceViewLeft;
    SurfaceHolder surfaceHolderLeft;

    SurfaceView surfaceViewRight;
    SurfaceHolder surfaceHolderRight;

    PictureCallback rawCallback;
    ShutterCallback shutterCallback;
    PictureCallback jpegCallback;
    /**
     * ATTENTION: This was auto-generated to implement the App Indexing API.
     * See https://g.co/AppIndexing/AndroidStudio for more information.
     */
    private GoogleApiClient client;


    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        surfaceViewLeft = (SurfaceView) findViewById(R.id.surfaceViewLeft);
        surfaceHolderLeft = surfaceViewLeft.getHolder();

        surfaceViewRight = (SurfaceView) findViewById(R.id.surfaceViewRight);
        surfaceHolderRight = surfaceViewRight.getHolder();

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        surfaceHolderLeft.addCallback(this);
        surfaceHolderRight.addCallback(this);

        // deprecated setting, but required on Android versions prior to 3.0
        surfaceHolderLeft.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        surfaceHolderRight.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        /*
        jpegCallback = new PictureCallback() {
            public void onPictureTaken(byte[] data, Camera camera) {
                FileOutputStream outStream = null;
                try {
                    outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
                    outStream.write(data);
                    outStream.close();
                    Log.d("Log", "onPictureTaken - wrote bytes: " + data.length);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                }
                Toast.makeText(getApplicationContext(), "Picture Saved", 2000).show();
                refreshCamera();
            }


        };
        */
        // ATTENTION: This was auto-generated to implement the App Indexing API.
        // See https://g.co/AppIndexing/AndroidStudio for more information.
        client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
    }


    //Surfacrview


    public void refreshCamera() {
        if (surfaceHolderLeft.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            camera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here
        // start preview with new settings
        try {
            camera.setPreviewDisplay(surfaceHolderLeft);
            camera.startPreview();


        } catch (Exception e) {

        }
    }



    public void onPreviewFrame() {

        if (surfaceHolderRight.getSurface() == null) {
            // preview surface does not exist
            return;
        }


        // stop preview before making changes
        try {
            camera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here
        // start preview with new settings
        try {
            surfaceHolderLeft.lockCanvas();
            camera.setPreviewDisplay(surfaceHolderRight);
            camera.setPreviewCallback((Camera.PreviewCallback) surfaceHolderLeft);
            camera.startPreview();


        } catch (Exception e) {

        }


    }


    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // Now that the size is known, set up the camera parameters and begin
        // the preview.
        refreshCamera();
        onPreviewFrame();
        
    }

    public void surfaceCreated(SurfaceHolder holder) {
        try {
            // open the camera
            camera = Camera.open();
        } catch (RuntimeException e) {
            // check for exceptions
            System.err.println(e);
            return;
        }
        Camera.Parameters param;
        param = camera.getParameters();

        // modify parameter
        param.setPreviewSize(352, 288);
        camera.setParameters(param);
        try {
            // The Surface has been created, now tell the camera where to draw
            // the preview.
            camera.setPreviewDisplay(surfaceHolderLeft);
            camera.startPreview();
        } catch (Exception e) {
            // check for exceptions
            System.err.println(e);
            return;
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // stop preview and release camera
        camera.stopPreview();
        camera.release();
        camera = null;
    }

    @Override
    public void onStart() {
        super.onStart();

        // ATTENTION: This was auto-generated to implement the App Indexing API.
        // See https://g.co/AppIndexing/AndroidStudio for more information.
        client.connect();
        Action viewAction = Action.newAction(
                Action.TYPE_VIEW, // TODO: choose an action type.
                "AndroidSurfaceviewExample Page", // TODO: Define a title for the content shown.
                // TODO: If you have web page content that matches this app activity's content,
                // make sure this auto-generated web page URL is correct.
                // Otherwise, set the URL to null.
                Uri.parse("http://host/path"),
                // TODO: Make sure this auto-generated app deep link URI is correct.
                Uri.parse("android-app://th.in.cybernoi.cardboardview/http/host/path")
        );
        AppIndex.AppIndexApi.start(client, viewAction);
    }

    @Override
    public void onStop() {
        super.onStop();

        // ATTENTION: This was auto-generated to implement the App Indexing API.
        // See https://g.co/AppIndexing/AndroidStudio for more information.
        Action viewAction = Action.newAction(
                Action.TYPE_VIEW, // TODO: choose an action type.
                "AndroidSurfaceviewExample Page", // TODO: Define a title for the content shown.
                // TODO: If you have web page content that matches this app activity's content,
                // make sure this auto-generated web page URL is correct.
                // Otherwise, set the URL to null.
                Uri.parse("http://host/path"),
                // TODO: Make sure this auto-generated app deep link URI is correct.
                Uri.parse("android-app://th.in.cybernoi.cardboardview/http/host/path")
        );
        AppIndex.AppIndexApi.end(client, viewAction);
        client.disconnect();
    }
}

Upvotes: 0

Views: 3373

Answers (2)

Daniel Chung
Daniel Chung

Reputation: 1

I successfully implemented cloned preview from single camera. Refer to code snippet below.

private Camera.PreviewCallback cbPreview = new Camera.PreviewCallback() {
    @Override
    public void onPreviewFrame(byte[] bytes, Camera camera) {
        int pf = mCamera.getParameters().getPreviewFormat();
        if (pf == ImageFormat.NV21)
            bmp = decodeNV21(bytes, camera);
        else
            bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        MainActivity.mImageView.setImageBitmap(bmp);
        MainActivity.mImageView.postInvalidate();
    }
};

private Bitmap decodeNV21(byte[] data, Camera camera){
    Bitmap retimage = null;

    int w = camera.getParameters().getPreviewSize().width;
    int h = camera.getParameters().getPreviewSize().height;

    //Get the YUV image
    YuvImage yuv_image = new YuvImage(data, camera.getParameters().getPreviewFormat(), w, h, null);

    //Convert Yuv to Jpeg
    Rect rect = new Rect(0, 0, w, h);
    ByteArrayOutputStream out_stream = new ByteArrayOutputStream();
    yuv_image.compressToJpeg(rect, 100, out_stream);

    //Convert Yuv to jpeg
    retimage = BitmapFactory.decodeByteArray(out_stream.toByteArray(), 0, out_stream.size());

    return retimage;
}

Upvotes: 0

rothloup
rothloup

Reputation: 1290

Each element in a layout needs to have a unique id. you have identified both screen elements as @+id/surfaceView. Try making them both unique. See modified layout file below - also don't forget to update your source code to populate both screen elements.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    tools:context="th.in.cybernoi.cardboardview.MainActivity">

    <SurfaceView
        android:id="@+id/surfaceViewLeft"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <SurfaceView
        android:id="@+id/surfaceViewRight"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

</LinearLayout>

Add code to your program to reference both SurfaceView objects. You just duplicate the code you already have. You should also check the rest of your program for other references to your SurfaceView object that need to be updated.

            surfaceViewLeft = (SurfaceView) findViewById(R.id.surfaceViewLeft);
        surfaceHolderLeft = surfaceViewLeft.getHolder();

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        surfaceHolderLeft.addCallback(this);

        // deprecated setting, but required on Android versions prior to 3.0
        surfaceHolderLeft.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        surfaceViewRight = (SurfaceView) findViewById(R.id.surfaceViewRight);
        surfaceHolderRight = surfaceViewRight.getHolder();

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        surfaceHolderRight.addCallback(this);

        // deprecated setting, but required on Android versions prior to 3.0
        surfaceHolderRight.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 

The key is to realize that although your left and right views are the same type of object (they are both SurfaceViews) they are completely unaware of each other. If you want something to happen to one view, you must write code that works explicitly on that view. If you also want it to happen in the other view, you must write code that works explicitly on the other view. This is an example of having two instances of the same object.

UPDATE: Upon further digging, I see that the above changes are neccesary but not sufficient. your call to camera.setPreviewDisplay(surfaceHolderLeft); only allows a single preview SurfaceView to be defined, so you can't preview on two surfaces using this method.

To accomplish what you are trying to do, I recommend creating a bitmap of the preview image (which can be obtained in a callback called onPreviewFrame(), which is similar to your onPictureTaken() callback. The bitmap data will be passed in through the first parameter) Then get aCanvasfor each Surface view (by callingSurfaceHolder.lockCanvas(), and then draw the bitmap you saved onto each Canvas by callingCanvas.drawBitmap()`. This should draw the original image onto each surface view.

Since you will be drawing to each surfaceView directly, you should get rid of the line that sets one of the surfaceViews as a preview so that you are competing with the camera for access to draw there. get rid of the line camera.setPreviewDisplay(surfaceHolderLeft); and instead write camera.setPreviewCallback(yourcallbackgoeshere);

Good luck.

Upvotes: 1

Related Questions