0

Under Android/NDK, I am using the next algorithm to convert from RGB to YUV420sp. I started to have a small amount of crash reports from some users. So after they sent me the logs, all seemed to fail in the next algorithm at the point I market with a comment, right at the second algorithn decodeARGB888_YUV420sp, the logs show a SIGILL error, which I found it has the next definition:

Illegal Instruction (ANSI) Generally indicates that the executable file is corrupted or use of data where a pointer to a function was expected.

The reports all come from the SGSII-skyrocket and Rogers variants, and the Samsung Captivate Glide. And not in all of them, as some other users with these devices also reported no problems at all.

Is there something specific with these devices hardware? Or any known bug? Or am I doing something wrong in my code?

JNIEXPORT void JNICALL Java_com_test_NatLib_decodeBitmapToYuv420sp(JNIEnv *env, jobject javaThis, jobject bitmap, jbyteArray yuv)
{
    AndroidBitmapInfo bitmapInfo;
    int code;
    void *nativeRGBPixels;

    if ((code = AndroidBitmap_getInfo(env, bitmap, &bitmapInfo)) < 0)
    {
        return;
    }

    if ((code = AndroidBitmap_lockPixels(env, bitmap, (void**)&nativeRGBPixels)) < 0)
    {
        return;
    }

    char *nativeYuvPixels = (char*)env->GetByteArrayElements(yuv, 0);

    decodeARGB888_YUV420sp(nativeRGBPixels, nativeYuvPixels, bitmapInfo.width, bitmapInfo.height);

    env->ReleaseByteArrayElements(yuv, (jbyte*)nativeYuvPixels , 0);
    AndroidBitmap_unlockPixels(env, bitmap);
}

static void decodeARGB888_YUV420sp(const int *argb, char *yuv, const int width, const int height)
{
    const int totalPixels = width * height;
    int indexPixel = 0;
    int indexY = 0;
    int indexUV = totalPixels;
    int R, G, B, Y, U, V;
    int x, y;

    for (y = 0; y < height; y++)
    {
        for (x = 0; x < width; x++)
        {

//--------------------------------------------------------------------
// AT THIS POINT IS WHERE THE LAST LOG WITH SIGILL WAS CAPTURED
//--------------------------------------------------------------------

            const int pixelValue = argb[indexPixel];

            R = pixelValue & 0xff;
            G = (pixelValue & 0xff00) >> 8;
            B = (pixelValue & 0xff0000) >> 16;

            // RGB to YUV algorithm for component Y
            Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;

            // NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2 meaning for
            // every 4 Y pixels there are 1 V and 1 U. Note the sampling is every other pixel AND every other scanline
            yuv[indexY++] = (char)((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));

            if (y % 2 == 0 && indexPixel % 2 == 0)
            {
                // RGB to YUV algorithm for component U & V
                U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
                V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;

                yuv[indexUV++] = (char)((V < 0) ? 0 : ((V > 255) ? 255 : V));
                yuv[indexUV++] = (char)((U < 0) ? 0 : ((U > 255) ? 255 : U));
            }

            indexPixel++;
        }
    }
}
PerracoLabs
  • 16,449
  • 15
  • 74
  • 127
  • 1
    I have a feeling these are all Tegra2 devices. Check out http://stackoverflow.com/questions/7102606/sigill-in-android-ndk-code – avish Jul 18 '13 at 04:07
  • Hi, the solution posted in your comment about the Tegra2 devices solved the problem. Thanks – PerracoLabs Jul 18 '13 at 11:49

2 Answers2

1

Since it is about SIGILL it is probably you are loosing env, its values goes garbage and processor executes some area in memory which is not instructions (text) but data. That's because jump target is calculated over env instance.

You can read JNI Tips to get some pointers aroudn env usage.

auselen
  • 27,577
  • 7
  • 73
  • 114
  • Yes this is what I am starting to think might be the problem, but if so, then I have no idea how to stop the garbage collector or whoever to stop messing with the parameters. About the second of the method signature, sorry it was a typo, thanks for spotting it, I have updated the answer. – PerracoLabs Jun 17 '13 at 08:58
  • it might be due to many things, because of that I'll just suggest you to read http://developer.android.com/training/articles/perf-jni.html – auselen Jun 17 '13 at 09:48
0

@Zhenya, I think that the actual solution should be different. You probably have in your Android.mk something like:

#ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
   LOCAL_ARM_NEON := true
#endif

This is WRONG. armeabi-v7a does not necessarily imply NEON (eg, Tegra2 chipset). Instead the check for NEON optimized code should always be a runtime check, and you can find documentation within the NDK on how to do that.

avish
  • 82
  • 1
  • 9
  • I agree with you about the NEON check, but as you can see in my code I don't use any neon at all in the algorithm, so makes no sense that it is failing because of neon. – PerracoLabs Jul 21 '13 at 16:33