From 9e9e47cd1913a34bd248a3ac5a8da9765e638bdc Mon Sep 17 00:00:00 2001 From: jstebbins Date: Mon, 9 Mar 2015 15:05:47 +0000 Subject: libhb: use jansson for hb_dict This paves the way to doing preset processing in libhb. Initially for the CLI but other frontends may benefit eventually. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@6981 b64f7644-9d1e-0410-96f1-a4d463321fa5 --- libhb/enc_qsv.c | 22 +- libhb/encavcodec.c | 13 +- libhb/encx264.c | 392 ++++++++++++++++----------------- libhb/encx265.c | 18 +- libhb/hb_dict.c | 620 +++++++++++++++++++++++++++++++++++++++++------------ libhb/hb_dict.h | 123 ++++++++--- libhb/hb_json.c | 1 + libhb/hb_json.h | 2 +- 8 files changed, 814 insertions(+), 377 deletions(-) (limited to 'libhb') diff --git a/libhb/enc_qsv.c b/libhb/enc_qsv.c index 8051bd5d0..c4aca79ff 100644 --- a/libhb/enc_qsv.c +++ b/libhb/enc_qsv.c @@ -577,27 +577,32 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job) if (job->encoder_options != NULL && *job->encoder_options) { hb_dict_t *options_list; - hb_dict_entry_t *option = NULL; options_list = hb_encopts_to_dict(job->encoder_options, job->vcodec); - while ((option = hb_dict_next(options_list, option)) != NULL) + + hb_dict_iter_t iter; + for (iter = hb_dict_iter_init(x264_opts); + iter != HB_DICT_ITER_DONE; + iter = hb_dict_iter_next(x264_opts, iter)) { - switch (hb_qsv_param_parse(&pv->param, pv->qsv_info, - option->key, option->value)) + 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); + + switch (hb_qsv_param_parse(&pv->param, pv->qsv_info, key, str)) { case HB_QSV_PARAM_OK: break; case HB_QSV_PARAM_BAD_NAME: - hb_log("encqsvInit: hb_qsv_param_parse: bad key %s", - option->key); + hb_log("encqsvInit: hb_qsv_param_parse: bad key %s", key); break; case HB_QSV_PARAM_BAD_VALUE: hb_log("encqsvInit: hb_qsv_param_parse: bad value %s for key %s", - option->value, option->key); + str, key); break; case HB_QSV_PARAM_UNSUPPORTED: hb_log("encqsvInit: hb_qsv_param_parse: unsupported option %s", - option->key); + key); break; case HB_QSV_PARAM_ERROR: @@ -605,6 +610,7 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job) hb_log("encqsvInit: hb_qsv_param_parse: unknown error"); break; } + free(str); } hb_dict_free(&options_list); } diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c index fe479a393..7b1c01ccc 100644 --- a/libhb/encavcodec.c +++ b/libhb/encavcodec.c @@ -170,11 +170,18 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job ) } /* iterate through lavc_opts and have avutil parse the options for us */ AVDictionary * av_opts = NULL; - hb_dict_entry_t * entry = NULL; - while( ( entry = hb_dict_next( lavc_opts, entry ) ) ) + hb_dict_iter_t iter; + for (iter = hb_dict_iter_init(lavc_opts); + iter != HB_DICT_ITER_DONE; + iter = hb_dict_iter_next(lavc_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 avutil for parsing. */ - av_dict_set( &av_opts, entry->key, entry->value, 0 ); + av_dict_set( &av_opts, key, str, 0 ); + free(str); } hb_dict_free( &lavc_opts ); diff --git a/libhb/encx264.c b/libhb/encx264.c index 780385d7b..d64e56547 100644 --- a/libhb/encx264.c +++ b/libhb/encx264.c @@ -200,18 +200,27 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job ) } /* iterate through x264_opts and have libx264 parse the options for us */ int ret; - hb_dict_entry_t * entry = NULL; - while( ( entry = hb_dict_next( x264_opts, entry ) ) ) + hb_dict_iter_t iter; + for (iter = hb_dict_iter_init(x264_opts); + iter != HB_DICT_ITER_DONE; + iter = hb_dict_iter_next(x264_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 libx264 for parsing. */ - ret = x264_param_parse( ¶m, entry->key, entry->value ); + ret = x264_param_parse(¶m, key, str); + /* Let x264 sanity check the options for us */ - if( ret == X264_PARAM_BAD_NAME ) - hb_log( "x264 options: Unknown suboption %s", entry->key ); - if( ret == X264_PARAM_BAD_VALUE ) - hb_log( "x264 options: Bad argument %s=%s", entry->key, entry->value ? entry->value : "(null)" ); + if (ret == X264_PARAM_BAD_NAME) + hb_log( "x264 options: Unknown suboption %s", key ); + if (ret == X264_PARAM_BAD_VALUE) + hb_log( "x264 options: Bad argument %s=%s", key, + str ? str : "(null)" ); + free(str); } - hb_dict_free( &x264_opts ); + hb_dict_free(&x264_opts); /* Reload colorimetry settings in case custom values were set * in the encoder_options string */ @@ -1046,15 +1055,21 @@ int hb_apply_h264_level(x264_param_t *param, const char *h264_level, return ret; } +static hb_value_t * value_pair(hb_value_t * v1, hb_value_t * v2) +{ + hb_value_t *array = hb_value_array_init(); + hb_value_array_append(array, v1); + hb_value_array_append(array, v2); + return array; +} + char * hb_x264_param_unparse(const char *x264_preset, const char *x264_tune, const char *x264_encopts, const char *h264_profile, const char *h264_level, int width, int height) { int i; - char buf[32]; char *unparsed_opts; hb_dict_t *x264_opts; - hb_dict_entry_t *entry; x264_param_t defaults, param; /* @@ -1077,7 +1092,6 @@ char * hb_x264_param_unparse(const char *x264_preset, const char *x264_tune, /* * place additional x264 options in a dictionary */ - entry = NULL; x264_opts = hb_encopts_to_dict(x264_encopts, HB_VCODEC_X264); /* @@ -1087,22 +1101,30 @@ char * hb_x264_param_unparse(const char *x264_preset, const char *x264_tune, * * clear them from x264_opts so as to not apply then during unparse. */ - hb_dict_unset(&x264_opts, "qp"); - hb_dict_unset(&x264_opts, "qp_constant"); - hb_dict_unset(&x264_opts, "crf"); - hb_dict_unset(&x264_opts, "bitrate"); - hb_dict_unset(&x264_opts, "fps"); - hb_dict_unset(&x264_opts, "force-cfr"); - hb_dict_unset(&x264_opts, "sar"); - hb_dict_unset(&x264_opts, "annexb"); + hb_dict_remove(x264_opts, "qp"); + hb_dict_remove(x264_opts, "qp_constant"); + hb_dict_remove(x264_opts, "crf"); + hb_dict_remove(x264_opts, "bitrate"); + hb_dict_remove(x264_opts, "fps"); + hb_dict_remove(x264_opts, "force-cfr"); + hb_dict_remove(x264_opts, "sar"); + hb_dict_remove(x264_opts, "annexb"); /* * apply the additional x264 options */ - while ((entry = hb_dict_next(x264_opts, entry)) != NULL) + hb_dict_iter_t iter; + for (iter = hb_dict_iter_init(x264_opts); + iter != HB_DICT_ITER_DONE; + iter = hb_dict_iter_next(x264_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); + // let's not pollute GUI logs with x264_param_parse return codes - x264_param_parse(¶m, entry->key, entry->value); + x264_param_parse(¶m, key, str); + free(str); } /* @@ -1146,19 +1168,19 @@ char * hb_x264_param_unparse(const char *x264_preset, const char *x264_tune, * also, don't bother with forms that aren't allowed by the x264 CLI, such * as "no-bframes" - there are too many. */ - hb_dict_unset(&x264_opts, "no-sliced-threads"); - hb_dict_unset(&x264_opts, "no-scenecut"); - hb_dict_unset(&x264_opts, "no-b-adapt"); - hb_dict_unset(&x264_opts, "no-weightb"); - hb_dict_unset(&x264_opts, "no-cabac"); - hb_dict_unset(&x264_opts, "interlaced"); // we unparse to tff/bff - hb_dict_unset(&x264_opts, "no-interlaced"); - hb_dict_unset(&x264_opts, "no-8x8dct"); - hb_dict_unset(&x264_opts, "no-mixed-refs"); - hb_dict_unset(&x264_opts, "no-fast-pskip"); - hb_dict_unset(&x264_opts, "no-dct-decimate"); - hb_dict_unset(&x264_opts, "no-psy"); - hb_dict_unset(&x264_opts, "no-mbtree"); + hb_dict_remove(x264_opts, "no-sliced-threads"); + hb_dict_remove(x264_opts, "no-scenecut"); + hb_dict_remove(x264_opts, "no-b-adapt"); + hb_dict_remove(x264_opts, "no-weightb"); + hb_dict_remove(x264_opts, "no-cabac"); + hb_dict_remove(x264_opts, "interlaced"); // we unparse to tff/bff + hb_dict_remove(x264_opts, "no-interlaced"); + hb_dict_remove(x264_opts, "no-8x8dct"); + hb_dict_remove(x264_opts, "no-mixed-refs"); + hb_dict_remove(x264_opts, "no-fast-pskip"); + hb_dict_remove(x264_opts, "no-dct-decimate"); + hb_dict_remove(x264_opts, "no-psy"); + hb_dict_remove(x264_opts, "no-mbtree"); /* * compare defaults to param and unparse to the x264_opts dictionary @@ -1166,75 +1188,74 @@ char * hb_x264_param_unparse(const char *x264_preset, const char *x264_tune, if (!param.b_sliced_threads != !defaults.b_sliced_threads) { // can be modified by: tune zerolatency - sprintf(buf, "%d", !!param.b_sliced_threads); - hb_dict_set(&x264_opts, "sliced-threads", buf); + hb_dict_set(x264_opts, "sliced-threads", + hb_value_bool(!!param.b_sliced_threads)); } else { - hb_dict_unset(&x264_opts, "sliced-threads"); + hb_dict_remove(x264_opts, "sliced-threads"); } if (param.i_sync_lookahead != defaults.i_sync_lookahead) { // can be modified by: tune zerolatency - sprintf(buf, "%d", param.i_sync_lookahead); - hb_dict_set(&x264_opts, "sync-lookahead", buf); + hb_dict_set(x264_opts, "sync-lookahead", + hb_value_int(param.i_sync_lookahead)); } else { - hb_dict_unset(&x264_opts, "sync-lookahead"); + hb_dict_remove(x264_opts, "sync-lookahead"); } if (param.i_level_idc != defaults.i_level_idc) { // can be modified by: level for (i = 0; hb_h264_level_values[i]; i++) if (param.i_level_idc == hb_h264_level_values[i]) - hb_dict_set(&x264_opts, "level", hb_h264_level_names[i]); + hb_dict_set(x264_opts, "level", + hb_value_string(hb_h264_level_names[i])); } else { - hb_dict_unset(&x264_opts, "level"); + hb_dict_remove(x264_opts, "level"); } if (param.i_frame_reference != defaults.i_frame_reference) { // can be modified by: presets, tunes, level - sprintf(buf, "%d", param.i_frame_reference); - hb_dict_set(&x264_opts, "ref", buf); + hb_dict_set(x264_opts, "ref", hb_value_int(param.i_frame_reference)); } else { - hb_dict_unset(&x264_opts, "ref"); + hb_dict_remove(x264_opts, "ref"); } if (param.i_scenecut_threshold != defaults.i_scenecut_threshold) { // can be modified by: preset ultrafast - sprintf(buf, "%d", param.i_scenecut_threshold); - hb_dict_set(&x264_opts, "scenecut", buf); + hb_dict_set(x264_opts, "scenecut", + hb_value_int(param.i_scenecut_threshold)); } else { - hb_dict_unset(&x264_opts, "scenecut"); + hb_dict_remove(x264_opts, "scenecut"); } if (param.i_bframe != defaults.i_bframe) { // can be modified by: presets, tunes, profile, level - sprintf(buf, "%d", param.i_bframe); - hb_dict_set(&x264_opts, "bframes", buf); + hb_dict_set(x264_opts, "bframes", hb_value_int(param.i_bframe)); } else { - hb_dict_unset(&x264_opts, "bframes"); + hb_dict_remove(x264_opts, "bframes"); } if (param.i_bframe > 0) { if (param.i_bframe_adaptive != defaults.i_bframe_adaptive) { // can be modified by: presets - sprintf(buf, "%d", param.i_bframe_adaptive); - hb_dict_set(&x264_opts, "b-adapt", buf); + hb_dict_set(x264_opts, "b-adapt", + hb_value_int(param.i_bframe_adaptive)); } else { - hb_dict_unset(&x264_opts, "b-adapt"); + hb_dict_remove(x264_opts, "b-adapt"); } if (param.i_bframe > 1 && param.i_bframe_pyramid != defaults.i_bframe_pyramid) @@ -1246,12 +1267,12 @@ char * hb_x264_param_unparse(const char *x264_preset, const char *x264_tune, param.i_bframe_pyramid = X264_B_PYRAMID_NORMAL; for (i = 0; x264_b_pyramid_names[i] != NULL; i++) if (param.i_bframe_pyramid == i) - hb_dict_set(&x264_opts, "b-pyramid", - x264_b_pyramid_names[i]); + hb_dict_set(x264_opts, "b-pyramid", + hb_value_string(x264_b_pyramid_names[i])); } else { - hb_dict_unset(&x264_opts, "b-pyramid"); + hb_dict_remove(x264_opts, "b-pyramid"); } if (param.analyse.i_direct_mv_pred != defaults.analyse.i_direct_mv_pred) { @@ -1262,109 +1283,108 @@ char * hb_x264_param_unparse(const char *x264_preset, const char *x264_tune, param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_AUTO; for (i = 0; x264_direct_pred_names[i] != NULL; i++) if (param.analyse.i_direct_mv_pred == i) - hb_dict_set(&x264_opts, "direct", - x264_direct_pred_names[i]); + hb_dict_set(x264_opts, "direct", + hb_value_string(x264_direct_pred_names[i])); } else { - hb_dict_unset(&x264_opts, "direct"); + hb_dict_remove(x264_opts, "direct"); } if (!param.analyse.b_weighted_bipred != !defaults.analyse.b_weighted_bipred) { // can be modified by: preset ultrafast, tune fastdecode - sprintf(buf, "%d", !!param.analyse.b_weighted_bipred); - hb_dict_set(&x264_opts, "weightb", buf); + hb_dict_set(x264_opts, "weightb", + hb_value_bool(!!param.analyse.b_weighted_bipred)); } else { - hb_dict_unset(&x264_opts, "weightb"); + hb_dict_remove(x264_opts, "weightb"); } } else { // no bframes, these options have no effect - hb_dict_unset(&x264_opts, "b-adapt"); - hb_dict_unset(&x264_opts, "b-pyramid"); - hb_dict_unset(&x264_opts, "direct"); - hb_dict_unset(&x264_opts, "weightb"); - hb_dict_unset(&x264_opts, "b-bias"); - hb_dict_unset(&x264_opts, "open-gop"); + hb_dict_remove(x264_opts, "b-adapt"); + hb_dict_remove(x264_opts, "b-pyramid"); + hb_dict_remove(x264_opts, "direct"); + hb_dict_remove(x264_opts, "weightb"); + hb_dict_remove(x264_opts, "b-bias"); + hb_dict_remove(x264_opts, "open-gop"); } if (!param.b_deblocking_filter != !defaults.b_deblocking_filter) { // can be modified by: preset ultrafast, tune fastdecode - sprintf(buf, "%d", !param.b_deblocking_filter); - hb_dict_set(&x264_opts, "no-deblock", buf); + hb_dict_set(x264_opts, "no-deblock", + hb_value_bool(!param.b_deblocking_filter)); } else { - hb_dict_unset(&x264_opts, "no-deblock"); + hb_dict_remove(x264_opts, "no-deblock"); } if (param.b_deblocking_filter && (param.i_deblocking_filter_alphac0 != defaults.i_deblocking_filter_alphac0 || param.i_deblocking_filter_beta != defaults.i_deblocking_filter_beta)) { // can be modified by: tunes - sprintf(buf, "%d,%d", param.i_deblocking_filter_alphac0, - param.i_deblocking_filter_beta); - hb_dict_set(&x264_opts, "deblock", buf); + hb_dict_set(x264_opts, "deblock", + value_pair(hb_value_int(param.i_deblocking_filter_alphac0), + hb_value_int(param.i_deblocking_filter_beta))); } else { - hb_dict_unset(&x264_opts, "deblock"); + hb_dict_remove(x264_opts, "deblock"); } if (!param.b_cabac != !defaults.b_cabac) { // can be modified by: preset ultrafast, tune fastdecode, profile - sprintf(buf, "%d", !!param.b_cabac); - hb_dict_set(&x264_opts, "cabac", buf); + hb_dict_set(x264_opts, "cabac", hb_value_bool(!!param.b_cabac)); } else { - hb_dict_unset(&x264_opts, "cabac"); + hb_dict_remove(x264_opts, "cabac"); } if (param.b_interlaced != defaults.b_interlaced) { if (param.b_tff) { - hb_dict_set(&x264_opts, "tff", "1"); - hb_dict_unset(&x264_opts, "bff"); + hb_dict_set(x264_opts, "tff", hb_value_bool(1)); + hb_dict_remove(x264_opts, "bff"); } else { - hb_dict_set(&x264_opts, "bff", "1"); - hb_dict_unset(&x264_opts, "tff"); + hb_dict_set(x264_opts, "bff", hb_value_bool(1)); + hb_dict_remove(x264_opts, "tff"); } - hb_dict_unset(&x264_opts, "fake-interlaced"); + hb_dict_remove(x264_opts, "fake-interlaced"); } else if (param.b_fake_interlaced != defaults.b_fake_interlaced) { - hb_dict_set(&x264_opts, "fake-interlaced", "1"); - hb_dict_unset(&x264_opts, "tff"); - hb_dict_unset(&x264_opts, "bff"); + hb_dict_set(x264_opts, "fake-interlaced", hb_value_bool(1)); + hb_dict_remove(x264_opts, "tff"); + hb_dict_remove(x264_opts, "bff"); } else { - hb_dict_unset(&x264_opts, "tff"); - hb_dict_unset(&x264_opts, "bff"); - hb_dict_unset(&x264_opts, "fake-interlaced"); + hb_dict_remove(x264_opts, "tff"); + hb_dict_remove(x264_opts, "bff"); + hb_dict_remove(x264_opts, "fake-interlaced"); } if (param.i_cqm_preset == defaults.i_cqm_preset && param.psz_cqm_file == defaults.psz_cqm_file) { // can be reset to default by: profile - hb_dict_unset(&x264_opts, "cqm"); - hb_dict_unset(&x264_opts, "cqm4"); - hb_dict_unset(&x264_opts, "cqm8"); - hb_dict_unset(&x264_opts, "cqm4i"); - hb_dict_unset(&x264_opts, "cqm4p"); - hb_dict_unset(&x264_opts, "cqm8i"); - hb_dict_unset(&x264_opts, "cqm8p"); - hb_dict_unset(&x264_opts, "cqm4iy"); - hb_dict_unset(&x264_opts, "cqm4ic"); - hb_dict_unset(&x264_opts, "cqm4py"); - hb_dict_unset(&x264_opts, "cqm4pc"); + hb_dict_remove(x264_opts, "cqm"); + hb_dict_remove(x264_opts, "cqm4"); + hb_dict_remove(x264_opts, "cqm8"); + hb_dict_remove(x264_opts, "cqm4i"); + hb_dict_remove(x264_opts, "cqm4p"); + hb_dict_remove(x264_opts, "cqm8i"); + hb_dict_remove(x264_opts, "cqm8p"); + hb_dict_remove(x264_opts, "cqm4iy"); + hb_dict_remove(x264_opts, "cqm4ic"); + hb_dict_remove(x264_opts, "cqm4py"); + hb_dict_remove(x264_opts, "cqm4pc"); } /* * Note: param.analyse.intra can only be modified directly or by using @@ -1375,7 +1395,7 @@ char * hb_x264_param_unparse(const char *x264_preset, const char *x264_tune, // can be modified by: presets, tune touhou if (!param.analyse.inter) { - hb_dict_set(&x264_opts, "analyse", "none"); + hb_dict_set(x264_opts, "analyse", hb_value_string("none")); } else if ((param.analyse.inter & X264_ANALYSE_I4x4) && (param.analyse.inter & X264_ANALYSE_I8x8) && @@ -1383,65 +1403,57 @@ char * hb_x264_param_unparse(const char *x264_preset, const char *x264_tune, (param.analyse.inter & X264_ANALYSE_PSUB8x8) && (param.analyse.inter & X264_ANALYSE_BSUB16x16)) { - hb_dict_set(&x264_opts, "analyse", "all"); + hb_dict_set(x264_opts, "analyse", hb_value_string("all")); } else { - sprintf(buf, "%s", ""); + hb_value_t *array = hb_value_array_init(); if (param.analyse.inter & X264_ANALYSE_I4x4) { - strcat(buf, "i4x4"); + hb_value_array_append(array, hb_value_string("i4x4")); } if (param.analyse.inter & X264_ANALYSE_I8x8) { - if (*buf) - strcat(buf, ","); - strcat(buf, "i8x8"); + hb_value_array_append(array, hb_value_string("i8x8")); } if (param.analyse.inter & X264_ANALYSE_PSUB16x16) { - if (*buf) - strcat(buf, ","); - strcat(buf, "p8x8"); + hb_value_array_append(array, hb_value_string("p8x8")); } if (param.analyse.inter & X264_ANALYSE_PSUB8x8) { - if (*buf) - strcat(buf, ","); - strcat(buf, "p4x4"); + hb_value_array_append(array, hb_value_string("p4x4")); } if (param.analyse.inter & X264_ANALYSE_BSUB16x16) { - if (*buf) - strcat(buf, ","); - strcat(buf, "b8x8"); + hb_value_array_append(array, hb_value_string("b8x8")); } - hb_dict_set(&x264_opts, "analyse", buf); + hb_dict_set(x264_opts, "analyse", array); } } else { - hb_dict_unset(&x264_opts, "analyse"); + hb_dict_remove(x264_opts, "analyse"); } if (!param.analyse.b_transform_8x8 != !defaults.analyse.b_transform_8x8) { // can be modified by: preset ultrafast, profile - sprintf(buf, "%d", !!param.analyse.b_transform_8x8); - hb_dict_set(&x264_opts, "8x8dct", buf); + hb_dict_set(x264_opts, "8x8dct", + hb_value_bool(!!param.analyse.b_transform_8x8)); } else { - hb_dict_unset(&x264_opts, "8x8dct"); + hb_dict_remove(x264_opts, "8x8dct"); } if (param.analyse.i_weighted_pred != defaults.analyse.i_weighted_pred) { // can be modified by: presets, tune fastdecode, profile - sprintf(buf, "%d", param.analyse.i_weighted_pred); - hb_dict_set(&x264_opts, "weightp", buf); + hb_dict_set(x264_opts, "weightp", + hb_value_int(param.analyse.i_weighted_pred)); } else { - hb_dict_unset(&x264_opts, "weightp"); + hb_dict_remove(x264_opts, "weightp"); } if (param.analyse.i_me_method != defaults.analyse.i_me_method) { @@ -1452,31 +1464,32 @@ char * hb_x264_param_unparse(const char *x264_preset, const char *x264_tune, param.analyse.i_me_method = X264_ME_TESA; for (i = 0; x264_motion_est_names[i] != NULL; i++) if (param.analyse.i_me_method == i) - hb_dict_set(&x264_opts, "me", x264_motion_est_names[i]); + hb_dict_set(x264_opts, "me", + hb_value_string(x264_motion_est_names[i])); } else { - hb_dict_unset(&x264_opts, "me"); + hb_dict_remove(x264_opts, "me"); } if (param.analyse.i_me_range != defaults.analyse.i_me_range) { // can be modified by: presets - sprintf(buf, "%d", param.analyse.i_me_range); - hb_dict_set(&x264_opts, "merange", buf); + hb_dict_set(x264_opts, "merange", + hb_value_int(param.analyse.i_me_range)); } else { - hb_dict_unset(&x264_opts, "merange"); + hb_dict_remove(x264_opts, "merange"); } if (param.analyse.i_mv_range != defaults.analyse.i_mv_range) { // can be modified by: level - sprintf(buf, "%d", param.analyse.i_mv_range); - hb_dict_set(&x264_opts, "mvrange", buf); + hb_dict_set(x264_opts, "mvrange", + hb_value_int(param.analyse.i_mv_range)); } else { - hb_dict_unset(&x264_opts, "mvrange"); + hb_dict_remove(x264_opts, "mvrange"); } if (param.analyse.i_subpel_refine > 9 && (param.rc.i_aq_mode == 0 || param.analyse.i_trellis < 2)) @@ -1487,76 +1500,75 @@ char * hb_x264_param_unparse(const char *x264_preset, const char *x264_tune, if (param.analyse.i_subpel_refine != defaults.analyse.i_subpel_refine) { // can be modified by: presets - sprintf(buf, "%d", param.analyse.i_subpel_refine); - hb_dict_set(&x264_opts, "subme", buf); + hb_dict_set(x264_opts, "subme", + hb_value_int(param.analyse.i_subpel_refine)); } else { - hb_dict_unset(&x264_opts, "subme"); + hb_dict_remove(x264_opts, "subme"); } if (!param.analyse.b_mixed_references != !defaults.analyse.b_mixed_references) { // can be modified by: presets - sprintf(buf, "%d", !!param.analyse.b_mixed_references); - hb_dict_set(&x264_opts, "mixed-refs", buf); + hb_dict_set(x264_opts, "mixed-refs", + hb_value_bool(!!param.analyse.b_mixed_references)); } else { - hb_dict_unset(&x264_opts, "mixed-refs"); + hb_dict_remove(x264_opts, "mixed-refs"); } if (param.analyse.i_trellis != defaults.analyse.i_trellis) { // can be modified by: presets - sprintf(buf, "%d", param.analyse.i_trellis); - hb_dict_set(&x264_opts, "trellis", buf); + hb_dict_set(x264_opts, "trellis", + hb_value_int(param.analyse.i_trellis)); } else { - hb_dict_unset(&x264_opts, "trellis"); + hb_dict_remove(x264_opts, "trellis"); } if (!param.analyse.b_fast_pskip != !defaults.analyse.b_fast_pskip) { // can be modified by: preset placebo - sprintf(buf, "%d", !!param.analyse.b_fast_pskip); - hb_dict_set(&x264_opts, "fast-pskip", buf); + hb_dict_set(x264_opts, "fast-pskip", + hb_value_bool(!!param.analyse.b_fast_pskip)); } else { - hb_dict_unset(&x264_opts, "fast-pskip"); + hb_dict_remove(x264_opts, "fast-pskip"); } if (!param.analyse.b_dct_decimate != !defaults.analyse.b_dct_decimate) { // can be modified by: tune grain - sprintf(buf, "%d", !!param.analyse.b_dct_decimate); - hb_dict_set(&x264_opts, "dct-decimate", buf); + hb_dict_set(x264_opts, "dct-decimate", + hb_value_bool(!!param.analyse.b_dct_decimate)); } else { - hb_dict_unset(&x264_opts, "dct-decimate"); + hb_dict_remove(x264_opts, "dct-decimate"); } if (!param.analyse.b_psy != !defaults.analyse.b_psy) { // can be modified by: tunes - sprintf(buf, "%d", !!param.analyse.b_psy); - hb_dict_set(&x264_opts, "psy", buf); + hb_dict_set(x264_opts, "psy", hb_value_bool(!!param.analyse.b_psy)); } else { - hb_dict_unset(&x264_opts, "psy"); + hb_dict_remove(x264_opts, "psy"); } if (param.analyse.b_psy && (param.analyse.f_psy_rd != defaults.analyse.f_psy_rd || param.analyse.f_psy_trellis != defaults.analyse.f_psy_trellis)) { // can be modified by: tunes - sprintf(buf, "%.2f,%.2f", param.analyse.f_psy_rd, - param.analyse.f_psy_trellis); - hb_dict_set(&x264_opts, "psy-rd", buf); + hb_dict_set(x264_opts, "psy-rd", + value_pair(hb_value_double(param.analyse.f_psy_rd), + hb_value_double(param.analyse.f_psy_trellis))); } else { - hb_dict_unset(&x264_opts, "psy-rd"); + hb_dict_remove(x264_opts, "psy-rd"); } /* * Note: while deadzone is incompatible with trellis, it still has a slight @@ -1565,126 +1577,122 @@ char * hb_x264_param_unparse(const char *x264_preset, const char *x264_tune, if (param.analyse.i_luma_deadzone[0] != defaults.analyse.i_luma_deadzone[0]) { // can be modified by: tune grain - sprintf(buf, "%d", param.analyse.i_luma_deadzone[0]); - hb_dict_set(&x264_opts, "deadzone-inter", buf); + hb_dict_set(x264_opts, "deadzone-inter", + hb_value_int(param.analyse.i_luma_deadzone[0])); } else { - hb_dict_unset(&x264_opts, "deadzone-inter"); + hb_dict_remove(x264_opts, "deadzone-inter"); } if (param.analyse.i_luma_deadzone[1] != defaults.analyse.i_luma_deadzone[1]) { // can be modified by: tune grain - sprintf(buf, "%d", param.analyse.i_luma_deadzone[1]); - hb_dict_set(&x264_opts, "deadzone-intra", buf); + hb_dict_set(x264_opts, "deadzone-intra", + hb_value_int(param.analyse.i_luma_deadzone[1])); } else { - hb_dict_unset(&x264_opts, "deadzone-intra"); + hb_dict_remove(x264_opts, "deadzone-intra"); } if (param.rc.i_vbv_buffer_size != defaults.rc.i_vbv_buffer_size) { // can be modified by: level - sprintf(buf, "%d", param.rc.i_vbv_buffer_size); - hb_dict_set(&x264_opts, "vbv-bufsize", buf); + hb_dict_set(x264_opts, "vbv-bufsize", + hb_value_int(param.rc.i_vbv_buffer_size)); if (param.rc.i_vbv_max_bitrate != defaults.rc.i_vbv_max_bitrate) { // can be modified by: level - sprintf(buf, "%d", param.rc.i_vbv_max_bitrate); - hb_dict_set(&x264_opts, "vbv-maxrate", buf); + hb_dict_set(x264_opts, "vbv-maxrate", + hb_value_int(param.rc.i_vbv_max_bitrate)); } else { - hb_dict_unset(&x264_opts, "vbv-maxrate"); + hb_dict_remove(x264_opts, "vbv-maxrate"); } } else { - hb_dict_unset(&x264_opts, "vbv-bufsize"); - hb_dict_unset(&x264_opts, "vbv-maxrate"); + hb_dict_remove(x264_opts, "vbv-bufsize"); + hb_dict_remove(x264_opts, "vbv-maxrate"); } if (param.rc.f_ip_factor != defaults.rc.f_ip_factor) { // can be modified by: tune grain - sprintf(buf, "%.2f", param.rc.f_ip_factor); - hb_dict_set(&x264_opts, "ipratio", buf); + hb_dict_set(x264_opts, "ipratio", + hb_value_double(param.rc.f_ip_factor)); } else { - hb_dict_unset(&x264_opts, "ipratio"); + hb_dict_remove(x264_opts, "ipratio"); } if (param.i_bframe > 0 && !param.rc.b_mb_tree && param.rc.f_pb_factor != defaults.rc.f_pb_factor) { // can be modified by: tune grain - sprintf(buf, "%.2f", param.rc.f_pb_factor); - hb_dict_set(&x264_opts, "pbratio", buf); + hb_dict_set(x264_opts, "pbratio", + hb_value_double(param.rc.f_pb_factor)); } else { // pbratio requires bframes and is incomaptible with mbtree - hb_dict_unset(&x264_opts, "pbratio"); + hb_dict_remove(x264_opts, "pbratio"); } if (param.rc.f_qcompress != defaults.rc.f_qcompress) { // can be modified by: tune grain - sprintf(buf, "%.2f", param.rc.f_qcompress); - hb_dict_set(&x264_opts, "qcomp", buf); + hb_dict_set(x264_opts, "qcomp", hb_value_double(param.rc.f_qcompress)); } else { - hb_dict_unset(&x264_opts, "qcomp"); + hb_dict_remove(x264_opts, "qcomp"); } if (param.rc.i_aq_mode != defaults.rc.i_aq_mode) { // can be modified by: preset ultrafast, tune psnr - sprintf(buf, "%d", param.rc.i_aq_mode); - hb_dict_set(&x264_opts, "aq-mode", buf); + hb_dict_set(x264_opts, "aq-mode", hb_value_int(param.rc.i_aq_mode)); } else { - hb_dict_unset(&x264_opts, "aq-mode"); + hb_dict_remove(x264_opts, "aq-mode"); } if (param.rc.i_aq_mode > 0 && param.rc.f_aq_strength != defaults.rc.f_aq_strength) { // can be modified by: tunes - sprintf(buf, "%.2f", param.rc.f_aq_strength); - hb_dict_set(&x264_opts, "aq-strength", buf); + hb_dict_set(x264_opts, "aq-strength", + hb_value_double(param.rc.f_aq_strength)); } else { - hb_dict_unset(&x264_opts, "aq-strength"); + hb_dict_remove(x264_opts, "aq-strength"); } if (!param.rc.b_mb_tree != !defaults.rc.b_mb_tree) { // can be modified by: presets, tune zerolatency - sprintf(buf, "%d", !!param.rc.b_mb_tree); - hb_dict_set(&x264_opts, "mbtree", buf); + hb_dict_set(x264_opts, "mbtree", hb_value_bool(!!param.rc.b_mb_tree)); } else { - hb_dict_unset(&x264_opts, "mbtree"); + hb_dict_remove(x264_opts, "mbtree"); } if (param.rc.i_lookahead != defaults.rc.i_lookahead) { // can be modified by: presets, tune zerolatency - sprintf(buf, "%d", param.rc.i_lookahead); - hb_dict_set(&x264_opts, "rc-lookahead", buf); + hb_dict_set(x264_opts, "rc-lookahead", + hb_value_int(param.rc.i_lookahead)); } else { - hb_dict_unset(&x264_opts, "rc-lookahead"); + hb_dict_remove(x264_opts, "rc-lookahead"); } if (!param.b_vfr_input != !defaults.b_vfr_input) { // can be modified by: tune zerolatency - sprintf(buf, "%d", !param.b_vfr_input); - hb_dict_set(&x264_opts, "force-cfr", buf); + hb_dict_set(x264_opts, "force-cfr", hb_value_bool(!param.b_vfr_input)); } else { - hb_dict_unset(&x264_opts, "force-cfr"); + hb_dict_remove(x264_opts, "force-cfr"); } /* convert the x264_opts dictionary to an encopts string */ diff --git a/libhb/encx265.c b/libhb/encx265.c index 324c07e5b..8743b8d20 100644 --- a/libhb/encx265.c +++ b/libhb/encx265.c @@ -184,16 +184,26 @@ int encx265Init(hb_work_object_t *w, hb_job_t *job) } /* 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) + 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 - if (param_parse(param, entry->key, entry->value)) + if (param_parse(param, key, str)) { + free(str); hb_dict_free(&x265_opts); goto fail; } + free(str); } hb_dict_free(&x265_opts); diff --git a/libhb/hb_dict.c b/libhb/hb_dict.c index 48d5c6a01..d8bbc8713 100644 --- a/libhb/hb_dict.c +++ b/libhb/hb_dict.c @@ -10,219 +10,561 @@ #include "hb.h" #include "hb_dict.h" -hb_dict_t * hb_dict_init( int alloc ) +hb_value_type_t hb_value_type(const hb_value_t *value) { - hb_dict_t * dict = NULL; - dict = malloc( sizeof( hb_dict_t ) ); - if( !dict ) + if (value == NULL) + return HB_VALUE_TYPE_NULL; + hb_value_type_t type = json_typeof(value); + if (type == JSON_TRUE || type == JSON_FALSE) + return HB_VALUE_TYPE_BOOL; + return type; +} + +hb_value_t * hb_value_dup(hb_value_t *value) +{ + if (value == NULL) return NULL; + return json_deep_copy(value); +} + +void hb_value_incref(hb_value_t *value) +{ + if (value == NULL) return; + json_incref(value); +} + +void hb_value_decref(hb_value_t *value) +{ + if (value == NULL) return; + json_decref(value); +} + +void hb_value_free(hb_value_t **_value) +{ + hb_value_decref(*_value); + *_value = NULL; +} + +hb_value_t * hb_value_string(const char * value) +{ + // json_string does not create a value for NULL strings. + // So create JSON_NULL in this case + if (value == NULL) + return json_null(); + return json_string(value); +} + +hb_value_t * hb_value_int(json_int_t value) +{ + return json_integer(value); +} + +hb_value_t * hb_value_double(double value) +{ + return json_real(value); +} + +hb_value_t * hb_value_bool(int value) +{ + return json_boolean(value); +} + +static hb_value_t* xform_null(hb_value_type_t type) +{ + switch (type) { - hb_log( "ERROR: could not allocate hb_dict_t" ); - return NULL; + default: + case HB_VALUE_TYPE_NULL: + return json_null(); + case HB_VALUE_TYPE_BOOL: + return json_false(); + case HB_VALUE_TYPE_INT: + return json_integer(0); + case HB_VALUE_TYPE_DOUBLE: + return json_real(0.0); + case HB_VALUE_TYPE_STRING: + return json_null(); } - dict->count = 0; - dict->objects = malloc( alloc * sizeof( hb_dict_entry_t ) ); - if( !dict->objects ) +} + +static hb_value_t* xform_bool(const hb_value_t *value, hb_value_type_t type) +{ + json_int_t b = json_is_true(value); + switch (type) { - hb_log( "ERROR: could not allocate hb_dict_t objects" ); - dict->alloc = 0; + default: + case HB_VALUE_TYPE_NULL: + return json_null(); + case HB_VALUE_TYPE_BOOL: + return json_boolean(b); + case HB_VALUE_TYPE_INT: + return json_integer(b); + case HB_VALUE_TYPE_DOUBLE: + return json_real(b); + case HB_VALUE_TYPE_STRING: + { + char *s = hb_strdup_printf("%"JSON_INTEGER_FORMAT, b); + hb_value_t *v = json_string(s); + free(s); + return v; + } } - else +} + +static hb_value_t* xform_int(const hb_value_t *value, hb_value_type_t type) +{ + json_int_t i = json_integer_value(value); + switch (type) { - dict->alloc = alloc; + default: + case HB_VALUE_TYPE_NULL: + return json_null(); + case HB_VALUE_TYPE_BOOL: + return json_boolean(i); + case HB_VALUE_TYPE_INT: + return json_integer(i); + case HB_VALUE_TYPE_DOUBLE: + return json_real(i); + case HB_VALUE_TYPE_STRING: + { + char *s = hb_strdup_printf("%"JSON_INTEGER_FORMAT, i); + hb_value_t *v = json_string(s); + free(s); + return v; + } } - return dict; } -void hb_dict_free( hb_dict_t ** dict_ptr ) +static hb_value_t* xform_double(const hb_value_t *value, hb_value_type_t type) { - hb_dict_t * dict = *dict_ptr; - if( dict ) + double d = json_real_value(value); + switch (type) { - if( dict->objects ) + default: + case HB_VALUE_TYPE_NULL: + return json_null(); + case HB_VALUE_TYPE_BOOL: + return json_boolean((int)d != 0); + case HB_VALUE_TYPE_INT: + return json_integer(d); + case HB_VALUE_TYPE_DOUBLE: + return json_real(d); + case HB_VALUE_TYPE_STRING: { - int i; - for( i = 0; i < dict->count; i++ ) - { - if( dict->objects[i].key ) - { - free( dict->objects[i].key ); - } - if( dict->objects[i].value ) - { - free( dict->objects[i].value ); - } - } - free( dict->objects ); + char *s = hb_strdup_printf("%g", d); + hb_value_t *v = json_string(s); + free(s); + return v; } - free( *dict_ptr ); - *dict_ptr = NULL; } } -void hb_dict_set( hb_dict_t ** dict_ptr, const char * key, const char * value ) +static hb_value_t* xform_string(const hb_value_t *value, hb_value_type_t type) { - hb_dict_t * dict = *dict_ptr; - if( !dict ) + const char *s = json_string_value(value); + switch (type) { - hb_log( "hb_dict_set: NULL dictionary" ); - return; + default: + case HB_VALUE_TYPE_NULL: + { + return json_null(); + } + case HB_VALUE_TYPE_BOOL: + { + if (s != NULL && + (!strcasecmp(s, "true") || + !strcasecmp(s, "yes") || + !strcasecmp(s, "1"))) + { + return json_true(); + } + return json_false(); + } + case HB_VALUE_TYPE_INT: + { + json_int_t i = 0; + if (s != NULL) + strtoll(s, NULL, 0); + return json_integer(i); + } + case HB_VALUE_TYPE_DOUBLE: + { + double d = 0.0; + if (s != NULL) + d = strtod(s, NULL); + return json_real(d); + } + case HB_VALUE_TYPE_STRING: + { + return json_string(s); + } } - if( !key || !strlen( key ) ) - return; - hb_dict_entry_t * entry = hb_dict_get( dict, key ); - if( entry ) +} + +static hb_value_t* xform_array(const hb_value_t *value, hb_value_type_t type) +{ + hb_value_t *first = NULL; + int count = hb_value_array_len(value); + + if (count > 0) + first = hb_value_array_get(value, 0); + switch (type) { - if( entry->value ) + default: + case HB_VALUE_TYPE_NULL: + case HB_VALUE_TYPE_BOOL: + case HB_VALUE_TYPE_INT: + case HB_VALUE_TYPE_DOUBLE: + return hb_value_xform(first, type); + case HB_VALUE_TYPE_STRING: { - if( value && !strcmp( value, entry->value ) ) - return; + char *r = strdup(""); + int ii; + for (ii = 0; ii < count; ii++) + { + hb_value_t *v = hb_value_array_get(value, ii); + hb_value_t *x = hb_value_xform(v, type); + const char *s = hb_value_get_string(x); + if (s != NULL) + { + char *tmp = r; + r = hb_strdup_printf("%s%s,", tmp, s); + free(tmp); + } + hb_value_free(&x); + } + int len = strlen(r); + hb_value_t *v; + if (len > 0) + { + // Removing trailing ',' + r[len - 1] = 0; + v = json_string(r); + } else { - free( entry->value ); - entry->value = NULL; + free(r); + r = NULL; + v = json_null(); } + free(r); + return v; } - if( value && strlen( value ) ) - entry->value = strdup( value ); } - else +} + +static hb_value_t* xform_dict(const hb_value_t *dict, hb_value_type_t type) +{ + hb_value_t *first = NULL; + hb_dict_iter_t iter = hb_dict_iter_init(dict); + + if (iter != HB_DICT_ITER_DONE) + first = hb_dict_iter_value(iter); + + switch (type) { - if( dict->alloc <= dict->count ) + default: + case HB_VALUE_TYPE_NULL: + case HB_VALUE_TYPE_BOOL: + case HB_VALUE_TYPE_INT: + case HB_VALUE_TYPE_DOUBLE: + return hb_value_xform(first, type); + case HB_VALUE_TYPE_STRING: { - hb_dict_entry_t * tmp = NULL; - tmp = malloc( ( 2 * dict->alloc ) * sizeof( hb_dict_entry_t ) ); - if( !tmp ) + char *r = strdup(""); + hb_dict_iter_t iter; + for (iter = hb_dict_iter_init(dict); + iter != HB_DICT_ITER_DONE; + iter = hb_dict_iter_next(dict, iter)) + { + const char *k = hb_dict_iter_key(iter); + hb_value_t *v = hb_dict_iter_value(iter); + hb_value_t *x = hb_value_xform(v, type); + const char *s = hb_value_get_string(x); + + char *tmp = r; + r = hb_strdup_printf("%s%s%s%s:", + r, + k, + s ? "=" : "", + s ? s : ""); + free(tmp); + hb_value_free(&x); + } + int len = strlen(r); + hb_value_t *v; + if (len > 0) { - hb_log( "ERROR: could not realloc hb_dict_t objects" ); - return; + // Removing trailing ':' + r[len - 1] = 0; + v = json_string(r); } - if( dict->objects ) + else { - if( dict->count ) - memcpy( tmp, dict->objects, dict->count * sizeof( hb_dict_entry_t ) ); - free( dict->objects ); + free(r); + r = NULL; + v = json_null(); } - dict->objects = tmp; - dict->alloc *= 2; - } - dict->objects[dict->count].key = strdup( key ); - if( value && strlen( value ) ) - dict->objects[dict->count].value = strdup( value ); - else - dict->objects[dict->count].value = NULL; - dict->count++; + free(r); + return v; + } } } -void hb_dict_unset( hb_dict_t ** dict_ptr, const char * key ) +hb_value_t* hb_value_xform(const hb_value_t *value, hb_value_type_t type) { - hb_dict_t * dict = *dict_ptr; - if( !dict || !dict->objects || !key || !strlen( key ) ) - return; - int i; - for( i = 0; i < dict->count; i++ ) - if( !strcmp( key, dict->objects[i].key ) ) + hb_value_type_t src_type = hb_value_type(value); + if (src_type == type && value != NULL) + { + json_incref((hb_value_t*)value); + return (hb_value_t*)value; + } + switch (src_type) + { + default: + case HB_VALUE_TYPE_NULL: + { + return xform_null(type); + } + case HB_VALUE_TYPE_BOOL: + { + return xform_bool(value, type); + } + case HB_VALUE_TYPE_INT: { - free( dict->objects[i].key ); - if( dict->objects[i].value ) - free( dict->objects[i].value ); - if( i != --dict->count ) - memmove( &dict->objects[i], &dict->objects[i+1], - sizeof( hb_dict_entry_t ) * ( dict->count - i ) ); + return xform_int(value, type); } + case HB_VALUE_TYPE_DOUBLE: + { + return xform_double(value, type); + } + case HB_VALUE_TYPE_STRING: + { + return xform_string(value, type); + } + case HB_VALUE_TYPE_ARRAY: + { + return xform_array(value, type); + } + case HB_VALUE_TYPE_DICT: + { + return xform_dict(value, type); + } + } } -hb_dict_entry_t * hb_dict_get( hb_dict_t * dict, const char * key ) +const char * hb_value_get_string(const hb_value_t *value) { - if( !dict || !dict->objects || !key || !strlen( key ) ) - return NULL; - int i; - for( i = 0; i < dict->count; i++ ) - if( !strcmp( key, dict->objects[i].key ) ) - return &dict->objects[i]; - return NULL; + if (hb_value_type(value) != HB_VALUE_TYPE_STRING) return NULL; + return json_string_value(value); +} + +json_int_t hb_value_get_int(const hb_value_t *value) +{ + json_int_t result; + hb_value_t *v = hb_value_xform(value, HB_VALUE_TYPE_INT); + result = json_integer_value(v); + json_decref(v); + return result; +} + +double hb_value_get_double(const hb_value_t *value) +{ + double result; + hb_value_t *v = hb_value_xform(value, HB_VALUE_TYPE_DOUBLE); + result = json_real_value(v); + json_decref(v); + return result; } -hb_dict_entry_t * hb_dict_next( hb_dict_t * dict, hb_dict_entry_t * previous ) +int hb_value_get_bool(const hb_value_t *value) { - if( dict == NULL || dict->objects == NULL || !dict->count ) + int result; + hb_value_t *v = hb_value_xform(value, HB_VALUE_TYPE_BOOL); + result = json_is_true(v); + json_decref(v); + return result; +} + +char* +hb_value_get_string_xform(const hb_value_t *value) +{ + char *result; + if (hb_value_type(value) == HB_VALUE_TYPE_NULL) + return NULL; + hb_value_t *v = hb_value_xform(value, HB_VALUE_TYPE_STRING); + if (hb_value_type(v) == HB_VALUE_TYPE_NULL) return NULL; - if( previous == NULL ) - return &dict->objects[0]; - unsigned int prev_index = previous - dict->objects; - if( prev_index + 1 < dict->count ) - return &dict->objects[prev_index+1]; - return NULL; + result = strdup(json_string_value(v)); + json_decref(v); + return result; +} + +void hb_dict_free(hb_dict_t **_dict) +{ + hb_value_free(_dict); +} + +hb_dict_t * hb_dict_init() +{ + return json_object(); +} + +void hb_dict_set(hb_dict_t * dict, const char *key, hb_value_t *value) +{ + json_object_set_new(dict, key, value); +} + +int hb_dict_remove(hb_dict_t * dict, const char * key) +{ + return json_object_del(dict, key) == 0; +} + +hb_value_t * hb_dict_get(hb_dict_t * dict, const char * key) +{ + return json_object_get(dict, key); +} + +hb_dict_iter_t hb_dict_iter_init(const hb_dict_t *dict) +{ + if (dict == NULL) + return HB_DICT_ITER_DONE; + return json_object_iter((hb_dict_t*)dict); +} + +hb_dict_iter_t hb_dict_iter_next(const hb_dict_t *dict, hb_dict_iter_t iter) +{ + return json_object_iter_next((hb_dict_t*)dict, iter); +} + +const char * hb_dict_iter_key(const hb_dict_iter_t iter) +{ + return json_object_iter_key(iter); } -hb_dict_t * hb_encopts_to_dict( const char * encopts, int encoder ) +hb_value_t * hb_dict_iter_value(const hb_dict_iter_t iter) +{ + return json_object_iter_value(iter); +} + +hb_value_array_t* +hb_value_array_init() +{ + return json_array(); +} + +void +hb_value_array_clear(hb_value_array_t *array) +{ + json_array_clear(array); +} + +hb_value_t* +hb_value_array_get(const hb_value_array_t *array, int index) +{ + return json_array_get(array, index); +} + +void +hb_value_array_set(hb_value_array_t *array, int index, hb_value_t *value) +{ + if (index < 0 || index >= json_array_size(array)) + { + hb_error("hb_value_array_set: invalid index %d size %zu", + index, json_array_size(array)); + return; + } + json_array_set_new(array, index, value); +} + +void +hb_value_array_insert(hb_value_array_t *array, int index, hb_value_t *value) +{ + json_array_insert_new(array, index, value); +} + +void +hb_value_array_append(hb_value_array_t *array, hb_value_t *value) +{ + json_array_append_new(array, value); +} + +void +hb_value_array_remove(hb_value_array_t *array, int index) +{ + json_array_remove(array, index); +} + +void +hb_value_array_copy(hb_value_array_t *dst, + const hb_value_array_t *src, int count) +{ + size_t len; + int ii; + + // empty the first array if it is not already empty + json_array_clear(dst); + + len = hb_value_array_len(src); + count = MIN(count, len); + for (ii = 0; ii < count; ii++) + hb_value_array_append(dst, hb_value_dup(hb_value_array_get(src, ii))); +} + +size_t +hb_value_array_len(const hb_value_array_t *array) +{ + return json_array_size(array); +} + +hb_dict_t * hb_encopts_to_dict(const char * encopts, int encoder) { hb_dict_t * dict = NULL; - if( encopts && *encopts ) + + if (encopts && *encopts) { char *cur_opt, *opts_start, *value; const char *name; - dict = hb_dict_init( 10 ); + dict = hb_dict_init(); if( !dict ) return NULL; - cur_opt = opts_start = strdup( encopts ); - if( opts_start ) + cur_opt = opts_start = strdup(encopts); + if (opts_start) { - while( *cur_opt ) + while (*cur_opt) { name = cur_opt; - cur_opt += strcspn( cur_opt, ":" ); - if( *cur_opt ) + cur_opt += strcspn(cur_opt, ":"); + if (*cur_opt) { *cur_opt = 0; cur_opt++; } - value = strchr( name, '=' ); - if( value ) + value = strchr(name, '='); + if (value) { *value = 0; value++; } // x264 has multiple names for some options - if( encoder == HB_VCODEC_X264 ) - name = hb_x264_encopt_name( name ); + if (encoder == HB_VCODEC_X264) + name = hb_x264_encopt_name(name); #ifdef USE_X265 // x265 has multiple names for some options - if( encoder == HB_VCODEC_X265 ) - name = hb_x265_encopt_name( name ); + if (encoder == HB_VCODEC_X265) + name = hb_x265_encopt_name(name); #endif - hb_dict_set( &dict, name, value ); + if (name != NULL) + { + hb_dict_set(dict, name, hb_value_string(value)); + } } } - free( opts_start ); + free(opts_start); } return dict; } -char * hb_dict_to_encopts( hb_dict_t * dict ) +char * hb_dict_to_encopts(const 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; + return hb_value_get_string_xform(dict); } diff --git a/libhb/hb_dict.h b/libhb/hb_dict.h index daa3b39a9..7df1a56fa 100644 --- a/libhb/hb_dict.h +++ b/libhb/hb_dict.h @@ -9,46 +9,109 @@ #if !defined(HB_DICT_H) #define HB_DICT_H -typedef struct hb_dict_entry_s hb_dict_entry_t; -typedef struct hb_dict_s hb_dict_t; +#include -/* Basic dictionary implementation. +#define HB_VALUE_TYPE_DICT JSON_OBJECT +#define HB_VALUE_TYPE_ARRAY JSON_ARRAY +#define HB_VALUE_TYPE_STRING JSON_STRING +#define HB_VALUE_TYPE_INT JSON_INTEGER +#define HB_VALUE_TYPE_DOUBLE JSON_REAL +#define HB_VALUE_TYPE_NULL JSON_NULL +#define HB_VALUE_TYPE_BOOL 0xff + +#define HB_DICT_ITER_DONE NULL + +typedef int hb_value_type_t; +typedef json_t hb_value_t; +typedef hb_value_t hb_dict_t; +typedef hb_value_t hb_value_array_t; +typedef void* hb_dict_iter_t; + +/* A dictionary implementation. * * an hb_dict_t must be initialized with hb_dict_init() before use. * * "key" must be a string with non-zero length (NULL and "" are invalid keys). - * "value" can be NULL (the zero-length string "" is mapped to NULL). - * - * hb_dict_next( dict, NULL ) returns the first key in the dictionary. - * hb_dict_next( dict, previous ) returns key directly following previous, or - * NULL if the end of the dictionary was reached. - * - * hb_encopts_to_dict() converts an op1=val1:opt2=val2:opt3=val3 type string to - * an hb_dict_t dictionary. */ + * "value" must be an hb_value_t* + */ +hb_dict_t * hb_dict_init(); +/* free dictionary and release references to all values it contains */ +void hb_dict_free(hb_dict_t ** dict_ptr); +/* add value to dictionary. dictionary takes ownership of value */ +void hb_dict_set(hb_dict_t * dict, const char * key, + hb_value_t * value); +/* remove value from dictionary. releases reference to value */ +int hb_dict_remove(hb_dict_t * dict, const char * key); +/* get value from dictionary. value has borrowed reference */ +hb_value_t * hb_dict_get(hb_dict_t * dict, const char * key); + +/* dict iterator + * hb_dict_iter_init(dict) returns an iter to the first key/value in the dict + * hb_dict_iter_next(dict, iter) returns an iter to the next key/value + * HB_DICT_ITER_DONE if the end of the dictionary was reached. + */ +hb_dict_iter_t hb_dict_iter_init(const hb_dict_t *dict); +hb_dict_iter_t hb_dict_iter_next(const hb_dict_t *dict, hb_dict_iter_t iter); +/* get key from iter */ +const char * hb_dict_iter_key(const hb_dict_iter_t iter); +/* get value from iter. value has borrowed reference */ +hb_value_t * hb_dict_iter_value(const hb_dict_iter_t iter); -hb_dict_t * hb_dict_init( int alloc ); -void hb_dict_free( hb_dict_t ** dict_ptr ); +/* hb_value_array_t */ +hb_value_array_t * hb_value_array_init(); +/* remove all elements of array */ +void hb_value_array_clear(hb_value_array_t *array); +/* get value from array. value has borrowed reference */ +hb_value_t * hb_value_array_get(const hb_value_array_t *array, int index); +/* replace value at index in array. array takes ownership of new value */ +void hb_value_array_set(hb_value_array_t *array, int index, + hb_value_t *value); +/* insert value at index in array. values move up. + * array takes ownership of new value */ +void hb_value_array_insert(hb_value_array_t *array, int index, + hb_value_t *value); +/* append value to array. array takes ownership of new value */ +void hb_value_array_append(hb_value_array_t *array, + hb_value_t *value); +/* remove value from array. releases reference to value */ +void hb_value_array_remove(hb_value_array_t *array, int index); +/* clears dst and performs a deep copy */ +void hb_value_array_copy(hb_value_array_t *dst, + const hb_value_array_t *src, int count); +size_t hb_value_array_len(const hb_value_array_t *array); -void hb_dict_set( hb_dict_t ** dict_ptr, const char * key, const char * value ); -void hb_dict_unset( hb_dict_t ** dict_ptr, const char * key ); +/* hb_value_t */ +int hb_value_type(const hb_value_t *value); +hb_value_t * hb_value_dup(hb_value_t *value); +void hb_value_incref(hb_value_t *value); +void hb_value_decref(hb_value_t *value); +void hb_value_free(hb_value_t **value); -hb_dict_entry_t * hb_dict_get( hb_dict_t * dict, const char * key ); -hb_dict_entry_t * hb_dict_next( hb_dict_t * dict, hb_dict_entry_t * previous ); +/* Create new hb_value_t */ +hb_value_t * hb_value_string(const char *value); +hb_value_t * hb_value_int(json_int_t value); +hb_value_t * hb_value_double(double value); +hb_value_t * hb_value_bool(int value); -hb_dict_t * hb_encopts_to_dict( const char * encopts, int encoder ); -char * hb_dict_to_encopts( hb_dict_t * dict ); +/* Transform hb_value_t from one type to another */ +hb_value_t * hb_value_xform(const hb_value_t *value, int type); -struct hb_dict_entry_s -{ - char * key; - char * value; -}; +/* Extract values */ +/* hb_value_t must be of type HB_VALUE_TYPE_STRING */ +const char * hb_value_get_string(const hb_value_t *value); +/* hb_value_t may be of any type, automatic conversion performed */ +json_int_t hb_value_get_int(const hb_value_t *value); +double hb_value_get_double(const hb_value_t *value); +int hb_value_get_bool(const hb_value_t *value); +/* converts value type and returns an allocated string representation. + * caller must free the returned string */ +char * hb_value_get_string_xform(const hb_value_t *value); -struct hb_dict_s -{ - int alloc; - int count; - hb_dict_entry_t * objects; -}; +/* specialized dict functions */ +/* + * hb_encopts_to_dict() converts an op1=val1:opt2=val2:opt3=val3 type string to + * an hb_dict_t dictionary. */ +hb_dict_t * hb_encopts_to_dict(const char * encopts, int encoder); +char * hb_dict_to_encopts(const hb_dict_t * dict); #endif // !defined(HB_DICT_H) diff --git a/libhb/hb_json.c b/libhb/hb_json.c index f4b1bb814..8020221d1 100644 --- a/libhb/hb_json.c +++ b/libhb/hb_json.c @@ -8,6 +8,7 @@ */ #include +#include "hb.h" #include "hb_json.h" #include "libavutil/base64.h" diff --git a/libhb/hb_json.h b/libhb/hb_json.h index b5025a6c2..a6ec311eb 100644 --- a/libhb/hb_json.h +++ b/libhb/hb_json.h @@ -14,7 +14,7 @@ extern "C" { #endif -#include "hb.h" +#include "common.h" char * hb_get_title_set_json(hb_handle_t * h); char * hb_title_to_json(const hb_title_t * title); -- cgit v1.2.3