如何在 Camera2 API Android 5.0 中获取单个预览帧?

Posted

技术标签:

【中文标题】如何在 Camera2 API Android 5.0 中获取单个预览帧?【英文标题】:How to get single preview frame in Camera2 API Android 5.0? 【发布时间】:2015-06-07 10:28:26 【问题描述】:

我正在尝试使用 Camera2 API 为 QR 码扫描功能获取 预览框架。在旧的 Camera API 中,它很简单:

    android.hardware.Camera mCamera;
    ...
    mCamera.setPreviewCallback(new Camera.PreviewCallback() 
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) 
            // will be invoked for every preview frame in addition to displaying them on the screen             
        
    );

但是,我无法找到一种方法来使用 Camera2 API 实现这一目标。我想接收多个可以处理的帧 - 最好的方法是接收旧 API 中的字节数组。任何想法如何做到这一点?

【问题讨论】:

看看这个问题。 ***.com/questions/25462277/… github.com/Gutyn/camera2QRcodeReader 我发布了这个例子,它使用最新的android2相机API来读取二维码。享受 【参考方案1】:

有点晚,但总比没有好:

通常TextureView 用于显示相机的预览。每次表面变化时,您都可以使用TextureView.SurfaceTextureListener 获取回调。 TextureView 确实提供了一个方法getBitmap(Bitmap),您可以使用它来获得与TextureView 相同大小的预览帧。

您可以使用this Google sample 作为起点。只需更新 surfaceTextureListener,如下所示:

private val surfaceTextureListener = object : TextureView.SurfaceTextureListener 

    override fun onSurfaceTextureAvailable(texture: SurfaceTexture, width: Int, height: Int) 
        openCamera(width, height)
    

    override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int) 
        configureTransform(width, height)
    

    override fun onSurfaceTextureDestroyed(texture: SurfaceTexture) = true

    override fun onSurfaceTextureUpdated(texture: SurfaceTexture) 
        // Start changes
        // Get the bitmap
        val frame = Bitmap.createBitmap(textureView.width, textureView.height, Bitmap.Config.ARGB_8888)
        textureView.getBitmap(frame)

        // Do whatever you like with the frame
        frameProcessor?.processFrame(frame)
        // End changes
    


【讨论】:

【参考方案2】:

使用下面的代码来做到这一点。

 CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        try 
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
            Size[] jpegSizes = null;
            if (characteristics != null) 
                jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
            
            int width = 480;//480x320
            int height = 320;
            if (jpegSizes != null && 0 < jpegSizes.length) 
                width = jpegSizes[0].getWidth();
                height = jpegSizes[0].getHeight();
            
            ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
            List<Surface> outputSurfaces = new ArrayList<Surface>(2);
            outputSurfaces.add(reader.getSurface());
            outputSurfaces.add(new Surface(textureView.getSurfaceTexture()));
            final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureBuilder.addTarget(reader.getSurface());
            captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
            // Orientation
            int rotation = ((Activity) context).getWindowManager().getDefaultDisplay().getRotation();
            captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
            final File file = getFileDir();
            ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() 
                @Override
                public void onImageAvailable(ImageReader reader) 
                    Image image = null;
                    try 
                        image = reader.acquireLatestImage();
                        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                        byte[] bytes = new byte[buffer.capacity()];
                        buffer.get(bytes);
                        save(bytes);
                     catch (FileNotFoundException e) 
                        e.printStackTrace();
                     catch (IOException e) 
                        e.printStackTrace();
                     finally 
                        if (image != null) 
                            image.close();
                        
                    
                

                private void save(byte[] bytes) throws IOException 
                    OutputStream output = null;
                    try 
                        output = new FileOutputStream(file);
                        output.write(bytes);
                     finally 
                        if (null != output) 
                            output.close();
                        
                    
                
            ;
            reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
         catch (CameraAccessException e) 
            e.printStackTrace();
        

【讨论】:

cameraDevice 是从哪里来的? 您正在展示如何捕获图像,问题是如何在捕获图像之前获取预览帧,例如增强现实 将 imagereader 作为 capturerequestbuilder 的目标会令人难以置信地减慢帧速率,不知道如何提高它

以上是关于如何在 Camera2 API Android 5.0 中获取单个预览帧?的主要内容,如果未能解决你的问题,请参考以下文章

如何实现RTMP推送Android Camera2数据

Android:如何检查设备是不是实现了 Camera2 api 功能?

android Camera2 API使用详解

如何使用Android的Camera2 API

如何实现Android平台GB28181设备对接Camera2数据

如何在 Android camera2 API 中同时配置前后两个摄像头?