Android Camera SDK NDK NDK_vendor介绍

news2024/10/3 2:16:56

Android Camera JNI NDK NDK_vendor介绍

  • 前言
  • 主要有哪几种interface?
  • Android SDK
    • Camera API 1
    • Camera API 2
    • 小结
  • Android NDK
    • NDK Interface
    • NDK Vendor Interface
    • 小结
  • Camera VTS Testcase
  • 总结
  • Reference

前言

本篇博客是想介绍Android camera从application layer到camera service layer整个框架中,能够使用的所有接口方式。

主要有哪几种interface?

分为两大类:Android SDK,Android NDK。
Android NDK分为NDK和NDK vendor。对于camera module Android SDK可以分为camera API 1和camera API 2。最后有一种特殊的方式是用过HIDL interface来实现camera APP,给出总体架构图:
Android camera overall architecture diagram

Android SDK

Camera API 1

  • API 1作为最原始的一套camera API现在已经被Google启用,已经不在有功能上的升级,可以提供基础capture pictures and videos in your applications。API 1流程非常的特殊,他是通过JNI layer调用到libcameraservice,如果想了解JNI移步:链接: Camera Java Native Interface(JNI)介绍。
  • 接下来通过camera open代码分析JNI调用过程
frameworks/base/core/java/android/hardware/Camera.java
public static Camera open() {
    int numberOfCameras = getNumberOfCameras();
    CameraInfo cameraInfo = new CameraInfo();
    for (int i = 0; i < numberOfCameras; i++) {
        getCameraInfo(i, cameraInfo);
        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
            return new Camera(i);
        }
    }
    return null;
}

如果在camera APP中调用API 1的open function去打开默认后置camera,一开始会新建一个camera device object,直接调用camera构造函数。

frameworks/base/core/java/android/hardware/Camera.java
Camera(int cameraId) {
    if(cameraId >= getNumberOfCameras()){
            throw new RuntimeException("Unknown camera ID");
    }
    int err = cameraInit(cameraId);initAppOps();
}

在camera 构造函数中调用cameraInit。

frameworks/base/core/java/android/hardware/Camera.java
private int cameraInit(int cameraId) {//调用到JNI中android_hardware_Camera_native_setup
    return native_setup(new WeakReference<Camera>(this), cameraId,
            ActivityThread.currentOpPackageName());
}

在camera Init中通过native_setup interface就会调用到JNI中android_hardware_Camera_native_setup function。

frameworks/base/core/jni/android_hardware_Camera.cpp
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId, jstring clientPackageName)
{
    const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
        env->GetStringChars(clientPackageName, NULL));
    jsize rawClientNameLen = env->GetStringLength(clientPackageName);
    String16 clientName(rawClientName, rawClientNameLen);
    env->ReleaseStringChars(clientPackageName,
                            reinterpret_cast<const jchar*>(rawClientName));
    int targetSdkVersion = android_get_application_target_sdk_version();
    sp<Camera> camera = Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID,
                                        Camera::USE_CALLING_PID, targetSdkVersion);
	…
    sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
    context->incStrong((void*)android_hardware_Camera_native_setup);
    camera->setListener(context);
    return NO_ERROR;
}
  • android_hardware_Camera_native_setup 中connect是Camera C/S架构的客户端,调用connect函数向服务器发送连接请求。
  • JNICameraContext这个类是一个监听类,用于处理底层Camera回调函数传来的数据和消息。
frameworks/av/camera/Camera.cpp
sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
        int clientUid, int clientPid, int targetSdkVersion)
{
    return CameraBaseT::connect(cameraId, clientPackageName, clientUid,
            clientPid, targetSdkVersion);
}

JNI调用进入C++ framework camera file connect function。

frameworks/av/camera/CameraBase.cpp
template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
                                               const String16& clientPackageName,
                                               int clientUid, int clientPid, int targetSdkVersion)
{
    ALOGV("%s: connect", __FUNCTION__);
	//创建一个camera对象,调用Camera和CameraBase构造函数
    sp<TCam> c = new TCam(cameraId);
    sp<TCamCallbacks> cl = c;
	//获取camera service对象
    const sp<::android::hardware::ICameraService> cs = getCameraService();
    binder::Status ret;
    if (cs != nullptr) {
        TCamConnectService fnConnectService = TCamTraits::fnConnectService;
        ret = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
                                               clientPid, targetSdkVersion, /*out*/ &c->mCamera);
    }return c;
}

CameraBase中通过获得到server端(camera service)代理对象ICameraService。
然后ICameraService通过fnConnectService链接camera service。

frameworks/av/camera/CameraBase.cpp
// establish binder interface to camera service
template <typename TCam, typename TCamTraits>
const sp<::android::hardware::ICameraService> CameraBase<TCam, TCamTraits>::getCameraService()
{
    Mutex::Autolock _l(gLock);
    if (gCameraService.get() == 0) {
        if (CameraUtils::isCameraServiceDisabled()) {
            return gCameraService;
        }
		//通过binder获取camera service
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
            binder = sm->getService(String16(kCameraServiceName));
            if (binder != 0) {
                break;
            }
            ALOGW("CameraService not published, waiting...");
            usleep(kCameraServicePollDelay);
        } while(true);
        if (gDeathNotifier == NULL) {
            gDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(gDeathNotifier);
        gCameraService = interface_cast<::android::hardware::ICameraService>(binder);
    }
    ALOGE_IF(gCameraService == 0, "no CameraService!?");
    return gCameraService;
}

getCameraService function中主要是展示通过binder的方法获取到camera service代理对象。
为什么fnConnectService可以链接camera device呢?因为fnConnectService就等于connect,如下代码:

frameworks/av/camera/Camera.cpp
CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService =
        &::android::hardware::ICameraService::connect;

而connect本身定义为AIDL interface,就是通过binder实现跨进程调用到camera service,在camera service中进一步处理。

frameworks/av/camera/aidl/android/hardware/ICameraService.aidl
AIDL 文件中定义的connect interface,目的为跨进程调用
ICamera connect(ICameraClient client,
        int cameraId,
        String opPackageName,
        int clientUid, int clientPid,
        int targetSdkVersion);

到此camera API 1的流程就梳理完毕,JNI在其中做一个桥梁的作用,API 1通过JNI连接到C++ framework,也展示JNI的目的就是为让java field可以调用到C++ field。

Camera API 2

  • 为更好的控制camera device,Google抛弃camera API 1重新设计camera API 2接口。
  • Camera2 provides in-depth controls for complex use cases, but requires you to manage device-specific configurations。
  • Camera API2 框架为应用提供更接近底层的相机控件,包括高效的零复制连拍/视频流以及曝光、增益、白平衡增益、颜色转换、去噪、锐化等方面的每帧控件。
  • camera API 2调用流程相对简单,直接从API 2 interface通过AIDL调用到camera service,接下来也是举例openCamera流程进行分析。
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public void openCamera(@NonNull String cameraId,
        @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
        throws CameraAccessException {
    openCameraForUid(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler),
            USE_CALLING_UID);
}

public void openCameraForUid(@NonNull String cameraId,
        @NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor,
        int clientUid, int oomScoreOffset) throws CameraAccessException {openCameraDeviceUserAsync(cameraId, callback, executor, clientUid, oomScoreOffset);
}

APP通过API 2 open camera操作可以调用到camera manager中的openCamera function,进而调用到openCameraForUid、openCameraDeviceUserAsync。

