blob: d07ae945d7ed9bfd8e16cfb483c1e040b32c1a65 [file] [log] [blame]
Eino-Ville Talvala8be20f52013-03-06 16:20:06 -08001/*
2 * Copyright (C) 2013 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 "Camera3-OutputStream"
18#define ATRACE_TAG ATRACE_TAG_CAMERA
19//#define LOG_NDEBUG 0
20
21// This is needed for stdint.h to define INT64_MAX in C++
22#define __STDC_LIMIT_MACROS
23
24#include <utils/Log.h>
25#include <utils/Trace.h>
26#include "Camera3OutputStream.h"
27
28#ifndef container_of
29#define container_of(ptr, type, member) \
30 (type *)((char*)(ptr) - offsetof(type, member))
31#endif
32
33namespace android {
34
35namespace camera3 {
36
37Camera3OutputStream::Camera3OutputStream(int id,
38 sp<ANativeWindow> consumer,
39 uint32_t width, uint32_t height, int format) :
40 Camera3Stream(id, CAMERA3_STREAM_OUTPUT, width, height, 0, format),
41 mConsumer(consumer),
42 mTransform(0),
43 mTotalBufferCount(0),
44 mDequeuedBufferCount(0),
45 mFrameCount(0),
46 mLastTimestamp(0) {
47
48 mCombinedFence = new Fence();
49 if (mConsumer == NULL) {
50 ALOGE("%s: Consumer is NULL!", __FUNCTION__);
51 mState = STATE_ERROR;
52 }
53}
54
55Camera3OutputStream::Camera3OutputStream(int id,
56 sp<ANativeWindow> consumer,
57 uint32_t width, uint32_t height, size_t maxSize, int format) :
58 Camera3Stream(id, CAMERA3_STREAM_OUTPUT,
59 width, height, maxSize, format),
60 mConsumer(consumer) {
61
62 if (format != HAL_PIXEL_FORMAT_BLOB) {
63 ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
64 format);
65 mState = STATE_ERROR;
66 }
67
68 if (mConsumer == NULL) {
69 ALOGE("%s: Consumer is NULL!", __FUNCTION__);
70 mState = STATE_ERROR;
71 }
72}
73
74Camera3OutputStream::~Camera3OutputStream() {
75 disconnectLocked();
76}
77
78status_t Camera3OutputStream::getBufferLocked(camera3_stream_buffer *buffer) {
79 ATRACE_CALL();
80 status_t res;
81
82 // Allow dequeue during IN_[RE]CONFIG for registration
83 if (mState != STATE_CONFIGURED &&
84 mState != STATE_IN_CONFIG && mState != STATE_IN_RECONFIG) {
85 ALOGE("%s: Stream %d: Can't get buffers in unconfigured state %d",
86 __FUNCTION__, mId, mState);
87 return INVALID_OPERATION;
88 }
89
90 // Only limit dequeue amount when fully configured
91 if (mState == STATE_CONFIGURED &&
92 mDequeuedBufferCount == camera3_stream::max_buffers) {
93 ALOGE("%s: Stream %d: Already dequeued maximum number of simultaneous"
94 " buffers (%d)", __FUNCTION__, mId,
95 camera3_stream::max_buffers);
96 return INVALID_OPERATION;
97 }
98
99 ANativeWindowBuffer* anb;
100 int fenceFd;
101
102 res = mConsumer->dequeueBuffer(mConsumer.get(), &anb, &fenceFd);
103 if (res != OK) {
104 ALOGE("%s: Stream %d: Can't dequeue next output buffer: %s (%d)",
105 __FUNCTION__, mId, strerror(-res), res);
106 return res;
107 }
108
109 // Handing out a raw pointer to this object. Increment internal refcount.
110 incStrong(this);
111 buffer->stream = this;
112 buffer->buffer = &(anb->handle);
113 buffer->acquire_fence = fenceFd;
114 buffer->release_fence = -1;
115 buffer->status = CAMERA3_BUFFER_STATUS_OK;
116
117 mDequeuedBufferCount++;
118
119 return OK;
120}
121
122status_t Camera3OutputStream::returnBufferLocked(
123 const camera3_stream_buffer &buffer,
124 nsecs_t timestamp) {
125 ATRACE_CALL();
126 status_t res;
127
128 // returnBuffer may be called from a raw pointer, not a sp<>, and we'll be
129 // decrementing the internal refcount next. In case this is the last ref, we
130 // might get destructed on the decStrong(), so keep an sp around until the
131 // end of the call - otherwise have to sprinkle the decStrong on all exit
132 // points.
133 sp<Camera3OutputStream> keepAlive(this);
134 decStrong(this);
135
136 // Allow buffers to be returned in the error state, to allow for disconnect
137 // and in the in-config states for registration
138 if (mState == STATE_CONSTRUCTED) {
139 ALOGE("%s: Stream %d: Can't return buffers in unconfigured state %d",
140 __FUNCTION__, mId, mState);
141 return INVALID_OPERATION;
142 }
143 if (mDequeuedBufferCount == 0) {
144 ALOGE("%s: Stream %d: No buffers outstanding to return", __FUNCTION__,
145 mId);
146 return INVALID_OPERATION;
147 }
148 if (buffer.status == CAMERA3_BUFFER_STATUS_ERROR) {
149 res = mConsumer->cancelBuffer(mConsumer.get(),
150 container_of(buffer.buffer, ANativeWindowBuffer, handle),
151 buffer.release_fence);
152 if (res != OK) {
153 ALOGE("%s: Stream %d: Error cancelling buffer to native window:"
154 " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
155 return res;
156 }
157 } else {
158 res = native_window_set_buffers_timestamp(mConsumer.get(), timestamp);
159 if (res != OK) {
160 ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)",
161 __FUNCTION__, mId, strerror(-res), res);
162 return res;
163 }
164
165 sp<Fence> releaseFence = new Fence(buffer.release_fence);
166 int anwReleaseFence = releaseFence->dup();
167
168 res = mConsumer->queueBuffer(mConsumer.get(),
169 container_of(buffer.buffer, ANativeWindowBuffer, handle),
170 anwReleaseFence);
171 if (res != OK) {
172 ALOGE("%s: Stream %d: Error queueing buffer to native window: %s (%d)",
173 __FUNCTION__, mId, strerror(-res), res);
174 close(anwReleaseFence);
175 return res;
176 }
177
178 mCombinedFence = Fence::merge(mName, mCombinedFence, releaseFence);
179 }
180
181 mDequeuedBufferCount--;
182 mBufferReturnedSignal.signal();
183 mLastTimestamp = timestamp;
184
185 return OK;
186}
187
188bool Camera3OutputStream::hasOutstandingBuffersLocked() const {
189 nsecs_t signalTime = mCombinedFence->getSignalTime();
190 ALOGV("%s: Stream %d: Has %d outstanding buffers,"
191 " buffer signal time is %lld",
192 __FUNCTION__, mId, mDequeuedBufferCount, signalTime);
193 if (mDequeuedBufferCount > 0 || signalTime == INT64_MAX) {
194 return true;
195 }
196 return false;
197}
198
199status_t Camera3OutputStream::waitUntilIdle(nsecs_t timeout) {
200 status_t res;
201 {
202 Mutex::Autolock l(mLock);
203 while (mDequeuedBufferCount > 0) {
204 if (timeout != TIMEOUT_NEVER) {
205 nsecs_t startTime = systemTime();
206 res = mBufferReturnedSignal.waitRelative(mLock, timeout);
207 if (res == TIMED_OUT) {
208 return res;
209 } else if (res != OK) {
210 ALOGE("%s: Error waiting for outstanding buffers: %s (%d)",
211 __FUNCTION__, strerror(-res), res);
212 return res;
213 }
214 nsecs_t deltaTime = systemTime() - startTime;
215 if (timeout <= deltaTime) {
216 timeout = 0;
217 } else {
218 timeout -= deltaTime;
219 }
220 } else {
221 res = mBufferReturnedSignal.wait(mLock);
222 if (res != OK) {
223 ALOGE("%s: Error waiting for outstanding buffers: %s (%d)",
224 __FUNCTION__, strerror(-res), res);
225 return res;
226 }
227 }
228 }
229 }
230
231 // No lock
232
233 unsigned int timeoutMs;
234 if (timeout == TIMEOUT_NEVER) {
235 timeoutMs = Fence::TIMEOUT_NEVER;
236 } else if (timeout == 0) {
237 timeoutMs = 0;
238 } else {
239 // Round up to wait at least 1 ms
240 timeoutMs = (timeout + 999999) / 1000000;
241 }
242
243 return mCombinedFence->wait(timeoutMs);
244}
245
246void Camera3OutputStream::dump(int fd, const Vector<String16> &args) const {
247 (void) args;
248 String8 lines;
249 lines.appendFormat(" Stream[%d]: Output\n", mId);
250 lines.appendFormat(" State: %d\n", mState);
251 lines.appendFormat(" Dims: %d x %d, format 0x%x\n",
252 camera3_stream::width, camera3_stream::height,
253 camera3_stream::format);
254 lines.appendFormat(" Max size: %d\n", mMaxSize);
255 lines.appendFormat(" Usage: %d, max HAL buffers: %d\n",
256 camera3_stream::usage, camera3_stream::max_buffers);
257 lines.appendFormat(" Frames produced: %d, last timestamp: %lld ns\n",
258 mFrameCount, mLastTimestamp);
259 lines.appendFormat(" Total buffers: %d, currently dequeued: %d\n",
260 mTotalBufferCount, mDequeuedBufferCount);
261 write(fd, lines.string(), lines.size());
262}
263
264status_t Camera3OutputStream::setTransform(int transform) {
265 ATRACE_CALL();
266 Mutex::Autolock l(mLock);
267 return setTransformLocked(transform);
268}
269
270status_t Camera3OutputStream::setTransformLocked(int transform) {
271 status_t res = OK;
272 if (mState == STATE_ERROR) {
273 ALOGE("%s: Stream in error state", __FUNCTION__);
274 return INVALID_OPERATION;
275 }
276
277 mTransform = transform;
278 if (mState == STATE_CONFIGURED) {
279 res = native_window_set_buffers_transform(mConsumer.get(),
280 transform);
281 if (res != OK) {
282 ALOGE("%s: Unable to configure stream transform to %x: %s (%d)",
283 __FUNCTION__, transform, strerror(-res), res);
284 }
285 }
286 return res;
287}
288
289status_t Camera3OutputStream::configureQueueLocked() {
290 status_t res;
291
292 switch (mState) {
293 case STATE_IN_RECONFIG:
294 res = disconnect();
295 if (res != OK) {
296 return res;
297 }
298 break;
299 case STATE_IN_CONFIG:
300 // OK
301 break;
302 default:
303 ALOGE("%s: Bad state: %d", __FUNCTION__, mState);
304 return INVALID_OPERATION;
305 }
306
307 // Configure consumer-side ANativeWindow interface
308 res = native_window_api_connect(mConsumer.get(),
309 NATIVE_WINDOW_API_CAMERA);
310 if (res != OK) {
311 ALOGE("%s: Unable to connect to native window for stream %d",
312 __FUNCTION__, mId);
313 return res;
314 }
315
316 res = native_window_set_usage(mConsumer.get(), camera3_stream::usage);
317 if (res != OK) {
318 ALOGE("%s: Unable to configure usage %08x for stream %d",
319 __FUNCTION__, camera3_stream::usage, mId);
320 return res;
321 }
322
323 res = native_window_set_scaling_mode(mConsumer.get(),
324 NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
325 if (res != OK) {
326 ALOGE("%s: Unable to configure stream scaling: %s (%d)",
327 __FUNCTION__, strerror(-res), res);
328 return res;
329 }
330
331 res = setTransformLocked(0);
332 if (res != OK) {
333 return res;
334 }
335
336 if (mMaxSize == 0) {
337 // For buffers of known size
338 res = native_window_set_buffers_geometry(mConsumer.get(),
339 camera3_stream::width, camera3_stream::height,
340 camera3_stream::format);
341 } else {
342 // For buffers with bounded size
343 res = native_window_set_buffers_geometry(mConsumer.get(),
344 mMaxSize, 1,
345 camera3_stream::format);
346 }
347 if (res != OK) {
348 ALOGE("%s: Unable to configure stream buffer geometry"
349 " %d x %d, format %x for stream %d",
350 __FUNCTION__, camera3_stream::width, camera3_stream::height,
351 camera3_stream::format, mId);
352 return res;
353 }
354
355 int maxConsumerBuffers;
356 res = mConsumer->query(mConsumer.get(),
357 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
358 if (res != OK) {
359 ALOGE("%s: Unable to query consumer undequeued"
360 " buffer count for stream %d", __FUNCTION__, mId);
361 return res;
362 }
363
364 ALOGV("%s: Consumer wants %d buffers", __FUNCTION__,
365 maxConsumerBuffers);
366
367 mTotalBufferCount = maxConsumerBuffers + camera3_stream::max_buffers;
368 mDequeuedBufferCount = 0;
369 mFrameCount = 0;
370 mLastTimestamp = 0;
371
372 res = native_window_set_buffer_count(mConsumer.get(),
373 mTotalBufferCount);
374 if (res != OK) {
375 ALOGE("%s: Unable to set buffer count for stream %d",
376 __FUNCTION__, mId);
377 return res;
378 }
379
380 res = native_window_set_buffers_transform(mConsumer.get(),
381 mTransform);
382 if (res != OK) {
383 ALOGE("%s: Unable to configure stream transform to %x: %s (%d)",
384 __FUNCTION__, mTransform, strerror(-res), res);
385 }
386
387 return OK;
388}
389
390size_t Camera3OutputStream::getBufferCountLocked() {
391 return mTotalBufferCount;
392}
393
394status_t Camera3OutputStream::disconnectLocked() {
395 status_t res;
396
397 switch (mState) {
398 case STATE_IN_RECONFIG:
399 case STATE_CONFIGURED:
400 // OK
401 break;
402 default:
403 // No connection, nothing to do
404 return OK;
405 }
406
407 if (mDequeuedBufferCount > 0) {
408 ALOGE("%s: Can't disconnect with %d buffers still dequeued!",
409 __FUNCTION__, mDequeuedBufferCount);
410 return INVALID_OPERATION;
411 }
412
413 res = native_window_api_disconnect(mConsumer.get(), NATIVE_WINDOW_API_CAMERA);
414
415 /**
416 * This is not an error. if client calling process dies, the window will
417 * also die and all calls to it will return DEAD_OBJECT, thus it's already
418 * "disconnected"
419 */
420 if (res == DEAD_OBJECT) {
421 ALOGW("%s: While disconnecting stream %d from native window, the"
422 " native window died from under us", __FUNCTION__, mId);
423 }
424 else if (res != OK) {
425 ALOGE("%s: Unable to disconnect stream %d from native window (error %d %s)",
426 __FUNCTION__, mId, res, strerror(-res));
427 mState = STATE_ERROR;
428 return res;
429 }
430
431 mState = (mState == STATE_IN_RECONFIG) ? STATE_IN_CONFIG : STATE_CONSTRUCTED;
432 return OK;
433}
434
435}; // namespace camera3
436
437}; // namespace android