GVKun编程网logo

使用Android camera2进行全屏预览(android camera 预览)

5

在本文中,我们将给您介绍关于使用Androidcamera2进行全屏预览的详细内容,并且为您解答androidcamera预览的相关问题,此外,我们还将为您提供关于Android5,camera2仅使

在本文中,我们将给您介绍关于使用Android camera2进行全屏预览的详细内容,并且为您解答android camera 预览的相关问题,此外,我们还将为您提供关于Android 5,camera2仅使用闪光灯、android Camera2 API使用详解、Android Camera2 API显示已处理的预览图像、Android Camera2 getPreviewFrame的知识。

本文目录一览:

使用Android camera2进行全屏预览(android camera 预览)

使用Android camera2进行全屏预览(android camera 预览)

我正在使用新的camera2 API构建自定义相机.我的代码基于Google here提供的代码示例.

我无法找到一种方法来全屏显示相机.在代码示例中,他们使用比率优化来适应所有屏幕,但它只占屏幕高度的3/4左右.

这是我的AutoFitTextureView代码:

public class AutoFitTextureView extends TextureView {

private int mRatioWidth = 0;
private int mRatioHeight = 0;

public AutoFitTextureView(Context context) {
    this(context,null);
}

public AutoFitTextureView(Context context,AttributeSet attrs) {
    this(context,attrs,0);
}

public AutoFitTextureView(Context context,AttributeSet attrs,int defStyle) {
    super(context,defStyle);
}

/**
 * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
 * calculated from the parameters. Note that the actual sizes of parameters don't matter,that
 * is,calling setAspectRatio(2,3) and setAspectRatio(4,6) make the same result.
 *
 * @param width  Relative horizontal size
 * @param height Relative vertical size
 */
public void setAspectRatio(int width,int height) {
    if (width < 0 || height < 0) {
        throw new IllegalArgumentException("Size cannot be negative.");
    }
    mRatioWidth = width;
    mRatioHeight = height;
    requestLayout();
}

@Override
protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec,heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);

    if (0 == mRatioWidth || 0 == mRatioHeight) {
        setMeasuredDimension(width,height);
    } else {
        if (width < height * mRatioWidth / mRatioHeight) {
            setMeasuredDimension(width,width * mRatioHeight / mRatioWidth);
        } else {
            setMeasuredDimension(height * mRatioWidth / mRatioHeight,height);
        }
    }
}

}

非常感谢您的帮助.

解决方法

这是您的问题的解决方案.在此 line中,纵横比设置为3/4.我更改了chooseVideSize方法,为MediaRecorder选择具有高清分辨率的视频大小.
private static Size chooseVideoSize(Size[] choices) {
        for (Size size : choices) {
            // Note that it will pick only HD video size,you should create more robust solution depending on screen size and available video sizes
            if (1920 == size.getWidth() && 1080 == size.getHeight()) {
                return size;
            }
        }
        Log.e(TAG,"Couldn't find any suitable video size");
        return choices[choices.length - 1];
    }

然后我更正了this method以根据视频大小纵横比选择预览尺寸,结果如下.

private static Size chooSEOptimalSize(Size[] choices,int width,int height,Size aspectRatio) {
    // Collect the supported resolutions that are at least as big as the preview Surface
    List<Size> bigEnough = new ArrayList<Size>();
    int w = aspectRatio.getWidth();
    int h = aspectRatio.getHeight();
    double ratio = (double) h / w;
    for (Size option : choices) {
        double optionRatio = (double) option.getHeight() / option.getWidth();
        if (ratio == optionRatio) {
            bigEnough.add(option);
        }
    }

    // Pick the smallest of those,assuming we found any
    if (bigEnough.size() > 0) {
        return Collections.min(bigEnough,new CompareSizesByArea());
    } else {
        Log.e(TAG,"Couldn't find any suitable preview size");
        return choices[1];
    }
}

