视频基础学习六——视频编码基础三(h264框架配合图文+具体抓包分析 万字)

news2025/1/22 8:35:29

系列文章目录

视频基础学习一——色立体、三原色以及像素
视频基础学习二——图像深度与格式(RGB与YUV)
视频基础学习三——视频帧率、码率与分辨率
视频基础学习四——视频编码基础一(冗余信息)
视频基础学习五——视频编码基础二(编码参数帧、GOP、码率等)
视频基础学习六——视频编码基础三(h264框架配合图文+具体抓包分析 万字)

文章目录

  • 系列文章目录
  • 前言
  • 一、h264架构
    • 1.h264裸流
    • 2.h264架构
      • VCL
      • NALU
  • 二、NALU深入了解
    • 1.NAL Unit header
    • 2.NAL Unit Body
      • 1)SPS、PPS
        • SPS
          • 长宽
          • 压缩级别
          • 序列参数集
        • PPS
          • pic_parameter_set_id
          • seq_parameter_set_id
          • weighted_pred_flag
          • weighted_bipred_idc
        • 扩展(图像与序列参数集)
      • 2)SEI
      • 3)IDR和非IDR
  • 三、FU-A分片
    • 1.分片
    • FU Header
      • 起始帧
      • 结束 帧
    • 2.SODB和RBSP
  • 总结


前言

上一篇文章中有提到视频编码有两个目的:1.压缩视频体积 2.提高对于网络传输的亲和性。而h264作为当下最流行的编码器,也是本人一直在学习的。

本章内容就是结合笔者自己抓包和阅读文章,根据实际包结合深入刨析h264数据流的格式是怎样的,这篇文章会很长。

|版本声明:山河君,未经博主允许,禁止转载


一、h264架构

1.h264裸流

首先,需要知道的是h264裸流是由一个个NALU(Network Abstract Layer Unit)单元组成,就像是这样:
在这里插入图片描述
那么为什么需要NALU?
NALU又是什么东西?
NALU长什么样子?
这个就需要我们对h264的架构有一定的了解,相信接下来的内容能够回答这三个问题。

2.h264架构

我们不止一次提到过,h264编码目的地是为了高效压缩视频和亲和网络。为了完成这两个目标,h264将系统框架分为了两个层面:【视频编码层面(VCL)】、【网络抽象层面(NAL)】,如下图:
在这里插入图片描述

  • 视频编码层(VCL):是对视频编码核心算法过程、子宏块、宏块、片等概念的定义。这层主要是为了尽可能的独立于网络来高效的对视频内容进行编码。编码完成后,输出的数据是 SODB(String Of Data Bits)

  • 网络适配层(NAL),是对图像序列、图像等片级别以上的概念的定义。这层负责将 VCL 产生的比特字符串适配到各种各样的网络和多元环境中。该层将 VCL 层输出的 SODB 数据打包成 RBSP(Raw Byte Sequence Payload)

总的来说,VLC负责表示视频数据内容,NAL负责格式化数据并提供头信息,保证数据适合各种存储和信道上的传输

VCL

其实在上一篇文章有说过,现在重新复习一下:

一帧是由若干个片(Slice)组成,一个片是由若干个宏块组成,而每一个宏块的大小是16x16的数据,一个宏块又可以分为1616,168,816,88,84,48,4*4,等大小不等的子块,具体关系如同下图:
在这里插入图片描述

扩展:

H264宏块是16x16的,H265宏块会根据宏块的变化幅度来进行宏块划分。而H265的编码单位可以选择从最小的8x8到最大的64x64。

H265压缩率相对于H264压缩率理论上要少百分之50。

NALU

一个视频帧可以被分成诺干个Slice,也就会产生对应的NALU。而一个NALU的组成如同下图:
在这里插入图片描述

  • StartCode:通常为0x000001或者0x00000001(一个完整帧产生多个Slice时使用三字节起始码,否则是四字节),表示这是一个NALU单元的开始,直到遇到下一个StartCode结束。
  • NAL Unit header:占用一字节,用来表示NALU类型
  • NAL Unit Body:可能是包含SPS、PPS、SEI、RBSP(Raw Byte Sequence Payload)等等其中一种信息,可以根据header获知。

二、NALU深入了解

