openh264 宏块级码率控制源码分析

news2025/1/19 19:21:19

openh264 宏块级码率控制函数关系

在这里插入图片描述

宏块级核心函数分析

WelsRcMbInitGom函数

  1. 功能:openh264 码率控制框架中宏块级码率控制函数,根据是否启用GOM QP来决定如何设置宏块的QP值,以控制编码的质量和比特率。
  2. 原理过程
  • 函数参数:
    • pEncCtx: 指向编码上下文的指针,包含编码过程中所需的全局信息。
    • pCurMb: 指向当前宏块的指针,宏块是视频编码的基本单位。
    • pSlice: 指向当前切片的指针,切片是一系列连续宏块的集合。
  • 局部变量:
    • pWelsSvcRc: 指向服务层码率控制结构的指针。
    • pSOverRc: 指向切片覆盖码率控制结构的指针。
    • pCurLayer: 指向当前解码质量层的指针。
    • kuiChromaQpIndexOffset: 色度QP索引偏移量,用于调整色度通道的量化参数。
  • 主要逻辑:
    • 首先,获取当前宏块的比特流位置,并更新到切片覆盖码率控制结构中。
    • 如果全局优化码率控制(GOM QP)被启用:
      • 如果当前宏块是GOM的起始宏块(即其索引能被GOM的数量整除),并且不是切片的起始宏块,则增加复杂度指数。
      • 调用RcCalculateGomQp函数计算GOM的QP值。
      • 调用RcGomTargetBits函数计算GOM的目标比特数。
      • 调用RcCalculateMbQp函数计算当前宏块的QP值。
    • 如果GOM QP未启用:
      • 将当前宏块的亮度QP值设置为全局QP值。
      • 根据亮度QP值和色度QP索引偏移量,计算并设置色度QP值。
  • 关键功能:
    • 函数通过判断是否启用GOM QP来决定如何设置宏块的量化参数(QP),这影响编码后视频的质量和比特率。
    • 使用CLIP3_QP_0_51宏来确保QP值在有效范围内(0到51)。
  1. 源码
void WelsRcMbInitGom (sWelsEncCtx* pEncCtx, SMB* pCurMb, SSlice* pSlice) {
  SWelsSvcRc* pWelsSvcRc        = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
  SRCSlicing* pSOverRc          = &pSlice->sSlicingOverRc;
  SDqLayer* pCurLayer           = pEncCtx->pCurDqLayer;
  const uint8_t kuiChromaQpIndexOffset = pCurLayer->sLayerInfo.pPpsP->uiChromaQpIndexOffset;

  pSOverRc->iBsPosSlice = pEncCtx->pFuncList->pfGetBsPosition (pSlice);
  if (pWelsSvcRc->bEnableGomQp) {
    //calculate gom qp and target bits at the beginning of gom
    if (0 == (pCurMb->iMbXY % pWelsSvcRc->iNumberMbGom)) {
      if (pCurMb->iMbXY != pSOverRc->iStartMbSlice) {
        pSOverRc->iComplexityIndexSlice++;
        RcCalculateGomQp (pEncCtx, pSlice, pCurMb);
      }
      RcGomTargetBits (pEncCtx, pSlice);
    }

    RcCalculateMbQp (pEncCtx, pSlice, pCurMb);
  } else {
    pCurMb->uiLumaQp   = pEncCtx->iGlobalQp;
    pCurMb->uiChromaQp = g_kuiChromaQpTable[CLIP3_QP_0_51 (pCurMb->uiLumaQp + kuiChromaQpIndexOffset)];
  }

}

RcCalculateGomQp函数

  1. 功能:计算宏块组的量化参数 qp 的具体实现
  2. 原理过程
  • 函数参数:
    • pEncCtx: 指向编码上下文的指针,包含编码过程中所需的全局信息。
    • pSlice: 指向当前切片的指针。
    • pCurMb: 指向当前宏块的指针,虽然在这段代码中没有直接使用。
  • 局部变量:
    • pWelsSvcRc: 指向服务层码率控制结构的指针。
    • pSOverRc: 指向切片覆盖码率控制结构的指针。
    • iBitsRatio: 用于计算比特率比例的变量。
  • 主要逻辑:
    • 计算剩余的比特数 iLeftBits,即目标比特数减去已使用的比特数。
    • 计算目标剩余比特数 iTargetLeftBits,考虑了当前GOM的已用比特数。
  • QP调整逻辑:
    • 如果剩余比特数小于或等于0,增加QP以降低质量,减少比特率的使用。
    • 否则,根据比特率比例 iBitsRatio 来调整QP:
      • 如果 iBitsRatio 小于 8409,增加QP 2。
      • 如果 iBitsRatio 在 8409 和 9439 之间,增加QP 1。
      • 如果 iBitsRatio 大于 10600,减少QP 1。
      • 如果 iBitsRatio 大于 11900,减少QP 2。
  • QP值的边界限制:
    • 使用 WELS_CLIP3 宏来确保计算出的QP值在允许的最小值和最大值之间。
  • 重置GOM比特计数器:
    • 将 iGomBitsSlice 重置为0,为下一个GOM的比特计数做准备。
  • 注释:
    • 注释中提到了一个可能的日志记录语句,但在这段代码中被注释掉了。
  • 设计目的:
    • 函数的目的是根据当前的编码比特率情况动态调整量化参数,以控制视频的质量和编码效率。
  • 关键功能:
    • 函数通过计算剩余比特数与目标比特数的比例,动态调整QP值,实现码率控制。
  1. 源码
void RcCalculateGomQp (sWelsEncCtx* pEncCtx, SSlice* pSlice, SMB* pCurMb) {
  SWelsSvcRc* pWelsSvcRc    = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
  SRCSlicing* pSOverRc      = &pSlice->sSlicingOverRc;
  int64_t iBitsRatio        = 1;

  int64_t iLeftBits         = pSOverRc->iTargetBitsSlice - pSOverRc->iFrameBitsSlice;
  int64_t iTargetLeftBits   = iLeftBits + pSOverRc->iGomBitsSlice - pSOverRc->iGomTargetBits;
  if ((iLeftBits <= 0) || (iTargetLeftBits <= 0)) {
    pSOverRc->iCalculatedQpSlice += 2;
  } else {
//globe decision
    iBitsRatio = 10000 * iLeftBits / (iTargetLeftBits + 1);
    if (iBitsRatio < 8409)              //2^(-1.5/6)*10000
      pSOverRc->iCalculatedQpSlice += 2;
    else if (iBitsRatio < 9439)         //2^(-0.5/6)*10000
      pSOverRc->iCalculatedQpSlice += 1;
    else if (iBitsRatio > 10600)        //2^(0.5/6)*10000
      pSOverRc->iCalculatedQpSlice -= 1;
    else if (iBitsRatio > 11900)        //2^(1.5/6)*10000
      pSOverRc->iCalculatedQpSlice -= 2;
  }
  pSOverRc->iCalculatedQpSlice = WELS_CLIP3 (pSOverRc->iCalculatedQpSlice, pWelsSvcRc->iMinFrameQp,
                                 pWelsSvcRc->iMaxFrameQp);
// WelsLog (& (pEncCtx->sLogCtx), WELS_LOG_DEBUG,"iCalculatedQpSlice =%d,iBitsRatio = %d\n",pSOverRc->iCalculatedQpSlice,iBitsRatio);
  pSOverRc->iGomBitsSlice = 0;

}

RcGomTargetBits函数

  1. 功能:在视频编码过程中为一个组(Group of Macroblocks,GOM)分配目标比特数。
  2. 原理过程
  • 函数参数:
    • pEncCtx: 指向编码上下文的指针,包含编码过程中所需的全局信息。
    • pSlice: 指向当前切片的指针。
  • 局部变量:
    • pWelsSvcRc: 指向当前依赖层的码率控制服务结构体的指针。
    • pWelsSvcRc_Base: 指向基础码率控制服务结构体的指针,可能用于比较或计算。
    • pSOverRc: 指向切片覆盖码率控制结构的指针。
    • iAllocateBits: 用于存储分配给当前GOM的比特数。
    • iSumSad: 用于累加GOM的总SAD(Sum of Absolute Differences)值。
    • iLastGomIndex: 表示最后一个GOM的索引。
    • iLeftBits: 表示剩余的比特数。
    • kiComplexityIndex: 表示当前GOM的复杂度指数。
  • 主要逻辑:
    • 计算最后一个GOM的索引 iLastGomIndex。
    • 计算剩余的比特数 iLeftBits。
    • 如果剩余比特数小于或等于0,将GOM的目标比特数设置为0并返回。
    • 如果当前复杂度指数等于最后一个GOM的索引,将所有剩余比特数分配给当前GOM。
    • 否则,计算从当前复杂度指数到最后一个GOM的SAD总和 iSumSad。
    • 根据SAD值按比例分配剩余比特数。
  • 比特分配策略:
    • 如果 iSumSad 为0,等比例分配剩余比特数。
    • 如果 iSumSad 不为0,根据当前GOM的SAD值占总SAD的比例来分配比特数。
  • 辅助函数:
    • RcJudgeBaseUsability: 用于判断基础码率控制服务结构体的可用性,其返回值可能用于计算。
  • 设计目的:
    • 函数的目的是根据宏块的复杂度和剩余的比特资源,动态地为每个GOM分配目标比特数,以优化视频质量和编码效率。
  • 关键功能:
    • 函数通过计算SAD值来评估宏块的复杂度,并据此分配比特数,实现码率控制。
  1. 源码
void RcGomTargetBits (sWelsEncCtx* pEncCtx, SSlice* pSlice) {
  SWelsSvcRc* pWelsSvcRc        = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
  SWelsSvcRc* pWelsSvcRc_Base   = NULL;
  SRCSlicing* pSOverRc          = &pSlice->sSlicingOverRc;

  int32_t iAllocateBits = 0;
  int32_t iSumSad = 0;
  int32_t iLastGomIndex = 0;
  int32_t iLeftBits = 0;
  const int32_t kiComplexityIndex = pSOverRc->iComplexityIndexSlice;
  int32_t i;

  iLastGomIndex  = pSOverRc->iEndMbSlice / pWelsSvcRc->iNumberMbGom;
  iLeftBits = pSOverRc->iTargetBitsSlice - pSOverRc->iFrameBitsSlice;
  if (iLeftBits <= 0) {
    pSOverRc->iGomTargetBits = 0;
    return;
  } else if (kiComplexityIndex >= iLastGomIndex) {
    iAllocateBits = iLeftBits;
  } else {
    pWelsSvcRc_Base = RcJudgeBaseUsability (pEncCtx);
    pWelsSvcRc_Base = (pWelsSvcRc_Base) ? pWelsSvcRc_Base : pWelsSvcRc;
    for (i = kiComplexityIndex + 1; i <= iLastGomIndex; i++) {
      iSumSad += pWelsSvcRc_Base->pCurrentFrameGomSad[i];
    }

    if (0 == iSumSad)
      iAllocateBits = WELS_DIV_ROUND (iLeftBits, (iLastGomIndex - kiComplexityIndex));
    else
      iAllocateBits = WELS_DIV_ROUND ((int64_t)iLeftBits * pWelsSvcRc_Base->pCurrentFrameGomSad[kiComplexityIndex + 1],
                                      iSumSad);
  }
  pSOverRc->iGomTargetBits = iAllocateBits;
}

RcCalculateMbQp函数

  1. 功能:作用是在视频编码过程中为当前宏块(Macroblock, MB)计算量化参数(Quantization Parameter, QP)
  2. 原理过程
  • 函数参数:
    • pEncCtx: 指向编码上下文的指针,包含编码过程中所需的全局信息。
    • pSlice: 指向当前切片的指针。
    • pCurMb: 指向当前宏块的指针。
  • 局部变量:
    • pWelsSvcRc: 指向服务层码率控制结构的指针。
    • pSOverRc: 指向切片覆盖码率控制结构的指针。
    • iLumaQp: 存储计算得到的亮度QP值。
    • pCurLayer: 指向当前解码质量层的指针。
    • kuiChromaQpIndexOffset: 色度QP索引偏移量。
  • 主要逻辑:
    • 从切片覆盖码率控制结构中获取iCalculatedQpSlice计算得到的亮度QP值 iLumaQp。
    • 如果启用了自适应量化(bEnableAdaptiveQuant),则根据宏块的运动和纹理信息调整QP值。
  • 自适应量化:
    • 如果启用自适应量化,使用 pMotionTextureIndexToDeltaQp 数组,根据宏块的位置 MbXY 来获取QP调整值,并将其加到基础QP值iLumaQp上。
    • 调整后的QP值通过 WELS_CLIP3 宏确保在允许的范围内。
  • 色度QP计算:
    • 使用色度QP表 g_kuiChromaQpTable 和色度QP索引偏移量 kuiChromaQpIndexOffset 来计算色度QP值。
    • 色度QP值通过 CLIP3_QP_0_51 宏确保在0到51的范围内。
  • 宏块QP赋值:
    • 将计算得到的亮度QP和色度QP值赋给当前宏块 pCurMb。
  1. 源码
void RcCalculateMbQp (sWelsEncCtx* pEncCtx, SSlice* pSlice, SMB* pCurMb) {
  SWelsSvcRc* pWelsSvcRc        = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
  SRCSlicing* pSOverRc          = &pSlice->sSlicingOverRc;

  int32_t iLumaQp               = pSOverRc->iCalculatedQpSlice;
  SDqLayer* pCurLayer           = pEncCtx->pCurDqLayer;
  const uint8_t kuiChromaQpIndexOffset = pCurLayer->sLayerInfo.pPpsP->uiChromaQpIndexOffset;
  if (pEncCtx->pSvcParam->bEnableAdaptiveQuant) {
    iLumaQp   = (int8_t)WELS_CLIP3 (iLumaQp +
                                    pEncCtx->pVaa->sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp[pCurMb->iMbXY], pWelsSvcRc->iMinFrameQp,
                                    pWelsSvcRc->iMaxFrameQp);
  }
  pCurMb->uiChromaQp    = g_kuiChromaQpTable[CLIP3_QP_0_51 (iLumaQp + kuiChromaQpIndexOffset)];
  pCurMb->uiLumaQp      = iLumaQp;
}

WelsRcMbInfoUpdateGom函数

  1. 功能:通过收集和更新宏块的编码信息来帮助编码器动态调整编码参数,以优化视频质量和编码效率。
  2. 原理过程
  • 函数参数:
    • pEncCtx: 指向编码上下文的指针,包含编码过程中所需的全局信息。
    • pCurMb: 指向当前宏块的指针。
    • iCostLuma: 当前宏块的亮度成本,用于码率控制。
    • pSlice: 指向当前切片的指针。
  • 局部变量:
    • pWelsSvcRc: 指向服务层码率控制结构的指针。
    • pSOverRc: 指向切片覆盖码率控制结构的指针。
    • kiComplexityIndex: 复杂度指数,用于码率控制策略。
  • 主要逻辑:
    • 计算当前宏块的比特数iCurMbBits,即从切片开始到当前宏块的比特流位置差。
    • 更新切片的总比特数iFrameBitsSlice和GOM(Group of Macroblocks)的总比特数iGomBitsSlice。
  • 码率控制相关操作:
    • 累加当前宏块的亮度成本iCostLuma到对应复杂度指数的成本数组pGomCost中。
    • 如果当前宏块的比特数大于0,更新切片的总QP(量化参数)和宏块计数器。
  • 设计目的:
    • 该函数的目的是在编码过程中收集和更新宏块的相关信息,以便进行有效的码率控制。
  • 关键功能:
    • 函数通过更新宏块的比特数和亮度成本,为后续的码率控制决策提供数据支持。
  1. 源码
void WelsRcMbInfoUpdateGom (sWelsEncCtx* pEncCtx, SMB* pCurMb, int32_t iCostLuma, SSlice* pSlice) {
  SWelsSvcRc* pWelsSvcRc            = &pEncCtx->pWelsSvcRc[pEncCtx->uiDependencyId];
  SRCSlicing* pSOverRc              = &pSlice->sSlicingOverRc;
  const int32_t kiComplexityIndex   = pSOverRc->iComplexityIndexSlice;

  int32_t iCurMbBits = pEncCtx->pFuncList->pfGetBsPosition (pSlice) - pSOverRc->iBsPosSlice;
  pSOverRc->iFrameBitsSlice += iCurMbBits;
  pSOverRc->iGomBitsSlice += iCurMbBits;

  pWelsSvcRc->pGomCost[kiComplexityIndex] += iCostLuma;
  if (iCurMbBits > 0) {
    pSOverRc->iTotalQpSlice += pCurMb->uiLumaQp;
    pSOverRc->iTotalMbSlice++;
  }
}

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

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

相关文章

高效管理:好用的项目管理工具推荐

在当今快速变化的商业环境中&#xff0c;高效的项目管理工具能够显著提升团队的生产力和项目的成功率&#xff0c;还能有效地跟踪项目进度。所以&#xff0c;一款优秀的项目管理工具首先要具备先进的项目管理理念&#xff0c;支持多种研发管理和项目管理方法论&#xff0c;才能…

“打造智能售货机系统,基于ruoyi微服务版本生成基础代码“

目录 # 开篇 1. 菜单 2. 字典配置 3. 表配置 3.1 导入表 3.2 区域管理 3.3 合作商管理 3.4 点位管理 4. 代码导入 4.1 后端代码生成 4.2 前端代码生成 5. 数据库代码执行 6. 点位管理菜单顺序修改 7. 页面展示 8. 附加设备表 8.1 新增设备管理菜单 8.2 创建字…

高效处理大数据:Kafka的13个核心概念详解

我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货! 大家好,我是你们的小米!今天我们来深入探讨一下Kafka这个强大而复杂的数据流平台。Kafka被广泛应用于高吞吐量、低延迟的数据流应用场景中。那么,我…

wordpress站群搭建3api代码生成和swagger使用

海鸥技术下午茶-wordpress站群搭建3api代码生成和swagger使用 目标:实现api编写和swagger使用 0.本次需要使用到的脚手架命令 生成 http server 代码 goctl api go -api all.api -dir ..生成swagger文档 goctl api plugin -plugin goctl-swagger"swagger -filename st…

【算法训练记录——Day32】

Day32——贪心算法Ⅱ 1.leetcode122买卖股票的最佳时机II2.leetcode55跳跃游戏3.leetcode45跳跃游戏II4.eetcode1005K次取反后最大化的数组和 目标&#xff1a; leetcode122买卖股票的最佳时机IIleetcode55跳跃游戏leetcode45跳跃游戏IIleetcode1005K次取反后最大化的数组和 1…

数据结构经典面试之链表——C#和C++篇

文章目录 一、链表的基本概念二、链表的操作三、定义链表的节点结构体&#xff08;C#&#xff09;四、定义链表的基本操作类&#xff08;C#&#xff09;五、创建一个链表实例并进行基本操作演示&#xff08;C#&#xff09;六、编写一个自定义链表操作函数&#xff08;C&#xf…

搭建一个简单的xxljob

数据库表结构&#xff1a; YyJobInfo&#xff1a; public class YyJobInfo {//定时任务idprivate int id;//该定时任务所属的执行器的idprivate int jobGroup;//定时任务描述private String jobDesc;//定时任务添加的时间private Date addTime;//定时任务的更新时间private D…

centos7将jar包制作服务并设置开机服务

为了避免服务器因为一些原因重启导致java服务没启动&#xff0c;我们将jar包制作为service并开机启动 制作过程 在网上找了一些关于java jar包制作开启启动的&#xff0c;大致流程为先做一个xxx.service&#xff0c;放在/etc/systemd/system/目录下&#xff0c;然后执行syste…

ASP.NET Core 6.0 启动方式

启动方式 Visualstudio 2022启动 IIS Express IIS Express 是一个专为开发人员优化的轻型独立版本的 IIS。 借助 IIS Express,可以轻松地使用最新版本的 IIS 开发和测试网站。 控制台版面 直接在浏览器输入监听的地址,监听的是 http://localhost:5137 脚本启动 dotnet run…

交易中的特殊存在

在交易的广袤天空中&#xff0c;有一群特殊的存在——他们&#xff0c;是Eagle Trader。 他们以鹰眼般的洞察力&#xff0c;捕捉市场的微妙变化&#xff0c;每一次决策都如同猎食者般精准&#xff1b;他们运用策略&#xff0c;如同雄鹰在风中翱翔&#xff0c;利用风向&#xf…

Setapp AI 怎么样,值得订阅吗?

Setapp 是一款提供 240 多款 Mac 软件库&#xff0c;可以满足 Mac 和 iOS 用户的各种需求。只需支付一笔订阅费&#xff0c;就可以使用一系列应用程序&#xff0c;这些应用程序可以简化任务、提高创造力和组织工作流程。不过&#xff0c;Setapp 并不只注重应用程序的数量&#…

R语言——类与对象

已知2024年4月23日是星期五&#xff0c;编写一个函数day.in.a.week (x, y,z)&#xff0c;参数x和y和z分别代表年月日&#xff0c;判断这一天是否存在&#xff08;例如&#xff0c;2018年没有2月29日&#xff0c;也没有11月31日&#xff09;&#xff0c;如果不存在&#xff0c;返…

2024097期传足14场胜负前瞻

2024097期售止时间为6月22日&#xff08;周六&#xff09;20点30分&#xff0c;敬请留意&#xff1a; 本期14场由欧洲杯、美洲杯、美职联组成&#xff0c;1.5以下赔率2场&#xff0c;1.5-2.0赔率10场&#xff0c;其他场次是平半盘、平盘。本期14场难度中等。以下为基础盘前瞻&a…

针对河南大学数据结构傻逼学堂在线的自动化脚本

首先展示一下我们的答案 {1: [对象], 2: [关系]} {1: [非数值计算], 2: [操作]} {1: [线性表]} [D] [B] [B] [C] [C] {1: [操作]} {1: [数据关系, 数据对象上关系的集合]} {1: [性质相同]} {1: [物理结构]} {1: [存储结构, 操作表示]} [C] [B] [D] [B] [D] [true] [false] [fa…

css文字镂空加描边

css文字镂空加描边 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>文字镂空</title><style>/* 公用样式 */html,body{width: 100%;height: 100%;position: relative;}/* html{overflow-y: scroll;} */*{margi…

(Python)可变类型不可变类型;引用传递值传递;浅拷贝深拷贝

从一段代码开始说事&#xff0c;先上代码&#xff1a; a [[1],[2],[3]] b [[4,5],[6,7],[7,8]] for i,j in zip(a,b):print(i,j)i [9]#i[0] 8j[:2][1,2]print(i, j) print(a) print(b) 运行的结果&#xff1a; [1] [4, 5] [9] [1, 2] [2] [6, 7] [9] [1, 2] [3] [7, 8] …

淘宝扭蛋机小程序:互联网时代下行业的发展动力

近几年&#xff0c;扭蛋机在潮玩市场风靡&#xff0c;与各类IP合作&#xff0c;推出各种新颖有趣的扭蛋商品&#xff0c;吸引了众多的IP粉丝&#xff0c;他们会通过扭蛋机进行抽奖&#xff0c;获得喜欢的商品。 目前&#xff0c;移动应用程序不断升级优化&#xff0c;“互联网…

RGB彩色模型理解与编程实例

一、引言 RGB彩色模型中的R、G和B为三原色&#xff0c;通常R、G和B分别用8位表示&#xff0c;因此24位的RGB 真彩色图像能表示16777216种颜色。在如右图所示RGB彩色立方体可知&#xff0c;任意两种原色混合可以合成一种新的颜色。红&#xff08;1&#xff0c;0&#xff0c;0&a…

番外篇 | YOLOv8算法解析和实战应用:车辆检测 + 车辆追踪 + 行驶速度计算

前言:Hello大家好,我是小哥谈。YOLOv8是ultralytics公司在2023年1月10号开源的,是YOLOv5的下一个重大更新版本,目前支持图像分类、物体检测和实例分割任务,在还没有开源时就收到了用户的广泛关注。它是一个SOTA模型,建立在以前YOLO版本的成功基础上,并引入了新的功能和改…

mock-前端数据模拟

简介 数据模拟不是开发流程中的必要一环 Json-server 简介&#xff1a; json-server 是一个简单的 Node.js 服务端应用程序&#xff0c;这个工具的主要作用是提供一个模拟的后端服务&#xff0c;可以在前端开发过程中独立于后端进行简单工作。 使用&#xff1a; 1、 安装…