⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rdo.c

📁 X264的纯C语言的的原码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************
 * rdo.c: h264 encoder library (rate-distortion optimization)
 *****************************************************************************
 * Copyright (C) 2005 x264 project
 *
 * Authors: Loren Merritt <lorenm@u.washington.edu>
 *
 * 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, USA.
 *****************************************************************************/

/* duplicate all the writer functions, just calculating bit cost
 * instead of writing the bitstream.
 * TODO: use these for fast 1st pass too. */

#define RDO_SKIP_BS

/* CAVLC: produces exactly the same bit count as a normal encode */
/* this probably still leaves some unnecessary computations */
/*#define bs_write1(s,v)     ((s)->i_bits_encoded += 1)
#define bs_write(s,n,v)    ((s)->i_bits_encoded += (n))
#define bs_write_ue(s,v)   ((s)->i_bits_encoded += bs_size_ue(v))
#define bs_write_se(s,v)   ((s)->i_bits_encoded += bs_size_se(v))
#define bs_write_te(s,v,l) ((s)->i_bits_encoded += bs_size_te(v,l))*/
#define x264_macroblock_write_cavlc  x264_macroblock_size_cavlc
#include "cavlc.c"

/* CABAC: not exactly the same. x264_cabac_size_decision() keeps track of
 * fractional bits, but only finite precision. */
#define x264_cabac_encode_decision(c,x,v) x264_cabac_size_decision(c,x,v)
#define x264_cabac_encode_terminal(c,v)   x264_cabac_size_decision(c,276,v)
#define x264_cabac_encode_bypass(c,v)     ((c)->f8_bits_encoded += 256)
#define x264_cabac_encode_flush(c)
///#define x264_macroblock_write_cabac  x264_macroblock_size_cabac
#define x264_cabac_mb_skip  x264_cabac_mb_size_skip_unused
///#include "encabac.c"


static int ssd_mb( x264_t *h )
{
    return h->pixf.ssd[PIXEL_16x16]( h->mb.pic.p_fenc[0], FENC_STRIDE,
                                     h->mb.pic.p_fdec[0], FDEC_STRIDE )
         + h->pixf.ssd[PIXEL_8x8](   h->mb.pic.p_fenc[1], FENC_STRIDE,
                                     h->mb.pic.p_fdec[1], FDEC_STRIDE )
         + h->pixf.ssd[PIXEL_8x8](   h->mb.pic.p_fenc[2], FENC_STRIDE,
                                     h->mb.pic.p_fdec[2], FDEC_STRIDE );
}

static int ssd_plane( x264_t *h, int size, int p, int x, int y )
{
    return h->pixf.ssd[size]( h->mb.pic.p_fenc[p] + x+y*FENC_STRIDE, FENC_STRIDE,
                              h->mb.pic.p_fdec[p] + x+y*FDEC_STRIDE, FDEC_STRIDE );
}

static int x264_rd_cost_mb( x264_t *h, int i_lambda2 )
{
    int b_transform_bak = h->mb.b_transform_8x8;
    int i_ssd;
    int i_bits;

    x264_macroblock_encode( h );

    i_ssd = ssd_mb( h );

    if( IS_SKIP( h->mb.i_type ) )
    {
        i_bits = 1 * i_lambda2;
    }
/*    else if( h->param.b_cabac )
    {
        x264_cabac_t cabac_tmp = h->cabac;
        cabac_tmp.f8_bits_encoded = 0;
        x264_macroblock_size_cabac( h, &cabac_tmp );
        i_bits = ( cabac_tmp.f8_bits_encoded * i_lambda2 + 128 ) >> 8;
    }*/
    else
    {
        bs_t bs_tmp = h->out.bs;
        bs_tmp.i_bits_encoded = 0;
        x264_macroblock_size_cavlc( h, &bs_tmp );
        i_bits = bs_tmp.i_bits_encoded * i_lambda2;
    }

    h->mb.b_transform_8x8 = b_transform_bak;

    return i_ssd + i_bits;
}

int x264_rd_cost_part( x264_t *h, int i_lambda2, int i8, int i_pixel )
{
    int i_ssd, i_bits;

    if( i_pixel == PIXEL_16x16 )
    {
        int type_bak = h->mb.i_type;
        int i_cost = x264_rd_cost_mb( h, i_lambda2 );
        h->mb.i_type = type_bak;
        return i_cost;
    }

    x264_macroblock_encode_p8x8( h, i8 );
    if( i_pixel == PIXEL_16x8 )
        x264_macroblock_encode_p8x8( h, i8+1 );
    if( i_pixel == PIXEL_8x16 )
        x264_macroblock_encode_p8x8( h, i8+2 );

    i_ssd = ssd_plane( h, i_pixel,   0, (i8&1)*8, (i8>>1)*8 )
          + ssd_plane( h, i_pixel+3, 1, (i8&1)*4, (i8>>1)*4 )
          + ssd_plane( h, i_pixel+3, 2, (i8&1)*4, (i8>>1)*4 );

/*    if( h->param.b_cabac )
    {
        x264_cabac_t cabac_tmp = h->cabac;
        cabac_tmp.f8_bits_encoded = 0;
        x264_partition_size_cabac( h, &cabac_tmp, i8, i_pixel );
        i_bits = ( cabac_tmp.f8_bits_encoded * i_lambda2 + 128 ) >> 8;
    }
    else
    {*/
        i_bits = x264_partition_size_cavlc( h, i8, i_pixel ) * i_lambda2;
///    }

    return i_ssd + i_bits;
}