上文说过NAL负责格式化数据并提供头信息,现在就来看看NAL层是如何提供头信息和格式化数据的。

1.NAL Unit header

NAL Unit header:NALU头信息,占用一字节,而这一字节的组成为

  • forbidden_bit(1bit) :禁止位,初始为0,占用NAL头的第一个位,当禁止位值为1时表示接收方需要纠错。
  • nal_reference_bit(2bits):表示优先级,取值越⼤,表示当前NAL越重要,需要优先受到保护。
  • nal_unit_type(5bits):表示当前NALU的类型有多少种

在这里引用网上做好的表格来介绍NAL的类型:
在这里插入图片描述
然后我们结合实际的抓包来进行分析其中几种类型

2.NAL Unit Body

上文说过,NAL单元的body会有多种,具体需要header进行判断,可能是SPS、PPS、SEI或者RBSP等,那么我们就以比较重要的几种先来看看

1)SPS、PPS

h264编码需要SPS和PPS中的信息才能进行解码,一般会在最开始进行发送一次,也有的会在每次I帧编出的时候发送,但是如果当编码器发生改变时候例如:视频分辨率改变,一定需要发送SPS和PPS信息。

SPS

那么SPS和PPS中到底有什么信息是解码必须要的呢?下面我们先看看SPS抓包后的信息
在这里插入图片描述
先分析第一个NAL unit ,对照NAL Unit header

6764001facd9405005bb011000000300100000030320f1831960取第一个字节
0x67:01100111
forbidden_bitL: 0 值为0
nal_reference_bit:11 值为3,表示受到最高保护
nal_unit_type:00111 值为7,对照表格可知为SPS(序列参数集)

下面是对整个SPS的解析

NAL unit: 6764001facd9405005bb011000000300100000030320f1831960
    0... .... = Forbidden_zero_bit: 0
    .11. .... = Nal_ref_idc: 3 #受到最高保护
    ...0 0111 = Nal_unit_type: Sequence parameter set (7) #对照nal_unit_type为sps
    Profile_idc: High profile (100)
    0... .... = Constraint_set0_flag: 0
    .0.. .... = Constraint_set1_flag: 0
    ..0. .... = Constraint_set2_flag: 0
    ...0 .... = Constraint_set3_flag: 0
    .... 0... = Constraint_set4_flag: 0
    .... .0.. = Constraint_set5_flag: 0
    .... ..00 = Reserved_zero_2bits: 0
    Level_id: 31 [Level 3.1 14 Mb/s] #码率等级
    1... .... = seq_parameter_set_id: 0 #序列参数集标志
    .010 .... = chroma_format_id: 1
    .... 1... = bit_depth_luma_minus8: 0
    .... .1.. = bit_depth_chroma_minus8: 0
    .... ..0. = qpprime_y_zero_transform_bypass_flag: 0
    .... ...0 = seq_scaling_matrix_present_flag: 0
    1... .... = log2_max_frame_num_minus4: 0
    .1.. .... = pic_order_cnt_type: 0
    ..01 1... = log2_max_pic_order_cnt_lsb_minus4: 2
    .... .001  01.. .... = num_ref_frames: 4
    ..0. .... = gaps_in_frame_num_value_allowed_flag: 0
    ...0 0000  0101 0000 = pic_width_in_mbs_minus1: 79 #宽
    0000 0101  101. .... = pic_height_in_map_units_minus1: 44 #长
    ...1 .... = frame_mbs_only_flag: 1
    .... 1... = direct_8x8_inference_flag: 1
    .... .0.. = frame_cropping_flag: 0
    .... ..1. = vui_parameters_present_flag: 1
    .... ...1 = aspect_ratio_info_present_flag: 1
    0000 0001 = aspect_ratio_idc: 1
    0... .... = overscan_info_present_flag: 0
    .0.. .... = video_signal_type_present_flag: 0
    ..0. .... = chroma_loc_info_present_flag: 0
    ...1 .... = timing_info_present_flag: 1
    .... 0000  0000 0000  0000 0000  0000 0011  0000 .... = num_units_in_tick: 48
    .... 0000  0001 0000  0000 0000  0000 0000  0000 .... = time_scale: 16777216
    .... 0... = fixed_frame_rate_flag: 0
    .... .0.. = nal_hrd_parameters_present_flag: 0
    .... ..1. = vcl_hrd_parameters_present_flag: 1
    .... ...1 = cpb_cnt_minus1: 0
    0000 .... = bit_rate_scale: 0
    .... 0011 = cpb_size_scale: 3
    0010 0... = bit_rate_value_minus1: 3
    .... .000  1111 .... = cpb_size_value_minus1: 14
    .... 0... = cbr_flag: 0
    .... .001  10.. .... = initial_cpb_removal_delay_length_minus1: 6
    ..00 001. = cpb_removal_delay_length_minus1: 1
    .... ...1  0001 .... = dpb_output_delay_length_minus11: 17
    .... 1001  0... .... = time_offset_length: 18
    .1.. .... = low_delay_hrd_flag: 1
    ..1. .... = pic_struct_present_flag: 1
    ...0 .... = bitstream_restriction_flag: 0
    .... 0... = rbsp_stop_bit: 0
    .... .000 = rbsp_trailing_bits: 0