我希望它会对你有所帮助!

Android 5,camera2仅使用闪光灯

Android 5,camera2仅使用闪光灯

如何解决Android 5,camera2仅使用闪光灯?

https://github.com/pinguo- yuyidong/Camera2/blob/master/app/src/main/java/us/yydcdut/androidltest/otheractivity/FlashActivity.java 在这里,您无需预览即可打开Flash 。

解决方法

像手电筒应用程序一样,我只需要将闪光灯与API camera2(Android 5,API级别21)一起使用。但是我发现的所有示例都需要在视图中显示摄像机流

android Camera2 API使用详解

android Camera2 API使用详解

原文: android Camera2 API使用详解

由于最近需要使用相机拍照等功能,鉴于老旧的相机API问题多多,而且新的设备都是基于安卓5.0以上的,于是本人决定研究一下安卓5.0新引入的Camera2 API 来实现 Camera2API地址

首先我们来熟悉一下官方给的这几个图:


这里引用了管道的概念将安卓设备和摄像头之间联通起来,系统向摄像头发送 Capture 请求,而摄像头会返回 CameraMetadata。这一切建立在一个叫作 CameraCaptureSession 的会话中。

fig.2


其中 CameraManager 是那个站在高处统管所有摄像投设备(CameraDevice)的管理者,而每个 CameraDevice 自己会负责建立 CameraCaptureSession 以及建立 CaptureRequest。CameraCharacteristics 是 CameraDevice 的属性描述类,非要做个对比的话,那么它与原来的 CameraInfo 有相似性。 类图中有着三个重要的 callback,虽然这增加了阅读代码的难度,但是你必须要习惯,因为这是新包的风格。其中 CameraCaptureSession.CaptureCallback 将处理预览和拍照图片的工作,需要重点对待。这些类是如何相互配合的?下面是简单的流程图。

fig.3

有了这三张图,那么接下来就好了理解了,我们按照拍照流程的指示,来吧整个过程走一遍

1首先定义一个SufaceView 用来实现预览照片用

surfaceView=(SurfaceView) findViewById(R.id.surfaceView);

surfaceHolder.addCallback(new SurfaceHolder.Callback() {
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        initCamera();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }
});
其中initCamera2()方法是用来初始化相机的方法
2获取Camera ID,该ID是用来打开相机的关键,一般后置摄像头是0,前置摄像头是1,这里我们选择后置摄像头做详解
mCameraID = "" + CameraCharacteristics.LENS_FACING_BACK;//后摄像头
3通过Camera ID 来打开摄像头,这里我们需要使用CamerManager,这是类是一个管理服务类,值得注意的是,打开摄像头是一个相当复杂的过程,不能直接在主线程中直接执行,其核心代码为:
HandlerThread handlerThread=new HandlerThread("Camera2");
handlerThread.start();
childHandler=new Handler(handlerThread.getLooper());
mainHandler=new Handler(getMainLooper());
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { //可以在这里处理拍照得到的临时照片 例如,写入本地
    @Override
    public void onImageAvailable(ImageReader reader) {
        mCameraDevice.close();
        surfaceView.setVisibility(View.GONE);
        iv_show.setVisibility(View.VISIBLE);
        // 拿到拍照照片数据
        Image image = reader.acquireNextImage();
        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
        byte[] bytes = new byte[buffer.remaining()];
        buffer.get(bytes);//由缓冲区存入字节数组
        final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        if (bitmap != null) {
            iv_show.setImageBitmap(bitmap);
        }
    }
}, mainHandler);

cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    //打开摄像头
    cameraManager.openCamera(mCameraID, stateCallback, mainHandler);
} catch (CameraAccessException e) {
    e.printStackTrace();
}
注意打开摄像头需要权限:
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
4 开启相机后有一个回调,stateCallback,该回调是用来返回相机是否正常打开的状态的
private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
    @Override
    public void onOpened(CameraDevice camera) {//打开摄像头
        mCameraDevice = camera;
        //开启预览
        takePreview();
    }

    @Override
    public void onDisconnected(CameraDevice camera) {//关闭摄像头
        if (null != mCameraDevice) {
            mCameraDevice.close();
            MainActivity.this.mCameraDevice = null;
        }
    }

    @Override
    public void onError(CameraDevice camera, int error) {//发生错误
        Toast.makeText(MainActivity.this, "摄像头开启失败", Toast.LENGTH_SHORT).show();
    }
};
5 相机开启成功后,执行回调中的onOpen方法,在该方法中,我们实现让图像显示在界面上
/**
 * 开始预览
 */
private void takePreview() {
    try {
        // 创建预览需要的CaptureRequest.Builder
        final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        // 将SurfaceView的surface作为CaptureRequest.Builder的目标
        previewRequestBuilder.addTarget(surfaceHolder.getSurface());
        // 创建CameraCaptureSession,该对象负责管理处理预览请求和拍照请求
        mCameraDevice.createCaptureSession(Arrays.asList(surfaceHolder.getSurface(), mImageReader.getSurface()), new CameraCaptureSession.StateCallback() // ③
        {
            @Override
            public void onConfigured(CameraCaptureSession cameraCaptureSession) {
                if (null == mCameraDevice) return;
                // 当摄像头已经准备好时,开始显示预览
                mCameraCaptureSession = cameraCaptureSession;
                try {
                    // 自动对焦
                    previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                    // 打开闪光灯
                    previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                    // 显示预览
                    CaptureRequest previewRequest = previewRequestBuilder.build();
                    mCameraCaptureSession.setRepeatingRequest(previewRequest, null, childHandler);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
                Toast.makeText(MainActivity.this, "配置失败", Toast.LENGTH_SHORT).show();
            }
        }, childHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}
6,预览完成后,接下来就是拍照了,注意某些手机的摄像头会和正常手机的摄像头另类,成像会成180度的倒立像,比如nexus 5x,这时候只需要设置
rORIENTATIONS的值来调整角度就可以
/**
 * 拍照
 */
private void takePicture() {
    if (mCameraDevice == null) return;
    // 创建拍照需要的CaptureRequest.Builder
    final CaptureRequest.Builder captureRequestBuilder;
    try {
        captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        // 将imageReader的surface作为CaptureRequest.Builder的目标
        captureRequestBuilder.addTarget(mImageReader.getSurface());
        // 自动对焦
        captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
        // 自动曝光
        captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
        // 获取手机方向
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        // 根据设备方向计算设置照片的方向
        captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)+rORIENTATIONS);
        //拍照
        CaptureRequest mCaptureRequest = captureRequestBuilder.build();
        mCameraCaptureSession.capture(mCaptureRequest, null, childHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

Android Camera2 API显示已处理的预览图像

Android Camera2 API显示已处理的预览图像

新的Camera 2 API与旧的相比非常不同.显示操纵的相机帧到管道的用户部分让我感到困惑.我知道 Camera preview image data processing with Android L and Camera2 API有很好的解释,但显示帧仍然不清楚.我的问题是,在一些处理过程中,在ImageReaders回调函数中显示帧的方式是什么,同时保持Camera2 api管道的效率和速度?

示例流程:

camera.add_target(imagereader.getsurface) – >在图像读取器上回调做一些处理 – > (在屏幕上显示已处理的图像?)

解决方法创意:每次处理新帧时,都会将位图发送到imageview.

解决方法

澄清问题后编辑;最初的答案在底部

取决于您在哪里进行处理.

如果您正在使用RenderScript,则可以将Surface从SurfaceView或TextureView连接到分配(使用setSurface),然后将处理后的输出写入该分配并使用Allocation.ioSend()将其发送出去. HDR Viewfinder demo使用这种方法.

如果您正在进行基于EGL着色器的处理,则可以使用eglCreateWindowSurface将Surface连接到EGLSurface,将Surface作为native_window参数.然后,您可以将最终输出渲染到该EGLSurface,当您调用eglSwapBuffers时,缓冲区将被发送到屏幕.

如果您正在进行本机处理,则可以使用NDK ANativeWindow methods写入从Java和convert传递到ANativeWindow的Surface.

如果你正在进行Java级处理,那真的很慢而且你可能不想这样做.但是可以使用新的Android M ImageWriter类,或者每帧上传一个纹理到EGL.

或者如您所说,每帧都绘制一个ImageView,但这样会很慢.

原始答案:

如果要捕获JPEG图像,只需将ByteBuffer的内容从Image.getPlanes()[0] .getBuffer()复制到byte []中,然后使用BitmapFactory.decodeByteArray将其转换为Bitmap.

如果您正在捕获YUV_420_888图像,那么您需要将自己的转换代码从3平面ycbcr 4:2:0格式写入您可以显示的内容,例如RGB []的RGB值来创建位图;遗憾的是,还没有一个方便的API.

如果您正在捕获RAW_SENSOR图像(拜耳模式未处理的传感器数据),那么您需要进行大量图像处理或只需保存DNG.

Android Camera2 getPreviewFrame

Android Camera2 getPreviewFrame

我试图让相机框架处于预览模式.我正在从github https://github.com/googlesamples/android-Camera2Basic运行示例项目

我遇到的问题是在预览模式下获取帧.

这是代码:

private CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {

    private void process(CaptureResult result) {
        switch (mState) {
            case STATE_PREVIEW: {

                //HERE, HOW CAN I RETRIEVE THE CURRENT FRAME?

                break;
            }
            case STATE_WAITING_LOCK: {
               ...
                break;
            }
            case STATE_WAITING_PRECAPTURE: {
             ...
                break;
            }
            case STATE_WAITING_NON_PRECAPTURE: {
             ...
                break;
            }
        }
    }

我尝试获取框架的另一件事是设置mImageReader.setonImageAvailableListener.
我期望能够获得框架onImageAvailable回调,但是永远不会调用onImageAvailable. onPreviewFrame是我自己的方法,我需要将它传递给当前帧.

  mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.JPEG, /*maxImages*/2);
  mImageReader.setonImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);

  private final ImageReader.OnImageAvailableListener mOnImageAvailableListener  = new ImageReader.OnImageAvailableListener() {

    @Override
    public void onImageAvailable(ImageReader reader) {
        mTextureView.onPreviewFrame(reader.acquireNextimage().getPlanes([0].getBuffer().array());
    }

};

我做错了什么?
谢谢.

解决方法:

当预览帧可用时,永远不会调用OnImageAvailableListener.onImageAvailable回调,因为发送到CameraCaptureSession.setRepeatingRequest()方法的CaptureRequest未将ImageReader的Surface列为输出目标.

您可以确定在将请求发送到摄像机时,您希望每个捕获的数据输出到哪些Surface(原始字节缓冲区).因此,要获取“预览帧”以触发onImageAvailable()回调,然后将其发送到onPreviewFrame()方法,只需添加以下行:

mPreviewRequestBuilder.addTarget(mImageReader.getSurface());

该行可以例如在将SurfaceTexture的Surface添加到同一请求构建器的其他类似行之后.

请注意,这会将每个预览帧发送到您的功能,以及捕获按钮的“输出帧”.您可能需要onImageAvailable()回调中的一些代码进行区分.

我们今天的关于使用Android camera2进行全屏预览android camera 预览的分享就到这里,谢谢您的阅读,如果想了解更多关于Android 5,camera2仅使用闪光灯、android Camera2 API使用详解、Android Camera2 API显示已处理的预览图像、Android Camera2 getPreviewFrame的相关信息,可以在本站进行搜索。

本文标签: