openh264 自适应量化功能源码分析

news2024/12/23 22:08:17

openh264

  • OpenH264是一个开源的H.264/AVC视频编解码器,由Cisco公司发起并贡献了最初的代码基础。它提供了一个用于视频编码和解码的库,支持H.264视频压缩标准,广泛应用于视频会议、流媒体和视频存储等领域。
  • OpenH264是实现H.264编解码功能的一个很好的选择,特别是对于需要免费解决方案的场景。
  • OpenH264的一些关键特性:
  • 开源:OpenH264遵循BSD风格的开源许可证,允许任何人自由使用、修改和分发。

  • 跨平台:支持多种操作系统,包括Windows、Linux、Mac OS X等。

  • 高性能:提供了高效的编码和解码算法,能够处理高分辨率视频。

  • 硬件加速:支持多种硬件加速技术,如Intel Quick Sync Video、NVIDIA CUDA等。

  • 编码配置灵活:允许用户根据需要配置编码参数,如分辨率、帧率、比特率等。

  • 解码能力:除了编码功能外,OpenH264也提供了解码能力,能够解码H.264编码的视频流。

  • API接口:提供了一套API接口,方便开发者集成到自己的应用程序中。

  • 社区支持:作为一个开源项目,OpenH264得到了活跃的社区支持,不断有新的功能和改进被加入。

自适应量化功能源码文件位置

  • openh264/codec/processing/adaptivequantization/AdaptiveQuantization.cpp

自适应量化功能源码文件流程

在这里插入图片描述

  • 说明
    • 可以看到目前 openh264 选择关闭自适应量化算法,需要重构。
    • 实现自适应量化的核心功能就是 Process 函数。

自适应量化功能原理分析

  1. 功能:实现视频编码自适应量化处理,涉及到图像的运动和纹理分析,以及量化参数的动态调整等。
  2. 过程
  • 初始化一些变量,包括图像宽度、高度、宏块(MB)宽度和高度,以及总宏块数等。
  • 声明了一些用于存储运动纹理单元SMotionTextureUnit和SVAACalcResult(Variable Adaptive Analysis)计算结果的指针;其中通过VAACalcSadSsdBgd_c/VAACalcSadBgd_c函数计算
    SVAACalcResult结构体中变量。
  • 初始化了一些用于计算量化步长和量化参数的变量。
  • 获取源图像和参考图像的Y分量的指针以及它们的跨度(stride)。
  • 进入运动分析部分,计算宏块的运动残差方差和纹理方差。
  • 如果SVAACalcResult计算结果中的指针与传入的图像指针相同;
    • 则使用SVAACalcResult结果;
    • 对每个宏块,根据运动和纹理分析结果,计算运动指数iAverageMotionIndex和纹理指数iAverageTextureIndex,并累加到平均值中。
  • 否则,
    • 调用m_pfVar函数进行运动和纹理分析;
    • 对每个宏块,根据运动和纹理分析结果,计算运动指数iAverageMotionIndex和纹理指数iAverageTextureIndex,并累加到平均值中。
  • 计算平均运动指数和纹理指数,并进行一些条件判断和调整。
  • 双层 for 循环处理每个宏块;
    • 根据运动和纹理指数映射到量化参数(QP),计算iMotionTextureIndexToDeltaQp;
    • 根自适应量化模式(AQ_QUALITY_MODE或AQ_BITRATE_MODE),调整量化参数iMotionTextureIndexToDeltaQp。
  • 将计算出的量化参数映射存储到m_sAdaptiveQuantParam结构体中iAverMotionTextureIndexToDeltaQp。
  • 设置返回值为成功(RET_SUCCESS)。
  1. 相关源码
  • Process函数
