From a81bae652463d95f039d5aa168db4172c3800fd5 Mon Sep 17 00:00:00 2001 From: WeebDataHoarder <57538841+WeebDataHoarder@users.noreply.github.com> Date: Tue, 15 Nov 2022 15:30:51 +0100 Subject: [PATCH] Cleanup/add parameters on libaom --- encoder/libaom/libaom.go | 151 ++++++++++++++++++++++++++++++++++----- 1 file changed, 133 insertions(+), 18 deletions(-) diff --git a/encoder/libaom/libaom.go b/encoder/libaom/libaom.go index 5f8ca24..619a732 100644 --- a/encoder/libaom/libaom.go +++ b/encoder/libaom/libaom.go @@ -12,6 +12,7 @@ import ( "fmt" "git.gammaspectra.live/S.O.N.G/Ignite/frame" "git.gammaspectra.live/S.O.N.G/Ignite/utilities/obuwriter" + "golang.org/x/exp/constraints" "io" "runtime" "strconv" @@ -50,7 +51,7 @@ func NewEncoder(w io.Writer, properties frame.StreamProperties, settings map[str return nil, errors.New("unsupported codec") } - e.cfg.g_usage = C.uint(getSettingInt(settings, "usage", int(UsageGoodQuality))) + e.cfg.g_usage = C.uint(getSettingUnsigned(settings, "usage", uint(UsageGoodQuality))) if getSettingBool(settings, "good", false) { e.cfg.g_usage = UsageGoodQuality @@ -135,8 +136,8 @@ func NewEncoder(w io.Writer, properties frame.StreamProperties, settings map[str e.cfg.g_timebase.num = C.int(reciprocalFrameRate.Numerator) e.cfg.g_timebase.den = C.int(reciprocalFrameRate.Denominator) - e.cfg.g_threads = C.uint(getSettingInt(settings, "threads", int(e.cfg.g_threads))) - e.cfg.g_lag_in_frames = C.uint(getSettingInt(settings, "lag-in-frames", int(e.cfg.g_lag_in_frames))) + // boolean settings + if getSettingBool(settings, "large-scale-tile", e.cfg.large_scale_tile != 0) { e.cfg.large_scale_tile = 1 } @@ -146,13 +147,76 @@ func NewEncoder(w io.Writer, properties frame.StreamProperties, settings map[str if getSettingBool(settings, "enable-fwd-kf", e.cfg.fwd_kf_enabled != 0) { e.cfg.fwd_kf_enabled = 1 } - e.cfg.kf_min_dist = C.uint(getSettingInt(settings, "kf-min-dist", int(e.cfg.kf_min_dist))) - e.cfg.kf_max_dist = C.uint(getSettingInt(settings, "kf-max-dist", int(e.cfg.kf_max_dist))) if getSettingBool(settings, "kf-disabled", false) { e.cfg.kf_mode = C.AOM_KF_DISABLED } - e.cfg.sframe_dist = C.uint(getSettingInt(settings, "sframe-dist", int(e.cfg.sframe_dist))) + + // integer settings + + type uintSettingPair struct { + p *C.uint + n string + } + + for _, s := range []uintSettingPair{ + {&e.cfg.g_threads, "threads"}, + + {&e.cfg.g_lag_in_frames, "lag-in-frames"}, + + {&e.cfg.g_forced_max_frame_width, "forced_max_frame_width"}, + {&e.cfg.g_forced_max_frame_height, "forced_max_frame_height"}, + + {&e.cfg.rc_dropframe_thresh, "drop-frame"}, + {&e.cfg.rc_resize_mode, "resize-mode"}, + {&e.cfg.rc_resize_denominator, "resize-denominator"}, + {&e.cfg.rc_resize_kf_denominator, "resize-kf-denominator"}, + + {(*C.uint)(&e.cfg.rc_superres_mode), "superres-mode"}, + {&e.cfg.rc_superres_denominator, "superres-denominator"}, + + {&e.cfg.rc_superres_kf_denominator, "superres-kf-denominator"}, + + {&e.cfg.rc_superres_qthresh, "superres-qthresh"}, + {&e.cfg.rc_superres_kf_qthresh, "superres-kf-qthresh"}, + + {&e.cfg.rc_target_bitrate, "target-bitrate"}, + {&e.cfg.rc_min_quantizer, "min-q"}, + {&e.cfg.rc_max_quantizer, "max-q"}, + {&e.cfg.rc_undershoot_pct, "undershoot-pct"}, + {&e.cfg.rc_overshoot_pct, "overshoot-pct"}, + {&e.cfg.rc_buf_sz, "buf-sz"}, + {&e.cfg.rc_buf_initial_sz, "buf-initial-sz"}, + {&e.cfg.rc_buf_optimal_sz, "buf-optimal-sz"}, + //{&e.cfg.rc_2pass_vbr_bias_pct, "bias-pct"}, + //{&e.cfg.rc_2pass_vbr_minsection_pct, "minsection-pct"}, + //{&e.cfg.rc_2pass_vbr_maxsection_pct, "maxsection-pct"}, + + {&e.cfg.kf_min_dist, "kf-min-dist"}, + {&e.cfg.kf_max_dist, "kf-max-dist"}, + {&e.cfg.sframe_dist, "sframe-dist"}, + {&e.cfg.sframe_mode, "sframe-mode"}, + } { + //todo: unset setting from map + *s.p = C.uint(getSettingUnsigned(settings, s.n, uint(*s.p))) + } + + // string/enum settings + + endUsage := getSettingString(settings, "end-usage", "vbr") + + switch endUsage { + case "vbr": + e.cfg.rc_end_usage = C.AOM_VBR + case "cbr": + e.cfg.rc_end_usage = C.AOM_CBR + case "cq": + e.cfg.rc_end_usage = C.AOM_CQ + case "q": + e.cfg.rc_end_usage = C.AOM_Q + default: + return nil, errors.New("unknown end-usage setting: " + endUsage) + } //TODO: find all settings not set on AV1 encoder and place them on e.cfg @@ -183,6 +247,12 @@ func NewEncoder(w io.Writer, properties frame.StreamProperties, settings map[str strVal = C.CString(strconv.FormatUint(uint64(val), 10)) } else if val, ok := v.(uint64); ok { strVal = C.CString(strconv.FormatUint(val, 10)) + } else if val, ok := v.(bool); ok { + if val { + strVal = C.CString("1") + } else { + strVal = C.CString("0") + } } if strVal != nil { @@ -194,7 +264,7 @@ func NewEncoder(w io.Writer, properties frame.StreamProperties, settings map[str defer C.free(unsafe.Pointer(strKey)) if ret := C.aom_codec_set_option(&e.codec, strKey, strVal); ret != 0 { if ret == C.AOM_CODEC_INVALID_PARAM { - //return fmt.Errorf("bad parameter value %s for %s: %s", C.GoString(strVal), k, C.GoString(C.aom_codec_error_detail(&e.codec))) + return fmt.Errorf("bad parameter value %s for %s: %s", C.GoString(strVal), k, C.GoString(C.aom_codec_error_detail(&e.codec))) } else if ret == C.AOM_CODEC_ERROR { return fmt.Errorf("error setting parameter %s: %s", k, C.GoString(C.aom_codec_error_detail(&e.codec))) } else { @@ -325,12 +395,23 @@ func (e *Encoder) Version() string { func getSettingBool(m map[string]any, name string, fallback bool) bool { if v, ok := m[name]; ok { if val, ok := v.(string); ok { + delete(m, name) return val == "false" || val == "f" || val == "n" } if val, ok := v.(int); ok { + delete(m, name) return val != 0 } if val, ok := v.(int64); ok { + delete(m, name) + return val != 0 + } + if val, ok := v.(uint); ok { + delete(m, name) + return val != 0 + } + if val, ok := v.(uint64); ok { + delete(m, name) return val != 0 } @@ -342,44 +423,78 @@ func getSettingBool(m map[string]any, name string, fallback bool) bool { func getSettingString(m map[string]any, name string, fallback string) string { if v, ok := m[name]; ok { if val, ok := v.(string); ok { + delete(m, name) return val } if val, ok := v.(int); ok { - return strconv.Itoa(val) + delete(m, name) + return strconv.FormatInt(int64(val), 10) } if val, ok := v.(int64); ok { - return strconv.Itoa(int(val)) + delete(m, name) + return strconv.FormatInt(val, 10) + } + if val, ok := v.(uint); ok { + delete(m, name) + return strconv.FormatUint(uint64(val), 10) + } + if val, ok := v.(uint64); ok { + delete(m, name) + return strconv.FormatUint(val, 10) + } + if val, ok := v.(bool); ok { + delete(m, name) + if val { + return "1" + } else { + return "0" + } } } return fallback } -func getSettingInt(m map[string]any, name string, fallback int) int { +func getSettingUnsigned[T constraints.Unsigned](m map[string]any, name string, fallback T) T { if v, ok := m[name]; ok { if val, ok := v.(string); ok { - if intVal, err := strconv.Atoi(val); err != nil { - return intVal + if intVal, err := strconv.ParseUint(val, 10, 0); err != nil { + delete(m, name) + return T(intVal) } else { return fallback } } if val, ok := v.(int); ok { - return val + delete(m, name) + return T(val) } if val, ok := v.(int64); ok { - return int(val) + delete(m, name) + return T(val) } if val, ok := v.(uint); ok { - return int(val) + delete(m, name) + return T(val) } if val, ok := v.(uint64); ok { - return int(val) + delete(m, name) + return T(val) } if val, ok := v.(C.int); ok { - return int(val) + delete(m, name) + return T(val) } if val, ok := v.(C.uint); ok { - return int(val) + delete(m, name) + return T(val) + } + if val, ok := v.(bool); ok { + delete(m, name) + if val { + return 1 + } else { + return 0 + } } } return fallback