当前位置: 首页 > news >正文

Android 13 - Media框架(26)- OMXNodeInstance(三)

上一节我们了解了OMXNodeInstance中的端口定义,这一节我们一起来学习ACodec、OMXNode、OMX 组件使用的 buffer 到底是怎么分配出来的,以及如何关联起来的。(我们只会去了解 graphic buffer的创建、input bytebuffer的创建、secure buffer的创建)

1、ACodec::allocateOutputMetadataBuffers

我们先一起来回忆一下,ACodec在使用surface的情况下给ouput port分配buffer使用的是allocateOutputMetadataBuffers方法,这时候真正的graphic buffer还未分配出来,BufferInfo的状态还是OWNED_BY_NATIVE_WINDOW(意为 buffer 还在 native 中)。

    for (OMX_U32 i = 0; i < bufferCount; i++) {BufferInfo info;info.mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;info.mFenceFd = -1;info.mRenderInfo = NULL;info.mGraphicBuffer = NULL;info.mNewGraphicBuffer = false;info.mDequeuedAt = mDequeueCounter;// 创建 meta datainfo.mData = new MediaCodecBuffer(mOutputFormat, new ABuffer(bufferSize));// Initialize fence fd to -1 to avoid warning in freeBuffer().((VideoNativeMetadata *)info.mData->base())->nFenceFd = -1;info.mCodecData = info.mData;err = mOMXNode->useBuffer(kPortIndexOutput, OMXBuffer::sPreset, &info.mBufferID);mBuffers[kPortIndexOutput].push(info);ALOGV("[%s] allocated meta buffer with ID %u",mComponentName.c_str(), info.mBufferID);}

这里BufferInfo是作为分配出来的buffer的索引,分配的 mCodecData (Meta data) 没有任何作用,仅仅是起着占位的作用。

ACodec 需要给这个 BufferInfo 打上索引,调用useBuffer时,传入的OMXBuffer类型是kBufferTypePreset,这个内容可以到 OMXBuffer.cpp 中查询。

1.1、useBuffer

进入到 OMXNodeInstance 中,首先就会检查 port mode,我们可以看到,如果port mode不是dynamic的类型,会直接报错。

status_t OMXNodeInstance::useBuffer(OMX_U32 portIndex, const OMXBuffer &omxBuffer, IOMX::buffer_id *buffer) {switch (omxBuffer.mBufferType) {case OMXBuffer::kBufferTypePreset: {if (mPortMode[portIndex] != IOMX::kPortModeDynamicANWBuffer&& mPortMode[portIndex] != IOMX::kPortModeDynamicNativeHandle) {break;}return useBuffer_l(portIndex, NULL, NULL, buffer);}}

kBufferTypePreset 在这里应该表示的是占位的意思。

我们不要被 useBuffer 的参数 buffer 迷惑了,它其实是一个 int 类型。判断完成后就会进入到 useBuffer_l 中。

1.2、useBuffer_l

进入下面的内容之前我们首先要了解的是,之所以方法名为 use buffer,指的是 OMX 组件端口使用的 buffer 是在其他地方分配的,OMX 组件仅仅只是使用。

useBuffer_l 的设计思路其实和之前的一篇文章中的 enableNativeBuffers_l 类似,它是把几个不同的设定写到一个函数体当中,用入参来判断当前走的是什么设定。useBuffer_l 有两个参数,但是它其实有三种可能的设定,一种是IMemory,另一种是 IHidlMemory,最后一个是两个参数都为 NULL,表示是一个占位

status_t OMXNodeInstance::useBuffer_l(OMX_U32 portIndex, const sp<IMemory> &params,const sp<IHidlMemory> &hParams, IOMX::buffer_id *buffer) {BufferMeta *buffer_meta;OMX_BUFFERHEADERTYPE *header;OMX_ERRORTYPE err = OMX_ErrorNone;// 判断是否使用 meta databool isMetadata = mMetadataType[portIndex] != kMetadataBufferTypeInvalid;// 如果使用graphic buffer但是不用meta data则直接报错if (!isMetadata && mGraphicBufferEnabled[portIndex]) {ALOGE("b/62948670");android_errorWriteLog(0x534e4554, "62948670");return INVALID_OPERATION;}// 检查参数,不能同时设定两个参数size_t paramsSize;void* paramsPointer;if (params != NULL && hParams != NULL) {return BAD_VALUE;}// 解析传递的buffer的指针以及buffer的大小,如果什么都没有传,那么指针为NULLif (params != NULL) {// TODO: Using unsecurePointer() has some associated security pitfalls//       (see declaration for details).//       Either document why it is safe in this case or address the//       issue (e.g. by copying).paramsPointer = params->unsecurePointer();paramsSize = params->size();} else if (hParams != NULL) {paramsPointer = hParams->getPointer();paramsSize = hParams->getSize();} else {paramsPointer = nullptr;}// 使用的buffer的大小OMX_U32 allottedSize;// metadata mode下,设定的是占位符,OMXNode 与 OMX 组件之间通过 metadata交流,metadata buffer由 OMXNode分配// 这里需要根据不同的类型分配不同类型的meta data,确定metadata sizeif (isMetadata) {if (mMetadataType[portIndex] == kMetadataBufferTypeGrallocSource) {allottedSize = sizeof(VideoGrallocMetadata);} else if (mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer) {// allottedSize = sizeof(VideoNativeMetadata);} else if (mMetadataType[portIndex] == kMetadataBufferTypeNativeHandleSource) {allottedSize = sizeof(VideoNativeHandleMetadata);} else {return BAD_VALUE;}} else {// NULL 只允许出现在 meta mode 当中// 如果不使用meta data 并且 没有传 buffer下来,那么直接报错// NULL params is allowed only in metadata mode.if (paramsPointer == nullptr) {ALOGE("b/25884056");return BAD_VALUE;}allottedSize = paramsSize;}// 是否是与graphic搭配使用的metadatabool isOutputGraphicMetadata = (portIndex == kPortIndexOutput) &&(mMetadataType[portIndex] == kMetadataBufferTypeGrallocSource ||mMetadataType[portIndex] == kMetadataBufferTypeANWBuffer);// 是否需要分配bufferuint32_t requiresAllocateBufferBit =(portIndex == kPortIndexInput)? kRequiresAllocateBufferOnInputPorts: kRequiresAllocateBufferOnOutputPorts;// quirks 模式下,如果不是使用的 meta data mode,则需要让 OMX 组件分配buffer// we use useBuffer for output metadata regardless of quirksif (!isOutputGraphicMetadata && (mQuirks & requiresAllocateBufferBit)) {// metadata buffers are not connected cross process; only copy if not meta.// quirks 模式下,将 OMX 组件分配的buffer 和 上层 buffer相关绑定,进行数据拷贝// 这应该是很没有效率的一种行为buffer_meta = new BufferMeta(params, hParams, portIndex, !isMetadata /* copy */, NULL /* data */);err = OMX_AllocateBuffer(mHandle, &header, portIndex, buffer_meta, allottedSize);if (err != OMX_ErrorNone) {CLOG_ERROR(allocateBuffer, err,SIMPLE_BUFFER(portIndex, (size_t)allottedSize,paramsPointer));}} else {OMX_U8 *data = NULL;// metadata buffers are not connected cross process// use a backup buffer instead of the actual bufferif (isMetadata) {// 为 meta data buffer 分配空间data = new (std::nothrow) OMX_U8[allottedSize];if (data == NULL) {return NO_MEMORY;}memset(data, 0, allottedSize);// 将 meta data buffer 封装到 BufferMeta 当中buffer_meta = new BufferMeta(params, hParams, portIndex, false /* copy */, data);} else {// 如果不是 meta data mode,直接使用buffer指针data = static_cast<OMX_U8 *>(paramsPointer);// 将 buffer 封装到 BufferMeta 当中buffer_meta = new BufferMeta(params, hParams, portIndex, false /* copy */, NULL);}// 直接把创建的 BufferMeta 传递给 OMX 组件使用,不需要进行buffer拷贝err = OMX_UseBuffer(mHandle, &header, portIndex, buffer_meta,allottedSize, data);if (err != OMX_ErrorNone) {CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(portIndex, (size_t)allottedSize, data));}}if (err != OMX_ErrorNone) {delete buffer_meta;buffer_meta = NULL;*buffer = 0;return StatusFromOMXError(err);}// 检查创建的buffer header中的上层数据是否和 创建的 buffer meta 相同CHECK_EQ(header->pAppPrivate, buffer_meta);// 为 buffer header 创建 index*buffer = makeBufferID(header);addActiveBuffer(portIndex, *buffer);sp<IOMXBufferSource> bufferSource(getBufferSource());if (bufferSource != NULL && portIndex == kPortIndexInput) {bufferSource->onInputBufferAdded(*buffer);}CLOG_BUFFER(useBuffer, NEW_BUFFER_FMT(*buffer, portIndex, "%u(%zu)@%p", allottedSize, paramsSize, paramsPointer));return OK;
}

useBuffer 的内容很长,里面有很多判断,很多同学可能读不太明白里面到底想干什么,这里我们就来解析一下:

  1. 首先,它会判断configure阶段配置的一些内容, 比如说metadata mode需要和graphic buffer共同使用;IMemory 参数和 IHidlMemory 参数不能同时设定;

  2. 接下来会分为两种情况,

    • metadata mode,也就是我们上面讨论的传下来的buffer类型是kBufferTypePreset的情况(占位),这种情况上层没有真正传buffer下来,OMX组件和上层通过metadata进行数据传递,所以usebuffer中会根据configure的配置获取需要传递的metadata类型,计算metadata所需的size;
    • preset byte buffer,这种就是普通的non secure buffer,可以通过指针读写buffer中的数据,use buffer需要获取buffer的地址以及大小;
  3. 判断是否用quirks,这个东西我们在创建OMXNodeInstance时有看见过,它是在xml中配置的,一旦有了这个配置,那么只要端口不是metadata mode,则需要让OMX组件分配buffer,上层传下来的buffer会与OMX分配的buffer做绑定,创建一个BufferMeta,上层传的数据会在这里做拷贝,写入到OMX组件分配的buffer当中。(这里是调用OMX_AllocateBuffer的地方之一)
    请添加图片描述

  4. 如果不使用quirks,那么数据就不需要在OMXNodeInstance层做中转了。

    • metadata mode,分配meta data大小的buffer,创建出BufferMeta;
    • preset byte buffer,直接用上层传的buffer创建BufferMeta;
    • 调用OMX_UseBuffer,将 BufferMeta 和 metadata/buffer 注册到 OMX 组件当中,并且创建出 OMX_BUFFERHEADERTYPE
  5. 为创建出的 OMX_BUFFERHEADERTYPE 分配 id;

到这里,useBuffer_l 的分析就完成了,之所以要在 OMXNodeInstance 这一层创建 BufferMeta,可能就是为了记录上层传下来的所有buffer,或者是做数据中转用的。

quirks模式会在 OMXNodeInstance 层多做一次数据拷贝,现在已经被弃用了。

再放上两张示意图:

一张是 preset byte buffer:
请添加图片描述

另一张是meta data,可以看到 meta data 模式下,output buffer 不会有任何东西回传给上层。
请添加图片描述
OMXNodeInstance 收到返回的 OMX_BUFFERHEADERTYPE 后会为其分配 id:

IOMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) {if (bufferHeader == NULL) {return 0;}Mutex::Autolock autoLock(mBufferIDLock);IOMX::buffer_id buffer;do { // handle the very unlikely case of ID overflowif (++mBufferIDCount == 0) {++mBufferIDCount;}buffer = (IOMX::buffer_id)mBufferIDCount;} while (mBufferIDToBufferHeader.indexOfKey(buffer) >= 0);mBufferIDToBufferHeader.add(buffer, bufferHeader);mBufferHeaderToBufferID.add(bufferHeader, buffer);return buffer;
}

可以看到一个 OMXNodeInstance 的buffer id用一个mBufferIDCount 成员来管理,所以input buffer和ouput buffer id 是连续的。

makeBufferID 还为 id 和 bufferheader 建立起一个映射,便于快速完成查找。

1.2、allocateSecureBuffer

allocate buffer 是让 OMX 组件分配需要使用的 buffer,在ACodec中,只有在使用 secure buffer时,会让omx组件分配buffer handle。secure buffer是一块受保护的buffer,我们无法读取到内部的资料,内存拷贝需要通过操作 handle 来完成,这里我们要看 handle 是如何创建的:

                BufferInfo info;info.mStatus = BufferInfo::OWNED_BY_US;info.mFenceFd = -1;info.mRenderInfo = NULL;info.mGraphicBuffer = NULL;info.mNewGraphicBuffer = false;if (mode == IOMX::kPortModePresetSecureBuffer) {void *ptr = NULL;sp<NativeHandle> native_handle;err = mOMXNode->allocateSecureBuffer(portIndex, bufSize, &info.mBufferID,&ptr, &native_handle);info.mData = (native_handle == NULL)? new SecureBuffer(format, ptr, bufSize): new SecureBuffer(format, native_handle, bufSize);info.mCodecData = info.mData;}

可以看到,直接就调用 OMXNode 的 allocateSecureBuffer 方法了,这块buffer将由native层创建,所以 allocateSecureBuffer 将会调用组件的OMX_AllocateBuffer方法:

status_t OMXNodeInstance::allocateSecureBuffer(OMX_U32 portIndex, size_t size, IOMX::buffer_id *buffer,void **buffer_data, sp<NativeHandle> *native_handle) {if (buffer == NULL || buffer_data == NULL || native_handle == NULL) {ALOGE("b/25884056");return BAD_VALUE;}if (portIndex >= NELEM(mSecureBufferType)) {ALOGE("b/31385713, portIndex(%u)", portIndex);android_errorWriteLog(0x534e4554, "31385713");return BAD_VALUE;}Mutex::Autolock autoLock(mLock);if (mHandle == NULL) {return DEAD_OBJECT;}if (!mSailed) {ALOGE("b/35467458");android_errorWriteLog(0x534e4554, "35467458");return BAD_VALUE;}// 检查 port modeif (mPortMode[portIndex] != IOMX::kPortModePresetSecureBuffer) {ALOGE("b/77486542");android_errorWriteLog(0x534e4554, "77486542");return INVALID_OPERATION;}// 创建 BufferMeta,这里的 bufferMeta没有起实质性作用BufferMeta *buffer_meta = new BufferMeta(portIndex);OMX_BUFFERHEADERTYPE *header;// 调用 OMX 组件分配 secure bufferOMX_ERRORTYPE err = OMX_AllocateBuffer(mHandle, &header, portIndex, buffer_meta, size);if (err != OMX_ErrorNone) {CLOG_ERROR(allocateBuffer, err, BUFFER_FMT(portIndex, "%zu@", size));delete buffer_meta;buffer_meta = NULL;*buffer = 0;return StatusFromOMXError(err);}CHECK_EQ(header->pAppPrivate, buffer_meta);// 为 bufferheader 分配id*buffer = makeBufferID(header);// OMX 组件创建的 secure buffer handle 将存储在 buffer header 的 pBuffer 中if (mSecureBufferType[portIndex] == kSecureBufferTypeNativeHandle) {*buffer_data = NULL;// 将handle封装为 native handle*native_handle = NativeHandle::create((native_handle_t *)header->pBuffer, false /* ownsHandle */);} else {*buffer_data = header->pBuffer;*native_handle = NULL;}addActiveBuffer(portIndex, *buffer);sp<IOMXBufferSource> bufferSource(getBufferSource());if (bufferSource != NULL && portIndex == kPortIndexInput) {bufferSource->onInputBufferAdded(*buffer);}CLOG_BUFFER(allocateSecureBuffer, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p:%p", size, *buffer_data,*native_handle == NULL ? NULL : (*native_handle)->handle()));return OK;
}

allocateSecureBuffer 和 useBuffer 的内容大同小异,只是调用 OMX_AllocateBuffer 回传的 buffer header 中存储有 OMX 组件分配的 secure buffer header,这个buffer handle将会被封装成为 NativeHandle 回传给上层。OMXNodeInstance 中的 BufferMeta 将不会存储任何相关的资讯。
请添加图片描述

相关文章:

Android 13 - Media框架(26)- OMXNodeInstance(三)

上一节我们了解了OMXNodeInstance中的端口定义&#xff0c;这一节我们一起来学习ACodec、OMXNode、OMX 组件使用的 buffer 到底是怎么分配出来的&#xff0c;以及如何关联起来的。&#xff08;我们只会去了解 graphic buffer的创建、input bytebuffer的创建、secure buffer的创…...

力扣题目学习笔记(OC + Swift)21. 合并两个有序链表

21. 合并两个有序链表 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 链表解题经典三把斧&#xff1a; 哑巴节点栈快慢指针 此题比较容易想到的解法是迭代法&#xff0c;生成哑巴节点&#xff0c;然后迭代生成后续节点。…...

C# WPF上位机开发(windows pad上的应用)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 大部分同学可能都认为c# wpf只能用在pc端。其实这是一种误解。c# wpf固然暂时只能运行在windows平台上面&#xff0c;但是windows平台不仅仅是电脑…...

Word使用技巧【开题报告】

1、修改目录&#xff1a;选中目录&#xff0c;点击更新域。 2、更改或删除单个页面上的页眉或页脚 3、借助其他软件在Word导入参考文献 利用zetero导入文献&#xff1a;安装zetero 解决参考文献插入问题 在Word中插入文献操作步骤 英文文献出现“等”&#xff0c;如何解决 Zote…...

电子学会C/C++编程等级考试2022年06月(七级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:有多少种二叉树 输入n(1<n<13),求n个结点的二叉树有多少种形态 时间限制:1000 内存限制:65536输入 整数n输出 答案 样例输入 3样例输出 5 答案: //参考答案 #include<bits/stdc++.h> using namespace std; …...

git中的smart checkout和force checkout

切换分支时出现了这个问题&#xff1a; 这是因为shiyan01分支修改了代码,但是没有commit, 所以在切换到test分支的时候弹出这个窗口 一、smart checkout(智能签出) 会把shiyan01分支的改动内容带到test分支。合并处理后的内容就变成了test分支的内容,而shiyan01分支的改动会被…...

vue3整合Element-Plus,极速上手。

条件分页查询&#xff1a; 需求分析&#xff1a; form表单 Button按钮 Table表格 Pagination分页 页面布局&#xff1a; 搜索表单&#xff1a; 如果表单封装的数据较多&#xff0c;建议绑定到一个对象中。 …...

学习Vue2.x

文章目录 一、使用Vue脚手架1.ref和props属性2.mixin混入3.组件化编码流程4.webStorage5.组件自定义事件6.全局事件总线7.消息订阅与发布 二、使用步骤1.引入库 一、使用Vue脚手架 1.ref和props属性 ref属性&#xff1a; &#xff08;1&#xff09;被用来给元素或子组件注册应…...

新手如何快速熟悉代码,写出东西(持续更新)

目录 第一章、最小编程任务的设想1.1&#xff09;程序员入门会遇到的问题1.2&#xff09;最小编程任务的设想1.3&#xff09;编程逻辑1.4&#xff09;具体需求 第二章、最小编程单元的练习2.1&#xff09;代码/需求方面2.1.1&#xff09;初级练习2.1.2&#xff09;中级练习2.1.…...

11-网络安全框架及模型-软件安全能力成熟度模型(SSCMM)

目录 软件安全能力成熟度模型 1 背景概述 2 主要内容 3 成熟度等级定义 4 关键过程和实践 5 评估方法 6 改进建议 7 持续改进 8 主要价值 9 应用场景 10 优势和局限性 备注 软件安全能力成熟度模型 1 背景概述 SSCMM模型是软件安全能力成熟度模型&#xff0c;它描…...

Linux操作系统基础知识点

Linux是一种计算机操作系统&#xff0c;其内核由林纳斯本纳第克特托瓦兹&#xff08;Linus Benedict Torvalds&#xff09;于1991年首次发布。Linux操作系统通常与GNU套件一起使用&#xff0c;因此也被称为GNU/Linux。它是一种类UNIX的操作系统&#xff0c;设计为多用户、多任务…...

python 通过opencv及face_recognition识别人脸

效果&#xff1a; 使用Python的cv2库和face_recognition库来进行人脸检测和比对的 0是代表一样 认为是同一人。 代码&#xff1a; pip install opencv-python pip install face_recognition# 导入cv2库&#xff0c;用于图像处理 import cv2 # 导入face_recognition库&#…...

Android开发中常见的Hook技术有哪些?

Hook技术介绍 Hook技术是一种在软件开发中常见的技术&#xff0c;它允许开发者在特定的事件发生时插入自定义的代码逻辑。常见的应用场景包括在函数调用前后执行特定的操作&#xff0c;或者在特定的事件发生时触发自定义的处理逻辑。 在Android开发中&#xff0c;Hook通常是通…...

【linux c多线程】线程的创建,线程信息的获取,获取线程返回值

线程创建 ​专栏内容&#xff1a; 参天引擎内核架构 本专栏一起来聊聊参天引擎内核架构&#xff0c;以及如何实现多机的数据库节点的多读多写&#xff0c;与传统主备&#xff0c;MPP的区别&#xff0c;技术难点的分析&#xff0c;数据元数据同步&#xff0c;多主节点的情况下对…...

MFC或QT中,自绘控件的目的和实现步骤

MFC自绘控件的步骤 自绘控件的目的是为了能够自定义控件的外观、行为和交互方式&#xff0c;以满足特定的需求&#xff0c;同时增强应用程序的用户体验。 实现步骤如下&#xff1a; 1、创建一个继承自MFC控件基类&#xff08;如CButton、CStatic等&#xff09;的自定义控件类…...

ceph集群搭建详细教程(ceph-deploy)

ceph-deploy比较适合生产环境&#xff0c;不是用cephadm搭建。相对麻烦一些&#xff0c;但是并不难&#xff0c;细节把握好就行&#xff0c;只是命令多一些而已。 实验环境 服务器主机public网段IP&#xff08;对外服务&#xff09;cluster网段IP&#xff08;集群通信&#x…...

机器视觉系统选型-避免畸变

在定位及高精度测量的系统中&#xff0c;镜头畸变的影响尤其重要 • 使用远心镜头 • 进行系统标定...

机器学习笔记 - 线性判别分析(LDA)的原理和应用

一、LDA简述 线性判别分析(LDA)是监督机器学习中用于解决多类分类问题的一种方法。LDA通过数据降维来分离具有多个特征的多个类。这项技术在数据科学中很重要,因为它有助于优化机器学习模型。 线性判别分析,也称为正态判别分析 (NDA) 或判别函数分析 (DFA),遵循生成模型框…...

基于5G智能网关的智慧塔吊监测方案

塔吊是建筑施工中必不可少的设施&#xff0c;由于塔吊工作重心高、起重载荷大、人工视距/视角受限等因素&#xff0c;也使得塔吊在工作过程中着较多的危险因素。对此&#xff0c;可以部署基于工业5G智能网关搭建智慧塔吊安全监测系统&#xff0c;实现对塔吊运行的全局精细监测感…...

CountDownLatch详解以及用法示例

一、什么是CountDownLatch CountDownLatch中count down是倒数的意思&#xff0c;latch则是门闩的含义。整体含义可以理解为倒数的门栓。 CountDownLatch的作用也是如此&#xff0c;在构造CountDownLatch(int count)&#xff1a;的时候需要传入一个整数count&#xff0c;在这个…...

【http】缓存协议

✨ 专栏介绍 在当今互联网时代&#xff0c;计算机网络已经成为了人们生活和工作中不可或缺的一部分。而要实现计算机之间的通信和数据传输&#xff0c;就需要依靠各种网络协议来进行规范和约束。无论是浏览网页、发送电子邮件还是进行在线交流&#xff0c;都离不开各种各样的网…...

vscode中使用GitHub Copilot Chat

文章目录 一、什么是Github Copilot Chat二、安装使用三、如何使用1. 聊天功能2. 内联功能 一、什么是Github Copilot Chat GitHub Copilot Chat 由 OpenAI 的 GPT-4 大型多模态模型提供支持&#xff0c;能带来更准确的代码建议、解释和指导。GitHub Copilot Chat 的内联功能可…...

lvgl 双物理显示器的驱动实现

目录 一、背景 1. 要实现的功能2. lvgl 版本 二、简单粗暴的方式 理论上可以这样实现缺陷&#xff1a; 三、lvgl 自身机制支持 3.1 实现思路3.2 初始化缓冲区和注册显示驱动 3.2.1 复制lv_port_disp → lv_port_disp_23.2.2 修改 lv_port_disp_2 文件3.2.3 在应用层调用显示器…...

论文阅读——X-Decoder

Generalized Decoding for Pixel, Image, and Language Towards a Generalized Multi-Modal Foundation Model 1、概述 X-Decoder没有为视觉和VL任务开发统一的接口&#xff0c;而是建立了一个通用的解码范式&#xff0c;该范式可以通过采用共同的&#xff08;例如语义&#…...

【Kubernetes】控制器Statefulset

Statefulset控制器 一、概念二、Statefulset资源清单文件编写技巧2.1、查看定义Statefulset资源需要的字段2.2、查看statefulset.spec字段如何定义2.3、查看statefulset的spec.template字段如何定义 三、Statefulset使用案例&#xff1a;部署web站点3.1、编写一个Statefulset资…...

智能优化算法应用:基于鱼鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于鱼鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于鱼鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.鱼鹰算法4.实验参数设定5.算法结果6.参考文献7.MA…...

探索 Vue3 (五) 骨架屏

骨架屏是页面的一个空白版本&#xff0c;通常会在页面完全渲染之前&#xff0c;通过一些灰色的区块大致勾勒出轮廓&#xff0c;待数据加载完成后&#xff0c;再替换成真实的内容。 目前主流 UI库 都有骨架屏&#xff0c;如 Element-UI、Antd 可以看到使用起来非常简单&#x…...

java取出list中的某几个属性组成一个新的集合的几种方式

我用了三种方式,1:forEach循环;2:for循环;3:stream方法 package org.springblade.test;import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors;public class Test {org.junit.jupiter.api…...

开源自托管导航页配置服务Dashy本地搭建结合内网穿透远程访问

开源自托管导航页配置服务Dashy本地搭建结合内网穿透远程访问 简介1. 安装Dashy2. 安装cpolar3.配置公网访问地址4. 固定域名访问 简介 Dashy 是一个开源的自托管的导航页配置服务&#xff0c;具有易于使用的可视化编辑器、状态检查、小工具和主题等功能。你可以将自己常用的一…...

Cloudstack多个管理服务器节点

https://docs.cloudstack.apache.org/en/4.18.0.0/adminguide/reliability.html 参考翻译&#xff1a; 代理上支持多个管理服务器 在具有多个管理服务器的Cloudstack环境中&#xff0c;可以根据算法配置代理&#xff0c;将其连接到哪个管理服务器。这对于内部负载均衡器或高可…...

31. Ajax

简介 AJAX 是 Asynchronous JavaScript And XML 的简称。直译为&#xff0c;异步的JS和XML。AJAX的实际意义是&#xff0c;不发生页面跳转、异步载入内容并改写页面内容的技术。AJAX也可以简单的理解为通过JS向服务器发送请求。 AJAX这门技术很早就被发明&#xff0c;但是直到…...

ArrayList源码学习笔记(3)

时隔两年&#xff0c;重新读ArrayList源码&#xff0c;轻松了很多&#xff0c;以问题的方式记录一下收获 装饰器模式 注释中提到ArrayList本身不是线程安全的&#xff0c;注释如下&#xff1a; * <p><strong>Note that this implementation is not synchronized.&…...

flutter怎么对ReorderableListView中的用于排序的控制手柄进行显示或隐藏

我在使用ReorderableListView创建可排序列表的时候&#xff0c;需要在编辑的时候才显示右侧的控制排序的手柄。研究了半天&#xff0c;配合搜索引擎&#xff0c;才找到正确的方案。 答案很简单&#xff0c;就是在它的属性当中有一个叫做&#xff1a;buildDefaultDragHandles的…...

python 1200例——【9】斐波那契数列

文章目录 定义求解方法1. 递归方法2. 循环方法3. 动态规划方法4. 矩阵方法总结:定义 斐波那契数列(Fibonacci sequence)是一个在自然世界中经常出现的数学序列。它是由0和1开始,然后的每个数字都是前两个数字的和。因此,斐波那契数列的前几个数字是:0, 1, 1, 2, 3, 5, 8…...

JavaScript读写T5557卡源码

本示例使用发卡器&#xff1a; https://item.taobao.com/item.htm?spma1z10.5-c-s.w4002-21818769070.13.48ce6f89XlQ9Vf&id675212889085 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-t…...

【数据结构】LRU缓存的简单模拟实现(leetcode力扣146LRU缓存)

文章目录 一、定义二、LRU模拟实现二、代码实现 一、定义 LRU是Least Recently Used的缩写&#xff0c;意思是最近最少使用&#xff0c;它是一种Cache替换算法。 Cache的容量有限&#xff0c;因此当Cache的容量用完后&#xff0c;而又有新的内容需要添加进来时&#xff0c; 就…...

基于电商场景的高并发RocketMQ实战-Commitlog基于内存的高并发写入优化、基于JVM offheap的内存读写分离机制

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 【11来了】文章导读地址&#xff1a;点击查看文章导读&#xff01; &#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f3…...

工具系列:TensorFlow决策森林_(3)使用dtreeviz可视化

文章目录 介绍设置安装 TF-DF 和 dtreeviz导入库 可视化分类树加载、清洗和准备数据分割训练/测试集并训练模型训练一个随机森林分类器显示决策树检查叶节点统计信息决策树如何对实例进行分类特征空间划分 可视化回归树加载、清洗和准备数据分割训练/测试集并训练模型训练一个随…...

【算法学习】斐波那契数列模型-动态规划

前言 我在算法学习过程中&#xff0c;针对斐波那契数列模型的动态规划的例题进行了一个整理&#xff0c;并且根据标准且可靠一点的动态规划解题思路进行求解类似的动归问题&#xff0c;来达到学习和今后复习的必要。 所谓的斐波那契数列模型&#xff0c;即当前状态的值等于前两…...

ES的安装和RestClient的操作

目录 初识elasticsearch 什么是elasticsearch elasticsearch的发展 Lucene的优缺点 elasticsearch的优势 倒排索引 es与mysql的概念对比 文档 索引 概念对比 架构 安装es 安装kibana 安装ik分词器 分词器 安装ik分词器 ik分词器的拓展和停用词典 操作索引库…...

访问者模式(Visitor)

访问者模式(Visitor Pattern)是一种将算法与对象结构分离的行为型设计模式。这种模式主要用于对一个由许多不同类型的对象构成的复杂对象结构(如组合结构)进行操作,而不需要对这些对象的类进行修改。 访问者模式涉及以下几个角色: 访问者(Visitor):为每一个具体元素类…...

ATTCK红队评估一

一、环境搭建 主机 ip地址 win7外网服务器&#xff08;两张网卡&#xff09; 外网&#xff1a;192.168.92.135 内网&#xff1a;192.168.52.143 server2003域成员主机 内网&#xff1a;192.168.52.141 server2008域空主机 内网&#xff1a;192.168.52.138 kali攻击机 …...

W5500-EVB-Pico评估版介绍

文章目录 1 概述2 板载资源2.1 硬件规格2.2 硬件规格2.3 工作条件 3 参考资料3.2 原理图3.3 尺寸图 (单位 : mm)3.4 参考例程 4 硬件协议栈优势 1 概述 W5500-EVB-Pico是基于树莓派RP2040和完全硬连线TCP/IP控制器W5500的微控制器开发板-基本上与树莓派Pico板相同&#xff0c;但…...

单聊和群聊

TCP协议单聊 服务端&#xff1a; import java.awt.BorderLayout; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Vec…...

Swift 检测 iCloud状态

Show me the code: func isICloudContainerAvailable() -> Bool {if let _ FileManager.default.ubiquityIdentityToken {return true} else {return false} }推荐一下刚上线的 App 熊猫小账本&#xff0c;里面有用到这篇博客讲的内容 熊猫小账本 一个简洁的记账 App&…...

使用Windi CSS(基于vue-cli)

1、先创建vue项目 利用脚手架vue-cli创建&#xff0c;根据需求设置vue版本、babel等&#xff0c;无特别要求直接用默认的vue2或vue3就行 vue create 项目名 2、运行vue项目&#xff0c;利用vue-cli安装Windi CSS 官网指导&#xff1a;Vue CLI 集成 | Windi CSS 我的经历&a…...

操作无法完成(错误 0x000006ba),Windows 11 PDF打印机无法使用解决办法

操作无法完成(错误 0x000006ba)&#xff0c;Windows 11 PDF打印机无法使用解决办法 解决方式一 先重启一次电脑&#xff0c;看看是否可以解决问题。 解决方式二 重新启动 Printer Spooler 服务...

Settings中电池选项-Android13

Settings中电池选项-Android13 1、设置中界面2、电池计算2.1 充电时间计算2.1.1 BatteryUsageStats获取2.1.2 BatteryStatsImpl计算 2.2 电池剩余使用时间2.2.1 Estimate获取2.2.2 BatteryStatsImpl计算 3、电池信息来源4、命令模拟* 日志 [电池]Android 9.0 电池未充电与充电字…...

解密 Java ForEach 提前终止问题

目录 前言&#xff1a;场景复现分析与解决方案解决方案详解总结 前言&#xff1a; 你是否曾在使用 Java 8 的 forEach 迭代集合时遇到过提前终止循环的问题&#xff1f;在这篇博客中&#xff0c;我们将深入探讨这一问题&#xff0c;并提供多种解决方案。通过场景复现、分析源码…...

7_js_dom编程入门1

Objective&#xff08;本课目标&#xff09; 掌握获取页面元素的常用方法 掌握事件触发案例 能够区分innerText和innerHTML的区别 综合案例训练 1 DOM 介绍 1.1 什么是DOM 文档对象模型&#xff08;Document Object Model&#xff0c;简称DOM&#xff09;&#xff0c;是 …...