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 优惠了很多...
国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
