x265代码阅读:encode()函数

本文详细解析了x265编码器中的encode()函数,包括其主要功能、内部流程及关键变量的作用。通过分析可知,该函数负责处理输入帧并输出编码后的帧。

转载于:https://blog.youkuaiyun.com/frd2009041510/article/details/51150318

非常感谢原作者的详细分析,再次表示感谢。

   在x265中,main()函数中调用了encoder_encode()函数,而encoder_encode()函数调用了encode()函数,encode()函数的主要功能是输入一帧图像,得到一帧图像的输出。

 

        encode()函数主要包括大致三个部分:

1)分析是否由于错误造成的代码终止,如g_checkFailuresm_aborted

2)判断是否有输入帧,若有,则判断该输入帧的像素深度、颜色空间是否支持,并判断List是否为空,若为空则创建;除此之外,还有一个比较重要的变量,即ret,此处初始化了ret0ret用于判断encode()函数的执行状况,0代表当前没有可供输出的重构帧,则返回encoder_encode()函数进行处理,1代表有输出,从encode()函数的最后一行代码return ret可以证实这一点。

3)用一个do/while()判断是否有输出,若有则ret1,并且调用了startCompressFrame()函数,startCompressFrame()函数的主要目的就是触发线程,为进一步的编码做准备。

 

        对应的代码分析如下:

