Decodificación de YUV a RGB en C / C ++ con NDK

Estoy tratando de convertir la alimentación de la cámara Android a un mapa de bits para el procesamiento de imágenes.

Tengo un código que convierte YUV a RGB en Java nativo que funciona, sin embargo, este proceso no es lo suficientemente rápido para el video en tiempo real, así que creo que tengo que convertirlo en C o C ++ antes de aplicar los filtros. Ya tengo el NDK configurado y trabajando así que el único bit que no sé cómo hacer es portar el siguiente código a C o C ++:

// decode Y, U, and V values on the YUV 420 buffer described as YCbCr_422_SP by Android // David Manpearl 081201 public void decodeYUV(int[] out, byte[] fg, int width, int height) throws NullPointerException, IllegalArgumentException { int sz = width * height; if (out == null) throw new NullPointerException("buffer out is null"); if (out.length < sz) throw new IllegalArgumentException("buffer out size " + out.length + " < minimum " + sz); if (fg == null) throw new NullPointerException("buffer 'fg' is null"); if (fg.length < sz) throw new IllegalArgumentException("buffer fg size " + fg.length + " < minimum " + sz * 3 / 2); int i, j; int Y, Cr = 0, Cb = 0; for (j = 0; j < height; j++) { int pixPtr = j * width; final int jDiv2 = j >> 1; for (i = 0; i < width; i++) { Y = fg[pixPtr]; if (Y < 0) Y += 255; if ((i & 0x1) != 1) { final int cOff = sz + jDiv2 * width + (i >> 1) * 2; Cb = fg[cOff]; if (Cb < 0) Cb += 127; else Cb -= 128; Cr = fg[cOff + 1]; if (Cr < 0) Cr += 127; else Cr -= 128; } int R = Y + Cr + (Cr >> 2) + (Cr >> 3) + (Cr >> 5); if (R < 0) R = 0; else if (R > 255) R = 255; int G = Y - (Cb >> 2) + (Cb >> 4) + (Cb >> 5) - (Cr >> 1) + (Cr >> 3) + (Cr >> 4) + (Cr >> 5); if (G < 0) G = 0; else if (G > 255) G = 255; int B = Y + Cb + (Cb >> 1) + (Cb >> 2) + (Cb >> 6); if (B < 0) B = 0; else if (B > 255) B = 255; out[pixPtr++] = 0xff000000 + (B << 16) + (G << 8) + R; } } } 

 decodeYUV(argb8888, data, camSize.width, camSize.height); Bitmap bitmap = Bitmap.createBitmap(argb8888, camSize.width, camSize.height, Config.ARGB_8888); 

¿Alguien sabe como hacer esto?

¡Muchas gracias!


Actualizar

