From a38b442474d711a9b9db8e7197a7876c37b2ca69 Mon Sep 17 00:00:00 2001 From: Harald Alvestrand Date: Wed, 24 Aug 2016 13:53:09 +0200 Subject: [PATCH 1/3] Update libvpx to version 1.6.0 This invalidates a set of configurations because legal values for VP9 "cpu-used" have changed, and require an update to the fixed-q patch for VP8. This touches a number of verification tools. NOTE this commit: Verification tool work showed that the way "verify_scores" works is not good. Another CL intended in order to fix that problem. --- bin/verify_scores | 17 +++++++++------- compile_tools.sh | 5 +++-- lib/vp9.py | 2 +- third_party/vp8_fixed_q.patch | 38 +++++++++++++++++------------------ 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/bin/verify_scores b/bin/verify_scores index 50e8086..2b62bb3 100755 --- a/bin/verify_scores +++ b/bin/verify_scores @@ -31,7 +31,7 @@ import mpeg_settings import encoder import optimizer import pick_codec - +import score_tools def ClassifyScoreRelation(old_score, new_score): if not old_score: @@ -45,12 +45,12 @@ def ClassifyScoreRelation(old_score, new_score): return 'improved' return 'worsened' -def VerifyOneTarget(codec_names, rate, videofile, old_scores, score): +def VerifyOneTarget(codec_names, rate, videofile, scorer_function, old_scores, score): change_counts = collections.Counter() for codec_name in codec_names: codec = pick_codec.PickCodec(codec_name) - old_optimizer = optimizer.Optimizer(codec, scoredir=old_scores) - new_optimizer = optimizer.Optimizer(codec) + old_optimizer = optimizer.Optimizer(codec, score_function=scorer_function, scoredir=old_scores) + new_optimizer = optimizer.Optimizer(codec, score_function=scorer_function) bestsofar = new_optimizer.RebaseEncoding( old_optimizer.BestEncoding(rate, videofile)) bestsofar.Recover() @@ -74,12 +74,12 @@ def VerifyOneTarget(codec_names, rate, videofile, old_scores, score): return change_counts -def VerifyResults(codec_names, old_scores, score): +def VerifyResults(codec_names, scorer_function, old_scores, score): change_counts = collections.Counter() for rate, filename in mpeg_settings.MpegFiles().AllFilesAndRates(): videofile = encoder.Videofile(filename) change_counts.update(VerifyOneTarget(codec_names, rate, - videofile, old_scores, score)) + videofile, scorer_function, old_scores, score)) print 'Result so far:', dict(change_counts) return change_counts @@ -88,9 +88,12 @@ def main(): parser.add_argument('codec_names', nargs='*', default=pick_codec.AllCodecNames()) parser.add_argument('--score', action='store_true', default=False) + parser.add_argument('--criterion', default='psnr') parser.add_argument('--old_scores', default='snapshot') args = parser.parse_args() - change_count = VerifyResults(args.codec_names, old_scores=args.old_scores, + scorer_function = score_tools.PickScorer(args.criterion) + change_count = VerifyResults(args.codec_names, + scorer_function, old_scores=args.old_scores, score=args.score) print 'Change evaluations: ', dict(change_count) return 0 diff --git a/compile_tools.sh b/compile_tools.sh index ad078b8..4266ed6 100755 --- a/compile_tools.sh +++ b/compile_tools.sh @@ -48,14 +48,15 @@ cd $WORKDIR/third_party build_vpxenc() { # Build the vpxenc and vpxdec binaries if [ ! -d libvpx ]; then - git clone http://git.chromium.org/webm/libvpx.git + git clone https://chromium.googlesource.com/webm/libvpx fi cd libvpx # Ensure we check out exactly a consistent version. git checkout -f master #git checkout v1.3.0 # Check out the Oct 20 2014 version of libvpx. - git checkout 9c98fb2bab6125a0614576bf7635981163b1cc79 + # git checkout 9c98fb2bab6125a0614576bf7635981163b1cc79 + git checkout v1.6.0 ./configure # Leftovers from previous compilations may be troublesome. make clean diff --git a/lib/vp9.py b/lib/vp9.py index f5f492c..c0c371e 100755 --- a/lib/vp9.py +++ b/lib/vp9.py @@ -29,7 +29,7 @@ def __init__(self, name='vp9'): super(Vp9Codec, self).__init__(name) self.extension = 'webm' self.option_set = encoder.OptionSet( - encoder.IntegerOption('cpu-used', 0, 16), + encoder.IntegerOption('cpu-used', 0, 8), # The "best" option gives encodes that are too slow to be useful. encoder.ChoiceOption(['good', 'rt']).Mandatory(), encoder.IntegerOption('passes', 1, 2), diff --git a/third_party/vp8_fixed_q.patch b/third_party/vp8_fixed_q.patch index bda762a..2c09cb3 100644 --- a/third_party/vp8_fixed_q.patch +++ b/third_party/vp8_fixed_q.patch @@ -37,10 +37,10 @@ Change-Id: Ic0000f50d5edf6351dad4ed0d398f7a88922bece 5 files changed, 53 insertions(+), 5 deletions(-) diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c -index 3cceb5a..c737d3c 100644 +index d5a0fff..4487ab4 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c -@@ -1578,7 +1578,8 @@ void vp8_change_config(VP8_COMP *cpi, VP8_CONFIG *oxcf) +@@ -1615,7 +1615,8 @@ void vp8_change_config(VP8_COMP *cpi, VP8_CONFIG *oxcf) if (oxcf->worst_allowed_q < 0) cpi->oxcf.fixed_q = q_trans[0]; else @@ -51,12 +51,12 @@ index 3cceb5a..c737d3c 100644 if (oxcf->alt_q < 0) cpi->oxcf.alt_q = q_trans[0]; diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c -index b1b079c..b6bef48 100644 +index 22a82b7..0c75011 100644 --- a/vp8/vp8_cx_iface.c +++ b/vp8/vp8_cx_iface.c -@@ -132,8 +132,19 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, +@@ -139,8 +139,19 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK(cfg, g_timebase.den, 1, 1000000000); - RANGE_CHECK(cfg, g_timebase.num, 1, cfg->g_timebase.den); + RANGE_CHECK(cfg, g_timebase.num, 1, 1000000000); RANGE_CHECK_HI(cfg, g_profile, 3); - RANGE_CHECK_HI(cfg, rc_max_quantizer, 63); - RANGE_CHECK_HI(cfg, rc_min_quantizer, cfg->rc_max_quantizer); @@ -76,7 +76,7 @@ index b1b079c..b6bef48 100644 RANGE_CHECK_HI(cfg, g_threads, 64); #if CONFIG_REALTIME_ONLY RANGE_CHECK_HI(cfg, g_lag_in_frames, 0); -@@ -333,7 +344,11 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, +@@ -342,7 +353,11 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, oxcf->best_allowed_q = cfg.rc_min_quantizer; oxcf->worst_allowed_q = cfg.rc_max_quantizer; oxcf->cq_level = vp8_cfg.cq_level; @@ -89,7 +89,7 @@ index b1b079c..b6bef48 100644 oxcf->under_shoot_pct = cfg.rc_undershoot_pct; oxcf->over_shoot_pct = cfg.rc_overshoot_pct; -@@ -1271,6 +1286,10 @@ static vpx_codec_enc_cfg_map_t vp8e_usage_cfg_map[] = +@@ -1315,6 +1330,10 @@ static vpx_codec_enc_cfg_map_t vp8e_usage_cfg_map[] = 256, /* rc_target_bandwidth */ 4, /* rc_min_quantizer */ 63, /* rc_max_quantizer */ @@ -101,10 +101,10 @@ index b1b079c..b6bef48 100644 100, /* rc_overshoot_pct */ diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c -index d3c2a13..7cb89b4 100644 +index 10d6893..03b84d6 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c -@@ -1344,6 +1344,12 @@ static vpx_codec_enc_cfg_map_t encoder_usage_cfg_map[] = { +@@ -1596,6 +1596,12 @@ static vpx_codec_enc_cfg_map_t encoder_usage_cfg_map[] = { 256, // rc_target_bandwidth 0, // rc_min_quantizer 63, // rc_max_quantizer @@ -113,15 +113,15 @@ index d3c2a13..7cb89b4 100644 + -1, + -1, + -1, -+ - 100, // rc_undershoot_pct - 100, // rc_overshoot_pct ++ + 25, // rc_undershoot_pct + 25, // rc_overshoot_pct diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h -index 044243d..41a6b3c 100644 +index 955e873..c7939e4 100644 --- a/vpx/vpx_encoder.h +++ b/vpx/vpx_encoder.h -@@ -519,6 +519,11 @@ extern "C" { +@@ -538,6 +538,11 @@ extern "C" { */ unsigned int rc_max_quantizer; @@ -134,10 +134,10 @@ index 044243d..41a6b3c 100644 /* * bitrate tolerance diff --git a/vpxenc.c b/vpxenc.c -index 2b89fc1..b9364e6 100644 +index efcf064..d34ad7a 100644 --- a/vpxenc.c +++ b/vpxenc.c -@@ -282,6 +282,14 @@ static const arg_def_t min_quantizer = ARG_DEF( +@@ -284,6 +284,14 @@ static const arg_def_t min_quantizer = ARG_DEF( NULL, "min-q", 1, "Minimum (best) quantizer"); static const arg_def_t max_quantizer = ARG_DEF( NULL, "max-q", 1, "Maximum (worst) quantizer"); @@ -152,7 +152,7 @@ index 2b89fc1..b9364e6 100644 static const arg_def_t undershoot_pct = ARG_DEF( NULL, "undershoot-pct", 1, "Datarate undershoot (min) target (%)"); static const arg_def_t overshoot_pct = ARG_DEF( -@@ -295,7 +303,8 @@ static const arg_def_t buf_optimal_sz = ARG_DEF( +@@ -297,7 +305,8 @@ static const arg_def_t buf_optimal_sz = ARG_DEF( static const arg_def_t *rc_args[] = { &dropframe_thresh, &resize_allowed, &resize_width, &resize_height, &resize_up_thresh, &resize_down_thresh, &end_usage, &target_bitrate, @@ -162,7 +162,7 @@ index 2b89fc1..b9364e6 100644 &buf_initial_sz, &buf_optimal_sz, NULL }; -@@ -1105,6 +1114,14 @@ static int parse_stream_params(struct VpxEncoderConfig *global, +@@ -1159,6 +1168,14 @@ static int parse_stream_params(struct VpxEncoderConfig *global, config->cfg.rc_min_quantizer = arg_parse_uint(&arg); } else if (arg_match(&arg, &max_quantizer, argi)) { config->cfg.rc_max_quantizer = arg_parse_uint(&arg); @@ -177,6 +177,4 @@ index 2b89fc1..b9364e6 100644 } else if (arg_match(&arg, &undershoot_pct, argi)) { config->cfg.rc_undershoot_pct = arg_parse_uint(&arg); } else if (arg_match(&arg, &overshoot_pct, argi)) { --- -1.8.2.3 From 514d2df0f376e24fee746db096e004828b356359 Mon Sep 17 00:00:00 2001 From: Harald Alvestrand Date: Wed, 31 Aug 2016 09:51:26 +0200 Subject: [PATCH 2/3] Fix bugs, add reporting This commit adds extensive reporting on what changed when a score changes. It also fixes a bug where the old score would be used for the new encoding. --- bin/verify_scores | 16 +++++++++++++--- lib/encoder.py | 12 ++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/bin/verify_scores b/bin/verify_scores index 2b62bb3..76d14e0 100755 --- a/bin/verify_scores +++ b/bin/verify_scores @@ -51,13 +51,13 @@ def VerifyOneTarget(codec_names, rate, videofile, scorer_function, old_scores, s codec = pick_codec.PickCodec(codec_name) old_optimizer = optimizer.Optimizer(codec, score_function=scorer_function, scoredir=old_scores) new_optimizer = optimizer.Optimizer(codec, score_function=scorer_function) - bestsofar = new_optimizer.RebaseEncoding( - old_optimizer.BestEncoding(rate, videofile)) + old_best_run = old_optimizer.BestEncoding(rate, videofile) + bestsofar = new_optimizer.RebaseEncoding(old_best_run) bestsofar.Recover() if score: bestsofar.Execute().Store() try: - old_score = old_optimizer.Score(bestsofar) + old_score = old_optimizer.Score(old_best_run) except encoder.Error: print 'No old score for %s %d %s, continuing' % \ (bestsofar.encoder.Hashname(), rate, videofile.filename) @@ -71,6 +71,16 @@ def VerifyOneTarget(codec_names, rate, videofile, scorer_function, old_scores, s result, old_score if old_score else float('-inf'), new_score if new_score else float('-inf')) + print 'Command line:', old_best_run.EncodeCommandLine() + if 'encoder_version' in old_best_run.Result(): + print 'Old version:', old_best_run.Result()['encoder_version'] + else: + print 'Old version unknown' + print 'New version:', bestsofar.Result()['encoder_version'] + print 'PSNR:', old_best_run.Result()['psnr'], '->', bestsofar.Result()['psnr'] + print 'Bitrate:', old_best_run.Result()['bitrate'], '->', bestsofar.Result()['bitrate'] + print 'Encode time:', old_best_run.Result()['encode_cputime'], '->', bestsofar.Result()['encode_cputime'] + print return change_counts diff --git a/lib/encoder.py b/lib/encoder.py index 806454c..8171d2c 100644 --- a/lib/encoder.py +++ b/lib/encoder.py @@ -767,10 +767,14 @@ def _FilesToEncodings(self, files, videofile, bitrate=None, encoder=None): candidates = [] for full_filename in files: - candidate = Encoding( - encoder or self._FileNameToEncoder(full_filename), - bitrate or _FileNameToBitrate(full_filename), - videofile or _FileNameToVideofile(full_filename)) + try: + candidate = Encoding( + encoder or self._FileNameToEncoder(full_filename), + bitrate or _FileNameToBitrate(full_filename), + videofile or _FileNameToVideofile(full_filename)) + except ParseError as e: + # print 'Ignoring parse error %s in file %s' % (e, full_filename) + continue try: candidate.Recover() candidates.append(candidate) From d80b00fb43f4382dc2a38521278e7af867f61a6e Mon Sep 17 00:00:00 2001 From: Harald Alvestrand Date: Thu, 15 Sep 2016 09:25:08 +0200 Subject: [PATCH 3/3] Linting and more parameters The aq-mode and end-usage parameters have been recommended for RT usage, so adding them. --- bin/verify_scores | 20 ++++++++++++++------ lib/encoder.py | 4 ++-- lib/vp9.py | 2 ++ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/bin/verify_scores b/bin/verify_scores index 76d14e0..c16e5c8 100755 --- a/bin/verify_scores +++ b/bin/verify_scores @@ -45,11 +45,14 @@ def ClassifyScoreRelation(old_score, new_score): return 'improved' return 'worsened' -def VerifyOneTarget(codec_names, rate, videofile, scorer_function, old_scores, score): +def VerifyOneTarget(codec_names, rate, videofile, scorer_function, + old_scores, score): + # pylint: disable=too-many-arguments, too-many-locals change_counts = collections.Counter() for codec_name in codec_names: codec = pick_codec.PickCodec(codec_name) - old_optimizer = optimizer.Optimizer(codec, score_function=scorer_function, scoredir=old_scores) + old_optimizer = optimizer.Optimizer(codec, score_function=scorer_function, + scoredir=old_scores) new_optimizer = optimizer.Optimizer(codec, score_function=scorer_function) old_best_run = old_optimizer.BestEncoding(rate, videofile) bestsofar = new_optimizer.RebaseEncoding(old_best_run) @@ -77,9 +80,13 @@ def VerifyOneTarget(codec_names, rate, videofile, scorer_function, old_scores, s else: print 'Old version unknown' print 'New version:', bestsofar.Result()['encoder_version'] - print 'PSNR:', old_best_run.Result()['psnr'], '->', bestsofar.Result()['psnr'] - print 'Bitrate:', old_best_run.Result()['bitrate'], '->', bestsofar.Result()['bitrate'] - print 'Encode time:', old_best_run.Result()['encode_cputime'], '->', bestsofar.Result()['encode_cputime'] + print 'PSNR: %5.3f -> %5.3f' % (old_best_run.Result()['psnr'], + bestsofar.Result()['psnr']) + print 'Bitrate: %d -> %d' % (old_best_run.Result()['bitrate'], + bestsofar.Result()['bitrate']) + print 'Encode time: %5.3f -> %5.3f' % ( + old_best_run.Result()['encode_cputime'], + bestsofar.Result()['encode_cputime']) print return change_counts @@ -89,7 +96,8 @@ def VerifyResults(codec_names, scorer_function, old_scores, score): for rate, filename in mpeg_settings.MpegFiles().AllFilesAndRates(): videofile = encoder.Videofile(filename) change_counts.update(VerifyOneTarget(codec_names, rate, - videofile, scorer_function, old_scores, score)) + videofile, scorer_function, + old_scores, score)) print 'Result so far:', dict(change_counts) return change_counts diff --git a/lib/encoder.py b/lib/encoder.py index 8171d2c..f925b17 100644 --- a/lib/encoder.py +++ b/lib/encoder.py @@ -772,8 +772,8 @@ def _FilesToEncodings(self, files, videofile, bitrate=None, encoder or self._FileNameToEncoder(full_filename), bitrate or _FileNameToBitrate(full_filename), videofile or _FileNameToVideofile(full_filename)) - except ParseError as e: - # print 'Ignoring parse error %s in file %s' % (e, full_filename) + except ParseError as err: + self.bad_encodings[full_filename] = err continue try: candidate.Recover() diff --git a/lib/vp9.py b/lib/vp9.py index c0c371e..a690ae9 100755 --- a/lib/vp9.py +++ b/lib/vp9.py @@ -33,6 +33,8 @@ def __init__(self, name='vp9'): # The "best" option gives encodes that are too slow to be useful. encoder.ChoiceOption(['good', 'rt']).Mandatory(), encoder.IntegerOption('passes', 1, 2), + encoder.IntegerOption('aq-mode', 0, 4), + encoder.Option('end-usage', ['cbr', 'vbr', 'cq', 'q']), ) def StartEncoder(self, context):