Android 13 Camera HAL启动流程(1)

欢迎关注微信公众号 无限无羡

前言

不积跬步,无以至千里;不积小流,无以成江海。

本章将作为Android Camera系列的开篇,后续将会持续输出相关文章,尽可能的形成一个完整的系列内容。全部更新完毕时间可能会比较长,因为Camera的东西其实很多的,本人也需要不断的学习和深入。由于目前对Camera驱动的内容了解的不多,所以驱动的内容会放到最后来讲,还希望大家理解和耐心等待,如果文章中有错误或者大家有想交流的内容都可以直接跟我交流,我们一起学习!

我们会先介绍Camera相关服务的启动流程,然后再讲解Camera的业务调用流程。原因是系统开机时Camera服务会进行一系列的初始化,这样上层应用使用Camera功能时就可以节省一些时间和资源,从而加快整个Camera业务流程的效率。我们会先讲Camera HAL服务的启动流程,然后再讲解cameraserver服务的启动流程,最后从上层应用的调用流程来详细分析Camera每个业务(比如预览、拍照、录像等)的具体实现。

所以本章就从Camera HAL服务的启动流程开始,本想用一篇文章来介绍完Camera HAL启动流程的,结果越写越多,写的多了代码就不容易连贯,反而影响阅读体验,故而分为多个章节来介绍,希望能够讲透彻,讲条理,讲清楚。

Android Camera整体架构

Android Camera架构

Camera的整体架构符合标准的Android架构,即App->FWK->HAL->Kernel,只不过在Android8.0之前HAL的so库是被System分区的服务动态加载的,对于camera hal来说就是被cameraserver进程动态加载,hal和cameraserver进程属于同一个进程。在Android8.0之后,Google加入了Treble机制,将HAL放到了独立的进程当中并且位于vendor分区,System服务通过binder访问vendor分区的HAL进程。对于camera来说就是cameraserver进程通过binder访问Camera HAL进程,后者在开机时通过init启动。这样就可以将厂商的私有实现与Google发布的aosp进行隔离,在系统升级时如果厂商的vendor分区没有修改的话,就可以不升级vendor分区,但是厂商必须按照Google定义的标准接口来实现HAL。

CameraProvider

Camera HAL运行在CameraProvider进程当中,目前已经到2.7版本,但是使用最多的是2.4版本,2.4是加入Treble机制后CameraProvider进程的第一个版本,所以我们先从这里开始。
CameraProvider进程是一个native服务,通过init.rc启动
(真正的进程名称是android.hardware.camera.provider@2.4-service_64,这里我们为了简写统一叫成CameraProvider进程)

// hardware/interfaces/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service_64.rc
service vendor.camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provider@2.4-service_64
    interface android.hardware.camera.provider@2.4::ICameraProvider legacy/0
    class hal
    user cameraserver
    group audio camera input drmrpc
    ioprio rt 4
    capabilities SYS_NICE
    task_profiles CameraServiceCapacity MaxPerformance

由上可以看出,进程启动时执行的时二进制/vendor/bin/hw/android.hardware.camera.provider@2.4-service_64,下面我们从Android.bp中找到该二进制的入口文件和入口函数。

// hardware/interfaces/camera/provider/2.4/default/Android.bp
...
cc_binary {
    name: "android.hardware.camera.provider@2.4-service_64",
    defaults: ["camera_service_defaults"],
    compile_multilib: "64",
    init_rc: ["android.hardware.camera.provider@2.4-service_64.rc"],
}
cc_defaults {
    name: "camera_service_defaults",
    defaults: ["hidl_defaults"],
    proprietary: true,
    relative_install_path: "hw",
    srcs: ["service.cpp"], // 二进制入口肯定时service.cpp里面的main函数
    shared_libs: [
        "android.hardware.camera.common@1.0",
        "android.hardware.camera.device@1.0",
        "android.hardware.camera.device@3.2",
        "android.hardware.camera.device@3.3",
        "android.hardware.camera.device@3.4",
        "android.hardware.camera.device@3.5",
        "android.hardware.camera.provider@2.4",
        "android.hardware.graphics.mapper@2.0",
        "android.hardware.graphics.mapper@3.0",
        "android.hardware.graphics.mapper@4.0",
        "android.hidl.allocator@1.0",
        "android.hidl.memory@1.0",
        "libbinder",
        "libcamera_metadata",
        "libcutils",
        "libhardware",
        "libhidlbase",
        "liblog",
        "libutils",
    ],
    static_libs: [
        "android.hardware.camera.common@1.0-helper",
    ],
    header_libs: [
        "camera.device@3.4-external-impl_headers",
        "camera.device@3.4-impl_headers",
        "camera.device@3.5-external-impl_headers",
        "camera.device@3.5-impl_headers",
    ],
}
...

从以上Android.bp文件中可以看出,/vendor/bin/hw/android.hardware.camera.provider@2.4-service_64只包含了一个源文件service.cpp,那么入口函数肯定就是这个cpp里面的main函数了。

// hardware/interfaces/camera/provider/2.4/default/service.cpp
int main()
{
    ALOGI("CameraProvider@2.4 legacy service is starting.");
    // The camera HAL may communicate to other vendor components via
    // /dev/vndbinder
    // 这里表示Camera hal可以跟其他 vendor hal进程通过binder通信,否则不可以
    android::ProcessState::initWithDriver("/dev/vndbinder");

    // b/166675194
    if (property_get_bool("ro.vendor.camera.provider24.disable_mem_init", false)) {
        if (mallopt(M_BIONIC_ZERO_INIT, 0) == 0) {
            // Note - heap initialization is only present on devices with Scudo.
            // Devices with jemalloc don't have heap-init, and thus the mallopt
            // will fail. On these devices, you probably just want to remove the
            // property.
            ALOGE("Disabling heap initialization failed.");
        }
    }

    status_t status;
    if (kLazyService) {
        status = defaultLazyPassthroughServiceImplementation<ICameraProvider>("legacy/0",
                                                                              /*maxThreads*/ 6);
    } else {
    	// kLazyService就是会延迟初始化,我们这里不细讲,后面单出一个章节介绍一下
    	// 启动时会执行下面的函数,这里记下这里的泛型类型为ICameraProvider,还有两个参数,后面有用
        status = defaultPassthroughServiceImplementation<ICameraProvider>("legacy/0",
                                                                          /*maxThreads*/ 6);
    }
    return status;
}

defaultPassthroughServiceImplementation的实现如下:

// system/libhidl/transport/include/hidl/LegacySupport.h
// 这里的两个泛型参数都为ICameraProvider
template <class Interface, class ExpectInterface = Interface>
__attribute__((warn_unused_result)) status_t defaultPassthroughServiceImplementation(
        const std::string& name, size_t maxThreads = 1) {
    // 设置该进程中binder通信线程池的最大线程数,这里maxThreads=6
    configureRpcThreadpool(maxThreads, true);
    // 注意这里的泛型类型为ICameraProvider, 参数name为legacy/0
    status_t result = registerPassthroughServiceImplementation<Interface, ExpectInterface>(name);

    if (result != OK) {
        return result;
    }
	// 把当前线程也就是主线程加入binder线程池
    joinRpcThreadpool();
    return UNKNOWN_ERROR;
}

registerPassthroughServiceImplementation最终会执行到如下函数:

// system/libhidl/transport/include/hidl/LegacySupport.h
template <class Interface, class ExpectInterface = Interface>
__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
        const std::string& name = "default") {
    // 这里Interface和ExpectInterface是ICameraProvider
    // ICameraProvider::descriptor为android.hardware.camera.provider@2.4::ICameraProvider
    // 至于ICameraProvider::descriptor的值哪里赋值的,后面细讲
    return registerPassthroughServiceImplementation(Interface::descriptor,
                                                    ExpectInterface::descriptor, name);
}
// system/libhidl/transport/LegacySupport.cpp
__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
        const std::string& interfaceName, const std::string& expectInterfaceName,
        const std::string& serviceName) {
    // 这里前两个参数为android.hardware.camera.provider@2.4::ICameraProvider,
    // 第三个参数为lambda表达式的一个函数,该函数传入两个参数,然后执行registerAsServiceInternal
    // 第四个参数为legacy/0
    return details::registerPassthroughServiceImplementation(
            interfaceName, expectInterfaceName,
            [](const sp<IBase>& service, const std::string& name) {
                return details::registerAsServiceInternal(service, name);
            },
            serviceName);
}
// system/libhidl/transport/LegacySupport.cpp
// 这个函数主要干了两件事情
// 1. 打开camera hal的so库,初始化Camera Hal,比如获取camera numbers,在getRawServiceInternal里实现
// 2. 将camera hal注册为binder服务,在registerServiceCb里实现,也就是上一步的lamda函数,最终调用的是
// 	  registerAsServiceInternal
__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
        const std::string& interfaceName, const std::string& expectInterfaceName,
        RegisterServiceCb registerServiceCb, const std::string& serviceName) {
    // 这是一个关键函数,第一个参数为android.hardware.camera.provider@2.4::ICameraProvider
    // 第二个参数为 legacy/0
    // 我们下面先分析这个函数,然后再继续
    sp<IBase> service =
            getRawServiceInternal(interfaceName, serviceName, true /*retry*/, true /*getStub*/);

	// 这里我们把后面的代码先省略掉,等getRawServiceInternal函数讲完之后再继续往下分析
    ...
}

