Android-jni技术-II

在概述中基本搭建了一个jni的工程,但是有很多细节都没有讨论,这篇文件就是进一步讨论JNI技术的具体方面的,包括String的传递及使用,java的属性和方法的使用和异常抛出等。 String的使用 java的属性和方法 类的使用 异常抛出 ##String的使用 我们都知道JAVA有String这个类可以很方便地使用字符串,而在c中我们通常是用char*,那么JNI是怎么在这两种类型里转换的呢? 在之前的工程添加以下代码: :::c static JNINativeMethod gMethods[] = { {"intToJni","(I)V", (void*)nativeIntToJni}, {"conversation","(Ljava/lang/String;)Ljava/lang/String;", (void*)nativeConversation}, }; jstring nativeConversation(JNIEnv* env, jobject clazz, jstring fromJava){ const char* message; message = (*env)->GetStringUTFChars(env,fromJava,NULL); __android_log_print(ANDROID_LOG_INFO,"TAG","message from java: %s", message); (*env)->ReleaseStringUTFChars(env, fromJava, message); return (*env)->NewStringUTF(env, "nice to see you , i am c"); } 可以看到fromJava是从java传进来的string,message是jstring转换为char*的容器。使用方法GetStringUTFChars进行转换,使用ReleaseStringUTFChars释放资源。 Warning GetStringUTFChars和ReleaseStringUTFChars需要成对出现,要不会有内存泄漏的,native想保存字符串可以使用memcpy复制一份 顺便说说,貌似getStringRegion不用释放。对于JAVA的数组,也是不能直接使用的,需要做像String一样的处理。 JNI String 方法的汇总 JNI Function Description Since GetStringChars ReleaseStringChars Obtains or releases a pointer to the contents of a string in Unicode format....

March 7, 2013

ubuntu-gcc版本切换

随着ubuntu版本的更新,内置的gcc也随着更新了,可是有时后我们用不到那么高版本的gcc,这时候我们就需要为ubunut切换低版本的gcc了,网上有些方法比较暴力,也比较麻烦,现在我推荐一种智能的方法。 首先我们用gcc -v查看一下我们用的是什么版本的gcc,同时可以使用ls /usr/bin/gcc*来查看机器装了什么版本的gcc。 如果系统没有我们想要的gcc版本,可以通过apt-get来获得,例如: :::sh sudo apt-get install gcc-4.5 gcc-4.5-multilib g++-4.5 g++4.5-multilib 下面就说说这么进行转换,例如我们想把gcc转换为4.4版本: :::sh sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.4 50 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.5 40 接这输入: :::sh sudo update-alternatives --config gcc 你会看到像下面的选项 :::sh 有 3 个候选项可用于替换 gcc (提供 /usr/bin/gcc)。 选择 路径 优先级 状态 * 0 /usr/bin/gcc-4.4 50 自动模式 1 /usr/bin/gcc-4.4 50 手动模式 2 /usr/bin/gcc-4.5 40 手动模式 3 /usr/bin/gcc-4.6 30 手动模式 要维持当前值[*]请按回车键,或者键入选择的编号: 选择你想要的gcc版本就好了,g++设置的方法相同。 如果想删除某个gcc版本的选项的话,可以使用 :::sh sudo update-alternatives --remove gcc /usr/bin/gcc-4....

March 7, 2013

android-jni技术-概述

JNI(Java Native Interface)是java调用本地代码的接口技术,基本上我是用它来在android中调用C/C++,android提供了一套套件叫做NDK(Native Development Kit),使我们可以很方便生成我们需要的目标文件。 专门有网站是介绍使用JNI的,网址是这里 ##使用举例 ###JAVA端实现 info 首先需要明确apk还是运行在Dalvik虚拟机中的,我们暂时还不能编写纯粹C/C++的应用,除非不需要面向用户界面 info 我们可以指定一个类来完成JAVA和C的交互工作,例如com.lingavin.jnisample.JavaToJni.java :::java package com.lingavin.jnsample; public class JavaToJni { static{ //系统加载 libnativejni.so System.loadLibrary("nativejni"); } //对应native函数的接口,用native关键字来修饰 public static native void intToJni(int number); } 就这样一个简单的JAVA端部分完成了,程序通过调用JavaToJni.intToJni(num),就可以将int传入C/C++处理。 ###native端实现 native端的实现才是重点内容,本次使用动态注册的方式和C语言来完成这项工作。 info jni本地代码的接口分为动态注册和静态注册,本文只体现动态注册 info info 要注意用C和用C++写jni接口是有些区别的,主要是方法调用上,C调用env方法是(*env)->xxx(env,xxx),C++则为env->xxx(xxx) info 在本工程中创建一个jni/目录,进去后创建native_sample_jni.c,我们将在这个文件中完成代码编写。开始是JNI_OnLoad函数。 info JNI_OnLoad函数是必须要的,系统就是从这个函数开始注册工作的。这个可以被看做回调函数 info :::c JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){ JNIEnv* env = NULL; jint result = -1; if((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK){ return result; } if(!registerNatives(env)){ return result; } result = JNI_VERSION_1_4; return result; } 看到JNI_OnLoad函数中调用了registerNatives函数,那就看看这个函数干了些什么。...

