基于ffmpeg的音视频编码

1 音频编码

本质上是由pcm文件转到一个协议文件 比如说aac协议

1.1 音频基本知识回归

  • 比特率
    比特率是指单位时间内传输或处理的比特(bit)数量,通常用 bps(bits per second,比特每秒)来表示。它是衡量数据传输速度和通信系统能力的重要指标。
  • 码率
    一般为编码之后,单位时间内传输的字节数
  • 声道布局

声道布局是指在音频系统中,各个声道的扬声器在空间中的分布方式以及它们所承担的音频信息分配方式。以下是一些常见的声道布局简介:
单声道:只有一个声道,所有音频信息都通过一个扬声器播放,声音缺乏空间感和立体感,常用于一些简单的音频设备或对音频要求不高的场景。
立体声:有左声道和右声道两个声道,通过两个扬声器分别播放不同的音频信号,模拟人耳听到声音的立体感,能让听众感受到声音的左右位置差异,营造出一定的空间感,是音乐播放、电影音频等常见的声道布局。
5.1 声道:由左前、中置、右前、左环绕、右环绕五个扬声器以及一个重低音扬声器(.1 表示)组成。左前、中置和右前扬声器主要负责前方的声音,包括人物对话、主要乐器声等;左环绕和右环绕扬声器用于营造环境音效和后方声音,增强沉浸感;重低音扬声器专门负责低频音效,如爆炸声、雷声等,能提升声音的震撼力,常用于家庭影院系统。
7.1 声道:在 5.1 声道的基础上,增加了左后环绕和右后环绕两个声道,进一步增强了后方的声音细节和空间感,使听众能更清晰地感受到来自后方各个方向的声音,提供更逼真的环绕音效,常用于高端影院和一些专业音频制作环境。

  • 采样率
    采样率是指在单位时间内对模拟信号进行采样的次数,通常用赫兹(Hz)来表示
  • 采样格式
    即一个样本点多少位存放

packed格式:交错
1 AV_SAMPLE_FMT_U8, ///< unsigned 8 bits
2 AV_SAMPLE_FMT_S16, ///< signed 16 bits
3 AV_SAMPLE_FMT_S32, ///< signed 32 bits
4 AV_SAMPLE_FMT_FLT, ///< float
5 AV_SAMPLE_FMT_DBL, ///< double

planar格式 左右分别存放
1 AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar
2 AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar
3 AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar
4 AV_SAMPLE_FMT_FLTP, ///< float, planar
5 AV_SAMPLE_FMT_DBLP, ///< double, planar
6 AV_SAMPLE_FMT_S64, ///< signed 64 bits
7 AV_SAMPLE_FMT_S64P, ///< signed 64 bits, planar

  • 一帧大小
    计算出每一帧的数据 单个采样点的字节 * 通道数目 * 每帧采样点数量
  • aac协议
    aac协议由一个adts头和一个音频数据包组成 一般希望planar格式
  • 编码器选择
    ffmpeg默认的aac编码器,默认编译出来的每帧数据都不带adts,但lib_fdk aac默认是带了adts header,而且此时codec_ctx->flags的值都为0.
    这样我们没法判断是否需要自己额外写入adts,因此我们在设置编码的时候可以直接将codec_ctx->flags = AV_CODEC_FLAG_GLOBAL_HEADER; 大家都不带adts

2.2 编码流程

在这里插入图片描述


const AVCodec *codec = NULL;//编码器
AVCodecContext *codec_ctx= NULL;//编码器设置codec = avcodec_find_encoder(codec_id)
codec_ctx = avcodec_alloc_context3(codec)codec_ctx->codec_id = codec_id;//idcodec_ctx->codec_type = AVMEDIA_TYPE_AUDIO;//typecodec_ctx->bit_rate = 128*1024;//码率codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;//立体声音codec_ctx->sample_rate    = 48000; //48000 采样率codec_ctx->channels       = av_get_channel_layout_nb_channels(codec_ctx->channel_layout);codec_ctx->profile = FF_PROFILE_AAC_LOW;    //低水平if(strcmp(codec->name, "aac") == 0) {codec_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;} else if(strcmp(codec->name, "libfdk_aac") == 0) {codec_ctx->sample_fmt = AV_SAMPLE_FMT_S16;} else {codec_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;}//采样格式/* 检测支持采样格式支持情况 */if (!check_sample_fmt(codec, codec_ctx->sample_fmt)) {fprintf(stderr, "Encoder does not support sample format %s",av_get_sample_fmt_name(codec_ctx->sample_fmt));exit(1);}if (!check_sample_rate(codec, codec_ctx->sample_rate)) {fprintf(stderr, "Encoder does not support sample rate %d", codec_ctx->sample_rate);exit(1);}if (!check_channel_layout(codec, codec_ctx->channel_layout)) {fprintf(stderr, "Encoder does not support channel layout %lu", codec_ctx->channel_layout);exit(1);}codec_ctx->flags = AV_CODEC_FLAG_GLOBAL_HEADER;
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {fprintf(stderr, "Could not open codec\n");exit(1);}

这一部分 无疑完成编码器的初始化
先找编码器->再初始化上下文->再连接再一起

note:不同的编码器对采样格式有性能限制,aac编码器倾向于planar格式编码,libfdk_aac倾向于packed格式编码


AVFrame *frame = NULL;//为原始数据
AVPacket *pkt = NULL;//编码数据
pkt = av_packet_alloc();
frame = av_frame_alloc();frame->nb_samples     = codec_ctx->frame_size;//一帧多少采样点frame->format         = codec_ctx->sample_fmt;//音频深度frame->channel_layout = codec_ctx->channel_layout;frame->channels = av_get_channel_layout_nb_channels(frame->channel_layout);ret = av_frame_get_buffer(frame, 0);int frame_bytes = av_get_bytes_per_sample(frame->format) * frame->channels * frame->nb_samples;uint8_t *pcm_buf = (uint8_t *)malloc(frame_bytes);
size_t read_bytes = fread(pcm_buf, 1, frame_bytes, infile);ret = av_frame_make_writable(frame);ret = av_samples_fill_arrays(frame->data, frame->linesize,pcm_buf, frame->channels,frame->nb_samples, frame->format, 0);

分配帧和数据包->初始化帧(给帧分配大小)->填充帧

ret = av_frame_get_buffer(frame, 0);0为让ffmpeg选择 是否对齐
av_samples_fill_arrays

uint8_t **audio_data
作用:这是一个指向指针数组的指针,用于存储每个声道的音频数据指针。AVFrame 中的 data 成员通常就是这样一个指针数组,用于存储不同声道的数据。例如,对于立体声(2 个声道),audio_data[0] 指向左声道数据,audio_data[1] 指向右声道数据。
示例:在 AVFrame 中使用时,通常传入 frame->data。
2. int *linesize
作用:这是一个指向整数数组的指针,用于存储每个声道数据的每行字节数(在音频数据中,“行” 可以理解为一个样本块)。这个值对于音频数据的正确处理非常重要,因为它表示了每个声道数据在内存中的布局信息。AVFrame 中的 linesize 成员就是用于存储这些信息的。
示例:在 AVFrame 中使用时,通常传入 frame->linesize。
3. const uint8_t *buf
作用:这是一个指向包含原始音频样本数据的缓冲区的指针。该缓冲区包含了要填充到 AVFrame 中的音频数据。
示例:在你的代码中,pcm_temp_buf 就是存储原始 PCM 音频数据的缓冲区,所以这里传入 pcm_temp_buf。
4. int nb_channels
作用:表示音频数据的声道数。例如,单声道音频的 nb_channels 为 1,立体声音频的 nb_channels 为 2。
示例:在 AVFrame 中使用时,通常传入 frame->channels。
?5. int nb_samples
作用:表示每个声道的样本数量。样本是音频数据的基本单位,nb_samples 决定了音频数据的时长和大小。
示例:在 AVFrame 中使用时,通常传入 frame->nb_samples。
6. enum AVSampleFormat sample_fmt
作用:表示音频样本的格式,它指定了每个样本的位深度、存储方式等信息。常见的样本格式有 AV_SAMPLE_FMT_S16(16 位有符号整数)、AV_SAMPLE_FMT_FLTP(浮点型平面格式)等。
示例:在 AVFrame 中使用时,通常传入 frame->format。
7. int align
作用:指定内存对齐方式。内存对齐可以提高内存访问效率,通常传入 0 让 FFmpeg 自动选择合适的对齐方式。


static int encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *output)
{int ret;/* send the frame for encoding */ret = avcodec_send_frame(ctx, frame);if (ret < 0) {fprintf(stderr, "Error sending the frame to the encoder\n");return -1;}/* read all the available output packets (in general there may be any number of them */// 编码和解码都是一样的,都是send 1次,然后receive多次, 直到AVERROR(EAGAIN)或者AVERROR_EOFwhile (ret >= 0) {ret = avcodec_receive_packet(ctx, pkt);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {return 0;} else if (ret < 0) {fprintf(stderr, "Error encoding audio frame\n");return -1;}size_t len = 0;printf("ctx->flags:0x%x & AV_CODEC_FLAG_GLOBAL_HEADER:0x%x, name:%s\n",ctx->flags, ctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER, ctx->codec->name);if((ctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) {// 需要额外的adts header写入uint8_t aac_header[7];get_adts_header(ctx, aac_header, pkt->size);len = fwrite(aac_header, 1, 7, output);if(len != 7) {fprintf(stderr, "fwrite aac_header failed\n");return -1;}}len = fwrite(pkt->data, 1, pkt->size, output);if(len != pkt->size) {fprintf(stderr, "fwrite aac data failed\n");return -1;}
}return -1;
}

发送帧->接受帧->写入文件

引入一个函数


2 视频编码

本质上是将一个yuv 变成一个h264文件

2.1 h264编码细节推荐

1 什么是视频码率
视频码率是视频数据(包含视频⾊彩量、亮度量、像素量)每秒输出的位数。⼀般⽤的单位是kbps。
2 设置视频码率的必要性
在⽹络视频应⽤中,视频质量和⽹络带宽占⽤是相⽭盾的。通常情况下,视频流占⽤的带宽越⾼则视频
质量也越⾼,需要的⽹络带宽也越⼤,解决这⼀⽭盾的钥匙当然是视频编解码技术。评判⼀种视频编解码技术的优劣,是⽐较在相同的带宽条件下,哪个视频质量更好;在相同的视频质量条件下,哪个占⽤的⽹络带宽更少(⽂件体积⼩)。
是不是视频码率越⾼,质量越好呢?理论上是这样的。然⽽在我们⾁眼分辨的范围内,当码率⾼到⼀定程度时,就没有什么差别了。所以码率设置有它的最优值,H.264(也叫AVC或X264)的⽂件中,视频的建议码率如下
在这里插入图片描述
3 –preset的参数主要调节编码速度和质量的平衡,有ultrafast、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、placebo这10个选项,从快到慢。

4 –tune的参数主要配合视频类型和视觉优化的参数,或特别的情况。如果视频的内容符合其中一个可用的调整值又或者有其中需要,则可以使用此选项,否则建议不使用(如tune grain是为高比特率的编码而设计的)。tune的值有:
film: 电影、真人类型;
animation: 动画;
grain: 需要保留大量的grain时用;
stillimage: 静态图像编码时使用;
psnr: 为提高psnr做了优化的参数;
ssim: 为提高ssim做了优化的参数;
fastdecode: 可以快速解码的参数;
zerolatency:零延迟,用在需要非常低的延迟的情况下,比如电视电话会议的编码。
5 在 H.264 编码中,profile(配置文件)用于指定编码视频流的特性和功能集合,不同的profile适用于不同的应用场景和设备。常见的 H.264 profile值及其特点如下:

  • Baseline Profile(基线配置文件)
    支持 I 帧(关键帧)和 P 帧(预测帧),不支持 B 帧(双向预测帧)。
    主要用于低延迟、低复杂度的应用,如视频会议、实时监控等。
    能够在相对较低的码率下提供较好的视频质量,适用于带宽有限的情况。
  • Main Profile(主配置文件)
    支持 I 帧、P 帧和 B 帧,提供了更高效的压缩性能。
    适用于大多数传统的视频应用,如视频存储、视频广播等。
    在相同的视频质量下,Main Profile 通常比 Baseline Profile 需要更高的码率,但能实现更好的压缩效果。
  • High Profile(高配置文件)
    进一步提高了压缩效率,支持更多的编码工具和特性,如更多的量化矩阵、自适应环路滤波等。
    主要用于高清和蓝光视频等对视频质量要求较高的应用。
    能够在高分辨率和高帧率的情况下提供出色的视频质量,但编码和解码的复杂度也相对较高。

baseline profile多应⽤于实时通信领域;
main profile多应⽤于流媒体领域;
high profile则多应⽤于⼴电和存储领域

6 bframes: I帧和P帧或者两个P帧之间可⽤的最⼤连续B帧数量,默认值为3。B帧可使⽤双向预测,从⽽显著提⾼压缩率,但由于需要缓存更多的帧数以及重排序的原因,会降低编码速度,增加编码延迟,因此在实时编码时也建议将该值设置为0。
在这里插入图片描述


const AVCodec *codec = NULL;
AVCodecContext *codec_ctx= NULL;codec = avcodec_find_encoder_by_name(codec_name);if (!codec) {fprintf(stderr, "Codec '%s' not found\n", codec_name);exit(1);}codec_ctx = avcodec_alloc_context3(codec);if (!codec_ctx) {fprintf(stderr, "Could not allocate video codec context\n");exit(1);}
codec_ctx->width = 1280;
codec_ctx->height = 720;
codec_ctx->time_base = (AVRational){1, 25};
codec_ctx->framerate = (AVRational){25, 1};
codec_ctx->gop_size = 25;   // I帧间隔
codec_ctx->max_b_frames = 2; // 如果不想包含B帧则设置为0
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;* // ultrafast all encode time:2270ms// medium all encode time:5815ms// veryslow all encode time:19836ms*/ret = av_opt_set(codec_ctx->priv_data, "preset", "medium", 0);if(ret != 0) {printf("av_opt_set preset failed\n");}/*profile 参数:profile 表示 H.264 编码的配置文件,这里设置为 main。* 不同的 profile 支持不同的编码特性和功能,main 配置文件提供了基本的编码功能,适用于大多数视频应用场景。*/ret = av_opt_set(codec_ctx->priv_data, "profile", "main", 0); // 默认是highif(ret != 0) {printf("av_opt_set profile failed\n");}/*tune 参数:tune 表示针对特定应用场景进行优化,* 这里设置为 zerolatency,表示进行零延迟编码,适用于直播等对延迟要求较高的场景。*/ret = av_opt_set(codec_ctx->priv_data, "tune","zerolatency",0);codec_ctx->bit_rate = 3000000;ret = avcodec_open2(codec_ctx, codec, NULL);if (ret < 0) {fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));exit(1);}

同理 先找编码器->初始化上下文->再绑定


AVFrame *frame = NULL;
AVPacket *pkt = NULL;pkt = av_packet_alloc();if (!pkt) {fprintf(stderr, "Could not allocate video frame\n");exit(1);}frame = av_frame_alloc();if (!frame) {fprintf(stderr, "Could not allocate video frame\n");exit(1);}// 为frame分配bufferframe->format = codec_ctx->pix_fmt;frame->width  = codec_ctx->width;frame->height = codec_ctx->height;ret = av_frame_get_buffer(frame, 0);int frame_bytes = av_image_get_buffer_size(frame->format, frame->width,frame->height, 1);
int8_t *yuv_buf = (uint8_t *)malloc(frame_bytes);ret = av_frame_make_writable(frame);int need_size = av_image_fill_arrays(frame->data, frame->linesize, yuv_buf,frame->format,frame->width, frame->height, 1);

同理 设置帧参数


static int encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,FILE *outfile)
{int ret;/* send the frame to the encoder */if (frame)printf("Send frame %3"PRId64"\n", frame->pts);/* 通过查阅代码,使用x264进行编码时,具体缓存帧是在x264源码进行,* 不会增加avframe对应buffer的reference*/ret = avcodec_send_frame(enc_ctx, frame);if (ret < 0){fprintf(stderr, "Error sending a frame for encoding\n");return -1;}while (ret >= 0){ret = avcodec_receive_packet(enc_ctx, pkt);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {return 0;} else if (ret < 0) {fprintf(stderr, "Error encoding audio frame\n");return -1;}if(pkt->flags & AV_PKT_FLAG_KEY)//该数据包是否为关键帧printf("Write packet flags:%d pts:%3"PRId64" dts:%3"PRId64" (size:%5d)\n",pkt->flags, pkt->pts, pkt->dts, pkt->size);if(!pkt->flags)printf("Write packet flags:%d pts:%3"PRId64" dts:%3"PRId64" (size:%5d)\n",pkt->flags, pkt->pts, pkt->dts, pkt->size);fwrite(pkt->data, 1, pkt->size, outfile);}return 0

int avcodec_encode_video2(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr);
此函数把输入的 AVFrame 编码成一个或多个 AVPacket,使用单个函数调用完成编码过程。got_packet_ptr 用于指示是否生成了有效的数据包。
avcodec_encode_video2:是一个同步接口,在一次调用里完成帧的发送和编码后数据包的接收。若编码器有缓存帧,可能需要多次调用该函数才能处理完所有缓存帧。


3 共同点

1.为什么要冲刷编码器

  • 清空缓存:编码器通常会有内部缓存来存储尚未输出的编码数据。在编码结束时或某些特定情况下,如切换编码参数、结束编码流程等,需要冲刷编码器,以确保这些缓存中的数据被完整地输出,避免数据丢失。
  • 保证数据完整性:冲刷操作可以使编码器将所有已处理但未发送的编码数据包发送出来,从而保证编码后的数据在文件或流中的完整性,使得后续的解码和播放等操作能够顺利进行。
  • 避免延迟:如果不进行冲刷,缓存中的数据可能会一直滞留在编码器中,导致输出延迟。冲刷编码器能够及时将数据输出,降低整体的编码延迟,特别是在实时性要求较高的场景,如直播、视频会议等中,这一点尤为重要。
  • 资源释放与重置:冲刷编码器有时也与资源的释放和重置相关。在完成一次编码任务后,通过冲刷可以清理编码器内部的临时资源,为下一次编码任务做好准备,确保编码器处于正确的初始状态,避免残留数据或状态对新的编码过程产生干扰。

2 为什么不要取消计数引用
avcodec_receive_packet 函数内部第一个调用的就是 av_packet_unref,它会对 AVPacket 进行引用计数的递减操作,并在引用计数为 0 时释放相关的资源。如果在外部再次手动调用 av_packet_unref,就会导致对同一个 AVPacket 的引用计数错误地多减一次,可能会造成资源过早释放,后续如果再使用该 AVPacket 相关的指针或数据,就会引发错误,比如出现野指针访问、程序崩溃等问题。

3 如何放入队列
由于编码器会释放数据,不能直接将原始的 pkt 插入到队列中。正确的做法是新分配一个 AVPacket,然后使用 av_packet_move_ref 函数将原始 pkt 对应的缓冲区转移到新分配的 AVPacket 中,再将新的 AVPacket 放入队列。这样做可以保证队列中的 AVPacket 拥有独立的缓冲区,不会因为编码器释放原始 pkt 的数据而导致队列中的数据被破坏。在放入队列时,还需要确保队列的操作是线程安全的,以避免多线程环境下的竞争条件和数据不一致问题。

4 流程不同
即aac要加头文件,以及编码器设置参数不一样 ,以及由两个api av_image_fill_arrays和av_samples_fill_arrays 不同

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

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

相关文章

BT137-ASEMI机器人功率器件专用BT137

编辑&#xff1a;LL BT137-ASEMI机器人功率器件专用BT137 型号&#xff1a;BT137 品牌&#xff1a;ASEMI 封装&#xff1a;TO-220F 批号&#xff1a;最新 引脚数量&#xff1a;3 封装尺寸&#xff1a;如图 特性&#xff1a;双向可控硅 工作结温&#xff1a;-40℃~150℃…

攻防世界 dice_game

dice_game ​​​​​​dice_game (1) motalymotaly-VMware-Virtual-Platform:~/桌面$ file game game: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]254…

Astral Ascent 星界战士(星座上升) [DLC 解锁] [Steam] [Windows SteamOS macOS]

Astral Ascent 星界战士&#xff08;星座上升&#xff09; [DLC 解锁] [Steam] [Windows & SteamOS & macOS] 需要有游戏正版基础本体&#xff0c;安装路径不能带有中文&#xff0c;或其它非常规拉丁字符&#xff1b; DLC 版本 至最新全部 DLC 后续可能无法及时更新文章…

git中reset和checkout的用法

git reset&#xff1a;重置分支的历史与工作区​ 核心作用​​&#xff1a;移动当前分支的指针&#xff08;即改变分支的历史&#xff09;&#xff0c;并可选地修改暂存区&#xff08;Index&#xff09;和工作目录&#xff08;Working Directory&#xff09;。常用于撤销提交或…

权限提升—Linux提权内核溢出漏洞辅助项目

前言 今天开启Linux提权的篇章&#xff0c;主要是讲一下Linux的内核漏洞提权&#xff0c;利用方式和Windows系统漏洞提权差不多&#xff0c;也是网上的项目扫一下&#xff0c;然后根据漏洞编号去找exp即可。 信息收集 首先要说一下Linux用户的权限划分。 系统用户&#xff…

React Native Redux 使用指南 redux-toolkit

React Native Redux 使用指南 redux-toolkit 一个可预测和可维护的全局状态管理 JavaScript 库 Redux 和 React-Redux以及**reduxjs/toolkit 的关系&#xff1a;** Redux、React-Redux、reduxjs/toolkit 是 React 生态中状态管理的「黄金三角组合」&#xff0c;它们的关系可…

JVM——Java 虚拟机是如何加载 Java 类的?

引入 在 Java 世界的底层运作中&#xff0c;类加载机制扮演着一个既神秘又关键的角色。它就像是一个精心设计的舞台幕后 machinery&#xff0c;确保了 Java 程序能够顺利运行。今天&#xff0c;我们就深入探索 Java 虚拟机&#xff08;JVM&#xff09;是如何加载 Java 类的。 …

清华团队提出时序聚类数据库内高效方案,已被SIGMOD 2025接收

时间序列聚类是挖掘物联网等场景下频繁模式的关键技术&#xff0c;但现有SOTA方法&#xff08;如K-Shape&#xff09;面临两大瓶颈&#xff1a;1&#xff09;传统数据库因LSM-Tree存储导致时间戳无序&#xff0c;难以直接支持高效聚类&#xff1b;2&#xff09;跨时间范围查询需…

【阿里云大模型高级工程师ACP学习笔记】2.8 部署模型

一、学习目标 特别说明:这一章节是2025年3月官方重点更新的部分,几乎对内容重新翻新改造了一遍,重点突出了对于如何结合不同的阿里云产品来部署大模型进行了更加详细的介绍和对比,这里整理给大家,方便大家参考。 在备考阿里云大模型高级工程师ACP认证的过程中,学习《2.8 …

第T10周:数据增强

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 从 tensorflow.keras 中导入 layers 模块&#xff0c;包含了常用的神经网络层&#xff0c;用来搭建模型结构。 检查并列出系统中可用的物理 GPU 设备&#xff…

uniapp 支付宝小程序自定义 navbar 无效解决方案

如图&#xff1a; uniapp编译到支付宝小程序隐藏默认的导航栏失效了 解决方案&#xff1a; 在 pages.json 文件中找到 globalStyle 中加入以下代码&#xff1a; "mp-alipay": {"transparentTitle": "always","titlePenetrate":…

vue2 el-element中el-select选中值,数据已经改变但选择框中不显示值,需要其他输入框输入值才显示这个选择框才会显示刚才选中的值

项目场景&#xff1a; <el-table-column label"税率" prop"TaxRate" width"180" align"center" show-overflow-tooltip><template slot-scope"{row, $index}"><el-form-item :prop"InquiryItemList. …

centos7 离线安装python3 保留python2

一、事前准备&#xff1a; &#xff08;1&#xff09;查看centos具体版本 cat /etc/redhat-releaseCentOS Linux release 7.4.1708 (Core) &#xff08;2&#xff09;查看linux中当前python版本 centos7 默认安装python2.7.5 &#xff08;3&#xff09;查看python3的依赖&#…

十三种通信接口芯片——《器件手册--通信接口芯片》

目录 通信接口芯片 简述 基本功能 常见类型 应用场景 详尽阐述 1 RS485/RS422芯片 1. RS485和RS422标准 2. 芯片功能 3. 典型芯片及特点 4. 应用场景 5. 设计注意事项 6. 选型建议 2 RS232芯片 1. RS232标准 2. 芯片功能 3. 典型芯片及特点 4. 应用场景 5. 设计注意事项 6…

2025年RAG技术发展现状分析

2025年&#xff0c;大模型RAG&#xff08;检索增强生成&#xff09;技术经历了快速迭代与深度应用&#xff0c;逐渐从技术探索走向行业落地&#xff0c;同时也面临安全性和实用性的新挑战。以下是其发展现状的综合分析&#xff1a; 一、技术架构的持续演进 从单一到模块化架构 …

case和字符串操作

使用if选择结构 if [];then elif [];then #注意这个地方,java是else if else ; fi 使用for循环结构 使用for循环&#xff0c;语法结构如下所示&#xff1a; for 变量名 in 值1 值2 值3 #值的数量决定循环任务的次数 do命令序列 done#循环输出1到10 for i in {1..10} #注…

Stm32 烧录 Micropython

目录 前言 准备工作 开始操作 问题回顾 后记 前言 去年曾经尝试Pico制作openmv固件&#xff0c;由于知识储备不够最后失败了&#xff0c;留了一个大坑&#xff0c;有了前几天的基础&#xff0c;慢慢补齐知识&#xff0c;最近这一周一直在学习如何编译Stm固件并烧录到单片机…

盐化行业数字化转型规划详细方案(124页PPT)(文末有下载方式)

资料解读&#xff1a;《盐化行业数字化转型规划详细解决方案》 详细资料请看本解读文章的最后内容。 该文档聚焦盐化行业数字化转型&#xff0c;全面阐述了盐化企业信息化建设的规划方案&#xff0c;涵盖战略、架构、实施计划、风险及效益等多个方面&#xff0c;旨在通过数字化…

2025年人工智能火爆技术总结

2025年人工智能火爆技术总结&#xff1a; 生成式人工智能 生成式人工智能可生成高质量的图像、视频、音频和文本等多种内容。如昆仑万维的SkyReels-V2能生成无限时长电影&#xff0c;其基于扩散强迫框架&#xff0c;结合多模态大语言模型和强化学习等技术&#xff0c;在运动动…

边缘计算革命:大模型轻量化部署全栈实战指南

当ResNet-152模型能在树莓派4B上实现每秒27帧实时推理时&#xff0c;边缘智能时代真正到来。本文解析从模型压缩到硬件加速的完整技术栈&#xff0c;实测Transformer类模型在移动端的部署时延可压缩至16ms&#xff0c;揭示ARM芯片实现INT4量化的工程秘诀与十种典型场景优化方案…