static void fill_cache( cache_hnd_t *h, int frame ) { /* shift frames out of the cache as the frame request is beyond the filled cache */ int shift = frame - LAST_FRAME; /* no frames to shift or no frames left to read */ if( shift <= 0 || h->eof ) return; /* the next frames to read are either * A) starting at the end of the current cache, or * B) starting at a new frame that has the end of the cache at the desired frame * and proceeding to fill the entire cache */ int cur_frame = X264_MAX( h->first_frame + h->cur_size, frame - h->max_size + 1 ); /* the new starting point is either * A) the current one shifted the number of frames entering/leaving the cache, or * B) at a new frame that has the end of the cache at the desired frame. */ h->first_frame = X264_MIN( h->first_frame + shift, cur_frame ); h->cur_size = X264_MAX( h->cur_size - shift, 0 ); while( h->cur_size < h->max_size ) { cli_pic_t temp; /* the old front frame is going to shift off, overwrite it with the new frame */ cli_pic_t *cache = h->cache[0]; if( h->prev_filter.get_frame( h->prev_hnd, &temp, cur_frame ) || x264_cli_pic_copy( cache, &temp ) || h->prev_filter.release_frame( h->prev_hnd, &temp, cur_frame ) ) { h->eof = cur_frame; return; } /* the read was successful, shift the frame off the front to the end */ x264_frame_push( (void*)h->cache, x264_frame_shift( (void*)h->cache ) ); cur_frame++; h->cur_size++; } }
void x264_speedcontrol_new( x264_t *h ) { x264_speedcontrol_t *sc = h->sc = x264_malloc( sizeof(x264_speedcontrol_t) ); x264_emms(); memset( sc, 0, sizeof(x264_speedcontrol_t) ); if( h->param.sc.f_speed <= 0 ) h->param.sc.f_speed = 1; sc->fps = h->param.i_fps_num / h->param.i_fps_den; sc->spf = 1e6 / sc->fps; h->param.sc.i_buffer_size = X264_MAX( 3, h->param.sc.i_buffer_size ); sc->buffer_size = h->param.sc.i_buffer_size * 1e6 / sc->fps; sc->buffer_fill = sc->buffer_size * h->param.sc.f_buffer_init; sc->buffer_fill = x264_clip3( sc->buffer_fill, sc->spf, sc->buffer_size ); sc->compensation_period = sc->buffer_size/4; sc->timestamp = x264_mdate(); sc->preset = -1; sc->prev_frame = 0; sc->cplx_num = 3e3; //FIXME estimate initial complexity sc->cplx_den = .1; sc->cplx_decay = 1 - 1./h->param.sc.i_buffer_size; sc->stat.min_buffer = sc->buffer_size; sc->stat.max_buffer = 0; sc->user_param = h->param; }
static int pix_number_of_planes( const AVPixFmtDescriptor *pix_desc ) { int num_planes = 0; for( int i = 0; i < pix_desc->nb_components; i++ ) { int plane_plus1 = pix_desc->comp[i].plane + 1; num_planes = X264_MAX( plane_plus1, num_planes ); } return num_planes; }
void x264_speedcontrol_sync( x264_t *h, float f_buffer_fill, int i_buffer_size ) { x264_speedcontrol_t *sc = h->sc; if( !h->param.sc.i_buffer_size ) return; if( i_buffer_size ) h->param.sc.i_buffer_size = X264_MAX( 3, h->param.sc.i_buffer_size ); sc->buffer_size = h->param.sc.i_buffer_size * 1e6 / sc->fps; sc->buffer_fill = sc->buffer_size * f_buffer_fill; }
static int get_frame( hnd_t handle, cli_pic_t *output, int frame ) { fix_vfr_pts_hnd_t *h = handle; /* if we want the holder picture and it errored, return the error. */ if( frame == h->holder_frame ) { if( h->holder_ret ) return h->holder_ret; } else { /* if we have a holder frame and we don't want it, release the frame */ if( h->holder_frame > 0 && h->holder_frame < frame && h->prev_filter.release_frame( h->prev_hnd, &h->holder, h->holder_frame ) ) return -1; h->holder_frame = -1; if( h->prev_filter.get_frame( h->prev_hnd, &h->holder, frame ) ) return -1; } /* if the frame's duration is not set already, read the next frame to set it. */ if( !h->holder.duration ) { /* allocate a buffer picture if we didn't already */ if( !h->buffer_allocated ) { if( x264_cli_pic_alloc( &h->buffer, h->holder.img.csp, h->holder.img.width, h->holder.img.height ) ) return -1; h->buffer_allocated = 1; } h->holder_frame = frame+1; /* copy the current frame to the buffer, release it, and then read in the next frame to the placeholder */ if( x264_cli_pic_copy( &h->buffer, &h->holder ) || h->prev_filter.release_frame( h->prev_hnd, &h->holder, frame ) ) return -1; h->holder_ret = h->prev_filter.get_frame( h->prev_hnd, &h->holder, h->holder_frame ); /* suppress non-monotonic pts warnings by setting the duration to be at least 1 */ if( !h->holder_ret ) h->last_duration = X264_MAX( h->holder.pts - h->buffer.pts, 1 ); h->buffer.duration = h->last_duration; *output = h->buffer; } else *output = h->holder; output->pts = h->pts; h->pts += output->duration; return 0; }
void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ) { int csp = param->i_csp & X264_CSP_MASK; sps->i_id = i_id; sps->i_mb_width = ( param->i_width + 15 ) / 16; sps->i_mb_height= ( param->i_height + 15 ) / 16; sps->i_chroma_format_idc = csp >= X264_CSP_I444 ? CHROMA_444 : csp >= X264_CSP_I422 ? CHROMA_422 : CHROMA_420; sps->b_qpprime_y_zero_transform_bypass = param->rc.i_rc_method == X264_RC_CQP && param->rc.i_qp_constant == 0; if( sps->b_qpprime_y_zero_transform_bypass || sps->i_chroma_format_idc == CHROMA_444 ) sps->i_profile_idc = PROFILE_HIGH444_PREDICTIVE; else if( sps->i_chroma_format_idc == CHROMA_422 ) sps->i_profile_idc = PROFILE_HIGH422; else if( BIT_DEPTH > 8 ) sps->i_profile_idc = PROFILE_HIGH10; else if( param->analyse.b_transform_8x8 || param->i_cqm_preset != X264_CQM_FLAT ) sps->i_profile_idc = PROFILE_HIGH; else if( param->b_cabac || param->i_bframe > 0 || param->b_interlaced || param->b_fake_interlaced || param->analyse.i_weighted_pred > 0 ) sps->i_profile_idc = PROFILE_MAIN; else sps->i_profile_idc = PROFILE_BASELINE; sps->b_constraint_set0 = sps->i_profile_idc == PROFILE_BASELINE; /* x264 doesn't support the features that are in Baseline and not in Main, * namely arbitrary_slice_order and slice_groups. */ sps->b_constraint_set1 = sps->i_profile_idc <= PROFILE_MAIN; /* Never set constraint_set2, it is not necessary and not used in real world. */ sps->b_constraint_set2 = 0; sps->b_constraint_set3 = 0; sps->i_level_idc = param->i_level_idc; if( param->i_level_idc == 9 && ( sps->i_profile_idc == PROFILE_BASELINE || sps->i_profile_idc == PROFILE_MAIN ) ) { sps->b_constraint_set3 = 1; /* level 1b with Baseline or Main profile is signalled via constraint_set3 */ sps->i_level_idc = 11; } /* Intra profiles */ if( param->i_keyint_max == 1 && sps->i_profile_idc > PROFILE_HIGH ) sps->b_constraint_set3 = 1; sps->vui.i_num_reorder_frames = param->i_bframe_pyramid ? 2 : param->i_bframe ? 1 : 0; /* extra slot with pyramid so that we don't have to override the * order of forgetting old pictures */ sps->vui.i_max_dec_frame_buffering = sps->i_num_ref_frames = X264_MIN(X264_REF_MAX, X264_MAX4(param->i_frame_reference, 1 + sps->vui.i_num_reorder_frames, param->i_bframe_pyramid ? 4 : 1, param->i_dpb_size)); sps->i_num_ref_frames -= param->i_bframe_pyramid == X264_B_PYRAMID_STRICT; if( param->i_keyint_max == 1 ) { sps->i_num_ref_frames = 0; sps->vui.i_max_dec_frame_buffering = 0; } /* number of refs + current frame */ int max_frame_num = sps->vui.i_max_dec_frame_buffering * (!!param->i_bframe_pyramid+1) + 1; /* Intra refresh cannot write a recovery time greater than max frame num-1 */ if( param->b_intra_refresh ) { int time_to_recovery = X264_MIN( sps->i_mb_width - 1, param->i_keyint_max ) + param->i_bframe - 1; max_frame_num = X264_MAX( max_frame_num, time_to_recovery+1 ); } sps->i_log2_max_frame_num = 4; while( (1 << sps->i_log2_max_frame_num) <= max_frame_num ) sps->i_log2_max_frame_num++; sps->i_poc_type = param->i_bframe || param->b_interlaced || param->i_avcintra_class ? 0 : 2; if( sps->i_poc_type == 0 ) { int max_delta_poc = (param->i_bframe + 2) * (!!param->i_bframe_pyramid + 1) * 2; sps->i_log2_max_poc_lsb = 4; while( (1 << sps->i_log2_max_poc_lsb) <= max_delta_poc * 2 ) sps->i_log2_max_poc_lsb++; } sps->b_vui = 1; sps->b_gaps_in_frame_num_value_allowed = 0; sps->b_frame_mbs_only = !(param->b_interlaced || param->b_fake_interlaced); if( !sps->b_frame_mbs_only ) sps->i_mb_height = ( sps->i_mb_height + 1 ) & ~1; sps->b_mb_adaptive_frame_field = param->b_interlaced; sps->b_direct8x8_inference = 1; sps->crop.i_left = param->crop_rect.i_left; sps->crop.i_top = param->crop_rect.i_top; sps->crop.i_right = param->crop_rect.i_right + sps->i_mb_width*16 - param->i_width; sps->crop.i_bottom = (param->crop_rect.i_bottom + sps->i_mb_height*16 - param->i_height) >> !sps->b_frame_mbs_only; sps->b_crop = sps->crop.i_left || sps->crop.i_top || sps->crop.i_right || sps->crop.i_bottom; sps->vui.b_aspect_ratio_info_present = 0; if( param->vui.i_sar_width > 0 && param->vui.i_sar_height > 0 ) { sps->vui.b_aspect_ratio_info_present = 1; sps->vui.i_sar_width = param->vui.i_sar_width; sps->vui.i_sar_height= param->vui.i_sar_height; } sps->vui.b_overscan_info_present = param->vui.i_overscan > 0 && param->vui.i_overscan <= 2; if( sps->vui.b_overscan_info_present ) sps->vui.b_overscan_info = ( param->vui.i_overscan == 2 ? 1 : 0 ); sps->vui.b_signal_type_present = 0; sps->vui.i_vidformat = ( param->vui.i_vidformat >= 0 && param->vui.i_vidformat <= 5 ? param->vui.i_vidformat : 5 ); sps->vui.b_fullrange = ( param->vui.b_fullrange >= 0 && param->vui.b_fullrange <= 1 ? param->vui.b_fullrange : ( csp >= X264_CSP_BGR ? 1 : 0 ) ); sps->vui.b_color_description_present = 0; sps->vui.i_colorprim = ( param->vui.i_colorprim >= 0 && param->vui.i_colorprim <= 9 ? param->vui.i_colorprim : 2 ); sps->vui.i_transfer = ( param->vui.i_transfer >= 0 && param->vui.i_transfer <= 15 ? param->vui.i_transfer : 2 ); sps->vui.i_colmatrix = ( param->vui.i_colmatrix >= 0 && param->vui.i_colmatrix <= 10 ? param->vui.i_colmatrix : ( csp >= X264_CSP_BGR ? 0 : 2 ) ); if( sps->vui.i_colorprim != 2 || sps->vui.i_transfer != 2 || sps->vui.i_colmatrix != 2 ) { sps->vui.b_color_description_present = 1; } if( sps->vui.i_vidformat != 5 || sps->vui.b_fullrange || sps->vui.b_color_description_present ) { sps->vui.b_signal_type_present = 1; } /* FIXME: not sufficient for interlaced video */ sps->vui.b_chroma_loc_info_present = param->vui.i_chroma_loc > 0 && param->vui.i_chroma_loc <= 5 && sps->i_chroma_format_idc == CHROMA_420; if( sps->vui.b_chroma_loc_info_present ) { sps->vui.i_chroma_loc_top = param->vui.i_chroma_loc; sps->vui.i_chroma_loc_bottom = param->vui.i_chroma_loc; } sps->vui.b_timing_info_present = param->i_timebase_num > 0 && param->i_timebase_den > 0; if( sps->vui.b_timing_info_present ) { sps->vui.i_num_units_in_tick = param->i_timebase_num; sps->vui.i_time_scale = param->i_timebase_den * 2; sps->vui.b_fixed_frame_rate = !param->b_vfr_input; } sps->vui.b_vcl_hrd_parameters_present = 0; // we don't support VCL HRD sps->vui.b_nal_hrd_parameters_present = !!param->i_nal_hrd; sps->vui.b_pic_struct_present = param->b_pic_struct; // NOTE: HRD related parts of the SPS are initialised in x264_ratecontrol_init_reconfigurable sps->vui.b_bitstream_restriction = param->i_keyint_max > 1; if( sps->vui.b_bitstream_restriction ) { sps->vui.b_motion_vectors_over_pic_boundaries = 1; sps->vui.i_max_bytes_per_pic_denom = 0; sps->vui.i_max_bits_per_mb_denom = 0; sps->vui.i_log2_max_mv_length_horizontal = sps->vui.i_log2_max_mv_length_vertical = (int)log2f( X264_MAX( 1, param->analyse.i_mv_range*4-1 ) ) + 1; } }
jlong Java_com_H264_H264Encoder_CompressBegin(JNIEnv* env,jobject thiz, jint width,jint height, jint FrameRate, jbyteArray filename){ en = (Encoder *) malloc(sizeof(Encoder)); en->param = (x264_param_t *) malloc(sizeof(x264_param_t)); en->picture = (x264_picture_t *) malloc(sizeof(x264_picture_t)); opt = (cli_opt_t *)malloc(sizeof(cli_opt_t)); //test nalcount=0; last_pts = 0; i_frame= 0; //test x264_nal_t *headers; int i_nal; jbyte * fname = (jbyte*)(*env)->GetByteArrayElements(env, filename, 0); mp4_output.open_file( fname, &opt->hout, &output_opt ); x264_param_default(en->param); // default param en->param->i_log_level = X264_LOG_NONE; en->param->i_width = width; // frame width en->param->i_height = height; // frame height en->param->rc.i_lookahead =0; en->param->i_bframe=0; en->param->i_fps_num =FrameRate; en->param->i_fps_den = 1; en->param->i_frame_reference=5; en->param->i_bframe_adaptive=1; en->param->b_vfr_input=1; en->param->i_timebase_num = 1; en->param->i_timebase_den = FrameRate; en->param->i_csp =X264_CSP_I420; en->param->analyse.b_psnr = 1; en->param->analyse.b_ssim = 1; int frames = 0; en->param->i_frame_total = 0; /////// // Intra refres: en->param->i_keyint_max = 30; en->param->b_intra_refresh = 1; //Rate control: en->param->rc.f_rf_constant = 25; en->param->rc.f_rf_constant_max = 35; //For streaming: en->param->b_repeat_headers = 0; en->param->b_annexb = 0; /////// uv = en->param->i_width * en->param->i_height; if ((en->handle = x264_encoder_open(en->param)) == 0) { return 0; } x264_encoder_parameters( en->handle, en->param ); /* Create a new pic */ x264_picture_alloc(en->picture, X264_CSP_I420, en->param->i_width, en->param->i_height); mp4_output.set_param(opt->hout,en->param); ticks_per_frame = (int64_t)en->param->i_timebase_den * en->param->i_fps_den / en->param->i_timebase_num / en->param->i_fps_num; ticks_per_frame = X264_MAX( ticks_per_frame, 1 ); __android_log_print(ANDROID_LOG_INFO, "H264Encoder native", "ticks_per_frame:%d",ticks_per_frame); if(x264_encoder_headers( en->handle, &headers, &i_nal)<0) ; __android_log_print(ANDROID_LOG_INFO, "H264Encoder native", "encoder header:%d",i_nal); mp4_output.write_headers(opt->hout, headers); (*env)->ReleaseByteArrayElements(env,filename,fname,0); return (jlong) en; }
void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ) { sps->i_id = i_id; sps->b_qpprime_y_zero_transform_bypass = param->rc.i_rc_method == X264_RC_CQP && param->rc.i_qp_constant == 0; if( sps->b_qpprime_y_zero_transform_bypass ) sps->i_profile_idc = PROFILE_HIGH444; else if( param->analyse.b_transform_8x8 || param->i_cqm_preset != X264_CQM_FLAT ) sps->i_profile_idc = PROFILE_HIGH; else if( param->b_cabac || param->i_bframe > 0 ) sps->i_profile_idc = PROFILE_MAIN; else sps->i_profile_idc = PROFILE_BASELINE; sps->i_level_idc = param->i_level_idc; sps->b_constraint_set0 = sps->i_profile_idc == PROFILE_BASELINE; /* x264 doesn't support the features that are in Baseline and not in Main, * namely arbitrary_slice_order and slice_groups. */ sps->b_constraint_set1 = sps->i_profile_idc <= PROFILE_MAIN; /* Never set constraint_set2, it is not necessary and not used in real world. */ sps->b_constraint_set2 = 0; sps->i_log2_max_frame_num = 4; /* at least 4 */ while( (1 << sps->i_log2_max_frame_num) <= param->i_keyint_max ) { sps->i_log2_max_frame_num++; } sps->i_log2_max_frame_num++; /* just in case */ sps->i_poc_type = 0; if( sps->i_poc_type == 0 ) { sps->i_log2_max_poc_lsb = sps->i_log2_max_frame_num + 1; /* max poc = 2*frame_num */ } else if( sps->i_poc_type == 1 ) { int i; /* FIXME */ sps->b_delta_pic_order_always_zero = 1; sps->i_offset_for_non_ref_pic = 0; sps->i_offset_for_top_to_bottom_field = 0; sps->i_num_ref_frames_in_poc_cycle = 0; for( i = 0; i < sps->i_num_ref_frames_in_poc_cycle; i++ ) { sps->i_offset_for_ref_frame[i] = 0; } } sps->b_vui = 1; sps->b_gaps_in_frame_num_value_allowed = 0; sps->i_mb_width = ( param->i_width + 15 ) / 16; sps->i_mb_height= ( param->i_height + 15 ) / 16; if( param->b_interlaced ) sps->i_mb_height = ( sps->i_mb_height + 1 ) & ~1; sps->b_frame_mbs_only = ! param->b_interlaced; sps->b_mb_adaptive_frame_field = param->b_interlaced; sps->b_direct8x8_inference = param->analyse.i_direct_8x8_inference || ! sps->b_frame_mbs_only || !(param->analyse.inter & X264_ANALYSE_PSUB8x8); sps->crop.i_left = 0; sps->crop.i_top = 0; sps->crop.i_right = sps->i_mb_width*16 - param->i_width; sps->crop.i_bottom = (sps->i_mb_height*16 - param->i_height) >> param->b_interlaced; sps->b_crop = sps->crop.i_left || sps->crop.i_top || sps->crop.i_right || sps->crop.i_bottom; sps->vui.b_aspect_ratio_info_present = 0; if( param->vui.i_sar_width > 0 && param->vui.i_sar_height > 0 ) { sps->vui.b_aspect_ratio_info_present = 1; sps->vui.i_sar_width = param->vui.i_sar_width; sps->vui.i_sar_height= param->vui.i_sar_height; } sps->vui.b_overscan_info_present = ( param->vui.i_overscan ? 1 : 0 ); if( sps->vui.b_overscan_info_present ) sps->vui.b_overscan_info = ( param->vui.i_overscan == 2 ? 1 : 0 ); sps->vui.b_signal_type_present = 0; sps->vui.i_vidformat = ( param->vui.i_vidformat <= 5 ? param->vui.i_vidformat : 5 ); sps->vui.b_fullrange = ( param->vui.b_fullrange ? 1 : 0 ); sps->vui.b_color_description_present = 0; sps->vui.i_colorprim = ( param->vui.i_colorprim <= 9 ? param->vui.i_colorprim : 2 ); sps->vui.i_transfer = ( param->vui.i_transfer <= 11 ? param->vui.i_transfer : 2 ); sps->vui.i_colmatrix = ( param->vui.i_colmatrix <= 9 ? param->vui.i_colmatrix : 2 ); if( sps->vui.i_colorprim != 2 || sps->vui.i_transfer != 2 || sps->vui.i_colmatrix != 2 ) { sps->vui.b_color_description_present = 1; } if( sps->vui.i_vidformat != 5 || sps->vui.b_fullrange || sps->vui.b_color_description_present ) { sps->vui.b_signal_type_present = 1; } /* FIXME: not sufficient for interlaced video */ sps->vui.b_chroma_loc_info_present = ( param->vui.i_chroma_loc ? 1 : 0 ); if( sps->vui.b_chroma_loc_info_present ) { sps->vui.i_chroma_loc_top = param->vui.i_chroma_loc; sps->vui.i_chroma_loc_bottom = param->vui.i_chroma_loc; } sps->vui.b_timing_info_present = 0; if( param->i_fps_num > 0 && param->i_fps_den > 0) { sps->vui.b_timing_info_present = 1; sps->vui.i_num_units_in_tick = param->i_fps_den; sps->vui.i_time_scale = param->i_fps_num * 2; sps->vui.b_fixed_frame_rate = 1; } sps->vui.i_num_reorder_frames = param->b_bframe_pyramid ? 2 : param->i_bframe ? 1 : 0; /* extra slot with pyramid so that we don't have to override the * order of forgetting old pictures */ sps->vui.i_max_dec_frame_buffering = sps->i_num_ref_frames = X264_MIN(16, X264_MAX(param->i_frame_reference, 1 + sps->vui.i_num_reorder_frames)); sps->vui.b_bitstream_restriction = 1; if( sps->vui.b_bitstream_restriction ) { sps->vui.b_motion_vectors_over_pic_boundaries = 1; sps->vui.i_max_bytes_per_pic_denom = 0; sps->vui.i_max_bits_per_mb_denom = 0; sps->vui.i_log2_max_mv_length_horizontal = sps->vui.i_log2_max_mv_length_vertical = (int)(log(param->analyse.i_mv_range*4-1)/log(2)) + 1; } }
static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x264_param_t *param, char *opt_string ) { selvry_hnd_t *h = malloc( sizeof(selvry_hnd_t) ); if( !h ) return -1; h->pattern_len = 0; h->step_size = 0; int offsets[MAX_PATTERN_SIZE]; for( char *tok, *p = opt_string; (tok = strtok( p, "," )); p = NULL ) { int val = x264_otoi( tok, -1 ); if( p ) { FAIL_IF_ERROR( val <= 0, "invalid step `%s'\n", tok ) h->step_size = val; continue; } FAIL_IF_ERROR( val < 0 || val >= h->step_size, "invalid offset `%s'\n", tok ) FAIL_IF_ERROR( h->pattern_len >= MAX_PATTERN_SIZE, "max pattern size %d reached\n", MAX_PATTERN_SIZE ) offsets[h->pattern_len++] = val; } FAIL_IF_ERROR( !h->step_size, "no step size provided\n" ) FAIL_IF_ERROR( !h->pattern_len, "no offsets supplied\n" ) h->pattern = malloc( h->pattern_len * sizeof(int) ); if( !h->pattern ) return -1; memcpy( h->pattern, offsets, h->pattern_len * sizeof(int) ); /* determine required cache size to maintain pattern. */ intptr_t max_rewind = 0; int min = h->step_size; for( int i = h->pattern_len-1; i >= 0; i-- ) { min = X264_MIN( min, offsets[i] ); if( i ) max_rewind = X264_MAX( max_rewind, offsets[i-1] - min + 1 ); /* reached maximum rewind size */ if( max_rewind == h->step_size ) break; } if( x264_init_vid_filter( "cache", handle, filter, info, param, (void*)max_rewind ) ) return -1; /* done initing, overwrite properties */ if( h->step_size != h->pattern_len ) { info->num_frames = (uint64_t)info->num_frames * h->pattern_len / h->step_size; info->fps_den *= h->step_size; info->fps_num *= h->pattern_len; x264_reduce_fraction( &info->fps_num, &info->fps_den ); if( info->vfr ) { info->timebase_den *= h->pattern_len; info->timebase_num *= h->step_size; x264_reduce_fraction( &info->timebase_num, &info->timebase_den ); } } h->pts = 0; h->vfr = info->vfr; h->prev_filter = *filter; h->prev_hnd = *handle; *filter = select_every_filter; *handle = h; return 0; }
void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ) { sps->i_id = i_id; int max_frame_num; sps->b_qpprime_y_zero_transform_bypass = param->rc.i_rc_method == X264_RC_CQP && param->rc.i_qp_constant == 0; if( sps->b_qpprime_y_zero_transform_bypass ) sps->i_profile_idc = PROFILE_HIGH444_PREDICTIVE; else if( BIT_DEPTH > 8 ) sps->i_profile_idc = PROFILE_HIGH10; else if( param->analyse.b_transform_8x8 || param->i_cqm_preset != X264_CQM_FLAT ) sps->i_profile_idc = PROFILE_HIGH; else if( param->b_cabac || param->i_bframe > 0 || param->b_interlaced || param->b_fake_interlaced || param->analyse.i_weighted_pred > 0 ) sps->i_profile_idc = PROFILE_MAIN; else sps->i_profile_idc = PROFILE_BASELINE; sps->i_level_idc = param->i_level_idc; sps->b_constraint_set0 = sps->i_profile_idc == PROFILE_BASELINE; /* x264 doesn't support the features that are in Baseline and not in Main, * namely arbitrary_slice_order and slice_groups. */ sps->b_constraint_set1 = sps->i_profile_idc <= PROFILE_MAIN; /* Never set constraint_set2, it is not necessary and not used in real world. */ sps->b_constraint_set2 = 0; sps->vui.i_num_reorder_frames = param->i_bframe_pyramid ? 2 : param->i_bframe ? 1 : 0; /* extra slot with pyramid so that we don't have to override the * order of forgetting old pictures */ sps->vui.i_max_dec_frame_buffering = sps->i_num_ref_frames = X264_MIN(X264_REF_MAX, X264_MAX4(param->i_frame_reference, 1 + sps->vui.i_num_reorder_frames, param->i_bframe_pyramid ? 4 : 1, param->i_dpb_size)); sps->i_num_ref_frames -= param->i_bframe_pyramid == X264_B_PYRAMID_STRICT; /* number of refs + current frame */ max_frame_num = sps->vui.i_max_dec_frame_buffering * (!!param->i_bframe_pyramid+1) + 1; sps->i_log2_max_frame_num = 4; while( (1 << sps->i_log2_max_frame_num) <= max_frame_num ) sps->i_log2_max_frame_num++; sps->i_poc_type = 0; if( sps->i_poc_type == 0 ) { int max_delta_poc = (param->i_bframe + 2) * (!!param->i_bframe_pyramid + 1) * 2; sps->i_log2_max_poc_lsb = 4; while( (1 << sps->i_log2_max_poc_lsb) <= max_delta_poc * 2 ) sps->i_log2_max_poc_lsb++; } else if( sps->i_poc_type == 1 ) { int i; /* FIXME */ sps->b_delta_pic_order_always_zero = 1; sps->i_offset_for_non_ref_pic = 0; sps->i_offset_for_top_to_bottom_field = 0; sps->i_num_ref_frames_in_poc_cycle = 0; for( i = 0; i < sps->i_num_ref_frames_in_poc_cycle; i++ ) { sps->i_offset_for_ref_frame[i] = 0; } } sps->b_vui = 1; sps->b_gaps_in_frame_num_value_allowed = 0; sps->i_mb_width = ( param->i_width + 15 ) / 16; sps->i_mb_height= ( param->i_height + 15 ) / 16; sps->b_frame_mbs_only = !(param->b_interlaced || param->b_fake_interlaced); if( !sps->b_frame_mbs_only ) sps->i_mb_height = ( sps->i_mb_height + 1 ) & ~1; sps->b_mb_adaptive_frame_field = param->b_interlaced; sps->b_direct8x8_inference = 1; sps->crop.i_left = 0; sps->crop.i_top = 0; sps->crop.i_right = sps->i_mb_width*16 - param->i_width; sps->crop.i_bottom = (sps->i_mb_height*16 - param->i_height) >> !sps->b_frame_mbs_only; sps->b_crop = sps->crop.i_left || sps->crop.i_top || sps->crop.i_right || sps->crop.i_bottom; sps->vui.b_aspect_ratio_info_present = 0; if( param->vui.i_sar_width > 0 && param->vui.i_sar_height > 0 ) { sps->vui.b_aspect_ratio_info_present = 1; sps->vui.i_sar_width = param->vui.i_sar_width; sps->vui.i_sar_height= param->vui.i_sar_height; } sps->vui.b_overscan_info_present = ( param->vui.i_overscan ? 1 : 0 ); if( sps->vui.b_overscan_info_present ) sps->vui.b_overscan_info = ( param->vui.i_overscan == 2 ? 1 : 0 ); sps->vui.b_signal_type_present = 0; sps->vui.i_vidformat = ( param->vui.i_vidformat <= 5 ? param->vui.i_vidformat : 5 ); sps->vui.b_fullrange = ( param->vui.b_fullrange ? 1 : 0 ); sps->vui.b_color_description_present = 0; sps->vui.i_colorprim = ( param->vui.i_colorprim <= 9 ? param->vui.i_colorprim : 2 ); sps->vui.i_transfer = ( param->vui.i_transfer <= 11 ? param->vui.i_transfer : 2 ); sps->vui.i_colmatrix = ( param->vui.i_colmatrix <= 9 ? param->vui.i_colmatrix : 2 ); if( sps->vui.i_colorprim != 2 || sps->vui.i_transfer != 2 || sps->vui.i_colmatrix != 2 ) { sps->vui.b_color_description_present = 1; } if( sps->vui.i_vidformat != 5 || sps->vui.b_fullrange || sps->vui.b_color_description_present ) { sps->vui.b_signal_type_present = 1; } /* FIXME: not sufficient for interlaced video */ sps->vui.b_chroma_loc_info_present = ( param->vui.i_chroma_loc ? 1 : 0 ); if( sps->vui.b_chroma_loc_info_present ) { sps->vui.i_chroma_loc_top = param->vui.i_chroma_loc; sps->vui.i_chroma_loc_bottom = param->vui.i_chroma_loc; } sps->vui.b_timing_info_present = param->i_timebase_num > 0 && param->i_timebase_den > 0; if( sps->vui.b_timing_info_present ) { sps->vui.i_num_units_in_tick = param->i_timebase_num; sps->vui.i_time_scale = param->i_timebase_den * 2; sps->vui.b_fixed_frame_rate = !param->b_vfr_input; } sps->vui.b_vcl_hrd_parameters_present = 0; // we don't support VCL HRD sps->vui.b_nal_hrd_parameters_present = !!param->i_nal_hrd; sps->vui.b_pic_struct_present = param->b_pic_struct; // NOTE: HRD related parts of the SPS are initialised in x264_ratecontrol_init_reconfigurable sps->vui.b_bitstream_restriction = 1; if( sps->vui.b_bitstream_restriction ) { sps->vui.b_motion_vectors_over_pic_boundaries = 1; sps->vui.i_max_bytes_per_pic_denom = 0; sps->vui.i_max_bits_per_mb_denom = 0; sps->vui.i_log2_max_mv_length_horizontal = sps->vui.i_log2_max_mv_length_vertical = (int)log2f( X264_MAX( 1, param->analyse.i_mv_range*4-1 ) ) + 1; } }
void x264_me_search_ref( x264_t *h, x264_me_t *m, int (*mvc)[2], int i_mvc, int *p_fullpel_thresh ) { const int i_pixel = m->i_pixel; const int i_me_range = h->param.analyse.i_me_range; const int b_chroma_me = h->mb.b_chroma_me && i_pixel <= PIXEL_8x8; int bmx, bmy, bcost; int omx, omy, pmx, pmy; uint8_t *p_fref = m->p_fref[0]; int i, j; int mv_x_min = h->mb.mv_min_fpel[0]; int mv_y_min = h->mb.mv_min_fpel[1]; int mv_x_max = h->mb.mv_max_fpel[0]; int mv_y_max = h->mb.mv_max_fpel[1]; const int16_t *p_cost_mvx = m->p_cost_mv - m->mvp[0]; const int16_t *p_cost_mvy = m->p_cost_mv - m->mvp[1]; if( h->mb.i_me_method == X264_ME_UMH ) { /* clamp mvp to inside frame+padding, so that we don't have to check it each iteration */ p_cost_mvx = m->p_cost_mv - x264_clip3( m->mvp[0], h->mb.mv_min[0], h->mb.mv_max[0] ); p_cost_mvy = m->p_cost_mv - x264_clip3( m->mvp[1], h->mb.mv_min[1], h->mb.mv_max[1] ); } bmx = pmx = x264_clip3( ( m->mvp[0] + 2 ) >> 2, mv_x_min, mv_x_max ); bmy = pmy = x264_clip3( ( m->mvp[1] + 2 ) >> 2, mv_y_min, mv_y_max ); bcost = COST_MAX; COST_MV( bmx, bmy ); /* I don't know why this helps */ bcost -= p_cost_mvx[ bmx<<2 ] + p_cost_mvy[ bmy<<2 ]; /* try extra predictors if provided */ for( i = 0; i < i_mvc; i++ ) { const int mx = x264_clip3( ( mvc[i][0] + 2 ) >> 2, mv_x_min, mv_x_max ); const int my = x264_clip3( ( mvc[i][1] + 2 ) >> 2, mv_y_min, mv_y_max ); if( mx != bmx || my != bmy ) COST_MV( mx, my ); } COST_MV( 0, 0 ); mv_x_max += 8; mv_y_max += 8; mv_x_min -= 8; mv_y_min -= 8; switch( h->mb.i_me_method ) { case X264_ME_DIA: /* diamond search, radius 1 */ #define DIA1_ITER(mx, my)\ {\ omx = mx;\ omy = my;\ COST_MV( omx , omy-1 );\ COST_MV( omx , omy+1 );\ COST_MV( omx-1, omy );\ COST_MV( omx+1, omy );\ } for( i = 0; i < i_me_range; i++ ) { DIA1_ITER( bmx, bmy ); if( bmx == omx && bmy == omy ) break; } break; case X264_ME_HEX: /* hexagon search, radius 2 */ #define HEX2_ITER(mx, my)\ {\ omx = mx;\ omy = my;\ COST_MV( omx-2, omy );\ COST_MV( omx-1, omy+2 );\ COST_MV( omx+1, omy+2 );\ COST_MV( omx+2, omy );\ COST_MV( omx+1, omy-2 );\ COST_MV( omx-1, omy-2 );\ } for( i = 0; i < i_me_range/2; i++ ) { HEX2_ITER( bmx, bmy ); if( bmx == omx && bmy == omy ) break; } /* square refine */ DIA1_ITER( bmx, bmy ); COST_MV( omx-1, omy-1 ); COST_MV( omx-1, omy+1 ); COST_MV( omx+1, omy-1 ); COST_MV( omx+1, omy+1 ); break; case X264_ME_UMH: /* Uneven-cross Multi-Hexagon-grid Search * as in JM, except without early termination */ DIA1_ITER( pmx, pmy ); if( pmx || pmy ) DIA1_ITER( 0, 0 ); DIA1_ITER( bmx, bmy ); if(i_pixel == PIXEL_4x4) goto umh_small_hex; /* cross */ omx = bmx; omy = bmy; for( i = 1; i < i_me_range; i+=2 ) { if( omx + i <= mv_x_max ) COST_MV( omx + i, omy ); if( omx - i >= mv_x_min ) COST_MV( omx - i, omy ); } for( i = 1; i < i_me_range/2; i+=2 ) { if( omy + i <= mv_y_max ) COST_MV( omx, omy + i ); if( omy - i >= mv_y_min ) COST_MV( omx, omy - i ); } /* 5x5 ESA */ omx = bmx; omy = bmy; for( i = 0; i < 24; i++ ) { static const int square2_x[24] = {1,1,0,-1,-1,-1, 0, 1, 2,2,2,2,1,0,-1,-2,-2,-2,-2,-2,-1, 0, 1, 2}; static const int square2_y[24] = {0,1,1, 1, 0,-1,-1,-1,-1,0,1,2,2,2, 2, 2, 1, 0,-1,-2,-2,-2,-2,-2}; COST_MV( omx + square2_x[i], omy + square2_y[i] ); } /* hexagon grid */ omx = bmx; omy = bmy; for( i = 1; i <= i_me_range/4; i++ ) { int bounds_check = 4*i > X264_MIN4( mv_x_max-omx, mv_y_max-omy, omx-mv_x_min, omy-mv_y_min ); for( j = 0; j < 16; j++ ) { static const int hex4_x[16] = {0,-2,-4,-4,-4,-4,-4,-2, 0, 2, 4, 4,4,4,4,2}; static const int hex4_y[16] = {4, 3, 2, 1, 0,-1,-2,-3,-4,-3,-2,-1,0,1,2,3}; int mx = omx + hex4_x[j]*i; int my = omy + hex4_y[j]*i; if( !bounds_check || ( mx >= mv_x_min && mx <= mv_x_max && my >= mv_y_min && my <= mv_y_max ) ) COST_MV( mx, my ); } } umh_small_hex: /* iterative search */ for( i = 0; i < i_me_range; i++ ) { HEX2_ITER( bmx, bmy ); if( bmx == omx && bmy == omy ) break; } for( i = 0; i < i_me_range; i++ ) { DIA1_ITER( bmx, bmy ); if( bmx == omx && bmy == omy ) break; } break; case X264_ME_ESA: { const int min_x = X264_MAX( bmx - i_me_range, mv_x_min); const int min_y = X264_MAX( bmy - i_me_range, mv_y_min); const int max_x = X264_MIN( bmx + i_me_range, mv_x_max); const int max_y = X264_MIN( bmy + i_me_range, mv_y_max); for( omy = min_y; omy <= max_y; omy++ ) for( omx = min_x; omx <= max_x; omx++ ) { COST_MV( omx, omy ); } } break; } /* -> qpel mv */ m->mv[0] = bmx << 2; m->mv[1] = bmy << 2; /* compute the real cost */ m->cost_mv = p_cost_mvx[ m->mv[0] ] + p_cost_mvy[ m->mv[1] ]; m->cost = h->pixf.mbcmp[i_pixel]( m->p_fenc[0], m->i_stride[0], &p_fref[bmy * m->i_stride[0] + bmx], m->i_stride[0] ) + m->cost_mv; if( b_chroma_me ) { const int bw = x264_pixel_size[m->i_pixel].w; const int bh = x264_pixel_size[m->i_pixel].h; uint8_t pix[8*8*2]; h->mc.mc_chroma( m->p_fref[4], m->i_stride[1], pix, 8, m->mv[0], m->mv[1], bw/2, bh/2 ); h->mc.mc_chroma( m->p_fref[5], m->i_stride[1], pix+8*8, 8, m->mv[0], m->mv[1], bw/2, bh/2 ); m->cost += h->pixf.mbcmp[i_pixel+3]( m->p_fenc[1], m->i_stride[1], pix, 8 ) + h->pixf.mbcmp[i_pixel+3]( m->p_fenc[2], m->i_stride[1], pix+8*8, 8 ); } /* subpel refine */ if( h->mb.i_subpel_refine >= 3 ) { int hpel, qpel; /* early termination (when examining multiple reference frames) * FIXME: this can update fullpel_thresh even if the match * ref is rejected after subpel refinement */ if( p_fullpel_thresh ) { if( (m->cost*7)>>3 > *p_fullpel_thresh ) return; else if( m->cost < *p_fullpel_thresh ) *p_fullpel_thresh = m->cost; }
void x264_speedcontrol_frame( x264_t *h ) { x264_speedcontrol_t *sc = h->sc; int64_t t, delta_t, delta_buffer; int delta_f; x264_emms(); // update buffer state after encoding and outputting the previous frame(s) t = x264_mdate(); delta_f = h->i_frame - sc->prev_frame; delta_t = t - sc->timestamp; delta_buffer = delta_f * sc->spf / h->param.sc.f_speed - delta_t; sc->buffer_fill += delta_buffer; sc->prev_frame = h->i_frame; sc->timestamp = t; // update the time predictor if( delta_f ) { int cpu_time = h->param.sc.b_alt_timer ? sc->cpu_time : delta_t; float decay = powf( sc->cplx_decay, delta_f ); sc->cplx_num *= decay; sc->cplx_den *= decay; sc->cplx_num += cpu_time / presets[sc->preset].time; sc->cplx_den += delta_f; sc->stat.avg_preset += sc->preset * delta_f; sc->stat.den += delta_f; } sc->stat.min_buffer = X264_MIN( sc->buffer_fill, sc->stat.min_buffer ); sc->stat.max_buffer = X264_MAX( sc->buffer_fill, sc->stat.max_buffer ); if( sc->buffer_fill > sc->buffer_size ) // oops, cpu was idle { // not really an error, but we'll warn for debugging purposes static int64_t idle_t = 0, print_interval = 0; idle_t += sc->buffer_fill - sc->buffer_size; if( t - print_interval > 1e6 ) { x264_log( h, X264_LOG_WARNING, "speedcontrol idle (%.6f sec)\n", idle_t/1e6 ); print_interval = t; idle_t = 0; } sc->buffer_fill = sc->buffer_size; } else if( sc->buffer_fill < 0 && delta_buffer < 0 ) // oops, we're late { // don't clip fullness to 0; we'll hope the real buffer was bigger than // specified, and maybe we can catch up. if the application had to drop // frames, then it should override the buffer fullness (FIXME implement this). x264_log( h, X264_LOG_WARNING, "speedcontrol underflow (%.6f sec)\n", sc->buffer_fill/1e6 ); } { // pick the preset that should return the buffer to 3/4-full within a time // specified by compensation_period float target = sc->spf / h->param.sc.f_speed * (sc->buffer_fill + sc->compensation_period) / (sc->buffer_size*3/4 + sc->compensation_period); float cplx = sc->cplx_num / sc->cplx_den; float set, t0, t1; float filled = (float) sc->buffer_fill / sc->buffer_size; int i; t0 = presets[0].time * cplx; for( i=1;; i++ ) { t1 = presets[i].time * cplx; if( t1 >= target || i == PRESETS-1 ) break; t0 = t1; } // linear interpolation between states set = i-1 + (target - t0) / (t1 - t0); // Even if our time estimations in the PRESETS array are off // this will push us towards our target fullness set += (20 * (filled-0.75)); set = x264_clip3f(set,0,PRESETS-1); apply_preset( h, dither( sc, set ) ); // FIXME if (h->param.i_log_level >= X264_LOG_DEBUG) { static float cpu, wall, tgt, den; float decay = 1-1/100.; cpu = cpu*decay + sc->cpu_time; wall = wall*decay + delta_t; tgt = tgt*decay + target; den = den*decay + 1; fprintf( stderr, "speed: %.2f %d[%.5f] (t/c/w: %6.0f/%6.0f/%6.0f = %.4f) fps=%.2f\r", set, sc->preset, (float)sc->buffer_fill / sc->buffer_size, tgt/den, cpu/den, wall/den, cpu/wall, 1e6*den/wall ); } } }
/* Result must be freed */ x264_param_t *x264_gtk_param_get (X264_Gtk *x264_gtk) { x264_param_t *param; if (!x264_gtk) return NULL; param = (x264_param_t *)g_malloc (sizeof (x264_param_t)); if (!param) return NULL; x264_param_default (param); /* rate control */ param->rc.f_ip_factor = 1.0 + (double)x264_gtk->keyframe_boost / 100.0; param->rc.f_pb_factor = 1.0 + (double)x264_gtk->bframes_reduction / 100.0; param->rc.f_qcompress = (double)x264_gtk->bitrate_variability / 100.0; param->rc.i_qp_min = x264_gtk->min_qp; param->rc.i_qp_max = x264_gtk->max_qp; param->rc.i_qp_step = x264_gtk->max_qp_step; param->i_scenecut_threshold = x264_gtk->scene_cut_threshold; param->i_keyint_min = x264_gtk->min_idr_frame_interval; param->i_keyint_max = x264_gtk->max_idr_frame_interval; param->rc.i_vbv_max_bitrate = x264_gtk->vbv_max_bitrate; param->rc.i_vbv_buffer_size = x264_gtk->vbv_buffer_size; param->rc.f_vbv_buffer_init = x264_gtk->vbv_buffer_init; /* mb */ param->analyse.b_transform_8x8 = x264_gtk->transform_8x8; param->analyse.inter = 0; if (x264_gtk->pframe_search_8) param->analyse.inter |= X264_ANALYSE_PSUB16x16; if (x264_gtk->bframe_search_8) param->analyse.inter |= X264_ANALYSE_BSUB16x16; if (x264_gtk->pframe_search_4) param->analyse.inter |= X264_ANALYSE_PSUB8x8; if (x264_gtk->inter_search_8) param->analyse.inter |= X264_ANALYSE_I8x8; if (x264_gtk->inter_search_4) param->analyse.inter |= X264_ANALYSE_I4x4; param->b_bframe_pyramid = x264_gtk->bframe_pyramid && x264_gtk->bframe; param->analyse.b_bidir_me = x264_gtk->bidir_me; param->b_bframe_adaptive = x264_gtk->bframe_adaptive; param->analyse.b_weighted_bipred = x264_gtk->weighted_bipred; param->i_bframe = x264_gtk->bframe; param->i_bframe_bias = x264_gtk->bframe_bias; param->analyse.i_direct_mv_pred = x264_gtk->direct_mode; /* param->b_bframe_pyramid = param->b_bframe_pyramid && (param->i_bframe > 1); */ /* more */ param->analyse.i_subpel_refine = x264_gtk->partition_decision + 1; param->analyse.b_bframe_rdo = x264_gtk->bframe_rdo; param->analyse.i_me_method = x264_gtk->me_method; param->analyse.i_me_range = x264_gtk->range; param->analyse.b_chroma_me = x264_gtk->chroma_me; param->analyse.i_trellis = x264_gtk->trellis; param->analyse.i_noise_reduction = x264_gtk->noise_reduction; param->i_frame_reference = x264_gtk->max_ref_frames; param->analyse.b_mixed_references = x264_gtk->mixed_refs; param->analyse.b_fast_pskip = x264_gtk->fast_pskip; param->analyse.b_dct_decimate = x264_gtk->dct_decimate; /* rdo : RD based mode decision for B-frames. Requires subme 6 */ param->vui.i_sar_width = x264_gtk->sample_ar_x; param->vui.i_sar_height = x264_gtk->sample_ar_y; param->i_threads = x264_gtk->threads; param->b_cabac = x264_gtk->cabac; param->b_deblocking_filter = x264_gtk->deblocking_filter; param->i_deblocking_filter_alphac0 = x264_gtk->strength; param->i_deblocking_filter_beta = x264_gtk->threshold; param->i_log_level = x264_gtk->debug_method - 1; /* cqm */ param->i_cqm_preset = x264_gtk->cqm_preset; if (x264_gtk->cqm_file && (x264_gtk->cqm_file[0] != '\0')) param->psz_cqm_file = x264_gtk->cqm_file; memcpy( param->cqm_4iy, x264_gtk->cqm_4iy, 16 ); memcpy( param->cqm_4ic, x264_gtk->cqm_4ic, 16 ); memcpy( param->cqm_4py, x264_gtk->cqm_4py, 16 ); memcpy( param->cqm_4pc, x264_gtk->cqm_4pc, 16 ); memcpy( param->cqm_8iy, x264_gtk->cqm_8iy, 64 ); memcpy( param->cqm_8py, x264_gtk->cqm_8py, 64 ); /* bitrate */ switch (x264_gtk->pass) { case X264_PASS_SINGLE_BITRATE: param->rc.i_rc_method = X264_RC_ABR; param->rc.i_bitrate = x264_gtk->average_bitrate; break; case X264_PASS_SINGLE_QUANTIZER: param->rc.i_rc_method = X264_RC_CQP; param->rc.i_qp_constant = x264_gtk->quantizer; break; case X264_PASS_MULTIPASS_1ST_FAST: param->analyse.i_subpel_refine = X264_MAX( X264_MIN( 3, param->analyse.i_subpel_refine - 1 ), 1 ); param->i_frame_reference = ( param->i_frame_reference + 1 ) >> 1; param->analyse.inter &= ( ~X264_ANALYSE_PSUB8x8 ); param->analyse.inter &= ( ~X264_ANALYSE_BSUB16x16 ); case X264_PASS_MULTIPASS_1ST: param->rc.i_rc_method = X264_RC_ABR; param->rc.i_bitrate = x264_gtk->average_bitrate; param->rc.f_rate_tolerance = 4.0; break; case X264_PASS_MULTIPASS_NTH: param->rc.i_rc_method = X264_RC_ABR; param->rc.i_bitrate = x264_gtk->average_bitrate; param->rc.f_rate_tolerance = 1.0; break; } param->rc.b_stat_write = x264_gtk->stat_write; param->rc.b_stat_read = x264_gtk->stat_read; /* FIXME: potential mem leak... */ param->rc.psz_stat_out = x264_gtk_path (x264_gtk->statsfile_name); return param; }