Android 处理onPreviewFrame中的帧时发生OutOfMemory错误
我在OnPreviewFrame()中捕获帧,然后在线程中处理它们以检查它们是否有效Android 处理onPreviewFrame中的帧时发生OutOfMemory错误,android,multithreading,memory,android-camera,Android,Multithreading,Memory,Android Camera,我在OnPreviewFrame()中捕获帧,然后在线程中处理它们以检查它们是否有效 public void onPreviewFrame(byte[] data, Camera camera) { if (imageFormat == ImageFormat.NV21) { //We only accept the NV21(YUV420) format. frameCount++; if (frameCount > 19 &
public void onPreviewFrame(byte[] data, Camera camera) {
if (imageFormat == ImageFormat.NV21) {
//We only accept the NV21(YUV420) format.
frameCount++;
if (frameCount > 19 && frameCount % 2 == 0) {
Camera.Parameters parameters = camera.getParameters();
FrameModel fModel = new FrameModel(data);
fModel.setPreviewWidth(parameters.getPreviewSize().width);
fModel.setPreviewHeight(parameters.getPreviewSize().height);
fModel.setPicFormat(parameters.getPreviewFormat());
fModel.setFrameCount(frameCount);
validateFrame(fModel);
}
}
}
在validateFrame()中,我将一个validateThread可运行实例提交给一个ThreadPoolExecutor,该ThreadPoolExecutor具有4个核心线程和最多线程,以并行处理帧
public class ValidatorThread implements Runnable {
private FrameModel frame;
public ValidatorThread(FrameModel fModel) {
frame = fModel;
}
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
processNV21Data();
}
private void processNV21Data() {
YuvImage yuv = new YuvImage(frame.getData(), frame.getPicFormat(),
frame.getPreviewWidth(), frame.getPreviewHeight(), null);
frame.releaseData();
ByteArrayOutputStream out = new ByteArrayOutputStream();
yuv.compressToJpeg(new Rect(0, 0, frame.getPreviewWidth(), frame.getPreviewHeight()), 100, out);
byte[] bytes = out.toByteArray();
yuv = null;
try {
if (out != null)
out.close();
out = null;
} catch (IOException e) {
e.printStackTrace();
}
Bitmap baseBitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
bytes = null;
// rotate bitmap
baseBitmap = rotateImage(baseBitmap, frame.getRotation());
//create copy of original bitmap to use later
Bitmap mCheckedBitmap = baseBitmap.copy(Bitmap.Config.ARGB_8888, true);
// convert base bitmap to greyscale for validation
baseBitmap = toGrayscale(baseBitmap);
boolean isBitmapValid = Util.isBitmapValid(baseBitmap);
if (isBitmapValid) {
baseBitmap.recycle();
mCheckedBitmap.recycle();
frame = null;
} else {
baseBitmap.recycle();
mCheckedBitmap.recycle();
frame = null;
}
}
public Bitmap toGrayscale(Bitmap bmpOriginal) {
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
bmpOriginal.recycle();
return bmpGrayscale;
}
private Bitmap rotateImage(final Bitmap source, float angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
Bitmap rotatedBitmap = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
source.recycle();
return rotatedBitmap;
}
}
FrameModel类具有以下声明:
public class FrameModel {
private byte[] data;
private int previewWidth;
private int previewHeight;
private int picFormat;
private int frameCount;
public void releaseData() {
data = null;
}
// getters and setters
}
处理多个帧时出现内存不足错误
有人能帮助您优化代码所需的内存吗?如果您从YUV数据生成灰度位图而不经过Jpeg,则可以减少内存使用。这也将大大加快
public Bitmap yuv2grayscale(byte[] yuv, int width, int height) {
int[] pixels = new int[width * height];
for (int i = 0; i < height*width; i++) {
int y = yuv[i] & 0xff;
pixels[i] = 0xFF000000 | y << 16 | y << 16 | y;
}
return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.RGB_565);
}
公共位图yuv2grayscale(字节[]yuv,整数宽度,整数高度){
int[]像素=新int[宽度*高度];
对于(int i=0;i<高度*宽度;i++){
int y=yuv[i]&0xff;
像素[i]=0xFF000000 | y可能捕获的帧具有较大的分辨率。在处理它之前尝试调整YuvImage和位图的大小堆不会被释放。这里的代码中是否存在内存泄漏?是否尝试在方法末尾将位图设置为null?我调用recycle()在位图上..有时我注意到,当GC速度非常快时,回收并不能很好地工作这是返回int[]…我可以得到字节[]中的灰度数据吗…因为我想使用位图。decodeByteArray()而不是createbitmap()…decodeByteArray()在压缩流上工作(请参阅),但相机会产生YUV。若要将其压缩为JPEG并解压缩回位图,则会浪费时间和内存。