You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
316 lines
14 KiB
316 lines
14 KiB
/* *************************************************************************
|
|
** INTEL Corporation Proprietary Information
|
|
**
|
|
** This listing is supplied under the terms of a license
|
|
** agreement with INTEL Corporation and may not be copied
|
|
** nor disclosed except in accordance with the terms of
|
|
** that agreement.
|
|
**
|
|
** Copyright (c) 1995 Intel Corporation.
|
|
** All Rights Reserved.
|
|
**
|
|
** *************************************************************************
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
* exbrc.cpp
|
|
*
|
|
* Description:
|
|
* Bit rate control routines for H.261 and H.263. The bit rate is controlled
|
|
* by changing QUANT value at the GOB level (H.261) or picture and GOB level
|
|
* (H.26X). InitBRC() must be called at the time encoder is instanced; it
|
|
* initializes some data values in BRCState structure. CalcPQUANT() computes the new
|
|
* quant. value at the picture level; it must always be called.
|
|
* CalcMBQUANT computes the new quant. value at the MB level; it need not be
|
|
* called if quant. adjustment is done at the picture level.
|
|
*
|
|
*
|
|
* Routines:
|
|
* InitBRC
|
|
* CalcPQUANT
|
|
* CalcMBQUANT
|
|
* Prototypes in:
|
|
* e3enc.h
|
|
* Note
|
|
* Encoder must update BRCState->uLastINTRAFrmSz, BRCState->uLastINTERFrmSz, and
|
|
* BRCState->uTargetFrmSize.
|
|
*/
|
|
|
|
/*
|
|
* $Header: S:\h26x\src\enc\exbrc.cpv 1.15 31 Oct 1996 14:59:26 MBODART $
|
|
* $Log: S:\h26x\src\enc\exbrc.cpv $
|
|
//
|
|
// Rev 1.15 31 Oct 1996 14:59:26 MBODART
|
|
// Prevent recent changes from inadvertantly affecting H.261.
|
|
//
|
|
// Rev 1.14 31 Oct 1996 10:05:38 KLILLEVO
|
|
// changed from DBOUT to DbgLog
|
|
//
|
|
//
|
|
// Rev 1.13 29 Aug 1996 09:31:54 CZHU
|
|
// Map intra-coded GOB to simpliar quality of inter-coded neighbours
|
|
//
|
|
// Rev 1.12 14 Aug 1996 16:46:22 CZHU
|
|
// Adjust QP for intra frames other than the first Key frames.
|
|
//
|
|
// Rev 1.11 12 Mar 1996 13:26:54 KLILLEVO
|
|
// new rate control with adaptive bit usage profile
|
|
//
|
|
// Rev 1.10 05 Feb 1996 17:15:12 TRGARDOS
|
|
// Added code to do custom quantizer selection for
|
|
// still frames
|
|
//
|
|
// Rev 1.9 01 Dec 1995 15:27:06 DBRUCKS
|
|
// I removed the QP_mean affects to the global_adj value.
|
|
// This resulted in removing any affect of the target frame rate on
|
|
// the global adj value.
|
|
//
|
|
// Rev 1.8 28 Nov 1995 15:01:04 TRGARDOS
|
|
// Initialized target frame rate in BRCinit.
|
|
//
|
|
// Rev 1.7 27 Nov 1995 19:26:00 TRGARDOS
|
|
// Cleaned up bit rate control functions to be generic h26x bit rate
|
|
// controller. Based off of macro blocks instead of GOBS now.
|
|
//
|
|
// Rev 1.6 26 Oct 1995 19:50:54 TRGARDOS
|
|
// Fixed a small mistake in the global adjust calculation
|
|
// and changed frame rate to a parameter.
|
|
//
|
|
// Rev 1.5 25 Oct 1995 23:22:36 SINGX
|
|
// Changed BRC back to we just get frame rate from client
|
|
// and compute global adjust ourselves.
|
|
//
|
|
// Rev 1.4 25 Oct 1995 20:14:40 TRGARDOS
|
|
// Added code to use global adjustment passed from client.
|
|
//
|
|
// Rev 1.3 12 Oct 1995 12:04:42 TRGARDOS
|
|
// Added QP_mean initialization in initBRC and added clipping
|
|
// to all calculations of the new QP.
|
|
//
|
|
// Rev 1.2 11 Oct 1995 19:35:00 TRGARDOS
|
|
// Modified bit rate controller.
|
|
//
|
|
// Rev 1.1 09 Oct 1995 11:48:10 TRGARDOS
|
|
// Added float typecasting.
|
|
//
|
|
// Rev 1.0 06 Oct 1995 16:41:22 AGUPTA2
|
|
// Initial revision.
|
|
*/
|
|
|
|
// PhilF-: In the LAN case and QCIF mode, it looks like even with the smallest quantizer
|
|
// we are way below the max allowed at 30fps. Therefore, with little motion,
|
|
// the bitrate looks constant at a low bitrate value. When high motion comes in,
|
|
// even with the same small quantizer we will remain below the max. So we will
|
|
// use that small quantizer, and the size of those compressed frames will get bigger
|
|
// because of the higher motion -> this explains why we don't have a straight
|
|
// line in the LAN case when looking at StatView...
|
|
|
|
#include "precomp.h"
|
|
|
|
U8 clampQP(int iUnclampedQP)
|
|
{
|
|
return ((iUnclampedQP < 2) ? 2 : (iUnclampedQP > 31) ? 31 : iUnclampedQP);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* InitBRC
|
|
* Parameter:
|
|
* BRCState: T_H263EncoderCatalog ptr
|
|
* Initializes some some variables in the encoder catalog.
|
|
* Note
|
|
* Must be called when the encoder is instanced.
|
|
*/
|
|
void InitBRC(BRCStateStruct *BRCState, U8 DefIntraQP, U8 DefInterQP, int numMBs)
|
|
{
|
|
FX_ENTRY("InitBRC");
|
|
|
|
BRCState->NumMBs = numMBs;
|
|
BRCState->u8INTRA_QP = DefIntraQP;
|
|
BRCState->u8INTER_QP = DefInterQP;
|
|
BRCState->uLastINTRAFrmSz = 0;
|
|
BRCState->uLastINTERFrmSz = 0;
|
|
BRCState->QP_mean = DefIntraQP;
|
|
BRCState->TargetFrameRate = (float) 0.0;
|
|
BRCState->u8StillQnt = 0;
|
|
|
|
DEBUGMSG(ZONE_BITRATE_CONTROL, ("%s: Bitrate controller initial state:\r\n numMBs = %ld macroblocks\r\n u8INTRA_QP = %ld\r\n u8INTER_QP = %ld\r\n", _fx_, BRCState->NumMBs, BRCState->u8INTRA_QP, BRCState->u8INTER_QP));
|
|
DEBUGMSG(ZONE_BITRATE_CONTROL, (" uLastINTRAFrmSz = %ld bytes\r\n uLastINTERFrmSz = %ld bytes\r\n QP_mean = %ld\r\n TargetFrameRate = %ld.%ld fps\r\n", BRCState->uLastINTRAFrmSz, BRCState->uLastINTERFrmSz, BRCState->QP_mean, (DWORD)BRCState->TargetFrameRate, (DWORD)((BRCState->TargetFrameRate - (float)(DWORD)BRCState->TargetFrameRate) * 10.0f)));
|
|
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* @doc INTERNAL H263FUNC
|
|
*
|
|
* @func U8 | CalcPQUANT | This function computes the PQUANT value to
|
|
* use for the current frame. This is done by using the target frame size
|
|
* and the results achieved with the previous frame.
|
|
*
|
|
* @parm BRCStateStruct * | BRCState | Specifies a pointer to the current
|
|
* state of the bitrate controller.
|
|
*
|
|
* @parm EnumPicCodType | PicCodType | Specifies the type of the current
|
|
* frame. If set to INTRAPIC, then the current frame is an I-frame. It
|
|
* set to INTERPIC, then it is a P-frame or a PB-frame.
|
|
*
|
|
* @rdesc The PQUANT value.
|
|
*
|
|
* @comm H.261 does not have PQUANT. So, H261 encoder can call this routine
|
|
* once and use the value returned as GQUANT for all GOBs. Or, it can
|
|
* call CalcMBQUANT for all GOBs.
|
|
*
|
|
* This routine MUST be called for every frame for which QUANT adjustment
|
|
* is required. CalcMBQUANT() might not be called.
|
|
*
|
|
* @xref <f FindNewQuant> <f CalcMBQUANT>
|
|
***************************************************************************/
|
|
U8 CalcPQUANT(BRCStateStruct *BRCState, EnumPicCodType PicCodType)
|
|
{
|
|
FX_ENTRY("CalcPQUANT");
|
|
|
|
if (PicCodType == INTERPIC)
|
|
{
|
|
if (BRCState->uLastINTERFrmSz != 0)
|
|
{
|
|
// Calculate the global adjustment parameter
|
|
// Use the average QP for the last P-frame as the starting point
|
|
// The quantizer increases faster than it decreases
|
|
if (BRCState->uLastINTERFrmSz > BRCState->uTargetFrmSize)
|
|
{
|
|
BRCState->Global_Adj = ((float)((int)BRCState->uLastINTERFrmSz - (int)BRCState->uTargetFrmSize)) / (float)BRCState->uTargetFrmSize;
|
|
|
|
DEBUGMSG(ZONE_BITRATE_CONTROL, ("%s: New u8INTER_QP = %ld, Global_Adj = +%ld.%ld (based on uLastINTERFrmSz = %ld bits, uTargetFrmSize = %ld bits, QP_mean = %ld)\r\n", _fx_, clampQP((int)(BRCState->QP_mean * (1 + BRCState->Global_Adj) + (float)0.5)), (DWORD)BRCState->Global_Adj, (DWORD)((BRCState->Global_Adj - (float)(DWORD)BRCState->Global_Adj) * 100.0f), (DWORD)BRCState->uLastINTERFrmSz << 3, (DWORD)BRCState->uTargetFrmSize << 3, (DWORD)BRCState->QP_mean));
|
|
}
|
|
else
|
|
{
|
|
BRCState->Global_Adj = ((float)((int)BRCState->uLastINTERFrmSz - (int)BRCState->uTargetFrmSize)) / ((float) 2.0 * BRCState->uTargetFrmSize);
|
|
|
|
DEBUGMSG(ZONE_BITRATE_CONTROL, ("%s: New u8INTER_QP = %ld, Global_Adj = -%ld.%ld (based on uLastINTERFrmSz = %ld bits, uTargetFrmSize = %ld bits, QP_mean = %ld)\r\n", _fx_,clampQP((int)(BRCState->QP_mean * (1 + BRCState->Global_Adj) + (float)0.5)), (DWORD)(BRCState->Global_Adj * -1.0f), (DWORD)((BRCState->Global_Adj - (float)(DWORD)(BRCState->Global_Adj * -1.0f)) * -100.0f), (DWORD)BRCState->uLastINTERFrmSz << 3, (DWORD)BRCState->uTargetFrmSize << 3, (DWORD)BRCState->QP_mean));
|
|
}
|
|
|
|
BRCState->u8INTER_QP = clampQP((int)(BRCState->QP_mean * (1 + BRCState->Global_Adj) + (float)0.5));
|
|
}
|
|
else
|
|
{
|
|
// This the first P-frame - use default value
|
|
BRCState->u8INTER_QP = clampQP((unsigned char) BRCState->QP_mean);
|
|
BRCState->Global_Adj = (float)0.0;
|
|
|
|
DEBUGMSG(ZONE_BITRATE_CONTROL, ("%s: First u8INTER_QP = %ld\r\n", _fx_, BRCState->u8INTER_QP));
|
|
}
|
|
|
|
return BRCState->u8INTER_QP;
|
|
}
|
|
else if (PicCodType == INTRAPIC)
|
|
{
|
|
if (BRCState->uLastINTRAFrmSz != 0)
|
|
{
|
|
// Calculate the global adjustment parameter
|
|
// Use the average QP for the last I-frame as the starting point
|
|
// Assume lighting & other conditions haven't changed too much since last I-frame
|
|
// The quantizer increases faster than it decreases
|
|
if (BRCState->uLastINTRAFrmSz > BRCState->uTargetFrmSize)
|
|
{
|
|
BRCState->Global_Adj = ((float) ((int)BRCState->uLastINTRAFrmSz - (int)BRCState->uTargetFrmSize) ) / ((float)BRCState->uTargetFrmSize);
|
|
|
|
DEBUGMSG(ZONE_BITRATE_CONTROL, ("%s: New u8INTRA_QP = %ld, Global_Adj = +%ld.%ld (based on uLastINTRAFrmSz = %ld bits, uTargetFrmSize = %ld bits)\r\n", _fx_, clampQP((int)(BRCState->u8INTRA_QP * (1 + BRCState->Global_Adj) + (float)0.5)), (DWORD)BRCState->Global_Adj, (DWORD)((BRCState->Global_Adj - (float)(DWORD)BRCState->Global_Adj) * 100.0f), (DWORD)BRCState->uLastINTRAFrmSz << 3, (DWORD)BRCState->uTargetFrmSize << 3));
|
|
}
|
|
else
|
|
{
|
|
// This the first I-frame - use default value
|
|
BRCState->Global_Adj = ((float) ((int)BRCState->uLastINTRAFrmSz - (int)BRCState->uTargetFrmSize) ) / ((float) 2.0 * BRCState->uTargetFrmSize);
|
|
|
|
DEBUGMSG(ZONE_BITRATE_CONTROL, ("%s: New u8INTRA_QP = %ld, Global_Adj = -%ld.%ld (based on uLastINTRAFrmSz = %ld bits, uTargetFrmSize = %ld bits)\r\n", _fx_, clampQP((int)(BRCState->u8INTRA_QP * (1 + BRCState->Global_Adj) + (float)0.5)), (DWORD)(BRCState->Global_Adj * -1.0f), (DWORD)((BRCState->Global_Adj - (float)(DWORD)(BRCState->Global_Adj * -1.0f)) * -100.0f), (DWORD)BRCState->uLastINTRAFrmSz << 3, (DWORD)BRCState->uTargetFrmSize << 3));
|
|
}
|
|
|
|
BRCState->u8INTRA_QP = clampQP((int)(BRCState->u8INTRA_QP * (1 + BRCState->Global_Adj) + (float)0.5));
|
|
}
|
|
else
|
|
{
|
|
DEBUGMSG(ZONE_BITRATE_CONTROL, ("%s: First u8INTRA_QP = %ld\r\n", _fx_, clampQP(BRCState->u8INTRA_QP)));
|
|
}
|
|
|
|
return clampQP(BRCState->u8INTRA_QP);
|
|
}
|
|
else
|
|
{
|
|
DBOUT("ERROR:BRC unknown frame type");
|
|
return clampQP(BRCState->u8INTRA_QP); // return any valid value
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* @doc INTERNAL H263FUNC
|
|
*
|
|
* @func U8 | CalcMBQUANT | This function computes the GQUANT value to
|
|
* use for the current GOB. This is done by using the target frame size and
|
|
* the running average of the GQUANTs computed for the previous GOBs in
|
|
* the current frame.
|
|
*
|
|
* @parm BRCStateStruct * | BRCState | Specifies a pointer to the current
|
|
* state of the bitrate controller.
|
|
*
|
|
* @parm U32 | uCumPrevFrmSize | Specifies the cumulated size of the previous
|
|
* GOBs in the previous frame.
|
|
*
|
|
* @parm U32 | uPrevFrmSize | Specifies the total size of the previous
|
|
* frame.
|
|
*
|
|
* @parm U32 | uCumFrmSize | Specifies the cumulated size of the previous
|
|
* GOBs.
|
|
*
|
|
* @parm EnumPicCodType | PicCodType | Specifies the type of the current
|
|
* frame. If set to INTRAPIC, then the current frame is an I-frame. It
|
|
* set to INTERPIC, then it is a P-frame or a PB-frame.
|
|
*
|
|
* @rdesc The GQUANT value.
|
|
*
|
|
* @xref <f FindNewQuant> <f CalcPQUANT>
|
|
***************************************************************************/
|
|
U8 CalcMBQUANT(BRCStateStruct *BRCState, U32 uCumPrevFrmSize, U32 uPrevFrmSize, U32 uCumFrmSize, EnumPicCodType PicCodType)
|
|
{
|
|
FX_ENTRY("CalcMBQUANT");
|
|
|
|
float Local_Adj;
|
|
int TargetCumSize;
|
|
|
|
if (PicCodType == INTERPIC)
|
|
{
|
|
// Calculate the local adjustment parameter by looking at how well we've
|
|
// been doing so far with the previous GOBs
|
|
TargetCumSize = (int)uCumPrevFrmSize * BRCState->uTargetFrmSize / uPrevFrmSize;
|
|
|
|
// If this is the first GOB there's no local adjustment to compute
|
|
Local_Adj = TargetCumSize ? (float)((int)uCumFrmSize - TargetCumSize) / (float)TargetCumSize : 0.0f;
|
|
|
|
BRCState->u8INTER_QP = clampQP((int)(BRCState->QP_mean * (1 + BRCState->Global_Adj + Local_Adj) + (float)0.5));
|
|
|
|
#ifdef _DEBUG
|
|
if (Local_Adj >= 0L)
|
|
{
|
|
DEBUGMSG(ZONE_BITRATE_CONTROL_DETAILS, (" %s: New u8INTER_QP = %ld, Local_Adj = +%ld.%ld (based on uLastINTERFrmSz = %ld bits, uTargetFrmSize = %ld bits, uCumPrevFrmSize = %ld, uPrevFrmSize = %ld, QP_mean = %ld)\r\n", _fx_, BRCState->u8INTER_QP, (DWORD)Local_Adj, (DWORD)((Local_Adj - (float)(DWORD)Local_Adj) * 100.0f), (DWORD)BRCState->uLastINTERFrmSz << 3, (DWORD)BRCState->uTargetFrmSize << 3, uCumPrevFrmSize, uPrevFrmSize, (DWORD)BRCState->QP_mean));
|
|
}
|
|
else
|
|
{
|
|
DEBUGMSG(ZONE_BITRATE_CONTROL_DETAILS, (" %s: New u8INTER_QP = %ld, Local_Adj = -%ld.%ld (based on uLastINTERFrmSz = %ld bits, uTargetFrmSize = %ld bits, uCumPrevFrmSize = %ld, uPrevFrmSize = %ld, QP_mean = %ld)\r\n", _fx_, BRCState->u8INTER_QP, (DWORD)(Local_Adj * -1.0f), (DWORD)((Local_Adj - (float)(DWORD)(Local_Adj * -1.0f)) * -100.0f), (DWORD)BRCState->uLastINTERFrmSz << 3, (DWORD)BRCState->uTargetFrmSize << 3, uCumPrevFrmSize, uPrevFrmSize, (DWORD)BRCState->QP_mean));
|
|
}
|
|
#endif
|
|
|
|
return BRCState->u8INTER_QP;
|
|
}
|
|
else if (PicCodType == INTRAPIC)
|
|
{
|
|
// The previous I-frame is so old that there isn't much point in doing local
|
|
// adjustments - so only consider the global changes
|
|
DEBUGMSG(ZONE_BITRATE_CONTROL_DETAILS, (" %s: New u8INTRA_QP = %ld\r\n", _fx_, BRCState->u8INTRA_QP));
|
|
|
|
return BRCState->u8INTRA_QP;
|
|
}
|
|
else
|
|
{
|
|
DBOUT("ERROR:BRC unknown frame type");
|
|
return BRCState->u8INTRA_QP; // return some valid value
|
|
}
|
|
}
|