frameworks/base/core/java/android/hardware/camera2/CameraManager.java
private CameraDevice openCameraDeviceUserAsync(String cameraId,
        CameraDevice.StateCallback callback, Executor executor, final int uid,
        final int oomScoreOffset) throws CameraAccessException {
    CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
    CameraDevice device = null;
    Map<String, CameraCharacteristics> physicalIdsToChars =
            getPhysicalIdToCharsMap(characteristics);
    synchronized (mLock) {
        ICameraDeviceUser cameraUser = null;
        android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
                new android.hardware.camera2.impl.CameraDeviceImpl(
                    cameraId,
                    callback,
                    executor,
                    characteristics,
                    physicalIdsToChars,
                    mContext.getApplicationInfo().targetSdkVersion,
                    mContext);
        ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
        try {
            ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
            if (cameraService == null) {
                throw new ServiceSpecificException(
                    ICameraService.ERROR_DISCONNECTED,
                    "Camera service is currently unavailable");
            }
            cameraUser = cameraService.connectDevice(callbacks, cameraId,
                mContext.getOpPackageName(),  mContext.getAttributionTag(), uid,
                oomScoreOffset, mContext.getApplicationInfo().targetSdkVersion);
        } catch (ServiceSpecificException e) {}
    return device;
}

openCameraDeviceUserAsync function中通过getCameraService获取到camera service代理ICameraService,这部分操作是在class CameraManagerGlobal中实现。

frameworks/base/core/java/android/hardware/camera2/CameraManager.java
class CameraManagerGlobal {
	public ICameraService getCameraService() {
	    synchronized(mLock) {
	        connectCameraServiceLocked();
	        if (mCameraService == null && !sCameraServiceDisabled) {
	            Log.e(TAG, "Camera service is unavailable");
	        }
	        return mCameraService;
	    }
	}

	private void connectCameraServiceLocked() {
	    // Only reconnect if necessary
	    if (mCameraService != null || sCameraServiceDisabled) return;
	    Log.i(TAG, "Connecting to camera service");
	    IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME);
	    if (cameraServiceBinder == null) {
	        // Camera service is now down, leave mCameraService as null
	        return;
	    }
	    try {
	        cameraServiceBinder.linkToDeath(this, /*flags*/ 0);
	    } catch (RemoteException e) {
	        // Camera service is now down, leave mCameraService as null
	        return;
	    }
		//直接通过AIDL 获取camera service
	    ICameraService cameraService = ICameraService.Stub.asInterface(cameraServiceBinder);}
}
  • global manger camera class主要作为保持和camera service的链接,并且distribute camera device callback notice。
  • getCameraService调用到connectCameraServiceLocked,可以很清楚的看到通过binder获取到cameraService。
  • 因为connectDevice interface本身定义为AIDL,跨进程的方式从java framework调用到camera service中。
frameworks/av/camera/aidl/android/hardware/ICameraService.aidl
 ICameraDeviceUser connectDevice(ICameraDeviceCallbacks callbacks,
         String cameraId,
         String opPackageName,
         @nullable String featureId,
         int clientUid, int oomScoreOffset,
         int targetSdkVersion);

以上就讲解完通过 API 2方式从APP调用到camera service。

小结

  • 虽然Android SDK中的API 1和API 2都是通过AIDL调用到camera service,但是分别是在C++ code和java code中调用,这里就体现AIDL这种接口描述性语言的优势,不需要考虑binder service和client两端的编程语言,只需要按照要求编写好AIDL interface,编译之后自动生成代码,在使用的时候按接口标准就可以实现。

Android NDK

NDK Interface

  • NDK的全拼是:Native Develop Kit,Android NDK 是一套允许您使用原生代码语言(例如C和C++)实现部分应用的工具集。在开发某些类型应用时,这有助于您重复使用以这些语言编写的代码库。
  • 我们来分析要是使用NDK的方式来编写camera APP进程的代码,open camera的流程是怎么样的。
frameworks/av/camera/ndk/NdkCameraManager.cpp
camera_status_t ACameraManager_openCamera(
        ACameraManager* mgr, const char* cameraId,
        ACameraDevice_StateCallbacks* callback,
        /*out*/ACameraDevice** device) {
    return mgr->openCamera(cameraId, callback, device);
}

在system分区中通过使用C++代码编写的camera APP,open camera调用的是NDK中的ACameraManager_openCamera,进一步进入camera manager openCamera function。

frameworks/av/camera/ndk/NdkCameraManager.cpp
camera_status_t
ACameraManager::openCamera(
        const char* cameraId,
        ACameraDevice_StateCallbacks* callback,
        /*out*/ACameraDevice** outDevice)
{
    sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
    sp<hardware::camera2::ICameraDeviceCallbacks> callbacks = device->getServiceCallback();
    sp<hardware::camera2::ICameraDeviceUser> deviceRemote;
    int targetSdkVersion = android_get_application_target_sdk_version();
	//调用CameraService::connectDevice
    binder::Status serviceRet = cs->connectDevice(
            callbacks, String16(cameraId), String16(""), {},
            hardware::ICameraService::USE_CALLING_UID, /*oomScoreOffset*/0,
            targetSdkVersion, /*out*/&deviceRemote);
	...
}

openCamera function中先通过getCameraService获取到camera service代理对象(其中代码流程同上,就不分析了),再通过connectDevice AIDL interface 跨进程连接到camera service。

NDK Vendor Interface

  • VNDK的全称是Vendor Native Development Kit,是Android 8.0引入的一种新技术。它表现一系列库的合集,用于让供应商开发自己的HALs。VNDK 包含在 system.img 中,并在运行时与供应商代码动态关联。
  • 使用vndk的原因是自Android8.0以来,Google引入了Treble架构,希望对vendor和system分区进行解耦处理,期待实现:framwork进程不加载vendor共享库,vendor进程仅加载vendor共享库(和部分framework共享库),而framework进程和vendor进程之间通过HIDL和hwbinder来通信
  • 这里也是通过open camera function,来分析在vendor分区中编写C++ 代码的camera APP 调用到camera service。
frameworks/av/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
camera_status_t
ACameraManager::openCamera(
        const char* cameraId,
        ACameraDevice_StateCallbacks* callback,
        /*out*/ACameraDevice** outDevice) {
    sp<ACameraMetadata> rawChars;
    camera_status_t ret = getCameraCharacteristics(cameraId, &rawChars);
    Mutex::Autolock _l(mLock);
    if (ret != ACAMERA_OK) {
        ALOGE("%s: cannot get camera characteristics for camera %s. err %d",
                __FUNCTION__, cameraId, ret);
        return ACAMERA_ERROR_INVALID_PARAMETER;
    }
    ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(rawChars));
    sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
    if (cs == nullptr) {
        ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
        delete device;
        return ACAMERA_ERROR_CAMERA_DISCONNECTED;
    }
    sp<ICameraDeviceCallback> callbacks = device->getServiceCallback();
    sp<ICameraDeviceUser_2_0> deviceRemote_2_0;
	//通过调用HidlCameraService中connectDevice,hidl方式
    Status status = Status::NO_ERROR;
    auto serviceRet = cs->connectDevice(
            callbacks, cameraId, [&status, &deviceRemote_2_0](auto s, auto &device) {
                                     status = s;
                                     deviceRemote_2_0 = device;
                                 });
	…
    sp<ICameraDeviceUser> deviceRemote = castResult;
    device->setRemoteDevice(deviceRemote);
    device->setDeviceMetadataQueues();
    *outDevice = device;
    return ACAMERA_OK;
}

这里直接给出的是NDK Vendor中的openCamera function,但是这个函数也是被ACameraManager_openCamera调用。
其中mgr->openCamera是调用NDK还是NDK Vendor中的interface呢?需要通过mCameraManager来确定。

ACameraManager_openCamera(mCameraManager, mCameraId, &mDeviceCb, &mDevice);
mCameraManager = ACameraManager_create();
ACameraManager* ACameraManager_create() {
    ATRACE_CALL();
    return new ACameraManager();
}

  • ACameraManager_openCamera调用时会传入mCameraManager,mCameraManager是由ACameraManager_create创建出来。ACameraManager_create 创建过程直接new ACameraManager对象。
NDK ACameraManager:
struct ACameraManager {
    ACameraManager() :
            mGlobalManager(&(android::acam::CameraManagerGlobal::getInstance())) {}
    ~ACameraManager();
    camera_status_t getCameraIdList(ACameraIdList** cameraIdList);
    static void     deleteCameraIdList(ACameraIdList* cameraIdList);

    camera_status_t getCameraCharacteristics(
            const char* cameraId, android::sp<ACameraMetadata>* characteristics);
    camera_status_t openCamera(const char* cameraId,
                               ACameraDevice_StateCallbacks* callback,
                               /*out*/ACameraDevice** device);

  private:
    enum {
        kCameraIdListNotInit = -1
    };
    android::Mutex         mLock;
    android::sp<android::acam::CameraManagerGlobal> mGlobalManager;
};

NDK Vendor ACameraManager:
struct ACameraManager {
    ACameraManager() :
            mGlobalManager(&(android::acam::CameraManagerGlobal::getInstance())) {}
    ~ACameraManager();
    camera_status_t getCameraIdList(ACameraIdList** cameraIdList);
    static void     deleteCameraIdList(ACameraIdList* cameraIdList);

    camera_status_t getCameraCharacteristics(
            const char* cameraId, android::sp<ACameraMetadata>* characteristics);

    camera_status_t openCamera(const char* cameraId,
                               ACameraDevice_StateCallbacks* callback,
                               /*out*/ACameraDevice** device);
    camera_status_t getTagFromName(const char *cameraId, const char *name, uint32_t *tag);

  private:
    enum {
        kCameraIdListNotInit = -1
    };
    android::Mutex         mLock;
    android::sp<android::acam::CameraManagerGlobal> mGlobalManager;
};
  • new ACameraManager需要区分是调用NDK还是NDK Vendor创建对象,不同的对象进而实现不同的调用接口逻辑。
  • 再回来看openCamera function中的connectDevice interface,其中传递的参数和NDK代码中明显不同,因为NDK Vendor调用的是HIDL 定义connectDevice interface。
frameworks/hardware/interfaces/cameraservice/service/2.0/ICameraService.hal
connectDevice(ICameraDeviceCallback callback, string cameraId)
    generates (Status status, ICameraDeviceUser device);
  • ICameraService.hal文件中定义的HIDL connectDevice interface。
  • cs->connectDevice通过binder跨进程可以调用到HidlCameraService::connectDevice中。

小结

  • 以上分析了通过NDK和NDK Vendor方式,connect device连接到camera service的代码流程,区别在于NDK使用AIDL interface而NDK Vendor使用 HIDL interface,并且在libcameraservice中对接的接口也不一样。
  • System分区中new ACameraManager实例调用NDK interface,Vendor 分区中new ACameraManager实例调用NDK Vendor interface。
  • HidlCameraService对上连接NDK Vendor,但是最终实现功能还是依赖于CameraService。

Camera VTS Testcase

  • HIDL interface提供的接口是可以直接实现camera device所有基础的功能,但是由于没有 camera service的介入对于管理camera device是非常困难的。使用这种方式构建camera APP非常的特殊,没有经过整个Android framework,可以直接对HAL进行测试。
  • Camera VTS testcase 是基于HDIL interface来实现功能的测试程序,毕竟是Google提供给HAL 厂商稳定的接口,肯定需要测试保证其稳定性。
  • 对于如果是camera service process没有启动的情况下,可以使用HDIL interface来写camera APP,感兴趣可以移步: Camera HIDL接口实现camera preview功能

总结

  • 这篇博客主要是对Android framework接口方式进行介绍,其中包括Android SDK和Android NDK,Android SDK可以分为API 1和API 2,其中API 1通过JNI的方式调用实现。
  • JNI调用的cameraBase是和NDK、NDK vendor处于同一目录下,framework中的audio和video服务层(av目录名字含义)。
  • CameraBase、API 2和NDK都是通过AIDL跨进程调用到libcameraservice,而只有NDK Vendor独特的使用HIDL跨进程调用到libcameraservice。

Reference

链接: Android JNI(一)——NDK与JNI基础

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/397419.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

谷歌插件Fetch在不同页面之间Cookie携带情况详解

content script 和 script inject 表现情况 在碰到content script 注入和用script标签注入一样&#xff0c;即使服务端有写入Cookie到域名下在该tab标签应用下也不会被保存&#xff0c;所以在发送时也无法自动携带&#xff0c;所以通过content script和<script>这种方式…

