1 /*############################################################################
2 # Copyright (C) 2005 Intel Corporation
3 #
4 # SPDX-License-Identifier: MIT
5 ############################################################################*/
6
7 #include "brc_routines.h"
8
9 #include <math.h>
10 #include <algorithm>
11
12 #ifndef MFX_VERSION
13 #error MFX_VERSION not defined
14 #endif
15
16 #define BRC_SCENE_CHANGE_RATIO1 20.0
17 #define BRC_SCENE_CHANGE_RATIO2 5.0
18
hevcBitRateScale(mfxU32 bitrate)19 static mfxU32 hevcBitRateScale(mfxU32 bitrate) {
20 mfxU32 bit_rate_scale = 0;
21 while (bit_rate_scale < 16 && (bitrate & ((1 << (6 + bit_rate_scale + 1)) - 1)) == 0)
22 bit_rate_scale++;
23 return bit_rate_scale;
24 }
hevcCbpSizeScale(mfxU32 cpbSize)25 static mfxU32 hevcCbpSizeScale(mfxU32 cpbSize) {
26 mfxU32 cpb_size_scale = 2;
27 while (cpb_size_scale < 16 && (cpbSize & ((1 << (4 + cpb_size_scale + 1)) - 1)) == 0)
28 cpb_size_scale++;
29 return cpb_size_scale;
30 }
31 const mfxU32 h264_h265_au_cpb_removal_delay_length_minus1 = 23;
32 const mfxU32 h264_bit_rate_scale = 4;
33 const mfxU32 h264_cpb_size_scale = 2;
34
Hevc_GetExtBuffer(mfxExtBuffer ** extBuf,mfxU32 numExtBuf,mfxU32 id)35 mfxExtBuffer* Hevc_GetExtBuffer(mfxExtBuffer** extBuf, mfxU32 numExtBuf, mfxU32 id) {
36 if (extBuf != 0) {
37 for (mfxU16 i = 0; i < numExtBuf; i++) {
38 if (extBuf[i] != 0 && extBuf[i]->BufferId == id) // assuming aligned buffers
39 return (extBuf[i]);
40 }
41 }
42
43 return 0;
44 }
45
Init(mfxVideoParam * par,bool bField)46 mfxStatus cBRCParams::Init(mfxVideoParam* par, bool bField) {
47 printf("Sample BRC is used\n");
48 MFX_CHECK_NULL_PTR1(par);
49 MFX_CHECK(par->mfx.RateControlMethod == MFX_RATECONTROL_CBR ||
50 par->mfx.RateControlMethod == MFX_RATECONTROL_VBR,
51 MFX_ERR_UNDEFINED_BEHAVIOR);
52 bFieldMode = bField;
53 codecId = par->mfx.CodecId;
54
55 mfxU32 k = par->mfx.BRCParamMultiplier == 0 ? 1 : par->mfx.BRCParamMultiplier;
56 targetbps = k * par->mfx.TargetKbps * 1000;
57 maxbps = k * par->mfx.MaxKbps * 1000;
58
59 maxbps = (par->mfx.RateControlMethod == MFX_RATECONTROL_CBR)
60 ? targetbps
61 : ((maxbps >= targetbps) ? maxbps : targetbps);
62
63 mfxU32 bit_rate_scale =
64 (par->mfx.CodecId == MFX_CODEC_AVC) ? h264_bit_rate_scale : hevcBitRateScale(maxbps);
65 mfxU32 cpb_size_scale =
66 (par->mfx.CodecId == MFX_CODEC_AVC) ? h264_cpb_size_scale : hevcCbpSizeScale(maxbps);
67
68 rateControlMethod = par->mfx.RateControlMethod;
69 maxbps = ((maxbps >> (6 + bit_rate_scale)) << (6 + bit_rate_scale));
70
71 mfxExtCodingOption* pExtCO = (mfxExtCodingOption*)Hevc_GetExtBuffer(par->ExtParam,
72 par->NumExtParam,
73 MFX_EXTBUFF_CODING_OPTION);
74
75 HRDConformance = MFX_BRC_NO_HRD;
76 if (pExtCO) {
77 if ((MFX_CODINGOPTION_OFF != pExtCO->NalHrdConformance) &&
78 (MFX_CODINGOPTION_OFF != pExtCO->VuiNalHrdParameters))
79 HRDConformance = MFX_BRC_HRD_STRONG;
80 else if ((MFX_CODINGOPTION_ON == pExtCO->NalHrdConformance) &&
81 (MFX_CODINGOPTION_OFF == pExtCO->VuiNalHrdParameters))
82 HRDConformance = MFX_BRC_HRD_WEAK;
83 }
84
85 if (HRDConformance != MFX_BRC_NO_HRD) {
86 bufferSizeInBytes = ((k * par->mfx.BufferSizeInKB * 1000) >> (cpb_size_scale + 1))
87 << (cpb_size_scale + 1);
88 initialDelayInBytes = ((k * par->mfx.InitialDelayInKB * 1000) >> (cpb_size_scale + 1))
89 << (cpb_size_scale + 1);
90 bRec = 1;
91 bPanic = (HRDConformance == MFX_BRC_HRD_STRONG) ? 1 : 0;
92 }
93 MFX_CHECK(par->mfx.FrameInfo.FrameRateExtD != 0 && par->mfx.FrameInfo.FrameRateExtN != 0,
94 MFX_ERR_UNDEFINED_BEHAVIOR);
95
96 frameRate = (mfxF64)par->mfx.FrameInfo.FrameRateExtN / (mfxF64)par->mfx.FrameInfo.FrameRateExtD;
97
98 width = par->mfx.FrameInfo.Width;
99 height = par->mfx.FrameInfo.Height;
100
101 chromaFormat = par->mfx.FrameInfo.ChromaFormat == 0 ? MFX_CHROMAFORMAT_YUV420
102 : par->mfx.FrameInfo.ChromaFormat;
103 bitDepthLuma = par->mfx.FrameInfo.BitDepthLuma == 0 ? 8 : par->mfx.FrameInfo.BitDepthLuma;
104
105 quantOffset = 6 * (bitDepthLuma - 8);
106
107 inputBitsPerFrame = targetbps / frameRate;
108 maxInputBitsPerFrame = maxbps / frameRate;
109 gopPicSize = par->mfx.GopPicSize * (bFieldMode ? 2 : 1);
110 gopRefDist = par->mfx.GopRefDist * (bFieldMode ? 2 : 1);
111
112 mfxExtCodingOption2* pExtCO2 =
113 (mfxExtCodingOption2*)Hevc_GetExtBuffer(par->ExtParam,
114 par->NumExtParam,
115 MFX_EXTBUFF_CODING_OPTION2);
116 bPyr = (pExtCO2 && pExtCO2->BRefType == MFX_B_REF_PYRAMID);
117 maxFrameSizeInBits = pExtCO2 ? pExtCO2->MaxFrameSize * 8 : 0;
118
119 fAbPeriodLong = 100;
120 fAbPeriodShort = 6;
121 dqAbPeriod = 100;
122 bAbPeriod = 100;
123
124 if (maxFrameSizeInBits) {
125 bRec = 1;
126 bPanic = 1;
127 }
128
129 if (pExtCO2 && pExtCO2->MaxQPI <= 51 && pExtCO2->MaxQPI > pExtCO2->MinQPI &&
130 pExtCO2->MinQPI >= 1 && pExtCO2->MaxQPP <= 51 && pExtCO2->MaxQPP > pExtCO2->MinQPP &&
131 pExtCO2->MinQPP >= 1 && pExtCO2->MaxQPB <= 51 && pExtCO2->MaxQPB > pExtCO2->MinQPB &&
132 pExtCO2->MinQPB >= 1) {
133 quantMaxI = pExtCO2->MaxQPI + quantOffset;
134 quantMinI = pExtCO2->MinQPI;
135 quantMaxP = pExtCO2->MaxQPP + quantOffset;
136 quantMinP = pExtCO2->MinQPP;
137 quantMaxB = pExtCO2->MaxQPB + quantOffset;
138 quantMinB = pExtCO2->MinQPB;
139 }
140 else {
141 quantMaxI = quantMaxP = quantMaxB = 51 + quantOffset;
142 quantMinI = quantMinP = quantMinB = 1;
143 }
144
145 mfxExtCodingOption3* pExtCO3 =
146 (mfxExtCodingOption3*)Hevc_GetExtBuffer(par->ExtParam,
147 par->NumExtParam,
148 MFX_EXTBUFF_CODING_OPTION3);
149 if (pExtCO3) {
150 WinBRCMaxAvgKbps = pExtCO3->WinBRCMaxAvgKbps * par->mfx.BRCParamMultiplier;
151 WinBRCSize = pExtCO3->WinBRCSize;
152 }
153 mMBBRC = pExtCO3 && (pExtCO3->EnableMBQP == MFX_CODINGOPTION_ON);
154 return MFX_ERR_NONE;
155 }
156
GetBRCResetType(mfxVideoParam * par,bool bNewSequence,bool & bBRCReset,bool & bSlidingWindowReset)157 mfxStatus cBRCParams::GetBRCResetType(mfxVideoParam* par,
158 bool bNewSequence,
159 bool& bBRCReset,
160 bool& bSlidingWindowReset) {
161 bBRCReset = false;
162 bSlidingWindowReset = false;
163
164 if (bNewSequence)
165 return MFX_ERR_NONE;
166
167 cBRCParams new_par;
168 mfxStatus sts = new_par.Init(par);
169 MFX_CHECK_STS(sts);
170
171 MFX_CHECK(new_par.rateControlMethod == rateControlMethod, MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
172 MFX_CHECK(new_par.HRDConformance == HRDConformance, MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
173 MFX_CHECK(new_par.frameRate == frameRate, MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
174 MFX_CHECK(new_par.width == width, MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
175 MFX_CHECK(new_par.height == height, MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
176 MFX_CHECK(new_par.chromaFormat == chromaFormat, MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
177 MFX_CHECK(new_par.bitDepthLuma == bitDepthLuma, MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
178
179 if (HRDConformance == MFX_BRC_HRD_STRONG) {
180 MFX_CHECK(new_par.bufferSizeInBytes == bufferSizeInBytes, MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
181 MFX_CHECK(new_par.initialDelayInBytes == initialDelayInBytes,
182 MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
183 MFX_CHECK(new_par.targetbps == targetbps, MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
184 MFX_CHECK(new_par.maxbps == maxbps, MFX_ERR_INCOMPATIBLE_VIDEO_PARAM);
185 }
186 else if (new_par.targetbps != targetbps || new_par.maxbps != maxbps) {
187 bBRCReset = true;
188 }
189
190 if (new_par.WinBRCMaxAvgKbps != WinBRCMaxAvgKbps) {
191 bBRCReset = true;
192 bSlidingWindowReset = true;
193 }
194
195 if (new_par.maxFrameSizeInBits != maxFrameSizeInBits)
196 bBRCReset = true;
197 if (new_par.gopPicSize != gopPicSize)
198 bBRCReset = true;
199 if (new_par.gopRefDist != gopRefDist)
200 bBRCReset = true;
201 if (new_par.bPyr != bPyr)
202 bBRCReset = true;
203 if (new_par.quantMaxI != quantMaxI)
204 bBRCReset = true;
205 if (new_par.quantMinI != quantMinI)
206 bBRCReset = true;
207 if (new_par.quantMaxP != quantMaxP)
208 bBRCReset = true;
209 if (new_par.quantMinP != quantMinP)
210 bBRCReset = true;
211 if (new_par.quantMaxB != quantMaxB)
212 bBRCReset = true;
213 if (new_par.quantMinB != quantMinB)
214 bBRCReset = true;
215
216 return MFX_ERR_NONE;
217 }
218
219 enum {
220 MFX_BRC_RECODE_NONE = 0,
221 MFX_BRC_RECODE_QP = 1,
222 MFX_BRC_RECODE_PANIC = 2,
223 };
224
225 mfxF64 const QSTEP[88] = {
226 0.630, 0.707, 0.794, 0.891, 1.000, 1.122, 1.260, 1.414, 1.587,
227 1.782, 2.000, 2.245, 2.520, 2.828, 3.175, 3.564, 4.000, 4.490,
228 5.040, 5.657, 6.350, 7.127, 8.000, 8.980, 10.079, 11.314, 12.699,
229 14.254, 16.000, 17.959, 20.159, 22.627, 25.398, 28.509, 32.000, 35.919,
230 40.317, 45.255, 50.797, 57.018, 64.000, 71.838, 80.635, 90.510, 101.594,
231 114.035, 128.000, 143.675, 161.270, 181.019, 203.187, 228.070, 256.000, 287.350,
232 322.540, 362.039, 406.375, 456.140, 512.000, 574.701, 645.080, 724.077, 812.749,
233 912.280, 1024.000, 1149.401, 1290.159, 1448.155, 1625.499, 1824.561, 2048.000, 2298.802,
234 2580.318, 2896.309, 3250.997, 3649.121, 4096.000, 4597.605, 5160.637, 5792.619, 6501.995,
235 7298.242, 8192.000, 9195.209, 10321.273, 11585.238, 13003.989, 14596.485
236 };
237
QStep2QpFloor(mfxF64 qstep,mfxI32 qpoffset=0)238 mfxI32 QStep2QpFloor(mfxF64 qstep,
239 mfxI32 qpoffset = 0) // QSTEP[qp] <= qstep, return 0<=qp<=51+mQuantOffset
240 {
241 mfxU8 qp = mfxU8(std::upper_bound(QSTEP, QSTEP + 51 + qpoffset, qstep) - QSTEP);
242 return qp > 0 ? qp - 1 : 0;
243 }
244
Qstep2QP(mfxF64 qstep,mfxI32 qpoffset=0)245 mfxI32 Qstep2QP(mfxF64 qstep, mfxI32 qpoffset = 0) // return 0<=qp<=51+mQuantOffset
246 {
247 mfxI32 qp = QStep2QpFloor(qstep, qpoffset);
248
249 // prevent going QSTEP index out of bounds
250 if (qp >= (mfxI32)(sizeof(QSTEP) / sizeof(QSTEP[0])) - 1)
251 return 0;
252 return (qp == 51 + qpoffset || qstep < (QSTEP[qp] + QSTEP[qp + 1]) / 2) ? qp : qp + 1;
253 }
QP2Qstep(mfxI32 qp,mfxI32 qpoffset=0)254 mfxF64 QP2Qstep(mfxI32 qp, mfxI32 qpoffset = 0) {
255 return QSTEP[std::min(51 + qpoffset, qp)];
256 }
257
GetNewQP(mfxF64 totalFrameBits,mfxF64 targetFrameSizeInBits,mfxI32 minQP,mfxI32 maxQP,mfxI32 qp,mfxI32 qp_offset,mfxF64 f_pow,bool bStrict=false,bool bLim=true)258 mfxI32 GetNewQP(mfxF64 totalFrameBits,
259 mfxF64 targetFrameSizeInBits,
260 mfxI32 minQP,
261 mfxI32 maxQP,
262 mfxI32 qp,
263 mfxI32 qp_offset,
264 mfxF64 f_pow,
265 bool bStrict = false,
266 bool bLim = true) {
267 mfxF64 qstep = 0, qstep_new = 0;
268 mfxI32 qp_new = qp;
269
270 qstep = QP2Qstep(qp, qp_offset);
271 qstep_new = qstep * pow(totalFrameBits / targetFrameSizeInBits, f_pow);
272 qp_new = Qstep2QP(qstep_new, qp_offset);
273
274 if (totalFrameBits < targetFrameSizeInBits) // overflow
275 {
276 if (qp <= minQP) {
277 return qp; // QP change is impossible
278 }
279 if (bLim)
280 qp_new = std::max(qp_new, (minQP + qp + 1) >> 1);
281 if (bStrict)
282 qp_new = std::min(qp_new, qp - 1);
283 }
284 else // underflow
285 {
286 if (qp >= maxQP) {
287 return qp; // QP change is impossible
288 }
289 if (bLim)
290 qp_new = std::min(qp_new, (maxQP + qp + 1) >> 1);
291 if (bStrict)
292 qp_new = std::max(qp_new, qp + 1);
293 }
294 return mfx::clamp(qp_new, minQP, maxQP);
295 }
296
UpdateQPParams(mfxI32 qp,mfxU32 type,BRC_Ctx & ctx,mfxU32,mfxI32 minQuant,mfxI32 maxQuant,mfxU32 level)297 void UpdateQPParams(mfxI32 qp,
298 mfxU32 type,
299 BRC_Ctx& ctx,
300 mfxU32 /* rec_num */,
301 mfxI32 minQuant,
302 mfxI32 maxQuant,
303 mfxU32 level) {
304 ctx.Quant = qp;
305 if (type == MFX_FRAMETYPE_I) {
306 ctx.QuantI = qp;
307 ctx.QuantP = qp + 1;
308 ctx.QuantB = qp + 2;
309 }
310 else if (type == MFX_FRAMETYPE_P) {
311 qp -= level;
312 ctx.QuantI = qp - 1;
313 ctx.QuantP = qp;
314 ctx.QuantB = qp + 1;
315 }
316 else if (type == MFX_FRAMETYPE_B) {
317 level = level > 0 ? level - 1 : 0;
318 qp -= level;
319 ctx.QuantI = qp - 2;
320 ctx.QuantP = qp - 1;
321 ctx.QuantB = qp;
322 }
323 ctx.QuantI = mfx::clamp(ctx.QuantI, minQuant, maxQuant);
324 ctx.QuantP = mfx::clamp(ctx.QuantP, minQuant, maxQuant);
325 ctx.QuantB = mfx::clamp(ctx.QuantB, minQuant, maxQuant);
326 //printf("ctx.QuantI %d, ctx.QuantP %d, ctx.QuantB %d, level %d\n", ctx.QuantI, ctx.QuantP, ctx.QuantB, level);
327 }
328
GetRawFrameSize(mfxU32 lumaSize,mfxU16 chromaFormat,mfxU16 bitDepthLuma)329 mfxI32 GetRawFrameSize(mfxU32 lumaSize, mfxU16 chromaFormat, mfxU16 bitDepthLuma) {
330 mfxI32 frameSize = lumaSize;
331
332 if (chromaFormat == MFX_CHROMAFORMAT_YUV420)
333 frameSize += lumaSize / 2;
334 else if (chromaFormat == MFX_CHROMAFORMAT_YUV422)
335 frameSize += lumaSize;
336 else if (chromaFormat == MFX_CHROMAFORMAT_YUV444)
337 frameSize += lumaSize * 2;
338
339 frameSize = frameSize * bitDepthLuma / 8;
340 return frameSize * 8; //frame size in bits
341 }
isFieldMode(mfxVideoParam * par)342 bool isFieldMode(mfxVideoParam* par) {
343 return ((par->mfx.CodecId == MFX_CODEC_HEVC) &&
344 !(par->mfx.FrameInfo.PicStruct & MFX_PICSTRUCT_PROGRESSIVE));
345 }
346
Init(mfxVideoParam * par)347 mfxStatus ExtBRC::Init(mfxVideoParam* par) {
348 mfxStatus sts = MFX_ERR_NONE;
349
350 MFX_CHECK(!m_bInit, MFX_ERR_UNDEFINED_BEHAVIOR);
351 sts = m_par.Init(par, isFieldMode(par));
352 MFX_CHECK_STS(sts);
353
354 if (m_par.HRDConformance != MFX_BRC_NO_HRD) {
355 if (m_par.codecId == MFX_CODEC_AVC)
356 m_hrdSpec.reset(new H264_HRD());
357 else
358 m_hrdSpec.reset(new HEVC_HRD());
359 m_hrdSpec->Init(m_par);
360 }
361 m_ctx = {};
362
363 m_ctx.fAbLong = m_par.inputBitsPerFrame;
364 m_ctx.fAbShort = m_par.inputBitsPerFrame;
365 m_ctx.encOrder = mfxU32(-1);
366
367 mfxI32 rawSize =
368 GetRawFrameSize(m_par.width * m_par.height, m_par.chromaFormat, m_par.bitDepthLuma);
369 mfxI32 qp = GetNewQP(rawSize,
370 m_par.inputBitsPerFrame,
371 m_par.quantMinI,
372 m_par.quantMaxI,
373 1,
374 m_par.quantOffset,
375 0.5,
376 false,
377 false);
378
379 UpdateQPParams(qp, MFX_FRAMETYPE_I, m_ctx, 0, m_par.quantMinI, m_par.quantMaxI, 0);
380
381 m_ctx.dQuantAb = qp > 0 ? 1. / qp : 1.0; //kw
382
383 if (m_par.WinBRCSize) {
384 m_avg.reset(new AVGBitrate(m_par.WinBRCSize,
385 (mfxU32)(m_par.WinBRCMaxAvgKbps * 1000.0 / m_par.frameRate),
386 (mfxU32)m_par.inputBitsPerFrame));
387 MFX_CHECK_NULL_PTR1(m_avg.get());
388 }
389 if (m_par.mMBBRC) {
390 mfxU32 size = par->AsyncDepth > 1 ? 2 : 1;
391 mfxU16 blSize = 16;
392 mfxU32 wInBlk = (par->mfx.FrameInfo.Width + blSize - 1) / blSize;
393 mfxU32 hInBlk = (par->mfx.FrameInfo.Height + blSize - 1) / blSize;
394
395 m_MBQPBuff.resize(size * wInBlk * hInBlk);
396 m_MBQP.resize(size);
397 m_ExtBuff.resize(size);
398
399 for (mfxU32 i = 0; i < size; i++) {
400 m_MBQP[i].Header.BufferId = MFX_EXTBUFF_MBQP;
401 m_MBQP[i].Header.BufferSz = sizeof(mfxExtMBQP);
402 m_MBQP[i].BlockSize = blSize;
403 m_MBQP[i].NumQPAlloc = wInBlk * hInBlk;
404 m_MBQP[i].Mode = MFX_MBQP_MODE_QP_VALUE;
405 m_MBQP[i].QP = &(m_MBQPBuff[i * wInBlk * hInBlk]);
406 m_ExtBuff[i] = (mfxExtBuffer*)&(m_MBQP[i]);
407 }
408 }
409 m_bInit = true;
410 return sts;
411 }
412
GetFrameType(mfxU16 m_frameType,mfxU16 level,mfxU16 gopRegDist)413 mfxU16 GetFrameType(mfxU16 m_frameType, mfxU16 level, mfxU16 gopRegDist) {
414 if (m_frameType & MFX_FRAMETYPE_IDR)
415 return MFX_FRAMETYPE_I;
416 else if (m_frameType & MFX_FRAMETYPE_I)
417 return MFX_FRAMETYPE_I;
418 else if (m_frameType & MFX_FRAMETYPE_P)
419 return MFX_FRAMETYPE_P;
420 else if ((m_frameType & MFX_FRAMETYPE_REF) && (level == 0 || gopRegDist == 1))
421 return MFX_FRAMETYPE_P; //low delay B
422 else
423 return MFX_FRAMETYPE_B;
424 }
425
isFrameBeforeIntra(mfxU32 order,mfxU32 intraOrder,mfxU32 gopPicSize,mfxU32 gopRefDist)426 bool isFrameBeforeIntra(mfxU32 order, mfxU32 intraOrder, mfxU32 gopPicSize, mfxU32 gopRefDist) {
427 mfxI32 distance0 = gopPicSize * 3 / 4;
428 mfxI32 distance1 = gopPicSize - gopRefDist * 3;
429 return mfxI32(order - intraOrder) > std::max(distance0, distance1);
430 }
431
SetRecodeParams(mfxU16 brcStatus,mfxI32 qp,mfxI32 qp_new,mfxI32 minQP,mfxI32 maxQP,BRC_Ctx & ctx,mfxBRCFrameStatus * status)432 mfxStatus SetRecodeParams(mfxU16 brcStatus,
433 mfxI32 qp,
434 mfxI32 qp_new,
435 mfxI32 minQP,
436 mfxI32 maxQP,
437 BRC_Ctx& ctx,
438 mfxBRCFrameStatus* status) {
439 ctx.bToRecode = 1;
440
441 if (brcStatus == MFX_BRC_BIG_FRAME || brcStatus == MFX_BRC_PANIC_BIG_FRAME) {
442 MFX_CHECK(qp_new >= qp, MFX_ERR_UNDEFINED_BEHAVIOR);
443 ctx.Quant = qp_new;
444 ctx.QuantMax = maxQP;
445 if (brcStatus == MFX_BRC_BIG_FRAME && qp_new > qp) {
446 ctx.QuantMin = std::max(qp + 1, minQP); //limit QP range for recoding
447 status->BRCStatus = MFX_BRC_BIG_FRAME;
448 }
449 else {
450 ctx.QuantMin = minQP;
451 ctx.bPanic = 1;
452 status->BRCStatus = MFX_BRC_PANIC_BIG_FRAME;
453 }
454 }
455 else if (brcStatus == MFX_BRC_SMALL_FRAME || brcStatus == MFX_BRC_PANIC_SMALL_FRAME) {
456 MFX_CHECK(qp_new <= qp, MFX_ERR_UNDEFINED_BEHAVIOR);
457
458 ctx.Quant = qp_new;
459 ctx.QuantMin = minQP; //limit QP range for recoding
460
461 if (brcStatus == MFX_BRC_SMALL_FRAME && qp_new < qp) {
462 ctx.QuantMax = std::min(qp - 1, maxQP);
463 status->BRCStatus = MFX_BRC_SMALL_FRAME;
464 }
465 else {
466 ctx.QuantMax = maxQP;
467 status->BRCStatus = MFX_BRC_PANIC_SMALL_FRAME;
468 ctx.bPanic = 1;
469 }
470 }
471 //printf("recode %d , qp %d new %d, status %d\n", ctx.encOrder, qp, qp_new, status->BRCStatus);
472 return MFX_ERR_NONE;
473 }
474 mfxI32
GetNewQPTotal(mfxF64 bo,mfxF64 dQP,mfxI32 minQP,mfxI32 maxQP,mfxI32 qp,bool bPyr,bool bSC)475 GetNewQPTotal(mfxF64 bo, mfxF64 dQP, mfxI32 minQP, mfxI32 maxQP, mfxI32 qp, bool bPyr, bool bSC) {
476 mfxU8 mode = (!bPyr);
477
478 bo = mfx::clamp(bo, -1.0, 1.0);
479 dQP = mfx::clamp(dQP, 1. / maxQP, 1. / minQP);
480 dQP = dQP + (1. / maxQP - dQP) * bo;
481 dQP = mfx::clamp(dQP, 1. / maxQP, 1. / minQP);
482 mfxI32 quant_new = (mfxI32)(1. / dQP + 0.5);
483
484 //printf(" GetNewQPTotal: bo %f, quant %d, quant_new %d, mode %d\n", bo, qp, quant_new, mode);
485 if (!bSC) {
486 if (mode == 0) // low: qp_diff [-2; 2]
487 {
488 if (quant_new >= qp + 5)
489 quant_new = qp + 2;
490 else if (quant_new > qp + 3)
491 quant_new = qp + 1;
492 else if (quant_new <= qp - 5)
493 quant_new = qp - 2;
494 else if (quant_new < qp - 2)
495 quant_new = qp - 1;
496 }
497 else // (mode == 1) midle: qp_diff [-3; 3]
498 {
499 if (quant_new >= qp + 5)
500 quant_new = qp + 3;
501 else if (quant_new > qp + 3)
502 quant_new = qp + 2;
503 else if (quant_new <= qp - 5)
504 quant_new = qp - 3;
505 else if (quant_new < qp - 2)
506 quant_new = qp - 2;
507 }
508 }
509 else {
510 quant_new = mfx::clamp(quant_new, qp - 5, qp + 5);
511 }
512 return mfx::clamp(quant_new, minQP, maxQP);
513 }
514 // Reduce AB period before intra and increase it after intra (to avoid intra frame affect on the bottom of hrd)
GetAbPeriodCoeff(mfxU32 numInGop,mfxU32 gopPicSize)515 mfxF64 GetAbPeriodCoeff(mfxU32 numInGop, mfxU32 gopPicSize) {
516 const mfxU32 maxForCorrection = 30;
517 const mfxF64 maxValue = 1.5;
518 const mfxF64 minValue = 1.0;
519
520 mfxU32 numForCorrection = std::min(gopPicSize / 2, maxForCorrection);
521 mfxF64 k[maxForCorrection] = {};
522
523 if (numInGop >= gopPicSize || gopPicSize < 2)
524 return 1.0;
525
526 for (mfxU32 i = 0; i < numForCorrection; i++) {
527 k[i] = maxValue - (maxValue - minValue) * i / numForCorrection;
528 }
529 if (numInGop < gopPicSize / 2) {
530 return k[numInGop < numForCorrection ? numInGop : numForCorrection - 1];
531 }
532 else {
533 mfxU32 n = gopPicSize - 1 - numInGop;
534 return 1.0 / k[n < numForCorrection ? n : numForCorrection - 1];
535 }
536 }
537
GetCurQP(mfxU32 type,mfxI32 layer)538 mfxI32 ExtBRC::GetCurQP(mfxU32 type, mfxI32 layer) {
539 mfxI32 qp = 0;
540 if (type == MFX_FRAMETYPE_I) {
541 qp = m_ctx.QuantI;
542 qp = mfx::clamp(qp, m_par.quantMinI, m_par.quantMaxI);
543 }
544 else if (type == MFX_FRAMETYPE_P) {
545 qp = m_ctx.QuantP + layer;
546 qp = mfx::clamp(qp, m_par.quantMinP, m_par.quantMaxP);
547 }
548 else {
549 qp = m_ctx.QuantB + (layer > 0 ? layer - 1 : 0);
550 qp = mfx::clamp(qp, m_par.quantMinB, m_par.quantMaxB);
551 }
552 //printf("GetCurQP I %d P %d B %d, min %d max %d type %d \n", m_ctx.QuantI, m_ctx.QuantP, m_ctx.QuantB, m_par.quantMinI, m_par.quantMaxI, type);
553
554 return qp;
555 }
556
CheckHrdAndUpdateQP(HRDCodecSpec & hrd,mfxU32 frameSizeInBits,mfxU32 eo,bool bIdr,mfxI32 currQP)557 inline mfxU16 CheckHrdAndUpdateQP(HRDCodecSpec& hrd,
558 mfxU32 frameSizeInBits,
559 mfxU32 eo,
560 bool bIdr,
561 mfxI32 currQP) {
562 if (frameSizeInBits > hrd.GetMaxFrameSizeInBits(eo, bIdr)) {
563 hrd.SetUndeflowQuant(currQP);
564 return MFX_BRC_BIG_FRAME;
565 }
566 else if (frameSizeInBits < hrd.GetMinFrameSizeInBits(eo, bIdr)) {
567 hrd.SetUndeflowQuant(currQP);
568 return MFX_BRC_SMALL_FRAME;
569 }
570 return MFX_BRC_OK;
571 }
GetFrameTargetSize(mfxU32 brcSts,mfxI32 minFrameSize,mfxI32 maxFrameSize)572 mfxI32 GetFrameTargetSize(mfxU32 brcSts, mfxI32 minFrameSize, mfxI32 maxFrameSize) {
573 if (brcSts != MFX_BRC_BIG_FRAME && brcSts != MFX_BRC_SMALL_FRAME)
574 return 0;
575 return (brcSts == MFX_BRC_BIG_FRAME) ? maxFrameSize * 3 / 4 : minFrameSize * 5 / 4;
576 }
Update(mfxBRCFrameParam * frame_par,mfxBRCFrameCtrl * frame_ctrl,mfxBRCFrameStatus * status)577 mfxStatus ExtBRC::Update(mfxBRCFrameParam* frame_par,
578 mfxBRCFrameCtrl* frame_ctrl,
579 mfxBRCFrameStatus* status) {
580 mfxStatus sts = MFX_ERR_NONE;
581
582 MFX_CHECK_NULL_PTR3(frame_par, frame_ctrl, status);
583 MFX_CHECK(m_bInit, MFX_ERR_NOT_INITIALIZED);
584
585 mfxU16& brcSts = status->BRCStatus;
586 status->MinFrameSize = 0;
587
588 //printf("ExtBRC::Update: m_ctx.encOrder %d , frame_par->EncodedOrder %d, frame_par->NumRecode %d, frame_par->CodedFrameSize %d, qp %d\n", m_ctx.encOrder , frame_par->EncodedOrder, frame_par->NumRecode, frame_par->CodedFrameSize, frame_ctrl->QpY);
589
590 mfxI32 bitsEncoded = frame_par->CodedFrameSize * 8;
591 mfxU32 picType = GetFrameType(frame_par->FrameType, frame_par->PyramidLayer, m_par.gopRefDist);
592 mfxI32 qpY = frame_ctrl->QpY + m_par.quantOffset;
593 mfxI32 layer = frame_par->PyramidLayer;
594 mfxF64 qstep = QP2Qstep(qpY, m_par.quantOffset);
595
596 mfxF64 fAbLong = m_ctx.fAbLong + (bitsEncoded - m_ctx.fAbLong) / m_par.fAbPeriodLong;
597 mfxF64 fAbShort = m_ctx.fAbShort + (bitsEncoded - m_ctx.fAbShort) / m_par.fAbPeriodShort;
598 mfxF64 eRate = bitsEncoded * sqrt(qstep);
599 mfxF64 e2pe = 0;
600 bool bMaxFrameSizeMode =
601 m_par.maxFrameSizeInBits != 0 && m_par.rateControlMethod == MFX_RATECONTROL_VBR &&
602 m_par.maxFrameSizeInBits < m_par.inputBitsPerFrame * 2 &&
603 m_ctx.totalDeviation < (-1) * m_par.inputBitsPerFrame * m_par.frameRate;
604
605 if (picType == MFX_FRAMETYPE_I)
606 e2pe = (m_ctx.eRateSH == 0) ? (BRC_SCENE_CHANGE_RATIO2 + 1) : eRate / m_ctx.eRateSH;
607 else
608 e2pe = (m_ctx.eRate == 0) ? (BRC_SCENE_CHANGE_RATIO2 + 1) : eRate / m_ctx.eRate;
609
610 mfxU32 frameSizeLim = 0xfffffff; // sliding window limitation or external frame size limitation
611
612 bool bSHStart = false;
613 bool bNeedUpdateQP = false;
614
615 brcSts = MFX_BRC_OK;
616
617 if (m_par.bRec && m_ctx.bToRecode &&
618 (m_ctx.encOrder != frame_par->EncodedOrder || frame_par->NumRecode == 0)) {
619 // Frame must be recoded, but encoder calls BR for another frame
620 return MFX_ERR_UNDEFINED_BEHAVIOR;
621 }
622 if (frame_par->NumRecode == 0 || m_ctx.encOrder != frame_par->EncodedOrder) {
623 // Set context for new frame
624 if (picType == MFX_FRAMETYPE_I)
625 m_ctx.LastIEncOrder = frame_par->EncodedOrder;
626 m_ctx.encOrder = frame_par->EncodedOrder;
627 m_ctx.poc = frame_par->DisplayOrder;
628 m_ctx.bToRecode = 0;
629 m_ctx.bPanic = 0;
630
631 if (picType == MFX_FRAMETYPE_I) {
632 m_ctx.QuantMin = m_par.quantMinI;
633 m_ctx.QuantMax = m_par.quantMaxI;
634 }
635 else if (picType == MFX_FRAMETYPE_P) {
636 m_ctx.QuantMin = m_par.quantMinP;
637 m_ctx.QuantMax = m_par.quantMaxP;
638 }
639 else {
640 m_ctx.QuantMin = m_par.quantMinB;
641 m_ctx.QuantMax = m_par.quantMaxB;
642 }
643 m_ctx.Quant = qpY;
644
645 if (m_ctx.SceneChange && (m_ctx.poc > m_ctx.SChPoc + 1 || m_ctx.poc == 0))
646 m_ctx.SceneChange &= ~16;
647
648 bNeedUpdateQP = true;
649
650 if (m_par.HRDConformance != MFX_BRC_NO_HRD) {
651 m_hrdSpec->ResetQuant();
652 }
653 //printf("m_ctx.SceneChange %d, m_ctx.poc %d, m_ctx.SChPoc, m_ctx.poc %d \n", m_ctx.SceneChange, m_ctx.poc, m_ctx.SChPoc, m_ctx.poc);
654 }
655 bool bIntra = picType == MFX_FRAMETYPE_I;
656 if (m_par.HRDConformance != MFX_BRC_NO_HRD) {
657 brcSts = CheckHrdAndUpdateQP(*m_hrdSpec.get(),
658 bitsEncoded,
659 frame_par->EncodedOrder,
660 bIntra,
661 qpY);
662
663 MFX_CHECK(brcSts == MFX_BRC_OK || (!m_ctx.bPanic), MFX_ERR_NOT_ENOUGH_BUFFER);
664 if (brcSts == MFX_BRC_OK && !m_ctx.bPanic)
665 bNeedUpdateQP = true;
666
667 status->MinFrameSize = m_hrdSpec->GetMinFrameSizeInBits(frame_par->EncodedOrder, bIntra);
668
669 //printf("%d: poc %d, size %d QP %d (%d %d), HRD sts %d, maxFrameSize %d, type %d \n",frame_par->EncodedOrder, frame_par->DisplayOrder, bitsEncoded, m_ctx.Quant, m_ctx.QuantMin, m_ctx.QuantMax, brcSts, m_hrd.GetMaxFrameSize(), frame_par->FrameType);
670 }
671 if (e2pe > BRC_SCENE_CHANGE_RATIO2) {
672 // scene change, resetting BRC statistics
673 fAbLong = m_ctx.fAbLong = m_par.inputBitsPerFrame;
674 fAbShort = m_ctx.fAbShort = m_par.inputBitsPerFrame;
675 fAbLong = m_ctx.fAbLong + (bitsEncoded - m_ctx.fAbLong) / m_par.fAbPeriodLong;
676 fAbShort = m_ctx.fAbShort + (bitsEncoded - m_ctx.fAbShort) / m_par.fAbPeriodShort;
677 m_ctx.SceneChange |= 1;
678 if (picType != MFX_FRAMETYPE_B) {
679 bSHStart = true;
680 m_ctx.SceneChange |= 16;
681 m_ctx.eRateSH = eRate;
682 //if ((frame_par->DisplayOrder - m_ctx.SChPoc) >= std::min((mfxU32)(m_par.frameRate), m_par.gopRefDist))
683 { m_ctx.dQuantAb = 1. / m_ctx.Quant; }
684 m_ctx.SChPoc = frame_par->DisplayOrder;
685 //printf("!!!!!!!!!!!!!!!!!!!!! %d m_ctx.SceneChange %d, order %d\n", frame_par->EncodedOrder, m_ctx.SceneChange, frame_par->DisplayOrder);
686 }
687 }
688
689 if (m_avg.get()) {
690 frameSizeLim = std::min(
691 frameSizeLim,
692 m_avg->GetMaxFrameSize(m_ctx.bPanic, bSHStart || bIntra, frame_par->NumRecode));
693 }
694 if (m_par.maxFrameSizeInBits) {
695 frameSizeLim = std::min(frameSizeLim, m_par.maxFrameSizeInBits);
696 }
697 //printf("frameSizeLim %d (%d)\n", frameSizeLim, bitsEncoded);
698
699 if (frame_par->NumRecode < 2)
700 // Check other condions for recoding (update qp is it is needed)
701 {
702 mfxF64 targetFrameSize = std::max<mfxF64>((mfxF64)m_par.inputBitsPerFrame, fAbLong);
703 mfxF64 maxFrameSize =
704 (m_ctx.encOrder == 0 ? 6.0 : (bSHStart || picType == MFX_FRAMETYPE_I) ? 8.0 : 4.0) *
705 targetFrameSize * (m_par.bPyr ? 1.5 : 1.0);
706 mfxI32 quantMax = m_ctx.QuantMax;
707 mfxI32 quantMin = m_ctx.QuantMin;
708 mfxI32 quant = qpY;
709
710 maxFrameSize = std::min(maxFrameSize, (mfxF64)frameSizeLim);
711
712 if (m_par.HRDConformance != MFX_BRC_NO_HRD) {
713 if (bSHStart || bIntra)
714 maxFrameSize =
715 std::min(maxFrameSize,
716 3.5 / 9. * m_hrdSpec->GetMaxFrameSizeInBits(m_ctx.encOrder, bIntra) +
717 5.5 / 9. * targetFrameSize);
718 else
719 maxFrameSize =
720 std::min(maxFrameSize,
721 2.5 / 9. * m_hrdSpec->GetMaxFrameSizeInBits(m_ctx.encOrder, bIntra) +
722 6.5 / 9. * targetFrameSize);
723
724 quantMax = std::min(m_hrdSpec->GetMaxQuant(), quantMax);
725 quantMin = std::max(m_hrdSpec->GetMinQuant(), quantMin);
726 }
727 maxFrameSize = std::max(maxFrameSize, targetFrameSize);
728
729 if (bitsEncoded > maxFrameSize && quant < quantMax) {
730 mfxI32 quant_new = GetNewQP(bitsEncoded,
731 (mfxU32)maxFrameSize,
732 quantMin,
733 quantMax,
734 quant,
735 m_par.quantOffset,
736 1);
737 if (quant_new > quant) {
738 bNeedUpdateQP = false;
739 //printf(" recode 1-0: %d: k %5f bitsEncoded %d maxFrameSize %d, targetSize %d, fAbLong %f, inputBitsPerFrame %d, qp %d new %d\n",frame_par->EncodedOrder, bitsEncoded/maxFrameSize, (int)bitsEncoded, (int)maxFrameSize,(int)targetFrameSize, fAbLong, m_par.inputBitsPerFrame, quant, quant_new);
740 if (quant_new > GetCurQP(picType, layer)) {
741 UpdateQPParams(bMaxFrameSizeMode ? quant_new - 1 : quant_new,
742 picType,
743 m_ctx,
744 0,
745 quantMin,
746 quantMax,
747 layer);
748 fAbLong = m_ctx.fAbLong = m_par.inputBitsPerFrame;
749 fAbShort = m_ctx.fAbShort = m_par.inputBitsPerFrame;
750 m_ctx.dQuantAb = 1. / quant_new;
751 }
752
753 if (m_par.bRec) {
754 SetRecodeParams(MFX_BRC_BIG_FRAME,
755 quant,
756 quant_new,
757 quantMin,
758 quantMax,
759 m_ctx,
760 status);
761 return sts;
762 }
763 } //(quant_new > quant)
764 } //bitsEncoded > maxFrameSize
765
766 if (bitsEncoded > maxFrameSize && quant == quantMax && picType != MFX_FRAMETYPE_I &&
767 m_par.bPanic && (!m_ctx.bPanic) &&
768 isFrameBeforeIntra(m_ctx.encOrder,
769 m_ctx.LastIEncOrder,
770 m_par.gopPicSize,
771 m_par.gopRefDist)) {
772 //skip frames before intra
773 SetRecodeParams(MFX_BRC_PANIC_BIG_FRAME,
774 quant,
775 quant,
776 quantMin,
777 quantMax,
778 m_ctx,
779 status);
780 return sts;
781 }
782 if (m_par.HRDConformance != MFX_BRC_NO_HRD && frame_par->NumRecode == 0 &&
783 (quant < quantMax)) {
784 mfxF64 maxFrameSizeHrd =
785 m_hrdSpec->GetMaxFrameSizeInBits(frame_par->EncodedOrder, bIntra);
786 mfxF64 FAMax = 1. / 9. * maxFrameSizeHrd + 8. / 9. * fAbLong;
787
788 if (fAbShort > FAMax) {
789 mfxI32 quant_new =
790 GetNewQP(fAbShort, FAMax, quantMin, quantMax, quant, m_par.quantOffset, 0.5);
791 //printf(" recode 2-0: %d: FAMax %f, fAbShort %f, quant_new %d\n",frame_par->EncodedOrder, FAMax, fAbShort, quant_new);
792
793 if (quant_new > quant) {
794 bNeedUpdateQP = false;
795 if (quant_new > GetCurQP(picType, layer)) {
796 UpdateQPParams(quant_new, picType, m_ctx, 0, quantMin, quantMax, layer);
797 fAbLong = m_ctx.fAbLong = m_par.inputBitsPerFrame;
798 fAbShort = m_ctx.fAbShort = m_par.inputBitsPerFrame;
799 m_ctx.dQuantAb = 1. / quant_new;
800 }
801 if (m_par.bRec) {
802 SetRecodeParams(MFX_BRC_BIG_FRAME,
803 quant,
804 quant_new,
805 quantMin,
806 quantMax,
807 m_ctx,
808 status);
809 return sts;
810 }
811 } //quant_new > quant
812 }
813 } //m_par.HRDConformance
814 }
815 if (((m_par.HRDConformance != MFX_BRC_NO_HRD && brcSts != MFX_BRC_OK) ||
816 (bitsEncoded > (mfxI32)frameSizeLim)) &&
817 m_par.bRec) {
818 mfxI32 quant = m_ctx.Quant;
819 mfxI32 quant_new = quant;
820 if (bitsEncoded > (mfxI32)frameSizeLim) {
821 brcSts = MFX_BRC_BIG_FRAME;
822 quant_new = GetNewQP(bitsEncoded,
823 frameSizeLim,
824 m_ctx.QuantMin,
825 m_ctx.QuantMax,
826 quant,
827 m_par.quantOffset,
828 1,
829 true);
830 }
831 else if (brcSts == MFX_BRC_BIG_FRAME || brcSts == MFX_BRC_SMALL_FRAME) {
832 mfxF64 targetSize = GetFrameTargetSize(
833 brcSts,
834 m_hrdSpec->GetMinFrameSizeInBits(frame_par->EncodedOrder, bIntra),
835 m_hrdSpec->GetMaxFrameSizeInBits(frame_par->EncodedOrder, bIntra));
836 if (targetSize == 0) {
837 return MFX_ERR_INVALID_VIDEO_PARAM;
838 }
839
840 quant_new = GetNewQP(bitsEncoded,
841 targetSize,
842 m_ctx.QuantMin,
843 m_ctx.QuantMax,
844 quant,
845 m_par.quantOffset,
846 1,
847 true);
848 }
849 if (quant_new != quant) {
850 if (brcSts == MFX_BRC_SMALL_FRAME) {
851 quant_new = std::max(quant_new, quant - 2);
852 brcSts = MFX_BRC_PANIC_SMALL_FRAME;
853 }
854 // Idea is to check a sign mismatch, 'true' if both are negative or positive
855 if ((quant_new - qpY) * (quant_new - GetCurQP(picType, layer)) > 0) {
856 UpdateQPParams(quant_new, picType, m_ctx, 0, m_ctx.QuantMin, m_ctx.QuantMax, layer);
857 }
858 bNeedUpdateQP = false;
859 }
860 SetRecodeParams(brcSts, quant, quant_new, m_ctx.QuantMin, m_ctx.QuantMax, m_ctx, status);
861 }
862 else {
863 // no recoding are needed. Save context params
864
865 mfxF64 k = 1. / m_ctx.Quant;
866 mfxF64 dqAbPeriod = m_par.dqAbPeriod;
867 if (m_ctx.bToRecode)
868 dqAbPeriod = (k < m_ctx.dQuantAb) ? 16 : 25;
869
870 if (bNeedUpdateQP) {
871 m_ctx.dQuantAb += (k - m_ctx.dQuantAb) / dqAbPeriod;
872 m_ctx.dQuantAb = mfx::clamp(m_ctx.dQuantAb, 1. / m_ctx.QuantMax, 1. / m_ctx.QuantMin);
873
874 m_ctx.fAbLong = fAbLong;
875 m_ctx.fAbShort = fAbShort;
876 }
877
878 bool oldScene = false;
879 if ((m_ctx.SceneChange & 16) && (m_ctx.poc < m_ctx.SChPoc) && (e2pe < .01) &&
880 (mfxF64)bitsEncoded < 1.5 * fAbLong)
881 oldScene = true;
882 //printf("-- m_ctx.eRate %f, eRate %f, e2pe %f\n", m_ctx.eRate, eRate, e2pe );
883
884 if (picType != MFX_FRAMETYPE_B) {
885 m_ctx.LastNonBFrameSize = bitsEncoded;
886 if (picType == MFX_FRAMETYPE_I)
887 m_ctx.eRateSH = eRate;
888 else
889 m_ctx.eRate = eRate;
890 }
891
892 if (m_avg.get()) {
893 m_avg->UpdateSlidingWindow(bitsEncoded,
894 m_ctx.encOrder,
895 m_ctx.bPanic,
896 bSHStart || picType == MFX_FRAMETYPE_I,
897 frame_par->NumRecode);
898 }
899
900 m_ctx.totalDeviation += ((mfxF64)bitsEncoded - m_par.inputBitsPerFrame);
901
902 //printf("-- %d (%d)) Total deviation %f, old scene %d, bNeedUpdateQP %d, m_ctx.Quant %d, type %d\n", frame_par->EncodedOrder, frame_par->DisplayOrder,m_ctx.totalDeviation, oldScene , bNeedUpdateQP, m_ctx.Quant,picType);
903
904 if (!m_ctx.bPanic && (!oldScene) && bNeedUpdateQP) {
905 mfxI32 quant_new = m_ctx.Quant;
906 //Update QP
907
908 mfxF64 totDev = m_ctx.totalDeviation;
909 mfxF64 HRDDev = 0.0;
910 mfxF64 maxFrameSizeHrd = 0.0;
911 if (m_par.HRDConformance != MFX_BRC_NO_HRD) {
912 HRDDev = m_hrdSpec->GetBufferDeviation(frame_par->EncodedOrder);
913 maxFrameSizeHrd = m_hrdSpec->GetMaxFrameSizeInBits(frame_par->EncodedOrder, bIntra);
914 //printf("HRDDiv %f\n", HRDDiv);
915 }
916 mfxF64 dequant_new = m_ctx.dQuantAb * pow(m_par.inputBitsPerFrame / m_ctx.fAbLong, 1.2);
917 mfxF64 bAbPreriod = m_par.bAbPeriod;
918
919 if (m_par.HRDConformance != MFX_BRC_NO_HRD) {
920 if (m_par.rateControlMethod == MFX_RATECONTROL_VBR &&
921 m_par.maxbps > m_par.targetbps) {
922 totDev = std::max(totDev, HRDDev);
923 }
924 else {
925 totDev = HRDDev;
926 }
927 if (totDev > 0) {
928 bAbPreriod =
929 (mfxF64)(m_par.bPyr ? 4 : 3) * (mfxF64)maxFrameSizeHrd / fAbShort *
930 GetAbPeriodCoeff(m_ctx.encOrder - m_ctx.LastIEncOrder, m_par.gopPicSize);
931 bAbPreriod = mfx::clamp(bAbPreriod, m_par.bAbPeriod / 10, m_par.bAbPeriod);
932 }
933 }
934 quant_new = GetNewQPTotal(totDev / bAbPreriod / (mfxF64)m_par.inputBitsPerFrame,
935 dequant_new,
936 m_ctx.QuantMin,
937 m_ctx.QuantMax,
938 m_ctx.Quant,
939 m_par.bPyr && m_par.bRec,
940 bSHStart && m_ctx.bToRecode == 0);
941 //printf(" ===%d quant old %d quant_new %d, bitsEncoded %d m_ctx.QuantMin %d m_ctx.QuantMax %d\n", frame_par->EncodedOrder, m_ctx.Quant, quant_new, bitsEncoded, m_ctx.QuantMin, m_ctx.QuantMax);
942
943 if (bMaxFrameSizeMode) {
944 mfxF64 targetMax = ((mfxF64)m_par.maxFrameSizeInBits *
945 ((bSHStart || picType == MFX_FRAMETYPE_I) ? 0.95 : 0.9));
946 mfxF64 targetMin =
947 ((mfxF64)m_par.maxFrameSizeInBits *
948 ((bSHStart || picType == MFX_FRAMETYPE_I) ? 0.9 : 0.8 /*0.75 : 0.5*/));
949 mfxI32 QuantNewMin = GetNewQP(bitsEncoded,
950 targetMax,
951 m_ctx.QuantMin,
952 m_ctx.QuantMax,
953 m_ctx.Quant,
954 m_par.quantOffset,
955 1,
956 false,
957 false);
958 mfxI32 QuantNewMax = GetNewQP(bitsEncoded,
959 targetMin,
960 m_ctx.QuantMin,
961 m_ctx.QuantMax,
962 m_ctx.Quant,
963 m_par.quantOffset,
964 1,
965 false,
966 false);
967 mfxI32 quant_corrected = m_ctx.Quant;
968
969 if (quant_corrected < QuantNewMin - 3)
970 quant_corrected += 2;
971 if (quant_corrected < QuantNewMin)
972 quant_corrected++;
973 else if (quant_corrected > QuantNewMax + 3)
974 quant_corrected -= 2;
975 else if (quant_corrected > QuantNewMax)
976 quant_corrected--;
977
978 //printf(" QuantNewMin %d, QuantNewMax %d, m_ctx.Quant %d, new %d (%d)\n", QuantNewMin, QuantNewMax, m_ctx.Quant, quant_corrected, quant_new);
979
980 quant_new = mfx::clamp(quant_corrected, m_ctx.QuantMin, m_ctx.QuantMax);
981 }
982 if ((quant_new - m_ctx.Quant) * (quant_new - GetCurQP(picType, layer)) >
983 0) // this check is actual for async scheme
984 {
985 //printf(" Update QP %d: totalDeviation %f, bAbPreriod %f (%f), QP %d (%d %d), qp_new %d (qpY %d), type %d, dequant_new %f (%f) , m_ctx.fAbLong %f, m_par.inputBitsPerFrame %f (%f)\n",frame_par->EncodedOrder,totDev , bAbPreriod, GetAbPeriodCoeff(m_ctx.encOrder - m_ctx.LastIEncOrder, m_par.gopPicSize), m_ctx.Quant, m_ctx.QuantMin, m_ctx.QuantMax,quant_new, qpY, picType, 1.0/dequant_new, 1.0/m_ctx.dQuantAb, m_ctx.fAbLong, m_par.inputBitsPerFrame, m_par.inputBitsPerFrame/m_ctx.fAbLong);
986 UpdateQPParams(quant_new, picType, m_ctx, 0, m_ctx.QuantMin, m_ctx.QuantMax, layer);
987 }
988 }
989 m_ctx.bToRecode = 0;
990 if (m_par.HRDConformance != MFX_BRC_NO_HRD) {
991 m_hrdSpec->Update(bitsEncoded, frame_par->EncodedOrder, bIntra);
992 }
993 }
994 return sts;
995 }
996
GetFrameCtrl(mfxBRCFrameParam * par,mfxBRCFrameCtrl * ctrl)997 mfxStatus ExtBRC::GetFrameCtrl(mfxBRCFrameParam* par, mfxBRCFrameCtrl* ctrl) {
998 MFX_CHECK_NULL_PTR2(par, ctrl);
999 MFX_CHECK(m_bInit, MFX_ERR_NOT_INITIALIZED);
1000
1001 mfxI32 qp = 0;
1002 if (par->EncodedOrder == m_ctx.encOrder) {
1003 qp = m_ctx.Quant;
1004 }
1005 else {
1006 mfxU16 type = GetFrameType(par->FrameType, par->PyramidLayer, m_par.gopRefDist);
1007 qp = GetCurQP(type, par->PyramidLayer);
1008 }
1009 ctrl->QpY = qp - m_par.quantOffset;
1010 if (m_par.HRDConformance != MFX_BRC_NO_HRD) {
1011 ctrl->InitialCpbRemovalDelay = m_hrdSpec->GetInitCpbRemovalDelay(par->EncodedOrder);
1012 ctrl->InitialCpbRemovalOffset = m_hrdSpec->GetInitCpbRemovalDelayOffset(par->EncodedOrder);
1013 }
1014 if (m_par.mMBBRC) {
1015 if (ctrl->NumExtParam == 0) {
1016 //attach MBBRC buffer
1017 ctrl->NumExtParam = 1;
1018 ctrl->ExtParam = &(m_ExtBuff[par->EncodedOrder % m_ExtBuff.size()]);
1019 }
1020 mfxExtMBQP* pExtMBQP =
1021 (mfxExtMBQP*)Hevc_GetExtBuffer(ctrl->ExtParam, ctrl->NumExtParam, MFX_EXTBUFF_MBQP);
1022 if (pExtMBQP) {
1023 //fill QP map
1024 for (size_t i = 0; i < pExtMBQP->NumQPAlloc; i++) {
1025 pExtMBQP->QP[i] = (mfxU8)(qp + ((qp < 51) ? (i % 2) : 0));
1026 }
1027 }
1028 }
1029 return MFX_ERR_NONE;
1030 }
1031
Reset(mfxVideoParam * par)1032 mfxStatus ExtBRC::Reset(mfxVideoParam* par) {
1033 mfxStatus sts = MFX_ERR_NONE;
1034 MFX_CHECK_NULL_PTR1(par);
1035 MFX_CHECK(m_bInit, MFX_ERR_NOT_INITIALIZED);
1036
1037 mfxExtEncoderResetOption* pRO =
1038 (mfxExtEncoderResetOption*)Hevc_GetExtBuffer(par->ExtParam,
1039 par->NumExtParam,
1040 MFX_EXTBUFF_ENCODER_RESET_OPTION);
1041 if (pRO && pRO->StartNewSequence == MFX_CODINGOPTION_ON) {
1042 Close();
1043 sts = Init(par);
1044 }
1045 else {
1046 bool brcReset = false;
1047 bool slidingWindowReset = false;
1048
1049 sts = m_par.GetBRCResetType(par, false, brcReset, slidingWindowReset);
1050 MFX_CHECK_STS(sts);
1051
1052 if (brcReset) {
1053 sts = m_par.Init(par, isFieldMode(par));
1054 MFX_CHECK_STS(sts);
1055
1056 m_ctx.Quant = (mfxI32)(
1057 1. / m_ctx.dQuantAb * pow(m_ctx.fAbLong / m_par.inputBitsPerFrame, 0.32) + 0.5);
1058 m_ctx.Quant = mfx::clamp(m_ctx.Quant, m_par.quantMinI, m_par.quantMaxI);
1059
1060 UpdateQPParams(m_ctx.Quant,
1061 MFX_FRAMETYPE_I,
1062 m_ctx,
1063 0,
1064 m_par.quantMinI,
1065 m_par.quantMaxI,
1066 0);
1067
1068 m_ctx.dQuantAb = 1. / m_ctx.Quant;
1069 m_ctx.fAbLong = m_par.inputBitsPerFrame;
1070 m_ctx.fAbShort = m_par.inputBitsPerFrame;
1071
1072 if (slidingWindowReset) {
1073 m_avg.reset(
1074 new AVGBitrate(m_par.WinBRCSize,
1075 (mfxU32)(m_par.WinBRCMaxAvgKbps * 1000.0 / m_par.frameRate),
1076 (mfxU32)m_par.inputBitsPerFrame));
1077 MFX_CHECK_NULL_PTR1(m_avg.get());
1078 }
1079 }
1080 }
1081 return sts;
1082 }
1083
Init(cBRCParams & par)1084 void HEVC_HRD::Init(cBRCParams& par) {
1085 m_hrdInput.Init(par);
1086 m_prevAuCpbRemovalDelayMinus1 = -1;
1087 m_prevAuCpbRemovalDelayMsb = 0;
1088 m_prevAuFinalArrivalTime = 0;
1089 m_prevBpAuNominalRemovalTime = (mfxU32)m_hrdInput.m_initCpbRemovalDelay;
1090 m_prevBpEncOrder = 0;
1091 }
1092
Reset(cBRCParams & par)1093 void HEVC_HRD::Reset(cBRCParams& par) {
1094 sHrdInput hrdInput;
1095 hrdInput.Init(par);
1096 m_hrdInput.m_bitrate = hrdInput.m_bitrate;
1097 m_hrdInput.m_cpbSize90k = hrdInput.m_cpbSize90k;
1098 }
1099
Update(mfxU32 sizeInbits,mfxU32 eo,bool bSEI)1100 void HEVC_HRD::Update(mfxU32 sizeInbits, mfxU32 eo, bool bSEI) {
1101 mfxF64 auNominalRemovalTime = 0.0;
1102 mfxF64 initCpbRemovalDelay = GetInitCpbRemovalDelay(eo);
1103 if (eo > 0) {
1104 mfxU32 auCpbRemovalDelayMinus1 = (eo - m_prevBpEncOrder) - 1;
1105 // (D-1)
1106 mfxU32 auCpbRemovalDelayMsb = 0;
1107
1108 if (!bSEI && (eo - m_prevBpEncOrder) != 1) {
1109 auCpbRemovalDelayMsb =
1110 ((mfxI32)auCpbRemovalDelayMinus1 <= m_prevAuCpbRemovalDelayMinus1)
1111 ? m_prevAuCpbRemovalDelayMsb + m_hrdInput.m_maxCpbRemovalDelay
1112 : m_prevAuCpbRemovalDelayMsb;
1113 }
1114
1115 m_prevAuCpbRemovalDelayMsb = auCpbRemovalDelayMsb;
1116 m_prevAuCpbRemovalDelayMinus1 = auCpbRemovalDelayMinus1;
1117
1118 // (D-2)
1119 mfxU32 auCpbRemovalDelayValMinus1 = auCpbRemovalDelayMsb + auCpbRemovalDelayMinus1;
1120 // (C-10, C-11)
1121 auNominalRemovalTime = m_prevBpAuNominalRemovalTime +
1122 m_hrdInput.m_clockTick * (auCpbRemovalDelayValMinus1 + 1);
1123 }
1124 else // (C-9)
1125 auNominalRemovalTime = m_hrdInput.m_initCpbRemovalDelay;
1126
1127 // (C-3)
1128 mfxF64 initArrivalTime = m_prevAuFinalArrivalTime;
1129
1130 if (!m_hrdInput.m_cbrFlag) {
1131 mfxF64 initArrivalEarliestTime = (bSEI)
1132 // (C-7)
1133 ? auNominalRemovalTime - initCpbRemovalDelay
1134 // (C-6)
1135 : auNominalRemovalTime - m_hrdInput.m_cpbSize90k;
1136 // (C-4)
1137 initArrivalTime = std::max<mfxF64>(m_prevAuFinalArrivalTime,
1138 initArrivalEarliestTime * m_hrdInput.m_bitrate);
1139 }
1140 // (C-8)
1141 mfxF64 auFinalArrivalTime = initArrivalTime + (mfxF64)sizeInbits * 90000;
1142
1143 m_prevAuFinalArrivalTime = auFinalArrivalTime;
1144
1145 if (bSEI) {
1146 m_prevBpAuNominalRemovalTime = auNominalRemovalTime;
1147 m_prevBpEncOrder = eo;
1148 }
1149 }
1150
GetInitCpbRemovalDelay(mfxU32 eo) const1151 mfxU32 HEVC_HRD::GetInitCpbRemovalDelay(mfxU32 eo) const {
1152 mfxF64 auNominalRemovalTime;
1153
1154 if (eo > 0) {
1155 // (D-1)
1156 mfxU32 auCpbRemovalDelayMsb = 0;
1157 mfxU32 auCpbRemovalDelayMinus1 = eo - m_prevBpEncOrder - 1;
1158
1159 // (D-2)
1160 mfxU32 auCpbRemovalDelayValMinus1 = auCpbRemovalDelayMsb + auCpbRemovalDelayMinus1;
1161 // (C-10, C-11)
1162 auNominalRemovalTime = m_prevBpAuNominalRemovalTime +
1163 m_hrdInput.m_clockTick * (auCpbRemovalDelayValMinus1 + 1);
1164
1165 // (C-17)
1166 mfxF64 deltaTime90k =
1167 auNominalRemovalTime - m_prevAuFinalArrivalTime / m_hrdInput.m_bitrate;
1168
1169 return (m_hrdInput.m_cbrFlag
1170 // (C-19)
1171 ? (mfxU32)(deltaTime90k)
1172 // (C-18)
1173 : (mfxU32)std::min(deltaTime90k, m_hrdInput.m_cpbSize90k));
1174 }
1175
1176 return (mfxU32)m_hrdInput.m_initCpbRemovalDelay;
1177 }
1178
GetTargetDelay(mfxF64 cpbSize90k,mfxF64 initCpbRemovalDelay,bool bVBR)1179 inline mfxF64 GetTargetDelay(mfxF64 cpbSize90k, mfxF64 initCpbRemovalDelay, bool bVBR) {
1180 return bVBR ? std::max(std::min(3.0 * cpbSize90k / 4.0, initCpbRemovalDelay), cpbSize90k / 2.0)
1181 : std::min(cpbSize90k / 2.0, initCpbRemovalDelay);
1182 }
GetBufferDeviation(mfxU32 eo) const1183 mfxF64 HEVC_HRD::GetBufferDeviation(mfxU32 eo) const {
1184 mfxU32 delay = GetInitCpbRemovalDelay(eo);
1185 mfxF64 targetDelay = GetTargetDelay(m_hrdInput.m_cpbSize90k,
1186 m_hrdInput.m_initCpbRemovalDelay,
1187 !m_hrdInput.m_cbrFlag);
1188 return (targetDelay - delay) / 90000.0 * m_hrdInput.m_bitrate;
1189 }
1190
GetBufferDeviationFactor(mfxU32 eo) const1191 mfxF64 HEVC_HRD::GetBufferDeviationFactor(mfxU32 eo) const {
1192 mfxU32 delay = GetInitCpbRemovalDelay(eo);
1193 mfxF64 targetDelay = GetTargetDelay(m_hrdInput.m_cpbSize90k,
1194 m_hrdInput.m_initCpbRemovalDelay,
1195 !m_hrdInput.m_cbrFlag);
1196 return abs((targetDelay - delay) / targetDelay);
1197 }
1198
GetMaxFrameSizeInBits(mfxU32 eo,bool) const1199 mfxU32 HEVC_HRD::GetMaxFrameSizeInBits(mfxU32 eo, bool /*bSEI*/) const {
1200 return (mfxU32)(GetInitCpbRemovalDelay(eo) / 90000.0 * m_hrdInput.m_bitrate);
1201 }
1202
GetMinFrameSizeInBits(mfxU32 eo,bool) const1203 mfxU32 HEVC_HRD::GetMinFrameSizeInBits(mfxU32 eo, bool /*bSEI*/) const {
1204 mfxU32 delay = GetInitCpbRemovalDelay(eo);
1205 if ((!m_hrdInput.m_cbrFlag) ||
1206 ((delay + m_hrdInput.m_clockTick + 16.0) < m_hrdInput.m_cpbSize90k))
1207 return 0;
1208 return (mfxU32)((delay + m_hrdInput.m_clockTick + 16.0 - m_hrdInput.m_cpbSize90k) / 90000.0 *
1209 m_hrdInput.m_bitrate +
1210 0.99999);
1211 }
1212
H264_HRD()1213 H264_HRD::H264_HRD() : m_trn_cur(0), m_taf_prv(0) {}
1214
Init(cBRCParams & par)1215 void H264_HRD::Init(cBRCParams& par) {
1216 m_hrdInput.Init(par);
1217 m_hrdInput.m_clockTick *= (1.0 / 90000.0);
1218 m_taf_prv = 0.0;
1219 m_trn_cur = m_hrdInput.m_initCpbRemovalDelay / 90000.0;
1220 m_trn_cur = GetInitCpbRemovalDelay(0) / 90000.0;
1221 }
1222
Reset(cBRCParams & par)1223 void H264_HRD::Reset(cBRCParams& par) {
1224 sHrdInput hrdInput;
1225 hrdInput.Init(par);
1226 m_hrdInput.m_bitrate = hrdInput.m_bitrate;
1227 m_hrdInput.m_cpbSize90k = hrdInput.m_cpbSize90k;
1228 }
1229
Update(mfxU32 sizeInbits,mfxU32 eo,bool bSEI)1230 void H264_HRD::Update(mfxU32 sizeInbits, mfxU32 eo, bool bSEI) {
1231 //const bool interlace = false; //BRC is frame level only
1232 mfxU32 initDelay = GetInitCpbRemovalDelay(eo);
1233
1234 double tai_earliest =
1235 bSEI ? m_trn_cur - (initDelay / 90000.0) : m_trn_cur - (m_hrdInput.m_cpbSize90k / 90000.0);
1236
1237 double tai_cur = (!m_hrdInput.m_cbrFlag) ? std::max(m_taf_prv, tai_earliest) : m_taf_prv;
1238
1239 m_taf_prv = tai_cur + (mfxF64)sizeInbits / m_hrdInput.m_bitrate;
1240 m_trn_cur += m_hrdInput.m_clockTick;
1241 }
1242
GetInitCpbRemovalDelay(mfxU32) const1243 mfxU32 H264_HRD::GetInitCpbRemovalDelay(mfxU32 /* eo */) const {
1244 double delay = std::max(0.0, m_trn_cur - m_taf_prv);
1245 mfxU32 initialCpbRemovalDelay = mfxU32(90000 * delay + 0.5);
1246
1247 return (mfxU32)(initialCpbRemovalDelay == 0
1248 ? 1 // should not be equal to 0
1249 : initialCpbRemovalDelay > m_hrdInput.m_cpbSize90k &&
1250 (!m_hrdInput.m_cbrFlag)
1251 ? m_hrdInput.m_cpbSize90k // should not exceed hrd buffer
1252 : initialCpbRemovalDelay);
1253 }
GetBufferDeviation(mfxU32 eo) const1254 mfxF64 H264_HRD::GetBufferDeviation(mfxU32 eo) const {
1255 mfxU32 delay = GetInitCpbRemovalDelay(eo);
1256 mfxF64 targetDelay = GetTargetDelay(m_hrdInput.m_cpbSize90k,
1257 m_hrdInput.m_initCpbRemovalDelay,
1258 !m_hrdInput.m_cbrFlag);
1259 return (targetDelay - delay) / 90000.0 * m_hrdInput.m_bitrate;
1260 }
GetBufferDeviationFactor(mfxU32 eo) const1261 mfxF64 H264_HRD::GetBufferDeviationFactor(mfxU32 eo) const {
1262 mfxU32 delay = GetInitCpbRemovalDelay(eo);
1263 mfxF64 targetDelay = GetTargetDelay(m_hrdInput.m_cpbSize90k,
1264 m_hrdInput.m_initCpbRemovalDelay,
1265 !m_hrdInput.m_cbrFlag);
1266 return abs((targetDelay - delay) / targetDelay);
1267 }
1268
GetInitCpbRemovalDelayOffset(mfxU32 eo) const1269 mfxU32 H264_HRD::GetInitCpbRemovalDelayOffset(mfxU32 eo) const {
1270 // init_cpb_removal_delay + init_cpb_removal_delay_offset should be constant
1271 return mfxU32(m_hrdInput.m_cpbSize90k - GetInitCpbRemovalDelay(eo));
1272 }
GetMinFrameSizeInBits(mfxU32 eo,bool) const1273 mfxU32 H264_HRD::GetMinFrameSizeInBits(mfxU32 eo, bool /*bSEI*/) const {
1274 mfxU32 delay = GetInitCpbRemovalDelay(eo);
1275 if ((!m_hrdInput.m_cbrFlag) ||
1276 ((delay + m_hrdInput.m_clockTick * 90000) < m_hrdInput.m_cpbSize90k))
1277 return 0;
1278
1279 return (mfxU32)((delay + m_hrdInput.m_clockTick * 90000.0 - m_hrdInput.m_cpbSize90k) / 90000.0 *
1280 m_hrdInput.m_bitrate) +
1281 16;
1282 }
GetMaxFrameSizeInBits(mfxU32 eo,bool bSEI) const1283 mfxU32 H264_HRD::GetMaxFrameSizeInBits(mfxU32 eo, bool bSEI) const {
1284 mfxU32 initDelay = GetInitCpbRemovalDelay(eo);
1285
1286 double tai_earliest = (bSEI) ? m_trn_cur - (initDelay / 90000.0)
1287 : m_trn_cur - (m_hrdInput.m_cpbSize90k / 90000.0);
1288
1289 double tai_cur = (!m_hrdInput.m_cbrFlag) ? std::max(m_taf_prv, tai_earliest) : m_taf_prv;
1290
1291 mfxU32 maxFrameSize = (mfxU32)((m_trn_cur - tai_cur) * m_hrdInput.m_bitrate);
1292
1293 return maxFrameSize;
1294 }
Init(cBRCParams par)1295 void sHrdInput::Init(cBRCParams par) {
1296 m_cbrFlag = (par.rateControlMethod == MFX_RATECONTROL_CBR);
1297 m_bitrate = par.maxbps;
1298 m_maxCpbRemovalDelay = 1 << (h264_h265_au_cpb_removal_delay_length_minus1 + 1);
1299 m_clockTick = 90000. / par.frameRate;
1300 m_cpbSize90k = mfxU32(90000. * par.bufferSizeInBytes * 8.0 / m_bitrate);
1301 m_initCpbRemovalDelay = 90000. * 8. * par.initialDelayInBytes / m_bitrate;
1302 }
1303