FFmpeg——视频拼接总结

news/2024/8/26 22:52:14/ 标签: ffmpeg, 音视频, c++

最近需要做一个关于视频拼接的内容,需要将两个视频合成一个视频,使用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;//异常结束}

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


http://www.ppmy.cn/news/1475257.html

相关文章

vue3使用Echarts图表生成项目进度甘特图

先看效果 代码展示 <template><h1>项目进度甘特图</h1><div id"app"><!-- Echarts 图表 --><div ref"progressChart" class"progressChart"></div></div> </template><script setup&…

Xcode Playgrounds:探索Swift编程的交互式乐园

Xcode Playgrounds&#xff1a;探索Swift编程的交互式乐园 Xcode是苹果公司为macOS开发的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它提供了一套完整的工具集&#xff0c;用于开发macOS、iOS、watchOS和tvOS应用。在Xcode中&#xff0c;Playgrounds是一个革命性的…

C++中的RTTI(运行时类型识别)的定义

C中的RTTI&#xff08;Runtime Type Identification&#xff0c;运行时类型识别&#xff09;是一种机制&#xff0c;它允许程序在运行时确定对象的实际类型。这是C语言为了支持面向对象编程中的多态性而提供的一个重要特性。RTTI主要通过两个运算符实现&#xff1a;typeid和dyn…

Mac M1安装配置Hadoop+Flink SQL环境

Flink 1.18.1 Hadoop 3.4.0 一、准备工作 系统&#xff1a;Mac M1 (MacOS Sonoma 14.3.1) JDK&#xff1a;jdk1.8.0_381 &#xff08;注意&#xff1a;尽量一定要用JDK8&#xff0c;少用高版本&#xff09; Scala&#xff1a;2.12 JDK安装在本机的/opt/jdk1.8.0_381.jdk/C…

ubuntu安装k8s+docker运行英伟达gpu cuda

安装k8sdocker sealos resetsealos run registry.cn-shanghai.aliyuncs.com/labring/kubernetes-docker:v1.27.7 registry.cn-shanghai.aliyuncs.com/labring/helm:v3.9.4 registry.cn-shanghai.aliyuncs.com/labring/cilium:v1.13.4 --single 英伟达Ubuntu驱动下载地址&…

鸿蒙系统创建签名文件及使用创建签名文件打包并安装

* 第一步 第二步&#xff1a;创建.p12文件&#xff0c;点击New如果有的话就Choose Existing 填好下面信息 点击Next进入到下面界面 开始生成csr文件如下图 点击OK–>Finish 文件保存在了下面目录 第三步 1.访问华为开发者平台&#xff0c;登录开发者账号&#xff0c;进…

重点区域分布式无人机探测防御系统详解

重点区域分布式无人机探测防御系统采用模块化设计&#xff0c;结合先进的传感技术、通信技术和数据处理技术&#xff0c;实现对无人机的高效探测与防御。系统架构由无人机探测模块、数据分析中心、防御与反制模块以及用户交互界面四大部分组成。系统特点包括分布式部署、高灵敏…

目前分布式光纤测温系统的主流架构有哪些?

分布式光纤测温技术的主流架构&#xff0c;历经多个阶段的发展和演变&#xff0c;每种架构都有其独特的特点和优势。回顾过去的发展历程&#xff0c;我们可以看到三种主要架构的演进&#xff0c;每一次创新都在不同程度上推动了技术的进步和市场的发展。 首先&#xff0c;2005…

[Elasticsearch]ES近似实时搜索的原因|ES非实时搜索的原因|ES Near real-time search

Elasticsearch-专栏&#x1f448;️ 往期回顾&#xff1a; ES单一查询定义&#x1f448;️ ES深分页问题&#x1f448;️ ES商城搜索实战&#x1f448;️ ES环境搭建:单节点模式/集群模式&#x1f448;️ ES开启认证&#x1f448;️ 近似实时搜索&#xff08;Near real-t…

光学传感器图像处理流程(一)

光学传感器图像处理流程&#xff08;一&#xff09; 1. 处理流程总览2. 详细处理流程2.1. 图像预处理2.1.1. 降噪处理2.1.2. 薄云处理2.1.3. 阴影处理 2.2. 辐射校正2.2.1. 辐射定标2.2.2. 大气校正2.2.3. 地形校正 2.3. 几何校正2.3.1. 图像配准2.3.2. 几何粗校正2.3.3. 几何精…

切割01串(牛客小白月赛98)

题意&#xff1a; 给三个整数n&#xff0c;l&#xff0c;r&#xff0c;和一个字符串s&#xff0c;满足l<|c0-c1|<r就可以切成字符串a和字符串b&#xff0c;c0为字符串a左侧出现0的次数&#xff0c;c1为字符串b右侧出现1的次数&#xff0c;求最多切割次数 知识点&#x…

HTML5新增的input元素属性:placeholder、required、autofocus、min、max等

HTML5 大幅度地增加与改良了 input 元素的属性&#xff0c;可以简单地使用这些属性来实现 HTML5 之前需要使用 JavaScript 才能实现的许多功能。 下面将详细介绍这些新增的 input 元素的属性。 属性说明属性说明placeholder在输入框显示描述性或提示性文本autocomplete是否保…

Java常用的API_02(正则表达式、爬虫)

Java正则表达式 七、正则表达式7.1 格式7.1.1 字符类注意字符类示例代码1例2 7.1.2 预定义字符预定义字符示例代码例2 7.1.3 区别总结 7.2 使用Pattern和Matcher类与直接使用String类的matches方法的区别。&#xff08;1&#xff09; 使用Pattern和Matcher类示例代码 &#xff…

使用Spring Boot创建自定义Starter

Spring Boot的起步依赖&#xff08;Starter&#xff09;简化了Spring应用的开发&#xff0c;提供了一组默认的库和配置。自定义Starter可以帮助你封装通用功能&#xff0c;便于在多个项目中重用。本文将详细介绍如何创建和使用自定义Spring Boot Starter。 一、什么是Spring B…

springboot增加过滤器后中文乱码

记录一下小问题 public class RepeatableHttpServletWrapper extends HttpServletRequestWrapper {private byte[] body;public RepeatableHttpServletWrapper(HttpServletRequest request) throws IOException {super(request);request.setCharacterEncoding("UTF-8&q…

物联网可编程中央控制主机

物联网可编程中央控制主机&#xff08;Programmable Central Control Host for IoT&#xff0c;如GF-MAXCC&#xff09;在多个领域都有广泛的应用。这些应用领域包括但不限于&#xff1a; 1. 智能家居 GEFFEN在智能家居系统中&#xff0c;物联网可编程中央控制主机充当着家庭…

批量制作word表格

问题背景 将excel表中的成绩内容制作为成绩单&#xff0c;每页对应一个学员的成绩&#xff0c;方便打印 代码实现 ## 导入包 import pandas as pd from docx import Document from docx.enum.text import WD_ALIGN_PARAGRAPH,WD_LINE_SPACING# 读取 Excel 内容 df pd.read_e…

巴基斯坦火爆的slots游戏借力Facebook广告获客优势分析

巴基斯坦火爆的slots游戏借力Facebook广告获客优势分析 在巴基斯坦&#xff0c;Slots游戏凭借其独特的魅力和玩法&#xff0c;深受玩家的喜爱。而在众多的推广渠道中&#xff0c;Facebook广告代投凭借其显著的优势&#xff0c;成为了Slots游戏在巴基斯坦市场推广的重要选择。以…

文心一言使用指南

文心一言使用指南 文心一言是百度推出的一款大语言模型&#xff0c;具备跨模态、跨语言的深度语义理解与生成能力。以下是文心一言的详细使用指南&#xff0c;帮助用户快速上手并充分利用其功能。 一、注册与登录 注册账号&#xff1a; 访问文心一言的官方网站或应用商店&am…

稀疏建模介绍,详解机器学习知识

目录 一、什么是机器学习&#xff1f;二、稀疏建模介绍三、Lasso回归简介四、Lasso超参数调整与模型选择 一、什么是机器学习&#xff1f; 机器学习是一种人工智能技术&#xff0c;它使计算机系统能够从数据中学习并做出预测或决策&#xff0c;而无需明确编程。它涉及到使用算…