主題
記錄安卓端上傳模塊優(yōu)化的經(jīng)歷。通過本次分享迎罗,咱們可以知道
- 一個文件經(jīng)歷了幾個步驟才能從手機(jī)上傳到服務(wù)端
- 能知道媒體文件壓縮的原理
圖片壓縮源碼https://github.com/Curzibn/Luban
視頻壓縮源碼https://github.com/fishwjy/VideoCompressor
整個優(yōu)化經(jīng)歷了兩個階段
- 第一階段是上傳模塊重構(gòu),并且通過UI和數(shù)據(jù)的分離洼畅,提升了擴(kuò)展性坯临,逐步被運(yùn)用到產(chǎn)品的各個模塊中
- 第二階段是上傳尺寸的優(yōu)化,通過對視頻文件的壓縮坟岔,大幅減少用戶的上傳等待時間。
chapter 1.上傳框架重構(gòu)
評估現(xiàn)有模塊表現(xiàn)
- 使用中低配置手機(jī)運(yùn)行apk摔桦,查看上傳模塊實(shí)際表現(xiàn)
- 使用Charles抓包工具社付,觀察每個上傳文件體積是否被壓縮到合理范圍、對上傳模塊發(fā)送的http請求按照功能對其分類,檢查是否可以合并同類請求
- 退出上傳鸥咖,查看上傳后續(xù)步驟是否被停止燕鸽;大文件重新上傳是否跳過已上傳的數(shù)據(jù)塊
- 查看上傳后的結(jié)果是否正常播放、是否失真啼辣、音頻異常
上傳模塊現(xiàn)存問題
- UI和上傳代碼耦合在一起啊研,難以拓展維護(hù)
- 停止上傳后仍然繼續(xù)上傳,說明流程控制有問題
- 在上傳時熙兔,對每個文件會進(jìn)行尺寸壓縮悲伶、計算md5值艾恼,比較費(fèi)時
- 每個文件上傳前都會發(fā)送一次存在校驗(yàn)(根據(jù)文件md5值)住涉,導(dǎo)致在上傳的場景中會發(fā)送多次http請求校驗(yàn)文件存在
- 視頻文件沒有做壓縮,導(dǎo)致上傳費(fèi)時
整體設(shè)計思路
- 數(shù)據(jù)UI分離:使用觀察模式钠绍,抽離UI部分代碼舆声。使用弱引用設(shè)置觀察者,避免生命周期不一致引起的內(nèi)存泄漏柳爽。
- 費(fèi)時操作前置:在選擇圖片的步驟媳握,開啟異步線程壓縮圖片、計算md5磷脯,將費(fèi)時操作提前處理掉(此步驟在mx4 pro上處理拍照的圖片耗時100~200ms蛾找,基本上選擇圖片后就已經(jīng)完成好了計算)
- 將文件上傳成功的md5值保存在內(nèi)存中,避免重復(fù)處理赵誓。
- 分次請求合并:向服務(wù)端開發(fā)者申請批校驗(yàn)的接口打毛,將多個文件存在的http請求被合并成一個。
優(yōu)化后 邏輯UML
文件切片
文件切片將一個大文件切成若干小文件進(jìn)行上傳俩功,在上傳失敗的情況下幻枉,可以跳過已上傳的小文件。
切片代碼底層使用JDK的RandomAccessFile
對文件提供數(shù)據(jù)讀取
經(jīng)測試诡蜓,上傳的瓶頸在于上行帶寬熬甫,所以切片、上傳時單線程任務(wù)蔓罚,不會出現(xiàn)10個切片一起上傳的情況椿肩。
切片目前設(shè)定為10MB一片,上傳時豺谈,把當(dāng)前的塊的數(shù)據(jù)讀取到內(nèi)存中進(jìn)行上傳
切片步驟
- 對文件md5計算郑象,向服務(wù)端校驗(yàn)文件是否已存在,是則提前結(jié)束
- 對文件進(jìn)行切片核无,計算每片的md5值用于校驗(yàn)是否已上傳扣唱。比如38mb的視頻,限定每片最大10mb,切出4片噪沙,最后一片8mb炼彪,其余10mb。
FileChannel fc = new RandomAccessFile(mSourceFile, "r").getChannel();
MappedByteBuffer byteBuffer;
for (int i = 0; i < mBlockCount; i++) {
long leftBlockSize = Math.min(mSourceFile.length() - i * mBlockSize, mBlockSize);
byteBuffer = fc.map(FileChannel.MapMode.READ_ONLY, i * mBlockSize, leftBlockSize).load();
mResultArray.add(new BlockInfoModel("", MD5Util.md5(byteBuffer), i));
}
fc.close();
- 批校驗(yàn)文件的切片md5值正歼, 記錄沒有被上傳過的切片下標(biāo)辐马,循環(huán)從源文件讀取對應(yīng)數(shù)據(jù)切片進(jìn)行上傳。切片數(shù)據(jù)流讀到內(nèi)存中性能最佳局义,但是需要謹(jǐn)慎考慮OOM問題喜爷;數(shù)據(jù)流保存到磁盤中,再循環(huán)每次1MB的讀取比較穩(wěn)健萄唇,但是性能稍差檩帐。本次重構(gòu)提供了這兩種切片方式都可以選擇
- 所有數(shù)據(jù)切片上傳成功后,向服務(wù)端發(fā)起一次文件合并請求另萤,成功則結(jié)束湃密,否則跳到步驟3。
chapter 2.媒體壓縮
對于媒體資源來說四敞,壓縮就是在保證用戶體驗(yàn)的情況下泛源,盡可能地抹去用戶感官之外的細(xì)節(jié),達(dá)到降低文件尺寸的目的
1.音頻的無損格式ape忿危、flv 壓縮到有損格式的Mp3达箍,就是抹去了人聽覺之外的音頻細(xì)節(jié)
2.圖片視頻經(jīng)過壓縮,雖然放大N倍看細(xì)節(jié)會變得模糊铺厨,但是正常瀏覽下是可以接受的
舉個例子
針對 1920*1080的屏幕截圖缎玫,經(jīng)過壓縮后尺寸不變,但是降低采樣率努释,文件體積從1MB降低到了200KB
圖片壓縮
壓縮算法參考魯班
通過等比例降低圖片的采樣率碘梢、分辨率、壓縮質(zhì)量等關(guān)鍵因素伐蒂,大幅度減少輸出的像素點(diǎn)數(shù)量煞躬,達(dá)到降低圖片的體積的目的
在不影響瀏覽體驗(yàn)的前提下,能很大比例壓縮圖片體積
視頻壓縮
通過降低視頻的分辨率逸邦、碼率等關(guān)鍵因素恩沛,降低視頻的體積。
壓縮方案可選1:第三方so庫FFmpeg
軟解 2:使用安卓原生MediaCodec
硬解
因?yàn)閴嚎s效率缕减、引入體積等問題雷客,我們選擇了MediaCodec
方案
我們采用的壓縮策略是分辨率450*800,碼率是1.5M
在選擇微信作為對比標(biāo)桿的情況下桥狡,我們達(dá)到了這個標(biāo)準(zhǔn)
視頻壓縮UI
總結(jié)
通過這兩個階段的重構(gòu)搅裙,安卓端的上傳模塊初步形成了一個完整的體系皱卓,能夠滿足產(chǎn)品的使用需求,被廣泛的應(yīng)用到各個產(chǎn)品線的業(yè)務(wù)模塊中部逮。
備注
碼率
碼率是數(shù)據(jù)傳輸時單位時間傳送的數(shù)據(jù)位數(shù),一般我們用的單位是kbps即千位每秒娜汁。
通俗一點(diǎn)的理解就是取樣率,單位時間內(nèi)取樣率越大兄朋,精度就越高掐禁,處理出來的文件就越接近原始文件
1920x1080分辨率的視頻,碼率應(yīng)該在8Mb以上颅和。
1080x720的分辨率傅事,應(yīng)該在5Mb左右
720x576分辨率,應(yīng)該在3Mb左右
640x480分辨率峡扩,應(yīng)該在1.5Mb左右
320x240的分辨率蹭越,應(yīng)該在600Kb左右。