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

MLT媒体程序框架03:滤镜——loudness

EBU R.128协议

引用链接
EBU的全称为European Broadcasting Union ,既欧洲广播联盟,为欧洲与北非各广播业者(包含广播电台与电视台)的合作组织,成立于1950年2月12日,有五十多个正式加盟国,总部位于瑞士日内瓦,目前中国是EBU的准会员。
EBU R.128实质上是欧洲广播联盟出的一个关于响度控制的建议书,该建议书在ITU-R BS.1770标准的(国际广播联盟规定的音频节目响度及真峰值的测量算法)基础之上,对响度的被测主体、积分窗长等细节作了更加明确的定义。

响度和动态范围的定义与相关的计量单位

  • 响度(Loudness)的定义: 在声学中,响度是人对声音压力的主观感受,也是听觉的一种属性,根据这种属性,可以对声音进行排序,如从安静排列到响亮,亦或者从响亮排列至安静。响度虽是声音的物理属性,但其却与听者的生理感受,心理感受息息相关,准确来说这属于心理物理学的范畴了。

  • 音量单位dBFS与dB: 首先dBFS与dB都是分贝的意思,而分贝一般指的就是音量大小。 dBFS全称decibels relative to full scale,什么叫full scale呢?既是满刻度,具体来讲是将0作为这种满刻度单位的最大值(也就是说此类值均为负数),凡是带FS后缀的计量单位都可这样理解(如LUFS或LKFS)。dB常用来形容一个音量到目标音量的“距离”,比如需要将一个信号从-4dBFS提升至-1dBFS,那么就需要对-4dBFS做3dB的提升操作。在业界,dBFS常被简称为dB,如-4dB等等。

  • 动态范围: 用通俗不严谨的话来说,动态范围指的是最大音量与最小音量之间的“距离”值,这个“距离”值就被称为动态范围,比如一段音频中的最大音量为-2dBFS,最小音量为-8dBFS,那么它的动态范围就是6dB。站在AD转换器的角度来说,动态范围指的是信号可以达到的最大不失真电平与本底噪声的差值。

  • EBU响度单位LUFS: LUFS的全称为Loudness units relative to full scale,既相对完整刻度的响度单位。广电行业中,LUFS是有一个目标响度值的,那就是-23LUFS,该值是广播世界的终极响度参考值!LUFS的数值越大,其响度就越大。至于为什么是-23LUFS,笔者暂未做深入研究。另外,LKFS是国际广播联盟用的单位,与LUFS差不多。

  • EBU响度单位LU: LU的全称为Loudness units,通常1LU“等同于”1dB(仅仅是理解层面上的“相等”),常用来形容两个LUFS之间的“距离”,如-25LUFS与-18LUFS间差了7LU。综上所述,dBFS与LUFS, dB与LU,虽测量算法不同,但其含义却是相似的。

响度示值,响度范围和真峰值的介绍

  • 瞬时响度 Momentary Loudness: 瞬时响度指的是400MS(毫秒)内的响度,并每过100ms进行一次更新,响应相当灵敏。
  • 短期响度 Short Term Loudness: 短期响度是提取3秒以内的信号,表达的是3S内的平均响度。
  • 综合响度 Integrated Loudness: 综合响度指的是整段音频的平均响度。
  • 响度范围 Loudness Range: 响度范围,经常被简称为LRA,其代表的是两个LUFS之间的“距离”,如一段音频的最小响度为-25LUFS,最大响度为-18LUFS,其间差了7LU,既代表该音频的响度范围为7LU。响度范围与动态范围表达的是一个意思,只是测量方法不一样。
  • 真峰值 True Peak: 在说真峰值之前,先用通俗的话来说说峰值是什么,峰值就是波形振幅的波峰值(波形有波谷和波峰之分),说白了就是波形瞬态的最大电平值。那为什么要在峰值之前加个“真”字呢?原因是这样的,以前有一种峰值测量方法,只有当峰值的持续时间超过一定的时间时(通常是几毫秒),才会计算出比较准确的峰值,这种测量算法被称为准峰值(QPPM)。而EBU给出了一种新的算法,无论它的持续时间有多短,都能正确的测量出其波形的真实峰值水平,故此,称其为真峰值。那么响度表中的真峰值指示条是用来干嘛的呢?它是用来检测信号有没有过载的,一旦信号过载就会被削波造成信号失真,正因如此,EBU给出建议为真峰值不要超过-1dBTP,目的就是防止信号产生过载削波,其单位为dBTP(dB True Peak真实峰值),对应的值是dBFS值。

双遍滤镜(loudness)

主要用于音频向度的精准标准化,其核心作用是通过两次处理(Double Pass)分析音频特征并应用目标响度参数,确保输出音频符合行业标准(如EBU R128 或 ITU-R BS.1770),同时优化动态范围控制

使用方式

One Pass: 调用滤镜分析得到result

std::string AudioAnalyze::analyzeAudio(const std::string &path,int trimIn,int trimOut) {Producer producer(getGlobalProfile(), nullptr,path.c_str());if(producer.get_length() <= 1 || producer.get_int("audio_index") == -1){std::cout << "analyzeAudio no effect"  << std::endl;return "";}if(trimOut > 0){producer.set_in_and_out(trimIn,trimOut);}Filter filter(getGlobalProfile(),"loudness");filter.set("program",-29);producer.attach(filter);Consumer consumer(getGlobalProfile(), "null");consumer.set("terminate_on_pause",0);consumer.connect(producer);consumer.start();while (!consumer.is_stopped()) {// ignoreif(filter.property_exists("results")){const char *results = filter.get("results");if(results != nullptr) {std::cout << "analyzeAudio results:" << results << std::endl;consumer.stop();return results;} else {std::cout << "analyzeAudio results:" << "error: key is null" << std::endl;return "";}}}return "";
}

Two Pass: 把result写入滤镜参数中,则会自动调整目标响度

std::shared_ptr<Filter> loudnessFilter{nullptr};
if (!results.empty()) {loudnessFilter = std::make_shared<Filter>(getGlobalProfile(), "loudness");loudnessFilter->set("program", configuration.aiDefaultLoudness);loudnessFilter->set("disable", 0);loudnessFilter->set("reload", 1);auto length = results.length() + 1;char *result = (char *) malloc(results.length() + 1);memcpy((void *) result, (const void *) results.c_str(), results.length());result[length - 1] = '\0';loudnessFilter->set("results", result);
}
loudnessFilter->set_in_and_out(trimIn, trimOut);
childClipInfo->producer->attach(*loudnessFilter);

关键源码分析

filter_get_audio

static int filter_get_audio(mlt_frame frame,void **buffer,mlt_audio_format *format,int *frequency,int *channels,int *samples)
{mlt_filter filter = mlt_frame_pop_audio(frame);mlt_properties properties = MLT_FILTER_PROPERTIES(filter);mlt_service_lock(MLT_FILTER_SERVICE(filter));// Get the producer's audio*format = mlt_audio_f32le;mlt_frame_get_audio(frame, buffer, format, frequency, channels, samples);char *results = mlt_properties_get(properties, "results");if (buffer && buffer[0] && results && strcmp(results, "")) {// Two Pass的时候走这个函数apply(filter, frame, buffer, format, frequency, channels, samples);} else {// One Pass的时候走这个函数analyze(filter, frame, buffer, format, frequency, channels, samples);}mlt_service_unlock(MLT_FILTER_SERVICE(filter));return 0;
}

analyze:分析得到原音频信息

static void analyze(mlt_filter filter,mlt_frame frame,void **buffer,mlt_audio_format *format,int *frequency,int *channels,int *samples)
{private_data *private = (private_data *) filter->child;mlt_position pos = mlt_filter_get_position(filter, frame);// If any frames are skipped, analysis data will be incomplete.// 作用:确保音频帧按顺序处理,跳过帧会导致分析中断。// 原因:EBU R128 要求连续分析,缺失帧会导致积分响度计算错误。if (private->analyze && pos != private->last_position + 1) {mlt_log_error(MLT_FILTER_SERVICE(filter), "Analysis Failed: Bad frame sequence\n");destroy_analyze_data(filter);}// Analyze Audioif (!private->analyze && pos == 0) {init_analyze_data(filter, *channels, *frequency);}if (private->analyze) {// 作用:将当前音频帧数据(buffer)输入 EBU R128 分析器,更新内部状态。ebur128_add_frames_float(private->analyze->state, *buffer, *samples);if (pos + 1 == mlt_filter_get_length2(filter, frame)) {mlt_properties properties = MLT_FILTER_PROPERTIES(filter);double loudness = 0.0;double range = 0.0;double tmpPeak = 0.0;double peak = 0.0;int i = 0;char result[MAX_RESULT_SIZE];// 计算整体响度ebur128_loudness_global(private->analyze->state, &loudness);// 计算响度范围ebur128_loudness_range(private->analyze->state, &range);// 获取声道峰值for (i = 0; i < *channels; i++) {ebur128_sample_peak(private->analyze->state, i, &tmpPeak);if (tmpPeak > peak) {peak = tmpPeak;}}// 格式化结果并存储snprintf(result, MAX_RESULT_SIZE, "L: %lf\tR: %lf\tP %lf", loudness, range, peak);result[MAX_RESULT_SIZE - 1] = '\0';mlt_log_info(MLT_FILTER_SERVICE(filter), "Stored results: %s\n", result);mlt_properties_set(properties, "results", result);destroy_analyze_data(filter);}private->last_position = pos;}
}
ebur128_gated_loudness: 计算 综合响度(Integrated Loudness)

这段代码是 EBU R128 综合响度(Integrated Loudness) 的核心计算逻辑,用于在音频处理中通过门限控制(Gating)剔除低能量部分,最终得到符合标准的响度值。

static int
ebur128_gated_loudness(ebur128_state** sts, size_t size, double* out) {struct ebur128_dq_entry* it;double gated_loudness = 0.0;double relative_threshold = 0.0;size_t above_thresh_counter = 0;size_t i, j, start_index;// 检查输入的音频状态结构体数组 sts 是否启用了综合响度模式(EBUR128_MODE_I)。若未启用,返回错误。
// 综合响度模式是 EBU R128 的核心功能,需通过 ebur128_init 初始化时设置模式标志for (i = 0; i < size; i++) {if (sts[i] && (sts[i]->mode & EBUR128_MODE_I) != EBUR128_MODE_I) {return EBUR128_ERROR_INVALID_MODE;}}
// 作用:遍历所有音频状态实例,调用 ebur128_calc_relative_threshold 计算 相对门限
// 相对门限:基于音频块能量分布,动态确定一个阈值,剔除低于该值的部分(如静音段或背景噪声)
// 公式:相对门限 = 平均能量 × 相对门限因子(默认-10 dB,即 relative_gate_factor = 0.1)
// 引用:EBU R128 要求综合响度计算需忽略低于动态门限的音频段,以聚焦主要节目内容for (i = 0; i < size; i++) {if (!sts[i]) {continue;}ebur128_calc_relative_threshold(sts[i], &above_thresh_counter,&relative_threshold);}if (!above_thresh_counter) {*out = -HUGE_VAL;return EBUR128_SUCCESS;}relative_threshold /= (double) above_thresh_counter;relative_threshold *= relative_gate_factor;
// 作用:根据相对门限值,确定直方图中高于门限的起始索引 start_index。
// 直方图优化:若启用直方图模式(use_histogram),直接遍历预计算的能量区间,跳过低能量部分。
// 未启用直方图:则需遍历块链表(block_list),逐个检查能量是否高于门限。
// 引用:直方图加速了能量统计,是 EBU R128 实现高效计算的关键优化 above_thresh_counter = 0;if (relative_threshold < histogram_energy_boundaries[0]) {start_index = 0;} else {start_index = find_histogram_index(relative_threshold);if (relative_threshold > histogram_energies[start_index]) {++start_index;}}
// 作用:统计所有高于门限的音频块能量总和 gated_loudness 及其数量 above_thresh_counter。
// 直方图模式:通过预计算的能量值 histogram_energies 和直方图计数快速累加。
// 块链表模式:遍历链表,筛选符合门限的块并累加能量。
// 引用:EBU R128 要求忽略低于门限的音频段,例如静音或低电平背景声for (i = 0; i < size; i++) {if (!sts[i]) {continue;}if (sts[i]->d->use_histogram) {for (j = start_index; j < 1000; ++j) {gated_loudness +=sts[i]->d->block_energy_histogram[j] * histogram_energies[j];above_thresh_counter += sts[i]->d->block_energy_histogram[j];}} else {STAILQ_FOREACH(it, &sts[i]->d->block_list, entries) {if (it->z >= relative_threshold) {++above_thresh_counter;gated_loudness += it->z;}}}}if (!above_thresh_counter) {*out = -HUGE_VAL;return EBUR128_SUCCESS;}
// 作用:
//  平均能量:将累积的能量总和除以有效块数量,得到平均能量。
// 能量转响度:调用 ebur128_energy_to_loudness 将能量转换为 LUFS(Loudness Units Full Scale)。
// 公式:LUFS = 10 × log₁₀(平均能量) - 绝对偏移值(如-0.691 dB,用于校准滤波器响应)
// 引用:LUFS 是 EBU R128 的标准化响度单位,综合响度目标值为 -23 LUFS(广播领域)gated_loudness /= (double) above_thresh_counter;*out = ebur128_energy_to_loudness(gated_loudness);return EBUR128_SUCCESS;
}
ebur128_loudness_range_multiple:计算响度范围(Loudness Range, LRA)

用于衡量音频节目中响度的动态变化
计算多个音频流的综合响度范围(LRA),即节目中最响的 95% 部分与最安静的 10% 部分之间的响度差(单位:LU)

输入:
sts:多个 ebur128_state 状态对象的数组(支持多路音频流合并计算)。
size:数组长度。
输出:
out:计算得到的 LRA 值。
返回值:错误码(成功为 EBUR128_SUCCESS)。

int ebur128_loudness_range_multiple(ebur128_state** sts,size_t size,double* out) {size_t i, j;struct ebur128_dq_entry* it;double* stl_vector;size_t stl_size;double* stl_relgated;size_t stl_relgated_size;double stl_power, stl_integrated;/* High and low percentile energy */double h_en, l_en;int use_histogram = 0;// 模式校验
// 必须启用 LRA 模式:所有状态对象需通过 EBUR128_MODE_LRA 初始化。
// 直方图模式一致性:所有状态对象需统一启用或禁用直方图(EBUR128_MODE_HISTOGRAM)。for (i = 0; i < size; ++i) {if (sts[i]) {if ((sts[i]->mode & EBUR128_MODE_LRA) != EBUR128_MODE_LRA) {return EBUR128_ERROR_INVALID_MODE;}if (i == 0 && sts[i]->mode & EBUR128_MODE_HISTOGRAM) {use_histogram = 1;} else if (use_histogram != !!(sts[i]->mode & EBUR128_MODE_HISTOGRAM)) {return EBUR128_ERROR_INVALID_MODE;}}}
// 直方图模式计算if (use_histogram) {unsigned long hist[1000] = { 0 };size_t percentile_low, percentile_high;size_t index;stl_size = 0;stl_power = 0.0;for (i = 0; i < size; ++i) {if (!sts[i]) {continue;}for (j = 0; j < 1000; ++j) {// 直方图累加:合并所有音频流的短期能量直方图(3秒窗口)。hist[j] += sts[i]->d->short_term_block_energy_histogram[j];stl_size += sts[i]->d->short_term_block_energy_histogram[j];stl_power += sts[i]->d->short_term_block_energy_histogram[j] *histogram_energies[j];}}if (!stl_size) {*out = 0.0;return EBUR128_SUCCESS;}
//门限处理:排除低于平均能量 -20 dB 的块(minus_twenty_decibels = 0.01)。// 平均能量stl_power /= stl_size;// // 应用-20 dB门限stl_integrated = minus_twenty_decibels * stl_power;if (stl_integrated < histogram_energy_boundaries[0]) {index = 0;} else {// 找到门限对应的直方图索引(直方图优化:跳过低于门限的区间,减少计算量。)index = find_histogram_index(stl_integrated);if (stl_integrated > histogram_energies[index]) {++index;}}stl_size = 0;for (j = index; j < 1000; ++j) {stl_size += hist[j];}if (!stl_size) {*out = 0.0;return EBUR128_SUCCESS;}
// 遍历直方图:累加直方图计数,找到对应百分位的能量值。// 10% 低百分位percentile_low = (size_t) ((stl_size - 1) * 0.1 + 0.5);// 95% 高百分位percentile_high = (size_t) ((stl_size - 1) * 0.95 + 0.5);stl_size = 0;j = index;while (stl_size <= percentile_low) {stl_size += hist[j++];}l_en = histogram_energies[j - 1];while (stl_size <= percentile_high) {stl_size += hist[j++];}h_en = histogram_energies[j - 1];
// 计算 LRA(将能量值转换为响度(LU),计算高低百分位的差值*out = ebur128_energy_to_loudness(h_en) - ebur128_energy_to_loudness(l_en);return EBUR128_SUCCESS;}
// 非直方图模式计算同理stl_size = 0;for (i = 0; i < size; ++i) {if (!sts[i]) {continue;}STAILQ_FOREACH(it, &sts[i]->d->short_term_block_list, entries) {++stl_size;}}if (!stl_size) {*out = 0.0;return EBUR128_SUCCESS;}stl_vector = (double*) malloc(stl_size * sizeof(double));if (!stl_vector) {return EBUR128_ERROR_NOMEM;}j = 0;for (i = 0; i < size; ++i) {if (!sts[i]) {continue;}STAILQ_FOREACH(it, &sts[i]->d->short_term_block_list, entries) {stl_vector[j] = it->z;++j;}}qsort(stl_vector, stl_size, sizeof(double), ebur128_double_cmp);stl_power = 0.0;for (i = 0; i < stl_size; ++i) {stl_power += stl_vector[i];}stl_power /= (double) stl_size;stl_integrated = minus_twenty_decibels * stl_power;stl_relgated = stl_vector;stl_relgated_size = stl_size;while (stl_relgated_size > 0 && *stl_relgated < stl_integrated) {++stl_relgated;--stl_relgated_size;}if (stl_relgated_size) {h_en = stl_relgated[(size_t) ((stl_relgated_size - 1) * 0.95 + 0.5)];l_en = stl_relgated[(size_t) ((stl_relgated_size - 1) * 0.1 + 0.5)];free(stl_vector);*out = ebur128_energy_to_loudness(h_en) - ebur128_energy_to_loudness(l_en);} else {free(stl_vector);*out = 0.0;}return EBUR128_SUCCESS;
}
ebur128_sample_peak:获取指定声道采样峰值(Sample Peak)

作用:获取音频流中指定声道的采样峰值电平(单位:dBFS)。
采样峰值(Sample Peak):音频信号在数字域中的最大绝对值,未经插值处理,直接来自采样点。
用途:检测音频是否削波(超过 0 dBFS),确保符合广播或流媒体的响度标准。

int ebur128_sample_peak(ebur128_state* st,unsigned int channel_number,double* out) {if ((st->mode & EBUR128_MODE_SAMPLE_PEAK) != EBUR128_MODE_SAMPLE_PEAK) {return EBUR128_ERROR_INVALID_MODE;}if (channel_number >= st->channels) {return EBUR128_ERROR_INVALID_CHANNEL_INDEX;}*out = st->d->sample_peak[channel_number];return EBUR128_SUCCESS;
}

apply

核心目标:将音频的响度调整到用户设定的目标值(如 EBU R128 规定的 -23 LUFS)。
输入依赖:需要预先通过分析阶段获取当前音频的响度(in_loudness)、响度范围(in_range)和峰值(in_peak)。
操作:计算增益系数并应用到音频数据,使其响度匹配目标值。

static void apply(mlt_filter filter,mlt_frame frame,void **buffer,mlt_audio_format *format,int *frequency,int *channels,int *samples)
{mlt_properties properties = MLT_FILTER_PROPERTIES(filter);char *results = mlt_properties_get(properties, "results");double in_loudness;double in_range;double in_peak;int scan_return = sscanf(results, "L: %lf\tR: %lf\tP %lf", &in_loudness, &in_range, &in_peak);if (scan_return != 3) {mlt_log_error(MLT_FILTER_SERVICE(filter), "Unable to load results: %s\n", results);} else {// 计算增益系数// 增益公式是固定的double target_db = mlt_properties_get_double(properties, "program");double delta_db = target_db - in_loudness;double coeff = delta_db > -90.0 ? pow(10.0, delta_db / 20.0) : 0.0;float *p = *buffer;int count = *samples * *channels;// 线性增益:将每个音频样本乘以计算出的增益系数。// 声道处理:遍历所有声道和样本,统一应用增益。for (int i = 0; i < count; i++) {p[i] = p[i] * coeff;}}
}

相关文章:

MLT媒体程序框架03:滤镜——loudness

EBU R.128协议 引用链接 EBU的全称为European Broadcasting Union &#xff0c;既欧洲广播联盟&#xff0c;为欧洲与北非各广播业者&#xff08;包含广播电台与电视台&#xff09;的合作组织&#xff0c;成立于1950年2月12日,有五十多个正式加盟国,总部位于瑞士日内瓦,目前中国…...

jenkins配置连接k8s集群

jenkins配置连接k8s集群 前言 我这边jenkins是在一个服务器里面&#xff0c;k8s集群在其他服务器&#xff0c;实现连接 首先jenkins下载有k8s插件 进入配置页面 获取k8s-api-server地址 对应k8s服务器执行 kubectl config view --minify -o jsonpath{.clusters[0].cluste…...

如何选择缓存模式?

如何选择缓存模式 当一个系统引入缓存后&#xff0c;最大的挑战之一便是如何确保缓存与后端数据库的一致性。目前&#xff0c;常见的解决方案主要有Cache Aside、Read/Write Throught和Write Back这三种缓存更新策略。 Read/Write Throught策略 读操作方面&#xff0c;如果缓…...

机器学习常见面试题

常见基模型 1. 线性模型&#xff08;Linear Models&#xff09; 特点&#xff1a;通过线性组合特征进行预测&#xff0c;适合处理线性关系。常见类型&#xff1a; 线性回归&#xff08;Linear Regression&#xff09;逻辑回归&#xff08;Logistic Regression&#xff09;岭回…...

网络安全配置截图 网络安全i

网络安全概念及规范 1.网络安全定义 网络安全的概述和发展历史 网络安全 广义的网络安全&#xff1a;Cyber Security&#xff08;网络空间安全&#xff09; 网络空间有独立且相互依存的信息基础设施和网络组成&#xff0c;包括互联网、电信网、计算机系统、嵌入式处理器和控…...

k8s概念及k8s集群部署(Centos7)

Centos7部署k8s集群 部署之前&#xff0c;先简单说下k8s是个啥&#xff1a; 一、k8s简介&#xff1a; k8s&#xff0c;全称&#xff1a;kubernetes&#xff0c;它可以看作是一个分布式系统支撑平台。k8s的作用&#xff1a; 1、故障自愈&#xff1a; k8s这个玩意可以监控容器…...

Manus详细介绍,Manus核心能力介绍

文章目录 前言Manus产品定位与核心理念:Manus产品特性与未来体验战略:Manus商业价值与创新指标:Manus技术特点与竞争优势:Manus用户反馈与展望:Manus市场竞争优势与团队战略:Manus深度总结与启发: 前言 这是一篇关于Manus智能体产品的用户体验评价报告&#xff0c;主要介绍了M…...

Apache XTable:在数据湖仓一体中推进数据互作性

Apache XTable 通过以多种开放表格式提供对数据的访问&#xff0c;在增强互作性方面迈出了一大步。移动数据很困难&#xff0c;在过去&#xff0c;这意味着在为数据湖仓一体选择开放表格式时&#xff0c;您被锁定在该选择中。一个令人兴奋的项目当在数据堆栈的这一层引入互作性…...

Java直通车系列14【Spring MVC】(深入学习 Controller 编写)

目录 基本概念 编写 Controller 的步骤和要点 1. 定义 Controller 类 2. 映射请求 3. 处理请求参数 4. 调用业务逻辑 5. 返回响应 场景示例 1. 简单的 Hello World 示例 2. 处理路径变量和请求参数 3. 处理表单提交 4. 处理 JSON 数据 5. 异常处理 基本概念 Cont…...

36-Openwrt wifi命令工具iwconfig、iwinfo、iwpriv、iwlist

增对wifi的调试命令有很多,这边列出我们常用的命令提供参考,方便查看信息定位问题。 1、iwconfig 查看当前 WIFI 的工作信道以及工作带宽模式: root@openwrt:/# iwconfig ra0 ra0 mt7603e ESSID:"openwrt" Mode:Managed Channel:8 Access Point: DC:4B…...

tauri加载网页处理点击a链接默认浏览器打开问题

添加click事件&#xff0c;当点击了a标签&#xff0c;就阻止默认事件&#xff0c;然后自己处理&#xff0c;在自己窗口中打开这个页面。将这个js注入到页面中就可以了 const hookClick (e) > {console.log(hookClick, e)e.preventDefault()const origin e.target.closest…...

openharmony 软总线-设备发现流程

6.1 设备发现流程 6.1.1 Wi-Fi设备发现 6.1.1.1 Wi-Fi设备发现流程 Wi-Fi设备在出厂状态或者恢复出厂状态下&#xff0c;设备上电默认开启SoftAP模式&#xff0c;SoftAP的工作信道在1&#xff0c;6&#xff0c;11中随机选择&#xff0c;SoftAP的Beacon消息中携带的SSID eleme…...

大白话CSS 优先级计算规则的详细推导与示例

大白话CSS 优先级计算规则的详细推导与示例 答题思路 引入概念&#xff1a;先通俗地解释什么是 CSS 优先级&#xff0c;让读者明白为什么要有优先级规则&#xff0c;即当多个 CSS 样式规则作用于同一个元素时&#xff0c;需要确定哪个规则起作用。介绍优先级的分类&#xff1…...

【GoTeams】-4:为项目引入etcd

本文目录 1. 书接上回2. 引入etcddiscoverystruct{}{} resolverserver 3. 将服务注册到etcd中4. 梳理下etcd调用逻辑 1. 书接上回 本节是为项目引入etcd这个环节&#xff0c;然后我们来看看具体该怎么实现。 首先来谈谈为什么要引入服务发现&#xff1f; 动态服务注册与发现…...

DeepSeek + Kimi:高效制作PPT实战详解

在快节奏的职场环境中&#xff0c;制作高质量的PPT已成为许多人的日常任务。然而&#xff0c;从零开始构思、设计、撰写并优化一份精美的PPT往往耗时费力。幸运的是&#xff0c;AI技术的飞速发展为我们提供了全新的解决方案。本文将详细介绍如何利用DeepSeek与Kimi智能助手的高…...

计算机基础:二进制基础06,用八进制来计数

专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏&#xff0c;故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 &#xff08;一&#xff09;WIn32 专栏导航 上一篇&#xff1a;计算机基础&#xff1a;二进制基础05&#xff0c;八进制简介 回…...

OSCP最新备考攻略:迎接2024改版后的OSCP+认证

OSCP&#xff08;Offensive Security Certified Professional&#xff09;是渗透测试领域一块金字招牌&#xff0c;由Offensive Security打造&#xff0c;因其硬核实战和高门槛备受推崇。2024年11月1日&#xff0c;OSCP迎来了一次重量级改版&#xff0c;推出了OSCP认证&#xf…...

Jmeter使用介绍

文章目录 前言Jmeter简介安装与配置JDK安装与配置JMeter安装与配置 打开JMeter方式一方式二 设置Jmeter语言为中文方法一&#xff08;仅一次性&#xff09;方法二(永久设置成中文) Jmeter文件常用目录 元件与组件元件组件元件的作用域元件的执行顺序第一个案例添加线程组添加 H…...

hooks useModule自定义hooks (二次封装AgGridReact ag-table)自定义表头,自定义表头搜索

场景业务&#xff1a; 多次运用AgGridReact的table 列表 思路&#xff1a; 运用自定义hooks进行二次封装&#xff1a; 通用配置例如&#xff1a;传参的参数&#xff0c;传参的url&#xff0c;需要缓存的key这些键值类 定制化配置例如&#xff1a;需要对table 的一些定制化传…...

Android Studio 配置国内镜像源

Android Studio版本号&#xff1a;2022.1.1 Patch 2 1、配置gradle国内镜像&#xff0c;用腾讯云 镜像源地址&#xff1a;https\://mirrors.cloud.tencent.com/gradle 2、配置Android SDK国内镜像 地址&#xff1a;Index of /AndroidSDK/...

OFA:通过简单的序列到序列学习框架统一架构、任务和模态

【摘要】 摘要总结 本文介绍了一种新的统一框架OFA(One For All),旨在通过一个简单的序列到序列学习框架来实现跨模态和单模态任务的统一预训练。OFA框架支持任务无关性和模态无关性,并能实现任务全面性。OFA统一了包括图像生成、视觉定位、图像字幕、图像分类、语言建模…...

C++11新特性2.空指针nullptr

目录 一.简介 1.基本概念 2.语法 二.使用示例 示例1&#xff1a;初始化指针 示例2&#xff1a;作为函数参数 三.nullptr与NULL的区别 1.类型安全 2.函数重载问题 3.注意事项 一.简介 1.基本概念 nullptr 是一个类型安全的空指针常量&#xff0c;它的类型是 std::nul…...

实战案例分享:WLAN TKIP/CCMP加密组件的选择

无线接入点&#xff08;AP&#xff09;与终端&#xff08;STA&#xff09;在连接过程中涉及多种加密算法&#xff0c;如CCMP、TKIP等&#xff0c;选择合适的加密组件对于保证网络安全和兼容性至关重要。本篇我们将分析Wi-Fi加密机制、Wi-Fi加密组件的选型要点、典型问题及解决方…...

Day(19)--IO流(三)

文件加密 ps:^异或: 两边相同就是false 两边不同就是true 如果比较的是数字,那就会把它转换成为二进制,从右自左依次比较 总结:如果一个数字被异或两次,结果还是原来的数字 缓冲流 字节缓冲流 BufferedInputStream------字节缓冲输入流 BufferedOutputStream----字节…...

解锁STM32外设:开启嵌入式开发新世界

✨✨✨这里是小韩学长yyds的BLOG(喜欢作者的点个关注吧) ✨✨✨想要了解更多内容可以访问我的主页 小韩学长yyds-CSDN博客 目录 探索 STM32 强大的外设家族 初窥门径&#xff1a;STM32 外设开发基础 开发方式与工具 外设配置基础步骤 深入剖析&#xff1a;常见外设应用实例…...

SSLScan实战指南:全面检测SSL/TLS安全配置

SSLScan是一款开源的SSL/TLS安全扫描工具,用于检测服务器的加密协议、支持的加密套件、证书信息以及潜在的安全漏洞。本指南将详细介绍如何安装、使用SSLScan,并结合实战案例帮助您全面评估服务器的安全性。 一、SSLScan简介 功能特性: 检测支持的SSL/TLS协议版本(如TLS 1.…...

docker学习笔记(1)从安装docker到使用Portainer部署容器

docker学习笔记第一课 先交代背景 docker宿主机系统&#xff1a;阿里云ubuntu22.04 开发机系统&#xff1a;win11 docker镜像仓库&#xff1a;阿里云&#xff0c;此阿里云与宿主机系统没有关系&#xff0c;是阿里云提供的一个免费的docker仓库 代码托管平台&#xff1a;github&…...

基于Spring Boot的健美操评分管理系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

【Linux】——初识操作系统

文章目录 冯-诺依曼体系结构操作系统shell 冯-诺依曼体系结构 我们现在所使用的计算机就是冯-诺依曼体系结构。 存储器就是内存。 由下图可知&#xff0c;寄存器最快&#xff0c;为啥不用寄存器呢&#xff1f; 因为越快价格就最贵&#xff0c;冯诺依曼体系结构的诞生&#xf…...

PromQL计算gateway指标增量最佳实践及常见问题答疑

普米官方网站 普米官方帮助&#xff1a;Getting started | Prometheus 普米下载地址&#xff1a;Download | Prometheus 普米查询语法&#xff1a;Querying basics | Prometheus 普米函数参考&#xff1a;Query functions | Prometheus promql计算增量 在PromQL&#xff…...