x265探索与研究(七):encode()函数
函数 探索 研究 Encode
2023-09-14 08:57:58 时间
h1 >
五分钟知识科普:什么是 Base64编码 | 算法必看系列三十九 Base64 编码是一种基于 64 个可打印字符来表示二进制数据的方法。目前 Base64 已经成为网络上常见的传输 8 位二进制字节代码的编码方式之一。本文将为大家详细介绍下 Base64 编码的相关知识。
decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode(‘gb2312’),表示将gb2312编码的字符串str1转换成unicode编码。
h1 "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/31073">
h1 "author-img" src="https://ucc.alicdn.com/avatar/img_b52c3e366f5980ae86989f8a252e3c5f.jpg?x-oss-process=image/resize,h_150,m_lfit" />
在x265中,main()函数中调用了encoder_encode()函数,而encoder_encode()函数调用了encode()函数,encode()函数的主要功能是输入一帧图像,得到一帧图像的输出。
encode()函数主要包括大致三个部分:
(1)分析是否由于错误造成的代码终止,如g_checkFailures、m_aborted。
(2)判断是否有输入帧,若有,则判断该输入帧的像素深度、颜色空间是否支持,并判断List是否为空,若为空则创建;除此之外,还有一个比较重要的变量,即ret,此处初始化了ret为0,ret用于判断encode()函数的执行状况,0代表当前没有可供输出的重构帧,则返回encoder_encode()函数进行处理,1代表有输出,从encode()函数的最后一行代码return ret可以证实这一点。
(3)用一个do/while()判断是否有输出,若有则ret为1,并且调用了startCompressFrame()函数,startCompressFrame()函数的主要目的就是触发线程,为进一步的编码做准备。
对应的代码分析如下:
/*=============================================================*/ ====== Analysed by: RuiDong Fang ====== Csdn Blog: http://blog.csdn.net/frd2009041510 ====== Date: 2016.04.14 ====== Funtion: encode()函数,Feed one new input frame into the encoder, get one frame out. /*=============================================================*/ * Feed one new input frame into the encoder, get one frame out. If pic_in is * NULL, a flush condition is implied and pic_in must be NULL for all subsequent * calls for this encoder instance. * pic_in input original YUV picture or NULL * pic_out pointer to reconstructed picture struct * returns 0 if no frames are currently available for output * 1 if frame was output, m_nalList contains access unit * negative on malloc error or abort */ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////1 #if CHECKED_BUILD || _DEBUG if (g_checkFailures) x265_log(m_param, X265_LOG_ERROR, "encoder aborting because of internal error\n"); return -1; #endif if (m_aborted) return -1; if (m_exportedPic) ATOMIC_DEC( m_exportedPic- m_countRefEncoders); m_exportedPic = NULL; m_dpb- recycleUnreferenced(); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////2 //若有输入时 if (pic_in) //判断输入帧的颜色空间是否支持,若不支持,打印错误 if (pic_in- colorSpace != m_param- internalCsp) x265_log(m_param, X265_LOG_ERROR, "Unsupported color space (%d) on input\n", pic_in- colorSpace); return -1; //输入的每一帧的深度必须处于8至16范围内 if (pic_in- bitDepth 8 || pic_in- bitDepth 16) x265_log(m_param, X265_LOG_ERROR, "Input bit depth (%d) must be between 8 and 16\n", pic_in- bitDepth); return -1; Frame *inFrame; if (m_dpb- m_freeList.empty()) //若List为空,则创建 inFrame = new Frame; x265_param* p = m_reconfigured? m_latestParam : m_param; if (inFrame- create(p)) /* the first PicYuv created is asked to generate the CU and block unit offset * arrays which are then shared with all subsequent PicYuv (orig and recon) * allocated by this top level encoder */ if (m_cuOffsetY) inFrame- m_fencPic- m_cuOffsetC = m_cuOffsetC; inFrame- m_fencPic- m_cuOffsetY = m_cuOffsetY; inFrame- m_fencPic- m_buOffsetC = m_buOffsetC; inFrame- m_fencPic- m_buOffsetY = m_buOffsetY; else if (!inFrame- m_fencPic- createOffsets(m_sps)) m_aborted = true; x265_log(m_param, X265_LOG_ERROR, "memory allocation failure, aborting encode\n"); inFrame- destroy(); delete inFrame; return -1; else m_cuOffsetC = inFrame- m_fencPic- m_cuOffsetC; m_cuOffsetY = inFrame- m_fencPic- m_cuOffsetY; m_buOffsetC = inFrame- m_fencPic- m_buOffsetC; m_buOffsetY = inFrame- m_fencPic- m_buOffsetY; else m_aborted = true; x265_log(m_param, X265_LOG_ERROR, "memory allocation failure, aborting encode\n"); inFrame- destroy(); delete inFrame; return -1; else //若List不为空,则popBack inFrame = m_dpb- m_freeList.popBack(); inFrame- m_lowresInit = false; /* Copy input picture into a Frame and PicYuv, send to lookahead */ inFrame- m_fencPic- copyFromPicture(*pic_in, m_sps.conformanceWindow.rightOffset, m_sps.conformanceWindow.bottomOffset); inFrame- m_poc = ++m_pocLast; inFrame- m_userData = pic_in- userData; inFrame- m_pts = pic_in- inFrame- m_forceqp = pic_in- forceqp; inFrame- m_param = m_reconfigured ? m_latestParam : m_param; if (m_pocLast == 0) //若POC=0 m_firstPts = inFrame- m_pts; if (m_bframeDelay m_pocLast == m_bframeDelay) m_bframeDelayTime = inFrame- m_pts - m_firstPts; /* Encoder holds a reference count until stats collection is finished */ ATOMIC_INC( inFrame- m_countRefEncoders); if ((m_param- rc.aqMode || m_param- bEnableWeightedPred || m_param- bEnableWeightedBiPred) (m_param- rc.cuTree m_param- rc.bStatRead)) if (!m_rateControl- cuTreeReadFor2Pass(inFrame)) m_aborted = 1; return -1; /* Use the frame types from the first pass, if available */ int sliceType = (m_param- rc.bStatRead) ? m_rateControl- rateControlSliceType(inFrame- m_poc) : pic_in- sliceType; /* In analysisSave mode, x265_analysis_data is allocated in pic_in and inFrame points to this */ /* Load analysis data before lookahead- addPicture, since sliceType has been decided */ if (m_param- analysisMode == X265_ANALYSIS_LOAD) x265_picture* inputPic = const_cast x265_picture* (pic_in); /* readAnalysisFile reads analysis data for the frame and allocates memory based on slicetype */ readAnalysisFile( inputPic- analysisData, inFrame- m_poc); inFrame- m_analysisData.poc = inFrame- m_poc; inFrame- m_analysisData.sliceType = inputPic- analysisData.sliceType; inFrame- m_analysisData.numCUsInFrame = inputPic- analysisData.numCUsInFrame; inFrame- m_analysisData.numPartitions = inputPic- analysisData.numPartitions; inFrame- m_analysisData.interData = inputPic- analysisData.interData; inFrame- m_analysisData.intraData = inputPic- analysisData.intraData; sliceType = inputPic- analysisData.sliceType; m_lookahead- addPicture(*inFrame, sliceType); m_numDelayedPic++; else //若没有输入 m_lookahead- flush(); FrameEncoder *curEncoder = m_frameEncoder[m_curEncoder]; m_curEncoder = (m_curEncoder + 1) % m_param- frameNumThreads; //当前要编码的帧 /*ret用于判断该整体函数的状况: 若当前没有可供输出的帧则为0(if no frames are currently available for output), 否则为1(1 if frame was output, m_nalList contains access unit negative on malloc error or abort)。*/ int ret = 0; /* Normal operation is to wait for the current frame encoder to complete its current frame * and then to give it a new frame to work on. In zero-latency mode, we must encode this * input picture before returning so the order must be reversed. This do/while() loop allows * us to alternate the order of the calls without ugly code replication */ Frame* outFrame = NULL; Frame* frameEnc = NULL; int pass = 0; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////3 //do/while() loop /* getEncodedPicture() should block until the FrameEncoder has completed * encoding the frame. This is how back-pressure through the API is * accomplished when the encoder is full */ if (!m_bZeroLatency || pass) outFrame = curEncoder- getEncodedPicture(m_nalList); if (outFrame) Slice *slice = outFrame- m_encData- m_slice; x265_frame_stats* frameData = NULL; /* Free up pic_in- analysisData since it has already been used */ if (m_param- analysisMode == X265_ANALYSIS_LOAD) freeAnalysis( outFrame- m_analysisData); if (pic_out) //若有输出 PicYuv *recpic = outFrame- m_reconPic; pic_out- poc = slice- m_poc; pic_out- bitDepth = X265_DEPTH; pic_out- userData = outFrame- m_userData; pic_out- colorSpace = m_param- internalCsp; frameData = (pic_out- frameData); pic_out- pts = outFrame- m_pts; pic_out- dts = outFrame- m_dts; //判断该帧的类型--I/P/B switch (slice- m_sliceType) case I_SLICE: pic_out- sliceType = outFrame- m_lowres.bKeyframe ? X265_TYPE_IDR : X265_TYPE_I; break; case P_SLICE: pic_out- sliceType = X265_TYPE_P; break; case B_SLICE: pic_out- sliceType = X265_TYPE_B; break; pic_out- planes[0] = recpic- m_picOrg[0]; pic_out- stride[0] = (int)(recpic- m_stride * sizeof(pixel)); pic_out- planes[1] = recpic- m_picOrg[1]; pic_out- stride[1] = (int)(recpic- m_strideC * sizeof(pixel)); pic_out- planes[2] = recpic- m_picOrg[2]; pic_out- stride[2] = (int)(recpic- m_strideC * sizeof(pixel)); /* Dump analysis data from pic_out to file in save mode and free */ if (m_param- analysisMode == X265_ANALYSIS_SAVE) pic_out- analysisData.poc = pic_out- pic_out- analysisData.sliceType = pic_out- sliceType; pic_out- analysisData.numCUsInFrame = outFrame- m_analysisData.numCUsInFrame; pic_out- analysisData.numPartitions = outFrame- m_analysisData.numPartitions; pic_out- analysisData.interData = outFrame- m_analysisData.interData; pic_out- analysisData.intraData = outFrame- m_analysisData.intraData; writeAnalysisFile( pic_out- analysisData); freeAnalysis( pic_out- analysisData); if (slice- m_sliceType == P_SLICE) if (slice- m_weightPredTable[0][0][0].bPresentFlag) m_numLumaWPFrames++; if (slice- m_weightPredTable[0][0][1].bPresentFlag || slice- m_weightPredTable[0][0][2].bPresentFlag) m_numChromaWPFrames++; else if (slice- m_sliceType == B_SLICE) bool bLuma = false, bChroma = false; for (int l = 0; l l++) if (slice- m_weightPredTable[l][0][0].bPresentFlag) bLuma = true; if (slice- m_weightPredTable[l][0][1].bPresentFlag || slice- m_weightPredTable[l][0][2].bPresentFlag) bChroma = true; if (bLuma) m_numLumaWPBiFrames++; if (bChroma) m_numChromaWPBiFrames++; if (m_aborted) return -1; finishFrameStats(outFrame, curEncoder, curEncoder- m_accessUnitBits, frameData); /* Write RateControl Frame level stats in multipass encodes */ if (m_param- rc.bStatWrite) if (m_rateControl- writeRateControlFrameStats(outFrame, curEncoder- m_rce)) m_aborted = true; /* Allow this frame to be recycled if no frame encoders are using it for reference */ if (!pic_out) ATOMIC_DEC( outFrame- m_countRefEncoders); m_dpb- recycleUnreferenced(); else m_exportedPic = outFrame; m_numDelayedPic--; ret = 1; //有输出,则ret为1 /* pop a single frame from decided list, then provide to frame encoder * curEncoder is guaranteed to be idle at this point */ if (!pass) frameEnc = m_lookahead- getDecidedPicture(); if (frameEnc !pass) /* give this frame a FrameData instance before encoding */ if (m_dpb- m_picSymFreeList) frameEnc- m_encData = m_dpb- m_picSymFreeList; m_dpb- m_picSymFreeList = m_dpb- m_picSymFreeList- m_freeListNext; frameEnc- reinit(m_sps); else frameEnc- allocEncodeData(m_param, m_sps); Slice* slice = frameEnc- m_encData- m_slice; slice- m_sps = m_sps; slice- m_pps = m_pps; slice- m_maxNumMergeCand = m_param- maxNumMergeCand; slice- m_endCUAddr = slice- realEndAddress(m_sps.numCUsInFrame * NUM_4x4_PARTITIONS); frameEnc- m_reconPic- m_cuOffsetC = m_cuOffsetC; frameEnc- m_reconPic- m_cuOffsetY = m_cuOffsetY; frameEnc- m_reconPic- m_buOffsetC = m_buOffsetC; frameEnc- m_reconPic- m_buOffsetY = m_buOffsetY; curEncoder- m_rce.encodeOrder = m_encodedFrameNum++; if (m_bframeDelay) int64_t *prevReorderedPts = m_prevReorderedPts; frameEnc- m_dts = m_encodedFrameNum m_bframeDelay ? prevReorderedPts[(m_encodedFrameNum - m_bframeDelay) % m_bframeDelay] : frameEnc- m_reorderedPts - m_bframeDelayTime; prevReorderedPts[m_encodedFrameNum % m_bframeDelay] = frameEnc- m_reorderedPts; else frameEnc- m_dts = frameEnc- m_reorderedPts; /* Allocate analysis data before encode in save mode. This is allocated in frameEnc */ if (m_param- analysisMode == X265_ANALYSIS_SAVE) x265_analysis_data* analysis = frameEnc- m_analysisData; analysis- poc = frameEnc- m_poc; analysis- sliceType = frameEnc- m_lowres.sliceType; uint32_t widthInCU = (m_param- sourceWidth + g_maxCUSize - 1) g_maxLog2CUSize; uint32_t heightInCU = (m_param- sourceHeight + g_maxCUSize - 1) g_maxLog2CUSize; uint32_t numCUsInFrame = widthInCU * heightInCU; analysis- numCUsInFrame = numCUsInFrame; analysis- numPartitions = NUM_4x4_PARTITIONS; allocAnalysis(analysis); /* determine references, setup RPS, etc */ m_dpb- prepareEncode(frameEnc); //========================准备编码前的一些工作,如决定参考帧,设置RPS等等 if (m_param- rc.rateControlMode != X265_RC_CQP) m_lookahead- getEstimatedPictureCost(frameEnc); /* Allow FrameEncoder::compressFrame() to start in the frame encoder thread */ if (!curEncoder- startCompressFrame(frameEnc)) //========================编码线程的开始,调用了startCompressFrame()函数,而startCompressFrame()调用了m_enable.trigger()以触发线程 m_aborted = true; else if (m_encodedFrameNum) m_rateControl- setFinalFrameCount(m_encodedFrameNum); while (m_bZeroLatency ++pass return ret;
五分钟知识科普:什么是 Base64编码 | 算法必看系列三十九 Base64 编码是一种基于 64 个可打印字符来表示二进制数据的方法。目前 Base64 已经成为网络上常见的传输 8 位二进制字节代码的编码方式之一。本文将为大家详细介绍下 Base64 编码的相关知识。
decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode(‘gb2312’),表示将gb2312编码的字符串str1转换成unicode编码。
h1 "feed-item-img" target="_blank" href="https://developer.aliyun.com/article/31073">
h1 "author-img" src="https://ucc.alicdn.com/avatar/img_b52c3e366f5980ae86989f8a252e3c5f.jpg?x-oss-process=image/resize,h_150,m_lfit" />
相关文章
- 【API】恶意样本分析手册——API函数篇
- x265探索与研究(十):encodeSlice()函数、encodeCTU()函数、encodeCU()函数与finishCU()函数分析
- x265探索与研究(六):main()函数
- matlab 函数 bwarea
- 探索PowerShell----函数
- python使用threading获取线程函数返回值的实现方法
- 探索PowerShell----函数
- ML之FE:数据随机抽样之利用pandas的sample函数对超大样本的数据集进行随机采样,并另存为csv文件
- ML之FE:pandas库中数据分析利器之groupby分组函数、agg聚合函数、同时使用groupby与agg函数组合案例之详细攻略
- Qt 日志处理方法(qInstallMsgHandler函数)简单实用
- c中gets函数使用可能导致缓冲区溢出