使用Allocations和RenderScript的内存错误

问题描述:

我正在将WiFi摄像头直播到我的Android平板电脑。我有在一个线程中运行的图像采集卡,它接着将像素并将它们传递给RenderScript以执行一些过滤处理(另一个线程)。我的输出分配链接到Surface进行查看。使用Allocations和RenderScript的内存错误

该应用程序将定期崩溃与SIGSEGV故障,监视器说它发生在线程,GCDaemon或JNISurfaceTexture。我有2个内核,我正在运行(可切换),最终都会失败。更基本的内核仅仅是一个像素[]从摄像机进入输入分配,然后发送到RenderScript,然后使用.ioSend()将结果输出分配给'forEach'调用。

如果我从摄像头线程中获取像素[]数组,并将其直接复制到输出Allocation,并调用.ioSend(),它从不崩溃(即避开RenderScript调用)。我也可以创建另一个输出分配(临时一个),并将其用作'forEach'调用的返回输出分配,将其复制到Surface链接的输出分配,并且不会崩溃,尽管我的确在图形中获得了一些奇怪的像素化效果视频。

我对RenderScript还是有点新意,但是可能会出现一些我不知道的线程安全问题?或者RS()中的一个bug?

这里是我正在配置的输入和输出分配:

android.renderscript.Element elemIN = android.renderscript.Element.createPixel(mRS, android.renderscript.Element.DataType.UNSIGNED_8, android.renderscript.Element.DataKind.PIXEL_RGBA); 
     Type.Builder TypeIn = new Type.Builder(mRS, elemIN); 

     mAllocationIn = Allocation.createTyped(mRS, 
      TypeIn.setX(videoWidth).setY(videoHeight).create(), 
      Allocation.MipmapControl.MIPMAP_NONE,  
      Allocation.USAGE_SCRIPT); 

mAllocationOut = Allocation.createTyped(mRS, TypeOUT.setX(videoWidth).setY(videoHeight).create(), 
      Allocation.MipmapControl.MIPMAP_NONE,  
      (Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_OUTPUT)); 

这里是我的简单的RGB内核:

uchar4 __attribute__((kernel)) toRgb_Color(uchar4 in) { 
    float4 ndviPixel; 
    uchar4 out; 

    ndviPixel.r = (float)(in[0]/255.0); 
    ndviPixel.g = (float)(in[1]/255.0); 
    ndviPixel.b = (float)(in[2]/255.0); 
    ndviPixel.a = 1.0f; 

    out = rsPackColorTo8888(ndviPixel); 
    ndviPixel = 0; 

    return out; 
} 

最后,我呼吁内核是:

mScript.forEach_toRgb_Color(mAllocationIn, mAllocationTemp); 

UPDATE

这里是如何,我宣布我TypeOUT:

mAllocationOut = Allocation.createTyped(mRS, TypeOUT.setX(videoWidth).setY(videoHeight).create(), 
      Allocation.MipmapControl.MIPMAP_NONE,  
      (Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_OUTPUT)); 

而且,我在等待表面从onSurfaceTextureAvailable事件创建像这样:

public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { 
     mSurface = new Surface(surfaceTexture); 
} 

创建我的输入和输出分配后,我使用锁存的'mSurface'来设置输出分配的输出表面,lik e这:

 mAllocationOut.setSurface(mSurface); 

我有mSurface声明为静态,如果这有什么区别。我尝试过和没有静态,我仍然得到崩溃。

监视器输出是在这里:

04-23 12:59:54.752: A/libc(15192): Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 15230 (Thread-1697) 
04-23 12:59:54.853: I/DEBUG(189): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 
04-23 12:59:54.853: I/DEBUG(189): Build fingerprint: 'nvidia/wx_na_wf/shieldtablet:5.0.1/LRX22C/29979_515.3274:user/release-keys' 
04-23 12:59:54.853: I/DEBUG(189): Revision: '0' 
04-23 12:59:54.853: I/DEBUG(189): ABI: 'arm' 
04-23 12:59:54.854: I/DEBUG(189): pid: 15192, tid: 15230, name: Thread-1697 >>> helios.android <<< 
04-23 12:59:54.854: I/DEBUG(189): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 
04-23 12:59:54.876: I/DEBUG(189):  r0 6f81a568 r1 00000001 r2 00000000 r3 00000000 
04-23 12:59:54.877: I/DEBUG(189):  r4 630a3200 r5 6f81a568 r6 00000000 r7 00000001 
04-23 12:59:54.877: I/DEBUG(189):  r8 12c24000 r9 7c9a0f40 sl 7e86d404 fp 00000008 
04-23 12:59:54.877: I/DEBUG(189):  ip 7f8e1a10 sp 7f8e1970 lr 4211475d pc 420d3f72 cpsr 200f0030 
04-23 12:59:54.878: I/DEBUG(189): backtrace: 
04-23 12:59:54.878: I/DEBUG(189):  #00 pc 000d3f72 /system/lib/libart.so (void std::__1::__tree_remove<std::__1::__tree_node_base<void*>*>(std::__1::__tree_node_base<void*>*, std::__1::__tree_node_base<void*>*)+205) 
04-23 12:59:54.878: I/DEBUG(189):  #01 pc 00114759 /system/lib/libart.so (art::gc::allocator::RosAlloc::RefillRun(art::Thread*, unsigned int)+232) 
04-23 12:59:54.878: I/DEBUG(189):  #02 pc 00114973 /system/lib/libart.so (art::gc::allocator::RosAlloc::AllocFromRun(art::Thread*, unsigned int, unsigned int*)+490) 
04-23 12:59:54.879: I/DEBUG(189):  #03 pc 0028ba97 /system/lib/libart.so (artAllocObjectFromCodeInitializedRosAlloc+98) 
04-23 12:59:54.879: I/DEBUG(189):  #04 pc 000a23cb /system/lib/libart.so (art_quick_alloc_object_initialized_rosalloc+10) 
04-23 12:59:54.879: I/DEBUG(189):  #05 pc 001d6359 /data/dalvik-cache/arm/[email protected]@boot.oat 
04-23 12:59:55.360: I/DEBUG(189): Tombstone written to: /data/tombstones/tombstone_01 
04-23 12:59:55.361: I/BootReceiver(659): Copying /data/tombstones/tombstone_01 to DropBox (SYSTEM_TOMBSTONE) 

问题在于您访问输入Allocation的方式。 Allocation中的每个元素都提供了全部4个组件。但是,它不能像这里所做的那样被当作一个数组来处理。试试这个:

uchar4 __attribute__((kernel)) toRgb_Color(uchar4 in) { 
    float4 tmpPixel = convert_float4(in); 

    // This copy is most likely unnecessary, but done for 
    // completeness. 
    float4 ndviPixel.r = tmpPixel.x; 
      ndviPixel.g = tmpPixel.y; 
      ndviPixel.b = tmpPixel.z; 
      ndviPixel.a = 255.0; 
    uchar4 out = rsPackColorTo8888(ndviPixel); 
    return out; 
} 
+0

好东西,很高兴你能够得到那个工作好。我猜你在做像素操作时是怎么做的,所以我不惊讶它有一些麻烦。但是,解决你的问题(崩溃)的关键是正确使用'uchar4'作为矢量而不是数组。 –

+0

无赖。我想我说得太快了。我剥离了我的RGB内核,只返回'uchar4 in',一段时间后我仍然崩溃。 –

+0

是否以'TypeIn'相同的方式创建'TypeOut'?用logcat(崩溃)输出更新您的原始帖子。 –

也许有像你说的(你得到OOM试图抓住这一点?)......你流的内容确实是一些致命的内存错误?也许你想要缓冲到很多...也许你给surfaceflinger一个太大的缓冲区...因为你直接控制像素和缓冲区的大小,如果不仔细地做,可能会发生很多错误......你是否可能锁定表面你的应用?这意味着你无法控制画布的大小,因此不再控制缓冲区大小......如果io不能帮助你,但是你已经准备好搜索你在谷歌上的错误了吗?