/*============================================================================*
* rate.c *
* *
* Procedures concerned with rate control *
* *
* EXPORTED PROCEDURES: *
* initRatecontrol() *
* targetRateControl() *
* updateRateControl() *
* MB_RateOut() *
* needQScaleChange() *
* incNumBlocks() *
* incQuant() *
* incMacroBlockBits() *
* setPictureRate() *
* setBitRate() *
* getBitRate() *
* setBufferSize() *
* getBufferSize() *
* *
* NOTES: *
* Naming conventions follow those of MPEG-2 draft algorithm (chap. 10) *
*============================================================================*/
/*
* Copyright (c) 1995 The Regents of the University of California.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose, without fee, and without written agreement is
* hereby granted, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
* CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
/*==============*
* HEADER FILES *
*==============*/
#include <sys/times.h>
#include "all.h"
#include "mtypes.h"
#include "bitio.h"
#include "frames.h"
#include "prototypes.h"
#include "param.h"
#include "mheaders.h"
#include "fsize.h"
#include "postdct.h"
#include "mpeg.h"
#include "parallel.h"
#include "dct.h"
#include "rate.h"
/*==================*
* GLOBAL VARIABLES *
*==================*/
#define MAX_BIT_RATE 104857600 /* 18 digit number in units of 400 */
#define MAX_BUFFER_SIZE 16760832 /* 10 digit number in units of 16k */
#define DEFAULT_BUFFER_SIZE 327680 /* maximun for "constrained" bitstream */
#define DEFAULT_VBV_FULLNESS 3 /* wait till 1/3 full */
#define DEFAULT_PICT_RATE_CODE 5 /* code for 30 Frames/sec */
#define DEFAULT_PICT_RATE 30 /* 30 frames per second */
#define MAX_VBV_DELAY 32768 /* 16 digits */
/* Variables from Parameter File */
static int RateControlMode = VARIABLE_RATE;
static int32 buffer_size = DEFAULT_BUFFER_SIZE;
static int32 bit_rate = -1;
/* Variables for the VBV buffer defined in MPEG specs */
static int32 VBV_delay =0; /* delay in units of 1/90000 seconds */
static int32 VBV_buffer = 0; /* fullness of the theoretical VBV buffer */
static int32 bufferFillRate = 0; /* constant rate at which buffer filled */
static int32 frameDelayIncrement = 0; /* number of "delay" units/Frame */
/* Global complexity measure variables */
static int Xi, Xp, Xb; /* Global complexity measure */
static int Si, Sp, Sb; /* Total # bits for last pict of type (Overhead?) */
static float Qi, Qp, Qb; /* avg quantizaton for last picture of type */
/* Target bit allocations for each type of picture*/
int Ti, Tp, Tb;
int current_Tx; /* allocation for current frame */
/* Count of number of pictures of each type remaining */
int GOP_X = 0;
int GOP_I = 0;
int GOP_P = 0;
int GOP_B = 0;
int Nx = 0;
int Ni = 0;
int Np = 0;
int Nb = 0;
/* Counters used while encoding frames */
int rc_numBlocks = 0;
int rc_totalQuant = 0;
int rc_bitsThisMB;
int rc_totalMBBits;
int rc_totalFrameBits;
int rc_totalOverheadBits = 0;
/* Want to print out Macroblock info every Nth MB */
int RC_MB_SAMPLE_RATE = 0;
static float Ki = .7;
static float Kp = 1;
static float Kb = 1.4;
static int rc_R;
static int rc_G;
/* Rate Control variables */
/* Virtual buffers for each frame type */
static int d0_i; /* Initial fullnesses */
static int d0_p;
static int d0_b;
static int lastFrameVirtBuf; /* fullness after last frame of this type */
static int currentVirtBuf; /* fullness during current encoding*/
static int MB_cnt = -1; /* Number of MB's in picture */
static int rc_Q; /* reference quantization parameter */
static int reactionParameter; /* Reaction parameter */
/* Adaptive Quantization variables */
static int act_j; /* spatial activity measure */
static float N_act; /* Normalised spacial activity */
static int avg_act; /* average activity value in last picture encoded */
static int total_act_j; /* Sum of activity values in current frame */
static int var_sblk; /* sub-block activity */
static int P_mean; /* Mean value of pixels in 8x8 sub-block */
static int mquant; /* Raw Quantization value */
static int Qscale; /* Clipped, truncated quantization value */
/* Output-related variables */
#ifdef RC_STATS_FILE
static FILE *RC_FILE;
#endif
static char *Frame_header1 = " Fm # Bit GOP V ";
static char *Frame_header2 = " # type MBs Alloc left Ni Np Nb N_act buff Q_rc Qscale";
static char *Frame_header3 = "---- - ---- ------ ------- -- -- -- ----- ------ ---- ----";
static char *Frame_trailer1 = " avg virt % GOP % VBV";
static char *Frame_trailer2 = " Sx Qx Xx act N_act buffer alloc left left buf delay";
static char *Frame_trailer3 = "------ --.-- ------- --- --.-- ------- --- ------- --- ------- ------";
static char *MB_header1 = "MB# #bits Q mqt Dj Q_j actj N_act totbits b/MB %alloc %done";
static char *MB_header2 = "--- ----- -- --- ------ --- ----- --.-- ------ ---- --- ---";
static char rc_buffer[101];
/* EXTERNAL Variables */
extern char *framePattern;
extern int framePatternLen;
/*===============================*
* INTERNAL PROCEDURE prototypes *
*===============================*/
int initGOPRateControl _ANSI_ARGS_((void));
int determineMBCount _ANSI_ARGS_((void));
void checkBufferFullness _ANSI_ARGS_((int count));
void checkSpatialActivity _ANSI_ARGS_((Block blk0, Block blk1, Block blk2, Block blk3));
void incNumBlocks _ANSI_ARGS_((int num));
void calculateVBVDelay _ANSI_ARGS_((int num));
void updateVBVBuffer _ANSI_ARGS_((int frameBits));
int BlockExperiments _ANSI_ARGS_((int16 *OrigBlock, int16 *NewBlock, int control));
/*=====================*
* EXPORTED PROCEDURES *
*=====================*/
/*===========================================================================*
*
* initRateControl
*
* initialize the allocation parameters.
*
* RETURNS: nothing
*
* SIDE EFFECTS: many global variables
*
* NOTES: Get rid of the redundant pattern stuff!!
*===========================================================================*/
int
initRateControl()
{
int index;
int result;
DBG_PRINT(("\tInitializing Allocation Data\n"));
#ifdef RC_STATS_FILE
RC_FILE = fopen("RC_STATS_FILE", "w");
if ( RC_FILE == NULL) {
DBG_PRINT(("\tOpen of RC file failed, using stderr\n"));
RC_FILE = stderr;
fprintf(RC_FILE, "\tOpen of RC file failed, using stderr\n");
fflush(RC_FILE);
}
#endif
/* Initialize Pattern info */
GOP_X = framePatternLen;
for ( index = 0; index < framePatternLen; index++ ) {
switch( framePattern[index] ) {
case 'i':
GOP_I++;
break;
case 'p':
GOP_P++;
break;
case 'b':
GOP_B++;
break;
default:
printf("\n\tERROR rate.c - BAD PATTERN!\n");
RateControlMode = VARIABLE_RATE;
return (0);
}
}
if (GOP_X != (GOP_I + GOP_P + GOP_B )) {
printf("\n\tERROR rate.c - Pattern Length Mismatch\n");
RateControlMode = VARIABLE_RATE;
return (-1);
}
/* Initializing GOP bit allocation */
rc_R = 0;
rc_G = (bit_rate * GOP_X/frameRateRounded);
/* Initialize the "global complexity measures" */
Xi = (160 * bit_rate/115);
Xp = (60 * bit_rate/115);
Xb = (42 * bit_rate/115);
/* Initialize MB counters */
rc_totalMBBits= rc_bitsThisMB= rc_totalFrameBits=rc_totalOverheadBits = 0;
rc_numBlocks = rc_totalQuant = 0;
/* init virtual buffers */
reactionParameter = (2 * bit_rate / frameRateRounded);
d0_i = (10 * reactionParameter / 31);
d0_p = (Kp * d0_i);
d0_b = (Kb * d0_i);
lastFrameVirtBuf = d0_i; /* start with I Frame */
rc_Q = lastFrameVirtBuf * 31 / reactionParameter;
/* init spatial activity measures */
avg_act = 400; /* Suggested initial value */
N_act = 1;
mquant = rc_Q * N_act;
frameDelayIncrement = (90000 / frameRateRounded); /* num of "delay" units per frame */
bufferFillRate = bit_rate / frameRateRounded; /* VBV buf fills at constant rate */
VBV_buffer = buffer_size;
DBG_PRINT(("\tVBV- delay: %d, fill rate: %d, delay/Frame: %d units, buffer size: %d\n",
VBV_delay, bufferFillRate, frameDelayIncrement, buffer_size));
result = initGOPRateControl();
return result;
}
/*===========================================================================*
*
* initGOPRateControl
*
* (re)-initialize the RC for the a new Group of Pictures.
* New bit allocation, but carry over complexity measures.
*
* RETURNS: nothing
*
* SIDE EFFECTS: many global variables
*
*===========================================================================*/
int
initGOPRateControl()
{
DBG_PRINT(("\tInitializing new GOP\n"));
Nx = GOP_X;
Ni = GOP_I;
Np = GOP_P;
Nb = GOP_B;
rc_R += rc_G;
DBG_PRINT(("\tbufsize: %d, bitrate: %d, pictrate: %d, GOP bits: %d\n",
buffer_size, bit_rate, frameRateRounded, rc_R));
DBG_PRINT(("\tXi: %d, Xp: %d, Xb: %d Nx: %d, Ni: %d, Np: %d, Nb: %d\n",
Xi, Xp, Xb, Nx,Ni,Np,Nb));
DBG_PRINT(("\td0_i: %d, d0_p: %d, d0_b: %d, avg_act: %d, rc_Q: %d, mquant: %d\n",
d0_i, d0_p, d0_b, avg_act, rc_Q, mquant));
return 1;
}
/*===========================================================================*
*
* targetRateControl
*
* Determine the target allocation for given picture type, initiates
* variables for rate control process.
*
* RETURNS: nothing.
*
* SIDE EFFECTS: many global variables
*
*===========================================================================*/
void
targetRateControl(frame)
MpegFrame *frame;
{
float temp1, minimumBits;
float tempX, tempY, tempZ;
int result;
int frameType;
char *strPtr;
minimumBits = (bit_rate / (8 * frameRateRounded));
/* Check if new GOP */
if (Nx == 0) {
initGOPRateControl();
}
if (MB_cnt < 0) {MB_cnt = determineMBCount();}
switch (frame->type) {
case TYPE_IFRAME:
frameType = 'I';
/* temp1 = ( rc_R / ( 1+ ((Np * Xp) / (Xi * Kp)) + ((Nb*Xb) / (Xi*Kb))))); */
tempX = ( (Np * Ki * Xp) / (Xi * Kp) );
tempY = ( (Nb * Ki * Xb) / (Xi*Kb) );
tempZ = Ni + tempX + tempY;
temp1 = (rc_R / tempZ);
result = (int) (temp1 > minimumBits ? temp1 : minimumBits);
current_Tx = Ti = result;
lastFrameVirtBuf = d0_i;
break;
case TYPE_PFRAME:
frameType = 'P';
tempX = ( (Ni * Kp * Xi) / (Ki * Xp) );
tempY = ( (Nb * Kp * Xb) / (Kb * Xp) );
tempZ = Np + tempX + tempY;
temp1 = (rc_R/ tempZ);
result = (int) (temp1 > minimumBits ? temp1 : minimumBits);
current_Tx = Tp = result;
lastFrameVirtBuf = d0_p;
break;
case TYPE_BFRAME:
frameType = 'B';
tempX = ( (Ni * Kb * Xi) / (Ki * Xb) );
tempY = ( (Np * Kb * Xp) / (Kp * Xb) );
tempZ = Nb + tempX + tempY;
temp1 = (rc_R/ tempZ);
result = (int) (temp1 > minimumBits ? temp1 : minimumBits);
current_Tx = Tb = result;
lastFrameVirtBuf = d0_b;
break;
default:
frameType = 'X';
}
N_act = 1;
rc_Q = lastFrameVirtBuf * 31 / reactionParameter;
mquant = rc_Q * N_act;
Qscale = (mquant > 31 ? 31 : mquant);
Qscale = (Qscale < 1 ? 1 : Qscale);
/* Print headers for Frame info */
strPtr = Frame_header1;
DBG_PRINT(("%s\n",strPtr));
strPtr = Frame_header2;
DBG_PRINT(("%s\n",strPtr));
strPtr = Frame_header3;
DBG_PRINT(("%s\n",strPtr));
/* Print Frame info */
sprintf(rc_buffer, "%4d %1c %4d %6d %7d %2d %2d %2d %2.2f %6d %4d %3d",
frame->id,frameType,MB_cnt,current_Tx,rc_R,Ni,Np,Nb, N_act, lastFrameVirtBuf, rc_Q, Qscale);
#ifdef RC_STATS_FILE
fprintf(RC_FILE,"%s\n", rc_buffer);
fflush(RC_FILE);
#endif
DBG_PRINT(("%s\n",rc_buffer));
/* Print headers for Macroblock info */
if (RC_MB_SAMPLE_RATE) {
strPtr = MB_header1;
DBG_PRINT(("%s\n",strPtr));
strPtr = MB_header2;
DBG_PRINT(("%s\n",strPtr));
} else {
return;
}
return;
}
/*===========================================================================*
*
* updateRateControl
*
* Update the statistics kept, after end of frame. Resets
* various global variables
*
* RETURNS: nothing
*
* SIDE EFFECTS: many global variables
*
*===========================================================================*/
void
updateRateControl(type)
int type;
{
int totalBits, frameComplexity, pctAllocUsed, pctGOPUsed;
float avgQuant;
char *strPtr;
totalBits = rc_totalFrameBits;
avgQuant = ((float) rc_totalQuant / (float) rc_numBlocks);
frameComplexity = totalBits * avgQuant;
pctAllocUsed = (totalBits *100 / current_Tx);
rc_R -= totalBits;
pctGOPUsed = (rc_R *100/ rc_G);
avg_act = (total_act_j / MB_cnt);
updateVBVBuffer(totalBits);
switch (type) {
case TYPE_IFRAME:
Ti = current_Tx;
d0_i = currentVirtBuf;
Ni--;
Si = totalBits;
Qi = avgQuant;
Xi = frameComplexity;
break;
case TYPE_PFRAME:
Tp = current_Tx;
d0_p = currentVirtBuf;
Np--;
Sp = totalBits;
Qp = avgQuant;
Xp = frameComplexity;
break;
case TYPE_BFRAME:
Tb = current_Tx;
d0_b = currentVirtBuf;
Nb--;
Sb = totalBits;
Qb = avgQuant;
Xb = frameComplexity;
break;
}
/* Print Frame info */
strPtr = Frame_trailer1;
DBG_PRINT(("%s\n",strPtr));
strPtr = Frame_trailer2;
DBG_PRINT(("%s\n",strPtr));
strPtr = Frame_trailer3;
DBG_PRINT(("%s\n",strPtr));
sprintf(rc_buffer, "%6d %2.2f %6d %3d %2.2f %7d %3d %7d %3d %6d %6d",
totalBits, avgQuant, frameComplexity, avg_act, N_act, currentVirtBuf, pctAllocUsed, rc_R, pctGOPUsed, VBV_buffer, VBV_delay);
#ifdef RC_STATS_FILE
fprintf(RC_FILE,"%s\n", rc_buffer);
fflush(RC_FILE);
#endif
DBG_PRINT(("%s\n",rc_buffer));
Nx--;
rc_totalMBBits= rc_bitsThisMB= rc_totalFrameBits=rc_totalOverheadBits = 0;
rc_numBlocks = rc_totalQuant = total_act_j = currentVirtBuf = 0;
DBG_PRINT(("GOP now has %d bits remaining (%3d%%) for %d frames .. , Ni= %d, Np= %d, Nb= %d\n", rc_R, (rc_R*100/rc_G), (Ni+Np+Nb), Ni, Np, Nb));
}
/*===========================================================================*
*
* MB_RateOut
*
* Prints out sampling of MB rate control data. Every "nth" block
* stats are printed, with "n" controled by global RC_MB_SAMPLE_RATE
* (NB. "skipped" blocks do not go through this function and thus do not
* show up in the sample )
*
* RETURNS: nothing
*
* SIDE EFFECTS: none
*
* NOTES:
*
*===========================================================================*/
void
MB_RateOut(type)
int type;
{
int totalBits;
int pctUsed, pctDone;
int bitsThisMB;
int bitsPerMB;
bitsThisMB = rc_bitsThisMB;
totalBits = rc_totalFrameBits;
bitsPerMB = (totalBits / rc_numBlocks);
pctDone = (rc_numBlocks * 100/ MB_cnt);
pctUsed = (totalBits *100/current_Tx);
sprintf(rc_buffer, "%3d %5d %2d %3d %6d %3d %6d %2.2f %6d %4d %3d %3d\n",
(rc_numBlocks - 1), bitsThisMB, Qscale, mquant, currentVirtBuf,
rc_Q, act_j, N_act, totalBits, bitsPerMB, pctUsed, pctDone);
#ifdef RC_STATS_FILE
fprintf(RC_FILE, "%s", rc_buffer);
fflush(RC_FILE);
#endif
if ( (RC_MB_SAMPLE_RATE) && ((rc_numBlocks -1) % RC_MB_SAMPLE_RATE)) {
DBG_PRINT(("%s\n", rc_buffer));
} else {
return;
}
}
/*===========================================================================*
*
* incNumBlocks()
*
*
* RETURNS: nothing
*
* SIDE EFFECTS: rc_numBlocks
*
* NOTES:
*
*===========================================================================*/
void incNumBlocks(num)
int num;
{
rc_numBlocks += num;
}
/*===========================================================================*
*
* incMacroBlockBits()
*
* Increments the number of Macro Block bits and the total of Frame
* bits by the number passed.
*
* RETURNS: nothing
*
* SIDE EFFECTS: rc_totalMBBits
*
* NOTES:
*
*===========================================================================*/
void incMacroBlockBits(num)
int num;
{
rc_bitsThisMB = num;
rc_totalMBBits += num;
rc_totalFrameBits += num;
}
/*===========================================================================*
*
* needQScaleChange(current Q scale, 4 luminance blocks)
*
*
* RETURNS: new Qscale
*
* SIDE EFFECTS:
*
*===========================================================================*/
int needQScaleChange(oldQScale, blk0, blk1, blk2, blk3)
int oldQScale;
Block blk0;
Block blk1;
Block blk2;
Block blk3;
{
/* One more MacroBlock seen */
rc_numBlocks++; /* this notes each block num in MB */
checkBufferFullness(oldQScale);
checkSpatialActivity(blk0, blk1, blk2, blk3);
mquant = rc_Q * N_act;
Qscale = (mquant > 31 ? 31 : mquant);
Qscale = (Qscale < 1 ? 1 : Qscale);
rc_totalQuant += Qscale;
if (oldQScale == Qscale)
return -1;
else
return Qscale;
}
/*===========================================================================*
*
* determineMBCount()
*
* Determines number of Macro Blocks in frame from the frame sizes
* passed.
*
* RETURNS: nothing
*
* SIDE EFFECTS: sets the count passed
*
*===========================================================================*/
int
determineMBCount ()
{
int y,x;
x = (Fsize_x +15)/16;
y = (Fsize_y +15)/16;
return (x * y);
}
/*===========================================================================*
*
* void checkBufferFullness ()
*
* Calculates the fullness of the virtual buffer for each
* frame type. Called before encoding each macro block. Along
* with the normalisec spatial activity measure (N_act), it
* determine the quantization factor for the next macroblock.
*
* RETURNS: nothing
*
* SIDE EFFECTS: the "currentVirtBuf" variable
*
* NOTES:
*
*===========================================================================*/
void checkBufferFullness (oldQScale)
int oldQScale;
{
int temp;
temp = lastFrameVirtBuf + rc_totalFrameBits;
temp -= (current_Tx * rc_numBlocks / MB_cnt);
currentVirtBuf = temp;
rc_Q = (currentVirtBuf * 31 / reactionParameter);
return;
}
/*===========================================================================*
*
* void checkSpatialActivity()
*
* Calcualtes the spatial activity for the four luminance blocks of the
* macroblock. Along with the normalised reference quantization parameter
* (rc_Q) , it determines the quantization factor for the next macroblock.
*
* RETURNS: nothing
*
* SIDE EFFECTS: the Adaptive quantization variables- act_j, N_act.
*
* NOTES:
*
*===========================================================================*/
void checkSpatialActivity(blk0, blk1, blk2, blk3)
Block blk0;
Block blk1;
Block blk2;
Block blk3;
{
int temp;
int16 *blkArray[4];
int16 *curBlock;
int16 *blk_ptr;
int var[4];
int i, j;
blkArray[0] = (int16 *) blk0;
blkArray[1] = (int16 *) blk1;
blkArray[2] = (int16 *) blk2;
blkArray[3] = (int16 *) blk3;
for (i =0; i < 4; i++) { /* Compute the activity in each block */
curBlock = blkArray[i];
blk_ptr = curBlock;
P_mean = 0;
/* Find the mean pixel value */
for (j=0; j < DCTSIZE_SQ; j ++) {
P_mean += *(blk_ptr++);
/* P_mean += curBlock[j];
if (curBlock[j] != *(blk_ptr++)) {
printf("\n\tARRAY ERROR: block %d\n", j);
}
*/
}
P_mean /= DCTSIZE_SQ;
/* Now find the variance */
curBlock = blkArray[i];
blk_ptr = curBlock;
var[i] = 0;
for (j=0; j < DCTSIZE_SQ; j++) {
#ifdef notdef
if (curBlock[j] != *(blk_ptr++)) {
printf("\n\tARRAY ERROR: block %d\n", j);
}
temp = curBlock[j] - P_mean;
#endif
temp = *(blk_ptr++) - P_mean;
var[i] += (temp * temp);
}
var[i] /= DCTSIZE_SQ;
}
/* Choose the minimum variance from the 4 blocks and use as the activity */
var_sblk = var[0];
for (i=1; i < 4; i++) {
var_sblk = (var_sblk < var[i] ? var_sblk : var[i]);
}
act_j = 1 + var_sblk;
total_act_j += act_j;
temp = (2 * act_j + avg_act);
N_act = ( (float) temp / (float) (act_j + 2*avg_act) );
return;
}
/*============================================================================*
*
* getRateMode ()
*
* Returns the rate mode- interpreted as either Fixed or Variable
*
* RETURNS: integer
*
* SIDE EFFECTS: none
*
*
*==========================================================================*/
int getRateMode()
{
return RateControlMode;
}
/*===========================================================================*
*
* setBitRate ()
*
* Checks the string parsed from the parameter file. Verifies
* number and sets global values. MPEG standard specifies that bit rate
* be rounded up to nearest 400 bits/sec.
*
* RETURNS: nothing
*
* SIDE EFFECTS: global variables
*
* NOTES: Should this be in the 400-bit units used in sequence header?
*
*===========================================================================*/
void setBitRate (charPtr)
char * charPtr;
{
int rate, rnd;
rate = atoi(charPtr);
if (rate > 0) {
RateControlMode = FIXED_RATE;
} else {
printf("Parameter File Error: invalid BIT_RATE: \"%s\", defaults to Variable ratemode\n",
charPtr);
RateControlMode = VARIABLE_RATE;
bit_rate = -1;
}
rnd = (rate % 400);
rate += (rnd ? 400 -rnd : 0); /* round UP to nearest 400 bps */
rate = (rate > MAX_BIT_RATE ? MAX_BIT_RATE : rate);
bit_rate = rate;
DBG_PRINT(("Bit rate is: %d\n", bit_rate));
}
/*===========================================================================*
*
* getBitRate ()
*
* Returns the bit rate read from the parameter file. This is the
* real rate in bits per second, not in 400 bit units as is written to
* the sequence header.
*
* RETURNS: int (-1 if Variable mode operation)
*
* SIDE EFFECTS: none
*
*===========================================================================*/
int getBitRate ()
{
return bit_rate;
}
/*===========================================================================*
*
* setBufferSize ()
*
* Checks the string parsed from the parameter file. Verifies
* number and sets global values.
*
* RETURNS: nothing
*
* SIDE EFFECTS: buffer_size global variable.
*
* NOTES: The global is in bits, NOT the 16kb units used in sequence header
*
*===========================================================================*/
void setBufferSize (charPtr)
char * charPtr;
{
int size;
size = atoi(charPtr);
size = (size > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : size);
if (size > 0) {
size = (16*1024) * ((size + (16*1024 - 1)) / (16*1024));
buffer_size = size;
} else {
buffer_size = DEFAULT_BUFFER_SIZE;
printf("Parameter File Error: invalid BUFFER_SIZE: \"%s\", defaults to : %d\n",
charPtr, buffer_size);
}
DBG_PRINT(("Buffer size is: %d\n", buffer_size));
}
/*===========================================================================*
*
* getBufferSize ()
*
* returns the buffer size read from the parameter file. Size is
* in bits- not in units of 16k as written to the sequence header.
*
* RETURNS: int (or -1 if invalid)
*
* SIDE EFFECTS: none
*
*===========================================================================*/
int getBufferSize ()
{
return buffer_size;
}
/*===========================================================================*
*
* updateVBVBuffer ()
*
* Update the VBV buffer after each frame. This theoretical
* buffer is being filled at constant rate, given by the bit rate.
* It is emptied as each frame is grabbed by the decoder. Exception
* is that the deocder will wait until the "delay" is over.
*
* RETURNS: nothing
*
* SIDE EFFECTS: VBV_buffer
*
* NOTES:
*
*===========================================================================*/
void updateVBVBuffer (frameBits)
int frameBits;
{
if (VBV_delay) {
VBV_delay -= frameDelayIncrement;
if (VBV_delay < 0) {
VBV_delay = 0;
}
} else {
VBV_buffer -= frameBits;
}
VBV_buffer += bufferFillRate;
if (VBV_buffer < 0) {
fprintf(stderr, "\tWARNING - VBV buffer underflow (%d)\n", VBV_buffer);
}
if (VBV_buffer > buffer_size) {
fprintf(stderr, "WARNING - VBV buffer overflow (%d > %d)\n",
VBV_buffer, buffer_size);
}
}
syntax highlighted by Code2HTML, v. 0.9.1