音视频开发:音频编码原理+采集+编码实战

原理:

  1. 消除冗余信息,压缩量最大,也叫有损压缩
  • 剔除人耳听觉范围外的音频信号20Hz以下和20000Hz以上;
  • 去除被掩蔽的音频信号,信号的遮蔽可以分为频域遮蔽和时域遮蔽;
  • 频域遮蔽效应
    屏蔽70分贝以下,20HZ以下,20000HZ以上
    屏蔽分贝小,频率小的声音
    两个频率相近发出的声音,去除低强度的,也就是分贝高的会盖住分贝低的

  • 时域遮蔽效应:
    根根时间推移,相近频率且同时出现的声音,声音强度高的遮蔽强度低的声音,并且去除同一时间段前后杂音,前遮蔽50毫秒,后遮蔽200毫秒,在这段时间内的声音,强度越接近就越会被屏蔽。

  1. 去除冗余信息后,再进行无损压缩;
  • 无损压缩就是压缩后的数据能够解压缩进行还原,有损则不能;
  • 熵编码中有
    哈夫曼编码:用一个很小的二进制数代替一个长的字符串,频率越高,编码越小,频率越低,编码越长
    算术编码:利用小数进行编码,在香农编码的基础改进而来的
    香农编码

音频编码过程

数据先同时通过 时域转频域变换器和心理学模型处理数据,前者将数据转换成多种频段的数据,然后剔除不需要的频段数据,后者会去除非人耳听到的范围声音和一些复合声音,最后将两者合并经过量化编码,无损编码之类的,形成比特流数据,在此之前还会有一些辅助数据,此后数据就会变得非常小;

常见的音频编码器

opus、aac、Ogg、Speex、iLBC、AMR、G.711, 最常用的编码器是opus aac。
opus常用于直播,尤其是无延迟的直播,webrtc默认使用opus;
AAC是应用最广泛的编解码;
Ogg收费;
Speex支持回音消除;
G.711一般用于固定电话,声音损耗严重,通话会失真;

本文福利, 免费领取C++音视频学习资料包+学习路线大纲、技术视频/代码,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs),有需要的可以进企鹅裙927239107领取哦~

 

AAC比较适合有一定延迟的直播,AAC-LD属于低延迟编码器

  • AAC编码器:目前应用最广泛,如iOS、安卓和其他嵌入式设备都包含了AAC硬件编解码器,主要学习这个编码器;
    用来取代mp3,比mp3更高的压缩比和保真性更强;



常用的规格有AAC LC、AAC HE V1 、AAC HE V2三种;

AAC HE V1 = AAC + SBR;
AAV HE V2 = AAC + SBR + PS;
目前AAC HE V1 已经被取代 V2 取代了;

V2的码流跟V1的差别不是很大,根据声音的数据变化,如果两个声道的差别很大,码流差别就会越小;

AAC 中header有两种格式:

就相当于在aac数据前面加了个Header,header里面就会包含aac数据的一些信息,方便进行编解码

  1. ADIF(Audio data interchange format): 特点是只能从头开始解码,可以确定的找到音频数据的开始部分,不能从音频数据中间开始,这种格式常用于磁盘文件中;
  2. ADTS(Audio Data Transport Format):在每一帧的数据里面都会有一个同步字,也就是每帧都有一个header,所以他可以在任意的位置开始进行解码,就像流式数据;
  • ADTS结构: 由7-9个字节组成,通常情况下是7个字节,如果有CRC 就是9个字节,字节中的每一位都有独特的含义;
    • 1~12bit:全部是1也就是0xFFF,表示是同步字;
    • 13:编码规范 0 = MPEG-4 1 = MPEG-2;
    • 14~15:总是0;
    • 16:是否有保护 1 代表 没有 CRC 0 代表有CRC;
    • 17~18:表示的是MPEG-4的音频类型:AAC LC、 AAC HE V1 、AAC HE V2
    • 19~22:表示的是采样率
    • 24~26:通道数
    • 31~33:数据长度,也包括了header的长度
  • 剩余的之后补上



其中每一十进制数对应的含义:

Audio Object Type: 在代码中实际获取类型的时候需要进行+1,才是下面的类型
1 == AAC main
2 == AAC LC
5 == SBR == HE V1
29 == ps == HE V2

其中的采样率是通过十进制数表示的一个采样率,有一个表,比如:0 == 96000Hz 1 == 88200HZ 等

音频采集实战

每个端音频采集的底层和应用层的库是不一样的,所以使用ffmpeg中间层能够实现跨平台开发;

  • Android端的底层库是AudioRecorder,应用层是MediaRecorder;
  • iOS端的底层库是AudioUnit,应用层是AVFoundation;
  • Windows端的常用的是Directshow OpenAL 还有Windows7之上的AudioCore;

使用ffmpeg有两种采集方式:

  1. 使用命令方式,命令详情查看ffmpeg相关指令的那篇
  2. 使用代码调用api的方式
  • 在mac下的动态库需要对动态库进行签名

获取本地签名证书列表:/usr/bin/security find-identity -v -p codesigning
查看动态库是否签名: codesign -d -vv 动态库文件
签名命令:codesign -fs "iPhone Distribution: 你的签名证书." 动态库文件
xcode环境:13.2.1
签名了如果还是报错,关掉沙盒并且设置 Enable Hardened Runtime 为NO
在项目中设置user header search path的时候,要使用全路径方式,我使用$(PROJECT_NAME)方式,有的头文件在链接的时候会报错;

采集音频的步骤:

  1. 打开输入输出设备,涉及的包是avdevice avformat 注册设备 设置采集方式,根据平台选择,即设置输入 打开音频设备
  2. 获取数据包 包:avcodec 主要使用av_read_frame方法获取数据 将数据放入packet中 在读取的时候注意缓冲区无未准备好的情况
  3. 将数据输出到文件 创建文件--- fopen 将数据写入文件-- fwrite 关闭文件 -- fclose
  • 打开设备 ·
void startRecorder(void) {// 上下文AVFormatContext *av_context = NULL;AVDictionary *options = NULL;// 1. 注册设备avdevice_register_all();// 2. 设置采集方式//设置采集方式 mac os 下是AVfoundation Windows下是dshow  linux 下是alsaAVInputFormat *format = av_find_input_format("avfoundation");// 3. 打开设备//里面的识别格式为[[video device]:[audio device]]  这里写0 是获取第1个音频设备char *name = ":0";// url 是路径 可以是网络路径也可以是本地路径 本地路径mac下的格式是 video : audio 这里表示获取第一个音频设备int result = avformat_open_input(&av_context, name, format, &options);if (result != 0) {char errors[1024];// 根据返回值生成错误信息av_make_error_string(errors, 1024, result);printf("打开设备失败:%s\n", errors);return;}printf("打开设备成功!\n");get_audio_packet(av_context,&packet_callback);// 关闭输入 上下文avformat_close_input(&av_context);}
  • 读取数据和存储到文件
void get_audio_packet(AVFormatContext *context, void (*packet_callback)(AVPacket)) {// w == 写  b == 二进制  + == 没有就创建文件FILE *f = fopen("/Users/cunw/Desktop/learning/音视频学习/音视频文件/code_recorder.pcm", "wb+");AVPacket *packet = av_packet_alloc();int result = -1;// 循环读取设备信息// result == -35 是Resource temporarily unavailable 因为获取太频繁 设备未准备好,还正在处理数据  // 因为输入设备准备好需要时间  睡一秒后再读取  sleep(1.0);while ((result = av_read_frame(·context, packet)) == 0  || result == -35) {if (packet->size > 0) {packet_callback(*packet);fwrite(packet->data, packet->size, 1, f);// 每读取一次 就清空数据包 不然数据包会一直增大av_packet_unref(packet);}}if (result != 0) {char errors[1024];av_make_error_string(errors, 1024, result);printf("get packet occured error is \"%s\" \n", errors);}// 将缓冲区剩余的数据 强制写入文件fflush(f);fclose(f);// 释放packet空间av_packet_free(&packet);}
// 回调函数
void packet_callback(AVPacket packet) {printf("packet size is %d\n",packet.size);}
  • 播放
  • ffplay 播放pcm数据: ffplay -ar(采样率) 44100 -ac(通道数) 2 -f(采样大小)f32le 文件名

音频编解码实战

音频重采样

就是将音频三元组(采样率 采样大小 通道数)的值转成另外一组值

1. 应用场景:

1、从设备采集的音频数据与编码器要求的不一致;
2、扬声器要求的音频数据与要播放的音频数据不一致;
3、方便运算:例如回音消除 将多声道变为单声道;

2. 如何判断是否需要重采样

  • 了解音频设备的参数
  • 查看ffmpeg源码

3. 重采样的步骤

api:需要使用libswresample库

1. 创建重采样上下文

 - swr_alloc_set_opts 通过设置采样参数获取上下文      

2. 设置参数

- 参数大体分为输出的采样率、采样大小、声道和输入的采样率、采样大小、声道;
- out_ch_layout:表示声道也可以是布局(扬声器的布局)AV_CH_LAYOUT_STEREO  立体声;
- out_sample_fmt:输出的采样格式 16 = AV_SAMPLE_FMT_S16 或者 32 =  AV_SAMPLE_FMT_FLT;
-  av_sample_fmt_s16 in_ch_layout:输入的声道布局  ;
-  in_sample_fmt 输入的采样格式 ;
-  in_sample_rate:  输入的采样率;
-  后两位是log相关 0,null

3. 初始化重采样

- swr_init 初始化上下文  

4. 进行重采样

- swr_convert 开始转换 ,目的就是将输入缓冲区的数据写入输出缓冲区out:输出结果缓冲区 out_count:每个通道的采样数 in:输入的缓冲区 in_count:输入的单个通道的采样数  
- 因为重采样的数据需要重新构造所以需要创建输入缓冲区和输出缓冲区  使用av_sample_array_and_samples audio_data创建其中的单通道采样数(单位是字节)`nb_samples = pkt.size / (32位 / 8) / 2(通道数)` linessize:缓冲区大小  align:对齐 0 
- 在转换前需要将pkt的data按字节拷贝到输入缓冲区,调用memcpy需要引用string.h- 将输出数据写入文件将输出缓冲区已经转换的数据写入文件

5. 释放资源

- 还有输入输出缓冲区的释放av_freep
- swr_free释放上下文

重采样上下文初始化代码

SwrContext * init_swr_context(void) {SwrContext *context = NULL;// 假设已经提前知道输入音频数据的三要素的值 AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_FLT, 44100context = swr_alloc_set_opts(NULL,AV_CH_LAYOUT_STEREO,AV_SAMPLE_FMT_S16,44100,AV_CH_LAYOUT_STEREO,AV_SAMPLE_FMT_FLT,44100,0, NULL);int result = swr_init(context);if (result != 0) {char error[1024];av_make_error_string(error, 1024, result);printf("初始化重采样上下文失败:%s", error);}return context;
}

将采集的数据重采样后 写入文件代码

void get_audio_packet(AVFormatContext *context, void (*packet_callback)(AVPacket)) {// w == 写  b == 二进制  + == 没有就创建文件FILE *f = fopen("/Users/cunw/Desktop/learning/音视频学习/音视频文件/resample.pcm", "wb+");// 初始化重采样上下文SwrContext *swr_context = init_swr_context();// 初始化转换的输入输出缓冲区uint8_t **out_buffer = NULL;int linesize_out = 0;av_samples_alloc_array_and_samples(&out_buffer, &linesize_out, 2, 512, AV_SAMPLE_FMT_S16, 0);uint8_t **in_buffer = NULL;int linesize_in = 0;// nb_samples 单通道采样数 4096 / (32 / 8) / 2 = 1024av_samples_alloc_array_and_samples(&in_buffer, &linesize_in, 2, 512, AV_SAMPLE_FMT_FLT, 0);AVPacket *packet = av_packet_alloc();int result = -1;// 循环读取设备信息// result == -35 是Resource temporarily unavailable 因为获取太频繁 设备未准备好,还正在处理数据sleep(1);while (((result = av_read_frame(context, packet)) == 0  || result == -35) && isRecording == 1) {if (packet->size > 0) {// 开始转换数据// 先将音频数据拷贝到输入缓冲区  只是重采样音频的话  只需要处理数组的第一个memcpy(in_buffer[0], packet->data, packet->size);// 再进行转换swr_convert(swr_context, out_buffer, 512, (const uint8_t **)in_buffer, 512);fwrite(out_buffer[0],linesize_out, 1, f);// 每读取一次 就清空数据包 不然数据包会一直增大av_packet_unref(packet);}}if (result != 0) {char errors[1024];av_make_error_string(errors, 1024, result);printf("get packet occured error is \"%s\" \n", errors);}// 释放重采样资源if (in_buffer) {av_freep(&in_buffer[0]);}if (out_buffer) {av_freep(&out_buffer[0]);}av_freep(&in_buffer);av_freep(&out_buffer);swr_free(&swr_context);// 将缓冲区剩余的数据 强制写入文件fflush(f);fclose(f);// 释放packet空间av_packet_free(&packet);}

ffmpeg 音频数据编码

本文福利, 免费领取C++音视频学习资料包+学习路线大纲、技术视频/代码,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,编解码,推拉流,srs),有需要的可以进企鹅裙927239107领取哦~

在使用fdk_aac编码器的时候,由于默认的ffmpeg有自带的aac,所以通过avcodec_find_encoder_by_name("libfdk_aac")就获取不到。在编译的时候加上--enable-libfdk-aac。注意:重新编译安装ffmpeg之前最好先删掉之前的ffmpeg,然后更新项目中的动态库;
如果还不行,试试单独下载安装[fdk_aac](https://www.linuxfromscratch.org/blfs/view/svn/multimedia/fdk-aac.html),再重新编译ffmpeg

  1. 创建编码器 avcodec
    1. avcodec_find_encoder 一种通过名字查找 一种是通过id查找,id的查找方式只会找默认的编码器,比如aac,如果是fdkaac就需要通过名字查找;
  2. AV_CODEC_ID_AAC | opus 其他编码器
  3. "libfdk_aac", aac默认的规格是AAC LC
  4. 创建上下文 avcodexcontext
    设置音频三要素
  5. avcodec_alloc_context3
    3表示第三个版本
  6. sample_fmt = av_sample_FMT_S16 aac编码器不支持flt 32位
  7. chnnel_layout = AV_CH_LAYOUT_STEREO( 或者chanels = 2)
  8. sample_rate = 44100
  9. bit_rate = 64000; (KB 码率)可选设置
  10. profile = FF_PROFILE_AAC_HE_V2; (只有bit_rate=0 才有用) 可选设置,设置编码器规格
  1. 打开编码器
  2. avcodex_opne2
    2表示第二个版本
    送数据给编码器时,编码器内部有一个缓冲区,缓冲一部分数据后才进行编码
  1. 编码
  2. 用AVFrame包装未编码的数据,相当于是个输入,用AVPacket包装已编码的数据,相当于是个输出;
  3. 调用avcodec_send_frame 将avframe缓冲区的数据发送给编码器,如果返回值大于0,就表示数据成功发送到了编码器,接着就可以通过循环使用 avcodec_receive_packet读取编码好的数据到AVPacket,并写入文件中,如果读取的结果是AVERROR(EAGIN)或者是AVERROR_EOF,就停止读取,如果是其他的负数,就停止编码;
  4. av_frame_alloc 堆区初始化frame
  5. 设置frame的nb_samples 单通道一个数据帧采样数 512
  1. format 每个采样的大小 av_sample_fmt_s16
  2. channel_layout 声道 av_ch_layout_stereo
  3. av_frame_get_buffer 分配frame里面buffer的大小
  4. 还要判断frame的buffer是否分配成功
  5. 将重采样后的数据memcpy到frame->data中
  6. 再将frame中的数据塞到编码器上下文中 avcodec_send_frame,该函数会返回一个int , 当结果>=0的时候表明有数据已经在编码缓冲区了;
  7. avcodec_receive_packet 读取编码好的数据 avpacket
  8. av_packet_alloc 分配编码后的数据空间
  9. 因为编码器上下文中有一个缓冲区,其中会缓存多个frame,因此并不是每塞一个frame就会有一个packet出来,所以需要通过一个while循环判断编码器的数据是否>=0,再通过avcodec_receive_packet获取packet,该函数也会返回一个int,如果返回值>=0表明获取成功,如果失败直接退出编码,这个值返回值还有其他含义,需要判断eagain 表明编码器没有数据了或者是有数据但是不够编码 这个eagain需要用AVERROR包装成一个负数,表明数据还没准备好 averror_eof 表明一点数据都没有了;
  10. 最后将数据编码后的数据写入到文件pkt->data,数据格式就是aac了;
  11. 在停止录制的时候,由于编码的缓存区可能还有数据,在最后关闭之前,再去取一遍编码数据放入文件;
  1. 释放资源

在结束的时候释放frame(av_frame_free) 和packet(av_packet_frame);

编码实战代码:

1. 创建fdk_aac编码器及上下文

AVCodecContext* init_codec_context(void) {// 创建aac编码器AVCodec *codec = avcodec_find_encoder_by_name("libfdk_aac");// 初始化上下文AVCodecContext *context = NULL;context = avcodec_alloc_context3(codec);context->sample_fmt = AV_SAMPLE_FMT_S16;context->sample_rate = 44100;context->channel_layout = AV_CH_LAYOUT_STEREO;context->bit_rate = 0;// bitrate == 0 才会生效context->profile = FF_PROFILE_AAC_HE_V2;int result = avcodec_open2(context, codec, NULL);if (result < 0) {char error[1024];av_make_error_string(error, 1024, result);av_log(NULL, AV_LOG_DEBUG, "创建AAC编码器失败:%s",error);}return context;}

2. 创建输入缓冲区

AVFrame* create_audio_input_frame(void) {AVFrame *codec_frame = NULL;codec_frame = av_frame_alloc();codec_frame->nb_samples = 512;codec_frame->channel_layout = AV_CH_LAYOUT_STEREO;codec_frame->format = AV_SAMPLE_FMT_S16;int buffer_result = av_frame_get_buffer(codec_frame, 0);if (buffer_result < 0) {char error[1024];av_make_error_string(error, 1024, buffer_result);printf("frame 缓冲区分配失败:%s", error);}return codec_frame;
}

3. 开始编码并写入文件

void audio_encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *packet, FILE *fl) {// 将数据送入编码器int codec_result = avcodec_send_frame(ctx, frame);while (codec_result >= 0) {// 从packet中循环读取编码好的数据codec_result = avcodec_receive_packet(ctx, packet);if (codec_result == AVERROR(EAGAIN) || codec_result == AVERROR_EOF) {break;} else if (codec_result < 0) {char error[1024];av_make_error_string(error, 1024, codec_result);printf("编码器出错:%s     停止编码", error);} else {fwrite(packet->data, 1,packet->size, fl);}}if (codec_result < 0) {char error[1024];av_make_error_string(error, 1024, codec_result);printf("将数据送入编码器错误: %s\n",error);}
}

4. 调用

  • 先将重采样的数据放入avframe的缓冲区中
memcpy(codec_frame->data[0], out_buffer[0], linesize_out);
  • 再开始编码
audio_encode(codec_context, codec_frame, codec_packet, f);
  • 总览
void get_audio_packet(AVFormatContext *context, void (*packet_callback)(AVPacket)) {// w == 写  b == 二进制  + == 没有就创建文件FILE *f = fopen("/Users/cunw/Desktop/learning/音视频学习/音视频文件/encoder.aac", "wb+");// 创建编码器上下文AVCodecContext *codec_context = init_codec_context();// 初始化输入缓冲区  AVframeAVFrame *codec_frame = create_audio_input_frame();// 初始化编码输出缓冲区AVPacket *codec_packet = av_packet_alloc();// 初始化重采样上下文SwrContext *swr_context = init_swr_context();// 初始化重采样的缓冲区uint8_t **out_buffer = NULL;int linesize_out = 0;uint8_t **in_buffer = NULL;int linesize_in = 0;init_resammple_buffer(&in_buffer, &linesize_in, &out_buffer, &linesize_out);AVPacket *packet = av_packet_alloc();int result = -1;// 循环读取设备信息while (isRecording == 1) {result = av_read_frame(context, packet);if (packet->size > 0 && result == 0) {packet_callback(*packet);// 开始转换数据// 先将音频数据拷贝到输入缓冲区  只是重采样音频的话  只需要处理数组的第一个memcpy(in_buffer[0], packet->data, packet->size);// 再进行转换swr_convert(swr_context, out_buffer, 512, (const uint8_t **)in_buffer, 512);// 将重采样好的数据按字节拷贝到frame缓冲区memcpy(codec_frame->data[0], out_buffer[0], linesize_out);audio_encode(codec_context, codec_frame, codec_packet, f);// 每读取一次 就清空数据包 不然数据包会一直增大av_packet_unref(packet);} else if (result == -EAGAIN) {// result == -35 是Resource temporarily unavailable 因为设备未准备好,还正在处理数据av_usleep(1);}}// 把缓冲区剩余的数据拿出来编码audio_encode(codec_context, NULL, codec_packet, f);if (result != 0) {char errors[1024];av_make_error_string(errors, 1024, result);printf("get packet occured error is \"%s\" \n", errors);}// 释放重采样资源if (in_buffer) {av_freep(&in_buffer[0]);}if (out_buffer) {av_freep(&out_buffer[0]);}av_freep(&in_buffer);av_freep(&out_buffer);swr_free(&swr_context);av_frame_free(&codec_frame);av_packet_free(&codec_packet);// 将缓冲区剩余的数据 强制写入文件fflush(f);fclose(f);// 释放packet空间av_packet_free(&packet);}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt 使用Quazip解压缩、压缩文件

1.环境搭建 Quazip&#xff0c;是在zlib基础上进行了简单封装的开源库&#xff0c;适用于多种平台&#xff0c;利用它可以很方便将单个或多个文件打包为zip文件&#xff0c;且打包后的zip文件可以通过其它工具打开。 下载Quazip QuaZIP download | SourceForge.net 解压后&…

利用ChatGPT进行股票走势分析

文章目录 1. 股票分析2. 技巧分析3. 分析技巧21. 股票分析 这张图片显示了一个股票交易软件的界面。以下是根据图片内容的一些解读: 股票代码: 图片右上角显示的代码是“600517”,这是股票的代码。 图形解读: 该图展示了股票的日K线图。其中,蜡烛图表示每日的开盘、收盘、最…

力扣第62题 不同路径 c++ 动态规划 dp二维 + dp一维 解法

题目 62. 不同路径 中等 相关标签 数学 动态规划 组合数学 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Fini…

电商课堂|5分钟了解电商数据分析完整流程,建议收藏!

账户效果下降&#xff0c;如何能够快速找到问题并优化调整&#xff1f; 相信百分之90%的竞价员都会说&#xff1a;“做数据分析。” 没错&#xff0c;数据分析能够帮助我们快速锁定问题所在&#xff0c;确定优化方向&#xff0c;还可以帮助我们找到流量控制的方向。那么做电商&…

译文:我们如何使 Elasticsearch 7.11 中的 date_histogram 聚合比以往更快

这篇文章是ES7.11版本的文章&#xff0c;主要学习的是思路&#xff0c;记录在这里留作以后参考用。 原文地址&#xff1a;https://www.elastic.co/cn/blog/how-we-made-date-histogram-aggregations-faster-than-ever-in-elasticsearch-7-11 正文开始&#xff1a; Elasticsea…

【C++的OpenCV】第十五课-OpenCV的绘图工具(rectangle、circle、line、polylines、putText)常用方法简介

&#x1f389;&#x1f389;&#x1f389; 欢迎各位来到小白 p i a o 的学习空间&#xff01; \color{red}{欢迎各位来到小白piao的学习空间&#xff01;} 欢迎各位来到小白piao的学习空间&#xff01;&#x1f389;&#x1f389;&#x1f389; &#x1f496; C\Python所有的入…

大数据预处理与采集实验三:Urllib的GET和POST请求(1)

目录 Urllib基本操作-GET ➢没有进行utf-8编码的输出 ➢经过utf-8decode之后的输出 ➢ Timeout参数&#xff1a;捕获由于连接超时而引发的异常 ◆Urllib基本操作-定制请求头 ➢ 在GET请求中加入多个访问参数 ◆Urllib基本操作-POST ➢有道词典网页爬取&#xff1a;找到…

Linux基本网页访问--防火墙、服务管理、selinux强制访问

正常访问外部网络需要进行4部操作操作&#xff1a; 1、开启httpd服务systemctl restart httpd 2、关闭防火墙服务 systemctl stop firewalld 3、访问数据库时&#xff0c;需要开启数据库的服务systemctl restart mariadb 4、关闭强制访问 setenforce 0 1、防火墙管理 firewal…

有了定时关机,省时省力!如何在Windows 11中设置自动关机

你有时会忘记关闭Windows 11吗?如果是这样的话,也许你应该考虑安排关机时间,以确保你的电脑在忘记选择关机时也能关机。 当你需要等待大型游戏下载完成时,安排关闭也是一个好主意。你可以用一个相对简单的命令在Windows 11中设置自动关机。 计时器将在指定的倒计时时间过…

表白墙(服务器)

目录 0.需求 1.创建Maven项目 2.给pom.xml内引入三个依赖 3.完善目录&#xff0c;并补充web.xml中的内容 4.编写代码 后端代码 ​编辑前端代码 5.引入数据库 创建message表 创建工具类 往MessageServlet类中添加方法 0.需求 前面写好了表白墙页面&#xff0c;但存…

C# Onnx Ultra-Fast-Lane-Detection-v2 车道线检测

效果 项目 代码 using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using System.Text; usi…

你真的会学习网络安全吗?

我敢说&#xff0c;现在网上90%的文章都没有把网络安全该学的东西讲清楚。 为什么&#xff1f;因为全网更多的都是在讲如何去渗透和公鸡&#xff0c;却没有把网安最注重的防御讲明白。 老话说得好&#xff1a;“攻击&#xff0c;是为了更好的防御。”如果连初衷都忘了&#xff…

数据结构和算法——用C语言实现所有图状结构及相关算法

文章目录 前言图的基本概念图的存储方式邻接矩阵邻接表十字链表临界多重表 图的遍历最小生成树普里姆算法&#xff08;Prim&#xff09;克鲁斯卡尔算法&#xff08;Kruskal&#xff09; 最短路径BFS求最短路径迪杰斯特拉算法&#xff08;Dijkstra&#xff09;弗洛伊德算法&…

Android Studio打包AAR

注意 依赖的Android Studio版本为4.2.2 更高的Android Studio版本使用方法可能有所不同&#xff0c;gradle的版本和gradle plugins的版本都会影响使用方式。 基于此&#xff0c;本文只能作为参考&#xff0c;而不能作为唯一答案&#xff0c;如果要完全依赖本文&#xff0c;则…

8年经验之谈 —— Redis的性能测试与优化!

Redis作为一种高性能的Key-Value数据库&#xff0c;一直受到众多开发者和企业的青睐。然而&#xff0c;在高并发、大数据存储的应用场景中&#xff0c;如何测试并优化Redis的性能&#xff0c;成为了问题。本文将从测试与优化两个方面来讲解如何达到最优的Redis性能。 一、性能…

深入浅出排序算法之计数排序

目录 1. 原理 2. 代码实现 3. 性能分析 1. 原理 首先看一个题目&#xff0c;有n个数&#xff0c;取值范围是 0~n&#xff0c;写出一个排序算法&#xff0c;要求时间复杂度和空间复杂度都是O(n)的。 为了达到这种效果&#xff0c;这一篇将会介绍一种不基于比较的排序方法。这…

K-means(K-均值)算法

K-means&#xff08;k-均值&#xff0c;也记为kmeans&#xff09;是聚类算法中的一种&#xff0c;由于其原理简单&#xff0c;可解释强&#xff0c;实现方便&#xff0c;收敛速度快&#xff0c;在数据挖掘、聚类分析、数据聚类、模式识别、金融风控、数据科学、智能营销和数据运…

我和云栖有个约会

云栖大会&#xff1a;聚焦创新&#xff0c;驱动未来 2009年&#xff0c;一场地方网站峰会在中国掀起了技术的浪潮。随着时间的推移&#xff0c;这场峰会逐渐演变成了全球领先的科技盛会——云栖大会。回首历史&#xff0c;云栖大会不仅是中国云计算产业发展的见证者&#xff0c…

高效分割分段视频:提升您的视频剪辑能力

在数字媒体时代&#xff0c;视频剪辑已经成为一项重要的技能。无论是制作个人影片、广告还是其他类型的视频内容&#xff0c;掌握高效的视频剪辑技巧都是必不可少的。本文将介绍如何引用云炫AI智剪高效地分割和分段视频&#xff0c;以提升您的视频剪辑能力。以下是详细的操作步…

2023-11-01 LeetCode每日一题(参加会议的最多员工数)

2023-11-01每日一题 一、题目编号 2127. 参加会议的最多员工数二、题目链接 点击跳转到题目位置 三、题目描述 一个公司准备组织一场会议&#xff0c;邀请名单上有 n 位员工。公司准备了一张 圆形 的桌子&#xff0c;可以坐下 任意数目 的员工。 员工编号为 0 到 n - 1 。…