FFmpeg处理流程
结构体
AVFormatContext
作用:管理媒体文件的封装格式上下文,存储文件格式、流信息、I/O 操作等元数据。
关键字段
AVInputFormat *iformat; // 输入格式(如MP4、FLV)
AVStream **streams; // 音视频流数组
int nb_streams; // 流数量
int64_t duration; // 总时长(微秒)
初始化:avformat_alloc_context(),avformat_open_input()
AVStream
作用:表示单个音视频流,包含编解码参数和时间基准。
关键字段:
AVCodecParameters *codecpar; // 编解码参数(如分辨率、采样率)
AVRational time_base; // 时间基(如1/30表示30fps)
初始化:avformat_new_stream()
AVCodec
AVCodecContext
作用:编解码器上下文,存储编解码参数(如码率、帧率、像素格式)。
关键字段:
enum AVCodecID codec_id; // 编解码器ID(如H.264、AAC)
int width, height; // 视频分辨率
enum AVPixelFormat pix_fmt; // 像素格式(如YUV420P)
AVRational time_base; // 编码器时间基
初始化:avcodec_alloc_context3(),avcodec_parameters_to_context()
AVPacket
作用:存储编码后的压缩数据(如H.264数据包)。
关键字段:
uint8_t *data; // 压缩数据指针
int size; // 数据大小
int64_t pts, dts; // 显示和解码时间戳
初始化:av_packet_alloc(),av_packet_unref()
AVFrame
作用:存储解码后的原始数据(如YUV像素数据或PCM音频样本)。
关键字段:
uint8_t *data[AV_NUM_DATA_POINTERS]; // 数据指针(如Y、U、V分量)
int linesize[AV_NUM_DATA_POINTERS]; // 每行字节数
int width, height; // 视频分辨率
初始化:av_frame_alloc(),av_frame_free()
SwsContext
作用:图像格式转换上下文(如YUV转RGB)。
初始化:sws_getContext(),销毁:sws_freeContext()
SwrContext
作用:音频重采样上下文(如48kHz转44.1kHz)。
初始化:swr_alloc_set_opts(),销毁:swr_free()
API
avformat_open_input
avformat_find_stream_info
av_find_best_stream
avcodec_alloc_context3
avcodec_parameters_to_context
avcodec_open2
avcodec_find_encoder
av_opt_set_int
sws_getContext
avformat_alloc_output_context2
avformat_new_stream
avcodec_parameters_from_context
avio_open
avformat_write_header
av_frame_alloc
av_frame_get_buffer
av_packet_alloc
av_read_frame
avcodec_send_packet
avcodec_receive_frame
sws_scale
av_rescale_q
avcodec_send_frame
avcodec_receive_packet
av_packet_rescale_ts
av_interleaved_write_frame
av_packet_unref
av_write_trailer
例子
#include <iostream>
#include <memory>// 使用 RAII 管理指针(可选,但推荐)
template<typename T, void(*Deleter)(T*)>
struct FFmpegResource {T* ptr = nullptr;FFmpegResource(T* p = nullptr) : ptr(p) {}~FFmpegResource() { if (ptr) Deleter(ptr); }
};using AVFormatContextPtr = FFmpegResource<AVFormatContext, avformat_close_input>;
using AVCodecContextPtr = FFmpegResource<AVCodecContext, avcodec_free_context>;
using SwsContextPtr = FFmpegResource<SwsContext, sws_freeContext>;
using AVFramePtr = FFmpegResource<AVFrame, av_frame_free>;
using AVPacketPtr = FFmpegResource<AVPacket, av_packet_free>;int main() {AVFormatContext *srcCtx = nullptr;AVCodecContext *srcDecCtx = nullptr, *encCtx = nullptr;SwsContext *swsCtx = nullptr;AVFrame *decFrame = nullptr, *encFrame = nullptr;AVPacket *pkt = nullptr;AVFormatContext *outputCtx = nullptr;int ret = 0;// 错误处理标签#define CHECK_ERROR(cond, msg, cleanup_label) \if ((cond)) { \std::cerr << (msg) << ": " << av_err2str(ret) << std::endl; \goto cleanup_label; \}// ============ 打开输入文件 ============ret = avformat_open_input(&srcCtx, srcPath.toStdString().c_str(), nullptr, nullptr);CHECK_ERROR(ret < 0, "打开视频文件失败", cleanup);ret = avformat_find_stream_info(srcCtx, nullptr);CHECK_ERROR(ret < 0, "获取视频流信息失败", cleanup);// ============ 初始化视频解码器 ============const AVCodec *srcDec = nullptr;int streamIndex = av_find_best_stream(srcCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &srcDec, 0);CHECK_ERROR(streamIndex < 0, "查找视频流失败", cleanup);srcDecCtx = avcodec_alloc_context3(srcDec);CHECK_ERROR(!srcDecCtx, "分配解码器上下文失败", cleanup);ret = avcodec_parameters_to_context(srcDecCtx, srcCtx->streams[streamIndex]->codecpar);CHECK_ERROR(ret < 0, "拷贝解码器参数失败", cleanup);ret = avcodec_open2(srcDecCtx, srcDec, nullptr);CHECK_ERROR(ret < 0, "打开解码器失败", cleanup);// ============ 初始化视频编码器 ============const AVCodec *srcEnc = avcodec_find_encoder(srcCtx->streams[streamIndex]->codecpar->codec_id);CHECK_ERROR(!srcEnc, "查找编码器失败", cleanup);encCtx = avcodec_alloc_context3(srcEnc);CHECK_ERROR(!encCtx, "分配编码器上下文失败", cleanup);// 配置编码参数encCtx->width = width;encCtx->height = height;encCtx->pix_fmt = AV_PIX_FMT_YUV420P;encCtx->time_base = {1, 30};encCtx->gop_size = 12;
// encCtx->bit_rate = 4000000; 不设置码率encCtx->profile = FF_PROFILE_H264_HIGH;encCtx->level = 40;encCtx->max_b_frames = 2;encCtx->color_range = AVCOL_RANGE_MPEG; // 颜色范围(tv)encCtx->color_primaries = AVCOL_PRI_BT709; // 颜色标准encCtx->color_trc = AVCOL_TRC_BT709; // 颜色传输特性encCtx->colorspace = AVCOL_SPC_BT709; // 颜色空间// 设置CRF模式与参数调整encCtx->flags |= AV_CODEC_FLAG_QSCALE;// 启用量化参数控制av_opt_set_int(encCtx->priv_data, "crf", 18, AV_OPT_SEARCH_CHILDREN);// 0-51,18为视觉无损av_opt_set(encCtx->priv_data, "preset", "veryslow", AV_OPT_SEARCH_CHILDREN); // 牺牲时间换取质量
// av_opt_set(encCtx->priv_data, "tune", "film", AV_OPT_SEARCH_CHILDREN); // 电影类用film,动画用animationret = avcodec_open2(encCtx, srcEnc, nullptr);CHECK_ERROR(ret < 0, "打开编码器失败", cleanup);// ============ 创建缩放上下文 ============swsCtx = sws_getContext(/* 参数保持原逻辑 */);CHECK_ERROR(!swsCtx, "创建缩放上下文失败", cleanup);// ============ 准备输出文件 ============ret = avformat_alloc_output_context2(&outputCtx, nullptr, nullptr, destPath.toStdString().c_str());CHECK_ERROR(ret < 0, "创建输出上下文失败", cleanup);AVStream *outStream = avformat_new_stream(outputCtx, nullptr);CHECK_ERROR(!outStream, "创建输出流失败", cleanup);ret = avcodec_parameters_from_context(outStream->codecpar, encCtx);CHECK_ERROR(ret < 0, "拷贝编码器参数到输出流失败", cleanup);// 显式设置输出流时间基与编码器一致 outStream->time_base = encCtx->time_base;if (!(outputCtx->oformat->flags & AVFMT_NOFILE)) {ret = avio_open(&outputCtx->pb, destPath.toStdString().c_str(), AVIO_FLAG_WRITE);CHECK_ERROR(ret < 0, "打开输出文件失败", cleanup);}ret = avformat_write_header(outputCtx, nullptr);CHECK_ERROR(ret < 0, "写入文件头失败", cleanup);// ============ 帧处理循环 ============decFrame = av_frame_alloc();encFrame = av_frame_alloc();pkt = av_packet_alloc();CHECK_ERROR(!decFrame || !encFrame || !pkt, "分配帧/包失败", cleanup);while (av_read_frame(srcCtx, pkt) >= 0) {if (pkt->stream_index != streamIndex) {av_packet_unref(pkt);continue;}// 解码if ((ret = avcodec_send_packet(srcDecCtx, pkt)) < 0) {cout << "读取包失败: " << av_err2str(ret) << endl;}while (ret >= 0) {ret = avcodec_receive_frame(srcDecCtx, decFrame);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {break;} else if (ret < 0) {cout << "读取帧失败: " << av_err2str(ret) << endl;}cout << "解码帧 pts: " << decFrame->pts << endl;// 缩放sws_scale(swsCtx, decFrame->data, decFrame->linesize,0, srcDecCtx->height, encFrame->data, encFrame->linesize);encFrame->pts = av_rescale_q(decFrame->pts, srcCtx->streams[streamIndex]->time_base, encCtx->time_base);// 编码AVPacket *encPkt = av_packet_alloc();if ((ret = avcodec_send_frame(encCtx, encFrame)) < 0) {cout << "发送帧到编码器失败: " << av_err2str(ret) << endl;}while (ret >= 0) {ret = avcodec_receive_packet(encCtx, encPkt);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {break;} else if (ret < 0) {cout << "编码器输出包失败: " << av_err2str(ret) << endl;}// 写入输出文件av_packet_rescale_ts(encPkt, encCtx->time_base, outStream->time_base);cout << "编码: " << encPkt->pts << endl;av_interleaved_write_frame(outputCtx, encPkt);av_packet_unref(encPkt);}}}// ============ 刷新编码器缓冲区 ============avcodec_send_frame(encCtx, nullptr); // 发送空帧刷新while (true) {AVPacket encPkt;av_init_packet(&encPkt);ret = avcodec_receive_packet(encCtx, &encPkt);if (ret == AVERROR_EOF || ret < 0) break;av_packet_rescale_ts(&encPkt, encCtx->time_base, outStream->time_base);av_interleaved_write_frame(outputCtx, &encPkt);av_packet_unref(&encPkt);}// ============ 写入文件尾 ============ret = av_write_trailer(outputCtx);CHECK_ERROR(ret < 0, "写入文件尾失败", cleanup);// ============ 资源释放 ============
cleanup:avformat_close_input(&srcCtx);avcodec_free_context(&srcDecCtx);avcodec_free_context(&encCtx);sws_freeContext(swsCtx);av_frame_free(&decFrame);av_frame_free(&encFrame);av_packet_free(&pkt);if (outputCtx && !(outputCtx->oformat->flags & AVFMT_NOFILE)) {avio_closep(&outputCtx->pb);}avformat_free_context(outputCtx);return ret;
}
相关文章:
FFmpeg处理流程
结构体 AVFormatContext 作用:管理媒体文件的封装格式上下文,存储文件格式、流信息、I/O 操作等元数据。 关键字段 AVInputFormat *iformat; // 输入格式(如MP4、FLV) AVStream **streams; // 音视频流数组 int nb_str…...
SpringMVC (一)基础
目录 SpringMVC 一 简单使用 1 新建模块选择指定参数 2 创建实现类 3 将项目启动 4 运行结果:在浏览器当中响应执行 二 RequestMapping 三 请求限定 SpringMVC SpringMVC是Spring的web模块,用来开发Web应用,SpringMVC应用最终作为B/…...
通过deepseek学习lua写网页
提问1:html通过post调用lua代码 要通过HTML页面调用Lua代码,通常需要一个服务器端环境来处理HTTP请求并执行Lua代码。HTML本身无法直接执行Lua代码,因为Lua是一种服务器端脚本语言,而HTML是客户端标记语言。 以下是一个简单的示…...
windows第十二章 MFC控件常用消息
文章目录 控件反射消息机制文本框控件EN_CHANGE消息EN_UPDATE消息EN_SETFOCUS消息EN_KILLFOCUS消息EN_MAXTEXT消息EN_ERRSPACE消息EN_HSCROLL消息 按钮控件BN_CLICKED消息BN_DOUBLECLICKED消息BN_SETFOCUS消息BN_KILLFOCUS消息 单选按钮BN_CLICKED 消息 复选框BN_CLICKEDBN_DOU…...
基于C语言的简单HTTP Web服务器实现
1. 概述 本案例使用C语言实现了一个简单的HTTP服务器,能够处理客户端的GET请求,并返回静态文件(如HTML、图片等)。在此案例中案例,我们主要使用的知识点有: Socket编程:基于TCP协议的Socket通信…...
JavaScript语言的区块链隐私
使用JavaScript保护区块链隐私 随着区块链技术的快速发展,隐私保护的重要性日益凸显。区块链技术虽然在透明性和去中心化方面表现优异,但其公开账本特性也使得用户的交易和身份信息容易暴露。因此,如何在区块链应用中实现隐私保护成为了一个…...
ZYNQ初识13(zynq_7020)hdmi和串口板载功能的验证
(1)另:首先需要确认供电模块,电压转换模块没有问题,测量后上电防止出现短路。通过vivado下载bit流文件检测JTAG下载口是否正常,如可正常检测,才可进行下一步验证。 (2)以…...
ollama下载的DeepSeek的模型(Model)文件在哪里?(C盘下)
目录 一、下载大模型(DeepSeek) 2. 安装 Ollama 3. 检查安装是否成功 二、拉取大模型(DeepSeek) 1. 打开命令行 2. 下载模型 3. 测试下载 4. 等待下载完成 三.模型存放路径 这个位置!! 在人工智能…...
docker的anythingllm和open-webui压缩包分享(国内镜像拉取,百度云压缩包分享)
文章目录 前言第一部分:镜像获取🚀 方式一:切换国内下载镜像✅1. 下载anythingllm✅ 2. 下载open-webui 🚀方式二:下载我分享的百度云✅ anythingllm压缩包百度云链接❎ open-webui压缩包 第二部分:下载之后…...
树莓科技(成都)集团:如何铸就第五代产业园标杆
树莓科技(成都)集团铸就第五代产业园标杆,主要体现在以下几个方面: 精准定位与前瞻布局 树莓科技并非盲目扩张,而是精准锚定数字经济发展方向。以成都为起点,迅速构建起全国性的园区版图,体现…...
父组件中循环生成多个子组件时,有且只有最后一个子组件的watch对象生效问题及解决办法
提示:父组件中循环生成多个子组件时,有且只有最后一个子组件的watch对象生效问题及解决办法 文章目录 [TOC](文章目录) 前言一、问题二、解决方法——使用function函数代替箭头函数()>{}总结 前言 问题:子组件用that解决watch无…...
《解锁Flutter:跨平台开发的未来之光》
《解锁Flutter:跨平台开发的未来之光》 Flutter:崭新时代的跨平台框架 在当今数字化浪潮中,移动应用已成为人们生活中不可或缺的一部分。无论是购物、社交、娱乐还是办公,我们都离不开各种手机应用。而在移动应用开发领域&#…...
求递增子序列LIS的两种方法
文章目录 前言一、普通动态规划(DP)求解LIS1.DP思路2.DP的状态定义与转移方程3.DP的时间与空间复杂度4.DP代码实现5.DP的图文示例 二、贪心 二分查找求解LIS1.思路分析2.贪心 二分的时间与空间复杂度 三. 模板题讲解1.洛谷B3637 最长上升子序列1.dp写法…...
【Linux篇】进程状态(僵尸进程,孤儿进程),优先级与调度机制
📌 个人主页: 孙同学_ 🔧 文章专栏:Liunx 💡 关注我,分享经验,助你少走弯路! 文章目录 1. 前文铺垫理解内核链表 2. 进程状态2.1 进程状态查看2.2 僵尸进程2.3 僵尸进程危害2.4 孤儿…...
SAP-ABAP:CONV(显示类型转换符)关键字详解
SAP ABAP CONV 关键字详解 CONV 是 ABAP 7.40 版本引入的显式类型转换操作符,用于将表达式的结果强制转换为指定的数据类型。它提供了一种清晰且类型安全的方式处理数据转换,避免隐式转换的潜在风险。以下是其核心特性和应用场景的全面解析:…...
AI应用加速落地丨MaxKB正在被政府、公共事业、教育和医疗行业用户广泛采纳
2025年2月至3月上旬,伴随着各个行业接入并使用DeepSeek,MaxKB开源知识库问答系统正在被越来越多的行业用户所采纳,是人工智能行业落地的强应用。目前,MaxKB在政府、公共事业、教育和医疗四大行业已经拥有了众多典型案例࿰…...
⚡️Jolt -- 通过JSON配置来处理复杂数据转换的工具
简介:一个能够通过JSON配置(特定的语法)来处理复杂数据转换的工具。 比如将API响应转换为内部系统所需的格式,或者处理来自不同来源的数据结构差异。例如,将嵌套的JSON结构扁平化,或者重命名字段࿰…...
Django系列教程(7)——路由配置URLConf
目录 URLconf是如何工作的? path和re_path方法 更多URL配置示例 URL的命名及reverse()方法 使用命名URL 硬编码URL - 不建议 URL指向基于类的视图(View) 通过URL传递额外的参数 小结 Django的项目文件夹和每个应用(app)目录下都有urls.py文件,它们构成了D…...
TDengine SQL 函数
单行函数 数学函数 ABSACOSASINATANCEILCOSDEGREESEXPFLOORGREATESTLEASTLNLOGMODPIPOWRADIANSRANDROUNDSIGNSINSQRTTANTRUNCATE 字符串函数 ASCIICHARCHAR_LENGTHCONCATCONCAT_WSLENGTHLOWERLTRIMPOSITIONREPEATREPLACERTRIMSUBSTRING/SUBSTRSUBSTRING_INDEXTRIMUPPER 转换函数…...
二维数组基础
在 C 语言中,二维数组是一种数据结构,它可以存储表格形式的数据,或是矩阵形式的数据。二维数组可以被看作是一个包含多个一维数组的数组,因此它有两个维度:行和列。 1. 二维数组的定义与声明 在 C 语言中,二维数组的定义形式如下: data_type array_name[rows][column…...
2024年第十五届蓝桥杯软件C/C++大学A组——五子棋对弈
蓝桥杯原题: 题目描述: “在五子棋的对弈中,友谊的小船说翻就翻? ” 不!对小蓝和小桥来说,五子棋不仅是棋盘上的较量,更是心与心之间的沟通。这两位挚友秉承着 “ 友谊第一,比赛第二…...
复试难度解析,西电先进材料与纳米科技学院学院考研录取情况
01、先进材料与纳米科技学院各个方向 02、24先进材料与纳米科技学院近三年复试分数线对比 PS:材料院24年院线学硕方向降低10分,专硕上涨15分;材料院在分数线相对于其他211、985院校对比来看,依然分数偏低,推荐大家关注…...
Deepseek Chatgpt Kimi 推荐的深度学习书单
朋友让推荐一些深度学习的书,让 Deepseek、Chatgpt、Kimi 分别生成了一份书单并做了对比,记录一下以备以后用到。 Chatgpt 推荐的深度学习书 1. chatgpt 推荐的书目截图 1.2 Chatgpt 推荐的深度学习书目文字版 如果你想学习 Deep Learning࿰…...
高频面试题(含笔试高频算法整理)基本总结回顾25
干货分享,感谢您的阅读! (暂存篇---后续会删除,完整版高频面试题基本总结回顾(含笔试高频算法整理)) 备注:引用请标注出处,同时存在的问题请在相关博客留言,…...
ClickHouse SQL优化:解锁高性能数据分析的关键
一、引言 1.1 ClickHouse的背景与优势 ClickHouse是一款高性能的列式数据库,专为在线分析处理(OLAP)场景设计。它以其卓越的读写性能、强大的数据压缩能力和灵活的SQL支持而闻名。ClickHouse能够轻松处理PB级数据,并在亚秒级内返回查询结果,这使其成为大数据分析领域的理…...
我与DeepSeek读《大型网站技术架构》(14)- 架构师领导艺术
文章目录 架构师领导艺术以人为本:激发团队潜能开放式协作:打破架构“所有权”壁垒妥协的艺术:聚焦核心目标成就他人:构建持续进化团队高效沟通:建立技术与人性的平衡 架构师领导艺术 本章聚焦架构师如何通过团队协作…...
mac安装mysql之后报错zsh: command not found: mysql !
在Mac上安装MySQL后,如果终端中找不到mysql命令,通常是 因为MySQL的命令行工具(如mysql客户端)没有被正确地添加到你的环境变量中。 检查 MySQL 是否已安装 ps -ef|grep mysql查看到路径在 /usr/local/mysql/bin 查看 .bash_pro…...
蓝桥杯备考:set容器用法(lower_bound)---营业额统计
如图所示,这道题的暴力解法就是枚举每天的营业额,让该营业额和前面的天的营业额依次相减取最小值这样的话我们的时间复杂度就是N平方,我们是很有可能超时的 所以我们选择用set容器的二分查找功能 我们每次遍历到一个数的时候,前…...
VSCode集成C语言开发环境
下载MinGW https://sourceforge.net/projects/mingw/ 点击download按钮下载exe文件到本地 点击exe文件安装 选择基础包和c编译版 vscode安装部分跳过 安装code runner和c/c插件 **(1) 创建 C 文件** 新建一个测试文件(例如 hello.c)…...
Python----数据可视化(pyecharts二:绘图一:条形图,直方图,折线图,散点图,箱图,饼图,热力图)
1、条形图 from pyecharts.charts import Bar from pyecharts.faker import Faker from pyecharts import options as opts # 绘制柱状图 bar (Bar() # 创建柱状图.add_yaxis("商家A", Faker.values(),colorFaker.rand_color()) # 添加数据.add_yaxis("商家B&…...
