关于ffmpeg:前端初识视频原理和ffmpeg

56次阅读

共计 10354 个字符,预计需要花费 26 分钟才能阅读完成。

本文导读

浏览本文你将取得一下常识:

理解视频的基本原理。

理解 FFmpeg 是什么,和一些罕用的用法。

用 FFmpeg 搭建简略的视频直播推流。

FFmpeg 在 nodeJs 中的一些用法。

背景

短视频大行其道的年代,作为程序员势必须要理解:视频编辑背地的原理和技术。本文简略的形容了视频的组成原理,和罕用的视频编辑工具,顺便提及了 NodeJs 中的用法。

想要理解视频原理,首先应该从图像原理开始说起。

图像根底

1. 像素

图像画面由一个数字序列示意的图像中的一个最小单位色块,被称之像素(pixel/px)。

留神:像素只有位图才会有,是用来记录位图图像的。

<div align=center><img src=”http://blog.toringo.cn/20200626111029.png” style=”zoom:50%;” /></div>

咱们所说的图像大小为 1920*1080,指的就是长宽各有 1920 和 1080 的像素点,那么一张1920*1080 的图片总共有的像素点为:1920*1080 = 2073600个像素点。

图像的大小如何计算?

图像的大小:像素数量 * 像素大小 = 图片大小 ,而 像素大小 像素深度 有关系。RGB 示意的真彩色能示意 256×256×256=16,777,216,就是咱们常见的1600 万色,是人眼可见的全副色调,超出没有意义。RGB 的像素深度有 1bit、4bit、8bit、16bit、24bit、32bit,如在ps 中下图在新建一张画布抉择8bit(指 rgb 每种色彩占 8bit),那这样1 px = 3 * 8bit = 24bit,俗称24 位图。依据以上公式就能算出如下图图像的大小:500 * 378 * 24 / 8 = 567000Byte = 567000Byte / 1024 = 553.7109375 Kb,和 ps 显示的图像大小一样。

但往往实在的图片大小远比以上计算的后果小很多,这是因为导出的图片都通过压缩的,对于图片压缩技术可自行搜寻学习。

视频根底

1. 视频和图像的关系?

视频就是图片一帧一帧连起来的产物,连起来的越快看着越晦涩,用 帧率(就是每秒播放图片的数量 FPS)来掂量视频的晦涩度。那么依据图片大小的算法就能算出视频的大小。

视频的大小 = 时长(秒)* 帧率(FPS)* 图片大小

那么 1920×1280 分辨率,30FPS,时长 1 秒的视频的大小就是:1920 * 1280 * 24 / 8 * 30 / 1024 / 1024 = 210.9375 M,那么 1 小时的影片须要:210.9 * 60 * 60 / 1024 = 741.4453125 G,不禁一句我 x,为啥我下载的大片才 1G 多,莫慌,视频要是这么简略,那咱们太天真了,所以就有了下文「视频编码」

<div align=center><img src=”http://blog.toringo.cn/20200726105929.png” style=”zoom: 25%;” /></div>

2. 视频是怎么来的?

<div align=center><img src=”http://blog.toringo.cn/ 视频如何产生.png” /></div>

几个概念

  • 帧(Frame):就是一张静止的画面,是视频的最小单位。
  • 帧速率(FPS):每秒播放图片的数量。
  • 码率(Bit Rate):视频文件在单位工夫内应用的数据流量,决定视频的品质和大小,单位是 kb/ s 或者 Mb/s。一般来说同样分辨率下,视频文件的码流越大,压缩比就越小,画面质量就越高。码流越大,阐明单位工夫内取样率越大,数据流,精度就越高,解决进去的文件就越靠近原始文件,图像品质越好,画质越清晰,要求播放设施的解码能力也越高。

    码率的常见三种模式:- CBR
      - 全程码率恒定
      - 文件大小可预测
      - 编码压力小,直播罕用
    - VBR
      - 码率可变
      - 简略场景码率低,简单场景码率高
    - CRF
      - 固定品质模式

## #视频形成

![](http://blog.toringo.cn/20200627204214.png)

视频和音频就像是饭和菜,封装格局就相当于碗。> ** 留神:** 下文所有 ` 视频 ` 均代表 ` 蕴含音频的视频 `。### 1. 视频封装格局

常见封装格局有 `MP4、AVI、FLV、mov、RMVB、MKV、WMV、3GP、ASF` 等。### 2. 编码格局

视频编码是对采纳视频压缩算法将一种视频格式装换成另一种视频格式的形容,音频编码同理。常见的视频编码格局有:`AC-1`、`MPEG2/H.262`、`VP8`、`MPEG4`、`VP9`、`H.261`、`H.263`、`H.264`、`H.265` 等。常见的音频编码格局有:`WMA`、`MP3`、`AC-3`、`AAC`、`APE`、`FLAC`、`WAV` 等。#### 视频压缩原理

次要是将视频像素数据(RGB,YUV 等)压缩成为视频码流,从而升高视频的数据量,也就是解决像素。> **YUV:**  和 `RGB` 一样是一种色彩编码格局,相比 `RGB` 更利于压缩。其中 "Y" 示意亮堂度(Lumina nce 或 Luma),也就是灰阶值;而 "U" 和 "V" 示意的则是色度(Chrominance 或 Chroma),作用是形容影像色调及饱和度,用于指定像素的色彩。** 视频压缩分为上面两种类型 **:**1. 帧内压缩 **

也叫空间压缩,相似于图像压缩,属于有损压缩算法,达不到很高的压缩比。**2. 帧间压缩 **  

次要是通过记录关键帧,通过压缩关键帧之间间断帧的冗余信息(间断帧内雷同的像素区域)的过程。为了记录关键帧,将视频的画面帧分为三类:- I 帧:帧内编码帧(intra picture),能展现最残缺的画面,可压缩的空间小,编码过程属于帧内编码。- P 帧:前向预测编码在帧(predictive-frame),须要参考后面的 I 帧或者 P 帧来找出不同局部进行编码,压缩比比拟高。- B 帧 双向预测,也就是 B 帧记录的是本帧与前后帧的差异。也就是说要解码 B 帧,不仅要获得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加获得最终的画面。B 帧压缩率高,然而对解码性能要求较高。**GOP(Group of Pictures)值 **

编码器将多张图像进行编码后生产成一段一段的 GOP,每一组 IPB 帧的序列蕴含多少帧,也就是一个 I 帧完结后须要通过多少帧能力呈现下一个 I 帧。所以同码率下 GOP 值越大,B 帧和 P 帧越多,视频品质越高。在压缩或者解压缩视频的过程用到 ** 编解码器(Codec)**。总的过程能够:![](http://blog.toringo.cn/20200630203846.png)    

** 视频的编码的过程:**

> 下图来源于[即时通讯网](http://www.52im.net/thread-2840-1-1.html)。![](http://blog.toringo.cn/20200807200311.png)

** 视频解码的过程:**

![](http://www.52im.net/data/attachment/forum/201604/16/131639c5cxopo2d6ciqjj2.png)

#### 音频压缩原理

音频压缩是在保障信号在听觉方面不产生失真的前提下,对音频数据信号进行尽可能大的压缩,去除冗余信息。冗余信号蕴含人耳听觉范围外的音频信号以及被掩蔽掉的音频信号等。例如,人耳所能觉察的声音信号的频率范畴为 20Hz~20KHz,除此之外的其它频率人耳无奈觉察,都可视为冗余信号。此外,依据人耳听觉的生理和心理声学景象,当一个强音信号与一个弱音信号同时存在时,弱音信号将被强音信号所掩蔽而听不见,这样弱音信号就能够视为冗余信号而不必传送。音频压缩不是明天的配角,想深刻学习可参考如下链接:>https://baike.baidu.com/item/%E9%9F%B3%E9%A2%91%E5%8E%8B%E7%BC%A9/392863
>
>https://www.kamilet.cn/how-audio-compression-works-and-can-you-really-tell-the-difference/



---



> 上面进入本文的第二个配角

## #FFmpeg

### 1. FFmpeg 什么?> FFmpeg is a collection of libraries and tools to process multimedia content such as audio, video, subtitles and related metadata.

简略说就是一个跨平台的视频解决的程序。### 2. FFmpeg 的原理

整个过程根本能够说成:解复用 => 解码 => 编码 => 复用器。

_ __
| | | |
| input | demuxer | encoded data | decoder
| file | ———> | packets | —–+
|_______| |______________| |

                                       v
                                  _________
                                 |         |
                                 | decoded |
                                 | frames  |
                                 |_________|

__ __ |
| | | | |
| output | <——– | encoded data | <—-+
| file | muxer | packets | encoder
|________| |______________|




### 3.FFmpeg 装置

FFmpeg 分为 3 个版本:Static、Shared、Dev

**Mac 装置:**

brew install ffmpeg


其余装置请参考[官网](https://ffmpeg.org/)。### 4. FFmpeg 用法

它能别离对视频的的各个组成进行编码,它对音视频的编码格局反对也比拟全面。例如:对视频容器的装换、音视频的压缩、视频截取、截图、滤镜、音频提取等等,十分弱小。** 命令行语法:**

ffmpeg [全局参数] [输出文件参数] -i [输出文件] [输入文件参数] [输入文件]




** 视频信息:**

// 获取视频信息
ffmpeg -i input.mp4

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from ‘input2.mp4’:
Metadata:

major_brand     : isom
minor_version   : 512
compatible_brands: isomiso2mp41
encoder         : Lavf58.29.100
description     : Packed by Bilibili XCoder v2.0.2

Duration: 00:08:24.45, start: 0.000000, bitrate: 2180 kb/s // 时长,码率

Stream #0:0(und): Video: hevc (Main) (hev1 / 0x31766568), yuv420p(tv), 1920x1080 [SAR 1:1 DAR 16:9], 2046 kb/s, 25 fps, 25 tbr, 16k tbn, 25 tbc (default)  // 第一个流是视频流,编码格局是 hevc(封装格局为 hev1),每一帧示意为 yuv420p,分辨率 1920*1080,码率 2046kb/s, fps 为 25。Metadata:
  handler_name    : VideoHandler
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 128 kb/s (default) // 第二个流是音频流,编码格局是 aac(封装格局为 mp4a)采样率是 44100 Hz,声道是立体声,码率 92Kbit/s。Metadata:
  handler_name    : SoundHandler



** 码率的装换:**

ffmpeg -i input.mp4 -b:v 64k -bufsize 64k output.mp4




** 帧率装换:**

ffmpeg -i input.mp4 -r 5 output.mp4




** 分辨率装换:**

ffmpeg -i input.mp4 -vf scale=480:-1 output.mp4 // 1080p 转为 480p




** 视频倍速:**

ffmpeg -i test1 “setpts=PTS/5” test4.mp4 // 视频 5 倍速装换
fmpeg -i input.mp4 -filter:a “atempo=2.0” 4s.mp4 // 音频 2 倍速播放
ffmpeg -i input.mp4 -filter_complex “[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]” -map “[v]” -map “[a]” -vn 4s.mp4 // 音视频同时 2 倍速




** 提取音视频:**

ffmpeg -i input.mp4 -an output.mp4 // 提取视频
ffmpeg -i input.mp4 -vn output.mp3 // 提取音频




** 视频比例转换:**

ffmpeg -i input.mp4 -aspect 21:9 output.mp4




** 视频容器转换:**

ffmpeg -i input.mp4 output.avi




** 视频截图:**

ffmpeg -ss 00:00:05 -i input.mp4 -vframes 1 -q:v 5 -f image2 pic-%03d.jpeg
// -ss 00:00:05 从第五秒开始 -vframes 1 只截取 1 帧 -q:v 5 图片品质 1 -5




** 视频截取:**

ffmpeg -ss 00:00:02 -i input.mp4 -t 6.5 -c copy cut.mp4
ffmpeg -ss 00:00:02 -i input.mp4 -to 00:00:10 -c copy cut.mp4




** 间断图片或视频生成 gif 图:**

ffmpeg -i output.mp4 -to 10 -r 30 -vf scale=100:-1 gg.gif // 截取视频某个局部生成 gif 100:-1 指定宽度,高度放弃原始比例

ffmpeg -r 5 -i pic-%03d.jpeg 11.gif // 多图生成 gif

// 图片还可生成视频
ffmpeg -r 20 -i pic-%03d.jpeg gif.mp4

ffmpeg -f concat -i “concat:part1.mp4|part2.mp4|3.mp4|part4.mp4” -c copy output.mp4 // 多个视频拼接成一个




** 图片或视频加滤镜:**

// 含糊滤镜
ffmpeg -y -i pic-012.jpeg -vf boxblur=7 blur.jpeg
// 变色
ffmpeg -i pic-012.jpeg -vf colorbalance=rm=1 colorbalance1.jpg // 调整 rgb 某个维度的权重实现变色。
ffmpeg -i pic-012.jpeg -vf colorchannelmixer=.3:.4:.3:0:.3:.4:.3:0:.3:.4:.3 colorchannelmixer1.jpg // 对 rgba 四个通道进行从新计算,并别离给定权重比例。
ffmpeg -i pic-012.jpeg -vf hue=h=30:s=1 hue1.jpg // 扭转色调,相当在调色板上调色
ffmpeg -i pic-012.jpeg -vf lutyuv=”y=negval:u=negval:v=negval” lutyuv1.jpg // lutyuv 用于 yuv 色彩空间
ffmpeg -i pic-012.jpeg -vf negate=0 negate1.jpg // 反转
ffmpeg -i pic-012.jpeg -vf swapuv swapuv1.jpg // UV 调换
ffmpeg -i pic-012.jpeg -vf crop=w=200:h=300:x=500:y=800 crop1.jpg // 裁剪




** 增加水印:**

ffmpeg -i input.mp4 -i pic-012.jpeg -filter_complex “[1:v] scale=176:144 [logo];0:voverlay=x=0:y=0” out.mp4 // 给视频增加图片水印

ffmpeg -i input.mp4 -vf “drawtext=fontsize=100:fontcolor=white:alpha=0.3:text=’%{localtime:%Y-%m-%d %H-%M-%S}’:y=h-line_h-100:x=(w-text_w)/2” output22.mp4// 增加文字水印

ffmpeg -i input.mp4 -i pic-012.jpeg -filter_complex “[1:v] scale=176:144 [logo];0:voverlay=x=0:y=0” out.mp4

ffmpeg -i input.mp4 -vf drawtext=”fontsize=100:text=’ 我是水印 ’:fontcolor=green:enable=lt(mod(t,3),1)” interval-sy.mp4
// t 工夫,s
// mod(t,2) 计算 t%2
// lt(mod(t,2),1) 如果 mod(t,2)<1, 返回 1,否则返回 0
// enable=lt(mod(t,2),1) 每隔 1s 显示一次水印,enable=lt(mod(t,3),1) 每隔 3s.




** 增加字幕:**

// 第一步 用 you-get 下载 B 站视频
// 第二步 用 danmaku2ass.py 转换弹幕 https://github.com/m13253/dan…
// 第三步 能够用 ffmpeg 转换弹幕
ffpmeg -i input.ass input.srt

// 第四步 给视频增加字幕或弹幕 字幕可增加多个
ffmpeg -i input.mp4 -vf subtitles=input.ass output.mp4




** 为音频增加封面:**

ffmpeg -loop 1 -i cover.jpg -i input.mp3 -c:v libx264 -c:a aac -b:a 192k -shortest output.mp4

// -loop 1 示意始终循环,-shortest 音频完结视频输入就完结




** 视频画中画:**

ffmpeg -re -i input.mp4 -vf “movie=output.mp4,scale = 480*320[test]; in overlay [out]” -vcodec libx264 videoInvideo.mp4




** 多宫格:**

ffmpeg -y -i input.mp4 -i input.mp4 \
-i input.mp4 -i input.mp4 \
-filter_complex “nullsrc=size=640×480[base]; \
[0:v]scale=320×240[topleft]; \
[1:v]scale=320×240[topright]; \
[2:v]scale=320×240[bottomleft]; \
[3:v]scale=320×240[bottomright]; \
baseoverlay=shortest=1[tmp1]; \
tmp1overlay=shortest=1:x=320[tmp2]; \
tmp2overlay=shortest=1:y=240[tmp3]; \
tmp3overlay=shortest=1:x=320:y=240″ \
-vcodec libx264 9_video_filtered.flv
// nullsrc 创立画布




** 视频压缩:**

ffmpeg -i input.mp3 -ab 128 output.mp3 // 压缩音频

ffmpeg -i input.mp4 -vf scale=1280:-1 -c:v libx264 -preset veryslow -crf 24 output.mp4 // 压缩视频




** 视频直播推流:**

// 录制视频保留在本地
ffmpeg -f avfoundation -i “1” -vcodec libx264 -preset ultrafast -f h264 -r 30 ~/Downloads/test.h264

// 推送已下载在文件夹的视频
ffmpeg -re -i ~/Downloads/xxx.mp4 -vcodec libx264 -acodec aac -strict -2 -f flv rtmp://localhost:1935/live

// 录制桌面
ffmpeg -f avfoundation -i “1” -vcodec libx264 -preset ultrafast -acodec libfaac -f flv rtmp://localhost:1935/rtmplive/room

// 录制桌面和麦克风
ffmpeg -f avfoundation -i “1:0” -vcodec libx264 -preset ultrafast -acodec libmp3lame -ar 44100 -ac 1 -f flv rtmp://localhost:1935/live/room

// 录制桌面和麦克风,并关上摄像头拍摄
ffmpeg -f avfoundation -framerate 30 -i “1:0” -f avfoundation -framerate 30 -video_size 640×480 -i “0” -c:v libx264 -preset ultrafast -filter_complex ‘overlay=main_w-overlay_w-10:main_h-overlay_h-10’ -acodec libmp3lame -ar 44100 -ac 1 -f flv rtmp://localhost:2016/rtmplive/room




** 直播 DEMO:**

1. 装置反对 `rtmp` 的 docker 镜像:` docker pull tiangolo/nginx-rtmp` 
2. 启动 `tiangolo/nginx-rtmp` 容器:`docker run -d -p 1935:1935 --name nginx-rtmp tiangolo/nginx-rtmp`
   查看 `nginx` 配置: `docker exec -it nginx-rtmp /bin/bash`
   ![](http://blog.toringo.cn/20200807202113.png)
   推流地址:`rtmp://10.17.8.189:1935/live`
3. Ffmpeg 推流:`ffmpeg -f avfoundation -i "1:0" -vcodec libx264 -preset ultrafast -acodec libmp3lame -ar 44100 -ac 1 -f flv rtmp://localhost:1935/live/room`
4. 用反对反对 `rtmp` 的播放器 (IINA) 或者 `ffplay` 关上:`ffplay rtmp://10.17.8.189:1935/live`

一个简略的直播 demo 就跑起来了。****



### 5. FFmpeg 在 Node 中的用法

**[Fluent-ffmpeg](https://github.com/fluent-ffmpeg/node-fluent-ffmpeg)**

**Fluent-ffmpeg** 是将简单的 **ffmpeg** 命令形象成 nodeJs 的模块,前提是零碎已装置 **FFmpeg**。** 一些简略的用法 **

// 视频信息
ffmpeg.ffprobe(input, function (err, metadata) {
console.dir(metadata);
});

// 提取音频
ffmpeg(input)
.audioCodec(“libmp3lame”)
.on(“error”, function (err) {

console.log("产生谬误:" + err.message);

})
.on(“end”, function () {

console.log("提取音频实现 ????????!");

})
.save(resOut);

// 提取视频
ffmpeg(input)
.noAudio()
.on(“error”, function (err) {

console.log("产生谬误:" + err.message);

})
.on(“end”, function () {

console.log("提取视频实现 ????????!");

})
.save(resOut);




## #总结

回顾一下,狭义上的视频是由:** 音频 ** 和 ** 视频 ** 两局部组成,它们别离有对应的 ** 各自的编码标准 **,** 视频容器 ** 是将不同编码格局的音、视频组合在一起的一种 ** 封装格局 **。视频编码格局次要是对视频的大小进行压缩,分为 ** 帧内压缩 ** 和 ** 帧间压缩 **,帧间压缩次要是通过记录 ** 关键帧 ** 模式来进行压缩。`FFmpeg` 是解决音视频编码的一种程序,次要原理:`demuxer => decoder => encoder => muxer`。`Fluent-ffmpeg` 是将简单的 `ffmpeg` 命令形象成 `nodeJs` 的模块,前提是零碎已装置 `FFmpeg`,这对于前端工程师来说,能够用它解决泛滥音视频操作。## #挖坑

** 下一篇预报:**`FFmpeg` 和 `wasm` 在浏览器中的碰撞

<br />

<p style="text-align: center">—— 完 ——</p>

<br />

> 本文参考文章
>
> [即时通讯网 - 史上最艰深视频编码技术入门](http://www.52im.net/thread-2840-1-1.html)
>
> [简书 - 音视频基础知识](https://www.jianshu.com/p/614b3e6e641a)
>
> [滤镜实现各种图片成果 | Video-Filters | avfilter | 变色](https://www.geek-share.com/detail/2763908000.html)
>
> [阮一峰:FFmpeg 视频解决入门教程](http://www.ruanyifeng.com/blog/2020/01/ffmpeg.html)









正文完
 0