/*********************************************************************** * 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 gval_write(FILE *file, hb_value_t *gval) { static int indent = 0; int ii; hb_value_type_t gtype; if (gval == NULL) return; gtype = hb_value_type(gval); if (gtype == HB_VALUE_TYPE_ARRAY) { hb_value_t *val; int count; indent_fprintf(file, indent, "<array>\n"); indent++; count = hb_value_array_len(gval); for (ii = 0; ii < count; ii++) { val = hb_value_array_get(gval, ii); gval_write(file, val); } indent--; indent_fprintf(file, indent, "</array>\n"); } else if (gtype == HB_VALUE_TYPE_DICT) { const char *key; hb_value_t *val; hb_dict_iter_t iter; indent_fprintf(file, indent, "<dict>\n"); indent++; for (iter = hb_dict_iter_init(gval); iter != HB_DICT_ITER_DONE; iter = hb_dict_iter_next(gval, iter)) { key = hb_dict_iter_key(iter); val = hb_dict_iter_value(iter); indent_fprintf(file, indent, "<key>%s</key>\n", key); gval_write(file, val); } indent--; indent_fprintf(file, indent, "</dict>\n"); } else if (gtype == HB_VALUE_TYPE_BOOL) { char *tag; if (hb_value_get_bool(gval)) { tag = "true"; } else { tag = "false"; } indent_fprintf(file, indent, "<%s />\n", tag); } else if (gtype == HB_VALUE_TYPE_DOUBLE) { double val = hb_value_get_double(gval); indent_fprintf(file, indent, "<real>%.17g</real>\n", val); } else if (gtype == HB_VALUE_TYPE_INT) { int64_t val = hb_value_get_int(gval); indent_fprintf(file, indent, "<integer>%"PRId64"</integer>\n", val); } else if (gtype == HB_VALUE_TYPE_STRING) { const char *str = hb_value_get_string(gval); char *esc = markup_escape_text(str); indent_fprintf(file, indent, "<string>%s</string>\n", esc); free(esc); } else { // Try to make anything thats unrecognized into a string hb_error("Unhandled data type %d", gtype); } }