我正在尝试在具有camera2(Galaxy S7)全功能的android设备上以固定帧速率(最好高达30)保存图像序列,但我无法a)获得稳定的帧速率,b)甚至达到20fps(使用jpeg编码)。我已经包括了来自
Android camera2 capture burst is too slow
.
JPEG的最小帧持续时间为33.33毫秒(分辨率低于1920x1080),根据
characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputMinFrameDuration(ImageFormat.JPEG, size);
每种尺寸的失速持续时间为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));
焦距设置为0.0(inf),iso设置为100,曝光时间为5ms。白平衡可以设置为关闭/自动/任何值,它不会影响以下时间。
我使用以下命令启动捕获会话:
session.setRepeatingRequest(_capReq.build(), captureListener, mBackgroundHandler);
注意:如果我请求RepeatingRequest或RepeatingBurst,则没有区别。。
在预览(仅附加纹理表面)中,所有内容均为30fps。
然而,只要我附加了一个图像读取器(在HandlerThread上运行的侦听器),我就会像下面这样实例化(不保存,只测量帧之间的时间):
reader = ImageReader.newInstance(_img_width, _img_height, ImageFormat.JPEG, 2);
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
带有时间测量代码:
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();
}
}
我周期性地重复时间差,如下所示:
99毫秒-66毫秒-66毫秒-99毫秒-66 ms-66毫秒。。。
我不明白为什么流配置映射为jpeg广告所花费的时间是原来的两倍或三倍?曝光时间远低于33ms的帧持续时间。是否有其他我不知道的内部处理发生?
我对YUV_420_888格式也尝试了同样的方法,这导致了33ms的恒定时间差。我在这里遇到的问题是,手机缺乏足够快的带宽来存储图像(我尝试了中描述的方法)
How to save a YUV_420_888 image?
). 如果你知道任何方法来压缩或编码这些图像足够快自己,请让我知道。
编辑:来自getOutputStallDuration的文档:“换句话说,使用重复的YUV请求将导致稳定的帧速率(假设为30 FPS)。如果定期提交单个JPEG请求,帧速率将保持在30 FPS(只要我们每次等待上一个JPEG返回)如果我们尝试提交重复的YUV+JPEG请求,则帧速率将从30fps下降。“这是否意味着我需要定期请求单个捕获()?
编辑2:来自
https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html
:“给定上述模型,应用程序的必要信息通过android.scaler.streamConfigurationMap字段使用getOutputMinFrameDuration(int,Size)提供。这些信息用于确定给定流配置可能的最大帧速率/最小帧速率。
具体而言,应用程序可以使用以下规则来确定其可以从摄像机设备请求的最小帧持续时间:
将当前配置的输入/输出流集合称为S。
通过在android.scaler中查找每个流的最小帧持续时间,以S为单位。使用getOutputMinFrameDuration(int,Size)的streamConfigurationMap(具有各自的大小/格式)。让这组帧持续时间称为F。
对于任何给定的请求R,R允许的最小帧持续时间是F中所有值中的最大值。将R中使用的流称为S_R。
如果S_r中的所有流都没有暂停时间(使用各自的大小/格式在getOutputStallDuration(int,Size)中列出),则F中的帧持续时间决定了应用程序在使用r作为重复请求时将获得的稳态帧速率。”