SurfaceView相机应用程序切换相机并修复暗预览

时间:2018-02-24 10:08:40

标签: android android-camera surfaceview surfaceholder

我正在使用表面视图构建相机应用程序。该应用程序正确加载相机并捕获图像。图像捕获有两种情况:

  1. 捕获图像,并且没有任何内容,即字节数组被发送到预览活动。它在这里工作正常。

  2. 捕获图像,并将图片回调中的字节数组发送到预览活动。

  3. 在第二种情况下,应用程序显示黑屏并变得无响应。我不相信我知道其原因,因为我已经查看了许多教程并看过相同的代码。

    到目前为止,这是我的代码:

    public class ImageActivity extends AppCompatActivity implements SurfaceHolder.Callback {
    
    private static final String TAG = ImageActivity.class.getSimpleName();
    
    private ImageButton closeIV;
    private ImageView flipCameraIV;
    private FloatingActionButton fab_capture;
    private LinearLayout galleryLayout;
    
    private Camera camera;
    private Camera.PictureCallback jpegCallback;
    private SurfaceView surfaceView;
    private SurfaceHolder holder;
    
    private int currCamId = 0;
    
    private boolean isGalleryImg = false;
    private boolean isCameraImg = false;
    
    private byte[] camBytes = null;
    
    private static final int GAL_REQ_CODE = 240;
    private static final int CAM_PERM_CODE = 242;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_image);
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().setStatusBarColor(getResources().getColor(R.color.black));
        }
    
        init();
    
        holder = surfaceView.getHolder();
        holder.addCallback(this);
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    
        currCamId = Camera.CameraInfo.CAMERA_FACING_BACK;
    
    }
    
    private void handleClicks() {
    
        closeIV.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });
    
        flipCameraIV.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.d(TAG, "Flip Clicked");
                switchCamera();
            }
        });
    
        galleryLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                isGalleryImg = true;
                Log.d(TAG, "Gallery Button Clicked");
                Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
                galleryIntent.setType("image/*");
                startActivityForResult(galleryIntent, GAL_REQ_CODE);
            }
        });
    
        fab_capture.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                captureImage();
            }
        });
    
        jpegCallback = new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] bytes, Camera camera) {
                assert bytes != null;
                Log.d(TAG, "Camera Bytes Array Length:\t" + bytes.length);
    
                isCameraImg = true;
    
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
    
    
                Intent intent = new Intent(ImageActivity.this, PreviewActivity.class);
                intent.putExtra("camera_bytes", bytes);
                intent.putExtra("fromCamera", isCameraImg);
                startActivity(intent);
                return;
    
                //refreshCamera();
            }
        };
    
    }
    
    
    private void captureImage() {
        camera.takePicture(null, null, jpegCallback);
    }
    
    public void refreshCamera() {
        if (holder.getSurface() == null) {
            return; // preview surface is empty
        }
    
        // stop preview, then make changes
        try {
            camera.stopPreview();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    
        try {
            camera.setPreviewDisplay(holder);
            camera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    
    }
    
    private void init() {
        closeIV = findViewById(R.id.closeIV);
        fab_capture = findViewById(R.id.fab_capture);
        galleryLayout = findViewById(R.id.galleryLayout);
        flipCameraIV = findViewById(R.id.flipCameraIV);
        surfaceView = findViewById(R.id.surfaceView);
    
        handleClicks();
    
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
    
        if (requestCode == GAL_REQ_CODE && resultCode == RESULT_OK) {
            Uri imgUri = data.getData();
            Intent intent = new Intent(ImageActivity.this, PreviewActivity.class);
            intent.putExtra("fromGallery", isGalleryImg);
            intent.putExtra("gallery_image", imgUri.toString());
            startActivity(intent);
        }
    
    }
    
    @TargetApi(Build.VERSION_CODES.M)
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    
        for (int mResults : grantResults) {
            if (mResults == PackageManager.PERMISSION_DENIED) {
                requestPermissions(new String[]{Manifest.permission.CAMERA,
                                Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        CAM_PERM_CODE);
            } else {
                Toast.makeText(ImageActivity.this, "Permission Already Granted", Toast.LENGTH_SHORT).show();
            }
        }
    
    }
    
    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        openCamera();
    }
    
    private void openCamera() {
        try {
            camera = Camera.open(currCamId);
        } catch (RuntimeException rex) {
            rex.printStackTrace();
        }
    
        Camera.Parameters parameters = camera.getParameters();
        parameters.setPreviewFrameRate(20);
        parameters.setPreviewSize(352, 288);
        camera.setDisplayOrientation(90);
        camera.setParameters(parameters);
    
        try {
            camera.setPreviewDisplay(holder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        camera.startPreview();
    }
    
    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        refreshCamera();
    }
    
    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        camera.stopPreview();
        camera.release();
        camera = null;
    
    }
    
    @Override
    protected void onPause() {
        super.onPause();
        camera.stopPreview();
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (camera != null){
            camera.stopPreview();
            camera.release();
            camera = null;
        }
    }
    

    }

    此外,我尝试使用此代码段切换到前置摄像头并再次返回,但无法正常工作。

    private void switchCamera() {
    
        // code I tried to switch camera with but not working
    
        if (currCamId == Camera.CameraInfo.CAMERA_FACING_BACK){
            currCamId = Camera.CameraInfo.CAMERA_FACING_FRONT;
        } else {
            currCamId = Camera.CameraInfo.CAMERA_FACING_BACK;
        }
    
        camera = Camera.open(currCamId);
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_FRONT, info);
    
        int rotation = this.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 rotate = (info.orientation - degrees + 360) % 360;
        Camera.Parameters parameters = camera.getParameters();
        parameters.setRotation(rotate);
    
        try {
            camera.setPreviewDisplay(surfaceView.getHolder());
        } catch (IOException e) {
            e.printStackTrace();
        }
    
        camera.setParameters(parameters);
        camera.setDisplayOrientation(90);
        camera.startPreview();
    
        //openCamera();
    
    }
    

    我需要帮助来解决这个问题。感谢。

1 个答案:

答案 0 :(得分:0)

正如我所见,您尝试将图片作为字节数组发送,这是不可能的。因为自api23以来对意图大小有限制。发送附加内容时,您必须考虑附加内容的大小,它确实会破坏用户体验并导致新活动的负载变慢。

无论如何,你的字节数组太大了所有的图片数据,我认为这会导致anr。你该怎么办?您必须首先将该字节数组保存为jpeg文件,然后将filepath添加到您的意图中。 Take a look to this solution

哦,而且,只是基于经验的友好建议,使用好的相机库而不是android-sdk的经典用法会更好。我可以说,Android开发的最糟糕的部分是媒体,特别是相机api。与ios相比,它的羞辱和谷歌自2015年以来没有对这种缺乏做任何开发。