Iliyan Malchev | 6d01645 | 2013-03-27 16:27:56 -0700 | [diff] [blame] | 1 | /* |
| 2 | ** Copyright (c) 2011-2012 The Linux Foundation. All rights reserved. |
| 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 | /*#error uncomment this for compiler test!*/ |
| 18 | |
| 19 | //#define ALOG_NDEBUG 0 |
| 20 | #define ALOG_NIDEBUG 0 |
| 21 | #define LOG_TAG "QCameraHWI_Mem" |
| 22 | #include <utils/Log.h> |
| 23 | |
| 24 | #include <utils/Errors.h> |
| 25 | #include <utils/threads.h> |
| 26 | //#include <binder/MemoryHeapPmem.h> |
| 27 | #include <utils/String16.h> |
| 28 | #include <sys/types.h> |
| 29 | #include <sys/stat.h> |
| 30 | #include <unistd.h> |
| 31 | #include <fcntl.h> |
| 32 | #include <cutils/properties.h> |
| 33 | #include <math.h> |
| 34 | #if HAVE_ANDROID_OS |
| 35 | #include <linux/android_pmem.h> |
| 36 | #endif |
| 37 | #include <linux/ioctl.h> |
| 38 | #include "QCameraParameters.h" |
| 39 | #include <media/mediarecorder.h> |
| 40 | #include <gralloc_priv.h> |
| 41 | |
| 42 | #include "QCameraHWI_Mem.h" |
| 43 | |
| 44 | #define CAMERA_HAL_UNUSED(expr) do { (void)(expr); } while (0) |
| 45 | |
| 46 | /* QCameraHardwareInterface class implementation goes here*/ |
| 47 | /* following code implement the contol logic of this class*/ |
| 48 | |
| 49 | namespace android { |
| 50 | |
| 51 | |
| 52 | static bool register_buf(int size, |
| 53 | int frame_size, |
| 54 | int cbcr_offset, |
| 55 | int yoffset, |
| 56 | int pmempreviewfd, |
| 57 | uint32_t offset, |
| 58 | uint8_t *buf, |
| 59 | int pmem_type, |
| 60 | bool vfe_can_write, |
| 61 | bool register_buffer = true); |
| 62 | |
| 63 | #if 0 |
| 64 | MMCameraDL::MMCameraDL(){ |
| 65 | ALOGV("MMCameraDL: E"); |
| 66 | libmmcamera = NULL; |
| 67 | #if DLOPEN_LIBMMCAMERA |
| 68 | libmmcamera = ::dlopen("liboemcamera.so", RTLD_NOW); |
| 69 | #endif |
| 70 | ALOGV("Open MM camera DL libeomcamera loaded at %p ", libmmcamera); |
| 71 | ALOGV("MMCameraDL: X"); |
| 72 | } |
| 73 | |
| 74 | void * MMCameraDL::pointer(){ |
| 75 | return libmmcamera; |
| 76 | } |
| 77 | |
| 78 | MMCameraDL::~MMCameraDL(){ |
| 79 | ALOGV("~MMCameraDL: E"); |
| 80 | LINK_mm_camera_destroy(); |
| 81 | if (libmmcamera != NULL) { |
| 82 | ::dlclose(libmmcamera); |
| 83 | ALOGV("closed MM Camera DL "); |
| 84 | } |
| 85 | libmmcamera = NULL; |
| 86 | ALOGV("~MMCameraDL: X"); |
| 87 | } |
| 88 | |
| 89 | |
| 90 | wp<MMCameraDL> MMCameraDL::instance; |
| 91 | Mutex MMCameraDL::singletonLock; |
| 92 | |
| 93 | |
| 94 | sp<MMCameraDL> MMCameraDL::getInstance(){ |
| 95 | Mutex::Autolock instanceLock(singletonLock); |
| 96 | sp<MMCameraDL> mmCamera = instance.promote(); |
| 97 | if(mmCamera == NULL){ |
| 98 | mmCamera = new MMCameraDL(); |
| 99 | instance = mmCamera; |
| 100 | } |
| 101 | return mmCamera; |
| 102 | } |
| 103 | #endif |
| 104 | |
| 105 | MemPool::MemPool(int buffer_size, int num_buffers, |
| 106 | int frame_size, |
| 107 | const char *name) : |
| 108 | mBufferSize(buffer_size), |
| 109 | mNumBuffers(num_buffers), |
| 110 | mFrameSize(frame_size), |
| 111 | mBuffers(NULL), mName(name) |
| 112 | { |
| 113 | int page_size_minus_1 = getpagesize() - 1; |
| 114 | mAlignedBufferSize = (buffer_size + page_size_minus_1) & (~page_size_minus_1); |
| 115 | } |
| 116 | |
| 117 | void MemPool::completeInitialization() |
| 118 | { |
| 119 | // If we do not know how big the frame will be, we wait to allocate |
| 120 | // the buffers describing the individual frames until we do know their |
| 121 | // size. |
| 122 | |
| 123 | if (mFrameSize > 0) { |
| 124 | mBuffers = new sp<MemoryBase>[mNumBuffers]; |
| 125 | for (int i = 0; i < mNumBuffers; i++) { |
| 126 | mBuffers[i] = new |
| 127 | MemoryBase(mHeap, |
| 128 | i * mAlignedBufferSize, |
| 129 | mFrameSize); |
| 130 | } |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | AshmemPool::AshmemPool(int buffer_size, int num_buffers, |
| 135 | int frame_size, |
| 136 | const char *name) : |
| 137 | MemPool(buffer_size, |
| 138 | num_buffers, |
| 139 | frame_size, |
| 140 | name) |
| 141 | { |
| 142 | ALOGV("constructing MemPool %s backed by ashmem: " |
| 143 | "%d frames @ %d uint8_ts, " |
| 144 | "buffer size %d", |
| 145 | mName, |
| 146 | num_buffers, frame_size, buffer_size); |
| 147 | |
| 148 | int page_mask = getpagesize() - 1; |
| 149 | int ashmem_size = buffer_size * num_buffers; |
| 150 | ashmem_size += page_mask; |
| 151 | ashmem_size &= ~page_mask; |
| 152 | |
| 153 | mHeap = new MemoryHeapBase(ashmem_size); |
| 154 | |
| 155 | completeInitialization(); |
| 156 | } |
| 157 | |
| 158 | static bool register_buf(int size, |
| 159 | int frame_size, |
| 160 | int cbcr_offset, |
| 161 | int yoffset, |
| 162 | int pmempreviewfd, |
| 163 | uint32_t offset, |
| 164 | uint8_t *buf, |
| 165 | int pmem_type, |
| 166 | bool vfe_can_write, |
| 167 | bool register_buffer) |
| 168 | { |
| 169 | /*TODO*/ |
| 170 | /* |
| 171 | struct msm_pmem_info pmemBuf; |
| 172 | CAMERA_HAL_UNUSED(frame_size); |
| 173 | |
| 174 | pmemBuf.type = pmem_type; |
| 175 | pmemBuf.fd = pmempreviewfd; |
| 176 | pmemBuf.offset = offset; |
| 177 | pmemBuf.len = size; |
| 178 | pmemBuf.vaddr = buf; |
| 179 | pmemBuf.y_off = yoffset; |
| 180 | pmemBuf.cbcr_off = cbcr_offset; |
| 181 | |
| 182 | pmemBuf.active = vfe_can_write; |
| 183 | |
| 184 | ALOGV("register_buf: reg = %d buffer = %p", |
| 185 | !register_buffer, buf); |
| 186 | if(native_start_ops(register_buffer ? CAMERA_OPS_REGISTER_BUFFER : |
| 187 | CAMERA_OPS_UNREGISTER_BUFFER ,(void *)&pmemBuf) < 0) { |
| 188 | ALOGE("register_buf: MSM_CAM_IOCTL_(UN)REGISTER_PMEM error %s", |
| 189 | strerror(errno)); |
| 190 | return false; |
| 191 | }*/ |
| 192 | |
| 193 | return true; |
| 194 | |
| 195 | } |
| 196 | |
| 197 | #if 0 |
| 198 | bool register_record_buffers(bool register_buffer) { |
| 199 | ALOGI("%s: (%d) E", __FUNCTION__, register_buffer); |
| 200 | struct msm_pmem_info pmemBuf; |
| 201 | |
| 202 | for (int cnt = 0; cnt < VIDEO_BUFFER_COUNT; ++cnt) { |
| 203 | pmemBuf.type = MSM_PMEM_VIDEO; |
| 204 | pmemBuf.fd = mRecordHeap->mHeap->getHeapID(); |
| 205 | pmemBuf.offset = mRecordHeap->mAlignedBufferSize * cnt; |
| 206 | pmemBuf.len = mRecordHeap->mBufferSize; |
| 207 | pmemBuf.vaddr = (uint8_t *)mRecordHeap->mHeap->base() + mRecordHeap->mAlignedBufferSize * cnt; |
| 208 | pmemBuf.y_off = 0; |
| 209 | pmemBuf.cbcr_off = recordframes[0].cbcr_off; |
| 210 | if(register_buffer == true) { |
| 211 | pmemBuf.active = (cnt<ACTIVE_VIDEO_BUFFERS); |
| 212 | if( (mVpeEnabled) && (cnt == kRecordBufferCount-1)) { |
| 213 | pmemBuf.type = MSM_PMEM_VIDEO_VPE; |
| 214 | pmemBuf.active = 1; |
| 215 | } |
| 216 | } else { |
| 217 | pmemBuf.active = false; |
| 218 | } |
| 219 | |
| 220 | ALOGV("register_buf: reg = %d buffer = %p", !register_buffer, |
| 221 | (void *)pmemBuf.vaddr); |
| 222 | if(native_start_ops(register_buffer ? CAMERA_OPS_REGISTER_BUFFER : |
| 223 | CAMERA_OPS_UNREGISTER_BUFFER ,(void *)&pmemBuf) < 0) { |
| 224 | ALOGE("register_buf: MSM_CAM_IOCTL_(UN)REGISTER_PMEM error %s", |
| 225 | strerror(errno)); |
| 226 | return false; |
| 227 | } |
| 228 | } |
| 229 | return true; |
| 230 | } |
| 231 | #endif |
| 232 | #if 0 |
| 233 | PmemPool::PmemPool(const char *pmem_pool, |
| 234 | int flags, |
| 235 | int pmem_type, |
| 236 | int buffer_size, int num_buffers, |
| 237 | int frame_size, int cbcr_offset, |
| 238 | int yOffset, const char *name) : |
| 239 | MemPool(buffer_size,num_buffers,frame_size,name), |
| 240 | mPmemType(pmem_type), |
| 241 | mCbCrOffset(cbcr_offset), |
| 242 | myOffset(yOffset) |
| 243 | { |
| 244 | ALOGI("constructing MemPool %s backed by pmem pool %s: " |
| 245 | "%d frames @ %d bytes, buffer size %d", |
| 246 | mName, |
| 247 | pmem_pool, num_buffers, frame_size, |
| 248 | buffer_size); |
| 249 | |
| 250 | //mMMCameraDLRef = MMCameraDL::getInstance(); |
| 251 | |
| 252 | |
| 253 | // Make a new mmap'ed heap that can be shared across processes. |
| 254 | // mAlignedBufferSize is already in 4k aligned. (do we need total size necessary to be in power of 2??) |
| 255 | mAlignedSize = mAlignedBufferSize * num_buffers; |
| 256 | |
| 257 | sp<MemoryHeapBase> masterHeap = |
| 258 | new MemoryHeapBase(pmem_pool, mAlignedSize, flags); |
| 259 | |
| 260 | if (masterHeap->getHeapID() < 0) { |
| 261 | ALOGE("failed to construct master heap for pmem pool %s", pmem_pool); |
| 262 | masterHeap.clear(); |
| 263 | return; |
| 264 | } |
| 265 | |
| 266 | sp<MemoryHeapPmem> pmemHeap = new MemoryHeapPmem(masterHeap, flags); |
| 267 | if (pmemHeap->getHeapID() >= 0) { |
| 268 | pmemHeap->slap(); |
| 269 | masterHeap.clear(); |
| 270 | mHeap = pmemHeap; |
| 271 | pmemHeap.clear(); |
| 272 | |
| 273 | mFd = mHeap->getHeapID(); |
| 274 | if (::ioctl(mFd, PMEM_GET_SIZE, &mSize)) { |
| 275 | ALOGE("pmem pool %s ioctl(PMEM_GET_SIZE) error %s (%d)", |
| 276 | pmem_pool, |
| 277 | ::strerror(errno), errno); |
| 278 | mHeap.clear(); |
| 279 | return; |
| 280 | } |
| 281 | |
| 282 | ALOGE("pmem pool %s ioctl(fd = %d, PMEM_GET_SIZE) is %ld", |
| 283 | pmem_pool, |
| 284 | mFd, |
| 285 | mSize.len); |
| 286 | ALOGE("mBufferSize=%d, mAlignedBufferSize=%d\n", mBufferSize, mAlignedBufferSize); |
| 287 | |
| 288 | #if 0 |
| 289 | // Unregister preview buffers with the camera drivers. Allow the VFE to write |
| 290 | // to all preview buffers except for the last one. |
| 291 | // Only Register the preview, snapshot and thumbnail buffers with the kernel. |
| 292 | if( (strcmp("postview", mName) != 0) ){ |
| 293 | int num_buf = num_buffers; |
| 294 | if(!strcmp("preview", mName)) num_buf = kPreviewBufferCount; |
| 295 | ALOGD("num_buffers = %d", num_buf); |
| 296 | for (int cnt = 0; cnt < num_buf; ++cnt) { |
| 297 | int active = 1; |
| 298 | if(pmem_type == MSM_PMEM_VIDEO){ |
| 299 | active = (cnt<ACTIVE_VIDEO_BUFFERS); |
| 300 | //When VPE is enabled, set the last record |
| 301 | //buffer as active and pmem type as PMEM_VIDEO_VPE |
| 302 | //as this is a requirement from VPE operation. |
| 303 | //No need to set this pmem type to VIDEO_VPE while unregistering, |
| 304 | //because as per camera stack design: "the VPE AXI is also configured |
| 305 | //when VFE is configured for VIDEO, which is as part of preview |
| 306 | //initialization/start. So during this VPE AXI config camera stack |
| 307 | //will lookup the PMEM_VIDEO_VPE buffer and give it as o/p of VPE and |
| 308 | //change it's type to PMEM_VIDEO". |
| 309 | if( (mVpeEnabled) && (cnt == kRecordBufferCount-1)) { |
| 310 | active = 1; |
| 311 | pmem_type = MSM_PMEM_VIDEO_VPE; |
| 312 | } |
| 313 | ALOGV(" pmempool creating video buffers : active %d ", active); |
| 314 | } |
| 315 | else if (pmem_type == MSM_PMEM_PREVIEW){ |
| 316 | active = (cnt < ACTIVE_PREVIEW_BUFFERS); |
| 317 | } |
| 318 | else if ((pmem_type == MSM_PMEM_MAINIMG) |
| 319 | || (pmem_type == MSM_PMEM_THUMBNAIL)){ |
| 320 | active = (cnt < ACTIVE_ZSL_BUFFERS); |
| 321 | } |
| 322 | register_buf(mBufferSize, |
| 323 | mFrameSize, mCbCrOffset, myOffset, |
| 324 | mHeap->getHeapID(), |
| 325 | mAlignedBufferSize * cnt, |
| 326 | (uint8_t *)mHeap->base() + mAlignedBufferSize * cnt, |
| 327 | pmem_type, |
| 328 | active); |
| 329 | } |
| 330 | } |
| 331 | #endif |
| 332 | completeInitialization(); |
| 333 | } |
| 334 | else ALOGE("pmem pool %s error: could not create master heap!", |
| 335 | pmem_pool); |
| 336 | ALOGI("%s: (%s) X ", __FUNCTION__, mName); |
| 337 | } |
| 338 | #endif |
| 339 | |
| 340 | PmemPool::~PmemPool() |
| 341 | { |
| 342 | ALOGV("%s: %s E", __FUNCTION__, mName); |
| 343 | #if 0 |
| 344 | if (mHeap != NULL) { |
| 345 | // Unregister preview buffers with the camera drivers. |
| 346 | // Only Unregister the preview, snapshot and thumbnail |
| 347 | // buffers with the kernel. |
| 348 | if( (strcmp("postview", mName) != 0) ){ |
| 349 | int num_buffers = mNumBuffers; |
| 350 | if(!strcmp("preview", mName)) num_buffers = PREVIEW_BUFFER_COUNT; |
| 351 | for (int cnt = 0; cnt < num_buffers; ++cnt) { |
| 352 | register_buf(mBufferSize, |
| 353 | mFrameSize, |
| 354 | mCbCrOffset, |
| 355 | myOffset, |
| 356 | mHeap->getHeapID(), |
| 357 | mAlignedBufferSize * cnt, |
| 358 | (uint8_t *)mHeap->base() + mAlignedBufferSize * cnt, |
| 359 | mPmemType, |
| 360 | false, |
| 361 | false /* unregister */); |
| 362 | } |
| 363 | } |
| 364 | } |
| 365 | mMMCameraDLRef.clear(); |
| 366 | #endif |
| 367 | ALOGV("%s: %s X", __FUNCTION__, mName); |
| 368 | } |
| 369 | MemPool::~MemPool() |
| 370 | { |
| 371 | ALOGV("destroying MemPool %s", mName); |
| 372 | if (mFrameSize > 0) |
| 373 | delete [] mBuffers; |
| 374 | mHeap.clear(); |
| 375 | ALOGV("destroying MemPool %s completed", mName); |
| 376 | } |
| 377 | |
| 378 | |
| 379 | status_t MemPool::dump(int fd, const Vector<String16>& args) const |
| 380 | { |
| 381 | const size_t SIZE = 256; |
| 382 | char buffer[SIZE]; |
| 383 | String8 result; |
| 384 | CAMERA_HAL_UNUSED(args); |
| 385 | snprintf(buffer, 255, "QualcommCameraHardware::AshmemPool::dump\n"); |
| 386 | result.append(buffer); |
| 387 | if (mName) { |
| 388 | snprintf(buffer, 255, "mem pool name (%s)\n", mName); |
| 389 | result.append(buffer); |
| 390 | } |
| 391 | if (mHeap != 0) { |
| 392 | snprintf(buffer, 255, "heap base(%p), size(%d), flags(%d), device(%s)\n", |
| 393 | mHeap->getBase(), mHeap->getSize(), |
| 394 | mHeap->getFlags(), mHeap->getDevice()); |
| 395 | result.append(buffer); |
| 396 | } |
| 397 | snprintf(buffer, 255, |
| 398 | "buffer size (%d), number of buffers (%d), frame size(%d)", |
| 399 | mBufferSize, mNumBuffers, mFrameSize); |
| 400 | result.append(buffer); |
| 401 | write(fd, result.string(), result.size()); |
| 402 | return NO_ERROR; |
| 403 | } |
| 404 | |
| 405 | }; |