Android 处理onPreviewFrame中的帧时发生OutOfMemory错误

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 &

我在OnPreviewFrame()中捕获帧,然后在线程中处理它们以检查它们是否有效

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并解压缩回位图,则会浪费时间和内存。