【JNI】 Android呼叫JNI的進階例項(攝像頭預覽資料轉碼RGB播放)
阿新 • • 發佈:2019-01-24
這裡要說下,儘量不要用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?- package com.eric.complexjni;
-
/*
- *@author Eric
- *@2015-12-7下午4:35:18
- */
- publicclass ImageUtilEngine {
- static {
- System.loadLibrary("");
- }
- publicnativeint[] decodeYUV420SP(byte[] buf, int width, int heigth);
- }
命令視窗: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?- #include <jni.h>
- #include <stdlib.h>
- #include <com_eric_complexjni_ImageUtilEngine.h>
- #include <android/log.h>
- #include <android/bitmap.h>
- #include <math.h>
- #define LOG_TAG "Spore.meitu"
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
- #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
- int min(int x, int y) {
- return (x <= y) ? x : y;
- }
- int max(int x,int y){
- return (x >= y) ? x : y;
- }
- int alpha(int color) {
- return (color >> 24) & 0xFF;
- }
- int red(int color) {
- return (color >> 16) & 0xFF;
- }
- int green(int color) {
- return (color >> 8) & 0xFF;
- }
- int blue(int color) {
- return color & 0xFF;
- }
- int ARGB(int alpha, int red, int green, int blue) {
- return (alpha << 24) | (red << 16) | (green << 8) | blue;
- }
- #include <unistd.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <linux/fb.h>
- #include <sys/mman.h>
- inlinestatic unsigned shortint make16color(unsigned char r, unsigned char g, unsigned char b)
- {
- return (
- (((r >> 3) & 31) << 11) |
- (((g >> 2) & 63) << 5) |
- ((b >> 3) & 31) );
- }
- int framebuffer_main()
- {
- LOGI("framebuffer code");
- int fbfd = 0;
- struct fb_var_screeninfo vinfo;
- struct fb_fix_screeninfo finfo;
- longint screensize = 0;
- char *fbp = 0;
- int x = 0, y = 0;
- int guage_height = 20, step = 10;
- longint location = 0;
- // Open the file for reading and writing
- LOGI("framebuffer code 1");
- fbfd = open("/dev/graphics/fb0", O_RDWR);
- LOGI("framebuffer code 2");
- if (!fbfd) {
- LOGI("Error: cannot open framebuffer device.\n");
- exit(1);
- }
- LOGI("The framebuffer device was opened successfully.\n");
- // Get fixed screen information
- if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
- LOGI("Error reading fixed information.\n");
- exit(2);
- }
- // Get variable screen information
- if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
- LOGI("Error reading variable information.\n");
- exit(3);
- }
- LOGI("sizeof(unsigned short) = %d\n", sizeof(unsigned short));
- LOGI("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
- LOGI("xoffset:%d, yoffset:%d, line_length: %d\n", vinfo.xoffset,
- vinfo.yoffset, finfo.line_length);
- // Figure out the size of the screen in bytes
- screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
- // Map the device to memory
- fbp = (char *) mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
- fbfd, 0);
- if ((int) fbp == -1) {
- LOGI("Error: failed to map framebuffer device to memory.\n");