1.音视频探索(5):JPEG格式与Libjpeg库编译移植
2.Android使用c++库
3.å¦ä½å¨Androidä¸ä½¿ç¨JNI
音视频探索(5):JPEG格式与Libjpeg库编译移植
libJPEG-turbo是用源译一个强大的JPEG图像处理库,它支持JPEG格式的码编编码和解码,尤其对于Android平台,用源译其底层压缩常采用libJPEG。码编然而,用源译Android系统为适应低版本设备,码编聊天派单源码压缩算法非标准,用源译可能导致图像质量和压缩性能的码编权衡。因此,用源译本篇将介绍如何利用AS的码编Cmake工具编译libJPEG-turbo,并通过JNI/NDK技术引入哈夫曼编码以优化Android中的用源译压缩质量。
哈夫曼编码是码编一种无损压缩方法,年由Huffman提出。用源译它依据字符出现概率构造编码,码编概率高的用源译信息编码较短。在图像压缩中,通过计算像素概率生成Huffman码表,梦幻源码泄漏编码后的图像数据记录每个像素的码字,与码表对应。例如,通过构建赫夫曼树,字符集中的字符对应树的路径,形成编码。
libJPEG-turbo中的JPEG编码与解码过程包括:分配压缩对象,设置输出和参数,茅坑游戏源码逐行处理数据,以及解压时分配和初始化解压对象、读取数据等。其核心结构体如jpeg_compress_struct和jpeg_decompress_struct,分别用于压缩和解压缩操作。
为了在Android上实现优化,我们需要从libjpeg-turbo源码开始,首先在CmakeLists.txt中配置项目,卡夫曼源码然后在Java层编写JNI方法,将C++的哈夫曼编码逻辑与Java代码连接。编译后,会生成libjpegtil.so文件,将其与libjpeg.so一同引入目标项目。
Android使用c++库
在Android平台上使用C++库主要有三种方式。
首先,可以直接使用C++库提供的准确的源码Java接口。这种方式通常需要第三方C++库提供JNI接口,并且将.so文件整合进APK即可。
其次,可以选择自己编写JNI接口。这种方法适用于第三方库或者自定义库,需要自行提供JNI接口并自行加载.so。
最后,如果自己编写的C++库需要调用其他C++库,则需自行引入目标第三方库。
举例说明第二种方式:进行NDK编译生成libtest.so,然后将libtest.so和libmylib.so放入APK。使用test接口时,无需额外前缀,加载libtest.so后,系统自动加载libmylib.so。
第三种方式示例:先查看目录布局。进行NDK编译直接集成,将so加入APK即可。在使用者的Android.mk中引入,使用者的源码函数可以直接调用。注意在NDK编译的mk文件中,LOCAL_MODULE名字不需要带lib前缀,加载动态库时系统自动加载相关依赖。
使用C++库时需注意以下几点:确保include语句位于mk文件末尾;使用$(call all-subdir-makefiles)仅引入当前目录下的子目录mk文件;对于赋值过的变量,使用+=追加值,:=会覆盖原有值;注释代码时避免使用\导致所有代码被注释;NDK编译的mk中,LOCAL_MODULE自动添加lib前缀,预编译使用PREBUILT_SHARED_LIBRARY;在已赋值变量上追加值应使用+=;NDK编译的mk文件中,加载动态库时自动加载依赖的动态库。
å¦ä½å¨Androidä¸ä½¿ç¨JNI
ãã1.å¼è¨
ããæ们ç¥éï¼Androidç³»ç»çåºå±åºç±c/c++ç¼åï¼ä¸å±Androidåºç¨ç¨åºéè¿Javaèææºè°ç¨åºå±æ¥å£ï¼è¡æ¥åºå±c/c++åºä¸Javaåºç¨ç¨åºé´çæ¥å£æ£æ¯JNIï¼JavaNative Interface)ãæ¬ææè¿°äºå¦ä½å¨ubuntuä¸é ç½®AndroidJNIçå¼åç¯å¢ï¼ä»¥åå¦ä½ç¼åä¸ä¸ªç®åçcå½æ°åºåJNIæ¥å£ï¼å¹¶éè¿ç¼åJavaç¨åºè°ç¨è¿äºæ¥å£ï¼æç»è¿è¡å¨æ¨¡æå¨ä¸çè¿ç¨ã
ãã2.ç¯å¢é ç½®
ãã2.1.å®è£ jdk1.6
ããï¼1ï¼ä»jdkå®æ¹ç½ç«ä¸è½½jdk-6u-linux-i.binæ件ã
ããï¼2ï¼æ§è¡jdkå®è£ æ件
ãã[html] view plaincopyprint?
ãã.$chmod a+x jdk-6u-linux-i.bin
ãã.$jdk-6u-linux-i.bin
ãã$chmod a+x jdk-6u-linux-i.bin
ãã$jdk-6u-linux-i.bin
ãã(3)é ç½®jdkç¯å¢åé
ãã[html] view plaincopyprint?
ãã.$sudo vim /etc/profile
ãã.#JAVAEVIRENMENT
ãã.exportJAVA_HOME=/usr/lib/java/jdk1.6.0_
ãã.exportJRE_HOME=$JAVA_HOME/jre
ãã.exportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
ãã.exportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
ãã$sudo vim /etc/profile
ãã#JAVAEVIRENMENT
ããexportJAVA_HOME=/usr/lib/java/jdk1.6.0_
ããexportJRE_HOME=$JAVA_HOME/jre
ããexportCLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
ããexportPATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
ããä¿ååéåºç¼è¾ï¼å¹¶éå¯ç³»ç»ã
ããï¼4ï¼éªè¯å®è£
ãã[html] view plaincopyprint?
ãã.$java -version
ãã.javaversion "1.6.0_"
ãã.Java(TM)SE Runtime Environment (build 1.6.0_-b)
ãã.JavaHotSpot(TM) Server VM (build .4-b, mixed mode)
ãã.$javah
ãã.ç¨æ³ï¼javah[é项]<ç±»>
ãã.å ¶ä¸[é项]å æ¬ï¼
ãã.-helpè¾åºæ¤å¸®å©æ¶æ¯å¹¶éåº
ãã.-classpath<è·¯å¾>ç¨äºè£ å ¥ç±»çè·¯å¾
ãã.-bootclasspath<è·¯å¾>ç¨äºè£ å ¥å¼å¯¼ç±»çè·¯å¾
ãã.-d<ç®å½>è¾åºç®å½
ãã.-o<æ件>è¾åºæ件ï¼åªè½ä½¿ç¨-dæ-oä¸çä¸ä¸ªï¼
ãã.-jniçæJNIæ ·å¼ç头æ件ï¼é»è®¤ï¼
ãã.-versionè¾åºçæ¬ä¿¡æ¯
ãã.-verboseå¯ç¨è¯¦ç»è¾åº
ãã.-forceå§ç»åå ¥è¾åºæ件
ãã.使ç¨å ¨éå®å称æå®<ç±»>ï¼ä¾
ãã.å¦ï¼java.lang.Objectï¼ã
ãã$java -version
ããjavaversion "1.6.0_"
ããJava(TM)SE Runtime Environment (build 1.6.0_-b)
ããJavaHotSpot(TM) Server VM (build .4-b, mixed mode)
ãã$javah
ããç¨æ³ï¼javah[é项]<ç±»>
ããå ¶ä¸[é项]å æ¬ï¼
ãã-helpè¾åºæ¤å¸®å©æ¶æ¯å¹¶éåº
ãã-classpath<è·¯å¾>ç¨äºè£ å ¥ç±»çè·¯å¾
ãã-bootclasspath<è·¯å¾>ç¨äºè£ å ¥å¼å¯¼ç±»çè·¯å¾
ãã-d<ç®å½>è¾åºç®å½
ãã-o<æ件>è¾åºæ件ï¼åªè½ä½¿ç¨-dæ-oä¸çä¸ä¸ªï¼
ãã-jniçæJNIæ ·å¼ç头æ件ï¼é»è®¤ï¼
ãã-versionè¾åºçæ¬ä¿¡æ¯
ãã-verboseå¯ç¨è¯¦ç»è¾åº
ãã-forceå§ç»åå ¥è¾åºæ件
ãã使ç¨å ¨éå®å称æå®<ç±»>ï¼ä¾
ããå¦ï¼java.lang.Objectï¼ã2.2.å®è£ androidåºç¨ç¨åºå¼åç¯å¢
ããubuntuä¸å®è£ androidåºç¨ç¨åºå¼åç¯å¢ä¸windows类似ï¼ä¾æ¬¡å®è£ 好以ä¸è½¯ä»¶å³å¯ï¼
ããï¼1ï¼Eclipse
ããï¼2ï¼ADT
ããï¼3ï¼AndroidSDK
ããä¸windowsä¸å®è£ å¯ä¸ä¸åçä¸ç¹æ¯ï¼ä¸è½½è¿äºè½¯ä»¶çæ¶åè¦ä¸è½½Linuxçæ¬çå®è£ å ã
ããå®è£ 好以ä¸androidåºç¨ç¨åºçå¼åç¯å¢åï¼è¿å¯ä»¥éæ©æ¯å¦éè¦é ç½®emulatoråadbå·¥å ·çç¯å¢åéï¼ä»¥æ¹ä¾¿å¨è¿è¡JNIå¼åçæ¶å使ç¨ãé ç½®æ¥éª¤å¦ä¸ï¼
ããæemulatoræå¨ç®å½android-sdk-linux/tools以åadbæå¨ç®å½android-sdk-linux/platform-toolsæ·»å å°ç¯å¢åéä¸ï¼android-sdk-linuxæandroidsdkå®è£ å android-sdk_rxx-linuxç解åç®å½ã
ãã[plain] view plaincopyprint?
ãã.$sudo vim /etc/profile
ãã.exportPATH=~/software/android/android-sdk-linux/tools:$PATH
ãã. exportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH
ãã$sudo vim /etc/profile
ããexportPATH=~/software/android/android-sdk-linux/tools:$PATH
ããexportPATH=~/software/android/android-sdk-linux/platform-tools:$PATH
ããç¼è¾å®æ¯åéåºï¼å¹¶éå¯çæã
ãã2.3.å®è£ NDK
ããNDKæ¯ç±androidæä¾çç¼è¯androidæ¬å°ä»£ç çä¸ä¸ªå·¥å ·ã
ããï¼1ï¼ä»androidndkå®ç½/sdk/ndk/index.htmlä¸è½½ndkï¼ç®åææ°çæ¬ä¸ºandroid-ndk-r6b-linux-x.tar.bz2.
ããï¼2ï¼è§£åndkå°å·¥ä½ç®å½ï¼
ãã[plain] view plaincopyprint?
ãã.$tar -xvf android-ndk-r6b-linux-x.tar.bz2
ãã.$sudo mv android-ndk-r6b /usr/local/ndk
ãã$tar -xvf android-ndk-r6b-linux-x.tar.bz2
ãã$sudo mv android-ndk-r6b /usr/local/ndk
ããï¼3ï¼è®¾ç½®ndkç¯å¢åé
ãã[plain] view plaincopyprint?
ãã.$sudo vim /etc/profile
ãã.exportPATH=/usr/local/ndk:$PATH
ãã$sudo vim /etc/profile
ããexportPATH=/usr/local/ndk:$PATH
ããç¼è¾å®æ¯åä¿åéåºï¼å¹¶éå¯çæ
ããï¼4ï¼éªè¯å®è£
ãã[plain] view plaincopyprint?
ãã.$ cd/usr/local/ndk/samples/hello-jni/
ãã.$ ndk-build
ãã.Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver
ãã.Gdbsetup : libs/armeabi/gdb.setup
ãã.Install : libhello-jni.so => libs/armeabi/libhello-jni.so
ãã$ cd/usr/local/ndk/samples/hello-jni/
ãã$ ndk-build
ããGdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver
ããGdbsetup : libs/armeabi/gdb.setup
ããInstall : libhello-jni.so => libs/armeabi/libhello-jni.so
ãã3.JNIå®ç°
ããæ们éè¦å®ä¹ä¸ä¸ªç¬¦åJNIæ¥å£è§èçc/c++æ¥å£ï¼è¿ä¸ªæ¥å£ä¸ç¨å¤ªå¤æï¼ä¾å¦è¾åºä¸ä¸ªå符串ãæ¥ä¸æ¥ï¼åéè¦æc/c++æ¥å£ç代ç æ件ç¼è¯æå ±äº«åºï¼å¨æåºï¼.soæ件ï¼å¹¶æ¾å°æ¨¡æå¨çç¸å ³ç®å½ä¸ãæåï¼å¯å¨Javaåºç¨ç¨åºï¼å°±å¯ä»¥çå°æç»ææäºã
ãã3.1.ç¼åJavaåºç¨ç¨åºä»£ç
ããï¼1ï¼å¯å¨Eclipseï¼æ°å»ºandroidå·¥ç¨
ããProjectï¼JNITest
ããPackageï¼org.tonny.jni
ããActivityï¼JNITest
ããï¼2ï¼ç¼è¾èµæºæ件
ããç¼è¾res/values/strings.xmlæ件å¦ä¸ï¼
ãã
ããç¼è¾res/layout/main.xmlæ件
ããæ们å¨ä¸»çé¢ä¸æ·»å äºä¸ä¸ªEditTextæ§ä»¶åä¸ä¸ªButtonæ§ä»¶ã
ããï¼3ï¼ç¼è¾JNITest.javaæ件
ã
ããstatic表示å¨ç³»ç»ç¬¬ä¸æ¬¡å 载类çæ¶åï¼å æ§è¡è¿ä¸æ®µä»£ç ï¼å¨è¿é表示å è½½å¨æåºlibJNITest.soæ件ã
ããåçè¿ä¸æ®µï¼
ãã[java] view plaincopyprint?
ãã.privatenativeString GetReply();
ããprivatenativeString GetReply();
ããnative表示è¿ä¸ªæ¹æ³ç±æ¬å°ä»£ç å®ä¹ï¼éè¦éè¿jniæ¥å£è°ç¨æ¬å°c/c++代ç ã
ãã[java] view plaincopyprint?
ãã.publicvoidonClick(View arg0) {
ãã.edtName.setText(reply);
ãã.}
ããpublicvoidonClick(View arg0) {
ããedtName.setText(reply);
ãã}
ããè¿æ®µä»£ç 表示ç¹å»æé®åï¼ænativeæ¹æ³çè¿åçå符串æ¾ç¤ºå°EditTextæ§ä»¶ã
ããï¼4ï¼ç¼è¯å·¥ç¨ï¼çæ.classæ件ã
ãã3.2.ç¨javahå·¥å ·çæ符åJNIè§èçcè¯è¨å¤´æ件
ããå¨ç»ç«¯ä¸ï¼è¿å ¥androidå·¥ç¨æå¨çbinç®å½
ãã[plain] view plaincopyprint?
ãã.$cd ~/project/Android/JNITest/bin
ãã$cd ~/project/Android/JNITest/bin
ããæ们ç¨lså½ä»¤æ¥çï¼å¯ä»¥çå°binç®å½ä¸æ个classesç®å½ï¼å ¶ç®å½ç»æ为classes/org/tonny/jniï¼å³classesçåç®å½ç»ææ¯androidå·¥ç¨çå åorg.tonny.jniã请注æï¼ä¸é¢æ们åå¤æ§è¡javahå½ä»¤çæ¶åï¼å¿ é¡»è¿å ¥å°org/tonny/jniçä¸çº§ç®å½ï¼å³classesç®å½ï¼å¦åjavahä¼æ示æ¾ä¸å°ç¸å ³çjavaç±»ã
ããä¸é¢ç»§ç»ï¼
ãã[plain] view plaincopyprint?
ãã.$cd classes
ãã.$javah org.tonny.jni.JNITest
ãã.$ls
ãã.org org_tonny_jni_JNITest.h
ãã$cd classes
ãã$javah org.tonny.jni.JNITest
ãã$ls
ããorg org_tonny_jni_JNITest.h
ããæ§è¡javahorg.tonny.jni.JNITestå½ä»¤ï¼å¨classesç®å½ä¸ä¼çæorg_tonny_jni_JNITest.h头æ件ãå¦æä¸è¿å ¥å°classesç®å½ä¸çè¯ï¼ä¹å¯ä»¥è¿æ ·ï¼
ãã[plain] view plaincopyprint?
ãã.$javah -classpath ~/project/Android/JNITest/bin/classesorg.tonny.jni.JNITest
ãã$javah -classpath ~/project/Android/JNITest/bin/classesorg.tonny.jni.JNITest
ãã-classpath åæ°è¡¨ç¤ºè£ 载类çç®å½ã
ãã3.3.ç¼åc/c++代ç
ããçæorg_tonny_jni_JNITest.h头æ件åï¼æ们就å¯ä»¥ç¼åç¸åºçå½æ°ä»£ç äºãä¸é¢å¨androidå·¥ç¨ç®å½ä¸æ°å»ºjniç®å½ï¼å³~/project/Android/JNITest/jniï¼æorg_tonny_jni_JNITest.h头æ件æ·è´å°jniç®å½ä¸ï¼å¹¶å¨jniç®å½ä¸æ°å»ºorg_tonny_jni_JNITest.cæ件ï¼ç¼è¾ä»£ç å¦ä¸ï¼
ãã[cpp] view plaincopyprint?
ãã.#include<jni.h>
ãã.#include<string.h>
ãã.#include"org_tonny_jni_JNITest.h"
ãã.
ãã.
ãã.JNIEXPORTjstring JNICALLJava_org_tonny_jni_JNITest_GetReply
ãã.(JNIEnv *env, jobject obj){
ãã.return(*env)->NewStringUTF(env,(char*)"Hello,JNITest");
ãã.}
ãã#include<jni.h>
ãã#include<string.h>
ãã#include"org_tonny_jni_JNITest.h"
ããJNIEXPORTjstring JNICALLJava_org_tonny_jni_JNITest_GetReply
ãã(JNIEnv *env, jobject obj){
ããreturn(*env)->NewStringUTF(env,(char*)"Hello,JNITest");
ãã}
ããæ们å¯ä»¥çå°ï¼è¯¥å½æ°çå®ç°ç¸å½ç®åï¼è¿åä¸ä¸ªå符串为ï¼"Hello,JNITest"
ãã3.4.ç¼åAndroid.mkæ件
ããå¨~/project/Android/JNITest/jniç®å½ä¸æ°å»ºAndroid.mkæ件ï¼androidå¯ä»¥æ ¹æ®è¿ä¸ªæ件çç¼è¯åæ°ç¼è¯æ¨¡åãç¼è¾Android.mkæ件å¦ä¸ï¼
ãã[plain] view plaincopyprint?
ãã.LOCAL_PATH:= $(call my-dir)
ãã.include$(CLEAR_VARS)
ãã.LOCAL_MODULE := libJNITest
ãã.LOCAL_SRC_FILES:= org_tonny_jni_JNITest.c
ãã.include$(BUILD_SHARED_LIBRARY)
ããLOCAL_PATH:= $(call my-dir)
ããinclude$(CLEAR_VARS)
ããLOCAL_MODULE := libJNITest
ããLOCAL_SRC_FILES:= org_tonny_jni_JNITest.c
ããinclude$(BUILD_SHARED_LIBRARY)
ããLOCAL_MODULE表示ç¼è¯çå¨æåºå称
ããLOCAL_SRC_FILES 表示æºä»£ç æ件
ãã3.5.ç¨ndkå·¥å ·ç¼è¯å¹¶çæ.soæ件
ããè¿å ¥å°JNITestçå·¥ç¨ç®å½ï¼æ§è¡ndk-buildå½ä»¤å³å¯çælibJNITest.soæ件ã
ãã[plain] view plaincopyprint?
ãã.$cd ~/project/Android/JNITest/
ãã.$ndk-build
ãã.Invalidattribute name:
ãã.package
ãã.Install : libJNITest.so => libs/armeabi/libJNITest.so
ãã$cd ~/project/Android/JNITest/
ãã$ndk-build
ããInvalidattribute name:
ããpackage
ããInstall : libJNITest.so => libs/armeabi/libJNITest.so
ããå¯ä»¥çå°ï¼å¨å·¥ç¨ç®å½çlibs/armeabiç®å½ä¸çæäºlibJNITest.soæ件ã
ãã3.6.å¨æ¨¡æå¨ä¸è¿è¡
ããï¼1ï¼é¦å ï¼æ们æandroid模æå¨å¯å¨èµ·æ¥ãè¿å ¥å°emulatoræå¨ç®å½ï¼æ§è¡emulatorå½ä»¤ï¼
ãã[plain] view plaincopyprint?
ãã.$cd ~/software/android/android-sdk-linux/tools
ãã.$./emulator @AVD-2.3.3-V -partition-size
ãã$cd ~/software/android/android-sdk-linux/tools
ãã$./emulator @AVD-2.3.3-V -partition-size
ããAVD-2.3.3-Vè¡¨ç¤ºä½ ç模æå¨å称ï¼ä¸å¨Eclipse->AVDManagerä¸çAVDName对åºï¼-partition-size表示模æå¨çåå¨è®¾å¤å®¹éã
ããï¼2ï¼æ¥ä¸æ¥ï¼æ们éè¦ælibJNITest.soæ件æ·è´å°æ¨¡æå¨ç/system/libç®å½ä¸ï¼æ§è¡ä»¥ä¸å½ä»¤ï¼
ãã[plain] view plaincopyprint?
ãã.$cd ~/project/Android/JNITest/libs/armeabi/
ãã.$adb remount
ãã.$adb push libJNITest.so /system/lib
ãã. KB/s ( bytes in 0.s)
ãã$cd ~/project/Android/JNITest/libs/armeabi/
ãã$adb remount
ãã$adb push libJNITest.so /system/lib
ãã KB/s ( bytes in 0.s)
ããå½å¨ç»ç«¯ä¸çå°æ KB/s ( bytes in 0.s)ä¼ è¾é度çä¿¡æ¯çæ¶åï¼è¯´ææ·è´æåã
ããï¼3ï¼å¨ç»ç«¯ä¸æ§è¡JNITestç¨åºï¼è¿ä¸ªæ们å¯ä»¥å¨Eclipseä¸ï¼å³é®ç¹å»JNITestå·¥ç¨ï¼RunAs->Android Applicationï¼å³å¯å¨æ¨¡æå¨ä¸å¯å¨ç¨åº