2017-06-19 17 views
0

OnPreviewFrame()でフレームをキャプチャし、スレッドで処理して有効かどうかを確認しています。 validateFrameでOutOfMemory 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); 
      } 
     }  
    } 

()、私は並列フレームを処理するために、4コアおよび最大スレッドとThreadPoolExecutorにValidatorThread実行可能なインスタンスを送信します。複数のフレームを処理している間、私はメモリエラーOutOf取得しています

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 
} 

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クラスには、このような宣言があります。

コードが必要とするメモリの最適化は誰でも助けてくれますか?

+0

おそらく、キャプチャされたフレームの解像度は高いです。処理する前にYuvImageとビットマップのサイズを変更しようとしてください – MatPag

+0

ヒープが割り当て解除されていません..コードにメモリリークはありますか? –

+0

メソッドの最後にビットマップをnullに設定しようとしましたか? – MatPag

答えて

0

Jpegを経由せずにYUVデータからグレースケールビットマップを作成すると、メモリ使用量を減らすことができます。これはまた、はるかに高速です。

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); 
} 

また、あなたはint[width*height]ピクセル配列を経由せずにRGB_565ビットマップを作成し、NDKを使用して所定の位置にビットマップのピクセルを操作することができます。

+0

これはint [] ..を返しています。私はBitmap.decodeByteArray()ではなくcreatebitmap()を使用したいので、バイト[] ..でグレースケールデータを取得できます。 –

+0

decodeByteArray()は圧縮ストリームで動作しますBitmapFactory.decodeByteArray(...)](https://stackoverflow.com/questions/24333450/formats-supported-by-bitmapfactory-decodebytearray *)でサポートされている形式ですが、カメラはYUVを生成します。それをJPEGに圧縮してBitmapに戻すと、時間とメモリの両方が浪費されます。 –

関連する問題