前提准备
- 一个高清的视频(这样转分辨率后起码不会糊)。
- 一个高清的水印图片(理由同上)。
- FFmpeg,直接官网下一个就可以,这里我使用的就是FFmpeg.exe。
下面将各个部分拆开练习,最后再合在一起。
1
2
3
4
ffmpeg -i 11.mp4
-vf "movie=wm.png [logo];[logo][in]scale2ref=w=oh*mdar:h=ih/10[logo-rescale][video-out];[video-out][logo-rescale]overlay=x=main_w/10-w/2:y=main_h/10-h/2 [out]"
-codec:v libx264 -s 1920x1080 -codec:a mp3
-map 0 -f ssegment -segment_format mpegts -segment_list playlist.m3u8 -segment_time 10 1080P%03d.ts
1 | ffmpeg -i 11.mp4 |
一些基本命令
1.转格式(容器转换)
1 | ffmpeg -i 11.mp4 out.avi |
直接在输出文件的后缀指定需要转的格式(容器)就行。
这样转码是会使用默认编码器,需要设置转码为copy来达到视频质量无损失。参考设置视频编码。
2.转分辨率
1 | ffmpeg -i 11.mp4 -s 1280x720 out.mp4 |
通过-s 1280x720
指定分辨率为720P。
3.设置视频编码
1 | ffmpeg -i 11.mp4 -s 1280x720 -codec:v libx264 -codec:a mp3 out.mp4 |
这里通过-codec:v libx264
指定视频编码格式为x264
,通过-codec:a mp3
指定音频编码格式为mp3
。
1 | ffmpeg -i 4K_BXJG.mp4 -codec:v copy -codec:a copy out.avi |
这里的转码格式被指定为copy
,实际上FFmpeg就会省去编解码过程,速度非常快。
Stream copy is a mode selected by supplying the copy parameter to the -codec option. It makes ffmpeg omit the decoding and encoding step for the specified stream, so it does only demuxing and muxing. It is useful for changing the container format or modifying container-level metadata.
Since there is no decoding or encoding, it is very fast and there is no quality loss.
上面是官网中的描述,可以看到使用copy可以无损的转化容器格式。
4.转图片分辨率
1 | ffmpeg -i wm.png -s 100x100 out.png |
可以看到转图片其实和转视频是同理的。
5.流选择
一个正常的视频至少有两个流,一个视频流,一个音频流。
通过输入而不输出可以查看媒体文件信息:
1 | ffmpeg -i 4K_BXJG.mp4 |
可以看到这个mp4文件包含两个流,0号流为视频流,1号流为音频流。
同时输入两个媒体文件试试:
1 | ffmpeg -i 4K_Z4.mp4 -i 4K_BXJG.mp4 |
可以发现流编号上面的规律,0:0
、0:1
表示第一个文件的两个流,1:0
、1:1
则表示第二个文件的两个流。
提取视频流:
1 | ffmpeg -i 1080_BXJG.mp4 -map 0:0 -codec copy out.mp4 |
上面的命令将原视频的视频流单独分离出来。
合并音视频流:
1 | ffmpeg -i 1080_BXJG.mp4 -i 4K_Z4.mp4 -map 0:0 -codec copy -map 1:1 -codec copy out.mp4 |
提取第一个视频的视频流,第二个视频的音频流,合并为out.mp4。
filter设置
1.过滤器图
先看官方文档说的:
Filtering in FFmpeg is enabled through the libavfilter library.
In libavfilter, a filter can have multiple inputs and multiple outputs. To illustrate the sorts of things that are possible, we consider the following filtergraph.
1 | [main] |
This filtergraph splits the input stream in two streams, then sends one stream through the crop filter and the vflip filter, before merging it back with the other stream by overlaying it on top.
filter即常说的滤镜,Filtering过程可以是一个多输入多输出的过程,多个输入的视频经过处理合并成一个或多个输出。
上面的过程的命令为:
1 | ffmpeg -i INPUT -vf "split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2" OUTPUT |
它的效果如下:
它将原视频复制(split),裁剪一半(crop),反转(cflip),覆盖(overlay)到原视频之上。
可以看到主要的处理过程在-vf
之后,它就代表filtergraph
也就是过滤器图(相似的还有-filter_complex
),相当于定义了一个视频处理的过程。
注意到:-vf
不能有多个输入,而-filter_complex
可以。
2.label(标签)
标签用于对流进行标记,目前我只知道它一些简单的用法。
例如上面的命令中的过滤器图:
"split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2"
- 它将原视频进行split,将它复制为两个流,一个命名为
[main]
,一个命名为[tmp]
。 - 它将
[tmp]
流进行crop操作和vfilp操作,处理之后的流命名为[flip]
。 - 输入
[main]
和[flip]
流,进行overlay(覆盖)操作,根据这里[main][flip]
的先后关系,这里将[flip]
覆盖到[main]
之上。
例如下面的命令,将第二个输入视频分辨率降低一半,然后覆盖到第一个视频之上:
1 | ffmpeg -i 1080_BXJG.mp4 -i 1080_BXJG.mp4 -filter_complex "[1:0]scale=w=iw/2:h=ih/2[scaled]; [0][scaled] overlay" tmp1.mp4 |
其中"[1:0]scale=w=iw/2:h=ih/2[scaled]; [0][scaled] overlay"
:
[1:0]
代表第二个视频的第一个流(视频流),将它的scale变为一半(iw/2
和ih/2
),然后标记为[scaled]
。[0]
就代表第一个输入的媒体文件,将[scaled]
置于它之上然后输出。
3.将视频分辨率降低一半
可以利用scale来完成,其中iw
、ih
分别代表输入的宽和高。
1 | ffmpeg -i 11.mp4 -vf "[in]scale=w=iw/2:h=ih/2[out]" out.mp4 |
为了展示效果,这里将降低了分辨率的视频覆盖到原视频之上:
1 | ffmpeg -i 1080_BXJG.mp4 -filter_complex "[0:0]scale=w=iw/2:h=ih/2[scaled]; [0][scaled] overlay" tmp1.mp4 |
4.为视频添加水印
为视频添加水印,也就是将水印覆盖到原视频之上,即overlay
滤镜。
简单覆盖:
1 | ffmpeg -i 1080_BXJG.mp4 -i wm.png -filter_complex overlay out.mp4 |
简单覆盖时,没有对水印大小进行调整,会造成下面的结果:
大小调整-1:
1 | ffmpeg -i 1080_BXJG.mp4 -i logo.png -filter_complex '[1]scale=w=200:h=-1[scaled]; [0][scaled]overlay' out.mp4 |
使用scale
滤镜来进行分辨率的调整,再将它覆盖到原视频之上:
可以看到这里成功的对水印的大小进行了调整,但是又有一点太小了。
那么问题来了,难道要不断的试来找到一个健康的分辨率吗?
大小调整-2:
1 | ffmpeg -i 1080_BXJG.mp4 -i logo.png -filter_complex '[1][0]scale2ref=w=oh*mdar:h=ih/8[scaled][0-out]; [0-out][scaled]overlay' out.mp4 |
scale2ref
滤镜有两个输入,它对第一个输入进行rescale,
但它与scale
滤镜的区别在于,它使用第二个输入作为参考,来进行第一个输入的rescale。
这里的[1][0]scale2ref=w=oh*mdar:h=ih/8[scaled][0-out]
中,ih指的就是参考输入[0]
的宽度,
为了保证水印的横纵比,这里使用oh*mdar
来定义水印的宽度。
水印位置调整-1:
可以看到上面水印都是贴着视频的左上角的,这里来对它的位置进行调整:
1 | ffmpeg -i 1080_BXJG.mp4 -i logo.png -filter_complex '[1][0]scale2ref=w=oh*mdar:h=ih/8[scaled][0-out]; [0-out][scaled]overlay=x=300:y=300' out.mp4 |
可以通过指定overlay的坐标来确定水印覆盖的位置(默认x=0,y=0,即左上角),这里将坐标指定在300,300,效果如下:
水印位置调整-2:
1 | ffmpeg -i 1080_BXJG.mp4 -i logo.png -filter_complex '[1][0]scale2ref=w=oh*mdar:h=ih/8[scaled][0-out]; [0-out][scaled]overlay=x=main_w/10-w/2:y=main_h/10-h/2' out.mp4 |
这里main_w
和main_h
指的就是视频输入([0-out]
)的宽和高,w
和h
则是水印输入([scaled]
)的宽和高,
这里将水印的中心点指定在视频输入的1/10宽和1/10高的位置。
转hls
hls即包括一个m3u(8)的索引文件,TS媒体分片文件和key加密串文件。
在ffmpeg中可以使用hls或者segment来实现。
使用segment muxer
1 | ffmpeg -i 1080_BXJG.mp4 -f segment -segment_format mpegts -segment_list playlist.m3u8 -segment_list_size 0 -segment_time 5 out%03d.ts |
上面的命令将输入视频切割为5秒一片的ts文件。其中,-segment_list playlist.m3u8
设置文件list输出到playlist.m3u8,
-segment_list_size 0
设置playlist.m3u8里面将包含所有切分出来的分片,
-segment_time 5
设置分片大小为5秒。
得到如下结果:
使用hls muxer
1 | ffmpeg -i 1080_BXJG.mp4 -map 0 -f hls -hls_segment_type mpegts -hls_list_size 6 -hls_time 5 -hls_segment_filename 'out%03d.ts' playlist.m3u8 |
参数基本一样,就不多解释了,效果如下:
转码,水印,hls
将上面的命令进行总结,可以融合得到下面这条命令:
1 | ffmpeg -i 1080_BXJG.mp4 -i logo.png \ |
这条命令将一个视频文件添加水印,并切割为5秒的ts小文件,同时将分辨率调整为1080P。
基于nginx的m3u8的点播、直播的实现
首先看我这里nginx的配置:
1 | cat /etc/nginx/nginx.conf |
我这里将nginx的服务起在11111端口,文件目录为/mycephfs/hls,浏览器打开192.168.90.233:11111
:
点播:
将对应的hls文件放入nginx的文件目录下:
1 | ll /mycephfs/hls/videos/BXJG-hls/ |
直接使用potplayer打开链接http://192.168.90.233:11111/hls/videos/BXJG-hls/playlist.m3u8
:
点播效果完成。
直播:
这里直播和点播的十分相似,它通过不断的修改.m3u8
文件来达到直播的目的。
同样的,使用一个本地的视频文件当作输入流来进行直播,需要加入-re
来模拟直播流的输入速度,-stream_loop
来不断重复输入。
另外,这个过程会不断产生新的ts文件,需要将使用过的小文件删除,添加-hls_list_size 5
将.m3u8
文件中的数量控制为5个,
添加-hls_flags delete_segments
开启自动删除过时的ts小文件。
1 | ffmpeg -re -stream_loop -1 -i 1080_MS.mp4 -i logo.png \ |
产生ts小文件的效果如下:
1 | ls /mycephfs/hls/videos/MS/ |
可以看到ffmpeg同一时刻只会保留6个ts文件。
同样的,使用potplayer打开连接http://192.168.90.233:11111/hls/videos/MS/live.m3u8
,就可以看到直播,
和点播十分相似,不同之处在于,这里会不断的播放下去: