|
1 /* |
|
2 * Copyright (C) 2009 The Android Open Source Project |
|
3 * Copyright (C) 2013 Mozilla Foundation |
|
4 * |
|
5 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
6 * you may not use this file except in compliance with the License. |
|
7 * You may obtain a copy of the License at |
|
8 * |
|
9 * http://www.apache.org/licenses/LICENSE-2.0 |
|
10 * |
|
11 * Unless required by applicable law or agreed to in writing, software |
|
12 * distributed under the License is distributed on an "AS IS" BASIS, |
|
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 * See the License for the specific language governing permissions and |
|
15 * limitations under the License. |
|
16 */ |
|
17 |
|
18 #include <base/basictypes.h> |
|
19 #include "nsDebug.h" |
|
20 #define DOM_CAMERA_LOG_LEVEL 3 |
|
21 #include "CameraCommon.h" |
|
22 /* |
|
23 #define CS_LOGD(...) DOM_CAMERA_LOGA(__VA_ARGS__) |
|
24 #define CS_LOGV(...) DOM_CAMERA_LOGI(__VA_ARGS__) |
|
25 #define CS_LOGI(...) DOM_CAMERA_LOGI(__VA_ARGS__) |
|
26 #define CS_LOGW(...) DOM_CAMERA_LOGW(__VA_ARGS__) |
|
27 #define CS_LOGE(...) DOM_CAMERA_LOGE(__VA_ARGS__) |
|
28 */ |
|
29 |
|
30 #define CS_LOGD(fmt, ...) DOM_CAMERA_LOGA("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) |
|
31 #define CS_LOGV(fmt, ...) DOM_CAMERA_LOGI("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) |
|
32 #define CS_LOGI(fmt, ...) DOM_CAMERA_LOGI("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) |
|
33 #define CS_LOGW(fmt, ...) DOM_CAMERA_LOGW("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) |
|
34 #define CS_LOGE(fmt, ...) DOM_CAMERA_LOGE("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) |
|
35 |
|
36 #include <OMX_Component.h> |
|
37 #include <binder/IPCThreadState.h> |
|
38 #include <media/stagefright/foundation/ADebug.h> |
|
39 #include <media/stagefright/MediaDefs.h> |
|
40 #include <media/stagefright/MediaErrors.h> |
|
41 #include <media/stagefright/MetaData.h> |
|
42 #include <camera/CameraParameters.h> |
|
43 #include <utils/String8.h> |
|
44 #include <cutils/properties.h> |
|
45 |
|
46 #include "GonkCameraSource.h" |
|
47 #include "GonkCameraListener.h" |
|
48 #include "GonkCameraHwMgr.h" |
|
49 |
|
50 using namespace mozilla; |
|
51 |
|
52 namespace android { |
|
53 |
|
54 static const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL; |
|
55 |
|
56 struct GonkCameraSourceListener : public GonkCameraListener { |
|
57 GonkCameraSourceListener(const sp<GonkCameraSource> &source); |
|
58 |
|
59 virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); |
|
60 virtual void postData(int32_t msgType, const sp<IMemory> &dataPtr, |
|
61 camera_frame_metadata_t *metadata); |
|
62 |
|
63 virtual void postDataTimestamp( |
|
64 nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr); |
|
65 |
|
66 protected: |
|
67 virtual ~GonkCameraSourceListener(); |
|
68 |
|
69 private: |
|
70 wp<GonkCameraSource> mSource; |
|
71 |
|
72 GonkCameraSourceListener(const GonkCameraSourceListener &); |
|
73 GonkCameraSourceListener &operator=(const GonkCameraSourceListener &); |
|
74 }; |
|
75 |
|
76 GonkCameraSourceListener::GonkCameraSourceListener(const sp<GonkCameraSource> &source) |
|
77 : mSource(source) { |
|
78 } |
|
79 |
|
80 GonkCameraSourceListener::~GonkCameraSourceListener() { |
|
81 } |
|
82 |
|
83 void GonkCameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) { |
|
84 CS_LOGV("notify(%d, %d, %d)", msgType, ext1, ext2); |
|
85 } |
|
86 |
|
87 void GonkCameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr, |
|
88 camera_frame_metadata_t *metadata) { |
|
89 CS_LOGV("postData(%d, ptr:%p, size:%d)", |
|
90 msgType, dataPtr->pointer(), dataPtr->size()); |
|
91 |
|
92 sp<GonkCameraSource> source = mSource.promote(); |
|
93 if (source.get() != NULL) { |
|
94 source->dataCallback(msgType, dataPtr); |
|
95 } |
|
96 } |
|
97 |
|
98 void GonkCameraSourceListener::postDataTimestamp( |
|
99 nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) { |
|
100 |
|
101 sp<GonkCameraSource> source = mSource.promote(); |
|
102 if (source.get() != NULL) { |
|
103 source->dataCallbackTimestamp(timestamp/1000, msgType, dataPtr); |
|
104 } |
|
105 } |
|
106 |
|
107 static int32_t getColorFormat(const char* colorFormat) { |
|
108 return OMX_COLOR_FormatYUV420SemiPlanar; //XXX nsGonkCameraControl uses only YUV420SemiPlanar |
|
109 |
|
110 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) { |
|
111 return OMX_COLOR_FormatYUV420Planar; |
|
112 } |
|
113 |
|
114 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422SP)) { |
|
115 return OMX_COLOR_FormatYUV422SemiPlanar; |
|
116 } |
|
117 |
|
118 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) { |
|
119 return OMX_COLOR_FormatYUV420SemiPlanar; |
|
120 } |
|
121 |
|
122 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422I)) { |
|
123 return OMX_COLOR_FormatYCbYCr; |
|
124 } |
|
125 |
|
126 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_RGB565)) { |
|
127 return OMX_COLOR_Format16bitRGB565; |
|
128 } |
|
129 |
|
130 if (!strcmp(colorFormat, "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar")) { |
|
131 return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar; |
|
132 } |
|
133 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 |
|
134 if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE)) { |
|
135 return OMX_COLOR_FormatAndroidOpaque; |
|
136 } |
|
137 #endif |
|
138 CS_LOGE("Uknown color format (%s), please add it to " |
|
139 "GonkCameraSource::getColorFormat", colorFormat); |
|
140 |
|
141 CHECK(!"Unknown color format"); |
|
142 } |
|
143 |
|
144 GonkCameraSource *GonkCameraSource::Create( |
|
145 const sp<GonkCameraHardware>& aCameraHw, |
|
146 Size videoSize, |
|
147 int32_t frameRate, |
|
148 bool storeMetaDataInVideoBuffers) { |
|
149 |
|
150 GonkCameraSource *source = new GonkCameraSource(aCameraHw, |
|
151 videoSize, frameRate, |
|
152 storeMetaDataInVideoBuffers); |
|
153 return source; |
|
154 } |
|
155 |
|
156 GonkCameraSource::GonkCameraSource( |
|
157 const sp<GonkCameraHardware>& aCameraHw, |
|
158 Size videoSize, |
|
159 int32_t frameRate, |
|
160 bool storeMetaDataInVideoBuffers) |
|
161 : mCameraFlags(0), |
|
162 mNumInputBuffers(0), |
|
163 mVideoFrameRate(-1), |
|
164 mNumFramesReceived(0), |
|
165 mLastFrameTimestampUs(0), |
|
166 mStarted(false), |
|
167 mNumFramesEncoded(0), |
|
168 mTimeBetweenFrameCaptureUs(0), |
|
169 mFirstFrameTimeUs(0), |
|
170 mNumFramesDropped(0), |
|
171 mNumGlitches(0), |
|
172 mGlitchDurationThresholdUs(200000), |
|
173 mCollectStats(false), |
|
174 mCameraHw(aCameraHw) { |
|
175 mVideoSize.width = -1; |
|
176 mVideoSize.height = -1; |
|
177 |
|
178 mInitCheck = init( |
|
179 videoSize, frameRate, |
|
180 storeMetaDataInVideoBuffers); |
|
181 if (mInitCheck != OK) releaseCamera(); |
|
182 } |
|
183 |
|
184 status_t GonkCameraSource::initCheck() const { |
|
185 return mInitCheck; |
|
186 } |
|
187 |
|
188 //TODO: Do we need to reimplement isCameraAvailable? |
|
189 |
|
190 /* |
|
191 * Check to see whether the requested video width and height is one |
|
192 * of the supported sizes. |
|
193 * @param width the video frame width in pixels |
|
194 * @param height the video frame height in pixels |
|
195 * @param suppportedSizes the vector of sizes that we check against |
|
196 * @return true if the dimension (width and height) is supported. |
|
197 */ |
|
198 static bool isVideoSizeSupported( |
|
199 int32_t width, int32_t height, |
|
200 const Vector<Size>& supportedSizes) { |
|
201 |
|
202 CS_LOGV("isVideoSizeSupported"); |
|
203 for (size_t i = 0; i < supportedSizes.size(); ++i) { |
|
204 if (width == supportedSizes[i].width && |
|
205 height == supportedSizes[i].height) { |
|
206 return true; |
|
207 } |
|
208 } |
|
209 return false; |
|
210 } |
|
211 |
|
212 /* |
|
213 * If the preview and video output is separate, we only set the |
|
214 * the video size, and applications should set the preview size |
|
215 * to some proper value, and the recording framework will not |
|
216 * change the preview size; otherwise, if the video and preview |
|
217 * output is the same, we need to set the preview to be the same |
|
218 * as the requested video size. |
|
219 * |
|
220 */ |
|
221 /* |
|
222 * Query the camera to retrieve the supported video frame sizes |
|
223 * and also to see whether CameraParameters::setVideoSize() |
|
224 * is supported or not. |
|
225 * @param params CameraParameters to retrieve the information |
|
226 * @@param isSetVideoSizeSupported retunrs whether method |
|
227 * CameraParameters::setVideoSize() is supported or not. |
|
228 * @param sizes returns the vector of Size objects for the |
|
229 * supported video frame sizes advertised by the camera. |
|
230 */ |
|
231 static void getSupportedVideoSizes( |
|
232 const CameraParameters& params, |
|
233 bool *isSetVideoSizeSupported, |
|
234 Vector<Size>& sizes) { |
|
235 |
|
236 *isSetVideoSizeSupported = true; |
|
237 params.getSupportedVideoSizes(sizes); |
|
238 if (sizes.size() == 0) { |
|
239 CS_LOGD("Camera does not support setVideoSize()"); |
|
240 params.getSupportedPreviewSizes(sizes); |
|
241 *isSetVideoSizeSupported = false; |
|
242 } |
|
243 } |
|
244 |
|
245 /* |
|
246 * Check whether the camera has the supported color format |
|
247 * @param params CameraParameters to retrieve the information |
|
248 * @return OK if no error. |
|
249 */ |
|
250 status_t GonkCameraSource::isCameraColorFormatSupported( |
|
251 const CameraParameters& params) { |
|
252 mColorFormat = getColorFormat(params.get( |
|
253 CameraParameters::KEY_VIDEO_FRAME_FORMAT)); |
|
254 if (mColorFormat == -1) { |
|
255 return BAD_VALUE; |
|
256 } |
|
257 return OK; |
|
258 } |
|
259 |
|
260 /* |
|
261 * Configure the camera to use the requested video size |
|
262 * (width and height) and/or frame rate. If both width and |
|
263 * height are -1, configuration on the video size is skipped. |
|
264 * if frameRate is -1, configuration on the frame rate |
|
265 * is skipped. Skipping the configuration allows one to |
|
266 * use the current camera setting without the need to |
|
267 * actually know the specific values (see Create() method). |
|
268 * |
|
269 * @param params the CameraParameters to be configured |
|
270 * @param width the target video frame width in pixels |
|
271 * @param height the target video frame height in pixels |
|
272 * @param frameRate the target frame rate in frames per second. |
|
273 * @return OK if no error. |
|
274 */ |
|
275 status_t GonkCameraSource::configureCamera( |
|
276 CameraParameters* params, |
|
277 int32_t width, int32_t height, |
|
278 int32_t frameRate) { |
|
279 CS_LOGV("configureCamera"); |
|
280 Vector<Size> sizes; |
|
281 bool isSetVideoSizeSupportedByCamera = true; |
|
282 getSupportedVideoSizes(*params, &isSetVideoSizeSupportedByCamera, sizes); |
|
283 bool isCameraParamChanged = false; |
|
284 if (width != -1 && height != -1) { |
|
285 if (!isVideoSizeSupported(width, height, sizes)) { |
|
286 CS_LOGE("Video dimension (%dx%d) is unsupported", width, height); |
|
287 return BAD_VALUE; |
|
288 } |
|
289 if (isSetVideoSizeSupportedByCamera) { |
|
290 params->setVideoSize(width, height); |
|
291 } else { |
|
292 params->setPreviewSize(width, height); |
|
293 } |
|
294 isCameraParamChanged = true; |
|
295 } else if ((width == -1 && height != -1) || |
|
296 (width != -1 && height == -1)) { |
|
297 // If one and only one of the width and height is -1 |
|
298 // we reject such a request. |
|
299 CS_LOGE("Requested video size (%dx%d) is not supported", width, height); |
|
300 return BAD_VALUE; |
|
301 } else { // width == -1 && height == -1 |
|
302 // Do not configure the camera. |
|
303 // Use the current width and height value setting from the camera. |
|
304 } |
|
305 |
|
306 if (frameRate != -1) { |
|
307 CHECK(frameRate > 0 && frameRate <= 120); |
|
308 const char* supportedFrameRates = |
|
309 params->get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES); |
|
310 CHECK(supportedFrameRates != NULL); |
|
311 CS_LOGV("Supported frame rates: %s", supportedFrameRates); |
|
312 char buf[4]; |
|
313 snprintf(buf, 4, "%d", frameRate); |
|
314 if (strstr(supportedFrameRates, buf) == NULL) { |
|
315 CS_LOGE("Requested frame rate (%d) is not supported: %s", |
|
316 frameRate, supportedFrameRates); |
|
317 return BAD_VALUE; |
|
318 } |
|
319 |
|
320 // The frame rate is supported, set the camera to the requested value. |
|
321 params->setPreviewFrameRate(frameRate); |
|
322 isCameraParamChanged = true; |
|
323 } else { // frameRate == -1 |
|
324 // Do not configure the camera. |
|
325 // Use the current frame rate value setting from the camera |
|
326 } |
|
327 |
|
328 if (isCameraParamChanged) { |
|
329 // Either frame rate or frame size needs to be changed. |
|
330 if (OK != mCameraHw->PushParameters(*params)) { |
|
331 CS_LOGE("Could not change settings." |
|
332 " Someone else is using camera?"); |
|
333 return -EBUSY; |
|
334 } |
|
335 } |
|
336 return OK; |
|
337 } |
|
338 |
|
339 /* |
|
340 * Check whether the requested video frame size |
|
341 * has been successfully configured or not. If both width and height |
|
342 * are -1, check on the current width and height value setting |
|
343 * is performed. |
|
344 * |
|
345 * @param params CameraParameters to retrieve the information |
|
346 * @param the target video frame width in pixels to check against |
|
347 * @param the target video frame height in pixels to check against |
|
348 * @return OK if no error |
|
349 */ |
|
350 status_t GonkCameraSource::checkVideoSize( |
|
351 const CameraParameters& params, |
|
352 int32_t width, int32_t height) { |
|
353 |
|
354 CS_LOGV("checkVideoSize"); |
|
355 // The actual video size is the same as the preview size |
|
356 // if the camera hal does not support separate video and |
|
357 // preview output. In this case, we retrieve the video |
|
358 // size from preview. |
|
359 int32_t frameWidthActual = -1; |
|
360 int32_t frameHeightActual = -1; |
|
361 Vector<Size> sizes; |
|
362 params.getSupportedVideoSizes(sizes); |
|
363 if (sizes.size() == 0) { |
|
364 // video size is the same as preview size |
|
365 params.getPreviewSize(&frameWidthActual, &frameHeightActual); |
|
366 } else { |
|
367 // video size may not be the same as preview |
|
368 params.getVideoSize(&frameWidthActual, &frameHeightActual); |
|
369 } |
|
370 if (frameWidthActual < 0 || frameHeightActual < 0) { |
|
371 CS_LOGE("Failed to retrieve video frame size (%dx%d)", |
|
372 frameWidthActual, frameHeightActual); |
|
373 return UNKNOWN_ERROR; |
|
374 } |
|
375 |
|
376 // Check the actual video frame size against the target/requested |
|
377 // video frame size. |
|
378 if (width != -1 && height != -1) { |
|
379 if (frameWidthActual != width || frameHeightActual != height) { |
|
380 CS_LOGE("Failed to set video frame size to %dx%d. " |
|
381 "The actual video size is %dx%d ", width, height, |
|
382 frameWidthActual, frameHeightActual); |
|
383 return UNKNOWN_ERROR; |
|
384 } |
|
385 } |
|
386 |
|
387 // Good now. |
|
388 mVideoSize.width = frameWidthActual; |
|
389 mVideoSize.height = frameHeightActual; |
|
390 return OK; |
|
391 } |
|
392 |
|
393 /* |
|
394 * Check the requested frame rate has been successfully configured or not. |
|
395 * If the target frameRate is -1, check on the current frame rate value |
|
396 * setting is performed. |
|
397 * |
|
398 * @param params CameraParameters to retrieve the information |
|
399 * @param the target video frame rate to check against |
|
400 * @return OK if no error. |
|
401 */ |
|
402 status_t GonkCameraSource::checkFrameRate( |
|
403 const CameraParameters& params, |
|
404 int32_t frameRate) { |
|
405 |
|
406 CS_LOGV("checkFrameRate"); |
|
407 int32_t frameRateActual = params.getPreviewFrameRate(); |
|
408 if (frameRateActual < 0) { |
|
409 CS_LOGE("Failed to retrieve preview frame rate (%d)", frameRateActual); |
|
410 return UNKNOWN_ERROR; |
|
411 } |
|
412 |
|
413 // Check the actual video frame rate against the target/requested |
|
414 // video frame rate. |
|
415 if (frameRate != -1 && (frameRateActual - frameRate) != 0) { |
|
416 CS_LOGE("Failed to set preview frame rate to %d fps. The actual " |
|
417 "frame rate is %d", frameRate, frameRateActual); |
|
418 return UNKNOWN_ERROR; |
|
419 } |
|
420 |
|
421 // Good now. |
|
422 mVideoFrameRate = frameRateActual; |
|
423 return OK; |
|
424 } |
|
425 |
|
426 /* |
|
427 * Initialize the GonkCameraSource so that it becomes |
|
428 * ready for providing the video input streams as requested. |
|
429 * @param camera the camera object used for the video source |
|
430 * @param cameraId if camera == 0, use camera with this id |
|
431 * as the video source |
|
432 * @param videoSize the target video frame size. If both |
|
433 * width and height in videoSize is -1, use the current |
|
434 * width and heigth settings by the camera |
|
435 * @param frameRate the target frame rate in frames per second. |
|
436 * if it is -1, use the current camera frame rate setting. |
|
437 * @param storeMetaDataInVideoBuffers request to store meta |
|
438 * data or real YUV data in video buffers. Request to |
|
439 * store meta data in video buffers may not be honored |
|
440 * if the source does not support this feature. |
|
441 * |
|
442 * @return OK if no error. |
|
443 */ |
|
444 status_t GonkCameraSource::init( |
|
445 Size videoSize, |
|
446 int32_t frameRate, |
|
447 bool storeMetaDataInVideoBuffers) { |
|
448 |
|
449 CS_LOGV("init"); |
|
450 status_t err = OK; |
|
451 //TODO: need to do something here to check the sanity of camera |
|
452 |
|
453 CameraParameters params; |
|
454 mCameraHw->PullParameters(params); |
|
455 if ((err = isCameraColorFormatSupported(params)) != OK) { |
|
456 return err; |
|
457 } |
|
458 |
|
459 // Set the camera to use the requested video frame size |
|
460 // and/or frame rate. |
|
461 if ((err = configureCamera(¶ms, |
|
462 videoSize.width, videoSize.height, |
|
463 frameRate))) { |
|
464 return err; |
|
465 } |
|
466 |
|
467 // Check on video frame size and frame rate. |
|
468 CameraParameters newCameraParams; |
|
469 mCameraHw->PullParameters(newCameraParams); |
|
470 if ((err = checkVideoSize(newCameraParams, |
|
471 videoSize.width, videoSize.height)) != OK) { |
|
472 return err; |
|
473 } |
|
474 if ((err = checkFrameRate(newCameraParams, frameRate)) != OK) { |
|
475 return err; |
|
476 } |
|
477 |
|
478 // By default, do not store metadata in video buffers |
|
479 mIsMetaDataStoredInVideoBuffers = false; |
|
480 mCameraHw->StoreMetaDataInBuffers(false); |
|
481 if (storeMetaDataInVideoBuffers) { |
|
482 if (OK == mCameraHw->StoreMetaDataInBuffers(true)) { |
|
483 mIsMetaDataStoredInVideoBuffers = true; |
|
484 } |
|
485 } |
|
486 |
|
487 int64_t glitchDurationUs = (1000000LL / mVideoFrameRate); |
|
488 if (glitchDurationUs > mGlitchDurationThresholdUs) { |
|
489 mGlitchDurationThresholdUs = glitchDurationUs; |
|
490 } |
|
491 |
|
492 // XXX: query camera for the stride and slice height |
|
493 // when the capability becomes available. |
|
494 mMeta = new MetaData; |
|
495 mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); |
|
496 mMeta->setInt32(kKeyColorFormat, mColorFormat); |
|
497 mMeta->setInt32(kKeyWidth, mVideoSize.width); |
|
498 mMeta->setInt32(kKeyHeight, mVideoSize.height); |
|
499 mMeta->setInt32(kKeyStride, mVideoSize.width); |
|
500 mMeta->setInt32(kKeySliceHeight, mVideoSize.height); |
|
501 mMeta->setInt32(kKeyFrameRate, mVideoFrameRate); |
|
502 return OK; |
|
503 } |
|
504 |
|
505 GonkCameraSource::~GonkCameraSource() { |
|
506 if (mStarted) { |
|
507 reset(); |
|
508 } else if (mInitCheck == OK) { |
|
509 // Camera is initialized but because start() is never called, |
|
510 // the lock on Camera is never released(). This makes sure |
|
511 // Camera's lock is released in this case. |
|
512 // TODO: Don't think I need to do this |
|
513 releaseCamera(); |
|
514 } |
|
515 } |
|
516 |
|
517 int GonkCameraSource::startCameraRecording() { |
|
518 CS_LOGV("startCameraRecording"); |
|
519 return mCameraHw->StartRecording(); |
|
520 } |
|
521 |
|
522 status_t GonkCameraSource::start(MetaData *meta) { |
|
523 int rv; |
|
524 |
|
525 CS_LOGV("start"); |
|
526 CHECK(!mStarted); |
|
527 if (mInitCheck != OK) { |
|
528 CS_LOGE("GonkCameraSource is not initialized yet"); |
|
529 return mInitCheck; |
|
530 } |
|
531 |
|
532 char value[PROPERTY_VALUE_MAX]; |
|
533 if (property_get("media.stagefright.record-stats", value, NULL) |
|
534 && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { |
|
535 mCollectStats = true; |
|
536 } |
|
537 |
|
538 mStartTimeUs = 0; |
|
539 mNumInputBuffers = 0; |
|
540 if (meta) { |
|
541 int64_t startTimeUs; |
|
542 if (meta->findInt64(kKeyTime, &startTimeUs)) { |
|
543 mStartTimeUs = startTimeUs; |
|
544 } |
|
545 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 |
|
546 int32_t nBuffers; |
|
547 if (meta->findInt32(kKeyNumBuffers, &nBuffers)) { |
|
548 CHECK_GT(nBuffers, 0); |
|
549 mNumInputBuffers = nBuffers; |
|
550 } |
|
551 #endif |
|
552 } |
|
553 |
|
554 // Register a listener with GonkCameraHardware so that we can get callbacks |
|
555 mCameraHw->SetListener(new GonkCameraSourceListener(this)); |
|
556 |
|
557 rv = startCameraRecording(); |
|
558 |
|
559 mStarted = (rv == OK); |
|
560 return rv; |
|
561 } |
|
562 |
|
563 void GonkCameraSource::stopCameraRecording() { |
|
564 CS_LOGV("stopCameraRecording"); |
|
565 mCameraHw->StopRecording(); |
|
566 } |
|
567 |
|
568 void GonkCameraSource::releaseCamera() { |
|
569 CS_LOGV("releaseCamera"); |
|
570 } |
|
571 |
|
572 status_t GonkCameraSource::reset() { |
|
573 CS_LOGD("reset: E"); |
|
574 Mutex::Autolock autoLock(mLock); |
|
575 mStarted = false; |
|
576 mFrameAvailableCondition.signal(); |
|
577 |
|
578 releaseQueuedFrames(); |
|
579 while (!mFramesBeingEncoded.empty()) { |
|
580 if (NO_ERROR != |
|
581 mFrameCompleteCondition.waitRelative(mLock, |
|
582 mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) { |
|
583 CS_LOGW("Timed out waiting for outstanding frames being encoded: %d", |
|
584 mFramesBeingEncoded.size()); |
|
585 } |
|
586 } |
|
587 stopCameraRecording(); |
|
588 releaseCamera(); |
|
589 |
|
590 if (mCollectStats) { |
|
591 CS_LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us", |
|
592 mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped, |
|
593 mLastFrameTimestampUs - mFirstFrameTimeUs); |
|
594 } |
|
595 |
|
596 if (mNumGlitches > 0) { |
|
597 CS_LOGW("%d long delays between neighboring video frames", mNumGlitches); |
|
598 } |
|
599 |
|
600 CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped); |
|
601 CS_LOGD("reset: X"); |
|
602 return OK; |
|
603 } |
|
604 |
|
605 void GonkCameraSource::releaseRecordingFrame(const sp<IMemory>& frame) { |
|
606 CS_LOGV("releaseRecordingFrame"); |
|
607 mCameraHw->ReleaseRecordingFrame(frame); |
|
608 } |
|
609 |
|
610 void GonkCameraSource::releaseQueuedFrames() { |
|
611 List<sp<IMemory> >::iterator it; |
|
612 while (!mFramesReceived.empty()) { |
|
613 it = mFramesReceived.begin(); |
|
614 releaseRecordingFrame(*it); |
|
615 mFramesReceived.erase(it); |
|
616 ++mNumFramesDropped; |
|
617 } |
|
618 } |
|
619 |
|
620 sp<MetaData> GonkCameraSource::getFormat() { |
|
621 return mMeta; |
|
622 } |
|
623 |
|
624 void GonkCameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) { |
|
625 releaseRecordingFrame(frame); |
|
626 } |
|
627 |
|
628 void GonkCameraSource::signalBufferReturned(MediaBuffer *buffer) { |
|
629 CS_LOGV("signalBufferReturned: %p", buffer->data()); |
|
630 Mutex::Autolock autoLock(mLock); |
|
631 for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin(); |
|
632 it != mFramesBeingEncoded.end(); ++it) { |
|
633 if ((*it)->pointer() == buffer->data()) { |
|
634 releaseOneRecordingFrame((*it)); |
|
635 mFramesBeingEncoded.erase(it); |
|
636 ++mNumFramesEncoded; |
|
637 buffer->setObserver(0); |
|
638 buffer->release(); |
|
639 mFrameCompleteCondition.signal(); |
|
640 return; |
|
641 } |
|
642 } |
|
643 CHECK(!"signalBufferReturned: bogus buffer"); |
|
644 } |
|
645 |
|
646 status_t GonkCameraSource::read( |
|
647 MediaBuffer **buffer, const ReadOptions *options) { |
|
648 CS_LOGV("read"); |
|
649 |
|
650 *buffer = NULL; |
|
651 |
|
652 int64_t seekTimeUs; |
|
653 ReadOptions::SeekMode mode; |
|
654 if (options && options->getSeekTo(&seekTimeUs, &mode)) { |
|
655 return ERROR_UNSUPPORTED; |
|
656 } |
|
657 |
|
658 sp<IMemory> frame; |
|
659 int64_t frameTime; |
|
660 |
|
661 { |
|
662 Mutex::Autolock autoLock(mLock); |
|
663 while (mStarted && mFramesReceived.empty()) { |
|
664 if (NO_ERROR != |
|
665 mFrameAvailableCondition.waitRelative(mLock, |
|
666 mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) { |
|
667 //TODO: check sanity of camera? |
|
668 CS_LOGW("Timed out waiting for incoming camera video frames: %lld us", |
|
669 mLastFrameTimestampUs); |
|
670 } |
|
671 } |
|
672 if (!mStarted) { |
|
673 return OK; |
|
674 } |
|
675 frame = *mFramesReceived.begin(); |
|
676 mFramesReceived.erase(mFramesReceived.begin()); |
|
677 |
|
678 frameTime = *mFrameTimes.begin(); |
|
679 mFrameTimes.erase(mFrameTimes.begin()); |
|
680 mFramesBeingEncoded.push_back(frame); |
|
681 *buffer = new MediaBuffer(frame->pointer(), frame->size()); |
|
682 (*buffer)->setObserver(this); |
|
683 (*buffer)->add_ref(); |
|
684 (*buffer)->meta_data()->setInt64(kKeyTime, frameTime); |
|
685 } |
|
686 return OK; |
|
687 } |
|
688 |
|
689 void GonkCameraSource::dataCallbackTimestamp(int64_t timestampUs, |
|
690 int32_t msgType, const sp<IMemory> &data) { |
|
691 CS_LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs); |
|
692 Mutex::Autolock autoLock(mLock); |
|
693 if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) { |
|
694 CS_LOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs); |
|
695 releaseOneRecordingFrame(data); |
|
696 return; |
|
697 } |
|
698 |
|
699 if (mNumFramesReceived > 0) { |
|
700 CHECK(timestampUs > mLastFrameTimestampUs); |
|
701 if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) { |
|
702 ++mNumGlitches; |
|
703 } |
|
704 } |
|
705 |
|
706 // May need to skip frame or modify timestamp. Currently implemented |
|
707 // by the subclass CameraSourceTimeLapse. |
|
708 if (skipCurrentFrame(timestampUs)) { |
|
709 releaseOneRecordingFrame(data); |
|
710 return; |
|
711 } |
|
712 |
|
713 mLastFrameTimestampUs = timestampUs; |
|
714 if (mNumFramesReceived == 0) { |
|
715 mFirstFrameTimeUs = timestampUs; |
|
716 // Initial delay |
|
717 if (mStartTimeUs > 0) { |
|
718 if (timestampUs < mStartTimeUs) { |
|
719 // Frame was captured before recording was started |
|
720 // Drop it without updating the statistical data. |
|
721 releaseOneRecordingFrame(data); |
|
722 return; |
|
723 } |
|
724 mStartTimeUs = timestampUs - mStartTimeUs; |
|
725 } |
|
726 } |
|
727 ++mNumFramesReceived; |
|
728 |
|
729 CHECK(data != NULL && data->size() > 0); |
|
730 mFramesReceived.push_back(data); |
|
731 int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs); |
|
732 mFrameTimes.push_back(timeUs); |
|
733 CS_LOGV("initial delay: %lld, current time stamp: %lld", |
|
734 mStartTimeUs, timeUs); |
|
735 mFrameAvailableCondition.signal(); |
|
736 } |
|
737 |
|
738 bool GonkCameraSource::isMetaDataStoredInVideoBuffers() const { |
|
739 CS_LOGV("isMetaDataStoredInVideoBuffers"); |
|
740 return mIsMetaDataStoredInVideoBuffers; |
|
741 } |
|
742 |
|
743 } // namespace android |