- 官网地址:ffmpeg.org/
- Android端,不想编译,可以直接使用ffmpeg-android-java
关于转码:
网络限制了视频传输的带宽。由于带宽限制,这就要求我们在传输之前通过实时视频转码将视频数据转换成带宽效率更高的格式。转码的意义在于可以在视频质量几乎不损失的前提下节省大量的网络带宽。FFmpeg主要就是做转码这件事情。
FFmpeg转码流程示意图:
_______ ______________
| | | |
| input | demuxer | encoded data | decoder
| file | ---------> | packets | -----+
|_______| |______________| |
v
_________
| |
| decoded |
| frames |
|_________|
________ ______________ |
| | | | |
| output | <-------- | encoded data | <----+
| file | muxer | packets | encoder
|________| |______________|
复制代码
基本命令解释:
-
-y => 覆盖输出
-
-i => 输入源头,比如一个视频的绝对路径:/sdcard/....,输出我们也是写绝对路径
-
-f => 输出格式,如果省略就取输出录制的后缀名为输出格式,比如输入mp4格式:-y -i input -f mp4 output
-
-c:v => 针对视频流的编码 ,等介于-vcodec
-
-c:a => 针对音频流的编码,等介于-acodec
-
-c:v h264 => 指定视频流h264编码方式,有时候也写成libx264,FFmpeg也可以识别
-
-c:a aac => 指定音频流aac编码方式
-
copy => 不编码,如-c:v copy就是对视频流不编码,注意:如果加了不必要的编码操作,会影响执行效率。
-
-an => 禁用音频
-
-vn => 禁用视频
-
-x264-params keyint=10 => 为视频设置关键帧,每隔10帧生成一个关键帧
-
-crf => 动态码率,压缩效果佳,不是一味追求体积,画质佳,H.264的CRF数字范围在0~51,23是默认值。
-
-b:v => 静态码率,压缩效率比较爆炸,一味控制体积
-
-filter_complex => 滤镜,简单滤镜是-vf,常用的有变速滤镜,水印滤镜等
-
-map => 可以理解为流的过滤器:
- -map[0:v] 就是选择第一输入源的视频流,流向输出。
- -map[1:a] 就是选择第二输入源的音频流,流向输出。
-
-max_muxing_queue_size=>如果视频比较大,需要指定这个值比较大(比如9999),否则程序执行会中断。
-
-fps 帧率
-
-vframes 帧数
-
-r帧率
-
-preset
- preset和crd参数一样,会影响压缩效果,preset可以很大程度影响程序的执行速度,每条命令都可以加,一般加载命令尾部,output之前:
preset 描述 ultrafast 编码速度最快 ,压缩效果最差 superfast ··· veryfast ··· faster ··· fast ··· medium – default preset slow ··· slower ··· veryslow 编码速度最慢 ,压缩效果从最好 -
h264编码相关,涉及CRF,Preset等,Encode/H.264
合并多个视频
-
使用concat协议:把视频转成ts流,contact合并多个ts生成视频:
- ts流涉及到一个参数:h264_mp4toannexb
mp4-->ts: remux an MP4 file containing an H.264 stream to mpegts format with ffmpeg, you can use the command: ffmpeg -i INPUT.mp4 -codec copy -bsf:v h264_mp4toannexb OUTPUT.ts 多个ts合并: ffmpeg -i "concat:input1.ts|input2.ts|input3.ts" -c copy output 复制代码
视频音频流变速
- How to speed up / slow down a video 视频速度变成原来的两倍:
ffmpeg -i input.mkv -filter:v "setpts=0.5*PTS" output.mkv
音频速度变成原来的两倍:ffmpeg -i input.mkv -filter:a "atempo=2.0" -vn output.mkv
如果是音频和视频一致加速两杯: 这里会涉及到滤镜的概念和-map指令的使用,输入有多个流,我们就可能用到-map指定: 假设有音频流和视频流:
speed是目标速率,比如2.
-y -i input -filter_complex [0:v]setpts=" + 1d/speed + "*PTS[v];[0:a]atempo=" + speed + "[a] output
复制代码
如果只有视频流:
-y -i input -vf [0:v]setpts=" + 1d/speed + "*PTS" output
复制代码
裁剪时长
- -ss 裁剪开始时间,单位秒
- -t 需要裁剪多长时间,单位秒 从第一秒,裁剪3秒视频生成新视频
-y -i input.mp4 -s 1 -t 3 ouput.mp4
生成缩率图
- 这里涉及两个指令-vframes ,-fps;
- -vframes是帧数
- -fps是帧率,(frames per second),时间(秒)fps=vframs -生成某个时刻的缩率图:
ffmpeg -i input.flv -ss 00:00:14.435 -vframes 1 out.png
每秒生成一张图片,命名为thumb1.png,thumb2.png,thumb3.png.....(输出是绝对路径)ffmpeg -i input -vf fps=1 thumb%d.png
每秒生成两张图片,命名为thumb001.png,thumb002.png,thumb003.png,-s指令来指定分辨率100100.....ffmpeg -i input -s 100X100 -vf fps=2 thumb%3d.png
图片生成幻灯片(多图合成视频)
- 如何输出的图片是规则的,img001png,img002.pmg,img003.pn... 我生成每秒10帧的幻灯片,默认是25帧每秒:
ffmpeg -framerate 10 -i img%03d.png output.mp4
注意:如果生成是h264的视频,加上 -vf format=yuv420p 或者 -pix_fmt yuv420p可以防止某些播放器无法解码视频。 生成幻灯片相关 - 如果文件名是不规则,也可以使用concat协议:
- 先生成一个text文件,写上对应的file和duration(时长):
duration 5 file '/path/to/cat.png' duration 1 file '/path/to/rat.png' duration 3 file '/path/to/tapeworm.png' duration 2 file '/path/to/tapeworm.png' 复制代码
ffmpeg -f concat -i input.txt -vsync vfr -pix_fmt yuv420p output.mp4
- 先生成一个text文件,写上对应的file和duration(时长):
更改分辨率
ffmpeg -i input -s width*height -c:v h264 output
从视频中裁剪一块区域出来
在起点(x,y)的地方裁剪下长高为wh的区域对应的视频(坐标系:以视频左上角为原点,向右为正方向,向下为正方向) ffmpeg -i -vf crop=w:h:x:y output
crop指令
水印
- 叠加一张静态图,overlay是picture左上角对应的坐标,(坐标系:以视频左上角为原点,向右为正方向,向下为正方向):
ffmpeg -i input -i picture -filter_complex overlay=0:0 output
- 叠加GIF,如果想要GIF无限循环,使用这条指令(否则可以用上面的指令):
ffmpeg -i input -ignore_loop 0 -i gif -filter_complex overlay=shortest=1
如果需要加坐标:ffmpeg -i input -ignore_loop 0 -i gif -filter_complex overlay=x:y:shortest=1
GIF
从视频前两秒片段中抽出一张帧率是10的GIF ffmpeg -i INPUT -ss 0 -t 2 -r 10 out.gif
上门的指令生成的GIF是比较模糊的,如果要生成高清的GIF: 先生成调色板,再利用调色板生成GIF,假设fps=10, ffmpeg -i INPUT -r 10 -vf fps=10,scale=300:-1:flags=lanczos,palettegen colorPalette.png
scale是缩放的意思,这里是设置宽为300,-1是保持宽高比. ffmpeg -i input -i colorPalette.png -r 10 -lavfi fps=10,scale=300:-1:flags=lanczos[x];[x][1:v]paletteuse
得到清晰GIF相关
Android 使用:
-
生成一个Shell命令数组,丢给FFmpeg可执行文件处理即可 tips:文档上的命令都是用空格隔开,其实把他理解成数组就好,重点是数组内的元素不要错即可;
String ffmpegSplitWord = "如果是空格容易出错,尽量是一个不容易和其他命令出突的字符(尽量和文件名不冲突)"; StringBuilder sb = new StringBuilder("-y"); sb.append(ffmpegSplitWord + "-i"); sb.append(ffmpegSplitWord + input.toString()); sb.append(ffmpegSplitWord + "-c:v"); sb.append(ffmpegSplitWord + "libx264"); sb.append(ffmpegSplitWord + "-x264-params"); sb.append(ffmpegSplitWord + "keyint=" + Constant.Camerasettings.keyint); setBitRate(ffmpegSplitWord, sb); setPreset(ffmpegSplitWord, sb); sb.append(ffmpegSplitWord + output.toString()); String ffmpeg_s = sb.toString(); String[] command=ffmpeg_s.split(ffmpegSplitWord); try { FFmpeg.getInstance(IApplication.getInstance()).execute(command, new ExecuteBinaryResponseHandler() { @Override public void onFailure(String s) { } @Override public void onSuccess(String s) { } @Override public void onProgress(String s) { } @Override public void onStart() { } @Override public void onFinish() { } }); } catch (FFmpegCommandAlreadyRunningException e) { } 复制代码
如何获取处理进度:
- FFmpeg在处理的过程会打印出一些信息,比如
frame= 1 fps=0.0 q=0.0 size= 0kB time=00:01:02.71 bitrate= 0.0kbits/s speed=2.88x
我们可以拿到time信息,这是处理到哪个时间点的信息,把他专程秒,处理视频时长,就可以得到处理进度。