返回首页

FFmpeg前传,音视频呀😳

FFmpeg前传,音视频呀😳

FFmpeg 剧情前传

在使用ffmpeg之前还是要有一些音视频基础知识的,虽然不多,但是在满足日常需求应该足够啦,防止我失忆,赶紧把知道的记录一下。

音频处理基础知识

音频处理流程(基于娱乐直播系统)

  • 音频数据流转 采集音频的原始数据为 PCM 数据 多媒体文件(mp4/flv 等)在传输过程中可以不用生成,如果向保存成常用格式可以被播放那就当我没说。

声音基础三要素

  • 音调 音频的快慢
  • 音色 谐波: 此处峰值最高的绿色波形为基频,变化全部在基频之上进行变化,通过两条峰值较低的频率,将基频变成粉色波线的频率, 而此处,粉色的波型,顶峰弯曲部分则称为谐波, 两条小的波形为一次谐波和二次谐波
  • 音量 振动的幅度,初中都知道就不说了。

模数转换

对模拟信号进行数字量化

  • 每隔一段时间对模拟信号进行采样

采样前

采样后

最终转换为二进制方波

音频常用原始数据及基本量化概念

原始数据常用格式

  • PCM
  • WAV

基本量化三个概念(在视频采样时,也是可以进行类比)

  • 采样大小(位深): 一个采样用多少 bit 存放。常用的是 16bit(16 位 位深)
  • 采样率: 采样频率 8k, 16k, 32k, 44.1k, 48k
  • 声道数: 单声道,双声道,多声道

码率计算

码率=采样率×采样大小×声道数码率 = 采样率 \times 采样大小 \times 声道数

eg: 采样率为 44.1KHz, 采样大小为 16bit, 双声道 PCM 数据编码的 WAV 文件,码率为 44.1K x 16 x 2= 1411.Kb/s 相当于每秒传输 1.4mb 大小的数据 WAV 编码数据,相当于在 PCM 数据上添加了一个 Header 来描述 PCM 数据

WAV例子

例如使用ffmpeg从flv视频中提取出音频wav数据文件并且使用xxd转换为16进制文件

ffmpeg -i v1.flv -vn -acodec pcm_s16le -ar 44100 -ac 2 out.wav

使用vim打开wav文件,并且使用xxd进行转换。

vim out.wav
# 在vim内的命令模式下
:%!xxd

下面是部分观察到的数据。

FFmpeg 采集音频流程

整体流程

整体流程

打开设备

  • 注册设备
    • 相关 api
    #include "libavdevice/avdevice.h"
    avdevice_register_all();
  • 设置采集方式 avfoundation(mac)/dshow(windows)/alsa(linux)
    • 相关 api
    #include "libavformat/avformat.h"
    AVInputFormat *iformat = av_find_input_format("audiostring")
  • 打开音频设备
    • 相关 api
    #include <libavcodec/avcodec.h>
    AVFormatContext *fmt_ctx = NULL;
    AVDictionary *options = NULL;
    int ret = avformat_open_input(&fmt_ctx, "device_name", iformat, &options);
    // 释放上下文
    avformat_close_input(&fmt_ctx);
    • 获取数据包相关 api
    AvPacket pkt;
    av_read_frame(fmt_ctx, &pkt);
    // 初始化资源
    av_init_packet(&pkt);
    // 释放资源
    av_packet_unref(&pkt);

录制音频

  • 创建文件
  • 将数据写入文件
  • 关闭文件

音频编码(压缩)

  • 消除冗余信息(有损压缩) (人耳听觉范围之外的音频信号以及被遮蔽掉的音频信号)

    • 频域遮蔽

    • 时域遮蔽

  • 无损压缩(zip 等) 熵编码 _ 哈夫曼编码 _ 算数编码 * 香农编码

音频编码过程

常见的音频编码器

  • OPUS 较新 WebRTC 默认使用 OPUS
  • AAC 在直播系统中应用广泛
  • Ogg
  • Speex
  • iLBC
  • AMR
  • G.711

