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

来源:互联网 发布:seo标题 编辑:程序博客网 时间:2024/05/01 14:11

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

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

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

1、工程结构:


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

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

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

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

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

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

Demo地址:


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

package com.eric.complexjni;/* *@author Eric  *@2015-12-7下午4:35:18 */public class ImageUtilEngine { static {        System.loadLibrary("");    } public native int[] decodeYUV420SP(byte[] buf, int width, int heigth);}
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

#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>inline static unsigned short int 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;long int screensize = 0;char *fbp = 0;int x = 0, y = 0;int guage_height = 20, step = 10;long int location = 0;// Open the file for reading and writingLOGI("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 informationif (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {LOGI("Error reading fixed information.\n");exit(2);}// Get variable screen informationif (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 bytesscreensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;// Map the device to memoryfbp = (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");exit(4);}LOGI("The framebuffer device was mapped to memory successfully.\n");//set to black color firstmemset(fbp, 0, screensize);//draw rectangley = (vinfo.yres - guage_height) / 2 - 2; // Where we are going to put the pixelfor (x = step - 2; x < vinfo.xres - step + 2; x++) {location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) + (y+ vinfo.yoffset) * finfo.line_length;*((unsigned short int*) (fbp + location)) = 255;}y = (vinfo.yres + guage_height) / 2 + 2; // Where we are going to put the pixelfor (x = step - 2; x < vinfo.xres - step + 2; x++) {location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) + (y+ vinfo.yoffset) * finfo.line_length;*((unsigned short int*) (fbp + location)) = 255;}x = step - 2;for (y = (vinfo.yres - guage_height) / 2 - 2; y < (vinfo.yres+ guage_height) / 2 + 2; y++) {location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) + (y+ vinfo.yoffset) * finfo.line_length;*((unsigned short int*) (fbp + location)) = 255;}x = vinfo.xres - step + 2;for (y = (vinfo.yres - guage_height) / 2 - 2; y < (vinfo.yres+ guage_height) / 2 + 2; y++) {location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) + (y+ vinfo.yoffset) * finfo.line_length;*((unsigned short int*) (fbp + location)) = 255;}// Figure out where in memory to put the pixelfor (x = step; x < vinfo.xres - step; x++) {for (y = (vinfo.yres - guage_height) / 2; y < (vinfo.yres+ guage_height) / 2; y++) {location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) + (y+ vinfo.yoffset) * finfo.line_length;if (vinfo.bits_per_pixel == 32) {*(fbp + location) = 100; // Some blue*(fbp + location + 1) = 15 + (x - 100) / 2; // A little green*(fbp + location + 2) = 200 - (y - 100) / 5; // A lot of red*(fbp + location + 3) = 0; // No transparency} else { //assume 16bppunsigned char b = 255 * x / (vinfo.xres - step);unsigned char g = 255; // (x - 100)/6 A little greenunsigned char r = 255; // A lot of redunsigned short int t = make16color(r, g, b);*((unsigned short int*) (fbp + location)) = t;}}//printf("x = %d, temp = %d\n", x, temp);//sleep to see itusleep(200);}//clean framebuffermunmap(fbp, screensize);close(fbfd);return 0;}int r_v_table[256],g_v_table[256],g_u_table[256],b_u_table[256],y_table[256];int r_yv_table[256][256],b_yu_table[256][256];int inited = 0;void initTable(){if (inited == 0){//framebuffer_main();inited = 1;int m = 0,n=0;for (; m < 256; m++){r_v_table[m] = 1634 * (m - 128);g_v_table[m] = 833 * (m - 128);g_u_table[m] = 400 * (m - 128);b_u_table[m] = 2066 * (m - 128);y_table[m] = 1192 * (m - 16);}int temp = 0;for (m = 0; m < 256; m++)for (n = 0; n < 256; n++){temp = 1192 * (m - 16) + 1634 * (n - 128);if (temp < 0) temp = 0; else if (temp > 262143) temp = 262143;r_yv_table[m][n] = temp;temp = 1192 * (m - 16) + 2066 * (n - 128);if (temp < 0) temp = 0; else if (temp > 262143) temp = 262143;b_yu_table[m][n] = temp;}}}jintArray Java_com_spore_ImageUtilEngine_decodeYUV420SP(JNIEnv * env,jobject thiz, jbyteArray buf, jint width, jint height) {jbyte * yuv420sp = (*env)->GetByteArrayElements(env, buf, 0);int frameSize = width * height;jint rgb[frameSize]; // 鏂板浘鍍忓儚绱犲��initTable();int i = 0, j = 0,yp = 0;int uvp = 0, u = 0, v = 0;for (j = 0, yp = 0; j < height; j++){uvp = frameSize + (j >> 1) * width;u = 0;v = 0;for (i = 0; i < width; i++, yp++){int y = (0xff & ((int) yuv420sp[yp]));if (y < 0)y = 0;if ((i & 1) == 0){v = (0xff & yuv420sp[uvp++]);u = (0xff & yuv420sp[uvp++]);}//int y1192 = 1192 * y;//int r = (y1192 + 1634 * v);//int g = (y1192 - 833 * v - 400 * u);//int b = (y1192 + 2066 * u);int y1192 = y_table[y];int r = r_yv_table[y][v];//(y1192 + r_v_table[v]);int g = (y1192 - g_v_table[v] - g_u_table[u]);int b = b_yu_table[y][u];//(y1192 + b_u_table[u]);//if (r < 0) r = 0; else if (r > 262143) r = 262143;if (g < 0) g = 0; else if (g > 262143) g = 262143;//if (b < 0) b = 0; else if (b > 262143) b = 262143;//r = (r >> 31) ? 0 : (r & 0x3ffff);//g = (g >> 31) ? 0 : (g & 0x3ffff);//b = (b >> 31) ? 0 : (b & 0x3ffff);rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);}}jintArray result = (*env)->NewIntArray(env, frameSize);(*env)->SetIntArrayRegion(env, result, 0, frameSize, rgb);(*env)->ReleaseByteArrayElements(env, buf, yuv420sp, 0);return result;}
5、在JNI目录下新建Android.mk文件用于生成so文件

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= com_eric_complexjni_ImageUtilEngine.cLOCAL_C_INCLUDES := $(JNI_H_INCLUDE) LOCAL_SHARED_LIBRARIES := libutils LOCAL_PRELINK_MODULE := false LOCAL_MODULE := SimpleJniLOCAL_LDLIBS    :=  -llog -ljnigraphicsinclude $(BUILD_SHARED_LIBRARY)
6、







0 1