該項目場景是方便用戶在廚房也能繼續經過智能平板觀看電視節目。咱們須要開發一個應用用來接收電視傳過來的音視頻數據,而後將音視頻數據傳輸到平板端進行播放,用戶能經過平板來操控電視。git
實際上,開發過程當中,還能挖掘出了下面幾個隱藏的需求。github
項目中視頻方面採用的技術邏輯爲: 咱們還須要考慮不少非功能性的需求。具體來說,我總結了如下幾個比較重要的方面。算法
包括產品的易用性和代碼的易用性。產品的易用性是指:用戶不須要花太多時間思考就能上手應用,老小皆宜。代碼的易用性是指:框架是否易集成、易插拔、跟業務代碼是否鬆耦合、提供的接口是否夠靈活等等,都是咱們應該花心思去思考和設計的。markdown
咱們但願應用自己的代碼執行效率,對系統沒有太多性能上的影響。音視頻播放一方面,咱們但願它是低延遲的,音視頻是同步的;另外一方面,咱們但願應用自己對內存的消耗不能太大。這塊後期需認真思考。網絡
是指在不修改或儘可能少修改代碼的狀況下添加新的功能,即符合開閉原則。在增長一些新的視頻數據的獲取方式、音頻獲取方式、或者編碼方式的時候,不需改動原有邏輯。框架
設備配對:818板卡發送NSD攜帶port,PAD端經過掃描同一ip網段下的該port設備,經過CRCP協議實現配對
ide
應用鑑權初步方案:1.818板卡未配對,正常發送帶port的NSD服務;2.當有設備配對後,818用配對設備的DeviceId經算法加密後發送加密port的NSD服務,PAD端有重試機制,第一次直接鏈接該port,失敗後使用算法解密後嘗試鏈接。鏈接成功之後默認配對
性能
818視頻採集、解碼及播放:Camera2 + MediaCodeC + SurfaceTexture,編碼格式採用h264
ui
818音頻採集、解碼及播放:AudioRecord + MediaCodec/OpusLib +AudioTrack,編碼格式爲Opus。 VS AAC:在編碼延時方面。首先,Opus是由兩個編解碼器Silk和Celt融合而成。Celt 僅編碼延時方面是優於AAC 的,合併成Opus後有所增加,但仍是低於AAC。 質量方面:Celt 最初的質量不如 AAC。在成爲 Opus 的一部分後,犧牲了一部分的延時,增長了一些新技術以後,質量與 AAC 至關,甚至更好一些。在壓縮率方面,Opus裏共有32種模式用來處理不一樣種類的信號,opus在碼率和音質上的確是有優點的。(參考 :https://zhuanlan.zhihu.com/p/66719842)
this
TVBOX喇叭進行播放: 當PAD中止電視回傳 且 本地有媒體播放時,經過BlueTooth藍牙配對
PAD遙控器指令發送:PAD 與818間經過CRCP傳輸遙控碼,818與3553之間經過AIDL傳遙控碼
總體工做流程
1.Camera2採集視頻數據:
整個過程使用Camera2來獲取數據,獲取的數據經過MediaCodec編碼,使用H264協議,接收端接收到數據以後解碼,而後經過TextureView渲染,大概是這麼一個流程,下面記錄下實現過程。
1.相機初始化 獲取可用的相機列表、相機相關的屬性
String[] cameraIdList = mCameraManager.getCameraIdList();
CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(cameraId);
複製代碼
2.在打開相機以前先,先要去獲取相機支持的最接近的預覽尺寸,而後要實例化一個ImageReader,用來接收Camera2的可用數據。這些作完以後,須要監測TextureView是否可用,不可用先設置setSurfaceTextureListener監聽,可用以後再來打開相機。 添加接收數據回調的Target Surface
mPreviewSize = getBestSupportedSize(new ArrayList<Size>(Arrays.asList(map.getOutputSizes(SurfaceTexture.class))));
mImageReader.setOnImageAvailableListener(this, mBackgroundHandler);
複製代碼
3.創建Camera2預覽會話,經過RepeatingRequest()進行連續請求
private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice cameraDevice) {
Camera2TextureView.this.mCameraDevice = cameraDevice;
createCaptureSession();
}
mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
//添加接收數據回調的Target Surface
mPreviewRequestBuilder.addTarget(mWorkingSurface);
mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
mCaptureSession.setRepeatingRequest(mPreviewRequest, null, mBackgroundHandler);
複製代碼
4.經過imageReader 讀取相機數據。因爲Camera2的yuv數據獲取到數據須要本身手動拼接,因此這裏是和Camera1不一樣的,獲取到的數據拼接成nv21,須要轉化成nv12,由於MediaCodec不支持nv21。採集到數據以後,經過mediaCodec進行編碼操做。
public void onImageAvailable(ImageReader reader) {
Image image= reader.acquireNextImage();
複製代碼
MirrorAudioManager是上帝類,持有AudioRecorder 和AudioEncoder的
1.設備配對時鑑權