使用 Allocations 和 RenderScript 的内存错误

Memory errors using Allocations and RenderScript

我正在将 WiFi 摄像头实时流式传输到我的 Android 平板电脑。我在一个线程中有图像采集卡 运行,它依次获取像素并将它们传递给 RenderScript 以进行一些过滤处理(另一个线程)。我的输出 Allocation 链接到 Surface 以供查看。

该应用程序会因 SIGSEGV 错误而定期崩溃,监视器表示它发生在线程、GCDaemon 或 JNISurfaceTexture 中。我有 2 个内核,目前是 运行(可切换),两者最终都会失败。更基本的内核只是从相机到输入 Allocation 的一个像素 [],它被发送到 RenderScript,然后使用 .ioSend() 将 'forEach' 调用的结果输出 Allocation 发送到表面。

如果我从相机线程中获取像素 [] 数组并将其直接复制到输出分配,并调用 .ioSend(),它永远不会崩溃(即绕过 RenderScript 调用)。我还可以创建另一个输出分配(临时分配)并将其用作 'forEach' 调用的 return 输出分配,将其复制到 Surface 链接输出分配,它不会崩溃,尽管我确实得到了视频中出现一些奇怪的像素化效果。

我对 RenderScript 还是有点陌生​​,但会不会有一些我不知道的线程安全问题?或者可能是 RS() 中的错误?

这是我配置输入和输出分配的方式:

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

更新

这是我声明 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' 设置输出分配的输出表面,如下所示:

        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/system@framework@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)

也许真的像你说的那样存在一些致命的内存错误(你有 OOM 吗?试着抓住这个)...你在流式传输内容吗?也许你想缓冲太多......也许你给了 surfaceflinger 一个太大的缓冲区......因为你直接控制像素和缓冲区大小,如果不仔细做就会发生很多错误......你是否可能将表面锁定在你的应用程序?这将意味着您无法控制 canvas 的大小,因此无法再控制缓冲区大小...如果 io 无法进一步帮助您,我很抱歉,但是您是否已经准备好搜索 google 上的错误?

问题在于您访问输入的方式 AllocationAllocation 中的每个元素都提供了所有 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;
}