天天看点

camera编解码介绍1 概述 2  CameraSource.read过程涉及的类图结构 3 CameraSource.read的调用流程 4 总结

1 概述

camera 的录像分为三个过程:

  1. camera模块将从hal层的预览线程中,获取原始的未压缩的yvu视屏帧,通过回调函数传递到CameraSource模块
  2. OMXCodec模块将从CameraSource模块的read接口获取yuv视频帧拷贝到编码模块提供的输入端口的buffer列表中,编码模块从输入端口的buffer列表读取包含yuv的buffer、编码、然后送回到输出端口的buffer列表,供OMXCodec模块取回
  3. 从OMXCodec模块的read接口读取压缩编码后的h264帧,通过TS容器写到输出文件句柄上,得到TS流的文件

在这篇文章中,我们将集中讨论第一种情况,即CameraSource.read()接口的调用过程

2  CameraSource.read过程涉及的类图结构

camera预览线程CameraHardware::inPreviewThread在获取到yuv视频帧后,通过调用CameraHardware::frameCallbackNotifier函数,即最终调用到 CameraClient::dataCallbackTimestamp函数,将视频帧buffer通过ICameraClient binder发送给Camera::dataCallbackTimestamp函数,该函数又通过 ICameraRecordingProxyListener binder将视频帧对应的Imemory句柄转发到CameraSource::dataCallbackTimestamp函数。 而在CameraSource::read函数中,会将刚才收到的IMemory句柄对应的内存如下的处理: *buffer = new MediaBuffer(frame->pointer(), frame->size()); 以上语句中的pointer()函数会将IMemory句柄对应的内存映射到CameraSource所在的进程C地址空间,从而使CameraSource和CameraClient共享同一个yuv视频内存块。

camera编解码介绍1 概述 2  CameraSource.read过程涉及的类图结构 3 CameraSource.read的调用流程 4 总结

需要注意的是:yuv视频帧,是在CameraClient所在的进程分配的,而CameraClient和camera HAL是属于同一个进程的。

3 CameraSource.read的调用流程

camera编解码介绍1 概述 2  CameraSource.read过程涉及的类图结构 3 CameraSource.read的调用流程 4 总结

以上Camerasource.read过程,涉及到2次binder调用,在数据传递的过程中,只是传递的共享内存对应的句柄(Imemory),而不是传输实际的yuv内存数据,所以效率比较高。在Camerasource.read函数中,通过调用的Imemory的pointer函数,来讲预览用的内存映射到Camerasource.read所在进程,从而可以直接访问该块内存。

另外录像和预览是同一个CameraHardware::inPreviewThread线程,这样就可以在录像、预览、停止录像等之间无缝的快速切换。

4 总结

camera录像过程,涉及到模块比较多,有camera模块,编码模块,omx模块,容器模块,并且涉及大块数据在各进程之间的共享操作。所以会比较复杂,中间会频繁使用binder来进行进程的通讯。一个秘诀就是:循着binder的机制来查看程序的数据流,而binder机制中的Bpxxx(客户端),Bnxxx(服务器端),Ixxx(接口),则是跟踪程序流程的重要线索。

另外binder服务又分为知名服务,和匿名服务,像camera模块,就有个media.camera的知名服务,而meidaRecorder模块则属于meida.player的知名服务,而更多的则是匿名服务,匿名服务可以通过知名服务或是其他已知的匿名服务来传递。

详细的binder传递过程,可以参考binder的驱动相关的文章。

继续阅读