封装
视频是什么?你可能知道 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 就是色彩信息。两个例子证明:
- 在黑暗中,颜色没有意义,因为看不到。
- 早年时候存在的黑白电视机就没有 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播放视频流程详解
视频和视频帧:视频和帧基础知识整理