📄 tm5rc.cpp
字号:
/* * Copyright (c) 1997 NextLevel Systems of Delaware, Inc. All rights reserved. * * This software module was developed by Bob Eifrig (at NextLevel * Systems of Delaware, Inc.), Xuemin Chen (at NextLevel Systems of * Delaware, Inc.), and Ajay Luthra (at NextLevel Systems of Delaware, * Inc.), in the course of development of the MPEG-4 Video Standard * (ISO/IEC 14496-2). This software module is an implementation of a * part of one or more tools as specified by the MPEG-4 Video Standard. * * NextLevel Systems of Delaware, Inc. grants the right, under its * copyright in this software module, to use this software module and to * make modifications to it for use in products which conform to the * MPEG-4 Video Standard. No license is granted for any use in * connection with products which do not conform to the MPEG-4 Video * Standard. * * Those intending to use this software module are advised that such use * may infringe existing and unissued patents. Please note that in * order to practice the MPEG-4 Video Standard, a license may be * required to certain patents held by NextLevel Systems of Delaware, * Inc., its parent or affiliates ("NextLevel"). The provision of this * software module conveys no license, express or implied, under any * patent rights of NextLevel or of any third party. This software * module is subject to change without notice. NextLevel assumes no * responsibility for any errors that may appear in this software * module. NEXTLEVEL DISCLAIMS ALL WARRANTIES, EXPRESS AND IMPLIED, * INCLUDING, BUT NOT LIMITED TO ANY WARRANTY THAT COMPLIANCE WITH OR * PRACTICE OF THE SPECIFICATIONS OR USE OF THIS SOFTWARE MODULE WILL * NOT INFRINGE THE INTELLECTUAL PROPERTY RIGHTS OF NEXTLEVEL OR ANY * THIRD PARTY, AND ANY IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. * * NextLevel retains the full right to use this software module for its * own purposes, to assign or transfer this software module to others, * to prevent others from using this software module in connection with * products which do not conform to the MPEG-4 Video Standard, and to * prevent others from infringing NextLevel's patents. * * As an express condition of the above license grant, users are * required to include this copyright notice in all copies or derivative * works of this software module. *//* MPEG-2 Video TM-5 rate control For the purpose of comparing MPEG-4 VM with MPEG-2 TM-5 27.03.97 By X. Chen in G.I. * 23.01.99 David Ruhoff: (double) cast to dj calc per Sarnoff labs * 16.03.99 David Ruhoff: conversion to microsoft-vfdis-v10-990124 */#include <stdio.h>#include <stdlib.h>#include <iostream.h>#include <math.h>#include "header.h"#include "typeapi.h"//#include "codehead.h"//#include "entropy/bitstrm.hpp"#include "entropy/entropy.hpp"#include "entropy/huffman.hpp"#include "mode.hpp"//#include "global.hpp"#include "vopses.hpp"#include "vopseenc.hpp"#include "tm5rc.hpp"void TM5rc::tm5rc_init_seq( char *pchQname, UInt rc_type_arg, AlphaUsage fAUsage, UInt uiWidth, UInt uiHeight, UInt uiBitRate, Double dFrameRate ){ if (fAUsage != RECTANGLE) { fprintf(stderr, "TM5 rate control requires a rectangular VOP\n"); exit(1); } rc_type = rc_type_arg; switch (rc_type) { case RC_TM5: break; case RC_TM5+1: assert(pchQname); assert(*pchQname); if ((Qfile = fopen(pchQname, "r")) == NULL) { fprintf(stderr, "Cannot open %s\n", pchQname); exit(1); } break; case RC_TM5+2: assert(pchQname); assert(*pchQname); if ((Qfile = fopen(pchQname, "w")) == NULL) { fprintf(stderr, "Cannot open %s\n", pchQname); exit(1); } break; default: fprintf(stderr, "Invalid rate control code: %d\n", rc_type); exit(1); } mb_width = (uiWidth + MB_SIZE - 1) / MB_SIZE; mb_height = (uiHeight + MB_SIZE - 1) / MB_SIZE; bitrate = uiBitRate; pic_rate = dFrameRate; /* memory leak -- need to free when done */ mbact = new double [mb_width * mb_height]; /* reaction parameter (constant) */ /* if (r_tm5==0) */ r_tm5 = (int)floor(2.0*bitrate/pic_rate + 0.5); /* average activity */ if (avg_act==0.0) avg_act = 400.0; /* remaining # of bits in GOP */ R_tm5 = 0; /* global complexity measure */ if (Xi==0) Xi = (int)floor(160.0*bitrate/115.0 + 0.5); if (Xp==0) Xp = (int)floor( 60.0*bitrate/115.0 + 0.5); if (Xb==0) Xb = (int)floor( 42.0*bitrate/115.0 + 0.5); /* virtual buffer fullness */ if (d0i==0) d0i = (int)floor(10.0*r_tm5/31.0 + 0.5); // ***** NOT CORRECT FOR NBIT ***** if (d0p==0) d0p = (int)floor(10.0*r_tm5/31.0 + 0.5); if (d0b==0) d0b = (int)floor(1.4*10.0*r_tm5/31.0 + 0.5); cout.sync_with_stdio(); fprintf(stdout,"rate control: sequence initialization\n"); fprintf(stdout," initial global complexity measures (I,P,B): Xi=%d, Xp=%d, Xb=%d\n", Xi, Xp, Xb); fprintf(stdout," reaction parameter: r_tm5=%d\n", r_tm5); fprintf(stdout," initial virtual buffer fullness (I,P,B): d0i=%d, d0p=%d, d0b=%d\n", d0i, d0p, d0b); fprintf(stdout," initial average activity: avg_act=%.1f\n\n", avg_act);}void TM5rc::tm5rc_init_GOP(int np,int nb){ if ((Ni + Np + Nb) != 0) { fprintf(stderr, "TM5: Short GOP, expected %d/%d/%d more I/P/B-pics\n", Ni, Np, Nb); exit(1); } R_tm5 += (int) floor((1 + np + nb) * bitrate / pic_rate + 0.5); Np = np; Nb = nb; Ni = 1; cout.sync_with_stdio(); fprintf(stdout,"\nrate control: new group of pictures (GOP)\n"); fprintf(stdout," target number of bits for GOP: R_tm5=%d\n",R_tm5); fprintf(stdout," number of P pictures in GOP: Np=%d\n",Np); fprintf(stdout," number of B pictures in GOP: Nb=%d\n\n",Nb);}/* Note: we need to substitute K for the 1.4 and 1.0 constants -- this can be modified to fit image content *//* Step 1: compute target bits for current picture being coded */void TM5rc::tm5rc_init_pict(VOPpredType vopPredType, const PixelC* ppxlcOrigY, Int row_size, Int iNumMBX, Int iNumMBY){ Double Tmin; Int type; switch (rc_type) { case RC_TM5+1: type = -1; if ((fscanf(Qfile, "%d", &type) != 1) || (type != vopPredType)) { fprintf(stderr, "Wrong pictue type: got %d, expected %d\n", type, vopPredType); exit(1); } return; case RC_TM5+2: fprintf(Qfile, "%d ", vopPredType); break; } switch (vopPredType) { default: fprintf(stderr, "Invalid vopPredType code: %d\n", vopPredType); exit(1); case IVOP: T_tm5 = (int) floor(R_tm5/(1.0+Np*Xp/(Xi*1.0)+Nb*Xb/(Xi*1.4)) + 0.5); d_tm5 = d0i; break; case PVOP: T_tm5 = (int) floor(R_tm5/(Np+Nb*1.0*Xb/(1.4*Xp)) + 0.5); d_tm5 = d0p; break; case BVOP: T_tm5 = (int) floor(R_tm5/(Nb+Np*1.4*Xp/(1.0*Xb)) + 0.5); d_tm5 = d0b; break; } Tmin = (int) floor(bitrate/(8.0*pic_rate) + 0.5); if (T_tm5<Tmin) T_tm5 = (int)Tmin; Q_tm5 = 0; tm5_calc_actj(ppxlcOrigY, row_size, iNumMBX, iNumMBY); actsum = 0.0; cout.sync_with_stdio(); fprintf(stdout,"rate control: start of picture\n"); fprintf(stdout," target number of bits: T_tm5=%d\n",T_tm5); fflush(stdout);//printf("ppxlcOrigY=%p row_size=%d iNumMBX=%d iNumMBY=%d\n", // ppxlcOrigY, row_size, iNumMBX, iNumMBY);}void TM5rc::tm5_calc_actj(const PixelC* ppxlcOrigY, Int row_size, Int iNumMBX, Int iNumMBY){ assert (MB_SIZE == 2*BLOCK_SIZE); Double actj, var; Int k = 0; Int iMBY, iMBX; for (iMBY=0; iMBY<iNumMBY; iMBY++) { const PixelC* ppxlcOrigMBY = ppxlcOrigY; for (iMBX=0; iMBX<iNumMBX; iMBX++) { /* take minimum spatial activity measure of luminance blocks */ actj = tm5_var_sblk(ppxlcOrigMBY, row_size); var = tm5_var_sblk(ppxlcOrigMBY+BLOCK_SIZE, row_size); if (var<actj) actj = var; var = tm5_var_sblk(ppxlcOrigMBY+BLOCK_SIZE*row_size, row_size); if (var<actj) actj = var; var = tm5_var_sblk(ppxlcOrigMBY+BLOCK_SIZE*row_size+BLOCK_SIZE, row_size); if (var<actj) actj = var; actj += 1.0; mbact[k++] = actj; ppxlcOrigMBY += MB_SIZE; } ppxlcOrigY += row_size*MB_SIZE; }}/* compute variance of 8x8 block */Double TM5rc::tm5_var_sblk(const PixelC *p, Int lx){ int i, j; unsigned int v, s, s2; assert (BLOCK_SIZE == 8); s = s2 = 0; for (j=0; j<8; j++) { for (i=0; i<8; i++) { v = *p++; s+= v; s2+= v*v; } p+= lx - 8; } return s2/64.0 - (s/64.0)*(s/64.0);}/* compute initial quantization stepsize (at the beginning of picture) */Int TM5rc::tm5rc_start_mb(){ Int mquant; if (rc_type == RC_TM5+1) { if (fscanf(Qfile, "%d", &mquant) != 1) { fprintf(stderr, "Q file read error\n"); exit(1); } return mquant; } mquant = (int) floor(d_tm5*31.0/r_tm5 + 0.5); // ***** NOT CORRECT FOR NBIT ************ /* clip mquant to legal range */ if (mquant<1) mquant = 1; if (mquant>31) // ***** NOT CORRECT FOR NBIT ************ mquant = 31; prev_mquant = mquant = mquant; if (rc_type == RC_TM5+2) { fprintf(Qfile, "%2d\n", mquant); linectr = 0; } cout.sync_with_stdio(); printf(" tm5rc_start_mb mquant=%d\n",mquant);//fprintf(stdout,"\tj\tsize\tmquant\td_tm5\tT_tm5\tdj\tQj\tactj\tN_actj\n"); return mquant;}/* Step 2: measure virtual buffer - estimated buffer discrepancy */Int TM5rc::tm5rc_calc_mquant(Int j, UInt size){ int mquant; double dj, Qj, actj, N_actj; if (rc_type == RC_TM5+1) { if (fscanf(Qfile, "%d", &mquant) != 1) { fprintf(stderr, "Q file read error\n"); exit(1); } return mquant; } /* measure virtual buffer discrepancy from uniform distribution model */ dj = (double)((double)d_tm5 + (double)size - (double)j*((double)T_tm5/((double)mb_width*(double)mb_height)));/*fprintf(stdout,"dj=%.5f: d_tm5=%.3f, size=%d, j=%d, T_tm5=%.3f, width=%d height=%d\n", (float)dj, (float)d_tm5, (int)size, (int)j, (float)T_tm5, (int)mb_width, (int)mb_height);*/ /* scale against dynamic range of mquant and the bits/picture count */ Qj = dj*31.0/r_tm5; // ***** NOT CORRECT FOR NBIT ************ actj = mbact[j]; actsum += actj; /* compute normalized activity */ N_actj = (2.0*actj+avg_act)/(actj+2.0*avg_act); /* modulate mquant with combined buffer and local activity measures */ mquant = (int) floor(Qj*N_actj + 0.5); /* clip mquant to legal range */ if (mquant<1) mquant = 1; if (mquant>31) // ***** NOT CORRECT FOR NBIT ************ mquant = 31; mquant = mquant; Q_tm5 += mquant; /* for calculation of average mquant */ if (rc_type == RC_TM5+2) { fprintf(Qfile, "%2d ", mquant); if (++(linectr) >= mb_width) { fprintf(Qfile, "\n"); linectr = 0; } }//fprintf(stdout,"\t%d\t%d\t%d\t%d\t%d\t%g\t%g\t%g\t%g\n",// j, size, mquant, d_tm5, T_tm5, dj, Qj, actj, N_actj); return mquant;}void TM5rc::tm5rc_update_pict(VOPpredType vopPredType, Int iVOPtotalBits){ double X; if (rc_type == RC_TM5+1) { switch (vopPredType) { case IVOP: Ni--; break; case PVOP: Np--; break; case BVOP: Nb--; break; default: break; } return; } /* total # of bits in picture */ R_tm5 -= iVOPtotalBits; /* remaining # of bits in GOV */ X = (int) floor(iVOPtotalBits*((0.5*(double)(Q_tm5))/ (mb_width*mb_height)) + 0.5); d_tm5 += iVOPtotalBits - T_tm5; avg_act = actsum/(mb_width*mb_height); switch (vopPredType) { case IVOP: Xi = (int)X; d0i = d_tm5; if (--(Ni) < 0) { fprintf(stderr, "TM5: too many I-pics in GOP\n"); exit(1); } break; case PVOP: Xp = (int)X; d0p = d_tm5; if (--(Np) < 0) { fprintf(stderr, "TM5: too many P-pics in GOP\n"); exit(1); } break; case BVOP: Xb = (int)X; d0b = d_tm5; if (--(Nb) < 0) { fprintf(stderr, "TM5: too many B-pics in GOP\n"); exit(1); } break; default: fprintf(stderr, "Invalid vopPredType code: %d\n", vopPredType); exit(1); } cout.sync_with_stdio(); fprintf(stdout,"rate control: end of picture\n"); fprintf(stdout," actual number of bits=%d\n",iVOPtotalBits); fprintf(stdout," average quantization parameter Q_tm5=%.1f\n", (double)Q_tm5/(mb_width*mb_height)); fprintf(stdout," remaining number of bits in GOP: R_tm5=%d\n",R_tm5); fprintf(stdout," global complexity measures (I,P,B): Xi=%d, Xp=%d, Xb=%d\n", Xi, Xp, Xb); fprintf(stdout," virtual buffer fullness (I,P,B): d0i=%d, d0p=%d, d0b=%d\n", d0i, d0p, d0b); fprintf(stdout," remaining number of P pictures in GOP: Np=%d\n",Np); fprintf(stdout," remaining number of B pictures in GOP: Nb=%d\n",Nb); fprintf(stdout," average activity: avg_act=%.1f\n", avg_act); fflush(stdout);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -