最近开始做Android平台下的相机开发,有别于驱动层和HAL层,我更多的是关注成像画质和虚拟预览等上层应用,整理了一点心得,感觉有必要记录一下成长的足迹。因为初学,不保证理解精准到位,请各位看官们坚定立场,大神请绕路走咯。
一、源码编译
对于自学开源软件,我已经养成了一套自己的学习法则,那肯定是下载源码—>查阅系统架构介绍(一定是官方网站为主+各路民间帖)—>扣取感兴趣小模块,导入IDE里深入分析—>再参考官网上对应部分的tutorials(好的开源软件这个部分都很赞!就像ROS)—>从编译helloworld开始学习编译源代码 —>改写代码,引用自己需要的三方库—>鉴于Android移动开发,最后一步一定是要在真机上install对应的apk咯。
1)开发环境的搭建
先确保安装好对应版本的JDK(我用jdk1.7.0_45),然后把官网上的adt-bundle-windows-x86_64-20131030下载下来,直接就可以用了!后面需要的build-tools、SDK-tools、platform-tools等软件包,就交给eclipse下的Android SDK Manager了,能保证网络通畅就行,真是一个简单粗暴但有效便捷的方法啊。
2)扣Gallery2源码
在Android-4.2.1_r1/packages/apps路径下截取Gallery2和Camera包。从4.0版本起,google将Gallery和Camera联系在了一起,编译前者的时候,后者不可获取,这从Gallery/AndroidManifest.xml文件中多处闪现的camera字眼中可见。这里,要提前在系统源码编译的/out/target/commom/obj/JAVA_LIBRARIES路径下,挖出几个后续Gallery2编译过程中所需要引用的几个静态库。分别将core_intermediates、framework_intermediates、mp4parser_intermediates、xmp_toolkit_intermediates四个路径下得classes.jar 文件分别重命名为 core_intermediates.jar、framework_intermediates.jar、mp4parser_intermediates.jar、xmp_toolkit_intermediates.jar,放入本地一个文件夹里,作为后续编译Gallery2模块源码静态库的预前准备。
3)在eclipse里面导入源码,编译
a .在eclipse里的Android Project from Existing Code里面选Gallery2文件夹,不要test。接着在项目属性的Java Build Path的Source选项下将gallerycommon和src_pd作为源代码文件夹add进入。这里我做的一件事是,在gallerycommon文件夹下,删除了原来自带的以src开头的包,新建了三个以com开头对应名称的包,然后就ctrl+a把对应路径下本地文件夹下的源java文件Paste到eclipse里对应的包名下(以防后续import时src的多余)。同时,在Build Path里面用Add Libraries将之前准备的几个jar包填进去。用Order and Export排一下序,就基本完成了第一步操作了。
b.这时,src等源文件里面还是一片红色小叉,不用着急。打开看后,发现很多都是import时文件缺损的问题,总结有两类,一类是R问题(对应的gen下面果然没有自己生成对应的R.java文件,这个先放一部),另一类就是camera相关的文件找不到的问题了,这个也等下一步解决吧。
c.查看最不该有红叉的资源文件夹,发现res/value下面的filtershow_strings.xml、photoeditor_strings.xml、strings.xml都有错误,原因是里面有重复定义!最简单粗暴的方法即是找到有错的语句,将其用<!-- -->注释掉。可以按照这种方法对values-xx开头的文件夹都做相同的处理,但参照前人的说法,支柱是简体中文的我们大可将values-zh-rCN之外的value-xx从项目中移除。剩下的rCN文件夹做上面同样的注释处理。
d.开始配置camera包了。一个导入之前不可缺少的工作是检查camera下的res文件夹和当前gallery工程下的res文件夹下的文件有无重名。例如:两者的values文件夹下都有atrrs.xml文件,则需要将camera的那一份重命名为atrrs_camera.xml,否则会发生覆盖导致出错。此时,在Gallery工程里右击import-General-File System,展开下面的两格小窗,不要选.git、test、Android.mk、CleanSpec.mk文件夹。
e.点击Clean后,发现gen/com.android.gallery3d下已经生成了R.java,要注意的是,此时Camera工程原本自身的com.android.camera.R(指向其对应的资源)也都整合到com.android.gallery3d.R文件中了。因此凡是有import com.android.camera.R的地方都该换成import com.android.gallery3d.R来替换。同时,之前引用了R导致报错的地方也应该import com.android.gallery3d.R。
f.等两秒,发现红叉不见了,clean编译时会报错:ImageFilterSharpen.java函数里找不到forEach_root()函数。在源代码编译的输出文件路径/out/target/common/obj/APPS/GALLERY2_intermediates/src/com/android/Gallery3d/filtershow/filters文件夹下找到ScriptC_convolve3x3.java一共可以找到3份同名的文件,将有forEach_root(Allocation, Allocation)接口的文件拷贝一份出来,在com.android.gallery3d.filtershow.filters路径下,将其名字改为MyScriptC_convolve3x3.java,区别开gen路径下的ScriptC_convolve3x3.java。并在引用其构造实例的地方更改名字,如在ImageFilterSharpen.java中,将ScriptC_convolve3x3 mScript改为MyScriptC_convolve3x3 mScript,并在相应地方同步更改类名。MyScriptC_convolve3x3.java代码如下:
- /*
- * Copyright (C) 2011-2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.android.gallery3d.filtershow.filters;
- import android.renderscript.*;
- import android.content.res.Resources;
- /**
- * @hide
- */
- public class MyScriptC_convolve3x3 extends ScriptC {
- private static final String __rs_resource_name = "convolve3x3";
- // Constructor
- public MyScriptC_convolve3x3(RenderScript rs) {
- this(rs,
- rs.getApplicationContext().getResources(),
- rs.getApplicationContext().getResources().getIdentifier(
- __rs_resource_name, "raw",
- rs.getApplicationContext().getPackageName()));
- }
- public MyScriptC_convolve3x3(RenderScript rs, Resources resources, int id) {
- super(rs, resources, id);
- __I32 = Element.I32(rs);
- __ALLOCATION = Element.ALLOCATION(rs);
- __F32 = Element.F32(rs);
- __U8_4 = Element.U8_4(rs);
- }
- private Element __ALLOCATION;
- private Element __F32;
- private Element __I32;
- private Element __U8_4;
- private FieldPacker __rs_fp_ALLOCATION;
- private FieldPacker __rs_fp_F32;
- private FieldPacker __rs_fp_I32;
- private final static int mExportVarIdx_gWidth = 0;
- private int mExportVar_gWidth;
- public synchronized void set_gWidth(int v) {
- setVar(mExportVarIdx_gWidth, v);
- mExportVar_gWidth = v;
- }
- public int get_gWidth() {
- return mExportVar_gWidth;
- }
- public Script.FieldID getFieldID_gWidth() {
- return createFieldID(mExportVarIdx_gWidth, null);
- }
- private final static int mExportVarIdx_gHeight = 1;
- private int mExportVar_gHeight;
- public synchronized void set_gHeight(int v) {
- setVar(mExportVarIdx_gHeight, v);
- mExportVar_gHeight = v;
- }
- public int get_gHeight() {
- return mExportVar_gHeight;
- }
- public Script.FieldID getFieldID_gHeight() {
- return createFieldID(mExportVarIdx_gHeight, null);
- }
- private final static int mExportVarIdx_gPixels = 2;
- private Allocation mExportVar_gPixels;
- public void bind_gPixels(Allocation v) {
- mExportVar_gPixels = v;
- if (v == null) bindAllocation(null, mExportVarIdx_gPixels);
- else bindAllocation(v, mExportVarIdx_gPixels);
- }
- public Allocation get_gPixels() {
- return mExportVar_gPixels;
- }
- private final static int mExportVarIdx_gIn = 3;
- private Allocation mExportVar_gIn;
- public synchronized void set_gIn(Allocation v) {
- setVar(mExportVarIdx_gIn, v);
- mExportVar_gIn = v;
- }
- public Allocation get_gIn() {
- return mExportVar_gIn;
- }
- public Script.FieldID getFieldID_gIn() {
- return createFieldID(mExportVarIdx_gIn, null);
- }
- private final static int mExportVarIdx_gCoeffs = 4;
- private float[] mExportVar_gCoeffs;
- public synchronized void set_gCoeffs(float[] v) {
- mExportVar_gCoeffs = v;
- FieldPacker fp = new FieldPacker(36);
- for (int ct1 = 0; ct1 < 9; ct1++) {
- fp.addF32(v[ct1]);
- }
- int []__dimArr = new int[1];
- __dimArr[0] = 9;
- setVar(mExportVarIdx_gCoeffs, fp, __F32, __dimArr);
- }
- public float[] get_gCoeffs() {
- return mExportVar_gCoeffs;
- }
- public Script.FieldID getFieldID_gCoeffs() {
- return createFieldID(mExportVarIdx_gCoeffs, null);
- }
- private final static int mExportForEachIdx_root = 0;
- public Script.KernelID getKernelID_root() {
- return createKernelID(mExportForEachIdx_root, 3, null, null);
- }
- public void forEach_root(Allocation ain, Allocation aout) {
- // check ain
- if (!ain.getType().getElement().isCompatible(__U8_4)) {
- throw new RSRuntimeException("Type mismatch with U8_4!");
- }
- // check aout
- if (!aout.getType().getElement().isCompatible(__U8_4)) {
- throw new RSRuntimeException("Type mismatch with U8_4!");
- }
- // Verify dimensions
- Type tIn = ain.getType();
- Type tOut = aout.getType();
- if ((tIn.getCount() != tOut.getCount()) ||
- (tIn.getX() != tOut.getX()) ||
- (tIn.getY() != tOut.getY()) ||
- (tIn.getZ() != tOut.getZ()) ||
- (tIn.hasFaces() != tOut.hasFaces()) ||
- (tIn.hasMipmaps() != tOut.hasMipmaps())) {
- throw new RSRuntimeException("Dimension mismatch between input and output parameters!");
- }
- forEach(mExportForEachIdx_root, ain, aout, null);
- }
- }
经过上述步骤,基于Android4.2源码的Gallery2、Camera模块在eclipse里面已能正常编译,生成对应的apk,贴一张“劫后照”:
二、apk安装
在Run As Android Application时, 接入真机后Console上会报错:Re-installation failed due to different application signatures。You must perform a full uninstall of the application. WARNING: This will remove the application data! Please execute 'adb uninstall com.android.gallery3d' in a shell.接着就退出了。但用模拟器运行则不会有错。从上面的错误信息中容易知道,这是因为现在的Android手机中很多已有了gallery3d系列应用,安装同名(我对应的版本号在AndroidManifest.xml下显示是1.1.40001)包会报冲突——有人就更改了包名,后面一路安装顺畅,最后在手机上出现了两个图库和相机应用。我没有这样做,选择的是删掉旧的应用包(系统默认包),安装新应用包。
查阅了一些文档,发现此方法简单有效——手机接入电脑,在windows下打开cmd,在adb.exe安装路径下使用adb shell进入手机真是系统级目录(区别于用户级目录),可以在/system/app下面看到Gallery.apk,使用rm命令删除之。再次回到eclipse里run项目的时候,依然会报Installation error: INSTALL_FAILED_UPDATE_INCOMPATIBLE错误。google一下,有人说是前一步删除旧的应用包时删的不太干净,因为/data/system/package.xml文件中或许还包含了该应用的相关信息,建议使用界面操作setting—>applications—>manage applications—>应用—> application Info —>uninstall进行优雅卸载。果然在我的手机setting下还能看到对应应用,于是我“强行停用”,并选择“清除数据”,“清除缓存”,重启了以后,再次clean,run,success!歪歪扭扭的图库+相机应用出现在了桌面上。(PS:刚开始相机有不明原因的卡顿,重启了两次手机后,ok了——目前不知晓原理,也许与系统launch之间需要一点点磨合?!)