【JNI】 Android调用JNI的进阶实例(摄像头预览数据转码RGB播放)

前一篇的博文介绍了:Android调用JNI的简单实例(附详细步骤),现在带来一个进阶版的,虽然时间隔得有点久远。

这里要说下,尽量不要用Java写编解码的东西,就算你是大神,你写的出来,但那也是不实用的,就像切西瓜一样,拿一把削水果刀去切西瓜,肯定比不上用西瓜刀方便吧,还是老老实实写个JNI调用得了,也不复杂C/C++方便的很,当然,这里不是说Java不行,语言只是工具,做什么事情用什么语言,没必要硬着头皮往上顶对吧。纯属个人观点,大神可以无视。

好了进入正题,该实例主要内容:开启摄像头预览,将获取到的视频帧YUV数据,通过JNI调用C的转码函数转为RGB类型数据然后返回,在自定义控件上绘制播放。

1、工程结构:

【JNI】 Android调用JNI的进阶实例(摄像头预览数据转码RGB播放)_第1张图片

该工程是在之前的SimpleJni实例上进行修改的,简单描述一下功能:

CameraEngineActivity主界面,用于加载控件及渲染等;

CameraView摄像头预览控件,用于预览及捕获视频帧YUV数据;

ImageUtilEngine声明调用C函数的接口类,声明native的C函数;

SporeRender渲染画面类,用于绘制图像;

Texture2D图像优化类,用于优化图像纹理;

Demo地址:


2、新建java调用C函数的接口类

[java]  view plain  copy
 print ?
  1. package com.eric.complexjni;  
  2. /* 
  3.  *@author Eric  
  4.  *@2015-12-7下午4:35:18 
  5.  */  
  6. public class ImageUtilEngine {  
  7.      static {  
  8.             System.loadLibrary("");  
  9.         }  
  10.   
  11.      public native int[] decodeYUV420SP(byte[] buf, int width, int heigth);  
  12. }  
3 、编译该接口类的头文件.h

命令窗口:Win+R运行cmd,cd进入到eclipse工作空间中ComplexJni工程目录,

输入javah -classpath bin/classes -d jni com.eric.complexjni.ImageUtilEngine编译接口类

【JNI】 Android调用JNI的进阶实例(摄像头预览数据转码RGB播放)_第2张图片

编译完成后,刷新工程,就可以看到工程中自动创建了jni文件夹,其中包含编译好的.h头文件

【JNI】 Android调用JNI的进阶实例(摄像头预览数据转码RGB播放)_第3张图片

4、在jni目录下新建com_eric_complexjni_ImageUtilEngine.h

[cpp]  view plain  copy
 print ?
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #define LOG_TAG "Spore.meitu"  
  8. #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)  
  9. #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)  
  10.   
  11. int min(int x, int y) {  
  12.     return (x <= y) ? x : y;  
  13. }  
  14. int max(int x,int y){  
  15.     return (x >= y) ? x : y;  
  16. }  
  17. int alpha(int color) {  
  18.     return (color >> 24) & 0xFF;  
  19. }  
  20. int red(int color) {  
  21.     return (color >> 16) & 0xFF;  
  22. }  
  23. int green(int color) {  
  24.     return (color >> 8) & 0xFF;  
  25. }  
  26. int blue(int color) {  
  27.     return color & 0xFF;  
  28. }  
  29. int ARGB(int alpha, int red, int green, int blue) {  
  30.     return (alpha << 24) | (red << 16) | (green << 8) | blue;  
  31. }  
  32.   
  33. #include   
  34. #include   
  35. #include   
  36. #include   
  37. #include   
  38. inline static unsigned short int make16color(unsigned char r, unsigned char g, unsigned char b)  
  39. {  
  40.     return (  
  41.  (((r >> 3) & 31) << 11) |  
  42.  (((g >> 2) & 63) << 5)  |  
  43.   ((b >> 3) & 31)        );  
  44. }  
  45.   
  46. int framebuffer_main()  
  47. {  
  48.     LOGI("framebuffer code");  
  49.     int fbfd = 0;  
  50.     struct fb_var_screeninfo vinfo;  
  51.     struct fb_fix_screeninfo finfo;  
  52.     long int screensize = 0;  
  53.     char *fbp = 0;  
  54.     int x = 0, y = 0;  
  55.     int guage_height = 20, step = 10;  
  56.     long int location = 0;  
  57.     // Open the file for reading and writing  
  58.     LOGI("framebuffer code 1");  
  59.     fbfd = open("/dev/graphics/fb0", O_RDWR);  
  60.     LOGI("framebuffer code 2");  
  61.     if (!fbfd) {  
  62.         LOGI("Error: cannot open framebuffer device.\n");  
  63.         exit(1);  
  64.     }  
  65.     LOGI("The framebuffer device was opened successfully.\n");  
  66.     // Get fixed screen information  
  67.     if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {  
  68.         LOGI("Error reading fixed information.\n");  
  69.         exit(2);  
  70.     }  
  71.     // Get variable screen information  
  72.     if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {  
  73.         LOGI("Error reading variable information.\n");  
  74.         exit(3);  
  75.     }  
  76.     LOGI("sizeof(unsigned short) = %d\n"sizeof(unsigned short));  
  77.     LOGI("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);  
  78.     LOGI("xoffset:%d, yoffset:%d, line_length: %d\n", vinfo.xoffset,  
  79.             vinfo.yoffset, finfo.line_length);  
  80.     // Figure out the size of the screen in bytes  
  81.     screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;  
  82.     // Map the device to memory  
  83.     fbp = (char *) mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,  
  84.             fbfd, 0);  
  85.     if ((int) fbp == -1) {  
  86.         LOGI("Error: failed to map framebuffer device to memory.\n");  
  87.         exit(4);  
  88.     }  
  89.     LOGI("The framebuffer device was mapped to memory successfully.\n");  
  90.     //set to black color first  
  91.     memset(fbp, 0, screensize);  
  92.     //draw rectangle  
  93.     y = (vinfo.yres - guage_height) / 2 - 2; // Where we are going to put the pixel  
  94.     for (x = step - 2; x < vinfo.xres - step + 2; x++) {  
  95.         location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) + (y  
  96.                 + vinfo.yoffset) * finfo.line_length;  
  97.         *((unsigned short int*) (fbp + location)) = 255;  
  98.     }  
  99.     y = (vinfo.yres + guage_height) / 2 + 2; // Where we are going to put the pixel  
  100.     for (x = step - 2; x < vinfo.xres - step + 2; x++) {  
  101.         location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) + (y  
  102.                 + vinfo.yoffset) * finfo.line_length;  
  103.         *((unsigned short int*) (fbp + location)) = 255;  
  104.     }  
  105.     x = step - 2;  
  106.     for (y = (vinfo.yres - guage_height) / 2 - 2; y < (vinfo.yres  
  107.             + guage_height) / 2 + 2; y++) {  
  108.         location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) + (y  
  109.                 + vinfo.yoffset) * finfo.line_length;  
  110.         *((unsigned short int*) (fbp + location)) = 255;  
  111.     }  
  112.     x = vinfo.xres - step + 2;  
  113.     for (y = (vinfo.yres - guage_height) / 2 - 2; y < (vinfo.yres  
  114.             + guage_height) / 2 + 2; y++) {  
  115.         location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) + (y  
  116.                 + vinfo.yoffset) * finfo.line_length;  
  117.         *((unsigned short int*) (fbp + location)) = 255;  
  118.     }  
  119.     // Figure out where in memory to put the pixel  
  120.     for (x = step; x < vinfo.xres - step; x++) {  
  121.         for (y = (vinfo.yres - guage_height) / 2; y < (vinfo.yres  
  122.                 + guage_height) / 2; y++) {  
  123.             location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) + (y  
  124.                     + vinfo.yoffset) * finfo.line_length;  
  125.             if (vinfo.bits_per_pixel == 32) {  
  126.                 *(fbp + location) = 100; // Some blue  
  127.                 *(fbp + location + 1) = 15 + (x - 100) / 2; // A little green  
  128.                 *(fbp + location + 2) = 200 - (y - 100) / 5; // A lot of red  
  129.                 *(fbp + location + 3) = 0; // No transparency  
  130.             } else { //assume 16bpp  
  131.                 unsigned char b = 255 * x / (vinfo.xres - step);  
  132.                 unsigned char g = 255; // (x - 100)/6 A little green  
  133.                 unsigned char r = 255; // A lot of red  
  134.                 unsigned short int t = make16color(r, g, b);  
  135.                 *((unsigned short int*) (fbp + location)) = t;  
  136.             }  
  137.         }  
  138.         //printf("x = %d, temp = %d\n", x, temp);  
  139.         //sleep to see it  
  140.         usleep(200);  
  141.     }  
  142.     //clean framebuffer  
  143.     munmap(fbp, screensize);  
  144.     close(fbfd);  
  145.     return 0;  
  146. }  
  147.   
  148. int r_v_table[256],g_v_table[256],g_u_table[256],b_u_table[256],y_table[256];  
  149. int r_yv_table[256][256],b_yu_table[256][256];  
  150. int inited = 0;  
  151.   
  152. void initTable()  
  153. {  
  154.     if (inited == 0)  
  155.     {  
  156.         //framebuffer_main();  
  157.         inited = 1;  
  158.         int m = 0,n=0;  
  159.         for (; m < 256; m++)  
  160.         {  
  161.             r_v_table[m] = 1634 * (m - 128);  
  162.             g_v_table[m] = 833 * (m - 128);  
  163.             g_u_table[m] = 400 * (m - 128);  
  164.             b_u_table[m] = 2066 * (m - 128);  
  165.             y_table[m] = 1192 * (m - 16);  
  166.         }  
  167.         int temp = 0;  
  168.         for (m = 0; m < 256; m++)  
  169.             for (n = 0; n < 256; n++)  
  170.             {  
  171.                 temp = 1192 * (m - 16) + 1634 * (n - 128);  
  172.                 if (temp < 0) temp = 0; else if (temp > 262143) temp = 262143;  
  173.                 r_yv_table[m][n] = temp;  
  174.   
  175.                 temp = 1192 * (m - 16) + 2066 * (n - 128);  
  176.                 if (temp < 0) temp = 0; else if (temp > 262143) temp = 262143;  
  177.                 b_yu_table[m][n] = temp;  
  178.             }  
  179.     }  
  180. }  
  181.   
  182. jintArray Java_com_spore_ImageUtilEngine_decodeYUV420SP(JNIEnv * env,  
  183.         jobject thiz, jbyteArray buf, jint width, jint height) {  
  184.     jbyte * yuv420sp = (*env)->GetByteArrayElements(env, buf, 0);  
  185.   
  186.     int frameSize = width * height;  
  187.     jint rgb[frameSize]; // 鏂板浘鍍忓儚绱犲��  
  188.   
  189.     initTable();  
  190.   
  191.     int i = 0, j = 0,yp = 0;  
  192.     int uvp = 0, u = 0, v = 0;  
  193.     for (j = 0, yp = 0; j < height; j++)  
  194.     {  
  195.         uvp = frameSize + (j >> 1) * width;  
  196.         u = 0;  
  197.         v = 0;  
  198.         for (i = 0; i < width; i++, yp++)  
  199.         {  
  200.             int y = (0xff & ((int) yuv420sp[yp]));  
  201.             if (y < 0)  
  202.                 y = 0;  
  203.             if ((i & 1) == 0)  
  204.             {  
  205.                 v = (0xff & yuv420sp[uvp++]);  
  206.                 u = (0xff & yuv420sp[uvp++]);  
  207.             }  
  208.   
  209. //          int y1192 = 1192 * y;  
  210. //          int r = (y1192 + 1634 * v);  
  211. //          int g = (y1192 - 833 * v - 400 * u);  
  212. //          int b = (y1192 + 2066 * u);  
  213.             int y1192 = y_table[y];  
  214.             int r = r_yv_table[y][v];//(y1192 + r_v_table[v]);  
  215.             int g = (y1192 - g_v_table[v] - g_u_table[u]);  
  216.             int b = b_yu_table[y][u];//(y1192 + b_u_table[u]);  
  217.   
  218.             //if (r < 0) r = 0; else if (r > 262143) r = 262143;  
  219.             if (g < 0) g = 0; else if (g > 262143) g = 262143;  
  220.             //if (b < 0) b = 0; else if (b > 262143) b = 262143;  
  221. //          r = (r >> 31) ? 0 : (r & 0x3ffff);  
  222. //          g = (g >> 31) ? 0 : (g & 0x3ffff);  
  223. //          b = (b >> 31) ? 0 : (b & 0x3ffff);  
  224.   
  225.             rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);  
  226.         }  
  227.     }  
  228.   
  229.     jintArray result = (*env)->NewIntArray(env, frameSize);  
  230.     (*env)->SetIntArrayRegion(env, result, 0, frameSize, rgb);  
  231.     (*env)->ReleaseByteArrayElements(env, buf, yuv420sp, 0);  
  232.     return result;  
  233. }  
5、在JNI目录下新建Android.mk文件用于生成so文件

[java]  view plain  copy
 print ?
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4.   
  5. LOCAL_SRC_FILES:= com_eric_complexjni_ImageUtilEngine.c  
  6. LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)   
  7. LOCAL_SHARED_LIBRARIES := libutils   
  8. LOCAL_PRELINK_MODULE := false   
  9. LOCAL_MODULE := SimpleJni  
  10. LOCAL_LDLIBS    :=  -llog -ljnigraphics  
  11.   
  12. include $(BUILD_SHARED_LIBRARY)  

你可能感兴趣的:(NDK-JNI开发)