March 5, 2013

一茶一坐

不小心走进了一茶一坐,发现里面的东西品质还是不错的,但是有点小贵,两个人5个菜,一共100多人民币。可能你会说5个菜才这么点钱还贵?问题是每个菜的分量都不多。 看看我们吃了些啥吧 这个好像是招牌菜,端上来有一个炉在下面烧着,冬天吃很多,鸡很滑,也很有麻油味。 另一道我很喜欢的菜,一个烧得很热的石锅,生牛肉在端上来的时候才放上去,然后服务员帮我们一直搅拌,牛肉慢慢变熟,然后就可以吃啦,很香的一个饭。 这里的煎饺子也不错,里面很多汁。 这个菜就有点不靠谱了。 这个焦糖布丁给了我很大的惊喜,颠覆了我对布丁的看法,像在吃芝士蛋糕。

March 5, 2013

安装ubuntu12.04后...

生命在于折腾,这次除了折腾博客,也折腾了一下系统,ubuntu12.04是一个非常棒的系统,因为它解决了很多以前无解的问题,例如:我笔记本的亮度调节问题,显卡发热问题。而且软件也做了很多调整,gvim竟然是7.3的,而且支持ibus输入中文,可以抛弃vimim插件了。 但是这一切并不是一安装好就有的,需要去配置,这就是为什么写这篇blog。 ##显卡驱动,亮度调节和保存问题 笔记本的配置是双显卡,6750m和核心显卡,dv4-3115,现在的闭源驱动已经可以很好地工作了。 首先去这里下载驱动。我下载的是13.01版本。 还要使用 sudo apt-get install ia32-libs 安装32位库,如果你的系统是64位的话。 然后就可以像装windows软件一样安装驱动了,安装完后执行 sudo aticonfig --inistial -f ,然后重启,检测是否成功的命令是 fglrxinfo 和 fgl_glxgears 。 安装完后打开/etc/default/grub 改一行语句: :::sh GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" 改为 GRUB_CMDLINE_LINUX_DEFAULT="quiet splash acpi_backlight=vendor" 接着运行sudo update-grub,然后重启电脑,这时系统可以调节亮度了,但是不会保存当前值 要保存值,先看看现在的亮度值是多少,可以通过cat /sys/class/backlight/intel_backlight/brightness ,我的值是2442,然后打开文件 sudo gedit /etc/rc.local,在exit0前面加一条语句 :::sh echo 2442 > /sys/class/backlight/intel_backlight/brightness ##安装触摸板驱动器 :::sh sudo add-apt-repository ppa:atareao/atareao sudo apt-get update sudo apt-get install touchpad-indicator ##其他软件的调整 ###1.gvim 使用sudo apt-get install gvim-gnome安装gvim,发现gvim是7.3,顿时欣喜若狂,可是配置了我自己的插件后,发觉打开好慢,而且有错误提示,上网搜索,得到修改方案,在~/.bashrc文件中追加下面信息 :::sh function gvim () { (/usr/bin/gvim -f "$@" &) } alias gvim='UBUNTU_MENUPROXY= gvim' ###2....

March 4, 2013

wav音频文件格式详解

