blob: a604c8f8342593736545e3a9a9440d5fc0d80f29 [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>
James Dongf1d5aa12012-02-06 23:46:37 -080023#include <media/stagefright/foundation/ADebug.h>
Andreas Huber20111aa2009-07-14 16:56:47 -070024#include <media/stagefright/CameraSource.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>
Mathias Agopiandf712ea2012-02-25 18:48:35 -080030#include <gui/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
James Donge8e5f862011-11-20 09:45:44 -080036static const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL;
37
Andreas Huberbe5c74f2009-10-13 17:08:31 -070038struct CameraSourceListener : public CameraListener {
39 CameraSourceListener(const sp<CameraSource> &source);
40
41 virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
Wu-cheng Li57c86182011-07-30 05:00:37 +080042 virtual void postData(int32_t msgType, const sp<IMemory> &dataPtr,
43 camera_frame_metadata_t *metadata);
Andreas Huberbe5c74f2009-10-13 17:08:31 -070044
45 virtual void postDataTimestamp(
46 nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
47
48protected:
49 virtual ~CameraSourceListener();
50
51private:
52 wp<CameraSource> mSource;
53
54 CameraSourceListener(const CameraSourceListener &);
55 CameraSourceListener &operator=(const CameraSourceListener &);
56};
57
58CameraSourceListener::CameraSourceListener(const sp<CameraSource> &source)
59 : mSource(source) {
60}
61
62CameraSourceListener::~CameraSourceListener() {
63}
64
65void CameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
Steve Block3856b092011-10-20 11:56:00 +010066 ALOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
Andreas Huberbe5c74f2009-10-13 17:08:31 -070067}
68
Wu-cheng Li57c86182011-07-30 05:00:37 +080069void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr,
70 camera_frame_metadata_t *metadata) {
Steve Block3856b092011-10-20 11:56:00 +010071 ALOGV("postData(%d, ptr:%p, size:%d)",
Andreas Huberbe5c74f2009-10-13 17:08:31 -070072 msgType, dataPtr->pointer(), dataPtr->size());
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -070073
74 sp<CameraSource> source = mSource.promote();
75 if (source.get() != NULL) {
76 source->dataCallback(msgType, dataPtr);
77 }
Andreas Huberbe5c74f2009-10-13 17:08:31 -070078}
79
80void CameraSourceListener::postDataTimestamp(
81 nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
James Dongc32cd792010-04-26 17:48:26 -070082
83 sp<CameraSource> source = mSource.promote();
84 if (source.get() != NULL) {
85 source->dataCallbackTimestamp(timestamp/1000, msgType, dataPtr);
86 }
Andreas Huberbe5c74f2009-10-13 17:08:31 -070087}
88
James Dong653252b2010-06-03 11:48:31 -070089static int32_t getColorFormat(const char* colorFormat) {
James Donge2d8ba82010-09-15 16:52:51 -070090 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) {
91 return OMX_COLOR_FormatYUV420Planar;
92 }
93
James Dong653252b2010-06-03 11:48:31 -070094 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422SP)) {
95 return OMX_COLOR_FormatYUV422SemiPlanar;
96 }
97
98 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) {
99 return OMX_COLOR_FormatYUV420SemiPlanar;
100 }
101
102 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422I)) {
103 return OMX_COLOR_FormatYCbYCr;
104 }
105
106 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_RGB565)) {
107 return OMX_COLOR_Format16bitRGB565;
108 }
109
Dandawate Saket1374edd2011-07-11 19:12:57 -0700110 if (!strcmp(colorFormat, "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar")) {
111 return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar;
112 }
113
Eino-Ville Talvalabf5bea92012-07-18 17:46:06 -0700114 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE)) {
115 return OMX_COLOR_FormatAndroidOpaque;
116 }
117
Steve Block29357bc2012-01-06 19:20:56 +0000118 ALOGE("Uknown color format (%s), please add it to "
James Donga1abc1a2010-09-13 16:30:51 -0700119 "CameraSource::getColorFormat", colorFormat);
120
James Dongf1d5aa12012-02-06 23:46:37 -0800121 CHECK(!"Unknown color format");
James Dong653252b2010-06-03 11:48:31 -0700122}
123
Andreas Huber20111aa2009-07-14 16:56:47 -0700124CameraSource *CameraSource::Create() {
James Dong54ff19a2010-10-08 11:59:32 -0700125 Size size;
126 size.width = -1;
127 size.height = -1;
Andreas Huber20111aa2009-07-14 16:56:47 -0700128
James Dong54ff19a2010-10-08 11:59:32 -0700129 sp<ICamera> camera;
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800130 return new CameraSource(camera, NULL, 0, size, -1, NULL, false);
Andreas Huber20111aa2009-07-14 16:56:47 -0700131}
132
Andreas Huber30ab6622009-11-16 15:43:38 -0800133// static
James Dong54ff19a2010-10-08 11:59:32 -0700134CameraSource *CameraSource::CreateFromCamera(
135 const sp<ICamera>& camera,
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800136 const sp<ICameraRecordingProxy>& proxy,
James Dong54ff19a2010-10-08 11:59:32 -0700137 int32_t cameraId,
138 Size videoSize,
139 int32_t frameRate,
James Dong5c952312010-10-18 21:42:27 -0700140 const sp<Surface>& surface,
141 bool storeMetaDataInVideoBuffers) {
Andreas Huber30ab6622009-11-16 15:43:38 -0800142
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800143 CameraSource *source = new CameraSource(camera, proxy, cameraId,
James Dong5c952312010-10-18 21:42:27 -0700144 videoSize, frameRate, surface,
145 storeMetaDataInVideoBuffers);
James Dong54ff19a2010-10-08 11:59:32 -0700146 return source;
Andreas Huber30ab6622009-11-16 15:43:38 -0800147}
148
James Dong54ff19a2010-10-08 11:59:32 -0700149CameraSource::CameraSource(
150 const sp<ICamera>& camera,
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800151 const sp<ICameraRecordingProxy>& proxy,
James Dong54ff19a2010-10-08 11:59:32 -0700152 int32_t cameraId,
153 Size videoSize,
154 int32_t frameRate,
James Dong5c952312010-10-18 21:42:27 -0700155 const sp<Surface>& surface,
156 bool storeMetaDataInVideoBuffers)
James Dong54ff19a2010-10-08 11:59:32 -0700157 : mCameraFlags(0),
158 mVideoFrameRate(-1),
159 mCamera(0),
160 mSurface(surface),
James Dong13aec892010-04-21 16:14:15 -0700161 mNumFramesReceived(0),
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700162 mLastFrameTimestampUs(0),
163 mStarted(false),
James Dong13aec892010-04-21 16:14:15 -0700164 mNumFramesEncoded(0),
James Donge8e5f862011-11-20 09:45:44 -0800165 mTimeBetweenFrameCaptureUs(0),
James Dong7757f502011-01-25 16:31:28 -0800166 mFirstFrameTimeUs(0),
James Dong13aec892010-04-21 16:14:15 -0700167 mNumFramesDropped(0),
James Dongf60cafe2010-06-19 09:04:18 -0700168 mNumGlitches(0),
169 mGlitchDurationThresholdUs(200000),
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700170 mCollectStats(false) {
James Dong54ff19a2010-10-08 11:59:32 -0700171 mVideoSize.width = -1;
172 mVideoSize.height = -1;
173
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800174 mInitCheck = init(camera, proxy, cameraId,
James Dong5c952312010-10-18 21:42:27 -0700175 videoSize, frameRate,
176 storeMetaDataInVideoBuffers);
Wu-cheng Li95068be2011-06-29 15:17:11 +0800177 if (mInitCheck != OK) releaseCamera();
James Dong54ff19a2010-10-08 11:59:32 -0700178}
179
180status_t CameraSource::initCheck() const {
181 return mInitCheck;
182}
183
184status_t CameraSource::isCameraAvailable(
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800185 const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
186 int32_t cameraId) {
James Dong54ff19a2010-10-08 11:59:32 -0700187
188 if (camera == 0) {
Wu-cheng Li08ad5ef2012-04-19 12:35:00 +0800189 mCamera = Camera::connect(cameraId);
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800190 if (mCamera == 0) return -EBUSY;
James Dong54ff19a2010-10-08 11:59:32 -0700191 mCameraFlags &= ~FLAGS_HOT_CAMERA;
192 } else {
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800193 // We get the proxy from Camera, not ICamera. We need to get the proxy
194 // to the remote Camera owned by the application. Here mCamera is a
195 // local Camera object created by us. We cannot use the proxy from
196 // mCamera here.
James Dong54ff19a2010-10-08 11:59:32 -0700197 mCamera = Camera::create(camera);
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800198 if (mCamera == 0) return -EBUSY;
199 mCameraRecordingProxy = proxy;
James Dong54ff19a2010-10-08 11:59:32 -0700200 mCameraFlags |= FLAGS_HOT_CAMERA;
James Dong3bd30202011-07-19 20:24:22 -0700201 mDeathNotifier = new DeathNotifier();
202 // isBinderAlive needs linkToDeath to work.
203 mCameraRecordingProxy->asBinder()->linkToDeath(mDeathNotifier);
James Dong54ff19a2010-10-08 11:59:32 -0700204 }
205
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800206 mCamera->lock();
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800207
James Dong54ff19a2010-10-08 11:59:32 -0700208 return OK;
209}
210
211
212/*
213 * Check to see whether the requested video width and height is one
214 * of the supported sizes.
215 * @param width the video frame width in pixels
216 * @param height the video frame height in pixels
217 * @param suppportedSizes the vector of sizes that we check against
218 * @return true if the dimension (width and height) is supported.
219 */
220static bool isVideoSizeSupported(
221 int32_t width, int32_t height,
222 const Vector<Size>& supportedSizes) {
223
Steve Block3856b092011-10-20 11:56:00 +0100224 ALOGV("isVideoSizeSupported");
James Dong54ff19a2010-10-08 11:59:32 -0700225 for (size_t i = 0; i < supportedSizes.size(); ++i) {
226 if (width == supportedSizes[i].width &&
227 height == supportedSizes[i].height) {
228 return true;
229 }
230 }
231 return false;
232}
233
234/*
235 * If the preview and video output is separate, we only set the
236 * the video size, and applications should set the preview size
237 * to some proper value, and the recording framework will not
238 * change the preview size; otherwise, if the video and preview
239 * output is the same, we need to set the preview to be the same
240 * as the requested video size.
241 *
242 */
243/*
244 * Query the camera to retrieve the supported video frame sizes
245 * and also to see whether CameraParameters::setVideoSize()
246 * is supported or not.
247 * @param params CameraParameters to retrieve the information
248 * @@param isSetVideoSizeSupported retunrs whether method
249 * CameraParameters::setVideoSize() is supported or not.
250 * @param sizes returns the vector of Size objects for the
251 * supported video frame sizes advertised by the camera.
252 */
253static void getSupportedVideoSizes(
254 const CameraParameters& params,
255 bool *isSetVideoSizeSupported,
256 Vector<Size>& sizes) {
257
258 *isSetVideoSizeSupported = true;
259 params.getSupportedVideoSizes(sizes);
260 if (sizes.size() == 0) {
Steve Blockb8a80522011-12-20 16:23:08 +0000261 ALOGD("Camera does not support setVideoSize()");
James Dong54ff19a2010-10-08 11:59:32 -0700262 params.getSupportedPreviewSizes(sizes);
263 *isSetVideoSizeSupported = false;
264 }
265}
266
267/*
268 * Check whether the camera has the supported color format
269 * @param params CameraParameters to retrieve the information
270 * @return OK if no error.
271 */
272status_t CameraSource::isCameraColorFormatSupported(
273 const CameraParameters& params) {
274 mColorFormat = getColorFormat(params.get(
275 CameraParameters::KEY_VIDEO_FRAME_FORMAT));
276 if (mColorFormat == -1) {
277 return BAD_VALUE;
278 }
279 return OK;
280}
281
282/*
283 * Configure the camera to use the requested video size
284 * (width and height) and/or frame rate. If both width and
285 * height are -1, configuration on the video size is skipped.
286 * if frameRate is -1, configuration on the frame rate
287 * is skipped. Skipping the configuration allows one to
288 * use the current camera setting without the need to
289 * actually know the specific values (see Create() method).
290 *
291 * @param params the CameraParameters to be configured
292 * @param width the target video frame width in pixels
293 * @param height the target video frame height in pixels
294 * @param frameRate the target frame rate in frames per second.
295 * @return OK if no error.
296 */
297status_t CameraSource::configureCamera(
298 CameraParameters* params,
299 int32_t width, int32_t height,
300 int32_t frameRate) {
Steve Block3856b092011-10-20 11:56:00 +0100301 ALOGV("configureCamera");
James Dong54ff19a2010-10-08 11:59:32 -0700302 Vector<Size> sizes;
303 bool isSetVideoSizeSupportedByCamera = true;
304 getSupportedVideoSizes(*params, &isSetVideoSizeSupportedByCamera, sizes);
305 bool isCameraParamChanged = false;
306 if (width != -1 && height != -1) {
307 if (!isVideoSizeSupported(width, height, sizes)) {
Steve Block29357bc2012-01-06 19:20:56 +0000308 ALOGE("Video dimension (%dx%d) is unsupported", width, height);
James Dong54ff19a2010-10-08 11:59:32 -0700309 return BAD_VALUE;
310 }
311 if (isSetVideoSizeSupportedByCamera) {
312 params->setVideoSize(width, height);
313 } else {
314 params->setPreviewSize(width, height);
315 }
316 isCameraParamChanged = true;
317 } else if ((width == -1 && height != -1) ||
318 (width != -1 && height == -1)) {
319 // If one and only one of the width and height is -1
320 // we reject such a request.
Steve Block29357bc2012-01-06 19:20:56 +0000321 ALOGE("Requested video size (%dx%d) is not supported", width, height);
James Dong54ff19a2010-10-08 11:59:32 -0700322 return BAD_VALUE;
323 } else { // width == -1 && height == -1
324 // Do not configure the camera.
325 // Use the current width and height value setting from the camera.
326 }
327
328 if (frameRate != -1) {
James Dong63573082010-10-24 09:32:39 -0700329 CHECK(frameRate > 0 && frameRate <= 120);
330 const char* supportedFrameRates =
331 params->get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES);
332 CHECK(supportedFrameRates != NULL);
Steve Block3856b092011-10-20 11:56:00 +0100333 ALOGV("Supported frame rates: %s", supportedFrameRates);
James Dong63573082010-10-24 09:32:39 -0700334 char buf[4];
335 snprintf(buf, 4, "%d", frameRate);
336 if (strstr(supportedFrameRates, buf) == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +0000337 ALOGE("Requested frame rate (%d) is not supported: %s",
James Dong63573082010-10-24 09:32:39 -0700338 frameRate, supportedFrameRates);
339 return BAD_VALUE;
340 }
341
342 // The frame rate is supported, set the camera to the requested value.
James Dong54ff19a2010-10-08 11:59:32 -0700343 params->setPreviewFrameRate(frameRate);
344 isCameraParamChanged = true;
345 } else { // frameRate == -1
346 // Do not configure the camera.
347 // Use the current frame rate value setting from the camera
348 }
349
350 if (isCameraParamChanged) {
351 // Either frame rate or frame size needs to be changed.
352 String8 s = params->flatten();
353 if (OK != mCamera->setParameters(s)) {
Steve Block29357bc2012-01-06 19:20:56 +0000354 ALOGE("Could not change settings."
James Dong54ff19a2010-10-08 11:59:32 -0700355 " Someone else is using camera %p?", mCamera.get());
356 return -EBUSY;
357 }
358 }
359 return OK;
360}
361
362/*
363 * Check whether the requested video frame size
364 * has been successfully configured or not. If both width and height
365 * are -1, check on the current width and height value setting
366 * is performed.
367 *
368 * @param params CameraParameters to retrieve the information
369 * @param the target video frame width in pixels to check against
370 * @param the target video frame height in pixels to check against
371 * @return OK if no error
372 */
373status_t CameraSource::checkVideoSize(
374 const CameraParameters& params,
375 int32_t width, int32_t height) {
376
Steve Block3856b092011-10-20 11:56:00 +0100377 ALOGV("checkVideoSize");
James Dongf96c9d12010-10-20 11:41:33 -0700378 // The actual video size is the same as the preview size
379 // if the camera hal does not support separate video and
380 // preview output. In this case, we retrieve the video
381 // size from preview.
James Dong54ff19a2010-10-08 11:59:32 -0700382 int32_t frameWidthActual = -1;
383 int32_t frameHeightActual = -1;
James Dongf96c9d12010-10-20 11:41:33 -0700384 Vector<Size> sizes;
385 params.getSupportedVideoSizes(sizes);
386 if (sizes.size() == 0) {
387 // video size is the same as preview size
388 params.getPreviewSize(&frameWidthActual, &frameHeightActual);
389 } else {
390 // video size may not be the same as preview
391 params.getVideoSize(&frameWidthActual, &frameHeightActual);
392 }
James Dong54ff19a2010-10-08 11:59:32 -0700393 if (frameWidthActual < 0 || frameHeightActual < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000394 ALOGE("Failed to retrieve video frame size (%dx%d)",
James Dong54ff19a2010-10-08 11:59:32 -0700395 frameWidthActual, frameHeightActual);
396 return UNKNOWN_ERROR;
397 }
398
399 // Check the actual video frame size against the target/requested
400 // video frame size.
401 if (width != -1 && height != -1) {
402 if (frameWidthActual != width || frameHeightActual != height) {
Steve Block29357bc2012-01-06 19:20:56 +0000403 ALOGE("Failed to set video frame size to %dx%d. "
James Dong54ff19a2010-10-08 11:59:32 -0700404 "The actual video size is %dx%d ", width, height,
405 frameWidthActual, frameHeightActual);
406 return UNKNOWN_ERROR;
407 }
408 }
409
410 // Good now.
411 mVideoSize.width = frameWidthActual;
412 mVideoSize.height = frameHeightActual;
413 return OK;
414}
415
416/*
417 * Check the requested frame rate has been successfully configured or not.
418 * If the target frameRate is -1, check on the current frame rate value
419 * setting is performed.
420 *
421 * @param params CameraParameters to retrieve the information
422 * @param the target video frame rate to check against
423 * @return OK if no error.
424 */
425status_t CameraSource::checkFrameRate(
426 const CameraParameters& params,
427 int32_t frameRate) {
428
Steve Block3856b092011-10-20 11:56:00 +0100429 ALOGV("checkFrameRate");
James Dong54ff19a2010-10-08 11:59:32 -0700430 int32_t frameRateActual = params.getPreviewFrameRate();
431 if (frameRateActual < 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000432 ALOGE("Failed to retrieve preview frame rate (%d)", frameRateActual);
James Dong54ff19a2010-10-08 11:59:32 -0700433 return UNKNOWN_ERROR;
434 }
435
436 // Check the actual video frame rate against the target/requested
437 // video frame rate.
438 if (frameRate != -1 && (frameRateActual - frameRate) != 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000439 ALOGE("Failed to set preview frame rate to %d fps. The actual "
James Dong54ff19a2010-10-08 11:59:32 -0700440 "frame rate is %d", frameRate, frameRateActual);
441 return UNKNOWN_ERROR;
442 }
443
444 // Good now.
445 mVideoFrameRate = frameRateActual;
446 return OK;
447}
448
449/*
450 * Initialize the CameraSource to so that it becomes
451 * ready for providing the video input streams as requested.
452 * @param camera the camera object used for the video source
453 * @param cameraId if camera == 0, use camera with this id
454 * as the video source
455 * @param videoSize the target video frame size. If both
456 * width and height in videoSize is -1, use the current
457 * width and heigth settings by the camera
458 * @param frameRate the target frame rate in frames per second.
459 * if it is -1, use the current camera frame rate setting.
James Dong5c952312010-10-18 21:42:27 -0700460 * @param storeMetaDataInVideoBuffers request to store meta
461 * data or real YUV data in video buffers. Request to
462 * store meta data in video buffers may not be honored
463 * if the source does not support this feature.
464 *
James Dong54ff19a2010-10-08 11:59:32 -0700465 * @return OK if no error.
466 */
467status_t CameraSource::init(
468 const sp<ICamera>& camera,
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800469 const sp<ICameraRecordingProxy>& proxy,
James Dong54ff19a2010-10-08 11:59:32 -0700470 int32_t cameraId,
471 Size videoSize,
James Dong5c952312010-10-18 21:42:27 -0700472 int32_t frameRate,
473 bool storeMetaDataInVideoBuffers) {
James Dong54ff19a2010-10-08 11:59:32 -0700474
Steve Block3856b092011-10-20 11:56:00 +0100475 ALOGV("init");
James Dong54ff19a2010-10-08 11:59:32 -0700476 status_t err = OK;
James Dongae4c1ac2011-07-08 17:59:29 -0700477 int64_t token = IPCThreadState::self()->clearCallingIdentity();
478 err = initWithCameraAccess(camera, proxy, cameraId,
479 videoSize, frameRate,
480 storeMetaDataInVideoBuffers);
481 IPCThreadState::self()->restoreCallingIdentity(token);
482 return err;
483}
484
485status_t CameraSource::initWithCameraAccess(
486 const sp<ICamera>& camera,
487 const sp<ICameraRecordingProxy>& proxy,
488 int32_t cameraId,
489 Size videoSize,
490 int32_t frameRate,
491 bool storeMetaDataInVideoBuffers) {
Steve Block3856b092011-10-20 11:56:00 +0100492 ALOGV("initWithCameraAccess");
James Dongae4c1ac2011-07-08 17:59:29 -0700493 status_t err = OK;
James Dong54ff19a2010-10-08 11:59:32 -0700494
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800495 if ((err = isCameraAvailable(camera, proxy, cameraId)) != OK) {
Steve Block29357bc2012-01-06 19:20:56 +0000496 ALOGE("Camera connection could not be established.");
James Dong54ff19a2010-10-08 11:59:32 -0700497 return err;
498 }
499 CameraParameters params(mCamera->getParameters());
500 if ((err = isCameraColorFormatSupported(params)) != OK) {
501 return err;
502 }
503
504 // Set the camera to use the requested video frame size
505 // and/or frame rate.
506 if ((err = configureCamera(&params,
507 videoSize.width, videoSize.height,
508 frameRate))) {
509 return err;
510 }
511
512 // Check on video frame size and frame rate.
513 CameraParameters newCameraParams(mCamera->getParameters());
514 if ((err = checkVideoSize(newCameraParams,
515 videoSize.width, videoSize.height)) != OK) {
516 return err;
517 }
518 if ((err = checkFrameRate(newCameraParams, frameRate)) != OK) {
519 return err;
520 }
521
Wu-cheng Li8e0792b2012-03-14 17:25:57 +0800522 // Set the preview display. Skip this if mSurface is null because
523 // applications may already set a surface to the camera.
524 if (mSurface != NULL) {
525 // This CHECK is good, since we just passed the lock/unlock
526 // check earlier by calling mCamera->setParameters().
527 CHECK_EQ((status_t)OK, mCamera->setPreviewDisplay(mSurface));
528 }
James Dong2b37ced2010-10-09 01:16:58 -0700529
James Dongabdd2ba2010-12-10 13:09:05 -0800530 // By default, do not store metadata in video buffers
James Dong5c952312010-10-18 21:42:27 -0700531 mIsMetaDataStoredInVideoBuffers = false;
James Dongabdd2ba2010-12-10 13:09:05 -0800532 mCamera->storeMetaDataInBuffers(false);
533 if (storeMetaDataInVideoBuffers) {
534 if (OK == mCamera->storeMetaDataInBuffers(true)) {
535 mIsMetaDataStoredInVideoBuffers = true;
536 }
James Dong5c952312010-10-18 21:42:27 -0700537 }
538
James Dong54ff19a2010-10-08 11:59:32 -0700539 int64_t glitchDurationUs = (1000000LL / mVideoFrameRate);
James Dongf60cafe2010-06-19 09:04:18 -0700540 if (glitchDurationUs > mGlitchDurationThresholdUs) {
541 mGlitchDurationThresholdUs = glitchDurationUs;
542 }
543
James Dongddcc4a62010-06-08 11:58:53 -0700544 // XXX: query camera for the stride and slice height
545 // when the capability becomes available.
James Dong653252b2010-06-03 11:48:31 -0700546 mMeta = new MetaData;
James Dong54ff19a2010-10-08 11:59:32 -0700547 mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
548 mMeta->setInt32(kKeyColorFormat, mColorFormat);
549 mMeta->setInt32(kKeyWidth, mVideoSize.width);
550 mMeta->setInt32(kKeyHeight, mVideoSize.height);
551 mMeta->setInt32(kKeyStride, mVideoSize.width);
552 mMeta->setInt32(kKeySliceHeight, mVideoSize.height);
James Dong393410a2010-11-10 20:43:53 -0800553 mMeta->setInt32(kKeyFrameRate, mVideoFrameRate);
James Dong54ff19a2010-10-08 11:59:32 -0700554 return OK;
Andreas Huber20111aa2009-07-14 16:56:47 -0700555}
556
557CameraSource::~CameraSource() {
558 if (mStarted) {
James Dongb44c9d22012-02-02 18:04:02 -0800559 reset();
James Dongae4c1ac2011-07-08 17:59:29 -0700560 } else if (mInitCheck == OK) {
561 // Camera is initialized but because start() is never called,
562 // the lock on Camera is never released(). This makes sure
563 // Camera's lock is released in this case.
564 releaseCamera();
Andreas Huber20111aa2009-07-14 16:56:47 -0700565 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700566}
567
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700568void CameraSource::startCameraRecording() {
Steve Block3856b092011-10-20 11:56:00 +0100569 ALOGV("startCameraRecording");
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800570 // Reset the identity to the current thread because media server owns the
571 // camera and recording is started by the applications. The applications
572 // will connect to the camera in ICameraRecordingProxy::startRecording.
573 int64_t token = IPCThreadState::self()->clearCallingIdentity();
James Dong3bd30202011-07-19 20:24:22 -0700574 if (mCameraFlags & FLAGS_HOT_CAMERA) {
575 mCamera->unlock();
576 mCamera.clear();
James Dongf1d5aa12012-02-06 23:46:37 -0800577 CHECK_EQ((status_t)OK,
578 mCameraRecordingProxy->startRecording(new ProxyListener(this)));
James Dong3bd30202011-07-19 20:24:22 -0700579 } else {
580 mCamera->setListener(new CameraSourceListener(this));
581 mCamera->startRecording();
582 CHECK(mCamera->recordingEnabled());
583 }
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800584 IPCThreadState::self()->restoreCallingIdentity(token);
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700585}
586
James Dongf60cafe2010-06-19 09:04:18 -0700587status_t CameraSource::start(MetaData *meta) {
Steve Block3856b092011-10-20 11:56:00 +0100588 ALOGV("start");
Andreas Huber0c891992009-08-26 14:48:20 -0700589 CHECK(!mStarted);
James Dong54ff19a2010-10-08 11:59:32 -0700590 if (mInitCheck != OK) {
Steve Block29357bc2012-01-06 19:20:56 +0000591 ALOGE("CameraSource is not initialized yet");
James Dong54ff19a2010-10-08 11:59:32 -0700592 return mInitCheck;
593 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700594
James Dong365a9632010-06-04 13:59:27 -0700595 char value[PROPERTY_VALUE_MAX];
596 if (property_get("media.stagefright.record-stats", value, NULL)
597 && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
598 mCollectStats = true;
599 }
James Dong9d7f58a2010-06-09 15:57:48 -0700600
James Dongf60cafe2010-06-19 09:04:18 -0700601 mStartTimeUs = 0;
602 int64_t startTimeUs;
603 if (meta && meta->findInt64(kKeyTime, &startTimeUs)) {
604 mStartTimeUs = startTimeUs;
605 }
606
James Dongc42478e2010-11-15 10:38:37 -0800607 startCameraRecording();
Andreas Huber20111aa2009-07-14 16:56:47 -0700608
609 mStarted = true;
Andreas Huber20111aa2009-07-14 16:56:47 -0700610 return OK;
611}
612
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700613void CameraSource::stopCameraRecording() {
Steve Block3856b092011-10-20 11:56:00 +0100614 ALOGV("stopCameraRecording");
James Dong3bd30202011-07-19 20:24:22 -0700615 if (mCameraFlags & FLAGS_HOT_CAMERA) {
616 mCameraRecordingProxy->stopRecording();
617 } else {
618 mCamera->setListener(NULL);
619 mCamera->stopRecording();
620 }
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700621}
622
James Dongea7b4852010-12-05 14:25:34 -0800623void CameraSource::releaseCamera() {
Steve Block3856b092011-10-20 11:56:00 +0100624 ALOGV("releaseCamera");
Wu-cheng Li95068be2011-06-29 15:17:11 +0800625 if (mCamera != 0) {
James Dongae4c1ac2011-07-08 17:59:29 -0700626 int64_t token = IPCThreadState::self()->clearCallingIdentity();
Wu-cheng Li95068be2011-06-29 15:17:11 +0800627 if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) {
Steve Block3856b092011-10-20 11:56:00 +0100628 ALOGV("Camera was cold when we started, stopping preview");
Wu-cheng Li95068be2011-06-29 15:17:11 +0800629 mCamera->stopPreview();
630 mCamera->disconnect();
Wu-cheng Li95068be2011-06-29 15:17:11 +0800631 }
James Dong3bd30202011-07-19 20:24:22 -0700632 mCamera->unlock();
Wu-cheng Li95068be2011-06-29 15:17:11 +0800633 mCamera.clear();
James Dong3bd30202011-07-19 20:24:22 -0700634 mCamera = 0;
James Dongae4c1ac2011-07-08 17:59:29 -0700635 IPCThreadState::self()->restoreCallingIdentity(token);
James Dongea7b4852010-12-05 14:25:34 -0800636 }
Wu-cheng Li95068be2011-06-29 15:17:11 +0800637 if (mCameraRecordingProxy != 0) {
638 mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
639 mCameraRecordingProxy.clear();
640 }
James Dongea7b4852010-12-05 14:25:34 -0800641 mCameraFlags = 0;
642}
643
James Dongb44c9d22012-02-02 18:04:02 -0800644status_t CameraSource::reset() {
645 ALOGD("reset: E");
James Dongc32cd792010-04-26 17:48:26 -0700646 Mutex::Autolock autoLock(mLock);
Andreas Huber20111aa2009-07-14 16:56:47 -0700647 mStarted = false;
James Dongc32cd792010-04-26 17:48:26 -0700648 mFrameAvailableCondition.signal();
James Dong365a9632010-06-04 13:59:27 -0700649
James Dong91974412011-08-24 19:50:36 -0700650 int64_t token;
651 bool isTokenValid = false;
652 if (mCamera != 0) {
653 token = IPCThreadState::self()->clearCallingIdentity();
654 isTokenValid = true;
655 }
James Dongc32cd792010-04-26 17:48:26 -0700656 releaseQueuedFrames();
James Dong7278cf32010-05-27 16:05:58 -0700657 while (!mFramesBeingEncoded.empty()) {
James Dong41152ef2010-12-20 21:29:12 -0800658 if (NO_ERROR !=
James Donge8e5f862011-11-20 09:45:44 -0800659 mFrameCompleteCondition.waitRelative(mLock,
660 mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000661 ALOGW("Timed out waiting for outstanding frames being encoded: %d",
James Dong365a9632010-06-04 13:59:27 -0700662 mFramesBeingEncoded.size());
James Dong41152ef2010-12-20 21:29:12 -0800663 }
James Dong7278cf32010-05-27 16:05:58 -0700664 }
James Dongd69c7f62010-12-09 11:24:22 -0800665 stopCameraRecording();
James Dongea7b4852010-12-05 14:25:34 -0800666 releaseCamera();
James Dong91974412011-08-24 19:50:36 -0700667 if (isTokenValid) {
668 IPCThreadState::self()->restoreCallingIdentity(token);
669 }
James Dong7278cf32010-05-27 16:05:58 -0700670
James Dong365a9632010-06-04 13:59:27 -0700671 if (mCollectStats) {
Steve Blockdf64d152012-01-04 20:05:49 +0000672 ALOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
James Dong365a9632010-06-04 13:59:27 -0700673 mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
674 mLastFrameTimestampUs - mFirstFrameTimeUs);
675 }
James Dong13aec892010-04-21 16:14:15 -0700676
James Dongba290022010-12-09 15:04:33 -0800677 if (mNumGlitches > 0) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000678 ALOGW("%d long delays between neighboring video frames", mNumGlitches);
James Dongba290022010-12-09 15:04:33 -0800679 }
680
James Dong13aec892010-04-21 16:14:15 -0700681 CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
James Dongb44c9d22012-02-02 18:04:02 -0800682 ALOGD("reset: X");
Andreas Huber20111aa2009-07-14 16:56:47 -0700683 return OK;
684}
685
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700686void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
Steve Block3856b092011-10-20 11:56:00 +0100687 ALOGV("releaseRecordingFrame");
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800688 if (mCameraRecordingProxy != NULL) {
689 mCameraRecordingProxy->releaseRecordingFrame(frame);
James Dong334d0972011-08-05 17:19:29 -0700690 } else if (mCamera != NULL) {
James Dong3bd30202011-07-19 20:24:22 -0700691 int64_t token = IPCThreadState::self()->clearCallingIdentity();
692 mCamera->releaseRecordingFrame(frame);
693 IPCThreadState::self()->restoreCallingIdentity(token);
James Dongd69c7f62010-12-09 11:24:22 -0800694 }
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700695}
696
James Dongc32cd792010-04-26 17:48:26 -0700697void CameraSource::releaseQueuedFrames() {
698 List<sp<IMemory> >::iterator it;
James Dong7278cf32010-05-27 16:05:58 -0700699 while (!mFramesReceived.empty()) {
700 it = mFramesReceived.begin();
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700701 releaseRecordingFrame(*it);
James Dong7278cf32010-05-27 16:05:58 -0700702 mFramesReceived.erase(it);
James Dong13aec892010-04-21 16:14:15 -0700703 ++mNumFramesDropped;
James Dongc32cd792010-04-26 17:48:26 -0700704 }
705}
706
Andreas Huber20111aa2009-07-14 16:56:47 -0700707sp<MetaData> CameraSource::getFormat() {
James Dong653252b2010-06-03 11:48:31 -0700708 return mMeta;
Andreas Huber20111aa2009-07-14 16:56:47 -0700709}
710
James Dongf60cafe2010-06-19 09:04:18 -0700711void CameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) {
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700712 releaseRecordingFrame(frame);
James Dongf60cafe2010-06-19 09:04:18 -0700713}
714
James Dong7278cf32010-05-27 16:05:58 -0700715void CameraSource::signalBufferReturned(MediaBuffer *buffer) {
Steve Block3856b092011-10-20 11:56:00 +0100716 ALOGV("signalBufferReturned: %p", buffer->data());
Andreas Huber56223b92010-08-11 12:34:32 -0700717 Mutex::Autolock autoLock(mLock);
James Dong7278cf32010-05-27 16:05:58 -0700718 for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
719 it != mFramesBeingEncoded.end(); ++it) {
720 if ((*it)->pointer() == buffer->data()) {
James Dongf60cafe2010-06-19 09:04:18 -0700721 releaseOneRecordingFrame((*it));
James Dong7278cf32010-05-27 16:05:58 -0700722 mFramesBeingEncoded.erase(it);
723 ++mNumFramesEncoded;
724 buffer->setObserver(0);
725 buffer->release();
726 mFrameCompleteCondition.signal();
727 return;
728 }
729 }
James Dongf1d5aa12012-02-06 23:46:37 -0800730 CHECK(!"signalBufferReturned: bogus buffer");
James Dong7278cf32010-05-27 16:05:58 -0700731}
732
Andreas Huber20111aa2009-07-14 16:56:47 -0700733status_t CameraSource::read(
734 MediaBuffer **buffer, const ReadOptions *options) {
Steve Block3856b092011-10-20 11:56:00 +0100735 ALOGV("read");
Andreas Huber20111aa2009-07-14 16:56:47 -0700736
737 *buffer = NULL;
738
739 int64_t seekTimeUs;
Andreas Huberabd1f4f2010-07-20 15:04:28 -0700740 ReadOptions::SeekMode mode;
741 if (options && options->getSeekTo(&seekTimeUs, &mode)) {
Andreas Huber20111aa2009-07-14 16:56:47 -0700742 return ERROR_UNSUPPORTED;
743 }
744
745 sp<IMemory> frame;
Andreas Huberbe5c74f2009-10-13 17:08:31 -0700746 int64_t frameTime;
Andreas Huber20111aa2009-07-14 16:56:47 -0700747
748 {
749 Mutex::Autolock autoLock(mLock);
James Dong79e23b42010-12-11 10:43:41 -0800750 while (mStarted && mFramesReceived.empty()) {
James Dong41152ef2010-12-20 21:29:12 -0800751 if (NO_ERROR !=
James Donge8e5f862011-11-20 09:45:44 -0800752 mFrameAvailableCondition.waitRelative(mLock,
753 mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
James Dong3bd30202011-07-19 20:24:22 -0700754 if (mCameraRecordingProxy != 0 &&
755 !mCameraRecordingProxy->asBinder()->isBinderAlive()) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000756 ALOGW("camera recording proxy is gone");
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800757 return ERROR_END_OF_STREAM;
758 }
Steve Block5ff1dd52012-01-05 23:22:43 +0000759 ALOGW("Timed out waiting for incoming camera video frames: %lld us",
James Dong41152ef2010-12-20 21:29:12 -0800760 mLastFrameTimestampUs);
761 }
James Dong542db5d2010-07-21 14:51:35 -0700762 }
James Dong79e23b42010-12-11 10:43:41 -0800763 if (!mStarted) {
764 return OK;
765 }
766 frame = *mFramesReceived.begin();
767 mFramesReceived.erase(mFramesReceived.begin());
768
769 frameTime = *mFrameTimes.begin();
770 mFrameTimes.erase(mFrameTimes.begin());
771 mFramesBeingEncoded.push_back(frame);
772 *buffer = new MediaBuffer(frame->pointer(), frame->size());
773 (*buffer)->setObserver(this);
774 (*buffer)->add_ref();
775 (*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
Andreas Huber20111aa2009-07-14 16:56:47 -0700776 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700777 return OK;
778}
779
James Dongc32cd792010-04-26 17:48:26 -0700780void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
781 int32_t msgType, const sp<IMemory> &data) {
Steve Block3856b092011-10-20 11:56:00 +0100782 ALOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
Andreas Huber20111aa2009-07-14 16:56:47 -0700783 Mutex::Autolock autoLock(mLock);
James Donga4726132011-02-16 12:28:26 -0800784 if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
Steve Block3856b092011-10-20 11:56:00 +0100785 ALOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs);
James Dongf60cafe2010-06-19 09:04:18 -0700786 releaseOneRecordingFrame(data);
James Dongc32cd792010-04-26 17:48:26 -0700787 return;
788 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700789
James Dong98cfde02011-06-03 17:21:16 -0700790 if (mNumFramesReceived > 0) {
791 CHECK(timestampUs > mLastFrameTimestampUs);
792 if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) {
793 ++mNumGlitches;
James Dongf60cafe2010-06-19 09:04:18 -0700794 }
James Dongf60cafe2010-06-19 09:04:18 -0700795 }
796
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700797 // May need to skip frame or modify timestamp. Currently implemented
798 // by the subclass CameraSourceTimeLapse.
James Dong79e23b42010-12-11 10:43:41 -0800799 if (skipCurrentFrame(timestampUs)) {
Nipun Kwatra65e7e6f2010-07-12 09:17:14 -0700800 releaseOneRecordingFrame(data);
801 return;
Nipun Kwatrafc20aab2010-06-30 18:51:31 -0700802 }
803
James Dong365a9632010-06-04 13:59:27 -0700804 mLastFrameTimestampUs = timestampUs;
James Dong13aec892010-04-21 16:14:15 -0700805 if (mNumFramesReceived == 0) {
James Dongc32cd792010-04-26 17:48:26 -0700806 mFirstFrameTimeUs = timestampUs;
James Dongf60cafe2010-06-19 09:04:18 -0700807 // Initial delay
808 if (mStartTimeUs > 0) {
809 if (timestampUs < mStartTimeUs) {
810 // Frame was captured before recording was started
811 // Drop it without updating the statistical data.
812 releaseOneRecordingFrame(data);
813 return;
814 }
815 mStartTimeUs = timestampUs - mStartTimeUs;
816 }
Andreas Huberbe5c74f2009-10-13 17:08:31 -0700817 }
James Dong13aec892010-04-21 16:14:15 -0700818 ++mNumFramesReceived;
Andreas Huberbe5c74f2009-10-13 17:08:31 -0700819
James Dong98cfde02011-06-03 17:21:16 -0700820 CHECK(data != NULL && data->size() > 0);
James Dong7278cf32010-05-27 16:05:58 -0700821 mFramesReceived.push_back(data);
James Dongf60cafe2010-06-19 09:04:18 -0700822 int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
823 mFrameTimes.push_back(timeUs);
Steve Block3856b092011-10-20 11:56:00 +0100824 ALOGV("initial delay: %lld, current time stamp: %lld",
James Dongf60cafe2010-06-19 09:04:18 -0700825 mStartTimeUs, timeUs);
Andreas Huber20111aa2009-07-14 16:56:47 -0700826 mFrameAvailableCondition.signal();
827}
828
James Dong5c952312010-10-18 21:42:27 -0700829bool CameraSource::isMetaDataStoredInVideoBuffers() const {
Steve Block3856b092011-10-20 11:56:00 +0100830 ALOGV("isMetaDataStoredInVideoBuffers");
James Dong5c952312010-10-18 21:42:27 -0700831 return mIsMetaDataStoredInVideoBuffers;
832}
833
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800834CameraSource::ProxyListener::ProxyListener(const sp<CameraSource>& source) {
835 mSource = source;
836}
837
838void CameraSource::ProxyListener::dataCallbackTimestamp(
839 nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
840 mSource->dataCallbackTimestamp(timestamp / 1000, msgType, dataPtr);
841}
842
843void CameraSource::DeathNotifier::binderDied(const wp<IBinder>& who) {
Steve Blockdf64d152012-01-04 20:05:49 +0000844 ALOGI("Camera recording proxy died");
Wu-cheng Li4ca2c7c2011-06-01 17:22:24 +0800845}
846
Andreas Huber20111aa2009-07-14 16:56:47 -0700847} // namespace android