当前位置: 首页 > 科技观察

神器 ffmpeg :操作视频,极度舒适

时间:2023-03-18 14:26:42 科技观察

神器ffmpeg:操作视频极其舒服本来以为是一次性的,但是这次活动的视频数据量巨大,而且视频文件长短不一,无法手动处理,所以Python又救了我。还等什么,让我们开始吧!最重要的事情无论做什么,都要分析出什么是最重要的,然后集中精力去征服它,然后继续寻找最重要的事情。对于我们的任务来说,不是什么大工程,但是还是要找最重要的事情做起,循序渐进,最终解决整个问题。整体来说,我们需要从一个目录中读取视频文件,然后对每个视频文件进行裁剪,最后保存处理后的文件。在这个过程中,最重要的是什么?我认为这是视频裁剪。如果你不能方便地裁剪视频,其他所有工作都将白费,对吧?现在很流行裁剪视频短视频。视频编辑软件有很多,功能也很丰富,但我们需要的只是裁剪功能,需要编程调用,最适合的是ffmpeg[1]。ffmpeg是一款功能强大的命令行工具,可以通过编程方式调用。从ffmpeg官网下载操作系统对应的版本。我下载了Windows版本[2]。下载后解压到一个目录下,然后将目录下的bin配置到环境变量中。然后打开命令行输入:>ffmpeg-versionffmpegversion2021-10-07-git-b6aeee2d8b-full_build-...测试一下,可以显示版本信息,说明配置完成。现在看文档发现分割视频文件的命令是:ffmpeg-i[文件名]-ss[开始时间]-t[长度]-ccopy[新文件名]i是要裁剪的文件,ss是裁剪起点时间t是裁剪结束时间或长度c存储用于剪切文件。用Python写一个调用:importsubprocessasspdefcut_video(filename,outfile,start,length=90):cmd="ffmpeg-i%s-ss%d-t%d-ccopy%s"%(filename,start,length,outfile)p=sp.Popen(cmd,shell=True)p.wait()return定义了一个函数,通过参数传入ffmpeg需要的信息,将裁剪命令写成字符串模板,将参数替换进去,用Popen执行命令子进程的,其中参数shell=True的意思是把命令整体执行p.wait()很重要,因为切的时候需要一段时间,而且是单独进程执行的,所以需要等待forexecution完成后做后续工作,否则可能找不到裁剪后的文件,这样视频裁剪工作就完成了,接下来看什么是最重要的。计算分段视频裁剪时,需要一些参数,尤其是开始时间,如何确定?如果做得不好,裁剪会很麻烦。因此,请看一下裁剪段是如何计算的。我需要将视频裁剪为一分半钟,因此我需要知道目标视频文件的持续时间。获取视频长度如何获取长度?ffmpeg提供了另一个命令——ffprobe。找了之后可以合成一个命令得到:>ffprobe-verror-show_entriesformat=duration-ofdefault=noprint_wrappers=11:nokey=1-ia.flv920.667命令比较复杂,可以先忽略其他参数,只要你将解析的视频文件传进来就好了。命令的结果是在一行中显示视频文件的长度。所以你可以写一个函数:importsubprocessasspdefget_video_duration(filename):cmd="ffprobe-verror-show_entriesformat=duration-ofdefault=noprint_wrappers=1:nokey=1-i%s"%filenamep=sp.Popen(cmd,stdout=sp.PIPE,stderr=sp.PIPE)p.wait()strout,strerr=p.communicate()#去掉最后一个回车ret=strout.decode("utf-8").split("\n")[0]returnret函数只有一个参数,是视频文件路径的合成命令语句,将视频文件路径替换为subprocess执行。请注意,您需要在执行命令后设置输出。使用wait等待命令执行,并通过communicate从结果中提取输出。视频文件的长度,通过返回segments得到视频的长度,确定每个segment的长度后,就可以计算需要多少segments了。代码很简单:importmathduration=math.floor(float(get_video_duration(filename)))part=math.ceil(duration/length)注意计算segments的时候需要向上取整,即用ceil包含最后一点尾巴。得到需要的段数后,可以用一个周期计算出每个段的起始时间。获取文件因为需要处理的文件比较多,所以需要自动获取需要处理的文件。方法很简单,也很常用。一般可以使用os.walk递归获取文件,也可以自己写,看实际情况。forfnameinos.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获取目录下的文件,然后结合文件的绝对路径,因为比较方便调用裁剪命令时需要绝对路径。获取文件名的目的是为了以后给裁剪出来的文件命名。代码整合现在每个部分都写好了,可以整合代码了:defmain(dir):outdir=os.path.join(dir,"output")ifnotos.path.exists(outdir):os.mkdir(outdir)forfnameinos.listdir(dir):fname=os.path.join(dir,os.path.join(dir,fname))ifos.path.isfile(fname):split_video(fname,outdir)主要方法是集成后的方法首先创建一个裁剪后的存储目录,放在视频文件目录的output目录下。通过listdir获取文件后,对每个文件进行处理,判断是否调用该文件的split_video方法开始处理一个视频文件。切割总结总的来说,这是一个非常简单的应用,核心功能就是调用一个ffmpeg命令。与技术相比,更重要的是如何分析和分解一个项目,从哪里入手。这里的方法一开始就是不断的寻找最重要的东西,以最重要的东西为线索继续推进,最终以自下而上的方式解决整个问题。希望这篇文章对你有所启发,谢谢。