基于AndroiidM的USB DVR的源码架构浅析,主要讲述大概流程,以便于分析问题。

APP层

源码路径:

AndroidM/vendor/mediatek/proprietary/packages/apps/DVR

主要 DVR操作的两个类 FrontView.javaMainActivity.java

1、 FrontView 继承了 SurfaceView 用于摄像头视频的预览,把 SurfaceView 通过调用 JNI 的 DVR.java 类对象方法 setFrontSurface(SurfaceHolder sh) 传入到底层,交给底层来实现在 SurfaceView 上的视频渲染。FrontView在主布局中被调用。

2、 MainActivity 中通过调用 JNI 的 DVR.java 类对象,实现了众多功能,包括解析度的改变(720p,1080p),录制时长的改变(10mins,5mins,3mins),视频预览的开始与停止,视频的录制,快照的截取,紧急录像,设置摄像头时间、坐标等等。主要在于实例化了一个 JNI 层的 DVR 类对象来调用底层的对于摄像头基本功能的实现。
应用设置 Handler 用来接收 framework 返回的消息,类型是DVRNativeEvent,需 要 注 意 接 收 到 DVRNativeEvent.DVR_UI_MSG_PREVIEW_ERROR等错误时需要做出容错措施。用到的DVR框架的主要方法为:DVR.SetFrontSurfaceDVR.StartRecordDVR.StopRecordDVR.StartPreviewDVR.StopPreview

FrameWork 层

源码路径:

AndroidM/vendor/mediatek/proprietary/frameworks/base/camera/dvr/…

主要的两个类为DVR.javaandroid_media_DVR.cpp

1、DVR.java中加载了drv_jni库,封装了几个关于摄像头属性的类,坐标、时间、VideoInfo、SinkInfo。根据摄像头底层功能函数定义了各个native方法,然后再用 java 方法把这些native方法再次封装起来,提供给上层对DVR类实例化后的调用。
2、android_media_DVR.cpp中定义各个函数用于对底层 dvrav.cpp 中的对于摄像头基本功能函数进行封装,然后将这些封装好的方法和 DVR.java中native方法映射起来。

Hardware层

源码路径:

AndroidM/vendor/mediatek/proprietary/hardware/mtkcam/dvr

主要的三个类为dvrav.cppPreviewRenderer.cppdvr_preview.cpp
1、 dvrav.cpp

该类被 JNI 层调用的方法最终通过 sendMsg 的方式来分别实现各个功能。在这个文件中,相当于底层与 JNI 的接口,所有的最终实现是通过这个文件中的方法分发下去具体各个类的函数中去实现功能函数。例如:start_preview,JNI 调用到 dvrav.cpp 中的 DVR_StartPreview()方法,通过 Msg 中的枚举量找到具体实现的地方,然后再分发下去调用 dvr_preview.cpp中的DVR_Preview_StartPreview(),在此方法中实例化一个结构体中PreviewRenderer对象mRenderer用于对视频的渲染。

2、 PreviewRenderer.cpp 该类主要功能是用MediaCodec对视频流数据进行硬解码操作,并且在SurfaceView上渲染视频。改变视频流格式的解码格式主要通过对MediaCodec进行配置,目前使用的是video/avc"(H.264)格式。

这篇文章有介绍使用MediaCodec硬解码MJPEG格式帧可能会遇到的问题:MediaCodec硬解码

3、dvr_preview.cpp
该类中函数主要功能是操作PreviewRenderer类对象,配置并初始化MediaCodec,对PreviewRenderer类对象中方法的实现与一些功能拓展。围绕创建实例,释放实例,获取预览实例,创建渲染Looper,释放渲染Looper,设置SurfaceView,开始和停止预览这几个功能。

底层实现中还包括了,在dvr_audiorecord.cpp中实现了关于音频记录的功能,在dvr_avimuxer.cpp中实现了音频和视频的整合,在dvr_recorder.cpp中实现了视频的记录和紧急视频的录制,在dvr_snapshot.cpp 实现视频快照的截取并保存等等,DVR中所有的基本都由底层来实现,上层只是调用。

V4L2驱动层

获取 USB 记录仪视频:采用 linux 下的V4L2(video for linux 2)标准接口,dvr_v4l2.hdvr_v4l2.cpp

open 设备节点(/dev/video21)拿的数是 H.264。

