android-camera2相機開發【4】-選取最優預覽輸出尺寸

1. 拍照模式下的最優輸出預覽尺寸選擇

通常來講拍照的時候儘可能選擇最大的輸出尺寸,以達到最好的預覽效果(和拍出的照片效果同樣)。java

2. 視頻模式下的最優輸出預覽尺寸選擇

  • 相機輸出尺寸默認是橫向的(寬>高),手機窗口通常是豎向的(不考慮旋轉橫置的狀況),因此比較時將輸出尺寸的 寬高比 與 預覽窗口的 高寬比 進行比較。
  • 錄製視頻的時候,爲了預覽和播放效果好(充滿窗口),能夠選擇寬高比與預覽窗口高寬比一致的輸出尺寸。
  • 若是沒有寬高比一致的輸出尺寸,則能夠選擇高寬比接近的。
  • 可是若是上面選擇的尺寸太小,則預覽圖像畫質比較模糊,因此能夠設定一個閾值,若是不知足閾值,則退而求其次選擇和預覽窗口面積最接近的輸出尺寸。

3. 代碼實現

在前文的基礎上進行調整,添加兩個按鈕,拍照模式、錄像模式,點擊後更新預覽窗口。android

首先,在獲取相機輸出尺寸列表時拍個序,按降序排列,方便後面的篩選。git

//獲取指定相機的輸出尺寸列表,並降序排序
        outputSizes = CameraUtils.getInstance().getCameraOutputSizes(cameraId, SurfaceTexture.class);
        Collections.sort(outputSizes, new Comparator<Size>() {
            @Override
            public int compare(Size o1, Size o2) {
                return o1.getWidth() * o1.getHeight() - o2.getWidth() * o2.getHeight();
            }
        });
        Collections.reverse(outputSizes);
複製代碼

而後設置按鈕點擊事件github

btnImageMode = view.findViewById(R.id.btn_image_mode);
        btnImageMode.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //拍照模式,選擇最大輸出尺寸
                updateCameraPreviewWithImageMode();
            }
        });

        btnVideoMode = view.findViewById(R.id.btn_video_mode);
        btnVideoMode.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //錄像模式,選擇寬高比和預覽窗口高寬比一致或最接近且的輸出尺寸
                //若是該輸出尺寸太小,則選擇和預覽窗口面積最接近的輸出尺寸
                updateCameraPreviewWithVideoMode();
            }
        });
複製代碼

拍照模式的最優輸出尺寸選擇ide

private void updateCameraPreviewWithImageMode(){
        previewSize = outputSizes.get(0);
        previewView.setAspectRation(previewSize.getWidth(), previewSize.getHeight());
        createPreviewSession();
    }
複製代碼

錄像模式下最優輸出尺寸的選擇spa

private void updateCameraPreviewWithVideoMode(){
        List<Size> sizes = new ArrayList<>();
        //計算預覽窗口高寬比,高寬比,高寬比
        float ratio = ((float) previewView.getHeight / previewView.getWidth());
        //首先選取寬高比與預覽窗口高寬比一致且最大的輸出尺寸
        for (int i = 0; i < outputSizes.size(); i++){
            if (((float)outputSizes.get(i).getWidth()) / outputSizes.get(i).getHeight() == ratio){
                sizes.add(outputSizes.get(i));
            }
        }
        if (sizes.size() > 0){
            previewSize = Collections.max(sizes, new CompareSizesByArea());
            previewView.setAspectRation(previewSize.getWidth(), previewSize.getHeight());
            createPreviewSession();
            return;
        }
        //若是不存在寬高比與預覽窗口高寬比一致的輸出尺寸,則選擇與其寬高比最接近的輸出尺寸
        sizes.clear();
        float detRatioMin = Float.MAX_VALUE;
        for (int i = 0; i < outputSizes.size(); i++){
            Size size = outputSizes.get(i);
            float curRatio = ((float)size.getWidth()) / size.getHeight();
            if (Math.abs(curRatio - ratio) < detRatioMin){
                detRatioMin = curRatio;
                previewSize = size;
            }
        }
        if (previewSize.getWidth() * previewSize.getHeight() > PREVIEW_SIZE_MIN){
            previewView.setAspectRation(previewSize.getWidth(), previewSize.getHeight());
            createPreviewSession();
        }
        //若是寬高比最接近的輸出尺寸過小,則選擇與預覽窗口面積最接近的輸出尺寸
        long area = previewView.getWidth() * previewView.getHeight();
        long detAreaMin = Long.MAX_VALUE;
        for (int i = 0; i < outputSizes.size(); i++){
            Size size = outputSizes.get(i);
            long curArea = size.getWidth() * size.getHeight();
            if (Math.abs(curArea - area) < detAreaMin){
                detAreaMin = curArea;
                previewSize = size;
            }
        }
        previewView.setAspectRation(previewSize.getWidth(), previewSize.getHeight());
        createPreviewSession();
    }
複製代碼

4. 總結

本文針對不一樣的使用場景,給出簡單的最優預覽輸出尺寸的選擇方法,固然還有更好,兼容性更強的方法,這裏提供一個簡單的思路。code

項目github地址視頻

相關文章
相關標籤/搜索