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

ffmpeg音视频开发从入门到精通——ffmpeg 视频数据抽取

文章目录

  • FFmpeg视频处理工具使用总结
    • 环境配置
    • 主函数与参数处理
    • 打开输入文件
    • 获取流信息
    • 分配输出文件上下文
    • 猜测输出文件格式
    • 创建视频流并设置参数
    • 打开输出文件并写入头信息
    • 读取、转换并写入帧数据
    • 写入尾信息并释放资源
    • 运行程序
    • 注意事项
    • 源代码

FFmpeg视频处理工具使用总结

环境配置

  • 在C++程序中使用FFmpeg之前,需要包含相应的头文件,并根据是否使用C++编译器,可能需要添加extern "C"块。在C++中,当包含C语言的头文件时,需要使用extern "C"来告诉编译器这是一个C语言的函数,避免C++的名称修饰导致链接错误。这个例子中,包含了FFmpeg库的头文件,用于处理多媒体文件。
  • 在C++中,当包含C语言的头文件时,需要使用extern "C"来告诉编译器这是一个C语言的函数,避免C++的名称修饰导致链接错误。
#ifdef __cplusplus
extern "C" {
#endif
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/log.h>
#ifdef __cplusplus
}
#endif

主函数与参数处理

程序入口点是main函数,它处理命令行参数并设置日志级别。

  • 检查传入的参数个数是否大于等于3,如果参数个数小于3,就输出错误信息并退出程序。

  • 将第一个参数赋值给变量src,将第二个参数赋值给变量dst,这样就得到了输入文件路径和输出文件路径。

  • 调用av_log_set_level函数设置日志级别为AV_LOG_DEBUG,这样在程序执行过程中会打印出调试级别的日志信息。

int main(int argc, char *argv[]) {// 参数检查if (argc < 3) {av_log(nullptr, AV_LOG_ERROR, "Usage: %s <input file> <output file>\n", argv[0]);exit(-1);}// 输入输出文件路径char *src = argv[1];char *dst = argv[2];// 设置日志级别av_log_set_level(AV_LOG_DEBUG);
}

打开输入文件

使用avformat_open_input打开输入文件,并检查返回值。avformat_open_input是libavformat库中的一个函数,用于打开一个输入文件并初始化输入上下文。
输入参数如下:

  1. AVFormatContext **ps:指向要初始化的AVFormatContext指针的指针。函数将分配一个AVFormatContext结构并将其指针保存在该参数指向的地址中。
  2. const char *url:输入文件的URL或文件名。
  3. AVInputFormat *fmt:强制指定要使用的输入格式。如果为NULL,则函数将根据输入文件的扩展名自动选择适当的格式。
  4. AVDictionary **options:一个指向AVDictionary结构指针的指针,用于设置差异化选项。可以使用该参数来设置例如输入缓冲区大小、超时值等选项。
  5. int (*interrupt_callback)(void):设置中断回调函数。如果输入操作需要中断,则调用此回调函数。如果为NULL,则不设置中断回调。

函数执行成功后,ps将指向已初始化的AVFormatContext结构,可以使用该结构来进行后续的输入操作。执行失败时,ps将保持不变,而函数将返回一个负值以表示错误原因。

int ret = avformat_open_input(&pFormatCtx, src, nullptr, nullptr);
if (ret < 0) {av_log(nullptr, AV_LOG_ERROR, "Could not open input file: %s\n", src);exit(-1);
}

获取流信息

调用av_find_best_stream找到最佳的视频流。
av_find_best_stream是FFmpeg库中的一个函数,用于查找最佳的流索引。它的定义如下:

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

参数说明如下:

  1. ic:指向AVFormatContext的指针,表示输入的封装格式上下文。
  2. type:表示所需流的媒体类型,可以是AVMEDIA_TYPE_AUDIOAVMEDIA_TYPE_VIDEOAVMEDIA_TYPE_SUBTITLE
  3. wanted_stream_nb:表示所需流的索引号。
  4. related_stream:表示关联的流的索引号。通常设置为负值,表示没有关联的流。
  5. decoder_ret:指向AVCodec指针的指针,用于返回找到的解码器。
  6. flags:表示查找流的标志位,可以是AVFMT_FLAG_NOFILEAVFMT_FLAG_GENPTS等。

函数返回值为找到的流的索引号,如果未找到则返回负值错误代码。

这个函数的主要功能是根据指定的媒体类型和索引号,在输入的封装格式上下文中查找最佳的流索引。它会根据一些条件(如流的媒体类型、时间基等)进行评估,然后返回找到的最佳流索引,并通过decoder_ret参数返回对应的解码器。av_find_best_stream是FFmpeg库中的一个函数,用于查找最佳的流索引。它的定义如下:

ret = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
if (ret < 0) {av_log(nullptr, AV_LOG_ERROR, "Failed to retrieve input stream information\n");goto _ERROR;
}

分配输出文件上下文

使用avformat_alloc_context分配输出文件的格式上下文。

avformat_alloc_context是FFmpeg中的一个函数,用于分配一个AVFormatContext结构体,并初始化其成员变量。

输入参数为void。avformat_alloc_context是FFmpeg中的一个函数,用于分配一个AVFormatContext结构体,并初始化其成员变量。

输入参数为void。

oFormatCtx = avformat_alloc_context();
if (oFormatCtx == nullptr) {av_log(nullptr, AV_LOG_ERROR, "Failed to allocate output context\n");goto _ERROR;
}

猜测输出文件格式

使用av_guess_format猜测输出文件的格式。
av_guess_format是FFmpeg库中的一个函数,用于猜测输入参数的格式。它的输入参数包括:

  1. const char *short_name:输入参数的短名称。这是一个字符串,通常是文件的扩展名或格式的简称。
  2. const char *filename:输入参数的文件名。这是一个字符串,指定要处理的文件路径。
  3. const char *mime_type:输入参数的MIME类型。这是一个字符串,指定要处理的媒体类型。

这些输入参数可根据实际需求来选择设置,也可以通过设置为NULL来忽略某些参数。根据提供的输入参数,av_guess_format函数会尝试猜测并返回最有可能的格式。

注意:在使用av_guess_format函数时,应确保FFmpeg库已正确初始化,并且所需的输入参数有效且符合可接受的格式。av_guess_format是FFmpeg库中的一个函数,用于猜测输入参数的格式。它的输入参数包括:

  1. const char *short_name:输入参数的短名称。这是一个字符串,通常是文件的扩展名或格式的简称。
  2. const char *filename:输入参数的文件名。这是一个字符串,指定要处理的文件路径。
  3. const char *mime_type:输入参数的MIME类型。这是一个字符串,指定要处理的媒体类型。

这些输入参数可根据实际需求来选择设置,也可以通过设置为NULL来忽略某些参数。根据提供的输入参数,av_guess_format函数会尝试猜测并返回最有可能的格式。

注意:在使用av_guess_format函数时,应确保FFmpeg库已正确初始化,并且所需的输入参数有效且符合可接受的格式。

outFmt = av_guess_format(nullptr, dst, nullptr);
if (outFmt == nullptr) {av_log(nullptr, AV_LOG_ERROR, "Failed to guess output format\n");goto _ERROR;
}
oFormatCtx->oformat = outFmt;

创建视频流并设置参数

为输出文件创建视频流,并复制输入视频流的参数。

outStream = avformat_new_stream(oFormatCtx, nullptr);
avcodec_parameters_copy(outStream->codecpar, pFormatCtx->streams[ret]->codecpar);
outStream->codecpar->codec_tag = 0;

打开输出文件并写入头信息

使用avio_open2打开输出文件,并使用avformat_write_header写入文件头信息。
avio_open2 是用于打开一个输入输出数据流的函数,它的输入参数包括:

  • AVIOContext **s:指向用于输入输出的 AVIOContext 结构体的指针。
  • const char *filename:输入输出的文件名或者URL地址,使用 “r” 模式打开用于输入,使用 “w” 模式打开用于输出。
  • int flags:打开文件的参数,可以是 AVIO_FLAG_READ 表示输入流、AVIO_FLAG_WRITE 表示输出流、AVIO_FLAG_READ_WRITE 表示输入输出流。
  • const AVIOInterruptCB *int_cb:输入输出中断回调函数的指针。
  • AVDictionary **options:用于传递其他选项的字典指针。可以设置 NULL 以忽略其他选项。

avformat_write_header 是用于写入文件头信息的函数,它的输入参数包括:

  • AVFormatContext *s:指向 AVFormatContext 结构体的指针,表示待写入文件的格式上下文。
  • AVDictionary **options:用于传递其他选项的字典指针。可以设置 NULL 以忽略其他选项。

这些函数用于打开输入输出数据流和写入文件头信息时,需要通过传入一些参数来配置打开的流和文件的属性和选项。avio_open2 是用于打开一个输入输出数据流的函数,它的输入参数包括:

ret = avio_open2(&oFormatCtx->pb, dst, AVIO_FLAG_WRITE, nullptr, nullptr);
if (ret < 0) {av_log(nullptr, AV_LOG_ERROR, "Failed to open output file: %s\n", dst);goto _ERROR;
}
ret = avformat_write_header(oFormatCtx, nullptr);
if (ret < 0) {av_log(nullptr, AV_LOG_ERROR, "Failed to write output file header\n");goto _ERROR;
}

读取、转换并写入帧数据

读取输入文件的视频帧,转换时间戳,并使用av_interleaved_write_frame写入输出文件。
av_interleaved_write_frame函数是FFmpeg库中的一个函数,用于将音视频数据包写入容器文件。

函数的参数如下:

  1. AVFormatContext *s: AVFormatContext结构体指针,表示容器格式上下文,用于管理容器格式相关的信息。

  2. AVPacket *pkt: AVPacket结构体指针,表示音视频数据包,包含音视频数据以及相关的参数信息。

函数的返回值为整形,表示函数的执行结果。如果返回值为0,则表示成功写入数据包;如果返回值为负值,则表示写入失败。

注意:在调用av_interleaved_write_frame函数之前,需要先调用avformat_write_header函数来写入容器文件的头部信息;在所有音视频数据包写入完成后,还需要调用av_write_trailer函数来写入容器文件的尾部信息。

此外,av_interleaved_write_frame函数只能用于写入已经交错存储的音视频数据包,如果数据包未经过交错处理,则需要使用av_write_frame函数来分别写入音频数据包和视频数据包。av_interleaved_write_frame函数是FFmpeg库中的一个函数,用于将音视频数据包写入容器文件。

while (av_read_frame(pFormatCtx, &pkt) >= 0) {if (pkt.stream_index == ret) {// 转换时间戳等pkt.pts = av_rescale_q_rnd(pkt.pts, inSteam->time_base, outStream->time_base, AV_ROUND_NEAR_INF);pkt.dts = av_rescale_q_rnd(pkt.dts, inSteam->time_base, outStream->time_base, AV_ROUND_NEAR_INF);pkt.duration = av_rescale_q(pkt.duration, inSteam->time_base, outStream->time_base);// 写入帧数据av_interleaved_write_frame(oFormatCtx, &pkt);}av_packet_unref(&pkt);
}

写入尾信息并释放资源

使用av_write_trailer写入文件尾信息,并释放所有资源。
函数av_write_trailer的参数是AVFormatContext。

AVFormatContext是一个存储了整个音视频文件信息的结构体,包含了音视频流、容器格式信息以及封装器相关的信息。

av_write_trailer函数的功能是将容器头信息写入到输出文件中,并完成文件封装的最后步骤。具体而言,它会将封装器中剩余的音视频数据写入到输出文件中,并更新容器头的相关信息,如文件大小、时长等。

在调用av_write_trailer函数之前,需要保证所有的音视频数据已经被写入到容器中,否则可能会导致文件不完整或者损坏。

调用av_write_trailer函数之后,应释放AVFormatContext相关的资源,包括关闭文件和释放相关的内存。

示例代码如下:

AVFormatContext* outputContext = nullptr;
// 初始化outputContext的代码
// ...
// 写入所有音视频数据到容器
// ...
av_write_trailer(outputContext);
// 释放相关资源
avformat_close_input(&outputContext);
avformat_free_context(outputContext);

函数av_write_trailer的参数是AVFormatContext。

AVFormatContext是一个存储了整个音视频文件信息的结构体,包含了音视频流、容器格式信息以及封装器相关的信息。

av_write_trailer函数的功能是将容器头信息写入到输出文件中,并完成文件封装的最后步骤。具体而言,它会将封装器中剩余的音视频数据写入到输出文件中,并更新容器头的相关信息,如文件大小、时长等。

在调用av_write_trailer函数之前,需要保证所有的音视频数据已经被写入到容器中,否则可能会导致文件不完整或者损坏。

调用av_write_trailer函数之后,应释放AVFormatContext相关的资源,包括关闭文件和释放相关的内存。

示例代码如下:

AVFormatContext* outputContext = nullptr;
// 初始化outputContext的代码
// ...
// 写入所有音视频数据到容器
// ...
av_write_trailer(outputContext);
// 释放相关资源
avformat_close_input(&outputContext);
avformat_free_context(outputContext);
av_write_trailer(oFormatCtx);_ERROR:
// 清理资源
if (oFormatCtx && oFormatCtx->pb) {avio_close(oFormatCtx->pb);oFormatCtx->pb = nullptr;
}
if (oFormatCtx) {avformat_free_context(oFormatCtx);oFormatCtx = nullptr;
}
if (pFormatCtx) {avformat_free_context(pFormatCtx);pFormatCtx = nullptr;
}

运行程序

程序需要传入两个参数:输入文件路径和输出文件路径。例如:

./my_ffmpeg_tool input.mp4 output.mkv

确保替换为您的实际文件名和所需的输出格式。

注意事项

  • 确保FFmpeg开发库已正确安装且可链接。
  • 检查程序输出的错误信息以进行调试。
  • 程序可能需要适当的读取和写入权限。

源代码

  • cmake 源文件
cmake_minimum_required(VERSION 3.27)
project(FFmpeg_exercise)
set(CMAKE_CXX_STANDARD 14)# 定义FFmpeg的安装路径变量
set(FFMPEG_INSTALL_DIR "/usr/local/ffmpeg")# 将FFmpeg的头文件目录添加到包含路径
include_directories(${FFMPEG_INSTALL_DIR}/include)# 定义FFmpeg库的基础名称(根据你的需要调整)
set(FFMPEG_LIBS "avcodec;avformat;avutil") # 用分号分隔库名# 寻找并链接FFmpeg库
foreach(FFMPEG_LIB ${FFMPEG_LIBS})find_library(${FFMPEG_LIB}_LIBRARY NAMES ${FFMPEG_LIB}PATHS ${FFMPEG_INSTALL_DIR}/lib NO_DEFAULT_PATH)list(APPEND FFMPEG_LIBRARIES ${${FFMPEG_LIB}_LIBRARY})
endforeach()add_executable(FFmpeg_exercise# main.cpp# extra_audic.cppextra_video.cpp)
# 链接FFmpeg库
target_link_libraries(FFmpeg_exercise ${FFMPEG_LIBRARIES})
  • cpp
//
// Created by 陈伟峰 on 2024/6/22.
//
#ifdef __cplusplus
extern "C" {
#endif
// 包含FFmpeg的头文件
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/log.h>
#ifdef __cplusplus}
#endif
#include <iostream>int main(int argc,char *argv[]){int ret {-1};int idx {-1};//1.处理一些参数char *src {nullptr};char *dst {nullptr};AVFormatContext *pFormatCtx {nullptr};AVFormatContext *oFormatCtx {nullptr};AVOutputFormat *outFmt {nullptr};AVStream *outStream {nullptr};AVStream *inSteam {nullptr};AVPacket pkt {nullptr};// 日志信息av_log_set_level(AV_LOG_DEBUG);if(argc<3){av_log(nullptr,AV_LOG_ERROR,"Usage:%s <input file> <output file>\n",argv[0]);exit(-1);}src = argv[1];dst = argv[2];// 2.打开多媒体输入文件ret = avformat_open_input(&pFormatCtx,src,nullptr,nullptr);if(ret<0){av_log(nullptr,AV_LOG_ERROR,"Could not open input file:%s\n",src);exit(-1);}// 3.获取多媒体文件信息ret = av_find_best_stream(pFormatCtx,AVMEDIA_TYPE_VIDEO,-1,-1,nullptr,0);if(ret<0){av_log(nullptr,AV_LOG_ERROR,"Failed to retrieve input stream information\n");goto _ERROR;}// 打开目的多媒体文件oFormatCtx = avformat_alloc_context();if(oFormatCtx==nullptr){av_log(nullptr,AV_LOG_ERROR,"Failed to allocate output context\n");goto _ERROR;}outFmt = av_guess_format(nullptr,dst,nullptr);if(outFmt==nullptr){av_log(nullptr,AV_LOG_ERROR,"Failed to guess output format\n");goto _ERROR;}oFormatCtx->oformat = outFmt;// 为目的文件,创建一个新的视频流outStream = avformat_new_stream(oFormatCtx,nullptr);// 设置视频参数inSteam = pFormatCtx->streams[idx];avcodec_parameters_copy(outStream->codecpar,pFormatCtx->streams[ret]->codecpar);outStream->codecpar->codec_tag = 0;// 绑定ret = avio_open2(&oFormatCtx->pb,dst,AVIO_FLAG_WRITE, nullptr, nullptr);if(ret<0){av_log(nullptr,AV_LOG_ERROR,"Failed to open output file:%s\n",dst);goto _ERROR;}// 写入头信息ret = avformat_write_header(oFormatCtx,nullptr);if(ret<0){av_log(nullptr,AV_LOG_ERROR,"Failed to write output file header\n");goto _ERROR;}// 写多媒体文件到目的文件ret = avformat_write_header(oFormatCtx,nullptr);if(ret<0){av_log(nullptr,AV_LOG_ERROR,"Failed to write output file header:%s\n", av_err2str(ret));goto _ERROR;}while(av_read_frame(pFormatCtx,&pkt)>=0) {if (pkt.stream_index == idx) {pkt.pts = av_rescale_q_rnd(pkt.pts, inSteam->time_base, outStream->time_base,(AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));pkt.dts = av_rescale_q_rnd(pkt.dts, inSteam->time_base, outStream->time_base,(AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));pkt.duration = av_rescale_q(pkt.duration, inSteam->time_base, outStream->time_base);pkt.stream_index = 0;pkt.pos = -1;av_interleaved_write_frame(oFormatCtx, &pkt);}av_packet_unref(&pkt);}// 写入尾信息av_write_trailer(oFormatCtx);_ERROR:if(oFormatCtx->pb){avio_close(oFormatCtx->pb);oFormatCtx->pb = nullptr;}if(oFormatCtx){avformat_free_context(oFormatCtx);oFormatCtx = nullptr;}if(pFormatCtx){avformat_free_context(pFormatCtx);pFormatCtx = nullptr;}return 0;
}
  • 执行
./main demo.mp4 demo2.h264
  • 运行
ffplay demo2.h264

image-20240622143747704

相关文章:

ffmpeg音视频开发从入门到精通——ffmpeg 视频数据抽取

文章目录 FFmpeg视频处理工具使用总结环境配置主函数与参数处理打开输入文件获取流信息分配输出文件上下文猜测输出文件格式创建视频流并设置参数打开输出文件并写入头信息读取、转换并写入帧数据写入尾信息并释放资源运行程序注意事项源代码 FFmpeg视频处理工具使用总结 环境…...

Node.js之文件夹的操作

1.创建文件夹操作 // 导入fs模块 const fs require(fs)//创建文件夹操操作 fs.mkdir(./Page, err > {if (err) {console.log(操作失败)return}console.log(操作成功) }) 2.递归创建文件夹 //递归创建文件夹 fs.mkdir(./a/b/c, {recursive: true}, err > {if (err) {co…...

线程的四种操作

所属专栏&#xff1a;Java学习 1. 线程的开启 start和run的区别&#xff1a; run&#xff1a;描述了线程要执行的任务&#xff0c;也可以称为线程的入口 start&#xff1a;调用系统函数&#xff0c;真正的在系统内核中创建线程&#xff08;创建PCB&#xff0c;加入到链…...

自我指导:提升语言模型自我生成指令的能力

人工智能咨询培训老师叶梓 转载标明出处 传统的语言模型&#xff0c;尤其是经过指令微调的大型模型&#xff0c;虽然在零样本&#xff08;zero-shot&#xff09;任务泛化上表现出色&#xff0c;但它们高度依赖于人类编写的指令数据。这些数据往往数量有限、多样性不足&#xf…...

使用Node.js实现单文件上传功能—含代码解释

1、概念 文件上传的具体内容 在前端让用户发送(上传)图片&#xff0c;图片由后端(服务器)接收&#xff0c;并转存到到服务端设备上的操作node.js的文件上传功能主要是使用&#xff1a;multer 插件实现的 搭建一个图片上传的接口 先让接口开通&#xff0c;再去做插件下载/配置等…...

【机器人工具箱Robotics Toolbox开发笔记(一)】Matlab机器人工具箱简介

MATLAB是一款被广泛应用于科学计算和工程领域的专业软件。它的全称为Matrix Laboratory&#xff08;矩阵实验室&#xff09;&#xff0c;因为其最基本的数据类型就是矢量与矩阵&#xff0c;所以在处理数学和科学问题时非常方便&#xff0c;可用于线性代数计算、图形和动态仿真的…...

基于 Metropolis 的朗之万算法

基于 Metropolis 的朗之万算法 1. 未经调整的朗之万算法2. 基于 Metropolis 的朗之万算法 (MALA)2.1. MH算法2.2. 基于 Metropolis 的朗之万算法 (MALA) 3. Metropolis 调整的朗之万截断算法&#xff08;MALTA&#xff09; 1. 未经调整的朗之万算法 未调整的朗之万算法 (ULA) 是…...

SAM2POINT:以zero-shot且快速的方式将任何 3D 视频分割为视频

摘要 我们介绍 SAM2POINT&#xff0c;这是一种采用 Segment Anything Model 2 (SAM 2) 进行零样本和快速 3D 分割的初步探索。 SAM2POINT 将任何 3D 数据解释为一系列多向视频&#xff0c;并利用 SAM 2 进行 3D 空间分割&#xff0c;无需进一步训练或 2D-3D 投影。 我们的框架…...

深入理解FastAPI的response_model:自动化数据验证与文档生成

使用 FastAPI 的 response_model 参数 在构建 RESTful API 时&#xff0c;确保数据的一致性和正确性是非常重要的。FastAPI 提供了强大的工具来帮助开发者实现这一目标。其中一个关键特性是 response_model 参数&#xff0c;它允许开发者定义期望的响应格式&#xff0c;并自动…...

【数据结构与算法 | 灵神题单 | 删除链表篇】力扣3217, 82, 237

总结&#xff0c;删除链表节点问题使用到列表&#xff0c;哈希表&#xff0c;递归比较容易超时&#xff0c;我觉得使用计数排序比较稳&#xff0c;处理起来也不是很难。 1. 力扣3217&#xff1a;从链表中移除在数组中的节点 1.1 题目&#xff1a; 给你一个整数数组 nums 和一…...

快速失败 (fail-fast) 和安全失败 (fail-safe)

1. 定义与工作原理 1.1 快速失败&#xff08;Fail-Fast&#xff09; 定义&#xff1a; 快速失败是一种系统设计原则&#xff0c;当系统遇到异常情况或错误时&#xff0c;立即停止执行并返回错误&#xff0c;而不是试图继续执行或处理潜在的问题。快速失败系统会主动检测系统中…...

【MySQL】MySQL中表的增删改查——(基础篇)(超详解)

前言&#xff1a; &#x1f31f;&#x1f31f;本期讲解关于MySQL中CDUD的基础操作&#xff0c;希望能帮到屏幕前的你。 &#x1f308;上期博客在这里&#xff1a;http://t.csdnimg.cn/fNldO &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 目录 …...

【B题第二套完整论文已出】2024数模国赛B题第二套完整论文+可运行代码参考(无偿分享)

2024数模国赛B题完整论文 摘要&#xff1a; 随着电子产品制造业的快速发展&#xff0c;质量控制与成本优化问题成为生产过程中亟待解决的核心挑战。为应对生产环节中的质量不确定性及成本控制需求&#xff0c;本文结合抽样检测理论和成本效益分析&#xff0c;通过构建数学模型…...

大数据之Flink(四)

11、水位线 11.1、水位线概念 一般实时流处理场景中&#xff0c;事件时间基本与处理时间保持同步&#xff0c;可能会略微延迟。 flink中用来衡量事件时间进展的标记就是水位线&#xff08;WaterMark&#xff09;。水位线可以看作一条特殊的数据记录&#xff0c;它是插入到数…...

《Web性能权威指南》-网络技术概览-读书笔记

注&#xff1a;TCP/IP等知识牵涉面太广&#xff0c;且不说本文&#xff0c;哪怕是原书&#xff0c;限于篇幅&#xff0c;很多知识点都是大致介绍下。如果想深入理解&#xff0c;需要更一步Google相关页面资料。 延迟与带宽 WPO&#xff0c;Web Performance Optimization&…...

最新版php进销存系统源码 ERP进销存专业化管理 永久免费升级更新+完整图文搭建教程

在当今信息化时代&#xff0c;企业管理的高效性与精确性是企业竞争力的关键。分享一款最新版的PHP进销存系统源码&#xff0c;一款专为企业设计的ERP进销存管理工具&#xff0c;其丰富的功能、灵活的子账号设置、强大的权限控制、以及独家升级的合同管理和报价单打印功能&#…...

【高效办公】三、两台电脑共享鼠标、键盘和文件,两台电脑当一个用的神操作!barrier

1.下载 ubuntu:sudo apt install barrierwindows:https://github.com/debauchee/barrier/releases-下载 : 2.4.0-Assets-BarrierSetup-2.4.0-release.exe 2.运行 ubuntu:sudo apt install barrierwindows:https://github.com/debauchee/barrier/releases-下载 : 2.4.0-Asset…...

智能合约系统DAPP开发

智能合约系统DAPP&#xff08;去中心化应用&#xff09;的开发是一个复杂且综合性的过程&#xff0c;它结合了区块链技术、智能合约编程、前端开发以及安全性等多方面的知识和技能。以下是对智能合约系统DAPP开发过程的详细概述&#xff1a; 一、需求分析 明确应用场景&#xf…...

宠物狗检测-目标检测数据集(包括VOC格式、YOLO格式)

宠物狗检测-目标检测数据集&#xff08;包括VOC格式、YOLO格式&#xff09; 数据集&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1roegkaGAURWUVRR-D7OzzA?pwddxv6 提取码&#xff1a;dxv6 数据集信息介绍&#xff1a; 共有20580 张图像和一一对应的标注文件 标…...

2.5多任务示例编程2

1.CUBEMX配置 2.代码 void StartADC(void const * argument) {/* USER CODE BEGIN StartADC */TickType_t pxPreviousWakeTimexTaskGetTickCount();/* Infinite loop */for(;;){HAL_ADC_Start(&hadc1);if(HAL_ADC_PollForConversion(&hadc1,100)HAL_OK){uint32_t valu…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

多模态图像修复系统:基于深度学习的图片修复实现

多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

Xela矩阵三轴触觉传感器的工作原理解析与应用场景

Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知&#xff0c;帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量&#xff0c;能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度&#xff0c;还为机器人、医疗设备和制造业的智…...

jdbc查询mysql数据库时,出现id顺序错误的情况

我在repository中的查询语句如下所示&#xff0c;即传入一个List<intager>的数据&#xff0c;返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致&#xff0c;会导致返回的id是从小到大排列的&#xff0c;但我不希望这样。 Query("SELECT NEW com…...

深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙

WebGL&#xff1a;在浏览器中解锁3D世界的魔法钥匙 引言&#xff1a;网页的边界正在消失 在数字化浪潮的推动下&#xff0c;网页早已不再是静态信息的展示窗口。如今&#xff0c;我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室&#xff0c;甚至沉浸式的V…...