我正在将WiFi摄像头直播到我的Android平板电脑上。我有一个在线程中运行的帧抓取器,它依次获取像素并将它们传递给RenderScript以进行一些过滤处理(另一个线程)。我的输出分配链接到曲面以供查看。
该应用程序将定期因SIGSEGV故障而崩溃,监视器表示这发生在Thread、GCDaemon或JNISurfaceTexture中。我有两个内核,我目前正在运行(可切换),两者最终都会失败。更基本的内核只是从相机到输入Allocation的一个像素[],在那里它被发送到RenderScript,然后使用.ioSend()将"forEach"调用的结果输出Allocation发送到曲面。
如果我从相机线程中获取pixel[]数组,并将其直接复制到输出Allocation,然后调用.ioSend(),它就不会崩溃(即绕过RenderScript调用)。我还可以创建另一个输出分配(临时分配),并将其用作"forEach"调用的返回输出分配,将其复制到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)
问题在于访问输入Allocation
的方式。CCD_ 2中的每个元件都具有全部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;
}
也许真的有一些致命的内存错误,就像你说的那样(你有OOM吗?试着抓住它)。。。你在流媒体播放内容吗?也许你想缓冲很多。。。也许你给了surfaceflinger太大的缓冲。。。由于直接控制像素和缓冲区大小,如果不小心操作,可能会出现许多错误。。。你可能在应用程序中锁定了表面吗?这意味着你不能再控制画布的大小,因此缓冲区的大小。。。如果io不能进一步帮助你,我很抱歉,但你已经准备好在谷歌上搜索错误了吗?