Android Camera从单个相机预览两个

时间:2016-02-08 14:07:03

标签: android camera android-camera

我想从单个相机enter image description here

构建关于相机两个预览的应用程序android

我尝试构建应用,我在Android Studio中使用SurfaceView,但我遇到问题,enter image description here

我想要示例代码,你能帮帮我吗? 非常感谢你。

我试过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>

立即更新编辑代码:9/02/16

  1. 编辑AndroidSurfaceviewExample.java
    • 添加public void onPreviewFrame()
  2.     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();
        }
    }

2 个答案:

答案 0 :(得分:1)

布局中的每个元素都需要具有唯一ID。您已将两个屏幕元素都标识为@+id/surfaceView。尝试使它们都独一无二。请参阅下面的修改后的布局文件 - 也不要忘记更新源代码以填充两个屏幕元素。

<?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>

向程序添加代码以引用两个SurfaceView对象。您只需复制已有的代码即可。您还应该检查程序的其余部分,以获取需要更新的SurfaceView对象的其他引用。

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

关键是要意识到虽然你的左视图和右视图是同一类型的对象(它们都是SurfaceViews),但它们完全没有意识到彼此。如果您希望某个视图发生某些事情,则必须编写在该视图上显式工作的代码。如果您还希望它在另一个视图中发生,则必须编写在另一个视图中显式工作的代码。这是具有相同对象的两个实例的示例。

更新:进一步挖掘后,我发现上述变化是必要的,但还不够。您对camera.setPreviewDisplay(surfaceHolderLeft);的调用只允许定义单个预览SurfaceView,因此您无法使用此方法在两个表面上进行预览。

要完成您要执行的操作,我建议您创建预览图像的位图(可以在名为onPreviewFrame()的回调中获取,这类似于您的onPictureTaken() callback. The bitmap data will be passed in through the first parameter) Then get a画布{{1 SurfaceHolder.lockCanvas()for each Surface view (by calling Canvas.drawBitmap()`。这应该将原始图像绘制到每个表面视图上。

由于您将直接绘制每个surfaceView,因此您应该摆脱将其中一个surfaceView设置为预览的行,以便您与相机竞争以获取在那里绘制。摆脱, and then draw the bitmap you saved onto each Canvas by calling行而不是写camera.setPreviewDisplay(surfaceHolderLeft);

祝你好运。

答案 1 :(得分:0)

我成功地实现了从单个摄像机克隆的预览。请参阅下面的代码段。

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