type
Post
status
Published
date
Dec 30, 2022
slug
summary
ffmpeg比想象中难懂很多
tags
python
ffmpeg
category
探索新世界
icon
password

引子

我需要实现一个功能
就是把一些段的视频片段批量打乱并且剪在一起
并不要求逻辑性以及完整性
找了很久都没有相关的轮子
我想也是
这个需求确实比较古怪
所以只好自己重新造轮子

大致思路

怎样才能把视频片段打散呢?
  1. 我想先把视频合并成一个完整的整体,然后导出一个长视频。这样的话,至少不会存在格式之间的冲突。
  1. 从中截取一些固定时长的小段落,比如10秒一个。
  1. 随机选择片段并且进行合并。

实现方法

安装ffmpeg

视频处理这方面还是绕不过ffmpeg
mac的话使用brew可以直接安装:
brew install ffmpeg
安装过程不是那么顺利,网络需要比较稳定。还有叫做gcc的依赖不能安装,根据提示下载了开发者工具才装上。
如果是win的话,安装过程相对来说是要简单一些。可以直接去ffmpeg的官网下载,然后在环境变量添加变量就行。

安装ffmpy

这是pyhton的一个库,可以使用python对ffmeg进行调用,使用pip直接安装即可:
pip install ffmpy

分割视频

这里参照了知乎上的一篇文章,讲的非常清楚。
我按照操作写了代码:
split_video=ffmpy.FFmpeg( inputs={'test.mov': None}, outputs={'test.mov': [ '-ss', '00:00:00', '-t', '120', '-vcodec', 'copy', '-acodec', 'copy' ]} split_video.run()
以上代码可以成功的运行,并且路径可以采用绝对路径。
上述代码运行之后,则是把视频从最开始裁截一段长为120秒的视频。如果我需要批量裁剪,那么就需要加上一个循环,每次都更新裁剪的起点-ss 参数的数值。而裁剪的长度-t 数值则可以固定不变为需要的长度。
所以我需要一个可以方便计算时间的函数。

计算时间

我参照了这篇博客
这里面使用了一个datetime 的库
里面有几点比较重要
  • strptime可以输入字符串转换成一个日期实例,起到自定义时间。不需要输入所有的数值,如果只输入时、分,那么年、月、日就是默认的数值。
  • timedelta 可以对时间进行加减。
  • strftime 可以格式化输出字符串,例如只输出年月日,或者调整输出顺序等。
于是我写了如下代码:
def time_adjust(complete_time:str,split_time:int): split_point_l=['00:00:00'] # 总时间的实例 complete_time_t=datetime.datetime.strptime(complete_time,'%H:%M:%S') # 初始时间的实例 start_time_t=datetime.datetime.strptime('00:00:00','%H:%M:%S') # 开始循环 while start_time_t<complete_time_t: # 更新后的时间 new_time_t=(start_time_t+datetime.timedelta(seconds=split_time)) # 赋予新的开始时间 start_time_t=new_time_t split_point_l.append(new_time_t.strftime('%H:%M:%S')) # 舍弃列表最后一个元素,并计算出最后还剩多少 split_point_l=split_point_l[:-1] # 计算最后跟总时间差多少秒 gap_time_t=complete_time_t-datetime.datetime.strptime(split_point_l[-1],'%H:%M:%S') final_time=(datetime.datetime.strptime('00:00:00','%H:%M:%S')+gap_time_t).strftime('%H:%M:%S') return split_point_l,final_time
这两天有点头晕,写的有点乱。
不过实现的功能就是,输入视频的总时间,和预期每个视频的长度,最后输出一个列表和一个字符串。
这个列表包括了所有即将被分割的小视频的时间点,而字符串则是代表最后一个视频的长度(因为基本上不可能完美的分割每一个视频,最后一个视频肯定会不够设定的时长。)

输出视频时间

以上的函数可以对输入的文件时长计算时间点,那么能不能自动获取视频文件的时长呢?
我看网上很多多说只需要
ffmpeg -i test.mov
在命令行下确实会输出相关的信息,以及一个报错提示(大概是没有指定输出还是什么意思)
但是在ffmpy的调用下就会报错,而且不能传出任何信息
所以我参考了知乎上一位给的代码。
def get_video_duration(filename): cap = cv2.VideoCapture(filename) if cap.isOpened(): rate = cap.get(5) frame_num =cap.get(7) duration = frame_num/rate return duration return -1
虽然看不明白,但确实可以正确的输出。输出的是视频的秒数,再调用datetime转成正确的格式即可。

循环分割视频

因为已经有了时间点的列表,所以继续写了循环分割视频的代码:
def split(complete_time:str,split_time:int=10): split_point_l,final_time=time_adjust(complete_time,split_time) # 制作一个每次切割时间的列表 split_time_l=[split_time]*(len(split_point_l)-1) split_time_l.append(final_time) print(len(split_point_l)) # 输出分割视频的数量 # 开始循环 i=0 for v1,v2 in zip(split_point_l,split_time_l): i+=1 split_video= ffmpy.FFmpeg( inputs={'test.mov': None}, outputs={'%d.mov'%i: [ '-ss', '%s'%v1, '-t', '%s'%v2, '-vcodec', 'copy', '-acodec', 'copy' ]} ) split_video.run() return
以上代码实现的效果是,输入完整的时长和分割的长度,就会自动循环分割视频。

合并视频

上文中知乎作者的一篇文章中,已经提到了如何合并视频。
不过是采用创建临时文件的方式。
def concat(): concat = ffmpy.FFmpeg( global_options=['-f', 'concat','-safe 0'], inputs={'file_l.txt': None}, outputs={'output.mov': ['-c', 'copy']} ) concat.run() return
以上的代码我稍微做了一定的调整,在合并之前先随机生成一个txt文件即可。
💡
这里有一个非常重要的点,让我卡了很久。 txt文件里面如果放着是文件的相对路径,是可以顺利读取并合并的。 但如果是绝对路径则不行。 我一开始以为是斜杠转义之类的问题,研究了很久。 后来在b站的一篇文章上找到了答案。 需要在参数中添加'-safe 0' ,同时txt中的文件路径需要用'' 进行包围。 我在windows的系统下做测试,所以路径都是反斜杠,不知道别的平台需不需要。

批量调整音量

视频之间会存在一个音量不统一的情况,观看的效果是非常差的。
我参照了下面up主在fcpx的设置。
(简单粗暴)fcpx批量统一音量,学会这个,一万条音频也可以搞定,_哔哩哔哩_bilibili
这是简单粗暴的做法,对于想快速出片的童鞋,当然会有美中不足,但是各取所需吧!, 视频播放量 9527、弹幕量 13、点赞数 239、投硬币枚数 143、收藏人数 593、转发人数 41, 视频作者 阿坚的课, 作者简介 阿坚的课,后期剪辑课程-fcpx VX:15346110106,相关视频:如何调整BGM俐落收尾,不要再淡入淡出! 配乐音频音量要多大才对?|FCPX教学第11集,FINAL CUT正确音量设定教程|让音量平衡、声音更好听|Final Cut Pro X完全制霸 第五集,【极度干货】环境噪音大?一招拯救音频让人声更清晰!,Final Cut后期声音处理,3步让你的声音更好听,快速提高声音质量,up主必看,「托尼明一」FCPX必备 高效质感插件分享4.0 背景字幕 人名条 电影片头 抖动毛刺特效 MV制作,【Pr新手教程】004 声音的处理 | 去除原声 | 调整音量大小 | 快速统一音量 | 局部调整音量大小 | 干货视频剪辑教程,FCPX自动动态音频平衡插件 一键解决你声音忽大忽小问题,AU新手教程 干音处理 第一步声音均衡,「音频教程」FCPX自带两款插件快速优化人声,让你的声音更好听,【声音要妙只需一招】音频降噪、去口水音、去嘶声
(简单粗暴)fcpx批量统一音量,学会这个,一万条音频也可以搞定,_哔哩哔哩_bilibili

流程总结

所有的操作已经理顺了,最后把流程理一遍,方便自己记住。
  1. 首先把视频全部导入fcpx,然后批量调整音量。
  1. 筛选、剪辑最后导出视频。
  1. 在handbrake中进行压缩,并转换成mp4格式的文件。
  1. 启动程序进行分割。
  1. 移动到NAS中的固定文件夹,以方便合并程序调用。
  1. 根据需要随机合并视频。

最后

ffmpeg实在是太难懂了
我以为看看官方的文档就可以掌握
事实上都是借助网上的中文资料才学会一些操作
「2022-12月」明基-halo终于被我拔草