注:问号以及未注释部分 会在x265-1.8版本内更新
/*****************************************************************************
* Copyright (C) 2013 x265 project
*
* Authors: Shin Yee
* Min Chen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*
* This program is also available under a commercial proprietary license.
* For more information, contact us at license @ x265.com.
*****************************************************************************/
#ifndef X265_FRAMEENCODER_H
#define X265_FRAMEENCODER_H
#include "common.h"
#include "wavefront.h"
#include "bitstream.h"
#include "frame.h"
#include "picyuv.h"
#include "md5.h"
#include "analysis.h"
#include "sao.h"
#include "entropy.h"
#include "framefilter.h"
#include "ratecontrol.h"
#include "reference.h"
#include "nal.h"
namespace x265 {
// private x265 namespace
class ThreadPool;
class Encoder;
#define ANGULAR_MODE_ID 2
#define AMP_ID 3
#define INTER_MODES 4
#define INTRA_MODES 3
struct StatisticLog
{
uint64_t cntInter[4];
uint64_t cntIntra[4];
uint64_t cuInterDistribution[4][INTER_MODES];
uint64_t cuIntraDistribution[4][INTRA_MODES];
uint64_t cntIntraNxN;
uint64_t cntSkipCu[4];
uint64_t cntTotalCu[4];
uint64_t totalCu;
StatisticLog()
{
memset(this, 0, sizeof(StatisticLog));
}
};
/* manages the state of encoding one row of CTU blocks. When
* WPP is active, several rows will be simultaneously encoded. */
struct CTURow
{
Entropy bufferedEntropy; /* store CTU2 context for next row CTU0 */
Entropy rowGoOnCoder; /* store context between CTUs, code bitstream if !SAO */
FrameStats rowStats;
/* Threading variables */
/* This lock must be acquired when reading or writing m_active or m_busy */
Lock lock;
/* row is ready to run, has no neighbor dependencies. The row may have
* external dependencies (reference frame pixels) that prevent it from being
* processed, so it may stay with m_active=true for some time before it is
* encoded by a worker thread. */
volatile bool active;
/* row is being processed by a worker thread. This flag is only true when a
* worker thread is within the context of FrameEncoder::processRow(). This
* flag is used to detect multiple possible wavefront problems. */
volatile bool busy;
/* count of completed CUs in this row */
volatile uint32_t completed;
/* called at the start of each frame to initialize state */
void init(Entropy& initContext)
{
active = false;
busy = false;
completed = 0;
memset(&rowStats, 0, sizeof(rowStats));
rowGoOnCoder.load(initContext);
}
};
// Manages the wave-front processing of a single encoding frame
class FrameEncoder : public WaveFront, public Thread
{
public:
FrameEncoder();
virtual ~FrameEncoder() {}
virtual bool init(Encoder *top, int numRows, int numCols);
void destroy();
/* triggers encode of a new frame by the worker thread */
/** 函数功能 : 触发compressframe()进行编码
/* 调用范围 : 只在Encoder::encode函数中被调用
* \参数 curFrame : 待编码帧
* 返回值 : 成功返回true 异常返回false
**/
bool startCompressFrame(Frame* curFrame);
/* blocks until worker thread is done, returns access unit */
Frame *getEncodedPicture(NALList& list);
Event m_enable;//PV操作,每完成一帧即compressFrame()之后就会wait 表示编码帧是否准备好
Event m_done;//在encoder.create中先进行wait 每完成一帧即compressFrame()之后才会触发
// 以上两个是一个PV原语,m_enable表示准备开始编码,在startCompressFrame函数中触发在compressFrame之后wait
// m_done表示编码完成,在getEncodedPicture之前wait,在compressFrame之后触发
Event m_completionEvent;
int m_localTldIdx; //???? 用途???打开wpp为-1 否则为m_pool->m_numWorkers + m_jpId; 初始化为0
volatile bool m_threadActive;//初始化为true 用于compressFrame并行,直到encoder->stop中才置为false
volatile bool m_bAllRowsStop;
volatile int m_completionCount;
volatile int m_vbvResetTriggerRow;
uint32_t m_numRows;
uint32_t m_numCols;
uint32_t m_filterRowDelay;
uint32_t m_filterRowDelayCus;
uint32_t m_refLagRows;
CTURow* m_rows;
RateControlEntry m_rce;
SEIDecodedPictureHash m_seiReconPictureDigest;
uint64_t m_SSDY;
uint64_t m_SSDU;
uint64_t m_SSDV;
double m_ssim;
uint64_t m_accessUnitBits;
uint32_t m_ssimCnt;
MD5Context m_state[3];
uint32_t m_crc[3];
uint32_t m_checksum[3];
StatisticLog m_sliceTypeLog[3]; // per-slice type CU statistics
FrameStats m_frameStats; // stats of current frame for multi-pass encodes
volatile int m_activeWorkerCount; // count of workers currently encoding or filtering CTUs
volatile int m_totalActiveWorkerCount; // sum of m_activeWorkerCount sampled at end of each CTU
volatile int m_activeWorkerCountSamples; // count of times m_activeWorkerCount was sampled (think vbv restarts)
volatile int m_countRowBlocks; // count of workers forced to abandon a row because of top dependency
int64_t m_startCompressTime; // 当前帧开始编码的时间点timestamp when frame encoder is given a frame
int64_t m_row0WaitTime; // timestamp when row 0 is allowed to start
int64_t m_allRowsAvailableTime; // timestamp when all reference dependencies are resolved
int64_t m_endCompressTime; // timestamp after all CTUs are compressed
int64_t m_endFrameTime; // timestamp after RCEnd, NR updates, etc
int64_t m_stallStartTime; // timestamp when worker count becomes 0
int64_t m_prevOutputTime; // 上一次视频帧的输出时间 用于计算编码一帧的时间 timestamp when prev frame was retrieved by API thread
int64_t m_slicetypeWaitTime; // 从上一帧编码完毕到开始编码新一帧的等待时间total elapsed time waiting for decided frame
int64_t m_totalWorkerElapsedTime; // total elapsed time spent by worker threads processing CTUs
int64_t m_totalNoWorkerTime; // total elapsed time without any active worker threads
#if DETAILED_CU_STATS
CUStats m_cuStats;
#endif
Encoder* m_top; //指向上层的encoder类
x265_param* m_param;//配置参数
Frame* m_frame;//当前正在编码的帧
NoiseReduction* m_nr;
ThreadLocalData* m_tld; //所有的线程公用同一个buffer 空间大小为m_pool->m_numWorkers 在单机4核测试是4 ,里面含有anlysis类用于后续编码 /* for --no-wpp */
Bitstream* m_outStreams;
uint32_t* m_substreamSizes;
CUGeom* m_cuGeoms;//initializeGeoms()中申请一次,往后一直复用, 申请空间为allocGeoms * CUGeom::MAX_GEOMS = allocGeoms * 85,
// 如果最后一行不够CTU,并且最右边一列不够CTU, allocGeoms = 4, 如果其中一种情况 allocGeoms = 2, 刚好都符合CTU allocGeoms = 1
// 存储关系 一维数组,按照四叉树层次遍历存储cusize、depth、encodeidx等信息
uint32_t* m_ctuGeomMap;//申请空间为所有CTU个数 每个CTU对应的CUGeom,因为CUGeom分为4份,需要对于边界情况需要单独处理
// 例如:当前CTU 号 为 n 则其CUGeom* geom = m_cuGeoms + m_ctuGeomMap[n] 或 m_cuGeoms[m_ctuGeomMap[cuAddr]]
Bitstream m_bs;
MotionReference m_mref[2][MAX_NUM_REF + 1];
Entropy m_entropyCoder;
Entropy m_initSliceContext;
FrameFilter m_frameFilter;
NALList m_nalList;
class WeightAnalysis : public BondedTaskGroup //用于多线程分析加权帧 只在FrameEncoder::compressFrame()应用
{
public:
FrameEncoder& master;//当前运行的 FrameEncoder 编码帧
/** 函数功能 : 获取当前的编码帧 类
/* 调用范围 : 只在FrameEncoder::compressFrame()函数中被调用
* 返回值 : 构造函数
**/
WeightAnalysis(FrameEncoder& fe) : master(fe) {}
/** 函数功能 : 分析加权信息
/* 调用范围 : 只在WorkerThread::threadMain()函数中被调用
* \返回 : null * */
void processTasks(int workerThreadId);
protected:
WeightAnalysis operator=(const WeightAnalysis&);//运算符重载
};
protected:
/** 函数功能 : 计算CU所以情况的几何信息
/* 调用范围 : 只在FrameEncoder::startCompressFrame函数中被调用
* 返回值 : 成功返回ture 失败返回 false
**/
bool initializeGeoms();
/* analyze / compress frame, can be run in parallel within reference constraints */
void compressFrame();
/* called by compressFrame to generate final per-row bitstreams */
void encodeSlice();
void threadMain();
int collectCTUStatistics(const CUData& ctu, uint32_t* qtreeInterCnt, uint32_t* qtreeIntraCnt, uint32_t* qtreeSkipCnt);
int calcCTUQP(const CUData& ctu);
void noiseReductionUpdate();
/* Called by WaveFront::findJob() */
virtual void processRow(int row, int threadId);
virtual void processRowEncoder(int row, ThreadLocalData& tld);
void enqueueRowEncoder(int row) { WaveFront::enqueueRow(row * 2 + 0); }
void enqueueRowFilter(int row) { WaveFront::enqueueRow(row * 2 + 1); }
void enableRowEncoder(int row) { WaveFront::enableRow(row * 2 + 0); }
void enableRowFilter(int row) { WaveFront::enableRow(row * 2 + 1); }
};
}
#endif // ifndef X265_FRAMEENCODER_H