EResult CAdaptiveQuantization::Process (int32_t iType, SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
  EResult eReturn = RET_INVALIDPARAM;

  int32_t iWidth     = pSrcPixMap->sRect.iRectWidth;
  int32_t iHeight    = pSrcPixMap->sRect.iRectHeight;
  int32_t iMbWidth  = iWidth  >> 4;
  int32_t iMbHeight = iHeight >> 4;
  int32_t iMbTotalNum    = iMbWidth * iMbHeight;

  SMotionTextureUnit* pMotionTexture = NULL;
  SVAACalcResult*     pVaaCalcResults = NULL;
  int32_t   iMotionTextureIndexToDeltaQp = 0;
  int32_t iAverMotionTextureIndexToDeltaQp = 0;  // double to uint32
  int64_t iAverageMotionIndex = 0;      // double to float
  int64_t iAverageTextureIndex = 0;

  int64_t iQStep = 0;
  int64_t iLumaMotionDeltaQp = 0;
  int64_t iLumaTextureDeltaQp = 0;

  uint8_t* pRefFrameY = NULL, *pCurFrameY = NULL;
  int32_t iRefStride = 0, iCurStride = 0;

  uint8_t* pRefFrameTmp = NULL, *pCurFrameTmp = NULL;
  int32_t i = 0, j = 0;

  pRefFrameY = (uint8_t*)pRefPixMap->pPixel[0];
  pCurFrameY = (uint8_t*)pSrcPixMap->pPixel[0];

  iRefStride  = pRefPixMap->iStride[0];
  iCurStride  = pSrcPixMap->iStride[0];

  /// motion //
  //  motion MB residual variance
  iAverageMotionIndex = 0;
  iAverageTextureIndex = 0;
  pMotionTexture = m_sAdaptiveQuantParam.pMotionTextureUnit;
  pVaaCalcResults = m_sAdaptiveQuantParam.pCalcResult;

  if (pVaaCalcResults->pRefY == pRefFrameY && pVaaCalcResults->pCurY == pCurFrameY) {
    int32_t iMbIndex = 0;
    int32_t iSumDiff, iSQDiff, uiSum, iSQSum;
    for (j = 0; j < iMbHeight; j ++) {
      pRefFrameTmp  = pRefFrameY;
      pCurFrameTmp  = pCurFrameY;
      for (i = 0; i < iMbWidth; i++) {
        iSumDiff =  pVaaCalcResults->pSad8x8[iMbIndex][0];
        iSumDiff += pVaaCalcResults->pSad8x8[iMbIndex][1];
        iSumDiff += pVaaCalcResults->pSad8x8[iMbIndex][2];
        iSumDiff += pVaaCalcResults->pSad8x8[iMbIndex][3];

        iSQDiff = pVaaCalcResults->pSsd16x16[iMbIndex];
        uiSum = pVaaCalcResults->pSum16x16[iMbIndex];
        iSQSum = pVaaCalcResults->pSumOfSquare16x16[iMbIndex];

        iSumDiff = iSumDiff >> 8;
        pMotionTexture->uiMotionIndex = (iSQDiff >> 8) - (iSumDiff * iSumDiff);

        uiSum = uiSum >> 8;
        pMotionTexture->uiTextureIndex = (iSQSum >> 8) - (uiSum * uiSum);

        iAverageMotionIndex += pMotionTexture->uiMotionIndex;
        iAverageTextureIndex += pMotionTexture->uiTextureIndex;
        pMotionTexture++;
        ++iMbIndex;
        pRefFrameTmp += MB_WIDTH_LUMA;
        pCurFrameTmp += MB_WIDTH_LUMA;
      }
      pRefFrameY += (iRefStride) << 4;
      pCurFrameY += (iCurStride) << 4;
    }
  } else {
    for (j = 0; j < iMbHeight; j ++) {
      pRefFrameTmp  = pRefFrameY;
      pCurFrameTmp  = pCurFrameY;
      for (i = 0; i < iMbWidth; i++) {
        m_pfVar (pRefFrameTmp, iRefStride, pCurFrameTmp, iCurStride, pMotionTexture);
        iAverageMotionIndex += pMotionTexture->uiMotionIndex;
        iAverageTextureIndex += pMotionTexture->uiTextureIndex;
        pMotionTexture++;
        pRefFrameTmp += MB_WIDTH_LUMA;
        pCurFrameTmp += MB_WIDTH_LUMA;

      }
      pRefFrameY += (iRefStride) << 4;
      pCurFrameY += (iCurStride) << 4;
    }
  }
  iAverageMotionIndex = WELS_DIV_ROUND64 (iAverageMotionIndex * AQ_INT_MULTIPLY, iMbTotalNum);
  iAverageTextureIndex = WELS_DIV_ROUND64 (iAverageTextureIndex * AQ_INT_MULTIPLY, iMbTotalNum);
  if ((iAverageMotionIndex <= AQ_PESN) && (iAverageMotionIndex >= -AQ_PESN)) {
    iAverageMotionIndex = AQ_INT_MULTIPLY;
  }
  if ((iAverageTextureIndex <= AQ_PESN) && (iAverageTextureIndex >= -AQ_PESN)) {
    iAverageTextureIndex = AQ_INT_MULTIPLY;
  }
  //  motion mb residual map to QP
  //  texture mb original map to QP
  iAverMotionTextureIndexToDeltaQp = 0;
  iAverageMotionIndex = WELS_DIV_ROUND64 (AVERAGE_TIME_MOTION * iAverageMotionIndex, AQ_TIME_INT_MULTIPLY);

  if (m_sAdaptiveQuantParam.iAdaptiveQuantMode == AQ_QUALITY_MODE) {
    iAverageTextureIndex = WELS_DIV_ROUND64 (AVERAGE_TIME_TEXTURE_QUALITYMODE * iAverageTextureIndex, AQ_TIME_INT_MULTIPLY);
  } else {
    iAverageTextureIndex = WELS_DIV_ROUND64 (AVERAGE_TIME_TEXTURE_BITRATEMODE * iAverageTextureIndex, AQ_TIME_INT_MULTIPLY);
  }

  int64_t iAQ_EPSN = - ((int64_t)AQ_PESN * AQ_TIME_INT_MULTIPLY * AQ_QSTEP_INT_MULTIPLY / AQ_INT_MULTIPLY);
  pMotionTexture = m_sAdaptiveQuantParam.pMotionTextureUnit;
  for (j = 0; j < iMbHeight; j ++) {
    for (i = 0; i < iMbWidth; i++) {
      int64_t a = WELS_DIV_ROUND64 ((int64_t) (pMotionTexture->uiTextureIndex) * AQ_INT_MULTIPLY * AQ_TIME_INT_MULTIPLY,
                                    iAverageTextureIndex);
      iQStep = WELS_DIV_ROUND64 ((a - AQ_TIME_INT_MULTIPLY) * AQ_QSTEP_INT_MULTIPLY, (a + MODEL_ALPHA));
      iLumaTextureDeltaQp = MODEL_TIME * iQStep;// range +- 6

      iMotionTextureIndexToDeltaQp = ((int32_t) (iLumaTextureDeltaQp / (AQ_TIME_INT_MULTIPLY)));

      a = WELS_DIV_ROUND64 (((int64_t)pMotionTexture->uiMotionIndex) * AQ_INT_MULTIPLY * AQ_TIME_INT_MULTIPLY,
                            iAverageMotionIndex);
      iQStep = WELS_DIV_ROUND64 ((a - AQ_TIME_INT_MULTIPLY) * AQ_QSTEP_INT_MULTIPLY, (a + MODEL_ALPHA));
      iLumaMotionDeltaQp = MODEL_TIME * iQStep;// range +- 6

      if ((m_sAdaptiveQuantParam.iAdaptiveQuantMode == AQ_QUALITY_MODE && iLumaMotionDeltaQp < iAQ_EPSN)
          || (m_sAdaptiveQuantParam.iAdaptiveQuantMode == AQ_BITRATE_MODE)) {
        iMotionTextureIndexToDeltaQp += ((int32_t) (iLumaMotionDeltaQp / (AQ_TIME_INT_MULTIPLY)));
      }

      m_sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp[j * iMbWidth + i] = (int8_t) (iMotionTextureIndexToDeltaQp /
          AQ_QSTEP_INT_MULTIPLY);
      iAverMotionTextureIndexToDeltaQp += iMotionTextureIndexToDeltaQp;
      pMotionTexture++;
    }
  }

  m_sAdaptiveQuantParam.iAverMotionTextureIndexToDeltaQp = iAverMotionTextureIndexToDeltaQp / iMbTotalNum;

  eReturn = RET_SUCCESS;

  return eReturn;
}
  • m_pfVar函数(指向SampleVariance16x16_c函数)
