📄 block.c
字号:
/***************************************************************************** * block.c: MPEG2 video transrating module ***************************************************************************** * Copyright (C) 2003-2004 the VideoLAN team * Copyright (C) 2003 Antoine Missout * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> * $Id: 67e6332caab2e32f3ca95d3244d56611bda2afbe $ * * Authors: Christophe Massiot <massiot@via.ecp.fr> * Laurent Aimar <fenrir@via.ecp.fr> * Antoine Missout * Michel Lespinasse <walken@zoy.org> * Aaron Holtzman <aholtzma@ess.engr.uvic.ca> * * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#define NDEBUG 1#include <assert.h>#include <math.h>#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_sout.h>#include <vlc_codec.h>#include "transrate.h"/**************************************************************************** * transrater, code from M2VRequantizer http://www.metakine.com/ ****************************************************************************//////---- begin ext mpeg code#include "getvlc.h"#include "putvlc.h"static inline int saturate( int i_value ){ if ( i_value > 2047 ) return 2047; if ( i_value < -2048 ) return -2048; return i_value;}static int64_t get_score( const RunLevel *blk, RunLevel *new_blk, int i_qscale, int i_qscale_new ){ int64_t score = 0; int i1 = -1, i2 = -1; while ( new_blk->level ) { int new_level = new_blk->level; int level = blk->level; if ( i1 > 64 || i2 > 64 || !blk->run || !new_blk->run ) return score; if ( i1 + blk->run == i2 + new_blk->run ) { int64_t tmp = saturate(level * i_qscale) - saturate(new_level * i_qscale_new); i1 += blk->run; i2 += new_blk->run; score += tmp * tmp; blk++; new_blk++; } else { int64_t tmp = saturate(level * i_qscale); i1 += blk->run; score += tmp * tmp; blk++; } } while ( blk->level ) { int level = blk->level; int64_t tmp = saturate(level * i_qscale); i1 += blk->run; score += tmp * tmp; blk++; } return score;}static void change_qscale( const RunLevel *blk, RunLevel *new_blk, int i_qscale, int i_qscale_new, int intra ){ int i = 0, li = 0; int rounding; if ( intra ) rounding = i_qscale_new / 3; else rounding = i_qscale_new / 6; while ( blk->level ) { int level = blk->level > 0 ? blk->level : -blk->level; int new_level = saturate(level * i_qscale) / i_qscale_new; i += blk->run; if ( new_level ) { new_blk->run = i - li; new_blk->level = blk->level > 0 ? new_level : -new_level; new_blk++; li = i; } blk++; } new_blk->level = 0;}static const uint8_t non_linear_mquant_table[32] ={ 0, 1, 2, 3, 4, 5, 6, 7, 8,10,12,14,16,18,20,22, 24,28,32,36,40,44,48,52, 56,64,72,80,88,96,104,112};static const uint8_t map_non_linear_mquant[113] ={ 0,1,2,3,4,5,6,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16, 16,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,22,22, 22,22,23,23,23,23,24,24,24,24,24,24,24,25,25,25,25,25,25,25,26,26, 26,26,26,26,26,26,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,29, 29,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,31,31,31,31,31};int scale_quant( transrate_t *tr, double qrate ){ int i_quant = (int)floor( tr->quantizer_scale * qrate + 0.5 ); if ( tr->q_scale_type ) { if ( i_quant < 1 ) i_quant = 1; if ( i_quant > 112 ) i_quant = 112; i_quant = non_linear_mquant_table[map_non_linear_mquant[i_quant]]; } else { if ( i_quant < 2 ) i_quant = 2; if ( i_quant > 62 ) i_quant = 62; i_quant = (i_quant / 2) * 2; // Must be *even* } return i_quant;}int increment_quant( transrate_t *tr, int i_quant ){ if ( tr->q_scale_type ) { assert( i_quant >= 1 && i_quant <= 112 ); i_quant = map_non_linear_mquant[i_quant] + 1; if ( i_quant > 31 ) i_quant = 31; i_quant = non_linear_mquant_table[i_quant]; } else { assert(!(i_quant & 1)); i_quant += 2; if ( i_quant > 62 ) i_quant = 62; } return i_quant;}static int decrement_quant( transrate_t *tr, int i_quant ){ if ( tr->q_scale_type ) { assert( i_quant >= 1 && i_quant <= 112 ); i_quant = map_non_linear_mquant[i_quant] - 1; if ( i_quant < 1 ) i_quant = 1; i_quant = non_linear_mquant_table[i_quant]; } else { assert(!(i_quant & 1)); i_quant -= 2; if ( i_quant < 2 ) i_quant = 2; } return i_quant;}static void quantize_block( transrate_t *tr, RunLevel *new_blk, int intra ){ RunLevel old_blk[65]; RunLevel *blk = old_blk; const uint8_t *old_matrix, *new_matrix; int i = 0, li = 0; memcpy( blk, new_blk, 65 * sizeof(RunLevel) ); if ( intra ) { old_matrix = tr->intra_quantizer_matrix; new_matrix = mpeg4_default_intra_matrix; } else { old_matrix = tr->non_intra_quantizer_matrix; new_matrix = mpeg4_default_non_intra_matrix; } while ( blk->level ) { int level = blk->level > 0 ? blk->level : -blk->level; int new_level = (level * old_matrix[i] + new_matrix[i]/2) / new_matrix[i]; i += blk->run; if (new_level) { new_blk->run = i - li; new_blk->level = blk->level > 0 ? new_level : -new_level; new_blk++; li = i; } blk++; } new_blk->level = 0;}int transrate_mb( transrate_t *tr, RunLevel blk[6][65], RunLevel new_blk[6][65], int i_cbp, int intra ){ int i_qscale = tr->quantizer_scale; int i_guessed_qscale = tr->new_quantizer_scale; int64_t i_last_error = 0; int i_last_qscale; int i_last_qscale_same_error = 0; int i_direction = 0; int i_new_cbp; int i_nb_blocks = 0; int i_nb_coeffs = 0; int i; for ( i = 0; i < 6; i++ ) { if ( i_cbp & (1 << (5 - i)) ) { RunLevel *cur_blk = blk[i]; i_nb_blocks++; while ( cur_blk->level ) { cur_blk++; i_nb_coeffs++; } } } /* See if we can change quantizer scale */ for ( ; ; ) { int64_t i_error = 0; i_new_cbp = 0; for ( i = 0; i < 6; i++ ) { if ( i_cbp & (1 << (5 - i)) ) { int64_t i_block_error; change_qscale( blk[i], new_blk[i], i_qscale, i_guessed_qscale, intra ); i_block_error = get_score( blk[i], new_blk[i], i_qscale, i_guessed_qscale ); if ( i > 3 ) i_block_error *= 4; if ( i_block_error > i_error ) i_error = i_block_error; if ( new_blk[i]->level ) i_new_cbp |= (1 << (5 - i)); } } if ( i_error >= (int64_t)tr->i_minimum_error && i_error <= (int64_t)tr->i_admissible_error ) { break; } if ( i_nb_coeffs <= 15 && i_error <= (int64_t)tr->i_admissible_error ) { /* There is no interest in changing the qscale (takes up 5 bits * we won't regain) */ break; } if ( !i_direction ) { if ( i_error > (int64_t)tr->i_admissible_error ) { i_direction = -1; i_last_qscale = i_guessed_qscale; i_guessed_qscale = decrement_quant( tr, i_guessed_qscale ); } else { i_direction = +1; i_last_qscale = i_guessed_qscale; i_guessed_qscale = increment_quant( tr, i_guessed_qscale ); i_last_error = i_error; i_last_qscale_same_error = i_last_qscale; } if ( i_guessed_qscale == i_last_qscale ) break; } else if ( i_direction < 0 ) { if ( i_error > (int64_t)tr->i_admissible_error ) { i_last_qscale = i_guessed_qscale; i_guessed_qscale = decrement_quant( tr, i_guessed_qscale ); if ( i_guessed_qscale == i_last_qscale ) break; } else { break; } } else { if ( i_error < (int64_t)tr->i_minimum_error ) { i_last_qscale = i_guessed_qscale; i_guessed_qscale = increment_quant( tr, i_guessed_qscale ); if ( i_error > i_last_error ) { i_last_error = i_error; i_last_qscale_same_error = i_last_qscale; } if ( i_guessed_qscale == i_last_qscale ) { if ( i_last_error == i_error ) { i_guessed_qscale = i_last_qscale_same_error; if ( i_guessed_qscale == i_qscale ) { memcpy( new_blk, blk, sizeof(RunLevel)*65*6 ); i_new_cbp = i_cbp; } else { i_new_cbp = 0; for ( i = 0; i < 6; i++ ) { if ( i_cbp & (1 << (5 - i)) ) { change_qscale( blk[i], new_blk[i], i_qscale, i_guessed_qscale, intra ); if ( new_blk[i]->level ) i_new_cbp |= (1 << (5 - i)); } } } } break; } } else { if ( i_error > (int64_t)tr->i_admissible_error || i_last_error == i_error ) { i_guessed_qscale = i_last_qscale_same_error; if ( i_guessed_qscale == i_qscale ) { memcpy( new_blk, blk, sizeof(RunLevel)*65*6 ); i_new_cbp = i_cbp; } else { i_new_cbp = 0; for ( i = 0; i < 6; i++ ) { if ( i_cbp & (1 << (5 - i)) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -