1/* 2 * Copyright (C) 2012 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 LOG_TAG "Camera2-CallbackProcessor" 18#define ATRACE_TAG ATRACE_TAG_CAMERA 19//#define LOG_NDEBUG 0 20 21#include <utils/Log.h> 22#include <utils/Trace.h> 23 24#include "CallbackProcessor.h" 25#include <gui/SurfaceTextureClient.h> 26#include "../Camera2Device.h" 27#include "../Camera2Client.h" 28 29 30namespace android { 31namespace camera2 { 32 33CallbackProcessor::CallbackProcessor(wp<Camera2Client> client): 34 Thread(false), 35 mClient(client), 36 mCallbackAvailable(false), 37 mCallbackStreamId(NO_STREAM) { 38} 39 40CallbackProcessor::~CallbackProcessor() { 41 ALOGV("%s: Exit", __FUNCTION__); 42 deleteStream(); 43} 44 45void CallbackProcessor::onFrameAvailable() { 46 Mutex::Autolock l(mInputMutex); 47 if (!mCallbackAvailable) { 48 mCallbackAvailable = true; 49 mCallbackAvailableSignal.signal(); 50 } 51} 52 53status_t CallbackProcessor::updateStream(const Parameters ¶ms) { 54 ATRACE_CALL(); 55 status_t res; 56 57 Mutex::Autolock l(mInputMutex); 58 59 sp<Camera2Client> client = mClient.promote(); 60 if (client == 0) return OK; 61 sp<Camera2Device> device = client->getCameraDevice(); 62 63 if (mCallbackConsumer == 0) { 64 // Create CPU buffer queue endpoint 65 mCallbackConsumer = new CpuConsumer(kCallbackHeapCount); 66 mCallbackConsumer->setFrameAvailableListener(this); 67 mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer")); 68 mCallbackWindow = new SurfaceTextureClient( 69 mCallbackConsumer->getProducerInterface()); 70 } 71 72 if (mCallbackStreamId != NO_STREAM) { 73 // Check if stream parameters have to change 74 uint32_t currentWidth, currentHeight, currentFormat; 75 res = device->getStreamInfo(mCallbackStreamId, 76 ¤tWidth, ¤tHeight, ¤tFormat); 77 if (res != OK) { 78 ALOGE("%s: Camera %d: Error querying callback output stream info: " 79 "%s (%d)", __FUNCTION__, client->getCameraId(), 80 strerror(-res), res); 81 return res; 82 } 83 if (currentWidth != (uint32_t)params.previewWidth || 84 currentHeight != (uint32_t)params.previewHeight || 85 currentFormat != (uint32_t)params.previewFormat) { 86 // Since size should only change while preview is not running, 87 // assuming that all existing use of old callback stream is 88 // completed. 89 ALOGV("%s: Camera %d: Deleting stream %d since the buffer dimensions changed", 90 __FUNCTION__, client->getCameraId(), mCallbackStreamId); 91 res = device->deleteStream(mCallbackStreamId); 92 if (res != OK) { 93 ALOGE("%s: Camera %d: Unable to delete old output stream " 94 "for callbacks: %s (%d)", __FUNCTION__, client->getCameraId(), 95 strerror(-res), res); 96 return res; 97 } 98 mCallbackStreamId = NO_STREAM; 99 } 100 } 101 102 if (mCallbackStreamId == NO_STREAM) { 103 ALOGV("Creating callback stream: %d %d format 0x%x", 104 params.previewWidth, params.previewHeight, 105 params.previewFormat); 106 res = device->createStream(mCallbackWindow, 107 params.previewWidth, params.previewHeight, 108 params.previewFormat, 0, &mCallbackStreamId); 109 if (res != OK) { 110 ALOGE("%s: Camera %d: Can't create output stream for callbacks: " 111 "%s (%d)", __FUNCTION__, client->getCameraId(), 112 strerror(-res), res); 113 return res; 114 } 115 } 116 117 return OK; 118} 119 120status_t CallbackProcessor::deleteStream() { 121 ATRACE_CALL(); 122 status_t res; 123 124 Mutex::Autolock l(mInputMutex); 125 126 if (mCallbackStreamId != NO_STREAM) { 127 sp<Camera2Client> client = mClient.promote(); 128 if (client == 0) return OK; 129 sp<Camera2Device> device = client->getCameraDevice(); 130 131 device->deleteStream(mCallbackStreamId); 132 133 mCallbackHeap.clear(); 134 mCallbackWindow.clear(); 135 mCallbackConsumer.clear(); 136 137 mCallbackStreamId = NO_STREAM; 138 } 139 return OK; 140} 141 142int CallbackProcessor::getStreamId() const { 143 Mutex::Autolock l(mInputMutex); 144 return mCallbackStreamId; 145} 146 147void CallbackProcessor::dump(int fd, const Vector<String16>& args) const { 148} 149 150bool CallbackProcessor::threadLoop() { 151 status_t res; 152 153 { 154 Mutex::Autolock l(mInputMutex); 155 while (!mCallbackAvailable) { 156 res = mCallbackAvailableSignal.waitRelative(mInputMutex, 157 kWaitDuration); 158 if (res == TIMED_OUT) return true; 159 } 160 mCallbackAvailable = false; 161 } 162 163 do { 164 sp<Camera2Client> client = mClient.promote(); 165 if (client == 0) return false; 166 res = processNewCallback(client); 167 } while (res == OK); 168 169 return true; 170} 171 172status_t CallbackProcessor::processNewCallback(sp<Camera2Client> &client) { 173 ATRACE_CALL(); 174 status_t res; 175 176 int callbackHeapId; 177 sp<Camera2Heap> callbackHeap; 178 size_t heapIdx; 179 180 CpuConsumer::LockedBuffer imgBuffer; 181 ALOGV("%s: Getting buffer", __FUNCTION__); 182 res = mCallbackConsumer->lockNextBuffer(&imgBuffer); 183 if (res != OK) { 184 if (res != BAD_VALUE) { 185 ALOGE("%s: Camera %d: Error receiving next callback buffer: " 186 "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res); 187 } 188 return res; 189 } 190 ALOGV("%s: Camera %d: Preview callback available", __FUNCTION__, 191 client->getCameraId()); 192 193 { 194 SharedParameters::Lock l(client->getParameters()); 195 196 if ( l.mParameters.state != Parameters::PREVIEW 197 && l.mParameters.state != Parameters::RECORD 198 && l.mParameters.state != Parameters::VIDEO_SNAPSHOT) { 199 ALOGV("%s: Camera %d: No longer streaming", 200 __FUNCTION__, client->getCameraId()); 201 mCallbackConsumer->unlockBuffer(imgBuffer); 202 return OK; 203 } 204 205 if (! (l.mParameters.previewCallbackFlags & 206 CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) ) { 207 ALOGV("%s: No longer enabled, dropping", __FUNCTION__); 208 mCallbackConsumer->unlockBuffer(imgBuffer); 209 return OK; 210 } 211 if ((l.mParameters.previewCallbackFlags & 212 CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) && 213 !l.mParameters.previewCallbackOneShot) { 214 ALOGV("%s: One shot mode, already sent, dropping", __FUNCTION__); 215 mCallbackConsumer->unlockBuffer(imgBuffer); 216 return OK; 217 } 218 219 if (imgBuffer.format != l.mParameters.previewFormat) { 220 ALOGE("%s: Camera %d: Unexpected format for callback: " 221 "%x, expected %x", __FUNCTION__, client->getCameraId(), 222 imgBuffer.format, l.mParameters.previewFormat); 223 mCallbackConsumer->unlockBuffer(imgBuffer); 224 return INVALID_OPERATION; 225 } 226 227 // In one-shot mode, stop sending callbacks after the first one 228 if (l.mParameters.previewCallbackFlags & 229 CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) { 230 ALOGV("%s: clearing oneshot", __FUNCTION__); 231 l.mParameters.previewCallbackOneShot = false; 232 } 233 } 234 235 size_t bufferSize = Camera2Client::calculateBufferSize( 236 imgBuffer.width, imgBuffer.height, 237 imgBuffer.format, imgBuffer.stride); 238 size_t currentBufferSize = (mCallbackHeap == 0) ? 239 0 : (mCallbackHeap->mHeap->getSize() / kCallbackHeapCount); 240 if (bufferSize != currentBufferSize) { 241 mCallbackHeap.clear(); 242 mCallbackHeap = new Camera2Heap(bufferSize, kCallbackHeapCount, 243 "Camera2Client::CallbackHeap"); 244 if (mCallbackHeap->mHeap->getSize() == 0) { 245 ALOGE("%s: Camera %d: Unable to allocate memory for callbacks", 246 __FUNCTION__, client->getCameraId()); 247 mCallbackConsumer->unlockBuffer(imgBuffer); 248 return INVALID_OPERATION; 249 } 250 251 mCallbackHeapHead = 0; 252 mCallbackHeapFree = kCallbackHeapCount; 253 } 254 255 if (mCallbackHeapFree == 0) { 256 ALOGE("%s: Camera %d: No free callback buffers, dropping frame", 257 __FUNCTION__, client->getCameraId()); 258 mCallbackConsumer->unlockBuffer(imgBuffer); 259 return OK; 260 } 261 262 heapIdx = mCallbackHeapHead; 263 264 mCallbackHeapHead = (mCallbackHeapHead + 1) & kCallbackHeapCount; 265 mCallbackHeapFree--; 266 267 // TODO: Get rid of this memcpy by passing the gralloc queue all the way 268 // to app 269 270 ssize_t offset; 271 size_t size; 272 sp<IMemoryHeap> heap = 273 mCallbackHeap->mBuffers[heapIdx]->getMemory(&offset, 274 &size); 275 uint8_t *data = (uint8_t*)heap->getBase() + offset; 276 memcpy(data, imgBuffer.data, bufferSize); 277 278 ALOGV("%s: Freeing buffer", __FUNCTION__); 279 mCallbackConsumer->unlockBuffer(imgBuffer); 280 281 // Call outside parameter lock to allow re-entrancy from notification 282 { 283 Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient); 284 if (l.mCameraClient != 0) { 285 ALOGV("%s: Camera %d: Invoking client data callback", 286 __FUNCTION__, client->getCameraId()); 287 l.mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, 288 mCallbackHeap->mBuffers[heapIdx], NULL); 289 } 290 } 291 292 // Only increment free if we're still using the same heap 293 mCallbackHeapFree++; 294 295 ALOGV("%s: exit", __FUNCTION__); 296 297 return OK; 298} 299 300}; // namespace camera2 301}; // namespace android 302