最近開始做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之間需要一點點磨合?!)