V4LCameraAdapter.cpp revision f7a4d11e9f710e2cd0592310ac1baecccb85f1d1
1/* 2 * Copyright (C) Texas Instruments - http://www.ti.com/ 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/** 18* @file V4LCameraAdapter.cpp 19* 20* This file maps the Camera Hardware Interface to V4L2. 21* 22*/ 23 24 25#include "V4LCameraAdapter.h" 26#include "CameraHal.h" 27#include "TICameraParameters.h" 28#include "DebugUtils.h" 29#include <signal.h> 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33#include <fcntl.h> 34#include <unistd.h> 35#include <errno.h> 36#include <sys/ioctl.h> 37#include <sys/mman.h> 38#include <sys/select.h> 39#include <linux/videodev.h> 40 41#include <ui/GraphicBuffer.h> 42#include <ui/GraphicBufferMapper.h> 43 44#include <cutils/properties.h> 45#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) 46static int mDebugFps = 0; 47 48#define Q16_OFFSET 16 49 50#define HERE(Msg) {CAMHAL_LOGEB("--=== %s===--\n", Msg);} 51 52namespace Ti { 53namespace Camera { 54 55//frames skipped before recalculating the framerate 56#define FPS_PERIOD 30 57 58//define this macro to save first few raw frames when starting the preview. 59//#define SAVE_RAW_FRAMES 1 60//#define DUMP_CAPTURE_FRAME 1 61//#define PPM_PER_FRAME_CONVERSION 1 62 63//Proto Types 64static void convertYUV422i_yuyvTouyvy(uint8_t *src, uint8_t *dest, size_t size ); 65static void convertYUV422ToNV12Tiler(unsigned char *src, unsigned char *dest, int width, int height ); 66static void convertYUV422ToNV12(unsigned char *src, unsigned char *dest, int width, int height ); 67 68android::Mutex gV4LAdapterLock; 69char device[15]; 70 71 72/*--------------------Camera Adapter Class STARTS here-----------------------------*/ 73 74/*--------------------V4L wrapper functions -------------------------------*/ 75status_t V4LCameraAdapter::v4lIoctl (int fd, int req, void* argp) { 76 status_t ret = NO_ERROR; 77 errno = 0; 78 79 do { 80 ret = ioctl (fd, req, argp); 81 }while (-1 == ret && EINTR == errno); 82 83 return ret; 84} 85 86status_t V4LCameraAdapter::v4lInitMmap(int& count) { 87 status_t ret = NO_ERROR; 88 89 //First allocate adapter internal buffers at V4L level for USB Cam 90 //These are the buffers from which we will copy the data into overlay buffers 91 /* Check if camera can handle NB_BUFFER buffers */ 92 mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 93 mVideoInfo->rb.memory = V4L2_MEMORY_MMAP; 94 mVideoInfo->rb.count = count; 95 96 ret = v4lIoctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb); 97 if (ret < 0) { 98 CAMHAL_LOGEB("VIDIOC_REQBUFS failed: %s", strerror(errno)); 99 return ret; 100 } 101 102 count = mVideoInfo->rb.count; 103 for (int i = 0; i < count; i++) { 104 105 memset (&mVideoInfo->buf, 0, sizeof (struct v4l2_buffer)); 106 107 mVideoInfo->buf.index = i; 108 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 109 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; 110 111 ret = v4lIoctl (mCameraHandle, VIDIOC_QUERYBUF, &mVideoInfo->buf); 112 if (ret < 0) { 113 CAMHAL_LOGEB("Unable to query buffer (%s)", strerror(errno)); 114 return ret; 115 } 116 117 mVideoInfo->mem[i] = mmap (NULL, 118 mVideoInfo->buf.length, 119 PROT_READ | PROT_WRITE, 120 MAP_SHARED, 121 mCameraHandle, 122 mVideoInfo->buf.m.offset); 123 124 CAMHAL_LOGVB(" mVideoInfo->mem[%d]=%p ; mVideoInfo->buf.length = %d", i, mVideoInfo->mem[i], mVideoInfo->buf.length); 125 if (mVideoInfo->mem[i] == MAP_FAILED) { 126 CAMHAL_LOGEB("Unable to map buffer [%d]. (%s)", i, strerror(errno)); 127 return -1; 128 } 129 } 130 return ret; 131} 132 133status_t V4LCameraAdapter::v4lInitUsrPtr(int& count) { 134 status_t ret = NO_ERROR; 135 136 mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 137 mVideoInfo->rb.memory = V4L2_MEMORY_USERPTR; 138 mVideoInfo->rb.count = count; 139 140 ret = v4lIoctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb); 141 if (ret < 0) { 142 CAMHAL_LOGEB("VIDIOC_REQBUFS failed for USERPTR: %s", strerror(errno)); 143 return ret; 144 } 145 146 count = mVideoInfo->rb.count; 147 return ret; 148} 149 150status_t V4LCameraAdapter::v4lStartStreaming () { 151 status_t ret = NO_ERROR; 152 enum v4l2_buf_type bufType; 153 154 if (!mVideoInfo->isStreaming) { 155 bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE; 156 157 ret = v4lIoctl (mCameraHandle, VIDIOC_STREAMON, &bufType); 158 if (ret < 0) { 159 CAMHAL_LOGEB("StartStreaming: Unable to start capture: %s", strerror(errno)); 160 return ret; 161 } 162 mVideoInfo->isStreaming = true; 163 } 164 return ret; 165} 166 167status_t V4LCameraAdapter::v4lStopStreaming (int nBufferCount) { 168 status_t ret = NO_ERROR; 169 enum v4l2_buf_type bufType; 170 171 if (mVideoInfo->isStreaming) { 172 bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE; 173 174 ret = v4lIoctl (mCameraHandle, VIDIOC_STREAMOFF, &bufType); 175 if (ret < 0) { 176 CAMHAL_LOGEB("StopStreaming: Unable to stop capture: %s", strerror(errno)); 177 goto EXIT; 178 } 179 mVideoInfo->isStreaming = false; 180 181 /* Unmap buffers */ 182 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 183 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; 184 for (int i = 0; i < nBufferCount; i++) { 185 if (munmap(mVideoInfo->mem[i], mVideoInfo->buf.length) < 0) { 186 CAMHAL_LOGEA("munmap() failed"); 187 } 188 } 189 190 //free the memory allocated during REQBUFS, by setting the count=0 191 mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 192 mVideoInfo->rb.memory = V4L2_MEMORY_MMAP; 193 mVideoInfo->rb.count = 0; 194 195 ret = v4lIoctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb); 196 if (ret < 0) { 197 CAMHAL_LOGEB("VIDIOC_REQBUFS failed: %s", strerror(errno)); 198 goto EXIT; 199 } 200 } 201EXIT: 202 return ret; 203} 204 205status_t V4LCameraAdapter::v4lSetFormat (int width, int height, uint32_t pix_format) { 206 status_t ret = NO_ERROR; 207 208 mVideoInfo->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 209 ret = v4lIoctl(mCameraHandle, VIDIOC_G_FMT, &mVideoInfo->format); 210 if (ret < 0) { 211 CAMHAL_LOGEB("VIDIOC_G_FMT Failed: %s", strerror(errno)); 212 } 213 214 mVideoInfo->width = width; 215 mVideoInfo->height = height; 216 mVideoInfo->framesizeIn = (width * height << 1); 217 mVideoInfo->formatIn = DEFAULT_PIXEL_FORMAT; 218 219 mVideoInfo->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 220 mVideoInfo->format.fmt.pix.width = width; 221 mVideoInfo->format.fmt.pix.height = height; 222 mVideoInfo->format.fmt.pix.pixelformat = pix_format; 223 224 ret = v4lIoctl(mCameraHandle, VIDIOC_S_FMT, &mVideoInfo->format); 225 if (ret < 0) { 226 CAMHAL_LOGEB("VIDIOC_S_FMT Failed: %s", strerror(errno)); 227 return ret; 228 } 229 v4lIoctl(mCameraHandle, VIDIOC_G_FMT, &mVideoInfo->format); 230 CAMHAL_LOGDB("VIDIOC_G_FMT : WxH = %dx%d", mVideoInfo->format.fmt.pix.width, mVideoInfo->format.fmt.pix.height); 231 return ret; 232} 233 234status_t V4LCameraAdapter::restartPreview () 235{ 236 status_t ret = NO_ERROR; 237 int width = 0; 238 int height = 0; 239 struct v4l2_streamparm streamParams; 240 241 //configure for preview size and pixel format. 242 mParams.getPreviewSize(&width, &height); 243 244 ret = v4lSetFormat (width, height, DEFAULT_PIXEL_FORMAT); 245 if (ret < 0) { 246 CAMHAL_LOGEB("v4lSetFormat Failed: %s", strerror(errno)); 247 goto EXIT; 248 } 249 250 ret = v4lInitMmap(mPreviewBufferCount); 251 if (ret < 0) { 252 CAMHAL_LOGEB("v4lInitMmap Failed: %s", strerror(errno)); 253 goto EXIT; 254 } 255 256 //set frame rate 257 streamParams.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 258 streamParams.parm.capture.capability = V4L2_CAP_TIMEPERFRAME; 259 streamParams.parm.capture.capturemode = V4L2_MODE_HIGHQUALITY; 260 streamParams.parm.capture.timeperframe.denominator = FPS_PERIOD; 261 streamParams.parm.capture.timeperframe.numerator= 1; 262 ret = v4lIoctl(mCameraHandle, VIDIOC_S_PARM, &streamParams); 263 if (ret < 0) { 264 CAMHAL_LOGEB("VIDIOC_S_PARM Failed: %s", strerror(errno)); 265 goto EXIT; 266 } 267 268 for (int i = 0; i < mPreviewBufferCountQueueable; i++) { 269 270 mVideoInfo->buf.index = i; 271 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 272 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; 273 274 ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); 275 if (ret < 0) { 276 CAMHAL_LOGEA("VIDIOC_QBUF Failed"); 277 goto EXIT; 278 } 279 nQueued++; 280 } 281 282 ret = v4lStartStreaming(); 283 CAMHAL_LOGDA("Ready for preview...."); 284EXIT: 285 return ret; 286} 287 288/*--------------------Camera Adapter Functions-----------------------------*/ 289status_t V4LCameraAdapter::initialize(CameraProperties::Properties* caps) 290{ 291 char value[PROPERTY_VALUE_MAX]; 292 293 LOG_FUNCTION_NAME; 294 property_get("debug.camera.showfps", value, "0"); 295 mDebugFps = atoi(value); 296 297 int ret = NO_ERROR; 298 299 // Allocate memory for video info structure 300 mVideoInfo = (struct VideoInfo *) calloc (1, sizeof (struct VideoInfo)); 301 if(!mVideoInfo) { 302 ret = NO_MEMORY; 303 goto EXIT; 304 } 305 306 if ((mCameraHandle = open(device, O_RDWR | O_NONBLOCK) ) == -1) { 307 CAMHAL_LOGEB("Error while opening handle to V4L2 Camera: %s", strerror(errno)); 308 ret = BAD_VALUE; 309 goto EXIT; 310 } 311 312 ret = v4lIoctl (mCameraHandle, VIDIOC_QUERYCAP, &mVideoInfo->cap); 313 if (ret < 0) { 314 CAMHAL_LOGEA("Error when querying the capabilities of the V4L Camera"); 315 ret = BAD_VALUE; 316 goto EXIT; 317 } 318 319 if ((mVideoInfo->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { 320 CAMHAL_LOGEA("Error while adapter initialization: video capture not supported."); 321 ret = BAD_VALUE; 322 goto EXIT; 323 } 324 325 if (!(mVideoInfo->cap.capabilities & V4L2_CAP_STREAMING)) { 326 CAMHAL_LOGEA("Error while adapter initialization: Capture device does not support streaming i/o"); 327 ret = BAD_VALUE; 328 goto EXIT; 329 } 330 331 // Initialize flags 332 mPreviewing = false; 333 mVideoInfo->isStreaming = false; 334 mRecording = false; 335 mCapturing = false; 336EXIT: 337 LOG_FUNCTION_NAME_EXIT; 338 return ret; 339} 340 341status_t V4LCameraAdapter::fillThisBuffer(CameraBuffer *frameBuf, CameraFrame::FrameType frameType) 342{ 343 status_t ret = NO_ERROR; 344 int idx = 0; 345 LOG_FUNCTION_NAME; 346 347 if ( frameType == CameraFrame::IMAGE_FRAME) { //(1 > mCapturedFrames) 348 // Signal end of image capture 349 if ( NULL != mEndImageCaptureCallback) { 350 CAMHAL_LOGDB("===========Signal End Image Capture=========="); 351 mEndImageCaptureCallback(mEndCaptureData); 352 } 353 goto EXIT; 354 } 355 if ( !mVideoInfo->isStreaming ) { 356 goto EXIT; 357 } 358 359 idx = mPreviewBufs.valueFor(frameBuf); 360 if(idx < 0) { 361 CAMHAL_LOGEB("Wrong index = %d",idx); 362 goto EXIT; 363 } 364 365 mVideoInfo->buf.index = idx; 366 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 367 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; 368 369 ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); 370 if (ret < 0) { 371 CAMHAL_LOGEA("VIDIOC_QBUF Failed"); 372 goto EXIT; 373 } 374 nQueued++; 375EXIT: 376 LOG_FUNCTION_NAME_EXIT; 377 return ret; 378 379} 380 381status_t V4LCameraAdapter::setParameters(const android::CameraParameters ¶ms) 382{ 383 status_t ret = NO_ERROR; 384 int width, height; 385 struct v4l2_streamparm streamParams; 386 387 LOG_FUNCTION_NAME; 388 389 if(!mPreviewing && !mCapturing) { 390 params.getPreviewSize(&width, &height); 391 CAMHAL_LOGDB("Width * Height %d x %d format 0x%x", width, height, DEFAULT_PIXEL_FORMAT); 392 393 ret = v4lSetFormat( width, height, DEFAULT_PIXEL_FORMAT); 394 if (ret < 0) { 395 CAMHAL_LOGEB(" VIDIOC_S_FMT Failed: %s", strerror(errno)); 396 goto EXIT; 397 } 398 //set frame rate 399 // Now its fixed to 30 FPS 400 streamParams.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 401 streamParams.parm.capture.capability = V4L2_CAP_TIMEPERFRAME; 402 streamParams.parm.capture.capturemode = V4L2_MODE_HIGHQUALITY; 403 streamParams.parm.capture.timeperframe.denominator = FPS_PERIOD; 404 streamParams.parm.capture.timeperframe.numerator= 1; 405 ret = v4lIoctl(mCameraHandle, VIDIOC_S_PARM, &streamParams); 406 if (ret < 0) { 407 CAMHAL_LOGEB(" VIDIOC_S_PARM Failed: %s", strerror(errno)); 408 goto EXIT; 409 } 410 int actualFps = streamParams.parm.capture.timeperframe.denominator / streamParams.parm.capture.timeperframe.numerator; 411 CAMHAL_LOGDB("Actual FPS set is : %d.", actualFps); 412 } 413 414 // Udpate the current parameter set 415 mParams = params; 416 417EXIT: 418 LOG_FUNCTION_NAME_EXIT; 419 return ret; 420} 421 422 423void V4LCameraAdapter::getParameters(android::CameraParameters& params) 424{ 425 LOG_FUNCTION_NAME; 426 427 // Return the current parameter set 428 params = mParams; 429 430 LOG_FUNCTION_NAME_EXIT; 431} 432 433 434///API to give the buffers to Adapter 435status_t V4LCameraAdapter::useBuffers(CameraMode mode, CameraBuffer *bufArr, int num, size_t length, unsigned int queueable) 436{ 437 status_t ret = NO_ERROR; 438 439 LOG_FUNCTION_NAME; 440 441 android::AutoMutex lock(mLock); 442 443 switch(mode) 444 { 445 case CAMERA_PREVIEW: 446 mPreviewBufferCountQueueable = queueable; 447 ret = UseBuffersPreview(bufArr, num); 448 break; 449 450 case CAMERA_IMAGE_CAPTURE: 451 mCaptureBufferCountQueueable = queueable; 452 ret = UseBuffersCapture(bufArr, num); 453 break; 454 455 case CAMERA_VIDEO: 456 //@warn Video capture is not fully supported yet 457 mPreviewBufferCountQueueable = queueable; 458 ret = UseBuffersPreview(bufArr, num); 459 break; 460 461 case CAMERA_MEASUREMENT: 462 break; 463 464 default: 465 break; 466 } 467 468 LOG_FUNCTION_NAME_EXIT; 469 470 return ret; 471} 472 473status_t V4LCameraAdapter::UseBuffersCapture(CameraBuffer *bufArr, int num) { 474 int ret = NO_ERROR; 475 476 LOG_FUNCTION_NAME; 477 if(NULL == bufArr) { 478 ret = BAD_VALUE; 479 goto EXIT; 480 } 481 482 for (int i = 0; i < num; i++) { 483 //Associate each Camera internal buffer with the one from Overlay 484 mCaptureBufs.add(&bufArr[i], i); 485 CAMHAL_LOGDB("capture- buff [%d] = 0x%x ",i, mCaptureBufs.keyAt(i)); 486 } 487 488 // Update the preview buffer count 489 mCaptureBufferCount = num; 490EXIT: 491 LOG_FUNCTION_NAME_EXIT; 492 return ret; 493 494} 495 496status_t V4LCameraAdapter::UseBuffersPreview(CameraBuffer *bufArr, int num) 497{ 498 int ret = NO_ERROR; 499 LOG_FUNCTION_NAME; 500 501 if(NULL == bufArr) { 502 ret = BAD_VALUE; 503 goto EXIT; 504 } 505 506 ret = v4lInitMmap(num); 507 if (ret == NO_ERROR) { 508 for (int i = 0; i < num; i++) { 509 //Associate each Camera internal buffer with the one from Overlay 510 mPreviewBufs.add(&bufArr[i], i); 511 CAMHAL_LOGDB("Preview- buff [%d] = 0x%x ",i, mPreviewBufs.keyAt(i)); 512 } 513 514 // Update the preview buffer count 515 mPreviewBufferCount = num; 516 } 517EXIT: 518 LOG_FUNCTION_NAME_EXIT; 519 return ret; 520} 521 522status_t V4LCameraAdapter::takePicture() { 523 status_t ret = NO_ERROR; 524 int width = 0; 525 int height = 0; 526 size_t yuv422i_buff_size = 0; 527 int index = 0; 528 char *fp = NULL; 529 CameraBuffer *buffer = NULL; 530 CameraFrame frame; 531 532 LOG_FUNCTION_NAME; 533 534 android::AutoMutex lock(mCaptureBufsLock); 535 536 if(mCapturing) { 537 CAMHAL_LOGEA("Already Capture in Progress..."); 538 ret = BAD_VALUE; 539 goto EXIT; 540 } 541 542 mCapturing = true; 543 mPreviewing = false; 544 545 // Stop preview streaming 546 ret = v4lStopStreaming(mPreviewBufferCount); 547 if (ret < 0 ) { 548 CAMHAL_LOGEB("v4lStopStreaming Failed: %s", strerror(errno)); 549 goto EXIT; 550 } 551 552 //configure for capture image size and pixel format. 553 mParams.getPictureSize(&width, &height); 554 CAMHAL_LOGDB("Image Capture Size WxH = %dx%d",width,height); 555 yuv422i_buff_size = width * height * 2; 556 557 ret = v4lSetFormat (width, height, DEFAULT_PIXEL_FORMAT); 558 if (ret < 0) { 559 CAMHAL_LOGEB("v4lSetFormat Failed: %s", strerror(errno)); 560 goto EXIT; 561 } 562 563 ret = v4lInitMmap(mCaptureBufferCount); 564 if (ret < 0) { 565 CAMHAL_LOGEB("v4lInitMmap Failed: %s", strerror(errno)); 566 goto EXIT; 567 } 568 569 for (int i = 0; i < mCaptureBufferCountQueueable; i++) { 570 571 mVideoInfo->buf.index = i; 572 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 573 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; 574 575 ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); 576 if (ret < 0) { 577 CAMHAL_LOGEA("VIDIOC_QBUF Failed"); 578 ret = BAD_VALUE; 579 goto EXIT; 580 } 581 nQueued++; 582 } 583 584 ret = v4lStartStreaming(); 585 if (ret < 0) { 586 CAMHAL_LOGEB("v4lStartStreaming Failed: %s", strerror(errno)); 587 goto EXIT; 588 } 589 590 CAMHAL_LOGDA("Streaming started for Image Capture"); 591 592 //get the frame and send to encode as JPG 593 fp = this->GetFrame(index); 594 if(!fp) { 595 CAMHAL_LOGEA("!!! Captured frame is NULL !!!!"); 596 ret = BAD_VALUE; 597 goto EXIT; 598 } 599 600 CAMHAL_LOGDA("::Capture Frame received from V4L::"); 601 buffer = mCaptureBufs.keyAt(index); 602 CAMHAL_LOGVB("## captureBuf[%d] = 0x%x, yuv422i_buff_size=%d", index, buffer->opaque, yuv422i_buff_size); 603 604 //copy the yuv422i data to the image buffer. 605 memcpy(buffer->opaque, fp, yuv422i_buff_size); 606 607#ifdef DUMP_CAPTURE_FRAME 608 //dump the YUV422 buffer in to a file 609 //a folder should have been created at /data/misc/camera/raw/ 610 { 611 int fd =-1; 612 fd = open("/data/misc/camera/raw/captured_yuv422i_dump.yuv", O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777); 613 if(fd < 0) { 614 CAMHAL_LOGEB("Unable to open file: %s", strerror(fd)); 615 } 616 else { 617 write(fd, fp, yuv422i_buff_size ); 618 close(fd); 619 CAMHAL_LOGDB("::Captured Frame dumped at /data/misc/camera/raw/captured_yuv422i_dump.yuv::"); 620 } 621 } 622#endif 623 624 CAMHAL_LOGDA("::sending capture frame to encoder::"); 625 frame.mFrameType = CameraFrame::IMAGE_FRAME; 626 frame.mBuffer = buffer; 627 frame.mLength = yuv422i_buff_size; 628 frame.mWidth = width; 629 frame.mHeight = height; 630 frame.mAlignment = width*2; 631 frame.mOffset = 0; 632 frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); 633 frame.mFrameMask = (unsigned int)CameraFrame::IMAGE_FRAME; 634 frame.mQuirks |= CameraFrame::ENCODE_RAW_YUV422I_TO_JPEG; 635 frame.mQuirks |= CameraFrame::FORMAT_YUV422I_YUYV; 636 637 ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask); 638 if (ret != NO_ERROR) { 639 CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret); 640 } else { 641 ret = sendFrameToSubscribers(&frame); 642 } 643 644 // Stop streaming after image capture 645 ret = v4lStopStreaming(mCaptureBufferCount); 646 if (ret < 0 ) { 647 CAMHAL_LOGEB("v4lStopStreaming Failed: %s", strerror(errno)); 648 goto EXIT; 649 } 650 651 ret = restartPreview(); 652EXIT: 653 LOG_FUNCTION_NAME_EXIT; 654 return ret; 655} 656 657status_t V4LCameraAdapter::stopImageCapture() 658{ 659 status_t ret = NO_ERROR; 660 LOG_FUNCTION_NAME; 661 662 //Release image buffers 663 if ( NULL != mReleaseImageBuffersCallback ) { 664 mReleaseImageBuffersCallback(mReleaseData); 665 } 666 mCaptureBufs.clear(); 667 668 mCapturing = false; 669 mPreviewing = true; 670 LOG_FUNCTION_NAME_EXIT; 671 return ret; 672} 673 674status_t V4LCameraAdapter::autoFocus() 675{ 676 status_t ret = NO_ERROR; 677 LOG_FUNCTION_NAME; 678 679 //autoFocus is not implemented. Just return. 680 LOG_FUNCTION_NAME_EXIT; 681 return ret; 682} 683 684status_t V4LCameraAdapter::startPreview() 685{ 686 status_t ret = NO_ERROR; 687 688 LOG_FUNCTION_NAME; 689 android::AutoMutex lock(mPreviewBufsLock); 690 691 if(mPreviewing) { 692 ret = BAD_VALUE; 693 goto EXIT; 694 } 695 696 for (int i = 0; i < mPreviewBufferCountQueueable; i++) { 697 698 mVideoInfo->buf.index = i; 699 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 700 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; 701 702 ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); 703 if (ret < 0) { 704 CAMHAL_LOGEA("VIDIOC_QBUF Failed"); 705 goto EXIT; 706 } 707 nQueued++; 708 } 709 710 ret = v4lStartStreaming(); 711 712 // Create and start preview thread for receiving buffers from V4L Camera 713 if(!mCapturing) { 714 mPreviewThread = new PreviewThread(this); 715 CAMHAL_LOGDA("Created preview thread"); 716 } 717 718 //Update the flag to indicate we are previewing 719 mPreviewing = true; 720 mCapturing = false; 721 722EXIT: 723 LOG_FUNCTION_NAME_EXIT; 724 return ret; 725} 726 727status_t V4LCameraAdapter::stopPreview() 728{ 729 enum v4l2_buf_type bufType; 730 int ret = NO_ERROR; 731 732 LOG_FUNCTION_NAME; 733 android::AutoMutex lock(mStopPreviewLock); 734 735 if(!mPreviewing) { 736 return NO_INIT; 737 } 738 mPreviewing = false; 739 740 ret = v4lStopStreaming(mPreviewBufferCount); 741 if (ret < 0) { 742 CAMHAL_LOGEB("StopStreaming: FAILED: %s", strerror(errno)); 743 } 744 745 nQueued = 0; 746 nDequeued = 0; 747 mFramesWithEncoder = 0; 748 749 mPreviewBufs.clear(); 750 751 mPreviewThread->requestExitAndWait(); 752 mPreviewThread.clear(); 753 754 LOG_FUNCTION_NAME_EXIT; 755 return ret; 756} 757 758char * V4LCameraAdapter::GetFrame(int &index) 759{ 760 int ret = NO_ERROR; 761 LOG_FUNCTION_NAME; 762 763 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 764 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; 765 766 /* DQ */ 767 // Some V4L drivers, notably uvc, protect each incoming call with 768 // a driver-wide mutex. If we use poll() or blocking VIDIOC_DQBUF ioctl 769 // here then we sometimes would run into a deadlock on VIDIO_QBUF ioctl. 770 while(true) { 771 if(!mVideoInfo->isStreaming) { 772 return NULL; 773 } 774 775 ret = v4lIoctl(mCameraHandle, VIDIOC_DQBUF, &mVideoInfo->buf); 776 if((ret == 0) || (errno != EAGAIN)) { 777 break; 778 } 779 } 780 781 if (ret < 0) { 782 CAMHAL_LOGEA("GetFrame: VIDIOC_DQBUF Failed"); 783 return NULL; 784 } 785 nDequeued++; 786 787 index = mVideoInfo->buf.index; 788 789 LOG_FUNCTION_NAME_EXIT; 790 return (char *)mVideoInfo->mem[mVideoInfo->buf.index]; 791} 792 793//API to get the frame size required to be allocated. This size is used to override the size passed 794//by camera service when VSTAB/VNF is turned ON for example 795status_t V4LCameraAdapter::getFrameSize(size_t &width, size_t &height) 796{ 797 status_t ret = NO_ERROR; 798 LOG_FUNCTION_NAME; 799 800 // Just return the current preview size, nothing more to do here. 801 mParams.getPreviewSize(( int * ) &width, 802 ( int * ) &height); 803 804 LOG_FUNCTION_NAME_EXIT; 805 806 return ret; 807} 808 809status_t V4LCameraAdapter::getFrameDataSize(size_t &dataFrameSize, size_t bufferCount) 810{ 811 // We don't support meta data, so simply return 812 return NO_ERROR; 813} 814 815status_t V4LCameraAdapter::getPictureBufferSize(CameraFrame &frame, size_t bufferCount) 816{ 817 int width = 0; 818 int height = 0; 819 int bytesPerPixel = 2; // for YUV422i; default pixel format 820 821 LOG_FUNCTION_NAME; 822 823 mParams.getPictureSize( &width, &height ); 824 frame.mLength = width * height * bytesPerPixel; 825 frame.mWidth = width; 826 frame.mHeight = height; 827 frame.mAlignment = width * bytesPerPixel; 828 829 CAMHAL_LOGDB("Picture size: W x H = %u x %u (size=%u bytes, alignment=%u bytes)", 830 frame.mWidth, frame.mHeight, frame.mLength, frame.mAlignment); 831 LOG_FUNCTION_NAME_EXIT; 832 return NO_ERROR; 833} 834 835static void debugShowFPS() 836{ 837 static int mFrameCount = 0; 838 static int mLastFrameCount = 0; 839 static nsecs_t mLastFpsTime = 0; 840 static float mFps = 0; 841 if(mDebugFps) { 842 mFrameCount++; 843 if (!(mFrameCount & 0x1F)) { 844 nsecs_t now = systemTime(); 845 nsecs_t diff = now - mLastFpsTime; 846 mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; 847 mLastFpsTime = now; 848 mLastFrameCount = mFrameCount; 849 CAMHAL_LOGD("Camera %d Frames, %f FPS", mFrameCount, mFps); 850 } 851 } 852} 853 854status_t V4LCameraAdapter::recalculateFPS() 855{ 856 float currentFPS; 857 858 mFrameCount++; 859 860 if ( ( mFrameCount % FPS_PERIOD ) == 0 ) 861 { 862 nsecs_t now = systemTime(); 863 nsecs_t diff = now - mLastFPSTime; 864 currentFPS = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; 865 mLastFPSTime = now; 866 mLastFrameCount = mFrameCount; 867 868 if ( 1 == mIter ) 869 { 870 mFPS = currentFPS; 871 } 872 else 873 { 874 //cumulative moving average 875 mFPS = mLastFPS + (currentFPS - mLastFPS)/mIter; 876 } 877 878 mLastFPS = mFPS; 879 mIter++; 880 } 881 882 return NO_ERROR; 883} 884 885void V4LCameraAdapter::onOrientationEvent(uint32_t orientation, uint32_t tilt) 886{ 887 LOG_FUNCTION_NAME; 888 889 LOG_FUNCTION_NAME_EXIT; 890} 891 892 893V4LCameraAdapter::V4LCameraAdapter(size_t sensor_index) 894{ 895 LOG_FUNCTION_NAME; 896 897 // Nothing useful to do in the constructor 898 mFramesWithEncoder = 0; 899 900 LOG_FUNCTION_NAME_EXIT; 901} 902 903V4LCameraAdapter::~V4LCameraAdapter() 904{ 905 LOG_FUNCTION_NAME; 906 907 // Close the camera handle and free the video info structure 908 close(mCameraHandle); 909 910 if (mVideoInfo) 911 { 912 free(mVideoInfo); 913 mVideoInfo = NULL; 914 } 915 916 LOG_FUNCTION_NAME_EXIT; 917} 918 919static void convertYUV422i_yuyvTouyvy(uint8_t *src, uint8_t *dest, size_t size ) { 920 //convert YUV422I yuyv to uyvy format. 921 uint32_t *bf = (uint32_t*)src; 922 uint32_t *dst = (uint32_t*)dest; 923 924 LOG_FUNCTION_NAME; 925 926 if (!src || !dest) { 927 return; 928 } 929 930 for(size_t i = 0; i < size; i = i+4) 931 { 932 dst[0] = ((bf[0] & 0x00FF00FF) << 8) | ((bf[0] & 0xFF00FF00) >> 8); 933 bf++; 934 dst++; 935 } 936 937 LOG_FUNCTION_NAME_EXIT; 938} 939 940static void convertYUV422ToNV12Tiler(unsigned char *src, unsigned char *dest, int width, int height ) { 941 //convert YUV422I to YUV420 NV12 format and copies directly to preview buffers (Tiler memory). 942 int stride = 4096; 943 unsigned char *bf = src; 944 unsigned char *dst_y = dest; 945 unsigned char *dst_uv = dest + ( height * stride); 946#ifdef PPM_PER_FRAME_CONVERSION 947 static int frameCount = 0; 948 static nsecs_t ppm_diff = 0; 949 nsecs_t ppm_start = systemTime(); 950#endif 951 952 LOG_FUNCTION_NAME; 953 954 if (width % 16 ) { 955 for(int i = 0; i < height; i++) { 956 for(int j = 0; j < width; j++) { 957 *dst_y = *bf; 958 dst_y++; 959 bf = bf + 2; 960 } 961 dst_y += (stride - width); 962 } 963 964 bf = src; 965 bf++; //UV sample 966 for(int i = 0; i < height/2; i++) { 967 for(int j=0; j<width; j++) { 968 *dst_uv = *bf; 969 dst_uv++; 970 bf = bf + 2; 971 } 972 bf = bf + width*2; 973 dst_uv = dst_uv + (stride - width); 974 } 975 } else { 976 //neon conversion 977 for(int i = 0; i < height; i++) { 978 int n = width; 979 int skip = i & 0x1; // skip uv elements for the odd rows 980 asm volatile ( 981 " pld [%[src], %[src_stride], lsl #2] \n\t" 982 " cmp %[n], #16 \n\t" 983 " blt 5f \n\t" 984 "0: @ 16 pixel copy \n\t" 985 " vld2.8 {q0, q1} , [%[src]]! @ q0 = yyyy.. q1 = uvuv.. \n\t" 986 " @ now q0 = y q1 = uv \n\t" 987 " vst1.32 {d0,d1}, [%[dst_y]]! \n\t" 988 " cmp %[skip], #0 \n\t" 989 " bne 1f \n\t" 990 " vst1.32 {d2,d3},[%[dst_uv]]! \n\t" 991 "1: @ skip odd rows for UV \n\t" 992 " sub %[n], %[n], #16 \n\t" 993 " cmp %[n], #16 \n\t" 994 " bge 0b \n\t" 995 "5: @ end \n\t" 996#ifdef NEEDS_ARM_ERRATA_754319_754320 997 " vmov s0,s0 @ add noop for errata item \n\t" 998#endif 999 : [dst_y] "+r" (dst_y), [dst_uv] "+r" (dst_uv), [src] "+r" (src), [n] "+r" (n) 1000 : [src_stride] "r" (width), [skip] "r" (skip) 1001 : "cc", "memory", "q0", "q1", "q2", "d0", "d1", "d2", "d3" 1002 ); 1003 dst_y = dst_y + (stride - width); 1004 if (skip == 0) { 1005 dst_uv = dst_uv + (stride - width); 1006 } 1007 } //end of for() 1008 } 1009 1010#ifdef PPM_PER_FRAME_CONVERSION 1011 ppm_diff += (systemTime() - ppm_start); 1012 frameCount++; 1013 1014 if (frameCount >= 30) { 1015 ppm_diff = ppm_diff / frameCount; 1016 LOGD("PPM: YUV422i to NV12 Conversion(%d x %d): %llu us ( %llu ms )", width, height, 1017 ns2us(ppm_diff), ns2ms(ppm_diff) ); 1018 ppm_diff = 0; 1019 frameCount = 0; 1020 } 1021#endif 1022 1023 LOG_FUNCTION_NAME_EXIT; 1024} 1025 1026static void convertYUV422ToNV12(unsigned char *src, unsigned char *dest, int width, int height ) { 1027 //convert YUV422I to YUV420 NV12 format. 1028 unsigned char *bf = src; 1029 unsigned char *dst_y = dest; 1030 unsigned char *dst_uv = dest + (width * height); 1031 1032 LOG_FUNCTION_NAME; 1033 1034 if (width % 16 ) { 1035 for(int i = 0; i < height; i++) { 1036 for(int j = 0; j < width; j++) { 1037 *dst_y = *bf; 1038 dst_y++; 1039 bf = bf + 2; 1040 } 1041 } 1042 1043 bf = src; 1044 bf++; //UV sample 1045 for(int i = 0; i < height/2; i++) { 1046 for(int j=0; j<width; j++) { 1047 *dst_uv = *bf; 1048 dst_uv++; 1049 bf = bf + 2; 1050 } 1051 bf = bf + width*2; 1052 } 1053 } else { 1054 //neon conversion 1055 for(int i = 0; i < height; i++) { 1056 int n = width; 1057 int skip = i & 0x1; // skip uv elements for the odd rows 1058 asm volatile ( 1059 " pld [%[src], %[src_stride], lsl #2] \n\t" 1060 " cmp %[n], #16 \n\t" 1061 " blt 5f \n\t" 1062 "0: @ 16 pixel copy \n\t" 1063 " vld2.8 {q0, q1} , [%[src]]! @ q0 = yyyy.. q1 = uvuv.. \n\t" 1064 " @ now q0 = y q1 = uv \n\t" 1065 " vst1.32 {d0,d1}, [%[dst_y]]! \n\t" 1066 " cmp %[skip], #0 \n\t" 1067 " bne 1f \n\t" 1068 " vst1.32 {d2,d3},[%[dst_uv]]! \n\t" 1069 "1: @ skip odd rows for UV \n\t" 1070 " sub %[n], %[n], #16 \n\t" 1071 " cmp %[n], #16 \n\t" 1072 " bge 0b \n\t" 1073 "5: @ end \n\t" 1074#ifdef NEEDS_ARM_ERRATA_754319_754320 1075 " vmov s0,s0 @ add noop for errata item \n\t" 1076#endif 1077 : [dst_y] "+r" (dst_y), [dst_uv] "+r" (dst_uv), [src] "+r" (src), [n] "+r" (n) 1078 : [src_stride] "r" (width), [skip] "r" (skip) 1079 : "cc", "memory", "q0", "q1", "q2", "d0", "d1", "d2", "d3" 1080 ); 1081 } 1082 } 1083 1084 LOG_FUNCTION_NAME_EXIT; 1085} 1086 1087#ifdef SAVE_RAW_FRAMES 1088void saveFile(unsigned char* buff, int buff_size) { 1089 static int counter = 1; 1090 int fd = -1; 1091 char fn[256]; 1092 1093 LOG_FUNCTION_NAME; 1094 if (counter > 3) { 1095 return; 1096 } 1097 //dump nv12 buffer 1098 counter++; 1099 sprintf(fn, "/data/misc/camera/raw/nv12_dump_%03d.yuv", counter); 1100 CAMHAL_LOGEB("Dumping nv12 frame to a file : %s.", fn); 1101 1102 fd = open(fn, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777); 1103 if(fd < 0) { 1104 CAMHAL_LOGE("Unable to open file %s: %s", fn, strerror(fd)); 1105 return; 1106 } 1107 1108 write(fd, buff, buff_size ); 1109 close(fd); 1110 1111 LOG_FUNCTION_NAME_EXIT; 1112} 1113#endif 1114 1115/* Preview Thread */ 1116// --------------------------------------------------------------------------- 1117 1118int V4LCameraAdapter::previewThread() 1119{ 1120 status_t ret = NO_ERROR; 1121 int width, height; 1122 CameraFrame frame; 1123 void *y_uv[2]; 1124 int index = 0; 1125 int stride = 4096; 1126 char *fp = NULL; 1127 1128 mParams.getPreviewSize(&width, &height); 1129 1130 if (mPreviewing) { 1131 1132 fp = this->GetFrame(index); 1133 if(!fp) { 1134 ret = BAD_VALUE; 1135 goto EXIT; 1136 } 1137 CameraBuffer *buffer = mPreviewBufs.keyAt(index); 1138 CameraFrame *lframe = (CameraFrame *)mFrameQueue.valueFor(buffer); 1139 if (!lframe) { 1140 ret = BAD_VALUE; 1141 goto EXIT; 1142 } 1143 1144 debugShowFPS(); 1145 1146 if ( mFrameSubscribers.size() == 0 ) { 1147 ret = BAD_VALUE; 1148 goto EXIT; 1149 } 1150 y_uv[0] = (void*) lframe->mYuv[0]; 1151 //y_uv[1] = (void*) lframe->mYuv[1]; 1152 //y_uv[1] = (void*) (lframe->mYuv[0] + height*stride); 1153 convertYUV422ToNV12Tiler ( (unsigned char*)fp, (unsigned char*)y_uv[0], width, height); 1154 CAMHAL_LOGVB("##...index= %d.;camera buffer= 0x%x; y= 0x%x; UV= 0x%x.",index, buffer, y_uv[0], y_uv[1] ); 1155 1156#ifdef SAVE_RAW_FRAMES 1157 unsigned char* nv12_buff = (unsigned char*) malloc(width*height*3/2); 1158 //Convert yuv422i to yuv420sp(NV12) & dump the frame to a file 1159 convertYUV422ToNV12 ( (unsigned char*)fp, nv12_buff, width, height); 1160 saveFile( nv12_buff, ((width*height)*3/2) ); 1161 free (nv12_buff); 1162#endif 1163 1164 frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC; 1165 frame.mBuffer = buffer; 1166 frame.mLength = width*height*3/2; 1167 frame.mAlignment = stride; 1168 frame.mOffset = 0; 1169 frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); 1170 frame.mFrameMask = (unsigned int)CameraFrame::PREVIEW_FRAME_SYNC; 1171 1172 if (mRecording) 1173 { 1174 frame.mFrameMask |= (unsigned int)CameraFrame::VIDEO_FRAME_SYNC; 1175 mFramesWithEncoder++; 1176 } 1177 1178 ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask); 1179 if (ret != NO_ERROR) { 1180 CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret); 1181 } else { 1182 ret = sendFrameToSubscribers(&frame); 1183 } 1184 } 1185EXIT: 1186 1187 return ret; 1188} 1189 1190//scan for video devices 1191void detectVideoDevice(char** video_device_list, int& num_device) { 1192 char dir_path[20]; 1193 char* filename; 1194 char** dev_list = video_device_list; 1195 DIR *d; 1196 struct dirent *dir; 1197 int index = 0; 1198 1199 strcpy(dir_path, DEVICE_PATH); 1200 d = opendir(dir_path); 1201 if(d) { 1202 //read each entry in the /dev/ and find if there is videox entry. 1203 while ((dir = readdir(d)) != NULL) { 1204 filename = dir->d_name; 1205 if (strncmp(filename, DEVICE_NAME, 5) == 0) { 1206 strcpy(dev_list[index],DEVICE_PATH); 1207 strncat(dev_list[index],filename,sizeof(DEVICE_NAME)); 1208 index++; 1209 } 1210 } //end of while() 1211 closedir(d); 1212 num_device = index; 1213 1214 for(int i=0; i<index; i++){ 1215 CAMHAL_LOGDB("Video device list::dev_list[%d]= %s",i,dev_list[i]); 1216 } 1217 } 1218} 1219 1220extern "C" CameraAdapter* V4LCameraAdapter_Factory(size_t sensor_index) 1221{ 1222 CameraAdapter *adapter = NULL; 1223 android::AutoMutex lock(gV4LAdapterLock); 1224 1225 LOG_FUNCTION_NAME; 1226 1227 adapter = new V4LCameraAdapter(sensor_index); 1228 if ( adapter ) { 1229 CAMHAL_LOGDB("New V4L Camera adapter instance created for sensor %d",sensor_index); 1230 } else { 1231 CAMHAL_LOGEA("V4L Camera adapter create failed for sensor index = %d!",sensor_index); 1232 } 1233 1234 LOG_FUNCTION_NAME_EXIT; 1235 1236 return adapter; 1237} 1238 1239extern "C" status_t V4LCameraAdapter_Capabilities( 1240 CameraProperties::Properties * const properties_array, 1241 const int starting_camera, const int max_camera, int & supportedCameras) 1242{ 1243 status_t ret = NO_ERROR; 1244 struct v4l2_capability cap; 1245 int tempHandle = NULL; 1246 int num_cameras_supported = 0; 1247 char device_list[5][15]; 1248 char* video_device_list[5]; 1249 int num_v4l_devices = 0; 1250 int sensorId = 0; 1251 CameraProperties::Properties* properties = NULL; 1252 1253 LOG_FUNCTION_NAME; 1254 1255 supportedCameras = 0; 1256 memset((void*)&cap, 0, sizeof(v4l2_capability)); 1257 1258 if (!properties_array) { 1259 CAMHAL_LOGEB("invalid param: properties = 0x%p", properties_array); 1260 LOG_FUNCTION_NAME_EXIT; 1261 return BAD_VALUE; 1262 } 1263 1264 for (int i = 0; i < 5; i++) { 1265 video_device_list[i] = device_list[i]; 1266 } 1267 //look for the connected video devices 1268 detectVideoDevice(video_device_list, num_v4l_devices); 1269 1270 for (int i = 0; i < num_v4l_devices; i++) { 1271 if ( (starting_camera + num_cameras_supported) < max_camera) { 1272 sensorId = starting_camera + num_cameras_supported; 1273 1274 CAMHAL_LOGDB("Opening device[%d] = %s..",i, video_device_list[i]); 1275 if ((tempHandle = open(video_device_list[i], O_RDWR)) == -1) { 1276 CAMHAL_LOGEB("Error while opening handle to V4L2 Camera(%s): %s",video_device_list[i], strerror(errno)); 1277 continue; 1278 } 1279 1280 ret = ioctl (tempHandle, VIDIOC_QUERYCAP, &cap); 1281 if (ret < 0) { 1282 CAMHAL_LOGEA("Error when querying the capabilities of the V4L Camera"); 1283 close(tempHandle); 1284 continue; 1285 } 1286 1287 //check for video capture devices 1288 if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { 1289 CAMHAL_LOGEA("Error while adapter initialization: video capture not supported."); 1290 close(tempHandle); 1291 continue; 1292 } 1293 1294 strcpy(device, video_device_list[i]); 1295 properties = properties_array + starting_camera + num_cameras_supported; 1296 1297 //fetch capabilities for this camera 1298 ret = V4LCameraAdapter::getCaps( sensorId, properties, tempHandle ); 1299 if (ret < 0) { 1300 CAMHAL_LOGEA("Error while getting capabilities."); 1301 close(tempHandle); 1302 continue; 1303 } 1304 1305 num_cameras_supported++; 1306 1307 } 1308 //For now exit this loop once a valid video capture device is found. 1309 //TODO: find all V4L capture devices and it capabilities 1310 break; 1311 }//end of for() loop 1312 1313 supportedCameras = num_cameras_supported; 1314 CAMHAL_LOGDB("Number of V4L cameras detected =%d", num_cameras_supported); 1315 1316EXIT: 1317 LOG_FUNCTION_NAME_EXIT; 1318 close(tempHandle); 1319 return NO_ERROR; 1320} 1321 1322} // namespace Camera 1323} // namespace Ti 1324 1325 1326/*--------------------Camera Adapter Class ENDS here-----------------------------*/ 1327 1328