音频编码质量比较

音频编码码率

AAC 格式

ADTS 格式详解

音频重采样

将音频三元组(采样率,采样大小和通道数)的值转成另外一组值 eg: 44100/16/2 -> 48000/16/2

重采样的步骤
  • 创建采样上下文
  • 设置参数
  • 初始化重采样
  • 进行重采样
  • 涉及 api
    swr_alloc_set_opts
    swr_init
    swr_convert
    swr_free

ffmpeg 编码过程

创建并打开编码器
  • 创建编码器 avcodec_find_encoder
  • 创建上下文 avcodec_alloc_context3
  • 打开编码器 avcodec_open2

视频基础

基础概念

  • 视频由一组图像组成,而图像又由像素组成,像素又由 RGB 组合而成

码流的计算

分辨率

  • X 轴的像素个数 x Y 轴的像素个数
  • 常见宽高比 16:9 / 4:3
  • 360P/72P/1K/2K

帧率

  • 每秒钟采集/播放图像的个数
  • 动画的帧率是 25 帧/s
  • 常见的帧率: 15 帧/s(满足实时通话), 30 帧/s, 60 帧/s

未编码的 RGB 码流

RGB码流=分辨率(×)×3(Byte)×帧率RGB码流 = 分辨率(宽 \times 高) \times 3(Byte) \times 帧率

eg: 1280x720x3x25 = 69120000 约 69M 通常说的码流用位来表示,此处还得乘 8

图像的显示

  • 图像等于显示区域
  • 图像小于显示区域(拉伸/留白)
  • 图像大于显示区域(缩小/截断)

YUV

YUV(也称 YCBCr): Y 表示明亮度, UV 的作用是描述的影像色彩及饱和度
  • 如果只存在 Y 数据,则图像位黑白
  • Cb 表示蓝色部分, Cr 部分表示红色部分
主要的采样格式有 YUV4:2:2, YUV4:2:2 和 YUV4:4:4

RGB 与 YUV 的关系

  • RGB 用于屏幕图像展示
  • YUV 用于采集与编码
RGB 转 YUV
Y=0.299×R+0.587×G+0.114×BU=0.147×R0.289×G+0.436×B=0.492×(BY)V=0.615×R0.515×G0.100×B=0.877(RY)\begin{aligned} Y &= 0.299 \times R + 0.587 \times G + 0.114 \times B \\ U &= -0.147 \times R - 0.289 \times G + 0.436 \times B = 0.492 \times (B - Y) \\ V &= 0.615 \times R -0.515 \times G - 0.100 \times B = 0.877 * (R - Y) \\ \end{aligned}
YUV 转 RGB
R=Y+1.140×VG=Y0.394×U0.581×VB=Y+2.032×U\begin{aligned} R &= Y + 1.140 \times V \\ G &= Y - 0.394 \times U - 0.581 \times V \\ B &= Y + 2.032 \times U \end{aligned}

YUV 常见格式

  • YUV4:4:4

  • YUV4:2:2

  • YUV4:2:0(应用最广泛) 4:2:0

YUV 数据量的计算

YUV=Y×1.5YUV=RGB÷2\begin{aligned} YUV &= Y \times 1.5 \\ YUV &= RGB \div 2 \end{aligned}

YUV4:2:0 存储格式

YUV 码流

YUV码流=分辨率(×)×1.5×帧率\begin{aligned} YUV码流 = 分辨率(宽 \times 高) \times 1.5 \times 帧率 \end{aligned}

H264 视频编码

GOP (Group of Pictures)

I/P/B IDR 帧

I 帧之前存在两个数据集,反别描述图像序列与图像本身

  • I 帧(interframe frame), 关键帧,采用帧内压缩技术, IDR 帧属于 I 帧
  • P 帧(forward Predicted frame), 向前参考帧.压缩时,只参考前面已经处理的帧,采用帧间压缩技术. 它占 I 帧的一半大小
  • B 帧(Bidirectionally predicted frame), 双向参考帧。压缩时,既参考前面已经处理的帧,也参考后面的帧,帧间压缩技术。它占 I 帧的14\frac{1}{4} 大小
  • IDR 帧(Instantaneous Decoder Refresh) 解码器立即刷新帧
    • 每当遇到 IDR 帧时,解码器就会清空解码器惨开 buffer 中的内容
    • 每个 GOP 中的第一帧就是 IDR 帧
    • IDR 帧是一种特殊的 I 帧
帧与分组的关系

先解码 I 帧,再解码 P 帧,B 帧参考前面的 I 和后面的 P 帧 而播放时,读取帧就是顺序读取

H264 压缩技术

宏块

  • 宏块是视频压缩操作的基本单元
  • 无论是帧内压缩还是帧间压缩,它们都以宏块位单位

帧内压缩

解决空域数据冗余问题(有损压缩)

帧内压缩理论

注:帧内压缩解决的是 I 帧的压缩问题

  • 相邻像素差别不大,所以可以进行宏块预测
    • 帧内预测
      • 9 种预测模式
      内部4x4矩形为预测结果
      ![](/pics/media/basic/pics/26.png)
      分别为垂直,水平,平均值预测结果
      ![](/pics/media/basic/pics/27.png)
      预测图象与原图进行比较
      - 帧内预测残差值 原始图与预测图的差值计算获取残差值 - 压缩 预测模式信息与残差值压缩 ![](/pics/media/basic/pics/28.png)
      压缩图解
  • 人对亮度的敏感超过色度
  • YUV 很容易将亮度与色度分开

帧间压缩

解决时域数据冗余问题(有损压缩)

GOP

进行帧间压缩的基础为 GOP,即在同一组画面相邻的图像间进行压缩

参考帧

见 I/P/B 帧部分

运动估计(宏块匹配 + 运动矢量)
  • 宏块查找
    • 三步搜索
    • 二维对数搜索
    • 四步搜索
    • 钻石搜索 查找宏块当前帧的坐标,并查找下一帧相似度最高宏块的坐标,这两个坐标即为运动矢量 整个过程即为 运动估计 需要存储的即为运动矢量

运动估计图示 1-1

运动估计图示 1-2

运动估计也存在残差值

  • 视频花屏的原因

    如果 GOP 分组中有帧丢失,会造成解码端的图像发生错误,出现花屏现象

  • 视频卡顿的原因

整数的离散余弦变换(DCT)(无损压缩)

将空间上的相关性变为频域上无关的数据然后进行量化(无损压缩)

VLC (变长编码) 压缩(无损压缩)

CABAC 压缩(无损压缩)

H264 编码整体流程

H264 码流

  • NAL 层(Network Abstration Layer) 视频数据网络抽象层
  • VCL 层(Video Coding Layer), 视频数据编码层

码流的基本概念

  • H264 Slice

  • SODB (String of Data Bits) 原始数据比特流,长度不一定是 8 的倍数,需要补齐,由 VCL 层产生

  • RBSP (Raw Byte Sequence Payload) SODB + trailing bites 算法是如果 SODB 最后一个字节不对齐,则补 1 和多个 0

  • NALU (Network Abstration Layer Unit) NAL Header(1B) + RBSP

    整体码流分层

Profile and Level (SPS(sequence paramater set))

H264 Profile

对视频压缩特性的描述,Profile 越高,说明采用了越高的压缩特性

H264 Level

Level 是对视频的描述,Level 越高,视频的码率,分辨率,fps 越高

PPS(Picture parameter set) and slice header

PPS

Slice Header
  • 帧类型
  • GOP 中解码帧序号
  • 预测权重
  • 滤波

RTMP 协议相关

....有时间再记录

FFmpeg 剧情

评论 (...)

加载中...