该项目场景是方便用户在厨房也能继续经过智能平板观看电视节目。咱们须要开发一个应用用来接收电视传过来的音视频数据,而后将音视频数据传输到平板端进行播放,用户能经过平板来操控电视。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.设备配对时鉴权