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 优惠了很多...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...

【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
[USACO23FEB] Bakery S
题目描述 Bessie 开了一家面包店! 在她的面包店里,Bessie 有一个烤箱,可以在 t C t_C tC 的时间内生产一块饼干或在 t M t_M tM 单位时间内生产一块松糕。 ( 1 ≤ t C , t M ≤ 10 9 ) (1 \le t_C,t_M \le 10^9) (1≤tC,tM≤109)。由于空间…...

使用VMware克隆功能快速搭建集群
自己搭建的虚拟机,后续不管是学习java还是大数据,都需要集群,java需要分布式的微服务,大数据Hadoop的计算集群,如果从头开始搭建虚拟机会比较费时费力,这里分享一下如何使用克隆功能快速搭建一个集群 先把…...

机器学习复习3--模型评估
误差与过拟合 我们将学习器对样本的实际预测结果与样本的真实值之间的差异称为:误差(error)。 误差定义: ①在训练集上的误差称为训练误差(training error)或经验误差(empirical error&#x…...

React、Git、计网、发展趋势等内容——前端面试宝典(字节、小红书和美团)
React React Hook实现架构、.Hook不能在循环嵌套语句中使用 , 为什么,Fiber架构,面试向面试官介绍,详细解释 用户: React Hook实现架构、.Hook不能在循环嵌套语句中使用 , 为什么,Fiber架构,面试向面试官介绍&#x…...