音视频开发_FFmpeg基石精讲

FFmpeg 框架

核心组件

  • libavcodec:一个编解码库,包含了众多的编码器和解码器用于编码和解码音视频流。
  • libavformat:一个封装格式库,用于处理各种音视频封装格式。
  • libavutil:一个工具库,提供了常见功能的简化接口,如数学计算、内存管理等。
  • libavfilter:滤镜库,用于对音视频数据进行过滤处理。
  • libavdevice:提供了捕捉与输出多媒体设备内容的接口。
  • libswscale:用于处理图像缩放以及色彩空间转换。
  • libswresample:用于处理音频采样数据的重采样、格式转换等。

FFmpeg工具集

  • ffmpeg:此命令行工具用于快速音视频转码、封装格式转换。
  • ffplay:一个简单的媒体播放器,基于SDL和FFmpeg库。
  • ffprobe:用于分析多媒体流信息的命令行工具。

关键功能

  • 转码:转换音视频编码格式,如将AVI转换为MP4。
  • 解码:根据编码格式将数据解码为原始音视频帧。
  • 编码:将原始音视频数据编码为特定格式。
  • 封装:将编码后的音视频数据封装到指定的容器格式。
  • 流化:处理音视频数据以适合网络流传输。
  • 滤镜处理:改变音视频数据的属性,如调整大小,裁剪,去除噪点等。

在这里插入图片描述

FFmpeg 内存引用计数模型

FFmpeg中的内存引用计数模型是一个核心的内存管理机制,用于确保音视频数据(如帧、包、缓冲区等)在多个组件之间安全地共享与释放。这个机制基于引用计数,可以防止资源的提早释放或内存泄漏。

AvBufferRef

在FFmpeg中,AvBufferRef类型的引用在各种数据结构(如AVFrame, AVPacket等)中被用作指向实际数据的指针。使用这种引用计数模型能够在不同的上下文中共享相同的数据,而无需复制数据。

引用计数工作原理

  1. 初始化: 当数据被分配时,它被包装在“buffer”的数据结构中,并且引用计数设置为1。
  2. 增加引用: 当另一个组件需要使用相同的数据时,引用计数会增加。
  3. 减少引用: 当组件完成对数据的使用,它将减少引用计数。这通常通过调用av_buffer_unref()或类似的函数完成。
  4. 释放内存: 当最后一个引用av_buffer_unref()被调用时,引用计数归零,相关数据结构与其所占用的内存将被释放。

为了使这个模型有效,所有组件在处理通过引用计数共享的数据时,都必须遵守增加和减少引用的规则,这确保了内存的正确管理。

这种模型在视频解码过程中尤为重要,因为解码视频通常会产生大量的视频帧数据,如果不进行合理管理,很容易造成内存不足的问题。使用AvBufferRef,多个组件可以同时访问帧数据而不需要进行数据的复制,这既减少了延迟也节约了资源。

解复用相关 AVFormat XXX等

AVFormatContext

AVFormatContext 结构体是FFmpeg库中一个核心的结构体,用于存储媒体文件或媒体流的信息以及对它们进行操作时所需的上下文信息。

AVFormatContext 结构体中关键的成员:

  • av_class: 一个指向 AVClass 的指针,用于日志记录和avoptions。通过它可以访问类的相关信息和方法。

  • iformat: 指向一个 AVInputFormat 结构体的指针。它描述了用于读取媒体文件的解复用器。

  • oformat: 指向一个 AVOutputFormat 结构体的指针。它描述了用于写入媒体文件的复用器。

  • streams: 指向 AVStream 结构体指针数组的一个指针,存储了文件中所有媒体流的信息。

  • nb_streams: 流的数量,说明 streams 数组含有多少个元素。

  • url: 一个表示媒体文件名或流的URL的字符串。

  • pb: 指向 AVIOContext 的一个指针,用于输入输出操作的抽象。

  • duration: 媒体文件的总时长。

  • bit_rate: 总比特率。

  • packet_size: 数据包的大小。

  • max_delay: 最大延迟。

  • flags: 各种标志,定义了上下文的额外属性。

  • probesize: 在读取流信息时确定要探测多少字节。

  • max_analyze_duration: 在读取流信息时设置最大分析时长。

  • metadata: 指向 AVDictionary 的指针,包含了文件的元数据,例如标题、作者、专辑等信息。

  • start_time: 流的开始时间。

  • pb: 指向一个 AVIOContext 结构体的指针,它表示内部I/O上下文,用于读写文件。

这些成员提供了对媒体文件和流的综合管理,包括读写、寻找、元数据处理和流信息获取等。

AVInputFormat

AVInputFormat结构体在FFmpeg中定义了一个特定媒体文件输入格式的解复用器(demuxer)接口。它包含了一系列的函数指针和变量,这些成员用于实现解复用的各个阶段功能,如打开文件、读取帧内容、寻找流信息等。

AVInputFormat结构体中的关键成员:

  • name: 指向一个字符串的指针,用来表示输入格式的名称,比如 “mp4” 或 “mpegts”。

  • long_name: 一个较为详细的格式描述,它通常是格式的完整名称。

  • flags: 标识输入格式的能力和限制,这可能包括对自定义IO支持、对查找操作的支持等。

  • extensions: 支持的文件扩展名,使用逗号分隔的字符串列表。

  • mime_type: 与输入格式相关的MIME类型。

  • priv_data_size: 针对此输入格式的私有数据结构的大小。

  • read_probe: 函数指针,用于探测输入格式是否支持处理给定的数据。

  • read_header: 函数指针,用于读取媒体文件的头部信息,设置AVFormatContext结构的其他成员。

  • read_packet: 函数指针,用于从媒体中读取一帧数据。

  • read_close: 函数指针,用于关闭解复用器并清理资源。

  • read_seek: 函数指针,用于支持在媒体文件中查找。

  • read_timestamp: 函数指针,用于获取特定位置的时间戳。

  • priv_class: 指向AVClass结构体的指针,用于支持私有选项设置。

AVInputFormat为不同的媒体文件类型提供了一组标准化的解复用API。不同的文件格式实现了不同的AVInputFormat实例,FFmpeg使用这些实例来实现对多种文件格式的支持。当用户打开一个媒体文件时,FFmpeg将会根据文件扩展名、文件内容等来选择合适的AVInputFormat结构体实例,以进行数据的解复用处理。

AVStream

AVStream结构体是FFmpeg中用于存储与特定媒体流(如视频流、音频流)相关的信息。它包含了一系列关键成员,这些成员提供了流的元数据和其他必要的信息,用于解复用和解码等操作。

AVStream结构体中的关键成员:

  • index: 流的索引编号,根据它在AVFormatContextstreams数组中的位置来确定。

  • id: 流的ID,用于在文件格式中识别流。

  • codecpar: 指向AVCodecParameters结构体的指针,包含了流的编解码器参数,如编解码器类型、视频的宽高、采样率等。

  • time_base: 流的时间基准,表示时间戳与实际时间的转换关系。这是一个AVRational类型的比率值,包含分子和分母。

  • start_time: 流中第一个可解码的帧的演示时间戳(Presentation Timestamp,PTS),以time_base为单位的。

  • duration: 该流在时间基准time_base单位下的总持续时间。

  • nb_frames: 流中的帧数,如果可知的话。

  • codec: (在新版FFmpeg中不建议使用,用codecpar代替)指向与流关联的AVCodecContext结构体,包含了所有与编解码器相关的详细信息和操作。

  • avg_frame_rate: 平均帧率,用AVRational类型表示。

  • r_frame_rate: 实际帧率,通常用于视频流。

  • disposition: 流的一些附加属性,例如是否有默认音频或是字幕。

  • metadata: 指向一个AVDictionary结构,包含了关于流的元数据键值对,例如语言或标题。

  • side_data: 一个指向AVPacketSideData数组的指针,存储了和流相关但不属于常规数据包的一些附加信息。

常见解复用操作

以下是使用FFmpeg进行解复用操作可能进行的一些步骤:

  1. 打开媒体文件:使用avformat_open_input函数打开输入文件,并创建AVFormatContext
  2. 读取流信息:调用avformat_find_stream_info函数获取媒体文件中的流信息。
  3. 查找音视频流:检查AVFormatContext中的AVStream来识别各个音视频流。
  4. 读取数据包:通过av_read_frame循环读取媒体文件中的数据包。
  5. 关闭输入:使用avformat_close_input清理并关闭AVFormatContext

例:

下面是一个解复用过程的代码片段:

AVFormatContext *fmt_ctx = NULL;
if (avformat_open_input(&fmt_ctx, "input.mp4", NULL, NULL) < 0) {
    // 打开文件失败
}

// 读取媒体文件信息
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
    // 读取流信息失败
}

// 查找第一个视频流
AVStream *video_stream = NULL;
for (int i = 0; i < fmt_ctx->nb_streams; i++) {
    if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
        video_stream = fmt_ctx->streams[i];
        break;
    }
}

// 读取数据包
AVPacket pkt;
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
    // 判断数据包是不是视频流的一部分
    if (pkt.stream_index == video_stream->index) {
        // 你可以在这里处理视频数据包
    }
    av_packet_unref(&pkt);
}

// 关闭输入
avformat_close_input(&fmt_ctx);

编解码相关 AVCodec XXX等

AVCodec

AVCodec:代表一个编解码器,描述了编解码器的相关操作如打开、关闭、编解码等。

AVCodec 的一些关键成员:

  • name:编解码器的名称,用以表征编解码器的内容(例如 “h264”、“aac” 等)。
  • long_name:编解码器的长名称,用于更详尽地描述编解码器(例如 “H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10”)。
  • type:编解码器的类型,表示它是视频编解码器、音频编解码器还是字幕编解码器,类型为 AVMediaType 枚举中的一个值。
  • id:编解码器的特定ID,对应于 AVCodecID 枚举中

AVCodecContext

AVCodecContext:提供了编解码的上下文,包含了一系列进行编解码所需的参数和设置。

AVCodecContext 的一些关键成员:

  • codec_id:代表了使用的编解码器的 AVCodecID
  • codec_type:媒体类型(视频、音频、字幕等),对应 AVMediaType
  • codec:指向实际的编解码器的指针。
  • bit_rate:码率,表示编解码的比特率。
  • widthheight:对于视频流,分别表示视频的宽和高。
  • sample_aspect_ratio:表示视频像素的宽高比。
  • pix_fmt:对于视频流,表示像素格式(AVPixelFormat)。
  • sample_fmt:对于音频流,表示样本格式(AVSampleFormat)。
  • sample_rate:对于音频流,表示采样率。
  • channel_layout:对于音频流,表示通道布局。
  • channels:对于音频流,表示通道数量。
  • time_base:时间基准,用于时间戳的转换。
  • gop_size:关键帧间的最大帧数。
  • max_b_frames:B帧的最大数量。
  • profile:编解码器使用的配置文件。
  • level:编解码器级别。
  • delay:编解码的延迟。
  • priv_data:指向编解码器私有数据的指针。
  • flags:各种标志,控制编解码过程中的选项(例如:是否进行帧间预测)。
  • extradataextradata_size:一些编解码器要求的额外数据和其大小。

AVCodecParameters

AVCodecParameters:包含了流的编解码相关参数,如编解码器的ID、比特率、帧率、分辨率等。

AVCodecParameters 结构体的关键成员包括:

  • codec_type:此流的媒体类型,例如视频、音频或字幕。
  • codec_id:编解码器的标识符,指定了使用哪种编解码器。
  • codec_tag:四字节码(fourcc),用来表示媒体的编码格式。
  • bit_rate:平均码率(比特/秒)。
  • format:对于视频流,表示像素格式;对于音频流,表示音频样本格式(sample format)。
  • widthheight:视频流的宽和高。
  • field_order:视频的字段排序(如逐行、交错等)。
  • color_rangecolor_primariescolor_trccolor_spacechroma_location:视频的色彩相关参数。
  • video_delay:视频流中的初始延迟帧数。

对于音频流,AVCodecParameters 还包括:

  • channel_layout:指明了音频流通道的布局。
  • channels:通道数。
  • sample_rate:音频采样率。
  • block_align:音频流中单个样本的字节数。
  • frame_size:音频帧的大小,对于固定帧率音频编码是一致的。

压缩数据 AVPacket

AVPacket 是 FFmpeg 中用来存储压缩数据(例如一个视频帧或者一个音频帧)的数据结构。它包含了编解码器所需的压缩数据,并附带时间戳、持续时间以及其他编解码过程中必须的元数据。

AVPacket 结构体的关键成员包括:

  • pts(Presentation Time Stamp):展示时间戳,表示这个数据包应该被展示的时间。它是基于流的 time_base 表达的。
  • dts(Decoding Time Stamp):解码时间戳,用于指定数据包解码的顺序。对于没有B帧的简单流,ptsdts 相同。
  • duration:数据包的持续时间,基于流的 time_base
  • data:指向存储压缩数据的实际字节序列的指针。
  • sizedata 指向的数据的大小,以字节为单位。
  • stream_index:这个 AVPacket 从属的流的索引,用于从 AVFormatContext 中识别出相应的流。
  • flags:包括一些标志位,比如是否是关键帧(AV_PKT_FLAG_KEY)。
  • side_data:一个指向额外数据数组的指针,以及这个数组中的元素数量。额外数据用于传输不在主要数据流中的其他信息,例如颜色空间信息、HDR元数据等。
  • pos:这个 AVPacket 在媒体文件中的字节位置,有助于调试或者定位。

通过 AVPacket,FFmpeg 可以将压缩数据从编码器传输到多路复用器(muxer)或从解复用器(demuxer)传输到解码器,同样也用于过滤器之间的数据传递。

未压缩数据 AVFrame

AVFrame 结构体在 FFmpeg 库中用于存储未压缩的数据,比如解码后的视频帧或音频样本。它是媒体处理中一个非常重要的组成部分,尤其是在解码、转码和过滤等操作中。

下面是 AVFrame 结构体的一些关键成员:

  • data:这是一个指针数组,用于存储实际的音视频帧数据。对于视频来说,data[0]data[1]data[2] 通常分别用于存储 Y、U、V 组件(对于 YUV 格式的视频)。对于音频来说,这个数组中的每个指针对应一个声道的样本数据。
  • linesize:这个整数数组存储了每个数据平面的步长(每行的字节数)。这对于视频帧是必须的,因为图像行不一定是紧凑排列的。
  • extended_data:这是 data 数组的一个扩展版本,它对于包含更多声道数据的平面格式音频尤其有用。
  • widthheight:对于视频帧,这代表了图像的宽度和高度。
  • nb_samples:对于音频帧,这表示帧中含有的样本数量。
  • format:对视频来说,这是一个指明像素格式(AVPixelFormat)的枚举值;对音频来说,这是一个指明样本格式(AVSampleFormat)的枚举值。
  • key_frame:一个标志,指示这个帧是否是关键帧。
  • pts:表示这个帧的演示时间戳,基于编解码器上下文的 time_base
  • best_effort_timestamp:解码器设置的最佳尝试时间戳,这有助于无 pts 的情况下估算实际的时间戳。
  • pkt_duration:基于流的 time_base,这个帧的持续时间。
  • pkt_pos:帧原始数据在媒体文件中的位置,用于调试。
  • channel_layout:对于音频帧,指示声道布局。
  • channelssample_rate:音频帧的声道数和样本率。
  • metadata:帧相关的元数据。

AVFrame 通常用在视频/音频解码器的输出端或编码器的输入端。它提供了一个通用并且灵活的方式来处理未压缩的音视频数据。

FFmpeg 面向对象思想

封装(Encapsulation)

FFmpeg 中的数据结构像 AVCodecContext, AVFrame, AVPacket 等封装了与编解码器、数据帧和数据包相关的状态和行为。对这些结构体的操作通常通过 API 函数进行,而不是直接访问内部成员,这类似于面向对象中的封装概念。

继承(Inheritance)

虽然 C 不支持正式的继承,FFmpeg 使用了指针来模拟继承。例如,所有的解码器(AVCodec)都有共同的函数和成员,但也可以定义额外的成员来扩展基本功能,类似于在面向对象编程中的基类和派生类概念。

多态(Polymorphism)

FFmpeg 通过函数指针在结构体中实现了多态。比如 AVCodec 结构体中包含多个函数指针,编解码器可以通过设置这些指针到特定函数来定义特定的行为。例如,不同的编解码器可以有不同的 encode2decode 函数实现。这使得代码可以在运行时根据不同编解码器的具体实现选择正确的函数来调用。

抽象(Abstraction)

FFmpeg 抽象出了一套 API,隐藏了底层的复杂实现细节,提供了相对简单的接口供开发者使用。例如,不管背后具体是什么编解码器,开发者都可以通过统一的 avcodec_open2avcodec_decode_video2avcodec_encode_audio2 等函数来执行操作。

总而言之,即使 FFmpeg 是用 C 语言编写的,它也在设计上模拟了一些 OOP 的概念,提高了代码的模块性、可读性和可维护性。然而,需要注意的是,这种模拟并不等同于真正的面向对象编程语言中的实现,如 C++,其中有对继承、多态、封装等特性的原生支持。

Packet/Frame 数据零拷贝

“零拷贝”(Zero-Copy)是一种优化技术,旨在降低数据传输过程中的CPU消耗,减少内存使用,降低延迟。在处理 AVPacketAVFrame 数据时,零拷贝的目的是尽可能减少数据从一个缓冲区到另一个缓冲区的复制操作。

如何实现零拷贝:

  1. 引用计数(Reference Counting): FFmpeg 为 AVFrameAVPacket 结构提供了引用计数机制。通过增加引用计数来“共享”数据而不实际复制数据,这可以通过使用 av_frame_refav_packet_ref 函数来实现。

  2. 直接缓冲区访问(Direct Buffer Access): 当解码器或编码器处理数据时,而不需要真正的数据所有权转移,它可以直接在原始缓冲区上操作,通过提供数据的指针而不是数据本身的副本。

  3. 自定义缓冲区分配(Custom Buffer Allocation): 通过接管缓冲区的分配和释放,用户可以控制数据的存储方式,例如,可以重用或池化 buffers 来减少频繁的内存分配。

  4. 内存映射(Memory Mapped I/O): 在适当的硬件和操作系统支持下,可以直接映射文件或设备内存到进程的地址空间,从而避免了数据在内核和用户空间之间的拷贝。

FFmpeg 中零拷贝的例子:

  • 解码器零拷贝:某些解码器支持零拷贝解码,即直接在 GPU 的内存中解码视频帧,然后通过硬件加速接口如 VDPAU, DXVA2, 或 VideoToolbox 将帧传递给显示或者进一步处理。

  • 过滤器零拷贝:FFmpeg 的过滤器图可以被配置为在过滤器之间传递 AVFrame 的引用而非数据副本。

  • 硬件加速:使用 FFmpeg 的硬件加速API(如 AVHWDeviceContext 和 AVHWFramesContext)可以实现数据在硬件加速的解码器和编码器间的零拷贝传输。

参考资料:

音视频流媒体开发课程(从基础到高级,从理论到实践)学习计划、一对一答疑
音视频开发(FFmpeg/WebRTC/RTMP)

整理了一些音视频开发学习资料、面试题 如有需要自行添加群:739729163 领取

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

交互式QGraphicsView(平移/缩放/旋转)

一 简述 Graphics View提供了一个平台&#xff0c;用于大量自定义 2D 图元的管理与交互&#xff0c;框架包括一个事件传播架构&#xff0c;支持场景 Scene 中的图元 Item 进行精确的双精度交互功能。Item 可以处理键盘事件、鼠标按下、移动、释放和双击事件&#xff0c;同时也…

SAP-MM-设置字段默认值

当我们创建订单时&#xff0c;有些字段总是重复输入&#xff0c;每次值也是固定的&#xff0c;例如生产订单 如上图“生产工厂都是1000”如何设置成默认每次进入都是1000呢&#xff1f; 点击字段&#xff0c;F1 查看参数ID“WRK” 输入tcode&#xff1a;SU3 按上图维护数据100…

Quartz完全开发手册(一篇学会Quartz所有知识点)

目录 一、Quartz概念 1.1、Quartz介绍 1.2、使用场景 1.3、特点 二、Quartz运行环境 三、Quartz设计模式 四、Quartz学习的核心概念 4.1、任务Job 4.2、触发器Trigger 4.3、调度器Scheduler 五、Quartz的体系结构与工作流程 5.1、体系结构 5.2、工作流程 六、Quar…

Python Flask框架 -- 模版继承

一个网站中&#xff0c;大部分网页的模块是重复的&#xff0c;比如顶部的导航栏&#xff0c;底部的备案信息。如果在每个页面中都重复的去写这些代码&#xff0c;会让项目变得臃肿&#xff0c;提高后期维护成本。比较好的做法是&#xff0c;通过模板继承&#xff0c;把一些重复…

SpringBoot-04 | spring-boot-starter-logging原理原理

SpringBoot-04 | spring-boot-starter-logging原理原理 第一步&#xff1a;springboot加载factories文件第二步&#xff1a;构造监听器第三步&#xff1a;注册监听器到Spring中第四步&#xff1a;开始加载日志框架第五步&#xff1a;加载日志框架logback-spring.xml第六步&…

全域电商数据实现高效稳定大批量采集♀

全域电商&#xff0c;是近几年的新趋势&#xff0c;几乎所有商家都在布局全域&#xff0c;追求全域增长。但商家发现&#xff0c;随着投入成本的上涨&#xff0c;利润却没有增加。 其中最为突出的是——商家为保证全域数据的及时更新&#xff0c;通过堆人头的方式完成每日取数任…

【应用笔记】LAT1305+使用STM32+TT类型IO的注意事项

1. 概述 在 STM32 系列 MCU 中&#xff0c; 除了一些特殊管脚外&#xff0c;绝大多数管脚都可以分类为 FT (兼容5V 信号)或 TT&#xff08;兼容 3V3 信号&#xff09;类型的 IO&#xff0c;由于 MCU 内部设计的不同&#xff0c; TT IO 相比 5V IO 有更多的限制&#xff0c;下面…

I2C协议

一.硬件连接 I2C必须使用开漏&#xff08;或集电极开路&#xff09;的引脚&#xff0c;其引脚框图如下所示。 SCL0对应78K0的P6.0引脚&#xff0c;SDA0对应78K0的P6.1引脚。 在使用开漏引脚通信时&#xff0c;需注意如下事项&#xff1a; 1&#xff09;两条总线须外接…

国产之光?Kimichat大模型200万字超长上下文突破

Kimi Chat简介 Kimi是AI大模型初创企业月之暗面&#xff08;Moonshot&#xff09;推出的AI产品。近日月之暗面宣布Kimi 智能助手在长上下文窗口技术上再次取得突破&#xff0c;无损上下文长度提升了一个数量级到200万字。 月之暗面&#xff08;Moonshot AI&#xff09;&#…

保姆级系列教程-玩转Fiddler抓包教程(1)-HTTP和HTTPS基础知识

2024软件测试面试刷题&#xff0c;这个小程序&#xff08;永久刷题&#xff09;&#xff0c;靠它快速找到工作了&#xff01;&#xff08;刷题APP的天花板&#xff09;【持续更新最新版】-CSDN博客 1.简介 有的小伙伴或者童鞋们可能会好奇地问&#xff0c;不是讲解和分享抓包…

CI/CD实战-jenkins部署 3

安装 软件下载地址&#xff1a;Index of /jenkins/redhat/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 启动服务 安装推荐插件 不新建用户&#xff0c;使用admin账号登录 修改一下初始密码 新建项目测试 安装git命令 生成密钥 在gitlab中上传公钥 修改ssh 创建中…

babel主要内容

定义 babel是一个编译工具 &#xff0c;用于把JSX等编译成浏览器可执行的javascript。 主要内容是几个包babel/parser 这个包主要是用于解析代码到AST树babel/types 这个包中有一堆API&#xff0c;用于手动创建ASTbabel/traverse 这个包主要是为了遍历AST树&#xff0c;结合具体…

C/C++代码性能优化——编程实践

1. 编程实践 在一些关键的地方&#xff0c;相应的编程技巧能够给性能带来重大提升。 1.1. 参数传递 传递非基本类型时&#xff0c;使用引用或指针&#xff0c;这样可以避免传递过程中发生拷贝。参数根据是否需要返回&#xff0c;相应加上const修饰&#xff0c;代码更安全&am…

硬盘、内存、缓存(CPU)和寄存器 空间大小与存取速度的区别及设计原理

一、寄存器和存储器是不同的 很多人会将 寄存器 与 存储器 二者混淆&#xff0c;认为它们是同一个东西。但并不是&#xff01;&#xff01; 寄存器是CPU上的一个模块 存储器是 内存硬盘的统称 二、存取速度的比较 CPU(包含寄存器&#xff0c;缓存) > 内存 > 硬盘 内…

浅谈Postman与Jmeter的区别、用法

前阶段做了一个小调查&#xff0c;发现软件测试行业做功能测试和接口测试的人相对比较多。在测试工作中&#xff0c;有高手&#xff0c;自然也会有小白&#xff0c;但有一点我们无法否认&#xff0c;就是每一个高手都是从小白开始的&#xff0c;所以今天我们就来谈谈一大部分人…

【TD3思路及代码】【自用笔记】

1 组成&#xff08;Target Network Delayed Training&#xff09; Actor网络&#xff1a;这个网络负责根据当前的状态输出动作值。在训练过程中&#xff0c;Actor网络会不断地学习和优化&#xff0c;以输出更合适的动作。Critic网络&#xff1a;TD3中有两个Critic网络&#xff…

2024Postman中变量的使用!

Postman中可设置的变量类型有全局变量&#xff0c;环境变量&#xff0c;集合变量&#xff0c;数据变量及局部变量。区别则是各变量作用域不同&#xff0c;全局变量适用于所有集合&#xff0c;环境变量适用于当前所选环境&#xff08;所有集合中均可使用不同环境变量&#xff09…

重磅|国家能源局开展配电网安全风险管控重点行动

据国家能源局3月21日消息&#xff0c;为紧扣新形势下电力保供和转型目标&#xff0c;聚焦配电网安全运行、供电保障、防灾减灾和坚强可靠等方面安全风险&#xff0c;推动解决城乡配电网发展薄弱等问题&#xff0c;全面提升配电网供电保障和综合承载能力&#xff0c;国家能源局决…

Mysql数据库:索引管理

目录 一、索引的概述 1、索引的概念 2、索引的作用 3、索引的副作用 4、创建索引的原则依据 5、索引优化 6、索引的分类 7、数据文件与索引文件 二、管理数据库索引 1、查询索引 2、创建索引 2.1 创建普通索引 2.2 创建唯一索引 2.3 创建主键索引 2.4 创建组合…

Xinstall让App推广变得高效而简单

随着移动互联网的迅猛发展&#xff0c;App已成为人们生活中不可或缺的一部分。然而&#xff0c;对于众多开发者和广告主来说&#xff0c;如何高效地推广自己的App&#xff0c;却一直是一个令人头疼的问题。今天&#xff0c;我们要为大家介绍的&#xff0c;正是国内专业的App全渠…
最新文章