blob: 1bc2fb9eecd7ceaf3d5633bd643fff6d69884875 [file] [log] [blame]
Andreas Huber20111aa2009-07-14 16:56:47 -07001/*
2 * Copyright (C) 2009 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
James Dongc32cd792010-04-26 17:48:26 -070017//#define LOG_NDEBUG 0
18#define LOG_TAG "CameraSource"
19#include <utils/Log.h>
Andreas Huber20111aa2009-07-14 16:56:47 -070020
Andreas Huber20111aa2009-07-14 16:56:47 -070021#include <OMX_Component.h>
James Dong9d7f58a2010-06-09 15:57:48 -070022#include <binder/IPCThreadState.h>
Andreas Huber20111aa2009-07-14 16:56:47 -070023#include <media/stagefright/CameraSource.h>
Andreas Huber0c891992009-08-26 14:48:20 -070024#include <media/stagefright/MediaDebug.h>
Andreas Huberbe5c74f2009-10-13 17:08:31 -070025#include <media/stagefright/MediaDefs.h>
Andreas Huber20111aa2009-07-14 16:56:47 -070026#include <media/stagefright/MediaErrors.h>
27#include <media/stagefright/MetaData.h>
Mathias Agopian3cf61352010-02-09 17:46:37 -080028#include <camera/Camera.h>
29#include <camera/CameraParameters.h>
James Dong54ff19a2010-10-08 11:59:32 -070030#include <surfaceflinger/Surface.h>
Andreas Huberbe5c74f2009-10-13 17:08:31 -070031#include <utils/String8.h>
James Dong365a9632010-06-04 13:59:27 -070032#include <cutils/properties.h>
Andreas Huber20111aa2009-07-14 16:56:47 -070033
34namespace android {
35
Andreas Huberbe5c74f2009-10-13 17:08:31 -070036struct CameraSourceListener : public CameraListener {
37 CameraSourceListener(const sp<CameraSource> &source);
38
39 virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
40 virtual void postData(int32_t msgType, const sp<IMemory> &dataPtr);
41
42 virtual void postDataTimestamp(
43 nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
44
45protected:
46 virtual ~CameraSourceListener();
47
48private:
49 wp<CameraSource> mSource;
50
51 CameraSourceListener(const CameraSourceListener &);
52 CameraSourceListener &operator=(const CameraSourceListener &);
53};
54
55CameraSourceListener::CameraSourceListener(const sp<CameraSource> &source)
56 : mSource(source) {
57}
58
59CameraSourceListener::~CameraSourceListener() {
60}
61
62void CameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
63 LOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
64}
65
66void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr) {
67 LOGV("postData(%d, ptr:%p, size:%d)",
68 msgType, dataPtr->pointer(), dataPtr->size());
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -070069
70 sp<CameraSource> source = mSource.promote();
71 if (source.get() != NULL) {
72 source->dataCallback(msgType, dataPtr);
73 }
Andreas Huberbe5c74f2009-10-13 17:08:31 -070074}
75
76void CameraSourceListener::postDataTimestamp(
77 nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
James Dongc32cd792010-04-26 17:48:26 -070078
79 sp<CameraSource> source = mSource.promote();
80 if (source.get() != NULL) {
81 source->dataCallbackTimestamp(timestamp/1000, msgType, dataPtr);
82 }
Andreas Huberbe5c74f2009-10-13 17:08:31 -070083}
84
James Dong653252b2010-06-03 11:48:31 -070085static int32_t getColorFormat(const char* colorFormat) {
James Donge2d8ba82010-09-15 16:52:51 -070086 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) {
87 return OMX_COLOR_FormatYUV420Planar;
88 }
89
James Dong653252b2010-06-03 11:48:31 -070090 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422SP)) {
91 return OMX_COLOR_FormatYUV422SemiPlanar;
92 }
93
94 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) {
95 return OMX_COLOR_FormatYUV420SemiPlanar;
96 }
97
98 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422I)) {
99 return OMX_COLOR_FormatYCbYCr;
100 }
101
102 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_RGB565)) {
103 return OMX_COLOR_Format16bitRGB565;
104 }
105
Dandawate Saket1374edd2011-07-11 19:12:57 -0700106 if (!strcmp(colorFormat, "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar")) {
107 return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar;
108 }
109
James Donga1abc1a2010-09-13 16:30:51 -0700110 LOGE("Uknown color format (%s), please add it to "
111 "CameraSource::getColorFormat", colorFormat);
112
James Dong653252b2010-06-03 11:48:31 -0700113 CHECK_EQ(0, "Unknown color format");
114}
115
Andreas Huber20111aa2009-07-14 16:56:47 -0700116CameraSource *CameraSource::Create() {
James Dong54ff19a2010-10-08 11:59:32 -0700117 Size size;
118 size.width = -1;
119 size.height = -1;
Andreas Huber20111aa2009-07-14 16:56:47 -0700120
James Dong54ff19a2010-10-08 11:59:32 -0700121 sp<ICamera> camera;
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800122 return new CameraSource(camera, NULL, 0, size, -1, NULL, false);
Andreas Huber20111aa2009-07-14 16:56:47 -0700123}
124
Andreas Huber30ab6622009-11-16 15:43:38 -0800125// static
James Dong54ff19a2010-10-08 11:59:32 -0700126CameraSource *CameraSource::CreateFromCamera(
127 const sp<ICamera>& camera,
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800128 const sp<ICameraRecordingProxy>& proxy,
James Dong54ff19a2010-10-08 11:59:32 -0700129 int32_t cameraId,
130 Size videoSize,
131 int32_t frameRate,
James Dong5c952312010-10-18 21:42:27 -0700132 const sp<Surface>& surface,
133 bool storeMetaDataInVideoBuffers) {
Andreas Huber30ab6622009-11-16 15:43:38 -0800134
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800135 CameraSource *source = new CameraSource(camera, proxy, cameraId,
James Dong5c952312010-10-18 21:42:27 -0700136 videoSize, frameRate, surface,
137 storeMetaDataInVideoBuffers);
James Dong54ff19a2010-10-08 11:59:32 -0700138 return source;
Andreas Huber30ab6622009-11-16 15:43:38 -0800139}
140
James Dong54ff19a2010-10-08 11:59:32 -0700141CameraSource::CameraSource(
142 const sp<ICamera>& camera,
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800143 const sp<ICameraRecordingProxy>& proxy,
James Dong54ff19a2010-10-08 11:59:32 -0700144 int32_t cameraId,
145 Size videoSize,
146 int32_t frameRate,
James Dong5c952312010-10-18 21:42:27 -0700147 const sp<Surface>& surface,
148 bool storeMetaDataInVideoBuffers)
James Dong54ff19a2010-10-08 11:59:32 -0700149 : mCameraFlags(0),
150 mVideoFrameRate(-1),
151 mCamera(0),
152 mSurface(surface),
James Dong13aec892010-04-21 16:14:15 -0700153 mNumFramesReceived(0),
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700154 mLastFrameTimestampUs(0),
155 mStarted(false),
James Dong13aec892010-04-21 16:14:15 -0700156 mNumFramesEncoded(0),
James Dong7757f502011-01-25 16:31:28 -0800157 mFirstFrameTimeUs(0),
James Dong13aec892010-04-21 16:14:15 -0700158 mNumFramesDropped(0),
James Dongf60cafe2010-06-19 09:04:18 -0700159 mNumGlitches(0),
160 mGlitchDurationThresholdUs(200000),
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700161 mCollectStats(false) {
James Dong54ff19a2010-10-08 11:59:32 -0700162 mVideoSize.width = -1;
163 mVideoSize.height = -1;
164
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800165 mInitCheck = init(camera, proxy, cameraId,
James Dong5c952312010-10-18 21:42:27 -0700166 videoSize, frameRate,
167 storeMetaDataInVideoBuffers);
Wu-cheng Li95068be2011-06-29 15:17:11 +0800168 if (mInitCheck != OK) releaseCamera();
James Dong54ff19a2010-10-08 11:59:32 -0700169}
170
171status_t CameraSource::initCheck() const {
172 return mInitCheck;
173}
174
175status_t CameraSource::isCameraAvailable(
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800176 const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
177 int32_t cameraId) {
James Dong54ff19a2010-10-08 11:59:32 -0700178
179 if (camera == 0) {
180 mCamera = Camera::connect(cameraId);
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800181 if (mCamera == 0) return -EBUSY;
182 // If proxy is not passed in by applications, still use the proxy of
183 // our own Camera to simplify the code.
184 mCameraRecordingProxy = mCamera->getRecordingProxy();
James Dong54ff19a2010-10-08 11:59:32 -0700185 mCameraFlags &= ~FLAGS_HOT_CAMERA;
186 } else {
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800187 // We get the proxy from Camera, not ICamera. We need to get the proxy
188 // to the remote Camera owned by the application. Here mCamera is a
189 // local Camera object created by us. We cannot use the proxy from
190 // mCamera here.
James Dong54ff19a2010-10-08 11:59:32 -0700191 mCamera = Camera::create(camera);
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800192 if (mCamera == 0) return -EBUSY;
193 mCameraRecordingProxy = proxy;
James Dong54ff19a2010-10-08 11:59:32 -0700194 mCameraFlags |= FLAGS_HOT_CAMERA;
195 }
196
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800197 mCamera->lock();
198 mDeathNotifier = new DeathNotifier();
199 // isBinderAlive needs linkToDeath to work.
200 mCameraRecordingProxy->asBinder()->linkToDeath(mDeathNotifier);
201
James Dong54ff19a2010-10-08 11:59:32 -0700202 return OK;
203}
204
205
206/*
207 * Check to see whether the requested video width and height is one
208 * of the supported sizes.
209 * @param width the video frame width in pixels
210 * @param height the video frame height in pixels
211 * @param suppportedSizes the vector of sizes that we check against
212 * @return true if the dimension (width and height) is supported.
213 */
214static bool isVideoSizeSupported(
215 int32_t width, int32_t height,
216 const Vector<Size>& supportedSizes) {
217
218 LOGV("isVideoSizeSupported");
219 for (size_t i = 0; i < supportedSizes.size(); ++i) {
220 if (width == supportedSizes[i].width &&
221 height == supportedSizes[i].height) {
222 return true;
223 }
224 }
225 return false;
226}
227
228/*
229 * If the preview and video output is separate, we only set the
230 * the video size, and applications should set the preview size
231 * to some proper value, and the recording framework will not
232 * change the preview size; otherwise, if the video and preview
233 * output is the same, we need to set the preview to be the same
234 * as the requested video size.
235 *
236 */
237/*
238 * Query the camera to retrieve the supported video frame sizes
239 * and also to see whether CameraParameters::setVideoSize()
240 * is supported or not.
241 * @param params CameraParameters to retrieve the information
242 * @@param isSetVideoSizeSupported retunrs whether method
243 * CameraParameters::setVideoSize() is supported or not.
244 * @param sizes returns the vector of Size objects for the
245 * supported video frame sizes advertised by the camera.
246 */
247static void getSupportedVideoSizes(
248 const CameraParameters& params,
249 bool *isSetVideoSizeSupported,
250 Vector<Size>& sizes) {
251
252 *isSetVideoSizeSupported = true;
253 params.getSupportedVideoSizes(sizes);
254 if (sizes.size() == 0) {
255 LOGD("Camera does not support setVideoSize()");
256 params.getSupportedPreviewSizes(sizes);
257 *isSetVideoSizeSupported = false;
258 }
259}
260
261/*
262 * Check whether the camera has the supported color format
263 * @param params CameraParameters to retrieve the information
264 * @return OK if no error.
265 */
266status_t CameraSource::isCameraColorFormatSupported(
267 const CameraParameters& params) {
268 mColorFormat = getColorFormat(params.get(
269 CameraParameters::KEY_VIDEO_FRAME_FORMAT));
270 if (mColorFormat == -1) {
271 return BAD_VALUE;
272 }
273 return OK;
274}
275
276/*
277 * Configure the camera to use the requested video size
278 * (width and height) and/or frame rate. If both width and
279 * height are -1, configuration on the video size is skipped.
280 * if frameRate is -1, configuration on the frame rate
281 * is skipped. Skipping the configuration allows one to
282 * use the current camera setting without the need to
283 * actually know the specific values (see Create() method).
284 *
285 * @param params the CameraParameters to be configured
286 * @param width the target video frame width in pixels
287 * @param height the target video frame height in pixels
288 * @param frameRate the target frame rate in frames per second.
289 * @return OK if no error.
290 */
291status_t CameraSource::configureCamera(
292 CameraParameters* params,
293 int32_t width, int32_t height,
294 int32_t frameRate) {
295
296 Vector<Size> sizes;
297 bool isSetVideoSizeSupportedByCamera = true;
298 getSupportedVideoSizes(*params, &isSetVideoSizeSupportedByCamera, sizes);
299 bool isCameraParamChanged = false;
300 if (width != -1 && height != -1) {
301 if (!isVideoSizeSupported(width, height, sizes)) {
302 LOGE("Video dimension (%dx%d) is unsupported", width, height);
303 return BAD_VALUE;
304 }
305 if (isSetVideoSizeSupportedByCamera) {
306 params->setVideoSize(width, height);
307 } else {
308 params->setPreviewSize(width, height);
309 }
310 isCameraParamChanged = true;
311 } else if ((width == -1 && height != -1) ||
312 (width != -1 && height == -1)) {
313 // If one and only one of the width and height is -1
314 // we reject such a request.
315 LOGE("Requested video size (%dx%d) is not supported", width, height);
316 return BAD_VALUE;
317 } else { // width == -1 && height == -1
318 // Do not configure the camera.
319 // Use the current width and height value setting from the camera.
320 }
321
322 if (frameRate != -1) {
James Dong63573082010-10-24 09:32:39 -0700323 CHECK(frameRate > 0 && frameRate <= 120);
324 const char* supportedFrameRates =
325 params->get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES);
326 CHECK(supportedFrameRates != NULL);
327 LOGV("Supported frame rates: %s", supportedFrameRates);
328 char buf[4];
329 snprintf(buf, 4, "%d", frameRate);
330 if (strstr(supportedFrameRates, buf) == NULL) {
331 LOGE("Requested frame rate (%d) is not supported: %s",
332 frameRate, supportedFrameRates);
333 return BAD_VALUE;
334 }
335
336 // The frame rate is supported, set the camera to the requested value.
James Dong54ff19a2010-10-08 11:59:32 -0700337 params->setPreviewFrameRate(frameRate);
338 isCameraParamChanged = true;
339 } else { // frameRate == -1
340 // Do not configure the camera.
341 // Use the current frame rate value setting from the camera
342 }
343
344 if (isCameraParamChanged) {
345 // Either frame rate or frame size needs to be changed.
346 String8 s = params->flatten();
347 if (OK != mCamera->setParameters(s)) {
348 LOGE("Could not change settings."
349 " Someone else is using camera %p?", mCamera.get());
350 return -EBUSY;
351 }
352 }
353 return OK;
354}
355
356/*
357 * Check whether the requested video frame size
358 * has been successfully configured or not. If both width and height
359 * are -1, check on the current width and height value setting
360 * is performed.
361 *
362 * @param params CameraParameters to retrieve the information
363 * @param the target video frame width in pixels to check against
364 * @param the target video frame height in pixels to check against
365 * @return OK if no error
366 */
367status_t CameraSource::checkVideoSize(
368 const CameraParameters& params,
369 int32_t width, int32_t height) {
370
James Dongf96c9d12010-10-20 11:41:33 -0700371 // The actual video size is the same as the preview size
372 // if the camera hal does not support separate video and
373 // preview output. In this case, we retrieve the video
374 // size from preview.
James Dong54ff19a2010-10-08 11:59:32 -0700375 int32_t frameWidthActual = -1;
376 int32_t frameHeightActual = -1;
James Dongf96c9d12010-10-20 11:41:33 -0700377 Vector<Size> sizes;
378 params.getSupportedVideoSizes(sizes);
379 if (sizes.size() == 0) {
380 // video size is the same as preview size
381 params.getPreviewSize(&frameWidthActual, &frameHeightActual);
382 } else {
383 // video size may not be the same as preview
384 params.getVideoSize(&frameWidthActual, &frameHeightActual);
385 }
James Dong54ff19a2010-10-08 11:59:32 -0700386 if (frameWidthActual < 0 || frameHeightActual < 0) {
387 LOGE("Failed to retrieve video frame size (%dx%d)",
388 frameWidthActual, frameHeightActual);
389 return UNKNOWN_ERROR;
390 }
391
392 // Check the actual video frame size against the target/requested
393 // video frame size.
394 if (width != -1 && height != -1) {
395 if (frameWidthActual != width || frameHeightActual != height) {
396 LOGE("Failed to set video frame size to %dx%d. "
397 "The actual video size is %dx%d ", width, height,
398 frameWidthActual, frameHeightActual);
399 return UNKNOWN_ERROR;
400 }
401 }
402
403 // Good now.
404 mVideoSize.width = frameWidthActual;
405 mVideoSize.height = frameHeightActual;
406 return OK;
407}
408
409/*
410 * Check the requested frame rate has been successfully configured or not.
411 * If the target frameRate is -1, check on the current frame rate value
412 * setting is performed.
413 *
414 * @param params CameraParameters to retrieve the information
415 * @param the target video frame rate to check against
416 * @return OK if no error.
417 */
418status_t CameraSource::checkFrameRate(
419 const CameraParameters& params,
420 int32_t frameRate) {
421
422 int32_t frameRateActual = params.getPreviewFrameRate();
423 if (frameRateActual < 0) {
424 LOGE("Failed to retrieve preview frame rate (%d)", frameRateActual);
425 return UNKNOWN_ERROR;
426 }
427
428 // Check the actual video frame rate against the target/requested
429 // video frame rate.
430 if (frameRate != -1 && (frameRateActual - frameRate) != 0) {
431 LOGE("Failed to set preview frame rate to %d fps. The actual "
432 "frame rate is %d", frameRate, frameRateActual);
433 return UNKNOWN_ERROR;
434 }
435
436 // Good now.
437 mVideoFrameRate = frameRateActual;
438 return OK;
439}
440
441/*
442 * Initialize the CameraSource to so that it becomes
443 * ready for providing the video input streams as requested.
444 * @param camera the camera object used for the video source
445 * @param cameraId if camera == 0, use camera with this id
446 * as the video source
447 * @param videoSize the target video frame size. If both
448 * width and height in videoSize is -1, use the current
449 * width and heigth settings by the camera
450 * @param frameRate the target frame rate in frames per second.
451 * if it is -1, use the current camera frame rate setting.
James Dong5c952312010-10-18 21:42:27 -0700452 * @param storeMetaDataInVideoBuffers request to store meta
453 * data or real YUV data in video buffers. Request to
454 * store meta data in video buffers may not be honored
455 * if the source does not support this feature.
456 *
James Dong54ff19a2010-10-08 11:59:32 -0700457 * @return OK if no error.
458 */
459status_t CameraSource::init(
460 const sp<ICamera>& camera,
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800461 const sp<ICameraRecordingProxy>& proxy,
James Dong54ff19a2010-10-08 11:59:32 -0700462 int32_t cameraId,
463 Size videoSize,
James Dong5c952312010-10-18 21:42:27 -0700464 int32_t frameRate,
465 bool storeMetaDataInVideoBuffers) {
James Dong54ff19a2010-10-08 11:59:32 -0700466
467 status_t err = OK;
James Dongae4c1ac2011-07-08 17:59:29 -0700468 int64_t token = IPCThreadState::self()->clearCallingIdentity();
469 err = initWithCameraAccess(camera, proxy, cameraId,
470 videoSize, frameRate,
471 storeMetaDataInVideoBuffers);
472 IPCThreadState::self()->restoreCallingIdentity(token);
473 return err;
474}
475
476status_t CameraSource::initWithCameraAccess(
477 const sp<ICamera>& camera,
478 const sp<ICameraRecordingProxy>& proxy,
479 int32_t cameraId,
480 Size videoSize,
481 int32_t frameRate,
482 bool storeMetaDataInVideoBuffers) {
483 status_t err = OK;
James Dong54ff19a2010-10-08 11:59:32 -0700484
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800485 if ((err = isCameraAvailable(camera, proxy, cameraId)) != OK) {
486 LOGE("Camera connection could not be established.");
James Dong54ff19a2010-10-08 11:59:32 -0700487 return err;
488 }
489 CameraParameters params(mCamera->getParameters());
490 if ((err = isCameraColorFormatSupported(params)) != OK) {
491 return err;
492 }
493
494 // Set the camera to use the requested video frame size
495 // and/or frame rate.
496 if ((err = configureCamera(&params,
497 videoSize.width, videoSize.height,
498 frameRate))) {
499 return err;
500 }
501
502 // Check on video frame size and frame rate.
503 CameraParameters newCameraParams(mCamera->getParameters());
504 if ((err = checkVideoSize(newCameraParams,
505 videoSize.width, videoSize.height)) != OK) {
506 return err;
507 }
508 if ((err = checkFrameRate(newCameraParams, frameRate)) != OK) {
509 return err;
510 }
511
512 // This CHECK is good, since we just passed the lock/unlock
513 // check earlier by calling mCamera->setParameters().
514 CHECK_EQ(OK, mCamera->setPreviewDisplay(mSurface));
James Dong2b37ced2010-10-09 01:16:58 -0700515
James Dongabdd2ba2010-12-10 13:09:05 -0800516 // By default, do not store metadata in video buffers
James Dong5c952312010-10-18 21:42:27 -0700517 mIsMetaDataStoredInVideoBuffers = false;
James Dongabdd2ba2010-12-10 13:09:05 -0800518 mCamera->storeMetaDataInBuffers(false);
519 if (storeMetaDataInVideoBuffers) {
520 if (OK == mCamera->storeMetaDataInBuffers(true)) {
521 mIsMetaDataStoredInVideoBuffers = true;
522 }
James Dong5c952312010-10-18 21:42:27 -0700523 }
524
James Dong54ff19a2010-10-08 11:59:32 -0700525 int64_t glitchDurationUs = (1000000LL / mVideoFrameRate);
James Dongf60cafe2010-06-19 09:04:18 -0700526 if (glitchDurationUs > mGlitchDurationThresholdUs) {
527 mGlitchDurationThresholdUs = glitchDurationUs;
528 }
529
James Dongddcc4a62010-06-08 11:58:53 -0700530 // XXX: query camera for the stride and slice height
531 // when the capability becomes available.
James Dong653252b2010-06-03 11:48:31 -0700532 mMeta = new MetaData;
James Dong54ff19a2010-10-08 11:59:32 -0700533 mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
534 mMeta->setInt32(kKeyColorFormat, mColorFormat);
535 mMeta->setInt32(kKeyWidth, mVideoSize.width);
536 mMeta->setInt32(kKeyHeight, mVideoSize.height);
537 mMeta->setInt32(kKeyStride, mVideoSize.width);
538 mMeta->setInt32(kKeySliceHeight, mVideoSize.height);
James Dong393410a2010-11-10 20:43:53 -0800539 mMeta->setInt32(kKeyFrameRate, mVideoFrameRate);
James Dong54ff19a2010-10-08 11:59:32 -0700540 return OK;
Andreas Huber20111aa2009-07-14 16:56:47 -0700541}
542
543CameraSource::~CameraSource() {
544 if (mStarted) {
545 stop();
James Dongae4c1ac2011-07-08 17:59:29 -0700546 } else if (mInitCheck == OK) {
547 // Camera is initialized but because start() is never called,
548 // the lock on Camera is never released(). This makes sure
549 // Camera's lock is released in this case.
550 releaseCamera();
Andreas Huber20111aa2009-07-14 16:56:47 -0700551 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700552}
553
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700554void CameraSource::startCameraRecording() {
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800555 // Reset the identity to the current thread because media server owns the
556 // camera and recording is started by the applications. The applications
557 // will connect to the camera in ICameraRecordingProxy::startRecording.
558 int64_t token = IPCThreadState::self()->clearCallingIdentity();
559 mCamera->unlock();
560 mCamera.clear();
561 IPCThreadState::self()->restoreCallingIdentity(token);
562 CHECK_EQ(OK, mCameraRecordingProxy->startRecording(new ProxyListener(this)));
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700563}
564
James Dongf60cafe2010-06-19 09:04:18 -0700565status_t CameraSource::start(MetaData *meta) {
Andreas Huber0c891992009-08-26 14:48:20 -0700566 CHECK(!mStarted);
James Dong54ff19a2010-10-08 11:59:32 -0700567 if (mInitCheck != OK) {
568 LOGE("CameraSource is not initialized yet");
569 return mInitCheck;
570 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700571
James Dong365a9632010-06-04 13:59:27 -0700572 char value[PROPERTY_VALUE_MAX];
573 if (property_get("media.stagefright.record-stats", value, NULL)
574 && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
575 mCollectStats = true;
576 }
James Dong9d7f58a2010-06-09 15:57:48 -0700577
James Dongf60cafe2010-06-19 09:04:18 -0700578 mStartTimeUs = 0;
579 int64_t startTimeUs;
580 if (meta && meta->findInt64(kKeyTime, &startTimeUs)) {
581 mStartTimeUs = startTimeUs;
582 }
583
James Dongc42478e2010-11-15 10:38:37 -0800584 startCameraRecording();
Andreas Huber20111aa2009-07-14 16:56:47 -0700585
586 mStarted = true;
Andreas Huber20111aa2009-07-14 16:56:47 -0700587 return OK;
588}
589
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700590void CameraSource::stopCameraRecording() {
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800591 mCameraRecordingProxy->stopRecording();
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700592}
593
James Dongea7b4852010-12-05 14:25:34 -0800594void CameraSource::releaseCamera() {
595 LOGV("releaseCamera");
Wu-cheng Li95068be2011-06-29 15:17:11 +0800596 if (mCamera != 0) {
James Dongae4c1ac2011-07-08 17:59:29 -0700597 int64_t token = IPCThreadState::self()->clearCallingIdentity();
Wu-cheng Li95068be2011-06-29 15:17:11 +0800598 if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) {
599 LOGV("Camera was cold when we started, stopping preview");
600 mCamera->stopPreview();
601 mCamera->disconnect();
602 } else {
603 // Unlock the camera so the application can lock it back.
604 mCamera->unlock();
605 }
606 mCamera.clear();
James Dongae4c1ac2011-07-08 17:59:29 -0700607 IPCThreadState::self()->restoreCallingIdentity(token);
James Dongea7b4852010-12-05 14:25:34 -0800608 }
Wu-cheng Li95068be2011-06-29 15:17:11 +0800609 if (mCameraRecordingProxy != 0) {
610 mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
611 mCameraRecordingProxy.clear();
612 }
James Dongea7b4852010-12-05 14:25:34 -0800613 mCameraFlags = 0;
614}
615
Andreas Huber20111aa2009-07-14 16:56:47 -0700616status_t CameraSource::stop() {
James Dong41152ef2010-12-20 21:29:12 -0800617 LOGD("stop: E");
James Dongc32cd792010-04-26 17:48:26 -0700618 Mutex::Autolock autoLock(mLock);
Andreas Huber20111aa2009-07-14 16:56:47 -0700619 mStarted = false;
James Dongc32cd792010-04-26 17:48:26 -0700620 mFrameAvailableCondition.signal();
James Dong365a9632010-06-04 13:59:27 -0700621
James Dongc32cd792010-04-26 17:48:26 -0700622 releaseQueuedFrames();
James Dong7278cf32010-05-27 16:05:58 -0700623 while (!mFramesBeingEncoded.empty()) {
James Dong41152ef2010-12-20 21:29:12 -0800624 if (NO_ERROR !=
625 mFrameCompleteCondition.waitRelative(mLock, 3000000000LL)) {
626 LOGW("Timed out waiting for outstanding frames being encoded: %d",
James Dong365a9632010-06-04 13:59:27 -0700627 mFramesBeingEncoded.size());
James Dong41152ef2010-12-20 21:29:12 -0800628 }
James Dong7278cf32010-05-27 16:05:58 -0700629 }
James Dongd69c7f62010-12-09 11:24:22 -0800630 stopCameraRecording();
James Dongea7b4852010-12-05 14:25:34 -0800631 releaseCamera();
James Dong7278cf32010-05-27 16:05:58 -0700632
James Dong365a9632010-06-04 13:59:27 -0700633 if (mCollectStats) {
634 LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
635 mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
636 mLastFrameTimestampUs - mFirstFrameTimeUs);
637 }
James Dong13aec892010-04-21 16:14:15 -0700638
James Dongba290022010-12-09 15:04:33 -0800639 if (mNumGlitches > 0) {
James Donga4726132011-02-16 12:28:26 -0800640 LOGW("%d long delays between neighboring video frames", mNumGlitches);
James Dongba290022010-12-09 15:04:33 -0800641 }
642
James Dong13aec892010-04-21 16:14:15 -0700643 CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
James Dong41152ef2010-12-20 21:29:12 -0800644 LOGD("stop: X");
Andreas Huber20111aa2009-07-14 16:56:47 -0700645 return OK;
646}
647
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700648void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800649 if (mCameraRecordingProxy != NULL) {
650 mCameraRecordingProxy->releaseRecordingFrame(frame);
James Dongd69c7f62010-12-09 11:24:22 -0800651 }
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700652}
653
James Dongc32cd792010-04-26 17:48:26 -0700654void CameraSource::releaseQueuedFrames() {
655 List<sp<IMemory> >::iterator it;
James Dong7278cf32010-05-27 16:05:58 -0700656 while (!mFramesReceived.empty()) {
657 it = mFramesReceived.begin();
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700658 releaseRecordingFrame(*it);
James Dong7278cf32010-05-27 16:05:58 -0700659 mFramesReceived.erase(it);
James Dong13aec892010-04-21 16:14:15 -0700660 ++mNumFramesDropped;
James Dongc32cd792010-04-26 17:48:26 -0700661 }
662}
663
Andreas Huber20111aa2009-07-14 16:56:47 -0700664sp<MetaData> CameraSource::getFormat() {
James Dong653252b2010-06-03 11:48:31 -0700665 return mMeta;
Andreas Huber20111aa2009-07-14 16:56:47 -0700666}
667
James Dongf60cafe2010-06-19 09:04:18 -0700668void CameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) {
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700669 releaseRecordingFrame(frame);
James Dongf60cafe2010-06-19 09:04:18 -0700670}
671
James Dong7278cf32010-05-27 16:05:58 -0700672void CameraSource::signalBufferReturned(MediaBuffer *buffer) {
673 LOGV("signalBufferReturned: %p", buffer->data());
Andreas Huber56223b92010-08-11 12:34:32 -0700674 Mutex::Autolock autoLock(mLock);
James Dong7278cf32010-05-27 16:05:58 -0700675 for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
676 it != mFramesBeingEncoded.end(); ++it) {
677 if ((*it)->pointer() == buffer->data()) {
James Dongf60cafe2010-06-19 09:04:18 -0700678 releaseOneRecordingFrame((*it));
James Dong7278cf32010-05-27 16:05:58 -0700679 mFramesBeingEncoded.erase(it);
680 ++mNumFramesEncoded;
681 buffer->setObserver(0);
682 buffer->release();
683 mFrameCompleteCondition.signal();
684 return;
685 }
686 }
687 CHECK_EQ(0, "signalBufferReturned: bogus buffer");
688}
689
Andreas Huber20111aa2009-07-14 16:56:47 -0700690status_t CameraSource::read(
691 MediaBuffer **buffer, const ReadOptions *options) {
James Dongc32cd792010-04-26 17:48:26 -0700692 LOGV("read");
Andreas Huber20111aa2009-07-14 16:56:47 -0700693
694 *buffer = NULL;
695
696 int64_t seekTimeUs;
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700697 ReadOptions::SeekMode mode;
698 if (options && options->getSeekTo(&seekTimeUs, &mode)) {
Andreas Huber20111aa2009-07-14 16:56:47 -0700699 return ERROR_UNSUPPORTED;
700 }
701
702 sp<IMemory> frame;
Andreas Huberbe5c74f2009-10-13 17:08:31 -0700703 int64_t frameTime;
Andreas Huber20111aa2009-07-14 16:56:47 -0700704
705 {
706 Mutex::Autolock autoLock(mLock);
James Dong79e23b42010-12-11 10:43:41 -0800707 while (mStarted && mFramesReceived.empty()) {
James Dong41152ef2010-12-20 21:29:12 -0800708 if (NO_ERROR !=
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800709 mFrameAvailableCondition.waitRelative(mLock, 1000000000LL)) {
710 if (!mCameraRecordingProxy->asBinder()->isBinderAlive()) {
711 LOGW("camera recording proxy is gone");
712 return ERROR_END_OF_STREAM;
713 }
James Dong41152ef2010-12-20 21:29:12 -0800714 LOGW("Timed out waiting for incoming camera video frames: %lld us",
715 mLastFrameTimestampUs);
716 }
James Dong542db5d2010-07-21 14:51:35 -0700717 }
James Dong79e23b42010-12-11 10:43:41 -0800718 if (!mStarted) {
719 return OK;
720 }
721 frame = *mFramesReceived.begin();
722 mFramesReceived.erase(mFramesReceived.begin());
723
724 frameTime = *mFrameTimes.begin();
725 mFrameTimes.erase(mFrameTimes.begin());
726 mFramesBeingEncoded.push_back(frame);
727 *buffer = new MediaBuffer(frame->pointer(), frame->size());
728 (*buffer)->setObserver(this);
729 (*buffer)->add_ref();
730 (*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
Andreas Huber20111aa2009-07-14 16:56:47 -0700731 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700732 return OK;
733}
734
James Dongc32cd792010-04-26 17:48:26 -0700735void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
736 int32_t msgType, const sp<IMemory> &data) {
737 LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
Andreas Huber20111aa2009-07-14 16:56:47 -0700738 Mutex::Autolock autoLock(mLock);
James Donga4726132011-02-16 12:28:26 -0800739 if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
740 LOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs);
James Dongf60cafe2010-06-19 09:04:18 -0700741 releaseOneRecordingFrame(data);
James Dongc32cd792010-04-26 17:48:26 -0700742 return;
743 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700744
James Dong98cfde02011-06-03 17:21:16 -0700745 if (mNumFramesReceived > 0) {
746 CHECK(timestampUs > mLastFrameTimestampUs);
747 if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) {
748 ++mNumGlitches;
James Dongf60cafe2010-06-19 09:04:18 -0700749 }
James Dongf60cafe2010-06-19 09:04:18 -0700750 }
751
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700752 // May need to skip frame or modify timestamp. Currently implemented
753 // by the subclass CameraSourceTimeLapse.
James Dong79e23b42010-12-11 10:43:41 -0800754 if (skipCurrentFrame(timestampUs)) {
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700755 releaseOneRecordingFrame(data);
756 return;
Nipun Kwatrafc20aab2010-06-30 18:51:31 -0700757 }
758
James Dong365a9632010-06-04 13:59:27 -0700759 mLastFrameTimestampUs = timestampUs;
James Dong13aec892010-04-21 16:14:15 -0700760 if (mNumFramesReceived == 0) {
James Dongc32cd792010-04-26 17:48:26 -0700761 mFirstFrameTimeUs = timestampUs;
James Dongf60cafe2010-06-19 09:04:18 -0700762 // Initial delay
763 if (mStartTimeUs > 0) {
764 if (timestampUs < mStartTimeUs) {
765 // Frame was captured before recording was started
766 // Drop it without updating the statistical data.
767 releaseOneRecordingFrame(data);
768 return;
769 }
770 mStartTimeUs = timestampUs - mStartTimeUs;
771 }
Andreas Huberbe5c74f2009-10-13 17:08:31 -0700772 }
James Dong13aec892010-04-21 16:14:15 -0700773 ++mNumFramesReceived;
Andreas Huberbe5c74f2009-10-13 17:08:31 -0700774
James Dong98cfde02011-06-03 17:21:16 -0700775 CHECK(data != NULL && data->size() > 0);
James Dong7278cf32010-05-27 16:05:58 -0700776 mFramesReceived.push_back(data);
James Dongf60cafe2010-06-19 09:04:18 -0700777 int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
778 mFrameTimes.push_back(timeUs);
779 LOGV("initial delay: %lld, current time stamp: %lld",
780 mStartTimeUs, timeUs);
Andreas Huber20111aa2009-07-14 16:56:47 -0700781 mFrameAvailableCondition.signal();
782}
783
James Dong5c952312010-10-18 21:42:27 -0700784bool CameraSource::isMetaDataStoredInVideoBuffers() const {
785 LOGV("isMetaDataStoredInVideoBuffers");
786 return mIsMetaDataStoredInVideoBuffers;
787}
788
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800789CameraSource::ProxyListener::ProxyListener(const sp<CameraSource>& source) {
790 mSource = source;
791}
792
793void CameraSource::ProxyListener::dataCallbackTimestamp(
794 nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
795 mSource->dataCallbackTimestamp(timestamp / 1000, msgType, dataPtr);
796}
797
798void CameraSource::DeathNotifier::binderDied(const wp<IBinder>& who) {
799 LOGI("Camera recording proxy died");
800}
801
Andreas Huber20111aa2009-07-14 16:56:47 -0700802} // namespace android