基于ffmepg的视频剪辑

1.ffmpeg命令实现视频剪辑

  FFmpeg是一个非常强大的视频处理工具,可以用来剪辑视频。以下是一个基本的FFmpeg命令行示例,用于剪辑视频:

$ ffmpeg -i ./最后一滴水.mp4  -ss 0:0:20  -t 50  -c copy output.mp4

  -i ./最后一滴水.mp4 输入文件
  -ss 0:0:20 剪辑的起始时间20s
  -t 50 剪辑的时长50s,也可以写成时分秒格式:00:00:50
  -c copy 复制编码以避免重编码,加快处理速度。
  output.mp4 输出文件

2.调用ffmpeg库实现视频剪辑

  • 音视频裁剪步骤

  (1)打开源媒体文件avformat_open_input
  (2)读取数据包,获取流信息avformat_find_stream_info,输出流信息av_dump_format
  (3)创建输出上下文avformat_alloc_output_context2
  (4)获取源文件中的流数据,拷贝到目标文件avcodec_parameters_copy
  (5)打开输出文件上下文avio_open
  (6)写入头数据avformat_write_header
  (7)设置到剪切的位置av_seek_frame
  (8)循环读取数据跑av_read_frame,对读取的数据包时间转换av_packet_rescale_ts,写入到目的媒体文件av_interleaved_write_frame
  (9)判断截取的尾时间av_q2d(istream->time_base)*pkt.pts >= end_time
  (10)写入文件尾数据av_write_trailer
  (11)释放资源

  • 流程图如下:
    在这里插入图片描述
