我想创建自己的SurfaceView并向其发送一个我从onPreviewFrame(byte []数据,Camera camera)方法获得的帧。 要做到这一点,我需要将Yuv中的帧转换为ARGB,并将它们绘制到Canvas到我的SurfaceView。
这是我的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()方法。 因为当我尝试使用640x480时一切都还可以,但是使用1280x720我会得到一些错误:
12-30 13:06:59.063 18034-18178 / youten.redo.y2ndkyuv420sp E / RenderScript:rsAssert失败:cmd-> cmdID< (sizeof(gPlaybackFuncs)/ sizeof(void *)),在156的frameworks / rs / rsThreadIO.cpp中 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:致命信号11(SIGSEGV)位于0x2fa27a84(代码= 1),线程18178(o.y2ndkyuv420sp)
我知道System.gc()是一个不好的做法,但是这里要做什么来分配内存? bitmap.recycle(); bitmap = null;没有解决问题。
答案 0 :(得分: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;
}