/*********************************************************************** * hb_work_encx265_init *********************************************************************** * **********************************************************************/ int encx265Init(hb_work_object_t *w, hb_job_t *job) { hb_work_private_t *pv = calloc(1, sizeof(hb_work_private_t)); int ret, depth; hb_rational_t vrate; x265_nal *nal; uint32_t nnal; const char * const *profile_names; pv->next_chapter_pts = AV_NOPTS_VALUE; pv->delayed_chapters = hb_list_init(); pv->job = job; w->private_data = pv; depth = hb_video_encoder_get_depth(job->vcodec); profile_names = hb_video_encoder_get_profiles(job->vcodec); pv->api = x265_api_get(depth); if (pv->api == NULL) { hb_error("encx265: x265_api_get failed, bit depth %d.", depth); goto fail; } x265_param *param = pv->param = pv->api->param_alloc(); if (pv->api->param_default_preset(param, job->encoder_preset, job->encoder_tune) < 0) { hb_error("encx265: x265_param_default_preset failed. Preset (%s) Tune (%s)", job->encoder_preset, job->encoder_tune); goto fail; } /* If the PSNR or SSIM tunes are in use, enable the relevant metric */ param->bEnablePsnr = param->bEnableSsim = 0; if (job->encoder_tune != NULL && *job->encoder_tune) { char *tmp = strdup(job->encoder_tune); char *tok = strtok(tmp, ",./-+"); do { if (!strncasecmp(tok, "psnr", 4)) { param->bEnablePsnr = 1; break; } if (!strncasecmp(tok, "ssim", 4)) { param->bEnableSsim = 1; break; } } while ((tok = strtok(NULL, ",./-+")) != NULL); free(tmp); } /* * Some HandBrake-specific defaults; users can override them * using the encoder_options string. */ hb_reduce(&vrate.num, &vrate.den, job->vrate.num, job->vrate.den); param->fpsNum = vrate.num; param->fpsDenom = vrate.den; param->keyframeMin = (double)job->orig_vrate.num / job->orig_vrate.den + 0.5; param->keyframeMax = param->keyframeMin * 10; /* * Video Signal Type (color description only). * * Use x265_param_parse (let x265 determine which bEnable * flags, if any, should be set in the x265_param struct). */ char colorprim[11], transfer[11], colormatrix[11]; switch (job->color_matrix_code) { case 1: // ITU BT.601 DVD or SD TV content (NTSC) strcpy(colorprim, "smpte170m"); strcpy(transfer, "bt709"); strcpy(colormatrix, "smpte170m"); break; case 2: // ITU BT.601 DVD or SD TV content (PAL) strcpy(colorprim, "bt470bg"); strcpy(transfer, "bt709"); strcpy(colormatrix, "smpte170m"); break; case 3: // ITU BT.709 HD content strcpy(colorprim, "bt709"); strcpy(transfer, "bt709"); strcpy(colormatrix, "bt709"); break; case 4: // custom snprintf(colorprim, sizeof(colorprim), "%d", job->color_prim); snprintf(transfer, sizeof(transfer), "%d", job->color_transfer); snprintf(colormatrix, sizeof(colormatrix), "%d", job->color_matrix); break; default: // detected during scan snprintf(colorprim, sizeof(colorprim), "%d", job->title->color_prim); snprintf(transfer, sizeof(transfer), "%d", job->title->color_transfer); snprintf(colormatrix, sizeof(colormatrix), "%d", job->title->color_matrix); break; } if (param_parse(pv, param, "colorprim", colorprim) || param_parse(pv, param, "transfer", transfer) || param_parse(pv, param, "colormatrix", colormatrix)) { goto fail; } /* iterate through x265_opts and parse the options */ hb_dict_t *x265_opts; x265_opts = hb_encopts_to_dict(job->encoder_options, job->vcodec); hb_dict_iter_t iter; for (iter = hb_dict_iter_init(x265_opts); iter != HB_DICT_ITER_DONE; iter = hb_dict_iter_next(x265_opts, iter)) { const char *key = hb_dict_iter_key(iter); hb_value_t *value = hb_dict_iter_value(iter); char *str = hb_value_get_string_xform(value); // here's where the strings are passed to libx265 for parsing // unknown options or bad values are non-fatal, see encx264.c param_parse(pv, param, key, str); free(str); } hb_dict_free(&x265_opts); /* * Reload colorimetry settings in case custom * values were set in the encoder_options string. */ job->color_matrix_code = 4; job->color_prim = param->vui.colorPrimaries; job->color_transfer = param->vui.transferCharacteristics; job->color_matrix = param->vui.matrixCoeffs; /* * Settings which can't be overriden in the encodeer_options string * (muxer-specific settings, resolution, ratecontrol, etc.). */ param->bRepeatHeaders = 0; param->sourceWidth = job->width; param->sourceHeight = job->height; /* * Let x265 determnine whether to use an aspect ratio * index vs. the extended SAR index + SAR width/height. */ char sar[22]; snprintf(sar, sizeof(sar), "%d:%d", job->par.num, job->par.den); if (param_parse(pv, param, "sar", sar)) { goto fail; } if (job->vquality > 0) { param->rc.rateControlMode = X265_RC_CRF; param->rc.rfConstant = job->vquality; } else { param->rc.rateControlMode = X265_RC_ABR; param->rc.bitrate = job->vbitrate; if (job->pass_id == HB_PASS_ENCODE_1ST || job->pass_id == HB_PASS_ENCODE_2ND) { char stats_file[1024] = ""; char pass[2]; snprintf(pass, sizeof(pass), "%d", job->pass_id); hb_get_tempory_filename(job->h, stats_file, "x265.log"); if (param_parse(pv, param, "stats", stats_file) || param_parse(pv, param, "pass", pass)) { goto fail; } if (job->pass_id == HB_PASS_ENCODE_1ST && job->fastfirstpass == 0 && param_parse(pv, param, "slow-firstpass", "1")) { goto fail; } } } /* statsfile (but not 2-pass) */ memset(pv->csvfn, 0, sizeof(pv->csvfn)); if (param->logLevel >= X265_LOG_DEBUG) { if (param->csvfn == NULL) { hb_get_tempory_filename(job->h, pv->csvfn, "x265.csv"); param->csvfn = pv->csvfn; } else { strncpy(pv->csvfn, param->csvfn, sizeof(pv->csvfn)); } } /* Apply profile and level settings last. */ if (job->encoder_profile != NULL && strcasecmp(job->encoder_profile, profile_names[0]) != 0 && pv->api->param_apply_profile(param, job->encoder_profile) < 0) { goto fail; } /* we should now know whether B-frames are enabled */ job->areBframes = (param->bframes > 0) + (param->bframes > 0 && param->bBPyramid > 0); /* Reset global variables before opening a new encoder */ pv->api->cleanup(); pv->x265 = pv->api->encoder_open(param); if (pv->x265 == NULL) { hb_error("encx265: x265_encoder_open failed."); goto fail; } /* * x265's output (headers and bitstream) are in Annex B format. * * Write the header as is, and let the muxer reformat * the extradata and output bitstream properly for us. */ ret = pv->api->encoder_headers(pv->x265, &nal, &nnal); if (ret < 0) { hb_error("encx265: x265_encoder_headers failed (%d)", ret); goto fail; } if (ret > sizeof(w->config->h265.headers)) { hb_error("encx265: bitstream headers too large (%d)", ret); goto fail; } memcpy(w->config->h265.headers, nal->payload, ret); w->config->h265.headers_length = ret; return 0; fail: w->private_data = NULL; free(pv); return 1; }
static void update_adv_settings_tooltip(signal_user_data_t *ud) { if (video_option_tooltip == NULL) { GtkWidget *eo = GTK_WIDGET(GHB_WIDGET(ud->builder, "VideoOptionExtra")); video_option_tooltip = gtk_widget_get_tooltip_text(eo); } int encoder = ghb_get_video_encoder(ud->settings); if (!ghb_dict_get_bool(ud->settings, "x264UseAdvancedOptions") && (encoder & HB_VCODEC_X264_MASK)) { GString *str = g_string_new(""); const char *preset; const char *tune; const char *profile; const char *level; const char *opts; char *tunes; preset = ghb_dict_get_string(ud->settings, "VideoPreset"); tune = ghb_dict_get_string(ud->settings, "VideoTune"); profile = ghb_dict_get_string(ud->settings, "VideoProfile"); level = ghb_dict_get_string(ud->settings, "VideoLevel"); opts = ghb_dict_get_string(ud->settings, "VideoOptionExtra"); if (tune[0] && strcmp(tune, "none")) { g_string_append_printf(str, "%s", tune); } if (ghb_dict_get_bool(ud->settings, "x264FastDecode")) { g_string_append_printf(str, "%s%s", str->str[0] ? "," : "", "fastdecode"); } if (ghb_dict_get_bool(ud->settings, "x264ZeroLatency")) { g_string_append_printf(str, "%s%s", str->str[0] ? "," : "", "zerolatency"); } tunes = g_string_free(str, FALSE); char * new_opts; int w = ghb_dict_get_int(ud->settings, "scale_width"); int h = ghb_dict_get_int(ud->settings, "scale_height"); if (w == 0 || h == 0) { if (!ghb_dict_get_bool(ud->settings, "autoscale")) { w = ghb_dict_get_int(ud->settings, "PictureWidth"); h = ghb_dict_get_int(ud->settings, "PictureHeight"); if (h == 0 && w != 0) { h = w * 9 / 16; } if (w == 0 && h != 0) { w = h * 16 / 9; } } if (w == 0 || h == 0) { w = 1280; h = 720; } } if (!strcasecmp(profile, "auto")) { profile = ""; } if (!strcasecmp(level, "auto")) { level = ""; } new_opts = hb_x264_param_unparse(hb_video_encoder_get_depth(encoder), preset, tunes, opts, profile, level, w, h); if (new_opts) ghb_update_x264Option(ud, new_opts); else ghb_update_x264Option(ud, ""); GtkWidget *eo = GTK_WIDGET(GHB_WIDGET(ud->builder, "VideoOptionExtra")); char * tt; if (new_opts) tt = g_strdup_printf(_("%s\n\nExpanded Options:\n\"%s\""), video_option_tooltip, new_opts); else tt = g_strdup_printf(_("%s\n\nExpanded Options:\n\"\""), video_option_tooltip); gtk_widget_set_tooltip_text(eo, tt); g_free(tt); g_free(new_opts); g_free(tunes); } else if (ghb_dict_get_bool(ud->settings, "x264UseAdvancedOptions")) { const char *opts = ghb_dict_get_string(ud->settings, "x264Option"); GtkWidget *eo = GTK_WIDGET(GHB_WIDGET(ud->builder, "VideoOptionExtra")); char * tt; if (opts) tt = g_strdup_printf(_("%s\n\nExpanded Options:\n\"%s\""), video_option_tooltip, opts); else tt = g_strdup_printf(_("%s\n\nExpanded Options:\n\"\""), video_option_tooltip); gtk_widget_set_tooltip_text(eo, tt); g_free(tt); } }