📄 encoder.c
字号:
/*****************************************************************************
* x264: h264 encoder
*****************************************************************************
* Copyright (C) 2003 Laurent Aimar
* $Id: encoder.c,v 1.1 2004/06/03 19:27:08 fenrir Exp $
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* 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.
*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "common/common.h"
#include "common/cpu.h"
#include "set.h"
#include "analyse.h"
#include "ratecontrol.h"
#include "macroblock.h"
#if VISUALIZE
#include "common/visualize.h"
#endif
//#define DEBUG_MB_TYPE
//#define DEBUG_DUMP_FRAME
//#define DEBUG_BENCHMARK
#ifdef DEBUG_BENCHMARK
static int64_t i_mtime_encode_frame = 0;
static int64_t i_mtime_analyse = 0;
static int64_t i_mtime_encode = 0;
static int64_t i_mtime_write = 0;
static int64_t i_mtime_filter = 0;
#define TIMER_START( d ) \
{ \
int64_t d##start = x264_mdate();
#define TIMER_STOP( d ) \
d += x264_mdate() - d##start;\
}
#else
#define TIMER_START( d )
#define TIMER_STOP( d )
#endif
#define NALU_OVERHEAD 5 // startcode + NAL type costs 5 bytes per frame
/****************************************************************************
*
******************************* x264 libs **********************************
*
****************************************************************************/
static float x264_psnr( int64_t i_sqe, int64_t i_size )
{
double f_mse = (double)i_sqe / ((double)65025.0 * (double)i_size);
if( f_mse <= 0.0000000001 ) /* Max 100dB */
return 100;
return (float)(-10.0 * log( f_mse ) / log( 10.0 ));
}
#ifdef DEBUG_DUMP_FRAME
static void x264_frame_dump( x264_t *h, x264_frame_t *fr, char *name )
{
FILE *f = fopen( name, "r+b" );
int i, y;
if( !f )
return;
/* Write the frame in display order */
fseek( f, fr->i_frame * h->param.i_height * h->param.i_width * 3 / 2, SEEK_SET );
for( i = 0; i < fr->i_plane; i++ )
{
for( y = 0; y < h->param.i_height / ( i == 0 ? 1 : 2 ); y++ )
{
fwrite( &fr->plane[i][y*fr->i_stride[i]], 1, h->param.i_width / ( i == 0 ? 1 : 2 ), f );
}
}
fclose( f );
}
#endif
/* Fill "default" values */
static void x264_slice_header_init( x264_t *h, x264_slice_header_t *sh,
x264_sps_t *sps, x264_pps_t *pps,
int i_type, int i_idr_pic_id, int i_frame, int i_qp )
{
x264_param_t *param = &h->param;
int i;
/* First we fill all field */
sh->sps = sps;
sh->pps = pps;
sh->i_type = i_type;
sh->i_first_mb = 0;
sh->i_last_mb = h->sps->i_mb_width * h->sps->i_mb_height;
sh->i_pps_id = pps->i_id;
sh->i_frame_num = i_frame;
sh->b_field_pic = 0; /* Not field support for now */
sh->b_bottom_field = 1; /* not yet used */
sh->i_idr_pic_id = i_idr_pic_id;
/* poc stuff, fixed later */
sh->i_poc_lsb = 0;
sh->i_delta_poc_bottom = 0;
sh->i_delta_poc[0] = 0;
sh->i_delta_poc[1] = 0;
sh->i_redundant_pic_cnt = 0;
if( !h->mb.b_direct_auto_read )
{
if( h->mb.b_direct_auto_write )
sh->b_direct_spatial_mv_pred = ( h->stat.i_direct_score[1] > h->stat.i_direct_score[0] );
else
sh->b_direct_spatial_mv_pred = ( param->analyse.i_direct_mv_pred == X264_DIRECT_PRED_SPATIAL );
}
/* else b_direct_spatial_mv_pred was read from the 2pass statsfile */
sh->b_num_ref_idx_override = 0;
sh->i_num_ref_idx_l0_active = 1;
sh->i_num_ref_idx_l1_active = 1;
sh->b_ref_pic_list_reordering_l0 = h->b_ref_reorder[0];
sh->b_ref_pic_list_reordering_l1 = h->b_ref_reorder[1];
/* If the ref list isn't in the default order, construct reordering header */
/* List1 reordering isn't needed yet */
if( sh->b_ref_pic_list_reordering_l0 )
{
int pred_frame_num = i_frame;
for( i = 0; i < h->i_ref0; i++ )
{
int diff = h->fref0[i]->i_frame_num - pred_frame_num;
if( diff == 0 )
x264_log( h, X264_LOG_ERROR, "diff frame num == 0\n" );
sh->ref_pic_list_order[0][i].idc = ( diff > 0 );
sh->ref_pic_list_order[0][i].arg = abs( diff ) - 1;
pred_frame_num = h->fref0[i]->i_frame_num;
}
}
sh->i_cabac_init_idc = param->i_cabac_init_idc;
sh->i_qp = i_qp;
sh->i_qp_delta = i_qp - pps->i_pic_init_qp;
sh->b_sp_for_swidth = 0;
sh->i_qs_delta = 0;
/* If effective qp <= 15, deblocking would have no effect anyway */
if( param->b_deblocking_filter
&& ( h->mb.b_variable_qp
|| 15 < i_qp + 2 * X264_MAX(param->i_deblocking_filter_alphac0, param->i_deblocking_filter_beta) ) )
{
sh->i_disable_deblocking_filter_idc = 0;
}
else
{
sh->i_disable_deblocking_filter_idc = 1;
}
sh->i_alpha_c0_offset = param->i_deblocking_filter_alphac0 << 1;
sh->i_beta_offset = param->i_deblocking_filter_beta << 1;
}
static void x264_slice_header_write( bs_t *s, x264_slice_header_t *sh, int i_nal_ref_idc )
{
int i;
bs_write_ue( s, sh->i_first_mb );
bs_write_ue( s, sh->i_type + 5 ); /* same type things */
bs_write_ue( s, sh->i_pps_id );
bs_write( s, sh->sps->i_log2_max_frame_num, sh->i_frame_num );
if( sh->i_idr_pic_id >= 0 ) /* NAL IDR */
{
bs_write_ue( s, sh->i_idr_pic_id );
}
if( sh->sps->i_poc_type == 0 )
{
bs_write( s, sh->sps->i_log2_max_poc_lsb, sh->i_poc_lsb );
if( sh->pps->b_pic_order && !sh->b_field_pic )
{
bs_write_se( s, sh->i_delta_poc_bottom );
}
}
else if( sh->sps->i_poc_type == 1 && !sh->sps->b_delta_pic_order_always_zero )
{
bs_write_se( s, sh->i_delta_poc[0] );
if( sh->pps->b_pic_order && !sh->b_field_pic )
{
bs_write_se( s, sh->i_delta_poc[1] );
}
}
if( sh->pps->b_redundant_pic_cnt )
{
bs_write_ue( s, sh->i_redundant_pic_cnt );
}
if( sh->i_type == SLICE_TYPE_B )
{
bs_write1( s, sh->b_direct_spatial_mv_pred );
}
if( sh->i_type == SLICE_TYPE_P || sh->i_type == SLICE_TYPE_SP || sh->i_type == SLICE_TYPE_B )
{
bs_write1( s, sh->b_num_ref_idx_override );
if( sh->b_num_ref_idx_override )
{
bs_write_ue( s, sh->i_num_ref_idx_l0_active - 1 );
if( sh->i_type == SLICE_TYPE_B )
{
bs_write_ue( s, sh->i_num_ref_idx_l1_active - 1 );
}
}
}
/* ref pic list reordering */
if( sh->i_type != SLICE_TYPE_I )
{
bs_write1( s, sh->b_ref_pic_list_reordering_l0 );
if( sh->b_ref_pic_list_reordering_l0 )
{
for( i = 0; i < sh->i_num_ref_idx_l0_active; i++ )
{
bs_write_ue( s, sh->ref_pic_list_order[0][i].idc );
bs_write_ue( s, sh->ref_pic_list_order[0][i].arg );
}
bs_write_ue( s, 3 );
}
}
if( sh->i_type == SLICE_TYPE_B )
{
bs_write1( s, sh->b_ref_pic_list_reordering_l1 );
if( sh->b_ref_pic_list_reordering_l1 )
{
for( i = 0; i < sh->i_num_ref_idx_l1_active; i++ )
{
bs_write_ue( s, sh->ref_pic_list_order[1][i].idc );
bs_write_ue( s, sh->ref_pic_list_order[1][i].arg );
}
bs_write_ue( s, 3 );
}
}
if( ( sh->pps->b_weighted_pred && ( sh->i_type == SLICE_TYPE_P || sh->i_type == SLICE_TYPE_SP ) ) ||
( sh->pps->b_weighted_bipred == 1 && sh->i_type == SLICE_TYPE_B ) )
{
/* FIXME */
}
if( i_nal_ref_idc != 0 )
{
if( sh->i_idr_pic_id >= 0 )
{
bs_write1( s, 0 ); /* no output of prior pics flag */
bs_write1( s, 0 ); /* long term reference flag */
}
else
{
bs_write1( s, 0 ); /* adaptive_ref_pic_marking_mode_flag */
}
}
if( sh->pps->b_cabac && sh->i_type != SLICE_TYPE_I )
{
bs_write_ue( s, sh->i_cabac_init_idc );
}
bs_write_se( s, sh->i_qp_delta ); /* slice qp delta */
if( sh->pps->b_deblocking_filter_control )
{
bs_write_ue( s, sh->i_disable_deblocking_filter_idc );
if( sh->i_disable_deblocking_filter_idc != 1 )
{
bs_write_se( s, sh->i_alpha_c0_offset >> 1 );
bs_write_se( s, sh->i_beta_offset >> 1 );
}
}
}
/****************************************************************************
*
****************************************************************************
****************************** External API*********************************
****************************************************************************
*
****************************************************************************/
static int x264_validate_parameters( x264_t *h )
{
if( h->param.i_width <= 0 || h->param.i_height <= 0 )
{
x264_log( h, X264_LOG_ERROR, "invalid width x height (%dx%d)\n",
h->param.i_width, h->param.i_height );
return -1;
}
if( h->param.i_width % 2 || h->param.i_height % 2 )
{
x264_log( h, X264_LOG_ERROR, "width or height not divisible by 2 (%dx%d)\n",
h->param.i_width, h->param.i_height );
return -1;
}
if( h->param.i_csp != X264_CSP_I420 )
{
x264_log( h, X264_LOG_ERROR, "invalid CSP (only I420 supported)\n" );
return -1;
}
h->param.i_threads = x264_clip3( h->param.i_threads, 1, X264_SLICE_MAX );
h->param.i_threads = X264_MIN( h->param.i_threads, (h->param.i_height + 15) / 16 );
#ifndef HAVE_PTHREAD
if( h->param.i_threads > 1 )
{
x264_log( h, X264_LOG_WARNING, "not compiled with pthread support!\n");
x264_log( h, X264_LOG_WARNING, "multislicing anyway, but you won't see any speed gain.\n" );
}
#endif
if( h->param.rc.b_cbr )
h->param.rc.i_rf_constant = 0;
if( h->param.rc.i_rf_constant > 0 )
h->param.rc.i_qp_constant = h->param.rc.i_rf_constant;
h->param.rc.i_rf_constant = x264_clip3( h->param.rc.i_rf_constant, 0, 51 );
h->param.rc.i_qp_constant = x264_clip3( h->param.rc.i_qp_constant, 0, 51 );
if( !h->param.rc.b_cbr && h->param.rc.i_qp_constant == 0 )
{
h->mb.b_lossless = 1;
h->param.analyse.b_transform_8x8 = 0;
h->param.i_cqm_preset = X264_CQM_FLAT;
h->param.psz_cqm_file = NULL;
h->param.rc.f_ip_factor = 1;
h->param.rc.f_pb_factor = 1;
h->param.analyse.b_psnr = 0;
h->param.analyse.i_chroma_qp_offset = 0;
h->param.analyse.i_trellis = 0;
h->param.analyse.b_fast_pskip = 0;
h->param.analyse.i_noise_reduction = 0;
h->param.analyse.i_subpel_refine = x264_clip3( h->param.analyse.i_subpel_refine, 1, 6 );
}
if( ( h->param.i_width % 16 || h->param.i_height % 16 ) && !h->mb.b_lossless )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -