C/C++ 程序员黄金方向 - 音视频基础知识和 ffmpeg 编译

C/C++ 程序员黄金方向 - 音视频基础知识和 ffmpeg 编译

1.常用概念

音视频相关名词、术语、概念

1.1 帧率

用于测量显示帧数的量度,测量单位为每秒显示帧数(fps)或 赫兹(Hz)。每秒显示帧数(fps)或者图形处理场时每秒能够更新的次数。一般来说 30fps 是可以接接受的,如果能将性能提升至 60fps 则可以明显提升交互感和逼真感,但是超过 75fps 就不容易察觉有明显的的流畅度提升。如果帧数超过屏幕刷新率,则会浪费图像处理能力,因为监视器不能以这么快的速度更新,这样超过的部分就浪费了。

1.2 分辨率

视频成像产品所形成的图像大小或尺寸

1.3 刷新率

刷新率是指屏幕每秒画面被刷新的次数,刷新率分为垂直刷新率和水平刷新率,一般提到的刷新率通常指垂直刷新率。垂直刷新率表示屏幕的图象每秒钟重绘多少次,也就是每秒钟屏幕刷新的次数,以 Hz(赫兹)为单位。刷新率越高越好,图象就越稳定,图像显示就越自然清晰,对眼睛的影响也越小。刷新频率越低,图像闪烁和抖动的就越厉害,眼睛疲劳得就越快。一般来说,如能达到 80Hz 以上的刷新频率就可完全消除图像闪烁和抖动感,眼睛也不会太容易疲劳。

1.4 编码格式

编码的目的是压缩数据量,采用编码算法压缩冗余数据。常用的编码格式有如下这两种。

  • MPEG(MPEG-2,MPEG-4)
  • H.26X(H.263,H.264/AVC,H.265/HEVC)

1.5 封装格式

把编码后的音视频数据以一定格式封装到一个容器,封装格式有 MKV、AVI、TS 等

1.6 码率

码率也就是比特率,比特率是单位时间播放连续的媒体的比特数量。比特率越高,带宽消耗的越多。

1.7 画质与码率

视频质量和码率、编码算法都有关系

1.8DTS 与 PTS

  • DTS:decode Time Stamp,主要用于标示读入内存中的比特流在什么时候开始送入解码器中进行解码
  • PTS:decode Time Stamp,主要用于度量解码后的视频帧什么时候被显示出来

1.9 YUV 与 RGB

  • YUV
  • YUV 是编译 true-color 颜色空间(color space)的种类,Y’UV, YUV, YCbCr,YPbPr 等专有名词都可以称为 YUV,彼此有重叠。“Y”表示明亮度(Luminance、Luma),“U”和“V”则是色度、浓度(Chrominance、Chroma)
  • RGB
  • 也是一种颜色空间模型,三原色光模式(RGB color model),又称 RGB 颜色模型或红绿蓝颜色模型,是一种加色模型,将红(Red)、绿(Green)、蓝(Blue)三原色的色光以不同的比例相加,以合成产生各种色彩光。

音视频免费学习地址:FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发

整理了一些面试题、学习资料、教学视频和学习路线图共享在群文件,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等),免费分享,有需要的可以点击 788280672 加群自取~希望对大家有帮助

1.10 视频帧及音频帧

常见的视频帧有 I、P、B 帧等

  • I 帧表示关键帧,可以理解为这一帧画面的完成保留,解码时只需要本帧数据就可以完成,这里其实可以把 I 帧的压缩等同于单独压缩一幅图片
  • P 帧又称前向预测编码帧,也有帧间预测编码帧,P 帧需要依赖前面的 I 帧或者 P 帧才能进行编解码,因为一般来说,P 帧存储的是当前帧画面与前一帧(前一帧可能是 I 帧也可能是 P 帧)的差别,较专业的说法是压缩了时间冗余信息,或者说提取了运动特性。(也就是差别帧,P 帧没有完整画面数据,只有与前一帧的画面差别的数据)
  • B 帧时双向差别帧,B 帧非常特殊,它存储的是本帧与前后帧的差别,因此带有 B 帧的视频在解码时的逻辑会更复杂些,CPU 开销会更大。(要解码 B 帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面数据与本帧数据的叠加取得最终的画面)

音视频概念没有视频帧那么清晰,几乎所有视频编码格式都可以简单地认为 I 帧就是编码后的一幅图像。但音频帧跟编码格式相关,它是各个编码标准自己实现的。

  • 对 PCM(未经编码的音频数据)来说,它根本就不需要帧的概念,根据采样率和采样精度就可以播放,比如比如采样率为 44.1HZ,采样精度为 16 位的音频,你可以算出 bitrate(比特率)是 44100* 16kbps,每秒的音频数据是固定的 44100*16/8 字节。
  • AMR 帧比较简单,它规定每 20ms 的音频是 1 帧,每一帧音频都是独立的,有肯能采用不同的编码算法
  • MP3 帧较复杂些,包含了更多的信息,比如采样率、比特率等各种参数。具体如下:音频数据帧个数由文件大小和帧长决定,每一帧的长度可能不固定,也肯能固定,由比特率决定,每一帧又分为帧头和数据实体两部分,帧头记录了 MP3 的比特率、采样率、版本等信息,每一帧之间相互独立。

1.11 量化精度

量化精度表示可以将模拟信号分成多少个等级,量化精度越高,音乐的声压振幅越接近原音乐。采样频率,它是针对每秒钟所采样的数量,而量化精度则是对于声波的振幅进行切割,形成类似阶梯的度量单位。所以,如果说采样频率是对声波水平进行的 X 轴切割,那么量化精度则是对 Y 轴的切割,切割的数量是以最大振幅切成 2 的 n 次方计算,n 就是 bit 数。如果是 8bit,那么在振幅方面的采样就有 256 阶,若是 16bit,则振幅的计量单位便会成为 65536 阶,越多的阶数就越能精确描述每个采样的振幅高度。如此,也就越接近原始声波的“能量”,在还原的过程序也就越接近原始的声音了。

1.12 采样率

采样率指每秒音频采样点个数(8000/44100Hz),采样率单位用 Hz 表示。像是 CD 音乐的标准采样频率为 44.1KHz(指的就是在 1s 中对声音采样 44100 次,也就是对声音 1 秒的声音记录 44100 个点,用 44100 个点来表示 1 秒钟的声音),这也是目前声卡与计算机作业间最常用的采样频率。


2.在 Mac 下编译 FFmpeg

2.1 下载 FFmepg 源码

ffmepg官网直通车

2.2 获取动态库.so

在根目录新建 build_android.sh

#!/bin/bash
NDK=/Users/xxx/Library/Android/sdk/ndk/21.1.6352462
SYSROOT=$NDK/platforms/android-16/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
#ADDI_CFLAGS="-marm"
function build_one
./configure \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--disable-yasm \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-doc \
--disable-symver \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make install
CPU=arm
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-marm"
build_one

提示:一般脚本书写不规范容易导致报错脚本中的 NDK=/Users/xxx/Library/Android/sdk/ndk/21.1.6352462 NDK 路径需要修改。

执行 ./build_android.sh 出现以下信息

最后在当前文件夹下生成 android 文件,里面有我们需要的.so

2.3 编译中遇到的问题

这里有一个重点,不同的 ffmpeg 版本如果用老的脚本文件会运行不出想要的效果,如果有时候 c 在编译时报错,那就要修改 ndk 版本,这边笔者使用的是 4.0 以上版本的 ffmpeg 和 ndk-r21b,以及所使用的脚本

#!/bin/bash
# 注意修改这里的ndk路径
NDK=/Users/xxx/android-ndk-r21b
API=21
# arm aarch64 i686 x86_64
ARCH=arm
# 指定目标cpu的架构 armv7a aarch64 i686 x86_64
PLATFORM=armv7a
TARGET=$PLATFORM-linux-androideabi
# 设置工具链mac苹果电脑的是darwin-x86_64 而如果是linux的话则是linux-x86_64
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64/bin
# 设置编译产物的输出目录,这里表示在当前目录下新建Android_out目录
PREFIX=$(pwd)/android/$PLATFORM
CFLAG="-D__ANDROID_API__=$API -U_FILE_OFFSET_BITS -DBIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD -Os -fPIC -DANDROID -D__thumb__ -mthumb -Wfatal-errors -Wno-deprecated -mfloat-abi=softfp -marm"
build_one()
./configure \
--prefix=$PREFIX \
--cc=$TOOLCHAIN/$TARGET$API-clang \
--cxx=$TOOLCHAIN/$TARGET$API-clang++ \
--ld=$TOOLCHAIN/$TARGET$API-clang \
--target-os=android \
--arch=$ARCH \
--cpu=$PLATFORM \
--cross-prefix=$TOOLCHAIN/$ARCH-linux-androideabi- \
--enable-cross-compile \
--enable-shared \
--disable-static \
--enable-runtime-cpudetect \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-symver \
--enable-small \
--enable-gpl \
--enable-nonfree \
--enable-version3 \
--disable-iconv \
--enable-neon \
--enable-hwaccels \
--enable-jni \
--enable-mediacodec \
--disable-avdevice  \
--disable-decoders \
--enable-decoder=vp9 \
--enable-decoder=h264 \
--enable-decoder=mpeg4 \
--enable-decoder=aac \
--enable-decoder=h264_mediacodec \
--disable-postproc \
--extra-cflags="$CFLAG" \
--extra-ldflags="-marm"
echo "out put path "$PREFIX
echo $TOOLCHAIN/$TARGET$API-clang
echo $TOOLCHAIN/$TARGET$API-clang++
echo $TOOLCHAIN/$TARGET$API-clang
build_one