当前位置: 首页 > news >正文

FFmpeg——视频拼接总结

最近需要做一个关于视频拼接的内容,需要将两个视频合成一个视频,使用opencv的话需要将视频读上来然后再写到文件了,这个会很消耗时间也没有必要。两个视频的编码格式是一样的,并不需要转码操作所以想法是直接将视频流补到后面,这样可以直接省去加解码操作。在查找了ffmpeg资料后发现是支持这么做的,但是必须要将文件一一打开然后复制到另一个文件中,资料中有很多中说法concat demuxer(解复用,这个其实不太理解什么意思,但是看说明就是利用一个txt文件将需要进行拼接的文件列在这个txt中,然后一一去处理,做一个流的拷贝)。FFmpeg功能强大唯一不好的一点是大部分都是使用命令行的操作,编程相关的内容少的可怜,而且很不全面,后面找了好久都没找到很完整的内容,需要自己一点一点去找和试,其中有几个不错的参考。一个是一本新上来的书,他有随书代码可以参考“ffmpeg从零基础到短视频上线”,这个里面的示例还是挺多的,感觉也挺实用的。还有就是官方的github代码以及“https://github.com/0voice/ffmpeg_develop_doc”这个网址下有很多的参考资料。这几个是我能找到相对较全并且内容也比较实用的资料了,剩下的基本上都是命令行之类的我用不到就先忽略。

这里主要记录一下完整的视频流拷贝代码,网上想找一个比较完整的代码好难,这个代码用于提供参考以及后面自己回顾。

这里就以两个文件为例进行合并,并且只转换其中的视频流。

vector<string> fileList = { url_origin,url_add };//这是两个文件
//获得原始输入视频文件编码等信息
const AVOutputFormat* ofmt = NULL;//输出格式
AVFormatContext* ifmt_ctx = NULL, * ofmt_ctx = NULL;//视频数据维护对象
AVPacket* pkt = NULL;//数据包int ret;//函数执行返回码
int stream_index;//数据流索引pkt = av_packet_alloc();//初始化数据包结构
if (!pkt)
{return;
}if ((ret = avformat_open_input(&ifmt_ctx, url_origin, 0, 0) < 0))
{goto end;//打开文件失败
}//获得输出文件名
string out_file;
auto name = ifmt_ctx->iformat->name;//自动识别文件的封装类型
//hevc只能使用MP4或者hevc封装才能完成转换,其余封装报错,因为这里进行了自动识别可以不用管具体格式
out_file.replace(out_file.find('.')+1, 3, name);
const char* out_filename = out_file.c_str();//根据第一个文件获得其中的编码等参数,这里要求两个文件的编码格式一样就是因为在写入文件时用的是相同的配置没有进行转码等操作
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0)
{goto end;
}avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
if (!ofmt_ctx)
{goto end;
}ofmt = ofmt_ctx->oformat;
//查找视频流并复制视频流的参数到输出流
for (int i = 0; i < ifmt_ctx->nb_streams; ++i)
{AVStream* in_stream = ifmt_ctx->streams[i];AVCodecParameters* in_codecpar = in_stream->codecpar;if (in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO)//非视频流跳过{continue;}AVStream* out_stream = avformat_new_stream(ofmt_ctx, NULL);//创建输出流if (!out_stream){goto end;}ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);//复制解码器参数if (ret < 0){goto end;}out_stream->time_base = in_stream->time_base;//复制时间基stream_index = i;out_stream->codecpar->codec_tag = 0;break;
}
avformat_close_input(&ifmt_ctx);//关闭文件//打开输出文件
if (!(ofmt->flags & AVFMT_NOFILE))
{ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);if (ret < 0){goto end;}
}ret = avformat_write_header(ofmt_ctx, NULL);//写入头信息,如编码等内容
if (ret < 0)
{goto end;
}int64_t i = 0;//用于计算时间戳,同时也是帧数
int64_t p_max_dts = 0;//用于拼文件的时间戳for (int index = 0; index < fileList.size(); ++index)//遍历文件
{if ((ret = avformat_open_input(&ifmt_ctx, fileList[index].c_str(), 0, 0)) < 0){goto end;}if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0)//查找文件流信息{goto end;}//对流直接进行转写while (1){AVStream* in_stream, * out_stream;ret = av_read_frame(ifmt_ctx, pkt);if (ret < 0){break;}pkt->stream_index = stream_index;//视频流编号//这里做一个提示,因为上述的例子只有视频没有音频所以不会越界,如果存在多种流的这里需要看一下你new了几个流,是否会越界in_stream = ifmt_ctx->streams[stream_index];out_stream = ofmt_ctx->streams[stream_index];//这里要对时间戳进行处理,否则写入的时候会失败//单帧时长int64_t frameDuration = av_rescale_q(1, av_inv_q(in_stream->time_base), in_stream->r_frame_rate);//将单帧的时间从输入流转化到输出流时间int64_t _t = av_rescale_q(frameDuration, in_stream->time_base, out_stream->time_base);//计算时间戳,并进行累计以推算后面的时间戳p_max_dts = _t * (i);pkt->dts = p_max_dts;pkt->pts = pkt->dts;//如果音视频都需要写入可能需要这个函数:av_interleaved_write_frame,他会进行交叉写入//pkt现在是空的,这个函数会获得pkt内容的所有权并重置,因此不需要unref,但是write_frame情况不同,需要手动释放ret = av_write_frame(ofmt_ctx, pkt);//直接将包写入输出文件不进行解码av_packet_unref(pkt);if (ret < 0){break;}++i;}//关闭文件avformat_close_input(&ifmt_ctx);
}av_write_trailer(ofmt_ctx);//写文件尾end:av_packet_free(&pkt);//这里传指针,因为要将pkt设为nullavformat_close_input(&ifmt_ctx);//同理if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE)){avio_closep(&ofmt_ctx->pb);//avio打开要释放}avformat_free_context(ofmt_ctx);if (ret < 0 && ret != AVERROR_EOF){return;//异常结束}

这个示例可以完成视频流的复制拼接,是一个比较简单的示例,要求文件编码等信息必须一致,不进行转码,速度比较快。

相关文章:

FFmpeg——视频拼接总结

最近需要做一个关于视频拼接的内容&#xff0c;需要将两个视频合成一个视频&#xff0c;使用opencv的话需要将视频读上来然后再写到文件了&#xff0c;这个会很消耗时间也没有必要。两个视频的编码格式是一样的&#xff0c;并不需要转码操作所以想法是直接将视频流补到后面&…...

springboot项目怎么样排除自带tomcat容器使用宝蓝德bes web中间件?

前言&#xff1a; 由于Spring Boot 1.x和2.x不兼容&#xff0c;BES提供了对应的Spring Boot Starter版本。 bes‑lite‑spring‑boot‑1.x‑starter.jar&#xff0c;适用于Spring Boot 1.x的版本。 bes‑lite‑spring‑boot‑2.x‑starter…...

响应式ref()和reactive()

文章目录 ref()reactive()ref对比reactivetoRefs与toRef ref() 作用&#xff1a;定义响应式变量。 语法&#xff1a;let xxxref(初始值)。 返回值&#xff1a;一个RefImpl的实例对象&#xff0c;简称ref对象或ref&#xff0c;ref对象的value属性是响应式的 注意点&#xff1…...

运维系列.Nginx中使用HTTP压缩功能

运维专题 Nginx中使用HTTP压缩功能 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550…...

vue3项目图片压缩+rem+自动重启等plugin使用与打包配置

一、Svg配置 每次引入一张 SVG 图片都需要写一次相对路径&#xff0c;并且对 SVG 图片进行压缩优化也不够方便。 vite-svg-loader插件加载SVG文件作为Vue组件&#xff0c;使用SVGO进行优化。 插件网站https://www.npmjs.com/package/vite-svg-loader 1. 安装 pnpm i vite-svg…...

数据库性能优化系统设计

设计一个数据库性能优化系统&#xff0c;目标是监测、诊断并改善数据库的运行效率&#xff0c;确保系统能够高效稳定地处理大量数据请求。以下是一个概要设计&#xff0c;包括关键模块、功能和实现思路&#xff1a; 1. 系统架构 分布式监控中心&#xff1a;采用分布式架构收集…...

MyBatisPlus-分页插件的基本使用

目录 配置插件 使用分页API 配置插件 首先&#xff0c;要在配置类中注册MyBatisPlus的核心插件&#xff0c;同时添加分页插件。&#xff08;可以放到config软件包下&#xff09; 可以看到&#xff0c;我们定义了一个配置类&#xff0c;在配置类里声明了一个Bean,这个Bean的名…...

深入探索Python库的奇妙世界:赋能编程的无限可能

在编程的浩瀚宇宙中&#xff0c;Python以其简洁的语法、强大的功能和广泛的应用领域&#xff0c;成为了众多开发者心中的璀璨明星。而Python之所以能够如此耀眼&#xff0c;很大程度上得益于其背后庞大的库生态系统。这些库&#xff0c;如同一块块精心雕琢的积木&#xff0c;让…...

力扣爆刷第161天之TOP100五连刷71-75(搜索二叉树、二维矩阵、路径总和)

力扣爆刷第161天之TOP100五连刷71-75&#xff08;搜索二叉树、二维矩阵、路径总和&#xff09; 文章目录 力扣爆刷第161天之TOP100五连刷71-75&#xff08;搜索二叉树、二维矩阵、路径总和&#xff09;一、98. 验证二叉搜索树二、394. 字符串解码三、34. 在排序数组中查找元素的…...

你真的了解Java内存模型JMM吗?

哈喽&#xff0c;大家好&#x1f389;&#xff0c;我是世杰。 本文我为大家介绍面试官经常考察的**「Java内存模型JMM相关内容」** 面试连环call 什么是Java内存模型(JMM)? 为什么需要JMM?Java线程的工作内存和主内存各自的作用?Java缓存一致性问题?Java的并发编程问题? …...

Springboot整合Jsch-Sftp

背景 开发一个基于jsch的sftp工具类&#xff0c;方便在以后的项目中使用。写代码的过程记录下来&#xff0c;作为备忘录。。。 Maven依赖 springboot依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-par…...

生成随机的验证码图片(Python)

文章目录 一、导入包二、生成随机的验证码三、生成随机的rgb颜色四、生成图片验证码总结&#xff1a; 一、导入包 import random from PIL import Image, ImageDraw, ImageFont二、生成随机的验证码 def random_code(length4):默认返回4位随机验证码&#xff0c;字符串code …...

0/1背包问题总结

文章目录 &#x1f347;什么是0/1背包问题&#xff1f;&#x1f348;例题&#x1f349;1.分割等和子集&#x1f349;2.目标和&#x1f349;3.最后一块石头的重量Ⅱ &#x1f34a;总结 博客主页&#xff1a;lyyyyrics &#x1f347;什么是0/1背包问题&#xff1f; 0/1背包问题是…...

模电基础 - 放大电路的频率响应

目录 一. 简介 二. 频率响应的基本概念 三. 波特图 四. 晶体管的高频等效模型 五. 场效应管的高频等效模型 六. 单管放大电路的频率响应 七.多级放大电路的频率响应 八. 频率响应与阶跃响应 一. 简介 放大电路的频率响应是指在输入不同频率的正弦信号时&#xff0c;电路…...

Java 8 到 Java 22 新特性详解

Java 8 到 Java 22 新特性详解 Java自发布以来一直在不断演进&#xff0c;添加新特性以提升开发效率和性能。本文将介绍Java 8到Java 22的主要新特性&#xff0c;帮助开发者了解各版本的新功能和改进。 Java 8 (2014) 1. Lambda 表达式 Lambda 表达式允许使用简洁的语法定义…...

华为OD机试题-提取字符串中最长数学表达式

题目描述 https://blog.csdn.net/weixin_51055612/article/details/139841128 题目描述 提取字符串中的最长合法简单数学表达式&#xff0c;字符串长度最长的&#xff0c;并计算表达式的值。如果没有&#xff0c;则返回0。 简单数学表达式只能包含以下内容&#xff1a;0-9数字&…...

专家指南:如何为您的电路选择理想的压敏电阻或热敏电阻

保护和维持电路功能需要两种设备&#xff1a;压敏电阻和热敏电阻。这两个电气元件有时会因后缀相似而混淆&#xff0c;但它们具有不同且重要的用途。 由于这种混淆&#xff0c;我们需要准确地了解这些组件是什么&#xff0c;这就是本文将要讨论的内容——应用程序、作用、优点…...

基于主流SpringBoot进行JavaWeb开发的学习路线

目录 一、学习路线 &#xff08;1&#xff09;第一部分&#xff08;Web前端开发的技术栈&#xff09; &#xff08;2&#xff09;第二部分&#xff08;Web后端开发&#xff09; 二、学习之后必备的技能 三、学习Web开发的基础与未来的收获 学完这一类知识目标&#xff1a;…...

医疗机器人中的具身智能进展——自主超声策略模型的任务编码和局部探索

医疗机器人一直是具身智能的研究热点。医学图像、医疗触诊、血压血氧、心率脉搏和生物电信号等多模态生物医学信息&#xff0c;不断丰富着医疗机器人的感知范畴。 自主超声 “自主超声”属于具身智能医疗机器人领域中话题度较高的研究方向。作为临床检查的重要手段之一&#…...

探索人工智能在电子商务平台与游戏发行商竞争中几种应用方式

过去 12 年来&#xff0c;电脑和视频游戏的发行策略发生了巨大变化。数字游戏的销量首次超过实体游戏的销量 在20132020 年的封锁进一步加速了这一趋势。例如&#xff0c;在意大利&#xff0c;封锁的第一周导致数字游戏下载量 暴涨174.9%. 展望未来&#xff0c;市场有望继续增…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...