1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/camera/GonkCameraSource.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,743 @@ 1.4 +/* 1.5 + * Copyright (C) 2009 The Android Open Source Project 1.6 + * Copyright (C) 2013 Mozilla Foundation 1.7 + * 1.8 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.9 + * you may not use this file except in compliance with the License. 1.10 + * You may obtain a copy of the License at 1.11 + * 1.12 + * http://www.apache.org/licenses/LICENSE-2.0 1.13 + * 1.14 + * Unless required by applicable law or agreed to in writing, software 1.15 + * distributed under the License is distributed on an "AS IS" BASIS, 1.16 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.17 + * See the License for the specific language governing permissions and 1.18 + * limitations under the License. 1.19 + */ 1.20 + 1.21 +#include <base/basictypes.h> 1.22 +#include "nsDebug.h" 1.23 +#define DOM_CAMERA_LOG_LEVEL 3 1.24 +#include "CameraCommon.h" 1.25 +/* 1.26 +#define CS_LOGD(...) DOM_CAMERA_LOGA(__VA_ARGS__) 1.27 +#define CS_LOGV(...) DOM_CAMERA_LOGI(__VA_ARGS__) 1.28 +#define CS_LOGI(...) DOM_CAMERA_LOGI(__VA_ARGS__) 1.29 +#define CS_LOGW(...) DOM_CAMERA_LOGW(__VA_ARGS__) 1.30 +#define CS_LOGE(...) DOM_CAMERA_LOGE(__VA_ARGS__) 1.31 +*/ 1.32 + 1.33 +#define CS_LOGD(fmt, ...) DOM_CAMERA_LOGA("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) 1.34 +#define CS_LOGV(fmt, ...) DOM_CAMERA_LOGI("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) 1.35 +#define CS_LOGI(fmt, ...) DOM_CAMERA_LOGI("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) 1.36 +#define CS_LOGW(fmt, ...) DOM_CAMERA_LOGW("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) 1.37 +#define CS_LOGE(fmt, ...) DOM_CAMERA_LOGE("[%s:%d]" fmt,__FILE__,__LINE__, ## __VA_ARGS__) 1.38 + 1.39 +#include <OMX_Component.h> 1.40 +#include <binder/IPCThreadState.h> 1.41 +#include <media/stagefright/foundation/ADebug.h> 1.42 +#include <media/stagefright/MediaDefs.h> 1.43 +#include <media/stagefright/MediaErrors.h> 1.44 +#include <media/stagefright/MetaData.h> 1.45 +#include <camera/CameraParameters.h> 1.46 +#include <utils/String8.h> 1.47 +#include <cutils/properties.h> 1.48 + 1.49 +#include "GonkCameraSource.h" 1.50 +#include "GonkCameraListener.h" 1.51 +#include "GonkCameraHwMgr.h" 1.52 + 1.53 +using namespace mozilla; 1.54 + 1.55 +namespace android { 1.56 + 1.57 +static const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL; 1.58 + 1.59 +struct GonkCameraSourceListener : public GonkCameraListener { 1.60 + GonkCameraSourceListener(const sp<GonkCameraSource> &source); 1.61 + 1.62 + virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); 1.63 + virtual void postData(int32_t msgType, const sp<IMemory> &dataPtr, 1.64 + camera_frame_metadata_t *metadata); 1.65 + 1.66 + virtual void postDataTimestamp( 1.67 + nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr); 1.68 + 1.69 +protected: 1.70 + virtual ~GonkCameraSourceListener(); 1.71 + 1.72 +private: 1.73 + wp<GonkCameraSource> mSource; 1.74 + 1.75 + GonkCameraSourceListener(const GonkCameraSourceListener &); 1.76 + GonkCameraSourceListener &operator=(const GonkCameraSourceListener &); 1.77 +}; 1.78 + 1.79 +GonkCameraSourceListener::GonkCameraSourceListener(const sp<GonkCameraSource> &source) 1.80 + : mSource(source) { 1.81 +} 1.82 + 1.83 +GonkCameraSourceListener::~GonkCameraSourceListener() { 1.84 +} 1.85 + 1.86 +void GonkCameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) { 1.87 + CS_LOGV("notify(%d, %d, %d)", msgType, ext1, ext2); 1.88 +} 1.89 + 1.90 +void GonkCameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr, 1.91 + camera_frame_metadata_t *metadata) { 1.92 + CS_LOGV("postData(%d, ptr:%p, size:%d)", 1.93 + msgType, dataPtr->pointer(), dataPtr->size()); 1.94 + 1.95 + sp<GonkCameraSource> source = mSource.promote(); 1.96 + if (source.get() != NULL) { 1.97 + source->dataCallback(msgType, dataPtr); 1.98 + } 1.99 +} 1.100 + 1.101 +void GonkCameraSourceListener::postDataTimestamp( 1.102 + nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) { 1.103 + 1.104 + sp<GonkCameraSource> source = mSource.promote(); 1.105 + if (source.get() != NULL) { 1.106 + source->dataCallbackTimestamp(timestamp/1000, msgType, dataPtr); 1.107 + } 1.108 +} 1.109 + 1.110 +static int32_t getColorFormat(const char* colorFormat) { 1.111 + return OMX_COLOR_FormatYUV420SemiPlanar; //XXX nsGonkCameraControl uses only YUV420SemiPlanar 1.112 + 1.113 + if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) { 1.114 + return OMX_COLOR_FormatYUV420Planar; 1.115 + } 1.116 + 1.117 + if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422SP)) { 1.118 + return OMX_COLOR_FormatYUV422SemiPlanar; 1.119 + } 1.120 + 1.121 + if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) { 1.122 + return OMX_COLOR_FormatYUV420SemiPlanar; 1.123 + } 1.124 + 1.125 + if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422I)) { 1.126 + return OMX_COLOR_FormatYCbYCr; 1.127 + } 1.128 + 1.129 + if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_RGB565)) { 1.130 + return OMX_COLOR_Format16bitRGB565; 1.131 + } 1.132 + 1.133 + if (!strcmp(colorFormat, "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar")) { 1.134 + return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar; 1.135 + } 1.136 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 1.137 + if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE)) { 1.138 + return OMX_COLOR_FormatAndroidOpaque; 1.139 + } 1.140 +#endif 1.141 + CS_LOGE("Uknown color format (%s), please add it to " 1.142 + "GonkCameraSource::getColorFormat", colorFormat); 1.143 + 1.144 + CHECK(!"Unknown color format"); 1.145 +} 1.146 + 1.147 +GonkCameraSource *GonkCameraSource::Create( 1.148 + const sp<GonkCameraHardware>& aCameraHw, 1.149 + Size videoSize, 1.150 + int32_t frameRate, 1.151 + bool storeMetaDataInVideoBuffers) { 1.152 + 1.153 + GonkCameraSource *source = new GonkCameraSource(aCameraHw, 1.154 + videoSize, frameRate, 1.155 + storeMetaDataInVideoBuffers); 1.156 + return source; 1.157 +} 1.158 + 1.159 +GonkCameraSource::GonkCameraSource( 1.160 + const sp<GonkCameraHardware>& aCameraHw, 1.161 + Size videoSize, 1.162 + int32_t frameRate, 1.163 + bool storeMetaDataInVideoBuffers) 1.164 + : mCameraFlags(0), 1.165 + mNumInputBuffers(0), 1.166 + mVideoFrameRate(-1), 1.167 + mNumFramesReceived(0), 1.168 + mLastFrameTimestampUs(0), 1.169 + mStarted(false), 1.170 + mNumFramesEncoded(0), 1.171 + mTimeBetweenFrameCaptureUs(0), 1.172 + mFirstFrameTimeUs(0), 1.173 + mNumFramesDropped(0), 1.174 + mNumGlitches(0), 1.175 + mGlitchDurationThresholdUs(200000), 1.176 + mCollectStats(false), 1.177 + mCameraHw(aCameraHw) { 1.178 + mVideoSize.width = -1; 1.179 + mVideoSize.height = -1; 1.180 + 1.181 + mInitCheck = init( 1.182 + videoSize, frameRate, 1.183 + storeMetaDataInVideoBuffers); 1.184 + if (mInitCheck != OK) releaseCamera(); 1.185 +} 1.186 + 1.187 +status_t GonkCameraSource::initCheck() const { 1.188 + return mInitCheck; 1.189 +} 1.190 + 1.191 +//TODO: Do we need to reimplement isCameraAvailable? 1.192 + 1.193 +/* 1.194 + * Check to see whether the requested video width and height is one 1.195 + * of the supported sizes. 1.196 + * @param width the video frame width in pixels 1.197 + * @param height the video frame height in pixels 1.198 + * @param suppportedSizes the vector of sizes that we check against 1.199 + * @return true if the dimension (width and height) is supported. 1.200 + */ 1.201 +static bool isVideoSizeSupported( 1.202 + int32_t width, int32_t height, 1.203 + const Vector<Size>& supportedSizes) { 1.204 + 1.205 + CS_LOGV("isVideoSizeSupported"); 1.206 + for (size_t i = 0; i < supportedSizes.size(); ++i) { 1.207 + if (width == supportedSizes[i].width && 1.208 + height == supportedSizes[i].height) { 1.209 + return true; 1.210 + } 1.211 + } 1.212 + return false; 1.213 +} 1.214 + 1.215 +/* 1.216 + * If the preview and video output is separate, we only set the 1.217 + * the video size, and applications should set the preview size 1.218 + * to some proper value, and the recording framework will not 1.219 + * change the preview size; otherwise, if the video and preview 1.220 + * output is the same, we need to set the preview to be the same 1.221 + * as the requested video size. 1.222 + * 1.223 + */ 1.224 +/* 1.225 + * Query the camera to retrieve the supported video frame sizes 1.226 + * and also to see whether CameraParameters::setVideoSize() 1.227 + * is supported or not. 1.228 + * @param params CameraParameters to retrieve the information 1.229 + * @@param isSetVideoSizeSupported retunrs whether method 1.230 + * CameraParameters::setVideoSize() is supported or not. 1.231 + * @param sizes returns the vector of Size objects for the 1.232 + * supported video frame sizes advertised by the camera. 1.233 + */ 1.234 +static void getSupportedVideoSizes( 1.235 + const CameraParameters& params, 1.236 + bool *isSetVideoSizeSupported, 1.237 + Vector<Size>& sizes) { 1.238 + 1.239 + *isSetVideoSizeSupported = true; 1.240 + params.getSupportedVideoSizes(sizes); 1.241 + if (sizes.size() == 0) { 1.242 + CS_LOGD("Camera does not support setVideoSize()"); 1.243 + params.getSupportedPreviewSizes(sizes); 1.244 + *isSetVideoSizeSupported = false; 1.245 + } 1.246 +} 1.247 + 1.248 +/* 1.249 + * Check whether the camera has the supported color format 1.250 + * @param params CameraParameters to retrieve the information 1.251 + * @return OK if no error. 1.252 + */ 1.253 +status_t GonkCameraSource::isCameraColorFormatSupported( 1.254 + const CameraParameters& params) { 1.255 + mColorFormat = getColorFormat(params.get( 1.256 + CameraParameters::KEY_VIDEO_FRAME_FORMAT)); 1.257 + if (mColorFormat == -1) { 1.258 + return BAD_VALUE; 1.259 + } 1.260 + return OK; 1.261 +} 1.262 + 1.263 +/* 1.264 + * Configure the camera to use the requested video size 1.265 + * (width and height) and/or frame rate. If both width and 1.266 + * height are -1, configuration on the video size is skipped. 1.267 + * if frameRate is -1, configuration on the frame rate 1.268 + * is skipped. Skipping the configuration allows one to 1.269 + * use the current camera setting without the need to 1.270 + * actually know the specific values (see Create() method). 1.271 + * 1.272 + * @param params the CameraParameters to be configured 1.273 + * @param width the target video frame width in pixels 1.274 + * @param height the target video frame height in pixels 1.275 + * @param frameRate the target frame rate in frames per second. 1.276 + * @return OK if no error. 1.277 + */ 1.278 +status_t GonkCameraSource::configureCamera( 1.279 + CameraParameters* params, 1.280 + int32_t width, int32_t height, 1.281 + int32_t frameRate) { 1.282 + CS_LOGV("configureCamera"); 1.283 + Vector<Size> sizes; 1.284 + bool isSetVideoSizeSupportedByCamera = true; 1.285 + getSupportedVideoSizes(*params, &isSetVideoSizeSupportedByCamera, sizes); 1.286 + bool isCameraParamChanged = false; 1.287 + if (width != -1 && height != -1) { 1.288 + if (!isVideoSizeSupported(width, height, sizes)) { 1.289 + CS_LOGE("Video dimension (%dx%d) is unsupported", width, height); 1.290 + return BAD_VALUE; 1.291 + } 1.292 + if (isSetVideoSizeSupportedByCamera) { 1.293 + params->setVideoSize(width, height); 1.294 + } else { 1.295 + params->setPreviewSize(width, height); 1.296 + } 1.297 + isCameraParamChanged = true; 1.298 + } else if ((width == -1 && height != -1) || 1.299 + (width != -1 && height == -1)) { 1.300 + // If one and only one of the width and height is -1 1.301 + // we reject such a request. 1.302 + CS_LOGE("Requested video size (%dx%d) is not supported", width, height); 1.303 + return BAD_VALUE; 1.304 + } else { // width == -1 && height == -1 1.305 + // Do not configure the camera. 1.306 + // Use the current width and height value setting from the camera. 1.307 + } 1.308 + 1.309 + if (frameRate != -1) { 1.310 + CHECK(frameRate > 0 && frameRate <= 120); 1.311 + const char* supportedFrameRates = 1.312 + params->get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES); 1.313 + CHECK(supportedFrameRates != NULL); 1.314 + CS_LOGV("Supported frame rates: %s", supportedFrameRates); 1.315 + char buf[4]; 1.316 + snprintf(buf, 4, "%d", frameRate); 1.317 + if (strstr(supportedFrameRates, buf) == NULL) { 1.318 + CS_LOGE("Requested frame rate (%d) is not supported: %s", 1.319 + frameRate, supportedFrameRates); 1.320 + return BAD_VALUE; 1.321 + } 1.322 + 1.323 + // The frame rate is supported, set the camera to the requested value. 1.324 + params->setPreviewFrameRate(frameRate); 1.325 + isCameraParamChanged = true; 1.326 + } else { // frameRate == -1 1.327 + // Do not configure the camera. 1.328 + // Use the current frame rate value setting from the camera 1.329 + } 1.330 + 1.331 + if (isCameraParamChanged) { 1.332 + // Either frame rate or frame size needs to be changed. 1.333 + if (OK != mCameraHw->PushParameters(*params)) { 1.334 + CS_LOGE("Could not change settings." 1.335 + " Someone else is using camera?"); 1.336 + return -EBUSY; 1.337 + } 1.338 + } 1.339 + return OK; 1.340 +} 1.341 + 1.342 +/* 1.343 + * Check whether the requested video frame size 1.344 + * has been successfully configured or not. If both width and height 1.345 + * are -1, check on the current width and height value setting 1.346 + * is performed. 1.347 + * 1.348 + * @param params CameraParameters to retrieve the information 1.349 + * @param the target video frame width in pixels to check against 1.350 + * @param the target video frame height in pixels to check against 1.351 + * @return OK if no error 1.352 + */ 1.353 +status_t GonkCameraSource::checkVideoSize( 1.354 + const CameraParameters& params, 1.355 + int32_t width, int32_t height) { 1.356 + 1.357 + CS_LOGV("checkVideoSize"); 1.358 + // The actual video size is the same as the preview size 1.359 + // if the camera hal does not support separate video and 1.360 + // preview output. In this case, we retrieve the video 1.361 + // size from preview. 1.362 + int32_t frameWidthActual = -1; 1.363 + int32_t frameHeightActual = -1; 1.364 + Vector<Size> sizes; 1.365 + params.getSupportedVideoSizes(sizes); 1.366 + if (sizes.size() == 0) { 1.367 + // video size is the same as preview size 1.368 + params.getPreviewSize(&frameWidthActual, &frameHeightActual); 1.369 + } else { 1.370 + // video size may not be the same as preview 1.371 + params.getVideoSize(&frameWidthActual, &frameHeightActual); 1.372 + } 1.373 + if (frameWidthActual < 0 || frameHeightActual < 0) { 1.374 + CS_LOGE("Failed to retrieve video frame size (%dx%d)", 1.375 + frameWidthActual, frameHeightActual); 1.376 + return UNKNOWN_ERROR; 1.377 + } 1.378 + 1.379 + // Check the actual video frame size against the target/requested 1.380 + // video frame size. 1.381 + if (width != -1 && height != -1) { 1.382 + if (frameWidthActual != width || frameHeightActual != height) { 1.383 + CS_LOGE("Failed to set video frame size to %dx%d. " 1.384 + "The actual video size is %dx%d ", width, height, 1.385 + frameWidthActual, frameHeightActual); 1.386 + return UNKNOWN_ERROR; 1.387 + } 1.388 + } 1.389 + 1.390 + // Good now. 1.391 + mVideoSize.width = frameWidthActual; 1.392 + mVideoSize.height = frameHeightActual; 1.393 + return OK; 1.394 +} 1.395 + 1.396 +/* 1.397 + * Check the requested frame rate has been successfully configured or not. 1.398 + * If the target frameRate is -1, check on the current frame rate value 1.399 + * setting is performed. 1.400 + * 1.401 + * @param params CameraParameters to retrieve the information 1.402 + * @param the target video frame rate to check against 1.403 + * @return OK if no error. 1.404 + */ 1.405 +status_t GonkCameraSource::checkFrameRate( 1.406 + const CameraParameters& params, 1.407 + int32_t frameRate) { 1.408 + 1.409 + CS_LOGV("checkFrameRate"); 1.410 + int32_t frameRateActual = params.getPreviewFrameRate(); 1.411 + if (frameRateActual < 0) { 1.412 + CS_LOGE("Failed to retrieve preview frame rate (%d)", frameRateActual); 1.413 + return UNKNOWN_ERROR; 1.414 + } 1.415 + 1.416 + // Check the actual video frame rate against the target/requested 1.417 + // video frame rate. 1.418 + if (frameRate != -1 && (frameRateActual - frameRate) != 0) { 1.419 + CS_LOGE("Failed to set preview frame rate to %d fps. The actual " 1.420 + "frame rate is %d", frameRate, frameRateActual); 1.421 + return UNKNOWN_ERROR; 1.422 + } 1.423 + 1.424 + // Good now. 1.425 + mVideoFrameRate = frameRateActual; 1.426 + return OK; 1.427 +} 1.428 + 1.429 +/* 1.430 + * Initialize the GonkCameraSource so that it becomes 1.431 + * ready for providing the video input streams as requested. 1.432 + * @param camera the camera object used for the video source 1.433 + * @param cameraId if camera == 0, use camera with this id 1.434 + * as the video source 1.435 + * @param videoSize the target video frame size. If both 1.436 + * width and height in videoSize is -1, use the current 1.437 + * width and heigth settings by the camera 1.438 + * @param frameRate the target frame rate in frames per second. 1.439 + * if it is -1, use the current camera frame rate setting. 1.440 + * @param storeMetaDataInVideoBuffers request to store meta 1.441 + * data or real YUV data in video buffers. Request to 1.442 + * store meta data in video buffers may not be honored 1.443 + * if the source does not support this feature. 1.444 + * 1.445 + * @return OK if no error. 1.446 + */ 1.447 +status_t GonkCameraSource::init( 1.448 + Size videoSize, 1.449 + int32_t frameRate, 1.450 + bool storeMetaDataInVideoBuffers) { 1.451 + 1.452 + CS_LOGV("init"); 1.453 + status_t err = OK; 1.454 + //TODO: need to do something here to check the sanity of camera 1.455 + 1.456 + CameraParameters params; 1.457 + mCameraHw->PullParameters(params); 1.458 + if ((err = isCameraColorFormatSupported(params)) != OK) { 1.459 + return err; 1.460 + } 1.461 + 1.462 + // Set the camera to use the requested video frame size 1.463 + // and/or frame rate. 1.464 + if ((err = configureCamera(¶ms, 1.465 + videoSize.width, videoSize.height, 1.466 + frameRate))) { 1.467 + return err; 1.468 + } 1.469 + 1.470 + // Check on video frame size and frame rate. 1.471 + CameraParameters newCameraParams; 1.472 + mCameraHw->PullParameters(newCameraParams); 1.473 + if ((err = checkVideoSize(newCameraParams, 1.474 + videoSize.width, videoSize.height)) != OK) { 1.475 + return err; 1.476 + } 1.477 + if ((err = checkFrameRate(newCameraParams, frameRate)) != OK) { 1.478 + return err; 1.479 + } 1.480 + 1.481 + // By default, do not store metadata in video buffers 1.482 + mIsMetaDataStoredInVideoBuffers = false; 1.483 + mCameraHw->StoreMetaDataInBuffers(false); 1.484 + if (storeMetaDataInVideoBuffers) { 1.485 + if (OK == mCameraHw->StoreMetaDataInBuffers(true)) { 1.486 + mIsMetaDataStoredInVideoBuffers = true; 1.487 + } 1.488 + } 1.489 + 1.490 + int64_t glitchDurationUs = (1000000LL / mVideoFrameRate); 1.491 + if (glitchDurationUs > mGlitchDurationThresholdUs) { 1.492 + mGlitchDurationThresholdUs = glitchDurationUs; 1.493 + } 1.494 + 1.495 + // XXX: query camera for the stride and slice height 1.496 + // when the capability becomes available. 1.497 + mMeta = new MetaData; 1.498 + mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); 1.499 + mMeta->setInt32(kKeyColorFormat, mColorFormat); 1.500 + mMeta->setInt32(kKeyWidth, mVideoSize.width); 1.501 + mMeta->setInt32(kKeyHeight, mVideoSize.height); 1.502 + mMeta->setInt32(kKeyStride, mVideoSize.width); 1.503 + mMeta->setInt32(kKeySliceHeight, mVideoSize.height); 1.504 + mMeta->setInt32(kKeyFrameRate, mVideoFrameRate); 1.505 + return OK; 1.506 +} 1.507 + 1.508 +GonkCameraSource::~GonkCameraSource() { 1.509 + if (mStarted) { 1.510 + reset(); 1.511 + } else if (mInitCheck == OK) { 1.512 + // Camera is initialized but because start() is never called, 1.513 + // the lock on Camera is never released(). This makes sure 1.514 + // Camera's lock is released in this case. 1.515 + // TODO: Don't think I need to do this 1.516 + releaseCamera(); 1.517 + } 1.518 +} 1.519 + 1.520 +int GonkCameraSource::startCameraRecording() { 1.521 + CS_LOGV("startCameraRecording"); 1.522 + return mCameraHw->StartRecording(); 1.523 +} 1.524 + 1.525 +status_t GonkCameraSource::start(MetaData *meta) { 1.526 + int rv; 1.527 + 1.528 + CS_LOGV("start"); 1.529 + CHECK(!mStarted); 1.530 + if (mInitCheck != OK) { 1.531 + CS_LOGE("GonkCameraSource is not initialized yet"); 1.532 + return mInitCheck; 1.533 + } 1.534 + 1.535 + char value[PROPERTY_VALUE_MAX]; 1.536 + if (property_get("media.stagefright.record-stats", value, NULL) 1.537 + && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { 1.538 + mCollectStats = true; 1.539 + } 1.540 + 1.541 + mStartTimeUs = 0; 1.542 + mNumInputBuffers = 0; 1.543 + if (meta) { 1.544 + int64_t startTimeUs; 1.545 + if (meta->findInt64(kKeyTime, &startTimeUs)) { 1.546 + mStartTimeUs = startTimeUs; 1.547 + } 1.548 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 1.549 + int32_t nBuffers; 1.550 + if (meta->findInt32(kKeyNumBuffers, &nBuffers)) { 1.551 + CHECK_GT(nBuffers, 0); 1.552 + mNumInputBuffers = nBuffers; 1.553 + } 1.554 +#endif 1.555 + } 1.556 + 1.557 + // Register a listener with GonkCameraHardware so that we can get callbacks 1.558 + mCameraHw->SetListener(new GonkCameraSourceListener(this)); 1.559 + 1.560 + rv = startCameraRecording(); 1.561 + 1.562 + mStarted = (rv == OK); 1.563 + return rv; 1.564 +} 1.565 + 1.566 +void GonkCameraSource::stopCameraRecording() { 1.567 + CS_LOGV("stopCameraRecording"); 1.568 + mCameraHw->StopRecording(); 1.569 +} 1.570 + 1.571 +void GonkCameraSource::releaseCamera() { 1.572 + CS_LOGV("releaseCamera"); 1.573 +} 1.574 + 1.575 +status_t GonkCameraSource::reset() { 1.576 + CS_LOGD("reset: E"); 1.577 + Mutex::Autolock autoLock(mLock); 1.578 + mStarted = false; 1.579 + mFrameAvailableCondition.signal(); 1.580 + 1.581 + releaseQueuedFrames(); 1.582 + while (!mFramesBeingEncoded.empty()) { 1.583 + if (NO_ERROR != 1.584 + mFrameCompleteCondition.waitRelative(mLock, 1.585 + mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) { 1.586 + CS_LOGW("Timed out waiting for outstanding frames being encoded: %d", 1.587 + mFramesBeingEncoded.size()); 1.588 + } 1.589 + } 1.590 + stopCameraRecording(); 1.591 + releaseCamera(); 1.592 + 1.593 + if (mCollectStats) { 1.594 + CS_LOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us", 1.595 + mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped, 1.596 + mLastFrameTimestampUs - mFirstFrameTimeUs); 1.597 + } 1.598 + 1.599 + if (mNumGlitches > 0) { 1.600 + CS_LOGW("%d long delays between neighboring video frames", mNumGlitches); 1.601 + } 1.602 + 1.603 + CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped); 1.604 + CS_LOGD("reset: X"); 1.605 + return OK; 1.606 +} 1.607 + 1.608 +void GonkCameraSource::releaseRecordingFrame(const sp<IMemory>& frame) { 1.609 + CS_LOGV("releaseRecordingFrame"); 1.610 + mCameraHw->ReleaseRecordingFrame(frame); 1.611 +} 1.612 + 1.613 +void GonkCameraSource::releaseQueuedFrames() { 1.614 + List<sp<IMemory> >::iterator it; 1.615 + while (!mFramesReceived.empty()) { 1.616 + it = mFramesReceived.begin(); 1.617 + releaseRecordingFrame(*it); 1.618 + mFramesReceived.erase(it); 1.619 + ++mNumFramesDropped; 1.620 + } 1.621 +} 1.622 + 1.623 +sp<MetaData> GonkCameraSource::getFormat() { 1.624 + return mMeta; 1.625 +} 1.626 + 1.627 +void GonkCameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) { 1.628 + releaseRecordingFrame(frame); 1.629 +} 1.630 + 1.631 +void GonkCameraSource::signalBufferReturned(MediaBuffer *buffer) { 1.632 + CS_LOGV("signalBufferReturned: %p", buffer->data()); 1.633 + Mutex::Autolock autoLock(mLock); 1.634 + for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin(); 1.635 + it != mFramesBeingEncoded.end(); ++it) { 1.636 + if ((*it)->pointer() == buffer->data()) { 1.637 + releaseOneRecordingFrame((*it)); 1.638 + mFramesBeingEncoded.erase(it); 1.639 + ++mNumFramesEncoded; 1.640 + buffer->setObserver(0); 1.641 + buffer->release(); 1.642 + mFrameCompleteCondition.signal(); 1.643 + return; 1.644 + } 1.645 + } 1.646 + CHECK(!"signalBufferReturned: bogus buffer"); 1.647 +} 1.648 + 1.649 +status_t GonkCameraSource::read( 1.650 + MediaBuffer **buffer, const ReadOptions *options) { 1.651 + CS_LOGV("read"); 1.652 + 1.653 + *buffer = NULL; 1.654 + 1.655 + int64_t seekTimeUs; 1.656 + ReadOptions::SeekMode mode; 1.657 + if (options && options->getSeekTo(&seekTimeUs, &mode)) { 1.658 + return ERROR_UNSUPPORTED; 1.659 + } 1.660 + 1.661 + sp<IMemory> frame; 1.662 + int64_t frameTime; 1.663 + 1.664 + { 1.665 + Mutex::Autolock autoLock(mLock); 1.666 + while (mStarted && mFramesReceived.empty()) { 1.667 + if (NO_ERROR != 1.668 + mFrameAvailableCondition.waitRelative(mLock, 1.669 + mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) { 1.670 + //TODO: check sanity of camera? 1.671 + CS_LOGW("Timed out waiting for incoming camera video frames: %lld us", 1.672 + mLastFrameTimestampUs); 1.673 + } 1.674 + } 1.675 + if (!mStarted) { 1.676 + return OK; 1.677 + } 1.678 + frame = *mFramesReceived.begin(); 1.679 + mFramesReceived.erase(mFramesReceived.begin()); 1.680 + 1.681 + frameTime = *mFrameTimes.begin(); 1.682 + mFrameTimes.erase(mFrameTimes.begin()); 1.683 + mFramesBeingEncoded.push_back(frame); 1.684 + *buffer = new MediaBuffer(frame->pointer(), frame->size()); 1.685 + (*buffer)->setObserver(this); 1.686 + (*buffer)->add_ref(); 1.687 + (*buffer)->meta_data()->setInt64(kKeyTime, frameTime); 1.688 + } 1.689 + return OK; 1.690 +} 1.691 + 1.692 +void GonkCameraSource::dataCallbackTimestamp(int64_t timestampUs, 1.693 + int32_t msgType, const sp<IMemory> &data) { 1.694 + CS_LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs); 1.695 + Mutex::Autolock autoLock(mLock); 1.696 + if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) { 1.697 + CS_LOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs); 1.698 + releaseOneRecordingFrame(data); 1.699 + return; 1.700 + } 1.701 + 1.702 + if (mNumFramesReceived > 0) { 1.703 + CHECK(timestampUs > mLastFrameTimestampUs); 1.704 + if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) { 1.705 + ++mNumGlitches; 1.706 + } 1.707 + } 1.708 + 1.709 + // May need to skip frame or modify timestamp. Currently implemented 1.710 + // by the subclass CameraSourceTimeLapse. 1.711 + if (skipCurrentFrame(timestampUs)) { 1.712 + releaseOneRecordingFrame(data); 1.713 + return; 1.714 + } 1.715 + 1.716 + mLastFrameTimestampUs = timestampUs; 1.717 + if (mNumFramesReceived == 0) { 1.718 + mFirstFrameTimeUs = timestampUs; 1.719 + // Initial delay 1.720 + if (mStartTimeUs > 0) { 1.721 + if (timestampUs < mStartTimeUs) { 1.722 + // Frame was captured before recording was started 1.723 + // Drop it without updating the statistical data. 1.724 + releaseOneRecordingFrame(data); 1.725 + return; 1.726 + } 1.727 + mStartTimeUs = timestampUs - mStartTimeUs; 1.728 + } 1.729 + } 1.730 + ++mNumFramesReceived; 1.731 + 1.732 + CHECK(data != NULL && data->size() > 0); 1.733 + mFramesReceived.push_back(data); 1.734 + int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs); 1.735 + mFrameTimes.push_back(timeUs); 1.736 + CS_LOGV("initial delay: %lld, current time stamp: %lld", 1.737 + mStartTimeUs, timeUs); 1.738 + mFrameAvailableCondition.signal(); 1.739 +} 1.740 + 1.741 +bool GonkCameraSource::isMetaDataStoredInVideoBuffers() const { 1.742 + CS_LOGV("isMetaDataStoredInVideoBuffers"); 1.743 + return mIsMetaDataStoredInVideoBuffers; 1.744 +} 1.745 + 1.746 +} // namespace android