The open source OpenXR runtime
at main 1027 lines 26 kB view raw
1// Copyright 2019-2022, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief V4L2 frameserver implementation 6 * @author Pete Black <pblack@collabora.com> 7 * @author Jakob Bornecrantz <jakob@collabora.com> 8 * @ingroup drv_v4l2 9 */ 10 11#include "os/os_time.h" 12 13#include "util/u_var.h" 14#include "util/u_sink.h" 15#include "util/u_misc.h" 16#include "util/u_debug.h" 17#include "util/u_format.h" 18#include "util/u_logging.h" 19#include "util/u_trace_marker.h" 20 21#include "v4l2_interface.h" 22#include "v4l2_driver.h" 23 24#include <stdio.h> 25#include <unistd.h> 26#include <pthread.h> 27 28#include <linux/videodev2.h> 29#include <linux/v4l2-common.h> 30#include <sys/ioctl.h> 31#include <sys/mman.h> 32#include <fcntl.h> 33 34 35/* 36 * 37 * Defines. 38 * 39 */ 40 41 42#define V_CONTROL_GET(VID, CONTROL) \ 43 do { \ 44 int _value = 0; \ 45 if (v4l2_control_get(VID, V4L2_CID_##CONTROL, &_value) != 0) { \ 46 V4L2_ERROR(VID, "failed to get V4L2_CID_" #CONTROL); \ 47 } else { \ 48 V4L2_DEBUG(VID, "V4L2_CID_" #CONTROL " = %i", _value); \ 49 } \ 50 } while (false); 51 52#define V_CONTROL_SET(VID, CONTROL, VALUE) \ 53 do { \ 54 if (v4l2_control_set(VID, V4L2_CID_##CONTROL, VALUE) != 0) { \ 55 V4L2_ERROR(VID, "failed to set V4L2_CID_" #CONTROL); \ 56 } \ 57 } while (false); 58 59DEBUG_GET_ONCE_LOG_OPTION(v4l2_log, "V4L2_LOG", U_LOGGING_WARN) 60DEBUG_GET_ONCE_NUM_OPTION(v4l2_exposure_absolute, "V4L2_EXPOSURE_ABSOLUTE", 10) 61 62/*! 63 * Streaming thread entrypoint 64 */ 65static void * 66v4l2_fs_mainloop(void *ptr); 67 68static void 69dump_controls(struct v4l2_fs *vid); 70 71static void 72dump_contron_name(uint32_t id); 73 74 75/* 76 * 77 * Misc helper functions 78 * 79 */ 80 81static size_t 82align_up(size_t size, size_t align) 83{ 84 if ((size % align) == 0) { 85 return size; 86 } 87 88 return size + (align - (size % align)); 89} 90 91static void 92v4l2_free_frame(struct xrt_frame *xf) 93{ 94 struct v4l2_frame *vf = (struct v4l2_frame *)xf; 95 struct v4l2_fs *vid = (struct v4l2_fs *)xf->owner; 96 97 vid->used_frames--; 98 99 if (!vid->is_running) { 100 return; 101 } 102 103 if (ioctl(vid->fd, VIDIOC_QBUF, &vf->v_buf) < 0) { 104 V4L2_ERROR(vid, "error: Requeue failed!"); 105 vid->is_running = false; 106 } 107} 108 109XRT_MAYBE_UNUSED static int 110v4l2_control_get(struct v4l2_fs *vid, uint32_t id, int *out_value) 111{ 112 struct v4l2_control control = {0}; 113 int ret; 114 115 control.id = id; 116 ret = ioctl(vid->fd, VIDIOC_G_CTRL, &control); 117 if (ret != 0) { 118 return ret; 119 } 120 121 *out_value = control.value; 122 return 0; 123} 124 125static int 126v4l2_control_set(struct v4l2_fs *vid, uint32_t id, int value) 127{ 128 struct v4l2_control control = {0}; 129 int ret; 130 131 control.id = id; 132 control.value = value; 133 ret = ioctl(vid->fd, VIDIOC_S_CTRL, &control); 134 if (ret != 0) { 135 return ret; 136 } 137 138 return 0; 139} 140 141static void 142v4l2_add_control_state(struct v4l2_fs *vid, int control, struct v4l2_state_want want[2], int force, const char *name) 143{ 144 struct v4l2_control_state *state = &vid->states[vid->num_states++]; 145 146 state->id = control; 147 state->name = name; 148 state->want[0] = want[0]; 149 state->want[1] = want[1]; 150 state->force = force; 151} 152 153static int 154v4l2_query_cap_and_validate(struct v4l2_fs *vid) 155{ 156 int ret; 157 158 /* 159 * Regular caps. 160 */ 161 struct v4l2_capability cap; 162 ret = ioctl(vid->fd, VIDIOC_QUERYCAP, &cap); 163 if (ret != 0) { 164 V4L2_ERROR(vid, "error: Failed to get v4l2 cap."); 165 return ret; 166 } 167 168 char *card = (char *)cap.card; 169 snprintf(vid->base.name, sizeof(vid->base.name), "%s", card); 170 171 V4L2_DEBUG(vid, "V4L2 device: '%s'", vid->base.name); 172 173 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { 174 // not a video device 175 V4L2_ERROR(vid, "error: Is not a capture device."); 176 return -1; 177 } 178 if (!(cap.capabilities & V4L2_CAP_STREAMING)) { 179 // cannot stream 180 V4L2_ERROR(vid, "error: Cannot stream!"); 181 return -1; 182 } 183 if (cap.capabilities & V4L2_CAP_EXT_PIX_FORMAT) { 184 // need to query for extended format info 185 vid->has.extended_format = true; 186 } 187 188 /* 189 * Stream capture caps. 190 */ 191 struct v4l2_streamparm stream = {0}; 192 stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 193 194 ret = ioctl(vid->fd, VIDIOC_G_PARM, &stream); 195 if (ret != 0) { 196 V4L2_ERROR(vid, "error: Failed to get v4l2 stream param."); 197 return ret; 198 } 199 200 if (stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { 201 // Does this device support setting the timeperframe interval. 202 vid->has.timeperframe = true; 203 } else { 204 V4L2_DEBUG(vid, "warning: No V4L2_CAP_TIMEPERFRAME"); 205 } 206 207 // Log controls. 208 if (vid->log_level <= U_LOGGING_DEBUG) { 209 dump_controls(vid); 210 } 211 212 /* 213 * Find quirks 214 */ 215 vid->quirks.ps4_cam = strcmp(card, "USB Camera-OV580: USB Camera-OV") == 0; 216 217#define ADD(CONTROL, WANT1, WANT2, WANT3, WANT4, NAME) \ 218 do { \ 219 struct v4l2_state_want want[2] = {{WANT1, WANT2}, {WANT3, WANT4}}; \ 220 v4l2_add_control_state(vid, V4L2_CID_##CONTROL, want, 2, NAME); \ 221 } while (false) 222 223 if (vid->quirks.ps4_cam) { 224 // The experimented best controls to best track things. 225 ADD(GAIN, // 226 true, 0, false, 0, // 227 "gain"); 228 ADD(AUTO_WHITE_BALANCE, // 229 true, 0, true, 1, // 230 "auto_white_balance"); 231 ADD(WHITE_BALANCE_TEMPERATURE, // 232 true, 3900, false, 0, // 233 "white_balance_temperature"); 234 ADD(EXPOSURE_AUTO, // 235 true, 2, true, 0, // 236 "exposure_auto"); 237 long num = debug_get_num_option_v4l2_exposure_absolute(); 238 ADD(EXPOSURE_ABSOLUTE, // 239 true, num, false, 0, // 240 "exposure_absolute"); 241 } 242 243 if (strcmp(card, "3D USB Camera: 3D USB Camera") == 0) { 244 // The experimented best controls to best track things. 245 ADD(AUTO_WHITE_BALANCE, // 246 true, 0, true, 1, // 247 "auto_white_balance"); 248 ADD(WHITE_BALANCE_TEMPERATURE, // 249 true, 6500, false, 0, // 250 "white_balance_temperature"); 251 ADD(EXPOSURE_AUTO, // 252 true, 1, true, 3, // 253 "exposure_auto"); 254 ADD(EXPOSURE_ABSOLUTE, // 255 true, 10, false, 0, // 256 "exposure_absolute"); 257 } 258 259 // Done 260 return 0; 261} 262 263static int 264v4l2_try_userptr(struct v4l2_fs *vid, struct v4l2_requestbuffers *v_bufrequest) 265{ 266 v_bufrequest->memory = V4L2_MEMORY_USERPTR; 267 if (ioctl(vid->fd, VIDIOC_REQBUFS, v_bufrequest) == 0) { 268 vid->capture.userptr = true; 269 return 0; 270 } 271 272 V4L2_DEBUG(vid, "info: Driver does not handle userptr buffers."); 273 return -1; 274} 275 276static int 277v4l2_try_mmap(struct v4l2_fs *vid, struct v4l2_requestbuffers *v_bufrequest) 278{ 279 v_bufrequest->memory = V4L2_MEMORY_MMAP; 280 if (ioctl(vid->fd, VIDIOC_REQBUFS, v_bufrequest) == 0) { 281 vid->capture.mmap = true; 282 return 0; 283 } 284 285 V4L2_DEBUG(vid, "info: Driver does not mmap userptr buffers."); 286 return -1; 287} 288 289static int 290v4l2_setup_mmap_buffer(struct v4l2_fs *vid, struct v4l2_frame *vf, struct v4l2_buffer *v_buf) 291{ 292 void *ptr = mmap(0, v_buf->length, PROT_READ, MAP_SHARED, vid->fd, v_buf->m.offset); 293 if (ptr == MAP_FAILED) { 294 V4L2_ERROR(vid, "error: Call to mmap failed!"); 295 return -1; 296 } 297 298 vf->mem = ptr; 299 300 return 0; 301} 302 303static int 304v4l2_setup_userptr_buffer(struct v4l2_fs *vid, struct v4l2_frame *vf, struct v4l2_buffer *v_buf) 305{ 306 // align this to a memory page, v4l2 likes it that way 307 long sz = sysconf(_SC_PAGESIZE); 308 size_t size = align_up(v_buf->length, (size_t)sz); 309 310 void *ptr = aligned_alloc(sz, size); 311 if (ptr == NULL) { 312 V4L2_ERROR(vid, "error: Could not alloc page-aligned memory!"); 313 return -1; 314 } 315 316 vf->mem = ptr; 317 v_buf->m.userptr = (intptr_t)ptr; 318 319 return 0; 320} 321 322 323/* 324 * 325 * Mode adding functions. 326 * 327 */ 328 329static struct v4l2_source_descriptor * 330v4l2_add_descriptor(struct v4l2_fs *vid) 331{ 332 uint32_t index = vid->num_descriptors++; 333 U_ARRAY_REALLOC_OR_FREE(vid->descriptors, struct v4l2_source_descriptor, vid->num_descriptors); 334 335 struct v4l2_source_descriptor *desc = &vid->descriptors[index]; 336 U_ZERO(desc); 337 338 return desc; 339} 340 341static void 342v4l2_list_modes_interval(struct v4l2_fs *vid, 343 const struct v4l2_fmtdesc *fmt, 344 const struct v4l2_frmsizeenum *size, 345 const struct v4l2_frmivalenum *interval) 346{ 347 if (interval->discrete.denominator % interval->discrete.numerator == 0) { 348 int fps = interval->discrete.denominator / interval->discrete.numerator; 349 350 V4L2_DEBUG(vid, "#%i %dx%d@%i", vid->num_descriptors, interval->width, interval->height, fps); 351 } else { 352 double fps = (double)interval->discrete.denominator / (double)interval->discrete.numerator; 353 354 V4L2_DEBUG(vid, "#%i %dx%d@%f", vid->num_descriptors, interval->width, interval->height, fps); 355 } 356} 357 358static void 359v4l2_list_modes_size(struct v4l2_fs *vid, const struct v4l2_fmtdesc *fmt, const struct v4l2_frmsizeenum *size) 360{ 361 if (size->type != V4L2_FRMSIZE_TYPE_DISCRETE) { 362 V4L2_DEBUG(vid, "warning: Skipping non discrete frame size."); 363 return; 364 } 365 366 struct v4l2_frmivalenum interval; 367 U_ZERO(&interval); 368 interval.pixel_format = size->pixel_format; 369 interval.width = size->discrete.width; 370 interval.height = size->discrete.height; 371 372 // Since we don't keep track of the interval 373 // we only make sure there is at least one. 374 while (ioctl(vid->fd, VIDIOC_ENUM_FRAMEINTERVALS, &interval) == 0) { 375 v4l2_list_modes_interval(vid, fmt, size, &interval); 376 interval.index++; 377 } 378 379 // We didn't find any frame intervals. 380 if (interval.index == 0) { 381 return; 382 } 383 384 enum xrt_format format = (enum xrt_format)0; 385 switch (interval.pixel_format) { 386 case V4L2_PIX_FMT_YUYV: format = XRT_FORMAT_YUYV422; break; 387 case V4L2_PIX_FMT_UYVY: format = XRT_FORMAT_UYVY422; break; 388 case V4L2_PIX_FMT_MJPEG: format = XRT_FORMAT_MJPEG; break; 389 case V4L2_PIX_FMT_SGRBG8: format = XRT_FORMAT_BAYER_GR8; break; 390 default: V4L2_ERROR(vid, "error: Format not supported."); return; 391 } 392 393 // Allocate new descriptor. 394 struct v4l2_source_descriptor *desc = v4l2_add_descriptor(vid); 395 396 // Fill out the stream variables. 397 desc->stream.width = interval.width; 398 desc->stream.height = interval.height; 399 desc->stream.format = interval.pixel_format; 400 snprintf(desc->format_name, sizeof(desc->format_name), "%s", fmt->description); 401 402 if (u_format_is_blocks(format)) { 403 u_format_size_for_dimensions(format, interval.width, interval.height, &desc->stream.stride, 404 &desc->stream.size); 405 } 406 407 // Fill out the out sink variables. 408 desc->base.stereo_format = XRT_STEREO_FORMAT_NONE; 409 desc->base.format = format; 410 desc->base.width = desc->stream.width; 411 desc->base.height = desc->stream.height; 412} 413 414static void 415v4l2_list_modes_fmt(struct v4l2_fs *vid, const struct v4l2_fmtdesc *fmt) 416{ 417 V4L2_DEBUG(vid, "format: %s %08x %d", fmt->description, fmt->pixelformat, fmt->type); 418 419 switch (fmt->pixelformat) { 420 case V4L2_PIX_FMT_YUYV: break; 421 case V4L2_PIX_FMT_UYVY: break; 422 case V4L2_PIX_FMT_MJPEG: break; 423 case V4L2_PIX_FMT_SGRBG8: break; 424 default: V4L2_ERROR(vid, "error: Unknown pixelformat '%s' '%08x'", fmt->description, fmt->pixelformat); return; 425 } 426 427 struct v4l2_frmsizeenum size = {0}; 428 size.pixel_format = fmt->pixelformat; 429 430 while (ioctl(vid->fd, VIDIOC_ENUM_FRAMESIZES, &size) == 0) { 431 v4l2_list_modes_size(vid, fmt, &size); 432 size.index++; 433 } 434} 435 436static void 437v4l2_list_modes(struct v4l2_fs *vid) 438{ 439 struct v4l2_fmtdesc desc; 440 U_ZERO(&desc); 441 desc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 442 443 while (ioctl(vid->fd, VIDIOC_ENUM_FMT, &desc) == 0) { 444 v4l2_list_modes_fmt(vid, &desc); 445 desc.index++; 446 } 447} 448 449static void 450v4l2_set_control_if_diff(struct v4l2_fs *vid, struct v4l2_control_state *state) 451{ 452 int value = 0; 453 int ret = 0; 454 455 struct v4l2_state_want *want = &state->want[vid->capture_type]; 456 if (!want->active) { 457 return; 458 } 459 460 ret = v4l2_control_get(vid, state->id, &value); 461 if (ret != 0) { 462 return; 463 } 464 465 if (value == want->value && state->force <= 0) { 466 return; 467 } 468 469#if 0 470 dump_contron_name(state->id); 471 472 U_LOG_E(" ret: %i, want: %i, was: %i, force: %i", ret, 473 state->want, value, state->force); 474#endif 475 476 ret = v4l2_control_set(vid, state->id, want->value); 477 if (ret != 0) { 478 fprintf(stderr, "Failed to set "); 479 dump_contron_name(state->id); 480 fprintf(stderr, "\n"); 481 return; 482 } 483 484 if (state->force > 0) { 485 state->force--; 486 } 487} 488 489static void 490v4l2_update_controls(struct v4l2_fs *vid) 491{ 492 for (size_t i = 0; i < vid->num_states; i++) { 493 v4l2_set_control_if_diff(vid, &vid->states[i]); 494 } 495} 496 497 498bool 499v4l2_fs_setup_format(struct v4l2_fs *vid) 500{ 501 if (vid->fd == -1) { 502 V4L2_ERROR(vid, "error: Device not opened!"); 503 return false; 504 } 505 506 507 struct v4l2_source_descriptor *desc = &vid->descriptors[vid->selected]; 508 509 struct v4l2_format v_format; 510 U_ZERO(&v_format); 511 v_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 512 v_format.fmt.pix.width = desc->stream.width; 513 v_format.fmt.pix.height = desc->stream.height; 514 v_format.fmt.pix.pixelformat = desc->stream.format; 515 v_format.fmt.pix.field = V4L2_FIELD_ANY; 516 if (vid->has.extended_format) { 517 v_format.fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; 518 } 519 520 if (ioctl(vid->fd, VIDIOC_S_FMT, &v_format) < 0) { 521 V4L2_ERROR(vid, "Could not set up format!"); 522 return false; 523 } 524 return true; 525} 526 527 528/* 529 * 530 * Exported functions. 531 * 532 */ 533 534static bool 535v4l2_fs_enumerate_modes(struct xrt_fs *xfs, struct xrt_fs_mode **out_modes, uint32_t *out_count) 536{ 537 struct v4l2_fs *vid = v4l2_fs(xfs); 538 if (vid->num_descriptors == 0) { 539 return false; 540 } 541 542 struct xrt_fs_mode *modes = U_TYPED_ARRAY_CALLOC(struct xrt_fs_mode, vid->num_descriptors); 543 if (modes == NULL) { 544 return false; 545 } 546 547 for (uint32_t i = 0; i < vid->num_descriptors; i++) { 548 modes[i] = vid->descriptors[i].base; 549 } 550 551 *out_modes = modes; 552 *out_count = vid->num_descriptors; 553 554 return true; 555} 556 557static bool 558v4l2_fs_configure_capture(struct xrt_fs *xfs, struct xrt_fs_capture_parameters *cp) 559{ 560 // struct v4l2_fs *vid = v4l2_fs(xfs); 561 //! @todo 562 return false; 563} 564 565static bool 566v4l2_fs_stream_start(struct xrt_fs *xfs, 567 struct xrt_frame_sink *xs, 568 enum xrt_fs_capture_type capture_type, 569 uint32_t descriptor_index) 570{ 571 struct v4l2_fs *vid = v4l2_fs(xfs); 572 573 if (descriptor_index >= vid->num_descriptors) { 574 V4L2_ERROR(vid, "error Invalid descriptor_index (%i >= %i)", descriptor_index, vid->num_descriptors); 575 return false; 576 } 577 vid->selected = descriptor_index; 578 579 vid->sink = xs; 580 vid->is_running = true; 581 vid->capture_type = capture_type; 582 583 if (!v4l2_fs_setup_format(vid)) { 584 vid->is_running = false; 585 return false; 586 } 587 588 if (pthread_create(&vid->stream_thread, NULL, v4l2_fs_mainloop, xfs)) { 589 vid->is_running = false; 590 V4L2_ERROR(vid, "error: Could not create thread"); 591 return false; 592 } 593 594 V4L2_TRACE(vid, "info: Started!"); 595 596 // we're off to the races! 597 return true; 598} 599 600static bool 601v4l2_fs_stream_stop(struct xrt_fs *xfs) 602{ 603 struct v4l2_fs *vid = v4l2_fs(xfs); 604 605 if (!vid->is_running) { 606 return true; 607 } 608 609 vid->is_running = false; 610 pthread_join(vid->stream_thread, NULL); 611 612 return true; 613} 614 615static bool 616v4l2_fs_is_running(struct xrt_fs *xfs) 617{ 618 struct v4l2_fs *vid = v4l2_fs(xfs); 619 620 return vid->is_running; 621} 622 623static void 624v4l2_fs_destroy(struct v4l2_fs *vid) 625{ 626 // Make sure that the stream is stopped. 627 v4l2_fs_stream_stop(&vid->base); 628 629 // Stop the variable tracking. 630 u_var_remove_root(vid); 631 u_sink_debug_destroy(&vid->usd); 632 633 if (vid->descriptors != NULL) { 634 free(vid->descriptors); 635 vid->descriptors = NULL; 636 vid->num_descriptors = 0; 637 } 638 639 vid->capture.mmap = false; 640 if (vid->capture.userptr) { 641 vid->capture.userptr = false; 642 for (uint32_t i = 0; i < NUM_V4L2_BUFFERS; i++) { 643 free(vid->frames[i].mem); 644 vid->frames[i].mem = NULL; 645 } 646 } 647 648 if (vid->fd >= 0) { 649 close(vid->fd); 650 vid->fd = -1; 651 } 652 653 free(vid); 654} 655 656static void 657v4l2_fs_node_break_apart(struct xrt_frame_node *node) 658{ 659 struct v4l2_fs *vid = container_of(node, struct v4l2_fs, node); 660 v4l2_fs_stream_stop(&vid->base); 661} 662 663static void 664v4l2_fs_node_destroy(struct xrt_frame_node *node) 665{ 666 struct v4l2_fs *vid = container_of(node, struct v4l2_fs, node); 667 v4l2_fs_destroy(vid); 668} 669 670struct xrt_fs * 671v4l2_fs_create(struct xrt_frame_context *xfctx, 672 const char *path, 673 const char *product, 674 const char *manufacturer, 675 const char *serial) 676{ 677 struct v4l2_fs *vid = U_TYPED_CALLOC(struct v4l2_fs); 678 vid->base.enumerate_modes = v4l2_fs_enumerate_modes; 679 vid->base.configure_capture = v4l2_fs_configure_capture; 680 vid->base.stream_start = v4l2_fs_stream_start; 681 vid->base.stream_stop = v4l2_fs_stream_stop; 682 vid->base.is_running = v4l2_fs_is_running; 683 vid->node.break_apart = v4l2_fs_node_break_apart; 684 vid->node.destroy = v4l2_fs_node_destroy; 685 vid->log_level = debug_get_log_option_v4l2_log(); 686 vid->fd = -1; 687 688 snprintf(vid->base.product, sizeof(vid->base.product), "%s", product); 689 snprintf(vid->base.manufacturer, sizeof(vid->base.manufacturer), "%s", manufacturer); 690 snprintf(vid->base.serial, sizeof(vid->base.serial), "%s", serial); 691 692 int fd = open(path, O_RDWR, 0); 693 if (fd < 0) { 694 V4L2_ERROR(vid, "Cannot open '%s'", path); 695 free(vid); 696 return NULL; 697 } 698 699 vid->fd = fd; 700 701 int ret = v4l2_query_cap_and_validate(vid); 702 if (ret != 0) { 703 v4l2_fs_destroy(vid); 704 vid = NULL; 705 return NULL; 706 } 707 708 // It's now safe to add it to the context. 709 xrt_frame_context_add(xfctx, &vid->node); 710 711 // Start the variable tracking after we know what device we have. 712 u_sink_debug_init(&vid->usd); 713 u_var_add_root(vid, "V4L2 Frameserver", true); 714 u_var_add_ro_text(vid, vid->base.name, "Card"); 715 u_var_add_log_level(vid, &vid->log_level, "Log Level"); 716 for (size_t i = 0; i < vid->num_states; i++) { 717 u_var_add_i32(vid, &vid->states[i].want[0].value, vid->states[i].name); 718 } 719 u_var_add_sink_debug(vid, &vid->usd, "Output"); 720 721 v4l2_list_modes(vid); 722 723 return &(vid->base); 724} 725 726void * 727v4l2_fs_mainloop(void *ptr) 728{ 729 U_TRACE_SET_THREAD_NAME("V4L2"); 730 731 struct xrt_fs *xfs = (struct xrt_fs *)ptr; 732 struct v4l2_fs *vid = v4l2_fs(xfs); 733 734 V4L2_DEBUG(vid, "info: Thread enter!"); 735 736 if (vid->fd == -1) { 737 V4L2_ERROR(vid, "error: Device not opened!"); 738 return NULL; 739 } 740 741 struct v4l2_source_descriptor *desc = &vid->descriptors[vid->selected]; 742 743 // set up our buffers - prefer userptr (client alloc) vs mmap (kernel 744 // alloc) 745 // TODO: using buffer caps may be better than 'fallthrough to mmap' 746 struct v4l2_requestbuffers v_bufrequest; 747 U_ZERO(&v_bufrequest); 748 v_bufrequest.count = NUM_V4L2_BUFFERS; 749 v_bufrequest.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 750 751 if (v4l2_try_userptr(vid, &v_bufrequest) != 0 && v4l2_try_mmap(vid, &v_bufrequest) != 0) { 752 V4L2_ERROR(vid, "error: Driver does not support mmap or userptr."); 753 return NULL; 754 } 755 756 757 for (uint32_t i = 0; i < NUM_V4L2_BUFFERS; i++) { 758 struct v4l2_frame *vf = &vid->frames[i]; 759 struct v4l2_buffer *v_buf = &vf->v_buf; 760 761 vf->base.owner = vid; 762 vf->base.destroy = v4l2_free_frame; 763 764 v_buf->index = i; 765 v_buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 766 v_buf->memory = v_bufrequest.memory; 767 768 if (ioctl(vid->fd, VIDIOC_QUERYBUF, v_buf) < 0) { 769 V4L2_ERROR(vid, "error: Could not query buffers!"); 770 return NULL; 771 } 772 773 if (vid->capture.userptr && v4l2_setup_userptr_buffer(vid, vf, v_buf) != 0) { 774 return NULL; 775 } 776 if (vid->capture.mmap && v4l2_setup_mmap_buffer(vid, vf, v_buf) != 0) { 777 return NULL; 778 } 779 780 // Silence valgrind. 781 memset(vf->mem, 0, v_buf->length); 782 783 // Queue this buffer 784 if (ioctl(vid->fd, VIDIOC_QBUF, v_buf) < 0) { 785 V4L2_ERROR(vid, "error: queueing buffer failed!"); 786 return NULL; 787 } 788 } 789 790 int start_capture = V4L2_BUF_TYPE_VIDEO_CAPTURE; 791 if (ioctl(vid->fd, VIDIOC_STREAMON, &start_capture) < 0) { 792 V4L2_ERROR(vid, "error: Could not start capture!"); 793 return NULL; 794 } 795 796 /* 797 * Need to set these after we have started the stream. 798 */ 799 v4l2_update_controls(vid); 800 801 struct v4l2_buffer v_buf = {0}; 802 v_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 803 v_buf.memory = v_bufrequest.memory; 804 805 while (vid->is_running) { 806 if (vid->used_frames == NUM_V4L2_BUFFERS) { 807 V4L2_ERROR(vid, "No frames left"); 808 } 809 810 if (ioctl(vid->fd, VIDIOC_DQBUF, &v_buf) < 0) { 811 V4L2_ERROR(vid, "error: Dequeue failed!"); 812 vid->is_running = false; 813 break; 814 } 815 816 v4l2_update_controls(vid); 817 818 SINK_TRACE_IDENT(v4l2_fs_frame); 819 820 V4L2_TRACE(vid, "Got frame #%u, index %i. Used frames are %i", v_buf.sequence, v_buf.index, 821 vid->used_frames); 822 823 struct v4l2_frame *vf = &vid->frames[v_buf.index]; 824 struct xrt_frame *xf = NULL; 825 826 xrt_frame_reference(&xf, &vf->base); 827 uint8_t *data = (uint8_t *)vf->mem; 828 829 //! @todo Sequence number and timestamp. 830 xf->width = desc->base.width; 831 xf->height = desc->base.height; 832 xf->format = desc->base.format; 833 xf->stereo_format = desc->base.stereo_format; 834 835 xf->data = data + desc->offset; 836 xf->stride = desc->stream.stride; 837 xf->size = v_buf.bytesused - desc->offset; 838 xf->source_id = vid->base.source_id; 839 xf->source_sequence = v_buf.sequence; 840 841 if ((v_buf.flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) != 0) { 842 xf->timestamp = os_timeval_to_ns(&v_buf.timestamp); 843 xf->source_timestamp = xf->timestamp; 844 } 845 846 vid->sink->push_frame(vid->sink, xf); 847 848 // Checks if active. 849 u_sink_debug_push_frame(&vid->usd, xf); 850 851 vid->used_frames++; 852 853 // The frame is requeued as soon as the refcount reaches zero, 854 // this can be done safely from another thread. 855 xrt_frame_reference(&xf, NULL); 856 } 857 858 V4L2_DEBUG(vid, "info: Thread leave!"); 859 860 return NULL; 861} 862 863 864/* 865 * 866 * Helper debug functions. 867 * 868 */ 869 870static void 871dump_integer(struct v4l2_fs *vid, struct v4l2_queryctrl *queryctrl) 872{ 873 U_LOG_D(" Type: Integer"); 874 U_LOG_D(" min: %i, max: %i, step: %i.", queryctrl->minimum, queryctrl->maximum, queryctrl->step); 875} 876 877static void 878dump_menu(struct v4l2_fs *vid, uint32_t id, uint32_t min, uint32_t max) 879{ 880 U_LOG_D(" Menu items:"); 881 882 struct v4l2_querymenu querymenu = {0}; 883 querymenu.id = id; 884 885 for (querymenu.index = min; querymenu.index <= max; querymenu.index++) { 886 if (0 != ioctl(vid->fd, VIDIOC_QUERYMENU, &querymenu)) { 887 U_LOG_D(" %i", querymenu.index); 888 continue; 889 } 890 U_LOG_D(" %i: %s", querymenu.index, querymenu.name); 891 } 892} 893 894static void 895dump_contron_name(uint32_t id) 896{ 897 const char *str = "ERROR"; 898 switch (id) { 899#define CASE(CONTROL) \ 900 case V4L2_CID_##CONTROL: str = "V4L2_CID_" #CONTROL; break 901 CASE(BRIGHTNESS); 902 CASE(CONTRAST); 903 CASE(SATURATION); 904 CASE(HUE); 905 CASE(AUDIO_VOLUME); 906 CASE(AUDIO_BALANCE); 907 CASE(AUDIO_BASS); 908 CASE(AUDIO_TREBLE); 909 CASE(AUDIO_MUTE); 910 CASE(AUDIO_LOUDNESS); 911 CASE(BLACK_LEVEL); 912 CASE(AUTO_WHITE_BALANCE); 913 CASE(DO_WHITE_BALANCE); 914 CASE(RED_BALANCE); 915 CASE(BLUE_BALANCE); 916 CASE(GAMMA); 917 918 CASE(EXPOSURE); 919 CASE(AUTOGAIN); 920 CASE(GAIN); 921#ifdef V4L2_CID_DIGITAL_GAIN 922 CASE(DIGITAL_GAIN); 923#endif 924 CASE(ANALOGUE_GAIN); 925 CASE(HFLIP); 926 CASE(VFLIP); 927 CASE(POWER_LINE_FREQUENCY); 928 CASE(POWER_LINE_FREQUENCY_DISABLED); 929 CASE(POWER_LINE_FREQUENCY_50HZ); 930 CASE(POWER_LINE_FREQUENCY_60HZ); 931 CASE(POWER_LINE_FREQUENCY_AUTO); 932 CASE(HUE_AUTO); 933 CASE(WHITE_BALANCE_TEMPERATURE); 934 CASE(SHARPNESS); 935 CASE(BACKLIGHT_COMPENSATION); 936 CASE(CHROMA_AGC); 937 CASE(CHROMA_GAIN); 938 CASE(COLOR_KILLER); 939 CASE(COLORFX); 940 CASE(COLORFX_CBCR); 941 CASE(AUTOBRIGHTNESS); 942 CASE(ROTATE); 943 CASE(BG_COLOR); 944 CASE(ILLUMINATORS_1); 945 CASE(ILLUMINATORS_2); 946 CASE(MIN_BUFFERS_FOR_CAPTURE); 947 CASE(MIN_BUFFERS_FOR_OUTPUT); 948 CASE(ALPHA_COMPONENT); 949 950 // Camera controls 951 CASE(EXPOSURE_AUTO); 952 CASE(EXPOSURE_ABSOLUTE); 953 CASE(EXPOSURE_AUTO_PRIORITY); 954 CASE(AUTO_EXPOSURE_BIAS); 955 CASE(PAN_RELATIVE); 956 CASE(TILT_RELATIVE); 957 CASE(PAN_RESET); 958 CASE(TILT_RESET); 959 CASE(PAN_ABSOLUTE); 960 CASE(TILT_ABSOLUTE); 961 CASE(FOCUS_ABSOLUTE); 962 CASE(FOCUS_RELATIVE); 963 CASE(FOCUS_AUTO); 964 CASE(ZOOM_ABSOLUTE); 965 CASE(ZOOM_RELATIVE); 966 CASE(ZOOM_CONTINUOUS); 967 CASE(PRIVACY); 968 CASE(IRIS_ABSOLUTE); 969 CASE(IRIS_RELATIVE); 970#undef CASE 971 default: fprintf(stderr, "0x%08x", id); return; 972 } 973 fprintf(stderr, "%s", str); 974} 975 976static void 977dump_controls(struct v4l2_fs *vid) 978{ 979 struct v4l2_queryctrl queryctrl = {0}; 980 981 queryctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; 982 while (0 == ioctl(vid->fd, VIDIOC_QUERYCTRL, &queryctrl)) { 983 fprintf(stderr, "Control "); 984 dump_contron_name(queryctrl.id); 985 fprintf(stderr, " '%s'", queryctrl.name); 986 987#define V_CHECK(FLAG) \ 988 do { \ 989 if (queryctrl.flags & V4L2_CTRL_FLAG_##FLAG) { \ 990 fprintf(stderr, ", " #FLAG); \ 991 } \ 992 } while (false) 993 994 V_CHECK(DISABLED); 995 V_CHECK(GRABBED); 996 V_CHECK(READ_ONLY); 997 V_CHECK(UPDATE); 998 V_CHECK(INACTIVE); 999 V_CHECK(SLIDER); 1000 V_CHECK(WRITE_ONLY); 1001 V_CHECK(VOLATILE); 1002 V_CHECK(HAS_PAYLOAD); 1003 V_CHECK(EXECUTE_ON_WRITE); 1004#ifdef V4L2_CTRL_FLAG_MODIFY_LAYOUT 1005 V_CHECK(MODIFY_LAYOUT); 1006#endif 1007#undef V_CHECK 1008 1009 U_LOG_E(" "); 1010 1011 switch (queryctrl.type) { 1012 case V4L2_CTRL_TYPE_BOOLEAN: U_LOG_D(" Type: Boolean"); break; 1013 case V4L2_CTRL_TYPE_INTEGER: dump_integer(vid, &queryctrl); break; 1014 case V4L2_CTRL_TYPE_INTEGER64: U_LOG_D(" Type: Integer64"); break; 1015 case V4L2_CTRL_TYPE_BUTTON: U_LOG_D(" Type: Buttons"); break; 1016 case V4L2_CTRL_TYPE_MENU: dump_menu(vid, queryctrl.id, queryctrl.minimum, queryctrl.maximum); break; 1017 case V4L2_CTRL_TYPE_STRING: U_LOG_D(" Type: String"); break; 1018 default: U_LOG_D(" Type: Unknown"); break; 1019 } 1020 1021 if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) { 1022 continue; 1023 } 1024 1025 queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; 1026 } 1027}