?? passreg.cpp
字號:
/******************************************************** * Some code. Copyright (C) 2003 by Pascal Massimino. * * All Rights Reserved. (http://skal.planet-d.net) * * For Educational/Academic use ONLY. See 'LICENSE.TXT'.* ********************************************************//* * two-pass log file regularizer * *********************************************************//* * This program can be used to generate, from a 1rst-pass * log file, a "roadmap" for the final encoding (2nd-pass). * * Usually, two-pass encoding amounts to the following three steps: * * a) 'tmp4 input.ppm -pass 1 -passfile pass1.log -q 2' * * This will generate a log file 'pass1.log' during the 1rst pass. * The input source (input.ppm) is analyzed only, using a fixed * quantizer (Note: no bitstream is generated). * * b) 'passreg pass1.log -o pass2.log -tp 50 -v' * * This will generate a road map file 'pass2.log' that aims at * reducing the original size by 50%. Various other options are * available for 'passreg'. For instance: '-ts' to specify a * target size, '-la'/'-ha/ for asymmetric bit distribution, etc... * * c) tmp4 input.ppm -pass 2 -passfile pass2.log -o output.mp4 -trellis -4v 60 * * This is the final encoding, using 'pass2.log' to drive the * quality and control the size of the bitstream.. * Any additional encoding option can be used (trellis, ...): * they needn't be exactly the same than the first pass. * * * Note: all of these are rather experimental, and you're encouraged * to play with options/code, since it's all an external application * from the core codec point of view. * * ********************************************************/#include <stdio.h>#include <math.h>#include <stdlib.h>#include <string.h>#include <assert.h>#ifdef _WINDOWS#include <io.h>#include <fcntl.h>#endifstruct PASS_PARAM{ struct PASS_FRAME { int Pic_Type; float Q, FCode, mMV, dMV; int Bytes, Txt_Bytes, MV_Bytes; int Avrg; float Avrg_mMV, Avrg_dMV; int New_Bytes, New_Txt_Bytes; void Accumulate(int nMin, int nMax, const PASS_FRAME Frames[]); }; struct PASS_SCENE { int Start, Len; int Bytes; float Q_Avrg; }; const char *In_File, *Out_File; int Verbose; int Target_Size; float Target_Percent; float FPS, Bit_Rate; int Hi_Amp_Percent; int Low_Amp_Percent; int Min_Frame, Max_Frame, Nb_Frames; int All_Frames, All_Key_Frames; int All_Bytes, All_Txt_Bytes, All_MV_Bytes; int Win_Size; int Log_Type; // 0: MPEG4, 1:H264 int Pic_W, Pic_H, Nb_MBs; int Pic_Min_Sizes[3]; int KBoost_Percent; int Reg_Method; // 0: assymetric scale 1: use average 2: scene activity float Act_Limit; PASS_FRAME *Frames; PASS_SCENE *Scenes; void Reset(); // default values void Cleanup(); void Compute_Windowed_Average(); void Regularize_Frames(); void Setup_New_Quantizers(); void Parse_In_File(); void Write_Out_File(); void Help( char **argv, const char *S=0 ); void Missing( const char *S ); int Parse_Int_Value(const int argc, const char * const *argv, int &k, const int Min=-0x7fffff, const int Max=0x7ffffff); float Parse_Float_Value(const int argc, const char * const *argv, int &k, const float Min=-1.e30f, const float Max=1.e30f); void Parse_Options( int argc, char **argv ); int Process(int argc, char *argv[]); // main entry call};#define ERROR for( ; 1; throw this )//////////////////////////////////////////////////////////void PASS_PARAM::Reset(){ Out_File = 0; In_File = 0; Verbose = 1; Target_Size = 0; Target_Percent = 0.; FPS = 25.f; Bit_Rate = 0; Hi_Amp_Percent = 30; Low_Amp_Percent = 10; Min_Frame = 0; Max_Frame =-1; Nb_Frames = 0; Win_Size = 20; Log_Type =-1; KBoost_Percent = 5; Reg_Method = 0; Act_Limit = 0.5f; Frames = 0; Scenes = 0;}void PASS_PARAM::Cleanup(){ if (Frames) free(Frames); if (Scenes) free(Scenes); Reset();}//////////////////////////////////////////////////////////// The main workvoid PASS_PARAM::PASS_FRAME::Accumulate(int nMin, int nMax, const PASS_FRAME Frames[]){ Bytes = 0; mMV = 0.; dMV = 0.; for(int n=nMin; n<nMax; ++n) { Bytes += Frames[n].Bytes; mMV += Frames[n].mMV; dMV += Frames[n].dMV; }}void PASS_PARAM::Compute_Windowed_Average(){ int n, nMin, nMax; PASS_FRAME Avrg; n = Min_Frame; for(nMin=n; nMin>=0 && nMin>=n-Win_Size; --nMin) if (Frames[nMin].Pic_Type==0) break; for(nMax=n+1; nMax<=Max_Frame && nMax<=n+Win_Size; ++nMax) if (Frames[nMax].Pic_Type==0) break; Avrg.Accumulate(nMin, nMax, Frames); while(1) { const int Nb_Samples = nMax - nMin; Frames[n].Avrg = Avrg.Bytes / Nb_Samples; Frames[n].Avrg_mMV = Avrg.mMV / Nb_Samples; Frames[n].Avrg_dMV = Avrg.dMV / Nb_Samples;// printf( "%d %d %d %d %d\n", n, nMin, nMax, Frames[n].Bytes, Frames[n].Avrg ); if (n==Max_Frame) break; if (n-Win_Size==nMin) { Avrg.Bytes -= Frames[nMin].Bytes; Avrg.mMV -= Frames[nMin].mMV; Avrg.dMV -= Frames[nMin].dMV; nMin++; } n++; if (n+Win_Size==nMax) { if (nMax<=Max_Frame && Frames[nMax].Pic_Type!=0) { Avrg.Bytes += Frames[nMax].Bytes; Avrg.mMV += Frames[nMax].mMV; Avrg.dMV += Frames[nMax].dMV; nMax++; } } else if (n==nMax) { nMin = nMax; for(nMax=nMax+1; nMax<=Max_Frame && nMax<=n+Win_Size; ++nMax) if (Frames[nMax].Pic_Type==0) break; Avrg.Accumulate(nMin, nMax, Frames); } }}void PASS_PARAM::Regularize_Frames(){ int n; int Locked_Size = 0, Rest_Size = 0; float Scale = Target_Percent/100.f; for(n=Min_Frame; n<=Max_Frame; ++n) { const int Type = Frames[n].Pic_Type; double s; if (Type==0) { s = 1. + KBoost_Percent/100.; } else { if (Reg_Method==0) { const int Delta = Frames[n].Bytes - Frames[n].Avrg; if (Delta>=0) s = 1. + Hi_Amp_Percent/100.; else s = 1. + Low_Amp_Percent/100.; } else if (Reg_Method==1) { s = 1.; } else { double Activity; double mMV = Frames[n].Avrg_mMV + .01; double dMV = Frames[n].Avrg_dMV + .01; Activity = log(mMV) - Act_Limit*log(dMV); if (Activity>0.) { s = 1. + Activity*Low_Amp_Percent/100.; } else {// Activity = 1. - (Act_Limit*dMV)/mMV; s = 1. - Activity*Hi_Amp_Percent/100.; } if (Verbose>2) printf( "%d %f %f %f %f %f %f\n", n, Activity, (float)s, Frames[n].Avrg_mMV, Frames[n].mMV, Frames[n].Avrg_dMV, Frames[n].dMV ); } } int New_Bytes = (Type==0) ? Frames[n].Bytes : Frames[n].Avrg; New_Bytes = (int)( s*Scale * New_Bytes ); if (New_Bytes<Pic_Min_Sizes[Type]) { New_Bytes = Pic_Min_Sizes[Type]; Frames[n].New_Bytes = New_Bytes; Locked_Size += New_Bytes; } else { Frames[n].New_Bytes = -New_Bytes; // negative value indicates "TODO later" Rest_Size += New_Bytes; } } Scale = 1.f * (Target_Size - Locked_Size) / Rest_Size; Locked_Size = 0; for(n=Min_Frame; n<=Max_Frame; ++n) { if (Frames[n].New_Bytes<0) Frames[n].New_Bytes = (int)( -Frames[n].New_Bytes*Scale ); Frames[n].New_Txt_Bytes = (int)( Frames[n].Txt_Bytes * 1.*Frames[n].New_Bytes / Frames[n].Bytes ); Locked_Size += Frames[n].New_Bytes; } if (Verbose>0) { printf( "Final size: %d bytes [underflow:%.4f%%]\n", Locked_Size, 100.f*Locked_Size/Target_Size-100.f ); printf( "Final Bitrate: %.2f kbps\n", FPS*Locked_Size*8.f/1000.f / Nb_Frames ); printf( "\n" ); }}void PASS_PARAM::Setup_New_Quantizers(){ int n; for(n=Min_Frame; n<=Max_Frame; ++n) { float New_Q = 0.; double Amp = 1. * Frames[n].Bytes / Frames[n].New_Bytes; if (Log_Type==0) { New_Q = (float)( Frames[n].Q * Amp ); New_Q = (New_Q<1.1f) ? 1.1f : (New_Q>31.5f) ? 31.5f : New_Q; } else { New_Q = (float)( Frames[n].Q * ( 1.0 + 0.112*log( Amp ) ) ); New_Q = (New_Q<0.1f) ? 0.1f : (New_Q>51.0f) ? 51.0f : New_Q; } Frames[n].Q = New_Q; }}//////////////////////////////////////////////////////////// Read in-filevoid PASS_PARAM::Parse_In_File(){ int i, n, Nb, s; PASS_FRAME F = {0}; PASS_SCENE *Scene; FILE *f; char *Mem, *Start; f = In_File ? fopen(In_File, "r") : stdin; if (f==0) ERROR fprintf( stderr, "Can't open in-file %s\n", In_File ); fseek(f, 0, SEEK_END); const int Size = (int)ftell(f); fseek(f, 0, SEEK_SET); Mem = (char*)malloc(Size+1); if (Mem==0) ERROR fprintf( stderr, "Malloc error for reading file (size=%d)\n", Size+1); if (fread(Mem, Size, 1, f)!=1) { free(Mem); ERROR fprintf( stderr, "Error reading in-file!\n" ); }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -