120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber/*
220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Copyright (C) 2009 The Android Open Source Project
320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber *
420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * you may not use this file except in compliance with the License.
620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * You may obtain a copy of the License at
720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber *
820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber *
1020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Unless required by applicable law or agreed to in writing, software
1120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
1220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * See the License for the specific language governing permissions and
1420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * limitations under the License.
1520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber */
1620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
17c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong//#define LOG_NDEBUG 0
18c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong#define LOG_TAG "CameraSource"
19c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong#include <utils/Log.h>
2020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <OMX_Component.h>
229d7f58a7da8502a4174a17ac49fcba6efa35a457James Dong#include <binder/IPCThreadState.h>
23f1d5aa162c02a16b7195a43a9bcea4d592600ac4James Dong#include <media/stagefright/foundation/ADebug.h>
2420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/CameraSource.h>
25be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber#include <media/stagefright/MediaDefs.h>
2620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaErrors.h>
2720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h>
283cf613507f1e2f7bd932d921a6e222e426fd3be4Mathias Agopian#include <camera/Camera.h>
293cf613507f1e2f7bd932d921a6e222e426fd3be4Mathias Agopian#include <camera/CameraParameters.h>
30df712ea86e6350f7005a02ab0e1c60c28a343ed0Mathias Agopian#include <gui/Surface.h>
31be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber#include <utils/String8.h>
32365a963142093a1cd8efdcea76b5f65096a5b115James Dong#include <cutils/properties.h>
3320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android {
3520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
36e8e5f86e9e310b065596c8cbbca1543eb833dee1James Dongstatic const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL;
37e8e5f86e9e310b065596c8cbbca1543eb833dee1James Dong
38be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huberstruct CameraSourceListener : public CameraListener {
39be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber    CameraSourceListener(const sp<CameraSource> &source);
40be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber
41be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber    virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
4257c86189bc07d9ccb0fd044e66df736d0bf19639Wu-cheng Li    virtual void postData(int32_t msgType, const sp<IMemory> &dataPtr,
4357c86189bc07d9ccb0fd044e66df736d0bf19639Wu-cheng Li                          camera_frame_metadata_t *metadata);
44be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber
45be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber    virtual void postDataTimestamp(
46be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber            nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
47be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber
48be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huberprotected:
49be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber    virtual ~CameraSourceListener();
50be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber
5120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate:
52be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber    wp<CameraSource> mSource;
53be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber
54be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber    CameraSourceListener(const CameraSourceListener &);
55be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber    CameraSourceListener &operator=(const CameraSourceListener &);
5620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber};
5720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
58be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas HuberCameraSourceListener::CameraSourceListener(const sp<CameraSource> &source)
59be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber    : mSource(source) {
60be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber}
6120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
62be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas HuberCameraSourceListener::~CameraSourceListener() {
63be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber}
6420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
65be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Hubervoid CameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
663856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
67be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber}
6820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6957c86189bc07d9ccb0fd044e66df736d0bf19639Wu-cheng Livoid CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr,
7057c86189bc07d9ccb0fd044e66df736d0bf19639Wu-cheng Li                                    camera_frame_metadata_t *metadata) {
713856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("postData(%d, ptr:%p, size:%d)",
72be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber         msgType, dataPtr->pointer(), dataPtr->size());
7365e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra
7465e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra    sp<CameraSource> source = mSource.promote();
7565e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra    if (source.get() != NULL) {
7665e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra        source->dataCallback(msgType, dataPtr);
7765e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra    }
78be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber}
79be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber
80be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Hubervoid CameraSourceListener::postDataTimestamp(
81be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber        nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
82c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong
83c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    sp<CameraSource> source = mSource.promote();
84c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    if (source.get() != NULL) {
85c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong        source->dataCallbackTimestamp(timestamp/1000, msgType, dataPtr);
86c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    }
87be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber}
8820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
89653252be963c07c99109d20f942d1f30c52a9360James Dongstatic int32_t getColorFormat(const char* colorFormat) {
90e2d8ba8c36fd39eb98f604b11654aa5466673260James Dong    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) {
91e2d8ba8c36fd39eb98f604b11654aa5466673260James Dong       return OMX_COLOR_FormatYUV420Planar;
92e2d8ba8c36fd39eb98f604b11654aa5466673260James Dong    }
93e2d8ba8c36fd39eb98f604b11654aa5466673260James Dong
94653252be963c07c99109d20f942d1f30c52a9360James Dong    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422SP)) {
95653252be963c07c99109d20f942d1f30c52a9360James Dong       return OMX_COLOR_FormatYUV422SemiPlanar;
96653252be963c07c99109d20f942d1f30c52a9360James Dong    }
97653252be963c07c99109d20f942d1f30c52a9360James Dong
98653252be963c07c99109d20f942d1f30c52a9360James Dong    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) {
99653252be963c07c99109d20f942d1f30c52a9360James Dong        return OMX_COLOR_FormatYUV420SemiPlanar;
100653252be963c07c99109d20f942d1f30c52a9360James Dong    }
101653252be963c07c99109d20f942d1f30c52a9360James Dong
102653252be963c07c99109d20f942d1f30c52a9360James Dong    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422I)) {
103653252be963c07c99109d20f942d1f30c52a9360James Dong        return OMX_COLOR_FormatYCbYCr;
104653252be963c07c99109d20f942d1f30c52a9360James Dong    }
105653252be963c07c99109d20f942d1f30c52a9360James Dong
106653252be963c07c99109d20f942d1f30c52a9360James Dong    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_RGB565)) {
107653252be963c07c99109d20f942d1f30c52a9360James Dong       return OMX_COLOR_Format16bitRGB565;
108653252be963c07c99109d20f942d1f30c52a9360James Dong    }
109653252be963c07c99109d20f942d1f30c52a9360James Dong
1101374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket    if (!strcmp(colorFormat, "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar")) {
1111374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket       return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar;
1121374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket    }
1131374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket
114bf5bea96f236adb5eef78c2f414ef82b3602a0f7Eino-Ville Talvala    if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE)) {
115bf5bea96f236adb5eef78c2f414ef82b3602a0f7Eino-Ville Talvala        return OMX_COLOR_FormatAndroidOpaque;
116bf5bea96f236adb5eef78c2f414ef82b3602a0f7Eino-Ville Talvala    }
117bf5bea96f236adb5eef78c2f414ef82b3602a0f7Eino-Ville Talvala
11829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block    ALOGE("Uknown color format (%s), please add it to "
119a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong         "CameraSource::getColorFormat", colorFormat);
120a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong
121f1d5aa162c02a16b7195a43a9bcea4d592600ac4James Dong    CHECK(!"Unknown color format");
122653252be963c07c99109d20f942d1f30c52a9360James Dong}
123653252be963c07c99109d20f942d1f30c52a9360James Dong
124ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville TalvalaCameraSource *CameraSource::Create(const String16 &clientName) {
12554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    Size size;
12654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    size.width = -1;
12754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    size.height = -1;
12820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
12954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    sp<ICamera> camera;
130ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala    return new CameraSource(camera, NULL, 0, clientName, -1,
131ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala            size, -1, NULL, false);
13220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
13320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
13430ab66297501757d745b9ae10da61adcd891f497Andreas Huber// static
13554ff19ac69ace7c05ea90d225e26dab3b133f487James DongCameraSource *CameraSource::CreateFromCamera(
13654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    const sp<ICamera>& camera,
1374ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    const sp<ICameraRecordingProxy>& proxy,
13854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    int32_t cameraId,
139ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala    const String16& clientName,
140ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala    uid_t clientUid,
14154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    Size videoSize,
14254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    int32_t frameRate,
14399617adda9bc46c43f511f0940bc735c73de61deMathias Agopian    const sp<IGraphicBufferProducer>& surface,
1445c9523154d106b555db6c41f85ab205a4f189b02James Dong    bool storeMetaDataInVideoBuffers) {
14554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
1464ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    CameraSource *source = new CameraSource(camera, proxy, cameraId,
147ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala            clientName, clientUid, videoSize, frameRate, surface,
148ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala            storeMetaDataInVideoBuffers);
14954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    return source;
15030ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
15130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
15254ff19ac69ace7c05ea90d225e26dab3b133f487James DongCameraSource::CameraSource(
15354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    const sp<ICamera>& camera,
1544ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    const sp<ICameraRecordingProxy>& proxy,
15554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    int32_t cameraId,
156ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala    const String16& clientName,
157ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala    uid_t clientUid,
15854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    Size videoSize,
15954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    int32_t frameRate,
16099617adda9bc46c43f511f0940bc735c73de61deMathias Agopian    const sp<IGraphicBufferProducer>& surface,
1615c9523154d106b555db6c41f85ab205a4f189b02James Dong    bool storeMetaDataInVideoBuffers)
16254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    : mCameraFlags(0),
163983cf231ab2d176a14595cdae46ff1b0c239af47James Dong      mNumInputBuffers(0),
16454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong      mVideoFrameRate(-1),
16554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong      mCamera(0),
16654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong      mSurface(surface),
16713aec890216948b0c364f8f92792129d0335f506James Dong      mNumFramesReceived(0),
16865e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra      mLastFrameTimestampUs(0),
16965e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra      mStarted(false),
17013aec890216948b0c364f8f92792129d0335f506James Dong      mNumFramesEncoded(0),
171e8e5f86e9e310b065596c8cbbca1543eb833dee1James Dong      mTimeBetweenFrameCaptureUs(0),
1727757f5010a771fb8824b6fdf9788f588a1577e3fJames Dong      mFirstFrameTimeUs(0),
17313aec890216948b0c364f8f92792129d0335f506James Dong      mNumFramesDropped(0),
174f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong      mNumGlitches(0),
175f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong      mGlitchDurationThresholdUs(200000),
17665e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra      mCollectStats(false) {
17754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    mVideoSize.width  = -1;
17854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    mVideoSize.height = -1;
17954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
1804ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    mInitCheck = init(camera, proxy, cameraId,
181ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala                    clientName, clientUid,
1825c9523154d106b555db6c41f85ab205a4f189b02James Dong                    videoSize, frameRate,
1835c9523154d106b555db6c41f85ab205a4f189b02James Dong                    storeMetaDataInVideoBuffers);
18495068be1426dc0a4dc856cf9e35550c31b901711Wu-cheng Li    if (mInitCheck != OK) releaseCamera();
18554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong}
18654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
18754ff19ac69ace7c05ea90d225e26dab3b133f487James Dongstatus_t CameraSource::initCheck() const {
18854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    return mInitCheck;
18954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong}
19054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
19154ff19ac69ace7c05ea90d225e26dab3b133f487James Dongstatus_t CameraSource::isCameraAvailable(
1924ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
193ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala    int32_t cameraId, const String16& clientName, uid_t clientUid) {
19454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
19554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if (camera == 0) {
196ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala        mCamera = Camera::connect(cameraId, clientName, clientUid);
1974ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li        if (mCamera == 0) return -EBUSY;
19854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        mCameraFlags &= ~FLAGS_HOT_CAMERA;
19954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    } else {
2004ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li        // We get the proxy from Camera, not ICamera. We need to get the proxy
2014ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li        // to the remote Camera owned by the application. Here mCamera is a
2024ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li        // local Camera object created by us. We cannot use the proxy from
2034ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li        // mCamera here.
20454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        mCamera = Camera::create(camera);
2054ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li        if (mCamera == 0) return -EBUSY;
2064ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li        mCameraRecordingProxy = proxy;
20754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        mCameraFlags |= FLAGS_HOT_CAMERA;
2083bd3020c00ec8264ac1fe3870800f326487f9221James Dong        mDeathNotifier = new DeathNotifier();
2093bd3020c00ec8264ac1fe3870800f326487f9221James Dong        // isBinderAlive needs linkToDeath to work.
2103bd3020c00ec8264ac1fe3870800f326487f9221James Dong        mCameraRecordingProxy->asBinder()->linkToDeath(mDeathNotifier);
21154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
21254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
2134ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    mCamera->lock();
2144ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li
21554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    return OK;
21654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong}
21754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
21854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
21954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong/*
22054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * Check to see whether the requested video width and height is one
22154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * of the supported sizes.
22254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param width the video frame width in pixels
22354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param height the video frame height in pixels
22454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param suppportedSizes the vector of sizes that we check against
22554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @return true if the dimension (width and height) is supported.
22654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong */
22754ff19ac69ace7c05ea90d225e26dab3b133f487James Dongstatic bool isVideoSizeSupported(
22854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    int32_t width, int32_t height,
22954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    const Vector<Size>& supportedSizes) {
23054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
2313856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("isVideoSizeSupported");
23254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    for (size_t i = 0; i < supportedSizes.size(); ++i) {
23354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        if (width  == supportedSizes[i].width &&
23454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong            height == supportedSizes[i].height) {
23554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong            return true;
23654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        }
23754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
23854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    return false;
23954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong}
24054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
24154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong/*
24254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * If the preview and video output is separate, we only set the
24354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * the video size, and applications should set the preview size
24454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * to some proper value, and the recording framework will not
24554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * change the preview size; otherwise, if the video and preview
24654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * output is the same, we need to set the preview to be the same
24754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * as the requested video size.
24854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong *
24954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong */
25054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong/*
25154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * Query the camera to retrieve the supported video frame sizes
25254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * and also to see whether CameraParameters::setVideoSize()
25354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * is supported or not.
25454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param params CameraParameters to retrieve the information
25554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @@param isSetVideoSizeSupported retunrs whether method
25654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong *      CameraParameters::setVideoSize() is supported or not.
25754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param sizes returns the vector of Size objects for the
25854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong *      supported video frame sizes advertised by the camera.
25954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong */
26054ff19ac69ace7c05ea90d225e26dab3b133f487James Dongstatic void getSupportedVideoSizes(
26154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    const CameraParameters& params,
26254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    bool *isSetVideoSizeSupported,
26354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    Vector<Size>& sizes) {
26454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
26554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    *isSetVideoSizeSupported = true;
26654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    params.getSupportedVideoSizes(sizes);
26754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if (sizes.size() == 0) {
268b8a805261bf0282e992d3608035e47d05a898710Steve Block        ALOGD("Camera does not support setVideoSize()");
26954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        params.getSupportedPreviewSizes(sizes);
27054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        *isSetVideoSizeSupported = false;
27154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
27254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong}
27354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
27454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong/*
27554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * Check whether the camera has the supported color format
27654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param params CameraParameters to retrieve the information
27754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @return OK if no error.
27854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong */
27954ff19ac69ace7c05ea90d225e26dab3b133f487James Dongstatus_t CameraSource::isCameraColorFormatSupported(
28054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        const CameraParameters& params) {
28154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    mColorFormat = getColorFormat(params.get(
28254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong            CameraParameters::KEY_VIDEO_FRAME_FORMAT));
28354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if (mColorFormat == -1) {
28454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        return BAD_VALUE;
28554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
28654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    return OK;
28754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong}
28854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
28954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong/*
29054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * Configure the camera to use the requested video size
29154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * (width and height) and/or frame rate. If both width and
29254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * height are -1, configuration on the video size is skipped.
29354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * if frameRate is -1, configuration on the frame rate
29454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * is skipped. Skipping the configuration allows one to
29554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * use the current camera setting without the need to
29654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * actually know the specific values (see Create() method).
29754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong *
29854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param params the CameraParameters to be configured
29954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param width the target video frame width in pixels
30054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param height the target video frame height in pixels
30154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param frameRate the target frame rate in frames per second.
30254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @return OK if no error.
30354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong */
30454ff19ac69ace7c05ea90d225e26dab3b133f487James Dongstatus_t CameraSource::configureCamera(
30554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        CameraParameters* params,
30654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        int32_t width, int32_t height,
30754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        int32_t frameRate) {
3083856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("configureCamera");
30954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    Vector<Size> sizes;
31054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    bool isSetVideoSizeSupportedByCamera = true;
31154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    getSupportedVideoSizes(*params, &isSetVideoSizeSupportedByCamera, sizes);
31254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    bool isCameraParamChanged = false;
31354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if (width != -1 && height != -1) {
31454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        if (!isVideoSizeSupported(width, height, sizes)) {
31529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Video dimension (%dx%d) is unsupported", width, height);
31654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong            return BAD_VALUE;
31754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        }
31854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        if (isSetVideoSizeSupportedByCamera) {
31954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong            params->setVideoSize(width, height);
32054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        } else {
32154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong            params->setPreviewSize(width, height);
32254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        }
32354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        isCameraParamChanged = true;
32454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    } else if ((width == -1 && height != -1) ||
32554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong               (width != -1 && height == -1)) {
32654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        // If one and only one of the width and height is -1
32754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        // we reject such a request.
32829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Requested video size (%dx%d) is not supported", width, height);
32954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        return BAD_VALUE;
33054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    } else {  // width == -1 && height == -1
33154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        // Do not configure the camera.
33254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        // Use the current width and height value setting from the camera.
33354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
33454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
33554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if (frameRate != -1) {
336635730831e08c32a5fe7c59125e0919b7e7899cdJames Dong        CHECK(frameRate > 0 && frameRate <= 120);
337635730831e08c32a5fe7c59125e0919b7e7899cdJames Dong        const char* supportedFrameRates =
338635730831e08c32a5fe7c59125e0919b7e7899cdJames Dong                params->get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES);
339635730831e08c32a5fe7c59125e0919b7e7899cdJames Dong        CHECK(supportedFrameRates != NULL);
3403856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("Supported frame rates: %s", supportedFrameRates);
341635730831e08c32a5fe7c59125e0919b7e7899cdJames Dong        char buf[4];
342635730831e08c32a5fe7c59125e0919b7e7899cdJames Dong        snprintf(buf, 4, "%d", frameRate);
343635730831e08c32a5fe7c59125e0919b7e7899cdJames Dong        if (strstr(supportedFrameRates, buf) == NULL) {
34429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Requested frame rate (%d) is not supported: %s",
345635730831e08c32a5fe7c59125e0919b7e7899cdJames Dong                frameRate, supportedFrameRates);
346635730831e08c32a5fe7c59125e0919b7e7899cdJames Dong            return BAD_VALUE;
347635730831e08c32a5fe7c59125e0919b7e7899cdJames Dong        }
348635730831e08c32a5fe7c59125e0919b7e7899cdJames Dong
349635730831e08c32a5fe7c59125e0919b7e7899cdJames Dong        // The frame rate is supported, set the camera to the requested value.
35054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        params->setPreviewFrameRate(frameRate);
35154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        isCameraParamChanged = true;
35254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    } else {  // frameRate == -1
35354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        // Do not configure the camera.
35454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        // Use the current frame rate value setting from the camera
35554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
35654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
35754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if (isCameraParamChanged) {
35854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        // Either frame rate or frame size needs to be changed.
35954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        String8 s = params->flatten();
36054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        if (OK != mCamera->setParameters(s)) {
36129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Could not change settings."
36254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong                 " Someone else is using camera %p?", mCamera.get());
36354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong            return -EBUSY;
36454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        }
36554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
36654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    return OK;
36754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong}
36854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
36954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong/*
37054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * Check whether the requested video frame size
37154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * has been successfully configured or not. If both width and height
37254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * are -1, check on the current width and height value setting
37354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * is performed.
37454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong *
37554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param params CameraParameters to retrieve the information
37654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param the target video frame width in pixels to check against
37754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param the target video frame height in pixels to check against
37854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @return OK if no error
37954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong */
38054ff19ac69ace7c05ea90d225e26dab3b133f487James Dongstatus_t CameraSource::checkVideoSize(
38154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        const CameraParameters& params,
38254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        int32_t width, int32_t height) {
38354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
3843856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("checkVideoSize");
385f96c9d193c70c7216b34e6c65f046a09a2a81f14James Dong    // The actual video size is the same as the preview size
386f96c9d193c70c7216b34e6c65f046a09a2a81f14James Dong    // if the camera hal does not support separate video and
387f96c9d193c70c7216b34e6c65f046a09a2a81f14James Dong    // preview output. In this case, we retrieve the video
388f96c9d193c70c7216b34e6c65f046a09a2a81f14James Dong    // size from preview.
38954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    int32_t frameWidthActual = -1;
39054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    int32_t frameHeightActual = -1;
391f96c9d193c70c7216b34e6c65f046a09a2a81f14James Dong    Vector<Size> sizes;
392f96c9d193c70c7216b34e6c65f046a09a2a81f14James Dong    params.getSupportedVideoSizes(sizes);
393f96c9d193c70c7216b34e6c65f046a09a2a81f14James Dong    if (sizes.size() == 0) {
394f96c9d193c70c7216b34e6c65f046a09a2a81f14James Dong        // video size is the same as preview size
395f96c9d193c70c7216b34e6c65f046a09a2a81f14James Dong        params.getPreviewSize(&frameWidthActual, &frameHeightActual);
396f96c9d193c70c7216b34e6c65f046a09a2a81f14James Dong    } else {
397f96c9d193c70c7216b34e6c65f046a09a2a81f14James Dong        // video size may not be the same as preview
398f96c9d193c70c7216b34e6c65f046a09a2a81f14James Dong        params.getVideoSize(&frameWidthActual, &frameHeightActual);
399f96c9d193c70c7216b34e6c65f046a09a2a81f14James Dong    }
40054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if (frameWidthActual < 0 || frameHeightActual < 0) {
40129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Failed to retrieve video frame size (%dx%d)",
40254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong                frameWidthActual, frameHeightActual);
40354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        return UNKNOWN_ERROR;
40454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
40554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
40654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    // Check the actual video frame size against the target/requested
40754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    // video frame size.
40854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if (width != -1 && height != -1) {
40954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        if (frameWidthActual != width || frameHeightActual != height) {
41029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Failed to set video frame size to %dx%d. "
41154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong                    "The actual video size is %dx%d ", width, height,
41254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong                    frameWidthActual, frameHeightActual);
41354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong            return UNKNOWN_ERROR;
41454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        }
41554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
41654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
41754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    // Good now.
41854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    mVideoSize.width = frameWidthActual;
41954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    mVideoSize.height = frameHeightActual;
42054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    return OK;
42154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong}
42254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
42354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong/*
42454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * Check the requested frame rate has been successfully configured or not.
42554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * If the target frameRate is -1, check on the current frame rate value
42654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * setting is performed.
42754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong *
42854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param params CameraParameters to retrieve the information
42954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param the target video frame rate to check against
43054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @return OK if no error.
43154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong */
43254ff19ac69ace7c05ea90d225e26dab3b133f487James Dongstatus_t CameraSource::checkFrameRate(
43354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        const CameraParameters& params,
43454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        int32_t frameRate) {
43554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
4363856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("checkFrameRate");
43754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    int32_t frameRateActual = params.getPreviewFrameRate();
43854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if (frameRateActual < 0) {
43929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Failed to retrieve preview frame rate (%d)", frameRateActual);
44054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        return UNKNOWN_ERROR;
44154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
44254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
44354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    // Check the actual video frame rate against the target/requested
44454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    // video frame rate.
44554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if (frameRate != -1 && (frameRateActual - frameRate) != 0) {
44629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Failed to set preview frame rate to %d fps. The actual "
44754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong                "frame rate is %d", frameRate, frameRateActual);
44854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        return UNKNOWN_ERROR;
44954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
45054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
45154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    // Good now.
45254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    mVideoFrameRate = frameRateActual;
45354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    return OK;
45454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong}
45554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
45654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong/*
45754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * Initialize the CameraSource to so that it becomes
45854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * ready for providing the video input streams as requested.
45954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param camera the camera object used for the video source
46054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param cameraId if camera == 0, use camera with this id
46154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong *      as the video source
46254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param videoSize the target video frame size. If both
46354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong *      width and height in videoSize is -1, use the current
46454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong *      width and heigth settings by the camera
46554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @param frameRate the target frame rate in frames per second.
46654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong *      if it is -1, use the current camera frame rate setting.
4675c9523154d106b555db6c41f85ab205a4f189b02James Dong * @param storeMetaDataInVideoBuffers request to store meta
4685c9523154d106b555db6c41f85ab205a4f189b02James Dong *      data or real YUV data in video buffers. Request to
4695c9523154d106b555db6c41f85ab205a4f189b02James Dong *      store meta data in video buffers may not be honored
4705c9523154d106b555db6c41f85ab205a4f189b02James Dong *      if the source does not support this feature.
4715c9523154d106b555db6c41f85ab205a4f189b02James Dong *
47254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong * @return OK if no error.
47354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong */
47454ff19ac69ace7c05ea90d225e26dab3b133f487James Dongstatus_t CameraSource::init(
47554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        const sp<ICamera>& camera,
4764ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li        const sp<ICameraRecordingProxy>& proxy,
47754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        int32_t cameraId,
478ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala        const String16& clientName,
479ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala        uid_t clientUid,
48054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        Size videoSize,
4815c9523154d106b555db6c41f85ab205a4f189b02James Dong        int32_t frameRate,
4825c9523154d106b555db6c41f85ab205a4f189b02James Dong        bool storeMetaDataInVideoBuffers) {
48354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
4843856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("init");
48554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    status_t err = OK;
486ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong    int64_t token = IPCThreadState::self()->clearCallingIdentity();
487ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala    err = initWithCameraAccess(camera, proxy, cameraId, clientName, clientUid,
488ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong                               videoSize, frameRate,
489ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong                               storeMetaDataInVideoBuffers);
490ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong    IPCThreadState::self()->restoreCallingIdentity(token);
491ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong    return err;
492ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong}
493ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong
494ae4c1ac6401185539c03ce0819e174fd1b04b136James Dongstatus_t CameraSource::initWithCameraAccess(
495ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong        const sp<ICamera>& camera,
496ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong        const sp<ICameraRecordingProxy>& proxy,
497ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong        int32_t cameraId,
498ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala        const String16& clientName,
499ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala        uid_t clientUid,
500ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong        Size videoSize,
501ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong        int32_t frameRate,
502ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong        bool storeMetaDataInVideoBuffers) {
5033856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("initWithCameraAccess");
504ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong    status_t err = OK;
5059d7f58a7da8502a4174a17ac49fcba6efa35a457James Dong
506ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala    if ((err = isCameraAvailable(camera, proxy, cameraId,
507ceb388d6c03c38b96dc41c0ea4804b749aa077c4Eino-Ville Talvala            clientName, clientUid)) != OK) {
50829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Camera connection could not be established.");
50954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        return err;
51054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
51154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    CameraParameters params(mCamera->getParameters());
51254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if ((err = isCameraColorFormatSupported(params)) != OK) {
51354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        return err;
51454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
515be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber
51654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    // Set the camera to use the requested video frame size
51754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    // and/or frame rate.
51854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if ((err = configureCamera(&params,
51954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong                    videoSize.width, videoSize.height,
52054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong                    frameRate))) {
52154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        return err;
52254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
523653252be963c07c99109d20f942d1f30c52a9360James Dong
52454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    // Check on video frame size and frame rate.
52554ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    CameraParameters newCameraParams(mCamera->getParameters());
52654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if ((err = checkVideoSize(newCameraParams,
52754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong                videoSize.width, videoSize.height)) != OK) {
52854ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        return err;
52954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
53054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if ((err = checkFrameRate(newCameraParams, frameRate)) != OK) {
53154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        return err;
53254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
53354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong
5348e0792bb55a604ffcd4aa90fdb4419d8b3c6ad24Wu-cheng Li    // Set the preview display. Skip this if mSurface is null because
5358e0792bb55a604ffcd4aa90fdb4419d8b3c6ad24Wu-cheng Li    // applications may already set a surface to the camera.
5368e0792bb55a604ffcd4aa90fdb4419d8b3c6ad24Wu-cheng Li    if (mSurface != NULL) {
5378e0792bb55a604ffcd4aa90fdb4419d8b3c6ad24Wu-cheng Li        // This CHECK is good, since we just passed the lock/unlock
5388e0792bb55a604ffcd4aa90fdb4419d8b3c6ad24Wu-cheng Li        // check earlier by calling mCamera->setParameters().
5394b820b0e1fa069714b123fc35784541d0f94d267Eino-Ville Talvala        CHECK_EQ((status_t)OK, mCamera->setPreviewTarget(mSurface));
5408e0792bb55a604ffcd4aa90fdb4419d8b3c6ad24Wu-cheng Li    }
5412b37ced30f89437c804c3945b901019b86d210aeJames Dong
542abdd2ba259a5dc863a821c9d1187d83f2e2395acJames Dong    // By default, do not store metadata in video buffers
5435c9523154d106b555db6c41f85ab205a4f189b02James Dong    mIsMetaDataStoredInVideoBuffers = false;
544abdd2ba259a5dc863a821c9d1187d83f2e2395acJames Dong    mCamera->storeMetaDataInBuffers(false);
545abdd2ba259a5dc863a821c9d1187d83f2e2395acJames Dong    if (storeMetaDataInVideoBuffers) {
546abdd2ba259a5dc863a821c9d1187d83f2e2395acJames Dong        if (OK == mCamera->storeMetaDataInBuffers(true)) {
547abdd2ba259a5dc863a821c9d1187d83f2e2395acJames Dong            mIsMetaDataStoredInVideoBuffers = true;
548abdd2ba259a5dc863a821c9d1187d83f2e2395acJames Dong        }
5495c9523154d106b555db6c41f85ab205a4f189b02James Dong    }
5505c9523154d106b555db6c41f85ab205a4f189b02James Dong
55154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    int64_t glitchDurationUs = (1000000LL / mVideoFrameRate);
552f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    if (glitchDurationUs > mGlitchDurationThresholdUs) {
553f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        mGlitchDurationThresholdUs = glitchDurationUs;
554f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    }
555f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong
556ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong    // XXX: query camera for the stride and slice height
557ddcc4a66d848deef6fb4689e64e30cd9bd2684feJames Dong    // when the capability becomes available.
558653252be963c07c99109d20f942d1f30c52a9360James Dong    mMeta = new MetaData;
55954ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    mMeta->setCString(kKeyMIMEType,  MEDIA_MIMETYPE_VIDEO_RAW);
56054ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    mMeta->setInt32(kKeyColorFormat, mColorFormat);
56154ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    mMeta->setInt32(kKeyWidth,       mVideoSize.width);
56254ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    mMeta->setInt32(kKeyHeight,      mVideoSize.height);
56354ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    mMeta->setInt32(kKeyStride,      mVideoSize.width);
56454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    mMeta->setInt32(kKeySliceHeight, mVideoSize.height);
565393410a441b6d06daf286ed496470e9d6b2b6ca8James Dong    mMeta->setInt32(kKeyFrameRate,   mVideoFrameRate);
56654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    return OK;
56720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
56820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
56920111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberCameraSource::~CameraSource() {
57020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mStarted) {
571b44c9d2bdc0d5b9cb03254022a58e017b516e9e6James Dong        reset();
572ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong    } else if (mInitCheck == OK) {
573ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong        // Camera is initialized but because start() is never called,
574ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong        // the lock on Camera is never released(). This makes sure
575ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong        // Camera's lock is released in this case.
576ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong        releaseCamera();
57720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
57820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
57920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
58065e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatravoid CameraSource::startCameraRecording() {
5813856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("startCameraRecording");
5824ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    // Reset the identity to the current thread because media server owns the
5834ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    // camera and recording is started by the applications. The applications
5844ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    // will connect to the camera in ICameraRecordingProxy::startRecording.
5854ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    int64_t token = IPCThreadState::self()->clearCallingIdentity();
586983cf231ab2d176a14595cdae46ff1b0c239af47James Dong    if (mNumInputBuffers > 0) {
587983cf231ab2d176a14595cdae46ff1b0c239af47James Dong        status_t err = mCamera->sendCommand(
588983cf231ab2d176a14595cdae46ff1b0c239af47James Dong            CAMERA_CMD_SET_VIDEO_BUFFER_COUNT, mNumInputBuffers, 0);
589983cf231ab2d176a14595cdae46ff1b0c239af47James Dong
590983cf231ab2d176a14595cdae46ff1b0c239af47James Dong        // This could happen for CameraHAL1 clients; thus the failure is
591983cf231ab2d176a14595cdae46ff1b0c239af47James Dong        // not a fatal error
592983cf231ab2d176a14595cdae46ff1b0c239af47James Dong        if (err != OK) {
593983cf231ab2d176a14595cdae46ff1b0c239af47James Dong            ALOGW("Failed to set video buffer count to %d due to %d",
594983cf231ab2d176a14595cdae46ff1b0c239af47James Dong                mNumInputBuffers, err);
595983cf231ab2d176a14595cdae46ff1b0c239af47James Dong        }
596983cf231ab2d176a14595cdae46ff1b0c239af47James Dong    }
597983cf231ab2d176a14595cdae46ff1b0c239af47James Dong
5983bd3020c00ec8264ac1fe3870800f326487f9221James Dong    if (mCameraFlags & FLAGS_HOT_CAMERA) {
5993bd3020c00ec8264ac1fe3870800f326487f9221James Dong        mCamera->unlock();
6003bd3020c00ec8264ac1fe3870800f326487f9221James Dong        mCamera.clear();
601f1d5aa162c02a16b7195a43a9bcea4d592600ac4James Dong        CHECK_EQ((status_t)OK,
602f1d5aa162c02a16b7195a43a9bcea4d592600ac4James Dong            mCameraRecordingProxy->startRecording(new ProxyListener(this)));
6033bd3020c00ec8264ac1fe3870800f326487f9221James Dong    } else {
6043bd3020c00ec8264ac1fe3870800f326487f9221James Dong        mCamera->setListener(new CameraSourceListener(this));
6053bd3020c00ec8264ac1fe3870800f326487f9221James Dong        mCamera->startRecording();
6063bd3020c00ec8264ac1fe3870800f326487f9221James Dong        CHECK(mCamera->recordingEnabled());
6073bd3020c00ec8264ac1fe3870800f326487f9221James Dong    }
6084ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    IPCThreadState::self()->restoreCallingIdentity(token);
60965e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra}
61065e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra
611f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongstatus_t CameraSource::start(MetaData *meta) {
6123856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("start");
6130c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(!mStarted);
61454ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    if (mInitCheck != OK) {
61529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("CameraSource is not initialized yet");
61654ff19ac69ace7c05ea90d225e26dab3b133f487James Dong        return mInitCheck;
61754ff19ac69ace7c05ea90d225e26dab3b133f487James Dong    }
61820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
619365a963142093a1cd8efdcea76b5f65096a5b115James Dong    char value[PROPERTY_VALUE_MAX];
620365a963142093a1cd8efdcea76b5f65096a5b115James Dong    if (property_get("media.stagefright.record-stats", value, NULL)
621365a963142093a1cd8efdcea76b5f65096a5b115James Dong        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
622365a963142093a1cd8efdcea76b5f65096a5b115James Dong        mCollectStats = true;
623365a963142093a1cd8efdcea76b5f65096a5b115James Dong    }
6249d7f58a7da8502a4174a17ac49fcba6efa35a457James Dong
625f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    mStartTimeUs = 0;
626983cf231ab2d176a14595cdae46ff1b0c239af47James Dong    mNumInputBuffers = 0;
627983cf231ab2d176a14595cdae46ff1b0c239af47James Dong    if (meta) {
628983cf231ab2d176a14595cdae46ff1b0c239af47James Dong        int64_t startTimeUs;
629983cf231ab2d176a14595cdae46ff1b0c239af47James Dong        if (meta->findInt64(kKeyTime, &startTimeUs)) {
630983cf231ab2d176a14595cdae46ff1b0c239af47James Dong            mStartTimeUs = startTimeUs;
631983cf231ab2d176a14595cdae46ff1b0c239af47James Dong        }
632983cf231ab2d176a14595cdae46ff1b0c239af47James Dong
633983cf231ab2d176a14595cdae46ff1b0c239af47James Dong        int32_t nBuffers;
634983cf231ab2d176a14595cdae46ff1b0c239af47James Dong        if (meta->findInt32(kKeyNumBuffers, &nBuffers)) {
635983cf231ab2d176a14595cdae46ff1b0c239af47James Dong            CHECK_GT(nBuffers, 0);
636983cf231ab2d176a14595cdae46ff1b0c239af47James Dong            mNumInputBuffers = nBuffers;
637983cf231ab2d176a14595cdae46ff1b0c239af47James Dong        }
638f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    }
639f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong
640c42478ed7b8a379d2f8a43d4d349680c8a37573fJames Dong    startCameraRecording();
64120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
64220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mStarted = true;
64320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    return OK;
64420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
64520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
64665e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatravoid CameraSource::stopCameraRecording() {
6473856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("stopCameraRecording");
6483bd3020c00ec8264ac1fe3870800f326487f9221James Dong    if (mCameraFlags & FLAGS_HOT_CAMERA) {
6493bd3020c00ec8264ac1fe3870800f326487f9221James Dong        mCameraRecordingProxy->stopRecording();
6503bd3020c00ec8264ac1fe3870800f326487f9221James Dong    } else {
6513bd3020c00ec8264ac1fe3870800f326487f9221James Dong        mCamera->setListener(NULL);
6523bd3020c00ec8264ac1fe3870800f326487f9221James Dong        mCamera->stopRecording();
6533bd3020c00ec8264ac1fe3870800f326487f9221James Dong    }
65465e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra}
65565e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra
656ea7b485595f8cec6a66668b5c54c8f297d843f77James Dongvoid CameraSource::releaseCamera() {
6573856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("releaseCamera");
65895068be1426dc0a4dc856cf9e35550c31b901711Wu-cheng Li    if (mCamera != 0) {
659ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong        int64_t token = IPCThreadState::self()->clearCallingIdentity();
66095068be1426dc0a4dc856cf9e35550c31b901711Wu-cheng Li        if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) {
6613856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("Camera was cold when we started, stopping preview");
66295068be1426dc0a4dc856cf9e35550c31b901711Wu-cheng Li            mCamera->stopPreview();
66395068be1426dc0a4dc856cf9e35550c31b901711Wu-cheng Li            mCamera->disconnect();
66495068be1426dc0a4dc856cf9e35550c31b901711Wu-cheng Li        }
6653bd3020c00ec8264ac1fe3870800f326487f9221James Dong        mCamera->unlock();
66695068be1426dc0a4dc856cf9e35550c31b901711Wu-cheng Li        mCamera.clear();
6673bd3020c00ec8264ac1fe3870800f326487f9221James Dong        mCamera = 0;
668ae4c1ac6401185539c03ce0819e174fd1b04b136James Dong        IPCThreadState::self()->restoreCallingIdentity(token);
66995068be1426dc0a4dc856cf9e35550c31b901711Wu-cheng Li    }
67095068be1426dc0a4dc856cf9e35550c31b901711Wu-cheng Li    if (mCameraRecordingProxy != 0) {
67195068be1426dc0a4dc856cf9e35550c31b901711Wu-cheng Li        mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
67295068be1426dc0a4dc856cf9e35550c31b901711Wu-cheng Li        mCameraRecordingProxy.clear();
673ea7b485595f8cec6a66668b5c54c8f297d843f77James Dong    }
674ea7b485595f8cec6a66668b5c54c8f297d843f77James Dong    mCameraFlags = 0;
675ea7b485595f8cec6a66668b5c54c8f297d843f77James Dong}
676ea7b485595f8cec6a66668b5c54c8f297d843f77James Dong
677b44c9d2bdc0d5b9cb03254022a58e017b516e9e6James Dongstatus_t CameraSource::reset() {
678b44c9d2bdc0d5b9cb03254022a58e017b516e9e6James Dong    ALOGD("reset: E");
679c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    Mutex::Autolock autoLock(mLock);
68020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mStarted = false;
681c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    mFrameAvailableCondition.signal();
682365a963142093a1cd8efdcea76b5f65096a5b115James Dong
6839197441e59be323e2f6f0c6506f7248eb6a944b2James Dong    int64_t token;
6849197441e59be323e2f6f0c6506f7248eb6a944b2James Dong    bool isTokenValid = false;
6859197441e59be323e2f6f0c6506f7248eb6a944b2James Dong    if (mCamera != 0) {
6869197441e59be323e2f6f0c6506f7248eb6a944b2James Dong        token = IPCThreadState::self()->clearCallingIdentity();
6879197441e59be323e2f6f0c6506f7248eb6a944b2James Dong        isTokenValid = true;
6889197441e59be323e2f6f0c6506f7248eb6a944b2James Dong    }
689c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    releaseQueuedFrames();
6907278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong    while (!mFramesBeingEncoded.empty()) {
69141152efd144ccf70c380d5c9a32105c02a039f43James Dong        if (NO_ERROR !=
692e8e5f86e9e310b065596c8cbbca1543eb833dee1James Dong            mFrameCompleteCondition.waitRelative(mLock,
693e8e5f86e9e310b065596c8cbbca1543eb833dee1James Dong                    mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
6945ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block            ALOGW("Timed out waiting for outstanding frames being encoded: %d",
695365a963142093a1cd8efdcea76b5f65096a5b115James Dong                mFramesBeingEncoded.size());
69641152efd144ccf70c380d5c9a32105c02a039f43James Dong        }
6977278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong    }
698d69c7f654cc772b03717999c1b24402d5c40e69fJames Dong    stopCameraRecording();
699ea7b485595f8cec6a66668b5c54c8f297d843f77James Dong    releaseCamera();
7009197441e59be323e2f6f0c6506f7248eb6a944b2James Dong    if (isTokenValid) {
7019197441e59be323e2f6f0c6506f7248eb6a944b2James Dong        IPCThreadState::self()->restoreCallingIdentity(token);
7029197441e59be323e2f6f0c6506f7248eb6a944b2James Dong    }
7037278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong
704365a963142093a1cd8efdcea76b5f65096a5b115James Dong    if (mCollectStats) {
705df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block        ALOGI("Frames received/encoded/dropped: %d/%d/%d in %lld us",
706365a963142093a1cd8efdcea76b5f65096a5b115James Dong                mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
707365a963142093a1cd8efdcea76b5f65096a5b115James Dong                mLastFrameTimestampUs - mFirstFrameTimeUs);
708365a963142093a1cd8efdcea76b5f65096a5b115James Dong    }
70913aec890216948b0c364f8f92792129d0335f506James Dong
710ba29002c7aee13c068049037cd14bba6a244da6bJames Dong    if (mNumGlitches > 0) {
7115ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block        ALOGW("%d long delays between neighboring video frames", mNumGlitches);
712ba29002c7aee13c068049037cd14bba6a244da6bJames Dong    }
713ba29002c7aee13c068049037cd14bba6a244da6bJames Dong
71413aec890216948b0c364f8f92792129d0335f506James Dong    CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
715b44c9d2bdc0d5b9cb03254022a58e017b516e9e6James Dong    ALOGD("reset: X");
71620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    return OK;
71720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
71820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
71965e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatravoid CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
7203856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("releaseRecordingFrame");
7214ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    if (mCameraRecordingProxy != NULL) {
7224ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li        mCameraRecordingProxy->releaseRecordingFrame(frame);
723334d097870eefeb45137b6df026f7db861d47663James Dong    } else if (mCamera != NULL) {
7243bd3020c00ec8264ac1fe3870800f326487f9221James Dong        int64_t token = IPCThreadState::self()->clearCallingIdentity();
7253bd3020c00ec8264ac1fe3870800f326487f9221James Dong        mCamera->releaseRecordingFrame(frame);
7263bd3020c00ec8264ac1fe3870800f326487f9221James Dong        IPCThreadState::self()->restoreCallingIdentity(token);
727d69c7f654cc772b03717999c1b24402d5c40e69fJames Dong    }
72865e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra}
72965e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra
730c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dongvoid CameraSource::releaseQueuedFrames() {
731c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    List<sp<IMemory> >::iterator it;
7327278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong    while (!mFramesReceived.empty()) {
7337278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong        it = mFramesReceived.begin();
73465e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra        releaseRecordingFrame(*it);
7357278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong        mFramesReceived.erase(it);
73613aec890216948b0c364f8f92792129d0335f506James Dong        ++mNumFramesDropped;
737c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    }
738c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong}
739c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong
74020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubersp<MetaData> CameraSource::getFormat() {
741653252be963c07c99109d20f942d1f30c52a9360James Dong    return mMeta;
74220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
74320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
744f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid CameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) {
74565e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra    releaseRecordingFrame(frame);
746f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong}
747f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong
7487278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dongvoid CameraSource::signalBufferReturned(MediaBuffer *buffer) {
7493856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("signalBufferReturned: %p", buffer->data());
75056223b96c2f6de5998496fac9d6703f06adc1dcaAndreas Huber    Mutex::Autolock autoLock(mLock);
7517278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong    for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
7527278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong         it != mFramesBeingEncoded.end(); ++it) {
7537278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong        if ((*it)->pointer() ==  buffer->data()) {
754f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            releaseOneRecordingFrame((*it));
7557278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong            mFramesBeingEncoded.erase(it);
7567278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong            ++mNumFramesEncoded;
7577278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong            buffer->setObserver(0);
7587278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong            buffer->release();
7597278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong            mFrameCompleteCondition.signal();
7607278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong            return;
7617278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong        }
7627278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong    }
763f1d5aa162c02a16b7195a43a9bcea4d592600ac4James Dong    CHECK(!"signalBufferReturned: bogus buffer");
7647278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong}
7657278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong
76620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberstatus_t CameraSource::read(
76720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        MediaBuffer **buffer, const ReadOptions *options) {
7683856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("read");
76920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
77020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    *buffer = NULL;
77120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
77220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    int64_t seekTimeUs;
773abd1f4f870925d6776dbe4b930b759a1ab6595caAndreas Huber    ReadOptions::SeekMode mode;
774abd1f4f870925d6776dbe4b930b759a1ab6595caAndreas Huber    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
77520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        return ERROR_UNSUPPORTED;
77620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
77720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
77820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    sp<IMemory> frame;
779be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber    int64_t frameTime;
78020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
78120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    {
78220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        Mutex::Autolock autoLock(mLock);
78379e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong        while (mStarted && mFramesReceived.empty()) {
78441152efd144ccf70c380d5c9a32105c02a039f43James Dong            if (NO_ERROR !=
785e8e5f86e9e310b065596c8cbbca1543eb833dee1James Dong                mFrameAvailableCondition.waitRelative(mLock,
786e8e5f86e9e310b065596c8cbbca1543eb833dee1James Dong                    mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
7873bd3020c00ec8264ac1fe3870800f326487f9221James Dong                if (mCameraRecordingProxy != 0 &&
7883bd3020c00ec8264ac1fe3870800f326487f9221James Dong                    !mCameraRecordingProxy->asBinder()->isBinderAlive()) {
7895ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block                    ALOGW("camera recording proxy is gone");
7904ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li                    return ERROR_END_OF_STREAM;
7914ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li                }
7925ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block                ALOGW("Timed out waiting for incoming camera video frames: %lld us",
79341152efd144ccf70c380d5c9a32105c02a039f43James Dong                    mLastFrameTimestampUs);
79441152efd144ccf70c380d5c9a32105c02a039f43James Dong            }
79520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
79679e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong        if (!mStarted) {
79779e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong            return OK;
79879e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong        }
79979e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong        frame = *mFramesReceived.begin();
80079e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong        mFramesReceived.erase(mFramesReceived.begin());
80179e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong
80279e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong        frameTime = *mFrameTimes.begin();
80379e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong        mFrameTimes.erase(mFrameTimes.begin());
80479e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong        mFramesBeingEncoded.push_back(frame);
80579e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong        *buffer = new MediaBuffer(frame->pointer(), frame->size());
80679e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong        (*buffer)->setObserver(this);
80779e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong        (*buffer)->add_ref();
80879e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong        (*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
8097278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong    }
81020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    return OK;
81120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
81220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
813c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dongvoid CameraSource::dataCallbackTimestamp(int64_t timestampUs,
814c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong        int32_t msgType, const sp<IMemory> &data) {
8153856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
81620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Mutex::Autolock autoLock(mLock);
817a472613aec322e25891abf5c77bf3f7e3c244920James Dong    if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
8183856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs);
819f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        releaseOneRecordingFrame(data);
820c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong        return;
821c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong    }
82220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
82398cfde007490a5903b729a4718c0dada755ae8f8James Dong    if (mNumFramesReceived > 0) {
82498cfde007490a5903b729a4718c0dada755ae8f8James Dong        CHECK(timestampUs > mLastFrameTimestampUs);
82598cfde007490a5903b729a4718c0dada755ae8f8James Dong        if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) {
82698cfde007490a5903b729a4718c0dada755ae8f8James Dong            ++mNumGlitches;
827f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        }
828f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    }
829f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong
83065e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra    // May need to skip frame or modify timestamp. Currently implemented
83165e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra    // by the subclass CameraSourceTimeLapse.
83279e23b41fad961008bfde6e26b3c6f86878ca69dJames Dong    if (skipCurrentFrame(timestampUs)) {
83365e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra        releaseOneRecordingFrame(data);
83465e7e6facda89927cb26594b3b65ae81b3235ebcNipun Kwatra        return;
835fc20aab463f527ab3b0664986f0381a86b375884Nipun Kwatra    }
836fc20aab463f527ab3b0664986f0381a86b375884Nipun Kwatra
837365a963142093a1cd8efdcea76b5f65096a5b115James Dong    mLastFrameTimestampUs = timestampUs;
83813aec890216948b0c364f8f92792129d0335f506James Dong    if (mNumFramesReceived == 0) {
839c32cd79d9ad4aba7d959b5b3be7361b4715e6f18James Dong        mFirstFrameTimeUs = timestampUs;
840f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        // Initial delay
841f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        if (mStartTimeUs > 0) {
842f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            if (timestampUs < mStartTimeUs) {
843f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong                // Frame was captured before recording was started
844f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong                // Drop it without updating the statistical data.
845f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong                releaseOneRecordingFrame(data);
846f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong                return;
847f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            }
848f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mStartTimeUs = timestampUs - mStartTimeUs;
849f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        }
850be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber    }
85113aec890216948b0c364f8f92792129d0335f506James Dong    ++mNumFramesReceived;
852be5c74f5da6a93b0d23f96e11848acfcc3b4d1d9Andreas Huber
85398cfde007490a5903b729a4718c0dada755ae8f8James Dong    CHECK(data != NULL && data->size() > 0);
8547278cf32f1aa6a322f6dff1f8b7dacf7b6dddba6James Dong    mFramesReceived.push_back(data);
855f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
856f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    mFrameTimes.push_back(timeUs);
8573856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("initial delay: %lld, current time stamp: %lld",
858f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        mStartTimeUs, timeUs);
85920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mFrameAvailableCondition.signal();
86020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
86120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8625c9523154d106b555db6c41f85ab205a4f189b02James Dongbool CameraSource::isMetaDataStoredInVideoBuffers() const {
8633856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("isMetaDataStoredInVideoBuffers");
8645c9523154d106b555db6c41f85ab205a4f189b02James Dong    return mIsMetaDataStoredInVideoBuffers;
8655c9523154d106b555db6c41f85ab205a4f189b02James Dong}
8665c9523154d106b555db6c41f85ab205a4f189b02James Dong
8674ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng LiCameraSource::ProxyListener::ProxyListener(const sp<CameraSource>& source) {
8684ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    mSource = source;
8694ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li}
8704ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li
8714ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Livoid CameraSource::ProxyListener::dataCallbackTimestamp(
8724ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li        nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
8734ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li    mSource->dataCallbackTimestamp(timestamp / 1000, msgType, dataPtr);
8744ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li}
8754ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li
8764ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Livoid CameraSource::DeathNotifier::binderDied(const wp<IBinder>& who) {
877df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block    ALOGI("Camera recording proxy died");
8784ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li}
8794ca2c7c913f8bd4ada13aca56d36045d42d1e00fWu-cheng Li
88020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}  // namespace android
881