Index: common/common.c =================================================================== --- common/common.c (revision 670) +++ common/common.c (working copy) @@ -58,6 +58,7 @@ param->vui.i_transfer = 2; /* undef */ param->vui.i_colmatrix = 2; /* undef */ param->vui.i_chroma_loc= 0; /* left center */ + param->fgm.b_fgm = 0; /* off */ param->i_fps_num = 25; param->i_fps_den = 1; param->i_level_idc = 51; /* as close to "unrestricted" as we can get */ @@ -276,6 +277,24 @@ p->vui.i_chroma_loc = atoi(value); b_error = ( p->vui.i_chroma_loc < 0 || p->vui.i_chroma_loc > 5 ); } + OPT2("fgm", "grain") + { + int i_fgm_args; + p->fgm.i_comp_model_value[0] = p->fgm.i_comp_model_value[1] = p->fgm.i_comp_model_value[2] = + p->fgm.i_comp_model_value[3] = p->fgm.i_comp_model_value[4] = p->fgm.i_comp_model_value[5] = -1; + i_fgm_args = sscanf( value, "%d,%d,%d,%d,%d,%d,%d,%d,%d", + &p->fgm.i_model_id, &p->fgm.i_blending_mode_id, &p->fgm.i_log2_scale_factor, + &p->fgm.i_comp_model_value[0], &p->fgm.i_comp_model_value[1], &p->fgm.i_comp_model_value[2], + &p->fgm.i_comp_model_value[3], &p->fgm.i_comp_model_value[4], &p->fgm.i_comp_model_value[5]); + if( i_fgm_args <= 9 && i_fgm_args >= 4) + { + p->fgm.b_fgm = 1; + p->fgm.i_num_model_values = i_fgm_args - 3; + b_error |= ( p->fgm.i_model_id < 0 || p->fgm.i_model_id > 1 ); + b_error |= ( p->fgm.i_blending_mode_id < 0 || p->fgm.i_blending_mode_id > 1 ); + b_error |= ( p->fgm.i_log2_scale_factor > 15 ); + } + } OPT("fps") { if( sscanf( value, "%d/%d", &p->i_fps_num, &p->i_fps_den ) == 2 ) Index: encoder/encoder.c =================================================================== --- encoder/encoder.c (revision 670) +++ encoder/encoder.c (working copy) @@ -811,6 +811,16 @@ x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST ); x264_pps_write( &h->out.bs, h->pps ); x264_nal_end( h ); + + /* fgm parameters */ + if (h->param.fgm.b_fgm) + x264_sei_fgm_validate( &h->param ); + if (h->param.fgm.b_fgm) + { + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + x264_sei_fgm_write( &h->out.bs, h, &h->param ); + x264_nal_end( h ); + } } /* now set output*/ *pi_nal = h->out.i_nal; @@ -1463,6 +1473,9 @@ x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); x264_sei_version_write( h, &h->out.bs ); x264_nal_end( h ); + + if (h->param.fgm.b_fgm) + x264_sei_fgm_validate( &h->param ); } /* generate sequence parameters */ @@ -1474,6 +1487,14 @@ x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST ); x264_pps_write( &h->out.bs, h->pps ); x264_nal_end( h ); + + /* fgm parameters */ + if (h->param.fgm.b_fgm) + { + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + x264_sei_fgm_write( &h->out.bs, h, &h->param ); + x264_nal_end( h ); + } } /* Write frame */ Index: encoder/set.c =================================================================== --- encoder/set.c (revision 670) +++ encoder/set.c (working copy) @@ -498,11 +498,130 @@ bs_write( s, 8, version[i] ); bs_rbsp_trailing( s ); - x264_free( opts ); x264_free( version ); } +void x264_sei_fgm_validate(x264_param_t *param ) +{ + if (param->fgm.i_model_id < 0 || param->fgm.i_model_id > 1) + { + param->fgm.b_fgm = 0; + return; + } + if (param->fgm.i_blending_mode_id < 0 || param->fgm.i_blending_mode_id > 1) + { + param->fgm.b_fgm = 0; + return; + } + if (param->fgm.i_log2_scale_factor < 0 || param->fgm.i_log2_scale_factor > 15) + { + param->fgm.b_fgm = 0; + return; + } + + switch (param->fgm.i_num_model_values) + { + case 6: + if (param->fgm.i_comp_model_value[5] == 0) + param->fgm.i_num_model_values--; + case 5: + if (param->fgm.i_comp_model_value[4] < 0 || param->fgm.i_comp_model_value[4] > param->fgm.i_comp_model_value[2]) + { + param->fgm.b_fgm = 0; + return; + } + if (param->fgm.i_num_model_values == 5) + if (param->fgm.i_comp_model_value[4] == param->fgm.i_model_id) + param->fgm.i_num_model_values--; + case 4: + if (param->fgm.i_comp_model_value[3] < 0 || param->fgm.i_comp_model_value[3] > param->fgm.i_comp_model_value[1]) + { + param->fgm.b_fgm = 0; + return; + } + if (param->fgm.i_num_model_values == 4) + if (param->fgm.i_comp_model_value[3] == 0) + param->fgm.i_num_model_values--; + case 3: + if (param->fgm.i_comp_model_value[2] < 0 || param->fgm.i_comp_model_value[2] > 15) + { + param->fgm.b_fgm = 0; + return; + } + if (param->fgm.i_num_model_values == 3) + if (param->fgm.i_model_id == 0) + { + if (param->fgm.i_comp_model_value[2] == param->fgm.i_comp_model_value[1]) + param->fgm.i_num_model_values--; + } + else + { + if (param->fgm.i_comp_model_value[2] == 0) + param->fgm.i_num_model_values--; + } + case 2: + if (param->fgm.i_comp_model_value[1] < 0 || param->fgm.i_comp_model_value[1] > 15) + { + param->fgm.b_fgm = 0; + return; + } + if (param->fgm.i_num_model_values == 2) + if (param->fgm.i_model_id == 0) + { + if (param->fgm.i_comp_model_value[1] == 8) + param->fgm.i_num_model_values--; + } + else + { + if (param->fgm.i_comp_model_value[1] == 0) + param->fgm.i_num_model_values--; + } + case 1: + break; + default: + param->fgm.b_fgm = 0; + return; + } +} + + +void x264_sei_fgm_write( bs_t *s, x264_t *h, x264_param_t *param ) +{ + int j; + + bs_write( s, 8, 0x13 ); // payload_type = film_grain_characteristics + + bs_write( s, 8, 0 ); // last payload_size + + bs_write1( s, 0); //film_grain_characteristics_cancel_flag + + bs_write( s, 2, param->fgm.i_model_id); + bs_write1( s, 0); //separate_colour_description_present_flag + bs_write( s, 2, param->fgm.i_blending_mode_id); + bs_write( s, 4, param->fgm.i_log2_scale_factor); + + //just luma + bs_write1( s, 1); //comp_model_present_flag[0] + bs_write1( s, 0); //comp_model_present_flag[1] + bs_write1( s, 0); //comp_model_present_flag[2] + + //only 1 single interval, full range + bs_write( s, 8, 0); //num_intensity_intervals_minus1 + bs_write( s, 3, param->fgm.i_num_model_values-1); + bs_write( s, 8, 0); //intensity_interval_lower_bound + bs_write( s, 8, 255); //intensity_interval_upper_bound + for (j=0; j<=param->fgm.i_num_model_values-1; j++) + { + bs_write_se(s, param->fgm.i_comp_model_value[j]); + } + + bs_write_ue( s, 1); //film_grain_characteristics_repetition_period + + bs_rbsp_trailing( s ); +} + + const x264_level_t x264_levels[] = { { 10, 1485, 99, 152064, 64, 175, 64, 64, 0, 0, 0, 1 }, Index: encoder/set.h =================================================================== --- encoder/set.h (revision 670) +++ encoder/set.h (working copy) @@ -29,6 +29,8 @@ void x264_pps_init( x264_pps_t *pps, int i_id, x264_param_t *param, x264_sps_t *sps ); void x264_pps_write( bs_t *s, x264_pps_t *pps ); void x264_sei_version_write( x264_t *h, bs_t *s ); +void x264_sei_fgm_validate(x264_param_t *param ); +void x264_sei_fgm_write( bs_t *s, x264_t *h, x264_param_t *param ); void x264_validate_levels( x264_t *h ); #endif Index: x264.c =================================================================== --- x264.c (revision 670) +++ x264.c (working copy) @@ -261,6 +261,17 @@ H1( " --cqm4iy, --cqm4ic, --cqm4py, --cqm4pc\n" " Set individual quant matrices\n" ); H1( "\n" ); + H1( "Film Grain Characteristics (Annex D):\n" ); + H1( "The film grain information is not used by the encoder but is a suggestions to\n" ); + H1( "the playback equipment in order to synthetically recreate grain.\n" ); + H1( "\n" ); + H1( " --grain Specify grain modeling parameters\n" + " - param0/model id - 0: frequency filtering - 1: auto-regression\n"); + H1( " - param1/blending mode id - 0: additive - 1: multiplicative\n", + " - param2 - scale factor (log2) used for the following parameters\n"); + H1( " - param3 to param8 - grain parameters values,\n"); + H1( " a minimum of 1 value should be provided\n"); + H1( "\n" ); H1( "Video Usability Info (Annex E):\n" ); H1( "The VUI settings are not used by the encoder but are merely suggestions to\n" ); H1( "the playback equipment. See doc/vui.txt for details. Use at your own risk.\n" ); @@ -455,6 +466,8 @@ { "transfer", required_argument, NULL, 0 }, { "colormatrix", required_argument, NULL, 0 }, { "chromaloc", required_argument, NULL, 0 }, + { "fgm", required_argument, NULL, 0 }, + { "grain", required_argument, NULL, 0 }, {0, 0, 0, 0} }; Index: x264.h =================================================================== --- x264.h (revision 670) +++ x264.h (working copy) @@ -165,6 +165,20 @@ int i_chroma_loc; /* both top & bottom */ } vui; +#define MAX_FGM_MODEL_VALUES 6 + + struct + { + int b_fgm; + + int i_model_id; + int i_blending_mode_id; + int i_log2_scale_factor; + + int i_comp_model_value[MAX_FGM_MODEL_VALUES]; + int i_num_model_values; + } fgm; + int i_fps_num; int i_fps_den;