[cpp]  view plain  copy
  1. /*=============================================================*/  
  2. /* 
  3.  ====== Analysed by: RuiDong Fang  
  4.  ====== Csdn Blog:   http://blog.youkuaiyun.com/frd2009041510  
  5.  ====== Date:        2016.04.14 
  6.  ====== Funtion:     encode()函数,Feed one new input frame into the encoder, get one frame out. 
  7.  */  
  8. /*=============================================================*/  
  9. /** 
  10.  * Feed one new input frame into the encoder, get one frame out. If pic_in is 
  11.  * NULL, a flush condition is implied and pic_in must be NULL for all subsequent 
  12.  * calls for this encoder instance. 
  13.  * 
  14.  * pic_in  input original YUV picture or NULL 
  15.  * pic_out pointer to reconstructed picture struct 
  16.  * 
  17.  * returns 0 if no frames are currently available for output 
  18.  *         1 if frame was output, m_nalList contains access unit 
  19.  *         negative on malloc error or abort */  
  20. int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)  
  21. {  
  22.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////1  
  23. #if CHECKED_BUILD || _DEBUG  
  24.     if (g_checkFailures)  
  25.     {  
  26.         x265_log(m_param, X265_LOG_ERROR, "encoder aborting because of internal error\n");  
  27.         return -1;  
  28.     }  
  29. #endif  
  30.     if (m_aborted)  
  31.         return -1;  
  32.   
  33.     if (m_exportedPic)  
  34.     {  
  35.         ATOMIC_DEC(&m_exportedPic->m_countRefEncoders);  
  36.         m_exportedPic = NULL;  
  37.         m_dpb->recycleUnreferenced();  
  38.     }  
  39.   
  40.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////2  
  41.     //若有输入时  
  42.     if (pic_in)  
  43.     {  
  44.         //判断输入帧的颜色空间是否支持,若不支持,打印错误  
  45.         if (pic_in->colorSpace != m_param->internalCsp)  
  46.         {  
  47.             x265_log(m_param, X265_LOG_ERROR, "Unsupported color space (%d) on input\n",  
  48.                      pic_in->colorSpace);  
  49.             return -1;  
  50.         }  
  51.   
  52.         //输入的每一帧的深度必须处于8至16范围内  
  53.         if (pic_in->bitDepth < 8 || pic_in->bitDepth > 16)  
  54.         {  
  55.             x265_log(m_param, X265_LOG_ERROR, "Input bit depth (%d) must be between 8 and 16\n",  
  56.                      pic_in->bitDepth);  
  57.             return -1;  
  58.         }  
  59.   
  60.         Frame *inFrame;  
  61.         if (m_dpb->m_freeList.empty())   //若List为空,则创建  
  62.         {  
  63.             inFrame = new Frame;  
  64.             x265_param* p = m_reconfigured? m_latestParam : m_param;  
  65.             if (inFrame->create(p))  
  66.             {  
  67.                 /* the first PicYuv created is asked to generate the CU and block unit offset 
  68.                  * arrays which are then shared with all subsequent PicYuv (orig and recon)  
  69.                  * allocated by this top level encoder */  
  70.                 if (m_cuOffsetY)  
  71.                 {  
  72.                     inFrame->m_fencPic->m_cuOffsetC = m_cuOffsetC;  
  73.                     inFrame->m_fencPic->m_cuOffsetY = m_cuOffsetY;  
  74.                     inFrame->m_fencPic->m_buOffsetC = m_buOffsetC;  
  75.                     inFrame->m_fencPic->m_buOffsetY = m_buOffsetY;  
  76.                 }  
  77.                 else  
  78.                 {  
  79.                     if (!inFrame->m_fencPic->createOffsets(m_sps))  
  80.                     {  
  81.                         m_aborted = true;  
  82.                         x265_log(m_param, X265_LOG_ERROR, "memory allocation failure, aborting encode\n");  
  83.                         inFrame->destroy();  
  84.                         delete inFrame;  
  85.                         return -1;  
  86.                     }  
  87.                     else  
  88.                     {  
  89.                         m_cuOffsetC = inFrame->m_fencPic->m_cuOffsetC;  
  90.                         m_cuOffsetY = inFrame->m_fencPic->m_cuOffsetY;  
  91.                         m_buOffsetC = inFrame->m_fencPic->m_buOffsetC;  
  92.                         m_buOffsetY = inFrame->m_fencPic->m_buOffsetY;  
  93.                     }  
  94.                 }  
  95.             }  
  96.             else  
  97.             {  
  98.                 m_aborted = true;  
  99.                 x265_log(m_param, X265_LOG_ERROR, "memory allocation failure, aborting encode\n");  
  100.                 inFrame->destroy();  
  101.                 delete inFrame;  
  102.                 return -1;  
  103.             }  
  104.         }  
  105.         else    //若List不为空,则popBack  
  106.         {  
  107.             inFrame = m_dpb->m_freeList.popBack();  
  108.             inFrame->m_lowresInit = false;  
  109.         }  
  110.   
  111.         /* Copy input picture into a Frame and PicYuv, send to lookahead */  
  112.         inFrame->m_fencPic->copyFromPicture(*pic_in, m_sps.conformanceWindow.rightOffset, m_sps.conformanceWindow.bottomOffset);  
  113.   
  114.         inFrame->m_poc       = ++m_pocLast;  
  115.         inFrame->m_userData  = pic_in->userData;  
  116.         inFrame->m_pts       = pic_in->pts;  
  117.         inFrame->m_forceqp   = pic_in->forceqp;  
  118.         inFrame->m_param     = m_reconfigured ? m_latestParam : m_param;  
  119.   
  120.         if (m_pocLast == 0) //若POC=0  
  121.             m_firstPts = inFrame->m_pts;  
  122.         if (m_bframeDelay && m_pocLast == m_bframeDelay)  
  123.             m_bframeDelayTime = inFrame->m_pts - m_firstPts;  
  124.   
  125.         /* Encoder holds a reference count until stats collection is finished */  
  126.         ATOMIC_INC(&inFrame->m_countRefEncoders);  
  127.   
  128.         if ((m_param->rc.aqMode || m_param->bEnableWeightedPred || m_param->bEnableWeightedBiPred) &&  
  129.             (m_param->rc.cuTree && m_param->rc.bStatRead))  
  130.         {  
  131.             if (!m_rateControl->cuTreeReadFor2Pass(inFrame))  
  132.             {  
  133.                 m_aborted = 1;  
  134.                 return -1;  
  135.             }  
  136.         }  
  137.   
  138.         /* Use the frame types from the first pass, if available */  
  139.         int sliceType = (m_param->rc.bStatRead) ? m_rateControl->rateControlSliceType(inFrame->m_poc) : pic_in->sliceType;  
  140.   
  141.         /* In analysisSave mode, x265_analysis_data is allocated in pic_in and inFrame points to this */  
  142.         /* Load analysis data before lookahead->addPicture, since sliceType has been decided */  
  143.         if (m_param->analysisMode == X265_ANALYSIS_LOAD)  
  144.         {  
  145.             x265_picture* inputPic = const_cast<x265_picture*>(pic_in);  
  146.             /* readAnalysisFile reads analysis data for the frame and allocates memory based on slicetype */  
  147.             readAnalysisFile(&inputPic->analysisData, inFrame->m_poc);  
  148.             inFrame->m_analysisData.poc = inFrame->m_poc;  
  149.             inFrame->m_analysisData.sliceType = inputPic->analysisData.sliceType;  
  150.             inFrame->m_analysisData.numCUsInFrame = inputPic->analysisData.numCUsInFrame;  
  151.             inFrame->m_analysisData.numPartitions = inputPic->analysisData.numPartitions;  
  152.             inFrame->m_analysisData.interData = inputPic->analysisData.interData;  
  153.             inFrame->m_analysisData.intraData = inputPic->analysisData.intraData;  
  154.             sliceType = inputPic->analysisData.sliceType;  
  155.         }  
  156.   
  157.         m_lookahead->addPicture(*inFrame, sliceType);  
  158.         m_numDelayedPic++;  
  159.     }  
  160.     else //若没有输入  
  161.         m_lookahead->flush();  
  162.   
  163.     FrameEncoder *curEncoder = m_frameEncoder[m_curEncoder];  
  164.     m_curEncoder = (m_curEncoder + 1) % m_param->frameNumThreads;    //当前要编码的帧  
  165.       
  166.     /*ret用于判断该整体函数的状况: 
  167.     若当前没有可供输出的帧则为0(if no frames are currently available for output), 
  168.     否则为1(1 if frame was output, m_nalList contains access unit negative on malloc error or abort)。*/  
  169.     int ret = 0;      
  170.   
  171.     /* Normal operation is to wait for the current frame encoder to complete its current frame 
  172.      * and then to give it a new frame to work on.  In zero-latency mode, we must encode this 
  173.      * input picture before returning so the order must be reversed. This do/while() loop allows 
  174.      * us to alternate the order of the calls without ugly code replication */  
  175.     Frame* outFrame = NULL;  
  176.     Frame* frameEnc = NULL;  
  177.     int pass = 0;  
  178.       
  179.     ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////3  
  180.     //do/while() loop  
  181.     do  
  182.     {  
  183.         /* getEncodedPicture() should block until the FrameEncoder has completed 
  184.          * encoding the frame.  This is how back-pressure through the API is 
  185.          * accomplished when the encoder is full */  
  186.         if (!m_bZeroLatency || pass)  
  187.             outFrame = curEncoder->getEncodedPicture(m_nalList);  
  188.         if (outFrame)  
  189.         {  
  190.             Slice *slice = outFrame->m_encData->m_slice;  
  191.             x265_frame_stats* frameData = NULL;  
  192.   
  193.             /* Free up pic_in->analysisData since it has already been used */  
  194.             if (m_param->analysisMode == X265_ANALYSIS_LOAD)  
  195.                 freeAnalysis(&outFrame->m_analysisData);  
  196.   
  197.             if (pic_out)    //若有输出  
  198.             {  
  199.                 PicYuv *recpic = outFrame->m_reconPic;  
  200.                 pic_out->poc = slice->m_poc;  
  201.                 pic_out->bitDepth = X265_DEPTH;  
  202.                 pic_out->userData = outFrame->m_userData;  
  203.                 pic_out->colorSpace = m_param->internalCsp;  
  204.                 frameData = &(pic_out->frameData);  
  205.   
  206.                 pic_out->pts = outFrame->m_pts;  
  207.                 pic_out->dts = outFrame->m_dts;  
  208.   
  209.                 //判断该帧的类型--I/P/B  
  210.                 switch (slice->m_sliceType)  
  211.                 {  
  212.                 case I_SLICE:  
  213.                     pic_out->sliceType = outFrame->m_lowres.bKeyframe ? X265_TYPE_IDR : X265_TYPE_I;  
  214.                     break;  
  215.                 case P_SLICE:  
  216.                     pic_out->sliceType = X265_TYPE_P;  
  217.                     break;  
  218.                 case B_SLICE:  
  219.                     pic_out->sliceType = X265_TYPE_B;  
  220.                     break;  
  221.                 }  
  222.   
  223.                 pic_out->planes[0] = recpic->m_picOrg[0];  
  224.                 pic_out->stride[0] = (int)(recpic->m_stride * sizeof(pixel));  
  225.                 pic_out->planes[1] = recpic->m_picOrg[1];  
  226.                 pic_out->stride[1] = (int)(recpic->m_strideC * sizeof(pixel));  
  227.                 pic_out->planes[2] = recpic->m_picOrg[2];  
  228.                 pic_out->stride[2] = (int)(recpic->m_strideC * sizeof(pixel));  
  229.   
  230.                 /* Dump analysis data from pic_out to file in save mode and free */  
  231.                 if (m_param->analysisMode == X265_ANALYSIS_SAVE)  
  232.                 {  
  233.                     pic_out->analysisData.poc = pic_out->poc;  
  234.                     pic_out->analysisData.sliceType = pic_out->sliceType;  
  235.                     pic_out->analysisData.numCUsInFrame = outFrame->m_analysisData.numCUsInFrame;  
  236.                     pic_out->analysisData.numPartitions = outFrame->m_analysisData.numPartitions;  
  237.                     pic_out->analysisData.interData = outFrame->m_analysisData.interData;  
  238.                     pic_out->analysisData.intraData = outFrame->m_analysisData.intraData;  
  239.                     writeAnalysisFile(&pic_out->analysisData);  
  240.                     freeAnalysis(&pic_out->analysisData);  
  241.                 }  
  242.             }  
  243.             if (slice->m_sliceType == P_SLICE)  
  244.             {  
  245.                 if (slice->m_weightPredTable[0][0][0].bPresentFlag)  
  246.                     m_numLumaWPFrames++;  
  247.                 if (slice->m_weightPredTable[0][0][1].bPresentFlag ||  
  248.                     slice->m_weightPredTable[0][0][2].bPresentFlag)  
  249.                     m_numChromaWPFrames++;  
  250.             }  
  251.             else if (slice->m_sliceType == B_SLICE)  
  252.             {  
  253.                 bool bLuma = false, bChroma = false;  
  254.                 for (int l = 0; l < 2; l++)  
  255.                 {  
  256.                     if (slice->m_weightPredTable[l][0][0].bPresentFlag)  
  257.                         bLuma = true;  
  258.                     if (slice->m_weightPredTable[l][0][1].bPresentFlag ||  
  259.                         slice->m_weightPredTable[l][0][2].bPresentFlag)  
  260.                         bChroma = true;  
  261.                 }  
  262.   
  263.                 if (bLuma)  
  264.                     m_numLumaWPBiFrames++;  
  265.                 if (bChroma)  
  266.                     m_numChromaWPBiFrames++;  
  267.             }  
  268.   
  269.             if (m_aborted)  
  270.                 return -1;  
  271.   
  272.             finishFrameStats(outFrame, curEncoder, curEncoder->m_accessUnitBits, frameData);  
  273.   
  274.             /* Write RateControl Frame level stats in multipass encodes */  
  275.             if (m_param->rc.bStatWrite)  
  276.                 if (m_rateControl->writeRateControlFrameStats(outFrame, &curEncoder->m_rce))  
  277.                     m_aborted = true;  
  278.   
  279.             /* Allow this frame to be recycled if no frame encoders are using it for reference */  
  280.             if (!pic_out)  
  281.             {  
  282.                 ATOMIC_DEC(&outFrame->m_countRefEncoders);  
  283.                 m_dpb->recycleUnreferenced();  
  284.             }  
  285.             else  
  286.                 m_exportedPic = outFrame;  
  287.   
  288.             m_numDelayedPic--;  
  289.   
  290.             ret = 1;    //有输出,则ret为1  
  291.         }  
  292.   
  293.         /* pop a single frame from decided list, then provide to frame encoder 
  294.          * curEncoder is guaranteed to be idle at this point */  
  295.         if (!pass)  
  296.             frameEnc = m_lookahead->getDecidedPicture();  
  297.           
  298.         if (frameEnc && !pass)  
  299.         {  
  300.             /* give this frame a FrameData instance before encoding */  
  301.             if (m_dpb->m_picSymFreeList)  
  302.             {  
  303.                 frameEnc->m_encData = m_dpb->m_picSymFreeList;  
  304.                 m_dpb->m_picSymFreeList = m_dpb->m_picSymFreeList->m_freeListNext;  
  305.                 frameEnc->reinit(m_sps);  
  306.             }  
  307.             else  
  308.             {  
  309.                 frameEnc->allocEncodeData(m_param, m_sps);  
  310.                 Slice* slice = frameEnc->m_encData->m_slice;  
  311.                 slice->m_sps = &m_sps;  
  312.                 slice->m_pps = &m_pps;  
  313.                 slice->m_maxNumMergeCand = m_param->maxNumMergeCand;  
  314.                 slice->m_endCUAddr = slice->realEndAddress(m_sps.numCUsInFrame * NUM_4x4_PARTITIONS);  
  315.                 frameEnc->m_reconPic->m_cuOffsetC = m_cuOffsetC;  
  316.                 frameEnc->m_reconPic->m_cuOffsetY = m_cuOffsetY;  
  317.                 frameEnc->m_reconPic->m_buOffsetC = m_buOffsetC;  
  318.                 frameEnc->m_reconPic->m_buOffsetY = m_buOffsetY;  
  319.             }  
  320.   
  321.             curEncoder->m_rce.encodeOrder = m_encodedFrameNum++;  
  322.             if (m_bframeDelay)  
  323.             {  
  324.                 int64_t *prevReorderedPts = m_prevReorderedPts;  
  325.                 frameEnc->m_dts = m_encodedFrameNum > m_bframeDelay  
  326.                     ? prevReorderedPts[(m_encodedFrameNum - m_bframeDelay) % m_bframeDelay]  
  327.                     : frameEnc->m_reorderedPts - m_bframeDelayTime;  
  328.                 prevReorderedPts[m_encodedFrameNum % m_bframeDelay] = frameEnc->m_reorderedPts;  
  329.             }  
  330.             else  
  331.                 frameEnc->m_dts = frameEnc->m_reorderedPts;  
  332.   
  333.             /* Allocate analysis data before encode in save mode. This is allocated in frameEnc */  
  334.             if (m_param->analysisMode == X265_ANALYSIS_SAVE)  
  335.             {  
  336.                 x265_analysis_data* analysis = &frameEnc->m_analysisData;  
  337.                 analysis->poc = frameEnc->m_poc;  
  338.                 analysis->sliceType = frameEnc->m_lowres.sliceType;  
  339.                 uint32_t widthInCU       = (m_param->sourceWidth  + g_maxCUSize - 1) >> g_maxLog2CUSize;  
  340.                 uint32_t heightInCU      = (m_param->sourceHeight + g_maxCUSize - 1) >> g_maxLog2CUSize;  
  341.   
  342.                 uint32_t numCUsInFrame   = widthInCU * heightInCU;  
  343.                 analysis->numCUsInFrame  = numCUsInFrame;  
  344.                 analysis->numPartitions  = NUM_4x4_PARTITIONS;  
  345.                 allocAnalysis(analysis);  
  346.             }  
  347.   
  348.             /* determine references, setup RPS, etc */  
  349.             m_dpb->prepareEncode(frameEnc);  //========================准备编码前的一些工作,如决定参考帧,设置RPS等等  
  350.   
  351.             if (m_param->rc.rateControlMode != X265_RC_CQP)  
  352.                 m_lookahead->getEstimatedPictureCost(frameEnc);  
  353.   
  354.             /* Allow FrameEncoder::compressFrame() to start in the frame encoder thread */  
  355.             if (!curEncoder->startCompressFrame(frameEnc))   //========================编码线程的开始,调用了startCompressFrame()函数,而startCompressFrame()调用了m_enable.trigger()以触发线程  
  356.                 m_aborted = true;  
  357.         }  
  358.         else if (m_encodedFrameNum)  
  359.             m_rateControl->setFinalFrameCount(m_encodedFrameNum);   
  360.     }  
  361.     while (m_bZeroLatency && ++pass < 2);  
  362.   
  363.     return ret;  
  364. }  
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值