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

基于 FFmpeg 的音视频处理基础原理与实验探究

目录

  • 1 基本知识
    • 1.1 解封装
    • 1.2 AAC和ADTS
      • 说明
    • 1.3 H264
      • 1.3.1 H264编码结构解析
      • 1.3.2 NALU
      • 1.3.2 分类
  • 2 实验1 探究音视频信息
    • 2.1 重要结构体介绍
    • 2.2 相关的API
  • 3 实验二 提取AAC数据
  • 4 实验三 提取h264

1 基本知识

1.1 解封装

在这里插入图片描述
封装的逆向操作:封装是把音频流、视频流、字幕流等不同成分按一定规则组合成视频文件(如 MP4、FLV ),复用器负责此过程。解封装则相反,是用解复用器(针对 MP4、FLV 等格式有对应解复用器)将视频文件再按规则拆分回音频流、视频流、字幕流等各个成分 。
流索引标识:解封装后,为区分各流,会给音频流、视频流等分配索引,如图中 audio_index = 1 表示音频流索引为 1 ,video_index = 0 表示视频流索引为 0 。程序后续可依这些索引分别处理对应流,比如解码视频流、播放音频流等 。

1.2 AAC和ADTS

AAC⾳频格式:Advanced Audio Coding(⾼级⾳频解码),是⼀种由MPEG-4
标准定义的有损⾳频压缩格式,由Fraunhofer发展,Dolby, Sony和AT&T是主要的贡献者。
分为两种封装格式

  • ADIF:Audio Data Interchange Format ⾳频数据交换格式。这种格式的特
    征是可以确定的找到这个⾳频数据的开始,不需进⾏在⾳频数据流中间开始
    的解码,即它的解码必须在明确定义的开始处进⾏。故这种格式常⽤在磁盘⽂件中。
  • ADTS的全称是Audio Data Transport Stream。是AAC⾳频的传输流格
    式。AAC⾳频格式在MPEG-2(ISO-13318-7 2003)中有定义。AAC后来
    ⼜被采⽤到MPEG-4标准中。这种格式的特征是它是⼀个有同步字的⽐特
    流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式

ADTS
在这里插入图片描述
有的时候当你编码AAC裸流的时候,会遇到写出来的AAC⽂件并不能在PC和⼿
机上播放,很⼤的可能就是AAC⽂件的每⼀帧⾥缺少了ADTS头信息⽂件的包装
拼接。
只需要加⼊头⽂件ADTS即可。⼀个AAC原始数据块⻓度是可变的,对原始帧加上ADTS头进⾏ADTS的封装,就形成了ADTS帧
ADTS帧
在这里插入图片描述
每⼀帧的ADTS的头⽂件都包含了⾳频的采样率,声道,帧⻓度等信息,这样解
码器才能解析读取。
⼀般情况下ADTS的头信息都是7个字节,分为2部分。

  • adts_fixed_header();
  • adts_variable_header();
    其⼀为固定头信息,紧接着是可变头信息。固定头信息中的数据每⼀帧都相
    同,⽽可变头信息则在帧与帧之间可变。
typedef struct {uint16_t syncword; // 同步字uint8_t id;        // MPEG标识符uint8_t layer;     // 层(固定为00)uint8_t protection_absent; // 是否有CRC校验uint8_t profile;   // AAC Profileuint8_t sampling_frequency_index; // 采样率索引uint8_t private_bit; // 私有位uint8_t channel_configuration; // 声道配置uint8_t original_copy; // 原始/拷贝标志uint8_t home;          // 主标志uint8_t copyright_identification_bit; // 版权标志位uint8_t copyright_identification_start; // 版权标志起始位uint16_t frame_length; // 帧长度uint8_t adts_buffer_fullness; // 缓存填充度uint8_t number_of_raw_data_blocks_in_frame; // 原始数据块数量
} ADTSHeader;

好的,以下是ADTS固定头参数的详细表格,包括字段名称、位长度、取值范围、含义和作用:

字段名称位长度取值范围含义作用
syncword120xFFF同步字标识一个ADTS帧的开始,用于帧同步。
ID10 或 1MPEG标识符区分MPEG版本:
0 = MPEG-4
1 = MPEG-2
Layer200固定为00,表示AAC编码。
protection_absent10 或 1误码校验标志表示是否包含CRC校验:
0 = 有CRC校验
1 = 无CRC校验
profile200-11AAC Profile(编码复杂度级别)表示编码复杂度:
00 = Main
01 = Low Complexity (LC)
10 = SSR
sampling_frequency_index40000-1111采样率索引通过索引查找采样率,例如:
0000 = 96 kHz
0100 = 44.1 kHz
private_bit10 或 1私有位用于私有用途,通常无具体含义。
channel_configuration30-7声道配置指定声道数和配置:
1 = 单声道
2 = 立体声
6 = 5.1声道
original_copy10 或 1原始/拷贝标志标识帧是否为原始数据:
0 = 拷贝
1 = 原始
home10 或 1主标志用于标识主音频流。
copyright_identification_bit10 或 1版权标志位标识是否包含版权信息。
copyright_identification_start10 或 1版权标志起始位标识版权信息的起始位置。

说明

  • syncword 是固定值 0xFFF,用于快速定位帧的起始位置
  • Layer 在AAC中始终为 00,因为AAC不使用MPEG音频的分层机制。
  • protection_absent 决定了帧头的长度(7字节或9字节)。
  • profilesampling_frequency_index 是关键字段,分别定义了编码复杂度和音频采样率。
  • channel_configuration 描述了音频的声道布局,例如立体声或5.1声道。
  • private_bitoriginal_copyhomecopyright_identification_bitcopyright_identification_start 主要用于扩展功能和版权保护。

1.3 H264

H.264从1999年开始,到2003年形成草案,最后在2007年定稿有待核实。在ITU的标准⾥称为H.264,在MPEG的标准⾥是MPEG-4的⼀个组成部分–MPEG-4 Part 10,⼜叫Advanced Video Codec,因此常常称为MPEG-4 AVC或直接叫AVC

H264编码原理
在⾳视频传输过程中,视频⽂件的传输是⼀个极⼤的问题;⼀段分辨率为19201080,每个像素点为RGB占⽤3个字节,帧率是25的视频,对于传输带宽的要求是:19201080325/1024/1024=148.315MB/s,换成bps则意味着视频每秒带宽为1186.523Mbps,这样的速率对于⽹络存储是不可接受的。因此视频压缩和编码技术应运⽽⽣。
对于视频⽂件来说,视频由单张图⽚帧所组成,⽐如每秒25帧,但是图⽚帧的像素块之间存在相似性,因此视频帧图像可以进⾏图像压缩;H264采⽤了16*16的分块⼤⼩对,视频帧图像进⾏相似⽐较和压缩编码
在这里插入图片描述
H264中的I帧、P帧和B帧
以下是提取的表格内容:

帧的分类中文意义
I帧帧内编码帧I帧通常是每个 GOP(MPEG 所使用的一种视频压缩技术)的第一个帧,经过适度地压缩,做为随机访问的参考点,可以当成图像。I帧可以看成是一个图像经过压缩后的产物。自身可以通过视频解压算法解压成一张单独的完整的图片
P帧前向预测编码帧通过充分将低于图像序列中前面已编码帧的时间冗余信息来压缩传输数据量的编码图像,也叫预测帧。需要参考其前面的一个I frame 或者P frame来生成一张完整的图片。
B帧双向预测帧既考虑与源图像序列前面已编码帧,也顾及源图像序列后面已编码帧之间的时间冗余信息来压缩传输数据量的编码图像, 也叫双向预测帧。则要参考其前一个I或者P帧及其后面的一个P帧来生成一张完整的图片

1.3.1 H264编码结构解析

IDR(Instantaneous Decoding Refresh,即时解码刷新)⼀个序列的第⼀个图像叫做 IDR 图像(⽴即刷新图像),IDR 图像都是 I 帧图像。I和IDR帧都使⽤帧内预测。I帧不⽤参考任何帧,但是之后的P帧和B帧是有可能参考这个I帧之前的帧的。IDR就不允许这样

原始图像 IDR1 B2 B3 P4 B5 B6 P7 B8 B9 I10
解码顺序:IDR1 P4 B2 B3 P7 B5 B6 I10 B8 B9 P13 B11 B12 P16 B14 B15

B8可以跨过I10去参考P7

IDR1 P4 B2 B3 P7 B5 B6 IDR8 P11 B9 B10 P14 B11 B12 这⾥的B9就只能参照IDR8和P1

其核⼼作⽤是,是为了解码的重同步,当解码器解码到 IDR 图像时,⽴即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始⼀个新的序列。这样,如果前⼀个序列出现重⼤错误,在这⾥可以获得重新同步的机会。IDR图像之后的图像永远不会使⽤IDR之前的图像的数据来解码

**GOP (图像组)**主要⽤作形容⼀个IDR帧 到下⼀个IDR帧之间的间隔了多少个帧
在这里插入图片描述
H264除了实现了对视频的压缩处理之外,为了⽅便⽹络传输,提供了对应的视频编码和分⽚策略;类似于⽹络数据封装成IP帧,在H264中将其称为组(GOP, group of pictures)、⽚(slice)、宏块(Macroblock)这些⼀起组成了H264的码流分层结构;H264将其组织成为序列(GOP)、图⽚(pictrue)、⽚(Slice)、宏块(Macroblock)、⼦块(subblock)五个层次

1.3.2 NALU

在这里插入图片描述
SPS(序列参数集)

  • 作用:SPS包含了整个视频序列的全局参数,这些参数对整个视频序列都是有效的。
  • 内容:

视频的分辨率(宽度和高度)。
帧率信息。
编码使用的Profile和Level。
其他全局参数,例如色域、比特深度等。
重要性:解码器需要这些信息来初始化解码环境,并正确解析后续的视频数据。

PPS(图像参数集)

  • 作用:PPS包含了特定图像(或几幅图像)的参数,这些参数对图像层面的操作是必需的。
  • 内容:
    宏块的编码参数。
    量化参数。
    其他图像特定的设置。
    重要性:解码器需要这些信息来正确解码每个图像(帧)。

因此,在发送I帧之前,必须先发送SPS和PPS,以确保解码器能够正确处理后续的视频数据。

NALU 是 GOP 的组成部分:一个 GOP 中的图像帧(I 帧、P 帧、B 帧等 )会被进一步封装成一个个 NALU 进行存储和传输 。比如一个 I 帧可能会被分割成多个 NALU,每个 NALU 包含 I 帧的一部分编码数据 ;P 帧和 B 帧也会以类似方式处理 。
编码与传输层面的关联:GOP 侧重于视频编码结构设计,决定帧间预测关系和编码顺序等 ,影响视频压缩效率和随机访问性能 。NALU 则更关注在网络环境下如何有效传输编码数据,通过 NALU 头信息标识数据类型和重要性等,便于网络适配和差错控制 。实际应用中,视频编码先按 GOP 结构组织帧,再将每个帧的编码数据封装成 NALU 在网络中传输 。接收端先按 NALU 接收数据,再依据 GOP 结构和 NALU 信息进行解码恢复视频 。

NALU结构
H.264原始码流(裸流)是由⼀个接⼀个NALU组成,它的功能分为两层,VCL(视频编码层)和NAL(⽹络提取层):

  • VCL:包括核⼼压缩引擎和块,宏块和⽚的语法级别定义,设计⽬标是尽可能地独⽴于⽹络进⾏⾼效的编码;
  • NAL:负责将VCL产⽣的⽐特字符串适配到各种各样的⽹络和多元环境中,覆盖了所有⽚级以上的语法级别

NALU结构单元

  • Start Code(起始码)
    作用:用于标识一个NALU单元的开始。
    格式:通常是00 00 00 01或00 00 01。
    说明:在H.264码流中,起始码帮助解码器识别NALU的边界。00 00 00 01通常用于完整帧被编码为多个slice(片)的场合,而00 00 01用于其他场合。
  • NALU Header(NALU头)
    长度:1字节。
    组成:
    • forbidden_zero_bit:1位,必须为0,用于错误检测。
    • nal_ref_idc:2位,表示NALU的重要性,取值范围为00到11。值越大,表示当前NALU越重要,需要优先保护。
    • nal_unit_type:5位,表示NALU的类型,如I帧、P帧、B帧、SPS、PPS等。
  • NALU Payload(NALU负载)
    内容:实际的编码数据,也称为RBSP(Raw Byte Sequence Payload,原始字节序列负载)。
    说明:负载部分包含具体的视频数据,如编码后的图像数据、参数集等。

1.3.2 分类

H264有两种封装
⼀种是annexb模式,传统模式,有startcode,SPS和PPS是在ES中
⼀种是mp4模式,⼀般mp4 mkv都是mp4模式,没有startcode,SPS和PPS以及其它信息
被封装在container中,每⼀个frame前⾯4个字节是这个frame的⻓度
很多解码器只⽀持annexb这种模式,因此需要将mp4做转换:在ffmpeg中⽤
h264_mp4toannexb_filter可以做转换

const AVBitStreamFilter *bsfilter =av_bsf_get_by_name("h264_mp4toannexb");
AVBSFContext *bsf_ctx = NULL;
//2 初始化过滤器上下⽂av_bsf_alloc(bsfilter, &bsf_ctx); //AVBSFContext;
// 3 添加解码器属性 
avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[videoindex]->codecpar);
av_bsf_init(bsf_ctx);

2 实验1 探究音视频信息

2.1 重要结构体介绍

以下是将上述代码中涉及的重要结构体的常用成员整理成的表格:

AVFormatContext 结构体
作用:描述一个媒体文件或媒体流的构成和基本信息,如文件格式、流的数量和类型、时长、比特率等。它是 FFmpeg 处理媒体文件的核心结构体,许多操作都围绕它展开。

成员名称类型描述
nb_streamsunsigned int媒体文件中流的数量,例如视频、音频、字幕流等的总数
bit_rateint64_t媒体文件的平均比特率,单位为比特每秒(bps),反映数据传输的速率
durationint64_t媒体文件的总时长,单位为微秒(us)
streamsAVStream **指向 AVStream 结构体数组的指针,每个 AVStream 代表一个流,通过该指针可访问各流的信息
urlchar *媒体文件的路径或网络地址,调用 avformat_open_input 时读取到的文件标识

AVStream 结构体
作用:存储媒体文件中单个流(音频流、视频流、字幕流等 )的相关信息

成员名称类型描述
indexint该流在媒体文件中的索引,用于唯一标识每个流
time_baseAVRational流的时间基,是一个表示分数的结构体,包含分子和分母,用于将时间戳转换为实际时间
durationint64_t流的总时长,以 time_base 为单位,若值为 AV_NOPTS_VALUE 表示时长未知
codecparAVCodecParameters *指向 AVCodecParameters 结构体的指针,存储该流的编解码器参数信息
avg_frame_rateAVRational视频流的平均帧率,以每秒帧数(fps)为单位,反映视频的播放速度

AVCodecParameters 结构体
作用:存储编解码器的参数信息,如编解码器 ID、媒体类型、数据格式(像素格式或采样格式 )、视频的宽高(视频流 )、音频的采样率和声道数(音频流 )等。

成员名称类型描述
codec_idenum AVCodecID编解码器的 ID,用于标识具体的编解码器,如 AV_CODEC_ID_H264 代表 H.264 视频编解码器
codec_typeenum AVMediaType媒体类型,表明该流是视频、音频还是字幕等,如 AVMEDIA_TYPE_VIDEO 代表视频流
formatint数据格式,对于视频流是像素格式(如 AV_PIX_FMT_YUV420P),对于音频流是采样格式(如 AV_SAMPLE_FMT_FLTP
widthint视频帧的宽度,单位为像素,仅适用于视频流
heightint视频帧的高度,单位为像素,仅适用于视频流
sample_rateint音频采样率,单位为 Hz,表示每秒采集的样本数,仅适用于音频流
channelsint音频声道数,如单声道为 1,立体声为 2,仅适用于音频流

AVPacket 结构体
AVPacket
作用:存储从媒体文件中读取的一帧压缩数据(音频帧或视频帧 ),包含时间戳、数据大小、流索引等信息。

成员名称类型描述
ptsint64_t显示时间戳(Presentation Timestamp),用于标识该帧在播放时的时间点
dtsint64_t解码时间戳(Decoding Timestamp),用于标识该帧在解码时的时间点
sizeint数据包中数据的大小,单位为字节
stream_indexint该数据包所属流的索引,用于确定是音频流、视频流还是其他流的数据
durationint64_t该帧的时长,以 AVStreamtime_base 为单位,反映帧的持续时间

2.2 相关的API

  • avformat_network_init void avformat_network_init(void);
    初始化网络组件,让 FFmpeg 支持网络流的读取,像 RTSP、HTTP 这类网络协议的流
  • int avformat_open_input(AVFormatContext **ps, const char *url, ff_const59 AVInputFormat *fmt, AVDictionary **options);

ps:指向 AVFormatContext 指针的指针。函数会分配并初始化 AVFormatContext,并将其地址存储在 *ps 中。
url:输入媒体文件的路径或者网络地址。
fmt:指定输入格式,通常设为 NULL,让 FFmpeg 自动探测。
options:传递给解复用器的选项,是一个 AVDictionary 指针,通常设为 NULL。

  • int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);

avformat_find_stream_info函数通过读取媒体文件的头部信息以及可能的一些额外数据,来填充AVFormatContext结构体中的各个字段,从而获取到流的信息,如流的数量、每个流的编码参数(包括视频的分辨率、帧率,音频的采样率、声道数等)、时长、比特率等。这些信息对于后续正确地解码和处理音视频数据非常重要
ic:指向 AVFormatContext 的指针,代表已打开的输入媒体文件。
options:传递给解复用器的选项,是一个 AVDictionary 指针,通常设为 NULL。

  • void av_dump_format(AVFormatContext *ic, int index, const char *url, int is_output);

功能:打印媒体文件的格式信息,涵盖流的数量、每个流的详细参数等。
参数:
ic:指向 AVFormatContext 的指针,代表已打开的输入媒体文件。
index:要打印信息的流的索引,通常设为 0 表示打印所有流的信息。
url:输入媒体文件的路径或者网络地址,用于显示信息。
is_output:指示是输入文件(0)还是输出文件(1)。

  • int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type, int wanted_stream_nb, int related_stream, AVCodec **decoder_ret, int flags);

功能:在媒体文件的流中查找指定类型(如音频、视频)的最佳流。
参数:
ic:指向 AVFormatContext 的指针,代表已打开的输入媒体文件。
type:要查找的流的类型,如 AVMEDIA_TYPE_AUDIO 或 AVMEDIA_TYPE_VIDEO。
wanted_stream_nb:指定要查找的流的编号,若为 -1 则查找任意流。
related_stream:相关流的编号,通常设为 -1。
decoder_ret:若不为 NULL,则返回找到的流的解码器。
flags:查找标志,通常设为 0。

  • int av_read_frame(AVFormatContext *s, AVPacket *pkt);

AVFormatContext 结构体 ifmt_ctx 表示)中读取一帧压缩数据(音频帧或视频帧)的函数。每次调用该函数时,它会从文件或流中解析并提取下一帧数据,并将其存储在 AVPacket 结构体 pkt 中
参数:
s:指向 AVFormatContext 的指针,代表已打开的输入媒体文件。
pkt:指向 AVPacket 的指针,用于存储读取到的帧数据。
返回:成功返回 0,文件结束返回 AVERROR_EOF,失败返回负错误码。

  • av_packet_alloc AVPacket *av_packet_alloc(void);

功能:分配一个 AVPacket 结构体,用于存储读取到的媒体帧数据。
参数:无。
返回值:成功返回分配的 AVPacket 指针,失败返回 NULL。

  • void av_packet_unref(AVPacket *pkt);

功能:减少 AVPacket 的引用计数,当引用计数为 0 时释放相关资源。
参数:
pkt:指向 AVPacket 的指针,要释放引用的数据包。
返回值:无。

  • void av_packet_free(AVPacket **pkt);

功能:释放 AVPacket 结构体及其关联的资源。
参数:
pkt:指向 AVPacket 指针的指针,要释放的数据包。
返回值:无

3 实验二 提取AAC数据

int adts_header(char * const p_adts_header, const int data_length,const int profile, const int samplerate,const int channels)
{int sampling_frequency_index = 3; // 默认使用48000hzint adtsLen = data_length + 7;int frequencies_size = sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]);int i = 0;for(i = 0; i < frequencies_size; i++){if(sampling_frequencies[i] == samplerate){sampling_frequency_index = i;break;}}if(i >= frequencies_size){printf("unsupport samplerate:%d\n", samplerate);return -1;}p_adts_header[0] = 0xff;         //syncword:0xfff                          高8bitsp_adts_header[1] = 0xf0;         //syncword:0xfff                          低4bitsp_adts_header[1] |= (0 << 3);    //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bitp_adts_header[1] |= (0 << 1);    //Layer:0                                 2bitsp_adts_header[1] |= 1;           //protection absent:1                     1bitp_adts_header[2] = (profile)<<6;            //profile:profile               2bitsp_adts_header[2] |= (sampling_frequency_index & 0x0f)<<2; //sampling frequency index:sampling_frequency_index  4bitsp_adts_header[2] |= (0 << 1);             //private bit:0                   1bitp_adts_header[2] |= (channels & 0x04)>>2; //channel configuration:channels  高1bitp_adts_header[3] = (channels & 0x03)<<6; //channel configuration:channels 低2bitsp_adts_header[3] |= (0 << 5);               //original:0                1bitp_adts_header[3] |= (0 << 4);               //home:0                    1bitp_adts_header[3] |= (0 << 3);               //copyright id bit:0        1bitp_adts_header[3] |= (0 << 2);               //copyright id start:0      1bitp_adts_header[3] |= ((adtsLen & 0x1800) >> 11);           //frame length:value   高2bitsp_adts_header[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);     //frame length:value    中间8bitsp_adts_header[5] = (uint8_t)((adtsLen & 0x7) << 5);       //frame length:value    低3bitsp_adts_header[5] |= 0x1f;                                 //buffer fullness:0x7ff 高5bitsp_adts_header[6] = 0xfc;      //‭11111100‬       //buffer fullness:0x7ff 低6bits// number_of_raw_data_blocks_in_frame://    表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧。return 0;
}

补充:
|:或运算 有 1 这个位就是1
&:与运行 全为 1 才能是1
<<:左移运算符:移运算符规则:左移运算符 << 用于将一个二进制数向左移动指定的位数。其基本规则是,将操作数的二进制表示向左移动指定的位数,右边空出的位用 0 填充,而左边超出的位则被丢弃。
(0 << 3) 的计算:
数字 0 的二进制表示(假设为 8 位)是 0000 0000。
对其进行左移 3 位操作,即将所有位向左移动 3 位,右边空出的 3 位用 0 填充,得到的结果仍然是 0000 0000,也就是十进制的 0。
最终:p_adts_header[1] =0xf1;


size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

ptr:指向用于存储读取数据的内存块的指针。
size:每个数据项的大小(以字节为单位)。
nmemb:要读取的数据项的数量。
stream:指向 FILE 对象的指针,表示要读取的文件流。


FILE *fopen(const char *filename, const char *mode);

  • filename:这是一个字符串,代表要打开的文件的名称。如果文件在当前工作目录之外,需要提供完整的文件路径。
  • mode:同样是字符串,用于指定文件的打开模式。常见的打开模式如下:
    “r”:以只读模式打开文本文件。文件必须存在,否则打开失败。
    “w”:以写入模式打开文本文件。若文件存在,其内容会被清空;若文件不存在,则创建新文件。
    “a”:以追加模式打开文本文件。若文件存在,写入的数据会添加到文件末尾;若文件不存在,则创建新文件。
    “r+”:以读写模式打开文本文件。文件必须存在。
    “w+”:以读写模式打开文本文件。若文件存在,内容会被清空;若不存在,则创建新文件。
    “a+”:以读写模式打开文本文件。若文件存在,写入的数据会添加到文件末尾;若不存在,则创建新文件。
    若要以二进制模式操作文件,在上述模式后面加上字母 b,例如 “rb”、“wb” 等。

#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>#define ADTS_HEADER_LEN  7;const int sampling_frequencies[] = {96000,  // 0x088200,  // 0x164000,  // 0x248000,  // 0x344100,  // 0x432000,  // 0x524000,  // 0x622050,  // 0x716000,  // 0x812000,  // 0x911025,  // 0xa8000   // 0xb// 0xc d e f是保留的
};int adts_header(char * const p_adts_header, const int data_length,const int profile, const int samplerate,const int channels)
{int sampling_frequency_index = 3; // 默认使用48000hzint adtsLen = data_length + 7;int frequencies_size = sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]);//计算大小int i = 0;for(i = 0; i < frequencies_size; i++){if(sampling_frequencies[i] == samplerate){sampling_frequency_index = i;break;}}//音频采样if(i >= frequencies_size){printf("unsupport samplerate:%d\n", samplerate);return -1;}p_adts_header[0] = 0xff;         //syncword:0xfff                          高8bitsp_adts_header[1] = 0xf0;         //syncword:0xfff                          低4bitsp_adts_header[1] |= (0 << 3);    //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bitp_adts_header[1] |= (0 << 1);    //Layer:0                                 2bitsp_adts_header[1] |= 1;           //protection absent:1                     1bitp_adts_header[2] = (profile)<<6;            //profile:profile               2bitsp_adts_header[2] |= (sampling_frequency_index & 0x0f)<<2; //sampling frequency index:sampling_frequency_index  4bitsp_adts_header[2] |= (0 << 1);             //private bit:0                   1bitp_adts_header[2] |= (channels & 0x04)>>2; //channel configuration:channels  高1bitp_adts_header[3] = (channels & 0x03)<<6; //channel configuration:channels 低2bitsp_adts_header[3] |= (0 << 5);               //original:0                1bitp_adts_header[3] |= (0 << 4);               //home:0                    1bitp_adts_header[3] |= (0 << 3);               //copyright id bit:0        1bitp_adts_header[3] |= (0 << 2);               //copyright id start:0      1bitp_adts_header[3] |= ((adtsLen & 0x1800) >> 11);           //frame length:value   高2bitsp_adts_header[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);     //frame length:value    中间8bitsp_adts_header[5] = (uint8_t)((adtsLen & 0x7) << 5);       //frame length:value    低3bitsp_adts_header[5] |= 0x1f;                                 //buffer fullness:0x7ff 高5bitsp_adts_header[6] = 0xfc;      //‭11111100‬       //buffer fullness:0x7ff 低6bits// number_of_raw_data_blocks_in_frame://    表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧。return 0;
}int main(int argc, char *argv[])
{int ret = -1;char errors[1024];char *in_filename = NULL;char *aac_filename = NULL;FILE *aac_fd = NULL;int audio_index = -1;int len = 0;AVFormatContext *ifmt_ctx = NULL;AVPacket pkt;// 设置打印级别av_log_set_level(AV_LOG_DEBUG);if(argc < 3){av_log(NULL, AV_LOG_DEBUG, "the count of parameters should be more than three!\n");return -1;}in_filename = argv[1];      // 输入文件aac_filename = argv[2];     // 输出文件if(in_filename == NULL || aac_filename == NULL){av_log(NULL, AV_LOG_DEBUG, "src or dts file is null, plz check them!\n");return -1;}aac_fd = fopen(aac_filename, "wb");if (!aac_fd){av_log(NULL, AV_LOG_DEBUG, "Could not open destination file %s\n", aac_filename);return -1;}// 打开输入文件if((ret = avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL)) < 0){av_strerror(ret, errors, 1024);av_log(NULL, AV_LOG_DEBUG, "Could not open source file: %s, %d(%s)\n",in_filename,ret,errors);return -1;}// 获取解码器信息if((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0){av_strerror(ret, errors, 1024);av_log(NULL, AV_LOG_DEBUG, "failed to find stream information: %s, %d(%s)\n",in_filename,ret,errors);return -1;}// dump媒体信息av_dump_format(ifmt_ctx, 0, in_filename, 0);// 初始化packetav_init_packet(&pkt);// 查找audio对应的steam indexaudio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);if(audio_index < 0){av_log(NULL, AV_LOG_DEBUG, "Could not find %s stream in input file %s\n",av_get_media_type_string(AVMEDIA_TYPE_AUDIO),in_filename);return AVERROR(EINVAL);}// 打印AAC级别printf("audio profile:%d, FF_PROFILE_AAC_LOW:%d\n",ifmt_ctx->streams[audio_index]->codecpar->profile,FF_PROFILE_AAC_LOW);if(ifmt_ctx->streams[audio_index]->codecpar->codec_id != AV_CODEC_ID_AAC){printf("the media file no contain AAC stream, it's codec_id is %d\n",ifmt_ctx->streams[audio_index]->codecpar->codec_id);goto failed;}// 读取媒体文件,并把aac数据帧写入到本地文件while(av_read_frame(ifmt_ctx, &pkt) >=0 ){if(pkt.stream_index == audio_index){char adts_header_buf[7] = {0};adts_header(adts_header_buf, pkt.size,ifmt_ctx->streams[audio_index]->codecpar->profile,ifmt_ctx->streams[audio_index]->codecpar->sample_rate,ifmt_ctx->streams[audio_index]->codecpar->channels);fwrite(adts_header_buf, 1, 7, aac_fd);  // 写adts header , ts流不适用,ts流分离出来的packet带了adts headerlen = fwrite( pkt.data, 1, pkt.size, aac_fd);   // 写adts dataif(len != pkt.size){av_log(NULL, AV_LOG_DEBUG, "warning, length of writed data isn't equal pkt.size(%d, %d)\n",len,pkt.size);}}av_packet_unref(&pkt);}failed:// 关闭输入文件if(ifmt_ctx){avformat_close_input(&ifmt_ctx);}if(aac_fd){fclose(aac_fd);}return 0;
}

4 实验三 提取h264

#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>static char err_buf[128] = {0};
static char* av_get_err(int errnum)
{av_strerror(errnum, err_buf, 128);return err_buf;
}int main(int argc, char **argv)
{AVFormatContext *ifmt_ctx = NULL;int             videoindex = -1;AVPacket        *pkt = NULL;int             ret = -1;int             file_end = 0; // 文件是否读取结束if(argc < 3){printf("usage inputfile outfile\n");return -1;}FILE *outfp=fopen(argv[2],"wb");printf("in:%s out:%s\n", argv[1], argv[2]);// 分配解复用器的内存,使用avformat_close_input释放ifmt_ctx = avformat_alloc_context();if (!ifmt_ctx){printf("[error] Could not allocate context.\n");return -1;}// 根据url打开码流,并选择匹配的解复用器ret = avformat_open_input(&ifmt_ctx,argv[1], NULL, NULL);if(ret != 0){printf("[error]avformat_open_input: %s\n", av_get_err(ret));return -1;}// 读取媒体文件的部分数据包以获取码流信息ret = avformat_find_stream_info(ifmt_ctx, NULL);if(ret < 0){printf("[error]avformat_find_stream_info: %s\n", av_get_err(ret));avformat_close_input(&ifmt_ctx);return -1;}// 查找出哪个码流是video/audio/subtitlesvideoindex = -1;// 推荐的方式videoindex = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);if(videoindex == -1){printf("Didn't find a video stream.\n");avformat_close_input(&ifmt_ctx);return -1;}// 分配数据包pkt = av_packet_alloc();av_init_packet(pkt);// 1 获取相应的比特流过滤器//FLV/MP4/MKV等结构中,h264需要h264_mp4toannexb处理。添加SPS/PPS等信息。const AVBitStreamFilter *bsfilter = av_bsf_get_by_name("h264_mp4toannexb");AVBSFContext *bsf_ctx = NULL;// 2 初始化过滤器上下文av_bsf_alloc(bsfilter, &bsf_ctx); //AVBSFContext;// 3 添加解码器属性avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[videoindex]->codecpar);av_bsf_init(bsf_ctx);file_end = 0;while (0 == file_end){if((ret = av_read_frame(ifmt_ctx, pkt)) < 0){// 没有更多包可读file_end = 1;printf("read file end: ret:%d\n", ret);}if(ret == 0 && pkt->stream_index == videoindex){
#if 1//int input_size = pkt->size;int out_pkt_count = 0;if (av_bsf_send_packet(bsf_ctx, pkt) != 0) // bitstreamfilter内部去维护内存空间{av_packet_unref(pkt);   // 你不用了就把资源释放掉continue;       // 继续送}av_packet_unref(pkt);   // 释放资源while(av_bsf_receive_packet(bsf_ctx, pkt) == 0){out_pkt_count++;// printf("fwrite size:%d\n", pkt->size);size_t size = fwrite(pkt->data, 1, pkt->size, outfp);if(size != pkt->size){printf("fwrite failed-> write:%u, pkt_size:%u\n", size, pkt->size);}av_packet_unref(pkt);}if(out_pkt_count >= 2){printf("cur pkt(size:%d) only get 1 out pkt, it get %d pkts\n",input_size, out_pkt_count);}#else       // TS流可以直接写入 stsize_t size = fwrite(pkt->data, 1, pkt->size, outfp);if(size != pkt->size){printf("fwrite failed-> write:%u, pkt_size:%u\n", size, pkt->size);}av_packet_unref(pkt);
#endif}else{if(ret == 0)av_packet_unref(pkt);        // 释放内存}}if(outfp)fclose(outfp);if(bsf_ctx)av_bsf_free(&bsf_ctx);if(pkt)av_packet_free(&pkt);if(ifmt_ctx)avformat_close_input(&ifmt_ctx);printf("finish\n");return 0;
}

发送数据包到过滤器:运用 av_bsf_send_packet 函数把输入的数据包发送给比特流过滤器上下文 bsf_ctx。若发送失败,释放该数据包并继续处理下一个数据包。
接收处理后的数据包:通过 av_bsf_receive_packet 函数从过滤器中接收处理后的数据包,可能会接收到多个输出数据包。
写入文件:将每个处理后的数据包写入输出文件。
调试信息输出:若接收到的输出数据包数量超过预期(这里是大于等于 2 个),输出调试信息。


相关文章:

基于 FFmpeg 的音视频处理基础原理与实验探究

目录 1 基本知识1.1 解封装1.2 AAC和ADTS说明 1.3 H2641.3.1 H264编码结构解析1.3.2 NALU1.3.2 分类 2 实验1 探究音视频信息2.1 重要结构体介绍2.2 相关的API 3 实验二 提取AAC数据4 实验三 提取h264 1 基本知识 1.1 解封装 封装的逆向操作&#xff1a;封装是把音频流、视频流…...

spark和hadoop的区别

一、核心定位与架构差异 Hadoop • 定位&#xff1a;分布式存储与计算的基础框架&#xff0c;核心解决海量数据的存储&#xff08;HDFS&#xff09;和离线批处理计算&#xff08;MapReduce&#xff09;问题&#xff0c;适合对实时性要求不高的大规模数据离线处理场景。 • 架构…...

vue使用语音识别

vue使用语音识别 使用 Web Speech API 实现语音识别功能 语音转换的原理可以简单概括为以下几个步骤&#xff1a; 声音捕捉&#xff1a;将声波转化为数字信号。特征提取&#xff1a;分析声音中的关键特征。声学模型&#xff1a;将声音特征与音素匹配。语言模型&#xff1a;根据…...

代码随想录算法训练营day8(栈与队列)

华子目录 用栈实现队列思路 用栈实现队列 https://leetcode.cn/problems/implement-queue-using-stacks/description/ push(x) -- 将一个元素放入队列的尾部。 pop() -- 从队列首部移除元素。 peek() -- 返回队列首部的元素。 empty() -- 返回队列是否为空。思路 初始化两个栈…...

GPT,Genini, Claude Llama, DeepSeek,Qwen,Grok,选对LLM大模型真的可以事半功倍!

选对大模型真的可以事半功倍&#xff01; 基于公开的技术报告、基准测试结果、在线反馈及用户使用情况&#xff0c;深入探讨各模型的特点、擅长领域及典型应用场景&#xff0c;为用户和开发者选择和应用合适的模型提供参考。 1. 引言 大型语言模型&#xff08;Large Language…...

Unocss 类名基操, tailwindcss 类名

这里只列出 unocss 的可实现类名&#xff0c;tailwindcss 可以拿去试试用 1. 父元素移入&#xff0c;子元素改样式 <!-- 必须是 group 类名 --> <div class"group"><div class"group-hover:color-red">Text</div> </div>2…...

Flowable7.x学习笔记(十)分页查询已部署 BPMN XML 流程

前言 上一篇文章我们已经完成了流程的部署功能&#xff0c;那么下一步就是要激活流程了&#xff0c;但是我们要需要明确的指定具体要激活部署后的哪一条流程&#xff0c;所以我们先把已部署的基础信息以及具体定义信息分页查询出来&#xff0c;本文先把基础代码生成以及完成分页…...

【阿里云大模型高级工程师ACP学习笔记】2.1 用大模型构建新人答疑机器人

学习目标 在备考阿里云大模型高级工程师ACP认证时,学习《2.1用大模型构建新人答疑机器人》这部分内容,主要是为了掌握利用大模型技术构建高效答疑机器人的方法,提升在大模型应用开发领域的专业能力。具体目标如下: 掌握大模型API调用:学会通过API调用通义千问大模型,熟悉…...

设计模式深度总结:概念、实现与框架中的应用

【全网最全】23种设计模式思维导图详解 | 含React/Vue/Spring实战案例 导图概述 本文通过高清思维导图系统梳理了23种设计模式&#xff0c;分为创建型、结构型、行为型三大类&#xff0c;并标注了各模式在主流框架&#xff08;如React、Vue、Spring&#xff09;中的典型应用场…...

2025 活体识别+人脸认证工具类【阿里云api,需要先申请试用】

&#xff08;1&#xff09;获取活体检测的人脸URL地址和Token。 &#xff08;2&#xff09;活体检测成功后&#xff0c;使用Token验证人脸检测结果的一致性。 &#xff08;3&#xff09;对于检测结果一致的人脸照片&#xff0c;进行姓名、身份证号和照片的认证流程。 一、活…...

【HDFS】verifyEC命令校验EC数据正确性

verifyEC命令是HDFS里用于验证EC文件正确性的一个工具。这是一个非常实用的工具,能帮助我们确定EC的数据内容是否正确,并且如果不正确的话,还有可能会触发reportBadBlock给NN,让NN进行块的重构。 本文先介绍一下verifyEC命令的使用方法,再描述其实现原理细节。 一、命令…...

【PCIE730】基于PCIe总线架构的4路10G光纤通道适配器

板卡简介 PCIE730是一款基于PCI Express总线架构的4路10G光纤通道适配器&#xff0c;板卡具有4通道SFP万兆光纤接口&#xff0c;x8 PCIE主机接口&#xff0c;具有1组64位DDR3 SDRAM作为高速缓存&#xff0c;可以实现4通道光纤网络数据的高速采集、实时记录和宽带回放。 该板卡还…...

蚂蚁全媒体总编刘鑫炜再添新职,出任共工新闻社新媒体研究院院长

2025年4月18日&#xff0c;共工新闻社正式宣布聘任蚂蚁全媒体总编刘鑫炜为新媒体研究院院长。此次任命标志着刘鑫炜在新媒体领域的专业能力与行业贡献再次获得权威机构认可。 刘鑫炜深耕新媒体领域多年&#xff0c;曾担任中国新闻传媒集团新媒体研究院院长、蚂蚁全媒体总编等职…...

C++11——可调用对象

目录 lambda 表达式语法 捕捉列表 function bind 调整参数个数 参数顺序 lambda 表达式语法 lambda表达式本质上是匿名函数对象&#xff0c;该表达式在语法使用层是没有类型的&#xff0c;一般用auto或模板参数定义的对象去接收它的对象&#xff08;模板参数定义的对象…...

【上位机——MFC】运行时类信息机制

运行时类信息机制的使用 类必须派生自CObject类内必须添加声明宏DECLARE_DYNAMIC(theClass)3.类外必须添加实现宏 IMPLEMENT_DYNAMIC(theClass,baseClass) 具备上述三个条件后&#xff0c;CObject::IsKindOf函数就可以正确判断对象是否属于某个类。 代码示例 #include <…...

数据中的知识产权问题

首席数据官高鹏律师团队编著 数据中的知识产权问题涉及法律、技术和社会多个层面&#xff0c;其复杂性随着数据价值的提升和数字化发展日益凸显。以下是核心要点的梳理和分析&#xff1a; 一、数据本身的知识产权属性 1. 原始数据&#xff08;Raw Data&#xff09; 通常不直…...

若依框架免登陆、页面全屏显示、打开新标签页(看板大屏)

1.免登陆&#xff1a;找到项目目录下src/permission.js&#xff0c;在白名单whiteList中添加上你的看板大屏路由地址&#xff0c;这样就不会校验该路由的token&#xff08;这里我添加的是/mesBoard/mesqualityboard&#xff09;&#xff1b; 要注意的是此时免登陆进来也会报404…...

算法-策略(递归,二叉搜索)

分而治之 一个大问题不断拆成各种小问题&#xff0c;大问题与小问题的方向要一致。 递归函数(递减) 分析时间函数的两种方法&#xff1a;递归树(跟踪树) &#xff0c;代换法。 例1 例2 这里的代换法注意&#xff0c;不要轻易的把常数加在一起&#xff0c;加在一起后看不出规…...

unity TEngine学习4

上一篇我们学习了UI部分&#xff0c;这一篇我们学习其他部分&#xff0c;按照老规矩还是先打开官方文档 ResourceModule 在官方文档里介绍了当前加载的设置&#xff0c;但是我们是小白看不懂&#xff0c;那就不管他内部怎么实现的&#xff0c;我们主要看下面的代码给的方法&am…...

掌握常见 HTTP 方法:GET、POST、PUT 到 CONNECT 全面梳理

今天面试还问了除了 get 和 post 方法还有其他请求方法吗&#xff0c;一个都不知道&#xff0c;这里记录下。 &#x1f310; 常见 HTTP 请求方法一览 方法作用描述是否幂等是否常用GET获取资源&#xff0c;参数一般拼接在 URL 中✅ 是✅ 常用POST创建资源 / 提交数据&#xff…...

在线查看【免费】 mp3,wav,mp4,flv 等音视频格式文件文件格式网站

可以免费在线查看 .docx/wps/Office/wmf/ psd/ psd/eml/epub/dwg, dxf/ txt/zip, rar/ jpg/mp3 m.gszh.xyz m.gszh.xyz 免费支持以下格式文件在线查看类型 支持 doc, docx, xls, xlsx, xlsm, ppt, pptx, csv, tsv, dotm, xlt, xltm, dot, dotx, xlam, xla, pages 等 Office 办…...

部署Kimi-VL-A3B-Instruct视频推理

部署Kimi-VL-A3B-Instruct视频推理 契机 ⚙ 最近国内AI公司月之暗面推出了Kimi-VL开源视觉模型。模型参数16.4B&#xff0c;但是推理时候激活参数2.8B。看了huggingface主页的Full comparison&#xff0c;在多项Benchmark的时候都展示出了不俗的实力。由于业务中使用了qwen-v…...

力扣面试经典150题(第二十四题)

问题 给定一个单词数组 words 和一个长度 maxWidth &#xff0c;重新排版单词&#xff0c;使其成为每行恰好有 maxWidth 个字符&#xff0c;且左右两端对齐的文本。 你应该使用 “贪心算法” 来放置给定的单词&#xff1b;也就是说&#xff0c;尽可能多地往每行中放置单词。必…...

Electron Demo 的快速编译与启动

前言 本文将带你从零开始&#xff0c;快速搭建并运行一个基于 OpenIMSDK 的 Electron 应用。本项目以 OpenIMSDK 开源版为基础&#xff0c;借助 openim/electron-client-sdk 与 openim/wasm-client-sdk&#xff0c;能够同时构建 Web 端及桌面端&#xff08;Windows、macOS、Lin…...

Web3核心技术解析:从区块链到C++实践

Web3作为下一代互联网的核心架构&#xff0c;正在通过区块链、智能合约、分布式存储等技术的融合&#xff0c;重塑数字世界的信任与协作模式。本文将从技术原理、应用场景及C实践案例三个维度&#xff0c;深入解析Web3的核心技术体系。 一、Web3的核心技术栈 1. 区块链&#x…...

Elasticsearch中的_source字段讲解