getRawServiceInternal

// system/libhidl/transport/ServiceManagement.cpp
// 第一个参数为android.hardware.camera.provider@2.4::ICameraProvider
//  第二个参数为 legacy/0
// 后两个参数都为true
sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
                                                             const std::string& instance,
                                                             bool retry, bool getStub) {
    using Transport = IServiceManager1_0::Transport;
    sp<Waiter> waiter;

    sp<IServiceManager1_1> sm;
    Transport transport = Transport::EMPTY;
    if (kIsRecovery) {
        transport = Transport::PASSTHROUGH;
    } else {
        sm = defaultServiceManager1_1();
        if (sm == nullptr) {
            ALOGE("getService: defaultServiceManager() is null");
            return nullptr;
        }
		// 这里最终会去读取/vendor/etc/vintf/manifest.xml文件来获取当前transport类型
		// 初始文件在device/xxx/manifest.xml,编译时跟其他manifest
		// 一起写入/vendor/etc/vintf/manifest.xml,定义如下:
		/*
		<manifest version="1.0" type="device" target-level="3">
    		<hal format="hidl">
        		<name>android.hardware.camera.provider</name>
        		<transport>hwbinder</transport>
        		<fqname>@2.4::ICameraProvider/legacy/0</fqname>
    		</hal>
		</manifest>
		*/
		// transport类型决定了当前HAL是绑定式还是直通式
        Return<Transport> transportRet = sm->getTransport(descriptor, instance);

        if (!transportRet.isOk()) {
            ALOGE("getService: defaultServiceManager()->getTransport returns %s",
                  transportRet.description().c_str());
            return nullptr;
        }
        transport = transportRet;
    }

    const bool vintfHwbinder = (transport == Transport::HWBINDER); // true
    const bool vintfPassthru = (transport == Transport::PASSTHROUGH); // false
    const bool trebleTestingOverride = isTrebleTestingOverride(); // false
    const bool allowLegacy = !kEnforceVintfManifest || (trebleTestingOverride && isDebuggable()); // false
    const bool vintfLegacy = (transport == Transport::EMPTY) && allowLegacy; // false

    if (!kEnforceVintfManifest) {
        ALOGE("getService: Potential race detected. The VINTF manifest is not being enforced. If "
              "a HAL server has a delay in starting and it is not in the manifest, it will not be "
              "retrieved. Please make sure all HALs on this device are in the VINTF manifest and "
              "enable PRODUCT_ENFORCE_VINTF_MANIFEST on this device (this is also enabled by "
              "PRODUCT_FULL_TREBLE). PRODUCT_ENFORCE_VINTF_MANIFEST will ensure that no race "
              "condition is possible here.");
        sleep(1);
    }

	// 因为参数getStub为true,所以这里的for循环不进入,不执行
    for (int tries = 0; !getStub && (vintfHwbinder || vintfLegacy); tries++) {
        if (waiter == nullptr && tries > 0) {
            waiter = new Waiter(descriptor, instance, sm);
        }
        if (waiter != nullptr) {
            waiter->reset();  // don't reorder this -- see comments on reset()
        }
        Return<sp<IBase>> ret = sm->get(descriptor, instance);
        if (!ret.isOk()) {
            ALOGE("getService: defaultServiceManager()->get returns %s for %s/%s.",
                  ret.description().c_str(), descriptor.c_str(), instance.c_str());
            break;
        }
        sp<IBase> base = ret;
        if (base != nullptr) {
            Return<bool> canCastRet =
                details::canCastInterface(base.get(), descriptor.c_str(), true /* emitError */);

            if (canCastRet.isOk() && canCastRet) {
                if (waiter != nullptr) {
                    waiter->done();
                }
                return base; // still needs to be wrapped by Bp class.
            }

            if (!handleCastError(canCastRet, descriptor, instance)) break;
        }

        // In case of legacy or we were not asked to retry, don't.
        if (vintfLegacy || !retry) break;

        if (waiter != nullptr) {
            ALOGI("getService: Trying again for %s/%s...", descriptor.c_str(), instance.c_str());
            waiter->wait(true /* timeout */);
        }
    }

    if (waiter != nullptr) {
        waiter->done();
    }

	// getStub为true,进入这里的if语句
    if (getStub || vintfPassthru || vintfLegacy) {
    	// getPassthroughServiceManager 返回new PassthroughServiceManager()
        const sp<IServiceManager1_0> pm = getPassthroughServiceManager();
        if (pm != nullptr) {
        	// 下面单独分析PassthroughServiceManager的get函数
            sp<IBase> base = pm->get(descriptor, instance).withDefault(nullptr);
            // getStub为true, trebleTestingOverride为false,这里的if进不去
            if (!getStub || trebleTestingOverride) {
                base = wrapPassthrough(base);
            }
            return base;
        }
    }
	
    return nullptr;
}

PassthroughServiceManager.get

// system/libhidl/transport/ServiceManagement.cpp
// descriptor: android.hardware.camera.provider@2.4::ICameraProvider
// instance:  legacy/0
sp<IBase> base = pm->get(descriptor, instance)
Return<sp<IBase>> get(const hidl_string& fqName,
                        const hidl_string& name) override {
    sp<IBase> ret = nullptr;

	// 主要就是执行了openLibs函数,我们先把参数理一下,然后在进入openLibs函数进行分析
	// 第一个参数fqName: android.hardware.camera.provider@2.4::ICameraProvider
	// 第二个参数是一个lamda函数,这个函数有三个参数,这里主要是这个lamda函数的实现,
	// 这里我们先省略,到调用的时候再详细讲
    openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
    ...
    }
}

PassthroughServiceManager.openLibs

// system/libhidl/transport/ServiceManagement.cpp
// openLibs函数实现
static void openLibs(
	// fqName:  android.hardware.camera.provider@2.4::ICameraProvider
    const std::string& fqName,
    // eachLib: 就是上面提到的lamda函数
    const std::function<bool /* continue */ (void* /* handle */, const std::string& /* lib */,
                                                const std::string& /* sym */)>& eachLib) {
    //fqName looks like android.hardware.foo@1.0::IFoo
    // 用::符号将参数分割为android.hardware.camera.provider@2.4和ICameraProvider
    size_t idx = fqName.find("::");

    if (idx == std::string::npos ||
            idx + strlen("::") + 1 >= fqName.size()) {
        LOG(ERROR) << "Invalid interface name passthrough lookup: " << fqName;
        return;
    }

	// 这里拿到的就是android.hardware.camera.provider@2.4
    std::string packageAndVersion = fqName.substr(0, idx);
    // 这里拿到的就是 ICameraProvider
    std::string ifaceName = fqName.substr(idx + strlen("::"));

	// prefix为android.hardware.camera.provider@2.4-impl
    const std::string prefix = packageAndVersion + "-impl";
    // sym为 HIDL_FETCH_ICameraProvider
    const std::string sym = "HIDL_FETCH_" + ifaceName;

	// 到此,上面参数已经解析完毕,下面根据prefix和sym来执行

    constexpr int dlMode = RTLD_LAZY;
    void* handle = nullptr;

    dlerror(); // clear

    static std::string halLibPathVndkSp = details::getVndkSpHwPath();
    std::vector<std::string> paths = {
        HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR, halLibPathVndkSp,
#ifndef __ANDROID_VNDK__
        HAL_LIBRARY_PATH_SYSTEM,
#endif
    };
    // 这里翻译下上面的paths变量:
        std::vector<std::string> paths = {
        "/odm/lib64/hw/", "/vendor/lib64/hw/", "/apex/com.android.vndk.v33/lib64/hw/",
#ifndef __ANDROID_VNDK__
        "/system/lib64/hw/",
#endif
    };
	// 条件为false,不进入
    if (details::isTrebleTestingOverride()) {
        // Load HAL implementations that are statically linked
        handle = dlopen(nullptr, dlMode);
        if (handle == nullptr) {
            const char* error = dlerror();
            LOG(ERROR) << "Failed to dlopen self: "
                        << (error == nullptr ? "unknown error" : error);
        } else if (!eachLib(handle, "SELF", sym)) {
            return;
        }
    }
	// 在paths的几个路径中寻找android.hardware.camera.provider@2.4-impl.so文件
	// 我们到设备里查看一下,发现在/vendor/lib64/hw目录下,因为是64位系统,所以/vendor/lib/hw/是不会遍历的
	// 130|emulator_car_x86_64:/ # find . -name android.hardware.camera.provider@2.4-impl.so                                                                                                        
	// ./vendor/lib/hw/android.hardware.camera.provider@2.4-impl.so
	// ./vendor/lib64/hw/android.hardware.camera.provider@2.4-impl.so
    for (const std::string& path : paths) {
        std::vector<std::string> libs = findFiles(path, prefix, ".so");

        for (const std::string &lib : libs) {
        	// fullPath=/vendor/lib64/hw/android.hardware.camera.provider@2.4-impl.so
            const std::string fullPath = path + lib;

            if (kIsRecovery || path == HAL_LIBRARY_PATH_SYSTEM) {
                handle = dlopen(fullPath.c_str(), dlMode);
            } else {
#if !defined(__ANDROID_RECOVERY__) && defined(__ANDROID__)
				// 最终执行这里,load so库,拿到handle
                handle = android_load_sphal_library(fullPath.c_str(), dlMode);
#endif
            }

            if (handle == nullptr) {
                const char* error = dlerror();
                LOG(ERROR) << "Failed to dlopen " << lib << ": "
                            << (error == nullptr ? "unknown error" : error);
                continue;
            }
			// 还记得eachLib函数吗,就是上面省略掉的lamda函数,下面开始分析
            if (!eachLib(handle, lib, sym)) {
                return;
            }
        }
    }
}

下面开始讲解eachLib lamda实现

	// fqName: android.hardware.camera.provider@2.4::ICameraProvider
	// name:  legacy/0 
    Return<sp<IBase>> get(const hidl_string& fqName,
                          const hidl_string& name) override {
        sp<IBase> ret = nullptr;
		// 这里的handle为dlopen /vendor/lib64/hw/android.hardware.camera.provider@2.4-impl.so后的handle
		// lib参数为android.hardware.camera.provider@2.4-impl.so
		// sym参数为HIDL_FETCH_ICameraProvider
        openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
            IBase* (*generator)(const char* name);
            // 通过dlsym在android.hardware.camera.provider@2.4-impl.so中找到HIDL_FETCH_ICameraProvider的地址
            *(void **)(&generator) = dlsym(handle, sym.c_str());
            if(!generator) {
                const char* error = dlerror();
                LOG(ERROR) << "Passthrough lookup opened " << lib << " but could not find symbol "
                           << sym << ": " << (error == nullptr ? "unknown error" : error)
                           << ". Keeping library open.";

                // dlclose too problematic in multi-threaded environment
                // dlclose(handle);

                return true;  // continue
            }
			// 执行HIDL_FETCH_ICameraProvider函数,参数为legacy/0 
            ret = (*generator)(name.c_str());

            if (ret == nullptr) {
                LOG(ERROR) << "Could not find instance '" << name.c_str() << "' in library " << lib
                           << ". Keeping library open.";

                // dlclose too problematic in multi-threaded environment
                // dlclose(handle);

                // this module doesn't provide this particular instance
                return true;  // continue
            }

            // Actual fqname might be a subclass.
            // This assumption is tested in vts_treble_vintf_test
            using ::android::hardware::details::getDescriptor;
            std::string actualFqName = getDescriptor(ret.get());
            CHECK(actualFqName.size() > 0);
            registerReference(actualFqName, name);
            return false;
        });

        return ret;
    }

HIDL_FETCH_ICameraProvider

// hardware/interfaces/camera/provider/2.4/default/CameraProvider_2_4.cpp
// 参数name为legacy/0 
ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name) {
    using namespace android::hardware::camera::provider::V2_4::implementation;
    ICameraProvider* provider = nullptr;
    if (strcmp(name, kLegacyProviderName) == 0) {
    	// 执行这里
        provider = getProviderImpl<LegacyCameraProviderImpl_2_4>();
    } else if (strcmp(name, kExternalProviderName) == 0) {
        provider = getProviderImpl<ExternalCameraProviderImpl_2_4>();
    } else {
        ALOGE("%s: unknown instance name: %s", __FUNCTION__, name);
    }

    return provider;
}

