char * hb_dict_to_encopts( hb_dict_t * dict ) { int first_opt = 1; char *tmp, *encopts_tmp, *encopts = NULL; hb_dict_entry_t * entry = NULL; while( ( entry = hb_dict_next( dict, entry ) ) ) { tmp = hb_strdup_printf( "%s%s%s%s", first_opt ? "" : ":", entry->key, entry->value ? "=" : "", entry->value ? entry->value : "" ); if( tmp ) { encopts_tmp = hb_strncat_dup( encopts, tmp, strlen( tmp ) ); if( encopts_tmp ) { if( encopts ) free( encopts ); encopts = encopts_tmp; } first_opt = 0; free( tmp ); } } return encopts; }
/*********************************************************************** * 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)); pv->next_chapter_pts = AV_NOPTS_VALUE; pv->delayed_chapters = hb_list_init(); pv->job = job; w->private_data = pv; int i, vrate, vrate_base; x265_nal *nal; uint32_t nnal; x265_param *param = pv->param = x265_param_alloc(); if (x265_param_default_preset(param, job->encoder_preset, job->encoder_tune) < 0) { free(pv); pv = NULL; return 1; } /* 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, &vrate_base, job->vrate, job->vrate_base); param->fpsNum = vrate; param->fpsDenom = vrate_base; param->keyframeMin = (int)((double)vrate / (double)vrate_base + 0.5); param->keyframeMax = param->keyframeMin * 10; /* iterate through x265_opts and parse the options */ hb_dict_entry_t *entry = NULL; hb_dict_t *x265_opts = hb_encopts_to_dict(job->encoder_options, job->vcodec); while ((entry = hb_dict_next(x265_opts, entry)) != NULL) { // here's where the strings are passed to libx265 for parsing int ret = x265_param_parse(param, entry->key, entry->value); // let x265 sanity check the options for us switch (ret) { case X265_PARAM_BAD_NAME: hb_log("encx265: unknown option '%s'", entry->key); break; case X265_PARAM_BAD_VALUE: hb_log("encx265: bad argument '%s=%s'", entry->key, entry->value ? entry->value : "(null)"); break; default: break; } } hb_dict_free(&x265_opts); /* * Settings which can't be overriden in the encodeer_options string * (muxer-specific settings, resolution, ratecontrol, etc.). */ param->sourceWidth = job->width; param->sourceHeight = job->height; 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; } /* 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 (x265_param_apply_profile(param, job->encoder_profile) < 0) { free(pv); pv = NULL; return 1; } /* we should now know whether B-frames are enabled */ job->areBframes = (param->bframes > 0) + (param->bframes > 0 && param->bBPyramid > 0); pv->x265 = x265_encoder_open(param); if (pv->x265 == NULL) { hb_error("encx265: x265_encoder_open failed."); free(pv); pv = NULL; return 1; } if (x265_encoder_headers(pv->x265, &nal, &nnal) < 0) { hb_error("encx265: x265_encoder_headers failed."); free(pv); pv = NULL; return 1; } /* * 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. */ w->config->h265.headers_length = 0; for (i = 0; i < nnal; i++) { if (w->config->h265.headers_length + nal[i].sizeBytes > HB_CONFIG_MAX_SIZE) { hb_error("encx265: bitstream headers too large"); free(pv); pv = NULL; return 1; } memcpy(w->config->h265.headers + w->config->h265.headers_length, nal[i].payload, nal[i].sizeBytes); w->config->h265.headers_length += nal[i].sizeBytes; } return 0; }