背景
id5a岖沛、id6平臺(tái)我們的相機(jī)暑始,對(duì)比相同平臺(tái)紅米6a和6的相機(jī),冷熱啟動(dòng)婴削,前后攝切換性能要差廊镜,對(duì)比競(jìng)品,我們期望優(yōu)化的比紅米6a和6的相機(jī)快10%.
問題分解
性能優(yōu)化的核心就是找到影響性能的hotspot,查找hotspot也是有套路的唉俗,首先要把相機(jī)啟動(dòng)流程分解出來嗤朴,一個(gè)階段一個(gè)階段分析。
相機(jī)的冷啟動(dòng)虫溜,可以分解如下幾步:
- AMS啟動(dòng)相機(jī)的Activity -> 相機(jī)的Activity收到onCreated消息 (可體現(xiàn)系統(tǒng)的性能)雹姊。
- onCreate begin -> onCreate end(主要是ui的加載)
- openCamera -> CameraOpened
- TextureView add -> SurfaceTexture created (Surface的創(chuàng)建時(shí)間)
- startPreview -> PreviewStarted
- setWindow -> PreviewCallback
Log如下:
01-01 12:01:57.099 794 3012 I ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.mediatek.camera/.CameraLauncher bnds=[150,976][290,1202] (has extras)} from uid 10064
01-01 12:01:57.169 8261 8261 D CamAp_QuickActivity: [ 0.000ms][BEGIN] onCreate
01-01 12:01:57.196 8261 8295 I CamAp_API1-Handler-0: [openCamera]+
01-01 12:01:57.217 532 2586 I mtkcam-dev1: [createSpecificCameraDevice1] dlopen libmtkcam_device1.so +
01-01 12:01:57.224 532 2586 I mtkcam-dev1: [createSpecificCameraDevice1] dlopen libmtkcam_device1.so -
01-01 12:01:57.259 532 2586 I mtkcam-dev1: [createSpecificCameraDevice1] - 0xe6a0ec00
01-01 12:01:57.260 532 2586 I mtkcam-dev1: 0[CameraDevice1Base::open] +
01-01 12:01:57.419 532 2586 I mtkcam-dev1: 0[CameraDevice1Base::open] Add new cameraId 0 - 0xe6a0ec00
01-01 12:01:57.419 532 2586 I mtkcam-dev1: 0[CameraDevice1Base::open] -
01-01 12:01:57.424 8261 8295 I CamAp_API1-Handler-0: [openCamera]-, executing time = 228ms.
01-01 12:01:57.537 8261 8261 D CamAp_QuickActivity: [367.294ms] [END] onCreate
01-01 12:01:57.542 8261 8261 D CamAp_QuickActivity: [ 0.000ms][BEGIN] onStart
01-01 12:01:57.546 8261 8261 D CamAp_QuickActivity: [ 3.762ms] [END] onStart
01-01 12:01:57.549 8261 8261 D CamAp_QuickActivity: [ 0.000ms][BEGIN] onResume
01-01 12:01:57.552 8261 8261 D CamAp_QuickActivity: isKeyguardLocked = false
01-01 12:01:57.552 8261 8261 D CamAp_QuickActivity: onResume --> onPermissionResumeTasks()
01-01 12:01:57.600 8261 8261 D CamAp_QuickActivity: [ 50.774ms] [END] onResume
01-01 12:01:57.685 8261 8294 I CamAp_API1-Handler-0: [setPreviewDisplay]+, pending time = 0ms.
01-01 12:01:57.686 8261 8294 I CamAp_API1-Handler-0: [setPreviewDisplay]-, executing time = 1ms.
01-01 12:01:57.700 8261 8294 I CamAp_API1-Handler-0: [startPreview]+, pending time = 0ms.
01-01 12:01:57.701 532 2586 W mtkcam-dev1: 0[CameraDevice1Base::initDisplayClient] NULL window is passed into...
01-01 12:01:57.701 532 2586 I mtkcam-dev1: 0[CameraDevice1Base::startPreview] +
01-01 12:01:57.720 8261 8261 I CamAp_TextureViewController: updatePreviewSize: new size (960 , 720 ) current size (0 , 0 ),mIsSurfaceCreated = false listener = com.mediatek.camera.common.mode.photo.PhotoMode$SurfaceChangeListener@a79ec89
01-01 12:01:57.735 532 2586 I mtkcam-dev1: 0[CameraDevice1Base::startPreview] - status(0)
01-01 12:01:57.736 8261 8294 I CamAp_API1-Handler-0: [startPreview]-, executing time = 36ms.
01-01 12:01:57.948 532 8363 I MtkCam/DCNode: [0::waitPreviewReady]wait for start preview done +
01-01 12:01:58.087 532 8363 I MtkCam/DCNode: [0::waitPreviewReady]wait for start preview done - , use 130 ms
01-01 12:01:58.053 8261 8261 D CamAp_TextureViewController: onSurfaceTextureAvailable surface = android.graphics.SurfaceTexture@2d48d1c width 720 height 960
01-01 12:01:58.056 8261 8294 I CamAp_API1-Handler-0: [setPreviewTexture]+, pending time = 0ms.
01-01 12:01:58.087 532 8363 I MtkCam/CamAdapter: (8363)[transitState] StateIdle --> StatePreview
01-01 12:01:58.089 532 2586 I MtkCam/DisplayClient: [setWindow] + window(0xe6a0ecf0), WxH=960x720, count(6), iNativeWindowConsumerUsage(256)
01-01 12:01:58.093 8261 8294 I CamAp_API1-Handler-0: [setPreviewTexture]-, executing time = 37ms.
01-01 12:01:58.279 8261 8295 D CamAp_PhotoDeviceController: [onPreviewFrame] mModeDeviceCallback = com.mediatek.camera.common.mode.photo.PhotoMode@feb2273
其中OnCreate begin -> onCreate end:花了367ms
01-01 12:01:57.169 8261 8261 D CamAp_QuickActivity: [ 0.000ms][BEGIN] onCreate
01-01 12:01:57.537 8261 8261 D CamAp_QuickActivity: [367.294ms] [END] onCreate
其中openCamera: 花了238ms
01-01 12:01:57.196 8261 8295 I CamAp_API1-Handler-0: [openCamera]+
01-01 12:01:57.424 8261 8295 I CamAp_API1-Handler-0: [openCamera]-, executing time = 228ms.
其中Surface Create: 花了333ms
01-01 12:01:57.720 8261 8261 I CamAp_TextureViewController: updatePreviewSize: new size (960 , 720 ) current size (0 , 0 ),mIsSurfaceCreated = false listener = com.mediatek.camera.common.mode.photo.PhotoMode$SurfaceChangeListener@a79ec89
01-01 12:01:58.053 8261 8261 D CamAp_TextureViewController: onSurfaceTextureAvailable surface = android.graphics.SurfaceTexture@2d48d1c width 720 height 960
其中startPreview:花386ms
01-01 12:01:57.701 532 2586 I mtkcam-dev1: 0[CameraDevice1Base::startPreview] +
01-01 12:01:58.087 532 8363 I MtkCam/CamAdapter: (8363)[transitState] StateIdle --> StatePreview
其中startWindow -> PreveiwCallback:花87ms
01-01 12:01:58.093 8261 8294 I CamAp_API1-Handler-0: [setPreviewTexture]-, executing time = 37ms.
01-01 12:01:58.279 8261 8295 D CamAp_PhotoDeviceController: [onPreviewFrame] mModeDeviceCallback = com.mediatek.camera.common.mode.photo.PhotoMode@feb2273
其中花時(shí)間的步驟,是2衡楞、3吱雏、4、5,主要ui加載瘾境,openCamera歧杏,surfaceCreated、startPreview寄雀。openCamera和startPreview花時(shí)間需要驅(qū)動(dòng)優(yōu)化得滤。ui加載和surfaceCreate需要上層看。
工具分析
traceView分析ui加載盒犹,發(fā)現(xiàn)沒有可優(yōu)化的懂更,現(xiàn)在加載的ui都是需要一進(jìn)去就要看見的眨业,不需要進(jìn)去看見的view,都使用viewStub延時(shí)加載處理了沮协,并且關(guān)于ui也優(yōu)化了好幾波龄捡。優(yōu)化空間比較小。不過針對(duì)冷啟動(dòng)慷暂,可以使用內(nèi)存常駐的方案聘殖,這樣實(shí)際上冷啟動(dòng)就是熱啟動(dòng)。主要原因是相機(jī)在手機(jī)啟動(dòng)時(shí)行瑞,收到啟動(dòng)廣播會(huì)啟動(dòng)一個(gè)服務(wù)奸腺,用于檢測(cè)是否溫度過高,服務(wù)拉起了相機(jī)應(yīng)用血久。內(nèi)存常駐后突照,此應(yīng)用就不被殺掉了。這樣啟動(dòng)速度優(yōu)化很大氧吐。
目前的方案:2G以上項(xiàng)目默認(rèn)使用內(nèi)存常駐方案讹蘑。
traceView教程
http://www.reibang.com/p/f81b20b9a7e2
https://developer.android.com/studio/profile/traceview
surface create優(yōu)化
現(xiàn)在主要的大頭就是Surface create優(yōu)化了。systrace分析創(chuàng)建surface過程筑舅,發(fā)現(xiàn)ArcFilter HandleThread一直在wait座慰。
systrace的教程
https://developer.android.google.cn/studio/command-line/systrace
查看代碼,是濾鏡等待arc算法引擎初始化和GL引擎初始化翠拣。這里的設(shè)計(jì)是有爭(zhēng)議的版仔,其實(shí)相機(jī)啟動(dòng)的時(shí)候并沒有開啟濾鏡,但是要初始化濾鏡的引擎心剥。做耗時(shí)benchmark:
01-02 01:22:07.991 23458-23554/? I/CamAp_TextureEnvExt: handleGlEnvInit(): Enter
01-02 01:22:07.991 23458-23458/? V/CamAp_TextureEnvExt: getCamSurfaceTexture:: in -1
01-02 01:22:08.090 23458-23554/? I/CamAp_TextureEnvExt: handleGlEnvInit(): Exit with bRet = EGL_SUCCESS
01-02 01:22:08.091 23458-23554/? I/CamAp_TextureEnvExt: handleArcFilterEngine(): init begin
01-02 01:22:08.095 23458-23458/? V/CamAp_TextureEnvExt: getCamSurfaceTexture:: ID=1
01-02 01:22:08.211 23458-23554/? I/CamAp_TextureEnvExt: handleArcFilterEngine(): init end engine = 0,prepareEngine=0
可以看出:初始化GLEnv需要99ms,初始引擎需要120ms.
優(yōu)化方案
這有兩種優(yōu)化方案:
- 啟動(dòng)時(shí)邦尊,不加載濾鏡引擎背桐,切換到濾鏡時(shí)加載优烧。后果是切換濾鏡時(shí)會(huì)卡一下,需要修改整個(gè)流程链峭,代碼修改量大畦娄。
- 分步初始化GLEnv和濾鏡引擎,理論上可以優(yōu)化120ms+,創(chuàng)建Surface和startPreview并行執(zhí)行弊仪。代碼改動(dòng)小熙卡,并且能達(dá)到優(yōu)化效果。
目前使用第二種方案励饵,代碼提交記錄:
http://192.168.10.10/#/c/213235/
前后切換速度優(yōu)化
前后切換速度對(duì)上層來說驳癌,主要有兩個(gè)方面影響,一是翻轉(zhuǎn)動(dòng)畫役听,一是高斯模糊颓鲜。翻轉(zhuǎn)動(dòng)畫使用高速相機(jī)測(cè)量表窘,只有9幀,平臺(tái)性能限制甜滨,有一種帶不動(dòng)的感覺乐严,對(duì)標(biāo)機(jī)也沒有,和產(chǎn)品溝通去掉衣摩。 能優(yōu)化的就是高斯模糊了昂验。
高斯模糊的耗時(shí)benchmark:
01-02 02:00:21.636 8089-8089/? I/CamAp_GaussianBlur: GaussianBlur,create render:42
01-02 02:00:21.636 8089-8089/? D/CamAp_GaussianBlur: preview width 750 height 1500
01-02 02:00:21.731 8089-8089/? I/CamAp_GaussianBlur: getPreview bitmap spent time: 125
01-02 02:00:21.821 8089-8089/? I/CamAp_GaussianBlur: blurBitmap,render bitmap:112
整個(gè)高斯模糊流程大概需要花279ms,主要耗時(shí)是getPreview和blurBitmap艾扮,還有init每次都要做既琴。
優(yōu)化方案
init需要花40多少ms,只做一次泡嘴。getPreview呛梆,對(duì)于高斯模糊,我們不需要一張清晰的圖片磕诊,反正后面也要做模糊填物。getPreview時(shí),我們?cè)O(shè)置一個(gè)采樣率霎终,采樣質(zhì)量降低16倍滞磺,做高斯模糊時(shí),我們?cè)O(shè)置一個(gè)較小模糊半徑因子莱褒,目前為5击困,這樣做模糊的速度快,模糊效果好广凸。
優(yōu)化后的耗時(shí)benchmark:
01-02 02:14:15.628 20947-20947/? D/CamAp_GaussianBlur: preview width 750 height 1500
01-02 02:14:15.632 20947-20947/? I/CamAp_GaussianBlur: getPreview bitmap spent time: 4
01-02 02:14:15.636 20947-20947/? I/CamAp_GaussianBlur: blurBitmap,render bitmap:4
代碼提交記錄:
http://192.168.10.10/#/c/213235/
熱啟動(dòng)優(yōu)化
熱啟動(dòng)優(yōu)化阅茶,和對(duì)比機(jī)不同的是,在預(yù)覽沒有出來之前谅海,我們做了一個(gè)高斯模糊的蓋板脸哀。和產(chǎn)品溝通需要去掉,去掉蓋板比較容易扭吁。引發(fā)兩個(gè)問題需要解決撞蜂。
- TextureView沒有被銷毀,會(huì)保留上一幀侥袜。主要表現(xiàn)熱啟動(dòng)會(huì)閃上一幀蝌诡。
- framework會(huì)有一個(gè)screenshot界面,同樣會(huì)閃上幀枫吧。
解決方案:
- 在pause時(shí)浦旱,把TextureView的alpha設(shè)置為0,第一幀上來,再把a(bǔ)lpha設(shè)置1九杂,讓其顯示颁湖。
- 應(yīng)用層關(guān)掉screenshot.
代碼提交記錄:
http://192.168.10.10/#/c/215036/
http://192.168.10.10/#/c/214142/
驅(qū)動(dòng)優(yōu)化
關(guān)于openCamera和startPreview優(yōu)化代兵,底層優(yōu)化了3a算法、加入了fastae和使用speed mode模式爷狈。詳情可以咨詢彭葉斌同學(xué)植影。