【Android 10 源码】Camera v1 startPreview 流程

Camera v1 startPreview 起点位于 android.hardware 包下的 Camera 类中,这是老版本的 Camera 预览的起点。

在这里插入图片描述

上面这张相机架构图左边就是关于 Camera v1 的关键组成。分析 Camera v1 startPreview 会涉及到其中的一些类。

Deprecated 已标注,表示 Camera v1 废弃状态。现在推荐使用 Camera v2 API,单只要代码没有完全移除,Camera v1 API 还是可以使用的,学习 Camera v1 startPreview 流程有助于理解 Camera v2 重新架构的原因。

开始捕捉和绘制预览帧到屏幕。在一个 surface 被 setPreviewDisplay(SurfaceHolder) 或 setPreviewTexture(SurfaceTexture) 提供之前,预览不会真正开始。如果 setPreviewCallback(Camera.previewcallback)、setOneShotPreviewCallback(Camera. previewcallback) 或 setPreviewCallbackWithBuffer(Camera.previewcallback) 被调用。当预览数据可用时,PreviewCallback#onPreviewFrame(byte[], Camera) 将被调用。

这个方法是个 JNI Native 实现,mNativeContext 这个字段内保存的是其对应 Native Camera 对象的指针。

frameworks/base/core/java/android/hardware/Camera.java


@Deprecated
public class Camera {
    ......
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    private long mNativeContext; // accessed by native methods
    ......
    /**
     * Starts capturing and drawing preview frames to the screen.
     * Preview will not actually start until a surface is supplied
     * with {@link #setPreviewDisplay(SurfaceHolder)} or
     * {@link #setPreviewTexture(SurfaceTexture)}.
     *
     * <p>If {@link #setPreviewCallback(Camera.PreviewCallback)},
     * {@link #setOneShotPreviewCallback(Camera.PreviewCallback)}, or
     * {@link #setPreviewCallbackWithBuffer(Camera.PreviewCallback)} were
     * called, {@link Camera.PreviewCallback#onPreviewFrame(byte[], Camera)}
     * will be called when preview data becomes available.
     *
     * @throws RuntimeException if starting preview fails; usually this would be
     *    because of a hardware or other low-level error, or because release()
     *    has been called on this Camera instance. The QCIF (176x144) exception
     *    mentioned in {@link Parameters#setPreviewSize setPreviewSize} and
     *    {@link Parameters#setPictureSize setPictureSize} can also cause this
     *    exception be thrown.
     */
    public native final void startPreview();    
    ......
}

Camera startPreview() 最终调到 android_hardware_Camera.cpp 中的 android_hardware_Camera_startPreview 方法。这个方法的核心流程如下:

  1. 调用 get_native_camera(…) 获取指向 Native Camera 对象的强指针,get_native_camera(…) 内部实际上先将对应的 Java 字段(mNativeContext)转换为指向 JNICameraContext 对象的指针,然后再调用 JNICameraContext::getCamera() 获取 指向 Native Camera 对象的强指针并返回;
  2. 如果获取到的指针为 0,直接返回;
  3. 如果获取的指针正常,则调用 Native Camera 对象 startPreview() 进一步处理,这个函数的返回值不为 NO_ERROR 时,抛出 RuntimeException:startPreview failed。

frameworks/base/core/jni/android_hardware_Camera.cpp

sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext)
{
    sp<Camera> camera;
    Mutex::Autolock _l(sLock);
    JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetLongField(thiz, fields.context));
    if (context != NULL) {
        camera = context->getCamera();
    }
    ALOGV("get_native_camera: context=%p, camera=%p", context, camera.get());
    if (camera == 0) {
        jniThrowRuntimeException(env,
                "Camera is being used after Camera.release() was called");
    }

    if (pContext != NULL) *pContext = context;
    return camera;
}
......
static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
{
    ALOGV("startPreview");
    sp<Camera> camera = get_native_camera(env, thiz, NULL);
    if (camera == 0) return;

    if (camera->startPreview() != NO_ERROR) {
        jniThrowRuntimeException(env, "startPreview failed");
        return;
    }
}
......
static const JNINativeMethod camMethods[] = {
  ......
  { "startPreview",
    "()V",
    (void *)android_hardware_Camera_startPreview },
  ......
};
......
// Get all the required offsets in java class and register native functions
int register_android_hardware_Camera(JNIEnv *env)
{
    field fields_to_find[] = {
        { "android/hardware/Camera", "mNativeContext",   "J", &fields.context },
        ......
    };
    ......
}

Camera::startPreview() 仅仅将开始预览的动作交给 ::android::hardware::ICamera,不难看出这里涉及到了 binder 调用。::android::hardware::ICamera 定义在 android/hardware/ICamera.h 中。

frameworks/av/camera/Camera.cpp

// start preview mode
status_t Camera::startPreview()
{
    ALOGV("startPreview");
    sp <::android::hardware::ICamera> c = mCamera;
    if (c == 0) return NO_INIT;
    return c->startPreview();
}

ICamera 类继承自 android::IInterface,熟悉的 binder 接口。DECLARE_META_INTERFACE 是个宏定义在 binder/IInterface.h 头文件中。

下面是 DECLARE_META_INTERFACE 展开后的样子,它声明了一些函数和 Field。

