分享

android之camera从上到下

 liluvu 2013-03-15
   如果你想了解一下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条评论

    发表

    请遵守用户 评论公约

    类似文章 更多