Android多媒體之Camera2的相關操作

張風捷特烈發表於2019-03-04

零、前言

Android 5.0+ (API 21)

Camera過時.png
---->[原始碼裡讓我們用camera2]
 * @deprecated We recommend using the new 
 {@link android.hardware.camera2} API for new applications.
複製程式碼

這裡的camera2可不是一個類哦


一、開啟相機並預覽

1.早聽聞camera2很複雜,沒想到這麼複雜,我都有點小hold不住
檢視佈局和上一篇一樣,只是實現變了而已

1.開啟相機:Camera2Activity#surfaceCreated方法中

開個相機就這麼麻煩…(圖畫出來感覺清楚多了)

開啟相機.png

1.1:準備兩個Handler
HandlerThread handlerThread = new HandlerThread("Camera2");//執行緒名,隨意
handlerThread.start();
mainHandler = new Handler(getMainLooper());//主執行緒Handler
childHandler = new Handler(handlerThread.getLooper());//子執行緒Handler
複製程式碼

上來就一個HandlerThread類,它是幹嘛的?又是Handler又是Thread的,名字怪嚇人的
一看原始碼,它彷彿是在逗我笑…一共就166行,繼承自Thread
getThreadHandler方法還是 * @hide的,這不是明擺著說:快用getLooper方法嗎?
有了Looper就能根據Looper建立該執行緒下的Handler,名字起的很到位

HandlerThread.png

1.2:開啟相機

主要在CameraDevice.StateCallback的onOpened回撥函式中有CameraDevice的引用
注意,到這裡還只是開啟了相機,並沒有預覽

mCameraID = "" + CameraCharacteristics.LENS_FACING_FRONT;//後攝像頭
//獲取攝像頭管理器
mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
    //AndroidStudio自動生成...if
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) !=
            PackageManager.PERMISSION_GRANTED) {
        return;
    }
    CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            mCameraDevice = camera;
            //TODO 預覽方法見下:--startPreview()
        }
        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
        }
        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
        }
    };
    mCameraManager.openCamera(mCameraID, stateCallback, mainHandler);
} catch (CameraAccessException e) {
    e.printStackTrace();
}
複製程式碼

2.開啟預覽:方法startPreview

開啟預覽真的挺費勁的

開啟預覽.png
/**
 * 開啟預覽
 */
