Metal之探究理解视频渲染RGB与YUV颜色编码

一、颜色编码

① RGB 颜色编码

  • RGB 三个字母分别代表红、绿、蓝,这三种颜色作为三个基底颜色,将它们以不同的比例相加,可以产生多种多样的颜色。
  • RGB 图像中,每个像素点都有红、绿、蓝三个基底颜色,其中每种原色都占用 8 bit,也就是一个字节(0-255),那么一个像素点也就占用 24 bit,也就是三个字节。

在这里插入图片描述

  • 在图像显示中,一张 1280 * 720 大小的图片,就代表着它有 1280 * 720 个像素点。其中每一个像素点的颜色显示都采用 RGB 编码方法,将 RGB 分别取不同的值,就会展示不同的颜色,就占用 1280 * 720 * 3 / 1024 / 1024 = 2.63 MB 存储空间。

② YUV 颜色编码

  • YUV 是指亮度参量色度参量分开表示的像素格式,而这样分开的好处就是不但可以避免相互干扰,还可以降低色度的采样率而不会对图像质量影响太大。
  • YUV 颜色编码采用的是明亮度色度来指定像素的颜色。
  • Y 表示明亮度(Luminance、Luma) U 和 V 表示色度(Chrominance、Chroma)而色度又定义了颜色的两个方面:色调和饱和度。
    • Y 通道数值越高,图片则越亮;
    • U 通道数值越高,颜色就越接近蓝色;
    • V 通道数值越高,颜色就越接近红色。
  • YUV 颜色编码格式在默认情况下是图像和视频压缩的标准。
  • 和 RGB 表示图像类似,每个像素点都包含 Y、U、V 分量。但是它的 Y 和 UV 分量是可以分离的,如果没有 UV 分量一样可以显示完整的图像,只不过是黑白的,如下图所示:

在这里插入图片描述

  • 对于 YUV 图像来说,并不是每个像素点都需要包含了 Y、U、V 三个分量,根据不同的采样格式,可以每个 Y 分量都对应自己的 UV 分量,也可以几个 Y 分量共用 UV 分量。

二、RGB 与 YUV 的相互转换

  • 对于图像显示器来说,它是通过 RGB 模型来显示图像的,而在传输图像数据时又是使用 YUV 模型,这是因为 YUV 模型可以节省带宽。因此就需要采集图像时将 RGB 模型转换到 YUV 模型,显示时再将 YUV 模型转换为 RGB 模型。
  • RGB 到 YUV 的转换,就是将图像所有像素点的 R、G、B 分量转换到 Y、U、V 分量。公式如下:
    Y = 0.299 * R + 0.587 * G + 0.114 * B
    U = -0.147 * R - 0.289 * G + 0.436 * B
    V = -0.615 * R - 0.515 * G - 0.100 * B
  • YUV 到 RGB 的转换如下:
    R = Y + 1.14 * V
    G = Y - 0.39 * U - 0.58 * V
    B = Y + 2.03 * U
  • 此时的转换结束后,每个像素点都有完整的 Y、U、V 分量。而之前提到 Y 和 UV 分量是可以分离的,接下来通过不同的采样方式,可以将图像的 Y、U、V 分量重新组合。
  • 不同采样格式都是在一张图像所有像素的 RGB 转换到 YUV 基础上进行的。

三、采样方式

  • YUV 的优点之一是,色度频道的采样率可比 Y 频道低,同时不会明显降低视觉质量。
  • 有一种表示法可用来描述 U 和 V 与 Y 的采样频率比例,这个表示法称为 A:B:C 表示法。

① YUV 4:4:4 采样

  • 表示色度频道没有下采样, 每个 Y 分量对应自己的 UV 分量,每一个 Y 分量对于一对 UV 分量,每像素占用 (Y + U + V = 8 + 8 + 8 = 24bits)3 字节。
  • 其中的 Y、U、V 三个分量的采样比例是相同的,所以每个像素点的分量信息都是完整的,每个分量占用 8bit,一个像素点占用 1 个字节。与 RGB 颜色编码相比,并没有节省带宽,占用的存储空间也没有减少。

在这里插入图片描述

  • 假设原始图像的像素为(一对[]表示一个像素点):
    [Y0, U0, V0]; [Y1, U1, V1]; [Y2, U2, V2]; [Y3, U3, V3];
  • 将原始图像像素按照YUV4:4:4采样的码流为(相对原始像素是原样输出):
    Y0, U0, V0, Y1, U1, V1, Y2, U2, V2, Y3, U3, V3
  • 最后映射还原的像素点 = 原始图像的像素,为:
    [Y0, U0, V0]; [Y1, U1, V1]; [Y2, U2, V2]; [Y3, U3, V3];
  • 可以看到这种采样方式的图像和 RGB 颜色模型的图像大小是一样,并没有达到节省带宽的目的,当将 RGB 图像转换为 YUV 图像时,也是先转换为 YUV 4:4:4 采样的图像。

② YUV 4:2:2 采样

  • 表示 2:1 的水平下采样,没有垂直下采样,每两个 Y 分量共用一对 UV 分量,每像素占用 (Y + 0.5U + 0.5V = 8 + 4 + 4 = 16bits)2 字节
  • 对于每两个 U 样例或 V 样例,每个扫描行都包含四个 Y 样例。
  • 两个 Y 分量共用一套 UV 分量,意味着 UV 分量是 Y 分量采样的一半,Y 分量和 UV 分量按照 2 : 1 的比例采样。如果水平方向有 4 个像素点,那么采样了 4 个 Y 分量,而只采样了 2 个 UV 分量。

在这里插入图片描述

  • 每采样一个像素点,都会采样 Y 分量,而 U、V 分量则会间隔一个采集一个;
  • 假设原始图像的像素为(一对[]表示一个像素点):
    [Y0, U0, V0]; [Y1, U1, V1]; [Y2, U2, V2]; [Y3, U3, V3];
  • 将原始图像像素按照 YUV4:2:2 采样的码流为:
    Y0, U0, Y1, V1, Y2, U2, Y3, V3
  • 最后映射还原的像素点为:
    [Y0, U0, V1]; [Y1, U0, V1]; [Y2, U2, V3]; [Y3, U2, V3];
  • 采样的码流映射为像素点,还是要满足每个像素点有 Y、U、V 三个分量。但是可以看到,第一和第二像素点公用了 U0、V1 分量,第三和第四个像素点公用了 U2、V3 分量,这样就节省了图像空间。

③ YUV 4:2:0 采样

  • 表示 2:1 的水平下采样,2:1 的垂直下采样,4 个 Y 分量共用一套 UV 分量,每四个 Y 分量共用一对 UV 分量,每像素占用 (Y + 0.25U + 0.25V = 8 + 2 + 2 = 12bits)1.5 字节
  • YUV 4:2:0 采样,并不是指只采样 U 分量而不采样 V 分量。而是指,在每一行扫描时,只扫描一种色度分量(U 或者 V),和 Y 分量按照 2 : 1 的方式采样。
  • 第一行扫描时,YU 按照 2 : 1 的方式采样,那么第二行扫描时,YV 分量按照 2:1 的方式采样。
  • 对于每个色度分量来说,它的水平方向和竖直方向的采样和 Y 分量相比都是 2:1 。
  • 在田字格的 4 个像素点中,4 个 Y 分量共用了一套 UV 分量,如图所示

在这里插入图片描述

  • 假设原始图像的像素为(一对 [] 表示一个像素点):
    [Y0, U0, V0]; [Y1, U1, V1]; [Y2, U2, V2]; [Y3, U3, V3];
    [Y5, U5, V5]; [Y6, U6, V6]; [Y7, U7, V7]; [Y8, U8, V8];
  • 将原始图像像素按照YUV4:2:0采样的码流为:
    Y0, U0, Y1, Y2, U2, Y3,
    Y5, V5, Y6, Y7, V7, Y8,
  • 最后映射还原的像素点为:
    [Y0, U0, V5]; [Y1, U0, V5]; [Y2, U2, V7]; [Y3, U2, V7];
    [Y5, U0, V5]; [Y6, U0, V5]; [Y7, U2, V7]; [Y8, U2, V7];
  • 从映射出的像素点中可以看到,四个 Y 分量是共用了一套 UV 分量,而且是按照 2*2 的小方格的形式分布的,相比 YUV 4:2:2 采样中两个 Y 分量共用一套 UV 分量,这样更能够节省空间。

④ YUV 4:1:1 采样

  • 表示 4:1 的水平下采样,没有垂直下采样。对于每个 U 样例或 V 样例,每个扫描行都包含四个 Y 样例。
  • 与其他格式相比,4:1:1 采样不太常用,本文不对其进行详细讨论

四、YUV 存储格式

① 平面格式与打包格式

  • YUV 格式可以分为打包格式和平面格式。在打包格式中,Y、U 和 V 组件存储在一个数组中,像素被组织到了一些巨像素组中,巨像素组的布局取决于格式;在平面格式中,Y、U 和 V 组件作为三个单独的平面进行存储。
    • planar 平面格式:指先连续存储所有像素点的 Y 分量,然后存储 U 分量,最后是 V 分量,如 YV12、YU12 格式;
    • packed 打包模式:指每个像素点的 Y、U、V 分量是连续交替存储的,如 YUYV 、NV21 格式。

② 基于 YUV 4:2:2 采样的格式

  • 常见的基于 YUV 4:2:2 采样的格式:YUYV 格式、UYVY 格式、YUV 422P 格式。
    • YUYV 格式:
      • YUYV 格式是采用打包格式进行存储的,指每个像素点都采用 Y 分量,但是每隔一个像素采样它的 UV 分量,排列顺序如下:
Y0 UO Y1 V0 Y2 U2 Y3 V2 
(Y0 和 Y1 公用 U0 V0 分量,Y2 和 Y3 公用 U2 V2 分量….)
      • YUYV 是 2 个Y 分量共用一对 UV 分量,YUYV 格式的存储格式:
(0  ~  7)  Y00  U00  Y01  V00  Y02  U01   Y03  V01
(8  ~ 15)  Y10  U10  Y11  V10  Y12  U11   Y13  V11
(16 ~ 23)  Y20  U20  Y21  V20  Y22  U21   Y23  V21
(24 ~ 31)  Y30  U30  Y31  V30  Y32  U31   Y33  V31
      • 一幅 720P (1280x720分辨率) 的图片,使用 YUV422 采样时占用存储大小为:
Y 分量:1280 * 720  = 921600 字节
U 分量:1280 * 720 * 0.5 = 460800 字节
V 分量:1280 * 720 * 0.5 = 460800 字节
总大小:Y 分量 + U 分量 + V 分量 =1280 * 720 + 1280 * 720 * 0.5 * 2/ 1024 / 1024 = 1.76 MB
      • 由上面计算可以看出 YUV422 采样的图像比 RGB 模型图像节省了 1/3 的存储空间,在传输时占用的带宽也会随之减小。
    • UYVY 格式:UYVY 格式也是采用打包格式进行存储,它的顺序和 YUYV 相反,先采用 U 分量再采样 Y 分量,排列顺序如下:
U0 Y0 V0 Y1 U2 Y2 V2 Y3
(Y0 和 Y1 公用 U0 V0 分量,Y2 和 Y3 公用 U2 V2 分量….)
    • YUV 422P 格式:YUV 422P 格式,又叫做 I422,采用的是平面格式进行存储,先存储所有的 Y 分量,再存储所有的 U 分量,再存储所有的 V 分量。

③ 基于 YUV 4:2:0 采样的格式

(A)YV12/YU12 (YUV420 采样方式)
  • 基于 YUV 4:2:0 采样的格式主要有 YUV 420P 和 YUV 420SP 两种类型,每个类型又对应其他具体格式。
YUV 420P 类型YUV 420SP 类型
YV12 格式NV12 格式
YU12 格式NV21 格式
  • YUV 420P 和 YUV 420SP 都是基于 Planar 平面模式进行存储的,先存储所有的 Y 分量后, YUV420P 类型就会先存储所有的 U 分量或者 V 分量,而 YUV420SP 则是按照 UV 或者 VU 的交替顺序进行存储,具体查看看下图:

在这里插入图片描述

  • YUV420P 的格式:

在这里插入图片描述

  • YV12 格式的存储方式:
(0  ~  3) Y00  Y01  Y02  Y03  
(4  ~  7) Y10  Y11  Y12  Y13  
(8  ~ 11) Y20  Y21  Y22  Y23
(12 ~ 15) Y30  Y31  Y32  Y33

(16 ~ 17) V00  V01
(18 ~ 19) V10  V11

(20 ~ 21) U00  U01
(22 ~ 23) U10  U11
  • YU12(也称 I420) 格式的存储方式:
(0  ~  3) Y00  Y01  Y02  Y03
(4  ~  7) Y10  Y11  Y12  Y13
(8  ~ 11) Y20  Y21  Y22  Y23
(12 ~ 15) Y30  Y31  Y32  Y33

(16 ~ 17) U00  U01
(18 ~ 19) U10  U11

(20 ~ 21) V00  V01
(22 ~ 23) V10  V11
  • 一幅 720P (1280x720分辨率) 的图片,使用 YUV420 采样时(格式 YV12/YU12 )占用存储大小为:
Y 分量:1280 * 720  = 921600 字节
U 分量:1280 * 720 *1/4= 230400 字节
V 分量:1280 * 720 *1/4= 230400 字节
总大小:Y 分量 + U 分量 + V 分量 =1280 * 720 + 1280 * 720 *1/4* 2/ 1024 / 1024 = 1.32 MB 
  • 由上面计算可以看出 YUV420 采样(格式 YV12/YU12 )的图像比 RGB 模型图像节省了 1/2 的存储空间。
(B)NV21/NV12 (YUV420 采样方式)
  • NV21/NV12 属于 YUV420SP,YUV420SP 格式有 2 个平面,Y 分量存储于一个平面,UV 分量交错存储于另一个平面。

在这里插入图片描述

  • NV21 格式的存储方式:
(0  ~  3) Y00  Y01  Y02  Y03  
(4  ~  7) Y10  Y11  Y12  Y13  
(8  ~ 11) Y20  Y21  Y22  Y23  
(12 ~ 15) Y30  Y31  Y32  Y33  

(16 ~ 19) V00  U00  V01  U01 
(20 ~ 23) V10  U10  V11  U11
  • NV12 格式的存储方式:
(0  ~  3) Y00  Y01  Y02  Y03
(4  ~  7) Y10  Y11  Y12  Y13
(8  ~ 11) Y20  Y21  Y22  Y23
(12 ~ 15) Y30  Y31  Y32  Y33

(16 ~ 19) U00  V00  U01  V01 
(20 ~ 23) U10  V10  U11  V11
  • NV21 与 NV12 格式的区别仅在于 UV 分量排列的先后顺序不同。一幅 720P (1280x720分辨率) 的图片,使用 YUV420 采样时(格式 NV21/NV12 )占用存储大小为:
Y 分量:1280 * 720  = 921600 字节
UV 分量:1280 * 720 *1/2= 460800 字节
总大小:Y 分量 + UV 分量 =1280 * 720 + 1280 * 720 *1/2)) / 1024 / 1024 = 1.32 MB 
  • 由上面计算可以看出 YUV420 采样(格式 NV21/NV12 )的图像比 RGB 模型图像也节省 1/2 的存储空间。

五、RGB 与YUV 转换矩阵的几何含义

  • YUV 与 RGB 的转换公式不止一种,主要原因是具体格式下,标准不同,这里采用苹果 Demo 中给出的转换矩阵,其它转换公式中,具体数值可能不同:
let ycbcrToRGBTransform = float4x4(
            simd_float4(+1.0000, +1.0000, +1.0000, +0.0000),
            simd_float4(+0.0000, -0.3441, +1.7720, +0.0000),
            simd_float4(+1.4020, -0.7141, +0.0000, +0.0000),
            simd_float4(-0.7010, +0.5291, -0.8860, +1.0000)
        );
  • 将上面向量与矩阵乘法写成行列式形式,可能更符合大家的直觉:
