Android-NDK - fread - android
I write this question, because I don't see this in any foro o helper pager, I have a app, it make two function basic, I have log in c and write in console step by step.
I have two case in my app, I call this line: "DEAD LINE", it one line code make fail all function, dosen't fial this line, when try to call.
Case 1: ("DEAD LINE" it's comments.)
Firth function ("setArrayByteYUV") write a buffer in the file (this make pefect with out problem), it to simple, the epp can pass de array of byte to c, and write the file:
This function run in the 4.2 - 5.0 - 6.0 android (crate file and write buffer).
Write all log in console.
Second function ("RenderProcessOther") read buffer by file, previously write, please pay present much attention:
This function run in the 4.2 - 5.0 - 6.0 android (open file).
Write all log in console.
Case 2: ("DEAD LINE" it's not comments.)
Firth function (setArrayByteYUV) write a buffer in the file (this make pefect with out problem), it to simple, I can pass de array of byte to c, and write the file:
This function run in the 4.2 - 5.0 - 6.0 android (crate file).
Write all log in console.
Second function (RenderProcessOther) read buffer by file, previously write, but, please pay present much attention:
This function run in the 4.2 android and read the buffer by file and finsh the process, but in 5.0 - 6.0 android fail, when call this function (Dosen't fial in the "LINE DEAD" fail to call function).
Write all log in console 4.2 android, but in 5.0 - 6.0 android fail, when call this function, and it dosen't write any log from this function. PD: when fail, Doesn't write ANY LOG from the function RenderProcessOther, like function doesn't exit.
In all case compile, never fail in the comple of ndk-build (case comments "DEAD LINE" or not comments "DEAD LINE").
I try with fgets and fread and all way, but in all ways it work same: in 4.2 run and read file, in 5.0 - 6.0 fail in the setArrayByteYUV if "DEAD LINE" it not commet.
Nota: The process write and read, Doesn't it have problem runtime error, and it compile fine.
If my code need "try" or "catch", validation "if" u other thing to make work "fread" "DEAD LINE" in the 5.0 - 6.0
Code C:
#include <jni.h>
#include <stdlib.h>
#include <android/log.h>
#include <pthread.h>
#include <stdio.h>
#include<string.h>
#include <stdlib.h>
#define APPNAME "MyApp"
#define EMPTY (0)
static jint *c_arrayPrincipal;
static jint **c_arrayMain;
static jint *rgbDataGlobal;
int startThread = 0;
int in = 0;
int inByte = 0;
int lengthglobal =0;
int rgbDataFinal[15000000];
jint lenVector = 0;
JNIEXPORT jint
Java_com_example_android_camera2basic_utils_Utils_setArrayByteYUV(JNIEnv* env, jobject thiz, jbyteArray arrY, jbyteArray arrU, jbyteArray arrV, jint indexP, jint width, jint height, jstring javaString){
const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);
int w = width;
int h = height;
int sz = w * h;
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 ind = 0;
int nind = lenVector;
int p = 0;
jsize lenY = (*env)->GetArrayLength(env, arrY);
jsize lenU = (*env)->GetArrayLength(env, arrU);
jsize lenV = (*env)->GetArrayLength(env, arrV);
char arr[lenY];
int rgbData2[sz];
int counter =0;
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "lenY: number: = %d",lenY);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "lenU: number: = %d",lenU);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "lenV: number: = %d",lenV);
//file/
int lstr = 0;
int mychar = 0;
FILE *pfileY = NULL;
FILE *pfileU = NULL;
FILE *pfileV = NULL;
char filenameconY[sizeof "/data/data/com.example.android.camera2basic/ls/myfile%04d-y.txt"];
char filenameconU[sizeof "/data/data/com.example.android.camera2basic/ls/myfile%04d-y.txt"];
char filenameconV[sizeof "/data/data/com.example.android.camera2basic/ls/myfile%04d-y.txt"];
//sprintf(filenamecon, "/storage/emulated/legacy/ls/myfile%04d.txt", indexP);
sprintf(filenameconY, "/data/data/com.example.android.camera2basic/ls/myfile%04d-y.txt", indexP);
sprintf(filenameconU, "/data/data/com.example.android.camera2basic/ls/myfile%04d-u.txt", indexP);
sprintf(filenameconV, "/data/data/com.example.android.camera2basic/ls/myfile%04d-v.txt", indexP);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "setArrayByte: number: = %d",1);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "setArrayByte: number: = %s",filenameconY);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "setArrayByte: number: = %s",filenameconU);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "setArrayByte: number: = %s",filenameconV);
//pfilecon = fopen(filenamecon, "a");
jboolean isCopy;
jbyte* c_arrayY = (*env)->GetByteArrayElements(env, arrY, &isCopy);
jbyte* c_arrayU = (*env)->GetByteArrayElements(env, arrU, &isCopy);
jbyte* c_arrayV = (*env)->GetByteArrayElements(env, arrV, &isCopy);
//File
pfileY = fopen(filenameconY, "w");
pfileU = fopen(filenameconU, "w");
pfileV = fopen(filenameconV, "w");
if(pfileY == NULL)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Error null file: = %d",2);
}
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "setArrayByte: number: = %d",2);
fwrite(c_arrayY , 1 , lenY+1 , pfileY );
fwrite(c_arrayU , 1 , lenU+1 , pfileU );
fwrite(c_arrayV , 1 , lenV+1 , pfileV );
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "setArrayByte: number: = %d",3);
(*env)->ReleaseStringUTFChars(env, javaString, nativeString);
(*env)->DeleteLocalRef(env,javaString);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "setArrayByte: number: = %d",4);
fclose(pfileY);
fclose(pfileU);
fclose(pfileV);
(*env)->ReleaseByteArrayElements(env, arrY, c_arrayY, 0);
(*env)->DeleteLocalRef(env,arrY);
(*env)->ReleaseByteArrayElements(env, arrU, c_arrayU, 0);
(*env)->DeleteLocalRef(env,arrU);
(*env)->ReleaseByteArrayElements(env, arrV, c_arrayV, 0);
(*env)->DeleteLocalRef(env,arrV);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "setArrayByte: number: = %d",5);
return 0;
}
JNIEXPORT jintArray JNICALL
Java_com_example_android_camera2basic_utils_Utils_RenderProcessOther(JNIEnv * env, jobject obj, jint number, jint width, jint height, jint api)
{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOtherYUV: api: = %d",api);
const char *nativeString = "";
int w = width;
int h = height;
int sz = w * h;
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 ind = 0;
int nind = lenVector;
int p = 0;
char arr[15000000];
int rgbData2[sz];
int counter =0;
int indexP =0;
char arrY[15000000];
char arrU[15000000];
char arrV[15000000];
int rgbDataFinalR[15000000];
if(api!=0) {
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOtherYUV: api IF: = %d",sz);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOther2: number: = %d",1);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOther: number: = %d",2);
rgbDataGlobal = (jint*)calloc(lenVector, sizeof(jint));
int lstr = 0;
int mychar = 0;
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOther: number: = %d",3);
int nnumber = (int)number;
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOther: nnumber: = %d",4);
for(indexP=1; indexP<nnumber;indexP++){
//filename =
//printf(filename, "/storage/emulated/legacy/ls/myfile%d.txt", (int)indexP);
pixPtr = 0;
char filenameconY[sizeof "/data/data/com.example.android.camera2basic/ls/myfile%04d-y.txt"];
char filenameconU[sizeof "/data/data/com.example.android.camera2basic/ls/myfile%04d-y.txt"];
char filenameconV[sizeof "/data/data/com.example.android.camera2basic/ls/myfile%04d-y.txt"];
//sprintf(filenamecon, "/storage/emulated/legacy/ls/myfile%04d.txt", indexP);
sprintf(filenameconY, "/data/data/com.example.android.camera2basic/ls/myfile%04d-y.txt", indexP);
sprintf(filenameconU, "/data/data/com.example.android.camera2basic/ls/myfile%04d-u.txt", indexP);
sprintf(filenameconV, "/data/data/com.example.android.camera2basic/ls/myfile%04d-v.txt", indexP);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "setArrayByte: number: = %d",1);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "setArrayByte: number: = %s",filenameconY);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "setArrayByte: number: = %s",filenameconU);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "setArrayByte: number: = %s",filenameconV);
FILE* fileY = fopen(filenameconY, "r");
FILE* fileU = fopen(filenameconU, "r");
FILE* fileV = fopen(filenameconV, "r");
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOther: indexP 4: = %d",indexP);
int n = sizeof(arrY);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "sizeof: sizeof 4: = %d",n);
if(n !=0){
n = sizeof(arrY)/sizeof(arrY[0]);
int step = (int)api;
int size = w * h;
for (i = 0; i<h; i++)
{
for (j=0; j<w; j++)
{
float Y = arrY[i*step + j];
float U = arrU[ (int)(size + (i/2)*(step/2) + j/2) ];
float V = arrV[ (int)(size*1.25 + (i/2)*(step/2) + j/2)];
float R = Y + (int)(1.772f*V);
float G = Y - (int)(0.344f*V + 0.714f*U);
float B = Y + (int)(1.402f*U);
if (R < 0){
R = 0;
}
if (G < 0){
G = 0;
} if (B < 0){
B = 0;
}
if (R > 255 ){
R = 255;
}
if (G > 255) {
G = 255;
} if (B > 255) {
B = 255;
}
int rint = (int)R;
int gint = (int)G;
int bint = (int)B;
int rgbDataPixel = 0xff000000 + (bint << 16) + (gint << 8) + rint;
rgbDataFinalR[pixPtr] = (int)rgbDataPixel;
pixPtr++;
}
}
fclose(fileY);
fclose(fileU);
fclose(fileV);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOther2: nnumber for close: = %d",indexP);
remove(filenameconY);
remove(filenameconU);
remove(filenameconV);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOther2: nnumber for remove: = %d",4);
}
}
}else{
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOtherYUV: api ELSE: = %d",sz);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOther: number: = %d",1);
rgbDataGlobal = (jint*)calloc(lenVector, sizeof(jint));
int lstr = 0;
int mychar = 0;
char *filename = NULL;
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOther: number: = %d",1);
int nnumber = (int)number;
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOther: nnumber: = %d",1);
for(indexP=1; indexP<nnumber;indexP++){
char filenamecon[sizeof "/storage/emulated/legacy/ls/myfile0000.txt"];
sprintf(filenamecon, "/data/data/com.example.android.camera2basic/ls/myfile%04d-y.txt", indexP);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOther: number: = %s",filenamecon);
FILE* file = fopen(filenamecon, "r");
if(file ==NULL){
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "no existe RenderProcessOther: number: = %s",filenamecon);
}
/* DEAD LINE */
/* DEAD LINE */
/* DEAD LINE */
fread(arr, lenVector,0 , file); // <------- DEAD LINE
///fgets(arr, lenVector, file)
/* DEAD LINE */
/* DEAD LINE */
/* DEAD LINE */
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "RenderProcessOther: indexP 4: = %d",indexP);
int n = sizeof(arr);
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "sizeof: sizeof 4: = %d",n);
if(n !=0){
n = sizeof(arr)/sizeof(arr[0]);
for(j = 0; j < h; j++) {
pixPtr = j * w;
jDiv2 = j >> 1;
for(i = 0; i < w; i++) {
counter++;
Y = arr[pixPtr];
if(Y < 0) Y += 255;
if((i & 0x1) != 1) {
cOff = sz + jDiv2 * w + (i >> 1) * 2;
Cb = arr[cOff];
if(Cb < 0) Cb += 127; else Cb -= 128;
Cr = arr[cOff + 1];
if(Cr < 0) Cr += 127; else Cr -= 128;
}
R = Y + Cr + (Cr >> 2) + (Cr >> 3) + (Cr >> 5);//1.406*~1.403
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);//1.765~1.770
if(B < 0) B = 0; else if(B > 255) B = 255;
if(indexP==0){
rgbDataFinal[pixPtr++] = 0xff000000 + (B << 16) + (G << 8) + R;
}else{
int pixPtrIndex = pixPtr++;
int rgbDataPixel = 0xff000000 + (B << 16) + (G << 8) + R;
int color = rgbDataPixel;
int r = color & 0xff;
int g = (color >> 8) & 0xff;
int b = (color >> 16) & 0xff;
int a = (color >> 24) & 0xff;
int color2 = rgbDataFinal[pixPtrIndex];
int r2 = color2 & 0xff;
int g2 = (color2 >> 8) & 0xff;
int b2 = (color2 >> 16) & 0xff;
int a2 = (color2 >> 24) & 0xff;
double ad = a - a2;
double rd = r - r2;
double gd = g - g2;
double bd = b- b2;
double ar = a2/a;
double rr = r2/r;
double gr = g2/g;
double br = b2/b;
if(a2<a|| r2<r|| g2<g || b2<b) {
double coeficiente = 0.5;
double d =(r - ((r - r2)*coeficiente));
int red1 = (int) d;
d =(g - ((g - g2)*coeficiente));
int green1 = (int)d;
d =(b - ((b - b2)*coeficiente));
int blue1 = (int)d;
int renderRGBDataPixel = 0xff000000 + (blue1 << 16) + (green1 << 8) + red1;
rgbDataFinal[pixPtrIndex] = renderRGBDataPixel;
}
}
}
}
fclose(file);
remove(filenamecon);
}
}
};
for (i = 0; i < sz; ++i) {
rgbDataGlobal[i]= rgbDataFinal[i];
}
jintArray jArray = (*env)->NewIntArray(env, sz);
if (jArray != NULL) {
jint u;
u =0;
(*env)->SetIntArrayRegion(env, jArray, 0, sz,rgbDataGlobal);
}
return jArray;
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := helloc
LOCAL_SRC_FILES := HelloC.c
LOCAL_LDLIBS := -llog -ldl -landroid
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := imageformat
LOCAL_SRC_FILES := ImageFormat.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI := armeabi armeabi-v7a mips x86
APP_PLATFORM := android-21
build.gradle
android {
compileSdkVersion 23
buildToolsVersion "24.0.0 rc3"
defaultConfig {
minSdkVersion 17
targetSdkVersion 23
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
}
Related
encrypt and decrypt utf8 string in android NDK jni
i write a simple string encrypt and decrypt with split string to two var and increment assci code and after swap right and left of string. when i encrypt this text = "this is test" this is work well, but when encrypt utf char don't word like this string = "تست تست تست تست" encrypt code is : JNIEXPORT jstring JNICALL Java_com_test_ndk_MainActivity_encrypt(JNIEnv* env, jobject thiz, jstring dec) { const char *nativeString = (*env)->GetStringUTFChars(env, dec, 0); char *newstr; char *left; char *right; int decLenght = strlen(nativeString); int middl = decLenght / 2; int i; newstr = substr(nativeString, 0, middl); int lenght = strlen(newstr); left = malloc(lenght); for (i = 0; i < lenght; i++) { left[i] = newstr[i] + 1; } left[lenght] = '\0'; newstr = substr(nativeString, middl, decLenght - middl); lenght = strlen(newstr); right = malloc(lenght); for (i = 0; i < lenght; i++) { right[i] = newstr[i] - 1; } right[lenght] = '\0'; strcat(right, left); (*env)->ReleaseStringUTFChars(env, dec, nativeString); return (*env)->NewStringUTF(env, right); } and decrypt code is : JNIEXPORT jstring JNICALL Java_com_test_ndk_MainActivity_decrypt(JNIEnv* env, jobject thiz, jstring enc) { const char *nativeString = (*env)->GetStringUTFChars(env, enc, 0); char *newstr; char *left; char *right; int encLenght = strlen(nativeString); int middl = encLenght / 2; int i; if (encLenght % 2 != 0) { middl++; } newstr = substr(nativeString, 0, middl); int lenght = strlen(newstr); left = malloc(lenght); for (i = 0; i < lenght; i++) { left[i] = (char) ((int) newstr[i] + 1); } left[lenght] = '\0'; newstr = substr(nativeString, middl, encLenght - middl); lenght = strlen(newstr); right = malloc(lenght); for (i = 0; i < lenght; i++) { right[i] = (char) ((int) newstr[i] - 1); } right[lenght] = '\0'; strcat(right, left); (*env)->ReleaseStringUTFChars(env, enc, nativeString); return (*env)->NewStringUTF(env, right); } substr function : char* substr(const char *source, unsigned int start, unsigned int end) { return strndup(source + start, end); } Does anyone have solution .
UTF-8 is not trivial for manipulations. For your encode/decode, you can use GetStringChars() (or the more efficient, but also more restrictive GetStringCritical()) and operate the resulting 16-bit jchar array.
implement water color effect on image using JNI
i implement some code for water color effect on image in android but it was to slow(it's take more then 2 minute) now i try to implement this in JNI for batter speed , hear is my java code for the inPixels is pixel of Bitmap . protected int[] filterPixels( int width, int height, int[] inPixels ) { int levels = 256; int index = 0; int[] rHistogram = new int[levels]; int[] gHistogram = new int[levels]; int[] bHistogram = new int[levels]; int[] rTotal = new int[levels]; int[] gTotal = new int[levels]; int[] bTotal = new int[levels]; int[] outPixels = new int[width * height]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { for (int i = 0; i < levels; i++) rHistogram[i] = gHistogram[i] = bHistogram[i] = rTotal[i] = gTotal[i] = bTotal[i] = 0; for (int row = -range; row <= range; row++) { int iy = y+row; int ioffset; if (0 <= iy && iy < height) { ioffset = iy*width; for (int col = -range; col <= range; col++) { int ix = x+col; if (0 <= ix && ix < width) { int rgb = inPixels[ioffset+ix]; int r = (rgb >> 16) & 0xff; int g = (rgb >> 8) & 0xff; int b = rgb & 0xff; int ri = r*levels/256; int gi = g*levels/256; int bi = b*levels/256; rTotal[ri] += r; gTotal[gi] += g; bTotal[bi] += b; rHistogram[ri]++; gHistogram[gi]++; bHistogram[bi]++; } } } } int r = 0, g = 0, b = 0; for (int i = 1; i < levels; i++) { if (rHistogram[i] > rHistogram[r]) r = i; if (gHistogram[i] > gHistogram[g]) g = i; if (bHistogram[i] > bHistogram[b]) b = i; } r = rTotal[r] / rHistogram[r]; g = gTotal[g] / gHistogram[g]; b = bTotal[b] / bHistogram[b]; outPixels[index] = (inPixels[index] & 0xff000000) | ( r << 16 ) | ( g << 8 ) | b; index++; } } return outPixels; } **OUTPUT image ** and i try to convert this java code to c code but i don't what is the wrong , hear the code for C void filterPixels( int width, int height, int inPixels[] ) { int levels = 256; int index = 0; int rHistogram [levels]; int gHistogram [levels]; int bHistogram [levels]; int rTotal [levels]; int gTotal [levels]; int bTotal [levels]; int outPixels [width * height]; //Loop Variables int y ; int x ; int i ; int row ; int col ; int j ; int range = 5 ; for ( y = 0; y < height; y++) { for ( x = 0; x < width; x++) { for ( i = 0; i < levels; i++) rHistogram[i] = gHistogram[i] = bHistogram[i] = rTotal[i] = gTotal[i] = bTotal[i] = 0; for ( row = -range; row <= range; row++) { int iy = y+row; int ioffset; if (0 <= iy && iy < height) { ioffset = iy*width; for ( col = -range; col <= range; col++) { int ix = x+col; if (0 <= ix && ix < width) { int rgb = inPixels[ioffset+ix]; int r = (rgb >> 16) & 0xff; int g = (rgb >> 8) & 0xff; int b = rgb & 0xff; int ri = r*levels/256; int gi = g*levels/256; int bi = b*levels/256; rTotal[ri] += r; gTotal[gi] += g; bTotal[bi] += b; rHistogram[ri]++; gHistogram[gi]++; bHistogram[bi]++; } } } } int r = 0, g = 0, b = 0; for ( j = 1; j < levels; j++) { if (rHistogram[j] > rHistogram[r]) r = j; if (gHistogram[j] > gHistogram[g]) g = j; if (bHistogram[j] > bHistogram[b]) b = j; } r = rTotal[r] / rHistogram[r]; g = gTotal[g] / gHistogram[g]; b = bTotal[b] / bHistogram[b]; outPixels[index] = (inPixels[index] & 0xff000000) | ( r << 16 ) | ( g << 8 ) | b; index++; } } } i check the pixel value of java code and c code both are same(for same image) code for call native function from my android activity . int[] pix = new int[oraginal.getWidth() * oraginal.getHeight()]; Bitmap bitmap = oraginal.copy(oraginal.getConfig(), true); bitmap.getPixels(pix, 0, bitmap.getWidth(), 0, 0,bitmap.getWidth(), bitmap.getHeight()); filterPixelsJNI(bitmap.getWidth(), bitmap.getHeight(), pix); bitmap.setPixels(pix, 0, bitmap.getWidth(), 0, 0,bitmap.getWidth(), bitmap.getHeight()); myView.setImageBitmap(bitmap); this is my first try for JNI so plz help me in this . UPDATE public native void filterPixelsJNI( int width, int height, int inPixels[] ); JNI JNIEXPORT void JNICALL Java_com_testndk_HelloWorldActivity_filterPixelsJNI (JNIEnv * env, jobject obj , jint width,jint height,jint inPixels[]){ filterPixels( width, height, inPixels); } filterPixels method witch is call from c code .
There are several problems with your JNI code. The algorithmic part is probably correct, but you're not dealing with the Java array to C array conversion correctly. First of all, the last argument of Java_com_testndk_HelloWorldActivity_filterPixelsJNI should be of type jintArray, and not jint []. This is how you pass a Java array to C code. Once you get this array, you can't process it directly, you'll have to convert it to a C array: JNIEXPORT void JNICALL Java_com_testndk_HelloWorldActivity_filterPixelsJNI (JNIEnv * env, jobject obj , jint width, jint height, jintArray inPixels) { int *c_inPixels = (*env)->GetIntArrayElements(env, inPixels, NULL); filterPixels( width, height, c_inPixels); // passing 0 as the last argument should copy native array to Java array (*env)->ReleaseIntArrayElements(env, inPixels, c_inPixels, 0); } I advise you to look at the JNI documentation, which explains how to deal with arrays: http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html Note that there are now easier ways of processing Java Bitmap objects using android NDK. See an other of my answers here for details.
Decoding YUV to RGB in C/C++ with NDK
I'm trying to convert the Android camera feed to a bitmap for image processing. I have some code that converts YUV to RGB in native java which works, however, this process isn't quick enough for real time video so I think I need to convert it in either C or C++ before I apply the filters. I already have the NDK set up and working so the only bit I don't know how to do is port the following code to C or 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); Does anyone know how to do this? Many thanks! Update This is how far I've got: 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; } } } But I'm getting the following C errors: 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 Line 53 is Y = yuv420sp[pixPtr]; if(Y < 0) Y += 255;
Here is your code corrected: #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] ); } it's also online at http://dl.dropbox.com/u/49855874/yuv-decoder.c My test: Camera preview at 640x480 Processing ~20ms on HTC Desire Camera preview at 320x240 Processing ~6ms on HTC Desire
I was getting Fatal signal 11 (SIGSEGV) until i changed this line: jbyte* yuv = yuv420sp; to this: jboolean isCopy; jbyte* yuv = (*env)->GetByteArrayElements(env, yuv420sp, &isCopy);
What I suggest is that don't do that yourself, due to somebody already done that perfect, use GPUImage library or just move this part of code. There is a android version of GPUImage: https://github.com/CyberAgent/android-gpuimage You can include this library if you use gradle, and call the method: GPUImageNativeLibrary.YUVtoRBGA( inputArray, WIDTH, HEIGHT, outputArray);
Calling JNI with Android NDK issue
I have a C function that I'm calling from Java using the Android NDK. Essentially it takes the camera data and converts it from YUV to RGB format. The problem is I'm not sure what object type imageOut is returned in as in C it's simply of type jobject. This is the snippet of code I have (unfortunately I have nothing else to go by): JNIEXPORT void JNICALL Java_com_twothreetwo_zoomplus_ZoomPlus_yuvrgb(JNIEnv *env, jobject obj, jbyteArray imageIn, jint widthIn, jint heightIn, jobject imageOut, jint widthOut, jint heightOut) { LOGI("width is %d; height is %d;",widthIn,heightIn); jbyte *cImageIn = (*env)->GetByteArrayElements(env, imageIn, NULL); jbyte *cImageOut = (jbyte*)(*env)->GetDirectBufferAddress(env, imageOut); unsigned int *rgbs = (unsigned int*)cImageOut; int half_widthIn = widthIn >> 1; //the end of the luminance data int lumEnd = (widthIn * heightIn) >> 1; //points to the next luminance value pair int lumPtr = 0; //points to the next chromiance value pair int chrPtr = lumEnd; //the end of the current luminance scanline int lineEnd = half_widthIn; unsigned short *yuvs; int x,y; for (y=0;y<heightIn;y++) { int yPosOut=(y*widthOut) >> 1; for (x=0;x<half_widthIn;x++) { //read the luminance and chromiance values int Y1 = yuvs[lumPtr++]; int Y2 = (Y1 >> 8) & 0xff; Y1 = Y1 & 0xff; int Cr = yuvs[chrPtr++]; int Cb = ((Cr >> 8) & 0xff) - 128; Cr = (Cr & 0xff) - 128; int R, G, B; //generate first RGB components B = Y1 + ((454 * Cb) >> 8); if (B < 0) B = 0; if (B > 255) B = 255; G = Y1 - ((88 * Cb + 183 * Cr) >> 8); if (G < 0) G = 0; if (G > 255) G = 255; R = Y1 + ((359 * Cr) >> 8); if (R < 0) R = 0; if (R > 255) R = 255; int val = ((R & 0xf8) << 8) | ((G & 0xfc) << 3) | (B >> 3); //generate second RGB components B = Y1 + ((454 * Cb) >> 8); if (B < 0) B = 0; if (B > 255) B = 255; G = Y1 - ((88 * Cb + 183 * Cr) >> 8); if (G < 0) G = 0; if (G > 255) G = 255; R = Y1 + ((359 * Cr) >> 8); if (R < 0) R = 0; if (R > 255) R = 255; rgbs[yPosOut+x] = val | ((((R & 0xf8) << 8) | ((G & 0xfc) << 3) | (B >> 3)) << 16); } //skip back to the start of the chromiance values when necessary chrPtr = lumEnd + ((lumPtr >> 1) / half_widthIn) * half_widthIn; lineEnd += half_widthIn; } (*env)->ReleaseByteArrayElements(env, imageIn, cImageIn, JNI_ABORT); } I'm calling the function in the onPreviewFrame function: public native void yuvrgb(byte[] yuvImageIn, int widthIn, int heightIn, Bitmap imageOut, int widthOut, int heightOut); public void onPreviewFrame(byte[] data, Camera camera) { yuvrgb(data,480,640,bitmapWip,480,640); cameraImageView.setImageBitmap(bitmapWip); } As you can see, I'm currently declaring imageOut as a Bitmap which is where I think I'm going wrong as I just guessed the type. I don't get any errors, the app simply crashes instantly. Does anyone know what I'm doing wrong?
cImageOut is an array of bytes. It's declared at the top of your C function: jbyte *cImageOut = (jbyte*)(*env)->GetDirectBufferAddress(env, imageOut); You should declare it as a byte array in your java code and then convert it to a Bitmap using BitmapFactory.decodeByteArray http://developer.android.com/reference/android/graphics/BitmapFactory.html#decodeByteArray%28byte[],%20int,%20int%29
How to convert RGB565 to YUV420SP faster on android?
I need display a jpeg picture, and convert it to YUV420SP. First I use SkBitmap to parse jpeg and display it, then I use the code below to convert RGB565 to YUV420SP on android, but it spend 75ms to convert a 640*480 RGB565 picture, so anybody know the faster way to convert RGB565 to YUV420SP on android? or faster way to convert jpeg file to YUV420SP on android? // Convert from RGB to YUV420 int RGB2YUV_YR[256], RGB2YUV_YG[256], RGB2YUV_YB[256]; int RGB2YUV_UR[256], RGB2YUV_UG[256], RGB2YUV_UBVR[256]; int RGB2YUV_VG[256], RGB2YUV_VB[256]; // // Table used for RGB to YUV420 conversion // void InitLookupTable() { static bool hasInited = false; if(hasInited) return ; hasInited = true; int i; for (i = 0; i < 256; i++) RGB2YUV_YR[i] = (float) 65.481 * (i << 8); for (i = 0; i < 256; i++) RGB2YUV_YG[i] = (float) 128.553 * (i << 8); for (i = 0; i < 256; i++) RGB2YUV_YB[i] = (float) 24.966 * (i << 8); for (i = 0; i < 256; i++) RGB2YUV_UR[i] = (float) 37.797 * (i << 8); for (i = 0; i < 256; i++) RGB2YUV_UG[i] = (float) 74.203 * (i << 8); for (i = 0; i < 256; i++) RGB2YUV_VG[i] = (float) 93.786 * (i << 8); for (i = 0; i < 256; i++) RGB2YUV_VB[i] = (float) 18.214 * (i << 8); for (i = 0; i < 256; i++) RGB2YUV_UBVR[i] = (float) 112 * (i << 8); } int ConvertRGB5652YUV420SP(int w, int h, unsigned char *bmp, unsigned char *yuv) { unsigned char *u, *v, *y, *uu, *vv; unsigned char *pu1, *pu2, *pu3, *pu4; unsigned char *pv1, *pv2, *pv3, *pv4; unsigned char rValue = 0, gValue = 0, bValue = 0; uint16_t* bmpPtr; int i, j; printf("ConvertRGB5652YUV420SP begin,w=%d,h=%d,bmp=%p,yuv=%p\n", w, h, bmp, yuv); struct timeval tpstart,tpend; gettimeofday(&tpstart,NULL); InitLookupTable(); gettimeofday(&tpend,NULL); float timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec; timeuse/=1000; printf("InitLookupTable used time=%f\n", timeuse); gettimeofday(&tpstart,NULL); uu = new unsigned char[w * h]; vv = new unsigned char[w * h]; if (uu == NULL || vv == NULL || yuv == NULL) return 0; y = yuv; u = uu; v = vv; // Get r,g,b pointers from bmp image data.... bmpPtr = (uint16_t*)bmp; //Get YUV values for rgb values... for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { uint16_t color = *bmpPtr; unsigned int r = (color>>11) & 0x1f; unsigned int g = (color>> 5) & 0x3f; unsigned int b = (color ) & 0x1f; rValue = (r<<3) | (r>>2); gValue = (g<<2) | (g>>4); bValue = (b<<3) | (b>>2); *y++ = (RGB2YUV_YR[rValue] + RGB2YUV_YG[gValue] + RGB2YUV_YB[bValue] + 1048576) >> 16; *u++ = (-RGB2YUV_UR[rValue] - RGB2YUV_UG[gValue] + RGB2YUV_UBVR[bValue] + 8388608) >> 16; *v++ = (RGB2YUV_UBVR[rValue] - RGB2YUV_VG[gValue] - RGB2YUV_VB[bValue] + 8388608) >> 16; bmpPtr++; } } gettimeofday(&tpend,NULL); timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec; timeuse/=1000; printf("Get YUV values used time=%f\n", timeuse); gettimeofday(&tpstart,NULL); // Now sample the U & V to obtain YUV 4:2:0 format // Get the right pointers... u = yuv + w * h; v = u + 1; // For U pu1 = uu; pu2 = pu1 + 1; pu3 = pu1 + w; pu4 = pu3 + 1; // For V pv1 = vv; pv2 = pv1 + 1; pv3 = pv1 + w; pv4 = pv3 + 1; // Do sampling.... for (i = 0; i < h; i += 2) { for (j = 0; j < w; j += 2) { *u = (*pu1 + *pu2 + *pu3 + *pu4) >> 2; u += 2; *v = (*pv1 + *pv2 + *pv3 + *pv4) >> 2; v += 2; pu1 += 2; pu2 += 2; pu3 += 2; pu4 += 2; pv1 += 2; pv2 += 2; pv3 += 2; pv4 += 2; } pu1 += w; pu2 += w; pu3 += w; pu4 += w; pv1 += w; pv2 += w; pv3 += w; pv4 += w; } gettimeofday(&tpend,NULL); timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec; timeuse/=1000; printf("Do sampling used time=%f\n", timeuse); gettimeofday(&tpstart,NULL); delete uu; delete vv; return 1; } int main(int argc, char **argv) { unsigned char bmp[640*480*2] = {0}; unsigned char yuv[(640*480*3)/2] = {0}; struct timeval tpstart,tpend; gettimeofday(&tpstart,NULL); ConvertRGB5652YUV420SP(640, 480, bmp, yuv); gettimeofday(&tpend,NULL); float timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec; timeuse/=1000; printf("ConvertARGB2YUV420SP used time=%f\n", timeuse); return 0; } output on android(armv6): ConvertRGB5652YUV420SP begin,w=640,h=480,bmp=0xbe7314fc,yuv=0xbe7c74fc InitLookupTable used time=0.383000 Get YUV values used time=61.394001 Do sampling used time=11.918000 ConvertARGB2YUV420SP used time=74.596001 cpu info: $ cat /proc/cpuinfo cat /proc/cpuinfo Processor : ARMv6-compatible processor rev 5 (v6l) BogoMIPS : 791.34 Features : swp half thumb fastmult vfp edsp java CPU implementer : 0x41 CPU architecture: 6TEJ CPU variant : 0x1 CPU part : 0xb36 CPU revision : 5 Hardware : IMAPX200 Revision : 0000 Serial : 0000000000000000
On ARMv7, use NEON. It will do the job in less than 1ms. (VGA) If you are stuck with ARMv6, optimize it in ARM assembly. (about 8ms on VGA) Use fixed-point arithmetic instead of the lookup tables. Get rid of them. make two masks : 0x001f001f : mask1 0x003f003f : mask2 then load two pixels at once into a 32bit register (which is a lot faster than 16bit read) and red, mask1, pixel, lsr #11 and grn, mask2, pixel, lsr #5 and blu, mask1, pixel now you have three registers, each containing two values - one in the lower, and the other in the upper 16 bits. smulxy instructions will do some miracles from here on. (16bit multiply) Good luck. PS : your lookup table isn't that good either. Why are they all in length of 256? You could reduce them to 32 (r and b related) and 64 (g related) Which will increase the cache hit rate. Probably that will just do for the targeted 40ms without resorting to assembly. Yes, cache-misses are THAT painful.
I have found a faster way in skia, it runs about 40ms. #include "SkColorPriv.h" #include "SkBitmap.h" #include "SkCanvas.h" #include "SkStream.h" using namespace android; // taken from jcolor.c in libjpeg #if 0 // 16bit - precise but slow #define CYR 19595 // 0.299 #define CYG 38470 // 0.587 #define CYB 7471 // 0.114 #define CUR -11059 // -0.16874 #define CUG -21709 // -0.33126 #define CUB 32768 // 0.5 #define CVR 32768 // 0.5 #define CVG -27439 // -0.41869 #define CVB -5329 // -0.08131 #define CSHIFT 16 #else // 8bit - fast, slightly less precise #define CYR 77 // 0.299 #define CYG 150 // 0.587 #define CYB 29 // 0.114 #define CUR -43 // -0.16874 #define CUG -85 // -0.33126 #define CUB 128 // 0.5 #define CVR 128 // 0.5 #define CVG -107 // -0.41869 #define CVB -21 // -0.08131 #define CSHIFT 8 #endif static void rgb2yuv_32(uint8_t dst[], SkPMColor c) { int r = SkGetPackedR32(c); int g = SkGetPackedG32(c); int b = SkGetPackedB32(c); int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT; int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT; int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT; dst[0] = SkToU8(y); dst[1] = SkToU8(u + 128); dst[2] = SkToU8(v + 128); } static void rgb2yuv_32_x(uint8_t *py, uint8_t *pu, uint8_t *pv, SkPMColor c) { int r = SkGetPackedR32(c); int g = SkGetPackedG32(c); int b = SkGetPackedB32(c); if(py != NULL){ int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT; *py = SkToU8(y); } if(pu != NULL){ int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT; *pu = SkToU8(u + 128); } if(pv != NULL){ int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT; *pv = SkToU8(v + 128); } } static void rgb2yuv_4444(uint8_t dst[], U16CPU c) { int r = SkGetPackedR4444(c); int g = SkGetPackedG4444(c); int b = SkGetPackedB4444(c); int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4); int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4); int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4); dst[0] = SkToU8(y); dst[1] = SkToU8(u + 128); dst[2] = SkToU8(v + 128); } static void rgb2yuv_4444_x(uint8_t *py, uint8_t *pu, uint8_t *pv, U16CPU c) { int r = SkGetPackedR4444(c); int g = SkGetPackedG4444(c); int b = SkGetPackedB4444(c); if(py != NULL){ int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4); *py = SkToU8(y); } if(pu != NULL){ int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4); *pu = SkToU8(u + 128); } if(pv != NULL){ int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4); *pv = SkToU8(v + 128); } } static void rgb2yuv_16(uint8_t dst[], U16CPU c) { int r = SkGetPackedR16(c); int g = SkGetPackedG16(c); int b = SkGetPackedB16(c); int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2); int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2); int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2); dst[0] = SkToU8(y); dst[1] = SkToU8(u + 128); dst[2] = SkToU8(v + 128); } static void rgb2yuv_16_x(uint8_t *py, uint8_t *pu, uint8_t *pv, U16CPU c) { int r = SkGetPackedR16(c); int g = SkGetPackedG16(c); int b = SkGetPackedB16(c); if(py != NULL){ int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2); *py = SkToU8(y); } if(pu != NULL){ int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2); *pu = SkToU8(u + 128); } if(pv != NULL){ int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2); *pv = SkToU8(v + 128); } } int ConvertRGB5652YUV420SPBySkia(SkBitmap* bmp, unsigned char* dst) { if(!bmp || !dst || bmp->getConfig() != SkBitmap::kRGB_565_Config) return -1; int width = bmp->width(); int height = bmp->height(); void *src = bmp->getPixels(); int src_rowbytes = bmp->rowBytes(); int stride = width; int dstheight = height; int i, j; uint8_t *y_base = (uint8_t *)dst; uint8_t *cb_base = (uint8_t *)((unsigned int)y_base + stride * dstheight); uint8_t *cr_base = cb_base + 1; uint8_t yuv[3]; uint8_t *y = NULL, *cb = NULL, *cr = NULL; uint16_t *rgb = (uint16_t *)src; for(i=0; i<height; i++){ rgb = (uint16_t *)((unsigned int)src + i * src_rowbytes); y = (uint8_t *)((unsigned int)y_base + i * stride); if((i & 0x1) == 0){ cb = (uint8_t *)((unsigned int)cb_base + ((i>>1) * stride)); cr = cb + 1; } for(j=0; j<width; j++){ if(i & 0x1){// valid y and cr if(j & 0x01){ // only y rgb2yuv_16_x(y++, NULL, NULL, *rgb++); }else{ // both y and cr rgb2yuv_16_x(y++, NULL, cr++, *rgb++); cr++; } }else{// valid y and cb if(j & 0x01){ // only y rgb2yuv_16_x(y++, NULL, NULL, *rgb++); }else{ // both y and cb rgb2yuv_16_x(y++, cb++, NULL, *rgb++); cb++; } } } } return 0; }