android之camera从上到下

Android之camera从上到下
如果你想了解一下android的camera的大致框架内容看看我附带的图片就可以达到要求。不过图片毕竟比较抽象,还是然我们看下源码吧!
源码从APP到硬件抽象层,以这中从上到下的调用流程非常清晰。大家可以很容易看懂。我想带大家看的是camera从摄像头捕获一帧数据如何送到android的surface并且显示出来的。在framework\base\libs\camera.cpp 中有setPreviewDisplay,当然这个Surface是从应用层的Surface.java一步一步传进来的。Camera.java(activity)里面的startPreview函数就是开始预览的,这里就调用了setPreviewDisplay(mSurfaceHolder);至于SurfaceHolder是什么东西不用我多说了。再到Camera.java(hardware)这个实际就是与jni的接口了
这里面就会通过Holder来获取Surface,然后通过jni将Surface设置进来:
static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface)
{
LOGV("setPreviewDisplay");
sp<Camera> camera = get_native_camera(env, thiz, NULL);
if (camera == 0) return;

sp<Surface> surface = NULL;
if (jSurface != NULL) {
surface = reinterpret_cast<Surface*>(env->GetIntField(jSurface, fields.surface));
}
if (camera->setPreviewDisplay(surface) != NO_ERROR) {
jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed");
}
}
从代码可以看到surface是做了一些变化的,surface = reinterpret_cast<Surface*>(env->GetIntField(jSurface, fields.surface));具体你看下Surface.java就知道了,这个Surface实际是native层的surface(class Surface : public EGLNativeBase<ANativeWindow, Surface, RefBase>);回到jni来,紧接着就将这个Surface设到了camera的客户端了(BnCameraClient)这个可以看图。
status_t Camera::setPreviewDisplay(const sp<Surface>& surface)
{
LOGV("setPreviewDisplay");
sp <ICamera> c = mCamera;
if (c == 0) return NO_INIT;
if (surface != 0) {
return c->setPreviewDisplay(surface->getISurface());
} else {
LOGD("app passed NULL surface");
return c->setPreviewDisplay(0);
}
}
这里又对调用了getISurface来获取另一个surface,此处的surface才是真做事的surface,管理它的正是surfaceFlinger,这个会在下一篇博客中解释。在这里可以说这个Surface其实就是SurfaceLayer(继承自LayerBaseClient::Surface),回到BnCameraClient,继续调用BnCamera的setPreviewDisplay将surface进行了保存mSurface = surface;
来到startPreview可以看到会点调用mHardware->startPreview();然后registerPreviewBuffers;对于mHardware它是不同的厂家来实现的,就是开了一个线程不断的从camera传感器获取数据,至于registerPreviewBuffers是关键,它将CameraHardware里面的内存(存储帧数据的缓存)注册到了Surface。仔细看的话你会发现这写内存可以存储8帧(不同厂家不一样)它是一块类似环形的buffer。看过代码的人应该都知道,在预览之前我们会先设置两个回调dataCallback和dataCallbackTimestamp,这两个的区别在于前者用于预览,而后者用于录制。我们看dataCallback:
void CameraService::Client::dataCallback(int32_t msgType,
const sp<IMemory>& dataPtr, void* user) {
LOG2("dataCallback(%d)", msgType);

sp<Client> client = getClientFromCookie(user);
if (client == 0) return;
if (!client->lockIfMessageWanted(msgType)) return;

if (dataPtr == 0) {
LOGE("Null data returned in data callback");
client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
return;
}

switch (msgType) {
case CAMERA_MSG_PREVIEW_FRAME:
client->handlePreviewData(dataPtr);
break;
case CAMERA_MSG_POSTVIEW_FRAME:
client->handlePostview(dataPtr);
break;
case CAMERA_MSG_RAW_IMAGE:
client->handleRawPicture(dataPtr);
break;
case CAMERA_MSG_COMPRESSED_IMAGE:
client->handleCompressedPicture(dataPtr);
break;
default:
client->handleGenericData(msgType, dataPtr);
break;
}
}
因为是Preview所以会到 client->handlePreviewData(dataPtr);而这个里面会有这样一句话mSurface->postBuffer(offset);看到了吧,就是说标号为offset的这块内存有数据拉,通知surfaceFlinger刷新这块内存将画面绘制到用户可见的Surface上面去。

先就这样吧,下回继续。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值