int cameraFd;
cameraFd = open("/dev/video0", O_RDWR, 0);```

打开视频设备后,可以设置该视频设备的属性,例如裁剪、缩放等。这一步是可选的。在Linux编程中,一般使用ioctl函数来对设备的I/O通道进行管理:

extern int ioctl (int __fd, unsigned long int __request, ...) __THROW;

__fd:设备的ID,例如刚才用open函数打开视频通道后返回的cameraFd;

__request:具体的命令标志符。

在进行V4L2开发中,一般会用到以下的命令标志符:

VIDIOC_REQBUFS:分配内存
VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
VIDIOC_QUERYCAP:查询驱动功能
VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式
VIDIOC_S_FMT:设置当前驱动的频捕获格式
VIDIOC_G_FMT:读取当前驱动的频捕获格式
VIDIOC_TRY_FMT:验证当前驱动的显示格式
VIDIOC_CROPCAP:查询驱动的修剪能力
VIDIOC_S_CROP:设置视频信号的边框
VIDIOC_G_CROP:读取视频信号的边框
VIDIOC_QBUF:把数据从缓存中读取出来
VIDIOC_DQBUF:把数据放回缓存队列
VIDIOC_STREAMON:开始视频显示函数
VIDIOC_STREAMOFF:结束视频显示函数
VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PAL或NTSC。

检查当前视频设备支持的标准,使用VIDIOC_QUERYSTD来检测:

v4l2_std_id std;
do {ret = ioctl(fd, VIDIOC_QUERYSTD, &std);
} while (ret == -1 && errno == EAGAIN);
switch (std) {case V4L2_STD_NTSC://……case V4L2_STD_PAL://……case V4L2_STD_AHD://……
}

设置视频捕获格式:

struct v4l2_format    fmt;
memset ( &fmt, 0, sizeof(fmt) );
fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width       = 720;
fmt.fmt.pix.height      = 576;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {return -1;
}v4l2_format结构体定义如下:struct v4l2_format
{enum v4l2_buf_type type;    // 数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTUREunion{struct v4l2_pix_format    pix; struct v4l2_window        win; struct v4l2_vbi_format    vbi; __u8    raw_data[200];         } fmt;
};
struct v4l2_pix_format
{__u32                   width;         // 宽,必须是16的倍数__u32                   height;        // 高,必须是16的倍数__u32                   pixelformat;   // 视频数据存储类型,例如是YUV4:2:2还是RGBenum v4l2_field         field;__u32                   bytesperline;   __u32                   sizeimage;enum v4l2_colorspace    colorspace;__u32                   priv;
};

获取并记录缓存的物理空间

typedef struct VideoBuffer {void   *start;size_t  length;
} VideoBuffer;VideoBuffer*          buffers = calloc( req.count, sizeof(*buffers) );
struct v4l2_buffer    buf;for (numBufs = 0; numBufs < req.count; numBufs++) {memset( &buf, 0, sizeof(buf) );buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;buf.index = numBufs;// 读取缓存if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {return -1;}buffers[numBufs].length = buf.length;// 转换成相对地址buffers[numBufs].start = mmap(NULL, buf.length,PROT_READ | PROT_WRITE,MAP_SHARED,fd, buf.m.offset);if (buffers[numBufs].start == MAP_FAILED) {return -1;}// 放入缓存队列if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {return -1;}
}

处理采集数据

struct v4l2_buffer buf;
memset(&buf,0,sizeof(buf));
buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory=V4L2_MEMORY_MMAP;
buf.index=0;//读取缓存
if (ioctl(cameraFd, VIDIOC_DQBUF, &buf) == -1)
{return -1;
}
//…………视频处理算法
//重新放入缓存队列
if (ioctl(cameraFd, VIDIOC_QBUF, &buf) == -1) {return -1;
}

更多V4L2介绍参考下面的博文:

v4l2的学习建议和流程解析

V4L2视频采集的基本流程

车载USB DVR(行车记录仪)的源码架构浅析(基于AndroiidM)相关推荐

  1. netty springmvc_springmvc源码架构解析之HandlerMapping

    说在前面 前期回顾 sharding-jdbc源码解析 更新完毕 spring源码解析 更新完毕 spring-mvc源码解析 更新完毕 spring-tx源码解析 更新完毕 spring-boot源 ...

  2. yolov3之pytorch源码解析_springmvc源码架构解析之view

    说在前面 前期回顾 sharding-jdbc源码解析 更新完毕 spring源码解析 更新完毕 spring-mvc源码解析 更新完毕 spring-tx源码解析 更新完毕 spring-boot源 ...

  3. vue的matcher_一张思维导图辅助你深入了解 Vue | Vue-Router | Vuex 源码架构

    1.前言 本文内容讲解的内容:一张思维导图辅助你深入了解 Vue | Vue-Router | Vuex 源码架构. 2. Vue 全家桶 先来张 Vue 全家桶 总图: 3. Vue 细分如下 源码 ...

  4. spring boot 源码_springboot源码架构解析listener

    说在前面 前期回顾 sharding-jdbc源码解析 更新完毕 spring源码解析 更新完毕 spring-mvc源码解析 更新完毕 spring-tx源码解析 更新完毕 spring-boot源 ...

  5. 从零手写pm-cli脚手架,统一阿里拍卖源码架构

    前言 ❝ 原文地址:https://github.com/Nealyang/PersonalBlog ❞ 脚手架其实是大多数前端都不陌生的东西,基于前面写过的两篇文章: 前端源码架构在拍卖详情页上的探 ...

  6. OpenBLAS学习一:源码架构解析GEMM分析

    1. 什么是OpenBLAS 1.1. BLAS 1.2. 功能 1.3. 使用 1.3.1. 编译 1.3.2. 调用 1.3.3. 定制化 build 2. OpenBLAS实现 2.1. TOP ...

  7. 网页短信后台开发 短息系统平台定制 web版定制 平台源码架构 短信源码开发升级接入SMPP通道

    网页短信后台开发 短息系统平台定制 web版定制 平台源码架构 短信源码开发升级接入SMPP通道 WEB短信系统SMPP接入功能上线 接入SMPP通道所需要用到的技术 1:多线程 2:服务程序,并不是 ...

  8. 从源码分析 Spring 基于注解的事务

    从源码分析 Spring 基于注解的事务 在spring引入基于注解的事务(@Transactional)之前,我们一般都是如下这样进行拦截事务的配置: <!-- 拦截器方式配置事务 --> ...

  9. 含文档+PPT+源码等]精品基于SSM的图书管理系统[包运行成功]

     博主介绍:✌在职Java研发工程师.专注于程序设计.源码分享.技术交流.专注于Java技术领域和毕业设计✌ 项目名称 含文档+PPT+源码等]精品基于SSM的图书管理系统[包运行成功] 系统介绍 & ...

最新文章

  1. java 合并txt文件_java合并文本文件并删除文件中重复行
  2. 很朴素的学习嵌入式系统的经验
  3. 汽车电子专业知识篇(三十二)-整车电控系统及架构设计技术
  4. ionic3 cordova ionic-native插件
  5. 《零基础》MySQL 安装(二)
  6. Mybatis主线流程源码解析
  7. 栈的输出_算法:栈和队列题目集合(一)
  8. 如何训练您的医生...使用开源
  9. 6代u笔记本完美支持win7_Z170等六代主板装WIN7后USB不能用实测超简单解决教程
  10. CentOS + PyCharm 环境下使用 LIBSVM(及 unresolved reference 问题的解决)
  11. Java编程:哈希表
  12. 转: 在CentOS 6.X 上面安装 Python 2.7.X
  13. HiJson简要说明
  14. Exposure X8 ps人像图片调色滤镜插件
  15. qq邮箱绑定重庆大学邮箱服务器,电子邮箱常见问题
  16. C/C++《数据结构课程设计》任务书[2022-12-27]
  17. 《Python程序设计(第3版)》[美] 约翰·策勒(John Zelle) 第 9 章 答案
  18. 从《三体》到Silkpunk,这些中式科幻用什么打动了西方人?
  19. 房东:你敢申报,我就涨房租!今冬,我一个程序员朋友离开了北京……
  20. 奇安信线上认证训练营测试题及答案-1

热门文章

  1. sql 求和并且将求和条件作为查询条件
  2. voipdiscount免费拨打全球电话(无需手机注册)
  3. EasyExcel自定义复杂的表头并在同sheet中实现分页
  4. [数据结构]基于二叉树的家谱系统
  5. 如何合理使用ClickHouse分区表
  6. web浮动框架 简易灯箱画廊设计
  7. C语言利用顺序表求两个集合的差集
  8. js 中的 this、that
  9. 【女装2018新款潮碎花半身裙韩版气质两件套裙子】http://m.tb.cn/h.3aHr1L7
  10. 使用Bind提供域名解析服务