1. 程式人生 > >【JNI】 Android呼叫JNI的進階例項(攝像頭預覽資料轉碼RGB播放)

【JNI】 Android呼叫JNI的進階例項(攝像頭預覽資料轉碼RGB播放)

這裡要說下,儘量不要用Java寫編解碼的東西,就算你是大神,你寫的出來,但那也是不實用的,就像切西瓜一樣,拿一把削水果刀去切西瓜,肯定比不上用西瓜刀方便吧,還是老老實實寫個JNI呼叫得了,也不復雜C/C++方便的很,當然,這裡不是說Java不行,語言只是工具,做什麼事情用什麼語言,沒必要硬著頭皮往上頂對吧。純屬個人觀點,大神可以無視。

好了進入正題,該例項主要內容:開啟攝像頭預覽,將獲取到的視訊幀YUV資料,通過JNI呼叫C的轉碼函式轉為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. publicclass ImageUtilEngine {  
  7.      static {  
  8.             System.loadLibrary("");  
  9.         }  
  10.      publicnativeint[] decodeYUV420SP(byte[] buf, int width, int heigth);  
  11. }  
3、編譯該介面類的標頭檔案.h

命令視窗:Win+R執行cmd,cd進入到eclipse工作空間中ComplexJni工程目錄,

輸入javah -classpath bin/classes -d jni com.eric.complexjni.ImageUtilEngine編譯介面類


編譯完成後,重新整理工程,就可以看到工程中自動建立了jni資料夾,其中包含編譯好的.h標頭檔案


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

[cpp] view plain copy  print?
  1. #include <jni.h>
  2. #include <stdlib.h>
  3. #include <com_eric_complexjni_ImageUtilEngine.h>
  4. #include <android/log.h>
  5. #include <android/bitmap.h>
  6. #include <math.h>
  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. int min(int x, int y) {  
  11.     return (x <= y) ? x : y;  
  12. }  
  13. int max(int x,int y){  
  14.     return (x >= y) ? x : y;  
  15. }  
  16. int alpha(int color) {  
  17.     return (color >> 24) & 0xFF;  
  18. }  
  19. int red(int color) {  
  20.     return (color >> 16) & 0xFF;  
  21. }  
  22. int green(int color) {  
  23.     return (color >> 8) & 0xFF;  
  24. }  
  25. int blue(int color) {  
  26.     return color & 0xFF;  
  27. }  
  28. int ARGB(int alpha, int red, int green, int blue) {  
  29.     return (alpha << 24) | (red << 16) | (green << 8) | blue;  
  30. }  
  31. #include <unistd.h>
  32. #include <stdio.h>
  33. #include <fcntl.h>
  34. #include <linux/fb.h>
  35. #include <sys/mman.h>
  36. inlinestatic unsigned shortint make16color(unsigned char r, unsigned char g, unsigned char b)  
  37. {  
  38.     return (  
  39.  (((r >> 3) & 31) << 11) |  
  40.  (((g >> 2) & 63) << 5)  |  
  41.   ((b >> 3) & 31)        );  
  42. }  
  43. int framebuffer_main()  
  44. {  
  45.     LOGI("framebuffer code");  
  46.     int fbfd = 0;  
  47.     struct fb_var_screeninfo vinfo;  
  48.     struct fb_fix_screeninfo finfo;  
  49.     longint screensize = 0;  
  50.     char *fbp = 0;  
  51.     int x = 0, y = 0;  
  52.     int guage_height = 20, step = 10;  
  53.     longint location = 0;  
  54.     // Open the file for reading and writing
  55.     LOGI("framebuffer code 1");  
  56.     fbfd = open("/dev/graphics/fb0", O_RDWR);  
  57.     LOGI("framebuffer code 2");  
  58.     if (!fbfd) {  
  59.         LOGI("Error: cannot open framebuffer device.\n");  
  60.         exit(1);  
  61.     }  
  62.     LOGI("The framebuffer device was opened successfully.\n");  
  63.     // Get fixed screen information
  64.     if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {  
  65.         LOGI("Error reading fixed information.\n");  
  66.         exit(2);  
  67.     }  
  68.     // Get variable screen information
  69.     if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {  
  70.         LOGI("Error reading variable information.\n");  
  71.         exit(3);  
  72.     }  
  73.     LOGI("sizeof(unsigned short) = %d\n"sizeof(unsigned short));  
  74.     LOGI("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);  
  75.     LOGI("xoffset:%d, yoffset:%d, line_length: %d\n", vinfo.xoffset,  
  76.             vinfo.yoffset, finfo.line_length);  
  77.     // Figure out the size of the screen in bytes
  78.     screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;  
  79.     // Map the device to memory
  80.     fbp = (char *) mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,  
  81.             fbfd, 0);  
  82.     if ((int) fbp == -1) {  
  83.         LOGI("Error: failed to map framebuffer device to memory.\n");