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、
- 【JNI】 Android调用JNI的进阶实例(摄像头预览数据转码RGB播放)
- Android调用JNI的进阶实例(摄像头预览数据转码RGB播放)
- Android下摄像头预览数据
- Android调用JNI的简单实例(附详细步骤)
- android开发(19) 调用手机的摄像头录像,并播放。
- android开发(19) 调用手机的摄像头录像,并播放。
- android开发(19) 调用手机的摄像头录像,并播放。
- Android 获取摄像头数据并压缩预览
- 最简单的SDL2播放视频的例子(SDL2播放RGB/YUV)--进阶
- Android下调用jni时进行的转码操作实例
- android 摄像头的调用
- android 摄像头的调用
- input 上传图片显示预览、调用摄像头,ios和Android的兼容性解决
- input 上传图片显示预览、调用摄像头,ios和Android的兼容性解决
- 我的Android进阶之旅------>Android MediaPlayer播放mp3的实例--简易mp3播放器
- Android摄像头开发:实时摄像头视频预览帧的编码问题(二)
- Android摄像头开发:实时摄像头视频预览帧的编码问题(二)
- Android摄像头开发:实时摄像头视频预览帧的编码问题(二)
- 排名函数(ROW_NUMBER、RANK、DENSE_RANK)及OVER子句
- gradle批量打包Android apk:不同的包使用不同的icon、label
- vs2013中如何打开asp.net配置页面
- Ebay架构特点(HPTS 2009)
- android 5.0新特性,recyclerview的基本用法,及应注意的问题
- Android调用JNI的进阶实例(摄像头预览数据转码RGB播放)
- 大型网站技术架构Tips
- 1055. The World's Richest (25)【排序】——PAT (Advanced Level) Practise
- struts2+jquery.ajax+json实现用户登陆,报错org.apache.struts2.json.JSONException:解决办法
- 利用jquery函数submit()提交表单注意事项
- Html判断客户端使用的Android还是Ios
- Java多线程简单介绍-1
- 010 MATLAB奇淫技巧之实现图片扫描
- 实验三的迷宫问题