CallbackProcessor.cpp revision cf70d3469332445dc3ffd09729da3538612b1bb2
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 "Camera2Client::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 res = device->deleteStream(mCallbackStreamId); 90 if (res != OK) { 91 ALOGE("%s: Camera %d: Unable to delete old output stream " 92 "for callbacks: %s (%d)", __FUNCTION__, client->getCameraId(), 93 strerror(-res), res); 94 return res; 95 } 96 mCallbackStreamId = NO_STREAM; 97 } 98 } 99 100 if (mCallbackStreamId == NO_STREAM) { 101 ALOGV("Creating callback stream: %d %d format 0x%x", 102 params.previewWidth, params.previewHeight, 103 params.previewFormat); 104 res = device->createStream(mCallbackWindow, 105 params.previewWidth, params.previewHeight, 106 params.previewFormat, 0, &mCallbackStreamId); 107 if (res != OK) { 108 ALOGE("%s: Camera %d: Can't create output stream for callbacks: " 109 "%s (%d)", __FUNCTION__, client->getCameraId(), 110 strerror(-res), res); 111 return res; 112 } 113 } 114 115 return OK; 116} 117 118status_t CallbackProcessor::deleteStream() { 119 ATRACE_CALL(); 120 status_t res; 121 122 Mutex::Autolock l(mInputMutex); 123 124 if (mCallbackStreamId != NO_STREAM) { 125 sp<Camera2Client> client = mClient.promote(); 126 if (client == 0) return OK; 127 sp<Camera2Device> device = client->getCameraDevice(); 128 129 device->deleteStream(mCallbackStreamId); 130 131 mCallbackHeap.clear(); 132 mCallbackWindow.clear(); 133 mCallbackConsumer.clear(); 134 135 mCallbackStreamId = NO_STREAM; 136 } 137 return OK; 138} 139 140int CallbackProcessor::getStreamId() const { 141 Mutex::Autolock l(mInputMutex); 142 return mCallbackStreamId; 143} 144 145void CallbackProcessor::dump(int fd, const Vector<String16>& args) const { 146} 147 148bool CallbackProcessor::threadLoop() { 149 status_t res; 150 151 { 152 Mutex::Autolock l(mInputMutex); 153 while (!mCallbackAvailable) { 154 res = mCallbackAvailableSignal.waitRelative(mInputMutex, 155 kWaitDuration); 156 if (res == TIMED_OUT) return true; 157 } 158 mCallbackAvailable = false; 159 } 160 161 do { 162 sp<Camera2Client> client = mClient.promote(); 163 if (client == 0) return false; 164 res = processNewCallback(client); 165 } while (res == OK); 166 167 return true; 168} 169 170status_t CallbackProcessor::processNewCallback(sp<Camera2Client> &client) { 171 ATRACE_CALL(); 172 status_t res; 173 174 int callbackHeapId; 175 sp<Camera2Heap> callbackHeap; 176 size_t heapIdx; 177 178 CpuConsumer::LockedBuffer imgBuffer; 179 ALOGV("%s: Getting buffer", __FUNCTION__); 180 res = mCallbackConsumer->lockNextBuffer(&imgBuffer); 181 if (res != OK) { 182 if (res != BAD_VALUE) { 183 ALOGE("%s: Camera %d: Error receiving next callback buffer: " 184 "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res); 185 } 186 return res; 187 } 188 ALOGV("%s: Camera %d: Preview callback available", __FUNCTION__, 189 client->getCameraId()); 190 191 { 192 SharedParameters::Lock l(client->getParameters()); 193 194 if ( l.mParameters.state != Parameters::PREVIEW 195 && l.mParameters.state != Parameters::RECORD 196 && l.mParameters.state != Parameters::VIDEO_SNAPSHOT) { 197 ALOGV("%s: Camera %d: No longer streaming", 198 __FUNCTION__, client->getCameraId()); 199 mCallbackConsumer->unlockBuffer(imgBuffer); 200 return OK; 201 } 202 203 if (! (l.mParameters.previewCallbackFlags & 204 CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) ) { 205 ALOGV("%s: No longer enabled, dropping", __FUNCTION__); 206 mCallbackConsumer->unlockBuffer(imgBuffer); 207 return OK; 208 } 209 if ((l.mParameters.previewCallbackFlags & 210 CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) && 211 !l.mParameters.previewCallbackOneShot) { 212 ALOGV("%s: One shot mode, already sent, dropping", __FUNCTION__); 213 mCallbackConsumer->unlockBuffer(imgBuffer); 214 return OK; 215 } 216 217 if (imgBuffer.format != l.mParameters.previewFormat) { 218 ALOGE("%s: Camera %d: Unexpected format for callback: " 219 "%x, expected %x", __FUNCTION__, client->getCameraId(), 220 imgBuffer.format, l.mParameters.previewFormat); 221 mCallbackConsumer->unlockBuffer(imgBuffer); 222 return INVALID_OPERATION; 223 } 224 225 // In one-shot mode, stop sending callbacks after the first one 226 if (l.mParameters.previewCallbackFlags & 227 CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) { 228 ALOGV("%s: clearing oneshot", __FUNCTION__); 229 l.mParameters.previewCallbackOneShot = false; 230 } 231 } 232 233 size_t bufferSize = Camera2Client::calculateBufferSize( 234 imgBuffer.width, imgBuffer.height, 235 imgBuffer.format, imgBuffer.stride); 236 size_t currentBufferSize = (mCallbackHeap == 0) ? 237 0 : (mCallbackHeap->mHeap->getSize() / kCallbackHeapCount); 238 if (bufferSize != currentBufferSize) { 239 mCallbackHeap.clear(); 240 mCallbackHeap = new Camera2Heap(bufferSize, kCallbackHeapCount, 241 "Camera2Client::CallbackHeap"); 242 if (mCallbackHeap->mHeap->getSize() == 0) { 243 ALOGE("%s: Camera %d: Unable to allocate memory for callbacks", 244 __FUNCTION__, client->getCameraId()); 245 mCallbackConsumer->unlockBuffer(imgBuffer); 246 return INVALID_OPERATION; 247 } 248 249 mCallbackHeapHead = 0; 250 mCallbackHeapFree = kCallbackHeapCount; 251 } 252 253 if (mCallbackHeapFree == 0) { 254 ALOGE("%s: Camera %d: No free callback buffers, dropping frame", 255 __FUNCTION__, client->getCameraId()); 256 mCallbackConsumer->unlockBuffer(imgBuffer); 257 return OK; 258 } 259 260 heapIdx = mCallbackHeapHead; 261 262 mCallbackHeapHead = (mCallbackHeapHead + 1) & kCallbackHeapCount; 263 mCallbackHeapFree--; 264 265 // TODO: Get rid of this memcpy by passing the gralloc queue all the way 266 // to app 267 268 ssize_t offset; 269 size_t size; 270 sp<IMemoryHeap> heap = 271 mCallbackHeap->mBuffers[heapIdx]->getMemory(&offset, 272 &size); 273 uint8_t *data = (uint8_t*)heap->getBase() + offset; 274 memcpy(data, imgBuffer.data, bufferSize); 275 276 ALOGV("%s: Freeing buffer", __FUNCTION__); 277 mCallbackConsumer->unlockBuffer(imgBuffer); 278 279 // Call outside parameter lock to allow re-entrancy from notification 280 { 281 Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient); 282 if (l.mCameraClient != 0) { 283 ALOGV("%s: Camera %d: Invoking client data callback", 284 __FUNCTION__, client->getCameraId()); 285 l.mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, 286 mCallbackHeap->mBuffers[heapIdx], NULL); 287 } 288 } 289 290 // Only increment free if we're still using the same heap 291 mCallbackHeapFree++; 292 293 ALOGV("%s: exit", __FUNCTION__); 294 295 return OK; 296} 297 298}; // namespace camera2 299}; // namespace android 300