1. 视频基础知识

1. 图像基础概念

  • 像素 :像素是一个图片的基本单位,pix是英语单词picture,加上英语单词"元素element",就得到了pixel,简称px。所以"像素"有"图像元素"之意。
  • 分辨率:指的是图像的大小或者尺寸。比如 1920x1080 。
  • 位深:指在记录数字图像的颜色时,计算机实际上是用每个像素需要的位深来表示的。比如红色分量使用 8bit 。
  • 帧率:在一秒钟时间内传输图片的帧数(张数),也可以理解为图形处理器每秒钟能够刷新几次。例如:25fps 表示一秒有 25 张图片。
  • 码率:视频文件在单位时间内使用的数据流量。例如 1Mbps 。
  • Stride:指在内存中每行像素所占的空间。为了实现内存对齐,每行像素在内存中所占的空间并不一定是图像的宽度。

1.1. 像素

像素是一个图片的基本单位pix是英语单词picture,加上英语单词"元素element",就得到了pixel,简称px。所以"像素"有"图像元素"之意。

例如 2500x2000 的照片就是指横向有 2500 个像素点,竖向有 2000 个像素点,总共是 500 万个像素,也俗称为 500 万像素照片。

将这个图片放大,可以发现是由一块一块的小方块组成的,每一个小方块就是一个像素点。

1.2. 分辨率

图像(视频)的分辨率指的是图像的大小或尺寸 。我们通常用像素来表示图像的尺寸。

例如分辨率为 2500x2000 的照片就是指的 横向(宽)有 2500 个像素点,竖向(高)有 2000 个像素点。

常见的分辨率:

360P(640x360)、720P(1280x720)、1080P(1920x1080)、4K(3840x2160)、8K(7680x4320)


常说的 1080P 720P 其实 指的是分辨率的垂直像素,一般情况下我们都是按照 16:9 (宽:高)来计算分辨率。

那么 720P 的分辨率计算流程如下:

  1. 720P 代表垂直(高)像素有 720 个像素点
  2. 由于图片的比例为 16:9 ,那么水平(宽)的像素点数量为 720 ÷ 9 × 16 = 1280
  3. 故 720P 的分辨率为 1280x720

像素越多视频就越清晰 ,1080P 的像素点总共有 1920x1080 约等于 200 万个像素,720p 的像素点总共有 1080x720 约等于 92 万个像素。1080p 的像素点数量比 720p 的像素点数量多两倍多,故 1080p 比 720p 更清晰。图像的分辨率越高,图像就越清晰。

低分辨率下只能看到一个大概的轮廓,而高分辨率能看到更多的细节,故更加清晰。

1.3. 位深

我们看到的彩色图片,都有三个通道,分别为红(R),绿(G),蓝(B)通道。 (如果需要透明度则还有 alpha 分量)。

通常每个通道用 8bit 表示,8bit 能表示 256 种颜色,所以可以组成 256*256*256=16,777,216=1677万种颜色。这里的 8bit 就是我们讲的位深。

**每个通道的位深越大,能够表示的颜色值也就越大。**比如现在高端电视说的是 10bit 色彩,即每个通道用 10bit 表示,10bit 能表示 1024 种颜色,故可以组成 1024*1024*1024 约等于 10亿种颜色,是 8bit 的 64 倍。

常见的颜色还是 8bit 居多。

1.4. 帧率

帧率即 FPS(每秒有多少帧画面)。经常玩游戏的小伙伴应该很熟,我们玩游戏时,FPS 越高就代表游戏画面越流畅,越低则越卡顿。

由于视觉图像在视网膜的暂时停留,一般图像帧率能达到 24 帧,我们就认为图像是连续动态的。

  • 电影帧率一般是 24fps
  • 电视剧一般是 25fps
  • 监控行业一般是 25fps
  • 音视频通话一般是 25fps

帧率越高,画面越流畅,需要的设备性能也越高。

1.5. 码率

  • 码率指的是视频文件在单位时间内使用的数据流量。比如 1Mbps 。
  • 大多数情况下 码率越高,分辨率越高,也就越清晰。但本身就模糊的视频文件码率也可以很大,分辨率小的视频文件也可能比分辨率大的视频文件清晰。【比如光线不好的时候录制的视频】
  • 对于同一个原始图像源的时候,同样的编码算法,码率越高,图像的失真就会越小,视频画面就会越清晰。【可见后面的h264编码,当采用低码率,那么在编码的时候就会设置更高的QStep】
  • 码率是一个统计的指标,并不是一个实际的功能。

1.6. Stride

设计到计算机底层对于内存的利用,不影响理解,只是开发时使用,这里不做介绍。

2. RGB、YUV深入讲解

  • RGB:红R、绿G、蓝B三种基色。
  • YUV:"Y" 表示明亮度(Luma),也就是灰阶值,"U" 和 "V" 表示的是色度(Chroma)。

2.1. RGB

  • 我们前面已经讲过 RGB 色彩表示,这里我们重点讲 RGB 的排列。通常的图像像素是按 RGB 顺序进行排列的,但有些图像处理要转换为转成其他顺序,比如 OpenCV 经常要转换为 BGR 的排列方式

常见的一些排列方式:

2.2. YUV

2.2.1. 基础介绍

  • 与我们熟知的 RGB 类似,YUV 也是一种颜色编码方法,它是指将亮度参量和色度参量分开进行表示的像素编码格式。
  • 这样分开的好处就是不但可以避免互相干扰,没有 UV 信息一样可以显示完整的图像 (因而解决了彩色电视与黑白电视的兼容问题 ),还可以降低色度的采样率而不会对图像质量影响太大 ,降低了视频信号传输时对频宽(宽度)的要求。

  • YUV 是一个比较笼统的说法,针对它的具体排列方式,可以分为很多种具体的格式,但基础两个格式如下:
    • 打包(packed)格式:将每个像素点的Y、U、V分量交叉排列 并以像素点为单元连续的存放在同一个数组中,通常几个相邻的像素组成一个宏像素(macro-pixel)。
    • 平面(planar)格式:使用三个数组分开连续的存放Y、U、V三个分量,即Y、U、V分别存放在各种的数组中。

2.2.2. 采样表示法

  • YUV 采用 A:B:C 表示法来描述 Y,U,V 采用频率比例,下图中黑点表示采样像素 Y 分量,空心圆表示采用像素的 UV 分量。主要分为 YUV 4:4:4、YUV 4:2:2、YUV 4:2:0 这三种常用的类型
  • 4:4:4 表示色度频道没有下采样,即每一个 Y 分量对应 一个 UV 分量。
  • 4:2:2 表示 2:1 的水平下采样,没有垂直下采样,即每两个 Y 分量共享 一个 UV 分量。
  • 4:2:0 表示 2:1 的水平下采样,2:1 的垂直下采样,即每四个 Y 分量共享 一个 UV 分量。

YUV4:4 : 4,不是说4个Y,4个V,4个U,而是说 Y 和 UV的比例关系。

同理 YUV4:2:0,也不是说4个Y,2个Y,0个U,也是说的 Y 和 UV 的比例关系。

2.2.3. YUV数据存储方式

下面以每个分量的采用数据为位深 8bit 为例描述YUV的数据存储方式

  1. 4:4:4 格式
  2. 4:2:2 格式
  3. 4:2:0 格式
2.2.3.1. YUV 4:4:4 格式

比如 I444(YUV444P)格式

  • 对应 FFmpeg 像素表示 AV_PIX_FMT_YUV444P
  • 该类型为 平面(planar)格式
  • 一个宏素块 24bit,即 3 个字节
2.2.3.2. YUV 4:2:2 格式

比如 I422(YUV422P)格式

  • 对应 FFmpeg 像素表示 AV_PIX_FMT_YUV422P
  • 该类型为 平面(planar)格式
  • 一个宏素块 16bit,即 2 个字节
2.2.3.3. YUV 4:2:0 格式【最常用】

比如 I420(YUV420P)格式

  • 对应 FFmpeg 像素表示 AV_PIX_FMT_YUV420P
  • 该类型为 平面(planar)格式
  • 一个宏素块 12bit,即 1.5 个字节
2.2.3.4. YUV 4:2:0 格式 - NV12

比如 NV12 格式

  • 对应 FFmpeg 像素表示 AV_PIX_FMT_NV12
  • 该类型为 YUV420P 的变种,对 Y 分量采用平面模式,对 UV 采用打包模式
  • 一个宏素块 12bit,即 1.5 个字节
2.2.3.5. YUV 4:2:0 格式 - 各种变种格式参考

2.3. RGB和YUV的转换

  • 通常情况下 RGB 和 YUV 直接的互相转换都是调用接口实现,比如 FFmpeg 的 swscale 或者 libyuv 等库。
  • 主要转换标准是 BT601 和 BT709。
    • TV range 的分量范围: 16-235(Y)、16-240(UV),故叫做 Limited Range
    • PC range 的分量范围: 0-255(Y、UV),故叫做 Full Range
    • 而对于 RGB 来说没有分量范围之分,全是 0-255
  • BT601 TV Range 转换公式

RGB 转换为 YUV:

Y = 0.299 * R + 0.587 * G + 0.114 * B;

U = -0.169 * R - 0.331 * G + 0.5 * B;

V = 0.5 * R - 0.419 * G - 0.081 * B;

YUV 转换为 RGB:

R = Y + 1.402 * (Y - 128)

G = Y +0.34414 * (U - 128) - 0.71414 * (U - 128)

B = Y + 1.772 * (V - 128)

  • 从 YUV 转换到 RGB ,如果值小于 0 要取 0,值大于 255 要取 255。

2.4. RGB和YUV的转换------为什么解码出错会出现绿屏

当解码时,从 packet 中解析 frame,由于解码失败,导致得到YUV的都为0,再根据公式转换为 RGB

R = 1.402 * (-128) = -126.598

G = -0.34414 * (-128) - 0.71414 * (-128) = 135.45984

B = 1.722 * (-128) = -126.228

由于 RGB 值范围是 [0,255],所以最终的值为:

R = 0

G = 135

B = 0

此时只有 G 分量有值,故全屏是绿色。

2.5. YUV Stride对齐问题

设计到计算机底层对于内存的利用,不影响理解,只是开发时使用,这里不做介绍。

3. 视频的主要概念

3.1. 基础名词

3.2. I帧

3.3. P、B帧

3.4. 常用视频压缩算法

4. 补充知识点

4.1. 常用分辨率

|----|------|------------|-------|------|
| 标号 | 视频类型 | 格式尺寸 | 类型 | 比例 |
| 1 | 4K | 4096*2160 | 4K | 16:9 |
| 2 | 2K | 2560*1440 | 2K | 16:9 |
| 3 | 全高清 | 1920*1080 | 1080p | 16:9 |
| 4 | 高清 | 1280*720 | 720p | 16:9 |
| 5 | 标清 | 720*480 | 480p | 3:2 |
| 6 | 标清 | 640*480 | 480p | 4:3 |
| 7 | 流畅 | 320*240 | 240p | 4:3 |

补充说明:

多数情况下4k特指4096 * 2160分辨率。而根据使用范围的不同,4K分辨率也有各种各样的衍生分辨率,例如Full Aperture 4K的4096 * 3112、Academy 4K的3656 * 2664以及UHDTV标准的3840 * 2160等,都属于4K分辨率的范畴。

原文链接:4K、2K、1080p、720p、480p、240p常见视频清晰度-CSDN博客

4.2. 位深

如果不是8bit,而是1bit,那么就只会有八种颜色了,全红、全绿、全蓝、全黑、全白...。因为每个通道只能显示两种颜色,红、非红;绿,非绿;蓝,非蓝。

4.3. 码率

每一秒传输的帧数是固定的,比如一秒传输10帧,每帧大小1MB,那么码率就是10MBps,但是如果降低码率了,降低为5Mbps,由于每秒传输的帧数不应该发生变化,所以每帧的大小只能传输0.5MB了,所以就会造成数据丢失(压缩的结果),回显就会出现不清晰,或者马赛克了。


4.3.1. 核心概念

  1. 帧率(FPS)与码率的关系
    • 帧率(FPS) 是每秒显示的帧数(如20FPS=20帧/秒),由视频的时序特性决定,与码率无关
    • 码率(比特率) 是每秒传输的数据量(如200Mbps),决定了 每帧能分配到的平均数据量
    • 关键结论
      • 当帧率固定时(如20FPS),降低码率会迫使编码器压缩每帧的数据量(减少每帧的比特数),而非减少帧数。
      • 提高码率则允许每帧保留更多数据,从而提升画质。
  1. 为什么压缩每帧会影响清晰度?
    • 视频编码(如H.264/H.265)的本质是用尽可能少的数据表示图像。编码器会通过以下手段压缩每帧:
      • 空间压缩:合并相似区域、舍弃高频细节(如纹理)。
      • 时间压缩:通过运动预测(帧间编码)减少冗余。
    • 码率降低时:编码器必须更激进地压缩每帧,导致:
      • 量化步长增大 → 更多细节被丢弃 → 画面模糊或出现块效应。
      • 运动预测精度下降 → 残差数据更粗糙 → 动态画面出现拖影。

4.3.2. 你的例子修正

  • 假设条件
    • 原始视频:10秒,20FPS → 共200帧,原始每帧1MB(未压缩)。
    • 编码后目标码率:
      • 200Mbps(25MB/s) :每秒分配25MB数据,平均每帧 25MB/20帧=1.25MB/帧
      • 100Mbps(12.5MB/s) :每秒分配12.5MB数据,平均每帧 12.5MB/20帧=0.625MB/帧
  • 关键区别
    • 高码率(1.25MB/帧)时,编码器可以保留更多细节(接近原始1MB/帧的未压缩质量)。
    • 低码率(0.625MB/帧)时,编码器必须将每帧压缩到更小的体积,导致画质下降。

4.3.3. 类比说明

  • 把视频想象成一本书
    • 帧率:每秒翻多少页(固定20页/秒)。
    • 码率:每页允许写的字数。
      • 高码率 → 每页字数多(细节丰富,清晰)。
      • 低码率 → 每页字数少(必须缩写或删减内容,信息丢失)。

4.3.4. 常见误区澄清

  1. "码率降低是否会导致丢帧?"
    • 不会!帧率(FPS)是编码前确定的参数(如20FPS),编码器会优先保证帧数,转而压缩每帧质量。
    • 只有极端情况下(如网络传输拥塞),可能主动丢帧,但这属于实时传输问题,而非编码本身的特性。
  1. "为什么不能直接降低分辨率?"
    • 降低分辨率(如1080p→720p)确实可以减少数据量,但这是另一种压缩手段。
    • 固定分辨率下,码率降低是通过压缩算法(如量化、预测)实现的,而非改变分辨率。

4.3.5. 总结

  • 帧率(FPS):决定视频的流畅度,编码时固定不变。
  • 码率:决定每帧的画质,码率越低,每帧被压缩得越狠,清晰度越低。
  • 编码器的任务:在固定帧率和目标码率下,智能分配每帧的数据量,平衡压缩率与画质。

4.4. 像素排列

常规理解来说一个像素不是一个字节,可以理解为一个对象。【这里指的位深为 8bit 】

比如不是说 char a[1280*720], a[0]是一个像素,应该理解为:

复制代码
struct pixel
{
    char r;
    char g;
    char b;
}
pixel a[1280*720];
a[0] 是一个像素。

当然,写代码肯定是按照char来理解的,那么就是 char a[1280*720*3],a[0]、a[1]、a[2] 三个组合是一个像素;a[3]、a[4]、a[5] 三个组合起来是一个像素。其中a[0]、a[1]、a[2]谁是R,谁是G,谁是B,就看排列规则了。

4.5. 花屏

  • 如果页面完全看不出来轮廓,代表分辨率选错了
  • 如果能看出来轮廓,但是花屏,那么分辨率没问题,数据格式选错了

4.6. YUV444和YUV420的命名

YUV444 代表4个Y,4个U,4个V。

YUV420 代表4个Y,1个U,一个V。

但是看名字不应该是4个Y,2个U,0个V吗,按道理4个Y,1个U,一个V不应该叫做 YUV411 吗?


但其实它的命名源于历史约定采样网格的排列方式,而非严格的数学比例。下面详细解释:

4.6.1. 1. YUV 4:2:0 的采样结构

YUV 4:2:0 的色度(UV)采样方式如下:

  • 每4个Y(亮度)像素 共享1个U和1个V(色度)值。
  • 但色度采样在垂直方向也进行了减半,即每隔一行才保留一组UV值。

实际存储示例(以2×2像素块为例):

复制代码
Y1 Y2   → 亮度(Y)全采样
Y3 Y4

U1 V1   → 色度(UV)在水平和垂直方向均减半
  • 4个Y对应 1个U和1个V(水平和垂直方向均共享)。

4.6.2. 2. 为什么叫4:2:0而不是4:1:1?

  • 4:2:0的命名逻辑
    • 第一个数字(4):参考基准(通常表示亮度的横向采样数)。
    • 第二个数字(2) :色度(U/V)在水平方向的采样比例(相对于亮度的一半)。
    • 第三个数字(0) :色度在垂直方向的采样比例(0表示垂直方向再减半)。
      • 即色度在水平和垂直方向均为亮度的一半,最终等效于"4个Y对应1个UV"。
  • 对比其他格式
    • 4:4:4:色度无降采样(每个Y对应一个UV)。
    • 4:2:2:色度水平减半,垂直全采样(每行保留UV)。
    • 4:1:1:色度水平降为1/4,垂直全采样(常见于DV视频)。
  • 关键区别
    4:2:0的"0"强调垂直方向也减半,而4:1:1的色度在垂直方向未减半。

4.6.3. 3. 命名背后的历史原因

  • 4:2:0的"0"是约定俗成
    早期工程师用数字表示色度采样相对于亮度的比例,垂直减半被标记为"0"(类似占位符),而非数学上的严格除法。
  • 与4:1:1的对比
    4:1:1是水平方向更激进的降采样(每4个Y共享1个UV,但垂直方向不降采样),而4:2:0是水平和垂直均减半。

4.6.4. 4. 直观图示

以8×8像素块为例:

  • Y(亮度):全采样(64个值)。
  • U/V(色度)
    • 水平方向:每隔1个像素采样(4:2:0 → 水平减半 → 每行4个UV)。
    • 垂直方向:每隔1行采样(4:2:0 → 垂直减半 → 共4行UV)。
    • 最终UV数据量:4×4=16个U和16个V,相当于64个Y对应16个UV → 4:1的比例

4.6.5. 5. 为什么不是4:1:1?

  • 4:1:1的色度采样
    • 水平方向:每4个Y共享1个UV。
    • 垂直方向:每行都保留UV(不降采样)。
    • 示例:8×8像素块中,UV数据量为2×8=16个(每行2个UV,共8行)。
    • 相当于64个Y对应16个UV → 4:1的比例,但垂直方向未减半。
  • 4:2:0的色度采样
    • 水平和垂直均减半 → 最终UV数据量是4:1:1的一半(更节省带宽)。

4.6.6. 总结

  • YUV 4:2:0 的命名反映的是色度在水平和垂直方向的减半采样("0"代表垂直减半),而实际存储比例是4个Y对应1个UV。
  • 4:1:1则是水平方向更激进的降采样,但垂直方向未减半。
  • 这种命名是历史惯例,数字更多表示"采样网格的分布方式",而非严格的数学比例。

如果需要记忆,可以简单理解为:

  • 4:2:0 = 色度在两个方向都减半(最终4Y:1UV)。
  • 4:1:1 = 色度仅在水平方向减半(垂直方向全采样)。

4.7. 生成BMP图片文件

复制代码
#include <iostream>
#include <fstream>
#include <vector>

// BMP 文件头
#pragma pack(push, 1) // 确保结构体没有字节填充
struct BMPFileHeader {
    uint16_t bfType;      // 文件类型,必须是 'BM'
    uint32_t bfSize;      // 文件大小
    uint16_t bfReserved1; // 保留,必须为 0
    uint16_t bfReserved2; // 保留,必须为 0
    uint32_t bfOffBits;   // 从文件头到像素数据的偏移
};

// DIB 头(BITMAPINFOHEADER)
struct BMPInfoHeader {
    uint32_t biSize;          // 此结构的大小(40 字节)
    int32_t  biWidth;         // 图像宽度
    int32_t  biHeight;        // 图像高度
    uint16_t biPlanes;        // 颜色平面数,必须为 1
    uint16_t biBitCount;      // 每像素位数(24 表示 RGB)
    uint32_t biCompression;   // 压缩类型(0 表示不压缩)
    uint32_t biSizeImage;     // 图像大小(可以为 0,如果不压缩)
    int32_t  biXPelsPerMeter; // 水平分辨率
    int32_t  biYPelsPerMeter; // 垂直分辨率
    uint32_t biClrUsed;       // 使用的颜色数(0 表示所有)
    uint32_t biClrImportant;  // 重要颜色数(0 表示所有)
};
#pragma pack(pop)

void createRedBMP(const char* filename) {
    int width = 640;
    int height = 480;

    /*
    * 这里 width * 3,是因为一个像素点有RGB3个点,故实际上一个像素点有三个点,刚好与下面的 infoHeader.biBitCount 对应。
    * 而且也一定要和下面的 infoHeader.biBitCount 对应,因为这里是计算的是总字节大小,这里 *3,就代表一个像素点3字节,那么每个RGB对应1个字节,那么 infoHeader.biBitCount 就该是24位,即3个字节,
    * 否则图形的总字节大小算下来就不对。 
    * +3 & (~3) 就是对齐四个字节的操作,先+3,向上填充直最近4的倍数,然后在 &(~3),把余数给去掉,(3 = 011, ~3 = 100,即最后两位一定会被去掉)
    */
    // 计算图像数据大小
    int row_padded = (width * 3 + 3) & (~3); // 每行 4 字节对齐
    int dataSize = row_padded * height;

    // 创建文件头和信息头
    BMPFileHeader fileHeader = {};
    BMPInfoHeader infoHeader = {};

    fileHeader.bfType = 0x4D42; // 'BM'
    fileHeader.bfSize = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + dataSize;
    fileHeader.bfOffBits = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader);

    infoHeader.biSize = sizeof(BMPInfoHeader);
    infoHeader.biWidth = width;
    infoHeader.biHeight = height;
    infoHeader.biPlanes = 1;
    infoHeader.biBitCount = 24; // RGB。 24 / 3 = 8位 = 1个字节。0~255。为什么要除3,因为一个像素要包含RGB3个点,故一位像素点,要切分成三份来使用。与上面的row_padded对应
    infoHeader.biCompression = 0; // 不压缩

    // 打开文件
    std::ofstream file(filename, std::ios::binary);
    if (!file) {
        std::cerr << "无法创建文件: " << filename << std::endl;
        return;
    }

    // 写入文件头和信息头
    file.write(reinterpret_cast<const char*>(&fileHeader), sizeof(fileHeader));
    file.write(reinterpret_cast<const char*>(&infoHeader), sizeof(infoHeader));

    // 写入像素数据(红色)
    std::vector<uint8_t> row(row_padded, 0); // 用于存储每行的数据
    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            row[x * 3 + 0] = 0;   // B
            row[x * 3 + 1] = 0;   // G
            row[x * 3 + 2] = 255; // R
        }
        file.write(reinterpret_cast<const char*>(row.data()), row_padded);
    }

    file.close();
}

int main() {
    createRedBMP("red_image.bmp");
    std::cout << "红色 BMP 图像已创建: red_image.bmp" << std::endl;
    return 0;
}

4.8. 生成YUV图片文件

复制代码
#include <iostream>
#include <fstream>

void generateRedYUVImage(const char* filename, int width, int height) {
    // 分配内存
    int size = width * height * 3;  // YUV444: 每个像素3个字节
    unsigned char* yuvData = new unsigned char[size];

    // 填充数据(全红)
    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            int index = (y * width + x) * 3;
            yuvData[index + 0] = 255;  // Y
            yuvData[index + 1] = 255;  // U
            yuvData[index + 2] = 255; // V
        }
    }

    // 保存数据到文件
    std::ofstream outFile(filename, std::ios::binary);
    if (outFile.is_open()) {
        outFile.write(reinterpret_cast<const char*>(yuvData), size);
        outFile.close();
        std::cout << "Image saved to " << filename << std::endl;
    }
    else {
        std::cerr << "Unable to open file for writing" << std::endl;
    }

    // 释放内存
    delete[] yuvData;
}

int main() {
    int width = 640;  // 图像宽度
    int height = 480; // 图像高度
    const char* filename = "red_image.yuv";

    generateRedYUVImage(filename, width, height);

    return 0;
}

使用ffplay播放:

复制代码
ffplay -f rawvideo -pixel_format yuv444p -video_size 640x480 red_image.yuv
相关推荐
強云30 分钟前
内存池(C++)
c++
JANYI20182 小时前
在c++中老是碰到string&,这是什么意思?
开发语言·c++
锦夏挽秋3 小时前
Qt 信号槽机制底层原理学习
c++·qt
天堂的恶魔9463 小时前
C++ - 仿 RabbitMQ 实现消息队列(1)(环境搭建)
开发语言·c++·rabbitmq
JCBP_5 小时前
C++(1)
开发语言·c++·算法
幼安2295 小时前
第一章-语言基础\3.STL
开发语言·c++
美狐美颜sdk6 小时前
什么是美颜SDK?美颜SDK安卓与iOS端开发指南
android·人工智能·ios·音视频·美颜sdk·直播美颜sdk
EasyDSS6 小时前
AI视频智能分析网关打造社区/工厂/校园/仓库智慧消防实现精准化安全管控
人工智能·音视频
北极有牛6 小时前
cpp学习笔记2--class
c++·笔记·学习
代码程序猿RIP7 小时前
【C语言干货】野指针
c语言·开发语言·数据结构·c++·算法