ffmpeg更改视频的帧率
note
视频帧率调整
帧率(fps-frame per second)
例如:原来帧率为30,调整后为1 现象:原来是每秒有30张图像,调整后每秒1张图像,看着图像很慢
实现:在每秒的时间区间里,取一张图像
version
#define LIBAVFILTER_VERSION_MINOR 12
#define LIBAVFILTER_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_MINOR 31
#define LIBAVCODEC_VERSION_MICRO 102
code
void CFfmpegOps::ChangeVideoFPS(const char *in_mp4, const char *out_mp4)
{AVFormatContext *in_fmt_ctx = nullptr;const AVInputFormat *in_fmt = nullptr;AVFormatContext *out_fmt_ctx = nullptr;const AVOutputFormat *out_fmt = nullptr;int ret = -1;int video_stream_index = 0;const AVCodec *decoder = nullptr;AVCodecContext *decoder_ctx = nullptr;const AVCodec* encoder = nullptr;AVCodecContext* encoder_ctx = nullptr;AVStream* in_avstream = nullptr;AVStream* out_avstream = nullptr;const AVFilter * avfilter_buffer_src = nullptr; // 源,video buffer可设置的参数有AVFilterContext* avfilter_ctx_buffer_src = nullptr;const AVFilter * avfilter_fps = nullptr; // 中间节点,video fps可设置的参数包含fpsAVFilterContext* avfilter_ctx_fps = nullptr;const AVFilter* avfilter_buffer_sink = nullptr; // 终,video buffersink可设置的参数只有pixel formatsAVFilterContext* avfilter_ctx_buffer_sink = nullptr;AVFilterGraph* avfiltergraph = nullptr;AVPacket* avpacket_src = nullptr;AVFrame* avframe_src = nullptr;AVFrame* avframe_dest = nullptr;AVPacket* avpacket_dest = nullptr;AVRational pixel_aspect = {.num = 1, .den = 1};ret = avformat_open_input(&in_fmt_ctx, in_mp4, nullptr, nullptr);if (ret < 0){printf("avformat_open_input error(%s)\n", GetFfmpegERR(ret));goto END;}in_fmt = in_fmt_ctx->iformat;ret = avformat_find_stream_info(in_fmt_ctx, nullptr);if (ret < 0){printf("avformat_find_stream_info error(%s)\n", GetFfmpegERR(ret));goto END;}ret = av_find_best_stream(in_fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);if (ret < 0){printf("av_find_best_stream error(%s)\n", GetFfmpegERR(ret));goto END;}video_stream_index = ret;in_avstream = in_fmt_ctx->streams[video_stream_index];decoder = avcodec_find_decoder(in_avstream->codecpar->codec_id);if (!decoder){printf("avcodec_find_decoder error\n");goto END;}decoder_ctx = avcodec_alloc_context3(decoder);if (!decoder_ctx){printf("avcodec_alloc_context3 error\n");goto END;}ret = avcodec_parameters_to_context(decoder_ctx, in_avstream->codecpar);if (ret < 0){printf("avcodec_parameters_to_context error(%s)\n", GetFfmpegERR(ret));goto END;}ret = avcodec_open2(decoder_ctx, decoder, nullptr);if (ret < 0){printf("avcodec_open2 error(%s)\n", GetFfmpegERR(ret));goto END;}avfiltergraph = avfilter_graph_alloc();if (!avfiltergraph){printf("avfilter_graph_alloc error\n");goto END;}avfilter_buffer_src = avfilter_get_by_name("buffer"); // buffer对应video,abuffer对应audioif (!avfilter_buffer_src){printf("avfilter_get_by_name error\n");goto END;}printf("avfilter_buffer_src->desc:%s\n", avfilter_buffer_src->description);avfilter_ctx_buffer_src = avfilter_graph_alloc_filter(avfiltergraph, avfilter_buffer_src, avfilter_buffer_src->name);if (!avfilter_ctx_buffer_src){printf("avfilter_graph_alloc_filter error\n");goto END;}// 设置avfilter_ctx_buffer_src的可选参数// 参照libavfilter/buffersrc.c文件中对video buffer的可选参数描述ret = av_opt_set(avfilter_ctx_buffer_src, "width", std::to_string(in_avstream->codecpar->width).c_str(), AV_OPT_SEARCH_CHILDREN);if (ret < 0){printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));goto END;}ret = av_opt_set(avfilter_ctx_buffer_src, "height", std::to_string(in_avstream->codecpar->height).c_str(), AV_OPT_SEARCH_CHILDREN);if (ret < 0){printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));goto END;}ret = av_opt_set(avfilter_ctx_buffer_src, "pix_fmt", av_get_pix_fmt_name((AVPixelFormat)(in_avstream->codecpar->format)), AV_OPT_SEARCH_CHILDREN);if (ret < 0){printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));goto END;}ret = av_opt_set_q(avfilter_ctx_buffer_src,"time_base", in_avstream->time_base,AV_OPT_SEARCH_CHILDREN);if (ret < 0){printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));goto END;}ret = av_opt_set_q(avfilter_ctx_buffer_src,"frame_rate", in_avstream->r_frame_rate,AV_OPT_SEARCH_CHILDREN);if (ret < 0){printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));goto END;}ret = av_opt_set_q(avfilter_ctx_buffer_src,"pixel_aspect", pixel_aspect,AV_OPT_SEARCH_CHILDREN);if (ret < 0){printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));goto END;}// 上面已经设置过参数,初始化就不传参了ret = avfilter_init_str(avfilter_ctx_buffer_src, nullptr);if (ret < 0){printf("avfilter_init_str error(%s)\n", GetFfmpegERR(ret));goto END;}avfilter_fps = avfilter_get_by_name("fps");if (!avfilter_fps){printf("avfilter_get_by_name error\n");goto END;}printf("avfilter_fps->desc:%s\n", avfilter_fps->description);avfilter_ctx_fps = avfilter_graph_alloc_filter(avfiltergraph, avfilter_fps, avfilter_fps->name);if (!avfilter_ctx_fps){printf("avfilter_graph_alloc_filter error\n");goto END;}ret = av_opt_set(avfilter_ctx_fps, "fps", "1",AV_OPT_SEARCH_CHILDREN);if (ret < 0){printf("av_opt_set error(%s)\n", GetFfmpegERR(ret));goto END;}ret = avfilter_init_str(avfilter_ctx_fps, nullptr);if (ret < 0){printf("avfilter_init_str error(%s)\n", GetFfmpegERR(ret));goto END;}avfilter_buffer_sink = avfilter_get_by_name("buffersink");if (!avfilter_buffer_sink){printf("avfilter_get_by_name error\n");goto END;}printf("avfilter_buffer_sink->desc:%s\n", avfilter_buffer_sink->description);avfilter_ctx_buffer_sink = avfilter_graph_alloc_filter(avfiltergraph, avfilter_buffer_sink, avfilter_buffer_sink->name);if (!avfilter_ctx_buffer_sink){printf("avfilter_graph_alloc_filter error\n");goto END;}ret = avfilter_init_str(avfilter_ctx_buffer_sink, nullptr);if (ret < 0){printf("avfilter_init_str error(%s)\n", GetFfmpegERR(ret));goto END;}// 把avfilter组成链// avfilter_link的作用,在src和dest之间新建AVFilterLink实例// srcpad:src的输出通道编号// destpad:dest的输入通道编号ret = avfilter_link(avfilter_ctx_buffer_src, 0, avfilter_ctx_fps, 0);if (ret != 0){printf("avfilter_link error(%s)\n", GetFfmpegERR(ret));goto END;}ret = avfilter_link(avfilter_ctx_fps, 0, avfilter_ctx_buffer_sink, 0);if (ret != 0){printf("avfilter_link error(%s)\n", GetFfmpegERR(ret));goto END;}ret = avfilter_graph_config(avfiltergraph, nullptr);if (ret < 0){printf("avfilter_graph_config error(%s)\n", GetFfmpegERR(ret));goto END;}ret = avformat_alloc_output_context2(&out_fmt_ctx, nullptr, nullptr, out_mp4);if (ret < 0){printf("avformat_alloc_output_context2 error(%s)\n", GetFfmpegERR(ret));goto END;}out_fmt = out_fmt_ctx->oformat;encoder = avcodec_find_encoder(decoder->id);if (!encoder){printf("avcodec_find_encoder error\n");goto END;}encoder_ctx = avcodec_alloc_context3(encoder);if (!encoder_ctx){printf("avcodec_alloc_context3 error\n");goto END;}encoder_ctx->pix_fmt = (AVPixelFormat)(av_buffersink_get_format(avfilter_ctx_buffer_sink));encoder_ctx->width = av_buffersink_get_w(avfilter_ctx_buffer_sink);encoder_ctx->height = av_buffersink_get_h(avfilter_ctx_buffer_sink);encoder_ctx->time_base = av_buffersink_get_time_base(avfilter_ctx_buffer_sink);encoder_ctx->framerate = av_buffersink_get_frame_rate(avfilter_ctx_buffer_sink);encoder_ctx->gop_size = decoder_ctx->gop_size;encoder_ctx->max_b_frames = decoder_ctx->max_b_frames;if (out_fmt->flags & AVFMT_GLOBALHEADER){encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;}ret = avcodec_open2(encoder_ctx, encoder, nullptr);if (ret < 0){printf("avcodec_open2 error(%s)\n", GetFfmpegERR(ret));goto END;}out_avstream = avformat_new_stream(out_fmt_ctx, encoder);if (!out_avstream){printf("avformat_new_stream error\n");goto END;}out_avstream->time_base = av_buffersink_get_time_base(avfilter_ctx_buffer_sink);out_avstream->r_frame_rate = av_buffersink_get_frame_rate(avfilter_ctx_buffer_sink);out_avstream->avg_frame_rate = av_buffersink_get_frame_rate(avfilter_ctx_buffer_sink);ret = avcodec_parameters_from_context(out_avstream->codecpar, encoder_ctx);if (ret < 0){printf("avcodec_parameters_from_context error(%s)\n", GetFfmpegERR(ret));goto END;}ret = avio_open(&(out_fmt_ctx->pb), out_mp4, AVIO_FLAG_WRITE);if (ret < 0){printf("avio_open error(%s)\n", GetFfmpegERR(ret));goto END;}// 调用avformat_write_header后,out_avstream的时间基发生了变化(10->102400),容器要求?ret = avformat_write_header(out_fmt_ctx, nullptr);if (ret < 0){printf("avformat_write_header error(%s)\n", GetFfmpegERR(ret));goto END;}avpacket_src = av_packet_alloc();if (!avpacket_src){printf("av_packet_alloc error\n");goto END;}avpacket_dest = av_packet_alloc();if (!avpacket_dest){printf("av_packet_alloc error\n");goto END;}avframe_src = av_frame_alloc();if (!avframe_src){printf("av_frame_alloc error\n");goto END;}avframe_dest = av_frame_alloc();if (!avframe_dest){printf("av_frame_alloc error\n");goto END;}while (1){// 从输入文件读取压缩视频帧ret = av_read_frame(in_fmt_ctx, avpacket_src);if (ret < 0){printf("av_read_frame error(%s)\n", GetFfmpegERR(ret));break;}if (avpacket_src->stream_index != video_stream_index){av_packet_unref(avpacket_src);continue;}// 把压缩视频帧发送给解码器ret = avcodec_send_packet(decoder_ctx, avpacket_src);if (ret != 0){printf("avcodec_send_packet error(%s)\n", GetFfmpegERR(ret));}else{// 接收解码器的输出视频帧ret = avcodec_receive_frame(decoder_ctx, avframe_src);if (ret != 0){printf("avcodec_receive_frame error(%s)\n", GetFfmpegERR(ret));}else{// 把视频帧交给avfilterret = av_buffersrc_write_frame(avfilter_ctx_buffer_src, avframe_src);if (ret != 0){printf("av_buffersrc_write_frame error(%s)\n", GetFfmpegERR(ret));}else{// 从avfilter获取视频帧ret = av_buffersink_get_frame(avfilter_ctx_buffer_sink, avframe_dest);if (ret < 0){printf("av_buffersink_get_frame error(%s)\n", GetFfmpegERR(ret));}else{// 把视频帧交给编码器ret = avcodec_send_frame(encoder_ctx, avframe_dest);if (ret != 0){printf("avcodec_send_frame error(%s)\n", GetFfmpegERR(ret));}else{// 从编码器获取压缩视频帧ret = avcodec_receive_packet(encoder_ctx, avpacket_dest);if (ret != 0){printf("avcodec_receive_packet error(%s)\n", GetFfmpegERR(ret));}else{av_packet_rescale_ts(avpacket_dest, encoder_ctx->time_base, out_avstream->time_base);// 写入到输出文件ret = av_write_frame(out_fmt_ctx, avpacket_dest);if (ret < 0){printf("av_write_frame error(%s)\n", GetFfmpegERR(ret));}}}}}}}}ret = av_write_trailer(out_fmt_ctx);if (ret < 0){printf("av_write_trailer error(%s)\n", GetFfmpegERR(ret));goto END;}END:if (avframe_dest){av_frame_free(&avframe_dest);avframe_dest = nullptr;}if (avframe_src){av_frame_free(&avframe_src);avframe_src = nullptr;}if (avpacket_src){av_packet_free(&avpacket_src);avpacket_src = nullptr;}if (avpacket_dest){av_packet_free(&avpacket_dest);avpacket_dest = nullptr;}if (avfilter_ctx_buffer_sink){avfilter_free(avfilter_ctx_buffer_sink);avfilter_ctx_buffer_sink = nullptr;}if (avfilter_ctx_fps){avfilter_free(avfilter_ctx_fps);avfilter_ctx_fps = nullptr;}if (avfilter_ctx_buffer_src){avfilter_free(avfilter_ctx_buffer_src);avfilter_ctx_buffer_src = nullptr;}if (avfiltergraph){avfilter_graph_free(&avfiltergraph);avfiltergraph = nullptr;}if (encoder_ctx){avcodec_free_context(&encoder_ctx);encoder_ctx = nullptr;}if (decoder_ctx){avcodec_free_context(&decoder_ctx);decoder_ctx = nullptr;}if (out_fmt_ctx){avformat_free_context(out_fmt_ctx);out_fmt_ctx = nullptr;}if (in_fmt_ctx){avformat_free_context(in_fmt_ctx);in_fmt_ctx = nullptr;}
}
performance


