Camera API 1 Preview

      在〈Camera API 1 Preview〉中尚無留言

Camera API

Andorid  自5.0開始, 對Camera API 進行重大的改版, 稱為Camera API 2. 而5.0之前, 稱為Camera API 1. Google開始推動API 2的開發, 故凡是使用API 1的方法, 都會被畫上刪除線提示為過期.

盡使API 1被畫上刪除線, 但還是可以使用. 而使用API 2時, 相對的也增加了開發的難度, 不容易理解. 再加上API 1其實是學習照相機開發的基礎, 故本篇還是以 API 1 講解 相關原理

 相機預覽元件

相機的預覽元件可以使用SurfaceView及TextureView, 此處以SurfaceView作說明

SurfaceView裏要顯示的資料可由多方來源提供, 比如由Ram, DMA, GPU等, 亦可由 Camera 提供數據. 要控制供應來源, 需先取得SurfaceView 的 SurfaceHoler, 再由 SurfaceHolder的 setType進行設定. SurfaceHolder是一個抽象介面, 用來控制SurfaceView的運作.

首先在layout中安置一個SurfaceView, 於onCreate中取得surfaceView物件後再由此物件取得surfaceHolder.

SurfaceView的建立需要花費一段相當長的時間(好幾百萬奈秒), 因此當建立完成, 或狀態改變時, 都會回調特定的方法, 這些方法全都集合於 SurfaceHoler.Callback類別中. 因此需要產生此一物件, 並由 holder.addCallback指定此回調物件

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().setFlags(
            WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN );
    setContentView(R.layout.activity_main);
    this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    surfaceView=(SurfaceView)findViewById(R.id.cameraView);
    holder=surfaceView.getHolder();
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    holder.addCallback(new CameraHolderCallback());
}

SurfaceHolder.Callback

實作SurfaceHolder.Callback介面需要實作三個方法 : surfaceCreated, surfaceChanged, surfaceDestroyed

SurfaceCreated是當SurfaceView建立完成時的回調方法, 可以在此處開啟相機, 設定參數等. 但在開啟相機前, 需先取得使用相機的權限, 所以可以在此要求 getPermission, 待真正取得權限, 再開啟相機, 設定相機與SurfaceView的連結, 並開啟預覽

SurfaceDestroyed是當SurfaceView銷毀時會被回調的方法, 因此可在此關閉相機的預覽並關閉相機

    class CameraHolderCallback implements SurfaceHolder.Callback{
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            getPermission();
        }
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            if(camera!=null){
                camera.stopPreview();
                camera.release();
                camera=null;
            }
        }
    }
    private void getPermission(){
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M){
            if(checkSelfPermission(Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED ||
                    checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED ||
                    checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(
                        this,
                        new String[]{
                                Manifest.permission.CAMERA,
                                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                                Manifest.permission.ACCESS_FINE_LOCATION},
                        REQUEST_PERMISSION);
            }
            else startUpCamera();
        }
        else{
            startUpCamera();
        }
    }
    //權限要求對畫框後的回調
    @Override
    public void onRequestPermissionsResult(
            int requestCode,
            @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        if(requestCode==REQUEST_PERMISSION) {
            Map<String, Integer> perms = new HashMap<String, Integer>();
            // Initial
            perms.put(Manifest.permission.CAMERA, PackageManager.PERMISSION_GRANTED);
            perms.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
            perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
            // Fill with results
            for (int i = 0; i < permissions.length; i++)
                perms.put(permissions[i], grantResults[i]);
            if (perms.get(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
                    && perms.get(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
                    && perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                startUpCamera();
            } else {
                Toast.makeText(this, "No permission", Toast.LENGTH_LONG).show();
                finish();
            }
        }
        else{
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
    private void startUpCamera(){
        camera=Camera.open();
        try {
            camera.setPreviewDisplay(holder);
            camera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

預覽

上述程式碼中的startUpCamera() 是在取得權限後才執行, 此方法中實作了三項工作

開啟相機 : camera=Camera.open()
設定SurfaceView與相機的連結 : camera.setPreviewDisplay(holder)
開始預覽 : camera.startPreview

完整程式碼下載 : CameraTest

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *