鸿蒙(API 12 Beta3版)【音频解码】

news2024/9/21 18:45:12

开发者可以调用本模块的Native API接口,完成音频解码,即将媒体数据解码为PCM码流。

当前支持的解码能力如下:

容器规格音频解码类型
mp4AAC、MPEG(MP3)、Flac、Vorbis、AudioViVid11+
m4aAAC
flacFlac
oggVorbis、opus
aacAAC
mp3MPEG(MP3)
amrAMR(amrnb、amrwb)
rawG711mu
apeAPE

适用场景

  • 音频播放

    在播放音频之前,需要先解码音频,再将数据输送到硬件扬声器播放。

  • 音频渲染

    在对音频文件进行音效处理之前,需要先解码再由音频处理模块进行音频渲染。

  • 音频编辑

    音频编辑(如调整单个声道的播放倍速等)需要基于PCM码流进行,所以需要先将音频文件解码。

开发指导

参考以下示例代码,完成音频解码的全流程,包括:创建解码器、设置解码参数(采样率/码率/声道数等)、开始、刷新、重置、销毁资源。

在应用开发过程中,开发者应按一定顺序调用方法,执行对应操作,否则系统可能会抛出异常或生成其他未定义的行为。具体顺序可参考下列开发步骤及对应说明。

如下为音频解码调用关系图:

1

在 CMake 脚本中链接动态库

target_link_libraries(sample PUBLIC libnative_media_codecbase.so)
target_link_libraries(sample PUBLIC libnative_media_core.so)
target_link_libraries(sample PUBLIC libnative_media_acodec.so)

开发步骤

  1. 添加头文件。
#include <multimedia/player_framework/native_avcodec_audiocodec.h>
#include <multimedia/native_audio_channel_layout.h>
#include <multimedia/player_framework/native_avcapability.h>
#include <multimedia/player_framework/native_avcodec_base.h>
#include <multimedia/player_framework/native_avformat.h>
#include <multimedia/player_framework/native_avbuffer.h>
  1. 创建解码器实例对象,OH_AVCodec *为解码器实例指针。
//c++标准库命名空间
using namespace std;
// 通过 codecname 创建解码器
OH_AVCapability *capability = OH_AVCodec_GetCapability(OH_AVCODEC_MIMETYPE_AUDIO_MPEG, false);
const char *name = OH_AVCapability_GetName(capability);
OH_AVCodec *audioDec_ = OH_AudioCodec_CreateByName(name);
// 设置判定是否为编码;设置false表示当前是解码。
bool isEncoder = false;
// 通过 Mimetype 创建解码器
OH_AVCodec *audioDec_ = OH_AudioCodec_CreateByMime(OH_AVCODEC_MIMETYPE_AUDIO_MPEG, isEncoder);
// 初始化队列
class ADecBufferSignal {
public:
    std::mutex inMutex_;
    std::mutex outMutex_;
    std::mutex startMutex_;
    std::condition_variable inCond_;
    std::condition_variable outCond_;
    std::condition_variable startCond_;
    std::queue<uint32_t> inQueue_;
    std::queue<uint32_t> outQueue_;
    std::queue<OH_AVBuffer *> inBufferQueue_;
    std::queue<OH_AVBuffer *> outBufferQueue_;
};
ADecBufferSignal *signal_;
  1. 调用OH_AudioCodec_RegisterCallback()注册回调函数。

    注册回调函数指针集合OH_AVCodecCallback,包括:

    • OH_AVCodecOnError:解码器运行错误。
    • OH_AVCodecOnStreamChanged:码流信息变化,如声道变化等。
    • OH_AVCodecOnNeedInputBuffer:运行过程中需要新的输入数据,即解码器已准备好,可以输入数据。
    • OH_AVCodecOnNewOutputBuffer:运行过程中产生了新的输出数据,即解码完成。

    开发者可以通过处理该回调报告的信息,确保解码器正常运转。

// OH_AVCodecOnError回调函数的实现
static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData)
{
    (void)codec;
    (void)errorCode;
    (void)userData;
}
// OH_AVCodecOnStreamChanged回调函数的实现
static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData)
{
    (void)codec;
    (void)format;
    (void)userData;
}
// OH_AVCodecOnNeedInputBuffer回调函数的实现
static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData)
{
    (void)codec;
    ADecBufferSignal *signal = static_cast<ADecBufferSignal *>(userData);
    unique_lock<mutex> lock(signal->inMutex_);
    signal->inQueue_.push(index);
    signal->inBufferQueue_.push(data);
    signal->inCond_.notify_all();
    // 解码输入码流送入inBufferQueue_队列
}
// OH_AVCodecOnNewOutputBuffer回调函数的实现
static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *data, void *userData)
{
    (void)codec;
    ADecBufferSignal *signal = static_cast<ADecBufferSignal *>(userData);
    unique_lock<mutex> lock(signal->outMutex_);
    signal->outQueue_.push(index);
    signal->outBufferQueue_.push(data);
    signal->outCond_.notify_all();
    // 将对应输出buffer的 index 送入outQueue_队列
    // 将对应解码完成的数据data送入outBufferQueue_队列
}
signal_ = new ADecBufferSignal();
OH_AVCodecCallback cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable};
int32_t ret = OH_AudioCodec_RegisterCallback(audioDec_, cb_, signal_);
if (ret != AVCS_ERR_OK) {
    // 异常处理
}
  1. (可选)OH_AudioCodec_SetDecryptionConfig设置解密配置。当获取到DRM信息(参考[音视频解封装]开发步骤第3步)后,通过此接口进行解密配置。DRM相关接口详见[DRM API文档]。此接口需在Prepare前调用。

添加头文件

#include <multimedia/drm_framework/native_mediakeysystem.h>
#include <multimedia/drm_framework/native_mediakeysession.h>
#include <multimedia/drm_framework/native_drm_err.h>
#include <multimedia/drm_framework/native_drm_common.h>

在 CMake 脚本中链接动态库

target_link_libraries(sample PUBLIC libnative_drm.so)

使用示例

// 根据DRM信息创建指定的DRM系统, 以创建"com.wiseplay.drm"为例
MediaKeySystem *system = nullptr;
int32_t ret = OH_MediaKeySystem_Create("com.wiseplay.drm", &system);
if (system == nullptr) {
    printf("create media key system failed");
    return;
}
// 进行DRM授权
// 创建解密会话
MediaKeySession *session = nullptr;
DRM_ContentProtectionLevel contentProtectionLevel = CONTENT_PROTECTION_LEVEL_SW_CRYPTO;
ret = OH_MediaKeySystem_CreateMediaKeySession(system, &contentProtectionLevel, &session);
if (session == nullptr) {
    printf("create media key session failed");
    return;
}
// 获取许可证请求、设置许可证响应等
// 设置解密配置, 即将解密会话、安全通路标志(当前音频解密不支持安全通路,应设置为false)设置到解码器中。
bool secureAudio = false;
ret = OH_AudioCodec_SetDecryptionConfig(audioDec_, session, secureAudio);
  1. 调用OH_AudioCodec_Configure()配置解码器。

    配置选项key值说明:

    描述AACFlacVorbisMPEGG711muAMR(amrnb、amrwb)APE
    OH_MD_KEY_AUD_SAMPLE_RATE采样率必须必须必须必须必须必须必须
    OH_MD_KEY_AUD_CHANNEL_COUNT声道数必须必须必须必须必须必须必须
    OH_MD_KEY_MAX_INPUT_SIZE最大输入长度可选可选可选可选可选可选可选
    OH_MD_KEY_AAC_IS_ADTS是否adts可选,默认1 latm类型------
    MD_KEY_AUDIO_SAMPLE_FORMAT输出音频流格式可选(SAMPLE_S16LE,SAMPLE_F32LE)-可选(SAMPLE_S16LE,SAMPLE_F32LE)可选可选(默认SAMPLE_S16LE)可选(SAMPLE_S16LE,SAMPLE_F32LE)可选
    MD_KEY_BITRATE可选可选可选可选可选可选可选可选
    MD_KEY_IDENTIFICATION_HEADERID Header--必须(和Codec_Config二选一)----
    MD_KEY_SETUP_HEADERSetup Header--必须(和Codec_Config二选一)----
    MD_KEY_CODEC_CONFIGMD_KEY_SETUP_HEADERID Header+Common Header+Setup Header 拼接-必须(和上述ID和Setup二选一)----
// 设置解码分辨率
int32_t ret;
// 配置音频采样率(必须)
constexpr uint32_t DEFAULT_SAMPLERATE = 44100;
// 配置音频码率(必须)
constexpr uint32_t DEFAULT_BITRATE = 32000;
// 配置音频声道数(必须)
constexpr uint32_t DEFAULT_CHANNEL_COUNT = 2;
// 配置最大输入长度(可选)
constexpr uint32_t DEFAULT_MAX_INPUT_SIZE = 1152;
// 配置是否为ADTS解码(acc)
constexpr uint32_t DEFAULT_AAC_TYPE = 1;
OH_AVFormat *format = OH_AVFormat_Create();
// 写入format
OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, DEFAULT_SAMPLERATE);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_BITRATE, DEFAULT_BITRATE);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, DEFAULT_CHANNEL_COUNT);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_MAX_INPUT_SIZE, DEFAULT_MAX_INPUT_SIZE);
OH_AVFormat_SetIntValue(format, OH_MD_KEY_AAC_IS_ADTS, DEFAULT_AAC_TYPE);
// 配置解码器
ret = OH_AudioCodec_Configure(audioDec_, format);
if (ret != AV_ERR_OK) {
    // 异常处理
}
  1. 调用OH_AudioCodec_Prepare(),解码器就绪。
ret = OH_AudioCodec_Prepare(audioDec_);
if (ret != AV_ERR_OK) {
    // 异常处理
}
  1. 调用OH_AudioCodec_Start()启动解码器,进入运行态。
unique_ptr<ifstream> inputFile_ = make_unique<ifstream>();
unique_ptr<ofstream> outFile_ = make_unique<ofstream>();
// 打开待解码二进制文件路径
inputFile_->open(inputFilePath.data(), ios::in | ios::binary); 
// 配置解码文件输出路径
outFile_->open(outputFilePath.data(), ios::out | ios::binary);
// 开始解码
ret = OH_AudioCodec_Start(audioDec_);
if (ret != AV_ERR_OK) {
    // 异常处理
}
  1. (可选)调用OH_AVCencInfo_SetAVBuffer(),设置cencInfo。

    若当前播放的节目是DRM加密节目,且由上层应用做媒体解封装,则须调用OH_AVCencInfo_SetAVBuffer()将cencInfo设置给AVBuffer,以实现AVBuffer中媒体数据的解密。

添加头文件

#include <multimedia/player_framework/native_cencinfo.h>

在 CMake 脚本中链接动态库

target_link_libraries(sample PUBLIC libnative_media_avcencinfo.so)

使用示例

auto buffer = signal_->inBufferQueue_.front();
int64_t size;
int64_t pts;
uint32_t keyIdLen = DRM_KEY_ID_SIZE;
uint8_t keyId[] = {
    0xd4, 0xb2, 0x01, 0xe4, 0x61, 0xc8, 0x98, 0x96,
    0xcf, 0x05, 0x22, 0x39, 0x8d, 0x09, 0xe6, 0x28};
uint32_t ivLen = DRM_KEY_IV_SIZE;
uint8_t iv[] = {
    0xbf, 0x77, 0xed, 0x51, 0x81, 0xde, 0x36, 0x3e,
    0x52, 0xf7, 0x20, 0x4f, 0x72, 0x14, 0xa3, 0x95};
uint32_t encryptedBlockCount = 0;
uint32_t skippedBlockCount = 0;
uint32_t firstEncryptedOffset = 0;
uint32_t subsampleCount = 1;
DrmSubsample subsamples[1] = { {0x10, 0x16} };
inputFile_.read(reinterpret_cast<char *>(&size), sizeof(size));
inputFile_.read(reinterpret_cast<char *>(&pts), sizeof(pts));
inputFile_.read((char *)OH_AVMemory_GetAddr(buffer), size);
OH_AVCencInfo *cencInfo = OH_AVCencInfo_Create();
if (cencInfo == nullptr) {
    // 异常处理
}
OH_AVErrCode errNo = OH_AVCencInfo_SetAlgorithm(cencInfo, DRM_ALG_CENC_AES_CTR);
if (errNo != AV_ERR_OK) {
    // 异常处理
}
errNo = OH_AVCencInfo_SetKeyIdAndIv(cencInfo, keyId, keyIdLen, iv, ivLen);
if (errNo != AV_ERR_OK) {
    // 异常处理
}
errNo = OH_AVCencInfo_SetSubsampleInfo(cencInfo, encryptedBlockCount, skippedBlockCount, firstEncryptedOffset,
    subsampleCount, subsamples);
if (errNo != AV_ERR_OK) {
    // 异常处理
}
errNo = OH_AVCencInfo_SetMode(cencInfo, DRM_CENC_INFO_KEY_IV_SUBSAMPLES_SET);
if (errNo != AV_ERR_OK) {
    // 异常处理
}
errNo = OH_AVCencInfo_SetAVBuffer(cencInfo, buffer);
if (errNo != AV_ERR_OK) {
    // 异常处理
}
errNo = OH_AVCencInfo_Destroy(cencInfo);
if (errNo != AV_ERR_OK) {
    // 异常处理
}
  1. 调用OH_AudioCodec_PushInputBuffer(),写入待解码的数据。

如果是结束,需要对flag标识成AVCODEC_BUFFER_FLAGS_EOS。

uint32_t index = signal_->inQueue_.front();
auto buffer = signal_->inBufferQueue_.front();
int64_t size;
int64_t pts;
// size是待解码数据的每帧帧长度。pts是每帧的时间戳,用于指示音频应该何时被播放。
// size和pts的获取来源:音视频资源文件或者待解码的数据流
// 若是解码音视频资源文件,则需从解封装OH_AVDemuxer_ReadSampleBuffer的buffer中获取
// 若是解码数据流,则需要从数据流的提供者获取。
// 此处为了介绍解码功能以测试文件中保存的size和pts为示例
inputFile_.read(reinterpret_cast<char *>(&size), sizeof(size));
inputFile_.read(reinterpret_cast<char *>(&pts), sizeof(pts));
inputFile_.read((char *)OH_AVBuffer_GetAddr(buffer), size);
OH_AVCodecBufferAttr attr = {0};
if (inputFile_->eof()) {
    attr.size = 0;
    attr.flags = AVCODEC_BUFFER_FLAGS_EOS;
} else {
    attr.size = size;
    attr.flags = AVCODEC_BUFFER_FLAGS_NONE;
}
attr.pts = pts;
OH_AVBuffer_SetBufferAttr(buffer, &attr);
int32_t ret = OH_AudioCodec_PushInputBuffer(audioDec_, index);
if (ret != AV_ERR_OK) {
    // 异常处理
}
  1. 调用OH_AudioCodec_FreeOutputBuffer(),输出解码后的PCM码流。

从API version 11开始,Audio Vivid新增获取获取元数据。

uint32_t index = signal_->outQueue_.front();
OH_AVBuffer *data = signal_->outBufferQueue_.front();
// 获取buffer attributes
OH_AVCodecBufferAttr attr = {0};
ret = OH_AVBuffer_GetBufferAttr(data, &attr);
if (ret != AV_ERR_OK) {
    // 异常处理
}
// 将解码完成数据data写入到对应输出文件中
pcmOutputFile_.write(reinterpret_cast<char *>(OH_AVBuffer_GetAddr(data)), attr.size);

// API version 11开始提供 获取audio vivid 元数据
OH_AVFormat * format = OH_AVBuffer_GetParameter(data);
uint8_t *metadata = nullptr;
size_t metaSize;
OH_AVFormat_GetBuffer(format,OH_MD_KEY_AUDIO_VIVID_METADATA,&metadata,&metaSize);

ret = OH_AudioCodec_FreeOutputBuffer(audioDec_, index);
if (ret != AV_ERR_OK) {
    // 异常处理
}
if (attr.flags == AVCODEC_BUFFER_FLAGS_EOS) {
    // 结束
}
  1. (可选)调用OH_AudioCodec_Flush()刷新解码器。

    调用OH_AudioCodec_Flush()后,解码器仍处于运行态,但会将当前队列清空,将已解码的数据释放。

    此时需要调用OH_AudioCodec_Start()重新开始解码。

    使用情况:

    • 在文件EOS之后,需要调用刷新
    • 在执行过程中遇到可继续执行的错误时(即OH_AudioCodec_IsValid 为true)调用
// 刷新解码器 audioDec_
ret = OH_AudioCodec_Flush(audioDec_);
if (ret != AV_ERR_OK) {
    // 异常处理
}
// 重新开始解码
ret = OH_AudioCodec_Start(audioDec_);
if (ret != AV_ERR_OK) {
    // 异常处理
}
  1. (可选)调用OH_AudioCodec_Reset()重置解码器。

    调用OH_AudioCodec_Reset()后,解码器回到初始化的状态,需要调用OH_AudioCodec_Configure()重新配置,然后调用OH_AudioCodec_Start()重新开始解码。

// 重置解码器 audioDec_
ret = OH_AudioCodec_Reset(audioDec_);
if (ret != AV_ERR_OK) {
    // 异常处理
}
// 重新配置解码器参数
ret = OH_AudioCodec_Configure(audioDec_, format);
if (ret != AV_ERR_OK) {
// 异常处理
}
  1. 调用OH_AudioCodec_Stop()停止解码器。
// 终止解码器 audioDec_
ret = OH_AudioCodec_Stop(audioDec_);
if (ret != AV_ERR_OK) {
    // 异常处理
}
  1. 调用OH_AudioCodec_Destroy()销毁解码器实例,释放资源。

    说明

    不要重复销毁解码器

// 调用OH_AudioCodec_Destroy, 注销解码器
ret = OH_AudioCodec_Destroy(audioDec_);
if (ret != AV_ERR_OK) {
    // 异常处理
} else {
    audioDec_ = NULL; // 不可重复destroy
}

最后呢

很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。

而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。

在这里插入图片描述

针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细鸿蒙(OpenHarmony )手册(共计1236页)与鸿蒙(OpenHarmony )开发入门视频,帮助大家在技术的道路上更进一步。

  • 《鸿蒙 (OpenHarmony)开发学习视频》
  • 《鸿蒙生态应用开发V2.0白皮书》
  • 《鸿蒙 (OpenHarmony)开发基础到实战手册》
  • OpenHarmony北向、南向开发环境搭建
  • 《鸿蒙开发基础》
  • 《鸿蒙开发进阶》
  • 《鸿蒙开发实战》

在这里插入图片描述

总结

鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发。

并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用。那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行! 自↓↓↓拿

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

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

相关文章

Journyx soap_cgi.pyc接口XML外部实体注入漏洞复现 [附POC]

文章目录 Journyx soap_cgi.pyc接口XML外部实体注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现Journyx soap_cgi.pyc接口XML外部实体注入漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内的相关技术…

线程池原理(一)线程池核心概述

更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验 线程回顾 创建线程的方式 继承 Thread 类实现 Runnable 接口 创建后的线程有如下状态&#xff1a; NEW&#xff1a;新建的线程&#xff0c;无任何操作 public static void main(String[] args) {Thread…

嵌入式初学-C语言-十八

#接嵌入式初学-C语言-十七# 变量的生命周期 1. 概念&#xff1a;变量在程序运行中存在的时间 2. 根据变量存在的时间不同&#xff0c;变量可分为静态存储和动态存储 3. 变量的存储类型 变量的完整定义格式&#xff1a;[存储类型] 数据类型 变量列表; 4. 存储类型 auto&…

yolov8人脸识别案例

GitHub - wangWEI201901/YOLOv8-Detection-Project: &#x1f6e3;️基于YOLOv8的智慧校园人脸识别和公路汽车检测

ITSM垂类下,企业如何逐步搭建一个好的AI Agent

随着企业数字化转型的不断深入&#xff0c;智能服务管理&#xff08;ITSM&#xff09;逐渐成为提升企业运营效率和服务质量的关键。企业纷纷探索如何将AI技术融入到IT服务管理中&#xff0c;以提升效率、降低成本并增强用户体验。成功实施AI并非易事&#xff0c;它要求企业在战…

探索全光网技术 | 全光网络技术方案选型建议五 (大厅场景)

目录 一、场景设计需求二、大厅场景拓扑三、部署方式四、产品相关规格说明五、方案优势与特点 注&#xff1a;本文章参考资料为&#xff1a;华三官方资料 - “新华三全光网络3.0解决方案&#xff08;教育&#xff09;”与 锐捷官方资料 - “【锐捷】高校极简以太全光3.X方案设计…

web基础与http协议与配置

目录 一、web基础 1.1 DNS与域名&#xff08;详解看前面章节&#xff09; 1.2 网页的概念&#xff08;HTTP/HTTPS&#xff09; 1.2.1 基本概念 1.2.2 HTML文档结构(了解) 1.2.3 web相关重点 1.2.4 静态资源和动态资源 二、http协议 2.1 概述 2.2 cookie和session&…

【HarmonyOS NEXT星河版开发学习】小型测试案例10-计数器案例

个人主页→VON 收录专栏→鸿蒙开发小型案例总结​​​​​ 基础语法部分会发布于github 和 gitee上面&#xff08;暂未发布&#xff09; 前言 鸿蒙开发中的点击事件是一个基础且重要的功能&#xff0c;它使得应用能够响应用户的各种触摸操作。通过对点击事件及其相关参数的深入…

扎克伯格说AI会让推荐系统变得更强大?一文读懂什么是智能推荐系统

导语&#xff1a;我认为很少有人意识到&#xff0c;推荐系统是世界上构想过的最大的计算系统之一。——Jensen Huang 前言 扎克伯格在 2024 年 7 月说&#xff0c;我们在组建 Reality Labs 之前就成立了 FAIR——人工智能研究中心&#xff0c;主要产品线有 Facebook 和 Insta…

006集—— 修饰符(public、private 、internal等)——C#学习笔记

封装 被定义为"把一个或多个项目封闭在一个物理的或者逻辑的包中"。在面向对象程序设计方法论中&#xff0c;封装是为了防止对实现细节的访问。 抽象和封装是面向对象程序设计的相关特性。抽象允许相关信息可视化&#xff0c;封装则使开发者实现所需级别的抽象。 C…

Python面试宝典第30题:找出第K大元素

题目 给定一个整数数组nums&#xff0c;请找出数组中第K大的数&#xff0c;保证答案存在。其中&#xff0c;1 < K < nums数组长度。 示例 1&#xff1a; 输入&#xff1a;nums [3, 2, 1, 5, 6, 4], K 2 输出&#xff1a;5 示例 2&#xff1a; 输入&#xff1a;nums …

