第三阶段应用层——2.2 视频监控—根据虚拟驱动vivi的使用过程彻底分析摄像头驱动

视频监控—根据虚拟驱动vivi的使用过程彻底分析摄像头驱动


一、虚拟驱动vivi测试

  1. 在Ubuntu虚拟机上安装xawtv,执行uname -a确实ubuntu的内核版本;
  2. 去www.kernel.org下载同版本的内核,解压后/drivers/media/video目录取出修改它的Makefile为:
KERN_DIR = /usr/src/linux-headers-"内核版本"-generic

all:
        make -C $(KERN_DIR) M=`pwd` modules 

clean:
        make -C $(KERN_DIR) M=`pwd` modules clean
        rm -rf modules.order

obj-m   += vivi.o
obj-m   += videobuf-core.o
obj-m   += videobuf-vmalloc.o
obj-m   += v4l2-common.o
  1. 执行make进行编译
  2. 加载驱动sudo modprobe vivisudo rmmod vivisudo insmod ./vivi.ko
  3. 查看对应的设备节点ls /dev/video*
  4. 执行xawtv -c /dev/videoX,启动测试vivi

二、根据log分析摄像头驱动

执行,打印出vivi使用时的xawtv.log,从中彻底分析摄像头驱动

由于log信息过多,只挑选出对应部分,由于vivi对应的设备节点为/dev/event0,在日志搜索/dev/event0得到以下有用信息

open("/dev/video0", O_RDWR|O_LARGEFILE) = 4
ioctl(4, VIDIOC_QUERYCAP or VT_OPENQRY, 0xbfaccd44) = 0
ioctl(4, VIDIOC_G_FMT or VT_SENDSIG, 0xbfaccc78) = 0
ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0
ioctl(4, 0xc02c564a, 0xbfaccb58)        = -1 EINVAL (Invalid argument)
ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0
ioctl(4, 0xc02c564a, 0xbfaccb58)        = -1 EINVAL (Invalid argument)
ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0
ioctl(4, 0xc02c564a, 0xbfaccb58)        = -1 EINVAL (Invalid argument)
ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0
ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0
ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = 0
ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0xbfaccbec) = -1 EINVAL (Invalid argument)
ioctl(4, VIDIOC_QUERYCAP or VT_OPENQRY, 0xbfaccb84) = 0
ioctl(4, VIDIOC_G_INPUT, 0xbfacca2c)    = 0
ioctl(4, VIDIOC_ENUMINPUT, 0xbfacca2c)  = 0
fstat64(4, {st_mode=S_IFCHR|0660, st_rdev=makedev(81, 0), ...}) = 0
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0xbfacca78) = -1 EINVAL (Invalid argument)
ioctl(4, VIDIOC_QUERYCAP or VT_OPENQRY, 0x9b40998) = 0
fcntl64(4, F_SETFD, FD_CLOEXEC)         = 0
ioctl(4, VIDIOC_ENUMINPUT, 0x9b40acc)   = 0
ioctl(4, VIDIOC_ENUMINPUT, 0x9b40b18)   = 0
ioctl(4, VIDIOC_ENUMINPUT, 0x9b40b64)   = 0
ioctl(4, VIDIOC_ENUMINPUT, 0x9b40bb0)   = 0
ioctl(4, VIDIOC_ENUMINPUT, 0x9b40bfc)   = -1 EINVAL (Invalid argument)
ioctl(4, VIDIOC_ENUMSTD, 0x9b40f8c)     = 0
ioctl(4, VIDIOC_ENUMSTD, 0x9b40fcc)     = 0
ioctl(4, VIDIOC_ENUMSTD, 0x9b4100c)     = 0
ioctl(4, VIDIOC_ENUMSTD, 0x9b4104c)     = 0
ioctl(4, VIDIOC_ENUMSTD, 0x9b4108c)     = 0
ioctl(4, VIDIOC_ENUMSTD, 0x9b410cc)     = 0
ioctl(4, VIDIOC_ENUMSTD, 0x9b4110c)     = 0
ioctl(4, VIDIOC_ENUMSTD, 0x9b4114c)     = -1 EINVAL (Invalid argument)
ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b4138c) = 0
ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b413cc) = 0
ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b4140c) = 0
ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b4144c) = 0
ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b4148c) = 0
ioctl(4, VIDIOC_ENUM_FMT or VT_SETMODE, 0x9b414cc) = 0
ioctl(4, VIDIOC_G_PARM, 0x9b40a00)      = 0
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41b8c) = 0
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41bd0) = 0
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41c14) = 0
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41c58) = 0
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41c9c) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41ce0) = 0
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41d24) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41d68) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41dac) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41df0) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41e34) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41e78) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41ebc) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41f00) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41f44) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41f88) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b41fcc) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42010) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42054) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42098) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b420dc) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42120) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42164) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b421a8) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b421ec) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42230) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42274) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b422b8) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b422fc) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42340) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42384) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b423c8) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4240c) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42450) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42494) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b424d8) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4251c) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42560) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b425a4) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b425e8) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4262c) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42670) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b426b4) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b426f8) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4273c) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42780) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b427c4) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42808) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4284c) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42890) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b428d4) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42918) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b4295c) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b429a0) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b429e4) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42a28) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42a6c) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42ab0) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42af4) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42b38) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42b7c) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42bc0) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42c04) = -1 EINVAL (Invalid argument)
ioctl(4, MATROXFB_TVOQUERYCTRL or VIDIOC_QUERYCTRL, 0x9b42c48) = -1 EINVAL (Invalid argument)
ioctl(4, VIDIOC_G_STD, 0xbfacce08)      = 0
ioctl(4, VIDIOC_G_INPUT, 0xbfacce1c)    = 0
ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce14) = 0
ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce14) = 0
ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce14) = 0
ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce14) = 0
ioctl(4, MATROXFB_G_TVOCTRL or VIDIOC_G_CTRL, 0xbfacce24) = 0
ioctl(4, VIDIOC_TRY_FMT, 0x9b42ca4)     = 0
ioctl(4, VIDIOC_S_FMT or VT_RELDISP, 0xbfacc754) = 0
ioctl(4, VIDIOC_TRY_FMT, 0x9b42ca4)     = 0
ioctl(4, VIDIOC_REQBUFS or VT_DISALLOCATE, 0x9b42d80) = 0
ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0x9b42d94) = 0
ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0x9b42dd8) = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_STREAMON, 0xbfacca2c)   = 0
ioctl(4, MATROXFB_S_TVOCTRL or VIDIOC_S_CTRL, 0xbfacce10) = 0
ioctl(4, MATROXFB_S_TVOCTRL or VIDIOC_S_CTRL, 0xbfacce10) = 0
ioctl(4, MATROXFB_S_TVOCTRL or VIDIOC_S_CTRL, 0xbfacce10) = 0
ioctl(4, MATROXFB_S_TVOCTRL or VIDIOC_S_CTRL, 0xbfacce10) = 0
ioctl(4, VIDIOC_S_INPUT, 0xbfacce84)    = 0
ioctl(4, VIDIOC_S_STD, 0x9b40f90)       = 0
select(5, [4], NULL, NULL, {5, 0})      = 1 (in [4], left {4, 985979})
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42dd8)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_QBUF, 0x9b42d94)        = 0
ioctl(4, VIDIOC_DQBUF, 0xbfaccd00)      = 0
ioctl(4, VIDIOC_STREAMOFF, 0xbfacc53c)  = 0
ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0xbfacc48c) = 0
ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0xbfacc48c) = 0
ioctl(4, VIDIOC_REQBUFS or VT_DISALLOCATE, 0x9b42d80) = -1 EINVAL (Invalid argument)
ioctl(4, VIDIOC_TRY_FMT, 0x9b42ca4)     = -1 EINVAL (Invalid argument)
ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000)    = 0
ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000)    = 0
ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000)    = 0
ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000)    = 0
ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000)    = 0
ioctl(4, VIDIOC_TRY_FMT, 0xbfacc000)    = 0
ioctl(4, VIDIOC_REQBUFS or VT_DISALLOCATE, 0xbfacc70c) = 0
ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0xbfacc61c) = 0
ioctl(4, VIDIOC_QUERYBUF or VT_RESIZE, 0xbfacc61c) = 0
ioctl(4, VIDIOC_QBUF, 0xbfacc61c)       = 0
ioctl(4, VIDIOC_QBUF, 0xbfacc61c)       = 0
ioctl(4, VIDIOC_STREAMON, 0xbfacc65c)   = 0
ioctl(4, VIDIOC_DQBUF, 0xbfacc6c8)      = 0
ioctl(4, VIDIOC_QBUF, 0xbfacc61c)       = 0

1、提取有用的信息,得到关键函数

下面分析的源码linux版本为linux-2.6.31.14

  • 以下为使用到的ioctl code for video
#define VIDIOC_QUERYCAP	  _IOR('V',  0, struct v4l2_capability)	//获取设备能力
#define VIDIOC_ENUM_FMT   _IOWR('V',  2, struct v4l2_fmtdesc)	//获取设备支持的帧格式
#define VIDIOC_G_FMT	  _IOWR('V',  4, struct v4l2_format)	//获取当前设备帧格式
#define VIDIOC_S_FMT	  _IOWR('V',  5, struct v4l2_format)	//设置当前设备帧格式
#define VIDIOC_REQBUFS	  _IOWR('V',  8, struct v4l2_requestbuffers)//申请内核空间缓冲区
#define VIDIOC_QUERYBUF   _IOWR('V',  9, struct v4l2_buffer)	//获取内核空间单帧缓冲区信息
#define VIDIOC_QBUF		  _IOWR('V', 15, struct v4l2_buffer)	//将单帧缓冲区放入采集入队队列
#define VIDIOC_DQBUF	  _IOWR('V', 17, struct v4l2_buffer)	//从采集出队队列取出单帧缓冲区
#define VIDIOC_STREAMON	  _IOW('V', 18, int)	//开始视频流采集
#define VIDIOC_STREAMOFF  _IOW('V', 19, int)	//关闭视频流采集

根据上述log中提取到的信息的宏定义,去xawtv源码中进行搜索,得到以下信息:

