FFmpeg是一个用于音视频处理的自由软件,被广泛用于音视频开发。FFmpeg功能强大,本文主要介绍如何使用FFmpeg命令行工具进行简单的视频处理。

安装FFmpeg可以在官网下载各平台软件包或者静态编译版本,也可以使用包管理工具安装。

基本概念

容器

我们熟悉的mp4,rmvb,mkv,avi是多媒体容器文件格式(或称多媒体封装格式),所谓容器是指将不同的数据流(视频流,音频流,字幕流等)封装在一个文件(载体)中。

播放时各种流分别进行解码等处理后,然后输出到显示器和音响等设备进行播放。多媒体容器格式不同于编码格式,一个容器中可以封装多种编码格式的媒体流。

流封装了实际的媒体数据,如视频流,音频流和字幕流等。一般情况下,流中的数据只能使用一种编码格式。

帧率

帧率(frames per second, fps)是每秒画面刷新的次数,帧率越高视频越流畅。一般来说30fps就是可以接受的,60fps则可以明显提升交互感和逼真感,但是一般超过75fps一般就不容易察觉到有明显的流畅度提升了。

分辨率

分辨率表示画面的精细程度,通常用像素密度来表示,常用的单位为ppi(像素每英寸)。通常像素密度越高画面越精细,模糊程度越低。

对于视频文件而言,像素密度是无法控制的(由播放器和显示设备决定)。我们通常用视频的像素数来表示它的分辨率如1080x640, 640x320等。

比特率

比特率(bit rate)又称码率,表示多媒体流每秒输出的字节数,单位为KB/s, Kbps等。同样的压缩算法下,比特率越高音视频的质量越好。

可变码率(Variable Bitrate, VBR)指的是编码器的输出码率可以根据输入源信号的复杂度进行自适应调整,以在输出质量保持不变的条件下尽可能减少数据量。VBR适用于存储,不太适用流式传输。

固定码率(Constant Bitrate, CBR)指的是编码器输出码率固定,CBR不适合存储,对于复杂内容可能没有足够码率进行编码,从而导致质量下降,同时会在简单内容部分浪费一些码率。

采样率

每秒钟对音频信号的采样次数,采样频率越高声音还原度越高,声音更加自然,单位是赫兹 Hz。

音频文件一般使用的采样率是 44.1 kHz,也就是一秒钟采样44100次,实验发现低于这个值就会有较明显的损失,而高于这个值人的耳朵已经很难分辨,而且增大了数字音频所占用的空间。

视频编码

视频流可以看做图片的序列,我们把这个序列中的一张图片称为一帧。若存储视频中所有帧则会数据量过大,不便于存储和传输。

所幸统计表明大多数视频相邻帧之间的区别并不大,所以对于一段变化不大的视频,我们可以先完整编码帧A,其后的B帧只需要编码与A帧不同的部分,B帧后的C帧则只编码与B帧的差异。如此递推,将一段视频编码为一个序列。

当某个图像与之前的图像变化很大无法参考前面的帧来生成,我们就结束上一个序列将该帧完整编码开始一个新的序列。

H264是目前流行的一种视频编码算法,它定义了三种帧:完整编码的I帧,参考I帧生成只包含差异的P帧,以及以及参考前后帧编码的B帧。

H264采用的核心算法是帧内压缩和帧间压缩,帧内压缩是生成I帧的算法,帧间压缩是生成B帧和P帧的算法。

通常,我们也把完整编码的I帧称为关键帧。因为解码非关键帧需要解码其参考的帧,因此在截图等不需要全部解码的操作中,经常截取关键帧以提升性能。

获得音视频信息

ffprobe是FFmpeg项目提供的用于分析视频信息的命令行工具。

随意下载一个测试视频testmp4, 然后终端中输入指令:

ffprobe -v quiet -print_format json -show_format -show_streams test.mp4

可以获得json格式输出的视频信息:

{
"streams": [ // 文件中包含的流
{
"index": 0, // 流的序号
"codec_name": "h264", // 流的编码格式
"codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", // 编码格式的全名
"profile": "High",
"codec_type": "video", // video表示这是一个视频流
"codec_time_base": "1/60",
"codec_tag_string": "avc1",
"codec_tag": "0x31637661",
"width": 1080, // 视频宽为1080像素
"height": 614, // 视频高为614像素
"coded_width": 1080,
"coded_height": 614,
"has_b_frames": 2,
"sample_aspect_ratio": "0:1",
"display_aspect_ratio": "0:1",
"pix_fmt": "yuv420p",
"level": 31,
"chroma_location": "left",
"refs": 1,
"is_avc": "true",
"nal_length_size": "4",
"r_frame_rate": "30/1", // 实际帧率
"avg_frame_rate": "30/1",
"time_base": "1/15360",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 153093,
"duration": "9.966992", // 以秒为单位的视频时间
"bit_rate": "2077265", // 视频的比特率
"bits_per_raw_sample": "8",
"nb_frames": "299",
"tags": { // 流中的附加信息,其中的字段可能为空
"rotate": 90, // 视频旋转的角度
"language": "und",
"handler_name": "VideoHandler"
}
},
{
"index": 1, // 流编号
"codec_name": "aac", // 流的编码格式
"codec_long_name": "AAC (Advanced Audio Coding)", // 编码格式的全名
"profile": "LC",
"codec_type": "audio", // 这是一个音频流
"codec_time_base": "1/44100",
"codec_tag_string": "mp4a",
"codec_tag": "0x6134706d",
"sample_fmt": "fltp",
"sample_rate": "44100", // 采样率
"channels": 2, // 声道数
"channel_layout": "stereo", // 声道布局,stereo为立体双声道
"bits_per_sample": 0,
"r_frame_rate": "0/0",
"avg_frame_rate": "0/0",
"time_base": "1/44100", // 每帧时长
"start_pts": 0,
"start_time": "0.000000", // 流开始播放时间
"duration_ts": 442367,
"duration": "10.030998", // 流时长
"bit_rate": "129341", // 比特率
"max_bit_rate": "129341",
"nb_frames": "433",
"tags": {
"language": "und",
"handler_name": "SoundHandler"
}
}
],
"format": { // 容器信息
"filename": "test.mp4", // 文件名
"nb_streams": 2,
"nb_programs": 0,
"format_name": "mov,mp4,m4a,3gp,3g2,mj2", // 封装格式名
"format_long_name": "QuickTime / MOV",
"start_time": "0.000000",
"duration": "10.055000",
"size": "2762615", // 文件字节数
"bit_rate": "2198002", // 比特率
"probe_score": 100,
"tags": {
"major_brand": "isom",
"minor_version": "512",
"compatible_brands": "isomiso2avc1mp41",
"encoder": "Lavf57.71.100"
}
}
}

示例中使用-v quiet选项将日志级别设为quiet避免日志信息污染json,-show_format显示文件的容器信息,-show_stream显示容器中流的信息,-show_frames则可以显示视频中每一帧的信息。

更多关于ffprobe的内容可以参考官方文档

使用ffmpeg进行视频处理

ffmpeg的命令格式:

ffmpeg \
[global_options] \
[input_file_options] -i input_url \
[actions] \
[output_file_options] output_url

我们可以将ffmpeg的选项分为全局选项和局部选项,局部选项用于设置输入输出或者滤镜等,通常位于被修饰的指令前面。

ffmpeg的基本流程为将容器中的各流进行解码,然后重新编码为指定的格式。在编码之前,可以使用filter对视频进行处理。

选项

选项的详细内容请参考官方文档

-y / -n

-y/-n 为全局选项, -y表示直接覆盖已经存在的输出文件, -n表示若某个输出文件已经存在则退出。

若没有设置-y-n选项,且某个输出文件已经存在ffmpeg会询问是否要覆盖输出文件。

ffmpeg -y -i test.mp4 test.mkv

-codec(-c)

指定输入输出的解码编码器, 可用的编解码器可以参考官方文档:

fmpeg -y -i test.mp4 -c:v libx264 -c:a copy test.mov

codec指定为copy则将输入流直接复制到输出流不进行编解码操作。

使用-c:STREAM_INDEX方式可以指定某一个流的解码器,STREAM_INDEX为stream对象的index属性。

-c:v-vcodec可以为所有视频流指定编码器,-c:v:1为第2个视频流指定编解码器。

-c:a-acodec可以为所有音频流指定编码器,-c:a:12为第13个视频流指定编解码器。

-ss

-ss选项用于设置流的开始时间,可以设置输入输出或者滤镜。在开始时间之前的帧将被跳过不被处理(输入不被解码,输出不被编码,滤镜不被处理)。

ffmpeg -ss 2 -t 10 -i test.mp4 test.mov

时长有两种方式来表示:

  • 秒数: 如-t 10-t 23.167
  • 时分秒: 如-t 10:23-t 21:31:00.233

-t

-t选项用于用于设置输入输出,-t-i前可以限制输入时长,-t在输出文件前可以限制输出时长。

读入test.mp4文件2s开始10s内的数据,转码后输出到test.mov:

ffmpeg -ss 2 -t 10 -i test.mp4 test.mov

读入test.mp4全部数据,全部转码后输出从第2s开始1min10s内的数据到test.mov:

ffmpeg -i test.mp4 -ss 2 -t 01:10 test.mov

-to

-to选项类似于-t选项,不同的是-to指定结束时刻,-t指定持续时间。

读入test.mp4文件2s到12s内的数据,转码后输出到test.mov:

ffmpeg -ss 2 -to 12 -i test.mp4 test.mov

读入test.mp4全部数据,全部转码后输出从01:00到01:30内的数据到test.mov:

ffmpeg -i test.mp4 -ss 01:00 -to 01:30 test.mov

-f

强制设置输入输出的文件格式,默认情况下ffmpeg会根据文件后缀名判断文件格式。

ffmpeg -formats命令会显示所有支持的编码格式。

-filter / -filter_complex

使用过滤器对流进行处理,下文将简要介绍filter的相关内容。

可以使用-vf代替-filter:v处理视频流, -af代替-filter:a处理音频流。

-vframes

设置输出文件中包含的总帧数:

ffmpeg -i test.mp4 -vframes 1 test.mov

-vn

不将视频流写到输出文件中

ffmpeg -i test.mp4 -vn -a:c copy out.mp3

-r

设置某个流的帧率:

ffmpeg -i test.mp4 -r:v 30 test.mov

-s

设置帧的大小:

ffmpeg -i test.mp4 -s 1080x680 out.mp4

-an

不将音频流写到输出文件中:

ffmpeg -i test.mp4 -v:c copy -an out.mp4

-threads

设置处理线程数:

ffmpeg -threads 8 -i test.mp4 out.mp4

可以设置处理

-shortest

当最短的输入流结束后即停止编码和输出。

ffmpeg -i bgm.mp3 -i test.mp4 -shortest output.mp4

filter

过滤器会对已解码的帧进行处理,处理后的帧会被重新编码输出,整个流程可以概括为:

Input -> DecodedFrames -> FilteredFrames -> EncodedData

简单过滤器是单输入单输出的(只能处理一个流),而复杂过滤器(filter_complex)是多输入多输出的可以进行更复杂的操作。

ffmpeg支持的各种滤镜可以参考官方文档-滤镜

scale

ffmpeg -y -i test.mp4 -vf "scale=2*in_w:2*in_h" test.mov

scale滤镜用于缩放视频, in_win_h代表输入的宽和高。

crop

ffmpeg -y -i test.mp4 -vf "crop=w=100:h=100:x=in_w/2:y=in_h,scale=400:400" test.mov

crop滤镜用于截取视频中的一个区域。

overlay

ffmpeg -y -i test.mp4 -i logo.png -filter_complex 'overlay=10:main_h-overlay_h-10' out.mp4

overlay滤镜将一个视频叠放在另一个视频上,可用于在视频中添加水印和动画等操作。

overlay的第一个输入为底层视频流,第二个输入为叠加视频流。main_wmain_h为底层视频的宽和高,overlay_woverlay_h为叠加视频的宽和高。

drawtext

ffmpeg -y -i test.mp4 -vf "drawtext=fontfile=CourierNew.ttf:text='hello world':x=100:y=50:fontsize=24" out.mp4

drawtext滤镜用于在视频上添加文字。

fade

ffmpeg -y -i test.mp4 -vf "fade=in:st=0:d=5" out.mp4

fade滤镜可以制作淡入淡出效果

fps

ffmpeg -y -i test.mp4 -vf "fps=60" out.mp4

fps滤镜通过删除帧或者复制帧的方法强制设置帧率。

ffmpeg -y -i test.mp4 -vf "fps=1" img%3d.png
ffmpeg -y -i test.mp4 -r 1 img%3d.png

上面两条指令都可以对视频每秒截取一帧图像,-r选项会截取关键帧并不一定截取0s、1s...处的帧,fps滤镜处理的是已经解码的帧因此可以精确的按照时间截取。

因为fps滤镜会解码要截图的视频片段,因此这种方式截图会慢很多。

应用示例

视频转码

ffmpeg -y \
-i test.mp4 \
-vcodec copy \
-acodec copy \
out.mkv

这条指令将容器格式由MP4转换到MKV,使用ffprobe检查输出文件可以发现,视频流没有发生变化,但是封装格式改变为mkv格式。

-vcodec是一个简单过滤器用于处理视频编码,copy表示将视频流复制到输出文件中。-acodec是处理音频编码的过滤器。

提取视频流

ffmpeg -y \
-i test.mp4 \
-vcodec copy \
-an \
out.mp4

-an表示不保留音频流。

提取音频

ffmpeg -y \
-i test.mp4 \
-ar 44100 -ac 2 -ab 192 \
-f mp3 \
output.mp3

分析:

  • -ar: 指定输出音频采样率
  • -ac: 指定输出音频通道(channel)数, 这里设置为双声道
  • -ab: 指定输出音频比特率,单位kb/s

按帧截取图像

截取第2s开始的10帧图像, 伸缩为352x240:

ffmpeg -y \
-ss 2 -i test.mp4 \
-vframes 10 \
-f image2 \
-s 352x240 \
img%03d.png

分析:

  • -ss 2 -i test.mp4ss为开始时间,用秒数或者hh:mm:ss[.xxx]格式表示。-i test.mp4表示输入源
  • -vframes: 指定截取的帧数, 这里是截取前10帧(从-ss指定开始时间算起)
  • -f: 指定输出文件的格式,如: image2, mjpeg, gif
  • -s: 对输出画面进行缩放
  • img%03d.png: 格式化输出文件名,本示例中输出img001.png, img002.png等。

-ss参数也可以放在vframes前:

ffmpeg -y \
-i test.mp4 \
-ss 2 -vframes 1 \
-f image2 \
-s 352x240 \
img.png

-ss参数是局部选项用于设置其后的一个命令,-ss 2 -i test.mp4表示从输入视频的第2s开始处理,忽略前两秒的内容。

-ss 2 -vframes 1表示从第2s开始截取,此时前2s的内容已经进行了解码。

对不需要处理的部分进行解码会浪费大量时间,因此建议使用-ss 2 -i test.mp4来表示截图开始时间。

按时间截取图像

从第2s到第12s内,每秒截取1帧图像:

ffmpeg -y \
-ss 2 -i test.mp4 \
-r 1 -t 10 \
-f image2 \
-s 352x240 \
img%03d.png

分析:

  • -t: 指定截取时长,这里截取10s
  • -r 1-t的局部选项设置每秒截取的帧数(截取帧率),若不设置则截取全部帧

-vframe一样-t的开始时间也有两种设置方式,基于同样的理由同样建议将-ss放在输入前。

截取视频片段

截取视频片段的方法与截图方法类似,只是将输出格式变为视频:

按时间截取:

 ffmpeg -y \
-ss 2 -i test.mp4 \
-r 20 -t 10 \
-s 352x240 \
clip.mp4

因为输出为视频,-r指定的截取帧率即为输出视频帧率。

按帧数截取:

ffmpeg -y \
-ss 2 -i test.mp4 \
-vframes 120 \
-s 352x240 \
clip.mp4

截取视频区域

截取视频区域:

ffmpeg -y \
-ss 2 -i test.mp4 \
-r 1 \
-t 10 \
-filter_complex "[0:v]crop=w=100:h=100:x=12:y=34,scale='400:400'[v]" \
-map "[v]" \
img%03d.png

crop滤镜可以截取视频部分区域,[0:v]crop=w=100:h=100:x=12:y=34,scale='400:400'[v]截取了左上角在(12,34)处,宽为100,高为100的矩形框中的内容,并将截图放大到400x400。

拼接视频

ffmpeg -i "concat:1.mp4|2.mp4|3.mp4" -c copy output.mp4

将图片合并为视频

ffmpeg -i img%3d.png output.gif
ffmpeg -i img%3d.png output.mp4

添加音频

ffmpeg -i bgm.mp3 -i test.mp4 output.mp4

添加水印

ffmpeg -y \
-i test.mp4 \
-i 1.png \
-filter_complex "[1]scale=w=480:h=280[s];[0][s]overlay=x=main_w-overlay_w-10:y=main_h-overlay_h-10[ov]" \
-map "[ov]" \
output.mp4

使用filter_complex先将水印图片(输入1)放大到480x280, 然后使用overlay滤镜将放大后的流[s]覆盖到视频(输入0)上。

若不需要使用scale进行缩放,则可以简化filter_complex表达式:

ffmpeg -y \
-i test.mp4 \
-i 1.png \
-filter_complex "overlay=x=main_w-overlay_w-10:y=main_h-overlay_h-10"
output.mp4

添加动画

ffmpeg -y -i test.mp4 -t 10 -loop 1 -framerate 6 -i ani%3d.png -filter_complex 'overlay=10:main_h-overlay_h-10' out.mp4

将多张图片(ani001.png, ani002.png...)组成动画, 然后将这个动画叠加在视频的左下角。-t 10 -loop 1会循环播放动画,持续10s。

该方式也支持gif格式的动画。

添加文字

ffmpeg -y -i test.mp4 -vf "drawtext=fontfile=CourierNew.ttf:text='hello world':x=100:y=50:fontsize=24" out.mp4

添加字幕

添加字幕有两种方式:

  • 将字幕添加为独立的流,mkv,avi等封装格式支持此种方式,mp4格式不支持
  • 将字幕叠加到视频中

添加字幕流:

ffprobe -show_streams -print_format json out.mp4

叠加字幕:

ffmpeg -i test.mp4  -i sub.srt -filter_complex "[0][1]overlay[v]" -map "[v]" out.mp4

HowToBurnSubtitlesIntoVideo详细介绍了烧录字幕的方法,作者建议尽量使用字幕流的方法添加字幕。

旋转视频

旋转视频有两种方式:

  • 在视频元信息中添加旋转角度信息,由播放器执行旋转
  • 将每帧图像旋转

添加元信息:

ffmpeg -i test.mp4 -metadata:s:v rotate="90" -codec copy out.mp4

逐帧旋转:

ffmpeg -i test.mp4 -vf "transpose=1" out.mp4

transpose滤镜的文档

FFMPEG指令的更多相关文章

  1. FFmpeg 维基百科

    FFmpeg是一个自由软件,可以运行音频和视频多种格式的录影.转换.流功能[1],包含了libavcodec ─这是一个用于多个项目中音频和视频的解码器库,以及libavformat——一个音频与视频 ...

  2. Java使用FFmpeg处理视频文件指南

    Java使用FFmpeg处理视频文件指南 本文主要讲述如何使用Java + FFmpeg实现对视频文件的信息提取.码率压缩.分辨率转换等功能: 之前在网上浏览了一大圈Java使用FFmpeg处理音视频 ...

  3. Java使用FFmpeg处理视频文件的方法教程

    这篇文章主要给大家介绍了关于Java使用FFmpeg处理视频文件的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧 前言 本文主要 ...

  4. ffmpeg命令参数详解

    ffmpeg命令参数详解 http://linux.51yip.com/search/ffmpeg ffmpeg图片加滤镜效果 参考:https://cloud.tencent.com/develop ...

  5. PHP 将amr音频文件转换为mp3格式

    说下整体思路 1.服务器安装ffmpeg 2.使用ffmpeg -i 指令来转换amr为mp3格式(这个到时候写在PHP代码中,使用exec函数执行即可) 3.在网页端使用HTML5的audio标签来 ...

  6. ffmpeg常用指令

    在osx系统下通过ffmpeg查看设备 ffmpeg -f avfoundation -list_devices true -i "" -f 指定的是输入输出格式, -i指定输入的 ...

  7. ffmpeg第7篇:数据流选择神器-map指令

    自动选择规则 ffmpeg在处理视频时,如果只提供了输入和输出参数,ffmpeg会自动地去选择相应的视频流和音频流来合成文件 自动选择的方式根据如下规则: 视频流:选分辨率最高的,比如有两个视频,一个 ...

  8. FFmpeg部署及相关指令操作说明

    1.首先在http://ffmpeg.zeranoe.com/builds/上下载static版本, 下载好以后解压缩到 c:/ffmpeg/ 2.配置环境变量 path -> c:/ffmpe ...

  9. ffmpeg 推流相关指令

    1.rtsp->rtsp(只解封装,不解码) ffmpeg -re -rtsp_transport tcp -i rtsp://usr:passwd@ip:port/h264/ch1/sub/a ...

随机推荐

  1. 【redis专题(3)】命令语法介绍之link

    通过链表结构可以模仿队列结构与堆栈结构:关于队列结构和堆栈结构可以查看https://www.zybuluo.com/a5635268/note/290475 增 lpush key value1 v ...

  2. [20171113]修改表结构删除列相关问题.txt

    [20171113]修改表结构删除列相关问题.txt --//维护表结构删除字段一般都是先ALTER TABLE <table_name> SET UNUSED (<column_n ...

  3. python第三十三天----静态方法、类方法、属性方法

    @staticmethod 装饰后,类中的方法转成静态方法 class a: @staticmethod def b(self): print('') 静态方法不可以访问实例变量或类变量,相当于类中的 ...

  4. 高德地图JS API 开发小结

    项目中有一块功能要用到高德地图,所以,想把编码小结一下. 首先是地图的初始化 var map = new AMap.Map("mapDiv", {                  ...

  5. ELK-logstash-6.3.2部署

    Logstash 是一款强大的数据处理工具,它可以实现数据传输,格式处理,格式化输出,还有强大的插件功能,常用于日志处理. 1. logstash部署 [yun@mini04 software]$ p ...

  6. VS2015安装与C++进行简单单元测试

    1:VS2015是微软最新发布的编译器,http://www.itellyou.cn/这是我们的北航大神助教提供的下载网址,以前我们都是自己在网上找,找到的总不是那么如意,这下大神助教提供的网址就好好 ...

  7. Ubuntu18.04 安装tomcat9

    1.官网下载 2.移动到/usr/local/tomcat 3.解压 4.修改权限,否则在idea中不能正常使用

  8. javascript获取指定区间范围随机数的方法

    每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code //获取指定区间范围随机数,包括lowerValue和upperValue funct ...

  9. .Net修改网站项目调试时的虚拟目录

    点中网站项目按F4,虚拟目录那个栏目全部删掉!

  10. Linux下rz/sz安装及使用方法

    新搞的云服务器用SecureCRT不支持上传和下载,没有找到rz命令.记录一下如何安装rz/sz命令的方法. 一.工具说明 在SecureCRT这样的ssh登录软件里, 通过在Linux界面里输入rz ...