1
/*
*****************************************************************************
2
* Capture_create
3
*****************************************************************************
*/
4 Capture_Handle Capture_create(BufTab_Handle hBufTab, Capture_Attrs *
attrs)
5
{
6
struct
v4l2_capability cap;
7
struct
v4l2_cropcap cropCap;
8
struct
v4l2_crop crop;
9
struct
v4l2_format fmt;
10
enum
v4l2_buf_type type;
11
Capture_Handle hCapture;
12
VideoStd_Type videoStd;
13
Int32 width, height;
14
Uint32 pixelFormat;
15
16
assert(attrs);
17
Dmai_clear(fmt);
18
19
/*
Allocate space for state object
*/
20 hCapture = calloc(
1,
sizeof
(Capture_Object));
21
22
if (hCapture ==
NULL) {
23 Dmai_err0(
"
Failed to allocate space for Capture Object\n
"
);
24
return
NULL;
25
}
26
27
/*
User allocated buffers by default
*/
28 hCapture->userAlloc =
TRUE;
29
30
/*
Open video capture device
*/
31
/*
打开V4L2视频输入设备
*/
32 hCapture->fd = open(attrs->captureDevice, O_RDWR,
0
);
33
34
if (hCapture->fd == -
1
) {
35 Dmai_err2(
"
Cannot open %s (%s)\n
", attrs->
captureDevice,
36
strerror(errno));
37
cleanup(hCapture);
38
return
NULL;
39
}
40
41
/*
See if an input is connected, and if so which standard
*/
42
/*
检测V4L2设备当前是否有视频信号输入,输入信号的标准
*/
43
if (Capture_detectVideoStd(hCapture, &videoStd, attrs) <
0
) {
44
cleanup(hCapture);
45
return
NULL;
46
}
47
48 hCapture->videoStd =
videoStd;
49
50
if (VideoStd_getResolution(videoStd, &width, &height) <
0
) {
51
cleanup(hCapture);
52 Dmai_err0(
"
Failed to get resolution of capture video standard\n
"
);
53
return
NULL;
54
}
55
56
/*
Query for capture device capabilities
*/
57
/*
这里就是调用ioctl直接操作v4l2设备了,查询设备的特性
*/
58
if (ioctl(hCapture->fd, VIDIOC_QUERYCAP, &cap) == -
1
) {
59
cleanup(hCapture);
60
if (errno ==
EINVAL) {
61 Dmai_err1(
"
%s is no V4L2 device\n
", attrs->
captureDevice);
62
cleanup(hCapture);
63
return
NULL;
64
}
65 Dmai_err2(
"
Failed VIDIOC_QUERYCAP on %s (%s)\n
", attrs->
captureDevice,
66
strerror(errno));
67
cleanup(hCapture);
68
return
NULL;
69
}
70
71
if (!(cap.capabilities &
V4L2_CAP_VIDEO_CAPTURE)) {
72 Dmai_err1(
"
%s is not a video capture device\n
", attrs->
captureDevice);
73
cleanup(hCapture);
74
return
NULL;
75
}
76
77
if (!(cap.capabilities &
V4L2_CAP_STREAMING)) {
78 Dmai_err1(
"
%s does not support streaming i/o\n
", attrs->
captureDevice);
79
cleanup(hCapture);
80
return
NULL;
81
}
82
83 fmt.type =
V4L2_BUF_TYPE_VIDEO_CAPTURE;
84
/*
获取V4L2设备的帧格式
*/
85
if (ioctl(hCapture->fd, VIDIOC_G_FMT, &fmt) == -
1
) {
86 Dmai_err2(
"
Failed VIDIOC_G_FMT on %s (%s)\n
", attrs->
captureDevice,
87
strerror(errno));
88
cleanup(hCapture);
89
return
NULL;
90
}
91
92 fmt.fmt.pix.width =
width;
93 fmt.fmt.pix.height =
height;
94 fmt.type =
V4L2_BUF_TYPE_VIDEO_CAPTURE;
95
96
switch(attrs->
colorSpace) {
97
case
ColorSpace_UYVY:
98 fmt.fmt.pix.pixelformat =
V4L2_PIX_FMT_UYVY;
99
break
;
100
case
ColorSpace_YUV420PSEMI:
101 fmt.fmt.pix.pixelformat =
V4L2_PIX_FMT_NV12;
102
break
;
103
case
ColorSpace_YUV422PSEMI:
104 fmt.fmt.pix.pixelformat =
V4L2_PIX_FMT_NV16;
105
break
;
106
default
:
107 Dmai_err1(
"
Unsupported color format %g\n
", attrs->
colorSpace);
108
cleanup(hCapture);
109
return
NULL;
110
}
111
112
if ((videoStd == VideoStd_BAYER_CIF) || (videoStd == VideoStd_BAYER_VGA) ||
113 (videoStd ==
VideoStd_BAYER_1280)) {
114 fmt.fmt.pix.pixelformat =
V4L2_PIX_FMT_SBGGR8;
115
}
116
117 fmt.fmt.pix.bytesperline =
BufferGfx_calcLineLength(fmt.fmt.pix.width,
118 attrs->
colorSpace);
119 fmt.fmt.pix.sizeimage = BufferGfx_calcSize(attrs->videoStd, attrs->
colorSpace);
120
121
//
printf("DMAI: pix.bytesperline= %d, pix.sizeimage= %d\r\n",fmt.fmt.pix.bytesperline,fmt.fmt.pix.sizeimage);
122 pixelFormat =
fmt.fmt.pix.pixelformat;
123
124
if ((videoStd == VideoStd_CIF) || (videoStd == VideoStd_SIF_PAL) ||
125 (videoStd == VideoStd_SIF_NTSC) || (videoStd == VideoStd_D1_PAL) ||
126 (videoStd == VideoStd_D1_NTSC) || (videoStd == VideoStd_1080I_30) ||
127 (videoStd ==
VideoStd_1080I_25)) {
128 fmt.fmt.pix.field =
V4L2_FIELD_INTERLACED;
129 }
else
{
130 fmt.fmt.pix.field =
V4L2_FIELD_NONE;
131
}
132
133
/*
设置V4L2输入设备的帧格式
*/
134
if (ioctl(hCapture->fd, VIDIOC_S_FMT, &fmt) == -
1
) {
135 printf(
"
Failed VIDIOC_S_FMT on %s (%s)\n
", attrs->
captureDevice,
136
strerror(errno));
137
cleanup(hCapture);
138
return
NULL;
139
}
140
141
if ((fmt.fmt.pix.width != width) || (fmt.fmt.pix.height !=
height)) {
142 Dmai_err4(
"
Failed to set resolution %d x %d (%d x %d)\n
"
, width,
143
height, fmt.fmt.pix.width, fmt.fmt.pix.height);
144
cleanup(hCapture);
145
return
NULL;
146
}
147
148
if (pixelFormat !=
fmt.fmt.pix.pixelformat) {
149 Dmai_err2(
"
Pixel format 0x%x not supported. Received 0x%x\n
"
,
150
pixelFormat, fmt.fmt.pix.pixelformat);
151
cleanup(hCapture);
152
return
NULL;
153
}
154
155 Dmai_dbg3(
"
Video input connected size %dx%d pitch %d\n
"
,
156
fmt.fmt.pix.width, fmt.fmt.pix.height, fmt.fmt.pix.bytesperline);
157
158
/*
Query for video input cropping capability
*/
159
160
if (attrs->cropWidth >
0 && attrs->cropHeight >
0
) {
161
162 cropCap.type =
V4L2_BUF_TYPE_VIDEO_CAPTURE;
163
if (ioctl(hCapture->fd, VIDIOC_CROPCAP, &cropCap) == -
1
) {
164 Dmai_err2(
"
VIDIOC_CROPCAP failed on %s (%s)\n
", attrs->
captureDevice,
165
strerror(errno));
166
cleanup(hCapture);
167
return
NULL;
168
}
169
170
if (attrs->cropX &
0x1
) {
171 Dmai_err1(
"
Crop width (%ld) needs to be even\n
", attrs->
cropX);
172
cleanup(hCapture);
173
return
NULL;
174
}
175
176 crop.type =
V4L2_BUF_TYPE_VIDEO_CAPTURE;
177 crop.c.left = attrs->
cropX;
178 crop.c.top = attrs->
cropY;
179 crop.c.width = attrs->
cropWidth;
180 crop.c.height = hCapture->topOffset ? attrs->cropHeight +
4 +
2
:
181 attrs->
cropHeight;
182
183 Dmai_dbg4(
"
Setting capture cropping at %dx%d size %dx%d\n
"
,
184
crop.c.left, crop.c.top, crop.c.width, crop.c.height);
185
186
/*
Crop the image depending on requested image size
*/
187
if (ioctl(hCapture->fd, VIDIOC_S_CROP, &crop) == -
1
) {
188 Dmai_err2(
"
VIDIOC_S_CROP failed on %s (%s)\n
", attrs->
captureDevice,
189
strerror(errno));
190
cleanup(hCapture);
191
return
NULL;
192
}
193
}
194
195
if (hBufTab ==
NULL) {
196 hCapture->userAlloc =
FALSE;
197
198
/*
The driver allocates the buffers
*/
199
/*
调用CMEM创建要用到的视频缓冲区
*/
200
if (_Dmai_v4l2DriverAlloc(hCapture->
fd,
201 attrs->
numBufs,
202
V4L2_BUF_TYPE_VIDEO_CAPTURE,
203 &hCapture->
bufDescs,
204 &
hBufTab,
205 hCapture->
topOffset,
206 attrs->colorSpace) <
0
) {
207 Dmai_err1(
"
Failed to allocate capture driver buffers on %s\n
"
,
208 attrs->
captureDevice);
209
cleanup(hCapture);
210
return
NULL;
211
}
212
}
213
else
{
214
/*
Make the driver use the user supplied buffers
*/
215
/*
如果调用者已经创建好缓冲区,那只需要加入相应的队列管理就可以
*/
216
if (_Dmai_v4l2UserAlloc(hCapture->
fd,
217 attrs->
numBufs,
218
V4L2_BUF_TYPE_VIDEO_CAPTURE,
219 &hCapture->
bufDescs,
220
hBufTab,
221
0, attrs->colorSpace) <
0
) {
222 Dmai_err1(
"
Failed to intialize capture driver buffers on %s\n
"
,
223 attrs->
captureDevice);
224
cleanup(hCapture);
225
return
NULL;
226
}
227
}
228
229 hCapture->hBufTab =
hBufTab;
230
231
/*
Start the video streaming
*/
232 type =
V4L2_BUF_TYPE_VIDEO_CAPTURE;
233
234
/*
配置完后,启动V4L2设备
*/
235
if (ioctl(hCapture->fd, VIDIOC_STREAMON, &type) == -
1
) {
236 Dmai_err2(
"
VIDIOC_STREAMON failed on %s (%s)\n
", attrs->
captureDevice,
237
strerror(errno));
238
cleanup(hCapture);
239
return
NULL;
240
}
241
242 hCapture->started =
TRUE;
243
244
return
hCapture;
245 }