private void startPreview() {
    try {
        // 建立預覽需要的CaptureRequest.Builder
        final CaptureRequest.Builder reqBuilder =
                mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        // 將SurfaceView的surface作為CaptureRequest.Builder的目標
        reqBuilder.addTarget(mHolder.getSurface());
        //reqBuilder可以設定引數
        reqBuilder.set( // 自動對焦
                CaptureRequest.CONTROL_AF_MODE,
                CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
        reqBuilder.set(// 開啟閃光燈
                CaptureRequest.CONTROL_AE_MODE,
                CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
        // 建立CameraCaptureSession,該物件負責管理處理預覽請求和拍照請求
        CameraCaptureSession.StateCallback stateCallback =
                new CameraCaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(CameraCaptureSession cameraCaptureSession) {
                        if (null == mCameraDevice) return;
                        // 當攝像頭已經準備好時,開始顯示預覽
                        mCameraCaptureSession = cameraCaptureSession;
                        try {
                            // 顯示預覽
                            mCameraCaptureSession.setRepeatingRequest(
                                    reqBuilder.build(), null, childHandler);
                        } catch (CameraAccessException e) {
                            e.printStackTrace();
                        }
                    }
                    @Override
                    public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
                        Toast.makeText(Camera2Activity.this, "配置失敗", Toast.LENGTH_SHORT).show();
                    }
                };
        mImageReader = ImageReader.newInstance(
                mIdSvVideo.getWidth(), mIdSvVideo.getHeight(),
                ImageFormat.JPEG, 1);
        mCameraDevice.createCaptureSession(
                Arrays.asList(mHolder.getSurface(), mImageReader.getSurface()),
                stateCallback,
                childHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}
複製程式碼

3.修正預覽的寬高比

費了這麼大的勁,然後終於可以預覽了,結果如下…頭像都變形了,這怎麼能忍
百度了一會,並沒有找到好的解決方法,然後發揮自己的聰明才智
把SurfaceView寬高比縮放成3:4,並對橫豎屏分別適配,完美解決

豎屏 橫屏
Android多媒體之Camera2的相關操作
Android多媒體之Camera2的相關操作

程式碼實現起來也非常簡單,根據長寬的大小,setScale,保證比例就行了
注意:SurfaceView在surfaceCreated回撥時才有尺寸,在onCreate時寬高為0

/**
 * 適應螢幕
 *
 * @param surfaceView
 */
private void adjustScreen(View surfaceView) {
    int height = surfaceView.getHeight();
    int width = surfaceView.getWidth();
    if (height > width) {
        float justH = width * 4.f / 3;
        mIdSvVideo.setScaleX(height / justH);
    } else {
        float justW = height * 4.f / 3;
        mIdSvVideo.setScaleY(width / justW);
    }
}
複製程式碼
豎屏 橫屏
Android多媒體之Camera2的相關操作
Android多媒體之Camera2的相關操作

Ok,總算完美顯示出來了,良好的開端是成功的一半,繼續


二、拍張照

想拍張照也不簡單啊…

拍照邏輯概覽.png

1.拍照方法封裝
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();//旋轉方向集合
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 void takePicture() {
    if (mCameraDevice != null) {
        try {
            CaptureRequest.Builder reqBuilder = mCameraDevice
                    .createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            reqBuilder.addTarget(mImageReader.getSurface());
            // 自動對焦
            reqBuilder.set(
                    CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            // 自動曝光
            reqBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            // 獲取手機方向
            int rotation = getWindowManager().getDefaultDisplay().getRotation();
            // 根據裝置方向計算設定照片的方向
            reqBuilder.set(
                    CaptureRequest.JPEG_ORIENTATION,
                    ORIENTATIONS.get(rotation));
            //拍照
            mCameraCaptureSession.capture(reqBuilder.build(), null, childHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
}
複製程式碼

2.儲存照片邏輯
//可以在這裡處理拍照得到的臨時照片
mImageReader.setOnImageAvailableListener(reader -> {
    // 拿到拍照照片資料
    Image image = reader.acquireNextImage();
    ByteBuffer buffer = image.getPlanes()[0].getBuffer();
    byte[] bytes = new byte[buffer.remaining()];
    buffer.get(bytes);//由緩衝區存入位元組陣列
    File file = FileHelper.get()
            .createFile("camera2/IMG-"+StrUtil.getCurrentTime_yyyyMMddHHmmss()+".jpg");
    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(file);
        fos.write(bytes);
        fos.flush();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (fos != null) {
                fos.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        startPreview();
        image.close();
    }
}, mainHandler);
複製程式碼

3.說個小坑

當拍一張時,一切挺好,再拍一張居然崩了…
前面ImageReader的maxImages引數設為1,maxImages (1) has already been acquired

    Process: com.toly1994.video, PID: 11594
    java.lang.IllegalStateException: maxImages (1) has already been acquired, call #close before acquiring more.
        at android.media.ImageReader.acquireNextImage(ImageReader.java:501)
        at com.toly1994.video.cameral2.Camera2Activity.lambda$surfaceCreated$9(Camera2Activity.java:355)
        at com.toly1994.video.cameral2.-$$Lambda$Camera2Activity$ip57VOWPzaqDJe_HhvMUPkOS6eo.onImageAvailable(Unknown Source:2)
複製程式碼

再看看ImageReader對maxImages的表述

he maximum number of images the user will want to access simultaneously. 
This should be as small as possible to limit memory use. 
Once maxImages Images are obtained by the user, one of them has to be released
before a new Image will become available for access through

使用者想要同時訪問的最大影像數量。這應該儘可能小,以限制記憶體的使用。
一旦使用者獲得了maxImages影像,在可以通過新影像進行訪問之前,必須先釋放其中一個影像
複製程式碼

所以拍完照後釋放一下還有重新startPreview()一下,不然就不動了


 image.close();
複製程式碼

三、照片尺寸問題

1.獲取支援的尺寸種類

這個和ImageReader個尺寸有關,我只說有關,沒說就是
經過前一篇我們知道,照片的尺寸都是固定的某些種
看下面,我用1080* 19201080* 1925結果拍的兩張尺寸一樣
說明傳參只是參考值,內部會自己進行調整,我設成1*1,結果尺寸144*176
這時應該會想到上一篇中列印的的圖片種類支援情況,這篇看一下camera2裡怎麼獲取

關於尺寸.png
//mImageReader = ImageReader.newInstance(
//                    1080, 1920,
//                   ImageFormat.JPEG, 1);

//mImageReader = ImageReader.newInstance(
//                    1080, 1925,
//                    ImageFormat.JPEG, 1);
                    
mImageReader = ImageReader.newInstance(
        1, 1,
        ImageFormat.JPEG, 1);
        
        

// 獲取攝像頭支援的配置屬性
StreamConfigurationMap map = characteristics.get(
        CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
// 獲取攝像頭支援的最大尺寸
List<Size> sizes = Arrays.asList(
        map.getOutputSizes(ImageFormat.JPEG));

for (int i = 0; i < sizes.size(); i++) {
    Size pSize = sizes.get(i);
    L.d("PictureSize.width = " + pSize.getWidth() + "--------PictureSize.height = " + pSize.getHeight());
}
複製程式碼

列印結果:和上一篇獲取的結果一樣

PictureSize.width = 5184--------PictureSize.height = 3880
PictureSize.width = 4608--------PictureSize.height = 3456
PictureSize.width = 4608--------PictureSize.height = 2592
PictureSize.width = 4608--------PictureSize.height = 2304
PictureSize.width = 4608--------PictureSize.height = 2176
PictureSize.width = 4608--------PictureSize.height = 2126
PictureSize.width = 4160--------PictureSize.height = 3120
PictureSize.width = 4160--------PictureSize.height = 2340
PictureSize.width = 4000--------PictureSize.height = 3000
PictureSize.width = 3840--------PictureSize.height = 2160
PictureSize.width = 3264--------PictureSize.height = 2448
PictureSize.width = 3264--------PictureSize.height = 1632
PictureSize.width = 3264--------PictureSize.height = 1552
PictureSize.width = 3264--------PictureSize.height = 1504
PictureSize.width = 3200--------PictureSize.height = 2400
PictureSize.width = 2592--------PictureSize.height = 1944
PictureSize.width = 2592--------PictureSize.height = 1940
PictureSize.width = 2592--------PictureSize.height = 1296
PictureSize.width = 2592--------PictureSize.height = 1232
PictureSize.width = 2592--------PictureSize.height = 1458
PictureSize.width = 2560--------PictureSize.height = 1920
PictureSize.width = 2688--------PictureSize.height = 1512
PictureSize.width = 2304--------PictureSize.height = 1728
PictureSize.width = 2304--------PictureSize.height = 1296
PictureSize.width = 2048--------PictureSize.height = 1536
PictureSize.width = 1920--------PictureSize.height = 1080
PictureSize.width = 1840--------PictureSize.height = 1380
PictureSize.width = 1600--------PictureSize.height = 1200
PictureSize.width = 1600--------PictureSize.height = 900
PictureSize.width = 1440--------PictureSize.height = 1080
PictureSize.width = 1280--------PictureSize.height = 960
PictureSize.width = 1280--------PictureSize.height = 768
PictureSize.width = 1280--------PictureSize.height = 720
PictureSize.width = 1024--------PictureSize.height = 768
PictureSize.width = 800--------PictureSize.height = 600
PictureSize.width = 800--------PictureSize.height = 480
PictureSize.width = 720--------PictureSize.height = 480
PictureSize.width = 640--------PictureSize.height = 480
PictureSize.width = 352--------PictureSize.height = 288
PictureSize.width = 320--------PictureSize.height = 240
PictureSize.width = 176--------PictureSize.height = 144
複製程式碼

2.獲取最大的尺寸

取容器的最大值而已,列印了一下,無誤

Size maxSize = Collections.max(sizes, (o1, o2) -> //獲取容器最大值
                o1.getWidth() * o1.getHeight() - o2.getWidth() * o1.getHeight());
複製程式碼

這下知道為什麼一開始的時候是變形的了,SurfaceView將Camera的區域全部顯示
然後寬必須變窄才能容下,所以預覽看起來就是變窄了,但排出的照片是好的

1080*1920 3880*5184
Android多媒體之Camera2的相關操作
Android多媒體之Camera2的相關操作

3.這就有個問題:

不能所見即所得,但它和介面不變形又二者不可兼得
沒辦法,寫個函式適配一下吧,根據手機的尺寸來動態計算何時的圖片大小
將螢幕高的2倍進行參考,取差值最小的index,再根據螢幕寬的兩倍,取差值最小的index
橫向縱向比較,就能取到最適合的了。看了一下,我手機自帶的相機拍出來的是2126*4608

/**
 * 計算該手機合適的照片尺寸
 */
private void fitPhotoSize() {
    // 獲取指定攝像頭的特性
    CameraCharacteristics characteristics = null;
    try {
        characteristics = mCameraManager.getCameraCharacteristics(mCameraID);
        // 獲取攝像頭支援的配置屬性
        StreamConfigurationMap map = characteristics.get(
                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        // 獲取攝像頭支援的最大尺寸
        List<Size> sizes = Arrays.asList(map.getOutputSizes(ImageFormat.JPEG));
        int minIndex = 0;//差距最小的索引
        int minDx = Integer.MAX_VALUE;
        int minDy = Integer.MAX_VALUE;
        int[] dxs = new int[sizes.size()];
        int justW = mWinSize.getHeight() * 2;//相機預設是橫向的,so
        int justH = mWinSize.getWidth() * 2;
        for (int i = 0; i < sizes.size(); i++) {
            dxs[i] = sizes.get(i).getWidth() - justW;
        }
        for (int i = 0; i < dxs.length; i++) {
            int abs = Math.abs(dxs[i]);
            if (abs < minDx) {
                minIndex = i;//獲取高的最適索引
                minDx = abs;
            }
        }
        for (int i = 0; i < sizes.size(); i++) {
            Size size = sizes.get(i);
            if (size.getWidth() == sizes.get(minIndex).getWidth()) {
                int dy = Math.abs(justH - size.getHeight());
                if (dy < minDy) {
                    minIndex = i;//獲取寬的最適索引
                    minDy = dy;
                }
            }
        }
        justSize = sizes.get(minIndex);
        L.d(justSize + L.l());
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}
複製程式碼

由於拍照的方法已封裝,所以延遲拍照功能和上一篇一樣


四:其他用法

1.預覽縮放處理

圖和上一篇差不多,直接拿來用了,錄個屏也怪麻煩…
這個效果百度找不到…根據套路看CaptureRequest原始碼裡支援那些請求
看到SCALER_CROP_REGION是一個Rect,感覺有點像,就用了,然後瞎貓碰到死耗子…

預覽縮放處理

/**
 * 縮放封裝
 */
public void setZoom() {
    if ((mRate - 1) * 10 / 4 + 1 > 4.6f) {
        mRate = 1;
    }
    String rate = new DecimalFormat("#.0").format((mRate - 1) * 10 / 4 + 1);
    mIdIvZoom.setText(rate + "x");
    try {
        CaptureRequest.Builder reqBuilder = mCameraDevice
                .createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        // 將SurfaceView的surface作為CaptureRequest.Builder的目標
        reqBuilder.addTarget(mHolder.getSurface());
        reqBuilder.set(
                CaptureRequest.SCALER_CROP_REGION,
                new Rect(0, 0, (int) (justSize.getWidth() / mRate), (int) (justSize.getHeight() / mRate)));
        mCameraCaptureSession.setRepeatingRequest(reqBuilder.build(), null, childHandler);
        mRate += 0.15;
    } catch (CameraAccessException e) {
        e.printStackTrace();

    }
}
複製程式碼

2.燈光的開啟與關閉
打燈.gif
//開閃光燈
mIdIvSplash.setOnClickListener(v -> {
    if (!isFlashLight) {
        mIdIvSplash.setImageTintList(ColorStateList.valueOf(0xffEFB90F));
    } else {
        mIdIvSplash.setImageTintList(ColorStateList.valueOf(0xfffffffF));
    }
    isFlashLight = !isFlashLight;
    try {
        CaptureRequest.Builder reqBuilder = mCameraDevice
                .createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        reqBuilder.addTarget(mHolder.getSurface());
        reqBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON);
        reqBuilder.set(CaptureRequest.FLASH_MODE,
                isFlashLight?CameraMetadata.FLASH_MODE_TORCH:CameraMetadata.FLASH_MODE_OFF);
        mCameraCaptureSession.setRepeatingRequest(reqBuilder.build(), null, childHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
});
複製程式碼

3.切換鏡頭:本功能參考文章
切換鏡頭.gif
 /**
  * 開啟指定攝像頭
  */
 private void changeCamera(int id) {
     closeCamera();
     try {
         if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
             throw new RuntimeException("Time out waiting to lock camera opening.");
         }
         if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
             return;
         }
         mCameraManager.openCamera(id+"", mStateCallback, childHandler);
     } catch (CameraAccessException e) {
         e.printStackTrace();
     } catch (InterruptedException e) {
         throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
     }
 }
 /**
  * 關閉當前相機
  */
 private void closeCamera() {
     try {
         mCameraOpenCloseLock.acquire();
         if (null != mCameraCaptureSession) {
             mCameraCaptureSession.close();
             mCameraCaptureSession = null;
         }
         if (null != mCameraDevice) {
             mCameraDevice.close();
             mCameraDevice = null;
         }
         if (null != mImageReader) {
             mImageReader.close();
             mImageReader = null;
         }
     } catch (InterruptedException e) {
         throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
     } finally {
         mCameraOpenCloseLock.release();
     }
 }
複製程式碼

五、錄影

視訊錄製.png

1.輔助類

有個小bug,只能錄一次…僅供參考,如果有好的解決方案,還請指教

/**
 * 作者:張風捷特烈<br/>
 * 時間:2019/1/8 0008:16:29<br/>
 * 郵箱:1981462002@qq.com<br/>
 * 說明:視訊錄製輔助類
 */
public class VideoRecorder2Utils {
    private MediaRecorder mediaRecorder;
    private SurfaceHolder.Callback callback;
    private SurfaceView surfaceView;
    private CameraDevice mCameraDevice;
    private int height;
    private int width;
    List<Surface> surfaces = new ArrayList<>();
    public static Size WH_2160X1080 = new Size(2160, 1080);
    public static Size WH_1920X1080 = new Size(1920, 1080);
    public static Size WH_1280X960 = new Size(1280, 960);
    public static Size WH_1440X720 = new Size(1440, 720);
    public static Size WH_1280X720 = new Size(1280, 720);
    public static Size WH_864X480 = new Size(864, 480);
    public static Size WH_800X480 = new Size(800, 480);
    public static Size WH_720X480 = new Size(720, 480);
    public static Size WH_640X480 = new Size(640, 480);
    public static Size WH_352X288 = new Size(352, 288);
    public static Size WH_320X240 = new Size(320, 240);
    public static Size WH_176X144 = new Size(176, 144);
    private CaptureRequest.Builder mPreviewBuilder;
    private CaptureRequest mCaptureRequest;
    private CameraCaptureSession mPreviewSession;
    public void create(SurfaceView surfaceView, CameraDevice cameraDevice, Size size) {
        this.surfaceView = surfaceView;
        mCameraDevice = cameraDevice;
        //建立錄製的session會話中的請求
        try {
            mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        height = size.getHeight();
        width = size.getWidth();
        mediaRecorder = new MediaRecorder();
    }
    public void stopRecord() {
        mediaRecorder.release();
        mediaRecorder = null;
        mediaRecorder = new MediaRecorder();
        surfaces.clear();
    }
    public void stop() {
        if (mediaRecorder != null) {
            mediaRecorder.release();
        }
    }
    public void destroy() {
        if (mediaRecorder != null) {
            mediaRecorder.release();
            mediaRecorder = null;
        }
    }
    /**
     * @param path 儲存的路徑
     * @param name 錄影視訊名稱(不包含字尾)
     */
    public void startRecord(String path, String name, Handler handler) {
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mediaRecorder.setVideoEncodingBitRate(700 * 1024);
        mediaRecorder.setVideoSize(width, height);
        mediaRecorder.setVideoFrameRate(24);
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
        mediaRecorder.setOutputFile(path + File.separator + name + ".mp4");
        File file1 = new File(path + File.separator + name + ".mp4");
        if (file1.exists()) {
            file1.delete();
        }
        try {
            mediaRecorder.prepare();
            mediaRecorder.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
        review(handler);
    }
    public void review(Handler handler) {
        Surface previewSurface = surfaceView.getHolder().getSurface();
        surfaces.add(previewSurface);
        mPreviewBuilder.addTarget(previewSurface);
        Surface recorderSurface = mediaRecorder.getSurface();
        surfaces.add(recorderSurface);
        mPreviewBuilder.addTarget(recorderSurface);
        try {
            mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(CameraCaptureSession session) {
                    try {
                        //建立捕獲請求
                        mCaptureRequest = mPreviewBuilder.build();
                        mPreviewSession = session;
                        //設定反覆捕獲資料的請求,這樣預覽介面就會一直有資料顯示
                        mPreviewSession.setRepeatingRequest(mCaptureRequest, null, handler);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                @Override
                public void onConfigureFailed(CameraCaptureSession session) {
                }
            }, handler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    //清除預覽Session
    private void closePreviewSession() {
        if (mPreviewSession != null) {
            mPreviewSession.close();
            mPreviewSession = null;
        }
    }
}
複製程式碼

2.使用
 /**
  * 錄影
  */
 private void recodeVideo() {
     String path = Environment.getExternalStorageDirectory().getAbsolutePath();
     mVideoRecorderUtils.startRecord(path, "Video",childHandler);
     mIdIvSnap.setImageTintList(ColorStateList.valueOf(0xffff0000));
 }
 /**
  * 停止錄影
  */
 private void stopRecodeVideo() {
     mIdIvSnap.setImageTintList(ColorStateList.valueOf(0xff0FC2EF));
     mVideoRecorderUtils.stopRecord();
     startPreview();
 }
 
//開啟照相機時初始化
mVideoRecorderUtils = new VideoRecorder2Utils();
mVideoRecorderUtils.create(mIdSvVideo, mCameraDevice,VideoRecorder2Utils.WH_720X480);
複製程式碼

後記:捷文規範

1.本文成長記錄及勘誤表
專案原始碼 日期 備註
V0.1-github 2018-1-9 Android多媒體之Camera2的相關操作
2.更多關於我
筆名 QQ 微信 愛好
張風捷特烈 1981462002 zdl1994328 語言
我的github 我的簡書 我的掘金 個人網站
3.宣告

1—-本文由張風捷特烈原創,轉載請註明
2—-歡迎廣大程式設計愛好者共同交流
3—-個人能力有限,如有不正之處歡迎大家批評指證,必定虛心改正
4—-看到這裡,我在此感謝你的喜歡與支援


icon_wx_200.png

相關文章