Android 5.0(21)之后,android.hardware.Camera被废弃(下面称为Camera1),还有一个android.graphics.Camera,这个android.graphics.Camera不是用来照相的,是用来处理图像的,可以做出3D的图像效果之类的,之前的Camera1则由android.hardware.Camera2来代替。

Camera2支持RAW输出,可以调节曝光,对焦模式,快门等,功能比原先Camera强大。

由于ImageFormat只有YUV420_888即YUV420系列,这里需要将其做一个转换,转成所需要的YUV420p:yyyyyyyyuuuuvvvv格式,参考文章:android camera2 拿到的yuv420数据到底是什么样的?

1、MainActivity.java文件:

package com.example.tongjiangsong.camera2base;import android.Manifest;import android.content.Context;import android.content.pm.PackageManager;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.ImageFormat;import android.hardware.camera2.CameraAccessException;import android.hardware.camera2.CameraCaptureSession;import android.hardware.camera2.CameraCharacteristics;import android.hardware.camera2.CameraDevice;import android.hardware.camera2.CameraManager;import android.hardware.camera2.CaptureRequest;import android.media.Image;import android.media.ImageReader;import android.os.Build;import android.os.Environment;import android.os.Handler;import android.os.HandlerThread;import android.support.annotation.RequiresApi;import android.support.v4.app.ActivityCompat;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.util.SparseIntArray;import android.view.Surface;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.widget.Button;import android.widget.ImageView;import android.widget.Toast;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.nio.ByteBuffer;import java.util.Arrays;public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();    private static final String TAG = "mainactivity" ;    ///为了使照片竖直显示    static {        ORIENTATIONS.append(Surface.ROTATION_0, 90);        ORIENTATIONS.append(Surface.ROTATION_90, 0);        ORIENTATIONS.append(Surface.ROTATION_180, 270);        ORIENTATIONS.append(Surface.ROTATION_270, 180);    }    private SurfaceView mSurfaceView;    private SurfaceHolder mSurfaceHolder;    private ImageView iv_show;    private CameraManager mCameraManager;//摄像头管理器    private Handler childHandler, mainHandler;    private String mCameraID;//摄像头Id 0 为后  1 为前    private ImageReader mImageReaderJPG;    private ImageReader mImageReaderPreview;    private CameraCaptureSession mCameraCaptureSession;    private CameraDevice mCameraDevice;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Button capture_btn = (Button)findViewById(R.id.capture_btn);        capture_btn.setOnClickListener(this);        initVIew();    }    /**     * 初始化     */    private void initVIew() {        iv_show = (ImageView) findViewById(R.id.image_preview);        //mSurfaceView        mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);        mSurfaceView.setOnClickListener(this);        mSurfaceHolder = mSurfaceView.getHolder();        mSurfaceHolder.setKeepScreenOn(true);        // mSurfaceView添加回调        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {            @Override            public void surfaceCreated(SurfaceHolder holder) { //SurfaceView创建                // 初始化Camera                initCamera2();            }            @Override            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {            }            @Override            public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView销毁                // 释放Camera资源                if (null != mCameraDevice) {                    mCameraDevice.close();                    MainActivity.this.mCameraDevice = null;                }            }        });    }    /**     * 初始化Camera2     */    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)    private void initCamera2() {        HandlerThread handlerThread = new HandlerThread("Camera2");        handlerThread.start();        childHandler = new Handler(handlerThread.getLooper());        mainHandler = new Handler(getMainLooper());        mCameraID = "" + CameraCharacteristics.LENS_FACING_FRONT;//后摄像头        mImageReaderJPG = ImageReader.newInstance(1080, 1920, ImageFormat.JPEG,1);        mImageReaderJPG.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { //可以在这里处理拍照得到的临时照片 例如,写入本地            @Override            public void onImageAvailable(ImageReader reader) {                //mCameraDevice.close();                //mSurfaceView.setVisibility(View.GONE);                //先验证手机是否有sdcard                String status = Environment.getExternalStorageState();                if (!status.equals(Environment.MEDIA_MOUNTED)) {                    Toast.makeText(getApplicationContext(), "你的sd卡不可用。", Toast.LENGTH_SHORT).show();                    return;                }                // 获取捕获的照片数据                Image image = reader.acquireNextImage();                ByteBuffer buffer = image.getPlanes()[0].getBuffer();                byte[] data = new byte[buffer.remaining()];                buffer.get(data);                //手机拍照都是存到这个路径                String filePath = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/";                String picturePath = System.currentTimeMillis() + ".jpg";                File file = new File(filePath, picturePath);                try {                    //存到本地相册                    FileOutputStream fileOutputStream = new FileOutputStream(file);                    fileOutputStream.write(data);                    fileOutputStream.close();                    iv_show.setVisibility(View.VISIBLE);                    //显示图片                    BitmapFactory.Options options = new BitmapFactory.Options();                    options.inSampleSize = 2;                    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);                    iv_show.setImageBitmap(bitmap);                } catch (FileNotFoundException e) {                    e.printStackTrace();                } catch (IOException e) {                    e.printStackTrace();                } finally {                    image.close();                }            }        }, mainHandler);        mImageReaderPreview = ImageReader.newInstance(1080, 1920, ImageFormat.YUV_420_888,1);        mImageReaderPreview.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { //可以在这里处理拍照得到的临时照片 例如,写入本地            @Override            public void onImageAvailable(ImageReader reader) {                // 获取捕获的照片数据                Image image = reader.acquireNextImage();                Log.i(TAG,"image format: " +image.getFormat());                // 从image里获取三个plane                Image.Plane[] planes = image.getPlanes();                for (int i = 0; i < planes.length; i++) {                    ByteBuffer iBuffer = planes[i].getBuffer();                    int iSize = iBuffer.remaining();                    Log.i(TAG, "pixelStride  " + planes[i].getPixelStride());                    Log.i(TAG, "rowStride   " + planes[i].getRowStride());                    Log.i(TAG, "width  " + image.getWidth());                    Log.i(TAG, "height  " + image.getHeight());                    Log.i(TAG, "Finished reading data from plane  " + i);                }                int n_image_size = image.getWidth()*image.getHeight()*3/2;                final byte[] yuv420pbuf = new byte[n_image_size];                System.arraycopy(ImageUtil.getBytesFromImageAsType(image, 0), 0, yuv420pbuf, 0, n_image_size);                image.close();            }        }, null);        //获取摄像头管理        mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);        try {            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {                return;            }            //打开摄像头            mCameraManager.openCamera(mCameraID, stateCallback, mainHandler);        } catch (CameraAccessException e) {            e.printStackTrace();        }    }    /**     * 摄像头创建监听     */    private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {        @Override        public void onOpened(CameraDevice camera) {//打开摄像头            mCameraDevice = camera;            //开启预览            takePreview();        }        @Override        public void onDisconnected(CameraDevice camera) {//关闭摄像头            if (null != mCameraDevice) {                mCameraDevice.close();                MainActivity.this.mCameraDevice = null;            }        }        @Override        public void onError(CameraDevice camera, int error) {//发生错误            Toast.makeText(MainActivity.this, "摄像头开启失败", Toast.LENGTH_SHORT).show();        }    };    /**     * 开始预览     */    private void takePreview() {        try {            // 创建预览需要的CaptureRequest.Builder            final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);            // 将SurfaceView的surface作为CaptureRequest.Builder的目标            previewRequestBuilder.addTarget(mSurfaceHolder.getSurface());            previewRequestBuilder.addTarget(mImageReaderPreview.getSurface());            // 创建CameraCaptureSession,该对象负责管理处理预览请求和拍照请求            mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface(), mImageReaderPreview.getSurface()), new CameraCaptureSession.StateCallback() // ③            {                @Override                public void onConfigured(CameraCaptureSession cameraCaptureSession) {                    if (null == mCameraDevice) return;                    // 当摄像头已经准备好时,开始显示预览                    mCameraCaptureSession = cameraCaptureSession;                    try {                        // 自动对焦                        previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);                        // 打开闪光灯                        previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);                        // 显示预览                        CaptureRequest previewRequest = previewRequestBuilder.build();                        mCameraCaptureSession.setRepeatingRequest(previewRequest, null, childHandler);                    } catch (CameraAccessException e) {                        e.printStackTrace();                    }                }                @Override                public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {                    Toast.makeText(MainActivity.this, "配置失败", Toast.LENGTH_SHORT).show();                }            }, childHandler);        } catch (CameraAccessException e) {            e.printStackTrace();        }    }    /**     * 点击事件     */    @Override    public void onClick(View v) {        switch (v.getId()) {            case R.id.capture_btn:                takePicture();                Toast.makeText(MainActivity.this, "拍照", Toast.LENGTH_SHORT).show();                break;        }    }    /**     * 拍照     */    private void takePicture() {        if (mCameraDevice == null) return;        // 创建拍照需要的CaptureRequest.Builder        final CaptureRequest.Builder captureRequestBuilder;        try {            captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);            // 将imageReader的surface作为CaptureRequest.Builder的目标            captureRequestBuilder.addTarget(mImageReaderJPG.getSurface());            // 自动对焦            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);            // 自动曝光            captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);            // 获取手机方向            int rotation = getWindowManager().getDefaultDisplay().getRotation();            // 根据设备方向计算设置照片的方向            captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));            //拍照            CaptureRequest mCaptureRequest = captureRequestBuilder.build();            mCameraCaptureSession.capture(mCaptureRequest, null, childHandler);        } catch (CameraAccessException e) {            e.printStackTrace();        }    }}