void SampleVariance16x16_c (uint8_t* pRefY, int32_t iRefStride, uint8_t* pSrcY, int32_t iSrcStride,
                            SMotionTextureUnit* pMotionTexture) {
  uint32_t uiCurSquare = 0,  uiSquare = 0;
  uint16_t uiCurSum = 0,  uiSum = 0;

  for (int32_t y = 0; y < MB_WIDTH_LUMA; y++) {
    for (int32_t x = 0; x < MB_WIDTH_LUMA; x++) {
      uint32_t uiDiff = WELS_ABS (pRefY[x] - pSrcY[x]);
      uiSum += uiDiff;
      uiSquare += uiDiff * uiDiff;

      uiCurSum += pSrcY[x];
      uiCurSquare += pSrcY[x] * pSrcY[x];
    }
    pRefY += iRefStride;
    pSrcY += iSrcStride;
  }

  uiSum = uiSum >> 8;
  pMotionTexture->uiMotionIndex = (uiSquare >> 8) - (uiSum * uiSum);

  uiCurSum = uiCurSum >> 8;
  pMotionTexture->uiTextureIndex = (uiCurSquare >> 8) - (uiCurSum * uiCurSum);
}

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

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

相关文章

关于vue2 antd 碰到的问题总结下

1.关于vue2 antd 视图更新问题 1.一种强制更新 Vue2是通过用Object…defineProperty来设置数据的getter和setter实现对数据和以及视图改变的监听的。对于数组和对象这种引用类型来说&#xff0c;getter和setter无法检测到它们内部的变化。用这种 this.$set(this.form, "…

