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
11void 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
25void 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
40void 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
67void 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
78void 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
88void 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
104void 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
122void 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
135void 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
148void 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
158void 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
179void 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
234static 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
244static const char short_options[] = "d:?b";
245static 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
251int 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