2、ImageUtil.java文件下

package com.example.tongjiangsong.camera2base;import android.graphics.ImageFormat;import android.media.Image;import android.util.Log;import java.nio.ByteBuffer;/** * yuv420p:  yyyyyyyyuuvv * yuv420sp: yyyyyyyyuvuv * nv21:     yyyyyyyyvuvu */public class ImageUtil {    public static final int YUV420P = 0;    public static final int YUV420SP = 1;    public static final int NV21 = 2;    private static final String TAG = "ImageUtil";    /***     * 此方法内注释以640*480为例     * 未考虑CropRect的     */    public static byte[] getBytesFromImageAsType(Image image, int type) {        try {            //获取源数据,如果是YUV格式的数据planes.length = 3            //plane[i]里面的实际数据可能存在byte[].length <= capacity (缓冲区总大小)            final Image.Plane[] planes = image.getPlanes();            //数据有效宽度,一般的,图片width <= rowStride,这也是导致byte[].length <= capacity的原因            // 所以我们只取width部分            int width = image.getWidth();            int height = image.getHeight();            //此处用来装填最终的YUV数据,需要1.5倍的图片大小,因为Y U V 比例为 4:1:1            byte[] yuvBytes = new byte[width * height * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8];            //目标数组的装填到的位置            int dstIndex = 0;            //临时存储uv数据的            byte uBytes[] = new byte[width * height / 4];            byte vBytes[] = new byte[width * height / 4];            int uIndex = 0;            int vIndex = 0;            int pixelsStride, rowStride;            for (int i = 0; i < planes.length; i++) {                pixelsStride = planes[i].getPixelStride();                rowStride = planes[i].getRowStride();                ByteBuffer buffer = planes[i].getBuffer();                //如果pixelsStride==2,一般的Y的buffer长度=640*480,UV的长度=640*480/2-1                //源数据的索引,y的数据是byte中连续的,u的数据是v向左移以为生成的,两者都是偶数位为有效数据                byte[] bytes = new byte[buffer.capacity()];                buffer.get(bytes);                int srcIndex = 0;                if (i == 0) {                    //直接取出来所有Y的有效区域,也可以存储成一个临时的bytes,到下一步再copy                    for (int j = 0; j < height; j++) {                        System.arraycopy(bytes, srcIndex, yuvBytes, dstIndex, width);                        srcIndex += rowStride;                        dstIndex += width;                    }                } else if (i == 1) {                    //根据pixelsStride取相应的数据                    for (int j = 0; j < height / 2; j++) {                        for (int k = 0; k < width / 2; k++) {                            uBytes[uIndex++] = bytes[srcIndex];                            srcIndex += pixelsStride;                        }                        if (pixelsStride == 2) {                            srcIndex += rowStride - width;                        } else if (pixelsStride == 1) {                            srcIndex += rowStride - width / 2;                        }                    }                } else if (i == 2) {                    //根据pixelsStride取相应的数据                    for (int j = 0; j < height / 2; j++) {                        for (int k = 0; k < width / 2; k++) {                            vBytes[vIndex++] = bytes[srcIndex];                            srcIndex += pixelsStride;                        }                        if (pixelsStride == 2) {                            srcIndex += rowStride - width;                        } else if (pixelsStride == 1) {                            srcIndex += rowStride - width / 2;                        }                    }                }            }            image.close();            //根据要求的结果类型进行填充            switch (type) {                case YUV420P:                    System.arraycopy(uBytes, 0, yuvBytes, dstIndex, uBytes.length);                    System.arraycopy(vBytes, 0, yuvBytes, dstIndex + uBytes.length, vBytes.length);                    break;                case YUV420SP:                    for (int i = 0; i < vBytes.length; i++) {                        yuvBytes[dstIndex++] = uBytes[i];                        yuvBytes[dstIndex++] = vBytes[i];                    }                    break;                case NV21:                    for (int i = 0; i < vBytes.length; i++) {                        yuvBytes[dstIndex++] = vBytes[i];                        yuvBytes[dstIndex++] = uBytes[i];                    }                    break;            }            return yuvBytes;        } catch (final Exception e) {            if (image != null) {                image.close();            }            Log.i(TAG, e.toString());        }        return null;    }}

3、activity_main.xml文件下

<?xml version="1.0" encoding="utf-8"?>                        

3、设置权限:

        

 

 

更多相关文章

  1. android开发数据存储方式
  2. Android 获取摄像头像素,个数
  3. 通过Android 客户端上传数据到服务器
  4. 通过adb工具查看android sqlite3数据库
  5. Android实习生 —— 网络请求及数据解析
  6. Android P的Socket通信实现之传输图片数据
  7. Android数据存储的方法

随机推荐

  1. Android(安卓)Keymaps and Keyboard Inpu
  2. Android:判断某APP是否安装
  3. android 查看apk中资源文件
  4. android studio 修改jdk默认编译版本
  5. android Parcelable序列化数组String[]
  6. Android(安卓)ProgressBar简单使用
  7. FFmpeg In Android(安卓)- tutorial-4-Sp
  8. Android(安卓)Applications Tutorial 23.
  9. Android(安卓)openGL hook
  10. Android上多个应用不能同时调用AudioReco