Android camera2 jpeg帧率

Tob*_*eis 5 android jpeg image yuv camera2

我试图在Android设备上保存具有固定帧率(最好高达30)的图像序列,具有相同功能的camera2(Galaxy S7),但我无法a)获得稳定的帧率,b)达到甚至20fps(使用jpeg)编码).我已经包含了Android camera2捕获突发的建议太慢了.

根据,JPEG的最小帧持续时间是33.33毫秒(对于低于1920x1080的分辨率)

characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputMinFrameDuration(ImageFormat.JPEG, size);
Run Code Online (Sandbox Code Playgroud)

并且每个尺寸的稳定度为0ms(类似于YUV_420_888).

我的捕获构建器如下所示:

captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CONTROL_AE_MODE_OFF);
captureBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, _exp_time);
captureBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);

captureBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, _iso_value);

captureBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, _foc_dist);
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CONTROL_AF_MODE_OFF);

captureBuilder.set(CaptureRequest.CONTROL_AWB_MODE, _wb_value);

// https://stackoverflow.com/questions/29265126/android-camera2-capture-burst-is-too-slow
captureBuilder.set(CaptureRequest.EDGE_MODE,CaptureRequest.EDGE_MODE_OFF); 
captureBuilder.set(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE, CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF);
captureBuilder.set(CaptureRequest.NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF);
captureBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);

// Orientation
int rotation = getWindowManager().getDefaultDisplay().getRotation();           
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,ORIENTATIONS.get(rotation));
Run Code Online (Sandbox Code Playgroud)

焦距设置为0.0(inf),iso设置为100,曝光时间设置为5ms.白平衡可以设置为OFF/AUTO/ANY VALUE,不会影响下面的时间.

我使用以下命令启动捕获会话:

session.setRepeatingRequest(_capReq.build(), captureListener, mBackgroundHandler);
Run Code Online (Sandbox Code Playgroud)

注意:如果我请求RepeatingRequest或RepeatingBurst,它没有区别.

在预览中(仅附加纹理表面),一切都是30fps.但是,只要我附加了一个图像阅读器(在HandlerThread上运行的监听器),我将其实例化如下(不保存,只测量帧之间的时间):

reader = ImageReader.newInstance(_img_width, _img_height, ImageFormat.JPEG, 2);
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
Run Code Online (Sandbox Code Playgroud)

使用时间测量代码:

ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
    @Override
    public void onImageAvailable(ImageReader myreader) {
        Image image = null;

        image = myreader.acquireNextImage();
        if (image == null) {
            return;
        }
        long curr = image.getTimestamp();
        Log.d("curr- _last_ts", "" + ((curr - last_ts) / 1000000) + " ms");
        last_ts = curr;
        image.close();
    }
}
Run Code Online (Sandbox Code Playgroud)

我会定期重复这样的时差:

99毫秒 - 66毫秒 - 66毫秒 - 99毫秒 - 66毫秒 - 66毫秒......

我不明白为什么这些流程配置映射为jpeg做广告的时间增加了两倍或三倍?曝光时间远低于33ms的帧持续时间.是否还有其他一些我不知道的内部处理?

我为YUV_420_888格式尝试了相同的操作,这导致了33ms的恒定时间差.我在这里遇到的问题是手机没有足够的带宽来快速存储图像(我尝试了如何保存YUV_420_888图像中描述的方法).如果您知道有任何方法可以自己快速压缩或编码这些图像,请告诉我.

编辑:从getOutputStallDuration的文档:"换句话说,使用重复的YUV请求将导致稳定的帧速率(假设它是30 FPS).如果定期提交单个JPEG请求,帧速率将保持在30 FPS (只要我们等待每次返回之前的JPEG).如果我们尝试提交重复的YUV + JPEG请求,那么帧速率将从30 FPS下降." 这是否意味着我需要定期请求单个capture()?

Edit2:来自https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html:"给定上面的模型,应用程序的必要信息是通过android.scaler.streamConfigurationMap字段使用getOutputMinFrameDuration提供的(int,Size).这些用于确定给定流配置可能的最大帧速率/最小帧持续时间.

具体来说,应用程序可以使用以下规则来确定它可以从摄像头设备请求的最小帧持续时间:

让当前配置的输入/输出流集合被称为S.通过使用getOutputMinFrameDuration(int,Size)(具有各自的大小/格式)在android.scaler.streamConfigurationMap中查找,找到S中每个流的最小帧持续时间. .让这组帧持续时间称为F.对于任何给定的请求R,R允许的最小帧持续时间是F中所有值的最大值.让R中使用的流称为S_r.如果S_r中没有任何流具有停顿时间(使用其各自的大小/格式在getOutputStallDuration(int,Size)中列出),则F中的帧持续时间确定应用程序在使用R as时将获得的稳态帧速率一个重复的请求."

Emi*_*elt 2

JPEG 输出并不是获取帧的最快方式。通过使用 OpenGL 将帧直接绘制到 Quad 上,您可以更快地完成此任务。

对于连拍捕获,更快的解决方案是将图像捕获到 RAM 中而不对其进行编码,然后异步编码并保存它们。

在此网站上,您可以找到许多与 Android 多媒体相关的优秀代码。

该特定程序使用 OpenGL 从 MPEG 视频中获取像素数据。使用相机代替视频作为输入并不困难。您基本上可以使用上述程序中的类中使用的纹理CodecOutputSurface作为捕获请求的输出纹理。