plugin_2pass2.c

来自「从FFMPEG转换而来的H264解码程序,VC下编译..」· C语言 代码 · 共 1,857 行 · 第 1/4 页

C
1,857
字号
/******************************************************************************
 *
 *  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: plugin_2pass2.c,v 1.7 2005/03/27 03:59:42 suxen_drol Exp $
 *
 *****************************************************************************/

#define BQUANT_PRESCALE
#undef COMPENSATE_FORMULA

/* forces second pass not to be bigger than first */
#undef PASS_SMALLER

/* automatically 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;

	/*----------------------------------
	 * Hysteresis 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
 ****************************************************************************/

int
xvid_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);
static  int check_curve_for_vbv_compliancy(rc_2pass2_t * rc, const float fps);
static  int scale_curve_for_vbv_compliancy(rc_2pass2_t * rc, const float fps);
#if 0
static void stats_print(rc_2pass2_t * rc);
#endif

/*----------------------------------------------------------------------------
 *--------------------------------------------------------------------------*/

static int
rc_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;

	/* v1.0.x */
	rc->param.version = param->version;
	rc->param.bitrate = param->bitrate;
	rc->param.filename = param->filename;
	rc->param.keyframe_boost = param->keyframe_boost;
	rc->param.curve_compression_high = param->curve_compression_high;
	rc->param.curve_compression_low = param->curve_compression_low;
	rc->param.overflow_control_strength = param->overflow_control_strength;
	rc->param.max_overflow_improvement = param->max_overflow_improvement;
	rc->param.max_overflow_degradation = param->max_overflow_degradation;
	rc->param.kfreduction = param->kfreduction;
	rc->param.kfthreshold = param->kfthreshold;
	rc->param.container_frame_overhead = param->container_frame_overhead;

	if (XVID_VERSION_MINOR(param->version) >= 1) {
		rc->param.vbv_size = param->vbv_size;
		rc->param.vbv_initial = param->vbv_initial;
		rc->param.vbv_maxrate = param->vbv_maxrate;
		rc->param.vbv_peakrate = param->vbv_peakrate;
	}else{
		rc->param.vbv_size =
		rc->param.vbv_initial =
		rc->param.vbv_maxrate =
		rc->param.vbv_peakrate = 0;
	}

	/* 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;
	DPRINTF(XVID_DEBUG_RC, "[xvid rc] -- Container Frame overhead: %d\n", rc->param.container_frame_overhead);
	if(rc->param.container_frame_overhead)
		DPRINTF(XVID_DEBUG_RC, "[xvid rc] -- New target filesize after container compensation: %lld\n", rc->target);

	/* When bitrate is not given it means it has been scaled by an external
	 * application */
	if (rc->param.bitrate) {
		/* Apply zone settings
		 * - set rc->tot_quant which represents the total num of bytes spent in
		 *   fixed quant zones
		 * - set rc->tot_weighted which represents the total amount of bytes
		 *   spent in normal or weighted zones in first pass (normal zones can
		 *   be considered weight=1)
		 * - set rc->tot_quant_invariant which represents the total num of bytes
		 *   spent in fixed quant zones for headers */
		zone_process(rc, create);
	} else {
		/* External scaling -- zones are ignored */
		for (i=0;i<rc->num_frames;i++) {
			rc->stats[i].zone_mode = XVID_ZONE_WEIGHT;
			rc->stats[i].weight = 1.0;
		}
		rc->tot_quant = 0;
	}

	/* Gathers some information about first pass stats:
	 *  - finds the minimum frame length for each frame type during 1st pass.
	 *     rc->min_size[]
	 *  - determines the maximum frame length observed (no frame type distinction).
	 *     rc->max_size
	 *  - count how many times each frame type has been used.
	 *     rc->count[]
	 *  - total bytes used per frame type
	 *     rc->tot_length[]
	 *  - total bytes considered invariant between the 2 passes
	 *  - store keyframe location
	 *     rc->keyframe_locations[]
	 */
	first_pass_stats_prepare_data(rc);

	/* If we have a user bitrate, it means it's an internal curve scaling */
	if (rc->param.bitrate) {
		/* Perform internal curve scaling */
		first_pass_scale_curve_internal(rc);
	}

	/* Apply advanced curve options, and compute some parameters in order to
	 * shape the curve in the BEFORE/AFTER pair of functions */
	scaled_curve_apply_advanced_parameters(rc);

	/* Check curve for VBV compliancy and rescale if necessary */
#ifdef VBV_FORCE
	if (rc->param.vbv_size==0) {
		rc->param.vbv_size      =  3145728;
		rc->param.vbv_initial   =  2359296;
		rc->param.vbv_maxrate   =  4854000;
		rc->param.vbv_peakrate  =  8000000;
	}
#endif

	/* vbv_size==0 switches VBV check off */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?