static av_cold void libx265_encode_init_csp(AVCodec *codec) { if (x265_api_get(12)) codec->pix_fmts = x265_csp_twelve; else if (x265_api_get(10)) codec->pix_fmts = x265_csp_ten; else if (x265_api_get(8)) codec->pix_fmts = x265_csp_eight; }
/*********************************************************************** * 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 av_cold int libx265_encode_init(AVCodecContext *avctx) { libx265Context *ctx = avctx->priv_data; ctx->api = x265_api_get(av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth); if (!ctx->api) ctx->api = x265_api_get(0); ctx->params = ctx->api->param_alloc(); if (!ctx->params) { av_log(avctx, AV_LOG_ERROR, "Could not allocate x265 param structure.\n"); return AVERROR(ENOMEM); } if (ctx->api->param_default_preset(ctx->params, ctx->preset, ctx->tune) < 0) { int i; av_log(avctx, AV_LOG_ERROR, "Error setting preset/tune %s/%s.\n", ctx->preset, ctx->tune); av_log(avctx, AV_LOG_INFO, "Possible presets:"); for (i = 0; x265_preset_names[i]; i++) av_log(avctx, AV_LOG_INFO, " %s", x265_preset_names[i]); av_log(avctx, AV_LOG_INFO, "\n"); av_log(avctx, AV_LOG_INFO, "Possible tunes:"); for (i = 0; x265_tune_names[i]; i++) av_log(avctx, AV_LOG_INFO, " %s", x265_tune_names[i]); av_log(avctx, AV_LOG_INFO, "\n"); return AVERROR(EINVAL); } ctx->params->frameNumThreads = avctx->thread_count; ctx->params->fpsNum = avctx->time_base.den; ctx->params->fpsDenom = avctx->time_base.num * avctx->ticks_per_frame; ctx->params->sourceWidth = avctx->width; ctx->params->sourceHeight = avctx->height; ctx->params->bEnablePsnr = !!(avctx->flags & AV_CODEC_FLAG_PSNR); if ((avctx->color_primaries <= AVCOL_PRI_SMPTE432 && avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) || (avctx->color_trc <= AVCOL_TRC_ARIB_STD_B67 && avctx->color_trc != AVCOL_TRC_UNSPECIFIED) || (avctx->colorspace <= AVCOL_SPC_ICTCP && avctx->colorspace != AVCOL_SPC_UNSPECIFIED)) { ctx->params->vui.bEnableVideoSignalTypePresentFlag = 1; ctx->params->vui.bEnableColorDescriptionPresentFlag = 1; // x265 validates the parameters internally ctx->params->vui.colorPrimaries = avctx->color_primaries; ctx->params->vui.transferCharacteristics = avctx->color_trc; ctx->params->vui.matrixCoeffs = avctx->colorspace; } if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0) { char sar[12]; int sar_num, sar_den; av_reduce(&sar_num, &sar_den, avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den, 65535); snprintf(sar, sizeof(sar), "%d:%d", sar_num, sar_den); if (ctx->api->param_parse(ctx->params, "sar", sar) == X265_PARAM_BAD_VALUE) { av_log(avctx, AV_LOG_ERROR, "Invalid SAR: %d:%d.\n", sar_num, sar_den); return AVERROR_INVALIDDATA; } } switch (avctx->pix_fmt) { case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUV420P10: case AV_PIX_FMT_YUV420P12: ctx->params->internalCsp = X265_CSP_I420; break; case AV_PIX_FMT_YUV422P: case AV_PIX_FMT_YUV422P10: case AV_PIX_FMT_YUV422P12: ctx->params->internalCsp = X265_CSP_I422; break; case AV_PIX_FMT_GBRP: case AV_PIX_FMT_GBRP10: case AV_PIX_FMT_GBRP12: ctx->params->vui.matrixCoeffs = AVCOL_SPC_RGB; ctx->params->vui.bEnableVideoSignalTypePresentFlag = 1; ctx->params->vui.bEnableColorDescriptionPresentFlag = 1; case AV_PIX_FMT_YUV444P: case AV_PIX_FMT_YUV444P10: case AV_PIX_FMT_YUV444P12: ctx->params->internalCsp = X265_CSP_I444; break; case AV_PIX_FMT_GRAY8: case AV_PIX_FMT_GRAY10: case AV_PIX_FMT_GRAY12: if (ctx->api->api_build_number < 85) { av_log(avctx, AV_LOG_ERROR, "libx265 version is %d, must be at least 85 for gray encoding.\n", ctx->api->api_build_number); return AVERROR_INVALIDDATA; } ctx->params->internalCsp = X265_CSP_I400; break; } if (ctx->crf >= 0) { char crf[6]; snprintf(crf, sizeof(crf), "%2.2f", ctx->crf); if (ctx->api->param_parse(ctx->params, "crf", crf) == X265_PARAM_BAD_VALUE) { av_log(avctx, AV_LOG_ERROR, "Invalid crf: %2.2f.\n", ctx->crf); return AVERROR(EINVAL); } } else if (avctx->bit_rate > 0) { ctx->params->rc.bitrate = avctx->bit_rate / 1000; ctx->params->rc.rateControlMode = X265_RC_ABR; } if (!(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) ctx->params->bRepeatHeaders = 1; if (ctx->x265_opts) { AVDictionary *dict = NULL; AVDictionaryEntry *en = NULL; if (!av_dict_parse_string(&dict, ctx->x265_opts, "=", ":", 0)) { while ((en = av_dict_get(dict, "", en, AV_DICT_IGNORE_SUFFIX))) { int parse_ret = ctx->api->param_parse(ctx->params, en->key, en->value); switch (parse_ret) { case X265_PARAM_BAD_NAME: av_log(avctx, AV_LOG_WARNING, "Unknown option: %s.\n", en->key); break; case X265_PARAM_BAD_VALUE: av_log(avctx, AV_LOG_WARNING, "Invalid value for %s: %s.\n", en->key, en->value); break; default: break; } } av_dict_free(&dict); } } if (ctx->profile) { if (ctx->api->param_apply_profile(ctx->params, ctx->profile) < 0) { int i; av_log(avctx, AV_LOG_ERROR, "Invalid or incompatible profile set: %s.\n", ctx->profile); av_log(avctx, AV_LOG_INFO, "Possible profiles:"); for (i = 0; x265_profile_names[i]; i++) av_log(avctx, AV_LOG_INFO, " %s", x265_profile_names[i]); av_log(avctx, AV_LOG_INFO, "\n"); return AVERROR(EINVAL); } } ctx->encoder = ctx->api->encoder_open(ctx->params); if (!ctx->encoder) { av_log(avctx, AV_LOG_ERROR, "Cannot open libx265 encoder.\n"); libx265_encode_close(avctx); return AVERROR_INVALIDDATA; } if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { x265_nal *nal; int nnal; avctx->extradata_size = ctx->api->encoder_headers(ctx->encoder, &nal, &nnal); if (avctx->extradata_size <= 0) { av_log(avctx, AV_LOG_ERROR, "Cannot encode headers.\n"); libx265_encode_close(avctx); return AVERROR_INVALIDDATA; } avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!avctx->extradata) { av_log(avctx, AV_LOG_ERROR, "Cannot allocate HEVC header of size %d.\n", avctx->extradata_size); libx265_encode_close(avctx); return AVERROR(ENOMEM); } memcpy(avctx->extradata, nal[0].payload, avctx->extradata_size); } return 0; }