📄 plugin_2pass2.c
字号:
/****************************************************************************** * * XviD Bit Rate Controller Library * - VBR 2 pass bitrate controller implementation - * * Copyright (C) 2002 Foxer <email?> * 2002 Dirk Knop <dknop@gwdg.de> * 2002-2003 Edouard Gomez <ed.gomez@free.fr> * 2003 Pete Ross <pross@xvid.org> * * This curve treatment algorithm is the one originally implemented by Foxer * and tuned by Dirk Knop for the XviD vfw frontend. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id$ * *****************************************************************************/#define BQUANT_PRESCALE#undef COMPENSATE_FORMULA/* forces second pass not to be bigger than first */#undef PASS_SMALLER/* automtically alters overflow controls (strength and improvement/degradation) to fight most common problems without user's knowladge */#define SMART_OVERFLOW_SETTING#include <stdio.h>#include <math.h>#include <limits.h>#include "../xvid.h"#include "../image/image.h"/***************************************************************************** * Some default settings ****************************************************************************/#define DEFAULT_KEYFRAME_BOOST 0#define DEFAULT_OVERFLOW_CONTROL_STRENGTH 10#define DEFAULT_CURVE_COMPRESSION_HIGH 0#define DEFAULT_CURVE_COMPRESSION_LOW 0#define DEFAULT_MAX_OVERFLOW_IMPROVEMENT 10#define DEFAULT_MAX_OVERFLOW_DEGRADATION 10/* Keyframe settings */#define DEFAULT_KFREDUCTION 20#define DEFAULT_KFTHRESHOLD 1/***************************************************************************** * Some default constants (can be tuned) ****************************************************************************//* Specify the invariant part of the headers bits (header+MV) * as hlength/cst */#define INVARIANT_HEADER_PART_IVOP 1 /* factor 1.0f */#define INVARIANT_HEADER_PART_PVOP 2 /* factor 0.5f */#define INVARIANT_HEADER_PART_BVOP 8 /* factor 0.125f *//***************************************************************************** * Structures ****************************************************************************//* Statistics */typedef struct { int type; /* first pass type */ int quant; /* first pass quant */ int blks[3]; /* k,m,y blks */ int length; /* first pass length */ int invariant; /* what we assume as being invariant between the two passes, it's a sub part of header + MV bits */ int scaled_length; /* scaled length */ int desired_length; /* desired length; calculated during encoding */ int error; int zone_mode; /* XVID_ZONE_xxx */ double weight;} twopass_stat_t;/* Context struct */typedef struct{ xvid_plugin_2pass2_t param; /*---------------------------------- * constant statistical data *--------------------------------*/ /* Number of frames of the sequence */ int num_frames; /* Number of Intra frames of the sequence */ int num_keyframes; /* Target filesize to reach */ uint64_t target; /* Count of each frame types */ int count[3]; /* Total length of each frame types (1st pass) */ uint64_t tot_length[3]; uint64_t tot_invariant[3]; /* Average length of each frame types (used first for 1st pass data and * then for scaled averages */ double avg_length[3]; /* Minimum frame length allowed for each frame type */ int min_length[3]; /* Total bytes per frame type once the curve has been scaled * NB: advanced parameters do not change this value. This field * represents the total scaled w/o any advanced settings */ uint64_t tot_scaled_length[3]; /* Maximum observed frame size observed during the first pass, the RC * will try tp force all frame sizes in the second pass to be under that * limit */ int max_length; /*---------------------------------- * Zones statistical data *--------------------------------*/ /* Total length used by XVID_ZONE_QUANT zones */ uint64_t tot_quant; uint64_t tot_quant_invariant; /* Holds the total amount of frame bytes, zone weighted (only scalable * part of frame bytes) */ uint64_t tot_weighted; /*---------------------------------- * Advanced settings helper ratios *--------------------------------*/ /* This the ratio that has to be applied to all p/b frames in order * to reserve/retrieve bits for/from keyframe boosting and consecutive * keyframe penalty */ double pb_iboost_tax_ratio; /* This the ratio to apply to all b/p frames in order to respect the * assymetric curve compression while respecting a target filesize * NB: The assymetric delta gain has to be computed before this ratio * is applied, and then the delta is added to the scaled size */ double assymetric_tax_ratio; /*---------------------------------- * Data from the stats file kept * into RAM for easy access *--------------------------------*/ /* Array of keyframe locations * eg: rc->keyframe_locations[100] returns the frame number of the 100th * keyframe */ int *keyframe_locations; /* Index of the last keyframe used in the keyframe_location */ int KF_idx; /* Array of all 1st pass data file -- see the twopass_stat_t structure * definition for more details */ twopass_stat_t * stats; /*---------------------------------- * Histerysis helpers *--------------------------------*/ /* This field holds the int2float conversion errors of each quant per * frame type, this allow the RC to keep track of rouding error and thus * increase or decrease the chosen quant according to this residue */ double quant_error[3][32]; /* This fields stores the count of each quant usage per frame type * No real role but for debugging */ int quant_count[3][32]; /* Last valid quantizer used per frame type, it allows quantizer * increament/decreament limitation in order to avoid big image quality * "jumps" */ int last_quant[3]; /*---------------------------------- * Overflow control *--------------------------------*/ /* Current overflow that has to be distributed to p/b frames */ double overflow; /* Total overflow for keyframes -- not distributed directly */ double KFoverflow; /* Amount of keyframe overflow to introduce to the global p/b frame * overflow counter at each encoded frame */ double KFoverflow_partial; /* Unknown ??? * ToDo: description */ double fq_error; int min_quant; /* internal minimal quant, prevents wrong quants from being used */ /*---------------------------------- * Debug *--------------------------------*/ double desired_total; double real_total;} rc_2pass2_t;/***************************************************************************** * Sub plugin functions prototypes ****************************************************************************/static int rc_2pass2_create(xvid_plg_create_t * create, rc_2pass2_t ** handle);static int rc_2pass2_before(rc_2pass2_t * rc, xvid_plg_data_t * data);static int rc_2pass2_after(rc_2pass2_t * rc, xvid_plg_data_t * data);static int rc_2pass2_destroy(rc_2pass2_t * rc, xvid_plg_destroy_t * destroy);/***************************************************************************** * Plugin definition ****************************************************************************/intxvid_plugin_2pass2(void * handle, int opt, void * param1, void * param2){ switch(opt) { case XVID_PLG_INFO : case XVID_PLG_FRAME : return 0; case XVID_PLG_CREATE : return rc_2pass2_create((xvid_plg_create_t*)param1, param2); case XVID_PLG_DESTROY : return rc_2pass2_destroy((rc_2pass2_t*)handle, (xvid_plg_destroy_t*)param1); case XVID_PLG_BEFORE : return rc_2pass2_before((rc_2pass2_t*)handle, (xvid_plg_data_t*)param1); case XVID_PLG_AFTER : return rc_2pass2_after((rc_2pass2_t*)handle, (xvid_plg_data_t*)param1); } return XVID_ERR_FAIL;}/***************************************************************************** * Sub plugin functions definitions ****************************************************************************//* First a few local helping function prototypes */static int statsfile_count_frames(rc_2pass2_t * rc, char * filename);static int statsfile_load(rc_2pass2_t *rc, char * filename);static void zone_process(rc_2pass2_t *rc, const xvid_plg_create_t * create);static void first_pass_stats_prepare_data(rc_2pass2_t * rc);static void first_pass_scale_curve_internal(rc_2pass2_t *rc);static void scaled_curve_apply_advanced_parameters(rc_2pass2_t * rc);#if 0static void stats_print(rc_2pass2_t * rc);#endif/*---------------------------------------------------------------------------- *--------------------------------------------------------------------------*/static intrc_2pass2_create(xvid_plg_create_t * create, rc_2pass2_t **handle){ xvid_plugin_2pass2_t * param = (xvid_plugin_2pass2_t *)create->param; rc_2pass2_t * rc; int i; rc = malloc(sizeof(rc_2pass2_t)); if (rc == NULL) return XVID_ERR_MEMORY; rc->param = *param; /* Initialize all defaults */#define _INIT(a, b) if((a) <= 0) (a) = (b) /* Let's set our defaults if needed */ _INIT(rc->param.keyframe_boost, DEFAULT_KEYFRAME_BOOST); _INIT(rc->param.overflow_control_strength, DEFAULT_OVERFLOW_CONTROL_STRENGTH); _INIT(rc->param.curve_compression_high, DEFAULT_CURVE_COMPRESSION_HIGH); _INIT(rc->param.curve_compression_low, DEFAULT_CURVE_COMPRESSION_LOW); _INIT(rc->param.max_overflow_improvement, DEFAULT_MAX_OVERFLOW_IMPROVEMENT); _INIT(rc->param.max_overflow_degradation, DEFAULT_MAX_OVERFLOW_DEGRADATION); /* Keyframe settings */ _INIT(rc->param.kfreduction, DEFAULT_KFREDUCTION); _INIT(rc->param.kfthreshold, DEFAULT_KFTHRESHOLD);#undef _INIT /* Initialize some stuff to zero */ for(i=0; i<3; i++) { int j; for (j=0; j<32; j++) { rc->quant_error[i][j] = 0; rc->quant_count[i][j] = 0; } } for (i=0; i<3; i++) rc->last_quant[i] = 0; rc->fq_error = 0; rc->min_quant = 1; /* Count frames (and intra frames) in the stats file, store the result into * the rc structure */ if (statsfile_count_frames(rc, param->filename) == -1) { DPRINTF(XVID_DEBUG_RC,"[xvid rc] -- ERROR: fopen %s failed\n", param->filename); free(rc); return(XVID_ERR_FAIL); } /* Allocate the stats' memory */ if ((rc->stats = malloc(rc->num_frames * sizeof(twopass_stat_t))) == NULL) { free(rc); return(XVID_ERR_MEMORY); } /* Allocate keyframes location's memory * PS: see comment in pre_process0 for the +1 location requirement */ rc->keyframe_locations = malloc((rc->num_keyframes + 1) * sizeof(int)); if (rc->keyframe_locations == NULL) { free(rc->stats); free(rc); return(XVID_ERR_MEMORY); } /* Load the first pass stats */ if (statsfile_load(rc, param->filename) == -1) { DPRINTF(XVID_DEBUG_RC,"[xvid rc] -- ERROR: fopen %s failed\n", param->filename); free(rc->keyframe_locations); free(rc->stats); free(rc); return XVID_ERR_FAIL; } /* Compute the target filesize */ if (rc->param.bitrate<0) { /* if negative, bitrate equals the target (in kbytes) */ rc->target = ((uint64_t)(-rc->param.bitrate)) * 1024; } else if (rc->num_frames < create->fbase/create->fincr) { /* Source sequence is less than 1s long, we do as if it was 1s long */ rc->target = rc->param.bitrate / 8; } else { /* Target filesize = bitrate/8 * numframes / framerate */ rc->target = ((uint64_t)rc->param.bitrate * (uint64_t)rc->num_frames * \ (uint64_t)create->fincr) / \ ((uint64_t)create->fbase * 8); } DPRINTF(XVID_DEBUG_RC, "[xvid rc] -- Frame rate: %d/%d (%ffps)\n", create->fbase, create->fincr, (double)create->fbase/(double)create->fincr); DPRINTF(XVID_DEBUG_RC, "[xvid rc] -- Number of frames: %d\n", rc->num_frames); if(rc->param.bitrate>=0) DPRINTF(XVID_DEBUG_RC, "[xvid rc] -- Target bitrate: %ld\n", rc->param.bitrate); DPRINTF(XVID_DEBUG_RC, "[xvid rc] -- Target filesize: %lld\n", rc->target); /* Compensate the average frame overhead caused by the container */ rc->target -= rc->num_frames*rc->param.container_frame_overhead;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -