openh264 Pskip 模式决策原理:WelsMdPSkipEnc 函数

news2024/11/17 16:23:39

WelsMdPSkipEnc函数介绍

  1. 函数功能:它尝试对当前宏块(MB)进行P-skip模式的编码,并返回一个布尔值表示是否成功。
  2. 函数参数
  • 函数接受编码上下文 pEncCtx
  • MD结构体 pWelsMd
  • 当前宏块 pCurMb
  • 宏块缓存 pMbCache
  1. 函数调用关系图
    在这里插入图片描述

WelsMdPSkipEnc 函数原理

  1. 原理过程
  • 获取当前编码层和函数列表;
  • 从缓存中获取参考帧的亮度、色度数据;
  • iLineSizeY 和 iLineSizeUV 分别是亮度和色度分量的行间距,用于计算像素数据的偏移;
  • pDstLuma, pDstCb, pDstCr 分别指向用于存储P-skip宏块数据的目标缓冲区,色度分量偏移量是亮度分量的两倍,因为色度分辨率通常是亮度分辨率的一半;
  • sMvp 用于存储预测的运动向量,初始化为 0;
  • 获取编码器的stride信息,iEncStride 是编码帧的stride,即每行像素的字节数,pEncMb 指向当前宏块的编码数据;
  • pStrideEncBlockOffset 包含了编码块的stride偏移信息,pEncBlockOffset 将用于计算编码块在帧中的具体位置;
  • iSadCostLuma、iSadCostChroma 和 iSadCostMb 分别初始化为0,这些变量将用于存储亮度、色度和整个宏块的SAD成本;
  • 调用 PredSkipMv 函数来预测P-skip宏块的运动向量sMvp;
  • 将运动向量的 iMvX 和 iMvY 成员右移两位,相当于除以4,从而将宏块级别的运动向量转换为四分之一像素级别的运动向量。这通常用于更精细的运动补偿;
  • 计算水平方向上的像素索引,将当前宏块的X坐标 iMbX 左移4位(乘以16),得到当前宏块左上角的像素索引。然后加上运动向量的X分量 sQpelMvp.iMvX,得到实际要引用的像素的X坐标 n ;
  • 检查水平方向是否越界,如果计算出的X坐标 n 小于 -29 或者大于宏块宽度加上12(转换为像素坐标后的范围),则认为运动向量越界,返回 false 表示不能使用这个运动向量;
  • 计算垂直方向上的像素索引,计算当前宏块的Y坐标 iMbY左移4位(乘以16), 加上运动向量的Y分量 sQpelMvp.iMvY,得到实际要引用的像素的Y坐标 n。
  • 检查垂直方向是否越界,如果计算出的Y坐标小于 -29 或者大于宏块高度加上12的范围,则认为运动向量越界,同样返回 false;
  • pRefLuma 指针根据四分之一像素精度的运动向量 sQpelMvp 进行偏移,以便对齐到正确的参考像素;
  • pMcLumaFunc 函数用于执行亮度分量的运动补偿,将参考帧中预测的宏块复制到目标位置 pDstLuma;
  • pfSampleSad[BLOCK_16x16] 函数计算编码宏块和运动补偿后的宏块之间的SAD成本,存储在 iSadCostLuma 变量中;
  • 类似的,pMcChromaFunc函数执行两个色度分量的运动补偿,pfSampleSad[BLOCK_8x8]函数计算两个色度分量的 SAD 代价,累加存储在iSadCostChroma变量中;
  • 宏块的总SAD成本 iSadCostMb 是亮度和色度SAD成本的总和;
  • 如果宏块的总SAD成本为0,或者小于预测的SAD成本 pWelsMd->iSadPredSkip,或者在P-slice中且参考宏块是P-skip类型且SAD成本小于参考宏块的SAD成本,则认为P-skip模式是可行的;
    • pfUpdateMbMv函数更新当前宏块的运动信息;
    • 根据是否使用SAD作为编码成本的度量,更新 pWelsMd 结构体中的相关亮度成本信息iCostLuma;
    • 宏块的总SAD成本 iSadCostMb 更新到pWelsMd 结构体的iCostSkipMb;
    • sMvp更新到pWelsMd 结构体的sP16x16Mv,同时更新到当前层解码图像的MV列表中对应位置‘
    • 返回 true,表示当前宏块是pskip 模式是可行的;
  • WelsDctMb 函数对亮度分量进行DCT变换;
  • WelsTryPYskip 函数尝试对Y分量进行P-skip检查。如果Y分量的DCT系数在阈值内,即宏块在视觉上没有显著变化,可以尝试P-skip;
    • 更新 色度 U 分量编码参数;
    • pfDctFourT4 函数用于对4x4块的色度分量执行DCT变换;
    • WelsTryPUVskip 函数尝试对U分量进行P-skip检查,如果U分量的DCT系数在阈值内,即宏块在视觉上没有显著变化,可以尝试P-skip;
      • 更新 色度 V 分量编码参数;
      • pfDctFourT4 函数用于对4x4块的色度分量执行DCT变换;
      • WelsTryPUVskip 函数尝试对V分量进行P-skip检查,如果V分量的DCT系数在阈值内,即宏块在视觉上没有显著变化,可以尝试P-skip;
        • pfUpdateMbMv函数更新当前宏块的运动信息;
        • 根据是否使用SAD作为编码成本的度量,更新 pWelsMd 结构体中的相关亮度成本信息iCostLuma;
        • 宏块的总SAD成本 iSadCostMb 更新到pWelsMd 结构体的iCostSkipMb;
        • sMvp更新到pWelsMd 结构体的sP16x16Mv,同时更新到当前层解码图像的MV列表中对应位置‘
        • 返回 true,表示当前宏块是pskip 模式是可行的;
  • 返回 false,表明P-skip 模式不可行。
  1. 原理图
    在这里插入图片描述

WelsMdPSkipEnc 函数源码

bool WelsMdPSkipEnc (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SMB* pCurMb, SMbCache* pMbCache) {
  SDqLayer* pCurLayer           = pEncCtx->pCurDqLayer;
  SWelsFuncPtrList* pFunc       = pEncCtx->pFuncList;

  uint8_t* pRefLuma = pMbCache->SPicData.pRefMb[0];
  uint8_t* pRefCb   = pMbCache->SPicData.pRefMb[1];
  uint8_t* pRefCr   = pMbCache->SPicData.pRefMb[2];
  int32_t iLineSizeY  = pCurLayer->pRefPic->iLineSize[0];
  int32_t iLineSizeUV = pCurLayer->pRefPic->iLineSize[1];

  uint8_t* pDstLuma = pMbCache->pSkipMb;
  uint8_t* pDstCb   = pMbCache->pSkipMb + 256;
  uint8_t* pDstCr   = pMbCache->pSkipMb + 256 + 64;

  SMVUnitXY sMvp = { 0 };
  int32_t n;

  int32_t iEncStride = pCurLayer->iEncStride[0];
  uint8_t* pEncMb = pMbCache->SPicData.pEncMb[0];
  int32_t* pStrideEncBlockOffset = pEncCtx->pStrideTab->pStrideEncBlockOffset[pEncCtx->uiDependencyId];
  int32_t* pEncBlockOffset;

  int32_t iSadCostLuma = 0;
  int32_t iSadCostChroma = 0;
  int32_t iSadCostMb = 0;

  PredSkipMv (pMbCache, &sMvp);

  // Special case, need to clip the vector //
  SMVUnitXY sQpelMvp = { static_cast<int16_t> (sMvp.iMvX >> 2), static_cast<int16_t> (sMvp.iMvY >> 2) };
  n = (pCurMb->iMbX << 4) + sQpelMvp.iMvX;
  if (n < -29)
    return false;
  else if (n > (int32_t) ((pCurLayer->iMbWidth << 4) + 12))
    return false;

  n = (pCurMb->iMbY << 4) + sQpelMvp.iMvY;
  if (n < -29)
    return false;
  else if (n > (int32_t) ((pCurLayer->iMbHeight << 4) + 12))
    return false;

  //luma
  pRefLuma += sQpelMvp.iMvY * iLineSizeY + sQpelMvp.iMvX;
  pFunc->sMcFuncs.pMcLumaFunc (pRefLuma, iLineSizeY, pDstLuma, 16, sMvp.iMvX, sMvp.iMvY, 16, 16);
  iSadCostLuma    = pFunc->sSampleDealingFuncs.pfSampleSad[BLOCK_16x16] (pMbCache->SPicData.pEncMb[0],
                    pCurLayer->iEncStride[0], pDstLuma, 16);

  const int32_t iStrideUV = (sQpelMvp.iMvY >> 1) * iLineSizeUV + (sQpelMvp.iMvX >> 1);
  pRefCb += iStrideUV;
  pFunc->sMcFuncs.pMcChromaFunc (pRefCb, iLineSizeUV, pDstCb, 8, sMvp.iMvX, sMvp.iMvY, 8, 8); //Cb
  iSadCostChroma  = pFunc->sSampleDealingFuncs.pfSampleSad[BLOCK_8x8] (pMbCache->SPicData.pEncMb[1],
                    pCurLayer->iEncStride[1], pDstCb, 8);

  pRefCr += iStrideUV;
  pFunc->sMcFuncs.pMcChromaFunc (pRefCr, iLineSizeUV, pDstCr, 8, sMvp.iMvX, sMvp.iMvY, 8, 8); //Cr
  iSadCostChroma += pFunc->sSampleDealingFuncs.pfSampleSad[BLOCK_8x8] (pMbCache->SPicData.pEncMb[2],
                    pCurLayer->iEncStride[2], pDstCr, 8);

  iSadCostMb = iSadCostLuma + iSadCostChroma;

  if (iSadCostMb == 0                             ||
      iSadCostMb < pWelsMd->iSadPredSkip   ||
      (pCurLayer->pRefPic->iPictureType == P_SLICE     &&
       pMbCache->uiRefMbType == MB_TYPE_SKIP    &&
       iSadCostMb < pCurLayer->pRefPic->pMbSkipSad[pCurMb->iMbXY])) {
    //update motion info to current MB
    ST32 (pCurMb->pRefIndex, 0);
    pFunc->pfUpdateMbMv (pCurMb->sMv, sMvp);

    if (pWelsMd->bMdUsingSad) {
      pCurMb->pSadCost[0] = iSadCostLuma;
      pWelsMd->iCostLuma = pCurMb->pSadCost[0];
    } else
      pWelsMd->iCostLuma = pFunc->sSampleDealingFuncs.pfSampleSatd[BLOCK_16x16] (pMbCache->SPicData.pEncMb[0],
                           pCurLayer->iEncStride[0], pDstLuma, 16);

    pWelsMd->iCostSkipMb = iSadCostMb;

    pCurMb->sP16x16Mv = sMvp;
    pCurLayer->pDecPic->sMvList[pCurMb->iMbXY] = sMvp;

    return true;
  }

  WelsDctMb (pMbCache->pCoeffLevel,  pEncMb, iEncStride, pDstLuma, pEncCtx->pFuncList->pfDctFourT4);

  if (WelsTryPYskip (pEncCtx, pCurMb, pMbCache)) {
    iEncStride = pEncCtx->pCurDqLayer->iEncStride[1];
    pEncMb = pMbCache->SPicData.pEncMb[1];
    pEncBlockOffset = pStrideEncBlockOffset + 16;
    pFunc->pfDctFourT4 (pMbCache->pCoeffLevel + 256, & (pEncMb[*pEncBlockOffset]), iEncStride, pMbCache->pSkipMb + 256, 8);
    if (WelsTryPUVskip (pEncCtx, pCurMb, pMbCache, 1)) {
      pEncMb = pMbCache->SPicData.pEncMb[2];
      pEncBlockOffset = pStrideEncBlockOffset + 20;
      pFunc->pfDctFourT4 (pMbCache->pCoeffLevel + 320, & (pEncMb[*pEncBlockOffset]), iEncStride, pMbCache->pSkipMb + 320, 8);
      if (WelsTryPUVskip (pEncCtx, pCurMb, pMbCache, 2)) {
        //update motion info to current MB
        ST32 (pCurMb->pRefIndex, 0);
        pFunc->pfUpdateMbMv (pCurMb->sMv, sMvp);

        if (pWelsMd->bMdUsingSad) {
          pCurMb->pSadCost[0] = iSadCostLuma;
          pWelsMd->iCostLuma = pCurMb->pSadCost[0];
        } else
          pWelsMd->iCostLuma = pFunc->sSampleDealingFuncs.pfSampleSatd[BLOCK_16x16] (pMbCache->SPicData.pEncMb[0],
                               pCurLayer->iEncStride[0], pDstLuma, 16);

        pWelsMd->iCostSkipMb = iSadCostMb;

        pCurMb->sP16x16Mv = sMvp;
        pCurLayer->pDecPic->sMvList[pCurMb->iMbXY] = sMvp;

        return true;
      }
    }
  }
  return false;
}

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

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

相关文章

人生的乐趣,在于对真知的追求

子曰&#xff1a;朝闻道&#xff0c;夕死可矣&#xff01; 孔子说&#xff1a;早上听到关于世界的真理&#xff0c;哪怕晚上就die了都可以。 这句话很有力量而经常被人引用&#xff0c;表达出我们如何看待沉重的肉身和精神世界。 我们的生活目的&#xff1a;道。 —— 要了解…

五种HTTP数据传输方式

在前端开发过程中,后端主要提供 http 接口来传输数据,而这种数据传输方式主要有五种: url paramqueryform-urlencodedform-datajson 下面就让我们一起来了解一下在Nest.js中如何使用这五种HTTP数据传输方式: 一,创建项目 使用nest new 创建一个nest的项目 nest new 项目名称 …

【送模板】5张图,帮你轻松搞懂OKR工作法

OKR是目标与关键结果法的缩写&#xff0c;OKR运用在工作中就是强调对业务进行逻辑思考&#xff0c;找到目标与关键结果之间的因果关系。这种因果关系的是否准确决定我们努力的价值。 OKR是一种高效的目标管理方法。“O”就是object&#xff0c;目标的意思&#xff0c;“kr”就…

项目的打包

一:打包到微信小程序 1)vscode打包 2)在微信小程序开发工具中打开路径,上传. 疑问:为什么pnpm bulid:mp-weixin用于打包,pnpm dev:mp-weixin也可生成对应路径下的文件?? 打包的是没有热重载,且打包体积更小. 二:条件编译 vscode可以打包成能在不同平台上运行的代码.但是有…

08--LVS网站高并发解决方案

前言&#xff1a;LVS&#xff0c;工作稳定&#xff0c;抗负载能力强&#xff0c;属于运维基础&#xff0c;这里将lvs两种模式的部署方式在这里记录一下&#xff0c;并在示例完成后&#xff0c;补充一下基础概念。本章不可避免的涉及到一些网络方面知识&#xff0c;会形象简单的…

被拷打已老实!面试官问我 #{} 和 ${} 的区别是什么?

引言&#xff1a;在使用 MyBatis 进行数据库操作时&#xff0c;#{} 和 ${} 的区别是面试中常见的问题&#xff0c;对理解如何在 MyBatis 中安全有效地处理 SQL 语句至关重要。正确使用这两种占位符不仅影响应用的安全性&#xff0c;还涉及到性能优化。 题目 被拷打已老实&…

富唯智能打造的AGV搬运机器人转运机器人

AGV搬运机器人&转运机器人 AGV搬运机器人&#xff0c;内部搭载ICD系列核心控制器&#xff0c;拥有不同的移载平台&#xff0c;负载最高可达 1000kq;重复精度高达5mm;支持 Wi-Fi漫游&#xff0c;实现更稳健的网络数据交互;无轨化激光 SLAM 导航&#xff0c;配合 3D 避障相机…

2024年仿真建模与多媒体技术国际学术会议(ISMMT 2024)

全称&#xff1a;2024年仿真建模与多媒体技术国际学术会议&#xff08;ISMMT 2024&#xff09; 会议网址:http://www.ismmt.com 会议时间&#xff1a;最终通知见官网&#xff01; 会议地点: 深圳 投稿邮箱&#xff1a;ismmtsub-conf.com投稿标题&#xff1a;ArticleTEL。投稿时…

什么是“基准测试集”呢?

基准测试集有三部分构成&#xff1a;DocumentSet、QuerySet、RelevantJudgement。在比较多个IR系统孰优孰劣的时候&#xff0c;要做的就是&#xff1a;使用统一的DecumentSet建立索引&#xff0c;然后使用统一的QuerySet去进行查询&#xff0c;最后使用统一的judgement进行评判…

web爬虫笔记:js逆向案例九(某多多 anti_content参数)补环境流程

web爬虫笔记:js逆向案例九(某多多 anti_content参数)补环境流程 一、目标网站:aHR0cHM6Ly9tb2JpbGUueWFuZ2tlZHVvLmNvbS8= 二、接口分析 1、快速定位加密位置(通过搜索/cells/hub/v3快速定位到加密js文件) 2、通过分析可知&#

HSP_09章 模块和包

文章目录 P102 模块的常见应用场景分析P103 模块的基本介绍1. 导入模块import2.实例演示 P104 自定义模块1.自定义模块的介绍:2. 注意事项和使用细节2.1 使用 __name__可以避免模块中测试代码的执行2.2 使用__all__可以控制 import *时,哪些功能被导入&#xff0c;注意: import…

禅道身份认证绕过漏洞(QVD-2024-15263)复现

禅道项目管理系统在开源版、企业版、旗舰版的部分版本中都存在此安全漏洞。攻击者可利用该漏洞创建任意账号实现未授权登录。 1.漏洞级别 高危 2.漏洞搜索 fofa: title"禅道"3.影响范围 v16.x < 禅道 < v18.12 &#xff08;开源版&#xff09; v6.x <…

Vue40-vueComponent构造函数

一、组件的本质&#xff1a;VueComponent构造函数 组件的本质是&#xff1a;构造函数 二、每一次调用vue.extend&#xff0c;返回的事一个全新的 VueComponent VueComponent的源码如下&#xff1a; 三、组件中的this 组件中的this是VueComponent实例对象&#xff0c;结构和vm…

通过视频网站传播的RecordBreaker窃密木马分析

1 攻击活动概览 近期&#xff0c;安天CERT监测到通过视频网站进行传播的攻击活动。攻击者窃取订阅者数量超过10万的视频创作者账号&#xff0c;发布与破解版热门软件相关的演示视频&#xff0c;诱导受害者下载RecordBreaker窃密木马。 RecordBreaker窃密木马是Raccoon…

基于DMAIC的SMT TX插件撞伤不良改善

在快速发展的电子制造领域&#xff0c;SMT&#xff08;表面贴装技术&#xff09;已经成为电子产品组装的核心技术之一。然而&#xff0c;SMT TX插件撞伤不良问题一直是制约生产效率与产品质量的瓶颈。本文将基于DMAIC&#xff08;定义、测量、分析、改进、控制&#xff09;方法…

注意力机制简介

为了减少计算复杂度&#xff0c;通过借鉴生物神经网络的一些机制&#xff0c;我们引入了局部连接、权重共享以及汇聚操作来简化神经网络结构。神经网络中可以存储的信息量称为网络容量。一般来讲&#xff0c;利用一组神经元来存储信息的容量和神经元的数量以及网络的复杂度成正…

重生奇迹MU 探秘奇幻世界

"探秘奇幻世界&#xff0c;成就无尽荣耀&#xff01;欢迎来到重生奇迹MU&#xff0c;一个永不落幕的游戏乐园。在这里&#xff0c;你可以尽情挑战各种困难&#xff0c;发掘神秘宝藏&#xff0c;还可与来自世界各地的玩家一起创造无尽的历史。为了帮助你更好地探索游戏世界…

用Vue3和ApexCharts打造交互式3D折线图

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 Vue.js 中使用 ApexCharts 构建交互式折线图 应用场景 ApexCharts 是一个功能强大的 JavaScript 库&#xff0c;用于创建交互式、可定制的图表。在 Vue.js 中&#xff0c;它可以通过 vue3-apexcharts 插件轻松…

IPython大揭秘:神奇技巧让你掌握无敌编程力量!

IPython技巧 基础技巧文件操作技巧输入输出技巧魔术命令技巧调试技巧程序性能优化技巧输入输出重定向技巧魔术命令控制技巧自定义显示格式技巧多线程多进程技巧异常处理技巧数据可视化技巧自定义魔术命令技巧安装扩展包技巧Jupyter Notebook集成技巧文档显示技巧代码块执行技巧…

2024 年 Python 基于 Kimi 智能助手 Moonshot Ai 模型搭建微信机器人(更新中)

注册 Kimi 开放平台 Kimi&#xff1a;https://www.moonshot.cn/ Kimi智能助手是北京月之暗面科技有限公司&#xff08;Moonshot AI&#xff09;于2023年10月9日推出的一款人工智能助手&#xff0c;主要为用户提供高效、便捷的信息服务。它具备多项强大功能&#xff0c;包括多…