Esto es lo lejos que tengo:

 JNIEXPORT void JNICALL Java_com_twothreetwo_zoomplus_ZoomPlus_YUVtoRGB(JNIEnv * env, jobject obj, jintArray rgb, jbyteArray yuv420sp, jint width, jint height) { int sz; int i; int j; int Y; int Cr = 0; int Cb = 0; int pixPtr = 0; int jDiv2 = 0; int R = 0; int G = 0; int B = 0; int cOff; sz = width * height; //if(out == null) throw new NullPointerException("buffer 'out' is null"); //if(out.length < sz) throw new IllegalArgumentException("buffer 'out' size " + out.length + " < minimum " + sz); //if(fg == null) throw new NullPointerException("buffer 'fg' is null"); //if(fg.length < sz) throw new IllegalArgumentException("buffer 'fg' size " + fg.length + " < minimum " + sz * 3/ 2); for(j = 0; j < height; j++) { pixPtr = j * width; jDiv2 = j >> 1; for(i = 0; i < width; i++) { Y = yuv420sp[pixPtr]; if(Y < 0) Y += 255; if((i & 0x1) != 1) { cOff = sz + jDiv2 * width + (i >> 1) * 2; Cb = yuv420sp[cOff]; if(Cb < 0) Cb += 127; else Cb -= 128; Cr = yuv420sp[cOff + 1]; if(Cr < 0) Cr += 127; else Cr -= 128; } R = Y + Cr + (Cr >> 2) + (Cr >> 3) + (Cr >> 5); if(R < 0) R = 0; else if(R > 255) R = 255; G = Y - (Cb >> 2) + (Cb >> 4) + (Cb >> 5) - (Cr >> 1) + (Cr >> 3) + (Cr >> 4) + (Cr >> 5); if(G < 0) G = 0; else if(G > 255) G = 255; B = Y + Cb + (Cb >> 1) + (Cb >> 2) + (Cb >> 6); if(B < 0) B = 0; else if(B > 255) B = 255; rgb[pixPtr++] = 0xff000000 + (B << 16) + (G << 8) + R; } } } 

Pero estoy recibiendo los siguientes errores C:

 apps/zoomplusndk/jni/zoomplusndk.c:53: warning: dereferencing 'void *' pointer apps/zoomplusndk/jni/zoomplusndk.c:53: error: void value not ignored as it ought to be apps/zoomplusndk/jni/zoomplusndk.c:56: warning: dereferencing 'void *' pointer apps/zoomplusndk/jni/zoomplusndk.c:56: error: void value not ignored as it ought to be apps/zoomplusndk/jni/zoomplusndk.c:58: warning: dereferencing 'void *' pointer apps/zoomplusndk/jni/zoomplusndk.c:58: error: void value not ignored as it ought to be apps/zoomplusndk/jni/zoomplusndk.c:67: warning: dereferencing 'void *' pointer apps/zoomplusndk/jni/zoomplusndk.c:67: error: invalid use of void expression 

La línea 53 es Y = yuv420sp [pixPtr]; si (Y <0) Y + = 255;

Aquí está su código corregido:

 #include <jni.h> #include <android/log.h> int* rgbData; int rgbDataSize = 0; JNIEXPORT void JNICALL Java_mk_g6_transparency_CameraPreview_YUVtoRBG(JNIEnv * env, jobject obj, jintArray rgb, jbyteArray yuv420sp, jint width, jint height) { int sz; int i; int j; int Y; int Cr = 0; int Cb = 0; int pixPtr = 0; int jDiv2 = 0; int R = 0; int G = 0; int B = 0; int cOff; int w = width; int h = height; sz = w * h; jbyte* yuv = yuv420sp; if(rgbDataSize < sz) { int tmp[sz]; rgbData = &tmp[0]; rgbDataSize = sz; __android_log_write(ANDROID_LOG_INFO, "JNI", "alloc"); } for(j = 0; j < h; j++) { pixPtr = j * w; jDiv2 = j >> 1; for(i = 0; i < w; i++) { Y = yuv[pixPtr]; if(Y < 0) Y += 255; if((i & 0x1) != 1) { cOff = sz + jDiv2 * w + (i >> 1) * 2; Cb = yuv[cOff]; if(Cb < 0) Cb += 127; else Cb -= 128; Cr = yuv[cOff + 1]; if(Cr < 0) Cr += 127; else Cr -= 128; } R = Y + Cr + (Cr >> 2) + (Cr >> 3) + (Cr >> 5); if(R < 0) R = 0; else if(R > 255) R = 255; G = Y - (Cb >> 2) + (Cb >> 4) + (Cb >> 5) - (Cr >> 1) + (Cr >> 3) + (Cr >> 4) + (Cr >> 5); if(G < 0) G = 0; else if(G > 255) G = 255; B = Y + Cb + (Cb >> 1) + (Cb >> 2) + (Cb >> 6); if(B < 0) B = 0; else if(B > 255) B = 255; rgbData[pixPtr++] = 0xff000000 + (B << 16) + (G << 8) + R; } } (*env)->SetIntArrayRegion(env, rgb, 0, sz, ( jint * ) &rgbData[0] ); } 

también está en línea en http://dl.dropbox.com/u/49855874/yuv-decoder.c

Mi prueba:

  • Vista previa de la cámara en 640×480 Procesamiento ~ 20ms en HTC Desire
  • Vista previa de la cámara a 320×240 Procesamiento ~ 6ms en HTC Desire

Estaba recibiendo la Fatal signal 11 (SIGSEGV) hasta que cambié esta línea:

 jbyte* yuv = yuv420sp; 

a esto:

 jboolean isCopy; jbyte* yuv = (*env)->GetByteArrayElements(env, yuv420sp, &isCopy); 

Lo que sugiero es que no lo hagas tú mismo, debido a que alguien ya lo ha hecho perfecto, utiliza la biblioteca GPUImage o simplemente mueve esta parte del código.

Hay una versión android de GPUImage: https://github.com/CyberAgent/android-gpuimage

Puede incluir esta biblioteca si utiliza gradle y llame al método: GPUImageNativeLibrary.YUVtoRBGA (inputArray, WIDTH, HEIGHT, outputArray);

  • Fuera de memoria al usar compresstojpeg en varios YuvImage uno a la vez
  • Cómo mostrar la imagen de YUV en Android
  • Convertir matriz de mapa de bits a YUV (YCbCr NV21)
  • Cómo convertir RGB565 a YUV420SP más rápido en Android?
  • Convertir android.media.Image (YUV_420_888) en mapa de bits
  • Camera.PreviewCallback equivalente en Camera2 API
  • Android cámara2 jpeg framerate
  • Rotación de la imagen YUV420 / NV21 en android
  • Problemas al escalar una imagen YUV utilizando la biblioteca libyuv
  • Cómo convertir el formato de imagen NV21 en mapa de bits?
  • Cámara adecuada2 YUV_420_888 a conversión de JPEG
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.