#include <stdio.h>
#include <libavutil/avutil.h>
#include <libavutil/timestamp.h>
#include <libavutil/rational.h>
#include <libavformat/avformat.h>
#include <stdlib.h>//音视频裁剪
int main(int argc,char **argv)
{av_log_set_level(AV_LOG_DEBUG);if(argc!=5){av_log(NULL,AV_LOG_INFO,"格式:./app <源文件> <目标文件> <起始时间> <结束时间>\n");return 0;}char *src=argv[1];//源文件char *dst=argv[2];//目标文件double start_time=atof(argv[3]);//起始时间double end_time=atof(argv[4]);//结束时间av_log(NULL,AV_LOG_INFO,"start=%.1f\t end=%.1f\n",start_time,end_time);if(end_time<=start_time){av_log(NULL,AV_LOG_ERROR,"裁剪的结束时间应大于起始时间\n");return 0;}//1.打开源媒体文件AVFormatContext *pfmtctx=NULL;AVFormatContext *ofmtctx=NULL;int64_t *start_time_dts=NULL;//保存每路流的dts起始时间int64_t *start_time_pts=NULL;//保存每路流的pts起始时间int *stream_arr=NULL;//用于保存有效流的下标int ret=avformat_open_input(&pfmtctx, src,NULL,NULL);if(ret!=0){av_log(NULL,AV_LOG_ERROR,"打开源媒体文件失败ret=%s\n",av_err2str(ret));return 0;}//2.读取数据包,获取流信息ret=avformat_find_stream_info(pfmtctx, NULL);if(ret<0){av_log(NULL,AV_LOG_ERROR,"获取流信息失败ret=%s\n",av_err2str(ret));goto _fil;}//输出流信息//av_dump_format(AVFormatContext * ic, int index, const char * url, int is_output)av_log(pfmtctx,AV_LOG_INFO,"文件名:%s\n",pfmtctx->iformat->name);//时长if (pfmtctx->duration != AV_NOPTS_VALUE) {int64_t hours, mins, secs, us;int64_t duration = pfmtctx->duration + (pfmtctx->duration <= INT64_MAX - 5000 ? 5000 : 0);secs  = duration / AV_TIME_BASE;us    = duration % AV_TIME_BASE;mins  = secs / 60;secs %= 60;hours = mins / 60;mins %= 60;av_log(NULL, AV_LOG_INFO, "播放时长:%02"PRId64":%02"PRId64":%02"PRId64".%02"PRId64"\n", hours, mins, secs,(100 * us) / AV_TIME_BASE);} //3.创建目标媒体文件上下文件ret=avformat_alloc_output_context2(&ofmtctx,NULL,NULL, dst);if(ret<0){av_log(NULL,AV_LOG_ERROR,"创建输出媒体文件上下文失败ret=%s\n",av_err2str(ret));goto _fil;}//4.读取源文件的所有流数据stream_arr=av_calloc(pfmtctx->nb_streams, sizeof(int));//用于保存流下标int stream_index=0;for(int i=0;i<pfmtctx->nb_streams;i++){AVStream *istream=pfmtctx->streams[i];//输入流数据AVStream *ostream=NULL;if(istream->codecpar->codec_type!=AVMEDIA_TYPE_VIDEO &&  //视频istream->codecpar->codec_type!=AVMEDIA_TYPE_AUDIO &&  //音频istream->codecpar->codec_type!=AVMEDIA_TYPE_SUBTITLE )  //字幕{stream_arr[i]=-1;//将除此之外的流下标置为-1continue;}stream_arr[i]=stream_index++;//正常流下标从0开始//创建一个输出流ostream=avformat_new_stream(ofmtctx,NULL);if(ostream==NULL){av_log(ofmtctx,AV_LOG_ERROR,"创建输出流失败\n");goto _fil;}//将源文件流数据拷贝到目标文件ret=avcodec_parameters_copy(ostream->codecpar, istream->codecpar);if(ret<0){av_log(ofmtctx,AV_LOG_ERROR,"拷贝流数据失败\n");goto _fil;}istream->codecpar->codec_tag=0;//解码器标志,填0表示由系统决定}//5.打开目标文件ret=avio_open(&ofmtctx->pb, dst,AVIO_FLAG_READ_WRITE);if(ret<0){av_log(ofmtctx,AV_LOG_ERROR,"打开目标文件失败ret=%s\n",av_err2str(ret));goto _fil;}//6.写入文件头数据ret=avformat_write_header(ofmtctx, NULL);if(ret<0){av_log(&ofmtctx,AV_LOG_ERROR,"写入头数据失败err=%s\n",av_err2str(ret));goto _fil;}/*7.设置要截取的起始位置int av_seek_frame(AVFormatContext *s, int stream_index,int64_t timestamp, int flags)形参:s --媒体文件上下文指针stream_index --流下标位置,填-1,时间戳会自动从AV_TIME_BASE单位转换为流特定的时基timestamp --要跳转到的位置,用设置的秒时间*AV_TIME_BASEflags  --查找流数据帧的处理方式,AVSEEK_FLAG_BACKWARD表示向后查找到关键帧(这对视频来说很重要)返回值:成功返回>=0AV_TIME_BASE -->该参数是ffmpeg内部的时间基准,pts、dts 、duration等均需使用该参数转换*/ret=av_seek_frame(pfmtctx,-1,start_time*AV_TIME_BASE ,AVSEEK_FLAG_BACKWARD);if(ret){av_log(&pfmtctx,AV_LOG_ERROR,"跳转到指定位置失败err=%s\n",av_err2str(ret));goto _fil;}start_time_dts=av_calloc(pfmtctx->nb_streams, sizeof(int64_t));start_time_pts=av_calloc(pfmtctx->nb_streams, sizeof(int64_t));for(int i=0;i<pfmtctx->nb_streams;i++){start_time_dts[i]=-1;//将默认值初始化为-1start_time_pts[i]=-1;}//8.从源文件中读取数据流AVPacket pkt;while(av_read_frame(pfmtctx,&pkt)==0){//判断读取的流是否为我们需要的流数据AVStream *istream=pfmtctx->streams[pkt.stream_index];//输入流数据AVStream *ostream=NULL;if(stream_arr[pkt.stream_index]==-1)//不需要的流数据{av_packet_unref(&pkt);//释放包continue;}if(istream->codecpar->codec_type==AVMEDIA_TYPE_VIDEO){av_log(pfmtctx,AV_LOG_INFO,"pts=%.1f s\n",av_q2d(istream->time_base)*pkt.pts);//显示pts时间}if(av_q2d(istream->time_base)*pkt.pts>=end_time)break;//判断是否结束时间到if(start_time_dts[pkt.stream_index]==-1 && pkt.dts>0){start_time_dts[pkt.stream_index]=pkt.dts;//保存截取的起始时间dts}if(start_time_pts[pkt.stream_index]==-1 && pkt.pts>0){start_time_pts[pkt.stream_index]=pkt.pts;//保存截取的起始时间pts}pkt.dts-=start_time_dts[pkt.stream_index];//解码时间戳pkt.pts-=start_time_pts[pkt.stream_index];//显示时间戳if(pkt.pts<pkt.dts){pkt.pts=pkt.dts;//显示时间戳pts>=解码时戳dts}pkt.stream_index=stream_arr[pkt.stream_index];//当前流下标ostream=ofmtctx->streams[pkt.stream_index];//输出流//时间转换:dts、pts、durationsav_packet_rescale_ts(&pkt,istream->time_base, ostream->time_base);pkt.pos=-1;//相对位置av_interleaved_write_frame(ofmtctx, &pkt);av_packet_unref(&pkt);//减少引用次数}//写入文件尾数据av_write_trailer(ofmtctx);_fil:avformat_close_input(&pfmtctx);avformat_free_context(ofmtctx);av_free(start_time_dts);av_free(start_time_pts);av_free(stream_arr);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/46971.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小试牛刀-区块链WalletConnect协议数据解密

目录 1.编写目的 2.工作原理 3.分析过程 3.1 websokcet连接 3.2 连接后的消息 3.3 获取sym_key 3.4 解密数据 Welcome to Code Blocks blog 本篇文章主要介绍了 [WalletConnect协议数据解密] ❤博主广交技术好友&#xff0c;喜欢文章的可以关注一下❤ 1.编写目的 最近在…

matlab y = 1/√x图像和y = 1/x图像

matlab y 1/√x图像和y 1/x图像 y 1/√x与y 1/x绘制结果y√x y 1/√x与y 1/x clc, clear, close all; length 3; axis_len 5;% Create a range of x values x linspace(0.01, length^2, 1000); % Avoid x 0 for 1/√x% Compute the corresponding y values y1 1 .…

链路聚合概述

目录 技术背景&#xff1a; 基本概念&#xff1a; 链路聚合的工作模式&#xff1a; 简介&#xff1a; 1&#xff09;Manual Load-balance&#xff08;手动负载分担&#xff09; 简介&#xff1a; 配置实施&#xff1a; 2&#xff09;LACP&#xff08;链路聚合控制协议&#xff…

银行业务知识全篇(财务知识、金融业务知识)

第一部分 零售业务 1.1 储蓄业务 4 1.1.1 普通活期储蓄(本外币) 4 1.1.2 定期储蓄(本外币) 5 1.1.3 活期一本通 9 1.1.4 定期一本通 10 1.1.5 电话银行 11 1.1.6 个人支票 11 1.1.7 通信存款 13 1.1.8 其他业务规…

守护动物乐园:视频AI智能监管方案助力动物园安全与秩序管理

一、背景分析 近日&#xff0c;某大熊猫参观基地通报了4位游客在参观时&#xff0c;向大熊猫室外活动场内吐口水的不文明行为。这几位游客的行为违反了入园参观规定并可能对大熊猫造成严重危害&#xff0c;已经被该熊猫基地终身禁止再次进入参观。而在此前&#xff0c;另一熊猫…

Go: IM系统技术架构梳理 (2)

概述 整个IM系统的一般架构如下 我们这张图展示了整个IM系统的一般架构可见分为四层那最上面这一层是前端&#xff0c;包括哪些东西呢&#xff1f; 它包括两部分&#xff0c;第一部分是跟用户直接交互的比如说各种IOS APP, 各种安卓 APP还有各种 web APP 在浏览器里面打开的以…

python编程技巧——list计算

1. 两个列表间运算 在Python中&#xff0c;如果你有两个同长度的列表&#xff0c;并且你想要对它们进行元素级别的相减&#xff08;即&#xff0c;第一个列表的每个元素减去第二个列表的对应元素&#xff09;&#xff0c;你可以使用列表推导式或者zip函数来实现。 以下是两种…

centos(或openEuler系统)安装clickhouse集群

192.168.9.60、192.168.9.63、192.168.9.64三台centos&#xff08;或openEuler系统&#xff09;安装clickhouse集群&#xff08;数据分散&#xff0c;不是1主2备&#xff09; 一、安装clickhouse集群 以下操作在每台机器上一摸一样的执行&#xff1a; 关闭防火墙&#xff1a…

WebGL-编译报错,如何定位sendfile报错位置

1&#xff09;WebGL-编译报错&#xff0c;如何定位sendfile报错位置 2&#xff09;设置DepthBufferBits和设置DepthStencilFormat的区别 3&#xff09;Unity打包exe后&#xff0c;游戏内拉不起Steam的内购 4&#xff09;使用了Play Asset Delivery提交版本被Google报错 这是第3…

【Qt+opencv】计时函数与图像变换

文章目录 前言计算时间函数图像变换旋转镜像缩放 总结 前言 在图像处理和计算机视觉的应用中&#xff0c;我们经常需要对图像进行各种变换&#xff0c;如旋转、缩放、剪切等。同时&#xff0c;为了评估算法的性能&#xff0c;我们也需要对代码的执行时间进行精确的测量。OpenC…

前端组件化技术实践:Vue自定义顶部导航栏组件的探索

摘要 随着前端技术的飞速发展&#xff0c;组件化开发已成为提高开发效率、降低维护成本的关键手段。本文将以Vue自定义顶部导航栏组件为例&#xff0c;深入探讨前端组件化开发的实践过程、优势以及面临的挑战&#xff0c;旨在为广大前端开发者提供有价值的参考和启示。 一、引…

R语言画散点图-饼图-折线图-柱状图-箱线图-直方图-曲线图-热力图-雷达图

R语言画散点图-饼图-折线图-柱状图-箱线图-直方图-曲线图-热力图-雷达图 散点图示例解析效果 饼图示例解析效果 折线图示例解析效果 柱状图示例解析效果 箱线图示例解析效果 直方图示例解析效果 曲线图使用 curve() 函数示例效果 使用 plot() 函数示例效果 使用 ggplot2 包绘制…

super和this的作用与区别(java)

目录 &#xff08;一&#xff09;super关键字 &#xff08;1&#xff09;super的作用 &#xff08;2&#xff09;super的用法 2.1&#xff1a;super调用父类成员变量 2.2super调用父类成员方法 &#xff08;3&#xff09;super&#xff08;&#xff09;的使用 (4)super注意…

NAS新品“翻车”后,绿联科技要上市了

在消费电子市场回暖的东风中&#xff0c;又一消费电子知名企业登陆A股。 近日&#xff0c;深圳市绿联科技股份有限公司&#xff08;下称“绿联科技”&#xff09;开启申购&#xff0c;将在创业板上市。本次上市&#xff0c;绿联科技的发行价为21.21元/股&#xff0c;发行数量为…

【.NET全栈】ASP.NET开发Web应用——ADO.NET数据访问技术

文章目录 前言一、ADO.NET基础1、ADO.NET架构2、ADO.NET数据提供者 二、连接数据库1、SqlConnection数据库连接类2、使用SqlConnectionStringBuilder连接字符串3、关闭和释放连接4、在web.config配置文件中保存连接字符串5、连接池技术 三、与数据库交互1、使用SqlCommand操作数…

Node.js 路由

Node.js 路由 介绍 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,它允许开发者使用 JavaScript 编写服务器端代码。Node.js 的一个核心特性是其事件驱动和非阻塞 I/O 模型,这使得它非常适合处理高并发和 I/O 密集型的应用程序。在 Node.js 中,路由是指确定应…

揭秘!Shopee/Lazada自养号测评高效法,三大策略助力商家快速出单

在东南亚电商的版图中&#xff0c;Lazada凭借其庞大的市场覆盖网络及卓越的服务品质&#xff0c;成功吸引了无数商家与消费者的瞩目。然而&#xff0c;对于渴望在Lazada平台上大展宏图的商家而言&#xff0c;出单的难易程度成为了一个值得深入探讨的议题。 一、Lazada出单的挑战…

GNU/Linux - U-BOOT的GPIO command

在嵌入式Linux开发中&#xff0c;先运行的是u-boot&#xff0c;然后再加载Linux内核。 启动时如果设置了u-boot等待时间&#xff0c;在等待时间内&#xff0c;按任意键就会进入u-boot命令行环境。 在u-boot命令行环境下&#xff0c;可以使用gpio命令来操作GPIO。 Synopsis gpi…

MPNN消息传递神经网络

MPNN&#xff08;Message Passing Neural Networks&#xff0c;消息传递神经网络&#xff09;是一种图神经网络&#xff08;GNN&#xff09;的架构&#xff0c;用于处理图结构数据。MPNNs 是一种通用的框架&#xff0c;许多其他图神经网络&#xff08;如GCN, GAT&#xff09;都…

泰迪科技2024年高校(本科/职业院校)大数据实验室建设及大数据实训平台整体解决方案

高校大数据应用人才培养目标 大数据专业是面向信息技术行业&#xff0c;培养德智体美劳全面发展的大数据领域的高素质管理型专门人才&#xff0c;毕业生具备扎实的管理学、经济学、自然科学、技术应用、人文社科的基本理论, 系统深入的大数据管理专业知识和实践能力&#xff0c…