int x264_rd_cost_i8x8( x264_t *h, int i_lambda2, int i8, int i_mode )
{
    int i_ssd, i_bits;

    x264_mb_encode_i8x8( h, i8, h->mb.i_qp );
    i_ssd = ssd_plane( h, PIXEL_8x8, 0, (i8&1)*8, (i8>>1)*8 );

/*    if( h->param.b_cabac )
    {
        x264_cabac_t cabac_tmp = h->cabac;
        cabac_tmp.f8_bits_encoded = 0;
        x264_partition_i8x8_size_cabac( h, &cabac_tmp, i8, i_mode );
        i_bits = ( cabac_tmp.f8_bits_encoded * i_lambda2 + 128 ) >> 8;
    }
    else
    {*/
        i_bits = x264_partition_i8x8_size_cavlc( h, i8, i_mode ) * i_lambda2;
  ///  }

    return i_ssd + i_bits;
}

int x264_rd_cost_i4x4( x264_t *h, int i_lambda2, int i4, int i_mode )
{
    int i_ssd, i_bits;

    x264_mb_encode_i4x4( h, i4, h->mb.i_qp );
    i_ssd = ssd_plane( h, PIXEL_4x4, 0, block_idx_x[i4]*4, block_idx_y[i4]*4 );

/*    if( h->param.b_cabac )
    {
        x264_cabac_t cabac_tmp = h->cabac;
        cabac_tmp.f8_bits_encoded = 0;
        x264_partition_i4x4_size_cabac( h, &cabac_tmp, i4, i_mode );
        i_bits = ( cabac_tmp.f8_bits_encoded * i_lambda2 + 128 ) >> 8;
    }
    else
    {*/
        i_bits = x264_partition_i4x4_size_cavlc( h, i4, i_mode ) * i_lambda2;
 ///   }

    return i_ssd + i_bits;
}

/****************************************************************************
 * Trellis RD quantization
 ****************************************************************************/

#define TRELLIS_SCORE_MAX ((uint64_t)1<<50)
#define CABAC_SIZE_BITS 8
#define SSD_WEIGHT_BITS 5
#define LAMBDA_BITS 4

/* precalculate the cost of coding abs_level_m1 */
static int cabac_prefix_transition[15][128];
static int cabac_prefix_size[15][128];
/*void x264_rdo_init( )
{
    int i_prefix;
    int i_ctx;
    for( i_prefix = 0; i_prefix < 15; i_prefix++ )
    {
        for( i_ctx = 0; i_ctx < 128; i_ctx++ )
        {
            int f8_bits = 0;
            uint8_t ctx = i_ctx;
            int i;

            for( i = 1; i < i_prefix; i++ )
                f8_bits += x264_cabac_size_decision2( &ctx, 1 );
            if( i_prefix > 0 && i_prefix < 14 )
                f8_bits += x264_cabac_size_decision2( &ctx, 0 );
            f8_bits += 1 << CABAC_SIZE_BITS; //sign

            cabac_prefix_size[i_prefix][i_ctx] = f8_bits;
            cabac_prefix_transition[i_prefix][i_ctx] = ctx;
        }
    }
}*/

// node ctx: 0..3: abslevel1 (with abslevelgt1 == 0).
//           4..7: abslevelgt1 + 3 (and abslevel1 doesn't matter).
/* map node ctx => cabac ctx for level=1 */
static const int coeff_abs_level1_ctx[8] = { 1, 2, 3, 4, 0, 0, 0, 0 };
/* map node ctx => cabac ctx for level>1 */
static const int coeff_abs_levelgt1_ctx[8] = { 5, 5, 5, 5, 6, 7, 8, 9 };
static const int coeff_abs_level_transition[2][8] = {
/* update node.ctx after coding a level=1 */
    { 1, 2, 3, 3, 4, 5, 6, 7 },
/* update node.ctx after coding a level>1 */
   { 4, 4, 4, 4, 5, 6, 7, 7 }
};

static const int lambda2_tab[6] = { 1024, 1290, 1625, 2048, 2580, 3251 };

typedef struct {
    uint64_t score;
    int level_idx; // index into level_tree[]
    uint8_t cabac_state[10]; //just the contexts relevant to coding abs_level_m1
} trellis_node_t;

// TODO:
// support chroma and i16x16 DC
// save cabac state between blocks?
// use trellis' RD score instead of x264_mb_decimate_score?
// code 8x8 sig/last flags forwards with deadzone and save the contexts at
//   each position?

⌨️ 快捷键说明

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