相关文章:
ffmpeg更改视频的帧率
note 视频帧率调整 帧率(fps-frame per second) 例如:原来帧率为30,调整后为1 现象:原来是每秒有30张图像,调整后每秒1张图像,看着图像很慢 实现:在每秒的时间区间里,取一张图像…...
设计模式13-单件模式
设计模式13-单件模式 写在前面对象性能模式典型模式1. 单例模式(Singleton Pattern)2. 享元模式(Flyweight Pattern)3. 原型模式(Prototype Pattern)4. 对象池模式(Object Pool Pattern…...
怎么给PDF文件加密码?关于PDF文件加密的四种方法推荐
怎么给PDF文件加密码?给PDF文件加上密码是保护文件安全的一种重要方法,特别是当需要在不受授权的访问下保护敏感信息时。这个过程不仅仅是简单地设置密码,而是涉及到对文档内容和访问控制的深思熟虑。加密PDF文件可以有效防止未经授权的用户查…...
GoFly快速开发框架基于Go语言和Vue3开发后台管理附件管理插件包
说明 为了给客户提供更好的交互体验,框架把附件管理独立打包成插件包,这样附件管理接可以做个不通需求的附件管理插件包来满足不同甲方客户需求。 目前附件插件包有2个:一个基础包、一个高级包 附件插件包功能 1.基础包 统一管理业务系统…...
matlab实验:实验六MATLAB 数值计算与符号运算
题目1:(线性方程组数值求解) 1. 用不同的方法求解下面方程:(方程原式参考 P369 实验 10,第 1 题) 第 1 种,左除和求逆函数(inv) 第 2 种 , 用 符 号 运 算 的…...
基于STM32设计的老人摔倒检测系统(4G+华为云IOT)(193)
文章目录 一、前言1.1 项目介绍【1】项目功能介绍【2】项目硬件模块组成1.2 设计思路【1】整体设计思路【2】整体构架【3】上位机开发思路【4】供电方式1.3 项目开发背景【1】选题的意义【2】可行性分析【3】参考文献【4】课题研究的意义【5】国内外技术发展现状【6】课题研究思…...
PyTorch和TensorFlow概念及对比
PyTorch和TensorFlow是两个流行的深度学习框架,用于构建和训练机器学习和深度学习模型。它们各自有一些独特的特点和优点: 一 、PyTorch 动态计算图: PyTorch使用动态计算图(Dynamic Computation Graph),…...
github的Codespaces是什么
目录 github的Codespaces是什么 一、定义与功能 二、特点与优势 三、工作原理 四、使用场景与限制 github的Codespaces是什么 GitHub的Codespaces是一个基于云的即时开发环境,它利用容器技术为开发者提供一个完全配置好的开发环境,以便他们能够直接在浏览器或通过Visua…...
Unity UGUI 之 图集
本文仅作学习笔记与交流,不作任何商业用途 本文包括但不限于unity官方手册,唐老狮,麦扣教程知识,引用会标记,如有不足还请斧正 本文在发布时间选用unity 2022.3.8稳定版本,请注意分别 1.什么是图集 精灵图…...
rust日常提问
rust 如何为类 添加一个函数 举例说明 在 Rust 中,我们通常使用 struct(结构体)来创建类似其他语言中的类(class)。Rust 中的结构体可以拥有关联函数(associated functions),这些函数…...
Vue3与Element-plus配合 直接修改表格中的一项数据——控制输入框的显示与隐藏
利用控制与隐藏输入框,直接修改表格中的每一项数据。 <!-- 表格模块 --> <div><el-table :data"tablelist" style"width: 100%"><el-table-column align"center" prop"deposit" label"接单押金">&l…...
设计模式--创建型
实现 #include <iostream> #include <memory>// 抽象产品类 class Product {public:virtual ~Product() {}virtual void Operation() const 0; };// 具体产品 类A class ConcreteProductA : public Product {public:virtual void Operation() const override {st…...
Vue3时间选择器datetimerange在数据库存开始时间和结束时间
♥️作者:小宋1021 🤵♂️个人主页:小宋1021主页 ♥️坚持分析平时学习到的项目以及学习到的软件开发知识,和大家一起努力呀!!! 🎈🎈加油! 加油!…...
鼠标移入事件 mouseover
<template><div><div mouseover"handleMouseOver">区域1</div></div> </template><script> export default {methods: {handleMouseOver() {console.log(鼠标悬停在区域1);}} } </script>...
UE4 自动换行——按排序关键字1.2.3.
要自动换行的字符串举例:“有效节点为:1.demo-worker-02 2.demo-worker-01 3.demo-master-01” 1.获取相邻两位字符串,组合后与关键字比较 2.当两位字符串与关键字相等,附加一次换行 3.其他例如 1)2)3)、(1)(2)(3)、<1><2><…...
Object.entries()解析出来的数组顺序乱了,健是string类型
现象: 从后端哪里拿到了一长串数据 const obj {"2023-07-01":10,"2023-09-18":2,"2023-10-10":3,"2024-01-10":1,"2024-01-12":1,"2024-02-20":4,"2024-07-01":4,... }; 比如上面的数据有一年的 并…...
SSM(Spring + Spring MVC + MyBatis)框架面试三道题
以下是三道关于SSM(Spring Spring MVC MyBatis)框架的面试题,由简单到困难进行排列: 1. 简答题:请简述Spring框架的核心特性。 答案: Spring框架的核心特性主要包括以下几个方面: 控制反转…...
ctfshow-web入门-php特性(web132-web136)
目录 1、web132 2、web133 3、web134 4、web135 5、web136 1、web132 存在 robots.txt 访问 /admin 需要传三个参数,并且需要满足: if($code mt_rand(1,0x36D) && $password $flag || $username "admin"){if($code admin){ech…...
通信原理-实验六:实验测验
实验六 实验测验 一:测验内容和要求 测试需要完成以下几个步骤: 配置好以下网络图;占总分10%(缺少一个扣一分)根据下面图配置好对应的IP和网关以及路由等相关配置,保证设备之间连通正常;占总…...
意得辑润色新用户注册直减15%
ABSJU202 优惠了很多...
英雄联盟智能助手Seraphine:免费开源的战绩查询与BP辅助神器
英雄联盟智能助手Seraphine:免费开源的战绩查询与BP辅助神器 【免费下载链接】Seraphine 英雄联盟战绩查询工具 项目地址: https://gitcode.com/gh_mirrors/se/Seraphine 还在为错过对局接受而懊恼吗?还在BP阶段犹豫不决错失最佳英雄选择吗&#…...
终极英雄联盟换肤工具:R3nzSkin国服特供版完整使用教程
终极英雄联盟换肤工具:R3nzSkin国服特供版完整使用教程 【免费下载链接】R3nzSkin-For-China-Server Skin changer for League of Legends (LOL) 项目地址: https://gitcode.com/gh_mirrors/r3/R3nzSkin-For-China-Server 想要在英雄联盟国服免费体验所有皮肤…...
比特币钱包密码恢复终极指南:如何找回丢失的密码和助记词
比特币钱包密码恢复终极指南:如何找回丢失的密码和助记词 【免费下载链接】btcrecover An open source Bitcoin wallet password and seed recovery tool designed for the case where you already know most of your password/seed, but need assistance in trying…...
QtScrcpy终极指南:如何免费实现高清Android投屏与多设备控制
QtScrcpy终极指南:如何免费实现高清Android投屏与多设备控制 【免费下载链接】QtScrcpy Android实时投屏软件,此应用程序提供USB(或通过TCP/IP)连接的Android设备的显示和控制。它不需要任何root访问权限 项目地址: https://gitcode.com/barry-ran/QtS…...
Flutter项目构建提速:告别‘gradle assembleDebug’卡顿的实战配置指南
1. 为什么Flutter项目构建会卡在gradle assembleDebug? 每次看到Android Studio卡在"Running Gradle task assembleDebug..."这个界面,我都忍不住想砸键盘。作为一个踩过无数坑的老Flutter开发者,我完全理解这种痛苦。其实这个问题…...
Python图像转二维数组:PIL与NumPy实战指南
1. 项目概述:从图片到数据的桥梁在图像处理、机器学习或者嵌入式开发的很多场景里,我们常常需要将一张图片“翻译”成计算机能直接理解和运算的数字形式。比如,你想分析一张照片的亮度分布,或者把一个简单的图标转换成单片机可以显…...
开源机械爪资源宝库:从入门到进阶的完整实践指南
1. 项目概述:一个为开源“机械爪”而生的资源宝库如果你对机器人、自动化或者开源硬件感兴趣,最近又在琢磨着给自己的项目加个能抓取、能操作的“手”,那么你很可能已经听说过或者正在寻找“OpenClaw”相关的资料。vincentkoc/awesome-opencl…...
ARM TLBIP指令解析与应用实践
1. ARM TLBIP指令深度解析在ARMv8/v9架构中,TLB(Translation Lookaside Buffer)作为内存管理单元(MMU)的核心组件,负责缓存虚拟地址到物理地址的转换结果。当页表发生变更时,必须及时使TLB中对应的缓存条目失效,以确保内存访问的正…...
高途CFO沈楠辞职 高级副总裁罗斌晋升为首席运营官
雷递网 乐天 5月15日高途(NYSE: GOTU)日前宣布管理层调整。高途称,公司CFO沈楠由于个人原因已递交辞呈,2026年5月31日生效。沈楠辞职后三个月内继续担任公司顾问,以确保平稳过渡。高途战略主管徐步青将负责公司资本市场相关事宜,高…...
基于ChatGPT的智能网页数据抓取:原理、实践与成本优化
1. 项目概述:当ChatGPT遇上网页抓取最近在做一个数据驱动的项目,需要从几十个不同结构的网站上抓取产品信息,手动复制粘贴显然不现实,而传统的爬虫脚本又需要为每个网站单独写解析规则,费时费力。就在我头疼的时候&…...
