1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //#define OVERLAY_DEBUG 1 18 #define LOG_TAG "Overlay" 19 20 #include <fcntl.h> 21 #include <errno.h> 22 #include <cutils/log.h> 23 #include <hardware/overlay.h> 24 #include <linux/videodev.h> 25 #include <sys/ioctl.h> 26 #include <sys/mman.h> 27 #include "v4l2_utils.h" 28 29 #define LOG_FUNCTION_NAME LOGV("%s: %s", __FILE__, __FUNCTION__); 30 31 #ifndef LOGE 32 #define LOGE(fmt,args...) \ 33 do { printf(fmt, ##args); } \ 34 while (0) 35 #endif 36 37 #ifndef LOGI 38 #define LOGI(fmt,args...) \ 39 do { LOGE(fmt, ##args); } \ 40 while (0) 41 #endif 42 #define V4L2_CID_PRIV_OFFSET 0x00530000 43 #define V4L2_CID_PRIV_ROTATION (V4L2_CID_PRIVATE_BASE \ 44 + V4L2_CID_PRIV_OFFSET + 0) 45 #define V4L2_CID_PRIV_COLORKEY (V4L2_CID_PRIVATE_BASE \ 46 + V4L2_CID_PRIV_OFFSET + 1) 47 #define V4L2_CID_PRIV_COLORKEY_EN (V4L2_CID_PRIVATE_BASE \ 48 + V4L2_CID_PRIV_OFFSET + 2) 49 50 51 52 int v4l2_overlay_get(int name) { 53 int result = -1; 54 switch (name) { 55 case OVERLAY_MINIFICATION_LIMIT: 56 result = 4; // 0 = no limit 57 break; 58 case OVERLAY_MAGNIFICATION_LIMIT: 59 result = 2; // 0 = no limit 60 break; 61 case OVERLAY_SCALING_FRAC_BITS: 62 result = 0; // 0 = infinite 63 break; 64 case OVERLAY_ROTATION_STEP_DEG: 65 result = 90; // 90 rotation steps (for instance) 66 break; 67 case OVERLAY_HORIZONTAL_ALIGNMENT: 68 result = 1; // 1-pixel alignment 69 break; 70 case OVERLAY_VERTICAL_ALIGNMENT: 71 result = 1; // 1-pixel alignment 72 break; 73 case OVERLAY_WIDTH_ALIGNMENT: 74 result = 1; // 1-pixel alignment 75 break; 76 case OVERLAY_HEIGHT_ALIGNMENT: 77 result = 1; // 1-pixel alignment 78 break; 79 } 80 return result; 81 } 82 83 int v4l2_overlay_open(int id) 84 { 85 LOG_FUNCTION_NAME 86 87 if (id == V4L2_OVERLAY_PLANE_VIDEO1) 88 return open("/dev/video1", O_RDWR); 89 else if (id == V4L2_OVERLAY_PLANE_VIDEO2) 90 return open("/dev/video2", O_RDWR); 91 return -EINVAL; 92 } 93 94 void dump_pixfmt(struct v4l2_pix_format *pix) 95 { 96 LOGI("w: %d\n", pix->width); 97 LOGI("h: %d\n", pix->height); 98 LOGI("color: %x\n", pix->colorspace); 99 switch (pix->pixelformat) { 100 case V4L2_PIX_FMT_YUYV: 101 LOGI ("YUYV\n"); 102 break; 103 case V4L2_PIX_FMT_UYVY: 104 LOGI ("UYVY\n"); 105 break; 106 case V4L2_PIX_FMT_RGB565: 107 LOGI ("RGB565\n"); 108 break; 109 case V4L2_PIX_FMT_RGB565X: 110 LOGI ("RGB565X\n"); 111 break; 112 default: 113 LOGI("not supported\n"); 114 } 115 } 116 117 void dump_crop(struct v4l2_crop *crop) 118 { 119 LOGI("crop l: %d ", crop->c.left); 120 LOGI("crop t: %d ", crop->c.top); 121 LOGI("crop w: %d ", crop->c.width); 122 LOGI("crop h: %d\n", crop->c.height); 123 } 124 125 void dump_window(struct v4l2_window *win) 126 { 127 LOGI("window l: %d ", win->w.left); 128 LOGI("window t: %d ", win->w.top); 129 LOGI("window w: %d ", win->w.width); 130 LOGI("window h: %d\n", win->w.height); 131 } 132 void v4l2_overlay_dump_state(int fd) 133 { 134 struct v4l2_format format; 135 struct v4l2_crop crop; 136 int ret; 137 138 LOGI("dumping driver state:"); 139 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 140 ret = ioctl(fd, VIDIOC_G_FMT, &format); 141 if (ret < 0) 142 return; 143 LOGI("output pixfmt:\n"); 144 dump_pixfmt(&format.fmt.pix); 145 146 format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; 147 ret = ioctl(fd, VIDIOC_G_FMT, &format); 148 if (ret < 0) 149 return; 150 LOGI("v4l2_overlay window:\n"); 151 dump_window(&format.fmt.win); 152 153 crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 154 ret = ioctl(fd, VIDIOC_G_CROP, &crop); 155 if (ret < 0) 156 return; 157 LOGI("output crop:\n"); 158 dump_crop(&crop); 159 /* 160 crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 161 ret = ioctl(fd, VIDIOC_G_CROP, &crop); 162 if (ret < 0) 163 return; 164 LOGI("ovelay crop:\n"); 165 dump_crop(&crop); 166 */ 167 } 168 169 static void error(int fd, const char *msg) 170 { 171 LOGE("Error = %s from %s", strerror(errno), msg); 172 #ifdef OVERLAY_DEBUG 173 v4l2_overlay_dump_state(fd); 174 #endif 175 } 176 177 static int v4l2_overlay_ioctl(int fd, int req, void *arg, const char* msg) 178 { 179 int ret; 180 ret = ioctl(fd, req, arg); 181 if (ret < 0) { 182 error(fd, msg); 183 return -1; 184 } 185 return 0; 186 } 187 188 int configure_pixfmt(struct v4l2_pix_format *pix, int32_t fmt, 189 uint32_t w, uint32_t h) 190 { 191 LOG_FUNCTION_NAME 192 193 int fd; 194 195 switch (fmt) { 196 case OVERLAY_FORMAT_RGB_565: 197 pix->pixelformat = V4L2_PIX_FMT_RGB565; 198 break; 199 case OVERLAY_FORMAT_YCbYCr_422_I: 200 pix->pixelformat = V4L2_PIX_FMT_YUYV; 201 break; 202 case OVERLAY_FORMAT_CbYCrY_422_I: 203 pix->pixelformat = V4L2_PIX_FMT_UYVY; 204 break; 205 default: 206 return -1; 207 } 208 pix->width = w; 209 pix->height = h; 210 return 0; 211 } 212 213 static void configure_window(struct v4l2_window *win, int32_t w, 214 int32_t h, int32_t x, int32_t y) 215 { 216 LOG_FUNCTION_NAME 217 218 win->w.left = x; 219 win->w.top = y; 220 win->w.width = w; 221 win->w.height = h; 222 } 223 224 void get_window(struct v4l2_format *format, int32_t *x, 225 int32_t *y, int32_t *w, int32_t *h) 226 { 227 LOG_FUNCTION_NAME 228 229 *x = format->fmt.win.w.left; 230 *y = format->fmt.win.w.top; 231 *w = format->fmt.win.w.width; 232 *h = format->fmt.win.w.height; 233 } 234 235 int v4l2_overlay_init(int fd, uint32_t w, uint32_t h, uint32_t fmt) 236 { 237 LOG_FUNCTION_NAME 238 239 struct v4l2_format format; 240 int ret; 241 242 /* configure the v4l2_overlay framebuffer */ 243 /* 244 ret = v4l2_overlay_ioctl(fd, VIDIOC_G_FBUF, &fbuf, "get fbuf"); 245 if (ret) 246 return ret; 247 if (fbuf.fmt.pixelformat != dst_format) { 248 fbuf.fmt.pixelformat = dst_format; 249 ret = v4l2_overlay_ioctl(fd, VIDIOC_S_FBUF, &fbuf, "set fbuf"); 250 if (ret) 251 return ret; 252 } 253 */ 254 255 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 256 ret = v4l2_overlay_ioctl(fd, VIDIOC_G_FMT, &format, "get format"); 257 if (ret) 258 return ret; 259 LOGI("v4l2_overlay_init:: w=%d h=%d\n", format.fmt.pix.width, format.fmt.pix.height); 260 261 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 262 configure_pixfmt(&format.fmt.pix, fmt, w, h); 263 LOGI("v4l2_overlay_init:: w=%d h=%d\n", format.fmt.pix.width, format.fmt.pix.height); 264 ret = v4l2_overlay_ioctl(fd, VIDIOC_S_FMT, &format, "set output format"); 265 266 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 267 ret = v4l2_overlay_ioctl(fd, VIDIOC_G_FMT, &format, "get output format"); 268 LOGI("v4l2_overlay_init:: w=%d h=%d\n", format.fmt.pix.width, format.fmt.pix.height); 269 return ret; 270 } 271 272 int v4l2_overlay_get_input_size_and_format(int fd, uint32_t *w, uint32_t *h, uint32_t *fmt) 273 { 274 LOG_FUNCTION_NAME 275 276 struct v4l2_format format; 277 int ret; 278 279 format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 280 ret = v4l2_overlay_ioctl(fd, VIDIOC_G_FMT, &format, "get format"); 281 *w = format.fmt.pix.width; 282 *h = format.fmt.pix.height; 283 //if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) 284 if (format.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) 285 *fmt = OVERLAY_FORMAT_CbYCrY_422_I; 286 else return -EINVAL; 287 return ret; 288 } 289 290 int v4l2_overlay_set_position(int fd, int32_t x, int32_t y, int32_t w, int32_t h) 291 { 292 LOG_FUNCTION_NAME 293 294 struct v4l2_format format; 295 int ret; 296 297 /* configure the src format pix */ 298 /* configure the dst v4l2_overlay window */ 299 format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; 300 ret = v4l2_overlay_ioctl(fd, VIDIOC_G_FMT, &format, 301 "get v4l2_overlay format"); 302 if (ret) 303 return ret; 304 LOGI("v4l2_overlay_set_position:: w=%d h=%d", format.fmt.win.w.width, format.fmt.win.w.height); 305 306 configure_window(&format.fmt.win, w, h, x, y); 307 308 format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; 309 ret = v4l2_overlay_ioctl(fd, VIDIOC_S_FMT, &format, 310 "set v4l2_overlay format"); 311 LOGI("v4l2_overlay_set_position:: w=%d h=%d", format.fmt.win.w.width, format.fmt.win.w.height); 312 313 if (ret) 314 return ret; 315 v4l2_overlay_dump_state(fd); 316 317 return 0; 318 } 319 320 int v4l2_overlay_get_position(int fd, int32_t *x, int32_t *y, int32_t *w, int32_t *h) 321 { 322 struct v4l2_format format; 323 int ret; 324 325 format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; 326 ret = v4l2_overlay_ioctl(fd, VIDIOC_G_FMT, &format, "get v4l2_overlay format"); 327 if (ret) 328 return ret; 329 get_window(&format, x, y, w, h); 330 return 0; 331 } 332 333 int v4l2_overlay_set_crop(int fd, uint32_t x, uint32_t y, uint32_t w, uint32_t h) 334 { 335 LOG_FUNCTION_NAME 336 337 struct v4l2_crop crop; 338 int ret; 339 340 crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 341 ret = v4l2_overlay_ioctl(fd, VIDIOC_G_CROP, &crop, "get crop"); 342 crop.c.left = x; 343 crop.c.top = y; 344 crop.c.width = w; 345 crop.c.height = h; 346 crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 347 348 return v4l2_overlay_ioctl(fd, VIDIOC_S_CROP, &crop, "set crop"); 349 } 350 351 int v4l2_overlay_get_crop(int fd, uint32_t *x, uint32_t *y, uint32_t *w, uint32_t *h) 352 { 353 LOG_FUNCTION_NAME 354 355 struct v4l2_crop crop; 356 int ret; 357 358 crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 359 ret = v4l2_overlay_ioctl(fd, VIDIOC_G_CROP, &crop, "get crop"); 360 *x = crop.c.left; 361 *y = crop.c.top; 362 *w = crop.c.width; 363 *h = crop.c.height; 364 return ret; 365 } 366 367 int v4l2_overlay_set_rotation(int fd, int degree, int step) 368 { 369 LOG_FUNCTION_NAME 370 371 int ret; 372 struct v4l2_control ctrl; 373 374 ctrl.id = V4L2_CID_ROTATE; 375 ctrl.value = degree; 376 ret = v4l2_overlay_ioctl(fd, VIDIOC_S_CTRL, &ctrl, "set rotation"); 377 378 return ret; 379 } 380 381 int v4l2_overlay_set_colorkey(int fd, int enable, int colorkey) 382 { 383 LOG_FUNCTION_NAME 384 385 int ret; 386 struct v4l2_framebuffer fbuf; 387 struct v4l2_format fmt; 388 389 memset(&fbuf, 0, sizeof(fbuf)); 390 ret = v4l2_overlay_ioctl(fd, VIDIOC_G_FBUF, &fbuf, "get transparency enables"); 391 392 if (ret) 393 return ret; 394 395 if (enable) 396 fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY; 397 else 398 fbuf.flags &= ~V4L2_FBUF_FLAG_CHROMAKEY; 399 400 ret = v4l2_overlay_ioctl(fd, VIDIOC_S_FBUF, &fbuf, "enable colorkey"); 401 402 if (ret) 403 return ret; 404 405 if (enable) 406 407 { 408 memset(&fmt, 0, sizeof(fmt)); 409 fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; 410 ret = v4l2_overlay_ioctl(fd, VIDIOC_G_FMT, &fmt, "get colorkey"); 411 412 if (ret) 413 return ret; 414 415 fmt.fmt.win.chromakey = colorkey & 0xFFFFFF; 416 417 ret = v4l2_overlay_ioctl(fd, VIDIOC_S_FMT, &fmt, "set colorkey"); 418 } 419 420 return ret; 421 } 422 423 int v4l2_overlay_set_global_alpha(int fd, int enable, int alpha) 424 { 425 LOG_FUNCTION_NAME 426 427 int ret; 428 struct v4l2_framebuffer fbuf; 429 struct v4l2_format fmt; 430 431 memset(&fbuf, 0, sizeof(fbuf)); 432 ret = v4l2_overlay_ioctl(fd, VIDIOC_G_FBUF, &fbuf, "get transparency enables"); 433 434 if (ret) 435 return ret; 436 437 if (enable) 438 fbuf.flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; 439 else 440 fbuf.flags &= ~V4L2_FBUF_FLAG_GLOBAL_ALPHA; 441 442 ret = v4l2_overlay_ioctl(fd, VIDIOC_S_FBUF, &fbuf, "enable global alpha"); 443 444 if (ret) 445 return ret; 446 447 if (enable) 448 { 449 memset(&fmt, 0, sizeof(fmt)); 450 fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; 451 ret = v4l2_overlay_ioctl(fd, VIDIOC_G_FMT, &fmt, "get global alpha"); 452 453 if (ret) 454 return ret; 455 456 fmt.fmt.win.global_alpha = alpha & 0xFF; 457 458 ret = v4l2_overlay_ioctl(fd, VIDIOC_S_FMT, &fmt, "set global alpha"); 459 } 460 461 return ret; 462 } 463 464 int v4l2_overlay_set_local_alpha(int fd, int enable) 465 { 466 int ret; 467 struct v4l2_framebuffer fbuf; 468 469 ret = v4l2_overlay_ioctl(fd, VIDIOC_G_FBUF, &fbuf, 470 "get transparency enables"); 471 472 if (ret) 473 return ret; 474 475 if (enable) 476 fbuf.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; 477 else 478 fbuf.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA; 479 480 ret = v4l2_overlay_ioctl(fd, VIDIOC_S_FBUF, &fbuf, "enable global alpha"); 481 482 return ret; 483 } 484 485 int v4l2_overlay_req_buf(int fd, uint32_t *num_bufs, int cacheable_buffers) 486 { 487 LOG_FUNCTION_NAME 488 489 struct v4l2_requestbuffers reqbuf; 490 int ret, i; 491 reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 492 reqbuf.memory = V4L2_MEMORY_MMAP; 493 reqbuf.count = *num_bufs; 494 //reqbuf.reserved[0] = cacheable_buffers; 495 ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf); 496 if (ret < 0) { 497 error(fd, "reqbuf ioctl"); 498 return ret; 499 } 500 LOGI("%d buffers allocated %d requested\n", reqbuf.count, 4); 501 if (reqbuf.count > *num_bufs) { 502 error(fd, "Not enough buffer structs passed to get_buffers"); 503 return -ENOMEM; 504 } 505 *num_bufs = reqbuf.count; 506 LOGI("buffer cookie is %d\n", reqbuf.type); 507 return 0; 508 } 509 510 static int is_mmaped(struct v4l2_buffer *buf) 511 { 512 return buf->flags == V4L2_BUF_FLAG_MAPPED; 513 } 514 515 static int is_queued(struct v4l2_buffer *buf) 516 { 517 /* is either on the input or output queue in the kernel */ 518 return (buf->flags & V4L2_BUF_FLAG_QUEUED) || 519 (buf->flags & V4L2_BUF_FLAG_DONE); 520 } 521 522 static int is_dequeued(struct v4l2_buffer *buf) 523 { 524 /* is on neither input or output queue in kernel */ 525 return (!(buf->flags & V4L2_BUF_FLAG_QUEUED) && 526 !(buf->flags & V4L2_BUF_FLAG_DONE)); 527 } 528 529 int v4l2_overlay_query_buffer(int fd, int index, struct v4l2_buffer *buf) 530 { 531 LOG_FUNCTION_NAME 532 533 memset(buf, 0, sizeof(struct v4l2_buffer)); 534 535 buf->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 536 buf->memory = V4L2_MEMORY_MMAP; 537 buf->index = index; 538 LOGI("query buffer, mem=%u type=%u index=%u\n", buf->memory, buf->type, 539 buf->index); 540 return v4l2_overlay_ioctl(fd, VIDIOC_QUERYBUF, buf, "querybuf ioctl"); 541 } 542 543 int v4l2_overlay_map_buf(int fd, int index, void **start, size_t *len) 544 { 545 LOG_FUNCTION_NAME 546 547 struct v4l2_buffer buf; 548 int ret; 549 550 ret = v4l2_overlay_query_buffer(fd, index, &buf); 551 if (ret) 552 return ret; 553 554 if (is_mmaped(&buf)) { 555 LOGE("Trying to mmap buffers that are already mapped!\n"); 556 return -EINVAL; 557 } 558 559 *len = buf.length; 560 *start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, 561 fd, buf.m.offset); 562 if (*start == MAP_FAILED) { 563 LOGE("map failed, length=%u offset=%u\n", buf.length, buf.m.offset); 564 return -EINVAL; 565 } 566 return 0; 567 } 568 569 int v4l2_overlay_unmap_buf(void *start, size_t len) 570 { 571 LOG_FUNCTION_NAME 572 573 return munmap(start, len); 574 } 575 576 577 int v4l2_overlay_get_caps(int fd, struct v4l2_capability *caps) 578 { 579 return v4l2_overlay_ioctl(fd, VIDIOC_QUERYCAP, caps, "query cap"); 580 } 581 582 int v4l2_overlay_stream_on(int fd) 583 { 584 LOG_FUNCTION_NAME 585 586 int ret; 587 uint32_t type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 588 589 ret = v4l2_overlay_set_local_alpha(fd, 1); 590 if (ret) 591 return ret; 592 593 ret = v4l2_overlay_ioctl(fd, VIDIOC_STREAMON, &type, "stream on"); 594 595 return ret; 596 } 597 598 int v4l2_overlay_stream_off(int fd) 599 { 600 LOG_FUNCTION_NAME 601 602 int ret; 603 uint32_t type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 604 605 ret = v4l2_overlay_set_local_alpha(fd, 0); 606 if (ret) 607 return ret; 608 609 ret = v4l2_overlay_ioctl(fd, VIDIOC_STREAMOFF, &type, "stream off"); 610 611 return ret; 612 } 613 614 int v4l2_overlay_q_buf(int fd, int index) 615 { 616 struct v4l2_buffer buf; 617 int ret; 618 619 /* 620 ret = v4l2_overlay_query_buffer(fd, buffer_cookie, index, &buf); 621 if (ret) 622 return ret; 623 if (is_queued(buf)) { 624 LOGE("Trying to queue buffer to kernel that is already queued!\n"); 625 return -EINVAL 626 } 627 */ 628 buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 629 buf.index = index; 630 buf.memory = V4L2_MEMORY_MMAP; 631 buf.field = V4L2_FIELD_NONE; 632 buf.timestamp.tv_sec = 0; 633 buf.timestamp.tv_usec = 0; 634 buf.flags = 0; 635 636 return v4l2_overlay_ioctl(fd, VIDIOC_QBUF, &buf, "qbuf"); 637 } 638 639 int v4l2_overlay_dq_buf(int fd, int *index) 640 { 641 struct v4l2_buffer buf; 642 int ret; 643 644 /* 645 ret = v4l2_overlay_query_buffer(fd, buffer_cookie, index, &buf); 646 if (ret) 647 return ret; 648 649 if (is_dequeued(buf)) { 650 LOGE("Trying to dequeue buffer that is not in kernel!\n"); 651 return -EINVAL 652 } 653 */ 654 buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 655 buf.memory = V4L2_MEMORY_MMAP; 656 657 ret = v4l2_overlay_ioctl(fd, VIDIOC_DQBUF, &buf, "dqbuf"); 658 if (ret) 659 return ret; 660 *index = buf.index; 661 return 0; 662 } 663