0

我想製作我自己的SurfaceView併發送一個幀,我已經從onPreviewFrame(byte [] data,Camera camera)方法獲得了這些幀。 要做到這一點,我需要將幀從Yuv轉換爲ARGB,並將它們繪製到我的SurfaceView的畫布上。Renderscript ScriptIntrinsicYuvToRGB和位圖分配

這裏是我的onPreviewFrame:

 public void onPreviewFrame(byte[] data, Camera camera) { 

     if (camera != null) { 
      camera.addCallbackBuffer(data); 
     } 

     // using RenderScript 
     Bitmap bitmap = RenderScriptFilter.convertYuvToRgbIntrinsic(rs, data, PREVIEW_WIDTH, PREVIEW_HEIGHT); 

     if (mFilterSurfaceView != null) { 
      SurfaceHolder holder = mFilterSurfaceView.getHolder(); 
      Canvas canvas = holder.lockCanvas(); 

      // draw bitmap to the canvas 
      canvas.drawBitmap(bitmap, 0, 0, mPaint); 

      holder.unlockCanvasAndPost(canvas); 
      mFrames++; 
      System.gc(); 
     } 
    } 
}; 

這裏是convertYuvToRgbIntrinsic方法:

public static Bitmap convertYuvToRgbIntrinsic(RenderScript rs, byte[] data, int w, int h) { 

    int imageWidth = w ; 
    int imageHeight = h ; 

    ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.RGBA_8888(rs)); 

    // Create the input allocation memory for Renderscript to work with 
    Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)) 
      .setX(imageWidth) 
      .setY(imageHeight) 
      .setYuvFormat(android.graphics.ImageFormat.NV21); 

    Allocation aIn = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT); 
    // Set the YUV frame data into the input allocation 
    aIn.copyFrom(data); 


    // Create the output allocation 
    Type.Builder rgbType = new Type.Builder(rs, Element.RGBA_8888(rs)) 
      .setX(imageWidth) 
      .setY(imageHeight); 

    Allocation aOut = Allocation.createTyped(rs, rgbType.create(), Allocation.USAGE_SCRIPT); 



    yuvToRgbIntrinsic.setInput(aIn); 
    // Run the script for every pixel on the input allocation and put the result in aOut 
    yuvToRgbIntrinsic.forEach(aOut); 

    // Create an output bitmap and copy the result into that bitmap 
    Bitmap outBitmap = Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888); 
    aOut.copyTo(outBitmap); 

    return outBitmap ; 

} 

我覺得似乎是因爲System.gc()的方法的問題。 因爲當我試着用640×480全沒關係,但與1280×720我得到了一些錯誤:

12-30 13:06:59.063 18034-18178/youten.redo.y2ndkyuv420sp E /的renderScript:rsAssert失敗:CMD- > cmdID <(sizeof(gPlaybackFuncs)/ sizeof(void *)),in frameworks/rs/rsThreadIO.cpp at 156 12-30 13:06:59.063 18034-18178/youten.redo.y2ndkyuv420sp E/RenderScript:playCoreCommands錯誤con 0x78fb79a0,cmd 2072915616 12-30 13:06:59.063 18034-18178/youten.redo.y2ndkyuv420sp A/libc:0x2fa27a84(代碼= 1)的致命信號11(SIGSEGV),線程18178(o.y2ndkyuv420sp)

我明白System.gc()是一個不好的習慣,但是在這裏做什麼來分配內存? bitmap.recycle();位圖=空;沒有解決這個問題。

回答

0

我不知道是什麼觸發了你的錯誤,以及這可能與垃圾收集器有關。無論如何,1280x720位圖可能會快速耗盡您的內存。

爲每個幀重新創建所有renderscript分配是相反的。關鍵是要做好一切準備工作,並重復使用。

附找到我使用的效用函數:

public Bitmap convertYuvImageToBitmap(Context context, YuvImage yuvImage) { 

    int w = yuvImage.getWidth(); 
    int h = yuvImage.getHeight(); 

    if (rs == null) { 
     // once 
     rs = RenderScript.create(context); 
     yuvToRgb = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs)); 
    } 

    if (yuvAllocation == null || yuvAllocation.getBytesSize() < yuvImage.getYuvData().length) { 
     yuvType = new Type.Builder(rs, Element.U8(rs)).setX(yuvImage.getYuvData().length); 
     yuvAllocation = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT); 
     Log.w(TAG, "allocate in " + yuvAllocation.getBytesSize() + " " + w + "x" + h); 
    } 

    if (rgbaAllocation == null || 
      rgbaAllocation.getBytesSize() < rgbaAllocation.getElement().getBytesSize()*w*h) { 
     rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(w).setY(h); 
     rgbaAllocation = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT); 
     Log.w(TAG, "allocate out " + rgbaAllocation.getBytesSize() + " " + w + "x" + h); 
    } 

    yuvAllocation.copyFrom(yuvImage.getYuvData()); 

    yuvToRgb.setInput(yuvAllocation); 
    yuvToRgb.forEach(rgbaAllocation); 

    if (bmpout == null) { 
     bmpout = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
    } 
    rgbaAllocation.copyTo(bmpout); 
    return bmpout; 
} 
+0

謝謝!你的代碼運行良好。我已經用Nexus 7進行測試,在1920x1080的內存中保存大約20幀,並且效果很好。早些時候,我在聯想瑜伽標籤2上測試了我的舊代碼,並且拋出了錯誤。所以,似乎這個延遲功能並不適合所有設備。無論如何,使用Renderscript從yuv轉換到rgb要比使用jni更快。 –

相關問題