Androidカスタムカメラ+TextureView撮影

10809 ワード

AndroidカスタムCamera+TextureView撮影#
カスタムcameraでは、次の点に注意してください.
  • cameraプレビューの角度.
  • textureviewのアスペクト比とcameraプレビュー時に設定したアスペクト比.
  • 撮影後の画像の回転角度.

  • カメラをカスタマイズする前に、この文章を見て、カメラセンサーの方向の問題を理解することができます.https://blog.csdn.net/c10WTiybQ1Ye3/article/details/78098459
    プレビューを詳しく解く角度の問題を解決するには、公式に推薦の書き方があります.
      /**
     *         
     *
     * @param context
     * @param cameraId
     * @param camera
     */
    public void setCameraDisplayOrientation(Activity context,
                                            int cameraId, Camera camera) {
        android.hardware.Camera.CameraInfo info =
                new android.hardware.Camera.CameraInfo();
        android.hardware.Camera.getCameraInfo(cameraId, info);
        int rotation = context.getWindowManager().getDefaultDisplay()
                .getRotation();
        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0: degrees = 0; break;
            case Surface.ROTATION_90: degrees = 90; break;
            case Surface.ROTATION_180: degrees = 180; break;
            case Surface.ROTATION_270: degrees = 270; break;
        }
    
        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
    
        camera.setDisplayOrientation(result);
    }
    

    プレビューは、アスペクト設定が適切でないとクラッシュする可能性があるだけでなく、プレビューインタフェースが変形する場合もあります.変形を解決するためには、プレビューインタフェースのアスペクト比とtextureviewのアスペクト比をできるだけ一致させるとともに、アスペクト設定の不適切な問題を解決し、カメラがサポートする解像度でも探すべきです.私が設定したtextureviewの幅は、幅の割合をより簡単に制御するために画面に満ちています.では、スクリーンの幅の高さの割合は、カメラ解像度の幅の高さの割合です.注意:カメラセンサは横スクリーンに取り付けられているので、画面のh/wで設定した解像度のw/hを決定する必要があります.
     /**
     *
     *
     * @param sizes      size
     * @param targetRatio h/w
     * @param comparator       
     * @param minWidth        
     * @return
     */
    public Camera.Size getOptimalPreviewSize(List sizes, float targetRatio, int comparator, int minWidth) {
        if (sizes == null)
            return null;
        Camera.Size optimalSize = null;
    
    
    	//  size    
        Collections.sort(sizes, getComparator(comparator));
    
        //            size
        List tempList = new ArrayList<>();
        for(Camera.Size size : sizes){
            Log.i("sss", "....width.....:"+size.width+"...height.."+size.height);
            if(size.width >= minWidth){
                tempList.add(size);
            }
        }
    
        if(tempList.size() > 0){
            //       ,             。
            for (Camera.Size size : tempList) {
                float currentRatio = ((float) size.width) / size.height;
                if (currentRatio - targetRatio == 0) {
                    optimalSize = size;
                    break;
                }
            }
        }else{
            //     
            for (Camera.Size size : sizes) {
                float currentRatio = ((float) size.width) / size.height;
                if (currentRatio - targetRatio == 0) {
                    optimalSize = size;
                    break;
                }
            }
        }
    
        //           
        if(optimalSize == null){
            float tempRation;
            float minRation = Float.MAX_VALUE;
            if(tempList.size() > 0){
                for (Camera.Size size : tempList) {
                    float curRatio = ((float) size.width) / size.height;
                    tempRation = Math.abs(targetRatio - curRatio);
                    if(tempRation 

    写真を撮った後の画像の回転角度は、画像の処理についてこの文章を参考にすることができます.https://blog.csdn.net/Lamphogani/article/details/79197015?utm_source=blogxgwz9私が欲しい効果は、画像の方向が携帯電話の方向に合わせて設定されているので、私が使っているのは
      orientationEventListener = new OrientationEventListener(context) {
            @Override
            public void onOrientationChanged(int orientation) {
                if (ORIENTATION_UNKNOWN == orientation) {
                    return;
                }
                Camera.CameraInfo info = new Camera.CameraInfo();
                Camera.getCameraInfo(cameraId, info);
    
                orientation = (orientation + 45) / 90 * 90;
                rotation = 0;
                if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                    rotation = (info.orientation - orientation + 360) % 360;
                } else {
                    rotation = (info.orientation + orientation) % 360;
                }
    			//         ,                      
                if (null != mCamera) {
                    Camera.Parameters parameters = mCamera.getParameters();
                    parameters.setRotation(rotation);
                    mCamera.setParameters(parameters);
                }
            }
        };
    

    私はただここで写真を撮った携帯電話の角度を記録して、それから画像を回転します.
     /**
     *            
     *
     * @param angle     
     * @return bitmap   
     */
    public  Bitmap rotaingImageView(int id, int angle, Bitmap bitmap) {
        //       
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);
        //                
        if (id == 1) {
            matrix.postScale(-1, 1);
        }
        //       ,         bitmap       ,
        //             bitmap。   bitmap    resizeBitmap
        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
                bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        if(resizedBitmap == null){
            resizedBitmap = bitmap;
        }
      
        return resizedBitmap;
    }
    

    以上のいくつかの問題に気づくと、ほとんど差がありません.残りは具体的なカスタマイズです.
    まず簡単な設定をします.camera+textureviewを使っているので、ウィンドウを開けて加速すべきで、setcontentviewで設定しました.
      //        , TextureView            
        getWindow().setFlags(
                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
    
        requestWindowFeature(Window.FEATURE_NO_TITLE); //     
    
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);  //    
        this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//            
        //        ,   7 
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
    

    それから権限の申請で、同時にtextureViewも登録しました.setSurfaceTextureListener(this);権限申請がtextureviewと作成に成功した後、cameraを初期化してcameraのプレビューを同時に開くことができます.
    `  //   
    String[] PERMISSIONS = {Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.CAMERA,
            Manifest.permission.RECORD_AUDIO
    };`
    
       camera
    
    `/**
     *
     * @param surfaceTexture
     * @param cameraId
     */
    @Override
    public void startPreview(SurfaceTexture surfaceTexture, int cameraId) {
    
        this.cameraId = cameraId;
        this.mSurfaceTexture = surfaceTexture;
    
        if (mCamera == null && mSurfaceTexture != null) {
    
            if(orientationEventListener != null){
                orientationEventListener.enable();
            }
    
            //   camera    
            mCamera = getCameraInstance(cameraId);
            //     
            try {
                if (mCamera != null) {
                    mCamera.setPreviewTexture(mSurfaceTexture);
                    mCamera.lock();
                    setCameraDisplayOrientation(context, cameraId, mCamera);
    
                    initCameraParameters();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    
    /**     Camera        */
    private Camera getCameraInstance(int cameraId) {
        try {
            mCamera = Camera.open(cameraId); //     Camera  
        }
        catch (Exception e) {
            //       (        )
        }
        return mCamera; //       null
    }
    
    
    ` /**
     *         
     */
    private void initCameraParameters() {
        //         
        mParameters = mCamera.getParameters();
        mCamera.lock();
    
        List focusModes = mParameters.getSupportedFocusModes();
        //       
        if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            // Autofocus mode is supported     
            mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        }
        if(focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)){
            mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 1    
        }
    //             
        previewSize = getOptimalPreviewSize(mParameters.getSupportedPreviewSizes(), DisplayUtils.getScreenRate(context), Constants.COMPARATOR_ASCEND, 1280);
        if (previewSize != null) {
            mParameters.setPreviewSize(previewSize.width, previewSize.height);
        }
        //     
        Camera.Size pictrueSize = getOptimalPreviewSize(mParameters.getSupportedPictureSizes(), DisplayUtils.getScreenRate(context), Constants.COMPARATOR_ASCEND, 1280);
        if (pictrueSize != null) {
            mParameters.setPictureSize(pictrueSize.width, pictrueSize.height);
        }
        //      
        mParameters.setPreviewFormat(ImageFormat.NV21);
    
        try {
            mCamera.setParameters(mParameters);
            mCamera.setPreviewCallback(mRecordingUtils);
            mCamera.startPreview();
            // 2            ,       
            mCamera.cancelAutoFocus();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    `
    最後にカメラの撮影操作です...写真を撮るには2つの方法があります.1つはcameraからです.setPreviewCallbackの傍受では,撮影時のストリームを取得してピクチャを生成し,もう1つはcameraのtakePictureメソッドで取得する.私が使っているのは2つ目です.後には、第1の傍受中の方法でスクリーンの録画も行われるが.
    mCamera.takePicture(null, null, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(final byte[] data, Camera camera) {
    
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
    					//        ,                 
                        Bitmap savebitmap = rotaingImageView(cameraId, tempRotation, bitmap);
    
                        String img_path = imagePath;
                        if(TextUtils.isEmpty(img_path)){
                            img_path = Constants.DEFAULT_DIRECTORY;
                        }
    
                        img_path = img_path + "/" + System.currentTimeMillis() + ".jpeg";
                        File file = BitmapUtils.saveJPGE_After(context, savebitmap, img_path, 100);
    
                        if(cameraResultCallBack != null){
                            cameraResultCallBack.takePhotoResult(file);
                        }
    
    					if(bitmap != null && !bitmap.isRecycled()){
    					    bitmap.recycle();
    					}
    
                        if(savebitmap != null && !savebitmap.isRecycled()){
                            savebitmap.recycle();
                            savebitmap = null;
                        }
    
                    }
                }).start();
    
                mCamera.startPreview();
            }
        });
    ``
    

    以上がカスタムcameraの基本的な操作フローです