AOMediaCodec / libavif

libavif - Library for encoding and decoding .avif files
Other
1.44k stars 188 forks source link

The "-a denoise-noise-level=" command is not working anymore. #1137

Open tuqueque opened 1 year ago

tuqueque commented 1 year ago

Hello... In past versions of avifenc (6 months ago or so) I was able to use the "-a denoise-noise-level=16" command and I got a nice, subtle film grain-like noise in my avif images that greatly helped cover some minor compression artifacts when using relatively low image quality settings. I could lower the image quality further using this setting and still get fantastic looking images!

Recently, this feature is not working anymore in avifenc. I even bumped the "denoise-noise-level" value to something crazy like 100 and still got no film grain noise. I know this feature is sort of borrowed from aomenc, but this still works in aomenc perfectly, so I don't know what's going on recently in avifenc.

I hope this is sort of a bug and this fantastic feature can be brought back into avifenc. It's one of my favorite features in aomenc and avifenc!

My system: Manjaro Linux, 5.19.7-1 kernel.

wantehchang commented 1 year ago

Hi tuqueque,

Thank you for the bug report. I don't use -a denoise-noise-level=, so I will need detailed steps to reproduce how you build avifenc and also aomenc. In particular, how you check out the libavif and libaom source trees.

Please also post the output of your avifenc --version command.

If you can still build an old version of avifenc in which -a denoise-noise-level=16 works, that will also be very helpful.

Thanks.

tuqueque commented 1 year ago

I don't use -a denoise-noise-level=, so I will need detailed steps to reproduce

The exact command I run when I convert images with avifenc is:

avifenc --codec aom --ignore-icc --yuv 420 --depth 10 --speed 1 --min 1 --max 63 --minalpha 1 --maxalpha 63 -a end-usage=q -a cq-level=16 -a frame-boost=1 -a enable-keyframe-filtering=1 -a tune=ssim -a dist-metric=qm-psnr -a enable-qm=1 -a qm-min=1 -a qm-max=14 -a enable-chroma-deltaq=1 -a enable-dnl-denoising=0 -a denoise-noise-level=256 -a enable-ab-partitions=0 -a disable-trellis-quant=0 -a quant-b-adapt=1 -a enable-tpl-model=1 -a deltaq-mode=3 -a aq-mode=1 -a sharpness=1 input_image.png output_image.avif

how you build avifenc and also aomenc. In particular, how you check out the libavif and libaom source trees.

I'm fairly new to building stuff from source, so I don't understand the question entirely, the one-liner version command I run to build avifenc is:

git clone https://github.com/AOMediaCodec/libavif.git && cd libavif && cd ext && ./aom.cmd && cd .. && cd .. && mkdir build && cd build && cmake /home/user/SourceBuilds/libavif -DCMAKE_BUILD_TYPE=Release -DAVIF_LOCAL_AOM=1 -DAVIF_CODEC_AOM=1 -DBUILD_SHARED_LIBS=0 -DAVIF_BUILD_APPS=1 && make

Please also post the output of your avifenc --version command.

avifenc --version
Version: 0.10.1 (aom [enc/dec]:3.5.0)
libyuv : available (1813)

If you can still build an old version of avifenc in which -a denoise-noise-level=16 works, that will also be very helpful.

Yes, I managed to find the last version where the -a denoise-noise-level=16 command worked, the version is 0.9.3

Just one little detail in case you do some testing with the command I run when converting images in avifenc, with version 0.9.3 of avifenc, the parameter -a dist-metric=qm-psnr will throw an error. I guess it wasn't implemented in that version yet, so just remove it when using 0.9.3.

wantehchang commented 1 year ago

Hi tuqueque,

Could you print the output of the avifenc --version command in which -a denoise-noise-level=16 works?

If you still have the source tree for that avifenc command, could you cd into the libavif directory and post the output of the git log -1 command?

Thanks.

tuqueque commented 1 year ago

Could you print the output of the avifenc --version command in which -a denoise-noise-level=16 works?

avifenc --version
Version: 0.9.3 (aom [enc/dec]:3.2.0)
libyuv : available (1813)

If you still have the source tree for that avifenc command, could you cd into the libavif directory and post the output of the git log -1 command?

Once again, I don't understand this question. I barely know git stuff. I mostly build stuff following what I find over Internet and try to understand the commands...

To build the 0.9.3 version of avifenc, I just downloaded the 0.9.3 sources from this very github site ( https://github.com/AOMediaCodec/libavif/archive/refs/tags/v0.9.3.zip ) and ran almost the same command as always, but "adapted" to the 0.9.3 folder:

cd libavif-0.9.3/ext && ./aom.cmd && cd .. && cd .. && mkdir build && cd build && cmake /home/user/SourceBuilds/libavif -DCMAKE_BUILD_TYPE=Release -DAVIF_LOCAL_AOM=1 -DAVIF_CODEC_AOM=1 -DBUILD_SHARED_LIBS=0 -DAVIF_BUILD_APPS=1 && make

The resulting libavif 0.9.3 binary seems to work as intended, so I think I'm doing it correctly... although probably not in the most elegant way.

wantehchang commented 1 year ago

Hi tuqueque,

Thank you. You've answered my questions about how you built both versions of avifenc.

You also mentioned you used aomenc. Did you build it from source code? Could you paste the last few lines of the output of aomenc --help? It should look like the following:

Included encoders:

    av1    - AOMedia Project AV1 Encoder 3.5.0-226-g6fb5c7eea (default)

        Use --codec to switch to a non-default encoder.

You also said denoise-noise-level=16 still works in aomenc perfectly. What is the aomenc command line you're using?

In the libaom v3.3.0 release notes, I found the following item:

It may be related to the problem you reported. I will ask my coworkers on the libaom team about this.

tuqueque commented 1 year ago

You also mentioned you used aomenc. Did you build it from source code?

Oh, yes, I forgot to answer that question... Yes, I build it from source, this is the command I use to build it:

git clone https://aomedia.googlesource.com/aom && mkdir aom_build && cd aom_build && cmake /home/user/SourceBuilds/aom -DCONFIG_TUNE_BUTTERAUGLI=1 -DCONFIG_THREE_PASS=1 -DCONFIG_FRAME_PARALLEL_ENCODE=1 && make

Could you paste the last few lines of the output of aomenc --help?

Included encoders:

    av1    - AOMedia Project AV1 Encoder 3.5.0-242-g6ed0c7a32 (default)

        Use --codec to switch to a non-default encoder.

You also said denoise-noise-level=16 still works in aomenc perfectly. What is the aomenc command line you're using?

Oh, boy... I use a VERY long string of commands involving ffmpeg piping the output to aomenc using 2-pass encoding and mkvmerge... the relevant portion of the command would be this:

--good --use-16bit-internal --end-usage=vbr --target-bitrate=512 --tile-columns=1 --tile-rows=0 --row-mt=1 --frame-parallel=1 --threads=4 --cpu-used=2 --min-q=1 --sb-size=64 --bit-depth=10 --lag-in-frames=48 --arnr-strength=0 --arnr-maxframes=0 --tune=ssim --dist-metric=qm-psnr --kf-min-dist=24 --kf-max-dist=1440 --sframe-dist=4096 --sframe-mode=1 --frame-boost=1 --enable-fwd-kf=1 --enable-keyframe-filtering=1 --enable-qm=1 --qm-min=1 --qm-max=14 --enable-chroma-deltaq=1 --enable-dnl-denoising=0 --denoise-noise-level=16 --enable-ab-partitions=0 --coeff-cost-upd-freq=1 --disable-trellis-quant=0 --quant-b-adapt=1 --enable-tpl-model=1 --deltaq-mode=3 --aq-mode=1 --sharpness=1 --webm -o FILE_OUTPUT

If you really want to see the full, insane string...

printf $RANDOM | xargs -i sh -c 'ffmpeg -i "INPUT_FILE" -ac 2 -vbr on -c:a libopus -compression_level 10 -frame_duration 60 -b:a 64k -y "{}_audio.opus" & ffmpeg -i "INPUT_FILE" -loglevel quiet -map 0:0 -an -sn -pix_fmt yuv420p -f yuv4mpegpipe - | aomenc --passes=2 --pass=1 --fpf={}_1stpass.log --two-pass-output={}_2ndpass.log --second-pass-log={}_2ndpass.log --good --use-16bit-internal --end-usage=vbr --target-bitrate=512 --tile-columns=1 --tile-rows=0 --row-mt=1 --frame-parallel=1 --threads=4 --cpu-used=2 --min-q=1 --sb-size=64 --bit-depth=10 --lag-in-frames=48 --arnr-strength=0 --arnr-maxframes=0 --tune=ssim --dist-metric=qm-psnr --kf-min-dist=24 --kf-max-dist=1440 --sframe-dist=4096 --sframe-mode=1 --frame-boost=1 --enable-fwd-kf=1 --enable-keyframe-filtering=1 --enable-qm=1 --qm-min=1 --qm-max=14 --enable-chroma-deltaq=1 --enable-dnl-denoising=0 --denoise-noise-level=16 --enable-ab-partitions=0 --coeff-cost-upd-freq=1 --disable-trellis-quant=0 --quant-b-adapt=1 --enable-tpl-model=1 --deltaq-mode=3 --aq-mode=1 --sharpness=1 --webm -o /dev/null - && ffmpeg -i "INPUT_FILE" -loglevel quiet -map 0:0 -an -sn -pix_fmt yuv420p -f yuv4mpegpipe - | aomenc --passes=2 --pass=2 --fpf={}_1stpass.log --two-pass-output={}_2ndpass.log --second-pass-log={}_2ndpass.log --good --use-16bit-internal --end-usage=vbr --target-bitrate=512 --tile-columns=1 --tile-rows=0 --row-mt=1 --frame-parallel=1 --threads=4 --cpu-used=2 --min-q=1 --sb-size=64 --bit-depth=10 --lag-in-frames=48 --arnr-strength=0 --arnr-maxframes=0 --tune=ssim --dist-metric=qm-psnr --kf-min-dist=24 --kf-max-dist=1440 --sframe-dist=4096 --sframe-mode=1 --frame-boost=1 --enable-fwd-kf=1 --enable-keyframe-filtering=1 --enable-qm=1 --qm-min=1 --qm-max=14 --enable-chroma-deltaq=1 --enable-dnl-denoising=0 --denoise-noise-level=16 --enable-ab-partitions=0 --coeff-cost-upd-freq=1 --disable-trellis-quant=0 --quant-b-adapt=1 --enable-tpl-model=1 --deltaq-mode=3 --aq-mode=1 --sharpness=1 --webm -o "{}_video.webm" - && mkvmerge -o "{}_2pass_speed2_kf24-1440_sf4096_b512.mkv" "/home/user/{}_video.webm" "/home/user/{}_audio.opus"

In the libaom v3.3.0 release notes, I found the following item:

* Auto select noise synthesis level for all intra

It may be related to the problem you reported. I will ask my coworkers on the libaom team about this.

Thanks! I really hope the film grain noise feature comes back to avifenc. It really is useful!

wantehchang commented 1 year ago

Hi tuqueque,

Thank you for the answers. I also found the libaom changelist "Auto select noise synthesis level for all intra":

https://aomedia-review.googlesource.com/c/aom/+/147641

The change at lines 3750-3766 in av1/encoder/encoder.c in the changelist can explain this bug. libavif uses the all intra mode of libaom to encode still images, and cpi->oxcf.noise_level is the -a denoise-noise-level= value you passed to avifenc. The current code replaces the cpi->oxcf.noise_level value that you specified with a synthetic value, and the synthetic value is capped at 5.0.

tuqueque commented 1 year ago

Huh, interesting... I hope you consider this a bug and not a feature in avifenc... I really think the user should be able to control/decide how much noise they want in an image. I don't like that the encoder decides what value to use.

Also, does this apply to aomenc as well?... Reading the description in the commit, it seems to only affect aomenc if the "--allintra" command is placed in conjuction with the "--denoise-noise-level" with a value greater than "0"... Which I still think it shouldn't happen. The user should always be able to control the amount of noise in the video.

Anyway, I'm doing a test to see if I can control the noise value in aomenc.

wantehchang commented 1 year ago

Hi tuqueque,

You should be able to see the same bug in aomenc (in version 3.3.0 or later) if you replace the --good option with --allintra.

I need to discuss with the author of the libaom changelist to see how to resolve this issue. That changelist essentially turns the user-specified denoise-noise-level value in all intra mode into a boolean that controls this new feature. This has the unintended side effect of hiding the original denoise-noise-level feature in all intra mode.

gitoss commented 1 month ago

Is there any update on this, i.e. is the issue resoloved in newer libaom versions?

wantehchang commented 1 month ago

I am very sorry this fell through the cracks. I believe this issue in libaom hasn't been resolved. In the latest version of libaom, the code in av1/encoder/encoder.c that I referred to in https://github.com/AOMediaCodec/libavif/issues/1137#issuecomment-1258871110 still has the same problem:

#if CONFIG_DENOISE
  // even if denoise_noise_level is > 0, we don't need need to denoise on pass
  // 1 of 2 if enable_dnl_denoising is disabled since the 2nd pass will be
  // encoding the original (non-denoised) frame   
  if (cpi->oxcf.noise_level > 0 && !(cpi->oxcf.pass == AOM_RC_FIRST_PASS &&
                                     !cpi->oxcf.enable_dnl_denoising)) {
#if !CONFIG_REALTIME_ONLY
    // Choose a synthetic noise level for still images for enhanced perceptual
    // quality based on an estimated noise level in the source, but only if
    // the noise level is set on the command line to > 0.
    if (cpi->oxcf.mode == ALLINTRA) {
      // No noise synthesis if source is very clean.
      // Uses a low edge threshold to focus on smooth areas.
      // Increase output noise setting a little compared to measured value.
      double y_noise_level = 0.0;
      av1_estimate_noise_level(sd, &y_noise_level, AOM_PLANE_Y, AOM_PLANE_Y,
                               cm->seq_params->bit_depth, 16);
      cpi->oxcf.noise_level = (float)(y_noise_level - 0.1);
      cpi->oxcf.noise_level = (float)AOMMAX(0.0, cpi->oxcf.noise_level);
      if (cpi->oxcf.noise_level > 0.0) {
        cpi->oxcf.noise_level += (float)0.5;
      }
      cpi->oxcf.noise_level = (float)AOMMIN(5.0, cpi->oxcf.noise_level);
    }
#endif

    if (apply_denoise_2d(cpi, sd, cpi->oxcf.noise_block_size,
                         cpi->oxcf.noise_level, time_stamp, end_time) < 0)
      res = -1;
  }
#endif  //  CONFIG_DENOISE
gitoss commented 4 weeks ago

I am very sorry this fell through the cracks. I believe this issue in libaom hasn't been resolved. In the latest version of libaom, the code in av1/encoder/encoder.c that I referred to in #1137 (comment) still has the same problem

Thanks - I understand that this problem would be solved for libavif if the respective commit in libaom would be reverted? https://aomedia-review.googlesource.com/c/aom/+/147641