📄 divx4_vbr.c
字号:
/* * divx4_vbr.c * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of the Linux * distribution for more details. * * 2-pass code OpenDivX port: * Copyright (C) 2001 Christoph Lampert <gruel@gmx.de> * * Large parts of this code were taken from VbrControl() from the OpenDivX * project, (C) divxnetworks, written by Eugene Kuznetsov <ekuznetsov@divxnetworks.com> * with the permission of Darrius "Junto" Thompson, Director DivX */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <math.h>#include <inttypes.h>#include "divx4_vbr.h"#include "mp_msg.h"#include "help_mp.h"//#include "transcode.h"#define FALSE 0#define TRUE 1/* Absolute maximum and minimum quantizers used in VBR modes */static const int min_quantizer=1;static const int max_quantizer=31;/* Limits on frame-level deviation of quantizer ( higher values correspond to frames with more changes and vice versa ) */ static const float min_quant_delta=-10.f;static const float max_quant_delta=5.f;/* Limits on stream-level deviation of quantizer ( used to make overall bitrate of stream close to requested value ) */static const float min_rc_quant_delta=.6f;static const float max_rc_quant_delta=1.5f;/* Crispness parameter controls threshold for decision whether to skip the frame or to code it. *///static const float max_crispness=100.f;/* Maximum allowed number of skipped frames in a line. *///static const int max_drops_line=0; // CHL We don't drop frames at the moment!typedef struct entry_s /* max 28 bytes/frame or 5 Mb for 2-hour movie */ { int quant; int text_bits; int motion_bits; int total_bits; float mult; short is_key_frame; short drop; } entry;static int m_iCount;static int m_iQuant;/*static int m_iCrispness;*/static short m_bDrop;static float m_fQuant;static int64_t m_lEncodedBits;static int64_t m_lExpectedBits;static FILE *m_pFile;static entry vFrame;static entry *m_vFrames;static long lFrameStart;static int iNumFrames;static int dummy;void VbrControl_init_1pass_vbr(int quality, int crispness){ m_fQuant=min_quantizer+((max_quantizer-min_quantizer)/6.)*(6-quality); m_iCount=0; m_bDrop=FALSE; VbrControl_update_1pass_vbr();}int VbrControl_init_2pass_vbr_analysis(const char *filename, int quality){ m_pFile=fopen(filename, "wb"); if(m_pFile==0) return -1; m_iCount=0; m_bDrop=FALSE; fprintf(m_pFile, "##version 1\n"); fprintf(m_pFile, "quality %d\n", quality); return 0;}int VbrControl_init_2pass_vbr_encoding(const char *filename, int bitrate, double framerate, int crispness, int quality){ int i; int64_t text_bits=0; int64_t total_bits=0; int64_t complexity=0; int64_t new_complexity=0; int64_t motion_bits=0; int64_t denominator=0; float qual_multiplier=1.; char head[20]; int64_t desired_bits; int64_t non_text_bits; float average_complexity; m_pFile=fopen(filename, "rb"); if(m_pFile==0) return -1; m_bDrop=FALSE; m_iCount=0; fread(head, 10, 1, m_pFile); if(!strncmp("##version ", head, 10)) { int version; int iOldQual; float old_qual, new_qual; fscanf(m_pFile, "%d\n", &version); fscanf(m_pFile, "quality %d\n", &iOldQual); switch(iOldQual) { case 5: old_qual=1.f; break; case 4: old_qual=1.1f; break; case 3: old_qual=1.25f; break; case 2: old_qual=1.4f; break; case 1: old_qual=2.f; break; } switch(quality) { case 5: new_qual=1.f; break; case 4: new_qual=1.1f; break; case 3: new_qual=1.25f; break; case 2: new_qual=1.4f; break; case 1: new_qual=2.f; break; } qual_multiplier=new_qual/old_qual; } else fseek(m_pFile, 0, SEEK_SET); lFrameStart=ftell(m_pFile); // save current position /* removed C++ dependencies, now read file twice :-( */ while(!feof(m_pFile)) { fscanf(m_pFile, "Frame %d: intra %hd, quant %d, texture %d, motion %d, total %d\n", &iNumFrames, &(vFrame.is_key_frame), &(vFrame.quant), &(vFrame.text_bits), &(vFrame.motion_bits), &(vFrame.total_bits)); vFrame.total_bits+=vFrame.text_bits*(qual_multiplier-1); vFrame.text_bits*=qual_multiplier; text_bits +=(int64_t)vFrame.text_bits; motion_bits += (int64_t)vFrame.motion_bits; total_bits +=(int64_t)vFrame.total_bits; complexity +=(int64_t)vFrame.text_bits*vFrame.quant;// printf("Frames %d, texture %d, motion %d, quant %d total %d ",// iNumFrames, vFrame.text_bits, vFrame.motion_bits, vFrame.quant, vFrame.total_bits);// printf("texture %d, total %d, complexity %lld \n",vFrame.text_bits,vFrame.total_bits, complexity); } iNumFrames++; average_complexity=complexity/iNumFrames; // if (verbose & TC_DEBUG) {// fprintf(stderr, "(%s) frames %d, texture %lld, motion %lld, total %lld, complexity %lld\n", __FILE__, iNumFrames, text_bits, motion_bits, total_bits, complexity);// } m_vFrames = (entry*)malloc(iNumFrames*sizeof(entry)); if (!m_vFrames) { mp_msg(MSGT_FIXME, MSGL_FIXME,MSGTR_OutOfMemory); return -2; //TC_EXPORT_ERROR; } fseek(m_pFile, lFrameStart, SEEK_SET); // start again for (i=0;i<iNumFrames;i++) { fscanf(m_pFile, "Frame %d: intra %hd, quant %d, texture %d, motion %d, total %d\n", &dummy, &(m_vFrames[i].is_key_frame), &(m_vFrames[i].quant), &(m_vFrames[i].text_bits), &(m_vFrames[i].motion_bits), &(m_vFrames[i].total_bits)); m_vFrames[i].total_bits += m_vFrames[i].text_bits*(qual_multiplier-1); m_vFrames[i].text_bits *= qual_multiplier; } if (m_pFile) { fclose(m_pFile); m_pFile=NULL; } desired_bits=(int64_t)bitrate*(int64_t)iNumFrames/framerate; non_text_bits=total_bits-text_bits; if(desired_bits<=non_text_bits) {/* char s[200];*/ mp_msg(MSGT_FIXME, MSGL_FIXME, MSGTR_OverridingTooLowBitrate, (float)(non_text_bits*framerate/(int64_t)iNumFrames)); desired_bits=non_text_bits*3/2;/* m_fQuant=max_quantizer; for(int i=0; i<iNumFrames; i++) { m_vFrames[i].drop=0; m_vFrames[i].mult=1; } VbrControl_set_quant(m_fQuant); return 0;*/ } desired_bits -= non_text_bits; /** BRIEF EXPLANATION OF WHAT'S GOING ON HERE. We assume that text_bits=complexity / quantizer total_bits-text_bits = const(complexity) where 'complexity' is a characteristic of the frame and does not depend much on quantizer dynamics. Using this equation, we calculate 'average' quantizer to be used for encoding ( 1st order effect ). Having constant quantizer for the entire stream is not very convenient - reconstruction errors are more noticeable in low-motion scenes. To compensate this effect, we multiply quantizer for each frame by (complexity/average_complexity)^k, ( k - parameter of adjustment ). k=0 means 'no compensation' and k=1 is 'constant bitrate mode'. We choose something in between, like 0.5 ( 2nd order effect ). **/ average_complexity=complexity/iNumFrames; for(i=0; i<iNumFrames; i++) { float mult; if(m_vFrames[i].is_key_frame) { if((i+1<iNumFrames) && (m_vFrames[i+1].is_key_frame)) mult=1.25; else mult=.75; } else { mult=m_vFrames[i].text_bits*m_vFrames[i].quant; mult=(float)sqrt(mult/average_complexity); // if(i && m_vFrames[i-1].is_key_frame)// mult *= 0.75; if(mult<0.5) mult=0.5; if(mult>1.5) mult=1.5; } m_vFrames[i].mult=mult; m_vFrames[i].drop=FALSE; new_complexity+=m_vFrames[i].text_bits*m_vFrames[i].quant; denominator+=desired_bits*m_vFrames[i].mult/iNumFrames; } m_fQuant=((double)new_complexity)/(double)denominator; if(m_fQuant<min_quantizer) m_fQuant=min_quantizer; if(m_fQuant>max_quantizer) m_fQuant=max_quantizer; m_pFile=fopen("analyse.log", "wb"); if(m_pFile) { fprintf(m_pFile, "Total frames: %d Avg quantizer: %f\n", iNumFrames, m_fQuant); fprintf(m_pFile, "Expecting %12lld bits\n", desired_bits+non_text_bits); fflush(m_pFile); } VbrControl_set_quant(m_fQuant*m_vFrames[0].mult); m_lEncodedBits=m_lExpectedBits=0; return 0;}int VbrControl_get_intra() { return m_vFrames[m_iCount].is_key_frame;}short VbrControl_get_drop() { return m_bDrop;}int VbrControl_get_quant() { return m_iQuant;}void VbrControl_set_quant(float quant){ m_iQuant=quant; if((rand() % 10)<((quant-m_iQuant) * 10)) m_iQuant++; if(m_iQuant<min_quantizer) m_iQuant=min_quantizer; if(m_iQuant>max_quantizer) m_iQuant=max_quantizer;}void VbrControl_update_1pass_vbr(){ VbrControl_set_quant(m_fQuant); m_iCount++;}void VbrControl_update_2pass_vbr_analysis(int is_key_frame, int motion_bits, int texture_bits, int total_bits, int quant){ if(!m_pFile) return; fprintf(m_pFile, "Frame %d: intra %d, quant %d, texture %d, motion %d, total %d\n", m_iCount, is_key_frame, quant, texture_bits, motion_bits, total_bits); m_iCount++;}void VbrControl_update_2pass_vbr_encoding(int motion_bits, int texture_bits, int total_bits){ double q; double dq; if(m_iCount>=iNumFrames) return; m_lExpectedBits+=(m_vFrames[m_iCount].total_bits-m_vFrames[m_iCount].text_bits) + m_vFrames[m_iCount].text_bits*m_vFrames[m_iCount].quant/m_fQuant; m_lEncodedBits+=(int64_t)total_bits; if(m_pFile) fprintf(m_pFile, "Frame %d: PRESENT, complexity %d, quant multiplier %f, texture %d, total %d ", m_iCount, m_vFrames[m_iCount].text_bits*m_vFrames[m_iCount].quant, m_vFrames[m_iCount].mult, texture_bits, total_bits); m_iCount++; q = m_fQuant * m_vFrames[m_iCount].mult; if(q<m_fQuant+min_quant_delta) q=m_fQuant+min_quant_delta; if(q>m_fQuant+max_quant_delta) q=m_fQuant+max_quant_delta; dq = (double)m_lEncodedBits/(double)m_lExpectedBits; dq*=dq; if(dq<min_rc_quant_delta) dq=min_rc_quant_delta; if(dq>max_rc_quant_delta) dq=max_rc_quant_delta; if(m_iCount<20) // no framerate corrections in first frames dq=1; if(m_pFile) fprintf(m_pFile, "Progress: expected %12lld, achieved %12lld, dq %f", m_lExpectedBits, m_lEncodedBits, dq); q *= dq; VbrControl_set_quant(q); if(m_pFile) fprintf(m_pFile, ", new quant %d\n", m_iQuant);}void VbrControl_close(){ if(m_pFile) { fclose(m_pFile); m_pFile=NULL; } free(m_vFrames);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -