一、Camera2简介
Camera2是Google在Android 5.0后推出的一个全新的相机API,Camera2和Camera没有继承关系,是完全重新设计的,且Camera2支持的功能也更加丰富,但是提供了更丰富的功能的同时也增加了使用的难度。Google的官方Demo:
https://github.com/googlesamples/android-Camera2Basic
二、Camera2预览流程
Camera2 API使用流程如下
三、使用Camera2获取预览数据
1.获取预览数据
一般情况下,大多设备其实只支持ImageFormat.YUV_420_888
和ImageFormat.JPEG
格式的预览数据,而ImageFormat.JPEG
是压缩格式,一般适用于拍照的场景,而不适合直接用于算法检测,因此我们一般取ImageFormat.YUV_420_888
作为我们获取预览数据的格式,对于YUV不太了解的同学可以戳这里。
mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(),
ImageFormat.YUV_420_888, 2);
mImageReader.setOnImageAvailableListener(
new OnImageAvailableListenerImpl(), mBackgroundHandler);
其中OnImageAvailableListenerImpl
的实现如下
private class OnImageAvailableListenerImpl implements ImageReader.OnImageAvailableListener {
private byte[] y;
private byte[] u;
private byte[] v;
private ReentrantLock lock = new ReentrantLock();
@Override
public void onImageAvailable(ImageReader reader) {
runOnSubThread(new Runnable() {
@Override
public void run() {
Image image = reader.acquireNextImage();
// Y:U:V == 4:2:2
if (image.getFormat() == ImageFormat.YUV_420_888) {
Image.Plane[] planes = image.getPlanes();
// 加锁确保y、u、v来源于同一个Image
lock.lock();
// 重复使用同一批byte数组,减少gc频率
if (y == null) {
y = new byte[planes[0].getBuffer().limit() - planes[0].getBuffer().position()];
u = new byte[planes[1].getBuffer().limit() - planes[1].getBuffer().position()];
v = new byte[planes[2].getBuffer().limit() - planes[2].getBuffer().position()];
}
if (image.getPlanes()[0].getBuffer().remaining() == y.length) {
planes[0].getBuffer().get(y);
planes[1].getBuffer().get(u);
planes[2].getBuffer().get(v);
//2.处理数据
byte[] nv21 = new byte[planes[0].getRowStride() * mPreviewSize.getHeight() * 3 / 2];
yuv422ToYuv420sp(y, u, v, nv21, planes[0].getRowStride(), mPreviewSize.getHeight());
}
lock.unlock();
}
image.close();
}
});
}
}
2.将YUV_420_888的数据转化成nv21
/**
* 将Y:U:V == 4:2:2的数据转换为nv21
*
* @param y Y 数据
* @param u U 数据
* @param v V 数据
* @param nv21 生成的nv21,需要预先分配内存
* @param stride 步长
* @param height 图像高度
*/
public void yuv422ToYuv420sp(byte[] y, byte[] u, byte[] v, byte[] nv21, int stride, int height) {
System.arraycopy(y, 0, nv21, 0, y.length);
// 注意,若length值为 y.length * 3 / 2 会有数组越界的风险,需使用真实数据长度计算
int length = y.length + u.length / 2 + v.length / 2;
int uIndex = 0, vIndex = 0;
for (int i = stride * height; i < length; i += 2) {
nv21[i] = v[vIndex];
nv21[i + 1] = u[uIndex];
vIndex += 2;
uIndex += 2;
}
List<FacePreviewInfo> facePreviewInfos = HrHelper.getInstance().onPreviewFrame(nv21, true);
HrHelper.getInstance().clearLeftFace(facePreviewInfos);
}