Camera中有很多check预览帧的需求,可以在应用层、HAL层通过不同的方法dump数据进而check某一时刻的Camera YUV数据、RGBA数据是否有异常,本节主要分析应用层dump 预览流YUV数据的方法,之后会继续check GPU框架下dump GLSurfaceView的RGBA数据的方法以及HAL层dump数据的节点和相关命令。
1.保存预览上来的YUV数据
配置YUV数据
配置预览回调数据
private static class CameraPreViewCallbackForward extends CameraPreViewCallbackAbstract {
private final Handler mHandler;
private final CameraPreviewDataCallback mCallback;
private final CameraAgent.CameraProxy mCamera;
public static CameraPreViewCallbackForward getNewInstance(Handler handler,
CameraProxy camera, CameraPreviewDataCallback cb) {
if (handler == null || camera == null || cb == null)
return null;
return new CameraPreViewCallbackForward(handler, camera, cb);
}
private CameraPreViewCallbackForward(Handler h, CameraProxy camera, CameraPreviewDataCallback cb) {
mHandler = h;
mCallback = cb;
mCamera = camera;
}
@Override
public void onImageAvailable(ImageReader reader) {
try (Image image = reader.acquireNextImage()) {
if(mAppMode == /*SettingsScopeNamespaces.PANORAMA*/37){
final Plane[] planeList = image.getPlanes();
if(planeList.length == 3){
...
onPreviewFrameImage(byteBuffer, rowStride, pixelStride);
}
}else{
//这边拿到绑定了mPreviewReader的YUV数据
onPreviewFrame(getNV21FromImage(image), mCamera);
}
}
}
@Override
public void onPreviewFrame(byte[] data, CameraAgent.CameraProxy camera) {
mHandler.post(new Runnable() {
@Override
public void run() {
//传给之前的callback回调
mCallback.onPreviewFrame(data, mCamera);
}
});
}
public void onPreviewFrameImage(ByteBuffer[] byteBuffer , int[] rowStride, int[] pixelStride){//add by cyy for 360 panorama request
mHandler.post(new Runnable() {
@Override
public void run() {
mCallback.onPreviewFrameImage(byteBuffer , rowStride, pixelStride);
}
});
}
}
保存YUV数据
public static String saveYuvImage(byte[] data, String path, String name){
if (data == null)
return null;
//File mediaStorageDir = mContext.getExternalFilesDir("megvii");
//File dir = new File(mediaStorageDir, path);
File dir = new File(path);
if (!dir.exists()) {
if (!dir.mkdirs()) {
return null;
}
}
String yuvFileName = name + ".yuv";
// String bitmapFileName = System.currentTimeMillis() + "";
File file = new File(dir, yuvFileName);
FileOutputStream fos = null;
String ret = null;
try {
fos = new FileOutputStream(file);
fos.write(data);
ret = file.getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fos != null) fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return ret;
}
SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");
String date = sDateFormat.format(new java.util.Date());
File mediaStorageDir = mActivity.getAndroidContext().getExternalFilesDir("DCIM");
File d = new File(mediaStorageDir, path);
//File d = new File("/storage/emulated/0/bitmap/");
File f = new File(d, date + ".yuv");
if (!d.exists()) {
d.mkdirs();
}
if (f.exists()) {
f.delete();
}
try {
FileOutputStream out = new FileOutputStream(f);
out.write(data);
out.flush();
out.close();
} catch (IOException e) {
Log.e(TAG, "CameraSaveBitmap saveBitmapToFileException:" + f.getAbsolutePath() + " Exception");
e.printStackTrace();
}
}
dump出来的预览图
原始的:
旋转90度的:
旋转yuv数据:
byte[] rotatedData = new byte[data.length];
for (int y = 0; y < cameraHeight; y++) {
for (int x = 0; x < cameraWidth; x++)
rotatedData[x * cameraHeight + cameraHeight - y - 1] = data[x + y * cameraWidth];
}
int tmp = cameraWidth;
cameraWidth = cameraHeight;
cameraHeight = tmp;
旋转时候没有去check stride,但是算法那边只读取y数据,所以没有造成太大影响
final Plane[] planeList = image.getPlanes();
if(planeList.length == 3){
final ByteBuffer[] byteBuffer = new ByteBuffer[3];
final int[] rowStride = new int[3];
final int[] pixelStride = new int[3];
byteBuffer[0] = planeList[0].getBuffer();
rowStride[0] = planeList[0].getRowStride();
pixelStride[0] = planeList[0].getPixelStride();
byteBuffer[1] = planeList[1].getBuffer();
rowStride[1] = planeList[1].getRowStride();
pixelStride[1] = planeList[1].getPixelStride();
byteBuffer[2] = planeList[2].getBuffer();
rowStride[2] = planeList[2].getRowStride();
pixelStride[2] = planeList[2].getPixelStride();
onPreviewFrameImage(byteBuffer, rowStride, pixelStride);
}
总结:
今天正好遇到算法检测不到人脸数据的问题,流程上看不出一些问题,然后就疯狂dump各个节点的流数据进行分析,那酸爽不言而喻,然后就乘机把dump的一些流程进行一下总结,痛苦被记录下来以后再遇到就没那么痛苦了吧!