##利用ffmpeg做音频转换 大多时候我们得到的都是mp3格式的音频文件,在linux下我们想要转换音频格式可以使用ffmpeg ,非常方便,没有ffmpeg就安装一个吧 sudo apt-get install ffmpeg 感觉ubuntu真心的方便。 :::java ffmpeg -i track8.mp3 -ar 44100 -ac 2 -acodec pcm_s32le track8.wav 根据上面的命令,我们把track8.mp3转换为采样率44100,采样精度32位,双声道的wav音频文件。 ##文件的十六进制表示 我们选择vim来看其十六进制数据,或许你不相信vim的强大,但事实就是如此,我们用vim打开一个wav是这样的: info 加上 -b 让vim知道你是打开了一个二进制文件,例如:vim track8.wav -b 不用急,只要用命令模式运行如下命令,将会有奇迹发生。:%!xxd 我们需要的信息就在眼前了。现在可以用来分析了。 ##wav框架 终于进入主题了。 分析头部信息前,首先要明确wav文件存储的头部信息是包含在trunk中的,wav由trunk组成的,一个wav大致有以下几个trunk RIFF WAVE Chunk ID=‘RIFF’ RiffType=‘WAVE’ Format Chunk ID = ‘fmt’ Fact Chunk(optional) ID = ‘fact’ Data Chunk ID = ‘data’ ##具体分析 RIFF WAVE Chunk 头 所占字节数 内容 例子 ID 4 ‘RIFF’ 0x52494646 Size 4 0x0037296c Type 4 ‘WAVE’ 0x57415645 可以看到首4个字节是’RIFF’,接着的四个字节是文件的总大小减去头8个字节,最后四个字节是格式类型’WAVE’。...

January 24, 2013

ffmpeg教程一:视频截图(Tutorial 01: Making Screencaps

教程原地址为:http://dranger.com/ffmpeg/tutorial01.html,本人只是做了翻译和部分接口更新工作,保证其能正常工作。需要做一些预备工作 :::java sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libavdevice-dev libavfilter-dev libavutil-dev libpostproc-dev 首先我们需要了解视频文件的一些基本概念,视频文件本身被称作容器,例如avi或者是quicktime,容器的类型确定了文件的信息。然后,容器里装的东西叫流(stream),通常包括视频流和音频流(“流”的意思其实就是“随着时间推移的一段连续的数据元素”)。流中的数据元素叫做“帧”。每个流由不同的编解码器来编码,编解码器定义了数据如何编码(COded)和解码(DECoded),所以叫做编解码器(CODEC)。编解码器的例子有Divx和mp3。包(Packets),是从流中读取的,通过解码器解包,得到原始的帧,我们便可以对这些数据进行播放等的处理。对于我们来说,每个包包含完整的帧,或者多个音频帧。 在初级的水平,处理音视频流是非常简单的: 从video.avi中获得视频流 从视频流中解包得到帧 如果帧不完整,重复第2步 对帧进行相关操作 重复第2步 用ffmpeg来处理多媒体就像上面的步骤那么简单,即使你的第4步可能很复杂。所以在本教程,我们先打开一个视频,读取视频流,获得帧,然后第4步是把帧数据存储为PPM文件。 ##打开文件 我们先来看一下怎么打开一个视频文件,首先把头文件包含进来 :::c #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> ... int main(int argc, char *argv[]){ av_register_all(); av_register_all只需要调用一次,他会注册所有可用的文件格式和编解码库,当文件被打开时他们将自动匹配相应的编解码库。如果你愿意,可以之注册个别的文件格式和编解码库。 现在我们真的要打开一个文件了 :::c AVFormatContext *pFormatCtx; if(av_open_input_file(&pFormatCtx,argv[1],NULL,0,NULL)!=0) return -1; 我们从传入的第一个参数获得文件路径,这个函数会读取文件头信息,并把信息保存在我们存入的pFormatCtx结构体当中。这个函数后面三个参数分别是指定文件格式,缓存大小,和格式化选项,当我们设置为NULL或0时,libavformat会自动完成这些工作。 这个函数仅仅是获得了头信息,下一步我们要得到流信息 :::c if(av_find_steam_info(pFormatCtx)<0) return -1 这个函数填充了pFormatCtx->streams流信息, 我们可以通过dump_format把信息打印出来 :::c dump_format(pFormatCtx, 0, argv[1], 0); pFromatCtx->streams只是大小为pFormateCtx->nb_streams的一系列的点,我们要从中得到视频流 :::c int i; AVCodecContext *pCodecCtx; // Find the first video stream videoStream=-1; for(i=0; i<pformatctx->nb_streams; i++) if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) { videoStream=i; break; } if(videoStream==-1) return -1; // Didn't find a video stream</pformatctx-></pre> // Get a pointer to the codec context for the video stream pCodecCtx=pFormatCtx->streams[videoStream]->codec; pCodecCtx包含了这个流在用的编解码的所有信息,但我们仍需要通过他获得特定的解码器然后打开他。...

January 17, 2013