openh264解码h264视频帧主流程
一 解析一帧的入口
int32_t WelsDecodeSlice (PWelsDecoderContext pCtx, bool bFirstSliceInLayer, PNalUnit pNalCur) {
// 解码slice
PDqLayer pCurDqLayer = pCtx->pCurDqLayer;
PFmo pFmo = pCtx->pFmo;
int32_t iRet;
int32_t iNextMbXyIndex, iSliceIdc;
PSlice pSlice = &pCurDqLayer->sLayerInfo.sSliceInLayer;
PSliceHeaderExt pSliceHeaderExt = &pSlice->sSliceHeaderExt;
PSliceHeader pSliceHeader = &pSliceHeaderExt->sSliceHeader;
int32_t iMbX, iMbY;
const int32_t kiCountNumMb = pSliceHeader->pSps->uiTotalMbCount; //need to be correct when fmo or multi slice
uint32_t uiEosFlag = 0;
PWelsDecMbFunc pDecMbFunc;
pSlice->iTotalMbInCurSlice = 0; //initialize at the starting of slice decoding.
if (pCtx->pPps->bEntropyCodingModeFlag) { //cabac 熵编码
if (pSlice->sSliceHeaderExt.bAdaptiveMotionPredFlag ||
pSlice->sSliceHeaderExt.bAdaptiveBaseModeFlag ||
pSlice->sSliceHeaderExt.bAdaptiveResidualPredFlag) {
WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR,
"WelsDecodeSlice()::::ILP flag exist, not supported with CABAC enabled!");
pCtx->iErrorCode |= dsBitstreamError;
return dsBitstreamError;
}
if (P_SLICE == pSliceHeader->eSliceType) //P Slice帧解析
pDecMbFunc = WelsDecodeMbCabacPSlice;
else if (B_SLICE == pSliceHeader->eSliceType) // B slice解析
pDecMbFunc = WelsDecodeMbCabacBSlice;
else //I_SLICE. B_SLICE is being supported
pDecMbFunc = WelsDecodeMbCabacISlice; // I Slice解析
} else { //
if (P_SLICE == pSliceHeader->eSliceType) {
pDecMbFunc = WelsDecodeMbCavlcPSlice;
} else if (B_SLICE == pSliceHeader->eSliceType) {
pDecMbFunc = WelsDecodeMbCavlcBSlice;
} else { //I_SLICE
pDecMbFunc = WelsDecodeMbCavlcISlice;
}
}
二 解析P slice函数
int32_t WelsDecodeMbCabacPSlice (PWelsDecoderContext pCtx, PNalUnit pNalCur, uint32_t& uiEosFlag) {
PDqLayer pCurDqLayer = pCtx->pCurDqLayer; //当前解码上下文
PSlice pSlice = &pCurDqLayer->sLayerInfo.sSliceInLayer; // slice上下文
PSliceHeader pSliceHeader = &pSlice->sSliceHeaderExt.sSliceHeader; // slice header
PPicture* ppRefPic = pCtx->sRefPic.pRefList[LIST_0]; //参考帧上下文
uint32_t uiCode;
int32_t iMbXy = pCurDqLayer->iMbXyIndex;
int32_t i;
SWelsNeighAvail uiNeighAvail;
pCurDqLayer->pCbp[iMbXy] = 0; //code block parttern信息
pCurDqLayer->pCbfDc[iMbXy] = 0;
pCurDqLayer->pChromaPredMode[iMbXy] = C_PRED_DC;
pCurDqLayer->pNoSubMbPartSizeLessThan8x8Flag[iMbXy] = true;
pCurDqLayer->pTransformSize8x8Flag[iMbXy] = false;
GetNeighborAvailMbType (&uiNeighAvail, pCurDqLayer); //填充邻居mb_type 为当前宏块解码做准备
WELS_READ_VERIFY (ParseSkipFlagCabac (pCtx, &uiNeighAvail, uiCode)); //解析是否为skip块
if (uiCode) {
int16_t pMv[2] = {0};
pCurDqLayer->pDec->pMbType[iMbXy] = MB_TYPE_SKIP;
ST32 (&pCurDqLayer->pNzc[iMbXy][0], 0);
ST32 (&pCurDqLayer->pNzc[iMbXy][4], 0);
ST32 (&pCurDqLayer->pNzc[iMbXy][8], 0);
ST32 (&pCurDqLayer->pNzc[iMbXy][12], 0);
ST32 (&pCurDqLayer->pNzc[iMbXy][16], 0);
ST32 (&pCurDqLayer->pNzc[iMbXy][20], 0);
pCurDqLayer->pInterPredictionDoneFlag[iMbXy] = 0;
memset (pCurDqLayer->pDec->pRefIndex[0][iMbXy], 0, sizeof (int8_t) * 16);
bool bIsPending = GetThreadCount (pCtx) > 1;
pCtx->bMbRefConcealed = pCtx->bRPLRError || pCtx->bMbRefConcealed || ! (ppRefPic[0] && (ppRefPic[0]->bIsComplete
|| bIsPending));
//predict mv
PredPSkipMvFromNeighbor (pCurDqLayer, pMv); //通过周围块的信息,计算得到当前块的mvp
for (i = 0; i < 16; i++) {
ST32 (pCurDqLayer->pDec->pMv[0][iMbXy][i], * (uint32_t*)pMv);
ST32 (pCurDqLayer->pMvd[0][iMbXy][i], 0);
}
//if (!pSlice->sSliceHeaderExt.bDefaultResidualPredFlag) {
// memset (pCurDqLayer->pScaledTCoeff[iMbXy], 0, 384 * sizeof (int16_t));
//}
//reset rS
pCurDqLayer->pLumaQp[iMbXy] = pSlice->iLastMbQp; //??????????????? dqaunt of previous mb 前一个qp,当前
//解码得到 delta + 这里的qp就是实际qp
for (i = 0; i < 2; i++) {
pCurDqLayer->pChromaQp[iMbXy][i] = g_kuiChromaQpTable[WELS_CLIP3 (pCurDqLayer->pLumaQp[iMbXy] +
pSliceHeader->pPps->iChromaQpIndexOffset[i], 0, 51)];
//计算得到chromaqp,和lumaqp有对应关系
}
//for neighboring CABAC usage
pSlice->iLastDeltaQp = 0;
WELS_READ_VERIFY (ParseEndOfSliceCabac (pCtx, uiEosFlag));
return ERR_NONE;
}
WELS_READ_VERIFY (WelsDecodeMbCabacPSliceBaseMode0 (pCtx, &uiNeighAvail, uiEosFlag)); //实际解析slice 中MB列表
return ERR_NONE;
三 解析Bslice过程
int32_t WelsDecodeMbCabacBSlice (PWelsDecoderContext pCtx, PNalUnit pNalCur, uint32_t& uiEosFlag) {
//解析B slice
PDqLayer pCurDqLayer = pCtx->pCurDqLayer; //当前帧上下文
PSlice pSlice = &pCurDqLayer->sLayerInfo.sSliceInLayer; //Slice指针
PSliceHeader pSliceHeader = &pSlice->sSliceHeaderExt.sSliceHeader; //当前slice头指着
PPicture* ppRefPicL0 = pCtx->sRefPic.pRefList[LIST_0]; //前向参考列表
PPicture* ppRefPicL1 = pCtx->sRefPic.pRefList[LIST_1]; //后向参考列表
uint32_t uiCode; //
int32_t iMbXy = pCurDqLayer->iMbXyIndex;
int32_t i;
SWelsNeighAvail uiNeighAvail;
pCurDqLayer->pCbp[iMbXy] = 0; //
pCurDqLayer->pCbfDc[iMbXy] = 0;
pCurDqLayer->pChromaPredMode[iMbXy] = C_PRED_DC;
pCurDqLayer->pNoSubMbPartSizeLessThan8x8Flag[iMbXy] = true;
pCurDqLayer->pTransformSize8x8Flag[iMbXy] = false;
GetNeighborAvailMbType (&uiNeighAvail, pCurDqLayer); //填充周围宏块信息
WELS_READ_VERIFY (ParseSkipFlagCabac (pCtx, &uiNeighAvail, uiCode)); //解析 skip标记
memset (pCurDqLayer->pDirect[iMbXy], 0, sizeof (int8_t) * 16);
bool bIsPending = GetThreadCount (pCtx) > 1;
if (uiCode) {
int16_t pMv[LIST_A][2] = { {0, 0}, { 0, 0 } };
int8_t ref[LIST_A] = { 0 };
pCurDqLayer->pDec->pMbType[iMbXy] = MB_TYPE_SKIP | MB_TYPE_DIRECT;
ST32 (&pCurDqLayer->pNzc[iMbXy][0], 0);
ST32 (&pCurDqLayer->pNzc[iMbXy][4], 0);
ST32 (&pCurDqLayer->pNzc[iMbXy][8], 0);
ST32 (&pCurDqLayer->pNzc[iMbXy][12], 0);
ST32 (&pCurDqLayer->pNzc[iMbXy][16], 0);
ST32 (&pCurDqLayer->pNzc[iMbXy][20], 0);
pCurDqLayer->pInterPredictionDoneFlag[iMbXy] = 0;
memset (pCurDqLayer->pDec->pRefIndex[LIST_0][iMbXy], 0, sizeof (int8_t) * 16);
memset (pCurDqLayer->pDec->pRefIndex[LIST_1][iMbXy], 0, sizeof (int8_t) * 16);
pCtx->bMbRefConcealed = pCtx->bRPLRError || pCtx->bMbRefConcealed || ! (ppRefPicL0[0] && (ppRefPicL0[0]->bIsComplete
|| bIsPending)) || ! (ppRefPicL1[0] && (ppRefPicL1[0]->bIsComplete || bIsPending));
if (pCtx->bMbRefConcealed) {
SLogContext* pLogCtx = & (pCtx->sLogCtx);
WelsLog (pLogCtx, WELS_LOG_ERROR, "Ref Picture for B-Slice is lost, B-Slice decoding cannot be continued!");
return GENERATE_ERROR_NO (ERR_LEVEL_SLICE_DATA, ERR_INFO_REFERENCE_PIC_LOST);
}
SubMbType subMbType;
if (pSliceHeader->iDirectSpatialMvPredFlag) { //Direct 块类型判断
//predict direct spatial mv
int32_t ret = PredMvBDirectSpatial (pCtx, pMv, ref, subMbType);
if (ret != ERR_NONE) {
return ret;
}
} else {
//temporal direct mode
int32_t ret = PredBDirectTemporal (pCtx, pMv, ref, subMbType);
if (ret != ERR_NONE) {
return ret;
}
}
//reset rS
pCurDqLayer->pLumaQp[iMbXy] = pSlice->iLastMbQp; //??????????????? dqaunt of previous mb
for (i = 0; i < 2; i++) {
pCurDqLayer->pChromaQp[iMbXy][i] = g_kuiChromaQpTable[WELS_CLIP3 (pCurDqLayer->pLumaQp[iMbXy] +
pSliceHeader->pPps->iChromaQpIndexOffset[i], 0, 51)];
}
//for neighboring CABAC usage
pSlice->iLastDeltaQp = 0;
WELS_READ_VERIFY (ParseEndOfSliceCabac (pCtx, uiEosFlag));
return ERR_NONE;
}
WELS_READ_VERIFY (WelsDecodeMbCabacBSliceBaseMode0 (pCtx, &uiNeighAvail, uiEosFlag)); //实际解析BSlice中的mb
return ERR_NONE;
}
四 解析ISlice过程
int32_t WelsDecodeMbCabacISliceBaseMode0 (PWelsDecoderContext pCtx, uint32_t& uiEosFlag) {
//解析I slice
PDqLayer pCurDqLayer = pCtx->pCurDqLayer; //当前帧解码上下文
PBitStringAux pBsAux = pCurDqLayer->pBitStringAux;
PSlice pSlice = &pCurDqLayer->sLayerInfo.sSliceInLayer; //slice上下文
PSliceHeader pSliceHeader = &pSlice->sSliceHeaderExt.sSliceHeader;
SWelsNeighAvail sNeighAvail;
int32_t iScanIdxStart = pSlice->sSliceHeaderExt.uiScanIdxStart;
int32_t iScanIdxEnd = pSlice->sSliceHeaderExt.uiScanIdxEnd;
int32_t iMbXy = pCurDqLayer->iMbXyIndex;
int32_t i;
uint32_t uiMbType = 0, uiCbp = 0, uiCbpLuma = 0, uiCbpChroma = 0;
ENFORCE_STACK_ALIGN_1D (uint8_t, pNonZeroCount, 48, 16);
pCurDqLayer->pNoSubMbPartSizeLessThan8x8Flag[iMbXy] = true;
pCurDqLayer->pTransformSize8x8Flag[iMbXy] = false;
pCurDqLayer->pInterPredictionDoneFlag[iMbXy] = 0;
pCurDqLayer->pResidualPredFlag[iMbXy] = pSlice->sSliceHeaderExt.bDefaultResidualPredFlag;
GetNeighborAvailMbType (&sNeighAvail, pCurDqLayer);
WELS_READ_VERIFY (ParseMBTypeISliceCabac (pCtx, &sNeighAvail, uiMbType)); //解析mb类型
if (uiMbType > 25) { //非法的mb类型
return GENERATE_ERROR_NO (ERR_LEVEL_MB_DATA, ERR_INFO_INVALID_MB_TYPE);
} else if (!pCtx->pSps->uiChromaFormatIdc && ((uiMbType >= 5 && uiMbType <= 12) || (uiMbType >= 17
&& uiMbType <= 24))) { //如果没有色度信息,这里mb类型不合法的类型判断
return GENERATE_ERROR_NO (ERR_LEVEL_MB_DATA, ERR_INFO_INVALID_MB_TYPE);
} else if (25 == uiMbType) { //I_PCM
WelsLog (& (pCtx->sLogCtx), WELS_LOG_DEBUG, "I_PCM mode exists in I slice!");
WELS_READ_VERIFY (ParseIPCMInfoCabac (pCtx)); //解析PCM 信息,cabac
pSlice->iLastDeltaQp = 0;
WELS_READ_VERIFY (ParseEndOfSliceCabac (pCtx, uiEosFlag));
if (uiEosFlag) {
RestoreCabacDecEngineToBS (pCtx->pCabacDecEngine, pCtx->pCurDqLayer->pBitStringAux);
}
return ERR_NONE;
} else if (0 == uiMbType) { //I4x4 16个4x4的帧内块
ENFORCE_STACK_ALIGN_1D (int8_t, pIntraPredMode, 48, 16);
pCurDqLayer->pDec->pMbType[iMbXy] = MB_TYPE_INTRA4x4;
相关文章:
openh264解码h264视频帧主流程
一 解析一帧的入口int32_t WelsDecodeSlice (PWelsDecoderContext pCtx, bool bFirstSliceInLayer, PNalUnit pNalCur) {// 解码slicePDqLayer pCurDqLayer pCtx->pCurDqLayer;PFmo pFmo pCtx->pFmo;int32_t iRet;int32_t iNextMbXyIndex, iSliceIdc;PSlice pSlice &a…...
【个人笔记】C语言位域
一句话解释位域:指定结构体内变量的的位宽,从而节省空间 例子: #include <stdio.h> struct _test {int bit1:3; // 第一个字节0 ~ 2位 int :0; // 空域:表示第一个字节 3~7都为0int bit2:1; // 第二个字节第0位int :3;…...
ROS笔记(1)——ROS的核心概念
目录 节点与管理器 话题通信 服务通信 参数——全局共享字典 节点与管理器 节点——执行单元 (1)执行具体任务的进程、独立运行的可执行文件 (2)不同节点可使用不同的编程语言,可分布式运行在不同的主机 ÿ…...

动态SQL使用【JavaEE】
动态SQL使用 1. if 标签 判断一个参数是否有值,如果没值,那么就会隐藏 if 中的 sql 语法: <if test"username!null">username#{username} </if>表达式:username 的参数是否为空 如果结果为 true,…...
leetcode刷题
1、stack栈相关 top():返回一个栈顶元素的引用,类型为 T&。如果栈为空,返回值未定义。 push(const T& obj):可以将对象副本压入栈顶。这是通过调用底层容器的 push_back() 函数完成的。 push(T&& obj)࿱…...

移动设备安全管理基础指南
什么是移动安全管理 (MSM) 移动安全管理是指为保护企业中的移动设备和企业数据而采取的行动。这些操作可以进一步被归类为反应性的或主动的,基于该操作是在数据和设备被破坏之前还是之后执行的。除了管理移动设备外,大多数MDM解决…...

【Java|多线程与高并发】 使用Thread 类创建线程的5种方法如何查看程序中的线程
文章目录前言线程创建1.继承Thread类重写run()方法如何查看程序中的线程?2.实现Runnable接口3.使用匿名内部类,继承Thread4.使用匿名内部类,实现Runnable5.⭐使用Lambda表达式,创建线程(重要)Thread 的常见构造方法总结前言 在这里主要补充说明一些问题,方便更好地理解下面的…...

零基础学MySQL(五)-- 详细讲解数据库中的常用函数
目录🎇一、聚合函数1️⃣count 函数(1)基本语法(2)基本练习(3)注意细节2️⃣sum 函数(1)基本语法(2)基本练习(3)注意细节3…...

第4章 流程控制-if-else,Switch,For循环(循环守卫,循环步长,倒叙打印),While循环,多重循环...
第 4 章 流程控制-if-else,Switch,For循环(循环守卫,循环步长,倒叙打印),While循环,多重循环 4.1 分支控制 if-else 让程序有选择的的执行,分支控制有三种:单分支、双分支、多分支 4.1.1 单分支 1)基本语法…...

2.4G-WiFi连接路由器过程
一、概述 WiFi的数据通信基于802.11协议进行,无线AP在工作时会定时向空中发送beacon数据包,基站(STA)从beacon中解析出AP的名称、加密方式等信息,从而发起连接。 二、WiFi连接路由器的详细过程 WiFi连接过程主要可以…...

3. SpringMVC Rest 风格
1. REST 简介 REST(Representational State Transfer),表现形式状态转换,它是一种软件架构风格。 当要表示一个网络资源的时候,可以使用两种方式: 传统风格资源描述形式 http://localhost/user/getById?…...
Python3简介
Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具有比其他语言更有特色语法结构。 Python 是面向对象语言: 这意味着P…...

如何学习PMP?
★基础要打牢 方法:“基础不牢,地动山摇”,如果基础不牢那么就很难拿高分,因为连最基础的题目分都不一定能拿到。 可以在针对基础知识,把PMBOK看一两遍,再次加深印象,再把平时做章节练习、每日5…...

【DSP视频教程】第11期:插补算法,曲线拟合丝滑顺畅,统计函数和基础函数加速实现,汇集SIMD,饱和和MAC乘累加应用实战(2023-02-12)
视频教程汇总帖:https://www.armbbs.cn/forum.php?modviewthread&tid110519 DSP视频教程有段时间没有更新了。 当前DSP库从CMSIS软件包里面独立出来,并且更新非常频繁,所以本期视频教程优先给大家简单介绍下新版DSP, 然后为…...

分类模型评估:混淆矩阵、准确率、召回率、ROC
1. 混淆矩阵 在二分类问题中,混淆矩阵被用来度量模型的准确率。因为在二分类问题中单一样本的预测结果只有Yes or No,即:真或者假两种结果,所以全体样本的经二分类模型处理后,处理结果不外乎四种情况,每种…...

算法 ——世界 一
个人简介:云计算网络运维专业人员,了解运维知识,掌握TCP/IP协议,每天分享网络运维知识与技能。个人爱好: 编程,打篮球,计算机知识个人名言:海不辞水,故能成其大;山不辞石…...

2023年3月AMA-CDGA/CDGP数据治理认证考试这些城市可以报名
目前2023年3月5日CDGA&CDGP开放报名的城市有:北京、上海、广州、深圳、杭州、重庆,西安,成都,长沙,济南,更多考场正在增加中… DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业…...

Java变量和数据类型,超详细整理,适合新手入门
目录 一、什么是变量? 二、变量 变量值互换 三、基本数据类型 1、八种基本数据类型 2、布尔值 3、字符串 四、从控制台输入 一、什么是变量? 变量是一种存储值的容器,它可以在程序的不同部分之间共享;变量可以存储数字、字…...

Echarts 设置折线图拐点的颜色,边框等样式,hover时改变颜色
第014个点击查看专栏目录上一篇文章我们讲到了如何设置拐点大小,图形类型,旋转角度,缩放同比,位置偏移等,这篇文章介绍如何设置拐点的颜色、边框大小颜色等样式。hover轴线时候,拐点的填充颜色改变文章目录示例效果示例…...
做 SQL 性能优化真是让人干瞪眼
很多大数据计算都是用SQL实现的,跑得慢时就要去优化SQL,但常常碰到让人干瞪眼的情况。 比如,存储过程中有三条大概形如这样的语句执行得很慢: select a,b,sum(x) from T group by a,b where …; select c,d,max(y) from T grou…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...

C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...