/**
為資溪等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及資溪網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為成都做網(wǎng)站、網(wǎng)站建設(shè)、資溪網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會得到認(rèn)可,從而選擇與我們長期合作。這樣,我們也可以走得更遠(yuǎn)!
* Android視頻聊天
* 1、初始化SDK 2、連接服務(wù)器、 3、用戶登錄;4、進(jìn)入房間;5、打開本地視頻;6、請求對方視頻
*/
public class VideoChatActivity extends Activity implements AnyChatBaseEvent
{
private AnyChatCoreSDK anychat; // 核心SDK
private SurfaceView remoteSurfaceView; // 對方視頻
private SurfaceView localSurfaceView; // 本地視頻
private ConfigEntity configEntity;
private boolean bSelfVideoOpened = false; // 本地視頻是否已打開
private boolean bOtherVideoOpened = false; // 對方視頻是否已打開
private TimerTask mTimerTask; // 定時器
private Timer mTimer = new Timer(true);
private Handler handler; // 用Handler來不間斷刷新即時視頻
private ListString userlist = new ArrayListString();//保存在線用戶列表
private int userid; // 用戶ID
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_chat);
remoteSurfaceView = (SurfaceView) findViewById(R.id.surface_remote);
localSurfaceView = (SurfaceView) findViewById(R.id.surface_local);
configEntity = ConfigService.LoadConfig(this);//加載視頻通話設(shè)置
loginSystem();// 初始化SDK 連接服務(wù)器
mTimerTask = new TimerTask(){
public void run(){
Message mesasge = new Message();
handler.sendMessage(mesasge);
}
};
mTimer.schedule(mTimerTask, 1000, 100);
handler = new Handler(){
@Override
public void handleMessage(Message msg){
VideoChat();// 不間斷顯示即時視頻通話畫面
super.handleMessage(msg);
}
};
}
? 本文之所以有必要編寫并作記錄,主要原因是因為在工作中開發(fā)出一個萬能的自定義camera預(yù)覽控件之后,本是一個提高效率以及提供一個強(qiáng)大能力的控件,但是產(chǎn)品并不能理解這個萬能控件存在的意義,產(chǎn)品無法與技術(shù)設(shè)計相結(jié)合的理解使用;并且發(fā)現(xiàn)我們的智能業(yè)務(wù)部Camera自定義預(yù)覽技術(shù)雖然是使用多年,但是我們并沒有真正的形成規(guī)范,由于產(chǎn)品在不能夠理解系統(tǒng)平臺(Android/iOS)給產(chǎn)品和研發(fā)帶來了什么,導(dǎo)致產(chǎn)品可能會出現(xiàn)在不理解系統(tǒng)平臺以及系統(tǒng)知識的情況下,臆想產(chǎn)品所謂的形態(tài);當(dāng)產(chǎn)品設(shè)計脫離了系統(tǒng)平臺所支持的技術(shù)點以及設(shè)計的初衷,就會導(dǎo)致回歸問題的時候,出現(xiàn)不必要的討論,其根結(jié)就是一點:“信息不同步,知識不同步”。
? ? 所以,為了提高效率,就采用記錄和分享的方式,嘗試性推動產(chǎn)品、測試、研發(fā)三者對工程與架構(gòu)的同步理解,更深的懂得程序架構(gòu)設(shè)計意義,嘗試性通過信息同步的方式,在一個統(tǒng)一的知識儲備的平臺下,共同完成一個更高效,和高品質(zhì)的工程產(chǎn)品。(為了能夠讓非技術(shù):產(chǎn)品設(shè)計,以及測試都能夠理解,所以,使用了更多的白話解釋)
? ? 附:強(qiáng)大靈活的FsCameraTextureView(第一版,自適應(yīng)截?。?第二版本版本:自適應(yīng)展示)
? ? 首先,拋出幾個問題,
? 1)什么是攝像頭支持的previewSize?
? 2)什么是視頻或者圖片的pictureSize?
? 3)? 如何獲取和查看攝像頭支持的PreViewSize 和PictureSize ?
? 4)手機(jī)預(yù)覽所見的區(qū)域SurfaceView(TextureView)與camera 的previewSize的關(guān)系是什么?
? 5)為什么會設(shè)計了兩種預(yù)覽方式view,兩種預(yù)覽方式都會有什么樣子的效果呢?
一,概述
通過Android Camera拍攝預(yù)覽中設(shè)置setPreviewCallback實現(xiàn)onPreviewFrame接口,實時截取每一幀視頻流數(shù)據(jù)(簡單說來,就是通過設(shè)置一個接口,接收系統(tǒng)回調(diào)通知我們的每一幀數(shù)據(jù))
二,知識點
1, camera支持的格式:
2,拍照流程
3,camera權(quán)限
三,Android Camera中PreviewSize、 PictureSize、 SurfaceView(TextureView)之間的關(guān)系
? ? 1,PreviewSize:
? ? ? 相機(jī)預(yù)覽時候的能支持的尺寸,簡單的說一下,就是預(yù)覽的大小,也就是拍照前能夠看到的圖片大小。(通過Android手機(jī)相機(jī)可以試一下,這個參數(shù)設(shè)置不同,同樣的焦距下,拍攝桌子上一個固定距離的東西,看到的視野會不同)
? ? ? 相機(jī)的預(yù)覽尺寸,不能隨意的設(shè)置值,只能通過camera的parameters的getSupportedPreviewSizes方法,獲取支持的預(yù)覽尺寸列表,并從列表中選擇一個設(shè)置在parameters中。(通俗簡單的說就是,獲取camera中能夠支持的預(yù)覽大小合集,如果你想要查看某個預(yù)覽對應(yīng)的尺寸,就把該尺寸設(shè)置到camera的屬性中即可,則camera會返回相對應(yīng)尺寸的預(yù)覽數(shù)據(jù)流提供顯示)。
? ? 2,PictureSize :
指的是拍照之后,最終拍攝到的圖片大小,也就是圖片的質(zhì)量。圖片尺寸同樣也只能從支持的列表中選取一個設(shè)置。 調(diào)用camera的takePicture方法(拍照)后,獲得拍照的圖像數(shù)據(jù),注意picturesize和previewsize的寬高比也要保證一致,否則獲取的圖片會將preview時的圖像裁剪成picturesize的比例。 previewsize的分辨率,只會影響預(yù)覽時的分辨率,不會影響獲取圖片的分辨率,所以preview只是確定了圖像的取景最大范圍。最終圖片的分辨率是由picturesize來決定。 所以,最好的設(shè)置方法,例如:previewsize為1280*720,picturesize為2560*1440。(由于我們沒有拍照業(yè)務(wù),目前這個知識,不做深究)
? ? 3,SurfaceView(TextureView)
? ? ? 用于展示camera預(yù)覽圖像的view,就是將preview獲得的數(shù)據(jù),放在這個view上。所以如果preview的寬高比和SurfaceView的寬高比不一樣,就會導(dǎo)致看到的圖像拉伸變形。圖像拉伸變形解決的辦法:
? ? ? (1)就是在確定preview的分辨率后,重新設(shè)置SurfaceView寬高;
? ? ? (2)如果SurfaceView寬高定死,則需要獲取一個比例適合SurfaceView尺寸的PreviewSize 的preview,盡量小的裁剪,然后填充在SurfaceView中。
? ? 4,利用圖片的顯示方式,理解Preview與SurfaceView(TextureView)顯示關(guān)系
? ? ? ImageView (UI上面設(shè)計的一個控件)與圖片bitmap 的關(guān)系,比如限定死一個ImageView的大小,但是圖片與ImageView尺寸不一致,就會有幾種方案,首先選取一張長方形1920*1080的圖片,ImageView就是紫色部分,無論長寬比都比ImageView要大。
圖片適配例1:拉伸填充ScaleType.FIT_XY :雖然被全部填充,但是整個圖片為了適配圖片已經(jīng)扭曲,失真,圖片縮放到控件大小,完全填充控件大小展示。
圖片適配例2:等比例裁剪填充ScaleType.CENTER_CROP ,因為在該模式下,圖片會被等比縮放直到完全填充整個ImageView,并居中顯示。該模式也是最常用的模式了。如圖可以看到,圖片的高度是能完全展示出來的,但是左右部分被進(jìn)行了裁剪,并沒有完全顯示。
圖片適配例3 :? ScaleType.CENTER_INSIDE,此模式,用以完全展示圖片內(nèi)容為目的。圖片將被等比縮放到能夠完整展示在ImageView中并居中,如果圖片大小,小于控件尺寸,那么就直接居中展示該圖片
? ? ? ? 圖片適配ImageView方式還有很多,就不一一列舉,這三種已經(jīng)足夠重要,為什么講解camera預(yù)覽,卻穿插了圖片的適配,其實可以這么理解,camera的preview就是由多張圖片組成,不斷的像幀動畫一樣變化,而SurfaceView就是一個載體,相當(dāng)于ImageView,業(yè)務(wù)中定死了SurfaceView的大小之后,被動的承載你選擇的previewSize,來展示camera的Preview,你可以選擇類似于前面三種例子來理解preview的填充,以下會舉例說明preview的填充策略選擇有哪幾種方式,我們會采用哪種方式:
? ? 1)拉伸填充,自適應(yīng)view,不可取,比如:手機(jī)的SurfaceView是整個手機(jī)的屏幕尺寸(全屏填充),或者任意尺寸比例的surfaceView,使用這種方式,就如同(圖片適配例1)的方式,導(dǎo)致視頻扭曲,拉伸。
? ? 2)等比例裁剪填充,目前我們項目中,采用的就是這種方式,并且提供給很多三方使用,已經(jīng)成為一種獨立,并且穩(wěn)定的技術(shù)實現(xiàn)自定義view,簡單說一下視頻的適配策略方式,SurfaceView隨便由業(yè)務(wù)方,自定義寬度大小,比如業(yè)務(wù)方選擇了1900*1000的SurfaceView, 我們的適配過程是:(1)從PreviewSize列表中選取最接近SurfaceView尺寸的PreviewSize(假設(shè)該攝像頭,只支持1920*1080,和320*640),1920*1080最接近,所以被獲?。?此處展示一下蹩腳的英文Try to find an size match aspect ratio and size,嘗試找到縱橫比與view大小比適中的一個尺寸)(2)等比例裁剪填充到SurfaceView,首先我們設(shè)計的邏輯是,先選取一個縮放比例,假設(shè)等比例1920的圖片按照SurfaceView的寬度等比例縮小到1900,而為了不讓Preview失真,則高度1080等比例縮小的值是1068.75(等比例方程式,這里就不重復(fù)初中的知識,請自行計算),所以圖片被壓縮成為1900*1068這個尺寸,依舊保證圖片完整,并且不失真。(3)將等比例縮減的圖片,1900*1068進(jìn)行顯示在1900*1000的SurfaceView中,就會有一種效果類似(圖片適配例2),寬度全部展示,高度被裁剪。(如同? 圖片適配例2中左右部分裁剪一樣的道理)? ? ? ? ? ? ? ? ? ? ? ?
? ? ? 3)完全展示camera內(nèi)容的縮放填充(類似圖片適配例3),我們打開任意一部手機(jī)的camera,預(yù)覽圖像都沒有全屏幕展示,類似拍照功能,所見即所得,PreviewSize是多少,就顯示什么樣子的比例尺寸,以及最后生產(chǎn)的照片比例就是多少,我們的自定義view,也可以隨意設(shè)置大小,此模式下,用以完全展示camera內(nèi)容為目的。Preview將被等比縮放到能夠完整展示在SurfaceView中并居中,但是可能會有部分位置無法填充(類似圖片適配例3顯示效果)。
(該方式只是進(jìn)行了技術(shù)儲備,由于沒有業(yè)務(wù)場景設(shè)計,所以沒有使用,目前只是儲備了這樣的自定義控件)
四,靈活的自定義TextureView預(yù)覽控件? ? ? ?
? ? FsCameraTextureView(第一版,自適應(yīng)截?。旱缺壤眉籼畛?,方式(適配方式2),采用前面說的適配方式2,而產(chǎn)出的一種自定義view,2019年5月產(chǎn)出至今,在金融APP,以及商城的app中使用,經(jīng)過逐步優(yōu)化,和多版本檢驗,目前該控件,擁有以下特點:? 1)穩(wěn)定:目前各個使用場景,均無邏輯崩潰,內(nèi)存泄漏,線程等任意問題; 2)靈活:隨意設(shè)置預(yù)覽view的尺寸大小,自適應(yīng)任意業(yè)務(wù)設(shè)計;不僅僅滿足刷臉業(yè)務(wù),并且滿足任意相機(jī)預(yù)覽業(yè)務(wù)方使用; 3)提高效率,減輕工作量:使用簡單,操作步驟簡潔,接入只需要兩步;減輕接入端,或者想要使用相機(jī)預(yù)覽的業(yè)務(wù)的工作量,不需要重復(fù)造車,并且安全穩(wěn)定。
? 輸出的業(yè)務(wù)方有(經(jīng)不完全統(tǒng)計):(目前業(yè)務(wù)為保密進(jìn)行公網(wǎng)保密處理)1)**創(chuàng)新科技業(yè)務(wù)部-區(qū)塊鏈部門 2)泰國人臉識別業(yè)務(wù)SDK3)S D**Bank 人臉業(yè)務(wù)4)核驗身份證業(yè)務(wù)5)HT**Bank 人臉業(yè)務(wù) 6)**云,商業(yè)平臺部門
? FsAllPreviewCameraTextureView(技術(shù)儲備版,全預(yù)覽模式顯示):完全展示camera內(nèi)容的縮放填充,采用前面說的(適配方式3)適合拍照相關(guān)的業(yè)務(wù)使用,優(yōu)點同樣是,外部業(yè)務(wù)隨意改變view大小,可以自適應(yīng)view,由于目前沒有業(yè)務(wù)方使用,暫時做儲備,不深入講解。
如果可以控件開源成功,后期,我將開源這兩個控件,讓更多的使用方使用,我們也希望共同技術(shù)進(jìn)步,提高工程產(chǎn)出的使用能力。
預(yù)計下一次分享內(nèi)容是(臨時命名)
1)人臉核驗內(nèi)存和線程爆表到泄漏為零
2)分享七年前參于的Scrum(如何提高崗位間效率所定制的敏捷開發(fā)過程)
本文參考:
1、使用FFMpeg進(jìn)行視頻采集,使用Live555進(jìn)行RTP傳輸,使用VideoView進(jìn)行播放。
csdn提到:重載FrameSource,寫一個服務(wù)類,可以從FrameSource的派生類讀取幀數(shù)據(jù),轉(zhuǎn)發(fā)給live555.
評價:本方案大型訪問量大的不行,少量連接比如100以內(nèi)的可以。
2、用gstreamer完成采集、編碼、組播??蛻舳耸褂肰ideoView進(jìn)行播放。
評價:本方案優(yōu)點為可以實現(xiàn)大訪問量。缺點是基本從底層架構(gòu),代碼量比較大。
3、使用FFmpeg進(jìn)行視頻采集,使用ffserver進(jìn)行視頻轉(zhuǎn)發(fā),客戶端使用VideoView播放。
評價:優(yōu)點是實現(xiàn)簡單、容易演示,缺點是實時性不好以及用戶量大不行。