python如何判断文件有多少行

如何统计读取的一个txt文本的行数呢&#xff1f; 最简单的办法是把文件读入一个大的列表中&#xff0c;然后统计列表的长度。如果文件的路径是以参数的形式filepath传递的&#xff0c;那么只用一行代码就可以完成我们的需求了&#xff1a; count len(open(filepath,rU).readl…

数字样机:惯性导航系统控制单元仿真

01.简介 惯性导航系统 (INS&#xff0c;Inertial Navigation System) 基于惯性原理建立&#xff0c;而惯性是物体自身的固有属性&#xff0c;因此其工作时既不依赖于外部信息&#xff0c;也不向外部辐射能量&#xff0c;优于卫星导航与无线电导航&#xff0c;是一种具备隐蔽性…

KEYSIGHT E5063A-006 无线功率传输分析

KEYSIGHT是德 E5063A-006 无线功率传输分析 E5063A-006 无线功率传输分析选件能够以任意负载阻抗设置&#xff0c;实时测量线圈或谐振器之间的无线功率传输效率&#xff08;WPT&#xff09;。基于测量结果进行的 2D/3D 分析&#xff0c;能够帮助用户更轻松地了解对负载阻抗的…

Selenium + Python 自动化测试07(滑块的操作方法)

我们的目标是&#xff1a;按照这一套资料学习下来&#xff0c;大家可以独立完成自动化测试的任务。 本篇文章主要讲述如何操作滑块。 目前很多系统登录或者注册的页面都有滑块相关的验证&#xff0c;selenium 中对滑块的基本操作采用了元素的拖曳的方式。需要用到Actiochains模…

市场惊人逆转:西格尔改口称降息紧迫性已减

最近&#xff0c;市场发生了惊人的逆转&#xff0c;让很多分析师和投资者感到意外。沃顿商学院教授**杰里米西格尔&#xff08;Jeremy Siegel&#xff09;**在短短三天内就改变了他对美联储政策的看法。此前&#xff0c;他曾呼吁美联储迅速降息&#xff0c;但现在他认为这种紧急…

五,搭建环境:辅助功能

五&#xff0c;搭建环境&#xff1a;辅助功能 文章目录 五&#xff0c;搭建环境&#xff1a;辅助功能编写登录失败异常编写常量类MD5 工具 (加密工具类)日志配置文件 编写登录失败异常 我们在 demo-module04-util 模块下&#xff0c;创建一个名为&#xff1a;com.rainbowsea.i…

10、MySQL-索引

目录 1、索引概述 2、索引结构 2.1 BTree 2.2 BTree 2.3 Hash 3、索引分类 4、索引语法 4.1 创建索引 4.2 查看索引 4.3 删除索引 5、SQL性能分析 5.1 SQL执行频率 5.2 慢查询日志 5.3 profile详情 5.4 explain执行计划 6、索引使用 6.1 验证索引效率 6.2 最左…

浪潮云服务器(Inspur)硬件监控指标解读

随着企业业务的快速发展&#xff0c;服务器的稳定运行变得愈发重要。浪潮云服务器以其高性能和稳定性&#xff0c;在数据中心中扮演着关键角色。为了确保服务器的稳定运行&#xff0c;监控易作为一款专业的IT基础设施监控软件&#xff0c;为浪潮云服务器提供了全面的硬件监控解…

Swift 中的函数式核心与命令式外壳:单向数据流

文章目录 前言函数式核心命令式外壳副作用可运行 Demo函数式核心部分命令式外壳部分副作用处理SwiftUI 界面代码运行截图代码解释 总结参考资料 前言 之前&#xff0c;我们讨论了在 Swift 中的函数式核心与命令式外壳的概念。其目标是通过值类型提取纯逻辑&#xff0c;并将副作…