chenkun372 / blog

my blog 博客搭建的坑,还有自我学习的经验,领悟。
7 stars 1 forks source link

神器 ffmpeg —— 操作视频,极度舒适 #4

Open chenkun372 opened 2 years ago

chenkun372 commented 2 years ago

整体来来看,我们需要从一个目录中读取视频文件,然后,对每个视频文件进行裁剪,最后将处理好的文件保存好。

在这个过程中,最重要的是什么呢?我觉得,是视频裁剪,如果不能方便的裁剪视频,其他的一切工作都是白费的,是吧。

裁剪视频 现在短视频很流行,有很多视频编辑软件,功能丰富,而我们需要的只是裁剪功能,而且需要用编程的方式调用,那么最合适的莫过于 ffmpeg了。

ffmpeg 是一个命令行工具,功能强大,可以编程调用。

从 ffmpeg 官网上下载对应操作系统的版本,我下的是 Windows 版[2]。

下载后解压到一个目录,然后将目录下的 bin,配置到环境变量里。然后打开一个命令行,输入:

ffmpeg -version ffmpeg version 2021-10-07-git-b6aeee2d8b-full_build- ... 测试一下,能显示出版本信息,说明配置好了。

现在读一下文档,发现拆分视频文件的命令是:

ffmpeg -i [filename] -ss [starttime] -t [length] -c copy [newfilename] i 为需要裁剪的文件 ss 为裁剪开始时间 t 为裁剪结束时间或者长度 c 为裁剪好的文件存放 好了,用 Python 写一个调用:

import subprocess as sp

def cut_video(filename, outfile, start, length=90): cmd = "ffmpeg -i %s -ss %d -t %d -c copy %s" % (filename, start, length, outfile) p = sp.Popen(cmd, shell=True) p.wait() return 定义了一个函数,通过参数传入 ffmpeg 需要的信息 将裁剪命令写成一个字符串模板,将参数替换到其中 用 subprocess 的 Popen 执行命令,其中参数 shell=True 表示将命令作为一个整体执行 p.wait() 很重要,因为裁剪需要一会儿,而且是另起进程执行的,所以需要等执行完成再做后续工作,否则可能找不到裁剪好的文件 这样视频裁剪工作就完成了,然后再看看什么是最重要的。

计算分段 视频裁剪时,需要一些参数,特别是开始时间,如何确定呢?如果这件事做不好,裁剪工作就很麻烦。

所以看看如何计算裁剪分段。

我需要将视频裁剪成一分半的小段,那么将需要知道目标视频文件的时间长度。

获取视频长度 如何获得长度呢?ffmpeg 提供了另一个命令 —— ffprobe。

找了一下,可以合成一个命令来获取:

ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 -i a.flv

920.667 命令比较复杂哈,可以先不用管其他参数,只要将要分析的视频文件传入就好了。命令的结果是显示一行视频文件的长度。

于是可以编写一个函数:

import subprocess as sp

def get_video_duration(filename): cmd = "ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 -i %s" % filename p = sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.PIPE) p.wait() strout, strerr = p.communicate() # 去掉最后的回车 ret = strout.decode("utf-8").split("\n")[0] return ret

函数只有一个参数,就是视频文件路径 合成命令语句,将视频文件路径替换进去 用 subprocess 来执行,注意这里需要设置一下命令执行后的输出 用 wait 等待命令执行完成 通过 communicate 提取输出结果 从结果中提取视频文件的长度,返回 分段 得到了视频长度,确定好每个分段的长度,就可以计算出需要多少分段了。

代码很简单:

import math duration = math.floor(float(get_video_duration(filename))) part = math.ceil(duration / length)

注意,计算分段时,需要进行向上取整,即用 ceil,以包含最后的一点尾巴。

得到了需要的分段数,用一个循环就可以计算出每一段的起始时间了。

获取文件 因为处理的文件很多,所以需要自动获取需要处理的文件。

方法很简单,也很常用,一般可以用 os.walk 递归获取文件,还可以自己写,具体根据实际情况。

for fname in os.listdir(dir): fname = os.path.join(dir, os.path.join(dir, fname)) basenames = os.path.basename(fname).split('.') mainname = basenames[0].split("_")[0] ... 提供视频文件所在的目录,通过 os.listdir 获取目录中的文件,然后,合成文件的绝对路径,因为调用裁剪命令时需要绝对路径比较方便。

获取文件名,是为了在后续对裁剪好的文件进行命名。

代码集成 现在每个部分都写好了,可以将代码集成起来了:

def main(dir): outdir = os.path.join(dir, "output") if not os.path.exists(outdir): os.mkdir(outdir)

for fname in os.listdir(dir):
    fname = os.path.join(dir, os.path.join(dir, fname))
    if os.path.isfile(fname):
        split_video(fname, outdir)

main 方法是集成后的方法 先创建一个裁剪好的存储目录,放在视频文件目录中的 output 目录里 通过 listdir 获取到文件后,对每个文件进行处理,其中判断了一下是否为文件 调用 split_video 方法开始对一个视频文件进行裁剪 总结 总体而言,这是个很简单的应用,核心功能就是调用了一个 ffmpeg 命令。

相对于技术,更重要的是如何对一个项目进行分析和分解,以及从什么地方开始。

这里的方式起始时,不断地找最重要地事情,以最重要的事情为线索不断地推进,最终以自下而上地方式解决整个问题。