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 firstvirtual 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 firststatus_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 doneif (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:

【Android 10 源码】Camera v1 startPreview 流程相关推荐

  1. 【Android 10 源码】MediaRecorder 录像流程:MediaRecorder 初始化

    MediaRecorder 用于录制音频和视频,录制控制基于一个简单的状态机.下面是典型的使用 camera2 API 录制,需要使用到的 MediaRecorder API. MediaRecord ...

  2. 【Android 10 源码】MediaRecorder 录像流程:MediaRecorder 配置

    MediaRecorder 录像配置主要涉及输出文件路径.音频来源.视频来源.输出格式.音频编码格式.视频编码格式.比特率.帧率和视频尺寸等. 我们假设视频输入源来自 Camera,Camera2 A ...

  3. 【Android 10 源码】MediaRecorder 录像流程:MediaRecorder 开始录制

    前面已经分析过 MediaRecorder 初始化和配置过程,接下来就可以真正进入录制流程了.现在不难得出这个结论:MediaRecorder 录制 Camera 的数据实际上是将预览数据经过 Med ...

  4. 【Android 10 源码】healthd 模块 HAL 2.0 分析

    Android 9 引入了从 health@1.0 HAL 升级的主要版本 android.hardware.health HAL 2.0.这一新 HAL 具有以下优势: 框架代码和供应商代码之间的区 ...

  5. 【Android 10 源码】深入理解 MediaCodec 组件分配

    MediaCodec 系列文章: [Android 10 源码]深入理解 MediaCodec 硬解码初始化 [Android 10 源码]深入理解 Omx 初始化 [Android 10 源码]深入 ...

  6. Ubuntu18.04 编译Android 10源码 并烧录源码到pixel3的避坑指南

    Ubuntu18.04 编译Android 10源码 并烧录源码到pixel3的避坑指南 实验环境 下载Android源码树 在pixel3上安装手机驱动版本 编译Android源码 Android ...

  7. 【Android 10 源码】深入理解 Omx 初始化

    MediaCodec 系列文章: [Android 10 源码]深入理解 MediaCodec 硬解码初始化 [Android 10 源码]深入理解 Omx 初始化 [Android 10 源码]深入 ...

  8. 【Android 10 源码】深入理解 software Codec2 服务启动

    MediaCodec 系列文章: [Android 10 源码]深入理解 MediaCodec 硬解码初始化 [Android 10 源码]深入理解 Omx 初始化 [Android 10 源码]深入 ...

  9. Android 音频源码分析——音量调节流程

    源码分析基于android9.0 一.声音类型 对于大多数手机用户来说,操作手机音量按键可以看到,声音类型分为四种:媒体.铃声.闹钟.通话,但是其系统内部则分为十几种类型. 声⾳类型用来区分不同播放用 ...

最新文章

  1. 开发日记-20190330
  2. Microsoft Visual Studio 2005 Beta 2 下载地址
  3. MSM8225 thermal设计
  4. oracle 得到一个树,Related to Oracle SQL 关于树形数据的遍历
  5. 一篇需要膜拜的文篇--Javascript异步编程模型进化(转)
  6. matlab 如何画二维图形,Matlab 学习 画图篇 一 二维图形
  7. java 弹幕游戏_JAVA 弹幕小游戏 1.0版本
  8. Android Camera setRecordingHint函数 在部分手机上的问题。
  9. 高等代数第3版下 [丘维声 著] 2015年版_2020年成人高考 专升本 高等数学复习攻略...
  10. UE的HoudiniEngine插件版本的匹配问题
  11. Windows勒索病毒“永恒之蓝”漏洞补丁包
  12. gitee和gitHub的命令和详细步骤操作
  13. 贪心算法解决雷达站建站问题
  14. 育儿书籍阅读顺序的建议
  15. 高仿富途牛牛-组件化(六)-炒鸡牛逼的布局记忆功能(序列化和反序列化)
  16. OpenCV 实时对象跟踪(质心跟踪)
  17. Linux内核4.14版本——mmc core(4)——card相关模块(mmc type card)
  18. 正则表达式-贪婪匹配与懒惰匹配之获取短信验证码
  19. 安装r 源代码 linux,在RStudio中从源代码安装R软件包时遇到问题-Ubuntu 16.04
  20. 计算机应用在航天,国产CPU的航天计算机应用

热门文章

  1. IMX6UL eMMC初始化流程
  2. 2019年,智能手机的交棒时刻
  3. 为什么不建议直接使用 @Async 注解
  4. 深度学习-LeCun、Bengio和Hinton的联合综述(下)
  5. 浅谈react和vue
  6. js获取后台返回的数据
  7. [C++练手项目] DocAnalysis
  8. LaTex排版之Texmaker安装
  9. R包安装时安装程序包****时退出的状态不是0,或者版本不适的一种解决方法。
  10. demo-原生js实现你说我猜小游戏