int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)
Frame *inFrame;
x265_param* p = (m_reconfigure || m_reconfigureRc) ? m_latestParam : m_param;
if (m_dpb->m_freeList.empty())
{
如果dpb的中没有free状态的Frame,就会去创建。freeList是一个Frame的pool,这样可以节约内存。
inFrame = new Frame;
Frame主要包括编码完成的数据,重建帧的YUV数据和要编码的YUV数据。
inFrame->m_encodeStartTime = x265_mdate();
这一帧的开始时间单位是ms。
if (inFrame->create(p, pic_in->quantOffsets))
{
主要是创建了要存储编码YUV数据的PicYUV,后续再详细分析
/* 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_sps.cuOffsetY)
{
inFrame->m_fencPic->m_cuOffsetY = m_sps.cuOffsetY;
inFrame->m_fencPic->m_buOffsetY = m_sps.buOffsetY;
if (m_param->internalCsp != X265_CSP_I400)
{
inFrame->m_fencPic->m_cuOffsetC = m_sps.cuOffsetC;
inFrame->m_fencPic->m_buOffsetC = m_sps.buOffsetC;
}
}
..........................
}
.......
}
把要编码的YUV数据拷贝到Frame结构体中
inFrame->m_fencPic->copyFromPicture(*pic_in, *m_param, m_sps.conformanceWindow.rightOffset, m_sps.conformanceWindow.bottomOffset);
/* The synchronization of slicetypeDecide is managed here. The findJob() method
* polls the occupancy of the input queue. If the queue is
* full, it will run slicetypeDecide() and output a mini-gop of frames to the
* output queue. If the flush() method has been called (implying no new pictures
* will be received) then the input queue is considered full if it has even one
* picture left. getDecidedPicture() removes pictures from the output queue and
* only blocks as a last resort. It does not start removing pictures until
* m_filled is true, which occurs after *more than* the lookahead depth of
* pictures have been input so slicetypeDecide() should have started prior to
* output pictures being withdrawn. The first slicetypeDecide() will obviously
* still require a blocking wait, but after this slicetypeDecide() will maintain
* its lead over the encoder (because one picture is added to the input queue
* each time one is removed from the output) and decides slice types of pictures
* just ahead of when the encoder needs them */
m_lookahead->addPicture(*inFrame, sliceType);
Manages the wave-front processing of a single encoding frame
class FrameEncoder : public WaveFront, public Thread。wave-font是一种并行处理的方式。
FrameEncoder *curEncoder = m_frameEncoder[m_curEncoder];
m_curEncoder = (m_curEncoder + 1) % m_param->frameNumThreads;
int ret = 0;
/* 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);
/* 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();
创建要编码的数据结构
frameEnc->allocEncodeData(m_reconfigure ? m_latestParam : m_param, m_sps);
Slice* slice = frameEnc->m_encData->m_slice;
slice->m_sps = &m_sps;
slice->m_pps = &m_pps;
slice->m_param = m_param;
/* determine references, setup RPS, etc */
m_dpb->prepareEncode(frameEnc);
码率控制
if (m_param->rc.rateControlMode != X265_RC_CQP)
m_lookahead->getEstimatedPictureCost(frameEnc);
slice->m_maxNumMergeCand = m_param->maxNumMergeCand;
slice->m_endCUAddr = slice->realEndAddress(m_sps.numCUs
/* Allow FrameEncoder::compressFrame() to start in the frame encoder thread */开始压缩帧
if (!curEncoder->startCompressFrame(frameEnc))
本文介绍了X265编码器的`encode`方法,讲解了如何创建和初始化Frame对象,包括分配内存、设置编码起始时间以及拷贝输入YUV数据。还涉及到编码流程中的WaveFront并行处理策略,以及如何进行码率控制和帧的压缩准备工作。
705