// 创建CameraProvider对象并返回,在CameraProvider的构造函数中,会执行IMPL的构造函数,
// 也就是LegacyCameraProviderImpl_2_4的构造函数
template<typename IMPL>
CameraProvider<IMPL>* getProviderImpl() {
    CameraProvider<IMPL> *provider = new CameraProvider<IMPL>();
    if (provider == nullptr) {
        ALOGE("%s: cannot allocate camera provider!", __FUNCTION__);
        return nullptr;
    }
    if (provider->isInitFailed()) {
        ALOGE("%s: camera provider init failed!", __FUNCTION__);
        delete provider;
        return nullptr;
    }
    return provider;
} 

LegacyCameraProviderImpl_2_4的构造函数实现

// hardware/interfaces/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp
LegacyCameraProviderImpl_2_4::LegacyCameraProviderImpl_2_4() :
        camera_module_callbacks_t({sCameraDeviceStatusChange,
                                   sTorchModeStatusChange}) {
    mInitFailed = initialize();
}

上面创建了LegacyCameraProviderImpl_2_4对象,并执行了其初始化函数initialize()。

总结一句其实就是CameraProvider进程启动时加载android.hardware.camera.provider@2.4-impl.so库并执行LegacyCameraProviderImpl_2_4的初始化函数。

好的,本节就先介绍到这里,下节继续接着讲解。

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Android Studio中拍照有两种方式:使用Camera API和使用CameraX API。 使用Camera API: 1. 添加权限到AndroidManifest.xml文件: ``` <uses-feature android:name="android.hardware.camera" /> <uses-permission android:name="android.permission.CAMERA" /> ``` 2. 在布局文件中添加一个SurfaceView或TextureView: ``` <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 3. 在Activity或Fragment中添加以下代码: ``` private Camera camera; private SurfaceView surfaceView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); surfaceView = findViewById(R.id.surfaceView); surfaceView.getHolder().addCallback(surfaceCallback); } private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { camera = Camera.open(); try { camera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewSize(width, height); camera.setParameters(parameters); camera.startPreview(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { camera.stopPreview(); camera.release(); camera = null; } }; public void takePicture(View view) { camera.takePicture(null, null, pictureCallback); } private Camera.PictureCallback pictureCallback = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { //处理拍照数据 } }; ``` 4. 在布局文件中添加一个按钮,并在Activity或Fragment中实现按钮的点击事件: ``` <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Take Picture" android:onClick="takePicture" /> ``` 使用CameraX API: 1. 添加依赖到build.gradle文件: ``` dependencies { def camerax_version = "1.0.0" // CameraX core library implementation "androidx.camera:camera-core:$camerax_version" // CameraX Camera2 extensions implementation "androidx.camera:camera-camera2:$camerax_version" // CameraX Lifecycle library implementation "androidx.camera:camera-lifecycle:$camerax_version" // CameraX View class implementation "androidx.camera:camera-view:1.0.0-alpha23" } ``` 2. 在布局文件中添加一个PreviewView: ``` <androidx.camera.view.PreviewView android:id="@+id/previewView" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 3. 在Activity或Fragment中添加以下代码: ``` private ListenableFuture<ProcessCameraProvider> cameraProviderFuture; private Preview preview; private ImageCapture imageCapture; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); cameraProviderFuture = ProcessCameraProvider.getInstance(this); cameraProviderFuture.addListener(() -> { try { ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); preview = new Preview.Builder().build(); preview.setSurfaceProvider(previewView.createSurfaceProvider()); imageCapture = new ImageCapture.Builder().build(); cameraProvider.unbindAll(); cameraProvider.bindToLifecycle(this, CameraSelector.DEFAULT_BACK_CAMERA, preview, imageCapture); } catch (ExecutionException | InterruptedException e) { e.printStackTrace(); } }, ContextCompat.getMainExecutor(this)); } public void takePicture(View view) { File file = new File(getExternalMediaDirs()[0], System.currentTimeMillis() + ".jpg"); ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build(); imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(this), new ImageCapture.OnImageSavedCallback() { @Override public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) { //处理拍照数据 } @Override public void onError(@NonNull ImageCaptureException exception) { exception.printStackTrace(); } }); } ``` 4. 在布局文件中添加一个按钮,并在Activity或Fragment中实现按钮的点击事件: ``` <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Take Picture" android:onClick="takePicture" /> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ZZH的Android

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

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

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

打赏作者

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

抵扣说明:

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

余额充值