dom/camera/GonkCameraSource.cpp

changeset 0
6474c204b198
     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(&params,
   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

mercurial