_source 在 Elasticsearch 查询中用于限制返回的字段,类似于 SQL 中的 SELECT 指定列。 代码示例: esSearchResults = es_service.search_documents({"query": {"terms": {"file_id":...

LlamaIndex 生成的本地索引文件和文件夹详解

LlamaIndex 生成的本地索引文件和文件夹详解 LlamaIndex 在生成本地索引时会创建一个 storage 文件夹&#xff0c;并在其中生成多个 JSON 文件。以下是每个文件的详细解释&#xff1a; 1. storage 文件夹结构 1.1 docstore.json 功能&#xff1a;存储文档内容及其相关信息。…...

笔记:react中 父组件怎么获取子组件中的属性或方法

在子组件中我们可以使用下面两个方法去暴露你所要放行的属性或方法&#x1f447; 1.useImperativeHandle 2.orwardRef 搭配使用例子 import React, { useState, forwardRef, useImperativeHandle } from "react"function Son(props, ref) {const [data] useStat…...

Python+CoppeliaSim+ZMQ remote API控制机器人跳舞

这是一个使用Python和CoppeliaSim&#xff08;V-REP&#xff09;控制ASTI人型机器人进行舞蹈动作的演示项目。 项目描述 本项目展示了如何使用Python通过ZeroMQ远程API与CoppeliaSim仿真环境进行交互&#xff0c;控制ASTI人型机器人执行预定义的舞蹈动作序列。项目包含完整的机…...

oracle rac时区问题导致远程查询时间不准

远程工具SQLDev工具和应用出来的时间都要慢12个小时 检查操作系统和硬件时间 # date Fri Apr 18 15:54:11 CST 2025 date -R Fri, 18 Apr 2025 16:06:24 0800 # hwclock -r Fri 18 Apr 2025 04:08:38 PM CST -0.313786 seconds 都是没有问题&#xff0c;时间和时区都是…...

LPO 光模块:下一代数据中心网络的节能高效新选择

一、LPO 光模块的定义与核心原理 LPO&#xff08;Linear Pluggable Optics&#xff0c;线性可插拔光模块&#xff09;是光通信领域针对高速率、低功耗需求推出的创新解决方案。其核心突破在于摒弃传统光模块中的 DSP&#xff08;数字信号处理&#xff09;芯片&#xff0c;采用线…...

MCP Server Java 开发框架的体验比较(spring ai mcp 和 solon ai mcp)

目前已知的两个 mcp-server java 应用开发框架&#xff08;ID类的&#xff0c;封装后体验都比较简洁&#xff09;&#xff1a; spring-ai-mcp&#xff0c;支持 java17 或以上solon-ai-mcp&#xff0c;支持 java8 或以上&#xff08;也支持集成到 springboot2, jfinal, vert.x …...

OpenCV 图形API(45)颜色空间转换-----将图像从 BGR 色彩空间转换为 YUV 色彩空间函数BGR2YUV()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从BGR色彩空间转换为YUV色彩空间。 该函数将输入图像从BGR色彩空间转换为YUV。B、G和R通道值的常规范围是0到255。 输出图像必须是8位无符…...

C++入门语法

C入门 首先第一点&#xff0c;C中可以混用C语言中的语法。但是C语言是不兼容C的。C主要是为了改进C语言而创建的一门语言&#xff0c;就是有人用C语言用不爽了&#xff0c;改出来个C。 命名空间 c语言中会有如下这样的问题&#xff1a; 那么C为了解决这个问题就整出了一个命名…...

个性化的配置AndroidStudio

Android Studio 提供诸多向导和模板&#xff0c;可用于验证 Java 开发套件 (JDK) 和可用 RAM 等系统要求&#xff0c;以及配置默认设置&#xff0c;例如经过优化的默认 Android 虚拟设备 (AVD) 模拟和更新的系统映像。本文档介绍了可用于自定义 Android Studio 使用方式的其他配…...

Python-24:小R的随机播放顺序

问题描述 小R有一个特殊的随机播放规则。他首先播放歌单中的第一首歌&#xff0c;播放后将其从歌单中移除。如果歌单中还有歌曲&#xff0c;则会将当前第一首歌移到最后一首。这个过程会一直重复&#xff0c;直到歌单中没有任何歌曲。 例如&#xff0c;给定歌单 [5, 3, 2, 1,…...

JavaScript — 总结

介绍 JavaScript是一种广泛应用于Web开发的高级脚本语言&#xff0c;主要用于为网页添加交互功能。作为前端开发的三大核心技术之一&#xff0c;它与HTML&#xff08;结构&#xff09;和CSS&#xff08;样式&#xff09;协同工作&#xff0c;通过操作DOM元素实现动态内容更新、…...

解决 Ubuntu 下 VTune 无法收集 CPU 硬件时间计数数据的问题

解决 Ubuntu 下 VTune 无法收集 CPU 硬件时间计数数据的问题 在 Ubuntu 上使用 Intel VTune Profiler 时遇到无法收集 CPU 硬件性能计数器数据的问题&#xff0c;通常是由于权限和系统配置问题导致的。以下是解决方案&#xff1a; 1. 检查并加载性能监控模块 首先确保 Linux…...

MySQL《事务》

文章目录 前言一、什么是事务&#xff1f;二、事务的ACID特性三、如何使用事务&#xff1f;3.1 查看支持事务的存储引擎3.2 语法3.3 开启一个事务&#xff0c;执行修改后回滚3.4 开启一个事务&#xff0c;执行修改后提交3.5 保存点3.6 自动/手动提交事务 四、事务的隔离性和隔离…...

微服务划分的思考

为什么 微服务不是十全十美的,不是银弹,是什么原因导致必须要做微服务划分,是否有足够的动机支撑,是项目需要,还是领导的想法,公司层面是否有相应的规划。 拆分后的服务谁来维护,研发同学是否愿意参与 为什么,思考清楚了,接下来看还需要考虑怎么做 单体应用的不足…...

介绍XML

XML&#xff08;Extensible Markup Language&#xff0c;可扩展标记语言&#xff09;是一种用于存储、传输和交换数据的标记语言&#xff0c;由万维网联盟&#xff08;W3C&#xff09;在1998年制定。它通过自定义标签描述数据结构&#xff0c;具有平台无关性、自描述性和结构化…...

从0开始配置spark-local模式

安装Spark的过程就是下载和解压的过程。接下来的操作&#xff0c;我们把它上传到集群中的节点&#xff0c;并解压运行。 1.启动虚拟机 2.通过finalshell连接虚拟机&#xff0c;并上传安装文件到 /opt/software下 3.解压spark安装文件到/opt/module下 tar -zxvf spark-3.3.1-…...

CSS基础-即学即用 -- 笔记1

目录 前言CSS 基础1. 层叠样式表来源理解优先级源码顺序经验法则继承inherit 关键字initial 关键字 2. 相对单位em 和 rem响应式面板视口的相对单位使用vw定义字号使用calc()定义字号自定义属性&#xff08;即CSS变量&#xff09; 3. 盒模型调整盒模型 前言 只需一分钟就能学会…...

日志文件太大,如何分卷压缩便于传输

在IT系统维护和开发工作中&#xff0c;日志文件的作用举足轻重&#xff0c;它不仅记录了系统运行过程中的详细信息&#xff0c;还能帮助技术人员诊断问题、追踪事件和分析性能。 然而&#xff0c;随着系统的长期运行&#xff0c;日志文件可能会迅速膨胀&#xff0c;特别是在高…...

【Django】设置让局域网内的人访问

操作步骤 1. 命令行窗口下查询【本机ip】 ipconfig2. Django项目的全局设置【settings.py】中进行如下设置 ALLOWED_HOSTS ["本机ip"]3. 启动Django项目&#xff1a;命令行下执行如下命令 python manage.py runserver 0.0.0.0:80004. 测试效果&#xff1a;浏览器…...

智慧教室电子班牌-智能管理系统源码,‌后端‌基于Spring Boot框架,前端‌使用Vue.js框架进行组件化开发

智慧班牌系统是一种集成了多种功能的电子班牌&#xff0c;包括校园信息发布、综合素质评价、考勤管理、家校互通、教务管理、考场管理和成绩分析等。它为班级和学校提供了一个多层次、多内容的信息发布平台&#xff0c;同时也为教师、家长和学生提供了一个安全、快捷、全面的互…...

[密码学实战]密评考试训练系统v1.0程序及密评参考题库(获取路径在文末)

[密码学实战]密评考试训练系统v1.0程序及密评参考题库 引言:密评考试的重要性与挑战 商用密码应用安全性评估(简称"密评") 作为我国密码领域的重要认证体系,已成为信息安全从业者的必备技能。根据国家密码管理局最新数据,截至2024年6月,全国仅有3000余人持有…...

Vue如何获取Dom

在Vue中获取DOM元素可以通过几种方法&#xff1a;1、使用模板引用&#xff08;ref&#xff09;&#xff0c;2、使用事件绑定&#xff0c;3、使用生命周期钩子。这些方法各有优缺点&#xff0c;适用于不同的场景。本文将详细介绍这些方法的使用方式及其适用场景&#xff0c;帮助…...

AI大模型 —— 国产大模型 —— 华为大模型

有这么一句话&#xff0c;那就是AI大模型分两种&#xff0c;一种是大模型&#xff1b;另一种是华为大模型。 如果从技术角度来分析&#xff0c;华为的技术不论是在软件还是硬件都比国外的大公司差距极大&#xff0c;甚至有些技术评论者认为华为的软硬件技术至少落后2.5代&#…...

LX4-数据手册相关

数据手册相关 一 如何获取数据手册 ST官网&#xff1a;www.st.com 中文社区网&#xff1a; https://www.stmcu.com.cn/Designresource/list/STM32F1/document/datasheet 淘宝的商品详情页 二 如何阅读数据手册 芯片手册 定义&#xff1a;由芯片制造商提供&#xff0c;详细…...