1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <getopt.h>
6 
7 #include <string>
8 
9 #include "media_v4l2_device.h"
10 
ExerciseControl(V4L2Device * v4l2_dev,uint32_t id,const char * control)11 void ExerciseControl(V4L2Device* v4l2_dev, uint32_t id, const char* control) {
12   v4l2_queryctrl query_ctrl;
13   if (v4l2_dev->QueryControl(id, &query_ctrl)) {
14     if (!v4l2_dev->SetControl(id, query_ctrl.maximum))
15       printf("[Warning] Can not set %s to maximum value\n", control);
16     if (!v4l2_dev->SetControl(id, query_ctrl.minimum))
17       printf("[Warning] Can not set %s to minimum value\n", control);
18     if (!v4l2_dev->SetControl(id, query_ctrl.default_value))
19       printf("[Warning] Can not set %s to default value\n", control);
20   } else {
21     printf("[Warning] Can not query control name :%s\n", control);
22   }
23 }
24 
TestMultipleOpen(const char * dev_name,V4L2Device::IOMethod io)25 void TestMultipleOpen(const char* dev_name, V4L2Device::IOMethod io) {
26   V4L2Device v4l2_dev1(dev_name, io, 4);
27   V4L2Device v4l2_dev2(dev_name, io, 4);
28   if (!v4l2_dev1.OpenDevice()) {
29     printf("[Error] Can not open device '%s' for the first time\n", dev_name);
30   }
31   if (!v4l2_dev2.OpenDevice()) {
32     printf("[Error] Can not open device '%s' for the second time\n", dev_name);
33     exit(EXIT_FAILURE);
34   }
35   v4l2_dev1.CloseDevice();
36   v4l2_dev2.CloseDevice();
37   printf("[OK ] V4L2DeviceTest.MultipleOpen\n");
38 }
39 
TestMultipleInit(const char * dev_name,V4L2Device::IOMethod io)40 void TestMultipleInit(const char* dev_name, V4L2Device::IOMethod io) {
41   V4L2Device v4l2_dev1(dev_name, io, 4);
42   V4L2Device v4l2_dev2(dev_name, io, 4);
43   if (!v4l2_dev1.OpenDevice()) {
44     printf("[Error] Can not open device '%s' for the first time\n", dev_name);
45   }
46   if (!v4l2_dev2.OpenDevice()) {
47     printf("[Error] Can not open device '%s' for the second time\n", dev_name);
48   }
49 
50   if (!v4l2_dev1.InitDevice(640, 480, V4L2_PIX_FMT_YUYV, 0)) {
51     printf("[Error] Can not init device '%s' for the first time\n", dev_name);
52   }
53 
54   // multiple streaming request should fail.
55   if (v4l2_dev2.InitDevice(640, 480, V4L2_PIX_FMT_YUYV, 0)) {
56     printf("[Error] Multiple init device '%s' should fail\n", dev_name);
57     exit(EXIT_FAILURE);
58   }
59 
60   v4l2_dev1.UninitDevice();
61   v4l2_dev2.UninitDevice();
62   v4l2_dev1.CloseDevice();
63   v4l2_dev2.CloseDevice();
64   printf("[OK ] V4L2DeviceTest.MultipleInit\n");
65 }
66 
TestEnumInputAndStandard(const char * dev_name,V4L2Device::IOMethod io)67 void TestEnumInputAndStandard(const char* dev_name, V4L2Device::IOMethod io) {
68   V4L2Device v4l2_dev1(dev_name, io, 4);
69   if (!v4l2_dev1.OpenDevice()) {
70     printf("[Error] Can not open device '%s'\n", dev_name);
71   }
72   v4l2_dev1.EnumInput();
73   v4l2_dev1.EnumStandard();
74   v4l2_dev1.CloseDevice();
75   printf("[OK ] V4L2DeviceTest.EnumInputAndStandard\n");
76 }
77 
TestEnumControl(const char * dev_name,V4L2Device::IOMethod io)78 void TestEnumControl(const char* dev_name, V4L2Device::IOMethod io) {
79   V4L2Device v4l2_dev(dev_name, io, 4);
80   if (!v4l2_dev.OpenDevice()) {
81     printf("[Error] Can not open device '%s'\n", dev_name);
82   }
83   v4l2_dev.EnumControl();
84   v4l2_dev.CloseDevice();
85   printf("[OK ] V4L2DeviceTest.EnumControl\n");
86 }
87 
TestSetControl(const char * dev_name,V4L2Device::IOMethod io)88 void TestSetControl(const char* dev_name, V4L2Device::IOMethod io) {
89   V4L2Device v4l2_dev(dev_name, io, 4);
90   if (!v4l2_dev.OpenDevice()) {
91     printf("[Error] Can not open device '%s'\n", dev_name);
92   }
93   ExerciseControl(&v4l2_dev, V4L2_CID_BRIGHTNESS, "brightness");
94   ExerciseControl(&v4l2_dev, V4L2_CID_CONTRAST, "contrast");
95   ExerciseControl(&v4l2_dev, V4L2_CID_SATURATION, "saturation");
96   ExerciseControl(&v4l2_dev, V4L2_CID_GAMMA, "gamma");
97   ExerciseControl(&v4l2_dev, V4L2_CID_HUE, "hue");
98   ExerciseControl(&v4l2_dev, V4L2_CID_GAIN, "gain");
99   ExerciseControl(&v4l2_dev, V4L2_CID_SHARPNESS, "sharpness");
100   v4l2_dev.CloseDevice();
101   printf("[OK ] V4L2DeviceTest.SetControl\n");
102 }
103 
TestSetCrop(const char * dev_name,V4L2Device::IOMethod io)104 void TestSetCrop(const char* dev_name, V4L2Device::IOMethod io) {
105   V4L2Device v4l2_dev(dev_name, io, 4);
106   if (!v4l2_dev.OpenDevice()) {
107     printf("[Error] Can not open device '%s'\n", dev_name);
108   }
109   v4l2_cropcap cropcap;
110   memset(&cropcap, 0, sizeof(cropcap));
111   if (v4l2_dev.GetCropCap(&cropcap)) {
112     v4l2_crop crop;
113     memset(&crop, 0, sizeof(crop));
114     crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
115     crop.c = cropcap.defrect;
116     v4l2_dev.SetCrop(&crop);
117   }
118   v4l2_dev.CloseDevice();
119   printf("[OK ] V4L2DeviceTest.SetCrop\n");
120 }
121 
TestGetCrop(const char * dev_name,V4L2Device::IOMethod io)122 void TestGetCrop(const char* dev_name, V4L2Device::IOMethod io) {
123   V4L2Device v4l2_dev(dev_name, io, 4);
124   if (!v4l2_dev.OpenDevice()) {
125     printf("[Error] Can not open device '%s'\n", dev_name);
126   }
127   v4l2_crop crop;
128   memset(&crop, 0, sizeof(crop));
129   crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
130   v4l2_dev.GetCrop(&crop);
131   v4l2_dev.CloseDevice();
132   printf("[OK ] V4L2DeviceTest.GetCrop\n");
133 }
134 
TestProbeCaps(const char * dev_name,V4L2Device::IOMethod io)135 void TestProbeCaps(const char* dev_name, V4L2Device::IOMethod io) {
136   V4L2Device v4l2_dev(dev_name, io, 4);
137   if (!v4l2_dev.OpenDevice()) {
138     printf("[Error] Can not open device '%s'\n", dev_name);
139   }
140   v4l2_capability caps;
141   if (!v4l2_dev.ProbeCaps(&caps, true)) {
142     printf("[Error] Can not probe caps on device '%s'\n", dev_name);
143   }
144   v4l2_dev.CloseDevice();
145   printf("[OK ] V4L2DeviceTest.ProbeCaps\n");
146 }
147 
TestEnumFormats(const char * dev_name,V4L2Device::IOMethod io)148 void TestEnumFormats(const char* dev_name, V4L2Device::IOMethod io) {
149   V4L2Device v4l2_dev(dev_name, io, 4);
150   if (!v4l2_dev.OpenDevice()) {
151     printf("[Error] Can not open device '%s'\n", dev_name);
152   }
153   v4l2_dev.EnumFormat(NULL);
154   v4l2_dev.CloseDevice();
155   printf("[OK ] V4L2DeviceTest.EnumFormats\n");
156 }
157 
TestEnumFrameSize(const char * dev_name,V4L2Device::IOMethod io)158 void TestEnumFrameSize(const char* dev_name, V4L2Device::IOMethod io) {
159   V4L2Device v4l2_dev(dev_name, io, 4);
160   if (!v4l2_dev.OpenDevice()) {
161     printf("[Error] Can not open device '%s'\n", dev_name);
162   }
163   uint32_t format_count = 0;
164   v4l2_dev.EnumFormat(&format_count);
165   for (uint32_t i = 0; i < format_count; ++i) {
166     uint32_t pixfmt = v4l2_dev.GetPixelFormat(i);
167     if (pixfmt == 0xFFFFFFFF) {
168       printf("[Error] Enumerate format error on device '%s'\n", dev_name);
169       exit(EXIT_FAILURE);
170     }
171     if (!v4l2_dev.EnumFrameSize(pixfmt)) {
172       printf("[Warning] Enumerate frame size error on device '%s'\n", dev_name);
173     };
174   }
175   v4l2_dev.CloseDevice();
176   printf("[OK ] V4L2DeviceTest.EnumFrameSize\n");
177 }
178 
TestFrameRate(const char * dev_name,V4L2Device::IOMethod io)179 void TestFrameRate(const char* dev_name, V4L2Device::IOMethod io) {
180   V4L2Device v4l2_dev(dev_name, io, 4);
181   if (!v4l2_dev.OpenDevice()) {
182     printf("[Error] Can not open device '%s'\n", dev_name);
183   }
184   v4l2_capability caps;
185   if (!v4l2_dev.ProbeCaps(&caps, true)) {
186     printf("[Error] Can not probe caps on device '%s'\n", dev_name);
187     exit(EXIT_FAILURE);
188   }
189   // we only try to adjust frame rate when it claims can.
190   if (caps.capabilities & V4L2_CAP_TIMEPERFRAME) {
191     v4l2_streamparm param;
192     if (!v4l2_dev.GetParam(&param)) {
193       printf("[Error] Can not get stream param on device '%s'\n", dev_name);
194       exit(EXIT_FAILURE);
195     }
196     if (!v4l2_dev.SetParam(&param)) {
197       printf("[Error] Can not set stream param on device '%s'\n", dev_name);
198       exit(EXIT_FAILURE);
199     }
200 
201     if (!v4l2_dev.SetFrameRate(15)) {
202       printf("[Error] SetFrameRate failed on '%s'\n", dev_name);
203       exit(EXIT_FAILURE);
204     }
205     if (!v4l2_dev.GetParam(&param)) {
206       printf("[Error] Can not get stream param on device '%s'\n", dev_name);
207       exit(EXIT_FAILURE);
208     }
209     if (param.parm.capture.timeperframe.denominator !=
210               param.parm.capture.timeperframe.numerator * 15) {
211       printf("[Error] Can not set frame rate to 15 on '%s'\n", dev_name);
212       exit(EXIT_FAILURE);
213     }
214 
215     if (!v4l2_dev.SetFrameRate(10)) {
216       printf("[Error] SetFrameRate failed on '%s'\n", dev_name);
217       exit(EXIT_FAILURE);
218     }
219     if (!v4l2_dev.GetParam(&param)) {
220       printf("[Error] Can not get stream param on device '%s'\n", dev_name);
221       exit(EXIT_FAILURE);
222     }
223     if (param.parm.capture.timeperframe.denominator !=
224               param.parm.capture.timeperframe.numerator * 10) {
225       printf("[Error] Can not set frame rate to 10 on '%s'\n", dev_name);
226       exit(EXIT_FAILURE);
227     }
228   }
229 
230   v4l2_dev.CloseDevice();
231   printf("[OK ] V4L2DeviceTest.FrameRate\n");
232 }
233 
PrintUsage()234 static void PrintUsage() {
235   printf("Usage: media_v4l2_unittest [options]\n\n"
236          "Options:\n"
237          "--device=DEVICE_NAME   Video device name [/dev/video]\n"
238          "--help                 Print usage\n"
239          "--buffer-io=mmap       Use memory mapped buffers\n"
240          "--buffer-io=read       Use read() calls\n"
241          "--buffer-io=userp      Use application allocated buffers\n");
242 }
243 
244 static const char short_options[] = "d:?b";
245 static const struct option long_options[] = {
246         { "device",       required_argument, NULL, 'd' },
247         { "help",         no_argument,       NULL, '?' },
248         { "buffer-io",    required_argument, NULL, 'b' },
249 };
250 
main(int argc,char ** argv)251 int main(int argc, char** argv) {
252   std::string dev_name = "/dev/video", io_name;
253   V4L2Device::IOMethod io = V4L2Device::IO_METHOD_MMAP;
254 
255   // Parse the command line.
256   for (;;) {
257     int32_t index;
258     int32_t c = getopt_long(argc, argv, short_options, long_options, &index);
259     if (-1 == c)
260       break;
261     switch (c) {
262       case 0:  // getopt_long() flag.
263         break;
264       case 'd':
265         // Initialize default v4l2 device name.
266         dev_name = strdup(optarg);
267         break;
268       case '?':
269         PrintUsage();
270         exit (EXIT_SUCCESS);
271       case 'b':
272         io_name = strdup(optarg);
273         if (io_name == "mmap") {
274           io = V4L2Device::IO_METHOD_MMAP;
275         } else if (io_name == "read") {
276           io = V4L2Device::IO_METHOD_READ;
277         } else if (io_name == "userp") {
278           io = V4L2Device::IO_METHOD_USERPTR;
279         } else {
280           PrintUsage();
281           exit(EXIT_FAILURE);
282         }
283         break;
284       default:
285         PrintUsage();
286         exit(EXIT_FAILURE);
287     }
288   }
289 
290   TestMultipleOpen(dev_name.c_str(), io);
291   TestMultipleInit(dev_name.c_str(), io);
292   TestEnumInputAndStandard(dev_name.c_str(), io);
293   TestEnumControl(dev_name.c_str(), io);
294   TestSetControl(dev_name.c_str(), io);
295   TestSetCrop(dev_name.c_str(), io);
296   TestGetCrop(dev_name.c_str(), io);
297   TestProbeCaps(dev_name.c_str(), io);
298   TestEnumFormats(dev_name.c_str(), io);
299   TestEnumFrameSize(dev_name.c_str(), io);
300   TestFrameRate(dev_name.c_str(), io);
301 }
302 
303