微信小程序第二节 —— 自定义组件。

&#x1f449;微信小程序第一节 —— 自定义顶部、底部导航栏以及获取胶囊体位置信息。 一、前言 &#x1f4d6;&#x1f4d6;&#x1f4d6;书接上回 &#xff0c;dai ga hou啊&#xff01;我是 &#x1f618;&#x1f618;&#x1f618;是江迪呀。在进行微信小程序开发中&am…

多维数组的地址,通过指针引用多维数组详解

通过指针引用一维数组可以参考这篇文章&#xff1a; 通过指针引用数组的几种方法的原理和差异&#xff1b;以及利用指针引用数组元素的技巧_juechen333的博客-CSDN博客一个数组包含若干元素&#xff0c;每个数组元素都占用存储单元&#xff0c;所以他们都有相应的地址&#xf…

《Ansible模块篇:debug模块详解》

一、简介 平时我们在使用ansible执行playbook时&#xff0c;经常可能会遇到一些错误&#xff0c;有的时候不知道问题在哪里 &#xff0c;这个时候可以使用-vvv参数打印出来详细信息&#xff0c;不过很多时候-vvv参数里很多东西并不是我们想要的&#xff0c;这时候就可以使用官方…

python第四天作业~函数练习

目录 作业4、判断以下哪些不能作为标识符 A、a B、&#xffe5;a C、_12 D、$a12 E、false F、False 作业5&#xff1a; 输入数&#xff0c;判断这个数是否是质数&#xff08;要求使用函数 for循环&#xff09; 作业6&#xff1a;求50~150之间的质数是…

ReentrantLock 源码解读

一、ReentrantLock ReentrantLock 是 java JUC 中的一个可重入锁&#xff0c;在上篇文章讲解 AQS 源码的时候提到 ReentrantLock 锁是基于 AQS 实现的&#xff0c;那是如何使用的 AQS 呢&#xff0c;本篇文章一起带大家看下 ReentrantLock 的源码。 在 AQS 中&#xff0c;如果…

linux安装influxdb-rpmyum方式

一、influxdb的安装InfluxDB简介时序数据库InfluxDB版是一款专门处理高写入和查询负载的时序数据库&#xff0c;用于存储大规模的时序数据并进行实时分析&#xff0c;包括来自DevOps监控、应用指标和IoT传感器上的数据主要特点&#xff1a;专为时间序列数据量身订造高性能数据存…

uniapp——ucharts的使用

ucharts是一个类似于echarts的图表框架 引入 在Hbuilder的插件下载仓库中搜索ucharts &#xff01;&#xff01;值得一提的是&#xff0c;Hbuilder的版本必须是大于3.1.0的&#xff01;&#xff01; 这样就导入到了项目的uni_modules里了 ucharts下载完成后&#xff0c;可以…

Java——异常机制

前言 随着对java的不断深入学习&#xff0c;在对语法以及编程思想有了一定的了解之后&#xff0c;在编程的过程中有可能会因为用户的输入不正确或者逻辑错误而出现异常或者错误&#xff0c;因此如何去捕捉与避免不应该出现的异常或者错误就变得十分重要。本文就介绍了java的异…

C++实现的二叉树创建和遍历,超入门邻家小女也懂了

目录 二叉树 特点 性质 二叉树的创建 声明 创建 -> 成员运算符 批量创建 二叉树的遍历 先序遍历 中序遍历 后序遍历 层序遍历 树的相关术语 特殊二叉树 满二叉树 完全二叉树 二叉树 树&#xff08;Tree&#xff09;是n(n≥0)个节点的有限集。在任意一棵…

Idea工具单工程使用卡顿设置

一、开启Idea内存占比指示 1.1、勾选Idea 内存指示器 1.2、右下角展示当前项目&#xff1a;内存/总内存&#xff08;726/1024MB&#xff09; ​​​​​​​ 二、修改Idea自定义内存 2.1、打开help - Edit Custom VM Options 2.2、自定义虚拟内存设置 -Xms1024m // 初始内存分…

【前端八股文】浏览器系列:浏览器渲染、前端路由、前端缓存(HTTP缓存)、缓存存储(HTTP缓存存储、本地存储)

文章目录渲染步骤DOM树与render树回流与重绘前端路由hash模式history模式两种模式对比前端缓存HTTP缓存强缓存协商缓存一般哪些文件对应哪些缓存HTTP缓存总结缓存存储HTTP缓存存储本地存储参考本系列目录&#xff1a;【前端八股文】目录总结 是以《代码随想录》八股文为主的笔记…

TTS | 语音合成论文概述

综述系列2021_A Survey on Neural Speech Synthesis论文&#xff1a;2106.15561.pdf (arxiv.org)论文从两个方面对神经语音合成领域的发展现状进行了梳理总结&#xff08;逻辑框架如图1所示&#xff09;&#xff1a;核心模块&#xff1a;分别从文本分析&#xff08;textanalysi…

【Linux内核一】在Linux系统下网口数据收发包的具体流向是什么?

在TCP/IP网络分层模型里&#xff0c;整个协议栈被分成了物理层、链路层、网络层&#xff0c;传输层和应用层。物理层对应的是网卡和网线&#xff0c;应用层对应的是我们常见的Nginx&#xff0c;FTP等等各种应用。Linux实现的是链路层、网络层和传输层这三层。 在Linux内核实现中…

Linux(Centos)安装Minio集群

目录1&#xff1a;简介2&#xff1a;功能与集成3&#xff1a;架构4&#xff1a;搭建集群4.1&#xff1a;挂载磁盘4.1.1&#xff1a;要求4.1.2&#xff1a;创建挂载目录4.1.3&#xff1a;注意&#xff1a;需要将新建的目录挂在到对应的磁盘下,磁盘不挂载好&#xff0c;集群启动会…

Tomcat 并发达太大导致系统崩溃解决方案

当 Tomcat 并发达太大导致系统崩溃时&#xff0c;可以通过以下几个步骤来解决这个问题&#xff1a; 1、分析原因 首先需要分析系统崩溃的原因&#xff0c;是因为Tomcat的性能瓶颈还是因为代码的Bug&#xff0c;或者是系统资源不足等等。 2、优化代码 如果是代码的问题&…

Unity Lighting -- 为场景烘焙lightmap

烘焙光照是什么&#xff1f; Unity中有两种不同的光照方式&#xff1a;实时光照和烘焙光照。 实时光照 Unity会在运行时实时计算光照。实时光源每一帧都会进行计算&#xff0c;这意味着它们对于场景中移动的角色和物体的响应性非常好&#xff0c;但它的开销也很大。 烘焙光照…

DJ1-3 操作系统引论

目录 操作系统的结构设计 1. 无结构操作系统 2. 模块化 OS 结构 3. 分层式 OS 结构 4. 微内核 OS 结构 操作系统的结构设计 操作系统是一个大型系统软件&#xff0c;其结构已经历了四代的变革&#xff1a; 第一代 OS 是无结构第二代 OS 采用模块式结构第三代是层次式结构…

韩国绿芯1~16通道触摸芯片型号推荐

随着技术的发展&#xff0c;触摸感应技术正日益受到更多关注和应用&#xff0c;目前实现触摸感应的方式主要有两种&#xff0c;一种是电阻式&#xff0c;另一种是电容式。电容式触摸具有感应灵敏、功耗低、寿命长等特点&#xff0c;因此逐步取代电阻式触摸&#xff0c;成为当前…

炫龙游戏本Win10系统总是蓝屏崩溃怎么办?

炫龙游戏本Win10系统总是蓝屏崩溃怎么办&#xff1f;有用户使用的炫龙游戏本最近总是在运行的过程中出现自动蓝屏的情况&#xff0c;有的时候自己还在操作电脑&#xff0c;而屏幕却蓝屏了&#xff0c;导致自己的工作被中断了。那么这个情况要怎么去进行修复呢&#xff1f;来看看…