对于视频的读取与处理,经常会碰到opencv与ffmpeg,所以本文就记录一下ffmpeg的学习过程,以及解答之前的几个疑惑:opencv与ffmpeg的区别是什么,什么时候使用后opencv,什么时候使用ffmpeg?ffmpeg的安装过程是什么,该怎么使用它?目前python有哪些方法使用ffmpeg,各有什么优缺点?
以下是百度百科关于ffmpeg的介绍:
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。
简单来说,ffmpeg是一个处理媒体文件的命令行工具 (command line based) ,它能够完成视频采集、视频编解码、视频格式转换、视频合并与裁切等复杂操作。也就是说,通过使用ffmpeg就能够完成大部分对视频的操作。
ffmpeg的一般安装情况可以参考此文章,但由于我是在linux服务器上使用ffmpeg,不方便拥有root权限,同时使用该服务器的其他用户也不一定需要使用ffmpeg,所以我这里采用的在自己的用户空间中安装ffmpeg的方法。
具体操作为去这里下载官方提供的release版本的包,选择适合自己服务器的系统、架构的版本(我用到的服务器为CentOS系统,X86架构,所以选择下图版本)
然后在linux下解压,解压完后将文件夹路径写入.bashrc就可以直接用ffmpeg命令。
export PATH="$PATH:/home/xxx/ffmpeg/ffmpeg-4.4-i686-static"
# 在.bashrc中加入这句话,其中$PATH后面的路径为解压后的文件夹的位置
在bash中输入ffmpeg,如果出现如下输出,则表明已经成功安装好了ffmpeg。
Note
添加路径到.bashrc文件中要注意不要把从root用户目录下的.bashrc文件中继承到的路径覆盖了,不然会出现bash打不开的情况。
export PATH="/home/xxx/ffmpeg/ffmpeg-4.4-i686-static"
就如这种情况,没有使用$PATH来继承之前的各种环境变量,而是直接用ffmpeg的路径覆盖了所有的环境变量,这样会导致bash打不开。
ffmpeg的简单操作可以参考这篇文章,如果需要使用更高级的方法则可以参考ffmpeg的文档,中文文档则参考这里。
使用 ffmpeg 命令的基本形式是:
ffmpeg [全局参数] {[输入文件参数] -i 输入文件地址} ... {[输出文件参数] 输出文件地址} ...
要注意的是,所有的参数仅仅对仅接下来的文件有效(下一个文件得把参数再写一遍)。
所有没有使用 -i 指定的文件都被认为是输出文件。 ffmpeg 可以接受多个输入文件并输出到您指定的位置。你也可以将输入输出都指定为同一个文件名,不过这个时候要在输出文件前使用用 -y 标记。
Note
你不应该将输入和输出混淆,先指定输入,再指定输出文件
ffmpeg 最简单的使用就是用来 显示文件信息 。不用给输出,只是简单的写:
ffmpeg -i file_name
视频和音频文件都可以使用:
ffmpeg -i video_file.mp4
ffmpeg -i audio_file.mp3 -hide_banner
通过以上,命令就可以查看音视频文件的一些具体信息,比如编码器,数据流等。
ffmpeg 最让人称道的应该就是可以轻而易举的在不同媒体格式之间进行自由转换了。只需要指明输入和输出文件名就行了, ffmpeg 会从后缀名猜测格式,这个方法同时适用于视频和音频文件
下面是一些例子:
ffmpeg -i video_input.mp4 video_output.avi
ffmpeg -i video_input.webm video_output.flv
ffmpeg -i audio_input.mp3 audio_output.ogg
ffmpeg -i audio_input.wav audio_output.flac
也可以同时指定多个输出后缀:这样会同时输出多个文件.
ffmpeg -i audio_input.wav audio_output_1.mp3 audio_output_2.ogg
如果想看支持的格式,可以用:
ffmpeg -formats
为了从视频文件中抽取音频,直接加一个 -vn 参数就可以了:
ffmpeg -i video.mp4 -vn audio.mp3
这会让命令复用原有文件的比特率,一般来说,使用 -ab (音频比特率)来指定编码比特率是比较好的:
ffmpeg -i video.mp4 -vn -ab 128k audio.mp3
一些常见的比特率有 96k, 128k, 192k, 256k, 320k (mp3也可以使用最高的比特率)。
其他的一些常用的参数比如 -ar (采样率: 22050, 441000, 48000), -ac (声道数), -f (音频格式, 通常会自动识别的). -ab 也可以使用 -b:a 来替代. 比如:
ffmpeg -i video.mov -vn -ar 44100 -ac 2 -b:a 128k -f mp3 audio.mp3
opencv是一个开源的计算机视觉库,其包含了数百个计算机视觉算法,实现了图像处理和计算机视觉方面的很多通用算法,已成为计算机视觉领域最有力的研究工具。
严谨来看,opencv和ffmpeg其实没有可比性,因为这两个库所实现的功能并不是很相同,侧重点并不相同。但是,由于平时做实验时发现利用opencv解码视频时速度不理想,所以就想具体了解以下这两者的具体不同之处。
opencv来读取视频时很方便,使用VideoCapture类就能很方便的读取文件或者摄像头的实时视频流。
import cv2
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
通过上面的几行代码就能实时读取摄像头的视频流(读取文件也类似),过程很是方便。但是,OpenCV中的视频功能是基于ffmpeg开发的,也就是说上面的代码在底层也是通过调用ffmpeg实现的。同时,在处理视频编解码的问题上,Opencv的运行速度比ffmpeg慢得多。通常,6或7分钟的视频ffmpeg只需要1或2分钟即可完成,而opencv大约需要5分钟。所以说,如果训练网络时所用到的数据集比较大时,可以采用ffmpeg来进行视频数据的解码和读取,而不是opencv的api,这样虽然会相对来说复杂一些,但也会有速度上的提升。
FFmpeg 是一个命令行工具,其能通过在命令行输入指令,来完成一系列复杂的音视频操作。但对于程序来说,在程序中输入命令行指令却又显得很麻烦,所以有了两个基于FFmpeg封装的python包————ffmpy、ffmpeg-python
ffmpy是一个用于FFmpeg的Python包装器,它根据提供的参数及其各自的选项编译FFmpeg命令行,并使用Python的子进程执行它。它可以读取任意数量的输入“文件”(常规文件、管道、网络流、抓取设备等),并写入任意数量的输出“文件”。有关FFmpeg命令行选项和参数如何工作的详细信息,请参阅FFmpeg文档
最简单的用法例子是将媒体从一种格式转换为另一种格式(在本例中是从MP4转换为MPEG传输流),同时保留所有其他属性:
from ffmpy3 import FFmpeg
ff = FFmpeg(inputs={'test.mp4': None},
outputs={'output.ts': None})
print(ff.cmd)
ff.run()
由该例子可以看出ffmpy封装了FFmpeg,能够提供相对与新手来说较为友好的FFmpeg使用方式
ffmpeg-python也是一个FFmpeg的封装器,但是相较于其他封装器,其能够处理较为复杂的信号图,一个简单的例子如下:
import ffmpeg
stream = ffmpeg.input('input.mp4')
stream = ffmpeg.hflip(stream)
stream = ffmpeg.output(stream, 'output.mp4')
ffmpeg.run(stream)
由上例其实可以比较明显的看出该python库的封装要更加符合python代码的使用风格,可以说是较为简便和直观。
同时,对于复杂的信号图处理,虽然ffmpeg能够很好的解决,但是写出来的代码或者指令会比较复杂以及晦涩难懂,如下面的信号图:
如果使用FFmepg,结果会是这样:
ffmpeg -i input.mp4 -i overlay.png -filter_complex "[0]trim=start_frame=10:end_frame=20[v0];\
[0]trim=start_frame=30:end_frame=40[v1];[v0][v1]concat=n=2[v2];[1]hflip[v3];\
[v2][v3]overlay=eof_action=repeat[v4];[v4]drawbox=50:50:120:120:red:t=5[v5]"\
-map [v5] output.mp4
这看起来很是复杂,也很是难懂。但如果使用ffmpeg-python,则结果就不一样了:
import ffmpeg
in_file = ffmpeg.input('input.mp4')
overlay_file = ffmpeg.input('overlay.png')
(
ffmpeg
.concat(
in_file.trim(start_frame=10, end_frame=20),
in_file.trim(start_frame=30, end_frame=40),
)
.overlay(overlay_file.hflip())
.drawbox(50, 50, 120, 120, color='red', thickness=5)
.output('out.mp4')
.run()
)
虽然代码量会比直接使用FFmpeg要多,但阅读性会好上很多,所以这里会强烈推荐使用该库来调用FFmpeg处理音视频。
Note
以上提到的两个python都是FFmpeg的封装器,其底层还是要调用系统中的FFmpeg,所以在安装这写python库之前也要安装FFmpeg,否则将无法工作。
同时,以上两个库都是开源库,具体链接如下:
Linux上的ffmpeg完全使用指南 – 目光博客 (eyehere.net)
Linux 没有root权限下ffmpeg的安装方式_Ray's Coding Island | 编码之岛-CSDN博客
ffmpy3与ffmpeg的简单使用_Jumping boy-CSDN博客