diff --git a/codecs/avif/Makefile b/codecs/avif/Makefile index 59d0b7de..c22eef1e 100644 --- a/codecs/avif/Makefile +++ b/codecs/avif/Makefile @@ -1,9 +1,9 @@ # libavif and libaom versions are from # https://docs.google.com/document/d/1wEEA5rRU7wT54k41u3qyZIZHDCJArIMzLuzsrLAwaK8/edit -CODEC_URL = https://github.com/AOMediaCodec/libavif/archive/d37ef74127986184500e571bf1f9793cc0bdef50.tar.gz +CODEC_URL = https://github.com/AOMediaCodec/libavif/archive/1c39e772c2c0d687691dd4b589a12c323f5f767d.tar.gz CODEC_PACKAGE = node_modules/libavif.tar.gz -LIBAOM_URL = https://aomedia.googlesource.com/aom/+archive/0a5da45c7f942908974f5ab8e107c9fa82048ae7.tar.gz +LIBAOM_URL = https://aomedia.googlesource.com/aom/+archive/v3.1.0.tar.gz LIBAOM_PACKAGE = node_modules/libaom.tar.gz export CODEC_DIR = node_modules/libavif diff --git a/codecs/avif/enc/avif_enc.cpp b/codecs/avif/enc/avif_enc.cpp index 23774b07..e7f63b43 100644 --- a/codecs/avif/enc/avif_enc.cpp +++ b/codecs/avif/enc/avif_enc.cpp @@ -29,8 +29,10 @@ struct AvifOptions { bool chromaDeltaQ; // 0-7 int sharpness; - // Target ssim rather than psnr - bool targetSsim; + // 0 = auto + // 1 = PSNR + // 2 = SSIM + int tune; // 0-50 int denoiseLevel; }; @@ -98,7 +100,7 @@ val encode(std::string buffer, int width, int height, AvifOptions options) { std::to_string(options.cqAlphaLevel).c_str()); } - if (options.targetSsim) { + if (options.tune == 2 || (options.tune == 0 && options.cqLevel <= 32)) { avifEncoderSetCodecSpecificOption(encoder, "tune", "ssim"); } @@ -136,7 +138,7 @@ EMSCRIPTEN_BINDINGS(my_module) { .field("speed", &AvifOptions::speed) .field("chromaDeltaQ", &AvifOptions::chromaDeltaQ) .field("sharpness", &AvifOptions::sharpness) - .field("targetSsim", &AvifOptions::targetSsim) + .field("tune", &AvifOptions::tune) .field("denoiseLevel", &AvifOptions::denoiseLevel) .field("subsample", &AvifOptions::subsample); diff --git a/codecs/avif/enc/avif_enc.d.ts b/codecs/avif/enc/avif_enc.d.ts index 5d14a092..cab6bb18 100644 --- a/codecs/avif/enc/avif_enc.d.ts +++ b/codecs/avif/enc/avif_enc.d.ts @@ -1,3 +1,9 @@ +export const enum AVIFTune { + auto, + psnr, + ssim, +} + export interface EncodeOptions { cqLevel: number; denoiseLevel: number; @@ -8,7 +14,7 @@ export interface EncodeOptions { subsample: number; chromaDeltaQ: boolean; sharpness: number; - targetSsim: boolean; + tune: AVIFTune; } export interface AVIFModule extends EmscriptenWasm.Module { diff --git a/codecs/avif/enc/avif_enc.wasm b/codecs/avif/enc/avif_enc.wasm index a9dc3e5b..7c1701bd 100755 Binary files a/codecs/avif/enc/avif_enc.wasm and b/codecs/avif/enc/avif_enc.wasm differ diff --git a/codecs/avif/enc/avif_enc_mt.js b/codecs/avif/enc/avif_enc_mt.js index 77d1143f..7c2551cb 100644 --- a/codecs/avif/enc/avif_enc_mt.js +++ b/codecs/avif/enc/avif_enc_mt.js @@ -18,7 +18,7 @@ function Ia(a){for(var b=0,c=0;c=a||a>aa().length||a&1||0>b)return-28;if(0==b)return 0;2147483647<=b&&(b=Infinity);var c=Atomics.load(w(),M.vb>>2),d=0;if(c==a&&Atomics.compareExchange(w(),M.vb>>2,c,0)==c&&(--b,d=1,0>=b))return 1;a=Atomics.notify(w(),a>>2,b);if(0<=a)return a+d;throw"Atomics.notify returned an unexpected value "+a;}z._emscripten_futex_wake=ab; function bb(a){if(B)throw"Internal Error! cleanupThread() can only ever be called from main application thread!";if(!a)throw"Internal Error! Null pthread_ptr in cleanupThread!";w()[a+12>>2]=0;(a=M.Ya[a])&&M.jb(a.worker)} var M={ac:1,kc:{yb:0,zb:0},Wa:[],$a:[],Lb:function(){for(var a=navigator.hardwareConcurrency,b=0;ba;++a)y()[M.Ua/4+a]=0;w()[M.Ua+12>>2]=M.Ua;a=M.Ua+156;w()[a>>2]=a;var b=N(512);for(a=0;128>a;++a)y()[b/4+a]=0;Atomics.store(y(),M.Ua+104>>2,b);Atomics.store(y(),M.Ua+40>>2,M.Ua);Atomics.store(y(),M.Ua+44>>2,42);M.tb();$a(M.Ua,!1,1);cb(M.Ua)},Nb:function(){M.tb();oa(z);M.receiveObjectTransfer=M.Sb;M.setThreadStatus=M.Tb;M.threadCancel=M.Yb;M.threadExit= @@ -86,7 +86,7 @@ z._emscripten_sync_run_in_main_thread_1=function(){return(z._emscripten_sync_run z._emscripten_sync_run_in_main_thread_3=function(){return(z._emscripten_sync_run_in_main_thread_3=z.asm.Ga).apply(null,arguments)};var Cc=z._emscripten_sync_run_in_main_thread_4=function(){return(Cc=z._emscripten_sync_run_in_main_thread_4=z.asm.Ha).apply(null,arguments)};z._emscripten_sync_run_in_main_thread_5=function(){return(z._emscripten_sync_run_in_main_thread_5=z.asm.Ia).apply(null,arguments)}; z._emscripten_sync_run_in_main_thread_6=function(){return(z._emscripten_sync_run_in_main_thread_6=z.asm.Ja).apply(null,arguments)};z._emscripten_sync_run_in_main_thread_7=function(){return(z._emscripten_sync_run_in_main_thread_7=z.asm.Ka).apply(null,arguments)}; var Wb=z._emscripten_run_in_main_runtime_thread_js=function(){return(Wb=z._emscripten_run_in_main_runtime_thread_js=z.asm.La).apply(null,arguments)},bc=z.__emscripten_call_on_thread=function(){return(bc=z.__emscripten_call_on_thread=z.asm.Ma).apply(null,arguments)};z._emscripten_tls_init=function(){return(z._emscripten_tls_init=z.asm.Na).apply(null,arguments)};z.dynCall_jiiiiiiiii=function(){return(z.dynCall_jiiiiiiiii=z.asm.Oa).apply(null,arguments)}; -z.dynCall_jiji=function(){return(z.dynCall_jiji=z.asm.Pa).apply(null,arguments)};z.dynCall_jiiiiiiii=function(){return(z.dynCall_jiiiiiiii=z.asm.Qa).apply(null,arguments)};z.dynCall_jiiiiii=function(){return(z.dynCall_jiiiiii=z.asm.Ra).apply(null,arguments)};z.dynCall_jiiiii=function(){return(z.dynCall_jiiiii=z.asm.Sa).apply(null,arguments)};z.dynCall_iiijii=function(){return(z.dynCall_iiijii=z.asm.Ta).apply(null,arguments)};var db=z._main_thread_futex=899124; +z.dynCall_jiji=function(){return(z.dynCall_jiji=z.asm.Pa).apply(null,arguments)};z.dynCall_jiiiiiiii=function(){return(z.dynCall_jiiiiiiii=z.asm.Qa).apply(null,arguments)};z.dynCall_jiiiiii=function(){return(z.dynCall_jiiiiii=z.asm.Ra).apply(null,arguments)};z.dynCall_jiiiii=function(){return(z.dynCall_jiiiii=z.asm.Sa).apply(null,arguments)};z.dynCall_iiijii=function(){return(z.dynCall_iiijii=z.asm.Ta).apply(null,arguments)};var db=z._main_thread_futex=899108; function zc(a,b){var c=Y();try{H.get(a)(b)}catch(d){P(c);if(d!==d+0&&"longjmp"!==d)throw d;Z(1,0)}}function Bc(a,b,c,d,f){var g=Y();try{H.get(a)(b,c,d,f)}catch(h){P(g);if(h!==h+0&&"longjmp"!==h)throw h;Z(1,0)}}function Ac(a,b,c){var d=Y();try{H.get(a)(b,c)}catch(f){P(d);if(f!==f+0&&"longjmp"!==f)throw f;Z(1,0)}}function yc(a,b,c,d,f,g,h,k,m,q){var p=Y();try{return H.get(a)(b,c,d,f,g,h,k,m,q)}catch(v){P(p);if(v!==v+0&&"longjmp"!==v)throw v;Z(1,0)}} function vc(a,b,c){var d=Y();try{return H.get(a)(b,c)}catch(f){P(d);if(f!==f+0&&"longjmp"!==f)throw f;Z(1,0)}}function wc(a,b,c,d,f){var g=Y();try{return H.get(a)(b,c,d,f)}catch(h){P(g);if(h!==h+0&&"longjmp"!==h)throw h;Z(1,0)}}function uc(a,b){var c=Y();try{return H.get(a)(b)}catch(d){P(c);if(d!==d+0&&"longjmp"!==d)throw d;Z(1,0)}}function xc(a,b,c,d,f,g,h,k,m){var q=Y();try{return H.get(a)(b,c,d,f,g,h,k,m)}catch(p){P(q);if(p!==p+0&&"longjmp"!==p)throw p;Z(1,0)}}z.PThread=M;z.PThread=M; z._pthread_self=oc;z.wasmMemory=e;z.ExitStatus=Fc;var Gc;function Fc(a){this.name="ExitStatus";this.message="Program terminated with exit("+a+")";this.status=a}Qa=function Hc(){Gc||Ic();Gc||(Qa=Hc)}; diff --git a/codecs/avif/enc/avif_enc_mt.wasm b/codecs/avif/enc/avif_enc_mt.wasm index 54ee4bef..a00bafa5 100755 Binary files a/codecs/avif/enc/avif_enc_mt.wasm and b/codecs/avif/enc/avif_enc_mt.wasm differ diff --git a/codecs/avif/enc/avif_node_enc.wasm b/codecs/avif/enc/avif_node_enc.wasm index a9dc3e5b..7c1701bd 100755 Binary files a/codecs/avif/enc/avif_node_enc.wasm and b/codecs/avif/enc/avif_node_enc.wasm differ diff --git a/src/features/encoders/avif/client/index.tsx b/src/features/encoders/avif/client/index.tsx index dc2e2a05..651c2fd3 100644 --- a/src/features/encoders/avif/client/index.tsx +++ b/src/features/encoders/avif/client/index.tsx @@ -1,4 +1,4 @@ -import { EncodeOptions, defaultOptions } from '../shared/meta'; +import { EncodeOptions, defaultOptions, AVIFTune } from '../shared/meta'; import type WorkerBridge from 'client/lazy-app/worker-bridge'; import { h, Component } from 'preact'; import { preventDefault, shallowEqual } from 'client/lazy-app/util'; @@ -37,7 +37,7 @@ interface State { sharpness: number; denoiseLevel: number; aqMode: number; - tune: 'ssim' | 'psnr'; + tune: AVIFTune; } const maxQuant = 63; @@ -82,7 +82,7 @@ export class Options extends Component { chromaDeltaQ: options.chromaDeltaQ, sharpness: options.sharpness, denoiseLevel: options.denoiseLevel, - tune: options.targetSsim ? 'ssim' : 'psnr', + tune: options.tune, }; } @@ -133,7 +133,7 @@ export class Options extends Component { chromaDeltaQ: optionState.chromaDeltaQ, sharpness: optionState.sharpness, denoiseLevel: optionState.denoiseLevel, - targetSsim: optionState.tune === 'ssim', + tune: optionState.tune, }; // Updating options, so we don't recalculate in getDerivedStateFromProps. @@ -268,13 +268,14 @@ export class Options extends Component { diff --git a/src/features/encoders/avif/shared/meta.ts b/src/features/encoders/avif/shared/meta.ts index 21371e27..2349a350 100644 --- a/src/features/encoders/avif/shared/meta.ts +++ b/src/features/encoders/avif/shared/meta.ts @@ -10,9 +10,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { EncodeOptions } from 'codecs/avif/enc/avif_enc'; +import { EncodeOptions, AVIFTune } from 'codecs/avif/enc/avif_enc'; -export { EncodeOptions }; +export { EncodeOptions, AVIFTune }; export const label = 'AVIF'; export const mimeType = 'image/avif'; @@ -27,5 +27,5 @@ export const defaultOptions: EncodeOptions = { subsample: 1, chromaDeltaQ: false, sharpness: 0, - targetSsim: false, + tune: AVIFTune.auto, };