T-Rex2: Towards Generic Object Detection via Text-Visual Prompt Synergy论文解读

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、引言二、文献综述1. Text-prompted Object Detection2. Visual-prompted Object Detection3. Interactive Object Detection 三、模型方法1. Visual-Text P…

在vscode 中使用npm的问题

当我装了 npm和nodejs后 跑项目在 文件中cmd的话可以直接运行但是在 vscode 中运行的时候就会报一下错误 解决方法就是在 vscode 中吧 power shell换成cmd 来运行就行了

JVM相关:Java内存区域

Java 虚拟机&#xff08;JVM)在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。 Java运行时数据区域是指Java虚拟机&#xff08;JVM&#xff09;在执行Java程序时&#xff0c;为了管理内存而划分的几个不同作用域。这些区域各自承担特定的任务&#xff0c…

知攻善防应急

知攻善防应急靶场一 小李在值守的过程中&#xff0c;发现有 CPU 占用飙升&#xff0c;出于胆子小&#xff0c;就立刻将服务器关机&#xff0c;并找你帮他分析&#xff0c;这是他的服务器系统&#xff0c;请你找出以下内容&#xff0c;并作为通关条件&#xff1a; 1.攻击者的 …

今日增长工具精选| 8个SaaS出海必备运营工具

一、SurveyMonkey 是一个灵活、方便、经济实惠的在线调查工具&#xff0c;可以通过自行设计定制化问卷&#xff0c;开展消费者调研&#xff0c;收集第一手数据&#xff0c;获取用户反馈。 客户涵盖财富100强公司以及其他不同规模和类型的组织&#xff0c;如公司、学术研究机构…

第二十六章CSS3续~

3.CSS3渐变属性 CSS3渐变(gradients)可以在两个或多个指定的颜色之间显示平稳的过渡。 以前&#xff0c;我们必须使用图像来实现这些效果。但是&#xff0c;通过使用CSS3渐变(gradients)&#xff0c;可以减少下载的事件和宽带的使用。由于渐变(gradient)是由浏览器生成的&…

首个文字生成手语模型来了!SignLLM通过文字描述来生成手语视频,目前已经支持八国手语!

SignLLM 是目前第一个通过文字描述生成手语视频的多语言手语模型。 该项目引入了首个多语言手语数据集 Prompt2Sign&#xff0c;它使用工具自动采集和处理网络上的手语视频&#xff0c;能够不断更新&#xff0c;且具有轻量化特点。 该模型当前支持 8 种手语类型。包括美国手语…

软件管理、rpm安装、yum安装、源码编译安装

目录 一、Windows安装/卸载 二、软件的卸载&#xff1a; 三、Linux的软件安装和卸载 3.1rpm安装 第一步&#xff1a;挂在光盘 第二步&#xff1a;查看/mnt 第三步&#xff1a;切换到/mnt/Packages 第四步&#xff1a;安装 3.2yum安装&#xff08;使用关盘作为yum源&…

29 - 买下所有产品的客户(高频 SQL 50 题基础版)

29 - 买下所有产品的客户 selectc.customer_id fromCustomer c group byc.customer_id havingcount(c.product_key)(select count(distinct product_key) from Product);

java版知识付费saas租户平台:剖析现代知识付费平台的功能架构与运营逻辑

在数字化学习的时代背景下&#xff0c;知识付费平台已经成为教育行业的一颗璀璨明星&#xff0c;以其用户需求为中心&#xff0c;提供便捷高效的学习途径。这些平台汇聚了众多专业知识&#xff0c;覆盖职业技能、生活兴趣和人文社科等多个领域&#xff0c;满足不同用户的学习需…

TikTok运营必看|7大广告类型及特点

TikTok广告是品牌或创作者付费向特定目标受众展示的推广内容&#xff08;通常是全屏视频&#xff09;。TikTok 上的广告是一种社交媒体营销形式&#xff0c;通常旨在提高广告商的知名度或销售特定产品或服务。 就 TikTok广告投放而言&#xff0c;其组织层级分为三个层级&#x…

【成品设计】基于红外线的目标跟踪无线测温系统设计

《基于红外线的目标跟踪无线测温系统设计》 整体功能&#xff1a; A端&#xff1a;无线跟踪端 主控&#xff1a;采用STM32F103C8T6单片机作为核心控制。360度编码模块数字脉冲输出红外解码编码模块OLED屏幕。 B端&#xff1a;无线待测端 主控&#xff1a;采用STM32F103C8T…

深入了解静态IP:基础知识与原理(固定IP地址解析)

在今天的数字化世界中&#xff0c;互联网连接已成为我们日常生活和工作中不可或缺的一部分。而在网络连接中&#xff0c;IP地址起着至关重要的作用。其中&#xff0c;静态IP地址因其独特的性质而备受关注。本文将深入探讨静态IP的基础知识、与动态IP的区别、工作原理以及为什么…

大模型创新企业集结!百度智能云千帆AI加速器Demo Day启动

新一轮技术革命风暴席卷而来&#xff0c;为创业带来源源不断的创新动力。过去一年&#xff0c;在金融、制造、交通、政务等领域&#xff0c;大模型正从理论到落地应用&#xff0c;逐步改变着行业的运作模式&#xff0c;成为推动行业创新和转型的关键力量。 针对生态伙伴、创业…

腾讯云Edgeone为我的网站保驾护航

文章目录 前言边缘安全加速平台介绍模拟网站被攻击攻击脚本攻击脚本执行 网站快速接入 EdgeOne前提条件&#xff08;注意事项&#xff09;添加站点添加加速域名 EdgeOne 防护效果EdgeOne 体验感受总结 前言 众所周知&#xff0c;网站如果没有安全防护&#xff0c;极易遭受恶意…

inBuilder 低代码平台新特性推荐 - 第二十期

今天来给大家带来的是 inBuilder 低代码平台特性推荐系列第二十期——菜单导航模式个性化示例。 场景介绍 目前平台提供了四种菜单导航模式&#xff0c;包括分组视图、列表视图、横向视图、平铺视图&#xff0c;均为横向导航&#xff0c;这些也是主流的菜单导航模式。 在某些…

UML实现图-组件图

概述 组件图(ComponentDiagram)描述了软件的各种组件和它们之间的依赖关系。组件图中通常包含4种元素:组件、程序、包、任务&#xff0c;各个组件之间还可以相互依赖。 一、组件的表示法 组件是定义了良好接口的物理实现单元&#xff0c;是系统中可替换的物理部件。在一般情…

JAVA-学习-2

一、类 1、类的定义 把相似的对象划分了一个类。 类指的就是一种模板&#xff0c;定义了一种特定类型的所有对象的属性和行为 在一个.java的问题件中&#xff0c;可以有多个class&#xff0c;但是智能有一个class是用public的class。被声明的public的class&#xff0c;必须和文…

AdSet通过审核并入驻全国SDK管理服务平台

SDK、API、H5是三种常见的APP广告接入方式&#xff0c;目前市面上使用最广泛的还是SDK对接&#xff0c;通过使用广告SDK&#xff0c;App开发者可以在App中展示广告商投放的广告&#xff0c;进而根据用户的点击赚取收益。具备一定规模流量、想快速获得收益的APP开发者都会考虑接…