public:
    static const ::android::String16 descriptor;
    static ::android::sp<ICamera> asInterface(
            const ::android::sp<::android::IBinder>& obj);
    virtual const ::android::String16& getInterfaceDescriptor() const;
    ICamera();
    virtual ~ICamera();
    static bool setDefaultImpl(std::unique_ptr<ICamera> impl);
    static const std::unique_ptr<ICamera>& getDefaultImpl();
private:
    static std::unique_ptr<ICamera> default_impl;
public:

目前只看到了 Binder 服务端没看到客户端,客户端一般定义为 BpXXX。实际上 BpCamera 实现在了 camera/ICamera.cpp 中。调用 ::android::hardware::ICamera 的 startPreview() 实际上调用 Camera 的 binder 代理端 BpCamera 实现的 startPreview()。最终代理端通过 binder 机制将请求发送到服务端 BnCamera 处理,处理前先在 onTransact(…) 中接收到请求后分发到相应的函数处理。

frameworks/av/camera/include/camera/android/hardware/ICamera.h

namespace android {
......
namespace hardware {
......
class ICamera: public android::IInterface
{
    /**
     * Keep up-to-date with ICamera.aidl in frameworks/base
     */
public:
    ......
    DECLARE_META_INTERFACE(Camera);
    ......
    // start preview mode, must call setPreviewTarget first
    virtual status_t        startPreview() = 0;
    ......
};

// ----------------------------------------------------------------------------

class BnCamera: public android::BnInterface<ICamera>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};

} // namespace hardware
} // namespace android

BpCamera::startPreview() 将 START_PREVIEW 请求封装到 Parcel 中发送出去,等待 BnCamera 处理返回结果到 Parcel(reply)。

frameworks/av/camera/ICamera.cpp


class BpCamera: public BpInterface<ICamera>
{
public:
    explicit BpCamera(const sp<IBinder>& impl)
        : BpInterface<ICamera>(impl)
    {
    }
    ......
    // start preview mode, must call setPreviewTarget first
    status_t startPreview()
    {
        ALOGV("startPreview");
        Parcel data, reply;
        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
        remote()->transact(START_PREVIEW, data, &reply);
        return reply.readInt32();
    }
    ......
};

BnCamera::onTransact(…) 接收到代理端 BpCamera 发来的 START_PREVIEW 请求,调用其内部实现 startPreview() 进一步处理。通常来说其内部实现在其子类中,也就说我们在 BnCamera 中其实无法找到 startPreview() 具体实现,实际上它实现在 CameraService 的内部类 Client 中。

frameworks/av/camera/ICamera.cpp


status_t BnCamera::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        case START_PREVIEW: {
            ALOGV("START_PREVIEW");
            CHECK_INTERFACE(ICamera, data, reply);
            reply->writeInt32(startPreview());
            return NO_ERROR;
        } break;
        ......
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}

CameraService::Client 的具体实现并不在 CameraService.cpp 中。实际上存在 CameraClient 和 Camera2Client。

frameworks/av/services/camera/libcameraservice/CameraService.h

namespace android {
......
class CameraService :
    public BinderService<CameraService>,
    public virtual ::android::hardware::BnCameraService,
    public virtual IBinder::DeathRecipient,
    public virtual CameraProviderManager::StatusListener
{
    ......
public:
    ......
    class Client : public hardware::BnCamera, public BasicClient
    {
    public:
        ......
        virtual status_t      startPreview() = 0;
        ......
    };
    ......
};

} // namespace android

先来分析 CameraClient,android.hardware.Camera API 和 Camera HAL 设备之间的接口 CAMERA_DEVICE_API_VERSION_1_0 版本。

frameworks/av/services/camera/libcameraservice/api1/CameraClient.h

namespace android {

class MemoryHeapBase;
class CameraHardwareInterface;

/**
 * Interface between android.hardware.Camera API and Camera HAL device for version
 * CAMERA_DEVICE_API_VERSION_1_0.
 */

class CameraClient : public CameraService::Client
{
public:
    ......
    virtual status_t        startPreview();
    ......
}

CameraClient::startPreview() -> CameraClient::startCameraMode(…) -> CameraClient::startPreviewMode() -> CameraHardwareInterface::startPreview()。

CameraClient::startPreviewMode() 内部主要使用了 mHardware,它是一个指向 CameraHardwareInterface 的强指针。

mHardware 是在 CameraClient::initialize(…) (初始化)函数中赋值的。

frameworks/av/services/camera/libcameraservice/api1/CameraClient.cpp

// start preview mode
status_t CameraClient::startPreview() {
    LOG1("startPreview (pid %d)", CameraThreadState::getCallingPid());
    return startCameraMode(CAMERA_PREVIEW_MODE);
}
......
// start preview or recording
status_t CameraClient::startCameraMode(camera_mode mode) {
    LOG1("startCameraMode(%d)", mode);
    Mutex::Autolock lock(mLock);
    status_t result = checkPidAndHardware();
    if (result != NO_ERROR) return result;

    switch(mode) {
        case CAMERA_PREVIEW_MODE:
            if (mSurface == 0 && mPreviewWindow == 0) {
                LOG1("mSurface is not set yet.");
                // still able to start preview in this case.
            }
            return startPreviewMode();
        ......
        default:
            return UNKNOWN_ERROR;
    }
}

status_t CameraClient::startPreviewMode() {
    LOG1("startPreviewMode");
    status_t result = NO_ERROR;

    // if preview has been enabled, nothing needs to be done
    if (mHardware->previewEnabled()) {
        return NO_ERROR;
    }

    if (mPreviewWindow != 0) {
        mHardware->setPreviewScalingMode(
            NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
        mHardware->setPreviewTransform(mOrientation);
    }
    mHardware->setPreviewWindow(mPreviewWindow);
    result = mHardware->startPreview();
    if (result == NO_ERROR) {
        sCameraService->updateProxyDeviceState(
            hardware::ICameraServiceProxy::CAMERA_STATE_ACTIVE,
            mCameraIdStr, mCameraFacing, mClientPackageName,
            hardware::ICameraServiceProxy::CAMERA_API_LEVEL_1);
    }
    return result;
}

CameraHardwareInterface::startPreview() 内部调用了 mHidlDevice startPreview(),mHidlDevice 是指向 hardware:📷:device::V1_0::ICameraDevice 类型的强指针。看的出来这里涉及 binder 调用。

frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface.cpp

status_t CameraHardwareInterface::startPreview()
{
    ALOGV("%s(%s)", __FUNCTION__, mName.string());
    if (CC_LIKELY(mHidlDevice != nullptr)) {
        return CameraProviderManager::mapToStatusT(
                mHidlDevice->startPreview());
    }
    return INVALID_OPERATION;
}

startPreview() 定义在 ICameraDevice.hal 中,厂家实现具体的开始预览逻辑。

hardware/interfaces/camera/device/1.0/ICameraDevice.hal

package android.hardware.camera.device@1.0;
......
/**
 * Camera device HAL, legacy version
 *
 * DEPRECATED. New devices are strongly recommended to use Camera HAL v3.2 or
 * newer.
 *
 * Supports the android.hardware.Camera API, and the android.hardware.camera2
 * API in LEGACY mode only.
 *
 * Will be removed in the Android P release.
 */
interface ICameraDevice {
    ......
    /**
     * Start preview mode.
     *
     * @return status The status code for this operation.
     */
    startPreview() generates (Status status);
    ......

总结一下流程图如下:

在这里插入图片描述

再来分析 Camera2Client,结合注释不难理解,Camera2Client 代表 android.hardware.Camera API 和 Camera HAL 设备之间的接口,支持 CAMERA_DEVICE_API_VERSION_3_0 及以上版本。

但 Camera2Client 并没有直接继承 CameraService::Client,而是继承了 Camera2ClientBase<CameraService::Client>,这个模板类中一定有答案!

frameworks/av/services/camera/libcameraservice/api1/Camera2Client.h

namespace android {

namespace camera2 {
......
}
......
/**
 * Interface between android.hardware.Camera API and Camera HAL device for versions
 * CAMERA_DEVICE_API_VERSION_3_0 and above.
 */
class Camera2Client :
        public Camera2ClientBase<CameraService::Client>
{
public:
    /**
     * ICamera interface (see ICamera for details)
     */
    ......
    virtual status_t        startPreview();
    ......
};

}; // namespace android

果然 Camera2ClientBase 继承了 TClientBase,相当于 Camera2Client 间接继承了 CameraService::Client。

frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.h

namespace android {
......
template <typename TClientBase>
class Camera2ClientBase :
        public TClientBase,
        public CameraDeviceBase::NotificationListener
{
public:
    ......
};

}; // namespace android    

Camera2Client::startPreview() -> Camera2Client::startPreviewL(Parameters &params, bool restart)。

Camera2Client::startPreviewL(…) 主要步骤如下:

  1. 如果预览已经激活(Parameters::PREVIEW、Parameters::RECORD 或 Parameters::VIDEO_SNAPSHOT),并且不重启(restart 参数表示重启),直接返回 OK。
  2. 如果参数的状态大于 Parameters::PREVIEW 并且不重启的情况下,则操作无效,返回 INVALID_OPERATION。
  3. 调用 StreamingProcessor::haveValidPreviewWindow() 获取是否存在有效的预览窗口,如果不存在就将状态设置为 Parameters::WAITING_FOR_PREVIEW_WINDOW (表示等待预览窗口就绪)直接返回 OK。
  4. 先把参数状态设置为停止状态 Parameters::STOPPED。
  5. 调用 StreamingProcessor::getPreviewStreamId() 获取预览流 ID。
  6. 调用 StreamingProcessor::updatePreviewStream(…) 更新预览流(内部会创建流,更新流 ID),更新不成功直接返回对应的错误码。
  7. 再次调用 StreamingProcessor::getPreviewStreamId() 获取预览流 ID,检查是否预览流有变化,第一次调用此处流 ID 会从 NO_STREAM 过渡到实际流 ID。
  8. 调用 JpegProcessor::getStreamId() 获取 Jpeg(捕获)流 ID。
  9. Jpeg 流会减慢预览,确保在开始预览前删除它。先调用 StreamingProcessor::getActiveRequestId() 获取激活的请求 ID(activeRequestId),如果 activeRequestId 不等于 0,则调用 StreamingProcessor::togglePauseStream(…) 暂停流,接下来调用 JpegProcessor::deleteStream() 删除 Jpeg 流,最后再调用 StreamingProcessor::togglePauseStream(…) 启用流。
  10. 如果没有启用 slowJpegMode,调用 Camera2Client::updateProcessorStream(…) 更新 Jpeg 流相关参数。
  11. 检查 Jpeg 流 ID 是否有变化,反映到 jpegStreamChanged 这个布尔变量上。
  12. 检查预览回调是否设置,或者参数中 previewCallbackSurface 被设置都要进入 callbacksEnabled 为 true 的这个分支,这里首先调用 StreamingProcessor::getRecordingStreamId() 获取录制流 ID,如果不为 NO_STREAM,先调用 StreamingProcessor::stopStream() 停止流,接着调用 StreamingProcessor::deleteRecordingStream() 删除录制流,最后调用 CallbackProcessor::updateStream() 更新回调流。
  13. 如果预览流已经变化,并且存在回调流时,先要调用 CallbackProcessor::deleteStream() 删除回调流。
  14. 如果使用 ZSL,并且录制流 ID 不为 NO_STREAM,则更新 Camera2Client::updateProcessorStream(…) 更新 ZSL 流相关参数。当 Jpeg 大小改变时清除 ZSL 缓冲区队列通过调用 ZslProcessor::clearZslQueue() 实现。
  15. 如果不使用 ZSL,直接调用 ZslProcessor::deleteStream() 删除 ZSL 流。
  16. 如果不是录制,也不是重启,则调用 StreamingProcessor::updatePreviewRequest(…) 更新预览请求,接下来调用 StreamingProcessor::startStream(…) 开启预览流。
  17. 如果是录制,不是重启,则调用 StreamingProcessor::updateRecordingRequest(…) 更新录制请求,接下来调用 StreamingProcessor::startStream(…) 开启录制流。
  18. 最后将参数状态设置为预览状态 Parameters::PREVIEW,返回 OK。

frameworks/av/services/camera/libcameraservice/api1/Camera2Client.cpp

status_t Camera2Client::startPreview() {
    ATRACE_CALL();
    ALOGV("%s: E", __FUNCTION__);
    Mutex::Autolock icl(mBinderSerializationLock);
    status_t res;
    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
    SharedParameters::Lock l(mParameters);
    return startPreviewL(l.mParameters, false);
}


status_t Camera2Client::startPreviewL(Parameters &params, bool restart) {
    ATRACE_CALL();
    status_t res;

    ALOGV("%s: state == %d, restart = %d", __FUNCTION__, params.state, restart);

    if ( (params.state == Parameters::PREVIEW ||
                    params.state == Parameters::RECORD ||
                    params.state == Parameters::VIDEO_SNAPSHOT)
            && !restart) {
        // Succeed attempt to re-enter a streaming state
        ALOGI("%s: Camera %d: Preview already active, ignoring restart",
                __FUNCTION__, mCameraId);
        return OK;
    }
    if (params.state > Parameters::PREVIEW && !restart) {
        ALOGE("%s: Can't start preview in state %s",
                __FUNCTION__,
                Parameters::getStateName(params.state));
        return INVALID_OPERATION;
    }

    if (!mStreamingProcessor->haveValidPreviewWindow()) {
        params.state = Parameters::WAITING_FOR_PREVIEW_WINDOW;
        return OK;
    }
    params.state = Parameters::STOPPED;
    int lastPreviewStreamId = mStreamingProcessor->getPreviewStreamId();

    res = mStreamingProcessor->updatePreviewStream(params);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to update preview stream: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        return res;
    }

    bool previewStreamChanged = mStreamingProcessor->getPreviewStreamId() != lastPreviewStreamId;

    // We could wait to create the JPEG output stream until first actual use
    // (first takePicture call). However, this would substantially increase the
    // first capture latency on HAL3 devices.
    // So create it unconditionally at preview start. As a drawback,
    // this increases gralloc memory consumption for applications that don't
    // ever take a picture. Do not enter this mode when jpeg stream will slow
    // down preview.
    // TODO: Find a better compromise, though this likely would involve HAL
    // changes.
    int lastJpegStreamId = mJpegProcessor->getStreamId();
    // If jpeg stream will slow down preview, make sure we remove it before starting preview
    if (params.slowJpegMode) {
        if (lastJpegStreamId != NO_STREAM) {
            // Pause preview if we are streaming
            int32_t activeRequestId = mStreamingProcessor->getActiveRequestId();
            if (activeRequestId != 0) {
                res = mStreamingProcessor->togglePauseStream(/*pause*/true);
                if (res != OK) {
                    ALOGE("%s: Camera %d: Can't pause streaming: %s (%d)",
                            __FUNCTION__, mCameraId, strerror(-res), res);
                }
                res = mDevice->waitUntilDrained();
                if (res != OK) {
                    ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
                            __FUNCTION__, mCameraId, strerror(-res), res);
                }
            }

            res = mJpegProcessor->deleteStream();

            if (res != OK) {
                ALOGE("%s: Camera %d: delete Jpeg stream failed: %s (%d)",
                        __FUNCTION__, mCameraId,  strerror(-res), res);
            }

            if (activeRequestId != 0) {
                res = mStreamingProcessor->togglePauseStream(/*pause*/false);
                if (res != OK) {
                    ALOGE("%s: Camera %d: Can't unpause streaming: %s (%d)",
                            __FUNCTION__, mCameraId, strerror(-res), res);
                }
            }
        }
    } else {
        res = updateProcessorStream(mJpegProcessor, params);
        if (res != OK) {
            ALOGE("%s: Camera %d: Can't pre-configure still image "
                    "stream: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }
    }
    bool jpegStreamChanged = mJpegProcessor->getStreamId() != lastJpegStreamId;

    Vector<int32_t> outputStreams;
    bool callbacksEnabled = (params.previewCallbackFlags &
            CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) ||
            params.previewCallbackSurface;

    if (callbacksEnabled) {
        // Can't have recording stream hanging around when enabling callbacks,
        // since it exceeds the max stream count on some devices.
        if (mStreamingProcessor->getRecordingStreamId() != NO_STREAM) {
            ALOGV("%s: Camera %d: Clearing out recording stream before "
                    "creating callback stream", __FUNCTION__, mCameraId);
            res = mStreamingProcessor->stopStream();
            if (res != OK) {
                ALOGE("%s: Camera %d: Can't stop streaming to delete "
                        "recording stream", __FUNCTION__, mCameraId);
                return res;
            }
            res = mStreamingProcessor->deleteRecordingStream();
            if (res != OK) {
                ALOGE("%s: Camera %d: Unable to delete recording stream before "
                        "enabling callbacks: %s (%d)", __FUNCTION__, mCameraId,
                        strerror(-res), res);
                return res;
            }
        }

        res = mCallbackProcessor->updateStream(params);
        if (res != OK) {
            ALOGE("%s: Camera %d: Unable to update callback stream: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }
        outputStreams.push(getCallbackStreamId());
    } else if (previewStreamChanged && mCallbackProcessor->getStreamId() != NO_STREAM) {
        /**
         * Delete the unused callback stream when preview stream is changed and
         * preview is not enabled. Don't need stop preview stream as preview is in
         * STOPPED state now.
         */
        ALOGV("%s: Camera %d: Delete unused preview callback stream.",  __FUNCTION__, mCameraId);
        res = mCallbackProcessor->deleteStream();
        if (res != OK) {
            ALOGE("%s: Camera %d: Unable to delete callback stream %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }
    }

    if (params.useZeroShutterLag() &&
            getRecordingStreamId() == NO_STREAM) {
        res = updateProcessorStream(mZslProcessor, params);
        if (res != OK) {
            ALOGE("%s: Camera %d: Unable to update ZSL stream: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            return res;
        }

        if (jpegStreamChanged) {
            ALOGV("%s: Camera %d: Clear ZSL buffer queue when Jpeg size is changed",
                    __FUNCTION__, mCameraId);
            mZslProcessor->clearZslQueue();
        }
        outputStreams.push(getZslStreamId());
    } else {
        mZslProcessor->deleteStream();
    }

    outputStreams.push(getPreviewStreamId());

    if (params.isDeviceZslSupported) {
        // If device ZSL is supported, resume preview buffers that may be paused
        // during last takePicture().
        mDevice->dropStreamBuffers(false, getPreviewStreamId());
    }

    if (!params.recordingHint) {
        if (!restart) {
            res = mStreamingProcessor->updatePreviewRequest(params);
            if (res != OK) {
                ALOGE("%s: Camera %d: Can't set up preview request: "
                        "%s (%d)", __FUNCTION__, mCameraId,
                        strerror(-res), res);
                return res;
            }
        }
        res = mStreamingProcessor->startStream(StreamingProcessor::PREVIEW,
                outputStreams);
    } else {
        if (!restart) {
            res = mStreamingProcessor->updateRecordingRequest(params);
            if (res != OK) {
                ALOGE("%s: Camera %d: Can't set up preview request with "
                        "record hint: %s (%d)", __FUNCTION__, mCameraId,
                        strerror(-res), res);
                return res;
            }
        }
        res = mStreamingProcessor->startStream(StreamingProcessor::RECORD,
                outputStreams);
    }
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to start streaming preview: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
        return res;
    }

    params.state = Parameters::PREVIEW;
    return OK;
}
  1. mDevice 是指向 CameraDeviceBase 的弱指针,先调用 promote() 转换为强指针。
  2. 如果预览流 ID 已经存在,检查参数是否变化,如果预览宽高已经改变,调用 Camera3Device::deleteStream(…) 删除流,并给 mPreviewStreamId 赋值为 NO_STREAM 。
  3. mPreviewStreamId 为 NO_STREAM 则调用 Camera3Device::createStream(…) 创建流。

mDevice 的值取自 Camera2Client::getCameraDevice(),但 Camera2Client 没有实现 getCameraDevice() 方法,所以实现其实在父类 Camera2ClientBase 中。

frameworks/av/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp

StreamingProcessor::StreamingProcessor(sp<Camera2Client> client):
        mClient(client),
        mDevice(client->getCameraDevice()),
        mId(client->getCameraId()),
        mActiveRequest(NONE),
        mPaused(false),
        mPreviewRequestId(Camera2Client::kPreviewRequestIdStart),
        mPreviewStreamId(NO_STREAM),
        mRecordingRequestId(Camera2Client::kRecordingRequestIdStart),
        mRecordingStreamId(NO_STREAM)
{
}
......
status_t StreamingProcessor::updatePreviewStream(const Parameters &params) {
    ATRACE_CALL();
    Mutex::Autolock m(mMutex);

    status_t res;
    sp<CameraDeviceBase> device = mDevice.promote();
    if (device == 0) {
        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
        return INVALID_OPERATION;
    }

    if (mPreviewStreamId != NO_STREAM) {
        // Check if stream parameters have to change
        CameraDeviceBase::StreamInfo streamInfo;
        res = device->getStreamInfo(mPreviewStreamId, &streamInfo);
        if (res != OK) {
            ALOGE("%s: Camera %d: Error querying preview stream info: "
                    "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
            return res;
        }
        if (streamInfo.width != (uint32_t)params.previewWidth ||
                streamInfo.height != (uint32_t)params.previewHeight) {
            ALOGV("%s: Camera %d: Preview size switch: %d x %d -> %d x %d",
                    __FUNCTION__, mId, streamInfo.width, streamInfo.height,
                    params.previewWidth, params.previewHeight);
            res = device->waitUntilDrained();
            if (res != OK) {
                ALOGE("%s: Camera %d: Error waiting for preview to drain: "
                        "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
                return res;
            }
            res = device->deleteStream(mPreviewStreamId);
            if (res != OK) {
                ALOGE("%s: Camera %d: Unable to delete old output stream "
                        "for preview: %s (%d)", __FUNCTION__, mId,
                        strerror(-res), res);
                return res;
            }
            mPreviewStreamId = NO_STREAM;
        }
    }

    if (mPreviewStreamId == NO_STREAM) {
        res = device->createStream(mPreviewWindow,
                params.previewWidth, params.previewHeight,
                CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, HAL_DATASPACE_UNKNOWN,
                CAMERA3_STREAM_ROTATION_0, &mPreviewStreamId, String8());
        if (res != OK) {
            ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)",
                    __FUNCTION__, mId, strerror(-res), res);
            return res;
        }
    }

    res = device->setStreamTransform(mPreviewStreamId,
            params.previewTransform);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to set preview stream transform: "
                "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
        return res;
    }

    return OK;
}

Camera2ClientBase::getCameraDevice() 直接返回 mDevice,mDevice 是在其构造函数中初始化的,实际为指向 Camera3Device 对象的指针。

frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp

template <typename TClientBase>
Camera2ClientBase<TClientBase>::Camera2ClientBase(
        const sp<CameraService>& cameraService,
        const sp<TCamCallbacks>& remoteCallback,
        const String16& clientPackageName,
        const String8& cameraId,
        int api1CameraId,
        int cameraFacing,
        int clientPid,
        uid_t clientUid,
        int servicePid):
        TClientBase(cameraService, remoteCallback, clientPackageName,
                cameraId, api1CameraId, cameraFacing, clientPid, clientUid, servicePid),
        mSharedCameraCallbacks(remoteCallback),
        mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
        mDevice(new Camera3Device(cameraId)),
        mDeviceActive(false), mApi1CameraId(api1CameraId)
{
    ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
            String8(clientPackageName).string(), clientPid, clientUid);

    mInitialClientPid = clientPid;
    LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}
......
template <typename TClientBase>
const sp<CameraDeviceBase>& Camera2ClientBase<TClientBase>::getCameraDevice() {
    return mDevice;
}

CameraDeviceBase 是 Camera device 版本 >= 2 的基础接口,接口到 Camera HAL device 版本 >= 2。Camera3Device 继承了它。

setStreamingRequest ———— 提交流媒体请求。CameraDevice 复制一个传入的缓冲区,调用者保留所有权。输出 lastFrameNumber 是前一个流请求的最后一个帧号。

createStream ———— 创建请求的 size、format、rotation 和 dataspace 的输出流。对于 HAL_PIXEL_FORMAT_BLOB 格式,宽度和高度应该是缓冲区的逻辑尺寸,而不是字节数。另一个版本 createStream 为传入多个消费者。

waitUntilDrained ———— 等待,直到所有请求都被处理。如果流 slot 不是空的,返回 INVALID_OPERATION,如果请求在 10 秒内没有完成处理,返回 TIMED_OUT。

frameworks/av/services/camera/libcameraservice/common/CameraDeviceBase.h


namespace android {
......
/**
 * Base interface for version >= 2 camera device classes, which interface to
 * camera HAL device versions >= 2.
 */
class CameraDeviceBase : public virtual RefBase {
  public:
    /**
     * Submit request for streaming. The CameraDevice makes a copy of the
     * passed-in buffer and the caller retains ownership.
     * Output lastFrameNumber is the last frame number of the previous streaming request.
     */
    virtual status_t setStreamingRequest(const CameraMetadata &request,
                                         int64_t *lastFrameNumber = NULL) = 0;
    ......
    /**
     * Create an output stream of the requested size, format, rotation and dataspace
     *
     * For HAL_PIXEL_FORMAT_BLOB formats, the width and height should be the
     * logical dimensions of the buffer, not the number of bytes.
     */
    virtual status_t createStream(sp<Surface> consumer,
            uint32_t width, uint32_t height, int format,
            android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
            const String8& physicalCameraId,
            std::vector<int> *surfaceIds = nullptr,
            int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
            bool isShared = false, uint64_t consumerUsage = 0) = 0;

    /**
     * Create an output stream of the requested size, format, rotation and
     * dataspace with a number of consumers.
     *
     * For HAL_PIXEL_FORMAT_BLOB formats, the width and height should be the
     * logical dimensions of the buffer, not the number of bytes.
     */
    virtual status_t createStream(const std::vector<sp<Surface>>& consumers,
            bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
            android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
            const String8& physicalCameraId,
            std::vector<int> *surfaceIds = nullptr,
            int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
            bool isShared = false, uint64_t consumerUsage = 0) = 0;
    ......
    /**
     * Wait until all requests have been processed. Returns INVALID_OPERATION if
     * the streaming slot is not empty, or TIMED_OUT if the requests haven't
     * finished processing in 10 seconds.
     */
    virtual status_t waitUntilDrained() = 0;
    ......
};

}; // namespace android

Camera3Device 继承了 CameraDeviceBase,它表示 CameraDevice 用于版本为 CAMERA_DEVICE_API_VERSION_3_0 或更高的 HAL 设备。

frameworks/av/services/camera/libcameraservice/device3/Camera3Device.h

/**
 * CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_3_0 or higher.
 */
class Camera3Device :
            public CameraDeviceBase,
            virtual public hardware::camera::device::V3_5::ICameraDeviceCallback {
    ......
}; // class Camera3Device

现在重点来关注 Camera3Device::createStream(…) 创建流。startPreview 流程调用的是单个消费者版本的 createStream(…),但从源码不难看出实际上最终还是调用的多消费者版本的 createStream(…)。

  1. 判断当前状态是否能够创建流,如果状态为 STATUS_ERROR、STATUS_UNINITIALIZED 直接返回 INVALID_OPERATION,如果状态为 STATUS_UNCONFIGURED 或 STATUS_CONFIGURED 表示可以正常下一步,如果为状态为 STATUS_ACTIVE,则先要调用 internalPauseAndWaitLocked(…) 停止活动以重新配置流,并将 wasActive 置为 true。
  2. 根据不同的格式等去构建 Camera3OutputStream 构造时需要的参数,new 一个 Camera3OutputStream 出来。当前流程 isShared 为 false,所以不会去构建 Camera3SharedOutputStream。
  3. 如果 wasActive 为 true,调用 configureStreamsLocked(…) 为新的流配置重用当前的操作模式和会话参数,最后调用 internalResumeLocked() 恢复活动。

Camera3OutputStream 是用于管理来自相机设备的单个输出数据流的类。

frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

status_t Camera3Device::createStream(sp<Surface> consumer,
            uint32_t width, uint32_t height, int format,
            android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
            const String8& physicalCameraId,
            std::vector<int> *surfaceIds, int streamSetId, bool isShared, uint64_t consumerUsage) {
    ATRACE_CALL();

    if (consumer == nullptr) {
        ALOGE("%s: consumer must not be null", __FUNCTION__);
        return BAD_VALUE;
    }

    std::vector<sp<Surface>> consumers;
    consumers.push_back(consumer);

    return createStream(consumers, /*hasDeferredConsumer*/ false, width, height,
            format, dataSpace, rotation, id, physicalCameraId, surfaceIds, streamSetId,
            isShared, consumerUsage);
}

status_t Camera3Device::createStream(const std::vector<sp<Surface>>& consumers,
        bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
        android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id,
        const String8& physicalCameraId,
        std::vector<int> *surfaceIds, int streamSetId, bool isShared, uint64_t consumerUsage) {
    ATRACE_CALL();

    Mutex::Autolock il(mInterfaceLock);
    nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
    Mutex::Autolock l(mLock);
    ALOGV("Camera %s: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d"
            " consumer usage %" PRIu64 ", isShared %d, physicalCameraId %s", mId.string(),
            mNextStreamId, width, height, format, dataSpace, rotation, consumerUsage, isShared,
            physicalCameraId.string());

    status_t res;
    bool wasActive = false;

    switch (mStatus) {
        case STATUS_ERROR:
            CLOGE("Device has encountered a serious error");
            return INVALID_OPERATION;
        case STATUS_UNINITIALIZED:
            CLOGE("Device not initialized");
            return INVALID_OPERATION;
        case STATUS_UNCONFIGURED:
        case STATUS_CONFIGURED:
            // OK
            break;
        case STATUS_ACTIVE:
            ALOGV("%s: Stopping activity to reconfigure streams", __FUNCTION__);
            res = internalPauseAndWaitLocked(maxExpectedDuration);
            if (res != OK) {
                SET_ERR_L("Can't pause captures to reconfigure streams!");
                return res;
            }
            wasActive = true;
            break;
        default:
            SET_ERR_L("Unexpected status: %d", mStatus);
            return INVALID_OPERATION;
    }
    assert(mStatus != STATUS_ACTIVE);

    sp<Camera3OutputStream> newStream;

    if (consumers.size() == 0 && !hasDeferredConsumer) {
        ALOGE("%s: Number of consumers cannot be smaller than 1", __FUNCTION__);
        return BAD_VALUE;
    }

    if (hasDeferredConsumer && format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
        ALOGE("Deferred consumer stream creation only support IMPLEMENTATION_DEFINED format");
        return BAD_VALUE;
    }

    if (format == HAL_PIXEL_FORMAT_BLOB) {
        ssize_t blobBufferSize;
        if (dataSpace == HAL_DATASPACE_DEPTH) {
            blobBufferSize = getPointCloudBufferSize();
            if (blobBufferSize <= 0) {
                SET_ERR_L("Invalid point cloud buffer size %zd", blobBufferSize);
                return BAD_VALUE;
            }
        } else if (dataSpace == static_cast<android_dataspace>(HAL_DATASPACE_JPEG_APP_SEGMENTS)) {
            blobBufferSize = width * height;
        } else {
            blobBufferSize = getJpegBufferSize(width, height);
            if (blobBufferSize <= 0) {
                SET_ERR_L("Invalid jpeg buffer size %zd", blobBufferSize);
                return BAD_VALUE;
            }
        }
        newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
                width, height, blobBufferSize, format, dataSpace, rotation,
                mTimestampOffset, physicalCameraId, streamSetId);
    } else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
        ssize_t rawOpaqueBufferSize = getRawOpaqueBufferSize(width, height);
        if (rawOpaqueBufferSize <= 0) {
            SET_ERR_L("Invalid RAW opaque buffer size %zd", rawOpaqueBufferSize);
            return BAD_VALUE;
        }
        newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
                width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
                mTimestampOffset, physicalCameraId, streamSetId);
    } else if (isShared) {
        newStream = new Camera3SharedOutputStream(mNextStreamId, consumers,
                width, height, format, consumerUsage, dataSpace, rotation,
                mTimestampOffset, physicalCameraId, streamSetId,
                mUseHalBufManager);
    } else if (consumers.size() == 0 && hasDeferredConsumer) {
        newStream = new Camera3OutputStream(mNextStreamId,
                width, height, format, consumerUsage, dataSpace, rotation,
                mTimestampOffset, physicalCameraId, streamSetId);
    } else {
        newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
                width, height, format, dataSpace, rotation,
                mTimestampOffset, physicalCameraId, streamSetId);
    }

    size_t consumerCount = consumers.size();
    for (size_t i = 0; i < consumerCount; i++) {
        int id = newStream->getSurfaceId(consumers[i]);
        if (id < 0) {
            SET_ERR_L("Invalid surface id");
            return BAD_VALUE;
        }
        if (surfaceIds != nullptr) {
            surfaceIds->push_back(id);
        }
    }

    newStream->setStatusTracker(mStatusTracker);

    newStream->setBufferManager(mBufferManager);

    res = mOutputStreams.add(mNextStreamId, newStream);
    if (res < 0) {
        SET_ERR_L("Can't add new stream to set: %s (%d)", strerror(-res), res);
        return res;
    }

    *id = mNextStreamId++;
    mNeedConfig = true;

    // Continue captures if active at start
    if (wasActive) {
        ALOGV("%s: Restarting activity to reconfigure streams", __FUNCTION__);
        // Reuse current operating mode and session parameters for new stream config
        res = configureStreamsLocked(mOperatingMode, mSessionParams);
        if (res != OK) {
            CLOGE("Can't reconfigure device for new stream %d: %s (%d)",
                    mNextStreamId, strerror(-res), res);
            return res;
        }
        internalResumeLocked();
    }
    ALOGV("Camera %s: Created new stream", mId.string());
    return OK;
}

最后来关注一下 StreamingProcessor::startStream(…) 开启录制流。主要调用了 Camera3Device::setStreamingRequest(…) 提交流媒体请求。后续流程和 Camera2 预览流程是一致的,这和架构图是匹配的。Android 源码 Camera2 架构相关文档参考《Android 源码 Camera2 架构初识

frameworks/av/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp

status_t StreamingProcessor::startStream(StreamType type,
        const Vector<int32_t> &outputStreams) {
    ATRACE_CALL();
    status_t res;

    if (type == NONE) return INVALID_OPERATION;

    sp<CameraDeviceBase> device = mDevice.promote();
    if (device == 0) {
        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
        return INVALID_OPERATION;
    }

    ALOGV("%s: Camera %d: type = %d", __FUNCTION__, mId, type);

    Mutex::Autolock m(mMutex);

    CameraMetadata &request = (type == PREVIEW) ?
            mPreviewRequest : mRecordingRequest;

    res = request.update(
        ANDROID_REQUEST_OUTPUT_STREAMS,
        outputStreams);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to set up preview request: %s (%d)",
                __FUNCTION__, mId, strerror(-res), res);
        return res;
    }

    res = request.sort();
    if (res != OK) {
        ALOGE("%s: Camera %d: Error sorting preview request: %s (%d)",
                __FUNCTION__, mId, strerror(-res), res);
        return res;
    }

    res = device->setStreamingRequest(request);
    if (res != OK) {
        ALOGE("%s: Camera %d: Unable to set preview request to start preview: "
                "%s (%d)",
                __FUNCTION__, mId, strerror(-res), res);
        return res;
    }
    mActiveRequest = type;
    mPaused = false;
    mActiveStreamIds = outputStreams;
    return OK;
}

总结一下流程图如下:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TYYJ-洪伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值