/*----- 1~7 在v4l2_open() ------*/
1. open
2. ioctl(4, VIDIOC_QUERYCAP

/*----- 3~7 在get_device_capabilities() ------*/
3. for()
        ioctl(4, VIDIOC_ENUMINPUT   // 列举输入源,VIDIOC_ENUMINPUT/VIDIOC_G_INPUT/VIDIOC_S_INPUT不是必需的
4. for()
        ioctl(4, VIDIOC_ENUMSTD 	// 列举标准(制式), 不是必需的
5. for()        
        ioctl(4, VIDIOC_ENUM_FMT 	// 列举格式

6. ioctl(4, VIDIOC_G_PARM
7. for()
        ioctl(4, VIDIOC_QUERYCTRL    // 查询属性(比如说亮度值最小值、最大值、默认值)

/*----- 8~10 在v4l2_read_attr() ------*/        
8. ioctl(4, VIDIOC_G_STD            // 获得当前使用的标准(制式), 不是必需的
9. ioctl(4, VIDIOC_G_INPUT 
10. ioctl(4, VIDIOC_G_CTRL           // 获得当前属性, 比如亮度是多少

11. ioctl(4, VIDIOC_TRY_FMT          // 试试能否支持某种格式
12. ioctl(4, VIDIOC_S_FMT            // 设置摄像头使用某种格式


/*----- 13~16 在v4l2_start_streaming() ------*/
13. ioctl(4, VIDIOC_REQBUFS          // 请求系统分配缓冲区
14. for()
        ioctl(4, VIDIOC_QUERYBUF     // 查询所分配的缓冲区
        mmap        
15. for ()
        ioctl(4, VIDIOC_QBUF         // 把缓冲区放入队列        
16. ioctl(4, VIDIOC_STREAMON         // 启动摄像头


/*----- 在v4l2_write_attr() ------*/
17. for ()
        ioctl(4, VIDIOC_S_CTRL       // 设置属性
    ioctl(4, VIDIOC_S_INPUT          // 设置输入源
    ioctl(4, VIDIOC_S_STD            / 设置标准(制式), 不是必需的

/*----- 在v4l2_nextframe()/v4l2_waiton() ------*/   
18. v4l2_queue_all
    v4l2_waiton    
        for ()
        {
            select(5, [4], NULL, NULL, {5, 0})      = 1 (in [4], left {4, 985979})
            ioctl(4, VIDIOC_DQBUF                // de-queue, 把缓冲区从队列中取出
            
            // 处理, 之以已经通过mmap获得了缓冲区的地址, 就可以直接访问数据        
            ioctl(4, VIDIOC_QBUF                 // 把缓冲区放入队列
        }
  • 得到测试vivi时xawtv的几个关键函数
1. v4l2_open()
2. v4l2_read_attr()/v4l2_write_attr()
3. v4l2_start_streaming()
4. v4l2_nextframe()/v4l2_waiton()

2、分析vivi.c源码

2.1 关键ioctl

vivi.c中,我们看到有如下vivi_ioctl_ops结构体:

static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
	.vidioc_querycap          = vidioc_querycap,			//获取设备能力
	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,	//获取设备支持的帧格式
	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,		//获取当前设备帧格式
	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,		//设置当前设备帧格式
	.vidioc_reqbufs       	  = vidioc_reqbufs,				//申请内核空间缓冲区
	.vidioc_querybuf      	  = vidioc_querybuf,			//获取内核空间单帧缓冲区信息
	.vidioc_qbuf          	  = vidioc_qbuf,				//将单帧缓冲区放入采集入队队列
	.vidioc_dqbuf         	  = vidioc_dqbuf,				//从采集出队队列取出单帧缓冲区
	.vidioc_s_std         	  = vidioc_s_std,				
	.vidioc_enum_input    	  = vidioc_enum_input,
	.vidioc_g_input      	  = vidioc_g_input,
	.vidioc_s_input       	  = vidioc_s_input,
	.vidioc_streamon      	  = vidioc_streamon,			//开始视频流采集
	.vidioc_streamoff     	  = vidioc_streamoff,			//关闭视频流采集
	.vidioc_log_status    	  = v4l2_ctrl_log_status,
	.vidioc_subscribe_event   = v4l2_ctrl_subscribe_event,
	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};

经过测试,实际提取出11个关键的ioctl

	// 表示它是一个摄像头设备
	.vidioc_querycap      = vidioc_querycap,

    /* 用于列举、获得、测试、设置摄像头的数据的格式 */
	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
	.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
	.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
	.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,

    /* 缓冲区操作: 申请/查询/放入队列/取出队列 */
	.vidioc_reqbufs       = vidioc_reqbufs,
	.vidioc_querybuf      = vidioc_querybuf,
	.vidioc_qbuf          = vidioc_qbuf,
	.vidioc_dqbuf         = vidioc_dqbuf,

	// 启动/停止
	.vidioc_streamon      = vidioc_streamon,
	.vidioc_streamoff     = vidioc_streamoff,	

2.2 分析数据的获取过程

vivi进行数据获取时,根据log的信息,数据的获取过程如下,在linux内核源码中v4l2-ioctl.c文件中找到对应的操作项

/*----- 13~16 在v4l2_start_streaming() ------*/
13. ioctl(4, VIDIOC_REQBUFS          // 请求系统分配缓冲区
14. for()
        ioctl(4, VIDIOC_QUERYBUF     // 查询所分配的缓冲区
        mmap        
15. for ()
        ioctl(4, VIDIOC_QBUF         // 把缓冲区放入队列        
16. ioctl(4, VIDIOC_STREAMON         // 启动摄像头


/*----- 在v4l2_write_attr() ------*/
17. for ()
        ioctl(4, VIDIOC_S_CTRL       // 设置属性
    ioctl(4, VIDIOC_S_INPUT          // 设置输入源
    ioctl(4, VIDIOC_S_STD            / 设置标准(制式), 不是必需的

/*----- 在v4l2_nextframe()/v4l2_waiton() ------*/   
18. v4l2_queue_all
    v4l2_waiton    
        for ()
        {
            select(5, [4], NULL, NULL, {5, 0})      = 1 (in [4], left {4, 985979})
            ioctl(4, VIDIOC_DQBUF                // de-queue, 把缓冲区从队列中取出
            
            // 处理, 之以已经通过mmap获得了缓冲区的地址, 就可以直接访问数据        
            ioctl(4, VIDIOC_QBUF                 // 把缓冲区放入队列
        }

在这里插入图片描述

2.2.1 请求系统分配缓冲区VIDIOC_REQBUFS

通过追踪源码可知,其最终调用的是vivi.c的vidioc_reqbufs(),此时的vidioc_reqbufs()分配的并不是真正的缓存,只是缓冲区的头部信息
在这里插入图片描述

2.2.2 查询与所分配的缓冲区VIDIOC_QUERYBUF

通过追踪源码可知,其最终调用的是vivi.c的vidioc_querybuf(),此时进行的是查询2.2.1中分配的缓冲区的状态
在这里插入图片描述
具体的状态信息为:数据格式、大小、每一行长度、高度
在这里插入图片描述

2.2.3 映射缓冲区mmap

此时才是正在的分配缓存通过2.2.1头部信息的中指针指向缓存(调用到才分配内存)
在这里插入图片描述

2.2.4 把缓冲区放入队列VIDIOC_QBUF

把缓冲区放入队列中,采用的是尾插法
在这里插入图片描述

2.2.5 启动摄像头VIDIOC_STREAMON

在这里插入图片描述

2.2.6 用select查询是否有数据

其采用的是poll机制,即硬件有数据时,程序才被唤醒
在这里插入图片描述

那么谁来唤醒呢?由vivi.c是一个虚拟驱动,其数据产生通过内核线程在一定时间内调用函数产生数据来唤醒进程
在这里插入图片描述

2.2.7 有数据后从队列里取出缓冲区VIDIOC_DQBUF

对于队列中的那么多缓冲区,APP如何知道哪一个缓冲区有数据
通过调用vidioc_dqbuf()来获取有数据的缓存区处理完该缓存区的数据后,从队列中删除该缓存区返回数据给APP
在这里插入图片描述

2.2.8 应用程序读取数据

根据2.2.6的VIDIOC_DQBUF得到缓冲区状态知道是哪一个缓冲区有数据去读对应的地址(该地址来自前面的mmap),之后返回2.2.4把缓冲区重新放入队列的尾部进行下一缓冲区数据的读取

3、总结

对于其缓冲区的数据处理过程如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42813232/article/details/107448904