封装

视频是什么?你可能知道 MP4,他是视频常用模式,你可能也听说过 AVI,FLV 等等很多视频格式,但她们内部是怎么构成的,你又不完全清楚。
这里先和大家分享下,我们知道的这些视频文件格式其实只是封装方式。视频文件内部包含了视频数据和音频数据,把他们通过某种方式封装起来,使得视频和音频数据同步就是封装要做的事情。

工具

视频播放涉及太多知识,泛泛而谈毫无意义,比如上一节,我说了封装,但你听了以后肯定还是摸不着头脑。
但如果有个工具可以边学习边操作理解起来就容易的多,这里我选择 FFmpeg。当然,OpenCV,VLC 原理也都差不多,学习其中的任何一种即可举一反三。

下载 FFmpeg

直接官网下载即可:https://ffmpeg.org/,在 download 选项下,找到您对应平台的二进制文件即可。

代码时间

有了FFmpeg,我这边直接通过如下命令来表明,视频文件是通过封装视频数据和音频数据来实现的:

./ffmpeg -i LRV_20230927_182949_01_029.mp4 ffmetadata FFMETADATAFILE
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'LRV_20230927_182949_01_029.mp4':
  Metadata:
    major_brand     : avc1
    minor_version   : 0
    compatible_brands: avc1isom
    creation_time   : 2023-09-27T18:29:39.000000Z
    cycle           : 16
    gop             : 16
  Duration: 00:00:12.88, start: 0.000000, bitrate: 13071 kb/s
  Stream #0:0[0x1](eng): Video: h264 (Main) (avc1 / 0x31637661), yuvj420p(pc, bt709, progressive), 368x640 [SAR 1:1 DAR 23:40], 3948 kb/s, 24 fps, 24 tbr, 24k tbn (default)
    Metadata:
      creation_time   : 2023-09-27T18:29:39.000000Z
      handler_name    :  Ambarella AVC
      vendor_id       : [0][0][0][0]
      encoder         : Ambarella AVC encoder
    Side data:
      displaymatrix: rotation of 90.00 degrees
  Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 192 kb/s (default)
    Metadata:
      creation_time   : 2023-09-27T18:29:39.000000Z
      handler_name    :  Ambarella AAC
      vendor_id       : [0][0][0][0]

其中 Stream #0:0[0x1](eng): Video: 表示的就是视频流;Stream #0:1[0x2](eng): Audio:表示的就是音频流。

小结

FFmpeg 看起来很强大,能直接知道读出视频文件中的视频部分和音频部分,虽然 Stream #0:0[0x1](eng): Video:Stream #0:1[0x2](eng): Audio: 这两行后面的内容我们暂时还不能读懂,但猜测是对视频数据和音频数据的参数的一些详细解读。

关于 FFmpeg

FFmpeg 并不能直接操作音视频,而是操作 PCM 或者 YUV

随之而来的问题:

YUV 是什么

YUV 格式有两大类:planar 和 packed。
对于 planar 的 YUV 格式,先连续存储所有像素点的 Y,紧接着存储所有像素点的 U,随后是所有像素点的 V。
对于 packed 的 YUV 格式,每个像素点的 Y,U,V 是连续交叉存储的。

YUV,分为三个分量,“Y”表示明亮度(Luminance 或 Luma),也就是灰度值;而 “U” 和 “V” 表示的则是色度(Chrominance或 Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。

与我们熟知的 RGB 类似,YUV 也是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有 UV 信息一样可以显示完整的图像,只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题。并且,YUV 不像 RGB 那样要求三个独立的视频信号同时传输,所以 用 YUV 方式传送占用极少的频宽

YUV码流的存储格式其实与其采样的方式密切相关,主流的采样方式有三种,YUV4:4:4,YUV4:2:2,YUV4:2:0

YUV VS RGB

RGB, YUV 都是用于记录视频/图片数据的。
YUV 中最重要的是 Y,因为人眼对亮度比较敏感,UV 就是色彩信息。两个例子证明:

  1. 在黑暗中,颜色没有意义,因为看不到。
  2. 早年时候存在的黑白电视机就没有 UV,只有 Y

为什么不实用 RGB 而是 YUV? 原因:YUV的优点是可以对其中两个分量CbCr进行采样而不太破坏图像的显示, rgb就不行会导致图像严重失真。

PCM 是什么

IJKPlayer

IJKPlayer 简介

ijkplayer是一个基于 FFmpeg 和 SDL 的开源 Android/iOS 视频播放器,由 bilibili 开发。它支持几乎所有视频格式,具有高效的硬件解码和渲染能力,可以实现流畅的视频播放体验。ijkplayer 还提供了丰富的 API 接口,支持多种播放控制方法和事件监听,可以让开发者灵活地集成和定制播放器。此外,ijkplayer 还提供了一些强大的剪辑和水印功能,可以实现视频编辑和个性化定制。
ijkplayer 和 FFMpeg、SDL 的关系是如何的呢?简单来说 ffmpeg 提供最基础的解码能力,将视频文件解析成特定的二进制流数据(比如我们常见的RGB、YUV),而SDL负责将特定的二进制流文件渲染出来。

IJKPlayer 在 iOS 和 Android 平台上实现的主要差异表现在视频硬解码方案和音视频渲染方案上:

iOS

  • 视频硬解码:VideoToolbox
  • 音频渲染:AudioQueue
  • 视频渲染:OpenGL ES

Android

  • 视频硬解码:MediaCodec
  • 音频渲染:OpenSL ES、AudioTrack
  • 视频渲染:OpenGL ES、MediaCodec

IJKPlayer 项目的目录结构

  • tool:初始化项目工程脚本。
  • config:编译 FFmpeg 使用的配置文件。
  • extra:存放编译 IJKPlayer 所需的依赖源文件, 如 FFmpeg、OpenSSL 等。
  • ijkmedia:核心代码。
  • ijkplayer:播放器数据下载及解码相关。
  • ijksdl:音视频数据渲染相关。
  • ios:iOS平台上的上层接口封装以及平台相关方法。
  • android:android平台上的上层接口封装以及平台相关方法。

IJKPlayer 解码(硬解/软解)

IJKPlayer 在视频解码上支持软解和硬解两种方式,可在起播前配置优先使用的解码方式,播放过程中不可切换。IJKPlayer 中的音频解码只支持软解,暂不支持硬解。

问题一:bilibili 国际版硬解转软解

问题二:卡顿率(Buffer队列)

问题三:seek操作

问题四:各平台渲染引擎
Android : ANativeWindow

参考

解析 IJKPlayer
音视频 ijkplayer 源码解析系列1--播放器介绍
我们为什么使用DASH
FFmpeg播放视频流程详解
视频和视频帧:视频和帧基础知识整理