Opened 8 years ago
Closed 7 years ago
#6127 closed defect (fixed)
non-intuitive behavior of random() function used in zoompan filter's expressions
Reported by: | Peter Basista | Owned by: | |
---|---|---|---|
Priority: | normal | Component: | avfilter |
Version: | git-master | Keywords: | zoompan |
Cc: | Blocked By: | ||
Blocking: | Reproduced by developer: | no | |
Analyzed by developer: | no |
Description
Summary of the bug:
when random() function is used in a naive way (i.e. "random(0)
", without previously setting the internal variable 0
) inside an expression for zoompan filter's options, it always returns the *same* number which is very close to zero:
$ /usr/bin/ffmpeg -loop 1 -i alley.png -filter "zoompan='s=1920x1200:fps=60:z=3:y=y+print(random(0)*1000000000):x=x+print(random(1)*1000000000)'" -frames 600 output.hevc -y ffmpeg version 3.2.2-2 Copyright (c) 2000-2016 the FFmpeg developers built with gcc 6.3.0 (Debian 6.3.0-4) 20170121 configuration: --prefix=/usr --extra-version=2 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libebur128 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared libavutil 55. 34.100 / 55. 34.100 libavcodec 57. 64.101 / 57. 64.101 libavformat 57. 56.100 / 57. 56.100 libavdevice 57. 1.100 / 57. 1.100 libavfilter 6. 65.100 / 6. 65.100 libavresample 3. 1. 0 / 3. 1. 0 libswscale 4. 2.100 / 4. 2.100 libswresample 2. 3.100 / 2. 3.100 libpostproc 54. 1.100 / 54. 1.100 [png_pipe @ 0x557e77849f00] Stream #0: not enough frames to estimate rate; consider increasing probesize Input #0, png_pipe, from 'alley.png': Duration: N/A, bitrate: N/A Stream #0:0: Video: png, rgb24(pc), 7360x4912, 25 tbr, 25 tbn, 25 tbc x265 [info]: HEVC encoder version 0.0 x265 [info]: build info [Linux][GCC 6.2.0][64 bit] 8bit+10bit+12bit x265 [info]: using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX AVX2 FMA3 LZCNT BMI2 x265 [info]: Main 4:4:4 profile, Level-5 (Main tier) x265 [info]: Thread pool created using 8 threads x265 [info]: Slices : 1 x265 [info]: frame threads / pool features : 3 / wpp(19 rows) x265 [info]: Coding QT: max CU size, min CU size : 64 / 8 x265 [info]: Residual QT: max TU size, max depth : 32 / 1 inter / 1 intra x265 [info]: ME / range / subpel / merge : hex / 57 / 2 / 2 x265 [info]: Keyframe min / max / scenecut : 25 / 250 / 40 x265 [info]: Cb/Cr QP Offset : 6 / 6 x265 [info]: Lookahead / bframes / badapt : 20 / 4 / 2 x265 [info]: b-pyramid / weightp / weightb : 1 / 1 / 0 x265 [info]: References / ref-limit cu / depth : 3 / on / on x265 [info]: AQ: mode / str / qg-size / cu-tree : 1 / 1.0 / 32 / 1 x265 [info]: Rate Control / qCompress : CRF-28.0 / 0.60 x265 [info]: tools: rd=3 psy-rd=2.00 rskip signhide tmvp strong-intra-smoothing x265 [info]: tools: lslices=7 deblock sao Output #0, hevc, to 'output.hevc': Metadata: encoder : Lavf57.56.100 Stream #0:0: Video: hevc (libx265), gbrp, 1920x1200, q=2-31, 60 fps, 60 tbn, 60 tbc Metadata: encoder : Lavc57.64.101 libx265 Stream mapping: Stream #0:0 -> #0:0 (png (native) -> hevc (libx265)) Press [q] to stop, [?] for help 0.054964 Last message repeated 1 times 0.054964 1 fps=0.0 q=0.0 size= 0kB time=00:00:00.00 bitrate=N/A speed= 0x Last message repeated 19 times 0.054964 11 fps=8.5 q=0.0 size= 0kB time=00:00:00.00 bitrate=N/A speed= 0x Last message repeated 15 times [swscaler @ 0x557e79781500] Warning: data is not aligned! This can lead to a speedloss 0.054964 Last message repeated 5 times 0.054964 22 fps= 12 q=0.0 size= 0kB time=00:00:00.00 bitrate=N/A speed= 0x Last message repeated 15 times 0.054964 30 fps= 13 q=-0.0 size= 6kB time=-00:00:00.01 bitrate=N/A speed=N/A Last message repeated 15 times 0.054964 38 fps= 13 q=-0.0 size= 7kB time=00:00:00.11 bitrate= 501.0kbits/s speed=0.04x Last message repeated 17 times 0.054964 47 fps= 14 q=-0.0 size= 9kB time=00:00:00.26 bitrate= 261.3kbits/s speed=0.077x Last message repeated 17 times 0.054964 56 fps= 14 q=-0.0 size= 10kB time=00:00:00.41 bitrate= 190.8kbits/s speed=0.104x Last message repeated 17 times 0.054964 65 fps= 14 q=-0.0 size= 11kB time=00:00:00.56 bitrate= 152.7kbits/s speed=0.125x Last message repeated 15 times 0.054964 73 fps= 14 q=-0.0 size= 12kB time=00:00:00.70 bitrate= 141.1kbits/s speed=0.139x Last message repeated 17 times 0.054964 82 fps= 15 q=-0.0 size= 13kB time=00:00:00.85 bitrate= 127.0kbits/s speed=0.152x Last message repeated 15 times ...
The output above is from Debian's version of ffmpeg, but the same behavior can be experienced in git-master version as of today.
Explanation:
zoompan filter uses the internal formula evaluator to *parse* and evaluate the expressions for its options. The parsing is done for *every* frame (see function output_single_frame
in libavfilter/vf_zoompan.c
, line 135). This means that for every frame, the evaluator initializes the parser's internal variables 0-9 for each of the parsed expressions to zero (see function av_expr_parse
in libavutil/eval.c
, line 667). Therefore, no function is able to store its internal state into one of the internal variables and use it during the next evaluation (which is typically for the next frame), because there will always be only a single evaluation for every parsed expression.
This breaks the intuitive behavior of functions which require internal state, like random(). It uses an internal variable to store its current "seed" from which it calculates the next pseudorandom number (see function eval_expr
in libavutil/eval.c
, line 220). When the seed value is always the same (i.e. zero), the generated "pseudorandom" number is always the same as well.
Suggestion:
This non-intuitive behavior is caused by the fact that the expressions are parsed for every frame. If the expressions were parsed only during the filter's initialization and evaluated for every frame, the internal variables would be preserved and the above described problem would not exist. Some other filters, like the crop filter, use this technique and I believe it would be better if zoompan used it as well.
Fixed in bf39f7eadc684ab291a6f42ee9a85a6c2d804bc7.