#include "libavcodec/avcodec.h"
#include "common/common.h"
// define structure
typedef struct {
int width;
int height;
int bitrate;
int framerate;
int i_interval;
} OUTPUT_PARAMS;
typedef struct {
OUTPUT_PARAMS OutParams;
x264_t *pX264EncHandle;
x264_param_t X264InitParam;
x264_picture_t X264Picture;
} ENCODER_OBJ;
typedef struct {
int width;
int height;
int stride;
unsigned char *py;
unsigned char *pcb;
unsigned char *pcr;
unsigned int pts;
} IMG_INFO;
ENCODER_OBJ g_Encoder;
// user setting
void X264_Params_UserSetting( x264_param_t *param )
{
param->i_threads = X264_THREADS_AUTO;
param->b_deterministic = 0;
param->i_sync_lookahead = X264_SYNC_LOOKAHEAD_AUTO;
// param->i_level_idc = 31;
/* Video properties */
param->i_csp = X264_CSP_I420;
param->i_width = 0;
param->i_height = 0;
param->vui.i_sar_width = 0;
param->vui.i_sar_height = 0;
param->vui.i_overscan = 0; /* undef */
param->vui.i_vidformat = 5; /* undef */
param->vui.b_fullrange = 0; /* off */
param->vui.i_colorprim = 2; /* undef */
param->vui.i_transfer = 2; /* undef */
param->vui.i_colmatrix = 2; /* undef */
param->vui.i_chroma_loc = 0; /* left center */
param->i_fps_num = 30;
param->i_fps_den = 1;
param->i_level_idc = -1;
param->i_slice_max_size = 0;
param->i_slice_max_mbs = 0;
param->i_slice_count = 0;
/* Encoder parameters */
param->i_frame_reference = 1;
param->i_keyint_max = 300;
param->i_keyint_min = X264_KEYINT_MIN_AUTO;
param->i_bframe = 0; // i_delay += i_bframe
param->i_scenecut_threshold = 40; // rarely needs to be adjusted. default=40
param->i_bframe_adaptive = X264_B_ADAPT_NONE; // recommand(X264_B_ADAPT_FAST==1)
param->i_bframe_bias = 0;
param->i_bframe_pyramid = X264_B_PYRAMID_NONE;
param->b_interlaced = 0;
param->b_constrained_intra = 0;
param->b_deblocking_filter = 1;
param->i_deblocking_filter_alphac0 = 0;
param->i_deblocking_filter_beta = 0;
param->b_cabac = 0;
param->i_cabac_init_idc = 0;
param->rc.i_rc_method = 0;//X264_RC_CRF;
param->rc.i_bitrate = 0;
param->rc.f_rate_tolerance = 1.0;
param->rc.i_vbv_max_bitrate = 0;
param->rc.i_vbv_buffer_size = 0;
param->rc.f_vbv_buffer_init = 0.9;
param->rc.i_qp_constant = 23 + QP_BD_OFFSET;
param->rc.f_rf_constant = 23;
param->rc.i_qp_min = 10;
param->rc.i_qp_max = 51; //QP_MAX;
param->rc.i_qp_step = 4;
param->rc.f_ip_factor = 1.4; //default, 1.4;
param->rc.f_pb_factor = 1.3;
param->rc.i_aq_mode = X264_AQ_VARIANCE;
param->rc.f_aq_strength = 1.0;
param->rc.i_lookahead = 1;
param->rc.b_stat_write = 0;
// param->rc.psz_stat_out = "x264_2pass.log";
param->rc.b_stat_read = 0;
// param->rc.psz_stat_in = "x264_2pass.log";
param->rc.f_qcompress = 0.6;
param->rc.f_qblur = 0.5;
param->rc.f_complexity_blur = 20;
param->rc.i_zones = 0;
param->rc.b_mb_tree = 1;
/* Log */
// param->pf_log = x264_log_default;
param->p_log_private = NULL;
param->i_log_level = X264_LOG_NONE; //X264_LOG_INFO;
/* */
param->analyse.intra = X264_ANALYSE_I4x4 | X264_ANALYSE_I8x8;
param->analyse.inter = X264_ANALYSE_I4x4 | X264_ANALYSE_I8x8 | X264_ANALYSE_PSUB16x16 | X264_ANALYSE_BSUB16x16;
param->analyse.i_direct_mv_pred = X264_DIRECT_PRED_SPATIAL;
param->analyse.i_me_method = X264_ME_DIA;
param->analyse.f_psy_rd = 1.0;
param->analyse.b_psy = 1;
param->analyse.f_psy_trellis = 0;
param->analyse.i_me_range = 16;
param->analyse.i_subpel_refine = 5;
param->analyse.b_mixed_references = 1;
param->analyse.b_chroma_me = 1;
param->analyse.i_mv_range_thread = -1;
param->analyse.i_mv_range = -1; // set from level_idc
param->analyse.i_chroma_qp_offset = 0;
param->analyse.b_fast_pskip = 1;
param->analyse.b_weighted_bipred = 1;
param->analyse.i_weighted_pred = X264_WEIGHTP_NONE; //X264_WEIGHTP_SMART;
param->analyse.b_dct_decimate = 1;
param->analyse.b_transform_8x8 = 0;
param->analyse.i_trellis = 1;
param->analyse.i_luma_deadzone[0] = 21;
param->analyse.i_luma_deadzone[1] = 11;
param->analyse.b_psnr = 0;
param->analyse.b_ssim = 0;
param->i_cqm_preset = X264_CQM_FLAT;
memset( param->cqm_4iy, 16, sizeof( param->cqm_4iy ) );
memset( param->cqm_4ic, 16, sizeof( param->cqm_4ic ) );
memset( param->cqm_4py, 16, sizeof( param->cqm_4py ) );
memset( param->cqm_4pc, 16, sizeof( param->cqm_4pc ) );
memset( param->cqm_8iy, 16, sizeof( param->cqm_8iy ) );
memset( param->cqm_8py, 16, sizeof( param->cqm_8py ) );
param->b_repeat_headers = 1;
param->b_annexb = 1;
param->b_aud = 0;
param->b_vfr_input = 0; // i_delay +=
param->i_nal_hrd = X264_NAL_HRD_NONE;
param->b_tff = 1;
param->b_pic_struct = 0;
param->b_fake_interlaced = 0;
param->i_frame_packing = -1;
}
// open x264 encoder - need mutex lock (not thread-safe)
int X264_EncOpen(OUTPUT_PARAMS *params)
{
int t_x264_thread;
t_x264_thread = x264_threading_init();
x264_param_default(&g_Encoder.X264InitParam);
X264_Params_UserSetting(&g_Encoder.X264InitParam);
g_Encoder.X264InitParam.i_width = params->width;
g_Encoder.X264InitParam.i_height = params->height;
g_Encoder.X264InitParam.i_fps_num = params->framerate;
g_Encoder.X264InitParam.i_keyint_max = params->i_interval;
g_Encoder.X264InitParam.rc.i_bitrate = params->bitrate;
g_Encoder.pX264EncHandle = x264_encoder_open(&g_Encoder.X264InitParam);
if (g_Encoder.pX264EncHandle == NULL)
{
printf("open encoder failed \r\n");
return -1;
}
g_Encoder.X264Picture.img.i_csp = X264_CSP_I420;
g_Encoder.X264Picture.img.i_plane = 3;
return 0;
}
// encode frame
int Encode_frame(x264_t *h, x264_picture_t *pic, unsigned char *streamEncoded, int *streamLength)
{
x264_picture_t pic_out;
x264_nal_t *nal;
int i_nal;
int t_encodedsize;
t_encodedsize = x264_encoder_encode(h, &nal, &i_nal, pic, &pic_out);
if (t_encodedsize < 0)
{
printf("encode frame error: %d\r\n", t_encodedsize);
return -1;
}
else
{
if (t_encodedsize!=0)
memcpy(streamEncoded, nal[0].p_payload, t_encodedsize);
*streamLength = t_encodedsize;
}
return t_encodedsize;
}
// encoder process
unsigned int g_X264_EncProcess = 0;
int X264_EncProcess(unsigned char *pstream, int *streamsize, IMG_INFO *img)
{
int t_encodedStreamLength;
g_Encoder.X264Picture.img.plane[0] = img->py;
g_Encoder.X264Picture.img.plane[1] = img->pcb;
g_Encoder.X264Picture.img.plane[2] = img->pcr;
g_Encoder.X264Picture.img.i_stride[0] = img->stride;
g_Encoder.X264Picture.img.i_stride[1] = img->stride/2;
g_Encoder.X264Picture.img.i_stride[2] = img->stride/2;
g_Encoder.X264Picture.i_type = X264_TYPE_AUTO;
g_Encoder.X264Picture.i_qpplus1 = X264_QP_AUTO;
g_Encoder.X264Picture.i_pic_struct = PIC_STRUCT_AUTO;
g_Encoder.X264Picture.i_pts = g_X264_EncProcess++;
t_encodedStreamLength = Encode_frame(g_Encoder.pX264EncHandle, &g_Encoder.X264Picture, pstream, streamsize);
return t_encodedStreamLength;
}
// close encoder
int X264_Close(int chan)
{
if (g_Encoder.pX264EncHandle)
x264_encoder_close(g_Encoder.pX264EncHandle);
return 0;
}
1. X264_EncOpen 함수인자인 OUTPUT_PARAMS 에 원하는 인코딩 설정값을 넣고 함수호출
2. 인코딩된 데이터를 담을 버퍼 포인터(pstream)와 yuv(YCrCb) 값이 담긴 프레임 버퍼 포인터를 지정하고 X264_EncProcess 함수호출
3. X264_EncProcess 함수의 pstream 에 인코딩된 프레임의 데이터가 저장됨
4. 인코더 종료시 X264_Close 호출
* 인코딩 성능을 높이려면 아래 ffmpeg 과 같이 x264 빌드시 enable-win32thread 옵션을 넣지말고 pthreadVC2.dll 을 사용할것
* 인코딩 성능을 높이려면 아래 ffmpeg 과 같이 x264 빌드시 enable-win32thread 옵션을 넣지말고 pthreadVC2.dll 을 사용할것