长宽

从上面我们看到,有两个重要的参数—— pic_width_in_mbs_minus1: 79 和pic_height_in_map_units_minus1: 44
通过这两个参数我们就可以算出视频的长宽
width = 16 * (pic_width_in_mbs_minus1 + 1) = 1280
height = 16 * (pic_height_in_map_units_minus1 + 1) = 720
是16的原因是在h264中一个宏块的长宽就是16

压缩级别

Profile_idc: High profile (100)
标识当前H.264码流的profile。H.264中定义了三种常用的档次profile:

  • 基准档次:baseline profile;
  • 主要档次:main profile;
  • 扩展档次:extended profile;
    新版中,还包括igh、High 10、High 4:2:2、High 4:4:4、High 10 Intra、High 4:2:2 Intra、High 4:4:4 Intra、CAVLC 4:4:4 Intra等
序列参数集

seq_parameter_set_id:表示当前的序列参数集的id。通过该id值,图像参数集pps可以引用其代表的sps中的参数。

PPS

接着来看看PPS中的信息

现在看第二个NAL unit ,对照NAL Unit header

68ebe3cb22c0取第一个字节
0x68:01101000
forbidden_bitL: 0 值为0
nal_reference_bit:11 值为3,表示受到最高保护
nal_unit_type:00111 值为8,对照表格可知为PPS(图像参数集)

再来看一下具体内容

NAL unit: 68ebe3cb22c0
    0... .... = Forbidden_zero_bit: 0
    .11. .... = Nal_ref_idc: 3 #受到保护最高
    ...0 1000 = Nal_unit_type: Picture parameter set (8) #对照nal_unit_type为pps
    1... .... = pic_parameter_set_id: 0
    .1.. .... = seq_parameter_set_id: 0
    ..1. .... = entropy_coding_mode_flag: 1
    ...0 .... = pic_order_present_flag: 0
    .... 1... = num_slice_groups_minus1: 0
    .... .011 = num_ref_idx_l0_active_minus1: 2
    1... .... = num_ref_idx_l1_active_minus1: 0
    .1.. .... = weighted_pred_flag: 1 #是否加权预测
    ..10 .... = weighted_bipred_idc: 2 #隐式预测
    .... 0011  1... .... = pic_init_qp_minus26(se(v)): -3
    .1.. .... = pic_init_qs_minus26: 0
    ..00 101. = chroma_qp_index_offset(se(v)): -2
    .... ...1 = deblocking_filter_control_present_flag: 1
    0... .... = constrained_intra_pred_flag: 0
    .0.. .... = redundant_pic_cnt_present_flag: 0
    ..1. .... = transform_8x8_mode_flag: 1
    ...0 .... = pic_scaling_matrix_present_flag: 0
    .... 0010  1... .... = second_chroma_qp_index_offset(se(v)): -2
    .1.. .... = rbsp_stop_bit: 1
    ..00 0000 = rbsp_trailing_bits: 0

pic_parameter_set_id

表示当前PPS的id。某个PPS在码流中会被相应的slice引用,slice引用PPS的方式就是在Slice header中保存PPS的id值。该值的取值范围为[0,255]

seq_parameter_set_id

表示当前PPS所引用的激活的SPS的id。通过这种方式,PPS中也可以取到对应SPS中的参数。该值的取值范围为[0,31]。

weighted_pred_flag

标识位,表示在P/SP slice中是否开启加权预测。

weighted_bipred_idc

表示在B Slice中加权预测的方法,取值范围为[0,2]。0表示默认加权预测,1表示显式加权预测,2表示隐式加权预测。

扩展(图像与序列参数集)

SPS称为序列参数集,PPS称为图像参数集,那么到底什么是参数集?参数集又有什么作用?

前面说过,帧就是对于Slice的编码,在一段视频中,有些编码参数像上述的加权、长宽等等都是不变的,这些就形成了序列参数集,而图像参数集就是对于序列参数集中的参数做了引用,看起来关系如下:
在这里插入图片描述

2)SEI

我们先看一下抓包的情况
在这里插入图片描述
SEI实际上是对于编码参数的一种扩展,从抓包中数据分析

0x06:00000110
forbidden_bitL: 0 值为0
nal_reference_bit:00 值为3,表示不受保护
nal_unit_type:00110 值为6,对照表格可知为SEI

从nal_reference_bit中不难看出,这种类型的包基本不受保护,也就是说,实际上该包丢弃之后,依旧可以正常解码,所以这里不过多赘述。

3)IDR和非IDR

从nal_unit_type表格中可以看出,type为1, 2, 3, 4, 5及12的NAL单元保存的是VCL数据,也被称为VCL的NAL单元。

但是通常来说,一张图片经过编码压缩后依旧占据一定体积,所以就需要分为多个NAL进行发送,也被称为切片(FU-A),而切片后的数据nal_unit_type为28也就是自定义数据。
例如:
在这里插入图片描述
从上图可以看到实际一帧被分为了多个FU-A,并不是一个NAL单元就拥有一张图片
分析一下7C

0x7C:01111100
forbidden_bitL: 0 值为0
nal_reference_bit:11 值为3,表示受到最高保护
nal_unit_type:11100 值为28,对照表格可知为自定义数据

三、FU-A分片

1.分片

当视频帧大小超过一定范围(MTU),则h264中视频帧将会进行分片处理,其实分片处理特别简单,如下图:
在这里插入图片描述

  • StartCode:——FU-A包中还是叫做StartCode
  • NAL Unit header——改名叫做FU indicator,只不过nal_unit_type一定是28
  • NAL Unit Body——被分为FU header和playload两部分

FU Header

总体大小为1字节,其中:

  • 第一位:Start标记位,为1表示分片起始位置
  • 第二位:end标记为,为1表示分片结束位置
  • 第三位:保留
  • 第四~八位:type,和 nal_unit_type表格一样解析

下面我们看一下I帧起始和结束实际包样子

起始帧

在这里插入图片描述

H.264
    FU identifier
        0... .... = F bit: No bit errors or other syntax violations
        .11. .... = Nal_ref_idc (NRI): 3 #受到保护权重最高
        ...1 1100 = Type: Fragmentation unit A (FU-A) (28) #nal_unit_type为28
    FU Header
        1... .... = Start bit: the first packet of FU-A picture #首帧开始
        .0.. .... = End bit: Not the last packet of FU-A picture #结束位为0
        ..0. .... = Forbidden bit: 0
        ...0 0101 = Nal_unit_type: Coded slice of an IDR picture (5) #对照nal_unit_type是IDR帧
    H264 NAL Unit Payload
        1... .... = first_mb_in_slice: 0
        .000 1000 = slice_type: I (I slice) (7)
        1... .... = pic_parameter_set_id: 0
        [Not decoded yet]

结束 帧

在这里插入图片描述

H.264
    FU identifier
        0... .... = F bit: No bit errors or other syntax violations
        .11. .... = Nal_ref_idc (NRI): 3 #受到最高保护
        ...1 1100 = Type: Fragmentation unit A (FU-A) (28)#nal_unit_type 为自定义
    FU Header
        0... .... = Start bit: Not the first packet of FU-A picture #起始标志为0
        .1.. .... = End bit: the last packet of FU-A picture #结束标志
        ..0. .... = Forbidden bit: 0
        ...0 0101 = Nal_unit_type: Coded slice of an IDR picture (5) #nal_unit_type为IDR

2.SODB和RBSP

上面说过,VCL层对于数据进行编码,编码输出的数据是SODB(String Of Data Bits),然后经过映射到NAL为RBSP(Raw Byte Sequence Payload)。

想要了解映射过程可以看一下,不过也可以不用关注:

如果SODB的内容是空的,那么RBSP的内容也是空的。否则,RBSP的第一个字节取自SODB的第1到第8个比特,RBSP字节内部按照从左到右从高到低的顺序排列。以此类推,RBSP中的每个字节都直接取自SODP的相应比特。RBSP的最后一个字节包含SODB的最后几个比特,以及trailing bits。其中,trailing bits的第一个比特为1,其余的比特为0,保证字节对齐。所以RBSP就等于,SODB在它的最后一个字节的最后一个比特后,紧跟值为1的1个比特,然后增加若干比特的0,以补齐这个字节。

从网上找的图片以供参考
在这里插入图片描述


总结

这是一篇很长的文章,也是对于视频流媒体入门的最后一篇文章,我希望能够对于一些刚进去音视频领域的朋友能够进行更好的梳理,能够提供一些帮助。

那么还是那句话

如果对您有所帮助,请帮忙点个赞吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1587307.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WinRAR再爆0 day漏洞,0 day漏洞该如何有效预防

WinRAR再爆0 day漏洞,已被利用超过4个月。 Winrar是一款免费的主流压缩文件解压软件,支持绝大部分压缩文件格式的解压,全球用户量超过5亿。Group-IB研究人员在分析DarkMe恶意软件时发现WinRAR在处理ZIP文件格式时的一个漏洞,漏洞…

基于Springboot的笔记记录分享网站(有报告)。Javaee项目,springboot项目。

演示视频: 基于Springboot的笔记记录分享网站(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构…

牛客 NC36 在两个长度相等的排序数组中找到上中位数【中等 模拟 Java,Go,PHP】

题目 题目链接: https://www.nowcoder.com/practice/6fbe70f3a51d44fa9395cfc49694404f 思路 直接模拟2个数组有顺序放到一个数组中,然后返回中间的数参考答案java import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 pu…

使用htmlentities()和nl2br()将文本数据正确显示到前台

问题&#xff1a; 在后台textarea里编辑了有一串字符串&#xff0c;虽然在textarea里编辑是有换行效果的&#xff0c;但是数据获取到就只是\n&#xff0c;前端是不认识这个的&#xff0c;正确输出到前台的换行只能是<br/>。 $str "ABCDEFGHIJKLMNOPQ"; echo…

Multisim仿真二极管、晶体管和场效应管学习笔记

Multisim仿真二极管、晶体管和场效应管 &#xff08;note&#xff1a;使用Multisim14.0版本进行仿真&#xff09; 文章目录 Multisim仿真二极管、晶体管和场效应管二极管的I-V特性晶体管的I-V特性场效应管的I-V特性 二极管的I-V特性 插入I-V analyzer 原理图绘制 改变仿真…

【MCU开发规范】:MCU的性能测试

MCU的性能测试 前序性能评判方法MIPSCoreMark EEMBC其他参考 前序 我们平时做MCU开发时&#xff0c;前期硬件选型&#xff08;选那颗MCU&#xff09;基本由硬件工程师和架构决定&#xff0c;到软件开发时只是被动的开发一些具体功能&#xff0c;因此很少参与MCU的选型。 大部分…

面试经典算法系列之二叉树1 -- 从前序与中序遍历序列构造二叉树

面试经典算法16 - 从前序与中序遍历序列构造二叉树 LeetCode.105 公众号&#xff1a;阿Q技术站 问题描述 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根…

02 - Git 之命令 +

1 Git相关概念 1.1 以下所谈三个区&#xff0c;文件并不只是简单地在三个区转移&#xff0c;而是以复制副本的方式转移 使用 Git 管理的项目&#xff0c;拥有三个区域&#xff0c;分别是 Working area工作区&#xff08;亦称为 工作树Working Tree&#xff09;、stage area …

学习JavaEE的日子 Day33 File类,IO流

Day33 1.File类 File是文件和目录路径名的抽象表示 File类的对象可以表示文件&#xff1a;C:\Users\Desktop\hhy.txt File类的对象可以表示目录路径名&#xff1a;C:\Users\Desktop File只关注文件本身的信息&#xff08;文件名、是否可读、是否可写…&#xff09;&#xff0c…

简单了解JVM

一.JVM简介 jvm及Java virtual machineJava虚拟机&#xff0c;它是一个虚构出来的计算机&#xff0c;一种规范。其实抛开这么专业的句子不说&#xff0c;就知道 JVM 其实就类似于一台小电脑运行在 windows 或者 linux 这些操作系统环境下即可。它直接和操作系统进行交互&#…

无人新零售引领的创新浪潮

无人新零售引领的创新浪潮 在数字化时代加速演进的背景下&#xff0c;无人新零售作为商业领域的一股新兴力量&#xff0c;正以其独特的高效性和便捷性重塑着传统的购物模式&#xff0c;开辟了一条充满创新潜力的发展道路。 依托人脸识别、物联网等尖端技术&#xff0c;无人新…

中位数和众数-第12届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第49讲。 中位数和众数&…

初识 QT

初始QT 什么是QTQT发展史QT支持的平台QT的优点QT的应用场景搭建QT开发环境QT的开发工具概述QT下载安装 使用QT创建项目QT 实现Hello World程序使用按钮控件来实现使用标签控件来实现 项目文件解析widget.hmain.cppwidget.cppwidget.ui.pro文件 对象树QT 窗口坐标体系 什么是QT …

《战神4》和《战神5》有什么联系吗 苹果电脑如何运行《战神4》苹果电脑玩战神 Mac玩游戏 战神5攻略 crossover激活码

《战神4》&#xff08;God of War 2018&#xff09;和《战神5》&#xff08;God of War: Ragnark&#xff09;是一对引人注目的游戏作品&#xff0c;它们不仅在游戏界引起了广泛的关注&#xff0c;也给玩家带来了深入探索北欧神话世界的机会。这两部游戏之间的联系不仅体现在剧…

hbase基础shell用法

HBase中用create命令创建表&#xff0c;具体如下&#xff1a; create student,Sname,Ssex,Sage,Sdept,course 此时&#xff0c;即创建了一个“student”表&#xff0c;属性有&#xff1a;Sname,Ssex,Sage,Sdept,course。因为HBase的表中会有一个系统默认的属性作为行键&#x…

移远通信:立足5G RedCap新质生产力,全力推动智能电网创新发展

随着全球能源结构的转型和电力需求的持续增长&#xff0c;智能电网产业迎来了新的发展机遇。而物联网、大数据等前沿技术的创新和应用&#xff0c;正在为电力行业的发展注入强劲的新质生产力。 4月9日&#xff0c;第四十八届中国电工仪器仪表产业发展技术研讨及展会在杭州拉开帷…

debian安装和基本使用

debian安装和基本使用 文章目录 debian安装和基本使用1. 为什么选择debian2. 如何下载Debian2.1 小型安装镜像2.2 完整安装镜像 3. Debian操作系统安装3.1 创建Debian虚拟机3.2 安装操作系统 4. Debian系统的初始设置4.1 桌面环境的配置4.2 配置网络4.3 生效网络配置4.4 配置de…

【ubuntu20.04】安装GeographicLib

下载地址 GeographicLib: Installing GeographicLib 我们是ubuntu20.04 &#xff0c;所以下载第一个 GeographicLib-2.3.tar.gz 接着跟着官方步骤安装&#xff0c;会出错&#xff01;&#xff01;&#xff01;&#xff01;马的 官方错误示例&#xff1a;tar xfpz Geographi…

React + three.js 3D模型骨骼绑定

系列文章目录 React 使用 three.js 加载 gltf 3D模型 | three.js 入门React three.js 3D模型骨骼绑定React three.js 3D模型面部表情控制 项目代码(github)&#xff1a;https://github.com/couchette/simple-react-three-skeleton-demo 项目代码(gitcode)&#xff1a;https:…

solidworks electrical 2D和3D有什么区别

SolidWorks Electrical 是一款专为电气设计开发的软件工具&#xff0c;它提供了两种主要的工作环境&#xff1a;2D电气设计和3D电气集成设计。两者在功能和应用场景上存在显著的区别&#xff1a; SolidWorks Electrical 2D 设计 特点与用途&#xff1a; SolidWorks Electrica…