R = Y + 1.402*V - 0.701
G = Y - 0.3441*U - 0.7141*V + 0.5291
B = Y + 1.772*U - 0.886
  • 可以发现,这个 YUV 转 RGB 的公式其实是个线性变换,用几何的方式表达就是说:
    • 将一个 RGB 的颜色用 xyz 坐标表示,那么将这个坐标(旋转、缩放、平移)之后,新的 xyz 坐标就可以表示 YUV 颜色值;
    • 反之也是,将一个 YUV 颜色分量当做 xyz 坐标,那么将这个坐标逆向(旋转、缩放、平移)之后,新的 xyz 坐标就可以表示 RGB 颜色值;
  • 于是,可以在 3D 空间中画一个边长为 1 的正方体,后方左下角(0, 0, 0) 就代表黑色,前方右上角(1, 1, 1) 就代表白色,如下图右下角立方体。同样复制一个,并将其坐标用矩阵转换到 YUV 空间,如下图左上角倾斜的长方体。

在这里插入图片描述

  • 对于 RGB 的立方体,比较简单:它的 x 坐标越大,越往右方,颜色越红;y 坐标越大,越往上方,颜色越绿;z 坐标越大,越往前方,颜色越蓝。
  • 而 YUV 的长方体,它的 x 坐标越大,越往右方,亮度越大;y 坐标越大,越往上方,颜色从黄到蓝;z 坐标越大,越往前方,颜色从青绿到红。

在这里插入图片描述

let box1 = scene.rootNode.childNode(withName: "box", recursively: true)!
let box2 = scene.rootNode.childNode(withName: "box2", recursively: true)!
simpleProgram(node: box1)
simpleProgram(node: box2)

// YUV 到 RGB
let ycbcrToRGBTransform = float4x4(
    simd_float4(+1.0000, +1.0000, +1.0000, +0.0000),
    simd_float4(+0.0000, -0.3441, +1.7720, +0.0000),
    simd_float4(+1.4020, -0.7141, +0.0000, +0.0000),
    simd_float4(-0.7010, +0.5291, -0.8860, +1.0000)
);
let p = ycbcrToRGBTransform.inverse // RGB 到 YUV
box1.simdTransform = p

// box2.simdTransform = box2.simdTransform * ycbcrToRGBTransform.inverse * box2.simdTransform.inverse
// 用 shader 进行可视化显示
func simpleProgram(node:SCNNode) {
    let program = SCNProgram()
    program.vertexFunctionName = "vertexShader"
    program.fragmentFunctionName = "fragmentShader"
    
    // 赋值给**SCNGeometry**或者**SCNMaterial**
    guard let material = node.geometry?.materials.first else { fatalError() }
    material.program = program
}
// 默认的头文件
#include <metal_stdlib>
using namespace metal;
// 与 SceneKit 配合使用时,需要的头文件
#include <SceneKit/scn_metal>


struct VertexInput {
    float3 position [[attribute(SCNVertexSemanticPosition)]];
};

struct ColorInOut {
    float4 position [[position]];
    float4 color;
};

struct MyNodeData {
    float4x4 modelViewProjectionTransform;
};


// 顶点着色器函数,输出为 ColorInOut 类型,输入为 VertexInput 类型的变量 in,和 MyNodeData 类型的变量指针 scn_node
vertex ColorInOut vertexShader(VertexInput in [[stage_in]], constant MyNodeData& scn_node [[buffer(0)]]) {
    ColorInOut out;
    // 将模型空间的顶点补全为 float4 类型,进行 MVP 变换
    out.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0);
    // 加 0.5,将坐标从[-0.5~0.5],转换到[0~1] 以代表颜色
    out.color = float4(in.position + 0.5, 1);
    return out;
}

// 片元着色器函数,输出为 half4,输入为 ColorInOut 类型的变量 in
fragment half4 fragmentShader(ColorInOut in [[stage_in]]) {
    return half4(in.color);
}

六、总结

  • YUV4:4:4 中 Y、U、V 分量的采样比例相同,既可以理解为原始图像像素点原样输出,存储空间没有任何变化。
  • YUV4:2:2 采样格式,是指每采样一个像素点,都会采样 Y 分量,而 U、V 分量则会间隔一个采集一个,本质是通过左右相邻像素点共用 U/V 分量。相比 RGB 颜色编码格式,节省了 1/3 的存储空间,同时节约了在传输时的带宽。
  • YUV4:2:0 采样格式,是实际开发中最常用的颜色编码格式,相比 YUV4:2:2 采样格式,更能节省空间。是指在 2*2 的田字格中有 4 个像素点,其中 4 个 Y 分量共用一套 UV 分量,其本质是通过田字格的上下左右像素点共用 U/V 分量。
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: 在线RGB颜色YUV转换器是一种在线工具,用于转换RGB颜色模式到YUV颜色模式。RGB代表红、绿、蓝,而YUV代表亮度、色度和饱和度。这个转换器的作用是帮助用户将RGB颜色格式转换YUV格式,这在数字图像和视频处理中非常常见。 使用在线RGB颜色YUV转换器,只需输入所需转换RGB颜色值,例如红色值为255,绿色值为0,蓝色值为0。然后点击“转换”按钮,即可得到其相应的YUV颜色值。这个转换器还提供了可视化效果,即用户在输入RGB值后,会在网页的右侧看到相应的颜色块,以便用户看到他们的RGB颜色是什么样的。 在实际应用中,将RGB颜色格式转换YUV格式的目的是为了压缩数字视频流。YUV模式更适合于视频编码,因为例如红色和绿色的像素虽然颜色不同,但在人眼中看起来差别不大,可以合并成一个颜色。同时,YUV模式中的亮度(Y)更重要,还可以通过调整Y的值来控制图像的亮度。因此,将RGBYUV是数字视频和图像处理中的一个重要步骤,这个在线转换器大大简化了这个过程。 ### 回答2: 一款在线RGB颜色YUV转换器是一种非常实用的工具,可以用于将 RGB 颜色转换YUV 颜色空间中的对应值。在许多图像处理和视频处理应用中都需要使用 YUV 颜色空间,所以这样的转换器非常有用。 通过这款在线转换器,您可以将 RGB 颜色值输入到指定的输入框中,然后将它们转换YUV 颜色空间中的对应值。转换后,您可以看到输出的 YUV 值,并且可以将它们用于进一步处理。 转换RGB颜色YUV颜色的过程非常简单。RGB 颜色是由红、绿和蓝三个通道的值组成的,而 YUV 颜色则是由亮度(Y)和色度(U、V)组成的。因此,转换过程就是将 RGB 颜色值分别转换为相应的 Y、U、V 值。具体的数学计算公式可以通过在线转换器中的算法实现。 这样的在线转换器不仅简单易用,而且非常方便。如果您需要在任何地方进行颜色处理或者视频处理,只需要打开浏览器,访问这个网站,就可以快速地将 RGB 颜色转换YUV 颜色空间中的对应值。 ### 回答3: 在线RGB颜色YUV转换器是一种网络工具,用于将RGB颜色格式转换YUV颜色格式RGB颜色格式是一种基于红色(R)、绿色(G)、蓝色(B)的颜色系统,广泛应用于电子设备显示屏幕、视频摄像头等领域;而YUV颜色格式则是一种基于亮度(Y)、色度(U)、色度(V)的颜色系统,主要用于数字视频压缩和传输中。 在线RGB颜色YUV转换器通常支持多种RGBYUV颜色格式之间的转换,例如RGB24、RGB32、YUV444、YUV422、YUV420等格式。使用者可以将需要转换RGB颜色值输入到工具中,该工具将根据用户选定的RGB颜色格式自动进行转换,输出对应的YUV颜色值。这个转换过程是通过对RGB像素中红绿蓝通道进行加权处理,以获取亮度和两个色度信号得到的。 在线RGB颜色YUV转换器适用于多种应用场景,例如构建数字视频系统、进行数字视频编辑、对图像进行编码、解码等。它不仅能够提高工作效率,还可以防止人为转换错误所带来的一系列问题,为用户提供更加准确、可靠的颜色转换服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

╰つ栺尖篴夢ゞ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值