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库中的一个函数,用于打开一个输入文件并初始化输入上下文。
输入参数如下:
- AVFormatContext **ps:指向要初始化的AVFormatContext指针的指针。函数将分配一个AVFormatContext结构并将其指针保存在该参数指向的地址中。
- const char *url:输入文件的URL或文件名。
- AVInputFormat *fmt:强制指定要使用的输入格式。如果为NULL,则函数将根据输入文件的扩展名自动选择适当的格式。
- AVDictionary **options:一个指向AVDictionary结构指针的指针,用于设置差异化选项。可以使用该参数来设置例如输入缓冲区大小、超时值等选项。
- 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);
参数说明如下:
ic
:指向AVFormatContext的指针,表示输入的封装格式上下文。type
:表示所需流的媒体类型,可以是AVMEDIA_TYPE_AUDIO
、AVMEDIA_TYPE_VIDEO
或AVMEDIA_TYPE_SUBTITLE
。wanted_stream_nb
:表示所需流的索引号。related_stream
:表示关联的流的索引号。通常设置为负值,表示没有关联的流。decoder_ret
:指向AVCodec指针的指针,用于返回找到的解码器。flags
:表示查找流的标志位,可以是AVFMT_FLAG_NOFILE
、AVFMT_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库中的一个函数,用于猜测输入参数的格式。它的输入参数包括:
const char *short_name
:输入参数的短名称。这是一个字符串,通常是文件的扩展名或格式的简称。const char *filename
:输入参数的文件名。这是一个字符串,指定要处理的文件路径。const char *mime_type
:输入参数的MIME类型。这是一个字符串,指定要处理的媒体类型。
这些输入参数可根据实际需求来选择设置,也可以通过设置为NULL来忽略某些参数。根据提供的输入参数,av_guess_format
函数会尝试猜测并返回最有可能的格式。
注意:在使用av_guess_format
函数时,应确保FFmpeg库已正确初始化,并且所需的输入参数有效且符合可接受的格式。av_guess_format
是FFmpeg库中的一个函数,用于猜测输入参数的格式。它的输入参数包括:
const char *short_name
:输入参数的短名称。这是一个字符串,通常是文件的扩展名或格式的简称。const char *filename
:输入参数的文件名。这是一个字符串,指定要处理的文件路径。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库中的一个函数,用于将音视频数据包写入容器文件。
函数的参数如下:
-
AVFormatContext *s: AVFormatContext结构体指针,表示容器格式上下文,用于管理容器格式相关的信息。
-
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
相关文章:

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…...

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

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

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

【机器人工具箱Robotics Toolbox开发笔记(一)】Matlab机器人工具箱简介
MATLAB是一款被广泛应用于科学计算和工程领域的专业软件。它的全称为Matrix Laboratory(矩阵实验室),因为其最基本的数据类型就是矢量与矩阵,所以在处理数学和科学问题时非常方便,可用于线性代数计算、图形和动态仿真的…...

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

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

深入理解FastAPI的response_model:自动化数据验证与文档生成
使用 FastAPI 的 response_model 参数 在构建 RESTful API 时,确保数据的一致性和正确性是非常重要的。FastAPI 提供了强大的工具来帮助开发者实现这一目标。其中一个关键特性是 response_model 参数,它允许开发者定义期望的响应格式,并自动…...

【数据结构与算法 | 灵神题单 | 删除链表篇】力扣3217, 82, 237
总结,删除链表节点问题使用到列表,哈希表,递归比较容易超时,我觉得使用计数排序比较稳,处理起来也不是很难。 1. 力扣3217:从链表中移除在数组中的节点 1.1 题目: 给你一个整数数组 nums 和一…...

快速失败 (fail-fast) 和安全失败 (fail-safe)
1. 定义与工作原理 1.1 快速失败(Fail-Fast) 定义: 快速失败是一种系统设计原则,当系统遇到异常情况或错误时,立即停止执行并返回错误,而不是试图继续执行或处理潜在的问题。快速失败系统会主动检测系统中…...

【MySQL】MySQL中表的增删改查——(基础篇)(超详解)
前言: 🌟🌟本期讲解关于MySQL中CDUD的基础操作,希望能帮到屏幕前的你。 🌈上期博客在这里:http://t.csdnimg.cn/fNldO 🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客 目录 …...

【B题第二套完整论文已出】2024数模国赛B题第二套完整论文+可运行代码参考(无偿分享)
2024数模国赛B题完整论文 摘要: 随着电子产品制造业的快速发展,质量控制与成本优化问题成为生产过程中亟待解决的核心挑战。为应对生产环节中的质量不确定性及成本控制需求,本文结合抽样检测理论和成本效益分析,通过构建数学模型…...

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

《Web性能权威指南》-网络技术概览-读书笔记
注:TCP/IP等知识牵涉面太广,且不说本文,哪怕是原书,限于篇幅,很多知识点都是大致介绍下。如果想深入理解,需要更一步Google相关页面资料。 延迟与带宽 WPO,Web Performance Optimization&…...

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

【高效办公】三、两台电脑共享鼠标、键盘和文件,两台电脑当一个用的神操作!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(去中心化应用)的开发是一个复杂且综合性的过程,它结合了区块链技术、智能合约编程、前端开发以及安全性等多方面的知识和技能。以下是对智能合约系统DAPP开发过程的详细概述: 一、需求分析 明确应用场景…...

宠物狗检测-目标检测数据集(包括VOC格式、YOLO格式)
宠物狗检测-目标检测数据集(包括VOC格式、YOLO格式) 数据集: 链接:https://pan.baidu.com/s/1roegkaGAURWUVRR-D7OzzA?pwddxv6 提取码:dxv6 数据集信息介绍: 共有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…...

JavaWeb - 4 - Vue Ajax
一.Vue Vue Vue是一套前端框架,免除原生JavaScript中的DOM操作,简化书写 基于MVVM(Model-VIew-ViewModel)思想,实现数据的双向绑定,将编程的关注点放在数据上 官网:https://cn.vuejs.org…...

深入掌握Go语言中的正则表达式与字符串处理
Go语言中的正则表达式与模式匹配 在编程中,字符串处理是常见的需求之一,而正则表达式则是一个强大的工具,能够帮助我们实现复杂的字符串匹配、提取和替换功能。Go语言内置了对正则表达式的支持,通过regexp包,我们可以…...

Docker进入容器运行命令
Docker进入容器运行命令 1. **使用 docker exec 进入容器并运行命令**语法:示例 1:进入容器并启动交互式 Bash 终端示例 2:在容器中运行单个命令 2. **使用 docker attach 进入容器**3. **使用 docker run 启动新容器并运行命令**4. **使用 d…...

[数据集][目标检测]机油泄漏检测数据集VOC+YOLO格式43张1类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):43 标注数量(xml文件个数):43 标注数量(txt文件个数):43 标注类别数…...

Python实现读取Excel数据详细教学版
Python实现读取Excel数据详细教学版 在处理数据和进行数据分析时,Excel文件是常见的数据载体。通过Python读取Excel数据,可以方便地对数据进行进一步的处理和分析。以下将详细介绍使用Python读取Excel数据的方法和相关库的使用,并提供具体代…...

【HarmonyOS】- 内存优化
文章目录 知识回顾前言源码分析1. onMemoryLevel2. 使用LRUCache优化ArkTS内存原理介绍3. 使用生命周期管理优化ArkTS内存4. 使用purgeable优化C++内存拓展知识1. Purgeable Memory总结知识回顾 前言 当应用程序占用过多内存时,系统可能会频繁进行内存回收和重新分配,导致应…...

【生日视频制作】保时捷车主提车交车仪式感AE模板修改文字软件生成器教程特效素材【AE模板】
生日视频制作教程保时捷车主提车交车仪式感AE模板修改文字特效广告生成神器素材祝福玩法AE模板工程 怎么如何做的【生日视频制作】保时捷车主提车交车仪式感AE模板修改文字软件生成器教程特效素材【AE模板】 生日视频制作步骤: 下载AE模板 安装AE软件 把AE模板导入…...

【自用14】C++俄罗斯方块-思路复盘3
在上篇降落函数中使用到了判断游戏是否结束的功能,因此这篇先从判断游戏是否结束开始 判断游戏是否结束 void failCheck(void){if(!moveable(START_X,START_Y,MOVE_DOWN,BLOCK_UP)){setcolor(WHITE);setfont(45,0,_T("隶体"));outtextxy(75,300,_T(&quo…...

ElasticSearch的DSL查询⑤(ES数据聚合、DSL语法数据聚合、RestClient数据聚合)
目录 一、数据聚合 1.1 DSL实现聚合 1.1.1 Bucket聚合 1.1.2 带条件聚合 1.1.3 Metric聚合 1.1.4 总结 2.1 RestClient实现聚合 2.1.1 Bucket聚合 2.1.2 带条件聚合 2.2.3 Metric聚合 一、数据聚合 聚合(aggregations)可以让我们极其方便的实…...

DBeaver 24.0 高阶用法
DBeaver 24.0 高阶用法 文章目录 DBeaver 24.0 高阶用法DBeaver 介绍功能一、元数据搜索功能二、仪表盘显示功能三、ER图功能四、导出数据最后 DBeaver 介绍 DBeaver 确实是一款功能强大的通用数据库管理工具,适合所有需要以专业方式处理数据的用户。它不仅提供了直…...