From: Alexandre Julliard <julliard@winehq.org> Only C code for now, without asm optimizations. Based on a patch by Rémi Bernon. --- NOTICES.md | 9 + configure | 32 +- configure.ac | 2 + libs/ffmpeg/LICENSE.md | 127 + libs/ffmpeg/Makefile.in | 138 + libs/ffmpeg/VERSION | 1 + libs/ffmpeg/compat/va_copy.h | 34 + libs/ffmpeg/compat/w32pthreads.h | 247 ++ libs/ffmpeg/config.h | 833 ++++ libs/ffmpeg/config_components.asm | 2305 ++++++++++ libs/ffmpeg/config_components.h | 2308 ++++++++++ libs/ffmpeg/libavcodec/defs.h | 362 ++ libs/ffmpeg/libavcodec/get_bits.h | 715 +++ libs/ffmpeg/libavcodec/mathops.h | 257 ++ libs/ffmpeg/libavcodec/put_bits.h | 453 ++ libs/ffmpeg/libavcodec/vlc.h | 298 ++ libs/ffmpeg/libavutil/aarch64/cpu.h | 45 + libs/ffmpeg/libavutil/aarch64/crc.h | 68 + libs/ffmpeg/libavutil/aarch64/intreadwrite.h | 42 + libs/ffmpeg/libavutil/aarch64/timer.h | 53 + libs/ffmpeg/libavutil/adler32.c | 96 + libs/ffmpeg/libavutil/adler32.h | 63 + libs/ffmpeg/libavutil/aes.c | 283 ++ libs/ffmpeg/libavutil/aes.h | 69 + libs/ffmpeg/libavutil/aes_ctr.c | 135 + libs/ffmpeg/libavutil/aes_ctr.h | 99 + libs/ffmpeg/libavutil/aes_internal.h | 45 + .../libavutil/ambient_viewing_environment.c | 59 + .../libavutil/ambient_viewing_environment.h | 72 + libs/ffmpeg/libavutil/arm/bswap.h | 50 + libs/ffmpeg/libavutil/arm/cpu.h | 38 + libs/ffmpeg/libavutil/arm/intmath.h | 146 + libs/ffmpeg/libavutil/arm/timer.h | 46 + libs/ffmpeg/libavutil/attributes.h | 240 + libs/ffmpeg/libavutil/attributes_internal.h | 45 + libs/ffmpeg/libavutil/audio_fifo.c | 230 + libs/ffmpeg/libavutil/audio_fifo.h | 187 + libs/ffmpeg/libavutil/avassert.h | 125 + libs/ffmpeg/libavutil/avconfig.h | 6 + libs/ffmpeg/libavutil/avsscanf.c | 969 ++++ libs/ffmpeg/libavutil/avstring.c | 465 ++ libs/ffmpeg/libavutil/avstring.h | 428 ++ libs/ffmpeg/libavutil/avutil.h | 364 ++ libs/ffmpeg/libavutil/base64.c | 183 + libs/ffmpeg/libavutil/base64.h | 72 + libs/ffmpeg/libavutil/blowfish.c | 425 ++ libs/ffmpeg/libavutil/blowfish.h | 82 + libs/ffmpeg/libavutil/bprint.c | 332 ++ libs/ffmpeg/libavutil/bprint.h | 254 ++ libs/ffmpeg/libavutil/bswap.h | 105 + libs/ffmpeg/libavutil/buffer.c | 422 ++ libs/ffmpeg/libavutil/buffer.h | 322 ++ libs/ffmpeg/libavutil/buffer_internal.h | 110 + libs/ffmpeg/libavutil/camellia.c | 416 ++ libs/ffmpeg/libavutil/camellia.h | 70 + libs/ffmpeg/libavutil/cast5.c | 511 +++ libs/ffmpeg/libavutil/cast5.h | 80 + libs/ffmpeg/libavutil/channel_layout.c | 977 ++++ libs/ffmpeg/libavutil/channel_layout.h | 762 ++++ libs/ffmpeg/libavutil/common.h | 589 +++ libs/ffmpeg/libavutil/container_fifo.c | 219 + libs/ffmpeg/libavutil/container_fifo.h | 130 + libs/ffmpeg/libavutil/cpu.c | 324 ++ libs/ffmpeg/libavutil/cpu.h | 157 + libs/ffmpeg/libavutil/cpu_internal.h | 66 + libs/ffmpeg/libavutil/crc.c | 449 ++ libs/ffmpeg/libavutil/crc.h | 102 + libs/ffmpeg/libavutil/csp.c | 715 +++ libs/ffmpeg/libavutil/csp.h | 208 + libs/ffmpeg/libavutil/des.c | 333 ++ libs/ffmpeg/libavutil/des.h | 81 + libs/ffmpeg/libavutil/detection_bbox.c | 73 + libs/ffmpeg/libavutil/detection_bbox.h | 108 + libs/ffmpeg/libavutil/dict.c | 286 ++ libs/ffmpeg/libavutil/dict.h | 242 + libs/ffmpeg/libavutil/display.c | 74 + libs/ffmpeg/libavutil/display.h | 109 + libs/ffmpeg/libavutil/dovi_meta.c | 76 + libs/ffmpeg/libavutil/dovi_meta.h | 408 ++ libs/ffmpeg/libavutil/downmix_info.c | 41 + libs/ffmpeg/libavutil/downmix_info.h | 115 + libs/ffmpeg/libavutil/dynarray.h | 70 + libs/ffmpeg/libavutil/emms.h | 102 + libs/ffmpeg/libavutil/encryption_info.c | 343 ++ libs/ffmpeg/libavutil/encryption_info.h | 205 + libs/ffmpeg/libavutil/error.c | 151 + libs/ffmpeg/libavutil/error.h | 129 + libs/ffmpeg/libavutil/eval.c | 855 ++++ libs/ffmpeg/libavutil/eval.h | 140 + libs/ffmpeg/libavutil/executor.c | 221 + libs/ffmpeg/libavutil/executor.h | 67 + libs/ffmpeg/libavutil/ffmath.h | 67 + libs/ffmpeg/libavutil/ffversion.h | 5 + libs/ffmpeg/libavutil/fifo.c | 292 ++ libs/ffmpeg/libavutil/fifo.h | 242 + libs/ffmpeg/libavutil/file.c | 153 + libs/ffmpeg/libavutil/file.h | 62 + libs/ffmpeg/libavutil/file_open.c | 192 + libs/ffmpeg/libavutil/file_open.h | 57 + libs/ffmpeg/libavutil/film_grain_params.c | 106 + libs/ffmpeg/libavutil/film_grain_params.h | 282 ++ libs/ffmpeg/libavutil/fixed_dsp.c | 173 + libs/ffmpeg/libavutil/fixed_dsp.h | 205 + libs/ffmpeg/libavutil/float2half.c | 55 + libs/ffmpeg/libavutil/float2half.h | 56 + libs/ffmpeg/libavutil/float_dsp.c | 168 + libs/ffmpeg/libavutil/float_dsp.h | 246 + libs/ffmpeg/libavutil/float_scalarproduct.c | 32 + libs/ffmpeg/libavutil/frame.c | 830 ++++ libs/ffmpeg/libavutil/frame.h | 1176 +++++ libs/ffmpeg/libavutil/half2float.c | 67 + libs/ffmpeg/libavutil/half2float.h | 57 + libs/ffmpeg/libavutil/hash.c | 253 ++ libs/ffmpeg/libavutil/hash.h | 264 ++ libs/ffmpeg/libavutil/hdr_dynamic_metadata.c | 397 ++ libs/ffmpeg/libavutil/hdr_dynamic_metadata.h | 376 ++ .../libavutil/hdr_dynamic_vivid_metadata.c | 47 + .../libavutil/hdr_dynamic_vivid_metadata.h | 292 ++ libs/ffmpeg/libavutil/hmac.c | 206 + libs/ffmpeg/libavutil/hmac.h | 99 + libs/ffmpeg/libavutil/hwcontext.c | 952 ++++ libs/ffmpeg/libavutil/hwcontext.h | 601 +++ libs/ffmpeg/libavutil/hwcontext_internal.h | 169 + libs/ffmpeg/libavutil/iamf.c | 565 +++ libs/ffmpeg/libavutil/iamf.h | 697 +++ libs/ffmpeg/libavutil/imgutils.c | 717 +++ libs/ffmpeg/libavutil/imgutils.h | 377 ++ libs/ffmpeg/libavutil/imgutils_internal.h | 34 + libs/ffmpeg/libavutil/integer.c | 166 + libs/ffmpeg/libavutil/integer.h | 86 + libs/ffmpeg/libavutil/internal.h | 153 + libs/ffmpeg/libavutil/intfloat.h | 77 + libs/ffmpeg/libavutil/intmath.c | 34 + libs/ffmpeg/libavutil/intmath.h | 164 + libs/ffmpeg/libavutil/intreadwrite.h | 677 +++ libs/ffmpeg/libavutil/lfg.c | 87 + libs/ffmpeg/libavutil/lfg.h | 81 + libs/ffmpeg/libavutil/libm.h | 473 ++ libs/ffmpeg/libavutil/lls.c | 120 + libs/ffmpeg/libavutil/lls.h | 64 + libs/ffmpeg/libavutil/log.c | 527 +++ libs/ffmpeg/libavutil/log.h | 427 ++ libs/ffmpeg/libavutil/log2_tab.c | 32 + libs/ffmpeg/libavutil/loongarch/cpu.h | 31 + libs/ffmpeg/libavutil/lzo.c | 207 + libs/ffmpeg/libavutil/lzo.h | 66 + libs/ffmpeg/libavutil/macros.h | 80 + .../libavutil/mastering_display_metadata.c | 93 + .../libavutil/mastering_display_metadata.h | 137 + libs/ffmpeg/libavutil/mathematics.c | 319 ++ libs/ffmpeg/libavutil/mathematics.h | 300 ++ libs/ffmpeg/libavutil/md5.c | 210 + libs/ffmpeg/libavutil/md5.h | 89 + libs/ffmpeg/libavutil/mem.c | 570 +++ libs/ffmpeg/libavutil/mem.h | 607 +++ libs/ffmpeg/libavutil/mem_internal.h | 136 + libs/ffmpeg/libavutil/murmur3.c | 158 + libs/ffmpeg/libavutil/murmur3.h | 115 + libs/ffmpeg/libavutil/opt.c | 2803 ++++++++++++ libs/ffmpeg/libavutil/opt.h | 1194 +++++ libs/ffmpeg/libavutil/parseutils.c | 793 ++++ libs/ffmpeg/libavutil/parseutils.h | 197 + libs/ffmpeg/libavutil/pixdesc.c | 3938 +++++++++++++++++ libs/ffmpeg/libavutil/pixdesc.h | 450 ++ libs/ffmpeg/libavutil/pixelutils.c | 95 + libs/ffmpeg/libavutil/pixelutils.h | 51 + libs/ffmpeg/libavutil/pixfmt.h | 817 ++++ libs/ffmpeg/libavutil/ppc/cpu.h | 29 + libs/ffmpeg/libavutil/qsort.h | 122 + libs/ffmpeg/libavutil/random_seed.c | 204 + libs/ffmpeg/libavutil/random_seed.h | 57 + libs/ffmpeg/libavutil/rational.c | 191 + libs/ffmpeg/libavutil/rational.h | 225 + libs/ffmpeg/libavutil/rc4.c | 66 + libs/ffmpeg/libavutil/rc4.h | 69 + libs/ffmpeg/libavutil/refstruct.c | 386 ++ libs/ffmpeg/libavutil/refstruct.h | 297 ++ libs/ffmpeg/libavutil/reverse.c | 40 + libs/ffmpeg/libavutil/reverse.h | 28 + libs/ffmpeg/libavutil/ripemd.c | 559 +++ libs/ffmpeg/libavutil/ripemd.h | 83 + libs/ffmpeg/libavutil/samplefmt.c | 263 ++ libs/ffmpeg/libavutil/samplefmt.h | 268 ++ libs/ffmpeg/libavutil/sfc64.h | 84 + libs/ffmpeg/libavutil/sha.c | 358 ++ libs/ffmpeg/libavutil/sha.h | 90 + libs/ffmpeg/libavutil/sha512.c | 289 ++ libs/ffmpeg/libavutil/sha512.h | 92 + libs/ffmpeg/libavutil/side_data.c | 315 ++ libs/ffmpeg/libavutil/side_data.h | 30 + libs/ffmpeg/libavutil/slicethread.c | 281 ++ libs/ffmpeg/libavutil/slicethread.h | 52 + libs/ffmpeg/libavutil/spherical.c | 86 + libs/ffmpeg/libavutil/spherical.h | 249 ++ libs/ffmpeg/libavutil/stereo3d.c | 151 + libs/ffmpeg/libavutil/stereo3d.h | 325 ++ libs/ffmpeg/libavutil/tdrdi.c | 51 + libs/ffmpeg/libavutil/tdrdi.h | 164 + libs/ffmpeg/libavutil/tea.c | 121 + libs/ffmpeg/libavutil/tea.h | 71 + libs/ffmpeg/libavutil/thread.h | 241 + libs/ffmpeg/libavutil/threadmessage.c | 240 + libs/ffmpeg/libavutil/threadmessage.h | 115 + libs/ffmpeg/libavutil/time.c | 98 + libs/ffmpeg/libavutil/time.h | 56 + libs/ffmpeg/libavutil/time_internal.h | 49 + libs/ffmpeg/libavutil/timecode.c | 254 ++ libs/ffmpeg/libavutil/timecode.h | 199 + libs/ffmpeg/libavutil/timecode_internal.c | 51 + libs/ffmpeg/libavutil/timecode_internal.h | 51 + libs/ffmpeg/libavutil/timer.h | 169 + libs/ffmpeg/libavutil/timestamp.c | 36 + libs/ffmpeg/libavutil/timestamp.h | 85 + libs/ffmpeg/libavutil/tree.c | 168 + libs/ffmpeg/libavutil/tree.h | 137 + libs/ffmpeg/libavutil/twofish.c | 335 ++ libs/ffmpeg/libavutil/twofish.h | 70 + libs/ffmpeg/libavutil/tx.c | 939 ++++ libs/ffmpeg/libavutil/tx.h | 210 + libs/ffmpeg/libavutil/tx_double.c | 21 + libs/ffmpeg/libavutil/tx_float.c | 21 + libs/ffmpeg/libavutil/tx_int32.c | 21 + libs/ffmpeg/libavutil/tx_priv.h | 392 ++ libs/ffmpeg/libavutil/tx_template.c | 2208 +++++++++ libs/ffmpeg/libavutil/utils.c | 115 + libs/ffmpeg/libavutil/uuid.c | 142 + libs/ffmpeg/libavutil/uuid.h | 146 + libs/ffmpeg/libavutil/version.c | 56 + libs/ffmpeg/libavutil/version.h | 123 + libs/ffmpeg/libavutil/version_major.h | 25 + libs/ffmpeg/libavutil/video_enc_params.c | 80 + libs/ffmpeg/libavutil/video_enc_params.h | 171 + libs/ffmpeg/libavutil/video_hint.c | 81 + libs/ffmpeg/libavutil/video_hint.h | 107 + libs/ffmpeg/libavutil/wchar_filename.h | 281 ++ libs/ffmpeg/libavutil/x86/asm.h | 153 + libs/ffmpeg/libavutil/x86/bswap.h | 79 + libs/ffmpeg/libavutil/x86/cpu.h | 107 + libs/ffmpeg/libavutil/x86/crc.h | 223 + libs/ffmpeg/libavutil/x86/intmath.h | 119 + libs/ffmpeg/libavutil/x86/intreadwrite.h | 56 + libs/ffmpeg/libavutil/x86/pixelutils.h | 26 + libs/ffmpeg/libavutil/x86/timer.h | 50 + libs/ffmpeg/libavutil/xga_font_data.c | 433 ++ libs/ffmpeg/libavutil/xga_font_data.h | 41 + libs/ffmpeg/libavutil/xtea.c | 253 ++ libs/ffmpeg/libavutil/xtea.h | 94 + libs/ffmpeg/libswresample/audioconvert.c | 251 ++ libs/ffmpeg/libswresample/audioconvert.h | 77 + libs/ffmpeg/libswresample/dither.c | 149 + libs/ffmpeg/libswresample/dither_template.c | 88 + libs/ffmpeg/libswresample/log2_tab.c | 1 + .../ffmpeg/libswresample/noise_shaping_data.c | 224 + libs/ffmpeg/libswresample/options.c | 156 + libs/ffmpeg/libswresample/rematrix.c | 649 +++ libs/ffmpeg/libswresample/rematrix_template.c | 137 + libs/ffmpeg/libswresample/resample.c | 513 +++ libs/ffmpeg/libswresample/resample.h | 68 + libs/ffmpeg/libswresample/resample_dsp.c | 78 + libs/ffmpeg/libswresample/resample_template.c | 223 + libs/ffmpeg/libswresample/swresample.c | 961 ++++ libs/ffmpeg/libswresample/swresample.h | 587 +++ libs/ffmpeg/libswresample/swresample_frame.c | 174 + .../libswresample/swresample_internal.h | 232 + libs/ffmpeg/libswresample/swresampleres.rc | 55 + libs/ffmpeg/libswresample/version.c | 45 + libs/ffmpeg/libswresample/version.h | 46 + libs/ffmpeg/libswresample/version_major.h | 31 + libs/ffmpeg/libswscale/alphablend.c | 177 + libs/ffmpeg/libswscale/bayer_template.c | 342 ++ libs/ffmpeg/libswscale/cms.c | 766 ++++ libs/ffmpeg/libswscale/cms.h | 105 + libs/ffmpeg/libswscale/csputils.c | 405 ++ libs/ffmpeg/libswscale/csputils.h | 113 + libs/ffmpeg/libswscale/format.c | 1522 +++++++ libs/ffmpeg/libswscale/format.h | 210 + libs/ffmpeg/libswscale/gamma.c | 72 + libs/ffmpeg/libswscale/graph.c | 921 ++++ libs/ffmpeg/libswscale/graph.h | 190 + libs/ffmpeg/libswscale/half2float.c | 19 + libs/ffmpeg/libswscale/hscale.c | 292 ++ libs/ffmpeg/libswscale/hscale_fast_bilinear.c | 55 + libs/ffmpeg/libswscale/input.c | 2770 ++++++++++++ libs/ffmpeg/libswscale/log2_tab.c | 1 + libs/ffmpeg/libswscale/lut3d.c | 277 ++ libs/ffmpeg/libswscale/lut3d.h | 98 + libs/ffmpeg/libswscale/ops.c | 859 ++++ libs/ffmpeg/libswscale/ops.h | 318 ++ libs/ffmpeg/libswscale/ops_backend.c | 108 + libs/ffmpeg/libswscale/ops_backend.h | 162 + libs/ffmpeg/libswscale/ops_chain.c | 292 ++ libs/ffmpeg/libswscale/ops_chain.h | 141 + libs/ffmpeg/libswscale/ops_dispatch.c | 395 ++ libs/ffmpeg/libswscale/ops_dispatch.h | 94 + libs/ffmpeg/libswscale/ops_internal.h | 120 + libs/ffmpeg/libswscale/ops_memcpy.c | 134 + libs/ffmpeg/libswscale/ops_optimizer.c | 778 ++++ libs/ffmpeg/libswscale/ops_tmpl_common.c | 205 + libs/ffmpeg/libswscale/ops_tmpl_float.c | 272 ++ libs/ffmpeg/libswscale/ops_tmpl_int.c | 600 +++ libs/ffmpeg/libswscale/options.c | 110 + libs/ffmpeg/libswscale/output.c | 3885 ++++++++++++++++ libs/ffmpeg/libswscale/rgb2rgb.c | 471 ++ libs/ffmpeg/libswscale/rgb2rgb.h | 165 + libs/ffmpeg/libswscale/rgb2rgb_template.c | 877 ++++ libs/ffmpeg/libswscale/slice.c | 402 ++ libs/ffmpeg/libswscale/swscale.c | 1572 +++++++ libs/ffmpeg/libswscale/swscale.h | 700 +++ libs/ffmpeg/libswscale/swscale_internal.h | 1200 +++++ libs/ffmpeg/libswscale/swscale_unscaled.c | 2720 ++++++++++++ libs/ffmpeg/libswscale/utils.c | 2467 +++++++++++ libs/ffmpeg/libswscale/version.c | 42 + libs/ffmpeg/libswscale/version.h | 44 + libs/ffmpeg/libswscale/version_major.h | 35 + libs/ffmpeg/libswscale/vscale.c | 321 ++ libs/ffmpeg/libswscale/yuv2rgb.c | 963 ++++ 316 files changed, 100447 insertions(+), 1 deletion(-) create mode 100644 libs/ffmpeg/LICENSE.md create mode 100644 libs/ffmpeg/Makefile.in create mode 100644 libs/ffmpeg/VERSION create mode 100644 libs/ffmpeg/compat/va_copy.h create mode 100644 libs/ffmpeg/compat/w32pthreads.h create mode 100644 libs/ffmpeg/config.h create mode 100644 libs/ffmpeg/config_components.asm create mode 100644 libs/ffmpeg/config_components.h create mode 100644 libs/ffmpeg/libavcodec/defs.h create mode 100644 libs/ffmpeg/libavcodec/get_bits.h create mode 100644 libs/ffmpeg/libavcodec/mathops.h create mode 100644 libs/ffmpeg/libavcodec/put_bits.h create mode 100644 libs/ffmpeg/libavcodec/vlc.h create mode 100644 libs/ffmpeg/libavutil/aarch64/cpu.h create mode 100644 libs/ffmpeg/libavutil/aarch64/crc.h create mode 100644 libs/ffmpeg/libavutil/aarch64/intreadwrite.h create mode 100644 libs/ffmpeg/libavutil/aarch64/timer.h create mode 100644 libs/ffmpeg/libavutil/adler32.c create mode 100644 libs/ffmpeg/libavutil/adler32.h create mode 100644 libs/ffmpeg/libavutil/aes.c create mode 100644 libs/ffmpeg/libavutil/aes.h create mode 100644 libs/ffmpeg/libavutil/aes_ctr.c create mode 100644 libs/ffmpeg/libavutil/aes_ctr.h create mode 100644 libs/ffmpeg/libavutil/aes_internal.h create mode 100644 libs/ffmpeg/libavutil/ambient_viewing_environment.c create mode 100644 libs/ffmpeg/libavutil/ambient_viewing_environment.h create mode 100644 libs/ffmpeg/libavutil/arm/bswap.h create mode 100644 libs/ffmpeg/libavutil/arm/cpu.h create mode 100644 libs/ffmpeg/libavutil/arm/intmath.h create mode 100644 libs/ffmpeg/libavutil/arm/timer.h create mode 100644 libs/ffmpeg/libavutil/attributes.h create mode 100644 libs/ffmpeg/libavutil/attributes_internal.h create mode 100644 libs/ffmpeg/libavutil/audio_fifo.c create mode 100644 libs/ffmpeg/libavutil/audio_fifo.h create mode 100644 libs/ffmpeg/libavutil/avassert.h create mode 100644 libs/ffmpeg/libavutil/avconfig.h create mode 100644 libs/ffmpeg/libavutil/avsscanf.c create mode 100644 libs/ffmpeg/libavutil/avstring.c create mode 100644 libs/ffmpeg/libavutil/avstring.h create mode 100644 libs/ffmpeg/libavutil/avutil.h create mode 100644 libs/ffmpeg/libavutil/base64.c create mode 100644 libs/ffmpeg/libavutil/base64.h create mode 100644 libs/ffmpeg/libavutil/blowfish.c create mode 100644 libs/ffmpeg/libavutil/blowfish.h create mode 100644 libs/ffmpeg/libavutil/bprint.c create mode 100644 libs/ffmpeg/libavutil/bprint.h create mode 100644 libs/ffmpeg/libavutil/bswap.h create mode 100644 libs/ffmpeg/libavutil/buffer.c create mode 100644 libs/ffmpeg/libavutil/buffer.h create mode 100644 libs/ffmpeg/libavutil/buffer_internal.h create mode 100644 libs/ffmpeg/libavutil/camellia.c create mode 100644 libs/ffmpeg/libavutil/camellia.h create mode 100644 libs/ffmpeg/libavutil/cast5.c create mode 100644 libs/ffmpeg/libavutil/cast5.h create mode 100644 libs/ffmpeg/libavutil/channel_layout.c create mode 100644 libs/ffmpeg/libavutil/channel_layout.h create mode 100644 libs/ffmpeg/libavutil/common.h create mode 100644 libs/ffmpeg/libavutil/container_fifo.c create mode 100644 libs/ffmpeg/libavutil/container_fifo.h create mode 100644 libs/ffmpeg/libavutil/cpu.c create mode 100644 libs/ffmpeg/libavutil/cpu.h create mode 100644 libs/ffmpeg/libavutil/cpu_internal.h create mode 100644 libs/ffmpeg/libavutil/crc.c create mode 100644 libs/ffmpeg/libavutil/crc.h create mode 100644 libs/ffmpeg/libavutil/csp.c create mode 100644 libs/ffmpeg/libavutil/csp.h create mode 100644 libs/ffmpeg/libavutil/des.c create mode 100644 libs/ffmpeg/libavutil/des.h create mode 100644 libs/ffmpeg/libavutil/detection_bbox.c create mode 100644 libs/ffmpeg/libavutil/detection_bbox.h create mode 100644 libs/ffmpeg/libavutil/dict.c create mode 100644 libs/ffmpeg/libavutil/dict.h create mode 100644 libs/ffmpeg/libavutil/display.c create mode 100644 libs/ffmpeg/libavutil/display.h create mode 100644 libs/ffmpeg/libavutil/dovi_meta.c create mode 100644 libs/ffmpeg/libavutil/dovi_meta.h create mode 100644 libs/ffmpeg/libavutil/downmix_info.c create mode 100644 libs/ffmpeg/libavutil/downmix_info.h create mode 100644 libs/ffmpeg/libavutil/dynarray.h create mode 100644 libs/ffmpeg/libavutil/emms.h create mode 100644 libs/ffmpeg/libavutil/encryption_info.c create mode 100644 libs/ffmpeg/libavutil/encryption_info.h create mode 100644 libs/ffmpeg/libavutil/error.c create mode 100644 libs/ffmpeg/libavutil/error.h create mode 100644 libs/ffmpeg/libavutil/eval.c create mode 100644 libs/ffmpeg/libavutil/eval.h create mode 100644 libs/ffmpeg/libavutil/executor.c create mode 100644 libs/ffmpeg/libavutil/executor.h create mode 100644 libs/ffmpeg/libavutil/ffmath.h create mode 100644 libs/ffmpeg/libavutil/ffversion.h create mode 100644 libs/ffmpeg/libavutil/fifo.c create mode 100644 libs/ffmpeg/libavutil/fifo.h create mode 100644 libs/ffmpeg/libavutil/file.c create mode 100644 libs/ffmpeg/libavutil/file.h create mode 100644 libs/ffmpeg/libavutil/file_open.c create mode 100644 libs/ffmpeg/libavutil/file_open.h create mode 100644 libs/ffmpeg/libavutil/film_grain_params.c create mode 100644 libs/ffmpeg/libavutil/film_grain_params.h create mode 100644 libs/ffmpeg/libavutil/fixed_dsp.c create mode 100644 libs/ffmpeg/libavutil/fixed_dsp.h create mode 100644 libs/ffmpeg/libavutil/float2half.c create mode 100644 libs/ffmpeg/libavutil/float2half.h create mode 100644 libs/ffmpeg/libavutil/float_dsp.c create mode 100644 libs/ffmpeg/libavutil/float_dsp.h create mode 100644 libs/ffmpeg/libavutil/float_scalarproduct.c create mode 100644 libs/ffmpeg/libavutil/frame.c create mode 100644 libs/ffmpeg/libavutil/frame.h create mode 100644 libs/ffmpeg/libavutil/half2float.c create mode 100644 libs/ffmpeg/libavutil/half2float.h create mode 100644 libs/ffmpeg/libavutil/hash.c create mode 100644 libs/ffmpeg/libavutil/hash.h create mode 100644 libs/ffmpeg/libavutil/hdr_dynamic_metadata.c create mode 100644 libs/ffmpeg/libavutil/hdr_dynamic_metadata.h create mode 100644 libs/ffmpeg/libavutil/hdr_dynamic_vivid_metadata.c create mode 100644 libs/ffmpeg/libavutil/hdr_dynamic_vivid_metadata.h create mode 100644 libs/ffmpeg/libavutil/hmac.c create mode 100644 libs/ffmpeg/libavutil/hmac.h create mode 100644 libs/ffmpeg/libavutil/hwcontext.c create mode 100644 libs/ffmpeg/libavutil/hwcontext.h create mode 100644 libs/ffmpeg/libavutil/hwcontext_internal.h create mode 100644 libs/ffmpeg/libavutil/iamf.c create mode 100644 libs/ffmpeg/libavutil/iamf.h create mode 100644 libs/ffmpeg/libavutil/imgutils.c create mode 100644 libs/ffmpeg/libavutil/imgutils.h create mode 100644 libs/ffmpeg/libavutil/imgutils_internal.h create mode 100644 libs/ffmpeg/libavutil/integer.c create mode 100644 libs/ffmpeg/libavutil/integer.h create mode 100644 libs/ffmpeg/libavutil/internal.h create mode 100644 libs/ffmpeg/libavutil/intfloat.h create mode 100644 libs/ffmpeg/libavutil/intmath.c create mode 100644 libs/ffmpeg/libavutil/intmath.h create mode 100644 libs/ffmpeg/libavutil/intreadwrite.h create mode 100644 libs/ffmpeg/libavutil/lfg.c create mode 100644 libs/ffmpeg/libavutil/lfg.h create mode 100644 libs/ffmpeg/libavutil/libm.h create mode 100644 libs/ffmpeg/libavutil/lls.c create mode 100644 libs/ffmpeg/libavutil/lls.h create mode 100644 libs/ffmpeg/libavutil/log.c create mode 100644 libs/ffmpeg/libavutil/log.h create mode 100644 libs/ffmpeg/libavutil/log2_tab.c create mode 100644 libs/ffmpeg/libavutil/loongarch/cpu.h create mode 100644 libs/ffmpeg/libavutil/lzo.c create mode 100644 libs/ffmpeg/libavutil/lzo.h create mode 100644 libs/ffmpeg/libavutil/macros.h create mode 100644 libs/ffmpeg/libavutil/mastering_display_metadata.c create mode 100644 libs/ffmpeg/libavutil/mastering_display_metadata.h create mode 100644 libs/ffmpeg/libavutil/mathematics.c create mode 100644 libs/ffmpeg/libavutil/mathematics.h create mode 100644 libs/ffmpeg/libavutil/md5.c create mode 100644 libs/ffmpeg/libavutil/md5.h create mode 100644 libs/ffmpeg/libavutil/mem.c create mode 100644 libs/ffmpeg/libavutil/mem.h create mode 100644 libs/ffmpeg/libavutil/mem_internal.h create mode 100644 libs/ffmpeg/libavutil/murmur3.c create mode 100644 libs/ffmpeg/libavutil/murmur3.h create mode 100644 libs/ffmpeg/libavutil/opt.c create mode 100644 libs/ffmpeg/libavutil/opt.h create mode 100644 libs/ffmpeg/libavutil/parseutils.c create mode 100644 libs/ffmpeg/libavutil/parseutils.h create mode 100644 libs/ffmpeg/libavutil/pixdesc.c create mode 100644 libs/ffmpeg/libavutil/pixdesc.h create mode 100644 libs/ffmpeg/libavutil/pixelutils.c create mode 100644 libs/ffmpeg/libavutil/pixelutils.h create mode 100644 libs/ffmpeg/libavutil/pixfmt.h create mode 100644 libs/ffmpeg/libavutil/ppc/cpu.h create mode 100644 libs/ffmpeg/libavutil/qsort.h create mode 100644 libs/ffmpeg/libavutil/random_seed.c create mode 100644 libs/ffmpeg/libavutil/random_seed.h create mode 100644 libs/ffmpeg/libavutil/rational.c create mode 100644 libs/ffmpeg/libavutil/rational.h create mode 100644 libs/ffmpeg/libavutil/rc4.c create mode 100644 libs/ffmpeg/libavutil/rc4.h create mode 100644 libs/ffmpeg/libavutil/refstruct.c create mode 100644 libs/ffmpeg/libavutil/refstruct.h create mode 100644 libs/ffmpeg/libavutil/reverse.c create mode 100644 libs/ffmpeg/libavutil/reverse.h create mode 100644 libs/ffmpeg/libavutil/ripemd.c create mode 100644 libs/ffmpeg/libavutil/ripemd.h create mode 100644 libs/ffmpeg/libavutil/samplefmt.c create mode 100644 libs/ffmpeg/libavutil/samplefmt.h create mode 100644 libs/ffmpeg/libavutil/sfc64.h create mode 100644 libs/ffmpeg/libavutil/sha.c create mode 100644 libs/ffmpeg/libavutil/sha.h create mode 100644 libs/ffmpeg/libavutil/sha512.c create mode 100644 libs/ffmpeg/libavutil/sha512.h create mode 100644 libs/ffmpeg/libavutil/side_data.c create mode 100644 libs/ffmpeg/libavutil/side_data.h create mode 100644 libs/ffmpeg/libavutil/slicethread.c create mode 100644 libs/ffmpeg/libavutil/slicethread.h create mode 100644 libs/ffmpeg/libavutil/spherical.c create mode 100644 libs/ffmpeg/libavutil/spherical.h create mode 100644 libs/ffmpeg/libavutil/stereo3d.c create mode 100644 libs/ffmpeg/libavutil/stereo3d.h create mode 100644 libs/ffmpeg/libavutil/tdrdi.c create mode 100644 libs/ffmpeg/libavutil/tdrdi.h create mode 100644 libs/ffmpeg/libavutil/tea.c create mode 100644 libs/ffmpeg/libavutil/tea.h create mode 100644 libs/ffmpeg/libavutil/thread.h create mode 100644 libs/ffmpeg/libavutil/threadmessage.c create mode 100644 libs/ffmpeg/libavutil/threadmessage.h create mode 100644 libs/ffmpeg/libavutil/time.c create mode 100644 libs/ffmpeg/libavutil/time.h create mode 100644 libs/ffmpeg/libavutil/time_internal.h create mode 100644 libs/ffmpeg/libavutil/timecode.c create mode 100644 libs/ffmpeg/libavutil/timecode.h create mode 100644 libs/ffmpeg/libavutil/timecode_internal.c create mode 100644 libs/ffmpeg/libavutil/timecode_internal.h create mode 100644 libs/ffmpeg/libavutil/timer.h create mode 100644 libs/ffmpeg/libavutil/timestamp.c create mode 100644 libs/ffmpeg/libavutil/timestamp.h create mode 100644 libs/ffmpeg/libavutil/tree.c create mode 100644 libs/ffmpeg/libavutil/tree.h create mode 100644 libs/ffmpeg/libavutil/twofish.c create mode 100644 libs/ffmpeg/libavutil/twofish.h create mode 100644 libs/ffmpeg/libavutil/tx.c create mode 100644 libs/ffmpeg/libavutil/tx.h create mode 100644 libs/ffmpeg/libavutil/tx_double.c create mode 100644 libs/ffmpeg/libavutil/tx_float.c create mode 100644 libs/ffmpeg/libavutil/tx_int32.c create mode 100644 libs/ffmpeg/libavutil/tx_priv.h create mode 100644 libs/ffmpeg/libavutil/tx_template.c create mode 100644 libs/ffmpeg/libavutil/utils.c create mode 100644 libs/ffmpeg/libavutil/uuid.c create mode 100644 libs/ffmpeg/libavutil/uuid.h create mode 100644 libs/ffmpeg/libavutil/version.c create mode 100644 libs/ffmpeg/libavutil/version.h create mode 100644 libs/ffmpeg/libavutil/version_major.h create mode 100644 libs/ffmpeg/libavutil/video_enc_params.c create mode 100644 libs/ffmpeg/libavutil/video_enc_params.h create mode 100644 libs/ffmpeg/libavutil/video_hint.c create mode 100644 libs/ffmpeg/libavutil/video_hint.h create mode 100644 libs/ffmpeg/libavutil/wchar_filename.h create mode 100644 libs/ffmpeg/libavutil/x86/asm.h create mode 100644 libs/ffmpeg/libavutil/x86/bswap.h create mode 100644 libs/ffmpeg/libavutil/x86/cpu.h create mode 100644 libs/ffmpeg/libavutil/x86/crc.h create mode 100644 libs/ffmpeg/libavutil/x86/intmath.h create mode 100644 libs/ffmpeg/libavutil/x86/intreadwrite.h create mode 100644 libs/ffmpeg/libavutil/x86/pixelutils.h create mode 100644 libs/ffmpeg/libavutil/x86/timer.h create mode 100644 libs/ffmpeg/libavutil/xga_font_data.c create mode 100644 libs/ffmpeg/libavutil/xga_font_data.h create mode 100644 libs/ffmpeg/libavutil/xtea.c create mode 100644 libs/ffmpeg/libavutil/xtea.h create mode 100644 libs/ffmpeg/libswresample/audioconvert.c create mode 100644 libs/ffmpeg/libswresample/audioconvert.h create mode 100644 libs/ffmpeg/libswresample/dither.c create mode 100644 libs/ffmpeg/libswresample/dither_template.c create mode 100644 libs/ffmpeg/libswresample/log2_tab.c create mode 100644 libs/ffmpeg/libswresample/noise_shaping_data.c create mode 100644 libs/ffmpeg/libswresample/options.c create mode 100644 libs/ffmpeg/libswresample/rematrix.c create mode 100644 libs/ffmpeg/libswresample/rematrix_template.c create mode 100644 libs/ffmpeg/libswresample/resample.c create mode 100644 libs/ffmpeg/libswresample/resample.h create mode 100644 libs/ffmpeg/libswresample/resample_dsp.c create mode 100644 libs/ffmpeg/libswresample/resample_template.c create mode 100644 libs/ffmpeg/libswresample/swresample.c create mode 100644 libs/ffmpeg/libswresample/swresample.h create mode 100644 libs/ffmpeg/libswresample/swresample_frame.c create mode 100644 libs/ffmpeg/libswresample/swresample_internal.h create mode 100644 libs/ffmpeg/libswresample/swresampleres.rc create mode 100644 libs/ffmpeg/libswresample/version.c create mode 100644 libs/ffmpeg/libswresample/version.h create mode 100644 libs/ffmpeg/libswresample/version_major.h create mode 100644 libs/ffmpeg/libswscale/alphablend.c create mode 100644 libs/ffmpeg/libswscale/bayer_template.c create mode 100644 libs/ffmpeg/libswscale/cms.c create mode 100644 libs/ffmpeg/libswscale/cms.h create mode 100644 libs/ffmpeg/libswscale/csputils.c create mode 100644 libs/ffmpeg/libswscale/csputils.h create mode 100644 libs/ffmpeg/libswscale/format.c create mode 100644 libs/ffmpeg/libswscale/format.h create mode 100644 libs/ffmpeg/libswscale/gamma.c create mode 100644 libs/ffmpeg/libswscale/graph.c create mode 100644 libs/ffmpeg/libswscale/graph.h create mode 100644 libs/ffmpeg/libswscale/half2float.c create mode 100644 libs/ffmpeg/libswscale/hscale.c create mode 100644 libs/ffmpeg/libswscale/hscale_fast_bilinear.c create mode 100644 libs/ffmpeg/libswscale/input.c create mode 100644 libs/ffmpeg/libswscale/log2_tab.c create mode 100644 libs/ffmpeg/libswscale/lut3d.c create mode 100644 libs/ffmpeg/libswscale/lut3d.h create mode 100644 libs/ffmpeg/libswscale/ops.c create mode 100644 libs/ffmpeg/libswscale/ops.h create mode 100644 libs/ffmpeg/libswscale/ops_backend.c create mode 100644 libs/ffmpeg/libswscale/ops_backend.h create mode 100644 libs/ffmpeg/libswscale/ops_chain.c create mode 100644 libs/ffmpeg/libswscale/ops_chain.h create mode 100644 libs/ffmpeg/libswscale/ops_dispatch.c create mode 100644 libs/ffmpeg/libswscale/ops_dispatch.h create mode 100644 libs/ffmpeg/libswscale/ops_internal.h create mode 100644 libs/ffmpeg/libswscale/ops_memcpy.c create mode 100644 libs/ffmpeg/libswscale/ops_optimizer.c create mode 100644 libs/ffmpeg/libswscale/ops_tmpl_common.c create mode 100644 libs/ffmpeg/libswscale/ops_tmpl_float.c create mode 100644 libs/ffmpeg/libswscale/ops_tmpl_int.c create mode 100644 libs/ffmpeg/libswscale/options.c create mode 100644 libs/ffmpeg/libswscale/output.c create mode 100644 libs/ffmpeg/libswscale/rgb2rgb.c create mode 100644 libs/ffmpeg/libswscale/rgb2rgb.h create mode 100644 libs/ffmpeg/libswscale/rgb2rgb_template.c create mode 100644 libs/ffmpeg/libswscale/slice.c create mode 100644 libs/ffmpeg/libswscale/swscale.c create mode 100644 libs/ffmpeg/libswscale/swscale.h create mode 100644 libs/ffmpeg/libswscale/swscale_internal.h create mode 100644 libs/ffmpeg/libswscale/swscale_unscaled.c create mode 100644 libs/ffmpeg/libswscale/utils.c create mode 100644 libs/ffmpeg/libswscale/version.c create mode 100644 libs/ffmpeg/libswscale/version.h create mode 100644 libs/ffmpeg/libswscale/version_major.h create mode 100644 libs/ffmpeg/libswscale/vscale.c create mode 100644 libs/ffmpeg/libswscale/yuv2rgb.c diff --git a/NOTICES.md b/NOTICES.md index 563d4f5414b..11a5b22f0c4 100644 --- a/NOTICES.md +++ b/NOTICES.md @@ -219,6 +219,15 @@ This algorithm is free of patents or of copyrights, as confirmed by Peter Shirle ``` +### FFmpeg +``` +Most files in FFmpeg are under the GNU Lesser General Public License version 2.1 +or later (LGPL v2.1+). Read the file `COPYING.LGPLv2.1` for details. Some other +files have MIT/X11/BSD-style licenses. In combination the LGPL v2.1+ applies to +FFmpeg. +``` + + ### FluidSynth ``` The source code for FluidSynth is distributed under the terms of the diff --git a/configure b/configure index bfef736053b..48c4e1b3cd1 100755 --- a/configure +++ b/configure @@ -736,6 +736,8 @@ GSM_PE_LIBS GSM_PE_CFLAGS FLUIDSYNTH_PE_LIBS FLUIDSYNTH_PE_CFLAGS +FFMPEG_PE_LIBS +FFMPEG_PE_CFLAGS FAUDIO_PE_LIBS FAUDIO_PE_CFLAGS CXXABI_PE_LIBS @@ -1675,6 +1677,7 @@ enable_dxerr8 enable_dxerr9 enable_dxguid enable_faudio +enable_ffmpeg enable_fluidsynth enable_gsm enable_icucommon @@ -1851,6 +1854,8 @@ CXXABI_PE_CFLAGS CXXABI_PE_LIBS FAUDIO_PE_CFLAGS FAUDIO_PE_LIBS +FFMPEG_PE_CFLAGS +FFMPEG_PE_LIBS FLUIDSYNTH_PE_CFLAGS FLUIDSYNTH_PE_LIBS GSM_PE_CFLAGS @@ -2670,6 +2675,11 @@ Some influential environment variables: version FAUDIO_PE_LIBS Linker flags for the PE faudio, overriding the bundled version + FFMPEG_PE_CFLAGS + C compiler flags for the PE ffmpeg, overriding the bundled + version + FFMPEG_PE_LIBS + Linker flags for the PE ffmpeg, overriding the bundled version FLUIDSYNTH_PE_CFLAGS C compiler flags for the PE fluidsynth, overriding the bundled version @@ -14443,6 +14453,23 @@ fi printf '%s\n' "$as_me:${as_lineno-$LINENO}: faudio cflags: $FAUDIO_PE_CFLAGS" >&5 printf '%s\n' "$as_me:${as_lineno-$LINENO}: faudio libs: $FAUDIO_PE_LIBS" >&5 +if ${FFMPEG_PE_LIBS:+false} : +then : + FFMPEG_PE_LIBS="ffmpeg bcrypt" + if ${FFMPEG_PE_CFLAGS:+false} : +then : + FFMPEG_PE_CFLAGS="-I\$(top_srcdir)/libs/ffmpeg" +else case e in #( + e) enable_ffmpeg=no ;; +esac +fi +else case e in #( + e) enable_ffmpeg=no ;; +esac +fi +printf '%s\n' "$as_me:${as_lineno-$LINENO}: ffmpeg cflags: $FFMPEG_PE_CFLAGS" >&5 +printf '%s\n' "$as_me:${as_lineno-$LINENO}: ffmpeg libs: $FFMPEG_PE_LIBS" >&5 + if ${FLUIDSYNTH_PE_LIBS:+false} : then : FLUIDSYNTH_PE_LIBS="fluidsynth" @@ -23782,6 +23809,7 @@ wine_fn_config_makefile libs/dxerr8 enable_dxerr8 wine_fn_config_makefile libs/dxerr9 enable_dxerr9 wine_fn_config_makefile libs/dxguid enable_dxguid wine_fn_config_makefile libs/faudio enable_faudio +wine_fn_config_makefile libs/ffmpeg enable_ffmpeg wine_fn_config_makefile libs/fluidsynth enable_fluidsynth wine_fn_config_makefile libs/gsm enable_gsm wine_fn_config_makefile libs/icucommon enable_icucommon @@ -24026,7 +24054,7 @@ dlls/wineandroid.drv/wine-debug.apk: dlls/wineandroid.drv/build.gradle ${wine_sr mv dlls/wineandroid.drv/build/outputs/apk/debug/wine-debug.apk \$@" -EXTERNAL_SUBDIRS="libs/capstone libs/c++ libs/c++abi libs/faudio libs/fluidsynth libs/gsm libs/icucommon libs/icui18n libs/jpeg libs/jxr libs/lcms2 libs/ldap libs/mpg123 libs/musl libs/png libs/sqlite3 libs/symcrypt libs/tiff libs/unwind libs/vkd3d libs/xml2 libs/xslt libs/zlib libs/compiler-rt" +EXTERNAL_SUBDIRS="libs/capstone libs/c++ libs/c++abi libs/faudio libs/ffmpeg libs/fluidsynth libs/gsm libs/icucommon libs/icui18n libs/jpeg libs/jxr libs/lcms2 libs/ldap libs/mpg123 libs/musl libs/png libs/sqlite3 libs/symcrypt libs/tiff libs/unwind libs/vkd3d libs/xml2 libs/xslt libs/zlib libs/compiler-rt" TAGSFLAGS="--langmap='c:+.idl.l.rh,make:(Make*.in)'" @@ -24877,6 +24905,8 @@ CXXABI_PE_CFLAGS = $CXXABI_PE_CFLAGS CXXABI_PE_LIBS = $CXXABI_PE_LIBS FAUDIO_PE_CFLAGS = $FAUDIO_PE_CFLAGS FAUDIO_PE_LIBS = $FAUDIO_PE_LIBS +FFMPEG_PE_CFLAGS = $FFMPEG_PE_CFLAGS +FFMPEG_PE_LIBS = $FFMPEG_PE_LIBS FLUIDSYNTH_PE_CFLAGS = $FLUIDSYNTH_PE_CFLAGS FLUIDSYNTH_PE_LIBS = $FLUIDSYNTH_PE_LIBS GSM_PE_CFLAGS = $GSM_PE_CFLAGS diff --git a/configure.ac b/configure.ac index d597bad3750..9644b1ccca4 100644 --- a/configure.ac +++ b/configure.ac @@ -1226,6 +1226,7 @@ WINE_EXTLIB_FLAGS(CAPSTONE, capstone, capstone, "-I\$(top_srcdir)/libs/capstone/ WINE_EXTLIB_FLAGS(CXX, c++, "c++ \$(CXXABI_PE_LIBS) msvcp140 vcruntime140") WINE_EXTLIB_FLAGS(CXXABI, c++abi, "c++abi \$(UNWIND_PE_LIBS) c++", "-I\$(top_srcdir)/libs/c++abi/include") WINE_EXTLIB_FLAGS(FAUDIO, faudio, "faudio mfplat mfreadwrite mfuuid propsys", "-I\$(top_srcdir)/libs/faudio/include") +WINE_EXTLIB_FLAGS(FFMPEG, ffmpeg, "ffmpeg bcrypt", "-I\$(top_srcdir)/libs/ffmpeg") WINE_EXTLIB_FLAGS(FLUIDSYNTH, fluidsynth, "fluidsynth", "-I\$(top_srcdir)/libs/fluidsynth/include") WINE_EXTLIB_FLAGS(GSM, gsm, gsm, "-I\$(top_srcdir)/libs/gsm/inc") WINE_EXTLIB_FLAGS(ICUCOMMON, icucommon, icucommon, "-I\$(top_srcdir)/libs/icucommon") @@ -3517,6 +3518,7 @@ WINE_CONFIG_MAKEFILE(libs/dxerr8) WINE_CONFIG_MAKEFILE(libs/dxerr9) WINE_CONFIG_MAKEFILE(libs/dxguid) WINE_CONFIG_MAKEFILE(libs/faudio) +WINE_CONFIG_MAKEFILE(libs/ffmpeg) WINE_CONFIG_MAKEFILE(libs/fluidsynth) WINE_CONFIG_MAKEFILE(libs/gsm) WINE_CONFIG_MAKEFILE(libs/icucommon) diff --git a/libs/ffmpeg/LICENSE.md b/libs/ffmpeg/LICENSE.md new file mode 100644 index 00000000000..371b0913ce7 --- /dev/null +++ b/libs/ffmpeg/LICENSE.md @@ -0,0 +1,127 @@ +# License + +Most files in FFmpeg are under the GNU Lesser General Public License version 2.1 +or later (LGPL v2.1+). Read the file `COPYING.LGPLv2.1` for details. Some other +files have MIT/X11/BSD-style licenses. In combination the LGPL v2.1+ applies to +FFmpeg. + +Some optional parts of FFmpeg are licensed under the GNU General Public License +version 2 or later (GPL v2+). See the file `COPYING.GPLv2` for details. None of +these parts are used by default, you have to explicitly pass `--enable-gpl` to +configure to activate them. In this case, FFmpeg's license changes to GPL v2+. + +Specifically, the GPL parts of FFmpeg are: + +- optional x86 optimization in the files + - `libavcodec/x86/flac_dsp_gpl.asm` + - `libavcodec/x86/idct_mmx.c` + - `libavfilter/x86/vf_removegrain.asm` +- the following building and testing tools + - `compat/solaris/make_sunver.pl` + - `doc/t2h.pm` + - `doc/texi2pod.pl` + - `libswresample/tests/swresample.c` + - `tests/checkasm/*` + - `tests/tiny_ssim.c` +- the following filters in libavfilter: + - `signature_lookup.c` + - `vf_blackframe.c` + - `vf_boxblur.c` + - `vf_colormatrix.c` + - `vf_cover_rect.c` + - `vf_cropdetect.c` + - `vf_delogo.c` + - `vf_eq.c` + - `vf_find_rect.c` + - `vf_fspp.c` + - `vf_histeq.c` + - `vf_hqdn3d.c` + - `vf_kerndeint.c` + - `vf_lensfun.c` (GPL version 3 or later) + - `vf_mcdeint.c` + - `vf_mpdecimate.c` + - `vf_nnedi.c` + - `vf_owdenoise.c` + - `vf_perspective.c` + - `vf_phase.c` + - `vf_pp7.c` + - `vf_pullup.c` + - `vf_repeatfields.c` + - `vf_sab.c` + - `vf_signature.c` + - `vf_smartblur.c` + - `vf_spp.c` + - `vf_stereo3d.c` + - `vf_super2xsai.c` + - `vf_tinterlace.c` + - `vf_uspp.c` + - `vf_vaguedenoiser.c` + - `vsrc_mptestsrc.c` + +Should you, for whatever reason, prefer to use version 3 of the (L)GPL, then +the configure parameter `--enable-version3` will activate this licensing option +for you. Read the file `COPYING.LGPLv3` or, if you have enabled GPL parts, +`COPYING.GPLv3` to learn the exact legal terms that apply in this case. + +There are a handful of files under other licensing terms, namely: + +* The files `libavcodec/jfdctfst.c`, `libavcodec/jfdctint_template.c` and + `libavcodec/jrevdct.c` are taken from libjpeg, see the top of the files for + licensing details. Specifically note that you must credit the IJG in the + documentation accompanying your program if you only distribute executables. + You must also indicate any changes including additions and deletions to + those three files in the documentation. +* `tests/reference.pnm` is under the expat license. + + +## External libraries + +FFmpeg can be combined with a number of external libraries, which sometimes +affect the licensing of binaries resulting from the combination. + +### Compatible libraries + +The following libraries are under GPL version 2: +- avisynth +- frei0r +- libcdio +- libdavs2 +- librubberband +- libvidstab +- libx264 +- libx265 +- libxavs +- libxavs2 +- libxvid + +When combining them with FFmpeg, FFmpeg needs to be licensed as GPL as well by +passing `--enable-gpl` to configure. + +The following libraries are under LGPL version 3: +- gmp +- libaribb24 +- liblensfun + +When combining them with FFmpeg, use the configure option `--enable-version3` to +upgrade FFmpeg to the LGPL v3. + +The VMAF, mbedTLS, RK MPI, OpenCORE and VisualOn libraries are under the Apache License +2.0. That license is incompatible with the LGPL v2.1 and the GPL v2, but not with +version 3 of those licenses. So to combine these libraries with FFmpeg, the +license version needs to be upgraded by passing `--enable-version3` to configure. + +The smbclient library is under the GPL v3, to combine it with FFmpeg, +the options `--enable-gpl` and `--enable-version3` have to be passed to +configure to upgrade FFmpeg to the GPL v3. + +### Incompatible libraries + +There are certain libraries you can combine with FFmpeg whose licenses are not +compatible with the GPL and/or the LGPL. If you wish to enable these +libraries, even in circumstances that their license may be incompatible, pass +`--enable-nonfree` to configure. This will cause the resulting binary to be +unredistributable. + +The Fraunhofer FDK AAC and OpenSSL libraries are under licenses which are +incompatible with the GPLv2 and v3. To the best of our knowledge, they are +compatible with the LGPL. diff --git a/libs/ffmpeg/Makefile.in b/libs/ffmpeg/Makefile.in new file mode 100644 index 00000000000..8aa75d58847 --- /dev/null +++ b/libs/ffmpeg/Makefile.in @@ -0,0 +1,138 @@ +STATICLIB = libffmpeg.a +EXTRADEFS = -DHAVE_AV_CONFIG_H + +SOURCES = \ + config.h \ + libavutil/adler32.c \ + libavutil/aes.c \ + libavutil/aes_ctr.c \ + libavutil/ambient_viewing_environment.c \ + libavutil/audio_fifo.c \ + libavutil/avsscanf.c \ + libavutil/avstring.c \ + libavutil/base64.c \ + libavutil/blowfish.c \ + libavutil/bprint.c \ + libavutil/buffer.c \ + libavutil/camellia.c \ + libavutil/cast5.c \ + libavutil/channel_layout.c \ + libavutil/container_fifo.c \ + libavutil/cpu.c \ + libavutil/crc.c \ + libavutil/csp.c \ + libavutil/des.c \ + libavutil/detection_bbox.c \ + libavutil/dict.c \ + libavutil/display.c \ + libavutil/dovi_meta.c \ + libavutil/downmix_info.c \ + libavutil/encryption_info.c \ + libavutil/error.c \ + libavutil/eval.c \ + libavutil/executor.c \ + libavutil/fifo.c \ + libavutil/file.c \ + libavutil/file_open.c \ + libavutil/film_grain_params.c \ + libavutil/fixed_dsp.c \ + libavutil/float2half.c \ + libavutil/float_dsp.c \ + libavutil/float_scalarproduct.c \ + libavutil/frame.c \ + libavutil/half2float.c \ + libavutil/hash.c \ + libavutil/hdr_dynamic_metadata.c \ + libavutil/hdr_dynamic_vivid_metadata.c \ + libavutil/hmac.c \ + libavutil/hwcontext.c \ + libavutil/iamf.c \ + libavutil/imgutils.c \ + libavutil/integer.c \ + libavutil/intmath.c \ + libavutil/lfg.c \ + libavutil/lls.c \ + libavutil/log.c \ + libavutil/log2_tab.c \ + libavutil/lzo.c \ + libavutil/mastering_display_metadata.c \ + libavutil/mathematics.c \ + libavutil/md5.c \ + libavutil/mem.c \ + libavutil/murmur3.c \ + libavutil/opt.c \ + libavutil/parseutils.c \ + libavutil/pixdesc.c \ + libavutil/pixelutils.c \ + libavutil/random_seed.c \ + libavutil/rational.c \ + libavutil/rc4.c \ + libavutil/refstruct.c \ + libavutil/reverse.c \ + libavutil/ripemd.c \ + libavutil/samplefmt.c \ + libavutil/sha.c \ + libavutil/sha512.c \ + libavutil/side_data.c \ + libavutil/slicethread.c \ + libavutil/spherical.c \ + libavutil/stereo3d.c \ + libavutil/tdrdi.c \ + libavutil/tea.c \ + libavutil/threadmessage.c \ + libavutil/time.c \ + libavutil/timecode.c \ + libavutil/timecode_internal.c \ + libavutil/timestamp.c \ + libavutil/tree.c \ + libavutil/twofish.c \ + libavutil/tx.c \ + libavutil/tx_double.c \ + libavutil/tx_float.c \ + libavutil/tx_int32.c \ + libavutil/utils.c \ + libavutil/uuid.c \ + libavutil/version.c \ + libavutil/video_enc_params.c \ + libavutil/video_hint.c \ + libavutil/xga_font_data.c \ + libavutil/xtea.c \ + libswresample/audioconvert.c \ + libswresample/dither.c \ + libswresample/log2_tab.c \ + libswresample/options.c \ + libswresample/rematrix.c \ + libswresample/resample.c \ + libswresample/resample_dsp.c \ + libswresample/swresample.c \ + libswresample/swresample_frame.c \ + libswresample/swresampleres.rc \ + libswresample/version.c \ + libswscale/alphablend.c \ + libswscale/cms.c \ + libswscale/csputils.c \ + libswscale/format.c \ + libswscale/gamma.c \ + libswscale/graph.c \ + libswscale/half2float.c \ + libswscale/hscale.c \ + libswscale/hscale_fast_bilinear.c \ + libswscale/input.c \ + libswscale/log2_tab.c \ + libswscale/lut3d.c \ + libswscale/ops.c \ + libswscale/ops_backend.c \ + libswscale/ops_chain.c \ + libswscale/ops_dispatch.c \ + libswscale/ops_memcpy.c \ + libswscale/ops_optimizer.c \ + libswscale/options.c \ + libswscale/output.c \ + libswscale/rgb2rgb.c \ + libswscale/slice.c \ + libswscale/swscale.c \ + libswscale/swscale_unscaled.c \ + libswscale/utils.c \ + libswscale/version.c \ + libswscale/vscale.c \ + libswscale/yuv2rgb.c diff --git a/libs/ffmpeg/VERSION b/libs/ffmpeg/VERSION new file mode 100644 index 00000000000..0e79152459e --- /dev/null +++ b/libs/ffmpeg/VERSION @@ -0,0 +1 @@ +8.1.1 diff --git a/libs/ffmpeg/compat/va_copy.h b/libs/ffmpeg/compat/va_copy.h new file mode 100644 index 00000000000..a40bbe66371 --- /dev/null +++ b/libs/ffmpeg/compat/va_copy.h @@ -0,0 +1,34 @@ +/* + * MSVC Compatible va_copy macro + * Copyright (c) 2012 Derek Buitenhuis + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef COMPAT_VA_COPY_H +#define COMPAT_VA_COPY_H + +#include <stdarg.h> + +#if !defined(va_copy) && defined(_MSC_VER) +#define va_copy(dst, src) ((dst) = (src)) +#endif +#if !defined(va_copy) && defined(__GNUC__) && __GNUC__ < 3 +#define va_copy(dst, src) __va_copy(dst, src) +#endif + +#endif /* COMPAT_VA_COPY_H */ diff --git a/libs/ffmpeg/compat/w32pthreads.h b/libs/ffmpeg/compat/w32pthreads.h new file mode 100644 index 00000000000..f689d04d514 --- /dev/null +++ b/libs/ffmpeg/compat/w32pthreads.h @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2010-2011 x264 project + * + * Authors: Steven Walters <kemuri9@gmail.com> + * Pegasys Inc. <http://www.pegasys-inc.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * w32threads to pthreads wrapper + */ + +#ifndef COMPAT_W32PTHREADS_H +#define COMPAT_W32PTHREADS_H + +/* Build up a pthread-like API using underlying Windows API. Have only static + * methods so as to not conflict with a potentially linked in pthread-win32 + * library. + * As most functions here are used without checking return values, + * only implement return values as necessary. */ + +#include <windows.h> +#include <process.h> +#include <time.h> + +#include "libavutil/attributes.h" +#include "libavutil/common.h" +#include "libavutil/internal.h" +#include "libavutil/mem.h" +#include "libavutil/time.h" +#include "libavutil/wchar_filename.h" + +typedef struct w32pthread_t { + void *handle; + void *(*func)(void* arg); + void *arg; + void *ret; +} *pthread_t; + +/* use light weight mutex/condition variable API for Windows Vista and later */ +typedef SRWLOCK pthread_mutex_t; +typedef CONDITION_VARIABLE pthread_cond_t; + +#define PTHREAD_MUTEX_INITIALIZER SRWLOCK_INIT +#define PTHREAD_COND_INITIALIZER CONDITION_VARIABLE_INIT + +#define InitializeCriticalSection(x) InitializeCriticalSectionEx(x, 0, 0) +#define WaitForSingleObject(a, b) WaitForSingleObjectEx(a, b, FALSE) + +#define PTHREAD_CANCEL_ENABLE 1 +#define PTHREAD_CANCEL_DISABLE 0 + +#if HAVE_WINRT +#define THREADFUNC_RETTYPE DWORD +#else +#define THREADFUNC_RETTYPE unsigned +#endif + +av_unused static THREADFUNC_RETTYPE +__stdcall attribute_align_arg win32thread_worker(void *arg) +{ + pthread_t h = (pthread_t)arg; + h->ret = h->func(h->arg); + return 0; +} + +av_unused static int pthread_create(pthread_t *thread, const void *unused_attr, + void *(*start_routine)(void*), void *arg) +{ + pthread_t ret; + + ret = (pthread_t)av_mallocz(sizeof(*ret)); + if (!ret) + return EAGAIN; + + ret->func = start_routine; + ret->arg = arg; +#if HAVE_WINRT + ret->handle = (void*)CreateThread(NULL, 0, win32thread_worker, ret, + 0, NULL); +#else + ret->handle = (void*)_beginthreadex(NULL, 0, win32thread_worker, ret, + 0, NULL); +#endif + + if (!ret->handle) { + av_free(ret); + return EAGAIN; + } + + *thread = ret; + + return 0; +} + +av_unused static int pthread_join(pthread_t thread, void **value_ptr) +{ + DWORD ret = WaitForSingleObject(thread->handle, INFINITE); + if (ret != WAIT_OBJECT_0) { + if (ret == WAIT_ABANDONED) + return EINVAL; + else + return EDEADLK; + } + if (value_ptr) + *value_ptr = thread->ret; + CloseHandle(thread->handle); + av_free(thread); + return 0; +} + +static inline int pthread_mutex_init(pthread_mutex_t *m, void* attr) +{ + InitializeSRWLock(m); + return 0; +} +static inline int pthread_mutex_destroy(pthread_mutex_t *m) +{ + /* Unlocked SWR locks use no resources */ + return 0; +} +static inline int pthread_mutex_lock(pthread_mutex_t *m) +{ + AcquireSRWLockExclusive(m); + return 0; +} +static inline int pthread_mutex_unlock(pthread_mutex_t *m) +{ + ReleaseSRWLockExclusive(m); + return 0; +} + +typedef INIT_ONCE pthread_once_t; +#define PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT + +av_unused static int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) +{ + BOOL pending = FALSE; + InitOnceBeginInitialize(once_control, 0, &pending, NULL); + if (pending) + init_routine(); + InitOnceComplete(once_control, 0, NULL); + return 0; +} + +static inline int pthread_cond_init(pthread_cond_t *cond, const void *unused_attr) +{ + InitializeConditionVariable(cond); + return 0; +} + +/* native condition variables do not destroy */ +static inline int pthread_cond_destroy(pthread_cond_t *cond) +{ + return 0; +} + +static inline int pthread_cond_broadcast(pthread_cond_t *cond) +{ + WakeAllConditionVariable(cond); + return 0; +} + +static inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + SleepConditionVariableSRW(cond, mutex, INFINITE, 0); + return 0; +} + +static inline int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + int64_t abs_milli = abstime->tv_sec * 1000LL + abstime->tv_nsec / 1000000; + DWORD t = av_clip64(abs_milli - av_gettime() / 1000, 0, UINT32_MAX); + + if (!SleepConditionVariableSRW(cond, mutex, t, 0)) { + DWORD err = GetLastError(); + if (err == ERROR_TIMEOUT) + return ETIMEDOUT; + else + return EINVAL; + } + return 0; +} + +static inline int pthread_cond_signal(pthread_cond_t *cond) +{ + WakeConditionVariable(cond); + return 0; +} + +static inline int pthread_setcancelstate(int state, int *oldstate) +{ + return 0; +} + +static inline int win32_thread_setname(const char *name) +{ +#if !HAVE_UWP + typedef HRESULT (WINAPI *SetThreadDescriptionFn)(HANDLE, PCWSTR); + + // Although SetThreadDescription lives in kernel32.dll, on Windows Server 2016, + // Windows 10 LTSB 2016 and Windows 10 version 1607, it was only available in + // kernelbase.dll. So, load it from there for maximum coverage. + HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll"); + if (!kernelbase) + return AVERROR(ENOSYS); + + SetThreadDescriptionFn pSetThreadDescription = + (SetThreadDescriptionFn)GetProcAddress(kernelbase, "SetThreadDescription"); + if (!pSetThreadDescription) + return AVERROR(ENOSYS); + + wchar_t *wname; + if (utf8towchar(name, &wname) < 0) + return AVERROR(ENOMEM); + + HRESULT hr = pSetThreadDescription(GetCurrentThread(), wname); + av_free(wname); + return SUCCEEDED(hr) ? 0 : AVERROR(EINVAL); +#else + // UWP is not supported because we cannot use LoadLibrary/GetProcAddress to + // detect the availability of the SetThreadDescription API. There is a small + // gap in Windows builds 1507-1607 where it was not available. UWP allows + // querying the availability of APIs with QueryOptionalDelayLoadedAPI, but it + // requires /DELAYLOAD:kernel32.dll during linking, and we cannot enforce that. + return AVERROR(ENOSYS); +#endif +} + +#endif /* COMPAT_W32PTHREADS_H */ diff --git a/libs/ffmpeg/config.h b/libs/ffmpeg/config.h new file mode 100644 index 00000000000..33940a3f895 --- /dev/null +++ b/libs/ffmpeg/config.h @@ -0,0 +1,833 @@ +/* Automatically generated by configure - do not modify! */ +#ifndef FFMPEG_CONFIG_H +#define FFMPEG_CONFIG_H +#define FFMPEG_CONFIGURATION "--disable-autodetect --disable-iconv --disable-all --disable-asm --enable-avutil --enable-swresample --enable-swscale --cross-prefix=i686-w64-mingw32- --arch=x86 --target-os=win32" +#define FFMPEG_LICENSE "LGPL version 2.1 or later" +#define CONFIG_THIS_YEAR 2026 +#define FFMPEG_DATADIR "/usr/local/share/ffmpeg" +#define AVCONV_DATADIR "/usr/local/share/ffmpeg" +#define CC_IDENT "gcc 15-win32 (GCC)" +#define OS_NAME win32 +#define EXTERN_PREFIX "_" +#define EXTERN_ASM _ +#define BUILDSUF "" +#define SLIBSUF ".dll" +#define SWS_MAX_FILTER_SIZE 256 +#define ARCH_AARCH64 0 +#define ARCH_ARM 0 +#define ARCH_IA64 0 +#define ARCH_LOONGARCH 0 +#define ARCH_LOONGARCH32 0 +#define ARCH_LOONGARCH64 0 +#define ARCH_M68K 0 +#define ARCH_MIPS 0 +#define ARCH_MIPS64 0 +#define ARCH_PARISC 0 +#define ARCH_PPC 0 +#define ARCH_PPC64 0 +#define ARCH_RISCV 0 +#define ARCH_S390 0 +#define ARCH_SPARC 0 +#define ARCH_SPARC64 0 +#define ARCH_TILEGX 0 +#define ARCH_TILEPRO 0 +#define ARCH_WASM 0 +#define ARCH_X86 0 +#define ARCH_X86_32 0 +#define ARCH_X86_64 0 +#define HAVE_ARMV5TE 0 +#define HAVE_ARMV6 0 +#define HAVE_ARMV6T2 0 +#define HAVE_ARMV8 0 +#define HAVE_ARM_CRC 0 +#define HAVE_DOTPROD 0 +#define HAVE_I8MM 0 +#define HAVE_NEON 0 +#define HAVE_VFP 0 +#define HAVE_VFPV3 0 +#define HAVE_SETEND 0 +#define HAVE_SVE 0 +#define HAVE_SVE2 0 +#define HAVE_SME 0 +#define HAVE_SME_I16I64 0 +#define HAVE_SME2 0 +#define HAVE_ALTIVEC 0 +#define HAVE_DCBZL 0 +#define HAVE_LDBRX 0 +#define HAVE_POWER8 0 +#define HAVE_PPC4XX 0 +#define HAVE_VEC_XL 0 +#define HAVE_VSX 0 +#define HAVE_RV 0 +#define HAVE_RVV 0 +#define HAVE_RV_ZICBOP 0 +#define HAVE_RV_ZVBB 0 +#define HAVE_SIMD128 0 +#define HAVE_AESNI 0 +#define HAVE_CLMUL 0 +#define HAVE_AMD3DNOW 0 +#define HAVE_AMD3DNOWEXT 0 +#define HAVE_AVX 0 +#define HAVE_AVX2 0 +#define HAVE_AVX512 0 +#define HAVE_AVX512ICL 0 +#define HAVE_FMA3 0 +#define HAVE_FMA4 0 +#define HAVE_MMX 0 +#define HAVE_MMXEXT 0 +#define HAVE_SSE 0 +#define HAVE_SSE2 0 +#define HAVE_SSE3 0 +#define HAVE_SSE4 0 +#define HAVE_SSE42 0 +#define HAVE_SSSE3 0 +#define HAVE_XOP 0 +#define HAVE_I686 0 +#define HAVE_MIPSFPU 0 +#define HAVE_MIPS32R2 0 +#define HAVE_MIPS32R5 0 +#define HAVE_MIPS64R2 0 +#define HAVE_MIPS32R6 0 +#define HAVE_MIPS64R6 0 +#define HAVE_MIPSDSP 0 +#define HAVE_MIPSDSPR2 0 +#define HAVE_MSA 0 +#define HAVE_LOONGSON2 0 +#define HAVE_LOONGSON3 0 +#define HAVE_MMI 0 +#define HAVE_LSX 0 +#define HAVE_LASX 0 +#define HAVE_ARMV5TE_EXTERNAL 0 +#define HAVE_ARMV6_EXTERNAL 0 +#define HAVE_ARMV6T2_EXTERNAL 0 +#define HAVE_ARMV8_EXTERNAL 0 +#define HAVE_ARM_CRC_EXTERNAL 0 +#define HAVE_DOTPROD_EXTERNAL 0 +#define HAVE_I8MM_EXTERNAL 0 +#define HAVE_NEON_EXTERNAL 0 +#define HAVE_VFP_EXTERNAL 0 +#define HAVE_VFPV3_EXTERNAL 0 +#define HAVE_SETEND_EXTERNAL 0 +#define HAVE_SVE_EXTERNAL 0 +#define HAVE_SVE2_EXTERNAL 0 +#define HAVE_SME_EXTERNAL 0 +#define HAVE_SME_I16I64_EXTERNAL 0 +#define HAVE_SME2_EXTERNAL 0 +#define HAVE_ALTIVEC_EXTERNAL 0 +#define HAVE_DCBZL_EXTERNAL 0 +#define HAVE_LDBRX_EXTERNAL 0 +#define HAVE_POWER8_EXTERNAL 0 +#define HAVE_PPC4XX_EXTERNAL 0 +#define HAVE_VEC_XL_EXTERNAL 0 +#define HAVE_VSX_EXTERNAL 0 +#define HAVE_RV_EXTERNAL 0 +#define HAVE_RVV_EXTERNAL 0 +#define HAVE_RV_ZICBOP_EXTERNAL 0 +#define HAVE_RV_ZVBB_EXTERNAL 0 +#define HAVE_SIMD128_EXTERNAL 0 +#define HAVE_AESNI_EXTERNAL 0 +#define HAVE_CLMUL_EXTERNAL 0 +#define HAVE_AMD3DNOW_EXTERNAL 0 +#define HAVE_AMD3DNOWEXT_EXTERNAL 0 +#define HAVE_AVX_EXTERNAL 0 +#define HAVE_AVX2_EXTERNAL 0 +#define HAVE_AVX512_EXTERNAL 0 +#define HAVE_AVX512ICL_EXTERNAL 0 +#define HAVE_FMA3_EXTERNAL 0 +#define HAVE_FMA4_EXTERNAL 0 +#define HAVE_MMX_EXTERNAL 0 +#define HAVE_MMXEXT_EXTERNAL 0 +#define HAVE_SSE_EXTERNAL 0 +#define HAVE_SSE2_EXTERNAL 0 +#define HAVE_SSE3_EXTERNAL 0 +#define HAVE_SSE4_EXTERNAL 0 +#define HAVE_SSE42_EXTERNAL 0 +#define HAVE_SSSE3_EXTERNAL 0 +#define HAVE_XOP_EXTERNAL 0 +#define HAVE_I686_EXTERNAL 0 +#define HAVE_MIPSFPU_EXTERNAL 0 +#define HAVE_MIPS32R2_EXTERNAL 0 +#define HAVE_MIPS32R5_EXTERNAL 0 +#define HAVE_MIPS64R2_EXTERNAL 0 +#define HAVE_MIPS32R6_EXTERNAL 0 +#define HAVE_MIPS64R6_EXTERNAL 0 +#define HAVE_MIPSDSP_EXTERNAL 0 +#define HAVE_MIPSDSPR2_EXTERNAL 0 +#define HAVE_MSA_EXTERNAL 0 +#define HAVE_LOONGSON2_EXTERNAL 0 +#define HAVE_LOONGSON3_EXTERNAL 0 +#define HAVE_MMI_EXTERNAL 0 +#define HAVE_LSX_EXTERNAL 0 +#define HAVE_LASX_EXTERNAL 0 +#define HAVE_ARMV5TE_INLINE 0 +#define HAVE_ARMV6_INLINE 0 +#define HAVE_ARMV6T2_INLINE 0 +#define HAVE_ARMV8_INLINE 0 +#define HAVE_ARM_CRC_INLINE 0 +#define HAVE_DOTPROD_INLINE 0 +#define HAVE_I8MM_INLINE 0 +#define HAVE_NEON_INLINE 0 +#define HAVE_VFP_INLINE 0 +#define HAVE_VFPV3_INLINE 0 +#define HAVE_SETEND_INLINE 0 +#define HAVE_SVE_INLINE 0 +#define HAVE_SVE2_INLINE 0 +#define HAVE_SME_INLINE 0 +#define HAVE_SME_I16I64_INLINE 0 +#define HAVE_SME2_INLINE 0 +#define HAVE_ALTIVEC_INLINE 0 +#define HAVE_DCBZL_INLINE 0 +#define HAVE_LDBRX_INLINE 0 +#define HAVE_POWER8_INLINE 0 +#define HAVE_PPC4XX_INLINE 0 +#define HAVE_VEC_XL_INLINE 0 +#define HAVE_VSX_INLINE 0 +#define HAVE_RV_INLINE 0 +#define HAVE_RVV_INLINE 0 +#define HAVE_RV_ZICBOP_INLINE 0 +#define HAVE_RV_ZVBB_INLINE 0 +#define HAVE_SIMD128_INLINE 0 +#define HAVE_AESNI_INLINE 0 +#define HAVE_CLMUL_INLINE 0 +#define HAVE_AMD3DNOW_INLINE 0 +#define HAVE_AMD3DNOWEXT_INLINE 0 +#define HAVE_AVX_INLINE 0 +#define HAVE_AVX2_INLINE 0 +#define HAVE_AVX512_INLINE 0 +#define HAVE_AVX512ICL_INLINE 0 +#define HAVE_FMA3_INLINE 0 +#define HAVE_FMA4_INLINE 0 +#define HAVE_MMX_INLINE 0 +#define HAVE_MMXEXT_INLINE 0 +#define HAVE_SSE_INLINE 0 +#define HAVE_SSE2_INLINE 0 +#define HAVE_SSE3_INLINE 0 +#define HAVE_SSE4_INLINE 0 +#define HAVE_SSE42_INLINE 0 +#define HAVE_SSSE3_INLINE 0 +#define HAVE_XOP_INLINE 0 +#define HAVE_I686_INLINE 0 +#define HAVE_MIPSFPU_INLINE 0 +#define HAVE_MIPS32R2_INLINE 0 +#define HAVE_MIPS32R5_INLINE 0 +#define HAVE_MIPS64R2_INLINE 0 +#define HAVE_MIPS32R6_INLINE 0 +#define HAVE_MIPS64R6_INLINE 0 +#define HAVE_MIPSDSP_INLINE 0 +#define HAVE_MIPSDSPR2_INLINE 0 +#define HAVE_MSA_INLINE 0 +#define HAVE_LOONGSON2_INLINE 0 +#define HAVE_LOONGSON3_INLINE 0 +#define HAVE_MMI_INLINE 0 +#define HAVE_LSX_INLINE 0 +#define HAVE_LASX_INLINE 0 +#define HAVE_ALIGNED_STACK 0 +#define HAVE_FAST_64BIT 0 +#define HAVE_FAST_CLZ 1 +#define HAVE_FAST_CMOV 1 +#define HAVE_FAST_FLOAT16 0 +#define HAVE_SIMD_ALIGN_16 0 +#define HAVE_SIMD_ALIGN_32 0 +#define HAVE_SIMD_ALIGN_64 0 +#define HAVE_MEMORYBARRIER 1 +#define HAVE_MM_EMPTY 0 +#define HAVE_RDTSC 0 +#define HAVE_SEM_TIMEDWAIT 0 +#define HAVE_INLINE_ASM 1 +#define HAVE_SYMVER 0 +#define HAVE_X86ASM 0 +#define HAVE_BIGENDIAN 0 +#define HAVE_FAST_UNALIGNED 0 +#define HAVE_ARPA_INET_H 0 +#define HAVE_ASM_HWPROBE_H 0 +#define HAVE_ASM_TYPES_H 0 +#define HAVE_CDIO_PARANOIA_H 0 +#define HAVE_CDIO_PARANOIA_PARANOIA_H 0 +#define HAVE_CUDA_H 0 +#define HAVE_DISPATCH_DISPATCH_H 0 +#define HAVE_DIRECT_H 1 +#define HAVE_DIRENT_H 1 +#define HAVE_DXGIDEBUG_H 1 +#define HAVE_DXVA_H 1 +#define HAVE_ES2_GL_H 0 +#define HAVE_GSM_H 0 +#define HAVE_IO_H 1 +#define HAVE_LINUX_DMA_BUF_H 0 +#define HAVE_LINUX_PERF_EVENT_H 0 +#define HAVE_MALLOC_H 1 +#define HAVE_POLL_H 0 +#define HAVE_PTHREAD_NP_H 0 +#define HAVE_SYS_HWPROBE_H 0 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_RESOURCE_H 0 +#define HAVE_SYS_SELECT_H 0 +#define HAVE_SYS_SOUNDCARD_H 0 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_UN_H 0 +#define HAVE_SYS_VIDEOIO_H 0 +#define HAVE_TERMIOS_H 0 +#define HAVE_UDPLITE_H 0 +#define HAVE_UNISTD_H 1 +#define HAVE_VALGRIND_VALGRIND_H 0 +#define HAVE_WINDOWS_H 1 +#define HAVE_WINSOCK2_H 1 +#define HAVE_INTRINSICS_NEON 0 +#define HAVE_INTRINSICS_SSE2 0 +#define HAVE_ATANF 1 +#define HAVE_ATAN2F 1 +#define HAVE_CBRT 1 +#define HAVE_CBRTF 1 +#define HAVE_COPYSIGN 1 +#define HAVE_COSF 1 +#define HAVE_ERF 1 +#define HAVE_EXP2 1 +#define HAVE_EXP2F 1 +#define HAVE_EXPF 1 +#define HAVE_HYPOT 1 +#define HAVE_ISFINITE 1 +#define HAVE_ISINF 1 +#define HAVE_ISNAN 1 +#define HAVE_LDEXPF 1 +#define HAVE_LLRINT 1 +#define HAVE_LLRINTF 1 +#define HAVE_LOG2 1 +#define HAVE_LOG2F 1 +#define HAVE_LOG10F 1 +#define HAVE_LRINT 1 +#define HAVE_LRINTF 1 +#define HAVE_POWF 1 +#define HAVE_RINT 1 +#define HAVE_ROUND 1 +#define HAVE_ROUNDF 1 +#define HAVE_SINF 1 +#define HAVE_TRUNC 1 +#define HAVE_TRUNCF 1 +#define HAVE_DOS_PATHS 1 +#define HAVE_LIBC_MSVCRT 0 +#define HAVE_MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS 0 +#define HAVE_SECTION_DATA_REL_RO 0 +#define HAVE_THREADS 1 +#define HAVE_UWP 0 +#define HAVE_WINRT 0 +#define HAVE_ACCESS 1 +#define HAVE_ALIGNED_MALLOC 1 +#define HAVE_ARC4RANDOM_BUF 0 +#define HAVE_CLOCK_GETTIME 0 +#define HAVE_CLOSESOCKET 1 +#define HAVE_COMMANDLINETOARGVW 1 +#define HAVE_ELF_AUX_INFO 0 +#define HAVE_FCNTL 0 +#define HAVE_GETADDRINFO 1 +#define HAVE_GETAUXVAL 0 +#define HAVE_GETENV 1 +#define HAVE_GETHRTIME 0 +#define HAVE_GETOPT 1 +#define HAVE_GETMODULEHANDLE 1 +#define HAVE_GETPROCESSAFFINITYMASK 1 +#define HAVE_GETPROCESSMEMORYINFO 1 +#define HAVE_GETPROCESSTIMES 1 +#define HAVE_GETRUSAGE 0 +#define HAVE_GETSTDHANDLE 1 +#define HAVE_GETSYSTEMTIMEASFILETIME 1 +#define HAVE_GETTIMEOFDAY 0 +#define HAVE_GLOB 0 +#define HAVE_GLXGETPROCADDRESS 0 +#define HAVE_GMTIME_R 0 +#define HAVE_INET_ATON 0 +#define HAVE_ISATTY 1 +#define HAVE_KBHIT 1 +#define HAVE_LOCALTIME_R 0 +#define HAVE_LSTAT 0 +#define HAVE_LZO1X_999_COMPRESS 0 +#define HAVE_MACH_ABSOLUTE_TIME 0 +#define HAVE_MAPVIEWOFFILE 1 +#define HAVE_MEMALIGN 0 +#define HAVE_MKSTEMP 0 +#define HAVE_MMAP 0 +#define HAVE_MPROTECT 1 +#define HAVE_NANOSLEEP 0 +#define HAVE_PEEKNAMEDPIPE 1 +#define HAVE_POSIX_MEMALIGN 0 +#define HAVE_PRCTL 0 +#define HAVE_PTHREAD_CANCEL 0 +#define HAVE_PTHREAD_SET_NAME_NP 0 +#define HAVE_PTHREAD_SETNAME_NP 0 +#define HAVE_SCHED_GETAFFINITY 0 +#define HAVE_SECITEMIMPORT 0 +#define HAVE_SETCONSOLETEXTATTRIBUTE 1 +#define HAVE_SETCONSOLECTRLHANDLER 1 +#define HAVE_SETDLLDIRECTORY 1 +#define HAVE_SETMODE 1 +#define HAVE_SETRLIMIT 0 +#define HAVE_SLEEP 1 +#define HAVE_STRERROR_R 0 +#define HAVE_SYSCONF 0 +#define HAVE_SYSCTL 0 +#define HAVE_SYSCTLBYNAME 0 +#define HAVE_TEMPNAM 1 +#define HAVE_USLEEP 0 +#define HAVE_UTGETOSTYPEFROMSTRING 0 +#define HAVE_VIRTUALALLOC 1 +#define HAVE_WGLGETPROCADDRESS 0 +#define HAVE_BCRYPT 1 +#define HAVE_VAAPI_DRM 0 +#define HAVE_VAAPI_X11 0 +#define HAVE_VAAPI_WIN32 0 +#define HAVE_VDPAU_X11 0 +#define HAVE_PTHREADS 0 +#define HAVE_OS2THREADS 0 +#define HAVE_W32THREADS 1 +#define HAVE_AS_ARCH_DIRECTIVE 0 +#define HAVE_AS_ARCHEXT_CRC_DIRECTIVE 0 +#define HAVE_AS_ARCHEXT_DOTPROD_DIRECTIVE 0 +#define HAVE_AS_ARCHEXT_I8MM_DIRECTIVE 0 +#define HAVE_AS_ARCHEXT_SVE_DIRECTIVE 0 +#define HAVE_AS_ARCHEXT_SVE2_DIRECTIVE 0 +#define HAVE_AS_ARCHEXT_SME_DIRECTIVE 0 +#define HAVE_AS_ARCHEXT_SME_I16I64_DIRECTIVE 0 +#define HAVE_AS_ARCHEXT_SME2_DIRECTIVE 0 +#define HAVE_AS_DN_DIRECTIVE 0 +#define HAVE_AS_FPU_DIRECTIVE 0 +#define HAVE_AS_FUNC 0 +#define HAVE_AS_OBJECT_ARCH 0 +#define HAVE_ASM_MOD_Q 0 +#define HAVE_BLOCKS_EXTENSION 0 +#define HAVE_EBP_AVAILABLE 1 +#define HAVE_EBX_AVAILABLE 1 +#define HAVE_GNU_AS 0 +#define HAVE_GNU_WINDRES 1 +#define HAVE_IBM_ASM 0 +#define HAVE_INLINE_ASM_DIRECT_SYMBOL_REFS 1 +#define HAVE_INLINE_ASM_LABELS 1 +#define HAVE_INLINE_ASM_NONLOCAL_LABELS 1 +#define HAVE_PRAGMA_DEPRECATED 1 +#define HAVE_RSYNC_CONTIMEOUT 1 +#define HAVE_SYMVER_ASM_LABEL 1 +#define HAVE_SYMVER_GNU_ASM 0 +#define HAVE_VFP_ARGS 0 +#define HAVE_XFORM_ASM 0 +#define HAVE_XMM_CLOBBERS 0 +#define HAVE_DPI_AWARENESS_CONTEXT 1 +#define HAVE_IDXGIOUTPUT5 1 +#define HAVE___X_ABI_CWINDOWS_CGRAPHICS_CCAPTURE_CIGRAPHICSCAPTURESESSION5 0 +#define HAVE_IDIRECT3DDXGIINTERFACEACCESS 0 +#define HAVE_KCMVIDEOCODECTYPE_HEVC 0 +#define HAVE_KCMVIDEOCODECTYPE_HEVCWITHALPHA 0 +#define HAVE_KCMVIDEOCODECTYPE_VP9 0 +#define HAVE_KCMVIDEOCODECTYPE_AV1 0 +#define HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE 0 +#define HAVE_KCVPIXELFORMATTYPE_422YPCBCR8BIPLANARVIDEORANGE 0 +#define HAVE_KCVPIXELFORMATTYPE_422YPCBCR10BIPLANARVIDEORANGE 0 +#define HAVE_KCVPIXELFORMATTYPE_422YPCBCR16BIPLANARVIDEORANGE 0 +#define HAVE_KCVPIXELFORMATTYPE_444YPCBCR8BIPLANARVIDEORANGE 0 +#define HAVE_KCVPIXELFORMATTYPE_444YPCBCR10BIPLANARVIDEORANGE 0 +#define HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE 0 +#define HAVE_KCVPIXELFORMATTYPE_422YPCBCR8_YUVS 0 +#define HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_2084_PQ 0 +#define HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG 0 +#define HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_LINEAR 0 +#define HAVE_KCVIMAGEBUFFERYCBCRMATRIX_ITU_R_2020 0 +#define HAVE_KCVIMAGEBUFFERCOLORPRIMARIES_ITU_R_2020 0 +#define HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2020 0 +#define HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_428_1 0 +#define HAVE_KVTQPMODULATIONLEVEL_DEFAULT 0 +#define HAVE_SECPKGCONTEXT_KEYINGMATERIALINFO 1 +#define HAVE_SOCKLEN_T 1 +#define HAVE_STRUCT_ADDRINFO 1 +#define HAVE_STRUCT_GROUP_SOURCE_REQ 1 +#define HAVE_STRUCT_IP_MREQ_SOURCE 1 +#define HAVE_STRUCT_IPV6_MREQ 1 +#define HAVE_STRUCT_MSGHDR_MSG_FLAGS 0 +#define HAVE_STRUCT_POLLFD 1 +#define HAVE_STRUCT_RUSAGE_RU_MAXRSS 0 +#define HAVE_STRUCT_SCTP_EVENT_SUBSCRIBE 0 +#define HAVE_STRUCT_SOCKADDR_IN6 1 +#define HAVE_STRUCT_SOCKADDR_SA_LEN 0 +#define HAVE_STRUCT_SOCKADDR_STORAGE 1 +#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 0 +#define HAVE_STRUCT_V4L2_FRMIVALENUM_DISCRETE 0 +#define HAVE_STRUCT_MFXCONFIGINTERFACE 0 +#define HAVE_GZIP 1 +#define HAVE_IOCTL_POSIX 0 +#define HAVE_LIBDRM_GETFB2 0 +#define HAVE_MAKEINFO 1 +#define HAVE_MAKEINFO_HTML 1 +#define HAVE_OPENCL_D3D11 0 +#define HAVE_OPENCL_DRM_ARM 0 +#define HAVE_OPENCL_DRM_BEIGNET 0 +#define HAVE_OPENCL_DXVA2 0 +#define HAVE_OPENCL_VAAPI_BEIGNET 0 +#define HAVE_OPENCL_VAAPI_INTEL_MEDIA 0 +#define HAVE_OPENCL_VIDEOTOOLBOX 0 +#define HAVE_PERL 1 +#define HAVE_POD2MAN 1 +#define HAVE_TEXI2HTML 0 +#define HAVE_XMLLINT 1 +#define HAVE_ZLIB_GZIP 0 +#define HAVE_OPENVINO2 0 +#define CONFIG_DOC 0 +#define CONFIG_HTMLPAGES 1 +#define CONFIG_MANPAGES 1 +#define CONFIG_PODPAGES 1 +#define CONFIG_TXTPAGES 1 +#define CONFIG_AVIO_HTTP_SERVE_FILES_EXAMPLE 1 +#define CONFIG_AVIO_LIST_DIR_EXAMPLE 1 +#define CONFIG_AVIO_READ_CALLBACK_EXAMPLE 1 +#define CONFIG_DECODE_AUDIO_EXAMPLE 0 +#define CONFIG_DECODE_FILTER_AUDIO_EXAMPLE 0 +#define CONFIG_DECODE_FILTER_VIDEO_EXAMPLE 0 +#define CONFIG_DECODE_VIDEO_EXAMPLE 0 +#define CONFIG_DEMUX_DECODE_EXAMPLE 0 +#define CONFIG_ENCODE_AUDIO_EXAMPLE 0 +#define CONFIG_ENCODE_VIDEO_EXAMPLE 0 +#define CONFIG_EXTRACT_MVS_EXAMPLE 0 +#define CONFIG_FILTER_AUDIO_EXAMPLE 0 +#define CONFIG_HW_DECODE_EXAMPLE 0 +#define CONFIG_MUX_EXAMPLE 0 +#define CONFIG_QSV_DECODE_EXAMPLE 0 +#define CONFIG_REMUX_EXAMPLE 0 +#define CONFIG_RESAMPLE_AUDIO_EXAMPLE 1 +#define CONFIG_SCALE_VIDEO_EXAMPLE 1 +#define CONFIG_SHOW_METADATA_EXAMPLE 0 +#define CONFIG_TRANSCODE_AAC_EXAMPLE 0 +#define CONFIG_TRANSCODE_EXAMPLE 0 +#define CONFIG_VAAPI_ENCODE_EXAMPLE 0 +#define CONFIG_VAAPI_TRANSCODE_EXAMPLE 0 +#define CONFIG_QSV_TRANSCODE_EXAMPLE 0 +#define CONFIG_AVISYNTH 0 +#define CONFIG_FREI0R 0 +#define CONFIG_LIBCDIO 0 +#define CONFIG_LIBDAVS2 0 +#define CONFIG_LIBDVDNAV 0 +#define CONFIG_LIBDVDREAD 0 +#define CONFIG_LIBRUBBERBAND 0 +#define CONFIG_LIBVIDSTAB 0 +#define CONFIG_LIBX264 0 +#define CONFIG_LIBX265 0 +#define CONFIG_LIBXAVS 0 +#define CONFIG_LIBXAVS2 0 +#define CONFIG_LIBXVID 0 +#define CONFIG_DECKLINK 0 +#define CONFIG_LIBFDK_AAC 0 +#define CONFIG_LIBMPEGHDEC 0 +#define CONFIG_GMP 0 +#define CONFIG_LIBARIBB24 0 +#define CONFIG_LIBLENSFUN 0 +#define CONFIG_LIBOPENCORE_AMRNB 0 +#define CONFIG_LIBOPENCORE_AMRWB 0 +#define CONFIG_LIBVO_AMRWBENC 0 +#define CONFIG_MBEDTLS 0 +#define CONFIG_RKMPP 0 +#define CONFIG_LIBSMBCLIENT 0 +#define CONFIG_CAIRO 0 +#define CONFIG_CHROMAPRINT 0 +#define CONFIG_GCRYPT 0 +#define CONFIG_GNUTLS 0 +#define CONFIG_JNI 0 +#define CONFIG_LADSPA 0 +#define CONFIG_LCMS2 0 +#define CONFIG_LIBAOM 0 +#define CONFIG_LIBARIBCAPTION 0 +#define CONFIG_LIBASS 0 +#define CONFIG_LIBBLURAY 0 +#define CONFIG_LIBBS2B 0 +#define CONFIG_LIBCACA 0 +#define CONFIG_LIBCELT 0 +#define CONFIG_LIBCODEC2 0 +#define CONFIG_LIBDAV1D 0 +#define CONFIG_LIBDC1394 0 +#define CONFIG_LIBFLITE 0 +#define CONFIG_LIBFONTCONFIG 0 +#define CONFIG_LIBFREETYPE 0 +#define CONFIG_LIBFRIBIDI 0 +#define CONFIG_LIBHARFBUZZ 0 +#define CONFIG_LIBGLSLANG 0 +#define CONFIG_LIBGME 0 +#define CONFIG_LIBGSM 0 +#define CONFIG_LIBIEC61883 0 +#define CONFIG_LIBILBC 0 +#define CONFIG_LIBJACK 0 +#define CONFIG_LIBJXL 0 +#define CONFIG_LIBKLVANC 0 +#define CONFIG_LIBKVAZAAR 0 +#define CONFIG_LIBLC3 0 +#define CONFIG_LIBLCEVC_DEC 0 +#define CONFIG_LIBMODPLUG 0 +#define CONFIG_LIBMP3LAME 0 +#define CONFIG_LIBMYSOFA 0 +#define CONFIG_LIBOAPV 0 +#define CONFIG_LIBOPENCV 0 +#define CONFIG_LIBOPENCOLORIO 0 +#define CONFIG_LIBOPENH264 0 +#define CONFIG_LIBOPENJPEG 0 +#define CONFIG_LIBOPENMPT 0 +#define CONFIG_LIBOPENVINO 0 +#define CONFIG_LIBOPUS 0 +#define CONFIG_LIBPLACEBO 0 +#define CONFIG_LIBPULSE 0 +#define CONFIG_LIBQRENCODE 0 +#define CONFIG_LIBQUIRC 0 +#define CONFIG_LIBRABBITMQ 0 +#define CONFIG_LIBRAV1E 0 +#define CONFIG_LIBRIST 0 +#define CONFIG_LIBRSVG 0 +#define CONFIG_LIBRTMP 0 +#define CONFIG_LIBSHADERC 0 +#define CONFIG_LIBSHINE 0 +#define CONFIG_LIBSMBCLIENT 0 +#define CONFIG_LIBSNAPPY 0 +#define CONFIG_LIBSOXR 0 +#define CONFIG_LIBSPEEX 0 +#define CONFIG_LIBSRT 0 +#define CONFIG_LIBSSH 0 +#define CONFIG_LIBSVTAV1 0 +#define CONFIG_LIBSVTJPEGXS 0 +#define CONFIG_LIBTENSORFLOW 0 +#define CONFIG_LIBTESSERACT 0 +#define CONFIG_LIBTHEORA 0 +#define CONFIG_LIBTLS 0 +#define CONFIG_LIBTORCH 0 +#define CONFIG_LIBTWOLAME 0 +#define CONFIG_LIBUAVS3D 0 +#define CONFIG_LIBV4L2 0 +#define CONFIG_LIBVMAF 0 +#define CONFIG_LIBVORBIS 0 +#define CONFIG_LIBVPX 0 +#define CONFIG_LIBVVENC 0 +#define CONFIG_LIBWEBP 0 +#define CONFIG_LIBXEVD 0 +#define CONFIG_LIBXEVDB 0 +#define CONFIG_LIBXEVE 0 +#define CONFIG_LIBXEVEB 0 +#define CONFIG_LIBXML2 0 +#define CONFIG_LIBZIMG 0 +#define CONFIG_LIBZMQ 0 +#define CONFIG_LIBZVBI 0 +#define CONFIG_LV2 0 +#define CONFIG_MEDIACODEC 0 +#define CONFIG_OHCODEC 0 +#define CONFIG_OPENAL 0 +#define CONFIG_OPENGL 0 +#define CONFIG_OPENSSL 0 +#define CONFIG_POCKETSPHINX 0 +#define CONFIG_VAPOURSYNTH 0 +#define CONFIG_VULKAN_STATIC 0 +#define CONFIG_WHISPER 0 +#define CONFIG_ALSA 0 +#define CONFIG_APPKIT 0 +#define CONFIG_AVFOUNDATION 0 +#define CONFIG_BZLIB 0 +#define CONFIG_COREIMAGE 0 +#define CONFIG_ICONV 0 +#define CONFIG_LIBXCB 0 +#define CONFIG_LIBXCB_SHM 0 +#define CONFIG_LIBXCB_SHAPE 0 +#define CONFIG_LIBXCB_XFIXES 0 +#define CONFIG_LZMA 0 +#define CONFIG_MEDIAFOUNDATION 0 +#define CONFIG_METAL 0 +#define CONFIG_SCHANNEL 0 +#define CONFIG_SDL2 0 +#define CONFIG_SECURETRANSPORT 0 +#define CONFIG_SNDIO 0 +#define CONFIG_XLIB 0 +#define CONFIG_ZLIB 0 +#define CONFIG_CUDA_NVCC 0 +#define CONFIG_CUDA_SDK 0 +#define CONFIG_LIBNPP 0 +#define CONFIG_LIBMFX 0 +#define CONFIG_LIBVPL 0 +#define CONFIG_MMAL 0 +#define CONFIG_OMX 0 +#define CONFIG_OPENCL 0 +#define CONFIG_AMF 0 +#define CONFIG_AUDIOTOOLBOX 0 +#define CONFIG_CUDA 0 +#define CONFIG_CUDA_LLVM 0 +#define CONFIG_CUVID 0 +#define CONFIG_D3D11VA 0 +#define CONFIG_D3D12VA 0 +#define CONFIG_DXVA2 0 +#define CONFIG_FFNVCODEC 0 +#define CONFIG_LIBDRM 0 +#define CONFIG_NVDEC 0 +#define CONFIG_NVENC 0 +#define CONFIG_VAAPI 0 +#define CONFIG_VDPAU 0 +#define CONFIG_VIDEOTOOLBOX 0 +#define CONFIG_VULKAN 0 +#define CONFIG_V4L2_M2M 0 +#define CONFIG_FTRAPV 0 +#define CONFIG_GRAY 0 +#define CONFIG_HARDCODED_TABLES 0 +#define CONFIG_OMX_RPI 0 +#define CONFIG_RUNTIME_CPUDETECT 1 +#define CONFIG_SAFE_BITSTREAM_READER 1 +#define CONFIG_SHARED 0 +#define CONFIG_SMALL 0 +#define CONFIG_STATIC 1 +#define CONFIG_SWSCALE_ALPHA 1 +#define CONFIG_UNSTABLE 1 +#define CONFIG_GPL 0 +#define CONFIG_NONFREE 0 +#define CONFIG_VERSION3 0 +#define CONFIG_AVDEVICE 0 +#define CONFIG_AVFILTER 0 +#define CONFIG_SWSCALE 1 +#define CONFIG_AVFORMAT 0 +#define CONFIG_AVCODEC 0 +#define CONFIG_SWRESAMPLE 1 +#define CONFIG_AVUTIL 1 +#define CONFIG_FFPLAY 0 +#define CONFIG_FFPROBE 0 +#define CONFIG_FFMPEG 0 +#define CONFIG_DWT 0 +#define CONFIG_ERROR_RESILIENCE 0 +#define CONFIG_FAAN 1 +#define CONFIG_FAST_UNALIGNED 0 +#define CONFIG_IAMF 1 +#define CONFIG_LSP 0 +#define CONFIG_PIXELUTILS 0 +#define CONFIG_NETWORK 0 +#define CONFIG_AUTODETECT 0 +#define CONFIG_FONTCONFIG 0 +#define CONFIG_LARGE_TESTS 1 +#define CONFIG_LINUX_PERF 0 +#define CONFIG_MACOS_KPERF 0 +#define CONFIG_MEMORY_POISONING 0 +#define CONFIG_NEON_CLOBBER_TEST 0 +#define CONFIG_OSSFUZZ 0 +#define CONFIG_PIC 0 +#define CONFIG_SHADER_COMPRESSION 0 +#define CONFIG_RESOURCE_COMPRESSION 0 +#define CONFIG_THUMB 0 +#define CONFIG_VALGRIND_BACKTRACE 0 +#define CONFIG_XMM_CLOBBER_TEST 0 +#define CONFIG_BSFS 0 +#define CONFIG_DECODERS 0 +#define CONFIG_ENCODERS 0 +#define CONFIG_HWACCELS 0 +#define CONFIG_PARSERS 0 +#define CONFIG_INDEVS 0 +#define CONFIG_OUTDEVS 0 +#define CONFIG_FILTERS 0 +#define CONFIG_DEMUXERS 0 +#define CONFIG_MUXERS 0 +#define CONFIG_PROTOCOLS 0 +#define CONFIG_AANDCTTABLES 0 +#define CONFIG_AC3DSP 0 +#define CONFIG_ADTS_HEADER 0 +#define CONFIG_ATSC_A53 0 +#define CONFIG_AUDIO_FRAME_QUEUE 0 +#define CONFIG_AUDIODSP 0 +#define CONFIG_BLOCKDSP 0 +#define CONFIG_BSWAPDSP 0 +#define CONFIG_CABAC 0 +#define CONFIG_CBS 0 +#define CONFIG_CBS_APV 0 +#define CONFIG_CBS_AV1 0 +#define CONFIG_CBS_H264 0 +#define CONFIG_CBS_H265 0 +#define CONFIG_CBS_H266 0 +#define CONFIG_CBS_JPEG 0 +#define CONFIG_CBS_LCEVC 0 +#define CONFIG_CBS_MPEG2 0 +#define CONFIG_CBS_VP8 0 +#define CONFIG_CBS_VP9 0 +#define CONFIG_CELP_MATH 0 +#define CONFIG_D3D12_INTRA_REFRESH 1 +#define CONFIG_D3D12_MOTION_ESTIMATOR 1 +#define CONFIG_D3D12_VIDEO_PROCESS_REFERENCE_INFO 0 +#define CONFIG_D3D12VA_ENCODE 0 +#define CONFIG_D3D12VA_ME_PRECISION_EIGHTH_PIXEL 1 +#define CONFIG_DEFLATE_WRAPPER 0 +#define CONFIG_DIRAC_PARSE 0 +#define CONFIG_DNN 0 +#define CONFIG_DOVI_RPUDEC 0 +#define CONFIG_DOVI_RPUENC 0 +#define CONFIG_DVPROFILE 0 +#define CONFIG_EVCPARSE 0 +#define CONFIG_FAANDCT 1 +#define CONFIG_FAANIDCT 1 +#define CONFIG_FDCTDSP 1 +#define CONFIG_FMTCONVERT 0 +#define CONFIG_FRAME_THREAD_ENCODER 0 +#define CONFIG_G722DSP 0 +#define CONFIG_GOLOMB 0 +#define CONFIG_GPLV3 0 +#define CONFIG_H263DSP 0 +#define CONFIG_H264CHROMA 0 +#define CONFIG_H264DSP 0 +#define CONFIG_H264PARSE 0 +#define CONFIG_H264PRED 0 +#define CONFIG_H264QPEL 0 +#define CONFIG_H264_SEI 0 +#define CONFIG_HEVCPARSE 0 +#define CONFIG_HEVC_SEI 0 +#define CONFIG_HPELDSP 0 +#define CONFIG_HUFFMAN 0 +#define CONFIG_HUFFYUVDSP 0 +#define CONFIG_HUFFYUVENCDSP 0 +#define CONFIG_IAMFDEC 0 +#define CONFIG_IAMFENC 0 +#define CONFIG_IDCTDSP 1 +#define CONFIG_INFLATE_WRAPPER 0 +#define CONFIG_INTRAX8 0 +#define CONFIG_ISO_MEDIA 0 +#define CONFIG_ISO_WRITER 0 +#define CONFIG_IVIDSP 0 +#define CONFIG_JPEGTABLES 0 +#define CONFIG_LGPLV3 0 +#define CONFIG_LIBX262 0 +#define CONFIG_LIBX264_HDR10 0 +#define CONFIG_LLAUDDSP 0 +#define CONFIG_LLVIDDSP 0 +#define CONFIG_LLVIDENCDSP 0 +#define CONFIG_LPC 0 +#define CONFIG_LZF 0 +#define CONFIG_ME_CMP 0 +#define CONFIG_MPEG_ER 0 +#define CONFIG_MPEGAUDIO 0 +#define CONFIG_MPEGAUDIODSP 0 +#define CONFIG_MPEGAUDIOHEADER 0 +#define CONFIG_MPEG4AUDIO 0 +#define CONFIG_MPEGVIDEO 0 +#define CONFIG_MPEGVIDEODEC 0 +#define CONFIG_MPEGVIDEOENC 0 +#define CONFIG_MPEGVIDEOENCDSP 0 +#define CONFIG_MSMPEG4DEC 0 +#define CONFIG_MSMPEG4ENC 0 +#define CONFIG_MSS34DSP 0 +#define CONFIG_PIXBLOCKDSP 0 +#define CONFIG_QPELDSP 0 +#define CONFIG_QSV 0 +#define CONFIG_QSVDEC 0 +#define CONFIG_QSVENC 0 +#define CONFIG_QSVVPP 0 +#define CONFIG_RANGECODER 0 +#define CONFIG_RIFFDEC 0 +#define CONFIG_RIFFENC 0 +#define CONFIG_RTPDEC 0 +#define CONFIG_RTPENC_CHAIN 0 +#define CONFIG_RV34DSP 0 +#define CONFIG_SCENE_SAD 0 +#define CONFIG_SINEWIN 0 +#define CONFIG_SMPTE_436M 0 +#define CONFIG_SNAPPY 0 +#define CONFIG_SRTP 0 +#define CONFIG_STARTCODE 0 +#define CONFIG_TEXTUREDSP 0 +#define CONFIG_TEXTUREDSPENC 0 +#define CONFIG_TPELDSP 0 +#define CONFIG_VAAPI_1 0 +#define CONFIG_VAAPI_ENCODE 0 +#define CONFIG_VULKAN_1_4 0 +#define CONFIG_VC1DSP 0 +#define CONFIG_VIDEODSP 0 +#define CONFIG_VP3DSP 0 +#define CONFIG_VP8DSP 0 +#define CONFIG_VULKAN_ENCODE 0 +#define CONFIG_VVC_SEI 0 +#define CONFIG_WMA_FREQS 0 +#define CONFIG_WMV2DSP 0 +#endif /* FFMPEG_CONFIG_H */ diff --git a/libs/ffmpeg/config_components.asm b/libs/ffmpeg/config_components.asm new file mode 100644 index 00000000000..fb59e0d165c --- /dev/null +++ b/libs/ffmpeg/config_components.asm @@ -0,0 +1,2305 @@ +; Automatically generated by configure - do not modify! +%define CONFIG_AAC_ADTSTOASC_BSF 0 +%define CONFIG_AHX_TO_MP2_BSF 0 +%define CONFIG_APV_METADATA_BSF 0 +%define CONFIG_AV1_FRAME_MERGE_BSF 0 +%define CONFIG_AV1_FRAME_SPLIT_BSF 0 +%define CONFIG_AV1_METADATA_BSF 0 +%define CONFIG_CHOMP_BSF 0 +%define CONFIG_DUMP_EXTRADATA_BSF 0 +%define CONFIG_DCA_CORE_BSF 0 +%define CONFIG_DOVI_RPU_BSF 0 +%define CONFIG_DTS2PTS_BSF 0 +%define CONFIG_DV_ERROR_MARKER_BSF 0 +%define CONFIG_EAC3_CORE_BSF 0 +%define CONFIG_EIA608_TO_SMPTE436M_BSF 0 +%define CONFIG_EVC_FRAME_MERGE_BSF 0 +%define CONFIG_EXTRACT_EXTRADATA_BSF 0 +%define CONFIG_FILTER_UNITS_BSF 0 +%define CONFIG_H264_METADATA_BSF 0 +%define CONFIG_H264_MP4TOANNEXB_BSF 0 +%define CONFIG_H264_REDUNDANT_PPS_BSF 0 +%define CONFIG_HAPQA_EXTRACT_BSF 0 +%define CONFIG_HEVC_METADATA_BSF 0 +%define CONFIG_HEVC_MP4TOANNEXB_BSF 0 +%define CONFIG_IMX_DUMP_HEADER_BSF 0 +%define CONFIG_LCEVC_METADATA_BSF 0 +%define CONFIG_MEDIA100_TO_MJPEGB_BSF 0 +%define CONFIG_MJPEG2JPEG_BSF 0 +%define CONFIG_MJPEGA_DUMP_HEADER_BSF 0 +%define CONFIG_MPEG2_METADATA_BSF 0 +%define CONFIG_MPEG4_UNPACK_BFRAMES_BSF 0 +%define CONFIG_MOV2TEXTSUB_BSF 0 +%define CONFIG_NOISE_BSF 0 +%define CONFIG_NULL_BSF 0 +%define CONFIG_OPUS_METADATA_BSF 0 +%define CONFIG_PCM_RECHUNK_BSF 0 +%define CONFIG_PGS_FRAME_MERGE_BSF 0 +%define CONFIG_PRORES_METADATA_BSF 0 +%define CONFIG_REMOVE_EXTRADATA_BSF 0 +%define CONFIG_SETTS_BSF 0 +%define CONFIG_SHOWINFO_BSF 0 +%define CONFIG_SMPTE436M_TO_EIA608_BSF 0 +%define CONFIG_TEXT2MOVSUB_BSF 0 +%define CONFIG_TRACE_HEADERS_BSF 0 +%define CONFIG_TRUEHD_CORE_BSF 0 +%define CONFIG_VP9_METADATA_BSF 0 +%define CONFIG_VP9_RAW_REORDER_BSF 0 +%define CONFIG_VP9_SUPERFRAME_BSF 0 +%define CONFIG_VP9_SUPERFRAME_SPLIT_BSF 0 +%define CONFIG_VVC_METADATA_BSF 0 +%define CONFIG_VVC_MP4TOANNEXB_BSF 0 +%define CONFIG_AASC_DECODER 0 +%define CONFIG_AIC_DECODER 0 +%define CONFIG_ALIAS_PIX_DECODER 0 +%define CONFIG_AGM_DECODER 0 +%define CONFIG_AMV_DECODER 0 +%define CONFIG_ANM_DECODER 0 +%define CONFIG_ANSI_DECODER 0 +%define CONFIG_APNG_DECODER 0 +%define CONFIG_APV_DECODER 0 +%define CONFIG_ARBC_DECODER 0 +%define CONFIG_ARGO_DECODER 0 +%define CONFIG_ASV1_DECODER 0 +%define CONFIG_ASV2_DECODER 0 +%define CONFIG_AURA_DECODER 0 +%define CONFIG_AURA2_DECODER 0 +%define CONFIG_AVRP_DECODER 0 +%define CONFIG_AVRN_DECODER 0 +%define CONFIG_AVS_DECODER 0 +%define CONFIG_AVUI_DECODER 0 +%define CONFIG_BETHSOFTVID_DECODER 0 +%define CONFIG_BFI_DECODER 0 +%define CONFIG_BINK_DECODER 0 +%define CONFIG_BITPACKED_DECODER 0 +%define CONFIG_BMP_DECODER 0 +%define CONFIG_BMV_VIDEO_DECODER 0 +%define CONFIG_BRENDER_PIX_DECODER 0 +%define CONFIG_C93_DECODER 0 +%define CONFIG_CAVS_DECODER 0 +%define CONFIG_CDGRAPHICS_DECODER 0 +%define CONFIG_CDTOONS_DECODER 0 +%define CONFIG_CDXL_DECODER 0 +%define CONFIG_CFHD_DECODER 0 +%define CONFIG_CINEPAK_DECODER 0 +%define CONFIG_CLEARVIDEO_DECODER 0 +%define CONFIG_CLJR_DECODER 0 +%define CONFIG_CLLC_DECODER 0 +%define CONFIG_COMFORTNOISE_DECODER 0 +%define CONFIG_CPIA_DECODER 0 +%define CONFIG_CRI_DECODER 0 +%define CONFIG_CSCD_DECODER 0 +%define CONFIG_CYUV_DECODER 0 +%define CONFIG_DDS_DECODER 0 +%define CONFIG_DFA_DECODER 0 +%define CONFIG_DIRAC_DECODER 0 +%define CONFIG_DNXHD_DECODER 0 +%define CONFIG_DPX_DECODER 0 +%define CONFIG_DSICINVIDEO_DECODER 0 +%define CONFIG_DVAUDIO_DECODER 0 +%define CONFIG_DVVIDEO_DECODER 0 +%define CONFIG_DXA_DECODER 0 +%define CONFIG_DXTORY_DECODER 0 +%define CONFIG_DXV_DECODER 0 +%define CONFIG_EACMV_DECODER 0 +%define CONFIG_EAMAD_DECODER 0 +%define CONFIG_EATGQ_DECODER 0 +%define CONFIG_EATGV_DECODER 0 +%define CONFIG_EATQI_DECODER 0 +%define CONFIG_EIGHTBPS_DECODER 0 +%define CONFIG_EIGHTSVX_EXP_DECODER 0 +%define CONFIG_EIGHTSVX_FIB_DECODER 0 +%define CONFIG_ESCAPE124_DECODER 0 +%define CONFIG_ESCAPE130_DECODER 0 +%define CONFIG_EXR_DECODER 0 +%define CONFIG_FFV1_DECODER 0 +%define CONFIG_FFVHUFF_DECODER 0 +%define CONFIG_FIC_DECODER 0 +%define CONFIG_FITS_DECODER 0 +%define CONFIG_FLASHSV_DECODER 0 +%define CONFIG_FLASHSV2_DECODER 0 +%define CONFIG_FLIC_DECODER 0 +%define CONFIG_FLV_DECODER 0 +%define CONFIG_FMVC_DECODER 0 +%define CONFIG_FOURXM_DECODER 0 +%define CONFIG_FRAPS_DECODER 0 +%define CONFIG_FRWU_DECODER 0 +%define CONFIG_G2M_DECODER 0 +%define CONFIG_GDV_DECODER 0 +%define CONFIG_GEM_DECODER 0 +%define CONFIG_GIF_DECODER 0 +%define CONFIG_H261_DECODER 0 +%define CONFIG_H263_DECODER 0 +%define CONFIG_H263I_DECODER 0 +%define CONFIG_H263P_DECODER 0 +%define CONFIG_H263_V4L2M2M_DECODER 0 +%define CONFIG_H264_DECODER 0 +%define CONFIG_H264_V4L2M2M_DECODER 0 +%define CONFIG_H264_MEDIACODEC_DECODER 0 +%define CONFIG_H264_MMAL_DECODER 0 +%define CONFIG_H264_QSV_DECODER 0 +%define CONFIG_H264_RKMPP_DECODER 0 +%define CONFIG_HAP_DECODER 0 +%define CONFIG_HEVC_DECODER 0 +%define CONFIG_HEVC_QSV_DECODER 0 +%define CONFIG_HEVC_RKMPP_DECODER 0 +%define CONFIG_HEVC_V4L2M2M_DECODER 0 +%define CONFIG_HNM4_VIDEO_DECODER 0 +%define CONFIG_HQ_HQA_DECODER 0 +%define CONFIG_HQX_DECODER 0 +%define CONFIG_HUFFYUV_DECODER 0 +%define CONFIG_HYMT_DECODER 0 +%define CONFIG_IDCIN_DECODER 0 +%define CONFIG_IFF_ILBM_DECODER 0 +%define CONFIG_IMM4_DECODER 0 +%define CONFIG_IMM5_DECODER 0 +%define CONFIG_INDEO2_DECODER 0 +%define CONFIG_INDEO3_DECODER 0 +%define CONFIG_INDEO4_DECODER 0 +%define CONFIG_INDEO5_DECODER 0 +%define CONFIG_INTERPLAY_VIDEO_DECODER 0 +%define CONFIG_IPU_DECODER 0 +%define CONFIG_JPEG2000_DECODER 0 +%define CONFIG_JPEGLS_DECODER 0 +%define CONFIG_JV_DECODER 0 +%define CONFIG_KGV1_DECODER 0 +%define CONFIG_KMVC_DECODER 0 +%define CONFIG_LAGARITH_DECODER 0 +%define CONFIG_LEAD_DECODER 0 +%define CONFIG_LOCO_DECODER 0 +%define CONFIG_LSCR_DECODER 0 +%define CONFIG_M101_DECODER 0 +%define CONFIG_MAGICYUV_DECODER 0 +%define CONFIG_MDEC_DECODER 0 +%define CONFIG_MEDIA100_DECODER 0 +%define CONFIG_MIMIC_DECODER 0 +%define CONFIG_MJPEG_DECODER 0 +%define CONFIG_MJPEGB_DECODER 0 +%define CONFIG_MMVIDEO_DECODER 0 +%define CONFIG_MOBICLIP_DECODER 0 +%define CONFIG_MOTIONPIXELS_DECODER 0 +%define CONFIG_MPEG1VIDEO_DECODER 0 +%define CONFIG_MPEG2VIDEO_DECODER 0 +%define CONFIG_MPEG4_DECODER 0 +%define CONFIG_MPEG4_V4L2M2M_DECODER 0 +%define CONFIG_MPEG4_MMAL_DECODER 0 +%define CONFIG_MPEGVIDEO_DECODER 0 +%define CONFIG_MPEG1_V4L2M2M_DECODER 0 +%define CONFIG_MPEG2_MMAL_DECODER 0 +%define CONFIG_MPEG2_V4L2M2M_DECODER 0 +%define CONFIG_MPEG2_QSV_DECODER 0 +%define CONFIG_MPEG2_MEDIACODEC_DECODER 0 +%define CONFIG_MSA1_DECODER 0 +%define CONFIG_MSCC_DECODER 0 +%define CONFIG_MSMPEG4V1_DECODER 0 +%define CONFIG_MSMPEG4V2_DECODER 0 +%define CONFIG_MSMPEG4V3_DECODER 0 +%define CONFIG_MSP2_DECODER 0 +%define CONFIG_MSRLE_DECODER 0 +%define CONFIG_MSS1_DECODER 0 +%define CONFIG_MSS2_DECODER 0 +%define CONFIG_MSVIDEO1_DECODER 0 +%define CONFIG_MSZH_DECODER 0 +%define CONFIG_MTS2_DECODER 0 +%define CONFIG_MV30_DECODER 0 +%define CONFIG_MVC1_DECODER 0 +%define CONFIG_MVC2_DECODER 0 +%define CONFIG_MVDV_DECODER 0 +%define CONFIG_MVHA_DECODER 0 +%define CONFIG_MWSC_DECODER 0 +%define CONFIG_MXPEG_DECODER 0 +%define CONFIG_NOTCHLC_DECODER 0 +%define CONFIG_NUV_DECODER 0 +%define CONFIG_PAF_VIDEO_DECODER 0 +%define CONFIG_PAM_DECODER 0 +%define CONFIG_PBM_DECODER 0 +%define CONFIG_PCX_DECODER 0 +%define CONFIG_PDV_DECODER 0 +%define CONFIG_PFM_DECODER 0 +%define CONFIG_PGM_DECODER 0 +%define CONFIG_PGMYUV_DECODER 0 +%define CONFIG_PGX_DECODER 0 +%define CONFIG_PHM_DECODER 0 +%define CONFIG_PHOTOCD_DECODER 0 +%define CONFIG_PICTOR_DECODER 0 +%define CONFIG_PIXLET_DECODER 0 +%define CONFIG_PNG_DECODER 0 +%define CONFIG_PPM_DECODER 0 +%define CONFIG_PRORES_DECODER 0 +%define CONFIG_PRORES_RAW_DECODER 0 +%define CONFIG_PROSUMER_DECODER 0 +%define CONFIG_PSD_DECODER 0 +%define CONFIG_PTX_DECODER 0 +%define CONFIG_QDRAW_DECODER 0 +%define CONFIG_QOI_DECODER 0 +%define CONFIG_QPEG_DECODER 0 +%define CONFIG_QTRLE_DECODER 0 +%define CONFIG_R10K_DECODER 0 +%define CONFIG_R210_DECODER 0 +%define CONFIG_RASC_DECODER 0 +%define CONFIG_RAWVIDEO_DECODER 0 +%define CONFIG_RKA_DECODER 0 +%define CONFIG_RL2_DECODER 0 +%define CONFIG_ROQ_DECODER 0 +%define CONFIG_RPZA_DECODER 0 +%define CONFIG_RSCC_DECODER 0 +%define CONFIG_RTV1_DECODER 0 +%define CONFIG_RV10_DECODER 0 +%define CONFIG_RV20_DECODER 0 +%define CONFIG_RV30_DECODER 0 +%define CONFIG_RV40_DECODER 0 +%define CONFIG_RV60_DECODER 0 +%define CONFIG_S302M_DECODER 0 +%define CONFIG_SANM_DECODER 0 +%define CONFIG_SCPR_DECODER 0 +%define CONFIG_SCREENPRESSO_DECODER 0 +%define CONFIG_SGA_DECODER 0 +%define CONFIG_SGI_DECODER 0 +%define CONFIG_SGIRLE_DECODER 0 +%define CONFIG_SHEERVIDEO_DECODER 0 +%define CONFIG_SIMBIOSIS_IMX_DECODER 0 +%define CONFIG_SMACKER_DECODER 0 +%define CONFIG_SMC_DECODER 0 +%define CONFIG_SMVJPEG_DECODER 0 +%define CONFIG_SNOW_DECODER 0 +%define CONFIG_SP5X_DECODER 0 +%define CONFIG_SPEEDHQ_DECODER 0 +%define CONFIG_SPEEX_DECODER 0 +%define CONFIG_SRGC_DECODER 0 +%define CONFIG_SUNRAST_DECODER 0 +%define CONFIG_SVQ1_DECODER 0 +%define CONFIG_SVQ3_DECODER 0 +%define CONFIG_TARGA_DECODER 0 +%define CONFIG_TARGA_Y216_DECODER 0 +%define CONFIG_TDSC_DECODER 0 +%define CONFIG_THEORA_DECODER 0 +%define CONFIG_THP_DECODER 0 +%define CONFIG_TIERTEXSEQVIDEO_DECODER 0 +%define CONFIG_TIFF_DECODER 0 +%define CONFIG_TMV_DECODER 0 +%define CONFIG_TRUEMOTION1_DECODER 0 +%define CONFIG_TRUEMOTION2_DECODER 0 +%define CONFIG_TRUEMOTION2RT_DECODER 0 +%define CONFIG_TSCC_DECODER 0 +%define CONFIG_TSCC2_DECODER 0 +%define CONFIG_TXD_DECODER 0 +%define CONFIG_ULTI_DECODER 0 +%define CONFIG_UTVIDEO_DECODER 0 +%define CONFIG_V210_DECODER 0 +%define CONFIG_V210X_DECODER 0 +%define CONFIG_V308_DECODER 0 +%define CONFIG_V408_DECODER 0 +%define CONFIG_V410_DECODER 0 +%define CONFIG_VB_DECODER 0 +%define CONFIG_VBN_DECODER 0 +%define CONFIG_VBLE_DECODER 0 +%define CONFIG_VC1_DECODER 0 +%define CONFIG_VC1IMAGE_DECODER 0 +%define CONFIG_VC1_MMAL_DECODER 0 +%define CONFIG_VC1_QSV_DECODER 0 +%define CONFIG_VC1_V4L2M2M_DECODER 0 +%define CONFIG_VCR1_DECODER 0 +%define CONFIG_VMDVIDEO_DECODER 0 +%define CONFIG_VMIX_DECODER 0 +%define CONFIG_VMNC_DECODER 0 +%define CONFIG_VP3_DECODER 0 +%define CONFIG_VP4_DECODER 0 +%define CONFIG_VP5_DECODER 0 +%define CONFIG_VP6_DECODER 0 +%define CONFIG_VP6A_DECODER 0 +%define CONFIG_VP6F_DECODER 0 +%define CONFIG_VP7_DECODER 0 +%define CONFIG_VP8_DECODER 0 +%define CONFIG_VP8_RKMPP_DECODER 0 +%define CONFIG_VP8_V4L2M2M_DECODER 0 +%define CONFIG_VP9_DECODER 0 +%define CONFIG_VP9_RKMPP_DECODER 0 +%define CONFIG_VP9_V4L2M2M_DECODER 0 +%define CONFIG_VQA_DECODER 0 +%define CONFIG_VQC_DECODER 0 +%define CONFIG_VVC_DECODER 0 +%define CONFIG_WBMP_DECODER 0 +%define CONFIG_WEBP_DECODER 0 +%define CONFIG_WCMV_DECODER 0 +%define CONFIG_WRAPPED_AVFRAME_DECODER 0 +%define CONFIG_WMV1_DECODER 0 +%define CONFIG_WMV2_DECODER 0 +%define CONFIG_WMV3_DECODER 0 +%define CONFIG_WMV3IMAGE_DECODER 0 +%define CONFIG_WNV1_DECODER 0 +%define CONFIG_XAN_WC3_DECODER 0 +%define CONFIG_XAN_WC4_DECODER 0 +%define CONFIG_XBM_DECODER 0 +%define CONFIG_XFACE_DECODER 0 +%define CONFIG_XL_DECODER 0 +%define CONFIG_XPM_DECODER 0 +%define CONFIG_XWD_DECODER 0 +%define CONFIG_Y41P_DECODER 0 +%define CONFIG_YLC_DECODER 0 +%define CONFIG_YOP_DECODER 0 +%define CONFIG_YUV4_DECODER 0 +%define CONFIG_ZERO12V_DECODER 0 +%define CONFIG_ZEROCODEC_DECODER 0 +%define CONFIG_ZLIB_DECODER 0 +%define CONFIG_ZMBV_DECODER 0 +%define CONFIG_AAC_DECODER 0 +%define CONFIG_AAC_FIXED_DECODER 0 +%define CONFIG_AAC_LATM_DECODER 0 +%define CONFIG_AC3_DECODER 0 +%define CONFIG_AC3_FIXED_DECODER 0 +%define CONFIG_ACELP_KELVIN_DECODER 0 +%define CONFIG_AHX_DECODER 0 +%define CONFIG_ALAC_DECODER 0 +%define CONFIG_ALS_DECODER 0 +%define CONFIG_AMRNB_DECODER 0 +%define CONFIG_AMRWB_DECODER 0 +%define CONFIG_APAC_DECODER 0 +%define CONFIG_APE_DECODER 0 +%define CONFIG_APTX_DECODER 0 +%define CONFIG_APTX_HD_DECODER 0 +%define CONFIG_ATRAC1_DECODER 0 +%define CONFIG_ATRAC3_DECODER 0 +%define CONFIG_ATRAC3AL_DECODER 0 +%define CONFIG_ATRAC3P_DECODER 0 +%define CONFIG_ATRAC3PAL_DECODER 0 +%define CONFIG_ATRAC9_DECODER 0 +%define CONFIG_BINKAUDIO_DCT_DECODER 0 +%define CONFIG_BINKAUDIO_RDFT_DECODER 0 +%define CONFIG_BMV_AUDIO_DECODER 0 +%define CONFIG_BONK_DECODER 0 +%define CONFIG_COOK_DECODER 0 +%define CONFIG_DCA_DECODER 0 +%define CONFIG_DFPWM_DECODER 0 +%define CONFIG_DOLBY_E_DECODER 0 +%define CONFIG_DSD_LSBF_DECODER 0 +%define CONFIG_DSD_MSBF_DECODER 0 +%define CONFIG_DSD_LSBF_PLANAR_DECODER 0 +%define CONFIG_DSD_MSBF_PLANAR_DECODER 0 +%define CONFIG_DSICINAUDIO_DECODER 0 +%define CONFIG_DSS_SP_DECODER 0 +%define CONFIG_DST_DECODER 0 +%define CONFIG_EAC3_DECODER 0 +%define CONFIG_EVRC_DECODER 0 +%define CONFIG_FASTAUDIO_DECODER 0 +%define CONFIG_FFWAVESYNTH_DECODER 0 +%define CONFIG_FLAC_DECODER 0 +%define CONFIG_FTR_DECODER 0 +%define CONFIG_G723_1_DECODER 0 +%define CONFIG_G728_DECODER 0 +%define CONFIG_G729_DECODER 0 +%define CONFIG_GSM_DECODER 0 +%define CONFIG_GSM_MS_DECODER 0 +%define CONFIG_HCA_DECODER 0 +%define CONFIG_HCOM_DECODER 0 +%define CONFIG_HDR_DECODER 0 +%define CONFIG_IAC_DECODER 0 +%define CONFIG_ILBC_DECODER 0 +%define CONFIG_IMC_DECODER 0 +%define CONFIG_INTERPLAY_ACM_DECODER 0 +%define CONFIG_MACE3_DECODER 0 +%define CONFIG_MACE6_DECODER 0 +%define CONFIG_METASOUND_DECODER 0 +%define CONFIG_MISC4_DECODER 0 +%define CONFIG_MLP_DECODER 0 +%define CONFIG_MP1_DECODER 0 +%define CONFIG_MP1FLOAT_DECODER 0 +%define CONFIG_MP2_DECODER 0 +%define CONFIG_MP2FLOAT_DECODER 0 +%define CONFIG_MP3FLOAT_DECODER 0 +%define CONFIG_MP3_DECODER 0 +%define CONFIG_MP3ADUFLOAT_DECODER 0 +%define CONFIG_MP3ADU_DECODER 0 +%define CONFIG_MP3ON4FLOAT_DECODER 0 +%define CONFIG_MP3ON4_DECODER 0 +%define CONFIG_MPC7_DECODER 0 +%define CONFIG_MPC8_DECODER 0 +%define CONFIG_MSNSIREN_DECODER 0 +%define CONFIG_NELLYMOSER_DECODER 0 +%define CONFIG_ON2AVC_DECODER 0 +%define CONFIG_OPUS_DECODER 0 +%define CONFIG_OSQ_DECODER 0 +%define CONFIG_PAF_AUDIO_DECODER 0 +%define CONFIG_QCELP_DECODER 0 +%define CONFIG_QDM2_DECODER 0 +%define CONFIG_QDMC_DECODER 0 +%define CONFIG_QOA_DECODER 0 +%define CONFIG_RA_144_DECODER 0 +%define CONFIG_RA_288_DECODER 0 +%define CONFIG_RALF_DECODER 0 +%define CONFIG_SBC_DECODER 0 +%define CONFIG_SHORTEN_DECODER 0 +%define CONFIG_SIPR_DECODER 0 +%define CONFIG_SIREN_DECODER 0 +%define CONFIG_SMACKAUD_DECODER 0 +%define CONFIG_SONIC_DECODER 0 +%define CONFIG_TAK_DECODER 0 +%define CONFIG_TRUEHD_DECODER 0 +%define CONFIG_TRUESPEECH_DECODER 0 +%define CONFIG_TTA_DECODER 0 +%define CONFIG_TWINVQ_DECODER 0 +%define CONFIG_VMDAUDIO_DECODER 0 +%define CONFIG_VORBIS_DECODER 0 +%define CONFIG_WAVARC_DECODER 0 +%define CONFIG_WAVPACK_DECODER 0 +%define CONFIG_WMALOSSLESS_DECODER 0 +%define CONFIG_WMAPRO_DECODER 0 +%define CONFIG_WMAV1_DECODER 0 +%define CONFIG_WMAV2_DECODER 0 +%define CONFIG_WMAVOICE_DECODER 0 +%define CONFIG_WS_SND1_DECODER 0 +%define CONFIG_XMA1_DECODER 0 +%define CONFIG_XMA2_DECODER 0 +%define CONFIG_PCM_ALAW_DECODER 0 +%define CONFIG_PCM_BLURAY_DECODER 0 +%define CONFIG_PCM_DVD_DECODER 0 +%define CONFIG_PCM_F16LE_DECODER 0 +%define CONFIG_PCM_F24LE_DECODER 0 +%define CONFIG_PCM_F32BE_DECODER 0 +%define CONFIG_PCM_F32LE_DECODER 0 +%define CONFIG_PCM_F64BE_DECODER 0 +%define CONFIG_PCM_F64LE_DECODER 0 +%define CONFIG_PCM_LXF_DECODER 0 +%define CONFIG_PCM_MULAW_DECODER 0 +%define CONFIG_PCM_S8_DECODER 0 +%define CONFIG_PCM_S8_PLANAR_DECODER 0 +%define CONFIG_PCM_S16BE_DECODER 0 +%define CONFIG_PCM_S16BE_PLANAR_DECODER 0 +%define CONFIG_PCM_S16LE_DECODER 0 +%define CONFIG_PCM_S16LE_PLANAR_DECODER 0 +%define CONFIG_PCM_S24BE_DECODER 0 +%define CONFIG_PCM_S24DAUD_DECODER 0 +%define CONFIG_PCM_S24LE_DECODER 0 +%define CONFIG_PCM_S24LE_PLANAR_DECODER 0 +%define CONFIG_PCM_S32BE_DECODER 0 +%define CONFIG_PCM_S32LE_DECODER 0 +%define CONFIG_PCM_S32LE_PLANAR_DECODER 0 +%define CONFIG_PCM_S64BE_DECODER 0 +%define CONFIG_PCM_S64LE_DECODER 0 +%define CONFIG_PCM_SGA_DECODER 0 +%define CONFIG_PCM_U8_DECODER 0 +%define CONFIG_PCM_U16BE_DECODER 0 +%define CONFIG_PCM_U16LE_DECODER 0 +%define CONFIG_PCM_U24BE_DECODER 0 +%define CONFIG_PCM_U24LE_DECODER 0 +%define CONFIG_PCM_U32BE_DECODER 0 +%define CONFIG_PCM_U32LE_DECODER 0 +%define CONFIG_PCM_VIDC_DECODER 0 +%define CONFIG_CBD2_DPCM_DECODER 0 +%define CONFIG_DERF_DPCM_DECODER 0 +%define CONFIG_GREMLIN_DPCM_DECODER 0 +%define CONFIG_INTERPLAY_DPCM_DECODER 0 +%define CONFIG_ROQ_DPCM_DECODER 0 +%define CONFIG_SDX2_DPCM_DECODER 0 +%define CONFIG_SOL_DPCM_DECODER 0 +%define CONFIG_XAN_DPCM_DECODER 0 +%define CONFIG_WADY_DPCM_DECODER 0 +%define CONFIG_ADPCM_4XM_DECODER 0 +%define CONFIG_ADPCM_ADX_DECODER 0 +%define CONFIG_ADPCM_AFC_DECODER 0 +%define CONFIG_ADPCM_AGM_DECODER 0 +%define CONFIG_ADPCM_AICA_DECODER 0 +%define CONFIG_ADPCM_ARGO_DECODER 0 +%define CONFIG_ADPCM_CIRCUS_DECODER 0 +%define CONFIG_ADPCM_CT_DECODER 0 +%define CONFIG_ADPCM_DTK_DECODER 0 +%define CONFIG_ADPCM_EA_DECODER 0 +%define CONFIG_ADPCM_EA_MAXIS_XA_DECODER 0 +%define CONFIG_ADPCM_EA_R1_DECODER 0 +%define CONFIG_ADPCM_EA_R2_DECODER 0 +%define CONFIG_ADPCM_EA_R3_DECODER 0 +%define CONFIG_ADPCM_EA_XAS_DECODER 0 +%define CONFIG_ADPCM_G722_DECODER 0 +%define CONFIG_ADPCM_G726_DECODER 0 +%define CONFIG_ADPCM_G726LE_DECODER 0 +%define CONFIG_ADPCM_IMA_ACORN_DECODER 0 +%define CONFIG_ADPCM_IMA_AMV_DECODER 0 +%define CONFIG_ADPCM_IMA_ALP_DECODER 0 +%define CONFIG_ADPCM_IMA_APC_DECODER 0 +%define CONFIG_ADPCM_IMA_APM_DECODER 0 +%define CONFIG_ADPCM_IMA_CUNNING_DECODER 0 +%define CONFIG_ADPCM_IMA_DAT4_DECODER 0 +%define CONFIG_ADPCM_IMA_DK3_DECODER 0 +%define CONFIG_ADPCM_IMA_DK4_DECODER 0 +%define CONFIG_ADPCM_IMA_EA_EACS_DECODER 0 +%define CONFIG_ADPCM_IMA_EA_SEAD_DECODER 0 +%define CONFIG_ADPCM_IMA_ESCAPE_DECODER 0 +%define CONFIG_ADPCM_IMA_HVQM2_DECODER 0 +%define CONFIG_ADPCM_IMA_HVQM4_DECODER 0 +%define CONFIG_ADPCM_IMA_ISS_DECODER 0 +%define CONFIG_ADPCM_IMA_MAGIX_DECODER 0 +%define CONFIG_ADPCM_IMA_MOFLEX_DECODER 0 +%define CONFIG_ADPCM_IMA_MTF_DECODER 0 +%define CONFIG_ADPCM_IMA_OKI_DECODER 0 +%define CONFIG_ADPCM_IMA_PDA_DECODER 0 +%define CONFIG_ADPCM_IMA_QT_DECODER 0 +%define CONFIG_ADPCM_IMA_RAD_DECODER 0 +%define CONFIG_ADPCM_IMA_SSI_DECODER 0 +%define CONFIG_ADPCM_IMA_SMJPEG_DECODER 0 +%define CONFIG_ADPCM_IMA_WAV_DECODER 0 +%define CONFIG_ADPCM_IMA_WS_DECODER 0 +%define CONFIG_ADPCM_IMA_XBOX_DECODER 0 +%define CONFIG_ADPCM_MS_DECODER 0 +%define CONFIG_ADPCM_MTAF_DECODER 0 +%define CONFIG_ADPCM_N64_DECODER 0 +%define CONFIG_ADPCM_PSX_DECODER 0 +%define CONFIG_ADPCM_PSXC_DECODER 0 +%define CONFIG_ADPCM_SANYO_DECODER 0 +%define CONFIG_ADPCM_SBPRO_2_DECODER 0 +%define CONFIG_ADPCM_SBPRO_3_DECODER 0 +%define CONFIG_ADPCM_SBPRO_4_DECODER 0 +%define CONFIG_ADPCM_SWF_DECODER 0 +%define CONFIG_ADPCM_THP_DECODER 0 +%define CONFIG_ADPCM_THP_LE_DECODER 0 +%define CONFIG_ADPCM_VIMA_DECODER 0 +%define CONFIG_ADPCM_XA_DECODER 0 +%define CONFIG_ADPCM_XMD_DECODER 0 +%define CONFIG_ADPCM_YAMAHA_DECODER 0 +%define CONFIG_ADPCM_ZORK_DECODER 0 +%define CONFIG_SSA_DECODER 0 +%define CONFIG_ASS_DECODER 0 +%define CONFIG_CCAPTION_DECODER 0 +%define CONFIG_DVBSUB_DECODER 0 +%define CONFIG_DVDSUB_DECODER 0 +%define CONFIG_JACOSUB_DECODER 0 +%define CONFIG_MICRODVD_DECODER 0 +%define CONFIG_MOVTEXT_DECODER 0 +%define CONFIG_MPL2_DECODER 0 +%define CONFIG_PGSSUB_DECODER 0 +%define CONFIG_PJS_DECODER 0 +%define CONFIG_REALTEXT_DECODER 0 +%define CONFIG_SAMI_DECODER 0 +%define CONFIG_SRT_DECODER 0 +%define CONFIG_STL_DECODER 0 +%define CONFIG_SUBRIP_DECODER 0 +%define CONFIG_SUBVIEWER_DECODER 0 +%define CONFIG_SUBVIEWER1_DECODER 0 +%define CONFIG_TEXT_DECODER 0 +%define CONFIG_VPLAYER_DECODER 0 +%define CONFIG_WEBVTT_DECODER 0 +%define CONFIG_XSUB_DECODER 0 +%define CONFIG_AAC_AT_DECODER 0 +%define CONFIG_AC3_AT_DECODER 0 +%define CONFIG_ADPCM_IMA_QT_AT_DECODER 0 +%define CONFIG_ALAC_AT_DECODER 0 +%define CONFIG_AMR_NB_AT_DECODER 0 +%define CONFIG_EAC3_AT_DECODER 0 +%define CONFIG_GSM_MS_AT_DECODER 0 +%define CONFIG_ILBC_AT_DECODER 0 +%define CONFIG_MP1_AT_DECODER 0 +%define CONFIG_MP2_AT_DECODER 0 +%define CONFIG_MP3_AT_DECODER 0 +%define CONFIG_PCM_ALAW_AT_DECODER 0 +%define CONFIG_PCM_MULAW_AT_DECODER 0 +%define CONFIG_QDMC_AT_DECODER 0 +%define CONFIG_QDM2_AT_DECODER 0 +%define CONFIG_LIBARIBCAPTION_DECODER 0 +%define CONFIG_LIBARIBB24_DECODER 0 +%define CONFIG_LIBCELT_DECODER 0 +%define CONFIG_LIBCODEC2_DECODER 0 +%define CONFIG_LIBDAV1D_DECODER 0 +%define CONFIG_LIBDAVS2_DECODER 0 +%define CONFIG_LIBFDK_AAC_DECODER 0 +%define CONFIG_LIBGSM_DECODER 0 +%define CONFIG_LIBGSM_MS_DECODER 0 +%define CONFIG_LIBILBC_DECODER 0 +%define CONFIG_LIBJXL_ANIM_DECODER 0 +%define CONFIG_LIBJXL_DECODER 0 +%define CONFIG_LIBLC3_DECODER 0 +%define CONFIG_LIBMPEGHDEC_DECODER 0 +%define CONFIG_LIBOPENCORE_AMRNB_DECODER 0 +%define CONFIG_LIBOPENCORE_AMRWB_DECODER 0 +%define CONFIG_LIBOPUS_DECODER 0 +%define CONFIG_LIBRSVG_DECODER 0 +%define CONFIG_LIBSPEEX_DECODER 0 +%define CONFIG_LIBSVTJPEGXS_DECODER 0 +%define CONFIG_LIBUAVS3D_DECODER 0 +%define CONFIG_LIBVORBIS_DECODER 0 +%define CONFIG_LIBVPX_VP8_DECODER 0 +%define CONFIG_LIBVPX_VP9_DECODER 0 +%define CONFIG_LIBXEVD_DECODER 0 +%define CONFIG_LIBZVBI_TELETEXT_DECODER 0 +%define CONFIG_BINTEXT_DECODER 0 +%define CONFIG_XBIN_DECODER 0 +%define CONFIG_IDF_DECODER 0 +%define CONFIG_AAC_MEDIACODEC_DECODER 0 +%define CONFIG_AMRNB_MEDIACODEC_DECODER 0 +%define CONFIG_AMRWB_MEDIACODEC_DECODER 0 +%define CONFIG_LIBAOM_AV1_DECODER 0 +%define CONFIG_AV1_DECODER 0 +%define CONFIG_AV1_CUVID_DECODER 0 +%define CONFIG_AV1_MEDIACODEC_DECODER 0 +%define CONFIG_AV1_QSV_DECODER 0 +%define CONFIG_AV1_AMF_DECODER 0 +%define CONFIG_LIBOPENH264_DECODER 0 +%define CONFIG_H264_AMF_DECODER 0 +%define CONFIG_H264_CUVID_DECODER 0 +%define CONFIG_H264_OH_DECODER 0 +%define CONFIG_HEVC_AMF_DECODER 0 +%define CONFIG_HEVC_CUVID_DECODER 0 +%define CONFIG_HEVC_MEDIACODEC_DECODER 0 +%define CONFIG_HEVC_OH_DECODER 0 +%define CONFIG_MJPEG_CUVID_DECODER 0 +%define CONFIG_MJPEG_QSV_DECODER 0 +%define CONFIG_MP3_MEDIACODEC_DECODER 0 +%define CONFIG_MPEG1_CUVID_DECODER 0 +%define CONFIG_MPEG2_CUVID_DECODER 0 +%define CONFIG_MPEG4_CUVID_DECODER 0 +%define CONFIG_MPEG4_MEDIACODEC_DECODER 0 +%define CONFIG_VC1_CUVID_DECODER 0 +%define CONFIG_VP8_CUVID_DECODER 0 +%define CONFIG_VP8_MEDIACODEC_DECODER 0 +%define CONFIG_VP8_QSV_DECODER 0 +%define CONFIG_VP9_AMF_DECODER 0 +%define CONFIG_VP9_CUVID_DECODER 0 +%define CONFIG_VP9_MEDIACODEC_DECODER 0 +%define CONFIG_VP9_QSV_DECODER 0 +%define CONFIG_VVC_QSV_DECODER 0 +%define CONFIG_VNULL_DECODER 0 +%define CONFIG_ANULL_DECODER 0 +%define CONFIG_A64MULTI_ENCODER 0 +%define CONFIG_A64MULTI5_ENCODER 0 +%define CONFIG_ALIAS_PIX_ENCODER 0 +%define CONFIG_AMV_ENCODER 0 +%define CONFIG_APNG_ENCODER 0 +%define CONFIG_ASV1_ENCODER 0 +%define CONFIG_ASV2_ENCODER 0 +%define CONFIG_AVRP_ENCODER 0 +%define CONFIG_AVUI_ENCODER 0 +%define CONFIG_BITPACKED_ENCODER 0 +%define CONFIG_BMP_ENCODER 0 +%define CONFIG_CFHD_ENCODER 0 +%define CONFIG_CINEPAK_ENCODER 0 +%define CONFIG_CLJR_ENCODER 0 +%define CONFIG_COMFORTNOISE_ENCODER 0 +%define CONFIG_DNXHD_ENCODER 0 +%define CONFIG_DPX_ENCODER 0 +%define CONFIG_DVVIDEO_ENCODER 0 +%define CONFIG_DXV_ENCODER 0 +%define CONFIG_EXR_ENCODER 0 +%define CONFIG_FFV1_ENCODER 0 +%define CONFIG_FFV1_VULKAN_ENCODER 0 +%define CONFIG_FFVHUFF_ENCODER 0 +%define CONFIG_FITS_ENCODER 0 +%define CONFIG_FLASHSV_ENCODER 0 +%define CONFIG_FLASHSV2_ENCODER 0 +%define CONFIG_FLV_ENCODER 0 +%define CONFIG_GIF_ENCODER 0 +%define CONFIG_H261_ENCODER 0 +%define CONFIG_H263_ENCODER 0 +%define CONFIG_H263P_ENCODER 0 +%define CONFIG_H264_MEDIACODEC_ENCODER 0 +%define CONFIG_H264_RKMPP_ENCODER 0 +%define CONFIG_HAP_ENCODER 0 +%define CONFIG_HEVC_RKMPP_ENCODER 0 +%define CONFIG_HUFFYUV_ENCODER 0 +%define CONFIG_JPEG2000_ENCODER 0 +%define CONFIG_JPEGLS_ENCODER 0 +%define CONFIG_LJPEG_ENCODER 0 +%define CONFIG_MAGICYUV_ENCODER 0 +%define CONFIG_MJPEG_ENCODER 0 +%define CONFIG_MPEG1VIDEO_ENCODER 0 +%define CONFIG_MPEG2VIDEO_ENCODER 0 +%define CONFIG_MPEG4_ENCODER 0 +%define CONFIG_MSMPEG4V2_ENCODER 0 +%define CONFIG_MSMPEG4V3_ENCODER 0 +%define CONFIG_MSRLE_ENCODER 0 +%define CONFIG_MSVIDEO1_ENCODER 0 +%define CONFIG_PAM_ENCODER 0 +%define CONFIG_PBM_ENCODER 0 +%define CONFIG_PCX_ENCODER 0 +%define CONFIG_PFM_ENCODER 0 +%define CONFIG_PGM_ENCODER 0 +%define CONFIG_PGMYUV_ENCODER 0 +%define CONFIG_PHM_ENCODER 0 +%define CONFIG_PNG_ENCODER 0 +%define CONFIG_PPM_ENCODER 0 +%define CONFIG_PRORES_ENCODER 0 +%define CONFIG_PRORES_AW_ENCODER 0 +%define CONFIG_PRORES_KS_ENCODER 0 +%define CONFIG_PRORES_KS_VULKAN_ENCODER 0 +%define CONFIG_QOI_ENCODER 0 +%define CONFIG_QTRLE_ENCODER 0 +%define CONFIG_R10K_ENCODER 0 +%define CONFIG_R210_ENCODER 0 +%define CONFIG_RAWVIDEO_ENCODER 0 +%define CONFIG_ROQ_ENCODER 0 +%define CONFIG_RPZA_ENCODER 0 +%define CONFIG_RV10_ENCODER 0 +%define CONFIG_RV20_ENCODER 0 +%define CONFIG_S302M_ENCODER 0 +%define CONFIG_SGI_ENCODER 0 +%define CONFIG_SMC_ENCODER 0 +%define CONFIG_SNOW_ENCODER 0 +%define CONFIG_SPEEDHQ_ENCODER 0 +%define CONFIG_SUNRAST_ENCODER 0 +%define CONFIG_SVQ1_ENCODER 0 +%define CONFIG_TARGA_ENCODER 0 +%define CONFIG_TIFF_ENCODER 0 +%define CONFIG_UTVIDEO_ENCODER 0 +%define CONFIG_V210_ENCODER 0 +%define CONFIG_V308_ENCODER 0 +%define CONFIG_V408_ENCODER 0 +%define CONFIG_V410_ENCODER 0 +%define CONFIG_VBN_ENCODER 0 +%define CONFIG_VC2_ENCODER 0 +%define CONFIG_WBMP_ENCODER 0 +%define CONFIG_WRAPPED_AVFRAME_ENCODER 0 +%define CONFIG_WMV1_ENCODER 0 +%define CONFIG_WMV2_ENCODER 0 +%define CONFIG_XBM_ENCODER 0 +%define CONFIG_XFACE_ENCODER 0 +%define CONFIG_XWD_ENCODER 0 +%define CONFIG_Y41P_ENCODER 0 +%define CONFIG_YUV4_ENCODER 0 +%define CONFIG_ZLIB_ENCODER 0 +%define CONFIG_ZMBV_ENCODER 0 +%define CONFIG_AAC_ENCODER 0 +%define CONFIG_AC3_ENCODER 0 +%define CONFIG_AC3_FIXED_ENCODER 0 +%define CONFIG_ALAC_ENCODER 0 +%define CONFIG_APTX_ENCODER 0 +%define CONFIG_APTX_HD_ENCODER 0 +%define CONFIG_DCA_ENCODER 0 +%define CONFIG_DFPWM_ENCODER 0 +%define CONFIG_EAC3_ENCODER 0 +%define CONFIG_FLAC_ENCODER 0 +%define CONFIG_G723_1_ENCODER 0 +%define CONFIG_HDR_ENCODER 0 +%define CONFIG_MLP_ENCODER 0 +%define CONFIG_MP2_ENCODER 0 +%define CONFIG_MP2FIXED_ENCODER 0 +%define CONFIG_NELLYMOSER_ENCODER 0 +%define CONFIG_OPUS_ENCODER 0 +%define CONFIG_RA_144_ENCODER 0 +%define CONFIG_SBC_ENCODER 0 +%define CONFIG_SONIC_ENCODER 0 +%define CONFIG_SONIC_LS_ENCODER 0 +%define CONFIG_TRUEHD_ENCODER 0 +%define CONFIG_TTA_ENCODER 0 +%define CONFIG_VORBIS_ENCODER 0 +%define CONFIG_WAVPACK_ENCODER 0 +%define CONFIG_WMAV1_ENCODER 0 +%define CONFIG_WMAV2_ENCODER 0 +%define CONFIG_PCM_ALAW_ENCODER 0 +%define CONFIG_PCM_BLURAY_ENCODER 0 +%define CONFIG_PCM_DVD_ENCODER 0 +%define CONFIG_PCM_F32BE_ENCODER 0 +%define CONFIG_PCM_F32LE_ENCODER 0 +%define CONFIG_PCM_F64BE_ENCODER 0 +%define CONFIG_PCM_F64LE_ENCODER 0 +%define CONFIG_PCM_MULAW_ENCODER 0 +%define CONFIG_PCM_S8_ENCODER 0 +%define CONFIG_PCM_S8_PLANAR_ENCODER 0 +%define CONFIG_PCM_S16BE_ENCODER 0 +%define CONFIG_PCM_S16BE_PLANAR_ENCODER 0 +%define CONFIG_PCM_S16LE_ENCODER 0 +%define CONFIG_PCM_S16LE_PLANAR_ENCODER 0 +%define CONFIG_PCM_S24BE_ENCODER 0 +%define CONFIG_PCM_S24DAUD_ENCODER 0 +%define CONFIG_PCM_S24LE_ENCODER 0 +%define CONFIG_PCM_S24LE_PLANAR_ENCODER 0 +%define CONFIG_PCM_S32BE_ENCODER 0 +%define CONFIG_PCM_S32LE_ENCODER 0 +%define CONFIG_PCM_S32LE_PLANAR_ENCODER 0 +%define CONFIG_PCM_S64BE_ENCODER 0 +%define CONFIG_PCM_S64LE_ENCODER 0 +%define CONFIG_PCM_U8_ENCODER 0 +%define CONFIG_PCM_U16BE_ENCODER 0 +%define CONFIG_PCM_U16LE_ENCODER 0 +%define CONFIG_PCM_U24BE_ENCODER 0 +%define CONFIG_PCM_U24LE_ENCODER 0 +%define CONFIG_PCM_U32BE_ENCODER 0 +%define CONFIG_PCM_U32LE_ENCODER 0 +%define CONFIG_PCM_VIDC_ENCODER 0 +%define CONFIG_ROQ_DPCM_ENCODER 0 +%define CONFIG_ADPCM_ADX_ENCODER 0 +%define CONFIG_ADPCM_ARGO_ENCODER 0 +%define CONFIG_ADPCM_G722_ENCODER 0 +%define CONFIG_ADPCM_G726_ENCODER 0 +%define CONFIG_ADPCM_G726LE_ENCODER 0 +%define CONFIG_ADPCM_IMA_AMV_ENCODER 0 +%define CONFIG_ADPCM_IMA_ALP_ENCODER 0 +%define CONFIG_ADPCM_IMA_APM_ENCODER 0 +%define CONFIG_ADPCM_IMA_QT_ENCODER 0 +%define CONFIG_ADPCM_IMA_SSI_ENCODER 0 +%define CONFIG_ADPCM_IMA_WAV_ENCODER 0 +%define CONFIG_ADPCM_IMA_WS_ENCODER 0 +%define CONFIG_ADPCM_MS_ENCODER 0 +%define CONFIG_ADPCM_SWF_ENCODER 0 +%define CONFIG_ADPCM_YAMAHA_ENCODER 0 +%define CONFIG_SSA_ENCODER 0 +%define CONFIG_ASS_ENCODER 0 +%define CONFIG_DVBSUB_ENCODER 0 +%define CONFIG_DVDSUB_ENCODER 0 +%define CONFIG_MOVTEXT_ENCODER 0 +%define CONFIG_SRT_ENCODER 0 +%define CONFIG_SUBRIP_ENCODER 0 +%define CONFIG_TEXT_ENCODER 0 +%define CONFIG_TTML_ENCODER 0 +%define CONFIG_WEBVTT_ENCODER 0 +%define CONFIG_XSUB_ENCODER 0 +%define CONFIG_AAC_AT_ENCODER 0 +%define CONFIG_ALAC_AT_ENCODER 0 +%define CONFIG_ILBC_AT_ENCODER 0 +%define CONFIG_PCM_ALAW_AT_ENCODER 0 +%define CONFIG_PCM_MULAW_AT_ENCODER 0 +%define CONFIG_LIBAOM_AV1_ENCODER 0 +%define CONFIG_LIBCODEC2_ENCODER 0 +%define CONFIG_LIBFDK_AAC_ENCODER 0 +%define CONFIG_LIBGSM_ENCODER 0 +%define CONFIG_LIBGSM_MS_ENCODER 0 +%define CONFIG_LIBILBC_ENCODER 0 +%define CONFIG_LIBJXL_ANIM_ENCODER 0 +%define CONFIG_LIBJXL_ENCODER 0 +%define CONFIG_LIBLC3_ENCODER 0 +%define CONFIG_LIBMP3LAME_ENCODER 0 +%define CONFIG_LIBOAPV_ENCODER 0 +%define CONFIG_LIBOPENCORE_AMRNB_ENCODER 0 +%define CONFIG_LIBOPENJPEG_ENCODER 0 +%define CONFIG_LIBOPUS_ENCODER 0 +%define CONFIG_LIBRAV1E_ENCODER 0 +%define CONFIG_LIBSHINE_ENCODER 0 +%define CONFIG_LIBSPEEX_ENCODER 0 +%define CONFIG_LIBSVTAV1_ENCODER 0 +%define CONFIG_LIBSVTJPEGXS_ENCODER 0 +%define CONFIG_LIBTHEORA_ENCODER 0 +%define CONFIG_LIBTWOLAME_ENCODER 0 +%define CONFIG_LIBVO_AMRWBENC_ENCODER 0 +%define CONFIG_LIBVORBIS_ENCODER 0 +%define CONFIG_LIBVPX_VP8_ENCODER 0 +%define CONFIG_LIBVPX_VP9_ENCODER 0 +%define CONFIG_LIBVVENC_ENCODER 0 +%define CONFIG_LIBWEBP_ANIM_ENCODER 0 +%define CONFIG_LIBWEBP_ENCODER 0 +%define CONFIG_LIBX262_ENCODER 0 +%define CONFIG_LIBX264_ENCODER 0 +%define CONFIG_LIBX264RGB_ENCODER 0 +%define CONFIG_LIBX265_ENCODER 0 +%define CONFIG_LIBXEVE_ENCODER 0 +%define CONFIG_LIBXAVS_ENCODER 0 +%define CONFIG_LIBXAVS2_ENCODER 0 +%define CONFIG_LIBXVID_ENCODER 0 +%define CONFIG_AAC_MF_ENCODER 0 +%define CONFIG_AC3_MF_ENCODER 0 +%define CONFIG_H263_V4L2M2M_ENCODER 0 +%define CONFIG_AV1_D3D12VA_ENCODER 0 +%define CONFIG_AV1_MEDIACODEC_ENCODER 0 +%define CONFIG_AV1_NVENC_ENCODER 0 +%define CONFIG_AV1_QSV_ENCODER 0 +%define CONFIG_AV1_AMF_ENCODER 0 +%define CONFIG_AV1_MF_ENCODER 0 +%define CONFIG_AV1_VAAPI_ENCODER 0 +%define CONFIG_AV1_VULKAN_ENCODER 0 +%define CONFIG_LIBOPENH264_ENCODER 0 +%define CONFIG_H264_AMF_ENCODER 0 +%define CONFIG_H264_D3D12VA_ENCODER 0 +%define CONFIG_H264_MF_ENCODER 0 +%define CONFIG_H264_NVENC_ENCODER 0 +%define CONFIG_H264_OH_ENCODER 0 +%define CONFIG_H264_OMX_ENCODER 0 +%define CONFIG_H264_QSV_ENCODER 0 +%define CONFIG_H264_V4L2M2M_ENCODER 0 +%define CONFIG_H264_VAAPI_ENCODER 0 +%define CONFIG_H264_VIDEOTOOLBOX_ENCODER 0 +%define CONFIG_H264_VULKAN_ENCODER 0 +%define CONFIG_HEVC_AMF_ENCODER 0 +%define CONFIG_HEVC_D3D12VA_ENCODER 0 +%define CONFIG_HEVC_MEDIACODEC_ENCODER 0 +%define CONFIG_HEVC_MF_ENCODER 0 +%define CONFIG_HEVC_NVENC_ENCODER 0 +%define CONFIG_HEVC_OH_ENCODER 0 +%define CONFIG_HEVC_QSV_ENCODER 0 +%define CONFIG_HEVC_V4L2M2M_ENCODER 0 +%define CONFIG_HEVC_VAAPI_ENCODER 0 +%define CONFIG_HEVC_VIDEOTOOLBOX_ENCODER 0 +%define CONFIG_HEVC_VULKAN_ENCODER 0 +%define CONFIG_LIBKVAZAAR_ENCODER 0 +%define CONFIG_MJPEG_QSV_ENCODER 0 +%define CONFIG_MJPEG_VAAPI_ENCODER 0 +%define CONFIG_MP3_MF_ENCODER 0 +%define CONFIG_MPEG2_QSV_ENCODER 0 +%define CONFIG_MPEG2_VAAPI_ENCODER 0 +%define CONFIG_MPEG4_MEDIACODEC_ENCODER 0 +%define CONFIG_MPEG4_OMX_ENCODER 0 +%define CONFIG_MPEG4_V4L2M2M_ENCODER 0 +%define CONFIG_PRORES_VIDEOTOOLBOX_ENCODER 0 +%define CONFIG_VP8_MEDIACODEC_ENCODER 0 +%define CONFIG_VP8_V4L2M2M_ENCODER 0 +%define CONFIG_VP8_VAAPI_ENCODER 0 +%define CONFIG_VP9_MEDIACODEC_ENCODER 0 +%define CONFIG_VP9_VAAPI_ENCODER 0 +%define CONFIG_VP9_QSV_ENCODER 0 +%define CONFIG_VNULL_ENCODER 0 +%define CONFIG_ANULL_ENCODER 0 +%define CONFIG_AV1_D3D11VA_HWACCEL 0 +%define CONFIG_AV1_D3D11VA2_HWACCEL 0 +%define CONFIG_AV1_D3D12VA_HWACCEL 0 +%define CONFIG_AV1_DXVA2_HWACCEL 0 +%define CONFIG_AV1_NVDEC_HWACCEL 0 +%define CONFIG_AV1_VAAPI_HWACCEL 0 +%define CONFIG_AV1_VDPAU_HWACCEL 0 +%define CONFIG_AV1_VIDEOTOOLBOX_HWACCEL 0 +%define CONFIG_AV1_VULKAN_HWACCEL 0 +%define CONFIG_DPX_VULKAN_HWACCEL 0 +%define CONFIG_FFV1_VULKAN_HWACCEL 0 +%define CONFIG_H263_VAAPI_HWACCEL 0 +%define CONFIG_H263_VIDEOTOOLBOX_HWACCEL 0 +%define CONFIG_H264_D3D11VA_HWACCEL 0 +%define CONFIG_H264_D3D11VA2_HWACCEL 0 +%define CONFIG_H264_D3D12VA_HWACCEL 0 +%define CONFIG_H264_DXVA2_HWACCEL 0 +%define CONFIG_H264_NVDEC_HWACCEL 0 +%define CONFIG_H264_VAAPI_HWACCEL 0 +%define CONFIG_H264_VDPAU_HWACCEL 0 +%define CONFIG_H264_VIDEOTOOLBOX_HWACCEL 0 +%define CONFIG_H264_VULKAN_HWACCEL 0 +%define CONFIG_HEVC_D3D11VA_HWACCEL 0 +%define CONFIG_HEVC_D3D11VA2_HWACCEL 0 +%define CONFIG_HEVC_D3D12VA_HWACCEL 0 +%define CONFIG_HEVC_DXVA2_HWACCEL 0 +%define CONFIG_HEVC_NVDEC_HWACCEL 0 +%define CONFIG_HEVC_VAAPI_HWACCEL 0 +%define CONFIG_HEVC_VDPAU_HWACCEL 0 +%define CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL 0 +%define CONFIG_HEVC_VULKAN_HWACCEL 0 +%define CONFIG_MJPEG_NVDEC_HWACCEL 0 +%define CONFIG_MJPEG_VAAPI_HWACCEL 0 +%define CONFIG_MPEG1_NVDEC_HWACCEL 0 +%define CONFIG_MPEG1_VDPAU_HWACCEL 0 +%define CONFIG_MPEG1_VIDEOTOOLBOX_HWACCEL 0 +%define CONFIG_MPEG2_D3D11VA_HWACCEL 0 +%define CONFIG_MPEG2_D3D11VA2_HWACCEL 0 +%define CONFIG_MPEG2_D3D12VA_HWACCEL 0 +%define CONFIG_MPEG2_DXVA2_HWACCEL 0 +%define CONFIG_MPEG2_NVDEC_HWACCEL 0 +%define CONFIG_MPEG2_VAAPI_HWACCEL 0 +%define CONFIG_MPEG2_VDPAU_HWACCEL 0 +%define CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL 0 +%define CONFIG_MPEG4_NVDEC_HWACCEL 0 +%define CONFIG_MPEG4_VAAPI_HWACCEL 0 +%define CONFIG_MPEG4_VDPAU_HWACCEL 0 +%define CONFIG_MPEG4_VIDEOTOOLBOX_HWACCEL 0 +%define CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL 0 +%define CONFIG_PRORES_VULKAN_HWACCEL 0 +%define CONFIG_PRORES_RAW_VULKAN_HWACCEL 0 +%define CONFIG_VC1_D3D11VA_HWACCEL 0 +%define CONFIG_VC1_D3D11VA2_HWACCEL 0 +%define CONFIG_VC1_D3D12VA_HWACCEL 0 +%define CONFIG_VC1_DXVA2_HWACCEL 0 +%define CONFIG_VC1_NVDEC_HWACCEL 0 +%define CONFIG_VC1_VAAPI_HWACCEL 0 +%define CONFIG_VC1_VDPAU_HWACCEL 0 +%define CONFIG_VP8_NVDEC_HWACCEL 0 +%define CONFIG_VP8_VAAPI_HWACCEL 0 +%define CONFIG_VP9_D3D11VA_HWACCEL 0 +%define CONFIG_VP9_D3D11VA2_HWACCEL 0 +%define CONFIG_VP9_D3D12VA_HWACCEL 0 +%define CONFIG_VP9_DXVA2_HWACCEL 0 +%define CONFIG_VP9_NVDEC_HWACCEL 0 +%define CONFIG_VP9_VAAPI_HWACCEL 0 +%define CONFIG_VP9_VDPAU_HWACCEL 0 +%define CONFIG_VP9_VIDEOTOOLBOX_HWACCEL 0 +%define CONFIG_VP9_VULKAN_HWACCEL 0 +%define CONFIG_VVC_VAAPI_HWACCEL 0 +%define CONFIG_WMV3_D3D11VA_HWACCEL 0 +%define CONFIG_WMV3_D3D11VA2_HWACCEL 0 +%define CONFIG_WMV3_D3D12VA_HWACCEL 0 +%define CONFIG_WMV3_DXVA2_HWACCEL 0 +%define CONFIG_WMV3_NVDEC_HWACCEL 0 +%define CONFIG_WMV3_VAAPI_HWACCEL 0 +%define CONFIG_WMV3_VDPAU_HWACCEL 0 +%define CONFIG_AAC_PARSER 0 +%define CONFIG_AAC_LATM_PARSER 0 +%define CONFIG_AC3_PARSER 0 +%define CONFIG_ADX_PARSER 0 +%define CONFIG_AHX_PARSER 0 +%define CONFIG_AMR_PARSER 0 +%define CONFIG_APV_PARSER 0 +%define CONFIG_AV1_PARSER 0 +%define CONFIG_AVS2_PARSER 0 +%define CONFIG_AVS3_PARSER 0 +%define CONFIG_BMP_PARSER 0 +%define CONFIG_CAVSVIDEO_PARSER 0 +%define CONFIG_COOK_PARSER 0 +%define CONFIG_CRI_PARSER 0 +%define CONFIG_DCA_PARSER 0 +%define CONFIG_DIRAC_PARSER 0 +%define CONFIG_DNXHD_PARSER 0 +%define CONFIG_DNXUC_PARSER 0 +%define CONFIG_DOLBY_E_PARSER 0 +%define CONFIG_DPX_PARSER 0 +%define CONFIG_DVAUDIO_PARSER 0 +%define CONFIG_DVBSUB_PARSER 0 +%define CONFIG_DVDSUB_PARSER 0 +%define CONFIG_DVD_NAV_PARSER 0 +%define CONFIG_EVC_PARSER 0 +%define CONFIG_FLAC_PARSER 0 +%define CONFIG_FTR_PARSER 0 +%define CONFIG_FFV1_PARSER 0 +%define CONFIG_G723_1_PARSER 0 +%define CONFIG_G729_PARSER 0 +%define CONFIG_GIF_PARSER 0 +%define CONFIG_GSM_PARSER 0 +%define CONFIG_H261_PARSER 0 +%define CONFIG_H263_PARSER 0 +%define CONFIG_H264_PARSER 0 +%define CONFIG_HEVC_PARSER 0 +%define CONFIG_HDR_PARSER 0 +%define CONFIG_IPU_PARSER 0 +%define CONFIG_JPEG2000_PARSER 0 +%define CONFIG_JPEGXL_PARSER 0 +%define CONFIG_JPEGXS_PARSER 0 +%define CONFIG_LCEVC_PARSER 0 +%define CONFIG_MISC4_PARSER 0 +%define CONFIG_MJPEG_PARSER 0 +%define CONFIG_MLP_PARSER 0 +%define CONFIG_MPEG4VIDEO_PARSER 0 +%define CONFIG_MPEGAUDIO_PARSER 0 +%define CONFIG_MPEGVIDEO_PARSER 0 +%define CONFIG_OPUS_PARSER 0 +%define CONFIG_PRORES_PARSER 0 +%define CONFIG_PNG_PARSER 0 +%define CONFIG_PNM_PARSER 0 +%define CONFIG_PRORES_RAW_PARSER 0 +%define CONFIG_QOI_PARSER 0 +%define CONFIG_RV34_PARSER 0 +%define CONFIG_SBC_PARSER 0 +%define CONFIG_SIPR_PARSER 0 +%define CONFIG_TAK_PARSER 0 +%define CONFIG_VC1_PARSER 0 +%define CONFIG_VORBIS_PARSER 0 +%define CONFIG_VP3_PARSER 0 +%define CONFIG_VP8_PARSER 0 +%define CONFIG_VP9_PARSER 0 +%define CONFIG_VVC_PARSER 0 +%define CONFIG_WEBP_PARSER 0 +%define CONFIG_XBM_PARSER 0 +%define CONFIG_XMA_PARSER 0 +%define CONFIG_XWD_PARSER 0 +%define CONFIG_ALSA_INDEV 0 +%define CONFIG_ANDROID_CAMERA_INDEV 0 +%define CONFIG_AVFOUNDATION_INDEV 0 +%define CONFIG_DECKLINK_INDEV 0 +%define CONFIG_DSHOW_INDEV 0 +%define CONFIG_FBDEV_INDEV 0 +%define CONFIG_GDIGRAB_INDEV 0 +%define CONFIG_IEC61883_INDEV 0 +%define CONFIG_JACK_INDEV 0 +%define CONFIG_KMSGRAB_INDEV 0 +%define CONFIG_LAVFI_INDEV 0 +%define CONFIG_OPENAL_INDEV 0 +%define CONFIG_OSS_INDEV 0 +%define CONFIG_PULSE_INDEV 0 +%define CONFIG_SNDIO_INDEV 0 +%define CONFIG_V4L2_INDEV 0 +%define CONFIG_VFWCAP_INDEV 0 +%define CONFIG_XCBGRAB_INDEV 0 +%define CONFIG_LIBCDIO_INDEV 0 +%define CONFIG_LIBDC1394_INDEV 0 +%define CONFIG_ALSA_OUTDEV 0 +%define CONFIG_AUDIOTOOLBOX_OUTDEV 0 +%define CONFIG_CACA_OUTDEV 0 +%define CONFIG_DECKLINK_OUTDEV 0 +%define CONFIG_FBDEV_OUTDEV 0 +%define CONFIG_OSS_OUTDEV 0 +%define CONFIG_PULSE_OUTDEV 0 +%define CONFIG_SNDIO_OUTDEV 0 +%define CONFIG_V4L2_OUTDEV 0 +%define CONFIG_XV_OUTDEV 0 +%define CONFIG_AAP_FILTER 0 +%define CONFIG_ABENCH_FILTER 0 +%define CONFIG_ACOMPRESSOR_FILTER 0 +%define CONFIG_ACONTRAST_FILTER 0 +%define CONFIG_ACOPY_FILTER 0 +%define CONFIG_ACUE_FILTER 0 +%define CONFIG_ACROSSFADE_FILTER 0 +%define CONFIG_ACROSSOVER_FILTER 0 +%define CONFIG_ACRUSHER_FILTER 0 +%define CONFIG_ADECLICK_FILTER 0 +%define CONFIG_ADECLIP_FILTER 0 +%define CONFIG_ADECORRELATE_FILTER 0 +%define CONFIG_ADELAY_FILTER 0 +%define CONFIG_ADENORM_FILTER 0 +%define CONFIG_ADERIVATIVE_FILTER 0 +%define CONFIG_ADRC_FILTER 0 +%define CONFIG_ADYNAMICEQUALIZER_FILTER 0 +%define CONFIG_ADYNAMICSMOOTH_FILTER 0 +%define CONFIG_AECHO_FILTER 0 +%define CONFIG_AEMPHASIS_FILTER 0 +%define CONFIG_AEVAL_FILTER 0 +%define CONFIG_AEXCITER_FILTER 0 +%define CONFIG_AFADE_FILTER 0 +%define CONFIG_AFFTDN_FILTER 0 +%define CONFIG_AFFTFILT_FILTER 0 +%define CONFIG_AFIR_FILTER 0 +%define CONFIG_AFORMAT_FILTER 0 +%define CONFIG_AFREQSHIFT_FILTER 0 +%define CONFIG_AFWTDN_FILTER 0 +%define CONFIG_AGATE_FILTER 0 +%define CONFIG_AIIR_FILTER 0 +%define CONFIG_AINTEGRAL_FILTER 0 +%define CONFIG_AINTERLEAVE_FILTER 0 +%define CONFIG_ALATENCY_FILTER 0 +%define CONFIG_ALIMITER_FILTER 0 +%define CONFIG_ALLPASS_FILTER 0 +%define CONFIG_ALOOP_FILTER 0 +%define CONFIG_AMERGE_FILTER 0 +%define CONFIG_AMETADATA_FILTER 0 +%define CONFIG_AMIX_FILTER 0 +%define CONFIG_AMULTIPLY_FILTER 0 +%define CONFIG_ANEQUALIZER_FILTER 0 +%define CONFIG_ANLMDN_FILTER 0 +%define CONFIG_ANLMF_FILTER 0 +%define CONFIG_ANLMS_FILTER 0 +%define CONFIG_ANULL_FILTER 0 +%define CONFIG_APAD_FILTER 0 +%define CONFIG_APERMS_FILTER 0 +%define CONFIG_APHASER_FILTER 0 +%define CONFIG_APHASESHIFT_FILTER 0 +%define CONFIG_APSNR_FILTER 0 +%define CONFIG_APSYCLIP_FILTER 0 +%define CONFIG_APULSATOR_FILTER 0 +%define CONFIG_AREALTIME_FILTER 0 +%define CONFIG_ARESAMPLE_FILTER 0 +%define CONFIG_AREVERSE_FILTER 0 +%define CONFIG_ARLS_FILTER 0 +%define CONFIG_ARNNDN_FILTER 0 +%define CONFIG_ASDR_FILTER 0 +%define CONFIG_ASEGMENT_FILTER 0 +%define CONFIG_ASELECT_FILTER 0 +%define CONFIG_ASENDCMD_FILTER 0 +%define CONFIG_ASETNSAMPLES_FILTER 0 +%define CONFIG_ASETPTS_FILTER 0 +%define CONFIG_ASETRATE_FILTER 0 +%define CONFIG_ASETTB_FILTER 0 +%define CONFIG_ASHOWINFO_FILTER 0 +%define CONFIG_ASIDEDATA_FILTER 0 +%define CONFIG_ASISDR_FILTER 0 +%define CONFIG_ASOFTCLIP_FILTER 0 +%define CONFIG_ASPECTRALSTATS_FILTER 0 +%define CONFIG_ASPLIT_FILTER 0 +%define CONFIG_ASR_FILTER 0 +%define CONFIG_ASTATS_FILTER 0 +%define CONFIG_ASTREAMSELECT_FILTER 0 +%define CONFIG_ASUBBOOST_FILTER 0 +%define CONFIG_ASUBCUT_FILTER 0 +%define CONFIG_ASUPERCUT_FILTER 0 +%define CONFIG_ASUPERPASS_FILTER 0 +%define CONFIG_ASUPERSTOP_FILTER 0 +%define CONFIG_ATEMPO_FILTER 0 +%define CONFIG_ATILT_FILTER 0 +%define CONFIG_ATRIM_FILTER 0 +%define CONFIG_AXCORRELATE_FILTER 0 +%define CONFIG_AZMQ_FILTER 0 +%define CONFIG_BANDPASS_FILTER 0 +%define CONFIG_BANDREJECT_FILTER 0 +%define CONFIG_BASS_FILTER 0 +%define CONFIG_BIQUAD_FILTER 0 +%define CONFIG_BS2B_FILTER 0 +%define CONFIG_CHANNELMAP_FILTER 0 +%define CONFIG_CHANNELSPLIT_FILTER 0 +%define CONFIG_CHORUS_FILTER 0 +%define CONFIG_COMPAND_FILTER 0 +%define CONFIG_COMPENSATIONDELAY_FILTER 0 +%define CONFIG_CROSSFEED_FILTER 0 +%define CONFIG_CRYSTALIZER_FILTER 0 +%define CONFIG_DCSHIFT_FILTER 0 +%define CONFIG_DEESSER_FILTER 0 +%define CONFIG_DIALOGUENHANCE_FILTER 0 +%define CONFIG_DRMETER_FILTER 0 +%define CONFIG_DYNAUDNORM_FILTER 0 +%define CONFIG_EARWAX_FILTER 0 +%define CONFIG_EBUR128_FILTER 0 +%define CONFIG_EQUALIZER_FILTER 0 +%define CONFIG_EXTRASTEREO_FILTER 0 +%define CONFIG_FIREQUALIZER_FILTER 0 +%define CONFIG_FLANGER_FILTER 0 +%define CONFIG_HAAS_FILTER 0 +%define CONFIG_HDCD_FILTER 0 +%define CONFIG_HEADPHONE_FILTER 0 +%define CONFIG_HIGHPASS_FILTER 0 +%define CONFIG_HIGHSHELF_FILTER 0 +%define CONFIG_JOIN_FILTER 0 +%define CONFIG_LADSPA_FILTER 0 +%define CONFIG_LOUDNORM_FILTER 0 +%define CONFIG_LOWPASS_FILTER 0 +%define CONFIG_LOWSHELF_FILTER 0 +%define CONFIG_LV2_FILTER 0 +%define CONFIG_MCOMPAND_FILTER 0 +%define CONFIG_PAN_FILTER 0 +%define CONFIG_REPLAYGAIN_FILTER 0 +%define CONFIG_RUBBERBAND_FILTER 0 +%define CONFIG_SIDECHAINCOMPRESS_FILTER 0 +%define CONFIG_SIDECHAINGATE_FILTER 0 +%define CONFIG_SILENCEDETECT_FILTER 0 +%define CONFIG_SILENCEREMOVE_FILTER 0 +%define CONFIG_SOFALIZER_FILTER 0 +%define CONFIG_SPEECHNORM_FILTER 0 +%define CONFIG_STEREOTOOLS_FILTER 0 +%define CONFIG_STEREOWIDEN_FILTER 0 +%define CONFIG_SUPEREQUALIZER_FILTER 0 +%define CONFIG_SURROUND_FILTER 0 +%define CONFIG_TILTSHELF_FILTER 0 +%define CONFIG_TREBLE_FILTER 0 +%define CONFIG_TREMOLO_FILTER 0 +%define CONFIG_VIBRATO_FILTER 0 +%define CONFIG_VIRTUALBASS_FILTER 0 +%define CONFIG_VOLUME_FILTER 0 +%define CONFIG_VOLUMEDETECT_FILTER 0 +%define CONFIG_WHISPER_FILTER 0 +%define CONFIG_AEVALSRC_FILTER 0 +%define CONFIG_AFDELAYSRC_FILTER 0 +%define CONFIG_AFIREQSRC_FILTER 0 +%define CONFIG_AFIRSRC_FILTER 0 +%define CONFIG_ANOISESRC_FILTER 0 +%define CONFIG_ANULLSRC_FILTER 0 +%define CONFIG_FLITE_FILTER 0 +%define CONFIG_HILBERT_FILTER 0 +%define CONFIG_SINC_FILTER 0 +%define CONFIG_SINE_FILTER 0 +%define CONFIG_ANULLSINK_FILTER 0 +%define CONFIG_ADDROI_FILTER 0 +%define CONFIG_ALPHAEXTRACT_FILTER 0 +%define CONFIG_ALPHAMERGE_FILTER 0 +%define CONFIG_AMPLIFY_FILTER 0 +%define CONFIG_ASS_FILTER 0 +%define CONFIG_ATADENOISE_FILTER 0 +%define CONFIG_AVGBLUR_FILTER 0 +%define CONFIG_AVGBLUR_OPENCL_FILTER 0 +%define CONFIG_AVGBLUR_VULKAN_FILTER 0 +%define CONFIG_BACKGROUNDKEY_FILTER 0 +%define CONFIG_BBOX_FILTER 0 +%define CONFIG_BENCH_FILTER 0 +%define CONFIG_BILATERAL_FILTER 0 +%define CONFIG_BILATERAL_CUDA_FILTER 0 +%define CONFIG_BITPLANENOISE_FILTER 0 +%define CONFIG_BLACKDETECT_FILTER 0 +%define CONFIG_BLACKDETECT_VULKAN_FILTER 0 +%define CONFIG_BLACKFRAME_FILTER 0 +%define CONFIG_BLEND_FILTER 0 +%define CONFIG_BLEND_VULKAN_FILTER 0 +%define CONFIG_BLOCKDETECT_FILTER 0 +%define CONFIG_BLURDETECT_FILTER 0 +%define CONFIG_BM3D_FILTER 0 +%define CONFIG_BOXBLUR_FILTER 0 +%define CONFIG_BOXBLUR_OPENCL_FILTER 0 +%define CONFIG_BWDIF_FILTER 0 +%define CONFIG_BWDIF_CUDA_FILTER 0 +%define CONFIG_BWDIF_VULKAN_FILTER 0 +%define CONFIG_CAS_FILTER 0 +%define CONFIG_CCREPACK_FILTER 0 +%define CONFIG_CHROMABER_VULKAN_FILTER 0 +%define CONFIG_CHROMAHOLD_FILTER 0 +%define CONFIG_CHROMAKEY_FILTER 0 +%define CONFIG_CHROMAKEY_CUDA_FILTER 0 +%define CONFIG_CHROMANR_FILTER 0 +%define CONFIG_CHROMASHIFT_FILTER 0 +%define CONFIG_CIESCOPE_FILTER 0 +%define CONFIG_CODECVIEW_FILTER 0 +%define CONFIG_COLORBALANCE_FILTER 0 +%define CONFIG_COLORCHANNELMIXER_FILTER 0 +%define CONFIG_COLORCONTRAST_FILTER 0 +%define CONFIG_COLORCORRECT_FILTER 0 +%define CONFIG_COLORDETECT_FILTER 0 +%define CONFIG_COLORIZE_FILTER 0 +%define CONFIG_COLORKEY_FILTER 0 +%define CONFIG_COLORKEY_OPENCL_FILTER 0 +%define CONFIG_COLORHOLD_FILTER 0 +%define CONFIG_COLORLEVELS_FILTER 0 +%define CONFIG_COLORMAP_FILTER 0 +%define CONFIG_COLORMATRIX_FILTER 0 +%define CONFIG_COLORSPACE_FILTER 0 +%define CONFIG_COLORSPACE_CUDA_FILTER 0 +%define CONFIG_COLORTEMPERATURE_FILTER 0 +%define CONFIG_CONVOLUTION_FILTER 0 +%define CONFIG_CONVOLUTION_OPENCL_FILTER 0 +%define CONFIG_CONVOLVE_FILTER 0 +%define CONFIG_COPY_FILTER 0 +%define CONFIG_COREIMAGE_FILTER 0 +%define CONFIG_CORR_FILTER 0 +%define CONFIG_COVER_RECT_FILTER 0 +%define CONFIG_CROP_FILTER 0 +%define CONFIG_CROPDETECT_FILTER 0 +%define CONFIG_CUE_FILTER 0 +%define CONFIG_CURVES_FILTER 0 +%define CONFIG_DATASCOPE_FILTER 0 +%define CONFIG_DBLUR_FILTER 0 +%define CONFIG_DCTDNOIZ_FILTER 0 +%define CONFIG_DEBAND_FILTER 0 +%define CONFIG_DEBLOCK_FILTER 0 +%define CONFIG_DECIMATE_FILTER 0 +%define CONFIG_DECONVOLVE_FILTER 0 +%define CONFIG_DEDOT_FILTER 0 +%define CONFIG_DEFLATE_FILTER 0 +%define CONFIG_DEFLICKER_FILTER 0 +%define CONFIG_DEINTERLACE_QSV_FILTER 0 +%define CONFIG_DEINTERLACE_D3D12_FILTER 0 +%define CONFIG_DEINTERLACE_VAAPI_FILTER 0 +%define CONFIG_DEJUDDER_FILTER 0 +%define CONFIG_DELOGO_FILTER 0 +%define CONFIG_DENOISE_VAAPI_FILTER 0 +%define CONFIG_DERAIN_FILTER 0 +%define CONFIG_DESHAKE_FILTER 0 +%define CONFIG_DESHAKE_OPENCL_FILTER 0 +%define CONFIG_DESPILL_FILTER 0 +%define CONFIG_DETELECINE_FILTER 0 +%define CONFIG_DILATION_FILTER 0 +%define CONFIG_DILATION_OPENCL_FILTER 0 +%define CONFIG_DISPLACE_FILTER 0 +%define CONFIG_DNN_CLASSIFY_FILTER 0 +%define CONFIG_DNN_DETECT_FILTER 0 +%define CONFIG_DNN_PROCESSING_FILTER 0 +%define CONFIG_DOUBLEWEAVE_FILTER 0 +%define CONFIG_DRAWBOX_FILTER 0 +%define CONFIG_DRAWGRAPH_FILTER 0 +%define CONFIG_DRAWGRID_FILTER 0 +%define CONFIG_DRAWTEXT_FILTER 0 +%define CONFIG_DRAWVG_FILTER 0 +%define CONFIG_EDGEDETECT_FILTER 0 +%define CONFIG_ELBG_FILTER 0 +%define CONFIG_ENTROPY_FILTER 0 +%define CONFIG_EPX_FILTER 0 +%define CONFIG_EQ_FILTER 0 +%define CONFIG_EROSION_FILTER 0 +%define CONFIG_EROSION_OPENCL_FILTER 0 +%define CONFIG_ESTDIF_FILTER 0 +%define CONFIG_EXPOSURE_FILTER 0 +%define CONFIG_EXTRACTPLANES_FILTER 0 +%define CONFIG_FADE_FILTER 0 +%define CONFIG_FEEDBACK_FILTER 0 +%define CONFIG_FFTDNOIZ_FILTER 0 +%define CONFIG_FFTFILT_FILTER 0 +%define CONFIG_FIELD_FILTER 0 +%define CONFIG_FIELDHINT_FILTER 0 +%define CONFIG_FIELDMATCH_FILTER 0 +%define CONFIG_FIELDORDER_FILTER 0 +%define CONFIG_FILLBORDERS_FILTER 0 +%define CONFIG_FIND_RECT_FILTER 0 +%define CONFIG_FLIP_VULKAN_FILTER 0 +%define CONFIG_FLOODFILL_FILTER 0 +%define CONFIG_FORMAT_FILTER 0 +%define CONFIG_FPS_FILTER 0 +%define CONFIG_FRAMEPACK_FILTER 0 +%define CONFIG_FRAMERATE_FILTER 0 +%define CONFIG_FRAMESTEP_FILTER 0 +%define CONFIG_FREEZEDETECT_FILTER 0 +%define CONFIG_FREEZEFRAMES_FILTER 0 +%define CONFIG_FREI0R_FILTER 0 +%define CONFIG_FSPP_FILTER 0 +%define CONFIG_FSYNC_FILTER 0 +%define CONFIG_GBLUR_FILTER 0 +%define CONFIG_GBLUR_VULKAN_FILTER 0 +%define CONFIG_GEQ_FILTER 0 +%define CONFIG_GRADFUN_FILTER 0 +%define CONFIG_GRAPHMONITOR_FILTER 0 +%define CONFIG_GRAYWORLD_FILTER 0 +%define CONFIG_GREYEDGE_FILTER 0 +%define CONFIG_GUIDED_FILTER 0 +%define CONFIG_HALDCLUT_FILTER 0 +%define CONFIG_HFLIP_FILTER 0 +%define CONFIG_HFLIP_VULKAN_FILTER 0 +%define CONFIG_HISTEQ_FILTER 0 +%define CONFIG_HISTOGRAM_FILTER 0 +%define CONFIG_HQDN3D_FILTER 0 +%define CONFIG_HQX_FILTER 0 +%define CONFIG_HSTACK_FILTER 0 +%define CONFIG_HSVHOLD_FILTER 0 +%define CONFIG_HSVKEY_FILTER 0 +%define CONFIG_HUE_FILTER 0 +%define CONFIG_HUESATURATION_FILTER 0 +%define CONFIG_HWDOWNLOAD_FILTER 0 +%define CONFIG_HWMAP_FILTER 0 +%define CONFIG_HWUPLOAD_FILTER 0 +%define CONFIG_HWUPLOAD_CUDA_FILTER 0 +%define CONFIG_HYSTERESIS_FILTER 0 +%define CONFIG_ICCDETECT_FILTER 0 +%define CONFIG_ICCGEN_FILTER 0 +%define CONFIG_IDENTITY_FILTER 0 +%define CONFIG_IDET_FILTER 0 +%define CONFIG_IL_FILTER 0 +%define CONFIG_INFLATE_FILTER 0 +%define CONFIG_INTERLACE_FILTER 0 +%define CONFIG_INTERLACE_VULKAN_FILTER 0 +%define CONFIG_INTERLEAVE_FILTER 0 +%define CONFIG_KERNDEINT_FILTER 0 +%define CONFIG_KIRSCH_FILTER 0 +%define CONFIG_LAGFUN_FILTER 0 +%define CONFIG_LATENCY_FILTER 0 +%define CONFIG_LCEVC_FILTER 0 +%define CONFIG_LENSCORRECTION_FILTER 0 +%define CONFIG_LENSFUN_FILTER 0 +%define CONFIG_LIBPLACEBO_FILTER 0 +%define CONFIG_LIBVMAF_FILTER 0 +%define CONFIG_LIBVMAF_CUDA_FILTER 0 +%define CONFIG_LIMITDIFF_FILTER 0 +%define CONFIG_LIMITER_FILTER 0 +%define CONFIG_LOOP_FILTER 0 +%define CONFIG_LUMAKEY_FILTER 0 +%define CONFIG_LUT_FILTER 0 +%define CONFIG_LUT1D_FILTER 0 +%define CONFIG_LUT2_FILTER 0 +%define CONFIG_LUT3D_FILTER 0 +%define CONFIG_LUTRGB_FILTER 0 +%define CONFIG_LUTYUV_FILTER 0 +%define CONFIG_MASKEDCLAMP_FILTER 0 +%define CONFIG_MASKEDMAX_FILTER 0 +%define CONFIG_MASKEDMERGE_FILTER 0 +%define CONFIG_MASKEDMIN_FILTER 0 +%define CONFIG_MASKEDTHRESHOLD_FILTER 0 +%define CONFIG_MASKFUN_FILTER 0 +%define CONFIG_MCDEINT_FILTER 0 +%define CONFIG_MEDIAN_FILTER 0 +%define CONFIG_MERGEPLANES_FILTER 0 +%define CONFIG_MESTIMATE_FILTER 0 +%define CONFIG_MESTIMATE_D3D12_FILTER 0 +%define CONFIG_METADATA_FILTER 0 +%define CONFIG_MIDEQUALIZER_FILTER 0 +%define CONFIG_MINTERPOLATE_FILTER 0 +%define CONFIG_MIX_FILTER 0 +%define CONFIG_MONOCHROME_FILTER 0 +%define CONFIG_MORPHO_FILTER 0 +%define CONFIG_MPDECIMATE_FILTER 0 +%define CONFIG_MSAD_FILTER 0 +%define CONFIG_MULTIPLY_FILTER 0 +%define CONFIG_NEGATE_FILTER 0 +%define CONFIG_NLMEANS_FILTER 0 +%define CONFIG_NLMEANS_OPENCL_FILTER 0 +%define CONFIG_NLMEANS_VULKAN_FILTER 0 +%define CONFIG_NNEDI_FILTER 0 +%define CONFIG_NOFORMAT_FILTER 0 +%define CONFIG_NOISE_FILTER 0 +%define CONFIG_NORMALIZE_FILTER 0 +%define CONFIG_NULL_FILTER 0 +%define CONFIG_OCR_FILTER 0 +%define CONFIG_OCV_FILTER 0 +%define CONFIG_OSCILLOSCOPE_FILTER 0 +%define CONFIG_OCIO_FILTER 0 +%define CONFIG_OVERLAY_FILTER 0 +%define CONFIG_OVERLAY_OPENCL_FILTER 0 +%define CONFIG_OVERLAY_QSV_FILTER 0 +%define CONFIG_OVERLAY_VAAPI_FILTER 0 +%define CONFIG_OVERLAY_VULKAN_FILTER 0 +%define CONFIG_OVERLAY_CUDA_FILTER 0 +%define CONFIG_OWDENOISE_FILTER 0 +%define CONFIG_PAD_FILTER 0 +%define CONFIG_PAD_CUDA_FILTER 0 +%define CONFIG_PAD_OPENCL_FILTER 0 +%define CONFIG_PALETTEGEN_FILTER 0 +%define CONFIG_PALETTEUSE_FILTER 0 +%define CONFIG_PERMS_FILTER 0 +%define CONFIG_PERSPECTIVE_FILTER 0 +%define CONFIG_PHASE_FILTER 0 +%define CONFIG_PHOTOSENSITIVITY_FILTER 0 +%define CONFIG_PIXDESCTEST_FILTER 0 +%define CONFIG_PIXELIZE_FILTER 0 +%define CONFIG_PIXSCOPE_FILTER 0 +%define CONFIG_PP7_FILTER 0 +%define CONFIG_PREMULTIPLY_FILTER 0 +%define CONFIG_PREMULTIPLY_DYNAMIC_FILTER 0 +%define CONFIG_PREWITT_FILTER 0 +%define CONFIG_PREWITT_OPENCL_FILTER 0 +%define CONFIG_PROCAMP_VAAPI_FILTER 0 +%define CONFIG_PROGRAM_OPENCL_FILTER 0 +%define CONFIG_PSEUDOCOLOR_FILTER 0 +%define CONFIG_PSNR_FILTER 0 +%define CONFIG_PULLUP_FILTER 0 +%define CONFIG_QP_FILTER 0 +%define CONFIG_QRENCODE_FILTER 0 +%define CONFIG_QUIRC_FILTER 0 +%define CONFIG_RANDOM_FILTER 0 +%define CONFIG_READEIA608_FILTER 0 +%define CONFIG_READVITC_FILTER 0 +%define CONFIG_REALTIME_FILTER 0 +%define CONFIG_REMAP_FILTER 0 +%define CONFIG_REMAP_OPENCL_FILTER 0 +%define CONFIG_REMOVEGRAIN_FILTER 0 +%define CONFIG_REMOVELOGO_FILTER 0 +%define CONFIG_REPEATFIELDS_FILTER 0 +%define CONFIG_REVERSE_FILTER 0 +%define CONFIG_RGBASHIFT_FILTER 0 +%define CONFIG_ROBERTS_FILTER 0 +%define CONFIG_ROBERTS_OPENCL_FILTER 0 +%define CONFIG_ROTATE_FILTER 0 +%define CONFIG_SAB_FILTER 0 +%define CONFIG_SCALE_FILTER 0 +%define CONFIG_VPP_AMF_FILTER 0 +%define CONFIG_SR_AMF_FILTER 0 +%define CONFIG_SCALE_CUDA_FILTER 0 +%define CONFIG_SCALE_D3D11_FILTER 0 +%define CONFIG_SCALE_D3D12_FILTER 0 +%define CONFIG_SCALE_NPP_FILTER 0 +%define CONFIG_SCALE_QSV_FILTER 0 +%define CONFIG_SCALE_VAAPI_FILTER 0 +%define CONFIG_SCALE_VT_FILTER 0 +%define CONFIG_SCALE_VULKAN_FILTER 0 +%define CONFIG_SCALE2REF_FILTER 0 +%define CONFIG_SCALE2REF_NPP_FILTER 0 +%define CONFIG_SCDET_FILTER 0 +%define CONFIG_SCDET_VULKAN_FILTER 0 +%define CONFIG_SCHARR_FILTER 0 +%define CONFIG_SCROLL_FILTER 0 +%define CONFIG_SEGMENT_FILTER 0 +%define CONFIG_SELECT_FILTER 0 +%define CONFIG_SELECTIVECOLOR_FILTER 0 +%define CONFIG_SENDCMD_FILTER 0 +%define CONFIG_SEPARATEFIELDS_FILTER 0 +%define CONFIG_SETDAR_FILTER 0 +%define CONFIG_SETFIELD_FILTER 0 +%define CONFIG_SETPARAMS_FILTER 0 +%define CONFIG_SETPTS_FILTER 0 +%define CONFIG_SETRANGE_FILTER 0 +%define CONFIG_SETSAR_FILTER 0 +%define CONFIG_SETTB_FILTER 0 +%define CONFIG_SHARPEN_NPP_FILTER 0 +%define CONFIG_SHARPNESS_VAAPI_FILTER 0 +%define CONFIG_SHEAR_FILTER 0 +%define CONFIG_SHOWINFO_FILTER 0 +%define CONFIG_SHOWPALETTE_FILTER 0 +%define CONFIG_SHUFFLEFRAMES_FILTER 0 +%define CONFIG_SHUFFLEPIXELS_FILTER 0 +%define CONFIG_SHUFFLEPLANES_FILTER 0 +%define CONFIG_SIDEDATA_FILTER 0 +%define CONFIG_SIGNALSTATS_FILTER 0 +%define CONFIG_SIGNATURE_FILTER 0 +%define CONFIG_SITI_FILTER 0 +%define CONFIG_SMARTBLUR_FILTER 0 +%define CONFIG_SOBEL_FILTER 0 +%define CONFIG_SOBEL_OPENCL_FILTER 0 +%define CONFIG_SPLIT_FILTER 0 +%define CONFIG_SPP_FILTER 0 +%define CONFIG_SR_FILTER 0 +%define CONFIG_SSIM_FILTER 0 +%define CONFIG_SSIM360_FILTER 0 +%define CONFIG_STEREO3D_FILTER 0 +%define CONFIG_STREAMSELECT_FILTER 0 +%define CONFIG_SUBTITLES_FILTER 0 +%define CONFIG_SUPER2XSAI_FILTER 0 +%define CONFIG_SWAPRECT_FILTER 0 +%define CONFIG_SWAPUV_FILTER 0 +%define CONFIG_TBLEND_FILTER 0 +%define CONFIG_TELECINE_FILTER 0 +%define CONFIG_THISTOGRAM_FILTER 0 +%define CONFIG_THRESHOLD_FILTER 0 +%define CONFIG_THUMBNAIL_FILTER 0 +%define CONFIG_THUMBNAIL_CUDA_FILTER 0 +%define CONFIG_TILE_FILTER 0 +%define CONFIG_TILTANDSHIFT_FILTER 0 +%define CONFIG_TINTERLACE_FILTER 0 +%define CONFIG_TLUT2_FILTER 0 +%define CONFIG_TMEDIAN_FILTER 0 +%define CONFIG_TMIDEQUALIZER_FILTER 0 +%define CONFIG_TMIX_FILTER 0 +%define CONFIG_TONEMAP_FILTER 0 +%define CONFIG_TONEMAP_OPENCL_FILTER 0 +%define CONFIG_TONEMAP_VAAPI_FILTER 0 +%define CONFIG_TPAD_FILTER 0 +%define CONFIG_TRANSPOSE_FILTER 0 +%define CONFIG_TRANSPOSE_NPP_FILTER 0 +%define CONFIG_TRANSPOSE_OPENCL_FILTER 0 +%define CONFIG_TRANSPOSE_VAAPI_FILTER 0 +%define CONFIG_TRANSPOSE_VT_FILTER 0 +%define CONFIG_TRANSPOSE_VULKAN_FILTER 0 +%define CONFIG_TRIM_FILTER 0 +%define CONFIG_UNPREMULTIPLY_FILTER 0 +%define CONFIG_UNSHARP_FILTER 0 +%define CONFIG_UNSHARP_OPENCL_FILTER 0 +%define CONFIG_UNTILE_FILTER 0 +%define CONFIG_USPP_FILTER 0 +%define CONFIG_V360_FILTER 0 +%define CONFIG_VAGUEDENOISER_FILTER 0 +%define CONFIG_VARBLUR_FILTER 0 +%define CONFIG_VECTORSCOPE_FILTER 0 +%define CONFIG_VFLIP_FILTER 0 +%define CONFIG_VFLIP_VULKAN_FILTER 0 +%define CONFIG_VFRDET_FILTER 0 +%define CONFIG_VIBRANCE_FILTER 0 +%define CONFIG_VIDSTABDETECT_FILTER 0 +%define CONFIG_VIDSTABTRANSFORM_FILTER 0 +%define CONFIG_VIF_FILTER 0 +%define CONFIG_VIGNETTE_FILTER 0 +%define CONFIG_VMAFMOTION_FILTER 0 +%define CONFIG_VPP_QSV_FILTER 0 +%define CONFIG_VSTACK_FILTER 0 +%define CONFIG_W3FDIF_FILTER 0 +%define CONFIG_WAVEFORM_FILTER 0 +%define CONFIG_WEAVE_FILTER 0 +%define CONFIG_XBR_FILTER 0 +%define CONFIG_XCORRELATE_FILTER 0 +%define CONFIG_XFADE_FILTER 0 +%define CONFIG_XFADE_OPENCL_FILTER 0 +%define CONFIG_XFADE_VULKAN_FILTER 0 +%define CONFIG_XMEDIAN_FILTER 0 +%define CONFIG_XPSNR_FILTER 0 +%define CONFIG_XSTACK_FILTER 0 +%define CONFIG_YADIF_FILTER 0 +%define CONFIG_YADIF_CUDA_FILTER 0 +%define CONFIG_YADIF_VIDEOTOOLBOX_FILTER 0 +%define CONFIG_YAEPBLUR_FILTER 0 +%define CONFIG_ZMQ_FILTER 0 +%define CONFIG_ZOOMPAN_FILTER 0 +%define CONFIG_ZSCALE_FILTER 0 +%define CONFIG_HSTACK_VAAPI_FILTER 0 +%define CONFIG_VSTACK_VAAPI_FILTER 0 +%define CONFIG_XSTACK_VAAPI_FILTER 0 +%define CONFIG_HSTACK_QSV_FILTER 0 +%define CONFIG_VSTACK_QSV_FILTER 0 +%define CONFIG_XSTACK_QSV_FILTER 0 +%define CONFIG_PAD_VAAPI_FILTER 0 +%define CONFIG_DRAWBOX_VAAPI_FILTER 0 +%define CONFIG_ALLRGB_FILTER 0 +%define CONFIG_ALLYUV_FILTER 0 +%define CONFIG_AMF_CAPTURE_FILTER 0 +%define CONFIG_CELLAUTO_FILTER 0 +%define CONFIG_COLOR_FILTER 0 +%define CONFIG_COLOR_VULKAN_FILTER 0 +%define CONFIG_COLORCHART_FILTER 0 +%define CONFIG_COLORSPECTRUM_FILTER 0 +%define CONFIG_COREIMAGESRC_FILTER 0 +%define CONFIG_DDAGRAB_FILTER 0 +%define CONFIG_FREI0R_SRC_FILTER 0 +%define CONFIG_GFXCAPTURE_FILTER 0 +%define CONFIG_GRADIENTS_FILTER 0 +%define CONFIG_HALDCLUTSRC_FILTER 0 +%define CONFIG_LIFE_FILTER 0 +%define CONFIG_MANDELBROT_FILTER 0 +%define CONFIG_MPTESTSRC_FILTER 0 +%define CONFIG_NULLSRC_FILTER 0 +%define CONFIG_OPENCLSRC_FILTER 0 +%define CONFIG_QRENCODESRC_FILTER 0 +%define CONFIG_PAL75BARS_FILTER 0 +%define CONFIG_PAL100BARS_FILTER 0 +%define CONFIG_PERLIN_FILTER 0 +%define CONFIG_RGBTESTSRC_FILTER 0 +%define CONFIG_SIERPINSKI_FILTER 0 +%define CONFIG_SMPTEBARS_FILTER 0 +%define CONFIG_SMPTEHDBARS_FILTER 0 +%define CONFIG_TESTSRC_FILTER 0 +%define CONFIG_TESTSRC2_FILTER 0 +%define CONFIG_YUVTESTSRC_FILTER 0 +%define CONFIG_ZONEPLATE_FILTER 0 +%define CONFIG_NULLSINK_FILTER 0 +%define CONFIG_A3DSCOPE_FILTER 0 +%define CONFIG_ABITSCOPE_FILTER 0 +%define CONFIG_ADRAWGRAPH_FILTER 0 +%define CONFIG_AGRAPHMONITOR_FILTER 0 +%define CONFIG_AHISTOGRAM_FILTER 0 +%define CONFIG_APHASEMETER_FILTER 0 +%define CONFIG_AVECTORSCOPE_FILTER 0 +%define CONFIG_CONCAT_FILTER 0 +%define CONFIG_SHOWCQT_FILTER 0 +%define CONFIG_SHOWCWT_FILTER 0 +%define CONFIG_SHOWFREQS_FILTER 0 +%define CONFIG_SHOWSPATIAL_FILTER 0 +%define CONFIG_SHOWSPECTRUM_FILTER 0 +%define CONFIG_SHOWSPECTRUMPIC_FILTER 0 +%define CONFIG_SHOWVOLUME_FILTER 0 +%define CONFIG_SHOWWAVES_FILTER 0 +%define CONFIG_SHOWWAVESPIC_FILTER 0 +%define CONFIG_SPECTRUMSYNTH_FILTER 0 +%define CONFIG_AVSYNCTEST_FILTER 0 +%define CONFIG_AMOVIE_FILTER 0 +%define CONFIG_MOVIE_FILTER 0 +%define CONFIG_AA_DEMUXER 0 +%define CONFIG_AAC_DEMUXER 0 +%define CONFIG_AAX_DEMUXER 0 +%define CONFIG_AC3_DEMUXER 0 +%define CONFIG_AC4_DEMUXER 0 +%define CONFIG_ACE_DEMUXER 0 +%define CONFIG_ACM_DEMUXER 0 +%define CONFIG_ACT_DEMUXER 0 +%define CONFIG_ADF_DEMUXER 0 +%define CONFIG_ADP_DEMUXER 0 +%define CONFIG_ADS_DEMUXER 0 +%define CONFIG_ADX_DEMUXER 0 +%define CONFIG_AEA_DEMUXER 0 +%define CONFIG_AFC_DEMUXER 0 +%define CONFIG_AIFF_DEMUXER 0 +%define CONFIG_AIX_DEMUXER 0 +%define CONFIG_ALP_DEMUXER 0 +%define CONFIG_AMR_DEMUXER 0 +%define CONFIG_AMRNB_DEMUXER 0 +%define CONFIG_AMRWB_DEMUXER 0 +%define CONFIG_ANM_DEMUXER 0 +%define CONFIG_APAC_DEMUXER 0 +%define CONFIG_APC_DEMUXER 0 +%define CONFIG_APE_DEMUXER 0 +%define CONFIG_APM_DEMUXER 0 +%define CONFIG_APNG_DEMUXER 0 +%define CONFIG_APTX_DEMUXER 0 +%define CONFIG_APTX_HD_DEMUXER 0 +%define CONFIG_APV_DEMUXER 0 +%define CONFIG_AQTITLE_DEMUXER 0 +%define CONFIG_ARGO_ASF_DEMUXER 0 +%define CONFIG_ARGO_BRP_DEMUXER 0 +%define CONFIG_ARGO_CVG_DEMUXER 0 +%define CONFIG_ASF_DEMUXER 0 +%define CONFIG_ASF_O_DEMUXER 0 +%define CONFIG_ASS_DEMUXER 0 +%define CONFIG_AST_DEMUXER 0 +%define CONFIG_AU_DEMUXER 0 +%define CONFIG_AV1_DEMUXER 0 +%define CONFIG_AVI_DEMUXER 0 +%define CONFIG_AVR_DEMUXER 0 +%define CONFIG_AVS_DEMUXER 0 +%define CONFIG_AVS2_DEMUXER 0 +%define CONFIG_AVS3_DEMUXER 0 +%define CONFIG_BETHSOFTVID_DEMUXER 0 +%define CONFIG_BFI_DEMUXER 0 +%define CONFIG_BINTEXT_DEMUXER 0 +%define CONFIG_BINK_DEMUXER 0 +%define CONFIG_BINKA_DEMUXER 0 +%define CONFIG_BIT_DEMUXER 0 +%define CONFIG_BITPACKED_DEMUXER 0 +%define CONFIG_BMV_DEMUXER 0 +%define CONFIG_BFSTM_DEMUXER 0 +%define CONFIG_BRSTM_DEMUXER 0 +%define CONFIG_BOA_DEMUXER 0 +%define CONFIG_BONK_DEMUXER 0 +%define CONFIG_C93_DEMUXER 0 +%define CONFIG_CAF_DEMUXER 0 +%define CONFIG_CAVSVIDEO_DEMUXER 0 +%define CONFIG_CDG_DEMUXER 0 +%define CONFIG_CDXL_DEMUXER 0 +%define CONFIG_CINE_DEMUXER 0 +%define CONFIG_CODEC2_DEMUXER 0 +%define CONFIG_CODEC2RAW_DEMUXER 0 +%define CONFIG_CONCAT_DEMUXER 0 +%define CONFIG_DASH_DEMUXER 0 +%define CONFIG_DATA_DEMUXER 0 +%define CONFIG_DAUD_DEMUXER 0 +%define CONFIG_DCSTR_DEMUXER 0 +%define CONFIG_DERF_DEMUXER 0 +%define CONFIG_DFA_DEMUXER 0 +%define CONFIG_DFPWM_DEMUXER 0 +%define CONFIG_DHAV_DEMUXER 0 +%define CONFIG_DIRAC_DEMUXER 0 +%define CONFIG_DNXHD_DEMUXER 0 +%define CONFIG_DSF_DEMUXER 0 +%define CONFIG_DSICIN_DEMUXER 0 +%define CONFIG_DSS_DEMUXER 0 +%define CONFIG_DTS_DEMUXER 0 +%define CONFIG_DTSHD_DEMUXER 0 +%define CONFIG_DV_DEMUXER 0 +%define CONFIG_DVBSUB_DEMUXER 0 +%define CONFIG_DVBTXT_DEMUXER 0 +%define CONFIG_DXA_DEMUXER 0 +%define CONFIG_EA_DEMUXER 0 +%define CONFIG_EA_CDATA_DEMUXER 0 +%define CONFIG_EAC3_DEMUXER 0 +%define CONFIG_EPAF_DEMUXER 0 +%define CONFIG_EVC_DEMUXER 0 +%define CONFIG_FFMETADATA_DEMUXER 0 +%define CONFIG_FILMSTRIP_DEMUXER 0 +%define CONFIG_FITS_DEMUXER 0 +%define CONFIG_FLAC_DEMUXER 0 +%define CONFIG_FLIC_DEMUXER 0 +%define CONFIG_FLV_DEMUXER 0 +%define CONFIG_LIVE_FLV_DEMUXER 0 +%define CONFIG_FOURXM_DEMUXER 0 +%define CONFIG_FRM_DEMUXER 0 +%define CONFIG_FSB_DEMUXER 0 +%define CONFIG_FWSE_DEMUXER 0 +%define CONFIG_G722_DEMUXER 0 +%define CONFIG_G723_1_DEMUXER 0 +%define CONFIG_G726_DEMUXER 0 +%define CONFIG_G726LE_DEMUXER 0 +%define CONFIG_G728_DEMUXER 0 +%define CONFIG_G729_DEMUXER 0 +%define CONFIG_GDV_DEMUXER 0 +%define CONFIG_GENH_DEMUXER 0 +%define CONFIG_GIF_DEMUXER 0 +%define CONFIG_GSM_DEMUXER 0 +%define CONFIG_GXF_DEMUXER 0 +%define CONFIG_H261_DEMUXER 0 +%define CONFIG_H263_DEMUXER 0 +%define CONFIG_H264_DEMUXER 0 +%define CONFIG_HCA_DEMUXER 0 +%define CONFIG_HCOM_DEMUXER 0 +%define CONFIG_HEVC_DEMUXER 0 +%define CONFIG_HLS_DEMUXER 0 +%define CONFIG_HNM_DEMUXER 0 +%define CONFIG_HXVS_DEMUXER 0 +%define CONFIG_IAMF_DEMUXER 0 +%define CONFIG_ICO_DEMUXER 0 +%define CONFIG_IDCIN_DEMUXER 0 +%define CONFIG_IDF_DEMUXER 0 +%define CONFIG_IFF_DEMUXER 0 +%define CONFIG_IFV_DEMUXER 0 +%define CONFIG_ILBC_DEMUXER 0 +%define CONFIG_IMAGE2_DEMUXER 0 +%define CONFIG_IMAGE2PIPE_DEMUXER 0 +%define CONFIG_IMAGE2_ALIAS_PIX_DEMUXER 0 +%define CONFIG_IMAGE2_BRENDER_PIX_DEMUXER 0 +%define CONFIG_IMF_DEMUXER 0 +%define CONFIG_INGENIENT_DEMUXER 0 +%define CONFIG_IPMOVIE_DEMUXER 0 +%define CONFIG_IPU_DEMUXER 0 +%define CONFIG_IRCAM_DEMUXER 0 +%define CONFIG_ISS_DEMUXER 0 +%define CONFIG_IV8_DEMUXER 0 +%define CONFIG_IVF_DEMUXER 0 +%define CONFIG_IVR_DEMUXER 0 +%define CONFIG_JACOSUB_DEMUXER 0 +%define CONFIG_JV_DEMUXER 0 +%define CONFIG_JPEGXL_ANIM_DEMUXER 0 +%define CONFIG_KUX_DEMUXER 0 +%define CONFIG_KVAG_DEMUXER 0 +%define CONFIG_LAF_DEMUXER 0 +%define CONFIG_LC3_DEMUXER 0 +%define CONFIG_LMLM4_DEMUXER 0 +%define CONFIG_LOAS_DEMUXER 0 +%define CONFIG_LUODAT_DEMUXER 0 +%define CONFIG_LRC_DEMUXER 0 +%define CONFIG_LVF_DEMUXER 0 +%define CONFIG_LXF_DEMUXER 0 +%define CONFIG_M4V_DEMUXER 0 +%define CONFIG_MCA_DEMUXER 0 +%define CONFIG_MCC_DEMUXER 0 +%define CONFIG_MATROSKA_DEMUXER 0 +%define CONFIG_MGSTS_DEMUXER 0 +%define CONFIG_MICRODVD_DEMUXER 0 +%define CONFIG_MJPEG_DEMUXER 0 +%define CONFIG_MJPEG_2000_DEMUXER 0 +%define CONFIG_MLP_DEMUXER 0 +%define CONFIG_MLV_DEMUXER 0 +%define CONFIG_MM_DEMUXER 0 +%define CONFIG_MMF_DEMUXER 0 +%define CONFIG_MODS_DEMUXER 0 +%define CONFIG_MOFLEX_DEMUXER 0 +%define CONFIG_MOV_DEMUXER 0 +%define CONFIG_MP3_DEMUXER 0 +%define CONFIG_MPC_DEMUXER 0 +%define CONFIG_MPC8_DEMUXER 0 +%define CONFIG_MPEGPS_DEMUXER 0 +%define CONFIG_MPEGTS_DEMUXER 0 +%define CONFIG_MPEGTSRAW_DEMUXER 0 +%define CONFIG_MPEGVIDEO_DEMUXER 0 +%define CONFIG_MPJPEG_DEMUXER 0 +%define CONFIG_MPL2_DEMUXER 0 +%define CONFIG_MPSUB_DEMUXER 0 +%define CONFIG_MSF_DEMUXER 0 +%define CONFIG_MSNWC_TCP_DEMUXER 0 +%define CONFIG_MSP_DEMUXER 0 +%define CONFIG_MTAF_DEMUXER 0 +%define CONFIG_MTV_DEMUXER 0 +%define CONFIG_MUSX_DEMUXER 0 +%define CONFIG_MV_DEMUXER 0 +%define CONFIG_MVI_DEMUXER 0 +%define CONFIG_MXF_DEMUXER 0 +%define CONFIG_MXG_DEMUXER 0 +%define CONFIG_NC_DEMUXER 0 +%define CONFIG_NISTSPHERE_DEMUXER 0 +%define CONFIG_NSP_DEMUXER 0 +%define CONFIG_NSV_DEMUXER 0 +%define CONFIG_NUT_DEMUXER 0 +%define CONFIG_NUV_DEMUXER 0 +%define CONFIG_OBU_DEMUXER 0 +%define CONFIG_OGG_DEMUXER 0 +%define CONFIG_OMA_DEMUXER 0 +%define CONFIG_OSQ_DEMUXER 0 +%define CONFIG_PAF_DEMUXER 0 +%define CONFIG_PCM_ALAW_DEMUXER 0 +%define CONFIG_PCM_MULAW_DEMUXER 0 +%define CONFIG_PCM_VIDC_DEMUXER 0 +%define CONFIG_PCM_F64BE_DEMUXER 0 +%define CONFIG_PCM_F64LE_DEMUXER 0 +%define CONFIG_PCM_F32BE_DEMUXER 0 +%define CONFIG_PCM_F32LE_DEMUXER 0 +%define CONFIG_PCM_S32BE_DEMUXER 0 +%define CONFIG_PCM_S32LE_DEMUXER 0 +%define CONFIG_PCM_S24BE_DEMUXER 0 +%define CONFIG_PCM_S24LE_DEMUXER 0 +%define CONFIG_PCM_S16BE_DEMUXER 0 +%define CONFIG_PCM_S16LE_DEMUXER 0 +%define CONFIG_PCM_S8_DEMUXER 0 +%define CONFIG_PCM_U32BE_DEMUXER 0 +%define CONFIG_PCM_U32LE_DEMUXER 0 +%define CONFIG_PCM_U24BE_DEMUXER 0 +%define CONFIG_PCM_U24LE_DEMUXER 0 +%define CONFIG_PCM_U16BE_DEMUXER 0 +%define CONFIG_PCM_U16LE_DEMUXER 0 +%define CONFIG_PCM_U8_DEMUXER 0 +%define CONFIG_PDV_DEMUXER 0 +%define CONFIG_PJS_DEMUXER 0 +%define CONFIG_PMP_DEMUXER 0 +%define CONFIG_PP_BNK_DEMUXER 0 +%define CONFIG_PVA_DEMUXER 0 +%define CONFIG_PVF_DEMUXER 0 +%define CONFIG_QCP_DEMUXER 0 +%define CONFIG_QOA_DEMUXER 0 +%define CONFIG_R3D_DEMUXER 0 +%define CONFIG_RAWVIDEO_DEMUXER 0 +%define CONFIG_RCWT_DEMUXER 0 +%define CONFIG_REALTEXT_DEMUXER 0 +%define CONFIG_REDSPARK_DEMUXER 0 +%define CONFIG_RKA_DEMUXER 0 +%define CONFIG_RL2_DEMUXER 0 +%define CONFIG_RM_DEMUXER 0 +%define CONFIG_ROQ_DEMUXER 0 +%define CONFIG_RPL_DEMUXER 0 +%define CONFIG_RSD_DEMUXER 0 +%define CONFIG_RSO_DEMUXER 0 +%define CONFIG_RTP_DEMUXER 0 +%define CONFIG_RTSP_DEMUXER 0 +%define CONFIG_S337M_DEMUXER 0 +%define CONFIG_SAMI_DEMUXER 0 +%define CONFIG_SAP_DEMUXER 0 +%define CONFIG_SBC_DEMUXER 0 +%define CONFIG_SBG_DEMUXER 0 +%define CONFIG_SCC_DEMUXER 0 +%define CONFIG_SCD_DEMUXER 0 +%define CONFIG_SDNS_DEMUXER 0 +%define CONFIG_SDP_DEMUXER 0 +%define CONFIG_SDR2_DEMUXER 0 +%define CONFIG_SDS_DEMUXER 0 +%define CONFIG_SDX_DEMUXER 0 +%define CONFIG_SEGAFILM_DEMUXER 0 +%define CONFIG_SER_DEMUXER 0 +%define CONFIG_SGA_DEMUXER 0 +%define CONFIG_SHORTEN_DEMUXER 0 +%define CONFIG_SIFF_DEMUXER 0 +%define CONFIG_SIMBIOSIS_IMX_DEMUXER 0 +%define CONFIG_SLN_DEMUXER 0 +%define CONFIG_SMACKER_DEMUXER 0 +%define CONFIG_SMJPEG_DEMUXER 0 +%define CONFIG_SMUSH_DEMUXER 0 +%define CONFIG_SOL_DEMUXER 0 +%define CONFIG_SOX_DEMUXER 0 +%define CONFIG_SPDIF_DEMUXER 0 +%define CONFIG_SRT_DEMUXER 0 +%define CONFIG_STR_DEMUXER 0 +%define CONFIG_STL_DEMUXER 0 +%define CONFIG_SUBVIEWER1_DEMUXER 0 +%define CONFIG_SUBVIEWER_DEMUXER 0 +%define CONFIG_SUP_DEMUXER 0 +%define CONFIG_SVAG_DEMUXER 0 +%define CONFIG_SVS_DEMUXER 0 +%define CONFIG_SWF_DEMUXER 0 +%define CONFIG_TAK_DEMUXER 0 +%define CONFIG_TEDCAPTIONS_DEMUXER 0 +%define CONFIG_THP_DEMUXER 0 +%define CONFIG_THREEDOSTR_DEMUXER 0 +%define CONFIG_TIERTEXSEQ_DEMUXER 0 +%define CONFIG_TMV_DEMUXER 0 +%define CONFIG_TRUEHD_DEMUXER 0 +%define CONFIG_TTA_DEMUXER 0 +%define CONFIG_TXD_DEMUXER 0 +%define CONFIG_TTY_DEMUXER 0 +%define CONFIG_TY_DEMUXER 0 +%define CONFIG_USM_DEMUXER 0 +%define CONFIG_V210_DEMUXER 0 +%define CONFIG_V210X_DEMUXER 0 +%define CONFIG_VAG_DEMUXER 0 +%define CONFIG_VC1_DEMUXER 0 +%define CONFIG_VC1T_DEMUXER 0 +%define CONFIG_VIVIDAS_DEMUXER 0 +%define CONFIG_VIVO_DEMUXER 0 +%define CONFIG_VMD_DEMUXER 0 +%define CONFIG_VOBSUB_DEMUXER 0 +%define CONFIG_VOC_DEMUXER 0 +%define CONFIG_VPK_DEMUXER 0 +%define CONFIG_VPLAYER_DEMUXER 0 +%define CONFIG_VQF_DEMUXER 0 +%define CONFIG_VVC_DEMUXER 0 +%define CONFIG_W64_DEMUXER 0 +%define CONFIG_WADY_DEMUXER 0 +%define CONFIG_WAVARC_DEMUXER 0 +%define CONFIG_WAV_DEMUXER 0 +%define CONFIG_WC3_DEMUXER 0 +%define CONFIG_WEBM_DASH_MANIFEST_DEMUXER 0 +%define CONFIG_WEBVTT_DEMUXER 0 +%define CONFIG_WSAUD_DEMUXER 0 +%define CONFIG_WSD_DEMUXER 0 +%define CONFIG_WSVQA_DEMUXER 0 +%define CONFIG_WTV_DEMUXER 0 +%define CONFIG_WVE_DEMUXER 0 +%define CONFIG_WV_DEMUXER 0 +%define CONFIG_XA_DEMUXER 0 +%define CONFIG_XBIN_DEMUXER 0 +%define CONFIG_XMD_DEMUXER 0 +%define CONFIG_XMV_DEMUXER 0 +%define CONFIG_XVAG_DEMUXER 0 +%define CONFIG_XWMA_DEMUXER 0 +%define CONFIG_YOP_DEMUXER 0 +%define CONFIG_YUV4MPEGPIPE_DEMUXER 0 +%define CONFIG_IMAGE_BMP_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_CRI_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_DDS_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_DPX_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_EXR_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_GEM_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_GIF_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_HDR_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_J2K_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_JPEG_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_JPEGLS_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_JPEGXL_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_JPEGXS_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_PAM_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_PBM_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_PCX_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_PFM_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_PGMYUV_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_PGM_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_PGX_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_PHM_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_PHOTOCD_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_PICTOR_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_PNG_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_PPM_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_PSD_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_QDRAW_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_QOI_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_SGI_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_SVG_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_SUNRAST_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_TIFF_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_VBN_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_WEBP_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_XBM_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_XPM_PIPE_DEMUXER 0 +%define CONFIG_IMAGE_XWD_PIPE_DEMUXER 0 +%define CONFIG_AVISYNTH_DEMUXER 0 +%define CONFIG_DVDVIDEO_DEMUXER 0 +%define CONFIG_LIBGME_DEMUXER 0 +%define CONFIG_LIBMODPLUG_DEMUXER 0 +%define CONFIG_LIBOPENMPT_DEMUXER 0 +%define CONFIG_VAPOURSYNTH_DEMUXER 0 +%define CONFIG_A64_MUXER 0 +%define CONFIG_AC3_MUXER 0 +%define CONFIG_AC4_MUXER 0 +%define CONFIG_ADTS_MUXER 0 +%define CONFIG_ADX_MUXER 0 +%define CONFIG_AEA_MUXER 0 +%define CONFIG_AIFF_MUXER 0 +%define CONFIG_ALP_MUXER 0 +%define CONFIG_AMR_MUXER 0 +%define CONFIG_AMV_MUXER 0 +%define CONFIG_APM_MUXER 0 +%define CONFIG_APNG_MUXER 0 +%define CONFIG_APTX_MUXER 0 +%define CONFIG_APTX_HD_MUXER 0 +%define CONFIG_APV_MUXER 0 +%define CONFIG_ARGO_ASF_MUXER 0 +%define CONFIG_ARGO_CVG_MUXER 0 +%define CONFIG_ASF_MUXER 0 +%define CONFIG_ASS_MUXER 0 +%define CONFIG_AST_MUXER 0 +%define CONFIG_ASF_STREAM_MUXER 0 +%define CONFIG_AU_MUXER 0 +%define CONFIG_AVI_MUXER 0 +%define CONFIG_AVIF_MUXER 0 +%define CONFIG_AVM2_MUXER 0 +%define CONFIG_AVS2_MUXER 0 +%define CONFIG_AVS3_MUXER 0 +%define CONFIG_BIT_MUXER 0 +%define CONFIG_CAF_MUXER 0 +%define CONFIG_CAVSVIDEO_MUXER 0 +%define CONFIG_CODEC2_MUXER 0 +%define CONFIG_CODEC2RAW_MUXER 0 +%define CONFIG_CRC_MUXER 0 +%define CONFIG_DASH_MUXER 0 +%define CONFIG_DATA_MUXER 0 +%define CONFIG_DAUD_MUXER 0 +%define CONFIG_DFPWM_MUXER 0 +%define CONFIG_DIRAC_MUXER 0 +%define CONFIG_DNXHD_MUXER 0 +%define CONFIG_DTS_MUXER 0 +%define CONFIG_DV_MUXER 0 +%define CONFIG_EAC3_MUXER 0 +%define CONFIG_EVC_MUXER 0 +%define CONFIG_F4V_MUXER 0 +%define CONFIG_FFMETADATA_MUXER 0 +%define CONFIG_FIFO_MUXER 0 +%define CONFIG_FILMSTRIP_MUXER 0 +%define CONFIG_FITS_MUXER 0 +%define CONFIG_FLAC_MUXER 0 +%define CONFIG_FLV_MUXER 0 +%define CONFIG_FRAMECRC_MUXER 0 +%define CONFIG_FRAMEHASH_MUXER 0 +%define CONFIG_FRAMEMD5_MUXER 0 +%define CONFIG_G722_MUXER 0 +%define CONFIG_G723_1_MUXER 0 +%define CONFIG_G726_MUXER 0 +%define CONFIG_G726LE_MUXER 0 +%define CONFIG_GIF_MUXER 0 +%define CONFIG_GSM_MUXER 0 +%define CONFIG_GXF_MUXER 0 +%define CONFIG_H261_MUXER 0 +%define CONFIG_H263_MUXER 0 +%define CONFIG_H264_MUXER 0 +%define CONFIG_HASH_MUXER 0 +%define CONFIG_HDS_MUXER 0 +%define CONFIG_HEVC_MUXER 0 +%define CONFIG_HLS_MUXER 0 +%define CONFIG_IAMF_MUXER 0 +%define CONFIG_ICO_MUXER 0 +%define CONFIG_ILBC_MUXER 0 +%define CONFIG_IMAGE2_MUXER 0 +%define CONFIG_IMAGE2PIPE_MUXER 0 +%define CONFIG_IPOD_MUXER 0 +%define CONFIG_IRCAM_MUXER 0 +%define CONFIG_ISMV_MUXER 0 +%define CONFIG_IVF_MUXER 0 +%define CONFIG_JACOSUB_MUXER 0 +%define CONFIG_KVAG_MUXER 0 +%define CONFIG_LATM_MUXER 0 +%define CONFIG_LC3_MUXER 0 +%define CONFIG_LRC_MUXER 0 +%define CONFIG_M4V_MUXER 0 +%define CONFIG_MCC_MUXER 0 +%define CONFIG_MD5_MUXER 0 +%define CONFIG_MATROSKA_MUXER 0 +%define CONFIG_MATROSKA_AUDIO_MUXER 0 +%define CONFIG_MICRODVD_MUXER 0 +%define CONFIG_MJPEG_MUXER 0 +%define CONFIG_MLP_MUXER 0 +%define CONFIG_MMF_MUXER 0 +%define CONFIG_MOV_MUXER 0 +%define CONFIG_MP2_MUXER 0 +%define CONFIG_MP3_MUXER 0 +%define CONFIG_MP4_MUXER 0 +%define CONFIG_MPEG1SYSTEM_MUXER 0 +%define CONFIG_MPEG1VCD_MUXER 0 +%define CONFIG_MPEG1VIDEO_MUXER 0 +%define CONFIG_MPEG2DVD_MUXER 0 +%define CONFIG_MPEG2SVCD_MUXER 0 +%define CONFIG_MPEG2VIDEO_MUXER 0 +%define CONFIG_MPEG2VOB_MUXER 0 +%define CONFIG_MPEGTS_MUXER 0 +%define CONFIG_MPJPEG_MUXER 0 +%define CONFIG_MXF_MUXER 0 +%define CONFIG_MXF_D10_MUXER 0 +%define CONFIG_MXF_OPATOM_MUXER 0 +%define CONFIG_NULL_MUXER 0 +%define CONFIG_NUT_MUXER 0 +%define CONFIG_OBU_MUXER 0 +%define CONFIG_OGA_MUXER 0 +%define CONFIG_OGG_MUXER 0 +%define CONFIG_OGV_MUXER 0 +%define CONFIG_OMA_MUXER 0 +%define CONFIG_OPUS_MUXER 0 +%define CONFIG_PCM_ALAW_MUXER 0 +%define CONFIG_PCM_MULAW_MUXER 0 +%define CONFIG_PCM_VIDC_MUXER 0 +%define CONFIG_PCM_F64BE_MUXER 0 +%define CONFIG_PCM_F64LE_MUXER 0 +%define CONFIG_PCM_F32BE_MUXER 0 +%define CONFIG_PCM_F32LE_MUXER 0 +%define CONFIG_PCM_S32BE_MUXER 0 +%define CONFIG_PCM_S32LE_MUXER 0 +%define CONFIG_PCM_S24BE_MUXER 0 +%define CONFIG_PCM_S24LE_MUXER 0 +%define CONFIG_PCM_S16BE_MUXER 0 +%define CONFIG_PCM_S16LE_MUXER 0 +%define CONFIG_PCM_S8_MUXER 0 +%define CONFIG_PCM_U32BE_MUXER 0 +%define CONFIG_PCM_U32LE_MUXER 0 +%define CONFIG_PCM_U24BE_MUXER 0 +%define CONFIG_PCM_U24LE_MUXER 0 +%define CONFIG_PCM_U16BE_MUXER 0 +%define CONFIG_PCM_U16LE_MUXER 0 +%define CONFIG_PCM_U8_MUXER 0 +%define CONFIG_PSP_MUXER 0 +%define CONFIG_RAWVIDEO_MUXER 0 +%define CONFIG_RCWT_MUXER 0 +%define CONFIG_RM_MUXER 0 +%define CONFIG_ROQ_MUXER 0 +%define CONFIG_RSO_MUXER 0 +%define CONFIG_RTP_MUXER 0 +%define CONFIG_RTP_MPEGTS_MUXER 0 +%define CONFIG_RTSP_MUXER 0 +%define CONFIG_SAP_MUXER 0 +%define CONFIG_SBC_MUXER 0 +%define CONFIG_SCC_MUXER 0 +%define CONFIG_SEGAFILM_MUXER 0 +%define CONFIG_SEGMENT_MUXER 0 +%define CONFIG_STREAM_SEGMENT_MUXER 0 +%define CONFIG_SMJPEG_MUXER 0 +%define CONFIG_SMOOTHSTREAMING_MUXER 0 +%define CONFIG_SOX_MUXER 0 +%define CONFIG_SPX_MUXER 0 +%define CONFIG_SPDIF_MUXER 0 +%define CONFIG_SRT_MUXER 0 +%define CONFIG_STREAMHASH_MUXER 0 +%define CONFIG_SUP_MUXER 0 +%define CONFIG_SWF_MUXER 0 +%define CONFIG_TEE_MUXER 0 +%define CONFIG_TG2_MUXER 0 +%define CONFIG_TGP_MUXER 0 +%define CONFIG_MKVTIMESTAMP_V2_MUXER 0 +%define CONFIG_TRUEHD_MUXER 0 +%define CONFIG_TTA_MUXER 0 +%define CONFIG_TTML_MUXER 0 +%define CONFIG_UNCODEDFRAMECRC_MUXER 0 +%define CONFIG_VC1_MUXER 0 +%define CONFIG_VC1T_MUXER 0 +%define CONFIG_VOC_MUXER 0 +%define CONFIG_VVC_MUXER 0 +%define CONFIG_W64_MUXER 0 +%define CONFIG_WAV_MUXER 0 +%define CONFIG_WEBM_MUXER 0 +%define CONFIG_WEBM_DASH_MANIFEST_MUXER 0 +%define CONFIG_WEBM_CHUNK_MUXER 0 +%define CONFIG_WEBP_MUXER 0 +%define CONFIG_WEBVTT_MUXER 0 +%define CONFIG_WHIP_MUXER 0 +%define CONFIG_WSAUD_MUXER 0 +%define CONFIG_WTV_MUXER 0 +%define CONFIG_WV_MUXER 0 +%define CONFIG_YUV4MPEGPIPE_MUXER 0 +%define CONFIG_CHROMAPRINT_MUXER 0 +%define CONFIG_ANDROID_CONTENT_PROTOCOL 0 +%define CONFIG_ASYNC_PROTOCOL 0 +%define CONFIG_BLURAY_PROTOCOL 0 +%define CONFIG_CACHE_PROTOCOL 0 +%define CONFIG_CONCAT_PROTOCOL 0 +%define CONFIG_CONCATF_PROTOCOL 0 +%define CONFIG_CRYPTO_PROTOCOL 0 +%define CONFIG_DATA_PROTOCOL 0 +%define CONFIG_FD_PROTOCOL 0 +%define CONFIG_FFRTMPCRYPT_PROTOCOL 0 +%define CONFIG_FFRTMPHTTP_PROTOCOL 0 +%define CONFIG_FILE_PROTOCOL 0 +%define CONFIG_FTP_PROTOCOL 0 +%define CONFIG_GOPHER_PROTOCOL 0 +%define CONFIG_GOPHERS_PROTOCOL 0 +%define CONFIG_HTTP_PROTOCOL 0 +%define CONFIG_HTTPPROXY_PROTOCOL 0 +%define CONFIG_HTTPS_PROTOCOL 0 +%define CONFIG_ICECAST_PROTOCOL 0 +%define CONFIG_MMSH_PROTOCOL 0 +%define CONFIG_MMST_PROTOCOL 0 +%define CONFIG_MD5_PROTOCOL 0 +%define CONFIG_PIPE_PROTOCOL 0 +%define CONFIG_PROMPEG_PROTOCOL 0 +%define CONFIG_RTMP_PROTOCOL 0 +%define CONFIG_RTMPE_PROTOCOL 0 +%define CONFIG_RTMPS_PROTOCOL 0 +%define CONFIG_RTMPT_PROTOCOL 0 +%define CONFIG_RTMPTE_PROTOCOL 0 +%define CONFIG_RTMPTS_PROTOCOL 0 +%define CONFIG_RTP_PROTOCOL 0 +%define CONFIG_SCTP_PROTOCOL 0 +%define CONFIG_SRTP_PROTOCOL 0 +%define CONFIG_SUBFILE_PROTOCOL 0 +%define CONFIG_TEE_PROTOCOL 0 +%define CONFIG_TCP_PROTOCOL 0 +%define CONFIG_TLS_PROTOCOL 0 +%define CONFIG_DTLS_PROTOCOL 0 +%define CONFIG_UDP_PROTOCOL 0 +%define CONFIG_UDPLITE_PROTOCOL 0 +%define CONFIG_UNIX_PROTOCOL 0 +%define CONFIG_LIBAMQP_PROTOCOL 0 +%define CONFIG_LIBRIST_PROTOCOL 0 +%define CONFIG_LIBRTMP_PROTOCOL 0 +%define CONFIG_LIBRTMPE_PROTOCOL 0 +%define CONFIG_LIBRTMPS_PROTOCOL 0 +%define CONFIG_LIBRTMPT_PROTOCOL 0 +%define CONFIG_LIBRTMPTE_PROTOCOL 0 +%define CONFIG_LIBSRT_PROTOCOL 0 +%define CONFIG_LIBSSH_PROTOCOL 0 +%define CONFIG_LIBSMBCLIENT_PROTOCOL 0 +%define CONFIG_LIBZMQ_PROTOCOL 0 +%define CONFIG_IPFS_GATEWAY_PROTOCOL 0 +%define CONFIG_IPNS_GATEWAY_PROTOCOL 0 diff --git a/libs/ffmpeg/config_components.h b/libs/ffmpeg/config_components.h new file mode 100644 index 00000000000..354bb86fa27 --- /dev/null +++ b/libs/ffmpeg/config_components.h @@ -0,0 +1,2308 @@ +/* Automatically generated by configure - do not modify! */ +#ifndef FFMPEG_CONFIG_COMPONENTS_H +#define FFMPEG_CONFIG_COMPONENTS_H +#define CONFIG_AAC_ADTSTOASC_BSF 0 +#define CONFIG_AHX_TO_MP2_BSF 0 +#define CONFIG_APV_METADATA_BSF 0 +#define CONFIG_AV1_FRAME_MERGE_BSF 0 +#define CONFIG_AV1_FRAME_SPLIT_BSF 0 +#define CONFIG_AV1_METADATA_BSF 0 +#define CONFIG_CHOMP_BSF 0 +#define CONFIG_DUMP_EXTRADATA_BSF 0 +#define CONFIG_DCA_CORE_BSF 0 +#define CONFIG_DOVI_RPU_BSF 0 +#define CONFIG_DTS2PTS_BSF 0 +#define CONFIG_DV_ERROR_MARKER_BSF 0 +#define CONFIG_EAC3_CORE_BSF 0 +#define CONFIG_EIA608_TO_SMPTE436M_BSF 0 +#define CONFIG_EVC_FRAME_MERGE_BSF 0 +#define CONFIG_EXTRACT_EXTRADATA_BSF 0 +#define CONFIG_FILTER_UNITS_BSF 0 +#define CONFIG_H264_METADATA_BSF 0 +#define CONFIG_H264_MP4TOANNEXB_BSF 0 +#define CONFIG_H264_REDUNDANT_PPS_BSF 0 +#define CONFIG_HAPQA_EXTRACT_BSF 0 +#define CONFIG_HEVC_METADATA_BSF 0 +#define CONFIG_HEVC_MP4TOANNEXB_BSF 0 +#define CONFIG_IMX_DUMP_HEADER_BSF 0 +#define CONFIG_LCEVC_METADATA_BSF 0 +#define CONFIG_MEDIA100_TO_MJPEGB_BSF 0 +#define CONFIG_MJPEG2JPEG_BSF 0 +#define CONFIG_MJPEGA_DUMP_HEADER_BSF 0 +#define CONFIG_MPEG2_METADATA_BSF 0 +#define CONFIG_MPEG4_UNPACK_BFRAMES_BSF 0 +#define CONFIG_MOV2TEXTSUB_BSF 0 +#define CONFIG_NOISE_BSF 0 +#define CONFIG_NULL_BSF 0 +#define CONFIG_OPUS_METADATA_BSF 0 +#define CONFIG_PCM_RECHUNK_BSF 0 +#define CONFIG_PGS_FRAME_MERGE_BSF 0 +#define CONFIG_PRORES_METADATA_BSF 0 +#define CONFIG_REMOVE_EXTRADATA_BSF 0 +#define CONFIG_SETTS_BSF 0 +#define CONFIG_SHOWINFO_BSF 0 +#define CONFIG_SMPTE436M_TO_EIA608_BSF 0 +#define CONFIG_TEXT2MOVSUB_BSF 0 +#define CONFIG_TRACE_HEADERS_BSF 0 +#define CONFIG_TRUEHD_CORE_BSF 0 +#define CONFIG_VP9_METADATA_BSF 0 +#define CONFIG_VP9_RAW_REORDER_BSF 0 +#define CONFIG_VP9_SUPERFRAME_BSF 0 +#define CONFIG_VP9_SUPERFRAME_SPLIT_BSF 0 +#define CONFIG_VVC_METADATA_BSF 0 +#define CONFIG_VVC_MP4TOANNEXB_BSF 0 +#define CONFIG_AASC_DECODER 0 +#define CONFIG_AIC_DECODER 0 +#define CONFIG_ALIAS_PIX_DECODER 0 +#define CONFIG_AGM_DECODER 0 +#define CONFIG_AMV_DECODER 0 +#define CONFIG_ANM_DECODER 0 +#define CONFIG_ANSI_DECODER 0 +#define CONFIG_APNG_DECODER 0 +#define CONFIG_APV_DECODER 0 +#define CONFIG_ARBC_DECODER 0 +#define CONFIG_ARGO_DECODER 0 +#define CONFIG_ASV1_DECODER 0 +#define CONFIG_ASV2_DECODER 0 +#define CONFIG_AURA_DECODER 0 +#define CONFIG_AURA2_DECODER 0 +#define CONFIG_AVRP_DECODER 0 +#define CONFIG_AVRN_DECODER 0 +#define CONFIG_AVS_DECODER 0 +#define CONFIG_AVUI_DECODER 0 +#define CONFIG_BETHSOFTVID_DECODER 0 +#define CONFIG_BFI_DECODER 0 +#define CONFIG_BINK_DECODER 0 +#define CONFIG_BITPACKED_DECODER 0 +#define CONFIG_BMP_DECODER 0 +#define CONFIG_BMV_VIDEO_DECODER 0 +#define CONFIG_BRENDER_PIX_DECODER 0 +#define CONFIG_C93_DECODER 0 +#define CONFIG_CAVS_DECODER 0 +#define CONFIG_CDGRAPHICS_DECODER 0 +#define CONFIG_CDTOONS_DECODER 0 +#define CONFIG_CDXL_DECODER 0 +#define CONFIG_CFHD_DECODER 0 +#define CONFIG_CINEPAK_DECODER 0 +#define CONFIG_CLEARVIDEO_DECODER 0 +#define CONFIG_CLJR_DECODER 0 +#define CONFIG_CLLC_DECODER 0 +#define CONFIG_COMFORTNOISE_DECODER 0 +#define CONFIG_CPIA_DECODER 0 +#define CONFIG_CRI_DECODER 0 +#define CONFIG_CSCD_DECODER 0 +#define CONFIG_CYUV_DECODER 0 +#define CONFIG_DDS_DECODER 0 +#define CONFIG_DFA_DECODER 0 +#define CONFIG_DIRAC_DECODER 0 +#define CONFIG_DNXHD_DECODER 0 +#define CONFIG_DPX_DECODER 0 +#define CONFIG_DSICINVIDEO_DECODER 0 +#define CONFIG_DVAUDIO_DECODER 0 +#define CONFIG_DVVIDEO_DECODER 0 +#define CONFIG_DXA_DECODER 0 +#define CONFIG_DXTORY_DECODER 0 +#define CONFIG_DXV_DECODER 0 +#define CONFIG_EACMV_DECODER 0 +#define CONFIG_EAMAD_DECODER 0 +#define CONFIG_EATGQ_DECODER 0 +#define CONFIG_EATGV_DECODER 0 +#define CONFIG_EATQI_DECODER 0 +#define CONFIG_EIGHTBPS_DECODER 0 +#define CONFIG_EIGHTSVX_EXP_DECODER 0 +#define CONFIG_EIGHTSVX_FIB_DECODER 0 +#define CONFIG_ESCAPE124_DECODER 0 +#define CONFIG_ESCAPE130_DECODER 0 +#define CONFIG_EXR_DECODER 0 +#define CONFIG_FFV1_DECODER 0 +#define CONFIG_FFVHUFF_DECODER 0 +#define CONFIG_FIC_DECODER 0 +#define CONFIG_FITS_DECODER 0 +#define CONFIG_FLASHSV_DECODER 0 +#define CONFIG_FLASHSV2_DECODER 0 +#define CONFIG_FLIC_DECODER 0 +#define CONFIG_FLV_DECODER 0 +#define CONFIG_FMVC_DECODER 0 +#define CONFIG_FOURXM_DECODER 0 +#define CONFIG_FRAPS_DECODER 0 +#define CONFIG_FRWU_DECODER 0 +#define CONFIG_G2M_DECODER 0 +#define CONFIG_GDV_DECODER 0 +#define CONFIG_GEM_DECODER 0 +#define CONFIG_GIF_DECODER 0 +#define CONFIG_H261_DECODER 0 +#define CONFIG_H263_DECODER 0 +#define CONFIG_H263I_DECODER 0 +#define CONFIG_H263P_DECODER 0 +#define CONFIG_H263_V4L2M2M_DECODER 0 +#define CONFIG_H264_DECODER 0 +#define CONFIG_H264_V4L2M2M_DECODER 0 +#define CONFIG_H264_MEDIACODEC_DECODER 0 +#define CONFIG_H264_MMAL_DECODER 0 +#define CONFIG_H264_QSV_DECODER 0 +#define CONFIG_H264_RKMPP_DECODER 0 +#define CONFIG_HAP_DECODER 0 +#define CONFIG_HEVC_DECODER 0 +#define CONFIG_HEVC_QSV_DECODER 0 +#define CONFIG_HEVC_RKMPP_DECODER 0 +#define CONFIG_HEVC_V4L2M2M_DECODER 0 +#define CONFIG_HNM4_VIDEO_DECODER 0 +#define CONFIG_HQ_HQA_DECODER 0 +#define CONFIG_HQX_DECODER 0 +#define CONFIG_HUFFYUV_DECODER 0 +#define CONFIG_HYMT_DECODER 0 +#define CONFIG_IDCIN_DECODER 0 +#define CONFIG_IFF_ILBM_DECODER 0 +#define CONFIG_IMM4_DECODER 0 +#define CONFIG_IMM5_DECODER 0 +#define CONFIG_INDEO2_DECODER 0 +#define CONFIG_INDEO3_DECODER 0 +#define CONFIG_INDEO4_DECODER 0 +#define CONFIG_INDEO5_DECODER 0 +#define CONFIG_INTERPLAY_VIDEO_DECODER 0 +#define CONFIG_IPU_DECODER 0 +#define CONFIG_JPEG2000_DECODER 0 +#define CONFIG_JPEGLS_DECODER 0 +#define CONFIG_JV_DECODER 0 +#define CONFIG_KGV1_DECODER 0 +#define CONFIG_KMVC_DECODER 0 +#define CONFIG_LAGARITH_DECODER 0 +#define CONFIG_LEAD_DECODER 0 +#define CONFIG_LOCO_DECODER 0 +#define CONFIG_LSCR_DECODER 0 +#define CONFIG_M101_DECODER 0 +#define CONFIG_MAGICYUV_DECODER 0 +#define CONFIG_MDEC_DECODER 0 +#define CONFIG_MEDIA100_DECODER 0 +#define CONFIG_MIMIC_DECODER 0 +#define CONFIG_MJPEG_DECODER 0 +#define CONFIG_MJPEGB_DECODER 0 +#define CONFIG_MMVIDEO_DECODER 0 +#define CONFIG_MOBICLIP_DECODER 0 +#define CONFIG_MOTIONPIXELS_DECODER 0 +#define CONFIG_MPEG1VIDEO_DECODER 0 +#define CONFIG_MPEG2VIDEO_DECODER 0 +#define CONFIG_MPEG4_DECODER 0 +#define CONFIG_MPEG4_V4L2M2M_DECODER 0 +#define CONFIG_MPEG4_MMAL_DECODER 0 +#define CONFIG_MPEGVIDEO_DECODER 0 +#define CONFIG_MPEG1_V4L2M2M_DECODER 0 +#define CONFIG_MPEG2_MMAL_DECODER 0 +#define CONFIG_MPEG2_V4L2M2M_DECODER 0 +#define CONFIG_MPEG2_QSV_DECODER 0 +#define CONFIG_MPEG2_MEDIACODEC_DECODER 0 +#define CONFIG_MSA1_DECODER 0 +#define CONFIG_MSCC_DECODER 0 +#define CONFIG_MSMPEG4V1_DECODER 0 +#define CONFIG_MSMPEG4V2_DECODER 0 +#define CONFIG_MSMPEG4V3_DECODER 0 +#define CONFIG_MSP2_DECODER 0 +#define CONFIG_MSRLE_DECODER 0 +#define CONFIG_MSS1_DECODER 0 +#define CONFIG_MSS2_DECODER 0 +#define CONFIG_MSVIDEO1_DECODER 0 +#define CONFIG_MSZH_DECODER 0 +#define CONFIG_MTS2_DECODER 0 +#define CONFIG_MV30_DECODER 0 +#define CONFIG_MVC1_DECODER 0 +#define CONFIG_MVC2_DECODER 0 +#define CONFIG_MVDV_DECODER 0 +#define CONFIG_MVHA_DECODER 0 +#define CONFIG_MWSC_DECODER 0 +#define CONFIG_MXPEG_DECODER 0 +#define CONFIG_NOTCHLC_DECODER 0 +#define CONFIG_NUV_DECODER 0 +#define CONFIG_PAF_VIDEO_DECODER 0 +#define CONFIG_PAM_DECODER 0 +#define CONFIG_PBM_DECODER 0 +#define CONFIG_PCX_DECODER 0 +#define CONFIG_PDV_DECODER 0 +#define CONFIG_PFM_DECODER 0 +#define CONFIG_PGM_DECODER 0 +#define CONFIG_PGMYUV_DECODER 0 +#define CONFIG_PGX_DECODER 0 +#define CONFIG_PHM_DECODER 0 +#define CONFIG_PHOTOCD_DECODER 0 +#define CONFIG_PICTOR_DECODER 0 +#define CONFIG_PIXLET_DECODER 0 +#define CONFIG_PNG_DECODER 0 +#define CONFIG_PPM_DECODER 0 +#define CONFIG_PRORES_DECODER 0 +#define CONFIG_PRORES_RAW_DECODER 0 +#define CONFIG_PROSUMER_DECODER 0 +#define CONFIG_PSD_DECODER 0 +#define CONFIG_PTX_DECODER 0 +#define CONFIG_QDRAW_DECODER 0 +#define CONFIG_QOI_DECODER 0 +#define CONFIG_QPEG_DECODER 0 +#define CONFIG_QTRLE_DECODER 0 +#define CONFIG_R10K_DECODER 0 +#define CONFIG_R210_DECODER 0 +#define CONFIG_RASC_DECODER 0 +#define CONFIG_RAWVIDEO_DECODER 0 +#define CONFIG_RKA_DECODER 0 +#define CONFIG_RL2_DECODER 0 +#define CONFIG_ROQ_DECODER 0 +#define CONFIG_RPZA_DECODER 0 +#define CONFIG_RSCC_DECODER 0 +#define CONFIG_RTV1_DECODER 0 +#define CONFIG_RV10_DECODER 0 +#define CONFIG_RV20_DECODER 0 +#define CONFIG_RV30_DECODER 0 +#define CONFIG_RV40_DECODER 0 +#define CONFIG_RV60_DECODER 0 +#define CONFIG_S302M_DECODER 0 +#define CONFIG_SANM_DECODER 0 +#define CONFIG_SCPR_DECODER 0 +#define CONFIG_SCREENPRESSO_DECODER 0 +#define CONFIG_SGA_DECODER 0 +#define CONFIG_SGI_DECODER 0 +#define CONFIG_SGIRLE_DECODER 0 +#define CONFIG_SHEERVIDEO_DECODER 0 +#define CONFIG_SIMBIOSIS_IMX_DECODER 0 +#define CONFIG_SMACKER_DECODER 0 +#define CONFIG_SMC_DECODER 0 +#define CONFIG_SMVJPEG_DECODER 0 +#define CONFIG_SNOW_DECODER 0 +#define CONFIG_SP5X_DECODER 0 +#define CONFIG_SPEEDHQ_DECODER 0 +#define CONFIG_SPEEX_DECODER 0 +#define CONFIG_SRGC_DECODER 0 +#define CONFIG_SUNRAST_DECODER 0 +#define CONFIG_SVQ1_DECODER 0 +#define CONFIG_SVQ3_DECODER 0 +#define CONFIG_TARGA_DECODER 0 +#define CONFIG_TARGA_Y216_DECODER 0 +#define CONFIG_TDSC_DECODER 0 +#define CONFIG_THEORA_DECODER 0 +#define CONFIG_THP_DECODER 0 +#define CONFIG_TIERTEXSEQVIDEO_DECODER 0 +#define CONFIG_TIFF_DECODER 0 +#define CONFIG_TMV_DECODER 0 +#define CONFIG_TRUEMOTION1_DECODER 0 +#define CONFIG_TRUEMOTION2_DECODER 0 +#define CONFIG_TRUEMOTION2RT_DECODER 0 +#define CONFIG_TSCC_DECODER 0 +#define CONFIG_TSCC2_DECODER 0 +#define CONFIG_TXD_DECODER 0 +#define CONFIG_ULTI_DECODER 0 +#define CONFIG_UTVIDEO_DECODER 0 +#define CONFIG_V210_DECODER 0 +#define CONFIG_V210X_DECODER 0 +#define CONFIG_V308_DECODER 0 +#define CONFIG_V408_DECODER 0 +#define CONFIG_V410_DECODER 0 +#define CONFIG_VB_DECODER 0 +#define CONFIG_VBN_DECODER 0 +#define CONFIG_VBLE_DECODER 0 +#define CONFIG_VC1_DECODER 0 +#define CONFIG_VC1IMAGE_DECODER 0 +#define CONFIG_VC1_MMAL_DECODER 0 +#define CONFIG_VC1_QSV_DECODER 0 +#define CONFIG_VC1_V4L2M2M_DECODER 0 +#define CONFIG_VCR1_DECODER 0 +#define CONFIG_VMDVIDEO_DECODER 0 +#define CONFIG_VMIX_DECODER 0 +#define CONFIG_VMNC_DECODER 0 +#define CONFIG_VP3_DECODER 0 +#define CONFIG_VP4_DECODER 0 +#define CONFIG_VP5_DECODER 0 +#define CONFIG_VP6_DECODER 0 +#define CONFIG_VP6A_DECODER 0 +#define CONFIG_VP6F_DECODER 0 +#define CONFIG_VP7_DECODER 0 +#define CONFIG_VP8_DECODER 0 +#define CONFIG_VP8_RKMPP_DECODER 0 +#define CONFIG_VP8_V4L2M2M_DECODER 0 +#define CONFIG_VP9_DECODER 0 +#define CONFIG_VP9_RKMPP_DECODER 0 +#define CONFIG_VP9_V4L2M2M_DECODER 0 +#define CONFIG_VQA_DECODER 0 +#define CONFIG_VQC_DECODER 0 +#define CONFIG_VVC_DECODER 0 +#define CONFIG_WBMP_DECODER 0 +#define CONFIG_WEBP_DECODER 0 +#define CONFIG_WCMV_DECODER 0 +#define CONFIG_WRAPPED_AVFRAME_DECODER 0 +#define CONFIG_WMV1_DECODER 0 +#define CONFIG_WMV2_DECODER 0 +#define CONFIG_WMV3_DECODER 0 +#define CONFIG_WMV3IMAGE_DECODER 0 +#define CONFIG_WNV1_DECODER 0 +#define CONFIG_XAN_WC3_DECODER 0 +#define CONFIG_XAN_WC4_DECODER 0 +#define CONFIG_XBM_DECODER 0 +#define CONFIG_XFACE_DECODER 0 +#define CONFIG_XL_DECODER 0 +#define CONFIG_XPM_DECODER 0 +#define CONFIG_XWD_DECODER 0 +#define CONFIG_Y41P_DECODER 0 +#define CONFIG_YLC_DECODER 0 +#define CONFIG_YOP_DECODER 0 +#define CONFIG_YUV4_DECODER 0 +#define CONFIG_ZERO12V_DECODER 0 +#define CONFIG_ZEROCODEC_DECODER 0 +#define CONFIG_ZLIB_DECODER 0 +#define CONFIG_ZMBV_DECODER 0 +#define CONFIG_AAC_DECODER 0 +#define CONFIG_AAC_FIXED_DECODER 0 +#define CONFIG_AAC_LATM_DECODER 0 +#define CONFIG_AC3_DECODER 0 +#define CONFIG_AC3_FIXED_DECODER 0 +#define CONFIG_ACELP_KELVIN_DECODER 0 +#define CONFIG_AHX_DECODER 0 +#define CONFIG_ALAC_DECODER 0 +#define CONFIG_ALS_DECODER 0 +#define CONFIG_AMRNB_DECODER 0 +#define CONFIG_AMRWB_DECODER 0 +#define CONFIG_APAC_DECODER 0 +#define CONFIG_APE_DECODER 0 +#define CONFIG_APTX_DECODER 0 +#define CONFIG_APTX_HD_DECODER 0 +#define CONFIG_ATRAC1_DECODER 0 +#define CONFIG_ATRAC3_DECODER 0 +#define CONFIG_ATRAC3AL_DECODER 0 +#define CONFIG_ATRAC3P_DECODER 0 +#define CONFIG_ATRAC3PAL_DECODER 0 +#define CONFIG_ATRAC9_DECODER 0 +#define CONFIG_BINKAUDIO_DCT_DECODER 0 +#define CONFIG_BINKAUDIO_RDFT_DECODER 0 +#define CONFIG_BMV_AUDIO_DECODER 0 +#define CONFIG_BONK_DECODER 0 +#define CONFIG_COOK_DECODER 0 +#define CONFIG_DCA_DECODER 0 +#define CONFIG_DFPWM_DECODER 0 +#define CONFIG_DOLBY_E_DECODER 0 +#define CONFIG_DSD_LSBF_DECODER 0 +#define CONFIG_DSD_MSBF_DECODER 0 +#define CONFIG_DSD_LSBF_PLANAR_DECODER 0 +#define CONFIG_DSD_MSBF_PLANAR_DECODER 0 +#define CONFIG_DSICINAUDIO_DECODER 0 +#define CONFIG_DSS_SP_DECODER 0 +#define CONFIG_DST_DECODER 0 +#define CONFIG_EAC3_DECODER 0 +#define CONFIG_EVRC_DECODER 0 +#define CONFIG_FASTAUDIO_DECODER 0 +#define CONFIG_FFWAVESYNTH_DECODER 0 +#define CONFIG_FLAC_DECODER 0 +#define CONFIG_FTR_DECODER 0 +#define CONFIG_G723_1_DECODER 0 +#define CONFIG_G728_DECODER 0 +#define CONFIG_G729_DECODER 0 +#define CONFIG_GSM_DECODER 0 +#define CONFIG_GSM_MS_DECODER 0 +#define CONFIG_HCA_DECODER 0 +#define CONFIG_HCOM_DECODER 0 +#define CONFIG_HDR_DECODER 0 +#define CONFIG_IAC_DECODER 0 +#define CONFIG_ILBC_DECODER 0 +#define CONFIG_IMC_DECODER 0 +#define CONFIG_INTERPLAY_ACM_DECODER 0 +#define CONFIG_MACE3_DECODER 0 +#define CONFIG_MACE6_DECODER 0 +#define CONFIG_METASOUND_DECODER 0 +#define CONFIG_MISC4_DECODER 0 +#define CONFIG_MLP_DECODER 0 +#define CONFIG_MP1_DECODER 0 +#define CONFIG_MP1FLOAT_DECODER 0 +#define CONFIG_MP2_DECODER 0 +#define CONFIG_MP2FLOAT_DECODER 0 +#define CONFIG_MP3FLOAT_DECODER 0 +#define CONFIG_MP3_DECODER 0 +#define CONFIG_MP3ADUFLOAT_DECODER 0 +#define CONFIG_MP3ADU_DECODER 0 +#define CONFIG_MP3ON4FLOAT_DECODER 0 +#define CONFIG_MP3ON4_DECODER 0 +#define CONFIG_MPC7_DECODER 0 +#define CONFIG_MPC8_DECODER 0 +#define CONFIG_MSNSIREN_DECODER 0 +#define CONFIG_NELLYMOSER_DECODER 0 +#define CONFIG_ON2AVC_DECODER 0 +#define CONFIG_OPUS_DECODER 0 +#define CONFIG_OSQ_DECODER 0 +#define CONFIG_PAF_AUDIO_DECODER 0 +#define CONFIG_QCELP_DECODER 0 +#define CONFIG_QDM2_DECODER 0 +#define CONFIG_QDMC_DECODER 0 +#define CONFIG_QOA_DECODER 0 +#define CONFIG_RA_144_DECODER 0 +#define CONFIG_RA_288_DECODER 0 +#define CONFIG_RALF_DECODER 0 +#define CONFIG_SBC_DECODER 0 +#define CONFIG_SHORTEN_DECODER 0 +#define CONFIG_SIPR_DECODER 0 +#define CONFIG_SIREN_DECODER 0 +#define CONFIG_SMACKAUD_DECODER 0 +#define CONFIG_SONIC_DECODER 0 +#define CONFIG_TAK_DECODER 0 +#define CONFIG_TRUEHD_DECODER 0 +#define CONFIG_TRUESPEECH_DECODER 0 +#define CONFIG_TTA_DECODER 0 +#define CONFIG_TWINVQ_DECODER 0 +#define CONFIG_VMDAUDIO_DECODER 0 +#define CONFIG_VORBIS_DECODER 0 +#define CONFIG_WAVARC_DECODER 0 +#define CONFIG_WAVPACK_DECODER 0 +#define CONFIG_WMALOSSLESS_DECODER 0 +#define CONFIG_WMAPRO_DECODER 0 +#define CONFIG_WMAV1_DECODER 0 +#define CONFIG_WMAV2_DECODER 0 +#define CONFIG_WMAVOICE_DECODER 0 +#define CONFIG_WS_SND1_DECODER 0 +#define CONFIG_XMA1_DECODER 0 +#define CONFIG_XMA2_DECODER 0 +#define CONFIG_PCM_ALAW_DECODER 0 +#define CONFIG_PCM_BLURAY_DECODER 0 +#define CONFIG_PCM_DVD_DECODER 0 +#define CONFIG_PCM_F16LE_DECODER 0 +#define CONFIG_PCM_F24LE_DECODER 0 +#define CONFIG_PCM_F32BE_DECODER 0 +#define CONFIG_PCM_F32LE_DECODER 0 +#define CONFIG_PCM_F64BE_DECODER 0 +#define CONFIG_PCM_F64LE_DECODER 0 +#define CONFIG_PCM_LXF_DECODER 0 +#define CONFIG_PCM_MULAW_DECODER 0 +#define CONFIG_PCM_S8_DECODER 0 +#define CONFIG_PCM_S8_PLANAR_DECODER 0 +#define CONFIG_PCM_S16BE_DECODER 0 +#define CONFIG_PCM_S16BE_PLANAR_DECODER 0 +#define CONFIG_PCM_S16LE_DECODER 0 +#define CONFIG_PCM_S16LE_PLANAR_DECODER 0 +#define CONFIG_PCM_S24BE_DECODER 0 +#define CONFIG_PCM_S24DAUD_DECODER 0 +#define CONFIG_PCM_S24LE_DECODER 0 +#define CONFIG_PCM_S24LE_PLANAR_DECODER 0 +#define CONFIG_PCM_S32BE_DECODER 0 +#define CONFIG_PCM_S32LE_DECODER 0 +#define CONFIG_PCM_S32LE_PLANAR_DECODER 0 +#define CONFIG_PCM_S64BE_DECODER 0 +#define CONFIG_PCM_S64LE_DECODER 0 +#define CONFIG_PCM_SGA_DECODER 0 +#define CONFIG_PCM_U8_DECODER 0 +#define CONFIG_PCM_U16BE_DECODER 0 +#define CONFIG_PCM_U16LE_DECODER 0 +#define CONFIG_PCM_U24BE_DECODER 0 +#define CONFIG_PCM_U24LE_DECODER 0 +#define CONFIG_PCM_U32BE_DECODER 0 +#define CONFIG_PCM_U32LE_DECODER 0 +#define CONFIG_PCM_VIDC_DECODER 0 +#define CONFIG_CBD2_DPCM_DECODER 0 +#define CONFIG_DERF_DPCM_DECODER 0 +#define CONFIG_GREMLIN_DPCM_DECODER 0 +#define CONFIG_INTERPLAY_DPCM_DECODER 0 +#define CONFIG_ROQ_DPCM_DECODER 0 +#define CONFIG_SDX2_DPCM_DECODER 0 +#define CONFIG_SOL_DPCM_DECODER 0 +#define CONFIG_XAN_DPCM_DECODER 0 +#define CONFIG_WADY_DPCM_DECODER 0 +#define CONFIG_ADPCM_4XM_DECODER 0 +#define CONFIG_ADPCM_ADX_DECODER 0 +#define CONFIG_ADPCM_AFC_DECODER 0 +#define CONFIG_ADPCM_AGM_DECODER 0 +#define CONFIG_ADPCM_AICA_DECODER 0 +#define CONFIG_ADPCM_ARGO_DECODER 0 +#define CONFIG_ADPCM_CIRCUS_DECODER 0 +#define CONFIG_ADPCM_CT_DECODER 0 +#define CONFIG_ADPCM_DTK_DECODER 0 +#define CONFIG_ADPCM_EA_DECODER 0 +#define CONFIG_ADPCM_EA_MAXIS_XA_DECODER 0 +#define CONFIG_ADPCM_EA_R1_DECODER 0 +#define CONFIG_ADPCM_EA_R2_DECODER 0 +#define CONFIG_ADPCM_EA_R3_DECODER 0 +#define CONFIG_ADPCM_EA_XAS_DECODER 0 +#define CONFIG_ADPCM_G722_DECODER 0 +#define CONFIG_ADPCM_G726_DECODER 0 +#define CONFIG_ADPCM_G726LE_DECODER 0 +#define CONFIG_ADPCM_IMA_ACORN_DECODER 0 +#define CONFIG_ADPCM_IMA_AMV_DECODER 0 +#define CONFIG_ADPCM_IMA_ALP_DECODER 0 +#define CONFIG_ADPCM_IMA_APC_DECODER 0 +#define CONFIG_ADPCM_IMA_APM_DECODER 0 +#define CONFIG_ADPCM_IMA_CUNNING_DECODER 0 +#define CONFIG_ADPCM_IMA_DAT4_DECODER 0 +#define CONFIG_ADPCM_IMA_DK3_DECODER 0 +#define CONFIG_ADPCM_IMA_DK4_DECODER 0 +#define CONFIG_ADPCM_IMA_EA_EACS_DECODER 0 +#define CONFIG_ADPCM_IMA_EA_SEAD_DECODER 0 +#define CONFIG_ADPCM_IMA_ESCAPE_DECODER 0 +#define CONFIG_ADPCM_IMA_HVQM2_DECODER 0 +#define CONFIG_ADPCM_IMA_HVQM4_DECODER 0 +#define CONFIG_ADPCM_IMA_ISS_DECODER 0 +#define CONFIG_ADPCM_IMA_MAGIX_DECODER 0 +#define CONFIG_ADPCM_IMA_MOFLEX_DECODER 0 +#define CONFIG_ADPCM_IMA_MTF_DECODER 0 +#define CONFIG_ADPCM_IMA_OKI_DECODER 0 +#define CONFIG_ADPCM_IMA_PDA_DECODER 0 +#define CONFIG_ADPCM_IMA_QT_DECODER 0 +#define CONFIG_ADPCM_IMA_RAD_DECODER 0 +#define CONFIG_ADPCM_IMA_SSI_DECODER 0 +#define CONFIG_ADPCM_IMA_SMJPEG_DECODER 0 +#define CONFIG_ADPCM_IMA_WAV_DECODER 0 +#define CONFIG_ADPCM_IMA_WS_DECODER 0 +#define CONFIG_ADPCM_IMA_XBOX_DECODER 0 +#define CONFIG_ADPCM_MS_DECODER 0 +#define CONFIG_ADPCM_MTAF_DECODER 0 +#define CONFIG_ADPCM_N64_DECODER 0 +#define CONFIG_ADPCM_PSX_DECODER 0 +#define CONFIG_ADPCM_PSXC_DECODER 0 +#define CONFIG_ADPCM_SANYO_DECODER 0 +#define CONFIG_ADPCM_SBPRO_2_DECODER 0 +#define CONFIG_ADPCM_SBPRO_3_DECODER 0 +#define CONFIG_ADPCM_SBPRO_4_DECODER 0 +#define CONFIG_ADPCM_SWF_DECODER 0 +#define CONFIG_ADPCM_THP_DECODER 0 +#define CONFIG_ADPCM_THP_LE_DECODER 0 +#define CONFIG_ADPCM_VIMA_DECODER 0 +#define CONFIG_ADPCM_XA_DECODER 0 +#define CONFIG_ADPCM_XMD_DECODER 0 +#define CONFIG_ADPCM_YAMAHA_DECODER 0 +#define CONFIG_ADPCM_ZORK_DECODER 0 +#define CONFIG_SSA_DECODER 0 +#define CONFIG_ASS_DECODER 0 +#define CONFIG_CCAPTION_DECODER 0 +#define CONFIG_DVBSUB_DECODER 0 +#define CONFIG_DVDSUB_DECODER 0 +#define CONFIG_JACOSUB_DECODER 0 +#define CONFIG_MICRODVD_DECODER 0 +#define CONFIG_MOVTEXT_DECODER 0 +#define CONFIG_MPL2_DECODER 0 +#define CONFIG_PGSSUB_DECODER 0 +#define CONFIG_PJS_DECODER 0 +#define CONFIG_REALTEXT_DECODER 0 +#define CONFIG_SAMI_DECODER 0 +#define CONFIG_SRT_DECODER 0 +#define CONFIG_STL_DECODER 0 +#define CONFIG_SUBRIP_DECODER 0 +#define CONFIG_SUBVIEWER_DECODER 0 +#define CONFIG_SUBVIEWER1_DECODER 0 +#define CONFIG_TEXT_DECODER 0 +#define CONFIG_VPLAYER_DECODER 0 +#define CONFIG_WEBVTT_DECODER 0 +#define CONFIG_XSUB_DECODER 0 +#define CONFIG_AAC_AT_DECODER 0 +#define CONFIG_AC3_AT_DECODER 0 +#define CONFIG_ADPCM_IMA_QT_AT_DECODER 0 +#define CONFIG_ALAC_AT_DECODER 0 +#define CONFIG_AMR_NB_AT_DECODER 0 +#define CONFIG_EAC3_AT_DECODER 0 +#define CONFIG_GSM_MS_AT_DECODER 0 +#define CONFIG_ILBC_AT_DECODER 0 +#define CONFIG_MP1_AT_DECODER 0 +#define CONFIG_MP2_AT_DECODER 0 +#define CONFIG_MP3_AT_DECODER 0 +#define CONFIG_PCM_ALAW_AT_DECODER 0 +#define CONFIG_PCM_MULAW_AT_DECODER 0 +#define CONFIG_QDMC_AT_DECODER 0 +#define CONFIG_QDM2_AT_DECODER 0 +#define CONFIG_LIBARIBCAPTION_DECODER 0 +#define CONFIG_LIBARIBB24_DECODER 0 +#define CONFIG_LIBCELT_DECODER 0 +#define CONFIG_LIBCODEC2_DECODER 0 +#define CONFIG_LIBDAV1D_DECODER 0 +#define CONFIG_LIBDAVS2_DECODER 0 +#define CONFIG_LIBFDK_AAC_DECODER 0 +#define CONFIG_LIBGSM_DECODER 0 +#define CONFIG_LIBGSM_MS_DECODER 0 +#define CONFIG_LIBILBC_DECODER 0 +#define CONFIG_LIBJXL_ANIM_DECODER 0 +#define CONFIG_LIBJXL_DECODER 0 +#define CONFIG_LIBLC3_DECODER 0 +#define CONFIG_LIBMPEGHDEC_DECODER 0 +#define CONFIG_LIBOPENCORE_AMRNB_DECODER 0 +#define CONFIG_LIBOPENCORE_AMRWB_DECODER 0 +#define CONFIG_LIBOPUS_DECODER 0 +#define CONFIG_LIBRSVG_DECODER 0 +#define CONFIG_LIBSPEEX_DECODER 0 +#define CONFIG_LIBSVTJPEGXS_DECODER 0 +#define CONFIG_LIBUAVS3D_DECODER 0 +#define CONFIG_LIBVORBIS_DECODER 0 +#define CONFIG_LIBVPX_VP8_DECODER 0 +#define CONFIG_LIBVPX_VP9_DECODER 0 +#define CONFIG_LIBXEVD_DECODER 0 +#define CONFIG_LIBZVBI_TELETEXT_DECODER 0 +#define CONFIG_BINTEXT_DECODER 0 +#define CONFIG_XBIN_DECODER 0 +#define CONFIG_IDF_DECODER 0 +#define CONFIG_AAC_MEDIACODEC_DECODER 0 +#define CONFIG_AMRNB_MEDIACODEC_DECODER 0 +#define CONFIG_AMRWB_MEDIACODEC_DECODER 0 +#define CONFIG_LIBAOM_AV1_DECODER 0 +#define CONFIG_AV1_DECODER 0 +#define CONFIG_AV1_CUVID_DECODER 0 +#define CONFIG_AV1_MEDIACODEC_DECODER 0 +#define CONFIG_AV1_QSV_DECODER 0 +#define CONFIG_AV1_AMF_DECODER 0 +#define CONFIG_LIBOPENH264_DECODER 0 +#define CONFIG_H264_AMF_DECODER 0 +#define CONFIG_H264_CUVID_DECODER 0 +#define CONFIG_H264_OH_DECODER 0 +#define CONFIG_HEVC_AMF_DECODER 0 +#define CONFIG_HEVC_CUVID_DECODER 0 +#define CONFIG_HEVC_MEDIACODEC_DECODER 0 +#define CONFIG_HEVC_OH_DECODER 0 +#define CONFIG_MJPEG_CUVID_DECODER 0 +#define CONFIG_MJPEG_QSV_DECODER 0 +#define CONFIG_MP3_MEDIACODEC_DECODER 0 +#define CONFIG_MPEG1_CUVID_DECODER 0 +#define CONFIG_MPEG2_CUVID_DECODER 0 +#define CONFIG_MPEG4_CUVID_DECODER 0 +#define CONFIG_MPEG4_MEDIACODEC_DECODER 0 +#define CONFIG_VC1_CUVID_DECODER 0 +#define CONFIG_VP8_CUVID_DECODER 0 +#define CONFIG_VP8_MEDIACODEC_DECODER 0 +#define CONFIG_VP8_QSV_DECODER 0 +#define CONFIG_VP9_AMF_DECODER 0 +#define CONFIG_VP9_CUVID_DECODER 0 +#define CONFIG_VP9_MEDIACODEC_DECODER 0 +#define CONFIG_VP9_QSV_DECODER 0 +#define CONFIG_VVC_QSV_DECODER 0 +#define CONFIG_VNULL_DECODER 0 +#define CONFIG_ANULL_DECODER 0 +#define CONFIG_A64MULTI_ENCODER 0 +#define CONFIG_A64MULTI5_ENCODER 0 +#define CONFIG_ALIAS_PIX_ENCODER 0 +#define CONFIG_AMV_ENCODER 0 +#define CONFIG_APNG_ENCODER 0 +#define CONFIG_ASV1_ENCODER 0 +#define CONFIG_ASV2_ENCODER 0 +#define CONFIG_AVRP_ENCODER 0 +#define CONFIG_AVUI_ENCODER 0 +#define CONFIG_BITPACKED_ENCODER 0 +#define CONFIG_BMP_ENCODER 0 +#define CONFIG_CFHD_ENCODER 0 +#define CONFIG_CINEPAK_ENCODER 0 +#define CONFIG_CLJR_ENCODER 0 +#define CONFIG_COMFORTNOISE_ENCODER 0 +#define CONFIG_DNXHD_ENCODER 0 +#define CONFIG_DPX_ENCODER 0 +#define CONFIG_DVVIDEO_ENCODER 0 +#define CONFIG_DXV_ENCODER 0 +#define CONFIG_EXR_ENCODER 0 +#define CONFIG_FFV1_ENCODER 0 +#define CONFIG_FFV1_VULKAN_ENCODER 0 +#define CONFIG_FFVHUFF_ENCODER 0 +#define CONFIG_FITS_ENCODER 0 +#define CONFIG_FLASHSV_ENCODER 0 +#define CONFIG_FLASHSV2_ENCODER 0 +#define CONFIG_FLV_ENCODER 0 +#define CONFIG_GIF_ENCODER 0 +#define CONFIG_H261_ENCODER 0 +#define CONFIG_H263_ENCODER 0 +#define CONFIG_H263P_ENCODER 0 +#define CONFIG_H264_MEDIACODEC_ENCODER 0 +#define CONFIG_H264_RKMPP_ENCODER 0 +#define CONFIG_HAP_ENCODER 0 +#define CONFIG_HEVC_RKMPP_ENCODER 0 +#define CONFIG_HUFFYUV_ENCODER 0 +#define CONFIG_JPEG2000_ENCODER 0 +#define CONFIG_JPEGLS_ENCODER 0 +#define CONFIG_LJPEG_ENCODER 0 +#define CONFIG_MAGICYUV_ENCODER 0 +#define CONFIG_MJPEG_ENCODER 0 +#define CONFIG_MPEG1VIDEO_ENCODER 0 +#define CONFIG_MPEG2VIDEO_ENCODER 0 +#define CONFIG_MPEG4_ENCODER 0 +#define CONFIG_MSMPEG4V2_ENCODER 0 +#define CONFIG_MSMPEG4V3_ENCODER 0 +#define CONFIG_MSRLE_ENCODER 0 +#define CONFIG_MSVIDEO1_ENCODER 0 +#define CONFIG_PAM_ENCODER 0 +#define CONFIG_PBM_ENCODER 0 +#define CONFIG_PCX_ENCODER 0 +#define CONFIG_PFM_ENCODER 0 +#define CONFIG_PGM_ENCODER 0 +#define CONFIG_PGMYUV_ENCODER 0 +#define CONFIG_PHM_ENCODER 0 +#define CONFIG_PNG_ENCODER 0 +#define CONFIG_PPM_ENCODER 0 +#define CONFIG_PRORES_ENCODER 0 +#define CONFIG_PRORES_AW_ENCODER 0 +#define CONFIG_PRORES_KS_ENCODER 0 +#define CONFIG_PRORES_KS_VULKAN_ENCODER 0 +#define CONFIG_QOI_ENCODER 0 +#define CONFIG_QTRLE_ENCODER 0 +#define CONFIG_R10K_ENCODER 0 +#define CONFIG_R210_ENCODER 0 +#define CONFIG_RAWVIDEO_ENCODER 0 +#define CONFIG_ROQ_ENCODER 0 +#define CONFIG_RPZA_ENCODER 0 +#define CONFIG_RV10_ENCODER 0 +#define CONFIG_RV20_ENCODER 0 +#define CONFIG_S302M_ENCODER 0 +#define CONFIG_SGI_ENCODER 0 +#define CONFIG_SMC_ENCODER 0 +#define CONFIG_SNOW_ENCODER 0 +#define CONFIG_SPEEDHQ_ENCODER 0 +#define CONFIG_SUNRAST_ENCODER 0 +#define CONFIG_SVQ1_ENCODER 0 +#define CONFIG_TARGA_ENCODER 0 +#define CONFIG_TIFF_ENCODER 0 +#define CONFIG_UTVIDEO_ENCODER 0 +#define CONFIG_V210_ENCODER 0 +#define CONFIG_V308_ENCODER 0 +#define CONFIG_V408_ENCODER 0 +#define CONFIG_V410_ENCODER 0 +#define CONFIG_VBN_ENCODER 0 +#define CONFIG_VC2_ENCODER 0 +#define CONFIG_WBMP_ENCODER 0 +#define CONFIG_WRAPPED_AVFRAME_ENCODER 0 +#define CONFIG_WMV1_ENCODER 0 +#define CONFIG_WMV2_ENCODER 0 +#define CONFIG_XBM_ENCODER 0 +#define CONFIG_XFACE_ENCODER 0 +#define CONFIG_XWD_ENCODER 0 +#define CONFIG_Y41P_ENCODER 0 +#define CONFIG_YUV4_ENCODER 0 +#define CONFIG_ZLIB_ENCODER 0 +#define CONFIG_ZMBV_ENCODER 0 +#define CONFIG_AAC_ENCODER 0 +#define CONFIG_AC3_ENCODER 0 +#define CONFIG_AC3_FIXED_ENCODER 0 +#define CONFIG_ALAC_ENCODER 0 +#define CONFIG_APTX_ENCODER 0 +#define CONFIG_APTX_HD_ENCODER 0 +#define CONFIG_DCA_ENCODER 0 +#define CONFIG_DFPWM_ENCODER 0 +#define CONFIG_EAC3_ENCODER 0 +#define CONFIG_FLAC_ENCODER 0 +#define CONFIG_G723_1_ENCODER 0 +#define CONFIG_HDR_ENCODER 0 +#define CONFIG_MLP_ENCODER 0 +#define CONFIG_MP2_ENCODER 0 +#define CONFIG_MP2FIXED_ENCODER 0 +#define CONFIG_NELLYMOSER_ENCODER 0 +#define CONFIG_OPUS_ENCODER 0 +#define CONFIG_RA_144_ENCODER 0 +#define CONFIG_SBC_ENCODER 0 +#define CONFIG_SONIC_ENCODER 0 +#define CONFIG_SONIC_LS_ENCODER 0 +#define CONFIG_TRUEHD_ENCODER 0 +#define CONFIG_TTA_ENCODER 0 +#define CONFIG_VORBIS_ENCODER 0 +#define CONFIG_WAVPACK_ENCODER 0 +#define CONFIG_WMAV1_ENCODER 0 +#define CONFIG_WMAV2_ENCODER 0 +#define CONFIG_PCM_ALAW_ENCODER 0 +#define CONFIG_PCM_BLURAY_ENCODER 0 +#define CONFIG_PCM_DVD_ENCODER 0 +#define CONFIG_PCM_F32BE_ENCODER 0 +#define CONFIG_PCM_F32LE_ENCODER 0 +#define CONFIG_PCM_F64BE_ENCODER 0 +#define CONFIG_PCM_F64LE_ENCODER 0 +#define CONFIG_PCM_MULAW_ENCODER 0 +#define CONFIG_PCM_S8_ENCODER 0 +#define CONFIG_PCM_S8_PLANAR_ENCODER 0 +#define CONFIG_PCM_S16BE_ENCODER 0 +#define CONFIG_PCM_S16BE_PLANAR_ENCODER 0 +#define CONFIG_PCM_S16LE_ENCODER 0 +#define CONFIG_PCM_S16LE_PLANAR_ENCODER 0 +#define CONFIG_PCM_S24BE_ENCODER 0 +#define CONFIG_PCM_S24DAUD_ENCODER 0 +#define CONFIG_PCM_S24LE_ENCODER 0 +#define CONFIG_PCM_S24LE_PLANAR_ENCODER 0 +#define CONFIG_PCM_S32BE_ENCODER 0 +#define CONFIG_PCM_S32LE_ENCODER 0 +#define CONFIG_PCM_S32LE_PLANAR_ENCODER 0 +#define CONFIG_PCM_S64BE_ENCODER 0 +#define CONFIG_PCM_S64LE_ENCODER 0 +#define CONFIG_PCM_U8_ENCODER 0 +#define CONFIG_PCM_U16BE_ENCODER 0 +#define CONFIG_PCM_U16LE_ENCODER 0 +#define CONFIG_PCM_U24BE_ENCODER 0 +#define CONFIG_PCM_U24LE_ENCODER 0 +#define CONFIG_PCM_U32BE_ENCODER 0 +#define CONFIG_PCM_U32LE_ENCODER 0 +#define CONFIG_PCM_VIDC_ENCODER 0 +#define CONFIG_ROQ_DPCM_ENCODER 0 +#define CONFIG_ADPCM_ADX_ENCODER 0 +#define CONFIG_ADPCM_ARGO_ENCODER 0 +#define CONFIG_ADPCM_G722_ENCODER 0 +#define CONFIG_ADPCM_G726_ENCODER 0 +#define CONFIG_ADPCM_G726LE_ENCODER 0 +#define CONFIG_ADPCM_IMA_AMV_ENCODER 0 +#define CONFIG_ADPCM_IMA_ALP_ENCODER 0 +#define CONFIG_ADPCM_IMA_APM_ENCODER 0 +#define CONFIG_ADPCM_IMA_QT_ENCODER 0 +#define CONFIG_ADPCM_IMA_SSI_ENCODER 0 +#define CONFIG_ADPCM_IMA_WAV_ENCODER 0 +#define CONFIG_ADPCM_IMA_WS_ENCODER 0 +#define CONFIG_ADPCM_MS_ENCODER 0 +#define CONFIG_ADPCM_SWF_ENCODER 0 +#define CONFIG_ADPCM_YAMAHA_ENCODER 0 +#define CONFIG_SSA_ENCODER 0 +#define CONFIG_ASS_ENCODER 0 +#define CONFIG_DVBSUB_ENCODER 0 +#define CONFIG_DVDSUB_ENCODER 0 +#define CONFIG_MOVTEXT_ENCODER 0 +#define CONFIG_SRT_ENCODER 0 +#define CONFIG_SUBRIP_ENCODER 0 +#define CONFIG_TEXT_ENCODER 0 +#define CONFIG_TTML_ENCODER 0 +#define CONFIG_WEBVTT_ENCODER 0 +#define CONFIG_XSUB_ENCODER 0 +#define CONFIG_AAC_AT_ENCODER 0 +#define CONFIG_ALAC_AT_ENCODER 0 +#define CONFIG_ILBC_AT_ENCODER 0 +#define CONFIG_PCM_ALAW_AT_ENCODER 0 +#define CONFIG_PCM_MULAW_AT_ENCODER 0 +#define CONFIG_LIBAOM_AV1_ENCODER 0 +#define CONFIG_LIBCODEC2_ENCODER 0 +#define CONFIG_LIBFDK_AAC_ENCODER 0 +#define CONFIG_LIBGSM_ENCODER 0 +#define CONFIG_LIBGSM_MS_ENCODER 0 +#define CONFIG_LIBILBC_ENCODER 0 +#define CONFIG_LIBJXL_ANIM_ENCODER 0 +#define CONFIG_LIBJXL_ENCODER 0 +#define CONFIG_LIBLC3_ENCODER 0 +#define CONFIG_LIBMP3LAME_ENCODER 0 +#define CONFIG_LIBOAPV_ENCODER 0 +#define CONFIG_LIBOPENCORE_AMRNB_ENCODER 0 +#define CONFIG_LIBOPENJPEG_ENCODER 0 +#define CONFIG_LIBOPUS_ENCODER 0 +#define CONFIG_LIBRAV1E_ENCODER 0 +#define CONFIG_LIBSHINE_ENCODER 0 +#define CONFIG_LIBSPEEX_ENCODER 0 +#define CONFIG_LIBSVTAV1_ENCODER 0 +#define CONFIG_LIBSVTJPEGXS_ENCODER 0 +#define CONFIG_LIBTHEORA_ENCODER 0 +#define CONFIG_LIBTWOLAME_ENCODER 0 +#define CONFIG_LIBVO_AMRWBENC_ENCODER 0 +#define CONFIG_LIBVORBIS_ENCODER 0 +#define CONFIG_LIBVPX_VP8_ENCODER 0 +#define CONFIG_LIBVPX_VP9_ENCODER 0 +#define CONFIG_LIBVVENC_ENCODER 0 +#define CONFIG_LIBWEBP_ANIM_ENCODER 0 +#define CONFIG_LIBWEBP_ENCODER 0 +#define CONFIG_LIBX262_ENCODER 0 +#define CONFIG_LIBX264_ENCODER 0 +#define CONFIG_LIBX264RGB_ENCODER 0 +#define CONFIG_LIBX265_ENCODER 0 +#define CONFIG_LIBXEVE_ENCODER 0 +#define CONFIG_LIBXAVS_ENCODER 0 +#define CONFIG_LIBXAVS2_ENCODER 0 +#define CONFIG_LIBXVID_ENCODER 0 +#define CONFIG_AAC_MF_ENCODER 0 +#define CONFIG_AC3_MF_ENCODER 0 +#define CONFIG_H263_V4L2M2M_ENCODER 0 +#define CONFIG_AV1_D3D12VA_ENCODER 0 +#define CONFIG_AV1_MEDIACODEC_ENCODER 0 +#define CONFIG_AV1_NVENC_ENCODER 0 +#define CONFIG_AV1_QSV_ENCODER 0 +#define CONFIG_AV1_AMF_ENCODER 0 +#define CONFIG_AV1_MF_ENCODER 0 +#define CONFIG_AV1_VAAPI_ENCODER 0 +#define CONFIG_AV1_VULKAN_ENCODER 0 +#define CONFIG_LIBOPENH264_ENCODER 0 +#define CONFIG_H264_AMF_ENCODER 0 +#define CONFIG_H264_D3D12VA_ENCODER 0 +#define CONFIG_H264_MF_ENCODER 0 +#define CONFIG_H264_NVENC_ENCODER 0 +#define CONFIG_H264_OH_ENCODER 0 +#define CONFIG_H264_OMX_ENCODER 0 +#define CONFIG_H264_QSV_ENCODER 0 +#define CONFIG_H264_V4L2M2M_ENCODER 0 +#define CONFIG_H264_VAAPI_ENCODER 0 +#define CONFIG_H264_VIDEOTOOLBOX_ENCODER 0 +#define CONFIG_H264_VULKAN_ENCODER 0 +#define CONFIG_HEVC_AMF_ENCODER 0 +#define CONFIG_HEVC_D3D12VA_ENCODER 0 +#define CONFIG_HEVC_MEDIACODEC_ENCODER 0 +#define CONFIG_HEVC_MF_ENCODER 0 +#define CONFIG_HEVC_NVENC_ENCODER 0 +#define CONFIG_HEVC_OH_ENCODER 0 +#define CONFIG_HEVC_QSV_ENCODER 0 +#define CONFIG_HEVC_V4L2M2M_ENCODER 0 +#define CONFIG_HEVC_VAAPI_ENCODER 0 +#define CONFIG_HEVC_VIDEOTOOLBOX_ENCODER 0 +#define CONFIG_HEVC_VULKAN_ENCODER 0 +#define CONFIG_LIBKVAZAAR_ENCODER 0 +#define CONFIG_MJPEG_QSV_ENCODER 0 +#define CONFIG_MJPEG_VAAPI_ENCODER 0 +#define CONFIG_MP3_MF_ENCODER 0 +#define CONFIG_MPEG2_QSV_ENCODER 0 +#define CONFIG_MPEG2_VAAPI_ENCODER 0 +#define CONFIG_MPEG4_MEDIACODEC_ENCODER 0 +#define CONFIG_MPEG4_OMX_ENCODER 0 +#define CONFIG_MPEG4_V4L2M2M_ENCODER 0 +#define CONFIG_PRORES_VIDEOTOOLBOX_ENCODER 0 +#define CONFIG_VP8_MEDIACODEC_ENCODER 0 +#define CONFIG_VP8_V4L2M2M_ENCODER 0 +#define CONFIG_VP8_VAAPI_ENCODER 0 +#define CONFIG_VP9_MEDIACODEC_ENCODER 0 +#define CONFIG_VP9_VAAPI_ENCODER 0 +#define CONFIG_VP9_QSV_ENCODER 0 +#define CONFIG_VNULL_ENCODER 0 +#define CONFIG_ANULL_ENCODER 0 +#define CONFIG_AV1_D3D11VA_HWACCEL 0 +#define CONFIG_AV1_D3D11VA2_HWACCEL 0 +#define CONFIG_AV1_D3D12VA_HWACCEL 0 +#define CONFIG_AV1_DXVA2_HWACCEL 0 +#define CONFIG_AV1_NVDEC_HWACCEL 0 +#define CONFIG_AV1_VAAPI_HWACCEL 0 +#define CONFIG_AV1_VDPAU_HWACCEL 0 +#define CONFIG_AV1_VIDEOTOOLBOX_HWACCEL 0 +#define CONFIG_AV1_VULKAN_HWACCEL 0 +#define CONFIG_DPX_VULKAN_HWACCEL 0 +#define CONFIG_FFV1_VULKAN_HWACCEL 0 +#define CONFIG_H263_VAAPI_HWACCEL 0 +#define CONFIG_H263_VIDEOTOOLBOX_HWACCEL 0 +#define CONFIG_H264_D3D11VA_HWACCEL 0 +#define CONFIG_H264_D3D11VA2_HWACCEL 0 +#define CONFIG_H264_D3D12VA_HWACCEL 0 +#define CONFIG_H264_DXVA2_HWACCEL 0 +#define CONFIG_H264_NVDEC_HWACCEL 0 +#define CONFIG_H264_VAAPI_HWACCEL 0 +#define CONFIG_H264_VDPAU_HWACCEL 0 +#define CONFIG_H264_VIDEOTOOLBOX_HWACCEL 0 +#define CONFIG_H264_VULKAN_HWACCEL 0 +#define CONFIG_HEVC_D3D11VA_HWACCEL 0 +#define CONFIG_HEVC_D3D11VA2_HWACCEL 0 +#define CONFIG_HEVC_D3D12VA_HWACCEL 0 +#define CONFIG_HEVC_DXVA2_HWACCEL 0 +#define CONFIG_HEVC_NVDEC_HWACCEL 0 +#define CONFIG_HEVC_VAAPI_HWACCEL 0 +#define CONFIG_HEVC_VDPAU_HWACCEL 0 +#define CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL 0 +#define CONFIG_HEVC_VULKAN_HWACCEL 0 +#define CONFIG_MJPEG_NVDEC_HWACCEL 0 +#define CONFIG_MJPEG_VAAPI_HWACCEL 0 +#define CONFIG_MPEG1_NVDEC_HWACCEL 0 +#define CONFIG_MPEG1_VDPAU_HWACCEL 0 +#define CONFIG_MPEG1_VIDEOTOOLBOX_HWACCEL 0 +#define CONFIG_MPEG2_D3D11VA_HWACCEL 0 +#define CONFIG_MPEG2_D3D11VA2_HWACCEL 0 +#define CONFIG_MPEG2_D3D12VA_HWACCEL 0 +#define CONFIG_MPEG2_DXVA2_HWACCEL 0 +#define CONFIG_MPEG2_NVDEC_HWACCEL 0 +#define CONFIG_MPEG2_VAAPI_HWACCEL 0 +#define CONFIG_MPEG2_VDPAU_HWACCEL 0 +#define CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL 0 +#define CONFIG_MPEG4_NVDEC_HWACCEL 0 +#define CONFIG_MPEG4_VAAPI_HWACCEL 0 +#define CONFIG_MPEG4_VDPAU_HWACCEL 0 +#define CONFIG_MPEG4_VIDEOTOOLBOX_HWACCEL 0 +#define CONFIG_PRORES_VIDEOTOOLBOX_HWACCEL 0 +#define CONFIG_PRORES_VULKAN_HWACCEL 0 +#define CONFIG_PRORES_RAW_VULKAN_HWACCEL 0 +#define CONFIG_VC1_D3D11VA_HWACCEL 0 +#define CONFIG_VC1_D3D11VA2_HWACCEL 0 +#define CONFIG_VC1_D3D12VA_HWACCEL 0 +#define CONFIG_VC1_DXVA2_HWACCEL 0 +#define CONFIG_VC1_NVDEC_HWACCEL 0 +#define CONFIG_VC1_VAAPI_HWACCEL 0 +#define CONFIG_VC1_VDPAU_HWACCEL 0 +#define CONFIG_VP8_NVDEC_HWACCEL 0 +#define CONFIG_VP8_VAAPI_HWACCEL 0 +#define CONFIG_VP9_D3D11VA_HWACCEL 0 +#define CONFIG_VP9_D3D11VA2_HWACCEL 0 +#define CONFIG_VP9_D3D12VA_HWACCEL 0 +#define CONFIG_VP9_DXVA2_HWACCEL 0 +#define CONFIG_VP9_NVDEC_HWACCEL 0 +#define CONFIG_VP9_VAAPI_HWACCEL 0 +#define CONFIG_VP9_VDPAU_HWACCEL 0 +#define CONFIG_VP9_VIDEOTOOLBOX_HWACCEL 0 +#define CONFIG_VP9_VULKAN_HWACCEL 0 +#define CONFIG_VVC_VAAPI_HWACCEL 0 +#define CONFIG_WMV3_D3D11VA_HWACCEL 0 +#define CONFIG_WMV3_D3D11VA2_HWACCEL 0 +#define CONFIG_WMV3_D3D12VA_HWACCEL 0 +#define CONFIG_WMV3_DXVA2_HWACCEL 0 +#define CONFIG_WMV3_NVDEC_HWACCEL 0 +#define CONFIG_WMV3_VAAPI_HWACCEL 0 +#define CONFIG_WMV3_VDPAU_HWACCEL 0 +#define CONFIG_AAC_PARSER 0 +#define CONFIG_AAC_LATM_PARSER 0 +#define CONFIG_AC3_PARSER 0 +#define CONFIG_ADX_PARSER 0 +#define CONFIG_AHX_PARSER 0 +#define CONFIG_AMR_PARSER 0 +#define CONFIG_APV_PARSER 0 +#define CONFIG_AV1_PARSER 0 +#define CONFIG_AVS2_PARSER 0 +#define CONFIG_AVS3_PARSER 0 +#define CONFIG_BMP_PARSER 0 +#define CONFIG_CAVSVIDEO_PARSER 0 +#define CONFIG_COOK_PARSER 0 +#define CONFIG_CRI_PARSER 0 +#define CONFIG_DCA_PARSER 0 +#define CONFIG_DIRAC_PARSER 0 +#define CONFIG_DNXHD_PARSER 0 +#define CONFIG_DNXUC_PARSER 0 +#define CONFIG_DOLBY_E_PARSER 0 +#define CONFIG_DPX_PARSER 0 +#define CONFIG_DVAUDIO_PARSER 0 +#define CONFIG_DVBSUB_PARSER 0 +#define CONFIG_DVDSUB_PARSER 0 +#define CONFIG_DVD_NAV_PARSER 0 +#define CONFIG_EVC_PARSER 0 +#define CONFIG_FLAC_PARSER 0 +#define CONFIG_FTR_PARSER 0 +#define CONFIG_FFV1_PARSER 0 +#define CONFIG_G723_1_PARSER 0 +#define CONFIG_G729_PARSER 0 +#define CONFIG_GIF_PARSER 0 +#define CONFIG_GSM_PARSER 0 +#define CONFIG_H261_PARSER 0 +#define CONFIG_H263_PARSER 0 +#define CONFIG_H264_PARSER 0 +#define CONFIG_HEVC_PARSER 0 +#define CONFIG_HDR_PARSER 0 +#define CONFIG_IPU_PARSER 0 +#define CONFIG_JPEG2000_PARSER 0 +#define CONFIG_JPEGXL_PARSER 0 +#define CONFIG_JPEGXS_PARSER 0 +#define CONFIG_LCEVC_PARSER 0 +#define CONFIG_MISC4_PARSER 0 +#define CONFIG_MJPEG_PARSER 0 +#define CONFIG_MLP_PARSER 0 +#define CONFIG_MPEG4VIDEO_PARSER 0 +#define CONFIG_MPEGAUDIO_PARSER 0 +#define CONFIG_MPEGVIDEO_PARSER 0 +#define CONFIG_OPUS_PARSER 0 +#define CONFIG_PRORES_PARSER 0 +#define CONFIG_PNG_PARSER 0 +#define CONFIG_PNM_PARSER 0 +#define CONFIG_PRORES_RAW_PARSER 0 +#define CONFIG_QOI_PARSER 0 +#define CONFIG_RV34_PARSER 0 +#define CONFIG_SBC_PARSER 0 +#define CONFIG_SIPR_PARSER 0 +#define CONFIG_TAK_PARSER 0 +#define CONFIG_VC1_PARSER 0 +#define CONFIG_VORBIS_PARSER 0 +#define CONFIG_VP3_PARSER 0 +#define CONFIG_VP8_PARSER 0 +#define CONFIG_VP9_PARSER 0 +#define CONFIG_VVC_PARSER 0 +#define CONFIG_WEBP_PARSER 0 +#define CONFIG_XBM_PARSER 0 +#define CONFIG_XMA_PARSER 0 +#define CONFIG_XWD_PARSER 0 +#define CONFIG_ALSA_INDEV 0 +#define CONFIG_ANDROID_CAMERA_INDEV 0 +#define CONFIG_AVFOUNDATION_INDEV 0 +#define CONFIG_DECKLINK_INDEV 0 +#define CONFIG_DSHOW_INDEV 0 +#define CONFIG_FBDEV_INDEV 0 +#define CONFIG_GDIGRAB_INDEV 0 +#define CONFIG_IEC61883_INDEV 0 +#define CONFIG_JACK_INDEV 0 +#define CONFIG_KMSGRAB_INDEV 0 +#define CONFIG_LAVFI_INDEV 0 +#define CONFIG_OPENAL_INDEV 0 +#define CONFIG_OSS_INDEV 0 +#define CONFIG_PULSE_INDEV 0 +#define CONFIG_SNDIO_INDEV 0 +#define CONFIG_V4L2_INDEV 0 +#define CONFIG_VFWCAP_INDEV 0 +#define CONFIG_XCBGRAB_INDEV 0 +#define CONFIG_LIBCDIO_INDEV 0 +#define CONFIG_LIBDC1394_INDEV 0 +#define CONFIG_ALSA_OUTDEV 0 +#define CONFIG_AUDIOTOOLBOX_OUTDEV 0 +#define CONFIG_CACA_OUTDEV 0 +#define CONFIG_DECKLINK_OUTDEV 0 +#define CONFIG_FBDEV_OUTDEV 0 +#define CONFIG_OSS_OUTDEV 0 +#define CONFIG_PULSE_OUTDEV 0 +#define CONFIG_SNDIO_OUTDEV 0 +#define CONFIG_V4L2_OUTDEV 0 +#define CONFIG_XV_OUTDEV 0 +#define CONFIG_AAP_FILTER 0 +#define CONFIG_ABENCH_FILTER 0 +#define CONFIG_ACOMPRESSOR_FILTER 0 +#define CONFIG_ACONTRAST_FILTER 0 +#define CONFIG_ACOPY_FILTER 0 +#define CONFIG_ACUE_FILTER 0 +#define CONFIG_ACROSSFADE_FILTER 0 +#define CONFIG_ACROSSOVER_FILTER 0 +#define CONFIG_ACRUSHER_FILTER 0 +#define CONFIG_ADECLICK_FILTER 0 +#define CONFIG_ADECLIP_FILTER 0 +#define CONFIG_ADECORRELATE_FILTER 0 +#define CONFIG_ADELAY_FILTER 0 +#define CONFIG_ADENORM_FILTER 0 +#define CONFIG_ADERIVATIVE_FILTER 0 +#define CONFIG_ADRC_FILTER 0 +#define CONFIG_ADYNAMICEQUALIZER_FILTER 0 +#define CONFIG_ADYNAMICSMOOTH_FILTER 0 +#define CONFIG_AECHO_FILTER 0 +#define CONFIG_AEMPHASIS_FILTER 0 +#define CONFIG_AEVAL_FILTER 0 +#define CONFIG_AEXCITER_FILTER 0 +#define CONFIG_AFADE_FILTER 0 +#define CONFIG_AFFTDN_FILTER 0 +#define CONFIG_AFFTFILT_FILTER 0 +#define CONFIG_AFIR_FILTER 0 +#define CONFIG_AFORMAT_FILTER 0 +#define CONFIG_AFREQSHIFT_FILTER 0 +#define CONFIG_AFWTDN_FILTER 0 +#define CONFIG_AGATE_FILTER 0 +#define CONFIG_AIIR_FILTER 0 +#define CONFIG_AINTEGRAL_FILTER 0 +#define CONFIG_AINTERLEAVE_FILTER 0 +#define CONFIG_ALATENCY_FILTER 0 +#define CONFIG_ALIMITER_FILTER 0 +#define CONFIG_ALLPASS_FILTER 0 +#define CONFIG_ALOOP_FILTER 0 +#define CONFIG_AMERGE_FILTER 0 +#define CONFIG_AMETADATA_FILTER 0 +#define CONFIG_AMIX_FILTER 0 +#define CONFIG_AMULTIPLY_FILTER 0 +#define CONFIG_ANEQUALIZER_FILTER 0 +#define CONFIG_ANLMDN_FILTER 0 +#define CONFIG_ANLMF_FILTER 0 +#define CONFIG_ANLMS_FILTER 0 +#define CONFIG_ANULL_FILTER 0 +#define CONFIG_APAD_FILTER 0 +#define CONFIG_APERMS_FILTER 0 +#define CONFIG_APHASER_FILTER 0 +#define CONFIG_APHASESHIFT_FILTER 0 +#define CONFIG_APSNR_FILTER 0 +#define CONFIG_APSYCLIP_FILTER 0 +#define CONFIG_APULSATOR_FILTER 0 +#define CONFIG_AREALTIME_FILTER 0 +#define CONFIG_ARESAMPLE_FILTER 0 +#define CONFIG_AREVERSE_FILTER 0 +#define CONFIG_ARLS_FILTER 0 +#define CONFIG_ARNNDN_FILTER 0 +#define CONFIG_ASDR_FILTER 0 +#define CONFIG_ASEGMENT_FILTER 0 +#define CONFIG_ASELECT_FILTER 0 +#define CONFIG_ASENDCMD_FILTER 0 +#define CONFIG_ASETNSAMPLES_FILTER 0 +#define CONFIG_ASETPTS_FILTER 0 +#define CONFIG_ASETRATE_FILTER 0 +#define CONFIG_ASETTB_FILTER 0 +#define CONFIG_ASHOWINFO_FILTER 0 +#define CONFIG_ASIDEDATA_FILTER 0 +#define CONFIG_ASISDR_FILTER 0 +#define CONFIG_ASOFTCLIP_FILTER 0 +#define CONFIG_ASPECTRALSTATS_FILTER 0 +#define CONFIG_ASPLIT_FILTER 0 +#define CONFIG_ASR_FILTER 0 +#define CONFIG_ASTATS_FILTER 0 +#define CONFIG_ASTREAMSELECT_FILTER 0 +#define CONFIG_ASUBBOOST_FILTER 0 +#define CONFIG_ASUBCUT_FILTER 0 +#define CONFIG_ASUPERCUT_FILTER 0 +#define CONFIG_ASUPERPASS_FILTER 0 +#define CONFIG_ASUPERSTOP_FILTER 0 +#define CONFIG_ATEMPO_FILTER 0 +#define CONFIG_ATILT_FILTER 0 +#define CONFIG_ATRIM_FILTER 0 +#define CONFIG_AXCORRELATE_FILTER 0 +#define CONFIG_AZMQ_FILTER 0 +#define CONFIG_BANDPASS_FILTER 0 +#define CONFIG_BANDREJECT_FILTER 0 +#define CONFIG_BASS_FILTER 0 +#define CONFIG_BIQUAD_FILTER 0 +#define CONFIG_BS2B_FILTER 0 +#define CONFIG_CHANNELMAP_FILTER 0 +#define CONFIG_CHANNELSPLIT_FILTER 0 +#define CONFIG_CHORUS_FILTER 0 +#define CONFIG_COMPAND_FILTER 0 +#define CONFIG_COMPENSATIONDELAY_FILTER 0 +#define CONFIG_CROSSFEED_FILTER 0 +#define CONFIG_CRYSTALIZER_FILTER 0 +#define CONFIG_DCSHIFT_FILTER 0 +#define CONFIG_DEESSER_FILTER 0 +#define CONFIG_DIALOGUENHANCE_FILTER 0 +#define CONFIG_DRMETER_FILTER 0 +#define CONFIG_DYNAUDNORM_FILTER 0 +#define CONFIG_EARWAX_FILTER 0 +#define CONFIG_EBUR128_FILTER 0 +#define CONFIG_EQUALIZER_FILTER 0 +#define CONFIG_EXTRASTEREO_FILTER 0 +#define CONFIG_FIREQUALIZER_FILTER 0 +#define CONFIG_FLANGER_FILTER 0 +#define CONFIG_HAAS_FILTER 0 +#define CONFIG_HDCD_FILTER 0 +#define CONFIG_HEADPHONE_FILTER 0 +#define CONFIG_HIGHPASS_FILTER 0 +#define CONFIG_HIGHSHELF_FILTER 0 +#define CONFIG_JOIN_FILTER 0 +#define CONFIG_LADSPA_FILTER 0 +#define CONFIG_LOUDNORM_FILTER 0 +#define CONFIG_LOWPASS_FILTER 0 +#define CONFIG_LOWSHELF_FILTER 0 +#define CONFIG_LV2_FILTER 0 +#define CONFIG_MCOMPAND_FILTER 0 +#define CONFIG_PAN_FILTER 0 +#define CONFIG_REPLAYGAIN_FILTER 0 +#define CONFIG_RUBBERBAND_FILTER 0 +#define CONFIG_SIDECHAINCOMPRESS_FILTER 0 +#define CONFIG_SIDECHAINGATE_FILTER 0 +#define CONFIG_SILENCEDETECT_FILTER 0 +#define CONFIG_SILENCEREMOVE_FILTER 0 +#define CONFIG_SOFALIZER_FILTER 0 +#define CONFIG_SPEECHNORM_FILTER 0 +#define CONFIG_STEREOTOOLS_FILTER 0 +#define CONFIG_STEREOWIDEN_FILTER 0 +#define CONFIG_SUPEREQUALIZER_FILTER 0 +#define CONFIG_SURROUND_FILTER 0 +#define CONFIG_TILTSHELF_FILTER 0 +#define CONFIG_TREBLE_FILTER 0 +#define CONFIG_TREMOLO_FILTER 0 +#define CONFIG_VIBRATO_FILTER 0 +#define CONFIG_VIRTUALBASS_FILTER 0 +#define CONFIG_VOLUME_FILTER 0 +#define CONFIG_VOLUMEDETECT_FILTER 0 +#define CONFIG_WHISPER_FILTER 0 +#define CONFIG_AEVALSRC_FILTER 0 +#define CONFIG_AFDELAYSRC_FILTER 0 +#define CONFIG_AFIREQSRC_FILTER 0 +#define CONFIG_AFIRSRC_FILTER 0 +#define CONFIG_ANOISESRC_FILTER 0 +#define CONFIG_ANULLSRC_FILTER 0 +#define CONFIG_FLITE_FILTER 0 +#define CONFIG_HILBERT_FILTER 0 +#define CONFIG_SINC_FILTER 0 +#define CONFIG_SINE_FILTER 0 +#define CONFIG_ANULLSINK_FILTER 0 +#define CONFIG_ADDROI_FILTER 0 +#define CONFIG_ALPHAEXTRACT_FILTER 0 +#define CONFIG_ALPHAMERGE_FILTER 0 +#define CONFIG_AMPLIFY_FILTER 0 +#define CONFIG_ASS_FILTER 0 +#define CONFIG_ATADENOISE_FILTER 0 +#define CONFIG_AVGBLUR_FILTER 0 +#define CONFIG_AVGBLUR_OPENCL_FILTER 0 +#define CONFIG_AVGBLUR_VULKAN_FILTER 0 +#define CONFIG_BACKGROUNDKEY_FILTER 0 +#define CONFIG_BBOX_FILTER 0 +#define CONFIG_BENCH_FILTER 0 +#define CONFIG_BILATERAL_FILTER 0 +#define CONFIG_BILATERAL_CUDA_FILTER 0 +#define CONFIG_BITPLANENOISE_FILTER 0 +#define CONFIG_BLACKDETECT_FILTER 0 +#define CONFIG_BLACKDETECT_VULKAN_FILTER 0 +#define CONFIG_BLACKFRAME_FILTER 0 +#define CONFIG_BLEND_FILTER 0 +#define CONFIG_BLEND_VULKAN_FILTER 0 +#define CONFIG_BLOCKDETECT_FILTER 0 +#define CONFIG_BLURDETECT_FILTER 0 +#define CONFIG_BM3D_FILTER 0 +#define CONFIG_BOXBLUR_FILTER 0 +#define CONFIG_BOXBLUR_OPENCL_FILTER 0 +#define CONFIG_BWDIF_FILTER 0 +#define CONFIG_BWDIF_CUDA_FILTER 0 +#define CONFIG_BWDIF_VULKAN_FILTER 0 +#define CONFIG_CAS_FILTER 0 +#define CONFIG_CCREPACK_FILTER 0 +#define CONFIG_CHROMABER_VULKAN_FILTER 0 +#define CONFIG_CHROMAHOLD_FILTER 0 +#define CONFIG_CHROMAKEY_FILTER 0 +#define CONFIG_CHROMAKEY_CUDA_FILTER 0 +#define CONFIG_CHROMANR_FILTER 0 +#define CONFIG_CHROMASHIFT_FILTER 0 +#define CONFIG_CIESCOPE_FILTER 0 +#define CONFIG_CODECVIEW_FILTER 0 +#define CONFIG_COLORBALANCE_FILTER 0 +#define CONFIG_COLORCHANNELMIXER_FILTER 0 +#define CONFIG_COLORCONTRAST_FILTER 0 +#define CONFIG_COLORCORRECT_FILTER 0 +#define CONFIG_COLORDETECT_FILTER 0 +#define CONFIG_COLORIZE_FILTER 0 +#define CONFIG_COLORKEY_FILTER 0 +#define CONFIG_COLORKEY_OPENCL_FILTER 0 +#define CONFIG_COLORHOLD_FILTER 0 +#define CONFIG_COLORLEVELS_FILTER 0 +#define CONFIG_COLORMAP_FILTER 0 +#define CONFIG_COLORMATRIX_FILTER 0 +#define CONFIG_COLORSPACE_FILTER 0 +#define CONFIG_COLORSPACE_CUDA_FILTER 0 +#define CONFIG_COLORTEMPERATURE_FILTER 0 +#define CONFIG_CONVOLUTION_FILTER 0 +#define CONFIG_CONVOLUTION_OPENCL_FILTER 0 +#define CONFIG_CONVOLVE_FILTER 0 +#define CONFIG_COPY_FILTER 0 +#define CONFIG_COREIMAGE_FILTER 0 +#define CONFIG_CORR_FILTER 0 +#define CONFIG_COVER_RECT_FILTER 0 +#define CONFIG_CROP_FILTER 0 +#define CONFIG_CROPDETECT_FILTER 0 +#define CONFIG_CUE_FILTER 0 +#define CONFIG_CURVES_FILTER 0 +#define CONFIG_DATASCOPE_FILTER 0 +#define CONFIG_DBLUR_FILTER 0 +#define CONFIG_DCTDNOIZ_FILTER 0 +#define CONFIG_DEBAND_FILTER 0 +#define CONFIG_DEBLOCK_FILTER 0 +#define CONFIG_DECIMATE_FILTER 0 +#define CONFIG_DECONVOLVE_FILTER 0 +#define CONFIG_DEDOT_FILTER 0 +#define CONFIG_DEFLATE_FILTER 0 +#define CONFIG_DEFLICKER_FILTER 0 +#define CONFIG_DEINTERLACE_QSV_FILTER 0 +#define CONFIG_DEINTERLACE_D3D12_FILTER 0 +#define CONFIG_DEINTERLACE_VAAPI_FILTER 0 +#define CONFIG_DEJUDDER_FILTER 0 +#define CONFIG_DELOGO_FILTER 0 +#define CONFIG_DENOISE_VAAPI_FILTER 0 +#define CONFIG_DERAIN_FILTER 0 +#define CONFIG_DESHAKE_FILTER 0 +#define CONFIG_DESHAKE_OPENCL_FILTER 0 +#define CONFIG_DESPILL_FILTER 0 +#define CONFIG_DETELECINE_FILTER 0 +#define CONFIG_DILATION_FILTER 0 +#define CONFIG_DILATION_OPENCL_FILTER 0 +#define CONFIG_DISPLACE_FILTER 0 +#define CONFIG_DNN_CLASSIFY_FILTER 0 +#define CONFIG_DNN_DETECT_FILTER 0 +#define CONFIG_DNN_PROCESSING_FILTER 0 +#define CONFIG_DOUBLEWEAVE_FILTER 0 +#define CONFIG_DRAWBOX_FILTER 0 +#define CONFIG_DRAWGRAPH_FILTER 0 +#define CONFIG_DRAWGRID_FILTER 0 +#define CONFIG_DRAWTEXT_FILTER 0 +#define CONFIG_DRAWVG_FILTER 0 +#define CONFIG_EDGEDETECT_FILTER 0 +#define CONFIG_ELBG_FILTER 0 +#define CONFIG_ENTROPY_FILTER 0 +#define CONFIG_EPX_FILTER 0 +#define CONFIG_EQ_FILTER 0 +#define CONFIG_EROSION_FILTER 0 +#define CONFIG_EROSION_OPENCL_FILTER 0 +#define CONFIG_ESTDIF_FILTER 0 +#define CONFIG_EXPOSURE_FILTER 0 +#define CONFIG_EXTRACTPLANES_FILTER 0 +#define CONFIG_FADE_FILTER 0 +#define CONFIG_FEEDBACK_FILTER 0 +#define CONFIG_FFTDNOIZ_FILTER 0 +#define CONFIG_FFTFILT_FILTER 0 +#define CONFIG_FIELD_FILTER 0 +#define CONFIG_FIELDHINT_FILTER 0 +#define CONFIG_FIELDMATCH_FILTER 0 +#define CONFIG_FIELDORDER_FILTER 0 +#define CONFIG_FILLBORDERS_FILTER 0 +#define CONFIG_FIND_RECT_FILTER 0 +#define CONFIG_FLIP_VULKAN_FILTER 0 +#define CONFIG_FLOODFILL_FILTER 0 +#define CONFIG_FORMAT_FILTER 0 +#define CONFIG_FPS_FILTER 0 +#define CONFIG_FRAMEPACK_FILTER 0 +#define CONFIG_FRAMERATE_FILTER 0 +#define CONFIG_FRAMESTEP_FILTER 0 +#define CONFIG_FREEZEDETECT_FILTER 0 +#define CONFIG_FREEZEFRAMES_FILTER 0 +#define CONFIG_FREI0R_FILTER 0 +#define CONFIG_FSPP_FILTER 0 +#define CONFIG_FSYNC_FILTER 0 +#define CONFIG_GBLUR_FILTER 0 +#define CONFIG_GBLUR_VULKAN_FILTER 0 +#define CONFIG_GEQ_FILTER 0 +#define CONFIG_GRADFUN_FILTER 0 +#define CONFIG_GRAPHMONITOR_FILTER 0 +#define CONFIG_GRAYWORLD_FILTER 0 +#define CONFIG_GREYEDGE_FILTER 0 +#define CONFIG_GUIDED_FILTER 0 +#define CONFIG_HALDCLUT_FILTER 0 +#define CONFIG_HFLIP_FILTER 0 +#define CONFIG_HFLIP_VULKAN_FILTER 0 +#define CONFIG_HISTEQ_FILTER 0 +#define CONFIG_HISTOGRAM_FILTER 0 +#define CONFIG_HQDN3D_FILTER 0 +#define CONFIG_HQX_FILTER 0 +#define CONFIG_HSTACK_FILTER 0 +#define CONFIG_HSVHOLD_FILTER 0 +#define CONFIG_HSVKEY_FILTER 0 +#define CONFIG_HUE_FILTER 0 +#define CONFIG_HUESATURATION_FILTER 0 +#define CONFIG_HWDOWNLOAD_FILTER 0 +#define CONFIG_HWMAP_FILTER 0 +#define CONFIG_HWUPLOAD_FILTER 0 +#define CONFIG_HWUPLOAD_CUDA_FILTER 0 +#define CONFIG_HYSTERESIS_FILTER 0 +#define CONFIG_ICCDETECT_FILTER 0 +#define CONFIG_ICCGEN_FILTER 0 +#define CONFIG_IDENTITY_FILTER 0 +#define CONFIG_IDET_FILTER 0 +#define CONFIG_IL_FILTER 0 +#define CONFIG_INFLATE_FILTER 0 +#define CONFIG_INTERLACE_FILTER 0 +#define CONFIG_INTERLACE_VULKAN_FILTER 0 +#define CONFIG_INTERLEAVE_FILTER 0 +#define CONFIG_KERNDEINT_FILTER 0 +#define CONFIG_KIRSCH_FILTER 0 +#define CONFIG_LAGFUN_FILTER 0 +#define CONFIG_LATENCY_FILTER 0 +#define CONFIG_LCEVC_FILTER 0 +#define CONFIG_LENSCORRECTION_FILTER 0 +#define CONFIG_LENSFUN_FILTER 0 +#define CONFIG_LIBPLACEBO_FILTER 0 +#define CONFIG_LIBVMAF_FILTER 0 +#define CONFIG_LIBVMAF_CUDA_FILTER 0 +#define CONFIG_LIMITDIFF_FILTER 0 +#define CONFIG_LIMITER_FILTER 0 +#define CONFIG_LOOP_FILTER 0 +#define CONFIG_LUMAKEY_FILTER 0 +#define CONFIG_LUT_FILTER 0 +#define CONFIG_LUT1D_FILTER 0 +#define CONFIG_LUT2_FILTER 0 +#define CONFIG_LUT3D_FILTER 0 +#define CONFIG_LUTRGB_FILTER 0 +#define CONFIG_LUTYUV_FILTER 0 +#define CONFIG_MASKEDCLAMP_FILTER 0 +#define CONFIG_MASKEDMAX_FILTER 0 +#define CONFIG_MASKEDMERGE_FILTER 0 +#define CONFIG_MASKEDMIN_FILTER 0 +#define CONFIG_MASKEDTHRESHOLD_FILTER 0 +#define CONFIG_MASKFUN_FILTER 0 +#define CONFIG_MCDEINT_FILTER 0 +#define CONFIG_MEDIAN_FILTER 0 +#define CONFIG_MERGEPLANES_FILTER 0 +#define CONFIG_MESTIMATE_FILTER 0 +#define CONFIG_MESTIMATE_D3D12_FILTER 0 +#define CONFIG_METADATA_FILTER 0 +#define CONFIG_MIDEQUALIZER_FILTER 0 +#define CONFIG_MINTERPOLATE_FILTER 0 +#define CONFIG_MIX_FILTER 0 +#define CONFIG_MONOCHROME_FILTER 0 +#define CONFIG_MORPHO_FILTER 0 +#define CONFIG_MPDECIMATE_FILTER 0 +#define CONFIG_MSAD_FILTER 0 +#define CONFIG_MULTIPLY_FILTER 0 +#define CONFIG_NEGATE_FILTER 0 +#define CONFIG_NLMEANS_FILTER 0 +#define CONFIG_NLMEANS_OPENCL_FILTER 0 +#define CONFIG_NLMEANS_VULKAN_FILTER 0 +#define CONFIG_NNEDI_FILTER 0 +#define CONFIG_NOFORMAT_FILTER 0 +#define CONFIG_NOISE_FILTER 0 +#define CONFIG_NORMALIZE_FILTER 0 +#define CONFIG_NULL_FILTER 0 +#define CONFIG_OCR_FILTER 0 +#define CONFIG_OCV_FILTER 0 +#define CONFIG_OSCILLOSCOPE_FILTER 0 +#define CONFIG_OCIO_FILTER 0 +#define CONFIG_OVERLAY_FILTER 0 +#define CONFIG_OVERLAY_OPENCL_FILTER 0 +#define CONFIG_OVERLAY_QSV_FILTER 0 +#define CONFIG_OVERLAY_VAAPI_FILTER 0 +#define CONFIG_OVERLAY_VULKAN_FILTER 0 +#define CONFIG_OVERLAY_CUDA_FILTER 0 +#define CONFIG_OWDENOISE_FILTER 0 +#define CONFIG_PAD_FILTER 0 +#define CONFIG_PAD_CUDA_FILTER 0 +#define CONFIG_PAD_OPENCL_FILTER 0 +#define CONFIG_PALETTEGEN_FILTER 0 +#define CONFIG_PALETTEUSE_FILTER 0 +#define CONFIG_PERMS_FILTER 0 +#define CONFIG_PERSPECTIVE_FILTER 0 +#define CONFIG_PHASE_FILTER 0 +#define CONFIG_PHOTOSENSITIVITY_FILTER 0 +#define CONFIG_PIXDESCTEST_FILTER 0 +#define CONFIG_PIXELIZE_FILTER 0 +#define CONFIG_PIXSCOPE_FILTER 0 +#define CONFIG_PP7_FILTER 0 +#define CONFIG_PREMULTIPLY_FILTER 0 +#define CONFIG_PREMULTIPLY_DYNAMIC_FILTER 0 +#define CONFIG_PREWITT_FILTER 0 +#define CONFIG_PREWITT_OPENCL_FILTER 0 +#define CONFIG_PROCAMP_VAAPI_FILTER 0 +#define CONFIG_PROGRAM_OPENCL_FILTER 0 +#define CONFIG_PSEUDOCOLOR_FILTER 0 +#define CONFIG_PSNR_FILTER 0 +#define CONFIG_PULLUP_FILTER 0 +#define CONFIG_QP_FILTER 0 +#define CONFIG_QRENCODE_FILTER 0 +#define CONFIG_QUIRC_FILTER 0 +#define CONFIG_RANDOM_FILTER 0 +#define CONFIG_READEIA608_FILTER 0 +#define CONFIG_READVITC_FILTER 0 +#define CONFIG_REALTIME_FILTER 0 +#define CONFIG_REMAP_FILTER 0 +#define CONFIG_REMAP_OPENCL_FILTER 0 +#define CONFIG_REMOVEGRAIN_FILTER 0 +#define CONFIG_REMOVELOGO_FILTER 0 +#define CONFIG_REPEATFIELDS_FILTER 0 +#define CONFIG_REVERSE_FILTER 0 +#define CONFIG_RGBASHIFT_FILTER 0 +#define CONFIG_ROBERTS_FILTER 0 +#define CONFIG_ROBERTS_OPENCL_FILTER 0 +#define CONFIG_ROTATE_FILTER 0 +#define CONFIG_SAB_FILTER 0 +#define CONFIG_SCALE_FILTER 0 +#define CONFIG_VPP_AMF_FILTER 0 +#define CONFIG_SR_AMF_FILTER 0 +#define CONFIG_SCALE_CUDA_FILTER 0 +#define CONFIG_SCALE_D3D11_FILTER 0 +#define CONFIG_SCALE_D3D12_FILTER 0 +#define CONFIG_SCALE_NPP_FILTER 0 +#define CONFIG_SCALE_QSV_FILTER 0 +#define CONFIG_SCALE_VAAPI_FILTER 0 +#define CONFIG_SCALE_VT_FILTER 0 +#define CONFIG_SCALE_VULKAN_FILTER 0 +#define CONFIG_SCALE2REF_FILTER 0 +#define CONFIG_SCALE2REF_NPP_FILTER 0 +#define CONFIG_SCDET_FILTER 0 +#define CONFIG_SCDET_VULKAN_FILTER 0 +#define CONFIG_SCHARR_FILTER 0 +#define CONFIG_SCROLL_FILTER 0 +#define CONFIG_SEGMENT_FILTER 0 +#define CONFIG_SELECT_FILTER 0 +#define CONFIG_SELECTIVECOLOR_FILTER 0 +#define CONFIG_SENDCMD_FILTER 0 +#define CONFIG_SEPARATEFIELDS_FILTER 0 +#define CONFIG_SETDAR_FILTER 0 +#define CONFIG_SETFIELD_FILTER 0 +#define CONFIG_SETPARAMS_FILTER 0 +#define CONFIG_SETPTS_FILTER 0 +#define CONFIG_SETRANGE_FILTER 0 +#define CONFIG_SETSAR_FILTER 0 +#define CONFIG_SETTB_FILTER 0 +#define CONFIG_SHARPEN_NPP_FILTER 0 +#define CONFIG_SHARPNESS_VAAPI_FILTER 0 +#define CONFIG_SHEAR_FILTER 0 +#define CONFIG_SHOWINFO_FILTER 0 +#define CONFIG_SHOWPALETTE_FILTER 0 +#define CONFIG_SHUFFLEFRAMES_FILTER 0 +#define CONFIG_SHUFFLEPIXELS_FILTER 0 +#define CONFIG_SHUFFLEPLANES_FILTER 0 +#define CONFIG_SIDEDATA_FILTER 0 +#define CONFIG_SIGNALSTATS_FILTER 0 +#define CONFIG_SIGNATURE_FILTER 0 +#define CONFIG_SITI_FILTER 0 +#define CONFIG_SMARTBLUR_FILTER 0 +#define CONFIG_SOBEL_FILTER 0 +#define CONFIG_SOBEL_OPENCL_FILTER 0 +#define CONFIG_SPLIT_FILTER 0 +#define CONFIG_SPP_FILTER 0 +#define CONFIG_SR_FILTER 0 +#define CONFIG_SSIM_FILTER 0 +#define CONFIG_SSIM360_FILTER 0 +#define CONFIG_STEREO3D_FILTER 0 +#define CONFIG_STREAMSELECT_FILTER 0 +#define CONFIG_SUBTITLES_FILTER 0 +#define CONFIG_SUPER2XSAI_FILTER 0 +#define CONFIG_SWAPRECT_FILTER 0 +#define CONFIG_SWAPUV_FILTER 0 +#define CONFIG_TBLEND_FILTER 0 +#define CONFIG_TELECINE_FILTER 0 +#define CONFIG_THISTOGRAM_FILTER 0 +#define CONFIG_THRESHOLD_FILTER 0 +#define CONFIG_THUMBNAIL_FILTER 0 +#define CONFIG_THUMBNAIL_CUDA_FILTER 0 +#define CONFIG_TILE_FILTER 0 +#define CONFIG_TILTANDSHIFT_FILTER 0 +#define CONFIG_TINTERLACE_FILTER 0 +#define CONFIG_TLUT2_FILTER 0 +#define CONFIG_TMEDIAN_FILTER 0 +#define CONFIG_TMIDEQUALIZER_FILTER 0 +#define CONFIG_TMIX_FILTER 0 +#define CONFIG_TONEMAP_FILTER 0 +#define CONFIG_TONEMAP_OPENCL_FILTER 0 +#define CONFIG_TONEMAP_VAAPI_FILTER 0 +#define CONFIG_TPAD_FILTER 0 +#define CONFIG_TRANSPOSE_FILTER 0 +#define CONFIG_TRANSPOSE_NPP_FILTER 0 +#define CONFIG_TRANSPOSE_OPENCL_FILTER 0 +#define CONFIG_TRANSPOSE_VAAPI_FILTER 0 +#define CONFIG_TRANSPOSE_VT_FILTER 0 +#define CONFIG_TRANSPOSE_VULKAN_FILTER 0 +#define CONFIG_TRIM_FILTER 0 +#define CONFIG_UNPREMULTIPLY_FILTER 0 +#define CONFIG_UNSHARP_FILTER 0 +#define CONFIG_UNSHARP_OPENCL_FILTER 0 +#define CONFIG_UNTILE_FILTER 0 +#define CONFIG_USPP_FILTER 0 +#define CONFIG_V360_FILTER 0 +#define CONFIG_VAGUEDENOISER_FILTER 0 +#define CONFIG_VARBLUR_FILTER 0 +#define CONFIG_VECTORSCOPE_FILTER 0 +#define CONFIG_VFLIP_FILTER 0 +#define CONFIG_VFLIP_VULKAN_FILTER 0 +#define CONFIG_VFRDET_FILTER 0 +#define CONFIG_VIBRANCE_FILTER 0 +#define CONFIG_VIDSTABDETECT_FILTER 0 +#define CONFIG_VIDSTABTRANSFORM_FILTER 0 +#define CONFIG_VIF_FILTER 0 +#define CONFIG_VIGNETTE_FILTER 0 +#define CONFIG_VMAFMOTION_FILTER 0 +#define CONFIG_VPP_QSV_FILTER 0 +#define CONFIG_VSTACK_FILTER 0 +#define CONFIG_W3FDIF_FILTER 0 +#define CONFIG_WAVEFORM_FILTER 0 +#define CONFIG_WEAVE_FILTER 0 +#define CONFIG_XBR_FILTER 0 +#define CONFIG_XCORRELATE_FILTER 0 +#define CONFIG_XFADE_FILTER 0 +#define CONFIG_XFADE_OPENCL_FILTER 0 +#define CONFIG_XFADE_VULKAN_FILTER 0 +#define CONFIG_XMEDIAN_FILTER 0 +#define CONFIG_XPSNR_FILTER 0 +#define CONFIG_XSTACK_FILTER 0 +#define CONFIG_YADIF_FILTER 0 +#define CONFIG_YADIF_CUDA_FILTER 0 +#define CONFIG_YADIF_VIDEOTOOLBOX_FILTER 0 +#define CONFIG_YAEPBLUR_FILTER 0 +#define CONFIG_ZMQ_FILTER 0 +#define CONFIG_ZOOMPAN_FILTER 0 +#define CONFIG_ZSCALE_FILTER 0 +#define CONFIG_HSTACK_VAAPI_FILTER 0 +#define CONFIG_VSTACK_VAAPI_FILTER 0 +#define CONFIG_XSTACK_VAAPI_FILTER 0 +#define CONFIG_HSTACK_QSV_FILTER 0 +#define CONFIG_VSTACK_QSV_FILTER 0 +#define CONFIG_XSTACK_QSV_FILTER 0 +#define CONFIG_PAD_VAAPI_FILTER 0 +#define CONFIG_DRAWBOX_VAAPI_FILTER 0 +#define CONFIG_ALLRGB_FILTER 0 +#define CONFIG_ALLYUV_FILTER 0 +#define CONFIG_AMF_CAPTURE_FILTER 0 +#define CONFIG_CELLAUTO_FILTER 0 +#define CONFIG_COLOR_FILTER 0 +#define CONFIG_COLOR_VULKAN_FILTER 0 +#define CONFIG_COLORCHART_FILTER 0 +#define CONFIG_COLORSPECTRUM_FILTER 0 +#define CONFIG_COREIMAGESRC_FILTER 0 +#define CONFIG_DDAGRAB_FILTER 0 +#define CONFIG_FREI0R_SRC_FILTER 0 +#define CONFIG_GFXCAPTURE_FILTER 0 +#define CONFIG_GRADIENTS_FILTER 0 +#define CONFIG_HALDCLUTSRC_FILTER 0 +#define CONFIG_LIFE_FILTER 0 +#define CONFIG_MANDELBROT_FILTER 0 +#define CONFIG_MPTESTSRC_FILTER 0 +#define CONFIG_NULLSRC_FILTER 0 +#define CONFIG_OPENCLSRC_FILTER 0 +#define CONFIG_QRENCODESRC_FILTER 0 +#define CONFIG_PAL75BARS_FILTER 0 +#define CONFIG_PAL100BARS_FILTER 0 +#define CONFIG_PERLIN_FILTER 0 +#define CONFIG_RGBTESTSRC_FILTER 0 +#define CONFIG_SIERPINSKI_FILTER 0 +#define CONFIG_SMPTEBARS_FILTER 0 +#define CONFIG_SMPTEHDBARS_FILTER 0 +#define CONFIG_TESTSRC_FILTER 0 +#define CONFIG_TESTSRC2_FILTER 0 +#define CONFIG_YUVTESTSRC_FILTER 0 +#define CONFIG_ZONEPLATE_FILTER 0 +#define CONFIG_NULLSINK_FILTER 0 +#define CONFIG_A3DSCOPE_FILTER 0 +#define CONFIG_ABITSCOPE_FILTER 0 +#define CONFIG_ADRAWGRAPH_FILTER 0 +#define CONFIG_AGRAPHMONITOR_FILTER 0 +#define CONFIG_AHISTOGRAM_FILTER 0 +#define CONFIG_APHASEMETER_FILTER 0 +#define CONFIG_AVECTORSCOPE_FILTER 0 +#define CONFIG_CONCAT_FILTER 0 +#define CONFIG_SHOWCQT_FILTER 0 +#define CONFIG_SHOWCWT_FILTER 0 +#define CONFIG_SHOWFREQS_FILTER 0 +#define CONFIG_SHOWSPATIAL_FILTER 0 +#define CONFIG_SHOWSPECTRUM_FILTER 0 +#define CONFIG_SHOWSPECTRUMPIC_FILTER 0 +#define CONFIG_SHOWVOLUME_FILTER 0 +#define CONFIG_SHOWWAVES_FILTER 0 +#define CONFIG_SHOWWAVESPIC_FILTER 0 +#define CONFIG_SPECTRUMSYNTH_FILTER 0 +#define CONFIG_AVSYNCTEST_FILTER 0 +#define CONFIG_AMOVIE_FILTER 0 +#define CONFIG_MOVIE_FILTER 0 +#define CONFIG_AA_DEMUXER 0 +#define CONFIG_AAC_DEMUXER 0 +#define CONFIG_AAX_DEMUXER 0 +#define CONFIG_AC3_DEMUXER 0 +#define CONFIG_AC4_DEMUXER 0 +#define CONFIG_ACE_DEMUXER 0 +#define CONFIG_ACM_DEMUXER 0 +#define CONFIG_ACT_DEMUXER 0 +#define CONFIG_ADF_DEMUXER 0 +#define CONFIG_ADP_DEMUXER 0 +#define CONFIG_ADS_DEMUXER 0 +#define CONFIG_ADX_DEMUXER 0 +#define CONFIG_AEA_DEMUXER 0 +#define CONFIG_AFC_DEMUXER 0 +#define CONFIG_AIFF_DEMUXER 0 +#define CONFIG_AIX_DEMUXER 0 +#define CONFIG_ALP_DEMUXER 0 +#define CONFIG_AMR_DEMUXER 0 +#define CONFIG_AMRNB_DEMUXER 0 +#define CONFIG_AMRWB_DEMUXER 0 +#define CONFIG_ANM_DEMUXER 0 +#define CONFIG_APAC_DEMUXER 0 +#define CONFIG_APC_DEMUXER 0 +#define CONFIG_APE_DEMUXER 0 +#define CONFIG_APM_DEMUXER 0 +#define CONFIG_APNG_DEMUXER 0 +#define CONFIG_APTX_DEMUXER 0 +#define CONFIG_APTX_HD_DEMUXER 0 +#define CONFIG_APV_DEMUXER 0 +#define CONFIG_AQTITLE_DEMUXER 0 +#define CONFIG_ARGO_ASF_DEMUXER 0 +#define CONFIG_ARGO_BRP_DEMUXER 0 +#define CONFIG_ARGO_CVG_DEMUXER 0 +#define CONFIG_ASF_DEMUXER 0 +#define CONFIG_ASF_O_DEMUXER 0 +#define CONFIG_ASS_DEMUXER 0 +#define CONFIG_AST_DEMUXER 0 +#define CONFIG_AU_DEMUXER 0 +#define CONFIG_AV1_DEMUXER 0 +#define CONFIG_AVI_DEMUXER 0 +#define CONFIG_AVR_DEMUXER 0 +#define CONFIG_AVS_DEMUXER 0 +#define CONFIG_AVS2_DEMUXER 0 +#define CONFIG_AVS3_DEMUXER 0 +#define CONFIG_BETHSOFTVID_DEMUXER 0 +#define CONFIG_BFI_DEMUXER 0 +#define CONFIG_BINTEXT_DEMUXER 0 +#define CONFIG_BINK_DEMUXER 0 +#define CONFIG_BINKA_DEMUXER 0 +#define CONFIG_BIT_DEMUXER 0 +#define CONFIG_BITPACKED_DEMUXER 0 +#define CONFIG_BMV_DEMUXER 0 +#define CONFIG_BFSTM_DEMUXER 0 +#define CONFIG_BRSTM_DEMUXER 0 +#define CONFIG_BOA_DEMUXER 0 +#define CONFIG_BONK_DEMUXER 0 +#define CONFIG_C93_DEMUXER 0 +#define CONFIG_CAF_DEMUXER 0 +#define CONFIG_CAVSVIDEO_DEMUXER 0 +#define CONFIG_CDG_DEMUXER 0 +#define CONFIG_CDXL_DEMUXER 0 +#define CONFIG_CINE_DEMUXER 0 +#define CONFIG_CODEC2_DEMUXER 0 +#define CONFIG_CODEC2RAW_DEMUXER 0 +#define CONFIG_CONCAT_DEMUXER 0 +#define CONFIG_DASH_DEMUXER 0 +#define CONFIG_DATA_DEMUXER 0 +#define CONFIG_DAUD_DEMUXER 0 +#define CONFIG_DCSTR_DEMUXER 0 +#define CONFIG_DERF_DEMUXER 0 +#define CONFIG_DFA_DEMUXER 0 +#define CONFIG_DFPWM_DEMUXER 0 +#define CONFIG_DHAV_DEMUXER 0 +#define CONFIG_DIRAC_DEMUXER 0 +#define CONFIG_DNXHD_DEMUXER 0 +#define CONFIG_DSF_DEMUXER 0 +#define CONFIG_DSICIN_DEMUXER 0 +#define CONFIG_DSS_DEMUXER 0 +#define CONFIG_DTS_DEMUXER 0 +#define CONFIG_DTSHD_DEMUXER 0 +#define CONFIG_DV_DEMUXER 0 +#define CONFIG_DVBSUB_DEMUXER 0 +#define CONFIG_DVBTXT_DEMUXER 0 +#define CONFIG_DXA_DEMUXER 0 +#define CONFIG_EA_DEMUXER 0 +#define CONFIG_EA_CDATA_DEMUXER 0 +#define CONFIG_EAC3_DEMUXER 0 +#define CONFIG_EPAF_DEMUXER 0 +#define CONFIG_EVC_DEMUXER 0 +#define CONFIG_FFMETADATA_DEMUXER 0 +#define CONFIG_FILMSTRIP_DEMUXER 0 +#define CONFIG_FITS_DEMUXER 0 +#define CONFIG_FLAC_DEMUXER 0 +#define CONFIG_FLIC_DEMUXER 0 +#define CONFIG_FLV_DEMUXER 0 +#define CONFIG_LIVE_FLV_DEMUXER 0 +#define CONFIG_FOURXM_DEMUXER 0 +#define CONFIG_FRM_DEMUXER 0 +#define CONFIG_FSB_DEMUXER 0 +#define CONFIG_FWSE_DEMUXER 0 +#define CONFIG_G722_DEMUXER 0 +#define CONFIG_G723_1_DEMUXER 0 +#define CONFIG_G726_DEMUXER 0 +#define CONFIG_G726LE_DEMUXER 0 +#define CONFIG_G728_DEMUXER 0 +#define CONFIG_G729_DEMUXER 0 +#define CONFIG_GDV_DEMUXER 0 +#define CONFIG_GENH_DEMUXER 0 +#define CONFIG_GIF_DEMUXER 0 +#define CONFIG_GSM_DEMUXER 0 +#define CONFIG_GXF_DEMUXER 0 +#define CONFIG_H261_DEMUXER 0 +#define CONFIG_H263_DEMUXER 0 +#define CONFIG_H264_DEMUXER 0 +#define CONFIG_HCA_DEMUXER 0 +#define CONFIG_HCOM_DEMUXER 0 +#define CONFIG_HEVC_DEMUXER 0 +#define CONFIG_HLS_DEMUXER 0 +#define CONFIG_HNM_DEMUXER 0 +#define CONFIG_HXVS_DEMUXER 0 +#define CONFIG_IAMF_DEMUXER 0 +#define CONFIG_ICO_DEMUXER 0 +#define CONFIG_IDCIN_DEMUXER 0 +#define CONFIG_IDF_DEMUXER 0 +#define CONFIG_IFF_DEMUXER 0 +#define CONFIG_IFV_DEMUXER 0 +#define CONFIG_ILBC_DEMUXER 0 +#define CONFIG_IMAGE2_DEMUXER 0 +#define CONFIG_IMAGE2PIPE_DEMUXER 0 +#define CONFIG_IMAGE2_ALIAS_PIX_DEMUXER 0 +#define CONFIG_IMAGE2_BRENDER_PIX_DEMUXER 0 +#define CONFIG_IMF_DEMUXER 0 +#define CONFIG_INGENIENT_DEMUXER 0 +#define CONFIG_IPMOVIE_DEMUXER 0 +#define CONFIG_IPU_DEMUXER 0 +#define CONFIG_IRCAM_DEMUXER 0 +#define CONFIG_ISS_DEMUXER 0 +#define CONFIG_IV8_DEMUXER 0 +#define CONFIG_IVF_DEMUXER 0 +#define CONFIG_IVR_DEMUXER 0 +#define CONFIG_JACOSUB_DEMUXER 0 +#define CONFIG_JV_DEMUXER 0 +#define CONFIG_JPEGXL_ANIM_DEMUXER 0 +#define CONFIG_KUX_DEMUXER 0 +#define CONFIG_KVAG_DEMUXER 0 +#define CONFIG_LAF_DEMUXER 0 +#define CONFIG_LC3_DEMUXER 0 +#define CONFIG_LMLM4_DEMUXER 0 +#define CONFIG_LOAS_DEMUXER 0 +#define CONFIG_LUODAT_DEMUXER 0 +#define CONFIG_LRC_DEMUXER 0 +#define CONFIG_LVF_DEMUXER 0 +#define CONFIG_LXF_DEMUXER 0 +#define CONFIG_M4V_DEMUXER 0 +#define CONFIG_MCA_DEMUXER 0 +#define CONFIG_MCC_DEMUXER 0 +#define CONFIG_MATROSKA_DEMUXER 0 +#define CONFIG_MGSTS_DEMUXER 0 +#define CONFIG_MICRODVD_DEMUXER 0 +#define CONFIG_MJPEG_DEMUXER 0 +#define CONFIG_MJPEG_2000_DEMUXER 0 +#define CONFIG_MLP_DEMUXER 0 +#define CONFIG_MLV_DEMUXER 0 +#define CONFIG_MM_DEMUXER 0 +#define CONFIG_MMF_DEMUXER 0 +#define CONFIG_MODS_DEMUXER 0 +#define CONFIG_MOFLEX_DEMUXER 0 +#define CONFIG_MOV_DEMUXER 0 +#define CONFIG_MP3_DEMUXER 0 +#define CONFIG_MPC_DEMUXER 0 +#define CONFIG_MPC8_DEMUXER 0 +#define CONFIG_MPEGPS_DEMUXER 0 +#define CONFIG_MPEGTS_DEMUXER 0 +#define CONFIG_MPEGTSRAW_DEMUXER 0 +#define CONFIG_MPEGVIDEO_DEMUXER 0 +#define CONFIG_MPJPEG_DEMUXER 0 +#define CONFIG_MPL2_DEMUXER 0 +#define CONFIG_MPSUB_DEMUXER 0 +#define CONFIG_MSF_DEMUXER 0 +#define CONFIG_MSNWC_TCP_DEMUXER 0 +#define CONFIG_MSP_DEMUXER 0 +#define CONFIG_MTAF_DEMUXER 0 +#define CONFIG_MTV_DEMUXER 0 +#define CONFIG_MUSX_DEMUXER 0 +#define CONFIG_MV_DEMUXER 0 +#define CONFIG_MVI_DEMUXER 0 +#define CONFIG_MXF_DEMUXER 0 +#define CONFIG_MXG_DEMUXER 0 +#define CONFIG_NC_DEMUXER 0 +#define CONFIG_NISTSPHERE_DEMUXER 0 +#define CONFIG_NSP_DEMUXER 0 +#define CONFIG_NSV_DEMUXER 0 +#define CONFIG_NUT_DEMUXER 0 +#define CONFIG_NUV_DEMUXER 0 +#define CONFIG_OBU_DEMUXER 0 +#define CONFIG_OGG_DEMUXER 0 +#define CONFIG_OMA_DEMUXER 0 +#define CONFIG_OSQ_DEMUXER 0 +#define CONFIG_PAF_DEMUXER 0 +#define CONFIG_PCM_ALAW_DEMUXER 0 +#define CONFIG_PCM_MULAW_DEMUXER 0 +#define CONFIG_PCM_VIDC_DEMUXER 0 +#define CONFIG_PCM_F64BE_DEMUXER 0 +#define CONFIG_PCM_F64LE_DEMUXER 0 +#define CONFIG_PCM_F32BE_DEMUXER 0 +#define CONFIG_PCM_F32LE_DEMUXER 0 +#define CONFIG_PCM_S32BE_DEMUXER 0 +#define CONFIG_PCM_S32LE_DEMUXER 0 +#define CONFIG_PCM_S24BE_DEMUXER 0 +#define CONFIG_PCM_S24LE_DEMUXER 0 +#define CONFIG_PCM_S16BE_DEMUXER 0 +#define CONFIG_PCM_S16LE_DEMUXER 0 +#define CONFIG_PCM_S8_DEMUXER 0 +#define CONFIG_PCM_U32BE_DEMUXER 0 +#define CONFIG_PCM_U32LE_DEMUXER 0 +#define CONFIG_PCM_U24BE_DEMUXER 0 +#define CONFIG_PCM_U24LE_DEMUXER 0 +#define CONFIG_PCM_U16BE_DEMUXER 0 +#define CONFIG_PCM_U16LE_DEMUXER 0 +#define CONFIG_PCM_U8_DEMUXER 0 +#define CONFIG_PDV_DEMUXER 0 +#define CONFIG_PJS_DEMUXER 0 +#define CONFIG_PMP_DEMUXER 0 +#define CONFIG_PP_BNK_DEMUXER 0 +#define CONFIG_PVA_DEMUXER 0 +#define CONFIG_PVF_DEMUXER 0 +#define CONFIG_QCP_DEMUXER 0 +#define CONFIG_QOA_DEMUXER 0 +#define CONFIG_R3D_DEMUXER 0 +#define CONFIG_RAWVIDEO_DEMUXER 0 +#define CONFIG_RCWT_DEMUXER 0 +#define CONFIG_REALTEXT_DEMUXER 0 +#define CONFIG_REDSPARK_DEMUXER 0 +#define CONFIG_RKA_DEMUXER 0 +#define CONFIG_RL2_DEMUXER 0 +#define CONFIG_RM_DEMUXER 0 +#define CONFIG_ROQ_DEMUXER 0 +#define CONFIG_RPL_DEMUXER 0 +#define CONFIG_RSD_DEMUXER 0 +#define CONFIG_RSO_DEMUXER 0 +#define CONFIG_RTP_DEMUXER 0 +#define CONFIG_RTSP_DEMUXER 0 +#define CONFIG_S337M_DEMUXER 0 +#define CONFIG_SAMI_DEMUXER 0 +#define CONFIG_SAP_DEMUXER 0 +#define CONFIG_SBC_DEMUXER 0 +#define CONFIG_SBG_DEMUXER 0 +#define CONFIG_SCC_DEMUXER 0 +#define CONFIG_SCD_DEMUXER 0 +#define CONFIG_SDNS_DEMUXER 0 +#define CONFIG_SDP_DEMUXER 0 +#define CONFIG_SDR2_DEMUXER 0 +#define CONFIG_SDS_DEMUXER 0 +#define CONFIG_SDX_DEMUXER 0 +#define CONFIG_SEGAFILM_DEMUXER 0 +#define CONFIG_SER_DEMUXER 0 +#define CONFIG_SGA_DEMUXER 0 +#define CONFIG_SHORTEN_DEMUXER 0 +#define CONFIG_SIFF_DEMUXER 0 +#define CONFIG_SIMBIOSIS_IMX_DEMUXER 0 +#define CONFIG_SLN_DEMUXER 0 +#define CONFIG_SMACKER_DEMUXER 0 +#define CONFIG_SMJPEG_DEMUXER 0 +#define CONFIG_SMUSH_DEMUXER 0 +#define CONFIG_SOL_DEMUXER 0 +#define CONFIG_SOX_DEMUXER 0 +#define CONFIG_SPDIF_DEMUXER 0 +#define CONFIG_SRT_DEMUXER 0 +#define CONFIG_STR_DEMUXER 0 +#define CONFIG_STL_DEMUXER 0 +#define CONFIG_SUBVIEWER1_DEMUXER 0 +#define CONFIG_SUBVIEWER_DEMUXER 0 +#define CONFIG_SUP_DEMUXER 0 +#define CONFIG_SVAG_DEMUXER 0 +#define CONFIG_SVS_DEMUXER 0 +#define CONFIG_SWF_DEMUXER 0 +#define CONFIG_TAK_DEMUXER 0 +#define CONFIG_TEDCAPTIONS_DEMUXER 0 +#define CONFIG_THP_DEMUXER 0 +#define CONFIG_THREEDOSTR_DEMUXER 0 +#define CONFIG_TIERTEXSEQ_DEMUXER 0 +#define CONFIG_TMV_DEMUXER 0 +#define CONFIG_TRUEHD_DEMUXER 0 +#define CONFIG_TTA_DEMUXER 0 +#define CONFIG_TXD_DEMUXER 0 +#define CONFIG_TTY_DEMUXER 0 +#define CONFIG_TY_DEMUXER 0 +#define CONFIG_USM_DEMUXER 0 +#define CONFIG_V210_DEMUXER 0 +#define CONFIG_V210X_DEMUXER 0 +#define CONFIG_VAG_DEMUXER 0 +#define CONFIG_VC1_DEMUXER 0 +#define CONFIG_VC1T_DEMUXER 0 +#define CONFIG_VIVIDAS_DEMUXER 0 +#define CONFIG_VIVO_DEMUXER 0 +#define CONFIG_VMD_DEMUXER 0 +#define CONFIG_VOBSUB_DEMUXER 0 +#define CONFIG_VOC_DEMUXER 0 +#define CONFIG_VPK_DEMUXER 0 +#define CONFIG_VPLAYER_DEMUXER 0 +#define CONFIG_VQF_DEMUXER 0 +#define CONFIG_VVC_DEMUXER 0 +#define CONFIG_W64_DEMUXER 0 +#define CONFIG_WADY_DEMUXER 0 +#define CONFIG_WAVARC_DEMUXER 0 +#define CONFIG_WAV_DEMUXER 0 +#define CONFIG_WC3_DEMUXER 0 +#define CONFIG_WEBM_DASH_MANIFEST_DEMUXER 0 +#define CONFIG_WEBVTT_DEMUXER 0 +#define CONFIG_WSAUD_DEMUXER 0 +#define CONFIG_WSD_DEMUXER 0 +#define CONFIG_WSVQA_DEMUXER 0 +#define CONFIG_WTV_DEMUXER 0 +#define CONFIG_WVE_DEMUXER 0 +#define CONFIG_WV_DEMUXER 0 +#define CONFIG_XA_DEMUXER 0 +#define CONFIG_XBIN_DEMUXER 0 +#define CONFIG_XMD_DEMUXER 0 +#define CONFIG_XMV_DEMUXER 0 +#define CONFIG_XVAG_DEMUXER 0 +#define CONFIG_XWMA_DEMUXER 0 +#define CONFIG_YOP_DEMUXER 0 +#define CONFIG_YUV4MPEGPIPE_DEMUXER 0 +#define CONFIG_IMAGE_BMP_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_CRI_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_DDS_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_DPX_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_EXR_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_GEM_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_GIF_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_HDR_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_J2K_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_JPEG_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_JPEGLS_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_JPEGXL_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_JPEGXS_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PAM_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PBM_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PCX_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PFM_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PGMYUV_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PGM_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PGX_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PHM_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PHOTOCD_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PICTOR_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PNG_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PPM_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_PSD_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_QDRAW_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_QOI_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_SGI_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_SVG_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_SUNRAST_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_TIFF_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_VBN_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_WEBP_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_XBM_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_XPM_PIPE_DEMUXER 0 +#define CONFIG_IMAGE_XWD_PIPE_DEMUXER 0 +#define CONFIG_AVISYNTH_DEMUXER 0 +#define CONFIG_DVDVIDEO_DEMUXER 0 +#define CONFIG_LIBGME_DEMUXER 0 +#define CONFIG_LIBMODPLUG_DEMUXER 0 +#define CONFIG_LIBOPENMPT_DEMUXER 0 +#define CONFIG_VAPOURSYNTH_DEMUXER 0 +#define CONFIG_A64_MUXER 0 +#define CONFIG_AC3_MUXER 0 +#define CONFIG_AC4_MUXER 0 +#define CONFIG_ADTS_MUXER 0 +#define CONFIG_ADX_MUXER 0 +#define CONFIG_AEA_MUXER 0 +#define CONFIG_AIFF_MUXER 0 +#define CONFIG_ALP_MUXER 0 +#define CONFIG_AMR_MUXER 0 +#define CONFIG_AMV_MUXER 0 +#define CONFIG_APM_MUXER 0 +#define CONFIG_APNG_MUXER 0 +#define CONFIG_APTX_MUXER 0 +#define CONFIG_APTX_HD_MUXER 0 +#define CONFIG_APV_MUXER 0 +#define CONFIG_ARGO_ASF_MUXER 0 +#define CONFIG_ARGO_CVG_MUXER 0 +#define CONFIG_ASF_MUXER 0 +#define CONFIG_ASS_MUXER 0 +#define CONFIG_AST_MUXER 0 +#define CONFIG_ASF_STREAM_MUXER 0 +#define CONFIG_AU_MUXER 0 +#define CONFIG_AVI_MUXER 0 +#define CONFIG_AVIF_MUXER 0 +#define CONFIG_AVM2_MUXER 0 +#define CONFIG_AVS2_MUXER 0 +#define CONFIG_AVS3_MUXER 0 +#define CONFIG_BIT_MUXER 0 +#define CONFIG_CAF_MUXER 0 +#define CONFIG_CAVSVIDEO_MUXER 0 +#define CONFIG_CODEC2_MUXER 0 +#define CONFIG_CODEC2RAW_MUXER 0 +#define CONFIG_CRC_MUXER 0 +#define CONFIG_DASH_MUXER 0 +#define CONFIG_DATA_MUXER 0 +#define CONFIG_DAUD_MUXER 0 +#define CONFIG_DFPWM_MUXER 0 +#define CONFIG_DIRAC_MUXER 0 +#define CONFIG_DNXHD_MUXER 0 +#define CONFIG_DTS_MUXER 0 +#define CONFIG_DV_MUXER 0 +#define CONFIG_EAC3_MUXER 0 +#define CONFIG_EVC_MUXER 0 +#define CONFIG_F4V_MUXER 0 +#define CONFIG_FFMETADATA_MUXER 0 +#define CONFIG_FIFO_MUXER 0 +#define CONFIG_FILMSTRIP_MUXER 0 +#define CONFIG_FITS_MUXER 0 +#define CONFIG_FLAC_MUXER 0 +#define CONFIG_FLV_MUXER 0 +#define CONFIG_FRAMECRC_MUXER 0 +#define CONFIG_FRAMEHASH_MUXER 0 +#define CONFIG_FRAMEMD5_MUXER 0 +#define CONFIG_G722_MUXER 0 +#define CONFIG_G723_1_MUXER 0 +#define CONFIG_G726_MUXER 0 +#define CONFIG_G726LE_MUXER 0 +#define CONFIG_GIF_MUXER 0 +#define CONFIG_GSM_MUXER 0 +#define CONFIG_GXF_MUXER 0 +#define CONFIG_H261_MUXER 0 +#define CONFIG_H263_MUXER 0 +#define CONFIG_H264_MUXER 0 +#define CONFIG_HASH_MUXER 0 +#define CONFIG_HDS_MUXER 0 +#define CONFIG_HEVC_MUXER 0 +#define CONFIG_HLS_MUXER 0 +#define CONFIG_IAMF_MUXER 0 +#define CONFIG_ICO_MUXER 0 +#define CONFIG_ILBC_MUXER 0 +#define CONFIG_IMAGE2_MUXER 0 +#define CONFIG_IMAGE2PIPE_MUXER 0 +#define CONFIG_IPOD_MUXER 0 +#define CONFIG_IRCAM_MUXER 0 +#define CONFIG_ISMV_MUXER 0 +#define CONFIG_IVF_MUXER 0 +#define CONFIG_JACOSUB_MUXER 0 +#define CONFIG_KVAG_MUXER 0 +#define CONFIG_LATM_MUXER 0 +#define CONFIG_LC3_MUXER 0 +#define CONFIG_LRC_MUXER 0 +#define CONFIG_M4V_MUXER 0 +#define CONFIG_MCC_MUXER 0 +#define CONFIG_MD5_MUXER 0 +#define CONFIG_MATROSKA_MUXER 0 +#define CONFIG_MATROSKA_AUDIO_MUXER 0 +#define CONFIG_MICRODVD_MUXER 0 +#define CONFIG_MJPEG_MUXER 0 +#define CONFIG_MLP_MUXER 0 +#define CONFIG_MMF_MUXER 0 +#define CONFIG_MOV_MUXER 0 +#define CONFIG_MP2_MUXER 0 +#define CONFIG_MP3_MUXER 0 +#define CONFIG_MP4_MUXER 0 +#define CONFIG_MPEG1SYSTEM_MUXER 0 +#define CONFIG_MPEG1VCD_MUXER 0 +#define CONFIG_MPEG1VIDEO_MUXER 0 +#define CONFIG_MPEG2DVD_MUXER 0 +#define CONFIG_MPEG2SVCD_MUXER 0 +#define CONFIG_MPEG2VIDEO_MUXER 0 +#define CONFIG_MPEG2VOB_MUXER 0 +#define CONFIG_MPEGTS_MUXER 0 +#define CONFIG_MPJPEG_MUXER 0 +#define CONFIG_MXF_MUXER 0 +#define CONFIG_MXF_D10_MUXER 0 +#define CONFIG_MXF_OPATOM_MUXER 0 +#define CONFIG_NULL_MUXER 0 +#define CONFIG_NUT_MUXER 0 +#define CONFIG_OBU_MUXER 0 +#define CONFIG_OGA_MUXER 0 +#define CONFIG_OGG_MUXER 0 +#define CONFIG_OGV_MUXER 0 +#define CONFIG_OMA_MUXER 0 +#define CONFIG_OPUS_MUXER 0 +#define CONFIG_PCM_ALAW_MUXER 0 +#define CONFIG_PCM_MULAW_MUXER 0 +#define CONFIG_PCM_VIDC_MUXER 0 +#define CONFIG_PCM_F64BE_MUXER 0 +#define CONFIG_PCM_F64LE_MUXER 0 +#define CONFIG_PCM_F32BE_MUXER 0 +#define CONFIG_PCM_F32LE_MUXER 0 +#define CONFIG_PCM_S32BE_MUXER 0 +#define CONFIG_PCM_S32LE_MUXER 0 +#define CONFIG_PCM_S24BE_MUXER 0 +#define CONFIG_PCM_S24LE_MUXER 0 +#define CONFIG_PCM_S16BE_MUXER 0 +#define CONFIG_PCM_S16LE_MUXER 0 +#define CONFIG_PCM_S8_MUXER 0 +#define CONFIG_PCM_U32BE_MUXER 0 +#define CONFIG_PCM_U32LE_MUXER 0 +#define CONFIG_PCM_U24BE_MUXER 0 +#define CONFIG_PCM_U24LE_MUXER 0 +#define CONFIG_PCM_U16BE_MUXER 0 +#define CONFIG_PCM_U16LE_MUXER 0 +#define CONFIG_PCM_U8_MUXER 0 +#define CONFIG_PSP_MUXER 0 +#define CONFIG_RAWVIDEO_MUXER 0 +#define CONFIG_RCWT_MUXER 0 +#define CONFIG_RM_MUXER 0 +#define CONFIG_ROQ_MUXER 0 +#define CONFIG_RSO_MUXER 0 +#define CONFIG_RTP_MUXER 0 +#define CONFIG_RTP_MPEGTS_MUXER 0 +#define CONFIG_RTSP_MUXER 0 +#define CONFIG_SAP_MUXER 0 +#define CONFIG_SBC_MUXER 0 +#define CONFIG_SCC_MUXER 0 +#define CONFIG_SEGAFILM_MUXER 0 +#define CONFIG_SEGMENT_MUXER 0 +#define CONFIG_STREAM_SEGMENT_MUXER 0 +#define CONFIG_SMJPEG_MUXER 0 +#define CONFIG_SMOOTHSTREAMING_MUXER 0 +#define CONFIG_SOX_MUXER 0 +#define CONFIG_SPX_MUXER 0 +#define CONFIG_SPDIF_MUXER 0 +#define CONFIG_SRT_MUXER 0 +#define CONFIG_STREAMHASH_MUXER 0 +#define CONFIG_SUP_MUXER 0 +#define CONFIG_SWF_MUXER 0 +#define CONFIG_TEE_MUXER 0 +#define CONFIG_TG2_MUXER 0 +#define CONFIG_TGP_MUXER 0 +#define CONFIG_MKVTIMESTAMP_V2_MUXER 0 +#define CONFIG_TRUEHD_MUXER 0 +#define CONFIG_TTA_MUXER 0 +#define CONFIG_TTML_MUXER 0 +#define CONFIG_UNCODEDFRAMECRC_MUXER 0 +#define CONFIG_VC1_MUXER 0 +#define CONFIG_VC1T_MUXER 0 +#define CONFIG_VOC_MUXER 0 +#define CONFIG_VVC_MUXER 0 +#define CONFIG_W64_MUXER 0 +#define CONFIG_WAV_MUXER 0 +#define CONFIG_WEBM_MUXER 0 +#define CONFIG_WEBM_DASH_MANIFEST_MUXER 0 +#define CONFIG_WEBM_CHUNK_MUXER 0 +#define CONFIG_WEBP_MUXER 0 +#define CONFIG_WEBVTT_MUXER 0 +#define CONFIG_WHIP_MUXER 0 +#define CONFIG_WSAUD_MUXER 0 +#define CONFIG_WTV_MUXER 0 +#define CONFIG_WV_MUXER 0 +#define CONFIG_YUV4MPEGPIPE_MUXER 0 +#define CONFIG_CHROMAPRINT_MUXER 0 +#define CONFIG_ANDROID_CONTENT_PROTOCOL 0 +#define CONFIG_ASYNC_PROTOCOL 0 +#define CONFIG_BLURAY_PROTOCOL 0 +#define CONFIG_CACHE_PROTOCOL 0 +#define CONFIG_CONCAT_PROTOCOL 0 +#define CONFIG_CONCATF_PROTOCOL 0 +#define CONFIG_CRYPTO_PROTOCOL 0 +#define CONFIG_DATA_PROTOCOL 0 +#define CONFIG_FD_PROTOCOL 0 +#define CONFIG_FFRTMPCRYPT_PROTOCOL 0 +#define CONFIG_FFRTMPHTTP_PROTOCOL 0 +#define CONFIG_FILE_PROTOCOL 0 +#define CONFIG_FTP_PROTOCOL 0 +#define CONFIG_GOPHER_PROTOCOL 0 +#define CONFIG_GOPHERS_PROTOCOL 0 +#define CONFIG_HTTP_PROTOCOL 0 +#define CONFIG_HTTPPROXY_PROTOCOL 0 +#define CONFIG_HTTPS_PROTOCOL 0 +#define CONFIG_ICECAST_PROTOCOL 0 +#define CONFIG_MMSH_PROTOCOL 0 +#define CONFIG_MMST_PROTOCOL 0 +#define CONFIG_MD5_PROTOCOL 0 +#define CONFIG_PIPE_PROTOCOL 0 +#define CONFIG_PROMPEG_PROTOCOL 0 +#define CONFIG_RTMP_PROTOCOL 0 +#define CONFIG_RTMPE_PROTOCOL 0 +#define CONFIG_RTMPS_PROTOCOL 0 +#define CONFIG_RTMPT_PROTOCOL 0 +#define CONFIG_RTMPTE_PROTOCOL 0 +#define CONFIG_RTMPTS_PROTOCOL 0 +#define CONFIG_RTP_PROTOCOL 0 +#define CONFIG_SCTP_PROTOCOL 0 +#define CONFIG_SRTP_PROTOCOL 0 +#define CONFIG_SUBFILE_PROTOCOL 0 +#define CONFIG_TEE_PROTOCOL 0 +#define CONFIG_TCP_PROTOCOL 0 +#define CONFIG_TLS_PROTOCOL 0 +#define CONFIG_DTLS_PROTOCOL 0 +#define CONFIG_UDP_PROTOCOL 0 +#define CONFIG_UDPLITE_PROTOCOL 0 +#define CONFIG_UNIX_PROTOCOL 0 +#define CONFIG_LIBAMQP_PROTOCOL 0 +#define CONFIG_LIBRIST_PROTOCOL 0 +#define CONFIG_LIBRTMP_PROTOCOL 0 +#define CONFIG_LIBRTMPE_PROTOCOL 0 +#define CONFIG_LIBRTMPS_PROTOCOL 0 +#define CONFIG_LIBRTMPT_PROTOCOL 0 +#define CONFIG_LIBRTMPTE_PROTOCOL 0 +#define CONFIG_LIBSRT_PROTOCOL 0 +#define CONFIG_LIBSSH_PROTOCOL 0 +#define CONFIG_LIBSMBCLIENT_PROTOCOL 0 +#define CONFIG_LIBZMQ_PROTOCOL 0 +#define CONFIG_IPFS_GATEWAY_PROTOCOL 0 +#define CONFIG_IPNS_GATEWAY_PROTOCOL 0 +#endif /* FFMPEG_CONFIG_COMPONENTS_H */ diff --git a/libs/ffmpeg/libavcodec/defs.h b/libs/ffmpeg/libavcodec/defs.h new file mode 100644 index 00000000000..b13e983b13a --- /dev/null +++ b/libs/ffmpeg/libavcodec/defs.h @@ -0,0 +1,362 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DEFS_H +#define AVCODEC_DEFS_H + +/** + * @file + * @ingroup libavc + * Misc types and constants that do not belong anywhere else. + */ + +#include <stdint.h> +#include <stdlib.h> + +/** + * @ingroup lavc_decoding + * Required number of additionally allocated bytes at the end of the input bitstream for decoding. + * This is mainly needed because some optimized bitstream readers read + * 32 or 64 bit at once and could read over the end.<br> + * Note: If the first 23 bits of the additional bytes are not 0, then damaged + * MPEG bitstreams could cause overread and segfault. + */ +#define AV_INPUT_BUFFER_PADDING_SIZE 64 + +/** + * Verify checksums embedded in the bitstream (could be of either encoded or + * decoded data, depending on the format) and print an error message on mismatch. + * If AV_EF_EXPLODE is also set, a mismatching checksum will result in the + * decoder/demuxer returning an error. + */ +#define AV_EF_CRCCHECK (1<<0) +#define AV_EF_BITSTREAM (1<<1) ///< detect bitstream specification deviations +#define AV_EF_BUFFER (1<<2) ///< detect improper bitstream length +#define AV_EF_EXPLODE (1<<3) ///< abort decoding on minor error detection + +#define AV_EF_IGNORE_ERR (1<<15) ///< ignore errors and continue +#define AV_EF_CAREFUL (1<<16) ///< consider things that violate the spec, are fast to calculate and have not been seen in the wild as errors +#define AV_EF_COMPLIANT (1<<17) ///< consider all spec non compliances as errors +#define AV_EF_AGGRESSIVE (1<<18) ///< consider things that a sane encoder/muxer should not do as an error + +#define FF_COMPLIANCE_VERY_STRICT 2 ///< Strictly conform to an older more strict version of the spec or reference software. +#define FF_COMPLIANCE_STRICT 1 ///< Strictly conform to all the things in the spec no matter what consequences. +#define FF_COMPLIANCE_NORMAL 0 +#define FF_COMPLIANCE_UNOFFICIAL -1 ///< Allow unofficial extensions +#define FF_COMPLIANCE_EXPERIMENTAL -2 ///< Allow nonstandardized experimental things. + + +#define AV_PROFILE_UNKNOWN -99 +#define AV_PROFILE_RESERVED -100 + +#define AV_PROFILE_AAC_MAIN 0 +#define AV_PROFILE_AAC_LOW 1 +#define AV_PROFILE_AAC_SSR 2 +#define AV_PROFILE_AAC_LTP 3 +#define AV_PROFILE_AAC_HE 4 +#define AV_PROFILE_AAC_HE_V2 28 +#define AV_PROFILE_AAC_LD 22 +#define AV_PROFILE_AAC_ELD 38 +#define AV_PROFILE_AAC_USAC 41 +#define AV_PROFILE_MPEG2_AAC_LOW 128 +#define AV_PROFILE_MPEG2_AAC_HE 131 + +#define AV_PROFILE_DNXHD 0 +#define AV_PROFILE_DNXHR_LB 1 +#define AV_PROFILE_DNXHR_SQ 2 +#define AV_PROFILE_DNXHR_HQ 3 +#define AV_PROFILE_DNXHR_HQX 4 +#define AV_PROFILE_DNXHR_444 5 + +#define AV_PROFILE_DTS 20 +#define AV_PROFILE_DTS_ES 30 +#define AV_PROFILE_DTS_96_24 40 +#define AV_PROFILE_DTS_HD_HRA 50 +#define AV_PROFILE_DTS_HD_MA 60 +#define AV_PROFILE_DTS_EXPRESS 70 +#define AV_PROFILE_DTS_HD_MA_X 61 +#define AV_PROFILE_DTS_HD_MA_X_IMAX 62 + +#define AV_PROFILE_EAC3_DDP_ATMOS 30 + +#define AV_PROFILE_TRUEHD_ATMOS 30 + +#define AV_PROFILE_MPEG2_422 0 +#define AV_PROFILE_MPEG2_HIGH 1 +#define AV_PROFILE_MPEG2_SS 2 +#define AV_PROFILE_MPEG2_SNR_SCALABLE 3 +#define AV_PROFILE_MPEG2_MAIN 4 +#define AV_PROFILE_MPEG2_SIMPLE 5 + +#define AV_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag +#define AV_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag + +#define AV_PROFILE_H264_BASELINE 66 +#define AV_PROFILE_H264_CONSTRAINED_BASELINE (66|AV_PROFILE_H264_CONSTRAINED) +#define AV_PROFILE_H264_MAIN 77 +#define AV_PROFILE_H264_EXTENDED 88 +#define AV_PROFILE_H264_HIGH 100 +#define AV_PROFILE_H264_HIGH_10 110 +#define AV_PROFILE_H264_HIGH_10_INTRA (110|AV_PROFILE_H264_INTRA) +#define AV_PROFILE_H264_MULTIVIEW_HIGH 118 +#define AV_PROFILE_H264_HIGH_422 122 +#define AV_PROFILE_H264_HIGH_422_INTRA (122|AV_PROFILE_H264_INTRA) +#define AV_PROFILE_H264_STEREO_HIGH 128 +#define AV_PROFILE_H264_HIGH_444 144 +#define AV_PROFILE_H264_HIGH_444_PREDICTIVE 244 +#define AV_PROFILE_H264_HIGH_444_INTRA (244|AV_PROFILE_H264_INTRA) +#define AV_PROFILE_H264_CAVLC_444 44 + +#define AV_PROFILE_VC1_SIMPLE 0 +#define AV_PROFILE_VC1_MAIN 1 +#define AV_PROFILE_VC1_COMPLEX 2 +#define AV_PROFILE_VC1_ADVANCED 3 + +#define AV_PROFILE_MPEG4_SIMPLE 0 +#define AV_PROFILE_MPEG4_SIMPLE_SCALABLE 1 +#define AV_PROFILE_MPEG4_CORE 2 +#define AV_PROFILE_MPEG4_MAIN 3 +#define AV_PROFILE_MPEG4_N_BIT 4 +#define AV_PROFILE_MPEG4_SCALABLE_TEXTURE 5 +#define AV_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6 +#define AV_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7 +#define AV_PROFILE_MPEG4_HYBRID 8 +#define AV_PROFILE_MPEG4_ADVANCED_REAL_TIME 9 +#define AV_PROFILE_MPEG4_CORE_SCALABLE 10 +#define AV_PROFILE_MPEG4_ADVANCED_CODING 11 +#define AV_PROFILE_MPEG4_ADVANCED_CORE 12 +#define AV_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13 +#define AV_PROFILE_MPEG4_SIMPLE_STUDIO 14 +#define AV_PROFILE_MPEG4_ADVANCED_SIMPLE 15 + +#define AV_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0 1 +#define AV_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1 2 +#define AV_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION 32768 +#define AV_PROFILE_JPEG2000_DCINEMA_2K 3 +#define AV_PROFILE_JPEG2000_DCINEMA_4K 4 + +#define AV_PROFILE_VP9_0 0 +#define AV_PROFILE_VP9_1 1 +#define AV_PROFILE_VP9_2 2 +#define AV_PROFILE_VP9_3 3 + +#define AV_PROFILE_HEVC_MAIN 1 +#define AV_PROFILE_HEVC_MAIN_10 2 +#define AV_PROFILE_HEVC_MAIN_STILL_PICTURE 3 +#define AV_PROFILE_HEVC_REXT 4 +#define AV_PROFILE_HEVC_MULTIVIEW_MAIN 6 +#define AV_PROFILE_HEVC_SCC 9 + +#define AV_PROFILE_VVC_MAIN_10 1 +#define AV_PROFILE_VVC_MAIN_10_444 33 + +#define AV_PROFILE_AV1_MAIN 0 +#define AV_PROFILE_AV1_HIGH 1 +#define AV_PROFILE_AV1_PROFESSIONAL 2 + +#define AV_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT 0xc0 +#define AV_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT 0xc1 +#define AV_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT 0xc2 +#define AV_PROFILE_MJPEG_HUFFMAN_LOSSLESS 0xc3 +#define AV_PROFILE_MJPEG_JPEG_LS 0xf7 + +#define AV_PROFILE_SBC_MSBC 1 + +#define AV_PROFILE_PRORES_PROXY 0 +#define AV_PROFILE_PRORES_LT 1 +#define AV_PROFILE_PRORES_STANDARD 2 +#define AV_PROFILE_PRORES_HQ 3 +#define AV_PROFILE_PRORES_4444 4 +#define AV_PROFILE_PRORES_XQ 5 + +#define AV_PROFILE_PRORES_RAW 0 +#define AV_PROFILE_PRORES_RAW_HQ 1 + +#define AV_PROFILE_ARIB_PROFILE_A 0 +#define AV_PROFILE_ARIB_PROFILE_C 1 + +#define AV_PROFILE_KLVA_SYNC 0 +#define AV_PROFILE_KLVA_ASYNC 1 + +#define AV_PROFILE_EVC_BASELINE 0 +#define AV_PROFILE_EVC_MAIN 1 + +#define AV_PROFILE_APV_422_10 33 +#define AV_PROFILE_APV_422_12 44 +#define AV_PROFILE_APV_444_10 55 +#define AV_PROFILE_APV_444_12 66 +#define AV_PROFILE_APV_4444_10 77 +#define AV_PROFILE_APV_4444_12 88 +#define AV_PROFILE_APV_400_10 99 + + +#define AV_LEVEL_UNKNOWN -99 + +enum AVFieldOrder { + AV_FIELD_UNKNOWN, + AV_FIELD_PROGRESSIVE, + AV_FIELD_TT, ///< Top coded_first, top displayed first + AV_FIELD_BB, ///< Bottom coded first, bottom displayed first + AV_FIELD_TB, ///< Top coded first, bottom displayed first + AV_FIELD_BT, ///< Bottom coded first, top displayed first +}; + +/** + * @ingroup lavc_decoding + */ +enum AVDiscard{ + /* We leave some space between them for extensions (drop some + * keyframes for intra-only or drop just some bidir frames). */ + AVDISCARD_NONE =-16, ///< discard nothing + AVDISCARD_DEFAULT = 0, ///< discard useless packets like 0 size packets in avi + AVDISCARD_NONREF = 8, ///< discard all non reference + AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames + AVDISCARD_NONINTRA= 24, ///< discard all non intra frames + AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes + AVDISCARD_ALL = 48, ///< discard all +}; + +enum AVAudioServiceType { + AV_AUDIO_SERVICE_TYPE_MAIN = 0, + AV_AUDIO_SERVICE_TYPE_EFFECTS = 1, + AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED = 2, + AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED = 3, + AV_AUDIO_SERVICE_TYPE_DIALOGUE = 4, + AV_AUDIO_SERVICE_TYPE_COMMENTARY = 5, + AV_AUDIO_SERVICE_TYPE_EMERGENCY = 6, + AV_AUDIO_SERVICE_TYPE_VOICE_OVER = 7, + AV_AUDIO_SERVICE_TYPE_KARAOKE = 8, + AV_AUDIO_SERVICE_TYPE_NB , ///< Not part of ABI +}; + +/** + * Pan Scan area. + * This specifies the area which should be displayed. + * Note there may be multiple such areas for one frame. + */ +typedef struct AVPanScan { + /** + * id + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int id; + + /** + * width and height in 1/16 pel + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int width; + int height; + + /** + * position of the top left corner in 1/16 pel for up to 3 fields/frames + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int16_t position[3][2]; +} AVPanScan; + +/** + * This structure describes the bitrate properties of an encoded bitstream. It + * roughly corresponds to a subset the VBV parameters for MPEG-2 or HRD + * parameters for H.264/HEVC. + */ +typedef struct AVCPBProperties { + /** + * Maximum bitrate of the stream, in bits per second. + * Zero if unknown or unspecified. + */ + int64_t max_bitrate; + /** + * Minimum bitrate of the stream, in bits per second. + * Zero if unknown or unspecified. + */ + int64_t min_bitrate; + /** + * Average bitrate of the stream, in bits per second. + * Zero if unknown or unspecified. + */ + int64_t avg_bitrate; + + /** + * The size of the buffer to which the ratecontrol is applied, in bits. + * Zero if unknown or unspecified. + */ + int64_t buffer_size; + + /** + * The delay between the time the packet this structure is associated with + * is received and the time when it should be decoded, in periods of a 27MHz + * clock. + * + * UINT64_MAX when unknown or unspecified. + */ + uint64_t vbv_delay; +} AVCPBProperties; + +/** + * Allocate a CPB properties structure and initialize its fields to default + * values. + * + * @param size if non-NULL, the size of the allocated struct will be written + * here. This is useful for embedding it in side data. + * + * @return the newly allocated struct or NULL on failure + */ +AVCPBProperties *av_cpb_properties_alloc(size_t *size); + +/** + * This structure supplies correlation between a packet timestamp and a wall clock + * production time. The definition follows the Producer Reference Time ('prft') + * as defined in ISO/IEC 14496-12 + */ +typedef struct AVProducerReferenceTime { + /** + * A UTC timestamp, in microseconds, since Unix epoch (e.g, av_gettime()). + */ + int64_t wallclock; + int flags; +} AVProducerReferenceTime; + +/** + * RTCP SR (Sender Report) information + * + * The received sender report information for an RTSP + * stream, exposed as AV_PKT_DATA_RTCP_SR side data. + */ +typedef struct AVRTCPSenderReport { + uint32_t ssrc; ///< Synchronization source identifier + uint64_t ntp_timestamp; ///< NTP time when the report was sent + uint32_t rtp_timestamp; ///< RTP time when the report was sent + uint32_t sender_nb_packets; ///< Total number of packets sent + uint32_t sender_nb_bytes; ///< Total number of bytes sent (excluding headers or padding) +} AVRTCPSenderReport; + +/** + * Encode extradata length to a buffer. Used by xiph codecs. + * + * @param s buffer to write to; must be at least (v/255+1) bytes long + * @param v size of extradata in bytes + * @return number of bytes written to the buffer. + */ +unsigned int av_xiphlacing(unsigned char *s, unsigned int v); + +#endif // AVCODEC_DEFS_H diff --git a/libs/ffmpeg/libavcodec/get_bits.h b/libs/ffmpeg/libavcodec/get_bits.h new file mode 100644 index 00000000000..a22c9755aed --- /dev/null +++ b/libs/ffmpeg/libavcodec/get_bits.h @@ -0,0 +1,715 @@ +/* + * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * bitstream reader API header. + */ + +#ifndef AVCODEC_GET_BITS_H +#define AVCODEC_GET_BITS_H + +#include <stdint.h> + +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/avassert.h" + +#include "defs.h" +#include "mathops.h" +#include "vlc.h" + +/* + * Safe bitstream reading: + * optionally, the get_bits API can check to ensure that we + * don't read past input buffer boundaries. This is protected + * with CONFIG_SAFE_BITSTREAM_READER at the global level, and + * then below that with UNCHECKED_BITSTREAM_READER at the per- + * decoder level. This means that decoders that check internally + * can "#define UNCHECKED_BITSTREAM_READER 1" to disable + * overread checks. + * Boundary checking causes a minor performance penalty so for + * applications that won't want/need this, it can be disabled + * globally using "#define CONFIG_SAFE_BITSTREAM_READER 0". + */ +#ifndef UNCHECKED_BITSTREAM_READER +#define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER +#endif + +#ifndef CACHED_BITSTREAM_READER +#define CACHED_BITSTREAM_READER 0 +#endif + +#if CACHED_BITSTREAM_READER + +// we always want the LE implementation, to provide get_bits_le() +#define BITSTREAM_LE + +#ifndef BITSTREAM_READER_LE +# define BITSTREAM_BE +# define BITSTREAM_DEFAULT_BE +#endif + +#include "bitstream.h" + +#undef BITSTREAM_LE +#undef BITSTREAM_BE +#undef BITSTREAM_DEFAULT_BE + +typedef BitstreamContext GetBitContext; + +#define get_bits_count bits_tell +#define get_bits_bytesize bits_bytesize +#define get_bits_left bits_left +#define skip_bits_long bits_skip +#define skip_bits bits_skip +#define get_bits bits_read_nz +#define get_bitsz bits_read +#define get_bits_long bits_read +#define get_bits1 bits_read_bit +#define get_bits64 bits_read_64 +#define get_xbits bits_read_xbits +#define get_sbits bits_read_signed_nz +#define get_sbits_long bits_read_signed +#define show_bits bits_peek +#define show_bits_long bits_peek +#define init_get_bits bits_init +#define init_get_bits8 bits_init8 +#define align_get_bits bits_align +#define get_vlc2 bits_read_vlc +#define get_vlc_multi bits_read_vlc_multi + +#define init_get_bits8_le(s, buffer, byte_size) bits_init8_le((BitstreamContextLE*)s, buffer, byte_size) +#define get_bits_le(s, n) bits_read_le((BitstreamContextLE*)s, n) + +#define show_bits1(s) bits_peek(s, 1) +#define skip_bits1(s) bits_skip(s, 1) + +#define skip_1stop_8data_bits bits_skip_1stop_8data + +#else // CACHED_BITSTREAM_READER + +typedef struct GetBitContext { + const uint8_t *buffer; + int index; + int size_in_bits; + int size_in_bits_plus8; +} GetBitContext; + +static inline unsigned int get_bits(GetBitContext *s, int n); +static inline void skip_bits(GetBitContext *s, int n); +static inline unsigned int show_bits(GetBitContext *s, int n); + +/* Bitstream reader API docs: + * name + * arbitrary name which is used as prefix for the internal variables + * + * gb + * getbitcontext + * + * OPEN_READER(name, gb) + * load gb into local variables + * + * CLOSE_READER(name, gb) + * store local vars in gb + * + * UPDATE_CACHE(name, gb) + * Refill the internal cache from the bitstream. + * After this call at least MIN_CACHE_BITS will be available. + * + * GET_CACHE(name, gb) + * Will output the contents of the internal cache, + * next bit is MSB of 32 or 64 bits (FIXME 64 bits). + * + * SHOW_UBITS(name, gb, num) + * Will return the next num bits. + * + * SHOW_SBITS(name, gb, num) + * Will return the next num bits and do sign extension. + * + * SKIP_BITS(name, gb, num) + * Will skip over the next num bits. + * Note, this is equivalent to SKIP_CACHE; SKIP_COUNTER. + * + * SKIP_CACHE(name, gb, num) + * Will remove the next num bits from the cache (note SKIP_COUNTER + * MUST be called before UPDATE_CACHE / CLOSE_READER). + * + * SKIP_COUNTER(name, gb, num) + * Will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS). + * + * LAST_SKIP_BITS(name, gb, num) + * Like SKIP_BITS, to be used if next call is UPDATE_CACHE or CLOSE_READER. + * + * BITS_LEFT(name, gb) + * Return the number of bits left + * + * For examples see get_bits, show_bits, skip_bits, get_vlc. + */ + +#define MIN_CACHE_BITS 25 + +#define OPEN_READER_NOSIZE_NOCACHE(name, gb) \ + unsigned int name ## _index = (gb)->index + +#define OPEN_READER_NOSIZE(name, gb) \ + OPEN_READER_NOSIZE_NOCACHE(name, gb); \ + unsigned int name ## _cache + +#if UNCHECKED_BITSTREAM_READER +#define OPEN_READER(name, gb) OPEN_READER_NOSIZE(name, gb) +#define OPEN_READER_SIZE(name, gb) ((void)0) +#define BITS_AVAILABLE(name, gb) 1 +#else +#define OPEN_READER_SIZE(name, gb) unsigned int name ## _size_plus8 = (gb)->size_in_bits_plus8 +#define OPEN_READER(name, gb) \ + OPEN_READER_NOSIZE(name, gb); \ + OPEN_READER_SIZE(name, gb) + +#define BITS_AVAILABLE(name, gb) name ## _index < name ## _size_plus8 +#endif + +#define CLOSE_READER(name, gb) (gb)->index = name ## _index + +#define UPDATE_CACHE_BE_EXT(name, gb, bits, dst_bits) name ## _cache = \ + AV_RB ## bits((gb)->buffer + (name ## _index >> 3)) << (name ## _index & 7) >> (bits - dst_bits) + +#define UPDATE_CACHE_LE_EXT(name, gb, bits, dst_bits) name ## _cache = \ + (uint ## dst_bits ## _t)(AV_RL ## bits((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7)) + +/* Using these two macros ensures that 32 bits are available. */ +# define UPDATE_CACHE_LE_32(name, gb) UPDATE_CACHE_LE_EXT(name, (gb), 64, 32) +# define UPDATE_CACHE_BE_32(name, gb) UPDATE_CACHE_BE_EXT(name, (gb), 64, 32) + +# define UPDATE_CACHE_LE(name, gb) UPDATE_CACHE_LE_EXT(name, (gb), 32, 32) +# define UPDATE_CACHE_BE(name, gb) UPDATE_CACHE_BE_EXT(name, (gb), 32, 32) + +#ifdef BITSTREAM_READER_LE + +# define UPDATE_CACHE(name, gb) UPDATE_CACHE_LE(name, gb) +# define UPDATE_CACHE_32(name, gb) UPDATE_CACHE_LE_32(name, (gb)) + +# define SKIP_CACHE(name, gb, num) name ## _cache >>= (num) + +#else + +# define UPDATE_CACHE(name, gb) UPDATE_CACHE_BE(name, gb) +# define UPDATE_CACHE_32(name, gb) UPDATE_CACHE_BE_32(name, (gb)) + +# define SKIP_CACHE(name, gb, num) name ## _cache <<= (num) + +#endif + +#if UNCHECKED_BITSTREAM_READER +# define SKIP_COUNTER(name, gb, num) name ## _index += (num) +#else +# define SKIP_COUNTER(name, gb, num) \ + name ## _index = FFMIN(name ## _size_plus8, name ## _index + (num)) +#endif + +#define BITS_LEFT(name, gb) ((int)((gb)->size_in_bits - name ## _index)) + +#define SKIP_BITS(name, gb, num) \ + do { \ + SKIP_CACHE(name, gb, num); \ + SKIP_COUNTER(name, gb, num); \ + } while (0) + +#define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) + +#define SHOW_UBITS_LE(name, gb, num) zero_extend(name ## _cache, num) +#define SHOW_SBITS_LE(name, gb, num) sign_extend(name ## _cache, num) + +#define SHOW_UBITS_BE(name, gb, num) NEG_USR32(name ## _cache, num) +#define SHOW_SBITS_BE(name, gb, num) NEG_SSR32(name ## _cache, num) + +#ifdef BITSTREAM_READER_LE +# define SHOW_UBITS(name, gb, num) SHOW_UBITS_LE(name, gb, num) +# define SHOW_SBITS(name, gb, num) SHOW_SBITS_LE(name, gb, num) +#else +# define SHOW_UBITS(name, gb, num) SHOW_UBITS_BE(name, gb, num) +# define SHOW_SBITS(name, gb, num) SHOW_SBITS_BE(name, gb, num) +#endif + +#define GET_CACHE(name, gb) ((uint32_t) name ## _cache) + + +static inline int get_bits_count(const GetBitContext *s) +{ + return s->index; +} + +/** + * Get the size of the GetBitContext's buffer in bytes. + * + * @param s the GetBitContext + * @param round_up If set, the number of bits will be rounded up to full bytes; + * this does not matter if the number of bits is known to be + * a multiple of eight, e.g. if the GetBitContext has been + * initialized with init_get_bits8. + */ +static inline int get_bits_bytesize(const GetBitContext *s, int round_up) +{ + return (s->size_in_bits + (round_up ? 7 : 0)) >> 3; +} + +/** + * Skips the specified number of bits. + * @param n the number of bits to skip, + * For the UNCHECKED_BITSTREAM_READER this must not cause the distance + * from the start to overflow int32_t. Staying within the bitstream + padding + * is sufficient, too. + */ +static inline void skip_bits_long(GetBitContext *s, int n) +{ +#if UNCHECKED_BITSTREAM_READER + s->index += n; +#else + s->index += av_clip(n, -s->index, s->size_in_bits_plus8 - s->index); +#endif +} + +/** + * Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB). + * if MSB not set it is negative + * @param n length in bits + */ +static inline int get_xbits(GetBitContext *s, int n) +{ + register int sign; + register int32_t cache; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + cache = GET_CACHE(re, s); + sign = ~cache >> 31; + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return (NEG_USR32(sign ^ cache, n) ^ sign) - sign; +} + +static inline int get_xbits_le(GetBitContext *s, int n) +{ + register int sign; + register int32_t cache; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE_LE(re, s); + cache = GET_CACHE(re, s); + sign = sign_extend(~cache, n) >> 31; + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return (zero_extend(sign ^ cache, n) ^ sign) - sign; +} + +static inline int get_sbits(GetBitContext *s, int n) +{ + register int tmp; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_SBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return tmp; +} + +/** + * Read 1-25 bits. + */ +static inline unsigned int get_bits(GetBitContext *s, int n) +{ + register unsigned int tmp; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + av_assert2(tmp < UINT64_C(1) << n); + return tmp; +} + +/** + * Read 0-25 bits. + */ +static av_always_inline int get_bitsz(GetBitContext *s, int n) +{ + return n ? get_bits(s, n) : 0; +} + +static inline unsigned int get_bits_le(GetBitContext *s, int n) +{ + register int tmp; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE_LE(re, s); + tmp = SHOW_UBITS_LE(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return tmp; +} + +/** + * Show 1-25 bits. + */ +static inline unsigned int show_bits(GetBitContext *s, int n) +{ + register unsigned int tmp; + OPEN_READER_NOSIZE(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); + return tmp; +} + +static inline void skip_bits(GetBitContext *s, int n) +{ + OPEN_READER_NOSIZE_NOCACHE(re, s); + OPEN_READER_SIZE(re, s); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); +} + +static inline unsigned int get_bits1(GetBitContext *s) +{ + unsigned int index = s->index; + uint8_t result = s->buffer[index >> 3]; +#ifdef BITSTREAM_READER_LE + result >>= index & 7; + result &= 1; +#else + result <<= index & 7; + result >>= 8 - 1; +#endif +#if !UNCHECKED_BITSTREAM_READER + if (s->index < s->size_in_bits_plus8) +#endif + index++; + s->index = index; + + return result; +} + +static inline unsigned int show_bits1(GetBitContext *s) +{ + return show_bits(s, 1); +} + +static inline void skip_bits1(GetBitContext *s) +{ + skip_bits(s, 1); +} + +/** + * Read 0-32 bits. + */ +static inline unsigned int get_bits_long(GetBitContext *s, int n) +{ + av_assert2(n>=0 && n<=32); + if (!n) { + return 0; + } else if ((!HAVE_FAST_64BIT || av_builtin_constant_p(n <= MIN_CACHE_BITS)) + && n <= MIN_CACHE_BITS) { + return get_bits(s, n); + } else { +#if HAVE_FAST_64BIT + unsigned tmp; + OPEN_READER(re, s); + UPDATE_CACHE_32(re, s); + tmp = SHOW_UBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + return tmp; +#else +#ifdef BITSTREAM_READER_LE + unsigned ret = get_bits(s, 16); + return ret | (get_bits(s, n - 16) << 16); +#else + unsigned ret = get_bits(s, 16) << (n - 16); + return ret | get_bits(s, n - 16); +#endif +#endif + } +} + +/** + * Read 0-64 bits. + */ +static inline uint64_t get_bits64(GetBitContext *s, int n) +{ + if (n <= 32) { + return get_bits_long(s, n); + } else { +#ifdef BITSTREAM_READER_LE + uint64_t ret = get_bits_long(s, 32); + return ret | (uint64_t) get_bits_long(s, n - 32) << 32; +#else + uint64_t ret = (uint64_t) get_bits_long(s, n - 32) << 32; + return ret | get_bits_long(s, 32); +#endif + } +} + +/** + * Read 0-32 bits as a signed integer. + */ +static inline int get_sbits_long(GetBitContext *s, int n) +{ + // sign_extend(x, 0) is undefined + if (!n) + return 0; + + return sign_extend(get_bits_long(s, n), n); +} + +/** + * Read 0-64 bits as a signed integer. + */ +static inline int64_t get_sbits64(GetBitContext *s, int n) +{ + // sign_extend(x, 0) is undefined + if (!n) + return 0; + + return sign_extend64(get_bits64(s, n), n); +} + +/** + * Show 0-32 bits. + */ +static inline unsigned int show_bits_long(GetBitContext *s, int n) +{ + if (n <= MIN_CACHE_BITS) { + return show_bits(s, n); + } else { + GetBitContext gb = *s; + return get_bits_long(&gb, n); + } +} + + +/** + * Initialize GetBitContext. + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param bit_size the size of the buffer in bits + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. + */ +static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, + int bit_size) +{ + int ret = 0; + + if (bit_size >= INT_MAX - FFMAX(7, AV_INPUT_BUFFER_PADDING_SIZE*8) || bit_size < 0 || !buffer) { + bit_size = 0; + buffer = NULL; + ret = AVERROR_INVALIDDATA; + } + + s->buffer = buffer; + s->size_in_bits = bit_size; + s->size_in_bits_plus8 = bit_size + 8; + s->index = 0; + + return ret; +} + +/** + * Initialize GetBitContext. + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param byte_size the size of the buffer in bytes + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. + */ +static inline int init_get_bits8(GetBitContext *s, const uint8_t *buffer, + int byte_size) +{ + if (byte_size > INT_MAX / 8 || byte_size < 0) + byte_size = -1; + return init_get_bits(s, buffer, byte_size * 8); +} + +static inline int init_get_bits8_le(GetBitContext *s, const uint8_t *buffer, + int byte_size) +{ + if (byte_size > INT_MAX / 8 || byte_size < 0) + byte_size = -1; + return init_get_bits(s, buffer, byte_size * 8); +} + +static inline const uint8_t *align_get_bits(GetBitContext *s) +{ + int n = -get_bits_count(s) & 7; + if (n) + skip_bits(s, n); + return s->buffer + (s->index >> 3); +} + +/** + * If the vlc code is invalid and max_depth=1, then no bits will be removed. + * If the vlc code is invalid and max_depth>1, then the number of bits removed + * is undefined. + */ +#define GET_VLC(code, name, gb, table, bits, max_depth) \ + do { \ + int n, nb_bits; \ + unsigned int index; \ + \ + index = SHOW_UBITS(name, gb, bits); \ + code = table[index].sym; \ + n = table[index].len; \ + \ + if (max_depth > 1 && n < 0) { \ + LAST_SKIP_BITS(name, gb, bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index].sym; \ + n = table[index].len; \ + if (max_depth > 2 && n < 0) { \ + LAST_SKIP_BITS(name, gb, nb_bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index].sym; \ + n = table[index].len; \ + } \ + } \ + SKIP_BITS(name, gb, n); \ + } while (0) + +#define GET_RL_VLC(level, run, name, gb, table, bits, \ + max_depth, need_update) \ + do { \ + int n, nb_bits; \ + unsigned int index; \ + \ + index = SHOW_UBITS(name, gb, bits); \ + level = table[index].level; \ + n = table[index].len8; \ + \ + if (max_depth > 1 && n < 0) { \ + SKIP_BITS(name, gb, bits); \ + if (need_update) { \ + UPDATE_CACHE(name, gb); \ + } \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + level; \ + level = table[index].level; \ + n = table[index].len8; \ + if (max_depth > 2 && n < 0) { \ + LAST_SKIP_BITS(name, gb, nb_bits); \ + if (need_update) { \ + UPDATE_CACHE(name, gb); \ + } \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + level; \ + level = table[index].level; \ + n = table[index].len8; \ + } \ + } \ + run = table[index].run; \ + SKIP_BITS(name, gb, n); \ + } while (0) + +/** + * Parse a vlc code. + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in vlc_init() + * @param max_depth is the number of times bits bits must be read to completely + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + * @returns the code parsed or -1 if no vlc matches + */ +static av_always_inline int get_vlc2(GetBitContext *s, const VLCElem *table, + int bits, int max_depth) +{ + int code; + + OPEN_READER(re, s); + UPDATE_CACHE(re, s); + + GET_VLC(code, re, s, table, bits, max_depth); + + CLOSE_READER(re, s); + + return code; +} + +static inline int get_vlc_multi(GetBitContext *s, uint8_t *dst, + av_unused const VLC_MULTI_ELEM *const Jtable, + const VLCElem *const table, + const int bits, const int max_depth, + av_unused const int symbols_size) +{ + dst[0] = get_vlc2(s, table, bits, max_depth); + return 1; +} + +static inline int decode012(GetBitContext *gb) +{ + int n; + n = get_bits1(gb); + if (n == 0) + return 0; + else + return get_bits1(gb) + 1; +} + +static inline int decode210(GetBitContext *gb) +{ + if (get_bits1(gb)) + return 0; + else + return 2 - get_bits1(gb); +} + +static inline int get_bits_left(GetBitContext *gb) +{ + return gb->size_in_bits - get_bits_count(gb); +} + +static inline int skip_1stop_8data_bits(GetBitContext *gb) +{ + if (get_bits_left(gb) <= 0) + return AVERROR_INVALIDDATA; + + while (get_bits1(gb)) { + skip_bits(gb, 8); + if (get_bits_left(gb) <= 0) + return AVERROR_INVALIDDATA; + } + + return 0; +} + +#endif // CACHED_BITSTREAM_READER + +#endif /* AVCODEC_GET_BITS_H */ diff --git a/libs/ffmpeg/libavcodec/mathops.h b/libs/ffmpeg/libavcodec/mathops.h new file mode 100644 index 00000000000..64431b8a159 --- /dev/null +++ b/libs/ffmpeg/libavcodec/mathops.h @@ -0,0 +1,257 @@ +/* + * simple math operations + * Copyright (c) 2001, 2002 Fabrice Bellard + * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> et al + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef AVCODEC_MATHOPS_H +#define AVCODEC_MATHOPS_H + +#include <stdint.h> + +#include "libavutil/attributes_internal.h" +#include "libavutil/common.h" +#include "config.h" + +#define MAX_NEG_CROP 1024 + +extern const uint32_t ff_inverse[257]; +extern const uint8_t ff_log2_run[41]; +EXTERN const uint32_t ff_square_tab[512]; +extern const uint8_t ff_sqrt_tab[256]; +EXTERN const uint8_t ff_crop_tab[256 + 2 * MAX_NEG_CROP]; +extern const uint8_t ff_zigzag_direct[64]; +extern const uint8_t ff_zigzag_scan[16+1]; + +#if ARCH_ARM +# include "arm/mathops.h" +#elif ARCH_MIPS +# include "mips/mathops.h" +#elif ARCH_PPC +# include "ppc/mathops.h" +#elif ARCH_RISCV +# include "riscv/mathops.h" +#elif ARCH_X86 +# include "x86/mathops.h" +#endif + +/* generic implementation */ + +#ifndef MUL64 +# define MUL64(a,b) ((int64_t)(a) * (int64_t)(b)) +#endif + +#ifndef MULL +# define MULL(a,b,s) (MUL64(a, b) >> (s)) +#endif + +#ifndef MULH +static av_always_inline int MULH(int a, int b){ + return MUL64(a, b) >> 32; +} +#endif + +#ifndef UMULH +static av_always_inline unsigned UMULH(unsigned a, unsigned b){ + return ((uint64_t)(a) * (uint64_t)(b))>>32; +} +#endif + +#ifndef MAC64 +# define MAC64(d, a, b) ((d) += MUL64(a, b)) +#endif + +#ifndef MLS64 +# define MLS64(d, a, b) ((d) -= MUL64(a, b)) +#endif + +/* signed 16x16 -> 32 multiply add accumulate */ +#ifndef MAC16 +# define MAC16(rt, ra, rb) rt += (ra) * (rb) +#endif + +/* signed 16x16 -> 32 multiply */ +#ifndef MUL16 +# define MUL16(ra, rb) ((ra) * (rb)) +#endif + +#ifndef MLS16 +# define MLS16(rt, ra, rb) ((rt) -= (ra) * (rb)) +#endif + +/* median of 3 */ +static inline av_const int median3_c(int a, int b, int c) +{ + int max2, min2, m; + + if (a >= b) { + max2 = a; + min2 = b; + } else { + max2 = b; + min2 = a; + } + m = (c >= max2) ? max2 : c; + + return (m >= min2) ? m : min2; +} + +#ifndef mid_pred +#define mid_pred median3_c +#endif + +#ifndef median4 +#define median4 median4 +static inline av_const int median4(int a, int b, int c, int d) +{ + if (a < b) { + if (c < d) return (FFMIN(b, d) + FFMAX(a, c)) / 2; + else return (FFMIN(b, c) + FFMAX(a, d)) / 2; + } else { + if (c < d) return (FFMIN(a, d) + FFMAX(b, c)) / 2; + else return (FFMIN(a, c) + FFMAX(b, d)) / 2; + } +} +#endif + +#define FF_SIGNBIT(x) ((x) >> CHAR_BIT * sizeof(x) - 1) + +#ifndef sign_extend +static inline av_const int sign_extend(int val, unsigned bits) +{ + unsigned shift = 8 * sizeof(int) - bits; + union { unsigned u; int s; } v = { (unsigned) val << shift }; + return v.s >> shift; +} +#endif + +#ifndef sign_extend64 +static inline av_const int64_t sign_extend64(int64_t val, unsigned bits) +{ + unsigned shift = 8 * sizeof(int64_t) - bits; + union { uint64_t u; int64_t s; } v = { (uint64_t) val << shift }; + return v.s >> shift; +} +#endif + +#ifndef zero_extend +static inline av_const unsigned zero_extend(unsigned val, unsigned bits) +{ + return (val << ((8 * sizeof(int)) - bits)) >> ((8 * sizeof(int)) - bits); +} +#endif + +#ifndef COPY3_IF_LT +#define COPY3_IF_LT(x, y, a, b, c, d)\ +if ((y) < (x)) {\ + (x) = (y);\ + (a) = (b);\ + (c) = (d);\ +} +#endif + +#ifndef MASK_ABS +#define MASK_ABS(mask, level) do { \ + mask = level >> 31; \ + level = (level ^ mask) - mask; \ + } while (0) +#endif + +#ifndef NEG_SSR32 +# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) +#endif + +#ifndef NEG_USR32 +# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) +#endif + +#if HAVE_BIGENDIAN +# ifndef PACK_2U8 +# define PACK_2U8(a,b) (((a) << 8) | (b)) +# endif +# ifndef PACK_4U8 +# define PACK_4U8(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) +# endif +# ifndef PACK_2U16 +# define PACK_2U16(a,b) (((a) << 16) | (b)) +# endif +#else +# ifndef PACK_2U8 +# define PACK_2U8(a,b) (((b) << 8) | (a)) +# endif +# ifndef PACK_4U2 +# define PACK_4U8(a,b,c,d) (((d) << 24) | ((c) << 16) | ((b) << 8) | (a)) +# endif +# ifndef PACK_2U16 +# define PACK_2U16(a,b) (((b) << 16) | (a)) +# endif +#endif + +#ifndef PACK_2S8 +# define PACK_2S8(a,b) PACK_2U8((a)&255, (b)&255) +#endif +#ifndef PACK_4S8 +# define PACK_4S8(a,b,c,d) PACK_4U8((a)&255, (b)&255, (c)&255, (d)&255) +#endif +#ifndef PACK_2S16 +# define PACK_2S16(a,b) PACK_2U16((a)&0xffff, (b)&0xffff) +#endif + +#ifndef FASTDIV +# define FASTDIV(a,b) ((uint32_t)((((uint64_t)a) * ff_inverse[b]) >> 32)) +#endif /* FASTDIV */ + +#ifndef ff_sqrt +#define ff_sqrt ff_sqrt +static inline av_const unsigned int ff_sqrt(unsigned int a) +{ + unsigned int b; + + if (a < 255) return (ff_sqrt_tab[a + 1] - 1) >> 4; + else if (a < (1 << 12)) b = ff_sqrt_tab[a >> 4] >> 2; +#if !CONFIG_SMALL + else if (a < (1 << 14)) b = ff_sqrt_tab[a >> 6] >> 1; + else if (a < (1 << 16)) b = ff_sqrt_tab[a >> 8] ; +#endif + else { + int s = av_log2_16bit(a >> 16) >> 1; + unsigned int c = a >> (s + 2); + b = ff_sqrt_tab[c >> (s + 8)]; + b = FASTDIV(c,b) + (b << s); + } + + return b - (a < b * b); +} +#endif + +static inline av_const float ff_sqrf(float a) +{ + return a*a; +} + +static inline int8_t ff_u8_to_s8(uint8_t a) +{ + union { + uint8_t u8; + int8_t s8; + } b; + b.u8 = a; + return b.s8; +} + +#endif /* AVCODEC_MATHOPS_H */ diff --git a/libs/ffmpeg/libavcodec/put_bits.h b/libs/ffmpeg/libavcodec/put_bits.h new file mode 100644 index 00000000000..98c0d7e51f0 --- /dev/null +++ b/libs/ffmpeg/libavcodec/put_bits.h @@ -0,0 +1,453 @@ +/* + * copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * bitstream writer API + */ + +#ifndef AVCODEC_PUT_BITS_H +#define AVCODEC_PUT_BITS_H + +#include <stdint.h> +#include <stddef.h> + +#include "config.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/avassert.h" +#include "libavutil/common.h" + +#if ARCH_X86_64 +// TODO: Benchmark and optionally enable on other 64-bit architectures. +typedef uint64_t BitBuf; +#define AV_WBBUF AV_WB64 +#define AV_WLBUF AV_WL64 +#define BUF_BITS 64 +#else +typedef uint32_t BitBuf; +#define AV_WBBUF AV_WB32 +#define AV_WLBUF AV_WL32 +#define BUF_BITS 32 +#endif + +typedef struct PutBitContext { + BitBuf bit_buf; + int bit_left; + uint8_t *buf, *buf_ptr, *buf_end; +} PutBitContext; + +/** + * Initialize the PutBitContext s. + * + * @param buffer the buffer where to put bits + * @param buffer_size the size in bytes of buffer + */ +static inline void init_put_bits(PutBitContext *s, uint8_t *buffer, + int buffer_size) +{ + if (buffer_size < 0) { + buffer_size = 0; + buffer = NULL; + } + + s->buf = buffer; + s->buf_end = s->buf + buffer_size; + s->buf_ptr = s->buf; + s->bit_left = BUF_BITS; + s->bit_buf = 0; +} + +/** + * Inform the compiler that a PutBitContext is flushed (i.e. if it has just + * been initialized or flushed). Undefined behaviour occurs if this is used + * with a PutBitContext for which this is not true. + */ +static inline void put_bits_assume_flushed(const PutBitContext *s) +{ + av_assume(s->bit_left == BUF_BITS); +} + +/** + * @return the total number of bits written to the bitstream. + */ +static inline int put_bits_count(PutBitContext *s) +{ + return (s->buf_ptr - s->buf) * 8 + BUF_BITS - s->bit_left; +} + +/** + * @return the number of bytes output so far; may only be called + * when the PutBitContext is freshly initialized or flushed. + */ +static inline int put_bytes_output(const PutBitContext *s) +{ + av_assert2(s->bit_left == BUF_BITS); + return s->buf_ptr - s->buf; +} + +/** + * @param round_up When set, the number of bits written so far will be + * rounded up to the next byte. + * @return the number of bytes output so far. + */ +static inline int put_bytes_count(const PutBitContext *s, int round_up) +{ + return s->buf_ptr - s->buf + ((BUF_BITS - s->bit_left + (round_up ? 7 : 0)) >> 3); +} + +/** + * Rebase the bit writer onto a reallocated buffer. + * + * @param buffer the buffer where to put bits + * @param buffer_size the size in bytes of buffer, + * must be large enough to hold everything written so far + */ +static inline void rebase_put_bits(PutBitContext *s, uint8_t *buffer, + int buffer_size) +{ + av_assert0(8*buffer_size >= put_bits_count(s)); + + s->buf_end = buffer + buffer_size; + s->buf_ptr = buffer + (s->buf_ptr - s->buf); + s->buf = buffer; +} + +/** + * @return the number of bits available in the bitstream. + */ +static inline int put_bits_left(PutBitContext* s) +{ + return (s->buf_end - s->buf_ptr) * 8 - BUF_BITS + s->bit_left; +} + +/** + * @param round_up When set, the number of bits written will be + * rounded up to the next byte. + * @return the number of bytes left. + */ +static inline int put_bytes_left(const PutBitContext *s, int round_up) +{ + return s->buf_end - s->buf_ptr - ((BUF_BITS - s->bit_left + (round_up ? 7 : 0)) >> 3); +} + +/** + * Pad the end of the output stream with zeros. + */ +static inline void flush_put_bits(PutBitContext *s) +{ +#ifndef BITSTREAM_WRITER_LE + if (s->bit_left < BUF_BITS) + s->bit_buf <<= s->bit_left; +#endif + while (s->bit_left < BUF_BITS) { + av_assert0(s->buf_ptr < s->buf_end); +#ifdef BITSTREAM_WRITER_LE + *s->buf_ptr++ = s->bit_buf; + s->bit_buf >>= 8; +#else + *s->buf_ptr++ = s->bit_buf >> (BUF_BITS - 8); + s->bit_buf <<= 8; +#endif + s->bit_left += 8; + } + s->bit_left = BUF_BITS; + s->bit_buf = 0; +} + +static inline void flush_put_bits_le(PutBitContext *s) +{ + while (s->bit_left < BUF_BITS) { + av_assert0(s->buf_ptr < s->buf_end); + *s->buf_ptr++ = s->bit_buf; + s->bit_buf >>= 8; + s->bit_left += 8; + } + s->bit_left = BUF_BITS; + s->bit_buf = 0; +} + +#ifdef BITSTREAM_WRITER_LE +#define ff_put_string ff_put_string_unsupported_here +#define ff_copy_bits ff_copy_bits_unsupported_here +#else + +/** + * Put the string string in the bitstream. + * + * @param terminate_string 0-terminates the written string if value is 1 + */ +void ff_put_string(PutBitContext *pb, const char *string, + int terminate_string); + +/** + * Copy the content of src to the bitstream. + * + * @param length the number of bits of src to copy + */ +void ff_copy_bits(PutBitContext *pb, const uint8_t *src, int length); +#endif + +static inline void put_bits_no_assert(PutBitContext *s, int n, BitBuf value) +{ + BitBuf bit_buf; + int bit_left; + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + /* XXX: optimize */ +#ifdef BITSTREAM_WRITER_LE + bit_buf |= value << (BUF_BITS - bit_left); + if (n >= bit_left) { + if (s->buf_end - s->buf_ptr >= sizeof(BitBuf)) { + AV_WLBUF(s->buf_ptr, bit_buf); + s->buf_ptr += sizeof(BitBuf); + } else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_buf = value >> bit_left; + bit_left += BUF_BITS; + } + bit_left -= n; +#else + if (n < bit_left) { + bit_buf = (bit_buf << n) | value; + bit_left -= n; + } else { + bit_buf <<= bit_left; + bit_buf |= value >> (n - bit_left); + if (s->buf_end - s->buf_ptr >= sizeof(BitBuf)) { + AV_WBBUF(s->buf_ptr, bit_buf); + s->buf_ptr += sizeof(BitBuf); + } else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_left += BUF_BITS - n; + bit_buf = value; + } +#endif + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +/** + * Write up to 31 bits into a bitstream. + * Use put_bits32 to write 32 bits. + */ +static inline void put_bits(PutBitContext *s, int n, BitBuf value) +{ + av_assert2(n <= 31 && value < (BitBuf)(1U << n)); + put_bits_no_assert(s, n, value); +} + +static inline void put_bits_le(PutBitContext *s, int n, BitBuf value) +{ + BitBuf bit_buf; + int bit_left; + + av_assert2(n <= 31 && value < (BitBuf)(1U << n)); + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + bit_buf |= value << (BUF_BITS - bit_left); + if (n >= bit_left) { + if (s->buf_end - s->buf_ptr >= sizeof(BitBuf)) { + AV_WLBUF(s->buf_ptr, bit_buf); + s->buf_ptr += sizeof(BitBuf); + } else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_buf = value >> bit_left; + bit_left += BUF_BITS; + } + bit_left -= n; + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +static inline void put_sbits(PutBitContext *pb, int n, int32_t value) +{ + av_assert2(n >= 0 && n <= 31); + + put_bits(pb, n, av_zero_extend(value, n)); +} + +/** + * Write exactly 32 bits into a bitstream. + */ +av_unused static void put_bits32(PutBitContext *s, uint32_t value) +{ + BitBuf bit_buf; + int bit_left; + + if (BUF_BITS > 32) { + put_bits_no_assert(s, 32, value); + return; + } + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + +#ifdef BITSTREAM_WRITER_LE + bit_buf |= (BitBuf)value << (BUF_BITS - bit_left); + if (s->buf_end - s->buf_ptr >= sizeof(BitBuf)) { + AV_WLBUF(s->buf_ptr, bit_buf); + s->buf_ptr += sizeof(BitBuf); + } else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_buf = (uint64_t)value >> bit_left; +#else + bit_buf = (uint64_t)bit_buf << bit_left; + bit_buf |= (BitBuf)value >> (BUF_BITS - bit_left); + if (s->buf_end - s->buf_ptr >= sizeof(BitBuf)) { + AV_WBBUF(s->buf_ptr, bit_buf); + s->buf_ptr += sizeof(BitBuf); + } else { + av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n"); + av_assert2(0); + } + bit_buf = value; +#endif + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +/** + * Write up to 63 bits into a bitstream. + */ +static inline void put_bits63(PutBitContext *s, int n, uint64_t value) +{ + av_assert2(n < 64U && value < (UINT64_C(1) << n)); + +#if BUF_BITS >= 64 + put_bits_no_assert(s, n, value); +#else + if (n < 32) + put_bits(s, n, value); + else if (n == 32) + put_bits32(s, value); + else if (n < 64) { + uint32_t lo = value & 0xffffffff; + uint32_t hi = value >> 32; +#ifdef BITSTREAM_WRITER_LE + put_bits32(s, lo); + put_bits(s, n - 32, hi); +#else + put_bits(s, n - 32, hi); + put_bits32(s, lo); +#endif + } +#endif +} + +/** + * Write up to 64 bits into a bitstream. + */ +static inline void put_bits64(PutBitContext *s, int n, uint64_t value) +{ + av_assert2((n == 64) || (n < 64 && value < (UINT64_C(1) << n))); + + if (n < 64) { + put_bits63(s, n, value); + } else { + uint32_t lo = value & 0xffffffff; + uint32_t hi = value >> 32; +#ifdef BITSTREAM_WRITER_LE + put_bits32(s, lo); + put_bits32(s, hi); +#else + put_bits32(s, hi); + put_bits32(s, lo); +#endif + } +} + +static inline void put_sbits63(PutBitContext *pb, int n, int64_t value) +{ + av_assert2(n >= 0 && n < 64); + + put_bits63(pb, n, (uint64_t)(value) & (~(UINT64_MAX << n))); +} + +/** + * Return the pointer to the byte where the bitstream writer will put + * the next bit. + */ +static inline uint8_t *put_bits_ptr(PutBitContext *s) +{ + return s->buf_ptr; +} + +/** + * Skip the given number of bytes. + * PutBitContext must be flushed & aligned to a byte boundary before calling this. + */ +static inline void skip_put_bytes(PutBitContext *s, int n) +{ + av_assert2((put_bits_count(s) & 7) == 0); + av_assert2(s->bit_left == BUF_BITS); + av_assert0(n <= s->buf_end - s->buf_ptr); + s->buf_ptr += n; +} + +/** + * Skip the given number of bits. + * Must only be used if the actual values in the bitstream do not matter. + * If n is < 0 the behavior is undefined. + */ +static inline void skip_put_bits(PutBitContext *s, int n) +{ + unsigned bits = BUF_BITS - s->bit_left + n; + s->buf_ptr += sizeof(BitBuf) * (bits / BUF_BITS); + s->bit_left = BUF_BITS - (bits & (BUF_BITS - 1)); +} + +/** + * Change the end of the buffer. + * + * @param size the new size in bytes of the buffer where to put bits + */ +static inline void set_put_bits_buffer_size(PutBitContext *s, int size) +{ + av_assert0(size <= INT_MAX/8 - BUF_BITS); + s->buf_end = s->buf + size; +} + +/** + * Pad the bitstream with zeros up to the next byte boundary. + */ +static inline void align_put_bits(PutBitContext *s) +{ + put_bits(s, s->bit_left & 7, 0); +} + +#undef AV_WBBUF +#undef AV_WLBUF + +#endif /* AVCODEC_PUT_BITS_H */ diff --git a/libs/ffmpeg/libavcodec/vlc.h b/libs/ffmpeg/libavcodec/vlc.h new file mode 100644 index 00000000000..7eecd9651fc --- /dev/null +++ b/libs/ffmpeg/libavcodec/vlc.h @@ -0,0 +1,298 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VLC_H +#define AVCODEC_VLC_H + +#include <stddef.h> +#include <stdint.h> + +#include "libavutil/macros.h" + +#define VLC_MULTI_MAX_SYMBOLS 6 + +// When changing this, be sure to also update tableprint_vlc.h accordingly. +typedef int16_t VLCBaseType; + +typedef struct VLCElem { + union { + /// The struct is for use as ordinary VLC (with get_vlc2()) + struct { + VLCBaseType sym; + VLCBaseType len; + }; + /// This struct is for use as run-length VLC (with GET_RL_VLC) + struct { + int16_t level; + int8_t len8; + uint8_t run; + }; + }; +} VLCElem; + +typedef VLCElem RL_VLC_ELEM; + +typedef struct VLC { + int bits; + VLCElem *table; + int table_size, table_allocated; +} VLC; + +typedef struct VLC_MULTI_ELEM { + union { + uint8_t val8[VLC_MULTI_MAX_SYMBOLS]; + uint16_t val16[VLC_MULTI_MAX_SYMBOLS / 2]; + }; + int8_t len; // -31,32 + uint8_t num; +} VLC_MULTI_ELEM; + +typedef struct VLC_MULTI { + VLC_MULTI_ELEM *table; + int table_size, table_allocated; +} VLC_MULTI; + +#define vlc_init(vlc, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + flags) \ + ff_vlc_init_sparse(vlc, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + NULL, 0, 0, flags) + +/** + * Build VLC decoding tables suitable for use with get_vlc2(). + * + * @param[in,out] vlc The VLC to be initialized; table and table_allocated + * must have been set when initializing a static VLC, + * otherwise this will be treated as uninitialized. + * @param[in] nb_bits The number of bits to use for the VLC table; + * higher values take up more memory and cache, but + * allow to read codes with fewer reads. + * Corresponds to the `bits` parameter of get_vlc2(). + * @param[in] nb_codes The number of provided bits, codes and (if supplied) + * symbol entries. + * @param[in] bits The lengths (in bits) of the codes. Entries > 0 + * correspond to valid codes; entries == 0 will be skipped. + * @param[in] bits_wrap Stride (in bytes) of the bits table. + * @param[in] codes_size Size of the bits. 1, 2 and 4 are supported. + * @param[in] codes Table which gives the bit pattern of of each vlc code. + * @param[in] codes_wrap Stride (in bytes) of the codes table. + * @param[in] codes_size Size of the codes. 1, 2 and 4 are supported. + * @param[in] symbols The symbols, i.e. what is returned from get_vlc2() + * when the corresponding code is encountered. + * May be NULL, then 0, 1, 2, 3, 4,... will be used. + * @param[in] symbols_wrap Stride (in bytes) of the symbols table. + * @param[in] symbols_size Size of the symbols. 1 and 2 are supported. + * @param[in] flags A combination of the VLC_INIT_* flags. + * + * 'wrap' and 'size' make it possible to use any memory configuration and types + * (byte/word/int) to store the 'bits', 'codes', and 'symbols' tables. + */ +int ff_vlc_init_sparse(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + const void *symbols, int symbols_wrap, int symbols_size, + int flags); + +/** + * Build VLC decoding tables suitable for use with get_vlc2() + * + * This function takes lengths and symbols and calculates the codes from them. + * For this the input lengths and symbols have to be sorted according to "left + * nodes in the corresponding tree first". + * + * @param[in,out] vlc The VLC to be initialized; table and table_allocated + * must have been set when initializing a static VLC, + * otherwise this will be treated as uninitialized. + * @param[in] nb_bits The number of bits to use for the VLC table; + * higher values take up more memory and cache, but + * allow to read codes with fewer reads. + * @param[in] nb_codes The number of provided length and (if supplied) symbol + * entries. + * @param[in] lens The lengths of the codes. Entries > 0 correspond to + * valid codes; entries == 0 will be skipped and entries + * with len < 0 indicate that the tree is incomplete and + * has an open end of length -len at this position. + * @param[in] lens_wrap Stride (in bytes) of the lengths. + * @param[in] symbols The symbols, i.e. what is returned from get_vlc2() + * when the corresponding code is encountered. + * May be NULL, then 0, 1, 2, 3, 4,... will be used. + * @param[in] symbols_wrap Stride (in bytes) of the symbols. + * @param[in] symbols_size Size of the symbols. 1 and 2 are supported. + * @param[in] offset An offset to apply to all the valid symbols. + * @param[in] flags A combination of the VLC_INIT_* flags; notice that + * VLC_INIT_INPUT_LE is pointless and ignored. + */ +int ff_vlc_init_from_lengths(VLC *vlc, int nb_bits, int nb_codes, + const int8_t *lens, int lens_wrap, + const void *symbols, int symbols_wrap, int symbols_size, + int offset, int flags, void *logctx); + +/** + * Build VLC decoding tables suitable for use with get_vlc_multi() + * + * This function takes lengths and symbols and calculates the codes from them. + * For this the input lengths and symbols have to be sorted according to "left + * nodes in the corresponding tree first". + * + * @param[in,out] vlc The VLC to be initialized; table and table_allocated + * must have been set when initializing a static VLC, + * otherwise this will be treated as uninitialized. + * @param[in,out] multi The VLC_MULTI to be initialized; table and table_allocated + * must have been set when initializing a static VLC, + * otherwise this will be treated as uninitialized. + * @param[in] nb_bits The number of bits to use for the VLC table; + * higher values take up more memory and cache, but + * allow to read codes with fewer reads. + * @param[in] nb_elems The max possible number of elements. + * @param[in] nb_codes The number of provided length and (if supplied) symbol + * entries. + * @param[in] lens The lengths of the codes. Entries > 0 correspond to + * valid codes; entries == 0 will be skipped and entries + * with len < 0 indicate that the tree is incomplete and + * has an open end of length -len at this position. + * @param[in] lens_wrap Stride (in bytes) of the lengths. + * @param[in] symbols The symbols, i.e. what is returned from get_vlc2() + * when the corresponding code is encountered. + * May be NULL, then 0, 1, 2, 3, 4,... will be used. + * @param[in] symbols_wrap Stride (in bytes) of the symbols. + * @param[in] symbols_size Size of the symbols. 1 and 2 are supported. + * @param[in] offset An offset to apply to all the valid symbols. + * @param[in] flags A combination of the VLC_INIT_* flags; notice that + * VLC_INIT_INPUT_LE is pointless and ignored. + */ +int ff_vlc_init_multi_from_lengths(VLC *vlc, VLC_MULTI *multi, int nb_bits, int nb_elems, + int nb_codes, const int8_t *lens, int lens_wrap, + const void *symbols, int symbols_wrap, int symbols_size, + int offset, int flags, void *logctx); + + +void ff_vlc_free_multi(VLC_MULTI *vlc); +void ff_vlc_free(VLC *vlc); + +#define VLC_INIT_USE_STATIC 1 +#define VLC_INIT_STATIC_OVERLONG (2 | VLC_INIT_USE_STATIC) +/* If VLC_INIT_INPUT_LE is set, the LSB bit of the codes used to + * initialize the VLC table is the first bit to be read. */ +#define VLC_INIT_INPUT_LE 4 +/* If set the VLC is intended for a little endian bitstream reader. */ +#define VLC_INIT_OUTPUT_LE 8 +#define VLC_INIT_LE (VLC_INIT_INPUT_LE | VLC_INIT_OUTPUT_LE) + +/** + * For static VLCs, the number of bits can often be hardcoded + * at each get_vlc2() callsite. Then using a full VLC would be uneconomical, + * because only VLC.table would ever be accessed after initialization. + * The following functions provide wrappers around the relevant ff_vlc_init_* + * functions suitable for said task. + * + * The ff_vlc_init_tables_* functions are intended to be used for initializing + * a series of VLCs. The user initializes a VLCInitState with the details + * about the underlying array of VLCElem; it is automatically updated by + * the ff_vlc_init_tables_* functions (i.e. table is incremented and size + * decremented by the number of elements of the current table). + * The VLC_INIT_STATIC_OVERLONG flag is also automatically added. + * These functions return a pointer to the table just initialized, + * potentially to be used in arrays of pointer to VLC tables. + * + * The ff_vlc_init_table_* functions are intended to be used for initializing + * a single VLC table, given by table and table_size. The VLC_INIT_USE_STATIC + * flag is automatically added. + */ + +typedef struct VLCInitState { + VLCElem *table; ///< points to where the next VLC table will be placed + unsigned size; ///< remaining number of elements in table +} VLCInitState; + +#define VLC_INIT_STATE(_table) { .table = (_table), .size = FF_ARRAY_ELEMS(_table) } + +void ff_vlc_init_table_from_lengths(VLCElem table[], int table_size, + int nb_bits, int nb_codes, + const int8_t *lens, int lens_wrap, + const void *symbols, int symbols_wrap, int symbols_size, + int offset, int flags); + +const VLCElem *ff_vlc_init_tables_from_lengths(VLCInitState *state, + int nb_bits, int nb_codes, + const int8_t *lens, int lens_wrap, + const void *symbols, int symbols_wrap, int symbols_size, + int offset, int flags); + +void ff_vlc_init_table_sparse(VLCElem table[], int table_size, + int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + const void *symbols, int symbols_wrap, int symbols_size, + int flags); + +const VLCElem *ff_vlc_init_tables_sparse(VLCInitState *state, + int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + const void *symbols, int symbols_wrap, int symbols_size, + int flags); + +static inline +const VLCElem *ff_vlc_init_tables(VLCInitState *state, + int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + int flags) +{ + return ff_vlc_init_tables_sparse(state, nb_bits, nb_codes, + bits, bits_wrap, bits_size, + codes, codes_wrap, codes_size, + NULL, 0, 0, flags); +} + +#define VLC_INIT_STATIC_SPARSE_TABLE(vlc_table, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + symbols, symbols_wrap, symbols_size, \ + flags) \ + ff_vlc_init_table_sparse(vlc_table, FF_ARRAY_ELEMS(vlc_table), \ + (nb_bits), (nb_codes), \ + (bits), (bits_wrap), (bits_size), \ + (codes), (codes_wrap), (codes_size), \ + (symbols), (symbols_wrap), (symbols_size), \ + (flags)) + +#define VLC_INIT_STATIC_TABLE(vlc_table, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + flags) \ + ff_vlc_init_table_sparse(vlc_table, FF_ARRAY_ELEMS(vlc_table), \ + (nb_bits), (nb_codes), \ + (bits), (bits_wrap), (bits_size), \ + (codes), (codes_wrap), (codes_size), \ + NULL, 0, 0, (flags)) + +#define VLC_INIT_STATIC_TABLE_FROM_LENGTHS(vlc_table, nb_bits, nb_codes, \ + lens, lens_wrap, \ + syms, syms_wrap, syms_size, \ + offset, flags) \ + ff_vlc_init_table_from_lengths(vlc_table, FF_ARRAY_ELEMS(vlc_table), \ + (nb_bits), (nb_codes), \ + (lens), (lens_wrap), \ + (syms), (syms_wrap), (syms_size), \ + (offset), (flags)) + +#endif /* AVCODEC_VLC_H */ diff --git a/libs/ffmpeg/libavutil/aarch64/cpu.h b/libs/ffmpeg/libavutil/aarch64/cpu.h new file mode 100644 index 00000000000..f1dff3f647d --- /dev/null +++ b/libs/ffmpeg/libavutil/aarch64/cpu.h @@ -0,0 +1,45 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AARCH64_CPU_H +#define AVUTIL_AARCH64_CPU_H + +#include "libavutil/cpu.h" +#include "libavutil/cpu_internal.h" + +#define have_armv8(flags) CPUEXT(flags, ARMV8) +#define have_neon(flags) CPUEXT(flags, NEON) +#define have_vfp(flags) CPUEXT(flags, VFP) +#define have_arm_crc(flags) CPUEXT(flags, ARM_CRC) +#define have_dotprod(flags) CPUEXT(flags, DOTPROD) +#define have_i8mm(flags) CPUEXT(flags, I8MM) +#define have_sve(flags) CPUEXT(flags, SVE) +#define have_sve2(flags) CPUEXT(flags, SVE2) +#define have_sme(flags) CPUEXT(flags, SME) +#define have_sme_i16i64(flags) CPUEXT(flags, SME_I16I64) +#define have_sme2(flags) CPUEXT(flags, SME2) + +#if HAVE_SVE +int ff_aarch64_sve_length(void); +#endif + +#if HAVE_SME +int ff_aarch64_sme_length(void); +#endif + +#endif /* AVUTIL_AARCH64_CPU_H */ diff --git a/libs/ffmpeg/libavutil/aarch64/crc.h b/libs/ffmpeg/libavutil/aarch64/crc.h new file mode 100644 index 00000000000..08efdd28f3e --- /dev/null +++ b/libs/ffmpeg/libavutil/aarch64/crc.h @@ -0,0 +1,68 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AARCH64_CRC_H +#define AVUTIL_AARCH64_CRC_H + +#include <stddef.h> +#include <stdint.h> + +#include "config.h" + +#include "cpu.h" +#include "libavutil/attributes_internal.h" +#include "libavutil/avassert.h" +#include "libavutil/cpu.h" +#include "libavutil/crc.h" + +FF_VISIBILITY_PUSH_HIDDEN +uint32_t ff_crc32_aarch64(const AVCRC *ctx, uint32_t crc, const uint8_t *buffer, + size_t length); +FF_VISIBILITY_POP_HIDDEN + +static inline uint32_t ff_crc_aarch64(const AVCRC *ctx, uint32_t crc, + const uint8_t *buffer, size_t length) +{ +#if HAVE_ARM_CRC + av_assert2(ctx[0] == AV_CRC_32_IEEE_LE + 1); + return ff_crc32_aarch64(ctx, crc, buffer, length); +#else + av_unreachable("AARCH64 has only AV_CRC_32_IEEE_LE arch-specific CRC code"); + return 0; +#endif +} + +static inline const AVCRC *ff_crc_get_table_aarch64(AVCRCId crc_id) +{ +#if HAVE_ARM_CRC + static const AVCRC crc32_ieee_le_ctx[] = { + AV_CRC_32_IEEE_LE + 1 + }; + + if (crc_id != AV_CRC_32_IEEE_LE) + return NULL; + + int cpu_flags = av_get_cpu_flags(); + if (have_arm_crc(cpu_flags)) { + return crc32_ieee_le_ctx; + } +#endif + return NULL; +} + +#endif /* AVUTIL_AARCH64_CRC_H */ diff --git a/libs/ffmpeg/libavutil/aarch64/intreadwrite.h b/libs/ffmpeg/libavutil/aarch64/intreadwrite.h new file mode 100644 index 00000000000..4ce2d649876 --- /dev/null +++ b/libs/ffmpeg/libavutil/aarch64/intreadwrite.h @@ -0,0 +1,42 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AARCH64_INTREADWRITE_H +#define AVUTIL_AARCH64_INTREADWRITE_H + +#if HAVE_INTRINSICS_NEON + +#include <arm_neon.h> + +#define AV_COPY128 AV_COPY128 +static av_always_inline void AV_COPY128(void *d, const void *s) +{ + uint8x16_t tmp = vld1q_u8((const uint8_t *)s); + vst1q_u8((uint8_t *)d, tmp); +} + +#define AV_ZERO128 AV_ZERO128 +static av_always_inline void AV_ZERO128(void *d) +{ + uint8x16_t zero = vdupq_n_u8(0); + vst1q_u8((uint8_t *)d, zero); +} + +#endif /* HAVE_INTRINSICS_NEON */ + +#endif /* AVUTIL_AARCH64_INTREADWRITE_H */ diff --git a/libs/ffmpeg/libavutil/aarch64/timer.h b/libs/ffmpeg/libavutil/aarch64/timer.h new file mode 100644 index 00000000000..922b0c5598a --- /dev/null +++ b/libs/ffmpeg/libavutil/aarch64/timer.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015 Janne Grunau <janne-libav@jannau.net> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AARCH64_TIMER_H +#define AVUTIL_AARCH64_TIMER_H + +#include <stdint.h> +#include "config.h" + +#if HAVE_INLINE_ASM + +#define AV_READ_TIME read_time + +static inline uint64_t read_time(void) +{ + uint64_t cycle_counter; + __asm__ volatile( + "isb \t\n" +#if defined(__ANDROID__) || defined(__APPLE__) + // cntvct_el0 has lower resolution than pmccntr_el0, but is usually + // accessible from user space by default. + "mrs %0, cntvct_el0 " +#else + // pmccntr_el0 has higher resolution, but is usually not accessible + // from user space by default (but access can be enabled with a custom + // kernel module). + "mrs %0, pmccntr_el0 " +#endif + : "=r"(cycle_counter) :: "memory" ); + + return cycle_counter; +} + +#endif /* HAVE_INLINE_ASM */ + +#endif /* AVUTIL_AARCH64_TIMER_H */ diff --git a/libs/ffmpeg/libavutil/adler32.c b/libs/ffmpeg/libavutil/adler32.c new file mode 100644 index 00000000000..7124f188029 --- /dev/null +++ b/libs/ffmpeg/libavutil/adler32.c @@ -0,0 +1,96 @@ +/* + * Compute the Adler-32 checksum of a data stream. + * This is a modified version based on adler32.c from the zlib library. + * + * Copyright (C) 1995 Mark Adler + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +/** + * @file + * Computes the Adler-32 checksum of a data stream + * + * This is a modified version based on adler32.c from the zlib library. + * @author Mark Adler + * @ingroup lavu_adler32 + */ + +#include "config.h" +#include "adler32.h" +#include "intreadwrite.h" +#include "macros.h" + +#define BASE 65521L /* largest prime smaller than 65536 */ + +#define DO1(buf) { s1 += *buf++; s2 += s1; } +#define DO4(buf) DO1(buf); DO1(buf); DO1(buf); DO1(buf); +#define DO16(buf) DO4(buf); DO4(buf); DO4(buf); DO4(buf); + +AVAdler av_adler32_update(AVAdler adler, const uint8_t *buf, size_t len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = adler >> 16; + + while (len > 0) { +#if HAVE_FAST_64BIT && HAVE_FAST_UNALIGNED && !CONFIG_SMALL + unsigned len2 = FFMIN((len-1) & ~7, 23*8); + if (len2) { + uint64_t a1= 0; + uint64_t a2= 0; + uint64_t b1= 0; + uint64_t b2= 0; + len -= len2; + s2 += s1*len2; + while (len2 >= 8) { + uint64_t v = AV_RN64(buf); + a2 += a1; + b2 += b1; + a1 += v &0x00FF00FF00FF00FF; + b1 += (v>>8)&0x00FF00FF00FF00FF; + len2 -= 8; + buf+=8; + } + + //We combine the 8 interleaved adler32 checksums without overflows + //Decreasing the number of iterations would allow below code to be + //simplified but would likely be slower due to the fewer iterations + //of the inner loop + s1 += ((a1+b1)*0x1000100010001)>>48; + s2 += ((((a2&0xFFFF0000FFFF)+(b2&0xFFFF0000FFFF)+((a2>>16)&0xFFFF0000FFFF)+((b2>>16)&0xFFFF0000FFFF))*0x800000008)>>32) +#if HAVE_BIGENDIAN + + 2*((b1*0x1000200030004)>>48) + + ((a1*0x1000100010001)>>48) + + 2*((a1*0x0000100020003)>>48); +#else + + 2*((a1*0x4000300020001)>>48) + + ((b1*0x1000100010001)>>48) + + 2*((b1*0x3000200010000)>>48); +#endif + } +#else + while (len > 4 && s2 < (1U << 31)) { + DO4(buf); + len -= 4; + } +#endif + DO1(buf); len--; + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} diff --git a/libs/ffmpeg/libavutil/adler32.h b/libs/ffmpeg/libavutil/adler32.h new file mode 100644 index 00000000000..232d07f5fe8 --- /dev/null +++ b/libs/ffmpeg/libavutil/adler32.h @@ -0,0 +1,63 @@ +/* + * copyright (c) 2006 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_adler32 + * Public header for Adler-32 hash function implementation. + */ + +#ifndef AVUTIL_ADLER32_H +#define AVUTIL_ADLER32_H + +#include <stddef.h> +#include <stdint.h> +#include "attributes.h" + +/** + * @defgroup lavu_adler32 Adler-32 + * @ingroup lavu_hash + * Adler-32 hash function implementation. + * + * @{ + */ + +typedef uint32_t AVAdler; + +/** + * Calculate the Adler32 checksum of a buffer. + * + * Passing the return value to a subsequent av_adler32_update() call + * allows the checksum of multiple buffers to be calculated as though + * they were concatenated. + * + * @param adler initial checksum value + * @param buf pointer to input buffer + * @param len size of input buffer + * @return updated checksum + */ +AVAdler av_adler32_update(AVAdler adler, const uint8_t *buf, + size_t len) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_ADLER32_H */ diff --git a/libs/ffmpeg/libavutil/aes.c b/libs/ffmpeg/libavutil/aes.c new file mode 100644 index 00000000000..de7144fab8b --- /dev/null +++ b/libs/ffmpeg/libavutil/aes.c @@ -0,0 +1,283 @@ +/* + * copyright (c) 2007 Michael Niedermayer <michaelni@gmx.at> + * + * some optimization ideas from aes128.c by Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> + +#include "config.h" +#include "aes.h" +#include "aes_internal.h" +#include "attributes.h" +#include "error.h" +#include "intreadwrite.h" +#include "macros.h" +#include "mem.h" +#include "thread.h" + +const int av_aes_size= sizeof(AVAES); + +struct AVAES *av_aes_alloc(void) +{ + return av_mallocz(sizeof(struct AVAES)); +} + +static const uint8_t rcon[10] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 +}; + +static uint8_t sbox[256]; +static uint8_t inv_sbox[256]; +#if CONFIG_SMALL +static uint32_t enc_multbl[1][256]; +static uint32_t dec_multbl[1][256]; +#else +static uint32_t enc_multbl[4][256]; +static uint32_t dec_multbl[4][256]; +#endif + +#if HAVE_BIGENDIAN +# define ROT(x, s) (((x) >> (s)) | ((x) << (32-(s)))) +#else +# define ROT(x, s) (((x) << (s)) | ((x) >> (32-(s)))) +#endif + +static inline void addkey(av_aes_block *dst, const av_aes_block *src, + const av_aes_block *round_key) +{ + dst->u64[0] = src->u64[0] ^ round_key->u64[0]; + dst->u64[1] = src->u64[1] ^ round_key->u64[1]; +} + +static inline void addkey_s(av_aes_block *dst, const uint8_t *src, + const av_aes_block *round_key) +{ + dst->u64[0] = AV_RN64(src) ^ round_key->u64[0]; + dst->u64[1] = AV_RN64(src + 8) ^ round_key->u64[1]; +} + +static inline void addkey_d(uint8_t *dst, const av_aes_block *src, + const av_aes_block *round_key) +{ + AV_WN64(dst, src->u64[0] ^ round_key->u64[0]); + AV_WN64(dst + 8, src->u64[1] ^ round_key->u64[1]); +} + +static void subshift(av_aes_block s0[2], int s, const uint8_t *box) +{ + unsigned char *s1_dst = (unsigned char*)s0[0].u8 + 3 - s; + const unsigned char *s1_src = s1_dst + sizeof(*s0); + unsigned char *s3_dst = (unsigned char*)s0[0].u8 + s + 1; + const unsigned char *s3_src = s3_dst + sizeof(*s0); + + s0[0].u8[ 0] = box[s0[1].u8[ 0]]; + s0[0].u8[ 4] = box[s0[1].u8[ 4]]; + s0[0].u8[ 8] = box[s0[1].u8[ 8]]; + s0[0].u8[12] = box[s0[1].u8[12]]; + s1_dst[ 0] = box[s1_src[ 4]]; + s1_dst[ 4] = box[s1_src[ 8]]; + s1_dst[ 8] = box[s1_src[12]]; + s1_dst[12] = box[s1_src[ 0]]; + s0[0].u8[ 2] = box[s0[1].u8[10]]; + s0[0].u8[10] = box[s0[1].u8[ 2]]; + s0[0].u8[ 6] = box[s0[1].u8[14]]; + s0[0].u8[14] = box[s0[1].u8[ 6]]; + s3_dst[ 0] = box[s3_src[12]]; + s3_dst[12] = box[s3_src[ 8]]; + s3_dst[ 8] = box[s3_src[ 4]]; + s3_dst[ 4] = box[s3_src[ 0]]; +} + +static inline int mix_core(uint32_t multbl[][256], int a, int b, int c, int d) +{ +#if CONFIG_SMALL + return multbl[0][a] ^ ROT(multbl[0][b], 8) ^ ROT(multbl[0][c], 16) ^ ROT(multbl[0][d], 24); +#else + return multbl[0][a] ^ multbl[1][b] ^ multbl[2][c] ^ multbl[3][d]; +#endif +} + +static inline void mix(av_aes_block state[2], uint32_t multbl[][256], int s1, int s3) +{ + uint8_t (*src)[4] = state[1].u8x4; + state[0].u32[0] = mix_core(multbl, src[0][0], src[s1 ][1], src[2][2], src[s3 ][3]); + state[0].u32[1] = mix_core(multbl, src[1][0], src[s3 - 1][1], src[3][2], src[s1 - 1][3]); + state[0].u32[2] = mix_core(multbl, src[2][0], src[s3 ][1], src[0][2], src[s1 ][3]); + state[0].u32[3] = mix_core(multbl, src[3][0], src[s1 - 1][1], src[1][2], src[s3 - 1][3]); +} + +static inline void aes_crypt(AVAES *a, int s, const uint8_t *sbox, + uint32_t multbl[][256]) +{ + int r; + + for (r = a->rounds - 1; r > 0; r--) { + mix(a->state, multbl, 3 - s, 1 + s); + addkey(&a->state[1], &a->state[0], &a->round_key[r]); + } + + subshift(&a->state[0], s, sbox); +} + +static void aes_encrypt(AVAES *a, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int rounds) +{ + while (count--) { + addkey_s(&a->state[1], src, &a->round_key[rounds]); + if (iv) + addkey_s(&a->state[1], iv, &a->state[1]); + aes_crypt(a, 2, sbox, enc_multbl); + addkey_d(dst, &a->state[0], &a->round_key[0]); + if (iv) + memcpy(iv, dst, 16); + src += 16; + dst += 16; + } +} + +static void aes_decrypt(AVAES *a, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int rounds) +{ + while (count--) { + addkey_s(&a->state[1], src, &a->round_key[rounds]); + aes_crypt(a, 0, inv_sbox, dec_multbl); + if (iv) { + addkey_s(&a->state[0], iv, &a->state[0]); + memcpy(iv, src, 16); + } + addkey_d(dst, &a->state[0], &a->round_key[0]); + src += 16; + dst += 16; + } +} + +void av_aes_crypt(AVAES *a, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt) +{ + a->crypt(a, dst, src, count, iv, a->rounds); +} + +static void init_multbl2(uint32_t tbl[][256], const int c[4], + const uint8_t *log8, const uint8_t *alog8, + const uint8_t *sbox) +{ + int i; + + for (i = 0; i < 256; i++) { + int x = sbox[i]; + if (x) { + int k, l, m, n; + x = log8[x]; + k = alog8[x + log8[c[0]]]; + l = alog8[x + log8[c[1]]]; + m = alog8[x + log8[c[2]]]; + n = alog8[x + log8[c[3]]]; + tbl[0][i] = AV_NE(MKBETAG(k, l, m, n), MKTAG(k, l, m, n)); +#if !CONFIG_SMALL + tbl[1][i] = ROT(tbl[0][i], 8); + tbl[2][i] = ROT(tbl[0][i], 16); + tbl[3][i] = ROT(tbl[0][i], 24); +#endif + } + } +} + +static AVOnce aes_static_init = AV_ONCE_INIT; + +static av_cold void aes_init_static(void) +{ + uint8_t log8[256]; + uint8_t alog8[512]; + int i, j = 1; + + for (i = 0; i < 255; i++) { + alog8[i] = alog8[i + 255] = j; + log8[j] = i; + j ^= j + j; + if (j > 255) + j ^= 0x11B; + } + for (i = 0; i < 256; i++) { + j = i ? alog8[255 - log8[i]] : 0; + j ^= (j << 1) ^ (j << 2) ^ (j << 3) ^ (j << 4); + j = (j ^ (j >> 8) ^ 99) & 255; + inv_sbox[j] = i; + sbox[i] = j; + } + init_multbl2(dec_multbl, (const int[4]) { 0xe, 0x9, 0xd, 0xb }, + log8, alog8, inv_sbox); + init_multbl2(enc_multbl, (const int[4]) { 0x2, 0x1, 0x1, 0x3 }, + log8, alog8, sbox); +} + +// this is based on the reference AES code by Paulo Barreto and Vincent Rijmen +int av_aes_init(AVAES *a, const uint8_t *key, int key_bits, int decrypt) +{ + int i, j, t, rconpointer = 0; + uint8_t tk[8][4]; + int KC = key_bits >> 5; + int rounds = KC + 6; + + a->rounds = rounds; + a->crypt = decrypt ? aes_decrypt : aes_encrypt; +#if ARCH_X86 && HAVE_X86ASM + ff_init_aes_x86(a, decrypt); +#endif + + ff_thread_once(&aes_static_init, aes_init_static); + + if (key_bits != 128 && key_bits != 192 && key_bits != 256) + return AVERROR(EINVAL); + + memcpy(tk, key, KC * 4); + memcpy(a->round_key[0].u8, key, KC * 4); + + for (t = KC * 4; t < (rounds + 1) * 16; t += KC * 4) { + for (i = 0; i < 4; i++) + tk[0][i] ^= sbox[tk[KC - 1][(i + 1) & 3]]; + tk[0][0] ^= rcon[rconpointer++]; + + for (j = 1; j < KC; j++) { + if (KC != 8 || j != KC >> 1) + for (i = 0; i < 4; i++) + tk[j][i] ^= tk[j - 1][i]; + else + for (i = 0; i < 4; i++) + tk[j][i] ^= sbox[tk[j - 1][i]]; + } + + memcpy((unsigned char*)a->round_key + t, tk, KC * 4); + } + + if (decrypt) { + for (i = 1; i < rounds; i++) { + av_aes_block tmp[3]; + tmp[2] = a->round_key[i]; + subshift(&tmp[1], 0, sbox); + mix(tmp, dec_multbl, 1, 3); + a->round_key[i] = tmp[0]; + } + } else { + for (i = 0; i < (rounds + 1) >> 1; i++) + FFSWAP(av_aes_block, a->round_key[i], a->round_key[rounds - i]); + } + + return 0; +} diff --git a/libs/ffmpeg/libavutil/aes.h b/libs/ffmpeg/libavutil/aes.h new file mode 100644 index 00000000000..4e73473688f --- /dev/null +++ b/libs/ffmpeg/libavutil/aes.h @@ -0,0 +1,69 @@ +/* + * copyright (c) 2007 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AES_H +#define AVUTIL_AES_H + +#include <stdint.h> + +#include "attributes.h" + +/** + * @defgroup lavu_aes AES + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_aes_size; + +struct AVAES; + +/** + * Allocate an AVAES context. + */ +struct AVAES *av_aes_alloc(void); + +/** + * Initialize an AVAES context. + * + * @param a The AVAES context + * @param key Pointer to the key + * @param key_bits 128, 192 or 256 + * @param decrypt 0 for encryption, 1 for decryption + */ +int av_aes_init(struct AVAES *a, const uint8_t *key, int key_bits, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param a The AVAES context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 16 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_aes_crypt(struct AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_AES_H */ diff --git a/libs/ffmpeg/libavutil/aes_ctr.c b/libs/ffmpeg/libavutil/aes_ctr.c new file mode 100644 index 00000000000..f653e54bd19 --- /dev/null +++ b/libs/ffmpeg/libavutil/aes_ctr.c @@ -0,0 +1,135 @@ +/* + * AES-CTR cipher + * Copyright (c) 2015 Eran Kornblau <erankor at gmail dot com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> + +#include "aes_ctr.h" +#include "aes.h" +#include "aes_internal.h" +#include "intreadwrite.h" +#include "macros.h" +#include "mem.h" +#include "random_seed.h" + +#define AES_BLOCK_SIZE (16) + +typedef struct AVAESCTR { + DECLARE_ALIGNED(8, uint8_t, counter)[AES_BLOCK_SIZE]; + DECLARE_ALIGNED(8, uint8_t, encrypted_counter)[AES_BLOCK_SIZE]; + int block_offset; + AVAES aes; +} AVAESCTR; + +struct AVAESCTR *av_aes_ctr_alloc(void) +{ + return av_mallocz(sizeof(struct AVAESCTR)); +} + +void av_aes_ctr_set_iv(struct AVAESCTR *a, const uint8_t* iv) +{ + memcpy(a->counter, iv, AES_CTR_IV_SIZE); + memset(a->counter + AES_CTR_IV_SIZE, 0, sizeof(a->counter) - AES_CTR_IV_SIZE); + a->block_offset = 0; +} + +void av_aes_ctr_set_full_iv(struct AVAESCTR *a, const uint8_t* iv) +{ + memcpy(a->counter, iv, sizeof(a->counter)); + a->block_offset = 0; +} + +const uint8_t* av_aes_ctr_get_iv(struct AVAESCTR *a) +{ + return a->counter; +} + +void av_aes_ctr_set_random_iv(struct AVAESCTR *a) +{ + uint32_t iv[2]; + + iv[0] = av_get_random_seed(); + iv[1] = av_get_random_seed(); + + av_aes_ctr_set_iv(a, (uint8_t*)iv); +} + +int av_aes_ctr_init(struct AVAESCTR *a, const uint8_t *key) +{ + av_aes_init(&a->aes, key, 128, 0); + + memset(a->counter, 0, sizeof(a->counter)); + a->block_offset = 0; + + return 0; +} + +void av_aes_ctr_free(struct AVAESCTR *a) +{ + av_free(a); +} + +static inline void av_aes_ctr_increment_be64(uint8_t* counter) +{ + uint64_t c = AV_RB64A(counter) + 1; + AV_WB64A(counter, c); +} + +void av_aes_ctr_increment_iv(struct AVAESCTR *a) +{ + av_aes_ctr_increment_be64(a->counter); + memset(a->counter + AES_CTR_IV_SIZE, 0, sizeof(a->counter) - AES_CTR_IV_SIZE); + a->block_offset = 0; +} + +void av_aes_ctr_crypt(struct AVAESCTR *a, uint8_t *dst, const uint8_t *src, int count) +{ + if (a->block_offset && count > 0) { + int left = FFMIN(count, AES_BLOCK_SIZE - a->block_offset); + for (int len = 0; len < left; len++) + dst[len] = src[len] ^ a->encrypted_counter[a->block_offset++]; + a->block_offset &= AES_BLOCK_SIZE - 1; + dst += left; + src += left; + count -= left; + } + + while (count >= AES_BLOCK_SIZE) { + av_aes_crypt(&a->aes, a->encrypted_counter, a->counter, 1, NULL, 0); + av_aes_ctr_increment_be64(a->counter + 8); +#if HAVE_FAST_64BIT + for (int len = 0; len < AES_BLOCK_SIZE; len += 8) + AV_WN64(&dst[len], AV_RN64(&src[len]) ^ AV_RN64A(&a->encrypted_counter[len])); +#else + for (int len = 0; len < AES_BLOCK_SIZE; len += 4) + AV_WN32(&dst[len], AV_RN32(&src[len]) ^ AV_RN32A(&a->encrypted_counter[len])); +#endif + dst += AES_BLOCK_SIZE; + src += AES_BLOCK_SIZE; + count -= AES_BLOCK_SIZE; + } + + if (count > 0) { + av_aes_crypt(&a->aes, a->encrypted_counter, a->counter, 1, NULL, 0); + av_aes_ctr_increment_be64(a->counter + 8); + for (int len = 0; len < count; len++) + dst[len] = src[len] ^ a->encrypted_counter[a->block_offset++]; + } +} diff --git a/libs/ffmpeg/libavutil/aes_ctr.h b/libs/ffmpeg/libavutil/aes_ctr.h new file mode 100644 index 00000000000..d98c0712276 --- /dev/null +++ b/libs/ffmpeg/libavutil/aes_ctr.h @@ -0,0 +1,99 @@ +/* + * AES-CTR cipher + * Copyright (c) 2015 Eran Kornblau <erankor at gmail dot com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AES_CTR_H +#define AVUTIL_AES_CTR_H + +/** + * @defgroup lavu_aes_ctr AES-CTR + * @ingroup lavu_crypto + * @{ + */ + +#include <stdint.h> + +#include "attributes.h" + +#define AES_CTR_KEY_SIZE (16) +#define AES_CTR_IV_SIZE (8) + +struct AVAESCTR; + +/** + * Allocate an AVAESCTR context. + */ +struct AVAESCTR *av_aes_ctr_alloc(void); + +/** + * Initialize an AVAESCTR context. + * + * @param a The AVAESCTR context to initialize + * @param key encryption key, must have a length of AES_CTR_KEY_SIZE + */ +int av_aes_ctr_init(struct AVAESCTR *a, const uint8_t *key); + +/** + * Release an AVAESCTR context. + * + * @param a The AVAESCTR context + */ +void av_aes_ctr_free(struct AVAESCTR *a); + +/** + * Process a buffer using a previously initialized context. + * + * @param a The AVAESCTR context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param size the size of src and dst + */ +void av_aes_ctr_crypt(struct AVAESCTR *a, uint8_t *dst, const uint8_t *src, int size); + +/** + * Get the current iv + */ +const uint8_t* av_aes_ctr_get_iv(struct AVAESCTR *a); + +/** + * Generate a random iv + */ +void av_aes_ctr_set_random_iv(struct AVAESCTR *a); + +/** + * Forcefully change the 8-byte iv + */ +void av_aes_ctr_set_iv(struct AVAESCTR *a, const uint8_t* iv); + +/** + * Forcefully change the "full" 16-byte iv, including the counter + */ +void av_aes_ctr_set_full_iv(struct AVAESCTR *a, const uint8_t* iv); + +/** + * Increment the top 64 bit of the iv (performed after each frame) + */ +void av_aes_ctr_increment_iv(struct AVAESCTR *a); + +/** + * @} + */ + +#endif /* AVUTIL_AES_CTR_H */ diff --git a/libs/ffmpeg/libavutil/aes_internal.h b/libs/ffmpeg/libavutil/aes_internal.h new file mode 100644 index 00000000000..17f79d3ce30 --- /dev/null +++ b/libs/ffmpeg/libavutil/aes_internal.h @@ -0,0 +1,45 @@ +/* + * copyright (c) 2015 rcombs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AES_INTERNAL_H +#define AVUTIL_AES_INTERNAL_H + +#include "mem_internal.h" +#include <stdint.h> + +typedef union { + uint64_t u64[2]; + uint32_t u32[4]; + uint8_t u8x4[4][4]; + uint8_t u8[16]; +} av_aes_block; + +typedef struct AVAES { + // Note: round_key[16] is accessed in the init code, but this only + // overwrites state, which does not matter (see also commit ba554c0). + DECLARE_ALIGNED(16, av_aes_block, round_key)[15]; + DECLARE_ALIGNED(16, av_aes_block, state)[2]; + int rounds; + void (*crypt)(struct AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int rounds); +} AVAES; + +void ff_init_aes_x86(AVAES *a, int decrypt); + +#endif /* AVUTIL_AES_INTERNAL_H */ diff --git a/libs/ffmpeg/libavutil/ambient_viewing_environment.c b/libs/ffmpeg/libavutil/ambient_viewing_environment.c new file mode 100644 index 00000000000..e3597277767 --- /dev/null +++ b/libs/ffmpeg/libavutil/ambient_viewing_environment.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 Jan Ekström <jeebjp@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ambient_viewing_environment.h" +#include "mem.h" + +static void get_defaults(AVAmbientViewingEnvironment *env) +{ + env->ambient_illuminance = + env->ambient_light_x = + env->ambient_light_y = (AVRational) { 0, 1 }; +} + +AVAmbientViewingEnvironment *av_ambient_viewing_environment_alloc(size_t *size) +{ + AVAmbientViewingEnvironment *env = + av_mallocz(sizeof(AVAmbientViewingEnvironment)); + if (!env) + return NULL; + + get_defaults(env); + + if (size) + *size = sizeof(*env); + + return env; +} + +AVAmbientViewingEnvironment *av_ambient_viewing_environment_create_side_data(AVFrame *frame) +{ + AVFrameSideData *side_data = + av_frame_new_side_data(frame, + AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT, + sizeof(AVAmbientViewingEnvironment)); + if (!side_data) + return NULL; + + memset(side_data->data, 0, side_data->size); + get_defaults((AVAmbientViewingEnvironment *)side_data->data); + + return (AVAmbientViewingEnvironment *)side_data->data; +} diff --git a/libs/ffmpeg/libavutil/ambient_viewing_environment.h b/libs/ffmpeg/libavutil/ambient_viewing_environment.h new file mode 100644 index 00000000000..e5e4ac21732 --- /dev/null +++ b/libs/ffmpeg/libavutil/ambient_viewing_environment.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2023 Jan Ekström <jeebjp@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AMBIENT_VIEWING_ENVIRONMENT_H +#define AVUTIL_AMBIENT_VIEWING_ENVIRONMENT_H + +#include <stddef.h> +#include "frame.h" +#include "rational.h" + +/** + * Ambient viewing environment metadata as defined by H.274. The values are + * saved in AVRationals so that they keep their exactness, while allowing for + * easy access to a double value with f.ex. av_q2d. + * + * @note sizeof(AVAmbientViewingEnvironment) is not part of the public ABI, and + * it must be allocated using av_ambient_viewing_environment_alloc. + */ +typedef struct AVAmbientViewingEnvironment { + /** + * Environmental illuminance of the ambient viewing environment in lux. + */ + AVRational ambient_illuminance; + + /** + * Normalized x chromaticity coordinate of the environmental ambient light + * in the nominal viewing environment according to the CIE 1931 definition + * of x and y as specified in ISO/CIE 11664-1. + */ + AVRational ambient_light_x; + + /** + * Normalized y chromaticity coordinate of the environmental ambient light + * in the nominal viewing environment according to the CIE 1931 definition + * of x and y as specified in ISO/CIE 11664-1. + */ + AVRational ambient_light_y; +} AVAmbientViewingEnvironment; + +/** + * Allocate an AVAmbientViewingEnvironment structure. + * + * @return the newly allocated struct or NULL on failure + */ +AVAmbientViewingEnvironment *av_ambient_viewing_environment_alloc(size_t *size); + +/** + * Allocate and add an AVAmbientViewingEnvironment structure to an existing + * AVFrame as side data. + * + * @return the newly allocated struct, or NULL on failure + */ +AVAmbientViewingEnvironment *av_ambient_viewing_environment_create_side_data(AVFrame *frame); + +#endif /* AVUTIL_AMBIENT_VIEWING_ENVIRONMENT_H */ diff --git a/libs/ffmpeg/libavutil/arm/bswap.h b/libs/ffmpeg/libavutil/arm/bswap.h new file mode 100644 index 00000000000..48fefa4da36 --- /dev/null +++ b/libs/ffmpeg/libavutil/arm/bswap.h @@ -0,0 +1,50 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ARM_BSWAP_H +#define AVUTIL_ARM_BSWAP_H + +#include <stdint.h> +#include "config.h" +#include "libavutil/attributes.h" + +#ifdef __ARMCC_VERSION + +#if HAVE_ARMV6 +#define av_bswap32 av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + return __rev(x); +} +#endif /* HAVE_ARMV6 */ + +#elif HAVE_INLINE_ASM + +#if HAVE_ARMV6_INLINE +#define av_bswap16 av_bswap16 +static av_always_inline av_const unsigned av_bswap16(unsigned x) +{ + unsigned y; + + __asm__("rev16 %0, %1" : "=r"(y) : "r"(x)); + return y; +} +#endif +#endif /* __ARMCC_VERSION */ + +#endif /* AVUTIL_ARM_BSWAP_H */ diff --git a/libs/ffmpeg/libavutil/arm/cpu.h b/libs/ffmpeg/libavutil/arm/cpu.h new file mode 100644 index 00000000000..1d6cc65dc48 --- /dev/null +++ b/libs/ffmpeg/libavutil/arm/cpu.h @@ -0,0 +1,38 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ARM_CPU_H +#define AVUTIL_ARM_CPU_H + +#include "libavutil/cpu.h" +#include "libavutil/cpu_internal.h" + +#define have_armv5te(flags) CPUEXT(flags, ARMV5TE) +#define have_armv6(flags) CPUEXT(flags, ARMV6) +#define have_armv6t2(flags) CPUEXT(flags, ARMV6T2) +#define have_vfp(flags) CPUEXT(flags, VFP) +#define have_vfpv3(flags) CPUEXT(flags, VFPV3) +#define have_neon(flags) CPUEXT(flags, NEON) +#define have_setend(flags) CPUEXT(flags, SETEND) + +/* some functions use the VFPv2 vector mode which is deprecated in ARMv7-A + * and might trap on such CPU depending on the OS configuration */ +#define have_vfp_vm(flags) \ + (HAVE_VFP && ((flags) & AV_CPU_FLAG_VFP_VM)) + +#endif /* AVUTIL_ARM_CPU_H */ diff --git a/libs/ffmpeg/libavutil/arm/intmath.h b/libs/ffmpeg/libavutil/arm/intmath.h new file mode 100644 index 00000000000..f19b21e98d3 --- /dev/null +++ b/libs/ffmpeg/libavutil/arm/intmath.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2010 Mans Rullgard <mans@mansr.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ARM_INTMATH_H +#define AVUTIL_ARM_INTMATH_H + +#include <stdint.h> + +#include "config.h" +#include "libavutil/attributes.h" + +#if HAVE_INLINE_ASM + +#if HAVE_ARMV6_INLINE + +#define av_clip_uint8 av_clip_uint8_arm +static av_always_inline av_const int av_clip_uint8_arm(int a) +{ + int x; + __asm__ ("usat %0, #8, %1" : "=r"(x) : "r"(a)); + return x; +} + +#define av_clip_int8 av_clip_int8_arm +static av_always_inline av_const int av_clip_int8_arm(int a) +{ + int x; + __asm__ ("ssat %0, #8, %1" : "=r"(x) : "r"(a)); + return x; +} + +#define av_clip_uint16 av_clip_uint16_arm +static av_always_inline av_const int av_clip_uint16_arm(int a) +{ + int x; + __asm__ ("usat %0, #16, %1" : "=r"(x) : "r"(a)); + return x; +} + +#define av_clip_int16 av_clip_int16_arm +static av_always_inline av_const int av_clip_int16_arm(int a) +{ + int x; + __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a)); + return x; +} + +#define av_clip_intp2 av_clip_intp2_arm +static av_always_inline av_const int av_clip_intp2_arm(int a, int p) +{ + if (av_builtin_constant_p(p)) { + unsigned x; + __asm__ ("ssat %0, %2, %1" : "=r"(x) : "r"(a), "i"(p+1)); + return x; + } else { + if (((unsigned)a + (1 << p)) & ~((2 << p) - 1)) + return (a >> 31) ^ ((1 << p) - 1); + else + return a; + } +} + +#define av_clip_uintp2 av_clip_uintp2_arm +static av_always_inline av_const unsigned av_clip_uintp2_arm(int a, int p) +{ + if (av_builtin_constant_p(p)) { + unsigned x; + __asm__ ("usat %0, %2, %1" : "=r"(x) : "r"(a), "i"(p)); + return x; + } else { + if (a & ~((1<<p) - 1)) return (~a) >> 31 & ((1<<p) - 1); + else return a; + } +} + +#define av_sat_add32 av_sat_add32_arm +static av_always_inline int av_sat_add32_arm(int a, int b) +{ + int r; + __asm__ ("qadd %0, %1, %2" : "=r"(r) : "r"(a), "r"(b)); + return r; +} + +#define av_sat_dadd32 av_sat_dadd32_arm +static av_always_inline int av_sat_dadd32_arm(int a, int b) +{ + int r; + __asm__ ("qdadd %0, %1, %2" : "=r"(r) : "r"(a), "r"(b)); + return r; +} + +#define av_sat_sub32 av_sat_sub32_arm +static av_always_inline int av_sat_sub32_arm(int a, int b) +{ + int r; + __asm__ ("qsub %0, %1, %2" : "=r"(r) : "r"(a), "r"(b)); + return r; +} + +#define av_sat_dsub32 av_sat_dsub32_arm +static av_always_inline int av_sat_dsub32_arm(int a, int b) +{ + int r; + __asm__ ("qdsub %0, %1, %2" : "=r"(r) : "r"(a), "r"(b)); + return r; +} + +#endif /* HAVE_ARMV6_INLINE */ + +#if HAVE_ASM_MOD_Q + +#define av_clipl_int32 av_clipl_int32_arm +static av_always_inline av_const int32_t av_clipl_int32_arm(int64_t a) +{ + int x, y; + __asm__ ("adds %1, %R2, %Q2, lsr #31 \n\t" + "itet ne \n\t" + "mvnne %1, #1<<31 \n\t" + "moveq %0, %Q2 \n\t" + "eorne %0, %1, %R2, asr #31 \n\t" + : "=r"(x), "=&r"(y) : "r"(a) : "cc"); + return x; +} + +#endif /* HAVE_ASM_MOD_Q */ + +#endif /* HAVE_INLINE_ASM */ + +#endif /* AVUTIL_ARM_INTMATH_H */ diff --git a/libs/ffmpeg/libavutil/arm/timer.h b/libs/ffmpeg/libavutil/arm/timer.h new file mode 100644 index 00000000000..08e4095d84d --- /dev/null +++ b/libs/ffmpeg/libavutil/arm/timer.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2009 Mans Rullgard <mans@mansr.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ARM_TIMER_H +#define AVUTIL_ARM_TIMER_H + +#include <stdint.h> +#include "config.h" + +#if defined(__APPLE__) + +#include <mach/mach_time.h> + +#define AV_READ_TIME mach_absolute_time + +#elif HAVE_INLINE_ASM && defined(__ARM_ARCH_7A__) && !defined(__ANDROID__) + +#define AV_READ_TIME read_time + +static inline uint64_t read_time(void) +{ + unsigned cc; + __asm__ volatile ("mrc p15, 0, %0, c9, c13, 0" : "=r"(cc)); + return cc; +} + +#endif /* HAVE_INLINE_ASM && __ARM_ARCH_7A__ */ + +#endif /* AVUTIL_ARM_TIMER_H */ diff --git a/libs/ffmpeg/libavutil/attributes.h b/libs/ffmpeg/libavutil/attributes.h new file mode 100644 index 00000000000..b405b4f0903 --- /dev/null +++ b/libs/ffmpeg/libavutil/attributes.h @@ -0,0 +1,240 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Macro definitions for various function/variable attributes + */ + +#ifndef AVUTIL_ATTRIBUTES_H +#define AVUTIL_ATTRIBUTES_H + +#ifdef __GNUC__ +# define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +# define AV_GCC_VERSION_AT_MOST(x,y) (__GNUC__ < (x) || __GNUC__ == (x) && __GNUC_MINOR__ <= (y)) +#else +# define AV_GCC_VERSION_AT_LEAST(x,y) 0 +# define AV_GCC_VERSION_AT_MOST(x,y) 0 +#endif + +#ifdef __has_builtin +# define AV_HAS_BUILTIN(x) __has_builtin(x) +#else +# define AV_HAS_BUILTIN(x) 0 +#endif + +#ifdef __has_attribute +# define AV_HAS_ATTRIBUTE(x) __has_attribute(x) +#else +# define AV_HAS_ATTRIBUTE(x) 0 +#endif + +#if defined(__cplusplus) && \ + defined(__has_cpp_attribute) && \ + __cplusplus >= 201103L +# define AV_HAS_STD_ATTRIBUTE(x) __has_cpp_attribute(x) +#elif !defined(__cplusplus) && \ + defined(__has_c_attribute) && \ + defined(__STDC_VERSION__) && \ + __STDC_VERSION__ >= 202311L +# define AV_HAS_STD_ATTRIBUTE(x) __has_c_attribute(x) +#else +# define AV_HAS_STD_ATTRIBUTE(x) 0 +#endif + +#ifndef av_always_inline +#if AV_GCC_VERSION_AT_LEAST(3,1) || defined(__clang__) +# define av_always_inline __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +# define av_always_inline __forceinline +#else +# define av_always_inline inline +#endif +#endif + +#ifndef av_extern_inline +#if defined(__ICL) && __ICL >= 1210 || defined(__GNUC_STDC_INLINE__) +# define av_extern_inline extern inline +#else +# define av_extern_inline inline +#endif +#endif + +#if AV_HAS_STD_ATTRIBUTE(nodiscard) +# define av_warn_unused_result [[nodiscard]] +#elif AV_GCC_VERSION_AT_LEAST(3,4) || defined(__clang__) +# define av_warn_unused_result __attribute__((warn_unused_result)) +#else +# define av_warn_unused_result +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) || defined(__clang__) +# define av_noinline __attribute__((noinline)) +#elif defined(_MSC_VER) +# define av_noinline __declspec(noinline) +#else +# define av_noinline +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) || defined(__clang__) +# define av_pure __attribute__((pure)) +#else +# define av_pure +#endif + +#if AV_GCC_VERSION_AT_LEAST(2,6) || defined(__clang__) +# define av_const __attribute__((const)) +#else +# define av_const +#endif + +#if AV_GCC_VERSION_AT_LEAST(4,3) || defined(__clang__) +# define av_cold __attribute__((cold)) +#else +# define av_cold +#endif + +#if AV_GCC_VERSION_AT_LEAST(4,1) && !defined(__llvm__) +# define av_flatten __attribute__((flatten)) +#else +# define av_flatten +#endif + +#if AV_HAS_STD_ATTRIBUTE(deprecated) +# define attribute_deprecated [[deprecated]] +#elif AV_GCC_VERSION_AT_LEAST(3,1) || defined(__clang__) +# define attribute_deprecated __attribute__((deprecated)) +#elif defined(_MSC_VER) +# define attribute_deprecated __declspec(deprecated) +#else +# define attribute_deprecated +#endif + +/** + * Disable warnings about deprecated features + * This is useful for sections of code kept for backward compatibility and + * scheduled for removal. + */ +#ifndef AV_NOWARN_DEPRECATED +#if AV_GCC_VERSION_AT_LEAST(4,6) || defined(__clang__) +# define AV_NOWARN_DEPRECATED(code) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \ + code \ + _Pragma("GCC diagnostic pop") +#elif defined(_MSC_VER) +# define AV_NOWARN_DEPRECATED(code) \ + __pragma(warning(push)) \ + __pragma(warning(disable : 4996)) \ + code; \ + __pragma(warning(pop)) +#else +# define AV_NOWARN_DEPRECATED(code) code +#endif +#endif + +#if AV_HAS_STD_ATTRIBUTE(maybe_unused) +# define av_unused [[maybe_unused]] +#elif defined(__GNUC__) || defined(__clang__) +# define av_unused __attribute__((unused)) +#else +# define av_unused +#endif + +/** + * Mark a variable as used and prevent the compiler from optimizing it + * away. This is useful for variables accessed only from inline + * assembler without the compiler being aware. + */ +#if AV_GCC_VERSION_AT_LEAST(3,1) || defined(__clang__) +# define av_used __attribute__((used)) +#else +# define av_used +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,3) || defined(__clang__) +# define av_alias __attribute__((may_alias)) +#else +# define av_alias +#endif + +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__INTEL_COMPILER) +# define av_uninit(x) x=x +#else +# define av_uninit(x) x +#endif + +#if defined(__GNUC__) || defined(__clang__) +# define av_builtin_constant_p __builtin_constant_p +#else +# define av_builtin_constant_p(x) 0 +#endif + +// for __MINGW_PRINTF_FORMAT and __MINGW_SCANF_FORMAT +#ifdef __MINGW32__ +# include <stdio.h> +#endif + +#ifdef __MINGW_PRINTF_FORMAT +# define AV_PRINTF_FMT __MINGW_PRINTF_FORMAT +#elif AV_HAS_ATTRIBUTE(format) +# define AV_PRINTF_FMT __printf__ +#endif + +#ifdef __MINGW_SCANF_FORMAT +# define AV_SCANF_FMT __MINGW_SCANF_FORMAT +#elif AV_HAS_ATTRIBUTE(format) +# define AV_SCANF_FMT __scanf__ +#endif + +#ifdef AV_PRINTF_FMT +# define av_printf_format(fmtpos, attrpos) __attribute__((format(AV_PRINTF_FMT, fmtpos, attrpos))) +#else +# define av_printf_format(fmtpos, attrpos) +#endif + +#ifdef AV_SCANF_FMT +# define av_scanf_format(fmtpos, attrpos) __attribute__((format(AV_SCANF_FMT, fmtpos, attrpos))) +#else +# define av_scanf_format(fmtpos, attrpos) +#endif + +#if AV_HAS_STD_ATTRIBUTE(noreturn) +# define av_noreturn [[noreturn]] +#elif AV_GCC_VERSION_AT_LEAST(2,5) || defined(__clang__) +# define av_noreturn __attribute__((noreturn)) +#else +# define av_noreturn +#endif + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wimplicit-const-int-float-conversion" +#pragma clang diagnostic ignored "-Wparentheses" +#pragma clang diagnostic ignored "-Wpass-failed" +#pragma clang diagnostic ignored "-Wpointer-sign" +#pragma clang diagnostic ignored "-Wshift-op-parentheses" +#pragma clang diagnostic ignored "-Wswitch" +#endif + +#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 202311L) +#define static_assert _Static_assert +#endif + +#endif /* AVUTIL_ATTRIBUTES_H */ diff --git a/libs/ffmpeg/libavutil/attributes_internal.h b/libs/ffmpeg/libavutil/attributes_internal.h new file mode 100644 index 00000000000..15d89120ad0 --- /dev/null +++ b/libs/ffmpeg/libavutil/attributes_internal.h @@ -0,0 +1,45 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ATTRIBUTES_INTERNAL_H +#define AVUTIL_ATTRIBUTES_INTERNAL_H + +#include "attributes.h" + +#if (AV_GCC_VERSION_AT_LEAST(4,0) || defined(__clang__)) && (defined(__ELF__) || defined(__MACH__)) +# define attribute_visibility_hidden __attribute__((visibility("hidden"))) +# define FF_VISIBILITY_PUSH_HIDDEN _Pragma("GCC visibility push(hidden)") +# define FF_VISIBILITY_POP_HIDDEN _Pragma("GCC visibility pop") +#else +# define attribute_visibility_hidden +# define FF_VISIBILITY_PUSH_HIDDEN +# define FF_VISIBILITY_POP_HIDDEN +#endif + +#define EXTERN extern attribute_visibility_hidden + +#if (AV_HAS_ATTRIBUTE(nonstring) && (AV_GCC_VERSION_AT_LEAST(15,1) || defined(__clang__))) +// Attribute to mark a variable initialized via a string literal as not +// containing string data to suppress warnings about unterminated strings +// in situations like char fourcc[4] = "TALB". +#define attribute_nonstring __attribute__((nonstring)) +#else +#define attribute_nonstring +#endif + +#endif /* AVUTIL_ATTRIBUTES_INTERNAL_H */ diff --git a/libs/ffmpeg/libavutil/audio_fifo.c b/libs/ffmpeg/libavutil/audio_fifo.c new file mode 100644 index 00000000000..dc2dea9b2dc --- /dev/null +++ b/libs/ffmpeg/libavutil/audio_fifo.c @@ -0,0 +1,230 @@ +/* + * Audio FIFO + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Audio FIFO + */ + +#include <limits.h> +#include <stddef.h> + +#include "audio_fifo.h" +#include "error.h" +#include "fifo.h" +#include "macros.h" +#include "mem.h" +#include "samplefmt.h" + +struct AVAudioFifo { + AVFifo **buf; /**< single buffer for interleaved, per-channel buffers for planar */ + int nb_buffers; /**< number of buffers */ + int nb_samples; /**< number of samples currently in the FIFO */ + int allocated_samples; /**< current allocated size, in samples */ + + int channels; /**< number of channels */ + enum AVSampleFormat sample_fmt; /**< sample format */ + int sample_size; /**< size, in bytes, of one sample in a buffer */ +}; + +void av_audio_fifo_free(AVAudioFifo *af) +{ + if (af) { + if (af->buf) { + int i; + for (i = 0; i < af->nb_buffers; i++) { + av_fifo_freep2(&af->buf[i]); + } + av_freep(&af->buf); + } + av_free(af); + } +} + +AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, + int nb_samples) +{ + AVAudioFifo *af; + int buf_size, i; + + /* get channel buffer size (also validates parameters) */ + if (av_samples_get_buffer_size(&buf_size, channels, nb_samples, sample_fmt, 1) < 0) + return NULL; + + af = av_mallocz(sizeof(*af)); + if (!af) + return NULL; + + af->channels = channels; + af->sample_fmt = sample_fmt; + af->sample_size = buf_size / nb_samples; + af->nb_buffers = av_sample_fmt_is_planar(sample_fmt) ? channels : 1; + + af->buf = av_calloc(af->nb_buffers, sizeof(*af->buf)); + if (!af->buf) + goto error; + + for (i = 0; i < af->nb_buffers; i++) { + af->buf[i] = av_fifo_alloc2(buf_size, 1, 0); + if (!af->buf[i]) + goto error; + } + af->allocated_samples = nb_samples; + + return af; + +error: + av_audio_fifo_free(af); + return NULL; +} + +int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples) +{ + const size_t cur_size = av_fifo_can_read (af->buf[0]) + + av_fifo_can_write(af->buf[0]); + int i, ret, buf_size; + + if ((ret = av_samples_get_buffer_size(&buf_size, af->channels, nb_samples, + af->sample_fmt, 1)) < 0) + return ret; + + if (buf_size > cur_size) { + for (i = 0; i < af->nb_buffers; i++) { + if ((ret = av_fifo_grow2(af->buf[i], buf_size - cur_size)) < 0) + return ret; + } + } + af->allocated_samples = nb_samples; + return 0; +} + +int av_audio_fifo_write(AVAudioFifo *af, void * const *data, int nb_samples) +{ + int i, ret, size; + + /* automatically reallocate buffers if needed */ + if (av_audio_fifo_space(af) < nb_samples) { + int current_size = av_audio_fifo_size(af); + /* check for integer overflow in new size calculation */ + if (INT_MAX / 2 - current_size < nb_samples) + return AVERROR(EINVAL); + /* reallocate buffers */ + if ((ret = av_audio_fifo_realloc(af, 2 * (current_size + nb_samples))) < 0) + return ret; + } + + size = nb_samples * af->sample_size; + for (i = 0; i < af->nb_buffers; i++) { + ret = av_fifo_write(af->buf[i], data[i], size); + if (ret < 0) + return AVERROR_BUG; + } + af->nb_samples += nb_samples; + + return nb_samples; +} + +int av_audio_fifo_peek(const AVAudioFifo *af, void * const *data, int nb_samples) +{ + return av_audio_fifo_peek_at(af, data, nb_samples, 0); +} + +int av_audio_fifo_peek_at(const AVAudioFifo *af, void * const *data, + int nb_samples, int offset) +{ + int i, ret, size; + + if (offset < 0 || offset >= af->nb_samples) + return AVERROR(EINVAL); + if (nb_samples < 0) + return AVERROR(EINVAL); + nb_samples = FFMIN(nb_samples, af->nb_samples); + if (!nb_samples) + return 0; + if (offset > af->nb_samples - nb_samples) + return AVERROR(EINVAL); + + offset *= af->sample_size; + size = nb_samples * af->sample_size; + for (i = 0; i < af->nb_buffers; i++) { + if ((ret = av_fifo_peek(af->buf[i], data[i], size, offset)) < 0) + return AVERROR_BUG; + } + + return nb_samples; +} + +int av_audio_fifo_read(AVAudioFifo *af, void * const *data, int nb_samples) +{ + int i, size; + + if (nb_samples < 0) + return AVERROR(EINVAL); + nb_samples = FFMIN(nb_samples, af->nb_samples); + if (!nb_samples) + return 0; + + size = nb_samples * af->sample_size; + for (i = 0; i < af->nb_buffers; i++) { + if (av_fifo_read(af->buf[i], data[i], size) < 0) + return AVERROR_BUG; + } + af->nb_samples -= nb_samples; + + return nb_samples; +} + +int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples) +{ + int i, size; + + if (nb_samples < 0) + return AVERROR(EINVAL); + nb_samples = FFMIN(nb_samples, af->nb_samples); + + if (nb_samples) { + size = nb_samples * af->sample_size; + for (i = 0; i < af->nb_buffers; i++) + av_fifo_drain2(af->buf[i], size); + af->nb_samples -= nb_samples; + } + return 0; +} + +void av_audio_fifo_reset(AVAudioFifo *af) +{ + int i; + + for (i = 0; i < af->nb_buffers; i++) + av_fifo_reset2(af->buf[i]); + + af->nb_samples = 0; +} + +int av_audio_fifo_size(AVAudioFifo *af) +{ + return af->nb_samples; +} + +int av_audio_fifo_space(AVAudioFifo *af) +{ + return af->allocated_samples - af->nb_samples; +} diff --git a/libs/ffmpeg/libavutil/audio_fifo.h b/libs/ffmpeg/libavutil/audio_fifo.h new file mode 100644 index 00000000000..fa5f59a2bef --- /dev/null +++ b/libs/ffmpeg/libavutil/audio_fifo.h @@ -0,0 +1,187 @@ +/* + * Audio FIFO + * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Audio FIFO Buffer + */ + +#ifndef AVUTIL_AUDIO_FIFO_H +#define AVUTIL_AUDIO_FIFO_H + +#include "attributes.h" +#include "samplefmt.h" + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_audiofifo Audio FIFO Buffer + * @{ + */ + +/** + * Context for an Audio FIFO Buffer. + * + * - Operates at the sample level rather than the byte level. + * - Supports multiple channels with either planar or packed sample format. + * - Automatic reallocation when writing to a full buffer. + */ +typedef struct AVAudioFifo AVAudioFifo; + +/** + * Free an AVAudioFifo. + * + * @param af AVAudioFifo to free + */ +void av_audio_fifo_free(AVAudioFifo *af); + +/** + * Allocate an AVAudioFifo. + * + * @param sample_fmt sample format + * @param channels number of channels + * @param nb_samples initial allocation size, in samples + * @return newly allocated AVAudioFifo, or NULL on error + */ +AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, + int nb_samples); + +/** + * Reallocate an AVAudioFifo. + * + * @param af AVAudioFifo to reallocate + * @param nb_samples new allocation size, in samples + * @return 0 if OK, or negative AVERROR code on failure + */ +av_warn_unused_result +int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples); + +/** + * Write data to an AVAudioFifo. + * + * The AVAudioFifo will be reallocated automatically if the available space + * is less than nb_samples. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to write to + * @param data audio data plane pointers + * @param nb_samples number of samples to write + * @return number of samples actually written, or negative AVERROR + * code on failure. If successful, the number of samples + * actually written will always be nb_samples. + */ +int av_audio_fifo_write(AVAudioFifo *af, void * const *data, int nb_samples); + +/** + * Peek data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to peek + * @return number of samples actually peek, or negative AVERROR code + * on failure. The number of samples actually peek will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_peek(const AVAudioFifo *af, void * const *data, int nb_samples); + +/** + * Peek data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to peek + * @param offset offset from current read position + * @return number of samples actually peek, or negative AVERROR code + * on failure. The number of samples actually peek will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_peek_at(const AVAudioFifo *af, void * const *data, + int nb_samples, int offset); + +/** + * Read data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to read + * @return number of samples actually read, or negative AVERROR code + * on failure. The number of samples actually read will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_read(AVAudioFifo *af, void * const *data, int nb_samples); + +/** + * Drain data from an AVAudioFifo. + * + * Removes the data without reading it. + * + * @param af AVAudioFifo to drain + * @param nb_samples number of samples to drain + * @return 0 if OK, or negative AVERROR code on failure + */ +int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples); + +/** + * Reset the AVAudioFifo buffer. + * + * This empties all data in the buffer. + * + * @param af AVAudioFifo to reset + */ +void av_audio_fifo_reset(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for reading. + * + * @param af the AVAudioFifo to query + * @return number of samples available for reading + */ +int av_audio_fifo_size(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for writing. + * + * @param af the AVAudioFifo to query + * @return number of samples available for writing + */ +int av_audio_fifo_space(AVAudioFifo *af); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_AUDIO_FIFO_H */ diff --git a/libs/ffmpeg/libavutil/avassert.h b/libs/ffmpeg/libavutil/avassert.h new file mode 100644 index 00000000000..e316a3c90d6 --- /dev/null +++ b/libs/ffmpeg/libavutil/avassert.h @@ -0,0 +1,125 @@ +/* + * copyright (c) 2010 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple assert() macros that are a bit more flexible than ISO C assert(). + * @author Michael Niedermayer <michaelni@gmx.at> + */ + +#ifndef AVUTIL_AVASSERT_H +#define AVUTIL_AVASSERT_H + +#include <stdlib.h> +#ifdef HAVE_AV_CONFIG_H +# include "config.h" +#endif +#include "attributes.h" +#include "log.h" +#include "macros.h" +#include "version.h" + +/** + * assert() equivalent, that is always enabled. + */ +#define av_assert0(cond) do { \ + if (!(cond)) { \ + av_log(NULL, AV_LOG_PANIC, "Assertion %s failed at %s:%d\n", \ + AV_STRINGIFY(cond), __FILE__, __LINE__); \ + abort(); \ + } \ +} while (0) + + +/** + * assert() equivalent, that does not lie in speed critical code. + * These asserts() thus can be enabled without fearing speed loss. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 0 +#define av_assert1(cond) av_assert0(cond) +#else +#define av_assert1(cond) ((void)0) +#endif + + +/** + * assert() equivalent, that does lie in speed critical code. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 +#define av_assert2(cond) av_assert0(cond) +#else +#define av_assert2(cond) ((void)0) +#endif + +#if FF_API_ASSERT_FPU +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 +#define av_assert2_fpu() av_assert0_fpu() +#else +#define av_assert2_fpu() ((void)0) +#endif +/** + * Assert that floating point operations can be executed. + * + * This will av_assert0() that the cpu is not in MMX state on X86 + * @deprecated without replacement + */ +attribute_deprecated +void av_assert0_fpu(void); +#endif + +/** + * Asserts that are used as compiler optimization hints depending + * upon ASSERT_LEVEL and NBDEBUG. + * + * Undefined behaviour occurs if execution reaches a point marked + * with av_unreachable() or if a condition used with av_assume() + * is false. + * + * The condition used with av_assume() should not have side-effects + * and should be visible to the compiler. + */ +#if defined(ASSERT_LEVEL) ? ASSERT_LEVEL > 0 : !defined(HAVE_AV_CONFIG_H) && !defined(NDEBUG) +#define av_unreachable(msg) \ +do { \ + av_log(NULL, AV_LOG_PANIC, \ + "Reached supposedly unreachable code at %s:%d: %s\n", \ + __FILE__, __LINE__, msg); \ + abort(); \ +} while (0) +#define av_assume(cond) av_assert0(cond) +#else +#if AV_GCC_VERSION_AT_LEAST(4, 5) || AV_HAS_BUILTIN(__builtin_unreachable) +#define av_unreachable(msg) __builtin_unreachable() +#elif defined(_MSC_VER) +#define av_unreachable(msg) __assume(0) +#elif __STDC_VERSION__ >= 202311L +#include <stddef.h> +#define av_unreachable(msg) unreachable() +#else +#define av_unreachable(msg) ((void)0) +#endif + +#define av_assume(cond) do { \ + if (!(cond)) \ + av_unreachable(); \ +} while (0) +#endif + +#endif /* AVUTIL_AVASSERT_H */ diff --git a/libs/ffmpeg/libavutil/avconfig.h b/libs/ffmpeg/libavutil/avconfig.h new file mode 100644 index 00000000000..8558b35027f --- /dev/null +++ b/libs/ffmpeg/libavutil/avconfig.h @@ -0,0 +1,6 @@ +/* Generated by ffmpeg configure */ +#ifndef AVUTIL_AVCONFIG_H +#define AVUTIL_AVCONFIG_H +#define AV_HAVE_BIGENDIAN 0 +#define AV_HAVE_FAST_UNALIGNED 0 +#endif /* AVUTIL_AVCONFIG_H */ diff --git a/libs/ffmpeg/libavutil/avsscanf.c b/libs/ffmpeg/libavutil/avsscanf.c new file mode 100644 index 00000000000..94f7710043e --- /dev/null +++ b/libs/ffmpeg/libavutil/avsscanf.c @@ -0,0 +1,969 @@ +/* + * Copyright (c) 2005-2014 Rich Felker, et al. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <errno.h> +#include <limits.h> +#include <math.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <float.h> + +#include "avstring.h" +#include "libm.h" + +typedef struct FFFILE { + size_t buf_size; + unsigned char *buf; + unsigned char *rpos, *rend; + unsigned char *shend; + ptrdiff_t shlim, shcnt; + void *cookie; + size_t (*read)(struct FFFILE *, unsigned char *, size_t); +} FFFILE; + +#define SIZE_hh -2 +#define SIZE_h -1 +#define SIZE_def 0 +#define SIZE_l 1 +#define SIZE_L 2 +#define SIZE_ll 3 + +#define shcnt(f) ((f)->shcnt + ((f)->rpos - (f)->buf)) + +static int fftoread(FFFILE *f) +{ + f->rpos = f->rend = f->buf + f->buf_size; + return 0; +} + +static size_t ffstring_read(FFFILE *f, unsigned char *buf, size_t len) +{ + char *src = f->cookie; + size_t k = len+256; + char *end = memchr(src, 0, k); + + if (end) k = end-src; + if (k < len) len = k; + memcpy(buf, src, len); + f->rpos = (void *)(src+len); + f->rend = (void *)(src+k); + f->cookie = src+k; + + return len; +} + +static int ffuflow(FFFILE *f) +{ + unsigned char c; + if (!fftoread(f) && f->read(f, &c, 1)==1) return c; + return EOF; +} + +static void ffshlim(FFFILE *f, ptrdiff_t lim) +{ + f->shlim = lim; + f->shcnt = f->buf - f->rpos; + /* If lim is nonzero, rend must be a valid pointer. */ + if (lim && f->rend - f->rpos > lim) + f->shend = f->rpos + lim; + else + f->shend = f->rend; +} + +static int ffshgetc(FFFILE *f) +{ + int c; + ptrdiff_t cnt = shcnt(f); + if (f->shlim && cnt >= f->shlim || (c=ffuflow(f)) < 0) { + f->shcnt = f->buf - f->rpos + cnt; + f->shend = 0; + return EOF; + } + cnt++; + if (f->shlim && f->rend - f->rpos > f->shlim - cnt) + f->shend = f->rpos + (f->shlim - cnt); + else + f->shend = f->rend; + f->shcnt = f->buf - f->rpos + cnt; + if (f->rpos[-1] != c) f->rpos[-1] = c; + return c; +} + +#define shlim(f, lim) ffshlim((f), (lim)) +#define shgetc(f) (((f)->rpos < (f)->shend) ? *(f)->rpos++ : ffshgetc(f)) +#define shunget(f) ((f)->shend ? (void)(f)->rpos-- : (void)0) + +static const unsigned char table[] = { -1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +}; + +static unsigned long long ffintscan(FFFILE *f, unsigned base, int pok, unsigned long long lim) +{ + const unsigned char *val = table+1; + int c, neg=0; + unsigned x; + unsigned long long y; + if (base > 36 || base == 1) { + errno = EINVAL; + return 0; + } + while (av_isspace((c=shgetc(f)))); + if (c=='+' || c=='-') { + neg = -(c=='-'); + c = shgetc(f); + } + if ((base == 0 || base == 16) && c=='0') { + c = shgetc(f); + if ((c|32)=='x') { + c = shgetc(f); + if (val[c]>=16) { + shunget(f); + if (pok) shunget(f); + else shlim(f, 0); + return 0; + } + base = 16; + } else if (base == 0) { + base = 8; + } + } else { + if (base == 0) base = 10; + if (val[c] >= base) { + shunget(f); + shlim(f, 0); + errno = EINVAL; + return 0; + } + } + if (base == 10) { + for (x=0; c-'0'<10U && x<=UINT_MAX/10-1; c=shgetc(f)) + x = x*10 + (c-'0'); + for (y=x; c-'0'<10U && y<=ULLONG_MAX/10 && 10*y<=ULLONG_MAX-(c-'0'); c=shgetc(f)) + y = y*10 + (c-'0'); + if (c-'0'>=10U) goto done; + } else if (!(base & base-1)) { + int bs = "\0\1\2\4\7\3\6\5"[(0x17*base)>>5&7]; + for (x=0; val[c]<base && x<=UINT_MAX/32; c=shgetc(f)) + x = x<<bs | val[c]; + for (y=x; val[c]<base && y<=ULLONG_MAX>>bs; c=shgetc(f)) + y = y<<bs | val[c]; + } else { + for (x=0; val[c]<base && x<=UINT_MAX/36-1; c=shgetc(f)) + x = x*base + val[c]; + for (y=x; val[c]<base && y<=ULLONG_MAX/base && base*y<=ULLONG_MAX-val[c]; c=shgetc(f)) + y = y*base + val[c]; + } + if (val[c]<base) { + for (; val[c]<base; c=shgetc(f)); + errno = ERANGE; + y = lim; + if (lim&1) neg = 0; + } +done: + shunget(f); + if (y>=lim) { + if (!(lim&1) && !neg) { + errno = ERANGE; + return lim-1; + } else if (y>lim) { + errno = ERANGE; + return lim; + } + } + return (y^neg)-neg; +} + +static long long scanexp(FFFILE *f, int pok) +{ + int c; + int x; + long long y; + int neg = 0; + + c = shgetc(f); + if (c=='+' || c=='-') { + neg = (c=='-'); + c = shgetc(f); + if (c-'0'>=10U && pok) shunget(f); + } + if (c-'0'>=10U) { + shunget(f); + return LLONG_MIN; + } + for (x=0; c-'0'<10U && x<INT_MAX/10; c = shgetc(f)) + x = 10*x + (c-'0'); + for (y=x; c-'0'<10U && y<LLONG_MAX/100; c = shgetc(f)) + y = 10*y + (c-'0'); + for (; c-'0'<10U; c = shgetc(f)); + shunget(f); + return neg ? -y : y; +} + +#define LD_B1B_DIG 2 +#define LD_B1B_MAX 9007199, 254740991 +#define KMAX 128 +#define MASK (KMAX-1) + +static double decfloat(FFFILE *f, int c, int bits, int emin, int sign, int pok) +{ + uint32_t x[KMAX]; + static const uint32_t th[] = { LD_B1B_MAX }; + int i, j, k, a, z; + long long lrp=0, dc=0; + long long e10=0; + int lnz = 0; + int gotdig = 0, gotrad = 0; + int rp; + int e2; + int emax = -emin-bits+3; + int denormal = 0; + double y; + double frac=0; + double bias=0; + static const int p10s[] = { 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000 }; + + j=0; + k=0; + + /* Don't let leading zeros consume buffer space */ + for (; c=='0'; c = shgetc(f)) gotdig=1; + if (c=='.') { + gotrad = 1; + for (c = shgetc(f); c=='0'; c = shgetc(f)) gotdig=1, lrp--; + } + + x[0] = 0; + for (; c-'0'<10U || c=='.'; c = shgetc(f)) { + if (c == '.') { + if (gotrad) break; + gotrad = 1; + lrp = dc; + } else if (k < KMAX-3) { + dc++; + if (c!='0') lnz = dc; + if (j) x[k] = x[k]*10 + c-'0'; + else x[k] = c-'0'; + if (++j==9) { + k++; + j=0; + } + gotdig=1; + } else { + dc++; + if (c!='0') { + lnz = (KMAX-4)*9; + x[KMAX-4] |= 1; + } + } + } + if (!gotrad) lrp=dc; + + if (gotdig && (c|32)=='e') { + e10 = scanexp(f, pok); + if (e10 == LLONG_MIN) { + if (pok) { + shunget(f); + } else { + shlim(f, 0); + return 0; + } + e10 = 0; + } + lrp += e10; + } else if (c>=0) { + shunget(f); + } + if (!gotdig) { + errno = EINVAL; + shlim(f, 0); + return 0; + } + + /* Handle zero specially to avoid nasty special cases later */ + if (!x[0]) return sign * 0.0; + + /* Optimize small integers (w/no exponent) and over/under-flow */ + if (lrp==dc && dc<10 && (bits>30 || x[0]>>bits==0)) + return sign * (double)x[0]; + if (lrp > -emin/2) { + errno = ERANGE; + return sign * DBL_MAX * DBL_MAX; + } + if (lrp < emin-2*DBL_MANT_DIG) { + errno = ERANGE; + return sign * DBL_MIN * DBL_MIN; + } + + /* Align incomplete final B1B digit */ + if (j) { + for (; j<9; j++) x[k]*=10; + k++; + j=0; + } + + a = 0; + z = k; + e2 = 0; + rp = lrp; + + /* Optimize small to mid-size integers (even in exp. notation) */ + if (lnz<9 && lnz<=rp && rp < 18) { + int bitlim; + if (rp == 9) return sign * (double)x[0]; + if (rp < 9) return sign * (double)x[0] / p10s[8-rp]; + bitlim = bits-3*(int)(rp-9); + if (bitlim>30 || x[0]>>bitlim==0) + return sign * (double)x[0] * p10s[rp-10]; + } + + /* Drop trailing zeros */ + for (; !x[z-1]; z--); + + /* Align radix point to B1B digit boundary */ + if (rp % 9) { + int rpm9 = rp>=0 ? rp%9 : rp%9+9; + int p10 = p10s[8-rpm9]; + uint32_t carry = 0; + for (k=a; k!=z; k++) { + uint32_t tmp = x[k] % p10; + x[k] = x[k]/p10 + carry; + carry = 1000000000/p10 * tmp; + if (k==a && !x[k]) { + a = (a+1 & MASK); + rp -= 9; + } + } + if (carry) x[z++] = carry; + rp += 9-rpm9; + } + + /* Upscale until desired number of bits are left of radix point */ + while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[a]<th[0])) { + uint32_t carry = 0; + e2 -= 29; + for (k=(z-1 & MASK); ; k=(k-1 & MASK)) { + uint64_t tmp = ((uint64_t)x[k] << 29) + carry; + if (tmp > 1000000000) { + carry = tmp / 1000000000; + x[k] = tmp % 1000000000; + } else { + carry = 0; + x[k] = tmp; + } + if (k==(z-1 & MASK) && k!=a && !x[k]) z = k; + if (k==a) break; + } + if (carry) { + rp += 9; + a = (a-1 & MASK); + if (a == z) { + z = (z-1 & MASK); + x[z-1 & MASK] |= x[z]; + } + x[a] = carry; + } + } + + /* Downscale until exactly number of bits are left of radix point */ + for (;;) { + uint32_t carry = 0; + int sh = 1; + for (i=0; i<LD_B1B_DIG; i++) { + k = (a+i & MASK); + if (k == z || x[k] < th[i]) { + i=LD_B1B_DIG; + break; + } + if (x[a+i & MASK] > th[i]) break; + } + if (i==LD_B1B_DIG && rp==9*LD_B1B_DIG) break; + /* FIXME: find a way to compute optimal sh */ + if (rp > 9+9*LD_B1B_DIG) sh = 9; + e2 += sh; + for (k=a; k!=z; k=(k+1 & MASK)) { + uint32_t tmp = x[k] & (1<<sh)-1; + x[k] = (x[k]>>sh) + carry; + carry = (1000000000>>sh) * tmp; + if (k==a && !x[k]) { + a = (a+1 & MASK); + i--; + rp -= 9; + } + } + if (carry) { + if ((z+1 & MASK) != a) { + x[z] = carry; + z = (z+1 & MASK); + } else x[z-1 & MASK] |= 1; + } + } + + /* Assemble desired bits into floating point variable */ + for (y=i=0; i<LD_B1B_DIG; i++) { + if ((a+i & MASK)==z) x[(z=(z+1 & MASK))-1] = 0; + y = 1000000000.0L * y + x[a+i & MASK]; + } + + y *= sign; + + /* Limit precision for denormal results */ + if (bits > DBL_MANT_DIG+e2-emin) { + bits = DBL_MANT_DIG+e2-emin; + if (bits<0) bits=0; + denormal = 1; + } + + /* Calculate bias term to force rounding, move out lower bits */ + if (bits < DBL_MANT_DIG) { + bias = copysign(scalbn(1, 2*DBL_MANT_DIG-bits-1), y); + frac = fmod(y, scalbn(1, DBL_MANT_DIG-bits)); + y -= frac; + y += bias; + } + + /* Process tail of decimal input so it can affect rounding */ + if ((a+i & MASK) != z) { + uint32_t t = x[a+i & MASK]; + if (t < 500000000 && (t || (a+i+1 & MASK) != z)) + frac += 0.25*sign; + else if (t > 500000000) + frac += 0.75*sign; + else if (t == 500000000) { + if ((a+i+1 & MASK) == z) + frac += 0.5*sign; + else + frac += 0.75*sign; + } + if (DBL_MANT_DIG-bits >= 2 && !fmod(frac, 1)) + frac++; + } + + y += frac; + y -= bias; + + if ((e2+DBL_MANT_DIG & INT_MAX) > emax-5) { + if (fabs(y) >= pow(2, DBL_MANT_DIG)) { + if (denormal && bits==DBL_MANT_DIG+e2-emin) + denormal = 0; + y *= 0.5; + e2++; + } + if (e2+DBL_MANT_DIG>emax || (denormal && frac)) + errno = ERANGE; + } + + return scalbn(y, e2); +} + +static double hexfloat(FFFILE *f, int bits, int emin, int sign, int pok) +{ + uint32_t x = 0; + double y = 0; + double scale = 1; + double bias = 0; + int gottail = 0, gotrad = 0, gotdig = 0; + long long rp = 0; + long long dc = 0; + long long e2 = 0; + int d; + int c; + + c = shgetc(f); + + /* Skip leading zeros */ + for (; c=='0'; c = shgetc(f)) + gotdig = 1; + + if (c=='.') { + gotrad = 1; + c = shgetc(f); + /* Count zeros after the radix point before significand */ + for (rp=0; c=='0'; c = shgetc(f), rp--) gotdig = 1; + } + + for (; c-'0'<10U || (c|32)-'a'<6U || c=='.'; c = shgetc(f)) { + if (c=='.') { + if (gotrad) break; + rp = dc; + gotrad = 1; + } else { + gotdig = 1; + if (c > '9') d = (c|32)+10-'a'; + else d = c-'0'; + if (dc<8) { + x = x*16 + d; + } else if (dc < DBL_MANT_DIG/4+1) { + y += d*(scale/=16); + } else if (d && !gottail) { + y += 0.5*scale; + gottail = 1; + } + dc++; + } + } + if (!gotdig) { + shunget(f); + if (pok) { + shunget(f); + if (gotrad) shunget(f); + } else { + shlim(f, 0); + } + return sign * 0.0; + } + if (!gotrad) rp = dc; + while (dc<8) x *= 16, dc++; + if ((c|32)=='p') { + e2 = scanexp(f, pok); + if (e2 == LLONG_MIN) { + if (pok) { + shunget(f); + } else { + shlim(f, 0); + return 0; + } + e2 = 0; + } + } else { + shunget(f); + } + e2 += 4*rp - 32; + + if (!x) return sign * 0.0; + if (e2 > -emin) { + errno = ERANGE; + return sign * DBL_MAX * DBL_MAX; + } + if (e2 < emin-2*DBL_MANT_DIG) { + errno = ERANGE; + return sign * DBL_MIN * DBL_MIN; + } + + while (x < 0x80000000) { + if (y>=0.5) { + x += x + 1; + y += y - 1; + } else { + x += x; + y += y; + } + e2--; + } + + if (bits > 32+e2-emin) { + bits = 32+e2-emin; + if (bits<0) bits=0; + } + + if (bits < DBL_MANT_DIG) + bias = copysign(scalbn(1, 32+DBL_MANT_DIG-bits-1), sign); + + if (bits<32 && y && !(x&1)) x++, y=0; + + y = bias + sign*(double)x + sign*y; + y -= bias; + + if (!y) errno = ERANGE; + + return scalbn(y, e2); +} + +static double fffloatscan(FFFILE *f, int prec, int pok) +{ + int sign = 1; + size_t i; + int bits; + int emin; + int c; + + switch (prec) { + case 0: + bits = FLT_MANT_DIG; + emin = FLT_MIN_EXP-bits; + break; + case 1: + bits = DBL_MANT_DIG; + emin = DBL_MIN_EXP-bits; + break; + case 2: + bits = DBL_MANT_DIG; + emin = DBL_MIN_EXP-bits; + break; + default: + return 0; + } + + while (av_isspace((c = shgetc(f)))); + + if (c=='+' || c=='-') { + sign -= 2*(c=='-'); + c = shgetc(f); + } + + for (i=0; i<8 && (c|32)=="infinity"[i]; i++) + if (i<7) c = shgetc(f); + if (i==3 || i==8 || (i>3 && pok)) { + if (i!=8) { + shunget(f); + if (pok) for (; i>3; i--) shunget(f); + } + return sign * INFINITY; + } + if (!i) for (i=0; i<3 && (c|32)=="nan"[i]; i++) + if (i<2) c = shgetc(f); + if (i==3) { + if (shgetc(f) != '(') { + shunget(f); + return NAN; + } + for (i=1; ; i++) { + c = shgetc(f); + if (c-'0'<10U || c-'A'<26U || c-'a'<26U || c=='_') + continue; + if (c==')') return NAN; + shunget(f); + if (!pok) { + errno = EINVAL; + shlim(f, 0); + return 0; + } + while (i--) shunget(f); + return NAN; + } + } + + if (i) { + shunget(f); + errno = EINVAL; + shlim(f, 0); + return 0; + } + + if (c=='0') { + c = shgetc(f); + if ((c|32) == 'x') + return hexfloat(f, bits, emin, sign, pok); + shunget(f); + c = '0'; + } + + return decfloat(f, c, bits, emin, sign, pok); +} + +static void *arg_n(va_list ap, unsigned int n) +{ + void *p; + unsigned int i; + va_list ap2; + va_copy(ap2, ap); + for (i=n; i>1; i--) va_arg(ap2, void *); + p = va_arg(ap2, void *); + va_end(ap2); + return p; +} + +static void store_int(void *dest, int size, unsigned long long i) +{ + if (!dest) return; + switch (size) { + case SIZE_hh: + *(char *)dest = i; + break; + case SIZE_h: + *(short *)dest = i; + break; + case SIZE_def: + *(int *)dest = i; + break; + case SIZE_l: + *(long *)dest = i; + break; + case SIZE_ll: + *(long long *)dest = i; + break; + } +} + +static int ff_vfscanf(FFFILE *f, const char *fmt, va_list ap) +{ + int width; + int size; + int base; + const unsigned char *p; + int c, t; + char *s; + void *dest=NULL; + int invert; + int matches=0; + unsigned long long x; + double y; + ptrdiff_t pos = 0; + unsigned char scanset[257]; + size_t i; + + for (p=(const unsigned char *)fmt; *p; p++) { + + if (av_isspace(*p)) { + while (av_isspace(p[1])) p++; + shlim(f, 0); + while (av_isspace(shgetc(f))); + shunget(f); + pos += shcnt(f); + continue; + } + if (*p != '%' || p[1] == '%') { + shlim(f, 0); + if (*p == '%') { + p++; + while (av_isspace((c=shgetc(f)))); + } else { + c = shgetc(f); + } + if (c!=*p) { + shunget(f); + if (c<0) goto input_fail; + goto match_fail; + } + pos += shcnt(f); + continue; + } + + p++; + if (*p=='*') { + dest = 0; p++; + } else if (av_isdigit(*p) && p[1]=='$') { + dest = arg_n(ap, *p-'0'); p+=2; + } else { + dest = va_arg(ap, void *); + } + + for (width=0; av_isdigit(*p); p++) { + width = 10*width + *p - '0'; + } + + if (*p=='m') { + s = 0; + p++; + } + + size = SIZE_def; + switch (*p++) { + case 'h': + if (*p == 'h') p++, size = SIZE_hh; + else size = SIZE_h; + break; + case 'l': + if (*p == 'l') p++, size = SIZE_ll; + else size = SIZE_l; + break; + case 'j': + size = SIZE_ll; + break; + case 'z': + case 't': + size = SIZE_l; + break; + case 'L': + size = SIZE_L; + break; + case 'd': case 'i': case 'o': case 'u': case 'x': + case 'a': case 'e': case 'f': case 'g': + case 'A': case 'E': case 'F': case 'G': case 'X': + case 's': case 'c': case '[': + case 'S': case 'C': + case 'p': case 'n': + p--; + break; + default: + goto fmt_fail; + } + + t = *p; + + /* C or S */ + if ((t&0x2f) == 3) { + t |= 32; + size = SIZE_l; + } + + switch (t) { + case 'c': + if (width < 1) width = 1; + case '[': + break; + case 'n': + store_int(dest, size, pos); + /* do not increment match count, etc! */ + continue; + default: + shlim(f, 0); + while (av_isspace(shgetc(f))); + shunget(f); + pos += shcnt(f); + } + + shlim(f, width); + if (shgetc(f) < 0) goto input_fail; + shunget(f); + + switch (t) { + case 's': + case 'c': + case '[': + if (t == 'c' || t == 's') { + memset(scanset, -1, sizeof scanset); + scanset[0] = 0; + if (t == 's') { + scanset[1 + '\t'] = 0; + scanset[1 + '\n'] = 0; + scanset[1 + '\v'] = 0; + scanset[1 + '\f'] = 0; + scanset[1 + '\r'] = 0; + scanset[1 + ' ' ] = 0; + } + } else { + if (*++p == '^') p++, invert = 1; + else invert = 0; + memset(scanset, invert, sizeof scanset); + scanset[0] = 0; + if (*p == '-') p++, scanset[1+'-'] = 1-invert; + else if (*p == ']') p++, scanset[1+']'] = 1-invert; + for (; *p != ']'; p++) { + if (!*p) goto fmt_fail; + if (*p=='-' && p[1] && p[1] != ']') + for (c=p++[-1]; c<*p; c++) + scanset[1+c] = 1-invert; + scanset[1+*p] = 1-invert; + } + } + s = 0; + i = 0; + if ((s = dest)) { + while (scanset[(c=shgetc(f))+1]) + s[i++] = c; + } else { + while (scanset[(c=shgetc(f))+1]); + } + shunget(f); + if (!shcnt(f)) goto match_fail; + if (t == 'c' && shcnt(f) != width) goto match_fail; + if (t != 'c') { + if (s) s[i] = 0; + } + break; + case 'p': + case 'X': + case 'x': + base = 16; + goto int_common; + case 'o': + base = 8; + goto int_common; + case 'd': + case 'u': + base = 10; + goto int_common; + case 'i': + base = 0; +int_common: + x = ffintscan(f, base, 0, ULLONG_MAX); + if (!shcnt(f)) + goto match_fail; + if (t=='p' && dest) + *(void **)dest = (void *)(uintptr_t)x; + else + store_int(dest, size, x); + break; + case 'a': case 'A': + case 'e': case 'E': + case 'f': case 'F': + case 'g': case 'G': + y = fffloatscan(f, size, 0); + if (!shcnt(f)) + goto match_fail; + if (dest) { + switch (size) { + case SIZE_def: + *(float *)dest = y; + break; + case SIZE_l: + *(double *)dest = y; + break; + case SIZE_L: + *(double *)dest = y; + break; + } + } + break; + } + + pos += shcnt(f); + if (dest) matches++; + } + if (0) { +fmt_fail: +input_fail: + if (!matches) matches--; + } +match_fail: + return matches; +} + +static int ff_vsscanf(const char *s, const char *fmt, va_list ap) +{ + FFFILE f = { + .buf = (void *)s, .cookie = (void *)s, + .read = ffstring_read, + }; + + return ff_vfscanf(&f, fmt, ap); +} + +int av_sscanf(const char *string, const char *format, ...) +{ + int ret; + va_list ap; + va_start(ap, format); + ret = ff_vsscanf(string, format, ap); + va_end(ap); + return ret; +} diff --git a/libs/ffmpeg/libavutil/avstring.c b/libs/ffmpeg/libavutil/avstring.c new file mode 100644 index 00000000000..281c5cdc88f --- /dev/null +++ b/libs/ffmpeg/libavutil/avstring.c @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * Copyright (c) 2007 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <limits.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include "config.h" +#include "mem.h" +#include "avassert.h" +#include "avstring.h" +#include "bprint.h" +#include "error.h" +#include "macros.h" + +int av_strstart(const char *str, const char *pfx, const char **ptr) +{ + while (*pfx && *pfx == *str) { + pfx++; + str++; + } + if (!*pfx && ptr) + *ptr = str; + return !*pfx; +} + +int av_stristart(const char *str, const char *pfx, const char **ptr) +{ + while (*pfx && av_toupper((unsigned)*pfx) == av_toupper((unsigned)*str)) { + pfx++; + str++; + } + if (!*pfx && ptr) + *ptr = str; + return !*pfx; +} + +char *av_stristr(const char *s1, const char *s2) +{ + if (!*s2) + return (char*)(intptr_t)s1; + + do + if (av_stristart(s1, s2, NULL)) + return (char*)(intptr_t)s1; + while (*s1++); + + return NULL; +} + +char *av_strnstr(const char *haystack, const char *needle, size_t hay_length) +{ + size_t needle_len = strlen(needle); + if (!needle_len) + return (char*)haystack; + while (hay_length >= needle_len) { + hay_length--; + if (!memcmp(haystack, needle, needle_len)) + return (char*)haystack; + haystack++; + } + return NULL; +} + +size_t av_strlcpy(char *dst, const char *src, size_t size) +{ + size_t len = 0; + while (++len < size && *src) + *dst++ = *src++; + if (len <= size) + *dst = 0; + return len + strlen(src) - 1; +} + +size_t av_strlcat(char *dst, const char *src, size_t size) +{ + size_t len = strlen(dst); + if (size <= len + 1) + return len + strlen(src); + return len + av_strlcpy(dst + len, src, size - len); +} + +size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...) +{ + size_t len = strlen(dst); + va_list vl; + + va_start(vl, fmt); + len += vsnprintf(dst + len, size > len ? size - len : 0, fmt, vl); + va_end(vl); + + return len; +} + +char *av_asprintf(const char *fmt, ...) +{ + char *p = NULL; + va_list va; + int len; + + va_start(va, fmt); + len = vsnprintf(NULL, 0, fmt, va); + va_end(va); + if (len < 0) + goto end; + + p = av_malloc(len + 1); + if (!p) + goto end; + + va_start(va, fmt); + len = vsnprintf(p, len + 1, fmt, va); + va_end(va); + if (len < 0) + av_freep(&p); + +end: + return p; +} + +#define WHITESPACES " \n\t\r" + +char *av_get_token(const char **buf, const char *term) +{ + char *out = av_realloc(NULL, strlen(*buf) + 1); + char *ret = out, *end = out; + const char *p = *buf; + if (!out) + return NULL; + p += strspn(p, WHITESPACES); + + while (*p && !strspn(p, term)) { + char c = *p++; + if (c == '\\' && *p) { + *out++ = *p++; + end = out; + } else if (c == '\'') { + while (*p && *p != '\'') + *out++ = *p++; + if (*p) { + p++; + end = out; + } + } else { + *out++ = c; + } + } + + do + *out-- = 0; + while (out >= end && strspn(out, WHITESPACES)); + + *buf = p; + + char *small_ret = av_realloc(ret, out - ret + 2); + return small_ret ? small_ret : ret; +} + +char *av_strtok(char *s, const char *delim, char **saveptr) +{ + char *tok; + + if (!s && !(s = *saveptr)) + return NULL; + + /* skip leading delimiters */ + s += strspn(s, delim); + + /* s now points to the first non delimiter char, or to the end of the string */ + if (!*s) { + *saveptr = NULL; + return NULL; + } + tok = s++; + + /* skip non delimiters */ + s += strcspn(s, delim); + if (*s) { + *s = 0; + *saveptr = s+1; + } else { + *saveptr = NULL; + } + + return tok; +} + +int av_strcasecmp(const char *a, const char *b) +{ + uint8_t c1, c2; + do { + c1 = av_tolower(*a++); + c2 = av_tolower(*b++); + } while (c1 && c1 == c2); + return c1 - c2; +} + +int av_strncasecmp(const char *a, const char *b, size_t n) +{ + uint8_t c1, c2; + if (n <= 0) + return 0; + do { + c1 = av_tolower(*a++); + c2 = av_tolower(*b++); + } while (--n && c1 && c1 == c2); + return c1 - c2; +} + +char *av_strireplace(const char *str, const char *from, const char *to) +{ + char *ret = NULL; + const char *pstr2, *pstr = str; + size_t tolen = strlen(to), fromlen = strlen(from); + AVBPrint pbuf; + + av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); + while ((pstr2 = av_stristr(pstr, from))) { + av_bprint_append_data(&pbuf, pstr, pstr2 - pstr); + pstr = pstr2 + fromlen; + av_bprint_append_data(&pbuf, to, tolen); + } + av_bprint_append_data(&pbuf, pstr, strlen(pstr)); + if (!av_bprint_is_complete(&pbuf)) { + av_bprint_finalize(&pbuf, NULL); + } else { + av_bprint_finalize(&pbuf, &ret); + } + + return ret; +} + +const char *av_basename(const char *path) +{ + char *p; +#if HAVE_DOS_PATHS + char *q, *d; +#endif + + if (!path || *path == '\0') + return "."; + + p = strrchr(path, '/'); +#if HAVE_DOS_PATHS + q = strrchr(path, '\\'); + d = strchr(path, ':'); + p = FFMAX3(p, q, d); +#endif + + if (!p) + return path; + + return p + 1; +} + +const char *av_dirname(char *path) +{ + char *p = path ? strrchr(path, '/') : NULL; + +#if HAVE_DOS_PATHS + char *q = path ? strrchr(path, '\\') : NULL; + char *d = path ? strchr(path, ':') : NULL; + + d = d ? d + 1 : d; + + p = FFMAX3(p, q, d); +#endif + + if (!p) + return "."; + + *p = '\0'; + + return path; +} + +char *av_append_path_component(const char *path, const char *component) +{ + size_t p_len, c_len; + char *fullpath; + + if (!path) + return av_strdup(component); + if (!component) + return av_strdup(path); + + p_len = strlen(path); + c_len = strlen(component); + if (p_len > SIZE_MAX - c_len || p_len + c_len > SIZE_MAX - 2) + return NULL; + fullpath = av_malloc(p_len + c_len + 2); + if (fullpath) { + if (p_len) { + av_strlcpy(fullpath, path, p_len + 1); + if (c_len) { + if (fullpath[p_len - 1] != '/' && component[0] != '/') + fullpath[p_len++] = '/'; + else if (fullpath[p_len - 1] == '/' && component[0] == '/') + p_len--; + } + } + av_strlcpy(&fullpath[p_len], component, c_len + 1); + fullpath[p_len + c_len] = 0; + } + return fullpath; +} + +int av_escape(char **dst, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags) +{ + AVBPrint dstbuf; + int ret; + + av_bprint_init(&dstbuf, 1, INT_MAX); /* (int)dstbuf.len must be >= 0 */ + av_bprint_escape(&dstbuf, src, special_chars, mode, flags); + + if (!av_bprint_is_complete(&dstbuf)) { + av_bprint_finalize(&dstbuf, NULL); + return AVERROR(ENOMEM); + } + if ((ret = av_bprint_finalize(&dstbuf, dst)) < 0) + return ret; + return dstbuf.len; +} + +int av_match_name(const char *name, const char *names) +{ + const char *p; + size_t len, namelen; + + if (!name || !names) + return 0; + + namelen = strlen(name); + while (*names) { + int negate = '-' == *names; + p = strchr(names, ','); + if (!p) + p = names + strlen(names); + names += negate; + len = FFMAX(p - names, namelen); + if (!av_strncasecmp(name, names, len) || !strncmp("ALL", names, FFMAX(3, p - names))) + return !negate; + names = p + (*p == ','); + } + return 0; +} + +int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end, + unsigned int flags) +{ + const uint8_t *p = *bufp; + uint32_t top; + uint64_t code; + int ret = 0, tail_len; + uint32_t overlong_encoding_mins[6] = { + 0x00000000, 0x00000080, 0x00000800, 0x00010000, 0x00200000, 0x04000000, + }; + + if (p >= buf_end) + return 0; + + code = *p++; + + /* first sequence byte starts with 10, or is 1111-1110 or 1111-1111, + which is not admitted */ + if ((code & 0xc0) == 0x80 || code >= 0xFE) { + ret = AVERROR(EILSEQ); + goto end; + } + top = (code & 128) >> 1; + + tail_len = 0; + while (code & top) { + int tmp; + tail_len++; + if (p >= buf_end) { + (*bufp) ++; + return AVERROR(EILSEQ); /* incomplete sequence */ + } + + /* we assume the byte to be in the form 10xx-xxxx */ + tmp = *p++ - 128; /* strip leading 1 */ + if (tmp>>6) { + (*bufp) ++; + return AVERROR(EILSEQ); + } + code = (code<<6) + tmp; + top <<= 5; + } + code &= (top << 1) - 1; + + /* check for overlong encodings */ + av_assert0(tail_len <= 5); + if (code < overlong_encoding_mins[tail_len]) { + ret = AVERROR(EILSEQ); + goto end; + } + + if (code >= 1U<<31) { + ret = AVERROR(EILSEQ); /* out-of-range value */ + goto end; + } + + *codep = code; + + if (code > 0x10FFFF && + !(flags & AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES)) + ret = AVERROR(EILSEQ); + if (code < 0x20 && code != 0x9 && code != 0xA && code != 0xD && + flags & AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES) + ret = AVERROR(EILSEQ); + if (code >= 0xD800 && code <= 0xDFFF && + !(flags & AV_UTF8_FLAG_ACCEPT_SURROGATES)) + ret = AVERROR(EILSEQ); + if ((code == 0xFFFE || code == 0xFFFF) && + !(flags & AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS)) + ret = AVERROR(EILSEQ); + +end: + *bufp = p; + return ret; +} + +int av_match_list(const char *name, const char *list, char separator) +{ + const char *p, *q; + + for (p = name; p && *p; ) { + for (q = list; q && *q; ) { + int k; + for (k = 0; p[k] == q[k] || (p[k]*q[k] == 0 && p[k]+q[k] == separator); k++) + if (k && (!p[k] || p[k] == separator)) + return 1; + q = strchr(q, separator); + if(q) + q++; + } + p = strchr(p, separator); + if (p) + p++; + } + + return 0; +} diff --git a/libs/ffmpeg/libavutil/avstring.h b/libs/ffmpeg/libavutil/avstring.h new file mode 100644 index 00000000000..17f7b03db52 --- /dev/null +++ b/libs/ffmpeg/libavutil/avstring.h @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2007 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AVSTRING_H +#define AVUTIL_AVSTRING_H + +#include <stddef.h> +#include <stdint.h> +#include "attributes.h" + +/** + * @addtogroup lavu_string + * @{ + */ + +/** + * Return non-zero if pfx is a prefix of str. If it is, *ptr is set to + * the address of the first character in str after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_strstart(const char *str, const char *pfx, const char **ptr); + +/** + * Return non-zero if pfx is a prefix of str independent of case. If + * it is, *ptr is set to the address of the first character in str + * after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_stristart(const char *str, const char *pfx, const char **ptr); + +/** + * Locate the first case-independent occurrence in the string haystack + * of the string needle. A zero-length string needle is considered to + * match at the start of haystack. + * + * This function is a case-insensitive version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_stristr(const char *haystack, const char *needle); + +/** + * Locate the first occurrence of the string needle in the string haystack + * where not more than hay_length characters are searched. A zero-length + * string needle is considered to match at the start of haystack. + * + * This function is a length-limited version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @param hay_length length of string to search in + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_strnstr(const char *haystack, const char *needle, size_t hay_length); + +/** + * Copy the string src to dst, but no more than size - 1 bytes, and + * null-terminate dst. + * + * This function is the same as BSD strlcpy(). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the length of src + * + * @warning since the return value is the length of src, src absolutely + * _must_ be a properly 0-terminated string, otherwise this will read beyond + * the end of the buffer and possibly crash. + */ +size_t av_strlcpy(char *dst, const char *src, size_t size); + +/** + * Append the string src to the string dst, but to a total length of + * no more than size - 1 bytes, and null-terminate dst. + * + * This function is similar to BSD strlcat(), but differs when + * size <= strlen(dst). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the total length of src and dst + * + * @warning since the return value use the length of src and dst, these + * absolutely _must_ be a properly 0-terminated strings, otherwise this + * will read beyond the end of the buffer and possibly crash. + */ +size_t av_strlcat(char *dst, const char *src, size_t size); + +/** + * Append output to a string, according to a format. Never write out of + * the destination buffer, and always put a terminating 0 within + * the buffer. + * @param dst destination buffer (string to which the output is + * appended) + * @param size total size of the destination buffer + * @param fmt printf-compatible format string, specifying how the + * following parameters are used + * @return the length of the string that would have been generated + * if enough space had been available + */ +size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...) av_printf_format(3, 4); + +/** + * Get the count of continuous non zero chars starting from the beginning. + * + * @param s the string whose length to count + * @param len maximum number of characters to check in the string, that + * is the maximum value which is returned by the function + */ +static inline size_t av_strnlen(const char *s, size_t len) +{ + size_t i; + for (i = 0; i < len && s[i]; i++) + ; + return i; +} + +/** + * Print arguments following specified format into a large enough auto + * allocated buffer. It is similar to GNU asprintf(). + * @param fmt printf-compatible format string, specifying how the + * following parameters are used. + * @return the allocated string + * @note You have to free the string yourself with av_free(). + */ +char *av_asprintf(const char *fmt, ...) av_printf_format(1, 2); + +/** + * Unescape the given string until a non escaped terminating char, + * and return the token corresponding to the unescaped string. + * + * The normal \ and ' escaping is supported. Leading and trailing + * whitespaces are removed, unless they are escaped with '\' or are + * enclosed between ''. + * + * @param buf the buffer to parse, buf will be updated to point to the + * terminating char + * @param term a 0-terminated list of terminating chars + * @return the malloced unescaped string, which must be av_freed by + * the user, NULL in case of allocation failure + */ +char *av_get_token(const char **buf, const char *term); + +/** + * Split the string into several tokens which can be accessed by + * successive calls to av_strtok(). + * + * A token is defined as a sequence of characters not belonging to the + * set specified in delim. + * + * On the first call to av_strtok(), s should point to the string to + * parse, and the value of saveptr is ignored. In subsequent calls, s + * should be NULL, and saveptr should be unchanged since the previous + * call. + * + * This function is similar to strtok_r() defined in POSIX.1. + * + * @param s the string to parse, may be NULL + * @param delim 0-terminated list of token delimiters, must be non-NULL + * @param saveptr user-provided pointer which points to stored + * information necessary for av_strtok() to continue scanning the same + * string. saveptr is updated to point to the next character after the + * first delimiter found, or to NULL if the string was terminated + * @return the found token, or NULL when no token is found + */ +char *av_strtok(char *s, const char *delim, char **saveptr); + +/** + * Locale-independent conversion of ASCII isdigit. + */ +static inline av_const int av_isdigit(int c) +{ + return c >= '0' && c <= '9'; +} + +/** + * Locale-independent conversion of ASCII isgraph. + */ +static inline av_const int av_isgraph(int c) +{ + return c > 32 && c < 127; +} + +/** + * Locale-independent conversion of ASCII isspace. + */ +static inline av_const int av_isspace(int c) +{ + return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || + c == '\v'; +} + +/** + * Locale-independent conversion of ASCII characters to uppercase. + */ +static inline av_const int av_toupper(int c) +{ + if (c >= 'a' && c <= 'z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII characters to lowercase. + */ +static inline av_const int av_tolower(int c) +{ + if (c >= 'A' && c <= 'Z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII isxdigit. + */ +static inline av_const int av_isxdigit(int c) +{ + c = av_tolower(c); + return av_isdigit(c) || (c >= 'a' && c <= 'f'); +} + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strcasecmp(const char *a, const char *b); + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strncasecmp(const char *a, const char *b, size_t n); + +/** + * Locale-independent strings replace. + * @note This means only ASCII-range characters are replaced. + */ +char *av_strireplace(const char *str, const char *from, const char *to); + +/** + * Thread safe basename. + * @param path the string to parse, on DOS both \ and / are considered separators. + * @return pointer to the basename substring. + * If path does not contain a slash, the function returns a copy of path. + * If path is a NULL pointer or points to an empty string, a pointer + * to a string "." is returned. + */ +const char *av_basename(const char *path); + +/** + * Thread safe dirname. + * @param path the string to parse, on DOS both \ and / are considered separators. + * @return A pointer to a string that's the parent directory of path. + * If path is a NULL pointer or points to an empty string, a pointer + * to a string "." is returned. + * @note the function may modify the contents of the path, so copies should be passed. + */ +const char *av_dirname(char *path); + +/** + * Match instances of a name in a comma-separated list of names. + * List entries are checked from the start to the end of the names list, + * the first match ends further processing. If an entry prefixed with '-' + * matches, then 0 is returned. The "ALL" list entry is considered to + * match all names. + * + * @param name Name to look for. + * @param names List of names. + * @return 1 on match, 0 otherwise. + */ +int av_match_name(const char *name, const char *names); + +/** + * Append path component to the existing path. + * Path separator '/' is placed between when needed. + * Resulting string have to be freed with av_free(). + * @param path base path + * @param component component to be appended + * @return new path or NULL on error. + */ +char *av_append_path_component(const char *path, const char *component); + +enum AVEscapeMode { + AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode. + AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping. + AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping. + AV_ESCAPE_MODE_XML, ///< Use XML non-markup character data escaping. +}; + +/** + * Consider spaces special and escape them even in the middle of the + * string. + * + * This is equivalent to adding the whitespace characters to the special + * characters lists, except it is guaranteed to use the exact same list + * of whitespace characters as the rest of libavutil. + */ +#define AV_ESCAPE_FLAG_WHITESPACE (1 << 0) + +/** + * Escape only specified special characters. + * Without this flag, escape also any characters that may be considered + * special by av_get_token(), such as the single quote. + */ +#define AV_ESCAPE_FLAG_STRICT (1 << 1) + +/** + * Within AV_ESCAPE_MODE_XML, additionally escape single quotes for single + * quoted attributes. + */ +#define AV_ESCAPE_FLAG_XML_SINGLE_QUOTES (1 << 2) + +/** + * Within AV_ESCAPE_MODE_XML, additionally escape double quotes for double + * quoted attributes. + */ +#define AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES (1 << 3) + + +/** + * Escape string in src, and put the escaped string in an allocated + * string in *dst, which must be freed with av_free(). + * + * @param dst pointer where an allocated string is put + * @param src string to escape, must be non-NULL + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_ macros + * @return the length of the allocated string, or a negative error code in case of error + * @see av_bprint_escape() + */ +av_warn_unused_result +int av_escape(char **dst, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +#define AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES 1 ///< accept codepoints over 0x10FFFF +#define AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS 2 ///< accept non-characters - 0xFFFE and 0xFFFF +#define AV_UTF8_FLAG_ACCEPT_SURROGATES 4 ///< accept UTF-16 surrogates codes +#define AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES 8 ///< exclude control codes not accepted by XML + +#define AV_UTF8_FLAG_ACCEPT_ALL \ + AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES|AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS|AV_UTF8_FLAG_ACCEPT_SURROGATES + +/** + * Read and decode a single UTF-8 code point (character) from the + * buffer in *buf, and update *buf to point to the next byte to + * decode. + * + * In case of an invalid byte sequence, the pointer will be updated to + * the next byte after the invalid sequence and the function will + * return an error code. + * + * Depending on the specified flags, the function will also fail in + * case the decoded code point does not belong to a valid range. + * + * @note For speed-relevant code a carefully implemented use of + * GET_UTF8() may be preferred. + * + * @param codep pointer used to return the parsed code in case of success. + * The value in *codep is set even in case the range check fails. + * @param bufp pointer to the address the first byte of the sequence + * to decode, updated by the function to point to the + * byte next after the decoded sequence + * @param buf_end pointer to the end of the buffer, points to the next + * byte past the last in the buffer. This is used to + * avoid buffer overreads (in case of an unfinished + * UTF-8 sequence towards the end of the buffer). + * @param flags a collection of AV_UTF8_FLAG_* flags + * @return >= 0 in case a sequence was successfully read, a negative + * value in case of invalid sequence + */ +av_warn_unused_result +int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end, + unsigned int flags); + +/** + * Check if a name is in a list. + * @returns 0 if not found, or the 1 based index where it has been found in the + * list. + */ +int av_match_list(const char *name, const char *list, char separator); + +/** + * See libc sscanf manual for more information. + * Locale-independent sscanf implementation. + */ +int av_sscanf(const char *string, const char *format, ...) av_scanf_format(2, 3); + +/** + * @} + */ + +#endif /* AVUTIL_AVSTRING_H */ diff --git a/libs/ffmpeg/libavutil/avutil.h b/libs/ffmpeg/libavutil/avutil.h new file mode 100644 index 00000000000..c8ae114ab6f --- /dev/null +++ b/libs/ffmpeg/libavutil/avutil.h @@ -0,0 +1,364 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AVUTIL_H +#define AVUTIL_AVUTIL_H + +/** + * @file + * @ingroup lavu + * Convenience header that includes @ref lavu "libavutil"'s core. + */ + +/** + * @mainpage + * + * @section ffmpeg_intro Introduction + * + * This document describes the usage of the different libraries + * provided by FFmpeg. + * + * @li @ref libavc "libavcodec" encoding/decoding library + * @li @ref lavfi "libavfilter" graph-based frame editing library + * @li @ref libavf "libavformat" I/O and muxing/demuxing library + * @li @ref lavd "libavdevice" special devices muxing/demuxing library + * @li @ref lavu "libavutil" common utility library + * @li @ref lswr "libswresample" audio resampling, format conversion and mixing + * @li @ref libsws "libswscale" color conversion and scaling library + * + * @section ffmpeg_versioning Versioning and compatibility + * + * Each of the FFmpeg libraries contains a version.h header, which defines a + * major, minor and micro version number with the + * <em>LIBRARYNAME_VERSION_{MAJOR,MINOR,MICRO}</em> macros. The major version + * number is incremented with backward incompatible changes - e.g. removing + * parts of the public API, reordering public struct members, etc. The minor + * version number is incremented for backward compatible API changes or major + * new features - e.g. adding a new public function or a new decoder. The micro + * version number is incremented for smaller changes that a calling program + * might still want to check for - e.g. changing behavior in a previously + * unspecified situation. + * + * FFmpeg guarantees backward API and ABI compatibility for each library as long + * as its major version number is unchanged. This means that no public symbols + * will be removed or renamed. Types and names of the public struct members and + * values of public macros and enums will remain the same (unless they were + * explicitly declared as not part of the public API). Documented behavior will + * not change. + * + * In other words, any correct program that works with a given FFmpeg snapshot + * should work just as well without any changes with any later snapshot with the + * same major versions. This applies to both rebuilding the program against new + * FFmpeg versions or to replacing the dynamic FFmpeg libraries that a program + * links against. + * + * However, new public symbols may be added and new members may be appended to + * public structs whose size is not part of public ABI (most public structs in + * FFmpeg). New macros and enum values may be added. Behavior in undocumented + * situations may change slightly (and be documented). All those are accompanied + * by an entry in doc/APIchanges and incrementing either the minor or micro + * version number. + */ + +/** + * @defgroup lavu libavutil + * Common code shared across all FFmpeg libraries. + * + * @note + * libavutil is designed to be modular. In most cases, in order to use the + * functions provided by one component of libavutil you must explicitly include + * the specific header containing that feature. If you are only using + * media-related components, you could simply include libavutil/avutil.h, which + * brings in most of the "core" components. + * + * @{ + * + * @defgroup lavu_crypto Crypto and Hashing + * + * @{ + * @} + * + * @defgroup lavu_math Mathematics + * @{ + * + * @} + * + * @defgroup lavu_string String Manipulation + * + * @{ + * + * @} + * + * @defgroup lavu_mem Memory Management + * + * @{ + * + * @} + * + * @defgroup lavu_data Data Structures + * @{ + * + * @} + * + * @defgroup lavu_video Video related + * + * @{ + * + * @} + * + * @defgroup lavu_audio Audio related + * + * @{ + * + * @} + * + * @defgroup lavu_error Error Codes + * + * @{ + * + * @} + * + * @defgroup lavu_log Logging Facility + * + * @{ + * + * @} + * + * @defgroup lavu_misc Other + * + * @{ + * + * @defgroup preproc_misc Preprocessor String Macros + * + * @{ + * + * @} + * + * @defgroup version_utils Library Version Macros + * + * @{ + * + * @} + */ + + +/** + * @addtogroup lavu_ver + * @{ + */ + +/** + * Return the LIBAVUTIL_VERSION_INT constant. + */ +unsigned avutil_version(void); + +/** + * Return an informative version string. This usually is the actual release + * version number or a git commit description. This string has no fixed format + * and can change any time. It should never be parsed by code. + */ +const char *av_version_info(void); + +/** + * Return the libavutil build-time configuration. + */ +const char *avutil_configuration(void); + +/** + * Return the libavutil license. + */ +const char *avutil_license(void); + +/** + * @} + */ + +/** + * @addtogroup lavu_media Media Type + * @brief Media Type + */ + +enum AVMediaType { + AVMEDIA_TYPE_UNKNOWN = -1, ///< Usually treated as AVMEDIA_TYPE_DATA + AVMEDIA_TYPE_VIDEO, + AVMEDIA_TYPE_AUDIO, + AVMEDIA_TYPE_DATA, ///< Opaque data information usually continuous + AVMEDIA_TYPE_SUBTITLE, + AVMEDIA_TYPE_ATTACHMENT, ///< Opaque data information usually sparse + AVMEDIA_TYPE_NB +}; + +/** + * Return a string describing the media_type enum, NULL if media_type + * is unknown. + */ +const char *av_get_media_type_string(enum AVMediaType media_type); + +/** + * @defgroup lavu_const Constants + * @{ + * + * @defgroup lavu_enc Encoding specific + * + * @note those definition should move to avcodec + * @{ + */ + +#define FF_LAMBDA_SHIFT 7 +#define FF_LAMBDA_SCALE (1<<FF_LAMBDA_SHIFT) +#define FF_QP2LAMBDA 118 ///< factor to convert from H.263 QP to lambda +#define FF_LAMBDA_MAX (256*128-1) + +#define FF_QUALITY_SCALE FF_LAMBDA_SCALE //FIXME maybe remove + +/** + * @} + * @defgroup lavu_time Timestamp specific + * + * FFmpeg internal timebase and timestamp definitions + * + * @{ + */ + +/** + * @brief Undefined timestamp value + * + * Usually reported by demuxer that work on containers that do not provide + * either pts or dts. + */ + +#define AV_NOPTS_VALUE ((int64_t)UINT64_C(0x8000000000000000)) + +/** + * Internal time base represented as integer + */ + +#define AV_TIME_BASE 1000000 + +/** + * Internal time base represented as fractional value + */ + +#ifdef __cplusplus +/* ISO C++ forbids compound-literals. */ +#define AV_TIME_BASE_Q av_make_q(1, AV_TIME_BASE) +#else +#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE} +#endif + +/** + * @} + * @} + * @defgroup lavu_picture Image related + * + * AVPicture types, pixel formats and basic image planes manipulation. + * + * @{ + */ + +enum AVPictureType { + AV_PICTURE_TYPE_NONE = 0, ///< Undefined + AV_PICTURE_TYPE_I, ///< Intra + AV_PICTURE_TYPE_P, ///< Predicted + AV_PICTURE_TYPE_B, ///< Bi-dir predicted + AV_PICTURE_TYPE_S, ///< S(GMC)-VOP MPEG-4 + AV_PICTURE_TYPE_SI, ///< Switching Intra + AV_PICTURE_TYPE_SP, ///< Switching Predicted + AV_PICTURE_TYPE_BI, ///< BI type +}; + +/** + * Return a single letter to describe the given picture type + * pict_type. + * + * @param[in] pict_type the picture type @return a single character + * representing the picture type, '?' if pict_type is unknown + */ +char av_get_picture_type_char(enum AVPictureType pict_type); + +/** + * @} + */ + +#include "common.h" +#include "rational.h" +#include "version.h" +#include "macros.h" +#include "mathematics.h" +#include "log.h" +#include "pixfmt.h" + +/** + * Return x default pointer in case p is NULL. + */ +static inline void *av_x_if_null(const void *p, const void *x) +{ + return (void *)(intptr_t)(p ? p : x); +} + +#if FF_API_OPT_INT_LIST +/** + * Compute the length of an integer list. + * + * @param elsize size in bytes of each list element (only 1, 2, 4 or 8) + * @param term list terminator (usually 0 or -1) + * @param list pointer to the list + * @return length of the list, in elements, not counting the terminator + */ +attribute_deprecated +unsigned av_int_list_length_for_size(unsigned elsize, + const void *list, uint64_t term) av_pure; + +/** + * Compute the length of an integer list. + * + * @param term list terminator (usually 0 or -1) + * @param list pointer to the list + * @return length of the list, in elements, not counting the terminator + */ +#define av_int_list_length(list, term) \ + av_int_list_length_for_size(sizeof(*(list)), list, term) +#endif + +/** + * Return the fractional representation of the internal time base. + */ +AVRational av_get_time_base_q(void); + +#define AV_FOURCC_MAX_STRING_SIZE 32 + +#define av_fourcc2str(fourcc) av_fourcc_make_string((char[AV_FOURCC_MAX_STRING_SIZE]){0}, fourcc) + +/** + * Fill the provided buffer with a string containing a FourCC (four-character + * code) representation. + * + * @param buf a buffer with size in bytes of at least AV_FOURCC_MAX_STRING_SIZE + * @param fourcc the fourcc to represent + * @return the buffer in input + */ +char *av_fourcc_make_string(char *buf, uint32_t fourcc); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_AVUTIL_H */ diff --git a/libs/ffmpeg/libavutil/base64.c b/libs/ffmpeg/libavutil/base64.c new file mode 100644 index 00000000000..69e11e6f5e1 --- /dev/null +++ b/libs/ffmpeg/libavutil/base64.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @brief Base64 encode/decode + * @author Ryan Martell <rdm4@martellventures.com> (with lots of Michael) + */ + +#include <limits.h> +#include <stddef.h> + +#include "base64.h" +#include "error.h" +#include "intreadwrite.h" + +/* ---------------- private code */ +static const uint8_t map2[256] = +{ + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, + + 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, + 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + + 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +#define BASE64_DEC_STEP(i) do { \ + bits = map2[in[i]]; \ + if (bits & 0x80) \ + goto out ## i; \ + v = i ? (v << 6) + bits : bits; \ +} while(0) + +int av_base64_decode(uint8_t *out, const char *in_str, int out_size) +{ + uint8_t *dst = out; + uint8_t *end; + // no sign extension + const uint8_t *in = in_str; + unsigned bits = 0xff; + unsigned v; + + if (!out) + goto validity_check; + + end = out + out_size; + while (end - dst > 3) { + BASE64_DEC_STEP(0); + BASE64_DEC_STEP(1); + BASE64_DEC_STEP(2); + BASE64_DEC_STEP(3); + // Using AV_WB32 directly confuses compiler + v = av_be2ne32(v << 8); + AV_WN32(dst, v); + dst += 3; + in += 4; + } + if (end - dst) { + BASE64_DEC_STEP(0); + BASE64_DEC_STEP(1); + BASE64_DEC_STEP(2); + BASE64_DEC_STEP(3); + *dst++ = v >> 16; + if (end - dst) + *dst++ = v >> 8; + if (end - dst) + *dst++ = v; + in += 4; + } +validity_check: + while (1) { + BASE64_DEC_STEP(0); + in++; + BASE64_DEC_STEP(0); + in++; + BASE64_DEC_STEP(0); + in++; + BASE64_DEC_STEP(0); + in++; + } + +out3: + if (end - dst) + *dst++ = v >> 10; + v <<= 2; +out2: + if (end - dst) + *dst++ = v >> 4; +out1: +out0: + return bits & 1 ? AVERROR_INVALIDDATA : out ? dst - out : 0; +} + +/***************************************************************************** +* b64_encode: Stolen from VLC's http.c. +* Simplified by Michael. +* Fixed edge cases and made it work from data (vs. strings) by Ryan. +*****************************************************************************/ + +char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size) +{ + static const char b64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + char *ret, *dst; + unsigned i_bits = 0; + int i_shift = 0; + int bytes_remaining = in_size; + + if (in_size >= UINT_MAX / 4 || + out_size < AV_BASE64_SIZE(in_size)) + return NULL; + ret = dst = out; + while (bytes_remaining > 3) { + i_bits = AV_RB32(in); + in += 3; bytes_remaining -= 3; + *dst++ = b64[ i_bits>>26 ]; + *dst++ = b64[(i_bits>>20) & 0x3F]; + *dst++ = b64[(i_bits>>14) & 0x3F]; + *dst++ = b64[(i_bits>>8 ) & 0x3F]; + } + i_bits = 0; + while (bytes_remaining) { + i_bits = (i_bits << 8) + *in++; + bytes_remaining--; + i_shift += 8; + } + while (i_shift > 0) { + *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f]; + i_shift -= 6; + } + while ((dst - ret) & 3) + *dst++ = '='; + *dst = '\0'; + + return ret; +} diff --git a/libs/ffmpeg/libavutil/base64.h b/libs/ffmpeg/libavutil/base64.h new file mode 100644 index 00000000000..2954c12d427 --- /dev/null +++ b/libs/ffmpeg/libavutil/base64.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BASE64_H +#define AVUTIL_BASE64_H + +#include <stdint.h> + +/** + * @defgroup lavu_base64 Base64 + * @ingroup lavu_crypto + * @{ + */ + +/** + * Decode a base64-encoded string. + * + * @param out buffer for decoded data + * @param in null-terminated input string + * @param out_size size in bytes of the out buffer, must be at + * least 3/4 of the length of in, that is AV_BASE64_DECODE_SIZE(strlen(in)) + * @return number of bytes written, or a negative value in case of + * invalid input + */ +int av_base64_decode(uint8_t *out, const char *in, int out_size); + +/** + * Calculate the output size in bytes needed to decode a base64 string + * with length x to a data buffer. + */ +#define AV_BASE64_DECODE_SIZE(x) ((x) * 3LL / 4) + +/** + * Encode data to base64 and null-terminate. + * + * @param out buffer for encoded data + * @param out_size size in bytes of the out buffer (including the + * null terminator), must be at least AV_BASE64_SIZE(in_size) + * @param in input buffer containing the data to encode + * @param in_size size in bytes of the in buffer + * @return out or NULL in case of error + */ +char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size); + +/** + * Calculate the output size needed to base64-encode x bytes to a + * null-terminated string. + */ +#define AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) + + /** + * @} + */ + +#endif /* AVUTIL_BASE64_H */ diff --git a/libs/ffmpeg/libavutil/blowfish.c b/libs/ffmpeg/libavutil/blowfish.c new file mode 100644 index 00000000000..6df60150ea9 --- /dev/null +++ b/libs/ffmpeg/libavutil/blowfish.c @@ -0,0 +1,425 @@ +/* + * Blowfish algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * loosely based on Paul Kocher's implementation + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> + +#include "attributes.h" +#include "intreadwrite.h" +#include "mem.h" +#include "blowfish.h" + +static const uint32_t orig_p[AV_BF_ROUNDS + 2] = { + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, + 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, + 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, + 0x9216D5D9, 0x8979FB1B +}; + +static const uint32_t orig_s[4][256] = { + { 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, + 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, + 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, + 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, + 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, + 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, + 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, + 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, + 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, + 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, + 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, + 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, + 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, + 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, + 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, + 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, + 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, + 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, + 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, + 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, + 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, + 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, + 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, + 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, + 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, + 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, + 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, + 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, + 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, + 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, + 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, + 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, + 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, + 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, + 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, + 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, + 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, + 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, + 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, + 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, + 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, + 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, + 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, + 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, + 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, + 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, + 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, + 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, + 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, + 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, + 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, + 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, + 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, + 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, + 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, + 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, + 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, + 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, + 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, + 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, + 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, + 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, + 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, + 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A }, + { 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, + 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, + 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, + 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, + 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, + 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, + 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, + 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, + 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, + 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, + 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, + 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, + 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, + 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, + 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, + 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, + 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, + 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, + 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, + 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, + 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, + 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, + 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, + 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, + 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, + 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, + 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, + 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, + 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, + 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, + 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, + 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, + 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, + 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, + 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, + 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, + 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, + 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, + 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, + 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, + 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, + 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, + 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, + 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, + 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, + 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, + 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, + 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, + 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, + 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, + 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, + 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, + 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, + 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, + 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, + 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, + 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, + 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, + 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, + 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, + 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, + 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, + 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, + 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 }, + { 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, + 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, + 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, + 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, + 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, + 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, + 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, + 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, + 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, + 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, + 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, + 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, + 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, + 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, + 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, + 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, + 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, + 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, + 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, + 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, + 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, + 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, + 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, + 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, + 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, + 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, + 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, + 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, + 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, + 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, + 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, + 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, + 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, + 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, + 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, + 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, + 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, + 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, + 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, + 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, + 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, + 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, + 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, + 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, + 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, + 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, + 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, + 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, + 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, + 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, + 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, + 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, + 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, + 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, + 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, + 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, + 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, + 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, + 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, + 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, + 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, + 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, + 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, + 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 }, + { 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, + 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, + 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, + 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, + 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, + 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, + 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, + 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, + 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, + 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, + 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, + 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, + 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, + 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, + 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, + 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, + 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, + 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, + 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, + 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, + 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, + 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, + 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, + 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, + 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, + 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, + 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, + 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, + 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, + 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, + 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, + 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, + 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, + 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, + 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, + 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, + 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, + 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, + 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, + 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, + 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, + 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, + 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, + 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, + 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, + 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, + 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, + 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, + 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, + 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, + 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, + 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, + 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, + 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, + 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, + 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, + 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, + 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, + 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, + 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, + 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, + 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, + 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, + 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 } +}; + +#define F(Xl, Xr, P) \ + Xr ^=((( ctx->s[0][ Xl >> 24 ] \ + + ctx->s[1][(Xl >> 16) & 0xFF])\ + ^ ctx->s[2][(Xl >> 8) & 0xFF])\ + + ctx->s[3][ Xl & 0xFF])\ + ^ P; + +AVBlowfish *av_blowfish_alloc(void) +{ + return av_mallocz(sizeof(struct AVBlowfish)); +} + +av_cold void av_blowfish_init(AVBlowfish *ctx, const uint8_t *key, int key_len) +{ + uint32_t data, data_l, data_r; + int i, j, k; + + memcpy(ctx->s, orig_s, sizeof(orig_s)); + + j = 0; + for (i = 0; i < AV_BF_ROUNDS + 2; ++i) { + data = 0; + for (k = 0; k < 4; k++) { + data = (data << 8) | key[j]; + if (++j >= key_len) + j = 0; + } + ctx->p[i] = orig_p[i] ^ data; + } + + data_l = data_r = 0; + + for (i = 0; i < AV_BF_ROUNDS + 2; i += 2) { + av_blowfish_crypt_ecb(ctx, &data_l, &data_r, 0); + ctx->p[i] = data_l; + ctx->p[i + 1] = data_r; + } + + for (i = 0; i < 4; ++i) { + for (j = 0; j < 256; j += 2) { + av_blowfish_crypt_ecb(ctx, &data_l, &data_r, 0); + ctx->s[i][j] = data_l; + ctx->s[i][j + 1] = data_r; + } + } +} + +void av_blowfish_crypt_ecb(AVBlowfish *ctx, uint32_t *xl, uint32_t *xr, + int decrypt) +{ + uint32_t Xl, Xr; + int i; + + Xl = *xl; + Xr = *xr; + + if (decrypt) { + Xl ^= ctx->p[AV_BF_ROUNDS + 1]; + for (i = AV_BF_ROUNDS; i > 0; i-=2) { + F(Xl, Xr, ctx->p[i ]); + F(Xr, Xl, ctx->p[i-1]); + } + + Xr ^= ctx->p[0]; + } else { + Xl ^= ctx->p[0]; + for (i = 1; i < AV_BF_ROUNDS+1; i+=2){ + F(Xl, Xr, ctx->p[i ]); + F(Xr, Xl, ctx->p[i+1]); + } + + Xr ^= ctx->p[AV_BF_ROUNDS + 1]; + } + + *xl = Xr; + *xr = Xl; +} + +void av_blowfish_crypt(AVBlowfish *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt) +{ + uint32_t v0, v1; + int i; + + if (decrypt) { + while (count--) { + v0 = AV_RB32(src); + v1 = AV_RB32(src + 4); + + av_blowfish_crypt_ecb(ctx, &v0, &v1, decrypt); + + if (iv) { + v0 ^= AV_RB32(iv); + v1 ^= AV_RB32(iv + 4); + memcpy(iv, src, 8); + } + + AV_WB32(dst, v0); + AV_WB32(dst + 4, v1); + + src += 8; + dst += 8; + } + } else { + while (count--) { + if (iv) { + for (i = 0; i < 8; i++) + dst[i] = src[i] ^ iv[i]; + v0 = AV_RB32(dst); + v1 = AV_RB32(dst + 4); + } else { + v0 = AV_RB32(src); + v1 = AV_RB32(src + 4); + } + + av_blowfish_crypt_ecb(ctx, &v0, &v1, decrypt); + + AV_WB32(dst, v0); + AV_WB32(dst + 4, v1); + + if (iv) + memcpy(iv, dst, 8); + + src += 8; + dst += 8; + } + } +} diff --git a/libs/ffmpeg/libavutil/blowfish.h b/libs/ffmpeg/libavutil/blowfish.h new file mode 100644 index 00000000000..9e289a40dab --- /dev/null +++ b/libs/ffmpeg/libavutil/blowfish.h @@ -0,0 +1,82 @@ +/* + * Blowfish algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BLOWFISH_H +#define AVUTIL_BLOWFISH_H + +#include <stdint.h> + +/** + * @defgroup lavu_blowfish Blowfish + * @ingroup lavu_crypto + * @{ + */ + +#define AV_BF_ROUNDS 16 + +typedef struct AVBlowfish { + uint32_t p[AV_BF_ROUNDS + 2]; + uint32_t s[4][256]; +} AVBlowfish; + +/** + * Allocate an AVBlowfish context. + */ +AVBlowfish *av_blowfish_alloc(void); + +/** + * Initialize an AVBlowfish context. + * + * @param ctx an AVBlowfish context + * @param key a key + * @param key_len length of the key + */ +void av_blowfish_init(struct AVBlowfish *ctx, const uint8_t *key, int key_len); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param xl left four bytes halves of input to be encrypted + * @param xr right four bytes halves of input to be encrypted + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt_ecb(struct AVBlowfish *ctx, uint32_t *xl, uint32_t *xr, + int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt(struct AVBlowfish *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_BLOWFISH_H */ diff --git a/libs/ffmpeg/libavutil/bprint.c b/libs/ffmpeg/libavutil/bprint.c new file mode 100644 index 00000000000..11e0f08774d --- /dev/null +++ b/libs/ffmpeg/libavutil/bprint.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2012 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include "avstring.h" +#include "bprint.h" +#include "compat/va_copy.h" +#include "error.h" +#include "macros.h" +#include "mem.h" + +#define av_bprint_room(buf) ((buf)->size - FFMIN((buf)->len, (buf)->size)) +#define av_bprint_is_allocated(buf) ((buf)->str != (buf)->reserved_internal_buffer) + +static int av_bprint_alloc(AVBPrint *buf, unsigned room) +{ + char *old_str, *new_str; + unsigned min_size, new_size; + + if (buf->size == buf->size_max) + return AVERROR(EIO); + if (!av_bprint_is_complete(buf)) + return AVERROR_INVALIDDATA; /* it is already truncated anyway */ + min_size = buf->len + 1 + FFMIN(UINT_MAX - buf->len - 1, room); + new_size = buf->size > buf->size_max / 2 ? buf->size_max : buf->size * 2; + if (new_size < min_size) + new_size = FFMIN(buf->size_max, min_size); + old_str = av_bprint_is_allocated(buf) ? buf->str : NULL; + new_str = av_realloc(old_str, new_size); + if (!new_str) + return AVERROR(ENOMEM); + if (!old_str) + memcpy(new_str, buf->str, buf->len + 1); + buf->str = new_str; + buf->size = new_size; + return 0; +} + +static void av_bprint_grow(AVBPrint *buf, unsigned extra_len) +{ + /* arbitrary margin to avoid small overflows */ + extra_len = FFMIN(extra_len, UINT_MAX - 5 - buf->len); + buf->len += extra_len; + if (buf->size) + buf->str[FFMIN(buf->len, buf->size - 1)] = 0; +} + +void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max) +{ + unsigned size_auto = (char *)buf + sizeof(*buf) - + buf->reserved_internal_buffer; + + if (size_max == AV_BPRINT_SIZE_AUTOMATIC) + size_max = size_auto; + buf->str = buf->reserved_internal_buffer; + buf->len = 0; + buf->size = FFMIN(size_auto, size_max); + buf->size_max = size_max; + *buf->str = 0; + if (size_init > buf->size) + av_bprint_alloc(buf, size_init - 1); +} + +void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size) +{ + if (size == 0) { + av_bprint_init(buf, 0, AV_BPRINT_SIZE_COUNT_ONLY); + return; + } + + buf->str = buffer; + buf->len = 0; + buf->size = size; + buf->size_max = size; + *buf->str = 0; +} + +void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg) +{ + unsigned room; + char *dst; + int extra_len; + va_list vl; + + while (1) { + room = av_bprint_room(buf); + dst = room ? buf->str + buf->len : NULL; + va_copy(vl, vl_arg); + extra_len = vsnprintf(dst, room, fmt, vl); + va_end(vl); + if (extra_len <= 0) + return; + if (extra_len < room) + break; + if (av_bprint_alloc(buf, extra_len)) + break; + } + av_bprint_grow(buf, extra_len); +} + +void av_bprintf(AVBPrint *buf, const char *fmt, ...) +{ + va_list vl; + va_start(vl, fmt); + av_vbprintf(buf, fmt, vl); + va_end(vl); +} + +void av_bprint_chars(AVBPrint *buf, char c, unsigned n) +{ + unsigned room, real_n; + + while (1) { + room = av_bprint_room(buf); + if (n < room) + break; + if (av_bprint_alloc(buf, n)) + break; + } + if (room) { + real_n = FFMIN(n, room - 1); + memset(buf->str + buf->len, c, real_n); + } + av_bprint_grow(buf, n); +} + +void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size) +{ + unsigned room, real_n; + + while (1) { + room = av_bprint_room(buf); + if (size < room) + break; + if (av_bprint_alloc(buf, size)) + break; + } + if (room) { + real_n = FFMIN(size, room - 1); + memcpy(buf->str + buf->len, data, real_n); + } + av_bprint_grow(buf, size); +} + +void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm) +{ + unsigned room; + size_t l; + size_t fmt_len = strlen(fmt); + + if (!*fmt) + return; + while (1) { + room = av_bprint_room(buf); + if (room && (l = strftime(buf->str + buf->len, room, fmt, tm))) + break; + + /* Due to the limitations of strftime() it is not possible to know if + * the output buffer is too small or the output is empty. + * However, a 256x output space requirement compared to the format + * string length is so unlikely we can safely assume empty output. This + * allows supporting possibly empty format strings like "%p". */ + if (room >> 8 > fmt_len) + break; + + /* strftime does not tell us how much room it would need: let us + retry with twice as much until the buffer is large enough */ + room = !room ? fmt_len + 1 : + room <= INT_MAX / 2 ? room * 2 : INT_MAX; + if (av_bprint_alloc(buf, room)) { + /* impossible to grow, try to manage something useful anyway */ + room = av_bprint_room(buf); + if (room < 1024) { + /* if strftime fails because the buffer has (almost) reached + its maximum size, let us try in a local buffer; 1k should + be enough to format any real date+time string */ + char buf2[1024]; + if ((l = strftime(buf2, sizeof(buf2), fmt, tm))) { + av_bprintf(buf, "%s", buf2); + return; + } + } + if (room) { + /* if anything else failed and the buffer is not already + truncated, let us add a stock string and force truncation */ + static const char txt[] = "[truncated strftime output]"; + memset(buf->str + buf->len, '!', room); + memcpy(buf->str + buf->len, txt, FFMIN(sizeof(txt) - 1, room)); + av_bprint_grow(buf, room); /* force truncation */ + } + return; + } + } + av_bprint_grow(buf, l); +} + +void av_bprint_get_buffer(AVBPrint *buf, unsigned size, + unsigned char **mem, unsigned *actual_size) +{ + if (size > av_bprint_room(buf)) + av_bprint_alloc(buf, size); + *actual_size = av_bprint_room(buf); + *mem = *actual_size ? buf->str + buf->len : NULL; +} + +void av_bprint_clear(AVBPrint *buf) +{ + if (buf->len) { + *buf->str = 0; + buf->len = 0; + } +} + +int av_bprint_finalize(AVBPrint *buf, char **ret_str) +{ + unsigned real_size = FFMIN(buf->len + 1, buf->size); + char *str; + int ret = 0; + + if (ret_str) { + if (av_bprint_is_allocated(buf)) { + str = av_realloc(buf->str, real_size); + if (!str) + str = buf->str; + buf->str = NULL; + } else { + str = av_memdup(buf->str, real_size); + if (!str) + ret = AVERROR(ENOMEM); + } + *ret_str = str; + } else { + if (av_bprint_is_allocated(buf)) + av_freep(&buf->str); + } + buf->size = real_size; + return ret; +} + +#define WHITESPACES " \n\t\r" + +void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags) +{ + const char *src0 = src; + + if (mode == AV_ESCAPE_MODE_AUTO) + mode = AV_ESCAPE_MODE_BACKSLASH; /* TODO: implement a heuristic */ + + switch (mode) { + case AV_ESCAPE_MODE_QUOTE: + /* enclose the string between '' */ + av_bprint_chars(dstbuf, '\'', 1); + for (; *src; src++) { + if (*src == '\'') + av_bprintf(dstbuf, "'\\''"); + else + av_bprint_chars(dstbuf, *src, 1); + } + av_bprint_chars(dstbuf, '\'', 1); + break; + + case AV_ESCAPE_MODE_XML: + /* escape XML non-markup character data as per 2.4 by default: */ + /* [^<&]* - ([^<&]* ']]>' [^<&]*) */ + + /* additionally, given one of the AV_ESCAPE_FLAG_XML_* flags, */ + /* escape those specific characters as required. */ + for (; *src; src++) { + switch (*src) { + case '&' : av_bprintf(dstbuf, "%s", "&"); break; + case '<' : av_bprintf(dstbuf, "%s", "<"); break; + case '>' : av_bprintf(dstbuf, "%s", ">"); break; + case '\'': + if (!(flags & AV_ESCAPE_FLAG_XML_SINGLE_QUOTES)) + goto XML_DEFAULT_HANDLING; + + av_bprintf(dstbuf, "%s", "'"); + break; + case '"' : + if (!(flags & AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES)) + goto XML_DEFAULT_HANDLING; + + av_bprintf(dstbuf, "%s", """); + break; +XML_DEFAULT_HANDLING: + default: av_bprint_chars(dstbuf, *src, 1); + } + } + break; + + /* case AV_ESCAPE_MODE_BACKSLASH or unknown mode */ + default: + /* \-escape characters */ + for (; *src; src++) { + int is_first_last = src == src0 || !*(src+1); + int is_ws = !!strchr(WHITESPACES, *src); + int is_strictly_special = special_chars && strchr(special_chars, *src); + int is_special = + is_strictly_special || strchr("'\\", *src) || + (is_ws && (flags & AV_ESCAPE_FLAG_WHITESPACE)); + + if (is_strictly_special || + (!(flags & AV_ESCAPE_FLAG_STRICT) && + (is_special || (is_ws && is_first_last)))) + av_bprint_chars(dstbuf, '\\', 1); + av_bprint_chars(dstbuf, *src, 1); + } + break; + } +} diff --git a/libs/ffmpeg/libavutil/bprint.h b/libs/ffmpeg/libavutil/bprint.h new file mode 100644 index 00000000000..4ac85705618 --- /dev/null +++ b/libs/ffmpeg/libavutil/bprint.h @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2012 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_avbprint + * AVBPrint public header + */ + +#ifndef AVUTIL_BPRINT_H +#define AVUTIL_BPRINT_H + +#include <stdarg.h> + +#include "attributes.h" +#include "avstring.h" + +/** + * @defgroup lavu_avbprint AVBPrint + * @ingroup lavu_data + * + * A buffer to print data progressively + * @{ + */ + +/** + * Define a structure with extra padding to a fixed size + * This helps ensuring binary compatibility with future versions. + */ + +#define FF_PAD_STRUCTURE(name, size, ...) \ +struct ff_pad_helper_##name { __VA_ARGS__ }; \ +typedef struct name { \ + __VA_ARGS__ \ + char reserved_padding[size - sizeof(struct ff_pad_helper_##name)]; \ +} name; + +/** + * Buffer to print data progressively + * + * The string buffer grows as necessary and is always 0-terminated. + * The content of the string is never accessed, and thus is + * encoding-agnostic and can even hold binary data. + * + * Small buffers are kept in the structure itself, and thus require no + * memory allocation at all (unless the contents of the buffer is needed + * after the structure goes out of scope). This is almost as lightweight as + * declaring a local `char buf[512]`. + * + * The length of the string can go beyond the allocated size: the buffer is + * then truncated, but the functions still keep account of the actual total + * length. + * + * In other words, AVBPrint.len can be greater than AVBPrint.size and records + * the total length of what would have been to the buffer if there had been + * enough memory. + * + * Append operations do not need to be tested for failure: if a memory + * allocation fails, data stop being appended to the buffer, but the length + * is still updated. This situation can be tested with + * av_bprint_is_complete(). + * + * The AVBPrint.size_max field determines several possible behaviours: + * - `size_max = -1` (= `UINT_MAX`) or any large value will let the buffer be + * reallocated as necessary, with an amortized linear cost. + * - `size_max = 0` prevents writing anything to the buffer: only the total + * length is computed. The write operations can then possibly be repeated in + * a buffer with exactly the necessary size + * (using `size_init = size_max = len + 1`). + * - `size_max = 1` is automatically replaced by the exact size available in the + * structure itself, thus ensuring no dynamic memory allocation. The + * internal buffer is large enough to hold a reasonable paragraph of text, + * such as the current paragraph. + */ + +FF_PAD_STRUCTURE(AVBPrint, 1024, + char *str; /**< string so far */ + unsigned len; /**< length so far */ + unsigned size; /**< allocated memory */ + unsigned size_max; /**< maximum allocated memory */ + char reserved_internal_buffer[1]; +) + +/** + * @name Max size special values + * Convenience macros for special values for av_bprint_init() size_max + * parameter. + * @{ + */ + +/** + * Buffer will be reallocated as necessary, with an amortized linear cost. + */ +#define AV_BPRINT_SIZE_UNLIMITED ((unsigned)-1) +/** + * Use the exact size available in the AVBPrint structure itself. + * + * Thus ensuring no dynamic memory allocation. The internal buffer is large + * enough to hold a reasonable paragraph of text, such as the current paragraph. + */ +#define AV_BPRINT_SIZE_AUTOMATIC 1 +/** + * Do not write anything to the buffer, only calculate the total length. + * + * The write operations can then possibly be repeated in a buffer with + * exactly the necessary size (using `size_init = size_max = AVBPrint.len + 1`). + */ +#define AV_BPRINT_SIZE_COUNT_ONLY 0 +/** @} */ + +/** + * Init a print buffer. + * + * @param buf buffer to init + * @param size_init initial size (including the final 0) + * @param size_max maximum size; + * - `0` means do not write anything, just count the length + * - `1` is replaced by the maximum value for automatic storage + * any large value means that the internal buffer will be + * reallocated as needed up to that limit + * - `-1` is converted to `UINT_MAX`, the largest limit possible. + * Check also `AV_BPRINT_SIZE_*` macros. + */ +void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max); + +/** + * Init a print buffer using a pre-existing buffer. + * + * The buffer will not be reallocated. + * In case size equals zero, the AVBPrint will be initialized to use + * the internal buffer as if using AV_BPRINT_SIZE_COUNT_ONLY with + * av_bprint_init(). + * + * @param buf buffer structure to init + * @param buffer byte buffer to use for the string data + * @param size size of buffer + */ +void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size); + +/** + * Append a formatted string to a print buffer. + */ +void av_bprintf(AVBPrint *buf, const char *fmt, ...) av_printf_format(2, 3); + +/** + * Append a formatted string to a print buffer. + */ +void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg); + +/** + * Append char c n times to a print buffer. + */ +void av_bprint_chars(AVBPrint *buf, char c, unsigned n); + +/** + * Append data to a print buffer. + * + * @param buf bprint buffer to use + * @param data pointer to data + * @param size size of data + */ +void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size); + +struct tm; +/** + * Append a formatted date and time to a print buffer. + * + * @param buf bprint buffer to use + * @param fmt date and time format string, see strftime() + * @param tm broken-down time structure to translate + * + * @note due to poor design of the standard strftime function, it may + * produce poor results if the format string expands to a very long text and + * the bprint buffer is near the limit stated by the size_max option. + */ +void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm); + +/** + * Allocate bytes in the buffer for external use. + * + * @param[in] buf buffer structure + * @param[in] size required size + * @param[out] mem pointer to the memory area + * @param[out] actual_size size of the memory area after allocation; + * can be larger or smaller than size + */ +void av_bprint_get_buffer(AVBPrint *buf, unsigned size, + unsigned char **mem, unsigned *actual_size); + +/** + * Reset the string to "" but keep internal allocated data. + */ +void av_bprint_clear(AVBPrint *buf); + +/** + * Test if the print buffer is complete (not truncated). + * + * It may have been truncated due to a memory allocation failure + * or the size_max limit (compare size and size_max if necessary). + */ +static inline int av_bprint_is_complete(const AVBPrint *buf) +{ + return buf->len < buf->size; +} + +/** + * Finalize a print buffer. + * + * The print buffer can no longer be used afterwards, + * but the len and size fields are still valid. + * + * @arg[out] ret_str if not NULL, used to return a permanent copy of the + * buffer contents, or NULL if memory allocation fails; + * if NULL, the buffer is discarded and freed + * @return 0 for success or error code (probably AVERROR(ENOMEM)) + */ +int av_bprint_finalize(AVBPrint *buf, char **ret_str); + +/** + * Escape the content in src and append it to dstbuf. + * + * @param dstbuf already inited destination bprint buffer + * @param src string containing the text to escape + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_* macros + */ +void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +/** @} */ + +#endif /* AVUTIL_BPRINT_H */ diff --git a/libs/ffmpeg/libavutil/bswap.h b/libs/ffmpeg/libavutil/bswap.h new file mode 100644 index 00000000000..c1e6591ce00 --- /dev/null +++ b/libs/ffmpeg/libavutil/bswap.h @@ -0,0 +1,105 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * byte swapping routines + */ + +#ifndef AVUTIL_BSWAP_H +#define AVUTIL_BSWAP_H + +#include <stdint.h> +#include "libavutil/avconfig.h" +#include "attributes.h" + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_ARM +# include "arm/bswap.h" +#elif ARCH_RISCV +# include "riscv/bswap.h" +#elif ARCH_X86 +# include "x86/bswap.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +#define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) +#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16)) +#define AV_BSWAP64C(x) (AV_BSWAP32C(x) << 32 | AV_BSWAP32C((x) >> 32)) + +#define AV_BSWAPC(s, x) AV_BSWAP##s##C(x) + +#ifndef av_bswap16 +static av_always_inline av_const uint16_t av_bswap16(uint16_t x) +{ + x= (x>>8) | (x<<8); + return x; +} +#endif + +#ifndef av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + return AV_BSWAP32C(x); +} +#endif + +#ifndef av_bswap64 +static inline uint64_t av_const av_bswap64(uint64_t x) +{ + return (uint64_t)av_bswap32((uint32_t)x) << 32 | av_bswap32((uint32_t)(x >> 32)); +} +#endif + +// be2ne ... big-endian to native-endian +// le2ne ... little-endian to native-endian + +#if AV_HAVE_BIGENDIAN +#define av_be2ne16(x) (x) +#define av_be2ne32(x) (x) +#define av_be2ne64(x) (x) +#define av_le2ne16(x) av_bswap16(x) +#define av_le2ne32(x) av_bswap32(x) +#define av_le2ne64(x) av_bswap64(x) +#define AV_BE2NEC(s, x) (x) +#define AV_LE2NEC(s, x) AV_BSWAPC(s, x) +#else +#define av_be2ne16(x) av_bswap16(x) +#define av_be2ne32(x) av_bswap32(x) +#define av_be2ne64(x) av_bswap64(x) +#define av_le2ne16(x) (x) +#define av_le2ne32(x) (x) +#define av_le2ne64(x) (x) +#define AV_BE2NEC(s, x) AV_BSWAPC(s, x) +#define AV_LE2NEC(s, x) (x) +#endif + +#define AV_BE2NE16C(x) AV_BE2NEC(16, x) +#define AV_BE2NE32C(x) AV_BE2NEC(32, x) +#define AV_BE2NE64C(x) AV_BE2NEC(64, x) +#define AV_LE2NE16C(x) AV_LE2NEC(16, x) +#define AV_LE2NE32C(x) AV_LE2NEC(32, x) +#define AV_LE2NE64C(x) AV_LE2NEC(64, x) + +#endif /* AVUTIL_BSWAP_H */ diff --git a/libs/ffmpeg/libavutil/buffer.c b/libs/ffmpeg/libavutil/buffer.c new file mode 100644 index 00000000000..a8101d83f01 --- /dev/null +++ b/libs/ffmpeg/libavutil/buffer.c @@ -0,0 +1,422 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdatomic.h> +#include <stdint.h> +#include <string.h> + +#include "avassert.h" +#include "buffer_internal.h" +#include "common.h" +#include "mem.h" +#include "thread.h" + +static AVBufferRef *buffer_create(AVBuffer *buf, uint8_t *data, size_t size, + void (*free)(void *opaque, uint8_t *data), + void *opaque, int flags) +{ + AVBufferRef *ref = NULL; + + buf->data = data; + buf->size = size; + buf->free = free ? free : av_buffer_default_free; + buf->opaque = opaque; + + atomic_init(&buf->refcount, 1); + + buf->flags = flags; + + ref = av_mallocz(sizeof(*ref)); + if (!ref) + return NULL; + + ref->buffer = buf; + ref->data = data; + ref->size = size; + + return ref; +} + +AVBufferRef *av_buffer_create(uint8_t *data, size_t size, + void (*free)(void *opaque, uint8_t *data), + void *opaque, int flags) +{ + AVBufferRef *ret; + AVBuffer *buf = av_mallocz(sizeof(*buf)); + if (!buf) + return NULL; + + ret = buffer_create(buf, data, size, free, opaque, flags); + if (!ret) { + av_free(buf); + return NULL; + } + return ret; +} + +void av_buffer_default_free(void *opaque, uint8_t *data) +{ + av_free(data); +} + +AVBufferRef *av_buffer_alloc(size_t size) +{ + AVBufferRef *ret = NULL; + uint8_t *data = NULL; + + data = av_malloc(size); + if (!data) + return NULL; + + ret = av_buffer_create(data, size, av_buffer_default_free, NULL, 0); + if (!ret) + av_freep(&data); + + return ret; +} + +AVBufferRef *av_buffer_allocz(size_t size) +{ + AVBufferRef *ret = av_buffer_alloc(size); + if (!ret) + return NULL; + + memset(ret->data, 0, size); + return ret; +} + +AVBufferRef *av_buffer_ref(const AVBufferRef *buf) +{ + AVBufferRef *ret = av_mallocz(sizeof(*ret)); + + if (!ret) + return NULL; + + *ret = *buf; + + atomic_fetch_add_explicit(&buf->buffer->refcount, 1, memory_order_relaxed); + + return ret; +} + +static void buffer_replace(AVBufferRef **dst, AVBufferRef **src) +{ + AVBuffer *b; + + b = (*dst)->buffer; + + if (src) { + **dst = **src; + av_freep(src); + } else + av_freep(dst); + + if (atomic_fetch_sub_explicit(&b->refcount, 1, memory_order_acq_rel) == 1) { + /* b->free below might already free the structure containing *b, + * so we have to read the flag now to avoid use-after-free. */ + int free_avbuffer = !(b->flags_internal & BUFFER_FLAG_NO_FREE); + b->free(b->opaque, b->data); + if (free_avbuffer) + av_free(b); + } +} + +void av_buffer_unref(AVBufferRef **buf) +{ + if (!buf || !*buf) + return; + + buffer_replace(buf, NULL); +} + +int av_buffer_is_writable(const AVBufferRef *buf) +{ + if (buf->buffer->flags & AV_BUFFER_FLAG_READONLY) + return 0; + + return atomic_load(&buf->buffer->refcount) == 1; +} + +void *av_buffer_get_opaque(const AVBufferRef *buf) +{ + return buf->buffer->opaque; +} + +int av_buffer_get_ref_count(const AVBufferRef *buf) +{ + return atomic_load(&buf->buffer->refcount); +} + +int av_buffer_make_writable(AVBufferRef **pbuf) +{ + AVBufferRef *newbuf, *buf = *pbuf; + + if (av_buffer_is_writable(buf)) + return 0; + + newbuf = av_buffer_alloc(buf->size); + if (!newbuf) + return AVERROR(ENOMEM); + + memcpy(newbuf->data, buf->data, buf->size); + + buffer_replace(pbuf, &newbuf); + + return 0; +} + +int av_buffer_realloc(AVBufferRef **pbuf, size_t size) +{ + AVBufferRef *buf = *pbuf; + uint8_t *tmp; + int ret; + + if (!buf) { + /* allocate a new buffer with av_realloc(), so it will be reallocatable + * later */ + uint8_t *data = av_realloc(NULL, size); + if (!data) + return AVERROR(ENOMEM); + + buf = av_buffer_create(data, size, av_buffer_default_free, NULL, 0); + if (!buf) { + av_freep(&data); + return AVERROR(ENOMEM); + } + + buf->buffer->flags_internal |= BUFFER_FLAG_REALLOCATABLE; + *pbuf = buf; + + return 0; + } else if (buf->size == size) + return 0; + + if (!(buf->buffer->flags_internal & BUFFER_FLAG_REALLOCATABLE) || + !av_buffer_is_writable(buf) || buf->data != buf->buffer->data) { + /* cannot realloc, allocate a new reallocable buffer and copy data */ + AVBufferRef *new = NULL; + + ret = av_buffer_realloc(&new, size); + if (ret < 0) + return ret; + + memcpy(new->data, buf->data, FFMIN(size, buf->size)); + + buffer_replace(pbuf, &new); + return 0; + } + + tmp = av_realloc(buf->buffer->data, size); + if (!tmp) + return AVERROR(ENOMEM); + + buf->buffer->data = buf->data = tmp; + buf->buffer->size = buf->size = size; + return 0; +} + +int av_buffer_replace(AVBufferRef **pdst, const AVBufferRef *src) +{ + AVBufferRef *dst = *pdst; + AVBufferRef *tmp; + + if (!src) { + av_buffer_unref(pdst); + return 0; + } + + if (dst && dst->buffer == src->buffer) { + /* make sure the data pointers match */ + dst->data = src->data; + dst->size = src->size; + return 0; + } + + tmp = av_buffer_ref(src); + if (!tmp) + return AVERROR(ENOMEM); + + av_buffer_unref(pdst); + *pdst = tmp; + return 0; +} + +AVBufferPool *av_buffer_pool_init2(size_t size, void *opaque, + AVBufferRef* (*alloc)(void *opaque, size_t size), + void (*pool_free)(void *opaque)) +{ + AVBufferPool *pool = av_mallocz(sizeof(*pool)); + if (!pool) + return NULL; + + if (ff_mutex_init(&pool->mutex, NULL)) { + av_free(pool); + return NULL; + } + + pool->size = size; + pool->opaque = opaque; + pool->alloc2 = alloc; + pool->alloc = av_buffer_alloc; // fallback + pool->pool_free = pool_free; + + atomic_init(&pool->refcount, 1); + + return pool; +} + +AVBufferPool *av_buffer_pool_init(size_t size, AVBufferRef* (*alloc)(size_t size)) +{ + AVBufferPool *pool = av_mallocz(sizeof(*pool)); + if (!pool) + return NULL; + + if (ff_mutex_init(&pool->mutex, NULL)) { + av_free(pool); + return NULL; + } + + pool->size = size; + pool->alloc = alloc ? alloc : av_buffer_alloc; + + atomic_init(&pool->refcount, 1); + + return pool; +} + +static void buffer_pool_flush(AVBufferPool *pool) +{ + while (pool->pool) { + BufferPoolEntry *buf = pool->pool; + pool->pool = buf->next; + + buf->free(buf->opaque, buf->data); + av_freep(&buf); + } +} + +/* + * This function gets called when the pool has been uninited and + * all the buffers returned to it. + */ +static void buffer_pool_free(AVBufferPool *pool) +{ + buffer_pool_flush(pool); + ff_mutex_destroy(&pool->mutex); + + if (pool->pool_free) + pool->pool_free(pool->opaque); + + av_freep(&pool); +} + +void av_buffer_pool_uninit(AVBufferPool **ppool) +{ + AVBufferPool *pool; + + if (!ppool || !*ppool) + return; + pool = *ppool; + *ppool = NULL; + + ff_mutex_lock(&pool->mutex); + buffer_pool_flush(pool); + ff_mutex_unlock(&pool->mutex); + + if (atomic_fetch_sub_explicit(&pool->refcount, 1, memory_order_acq_rel) == 1) + buffer_pool_free(pool); +} + +static void pool_release_buffer(void *opaque, uint8_t *data) +{ + BufferPoolEntry *buf = opaque; + AVBufferPool *pool = buf->pool; + + ff_mutex_lock(&pool->mutex); + buf->next = pool->pool; + pool->pool = buf; + ff_mutex_unlock(&pool->mutex); + + if (atomic_fetch_sub_explicit(&pool->refcount, 1, memory_order_acq_rel) == 1) + buffer_pool_free(pool); +} + +/* allocate a new buffer and override its free() callback so that + * it is returned to the pool on free */ +static AVBufferRef *pool_alloc_buffer(AVBufferPool *pool) +{ + BufferPoolEntry *buf; + AVBufferRef *ret; + + av_assert0(pool->alloc || pool->alloc2); + + ret = pool->alloc2 ? pool->alloc2(pool->opaque, pool->size) : + pool->alloc(pool->size); + if (!ret) + return NULL; + + buf = av_mallocz(sizeof(*buf)); + if (!buf) { + av_buffer_unref(&ret); + return NULL; + } + + buf->data = ret->buffer->data; + buf->opaque = ret->buffer->opaque; + buf->free = ret->buffer->free; + buf->pool = pool; + + ret->buffer->opaque = buf; + ret->buffer->free = pool_release_buffer; + + return ret; +} + +AVBufferRef *av_buffer_pool_get(AVBufferPool *pool) +{ + AVBufferRef *ret; + BufferPoolEntry *buf; + + ff_mutex_lock(&pool->mutex); + buf = pool->pool; + if (buf) { + memset(&buf->buffer, 0, sizeof(buf->buffer)); + ret = buffer_create(&buf->buffer, buf->data, pool->size, + pool_release_buffer, buf, 0); + if (ret) { + pool->pool = buf->next; + buf->next = NULL; + buf->buffer.flags_internal |= BUFFER_FLAG_NO_FREE; + } + } else { + ret = pool_alloc_buffer(pool); + } + ff_mutex_unlock(&pool->mutex); + + if (ret) + atomic_fetch_add_explicit(&pool->refcount, 1, memory_order_relaxed); + + return ret; +} + +void *av_buffer_pool_buffer_get_opaque(const AVBufferRef *ref) +{ + BufferPoolEntry *buf = ref->buffer->opaque; + av_assert0(buf); + return buf->opaque; +} diff --git a/libs/ffmpeg/libavutil/buffer.h b/libs/ffmpeg/libavutil/buffer.h new file mode 100644 index 00000000000..e1ef5b7f07f --- /dev/null +++ b/libs/ffmpeg/libavutil/buffer.h @@ -0,0 +1,322 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_buffer + * refcounted data buffer API + */ + +#ifndef AVUTIL_BUFFER_H +#define AVUTIL_BUFFER_H + +#include <stddef.h> +#include <stdint.h> + +/** + * @defgroup lavu_buffer AVBuffer + * @ingroup lavu_data + * + * @{ + * AVBuffer is an API for reference-counted data buffers. + * + * There are two core objects in this API -- AVBuffer and AVBufferRef. AVBuffer + * represents the data buffer itself; it is opaque and not meant to be accessed + * by the caller directly, but only through AVBufferRef. However, the caller may + * e.g. compare two AVBuffer pointers to check whether two different references + * are describing the same data buffer. AVBufferRef represents a single + * reference to an AVBuffer and it is the object that may be manipulated by the + * caller directly. + * + * There are two functions provided for creating a new AVBuffer with a single + * reference -- av_buffer_alloc() to just allocate a new buffer, and + * av_buffer_create() to wrap an existing array in an AVBuffer. From an existing + * reference, additional references may be created with av_buffer_ref(). + * Use av_buffer_unref() to free a reference (this will automatically free the + * data once all the references are freed). + * + * The convention throughout this API and the rest of FFmpeg is such that the + * buffer is considered writable if there exists only one reference to it (and + * it has not been marked as read-only). The av_buffer_is_writable() function is + * provided to check whether this is true and av_buffer_make_writable() will + * automatically create a new writable buffer when necessary. + * Of course nothing prevents the calling code from violating this convention, + * however that is safe only when all the existing references are under its + * control. + * + * @note Referencing and unreferencing the buffers is thread-safe and thus + * may be done from multiple threads simultaneously without any need for + * additional locking. + * + * @note Two different references to the same buffer can point to different + * parts of the buffer (i.e. their AVBufferRef.data will not be equal). + */ + +/** + * A reference counted buffer type. It is opaque and is meant to be used through + * references (AVBufferRef). + */ +typedef struct AVBuffer AVBuffer; + +/** + * A reference to a data buffer. + * + * The size of this struct is not a part of the public ABI and it is not meant + * to be allocated directly. + */ +typedef struct AVBufferRef { + AVBuffer *buffer; + + /** + * The data buffer. It is considered writable if and only if + * this is the only reference to the buffer, in which case + * av_buffer_is_writable() returns 1. + */ + uint8_t *data; + /** + * Size of data in bytes. + */ + size_t size; +} AVBufferRef; + +/** + * Allocate an AVBuffer of the given size using av_malloc(). + * + * @return an AVBufferRef of given size or NULL when out of memory + */ +AVBufferRef *av_buffer_alloc(size_t size); + +/** + * Same as av_buffer_alloc(), except the returned buffer will be initialized + * to zero. + */ +AVBufferRef *av_buffer_allocz(size_t size); + +/** + * Always treat the buffer as read-only, even when it has only one + * reference. + */ +#define AV_BUFFER_FLAG_READONLY (1 << 0) + +/** + * Create an AVBuffer from an existing array. + * + * If this function is successful, data is owned by the AVBuffer. The caller may + * only access data through the returned AVBufferRef and references derived from + * it. + * If this function fails, data is left untouched. + * @param data data array + * @param size size of data in bytes + * @param free a callback for freeing this buffer's data + * @param opaque parameter to be got for processing or passed to free + * @param flags a combination of AV_BUFFER_FLAG_* + * + * @return an AVBufferRef referring to data on success, NULL on failure. + */ +AVBufferRef *av_buffer_create(uint8_t *data, size_t size, + void (*free)(void *opaque, uint8_t *data), + void *opaque, int flags); + +/** + * Default free callback, which calls av_free() on the buffer data. + * This function is meant to be passed to av_buffer_create(), not called + * directly. + */ +void av_buffer_default_free(void *opaque, uint8_t *data); + +/** + * Create a new reference to an AVBuffer. + * + * @return a new AVBufferRef referring to the same AVBuffer as buf or NULL on + * failure. + */ +AVBufferRef *av_buffer_ref(const AVBufferRef *buf); + +/** + * Free a given reference and automatically free the buffer if there are no more + * references to it. + * + * @param buf the reference to be freed. The pointer is set to NULL on return. + */ +void av_buffer_unref(AVBufferRef **buf); + +/** + * @return 1 if the caller may write to the data referred to by buf (which is + * true if and only if buf is the only reference to the underlying AVBuffer). + * Return 0 otherwise. + * A positive answer is valid until av_buffer_ref() is called on buf. + */ +int av_buffer_is_writable(const AVBufferRef *buf); + +/** + * @return the opaque parameter set by av_buffer_create. + */ +void *av_buffer_get_opaque(const AVBufferRef *buf); + +int av_buffer_get_ref_count(const AVBufferRef *buf); + +/** + * Create a writable reference from a given buffer reference, avoiding data copy + * if possible. + * + * @param buf buffer reference to make writable. On success, buf is either left + * untouched, or it is unreferenced and a new writable AVBufferRef is + * written in its place. On failure, buf is left untouched. + * @return 0 on success, a negative AVERROR on failure. + */ +int av_buffer_make_writable(AVBufferRef **buf); + +/** + * Reallocate a given buffer. + * + * @param buf a buffer reference to reallocate. On success, buf will be + * unreferenced and a new reference with the required size will be + * written in its place. On failure buf will be left untouched. *buf + * may be NULL, then a new buffer is allocated. + * @param size required new buffer size. + * @return 0 on success, a negative AVERROR on failure. + * + * @note the buffer is actually reallocated with av_realloc() only if it was + * initially allocated through av_buffer_realloc(NULL) and there is only one + * reference to it (i.e. the one passed to this function). In all other cases + * a new buffer is allocated and the data is copied. + */ +int av_buffer_realloc(AVBufferRef **buf, size_t size); + +/** + * Ensure dst refers to the same data as src. + * + * When *dst is already equivalent to src, do nothing. Otherwise unreference dst + * and replace it with a new reference to src. + * + * @param dst Pointer to either a valid buffer reference or NULL. On success, + * this will point to a buffer reference equivalent to src. On + * failure, dst will be left untouched. + * @param src A buffer reference to replace dst with. May be NULL, then this + * function is equivalent to av_buffer_unref(dst). + * @return 0 on success + * AVERROR(ENOMEM) on memory allocation failure. + */ +int av_buffer_replace(AVBufferRef **dst, const AVBufferRef *src); + +/** + * @} + */ + +/** + * @defgroup lavu_bufferpool AVBufferPool + * @ingroup lavu_data + * + * @{ + * AVBufferPool is an API for a lock-free thread-safe pool of AVBuffers. + * + * Frequently allocating and freeing large buffers may be slow. AVBufferPool is + * meant to solve this in cases when the caller needs a set of buffers of the + * same size (the most obvious use case being buffers for raw video or audio + * frames). + * + * At the beginning, the user must call av_buffer_pool_init() to create the + * buffer pool. Then whenever a buffer is needed, call av_buffer_pool_get() to + * get a reference to a new buffer, similar to av_buffer_alloc(). This new + * reference works in all aspects the same way as the one created by + * av_buffer_alloc(). However, when the last reference to this buffer is + * unreferenced, it is returned to the pool instead of being freed and will be + * reused for subsequent av_buffer_pool_get() calls. + * + * When the caller is done with the pool and no longer needs to allocate any new + * buffers, av_buffer_pool_uninit() must be called to mark the pool as freeable. + * Once all the buffers are released, it will automatically be freed. + * + * Allocating and releasing buffers with this API is thread-safe as long as + * either the default alloc callback is used, or the user-supplied one is + * thread-safe. + */ + +/** + * The buffer pool. This structure is opaque and not meant to be accessed + * directly. It is allocated with av_buffer_pool_init() and freed with + * av_buffer_pool_uninit(). + */ +typedef struct AVBufferPool AVBufferPool; + +/** + * Allocate and initialize a buffer pool. + * + * @param size size of each buffer in this pool + * @param alloc a function that will be used to allocate new buffers when the + * pool is empty. May be NULL, then the default allocator will be used + * (av_buffer_alloc()). + * @return newly created buffer pool on success, NULL on error. + */ +AVBufferPool *av_buffer_pool_init(size_t size, AVBufferRef* (*alloc)(size_t size)); + +/** + * Allocate and initialize a buffer pool with a more complex allocator. + * + * @param size size of each buffer in this pool + * @param opaque arbitrary user data used by the allocator + * @param alloc a function that will be used to allocate new buffers when the + * pool is empty. May be NULL, then the default allocator will be + * used (av_buffer_alloc()). + * @param pool_free a function that will be called immediately before the pool + * is freed. I.e. after av_buffer_pool_uninit() is called + * by the caller and all the frames are returned to the pool + * and freed. It is intended to uninitialize the user opaque + * data. May be NULL. + * @return newly created buffer pool on success, NULL on error. + */ +AVBufferPool *av_buffer_pool_init2(size_t size, void *opaque, + AVBufferRef* (*alloc)(void *opaque, size_t size), + void (*pool_free)(void *opaque)); + +/** + * Mark the pool as being available for freeing. It will actually be freed only + * once all the allocated buffers associated with the pool are released. Thus it + * is safe to call this function while some of the allocated buffers are still + * in use. + * + * @param pool pointer to the pool to be freed. It will be set to NULL. + */ +void av_buffer_pool_uninit(AVBufferPool **pool); + +/** + * Allocate a new AVBuffer, reusing an old buffer from the pool when available. + * This function may be called simultaneously from multiple threads. + * + * @return a reference to the new buffer on success, NULL on error. + */ +AVBufferRef *av_buffer_pool_get(AVBufferPool *pool); + +/** + * Query the original opaque parameter of an allocated buffer in the pool. + * + * @param ref a buffer reference to a buffer returned by av_buffer_pool_get. + * @return the opaque parameter set by the buffer allocator function of the + * buffer pool. + * + * @note the opaque parameter of ref is used by the buffer pool implementation, + * therefore you have to use this function to access the original opaque + * parameter of an allocated buffer. + */ +void *av_buffer_pool_buffer_get_opaque(const AVBufferRef *ref); + +/** + * @} + */ + +#endif /* AVUTIL_BUFFER_H */ diff --git a/libs/ffmpeg/libavutil/buffer_internal.h b/libs/ffmpeg/libavutil/buffer_internal.h new file mode 100644 index 00000000000..adb916aaa22 --- /dev/null +++ b/libs/ffmpeg/libavutil/buffer_internal.h @@ -0,0 +1,110 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BUFFER_INTERNAL_H +#define AVUTIL_BUFFER_INTERNAL_H + +#include <stdatomic.h> +#include <stdint.h> + +#include "buffer.h" +#include "thread.h" + +/** + * The buffer was av_realloc()ed, so it is reallocatable. + */ +#define BUFFER_FLAG_REALLOCATABLE (1 << 0) +/** + * The AVBuffer structure is part of a larger structure + * and should not be freed. + */ +#define BUFFER_FLAG_NO_FREE (1 << 1) + +struct AVBuffer { + uint8_t *data; /**< data described by this buffer */ + size_t size; /**< size of data in bytes */ + + /** + * number of existing AVBufferRef instances referring to this buffer + */ + atomic_uint refcount; + + /** + * a callback for freeing the data + */ + void (*free)(void *opaque, uint8_t *data); + + /** + * an opaque pointer, to be used by the freeing callback + */ + void *opaque; + + /** + * A combination of AV_BUFFER_FLAG_* + */ + int flags; + + /** + * A combination of BUFFER_FLAG_* + */ + int flags_internal; +}; + +typedef struct BufferPoolEntry { + uint8_t *data; + + /* + * Backups of the original opaque/free of the AVBuffer corresponding to + * data. They will be used to free the buffer when the pool is freed. + */ + void *opaque; + void (*free)(void *opaque, uint8_t *data); + + AVBufferPool *pool; + struct BufferPoolEntry *next; + + /* + * An AVBuffer structure to (re)use as AVBuffer for subsequent uses + * of this BufferPoolEntry. + */ + AVBuffer buffer; +} BufferPoolEntry; + +struct AVBufferPool { + AVMutex mutex; + BufferPoolEntry *pool; + + /* + * This is used to track when the pool is to be freed. + * The pointer to the pool itself held by the caller is considered to + * be one reference. Each buffer requested by the caller increases refcount + * by one, returning the buffer to the pool decreases it by one. + * refcount reaches zero when the buffer has been uninited AND all the + * buffers have been released, then it's safe to free the pool and all + * the buffers in it. + */ + atomic_uint refcount; + + size_t size; + void *opaque; + AVBufferRef* (*alloc)(size_t size); + AVBufferRef* (*alloc2)(void *opaque, size_t size); + void (*pool_free)(void *opaque); +}; + +#endif /* AVUTIL_BUFFER_INTERNAL_H */ diff --git a/libs/ffmpeg/libavutil/camellia.c b/libs/ffmpeg/libavutil/camellia.c new file mode 100644 index 00000000000..3fc3b082913 --- /dev/null +++ b/libs/ffmpeg/libavutil/camellia.c @@ -0,0 +1,416 @@ +/* + * An implementation of the CAMELLIA algorithm as mentioned in RFC3713 + * Copyright (c) 2014 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> + +#include "camellia.h" +#include "error.h" +#include "intreadwrite.h" +#include "mem.h" +#include "attributes.h" + +#define LR32(x,c) ((x) << (c) | (x) >> (32 - (c))) +#define RR32(x,c) ((x) >> (c) | (x) << (32 - (c))) + +#define MASK8 0xff +#define MASK32 0xffffffff +#define MASK64 0xffffffffffffffff + +#define Sigma1 0xA09E667F3BCC908B +#define Sigma2 0xB67AE8584CAA73B2 +#define Sigma3 0xC6EF372FE94F82BE +#define Sigma4 0x54FF53A5F1D36F1C +#define Sigma5 0x10E527FADE682D1D +#define Sigma6 0xB05688C2B3E6C1FD + +static uint64_t SP[8][256]; + +typedef struct AVCAMELLIA { + uint64_t Kw[4]; + uint64_t Ke[6]; + uint64_t K[24]; + int key_bits; +} AVCAMELLIA; + +static const uint8_t SBOX1[256] = { +112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, 174, 65, + 35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, 29, 101, 146, 189, +134, 184, 175, 143, 124, 235, 31, 206, 62, 48, 220, 95, 94, 197, 11, 26, +166, 225, 57, 202, 213, 71, 93, 61, 217, 1, 90, 214, 81, 86, 108, 77, +139, 13, 154, 102, 251, 204, 176, 45, 116, 18, 43, 32, 240, 177, 132, 153, +223, 76, 203, 194, 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215, + 20, 88, 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34, +254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, 105, 80, +170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, 224, 255, 100, 210, + 16, 196, 0, 72, 163, 247, 117, 219, 138, 3, 230, 218, 9, 63, 221, 148, +135, 92, 131, 2, 205, 74, 144, 51, 115, 103, 246, 243, 157, 127, 191, 226, + 82, 155, 216, 38, 200, 55, 198, 59, 129, 150, 111, 75, 19, 190, 99, 46, +233, 121, 167, 140, 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89, +120, 152, 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250, +114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, 241, 164, + 64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, 119, 199, 128, 158 +}; + +static const uint8_t SBOX2[256] = { +224, 5, 88, 217, 103, 78, 129, 203, 201, 11, 174, 106, 213, 24, 93, 130, + 70, 223, 214, 39, 138, 50, 75, 66, 219, 28, 158, 156, 58, 202, 37, 123, + 13, 113, 95, 31, 248, 215, 62, 157, 124, 96, 185, 190, 188, 139, 22, 52, + 77, 195, 114, 149, 171, 142, 186, 122, 179, 2, 180, 173, 162, 172, 216, 154, + 23, 26, 53, 204, 247, 153, 97, 90, 232, 36, 86, 64, 225, 99, 9, 51, +191, 152, 151, 133, 104, 252, 236, 10, 218, 111, 83, 98, 163, 46, 8, 175, + 40, 176, 116, 194, 189, 54, 34, 56, 100, 30, 57, 44, 166, 48, 229, 68, +253, 136, 159, 101, 135, 107, 244, 35, 72, 16, 209, 81, 192, 249, 210, 160, + 85, 161, 65, 250, 67, 19, 196, 47, 168, 182, 60, 43, 193, 255, 200, 165, + 32, 137, 0, 144, 71, 239, 234, 183, 21, 6, 205, 181, 18, 126, 187, 41, + 15, 184, 7, 4, 155, 148, 33, 102, 230, 206, 237, 231, 59, 254, 127, 197, +164, 55, 177, 76, 145, 110, 141, 118, 3, 45, 222, 150, 38, 125, 198, 92, +211, 242, 79, 25, 63, 220, 121, 29, 82, 235, 243, 109, 94, 251, 105, 178, +240, 49, 12, 212, 207, 140, 226, 117, 169, 74, 87, 132, 17, 69, 27, 245, +228, 14, 115, 170, 241, 221, 89, 20, 108, 146, 84, 208, 120, 112, 227, 73, +128, 80, 167, 246, 119, 147, 134, 131, 42, 199, 91, 233, 238, 143, 1, 61 +}; + +static const uint8_t SBOX3[256] = { + 56, 65, 22, 118, 217, 147, 96, 242, 114, 194, 171, 154, 117, 6, 87, 160, +145, 247, 181, 201, 162, 140, 210, 144, 246, 7, 167, 39, 142, 178, 73, 222, + 67, 92, 215, 199, 62, 245, 143, 103, 31, 24, 110, 175, 47, 226, 133, 13, + 83, 240, 156, 101, 234, 163, 174, 158, 236, 128, 45, 107, 168, 43, 54, 166, +197, 134, 77, 51, 253, 102, 88, 150, 58, 9, 149, 16, 120, 216, 66, 204, +239, 38, 229, 97, 26, 63, 59, 130, 182, 219, 212, 152, 232, 139, 2, 235, + 10, 44, 29, 176, 111, 141, 136, 14, 25, 135, 78, 11, 169, 12, 121, 17, +127, 34, 231, 89, 225, 218, 61, 200, 18, 4, 116, 84, 48, 126, 180, 40, + 85, 104, 80, 190, 208, 196, 49, 203, 42, 173, 15, 202, 112, 255, 50, 105, + 8, 98, 0, 36, 209, 251, 186, 237, 69, 129, 115, 109, 132, 159, 238, 74, +195, 46, 193, 1, 230, 37, 72, 153, 185, 179, 123, 249, 206, 191, 223, 113, + 41, 205, 108, 19, 100, 155, 99, 157, 192, 75, 183, 165, 137, 95, 177, 23, +244, 188, 211, 70, 207, 55, 94, 71, 148, 250, 252, 91, 151, 254, 90, 172, + 60, 76, 3, 53, 243, 35, 184, 93, 106, 146, 213, 33, 68, 81, 198, 125, + 57, 131, 220, 170, 124, 119, 86, 5, 27, 164, 21, 52, 30, 28, 248, 82, + 32, 20, 233, 189, 221, 228, 161, 224, 138, 241, 214, 122, 187, 227, 64, 79 +}; + +static const uint8_t SBOX4[256] = { +112, 44, 179, 192, 228, 87, 234, 174, 35, 107, 69, 165, 237, 79, 29, 146, +134, 175, 124, 31, 62, 220, 94, 11, 166, 57, 213, 93, 217, 90, 81, 108, +139, 154, 251, 176, 116, 43, 240, 132, 223, 203, 52, 118, 109, 169, 209, 4, + 20, 58, 222, 17, 50, 156, 83, 242, 254, 207, 195, 122, 36, 232, 96, 105, +170, 160, 161, 98, 84, 30, 224, 100, 16, 0, 163, 117, 138, 230, 9, 221, +135, 131, 205, 144, 115, 246, 157, 191, 82, 216, 200, 198, 129, 111, 19, 99, +233, 167, 159, 188, 41, 249, 47, 180, 120, 6, 231, 113, 212, 171, 136, 141, +114, 185, 248, 172, 54, 42, 60, 241, 64, 211, 187, 67, 21, 173, 119, 128, +130, 236, 39, 229, 133, 53, 12, 65, 239, 147, 25, 33, 14, 78, 101, 189, +184, 143, 235, 206, 48, 95, 197, 26, 225, 202, 71, 61, 1, 214, 86, 77, + 13, 102, 204, 45, 18, 32, 177, 153, 76, 194, 126, 5, 183, 49, 23, 215, + 88, 97, 27, 28, 15, 22, 24, 34, 68, 178, 181, 145, 8, 168, 252, 80, +208, 125, 137, 151, 91, 149, 255, 210, 196, 72, 247, 219, 3, 218, 63, 148, + 92, 2, 74, 51, 103, 243, 127, 226, 155, 38, 55, 59, 150, 75, 190, 46, +121, 140, 110, 142, 245, 182, 253, 89, 152, 106, 70, 186, 37, 66, 162, 250, + 7, 85, 238, 10, 73, 104, 56, 164, 40, 123, 201, 193, 227, 244, 199, 158 +}; + +const int av_camellia_size = sizeof(AVCAMELLIA); + +static void LR128(uint64_t d[2], const uint64_t K[2], int x) +{ + int i = 0; + if (64 <= x && x < 128) { + i = 1; + x -= 64; + } + if (x <= 0 || x >= 128) { + d[0] = K[i]; + d[1] = K[!i]; + return; + } + d[0] = (K[i] << x | K[!i] >> (64 - x)); + d[1] = (K[!i] << x | K[i] >> (64 - x)); +} + +static uint64_t F(uint64_t F_IN, uint64_t KE) +{ + KE ^= F_IN; + F_IN=SP[0][KE >> 56]^SP[1][(KE >> 48) & MASK8]^SP[2][(KE >> 40) & MASK8]^SP[3][(KE >> 32) & MASK8]^SP[4][(KE >> 24) & MASK8]^SP[5][(KE >> 16) & MASK8]^SP[6][(KE >> 8) & MASK8]^SP[7][KE & MASK8]; + return F_IN; +} + +static uint64_t FL(uint64_t FL_IN, uint64_t KE) +{ + uint32_t x1, x2, k1, k2; + x1 = FL_IN >> 32; + x2 = FL_IN & MASK32; + k1 = KE >> 32; + k2 = KE & MASK32; + x2 = x2 ^ LR32((x1 & k1), 1); + x1 = x1 ^ (x2 | k2); + return ((uint64_t)x1 << 32) | (uint64_t)x2; +} + +static uint64_t FLINV(uint64_t FLINV_IN, uint64_t KE) +{ + uint32_t x1, x2, k1, k2; + x1 = FLINV_IN >> 32; + x2 = FLINV_IN & MASK32; + k1 = KE >> 32; + k2 = KE & MASK32; + x1 = x1 ^ (x2 | k2); + x2 = x2 ^ LR32((x1 & k1), 1); + return ((uint64_t)x1 << 32) | (uint64_t)x2; +} + +static const uint8_t shifts[2][12] = { + {0, 15, 15, 45, 45, 60, 94, 94, 111}, + {0, 15, 15, 30, 45, 45, 60, 60, 77, 94, 94, 111} +}; + +static const uint8_t vars[2][12] = { + {2, 0, 2, 0, 2, 2, 0, 2, 0}, + {3, 1, 2, 3, 0, 2, 1, 3, 0, 1, 2, 0} +}; + +static void generate_round_keys(AVCAMELLIA *cs, uint64_t Kl[2], uint64_t Kr[2], uint64_t Ka[2], uint64_t Kb[2]) +{ + int i; + uint64_t *Kd[4], d[2]; + Kd[0] = Kl; + Kd[1] = Kr; + Kd[2] = Ka; + Kd[3] = Kb; + cs->Kw[0] = Kl[0]; + cs->Kw[1] = Kl[1]; + if (cs->key_bits == 128) { + for (i = 0; i < 9; i++) { + LR128(d, Kd[vars[0][i]], shifts[0][i]); + cs->K[2*i] = d[0]; + cs->K[2*i+1] = d[1]; + } + LR128(d, Kd[0], 60); + cs->K[9] = d[1]; + LR128(d, Kd[2], 30); + cs->Ke[0] = d[0]; + cs->Ke[1] = d[1]; + LR128(d, Kd[0], 77); + cs->Ke[2] = d[0]; + cs->Ke[3] = d[1]; + LR128(d, Kd[2], 111); + cs->Kw[2] = d[0]; + cs->Kw[3] = d[1]; + } else { + for (i = 0; i < 12; i++) { + LR128(d, Kd[vars[1][i]], shifts[1][i]); + cs->K[2*i] = d[0]; + cs->K[2*i+1] = d[1]; + } + LR128(d, Kd[1], 30); + cs->Ke[0] = d[0]; + cs->Ke[1] = d[1]; + LR128(d, Kd[0], 60); + cs->Ke[2] = d[0]; + cs->Ke[3] = d[1]; + LR128(d, Kd[2], 77); + cs->Ke[4] = d[0]; + cs->Ke[5] = d[1]; + LR128(d, Kd[3], 111); + cs->Kw[2] = d[0]; + cs->Kw[3] = d[1]; + } +} + +static void camellia_encrypt(AVCAMELLIA *cs, uint8_t *dst, const uint8_t *src) +{ + uint64_t D1, D2; + D1 = AV_RB64(src); + D2 = AV_RB64(src + 8); + D1 ^= cs->Kw[0]; + D2 ^= cs->Kw[1]; + D2 ^= F(D1, cs->K[0]); + D1 ^= F(D2, cs->K[1]); + D2 ^= F(D1, cs->K[2]); + D1 ^= F(D2, cs->K[3]); + D2 ^= F(D1, cs->K[4]); + D1 ^= F(D2, cs->K[5]); + D1 = FL(D1, cs->Ke[0]); + D2 = FLINV(D2, cs->Ke[1]); + D2 ^= F(D1, cs->K[6]); + D1 ^= F(D2, cs->K[7]); + D2 ^= F(D1, cs->K[8]); + D1 ^= F(D2, cs->K[9]); + D2 ^= F(D1, cs->K[10]); + D1 ^= F(D2, cs->K[11]); + D1 = FL(D1, cs->Ke[2]); + D2 = FLINV(D2, cs->Ke[3]); + D2 ^= F(D1, cs->K[12]); + D1 ^= F(D2, cs->K[13]); + D2 ^= F(D1, cs->K[14]); + D1 ^= F(D2, cs->K[15]); + D2 ^= F(D1, cs->K[16]); + D1 ^= F(D2, cs->K[17]); + if (cs->key_bits != 128) { + D1 = FL(D1, cs->Ke[4]); + D2 = FLINV(D2, cs->Ke[5]); + D2 ^= F(D1, cs->K[18]); + D1 ^= F(D2, cs->K[19]); + D2 ^= F(D1, cs->K[20]); + D1 ^= F(D2, cs->K[21]); + D2 ^= F(D1, cs->K[22]); + D1 ^= F(D2, cs->K[23]); + } + D2 ^= cs->Kw[2]; + D1 ^= cs->Kw[3]; + AV_WB64(dst, D2); + AV_WB64(dst + 8, D1); +} + +static void camellia_decrypt(AVCAMELLIA *cs, uint8_t *dst, const uint8_t *src, uint8_t *iv) +{ + uint64_t D1, D2; + D1 = AV_RB64(src); + D2 = AV_RB64(src + 8); + D1 ^= cs->Kw[2]; + D2 ^= cs->Kw[3]; + if (cs->key_bits != 128) { + D2 ^= F(D1, cs->K[23]); + D1 ^= F(D2, cs->K[22]); + D2 ^= F(D1, cs->K[21]); + D1 ^= F(D2, cs->K[20]); + D2 ^= F(D1, cs->K[19]); + D1 ^= F(D2, cs->K[18]); + D1 = FL(D1, cs->Ke[5]); + D2 = FLINV(D2, cs->Ke[4]); + } + D2 ^= F(D1, cs->K[17]); + D1 ^= F(D2, cs->K[16]); + D2 ^= F(D1, cs->K[15]); + D1 ^= F(D2, cs->K[14]); + D2 ^= F(D1, cs->K[13]); + D1 ^= F(D2, cs->K[12]); + D1 = FL(D1, cs->Ke[3]); + D2 = FLINV(D2, cs->Ke[2]); + D2 ^= F(D1, cs->K[11]); + D1 ^= F(D2, cs->K[10]); + D2 ^= F(D1, cs->K[9]); + D1 ^= F(D2, cs->K[8]); + D2 ^= F(D1, cs->K[7]); + D1 ^= F(D2, cs->K[6]); + D1 = FL(D1, cs->Ke[1]); + D2 = FLINV(D2, cs->Ke[0]); + D2 ^= F(D1, cs->K[5]); + D1 ^= F(D2, cs->K[4]); + D2 ^= F(D1, cs->K[3]); + D1 ^= F(D2, cs->K[2]); + D2 ^= F(D1, cs->K[1]); + D1 ^= F(D2, cs->K[0]); + D2 ^= cs->Kw[0]; + D1 ^= cs->Kw[1]; + if (iv) { + D2 ^= AV_RB64(iv); + D1 ^= AV_RB64(iv + 8); + memcpy(iv, src, 16); + } + AV_WB64(dst, D2); + AV_WB64(dst + 8, D1); +} + +static void computeSP(void) +{ + uint64_t z; + int i; + for (i = 0; i < 256; i++) { + z = SBOX1[i]; + SP[0][i] = (z << 56) ^ (z << 48) ^ (z << 40) ^ (z << 24) ^ z; + SP[7][i] = (z << 56) ^ (z << 48) ^ (z << 40) ^ (z << 24) ^ (z << 16) ^ (z << 8); + z = SBOX2[i]; + SP[1][i] = (z << 48) ^ (z << 40) ^ (z << 32) ^ (z << 24) ^ (z << 16); + SP[4][i] = (z << 48) ^ (z << 40) ^ (z << 32) ^ (z << 16) ^ (z << 8) ^ z; + z = SBOX3[i]; + SP[2][i] = (z << 56) ^ (z << 40) ^ (z << 32) ^ (z << 16) ^ (z << 8); + SP[5][i] = (z << 56) ^ (z << 40) ^ (z << 32) ^ (z << 24) ^ (z << 8) ^ z; + z = SBOX4[i]; + SP[3][i] = (z << 56) ^ (z << 48) ^ (z << 32) ^ (z << 8) ^ z; + SP[6][i] = (z << 56) ^ (z << 48) ^ (z << 32) ^ (z << 24) ^ (z << 16) ^ z; + } +} + +struct AVCAMELLIA *av_camellia_alloc(void) +{ + return av_mallocz(sizeof(struct AVCAMELLIA)); +} + +av_cold int av_camellia_init(AVCAMELLIA *cs, const uint8_t *key, int key_bits) +{ + uint64_t Kl[2], Kr[2], Ka[2], Kb[2]; + uint64_t D1, D2; + if (key_bits != 128 && key_bits != 192 && key_bits != 256) + return AVERROR(EINVAL); + memset(Kb, 0, sizeof(Kb)); + memset(Kr, 0, sizeof(Kr)); + cs->key_bits = key_bits; + Kl[0] = AV_RB64(key); + Kl[1] = AV_RB64(key + 8); + if (key_bits == 192) { + Kr[0] = AV_RB64(key + 16); + Kr[1] = ~Kr[0]; + } else if (key_bits == 256) { + Kr[0] = AV_RB64(key + 16); + Kr[1] = AV_RB64(key + 24); + } + computeSP(); + D1 = Kl[0] ^ Kr[0]; + D2 = Kl[1] ^ Kr[1]; + D2 ^= F(D1, Sigma1); + D1 ^= F(D2, Sigma2); + D1 ^= Kl[0]; + D2 ^= Kl[1]; + D2 ^= F(D1, Sigma3); + D1 ^= F(D2, Sigma4); + Ka[0] = D1; + Ka[1] = D2; + if (key_bits != 128) { + D1 = Ka[0] ^ Kr[0]; + D2 = Ka[1] ^ Kr[1]; + D2 ^= F(D1, Sigma5); + D1 ^= F(D2, Sigma6); + Kb[0] = D1; + Kb[1] = D2; + } + generate_round_keys(cs, Kl, Kr, Ka, Kb); + return 0; +} + +void av_camellia_crypt(AVCAMELLIA *cs, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt) +{ + int i; + while (count--) { + if (decrypt) { + camellia_decrypt(cs, dst, src, iv); + } else { + if (iv) { + for (i = 0; i < 16; i++) + dst[i] = src[i] ^ iv[i]; + camellia_encrypt(cs, dst, dst); + memcpy(iv, dst, 16); + } else { + camellia_encrypt(cs, dst, src); + } + } + src = src + 16; + dst = dst + 16; + } +} diff --git a/libs/ffmpeg/libavutil/camellia.h b/libs/ffmpeg/libavutil/camellia.h new file mode 100644 index 00000000000..96787102e2a --- /dev/null +++ b/libs/ffmpeg/libavutil/camellia.h @@ -0,0 +1,70 @@ +/* + * An implementation of the CAMELLIA algorithm as mentioned in RFC3713 + * Copyright (c) 2014 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CAMELLIA_H +#define AVUTIL_CAMELLIA_H + +#include <stdint.h> + + +/** + * @file + * @brief Public header for libavutil CAMELLIA algorithm + * @defgroup lavu_camellia CAMELLIA + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_camellia_size; + +struct AVCAMELLIA; + +/** + * Allocate an AVCAMELLIA context + * To free the struct: av_free(ptr) + */ +struct AVCAMELLIA *av_camellia_alloc(void); + +/** + * Initialize an AVCAMELLIA context. + * + * @param ctx an AVCAMELLIA context + * @param key a key of 16, 24, 32 bytes used for encryption/decryption + * @param key_bits number of keybits: possible are 128, 192, 256 + */ +int av_camellia_init(struct AVCAMELLIA *ctx, const uint8_t *key, int key_bits); + +/** + * Encrypt or decrypt a buffer using a previously initialized context + * + * @param ctx an AVCAMELLIA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 16 byte blocks + * @param iv initialization vector for CBC mode, NULL for ECB mode + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_camellia_crypt(struct AVCAMELLIA *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t* iv, int decrypt); + +/** + * @} + */ +#endif /* AVUTIL_CAMELLIA_H */ diff --git a/libs/ffmpeg/libavutil/cast5.c b/libs/ffmpeg/libavutil/cast5.c new file mode 100644 index 00000000000..e1d2c5cadd4 --- /dev/null +++ b/libs/ffmpeg/libavutil/cast5.c @@ -0,0 +1,511 @@ +/* + * An implementation of the CAST128 algorithm as mentioned in RFC2144 + * Copyright (c) 2014 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> + +#include "cast5.h" +#include "error.h" +#include "intreadwrite.h" +#include "mem.h" +#include "attributes.h" + +#define IA(x) ((x) >> 24) +#define IB(x) (((x) >> 16) & 0xff) +#define IC(x) (((x) >> 8) & 0xff) +#define ID(x) ((x) & 0xff) + +#define LR(x, c) (((x) << (c)) | ((x) >> ((32 - (c)) & 31))) + +#define F3(l, r, i) \ + do { \ + I = LR(cs->Km[i] - r, cs->Kr[i]); \ + f = ((S1[IA(I)] + S2[IB(I)]) ^ S3[IC(I)]) - S4[ID(I)]; \ + l = f ^ l; \ + } while (0) + +#define F2(l, r, i) \ + do { \ + I = LR(cs->Km[i] ^ r, cs->Kr[i]); \ + f = ((S1[IA(I)] - S2[IB(I)]) + S3[IC(I)]) ^ S4[ID(I)]; \ + l = f ^ l; \ + } while (0) + +#define F1(l, r, i) \ + do { \ + I = LR(cs->Km[i] + r, cs->Kr[i]); \ + f = ((S1[IA(I)] ^ S2[IB(I)]) - S3[IC(I)]) + S4[ID(I)]; \ + l = f ^ l; \ + } while (0) + +#define COMPUTE_Z \ + do { \ + z[0] = x[0] ^ S5[IB(x[3])] ^ S6[ID(x[3])] ^ S7[IA(x[3])] ^ S8[IC(x[3])] ^ S7[IA(x[2])]; \ + z[1] = x[2] ^ S5[IA(z[0])] ^ S6[IC(z[0])] ^ S7[IB(z[0])] ^ S8[ID(z[0])] ^ S8[IC(x[2])]; \ + z[2] = x[3] ^ S5[ID(z[1])] ^ S6[IC(z[1])] ^ S7[IB(z[1])] ^ S8[IA(z[1])] ^ S5[IB(x[2])]; \ + z[3] = x[1] ^ S5[IC(z[2])] ^ S6[IB(z[2])] ^ S7[ID(z[2])] ^ S8[IA(z[2])] ^ S6[ID(x[2])]; \ + } while (0) + +#define COMPUTE_X \ + do { \ + x[0] = z[2] ^ S5[IB(z[1])] ^ S6[ID(z[1])] ^ S7[IA(z[1])] ^ S8[IC(z[1])] ^ S7[IA(z[0])]; \ + x[1] = z[0] ^ S5[IA(x[0])] ^ S6[IC(x[0])] ^ S7[IB(x[0])] ^ S8[ID(x[0])] ^ S8[IC(z[0])]; \ + x[2] = z[1] ^ S5[ID(x[1])] ^ S6[IC(x[1])] ^ S7[IB(x[1])] ^ S8[IA(x[1])] ^ S5[IB(z[0])]; \ + x[3] = z[3] ^ S5[IC(x[2])] ^ S6[IB(x[2])] ^ S7[ID(x[2])] ^ S8[IA(x[2])] ^ S6[ID(z[0])]; \ + } while (0) + + +typedef struct AVCAST5 { + uint32_t Km[17]; + uint32_t Kr[17]; + int rounds; +} AVCAST5; + +const int av_cast5_size = sizeof(AVCAST5); + +static const uint32_t S1[256] = { + 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, + 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, + 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, + 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, + 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, + 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, + 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, + 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, + 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, + 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, + 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, + 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, + 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, + 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, + 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, + 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, + 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, + 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, + 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, + 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, + 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, + 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, + 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, + 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, + 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, + 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, + 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, + 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, + 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, + 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, + 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, + 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf +}; + +static const uint32_t S2[256] = { + 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, + 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, + 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, + 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, + 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, + 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, + 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, + 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, + 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, + 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, + 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, + 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, + 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, + 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, + 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, + 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, + 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, + 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, + 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, + 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, + 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, + 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, + 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, + 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, + 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, + 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, + 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, + 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, + 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, + 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, + 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, + 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1 +}; + +static const uint32_t S3[256] = { + 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, + 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, + 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, + 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, + 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, + 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, + 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, + 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, + 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, + 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, + 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, + 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, + 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, + 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, + 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, + 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, + 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, + 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, + 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, + 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, + 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, + 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, + 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, + 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, + 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, + 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, + 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, + 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, + 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, + 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, + 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, + 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783 +}; + +static const uint32_t S4[256] = { + 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, + 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, + 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, + 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, + 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, + 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, + 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, + 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, + 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, + 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, + 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, + 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, + 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, + 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, + 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, + 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, + 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, + 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, + 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, + 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, + 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, + 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, + 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, + 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, + 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, + 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, + 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, + 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, + 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, + 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, + 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, + 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2 +}; + +static const uint32_t S5[256] = { + 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, + 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, + 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, + 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, + 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, + 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, + 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, + 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, + 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, + 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, + 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, + 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, + 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, + 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, + 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, + 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, + 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, + 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, + 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, + 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, + 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, + 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, + 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, + 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, + 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, + 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, + 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, + 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, + 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, + 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, + 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, + 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4 +}; + +static const uint32_t S6[256] = { + 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, + 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, + 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, + 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, + 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, + 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, + 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, + 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, + 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, + 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, + 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, + 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, + 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, + 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, + 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, + 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, + 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, + 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, + 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, + 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, + 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, + 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, + 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, + 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, + 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, + 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, + 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, + 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, + 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, + 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, + 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, + 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f +}; + +static const uint32_t S7[256] = { + 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, + 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, + 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, + 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, + 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, + 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, + 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, + 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, + 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, + 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, + 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, + 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, + 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, + 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, + 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, + 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, + 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, + 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, + 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, + 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, + 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, + 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, + 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, + 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, + 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, + 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, + 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, + 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, + 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, + 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, + 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, + 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3 +}; + +static const uint32_t S8[256] = { + 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, + 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, + 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, + 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, + 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, + 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, + 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, + 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, + 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, + 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, + 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, + 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, + 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, + 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, + 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, + 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, + 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, + 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, + 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, + 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, + 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, + 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, + 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, + 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, + 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, + 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, + 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, + 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, + 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, + 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, + 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, + 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e +}; + +static void generate_round_keys(int rnds, uint32_t* K, uint32_t* x, uint32_t* z) +{ + COMPUTE_Z; + + K[1] = S5[IA(z[2])] ^ S6[IB(z[2])] ^ S7[ID(z[1])] ^ S8[IC(z[1])] ^ S5[IC(z[0])]; + K[2] = S5[IC(z[2])] ^ S6[ID(z[2])] ^ S7[IB(z[1])] ^ S8[IA(z[1])] ^ S6[IC(z[1])]; + K[3] = S5[IA(z[3])] ^ S6[IB(z[3])] ^ S7[ID(z[0])] ^ S8[IC(z[0])] ^ S7[IB(z[2])]; + K[4] = S5[IC(z[3])] ^ S6[ID(z[3])] ^ S7[IB(z[0])] ^ S8[IA(z[0])] ^ S8[IA(z[3])]; + + COMPUTE_X; + + K[5] = S5[ID(x[0])] ^ S6[IC(x[0])] ^ S7[IA(x[3])] ^ S8[IB(x[3])] ^ S5[IA(x[2])]; + K[6] = S5[IB(x[0])] ^ S6[IA(x[0])] ^ S7[IC(x[3])] ^ S8[ID(x[3])] ^ S6[IB(x[3])]; + K[7] = S5[ID(x[1])] ^ S6[IC(x[1])] ^ S7[IA(x[2])] ^ S8[IB(x[2])] ^ S7[ID(x[0])]; + K[8] = S5[IB(x[1])] ^ S6[IA(x[1])] ^ S7[IC(x[2])] ^ S8[ID(x[2])] ^ S8[ID(x[1])]; + + COMPUTE_Z; + + K[9] = S5[ID(z[0])] ^ S6[IC(z[0])] ^ S7[IA(z[3])] ^ S8[IB(z[3])] ^ S5[IB(z[2])]; + K[10] = S5[IB(z[0])] ^ S6[IA(z[0])] ^ S7[IC(z[3])] ^ S8[ID(z[3])] ^ S6[IA(z[3])]; + K[11] = S5[ID(z[1])] ^ S6[IC(z[1])] ^ S7[IA(z[2])] ^ S8[IB(z[2])] ^ S7[IC(z[0])]; + K[12] = S5[IB(z[1])] ^ S6[IA(z[1])] ^ S7[IC(z[2])] ^ S8[ID(z[2])] ^ S8[IC(z[1])]; + + COMPUTE_X; + + if (rnds == 16) { + K[13] = S5[IA(x[2])] ^ S6[IB(x[2])] ^ S7[ID(x[1])] ^ S8[IC(x[1])] ^ S5[ID(x[0])]; + K[14] = S5[IC(x[2])] ^ S6[ID(x[2])] ^ S7[IB(x[1])] ^ S8[IA(x[1])] ^ S6[ID(x[1])]; + K[15] = S5[IA(x[3])] ^ S6[IB(x[3])] ^ S7[ID(x[0])] ^ S8[IC(x[0])] ^ S7[IA(x[2])]; + K[16] = S5[IC(x[3])] ^ S6[ID(x[3])] ^ S7[IB(x[0])] ^ S8[IA(x[0])] ^ S8[IB(x[3])]; + } +} + +static void encipher(AVCAST5* cs, uint8_t* dst, const uint8_t* src) +{ + uint32_t r, l, f, I; + l = AV_RB32(src); + r = AV_RB32(src + 4); + F1(l, r, 1); + F2(r, l, 2); + F3(l, r, 3); + F1(r, l, 4); + F2(l, r, 5); + F3(r, l, 6); + F1(l, r, 7); + F2(r, l, 8); + F3(l, r, 9); + F1(r, l, 10); + F2(l, r, 11); + F3(r, l, 12); + if (cs->rounds == 16) { + F1(l, r, 13); + F2(r, l, 14); + F3(l, r, 15); + F1(r, l, 16); + } + AV_WB32(dst, r); + AV_WB32(dst + 4, l); +} + +static void decipher(AVCAST5* cs, uint8_t* dst, const uint8_t* src, uint8_t *iv) +{ + uint32_t f, I, r, l; + l = AV_RB32(src); + r = AV_RB32(src + 4); + if (cs->rounds == 16) { + F1(l, r, 16); + F3(r, l, 15); + F2(l, r, 14); + F1(r, l, 13); + } + F3(l, r, 12); + F2(r, l, 11); + F1(l, r, 10); + F3(r, l, 9); + F2(l, r, 8); + F1(r, l, 7); + F3(l, r, 6); + F2(r, l, 5); + F1(l, r, 4); + F3(r, l, 3); + F2(l, r, 2); + F1(r, l, 1); + if (iv) { + r ^= AV_RB32(iv); + l ^= AV_RB32(iv + 4); + memcpy(iv, src, 8); + } + AV_WB32(dst, r); + AV_WB32(dst + 4, l); +} + +struct AVCAST5 *av_cast5_alloc(void) +{ + return av_mallocz(sizeof(struct AVCAST5)); +} + +av_cold int av_cast5_init(AVCAST5* cs, const uint8_t *key, int key_bits) +{ + uint8_t newKey[16]; + int i; + uint32_t p[4], q[4]; + if (key_bits % 8 || key_bits < 40 || key_bits > 128) + return AVERROR(EINVAL); + memset(newKey, 0, sizeof(newKey)); + memcpy(newKey, key, key_bits >> 3); + + cs->rounds = key_bits <= 80 ? 12 : 16; + for (i = 0; i < 4; i++) + q[i] = AV_RB32(newKey + (4 * i)); + generate_round_keys(cs->rounds, cs->Km, q, p); + generate_round_keys(cs->rounds, cs->Kr, q, p); + for (i = 0; i <= cs->rounds; i++) + cs->Kr[i] = cs->Kr[i] & 0x1f; + return 0; +} + +void av_cast5_crypt2(AVCAST5* cs, uint8_t* dst, const uint8_t* src, int count, uint8_t *iv, int decrypt) +{ + int i; + while (count--) { + if (decrypt) { + decipher(cs, dst, src, iv); + } else { + if (iv) { + for (i = 0; i < 8; i++) + dst[i] = src[i] ^ iv[i]; + encipher(cs, dst, dst); + memcpy(iv, dst, 8); + } else { + encipher(cs, dst, src); + } + } + src = src + 8; + dst = dst + 8; + } +} +void av_cast5_crypt(AVCAST5* cs, uint8_t* dst, const uint8_t* src, int count, int decrypt) +{ + while (count--) { + if (decrypt){ + decipher(cs, dst, src, NULL); + } else { + encipher(cs, dst, src); + } + src = src + 8; + dst = dst + 8; + } +} diff --git a/libs/ffmpeg/libavutil/cast5.h b/libs/ffmpeg/libavutil/cast5.h new file mode 100644 index 00000000000..ad5b347e685 --- /dev/null +++ b/libs/ffmpeg/libavutil/cast5.h @@ -0,0 +1,80 @@ +/* + * An implementation of the CAST128 algorithm as mentioned in RFC2144 + * Copyright (c) 2014 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CAST5_H +#define AVUTIL_CAST5_H + +#include <stdint.h> + + +/** + * @file + * @brief Public header for libavutil CAST5 algorithm + * @defgroup lavu_cast5 CAST5 + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_cast5_size; + +struct AVCAST5; + +/** + * Allocate an AVCAST5 context + * To free the struct: av_free(ptr) + */ +struct AVCAST5 *av_cast5_alloc(void); +/** + * Initialize an AVCAST5 context. + * + * @param ctx an AVCAST5 context + * @param key a key of 5,6,...16 bytes used for encryption/decryption + * @param key_bits number of keybits: possible are 40,48,...,128 + * @return 0 on success, less than 0 on failure + */ +int av_cast5_init(struct AVCAST5 *ctx, const uint8_t *key, int key_bits); + +/** + * Encrypt or decrypt a buffer using a previously initialized context, ECB mode only + * + * @param ctx an AVCAST5 context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_cast5_crypt(struct AVCAST5 *ctx, uint8_t *dst, const uint8_t *src, int count, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context + * + * @param ctx an AVCAST5 context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, NULL for ECB mode + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_cast5_crypt2(struct AVCAST5 *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); +/** + * @} + */ +#endif /* AVUTIL_CAST5_H */ diff --git a/libs/ffmpeg/libavutil/channel_layout.c b/libs/ffmpeg/libavutil/channel_layout.c new file mode 100644 index 00000000000..cfa8e05d56f --- /dev/null +++ b/libs/ffmpeg/libavutil/channel_layout.c @@ -0,0 +1,977 @@ +/* + * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * audio channel layout utility functions + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "avassert.h" +#include "channel_layout.h" +#include "bprint.h" +#include "common.h" +#include "error.h" +#include "macros.h" +#include "mem.h" +#include "opt.h" + +#define CHAN_IS_AMBI(x) ((x) >= AV_CHAN_AMBISONIC_BASE &&\ + (x) <= AV_CHAN_AMBISONIC_END) + +struct channel_name { + const char *name; + const char *description; +}; + +static const struct channel_name channel_names[] = { + [AV_CHAN_FRONT_LEFT ] = { "FL", "front left" }, + [AV_CHAN_FRONT_RIGHT ] = { "FR", "front right" }, + [AV_CHAN_FRONT_CENTER ] = { "FC", "front center" }, + [AV_CHAN_LOW_FREQUENCY ] = { "LFE", "low frequency" }, + [AV_CHAN_BACK_LEFT ] = { "BL", "back left" }, + [AV_CHAN_BACK_RIGHT ] = { "BR", "back right" }, + [AV_CHAN_FRONT_LEFT_OF_CENTER ] = { "FLC", "front left-of-center" }, + [AV_CHAN_FRONT_RIGHT_OF_CENTER] = { "FRC", "front right-of-center" }, + [AV_CHAN_BACK_CENTER ] = { "BC", "back center" }, + [AV_CHAN_SIDE_LEFT ] = { "SL", "side left" }, + [AV_CHAN_SIDE_RIGHT ] = { "SR", "side right" }, + [AV_CHAN_TOP_CENTER ] = { "TC", "top center" }, + [AV_CHAN_TOP_FRONT_LEFT ] = { "TFL", "top front left" }, + [AV_CHAN_TOP_FRONT_CENTER ] = { "TFC", "top front center" }, + [AV_CHAN_TOP_FRONT_RIGHT ] = { "TFR", "top front right" }, + [AV_CHAN_TOP_BACK_LEFT ] = { "TBL", "top back left" }, + [AV_CHAN_TOP_BACK_CENTER ] = { "TBC", "top back center" }, + [AV_CHAN_TOP_BACK_RIGHT ] = { "TBR", "top back right" }, + [AV_CHAN_STEREO_LEFT ] = { "DL", "downmix left" }, + [AV_CHAN_STEREO_RIGHT ] = { "DR", "downmix right" }, + [AV_CHAN_WIDE_LEFT ] = { "WL", "wide left" }, + [AV_CHAN_WIDE_RIGHT ] = { "WR", "wide right" }, + [AV_CHAN_SURROUND_DIRECT_LEFT ] = { "SDL", "surround direct left" }, + [AV_CHAN_SURROUND_DIRECT_RIGHT] = { "SDR", "surround direct right" }, + [AV_CHAN_LOW_FREQUENCY_2 ] = { "LFE2", "low frequency 2" }, + [AV_CHAN_TOP_SIDE_LEFT ] = { "TSL", "top side left" }, + [AV_CHAN_TOP_SIDE_RIGHT ] = { "TSR", "top side right" }, + [AV_CHAN_BOTTOM_FRONT_CENTER ] = { "BFC", "bottom front center" }, + [AV_CHAN_BOTTOM_FRONT_LEFT ] = { "BFL", "bottom front left" }, + [AV_CHAN_BOTTOM_FRONT_RIGHT ] = { "BFR", "bottom front right" }, + [AV_CHAN_SIDE_SURROUND_LEFT ] = { "SSL", "side surround left" }, + [AV_CHAN_SIDE_SURROUND_RIGHT ] = { "SSR", "side surround right" }, + [AV_CHAN_TOP_SURROUND_LEFT ] = { "TTL", "top surround left" }, + [AV_CHAN_TOP_SURROUND_RIGHT ] = { "TTR", "top surround right" }, + [AV_CHAN_BINAURAL_LEFT ] = { "BIL", "binaural left" }, + [AV_CHAN_BINAURAL_RIGHT ] = { "BIR", "binaural right" }, +}; + +void av_channel_name_bprint(AVBPrint *bp, enum AVChannel channel_id) +{ + if (channel_id >= AV_CHAN_AMBISONIC_BASE && + channel_id <= AV_CHAN_AMBISONIC_END) + av_bprintf(bp, "AMBI%d", channel_id - AV_CHAN_AMBISONIC_BASE); + else if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names) && + channel_names[channel_id].name) + av_bprintf(bp, "%s", channel_names[channel_id].name); + else if (channel_id == AV_CHAN_NONE) + av_bprintf(bp, "NONE"); + else if (channel_id == AV_CHAN_UNKNOWN) + av_bprintf(bp, "UNK"); + else if (channel_id == AV_CHAN_UNUSED) + av_bprintf(bp, "UNSD"); + else + av_bprintf(bp, "USR%d", channel_id); +} + +int av_channel_name(char *buf, size_t buf_size, enum AVChannel channel_id) +{ + AVBPrint bp; + + if (!buf && buf_size) + return AVERROR(EINVAL); + + av_bprint_init_for_buffer(&bp, buf, buf_size); + av_channel_name_bprint(&bp, channel_id); + + if (bp.len >= INT_MAX) + return AVERROR(ERANGE); + return bp.len + 1; +} + +void av_channel_description_bprint(AVBPrint *bp, enum AVChannel channel_id) +{ + if (channel_id >= AV_CHAN_AMBISONIC_BASE && + channel_id <= AV_CHAN_AMBISONIC_END) + av_bprintf(bp, "ambisonic ACN %d", channel_id - AV_CHAN_AMBISONIC_BASE); + else if ((unsigned)channel_id < FF_ARRAY_ELEMS(channel_names) && + channel_names[channel_id].description) + av_bprintf(bp, "%s", channel_names[channel_id].description); + else if (channel_id == AV_CHAN_NONE) + av_bprintf(bp, "none"); + else if (channel_id == AV_CHAN_UNKNOWN) + av_bprintf(bp, "unknown"); + else if (channel_id == AV_CHAN_UNUSED) + av_bprintf(bp, "unused"); + else + av_bprintf(bp, "user %d", channel_id); +} + +int av_channel_description(char *buf, size_t buf_size, enum AVChannel channel_id) +{ + AVBPrint bp; + + if (!buf && buf_size) + return AVERROR(EINVAL); + + av_bprint_init_for_buffer(&bp, buf, buf_size); + av_channel_description_bprint(&bp, channel_id); + + if (bp.len >= INT_MAX) + return AVERROR(ERANGE); + return bp.len + 1; +} + +enum AVChannel av_channel_from_string(const char *str) +{ + int i; + char *endptr = (char *)str; + enum AVChannel id = AV_CHAN_NONE; + + if (!strncmp(str, "AMBI", 4)) { + i = strtol(str + 4, NULL, 0); + if (i < 0 || i > AV_CHAN_AMBISONIC_END - AV_CHAN_AMBISONIC_BASE) + return AV_CHAN_NONE; + return AV_CHAN_AMBISONIC_BASE + i; + } + + for (i = 0; i < FF_ARRAY_ELEMS(channel_names); i++) { + if (channel_names[i].name && !strcmp(str, channel_names[i].name)) + return i; + } + if (!strcmp(str, "UNK")) + return AV_CHAN_UNKNOWN; + if (!strcmp(str, "UNSD")) + return AV_CHAN_UNUSED; + + if (!strncmp(str, "USR", 3)) { + const char *p = str + 3; + id = strtol(p, &endptr, 0); + } + if (id >= 0 && !*endptr) + return id; + + return AV_CHAN_NONE; +} + +struct channel_layout_name { + const char *name; + AVChannelLayout layout; +}; + +static const struct channel_layout_name channel_layout_map[] = { + { "mono", AV_CHANNEL_LAYOUT_MONO }, + { "stereo", AV_CHANNEL_LAYOUT_STEREO }, + { "2.1", AV_CHANNEL_LAYOUT_2POINT1 }, + { "3.0", AV_CHANNEL_LAYOUT_SURROUND }, + { "3.0(back)", AV_CHANNEL_LAYOUT_2_1 }, + { "4.0", AV_CHANNEL_LAYOUT_4POINT0 }, + { "quad", AV_CHANNEL_LAYOUT_QUAD }, + { "quad(side)", AV_CHANNEL_LAYOUT_2_2 }, + { "3.1", AV_CHANNEL_LAYOUT_3POINT1 }, + { "5.0", AV_CHANNEL_LAYOUT_5POINT0_BACK }, + { "5.0(side)", AV_CHANNEL_LAYOUT_5POINT0 }, + { "4.1", AV_CHANNEL_LAYOUT_4POINT1 }, + { "5.1", AV_CHANNEL_LAYOUT_5POINT1_BACK }, + { "5.1(side)", AV_CHANNEL_LAYOUT_5POINT1 }, + { "6.0", AV_CHANNEL_LAYOUT_6POINT0 }, + { "6.0(front)", AV_CHANNEL_LAYOUT_6POINT0_FRONT }, + { "3.1.2", AV_CHANNEL_LAYOUT_3POINT1POINT2 }, + { "hexagonal", AV_CHANNEL_LAYOUT_HEXAGONAL }, + { "6.1", AV_CHANNEL_LAYOUT_6POINT1 }, + { "6.1(back)", AV_CHANNEL_LAYOUT_6POINT1_BACK }, + { "6.1(front)", AV_CHANNEL_LAYOUT_6POINT1_FRONT }, + { "7.0", AV_CHANNEL_LAYOUT_7POINT0 }, + { "7.0(front)", AV_CHANNEL_LAYOUT_7POINT0_FRONT }, + { "7.1", AV_CHANNEL_LAYOUT_7POINT1 }, + { "7.1(wide)", AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK }, + { "7.1(wide-side)", AV_CHANNEL_LAYOUT_7POINT1_WIDE }, + { "5.1.2", AV_CHANNEL_LAYOUT_5POINT1POINT2 }, + { "5.1.2(back)", AV_CHANNEL_LAYOUT_5POINT1POINT2_BACK }, + { "octagonal", AV_CHANNEL_LAYOUT_OCTAGONAL }, + { "cube", AV_CHANNEL_LAYOUT_CUBE }, + { "5.1.4", AV_CHANNEL_LAYOUT_5POINT1POINT4_BACK }, + { "7.1.2", AV_CHANNEL_LAYOUT_7POINT1POINT2 }, + { "7.1.4", AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK }, + { "7.2.3", AV_CHANNEL_LAYOUT_7POINT2POINT3 }, + { "9.1.4", AV_CHANNEL_LAYOUT_9POINT1POINT4_BACK }, + { "9.1.6", AV_CHANNEL_LAYOUT_9POINT1POINT6 }, + { "hexadecagonal", AV_CHANNEL_LAYOUT_HEXADECAGONAL }, + { "binaural", AV_CHANNEL_LAYOUT_BINAURAL }, + { "downmix", AV_CHANNEL_LAYOUT_STEREO_DOWNMIX, }, + { "22.2", AV_CHANNEL_LAYOUT_22POINT2, }, +}; + +int av_channel_layout_custom_init(AVChannelLayout *channel_layout, int nb_channels) +{ + AVChannelCustom *map; + + if (nb_channels <= 0) + return AVERROR(EINVAL); + + map = av_calloc(nb_channels, sizeof(*channel_layout->u.map)); + if (!map) + return AVERROR(ENOMEM); + for (int i = 0; i < nb_channels; i++) + map[i].id = AV_CHAN_UNKNOWN; + + channel_layout->order = AV_CHANNEL_ORDER_CUSTOM; + channel_layout->nb_channels = nb_channels; + channel_layout->u.map = map; + + return 0; +} + +int av_channel_layout_from_mask(AVChannelLayout *channel_layout, + uint64_t mask) +{ + if (!mask) + return AVERROR(EINVAL); + + channel_layout->order = AV_CHANNEL_ORDER_NATIVE; + channel_layout->nb_channels = av_popcount64(mask); + channel_layout->u.mask = mask; + + return 0; +} + +static int parse_channel_list(AVChannelLayout *ch_layout, const char *str) +{ + int ret; + int nb_channels = 0; + AVChannelCustom *map = NULL; + AVChannelCustom custom = {0}; + + while (*str) { + char *channel, *chname; + int ret = av_opt_get_key_value(&str, "@", "+", AV_OPT_FLAG_IMPLICIT_KEY, &channel, &chname); + if (ret < 0) { + av_freep(&map); + return ret; + } + if (*str) + str++; // skip separator + if (!channel) { + channel = chname; + chname = NULL; + } + av_strlcpy(custom.name, chname ? chname : "", sizeof(custom.name)); + custom.id = av_channel_from_string(channel); + av_free(channel); + av_free(chname); + if (custom.id == AV_CHAN_NONE) { + av_freep(&map); + return AVERROR(EINVAL); + } + + av_dynarray2_add((void **)&map, &nb_channels, sizeof(custom), (void *)&custom); + if (!map) + return AVERROR(ENOMEM); + } + + if (!nb_channels) + return AVERROR(EINVAL); + + ch_layout->order = AV_CHANNEL_ORDER_CUSTOM; + ch_layout->u.map = map; + ch_layout->nb_channels = nb_channels; + + ret = av_channel_layout_retype(ch_layout, 0, AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL); + av_assert0(ret == 0); + + return 0; +} + +int av_channel_layout_from_string(AVChannelLayout *channel_layout, + const char *str) +{ + int i, matches, ret; + int channels = 0, nb_channels = 0; + char *chlist, *end; + uint64_t mask = 0; + + /* channel layout names */ + for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) { + if (channel_layout_map[i].name && !strcmp(str, channel_layout_map[i].name)) { + *channel_layout = channel_layout_map[i].layout; + return 0; + } + } + + /* This function is a channel layout initializer, so we have to + * zero-initialize before we start setting fields individually. */ + memset(channel_layout, 0, sizeof(*channel_layout)); + + /* ambisonic */ + if (!strncmp(str, "ambisonic ", 10)) { + const char *p = str + 10; + char *endptr; + AVChannelLayout extra = {0}; + int order; + + order = strtol(p, &endptr, 0); + if (order < 0 || order + 1 > INT_MAX / (order + 1) || + (*endptr && *endptr != '+')) + return AVERROR(EINVAL); + + channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC; + channel_layout->nb_channels = (order + 1) * (order + 1); + + if (*endptr) { + int ret = av_channel_layout_from_string(&extra, endptr + 1); + if (ret < 0) + return ret; + if (extra.nb_channels >= INT_MAX - channel_layout->nb_channels) { + av_channel_layout_uninit(&extra); + return AVERROR(EINVAL); + } + + if (extra.order == AV_CHANNEL_ORDER_NATIVE) { + channel_layout->u.mask = extra.u.mask; + } else { + channel_layout->order = AV_CHANNEL_ORDER_CUSTOM; + channel_layout->u.map = + av_calloc(channel_layout->nb_channels + extra.nb_channels, + sizeof(*channel_layout->u.map)); + if (!channel_layout->u.map) { + av_channel_layout_uninit(&extra); + return AVERROR(ENOMEM); + } + + for (i = 0; i < channel_layout->nb_channels; i++) + channel_layout->u.map[i].id = AV_CHAN_AMBISONIC_BASE + i; + for (i = 0; i < extra.nb_channels; i++) { + enum AVChannel ch = av_channel_layout_channel_from_index(&extra, i); + if (CHAN_IS_AMBI(ch)) { + av_channel_layout_uninit(channel_layout); + av_channel_layout_uninit(&extra); + return AVERROR(EINVAL); + } + channel_layout->u.map[channel_layout->nb_channels + i].id = ch; + if (extra.order == AV_CHANNEL_ORDER_CUSTOM && + extra.u.map[i].name[0]) + av_strlcpy(channel_layout->u.map[channel_layout->nb_channels + i].name, + extra.u.map[i].name, + sizeof(channel_layout->u.map[channel_layout->nb_channels + i].name)); + } + } + channel_layout->nb_channels += extra.nb_channels; + av_channel_layout_uninit(&extra); + } + + return 0; + } + + chlist = av_strdup(str); + if (!chlist) + return AVERROR(ENOMEM); + + /* channel names */ + matches = av_sscanf(str, "%d channels (%[^)]", &nb_channels, chlist); + ret = parse_channel_list(channel_layout, chlist); + av_freep(&chlist); + if (ret < 0 && ret != AVERROR(EINVAL)) + return ret; + + if (ret >= 0) { + end = strchr(str, ')'); + if (matches == 2 && (nb_channels != channel_layout->nb_channels || !end || *++end)) { + av_channel_layout_uninit(channel_layout); + return AVERROR(EINVAL); + } + return 0; + } + + errno = 0; + mask = strtoull(str, &end, 0); + + /* channel layout mask */ + if (!errno && !*end && !strchr(str, '-') && mask) { + av_channel_layout_from_mask(channel_layout, mask); + return 0; + } + + errno = 0; + channels = strtol(str, &end, 10); + + /* number of channels */ + if (!errno && !strcmp(end, "c") && channels > 0) { + av_channel_layout_default(channel_layout, channels); + if (channel_layout->order == AV_CHANNEL_ORDER_NATIVE) + return 0; + } + + /* number of unordered channels */ + if (!errno && (!strcmp(end, "C") || !strcmp(end, " channels")) + && channels > 0) { + channel_layout->order = AV_CHANNEL_ORDER_UNSPEC; + channel_layout->nb_channels = channels; + return 0; + } + + return AVERROR(EINVAL); +} + +void av_channel_layout_uninit(AVChannelLayout *channel_layout) +{ + if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) + av_freep(&channel_layout->u.map); + memset(channel_layout, 0, sizeof(*channel_layout)); +} + +int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src) +{ + av_channel_layout_uninit(dst); + *dst = *src; + if (src->order == AV_CHANNEL_ORDER_CUSTOM) { + dst->u.map = av_malloc_array(src->nb_channels, sizeof(*dst->u.map)); + if (!dst->u.map) + return AVERROR(ENOMEM); + memcpy(dst->u.map, src->u.map, src->nb_channels * sizeof(*src->u.map)); + } + return 0; +} + +static int64_t masked_description(const AVChannelLayout *channel_layout, int start_channel) +{ + uint64_t mask = 0; + for (int i = start_channel; i < channel_layout->nb_channels; i++) { + enum AVChannel ch = channel_layout->u.map[i].id; + if (ch >= 0 && ch < 63 && mask < (1ULL << ch)) + mask |= (1ULL << ch); + else + return AVERROR(EINVAL); + } + return mask; +} + +static int has_channel_names(const AVChannelLayout *channel_layout) +{ + if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM) + return 0; + for (int i = 0; i < channel_layout->nb_channels; i++) + if (channel_layout->u.map[i].name[0]) + return 1; + return 0; +} + +int av_channel_layout_ambisonic_order(const AVChannelLayout *channel_layout) +{ + int i, highest_ambi, order; + + if (channel_layout->order != AV_CHANNEL_ORDER_AMBISONIC && + channel_layout->order != AV_CHANNEL_ORDER_CUSTOM) + return AVERROR(EINVAL); + + highest_ambi = -1; + if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC) + highest_ambi = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask) - 1; + else { + const AVChannelCustom *map = channel_layout->u.map; + av_assert0(channel_layout->order == AV_CHANNEL_ORDER_CUSTOM); + + for (i = 0; i < channel_layout->nb_channels; i++) { + int is_ambi = CHAN_IS_AMBI(map[i].id); + + /* ambisonic following non-ambisonic */ + if (i > 0 && is_ambi && !CHAN_IS_AMBI(map[i - 1].id)) + return AVERROR(EINVAL); + + /* non-default ordering */ + if (is_ambi && map[i].id - AV_CHAN_AMBISONIC_BASE != i) + return AVERROR(EINVAL); + + if (CHAN_IS_AMBI(map[i].id)) + highest_ambi = i; + } + } + /* no ambisonic channels*/ + if (highest_ambi < 0) + return AVERROR(EINVAL); + + order = floor(sqrt(highest_ambi)); + /* incomplete order - some harmonics are missing */ + if ((order + 1) * (order + 1) != highest_ambi + 1) + return AVERROR(EINVAL); + + return order; +} + +static enum AVChannelOrder canonical_order(AVChannelLayout *channel_layout) +{ + int has_known_channel = 0; + int order; + + if (channel_layout->order != AV_CHANNEL_ORDER_CUSTOM) + return channel_layout->order; + + if (has_channel_names(channel_layout)) + return AV_CHANNEL_ORDER_CUSTOM; + + for (int i = 0; i < channel_layout->nb_channels && !has_known_channel; i++) + if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN) + has_known_channel = 1; + if (!has_known_channel) + return AV_CHANNEL_ORDER_UNSPEC; + + if (masked_description(channel_layout, 0) > 0) + return AV_CHANNEL_ORDER_NATIVE; + + order = av_channel_layout_ambisonic_order(channel_layout); + if (order >= 0 && masked_description(channel_layout, (order + 1) * (order + 1)) >= 0) + return AV_CHANNEL_ORDER_AMBISONIC; + + return AV_CHANNEL_ORDER_CUSTOM; +} + +/** + * If the custom layout is n-th order standard-order ambisonic, with optional + * extra non-diegetic channels at the end, write its string description in bp. + * Return a negative error code otherwise. + */ +static int try_describe_ambisonic(AVBPrint *bp, const AVChannelLayout *channel_layout) +{ + int nb_ambi_channels; + int order = av_channel_layout_ambisonic_order(channel_layout); + if (order < 0) + return order; + + av_bprintf(bp, "ambisonic %d", order); + + /* extra channels present */ + nb_ambi_channels = (order + 1) * (order + 1); + if (nb_ambi_channels < channel_layout->nb_channels) { + AVChannelLayout extra = { 0 }; + + if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC) { + extra.order = AV_CHANNEL_ORDER_NATIVE; + extra.nb_channels = av_popcount64(channel_layout->u.mask); + extra.u.mask = channel_layout->u.mask; + } else { + int64_t mask; + if (!has_channel_names(channel_layout) && + (mask = masked_description(channel_layout, nb_ambi_channels)) > 0) { + extra.order = AV_CHANNEL_ORDER_NATIVE; + extra.nb_channels = av_popcount64(mask); + extra.u.mask = mask; + } else { + extra.order = AV_CHANNEL_ORDER_CUSTOM; + extra.nb_channels = channel_layout->nb_channels - nb_ambi_channels; + extra.u.map = channel_layout->u.map + nb_ambi_channels; + } + } + + av_bprint_chars(bp, '+', 1); + av_channel_layout_describe_bprint(&extra, bp); + /* Not calling uninit here on extra because we don't own the u.map pointer */ + } + + return 0; +} + +int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout, + AVBPrint *bp) +{ + int i; + + switch (channel_layout->order) { + case AV_CHANNEL_ORDER_NATIVE: + for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) + if (channel_layout->u.mask == channel_layout_map[i].layout.u.mask) { + av_bprintf(bp, "%s", channel_layout_map[i].name); + return 0; + } + // fall-through + case AV_CHANNEL_ORDER_CUSTOM: + if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) { + int64_t mask; + int res = try_describe_ambisonic(bp, channel_layout); + if (res >= 0) + return 0; + if (!has_channel_names(channel_layout) && + (mask = masked_description(channel_layout, 0)) > 0) { + AVChannelLayout native = { .order = AV_CHANNEL_ORDER_NATIVE, + .nb_channels = av_popcount64(mask), + .u.mask = mask }; + return av_channel_layout_describe_bprint(&native, bp); + } + } + if (channel_layout->nb_channels) + av_bprintf(bp, "%d channels (", channel_layout->nb_channels); + for (i = 0; i < channel_layout->nb_channels; i++) { + enum AVChannel ch = av_channel_layout_channel_from_index(channel_layout, i); + + if (i) + av_bprintf(bp, "+"); + av_channel_name_bprint(bp, ch); + if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM && + channel_layout->u.map[i].name[0]) + av_bprintf(bp, "@%s", channel_layout->u.map[i].name); + } + if (channel_layout->nb_channels) { + av_bprintf(bp, ")"); + return 0; + } + // fall-through + case AV_CHANNEL_ORDER_UNSPEC: + av_bprintf(bp, "%d channels", channel_layout->nb_channels); + return 0; + case AV_CHANNEL_ORDER_AMBISONIC: + return try_describe_ambisonic(bp, channel_layout); + default: + return AVERROR(EINVAL); + } +} + +int av_channel_layout_describe(const AVChannelLayout *channel_layout, + char *buf, size_t buf_size) +{ + AVBPrint bp; + int ret; + + if (!buf && buf_size) + return AVERROR(EINVAL); + + av_bprint_init_for_buffer(&bp, buf, buf_size); + ret = av_channel_layout_describe_bprint(channel_layout, &bp); + if (ret < 0) + return ret; + + if (bp.len >= INT_MAX) + return AVERROR(ERANGE); + return bp.len + 1; +} + +enum AVChannel +av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout, + unsigned int idx) +{ + int i; + + if (idx >= channel_layout->nb_channels) + return AV_CHAN_NONE; + + switch (channel_layout->order) { + case AV_CHANNEL_ORDER_CUSTOM: + return channel_layout->u.map[idx].id; + case AV_CHANNEL_ORDER_AMBISONIC: { + int ambi_channels = channel_layout->nb_channels - av_popcount64(channel_layout->u.mask); + if (idx < ambi_channels) + return AV_CHAN_AMBISONIC_BASE + idx; + idx -= ambi_channels; + } + // fall-through + case AV_CHANNEL_ORDER_NATIVE: + for (i = 0; i < 64; i++) { + if ((1ULL << i) & channel_layout->u.mask && !idx--) + return i; + } + default: + return AV_CHAN_NONE; + } +} + +enum AVChannel +av_channel_layout_channel_from_string(const AVChannelLayout *channel_layout, + const char *str) +{ + int index = av_channel_layout_index_from_string(channel_layout, str); + + if (index < 0) + return AV_CHAN_NONE; + + return av_channel_layout_channel_from_index(channel_layout, index); +} + +int av_channel_layout_index_from_channel(const AVChannelLayout *channel_layout, + enum AVChannel channel) +{ + int i; + + if (channel == AV_CHAN_NONE) + return AVERROR(EINVAL); + + switch (channel_layout->order) { + case AV_CHANNEL_ORDER_CUSTOM: + for (i = 0; i < channel_layout->nb_channels; i++) + if (channel_layout->u.map[i].id == channel) + return i; + return AVERROR(EINVAL); + case AV_CHANNEL_ORDER_AMBISONIC: + case AV_CHANNEL_ORDER_NATIVE: { + uint64_t mask = channel_layout->u.mask; + int ambi_channels = channel_layout->nb_channels - av_popcount64(mask); + if (channel_layout->order == AV_CHANNEL_ORDER_AMBISONIC && + channel >= AV_CHAN_AMBISONIC_BASE) { + if (channel - AV_CHAN_AMBISONIC_BASE >= ambi_channels) + return AVERROR(EINVAL); + return channel - AV_CHAN_AMBISONIC_BASE; + } + if ((unsigned)channel > 63 || !(mask & (1ULL << channel))) + return AVERROR(EINVAL); + mask &= (1ULL << channel) - 1; + return av_popcount64(mask) + ambi_channels; + } + default: + return AVERROR(EINVAL); + } +} + +int av_channel_layout_index_from_string(const AVChannelLayout *channel_layout, + const char *str) +{ + char *chname; + enum AVChannel ch = AV_CHAN_NONE; + + switch (channel_layout->order) { + case AV_CHANNEL_ORDER_CUSTOM: + chname = strstr(str, "@"); + if (chname) { + char buf[16]; + chname++; + av_strlcpy(buf, str, FFMIN(sizeof(buf), chname - str)); + if (!*chname) + chname = NULL; + ch = av_channel_from_string(buf); + if (ch == AV_CHAN_NONE && *buf) + return AVERROR(EINVAL); + } + for (int i = 0; chname && i < channel_layout->nb_channels; i++) { + if (!strcmp(chname, channel_layout->u.map[i].name) && + (ch == AV_CHAN_NONE || ch == channel_layout->u.map[i].id)) + return i; + } + // fall-through + case AV_CHANNEL_ORDER_AMBISONIC: + case AV_CHANNEL_ORDER_NATIVE: + ch = av_channel_from_string(str); + if (ch == AV_CHAN_NONE) + return AVERROR(EINVAL); + return av_channel_layout_index_from_channel(channel_layout, ch); + } + + return AVERROR(EINVAL); +} + +int av_channel_layout_check(const AVChannelLayout *channel_layout) +{ + if (channel_layout->nb_channels <= 0) + return 0; + + switch (channel_layout->order) { + case AV_CHANNEL_ORDER_NATIVE: + return av_popcount64(channel_layout->u.mask) == channel_layout->nb_channels; + case AV_CHANNEL_ORDER_CUSTOM: + if (!channel_layout->u.map) + return 0; + for (int i = 0; i < channel_layout->nb_channels; i++) { + if (channel_layout->u.map[i].id == AV_CHAN_NONE) + return 0; + } + return 1; + case AV_CHANNEL_ORDER_AMBISONIC: + /* If non-diegetic channels are present, ensure they are taken into account */ + return av_popcount64(channel_layout->u.mask) < channel_layout->nb_channels; + case AV_CHANNEL_ORDER_UNSPEC: + return 1; + default: + return 0; + } +} + +int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1) +{ + int i; + + /* different channel counts -> not equal */ + if (chl->nb_channels != chl1->nb_channels) + return 1; + + /* if only one is unspecified -> not equal */ + if ((chl->order == AV_CHANNEL_ORDER_UNSPEC) != + (chl1->order == AV_CHANNEL_ORDER_UNSPEC)) + return 1; + /* both are unspecified -> equal */ + else if (chl->order == AV_CHANNEL_ORDER_UNSPEC) + return 0; + + /* can compare masks directly */ + if ((chl->order == AV_CHANNEL_ORDER_NATIVE || + chl->order == AV_CHANNEL_ORDER_AMBISONIC) && + chl->order == chl1->order) + return chl->u.mask != chl1->u.mask; + + /* compare channel by channel */ + for (i = 0; i < chl->nb_channels; i++) + if (av_channel_layout_channel_from_index(chl, i) != + av_channel_layout_channel_from_index(chl1, i)) + return 1; + return 0; +} + +void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(channel_layout_map); i++) + if (nb_channels == channel_layout_map[i].layout.nb_channels) { + *ch_layout = channel_layout_map[i].layout; + return; + } + + ch_layout->order = AV_CHANNEL_ORDER_UNSPEC; + ch_layout->nb_channels = nb_channels; +} + +const AVChannelLayout *av_channel_layout_standard(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVChannelLayout *ch_layout = NULL; + + if (i < FF_ARRAY_ELEMS(channel_layout_map)) { + ch_layout = &channel_layout_map[i].layout; + *opaque = (void*)(i + 1); + } + + return ch_layout; +} + +uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout, + uint64_t mask) +{ + uint64_t ret = 0; + int i; + + switch (channel_layout->order) { + case AV_CHANNEL_ORDER_NATIVE: + case AV_CHANNEL_ORDER_AMBISONIC: + return channel_layout->u.mask & mask; + case AV_CHANNEL_ORDER_CUSTOM: + for (i = 0; i < 64; i++) + if (mask & (1ULL << i) && av_channel_layout_index_from_channel(channel_layout, i) >= 0) + ret |= (1ULL << i); + break; + } + + return ret; +} + +int av_channel_layout_retype(AVChannelLayout *channel_layout, enum AVChannelOrder order, int flags) +{ + int allow_lossy = !(flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS); + int lossy; + + if (!av_channel_layout_check(channel_layout)) + return AVERROR(EINVAL); + + if (flags & AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL) + order = canonical_order(channel_layout); + + if (channel_layout->order == order) + return 0; + + switch (order) { + case AV_CHANNEL_ORDER_UNSPEC: { + int nb_channels = channel_layout->nb_channels; + if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) { + lossy = 0; + for (int i = 0; i < nb_channels; i++) { + if (channel_layout->u.map[i].id != AV_CHAN_UNKNOWN || channel_layout->u.map[i].name[0]) { + lossy = 1; + break; + } + } + } else { + lossy = 1; + } + if (!lossy || allow_lossy) { + void *opaque = channel_layout->opaque; + av_channel_layout_uninit(channel_layout); + channel_layout->order = AV_CHANNEL_ORDER_UNSPEC; + channel_layout->nb_channels = nb_channels; + channel_layout->opaque = opaque; + return lossy; + } + return AVERROR(ENOSYS); + } + case AV_CHANNEL_ORDER_NATIVE: + if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) { + int64_t mask = masked_description(channel_layout, 0); + if (mask < 0) + return AVERROR(ENOSYS); + lossy = has_channel_names(channel_layout); + if (!lossy || allow_lossy) { + void *opaque = channel_layout->opaque; + av_channel_layout_uninit(channel_layout); + av_channel_layout_from_mask(channel_layout, mask); + channel_layout->opaque = opaque; + return lossy; + } + } + return AVERROR(ENOSYS); + case AV_CHANNEL_ORDER_CUSTOM: { + AVChannelLayout custom = { 0 }; + int ret = av_channel_layout_custom_init(&custom, channel_layout->nb_channels); + void *opaque = channel_layout->opaque; + if (ret < 0) + return ret; + if (channel_layout->order != AV_CHANNEL_ORDER_UNSPEC) + for (int i = 0; i < channel_layout->nb_channels; i++) + custom.u.map[i].id = av_channel_layout_channel_from_index(channel_layout, i); + av_channel_layout_uninit(channel_layout); + *channel_layout = custom; + channel_layout->opaque = opaque; + return 0; + } + case AV_CHANNEL_ORDER_AMBISONIC: + if (channel_layout->order == AV_CHANNEL_ORDER_CUSTOM) { + int64_t mask; + int nb_channels = channel_layout->nb_channels; + int order = av_channel_layout_ambisonic_order(channel_layout); + if (order < 0) + return AVERROR(ENOSYS); + mask = masked_description(channel_layout, (order + 1) * (order + 1)); + if (mask < 0) + return AVERROR(ENOSYS); + lossy = has_channel_names(channel_layout); + if (!lossy || allow_lossy) { + void *opaque = channel_layout->opaque; + av_channel_layout_uninit(channel_layout); + channel_layout->order = AV_CHANNEL_ORDER_AMBISONIC; + channel_layout->nb_channels = nb_channels; + channel_layout->u.mask = mask; + channel_layout->opaque = opaque; + return lossy; + } + } + return AVERROR(ENOSYS); + default: + return AVERROR(EINVAL); + } +} diff --git a/libs/ffmpeg/libavutil/channel_layout.h b/libs/ffmpeg/libavutil/channel_layout.h new file mode 100644 index 00000000000..5ad2d5ed98f --- /dev/null +++ b/libs/ffmpeg/libavutil/channel_layout.h @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * Copyright (c) 2008 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CHANNEL_LAYOUT_H +#define AVUTIL_CHANNEL_LAYOUT_H + +#include <stdint.h> +#include <stdlib.h> + +#include "version.h" +#include "attributes.h" + +/** + * @file + * @ingroup lavu_audio_channels + * Public libavutil channel layout APIs header. + */ + + +/** + * @defgroup lavu_audio_channels Audio channels + * @ingroup lavu_audio + * + * Audio channel layout utility functions + * + * @{ + */ + +enum AVChannel { + /// Invalid channel index + AV_CHAN_NONE = -1, + AV_CHAN_FRONT_LEFT, + AV_CHAN_FRONT_RIGHT, + AV_CHAN_FRONT_CENTER, + AV_CHAN_LOW_FREQUENCY, + AV_CHAN_BACK_LEFT, + AV_CHAN_BACK_RIGHT, + AV_CHAN_FRONT_LEFT_OF_CENTER, + AV_CHAN_FRONT_RIGHT_OF_CENTER, + AV_CHAN_BACK_CENTER, + AV_CHAN_SIDE_LEFT, + AV_CHAN_SIDE_RIGHT, + AV_CHAN_TOP_CENTER, + AV_CHAN_TOP_FRONT_LEFT, + AV_CHAN_TOP_FRONT_CENTER, + AV_CHAN_TOP_FRONT_RIGHT, + AV_CHAN_TOP_BACK_LEFT, + AV_CHAN_TOP_BACK_CENTER, + AV_CHAN_TOP_BACK_RIGHT, + /** Stereo downmix. */ + AV_CHAN_STEREO_LEFT = 29, + /** See above. */ + AV_CHAN_STEREO_RIGHT, + AV_CHAN_WIDE_LEFT, + AV_CHAN_WIDE_RIGHT, + AV_CHAN_SURROUND_DIRECT_LEFT, + AV_CHAN_SURROUND_DIRECT_RIGHT, + AV_CHAN_LOW_FREQUENCY_2, + AV_CHAN_TOP_SIDE_LEFT, + AV_CHAN_TOP_SIDE_RIGHT, + AV_CHAN_BOTTOM_FRONT_CENTER, + AV_CHAN_BOTTOM_FRONT_LEFT, + AV_CHAN_BOTTOM_FRONT_RIGHT, + AV_CHAN_SIDE_SURROUND_LEFT, ///< +90 degrees, Lss, SiL + AV_CHAN_SIDE_SURROUND_RIGHT, ///< -90 degrees, Rss, SiR + AV_CHAN_TOP_SURROUND_LEFT, ///< +110 degrees, Lvs, TpLS + AV_CHAN_TOP_SURROUND_RIGHT, ///< -110 degrees, Rvs, TpRS + + AV_CHAN_BINAURAL_LEFT = 61, + AV_CHAN_BINAURAL_RIGHT, + + /** Channel is empty can be safely skipped. */ + AV_CHAN_UNUSED = 0x200, + + /** Channel contains data, but its position is unknown. */ + AV_CHAN_UNKNOWN = 0x300, + + /** + * Range of channels between AV_CHAN_AMBISONIC_BASE and + * AV_CHAN_AMBISONIC_END represent Ambisonic components using the ACN system. + * + * Given a channel id `<i>` between AV_CHAN_AMBISONIC_BASE and + * AV_CHAN_AMBISONIC_END (inclusive), the ACN index of the channel `<n>` is + * `<n> = <i> - AV_CHAN_AMBISONIC_BASE`. + * + * @note these values are only used for AV_CHANNEL_ORDER_CUSTOM channel + * orderings, the AV_CHANNEL_ORDER_AMBISONIC ordering orders the channels + * implicitly by their position in the stream. + */ + AV_CHAN_AMBISONIC_BASE = 0x400, + // leave space for 1024 ids, which correspond to maximum order-32 harmonics, + // which should be enough for the foreseeable use cases + AV_CHAN_AMBISONIC_END = 0x7ff, +}; + +enum AVChannelOrder { + /** + * Only the channel count is specified, without any further information + * about the channel order. + */ + AV_CHANNEL_ORDER_UNSPEC, + /** + * The native channel order, i.e. the channels are in the same order in + * which they are defined in the AVChannel enum. This supports up to 63 + * different channels. + */ + AV_CHANNEL_ORDER_NATIVE, + /** + * The channel order does not correspond to any other predefined order and + * is stored as an explicit map. For example, this could be used to support + * layouts with 64 or more channels, or with empty/skipped (AV_CHAN_UNUSED) + * channels at arbitrary positions. + */ + AV_CHANNEL_ORDER_CUSTOM, + /** + * The audio is represented as the decomposition of the sound field into + * spherical harmonics. Each channel corresponds to a single expansion + * component. Channels are ordered according to ACN (Ambisonic Channel + * Number). + * + * The channel with the index n in the stream contains the spherical + * harmonic of degree l and order m given by + * @code{.unparsed} + * l = floor(sqrt(n)), + * m = n - l * (l + 1). + * @endcode + * + * Conversely given a spherical harmonic of degree l and order m, the + * corresponding channel index n is given by + * @code{.unparsed} + * n = l * (l + 1) + m. + * @endcode + * + * Normalization is assumed to be SN3D (Schmidt Semi-Normalization) + * as defined in AmbiX format $ 2.1. + */ + AV_CHANNEL_ORDER_AMBISONIC, + /** + * Number of channel orders, not part of ABI/API + */ + FF_CHANNEL_ORDER_NB +}; + + +/** + * @defgroup channel_masks Audio channel masks + * + * A channel layout is a 64-bits integer with a bit set for every channel. + * The number of bits set must be equal to the number of channels. + * The value 0 means that the channel layout is not known. + * @note this data structure is not powerful enough to handle channels + * combinations that have the same channel multiple times, such as + * dual-mono. + * + * @{ + */ +#define AV_CH_FRONT_LEFT (1ULL << AV_CHAN_FRONT_LEFT ) +#define AV_CH_FRONT_RIGHT (1ULL << AV_CHAN_FRONT_RIGHT ) +#define AV_CH_FRONT_CENTER (1ULL << AV_CHAN_FRONT_CENTER ) +#define AV_CH_LOW_FREQUENCY (1ULL << AV_CHAN_LOW_FREQUENCY ) +#define AV_CH_BACK_LEFT (1ULL << AV_CHAN_BACK_LEFT ) +#define AV_CH_BACK_RIGHT (1ULL << AV_CHAN_BACK_RIGHT ) +#define AV_CH_FRONT_LEFT_OF_CENTER (1ULL << AV_CHAN_FRONT_LEFT_OF_CENTER ) +#define AV_CH_FRONT_RIGHT_OF_CENTER (1ULL << AV_CHAN_FRONT_RIGHT_OF_CENTER) +#define AV_CH_BACK_CENTER (1ULL << AV_CHAN_BACK_CENTER ) +#define AV_CH_SIDE_LEFT (1ULL << AV_CHAN_SIDE_LEFT ) +#define AV_CH_SIDE_RIGHT (1ULL << AV_CHAN_SIDE_RIGHT ) +#define AV_CH_TOP_CENTER (1ULL << AV_CHAN_TOP_CENTER ) +#define AV_CH_TOP_FRONT_LEFT (1ULL << AV_CHAN_TOP_FRONT_LEFT ) +#define AV_CH_TOP_FRONT_CENTER (1ULL << AV_CHAN_TOP_FRONT_CENTER ) +#define AV_CH_TOP_FRONT_RIGHT (1ULL << AV_CHAN_TOP_FRONT_RIGHT ) +#define AV_CH_TOP_BACK_LEFT (1ULL << AV_CHAN_TOP_BACK_LEFT ) +#define AV_CH_TOP_BACK_CENTER (1ULL << AV_CHAN_TOP_BACK_CENTER ) +#define AV_CH_TOP_BACK_RIGHT (1ULL << AV_CHAN_TOP_BACK_RIGHT ) +#define AV_CH_STEREO_LEFT (1ULL << AV_CHAN_STEREO_LEFT ) +#define AV_CH_STEREO_RIGHT (1ULL << AV_CHAN_STEREO_RIGHT ) +#define AV_CH_WIDE_LEFT (1ULL << AV_CHAN_WIDE_LEFT ) +#define AV_CH_WIDE_RIGHT (1ULL << AV_CHAN_WIDE_RIGHT ) +#define AV_CH_SURROUND_DIRECT_LEFT (1ULL << AV_CHAN_SURROUND_DIRECT_LEFT ) +#define AV_CH_SURROUND_DIRECT_RIGHT (1ULL << AV_CHAN_SURROUND_DIRECT_RIGHT) +#define AV_CH_LOW_FREQUENCY_2 (1ULL << AV_CHAN_LOW_FREQUENCY_2 ) +#define AV_CH_TOP_SIDE_LEFT (1ULL << AV_CHAN_TOP_SIDE_LEFT ) +#define AV_CH_TOP_SIDE_RIGHT (1ULL << AV_CHAN_TOP_SIDE_RIGHT ) +#define AV_CH_BOTTOM_FRONT_CENTER (1ULL << AV_CHAN_BOTTOM_FRONT_CENTER ) +#define AV_CH_BOTTOM_FRONT_LEFT (1ULL << AV_CHAN_BOTTOM_FRONT_LEFT ) +#define AV_CH_BOTTOM_FRONT_RIGHT (1ULL << AV_CHAN_BOTTOM_FRONT_RIGHT ) +#define AV_CH_SIDE_SURROUND_LEFT (1ULL << AV_CHAN_SIDE_SURROUND_LEFT ) +#define AV_CH_SIDE_SURROUND_RIGHT (1ULL << AV_CHAN_SIDE_SURROUND_RIGHT ) +#define AV_CH_TOP_SURROUND_LEFT (1ULL << AV_CHAN_TOP_SURROUND_LEFT ) +#define AV_CH_TOP_SURROUND_RIGHT (1ULL << AV_CHAN_TOP_SURROUND_RIGHT ) +#define AV_CH_BINAURAL_LEFT (1ULL << AV_CHAN_BINAURAL_LEFT ) +#define AV_CH_BINAURAL_RIGHT (1ULL << AV_CHAN_BINAURAL_RIGHT ) + +/** + * @} + * @defgroup channel_mask_c Audio channel layouts + * @{ + * */ +#define AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT) +#define AV_CH_LAYOUT_2POINT1 (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_1 (AV_CH_LAYOUT_STEREO|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_3POINT1 (AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_4POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_4POINT1 (AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_2 (AV_CH_LAYOUT_STEREO|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_QUAD (AV_CH_LAYOUT_STEREO|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_5POINT1 (AV_CH_LAYOUT_5POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_5POINT0_BACK (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT1_BACK (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_6POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT0_FRONT (AV_CH_LAYOUT_2_2|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_HEXAGONAL (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_3POINT1POINT2 (AV_CH_LAYOUT_3POINT1|AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT) +#define AV_CH_LAYOUT_6POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_FRONT (AV_CH_LAYOUT_6POINT0_FRONT|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_7POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT0_FRONT (AV_CH_LAYOUT_5POINT0|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT1_WIDE (AV_CH_LAYOUT_5POINT1|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1_WIDE_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_5POINT1POINT2 (AV_CH_LAYOUT_5POINT1|AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT) +#define AV_CH_LAYOUT_5POINT1POINT2_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT) +#define AV_CH_LAYOUT_OCTAGONAL (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_CENTER|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_CUBE (AV_CH_LAYOUT_QUAD|AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT|AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT1POINT4_BACK (AV_CH_LAYOUT_5POINT1POINT2|AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT1POINT2 (AV_CH_LAYOUT_7POINT1|AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT) +#define AV_CH_LAYOUT_7POINT1POINT4_BACK (AV_CH_LAYOUT_7POINT1POINT2|AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT2POINT3 (AV_CH_LAYOUT_7POINT1POINT2|AV_CH_TOP_BACK_CENTER|AV_CH_LOW_FREQUENCY_2) +#define AV_CH_LAYOUT_9POINT1POINT4_BACK (AV_CH_LAYOUT_7POINT1POINT4_BACK|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_9POINT1POINT6 (AV_CH_LAYOUT_9POINT1POINT4_BACK|AV_CH_TOP_SIDE_LEFT|AV_CH_TOP_SIDE_RIGHT) +#define AV_CH_LAYOUT_HEXADECAGONAL (AV_CH_LAYOUT_OCTAGONAL|AV_CH_WIDE_LEFT|AV_CH_WIDE_RIGHT|AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_RIGHT|AV_CH_TOP_BACK_CENTER|AV_CH_TOP_FRONT_CENTER|AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT) +#define AV_CH_LAYOUT_BINAURAL (AV_CH_BINAURAL_LEFT|AV_CH_BINAURAL_RIGHT) +#define AV_CH_LAYOUT_STEREO_DOWNMIX (AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT) +#define AV_CH_LAYOUT_22POINT2 (AV_CH_LAYOUT_9POINT1POINT6|AV_CH_BACK_CENTER|AV_CH_LOW_FREQUENCY_2|AV_CH_TOP_FRONT_CENTER|AV_CH_TOP_CENTER|AV_CH_TOP_BACK_CENTER|AV_CH_BOTTOM_FRONT_CENTER|AV_CH_BOTTOM_FRONT_LEFT|AV_CH_BOTTOM_FRONT_RIGHT) + +#define AV_CH_LAYOUT_7POINT1_TOP_BACK AV_CH_LAYOUT_5POINT1POINT2_BACK + +enum AVMatrixEncoding { + AV_MATRIX_ENCODING_NONE, + AV_MATRIX_ENCODING_DOLBY, + AV_MATRIX_ENCODING_DPLII, + AV_MATRIX_ENCODING_DPLIIX, + AV_MATRIX_ENCODING_DPLIIZ, + AV_MATRIX_ENCODING_DOLBYEX, + AV_MATRIX_ENCODING_DOLBYHEADPHONE, + AV_MATRIX_ENCODING_NB +}; + +/** + * @} + */ + +/** + * An AVChannelCustom defines a single channel within a custom order layout + * + * Unlike most structures in FFmpeg, sizeof(AVChannelCustom) is a part of the + * public ABI. + * + * No new fields may be added to it without a major version bump. + */ +typedef struct AVChannelCustom { + enum AVChannel id; + char name[16]; + void *opaque; +} AVChannelCustom; + +/** + * An AVChannelLayout holds information about the channel layout of audio data. + * + * A channel layout here is defined as a set of channels ordered in a specific + * way (unless the channel order is AV_CHANNEL_ORDER_UNSPEC, in which case an + * AVChannelLayout carries only the channel count). + * All orders may be treated as if they were AV_CHANNEL_ORDER_UNSPEC by + * ignoring everything but the channel count, as long as av_channel_layout_check() + * considers they are valid. + * + * Unlike most structures in FFmpeg, sizeof(AVChannelLayout) is a part of the + * public ABI and may be used by the caller. E.g. it may be allocated on stack + * or embedded in caller-defined structs. + * + * AVChannelLayout can be initialized as follows: + * - default initialization with {0}, followed by setting all used fields + * correctly; + * - by assigning one of the predefined AV_CHANNEL_LAYOUT_* initializers; + * - with a constructor function, such as av_channel_layout_default(), + * av_channel_layout_from_mask() or av_channel_layout_from_string(). + * + * The channel layout must be uninitialized with av_channel_layout_uninit() + * + * Copying an AVChannelLayout via assigning is forbidden, + * av_channel_layout_copy() must be used instead (and its return value should + * be checked) + * + * No new fields may be added to it without a major version bump, except for + * new elements of the union fitting in sizeof(uint64_t). + */ +typedef struct AVChannelLayout { + /** + * Channel order used in this layout. + * This is a mandatory field. + */ + enum AVChannelOrder order; + + /** + * Number of channels in this layout. Mandatory field. + */ + int nb_channels; + + /** + * Details about which channels are present in this layout. + * For AV_CHANNEL_ORDER_UNSPEC, this field is undefined and must not be + * used. + */ + union { + /** + * This member must be used for AV_CHANNEL_ORDER_NATIVE, and may be used + * for AV_CHANNEL_ORDER_AMBISONIC to signal non-diegetic channels. + * It is a bitmask, where the position of each set bit means that the + * AVChannel with the corresponding value is present. + * + * I.e. when (mask & (1 << AV_CHAN_FOO)) is non-zero, then AV_CHAN_FOO + * is present in the layout. Otherwise it is not present. + * + * @note when a channel layout using a bitmask is constructed or + * modified manually (i.e. not using any of the av_channel_layout_* + * functions), the code doing it must ensure that the number of set bits + * is equal to nb_channels. + */ + uint64_t mask; + /** + * This member must be used when the channel order is + * AV_CHANNEL_ORDER_CUSTOM. It is a nb_channels-sized array, with each + * element signalling the presence of the AVChannel with the + * corresponding value in map[i].id. + * + * I.e. when map[i].id is equal to AV_CHAN_FOO, then AV_CH_FOO is the + * i-th channel in the audio data. + * + * When map[i].id is in the range between AV_CHAN_AMBISONIC_BASE and + * AV_CHAN_AMBISONIC_END (inclusive), the channel contains an ambisonic + * component with ACN index (as defined above) + * n = map[i].id - AV_CHAN_AMBISONIC_BASE. + * + * map[i].name may be filled with a 0-terminated string, in which case + * it will be used for the purpose of identifying the channel with the + * convenience functions below. Otherwise it must be zeroed. + */ + AVChannelCustom *map; + } u; + + /** + * For some private data of the user. + */ + void *opaque; +} AVChannelLayout; + +/** + * Macro to define native channel layouts + * + * @note This doesn't use designated initializers for compatibility with C++ 17 and older. + */ +#define AV_CHANNEL_LAYOUT_MASK(nb, m) \ + { /* .order */ AV_CHANNEL_ORDER_NATIVE, \ + /* .nb_channels */ (nb), \ + /* .u.mask */ { m }, \ + /* .opaque */ NULL } + +/** + * @name Common pre-defined channel layouts + * @{ + */ +#define AV_CHANNEL_LAYOUT_MONO AV_CHANNEL_LAYOUT_MASK(1, AV_CH_LAYOUT_MONO) +#define AV_CHANNEL_LAYOUT_STEREO AV_CHANNEL_LAYOUT_MASK(2, AV_CH_LAYOUT_STEREO) +#define AV_CHANNEL_LAYOUT_2POINT1 AV_CHANNEL_LAYOUT_MASK(3, AV_CH_LAYOUT_2POINT1) +#define AV_CHANNEL_LAYOUT_2_1 AV_CHANNEL_LAYOUT_MASK(3, AV_CH_LAYOUT_2_1) +#define AV_CHANNEL_LAYOUT_SURROUND AV_CHANNEL_LAYOUT_MASK(3, AV_CH_LAYOUT_SURROUND) +#define AV_CHANNEL_LAYOUT_3POINT1 AV_CHANNEL_LAYOUT_MASK(4, AV_CH_LAYOUT_3POINT1) +#define AV_CHANNEL_LAYOUT_4POINT0 AV_CHANNEL_LAYOUT_MASK(4, AV_CH_LAYOUT_4POINT0) +#define AV_CHANNEL_LAYOUT_4POINT1 AV_CHANNEL_LAYOUT_MASK(5, AV_CH_LAYOUT_4POINT1) +#define AV_CHANNEL_LAYOUT_2_2 AV_CHANNEL_LAYOUT_MASK(4, AV_CH_LAYOUT_2_2) +#define AV_CHANNEL_LAYOUT_QUAD AV_CHANNEL_LAYOUT_MASK(4, AV_CH_LAYOUT_QUAD) +#define AV_CHANNEL_LAYOUT_5POINT0 AV_CHANNEL_LAYOUT_MASK(5, AV_CH_LAYOUT_5POINT0) +#define AV_CHANNEL_LAYOUT_5POINT1 AV_CHANNEL_LAYOUT_MASK(6, AV_CH_LAYOUT_5POINT1) +#define AV_CHANNEL_LAYOUT_5POINT0_BACK AV_CHANNEL_LAYOUT_MASK(5, AV_CH_LAYOUT_5POINT0_BACK) +#define AV_CHANNEL_LAYOUT_5POINT1_BACK AV_CHANNEL_LAYOUT_MASK(6, AV_CH_LAYOUT_5POINT1_BACK) +#define AV_CHANNEL_LAYOUT_6POINT0 AV_CHANNEL_LAYOUT_MASK(6, AV_CH_LAYOUT_6POINT0) +#define AV_CHANNEL_LAYOUT_6POINT0_FRONT AV_CHANNEL_LAYOUT_MASK(6, AV_CH_LAYOUT_6POINT0_FRONT) +#define AV_CHANNEL_LAYOUT_3POINT1POINT2 AV_CHANNEL_LAYOUT_MASK(6, AV_CH_LAYOUT_3POINT1POINT2) +#define AV_CHANNEL_LAYOUT_HEXAGONAL AV_CHANNEL_LAYOUT_MASK(6, AV_CH_LAYOUT_HEXAGONAL) +#define AV_CHANNEL_LAYOUT_6POINT1 AV_CHANNEL_LAYOUT_MASK(7, AV_CH_LAYOUT_6POINT1) +#define AV_CHANNEL_LAYOUT_6POINT1_BACK AV_CHANNEL_LAYOUT_MASK(7, AV_CH_LAYOUT_6POINT1_BACK) +#define AV_CHANNEL_LAYOUT_6POINT1_FRONT AV_CHANNEL_LAYOUT_MASK(7, AV_CH_LAYOUT_6POINT1_FRONT) +#define AV_CHANNEL_LAYOUT_7POINT0 AV_CHANNEL_LAYOUT_MASK(7, AV_CH_LAYOUT_7POINT0) +#define AV_CHANNEL_LAYOUT_7POINT0_FRONT AV_CHANNEL_LAYOUT_MASK(7, AV_CH_LAYOUT_7POINT0_FRONT) +#define AV_CHANNEL_LAYOUT_7POINT1 AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_7POINT1) +#define AV_CHANNEL_LAYOUT_7POINT1_WIDE AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_7POINT1_WIDE) +#define AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_7POINT1_WIDE_BACK) +#define AV_CHANNEL_LAYOUT_5POINT1POINT2 AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_5POINT1POINT2) +#define AV_CHANNEL_LAYOUT_5POINT1POINT2_BACK AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_5POINT1POINT2_BACK) +#define AV_CHANNEL_LAYOUT_OCTAGONAL AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_OCTAGONAL) +#define AV_CHANNEL_LAYOUT_CUBE AV_CHANNEL_LAYOUT_MASK(8, AV_CH_LAYOUT_CUBE) +#define AV_CHANNEL_LAYOUT_5POINT1POINT4_BACK AV_CHANNEL_LAYOUT_MASK(10, AV_CH_LAYOUT_5POINT1POINT4_BACK) +#define AV_CHANNEL_LAYOUT_7POINT1POINT2 AV_CHANNEL_LAYOUT_MASK(10, AV_CH_LAYOUT_7POINT1POINT2) +#define AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK AV_CHANNEL_LAYOUT_MASK(12, AV_CH_LAYOUT_7POINT1POINT4_BACK) +#define AV_CHANNEL_LAYOUT_7POINT2POINT3 AV_CHANNEL_LAYOUT_MASK(12, AV_CH_LAYOUT_7POINT2POINT3) +#define AV_CHANNEL_LAYOUT_9POINT1POINT4_BACK AV_CHANNEL_LAYOUT_MASK(14, AV_CH_LAYOUT_9POINT1POINT4_BACK) +#define AV_CHANNEL_LAYOUT_9POINT1POINT6 AV_CHANNEL_LAYOUT_MASK(16, AV_CH_LAYOUT_9POINT1POINT6) +#define AV_CHANNEL_LAYOUT_HEXADECAGONAL AV_CHANNEL_LAYOUT_MASK(16, AV_CH_LAYOUT_HEXADECAGONAL) +#define AV_CHANNEL_LAYOUT_BINAURAL AV_CHANNEL_LAYOUT_MASK(2, AV_CH_LAYOUT_BINAURAL) +#define AV_CHANNEL_LAYOUT_STEREO_DOWNMIX AV_CHANNEL_LAYOUT_MASK(2, AV_CH_LAYOUT_STEREO_DOWNMIX) +#define AV_CHANNEL_LAYOUT_22POINT2 AV_CHANNEL_LAYOUT_MASK(24, AV_CH_LAYOUT_22POINT2) + +#define AV_CHANNEL_LAYOUT_7POINT1_TOP_BACK AV_CHANNEL_LAYOUT_5POINT1POINT2_BACK + +#define AV_CHANNEL_LAYOUT_AMBISONIC_FIRST_ORDER \ + { /* .order */ AV_CHANNEL_ORDER_AMBISONIC, \ + /* .nb_channels */ 4, \ + /* .u.mask */ { 0 }, \ + /* .opaque */ NULL } +/** @} */ + +struct AVBPrint; + +/** + * Get a human readable string in an abbreviated form describing a given channel. + * This is the inverse function of @ref av_channel_from_string(). + * + * @param buf pre-allocated buffer where to put the generated string + * @param buf_size size in bytes of the buffer. + * @param channel the AVChannel whose name to get + * @return amount of bytes needed to hold the output string, or a negative AVERROR + * on failure. If the returned value is bigger than buf_size, then the + * string was truncated. + */ +int av_channel_name(char *buf, size_t buf_size, enum AVChannel channel); + +/** + * bprint variant of av_channel_name(). + * + * @note the string will be appended to the bprint buffer. + */ +void av_channel_name_bprint(struct AVBPrint *bp, enum AVChannel channel_id); + +/** + * Get a human readable string describing a given channel. + * + * @param buf pre-allocated buffer where to put the generated string + * @param buf_size size in bytes of the buffer. + * @param channel the AVChannel whose description to get + * @return amount of bytes needed to hold the output string, or a negative AVERROR + * on failure. If the returned value is bigger than buf_size, then the + * string was truncated. + */ +int av_channel_description(char *buf, size_t buf_size, enum AVChannel channel); + +/** + * bprint variant of av_channel_description(). + * + * @note the string will be appended to the bprint buffer. + */ +void av_channel_description_bprint(struct AVBPrint *bp, enum AVChannel channel_id); + +/** + * This is the inverse function of @ref av_channel_name(). + * + * @return the channel with the given name + * AV_CHAN_NONE when name does not identify a known channel + */ +enum AVChannel av_channel_from_string(const char *name); + +/** + * Initialize a custom channel layout with the specified number of channels. + * The channel map will be allocated and the designation of all channels will + * be set to AV_CHAN_UNKNOWN. + * + * This is only a convenience helper function, a custom channel layout can also + * be constructed without using this. + * + * @param channel_layout the layout structure to be initialized + * @param nb_channels the number of channels + * + * @return 0 on success + * AVERROR(EINVAL) if the number of channels <= 0 + * AVERROR(ENOMEM) if the channel map could not be allocated + */ +int av_channel_layout_custom_init(AVChannelLayout *channel_layout, int nb_channels); + +/** + * Initialize a native channel layout from a bitmask indicating which channels + * are present. + * + * @param channel_layout the layout structure to be initialized + * @param mask bitmask describing the channel layout + * + * @return 0 on success + * AVERROR(EINVAL) for invalid mask values + */ +int av_channel_layout_from_mask(AVChannelLayout *channel_layout, uint64_t mask); + +/** + * Initialize a channel layout from a given string description. + * The input string can be represented by: + * - the formal channel layout name (returned by av_channel_layout_describe()) + * - single or multiple channel names (returned by av_channel_name(), eg. "FL", + * or concatenated with "+", each optionally containing a custom name after + * a "@", eg. "FL@Left+FR@Right+LFE") + * - a decimal or hexadecimal value of a native channel layout (eg. "4" or "0x4") + * - the number of channels with default layout (eg. "4c") + * - the number of unordered channels (eg. "4C" or "4 channels") + * - the ambisonic order followed by optional non-diegetic channels (eg. + * "ambisonic 2+stereo") + * On error, the channel layout will remain uninitialized, but not necessarily + * untouched. + * + * @param channel_layout uninitialized channel layout for the result + * @param str string describing the channel layout + * @return 0 on success parsing the channel layout + * AVERROR(EINVAL) if an invalid channel layout string was provided + * AVERROR(ENOMEM) if there was not enough memory + */ +int av_channel_layout_from_string(AVChannelLayout *channel_layout, + const char *str); + +/** + * Get the default channel layout for a given number of channels. + * + * @param ch_layout the layout structure to be initialized + * @param nb_channels number of channels + */ +void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels); + +/** + * Iterate over all standard channel layouts. + * + * @param opaque a pointer where libavutil will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the standard channel layout or NULL when the iteration is + * finished + */ +const AVChannelLayout *av_channel_layout_standard(void **opaque); + +/** + * Free any allocated data in the channel layout and reset the channel + * count to 0. + * + * @param channel_layout the layout structure to be uninitialized + */ +void av_channel_layout_uninit(AVChannelLayout *channel_layout); + +/** + * Make a copy of a channel layout. This differs from just assigning src to dst + * in that it allocates and copies the map for AV_CHANNEL_ORDER_CUSTOM. + * + * @note the destination channel_layout will be always uninitialized before copy. + * + * @param dst destination channel layout + * @param src source channel layout + * @return 0 on success, a negative AVERROR on error. + */ +int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src); + +/** + * Get a human-readable string describing the channel layout properties. + * The string will be in the same format that is accepted by + * @ref av_channel_layout_from_string(), allowing to rebuild the same + * channel layout, except for opaque pointers. + * + * @param channel_layout channel layout to be described + * @param buf pre-allocated buffer where to put the generated string + * @param buf_size size in bytes of the buffer. + * @return amount of bytes needed to hold the output string, or a negative AVERROR + * on failure. If the returned value is bigger than buf_size, then the + * string was truncated. + */ +int av_channel_layout_describe(const AVChannelLayout *channel_layout, + char *buf, size_t buf_size); + +/** + * bprint variant of av_channel_layout_describe(). + * + * @note the string will be appended to the bprint buffer. + * @return 0 on success, or a negative AVERROR value on failure. + */ +int av_channel_layout_describe_bprint(const AVChannelLayout *channel_layout, + struct AVBPrint *bp); + +/** + * Get the channel with the given index in a channel layout. + * + * @param channel_layout input channel layout + * @param idx index of the channel + * @return channel with the index idx in channel_layout on success or + * AV_CHAN_NONE on failure (if idx is not valid or the channel order is + * unspecified) + */ +enum AVChannel +av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout, unsigned int idx); + +/** + * Get the index of a given channel in a channel layout. In case multiple + * channels are found, only the first match will be returned. + * + * @param channel_layout input channel layout + * @param channel the channel whose index to obtain + * @return index of channel in channel_layout on success or a negative number if + * channel is not present in channel_layout. + */ +int av_channel_layout_index_from_channel(const AVChannelLayout *channel_layout, + enum AVChannel channel); + +/** + * Get the index in a channel layout of a channel described by the given string. + * In case multiple channels are found, only the first match will be returned. + * + * This function accepts channel names in the same format as + * @ref av_channel_from_string(). + * + * @param channel_layout input channel layout + * @param name string describing the channel whose index to obtain + * @return a channel index described by the given string, or a negative AVERROR + * value. + */ +int av_channel_layout_index_from_string(const AVChannelLayout *channel_layout, + const char *name); + +/** + * Get a channel described by the given string. + * + * This function accepts channel names in the same format as + * @ref av_channel_from_string(). + * + * @param channel_layout input channel layout + * @param name string describing the channel to obtain + * @return a channel described by the given string in channel_layout on success + * or AV_CHAN_NONE on failure (if the string is not valid or the channel + * order is unspecified) + */ +enum AVChannel +av_channel_layout_channel_from_string(const AVChannelLayout *channel_layout, + const char *name); + +/** + * Find out what channels from a given set are present in a channel layout, + * without regard for their positions. + * + * @param channel_layout input channel layout + * @param mask a combination of AV_CH_* representing a set of channels + * @return a bitfield representing all the channels from mask that are present + * in channel_layout + */ +uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout, + uint64_t mask); + +/** + * Check whether a channel layout is valid, i.e. can possibly describe audio + * data. + * + * @param channel_layout input channel layout + * @return 1 if channel_layout is valid, 0 otherwise. + */ +int av_channel_layout_check(const AVChannelLayout *channel_layout); + +/** + * Check whether two channel layouts are semantically the same, i.e. the same + * channels are present on the same positions in both. + * + * If one of the channel layouts is AV_CHANNEL_ORDER_UNSPEC, while the other is + * not, they are considered to be unequal. If both are AV_CHANNEL_ORDER_UNSPEC, + * they are considered equal iff the channel counts are the same in both. + * + * @param chl input channel layout + * @param chl1 input channel layout + * @return 0 if chl and chl1 are equal, 1 if they are not equal. A negative + * AVERROR code if one or both are invalid. + */ +int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1); + +/** + * Return the order if the layout is n-th order standard-order ambisonic. + * The presence of optional extra non-diegetic channels at the end is not taken + * into account. + * + * @param channel_layout input channel layout + * @return the order of the layout, a negative error code otherwise. + */ +int av_channel_layout_ambisonic_order(const AVChannelLayout *channel_layout); + +/** + * The conversion must be lossless. + */ +#define AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS (1 << 0) + +/** + * The specified retype target order is ignored and the simplest possible + * (canonical) order is used for which the input layout can be losslessy + * represented. + */ +#define AV_CHANNEL_LAYOUT_RETYPE_FLAG_CANONICAL (1 << 1) + +/** + * Change the AVChannelOrder of a channel layout. + * + * Change of AVChannelOrder can be either lossless or lossy. In case of a + * lossless conversion all the channel designations and the associated channel + * names (if any) are kept. On a lossy conversion the channel names and channel + * designations might be lost depending on the capabilities of the desired + * AVChannelOrder. Note that some conversions are simply not possible in which + * case this function returns AVERROR(ENOSYS). + * + * The following conversions are supported: + * + * Any -> Custom : Always possible, always lossless. + * Any -> Unspecified: Always possible, lossless if channel designations + * are all unknown and channel names are not used, lossy otherwise. + * Custom -> Ambisonic : Possible if it contains ambisonic channels with + * optional non-diegetic channels in the end. Lossy if the channels have + * custom names, lossless otherwise. + * Custom -> Native : Possible if it contains native channels in native + * order. Lossy if the channels have custom names, lossless otherwise. + * + * On error this function keeps the original channel layout untouched. + * + * @param channel_layout channel layout which will be changed + * @param order the desired channel layout order + * @param flags a combination of AV_CHANNEL_LAYOUT_RETYPE_FLAG_* constants + * @return 0 if the conversion was successful and lossless or if the channel + * layout was already in the desired order + * >0 if the conversion was successful but lossy + * AVERROR(ENOSYS) if the conversion was not possible (or would be + * lossy and AV_CHANNEL_LAYOUT_RETYPE_FLAG_LOSSLESS was specified) + * AVERROR(EINVAL), AVERROR(ENOMEM) on error + */ +int av_channel_layout_retype(AVChannelLayout *channel_layout, enum AVChannelOrder order, int flags); + +/** + * @} + */ + +#endif /* AVUTIL_CHANNEL_LAYOUT_H */ diff --git a/libs/ffmpeg/libavutil/common.h b/libs/ffmpeg/libavutil/common.h new file mode 100644 index 00000000000..bf23aa50b0c --- /dev/null +++ b/libs/ffmpeg/libavutil/common.h @@ -0,0 +1,589 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * common internal and external API header + */ + +#ifndef AVUTIL_COMMON_H +#define AVUTIL_COMMON_H + +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) && !defined(UINT64_C) +#error missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS +#endif + +#include <errno.h> +#include <inttypes.h> +#include <limits.h> +#include <math.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "attributes.h" +#include "error.h" +#include "macros.h" +#include "version.h" + +#ifdef HAVE_AV_CONFIG_H +# include "config.h" +# include "intmath.h" +# include "internal.h" +#else +# include "mem.h" +#endif /* HAVE_AV_CONFIG_H */ + +//rounded division & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>=0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +/* Fast a/(1<<b) rounded toward +inf. Assume a>=0 and b>=0 */ +#define AV_CEIL_RSHIFT(a,b) (!av_builtin_constant_p(b) ? -((-(a)) >> (b)) \ + : ((a) + (1<<(b)) - 1) >> (b)) +/* Backwards compat. */ +#define FF_CEIL_RSHIFT AV_CEIL_RSHIFT + +#define FFUDIV(a,b) (((a)>0 ?(a):(a)-(b)+1) / (b)) +#define FFUMOD(a,b) ((a)-(b)*FFUDIV(a,b)) + +/** + * Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they + * are not representable as absolute values of their type. This is the same + * as with *abs() + * @see FFNABS() + */ +#define FFABS(a) ((a) >= 0 ? (a) : (-(a))) +#define FFSIGN(a) ((a) > 0 ? 1 : -1) + +/** + * Negative Absolute value. + * this works for all integers of all types. + * As with many macros, this evaluates its argument twice, it thus must not have + * a sideeffect, that is FFNABS(x++) has undefined behavior. + */ +#define FFNABS(a) ((a) <= 0 ? (a) : (-(a))) + +/** + * Unsigned Absolute value. + * This takes the absolute value of a signed int and returns it as a unsigned. + * This also works with INT_MIN which would otherwise not be representable + * As with many macros, this evaluates its argument twice. + */ +#define FFABSU(a) ((a) <= 0 ? -(unsigned)(a) : (unsigned)(a)) +#define FFABS64U(a) ((a) <= 0 ? -(uint64_t)(a) : (uint64_t)(a)) + +/* misc math functions */ + +#ifndef av_ceil_log2 +# define av_ceil_log2 av_ceil_log2_c +#endif +#ifndef av_clip +# define av_clip av_clip_c +#endif +#ifndef av_clip64 +# define av_clip64 av_clip64_c +#endif +#ifndef av_clip_uint8 +# define av_clip_uint8 av_clip_uint8_c +#endif +#ifndef av_clip_int8 +# define av_clip_int8 av_clip_int8_c +#endif +#ifndef av_clip_uint16 +# define av_clip_uint16 av_clip_uint16_c +#endif +#ifndef av_clip_int16 +# define av_clip_int16 av_clip_int16_c +#endif +#ifndef av_clipl_int32 +# define av_clipl_int32 av_clipl_int32_c +#endif +#ifndef av_clip_intp2 +# define av_clip_intp2 av_clip_intp2_c +#endif +#ifndef av_clip_uintp2 +# define av_clip_uintp2 av_clip_uintp2_c +#endif +#ifndef av_sat_add32 +# define av_sat_add32 av_sat_add32_c +#endif +#ifndef av_sat_dadd32 +# define av_sat_dadd32 av_sat_dadd32_c +#endif +#ifndef av_sat_sub32 +# define av_sat_sub32 av_sat_sub32_c +#endif +#ifndef av_sat_dsub32 +# define av_sat_dsub32 av_sat_dsub32_c +#endif +#ifndef av_sat_add64 +# define av_sat_add64 av_sat_add64_c +#endif +#ifndef av_sat_sub64 +# define av_sat_sub64 av_sat_sub64_c +#endif +#ifndef av_clipf +# define av_clipf av_clipf_c +#endif +#ifndef av_clipd +# define av_clipd av_clipd_c +#endif +#ifndef av_zero_extend +# define av_zero_extend av_zero_extend_c +#endif +#ifndef av_popcount +# define av_popcount av_popcount_c +#endif +#ifndef av_popcount64 +# define av_popcount64 av_popcount64_c +#endif +#ifndef av_parity +# define av_parity av_parity_c +#endif + +#ifndef av_log2 +av_const int av_log2(unsigned v); +#endif + +#ifndef av_log2_16bit +av_const int av_log2_16bit(unsigned v); +#endif + +/** + * Clip a signed integer value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const int av_clip_c(int a, int amin, int amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a signed 64bit integer value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a signed integer value into the 0-255 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const uint8_t av_clip_uint8_c(int a) +{ + if (a&(~0xFF)) return (~a)>>31; + else return a; +} + +/** + * Clip a signed integer value into the -128,127 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int8_t av_clip_int8_c(int a) +{ + if ((a+0x80U) & ~0xFF) return (a>>31) ^ 0x7F; + else return a; +} + +/** + * Clip a signed integer value into the 0-65535 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const uint16_t av_clip_uint16_c(int a) +{ + if (a&(~0xFFFF)) return (~a)>>31; + else return a; +} + +/** + * Clip a signed integer value into the -32768,32767 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int16_t av_clip_int16_c(int a) +{ + if ((a+0x8000U) & ~0xFFFF) return (a>>31) ^ 0x7FFF; + else return a; +} + +/** + * Clip a signed 64-bit integer value into the -2147483648,2147483647 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int32_t av_clipl_int32_c(int64_t a) +{ + if ((a+UINT64_C(0x80000000)) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF); + else return (int32_t)a; +} + +/** + * Clip a signed integer into the -(2^p),(2^p-1) range. + * @param a value to clip + * @param p bit position to clip at + * @return clipped value + */ +static av_always_inline av_const int av_clip_intp2_c(int a, int p) +{ + if (((unsigned)a + (1U << p)) & ~((2U << p) - 1)) + return (a >> 31) ^ ((1 << p) - 1); + else + return a; +} + +/** + * Clip a signed integer to an unsigned power of two range. + * @param a value to clip + * @param p bit position to clip at + * @return clipped value + */ +static av_always_inline av_const unsigned av_clip_uintp2_c(int a, int p) +{ + if (a & ~((1U<<p) - 1)) return (~a) >> 31 & ((1U<<p) - 1); + else return a; +} + +/** + * Clear high bits from an unsigned integer starting with specific bit position + * @param a value to clip + * @param p bit position to clip at. Must be between 0 and 31. + * @return clipped value + */ +static av_always_inline av_const unsigned av_zero_extend_c(unsigned a, unsigned p) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (p > 31) abort(); +#endif + return a & ((1U << p) - 1); +} + +#if FF_API_MOD_UINTP2 +#ifndef av_mod_uintp2 +# define av_mod_uintp2 av_mod_uintp2_c +#endif +attribute_deprecated +static av_always_inline av_const unsigned av_mod_uintp2_c(unsigned a, unsigned p) +{ + return av_zero_extend_c(a, p); +} +#endif + +/** + * Add two signed 32-bit values with saturation. + * + * @param a one value + * @param b another value + * @return sum with signed saturation + */ +static av_always_inline int av_sat_add32_c(int a, int b) +{ + return av_clipl_int32((int64_t)a + b); +} + +/** + * Add a doubled value to another value with saturation at both stages. + * + * @param a first value + * @param b value doubled and added to a + * @return sum sat(a + sat(2*b)) with signed saturation + */ +static av_always_inline int av_sat_dadd32_c(int a, int b) +{ + return av_sat_add32(a, av_sat_add32(b, b)); +} + +/** + * Subtract two signed 32-bit values with saturation. + * + * @param a one value + * @param b another value + * @return difference with signed saturation + */ +static av_always_inline int av_sat_sub32_c(int a, int b) +{ + return av_clipl_int32((int64_t)a - b); +} + +/** + * Subtract a doubled value from another value with saturation at both stages. + * + * @param a first value + * @param b value doubled and subtracted from a + * @return difference sat(a - sat(2*b)) with signed saturation + */ +static av_always_inline int av_sat_dsub32_c(int a, int b) +{ + return av_sat_sub32(a, av_sat_add32(b, b)); +} + +/** + * Add two signed 64-bit values with saturation. + * + * @param a one value + * @param b another value + * @return sum with signed saturation + */ +static av_always_inline int64_t av_sat_add64_c(int64_t a, int64_t b) { +#if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_add_overflow) + int64_t tmp; + return !__builtin_add_overflow(a, b, &tmp) ? tmp : (tmp < 0 ? INT64_MAX : INT64_MIN); +#else + int64_t s = a+(uint64_t)b; + if ((int64_t)(a^b | ~s^b) >= 0) + return INT64_MAX ^ (b >> 63); + return s; +#endif +} + +/** + * Subtract two signed 64-bit values with saturation. + * + * @param a one value + * @param b another value + * @return difference with signed saturation + */ +static av_always_inline int64_t av_sat_sub64_c(int64_t a, int64_t b) { +#if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_sub_overflow) + int64_t tmp; + return !__builtin_sub_overflow(a, b, &tmp) ? tmp : (tmp < 0 ? INT64_MAX : INT64_MIN); +#else + if (b <= 0 && a >= INT64_MAX + b) + return INT64_MAX; + if (b >= 0 && a <= INT64_MIN + b) + return INT64_MIN; + return a - b; +#endif +} + +/** + * Clip a float value into the amin-amax range. + * If a is nan or -inf amin will be returned. + * If a is +inf amax will be returned. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const float av_clipf_c(float a, float amin, float amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + return FFMIN(FFMAX(a, amin), amax); +} + +/** + * Clip a double value into the amin-amax range. + * If a is nan or -inf amin will be returned. + * If a is +inf amax will be returned. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const double av_clipd_c(double a, double amin, double amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + return FFMIN(FFMAX(a, amin), amax); +} + +/** Compute ceil(log2(x)). + * @param x value used to compute ceil(log2(x)) + * @return computed ceiling of log2(x) + */ +static av_always_inline av_const int av_ceil_log2_c(int x) +{ + return av_log2((x - 1U) << 1); +} + +/** + * Count number of bits set to one in x + * @param x value to count bits of + * @return the number of bits set to one in x + */ +static av_always_inline av_const int av_popcount_c(uint32_t x) +{ + x -= (x >> 1) & 0x55555555; + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x += x >> 8; + return (x + (x >> 16)) & 0x3F; +} + +/** + * Count number of bits set to one in x + * @param x value to count bits of + * @return the number of bits set to one in x + */ +static av_always_inline av_const int av_popcount64_c(uint64_t x) +{ + return av_popcount((uint32_t)x) + av_popcount((uint32_t)(x >> 32)); +} + +static av_always_inline av_const int av_parity_c(uint32_t v) +{ + return av_popcount(v) & 1; +} + +/** + * Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form. + * + * @param val Output value, must be an lvalue of type uint32_t. + * @param GET_BYTE Expression reading one byte from the input. + * Evaluated up to 7 times (4 for the currently + * assigned Unicode range). With a memory buffer + * input, this could be *ptr++, or if you want to make sure + * that *ptr stops at the end of a NULL terminated string then + * *ptr ? *ptr++ : 0 + * @param ERROR Expression to be evaluated on invalid input, + * typically a goto statement. + * + * @warning ERROR should not contain a loop control statement which + * could interact with the internal while loop, and should force an + * exit from the macro code (e.g. through a goto or a return) in order + * to prevent undefined results. + */ +#define GET_UTF8(val, GET_BYTE, ERROR)\ + val= (uint8_t)(GET_BYTE);\ + {\ + uint32_t top = (val & 128) >> 1;\ + if ((val & 0xc0) == 0x80 || val >= 0xFE)\ + {ERROR}\ + while (val & top) {\ + unsigned int tmp = (uint8_t)(GET_BYTE) - 128;\ + if(tmp>>6)\ + {ERROR}\ + val= (val<<6) + tmp;\ + top <<= 5;\ + }\ + val &= (top << 1) - 1;\ + } + +/** + * Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form. + * + * @param val Output value, must be an lvalue of type uint32_t. + * @param GET_16BIT Expression returning two bytes of UTF-16 data converted + * to native byte order. Evaluated one or two times. + * @param ERROR Expression to be evaluated on invalid input, + * typically a goto statement. + */ +#define GET_UTF16(val, GET_16BIT, ERROR)\ + val = (uint16_t)(GET_16BIT);\ + {\ + unsigned int hi = val - 0xD800;\ + if (hi < 0x800) {\ + val = (uint16_t)(GET_16BIT) - 0xDC00;\ + if (val > 0x3FFU || hi > 0x3FFU)\ + {ERROR}\ + val += (hi<<10) + 0x10000;\ + }\ + }\ + +/** + * @def PUT_UTF8(val, tmp, PUT_BYTE) + * Convert a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long). + * @param val is an input-only argument and should be of type uint32_t. It holds + * a UCS-4 encoded Unicode character that is to be converted to UTF-8. If + * val is given as a function it is executed only once. + * @param tmp is a temporary variable and should be of type uint8_t. It + * represents an intermediate value during conversion that is to be + * output by PUT_BYTE. + * @param PUT_BYTE writes the converted UTF-8 bytes to any proper destination. + * It could be a function or a statement, and uses tmp as the input byte. + * For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be + * executed up to 4 times for values in the valid UTF-8 range and up to + * 7 times in the general case, depending on the length of the converted + * Unicode character. + */ +#define PUT_UTF8(val, tmp, PUT_BYTE)\ + {\ + int bytes, shift;\ + uint32_t in = val;\ + if (in < 0x80) {\ + tmp = in;\ + PUT_BYTE\ + } else {\ + bytes = (av_log2(in) + 4) / 5;\ + shift = (bytes - 1) * 6;\ + tmp = (256 - (256 >> bytes)) | (in >> shift);\ + PUT_BYTE\ + while (shift >= 6) {\ + shift -= 6;\ + tmp = 0x80 | ((in >> shift) & 0x3f);\ + PUT_BYTE\ + }\ + }\ + } + +/** + * @def PUT_UTF16(val, tmp, PUT_16BIT) + * Convert a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes). + * @param val is an input-only argument and should be of type uint32_t. It holds + * a UCS-4 encoded Unicode character that is to be converted to UTF-16. If + * val is given as a function it is executed only once. + * @param tmp is a temporary variable and should be of type uint16_t. It + * represents an intermediate value during conversion that is to be + * output by PUT_16BIT. + * @param PUT_16BIT writes the converted UTF-16 data to any proper destination + * in desired endianness. It could be a function or a statement, and uses tmp + * as the input byte. For example, PUT_BYTE could be "*output++ = tmp;" + * PUT_BYTE will be executed 1 or 2 times depending on input character. + */ +#define PUT_UTF16(val, tmp, PUT_16BIT)\ + {\ + uint32_t in = val;\ + if (in < 0x10000) {\ + tmp = in;\ + PUT_16BIT\ + } else {\ + tmp = 0xD800 | ((in - 0x10000) >> 10);\ + PUT_16BIT\ + tmp = 0xDC00 | ((in - 0x10000) & 0x3FF);\ + PUT_16BIT\ + }\ + }\ + +#endif /* AVUTIL_COMMON_H */ diff --git a/libs/ffmpeg/libavutil/container_fifo.c b/libs/ffmpeg/libavutil/container_fifo.c new file mode 100644 index 00000000000..34a78e7ef31 --- /dev/null +++ b/libs/ffmpeg/libavutil/container_fifo.c @@ -0,0 +1,219 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avassert.h" +#include "container_fifo.h" +#include "error.h" +#include "fifo.h" +#include "frame.h" +#include "mem.h" +#include "refstruct.h" + +struct AVContainerFifo { + AVFifo *fifo; + AVRefStructPool *pool; + + void *opaque; + void* (*container_alloc)(void *opaque); + void (*container_reset)(void *opaque, void *obj); + void (*container_free) (void *opaque, void *obj); + int (*fifo_transfer) (void *opaque, void *dst, void *src, unsigned flags); + +}; + +static int container_fifo_init_entry(AVRefStructOpaque opaque, void *obj) +{ + AVContainerFifo *cf = opaque.nc; + void **pobj = obj; + + *pobj = cf->container_alloc(cf->opaque); + if (!*pobj) + return AVERROR(ENOMEM); + + return 0; +} + +static void container_fifo_reset_entry(AVRefStructOpaque opaque, void *obj) +{ + AVContainerFifo *cf = opaque.nc; + cf->container_reset(cf->opaque, *(void**)obj); +} + +static void container_fifo_free_entry(AVRefStructOpaque opaque, void *obj) +{ + AVContainerFifo *cf = opaque.nc; + cf->container_free(cf->opaque, *(void**)obj); +} + +AVContainerFifo* +av_container_fifo_alloc(void *opaque, + void* (*container_alloc)(void *opaque), + void (*container_reset)(void *opaque, void *obj), + void (*container_free) (void *opaque, void *obj), + int (*fifo_transfer) (void *opaque, void *dst, void *src, unsigned flags), + unsigned flags) +{ + AVContainerFifo *cf; + + cf = av_mallocz(sizeof(*cf)); + if (!cf) + return NULL; + + cf->opaque = opaque; + cf->container_alloc = container_alloc; + cf->container_reset = container_reset; + cf->container_free = container_free; + cf->fifo_transfer = fifo_transfer; + + cf->fifo = av_fifo_alloc2(1, sizeof(void*), AV_FIFO_FLAG_AUTO_GROW); + if (!cf->fifo) + goto fail; + + cf->pool = av_refstruct_pool_alloc_ext(sizeof(void*), 0, cf, + container_fifo_init_entry, + container_fifo_reset_entry, + container_fifo_free_entry, + NULL); + if (!cf->pool) + goto fail; + + return cf; +fail: + av_container_fifo_free(&cf); + return NULL; +} + +void av_container_fifo_free(AVContainerFifo **pcf) +{ + AVContainerFifo *cf; + + if (!*pcf) + return; + + cf = *pcf; + + if (cf->fifo) { + void *obj; + while (av_fifo_read(cf->fifo, &obj, 1) >= 0) + av_refstruct_unref(&obj); + av_fifo_freep2(&cf->fifo); + } + + av_refstruct_pool_uninit(&cf->pool); + + av_freep(pcf); +} + +int av_container_fifo_read(AVContainerFifo *cf, void *obj, unsigned flags) +{ + void **psrc; + int ret; + + ret = av_fifo_read(cf->fifo, &psrc, 1); + if (ret < 0) + return ret; + + ret = cf->fifo_transfer(cf->opaque, obj, *psrc, flags); + av_refstruct_unref(&psrc); + + return ret; +} + +int av_container_fifo_peek(AVContainerFifo *cf, void **pdst, size_t offset) +{ + void **pobj; + int ret; + + ret = av_fifo_peek(cf->fifo, &pobj, 1, offset); + if (ret < 0) + return ret; + + *pdst = *pobj; + + return 0; +} + +void av_container_fifo_drain(AVContainerFifo *cf, size_t nb_elems) +{ + av_assert0(nb_elems <= av_fifo_can_read(cf->fifo)); + while (nb_elems--) { + void **pobj; + int ret = av_fifo_read(cf->fifo, &pobj, 1); + av_assert0(ret >= 0); + av_refstruct_unref(&pobj); + } +} + +int av_container_fifo_write(AVContainerFifo *cf, void *obj, unsigned flags) +{ + void **pdst; + int ret; + + pdst = av_refstruct_pool_get(cf->pool); + if (!pdst) + return AVERROR(ENOMEM); + + ret = cf->fifo_transfer(cf->opaque, *pdst, obj, flags); + if (ret < 0) + goto fail; + + ret = av_fifo_write(cf->fifo, &pdst, 1); + if (ret < 0) + goto fail; + + return 0; +fail: + av_refstruct_unref(&pdst); + return ret; +} + +size_t av_container_fifo_can_read(const AVContainerFifo *cf) +{ + return av_fifo_can_read(cf->fifo); +} + +static void *frame_alloc(void *opaque) +{ + return av_frame_alloc(); +} + +static void frame_reset(void *opaque, void *obj) +{ + av_frame_unref(obj); +} + +static void frame_free(void *opaque, void *obj) +{ + AVFrame *frame = obj; + av_frame_free(&frame); +} + +static int frame_transfer(void *opaque, void *dst, void *src, unsigned flags) +{ + if (flags & AV_CONTAINER_FIFO_FLAG_REF) + return av_frame_ref(dst, src); + + av_frame_move_ref(dst, src); + return 0; +} + +AVContainerFifo *av_container_fifo_alloc_avframe(unsigned flags) +{ + return av_container_fifo_alloc(NULL, frame_alloc, frame_reset, frame_free, + frame_transfer, 0); +} diff --git a/libs/ffmpeg/libavutil/container_fifo.h b/libs/ffmpeg/libavutil/container_fifo.h new file mode 100644 index 00000000000..ff9249311f6 --- /dev/null +++ b/libs/ffmpeg/libavutil/container_fifo.h @@ -0,0 +1,130 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CONTAINER_FIFO_H +#define AVUTIL_CONTAINER_FIFO_H + +#include <stddef.h> + +/** + * AVContainerFifo is a FIFO for "containers" - dynamically allocated reusable + * structs (e.g. AVFrame or AVPacket). AVContainerFifo uses an internal pool of + * such containers to avoid allocating and freeing them repeatedly. + */ +typedef struct AVContainerFifo AVContainerFifo; + +enum AVContainerFifoFlags { + /** + * Signal to av_container_fifo_write() that it should make a new reference + * to data in src rather than consume its contents. + * + * @note you must handle this flag manually in your own fifo_transfer() + * callback + */ + AV_CONTAINER_FIFO_FLAG_REF = (1 << 0), + + /** + * This and all higher bits in flags may be set to any value by the caller + * and are guaranteed to be passed through to the fifo_transfer() callback + * and not be interpreted by AVContainerFifo code. + */ + AV_CONTAINER_FIFO_FLAG_USER = (1 << 16), +}; + +/** + * Allocate a new AVContainerFifo for the container type defined by provided + * callbacks. + * + * @param opaque user data that will be passed to the callbacks provided to this + * function + * @param container_alloc allocate a new container instance and return a pointer + * to it, or NULL on failure + * @param container_reset reset the provided container instance to a clean state + * @param container_free free the provided container instance + * @param fifo_transfer Transfer the contents of container src to dst. + * @param flags currently unused + * + * @return newly allocated AVContainerFifo, or NULL on failure + */ +AVContainerFifo* +av_container_fifo_alloc(void *opaque, + void* (*container_alloc)(void *opaque), + void (*container_reset)(void *opaque, void *obj), + void (*container_free) (void *opaque, void *obj), + int (*fifo_transfer) (void *opaque, void *dst, void *src, unsigned flags), + unsigned flags); + +/** + * Allocate an AVContainerFifo instance for AVFrames. + * + * @param flags currently unused + */ +AVContainerFifo *av_container_fifo_alloc_avframe(unsigned flags); + +/** + * Free a AVContainerFifo and everything in it. + */ +void av_container_fifo_free(AVContainerFifo **cf); + +/** + * Write the contents of obj to the FIFO. + * + * The fifo_transfer() callback previously provided to av_container_fifo_alloc() + * will be called with obj as src in order to perform the actual transfer. + */ +int av_container_fifo_write(AVContainerFifo *cf, void *obj, unsigned flags); + +/** + * Read the next available object from the FIFO into obj. + * + * The fifo_read() callback previously provided to av_container_fifo_alloc() + * will be called with obj as dst in order to perform the actual transfer. + */ +int av_container_fifo_read(AVContainerFifo *cf, void *obj, unsigned flags); + +/** + * Access objects stored in the FIFO without retrieving them. The + * fifo_transfer() callback will NOT be invoked and the FIFO state will not be + * modified. + * + * @param pobj Pointer to the object stored in the FIFO will be written here on + * success. The object remains owned by the FIFO and the caller may + * only access it as long as the FIFO is not modified. + * @param offset Position of the object to retrieve - 0 is the next item that + * would be read, 1 the one after, etc. Must be smaller than + * av_container_fifo_can_read(). + * + * @retval 0 success, a pointer was written into pobj + * @retval AVERROR(EINVAL) invalid offset value + */ +int av_container_fifo_peek(AVContainerFifo *cf, void **pobj, size_t offset); + +/** + * Discard the specified number of elements from the FIFO. + * + * @param nb_elems number of elements to discard, MUST NOT be larger than + * av_fifo_can_read(f) + */ +void av_container_fifo_drain(AVContainerFifo *cf, size_t nb_elems); + +/** + * @return number of objects available for reading + */ +size_t av_container_fifo_can_read(const AVContainerFifo *cf); + +#endif // AVCODEC_CONTAINER_FIFO_H diff --git a/libs/ffmpeg/libavutil/cpu.c b/libs/ffmpeg/libavutil/cpu.c new file mode 100644 index 00000000000..07b90aa90a1 --- /dev/null +++ b/libs/ffmpeg/libavutil/cpu.c @@ -0,0 +1,324 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#if HAVE_SCHED_GETAFFINITY +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif +#include <sched.h> +#endif + +#include <stddef.h> +#include <stdint.h> +#include <stdatomic.h> + +#include "attributes.h" +#include "cpu.h" +#include "cpu_internal.h" +#include "opt.h" +#include "common.h" + +#if HAVE_GETPROCESSAFFINITYMASK || HAVE_WINRT +#include <windows.h> +#endif +#if HAVE_SYSCTL +#if HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +#include <sys/types.h> +#include <sys/sysctl.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +#if HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO +#include <sys/auxv.h> +#endif + +static atomic_int cpu_flags = -1; +static atomic_int cpu_count = -1; + +static int get_cpu_flags(void) +{ +#if ARCH_MIPS + return ff_get_cpu_flags_mips(); +#elif ARCH_AARCH64 + return ff_get_cpu_flags_aarch64(); +#elif ARCH_ARM + return ff_get_cpu_flags_arm(); +#elif ARCH_PPC + return ff_get_cpu_flags_ppc(); +#elif ARCH_RISCV + return ff_get_cpu_flags_riscv(); +#elif ARCH_WASM + return ff_get_cpu_flags_wasm(); +#elif ARCH_X86 + return ff_get_cpu_flags_x86(); +#elif ARCH_LOONGARCH + return ff_get_cpu_flags_loongarch(); +#endif + return 0; +} + +void av_force_cpu_flags(int arg){ + if (ARCH_X86 && + (arg & ( AV_CPU_FLAG_3DNOW | + AV_CPU_FLAG_3DNOWEXT | + AV_CPU_FLAG_MMXEXT | + AV_CPU_FLAG_SSE | + AV_CPU_FLAG_SSE2 | + AV_CPU_FLAG_SSE2SLOW | + AV_CPU_FLAG_SSE3 | + AV_CPU_FLAG_SSE3SLOW | + AV_CPU_FLAG_SSSE3 | + AV_CPU_FLAG_SSE4 | + AV_CPU_FLAG_SSE42 | + AV_CPU_FLAG_AVX | + AV_CPU_FLAG_AVXSLOW | + AV_CPU_FLAG_XOP | + AV_CPU_FLAG_FMA3 | + AV_CPU_FLAG_FMA4 | + AV_CPU_FLAG_AVX2 | + AV_CPU_FLAG_AVX512 )) + && !(arg & AV_CPU_FLAG_MMX)) { + av_log(NULL, AV_LOG_WARNING, "MMX implied by specified flags\n"); + arg |= AV_CPU_FLAG_MMX; + } + + atomic_store_explicit(&cpu_flags, arg, memory_order_relaxed); +} + +int av_get_cpu_flags(void) +{ + int flags = atomic_load_explicit(&cpu_flags, memory_order_relaxed); + if (flags == -1) { + flags = get_cpu_flags(); + atomic_store_explicit(&cpu_flags, flags, memory_order_relaxed); + } + return flags; +} + +int av_parse_cpu_caps(unsigned *flags, const char *s) +{ + static const AVOption cpuflags_opts[] = { + { "flags" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" }, +#if ARCH_PPC + { "altivec" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ALTIVEC }, .unit = "flags" }, + { "vsx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VSX }, .unit = "flags" }, + { "power8" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_POWER8 }, .unit = "flags" }, +#elif ARCH_X86 + { "mmx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX }, .unit = "flags" }, + { "mmx2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX2 }, .unit = "flags" }, + { "mmxext" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX2 }, .unit = "flags" }, + { "sse" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE }, .unit = "flags" }, + { "sse2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE2 }, .unit = "flags" }, + { "sse2slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE2SLOW }, .unit = "flags" }, + { "sse3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE3 }, .unit = "flags" }, + { "sse3slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE3SLOW }, .unit = "flags" }, + { "ssse3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSSE3 }, .unit = "flags" }, + { "atom" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ATOM }, .unit = "flags" }, + { "sse4.1" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE4 }, .unit = "flags" }, + { "sse4.2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SSE42 }, .unit = "flags" }, + { "avx" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVX }, .unit = "flags" }, + { "avxslow" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVXSLOW }, .unit = "flags" }, + { "xop" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_XOP }, .unit = "flags" }, + { "fma3" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_FMA3 }, .unit = "flags" }, + { "fma4" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_FMA4 }, .unit = "flags" }, + { "avx2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVX2 }, .unit = "flags" }, + { "bmi1" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_BMI1 }, .unit = "flags" }, + { "bmi2" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_BMI2 }, .unit = "flags" }, + { "3dnow" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_3DNOW }, .unit = "flags" }, + { "3dnowext", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_3DNOWEXT }, .unit = "flags" }, + { "cmov", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_CMOV }, .unit = "flags" }, + { "aesni", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AESNI }, .unit = "flags" }, + { "clmul", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_CLMUL }, .unit = "flags" }, + { "avx512" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVX512 }, .unit = "flags" }, + { "avx512icl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVX512ICL }, .unit = "flags" }, + { "slowgather", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SLOW_GATHER }, .unit = "flags" }, + +#define CPU_FLAG_P2 AV_CPU_FLAG_CMOV | AV_CPU_FLAG_MMX +#define CPU_FLAG_P3 CPU_FLAG_P2 | AV_CPU_FLAG_MMX2 | AV_CPU_FLAG_SSE +#define CPU_FLAG_P4 CPU_FLAG_P3| AV_CPU_FLAG_SSE2 + { "pentium2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_P2 }, .unit = "flags" }, + { "pentium3", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_P3 }, .unit = "flags" }, + { "pentium4", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_P4 }, .unit = "flags" }, + +#define CPU_FLAG_K62 AV_CPU_FLAG_MMX | AV_CPU_FLAG_3DNOW +#define CPU_FLAG_ATHLON CPU_FLAG_K62 | AV_CPU_FLAG_CMOV | AV_CPU_FLAG_3DNOWEXT | AV_CPU_FLAG_MMX2 +#define CPU_FLAG_ATHLONXP CPU_FLAG_ATHLON | AV_CPU_FLAG_SSE +#define CPU_FLAG_K8 CPU_FLAG_ATHLONXP | AV_CPU_FLAG_SSE2 + { "k6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMX }, .unit = "flags" }, + { "k62", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_K62 }, .unit = "flags" }, + { "athlon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_ATHLON }, .unit = "flags" }, + { "athlonxp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_ATHLONXP }, .unit = "flags" }, + { "k8", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPU_FLAG_K8 }, .unit = "flags" }, +#elif ARCH_ARM + { "armv5te", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV5TE }, .unit = "flags" }, + { "armv6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV6 }, .unit = "flags" }, + { "armv6t2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV6T2 }, .unit = "flags" }, + { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" }, + { "vfp_vm", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP_VM }, .unit = "flags" }, + { "vfpv3", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFPV3 }, .unit = "flags" }, + { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" }, + { "setend", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SETEND }, .unit = "flags" }, +#elif ARCH_AARCH64 + { "armv8", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV8 }, .unit = "flags" }, + { "neon", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_NEON }, .unit = "flags" }, + { "vfp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_VFP }, .unit = "flags" }, + { "dotprod", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_DOTPROD }, .unit = "flags" }, + { "i8mm", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_I8MM }, .unit = "flags" }, + { "sve", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SVE }, .unit = "flags" }, + { "sve2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SVE2 }, .unit = "flags" }, + { "sme", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SME }, .unit = "flags" }, + { "crc", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARM_CRC }, .unit = "flags" }, + { "sme_i16i64", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SME_I16I64 }, .unit = "flags" }, + + { "sme2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SME2 }, .unit = "flags" }, +#elif ARCH_MIPS + { "mmi", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MMI }, .unit = "flags" }, + { "msa", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_MSA }, .unit = "flags" }, +#elif ARCH_LOONGARCH + { "lsx", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_LSX }, .unit = "flags" }, + { "lasx", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_LASX }, .unit = "flags" }, +#elif ARCH_RISCV + { "rvi", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVI }, .unit = "flags" }, + { "rvb", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVB }, .unit = "flags" }, + { "zve32x", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVV_I32 }, .unit = "flags" }, + { "zve32f", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVV_F32 }, .unit = "flags" }, + { "zve64x", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVV_I64 }, .unit = "flags" }, + { "zve64d", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVV_F64 }, .unit = "flags" }, + { "zbb", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RVB_BASIC }, .unit = "flags" }, + { "zvbb", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RV_ZVBB }, .unit = "flags" }, + { "misaligned", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_RV_MISALIGNED }, .unit = "flags" }, +#elif ARCH_WASM + { "simd128", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_SIMD128 }, .unit = "flags" }, +#endif + { NULL }, + }; + static const AVClass class = { + .class_name = "cpuflags", + .item_name = av_default_item_name, + .option = cpuflags_opts, + .version = LIBAVUTIL_VERSION_INT, + }; + const AVClass *pclass = &class; + + return av_opt_eval_flags(&pclass, &cpuflags_opts[0], s, flags); +} + +int av_cpu_count(void) +{ + static atomic_int printed = 0; + + int nb_cpus = 1; + int count = 0; +#if HAVE_WINRT + SYSTEM_INFO sysinfo; +#endif +#if HAVE_SCHED_GETAFFINITY && defined(CPU_COUNT) + cpu_set_t cpuset; + + CPU_ZERO(&cpuset); + + if (!sched_getaffinity(0, sizeof(cpuset), &cpuset)) + nb_cpus = CPU_COUNT(&cpuset); +#elif HAVE_GETPROCESSAFFINITYMASK + DWORD_PTR proc_aff, sys_aff; + if (GetProcessAffinityMask(GetCurrentProcess(), &proc_aff, &sys_aff)) + nb_cpus = av_popcount64(proc_aff); +#elif HAVE_SYSCTL && defined(HW_NCPUONLINE) + int mib[2] = { CTL_HW, HW_NCPUONLINE }; + size_t len = sizeof(nb_cpus); + + if (sysctl(mib, 2, &nb_cpus, &len, NULL, 0) == -1) + nb_cpus = 0; +#elif HAVE_SYSCTL && defined(HW_NCPU) + int mib[2] = { CTL_HW, HW_NCPU }; + size_t len = sizeof(nb_cpus); + + if (sysctl(mib, 2, &nb_cpus, &len, NULL, 0) == -1) + nb_cpus = 0; +#elif HAVE_SYSCONF && defined(_SC_NPROC_ONLN) + nb_cpus = sysconf(_SC_NPROC_ONLN); +#elif HAVE_SYSCONF && defined(_SC_NPROCESSORS_ONLN) + nb_cpus = sysconf(_SC_NPROCESSORS_ONLN); +#elif HAVE_WINRT + GetNativeSystemInfo(&sysinfo); + nb_cpus = sysinfo.dwNumberOfProcessors; +#endif + + if (!atomic_exchange_explicit(&printed, 1, memory_order_relaxed)) + av_log(NULL, AV_LOG_DEBUG, "detected %d logical cores\n", nb_cpus); + + count = atomic_load_explicit(&cpu_count, memory_order_relaxed); + + if (count > 0) { + nb_cpus = count; + av_log(NULL, AV_LOG_DEBUG, "overriding to %d logical cores\n", nb_cpus); + } + + return nb_cpus; +} + +void av_cpu_force_count(int count) +{ + atomic_store_explicit(&cpu_count, count, memory_order_relaxed); +} + +size_t av_cpu_max_align(void) +{ +#if ARCH_MIPS + return ff_get_cpu_max_align_mips(); +#elif ARCH_AARCH64 + return ff_get_cpu_max_align_aarch64(); +#elif ARCH_ARM + return ff_get_cpu_max_align_arm(); +#elif ARCH_PPC + return ff_get_cpu_max_align_ppc(); +#elif ARCH_WASM + return ff_get_cpu_max_align_wasm(); +#elif ARCH_X86 + return ff_get_cpu_max_align_x86(); +#elif ARCH_LOONGARCH + return ff_get_cpu_max_align_loongarch(); +#endif + + return 8; +} + +#if !ARCH_X86 +unsigned long ff_getauxval(unsigned long type) +{ +#if HAVE_GETAUXVAL + return getauxval(type); +#elif HAVE_ELF_AUX_INFO + unsigned long aux = 0; + int ret = elf_aux_info(type, &aux, sizeof(aux)); + if (ret != 0) { + errno = ret; + } + return aux; +#else + errno = ENOSYS; + return 0; +#endif +} +#endif diff --git a/libs/ffmpeg/libavutil/cpu.h b/libs/ffmpeg/libavutil/cpu.h new file mode 100644 index 00000000000..464d4cd5dff --- /dev/null +++ b/libs/ffmpeg/libavutil/cpu.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CPU_H +#define AVUTIL_CPU_H + +#include <stddef.h> +#include "version.h" + +#if FF_API_CPU_FLAG_FORCE +#define AV_CPU_FLAG_FORCE 0x80000000 /* @deprecated, should not be used */ +#endif + + /* lower 16 bits - CPU features */ +#define AV_CPU_FLAG_MMX 0x0001 ///< standard MMX +#define AV_CPU_FLAG_MMXEXT 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_MMX2 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_3DNOW 0x0004 ///< AMD 3DNOW +#define AV_CPU_FLAG_SSE 0x0008 ///< SSE functions +#define AV_CPU_FLAG_SSE2 0x0010 ///< PIV SSE2 functions +#define AV_CPU_FLAG_SSE2SLOW 0x40000000 ///< SSE2 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_3DNOWEXT 0x0020 ///< AMD 3DNowExt +#define AV_CPU_FLAG_SSE3 0x0040 ///< Prescott SSE3 functions +#define AV_CPU_FLAG_SSE3SLOW 0x20000000 ///< SSE3 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_SSSE3 0x0080 ///< Conroe SSSE3 functions +#define AV_CPU_FLAG_SSSE3SLOW 0x4000000 ///< SSSE3 supported, but usually not faster +#define AV_CPU_FLAG_ATOM 0x10000000 ///< Atom processor, some SSSE3 instructions are slower +#define AV_CPU_FLAG_SSE4 0x0100 ///< Penryn SSE4.1 functions +#define AV_CPU_FLAG_SSE42 0x0200 ///< Nehalem SSE4.2 functions +#define AV_CPU_FLAG_AESNI 0x80000 ///< Advanced Encryption Standard functions +#define AV_CPU_FLAG_CLMUL 0x400000 ///< Carry-less Multiplication instruction +#define AV_CPU_FLAG_AVX 0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_AVXSLOW 0x8000000 ///< AVX supported, but slow when using YMM registers (e.g. Bulldozer) +#define AV_CPU_FLAG_XOP 0x0400 ///< Bulldozer XOP functions +#define AV_CPU_FLAG_FMA4 0x0800 ///< Bulldozer FMA4 functions +#define AV_CPU_FLAG_CMOV 0x1000 ///< supports cmov instruction +#define AV_CPU_FLAG_AVX2 0x8000 ///< AVX2 functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_FMA3 0x10000 ///< Haswell FMA3 functions +#define AV_CPU_FLAG_BMI1 0x20000 ///< Bit Manipulation Instruction Set 1 +#define AV_CPU_FLAG_BMI2 0x40000 ///< Bit Manipulation Instruction Set 2 +#define AV_CPU_FLAG_AVX512 0x100000 ///< AVX-512 functions: requires OS support even if YMM/ZMM registers aren't used +#define AV_CPU_FLAG_AVX512ICL 0x200000 ///< F/CD/BW/DQ/VL/VNNI/IFMA/VBMI/VBMI2/VPOPCNTDQ/BITALG/GFNI/VAES/VPCLMULQDQ +#define AV_CPU_FLAG_SLOW_GATHER 0x2000000 ///< CPU has slow gathers. + +#define AV_CPU_FLAG_ALTIVEC 0x0001 ///< standard +#define AV_CPU_FLAG_VSX 0x0002 ///< ISA 2.06 +#define AV_CPU_FLAG_POWER8 0x0004 ///< ISA 2.07 + +#define AV_CPU_FLAG_ARMV5TE (1 << 0) +#define AV_CPU_FLAG_ARMV6 (1 << 1) +#define AV_CPU_FLAG_ARMV6T2 (1 << 2) +#define AV_CPU_FLAG_VFP (1 << 3) +#define AV_CPU_FLAG_VFPV3 (1 << 4) +#define AV_CPU_FLAG_NEON (1 << 5) +#define AV_CPU_FLAG_ARMV8 (1 << 6) +#define AV_CPU_FLAG_VFP_VM (1 << 7) ///< VFPv2 vector mode, deprecated in ARMv7-A and unavailable in various CPUs implementations +#define AV_CPU_FLAG_DOTPROD (1 << 8) +#define AV_CPU_FLAG_I8MM (1 << 9) +#define AV_CPU_FLAG_SVE (1 <<10) +#define AV_CPU_FLAG_SVE2 (1 <<11) +#define AV_CPU_FLAG_SME (1 <<12) +#define AV_CPU_FLAG_ARM_CRC (1 <<13) +#define AV_CPU_FLAG_SME2 (1 <<14) +#define AV_CPU_FLAG_SME_I16I64 (1 <<15) +#define AV_CPU_FLAG_SETEND (1 <<16) + +#define AV_CPU_FLAG_MMI (1 << 0) +#define AV_CPU_FLAG_MSA (1 << 1) + +//Loongarch SIMD extension. +#define AV_CPU_FLAG_LSX (1 << 0) +#define AV_CPU_FLAG_LASX (1 << 1) + +// RISC-V extensions +#define AV_CPU_FLAG_RVI (1 << 0) ///< I (full GPR bank) +#if FF_API_RISCV_FD_ZBA +#define AV_CPU_FLAG_RVF (1 << 1) ///< F (single precision FP) +#define AV_CPU_FLAG_RVD (1 << 2) ///< D (double precision FP) +#endif +#define AV_CPU_FLAG_RVV_I32 (1 << 3) ///< Vectors of 8/16/32-bit int's */ +#define AV_CPU_FLAG_RVV_F32 (1 << 4) ///< Vectors of float's */ +#define AV_CPU_FLAG_RVV_I64 (1 << 5) ///< Vectors of 64-bit int's */ +#define AV_CPU_FLAG_RVV_F64 (1 << 6) ///< Vectors of double's +#define AV_CPU_FLAG_RVB_BASIC (1 << 7) ///< Basic bit-manipulations +#if FF_API_RISCV_FD_ZBA +#define AV_CPU_FLAG_RVB_ADDR (1 << 8) ///< Address bit-manipulations +#endif +#define AV_CPU_FLAG_RV_ZVBB (1 << 9) ///< Vector basic bit-manipulations +#define AV_CPU_FLAG_RV_MISALIGNED (1 <<10) ///< Fast misaligned accesses +#define AV_CPU_FLAG_RVB (1 <<11) ///< B (bit manipulations) + +// WASM extensions +#define AV_CPU_FLAG_SIMD128 (1 << 0) + +/** + * Return the flags which specify extensions supported by the CPU. + * The returned value is affected by av_force_cpu_flags() if that was used + * before. So av_get_cpu_flags() can easily be used in an application to + * detect the enabled cpu flags. + */ +int av_get_cpu_flags(void); + +/** + * Disables cpu detection and forces the specified flags. + * -1 is a special case that disables forcing of specific flags. + */ +void av_force_cpu_flags(int flags); + +/** + * Parse CPU caps from a string and update the given AV_CPU_* flags based on that. + * + * @return negative on error. + */ +int av_parse_cpu_caps(unsigned *flags, const char *s); + +/** + * @return the number of logical CPU cores present. + */ +int av_cpu_count(void); + +/** + * Overrides cpu count detection and forces the specified count. + * Count < 1 disables forcing of specific count. + */ +void av_cpu_force_count(int count); + +/** + * Get the maximum data alignment that may be required by FFmpeg. + * + * Note that this is affected by the build configuration and the CPU flags mask, + * so e.g. if the CPU supports AVX, but libavutil has been built with + * --disable-avx or the AV_CPU_FLAG_AVX flag has been disabled through + * av_set_cpu_flags_mask(), then this function will behave as if AVX is not + * present. + */ +size_t av_cpu_max_align(void); + +#endif /* AVUTIL_CPU_H */ diff --git a/libs/ffmpeg/libavutil/cpu_internal.h b/libs/ffmpeg/libavutil/cpu_internal.h new file mode 100644 index 00000000000..8dca62334a0 --- /dev/null +++ b/libs/ffmpeg/libavutil/cpu_internal.h @@ -0,0 +1,66 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CPU_INTERNAL_H +#define AVUTIL_CPU_INTERNAL_H + +#include "config.h" + +#include "cpu.h" + +#define CPUEXT_SUFFIX(flags, suffix, cpuext) \ + (HAVE_ ## cpuext ## suffix && ((flags) & AV_CPU_FLAG_ ## cpuext)) + +#define CPUEXT_SUFFIX_FAST2(flags, suffix, cpuext, slow_cpuext) \ + (HAVE_ ## cpuext ## suffix && ((flags) & AV_CPU_FLAG_ ## cpuext) && \ + !((flags) & AV_CPU_FLAG_ ## slow_cpuext ## SLOW)) + +#define CPUEXT_SUFFIX_SLOW(flags, suffix, cpuext) \ + (HAVE_ ## cpuext ## suffix && \ + ((flags) & (AV_CPU_FLAG_ ## cpuext | AV_CPU_FLAG_ ## cpuext ## SLOW))) + +#define CPUEXT_SUFFIX_SLOW2(flags, suffix, cpuext, slow_cpuext) \ + (HAVE_ ## cpuext ## suffix && ((flags) & AV_CPU_FLAG_ ## cpuext) && \ + ((flags) & (AV_CPU_FLAG_ ## slow_cpuext | AV_CPU_FLAG_ ## slow_cpuext ## SLOW))) + +#define CPUEXT_SUFFIX_FAST(flags, suffix, cpuext) CPUEXT_SUFFIX_FAST2(flags, suffix, cpuext, cpuext) + +#define CPUEXT(flags, cpuext) CPUEXT_SUFFIX(flags, , cpuext) +#define CPUEXT_FAST(flags, cpuext) CPUEXT_SUFFIX_FAST(flags, , cpuext) +#define CPUEXT_SLOW(flags, cpuext) CPUEXT_SUFFIX_SLOW(flags, , cpuext) + +int ff_get_cpu_flags_mips(void); +int ff_get_cpu_flags_aarch64(void); +int ff_get_cpu_flags_arm(void); +int ff_get_cpu_flags_ppc(void); +int ff_get_cpu_flags_riscv(void); +int ff_get_cpu_flags_wasm(void); +int ff_get_cpu_flags_x86(void); +int ff_get_cpu_flags_loongarch(void); + +size_t ff_get_cpu_max_align_mips(void); +size_t ff_get_cpu_max_align_aarch64(void); +size_t ff_get_cpu_max_align_arm(void); +size_t ff_get_cpu_max_align_ppc(void); +size_t ff_get_cpu_max_align_wasm(void); +size_t ff_get_cpu_max_align_x86(void); +size_t ff_get_cpu_max_align_loongarch(void); + +unsigned long ff_getauxval(unsigned long type); + +#endif /* AVUTIL_CPU_INTERNAL_H */ diff --git a/libs/ffmpeg/libavutil/crc.c b/libs/ffmpeg/libavutil/crc.c new file mode 100644 index 00000000000..c8ccaf81621 --- /dev/null +++ b/libs/ffmpeg/libavutil/crc.c @@ -0,0 +1,449 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "thread.h" +#include "avassert.h" +#include "bswap.h" +#include "crc.h" +#include "error.h" +#if ARCH_AARCH64 +#include "libavutil/aarch64/crc.h" +#elif ARCH_X86 +#include "libavutil/x86/crc.h" +#endif + +#if CONFIG_HARDCODED_TABLES +static const AVCRC av_crc_table[AV_CRC_MAX][257] = { + [AV_CRC_8_ATM] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, + 0x24, 0x23, 0x2A, 0x2D, 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, + 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 0xE0, 0xE7, 0xEE, 0xE9, + 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, + 0xB4, 0xB3, 0xBA, 0xBD, 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, + 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 0xB7, 0xB0, 0xB9, 0xBE, + 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, + 0x03, 0x04, 0x0D, 0x0A, 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, + 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, 0x89, 0x8E, 0x87, 0x80, + 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, + 0xDD, 0xDA, 0xD3, 0xD4, 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, + 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 0x19, 0x1E, 0x17, 0x10, + 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, + 0x6A, 0x6D, 0x64, 0x63, 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, + 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 0xAE, 0xA9, 0xA0, 0xA7, + 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, + 0xFA, 0xFD, 0xF4, 0xF3, 0x01 + }, + [AV_CRC_8_EBU] = { + 0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53, 0xE8, 0xF5, 0xD2, 0xCF, + 0x9C, 0x81, 0xA6, 0xBB, 0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E, + 0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76, 0x87, 0x9A, 0xBD, 0xA0, + 0xF3, 0xEE, 0xC9, 0xD4, 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C, + 0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19, 0xA2, 0xBF, 0x98, 0x85, + 0xD6, 0xCB, 0xEC, 0xF1, 0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40, + 0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8, 0xDE, 0xC3, 0xE4, 0xF9, + 0xAA, 0xB7, 0x90, 0x8D, 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65, + 0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7, 0x7C, 0x61, 0x46, 0x5B, + 0x08, 0x15, 0x32, 0x2F, 0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A, + 0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2, 0x26, 0x3B, 0x1C, 0x01, + 0x52, 0x4F, 0x68, 0x75, 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D, + 0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8, 0x03, 0x1E, 0x39, 0x24, + 0x77, 0x6A, 0x4D, 0x50, 0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2, + 0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A, 0x6C, 0x71, 0x56, 0x4B, + 0x18, 0x05, 0x22, 0x3F, 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7, + 0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66, 0xDD, 0xC0, 0xE7, 0xFA, + 0xA9, 0xB4, 0x93, 0x8E, 0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB, + 0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43, 0xB2, 0xAF, 0x88, 0x95, + 0xC6, 0xDB, 0xFC, 0xE1, 0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09, + 0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C, 0x97, 0x8A, 0xAD, 0xB0, + 0xE3, 0xFE, 0xD9, 0xC4, 0x01 + }, + [AV_CRC_16_ANSI] = { + 0x0000, 0x0580, 0x0F80, 0x0A00, 0x1B80, 0x1E00, 0x1400, 0x1180, + 0x3380, 0x3600, 0x3C00, 0x3980, 0x2800, 0x2D80, 0x2780, 0x2200, + 0x6380, 0x6600, 0x6C00, 0x6980, 0x7800, 0x7D80, 0x7780, 0x7200, + 0x5000, 0x5580, 0x5F80, 0x5A00, 0x4B80, 0x4E00, 0x4400, 0x4180, + 0xC380, 0xC600, 0xCC00, 0xC980, 0xD800, 0xDD80, 0xD780, 0xD200, + 0xF000, 0xF580, 0xFF80, 0xFA00, 0xEB80, 0xEE00, 0xE400, 0xE180, + 0xA000, 0xA580, 0xAF80, 0xAA00, 0xBB80, 0xBE00, 0xB400, 0xB180, + 0x9380, 0x9600, 0x9C00, 0x9980, 0x8800, 0x8D80, 0x8780, 0x8200, + 0x8381, 0x8601, 0x8C01, 0x8981, 0x9801, 0x9D81, 0x9781, 0x9201, + 0xB001, 0xB581, 0xBF81, 0xBA01, 0xAB81, 0xAE01, 0xA401, 0xA181, + 0xE001, 0xE581, 0xEF81, 0xEA01, 0xFB81, 0xFE01, 0xF401, 0xF181, + 0xD381, 0xD601, 0xDC01, 0xD981, 0xC801, 0xCD81, 0xC781, 0xC201, + 0x4001, 0x4581, 0x4F81, 0x4A01, 0x5B81, 0x5E01, 0x5401, 0x5181, + 0x7381, 0x7601, 0x7C01, 0x7981, 0x6801, 0x6D81, 0x6781, 0x6201, + 0x2381, 0x2601, 0x2C01, 0x2981, 0x3801, 0x3D81, 0x3781, 0x3201, + 0x1001, 0x1581, 0x1F81, 0x1A01, 0x0B81, 0x0E01, 0x0401, 0x0181, + 0x0383, 0x0603, 0x0C03, 0x0983, 0x1803, 0x1D83, 0x1783, 0x1203, + 0x3003, 0x3583, 0x3F83, 0x3A03, 0x2B83, 0x2E03, 0x2403, 0x2183, + 0x6003, 0x6583, 0x6F83, 0x6A03, 0x7B83, 0x7E03, 0x7403, 0x7183, + 0x5383, 0x5603, 0x5C03, 0x5983, 0x4803, 0x4D83, 0x4783, 0x4203, + 0xC003, 0xC583, 0xCF83, 0xCA03, 0xDB83, 0xDE03, 0xD403, 0xD183, + 0xF383, 0xF603, 0xFC03, 0xF983, 0xE803, 0xED83, 0xE783, 0xE203, + 0xA383, 0xA603, 0xAC03, 0xA983, 0xB803, 0xBD83, 0xB783, 0xB203, + 0x9003, 0x9583, 0x9F83, 0x9A03, 0x8B83, 0x8E03, 0x8403, 0x8183, + 0x8002, 0x8582, 0x8F82, 0x8A02, 0x9B82, 0x9E02, 0x9402, 0x9182, + 0xB382, 0xB602, 0xBC02, 0xB982, 0xA802, 0xAD82, 0xA782, 0xA202, + 0xE382, 0xE602, 0xEC02, 0xE982, 0xF802, 0xFD82, 0xF782, 0xF202, + 0xD002, 0xD582, 0xDF82, 0xDA02, 0xCB82, 0xCE02, 0xC402, 0xC182, + 0x4382, 0x4602, 0x4C02, 0x4982, 0x5802, 0x5D82, 0x5782, 0x5202, + 0x7002, 0x7582, 0x7F82, 0x7A02, 0x6B82, 0x6E02, 0x6402, 0x6182, + 0x2002, 0x2582, 0x2F82, 0x2A02, 0x3B82, 0x3E02, 0x3402, 0x3182, + 0x1382, 0x1602, 0x1C02, 0x1982, 0x0802, 0x0D82, 0x0782, 0x0202, + 0x0001 + }, + [AV_CRC_16_CCITT] = { + 0x0000, 0x2110, 0x4220, 0x6330, 0x8440, 0xA550, 0xC660, 0xE770, + 0x0881, 0x2991, 0x4AA1, 0x6BB1, 0x8CC1, 0xADD1, 0xCEE1, 0xEFF1, + 0x3112, 0x1002, 0x7332, 0x5222, 0xB552, 0x9442, 0xF772, 0xD662, + 0x3993, 0x1883, 0x7BB3, 0x5AA3, 0xBDD3, 0x9CC3, 0xFFF3, 0xDEE3, + 0x6224, 0x4334, 0x2004, 0x0114, 0xE664, 0xC774, 0xA444, 0x8554, + 0x6AA5, 0x4BB5, 0x2885, 0x0995, 0xEEE5, 0xCFF5, 0xACC5, 0x8DD5, + 0x5336, 0x7226, 0x1116, 0x3006, 0xD776, 0xF666, 0x9556, 0xB446, + 0x5BB7, 0x7AA7, 0x1997, 0x3887, 0xDFF7, 0xFEE7, 0x9DD7, 0xBCC7, + 0xC448, 0xE558, 0x8668, 0xA778, 0x4008, 0x6118, 0x0228, 0x2338, + 0xCCC9, 0xEDD9, 0x8EE9, 0xAFF9, 0x4889, 0x6999, 0x0AA9, 0x2BB9, + 0xF55A, 0xD44A, 0xB77A, 0x966A, 0x711A, 0x500A, 0x333A, 0x122A, + 0xFDDB, 0xDCCB, 0xBFFB, 0x9EEB, 0x799B, 0x588B, 0x3BBB, 0x1AAB, + 0xA66C, 0x877C, 0xE44C, 0xC55C, 0x222C, 0x033C, 0x600C, 0x411C, + 0xAEED, 0x8FFD, 0xECCD, 0xCDDD, 0x2AAD, 0x0BBD, 0x688D, 0x499D, + 0x977E, 0xB66E, 0xD55E, 0xF44E, 0x133E, 0x322E, 0x511E, 0x700E, + 0x9FFF, 0xBEEF, 0xDDDF, 0xFCCF, 0x1BBF, 0x3AAF, 0x599F, 0x788F, + 0x8891, 0xA981, 0xCAB1, 0xEBA1, 0x0CD1, 0x2DC1, 0x4EF1, 0x6FE1, + 0x8010, 0xA100, 0xC230, 0xE320, 0x0450, 0x2540, 0x4670, 0x6760, + 0xB983, 0x9893, 0xFBA3, 0xDAB3, 0x3DC3, 0x1CD3, 0x7FE3, 0x5EF3, + 0xB102, 0x9012, 0xF322, 0xD232, 0x3542, 0x1452, 0x7762, 0x5672, + 0xEAB5, 0xCBA5, 0xA895, 0x8985, 0x6EF5, 0x4FE5, 0x2CD5, 0x0DC5, + 0xE234, 0xC324, 0xA014, 0x8104, 0x6674, 0x4764, 0x2454, 0x0544, + 0xDBA7, 0xFAB7, 0x9987, 0xB897, 0x5FE7, 0x7EF7, 0x1DC7, 0x3CD7, + 0xD326, 0xF236, 0x9106, 0xB016, 0x5766, 0x7676, 0x1546, 0x3456, + 0x4CD9, 0x6DC9, 0x0EF9, 0x2FE9, 0xC899, 0xE989, 0x8AB9, 0xABA9, + 0x4458, 0x6548, 0x0678, 0x2768, 0xC018, 0xE108, 0x8238, 0xA328, + 0x7DCB, 0x5CDB, 0x3FEB, 0x1EFB, 0xF98B, 0xD89B, 0xBBAB, 0x9ABB, + 0x754A, 0x545A, 0x376A, 0x167A, 0xF10A, 0xD01A, 0xB32A, 0x923A, + 0x2EFD, 0x0FED, 0x6CDD, 0x4DCD, 0xAABD, 0x8BAD, 0xE89D, 0xC98D, + 0x267C, 0x076C, 0x645C, 0x454C, 0xA23C, 0x832C, 0xE01C, 0xC10C, + 0x1FEF, 0x3EFF, 0x5DCF, 0x7CDF, 0x9BAF, 0xBABF, 0xD98F, 0xF89F, + 0x176E, 0x367E, 0x554E, 0x745E, 0x932E, 0xB23E, 0xD10E, 0xF01E, + 0x0001 + }, + [AV_CRC_24_IEEE] = { + 0x000000, 0xFB4C86, 0x0DD58A, 0xF6990C, 0xE1E693, 0x1AAA15, 0xEC3319, + 0x177F9F, 0x3981A1, 0xC2CD27, 0x34542B, 0xCF18AD, 0xD86732, 0x232BB4, + 0xD5B2B8, 0x2EFE3E, 0x894EC5, 0x720243, 0x849B4F, 0x7FD7C9, 0x68A856, + 0x93E4D0, 0x657DDC, 0x9E315A, 0xB0CF64, 0x4B83E2, 0xBD1AEE, 0x465668, + 0x5129F7, 0xAA6571, 0x5CFC7D, 0xA7B0FB, 0xE9D10C, 0x129D8A, 0xE40486, + 0x1F4800, 0x08379F, 0xF37B19, 0x05E215, 0xFEAE93, 0xD050AD, 0x2B1C2B, + 0xDD8527, 0x26C9A1, 0x31B63E, 0xCAFAB8, 0x3C63B4, 0xC72F32, 0x609FC9, + 0x9BD34F, 0x6D4A43, 0x9606C5, 0x81795A, 0x7A35DC, 0x8CACD0, 0x77E056, + 0x591E68, 0xA252EE, 0x54CBE2, 0xAF8764, 0xB8F8FB, 0x43B47D, 0xB52D71, + 0x4E61F7, 0xD2A319, 0x29EF9F, 0xDF7693, 0x243A15, 0x33458A, 0xC8090C, + 0x3E9000, 0xC5DC86, 0xEB22B8, 0x106E3E, 0xE6F732, 0x1DBBB4, 0x0AC42B, + 0xF188AD, 0x0711A1, 0xFC5D27, 0x5BEDDC, 0xA0A15A, 0x563856, 0xAD74D0, + 0xBA0B4F, 0x4147C9, 0xB7DEC5, 0x4C9243, 0x626C7D, 0x9920FB, 0x6FB9F7, + 0x94F571, 0x838AEE, 0x78C668, 0x8E5F64, 0x7513E2, 0x3B7215, 0xC03E93, + 0x36A79F, 0xCDEB19, 0xDA9486, 0x21D800, 0xD7410C, 0x2C0D8A, 0x02F3B4, + 0xF9BF32, 0x0F263E, 0xF46AB8, 0xE31527, 0x1859A1, 0xEEC0AD, 0x158C2B, + 0xB23CD0, 0x497056, 0xBFE95A, 0x44A5DC, 0x53DA43, 0xA896C5, 0x5E0FC9, + 0xA5434F, 0x8BBD71, 0x70F1F7, 0x8668FB, 0x7D247D, 0x6A5BE2, 0x911764, + 0x678E68, 0x9CC2EE, 0xA44733, 0x5F0BB5, 0xA992B9, 0x52DE3F, 0x45A1A0, + 0xBEED26, 0x48742A, 0xB338AC, 0x9DC692, 0x668A14, 0x901318, 0x6B5F9E, + 0x7C2001, 0x876C87, 0x71F58B, 0x8AB90D, 0x2D09F6, 0xD64570, 0x20DC7C, + 0xDB90FA, 0xCCEF65, 0x37A3E3, 0xC13AEF, 0x3A7669, 0x148857, 0xEFC4D1, + 0x195DDD, 0xE2115B, 0xF56EC4, 0x0E2242, 0xF8BB4E, 0x03F7C8, 0x4D963F, + 0xB6DAB9, 0x4043B5, 0xBB0F33, 0xAC70AC, 0x573C2A, 0xA1A526, 0x5AE9A0, + 0x74179E, 0x8F5B18, 0x79C214, 0x828E92, 0x95F10D, 0x6EBD8B, 0x982487, + 0x636801, 0xC4D8FA, 0x3F947C, 0xC90D70, 0x3241F6, 0x253E69, 0xDE72EF, + 0x28EBE3, 0xD3A765, 0xFD595B, 0x0615DD, 0xF08CD1, 0x0BC057, 0x1CBFC8, + 0xE7F34E, 0x116A42, 0xEA26C4, 0x76E42A, 0x8DA8AC, 0x7B31A0, 0x807D26, + 0x9702B9, 0x6C4E3F, 0x9AD733, 0x619BB5, 0x4F658B, 0xB4290D, 0x42B001, + 0xB9FC87, 0xAE8318, 0x55CF9E, 0xA35692, 0x581A14, 0xFFAAEF, 0x04E669, + 0xF27F65, 0x0933E3, 0x1E4C7C, 0xE500FA, 0x1399F6, 0xE8D570, 0xC62B4E, + 0x3D67C8, 0xCBFEC4, 0x30B242, 0x27CDDD, 0xDC815B, 0x2A1857, 0xD154D1, + 0x9F3526, 0x6479A0, 0x92E0AC, 0x69AC2A, 0x7ED3B5, 0x859F33, 0x73063F, + 0x884AB9, 0xA6B487, 0x5DF801, 0xAB610D, 0x502D8B, 0x475214, 0xBC1E92, + 0x4A879E, 0xB1CB18, 0x167BE3, 0xED3765, 0x1BAE69, 0xE0E2EF, 0xF79D70, + 0x0CD1F6, 0xFA48FA, 0x01047C, 0x2FFA42, 0xD4B6C4, 0x222FC8, 0xD9634E, + 0xCE1CD1, 0x355057, 0xC3C95B, 0x3885DD, 0x000001, + }, + [AV_CRC_32_IEEE] = { + 0x00000000, 0xB71DC104, 0x6E3B8209, 0xD926430D, 0xDC760413, 0x6B6BC517, + 0xB24D861A, 0x0550471E, 0xB8ED0826, 0x0FF0C922, 0xD6D68A2F, 0x61CB4B2B, + 0x649B0C35, 0xD386CD31, 0x0AA08E3C, 0xBDBD4F38, 0x70DB114C, 0xC7C6D048, + 0x1EE09345, 0xA9FD5241, 0xACAD155F, 0x1BB0D45B, 0xC2969756, 0x758B5652, + 0xC836196A, 0x7F2BD86E, 0xA60D9B63, 0x11105A67, 0x14401D79, 0xA35DDC7D, + 0x7A7B9F70, 0xCD665E74, 0xE0B62398, 0x57ABE29C, 0x8E8DA191, 0x39906095, + 0x3CC0278B, 0x8BDDE68F, 0x52FBA582, 0xE5E66486, 0x585B2BBE, 0xEF46EABA, + 0x3660A9B7, 0x817D68B3, 0x842D2FAD, 0x3330EEA9, 0xEA16ADA4, 0x5D0B6CA0, + 0x906D32D4, 0x2770F3D0, 0xFE56B0DD, 0x494B71D9, 0x4C1B36C7, 0xFB06F7C3, + 0x2220B4CE, 0x953D75CA, 0x28803AF2, 0x9F9DFBF6, 0x46BBB8FB, 0xF1A679FF, + 0xF4F63EE1, 0x43EBFFE5, 0x9ACDBCE8, 0x2DD07DEC, 0x77708634, 0xC06D4730, + 0x194B043D, 0xAE56C539, 0xAB068227, 0x1C1B4323, 0xC53D002E, 0x7220C12A, + 0xCF9D8E12, 0x78804F16, 0xA1A60C1B, 0x16BBCD1F, 0x13EB8A01, 0xA4F64B05, + 0x7DD00808, 0xCACDC90C, 0x07AB9778, 0xB0B6567C, 0x69901571, 0xDE8DD475, + 0xDBDD936B, 0x6CC0526F, 0xB5E61162, 0x02FBD066, 0xBF469F5E, 0x085B5E5A, + 0xD17D1D57, 0x6660DC53, 0x63309B4D, 0xD42D5A49, 0x0D0B1944, 0xBA16D840, + 0x97C6A5AC, 0x20DB64A8, 0xF9FD27A5, 0x4EE0E6A1, 0x4BB0A1BF, 0xFCAD60BB, + 0x258B23B6, 0x9296E2B2, 0x2F2BAD8A, 0x98366C8E, 0x41102F83, 0xF60DEE87, + 0xF35DA999, 0x4440689D, 0x9D662B90, 0x2A7BEA94, 0xE71DB4E0, 0x500075E4, + 0x892636E9, 0x3E3BF7ED, 0x3B6BB0F3, 0x8C7671F7, 0x555032FA, 0xE24DF3FE, + 0x5FF0BCC6, 0xE8ED7DC2, 0x31CB3ECF, 0x86D6FFCB, 0x8386B8D5, 0x349B79D1, + 0xEDBD3ADC, 0x5AA0FBD8, 0xEEE00C69, 0x59FDCD6D, 0x80DB8E60, 0x37C64F64, + 0x3296087A, 0x858BC97E, 0x5CAD8A73, 0xEBB04B77, 0x560D044F, 0xE110C54B, + 0x38368646, 0x8F2B4742, 0x8A7B005C, 0x3D66C158, 0xE4408255, 0x535D4351, + 0x9E3B1D25, 0x2926DC21, 0xF0009F2C, 0x471D5E28, 0x424D1936, 0xF550D832, + 0x2C769B3F, 0x9B6B5A3B, 0x26D61503, 0x91CBD407, 0x48ED970A, 0xFFF0560E, + 0xFAA01110, 0x4DBDD014, 0x949B9319, 0x2386521D, 0x0E562FF1, 0xB94BEEF5, + 0x606DADF8, 0xD7706CFC, 0xD2202BE2, 0x653DEAE6, 0xBC1BA9EB, 0x0B0668EF, + 0xB6BB27D7, 0x01A6E6D3, 0xD880A5DE, 0x6F9D64DA, 0x6ACD23C4, 0xDDD0E2C0, + 0x04F6A1CD, 0xB3EB60C9, 0x7E8D3EBD, 0xC990FFB9, 0x10B6BCB4, 0xA7AB7DB0, + 0xA2FB3AAE, 0x15E6FBAA, 0xCCC0B8A7, 0x7BDD79A3, 0xC660369B, 0x717DF79F, + 0xA85BB492, 0x1F467596, 0x1A163288, 0xAD0BF38C, 0x742DB081, 0xC3307185, + 0x99908A5D, 0x2E8D4B59, 0xF7AB0854, 0x40B6C950, 0x45E68E4E, 0xF2FB4F4A, + 0x2BDD0C47, 0x9CC0CD43, 0x217D827B, 0x9660437F, 0x4F460072, 0xF85BC176, + 0xFD0B8668, 0x4A16476C, 0x93300461, 0x242DC565, 0xE94B9B11, 0x5E565A15, + 0x87701918, 0x306DD81C, 0x353D9F02, 0x82205E06, 0x5B061D0B, 0xEC1BDC0F, + 0x51A69337, 0xE6BB5233, 0x3F9D113E, 0x8880D03A, 0x8DD09724, 0x3ACD5620, + 0xE3EB152D, 0x54F6D429, 0x7926A9C5, 0xCE3B68C1, 0x171D2BCC, 0xA000EAC8, + 0xA550ADD6, 0x124D6CD2, 0xCB6B2FDF, 0x7C76EEDB, 0xC1CBA1E3, 0x76D660E7, + 0xAFF023EA, 0x18EDE2EE, 0x1DBDA5F0, 0xAAA064F4, 0x738627F9, 0xC49BE6FD, + 0x09FDB889, 0xBEE0798D, 0x67C63A80, 0xD0DBFB84, 0xD58BBC9A, 0x62967D9E, + 0xBBB03E93, 0x0CADFF97, 0xB110B0AF, 0x060D71AB, 0xDF2B32A6, 0x6836F3A2, + 0x6D66B4BC, 0xDA7B75B8, 0x035D36B5, 0xB440F7B1, 0x00000001 + }, + [AV_CRC_32_IEEE_LE] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, 0x00000001 + }, + [AV_CRC_16_ANSI_LE] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040, + 0x0001 + }, +}; +#else +#if CONFIG_SMALL +#define CRC_TABLE_SIZE 257 +#else +#define CRC_TABLE_SIZE 1024 +#endif +static AVCRC av_crc_table[AV_CRC_MAX][CRC_TABLE_SIZE]; + +#define DECLARE_CRC_INIT_TABLE_ONCE(id, le, bits, poly) \ +static AVOnce id ## _once_control = AV_ONCE_INIT; \ +static void id ## _init_table_once(void) \ +{ \ + av_assert0(av_crc_init(av_crc_table[id], le, bits, poly, sizeof(av_crc_table[id])) >= 0); \ +} + +#define CRC_INIT_TABLE_ONCE(id) ff_thread_once(&id ## _once_control, id ## _init_table_once) + +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_8_ATM, 0, 8, 0x07) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_8_EBU, 0, 8, 0x1D) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI, 0, 16, 0x8005) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_16_CCITT, 0, 16, 0x1021) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_24_IEEE, 0, 24, 0x864CFB) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE, 0, 32, 0x04C11DB7) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE_LE, 1, 32, 0xEDB88320) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI_LE, 1, 16, 0xA001) +#endif + +int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size) +{ + unsigned i, j; + uint32_t c; + + if (bits < 8 || bits > 32 || poly >= (1LL << bits)) + return AVERROR(EINVAL); + if (ctx_size != sizeof(AVCRC) * 257 && ctx_size != sizeof(AVCRC) * 1024) + return AVERROR(EINVAL); + +#if ARCH_X86 + int done = ff_crc_init_x86(ctx, le, bits, poly, ctx_size); + if (done) + return 0; +#endif + + for (i = 0; i < 256; i++) { + if (le) { + for (c = i, j = 0; j < 8; j++) + c = (c >> 1) ^ (poly & (-(c & 1))); + ctx[i] = c; + } else { + for (c = i << 24, j = 0; j < 8; j++) + c = (c << 1) ^ ((poly << (32 - bits)) & (((int32_t) c) >> 31)); + ctx[i] = av_bswap32(c); + } + } + ctx[256] = 1; +#if !CONFIG_SMALL + if (ctx_size >= sizeof(AVCRC) * 1024) + for (i = 0; i < 256; i++) + for (j = 0; j < 3; j++) + ctx[256 * (j + 1) + i] = + (ctx[256 * j + i] >> 8) ^ ctx[ctx[256 * j + i] & 0xFF]; +#endif + + return 0; +} + +const AVCRC *av_crc_get_table(AVCRCId crc_id) +{ + if ((unsigned)crc_id >= AV_CRC_MAX) + return NULL; +// Check for arch-specific extensions first to avoid initializing +// ordinary CRC tables unnecessarily. +#if ARCH_AARCH64 + const AVCRC *table = ff_crc_get_table_aarch64(crc_id); + if (table) + return table; +#elif ARCH_X86 + const AVCRC *table = ff_crc_get_table_x86(crc_id); + if (table) + return table; +#endif + +#if !CONFIG_HARDCODED_TABLES + switch (crc_id) { + case AV_CRC_8_ATM: CRC_INIT_TABLE_ONCE(AV_CRC_8_ATM); break; + case AV_CRC_8_EBU: CRC_INIT_TABLE_ONCE(AV_CRC_8_EBU); break; + case AV_CRC_16_ANSI: CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI); break; + case AV_CRC_16_CCITT: CRC_INIT_TABLE_ONCE(AV_CRC_16_CCITT); break; + case AV_CRC_24_IEEE: CRC_INIT_TABLE_ONCE(AV_CRC_24_IEEE); break; + case AV_CRC_32_IEEE: CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE); break; + case AV_CRC_32_IEEE_LE: CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE_LE); break; + case AV_CRC_16_ANSI_LE: CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI_LE); break; + default: av_unreachable("already checked"); + } +#endif + return av_crc_table[crc_id]; +} + +uint32_t av_crc(const AVCRC *ctx, uint32_t crc, + const uint8_t *buffer, size_t length) +{ + if (ctx[0]) { +#if ARCH_AARCH64 + return ff_crc_aarch64(ctx, crc, buffer, length); +#elif ARCH_X86 + return ff_crc_x86(ctx, crc, buffer, length); +#endif + } + av_assert2(ctx[0] == 0); + + const uint8_t *end = buffer + length; + +#if !CONFIG_SMALL + if (!ctx[256]) { + while (((intptr_t) buffer & 3) && buffer < end) + crc = ctx[((uint8_t) crc) ^ *buffer++] ^ (crc >> 8); + + while (buffer < end - 3) { + crc ^= av_le2ne32(*(const uint32_t *) buffer); buffer += 4; + crc = ctx[3 * 256 + ( crc & 0xFF)] ^ + ctx[2 * 256 + ((crc >> 8 ) & 0xFF)] ^ + ctx[1 * 256 + ((crc >> 16) & 0xFF)] ^ + ctx[0 * 256 + ((crc >> 24) )]; + } + } +#endif + while (buffer < end) + crc = ctx[((uint8_t) crc) ^ *buffer++] ^ (crc >> 8); + + return crc; +} diff --git a/libs/ffmpeg/libavutil/crc.h b/libs/ffmpeg/libavutil/crc.h new file mode 100644 index 00000000000..7f59812a18c --- /dev/null +++ b/libs/ffmpeg/libavutil/crc.h @@ -0,0 +1,102 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_crc32 + * Public header for CRC hash function implementation. + */ + +#ifndef AVUTIL_CRC_H +#define AVUTIL_CRC_H + +#include <stdint.h> +#include <stddef.h> +#include "attributes.h" + +/** + * @defgroup lavu_crc32 CRC + * @ingroup lavu_hash + * CRC (Cyclic Redundancy Check) hash function implementation. + * + * This module supports numerous CRC polynomials, in addition to the most + * widely used CRC-32-IEEE. See @ref AVCRCId for a list of available + * polynomials. + * + * @{ + */ + +typedef uint32_t AVCRC; + +typedef enum { + AV_CRC_8_ATM, + AV_CRC_16_ANSI, + AV_CRC_16_CCITT, + AV_CRC_32_IEEE, + AV_CRC_32_IEEE_LE, /*< reversed bitorder version of AV_CRC_32_IEEE */ + AV_CRC_16_ANSI_LE, /*< reversed bitorder version of AV_CRC_16_ANSI */ + AV_CRC_24_IEEE, + AV_CRC_8_EBU, + AV_CRC_MAX, /*< Not part of public API! Do not use outside libavutil. */ +}AVCRCId; + +/** + * Initialize a CRC table. + * @param ctx must be an array of size sizeof(AVCRC)*257 or sizeof(AVCRC)*1024 + * @param le If 1, the lowest bit represents the coefficient for the highest + * exponent of the corresponding polynomial (both for poly and + * actual CRC). + * If 0, you must swap the CRC parameter and the result of av_crc + * if you need the standard representation (can be simplified in + * most cases to e.g. bswap16): + * av_bswap32(crc << (32-bits)) + * @param bits number of bits for the CRC + * @param poly generator polynomial without the x**bits coefficient, in the + * representation as specified by le + * @param ctx_size size of ctx in bytes + * @return <0 on failure + */ +int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size); + +/** + * Get an initialized standard CRC table. + * @param crc_id ID of a standard CRC + * @return a pointer to the CRC table or NULL on failure + */ +const AVCRC *av_crc_get_table(AVCRCId crc_id); + +/** + * Calculate the CRC of a block. + * @param ctx initialized AVCRC array (see av_crc_init()) + * @param crc CRC of previous blocks if any or initial value for CRC + * @param buffer buffer whose CRC to calculate + * @param length length of the buffer + * @return CRC updated with the data from the given block + * + * @see av_crc_init() "le" parameter + */ +uint32_t av_crc(const AVCRC *ctx, uint32_t crc, + const uint8_t *buffer, size_t length) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_CRC_H */ diff --git a/libs/ffmpeg/libavutil/csp.c b/libs/ffmpeg/libavutil/csp.c new file mode 100644 index 00000000000..8ff53cff5fa --- /dev/null +++ b/libs/ffmpeg/libavutil/csp.c @@ -0,0 +1,715 @@ +/* + * Copyright (c) 2015 Kevin Wheatley <kevin.j.wheatley@gmail.com> + * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com> + * Copyright (c) 2023 Leo Izen <leo.izen@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file Colorspace functions for libavutil + * @author Ronald S. Bultje <rsbultje@gmail.com> + * @author Leo Izen <leo.izen@gmail.com> + * @author Kevin Wheatley <kevin.j.wheatley@gmail.com> + */ + +#include <stdlib.h> +#include <math.h> + +#include "attributes.h" +#include "csp.h" +#include "pixfmt.h" +#include "rational.h" + +#define AVR(d) { (int)(d * 100000 + 0.5), 100000 } + +/* + * All constants explained in e.g. https://linuxtv.org/downloads/v4l-dvb-apis/ch02s06.html + * The older ones (bt470bg/m) are also explained in their respective ITU docs + * (e.g. https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.470-5-199802-S!!PDF-E.p...) + * whereas the newer ones can typically be copied directly from wikipedia :) + */ +static const struct AVLumaCoefficients luma_coefficients[AVCOL_SPC_NB] = { + [AVCOL_SPC_FCC] = { AVR(0.30), AVR(0.59), AVR(0.11) }, + [AVCOL_SPC_BT470BG] = { AVR(0.299), AVR(0.587), AVR(0.114) }, + [AVCOL_SPC_SMPTE170M] = { AVR(0.299), AVR(0.587), AVR(0.114) }, + [AVCOL_SPC_BT709] = { AVR(0.2126), AVR(0.7152), AVR(0.0722) }, + [AVCOL_SPC_SMPTE240M] = { AVR(0.212), AVR(0.701), AVR(0.087) }, + [AVCOL_SPC_YCOCG] = { AVR(0.25), AVR(0.5), AVR(0.25) }, + [AVCOL_SPC_RGB] = { AVR(1), AVR(1), AVR(1) }, + [AVCOL_SPC_BT2020_NCL] = { AVR(0.2627), AVR(0.6780), AVR(0.0593) }, + [AVCOL_SPC_BT2020_CL] = { AVR(0.2627), AVR(0.6780), AVR(0.0593) }, +}; + +const struct AVLumaCoefficients *av_csp_luma_coeffs_from_avcsp(enum AVColorSpace csp) +{ + const AVLumaCoefficients *coeffs; + + if ((unsigned)csp >= AVCOL_SPC_NB) + return NULL; + coeffs = &luma_coefficients[csp]; + if (!coeffs->cr.num) + return NULL; + + return coeffs; +} + +#define WP_D65 { AVR(0.3127), AVR(0.3290) } +#define WP_C { AVR(0.3100), AVR(0.3160) } +#define WP_DCI { AVR(0.3140), AVR(0.3510) } +#define WP_E { {1, 3}, {1, 3} } + +static const AVColorPrimariesDesc color_primaries[AVCOL_PRI_NB] = { + [AVCOL_PRI_BT709] = { WP_D65, { { AVR(0.640), AVR(0.330) }, { AVR(0.300), AVR(0.600) }, { AVR(0.150), AVR(0.060) } } }, + [AVCOL_PRI_BT470M] = { WP_C, { { AVR(0.670), AVR(0.330) }, { AVR(0.210), AVR(0.710) }, { AVR(0.140), AVR(0.080) } } }, + [AVCOL_PRI_BT470BG] = { WP_D65, { { AVR(0.640), AVR(0.330) }, { AVR(0.290), AVR(0.600) }, { AVR(0.150), AVR(0.060) } } }, + [AVCOL_PRI_SMPTE170M] = { WP_D65, { { AVR(0.630), AVR(0.340) }, { AVR(0.310), AVR(0.595) }, { AVR(0.155), AVR(0.070) } } }, + [AVCOL_PRI_SMPTE240M] = { WP_D65, { { AVR(0.630), AVR(0.340) }, { AVR(0.310), AVR(0.595) }, { AVR(0.155), AVR(0.070) } } }, + [AVCOL_PRI_SMPTE428] = { WP_E, { { AVR(0.735), AVR(0.265) }, { AVR(0.274), AVR(0.718) }, { AVR(0.167), AVR(0.009) } } }, + [AVCOL_PRI_SMPTE431] = { WP_DCI, { { AVR(0.680), AVR(0.320) }, { AVR(0.265), AVR(0.690) }, { AVR(0.150), AVR(0.060) } } }, + [AVCOL_PRI_SMPTE432] = { WP_D65, { { AVR(0.680), AVR(0.320) }, { AVR(0.265), AVR(0.690) }, { AVR(0.150), AVR(0.060) } } }, + [AVCOL_PRI_FILM] = { WP_C, { { AVR(0.681), AVR(0.319) }, { AVR(0.243), AVR(0.692) }, { AVR(0.145), AVR(0.049) } } }, + [AVCOL_PRI_BT2020] = { WP_D65, { { AVR(0.708), AVR(0.292) }, { AVR(0.170), AVR(0.797) }, { AVR(0.131), AVR(0.046) } } }, + [AVCOL_PRI_JEDEC_P22] = { WP_D65, { { AVR(0.630), AVR(0.340) }, { AVR(0.295), AVR(0.605) }, { AVR(0.155), AVR(0.077) } } }, +}; + +static const AVColorPrimariesDesc color_primaries_ext[AVCOL_PRI_EXT_NB - + AVCOL_PRI_EXT_BASE] = { + [AVCOL_PRI_V_GAMUT - AVCOL_PRI_EXT_BASE] = { WP_D65, { { AVR(0.730), AVR(0.280) }, { AVR(0.165), AVR(0.840) }, { AVR(0.100), AVR(-0.030) } } }, +}; + +const AVColorPrimariesDesc *av_csp_primaries_desc_from_id(enum AVColorPrimaries prm) +{ + const AVColorPrimariesDesc *p = NULL; + if ((unsigned)prm < AVCOL_PRI_NB) + p = &color_primaries[prm]; + else if (((unsigned)prm >= AVCOL_PRI_EXT_BASE) && + ((unsigned)prm < AVCOL_PRI_EXT_NB)) + p = &color_primaries_ext[prm - AVCOL_PRI_EXT_BASE]; + if (!p || !p->prim.r.x.num) + return NULL; + return p; +} + +static av_always_inline AVRational abs_sub_q(AVRational r1, AVRational r2) +{ + AVRational diff = av_sub_q(r1, r2); + /* denominator assumed to be positive */ + return av_make_q(abs(diff.num), diff.den); +} + +enum AVColorPrimaries av_csp_primaries_id_from_desc(const AVColorPrimariesDesc *prm) +{ + AVRational delta; + + for (enum AVColorPrimaries p = 0; p < AVCOL_PRI_NB; p++) { + const AVColorPrimariesDesc *ref = &color_primaries[p]; + if (!ref->prim.r.x.num) + continue; + + delta = abs_sub_q(prm->prim.r.x, ref->prim.r.x); + delta = av_add_q(delta, abs_sub_q(prm->prim.r.y, ref->prim.r.y)); + delta = av_add_q(delta, abs_sub_q(prm->prim.g.x, ref->prim.g.x)); + delta = av_add_q(delta, abs_sub_q(prm->prim.g.y, ref->prim.g.y)); + delta = av_add_q(delta, abs_sub_q(prm->prim.b.x, ref->prim.b.x)); + delta = av_add_q(delta, abs_sub_q(prm->prim.b.y, ref->prim.b.y)); + delta = av_add_q(delta, abs_sub_q(prm->wp.x, ref->wp.x)); + delta = av_add_q(delta, abs_sub_q(prm->wp.y, ref->wp.y)); + + if (av_cmp_q(delta, av_make_q(1, 1000)) < 0) + return p; + } + + return AVCOL_PRI_UNSPECIFIED; +} + +static const double approximate_gamma[AVCOL_TRC_NB] = { + [AVCOL_TRC_BT709] = 1.961, + [AVCOL_TRC_SMPTE170M] = 1.961, + [AVCOL_TRC_SMPTE240M] = 1.961, + [AVCOL_TRC_BT1361_ECG] = 1.961, + [AVCOL_TRC_BT2020_10] = 1.961, + [AVCOL_TRC_BT2020_12] = 1.961, + [AVCOL_TRC_GAMMA22] = 2.2, + [AVCOL_TRC_IEC61966_2_1] = 2.2, + [AVCOL_TRC_GAMMA28] = 2.8, + [AVCOL_TRC_LINEAR] = 1.0, + [AVCOL_TRC_SMPTE428] = 2.6, +}; + +static const double approximate_gamma_ext[AVCOL_TRC_EXT_NB - + AVCOL_TRC_EXT_BASE] = { + [AVCOL_TRC_V_LOG - AVCOL_TRC_EXT_BASE] = 2.2, +}; + +double av_csp_approximate_trc_gamma(enum AVColorTransferCharacteristic trc) +{ + if (trc < AVCOL_TRC_NB) + return approximate_gamma[trc]; + else if ((trc >= AVCOL_TRC_EXT_BASE) && (trc < AVCOL_TRC_EXT_NB)) + return approximate_gamma_ext[trc - AVCOL_TRC_EXT_BASE]; + return 0.0; +} + +static const double approximate_eotf_gamma[AVCOL_TRC_NB] = { + [AVCOL_TRC_BT709] = 2.2, + [AVCOL_TRC_SMPTE170M] = 2.2, + [AVCOL_TRC_SMPTE240M] = 2.2, + [AVCOL_TRC_BT1361_ECG] = 2.2, + [AVCOL_TRC_BT2020_10] = 2.2, + [AVCOL_TRC_BT2020_12] = 2.2, + [AVCOL_TRC_GAMMA22] = 2.2, + [AVCOL_TRC_IEC61966_2_1] = 2.2, + [AVCOL_TRC_GAMMA28] = 2.8, + [AVCOL_TRC_LINEAR] = 1.0, + [AVCOL_TRC_SMPTE428] = 2.6, +}; + +static const double approximate_eotf_gamma_ext[AVCOL_TRC_EXT_NB - + AVCOL_TRC_EXT_BASE] = { + [AVCOL_TRC_V_LOG - AVCOL_TRC_EXT_BASE] = 2.2, +}; + +double av_csp_approximate_eotf_gamma(enum AVColorTransferCharacteristic trc) +{ + if ((unsigned)trc < AVCOL_TRC_NB) + return approximate_eotf_gamma[trc]; + else if (((unsigned)trc >= AVCOL_TRC_EXT_BASE) && + ((unsigned)trc < AVCOL_TRC_EXT_NB)) + return approximate_eotf_gamma_ext[trc - AVCOL_TRC_EXT_BASE]; + return 0.0; +} + +#define BT709_alpha 1.099296826809442 +#define BT709_beta 0.018053968510807 + +static double trc_bt709(double Lc) +{ + const double a = BT709_alpha; + const double b = BT709_beta; + + return (0.0 > Lc) ? 0.0 + : ( b > Lc) ? 4.500 * Lc + : a * pow(Lc, 0.45) - (a - 1.0); +} + +static double trc_bt709_inv(double E) +{ + const double a = BT709_alpha; + const double b = 4.500 * BT709_beta; + + return (0.0 > E) ? 0.0 + : ( b > E) ? E / 4.500 + : pow((E + (a - 1.0)) / a, 1.0 / 0.45); +} + +static double trc_gamma22(double Lc) +{ + return (0.0 > Lc) ? 0.0 : pow(Lc, 1.0/ 2.2); +} + +static double trc_gamma22_inv(double E) +{ + return (0.0 > E) ? 0.0 : pow(E, 2.2); +} + +static double trc_gamma28(double Lc) +{ + return (0.0 > Lc) ? 0.0 : pow(Lc, 1.0/ 2.8); +} + +static double trc_gamma28_inv(double E) +{ + return (0.0 > E) ? 0.0 : pow(E, 2.8); +} + +static double trc_smpte240M(double Lc) +{ + const double a = 1.1115; + const double b = 0.0228; + + return (0.0 > Lc) ? 0.0 + : ( b > Lc) ? 4.000 * Lc + : a * pow(Lc, 0.45) - (a - 1.0); +} + +static double trc_smpte240M_inv(double E) +{ + const double a = 1.1115; + const double b = 4.000 * 0.0228; + + return (0.0 > E) ? 0.0 + : ( b > E) ? E / 4.000 + : pow((E + (a - 1.0)) / a, 1.0 / 0.45); +} + +static double trc_linear(double Lc) +{ + return Lc; +} + +static double trc_log(double Lc) +{ + return (0.01 > Lc) ? 0.0 : 1.0 + log10(Lc) / 2.0; +} + +static double trc_log_inv(double E) +{ + return (0.0 > E) ? 0.01 : pow(10.0, 2.0 * (E - 1.0)); +} + +static double trc_log_sqrt(double Lc) +{ + // sqrt(10) / 1000 + return (0.00316227766 > Lc) ? 0.0 : 1.0 + log10(Lc) / 2.5; +} + +static double trc_log_sqrt_inv(double E) +{ + return (0.0 > E) ? 0.00316227766 : pow(10.0, 2.5 * (E - 1.0)); +} + +static double trc_iec61966_2_4(double Lc) +{ + const double a = BT709_alpha; + const double b = BT709_beta; + + return (-b >= Lc) ? -a * pow(-Lc, 0.45) + (a - 1.0) + : ( b > Lc) ? 4.500 * Lc + : a * pow( Lc, 0.45) - (a - 1.0); +} + +static double trc_iec61966_2_4_inv(double E) +{ + const double a = BT709_alpha; + const double b = 4.500 * BT709_beta; + + return (-b >= E) ? -pow((-E + (a - 1.0)) / a, 1.0 / 0.45) + : ( b > E) ? E / 4.500 + : pow(( E + (a - 1.0)) / a, 1.0 / 0.45); +} + +static double trc_bt1361(double Lc) +{ + const double a = BT709_alpha; + const double b = BT709_beta; + + return (-0.0045 >= Lc) ? -(a * pow(-4.0 * Lc, 0.45) + (a - 1.0)) / 4.0 + : ( b > Lc) ? 4.500 * Lc + : a * pow( Lc, 0.45) - (a - 1.0); +} + +static double trc_bt1361_inv(double E) +{ + const double a = BT709_alpha; + const double b = 4.500 * BT709_beta; + + return (-0.02025 >= E) ? -pow((-4.0 * E - (a - 1.0)) / a, 1.0 / 0.45) / 4.0 + : ( b > E) ? E / 4.500 + : pow(( E + (a - 1.0)) / a, 1.0 / 0.45); +} + +static double trc_iec61966_2_1(double Lc) +{ + const double a = 1.055; + const double b = 0.0031308; + + return (0.0 > Lc) ? 0.0 + : ( b > Lc) ? 12.92 * Lc + : a * pow(Lc, 1.0 / 2.4) - (a - 1.0); +} + +static double trc_iec61966_2_1_inv(double E) +{ + const double a = 1.055; + const double b = 12.92 * 0.0031308; + + return (0.0 > E) ? 0.0 + : ( b > E) ? E / 12.92 + : pow((E + (a - 1.0)) / a, 2.4); + return E; +} + +#define PQ_c1 ( 3424.0 / 4096.0) /* c3-c2 + 1 */ +#define PQ_c2 ( 32.0 * 2413.0 / 4096.0) +#define PQ_c3 ( 32.0 * 2392.0 / 4096.0) +#define PQ_m (128.0 * 2523.0 / 4096.0) +#define PQ_n ( 0.25 * 2610.0 / 4096.0) + +static double trc_smpte_st2084(double Lc) +{ + const double c1 = PQ_c1; + const double c2 = PQ_c2; + const double c3 = PQ_c3; + const double m = PQ_m; + const double n = PQ_n; + const double L = Lc / 10000.0; + const double Ln = pow(L, n); + + return (0.0 > Lc) ? 0.0 + : pow((c1 + c2 * Ln) / (1.0 + c3 * Ln), m); + +} + +static double trc_smpte_st2084_inv(double E) +{ + const double c1 = PQ_c1; + const double c2 = PQ_c2; + const double c3 = PQ_c3; + const double m = PQ_m; + const double n = PQ_n; + const double Em = pow(E, 1.0 / m); + + return (c1 > Em) ? 0.0 + : 10000.0 * pow((Em - c1) / (c2 - c3 * Em), 1.0 / n); +} + +#define DCI_L 48.00 +#define DCI_P 52.37 + +static double trc_smpte_st428_1(double Lc) +{ + return (0.0 > Lc) ? 0.0 : pow(DCI_L / DCI_P * Lc, 1.0 / 2.6); +} + +static double trc_smpte_st428_1_inv(double E) +{ + return (0.0 > E) ? 0.0 : DCI_P / DCI_L * pow(E, 2.6); +} + +#define HLG_a 0.17883277 +#define HLG_b 0.28466892 +#define HLG_c 0.55991073 + +static double trc_arib_std_b67(double Lc) { + // The function uses the definition from HEVC, which assumes that the peak + // white is input level = 1. (this is equivalent to scaling E = Lc * 12 and + // using the definition from the ARIB STD-B67 spec) + const double a = HLG_a; + const double b = HLG_b; + const double c = HLG_c; + return (0.0 > Lc) ? 0.0 : + (Lc <= 1.0 / 12.0 ? sqrt(3.0 * Lc) : a * log(12.0 * Lc - b) + c); +} + +static double trc_arib_std_b67_inv(double E) +{ + const double a = HLG_a; + const double b = HLG_b; + const double c = HLG_c; + return (0.0 > E) ? 0.0 : + (E <= 0.5 ? E * E / 3.0 : (exp((E - c) / a) + b) / 12.0); +} + +#define VLOG_c1 0.01 +#define VLOG_c2 0.181 +#define VLOG_b 0.00873 +#define VLOG_c 0.241514 +#define VLOG_d 0.598206 + +static double trc_v_log(double E) +{ + const double c1 = VLOG_c1; + const double b = VLOG_b; + const double c = VLOG_c; + const double d = VLOG_d; + return (E < c1) ? (5.6 * E + 0.125) : + (c * log10(E + b) + d); +} + +static double trc_v_log_inv(double E) +{ + const double c2 = VLOG_c2; + const double b = VLOG_b; + const double c = VLOG_c; + const double d = VLOG_d; + return (E < c2) ? (E - 0.125) / 5.6 : + (pow(10.0, ((E - d) / c)) - b); +} + +static const av_csp_trc_function trc_funcs[AVCOL_TRC_NB] = { + [AVCOL_TRC_BT709] = trc_bt709, + [AVCOL_TRC_GAMMA22] = trc_gamma22, + [AVCOL_TRC_GAMMA28] = trc_gamma28, + [AVCOL_TRC_SMPTE170M] = trc_bt709, + [AVCOL_TRC_SMPTE240M] = trc_smpte240M, + [AVCOL_TRC_LINEAR] = trc_linear, + [AVCOL_TRC_LOG] = trc_log, + [AVCOL_TRC_LOG_SQRT] = trc_log_sqrt, + [AVCOL_TRC_IEC61966_2_4] = trc_iec61966_2_4, + [AVCOL_TRC_BT1361_ECG] = trc_bt1361, + [AVCOL_TRC_IEC61966_2_1] = trc_iec61966_2_1, + [AVCOL_TRC_BT2020_10] = trc_bt709, + [AVCOL_TRC_BT2020_12] = trc_bt709, + [AVCOL_TRC_SMPTE2084] = trc_smpte_st2084, + [AVCOL_TRC_SMPTE428] = trc_smpte_st428_1, + [AVCOL_TRC_ARIB_STD_B67] = trc_arib_std_b67, +}; + +static const av_csp_trc_function trc_funcs_ext[AVCOL_TRC_EXT_NB - + AVCOL_TRC_EXT_BASE] = { + [AVCOL_TRC_V_LOG - AVCOL_TRC_EXT_BASE] = trc_v_log, +}; + +av_csp_trc_function av_csp_trc_func_from_id(enum AVColorTransferCharacteristic trc) +{ + if ((unsigned)trc < AVCOL_TRC_NB) + return trc_funcs[trc]; + else if (((unsigned)trc >= AVCOL_TRC_EXT_BASE) && + ((unsigned)trc < AVCOL_TRC_EXT_NB)) + return trc_funcs_ext[trc - AVCOL_TRC_EXT_BASE]; + return NULL; +} + +static const av_csp_trc_function trc_inv_funcs[AVCOL_TRC_NB] = { + [AVCOL_TRC_BT709] = trc_bt709_inv, + [AVCOL_TRC_GAMMA22] = trc_gamma22_inv, + [AVCOL_TRC_GAMMA28] = trc_gamma28_inv, + [AVCOL_TRC_SMPTE170M] = trc_bt709_inv, + [AVCOL_TRC_SMPTE240M] = trc_smpte240M_inv, + [AVCOL_TRC_LINEAR] = trc_linear, + [AVCOL_TRC_LOG] = trc_log_inv, + [AVCOL_TRC_LOG_SQRT] = trc_log_sqrt_inv, + [AVCOL_TRC_IEC61966_2_4] = trc_iec61966_2_4_inv, + [AVCOL_TRC_BT1361_ECG] = trc_bt1361_inv, + [AVCOL_TRC_IEC61966_2_1] = trc_iec61966_2_1_inv, + [AVCOL_TRC_BT2020_10] = trc_bt709_inv, + [AVCOL_TRC_BT2020_12] = trc_bt709_inv, + [AVCOL_TRC_SMPTE2084] = trc_smpte_st2084_inv, + [AVCOL_TRC_SMPTE428] = trc_smpte_st428_1_inv, + [AVCOL_TRC_ARIB_STD_B67] = trc_arib_std_b67_inv, +}; + +static const av_csp_trc_function trc_inv_funcs_ext[AVCOL_TRC_EXT_NB - + AVCOL_TRC_EXT_BASE] = { + [AVCOL_TRC_V_LOG - AVCOL_TRC_EXT_BASE] = trc_v_log_inv, +}; + +av_csp_trc_function av_csp_trc_func_inv_from_id(enum AVColorTransferCharacteristic trc) +{ + if ((unsigned)trc < AVCOL_TRC_NB) + return trc_inv_funcs[trc]; + else if (((unsigned)trc >= AVCOL_TRC_EXT_BASE) && + ((unsigned)trc < AVCOL_TRC_EXT_NB)) + return trc_inv_funcs_ext[trc - AVCOL_TRC_EXT_BASE]; + return NULL; +} + +static void eotf_linear(const double Lw, const double Lb, double E[3]) +{ + for (int i = 0; i < 3; i++) + E[i] = (Lw - Lb) * E[i] + Lb; +} + +static void eotf_linear_inv(const double Lw, const double Lb, double L[3]) +{ + for (int i = 0; i < 3; i++) + L[i] = (L[i] - Lb) / (Lw - Lb); +} + +#define WRAP_SDR_OETF(name) \ +static void oetf_##name(double L[3]) \ +{ \ + for (int i = 0; i < 3; i++) \ + L[i] = trc_##name(L[i]); \ +} \ + \ +static void oetf_##name##_inv(double E[3]) \ +{ \ + for (int i = 0; i < 3; i++) \ + E[i] = trc_##name##_inv(E[i]); \ +} + +WRAP_SDR_OETF(gamma22) +WRAP_SDR_OETF(gamma28) +WRAP_SDR_OETF(iec61966_2_1) + +#define WRAP_SDR_EOTF(name) \ +static void eotf_##name(double Lw, double Lb, double E[3]) \ +{ \ + oetf_##name##_inv(E); \ + eotf_linear(Lw, Lb, E); \ +} \ + \ +static void eotf_##name##_inv(double Lw, double Lb, double L[3]) \ +{ \ + eotf_linear_inv(Lw, Lb, L); \ + oetf_##name(L); \ +} + +WRAP_SDR_EOTF(gamma22) +WRAP_SDR_EOTF(gamma28) +WRAP_SDR_EOTF(iec61966_2_1) + +static void eotf_bt1886(const double Lw, const double Lb, double E[3]) +{ + const double Lw_inv = pow(Lw, 1.0 / 2.4); + const double Lb_inv = pow(Lb, 1.0 / 2.4); + const double a = pow(Lw_inv - Lb_inv, 2.4); + const double b = Lb_inv / (Lw_inv - Lb_inv); + + for (int i = 0; i < 3; i++) + E[i] = (-b > E[i]) ? 0.0 : a * pow(E[i] + b, 2.4); +} + +static void eotf_bt1886_inv(const double Lw, const double Lb, double L[3]) +{ + const double Lw_inv = pow(Lw, 1.0 / 2.4); + const double Lb_inv = pow(Lb, 1.0 / 2.4); + const double a = pow(Lw_inv - Lb_inv, 2.4); + const double b = Lb_inv / (Lw_inv - Lb_inv); + + for (int i = 0; i < 3; i++) + L[i] = (0.0 > L[i]) ? 0.0 : pow(L[i] / a, 1.0 / 2.4) - b; +} + +static void eotf_smpte_st2084(const double Lw, const double Lb, double E[3]) +{ + for (int i = 0; i < 3; i++) + E[i] = trc_smpte_st2084_inv(E[i]); +} + +static void eotf_smpte_st2084_inv(const double Lw, const double Lb, double L[3]) +{ + for (int i = 0; i < 3; i++) + L[i] = trc_smpte_st2084(L[i]); +} + +/* This implementation assumes an SMPTE RP 431-2 reference projector (DCI) */ +#define DCI_L 48.00 +#define DCI_P 52.37 +#define DCI_X (42.94 / DCI_L) +#define DCI_Z (45.82 / DCI_L) + +static void eotf_smpte_st428_1(const double Lw_Y, const double Lb_Y, double E[3]) +{ + const double Lw[3] = { DCI_X * Lw_Y, Lw_Y, DCI_Z * Lw_Y }; + const double Lb[3] = { DCI_X * Lb_Y, Lb_Y, DCI_Z * Lb_Y }; + + for (int i = 0; i < 3; i++) { + E[i] = (0.0 > E[i]) ? 0.0 : pow(E[i], 2.6) * DCI_P / DCI_L; + E[i] = E[i] * (Lw[i] - Lb[i]) + Lb[i]; + } +} + +static void eotf_smpte_st428_1_inv(const double Lw_Y, const double Lb_Y, double L[3]) +{ + const double Lw[3] = { DCI_X * Lw_Y, Lw_Y, DCI_Z * Lw_Y }; + const double Lb[3] = { DCI_X * Lb_Y, Lb_Y, DCI_Z * Lb_Y }; + + for (int i = 0; i < 3; i++) { + L[i] = (L[i] - Lb[i]) / (Lw[i] - Lb[i]); + L[i] = (0.0 > L[i]) ? 0.0 : pow(L[i] * DCI_L / DCI_P, 1.0 / 2.6); + } +} + +static void eotf_arib_std_b67(const double Lw, const double Lb, double E[3]) +{ + const double gamma = fmax(1.2 + 0.42 * log10(Lw / 1000.0), 1.0); + + /** + * Note: This equation is technically only accurate if the contrast ratio + * Lw:Lb is greater than 12:1; otherwise we would need to use a different, + * significantly more complicated solution. Ignore this as a highly + * degenerate case, since any real world reference display will have a + * static contrast ratio multiple orders of magnitude higher. + */ + const double beta = sqrt(3 * pow(Lb / Lw, 1.0 / gamma)); + double luma; + + for (int i = 0; i < 3; i++) + E[i] = trc_arib_std_b67_inv((1 - beta) * E[i] + beta); + + luma = 0.2627 * E[0] + 0.6780 * E[1] + 0.0593 * E[2]; + luma = pow(fmax(luma, 0.0), gamma - 1.0); + for (int i = 0; i < 3; i++) + E[i] *= Lw * luma; +} + +static void eotf_arib_std_b67_inv(const double Lw, const double Lb, double L[3]) +{ + const double gamma = fmax(1.2 + 0.42 * log10(Lw / 1000.0), 1.0); + const double beta = sqrt(3 * pow(Lb / Lw, 1 / gamma)); + double luma = 0.2627 * L[0] + 0.6780 * L[1] + 0.0593 * L[2]; + + if (luma > 0.0) { + luma = pow(luma / Lw, (1 - gamma) / gamma); + for (int i = 0; i < 3; i++) + L[i] *= luma / Lw; + } else { + L[0] = L[1] = L[2] = 0.0; + } + + for (int i = 0; i < 3; i++) + L[i] = (trc_arib_std_b67(L[i]) - beta) / (1 - beta); +} + +static const av_csp_eotf_function eotf_funcs[AVCOL_TRC_NB] = { + [AVCOL_TRC_BT709] = eotf_bt1886, + [AVCOL_TRC_GAMMA22] = eotf_gamma22, + [AVCOL_TRC_GAMMA28] = eotf_gamma28, + [AVCOL_TRC_SMPTE170M] = eotf_bt1886, + [AVCOL_TRC_SMPTE240M] = eotf_bt1886, + [AVCOL_TRC_LINEAR] = eotf_linear, + /* There is no EOTF associated with these logarithmic encodings, since they + * are defined purely for transmission of scene referred data. */ + [AVCOL_TRC_LOG] = NULL, + [AVCOL_TRC_LOG_SQRT] = NULL, + /* BT.1886 is already defined for values below 0.0, as far as physically + * meaningful, so we can directly use it for extended range encodings */ + [AVCOL_TRC_IEC61966_2_4] = eotf_bt1886, + [AVCOL_TRC_BT1361_ECG] = eotf_bt1886, + [AVCOL_TRC_IEC61966_2_1] = eotf_iec61966_2_1, + [AVCOL_TRC_BT2020_10] = eotf_bt1886, + [AVCOL_TRC_BT2020_12] = eotf_bt1886, + [AVCOL_TRC_SMPTE2084] = eotf_smpte_st2084, + [AVCOL_TRC_SMPTE428] = eotf_smpte_st428_1, + [AVCOL_TRC_ARIB_STD_B67] = eotf_arib_std_b67, +}; + +av_csp_eotf_function av_csp_itu_eotf(enum AVColorTransferCharacteristic trc) +{ + if ((unsigned)trc >= AVCOL_TRC_NB) + return NULL; + return eotf_funcs[trc]; +} + +static const av_csp_eotf_function eotf_inv_funcs[AVCOL_TRC_NB] = { + [AVCOL_TRC_BT709] = eotf_bt1886_inv, + [AVCOL_TRC_GAMMA22] = eotf_gamma22_inv, + [AVCOL_TRC_GAMMA28] = eotf_gamma28_inv, + [AVCOL_TRC_SMPTE170M] = eotf_bt1886_inv, + [AVCOL_TRC_SMPTE240M] = eotf_bt1886_inv, + [AVCOL_TRC_LINEAR] = eotf_linear_inv, + [AVCOL_TRC_LOG] = NULL, + [AVCOL_TRC_LOG_SQRT] = NULL, + [AVCOL_TRC_IEC61966_2_4] = eotf_bt1886_inv, + [AVCOL_TRC_BT1361_ECG] = eotf_bt1886_inv, + [AVCOL_TRC_IEC61966_2_1] = eotf_iec61966_2_1_inv, + [AVCOL_TRC_BT2020_10] = eotf_bt1886_inv, + [AVCOL_TRC_BT2020_12] = eotf_bt1886_inv, + [AVCOL_TRC_SMPTE2084] = eotf_smpte_st2084_inv, + [AVCOL_TRC_SMPTE428] = eotf_smpte_st428_1_inv, + [AVCOL_TRC_ARIB_STD_B67] = eotf_arib_std_b67_inv, +}; + +av_csp_eotf_function av_csp_itu_eotf_inv(enum AVColorTransferCharacteristic trc) +{ + if ((unsigned)trc >= AVCOL_TRC_NB) + return NULL; + return eotf_inv_funcs[trc]; +} diff --git a/libs/ffmpeg/libavutil/csp.h b/libs/ffmpeg/libavutil/csp.h new file mode 100644 index 00000000000..9d75ccbb640 --- /dev/null +++ b/libs/ffmpeg/libavutil/csp.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2015 Kevin Wheatley <kevin.j.wheatley@gmail.com> + * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com> + * Copyright (c) 2023 Leo Izen <leo.izen@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CSP_H +#define AVUTIL_CSP_H + +#include "pixfmt.h" +#include "rational.h" + +/** + * @file + * Colorspace value utility functions for libavutil. + * @ingroup lavu_math_csp + * @author Ronald S. Bultje <rsbultje@gmail.com> + * @author Leo Izen <leo.izen@gmail.com> + * @author Kevin Wheatley <kevin.j.wheatley@gmail.com> + */ + +/** + * @defgroup lavu_math_csp Colorspace Utility + * @ingroup lavu_math + * @{ + */ + +/** + * Struct containing luma coefficients to be used for RGB to YUV/YCoCg, or similar + * calculations. + */ +typedef struct AVLumaCoefficients { + AVRational cr, cg, cb; +} AVLumaCoefficients; + +/** + * Struct containing chromaticity x and y values for the standard CIE 1931 + * chromaticity definition. + */ +typedef struct AVCIExy { + AVRational x, y; +} AVCIExy; + +/** + * Struct defining the red, green, and blue primary locations in terms of CIE + * 1931 chromaticity x and y. + */ +typedef struct AVPrimaryCoefficients { + AVCIExy r, g, b; +} AVPrimaryCoefficients; + +/** + * Struct defining white point location in terms of CIE 1931 chromaticity x + * and y. + */ +typedef AVCIExy AVWhitepointCoefficients; + +/** + * Struct that contains both white point location and primaries location, providing + * the complete description of a color gamut. + */ +typedef struct AVColorPrimariesDesc { + AVWhitepointCoefficients wp; + AVPrimaryCoefficients prim; +} AVColorPrimariesDesc; + +/** + * Function pointer representing a double -> double transfer function that + * performs either an OETF transfer function, or alternatively an inverse EOTF + * function (in particular, for SMPTE ST 2084 / PQ). This function inputs + * linear light, and outputs gamma encoded light. + * + * See ITU-T H.273 for more information. + */ +typedef double (*av_csp_trc_function)(double); + +/** + * Retrieves the Luma coefficients necessary to construct a conversion matrix + * from an enum constant describing the colorspace. + * @param csp An enum constant indicating YUV or similar colorspace. + * @return The Luma coefficients associated with that colorspace, or NULL + * if the constant is unknown to libavutil. + */ +const AVLumaCoefficients *av_csp_luma_coeffs_from_avcsp(enum AVColorSpace csp); + +/** + * Retrieves a complete gamut description from an enum constant describing the + * color primaries. + * @param prm An enum constant indicating primaries + * @return A description of the colorspace gamut associated with that enum + * constant, or NULL if the constant is unknown to libavutil. + */ +const AVColorPrimariesDesc *av_csp_primaries_desc_from_id(enum AVColorPrimaries prm); + +/** + * Detects which enum AVColorPrimaries constant corresponds to the given complete + * gamut description. + * @see enum AVColorPrimaries + * @param prm A description of the colorspace gamut + * @return The enum constant associated with this gamut, or + * AVCOL_PRI_UNSPECIFIED if no clear match can be identified. + */ +enum AVColorPrimaries av_csp_primaries_id_from_desc(const AVColorPrimariesDesc *prm); + +/** + * Determine a suitable 'gamma' value to match the supplied + * AVColorTransferCharacteristic. + * + * See Apple Technical Note TN2257 (https://developer.apple.com/library/mac/technotes/tn2257/_index.html) + * + * This function returns the gamma exponent for the OETF. For example, sRGB is approximated + * by gamma 2.2, not by gamma 0.45455. + * + * @return Will return an approximation to the simple gamma function matching + * the supplied Transfer Characteristic, Will return 0.0 for any + * we cannot reasonably match against. + */ +double av_csp_approximate_trc_gamma(enum AVColorTransferCharacteristic trc); + +/** + * Determine a suitable EOTF 'gamma' value to match the supplied + * AVColorTransferCharacteristic. + * + * This function returns the gamma value (exponent) for a simple pure power + * function approximation of the supplied AVColorTransferCharacteristic, or 0. + * if no reasonable approximation exists. + * + * EOTF(v) = (L_w - L_b) * v^gamma + L_b + * + * @return Will return an approximation to the simple gamma function matching + * the supplied Transfer Characteristic EOTF, Will return 0.0 for any + * we cannot reasonably match against. + */ +double av_csp_approximate_eotf_gamma(enum AVColorTransferCharacteristic trc); + +/** + * Determine the function needed to apply the given + * AVColorTransferCharacteristic to linear input. + * + * The function returned should expect a nominal domain and range of [0.0-1.0] + * values outside of this range maybe valid depending on the chosen + * characteristic function. + * + * @return Will return pointer to the function matching the + * supplied Transfer Characteristic. If unspecified will + * return NULL: + */ +av_csp_trc_function av_csp_trc_func_from_id(enum AVColorTransferCharacteristic trc); + +/** + * Returns the mathematical inverse of the corresponding TRC function. + */ +av_csp_trc_function av_csp_trc_func_inv_from_id(enum AVColorTransferCharacteristic trc); + +/** + * Function pointer representing an ITU EOTF transfer for a given reference + * display configuration. + * + * @param Lw The white point luminance of the display, in nits (cd/m^2). + * @param Lb The black point luminance of the display, in nits (cd/m^2). + */ +typedef void (*av_csp_eotf_function)(double Lw, double Lb, double c[3]); + +/** + * Returns the ITU EOTF corresponding to a given TRC. This converts from the + * signal level [0,1] to the raw output display luminance in nits (cd/m^2). + * This is done per channel in RGB space, except for AVCOL_TRC_SMPTE428, which + * assumes CIE XYZ in- and output. + * + * @return A pointer to the function implementing the given TRC, or NULL if no + * such function is defined. + * + * @note In general, the resulting function is defined (wherever possible) for + * out-of-range values, even though these values do not have a physical + * meaning on the given display. Users should clamp inputs (or outputs) + * if this behavior is not desired. + * + * This is also the case for functions like PQ, which are defined over an + * absolute signal range independent of the target display capabilities. + */ +av_csp_eotf_function av_csp_itu_eotf(enum AVColorTransferCharacteristic trc); + +/** + * Returns the mathematical inverse of the corresponding EOTF. + */ +av_csp_eotf_function av_csp_itu_eotf_inv(enum AVColorTransferCharacteristic trc); + +/** + * @} + */ + +#endif /* AVUTIL_CSP_H */ diff --git a/libs/ffmpeg/libavutil/des.c b/libs/ffmpeg/libavutil/des.c new file mode 100644 index 00000000000..e0e9a86660f --- /dev/null +++ b/libs/ffmpeg/libavutil/des.c @@ -0,0 +1,333 @@ +/* + * DES encryption/decryption + * Copyright (c) 2007 Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include <stdint.h> + +#include "attributes.h" +#include "error.h" +#include "intreadwrite.h" +#include "mem.h" +#include "des.h" + +#define T(a, b, c, d, e, f, g, h) 64 - a, 64 - b, 64 - c, 64 - d, 64 - e, 64 - f, 64 - g, 64 - h +static const uint8_t IP_shuffle[] = { + T(58, 50, 42, 34, 26, 18, 10, 2), + T(60, 52, 44, 36, 28, 20, 12, 4), + T(62, 54, 46, 38, 30, 22, 14, 6), + T(64, 56, 48, 40, 32, 24, 16, 8), + T(57, 49, 41, 33, 25, 17, 9, 1), + T(59, 51, 43, 35, 27, 19, 11, 3), + T(61, 53, 45, 37, 29, 21, 13, 5), + T(63, 55, 47, 39, 31, 23, 15, 7) +}; +#undef T + +#if CONFIG_SMALL || defined(GENTABLES) +#define T(a, b, c, d) 32 - a, 32 - b, 32 - c, 32 - d +static const uint8_t P_shuffle[] = { + T(16, 7, 20, 21), + T(29, 12, 28, 17), + T( 1, 15, 23, 26), + T( 5, 18, 31, 10), + T( 2, 8, 24, 14), + T(32, 27, 3, 9), + T(19, 13, 30, 6), + T(22, 11, 4, 25) +}; +#undef T +#endif + +#define T(a, b, c, d, e, f, g) 64 - a, 64 - b, 64 - c, 64 - d, 64 - e, 64 - f, 64 - g +static const uint8_t PC1_shuffle[] = { + T(57, 49, 41, 33, 25, 17, 9), + T( 1, 58, 50, 42, 34, 26, 18), + T(10, 2, 59, 51, 43, 35, 27), + T(19, 11, 3, 60, 52, 44, 36), + T(63, 55, 47, 39, 31, 23, 15), + T( 7, 62, 54, 46, 38, 30, 22), + T(14, 6, 61, 53, 45, 37, 29), + T(21, 13, 5, 28, 20, 12, 4) +}; +#undef T + +#define T(a, b, c, d, e, f) 56 - a, 56 - b, 56 - c, 56 - d, 56 - e, 56 - f +static const uint8_t PC2_shuffle[] = { + T(14, 17, 11, 24, 1, 5), + T( 3, 28, 15, 6, 21, 10), + T(23, 19, 12, 4, 26, 8), + T(16, 7, 27, 20, 13, 2), + T(41, 52, 31, 37, 47, 55), + T(30, 40, 51, 45, 33, 48), + T(44, 49, 39, 56, 34, 53), + T(46, 42, 50, 36, 29, 32) +}; +#undef T + +#if CONFIG_SMALL +static const uint8_t S_boxes[8][32] = { + { 0x0e, 0xf4, 0x7d, 0x41, 0xe2, 0x2f, 0xdb, 0x18, 0xa3, 0x6a, 0xc6, 0xbc, 0x95, 0x59, 0x30, 0x87, + 0xf4, 0xc1, 0x8e, 0x28, 0x4d, 0x96, 0x12, 0x7b, 0x5f, 0xbc, 0x39, 0xe7, 0xa3, 0x0a, 0x65, 0xd0, }, + { 0x3f, 0xd1, 0x48, 0x7e, 0xf6, 0x2b, 0x83, 0xe4, 0xc9, 0x07, 0x12, 0xad, 0x6c, 0x90, 0xb5, 0x5a, + 0xd0, 0x8e, 0xa7, 0x1b, 0x3a, 0xf4, 0x4d, 0x21, 0xb5, 0x68, 0x7c, 0xc6, 0x09, 0x53, 0xe2, 0x9f, }, + { 0xda, 0x70, 0x09, 0x9e, 0x36, 0x43, 0x6f, 0xa5, 0x21, 0x8d, 0x5c, 0xe7, 0xcb, 0xb4, 0xf2, 0x18, + 0x1d, 0xa6, 0xd4, 0x09, 0x68, 0x9f, 0x83, 0x70, 0x4b, 0xf1, 0xe2, 0x3c, 0xb5, 0x5a, 0x2e, 0xc7, }, + { 0xd7, 0x8d, 0xbe, 0x53, 0x60, 0xf6, 0x09, 0x3a, 0x41, 0x72, 0x28, 0xc5, 0x1b, 0xac, 0xe4, 0x9f, + 0x3a, 0xf6, 0x09, 0x60, 0xac, 0x1b, 0xd7, 0x8d, 0x9f, 0x41, 0x53, 0xbe, 0xc5, 0x72, 0x28, 0xe4, }, + { 0xe2, 0xbc, 0x24, 0xc1, 0x47, 0x7a, 0xdb, 0x16, 0x58, 0x05, 0xf3, 0xaf, 0x3d, 0x90, 0x8e, 0x69, + 0xb4, 0x82, 0xc1, 0x7b, 0x1a, 0xed, 0x27, 0xd8, 0x6f, 0xf9, 0x0c, 0x95, 0xa6, 0x43, 0x50, 0x3e, }, + { 0xac, 0xf1, 0x4a, 0x2f, 0x79, 0xc2, 0x96, 0x58, 0x60, 0x1d, 0xd3, 0xe4, 0x0e, 0xb7, 0x35, 0x8b, + 0x49, 0x3e, 0x2f, 0xc5, 0x92, 0x58, 0xfc, 0xa3, 0xb7, 0xe0, 0x14, 0x7a, 0x61, 0x0d, 0x8b, 0xd6, }, + { 0xd4, 0x0b, 0xb2, 0x7e, 0x4f, 0x90, 0x18, 0xad, 0xe3, 0x3c, 0x59, 0xc7, 0x25, 0xfa, 0x86, 0x61, + 0x61, 0xb4, 0xdb, 0x8d, 0x1c, 0x43, 0xa7, 0x7e, 0x9a, 0x5f, 0x06, 0xf8, 0xe0, 0x25, 0x39, 0xc2, }, + { 0x1d, 0xf2, 0xd8, 0x84, 0xa6, 0x3f, 0x7b, 0x41, 0xca, 0x59, 0x63, 0xbe, 0x05, 0xe0, 0x9c, 0x27, + 0x27, 0x1b, 0xe4, 0x71, 0x49, 0xac, 0x8e, 0xd2, 0xf0, 0xc6, 0x9a, 0x0d, 0x3f, 0x53, 0x65, 0xb8, + } +}; +#else +/** + * This table contains the results of applying both the S-box and P-shuffle. + * It can be regenerated by compiling tests/des.c with "-DCONFIG_SMALL -DGENTABLES". + */ +static const uint32_t S_boxes_P_shuffle[8][64] = { + { 0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202, 0x00000002, 0x00008000, + 0x00000200, 0x00808200, 0x00808202, 0x00000200, 0x00800202, 0x00808002, 0x00800000, 0x00000002, + 0x00000202, 0x00800200, 0x00800200, 0x00008200, 0x00008200, 0x00808000, 0x00808000, 0x00800202, + 0x00008002, 0x00800002, 0x00800002, 0x00008002, 0x00000000, 0x00000202, 0x00008202, 0x00800000, + 0x00008000, 0x00808202, 0x00000002, 0x00808000, 0x00808200, 0x00800000, 0x00800000, 0x00000200, + 0x00808002, 0x00008000, 0x00008200, 0x00800002, 0x00000200, 0x00000002, 0x00800202, 0x00008202, + 0x00808202, 0x00008002, 0x00808000, 0x00800202, 0x00800002, 0x00000202, 0x00008202, 0x00808200, + 0x00000202, 0x00800200, 0x00800200, 0x00000000, 0x00008002, 0x00008200, 0x00000000, 0x00808002, }, + { 0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010, 0x40080010, 0x40004010, + 0x40000010, 0x40084010, 0x40084000, 0x40000000, 0x40004000, 0x00080000, 0x00000010, 0x40080010, + 0x00084000, 0x00080010, 0x40004010, 0x00000000, 0x40000000, 0x00004000, 0x00084010, 0x40080000, + 0x00080010, 0x40000010, 0x00000000, 0x00084000, 0x00004010, 0x40084000, 0x40080000, 0x00004010, + 0x00000000, 0x00084010, 0x40080010, 0x00080000, 0x40004010, 0x40080000, 0x40084000, 0x00004000, + 0x40080000, 0x40004000, 0x00000010, 0x40084010, 0x00084010, 0x00000010, 0x00004000, 0x40000000, + 0x00004010, 0x40084000, 0x00080000, 0x40000010, 0x00080010, 0x40004010, 0x40000010, 0x00080010, + 0x00084000, 0x00000000, 0x40004000, 0x00004010, 0x40000000, 0x40080010, 0x40084010, 0x00084000, }, + { 0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000, 0x00010104, 0x04000100, + 0x00010004, 0x04000004, 0x04000004, 0x00010000, 0x04010104, 0x00010004, 0x04010000, 0x00000104, + 0x04000000, 0x00000004, 0x04010100, 0x00000100, 0x00010100, 0x04010000, 0x04010004, 0x00010104, + 0x04000104, 0x00010100, 0x00010000, 0x04000104, 0x00000004, 0x04010104, 0x00000100, 0x04000000, + 0x04010100, 0x04000000, 0x00010004, 0x00000104, 0x00010000, 0x04010100, 0x04000100, 0x00000000, + 0x00000100, 0x00010004, 0x04010104, 0x04000100, 0x04000004, 0x00000100, 0x00000000, 0x04010004, + 0x04000104, 0x00010000, 0x04000000, 0x04010104, 0x00000004, 0x00010104, 0x00010100, 0x04000004, + 0x04010000, 0x04000104, 0x00000104, 0x04010000, 0x00010104, 0x00000004, 0x04010004, 0x00010100, }, + { 0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040, 0x80400000, 0x80001000, + 0x00000000, 0x00401000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00400040, 0x80400000, + 0x80000000, 0x00001000, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x80001000, 0x00001040, + 0x80400040, 0x80000000, 0x00001040, 0x00400040, 0x00001000, 0x00401040, 0x80401040, 0x80000040, + 0x00400040, 0x80400000, 0x00401000, 0x80401040, 0x80000040, 0x00000000, 0x00000000, 0x00401000, + 0x00001040, 0x00400040, 0x80400040, 0x80000000, 0x80401000, 0x80001040, 0x80001040, 0x00000040, + 0x80401040, 0x80000040, 0x80000000, 0x00001000, 0x80400000, 0x80001000, 0x00401040, 0x80400040, + 0x80001000, 0x00001040, 0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x00001000, 0x00401040, }, + { 0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080, 0x20000000, 0x01040000, + 0x20040080, 0x00040000, 0x01000080, 0x20040080, 0x21000080, 0x21040000, 0x00040080, 0x20000000, + 0x01000000, 0x20040000, 0x20040000, 0x00000000, 0x20000080, 0x21040080, 0x21040080, 0x01000080, + 0x21040000, 0x20000080, 0x00000000, 0x21000000, 0x01040080, 0x01000000, 0x21000000, 0x00040080, + 0x00040000, 0x21000080, 0x00000080, 0x01000000, 0x20000000, 0x01040000, 0x21000080, 0x20040080, + 0x01000080, 0x20000000, 0x21040000, 0x01040080, 0x20040080, 0x00000080, 0x01000000, 0x21040000, + 0x21040080, 0x00040080, 0x21000000, 0x21040080, 0x01040000, 0x00000000, 0x20040000, 0x21000000, + 0x00040080, 0x01000080, 0x20000080, 0x00040000, 0x00000000, 0x20040000, 0x01040080, 0x20000080, }, + { 0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008, 0x10202008, 0x00200000, + 0x10002000, 0x00202008, 0x00200000, 0x10000008, 0x00200008, 0x10002000, 0x10000000, 0x00002008, + 0x00000000, 0x00200008, 0x10002008, 0x00002000, 0x00202000, 0x10002008, 0x00000008, 0x10200008, + 0x10200008, 0x00000000, 0x00202008, 0x10202000, 0x00002008, 0x00202000, 0x10202000, 0x10000000, + 0x10002000, 0x00000008, 0x10200008, 0x00202000, 0x10202008, 0x00200000, 0x00002008, 0x10000008, + 0x00200000, 0x10002000, 0x10000000, 0x00002008, 0x10000008, 0x10202008, 0x00202000, 0x10200000, + 0x00202008, 0x10202000, 0x00000000, 0x10200008, 0x00000008, 0x00002000, 0x10200000, 0x00202008, + 0x00002000, 0x00200008, 0x10002008, 0x00000000, 0x10202000, 0x10000000, 0x00200008, 0x10002008, }, + { 0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401, 0x00100401, 0x02100400, + 0x02100401, 0x00100000, 0x00000000, 0x02000001, 0x00000001, 0x02000000, 0x02100001, 0x00000401, + 0x02000400, 0x00100401, 0x00100001, 0x02000400, 0x02000001, 0x02100000, 0x02100400, 0x00100001, + 0x02100000, 0x00000400, 0x00000401, 0x02100401, 0x00100400, 0x00000001, 0x02000000, 0x00100400, + 0x02000000, 0x00100400, 0x00100000, 0x02000401, 0x02000401, 0x02100001, 0x02100001, 0x00000001, + 0x00100001, 0x02000000, 0x02000400, 0x00100000, 0x02100400, 0x00000401, 0x00100401, 0x02100400, + 0x00000401, 0x02000001, 0x02100401, 0x02100000, 0x00100400, 0x00000000, 0x00000001, 0x02100401, + 0x00000000, 0x00100401, 0x02100000, 0x00000400, 0x02000001, 0x02000400, 0x00000400, 0x00100001, }, + { 0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820, 0x00000020, 0x08000000, + 0x00020020, 0x08020000, 0x08020820, 0x00020800, 0x08020800, 0x00020820, 0x00000800, 0x00000020, + 0x08020000, 0x08000020, 0x08000800, 0x00000820, 0x00020800, 0x00020020, 0x08020020, 0x08020800, + 0x00000820, 0x00000000, 0x00000000, 0x08020020, 0x08000020, 0x08000800, 0x00020820, 0x00020000, + 0x00020820, 0x00020000, 0x08020800, 0x00000800, 0x00000020, 0x08020020, 0x00000800, 0x00020820, + 0x08000800, 0x00000020, 0x08000020, 0x08020000, 0x08020020, 0x08000000, 0x00020000, 0x08000820, + 0x00000000, 0x08020820, 0x00020020, 0x08000020, 0x08020000, 0x08000800, 0x08000820, 0x00000000, + 0x08020820, 0x00020800, 0x00020800, 0x00000820, 0x00000820, 0x00020020, 0x08000000, 0x08020800, }, +}; +#endif + +static uint64_t shuffle(uint64_t in, const uint8_t *shuffle, int shuffle_len) +{ + int i; + uint64_t res = 0; + for (i = 0; i < shuffle_len; i++) + res += res + ((in >> *shuffle++) & 1); + return res; +} + +static uint64_t shuffle_inv(uint64_t in, const uint8_t *shuffle, int shuffle_len) +{ + int i; + uint64_t res = 0; + shuffle += shuffle_len - 1; + for (i = 0; i < shuffle_len; i++) { + res |= (in & 1) << *shuffle--; + in >>= 1; + } + return res; +} + +static uint32_t f_func(uint32_t r, uint64_t k) +{ + int i; + uint32_t out = 0; + // rotate to get first part of E-shuffle in the lowest 6 bits + r = (r << 1) | (r >> 31); + // apply S-boxes, those compress the data again from 8 * 6 to 8 * 4 bits + for (i = 7; i >= 0; i--) { + uint8_t tmp = (r ^ k) & 0x3f; +#if CONFIG_SMALL + uint8_t v = S_boxes[i][tmp >> 1]; + if (tmp & 1) + v >>= 4; + out = (out >> 4) | (v << 28); +#else + out |= S_boxes_P_shuffle[i][tmp]; +#endif + // get next 6 bits of E-shuffle and round key k into the lowest bits + r = (r >> 4) | (r << 28); + k >>= 6; + } +#if CONFIG_SMALL + out = shuffle(out, P_shuffle, sizeof(P_shuffle)); +#endif + return out; +} + +/** + * @brief rotate the two halves of the expanded 56 bit key each 1 bit left + * + * Note: the specification calls this "shift", so I kept it although + * it is confusing. + */ +static uint64_t key_shift_left(uint64_t CDn) +{ + uint64_t carries = (CDn >> 27) & 0x10000001; + CDn <<= 1; + CDn &= ~0x10000001; + CDn |= carries; + return CDn; +} + +static void gen_roundkeys(uint64_t K[16], uint64_t key) +{ + int i; + // discard parity bits from key and shuffle it into C and D parts + uint64_t CDn = shuffle(key, PC1_shuffle, sizeof(PC1_shuffle)); + // generate round keys + for (i = 0; i < 16; i++) { + CDn = key_shift_left(CDn); + if (i > 1 && i != 8 && i != 15) + CDn = key_shift_left(CDn); + K[i] = shuffle(CDn, PC2_shuffle, sizeof(PC2_shuffle)); + } +} + +static uint64_t des_encdec(uint64_t in, uint64_t K[16], int decrypt) +{ + int i; + // used to apply round keys in reverse order for decryption + decrypt = decrypt ? 15 : 0; + // shuffle irrelevant to security but to ease hardware implementations + in = shuffle(in, IP_shuffle, sizeof(IP_shuffle)); + for (i = 0; i < 16; i++) { + uint32_t f_res; + f_res = f_func(in, K[decrypt ^ i]); + in = (in << 32) | (in >> 32); + in ^= f_res; + } + in = (in << 32) | (in >> 32); + // reverse shuffle used to ease hardware implementations + in = shuffle_inv(in, IP_shuffle, sizeof(IP_shuffle)); + return in; +} + +AVDES *av_des_alloc(void) +{ + return av_mallocz(sizeof(struct AVDES)); +} + +int av_des_init(AVDES *d, const uint8_t *key, int key_bits, av_unused int decrypt) { + if (key_bits != 64 && key_bits != 192) + return AVERROR(EINVAL); + d->triple_des = key_bits > 64; + gen_roundkeys(d->round_keys[0], AV_RB64(key)); + if (d->triple_des) { + gen_roundkeys(d->round_keys[1], AV_RB64(key + 8)); + gen_roundkeys(d->round_keys[2], AV_RB64(key + 16)); + } + return 0; +} + +static void av_des_crypt_mac(AVDES *d, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt, int mac) +{ + uint64_t iv_val = iv ? AV_RB64(iv) : 0; + while (count-- > 0) { + uint64_t dst_val; + uint64_t src_val = src ? AV_RB64(src) : 0; + if (decrypt) { + uint64_t tmp = src_val; + if (d->triple_des) { + src_val = des_encdec(src_val, d->round_keys[2], 1); + src_val = des_encdec(src_val, d->round_keys[1], 0); + } + dst_val = des_encdec(src_val, d->round_keys[0], 1) ^ iv_val; + iv_val = iv ? tmp : 0; + } else { + dst_val = des_encdec(src_val ^ iv_val, d->round_keys[0], 0); + if (d->triple_des) { + dst_val = des_encdec(dst_val, d->round_keys[1], 1); + dst_val = des_encdec(dst_val, d->round_keys[2], 0); + } + iv_val = iv ? dst_val : 0; + } + AV_WB64(dst, dst_val); + src += 8; + if (!mac) + dst += 8; + } + if (iv) + AV_WB64(iv, iv_val); +} + +void av_des_crypt(AVDES *d, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt) +{ + av_des_crypt_mac(d, dst, src, count, iv, decrypt, 0); +} + +void av_des_mac(AVDES *d, uint8_t *dst, const uint8_t *src, int count) +{ + av_des_crypt_mac(d, dst, src, count, (uint8_t[8]) { 0 }, 0, 1); +} diff --git a/libs/ffmpeg/libavutil/des.h b/libs/ffmpeg/libavutil/des.h new file mode 100644 index 00000000000..3a3e6fa47ce --- /dev/null +++ b/libs/ffmpeg/libavutil/des.h @@ -0,0 +1,81 @@ +/* + * DES encryption/decryption + * Copyright (c) 2007 Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DES_H +#define AVUTIL_DES_H + +#include <stdint.h> + +/** + * @defgroup lavu_des DES + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVDES { + uint64_t round_keys[3][16]; + int triple_des; +} AVDES; + +/** + * Allocate an AVDES context. + */ +AVDES *av_des_alloc(void); + +/** + * @brief Initializes an AVDES context. + * + * @param d pointer to a AVDES structure to initialize + * @param key pointer to the key to use + * @param key_bits must be 64 or 192 + * @param decrypt 0 for encryption/CBC-MAC, 1 for decryption + * @return zero on success, negative value otherwise + */ +int av_des_init(struct AVDES *d, const uint8_t *key, int key_bits, int decrypt); + +/** + * @brief Encrypts / decrypts using the DES algorithm. + * + * @param d pointer to the AVDES structure + * @param dst destination array, can be equal to src, must be 8-byte aligned + * @param src source array, can be equal to dst, must be 8-byte aligned, may be NULL + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used, + * must be 8-byte aligned + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_des_crypt(struct AVDES *d, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @brief Calculates CBC-MAC using the DES algorithm. + * + * @param d pointer to the AVDES structure + * @param dst destination array, can be equal to src, must be 8-byte aligned + * @param src source array, can be equal to dst, must be 8-byte aligned, may be NULL + * @param count number of 8 byte blocks + */ +void av_des_mac(struct AVDES *d, uint8_t *dst, const uint8_t *src, int count); + +/** + * @} + */ + +#endif /* AVUTIL_DES_H */ diff --git a/libs/ffmpeg/libavutil/detection_bbox.c b/libs/ffmpeg/libavutil/detection_bbox.c new file mode 100644 index 00000000000..cb157b355bd --- /dev/null +++ b/libs/ffmpeg/libavutil/detection_bbox.c @@ -0,0 +1,73 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "detection_bbox.h" +#include "mem.h" + +AVDetectionBBoxHeader *av_detection_bbox_alloc(uint32_t nb_bboxes, size_t *out_size) +{ + size_t size; + struct BBoxContext { + AVDetectionBBoxHeader header; + AVDetectionBBox boxes; + }; + const size_t bboxes_offset = offsetof(struct BBoxContext, boxes); + const size_t bbox_size = sizeof(AVDetectionBBox); + AVDetectionBBoxHeader *header; + + size = bboxes_offset; + if (nb_bboxes > (SIZE_MAX - size) / bbox_size) + return NULL; + size += bbox_size * nb_bboxes; + + header = av_mallocz(size); + if (!header) + return NULL; + + header->nb_bboxes = nb_bboxes; + header->bbox_size = bbox_size; + header->bboxes_offset = bboxes_offset; + + if (out_size) + *out_size = size; + + return header; +} + +AVDetectionBBoxHeader *av_detection_bbox_create_side_data(AVFrame *frame, uint32_t nb_bboxes) +{ + AVBufferRef *buf; + AVDetectionBBoxHeader *header; + size_t size; + + header = av_detection_bbox_alloc(nb_bboxes, &size); + if (!header) + return NULL; + buf = av_buffer_create((uint8_t *)header, size, NULL, NULL, 0); + if (!buf) { + av_freep(&header); + return NULL; + } + + if (!av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DETECTION_BBOXES, buf)) { + av_buffer_unref(&buf); + return NULL; + } + + return header; +} diff --git a/libs/ffmpeg/libavutil/detection_bbox.h b/libs/ffmpeg/libavutil/detection_bbox.h new file mode 100644 index 00000000000..011988052c2 --- /dev/null +++ b/libs/ffmpeg/libavutil/detection_bbox.h @@ -0,0 +1,108 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DETECTION_BBOX_H +#define AVUTIL_DETECTION_BBOX_H + +#include "rational.h" +#include "avassert.h" +#include "frame.h" + +typedef struct AVDetectionBBox { + /** + * Distance in pixels from the left/top edge of the frame, + * together with width and height, defining the bounding box. + */ + int x; + int y; + int w; + int h; + +#define AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE 64 + + /** + * Detect result with confidence + */ + char detect_label[AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE]; + AVRational detect_confidence; + + /** + * At most 4 classifications based on the detected bounding box. + * For example, we can get max 4 different attributes with 4 different + * DNN models on one bounding box. + * classify_count is zero if no classification. + */ +#define AV_NUM_DETECTION_BBOX_CLASSIFY 4 + uint32_t classify_count; + char classify_labels[AV_NUM_DETECTION_BBOX_CLASSIFY][AV_DETECTION_BBOX_LABEL_NAME_MAX_SIZE]; + AVRational classify_confidences[AV_NUM_DETECTION_BBOX_CLASSIFY]; +} AVDetectionBBox; + +typedef struct AVDetectionBBoxHeader { + /** + * Information about how the bounding box is generated. + * for example, the DNN model name. + */ + char source[256]; + + /** + * Number of bounding boxes in the array. + */ + uint32_t nb_bboxes; + + /** + * Offset in bytes from the beginning of this structure at which + * the array of bounding boxes starts. + */ + size_t bboxes_offset; + + /** + * Size of each bounding box in bytes. + */ + size_t bbox_size; +} AVDetectionBBoxHeader; + +/* + * Get the bounding box at the specified {@code idx}. Must be between 0 and nb_bboxes. + */ +static av_always_inline AVDetectionBBox * +av_get_detection_bbox(const AVDetectionBBoxHeader *header, unsigned int idx) +{ + av_assert0(idx < header->nb_bboxes); + return (AVDetectionBBox *)((uint8_t *)header + header->bboxes_offset + + idx * header->bbox_size); +} + +/** + * Allocates memory for AVDetectionBBoxHeader, plus an array of {@code nb_bboxes} + * AVDetectionBBox, and initializes the variables. + * Can be freed with a normal av_free() call. + * + * @param nb_bboxes number of AVDetectionBBox structures to allocate + * @param out_size if non-NULL, the size in bytes of the resulting data array is + * written here. + */ +AVDetectionBBoxHeader *av_detection_bbox_alloc(uint32_t nb_bboxes, size_t *out_size); + +/** + * Allocates memory for AVDetectionBBoxHeader, plus an array of {@code nb_bboxes} + * AVDetectionBBox, in the given AVFrame {@code frame} as AVFrameSideData of type + * AV_FRAME_DATA_DETECTION_BBOXES and initializes the variables. + */ +AVDetectionBBoxHeader *av_detection_bbox_create_side_data(AVFrame *frame, uint32_t nb_bboxes); +#endif diff --git a/libs/ffmpeg/libavutil/dict.c b/libs/ffmpeg/libavutil/dict.c new file mode 100644 index 00000000000..fafb454fd38 --- /dev/null +++ b/libs/ffmpeg/libavutil/dict.c @@ -0,0 +1,286 @@ +/* + * copyright (c) 2009 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <inttypes.h> +#include <stdio.h> +#include <string.h> + +#include "avassert.h" +#include "avstring.h" +#include "dict.h" +#include "error.h" +#include "mem.h" +#include "bprint.h" + +struct AVDictionary { + int count; + AVDictionaryEntry *elems; +}; + +int av_dict_count(const AVDictionary *m) +{ + return m ? m->count : 0; +} + +const AVDictionaryEntry *av_dict_iterate(const AVDictionary *m, + const AVDictionaryEntry *prev) +{ + int i = 0; + + if (!m) + return NULL; + + if (prev) + i = prev - m->elems + 1; + + av_assert2(i >= 0); + if (i >= m->count) + return NULL; + + return &m->elems[i]; +} + +AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key, + const AVDictionaryEntry *prev, int flags) +{ + const AVDictionaryEntry *entry = prev; + unsigned int j; + + if (!key) + return NULL; + + while ((entry = av_dict_iterate(m, entry))) { + const char *s = entry->key; + if (flags & AV_DICT_MATCH_CASE) + for (j = 0; s[j] == key[j] && key[j]; j++) + ; + else + for (j = 0; av_toupper(s[j]) == av_toupper(key[j]) && key[j]; j++) + ; + if (key[j]) + continue; + if (s[j] && !(flags & AV_DICT_IGNORE_SUFFIX)) + continue; + return (AVDictionaryEntry *)entry; + } + return NULL; +} + +int av_dict_set(AVDictionary **pm, const char *key, const char *value, + int flags) +{ + AVDictionary *m = *pm; + AVDictionaryEntry *tag = NULL; + char *copy_key = NULL, *copy_value = NULL; + int err; + + if (flags & AV_DICT_DONT_STRDUP_VAL) + copy_value = (void *)value; + else if (value) + copy_value = av_strdup(value); + if (!key) { + err = AVERROR(EINVAL); + goto err_out; + } + if (flags & AV_DICT_DONT_STRDUP_KEY) + copy_key = (void *)key; + else + copy_key = av_strdup(key); + if (!copy_key || (value && !copy_value)) + goto enomem; + + if (!(flags & AV_DICT_MULTIKEY)) { + tag = av_dict_get(m, key, NULL, flags); + } else if (flags & AV_DICT_DEDUP) { + while ((tag = av_dict_get(m, key, tag, flags))) { + if ((!value && !tag->value) || + (value && tag->value && !strcmp(value, tag->value))) { + av_free(copy_key); + av_free(copy_value); + return 0; + } + } + } + if (!m) + m = *pm = av_mallocz(sizeof(*m)); + if (!m) + goto enomem; + + if (tag) { + if (flags & AV_DICT_DONT_OVERWRITE) { + av_free(copy_key); + av_free(copy_value); + return 0; + } + if (copy_value && flags & AV_DICT_APPEND) { + size_t oldlen = strlen(tag->value); + size_t new_part_len = strlen(copy_value); + size_t len = oldlen + new_part_len + 1; + char *newval = av_realloc(tag->value, len); + if (!newval) + goto enomem; + memcpy(newval + oldlen, copy_value, new_part_len + 1); + av_freep(©_value); + copy_value = newval; + } else + av_free(tag->value); + av_free(tag->key); + *tag = m->elems[--m->count]; + } else if (copy_value) { + AVDictionaryEntry *tmp = av_realloc_array(m->elems, + m->count + 1, sizeof(*m->elems)); + if (!tmp) + goto enomem; + m->elems = tmp; + } + if (copy_value) { + m->elems[m->count].key = copy_key; + m->elems[m->count].value = copy_value; + m->count++; + } else { + err = 0; + goto end; + } + + return 0; + +enomem: + err = AVERROR(ENOMEM); +err_out: + av_free(copy_value); +end: + if (m && !m->count) { + av_freep(&m->elems); + av_freep(pm); + } + av_free(copy_key); + return err; +} + +int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, + int flags) +{ + char valuestr[22]; + snprintf(valuestr, sizeof(valuestr), "%"PRId64, value); + flags &= ~AV_DICT_DONT_STRDUP_VAL; + return av_dict_set(pm, key, valuestr, flags); +} + +static int parse_key_value_pair(AVDictionary **pm, const char **buf, + const char *key_val_sep, const char *pairs_sep, + int flags) +{ + char *key = av_get_token(buf, key_val_sep); + char *val = NULL; + int ret; + + if (key && *key && strspn(*buf, key_val_sep)) { + (*buf)++; + val = av_get_token(buf, pairs_sep); + } + + if (key && *key && val && *val) + ret = av_dict_set(pm, key, val, flags); + else + ret = AVERROR(EINVAL); + + av_freep(&key); + av_freep(&val); + + return ret; +} + +int av_dict_parse_string(AVDictionary **pm, const char *str, + const char *key_val_sep, const char *pairs_sep, + int flags) +{ + int ret; + + if (!str) + return 0; + + /* ignore STRDUP flags */ + flags &= ~(AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); + + while (*str) { + if ((ret = parse_key_value_pair(pm, &str, key_val_sep, pairs_sep, flags)) < 0) + return ret; + + if (*str) + str++; + } + + return 0; +} + +void av_dict_free(AVDictionary **pm) +{ + AVDictionary *m = *pm; + + if (m) { + while (m->count--) { + av_freep(&m->elems[m->count].key); + av_freep(&m->elems[m->count].value); + } + av_freep(&m->elems); + } + av_freep(pm); +} + +int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags) +{ + const AVDictionaryEntry *t = NULL; + + while ((t = av_dict_iterate(src, t))) { + int ret = av_dict_set(dst, t->key, t->value, flags); + if (ret < 0) + return ret; + } + + return 0; +} + +int av_dict_get_string(const AVDictionary *m, char **buffer, + const char key_val_sep, const char pairs_sep) +{ + const AVDictionaryEntry *t = NULL; + AVBPrint bprint; + int cnt = 0; + char special_chars[] = {pairs_sep, key_val_sep, '\0'}; + + if (!buffer || pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep || + pairs_sep == '\\' || key_val_sep == '\\') + return AVERROR(EINVAL); + + if (!av_dict_count(m)) { + *buffer = av_strdup(""); + return *buffer ? 0 : AVERROR(ENOMEM); + } + + av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); + while ((t = av_dict_iterate(m, t))) { + if (cnt++) + av_bprint_append_data(&bprint, &pairs_sep, 1); + av_bprint_escape(&bprint, t->key, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); + av_bprint_append_data(&bprint, &key_val_sep, 1); + av_bprint_escape(&bprint, t->value, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); + } + return av_bprint_finalize(&bprint, buffer); +} diff --git a/libs/ffmpeg/libavutil/dict.h b/libs/ffmpeg/libavutil/dict.h new file mode 100644 index 00000000000..93c7cbf1286 --- /dev/null +++ b/libs/ffmpeg/libavutil/dict.h @@ -0,0 +1,242 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Public dictionary API. + * @deprecated + * AVDictionary is provided for compatibility with libav. It is both in + * implementation as well as API inefficient. It does not scale and is + * extremely slow with large dictionaries. + * It is recommended that new code uses our tree container from tree.c/h + * where applicable, which uses AVL trees to achieve O(log n) performance. + */ + +#ifndef AVUTIL_DICT_H +#define AVUTIL_DICT_H + +#include <stdint.h> + +/** + * @addtogroup lavu_dict AVDictionary + * @ingroup lavu_data + * + * @brief Simple key:value store + * + * @{ + * Dictionaries are used for storing key-value pairs. + * + * - To **create an AVDictionary**, simply pass an address of a NULL + * pointer to av_dict_set(). NULL can be used as an empty dictionary + * wherever a pointer to an AVDictionary is required. + * - To **insert an entry**, use av_dict_set(). + * - Use av_dict_get() to **retrieve an entry**. + * - To **iterate over all entries**, use av_dict_iterate(). + * - In order to **free the dictionary and all its contents**, use av_dict_free(). + * + @code + AVDictionary *d = NULL; // "create" an empty dictionary + AVDictionaryEntry *t = NULL; + + av_dict_set(&d, "foo", "bar", 0); // add an entry + + char *k = av_strdup("key"); // if your strings are already allocated, + char *v = av_strdup("value"); // you can avoid copying them like this + av_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); + + while ((t = av_dict_iterate(d, t))) { + <....> // iterate over all entries in d + } + av_dict_free(&d); + @endcode + */ + +/** + * @name AVDictionary Flags + * Flags that influence behavior of the matching of keys or insertion to the dictionary. + * @{ + */ +#define AV_DICT_MATCH_CASE 1 /**< Only get an entry with exact-case key match. Only relevant in av_dict_get(). */ +#define AV_DICT_IGNORE_SUFFIX 2 /**< Return first entry in a dictionary whose first part corresponds to the search key, + ignoring the suffix of the found key string. Only relevant in av_dict_get(). */ +#define AV_DICT_DONT_STRDUP_KEY 4 /**< Take ownership of a key that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_STRDUP_VAL 8 /**< Take ownership of a value that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_OVERWRITE 16 /**< Don't overwrite existing entries. */ +#define AV_DICT_APPEND 32 /**< If the entry already exists, append to it. Note that no + delimiter is added, the strings are simply concatenated. */ +#define AV_DICT_MULTIKEY 64 /**< Allow to store several equal keys in the dictionary */ +#define AV_DICT_DEDUP 128 /**< If inserting a value that already exists for a key, do nothing. Only relevant with AV_DICT_MULTIKEY. */ +/** + * @} + */ + +typedef struct AVDictionaryEntry { + char *key; + char *value; +} AVDictionaryEntry; + +typedef struct AVDictionary AVDictionary; + +/** + * Get a dictionary entry with matching key. + * + * The returned entry key or value must not be changed, or it will + * cause undefined behavior. + * + * @param prev Set to the previous matching element to find the next. + * If set to NULL the first matching element is returned. + * @param key Matching key + * @param flags A collection of AV_DICT_* flags controlling how the + * entry is retrieved + * + * @return Found entry or NULL in case no matching entry was found in the dictionary + */ +AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key, + const AVDictionaryEntry *prev, int flags); + +/** + * Iterate over a dictionary + * + * Iterates through all entries in the dictionary. + * + * @warning The returned AVDictionaryEntry key/value must not be changed. + * + * @warning As av_dict_set() invalidates all previous entries returned + * by this function, it must not be called while iterating over the dict. + * + * Typical usage: + * @code + * const AVDictionaryEntry *e = NULL; + * while ((e = av_dict_iterate(m, e))) { + * // ... + * } + * @endcode + * + * @param m The dictionary to iterate over + * @param prev Pointer to the previous AVDictionaryEntry, NULL initially + * + * @retval AVDictionaryEntry* The next element in the dictionary + * @retval NULL No more elements in the dictionary + */ +const AVDictionaryEntry *av_dict_iterate(const AVDictionary *m, + const AVDictionaryEntry *prev); + +/** + * Get number of entries in dictionary. + * + * @param m dictionary + * @return number of entries in dictionary + */ +int av_dict_count(const AVDictionary *m); + +/** + * Set the given entry in *pm, overwriting an existing entry. + * + * Note: If AV_DICT_DONT_STRDUP_KEY or AV_DICT_DONT_STRDUP_VAL is set, + * these arguments will be freed on error. + * + * @warning Adding a new entry to a dictionary invalidates all existing entries + * previously returned with av_dict_get() or av_dict_iterate(). + * + * @param pm Pointer to a pointer to a dictionary struct. If *pm is NULL + * a dictionary struct is allocated and put in *pm. + * @param key Entry key to add to *pm (will either be av_strduped or added as a new key depending on flags) + * @param value Entry value to add to *pm (will be av_strduped or added as a new key depending on flags). + * Passing a NULL value will cause an existing entry to be deleted. + * + * @return >= 0 on success otherwise an error code <0 + */ +int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags); + +/** + * Convenience wrapper for av_dict_set() that converts the value to a string + * and stores it. + * + * Note: If ::AV_DICT_DONT_STRDUP_KEY is set, key will be freed on error. + */ +int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags); + +/** + * Parse the key/value pairs list and add the parsed entries to a dictionary. + * + * In case of failure, all the successfully set entries are stored in + * *pm. You may need to manually free the created dictionary. + * + * @param key_val_sep A 0-terminated list of characters used to separate + * key from value + * @param pairs_sep A 0-terminated list of characters used to separate + * two pairs from each other + * @param flags Flags to use when adding to the dictionary. + * ::AV_DICT_DONT_STRDUP_KEY and ::AV_DICT_DONT_STRDUP_VAL + * are ignored since the key/value tokens will always + * be duplicated. + * + * @return 0 on success, negative AVERROR code on failure + */ +int av_dict_parse_string(AVDictionary **pm, const char *str, + const char *key_val_sep, const char *pairs_sep, + int flags); + +/** + * Copy entries from one AVDictionary struct into another. + * + * @note Metadata is read using the ::AV_DICT_IGNORE_SUFFIX flag + * + * @param dst Pointer to a pointer to a AVDictionary struct to copy into. If *dst is NULL, + * this function will allocate a struct for you and put it in *dst + * @param src Pointer to the source AVDictionary struct to copy items from. + * @param flags Flags to use when setting entries in *dst + * + * @return 0 on success, negative AVERROR code on failure. If dst was allocated + * by this function, callers should free the associated memory. + */ +int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags); + +/** + * Free all the memory allocated for an AVDictionary struct + * and all keys and values. + */ +void av_dict_free(AVDictionary **m); + +/** + * Get dictionary entries as a string. + * + * Create a string containing dictionary's entries. + * Such string may be passed back to av_dict_parse_string(). + * @note String is escaped with backslashes ('\'). + * + * @warning Separators cannot be neither '\\' nor '\0'. They also cannot be the same. + * + * @param[in] m The dictionary + * @param[out] buffer Pointer to buffer that will be allocated with string containing entries. + * Buffer must be freed by the caller when is no longer needed. + * @param[in] key_val_sep Character used to separate key from value + * @param[in] pairs_sep Character used to separate two pairs from each other + * + * @return >= 0 on success, negative on error + */ +int av_dict_get_string(const AVDictionary *m, char **buffer, + const char key_val_sep, const char pairs_sep); + +/** + * @} + */ + +#endif /* AVUTIL_DICT_H */ diff --git a/libs/ffmpeg/libavutil/display.c b/libs/ffmpeg/libavutil/display.c new file mode 100644 index 00000000000..d31061283cf --- /dev/null +++ b/libs/ffmpeg/libavutil/display.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2014 Vittorio Giovara <vittorio.giovara@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdint.h> +#include <string.h> +#include <math.h> + +#include "display.h" +#include "libm.h" +#include "mathematics.h" + +// fixed point to double +#define CONV_FP(x) ((double) (x)) / (1 << 16) + +// double to fixed point +#define CONV_DB(x) (int32_t) ((x) * (1 << 16)) + +double av_display_rotation_get(const int32_t matrix[9]) +{ + double rotation, scale[2]; + + scale[0] = hypot(CONV_FP(matrix[0]), CONV_FP(matrix[3])); + scale[1] = hypot(CONV_FP(matrix[1]), CONV_FP(matrix[4])); + + if (scale[0] == 0.0 || scale[1] == 0.0) + return NAN; + + rotation = atan2(CONV_FP(matrix[1]) / scale[1], + CONV_FP(matrix[0]) / scale[0]) * 180 / M_PI; + + return -rotation; +} + +void av_display_rotation_set(int32_t matrix[9], double angle) +{ + double radians = -angle * M_PI / 180.0f; + double c = cos(radians); + double s = sin(radians); + + memset(matrix, 0, 9 * sizeof(int32_t)); + + matrix[0] = CONV_DB(c); + matrix[1] = CONV_DB(-s); + matrix[3] = CONV_DB(s); + matrix[4] = CONV_DB(c); + matrix[8] = 1 << 30; +} + +void av_display_matrix_flip(int32_t matrix[9], int hflip, int vflip) +{ + int i; + const int flip[] = { 1 - 2 * (!!hflip), 1 - 2 * (!!vflip), 1 }; + + if (hflip || vflip) + for (i = 0; i < 9; i++) + matrix[i] *= flip[i % 3]; +} diff --git a/libs/ffmpeg/libavutil/display.h b/libs/ffmpeg/libavutil/display.h new file mode 100644 index 00000000000..50f2b44caf5 --- /dev/null +++ b/libs/ffmpeg/libavutil/display.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014 Vittorio Giovara <vittorio.giovara@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_video_display + * Display matrix + */ + +#ifndef AVUTIL_DISPLAY_H +#define AVUTIL_DISPLAY_H + +#include <stdint.h> + +/** + * @defgroup lavu_video_display Display transformation matrix functions + * @ingroup lavu_video + * + * The display transformation matrix specifies an affine transformation that + * should be applied to video frames for correct presentation. It is compatible + * with the matrices stored in the ISO/IEC 14496-12 container format. + * + * The data is a 3x3 matrix represented as a 9-element array: + * + * @code{.unparsed} + * | a b u | + * (a, b, u, c, d, v, x, y, w) -> | c d v | + * | x y w | + * @endcode + * + * All numbers are stored in native endianness, as 16.16 fixed-point values, + * except for u, v and w, which are stored as 2.30 fixed-point values. + * + * The transformation maps a point (p, q) in the source (pre-transformation) + * frame to the point (p', q') in the destination (post-transformation) frame as + * follows: + * + * @code{.unparsed} + * | a b u | + * (p, q, 1) . | c d v | = z * (p', q', 1) + * | x y w | + * @endcode + * + * The transformation can also be more explicitly written in components as + * follows: + * + * @code{.unparsed} + * p' = (a * p + c * q + x) / z; + * q' = (b * p + d * q + y) / z; + * z = u * p + v * q + w + * @endcode + * + * @{ + */ + +/** + * Extract the rotation component of the transformation matrix. + * + * @param matrix the transformation matrix + * @return the angle (in degrees) by which the transformation rotates the frame + * counterclockwise. The angle will be in range [-180.0, 180.0], + * or NaN if the matrix is singular. + * + * @note floating point numbers are inherently inexact, so callers are + * recommended to round the return value to nearest integer before use. + */ +double av_display_rotation_get(const int32_t matrix[9]); + +/** + * Initialize a transformation matrix describing a pure clockwise + * rotation by the specified angle (in degrees). + * + * @param[out] matrix a transformation matrix (will be fully overwritten + * by this function) + * @param angle rotation angle in degrees. + */ +void av_display_rotation_set(int32_t matrix[9], double angle); + +/** + * Flip the input matrix horizontally and/or vertically. + * + * @param[in,out] matrix a transformation matrix + * @param hflip whether the matrix should be flipped horizontally + * @param vflip whether the matrix should be flipped vertically + */ +void av_display_matrix_flip(int32_t matrix[9], int hflip, int vflip); + +/** + * @} + */ + +#endif /* AVUTIL_DISPLAY_H */ diff --git a/libs/ffmpeg/libavutil/dovi_meta.c b/libs/ffmpeg/libavutil/dovi_meta.c new file mode 100644 index 00000000000..dfa4a438ed4 --- /dev/null +++ b/libs/ffmpeg/libavutil/dovi_meta.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Jun Zhao<barryjzhao@tencent.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> + +#include "dovi_meta.h" +#include "mem.h" + +AVDOVIDecoderConfigurationRecord *av_dovi_alloc(size_t *size) +{ + AVDOVIDecoderConfigurationRecord *dovi = + av_mallocz(sizeof(AVDOVIDecoderConfigurationRecord)); + if (!dovi) + return NULL; + + if (size) + *size = sizeof(*dovi); + + return dovi; +} + +typedef struct AVDOVIMetadataInternal { + AVDOVIMetadata metadata; + AVDOVIRpuDataHeader header; + AVDOVIDataMapping mapping; + AVDOVIColorMetadata color; + AVDOVIDmData ext_blocks[AV_DOVI_MAX_EXT_BLOCKS]; +} AVDOVIMetadataInternal; + +AVDOVIMetadata *av_dovi_metadata_alloc(size_t *size) +{ + AVDOVIMetadataInternal *dovi = av_mallocz(sizeof(AVDOVIMetadataInternal)); + if (!dovi) + return NULL; + + if (size) + *size = sizeof(*dovi); + + dovi->metadata = (struct AVDOVIMetadata) { + .header_offset = offsetof(AVDOVIMetadataInternal, header), + .mapping_offset = offsetof(AVDOVIMetadataInternal, mapping), + .color_offset = offsetof(AVDOVIMetadataInternal, color), + .ext_block_offset = offsetof(AVDOVIMetadataInternal, ext_blocks), + .ext_block_size = sizeof(AVDOVIDmData), + }; + + return &dovi->metadata; +} + +AVDOVIDmData *av_dovi_find_level(const AVDOVIMetadata *data, uint8_t level) +{ + for (int i = 0; i < data->num_ext_blocks; i++) { + AVDOVIDmData *ext = av_dovi_get_ext(data, i); + if (ext->level == level) + return ext; + } + + return NULL; +} diff --git a/libs/ffmpeg/libavutil/dovi_meta.h b/libs/ffmpeg/libavutil/dovi_meta.h new file mode 100644 index 00000000000..c102bf384f4 --- /dev/null +++ b/libs/ffmpeg/libavutil/dovi_meta.h @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2020 Vacing Fang <vacingfang@tencent.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * DOVI configuration + */ + + +#ifndef AVUTIL_DOVI_META_H +#define AVUTIL_DOVI_META_H + +#include <stdint.h> +#include <stddef.h> + +#include "rational.h" +#include "csp.h" + +/* + * DOVI configuration + * ref: dolby-vision-bitstreams-within-the-iso-base-media-file-format-v2.1.2 + dolby-vision-bitstreams-in-mpeg-2-transport-stream-multiplex-v1.2 + * @code + * uint8_t dv_version_major, the major version number that the stream complies with + * uint8_t dv_version_minor, the minor version number that the stream complies with + * uint8_t dv_profile, the Dolby Vision profile + * uint8_t dv_level, the Dolby Vision level + * uint8_t rpu_present_flag + * uint8_t el_present_flag + * uint8_t bl_present_flag + * uint8_t dv_bl_signal_compatibility_id + * uint8_t dv_md_compression, the compression method in use + * @endcode + * + * @note The struct must be allocated with av_dovi_alloc() and + * its size is not a part of the public ABI. + */ +typedef struct AVDOVIDecoderConfigurationRecord { + uint8_t dv_version_major; + uint8_t dv_version_minor; + uint8_t dv_profile; + uint8_t dv_level; + uint8_t rpu_present_flag; + uint8_t el_present_flag; + uint8_t bl_present_flag; + uint8_t dv_bl_signal_compatibility_id; + uint8_t dv_md_compression; +} AVDOVIDecoderConfigurationRecord; + +enum AVDOVICompression { + AV_DOVI_COMPRESSION_NONE = 0, + AV_DOVI_COMPRESSION_LIMITED = 1, + AV_DOVI_COMPRESSION_RESERVED = 2, + AV_DOVI_COMPRESSION_EXTENDED = 3, +}; + +/** + * Allocate a AVDOVIDecoderConfigurationRecord structure and initialize its + * fields to default values. + * + * @return the newly allocated struct or NULL on failure + */ +AVDOVIDecoderConfigurationRecord *av_dovi_alloc(size_t *size); + +/** + * Dolby Vision RPU data header. + * + * @note sizeof(AVDOVIRpuDataHeader) is not part of the public ABI. + */ +typedef struct AVDOVIRpuDataHeader { + uint8_t rpu_type; + uint16_t rpu_format; + uint8_t vdr_rpu_profile; + uint8_t vdr_rpu_level; + uint8_t chroma_resampling_explicit_filter_flag; + uint8_t coef_data_type; /* informative, lavc always converts to fixed */ + uint8_t coef_log2_denom; + uint8_t vdr_rpu_normalized_idc; + uint8_t bl_video_full_range_flag; + uint8_t bl_bit_depth; /* [8, 16] */ + uint8_t el_bit_depth; /* [8, 16] */ + uint8_t vdr_bit_depth; /* [8, 16] */ + uint8_t spatial_resampling_filter_flag; + uint8_t el_spatial_resampling_filter_flag; + uint8_t disable_residual_flag; + uint8_t ext_mapping_idc_0_4; /* extended base layer inverse mapping indicator */ + uint8_t ext_mapping_idc_5_7; /* reserved */ +} AVDOVIRpuDataHeader; + +enum AVDOVIMappingMethod { + AV_DOVI_MAPPING_POLYNOMIAL = 0, + AV_DOVI_MAPPING_MMR = 1, +}; + +/** + * Coefficients of a piece-wise function. The pieces of the function span the + * value ranges between two adjacent pivot values. + */ +#define AV_DOVI_MAX_PIECES 8 +typedef struct AVDOVIReshapingCurve { + uint8_t num_pivots; /* [2, 9] */ + uint16_t pivots[AV_DOVI_MAX_PIECES + 1]; /* sorted ascending */ + enum AVDOVIMappingMethod mapping_idc[AV_DOVI_MAX_PIECES]; + /* AV_DOVI_MAPPING_POLYNOMIAL */ + uint8_t poly_order[AV_DOVI_MAX_PIECES]; /* [1, 2] */ + int64_t poly_coef[AV_DOVI_MAX_PIECES][3]; /* x^0, x^1, x^2 */ + /* AV_DOVI_MAPPING_MMR */ + uint8_t mmr_order[AV_DOVI_MAX_PIECES]; /* [1, 3] */ + int64_t mmr_constant[AV_DOVI_MAX_PIECES]; + int64_t mmr_coef[AV_DOVI_MAX_PIECES][3/* order - 1 */][7]; +} AVDOVIReshapingCurve; + +enum AVDOVINLQMethod { + AV_DOVI_NLQ_NONE = -1, + AV_DOVI_NLQ_LINEAR_DZ = 0, +}; + +/** + * Coefficients of the non-linear inverse quantization. For the interpretation + * of these, see ETSI GS CCM 001. + */ +typedef struct AVDOVINLQParams { + uint16_t nlq_offset; + uint64_t vdr_in_max; + /* AV_DOVI_NLQ_LINEAR_DZ */ + uint64_t linear_deadzone_slope; + uint64_t linear_deadzone_threshold; +} AVDOVINLQParams; + +/** + * Dolby Vision RPU data mapping parameters. + * + * @note sizeof(AVDOVIDataMapping) is not part of the public ABI. + */ +typedef struct AVDOVIDataMapping { + uint8_t vdr_rpu_id; + uint8_t mapping_color_space; + uint8_t mapping_chroma_format_idc; + AVDOVIReshapingCurve curves[3]; /* per component */ + + /* Non-linear inverse quantization */ + enum AVDOVINLQMethod nlq_method_idc; + uint32_t num_x_partitions; + uint32_t num_y_partitions; + AVDOVINLQParams nlq[3]; /* per component */ + uint16_t nlq_pivots[2]; +} AVDOVIDataMapping; + +/** + * Dolby Vision RPU colorspace metadata parameters. + * + * @note sizeof(AVDOVIColorMetadata) is not part of the public ABI. + */ +typedef struct AVDOVIColorMetadata { + uint8_t dm_metadata_id; + uint8_t scene_refresh_flag; + + /** + * Coefficients of the custom Dolby Vision IPT-PQ matrices. These are to be + * used instead of the matrices indicated by the frame's colorspace tags. + * The output of rgb_to_lms_matrix is to be fed into a BT.2020 LMS->RGB + * matrix based on a Hunt-Pointer-Estevez transform, but without any + * crosstalk. (See the definition of the ICtCp colorspace for more + * information.) + */ + AVRational ycc_to_rgb_matrix[9]; /* before PQ linearization */ + AVRational ycc_to_rgb_offset[3]; /* input offset of neutral value */ + AVRational rgb_to_lms_matrix[9]; /* after PQ linearization */ + + /** + * Extra signal metadata (see Dolby patents for more info). + */ + uint16_t signal_eotf; + uint16_t signal_eotf_param0; + uint16_t signal_eotf_param1; + uint32_t signal_eotf_param2; + uint8_t signal_bit_depth; + uint8_t signal_color_space; + uint8_t signal_chroma_format; + uint8_t signal_full_range_flag; /* [0, 3] */ + uint16_t source_min_pq; + uint16_t source_max_pq; + uint16_t source_diagonal; +} AVDOVIColorMetadata; + +typedef struct AVDOVIDmLevel1 { + /* Per-frame brightness metadata */ + uint16_t min_pq; + uint16_t max_pq; + uint16_t avg_pq; +} AVDOVIDmLevel1; + +typedef struct AVDOVIDmLevel2 { + /* Usually derived from level 8 (at different levels) */ + uint16_t target_max_pq; + uint16_t trim_slope; + uint16_t trim_offset; + uint16_t trim_power; + uint16_t trim_chroma_weight; + uint16_t trim_saturation_gain; + int16_t ms_weight; +} AVDOVIDmLevel2; + +typedef struct AVDOVIDmLevel3 { + uint16_t min_pq_offset; + uint16_t max_pq_offset; + uint16_t avg_pq_offset; +} AVDOVIDmLevel3; + +typedef struct AVDOVIDmLevel4 { + uint16_t anchor_pq; + uint16_t anchor_power; +} AVDOVIDmLevel4; + +typedef struct AVDOVIDmLevel5 { + /* Active area definition */ + uint16_t left_offset; + uint16_t right_offset; + uint16_t top_offset; + uint16_t bottom_offset; +} AVDOVIDmLevel5; + +typedef struct AVDOVIDmLevel6 { + /* Static HDR10 metadata */ + uint16_t max_luminance; + uint16_t min_luminance; + uint16_t max_cll; + uint16_t max_fall; +} AVDOVIDmLevel6; + +typedef struct AVDOVIDmLevel8 { + /* Extended version of level 2 */ + uint8_t target_display_index; + uint16_t trim_slope; + uint16_t trim_offset; + uint16_t trim_power; + uint16_t trim_chroma_weight; + uint16_t trim_saturation_gain; + uint16_t ms_weight; + uint16_t target_mid_contrast; + uint16_t clip_trim; + uint8_t saturation_vector_field[6]; + uint8_t hue_vector_field[6]; +} AVDOVIDmLevel8; + +typedef struct AVDOVIDmLevel9 { + /* Source display characteristics */ + uint8_t source_primary_index; + AVColorPrimariesDesc source_display_primaries; +} AVDOVIDmLevel9; + +typedef struct AVDOVIDmLevel10 { + /* Target display characteristics */ + uint8_t target_display_index; + uint16_t target_max_pq; + uint16_t target_min_pq; + uint8_t target_primary_index; + AVColorPrimariesDesc target_display_primaries; +} AVDOVIDmLevel10; + +typedef struct AVDOVIDmLevel11 { + uint8_t content_type; + uint8_t whitepoint; + uint8_t reference_mode_flag; +#if FF_API_DOVI_L11_INVALID_PROPS + attribute_deprecated + uint8_t sharpness; + attribute_deprecated + uint8_t noise_reduction; + attribute_deprecated + uint8_t mpeg_noise_reduction; + attribute_deprecated + uint8_t frame_rate_conversion; + attribute_deprecated + uint8_t brightness; + attribute_deprecated + uint8_t color; +#endif +} AVDOVIDmLevel11; + +typedef struct AVDOVIDmLevel254 { + /* DMv2 info block, always present in samples with DMv2 metadata */ + uint8_t dm_mode; + uint8_t dm_version_index; +} AVDOVIDmLevel254; + +typedef struct AVDOVIDmLevel255 { + /* Debug block, not really used in samples */ + uint8_t dm_run_mode; + uint8_t dm_run_version; + uint8_t dm_debug[4]; +} AVDOVIDmLevel255; + +/** + * Dolby Vision metadata extension block. Dynamic extension blocks may change + * from frame to frame, while static blocks are constant throughout the entire + * sequence. + * + * @note sizeof(AVDOVIDmData) is not part of the public API. + */ +typedef struct AVDOVIDmData { + uint8_t level; /* [1, 255] */ + union { + AVDOVIDmLevel1 l1; /* dynamic */ + AVDOVIDmLevel2 l2; /* dynamic, may appear multiple times */ + AVDOVIDmLevel3 l3; /* dynamic */ + AVDOVIDmLevel4 l4; /* dynamic */ + AVDOVIDmLevel5 l5; /* dynamic */ + AVDOVIDmLevel6 l6; /* static */ + /* level 7 is currently unused */ + AVDOVIDmLevel8 l8; /* dynamic, may appear multiple times */ + AVDOVIDmLevel9 l9; /* dynamic */ + AVDOVIDmLevel10 l10; /* static, may appear multiple times */ + AVDOVIDmLevel11 l11; /* dynamic */ + AVDOVIDmLevel254 l254; /* static */ + AVDOVIDmLevel255 l255; /* static */ + }; +} AVDOVIDmData; + +/** + * Combined struct representing a combination of header, mapping and color + * metadata, for attaching to frames as side data. + * + * @note The struct must be allocated with av_dovi_metadata_alloc() and + * its size is not a part of the public ABI. + */ + +typedef struct AVDOVIMetadata { + /** + * Offset in bytes from the beginning of this structure at which the + * respective structs start. + */ + size_t header_offset; /* AVDOVIRpuDataHeader */ + size_t mapping_offset; /* AVDOVIDataMapping */ + size_t color_offset; /* AVDOVIColorMetadata */ + + size_t ext_block_offset; /* offset to start of ext blocks array */ + size_t ext_block_size; /* size per element */ + int num_ext_blocks; /* number of extension blocks */ + + /* static limit on num_ext_blocks, derived from bitstream limitations */ +#define AV_DOVI_MAX_EXT_BLOCKS 32 +} AVDOVIMetadata; + +static av_always_inline AVDOVIRpuDataHeader * +av_dovi_get_header(const AVDOVIMetadata *data) +{ + return (AVDOVIRpuDataHeader *)((uint8_t *) data + data->header_offset); +} + +static av_always_inline AVDOVIDataMapping * +av_dovi_get_mapping(const AVDOVIMetadata *data) +{ + return (AVDOVIDataMapping *)((uint8_t *) data + data->mapping_offset); +} + +static av_always_inline AVDOVIColorMetadata * +av_dovi_get_color(const AVDOVIMetadata *data) +{ + return (AVDOVIColorMetadata *)((uint8_t *) data + data->color_offset); +} + +/** + * Gets the specified Dolby Vision Display Management (DM) metadata + * @param index must be non negative and below data->num_ext_blocks + */ +static av_always_inline AVDOVIDmData * +av_dovi_get_ext(const AVDOVIMetadata *data, int index) +{ + return (AVDOVIDmData *)((uint8_t *) data + data->ext_block_offset + + data->ext_block_size * index); +} + +/** + * Find an extension block with a given level, or NULL. In the case of + * multiple extension blocks, only the first is returned. + */ +AVDOVIDmData *av_dovi_find_level(const AVDOVIMetadata *data, uint8_t level); + +/** + * Allocate an AVDOVIMetadata structure and initialize its + * fields to default values. + * + * @param size If this parameter is non-NULL, the size in bytes of the + * allocated struct will be written here on success + * + * @return the newly allocated struct or NULL on failure + */ +AVDOVIMetadata *av_dovi_metadata_alloc(size_t *size); + +#endif /* AVUTIL_DOVI_META_H */ diff --git a/libs/ffmpeg/libavutil/downmix_info.c b/libs/ffmpeg/libavutil/downmix_info.c new file mode 100644 index 00000000000..7e6c3e854d3 --- /dev/null +++ b/libs/ffmpeg/libavutil/downmix_info.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014 Tim Walker <tdskywalker@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "downmix_info.h" +#include "frame.h" + +AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame) +{ + AVFrameSideData *side_data; + + side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_DOWNMIX_INFO); + + if (!side_data) { + side_data = av_frame_new_side_data(frame, AV_FRAME_DATA_DOWNMIX_INFO, + sizeof(AVDownmixInfo)); + if (side_data) + memset(side_data->data, 0, sizeof(AVDownmixInfo)); + } + + if (!side_data) + return NULL; + + return (AVDownmixInfo*)side_data->data; +} diff --git a/libs/ffmpeg/libavutil/downmix_info.h b/libs/ffmpeg/libavutil/downmix_info.h new file mode 100644 index 00000000000..221cf5bf9ba --- /dev/null +++ b/libs/ffmpeg/libavutil/downmix_info.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014 Tim Walker <tdskywalker@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DOWNMIX_INFO_H +#define AVUTIL_DOWNMIX_INFO_H + +#include "frame.h" + +/** + * @file + * audio downmix medatata + */ + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * @defgroup downmix_info Audio downmix metadata + * @{ + */ + +/** + * Possible downmix types. + */ +enum AVDownmixType { + AV_DOWNMIX_TYPE_UNKNOWN, /**< Not indicated. */ + AV_DOWNMIX_TYPE_LORO, /**< Lo/Ro 2-channel downmix (Stereo). */ + AV_DOWNMIX_TYPE_LTRT, /**< Lt/Rt 2-channel downmix, Dolby Surround compatible. */ + AV_DOWNMIX_TYPE_DPLII, /**< Lt/Rt 2-channel downmix, Dolby Pro Logic II compatible. */ + AV_DOWNMIX_TYPE_NB /**< Number of downmix types. Not part of ABI. */ +}; + +/** + * This structure describes optional metadata relevant to a downmix procedure. + * + * All fields are set by the decoder to the value indicated in the audio + * bitstream (if present), or to a "sane" default otherwise. + */ +typedef struct AVDownmixInfo { + /** + * Type of downmix preferred by the mastering engineer. + */ + enum AVDownmixType preferred_downmix_type; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during a regular downmix. + */ + double center_mix_level; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during an Lt/Rt compatible downmix. + */ + double center_mix_level_ltrt; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during a regular downmix. + */ + double surround_mix_level; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during an Lt/Rt compatible downmix. + */ + double surround_mix_level_ltrt; + + /** + * Absolute scale factor representing the level at which the LFE data is + * mixed into L/R channels during downmixing. + */ + double lfe_mix_level; +} AVDownmixInfo; + +/** + * Get a frame's AV_FRAME_DATA_DOWNMIX_INFO side data for editing. + * + * If the side data is absent, it is created and added to the frame. + * + * @param frame the frame for which the side data is to be obtained or created + * + * @return the AVDownmixInfo structure to be edited by the caller, or NULL if + * the structure cannot be allocated. + */ +AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame); + +/** + * @} + */ + +/** + * @} + */ + +#endif /* AVUTIL_DOWNMIX_INFO_H */ diff --git a/libs/ffmpeg/libavutil/dynarray.h b/libs/ffmpeg/libavutil/dynarray.h new file mode 100644 index 00000000000..3a7e146422a --- /dev/null +++ b/libs/ffmpeg/libavutil/dynarray.h @@ -0,0 +1,70 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DYNARRAY_H +#define AVUTIL_DYNARRAY_H + +#include "log.h" +#include "mem.h" + +/** + * Add an element to a dynamic array. + * + * The array is reallocated when its number of elements reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the size is incremented. + * + * @param av_size_max maximum size of the array, usually the MAX macro of + * the type of the size + * @param av_elt_size size of the elements in the array, in bytes + * @param av_array pointer to the array, must be a lvalue + * @param av_size size of the array, must be an integer lvalue + * @param av_success statement to execute on success; at this point, the + * size variable is not yet incremented + * @param av_failure statement to execute on failure; if this happens, the + * array and size are not changed; the statement can end + * with a return or a goto + */ +#define FF_DYNARRAY_ADD(av_size_max, av_elt_size, av_array, av_size, \ + av_success, av_failure) \ + do { \ + size_t av_size_new = (av_size); \ + if (!((av_size) & ((av_size) - 1))) { \ + av_size_new = (av_size) ? (av_size) << 1 : 1; \ + if (av_size_new > (av_size_max) / (av_elt_size)) { \ + av_size_new = 0; \ + } else { \ + void *av_array_new = \ + av_realloc((av_array), av_size_new * (av_elt_size)); \ + if (!av_array_new) \ + av_size_new = 0; \ + else \ + (av_array) = av_array_new; \ + } \ + } \ + if (av_size_new) { \ + { av_success } \ + (av_size)++; \ + } else { \ + av_failure \ + } \ + } while (0) + +#endif /* AVUTIL_DYNARRAY_H */ diff --git a/libs/ffmpeg/libavutil/emms.h b/libs/ffmpeg/libavutil/emms.h new file mode 100644 index 00000000000..2b9a456223d --- /dev/null +++ b/libs/ffmpeg/libavutil/emms.h @@ -0,0 +1,102 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_EMMS_H +#define AVUTIL_EMMS_H + +#include <stdint.h> +#include <stdlib.h> + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/log.h" + +#if ARCH_X86 + +void avpriv_emms_asm(void); + +#if HAVE_MMX_INLINE +#ifndef __MMX__ +#include "libavutil/cpu.h" +#endif + +# define emms_c emms_c +/** + * Empty mmx state. + * this must be called between any dsp function and float/double code. + * for example sin(); dsp->idct_put(); emms_c(); cos() + * Note, *alloc() and *free() also use float code in some libc implementations + * thus this also applies to them or any function using them. + */ +static av_always_inline void emms_c(void) +{ +/* Some inlined functions may also use mmx instructions regardless of + * runtime cpuflags. With that in mind, we unconditionally empty the + * mmx state if the target cpu chosen at configure time supports it. + */ +#if !defined(__MMX__) + if(av_get_cpu_flags() & AV_CPU_FLAG_MMX) +#endif + __asm__ volatile ("emms" ::: "memory"); +} + +static inline void ff_assert0_fpu(const char *file, int line_number) +{ + uint16_t state[14]; + __asm__ volatile ( + "fstenv %0 \n\t" + : "+m" (state) + : + : "memory" + ); + if ((state[4] & 3) != 3) { + emms_c(); + av_log(NULL, AV_LOG_PANIC, + "Invalid floating point state assertion " + "triggered at line %u in file %s\n", + line_number, file); + abort(); + } +} + +#define ff_assert0_fpu() ff_assert0_fpu(__FILE__, __LINE__) + +#elif HAVE_MMX && HAVE_MM_EMPTY +# include <mmintrin.h> +# define emms_c _mm_empty +#elif HAVE_MMX_EXTERNAL +# define emms_c avpriv_emms_asm +#endif /* HAVE_MMX_INLINE */ + +#endif /* ARCH_X86 */ + +#ifndef emms_c +# define emms_c() do {} while(0) +#endif + +#ifndef ff_assert0_fpu +#define ff_assert0_fpu() ((void)0) +#endif + +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 1 +#define ff_assert1_fpu() ff_assert0_fpu() +#else +#define ff_assert1_fpu() ((void)0) +#endif + +#endif /* AVUTIL_EMMS_H */ diff --git a/libs/ffmpeg/libavutil/encryption_info.c b/libs/ffmpeg/libavutil/encryption_info.c new file mode 100644 index 00000000000..e4ff015b371 --- /dev/null +++ b/libs/ffmpeg/libavutil/encryption_info.c @@ -0,0 +1,343 @@ +/** + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> + +#include "encryption_info.h" +#include "mem.h" +#include "intreadwrite.h" + +#define FF_ENCRYPTION_INFO_EXTRA 24 + +// The format of the AVEncryptionInfo side data: +// u32be scheme +// u32be crypt_byte_block +// u32be skip_byte_block +// u32be key_id_size +// u32be iv_size +// u32be subsample_count +// u8[key_id_size] key_id +// u8[iv_size] iv +// { +// u32be bytes_of_clear_data +// u32be bytes_of_protected_data +// }[subsample_count] + +AVEncryptionInfo *av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size) +{ + AVEncryptionInfo *info; + + info = av_mallocz(sizeof(*info)); + if (!info) + return NULL; + + info->key_id = av_mallocz(key_id_size); + info->key_id_size = key_id_size; + info->iv = av_mallocz(iv_size); + info->iv_size = iv_size; + info->subsamples = av_calloc(subsample_count, sizeof(*info->subsamples)); + info->subsample_count = subsample_count; + + // Allow info->subsamples to be NULL if there are no subsamples. + if (!info->key_id || !info->iv || (!info->subsamples && subsample_count)) { + av_encryption_info_free(info); + return NULL; + } + + return info; +} + +AVEncryptionInfo *av_encryption_info_clone(const AVEncryptionInfo *info) +{ + AVEncryptionInfo *ret; + + ret = av_encryption_info_alloc(info->subsample_count, info->key_id_size, info->iv_size); + if (!ret) + return NULL; + + ret->scheme = info->scheme; + ret->crypt_byte_block = info->crypt_byte_block; + ret->skip_byte_block = info->skip_byte_block; + memcpy(ret->iv, info->iv, info->iv_size); + memcpy(ret->key_id, info->key_id, info->key_id_size); + memcpy(ret->subsamples, info->subsamples, sizeof(*info->subsamples) * info->subsample_count); + return ret; +} + +void av_encryption_info_free(AVEncryptionInfo *info) +{ + if (info) { + av_free(info->key_id); + av_free(info->iv); + av_free(info->subsamples); + av_free(info); + } +} + +AVEncryptionInfo *av_encryption_info_get_side_data(const uint8_t* buffer, size_t size) +{ + AVEncryptionInfo *info; + uint64_t key_id_size, iv_size, subsample_count, i; + + if (!buffer || size < FF_ENCRYPTION_INFO_EXTRA) + return NULL; + + key_id_size = AV_RB32(buffer + 12); + iv_size = AV_RB32(buffer + 16); + subsample_count = AV_RB32(buffer + 20); + + if (size < FF_ENCRYPTION_INFO_EXTRA + key_id_size + iv_size + subsample_count * 8) + return NULL; + + info = av_encryption_info_alloc(subsample_count, key_id_size, iv_size); + if (!info) + return NULL; + + info->scheme = AV_RB32(buffer); + info->crypt_byte_block = AV_RB32(buffer + 4); + info->skip_byte_block = AV_RB32(buffer + 8); + memcpy(info->key_id, buffer + 24, key_id_size); + memcpy(info->iv, buffer + key_id_size + 24, iv_size); + + buffer += key_id_size + iv_size + 24; + for (i = 0; i < subsample_count; i++) { + info->subsamples[i].bytes_of_clear_data = AV_RB32(buffer); + info->subsamples[i].bytes_of_protected_data = AV_RB32(buffer + 4); + buffer += 8; + } + + return info; +} + +uint8_t *av_encryption_info_add_side_data(const AVEncryptionInfo *info, size_t *size) +{ + uint8_t *buffer, *cur_buffer; + uint32_t i; + + if (UINT32_MAX - FF_ENCRYPTION_INFO_EXTRA < info->key_id_size || + UINT32_MAX - FF_ENCRYPTION_INFO_EXTRA - info->key_id_size < info->iv_size || + (UINT32_MAX - FF_ENCRYPTION_INFO_EXTRA - info->key_id_size - info->iv_size) / 8 < info->subsample_count) { + return NULL; + } + + *size = FF_ENCRYPTION_INFO_EXTRA + info->key_id_size + info->iv_size + + (info->subsample_count * 8); + cur_buffer = buffer = av_malloc(*size); + if (!buffer) + return NULL; + + AV_WB32(cur_buffer, info->scheme); + AV_WB32(cur_buffer + 4, info->crypt_byte_block); + AV_WB32(cur_buffer + 8, info->skip_byte_block); + AV_WB32(cur_buffer + 12, info->key_id_size); + AV_WB32(cur_buffer + 16, info->iv_size); + AV_WB32(cur_buffer + 20, info->subsample_count); + cur_buffer += 24; + memcpy(cur_buffer, info->key_id, info->key_id_size); + cur_buffer += info->key_id_size; + memcpy(cur_buffer, info->iv, info->iv_size); + cur_buffer += info->iv_size; + for (i = 0; i < info->subsample_count; i++) { + AV_WB32(cur_buffer, info->subsamples[i].bytes_of_clear_data); + AV_WB32(cur_buffer + 4, info->subsamples[i].bytes_of_protected_data); + cur_buffer += 8; + } + + return buffer; +} + +// The format of the AVEncryptionInitInfo side data: +// u32be init_info_count +// { +// u32be system_id_size +// u32be num_key_ids +// u32be key_id_size +// u32be data_size +// u8[system_id_size] system_id +// u8[key_id_size][num_key_id] key_ids +// u8[data_size] data +// }[init_info_count] + +#define FF_ENCRYPTION_INIT_INFO_EXTRA 16 + +AVEncryptionInitInfo *av_encryption_init_info_alloc( + uint32_t system_id_size, uint32_t num_key_ids, uint32_t key_id_size, uint32_t data_size) +{ + AVEncryptionInitInfo *info; + uint32_t i; + + info = av_mallocz(sizeof(*info)); + if (!info) + return NULL; + + info->system_id = av_mallocz(system_id_size); + info->system_id_size = system_id_size; + info->key_ids = key_id_size ? av_calloc(num_key_ids, sizeof(*info->key_ids)) : NULL; + info->num_key_ids = num_key_ids; + info->key_id_size = key_id_size; + info->data = av_mallocz(data_size); + info->data_size = data_size; + + // Allow pointers to be NULL if the size is 0. + if ((!info->system_id && system_id_size) || (!info->data && data_size) || + (!info->key_ids && num_key_ids && key_id_size)) { + av_encryption_init_info_free(info); + return NULL; + } + + if (key_id_size) { + for (i = 0; i < num_key_ids; i++) { + info->key_ids[i] = av_mallocz(key_id_size); + if (!info->key_ids[i]) { + av_encryption_init_info_free(info); + return NULL; + } + } + } + + return info; +} + +void av_encryption_init_info_free(AVEncryptionInitInfo *info) +{ + uint32_t i; + if (info) { + for (i = 0; i < info->num_key_ids; i++) { + av_free(info->key_ids[i]); + } + av_encryption_init_info_free(info->next); + av_free(info->system_id); + av_free(info->key_ids); + av_free(info->data); + av_free(info); + } +} + +AVEncryptionInitInfo *av_encryption_init_info_get_side_data( + const uint8_t *side_data, size_t side_data_size) +{ + // |ret| tracks the front of the list, |info| tracks the back. + AVEncryptionInitInfo *ret = NULL, *info, *temp_info; + uint64_t system_id_size, num_key_ids, key_id_size, data_size, i, j; + uint64_t init_info_count; + + if (!side_data || side_data_size < 4) + return NULL; + + init_info_count = AV_RB32(side_data); + side_data += 4; + side_data_size -= 4; + for (i = 0; i < init_info_count; i++) { + if (side_data_size < FF_ENCRYPTION_INIT_INFO_EXTRA) { + av_encryption_init_info_free(ret); + return NULL; + } + + system_id_size = AV_RB32(side_data); + num_key_ids = AV_RB32(side_data + 4); + key_id_size = AV_RB32(side_data + 8); + data_size = AV_RB32(side_data + 12); + + // UINT32_MAX + UINT32_MAX + UINT32_MAX * UINT32_MAX == UINT64_MAX + if (side_data_size - FF_ENCRYPTION_INIT_INFO_EXTRA < system_id_size + data_size + num_key_ids * key_id_size) { + av_encryption_init_info_free(ret); + return NULL; + } + side_data += FF_ENCRYPTION_INIT_INFO_EXTRA; + side_data_size -= FF_ENCRYPTION_INIT_INFO_EXTRA; + + temp_info = av_encryption_init_info_alloc(system_id_size, num_key_ids, key_id_size, data_size); + if (!temp_info) { + av_encryption_init_info_free(ret); + return NULL; + } + if (i == 0) { + info = ret = temp_info; + } else { + info->next = temp_info; + info = temp_info; + } + + memcpy(info->system_id, side_data, system_id_size); + side_data += system_id_size; + side_data_size -= system_id_size; + for (j = 0; j < num_key_ids; j++) { + memcpy(info->key_ids[j], side_data, key_id_size); + side_data += key_id_size; + side_data_size -= key_id_size; + } + memcpy(info->data, side_data, data_size); + side_data += data_size; + side_data_size -= data_size; + } + + return ret; +} + +uint8_t *av_encryption_init_info_add_side_data(const AVEncryptionInitInfo *info, size_t *side_data_size) +{ + const AVEncryptionInitInfo *cur_info; + uint8_t *buffer, *cur_buffer; + uint32_t i, init_info_count; + uint64_t temp_side_data_size; + + temp_side_data_size = 4; + init_info_count = 0; + for (cur_info = info; cur_info; cur_info = cur_info->next) { + temp_side_data_size += (uint64_t)FF_ENCRYPTION_INIT_INFO_EXTRA + cur_info->system_id_size + cur_info->data_size; + if (init_info_count == UINT32_MAX || temp_side_data_size > UINT32_MAX) { + return NULL; + } + init_info_count++; + + if (cur_info->num_key_ids) { + temp_side_data_size += (uint64_t)cur_info->num_key_ids * cur_info->key_id_size; + if (temp_side_data_size > UINT32_MAX) { + return NULL; + } + } + } + *side_data_size = temp_side_data_size; + + cur_buffer = buffer = av_malloc(*side_data_size); + if (!buffer) + return NULL; + + AV_WB32(cur_buffer, init_info_count); + cur_buffer += 4; + for (cur_info = info; cur_info; cur_info = cur_info->next) { + AV_WB32(cur_buffer, cur_info->system_id_size); + AV_WB32(cur_buffer + 4, cur_info->num_key_ids); + AV_WB32(cur_buffer + 8, cur_info->key_id_size); + AV_WB32(cur_buffer + 12, cur_info->data_size); + cur_buffer += 16; + + memcpy(cur_buffer, cur_info->system_id, cur_info->system_id_size); + cur_buffer += cur_info->system_id_size; + for (i = 0; i < cur_info->num_key_ids; i++) { + memcpy(cur_buffer, cur_info->key_ids[i], cur_info->key_id_size); + cur_buffer += cur_info->key_id_size; + } + if (cur_info->data_size > 0) { + memcpy(cur_buffer, cur_info->data, cur_info->data_size); + cur_buffer += cur_info->data_size; + } + } + + return buffer; +} diff --git a/libs/ffmpeg/libavutil/encryption_info.h b/libs/ffmpeg/libavutil/encryption_info.h new file mode 100644 index 00000000000..8fe7ebfe432 --- /dev/null +++ b/libs/ffmpeg/libavutil/encryption_info.h @@ -0,0 +1,205 @@ +/** + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ENCRYPTION_INFO_H +#define AVUTIL_ENCRYPTION_INFO_H + +#include <stddef.h> +#include <stdint.h> + +typedef struct AVSubsampleEncryptionInfo { + /** The number of bytes that are clear. */ + unsigned int bytes_of_clear_data; + + /** + * The number of bytes that are protected. If using pattern encryption, + * the pattern applies to only the protected bytes; if not using pattern + * encryption, all these bytes are encrypted. + */ + unsigned int bytes_of_protected_data; +} AVSubsampleEncryptionInfo; + +/** + * This describes encryption info for a packet. This contains frame-specific + * info for how to decrypt the packet before passing it to the decoder. + * + * The size of this struct is not part of the public ABI. + */ +typedef struct AVEncryptionInfo { + /** The fourcc encryption scheme, in big-endian byte order. */ + uint32_t scheme; + + /** + * Only used for pattern encryption. This is the number of 16-byte blocks + * that are encrypted. + */ + uint32_t crypt_byte_block; + + /** + * Only used for pattern encryption. This is the number of 16-byte blocks + * that are clear. + */ + uint32_t skip_byte_block; + + /** + * The ID of the key used to encrypt the packet. This should always be + * 16 bytes long, but may be changed in the future. + */ + uint8_t *key_id; + uint32_t key_id_size; + + /** + * The initialization vector. This may have been zero-filled to be the + * correct block size. This should always be 16 bytes long, but may be + * changed in the future. + */ + uint8_t *iv; + uint32_t iv_size; + + /** + * An array of subsample encryption info specifying how parts of the sample + * are encrypted. If there are no subsamples, then the whole sample is + * encrypted. + */ + AVSubsampleEncryptionInfo *subsamples; + uint32_t subsample_count; +} AVEncryptionInfo; + +/** + * This describes info used to initialize an encryption key system. + * + * The size of this struct is not part of the public ABI. + */ +typedef struct AVEncryptionInitInfo { + /** + * A unique identifier for the key system this is for, can be NULL if it + * is not known. This should always be 16 bytes, but may change in the + * future. + */ + uint8_t* system_id; + uint32_t system_id_size; + + /** + * An array of key IDs this initialization data is for. All IDs are the + * same length. Can be NULL if there are no known key IDs. + */ + uint8_t** key_ids; + /** The number of key IDs. */ + uint32_t num_key_ids; + /** + * The number of bytes in each key ID. This should always be 16, but may + * change in the future. + */ + uint32_t key_id_size; + + /** + * Key-system specific initialization data. This data is copied directly + * from the file and the format depends on the specific key system. This + * can be NULL if there is no initialization data; in that case, there + * will be at least one key ID. + */ + uint8_t* data; + uint32_t data_size; + + /** + * An optional pointer to the next initialization info in the list. + */ + struct AVEncryptionInitInfo *next; +} AVEncryptionInitInfo; + +/** + * Allocates an AVEncryptionInfo structure and sub-pointers to hold the given + * number of subsamples. This will allocate pointers for the key ID, IV, + * and subsample entries, set the size members, and zero-initialize the rest. + * + * @param subsample_count The number of subsamples. + * @param key_id_size The number of bytes in the key ID, should be 16. + * @param iv_size The number of bytes in the IV, should be 16. + * + * @return The new AVEncryptionInfo structure, or NULL on error. + */ +AVEncryptionInfo *av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size); + +/** + * Allocates an AVEncryptionInfo structure with a copy of the given data. + * @return The new AVEncryptionInfo structure, or NULL on error. + */ +AVEncryptionInfo *av_encryption_info_clone(const AVEncryptionInfo *info); + +/** + * Frees the given encryption info object. This MUST NOT be used to free the + * side-data data pointer, that should use normal side-data methods. + */ +void av_encryption_info_free(AVEncryptionInfo *info); + +/** + * Creates a copy of the AVEncryptionInfo that is contained in the given side + * data. The resulting object should be passed to av_encryption_info_free() + * when done. + * + * @return The new AVEncryptionInfo structure, or NULL on error. + */ +AVEncryptionInfo *av_encryption_info_get_side_data(const uint8_t *side_data, size_t side_data_size); + +/** + * Allocates and initializes side data that holds a copy of the given encryption + * info. The resulting pointer should be either freed using av_free or given + * to av_packet_add_side_data(). + * + * @return The new side-data pointer, or NULL. + */ +uint8_t *av_encryption_info_add_side_data( + const AVEncryptionInfo *info, size_t *side_data_size); + + +/** + * Allocates an AVEncryptionInitInfo structure and sub-pointers to hold the + * given sizes. This will allocate pointers and set all the fields. + * + * @return The new AVEncryptionInitInfo structure, or NULL on error. + */ +AVEncryptionInitInfo *av_encryption_init_info_alloc( + uint32_t system_id_size, uint32_t num_key_ids, uint32_t key_id_size, uint32_t data_size); + +/** + * Frees the given encryption init info object. This MUST NOT be used to free + * the side-data data pointer, that should use normal side-data methods. + */ +void av_encryption_init_info_free(AVEncryptionInitInfo* info); + +/** + * Creates a copy of the AVEncryptionInitInfo that is contained in the given + * side data. The resulting object should be passed to + * av_encryption_init_info_free() when done. + * + * @return The new AVEncryptionInitInfo structure, or NULL on error. + */ +AVEncryptionInitInfo *av_encryption_init_info_get_side_data( + const uint8_t* side_data, size_t side_data_size); + +/** + * Allocates and initializes side data that holds a copy of the given encryption + * init info. The resulting pointer should be either freed using av_free or + * given to av_packet_add_side_data(). + * + * @return The new side-data pointer, or NULL. + */ +uint8_t *av_encryption_init_info_add_side_data( + const AVEncryptionInitInfo *info, size_t *side_data_size); + +#endif /* AVUTIL_ENCRYPTION_INFO_H */ diff --git a/libs/ffmpeg/libavutil/error.c b/libs/ffmpeg/libavutil/error.c new file mode 100644 index 00000000000..2c9f0028bd2 --- /dev/null +++ b/libs/ffmpeg/libavutil/error.c @@ -0,0 +1,151 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#undef _GNU_SOURCE +#define _XOPEN_SOURCE 600 /* XSI-compliant version of strerror_r */ +#include <stdio.h> +#include <string.h> +#include "config.h" +#include "avstring.h" +#include "error.h" +#include "macros.h" + +#define AVERROR_INPUT_AND_OUTPUT_CHANGED (AVERROR_INPUT_CHANGED | AVERROR_OUTPUT_CHANGED) + +#define AVERROR_LIST(E, E2) \ + E(BSF_NOT_FOUND, "Bitstream filter not found") \ + E(BUG, "Internal bug, should not have happened") \ + E2(BUG2, BUG, "Internal bug, should not have happened") \ + E(BUFFER_TOO_SMALL, "Buffer too small") \ + E(DECODER_NOT_FOUND, "Decoder not found") \ + E(DEMUXER_NOT_FOUND, "Demuxer not found") \ + E(ENCODER_NOT_FOUND, "Encoder not found") \ + E(EOF, "End of file") \ + E(EXIT, "Immediate exit requested") \ + E(EXTERNAL, "Generic error in an external library") \ + E(FILTER_NOT_FOUND, "Filter not found") \ + E(INPUT_CHANGED, "Input changed") \ + E(INVALIDDATA, "Invalid data found when processing input") \ + E(MUXER_NOT_FOUND, "Muxer not found") \ + E(OPTION_NOT_FOUND, "Option not found") \ + E(OUTPUT_CHANGED, "Output changed") \ + E(PATCHWELCOME, "Not yet implemented in FFmpeg, patches welcome") \ + E(PROTOCOL_NOT_FOUND, "Protocol not found") \ + E(STREAM_NOT_FOUND, "Stream not found") \ + E(UNKNOWN, "Unknown error occurred") \ + E(EXPERIMENTAL, "Experimental feature") \ + E(INPUT_AND_OUTPUT_CHANGED, "Input and output changed") \ + E(HTTP_BAD_REQUEST, "Server returned 400 Bad Request") \ + E(HTTP_UNAUTHORIZED, "Server returned 401 Unauthorized (authorization failed)") \ + E(HTTP_FORBIDDEN, "Server returned 403 Forbidden (access denied)") \ + E(HTTP_NOT_FOUND, "Server returned 404 Not Found") \ + E(HTTP_TOO_MANY_REQUESTS, "Server returned 429 Too Many Requests") \ + E(HTTP_OTHER_4XX, "Server returned 4XX Client Error, but not one of 40{0,1,3,4}") \ + E(HTTP_SERVER_ERROR, "Server returned 5XX Server Error reply") \ + +#define STRERROR_LIST(E) \ + E(E2BIG, "Argument list too long") \ + E(EACCES, "Permission denied") \ + E(EAGAIN, "Resource temporarily unavailable") \ + E(EBADF, "Bad file descriptor") \ + E(EBUSY, "Device or resource busy") \ + E(ECHILD, "No child processes") \ + E(EDEADLK, "Resource deadlock avoided") \ + E(EDOM, "Numerical argument out of domain") \ + E(EEXIST, "File exists") \ + E(EFAULT, "Bad address") \ + E(EFBIG, "File too large") \ + E(EILSEQ, "Illegal byte sequence") \ + E(EINTR, "Interrupted system call") \ + E(EINVAL, "Invalid argument") \ + E(EIO, "I/O error") \ + E(EISDIR, "Is a directory") \ + E(EMFILE, "Too many open files") \ + E(EMLINK, "Too many links") \ + E(ENAMETOOLONG, "File name too long") \ + E(ENFILE, "Too many open files in system") \ + E(ENODEV, "No such device") \ + E(ENOENT, "No such file or directory") \ + E(ENOEXEC, "Exec format error") \ + E(ENOLCK, "No locks available") \ + E(ENOMEM, "Cannot allocate memory") \ + E(ENOSPC, "No space left on device") \ + E(ENOSYS, "Function not implemented") \ + E(ENOTDIR, "Not a directory") \ + E(ENOTEMPTY, "Directory not empty") \ + E(ENOTTY, "Inappropriate I/O control operation") \ + E(ENXIO, "No such device or address") \ + E(EPERM, "Operation not permitted") \ + E(EPIPE, "Broken pipe") \ + E(ERANGE, "Result too large") \ + E(EROFS, "Read-only file system") \ + E(ESPIPE, "Illegal seek") \ + E(ESRCH, "No such process") \ + E(EXDEV, "Cross-device link") \ + +enum { +#define OFFSET(CODE, DESC) \ + ERROR_ ## CODE ## _OFFSET, \ + ERROR_ ## CODE ## _END_OFFSET = ERROR_ ## CODE ## _OFFSET + sizeof(DESC) - 1, +#define NOTHING(CODE, CODE2, DESC) + AVERROR_LIST(OFFSET, NOTHING) +#if !HAVE_STRERROR_R + STRERROR_LIST(OFFSET) +#endif +}; + +#define STRING(CODE, DESC) DESC "\0" +static const char error_stringtable[] = + AVERROR_LIST(STRING, NOTHING) +#if !HAVE_STRERROR_R + STRERROR_LIST(STRING) +#endif +; + +static const struct ErrorEntry { + int num; + unsigned offset; +} error_entries[] = { +#define ENTRY(CODE, DESC) { .num = AVERROR_ ## CODE, .offset = ERROR_ ## CODE ## _OFFSET }, +#define ENTRY2(CODE, CODE2, DESC) { .num = AVERROR_ ## CODE, .offset = ERROR_ ## CODE2 ## _OFFSET }, + AVERROR_LIST(ENTRY, ENTRY2) +#if !HAVE_STRERROR_R +#undef ENTRY +#define ENTRY(CODE, DESC) { .num = AVERROR(CODE), .offset = ERROR_ ## CODE ## _OFFSET }, + STRERROR_LIST(ENTRY) +#endif +}; + +int av_strerror(int errnum, char *errbuf, size_t errbuf_size) +{ + for (size_t i = 0; i < FF_ARRAY_ELEMS(error_entries); ++i) { + if (errnum == error_entries[i].num) { + av_strlcpy(errbuf, error_stringtable + error_entries[i].offset, errbuf_size); + return 0; + } + } +#if HAVE_STRERROR_R + int ret = AVERROR(strerror_r(AVUNERROR((unsigned)errnum), errbuf, errbuf_size)); +#else + int ret = -1; +#endif + if (ret < 0) + snprintf(errbuf, errbuf_size, "Error number %d occurred", errnum); + + return ret; +} diff --git a/libs/ffmpeg/libavutil/error.h b/libs/ffmpeg/libavutil/error.h new file mode 100644 index 00000000000..1efa86c4c10 --- /dev/null +++ b/libs/ffmpeg/libavutil/error.h @@ -0,0 +1,129 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * error code definitions + */ + +#ifndef AVUTIL_ERROR_H +#define AVUTIL_ERROR_H + +#include <errno.h> +#include <stddef.h> + +#include "macros.h" + +/** + * @addtogroup lavu_error + * + * @{ + */ + + +/* error handling */ +#if EDOM > 0 +#define AVERROR(e) (-(e)) ///< Returns a negative error code from a POSIX error code, to return from library functions. +#define AVUNERROR(e) (-(e)) ///< Returns a POSIX error code from a library function error return value. +#else +/* Some platforms have E* and errno already negated. */ +#define AVERROR(e) (e) +#define AVUNERROR(e) (e) +#endif + +#define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d)) + +#define AVERROR_BSF_NOT_FOUND FFERRTAG(0xF8,'B','S','F') ///< Bitstream filter not found +#define AVERROR_BUG FFERRTAG( 'B','U','G','!') ///< Internal bug, also see AVERROR_BUG2 +#define AVERROR_BUFFER_TOO_SMALL FFERRTAG( 'B','U','F','S') ///< Buffer too small +#define AVERROR_DECODER_NOT_FOUND FFERRTAG(0xF8,'D','E','C') ///< Decoder not found +#define AVERROR_DEMUXER_NOT_FOUND FFERRTAG(0xF8,'D','E','M') ///< Demuxer not found +#define AVERROR_ENCODER_NOT_FOUND FFERRTAG(0xF8,'E','N','C') ///< Encoder not found +#define AVERROR_EOF FFERRTAG( 'E','O','F',' ') ///< End of file +#define AVERROR_EXIT FFERRTAG( 'E','X','I','T') ///< Immediate exit was requested; the called function should not be restarted +#define AVERROR_EXTERNAL FFERRTAG( 'E','X','T',' ') ///< Generic error in an external library +#define AVERROR_FILTER_NOT_FOUND FFERRTAG(0xF8,'F','I','L') ///< Filter not found +#define AVERROR_INVALIDDATA FFERRTAG( 'I','N','D','A') ///< Invalid data found when processing input +#define AVERROR_MUXER_NOT_FOUND FFERRTAG(0xF8,'M','U','X') ///< Muxer not found +#define AVERROR_OPTION_NOT_FOUND FFERRTAG(0xF8,'O','P','T') ///< Option not found +#define AVERROR_PATCHWELCOME FFERRTAG( 'P','A','W','E') ///< Not yet implemented in FFmpeg, patches welcome +#define AVERROR_PROTOCOL_NOT_FOUND FFERRTAG(0xF8,'P','R','O') ///< Protocol not found + +#define AVERROR_STREAM_NOT_FOUND FFERRTAG(0xF8,'S','T','R') ///< Stream not found +/** + * This is semantically identical to AVERROR_BUG + * it has been introduced in Libav after our AVERROR_BUG and with a modified value. + */ +#define AVERROR_BUG2 FFERRTAG( 'B','U','G',' ') +#define AVERROR_UNKNOWN FFERRTAG( 'U','N','K','N') ///< Unknown error, typically from an external library +#define AVERROR_EXPERIMENTAL (-0x2bb2afa8) ///< Requested feature is flagged experimental. Set strict_std_compliance if you really want to use it. +#define AVERROR_INPUT_CHANGED (-0x636e6701) ///< Input changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_OUTPUT_CHANGED) +#define AVERROR_OUTPUT_CHANGED (-0x636e6702) ///< Output changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_INPUT_CHANGED) +/* HTTP & RTSP errors */ +#define AVERROR_HTTP_BAD_REQUEST FFERRTAG(0xF8,'4','0','0') +#define AVERROR_HTTP_UNAUTHORIZED FFERRTAG(0xF8,'4','0','1') +#define AVERROR_HTTP_FORBIDDEN FFERRTAG(0xF8,'4','0','3') +#define AVERROR_HTTP_NOT_FOUND FFERRTAG(0xF8,'4','0','4') +#define AVERROR_HTTP_TOO_MANY_REQUESTS FFERRTAG(0xF8,'4','2','9') +#define AVERROR_HTTP_OTHER_4XX FFERRTAG(0xF8,'4','X','X') +#define AVERROR_HTTP_SERVER_ERROR FFERRTAG(0xF8,'5','X','X') + +#define AV_ERROR_MAX_STRING_SIZE 64 + +/** + * Put a description of the AVERROR code errnum in errbuf. + * In case of failure the global variable errno is set to indicate the + * error. Even in case of failure av_strerror() will print a generic + * error message indicating the errnum provided to errbuf. + * + * @param errnum error code to describe + * @param errbuf buffer to which description is written + * @param errbuf_size the size in bytes of errbuf + * @return 0 on success, a negative value if a description for errnum + * cannot be found + */ +int av_strerror(int errnum, char *errbuf, size_t errbuf_size); + +/** + * Fill the provided buffer with a string containing an error string + * corresponding to the AVERROR code errnum. + * + * @param errbuf a buffer + * @param errbuf_size size in bytes of errbuf + * @param errnum error code to describe + * @return the buffer in input, filled with the error description + * @see av_strerror() + */ +static inline char *av_make_error_string(char *errbuf, size_t errbuf_size, int errnum) +{ + av_strerror(errnum, errbuf, errbuf_size); + return errbuf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_err2str(errnum) \ + av_make_error_string((char[AV_ERROR_MAX_STRING_SIZE]){0}, AV_ERROR_MAX_STRING_SIZE, errnum) + +/** + * @} + */ + +#endif /* AVUTIL_ERROR_H */ diff --git a/libs/ffmpeg/libavutil/eval.c b/libs/ffmpeg/libavutil/eval.c new file mode 100644 index 00000000000..56123a3831e --- /dev/null +++ b/libs/ffmpeg/libavutil/eval.c @@ -0,0 +1,855 @@ +/* + * Copyright (c) 2002-2006 Michael Niedermayer <michaelni@gmx.at> + * Copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple arithmetic expression evaluator. + * + * see http://joe.hotchkiss.com/programming/eval/eval.html + */ + +#include <float.h> +#include "attributes.h" +#include "avassert.h" +#include "avutil.h" +#include "common.h" +#include "eval.h" +#include "ffmath.h" +#include "log.h" +#include "mathematics.h" +#include "mem.h" +#include "sfc64.h" +#include "time.h" +#include "avstring.h" +#include "reverse.h" + +#define MAX_DEPTH 100 + +typedef struct Parser { + const AVClass *class; + int stack_index; + char *s; + const double *const_values; + const char * const *const_names; // NULL terminated + double (* const *funcs1)(void *, double a); // NULL terminated + const char * const *func1_names; // NULL terminated + double (* const *funcs2)(void *, double a, double b); // NULL terminated + const char * const *func2_names; // NULL terminated + void *opaque; + int log_offset; + void *log_ctx; +#define VARS 10 + double *var; + FFSFC64 *prng_state; +} Parser; + +static const AVClass eval_class = { + .class_name = "Eval", + .item_name = av_default_item_name, + .option = NULL, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = offsetof(Parser, log_offset), + .parent_log_context_offset = offsetof(Parser, log_ctx), +}; + +static const struct { + double bin_val; + double dec_val; + int8_t exp; +} si_prefixes['z' - 'E' + 1] = { + ['y'-'E']= { 8.271806125530276749e-25, 1e-24, -24 }, + ['z'-'E']= { 8.4703294725430034e-22, 1e-21, -21 }, + ['a'-'E']= { 8.6736173798840355e-19, 1e-18, -18 }, + ['f'-'E']= { 8.8817841970012523e-16, 1e-15, -15 }, + ['p'-'E']= { 9.0949470177292824e-13, 1e-12, -12 }, + ['n'-'E']= { 9.3132257461547852e-10, 1e-9, -9 }, + ['u'-'E']= { 9.5367431640625e-7, 1e-6, -6 }, + ['m'-'E']= { 9.765625e-4, 1e-3, -3 }, + ['c'-'E']= { 9.8431332023036951e-3, 1e-2, -2 }, + ['d'-'E']= { 9.921256574801246e-2, 1e-1, -1 }, + ['h'-'E']= { 1.0159366732596479e2, 1e2, 2 }, + ['k'-'E']= { 1.024e3, 1e3, 3 }, + ['K'-'E']= { 1.024e3, 1e3, 3 }, + ['M'-'E']= { 1.048576e6, 1e6, 6 }, + ['G'-'E']= { 1.073741824e9, 1e9, 9 }, + ['T'-'E']= { 1.099511627776e12, 1e12, 12 }, + ['P'-'E']= { 1.125899906842624e15, 1e15, 15 }, + ['E'-'E']= { 1.152921504606847e18, 1e18, 18 }, + ['Z'-'E']= { 1.1805916207174113e21, 1e21, 21 }, + ['Y'-'E']= { 1.2089258196146292e24, 1e24, 24 }, +}; + +static const struct { + const char *name; + double value; +} constants[] = { + { "E", M_E }, + { "PI", M_PI }, + { "PHI", M_PHI }, + { "QP2LAMBDA", FF_QP2LAMBDA }, +}; + +double av_strtod(const char *numstr, char **tail) +{ + double d; + char *next; + if(numstr[0]=='0' && (numstr[1]|0x20)=='x') { + d = strtoul(numstr, &next, 16); + } else + d = strtod(numstr, &next); + /* if parsing succeeded, check for and interpret postfixes */ + if (next!=numstr) { + if (next[0] == 'd' && next[1] == 'B') { + /* treat dB as decibels instead of decibytes */ + d = ff_exp10(d / 20); + next += 2; + } else if (*next >= 'E' && *next <= 'z') { + int e= si_prefixes[*next - 'E'].exp; + if (e) { + if (next[1] == 'i') { + d*= si_prefixes[*next - 'E'].bin_val; + next+=2; + } else { + d*= si_prefixes[*next - 'E'].dec_val; + next++; + } + } + } + + if (*next=='B') { + d*=8; + next++; + } + } + /* if requested, fill in tail with the position after the last parsed + character */ + if (tail) + *tail = next; + return d; +} + +#define IS_IDENTIFIER_CHAR(c) ((c) - '0' <= 9U || (c) - 'a' <= 25U || (c) - 'A' <= 25U || (c) == '_') + +static int strmatch(const char *s, const char *prefix) +{ + int i; + for (i=0; prefix[i]; i++) { + if (prefix[i] != s[i]) return 0; + } + /* return 1 only if the s identifier is terminated */ + return !IS_IDENTIFIER_CHAR(s[i]); +} + +enum { + e_value, e_const, e_func0, e_func1, e_func2, + e_squish, e_gauss, e_ld, e_isnan, e_isinf, + e_mod, e_max, e_min, e_eq, e_gt, e_gte, e_lte, e_lt, + e_pow, e_mul, e_div, e_add, + e_last, e_st, e_while, e_taylor, e_root, e_floor, e_ceil, e_trunc, e_round, + e_sqrt, e_not, e_random, e_hypot, e_gcd, + e_if, e_ifnot, e_print, e_bitand, e_bitor, e_between, e_clip, e_atan2, e_lerp, + e_sgn, e_randomi +}; +struct AVExpr { + unsigned char type; + unsigned char root; + short depth; + int const_index; + double value; // is sign in other types + union { + double (*func0)(double); + double (*func1)(void *, double); + double (*func2)(void *, double, double); + } ; + struct AVExpr *param[3]; +}; + +typedef struct { + AVExpr avexpr; + double *var; + FFSFC64 *prng_state; +} AVExprRoot; + +static double etime(double v) +{ + return av_gettime() * 0.000001; +} + +static double eval_expr(Parser *p, AVExpr *e) +{ + switch (e->type) { + case e_value: return e->value; + case e_const: return e->value * p->const_values[e->const_index]; + case e_func0: return e->value * e->func0(eval_expr(p, e->param[0])); + case e_func1: return e->value * e->func1(p->opaque, eval_expr(p, e->param[0])); + case e_func2: return e->value * e->func2(p->opaque, eval_expr(p, e->param[0]), eval_expr(p, e->param[1])); + case e_squish: return 1/(1+exp(4*eval_expr(p, e->param[0]))); + case e_gauss: { double d = eval_expr(p, e->param[0]); return exp(-d*d/2)/sqrt(2*M_PI); } + case e_ld: return e->value * p->var[av_clip(eval_expr(p, e->param[0]), 0, VARS-1)]; + case e_isnan: return e->value * !!isnan(eval_expr(p, e->param[0])); + case e_isinf: return e->value * !!isinf(eval_expr(p, e->param[0])); + case e_floor: return e->value * floor(eval_expr(p, e->param[0])); + case e_ceil : return e->value * ceil (eval_expr(p, e->param[0])); + case e_trunc: return e->value * trunc(eval_expr(p, e->param[0])); + case e_round: return e->value * round(eval_expr(p, e->param[0])); + case e_sgn: return e->value * FFDIFFSIGN(eval_expr(p, e->param[0]), 0); + case e_sqrt: return e->value * sqrt (eval_expr(p, e->param[0])); + case e_not: return e->value * (eval_expr(p, e->param[0]) == 0); + case e_if: return e->value * (eval_expr(p, e->param[0]) ? eval_expr(p, e->param[1]) : + e->param[2] ? eval_expr(p, e->param[2]) : 0); + case e_ifnot: return e->value * (!eval_expr(p, e->param[0]) ? eval_expr(p, e->param[1]) : + e->param[2] ? eval_expr(p, e->param[2]) : 0); + case e_clip: { + double x = eval_expr(p, e->param[0]); + double min = eval_expr(p, e->param[1]), max = eval_expr(p, e->param[2]); + if (isnan(min) || isnan(max) || isnan(x) || min > max) + return NAN; + return e->value * av_clipd(eval_expr(p, e->param[0]), min, max); + } + case e_between: { + double d = eval_expr(p, e->param[0]); + return e->value * (d >= eval_expr(p, e->param[1]) && + d <= eval_expr(p, e->param[2])); + } + case e_lerp: { + double v0 = eval_expr(p, e->param[0]); + double v1 = eval_expr(p, e->param[1]); + double f = eval_expr(p, e->param[2]); + return v0 + (v1 - v0) * f; + } + case e_print: { + double x = eval_expr(p, e->param[0]); + int level = e->param[1] ? av_clip(eval_expr(p, e->param[1]), INT_MIN, INT_MAX) : AV_LOG_INFO; + av_log(p, level, "%f\n", x); + return x; + } + +#define COMPUTE_NEXT_RANDOM() \ + int idx = av_clip(eval_expr(p, e->param[0]), 0, VARS-1); \ + FFSFC64 *s = p->prng_state + idx; \ + uint64_t r; \ + \ + if (!s->counter) { \ + r = isnan(p->var[idx]) ? 0 : p->var[idx]; \ + ff_sfc64_init(s, r, r, r, 12); \ + } \ + r = ff_sfc64_get(s); \ + p->var[idx] = r; \ + + case e_random: { + COMPUTE_NEXT_RANDOM(); + return r * (1.0/UINT64_MAX); + } + case e_randomi: { + double min = eval_expr(p, e->param[1]); + double max = eval_expr(p, e->param[2]); + COMPUTE_NEXT_RANDOM(); + return min + (max - min) * r / UINT64_MAX; + } + case e_while: { + double d = NAN; + while (eval_expr(p, e->param[0])) + d=eval_expr(p, e->param[1]); + return d; + } + case e_taylor: { + double t = 1, d = 0, v; + double x = eval_expr(p, e->param[1]); + int id = e->param[2] ? av_clip(eval_expr(p, e->param[2]), 0, VARS-1) : 0; + int i; + double var0 = p->var[id]; + for(i=0; i<1000; i++) { + double ld = d; + p->var[id] = i; + v = eval_expr(p, e->param[0]); + d += t*v; + if(ld==d && v) + break; + t *= x / (i+1); + } + p->var[id] = var0; + return d; + } + case e_root: { + int i, j; + double low = -1, high = -1, v, low_v = -DBL_MAX, high_v = DBL_MAX; + double var0 = p->var[0]; + double x_max = eval_expr(p, e->param[1]); + for(i=-1; i<1024; i++) { + if(i<255) { + p->var[0] = ff_reverse[i&255]*x_max/255; + } else { + p->var[0] = x_max*pow(0.9, i-255); + if (i&1) p->var[0] *= -1; + if (i&2) p->var[0] += low; + else p->var[0] += high; + } + v = eval_expr(p, e->param[0]); + if (v<=0 && v>low_v) { + low = p->var[0]; + low_v = v; + } + if (v>=0 && v<high_v) { + high = p->var[0]; + high_v = v; + } + if (low>=0 && high>=0){ + for (j=0; j<1000; j++) { + p->var[0] = (low+high)*0.5; + if (low == p->var[0] || high == p->var[0]) + break; + v = eval_expr(p, e->param[0]); + if (v<=0) low = p->var[0]; + if (v>=0) high= p->var[0]; + if (isnan(v)) { + low = high = v; + break; + } + } + break; + } + } + p->var[0] = var0; + return -low_v<high_v ? low : high; + } + default: { + double d = eval_expr(p, e->param[0]); + double d2 = eval_expr(p, e->param[1]); + switch (e->type) { + case e_mod: return e->value * (d - floor(d2 ? d / d2 : d * INFINITY) * d2); + case e_gcd: return e->value * av_gcd(d,d2); + case e_max: return e->value * (d > d2 ? d : d2); + case e_min: return e->value * (d < d2 ? d : d2); + case e_eq: return e->value * (d == d2 ? 1.0 : 0.0); + case e_gt: return e->value * (d > d2 ? 1.0 : 0.0); + case e_gte: return e->value * (d >= d2 ? 1.0 : 0.0); + case e_lt: return e->value * (d < d2 ? 1.0 : 0.0); + case e_lte: return e->value * (d <= d2 ? 1.0 : 0.0); + case e_pow: return e->value * pow(d, d2); + case e_mul: return e->value * (d * d2); + case e_div: return e->value * (d2 ? (d / d2) : d * INFINITY); + case e_add: return e->value * (d + d2); + case e_last:return e->value * d2; + case e_st : { + int index = av_clip(d, 0, VARS-1); + p->prng_state[index].counter = 0; + return e->value * (p->var[index]= d2); + } + case e_hypot:return e->value * hypot(d, d2); + case e_atan2:return e->value * atan2(d, d2); + case e_bitand: return isnan(d) || isnan(d2) ? NAN : e->value * ((long int)d & (long int)d2); + case e_bitor: return isnan(d) || isnan(d2) ? NAN : e->value * ((long int)d | (long int)d2); + } + } + } + return NAN; +} + +static int parse_expr(AVExpr **e, Parser *p); + +void av_expr_free(AVExpr *e) +{ + if (!e) return; + av_expr_free(e->param[0]); + av_expr_free(e->param[1]); + av_expr_free(e->param[2]); + if (e->root) { + AVExprRoot *r = (AVExprRoot*)e; + av_freep(&r->var); + av_freep(&r->prng_state); + } + av_freep(&e); +} + +static int parse_primary(AVExpr **e, Parser *p) +{ + AVExpr *d = av_mallocz(sizeof(AVExpr)); + char *next = p->s, *s0 = p->s; + int ret, i; + + if (!d) + return AVERROR(ENOMEM); + + /* number */ + d->value = av_strtod(p->s, &next); + if (next != p->s) { + d->type = e_value; + p->s= next; + *e = d; + return 0; + } + d->value = 1; + + /* named constants */ + for (i=0; p->const_names && p->const_names[i]; i++) { + if (strmatch(p->s, p->const_names[i])) { + p->s+= strlen(p->const_names[i]); + d->type = e_const; + d->const_index = i; + *e = d; + return 0; + } + } + for (i = 0; i < FF_ARRAY_ELEMS(constants); i++) { + if (strmatch(p->s, constants[i].name)) { + p->s += strlen(constants[i].name); + d->type = e_value; + d->value = constants[i].value; + *e = d; + return 0; + } + } + + p->s= strchr(p->s, '('); + if (!p->s) { + av_log(p, AV_LOG_ERROR, "Undefined constant or missing '(' in '%s'\n", s0); + p->s= next; + av_expr_free(d); + return AVERROR(EINVAL); + } + p->s++; // "(" + if (*next == '(') { // special case do-nothing + av_freep(&d); + if ((ret = parse_expr(&d, p)) < 0) + return ret; + if (p->s[0] != ')') { + av_log(p, AV_LOG_ERROR, "Missing ')' in '%s'\n", s0); + av_expr_free(d); + return AVERROR(EINVAL); + } + p->s++; // ")" + *e = d; + return 0; + } + if ((ret = parse_expr(&(d->param[0]), p)) < 0) { + av_expr_free(d); + return ret; + } + if (p->s[0]== ',') { + p->s++; // "," + parse_expr(&d->param[1], p); + } + if (p->s[0]== ',') { + p->s++; // "," + parse_expr(&d->param[2], p); + } + if (p->s[0] != ')') { + av_log(p, AV_LOG_ERROR, "Missing ')' or too many args in '%s'\n", s0); + av_expr_free(d); + return AVERROR(EINVAL); + } + p->s++; // ")" + + for (int i = 0; i<3; i++) + if (d->param[i]) + d->depth = FFMAX(d->depth, d->param[i]->depth+1); + if (d->depth > MAX_DEPTH) { + av_expr_free(d); + return AVERROR(EINVAL); + } + + d->type = e_func0; + if (strmatch(next, "sinh" )) d->func0 = sinh; + else if (strmatch(next, "cosh" )) d->func0 = cosh; + else if (strmatch(next, "tanh" )) d->func0 = tanh; + else if (strmatch(next, "sin" )) d->func0 = sin; + else if (strmatch(next, "cos" )) d->func0 = cos; + else if (strmatch(next, "tan" )) d->func0 = tan; + else if (strmatch(next, "atan" )) d->func0 = atan; + else if (strmatch(next, "asin" )) d->func0 = asin; + else if (strmatch(next, "acos" )) d->func0 = acos; + else if (strmatch(next, "exp" )) d->func0 = exp; + else if (strmatch(next, "log" )) d->func0 = log; + else if (strmatch(next, "abs" )) d->func0 = fabs; + else if (strmatch(next, "time" )) d->func0 = etime; + else if (strmatch(next, "squish")) d->type = e_squish; + else if (strmatch(next, "gauss" )) d->type = e_gauss; + else if (strmatch(next, "mod" )) d->type = e_mod; + else if (strmatch(next, "max" )) d->type = e_max; + else if (strmatch(next, "min" )) d->type = e_min; + else if (strmatch(next, "eq" )) d->type = e_eq; + else if (strmatch(next, "gte" )) d->type = e_gte; + else if (strmatch(next, "gt" )) d->type = e_gt; + else if (strmatch(next, "lte" )) d->type = e_lte; + else if (strmatch(next, "lt" )) d->type = e_lt; + else if (strmatch(next, "ld" )) d->type = e_ld; + else if (strmatch(next, "isnan" )) d->type = e_isnan; + else if (strmatch(next, "isinf" )) d->type = e_isinf; + else if (strmatch(next, "st" )) d->type = e_st; + else if (strmatch(next, "while" )) d->type = e_while; + else if (strmatch(next, "taylor")) d->type = e_taylor; + else if (strmatch(next, "root" )) d->type = e_root; + else if (strmatch(next, "floor" )) d->type = e_floor; + else if (strmatch(next, "ceil" )) d->type = e_ceil; + else if (strmatch(next, "trunc" )) d->type = e_trunc; + else if (strmatch(next, "round" )) d->type = e_round; + else if (strmatch(next, "sqrt" )) d->type = e_sqrt; + else if (strmatch(next, "not" )) d->type = e_not; + else if (strmatch(next, "pow" )) d->type = e_pow; + else if (strmatch(next, "print" )) d->type = e_print; + else if (strmatch(next, "random")) d->type = e_random; + else if (strmatch(next, "randomi")) d->type = e_randomi; + else if (strmatch(next, "hypot" )) d->type = e_hypot; + else if (strmatch(next, "gcd" )) d->type = e_gcd; + else if (strmatch(next, "if" )) d->type = e_if; + else if (strmatch(next, "ifnot" )) d->type = e_ifnot; + else if (strmatch(next, "bitand")) d->type = e_bitand; + else if (strmatch(next, "bitor" )) d->type = e_bitor; + else if (strmatch(next, "between"))d->type = e_between; + else if (strmatch(next, "clip" )) d->type = e_clip; + else if (strmatch(next, "atan2" )) d->type = e_atan2; + else if (strmatch(next, "lerp" )) d->type = e_lerp; + else if (strmatch(next, "sgn" )) d->type = e_sgn; + else { + for (i=0; p->func1_names && p->func1_names[i]; i++) { + if (strmatch(next, p->func1_names[i])) { + d->func1 = p->funcs1[i]; + d->type = e_func1; + d->const_index = i; + *e = d; + return 0; + } + } + + for (i=0; p->func2_names && p->func2_names[i]; i++) { + if (strmatch(next, p->func2_names[i])) { + d->func2 = p->funcs2[i]; + d->type = e_func2; + d->const_index = i; + *e = d; + return 0; + } + } + + av_log(p, AV_LOG_ERROR, "Unknown function in '%s'\n", s0); + av_expr_free(d); + return AVERROR(EINVAL); + } + + *e = d; + return 0; +} + +static AVExpr *make_eval_expr(int type, int value, AVExpr *p0, AVExpr *p1) +{ + int depth = FFMAX(p0->depth, p1->depth) + 1; + if (depth > MAX_DEPTH) + return NULL; + AVExpr *e = av_mallocz(sizeof(AVExpr)); + if (!e) + return NULL; + e->type =type ; + e->value =value ; + e->param[0] =p0 ; + e->param[1] =p1 ; + e->depth = depth; + return e; +} + +static int parse_pow(AVExpr **e, Parser *p, int *sign) +{ + *sign= (*p->s == '+') - (*p->s == '-'); + p->s += *sign&1; + return parse_primary(e, p); +} + +static int parse_dB(AVExpr **e, Parser *p, int *sign) +{ + /* do not filter out the negative sign when parsing a dB value. + for example, -3dB is not the same as -(3dB) */ + if (*p->s == '-') { + char *next; + av_unused double ignored = strtod(p->s, &next); + if (next != p->s && next[0] == 'd' && next[1] == 'B') { + *sign = 0; + return parse_primary(e, p); + } + } + return parse_pow(e, p, sign); +} + +static int parse_factor(AVExpr **e, Parser *p) +{ + int sign, sign2, ret; + AVExpr *e0, *e1, *e2; + if ((ret = parse_dB(&e0, p, &sign)) < 0) + return ret; + while(p->s[0]=='^'){ + e1 = e0; + p->s++; + if ((ret = parse_dB(&e2, p, &sign2)) < 0) { + av_expr_free(e1); + return ret; + } + e0 = make_eval_expr(e_pow, 1, e1, e2); + if (!e0) { + av_expr_free(e1); + av_expr_free(e2); + return AVERROR(ENOMEM); + } + if (e0->param[1]) e0->param[1]->value *= (sign2|1); + } + if (e0) e0->value *= (sign|1); + + *e = e0; + return 0; +} + +static int parse_term(AVExpr **e, Parser *p) +{ + int ret; + AVExpr *e0, *e1, *e2; + if ((ret = parse_factor(&e0, p)) < 0) + return ret; + while (p->s[0]=='*' || p->s[0]=='/') { + int c= *p->s++; + e1 = e0; + if ((ret = parse_factor(&e2, p)) < 0) { + av_expr_free(e1); + return ret; + } + e0 = make_eval_expr(c == '*' ? e_mul : e_div, 1, e1, e2); + if (!e0) { + av_expr_free(e1); + av_expr_free(e2); + return AVERROR(ENOMEM); + } + } + *e = e0; + return 0; +} + +static int parse_subexpr(AVExpr **e, Parser *p) +{ + int ret; + AVExpr *e0, *e1, *e2; + if ((ret = parse_term(&e0, p)) < 0) + return ret; + while (*p->s == '+' || *p->s == '-') { + e1 = e0; + if ((ret = parse_term(&e2, p)) < 0) { + av_expr_free(e1); + return ret; + } + e0 = make_eval_expr(e_add, 1, e1, e2); + if (!e0) { + av_expr_free(e1); + av_expr_free(e2); + return AVERROR(ENOMEM); + } + }; + + *e = e0; + return 0; +} + +static int parse_expr(AVExpr **e, Parser *p) +{ + int ret; + AVExpr *e0, *e1, *e2; + if (p->stack_index <= 0) //protect against stack overflows + return AVERROR(EINVAL); + p->stack_index--; + + if ((ret = parse_subexpr(&e0, p)) < 0) + return ret; + while (*p->s == ';') { + p->s++; + e1 = e0; + if ((ret = parse_subexpr(&e2, p)) < 0) { + av_expr_free(e1); + return ret; + } + e0 = make_eval_expr(e_last, 1, e1, e2); + if (!e0) { + av_expr_free(e1); + av_expr_free(e2); + return AVERROR(ENOMEM); + } + }; + + p->stack_index++; + *e = e0; + return 0; +} + +static int verify_expr(AVExpr *e) +{ + if (!e) return 0; + switch (e->type) { + case e_value: + case e_const: return 1; + case e_func0: + case e_func1: + case e_squish: + case e_ld: + case e_gauss: + case e_isnan: + case e_isinf: + case e_floor: + case e_ceil: + case e_trunc: + case e_round: + case e_sqrt: + case e_not: + case e_random: + case e_sgn: + return verify_expr(e->param[0]) && !e->param[1]; + case e_print: + return verify_expr(e->param[0]) + && (!e->param[1] || verify_expr(e->param[1])); + case e_if: + case e_ifnot: + case e_taylor: + return verify_expr(e->param[0]) && verify_expr(e->param[1]) + && (!e->param[2] || verify_expr(e->param[2])); + case e_between: + case e_clip: + case e_lerp: + case e_randomi: + return verify_expr(e->param[0]) && + verify_expr(e->param[1]) && + verify_expr(e->param[2]); + default: return verify_expr(e->param[0]) && verify_expr(e->param[1]) && !e->param[2]; + } +} + +int av_expr_parse(AVExpr **expr, const char *s, + const char * const *const_names, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + int log_offset, void *log_ctx) +{ + Parser p = { 0 }; + AVExpr *e = NULL; + char *w = av_malloc(strlen(s) + 1); + char *wp = w; + const char *s0 = s; + int ret = 0; + + if (!w) + return AVERROR(ENOMEM); + + while (*s) + if (!av_isspace(*s++)) *wp++ = s[-1]; + *wp++ = 0; + + p.class = &eval_class; + p.stack_index=100; + p.s= w; + p.const_names = const_names; + p.funcs1 = funcs1; + p.func1_names = func1_names; + p.funcs2 = funcs2; + p.func2_names = func2_names; + p.log_offset = log_offset; + p.log_ctx = log_ctx; + + if ((ret = parse_expr(&e, &p)) < 0) + goto end; + if (*p.s) { + av_log(&p, AV_LOG_ERROR, "Invalid chars '%s' at the end of expression '%s'\n", p.s, s0); + ret = AVERROR(EINVAL); + goto end; + } + if (!verify_expr(e)) { + ret = AVERROR(EINVAL); + goto end; + } + AVExprRoot *r = av_realloc(e, sizeof(*r)); + if (!r) { + ret = AVERROR(ENOMEM); + goto end; + } + e = (AVExpr*)r; + e->root = 1; + r->var= av_mallocz(sizeof(double) *VARS); + r->prng_state = av_mallocz(sizeof(*r->prng_state) *VARS); + if (!r->var || !r->prng_state) { + ret = AVERROR(ENOMEM); + goto end; + } + *expr = e; + e = NULL; +end: + av_expr_free(e); + av_free(w); + return ret; +} + +static int expr_count(AVExpr *e, unsigned *counter, int size, int type) +{ + int i; + + if (!e || !counter || !size) + return AVERROR(EINVAL); + + for (i = 0; e->type != type && i < 3 && e->param[i]; i++) + expr_count(e->param[i], counter, size, type); + + if (e->type == type && e->const_index < size) + counter[e->const_index]++; + + return 0; +} + +int av_expr_count_vars(AVExpr *e, unsigned *counter, int size) +{ + return expr_count(e, counter, size, e_const); +} + +int av_expr_count_func(AVExpr *e, unsigned *counter, int size, int arg) +{ + return expr_count(e, counter, size, ((int[]){e_const, e_func1, e_func2})[arg]); +} + +double av_expr_eval(AVExpr *e, const double *const_values, void *opaque) +{ + av_assert1(e->root); + AVExprRoot *r = (AVExprRoot *)e; + Parser p = { + .class = &eval_class, + .const_values = const_values, + .opaque = opaque, + .var = r->var, + .prng_state = r->prng_state, + }; + + return eval_expr(&p, e); +} + +int av_expr_parse_and_eval(double *d, const char *s, + const char * const *const_names, const double *const_values, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + void *opaque, int log_offset, void *log_ctx) +{ + AVExpr *e = NULL; + int ret = av_expr_parse(&e, s, const_names, func1_names, funcs1, func2_names, funcs2, log_offset, log_ctx); + + if (ret < 0) { + *d = NAN; + return ret; + } + *d = av_expr_eval(e, const_values, opaque); + av_expr_free(e); + return isnan(*d) ? AVERROR(EINVAL) : 0; +} diff --git a/libs/ffmpeg/libavutil/eval.h b/libs/ffmpeg/libavutil/eval.h new file mode 100644 index 00000000000..0d3eaeb3fbc --- /dev/null +++ b/libs/ffmpeg/libavutil/eval.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple arithmetic expression evaluator + */ + +#ifndef AVUTIL_EVAL_H +#define AVUTIL_EVAL_H + +typedef struct AVExpr AVExpr; + +/** + * Parse and evaluate an expression. + * Note, this is significantly slower than av_expr_eval(). + * + * @param res a pointer to a double where is put the result value of + * the expression, or NAN in case of error + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param const_values a zero terminated array of values for the identifiers from const_names + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @param log_offset log level offset, can be used to silence error messages + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse_and_eval(double *res, const char *s, + const char * const *const_names, const double *const_values, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + void *opaque, int log_offset, void *log_ctx); + +/** + * Parse an expression. + * + * @param expr a pointer where is put an AVExpr containing the parsed + * value in case of successful parsing, or NULL otherwise. + * The pointed to AVExpr must be freed with av_expr_free() by the user + * when it is not needed anymore. + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param log_offset log level offset, can be used to silence error messages + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse(AVExpr **expr, const char *s, + const char * const *const_names, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + int log_offset, void *log_ctx); + +/** + * Evaluate a previously parsed expression. + * + * @param e the AVExpr to evaluate + * @param const_values a zero terminated array of values for the identifiers from av_expr_parse() const_names + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @return the value of the expression + */ +double av_expr_eval(AVExpr *e, const double *const_values, void *opaque); + +/** + * Track the presence of variables and their number of occurrences in a parsed expression + * + * @param e the AVExpr to track variables in + * @param counter a zero-initialized array where the count of each variable will be stored + * @param size size of array + * @return 0 on success, a negative value indicates that no expression or array was passed + * or size was zero + */ +int av_expr_count_vars(AVExpr *e, unsigned *counter, int size); + +/** + * Track the presence of user provided functions and their number of occurrences + * in a parsed expression. + * + * @param e the AVExpr to track user provided functions in + * @param counter a zero-initialized array where the count of each function will be stored + * if you passed 5 functions with 2 arguments to av_expr_parse() + * then for arg=2 this will use up to 5 entries. + * @param size size of array + * @param arg number of arguments the counted functions have + * @return 0 on success, a negative value indicates that no expression or array was passed + * or size was zero + */ +int av_expr_count_func(AVExpr *e, unsigned *counter, int size, int arg); + +/** + * Free a parsed expression previously created with av_expr_parse(). + */ +void av_expr_free(AVExpr *e); + +/** + * Parse the string in numstr and return its value as a double. If + * the string is empty, contains only whitespaces, or does not contain + * an initial substring that has the expected syntax for a + * floating-point number, no conversion is performed. In this case, + * returns a value of zero and the value returned in tail is the value + * of numstr. + * + * @param numstr a string representing a number, may contain one of + * the International System number postfixes, for example 'K', 'M', + * 'G'. If 'i' is appended after the postfix, powers of 2 are used + * instead of powers of 10. The 'B' postfix multiplies the value by + * 8, and can be appended after another postfix or used alone. This + * allows using for example 'KB', 'MiB', 'G' and 'B' as postfix. + * @param tail if non-NULL puts here the pointer to the char next + * after the last parsed character + */ +double av_strtod(const char *numstr, char **tail); + +#endif /* AVUTIL_EVAL_H */ diff --git a/libs/ffmpeg/libavutil/executor.c b/libs/ffmpeg/libavutil/executor.c new file mode 100644 index 00000000000..bfce2ac444c --- /dev/null +++ b/libs/ffmpeg/libavutil/executor.c @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2023 Nuo Mi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include <stdbool.h> + +#include "mem.h" +#include "thread.h" + +#include "executor.h" + +#if !HAVE_THREADS + +#define ExecutorThread char + +#define executor_thread_create(t, a, s, ar) 0 +#define executor_thread_join(t, r) do {} while(0) + +#else + +#define ExecutorThread pthread_t + +#define executor_thread_create(t, a, s, ar) pthread_create(t, a, s, ar) +#define executor_thread_join(t, r) pthread_join(t, r) + +#endif //!HAVE_THREADS + +typedef struct ThreadInfo { + AVExecutor *e; + ExecutorThread thread; +} ThreadInfo; + +struct AVExecutor { + AVTaskCallbacks cb; + int thread_count; + bool recursive; + + ThreadInfo *threads; + uint8_t *local_contexts; + + AVMutex lock; + AVCond cond; + int die; + + AVTask *tasks; +}; + +static AVTask* remove_task(AVTask **prev, AVTask *t) +{ + *prev = t->next; + t->next = NULL; + return t; +} + +static void add_task(AVTask **prev, AVTask *t) +{ + t->next = *prev; + *prev = t; +} + +static int run_one_task(AVExecutor *e, void *lc) +{ + AVTaskCallbacks *cb = &e->cb; + AVTask **prev; + + for (prev = &e->tasks; *prev && !cb->ready(*prev, cb->user_data); prev = &(*prev)->next) + /* nothing */; + if (*prev) { + AVTask *t = remove_task(prev, *prev); + if (e->thread_count > 0) + ff_mutex_unlock(&e->lock); + cb->run(t, lc, cb->user_data); + if (e->thread_count > 0) + ff_mutex_lock(&e->lock); + return 1; + } + return 0; +} + +#if HAVE_THREADS +static void *executor_worker_task(void *data) +{ + ThreadInfo *ti = (ThreadInfo*)data; + AVExecutor *e = ti->e; + void *lc = e->local_contexts + (ti - e->threads) * e->cb.local_context_size; + + ff_mutex_lock(&e->lock); + while (1) { + if (e->die) break; + + if (!run_one_task(e, lc)) { + //no task in one loop + ff_cond_wait(&e->cond, &e->lock); + } + } + ff_mutex_unlock(&e->lock); + return NULL; +} +#endif + +static void executor_free(AVExecutor *e, const int has_lock, const int has_cond) +{ + if (e->thread_count) { + //signal die + ff_mutex_lock(&e->lock); + e->die = 1; + ff_cond_broadcast(&e->cond); + ff_mutex_unlock(&e->lock); + + for (int i = 0; i < e->thread_count; i++) + executor_thread_join(e->threads[i].thread, NULL); + } + if (has_cond) + ff_cond_destroy(&e->cond); + if (has_lock) + ff_mutex_destroy(&e->lock); + + av_free(e->threads); + av_free(e->local_contexts); + + av_free(e); +} + +AVExecutor* av_executor_alloc(const AVTaskCallbacks *cb, int thread_count) +{ + AVExecutor *e; + int has_lock = 0, has_cond = 0; + if (!cb || !cb->user_data || !cb->ready || !cb->run || !cb->priority_higher) + return NULL; + + e = av_mallocz(sizeof(*e)); + if (!e) + return NULL; + e->cb = *cb; + + e->local_contexts = av_calloc(FFMAX(thread_count, 1), e->cb.local_context_size); + if (!e->local_contexts) + goto free_executor; + + e->threads = av_calloc(FFMAX(thread_count, 1), sizeof(*e->threads)); + if (!e->threads) + goto free_executor; + + if (!thread_count) + return e; + + has_lock = !ff_mutex_init(&e->lock, NULL); + has_cond = !ff_cond_init(&e->cond, NULL); + + if (!has_lock || !has_cond) + goto free_executor; + + for (/* nothing */; e->thread_count < thread_count; e->thread_count++) { + ThreadInfo *ti = e->threads + e->thread_count; + ti->e = e; + if (executor_thread_create(&ti->thread, NULL, executor_worker_task, ti)) + goto free_executor; + } + return e; + +free_executor: + executor_free(e, has_lock, has_cond); + return NULL; +} + +void av_executor_free(AVExecutor **executor) +{ + int thread_count; + + if (!executor || !*executor) + return; + thread_count = (*executor)->thread_count; + executor_free(*executor, thread_count, thread_count); + *executor = NULL; +} + +void av_executor_execute(AVExecutor *e, AVTask *t) +{ + AVTaskCallbacks *cb = &e->cb; + AVTask **prev; + + if (e->thread_count) + ff_mutex_lock(&e->lock); + if (t) { + for (prev = &e->tasks; *prev && cb->priority_higher(*prev, t); prev = &(*prev)->next) + /* nothing */; + add_task(prev, t); + } + if (e->thread_count) { + ff_cond_signal(&e->cond); + ff_mutex_unlock(&e->lock); + } + + if (!e->thread_count || !HAVE_THREADS) { + if (e->recursive) + return; + e->recursive = true; + // We are running in a single-threaded environment, so we must handle all tasks ourselves + while (run_one_task(e, e->local_contexts)) + /* nothing */; + e->recursive = false; + } +} diff --git a/libs/ffmpeg/libavutil/executor.h b/libs/ffmpeg/libavutil/executor.h new file mode 100644 index 00000000000..0eb21c10c87 --- /dev/null +++ b/libs/ffmpeg/libavutil/executor.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 Nuo Mi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_EXECUTOR_H +#define AVUTIL_EXECUTOR_H + +typedef struct AVExecutor AVExecutor; +typedef struct AVTask AVTask; + +struct AVTask { + AVTask *next; +}; + +typedef struct AVTaskCallbacks { + void *user_data; + + int local_context_size; + + // return 1 if a's priority > b's priority + int (*priority_higher)(const AVTask *a, const AVTask *b); + + // task is ready for run + int (*ready)(const AVTask *t, void *user_data); + + // run the task + int (*run)(AVTask *t, void *local_context, void *user_data); +} AVTaskCallbacks; + +/** + * Alloc executor + * @param callbacks callback structure for executor + * @param thread_count worker thread number, 0 for run on caller's thread directly + * @return return the executor + */ +AVExecutor* av_executor_alloc(const AVTaskCallbacks *callbacks, int thread_count); + +/** + * Free executor + * @param e pointer to executor + */ +void av_executor_free(AVExecutor **e); + +/** + * Add task to executor + * @param e pointer to executor + * @param t pointer to task. If NULL, it will wakeup one work thread + */ +void av_executor_execute(AVExecutor *e, AVTask *t); + +#endif //AVUTIL_EXECUTOR_H diff --git a/libs/ffmpeg/libavutil/ffmath.h b/libs/ffmpeg/libavutil/ffmath.h new file mode 100644 index 00000000000..aad1347f26d --- /dev/null +++ b/libs/ffmpeg/libavutil/ffmath.h @@ -0,0 +1,67 @@ +/* + * copyright (c) 2016 Ganesh Ajjanagadde <gajjanag@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * internal math functions header + */ + +#ifndef AVUTIL_FFMATH_H +#define AVUTIL_FFMATH_H + +#include "attributes.h" +#include "libm.h" + +/** + * Compute 10^x for floating point values. Note: this function is by no means + * "correctly rounded", and is meant as a fast, reasonably accurate approximation. + * For instance, maximum relative error for the double precision variant is + * ~ 1e-13 for very small and very large values. + * This is ~2x faster than GNU libm's approach, which is still off by 2ulp on + * some inputs. + * @param x exponent + * @return 10^x + */ +static av_always_inline double ff_exp10(double x) +{ + return exp2(M_LOG2_10 * x); +} + +static av_always_inline float ff_exp10f(float x) +{ + return exp2f(M_LOG2_10 * x); +} + +/** + * Compute x^y for floating point x, y. Note: this function is faster than the + * libm variant due to mainly 2 reasons: + * 1. It does not handle any edge cases. In particular, this is only guaranteed + * to work correctly for x > 0. + * 2. It is not as accurate as a standard nearly "correctly rounded" libm variant. + * @param x base + * @param y exponent + * @return x^y + */ +static av_always_inline float ff_fast_powf(float x, float y) +{ + return expf(logf(x) * y); +} + +#endif /* AVUTIL_FFMATH_H */ diff --git a/libs/ffmpeg/libavutil/ffversion.h b/libs/ffmpeg/libavutil/ffversion.h new file mode 100644 index 00000000000..c1a8d885e89 --- /dev/null +++ b/libs/ffmpeg/libavutil/ffversion.h @@ -0,0 +1,5 @@ +/* Automatically generated by version.sh, do not manually edit! */ +#ifndef AVUTIL_FFVERSION_H +#define AVUTIL_FFVERSION_H +#define FFMPEG_VERSION "8.1.1" +#endif /* AVUTIL_FFVERSION_H */ diff --git a/libs/ffmpeg/libavutil/fifo.c b/libs/ffmpeg/libavutil/fifo.c new file mode 100644 index 00000000000..8806c668d7e --- /dev/null +++ b/libs/ffmpeg/libavutil/fifo.c @@ -0,0 +1,292 @@ +/* + * a very simple circular buffer FIFO implementation + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * Copyright (c) 2006 Roman Shaposhnik + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdint.h> +#include <string.h> + +#include "avassert.h" +#include "error.h" +#include "fifo.h" +#include "macros.h" +#include "mem.h" + +// by default the FIFO can be auto-grown to 1MB +#define AUTO_GROW_DEFAULT_BYTES (1024 * 1024) + +struct AVFifo { + uint8_t *buffer; + + size_t elem_size, nb_elems; + size_t offset_r, offset_w; + // distinguishes the ambiguous situation offset_r == offset_w + int is_empty; + + unsigned int flags; + size_t auto_grow_limit; +}; + +AVFifo *av_fifo_alloc2(size_t nb_elems, size_t elem_size, + unsigned int flags) +{ + AVFifo *f; + void *buffer = NULL; + + if (!elem_size) + return NULL; + + if (nb_elems) { + buffer = av_realloc_array(NULL, nb_elems, elem_size); + if (!buffer) + return NULL; + } + f = av_mallocz(sizeof(*f)); + if (!f) { + av_free(buffer); + return NULL; + } + f->buffer = buffer; + f->nb_elems = nb_elems; + f->elem_size = elem_size; + f->is_empty = 1; + + f->flags = flags; + f->auto_grow_limit = FFMAX(AUTO_GROW_DEFAULT_BYTES / elem_size, 1); + + return f; +} + +void av_fifo_auto_grow_limit(AVFifo *f, size_t max_elems) +{ + f->auto_grow_limit = max_elems; +} + +size_t av_fifo_elem_size(const AVFifo *f) +{ + return f->elem_size; +} + +size_t av_fifo_can_read(const AVFifo *f) +{ + if (f->offset_w <= f->offset_r && !f->is_empty) + return f->nb_elems - f->offset_r + f->offset_w; + return f->offset_w - f->offset_r; +} + +size_t av_fifo_can_write(const AVFifo *f) +{ + return f->nb_elems - av_fifo_can_read(f); +} + +int av_fifo_grow2(AVFifo *f, size_t inc) +{ + uint8_t *tmp; + + if (inc > SIZE_MAX - f->nb_elems) + return AVERROR(EINVAL); + + tmp = av_realloc_array(f->buffer, f->nb_elems + inc, f->elem_size); + if (!tmp) + return AVERROR(ENOMEM); + f->buffer = tmp; + + // move the data from the beginning of the ring buffer + // to the newly allocated space + if (f->offset_w <= f->offset_r && !f->is_empty) { + const size_t copy = FFMIN(inc, f->offset_w); + memcpy(tmp + f->nb_elems * f->elem_size, tmp, copy * f->elem_size); + if (copy < f->offset_w) { + memmove(tmp, tmp + copy * f->elem_size, + (f->offset_w - copy) * f->elem_size); + f->offset_w -= copy; + } else + f->offset_w = copy == inc ? 0 : f->nb_elems + copy; + } + + f->nb_elems += inc; + + return 0; +} + +static int fifo_check_space(AVFifo *f, size_t to_write) +{ + const size_t can_write = av_fifo_can_write(f); + const size_t need_grow = to_write > can_write ? to_write - can_write : 0; + size_t can_grow; + + if (!need_grow) + return 0; + + can_grow = f->auto_grow_limit > f->nb_elems ? + f->auto_grow_limit - f->nb_elems : 0; + if ((f->flags & AV_FIFO_FLAG_AUTO_GROW) && need_grow <= can_grow) { + // allocate a bit more than necessary, if we can + const size_t inc = (need_grow < can_grow / 2 ) ? need_grow * 2 : can_grow; + return av_fifo_grow2(f, inc); + } + + return AVERROR(ENOSPC); +} + +static int fifo_write_common(AVFifo *f, const uint8_t *buf, size_t *nb_elems, + AVFifoCB read_cb, void *opaque) +{ + size_t to_write = *nb_elems; + size_t offset_w; + int ret = 0; + + ret = fifo_check_space(f, to_write); + if (ret < 0) + return ret; + + offset_w = f->offset_w; + + while (to_write > 0) { + size_t len = FFMIN(f->nb_elems - offset_w, to_write); + uint8_t *wptr = f->buffer + offset_w * f->elem_size; + + if (read_cb) { + ret = read_cb(opaque, wptr, &len); + if (ret < 0 || len == 0) + break; + } else { + memcpy(wptr, buf, len * f->elem_size); + buf += len * f->elem_size; + } + offset_w += len; + if (offset_w >= f->nb_elems) + offset_w = 0; + to_write -= len; + } + f->offset_w = offset_w; + + if (*nb_elems != to_write) + f->is_empty = 0; + *nb_elems -= to_write; + + return ret; +} + +int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems) +{ + return fifo_write_common(f, buf, &nb_elems, NULL, NULL); +} + +int av_fifo_write_from_cb(AVFifo *f, AVFifoCB read_cb, + void *opaque, size_t *nb_elems) +{ + return fifo_write_common(f, NULL, nb_elems, read_cb, opaque); +} + +static int fifo_peek_common(const AVFifo *f, uint8_t *buf, size_t *nb_elems, + size_t offset, AVFifoCB write_cb, void *opaque) +{ + size_t to_read = *nb_elems; + size_t offset_r = f->offset_r; + size_t can_read = av_fifo_can_read(f); + int ret = 0; + + if (offset > can_read || to_read > can_read - offset) { + *nb_elems = 0; + return AVERROR(EINVAL); + } + + if (offset_r >= f->nb_elems - offset) + offset_r -= f->nb_elems - offset; + else + offset_r += offset; + + while (to_read > 0) { + size_t len = FFMIN(f->nb_elems - offset_r, to_read); + uint8_t *rptr = f->buffer + offset_r * f->elem_size; + + if (write_cb) { + ret = write_cb(opaque, rptr, &len); + if (ret < 0 || len == 0) + break; + } else { + memcpy(buf, rptr, len * f->elem_size); + buf += len * f->elem_size; + } + offset_r += len; + if (offset_r >= f->nb_elems) + offset_r = 0; + to_read -= len; + } + + *nb_elems -= to_read; + + return ret; +} + +int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems) +{ + int ret = fifo_peek_common(f, buf, &nb_elems, 0, NULL, NULL); + av_fifo_drain2(f, nb_elems); + return ret; +} + +int av_fifo_read_to_cb(AVFifo *f, AVFifoCB write_cb, + void *opaque, size_t *nb_elems) +{ + int ret = fifo_peek_common(f, NULL, nb_elems, 0, write_cb, opaque); + av_fifo_drain2(f, *nb_elems); + return ret; +} + +int av_fifo_peek(const AVFifo *f, void *buf, size_t nb_elems, size_t offset) +{ + return fifo_peek_common(f, buf, &nb_elems, offset, NULL, NULL); +} + +int av_fifo_peek_to_cb(const AVFifo *f, AVFifoCB write_cb, void *opaque, + size_t *nb_elems, size_t offset) +{ + return fifo_peek_common(f, NULL, nb_elems, offset, write_cb, opaque); +} + +void av_fifo_drain2(AVFifo *f, size_t size) +{ + const size_t cur_size = av_fifo_can_read(f); + + av_assert0(cur_size >= size); + if (cur_size == size) + f->is_empty = 1; + + if (f->offset_r >= f->nb_elems - size) + f->offset_r -= f->nb_elems - size; + else + f->offset_r += size; +} + +void av_fifo_reset2(AVFifo *f) +{ + f->offset_r = f->offset_w = 0; + f->is_empty = 1; +} + +void av_fifo_freep2(AVFifo **f) +{ + if (*f) { + av_freep(&(*f)->buffer); + av_freep(f); + } +} diff --git a/libs/ffmpeg/libavutil/fifo.h b/libs/ffmpeg/libavutil/fifo.h new file mode 100644 index 00000000000..f2206c35f52 --- /dev/null +++ b/libs/ffmpeg/libavutil/fifo.h @@ -0,0 +1,242 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_fifo + * A generic FIFO API + */ + +#ifndef AVUTIL_FIFO_H +#define AVUTIL_FIFO_H + +#include <stddef.h> + +/** + * @defgroup lavu_fifo AVFifo + * @ingroup lavu_data + * + * @{ + * A generic FIFO API + */ + +typedef struct AVFifo AVFifo; + +/** + * Callback for writing or reading from a FIFO, passed to (and invoked from) the + * av_fifo_*_cb() functions. It may be invoked multiple times from a single + * av_fifo_*_cb() call and may process less data than the maximum size indicated + * by nb_elems. + * + * @param opaque the opaque pointer provided to the av_fifo_*_cb() function + * @param buf the buffer for reading or writing the data, depending on which + * av_fifo_*_cb function is called + * @param nb_elems On entry contains the maximum number of elements that can be + * read from / written into buf. On success, the callback should + * update it to contain the number of elements actually written. + * + * @return 0 on success, a negative error code on failure (will be returned from + * the invoking av_fifo_*_cb() function) + */ +typedef int AVFifoCB(void *opaque, void *buf, size_t *nb_elems); + +/** + * Automatically resize the FIFO on writes, so that the data fits. This + * automatic resizing happens up to a limit that can be modified with + * av_fifo_auto_grow_limit(). + */ +#define AV_FIFO_FLAG_AUTO_GROW (1 << 0) + +/** + * Allocate and initialize an AVFifo with a given element size. + * + * @param elems initial number of elements that can be stored in the FIFO + * @param elem_size Size in bytes of a single element. Further operations on + * the returned FIFO will implicitly use this element size. + * @param flags a combination of AV_FIFO_FLAG_* + * + * @return newly-allocated AVFifo on success, a negative error code on failure + */ +AVFifo *av_fifo_alloc2(size_t elems, size_t elem_size, + unsigned int flags); + +/** + * @return Element size for FIFO operations. This element size is set at + * FIFO allocation and remains constant during its lifetime + */ +size_t av_fifo_elem_size(const AVFifo *f); + +/** + * Set the maximum size (in elements) to which the FIFO can be resized + * automatically. Has no effect unless AV_FIFO_FLAG_AUTO_GROW is used. + */ +void av_fifo_auto_grow_limit(AVFifo *f, size_t max_elems); + +/** + * @return number of elements available for reading from the given FIFO. + */ +size_t av_fifo_can_read(const AVFifo *f); + +/** + * @return Number of elements that can be written into the given FIFO without + * growing it. + * + * In other words, this number of elements or less is guaranteed to fit + * into the FIFO. More data may be written when the + * AV_FIFO_FLAG_AUTO_GROW flag was specified at FIFO creation, but this + * may involve memory allocation, which can fail. + */ +size_t av_fifo_can_write(const AVFifo *f); + +/** + * Enlarge an AVFifo. + * + * On success, the FIFO will be large enough to hold exactly + * inc + av_fifo_can_read() + av_fifo_can_write() + * elements. In case of failure, the old FIFO is kept unchanged. + * + * @param f AVFifo to resize + * @param inc number of elements to allocate for, in addition to the current + * allocated size + * @return a non-negative number on success, a negative error code on failure + */ +int av_fifo_grow2(AVFifo *f, size_t inc); + +/** + * Write data into a FIFO. + * + * In case nb_elems > av_fifo_can_write(f) and the AV_FIFO_FLAG_AUTO_GROW flag + * was not specified at FIFO creation, nothing is written and an error + * is returned. + * + * Calling function is guaranteed to succeed if nb_elems <= av_fifo_can_write(f). + * + * @param f the FIFO buffer + * @param buf Data to be written. nb_elems * av_fifo_elem_size(f) bytes will be + * read from buf on success. + * @param nb_elems number of elements to write into FIFO + * + * @return a non-negative number on success, a negative error code on failure + */ +int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems); + +/** + * Write data from a user-provided callback into a FIFO. + * + * @param f the FIFO buffer + * @param read_cb Callback supplying the data to the FIFO. May be called + * multiple times. + * @param opaque opaque user data to be provided to read_cb + * @param nb_elems Should point to the maximum number of elements that can be + * written. Will be updated to contain the number of elements + * actually written. + * + * @return non-negative number on success, a negative error code on failure + */ +int av_fifo_write_from_cb(AVFifo *f, AVFifoCB read_cb, + void *opaque, size_t *nb_elems); + +/** + * Read data from a FIFO. + * + * In case nb_elems > av_fifo_can_read(f), nothing is read and an error + * is returned. + * + * @param f the FIFO buffer + * @param buf Buffer to store the data. nb_elems * av_fifo_elem_size(f) bytes + * will be written into buf on success. + * @param nb_elems number of elements to read from FIFO + * + * @return a non-negative number on success, a negative error code on failure + */ +int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems); + +/** + * Feed data from a FIFO into a user-provided callback. + * + * @param f the FIFO buffer + * @param write_cb Callback the data will be supplied to. May be called + * multiple times. + * @param opaque opaque user data to be provided to write_cb + * @param nb_elems Should point to the maximum number of elements that can be + * read. Will be updated to contain the total number of elements + * actually sent to the callback. + * + * @return non-negative number on success, a negative error code on failure + */ +int av_fifo_read_to_cb(AVFifo *f, AVFifoCB write_cb, + void *opaque, size_t *nb_elems); + +/** + * Read data from a FIFO without modifying FIFO state. + * + * Returns an error if an attempt is made to peek to nonexistent elements + * (i.e. if offset + nb_elems is larger than av_fifo_can_read(f)). + * + * @param f the FIFO buffer + * @param buf Buffer to store the data. nb_elems * av_fifo_elem_size(f) bytes + * will be written into buf. + * @param nb_elems number of elements to read from FIFO + * @param offset number of initial elements to skip. + * + * @return a non-negative number on success, a negative error code on failure + */ +int av_fifo_peek(const AVFifo *f, void *buf, size_t nb_elems, size_t offset); + +/** + * Feed data from a FIFO into a user-provided callback. + * + * @param f the FIFO buffer + * @param write_cb Callback the data will be supplied to. May be called + * multiple times. + * @param opaque opaque user data to be provided to write_cb + * @param nb_elems Should point to the maximum number of elements that can be + * read. Will be updated to contain the total number of elements + * actually sent to the callback. + * @param offset number of initial elements to skip; offset + *nb_elems must not + * be larger than av_fifo_can_read(f). + * + * @return a non-negative number on success, a negative error code on failure + */ +int av_fifo_peek_to_cb(const AVFifo *f, AVFifoCB write_cb, void *opaque, + size_t *nb_elems, size_t offset); + +/** + * Discard the specified amount of data from an AVFifo. + * @param size number of elements to discard, MUST NOT be larger than + * av_fifo_can_read(f) + */ +void av_fifo_drain2(AVFifo *f, size_t size); + +/* + * Empty the AVFifo. + * @param f AVFifo to reset + */ +void av_fifo_reset2(AVFifo *f); + +/** + * Free an AVFifo and reset pointer to NULL. + * @param f Pointer to an AVFifo to free. *f == NULL is allowed. + */ +void av_fifo_freep2(AVFifo **f); + +/** + * @} + */ + +#endif /* AVUTIL_FIFO_H */ diff --git a/libs/ffmpeg/libavutil/file.c b/libs/ffmpeg/libavutil/file.c new file mode 100644 index 00000000000..4ef940a6c3c --- /dev/null +++ b/libs/ffmpeg/libavutil/file.c @@ -0,0 +1,153 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "error.h" +#include "file.h" +#include "file_open.h" +#include "internal.h" +#include "log.h" +#include "mem.h" +#include <fcntl.h> +#include <sys/stat.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_IO_H +#include <io.h> +#endif +#if HAVE_MMAP +#include <sys/mman.h> +#elif HAVE_MAPVIEWOFFILE +#include <windows.h> +#endif + +typedef struct FileLogContext { + const AVClass *class; + int log_offset; + void *log_ctx; +} FileLogContext; + +static const AVClass file_log_ctx_class = { + .class_name = "FILE", + .item_name = av_default_item_name, + .option = NULL, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = offsetof(FileLogContext, log_offset), + .parent_log_context_offset = offsetof(FileLogContext, log_ctx), +}; + +int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, + int log_offset, void *log_ctx) +{ + FileLogContext file_log_ctx = { &file_log_ctx_class, log_offset, log_ctx }; + int err, fd = avpriv_open(filename, O_RDONLY); + struct stat st; + av_unused void *ptr; + off_t off_size; + *bufptr = NULL; + *size = 0; + + if (fd < 0) { + err = AVERROR(errno); + av_log(&file_log_ctx, AV_LOG_ERROR, "Cannot read file '%s': %s\n", filename, av_err2str(err)); + return err; + } + + if (fstat(fd, &st) < 0) { + err = AVERROR(errno); + av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in fstat(): %s\n", av_err2str(err)); + close(fd); + return err; + } + + off_size = st.st_size; + if (off_size > SIZE_MAX) { + av_log(&file_log_ctx, AV_LOG_ERROR, + "File size for file '%s' is too big\n", filename); + close(fd); + return AVERROR(EINVAL); + } + *size = off_size; + + if (!*size) { + *bufptr = NULL; + goto out; + } + +#if HAVE_MMAP + ptr = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (ptr == MAP_FAILED) { + err = AVERROR(errno); + av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in mmap(): %s\n", av_err2str(err)); + close(fd); + *size = 0; + return err; + } + *bufptr = ptr; +#elif HAVE_MAPVIEWOFFILE + { + HANDLE mh, fh = (HANDLE)_get_osfhandle(fd); + + mh = CreateFileMapping(fh, NULL, PAGE_READONLY, 0, 0, NULL); + if (!mh) { + av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in CreateFileMapping()\n"); + close(fd); + *size = 0; + return -1; + } + + ptr = MapViewOfFile(mh, FILE_MAP_COPY, 0, 0, *size); + CloseHandle(mh); + if (!ptr) { + av_log(&file_log_ctx, AV_LOG_ERROR, "Error occurred in MapViewOfFile()\n"); + close(fd); + *size = 0; + return -1; + } + + *bufptr = ptr; + } +#else + *bufptr = av_malloc(*size); + if (!*bufptr) { + av_log(&file_log_ctx, AV_LOG_ERROR, "Memory allocation error occurred\n"); + close(fd); + *size = 0; + return AVERROR(ENOMEM); + } + read(fd, *bufptr, *size); +#endif + +out: + close(fd); + return 0; +} + +void av_file_unmap(uint8_t *bufptr, size_t size) +{ + if (!size || !bufptr) + return; +#if HAVE_MMAP + munmap(bufptr, size); +#elif HAVE_MAPVIEWOFFILE + UnmapViewOfFile(bufptr); +#else + av_free(bufptr); +#endif +} diff --git a/libs/ffmpeg/libavutil/file.h b/libs/ffmpeg/libavutil/file.h new file mode 100644 index 00000000000..fced1701082 --- /dev/null +++ b/libs/ffmpeg/libavutil/file.h @@ -0,0 +1,62 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FILE_H +#define AVUTIL_FILE_H + +#include <stddef.h> +#include <stdint.h> + +#include "attributes.h" + +/** + * @file + * Misc file utilities. + */ + +/** + * Read the file with name filename, and put its content in a newly + * allocated buffer or map it with mmap() when available. + * In case of success set *bufptr to the read or mmapped buffer, and + * *size to the size in bytes of the buffer in *bufptr. + * Unlike mmap this function succeeds with zero sized files, in this + * case *bufptr will be set to NULL and *size will be set to 0. + * The returned buffer must be released with av_file_unmap(). + * + * @param filename path to the file + * @param[out] bufptr pointee is set to the mapped or allocated buffer + * @param[out] size pointee is set to the size in bytes of the buffer + * @param log_offset loglevel offset used for logging + * @param log_ctx context used for logging + * @return a non negative number in case of success, a negative value + * corresponding to an AVERROR error code in case of failure + */ +av_warn_unused_result +int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, + int log_offset, void *log_ctx); + +/** + * Unmap or free the buffer bufptr created by av_file_map(). + * + * @param bufptr the buffer previously created with av_file_map() + * @param size size in bytes of bufptr, must be the same as returned + * by av_file_map() + */ +void av_file_unmap(uint8_t *bufptr, size_t size); + +#endif /* AVUTIL_FILE_H */ diff --git a/libs/ffmpeg/libavutil/file_open.c b/libs/ffmpeg/libavutil/file_open.c new file mode 100644 index 00000000000..121a562fcb6 --- /dev/null +++ b/libs/ffmpeg/libavutil/file_open.c @@ -0,0 +1,192 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "avutil.h" +#include "file_open.h" +#include "mem.h" +#include <stdarg.h> +#include <fcntl.h> +#include <sys/stat.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_IO_H +#include <io.h> +#endif + +#ifdef _WIN32 +#undef open +#undef lseek +#undef stat +#undef fstat +#include <windows.h> +#include <share.h> +#include <errno.h> +#include "wchar_filename.h" + +static int win32_open(const char *filename_utf8, int oflag, int pmode) +{ + int fd; + wchar_t *filename_w; + + /* convert UTF-8 to wide chars */ + if (get_extended_win32_path(filename_utf8, &filename_w)) + return -1; + if (!filename_w) + goto fallback; + + fd = _wsopen(filename_w, oflag, SH_DENYNO, pmode); + av_freep(&filename_w); + + if (fd != -1 || (oflag & O_CREAT)) + return fd; + +fallback: + /* filename may be in CP_ACP */ + return _sopen(filename_utf8, oflag, SH_DENYNO, pmode); +} +#define open win32_open +#endif + +int avpriv_open(const char *filename, int flags, ...) +{ + int fd; + unsigned int mode = 0; + va_list ap; + + va_start(ap, flags); + if (flags & O_CREAT) + mode = va_arg(ap, unsigned int); + va_end(ap); + +#ifdef O_CLOEXEC + flags |= O_CLOEXEC; +#endif +#ifdef O_NOINHERIT + flags |= O_NOINHERIT; +#endif + + fd = open(filename, flags, mode); +#if HAVE_FCNTL + if (fd != -1) { + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + av_log(NULL, AV_LOG_DEBUG, "Failed to set close on exec\n"); + } +#endif + + return fd; +} + +typedef struct FileLogContext { + const AVClass *class; + int log_offset; + void *log_ctx; +} FileLogContext; + +static const AVClass file_log_ctx_class = { + .class_name = "TEMPFILE", + .item_name = av_default_item_name, + .option = NULL, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = offsetof(FileLogContext, log_offset), + .parent_log_context_offset = offsetof(FileLogContext, log_ctx), +}; + +int avpriv_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx) +{ + FileLogContext file_log_ctx = { &file_log_ctx_class, log_offset, log_ctx }; + int fd = -1; +#if HAVE_MKSTEMP + size_t len = strlen(prefix) + 12; /* room for "/tmp/" and "XXXXXX\0" */ + *filename = av_malloc(len); +#elif HAVE_TEMPNAM + void *ptr= tempnam(NULL, prefix); + if(!ptr) + ptr= tempnam(".", prefix); + *filename = av_strdup(ptr); + free(ptr); +#else + return AVERROR(ENOSYS); +#endif + /* -----common section-----*/ + if (!*filename) { + av_log(&file_log_ctx, AV_LOG_ERROR, "ff_tempfile: Cannot allocate file name\n"); + return AVERROR(ENOMEM); + } +#if !HAVE_MKSTEMP +# ifndef O_BINARY +# define O_BINARY 0 +# endif +# ifndef O_EXCL +# define O_EXCL 0 +# endif + fd = open(*filename, O_RDWR | O_BINARY | O_CREAT | O_EXCL, 0600); +#else + snprintf(*filename, len, "/tmp/%sXXXXXX", prefix); + fd = mkstemp(*filename); +#if defined(_WIN32) || defined (__ANDROID__) || defined(__DJGPP__) + if (fd < 0) { + snprintf(*filename, len, "./%sXXXXXX", prefix); + fd = mkstemp(*filename); + } +#endif +#endif + /* -----common section-----*/ + if (fd < 0) { + int err = AVERROR(errno); + av_log(&file_log_ctx, AV_LOG_ERROR, "ff_tempfile: Cannot open temporary file %s\n", *filename); + av_freep(filename); + return err; + } + return fd; /* success */ +} + +FILE *avpriv_fopen_utf8(const char *path, const char *mode) +{ + int fd; + int access; + const char *m = mode; + + switch (*m++) { + case 'r': access = O_RDONLY; break; + case 'w': access = O_CREAT|O_WRONLY|O_TRUNC; break; + case 'a': access = O_CREAT|O_WRONLY|O_APPEND; break; + default : + errno = EINVAL; + return NULL; + } + while (*m) { + if (*m == '+') { + access &= ~(O_RDONLY | O_WRONLY); + access |= O_RDWR; + } else if (*m == 'b') { +#ifdef O_BINARY + access |= O_BINARY; +#endif + } else if (*m) { + errno = EINVAL; + return NULL; + } + m++; + } + fd = avpriv_open(path, access, 0666); + if (fd == -1) + return NULL; + return fdopen(fd, mode); +} diff --git a/libs/ffmpeg/libavutil/file_open.h b/libs/ffmpeg/libavutil/file_open.h new file mode 100644 index 00000000000..6a000047416 --- /dev/null +++ b/libs/ffmpeg/libavutil/file_open.h @@ -0,0 +1,57 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FILE_OPEN_H +#define AVUTIL_FILE_OPEN_H + +#include <stdio.h> + +#include "config.h" +#include "attributes.h" + +#if HAVE_LIBC_MSVCRT +#define avpriv_fopen_utf8 ff_fopen_utf8 +#define avpriv_open ff_open +#define avpriv_tempfile ff_tempfile +#endif + + /** + * A wrapper for open() setting O_CLOEXEC. + */ +av_warn_unused_result +int avpriv_open(const char *filename, int flags, ...); + +/** + * Open a file using a UTF-8 filename. + */ +FILE *avpriv_fopen_utf8(const char *path, const char *mode); + +/** + * Wrapper to work around the lack of mkstemp() on mingw. + * Also, tries to create file in /tmp first, if possible. + * *prefix can be a character constant; *filename will be allocated internally. + * @return file descriptor of opened file (or negative value corresponding to an + * AVERROR code on error) + * and opened file name in **filename. + * @note On very old libcs it is necessary to set a secure umask before + * calling this, av_tempfile() can't call umask itself as it is used in + * libraries and could interfere with the calling application. + */ +int avpriv_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx); + +#endif /* AVUTIL_FILE_OPEN_H */ diff --git a/libs/ffmpeg/libavutil/film_grain_params.c b/libs/ffmpeg/libavutil/film_grain_params.c new file mode 100644 index 00000000000..0a6004b6b30 --- /dev/null +++ b/libs/ffmpeg/libavutil/film_grain_params.c @@ -0,0 +1,106 @@ +/** + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "film_grain_params.h" +#include "mem.h" +#include "pixdesc.h" + +AVFilmGrainParams *av_film_grain_params_alloc(size_t *size) +{ + AVFilmGrainParams *params = av_mallocz(sizeof(AVFilmGrainParams)); + + if (size) + *size = sizeof(*params); + + return params; +} + +AVFilmGrainParams *av_film_grain_params_create_side_data(AVFrame *frame) +{ + AVFilmGrainParams *fgp; + AVFrameSideData *side_data = av_frame_new_side_data(frame, + AV_FRAME_DATA_FILM_GRAIN_PARAMS, + sizeof(AVFilmGrainParams)); + if (!side_data) + return NULL; + + fgp = (AVFilmGrainParams *) side_data->data; + *fgp = (AVFilmGrainParams) { + .color_range = AVCOL_RANGE_UNSPECIFIED, + .color_primaries = AVCOL_PRI_UNSPECIFIED, + .color_trc = AVCOL_TRC_UNSPECIFIED, + .color_space = AVCOL_SPC_UNSPECIFIED, + }; + + return fgp; +} + +const AVFilmGrainParams *av_film_grain_params_select(const AVFrame *frame) +{ + const AVFilmGrainParams *fgp, *best = NULL; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + int bit_depth_luma, bit_depth_chroma; + if (!desc) + return NULL; + + /* There are no YUV formats with different bit depth per component, + * so just check both against the first component for simplicity */ + bit_depth_luma = bit_depth_chroma = desc->comp[0].depth; + + for (int i = 0; i < frame->nb_side_data; i++) { + if (frame->side_data[i]->type != AV_FRAME_DATA_FILM_GRAIN_PARAMS) + continue; + fgp = (const AVFilmGrainParams*)frame->side_data[i]->data; + if (fgp->width && fgp->width > frame->width || + fgp->height && fgp->height > frame->height) + continue; + +#define CHECK(a, b, unspec) \ + if ((a) != (unspec) && (b) != (unspec) && (a) != (b)) \ + continue + + CHECK(fgp->bit_depth_luma, bit_depth_luma, 0); + CHECK(fgp->bit_depth_chroma, bit_depth_chroma, 0); + CHECK(fgp->color_range, frame->color_range, AVCOL_RANGE_UNSPECIFIED); + CHECK(fgp->color_primaries, frame->color_primaries, AVCOL_PRI_UNSPECIFIED); + CHECK(fgp->color_trc, frame->color_trc, AVCOL_TRC_UNSPECIFIED); + CHECK(fgp->color_space, frame->colorspace, AVCOL_SPC_UNSPECIFIED); + + switch (fgp->type) { + case AV_FILM_GRAIN_PARAMS_NONE: + continue; + case AV_FILM_GRAIN_PARAMS_AV1: + /* AOM FGS needs an exact match for the chroma resolution */ + if (fgp->subsampling_x != desc->log2_chroma_w || + fgp->subsampling_y != desc->log2_chroma_h) + continue; + break; + case AV_FILM_GRAIN_PARAMS_H274: + /* H.274 FGS can be adapted to any lower chroma resolution */ + if (fgp->subsampling_x > desc->log2_chroma_w || + fgp->subsampling_y > desc->log2_chroma_h) + continue; + break; + } + + if (!best || best->width < fgp->width || best->height < fgp->height) + best = fgp; + } + + return best; +} diff --git a/libs/ffmpeg/libavutil/film_grain_params.h b/libs/ffmpeg/libavutil/film_grain_params.h new file mode 100644 index 00000000000..2915611c9c1 --- /dev/null +++ b/libs/ffmpeg/libavutil/film_grain_params.h @@ -0,0 +1,282 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FILM_GRAIN_PARAMS_H +#define AVUTIL_FILM_GRAIN_PARAMS_H + +#include "frame.h" + +enum AVFilmGrainParamsType { + AV_FILM_GRAIN_PARAMS_NONE = 0, + + /** + * The union is valid when interpreted as AVFilmGrainAOMParams (codec.aom) + */ + AV_FILM_GRAIN_PARAMS_AV1, + + /** + * The union is valid when interpreted as AVFilmGrainH274Params (codec.h274) + */ + AV_FILM_GRAIN_PARAMS_H274, +}; + +/** + * This structure describes how to handle film grain synthesis for AOM codecs. + * + * @note The struct must be allocated as part of AVFilmGrainParams using + * av_film_grain_params_alloc(). Its size is not a part of the public ABI. + */ +typedef struct AVFilmGrainAOMParams { + /** + * Number of points, and the scale and value for each point of the + * piecewise linear scaling function for the uma plane. + */ + int num_y_points; + uint8_t y_points[14][2 /* value, scaling */]; + + /** + * Signals whether to derive the chroma scaling function from the luma. + * Not equivalent to copying the luma values and scales. + */ + int chroma_scaling_from_luma; + + /** + * If chroma_scaling_from_luma is set to 0, signals the chroma scaling + * function parameters. + */ + int num_uv_points[2 /* cb, cr */]; + uint8_t uv_points[2 /* cb, cr */][10][2 /* value, scaling */]; + + /** + * Specifies the shift applied to the chroma components. For AV1, its within + * [8; 11] and determines the range and quantization of the film grain. + */ + int scaling_shift; + + /** + * Specifies the auto-regression lag. + */ + int ar_coeff_lag; + + /** + * Luma auto-regression coefficients. The number of coefficients is given by + * 2 * ar_coeff_lag * (ar_coeff_lag + 1). + */ + int8_t ar_coeffs_y[24]; + + /** + * Chroma auto-regression coefficients. The number of coefficients is given by + * 2 * ar_coeff_lag * (ar_coeff_lag + 1) + !!num_y_points. + */ + int8_t ar_coeffs_uv[2 /* cb, cr */][25]; + + /** + * Specifies the range of the auto-regressive coefficients. Values of 6, + * 7, 8 and so on represent a range of [-2, 2), [-1, 1), [-0.5, 0.5) and + * so on. For AV1 must be between 6 and 9. + */ + int ar_coeff_shift; + + /** + * Signals the down shift applied to the generated gaussian numbers during + * synthesis. + */ + int grain_scale_shift; + + /** + * Specifies the luma/chroma multipliers for the index to the component + * scaling function. + */ + int uv_mult[2 /* cb, cr */]; + int uv_mult_luma[2 /* cb, cr */]; + + /** + * Offset used for component scaling function. For AV1 its a 9-bit value + * with a range [-256, 255] + */ + int uv_offset[2 /* cb, cr */]; + + /** + * Signals whether to overlap film grain blocks. + */ + int overlap_flag; + + /** + * Signals to clip to limited color levels after film grain application. + */ + int limit_output_range; +} AVFilmGrainAOMParams; + +/** + * This structure describes how to handle film grain synthesis for codecs using + * the ITU-T H.274 Versatile supplemental enhancement information message. + * + * @note The struct must be allocated as part of AVFilmGrainParams using + * av_film_grain_params_alloc(). Its size is not a part of the public ABI. + */ +typedef struct AVFilmGrainH274Params { + /** + * Specifies the film grain simulation mode. + * 0 = Frequency filtering, 1 = Auto-regression + */ + int model_id; + + /** + * Specifies the blending mode used to blend the simulated film grain + * with the decoded images. + * + * 0 = Additive, 1 = Multiplicative + */ + int blending_mode_id; + + /** + * Specifies a scale factor used in the film grain characterization equations. + */ + int log2_scale_factor; + + /** + * Indicates if the modelling of film grain for a given component is present. + */ + int component_model_present[3 /* y, cb, cr */]; + + /** + * Specifies the number of intensity intervals for which a specific set of + * model values has been estimated, with a range of [1, 256]. + */ + uint16_t num_intensity_intervals[3 /* y, cb, cr */]; + + /** + * Specifies the number of model values present for each intensity interval + * in which the film grain has been modelled, with a range of [1, 6]. + */ + uint8_t num_model_values[3 /* y, cb, cr */]; + + /** + * Specifies the lower ounds of each intensity interval for whichthe set of + * model values applies for the component. + */ + uint8_t intensity_interval_lower_bound[3 /* y, cb, cr */][256 /* intensity interval */]; + + /** + * Specifies the upper bound of each intensity interval for which the set of + * model values applies for the component. + */ + uint8_t intensity_interval_upper_bound[3 /* y, cb, cr */][256 /* intensity interval */]; + + /** + * Specifies the model values for the component for each intensity interval. + * - When model_id == 0, the following applies: + * For comp_model_value[y], the range of values is [0, 2^bit_depth_luma - 1] + * For comp_model_value[cb..cr], the range of values is [0, 2^bit_depth_chroma - 1] + * - Otherwise, the following applies: + * For comp_model_value[y], the range of values is [-2^(bit_depth_luma - 1), 2^(bit_depth_luma - 1) - 1] + * For comp_model_value[cb..cr], the range of values is [-2^(bit_depth_chroma - 1), 2^(bit_depth_chroma - 1) - 1] + */ + int16_t comp_model_value[3 /* y, cb, cr */][256 /* intensity interval */][6 /* model value */]; +} AVFilmGrainH274Params; + +/** + * This structure describes how to handle film grain synthesis in video + * for specific codecs. Must be present on every frame where film grain is + * meant to be synthesised for correct presentation. + * + * @note The struct must be allocated with av_film_grain_params_alloc() and + * its size is not a part of the public ABI. + */ +typedef struct AVFilmGrainParams { + /** + * Specifies the codec for which this structure is valid. + */ + enum AVFilmGrainParamsType type; + + /** + * Seed to use for the synthesis process, if the codec allows for it. + * + * @note For H.264, this refers to `pic_offset` as defined in + * SMPTE RDD 5-2006. + */ + uint64_t seed; + + /** + * Intended display resolution. May be 0 if the codec does not specify + * any restrictions. + */ + + int width, height; + + /** + * Intended subsampling ratio, or 0 for luma-only streams. + */ + int subsampling_x, subsampling_y; + + /** + * Intended video signal characteristics. + */ + enum AVColorRange color_range; + enum AVColorPrimaries color_primaries; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace color_space; + + /** + * Intended bit depth, or 0 for unknown/unspecified. + */ + int bit_depth_luma; + int bit_depth_chroma; + + /** + * Additional fields may be added both here and in any structure included. + * If a codec's film grain structure differs slightly over another + * codec's, fields within may change meaning depending on the type. + */ + union { + AVFilmGrainAOMParams aom; + AVFilmGrainH274Params h274; + } codec; +} AVFilmGrainParams; + +/** + * Allocate an AVFilmGrainParams structure and set its fields to + * default values. The resulting struct can be freed using av_freep(). + * If size is not NULL it will be set to the number of bytes allocated. + * + * @return An AVFilmGrainParams filled with default values or NULL + * on failure. + */ +AVFilmGrainParams *av_film_grain_params_alloc(size_t *size); + +/** + * Allocate a complete AVFilmGrainParams and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVFilmGrainParams structure to be filled by caller. + */ +AVFilmGrainParams *av_film_grain_params_create_side_data(AVFrame *frame); + +/** + * Select the most appropriate film grain parameters set for the frame, + * taking into account the frame's format, resolution and video signal + * characteristics. + * + * @note, for H.274, this may select a film grain parameter set with + * greater chroma resolution than the frame. Users should take care to + * correctly adjust the chroma grain frequency to the frame. + */ +const AVFilmGrainParams *av_film_grain_params_select(const AVFrame *frame); + +#endif /* AVUTIL_FILM_GRAIN_PARAMS_H */ diff --git a/libs/ffmpeg/libavutil/fixed_dsp.c b/libs/ffmpeg/libavutil/fixed_dsp.c new file mode 100644 index 00000000000..74cefdb145c --- /dev/null +++ b/libs/ffmpeg/libavutil/fixed_dsp.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2012 + * MIPS Technologies, Inc., California. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Nedeljko Babic (nedeljko.babic imgtec com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "common.h" +#include "fixed_dsp.h" +#include "mem.h" + +static void vector_fmul_add_c(int *dst, const int *src0, const int *src1, const int *src2, int len){ + int i; + int64_t accu; + + for (i=0; i<len; i++) { + accu = (int64_t)src0[i] * src1[i]; + dst[i] = src2[i] + (int)((accu + 0x40000000) >> 31); + } +} + +static void vector_fmul_reverse_c(int *dst, const int *src0, const int *src1, int len) +{ + int i; + int64_t accu; + + src1 += len-1; + for (i=0; i<len; i++) { + accu = (int64_t)src0[i] * src1[-i]; + dst[i] = (int)((accu+0x40000000) >> 31); + } +} + +static void vector_fmul_window_scaled_c(int16_t *dst, const int32_t *src0, + const int32_t *src1, const int32_t *win, + int len, uint8_t bits) +{ + int32_t s0, s1, wi, wj, i,j, round; + + dst += len; + win += len; + src0+= len; + round = bits? 1 << (bits-1) : 0; + + for (i=-len, j=len-1; i<0; i++, j--) { + s0 = src0[i]; + s1 = src1[j]; + wi = win[i]; + wj = win[j]; + dst[i] = av_clip_int16(((((int64_t)s0*wj - (int64_t)s1*wi + 0x40000000) >> 31) + round) >> bits); + dst[j] = av_clip_int16(((((int64_t)s0*wi + (int64_t)s1*wj + 0x40000000) >> 31) + round) >> bits); + } +} + +static void vector_fmul_window_c(int32_t *dst, const int32_t *src0, + const int32_t *src1, const int32_t *win, + int len) +{ + int32_t s0, s1, wi, wj, i, j; + + dst += len; + win += len; + src0+= len; + + for (i=-len, j=len-1; i<0; i++, j--) { + s0 = src0[i]; + s1 = src1[j]; + wi = win[i]; + wj = win[j]; + dst[i] = ((int64_t)s0*wj - (int64_t)s1*wi + 0x40000000) >> 31; + dst[j] = ((int64_t)s0*wi + (int64_t)s1*wj + 0x40000000) >> 31; + } +} + +static void vector_fmul_c(int *dst, const int *src0, const int *src1, int len) +{ + int i; + int64_t accu; + + for (i = 0; i < len; i++){ + accu = (int64_t)src0[i] * src1[i]; + dst[i] = (int)((accu+0x40000000) >> 31); + } +} + +static int scalarproduct_fixed_c(const int *v1, const int *v2, int len) +{ + /** p is initialized with 0x40000000 so that the proper rounding will occur + * at the end */ + int64_t p = 0x40000000; + int i; + + for (i = 0; i < len; i++) + p += (int64_t)v1[i] * v2[i]; + + return (int)(p >> 31); +} + +static void butterflies_fixed_c(int *restrict v1s, int *restrict v2, int len) +{ + int i; + unsigned int *v1 = v1s; + + for (i = 0; i < len; i++){ + int t = v1[i] - v2[i]; + v1[i] += v2[i]; + v2[i] = t; + } +} + +AVFixedDSPContext * avpriv_alloc_fixed_dsp(int bit_exact) +{ + AVFixedDSPContext * fdsp = av_malloc(sizeof(AVFixedDSPContext)); + + if (!fdsp) + return NULL; + + fdsp->vector_fmul_window_scaled = vector_fmul_window_scaled_c; + fdsp->vector_fmul_window = vector_fmul_window_c; + fdsp->vector_fmul = vector_fmul_c; + fdsp->vector_fmul_add = vector_fmul_add_c; + fdsp->vector_fmul_reverse = vector_fmul_reverse_c; + fdsp->butterflies_fixed = butterflies_fixed_c; + fdsp->scalarproduct_fixed = scalarproduct_fixed_c; + +#if ARCH_RISCV + ff_fixed_dsp_init_riscv(fdsp); +#elif ARCH_X86 && HAVE_X86ASM + ff_fixed_dsp_init_x86(fdsp); +#endif + + return fdsp; +} diff --git a/libs/ffmpeg/libavutil/fixed_dsp.h b/libs/ffmpeg/libavutil/fixed_dsp.h new file mode 100644 index 00000000000..9b566af6758 --- /dev/null +++ b/libs/ffmpeg/libavutil/fixed_dsp.h @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2012 + * MIPS Technologies, Inc., California. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Nedeljko Babic (nbabic@mips.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FIXED_DSP_H +#define AVUTIL_FIXED_DSP_H + +#include <stdint.h> +#include "attributes.h" +#include "libavcodec/mathops.h" + +typedef struct AVFixedDSPContext { + /* Assume len is a multiple of 16, and arrays are 32-byte aligned */ + /* Results of multiplications are scaled down by 31 bit (and rounded) if not + * stated otherwise */ + + /** + * Overlap/add with window function. + * Result is scaled down by "bits" bits. + * Used primarily by MDCT-based audio codecs. + * Source and destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 16-byte aligned + * @param src0 first source vector + * constraints: 16-byte aligned + * @param src1 second source vector + * constraints: 16-byte aligned + * @param win half-window vector + * constraints: 16-byte aligned + * @param len length of vector + * constraints: multiple of 4 + * @param bits scaling parameter + * + */ + void (*vector_fmul_window_scaled)(int16_t *dst, const int32_t *src0, const int32_t *src1, const int32_t *win, int len, uint8_t bits); + + /** + * Overlap/add with window function. + * Used primarily by MDCT-based audio codecs. + * Source and destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 32-byte aligned + * @param src0 first source vector + * constraints: 16-byte aligned + * @param src1 second source vector + * constraints: 16-byte aligned + * @param win half-window vector + * constraints: 16-byte aligned + * @param len length of vector + * constraints: multiple of 4 + */ + void (*vector_fmul_window)(int32_t *dst, const int32_t *src0, const int32_t *src1, const int32_t *win, int len); + + /** + * Fixed-point multiplication that calculates the entry wise product of two + * vectors of integers and stores the result in a vector of integers. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_fmul)(int *dst, const int *src0, const int *src1, + int len); + + void (*vector_fmul_reverse)(int *dst, const int *src0, const int *src1, int len); + /** + * Calculate the entry wise product of two vectors of integers, add a third vector of + * integers and store the result in a vector of integers. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param src2 third input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_fmul_add)(int *dst, const int *src0, const int *src1, + const int *src2, int len); + + /** + * Calculate the scalar product of two vectors of integers. + * + * @param v1 first vector, 16-byte aligned + * @param v2 second vector, 16-byte aligned + * @param len length of vectors, multiple of 4 + * + * @return sum of elementwise products + */ + int (*scalarproduct_fixed)(const int *v1, const int *v2, int len); + + /** + * Calculate the sum and difference of two vectors of integers. + * + * @param v1 first input vector, sum output, 16-byte aligned + * @param v2 second input vector, difference output, 16-byte aligned + * @param len length of vectors, multiple of 4 + */ + void (*butterflies_fixed)(int *restrict v1, int *restrict v2, int len); +} AVFixedDSPContext; + +/** + * Allocate and initialize a fixed DSP context. + * note: should be freed with a av_free call when no longer needed. + * + * @param strict setting to non-zero avoids using functions which may not be IEEE-754 compliant + */ +AVFixedDSPContext * avpriv_alloc_fixed_dsp(int strict); + +void ff_fixed_dsp_init_riscv(AVFixedDSPContext *fdsp); +void ff_fixed_dsp_init_x86(AVFixedDSPContext *fdsp); + +/** + * Calculate the square root + * + * @param x input fixed point number + * + * @param bits format of fixed point number (32 - bits).bits + * + * note: input is normalized to (0, 1) fixed point value + */ + +static av_always_inline int fixed_sqrt(int x, int bits) +{ + int retval, bit_mask, guess, square, i; + int64_t accu; + int shift1 = 30 - bits; + int shift2 = bits - 15; + + if (shift1 > 0) retval = ff_sqrt(x << shift1); + else retval = ff_sqrt(x >> -shift1); + + if (shift2 > 0) { + retval = retval << shift2; + bit_mask = (1 << (shift2 - 1)); + + for (i=0; i<shift2; i++){ + guess = retval + bit_mask; + accu = (int64_t)guess * guess; + square = (int)((accu + bit_mask) >> bits); + if (x >= square) + retval += bit_mask; + bit_mask >>= 1; + } + + } + else retval >>= (-shift2); + + return retval; +} + +#endif /* AVUTIL_FIXED_DSP_H */ diff --git a/libs/ffmpeg/libavutil/float2half.c b/libs/ffmpeg/libavutil/float2half.c new file mode 100644 index 00000000000..1a283956e7a --- /dev/null +++ b/libs/ffmpeg/libavutil/float2half.c @@ -0,0 +1,55 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/float2half.h" + +void ff_init_float2half_tables(Float2HalfTables *t) +{ +#if !HAVE_FAST_FLOAT16 + for (int i = 0; i < 256; i++) { + int e = i - 127; + + if (e < -24) { // Very small numbers map to zero + t->basetable[i|0x000] = 0x0000; + t->basetable[i|0x100] = 0x8000; + t->shifttable[i|0x000] = 24; + t->shifttable[i|0x100] = 24; + } else if (e < -14) { // Small numbers map to denorms + t->basetable[i|0x000] = (0x0400>>(-e-14)); + t->basetable[i|0x100] = (0x0400>>(-e-14)) | 0x8000; + t->shifttable[i|0x000] = -e-1; + t->shifttable[i|0x100] = -e-1; + } else if (e <= 15) { // Normal numbers just lose precision + t->basetable[i|0x000] = ((e + 15) << 10); + t->basetable[i|0x100] = ((e + 15) << 10) | 0x8000; + t->shifttable[i|0x000] = 13; + t->shifttable[i|0x100] = 13; + } else if (e < 128) { // Large numbers map to Infinity + t->basetable[i|0x000] = 0x7C00; + t->basetable[i|0x100] = 0xFC00; + t->shifttable[i|0x000] = 24; + t->shifttable[i|0x100] = 24; + } else { // Infinity and NaN's stay Infinity and NaN's + t->basetable[i|0x000] = 0x7C00; + t->basetable[i|0x100] = 0xFC00; + t->shifttable[i|0x000] = 13; + t->shifttable[i|0x100] = 13; + } + } +#endif +} diff --git a/libs/ffmpeg/libavutil/float2half.h b/libs/ffmpeg/libavutil/float2half.h new file mode 100644 index 00000000000..e619046911b --- /dev/null +++ b/libs/ffmpeg/libavutil/float2half.h @@ -0,0 +1,56 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FLOAT2HALF_H +#define AVUTIL_FLOAT2HALF_H + +#include <stdint.h> +#include "intfloat.h" + +#include "config.h" + +typedef struct Float2HalfTables { +#if HAVE_FAST_FLOAT16 + uint8_t dummy; +#else + uint16_t basetable[512]; + uint8_t shifttable[512]; +#endif +} Float2HalfTables; + +void ff_init_float2half_tables(Float2HalfTables *t); + +static inline uint16_t float2half(uint32_t f, const Float2HalfTables *t) +{ +#if HAVE_FAST_FLOAT16 + union { + _Float16 f; + uint16_t i; + } u; + u.f = av_int2float(f); + return u.i; +#else + uint16_t h; + + h = t->basetable[(f >> 23) & 0x1ff] + ((f & 0x007fffff) >> t->shifttable[(f >> 23) & 0x1ff]); + + return h; +#endif +} + +#endif /* AVUTIL_FLOAT2HALF_H */ diff --git a/libs/ffmpeg/libavutil/float_dsp.c b/libs/ffmpeg/libavutil/float_dsp.c new file mode 100644 index 00000000000..5bfa1008d13 --- /dev/null +++ b/libs/ffmpeg/libavutil/float_dsp.c @@ -0,0 +1,168 @@ +/* + * Copyright 2005 Balatoni Denes + * Copyright 2006 Loren Merritt + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "attributes.h" +#include "float_dsp.h" +#include "mem.h" + +static void vector_fmul_c(float *dst, const float *src0, const float *src1, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] = src0[i] * src1[i]; +} + +static void vector_dmul_c(double *dst, const double *src0, const double *src1, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] = src0[i] * src1[i]; +} + +static void vector_fmac_scalar_c(float *dst, const float *src, float mul, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] += src[i] * mul; +} + +static void vector_dmac_scalar_c(double *dst, const double *src, double mul, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] += src[i] * mul; +} + +static void vector_fmul_scalar_c(float *dst, const float *src, float mul, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] = src[i] * mul; +} + +static void vector_dmul_scalar_c(double *dst, const double *src, double mul, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] = src[i] * mul; +} + +static void vector_fmul_window_c(float *dst, const float *src0, + const float *src1, const float *win, int len) +{ + int i, j; + + dst += len; + win += len; + src0 += len; + + for (i = -len, j = len - 1; i < 0; i++, j--) { + float s0 = src0[i]; + float s1 = src1[j]; + float wi = win[i]; + float wj = win[j]; + dst[i] = s0 * wj - s1 * wi; + dst[j] = s0 * wi + s1 * wj; + } +} + +static void vector_fmul_add_c(float *dst, const float *src0, const float *src1, + const float *src2, int len){ + int i; + + for (i = 0; i < len; i++) + dst[i] = src0[i] * src1[i] + src2[i]; +} + +static void vector_fmul_reverse_c(float *dst, const float *src0, + const float *src1, int len) +{ + int i; + + src1 += len-1; + for (i = 0; i < len; i++) + dst[i] = src0[i] * src1[-i]; +} + +static void butterflies_float_c(float *restrict v1, float *restrict v2, + int len) +{ + int i; + + for (i = 0; i < len; i++) { + float t = v1[i] - v2[i]; + v1[i] += v2[i]; + v2[i] = t; + } +} + +double ff_scalarproduct_double_c(const double *v1, const double *v2, + size_t len) +{ + double p = 0.0; + + for (size_t i = 0; i < len; i++) + p += v1[i] * v2[i]; + + return p; +} + +av_cold AVFloatDSPContext *avpriv_float_dsp_alloc(int bit_exact) +{ + AVFloatDSPContext *fdsp = av_mallocz(sizeof(AVFloatDSPContext)); + if (!fdsp) + return NULL; + + fdsp->vector_fmul = vector_fmul_c; + fdsp->vector_dmul = vector_dmul_c; + fdsp->vector_fmac_scalar = vector_fmac_scalar_c; + fdsp->vector_fmul_scalar = vector_fmul_scalar_c; + fdsp->vector_dmac_scalar = vector_dmac_scalar_c; + fdsp->vector_dmul_scalar = vector_dmul_scalar_c; + fdsp->vector_fmul_window = vector_fmul_window_c; + fdsp->vector_fmul_add = vector_fmul_add_c; + fdsp->vector_fmul_reverse = vector_fmul_reverse_c; + fdsp->butterflies_float = butterflies_float_c; + fdsp->scalarproduct_float = ff_scalarproduct_float_c; + fdsp->scalarproduct_double = ff_scalarproduct_double_c; + +#if ARCH_AARCH64 + ff_float_dsp_init_aarch64(fdsp); +#elif ARCH_ARM + ff_float_dsp_init_arm(fdsp); +#elif ARCH_PPC + ff_float_dsp_init_ppc(fdsp, bit_exact); +#elif ARCH_RISCV + ff_float_dsp_init_riscv(fdsp); +#elif ARCH_X86 && HAVE_X86ASM + ff_float_dsp_init_x86(fdsp); +#elif ARCH_MIPS + ff_float_dsp_init_mips(fdsp); +#endif + return fdsp; +} diff --git a/libs/ffmpeg/libavutil/float_dsp.h b/libs/ffmpeg/libavutil/float_dsp.h new file mode 100644 index 00000000000..ab34277c208 --- /dev/null +++ b/libs/ffmpeg/libavutil/float_dsp.h @@ -0,0 +1,246 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FLOAT_DSP_H +#define AVUTIL_FLOAT_DSP_H + +#include <stddef.h> + +typedef struct AVFloatDSPContext { + /** + * Calculate the entry wise product of two vectors of floats and store the result in + * a vector of floats. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_fmul)(float *dst, const float *src0, const float *src1, + int len); + + /** + * Multiply a vector of floats by a scalar float and add to + * destination vector. Source and destination vectors must + * overlap exactly or not at all. + * + * @param dst result vector + * constraints: 32-byte aligned + * @param src input vector + * constraints: 32-byte aligned + * @param mul scalar value + * @param len length of vector + * constraints: multiple of 16 + */ + void (*vector_fmac_scalar)(float *dst, const float *src, float mul, + int len); + + /** + * Multiply a vector of doubles by a scalar double and add to + * destination vector. Source and destination vectors must + * overlap exactly or not at all. + * + * @param dst result vector + * constraints: 32-byte aligned + * @param src input vector + * constraints: 32-byte aligned + * @param mul scalar value + * @param len length of vector + * constraints: multiple of 16 + */ + void (*vector_dmac_scalar)(double *dst, const double *src, double mul, + int len); + + /** + * Multiply a vector of floats by a scalar float. Source and + * destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 16-byte aligned + * @param src input vector + * constraints: 16-byte aligned + * @param mul scalar value + * @param len length of vector + * constraints: multiple of 4 + */ + void (*vector_fmul_scalar)(float *dst, const float *src, float mul, + int len); + + /** + * Multiply a vector of double by a scalar double. Source and + * destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 32-byte aligned + * @param src input vector + * constraints: 32-byte aligned + * @param mul scalar value + * @param len length of vector + * constraints: multiple of 8 + */ + void (*vector_dmul_scalar)(double *dst, const double *src, double mul, + int len); + + /** + * Overlap/add with window function. + * Used primarily by MDCT-based audio codecs. + * Source and destination vectors must overlap exactly or not at all. + * + * @param dst result vector + * constraints: 16-byte aligned + * @param src0 first source vector + * constraints: 16-byte aligned + * @param src1 second source vector + * constraints: 16-byte aligned + * @param win half-window vector + * constraints: 16-byte aligned + * @param len length of vector + * constraints: multiple of 4 + */ + void (*vector_fmul_window)(float *dst, const float *src0, + const float *src1, const float *win, int len); + + /** + * Calculate the entry wise product of two vectors of floats, add a third vector of + * floats and store the result in a vector of floats. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param src2 third input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_fmul_add)(float *dst, const float *src0, const float *src1, + const float *src2, int len); + + /** + * Calculate the entry wise product of two vectors of floats, and store the result + * in a vector of floats. The second vector of floats is iterated over + * in reverse order. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_fmul_reverse)(float *dst, const float *src0, + const float *src1, int len); + + /** + * Calculate the sum and difference of two vectors of floats. + * + * @param v1 first input vector, sum output, 16-byte aligned + * @param v2 second input vector, difference output, 16-byte aligned + * @param len length of vectors, multiple of 4 + */ + void (*butterflies_float)(float *restrict v1, float *restrict v2, int len); + + /** + * Calculate the scalar product of two vectors of floats. + * + * @param v1 first vector, 16-byte aligned + * @param v2 second vector, 16-byte aligned + * @param len length of vectors, multiple of 4 + * + * @return sum of elementwise products + */ + float (*scalarproduct_float)(const float *v1, const float *v2, int len); + + /** + * Calculate the entry wise product of two vectors of doubles and store the result in + * a vector of doubles. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_dmul)(double *dst, const double *src0, const double *src1, + int len); + + /** + * Calculate the scalar product of two vectors of doubles. + * + * @param v1 first vector + * constraints: 32-byte aligned + * @param v2 second vector + * constraints: 32-byte aligned + * @param len length of vectors + * constraints: multiple of 16 + * + * @return inner product of the vectors + */ + double (*scalarproduct_double)(const double *v1, const double *v2, + size_t len); +} AVFloatDSPContext; + +/** + * Return the scalar product of two vectors of floats. + * + * @param v1 first input vector + * @param v2 first input vector + * @param len number of elements + * + * @return sum of elementwise products + */ +float ff_scalarproduct_float_c(const float *v1, const float *v2, int len); + +/** + * Return the scalar product of two vectors of doubles. + * + * @param v1 first input vector + * @param v2 first input vector + * @param len number of elements + * + * @return inner product of the vectors + */ +double ff_scalarproduct_double_c(const double *v1, const double *v2, + size_t len); + +void ff_float_dsp_init_aarch64(AVFloatDSPContext *fdsp); +void ff_float_dsp_init_arm(AVFloatDSPContext *fdsp); +void ff_float_dsp_init_ppc(AVFloatDSPContext *fdsp, int strict); +void ff_float_dsp_init_riscv(AVFloatDSPContext *fdsp); +void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp); +void ff_float_dsp_init_mips(AVFloatDSPContext *fdsp); + +/** + * Allocate a float DSP context. + * + * @param strict setting to non-zero avoids using functions which may not be IEEE-754 compliant + */ +AVFloatDSPContext *avpriv_float_dsp_alloc(int strict); + +#endif /* AVUTIL_FLOAT_DSP_H */ diff --git a/libs/ffmpeg/libavutil/float_scalarproduct.c b/libs/ffmpeg/libavutil/float_scalarproduct.c new file mode 100644 index 00000000000..e95e67fde1d --- /dev/null +++ b/libs/ffmpeg/libavutil/float_scalarproduct.c @@ -0,0 +1,32 @@ +/* + * Copyright 2005 Balatoni Denes + * Copyright 2006 Loren Merritt + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "float_dsp.h" + +float ff_scalarproduct_float_c(const float *v1, const float *v2, int len) +{ + float p = 0.0; + + for (int i = 0; i < len; i++) + p += v1[i] * v2[i]; + + return p; +} diff --git a/libs/ffmpeg/libavutil/frame.c b/libs/ffmpeg/libavutil/frame.c new file mode 100644 index 00000000000..be30eb09d2a --- /dev/null +++ b/libs/ffmpeg/libavutil/frame.c @@ -0,0 +1,830 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "channel_layout.h" +#include "avassert.h" +#include "buffer.h" +#include "dict.h" +#include "frame.h" +#include "imgutils.h" +#include "mem.h" +#include "refstruct.h" +#include "samplefmt.h" +#include "side_data.h" +#include "hwcontext.h" + +static void get_frame_defaults(AVFrame *frame) +{ + memset(frame, 0, sizeof(*frame)); + + frame->pts = + frame->pkt_dts = AV_NOPTS_VALUE; + frame->best_effort_timestamp = AV_NOPTS_VALUE; + frame->duration = 0; + frame->time_base = (AVRational){ 0, 1 }; + frame->sample_aspect_ratio = (AVRational){ 0, 1 }; + frame->format = -1; /* unknown */ + frame->extended_data = frame->data; + frame->color_primaries = AVCOL_PRI_UNSPECIFIED; + frame->color_trc = AVCOL_TRC_UNSPECIFIED; + frame->colorspace = AVCOL_SPC_UNSPECIFIED; + frame->color_range = AVCOL_RANGE_UNSPECIFIED; + frame->chroma_location = AVCHROMA_LOC_UNSPECIFIED; + frame->alpha_mode = AVALPHA_MODE_UNSPECIFIED; + frame->flags = 0; +} + +AVFrame *av_frame_alloc(void) +{ + AVFrame *frame = av_malloc(sizeof(*frame)); + + if (!frame) + return NULL; + + get_frame_defaults(frame); + + return frame; +} + +void av_frame_free(AVFrame **frame) +{ + if (!frame || !*frame) + return; + + av_frame_unref(*frame); + av_freep(frame); +} + +#define ALIGN (HAVE_SIMD_ALIGN_64 ? 64 : 32) + +static int get_video_buffer(AVFrame *frame, int align) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + int ret, padded_height; + int plane_padding; + ptrdiff_t linesizes[4]; + size_t total_size, sizes[4]; + + if (!desc) + return AVERROR(EINVAL); + + if ((ret = av_image_check_size(frame->width, frame->height, 0, NULL)) < 0) + return ret; + + if (align <= 0) + align = ALIGN; + plane_padding = FFMAX(ALIGN, align); + + if (!frame->linesize[0]) { + for (int i = 1; i <= align; i += i) { + ret = av_image_fill_linesizes(frame->linesize, frame->format, + FFALIGN(frame->width, i)); + if (ret < 0) + return ret; + if (!(frame->linesize[0] & (align-1))) + break; + } + + for (int i = 0; i < 4 && frame->linesize[i]; i++) + frame->linesize[i] = FFALIGN(frame->linesize[i], align); + } + + for (int i = 0; i < 4; i++) + linesizes[i] = frame->linesize[i]; + + padded_height = FFALIGN(frame->height, 32); + if ((ret = av_image_fill_plane_sizes(sizes, frame->format, + padded_height, linesizes)) < 0) + return ret; + + total_size = 4 * plane_padding + 4 * align; + for (int i = 0; i < 4; i++) { + if (sizes[i] > SIZE_MAX - total_size) + return AVERROR(EINVAL); + total_size += sizes[i]; + } + + frame->buf[0] = av_buffer_alloc(total_size); + if (!frame->buf[0]) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if ((ret = av_image_fill_pointers(frame->data, frame->format, padded_height, + frame->buf[0]->data, frame->linesize)) < 0) + goto fail; + + for (int i = 1; i < 4; i++) { + if (frame->data[i]) + frame->data[i] += i * plane_padding; + frame->data[i] = (uint8_t *)FFALIGN((uintptr_t)frame->data[i], align); + } + + frame->extended_data = frame->data; + + return 0; +fail: + av_frame_unref(frame); + return ret; +} + +static int get_audio_buffer(AVFrame *frame, int align) +{ + int planar = av_sample_fmt_is_planar(frame->format); + int channels, planes; + size_t size; + int ret; + + channels = frame->ch_layout.nb_channels; + planes = planar ? channels : 1; + if (!frame->linesize[0]) { + ret = av_samples_get_buffer_size(&frame->linesize[0], channels, + frame->nb_samples, frame->format, + align); + if (ret < 0) + return ret; + } + + if (align <= 0) + align = ALIGN; + + if (planes > AV_NUM_DATA_POINTERS) { + frame->extended_data = av_calloc(planes, + sizeof(*frame->extended_data)); + frame->extended_buf = av_calloc(planes - AV_NUM_DATA_POINTERS, + sizeof(*frame->extended_buf)); + if (!frame->extended_data || !frame->extended_buf) { + av_freep(&frame->extended_data); + av_freep(&frame->extended_buf); + return AVERROR(ENOMEM); + } + frame->nb_extended_buf = planes - AV_NUM_DATA_POINTERS; + } else + frame->extended_data = frame->data; + + if (frame->linesize[0] > SIZE_MAX - align) + return AVERROR(EINVAL); + size = frame->linesize[0] + (size_t)align; + + for (int i = 0; i < FFMIN(planes, AV_NUM_DATA_POINTERS); i++) { + frame->buf[i] = av_buffer_alloc(size); + if (!frame->buf[i]) { + av_frame_unref(frame); + return AVERROR(ENOMEM); + } + frame->extended_data[i] = frame->data[i] = + (uint8_t *)FFALIGN((uintptr_t)frame->buf[i]->data, align); + } + for (int i = 0; i < planes - AV_NUM_DATA_POINTERS; i++) { + frame->extended_buf[i] = av_buffer_alloc(size); + if (!frame->extended_buf[i]) { + av_frame_unref(frame); + return AVERROR(ENOMEM); + } + frame->extended_data[i + AV_NUM_DATA_POINTERS] = + (uint8_t *)FFALIGN((uintptr_t)frame->extended_buf[i]->data, align); + } + return 0; + +} + +int av_frame_get_buffer(AVFrame *frame, int align) +{ + if (frame->format < 0) + return AVERROR(EINVAL); + + if (frame->width > 0 && frame->height > 0) + return get_video_buffer(frame, align); + else if (frame->nb_samples > 0 && + (av_channel_layout_check(&frame->ch_layout))) + return get_audio_buffer(frame, align); + + return AVERROR(EINVAL); +} + +static int frame_copy_props(AVFrame *dst, const AVFrame *src, int force_copy) +{ + dst->pict_type = src->pict_type; + dst->sample_aspect_ratio = src->sample_aspect_ratio; + dst->crop_top = src->crop_top; + dst->crop_bottom = src->crop_bottom; + dst->crop_left = src->crop_left; + dst->crop_right = src->crop_right; + dst->pts = src->pts; + dst->duration = src->duration; + dst->repeat_pict = src->repeat_pict; + dst->sample_rate = src->sample_rate; + dst->opaque = src->opaque; + dst->pkt_dts = src->pkt_dts; + dst->time_base = src->time_base; + dst->quality = src->quality; + dst->best_effort_timestamp = src->best_effort_timestamp; + dst->flags = src->flags; + dst->decode_error_flags = src->decode_error_flags; + dst->color_primaries = src->color_primaries; + dst->color_trc = src->color_trc; + dst->colorspace = src->colorspace; + dst->color_range = src->color_range; + dst->chroma_location = src->chroma_location; + dst->alpha_mode = src->alpha_mode; + + av_dict_copy(&dst->metadata, src->metadata, 0); + + for (int i = 0; i < src->nb_side_data; i++) { + const AVFrameSideData *sd_src = src->side_data[i]; + AVFrameSideData *sd_dst; + if ( sd_src->type == AV_FRAME_DATA_PANSCAN + && (src->width != dst->width || src->height != dst->height)) + continue; + if (force_copy) { + sd_dst = av_frame_new_side_data(dst, sd_src->type, + sd_src->size); + if (!sd_dst) { + av_frame_side_data_free(&dst->side_data, &dst->nb_side_data); + return AVERROR(ENOMEM); + } + memcpy(sd_dst->data, sd_src->data, sd_src->size); + } else { + AVBufferRef *ref = av_buffer_ref(sd_src->buf); + sd_dst = av_frame_new_side_data_from_buf(dst, sd_src->type, ref); + if (!sd_dst) { + av_buffer_unref(&ref); + av_frame_side_data_free(&dst->side_data, &dst->nb_side_data); + return AVERROR(ENOMEM); + } + } + av_dict_copy(&sd_dst->metadata, sd_src->metadata, 0); + } + + av_refstruct_replace(&dst->private_ref, src->private_ref); + return av_buffer_replace(&dst->opaque_ref, src->opaque_ref); +} + +int av_frame_ref(AVFrame *dst, const AVFrame *src) +{ + int ret = 0; + + av_assert1(dst->width == 0 && dst->height == 0); + av_assert1(dst->ch_layout.nb_channels == 0 && + dst->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC); + + dst->format = src->format; + dst->width = src->width; + dst->height = src->height; + dst->nb_samples = src->nb_samples; + + ret = frame_copy_props(dst, src, 0); + if (ret < 0) + goto fail; + + ret = av_channel_layout_copy(&dst->ch_layout, &src->ch_layout); + if (ret < 0) + goto fail; + + /* duplicate the frame data if it's not refcounted */ + if (!src->buf[0]) { + ret = av_frame_get_buffer(dst, 0); + if (ret < 0) + goto fail; + + ret = av_frame_copy(dst, src); + if (ret < 0) + goto fail; + + return 0; + } + + /* ref the buffers */ + for (int i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) { + if (!src->buf[i]) + continue; + dst->buf[i] = av_buffer_ref(src->buf[i]); + if (!dst->buf[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + if (src->extended_buf) { + dst->extended_buf = av_calloc(src->nb_extended_buf, + sizeof(*dst->extended_buf)); + if (!dst->extended_buf) { + ret = AVERROR(ENOMEM); + goto fail; + } + dst->nb_extended_buf = src->nb_extended_buf; + + for (int i = 0; i < src->nb_extended_buf; i++) { + dst->extended_buf[i] = av_buffer_ref(src->extended_buf[i]); + if (!dst->extended_buf[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + } + + if (src->hw_frames_ctx) { + dst->hw_frames_ctx = av_buffer_ref(src->hw_frames_ctx); + if (!dst->hw_frames_ctx) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + /* duplicate extended data */ + if (src->extended_data != src->data) { + int ch = dst->ch_layout.nb_channels; + + if (ch <= 0 || ch > SIZE_MAX / sizeof(*dst->extended_data)) { + ret = AVERROR(EINVAL); + goto fail; + } + + dst->extended_data = av_memdup(src->extended_data, sizeof(*dst->extended_data) * ch); + if (!dst->extended_data) { + ret = AVERROR(ENOMEM); + goto fail; + } + } else + dst->extended_data = dst->data; + + memcpy(dst->data, src->data, sizeof(src->data)); + memcpy(dst->linesize, src->linesize, sizeof(src->linesize)); + + return 0; + +fail: + av_frame_unref(dst); + return ret; +} + +int av_frame_replace(AVFrame *dst, const AVFrame *src) +{ + int ret = 0; + + if (dst == src) + return AVERROR(EINVAL); + + if (!src->buf[0]) { + av_frame_unref(dst); + + /* duplicate the frame data if it's not refcounted */ + if ( src->data[0] || src->data[1] + || src->data[2] || src->data[3]) + return av_frame_ref(dst, src); + + ret = frame_copy_props(dst, src, 0); + if (ret < 0) + goto fail; + } + + dst->format = src->format; + dst->width = src->width; + dst->height = src->height; + dst->nb_samples = src->nb_samples; + + ret = av_channel_layout_copy(&dst->ch_layout, &src->ch_layout); + if (ret < 0) + goto fail; + + av_frame_side_data_free(&dst->side_data, &dst->nb_side_data); + av_dict_free(&dst->metadata); + ret = frame_copy_props(dst, src, 0); + if (ret < 0) + goto fail; + + /* replace the buffers */ + for (int i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) { + ret = av_buffer_replace(&dst->buf[i], src->buf[i]); + if (ret < 0) + goto fail; + } + + if (src->extended_buf) { + if (dst->nb_extended_buf != src->nb_extended_buf) { + int nb_extended_buf = FFMIN(dst->nb_extended_buf, src->nb_extended_buf); + void *tmp; + + for (int i = nb_extended_buf; i < dst->nb_extended_buf; i++) + av_buffer_unref(&dst->extended_buf[i]); + + tmp = av_realloc_array(dst->extended_buf, src->nb_extended_buf, + sizeof(*dst->extended_buf)); + if (!tmp) { + ret = AVERROR(ENOMEM); + goto fail; + } + dst->extended_buf = tmp; + dst->nb_extended_buf = src->nb_extended_buf; + + memset(&dst->extended_buf[nb_extended_buf], 0, + (src->nb_extended_buf - nb_extended_buf) * sizeof(*dst->extended_buf)); + } + + for (int i = 0; i < src->nb_extended_buf; i++) { + ret = av_buffer_replace(&dst->extended_buf[i], src->extended_buf[i]); + if (ret < 0) + goto fail; + } + } else if (dst->extended_buf) { + for (int i = 0; i < dst->nb_extended_buf; i++) + av_buffer_unref(&dst->extended_buf[i]); + av_freep(&dst->extended_buf); + } + + ret = av_buffer_replace(&dst->hw_frames_ctx, src->hw_frames_ctx); + if (ret < 0) + goto fail; + + if (dst->extended_data != dst->data) + av_freep(&dst->extended_data); + + if (src->extended_data != src->data) { + int ch = dst->ch_layout.nb_channels; + + if (ch <= 0 || ch > SIZE_MAX / sizeof(*dst->extended_data)) { + ret = AVERROR(EINVAL); + goto fail; + } + + dst->extended_data = av_memdup(src->extended_data, sizeof(*dst->extended_data) * ch); + if (!dst->extended_data) { + ret = AVERROR(ENOMEM); + goto fail; + } + } else + dst->extended_data = dst->data; + + memcpy(dst->data, src->data, sizeof(src->data)); + memcpy(dst->linesize, src->linesize, sizeof(src->linesize)); + + return 0; + +fail: + av_frame_unref(dst); + return ret; +} + +AVFrame *av_frame_clone(const AVFrame *src) +{ + AVFrame *ret = av_frame_alloc(); + + if (!ret) + return NULL; + + if (av_frame_ref(ret, src) < 0) + av_frame_free(&ret); + + return ret; +} + +void av_frame_unref(AVFrame *frame) +{ + if (!frame) + return; + + av_frame_side_data_free(&frame->side_data, &frame->nb_side_data); + + for (int i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++) + av_buffer_unref(&frame->buf[i]); + for (int i = 0; i < frame->nb_extended_buf; i++) + av_buffer_unref(&frame->extended_buf[i]); + av_freep(&frame->extended_buf); + av_dict_free(&frame->metadata); + + av_buffer_unref(&frame->hw_frames_ctx); + + av_buffer_unref(&frame->opaque_ref); + av_refstruct_unref(&frame->private_ref); + + if (frame->extended_data != frame->data) + av_freep(&frame->extended_data); + + av_channel_layout_uninit(&frame->ch_layout); + + get_frame_defaults(frame); +} + +void av_frame_move_ref(AVFrame *dst, AVFrame *src) +{ + av_assert1(dst->width == 0 && dst->height == 0); + av_assert1(dst->ch_layout.nb_channels == 0 && + dst->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC); + + *dst = *src; + if (src->extended_data == src->data) + dst->extended_data = dst->data; + get_frame_defaults(src); +} + +int av_frame_is_writable(AVFrame *frame) +{ + int ret = 1; + + /* assume non-refcounted frames are not writable */ + if (!frame->buf[0]) + return 0; + + for (int i = 0; i < FF_ARRAY_ELEMS(frame->buf); i++) + if (frame->buf[i]) + ret &= !!av_buffer_is_writable(frame->buf[i]); + for (int i = 0; i < frame->nb_extended_buf; i++) + ret &= !!av_buffer_is_writable(frame->extended_buf[i]); + + return ret; +} + +int av_frame_make_writable(AVFrame *frame) +{ + AVFrame tmp; + int ret; + + if (av_frame_is_writable(frame)) + return 0; + + memset(&tmp, 0, sizeof(tmp)); + tmp.format = frame->format; + tmp.width = frame->width; + tmp.height = frame->height; + tmp.nb_samples = frame->nb_samples; + ret = av_channel_layout_copy(&tmp.ch_layout, &frame->ch_layout); + if (ret < 0) { + av_frame_unref(&tmp); + return ret; + } + + if (frame->hw_frames_ctx) + ret = av_hwframe_get_buffer(frame->hw_frames_ctx, &tmp, 0); + else + ret = av_frame_get_buffer(&tmp, 0); + if (ret < 0) + return ret; + + ret = av_frame_copy(&tmp, frame); + if (ret < 0) { + av_frame_unref(&tmp); + return ret; + } + + ret = av_frame_copy_props(&tmp, frame); + if (ret < 0) { + av_frame_unref(&tmp); + return ret; + } + + av_frame_unref(frame); + + *frame = tmp; + if (tmp.data == tmp.extended_data) + frame->extended_data = frame->data; + + return 0; +} + +int av_frame_copy_props(AVFrame *dst, const AVFrame *src) +{ + return frame_copy_props(dst, src, 1); +} + +AVBufferRef *av_frame_get_plane_buffer(const AVFrame *frame, int plane) +{ + uintptr_t data; + int planes; + + if (frame->nb_samples) { + int channels = frame->ch_layout.nb_channels; + if (!channels) + return NULL; + planes = av_sample_fmt_is_planar(frame->format) ? channels : 1; + } else + planes = 4; + + if (plane < 0 || plane >= planes || !frame->extended_data[plane]) + return NULL; + data = (uintptr_t)frame->extended_data[plane]; + + for (int i = 0; i < FF_ARRAY_ELEMS(frame->buf) && frame->buf[i]; i++) { + AVBufferRef *buf = frame->buf[i]; + uintptr_t buf_begin = (uintptr_t)buf->data; + + if (data >= buf_begin && data < buf_begin + buf->size) + return buf; + } + for (int i = 0; i < frame->nb_extended_buf; i++) { + AVBufferRef *buf = frame->extended_buf[i]; + uintptr_t buf_begin = (uintptr_t)buf->data; + + if (data >= buf_begin && data < buf_begin + buf->size) + return buf; + } + return NULL; +} + +AVFrameSideData *av_frame_new_side_data_from_buf(AVFrame *frame, + enum AVFrameSideDataType type, + AVBufferRef *buf) +{ + return + ff_frame_side_data_add_from_buf( + &frame->side_data, &frame->nb_side_data, type, buf); +} + +AVFrameSideData *av_frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + size_t size) +{ + AVFrameSideData *ret; + AVBufferRef *buf = av_buffer_alloc(size); + ret = av_frame_new_side_data_from_buf(frame, type, buf); + if (!ret) + av_buffer_unref(&buf); + return ret; +} + +AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, + enum AVFrameSideDataType type) +{ + return (AVFrameSideData *)av_frame_side_data_get( + frame->side_data, frame->nb_side_data, + type + ); +} + +static int frame_copy_video(AVFrame *dst, const AVFrame *src) +{ + int planes; + + if (dst->width < src->width || + dst->height < src->height) + return AVERROR(EINVAL); + + if (src->hw_frames_ctx || dst->hw_frames_ctx) + return av_hwframe_transfer_data(dst, src, 0); + + planes = av_pix_fmt_count_planes(dst->format); + for (int i = 0; i < planes; i++) + if (!dst->data[i] || !src->data[i]) + return AVERROR(EINVAL); + + av_image_copy2(dst->data, dst->linesize, + src->data, src->linesize, + dst->format, src->width, src->height); + + return 0; +} + +static int frame_copy_audio(AVFrame *dst, const AVFrame *src) +{ + int planar = av_sample_fmt_is_planar(dst->format); + int channels = dst->ch_layout.nb_channels; + int planes = planar ? channels : 1; + + if (dst->nb_samples != src->nb_samples || + av_channel_layout_compare(&dst->ch_layout, &src->ch_layout)) + return AVERROR(EINVAL); + + for (int i = 0; i < planes; i++) + if (!dst->extended_data[i] || !src->extended_data[i]) + return AVERROR(EINVAL); + + av_samples_copy(dst->extended_data, src->extended_data, 0, 0, + dst->nb_samples, channels, dst->format); + + return 0; +} + +int av_frame_copy(AVFrame *dst, const AVFrame *src) +{ + if (dst->format != src->format || dst->format < 0) + return AVERROR(EINVAL); + + if (dst->width > 0 && dst->height > 0) + return frame_copy_video(dst, src); + else if (dst->nb_samples > 0 && + (av_channel_layout_check(&dst->ch_layout))) + return frame_copy_audio(dst, src); + + return AVERROR(EINVAL); +} + +void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type) +{ + av_frame_side_data_remove(&frame->side_data, &frame->nb_side_data, type); +} + +static int calc_cropping_offsets(size_t offsets[4], const AVFrame *frame, + const AVPixFmtDescriptor *desc) +{ + for (int i = 0; frame->data[i]; i++) { + const AVComponentDescriptor *comp = NULL; + int shift_x = (i == 1 || i == 2) ? desc->log2_chroma_w : 0; + int shift_y = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; + + if (desc->flags & AV_PIX_FMT_FLAG_PAL && i == 1) { + offsets[i] = 0; + break; + } + + /* find any component descriptor for this plane */ + for (int j = 0; j < desc->nb_components; j++) { + if (desc->comp[j].plane == i) { + comp = &desc->comp[j]; + break; + } + } + if (!comp) + return AVERROR_BUG; + + offsets[i] = (frame->crop_top >> shift_y) * frame->linesize[i] + + (frame->crop_left >> shift_x) * comp->step; + } + + return 0; +} + +int av_frame_apply_cropping(AVFrame *frame, int flags) +{ + const AVPixFmtDescriptor *desc; + size_t offsets[4]; + int ret; + + if (!(frame->width > 0 && frame->height > 0)) + return AVERROR(EINVAL); + + if (frame->crop_left >= INT_MAX - frame->crop_right || + frame->crop_top >= INT_MAX - frame->crop_bottom || + (frame->crop_left + frame->crop_right) >= frame->width || + (frame->crop_top + frame->crop_bottom) >= frame->height) + return AVERROR(ERANGE); + + desc = av_pix_fmt_desc_get(frame->format); + if (!desc) + return AVERROR_BUG; + + /* Apply just the right/bottom cropping for hwaccel formats. Bitstream + * formats cannot be easily handled here either (and corresponding decoders + * should not export any cropping anyway), so do the same for those as well. + * */ + if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_HWACCEL)) { + frame->width -= frame->crop_right; + frame->height -= frame->crop_bottom; + frame->crop_right = 0; + frame->crop_bottom = 0; + return 0; + } + + /* calculate the offsets for each plane */ + ret = calc_cropping_offsets(offsets, frame, desc); + if (ret < 0) + return ret; + + /* adjust the offsets to avoid breaking alignment */ + if (!(flags & AV_FRAME_CROP_UNALIGNED)) { + int log2_crop_align = frame->crop_left ? ff_ctz(frame->crop_left) : INT_MAX; + int min_log2_align = INT_MAX; + + for (int i = 0; frame->data[i]; i++) { + int log2_align = offsets[i] ? ff_ctz(offsets[i]) : INT_MAX; + min_log2_align = FFMIN(log2_align, min_log2_align); + } + + /* we assume, and it should always be true, that the data alignment is + * related to the cropping alignment by a constant power-of-2 factor */ + if (log2_crop_align < min_log2_align) + return AVERROR_BUG; + + if (min_log2_align < 5 && log2_crop_align != INT_MAX) { + frame->crop_left &= ~((1 << (5 + log2_crop_align - min_log2_align)) - 1); + ret = calc_cropping_offsets(offsets, frame, desc); + if (ret < 0) + return ret; + } + } + + for (int i = 0; frame->data[i]; i++) + frame->data[i] += offsets[i]; + + frame->width -= (frame->crop_left + frame->crop_right); + frame->height -= (frame->crop_top + frame->crop_bottom); + frame->crop_left = 0; + frame->crop_right = 0; + frame->crop_top = 0; + frame->crop_bottom = 0; + + return 0; +} diff --git a/libs/ffmpeg/libavutil/frame.h b/libs/ffmpeg/libavutil/frame.h new file mode 100644 index 00000000000..771c9ce4537 --- /dev/null +++ b/libs/ffmpeg/libavutil/frame.h @@ -0,0 +1,1176 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_frame + * reference-counted frame API + */ + +#ifndef AVUTIL_FRAME_H +#define AVUTIL_FRAME_H + +#include <stddef.h> +#include <stdint.h> + +#include "avutil.h" +#include "buffer.h" +#include "channel_layout.h" +#include "dict.h" +#include "rational.h" +#include "samplefmt.h" +#include "pixfmt.h" +#include "version.h" + + +/** + * @defgroup lavu_frame AVFrame + * @ingroup lavu_data + * + * @{ + * AVFrame is an abstraction for reference-counted raw multimedia data. + */ + +enum AVFrameSideDataType { + /** + * The data is the AVPanScan struct defined in libavcodec. + */ + AV_FRAME_DATA_PANSCAN, + /** + * ATSC A53 Part 4 Closed Captions. + * A53 CC bitstream is stored as uint8_t in AVFrameSideData.data. + * The number of bytes of CC data is AVFrameSideData.size. + */ + AV_FRAME_DATA_A53_CC, + /** + * Stereoscopic 3d metadata. + * The data is the AVStereo3D struct defined in libavutil/stereo3d.h. + */ + AV_FRAME_DATA_STEREO3D, + /** + * The data is the AVMatrixEncoding enum defined in libavutil/channel_layout.h. + */ + AV_FRAME_DATA_MATRIXENCODING, + /** + * Metadata relevant to a downmix procedure. + * The data is the AVDownmixInfo struct defined in libavutil/downmix_info.h. + */ + AV_FRAME_DATA_DOWNMIX_INFO, + /** + * ReplayGain information in the form of the AVReplayGain struct. + */ + AV_FRAME_DATA_REPLAYGAIN, + /** + * This side data contains a 3x3 transformation matrix describing an affine + * transformation that needs to be applied to the frame for correct + * presentation. + * + * See libavutil/display.h for a detailed description of the data. + */ + AV_FRAME_DATA_DISPLAYMATRIX, + /** + * Active Format Description data consisting of a single byte as specified + * in ETSI TS 101 154 using AVActiveFormatDescription enum. + */ + AV_FRAME_DATA_AFD, + /** + * Motion vectors exported by some codecs (on demand through the export_mvs + * flag set in the libavcodec AVCodecContext flags2 option). + * The data is the AVMotionVector struct defined in + * libavutil/motion_vector.h. + */ + AV_FRAME_DATA_MOTION_VECTORS, + /** + * Recommends skipping the specified number of samples. This is exported + * only if the "skip_manual" AVOption is set in libavcodec. + * This has the same format as AV_PKT_DATA_SKIP_SAMPLES. + * @code + * u32le number of samples to skip from start of this packet + * u32le number of samples to skip from end of this packet + * u8 reason for start skip + * u8 reason for end skip (0=padding silence, 1=convergence) + * @endcode + */ + AV_FRAME_DATA_SKIP_SAMPLES, + /** + * This side data must be associated with an audio frame and corresponds to + * enum AVAudioServiceType defined in avcodec.h. + */ + AV_FRAME_DATA_AUDIO_SERVICE_TYPE, + /** + * Mastering display metadata associated with a video frame. The payload is + * an AVMasteringDisplayMetadata type and contains information about the + * mastering display color volume. + */ + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA, + /** + * The GOP timecode in 25 bit timecode format. Data format is 64-bit integer. + * This is set on the first frame of a GOP that has a temporal reference of 0. + */ + AV_FRAME_DATA_GOP_TIMECODE, + + /** + * The data represents the AVSphericalMapping structure defined in + * libavutil/spherical.h. + */ + AV_FRAME_DATA_SPHERICAL, + + /** + * Content light level (based on CTA-861.3). This payload contains data in + * the form of the AVContentLightMetadata struct. + */ + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, + + /** + * The data contains an ICC profile as an opaque octet buffer following the + * format described by ISO 15076-1 with an optional name defined in the + * metadata key entry "name". + */ + AV_FRAME_DATA_ICC_PROFILE, + + /** + * Timecode which conforms to SMPTE ST 12-1. The data is an array of 4 uint32_t + * where the first uint32_t describes how many (1-3) of the other timecodes are used. + * The timecode format is described in the documentation of av_timecode_get_smpte_from_framenum() + * function in libavutil/timecode.h. + */ + AV_FRAME_DATA_S12M_TIMECODE, + + /** + * HDR dynamic metadata associated with a video frame. The payload is + * an AVDynamicHDRPlus type and contains information for color + * volume transform - application 4 of SMPTE 2094-40:2016 standard. + */ + AV_FRAME_DATA_DYNAMIC_HDR_PLUS, + + /** + * Regions Of Interest, the data is an array of AVRegionOfInterest type, the number of + * array element is implied by AVFrameSideData.size / AVRegionOfInterest.self_size. + */ + AV_FRAME_DATA_REGIONS_OF_INTEREST, + + /** + * Encoding parameters for a video frame, as described by AVVideoEncParams. + */ + AV_FRAME_DATA_VIDEO_ENC_PARAMS, + + /** + * User data unregistered metadata associated with a video frame. + * This is the H.26[45] UDU SEI message, and shouldn't be used for any other purpose + * The data is stored as uint8_t in AVFrameSideData.data which is 16 bytes of + * uuid_iso_iec_11578 followed by AVFrameSideData.size - 16 bytes of user_data_payload_byte. + */ + AV_FRAME_DATA_SEI_UNREGISTERED, + + /** + * Film grain parameters for a frame, described by AVFilmGrainParams. + * Must be present for every frame which should have film grain applied. + * + * May be present multiple times, for example when there are multiple + * alternative parameter sets for different video signal characteristics. + * The user should select the most appropriate set for the application. + */ + AV_FRAME_DATA_FILM_GRAIN_PARAMS, + + /** + * Bounding boxes for object detection and classification, + * as described by AVDetectionBBoxHeader. + */ + AV_FRAME_DATA_DETECTION_BBOXES, + + /** + * Dolby Vision RPU raw data, suitable for passing to x265 + * or other libraries. Array of uint8_t, with NAL emulation + * bytes intact. + */ + AV_FRAME_DATA_DOVI_RPU_BUFFER, + + /** + * Parsed Dolby Vision metadata, suitable for passing to a software + * implementation. The payload is the AVDOVIMetadata struct defined in + * libavutil/dovi_meta.h. + */ + AV_FRAME_DATA_DOVI_METADATA, + + /** + * HDR Vivid dynamic metadata associated with a video frame. The payload is + * an AVDynamicHDRVivid type and contains information for color + * volume transform - CUVA 005.1-2021. + */ + AV_FRAME_DATA_DYNAMIC_HDR_VIVID, + + /** + * Ambient viewing environment metadata, as defined by H.274. + */ + AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT, + + /** + * Provide encoder-specific hinting information about changed/unchanged + * portions of a frame. It can be used to pass information about which + * macroblocks can be skipped because they didn't change from the + * corresponding ones in the previous frame. This could be useful for + * applications which know this information in advance to speed up + * encoding. + */ + AV_FRAME_DATA_VIDEO_HINT, + + /** + * Raw LCEVC payload data, as a uint8_t array, with NAL emulation + * bytes intact. + */ + AV_FRAME_DATA_LCEVC, + + /** + * This side data must be associated with a video frame. + * The presence of this side data indicates that the video stream is + * composed of multiple views (e.g. stereoscopic 3D content, + * cf. H.264 Annex H or H.265 Annex G). + * The data is an int storing the view ID. + */ + AV_FRAME_DATA_VIEW_ID, + + /** + * This side data contains information about the reference display width(s) + * and reference viewing distance(s) as well as information about the + * corresponding reference stereo pair(s), i.e., the pair(s) of views to be + * displayed for the viewer's left and right eyes on the reference display + * at the reference viewing distance. + * The payload is the AV3DReferenceDisplaysInfo struct defined in + * libavutil/tdrdi.h. + */ + AV_FRAME_DATA_3D_REFERENCE_DISPLAYS, + + /** + * Extensible image file format metadata. The payload is a buffer containing + * EXIF metadata, starting with either 49 49 2a 00, or 4d 4d 00 2a. + */ + AV_FRAME_DATA_EXIF, +}; + +enum AVActiveFormatDescription { + AV_AFD_SAME = 8, + AV_AFD_4_3 = 9, + AV_AFD_16_9 = 10, + AV_AFD_14_9 = 11, + AV_AFD_4_3_SP_14_9 = 13, + AV_AFD_16_9_SP_14_9 = 14, + AV_AFD_SP_4_3 = 15, +}; + + +/** + * Structure to hold side data for an AVFrame. + * + * sizeof(AVFrameSideData) is not a part of the public ABI, so new fields may be added + * to the end with a minor bump. + */ +typedef struct AVFrameSideData { + enum AVFrameSideDataType type; + uint8_t *data; + size_t size; + AVDictionary *metadata; + AVBufferRef *buf; +} AVFrameSideData; + +enum AVSideDataProps { + /** + * The side data type can be used in stream-global structures. + * Side data types without this property are only meaningful on per-frame + * basis. + */ + AV_SIDE_DATA_PROP_GLOBAL = (1 << 0), + + /** + * Multiple instances of this side data type can be meaningfully present in + * a single side data array. + */ + AV_SIDE_DATA_PROP_MULTI = (1 << 1), + + /** + * Side data depends on the video dimensions. Side data with this property + * loses its meaning when rescaling or cropping the image, unless + * either recomputed or adjusted to the new resolution. + */ + AV_SIDE_DATA_PROP_SIZE_DEPENDENT = (1 << 2), + + /** + * Side data depends on the video color space. Side data with this property + * loses its meaning when changing the video color encoding, e.g. by + * adapting to a different set of primaries or transfer characteristics. + */ + AV_SIDE_DATA_PROP_COLOR_DEPENDENT = (1 << 3), + + /** + * Side data depends on the channel layout. Side data with this property + * loses its meaning when downmixing or upmixing, unless either recomputed + * or adjusted to the new layout. + */ + AV_SIDE_DATA_PROP_CHANNEL_DEPENDENT = (1 << 4), +}; + +/** + * This struct describes the properties of a side data type. Its instance + * corresponding to a given type can be obtained from av_frame_side_data_desc(). + */ +typedef struct AVSideDataDescriptor { + /** + * Human-readable side data description. + */ + const char *name; + + /** + * Side data property flags, a combination of AVSideDataProps values. + */ + unsigned props; +} AVSideDataDescriptor; + +/** + * Structure describing a single Region Of Interest. + * + * When multiple regions are defined in a single side-data block, they + * should be ordered from most to least important - some encoders are only + * capable of supporting a limited number of distinct regions, so will have + * to truncate the list. + * + * When overlapping regions are defined, the first region containing a given + * area of the frame applies. + */ +typedef struct AVRegionOfInterest { + /** + * Must be set to the size of this data structure (that is, + * sizeof(AVRegionOfInterest)). + */ + uint32_t self_size; + /** + * Distance in pixels from the top edge of the frame to the top and + * bottom edges and from the left edge of the frame to the left and + * right edges of the rectangle defining this region of interest. + * + * The constraints on a region are encoder dependent, so the region + * actually affected may be slightly larger for alignment or other + * reasons. + */ + int top; + int bottom; + int left; + int right; + /** + * Quantisation offset. + * + * Must be in the range -1 to +1. A value of zero indicates no quality + * change. A negative value asks for better quality (less quantisation), + * while a positive value asks for worse quality (greater quantisation). + * + * The range is calibrated so that the extreme values indicate the + * largest possible offset - if the rest of the frame is encoded with the + * worst possible quality, an offset of -1 indicates that this region + * should be encoded with the best possible quality anyway. Intermediate + * values are then interpolated in some codec-dependent way. + * + * For example, in 10-bit H.264 the quantisation parameter varies between + * -12 and 51. A typical qoffset value of -1/10 therefore indicates that + * this region should be encoded with a QP around one-tenth of the full + * range better than the rest of the frame. So, if most of the frame + * were to be encoded with a QP of around 30, this region would get a QP + * of around 24 (an offset of approximately -1/10 * (51 - -12) = -6.3). + * An extreme value of -1 would indicate that this region should be + * encoded with the best possible quality regardless of the treatment of + * the rest of the frame - that is, should be encoded at a QP of -12. + */ + AVRational qoffset; +} AVRegionOfInterest; + +/** + * This structure describes decoded (raw) audio or video data. + * + * AVFrame must be allocated using av_frame_alloc(). Note that this only + * allocates the AVFrame itself, the buffers for the data must be managed + * through other means (see below). + * AVFrame must be freed with av_frame_free(). + * + * AVFrame is typically allocated once and then reused multiple times to hold + * different data (e.g. a single AVFrame to hold frames received from a + * decoder). In such a case, av_frame_unref() will free any references held by + * the frame and reset it to its original clean state before it + * is reused again. + * + * The data described by an AVFrame is usually reference counted through the + * AVBuffer API. The underlying buffer references are stored in AVFrame.buf / + * AVFrame.extended_buf. An AVFrame is considered to be reference counted if at + * least one reference is set, i.e. if AVFrame.buf[0] != NULL. In such a case, + * every single data plane must be contained in one of the buffers in + * AVFrame.buf or AVFrame.extended_buf. + * There may be a single buffer for all the data, or one separate buffer for + * each plane, or anything in between. + * + * sizeof(AVFrame) is not a part of the public ABI, so new fields may be added + * to the end with a minor bump. + * + * Fields can be accessed through AVOptions, the name string used, matches the + * C structure field name for fields accessible through AVOptions. + */ +typedef struct AVFrame { +#define AV_NUM_DATA_POINTERS 8 + /** + * pointer to the picture/channel planes. + * This might be different from the first allocated byte. For video, + * it could even point to the end of the image data. + * + * All pointers in data and extended_data must point into one of the + * AVBufferRef in buf or extended_buf. + * + * Some decoders access areas outside 0,0 - width,height, please + * see avcodec_align_dimensions2(). Some filters and swscale can read + * up to 16 bytes beyond the planes, if these filters are to be used, + * then 16 extra bytes must be allocated. + * + * NOTE: Pointers not needed by the format MUST be set to NULL. + * + * @attention In case of video, the data[] pointers can point to the + * end of image data in order to reverse line order, when used in + * combination with negative values in the linesize[] array. + */ + uint8_t *data[AV_NUM_DATA_POINTERS]; + + /** + * For video, a positive or negative value, which is typically indicating + * the size in bytes of each picture line, but it can also be: + * - the negative byte size of lines for vertical flipping + * (with data[n] pointing to the end of the data + * - a positive or negative multiple of the byte size as for accessing + * even and odd fields of a frame (possibly flipped) + * + * For audio, only linesize[0] may be set. For planar audio, each channel + * plane must be the same size. + * + * For video the linesizes should be multiples of the CPUs alignment + * preference, this is 16 or 32 for modern desktop CPUs. + * Some code requires such alignment other code can be slower without + * correct alignment, for yet other it makes no difference. + * + * @note The linesize may be larger than the size of usable data -- there + * may be extra padding present for performance reasons. + * + * @attention In case of video, line size values can be negative to achieve + * a vertically inverted iteration over image lines. + */ + int linesize[AV_NUM_DATA_POINTERS]; + + /** + * pointers to the data planes/channels. + * + * For video, this should simply point to data[]. + * + * For planar audio, each channel has a separate data pointer, and + * linesize[0] contains the size of each channel buffer. + * For packed audio, there is just one data pointer, and linesize[0] + * contains the total size of the buffer for all channels. + * + * Note: Both data and extended_data should always be set in a valid frame, + * but for planar audio with more channels that can fit in data, + * extended_data must be used in order to access all channels. + */ + uint8_t **extended_data; + + /** + * @name Video dimensions + * Video frames only. The coded dimensions (in pixels) of the video frame, + * i.e. the size of the rectangle that contains some well-defined values. + * + * @note The part of the frame intended for display/presentation is further + * restricted by the @ref cropping "Cropping rectangle". + * @{ + */ + int width, height; + /** + * @} + */ + + /** + * number of audio samples (per channel) described by this frame + */ + int nb_samples; + + /** + * format of the frame, -1 if unknown or unset + * Values correspond to enum AVPixelFormat for video frames, + * enum AVSampleFormat for audio) + */ + int format; + + /** + * Picture type of the frame. + */ + enum AVPictureType pict_type; + + /** + * Sample aspect ratio for the video frame, 0/1 if unknown/unspecified. + */ + AVRational sample_aspect_ratio; + + /** + * Presentation timestamp in time_base units (time when frame should be shown to user). + */ + int64_t pts; + + /** + * DTS copied from the AVPacket that triggered returning this frame. (if frame threading isn't used) + * This is also the Presentation time of this AVFrame calculated from + * only AVPacket.dts values without pts values. + */ + int64_t pkt_dts; + + /** + * Time base for the timestamps in this frame. + * In the future, this field may be set on frames output by decoders or + * filters, but its value will be by default ignored on input to encoders + * or filters. + */ + AVRational time_base; + + /** + * quality (between 1 (good) and FF_LAMBDA_MAX (bad)) + */ + int quality; + + /** + * Frame owner's private data. + * + * This field may be set by the code that allocates/owns the frame data. + * It is then not touched by any library functions, except: + * - it is copied to other references by av_frame_copy_props() (and hence by + * av_frame_ref()); + * - it is set to NULL when the frame is cleared by av_frame_unref() + * - on the caller's explicit request. E.g. libavcodec encoders/decoders + * will copy this field to/from @ref AVPacket "AVPackets" if the caller sets + * @ref AV_CODEC_FLAG_COPY_OPAQUE. + * + * @see opaque_ref the reference-counted analogue + */ + void *opaque; + + /** + * Number of fields in this frame which should be repeated, i.e. the total + * duration of this frame should be repeat_pict + 2 normal field durations. + * + * For interlaced frames this field may be set to 1, which signals that this + * frame should be presented as 3 fields: beginning with the first field (as + * determined by AV_FRAME_FLAG_TOP_FIELD_FIRST being set or not), followed + * by the second field, and then the first field again. + * + * For progressive frames this field may be set to a multiple of 2, which + * signals that this frame's duration should be (repeat_pict + 2) / 2 + * normal frame durations. + * + * @note This field is computed from MPEG2 repeat_first_field flag and its + * associated flags, H.264 pic_struct from picture timing SEI, and + * their analogues in other codecs. Typically it should only be used when + * higher-layer timing information is not available. + */ + int repeat_pict; + + /** + * Sample rate of the audio data. + */ + int sample_rate; + + /** + * AVBuffer references backing the data for this frame. All the pointers in + * data and extended_data must point inside one of the buffers in buf or + * extended_buf. This array must be filled contiguously -- if buf[i] is + * non-NULL then buf[j] must also be non-NULL for all j < i. + * + * There may be at most one AVBuffer per data plane, so for video this array + * always contains all the references. For planar audio with more than + * AV_NUM_DATA_POINTERS channels, there may be more buffers than can fit in + * this array. Then the extra AVBufferRef pointers are stored in the + * extended_buf array. + */ + AVBufferRef *buf[AV_NUM_DATA_POINTERS]; + + /** + * For planar audio which requires more than AV_NUM_DATA_POINTERS + * AVBufferRef pointers, this array will hold all the references which + * cannot fit into AVFrame.buf. + * + * Note that this is different from AVFrame.extended_data, which always + * contains all the pointers. This array only contains the extra pointers, + * which cannot fit into AVFrame.buf. + * + * This array is always allocated using av_malloc() by whoever constructs + * the frame. It is freed in av_frame_unref(). + */ + AVBufferRef **extended_buf; + /** + * Number of elements in extended_buf. + */ + int nb_extended_buf; + + AVFrameSideData **side_data; + int nb_side_data; + +/** + * @defgroup lavu_frame_flags AV_FRAME_FLAGS + * @ingroup lavu_frame + * Flags describing additional frame properties. + * + * @{ + */ + +/** + * The frame data may be corrupted, e.g. due to decoding errors. + */ +#define AV_FRAME_FLAG_CORRUPT (1 << 0) +/** + * A flag to mark frames that are keyframes. + */ +#define AV_FRAME_FLAG_KEY (1 << 1) +/** + * A flag to mark the frames which need to be decoded, but shouldn't be output. + */ +#define AV_FRAME_FLAG_DISCARD (1 << 2) +/** + * A flag to mark frames whose content is interlaced. + */ +#define AV_FRAME_FLAG_INTERLACED (1 << 3) +/** + * A flag to mark frames where the top field is displayed first if the content + * is interlaced. + */ +#define AV_FRAME_FLAG_TOP_FIELD_FIRST (1 << 4) +/** + * A decoder can use this flag to mark frames which were originally encoded losslessly. + * + * For coding bitstream formats which support both lossless and lossy + * encoding, it is sometimes possible for a decoder to determine which method + * was used when the bitstream was encoded. + */ +#define AV_FRAME_FLAG_LOSSLESS (1 << 5) +/** + * @} + */ + + /** + * Frame flags, a combination of @ref lavu_frame_flags + */ + int flags; + + /** + * MPEG vs JPEG YUV range. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorRange color_range; + + enum AVColorPrimaries color_primaries; + + enum AVColorTransferCharacteristic color_trc; + + /** + * YUV colorspace type. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorSpace colorspace; + + enum AVChromaLocation chroma_location; + + /** + * frame timestamp estimated using various heuristics, in stream time base + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int64_t best_effort_timestamp; + + /** + * metadata. + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + AVDictionary *metadata; + + /** + * decode error flags of the frame, set to a combination of + * FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there + * were errors during the decoding. + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int decode_error_flags; +#define FF_DECODE_ERROR_INVALID_BITSTREAM 1 +#define FF_DECODE_ERROR_MISSING_REFERENCE 2 +#define FF_DECODE_ERROR_CONCEALMENT_ACTIVE 4 +#define FF_DECODE_ERROR_DECODE_SLICES 8 + + /** + * For hwaccel-format frames, this should be a reference to the + * AVHWFramesContext describing the frame. + */ + AVBufferRef *hw_frames_ctx; + + /** + * Frame owner's private data. + * + * This field may be set by the code that allocates/owns the frame data. + * It is then not touched by any library functions, except: + * - a new reference to the underlying buffer is propagated by + * av_frame_copy_props() (and hence by av_frame_ref()); + * - it is unreferenced in av_frame_unref(); + * - on the caller's explicit request. E.g. libavcodec encoders/decoders + * will propagate a new reference to/from @ref AVPacket "AVPackets" if the + * caller sets @ref AV_CODEC_FLAG_COPY_OPAQUE. + * + * @see opaque the plain pointer analogue + */ + AVBufferRef *opaque_ref; + + /** + * @anchor cropping + * @name Cropping + * Video frames only. The number of pixels to discard from the + * top/bottom/left/right border of the frame to obtain the sub-rectangle of + * the frame intended for presentation. + * @{ + */ + size_t crop_top; + size_t crop_bottom; + size_t crop_left; + size_t crop_right; + /** + * @} + */ + + /** + * RefStruct reference for internal use by a single libav* library. + * Must not be used to transfer data between libraries. + * Has to be NULL when ownership of the frame leaves the respective library. + * + * Code outside the FFmpeg libs must never check or change private_ref. + */ + void *private_ref; + + /** + * Channel layout of the audio data. + */ + AVChannelLayout ch_layout; + + /** + * Duration of the frame, in the same units as pts. 0 if unknown. + */ + int64_t duration; + + /** + * Indicates how the alpha channel of the video is to be handled. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVAlphaMode alpha_mode; +} AVFrame; + + +/** + * Allocate an AVFrame and set its fields to default values. The resulting + * struct must be freed using av_frame_free(). + * + * @return An AVFrame filled with default values or NULL on failure. + * + * @note this only allocates the AVFrame itself, not the data buffers. Those + * must be allocated through other means, e.g. with av_frame_get_buffer() or + * manually. + */ +AVFrame *av_frame_alloc(void); + +/** + * Free the frame and any dynamically allocated objects in it, + * e.g. extended_data. If the frame is reference counted, it will be + * unreferenced first. + * + * @param frame frame to be freed. The pointer will be set to NULL. + */ +void av_frame_free(AVFrame **frame); + +/** + * Set up a new reference to the data described by the source frame. + * + * Copy frame properties from src to dst and create a new reference for each + * AVBufferRef from src. + * + * If src is not reference counted, new buffers are allocated and the data is + * copied. + * + * @warning: dst MUST have been either unreferenced with av_frame_unref(dst), + * or newly allocated with av_frame_alloc() before calling this + * function, or undefined behavior will occur. + * + * @return 0 on success, a negative AVERROR on error + */ +int av_frame_ref(AVFrame *dst, const AVFrame *src); + +/** + * Ensure the destination frame refers to the same data described by the source + * frame, either by creating a new reference for each AVBufferRef from src if + * they differ from those in dst, by allocating new buffers and copying data if + * src is not reference counted, or by unreferencing it if src is empty. + * + * Frame properties on dst will be replaced by those from src. + * + * @return 0 on success, a negative AVERROR on error. On error, dst is + * unreferenced. + */ +int av_frame_replace(AVFrame *dst, const AVFrame *src); + +/** + * Create a new frame that references the same data as src. + * + * This is a shortcut for av_frame_alloc()+av_frame_ref(). + * + * @return newly created AVFrame on success, NULL on error. + */ +AVFrame *av_frame_clone(const AVFrame *src); + +/** + * Unreference all the buffers referenced by frame and reset the frame fields. + */ +void av_frame_unref(AVFrame *frame); + +/** + * Move everything contained in src to dst and reset src. + * + * @warning: dst is not unreferenced, but directly overwritten without reading + * or deallocating its contents. Call av_frame_unref(dst) manually + * before calling this function to ensure that no memory is leaked. + */ +void av_frame_move_ref(AVFrame *dst, AVFrame *src); + +/** + * Allocate new buffer(s) for audio or video data. + * + * The following fields must be set on frame before calling this function: + * - format (pixel format for video, sample format for audio) + * - width and height for video + * - nb_samples and ch_layout for audio + * + * This function will fill AVFrame.data and AVFrame.buf arrays and, if + * necessary, allocate and fill AVFrame.extended_data and AVFrame.extended_buf. + * For planar formats, one buffer will be allocated for each plane. + * + * @warning: if frame already has been allocated, calling this function will + * leak memory. In addition, undefined behavior can occur in certain + * cases. + * + * @param frame frame in which to store the new buffers. + * @param align Required buffer size and data pointer alignment. If equal to 0, + * alignment will be chosen automatically for the current CPU. + * It is highly recommended to pass 0 here unless you know what + * you are doing. + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_frame_get_buffer(AVFrame *frame, int align); + +/** + * Check if the frame data is writable. + * + * @return A positive value if the frame data is writable (which is true if and + * only if each of the underlying buffers has only one reference, namely the one + * stored in this frame). Return 0 otherwise. + * + * If 1 is returned the answer is valid until av_buffer_ref() is called on any + * of the underlying AVBufferRefs (e.g. through av_frame_ref() or directly). + * + * @see av_frame_make_writable(), av_buffer_is_writable() + */ +int av_frame_is_writable(AVFrame *frame); + +/** + * Ensure that the frame data is writable, avoiding data copy if possible. + * + * Do nothing if the frame is writable, allocate new buffers and copy the data + * if it is not. Non-refcounted frames behave as non-writable, i.e. a copy + * is always made. + * + * @return 0 on success, a negative AVERROR on error. + * + * @see av_frame_is_writable(), av_buffer_is_writable(), + * av_buffer_make_writable() + */ +int av_frame_make_writable(AVFrame *frame); + +/** + * Copy the frame data from src to dst. + * + * This function does not allocate anything, dst must be already initialized and + * allocated with the same parameters as src. + * + * This function only copies the frame data (i.e. the contents of the data / + * extended data arrays), not any other properties. + * + * @return >= 0 on success, a negative AVERROR on error. + */ +int av_frame_copy(AVFrame *dst, const AVFrame *src); + +/** + * Copy only "metadata" fields from src to dst. + * + * Metadata for the purpose of this function are those fields that do not affect + * the data layout in the buffers. E.g. pts, sample rate (for audio) or sample + * aspect ratio (for video), but not width/height or channel layout. + * Side data is also copied. + */ +int av_frame_copy_props(AVFrame *dst, const AVFrame *src); + +/** + * Get the buffer reference a given data plane is stored in. + * + * @param frame the frame to get the plane's buffer from + * @param plane index of the data plane of interest in frame->extended_data. + * + * @return the buffer reference that contains the plane or NULL if the input + * frame is not valid. + */ +AVBufferRef *av_frame_get_plane_buffer(const AVFrame *frame, int plane); + +/** + * Add a new side data to a frame. + * + * @param frame a frame to which the side data should be added + * @param type type of the added side data + * @param size size of the side data + * + * @return newly added side data on success, NULL on error + */ +AVFrameSideData *av_frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + size_t size); + +/** + * Add a new side data to a frame from an existing AVBufferRef + * + * @param frame a frame to which the side data should be added + * @param type the type of the added side data + * @param buf an AVBufferRef to add as side data. The ownership of + * the reference is transferred to the frame. + * + * @return newly added side data on success, NULL on error. On failure + * the frame is unchanged and the AVBufferRef remains owned by + * the caller. + */ +AVFrameSideData *av_frame_new_side_data_from_buf(AVFrame *frame, + enum AVFrameSideDataType type, + AVBufferRef *buf); + +/** + * @return a pointer to the side data of a given type on success, NULL if there + * is no side data with such type in this frame. + */ +AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, + enum AVFrameSideDataType type); + +/** + * Remove and free all side data instances of the given type. + */ +void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type); + + +/** + * Flags for frame cropping. + */ +enum { + /** + * Apply the maximum possible cropping, even if it requires setting the + * AVFrame.data[] entries to unaligned pointers. Passing unaligned data + * to FFmpeg API is generally not allowed, and causes undefined behavior + * (such as crashes). You can pass unaligned data only to FFmpeg APIs that + * are explicitly documented to accept it. Use this flag only if you + * absolutely know what you are doing. + */ + AV_FRAME_CROP_UNALIGNED = 1 << 0, +}; + +/** + * Crop the given video AVFrame according to its crop_left/crop_top/crop_right/ + * crop_bottom fields. If cropping is successful, the function will adjust the + * data pointers and the width/height fields, and set the crop fields to 0. + * + * In all cases, the cropping boundaries will be rounded to the inherent + * alignment of the pixel format. In some cases, such as for opaque hwaccel + * formats, the left/top cropping is ignored. The crop fields are set to 0 even + * if the cropping was rounded or ignored. + * + * @param frame the frame which should be cropped + * @param flags Some combination of AV_FRAME_CROP_* flags, or 0. + * + * @return >= 0 on success, a negative AVERROR on error. If the cropping fields + * were invalid, AVERROR(ERANGE) is returned, and nothing is changed. + */ +int av_frame_apply_cropping(AVFrame *frame, int flags); + +/** + * @return a string identifying the side data type + */ +const char *av_frame_side_data_name(enum AVFrameSideDataType type); + +/** + * @return side data descriptor corresponding to a given side data type, NULL + * when not available. + */ +const AVSideDataDescriptor *av_frame_side_data_desc(enum AVFrameSideDataType type); + +/** + * Free all side data entries and their contents, then zeroes out the + * values which the pointers are pointing to. + * + * @param sd pointer to array of side data to free. Will be set to NULL + * upon return. + * @param nb_sd pointer to an integer containing the number of entries in + * the array. Will be set to 0 upon return. + */ +void av_frame_side_data_free(AVFrameSideData ***sd, int *nb_sd); + +/** + * Remove existing entries before adding new ones. + */ +#define AV_FRAME_SIDE_DATA_FLAG_UNIQUE (1 << 0) +/** + * Don't add a new entry if another of the same type exists. + * Applies only for side data types without the AV_SIDE_DATA_PROP_MULTI prop. + */ +#define AV_FRAME_SIDE_DATA_FLAG_REPLACE (1 << 1) +/** + * Create a new reference to the passed in buffer instead of taking ownership + * of it. + */ +#define AV_FRAME_SIDE_DATA_FLAG_NEW_REF (1 << 2) + +/** + * Add new side data entry to an array. + * + * @param sd pointer to array of side data to which to add another entry, + * or to NULL in order to start a new array. + * @param nb_sd pointer to an integer containing the number of entries in + * the array. + * @param type type of the added side data + * @param size size of the side data + * @param flags Some combination of AV_FRAME_SIDE_DATA_FLAG_* flags, or 0. + * + * @return newly added side data on success, NULL on error. + * @note In case of AV_FRAME_SIDE_DATA_FLAG_UNIQUE being set, entries of + * matching AVFrameSideDataType will be removed before the addition + * is attempted. + * @note In case of AV_FRAME_SIDE_DATA_FLAG_REPLACE being set, if an + * entry of the same type already exists, it will be replaced instead. + */ +AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd, + enum AVFrameSideDataType type, + size_t size, unsigned int flags); + +/** + * Add a new side data entry to an array from an existing AVBufferRef. + * + * @param sd pointer to array of side data to which to add another entry, + * or to NULL in order to start a new array. + * @param nb_sd pointer to an integer containing the number of entries in + * the array. + * @param type type of the added side data + * @param buf Pointer to AVBufferRef to add to the array. On success, + * the function takes ownership of the AVBufferRef and *buf is + * set to NULL, unless AV_FRAME_SIDE_DATA_FLAG_NEW_REF is set + * in which case the ownership will remain with the caller. + * @param flags Some combination of AV_FRAME_SIDE_DATA_FLAG_* flags, or 0. + * + * @return newly added side data on success, NULL on error. + * @note In case of AV_FRAME_SIDE_DATA_FLAG_UNIQUE being set, entries of + * matching AVFrameSideDataType will be removed before the addition + * is attempted. + * @note In case of AV_FRAME_SIDE_DATA_FLAG_REPLACE being set, if an + * entry of the same type already exists, it will be replaced instead. + * + */ +AVFrameSideData *av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd, + enum AVFrameSideDataType type, + AVBufferRef **buf, unsigned int flags); + +/** + * Add a new side data entry to an array based on existing side data, taking + * a reference towards the contained AVBufferRef. + * + * @param sd pointer to array of side data to which to add another entry, + * or to NULL in order to start a new array. + * @param nb_sd pointer to an integer containing the number of entries in + * the array. + * @param src side data to be cloned, with a new reference utilized + * for the buffer. + * @param flags Some combination of AV_FRAME_SIDE_DATA_FLAG_* flags, or 0. + * + * @return negative error code on failure, >=0 on success. + * @note In case of AV_FRAME_SIDE_DATA_FLAG_UNIQUE being set, entries of + * matching AVFrameSideDataType will be removed before the addition + * is attempted. + * @note In case of AV_FRAME_SIDE_DATA_FLAG_REPLACE being set, if an + * entry of the same type already exists, it will be replaced instead. + */ +int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd, + const AVFrameSideData *src, unsigned int flags); + +/** + * Get a side data entry of a specific type from an array. + * + * @param sd array of side data. + * @param nb_sd integer containing the number of entries in the array. + * @param type type of side data to be queried + * + * @return a pointer to the side data of a given type on success, NULL if there + * is no side data with such type in this set. + */ +const AVFrameSideData *av_frame_side_data_get_c(const AVFrameSideData * const *sd, + const int nb_sd, + enum AVFrameSideDataType type); + +/** + * Wrapper around av_frame_side_data_get_c() to workaround the limitation + * that for any type T the conversion from T * const * to const T * const * + * is not performed automatically in C. + * @see av_frame_side_data_get_c() + */ +static inline +const AVFrameSideData *av_frame_side_data_get(AVFrameSideData * const *sd, + const int nb_sd, + enum AVFrameSideDataType type) +{ + return av_frame_side_data_get_c((const AVFrameSideData * const *)sd, + nb_sd, type); +} + +/** + * Remove and free all side data instances of the given type from an array. + */ +void av_frame_side_data_remove(AVFrameSideData ***sd, int *nb_sd, + enum AVFrameSideDataType type); + +/** + * Remove and free all side data instances that match any of the given + * side data properties. (See enum AVSideDataProps) + */ +void av_frame_side_data_remove_by_props(AVFrameSideData ***sd, int *nb_sd, + int props); + +/** + * @} + */ + +#endif /* AVUTIL_FRAME_H */ diff --git a/libs/ffmpeg/libavutil/half2float.c b/libs/ffmpeg/libavutil/half2float.c new file mode 100644 index 00000000000..4de2180a197 --- /dev/null +++ b/libs/ffmpeg/libavutil/half2float.c @@ -0,0 +1,67 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/half2float.h" + +#if !HAVE_FAST_FLOAT16 +static uint32_t convertmantissa(uint32_t i) +{ + int32_t m = i << 13; // Zero pad mantissa bits + int32_t e = 0; // Zero exponent + + while (!(m & 0x00800000)) { // While not normalized + e -= 0x00800000; // Decrement exponent (1<<23) + m <<= 1; // Shift mantissa + } + + m &= ~0x00800000; // Clear leading 1 bit + e += 0x38800000; // Adjust bias ((127-14)<<23) + + return m | e; // Return combined number +} +#endif + +void ff_init_half2float_tables(Half2FloatTables *t) +{ +#if !HAVE_FAST_FLOAT16 + t->mantissatable[0] = 0; + for (int i = 1; i < 1024; i++) + t->mantissatable[i] = convertmantissa(i); + for (int i = 1024; i < 2048; i++) + t->mantissatable[i] = 0x38000000UL + ((i - 1024) << 13UL); + for (int i = 2048; i < 3072; i++) + t->mantissatable[i] = t->mantissatable[i - 1024] | 0x400000UL; + t->mantissatable[2048] = t->mantissatable[1024]; + + t->exponenttable[0] = 0; + for (int i = 1; i < 31; i++) + t->exponenttable[i] = i << 23; + for (int i = 33; i < 63; i++) + t->exponenttable[i] = 0x80000000UL + ((i - 32) << 23UL); + t->exponenttable[31]= 0x47800000UL; + t->exponenttable[32]= 0x80000000UL; + t->exponenttable[63]= 0xC7800000UL; + + t->offsettable[0] = 0; + for (int i = 1; i < 64; i++) + t->offsettable[i] = 1024; + t->offsettable[31] = 2048; + t->offsettable[32] = 0; + t->offsettable[63] = 2048; +#endif +} diff --git a/libs/ffmpeg/libavutil/half2float.h b/libs/ffmpeg/libavutil/half2float.h new file mode 100644 index 00000000000..dbd5e7150fb --- /dev/null +++ b/libs/ffmpeg/libavutil/half2float.h @@ -0,0 +1,57 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HALF2FLOAT_H +#define AVUTIL_HALF2FLOAT_H + +#include <stdint.h> +#include "intfloat.h" + +#include "config.h" + +typedef struct Half2FloatTables { +#if HAVE_FAST_FLOAT16 + uint8_t dummy; +#else + uint32_t mantissatable[3072]; + uint32_t exponenttable[64]; + uint16_t offsettable[64]; +#endif +} Half2FloatTables; + +void ff_init_half2float_tables(Half2FloatTables *t); + +static inline uint32_t half2float(uint16_t h, const Half2FloatTables *t) +{ +#if HAVE_FAST_FLOAT16 + union { + _Float16 f; + uint16_t i; + } u; + u.i = h; + return av_float2int(u.f); +#else + uint32_t f; + + f = t->mantissatable[t->offsettable[h >> 10] + (h & 0x3ff)] + t->exponenttable[h >> 10]; + + return f; +#endif +} + +#endif /* AVUTIL_HALF2FLOAT_H */ diff --git a/libs/ffmpeg/libavutil/hash.c b/libs/ffmpeg/libavutil/hash.c new file mode 100644 index 00000000000..fbc24194dea --- /dev/null +++ b/libs/ffmpeg/libavutil/hash.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2013 Reimar Döffinger <Reimar.Doeffinger@gmx.de> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <assert.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include "hash.h" + +#include "adler32.h" +#include "crc.h" +#include "md5.h" +#include "murmur3.h" +#include "ripemd.h" +#include "sha.h" +#include "sha512.h" + +#include "avstring.h" +#include "base64.h" +#include "error.h" +#include "intreadwrite.h" +#include "mem.h" + +// ENTRY(HASH_TYPE, HASH_NAME, HASH_SIZE) +#define HASHES(ENTRY) \ + ENTRY(MD5, "MD5", 16) \ + ENTRY(MURMUR3, "murmur3", 16) \ + ENTRY(RIPEMD128, "RIPEMD128", 16) \ + ENTRY(RIPEMD160, "RIPEMD160", 20) \ + ENTRY(RIPEMD256, "RIPEMD256", 32) \ + ENTRY(RIPEMD320, "RIPEMD320", 40) \ + ENTRY(SHA160, "SHA160", 20) \ + ENTRY(SHA224, "SHA224", 28) \ + ENTRY(SHA256, "SHA256", 32) \ + ENTRY(SHA512_224, "SHA512/224", 28) \ + ENTRY(SHA512_256, "SHA512/256", 32) \ + ENTRY(SHA384, "SHA384", 48) \ + ENTRY(SHA512, "SHA512", 64) \ + ENTRY(CRC32, "CRC32", 4) \ + ENTRY(ADLER32, "adler32", 4) \ + +enum hashtype { +#define HASH_TYPE(TYPE, NAME, SIZE) TYPE, + HASHES(HASH_TYPE) + NUM_HASHES +}; + +typedef struct AVHashContext { + void *ctx; + enum hashtype type; + const AVCRC *crctab; + uint32_t crc; +} AVHashContext; + +#define HASH_MAX_SIZE(TYPE, NAME, SIZE) \ + HASH_MAX_SIZE_BEFORE_ ## TYPE, \ + HASH_MAX_SIZE_UNTIL_ ## TYPE ## _MINUS_ONE = FFMAX(SIZE, HASH_MAX_SIZE_BEFORE_ ## TYPE) - 1, +enum { + HASHES(HASH_MAX_SIZE) + MAX_HASH_SIZE +}; +static_assert(AV_HASH_MAX_SIZE >= MAX_HASH_SIZE, "AV_HASH_MAX_SIZE needs to be updated!"); + +#define HASH_MAX_NAME_SIZE(TYPE, NAME, SIZE) \ + HASH_MAX_NAME_SIZE_BEFORE_ ## TYPE, \ + HASH_MAX_NAME_SIZE_UNTIL_ ## TYPE ## _MINUS_ONE = FFMAX(sizeof(NAME), HASH_MAX_NAME_SIZE_BEFORE_ ## TYPE) - 1, +enum { + HASHES(HASH_MAX_NAME_SIZE) + MAX_HASH_NAME_SIZE +}; + +static const struct { + const char name[MAX_HASH_NAME_SIZE]; + int size; +} hashdesc[] = { +#define HASH_DESC(TYPE, NAME, SIZE) [TYPE] = { NAME, SIZE }, + HASHES(HASH_DESC) +}; + +const char *av_hash_names(int i) +{ + if (i < 0 || i >= NUM_HASHES) return NULL; + return hashdesc[i].name; +} + +const char *av_hash_get_name(const AVHashContext *ctx) +{ + return hashdesc[ctx->type].name; +} + +int av_hash_get_size(const AVHashContext *ctx) +{ + return hashdesc[ctx->type].size; +} + +int av_hash_alloc(AVHashContext **ctx, const char *name) +{ + AVHashContext *res; + int i; + *ctx = NULL; + for (i = 0; i < NUM_HASHES; i++) + if (av_strcasecmp(name, hashdesc[i].name) == 0) + break; + if (i >= NUM_HASHES) return AVERROR(EINVAL); + res = av_mallocz(sizeof(*res)); + if (!res) return AVERROR(ENOMEM); + res->type = i; + switch (i) { + case MD5: res->ctx = av_md5_alloc(); break; + case MURMUR3: res->ctx = av_murmur3_alloc(); break; + case RIPEMD128: + case RIPEMD160: + case RIPEMD256: + case RIPEMD320: res->ctx = av_ripemd_alloc(); break; + case SHA160: + case SHA224: + case SHA256: res->ctx = av_sha_alloc(); break; + case SHA512_224: + case SHA512_256: + case SHA384: + case SHA512: res->ctx = av_sha512_alloc(); break; + case CRC32: res->crctab = av_crc_get_table(AV_CRC_32_IEEE_LE); break; + case ADLER32: break; + } + if (i != ADLER32 && i != CRC32 && !res->ctx) { + av_free(res); + return AVERROR(ENOMEM); + } + *ctx = res; + return 0; +} + +void av_hash_init(AVHashContext *ctx) +{ + switch (ctx->type) { + case MD5: av_md5_init(ctx->ctx); break; + case MURMUR3: av_murmur3_init(ctx->ctx); break; + case RIPEMD128: av_ripemd_init(ctx->ctx, 128); break; + case RIPEMD160: av_ripemd_init(ctx->ctx, 160); break; + case RIPEMD256: av_ripemd_init(ctx->ctx, 256); break; + case RIPEMD320: av_ripemd_init(ctx->ctx, 320); break; + case SHA160: av_sha_init(ctx->ctx, 160); break; + case SHA224: av_sha_init(ctx->ctx, 224); break; + case SHA256: av_sha_init(ctx->ctx, 256); break; + case SHA512_224: av_sha512_init(ctx->ctx, 224); break; + case SHA512_256: av_sha512_init(ctx->ctx, 256); break; + case SHA384: av_sha512_init(ctx->ctx, 384); break; + case SHA512: av_sha512_init(ctx->ctx, 512); break; + case CRC32: ctx->crc = UINT32_MAX; break; + case ADLER32: ctx->crc = 1; break; + } +} + +void av_hash_update(AVHashContext *ctx, const uint8_t *src, size_t len) +{ + switch (ctx->type) { + case MD5: av_md5_update(ctx->ctx, src, len); break; + case MURMUR3: av_murmur3_update(ctx->ctx, src, len); break; + case RIPEMD128: + case RIPEMD160: + case RIPEMD256: + case RIPEMD320: av_ripemd_update(ctx->ctx, src, len); break; + case SHA160: + case SHA224: + case SHA256: av_sha_update(ctx->ctx, src, len); break; + case SHA512_224: + case SHA512_256: + case SHA384: + case SHA512: av_sha512_update(ctx->ctx, src, len); break; + case CRC32: ctx->crc = av_crc(ctx->crctab, ctx->crc, src, len); break; + case ADLER32: ctx->crc = av_adler32_update(ctx->crc, src, len); break; + } +} + +void av_hash_final(AVHashContext *ctx, uint8_t *dst) +{ + switch (ctx->type) { + case MD5: av_md5_final(ctx->ctx, dst); break; + case MURMUR3: av_murmur3_final(ctx->ctx, dst); break; + case RIPEMD128: + case RIPEMD160: + case RIPEMD256: + case RIPEMD320: av_ripemd_final(ctx->ctx, dst); break; + case SHA160: + case SHA224: + case SHA256: av_sha_final(ctx->ctx, dst); break; + case SHA512_224: + case SHA512_256: + case SHA384: + case SHA512: av_sha512_final(ctx->ctx, dst); break; + case CRC32: AV_WB32(dst, ctx->crc ^ UINT32_MAX); break; + case ADLER32: AV_WB32(dst, ctx->crc); break; + } +} + +void av_hash_final_bin(struct AVHashContext *ctx, uint8_t *dst, int size) +{ + uint8_t buf[AV_HASH_MAX_SIZE]; + unsigned rsize = av_hash_get_size(ctx); + + av_hash_final(ctx, buf); + memcpy(dst, buf, FFMIN(size, rsize)); + if (size > rsize) + memset(dst + rsize, 0, size - rsize); +} + +void av_hash_final_hex(struct AVHashContext *ctx, uint8_t *dst, int size) +{ + uint8_t buf[AV_HASH_MAX_SIZE]; + unsigned rsize = av_hash_get_size(ctx), i; + + av_hash_final(ctx, buf); + for (i = 0; i < FFMIN(rsize, size / 2); i++) + snprintf(dst + i * 2, size - i * 2, "%02x", buf[i]); +} + +void av_hash_final_b64(struct AVHashContext *ctx, uint8_t *dst, int size) +{ + uint8_t buf[AV_HASH_MAX_SIZE], b64[AV_BASE64_SIZE(AV_HASH_MAX_SIZE)]; + unsigned rsize = av_hash_get_size(ctx), osize; + + av_hash_final(ctx, buf); + av_base64_encode(b64, sizeof(b64), buf, rsize); + osize = AV_BASE64_SIZE(rsize); + memcpy(dst, b64, FFMIN(osize, size)); + if (size < osize) + dst[size - 1] = 0; +} + +void av_hash_freep(AVHashContext **ctx) +{ + if (*ctx) + av_freep(&(*ctx)->ctx); + av_freep(ctx); +} diff --git a/libs/ffmpeg/libavutil/hash.h b/libs/ffmpeg/libavutil/hash.h new file mode 100644 index 00000000000..94151ded7cb --- /dev/null +++ b/libs/ffmpeg/libavutil/hash.h @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2013 Reimar Döffinger <Reimar.Doeffinger@gmx.de> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_hash_generic + * Generic hashing API + */ + +#ifndef AVUTIL_HASH_H +#define AVUTIL_HASH_H + +#include <stddef.h> +#include <stdint.h> + +/** + * @defgroup lavu_hash Hash Functions + * @ingroup lavu_crypto + * Hash functions useful in multimedia. + * + * Hash functions are widely used in multimedia, from error checking and + * concealment to internal regression testing. libavutil has efficient + * implementations of a variety of hash functions that may be useful for + * FFmpeg and other multimedia applications. + * + * @{ + * + * @defgroup lavu_hash_generic Generic Hashing API + * An abstraction layer for all hash functions supported by libavutil. + * + * If your application needs to support a wide range of different hash + * functions, then the Generic Hashing API is for you. It provides a generic, + * reusable API for @ref lavu_hash "all hash functions" implemented in libavutil. + * If you just need to use one particular hash function, use the @ref lavu_hash + * "individual hash" directly. + * + * @section Sample Code + * + * A basic template for using the Generic Hashing API follows: + * + * @code + * struct AVHashContext *ctx = NULL; + * const char *hash_name = NULL; + * uint8_t *output_buf = NULL; + * + * // Select from a string returned by av_hash_names() + * hash_name = ...; + * + * // Allocate a hash context + * ret = av_hash_alloc(&ctx, hash_name); + * if (ret < 0) + * return ret; + * + * // Initialize the hash context + * av_hash_init(ctx); + * + * // Update the hash context with data + * while (data_left) { + * av_hash_update(ctx, data, size); + * } + * + * // Now we have no more data, so it is time to finalize the hash and get the + * // output. But we need to first allocate an output buffer. Note that you can + * // use any memory allocation function, including malloc(), not just + * // av_malloc(). + * output_buf = av_malloc(av_hash_get_size(ctx)); + * if (!output_buf) + * return AVERROR(ENOMEM); + * + * // Finalize the hash context. + * // You can use any of the av_hash_final*() functions provided, for other + * // output formats. If you do so, be sure to adjust the memory allocation + * // above. See the function documentation below for the exact amount of extra + * // memory needed. + * av_hash_final(ctx, output_buffer); + * + * // Free the context + * av_hash_freep(&ctx); + * @endcode + * + * @section Hash Function-Specific Information + * If the CRC32 hash is selected, the #AV_CRC_32_IEEE polynomial will be + * used. + * + * If the Murmur3 hash is selected, the default seed will be used. See @ref + * lavu_murmur3_seedinfo "Murmur3" for more information. + * + * @{ + */ + +/** + * @example ffhash.c + * This example is a simple command line application that takes one or more + * arguments. It demonstrates a typical use of the hashing API with allocation, + * initialization, updating, and finalizing. + */ + +struct AVHashContext; + +/** + * Allocate a hash context for the algorithm specified by name. + * + * @return >= 0 for success, a negative error code for failure + * + * @note The context is not initialized after a call to this function; you must + * call av_hash_init() to do so. + */ +int av_hash_alloc(struct AVHashContext **ctx, const char *name); + +/** + * Get the names of available hash algorithms. + * + * This function can be used to enumerate the algorithms. + * + * @param[in] i Index of the hash algorithm, starting from 0 + * @return Pointer to a static string or `NULL` if `i` is out of range + */ +const char *av_hash_names(int i); + +/** + * Get the name of the algorithm corresponding to the given hash context. + */ +const char *av_hash_get_name(const struct AVHashContext *ctx); + +/** + * Maximum value that av_hash_get_size() will currently return. + * + * You can use this if you absolutely want or need to use static allocation for + * the output buffer and are fine with not supporting hashes newly added to + * libavutil without recompilation. + * + * @warning + * Adding new hashes with larger sizes, and increasing the macro while doing + * so, will not be considered an ABI change. To prevent your code from + * overflowing a buffer, either dynamically allocate the output buffer with + * av_hash_get_size(), or limit your use of the Hashing API to hashes that are + * already in FFmpeg during the time of compilation. + */ +#define AV_HASH_MAX_SIZE 64 + +/** + * Get the size of the resulting hash value in bytes. + * + * The maximum value this function will currently return is available as macro + * #AV_HASH_MAX_SIZE. + * + * @param[in] ctx Hash context + * @return Size of the hash value in bytes + */ +int av_hash_get_size(const struct AVHashContext *ctx); + +/** + * Initialize or reset a hash context. + * + * @param[in,out] ctx Hash context + */ +void av_hash_init(struct AVHashContext *ctx); + +/** + * Update a hash context with additional data. + * + * @param[in,out] ctx Hash context + * @param[in] src Data to be added to the hash context + * @param[in] len Size of the additional data + */ +void av_hash_update(struct AVHashContext *ctx, const uint8_t *src, size_t len); + +/** + * Finalize a hash context and compute the actual hash value. + * + * The minimum size of `dst` buffer is given by av_hash_get_size() or + * #AV_HASH_MAX_SIZE. The use of the latter macro is discouraged. + * + * It is not safe to update or finalize a hash context again, if it has already + * been finalized. + * + * @param[in,out] ctx Hash context + * @param[out] dst Where the final hash value will be stored + * + * @see av_hash_final_bin() provides an alternative API + */ +void av_hash_final(struct AVHashContext *ctx, uint8_t *dst); + +/** + * Finalize a hash context and store the actual hash value in a buffer. + * + * It is not safe to update or finalize a hash context again, if it has already + * been finalized. + * + * If `size` is smaller than the hash size (given by av_hash_get_size()), the + * hash is truncated; if size is larger, the buffer is padded with 0. + * + * @param[in,out] ctx Hash context + * @param[out] dst Where the final hash value will be stored + * @param[in] size Number of bytes to write to `dst` + */ +void av_hash_final_bin(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and store the hexadecimal representation of the + * actual hash value as a string. + * + * It is not safe to update or finalize a hash context again, if it has already + * been finalized. + * + * The string is always 0-terminated. + * + * If `size` is smaller than `2 * hash_size + 1`, where `hash_size` is the + * value returned by av_hash_get_size(), the string will be truncated. + * + * @param[in,out] ctx Hash context + * @param[out] dst Where the string will be stored + * @param[in] size Maximum number of bytes to write to `dst` + */ +void av_hash_final_hex(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and store the Base64 representation of the + * actual hash value as a string. + * + * It is not safe to update or finalize a hash context again, if it has already + * been finalized. + * + * The string is always 0-terminated. + * + * If `size` is smaller than AV_BASE64_SIZE(hash_size), where `hash_size` is + * the value returned by av_hash_get_size(), the string will be truncated. + * + * @param[in,out] ctx Hash context + * @param[out] dst Where the final hash value will be stored + * @param[in] size Maximum number of bytes to write to `dst` + */ +void av_hash_final_b64(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Free hash context and set hash context pointer to `NULL`. + * + * @param[in,out] ctx Pointer to hash context + */ +void av_hash_freep(struct AVHashContext **ctx); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_HASH_H */ diff --git a/libs/ffmpeg/libavutil/hdr_dynamic_metadata.c b/libs/ffmpeg/libavutil/hdr_dynamic_metadata.c new file mode 100644 index 00000000000..7033f060c0a --- /dev/null +++ b/libs/ffmpeg/libavutil/hdr_dynamic_metadata.c @@ -0,0 +1,397 @@ +/** + * Copyright (c) 2018 Mohammad Izadi <moh.izadi at gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avassert.h" +#include "hdr_dynamic_metadata.h" +#include "mem.h" +#include "libavcodec/defs.h" +#include "libavcodec/get_bits.h" +#include "libavcodec/put_bits.h" + +static const int64_t luminance_den = 1; +static const int32_t peak_luminance_den = 15; +static const int64_t rgb_den = 100000; +static const int32_t fraction_pixel_den = 1000; +static const int32_t knee_point_den = 4095; +static const int32_t bezier_anchor_den = 1023; +static const int32_t saturation_weight_den = 8; + +AVDynamicHDRPlus *av_dynamic_hdr_plus_alloc(size_t *size) +{ + AVDynamicHDRPlus *hdr_plus = av_mallocz(sizeof(AVDynamicHDRPlus)); + if (!hdr_plus) + return NULL; + + if (size) + *size = sizeof(*hdr_plus); + + return hdr_plus; +} + +AVDynamicHDRPlus *av_dynamic_hdr_plus_create_side_data(AVFrame *frame) +{ + AVFrameSideData *side_data = av_frame_new_side_data(frame, + AV_FRAME_DATA_DYNAMIC_HDR_PLUS, + sizeof(AVDynamicHDRPlus)); + if (!side_data) + return NULL; + + memset(side_data->data, 0, sizeof(AVDynamicHDRPlus)); + + return (AVDynamicHDRPlus *)side_data->data; +} + +int av_dynamic_hdr_plus_from_t35(AVDynamicHDRPlus *s, const uint8_t *data, + size_t size) +{ + uint8_t padded_buf[AV_HDR_PLUS_MAX_PAYLOAD_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; + GetBitContext gbc, *gb = &gbc; + int ret; + + if (!s) + return AVERROR(ENOMEM); + + if (size > AV_HDR_PLUS_MAX_PAYLOAD_SIZE) + return AVERROR(EINVAL); + + memcpy(padded_buf, data, size); + // Zero-initialize the buffer padding to avoid overreads into uninitialized data. + memset(padded_buf + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + ret = init_get_bits8(gb, padded_buf, size); + if (ret < 0) + return ret; + + if (get_bits_left(gb) < 10) + return AVERROR_INVALIDDATA; + + s->application_version = get_bits(gb, 8); + s->num_windows = get_bits(gb, 2); + + if (s->num_windows < 1 || s->num_windows > 3) { + return AVERROR_INVALIDDATA; + } + + if (get_bits_left(gb) < ((19 * 8 + 1) * (s->num_windows - 1))) + return AVERROR_INVALIDDATA; + + for (int w = 1; w < s->num_windows; w++) { + // The corners are set to absolute coordinates here. They should be + // converted to the relative coordinates (in [0, 1]) in the decoder. + AVHDRPlusColorTransformParams *params = &s->params[w]; + params->window_upper_left_corner_x = + (AVRational){get_bits(gb, 16), 1}; + params->window_upper_left_corner_y = + (AVRational){get_bits(gb, 16), 1}; + params->window_lower_right_corner_x = + (AVRational){get_bits(gb, 16), 1}; + params->window_lower_right_corner_y = + (AVRational){get_bits(gb, 16), 1}; + + params->center_of_ellipse_x = get_bits(gb, 16); + params->center_of_ellipse_y = get_bits(gb, 16); + params->rotation_angle = get_bits(gb, 8); + params->semimajor_axis_internal_ellipse = get_bits(gb, 16); + params->semimajor_axis_external_ellipse = get_bits(gb, 16); + params->semiminor_axis_external_ellipse = get_bits(gb, 16); + params->overlap_process_option = get_bits1(gb); + } + + if (get_bits_left(gb) < 28) + return AVERROR_INVALIDDATA; + + s->targeted_system_display_maximum_luminance = + (AVRational){get_bits_long(gb, 27), luminance_den}; + s->targeted_system_display_actual_peak_luminance_flag = get_bits1(gb); + + if (s->targeted_system_display_actual_peak_luminance_flag) { + int rows, cols; + if (get_bits_left(gb) < 10) + return AVERROR_INVALIDDATA; + rows = get_bits(gb, 5); + cols = get_bits(gb, 5); + if (((rows < 2) || (rows > 25)) || ((cols < 2) || (cols > 25))) { + return AVERROR_INVALIDDATA; + } + s->num_rows_targeted_system_display_actual_peak_luminance = rows; + s->num_cols_targeted_system_display_actual_peak_luminance = cols; + + if (get_bits_left(gb) < (rows * cols * 4)) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + s->targeted_system_display_actual_peak_luminance[i][j] = + (AVRational){get_bits(gb, 4), peak_luminance_den}; + } + } + } + for (int w = 0; w < s->num_windows; w++) { + AVHDRPlusColorTransformParams *params = &s->params[w]; + if (get_bits_left(gb) < (3 * 17 + 17 + 4)) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < 3; i++) { + params->maxscl[i] = + (AVRational){get_bits(gb, 17), rgb_den}; + } + params->average_maxrgb = + (AVRational){get_bits(gb, 17), rgb_den}; + params->num_distribution_maxrgb_percentiles = get_bits(gb, 4); + + if (get_bits_left(gb) < + (params->num_distribution_maxrgb_percentiles * 24)) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < params->num_distribution_maxrgb_percentiles; i++) { + params->distribution_maxrgb[i].percentage = get_bits(gb, 7); + params->distribution_maxrgb[i].percentile = + (AVRational){get_bits(gb, 17), rgb_den}; + } + + if (get_bits_left(gb) < 10) + return AVERROR_INVALIDDATA; + + params->fraction_bright_pixels = (AVRational){get_bits(gb, 10), fraction_pixel_den}; + } + if (get_bits_left(gb) < 1) + return AVERROR_INVALIDDATA; + s->mastering_display_actual_peak_luminance_flag = get_bits1(gb); + if (s->mastering_display_actual_peak_luminance_flag) { + int rows, cols; + if (get_bits_left(gb) < 10) + return AVERROR_INVALIDDATA; + rows = get_bits(gb, 5); + cols = get_bits(gb, 5); + if (((rows < 2) || (rows > 25)) || ((cols < 2) || (cols > 25))) { + return AVERROR_INVALIDDATA; + } + s->num_rows_mastering_display_actual_peak_luminance = rows; + s->num_cols_mastering_display_actual_peak_luminance = cols; + + if (get_bits_left(gb) < (rows * cols * 4)) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + s->mastering_display_actual_peak_luminance[i][j] = + (AVRational){get_bits(gb, 4), peak_luminance_den}; + } + } + } + + for (int w = 0; w < s->num_windows; w++) { + AVHDRPlusColorTransformParams *params = &s->params[w]; + if (get_bits_left(gb) < 1) + return AVERROR_INVALIDDATA; + + params->tone_mapping_flag = get_bits1(gb); + if (params->tone_mapping_flag) { + if (get_bits_left(gb) < 28) + return AVERROR_INVALIDDATA; + + params->knee_point_x = + (AVRational){get_bits(gb, 12), knee_point_den}; + params->knee_point_y = + (AVRational){get_bits(gb, 12), knee_point_den}; + params->num_bezier_curve_anchors = get_bits(gb, 4); + + if (get_bits_left(gb) < (params->num_bezier_curve_anchors * 10)) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < params->num_bezier_curve_anchors; i++) { + params->bezier_curve_anchors[i] = + (AVRational){get_bits(gb, 10), bezier_anchor_den}; + } + } + + if (get_bits_left(gb) < 1) + return AVERROR_INVALIDDATA; + params->color_saturation_mapping_flag = get_bits1(gb); + if (params->color_saturation_mapping_flag) { + if (get_bits_left(gb) < 6) + return AVERROR_INVALIDDATA; + params->color_saturation_weight = + (AVRational){get_bits(gb, 6), saturation_weight_den}; + } + } + + return 0; +} + +int av_dynamic_hdr_plus_to_t35(const AVDynamicHDRPlus *s, uint8_t **data, size_t *size) +{ + uint8_t *buf; + size_t size_bits, size_bytes; + PutBitContext pbc, *pb = &pbc; + + if (!s) + return AVERROR(EINVAL); + if ((!data || *data) && !size) + return AVERROR(EINVAL); + + /** + * Buffer size per CTA-861-H p.253-254: + * 48 header bits (excluded from the serialized payload) + * 8 bits for application_mode + * 2 bits for num_windows + * 153 bits for window geometry, for each window above 1 + * 27 bits for targeted_system_display_maximum_luminance + * 1-2511 bits for targeted system display peak luminance information + * 82-442 bits per window for pixel distribution information + * 1-2511 bits for mastering display peak luminance information + * 1-179 bits per window for tonemapping information + * 1-7 bits per window for color saturation mapping information + * Total: 123-7249 bits, excluding trimmed header bits + */ + size_bits = 8; + + size_bits += 2; + + for (int w = 1; w < s->num_windows; w++) + size_bits += 153; + + size_bits += 27; + + size_bits += 1; + if (s->targeted_system_display_actual_peak_luminance_flag) + size_bits += 10 + + s->num_rows_targeted_system_display_actual_peak_luminance * + s->num_cols_targeted_system_display_actual_peak_luminance * 4; + + for (int w = 0; w < s->num_windows; w++) + size_bits += 72 + s->params[w].num_distribution_maxrgb_percentiles * 24 + 10; + + size_bits += 1; + if (s->mastering_display_actual_peak_luminance_flag) + size_bits += 10 + + s->num_rows_mastering_display_actual_peak_luminance * + s->num_cols_mastering_display_actual_peak_luminance * 4; + + for (int w = 0; w < s->num_windows; w++) { + size_bits += 1; + if (s->params[w].tone_mapping_flag) + size_bits += 28 + s->params[w].num_bezier_curve_anchors * 10; + + size_bits += 1; + if (s->params[w].color_saturation_mapping_flag) + size_bits += 6; + } + + size_bytes = (size_bits + 7) / 8; + + av_assert0(size_bytes <= AV_HDR_PLUS_MAX_PAYLOAD_SIZE); + + if (!data) { + *size = size_bytes; + return 0; + } else if (*data) { + if (*size < size_bytes) + return AVERROR_BUFFER_TOO_SMALL; + buf = *data; + } else { + buf = av_malloc(size_bytes); + if (!buf) + return AVERROR(ENOMEM); + } + + init_put_bits(pb, buf, size_bytes); + + // application_mode is set to Application Version 1 + put_bits(pb, 8, 1); + + // Payload as per CTA-861-H p.253-254 + put_bits(pb, 2, s->num_windows); + + for (int w = 1; w < s->num_windows; w++) { + put_bits(pb, 16, s->params[w].window_upper_left_corner_x.num / s->params[w].window_upper_left_corner_x.den); + put_bits(pb, 16, s->params[w].window_upper_left_corner_y.num / s->params[w].window_upper_left_corner_y.den); + put_bits(pb, 16, s->params[w].window_lower_right_corner_x.num / s->params[w].window_lower_right_corner_x.den); + put_bits(pb, 16, s->params[w].window_lower_right_corner_y.num / s->params[w].window_lower_right_corner_y.den); + put_bits(pb, 16, s->params[w].center_of_ellipse_x); + put_bits(pb, 16, s->params[w].center_of_ellipse_y); + put_bits(pb, 8, s->params[w].rotation_angle); + put_bits(pb, 16, s->params[w].semimajor_axis_internal_ellipse); + put_bits(pb, 16, s->params[w].semimajor_axis_external_ellipse); + put_bits(pb, 16, s->params[w].semiminor_axis_external_ellipse); + put_bits(pb, 1, s->params[w].overlap_process_option); + } + + put_bits(pb, 27, s->targeted_system_display_maximum_luminance.num * luminance_den / + s->targeted_system_display_maximum_luminance.den); + put_bits(pb, 1, s->targeted_system_display_actual_peak_luminance_flag); + if (s->targeted_system_display_actual_peak_luminance_flag) { + put_bits(pb, 5, s->num_rows_targeted_system_display_actual_peak_luminance); + put_bits(pb, 5, s->num_cols_targeted_system_display_actual_peak_luminance); + for (int i = 0; i < s->num_rows_targeted_system_display_actual_peak_luminance; i++) { + for (int j = 0; j < s->num_cols_targeted_system_display_actual_peak_luminance; j++) + put_bits(pb, 4, s->targeted_system_display_actual_peak_luminance[i][j].num * peak_luminance_den / + s->targeted_system_display_actual_peak_luminance[i][j].den); + } + } + + for (int w = 0; w < s->num_windows; w++) { + for (int i = 0; i < 3; i++) + put_bits(pb, 17, s->params[w].maxscl[i].num * rgb_den / s->params[w].maxscl[i].den); + put_bits(pb, 17, s->params[w].average_maxrgb.num * rgb_den / s->params[w].average_maxrgb.den); + put_bits(pb, 4, s->params[w].num_distribution_maxrgb_percentiles); + for (int i = 0; i < s->params[w].num_distribution_maxrgb_percentiles; i++) { + put_bits(pb, 7, s->params[w].distribution_maxrgb[i].percentage); + put_bits(pb, 17, s->params[w].distribution_maxrgb[i].percentile.num * rgb_den / + s->params[w].distribution_maxrgb[i].percentile.den); + } + put_bits(pb, 10, s->params[w].fraction_bright_pixels.num * fraction_pixel_den / + s->params[w].fraction_bright_pixels.den); + } + + put_bits(pb, 1, s->mastering_display_actual_peak_luminance_flag); + if (s->mastering_display_actual_peak_luminance_flag) { + put_bits(pb, 5, s->num_rows_mastering_display_actual_peak_luminance); + put_bits(pb, 5, s->num_cols_mastering_display_actual_peak_luminance); + for (int i = 0; i < s->num_rows_mastering_display_actual_peak_luminance; i++) { + for (int j = 0; j < s->num_cols_mastering_display_actual_peak_luminance; j++) + put_bits(pb, 4, s->mastering_display_actual_peak_luminance[i][j].num * peak_luminance_den / + s->mastering_display_actual_peak_luminance[i][j].den); + } + } + + for (int w = 0; w < s->num_windows; w++) { + put_bits(pb, 1, s->params[w].tone_mapping_flag); + if (s->params[w].tone_mapping_flag) { + put_bits(pb, 12, s->params[w].knee_point_x.num * knee_point_den / s->params[w].knee_point_x.den); + put_bits(pb, 12, s->params[w].knee_point_y.num * knee_point_den / s->params[w].knee_point_y.den); + put_bits(pb, 4, s->params[w].num_bezier_curve_anchors); + for (int i = 0; i < s->params[w].num_bezier_curve_anchors; i++) + put_bits(pb, 10, s->params[w].bezier_curve_anchors[i].num * bezier_anchor_den / + s->params[w].bezier_curve_anchors[i].den); + put_bits(pb, 1, s->params[w].color_saturation_mapping_flag); + if (s->params[w].color_saturation_mapping_flag) + put_bits(pb, 6, s->params[w].color_saturation_weight.num * saturation_weight_den / + s->params[w].color_saturation_weight.den); + } + } + + flush_put_bits(pb); + + *data = buf; + if (size) + *size = size_bytes; + return 0; +} diff --git a/libs/ffmpeg/libavutil/hdr_dynamic_metadata.h b/libs/ffmpeg/libavutil/hdr_dynamic_metadata.h new file mode 100644 index 00000000000..5100ed6f41f --- /dev/null +++ b/libs/ffmpeg/libavutil/hdr_dynamic_metadata.h @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2018 Mohammad Izadi <moh.izadi at gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HDR_DYNAMIC_METADATA_H +#define AVUTIL_HDR_DYNAMIC_METADATA_H + +#include "frame.h" +#include "rational.h" + +/** + * Option for overlapping elliptical pixel selectors in an image. + */ +enum AVHDRPlusOverlapProcessOption { + AV_HDR_PLUS_OVERLAP_PROCESS_WEIGHTED_AVERAGING = 0, + AV_HDR_PLUS_OVERLAP_PROCESS_LAYERING = 1, +}; + +/** + * Represents the percentile at a specific percentage in + * a distribution. + */ +typedef struct AVHDRPlusPercentile { + /** + * The percentage value corresponding to a specific percentile linearized + * RGB value in the processing window in the scene. The value shall be in + * the range of 0 to100, inclusive. + */ + uint8_t percentage; + + /** + * The linearized maxRGB value at a specific percentile in the processing + * window in the scene. The value shall be in the range of 0 to 1, inclusive + * and in multiples of 0.00001. + */ + AVRational percentile; +} AVHDRPlusPercentile; + +/** + * Color transform parameters at a processing window in a dynamic metadata for + * SMPTE 2094-40. + */ +typedef struct AVHDRPlusColorTransformParams { + /** + * The relative x coordinate of the top left pixel of the processing + * window. The value shall be in the range of 0 and 1, inclusive and + * in multiples of 1/(width of Picture - 1). The value 1 corresponds + * to the absolute coordinate of width of Picture - 1. The value for + * first processing window shall be 0. + */ + AVRational window_upper_left_corner_x; + + /** + * The relative y coordinate of the top left pixel of the processing + * window. The value shall be in the range of 0 and 1, inclusive and + * in multiples of 1/(height of Picture - 1). The value 1 corresponds + * to the absolute coordinate of height of Picture - 1. The value for + * first processing window shall be 0. + */ + AVRational window_upper_left_corner_y; + + /** + * The relative x coordinate of the bottom right pixel of the processing + * window. The value shall be in the range of 0 and 1, inclusive and + * in multiples of 1/(width of Picture - 1). The value 1 corresponds + * to the absolute coordinate of width of Picture - 1. The value for + * first processing window shall be 1. + */ + AVRational window_lower_right_corner_x; + + /** + * The relative y coordinate of the bottom right pixel of the processing + * window. The value shall be in the range of 0 and 1, inclusive and + * in multiples of 1/(height of Picture - 1). The value 1 corresponds + * to the absolute coordinate of height of Picture - 1. The value for + * first processing window shall be 1. + */ + AVRational window_lower_right_corner_y; + + /** + * The x coordinate of the center position of the concentric internal and + * external ellipses of the elliptical pixel selector in the processing + * window. The value shall be in the range of 0 to (width of Picture - 1), + * inclusive and in multiples of 1 pixel. + */ + uint16_t center_of_ellipse_x; + + /** + * The y coordinate of the center position of the concentric internal and + * external ellipses of the elliptical pixel selector in the processing + * window. The value shall be in the range of 0 to (height of Picture - 1), + * inclusive and in multiples of 1 pixel. + */ + uint16_t center_of_ellipse_y; + + /** + * The clockwise rotation angle in degree of arc with respect to the + * positive direction of the x-axis of the concentric internal and external + * ellipses of the elliptical pixel selector in the processing window. The + * value shall be in the range of 0 to 180, inclusive and in multiples of 1. + */ + uint8_t rotation_angle; + + /** + * The semi-major axis value of the internal ellipse of the elliptical pixel + * selector in amount of pixels in the processing window. The value shall be + * in the range of 1 to 65535, inclusive and in multiples of 1 pixel. + */ + uint16_t semimajor_axis_internal_ellipse; + + /** + * The semi-major axis value of the external ellipse of the elliptical pixel + * selector in amount of pixels in the processing window. The value + * shall not be less than semimajor_axis_internal_ellipse of the current + * processing window. The value shall be in the range of 1 to 65535, + * inclusive and in multiples of 1 pixel. + */ + uint16_t semimajor_axis_external_ellipse; + + /** + * The semi-minor axis value of the external ellipse of the elliptical pixel + * selector in amount of pixels in the processing window. The value shall be + * in the range of 1 to 65535, inclusive and in multiples of 1 pixel. + */ + uint16_t semiminor_axis_external_ellipse; + + /** + * Overlap process option indicates one of the two methods of combining + * rendered pixels in the processing window in an image with at least one + * elliptical pixel selector. For overlapping elliptical pixel selectors + * in an image, overlap_process_option shall have the same value. + */ + enum AVHDRPlusOverlapProcessOption overlap_process_option; + + /** + * The maximum of the color components of linearized RGB values in the + * processing window in the scene. The values should be in the range of 0 to + * 1, inclusive and in multiples of 0.00001. maxscl[ 0 ], maxscl[ 1 ], and + * maxscl[ 2 ] are corresponding to R, G, B color components respectively. + */ + AVRational maxscl[3]; + + /** + * The average of linearized maxRGB values in the processing window in the + * scene. The value should be in the range of 0 to 1, inclusive and in + * multiples of 0.00001. + */ + AVRational average_maxrgb; + + /** + * The number of linearized maxRGB values at given percentiles in the + * processing window in the scene. The maximum value shall be 15. + */ + uint8_t num_distribution_maxrgb_percentiles; + + /** + * The linearized maxRGB values at given percentiles in the + * processing window in the scene. + */ + AVHDRPlusPercentile distribution_maxrgb[15]; + + /** + * The fraction of selected pixels in the image that contains the brightest + * pixel in the scene. The value shall be in the range of 0 to 1, inclusive + * and in multiples of 0.001. + */ + AVRational fraction_bright_pixels; + + /** + * This flag indicates that the metadata for the tone mapping function in + * the processing window is present (for value of 1). + */ + uint8_t tone_mapping_flag; + + /** + * The x coordinate of the separation point between the linear part and the + * curved part of the tone mapping function. The value shall be in the range + * of 0 to 1, excluding 0 and in multiples of 1/4095. + */ + AVRational knee_point_x; + + /** + * The y coordinate of the separation point between the linear part and the + * curved part of the tone mapping function. The value shall be in the range + * of 0 to 1, excluding 0 and in multiples of 1/4095. + */ + AVRational knee_point_y; + + /** + * The number of the intermediate anchor parameters of the tone mapping + * function in the processing window. The maximum value shall be 15. + */ + uint8_t num_bezier_curve_anchors; + + /** + * The intermediate anchor parameters of the tone mapping function in the + * processing window in the scene. The values should be in the range of 0 + * to 1, inclusive and in multiples of 1/1023. + */ + AVRational bezier_curve_anchors[15]; + + /** + * This flag shall be equal to 0 in bitstreams conforming to this version of + * this Specification. Other values are reserved for future use. + */ + uint8_t color_saturation_mapping_flag; + + /** + * The color saturation gain in the processing window in the scene. The + * value shall be in the range of 0 to 63/8, inclusive and in multiples of + * 1/8. The default value shall be 1. + */ + AVRational color_saturation_weight; +} AVHDRPlusColorTransformParams; + +/** + * This struct represents dynamic metadata for color volume transform - + * application 4 of SMPTE 2094-40:2016 standard. + * + * To be used as payload of a AVFrameSideData or AVPacketSideData with the + * appropriate type. + * + * @note The struct should be allocated with + * av_dynamic_hdr_plus_alloc() and its size is not a part of + * the public ABI. + */ +typedef struct AVDynamicHDRPlus { + /** + * Country code by Rec. ITU-T T.35 Annex A. The value shall be 0xB5. + */ + uint8_t itu_t_t35_country_code; + + /** + * Application version in the application defining document in ST-2094 + * suite. The value shall be set to 0. + */ + uint8_t application_version; + + /** + * The number of processing windows. The value shall be in the range + * of 1 to 3, inclusive. + */ + uint8_t num_windows; + + /** + * The color transform parameters for every processing window. + */ + AVHDRPlusColorTransformParams params[3]; + + /** + * The nominal maximum display luminance of the targeted system display, + * in units of 0.0001 candelas per square metre. The value shall be in + * the range of 0 to 10000, inclusive. + */ + AVRational targeted_system_display_maximum_luminance; + + /** + * This flag shall be equal to 0 in bit streams conforming to this version + * of this Specification. The value 1 is reserved for future use. + */ + uint8_t targeted_system_display_actual_peak_luminance_flag; + + /** + * The number of rows in the targeted system_display_actual_peak_luminance + * array. The value shall be in the range of 2 to 25, inclusive. + */ + uint8_t num_rows_targeted_system_display_actual_peak_luminance; + + /** + * The number of columns in the + * targeted_system_display_actual_peak_luminance array. The value shall be + * in the range of 2 to 25, inclusive. + */ + uint8_t num_cols_targeted_system_display_actual_peak_luminance; + + /** + * The normalized actual peak luminance of the targeted system display. The + * values should be in the range of 0 to 1, inclusive and in multiples of + * 1/15. + */ + AVRational targeted_system_display_actual_peak_luminance[25][25]; + + /** + * This flag shall be equal to 0 in bitstreams conforming to this version of + * this Specification. The value 1 is reserved for future use. + */ + uint8_t mastering_display_actual_peak_luminance_flag; + + /** + * The number of rows in the mastering_display_actual_peak_luminance array. + * The value shall be in the range of 2 to 25, inclusive. + */ + uint8_t num_rows_mastering_display_actual_peak_luminance; + + /** + * The number of columns in the mastering_display_actual_peak_luminance + * array. The value shall be in the range of 2 to 25, inclusive. + */ + uint8_t num_cols_mastering_display_actual_peak_luminance; + + /** + * The normalized actual peak luminance of the mastering display used for + * mastering the image essence. The values should be in the range of 0 to 1, + * inclusive and in multiples of 1/15. + */ + AVRational mastering_display_actual_peak_luminance[25][25]; +} AVDynamicHDRPlus; + +/** + * Allocate an AVDynamicHDRPlus structure and set its fields to + * default values. The resulting struct can be freed using av_freep(). + * + * @return An AVDynamicHDRPlus filled with default values or NULL + * on failure. + */ +AVDynamicHDRPlus *av_dynamic_hdr_plus_alloc(size_t *size); + +/** + * Allocate a complete AVDynamicHDRPlus and add it to the frame. + * @param frame The frame which side data is added to. + * + * @return The AVDynamicHDRPlus structure to be filled by caller or NULL + * on failure. + */ +AVDynamicHDRPlus *av_dynamic_hdr_plus_create_side_data(AVFrame *frame); + +/** + * Parse the user data registered ITU-T T.35 to AVbuffer (AVDynamicHDRPlus). + * The T.35 buffer must begin with the application mode, skipping the + * country code, terminal provider codes, and application identifier. + * @param s A pointer containing the decoded AVDynamicHDRPlus structure. + * @param data The byte array containing the raw ITU-T T.35 data. + * @param size Size of the data array in bytes. + * + * @return >= 0 on success. Otherwise, returns the appropriate AVERROR. + */ +int av_dynamic_hdr_plus_from_t35(AVDynamicHDRPlus *s, const uint8_t *data, + size_t size); + +#define AV_HDR_PLUS_MAX_PAYLOAD_SIZE 907 + +/** + * Serialize dynamic HDR10+ metadata to a user data registered ITU-T T.35 buffer, + * excluding the first 48 bytes of the header, and beginning with the application mode. + * @param s A pointer containing the decoded AVDynamicHDRPlus structure. + * @param[in,out] data A pointer to pointer to a byte buffer to be filled with the + * serialized metadata. + * If *data is NULL, a buffer be will be allocated and a pointer to + * it stored in its place. The caller assumes ownership of the buffer. + * May be NULL, in which case the function will only store the + * required buffer size in *size. + * @param[in,out] size A pointer to a size to be set to the returned buffer's size. + * If *data is not NULL, *size must contain the size of the input + * buffer. May be NULL only if *data is NULL. + * + * @return >= 0 on success. Otherwise, returns the appropriate AVERROR. + */ +int av_dynamic_hdr_plus_to_t35(const AVDynamicHDRPlus *s, uint8_t **data, size_t *size); + +#endif /* AVUTIL_HDR_DYNAMIC_METADATA_H */ diff --git a/libs/ffmpeg/libavutil/hdr_dynamic_vivid_metadata.c b/libs/ffmpeg/libavutil/hdr_dynamic_vivid_metadata.c new file mode 100644 index 00000000000..32da01f5875 --- /dev/null +++ b/libs/ffmpeg/libavutil/hdr_dynamic_vivid_metadata.c @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2021 Limin Wang <lance.lmwang at gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hdr_dynamic_vivid_metadata.h" +#include "mem.h" + +AVDynamicHDRVivid *av_dynamic_hdr_vivid_alloc(size_t *size) +{ + AVDynamicHDRVivid *hdr_vivid = av_mallocz(sizeof(AVDynamicHDRVivid)); + if (!hdr_vivid) + return NULL; + + if (size) + *size = sizeof(*hdr_vivid); + + return hdr_vivid; +} + +AVDynamicHDRVivid *av_dynamic_hdr_vivid_create_side_data(AVFrame *frame) +{ + AVFrameSideData *side_data = av_frame_new_side_data(frame, + AV_FRAME_DATA_DYNAMIC_HDR_VIVID, + sizeof(AVDynamicHDRVivid)); + if (!side_data) + return NULL; + + memset(side_data->data, 0, sizeof(AVDynamicHDRVivid)); + + return (AVDynamicHDRVivid *)side_data->data; +} diff --git a/libs/ffmpeg/libavutil/hdr_dynamic_vivid_metadata.h b/libs/ffmpeg/libavutil/hdr_dynamic_vivid_metadata.h new file mode 100644 index 00000000000..d45b4a0f658 --- /dev/null +++ b/libs/ffmpeg/libavutil/hdr_dynamic_vivid_metadata.h @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2021 Limin Wang <lance.lmwang at gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HDR_DYNAMIC_VIVID_METADATA_H +#define AVUTIL_HDR_DYNAMIC_VIVID_METADATA_H + +#include "frame.h" +#include "rational.h" + +/** + * HDR Vivid three spline params. + */ +typedef struct AVHDRVivid3SplineParams { + /** + * The mode of three Spline. the value shall be in the range + * of 0 to 3, inclusive. + */ + int th_mode; + + /** + * three_Spline_TH_enable_MB is in the range of 0.0 to 1.0, inclusive + * and in multiples of 1.0/255. + * + */ + AVRational th_enable_mb; + + /** + * 3Spline_TH_enable of three Spline. + * The value shall be in the range of 0.0 to 1.0, inclusive. + * and in multiples of 1.0/4095. + */ + AVRational th_enable; + + /** + * 3Spline_TH_Delta1 of three Spline. + * The value shall be in the range of 0.0 to 0.25, inclusive, + * and in multiples of 0.25/1023. + */ + AVRational th_delta1; + + /** + * 3Spline_TH_Delta2 of three Spline. + * The value shall be in the range of 0.0 to 0.25, inclusive, + * and in multiples of 0.25/1023. + */ + AVRational th_delta2; + + /** + * 3Spline_enable_Strength of three Spline. + * The value shall be in the range of 0.0 to 1.0, inclusive, + * and in multiples of 1.0/255. + */ + AVRational enable_strength; +} AVHDRVivid3SplineParams; + +/** + * Color tone mapping parameters at a processing window in a dynamic metadata for + * CUVA 005.1:2021. + */ +typedef struct AVHDRVividColorToneMappingParams { + /** + * The nominal maximum display luminance of the targeted system display, + * in multiples of 1.0/4095 candelas per square metre. The value shall be in + * the range of 0.0 to 1.0, inclusive. + */ + AVRational targeted_system_display_maximum_luminance; + + /** + * This flag indicates that transfer the base parameter(for value of 1) + */ + int base_enable_flag; + + /** + * base_param_m_p in the base parameter, + * in multiples of 1.0/16383. The value shall be in + * the range of 0.0 to 1.0, inclusive. + */ + AVRational base_param_m_p; + + /** + * base_param_m_m in the base parameter, + * in multiples of 1.0/10. The value shall be in + * the range of 0.0 to 6.3, inclusive. + */ + AVRational base_param_m_m; + + /** + * base_param_m_a in the base parameter, + * in multiples of 1.0/1023. The value shall be in + * the range of 0.0 to 1.0 inclusive. + */ + AVRational base_param_m_a; + + /** + * base_param_m_b in the base parameter, + * in multiples of 1/1023. The value shall be in + * the range of 0.0 to 1.0, inclusive. + */ + AVRational base_param_m_b; + + /** + * base_param_m_n in the base parameter, + * in multiples of 1.0/10. The value shall be in + * the range of 0.0 to 6.3, inclusive. + */ + AVRational base_param_m_n; + + /** + * indicates k1_0 in the base parameter, + * base_param_k1 <= 1: k1_0 = base_param_k1 + * base_param_k1 > 1: reserved + */ + int base_param_k1; + + /** + * indicates k2_0 in the base parameter, + * base_param_k2 <= 1: k2_0 = base_param_k2 + * base_param_k2 > 1: reserved + */ + int base_param_k2; + + /** + * indicates k3_0 in the base parameter, + * base_param_k3 == 1: k3_0 = base_param_k3 + * base_param_k3 == 2: k3_0 = maximum_maxrgb + * base_param_k3 > 2: reserved + */ + int base_param_k3; + + /** + * This flag indicates that delta mode of base parameter(for value of 1) + */ + int base_param_Delta_enable_mode; + + /** + * base_param_Delta in the base parameter, + * in multiples of 1.0/127. The value shall be in + * the range of 0.0 to 1.0, inclusive. + */ + AVRational base_param_Delta; + + /** + * indicates 3Spline_enable_flag in the base parameter, + * This flag indicates that transfer three Spline of base parameter(for value of 1) + */ + int three_Spline_enable_flag; + + /** + * The number of three Spline. The value shall be in the range + * of 1 to 2, inclusive. + */ + int three_Spline_num; + + AVHDRVivid3SplineParams three_spline[2]; +} AVHDRVividColorToneMappingParams; + + +/** + * Color transform parameters at a processing window in a dynamic metadata for + * CUVA 005.1:2021. + */ +typedef struct AVHDRVividColorTransformParams { + /** + * Indicates the minimum brightness of the displayed content. + * The values should be in the range of 0.0 to 1.0, + * inclusive and in multiples of 1/4095. + */ + AVRational minimum_maxrgb; + + /** + * Indicates the average brightness of the displayed content. + * The values should be in the range of 0.0 to 1.0, + * inclusive and in multiples of 1/4095. + */ + AVRational average_maxrgb; + + /** + * Indicates the variance brightness of the displayed content. + * The values should be in the range of 0.0 to 1.0, + * inclusive and in multiples of 1/4095. + */ + AVRational variance_maxrgb; + + /** + * Indicates the maximum brightness of the displayed content. + * The values should be in the range of 0.0 to 1.0, inclusive + * and in multiples of 1/4095. + */ + AVRational maximum_maxrgb; + + /** + * This flag indicates that the metadata for the tone mapping function in + * the processing window is present (for value of 1). + */ + int tone_mapping_mode_flag; + + /** + * The number of tone mapping param. The value shall be in the range + * of 1 to 2, inclusive. + */ + int tone_mapping_param_num; + + /** + * The color tone mapping parameters. + */ + AVHDRVividColorToneMappingParams tm_params[2]; + + /** + * This flag indicates that the metadata for the color saturation mapping in + * the processing window is present (for value of 1). + */ + int color_saturation_mapping_flag; + + /** + * The number of color saturation param. The value shall be in the range + * of 0 to 7, inclusive. + */ + int color_saturation_num; + + /** + * Indicates the color correction strength parameter. + * The values should be in the range of 0.0 to 2.0, inclusive + * and in multiples of 1/128. + */ + AVRational color_saturation_gain[8]; +} AVHDRVividColorTransformParams; + +/** + * This struct represents dynamic metadata for color volume transform - + * CUVA 005.1:2021 standard + * + * To be used as payload of a AVFrameSideData or AVPacketSideData with the + * appropriate type. + * + * @note The struct should be allocated with + * av_dynamic_hdr_vivid_alloc() and its size is not a part of + * the public ABI. + */ +typedef struct AVDynamicHDRVivid { + /** + * The system start code. The value shall be set to 0x01. + */ + uint8_t system_start_code; + + /** + * The number of processing windows. The value shall be set to 0x01 + * if the system_start_code is 0x01. + */ + uint8_t num_windows; + + /** + * The color transform parameters for every processing window. + */ + AVHDRVividColorTransformParams params[3]; +} AVDynamicHDRVivid; + +/** + * Allocate an AVDynamicHDRVivid structure and set its fields to + * default values. The resulting struct can be freed using av_freep(). + * + * @return An AVDynamicHDRVivid filled with default values or NULL + * on failure. + */ +AVDynamicHDRVivid *av_dynamic_hdr_vivid_alloc(size_t *size); + +/** + * Allocate a complete AVDynamicHDRVivid and add it to the frame. + * @param frame The frame which side data is added to. + * + * @return The AVDynamicHDRVivid structure to be filled by caller or NULL + * on failure. + */ +AVDynamicHDRVivid *av_dynamic_hdr_vivid_create_side_data(AVFrame *frame); + +#endif /* AVUTIL_HDR_DYNAMIC_VIVID_METADATA_H */ diff --git a/libs/ffmpeg/libavutil/hmac.c b/libs/ffmpeg/libavutil/hmac.c new file mode 100644 index 00000000000..6daca00b8fe --- /dev/null +++ b/libs/ffmpeg/libavutil/hmac.c @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2012 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include "attributes.h" +#include "error.h" +#include "hmac.h" +#include "md5.h" +#include "sha.h" +#include "sha512.h" +#include "mem.h" + +#define MAX_HASHLEN 64 +#define MAX_BLOCKLEN 128 + +typedef void (*hmac_final)(void *ctx, uint8_t *dst); +typedef void (*hmac_update)(void *ctx, const uint8_t *src, size_t len); +typedef void (*hmac_init)(void *ctx); + +struct AVHMAC { + void *hash; + int blocklen, hashlen; + hmac_final final; + hmac_update update; + hmac_init init; + uint8_t key[MAX_BLOCKLEN]; + int keylen; +}; + +#define DEFINE_ALGO_BITS_INIT(prefix, bits) \ +static av_cold void prefix##bits##_init(void *ctx) \ +{ \ + av_##prefix##_init(ctx, bits); \ +} + +#define DEFINE_ALGO_INIT(prefix) \ +static av_cold void prefix##_init(void *ctx) \ +{ \ + av_##prefix##_init(ctx); \ +} + +#define DEFINE_ALGO(prefix) \ +static void prefix##_update(void *ctx, const uint8_t *src, size_t len) \ +{ \ + av_##prefix##_update(ctx, src, len); \ +} \ +static void prefix##_final(void *ctx, uint8_t *dst) \ +{ \ + av_##prefix##_final(ctx, dst); \ +} + +DEFINE_ALGO_INIT(md5) +DEFINE_ALGO_BITS_INIT(sha, 160) +DEFINE_ALGO_BITS_INIT(sha, 224) +DEFINE_ALGO_BITS_INIT(sha, 256) +DEFINE_ALGO_BITS_INIT(sha512, 384) +DEFINE_ALGO_BITS_INIT(sha512, 512) +DEFINE_ALGO(md5) +DEFINE_ALGO(sha) +DEFINE_ALGO(sha512) + +AVHMAC *av_hmac_alloc(enum AVHMACType type) +{ + AVHMAC *c = av_mallocz(sizeof(*c)); + if (!c) + return NULL; + switch (type) { + case AV_HMAC_MD5: + c->blocklen = 64; + c->hashlen = 16; + c->init = md5_init; + c->update = md5_update; + c->final = md5_final; + c->hash = av_md5_alloc(); + break; + case AV_HMAC_SHA1: + c->blocklen = 64; + c->hashlen = 20; + c->init = sha160_init; + c->update = sha_update; + c->final = sha_final; + c->hash = av_sha_alloc(); + break; + case AV_HMAC_SHA224: + c->blocklen = 64; + c->hashlen = 28; + c->init = sha224_init; + c->update = sha_update; + c->final = sha_final; + c->hash = av_sha_alloc(); + break; + case AV_HMAC_SHA256: + c->blocklen = 64; + c->hashlen = 32; + c->init = sha256_init; + c->update = sha_update; + c->final = sha_final; + c->hash = av_sha_alloc(); + break; + case AV_HMAC_SHA384: + c->blocklen = 128; + c->hashlen = 48; + c->init = sha512384_init; + c->update = sha512_update; + c->final = sha512_final; + c->hash = av_sha512_alloc(); + break; + case AV_HMAC_SHA512: + c->blocklen = 128; + c->hashlen = 64; + c->init = sha512512_init; + c->update = sha512_update; + c->final = sha512_final; + c->hash = av_sha512_alloc(); + break; + default: + av_free(c); + return NULL; + } + if (!c->hash) { + av_free(c); + return NULL; + } + return c; +} + +void av_hmac_free(AVHMAC *c) +{ + if (!c) + return; + av_freep(&c->hash); + av_free(c); +} + +void av_hmac_init(AVHMAC *c, const uint8_t *key, unsigned int keylen) +{ + int i; + uint8_t block[MAX_BLOCKLEN]; + if (keylen > c->blocklen) { + c->init(c->hash); + c->update(c->hash, key, keylen); + c->final(c->hash, c->key); + c->keylen = c->hashlen; + } else { + memcpy(c->key, key, keylen); + c->keylen = keylen; + } + c->init(c->hash); + for (i = 0; i < c->keylen; i++) + block[i] = c->key[i] ^ 0x36; + for (i = c->keylen; i < c->blocklen; i++) + block[i] = 0x36; + c->update(c->hash, block, c->blocklen); +} + +void av_hmac_update(AVHMAC *c, const uint8_t *data, unsigned int len) +{ + c->update(c->hash, data, len); +} + +int av_hmac_final(AVHMAC *c, uint8_t *out, unsigned int outlen) +{ + uint8_t block[MAX_BLOCKLEN]; + int i; + if (outlen < c->hashlen) + return AVERROR(EINVAL); + c->final(c->hash, out); + c->init(c->hash); + for (i = 0; i < c->keylen; i++) + block[i] = c->key[i] ^ 0x5C; + for (i = c->keylen; i < c->blocklen; i++) + block[i] = 0x5C; + c->update(c->hash, block, c->blocklen); + c->update(c->hash, out, c->hashlen); + c->final(c->hash, out); + return c->hashlen; +} + +int av_hmac_calc(AVHMAC *c, const uint8_t *data, unsigned int len, + const uint8_t *key, unsigned int keylen, + uint8_t *out, unsigned int outlen) +{ + av_hmac_init(c, key, keylen); + av_hmac_update(c, data, len); + return av_hmac_final(c, out, outlen); +} diff --git a/libs/ffmpeg/libavutil/hmac.h b/libs/ffmpeg/libavutil/hmac.h new file mode 100644 index 00000000000..ca4da6a689d --- /dev/null +++ b/libs/ffmpeg/libavutil/hmac.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2012 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HMAC_H +#define AVUTIL_HMAC_H + +#include <stdint.h> + +/** + * @defgroup lavu_hmac HMAC + * @ingroup lavu_crypto + * @{ + */ + +enum AVHMACType { + AV_HMAC_MD5, + AV_HMAC_SHA1, + AV_HMAC_SHA224, + AV_HMAC_SHA256, + AV_HMAC_SHA384, + AV_HMAC_SHA512, +}; + +typedef struct AVHMAC AVHMAC; + +/** + * Allocate an AVHMAC context. + * @param type The hash function used for the HMAC. + */ +AVHMAC *av_hmac_alloc(enum AVHMACType type); + +/** + * Free an AVHMAC context. + * @param ctx The context to free, may be NULL + */ +void av_hmac_free(AVHMAC *ctx); + +/** + * Initialize an AVHMAC context with an authentication key. + * @param ctx The HMAC context + * @param key The authentication key + * @param keylen The length of the key, in bytes + */ +void av_hmac_init(AVHMAC *ctx, const uint8_t *key, unsigned int keylen); + +/** + * Hash data with the HMAC. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + */ +void av_hmac_update(AVHMAC *ctx, const uint8_t *data, unsigned int len); + +/** + * Finish hashing and output the HMAC digest. + * @param ctx The HMAC context + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_final(AVHMAC *ctx, uint8_t *out, unsigned int outlen); + +/** + * Hash an array of data with a key. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + * @param key The authentication key + * @param keylen The length of the key, in bytes + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_calc(AVHMAC *ctx, const uint8_t *data, unsigned int len, + const uint8_t *key, unsigned int keylen, + uint8_t *out, unsigned int outlen); + +/** + * @} + */ + +#endif /* AVUTIL_HMAC_H */ diff --git a/libs/ffmpeg/libavutil/hwcontext.c b/libs/ffmpeg/libavutil/hwcontext.c new file mode 100644 index 00000000000..83bd7457e8e --- /dev/null +++ b/libs/ffmpeg/libavutil/hwcontext.c @@ -0,0 +1,952 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "avassert.h" +#include "buffer.h" +#include "common.h" +#include "hwcontext.h" +#include "hwcontext_internal.h" +#include "imgutils.h" +#include "log.h" +#include "mem.h" +#include "pixdesc.h" +#include "pixfmt.h" + +static const HWContextType * const hw_table[] = { +#if CONFIG_CUDA + &ff_hwcontext_type_cuda, +#endif +#if CONFIG_D3D11VA + &ff_hwcontext_type_d3d11va, +#endif +#if CONFIG_D3D12VA + &ff_hwcontext_type_d3d12va, +#endif +#if CONFIG_LIBDRM + &ff_hwcontext_type_drm, +#endif +#if CONFIG_DXVA2 + &ff_hwcontext_type_dxva2, +#endif +#if CONFIG_OPENCL + &ff_hwcontext_type_opencl, +#endif +#if CONFIG_QSV + &ff_hwcontext_type_qsv, +#endif +#if CONFIG_VAAPI + &ff_hwcontext_type_vaapi, +#endif +#if CONFIG_VDPAU + &ff_hwcontext_type_vdpau, +#endif +#if CONFIG_VIDEOTOOLBOX + &ff_hwcontext_type_videotoolbox, +#endif +#if CONFIG_MEDIACODEC + &ff_hwcontext_type_mediacodec, +#endif +#if CONFIG_VULKAN + &ff_hwcontext_type_vulkan, +#endif +#if CONFIG_AMF + &ff_hwcontext_type_amf, +#endif +#if CONFIG_OHCODEC + &ff_hwcontext_type_oh, +#endif + NULL, +}; + +static const char *const hw_type_names[] = { + [AV_HWDEVICE_TYPE_CUDA] = "cuda", + [AV_HWDEVICE_TYPE_DRM] = "drm", + [AV_HWDEVICE_TYPE_DXVA2] = "dxva2", + [AV_HWDEVICE_TYPE_D3D11VA] = "d3d11va", + [AV_HWDEVICE_TYPE_D3D12VA] = "d3d12va", + [AV_HWDEVICE_TYPE_OPENCL] = "opencl", + [AV_HWDEVICE_TYPE_QSV] = "qsv", + [AV_HWDEVICE_TYPE_VAAPI] = "vaapi", + [AV_HWDEVICE_TYPE_VDPAU] = "vdpau", + [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox", + [AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec", + [AV_HWDEVICE_TYPE_VULKAN] = "vulkan", + [AV_HWDEVICE_TYPE_AMF] = "amf", + [AV_HWDEVICE_TYPE_OHCODEC] = "ohcodec", +}; + +typedef struct FFHWDeviceContext { + /** + * The public AVHWDeviceContext. See hwcontext.h for it. + */ + AVHWDeviceContext p; + + const HWContextType *hw_type; + + /** + * For a derived device, a reference to the original device + * context it was derived from. + */ + AVBufferRef *source_device; +} FFHWDeviceContext; + +enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name) +{ + int type; + for (type = 0; type < FF_ARRAY_ELEMS(hw_type_names); type++) { + if (hw_type_names[type] && !strcmp(hw_type_names[type], name)) + return type; + } + return AV_HWDEVICE_TYPE_NONE; +} + +const char *av_hwdevice_get_type_name(enum AVHWDeviceType type) +{ + if (type > AV_HWDEVICE_TYPE_NONE && + type < FF_ARRAY_ELEMS(hw_type_names)) + return hw_type_names[type]; + else + return NULL; +} + +enum AVHWDeviceType av_hwdevice_iterate_types(enum AVHWDeviceType prev) +{ + enum AVHWDeviceType next; + int i, set = 0; + for (i = 0; hw_table[i]; i++) { + if (prev != AV_HWDEVICE_TYPE_NONE && hw_table[i]->type <= prev) + continue; + if (!set || hw_table[i]->type < next) { + next = hw_table[i]->type; + set = 1; + } + } + return set ? next : AV_HWDEVICE_TYPE_NONE; +} + +static const char *hwdevice_ctx_get_name(void *ptr) +{ + FFHWDeviceContext *ctx = ptr; + return ctx->hw_type->name; +} + +static const AVClass hwdevice_ctx_class = { + .class_name = "AVHWDeviceContext", + .item_name = hwdevice_ctx_get_name, + .category = AV_CLASS_CATEGORY_HWDEVICE, + .version = LIBAVUTIL_VERSION_INT, +}; + +static void hwdevice_ctx_free(void *opaque, uint8_t *data) +{ + FFHWDeviceContext *ctxi = (FFHWDeviceContext*)data; + AVHWDeviceContext *ctx = &ctxi->p; + + /* uninit might still want access the hw context and the user + * free() callback might destroy it, so uninit has to be called first */ + if (ctxi->hw_type->device_uninit) + ctxi->hw_type->device_uninit(ctx); + + if (ctx->free) + ctx->free(ctx); + + av_buffer_unref(&ctxi->source_device); + + av_freep(&ctx->hwctx); + av_freep(&ctx); +} + +AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type) +{ + FFHWDeviceContext *ctxi; + AVHWDeviceContext *ctx; + AVBufferRef *buf; + const HWContextType *hw_type = NULL; + int i; + + for (i = 0; hw_table[i]; i++) { + if (hw_table[i]->type == type) { + hw_type = hw_table[i]; + break; + } + } + if (!hw_type) + return NULL; + + ctxi = av_mallocz(sizeof(*ctxi)); + if (!ctxi) + return NULL; + ctx = &ctxi->p; + + if (hw_type->device_hwctx_size) { + ctx->hwctx = av_mallocz(hw_type->device_hwctx_size); + if (!ctx->hwctx) + goto fail; + } + + buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx), + hwdevice_ctx_free, NULL, + AV_BUFFER_FLAG_READONLY); + if (!buf) + goto fail; + + ctx->type = type; + ctx->av_class = &hwdevice_ctx_class; + + ctxi->hw_type = hw_type; + + return buf; + +fail: + av_freep(&ctx->hwctx); + av_freep(&ctx); + return NULL; +} + +int av_hwdevice_ctx_init(AVBufferRef *ref) +{ + FFHWDeviceContext *ctxi = (FFHWDeviceContext*)ref->data; + AVHWDeviceContext *ctx = &ctxi->p; + int ret = 0; + + if (ctxi->hw_type->device_init) + ret = ctxi->hw_type->device_init(ctx); + + return ret; +} + +static const AVClass hwframe_ctx_class = { + .class_name = "AVHWFramesContext", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, +}; + +static void hwframe_ctx_free(void *opaque, uint8_t *data) +{ + FFHWFramesContext *ctxi = (FFHWFramesContext*)data; + AVHWFramesContext *ctx = &ctxi->p; + + if (ctxi->pool_internal) + av_buffer_pool_uninit(&ctxi->pool_internal); + + if (ctxi->hw_type->frames_uninit) + ctxi->hw_type->frames_uninit(ctx); + + if (ctx->free) + ctx->free(ctx); + + av_buffer_unref(&ctxi->source_frames); + + av_buffer_unref(&ctx->device_ref); + + av_freep(&ctx->hwctx); + av_freep(&ctx); +} + +AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ref_in) +{ + FFHWDeviceContext *device_ctx = (FFHWDeviceContext*)device_ref_in->data; + const HWContextType *hw_type = device_ctx->hw_type; + FFHWFramesContext *ctxi; + AVHWFramesContext *ctx; + AVBufferRef *buf, *device_ref = NULL; + + ctxi = av_mallocz(sizeof(*ctxi)); + if (!ctxi) + return NULL; + ctx = &ctxi->p; + + if (hw_type->frames_hwctx_size) { + ctx->hwctx = av_mallocz(hw_type->frames_hwctx_size); + if (!ctx->hwctx) + goto fail; + } + + device_ref = av_buffer_ref(device_ref_in); + if (!device_ref) + goto fail; + + buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx), + hwframe_ctx_free, NULL, + AV_BUFFER_FLAG_READONLY); + if (!buf) + goto fail; + + ctx->av_class = &hwframe_ctx_class; + ctx->device_ref = device_ref; + ctx->device_ctx = &device_ctx->p; + ctx->format = AV_PIX_FMT_NONE; + ctx->sw_format = AV_PIX_FMT_NONE; + + ctxi->hw_type = hw_type; + + return buf; + +fail: + av_buffer_unref(&device_ref); + av_freep(&ctx->hwctx); + av_freep(&ctx); + return NULL; +} + +static int hwframe_pool_prealloc(AVBufferRef *ref) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data; + AVFrame **frames; + int i, ret = 0; + + frames = av_calloc(ctx->initial_pool_size, sizeof(*frames)); + if (!frames) + return AVERROR(ENOMEM); + + for (i = 0; i < ctx->initial_pool_size; i++) { + frames[i] = av_frame_alloc(); + if (!frames[i]) + goto fail; + + ret = av_hwframe_get_buffer(ref, frames[i], 0); + if (ret < 0) + goto fail; + } + +fail: + for (i = 0; i < ctx->initial_pool_size; i++) + av_frame_free(&frames[i]); + av_freep(&frames); + + return ret; +} + +int av_hwframe_ctx_init(AVBufferRef *ref) +{ + FFHWFramesContext *ctxi = (FFHWFramesContext*)ref->data; + AVHWFramesContext *ctx = &ctxi->p; + const enum AVPixelFormat *pix_fmt; + int ret; + + if (ctxi->source_frames) { + /* A derived frame context is already initialised. */ + return 0; + } + + /* validate the pixel format */ + for (pix_fmt = ctxi->hw_type->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++) { + if (*pix_fmt == ctx->format) + break; + } + if (*pix_fmt == AV_PIX_FMT_NONE) { + av_log(ctx, AV_LOG_ERROR, + "The hardware pixel format '%s' is not supported by the device type '%s'\n", + av_get_pix_fmt_name(ctx->format), ctxi->hw_type->name); + return AVERROR(ENOSYS); + } + + /* validate the dimensions */ + ret = av_image_check_size(ctx->width, ctx->height, 0, ctx); + if (ret < 0) + return ret; + + /* format-specific init */ + if (ctxi->hw_type->frames_init) { + ret = ctxi->hw_type->frames_init(ctx); + if (ret < 0) + return ret; + } + + if (ctxi->pool_internal && !ctx->pool) + ctx->pool = ctxi->pool_internal; + + /* preallocate the frames in the pool, if requested */ + if (ctx->initial_pool_size > 0) { + ret = hwframe_pool_prealloc(ref); + if (ret < 0) + return ret; + } + + return 0; +} + +int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ref, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats, int flags) +{ + FFHWFramesContext *ctxi = (FFHWFramesContext*)hwframe_ref->data; + + if (!ctxi->hw_type->transfer_get_formats) + return AVERROR(ENOSYS); + + return ctxi->hw_type->transfer_get_formats(&ctxi->p, dir, formats); +} + +static int transfer_data_alloc(AVFrame *dst, const AVFrame *src, int flags) +{ + AVHWFramesContext *ctx; + AVFrame *frame_tmp; + int ret = 0; + + if (!src->hw_frames_ctx) + return AVERROR(EINVAL); + ctx = (AVHWFramesContext*)src->hw_frames_ctx->data; + + frame_tmp = av_frame_alloc(); + if (!frame_tmp) + return AVERROR(ENOMEM); + + /* if the format is set, use that + * otherwise pick the first supported one */ + if (dst->format >= 0) { + frame_tmp->format = dst->format; + } else { + enum AVPixelFormat *formats; + + ret = av_hwframe_transfer_get_formats(src->hw_frames_ctx, + AV_HWFRAME_TRANSFER_DIRECTION_FROM, + &formats, 0); + if (ret < 0) + goto fail; + frame_tmp->format = formats[0]; + av_freep(&formats); + } + frame_tmp->width = ctx->width; + frame_tmp->height = ctx->height; + + ret = av_frame_get_buffer(frame_tmp, 0); + if (ret < 0) + goto fail; + + ret = av_hwframe_transfer_data(frame_tmp, src, flags); + if (ret < 0) + goto fail; + + frame_tmp->width = src->width; + frame_tmp->height = src->height; + + av_frame_move_ref(dst, frame_tmp); + +fail: + av_frame_free(&frame_tmp); + return ret; +} + +int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags) +{ + int ret; + + if (!dst->buf[0]) + return transfer_data_alloc(dst, src, flags); + + /* + * Hardware -> Hardware Transfer. + * Unlike Software -> Hardware or Hardware -> Software, the transfer + * function could be provided by either the src or dst, depending on + * the specific combination of hardware. + */ + if (src->hw_frames_ctx && dst->hw_frames_ctx) { + FFHWFramesContext *src_ctx = + (FFHWFramesContext*)src->hw_frames_ctx->data; + FFHWFramesContext *dst_ctx = + (FFHWFramesContext*)dst->hw_frames_ctx->data; + + if (src_ctx->source_frames) { + av_log(src_ctx, AV_LOG_ERROR, + "A device with a derived frame context cannot be used as " + "the source of a HW -> HW transfer."); + return AVERROR(ENOSYS); + } + + if (dst_ctx->source_frames) { + av_log(src_ctx, AV_LOG_ERROR, + "A device with a derived frame context cannot be used as " + "the destination of a HW -> HW transfer."); + return AVERROR(ENOSYS); + } + + ret = src_ctx->hw_type->transfer_data_from(&src_ctx->p, dst, src); + if (ret == AVERROR(ENOSYS)) + ret = dst_ctx->hw_type->transfer_data_to(&dst_ctx->p, dst, src); + if (ret < 0) + return ret; + } else { + if (src->hw_frames_ctx) { + FFHWFramesContext *ctx = (FFHWFramesContext*)src->hw_frames_ctx->data; + + ret = ctx->hw_type->transfer_data_from(&ctx->p, dst, src); + if (ret < 0) + return ret; + } else if (dst->hw_frames_ctx) { + FFHWFramesContext *ctx = (FFHWFramesContext*)dst->hw_frames_ctx->data; + + ret = ctx->hw_type->transfer_data_to(&ctx->p, dst, src); + if (ret < 0) + return ret; + } else { + return AVERROR(ENOSYS); + } + } + return 0; +} + +int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags) +{ + FFHWFramesContext *ctxi = (FFHWFramesContext*)hwframe_ref->data; + AVHWFramesContext *ctx = &ctxi->p; + int ret; + + if (ctxi->source_frames) { + // This is a derived frame context, so we allocate in the source + // and map the frame immediately. + AVFrame *src_frame; + + frame->format = ctx->format; + frame->hw_frames_ctx = av_buffer_ref(hwframe_ref); + if (!frame->hw_frames_ctx) + return AVERROR(ENOMEM); + + src_frame = av_frame_alloc(); + if (!src_frame) + return AVERROR(ENOMEM); + + ret = av_hwframe_get_buffer(ctxi->source_frames, + src_frame, 0); + if (ret < 0) { + av_frame_free(&src_frame); + return ret; + } + + ret = av_hwframe_map(frame, src_frame, + ctxi->source_allocation_map_flags); + if (ret) { + av_log(ctx, AV_LOG_ERROR, "Failed to map frame into derived " + "frame context: %d.\n", ret); + av_frame_free(&src_frame); + return ret; + } + + // Free the source frame immediately - the mapped frame still + // contains a reference to it. + av_frame_free(&src_frame); + + return 0; + } + + if (!ctxi->hw_type->frames_get_buffer) + return AVERROR(ENOSYS); + + if (!ctx->pool) + return AVERROR(EINVAL); + + frame->hw_frames_ctx = av_buffer_ref(hwframe_ref); + if (!frame->hw_frames_ctx) + return AVERROR(ENOMEM); + + ret = ctxi->hw_type->frames_get_buffer(ctx, frame); + if (ret < 0) { + av_buffer_unref(&frame->hw_frames_ctx); + return ret; + } + + frame->extended_data = frame->data; + + return 0; +} + +void *av_hwdevice_hwconfig_alloc(AVBufferRef *ref) +{ + FFHWDeviceContext *ctx = (FFHWDeviceContext*)ref->data; + const HWContextType *hw_type = ctx->hw_type; + + if (hw_type->device_hwconfig_size == 0) + return NULL; + + return av_mallocz(hw_type->device_hwconfig_size); +} + +AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref, + const void *hwconfig) +{ + FFHWDeviceContext *ctx = (FFHWDeviceContext*)ref->data; + const HWContextType *hw_type = ctx->hw_type; + AVHWFramesConstraints *constraints; + + if (!hw_type->frames_get_constraints) + return NULL; + + constraints = av_mallocz(sizeof(*constraints)); + if (!constraints) + return NULL; + + constraints->min_width = constraints->min_height = 0; + constraints->max_width = constraints->max_height = INT_MAX; + + if (hw_type->frames_get_constraints(&ctx->p, hwconfig, constraints) >= 0) { + return constraints; + } else { + av_hwframe_constraints_free(&constraints); + return NULL; + } +} + +void av_hwframe_constraints_free(AVHWFramesConstraints **constraints) +{ + if (*constraints) { + av_freep(&(*constraints)->valid_hw_formats); + av_freep(&(*constraints)->valid_sw_formats); + } + av_freep(constraints); +} + +int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type, + const char *device, AVDictionary *opts, int flags) +{ + AVBufferRef *device_ref = NULL; + FFHWDeviceContext *device_ctx; + int ret = 0; + + device_ref = av_hwdevice_ctx_alloc(type); + if (!device_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + device_ctx = (FFHWDeviceContext*)device_ref->data; + + if (!device_ctx->hw_type->device_create) { + ret = AVERROR(ENOSYS); + goto fail; + } + + ret = device_ctx->hw_type->device_create(&device_ctx->p, device, + opts, flags); + if (ret < 0) + goto fail; + + ret = av_hwdevice_ctx_init(device_ref); + if (ret < 0) + goto fail; + + *pdevice_ref = device_ref; + return 0; +fail: + av_buffer_unref(&device_ref); + *pdevice_ref = NULL; + return ret; +} + +int av_hwdevice_ctx_create_derived_opts(AVBufferRef **dst_ref_ptr, + enum AVHWDeviceType type, + AVBufferRef *src_ref, + AVDictionary *options, int flags) +{ + AVBufferRef *dst_ref = NULL, *tmp_ref; + FFHWDeviceContext *dst_ctx; + int ret = 0; + + tmp_ref = src_ref; + while (tmp_ref) { + FFHWDeviceContext *tmp_ctx = (FFHWDeviceContext*)tmp_ref->data; + if (tmp_ctx->p.type == type) { + dst_ref = av_buffer_ref(tmp_ref); + if (!dst_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + goto done; + } + tmp_ref = tmp_ctx->source_device; + } + + dst_ref = av_hwdevice_ctx_alloc(type); + if (!dst_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + dst_ctx = (FFHWDeviceContext*)dst_ref->data; + + tmp_ref = src_ref; + while (tmp_ref) { + FFHWDeviceContext *tmp_ctx = (FFHWDeviceContext*)tmp_ref->data; + if (dst_ctx->hw_type->device_derive) { + ret = dst_ctx->hw_type->device_derive(&dst_ctx->p, + &tmp_ctx->p, + options, flags); + if (ret == 0) { + dst_ctx->source_device = av_buffer_ref(src_ref); + if (!dst_ctx->source_device) { + ret = AVERROR(ENOMEM); + goto fail; + } + ret = av_hwdevice_ctx_init(dst_ref); + if (ret < 0) + goto fail; + goto done; + } + if (ret != AVERROR(ENOSYS)) + goto fail; + } + tmp_ref = tmp_ctx->source_device; + } + + ret = AVERROR(ENOSYS); + goto fail; + +done: + *dst_ref_ptr = dst_ref; + return 0; + +fail: + av_buffer_unref(&dst_ref); + *dst_ref_ptr = NULL; + return ret; +} + +int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ref_ptr, + enum AVHWDeviceType type, + AVBufferRef *src_ref, int flags) +{ + return av_hwdevice_ctx_create_derived_opts(dst_ref_ptr, type, src_ref, + NULL, flags); +} + +static void ff_hwframe_unmap(void *opaque, uint8_t *data) +{ + HWMapDescriptor *hwmap = (HWMapDescriptor*)data; + AVHWFramesContext *ctx = opaque; + + if (hwmap->unmap) + hwmap->unmap(ctx, hwmap); + + av_frame_free(&hwmap->source); + + av_buffer_unref(&hwmap->hw_frames_ctx); + + av_free(hwmap); +} + +int ff_hwframe_map_create(AVBufferRef *hwframe_ref, + AVFrame *dst, const AVFrame *src, + void (*unmap)(AVHWFramesContext *ctx, + HWMapDescriptor *hwmap), + void *priv) +{ + AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; + HWMapDescriptor *hwmap; + int ret; + + hwmap = av_mallocz(sizeof(*hwmap)); + if (!hwmap) { + ret = AVERROR(ENOMEM); + goto fail; + } + + hwmap->source = av_frame_alloc(); + if (!hwmap->source) { + ret = AVERROR(ENOMEM); + goto fail; + } + ret = av_frame_ref(hwmap->source, src); + if (ret < 0) + goto fail; + + hwmap->hw_frames_ctx = av_buffer_ref(hwframe_ref); + if (!hwmap->hw_frames_ctx) { + ret = AVERROR(ENOMEM); + goto fail; + } + + hwmap->unmap = unmap; + hwmap->priv = priv; + + dst->buf[0] = av_buffer_create((uint8_t*)hwmap, sizeof(*hwmap), + &ff_hwframe_unmap, ctx, 0); + if (!dst->buf[0]) { + ret = AVERROR(ENOMEM); + goto fail; + } + + return 0; + +fail: + if (hwmap) { + av_buffer_unref(&hwmap->hw_frames_ctx); + av_frame_free(&hwmap->source); + } + av_free(hwmap); + return ret; +} + +int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags) +{ + AVBufferRef *orig_dst_frames = dst->hw_frames_ctx; + enum AVPixelFormat orig_dst_fmt = dst->format; + HWMapDescriptor *hwmap; + int ret; + + if (src->hw_frames_ctx && dst->hw_frames_ctx) { + FFHWFramesContext *src_frames = (FFHWFramesContext*)src->hw_frames_ctx->data; + FFHWFramesContext *dst_frames = (FFHWFramesContext*)dst->hw_frames_ctx->data; + + if ((src_frames == dst_frames && + src->format == dst_frames->p.sw_format && + dst->format == dst_frames->p.format) || + (src_frames->source_frames && + src_frames->source_frames->data == + (uint8_t*)dst_frames)) { + // This is an unmap operation. We don't need to directly + // do anything here other than fill in the original frame, + // because the real unmap will be invoked when the last + // reference to the mapped frame disappears. + if (!src->buf[0]) { + av_log(src_frames, AV_LOG_ERROR, "Invalid mapping " + "found when attempting unmap.\n"); + return AVERROR(EINVAL); + } + hwmap = (HWMapDescriptor*)src->buf[0]->data; + return av_frame_replace(dst, hwmap->source); + } + } + + if (src->hw_frames_ctx) { + FFHWFramesContext *src_frames = (FFHWFramesContext*)src->hw_frames_ctx->data; + + if (src_frames->p.format == src->format && + src_frames->hw_type->map_from) { + ret = src_frames->hw_type->map_from(&src_frames->p, + dst, src, flags); + if (ret >= 0) + return ret; + else if (ret != AVERROR(ENOSYS)) + goto fail; + } + } + + if (dst->hw_frames_ctx) { + FFHWFramesContext *dst_frames = (FFHWFramesContext*)dst->hw_frames_ctx->data; + + if (dst_frames->p.format == dst->format && + dst_frames->hw_type->map_to) { + ret = dst_frames->hw_type->map_to(&dst_frames->p, + dst, src, flags); + if (ret >= 0) + return ret; + else if (ret != AVERROR(ENOSYS)) + goto fail; + } + } + + return AVERROR(ENOSYS); + +fail: + // if the caller provided dst frames context, it should be preserved + // by this function + av_assert0(orig_dst_frames == NULL || + orig_dst_frames == dst->hw_frames_ctx); + + // preserve user-provided dst frame fields, but clean + // anything we might have set + dst->hw_frames_ctx = NULL; + av_frame_unref(dst); + + dst->hw_frames_ctx = orig_dst_frames; + dst->format = orig_dst_fmt; + + return ret; +} + +int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx, + enum AVPixelFormat format, + AVBufferRef *derived_device_ctx, + AVBufferRef *source_frame_ctx, + int flags) +{ + AVBufferRef *dst_ref = NULL; + FFHWFramesContext *dsti = NULL; + FFHWFramesContext *srci = (FFHWFramesContext*)source_frame_ctx->data; + AVHWFramesContext *dst, *src = &srci->p; + int ret; + + if (srci->source_frames) { + AVHWFramesContext *src_src = + (AVHWFramesContext*)srci->source_frames->data; + AVHWDeviceContext *dst_dev = + (AVHWDeviceContext*)derived_device_ctx->data; + + if (src_src->device_ctx == dst_dev) { + // This is actually an unmapping, so we just return a + // reference to the source frame context. + *derived_frame_ctx = av_buffer_ref(srci->source_frames); + if (!*derived_frame_ctx) { + ret = AVERROR(ENOMEM); + goto fail; + } + return 0; + } + } + + dst_ref = av_hwframe_ctx_alloc(derived_device_ctx); + if (!dst_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + + dsti = (FFHWFramesContext*)dst_ref->data; + dst = &dsti->p; + + dst->format = format; + dst->sw_format = src->sw_format; + dst->width = src->width; + dst->height = src->height; + + dsti->source_frames = av_buffer_ref(source_frame_ctx); + if (!dsti->source_frames) { + ret = AVERROR(ENOMEM); + goto fail; + } + + dsti->source_allocation_map_flags = + flags & (AV_HWFRAME_MAP_READ | + AV_HWFRAME_MAP_WRITE | + AV_HWFRAME_MAP_OVERWRITE | + AV_HWFRAME_MAP_DIRECT); + + ret = AVERROR(ENOSYS); + if (srci->hw_type->frames_derive_from) + ret = srci->hw_type->frames_derive_from(dst, src, flags); + if (ret == AVERROR(ENOSYS) && + dsti->hw_type->frames_derive_to) + ret = dsti->hw_type->frames_derive_to(dst, src, flags); + if (ret == AVERROR(ENOSYS)) + ret = 0; + if (ret) + goto fail; + + *derived_frame_ctx = dst_ref; + return 0; + +fail: + if (dsti) + av_buffer_unref(&dsti->source_frames); + av_buffer_unref(&dst_ref); + return ret; +} + +int ff_hwframe_map_replace(AVFrame *dst, const AVFrame *src) +{ + HWMapDescriptor *hwmap = (HWMapDescriptor*)dst->buf[0]->data; + return av_frame_replace(hwmap->source, src); +} diff --git a/libs/ffmpeg/libavutil/hwcontext.h b/libs/ffmpeg/libavutil/hwcontext.h new file mode 100644 index 00000000000..29374cf0a7e --- /dev/null +++ b/libs/ffmpeg/libavutil/hwcontext.h @@ -0,0 +1,601 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_H +#define AVUTIL_HWCONTEXT_H + +#include "buffer.h" +#include "frame.h" +#include "log.h" +#include "pixfmt.h" + +enum AVHWDeviceType { + AV_HWDEVICE_TYPE_NONE, + AV_HWDEVICE_TYPE_VDPAU, + AV_HWDEVICE_TYPE_CUDA, + AV_HWDEVICE_TYPE_VAAPI, + AV_HWDEVICE_TYPE_DXVA2, + AV_HWDEVICE_TYPE_QSV, + AV_HWDEVICE_TYPE_VIDEOTOOLBOX, + AV_HWDEVICE_TYPE_D3D11VA, + AV_HWDEVICE_TYPE_DRM, + AV_HWDEVICE_TYPE_OPENCL, + AV_HWDEVICE_TYPE_MEDIACODEC, + AV_HWDEVICE_TYPE_VULKAN, + AV_HWDEVICE_TYPE_D3D12VA, + AV_HWDEVICE_TYPE_AMF, + /* OpenHarmony Codec device */ + AV_HWDEVICE_TYPE_OHCODEC, +}; + +/** + * This struct aggregates all the (hardware/vendor-specific) "high-level" state, + * i.e. state that is not tied to a concrete processing configuration. + * E.g., in an API that supports hardware-accelerated encoding and decoding, + * this struct will (if possible) wrap the state that is common to both encoding + * and decoding and from which specific instances of encoders or decoders can be + * derived. + * + * This struct is reference-counted with the AVBuffer mechanism. The + * av_hwdevice_ctx_alloc() constructor yields a reference, whose data field + * points to the actual AVHWDeviceContext. Further objects derived from + * AVHWDeviceContext (such as AVHWFramesContext, describing a frame pool with + * specific properties) will hold an internal reference to it. After all the + * references are released, the AVHWDeviceContext itself will be freed, + * optionally invoking a user-specified callback for uninitializing the hardware + * state. + */ +typedef struct AVHWDeviceContext { + /** + * A class for logging. Set by av_hwdevice_ctx_alloc(). + */ + const AVClass *av_class; + + /** + * This field identifies the underlying API used for hardware access. + * + * This field is set when this struct is allocated and never changed + * afterwards. + */ + enum AVHWDeviceType type; + + /** + * The format-specific data, allocated and freed by libavutil along with + * this context. + * + * Should be cast by the user to the format-specific context defined in the + * corresponding header (hwcontext_*.h) and filled as described in the + * documentation before calling av_hwdevice_ctx_init(). + * + * After calling av_hwdevice_ctx_init() this struct should not be modified + * by the caller. + */ + void *hwctx; + + /** + * This field may be set by the caller before calling av_hwdevice_ctx_init(). + * + * If non-NULL, this callback will be called when the last reference to + * this context is unreferenced, immediately before it is freed. + * + * @note when other objects (e.g an AVHWFramesContext) are derived from this + * struct, this callback will be invoked after all such child objects + * are fully uninitialized and their respective destructors invoked. + */ + void (*free)(struct AVHWDeviceContext *ctx); + + /** + * Arbitrary user data, to be used e.g. by the free() callback. + */ + void *user_opaque; +} AVHWDeviceContext; + +/** + * This struct describes a set or pool of "hardware" frames (i.e. those with + * data not located in normal system memory). All the frames in the pool are + * assumed to be allocated in the same way and interchangeable. + * + * This struct is reference-counted with the AVBuffer mechanism and tied to a + * given AVHWDeviceContext instance. The av_hwframe_ctx_alloc() constructor + * yields a reference, whose data field points to the actual AVHWFramesContext + * struct. + */ +typedef struct AVHWFramesContext { + /** + * A class for logging. + */ + const AVClass *av_class; + + /** + * A reference to the parent AVHWDeviceContext. This reference is owned and + * managed by the enclosing AVHWFramesContext, but the caller may derive + * additional references from it. + */ + AVBufferRef *device_ref; + + /** + * The parent AVHWDeviceContext. This is simply a pointer to + * device_ref->data provided for convenience. + * + * Set by libavutil in av_hwframe_ctx_init(). + */ + AVHWDeviceContext *device_ctx; + + /** + * The format-specific data, allocated and freed automatically along with + * this context. + * + * The user shall ignore this field if the corresponding format-specific + * header (hwcontext_*.h) does not define a context to be used as + * AVHWFramesContext.hwctx. + * + * Otherwise, it should be cast by the user to said context and filled + * as described in the documentation before calling av_hwframe_ctx_init(). + * + * After any frames using this context are created, the contents of this + * struct should not be modified by the caller. + */ + void *hwctx; + + /** + * This field may be set by the caller before calling av_hwframe_ctx_init(). + * + * If non-NULL, this callback will be called when the last reference to + * this context is unreferenced, immediately before it is freed. + */ + void (*free)(struct AVHWFramesContext *ctx); + + /** + * Arbitrary user data, to be used e.g. by the free() callback. + */ + void *user_opaque; + + /** + * A pool from which the frames are allocated by av_hwframe_get_buffer(). + * This field may be set by the caller before calling av_hwframe_ctx_init(). + * The buffers returned by calling av_buffer_pool_get() on this pool must + * have the properties described in the documentation in the corresponding hw + * type's header (hwcontext_*.h). The pool will be freed strictly before + * this struct's free() callback is invoked. + * + * This field may be NULL, then libavutil will attempt to allocate a pool + * internally. Note that certain device types enforce pools allocated at + * fixed size (frame count), which cannot be extended dynamically. In such a + * case, initial_pool_size must be set appropriately. + */ + AVBufferPool *pool; + + /** + * Initial size of the frame pool. If a device type does not support + * dynamically resizing the pool, then this is also the maximum pool size. + * + * May be set by the caller before calling av_hwframe_ctx_init(). Must be + * set if pool is NULL and the device type does not support dynamic pools. + */ + int initial_pool_size; + + /** + * The pixel format identifying the underlying HW surface type. + * + * Must be a hwaccel format, i.e. the corresponding descriptor must have the + * AV_PIX_FMT_FLAG_HWACCEL flag set. + * + * Must be set by the user before calling av_hwframe_ctx_init(). + */ + enum AVPixelFormat format; + + /** + * The pixel format identifying the actual data layout of the hardware + * frames. + * + * Must be set by the caller before calling av_hwframe_ctx_init(). + * + * @note when the underlying API does not provide the exact data layout, but + * only the colorspace/bit depth, this field should be set to the fully + * planar version of that format (e.g. for 8-bit 420 YUV it should be + * AV_PIX_FMT_YUV420P, not AV_PIX_FMT_NV12 or anything else). + */ + enum AVPixelFormat sw_format; + + /** + * The allocated dimensions of the frames in this pool. + * + * Must be set by the user before calling av_hwframe_ctx_init(). + */ + int width, height; +} AVHWFramesContext; + +/** + * Look up an AVHWDeviceType by name. + * + * @param name String name of the device type (case-insensitive). + * @return The type from enum AVHWDeviceType, or AV_HWDEVICE_TYPE_NONE if + * not found. + */ +enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name); + +/** Get the string name of an AVHWDeviceType. + * + * @param type Type from enum AVHWDeviceType. + * @return Pointer to a static string containing the name, or NULL if the type + * is not valid. + */ +const char *av_hwdevice_get_type_name(enum AVHWDeviceType type); + +/** + * Iterate over supported device types. + * + * @param prev AV_HWDEVICE_TYPE_NONE initially, then the previous type + * returned by this function in subsequent iterations. + * @return The next usable device type from enum AVHWDeviceType, or + * AV_HWDEVICE_TYPE_NONE if there are no more. + */ +enum AVHWDeviceType av_hwdevice_iterate_types(enum AVHWDeviceType prev); + +/** + * Allocate an AVHWDeviceContext for a given hardware type. + * + * @param type the type of the hardware device to allocate. + * @return a reference to the newly created AVHWDeviceContext on success or NULL + * on failure. + */ +AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type); + +/** + * Finalize the device context before use. This function must be called after + * the context is filled with all the required information and before it is + * used in any way. + * + * @param ref a reference to the AVHWDeviceContext + * @return 0 on success, a negative AVERROR code on failure + */ +int av_hwdevice_ctx_init(AVBufferRef *ref); + +/** + * Open a device of the specified type and create an AVHWDeviceContext for it. + * + * This is a convenience function intended to cover the simple cases. Callers + * who need to fine-tune device creation/management should open the device + * manually and then wrap it in an AVHWDeviceContext using + * av_hwdevice_ctx_alloc()/av_hwdevice_ctx_init(). + * + * The returned context is already initialized and ready for use, the caller + * should not call av_hwdevice_ctx_init() on it. The user_opaque/free fields of + * the created AVHWDeviceContext are set by this function and should not be + * touched by the caller. + * + * @param device_ctx On success, a reference to the newly-created device context + * will be written here. The reference is owned by the caller + * and must be released with av_buffer_unref() when no longer + * needed. On failure, NULL will be written to this pointer. + * @param type The type of the device to create. + * @param device A type-specific string identifying the device to open. + * @param opts A dictionary of additional (type-specific) options to use in + * opening the device. The dictionary remains owned by the caller. + * @param flags currently unused + * + * @return 0 on success, a negative AVERROR code on failure. + */ +int av_hwdevice_ctx_create(AVBufferRef **device_ctx, enum AVHWDeviceType type, + const char *device, AVDictionary *opts, int flags); + +/** + * Create a new device of the specified type from an existing device. + * + * If the source device is a device of the target type or was originally + * derived from such a device (possibly through one or more intermediate + * devices of other types), then this will return a reference to the + * existing device of the same type as is requested. + * + * Otherwise, it will attempt to derive a new device from the given source + * device. If direct derivation to the new type is not implemented, it will + * attempt the same derivation from each ancestor of the source device in + * turn looking for an implemented derivation method. + * + * @param dst_ctx On success, a reference to the newly-created + * AVHWDeviceContext. + * @param type The type of the new device to create. + * @param src_ctx A reference to an existing AVHWDeviceContext which will be + * used to create the new device. + * @param flags Currently unused; should be set to zero. + * @return Zero on success, a negative AVERROR code on failure. + */ +int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ctx, + enum AVHWDeviceType type, + AVBufferRef *src_ctx, int flags); + +/** + * Create a new device of the specified type from an existing device. + * + * This function performs the same action as av_hwdevice_ctx_create_derived, + * however, it is able to set options for the new device to be derived. + * + * @param dst_ctx On success, a reference to the newly-created + * AVHWDeviceContext. + * @param type The type of the new device to create. + * @param src_ctx A reference to an existing AVHWDeviceContext which will be + * used to create the new device. + * @param options Options for the new device to create, same format as in + * av_hwdevice_ctx_create. + * @param flags Currently unused; should be set to zero. + * @return Zero on success, a negative AVERROR code on failure. + */ +int av_hwdevice_ctx_create_derived_opts(AVBufferRef **dst_ctx, + enum AVHWDeviceType type, + AVBufferRef *src_ctx, + AVDictionary *options, int flags); + +/** + * Allocate an AVHWFramesContext tied to a given device context. + * + * @param device_ctx a reference to a AVHWDeviceContext. This function will make + * a new reference for internal use, the one passed to the + * function remains owned by the caller. + * @return a reference to the newly created AVHWFramesContext on success or NULL + * on failure. + */ +AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ctx); + +/** + * Finalize the context before use. This function must be called after the + * context is filled with all the required information and before it is attached + * to any frames. + * + * @param ref a reference to the AVHWFramesContext + * @return 0 on success, a negative AVERROR code on failure + */ +int av_hwframe_ctx_init(AVBufferRef *ref); + +/** + * Allocate a new frame attached to the given AVHWFramesContext. + * + * @param hwframe_ctx a reference to an AVHWFramesContext + * @param frame an empty (freshly allocated or unreffed) frame to be filled with + * newly allocated buffers. + * @param flags currently unused, should be set to zero + * @return 0 on success, a negative AVERROR code on failure + */ +int av_hwframe_get_buffer(AVBufferRef *hwframe_ctx, AVFrame *frame, int flags); + +/** + * Copy data to or from a hw surface. At least one of dst/src must have an + * AVHWFramesContext attached. + * + * If src has an AVHWFramesContext attached, then the format of dst (if set) + * must use one of the formats returned by av_hwframe_transfer_get_formats(src, + * AV_HWFRAME_TRANSFER_DIRECTION_FROM). + * If dst has an AVHWFramesContext attached, then the format of src must use one + * of the formats returned by av_hwframe_transfer_get_formats(dst, + * AV_HWFRAME_TRANSFER_DIRECTION_TO) + * + * dst may be "clean" (i.e. with data/buf pointers unset), in which case the + * data buffers will be allocated by this function using av_frame_get_buffer(). + * If dst->format is set, then this format will be used, otherwise (when + * dst->format is AV_PIX_FMT_NONE) the first acceptable format will be chosen. + * + * The two frames must have matching allocated dimensions (i.e. equal to + * AVHWFramesContext.width/height), since not all device types support + * transferring a sub-rectangle of the whole surface. The display dimensions + * (i.e. AVFrame.width/height) may be smaller than the allocated dimensions, but + * also have to be equal for both frames. When the display dimensions are + * smaller than the allocated dimensions, the content of the padding in the + * destination frame is unspecified. + * + * @param dst the destination frame. dst is not touched on failure. + * @param src the source frame. + * @param flags currently unused, should be set to zero + * @return 0 on success, a negative AVERROR error code on failure. + */ +int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags); + +enum AVHWFrameTransferDirection { + /** + * Transfer the data from the queried hw frame. + */ + AV_HWFRAME_TRANSFER_DIRECTION_FROM, + + /** + * Transfer the data to the queried hw frame. + */ + AV_HWFRAME_TRANSFER_DIRECTION_TO, +}; + +/** + * Get a list of possible source or target formats usable in + * av_hwframe_transfer_data(). + * + * @param hwframe_ctx the frame context to obtain the information for + * @param dir the direction of the transfer + * @param formats the pointer to the output format list will be written here. + * The list is terminated with AV_PIX_FMT_NONE and must be freed + * by the caller when no longer needed using av_free(). + * If this function returns successfully, the format list will + * have at least one item (not counting the terminator). + * On failure, the contents of this pointer are unspecified. + * @param flags currently unused, should be set to zero + * @return 0 on success, a negative AVERROR code on failure. + */ +int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ctx, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats, int flags); + + +/** + * This struct describes the constraints on hardware frames attached to + * a given device with a hardware-specific configuration. This is returned + * by av_hwdevice_get_hwframe_constraints() and must be freed by + * av_hwframe_constraints_free() after use. + */ +typedef struct AVHWFramesConstraints { + /** + * A list of possible values for format in the hw_frames_ctx, + * terminated by AV_PIX_FMT_NONE. This member will always be filled. + */ + enum AVPixelFormat *valid_hw_formats; + + /** + * A list of possible values for sw_format in the hw_frames_ctx, + * terminated by AV_PIX_FMT_NONE. Can be NULL if this information is + * not known. + */ + enum AVPixelFormat *valid_sw_formats; + + /** + * The minimum size of frames in this hw_frames_ctx. + * (Zero if not known.) + */ + int min_width; + int min_height; + + /** + * The maximum size of frames in this hw_frames_ctx. + * (INT_MAX if not known / no limit.) + */ + int max_width; + int max_height; +} AVHWFramesConstraints; + +/** + * Allocate a HW-specific configuration structure for a given HW device. + * After use, the user must free all members as required by the specific + * hardware structure being used, then free the structure itself with + * av_free(). + * + * @param device_ctx a reference to the associated AVHWDeviceContext. + * @return The newly created HW-specific configuration structure on + * success or NULL on failure. + */ +void *av_hwdevice_hwconfig_alloc(AVBufferRef *device_ctx); + +/** + * Get the constraints on HW frames given a device and the HW-specific + * configuration to be used with that device. If no HW-specific + * configuration is provided, returns the maximum possible capabilities + * of the device. + * + * @param ref a reference to the associated AVHWDeviceContext. + * @param hwconfig a filled HW-specific configuration structure, or NULL + * to return the maximum possible capabilities of the device. + * @return AVHWFramesConstraints structure describing the constraints + * on the device, or NULL if not available. + */ +AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref, + const void *hwconfig); + +/** + * Free an AVHWFrameConstraints structure. + * + * @param constraints The (filled or unfilled) AVHWFrameConstraints structure. + */ +void av_hwframe_constraints_free(AVHWFramesConstraints **constraints); + + +/** + * Flags to apply to frame mappings. + */ +enum { + /** + * The mapping must be readable. + */ + AV_HWFRAME_MAP_READ = 1 << 0, + /** + * The mapping must be writeable. + */ + AV_HWFRAME_MAP_WRITE = 1 << 1, + /** + * The mapped frame will be overwritten completely in subsequent + * operations, so the current frame data need not be loaded. Any values + * which are not overwritten are unspecified. + */ + AV_HWFRAME_MAP_OVERWRITE = 1 << 2, + /** + * The mapping must be direct. That is, there must not be any copying in + * the map or unmap steps. Note that performance of direct mappings may + * be much lower than normal memory. + */ + AV_HWFRAME_MAP_DIRECT = 1 << 3, +}; + +/** + * Map a hardware frame. + * + * This has a number of different possible effects, depending on the format + * and origin of the src and dst frames. On input, src should be a usable + * frame with valid buffers and dst should be blank (typically as just created + * by av_frame_alloc()). src should have an associated hwframe context, and + * dst may optionally have a format and associated hwframe context. + * + * If src was created by mapping a frame from the hwframe context of dst, + * then this function undoes the mapping - dst is replaced by a reference to + * the frame that src was originally mapped from. + * + * If both src and dst have an associated hwframe context, then this function + * attempts to map the src frame from its hardware context to that of dst and + * then fill dst with appropriate data to be usable there. This will only be + * possible if the hwframe contexts and associated devices are compatible - + * given compatible devices, av_hwframe_ctx_create_derived() can be used to + * create a hwframe context for dst in which mapping should be possible. + * + * If src has a hwframe context but dst does not, then the src frame is + * mapped to normal memory and should thereafter be usable as a normal frame. + * If the format is set on dst, then the mapping will attempt to create dst + * with that format and fail if it is not possible. If format is unset (is + * AV_PIX_FMT_NONE) then dst will be mapped with whatever the most appropriate + * format to use is (probably the sw_format of the src hwframe context). + * + * A return value of AVERROR(ENOSYS) indicates that the mapping is not + * possible with the given arguments and hwframe setup, while other return + * values indicate that it failed somehow. + * + * On failure, the destination frame will be left blank, except for the + * hw_frames_ctx/format fields they may have been set by the caller - those will + * be preserved as they were. + * + * @param dst Destination frame, to contain the mapping. + * @param src Source frame, to be mapped. + * @param flags Some combination of AV_HWFRAME_MAP_* flags. + * @return Zero on success, negative AVERROR code on failure. + */ +int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags); + + +/** + * Create and initialise an AVHWFramesContext as a mapping of another existing + * AVHWFramesContext on a different device. + * + * av_hwframe_ctx_init() should not be called after this. + * + * @param derived_frame_ctx On success, a reference to the newly created + * AVHWFramesContext. + * @param format The AVPixelFormat for the derived context. + * @param derived_device_ctx A reference to the device to create the new + * AVHWFramesContext on. + * @param source_frame_ctx A reference to an existing AVHWFramesContext + * which will be mapped to the derived context. + * @param flags Some combination of AV_HWFRAME_MAP_* flags, defining the + * mapping parameters to apply to frames which are allocated + * in the derived device. + * @return Zero on success, negative AVERROR code on failure. + */ +int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx, + enum AVPixelFormat format, + AVBufferRef *derived_device_ctx, + AVBufferRef *source_frame_ctx, + int flags); + +#endif /* AVUTIL_HWCONTEXT_H */ diff --git a/libs/ffmpeg/libavutil/hwcontext_internal.h b/libs/ffmpeg/libavutil/hwcontext_internal.h new file mode 100644 index 00000000000..dcfdc2016a3 --- /dev/null +++ b/libs/ffmpeg/libavutil/hwcontext_internal.h @@ -0,0 +1,169 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_INTERNAL_H +#define AVUTIL_HWCONTEXT_INTERNAL_H + +#include <stddef.h> + +#include "buffer.h" +#include "hwcontext.h" +#include "frame.h" +#include "pixfmt.h" + +typedef struct HWContextType { + enum AVHWDeviceType type; + const char *name; + + /** + * An array of pixel formats supported by the AVHWFramesContext instances + * Terminated by AV_PIX_FMT_NONE. + */ + const enum AVPixelFormat *pix_fmts; + + /** + * size of the public hardware-specific context, + * i.e. AVHWDeviceContext.hwctx + */ + size_t device_hwctx_size; + + /** + * Size of the hardware-specific device configuration. + * (Used to query hwframe constraints.) + */ + size_t device_hwconfig_size; + + /** + * size of the public frame pool hardware-specific context, + * i.e. AVHWFramesContext.hwctx + */ + size_t frames_hwctx_size; + + int (*device_create)(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags); + int (*device_derive)(AVHWDeviceContext *dst_ctx, + AVHWDeviceContext *src_ctx, + AVDictionary *opts, int flags); + + int (*device_init)(AVHWDeviceContext *ctx); + void (*device_uninit)(AVHWDeviceContext *ctx); + + int (*frames_get_constraints)(AVHWDeviceContext *ctx, + const void *hwconfig, + AVHWFramesConstraints *constraints); + + int (*frames_init)(AVHWFramesContext *ctx); + void (*frames_uninit)(AVHWFramesContext *ctx); + + int (*frames_get_buffer)(AVHWFramesContext *ctx, AVFrame *frame); + int (*transfer_get_formats)(AVHWFramesContext *ctx, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats); + int (*transfer_data_to)(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src); + int (*transfer_data_from)(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src); + + int (*map_to)(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src, int flags); + int (*map_from)(AVHWFramesContext *ctx, AVFrame *dst, + const AVFrame *src, int flags); + + int (*frames_derive_to)(AVHWFramesContext *dst_ctx, + AVHWFramesContext *src_ctx, int flags); + int (*frames_derive_from)(AVHWFramesContext *dst_ctx, + AVHWFramesContext *src_ctx, int flags); +} HWContextType; + +typedef struct FFHWFramesContext { + /** + * The public AVHWFramesContext. See hwcontext.h for it. + */ + AVHWFramesContext p; + + const HWContextType *hw_type; + + AVBufferPool *pool_internal; + + /** + * For a derived context, a reference to the original frames + * context it was derived from. + */ + AVBufferRef *source_frames; + /** + * Flags to apply to the mapping from the source to the derived + * frame context when trying to allocate in the derived context. + */ + int source_allocation_map_flags; +} FFHWFramesContext; + +static inline FFHWFramesContext *ffhwframesctx(AVHWFramesContext *ctx) +{ + return (FFHWFramesContext*)ctx; +} + +typedef struct HWMapDescriptor { + /** + * A reference to the original source of the mapping. + */ + AVFrame *source; + /** + * A reference to the hardware frames context in which this + * mapping was made. May be the same as source->hw_frames_ctx, + * but need not be. + */ + AVBufferRef *hw_frames_ctx; + /** + * Unmap function. + */ + void (*unmap)(AVHWFramesContext *ctx, + struct HWMapDescriptor *hwmap); + /** + * Hardware-specific private data associated with the mapping. + */ + void *priv; +} HWMapDescriptor; + +int ff_hwframe_map_create(AVBufferRef *hwframe_ref, + AVFrame *dst, const AVFrame *src, + void (*unmap)(AVHWFramesContext *ctx, + HWMapDescriptor *hwmap), + void *priv); + +/** + * Replace the current hwmap of dst with the one from src, used for indirect + * mappings like VAAPI->(DRM)->OpenCL/Vulkan where a direct interop is missing + */ +int ff_hwframe_map_replace(AVFrame *dst, const AVFrame *src); + +extern const HWContextType ff_hwcontext_type_cuda; +extern const HWContextType ff_hwcontext_type_d3d11va; +extern const HWContextType ff_hwcontext_type_d3d12va; +extern const HWContextType ff_hwcontext_type_drm; +extern const HWContextType ff_hwcontext_type_dxva2; +extern const HWContextType ff_hwcontext_type_opencl; +extern const HWContextType ff_hwcontext_type_qsv; +extern const HWContextType ff_hwcontext_type_vaapi; +extern const HWContextType ff_hwcontext_type_vdpau; +extern const HWContextType ff_hwcontext_type_videotoolbox; +extern const HWContextType ff_hwcontext_type_mediacodec; +extern const HWContextType ff_hwcontext_type_vulkan; +extern const HWContextType ff_hwcontext_type_amf; +extern const HWContextType ff_hwcontext_type_oh; + +#endif /* AVUTIL_HWCONTEXT_INTERNAL_H */ diff --git a/libs/ffmpeg/libavutil/iamf.c b/libs/ffmpeg/libavutil/iamf.c new file mode 100644 index 00000000000..76707563cbb --- /dev/null +++ b/libs/ffmpeg/libavutil/iamf.c @@ -0,0 +1,565 @@ +/* + * Immersive Audio Model and Formats helper functions and defines + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <limits.h> +#include <stddef.h> +#include <stdint.h> + +#include "avassert.h" +#include "error.h" +#include "iamf.h" +#include "log.h" +#include "mem.h" +#include "opt.h" + +#define IAMF_ADD_FUNC_TEMPLATE(parent_type, parent_name, child_type, child_name, suffix) \ +child_type *av_iamf_ ## parent_name ## _add_ ## child_name(parent_type *parent_name) \ +{ \ + child_type **child_name ## suffix, *child_name; \ + \ + if (parent_name->nb_## child_name ## suffix == UINT_MAX) \ + return NULL; \ + \ + child_name ## suffix = av_realloc_array(parent_name->child_name ## suffix, \ + parent_name->nb_## child_name ## suffix + 1, \ + sizeof(*parent_name->child_name ## suffix)); \ + if (!child_name ## suffix) \ + return NULL; \ + \ + parent_name->child_name ## suffix = child_name ## suffix; \ + \ + child_name = parent_name->child_name ## suffix[parent_name->nb_## child_name ## suffix] \ + = av_mallocz(sizeof(*child_name)); \ + if (!child_name) \ + return NULL; \ + \ + child_name->av_class = &child_name ## _class; \ + av_opt_set_defaults(child_name); \ + parent_name->nb_## child_name ## suffix++; \ + \ + return child_name; \ +} + +#define FLAGS AV_OPT_FLAG_ENCODING_PARAM + +// +// Param Definition +// +#define OFFSET(x) offsetof(AVIAMFMixGain, x) +static const AVOption mix_gain_options[] = { + { "subblock_duration", "set subblock_duration", OFFSET(subblock_duration), AV_OPT_TYPE_UINT, {.i64 = 1 }, 1, UINT_MAX, FLAGS }, + { "animation_type", "set animation_type", OFFSET(animation_type), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, 2, FLAGS }, + { "start_point_value", "set start_point_value", OFFSET(start_point_value), AV_OPT_TYPE_RATIONAL, {.dbl = 0 }, -128.0, 128.0, FLAGS }, + { "end_point_value", "set end_point_value", OFFSET(end_point_value), AV_OPT_TYPE_RATIONAL, {.dbl = 0 }, -128.0, 128.0, FLAGS }, + { "control_point_value", "set control_point_value", OFFSET(control_point_value), AV_OPT_TYPE_RATIONAL, {.dbl = 0 }, -128.0, 128.0, FLAGS }, + { "control_point_relative_time", "set control_point_relative_time", OFFSET(control_point_relative_time), AV_OPT_TYPE_RATIONAL, {.dbl = 0 }, 0.0, 1.0, FLAGS }, + { NULL }, +}; + +static const AVClass mix_gain_class = { + .class_name = "AVIAMFMixGain", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = mix_gain_options, +}; + +#undef OFFSET +#define OFFSET(x) offsetof(AVIAMFDemixingInfo, x) +static const AVOption demixing_info_options[] = { + { "subblock_duration", "set subblock_duration", OFFSET(subblock_duration), AV_OPT_TYPE_UINT, {.i64 = 1 }, 1, UINT_MAX, FLAGS }, + { "dmixp_mode", "set dmixp_mode", OFFSET(dmixp_mode), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, 6, FLAGS }, + { NULL }, +}; + +static const AVClass demixing_info_class = { + .class_name = "AVIAMFDemixingInfo", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = demixing_info_options, +}; + +#undef OFFSET +#define OFFSET(x) offsetof(AVIAMFReconGain, x) +static const AVOption recon_gain_options[] = { + { "subblock_duration", "set subblock_duration", OFFSET(subblock_duration), AV_OPT_TYPE_UINT, {.i64 = 1 }, 1, UINT_MAX, FLAGS }, + { NULL }, +}; + +static const AVClass recon_gain_class = { + .class_name = "AVIAMFReconGain", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = recon_gain_options, +}; + +#undef OFFSET +#define OFFSET(x) offsetof(AVIAMFParamDefinition, x) +static const AVOption param_definition_options[] = { + { "parameter_id", "set parameter_id", OFFSET(parameter_id), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, UINT_MAX, FLAGS }, + { "parameter_rate", "set parameter_rate", OFFSET(parameter_rate), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, UINT_MAX, FLAGS }, + { "duration", "set duration", OFFSET(duration), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, UINT_MAX, FLAGS }, + { "constant_subblock_duration", "set constant_subblock_duration", OFFSET(constant_subblock_duration), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, UINT_MAX, FLAGS }, + { NULL }, +}; + +static const AVClass *param_definition_child_iterate(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVClass *ret = NULL; + + switch(i) { + case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: + ret = &mix_gain_class; + break; + case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: + ret = &demixing_info_class; + break; + case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: + ret = &recon_gain_class; + break; + default: + break; + } + + if (ret) + *opaque = (void*)(i + 1); + return ret; +} + +static const AVClass param_definition_class = { + .class_name = "AVIAMFParamDefinition", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = param_definition_options, + .child_class_iterate = param_definition_child_iterate, +}; + +const AVClass *av_iamf_param_definition_get_class(void) +{ + return ¶m_definition_class; +} + +AVIAMFParamDefinition *av_iamf_param_definition_alloc(enum AVIAMFParamDefinitionType type, + unsigned int nb_subblocks, size_t *out_size) +{ + + struct MixGainStruct { + AVIAMFParamDefinition p; + AVIAMFMixGain m; + }; + struct DemixStruct { + AVIAMFParamDefinition p; + AVIAMFDemixingInfo d; + }; + struct ReconGainStruct { + AVIAMFParamDefinition p; + AVIAMFReconGain r; + }; + size_t subblocks_offset, subblock_size; + size_t size; + AVIAMFParamDefinition *par; + + switch (type) { + case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: + subblocks_offset = offsetof(struct MixGainStruct, m); + subblock_size = sizeof(AVIAMFMixGain); + break; + case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: + subblocks_offset = offsetof(struct DemixStruct, d); + subblock_size = sizeof(AVIAMFDemixingInfo); + break; + case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: + subblocks_offset = offsetof(struct ReconGainStruct, r); + subblock_size = sizeof(AVIAMFReconGain); + break; + default: + return NULL; + } + + size = subblocks_offset; + if (nb_subblocks > (SIZE_MAX - size) / subblock_size) + return NULL; + size += subblock_size * nb_subblocks; + + par = av_mallocz(size); + if (!par) + return NULL; + + par->av_class = ¶m_definition_class; + av_opt_set_defaults(par); + + par->type = type; + par->nb_subblocks = nb_subblocks; + par->subblock_size = subblock_size; + par->subblocks_offset = subblocks_offset; + + for (int i = 0; i < nb_subblocks; i++) { + void *subblock = av_iamf_param_definition_get_subblock(par, i); + + switch (type) { + case AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN: + ((AVIAMFMixGain *)subblock)->av_class = &mix_gain_class; + break; + case AV_IAMF_PARAMETER_DEFINITION_DEMIXING: + ((AVIAMFDemixingInfo *)subblock)->av_class = &demixing_info_class; + break; + case AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN: + ((AVIAMFReconGain *)subblock)->av_class = &recon_gain_class; + break; + default: + av_assert0(0); + } + } + + if (out_size) + *out_size = size; + + return par; +} + +// +// Audio Element +// +static const AVOptionArrayDef demixing_matrix_def = { .size_max = (255 + 255) * 255, .sep = '|' }; + +#undef OFFSET +#define OFFSET(x) offsetof(AVIAMFLayer, x) +static const AVOption layer_options[] = { + { "ch_layout", "set ch_layout", OFFSET(ch_layout), AV_OPT_TYPE_CHLAYOUT, {.str = NULL }, 0, 0, FLAGS }, + { "flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, + {.i64 = 0 }, 0, AV_IAMF_LAYER_FLAG_RECON_GAIN, FLAGS, .unit = "flags" }, + {"recon_gain", "Recon gain is present", 0, AV_OPT_TYPE_CONST, + {.i64 = AV_IAMF_LAYER_FLAG_RECON_GAIN }, INT_MIN, INT_MAX, FLAGS, .unit = "flags"}, + { "output_gain_flags", "set output_gain_flags", OFFSET(output_gain_flags), AV_OPT_TYPE_FLAGS, + {.i64 = 0 }, 0, (1 << 6) - 1, FLAGS, .unit = "output_gain_flags" }, + {"FL", "Left channel", 0, AV_OPT_TYPE_CONST, + {.i64 = 1 << 5 }, INT_MIN, INT_MAX, FLAGS, .unit = "output_gain_flags"}, + {"FR", "Right channel", 0, AV_OPT_TYPE_CONST, + {.i64 = 1 << 4 }, INT_MIN, INT_MAX, FLAGS, .unit = "output_gain_flags"}, + {"BL", "Left surround channel", 0, AV_OPT_TYPE_CONST, + {.i64 = 1 << 3 }, INT_MIN, INT_MAX, FLAGS, .unit = "output_gain_flags"}, + {"BR", "Right surround channel", 0, AV_OPT_TYPE_CONST, + {.i64 = 1 << 2 }, INT_MIN, INT_MAX, FLAGS, .unit = "output_gain_flags"}, + {"TFL", "Left top front channel", 0, AV_OPT_TYPE_CONST, + {.i64 = 1 << 1 }, INT_MIN, INT_MAX, FLAGS, .unit = "output_gain_flags"}, + {"TFR", "Right top front channel", 0, AV_OPT_TYPE_CONST, + {.i64 = 1 << 0 }, INT_MIN, INT_MAX, FLAGS, .unit = "output_gain_flags"}, + { "output_gain", "set output_gain", OFFSET(output_gain), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS }, + { "ambisonics_mode", "set ambisonics_mode", OFFSET(ambisonics_mode), AV_OPT_TYPE_INT, + { .i64 = AV_IAMF_AMBISONICS_MODE_MONO }, + AV_IAMF_AMBISONICS_MODE_MONO, AV_IAMF_AMBISONICS_MODE_PROJECTION, FLAGS, .unit = "ambisonics_mode" }, + { "mono", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = AV_IAMF_AMBISONICS_MODE_MONO }, .unit = "ambisonics_mode" }, + { "projection", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = AV_IAMF_AMBISONICS_MODE_PROJECTION }, .unit = "ambisonics_mode" }, + { "demixing_matrix", "set demixing_matrix", OFFSET(demixing_matrix), AV_OPT_TYPE_RATIONAL | AV_OPT_TYPE_FLAG_ARRAY, + { .arr = &demixing_matrix_def }, -1.0, 1.0, FLAGS }, + { NULL }, +}; + +static const AVClass layer_class = { + .class_name = "AVIAMFLayer", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = layer_options, +}; + +#undef OFFSET +#define OFFSET(x) offsetof(AVIAMFAudioElement, x) +static const AVOption audio_element_options[] = { + { "audio_element_type", "set audio_element_type", OFFSET(audio_element_type), AV_OPT_TYPE_INT, + {.i64 = AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL }, + AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL, AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE, FLAGS, .unit = "audio_element_type" }, + { "channel", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL }, .unit = "audio_element_type" }, + { "scene", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE }, .unit = "audio_element_type" }, + { "default_w", "set default_w", OFFSET(default_w), AV_OPT_TYPE_UINT, {.i64 = 0 }, 0, 10, FLAGS }, + { NULL }, +}; + +static const AVClass *audio_element_child_iterate(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVClass *ret = NULL; + + if (i) + ret = &layer_class; + + if (ret) + *opaque = (void*)(i + 1); + return ret; +} + +static const AVClass audio_element_class = { + .class_name = "AVIAMFAudioElement", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = audio_element_options, + .child_class_iterate = audio_element_child_iterate, +}; + +const AVClass *av_iamf_audio_element_get_class(void) +{ + return &audio_element_class; +} + +AVIAMFAudioElement *av_iamf_audio_element_alloc(void) +{ + AVIAMFAudioElement *audio_element = av_mallocz(sizeof(*audio_element)); + + if (audio_element) { + audio_element->av_class = &audio_element_class; + av_opt_set_defaults(audio_element); + } + + return audio_element; +} + +IAMF_ADD_FUNC_TEMPLATE(AVIAMFAudioElement, audio_element, AVIAMFLayer, layer, s) + +void av_iamf_audio_element_free(AVIAMFAudioElement **paudio_element) +{ + AVIAMFAudioElement *audio_element = *paudio_element; + + if (!audio_element) + return; + + for (int i = 0; i < audio_element->nb_layers; i++) { + AVIAMFLayer *layer = audio_element->layers[i]; + av_opt_free(layer); + av_free(layer->demixing_matrix); + av_free(layer); + } + av_free(audio_element->layers); + + av_free(audio_element->demixing_info); + av_free(audio_element->recon_gain_info); + av_freep(paudio_element); +} + +// +// Mix Presentation +// +#undef OFFSET +#define OFFSET(x) offsetof(AVIAMFSubmixElement, x) +static const AVOption submix_element_options[] = { + { "headphones_rendering_mode", "Headphones rendering mode", OFFSET(headphones_rendering_mode), AV_OPT_TYPE_INT, + { .i64 = AV_IAMF_HEADPHONES_MODE_STEREO }, + AV_IAMF_HEADPHONES_MODE_STEREO, AV_IAMF_HEADPHONES_MODE_BINAURAL, FLAGS, .unit = "headphones_rendering_mode" }, + { "stereo", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = AV_IAMF_HEADPHONES_MODE_STEREO }, .unit = "headphones_rendering_mode" }, + { "binaural", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = AV_IAMF_HEADPHONES_MODE_BINAURAL }, .unit = "headphones_rendering_mode" }, + { "default_mix_gain", "Default mix gain", OFFSET(default_mix_gain), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS }, + { "annotations", "Annotations", OFFSET(annotations), AV_OPT_TYPE_DICT, { .str = NULL }, 0, 0, FLAGS }, + { NULL }, +}; + +static void *submix_element_child_next(void *obj, void *prev) +{ + AVIAMFSubmixElement *submix_element = obj; + if (!prev) + return submix_element->element_mix_config; + + return NULL; +} + +static const AVClass *submix_element_child_iterate(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVClass *ret = NULL; + + if (i) + ret = ¶m_definition_class; + + if (ret) + *opaque = (void*)(i + 1); + return ret; +} + +static const AVClass element_class = { + .class_name = "AVIAMFSubmixElement", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = submix_element_options, + .child_next = submix_element_child_next, + .child_class_iterate = submix_element_child_iterate, +}; + +IAMF_ADD_FUNC_TEMPLATE(AVIAMFSubmix, submix, AVIAMFSubmixElement, element, s) + +#undef OFFSET +#define OFFSET(x) offsetof(AVIAMFSubmixLayout, x) +static const AVOption submix_layout_options[] = { + { "layout_type", "Layout type", OFFSET(layout_type), AV_OPT_TYPE_INT, + { .i64 = AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS }, + AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS, AV_IAMF_SUBMIX_LAYOUT_TYPE_BINAURAL, FLAGS, .unit = "layout_type" }, + { "loudspeakers", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS }, .unit = "layout_type" }, + { "binaural", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = AV_IAMF_SUBMIX_LAYOUT_TYPE_BINAURAL }, .unit = "layout_type" }, + { "sound_system", "Sound System", OFFSET(sound_system), AV_OPT_TYPE_CHLAYOUT, { .str = NULL }, 0, 0, FLAGS }, + { "integrated_loudness", "Integrated loudness", OFFSET(integrated_loudness), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS }, + { "digital_peak", "Digital peak", OFFSET(digital_peak), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS }, + { "true_peak", "True peak", OFFSET(true_peak), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS }, + { "dialog_anchored_loudness", "Anchored loudness (Dialog)", OFFSET(dialogue_anchored_loudness), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS }, + { "album_anchored_loudness", "Anchored loudness (Album)", OFFSET(album_anchored_loudness), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS }, + { NULL }, +}; + +static const AVClass layout_class = { + .class_name = "AVIAMFSubmixLayout", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = submix_layout_options, +}; + +IAMF_ADD_FUNC_TEMPLATE(AVIAMFSubmix, submix, AVIAMFSubmixLayout, layout, s) + +#undef OFFSET +#define OFFSET(x) offsetof(AVIAMFSubmix, x) +static const AVOption submix_presentation_options[] = { + { "default_mix_gain", "Default mix gain", OFFSET(default_mix_gain), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, -128.0, 128.0, FLAGS }, + { NULL }, +}; + +static void *submix_presentation_child_next(void *obj, void *prev) +{ + AVIAMFSubmix *sub_mix = obj; + if (!prev) + return sub_mix->output_mix_config; + + return NULL; +} + +static const AVClass *submix_presentation_child_iterate(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVClass *ret = NULL; + + switch(i) { + case 0: + ret = &element_class; + break; + case 1: + ret = &layout_class; + break; + case 2: + ret = ¶m_definition_class; + break; + default: + break; + } + + if (ret) + *opaque = (void*)(i + 1); + return ret; +} + +static const AVClass submix_class = { + .class_name = "AVIAMFSubmix", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = submix_presentation_options, + .child_next = submix_presentation_child_next, + .child_class_iterate = submix_presentation_child_iterate, +}; + +#undef OFFSET +#define OFFSET(x) offsetof(AVIAMFMixPresentation, x) +static const AVOption mix_presentation_options[] = { + { "annotations", "set annotations", OFFSET(annotations), AV_OPT_TYPE_DICT, {.str = NULL }, 0, 0, FLAGS }, + { NULL }, +}; + +#undef OFFSET +#undef FLAGS + +static const AVClass *mix_presentation_child_iterate(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVClass *ret = NULL; + + if (i) + ret = &submix_class; + + if (ret) + *opaque = (void*)(i + 1); + return ret; +} + +static const AVClass mix_presentation_class = { + .class_name = "AVIAMFMixPresentation", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .option = mix_presentation_options, + .child_class_iterate = mix_presentation_child_iterate, +}; + +const AVClass *av_iamf_mix_presentation_get_class(void) +{ + return &mix_presentation_class; +} + +AVIAMFMixPresentation *av_iamf_mix_presentation_alloc(void) +{ + AVIAMFMixPresentation *mix_presentation = av_mallocz(sizeof(*mix_presentation)); + + if (mix_presentation) { + mix_presentation->av_class = &mix_presentation_class; + av_opt_set_defaults(mix_presentation); + } + + return mix_presentation; +} + +IAMF_ADD_FUNC_TEMPLATE(AVIAMFMixPresentation, mix_presentation, AVIAMFSubmix, submix, es) + +void av_iamf_mix_presentation_free(AVIAMFMixPresentation **pmix_presentation) +{ + AVIAMFMixPresentation *mix_presentation = *pmix_presentation; + + if (!mix_presentation) + return; + + for (int i = 0; i < mix_presentation->nb_submixes; i++) { + AVIAMFSubmix *sub_mix = mix_presentation->submixes[i]; + for (int j = 0; j < sub_mix->nb_elements; j++) { + AVIAMFSubmixElement *submix_element = sub_mix->elements[j]; + av_opt_free(submix_element); + av_free(submix_element->element_mix_config); + av_free(submix_element); + } + av_free(sub_mix->elements); + for (int j = 0; j < sub_mix->nb_layouts; j++) { + AVIAMFSubmixLayout *submix_layout = sub_mix->layouts[j]; + av_opt_free(submix_layout); + av_free(submix_layout); + } + av_free(sub_mix->layouts); + av_free(sub_mix->output_mix_config); + av_free(sub_mix); + } + av_opt_free(mix_presentation); + av_free(mix_presentation->submixes); + + av_freep(pmix_presentation); +} diff --git a/libs/ffmpeg/libavutil/iamf.h b/libs/ffmpeg/libavutil/iamf.h new file mode 100644 index 00000000000..a755e7d682e --- /dev/null +++ b/libs/ffmpeg/libavutil/iamf.h @@ -0,0 +1,697 @@ +/* + * Immersive Audio Model and Formats helper functions and defines + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_IAMF_H +#define AVUTIL_IAMF_H + +/** + * @file + * Immersive Audio Model and Formats API header + * @see <a href="https://aomediacodec.github.io/iamf/">Immersive Audio Model and Formats</a> + */ + +#include <stdint.h> +#include <stddef.h> + +#include "attributes.h" +#include "avassert.h" +#include "channel_layout.h" +#include "dict.h" +#include "rational.h" + +/** + * @defgroup lavu_iamf Immersive Audio Model and Formats + * @ingroup lavu_audio + * + * Immersive Audio Model and Formats related functions and defines + * + * @defgroup lavu_iamf_params Parameter Definition + * @ingroup lavu_iamf + * @{ + * Parameters as defined in section 3.6.1 and 3.8 of IAMF. + * @} + * + * @defgroup lavu_iamf_audio Audio Element + * @ingroup lavu_iamf + * @{ + * Audio Elements as defined in section 3.6 of IAMF. + * @} + * + * @defgroup lavu_iamf_mix Mix Presentation + * @ingroup lavu_iamf + * @{ + * Mix Presentations as defined in section 3.7 of IAMF. + * @} + * + * @addtogroup lavu_iamf_params + * @{ + */ +enum AVIAMFAnimationType { + AV_IAMF_ANIMATION_TYPE_STEP, + AV_IAMF_ANIMATION_TYPE_LINEAR, + AV_IAMF_ANIMATION_TYPE_BEZIER, +}; + +/** + * Mix Gain Parameter Data as defined in section 3.8.1 of IAMF. + * + * @note This struct's size is not a part of the public ABI. + */ +typedef struct AVIAMFMixGain { + const AVClass *av_class; + + /** + * Duration for the given subblock, in units of + * 1 / @ref AVIAMFParamDefinition.parameter_rate "parameter_rate". + * It must not be 0. + */ + unsigned int subblock_duration; + /** + * The type of animation applied to the parameter values. + */ + enum AVIAMFAnimationType animation_type; + /** + * Parameter value that is applied at the start of the subblock. + * Applies to all defined Animation Types. + * + * Valid range of values is -128.0 to 128.0 + */ + AVRational start_point_value; + /** + * Parameter value that is applied at the end of the subblock. + * Applies only to AV_IAMF_ANIMATION_TYPE_LINEAR and + * AV_IAMF_ANIMATION_TYPE_BEZIER Animation Types. + * + * Valid range of values is -128.0 to 128.0 + */ + AVRational end_point_value; + /** + * Parameter value of the middle control point of a quadratic Bezier + * curve, i.e., its y-axis value. + * Applies only to AV_IAMF_ANIMATION_TYPE_BEZIER Animation Type. + * + * Valid range of values is -128.0 to 128.0 + */ + AVRational control_point_value; + /** + * Parameter value of the time of the middle control point of a + * quadratic Bezier curve, i.e., its x-axis value. + * Applies only to AV_IAMF_ANIMATION_TYPE_BEZIER Animation Type. + * + * Valid range of values is 0.0 to 1.0 + */ + AVRational control_point_relative_time; +} AVIAMFMixGain; + +/** + * Demixing Info Parameter Data as defined in section 3.8.2 of IAMF. + * + * @note This struct's size is not a part of the public ABI. + */ +typedef struct AVIAMFDemixingInfo { + const AVClass *av_class; + + /** + * Duration for the given subblock, in units of + * 1 / @ref AVIAMFParamDefinition.parameter_rate "parameter_rate". + * It must not be 0. + */ + unsigned int subblock_duration; + /** + * Pre-defined combination of demixing parameters. + */ + unsigned int dmixp_mode; +} AVIAMFDemixingInfo; + +/** + * Recon Gain Info Parameter Data as defined in section 3.8.3 of IAMF. + * + * @note This struct's size is not a part of the public ABI. + */ +typedef struct AVIAMFReconGain { + const AVClass *av_class; + + /** + * Duration for the given subblock, in units of + * 1 / @ref AVIAMFParamDefinition.parameter_rate "parameter_rate". + * It must not be 0. + */ + unsigned int subblock_duration; + + /** + * Array of gain values to be applied to each channel for each layer + * defined in the Audio Element referencing the parent Parameter Definition. + * Values for layers where the AV_IAMF_LAYER_FLAG_RECON_GAIN flag is not set + * are undefined. + * + * Channel order is: FL, C, FR, SL, SR, TFL, TFR, BL, BR, TBL, TBR, LFE + */ + uint8_t recon_gain[6][12]; +} AVIAMFReconGain; + +enum AVIAMFParamDefinitionType { + /** + * Subblocks are of struct type AVIAMFMixGain + */ + AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN, + /** + * Subblocks are of struct type AVIAMFDemixingInfo + */ + AV_IAMF_PARAMETER_DEFINITION_DEMIXING, + /** + * Subblocks are of struct type AVIAMFReconGain + */ + AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN, +}; + +/** + * Parameters as defined in section 3.6.1 of IAMF. + * + * The struct is allocated by av_iamf_param_definition_alloc() along with an + * array of subblocks, its type depending on the value of type. + * This array is placed subblocks_offset bytes after the start of this struct. + * + * @note This struct's size is not a part of the public ABI. + */ +typedef struct AVIAMFParamDefinition { + const AVClass *av_class; + + /** + * Offset in bytes from the start of this struct, at which the subblocks + * array is located. + */ + size_t subblocks_offset; + /** + * Size in bytes of each element in the subblocks array. + */ + size_t subblock_size; + /** + * Number of subblocks in the array. + */ + unsigned int nb_subblocks; + + /** + * Parameters type. Determines the type of the subblock elements. + */ + enum AVIAMFParamDefinitionType type; + + /** + * Identifier for the parameter substream. + */ + unsigned int parameter_id; + /** + * Sample rate for the parameter substream. It must not be 0. + */ + unsigned int parameter_rate; + + /** + * The accumulated duration of all blocks in this parameter definition, + * in units of 1 / @ref parameter_rate. + * + * May be 0, in which case all duration values should be specified in + * another parameter definition referencing the same parameter_id. + */ + unsigned int duration; + /** + * The duration of every subblock in the case where all subblocks, with + * the optional exception of the last subblock, have equal durations. + * + * Must be 0 if subblocks have different durations. + */ + unsigned int constant_subblock_duration; +} AVIAMFParamDefinition; + +const AVClass *av_iamf_param_definition_get_class(void); + +/** + * Allocates memory for AVIAMFParamDefinition, plus an array of {@code nb_subblocks} + * amount of subblocks of the given type and initializes the variables. Can be + * freed with a normal av_free() call. + * + * @param size if non-NULL, the size in bytes of the resulting data array is written here. + */ +AVIAMFParamDefinition *av_iamf_param_definition_alloc(enum AVIAMFParamDefinitionType type, + unsigned int nb_subblocks, size_t *size); + +/** + * Get the subblock at the specified {@code idx}. Must be between 0 and nb_subblocks - 1. + * + * The @ref AVIAMFParamDefinition.type "param definition type" defines + * the struct type of the returned pointer. + */ +static av_always_inline void* +av_iamf_param_definition_get_subblock(const AVIAMFParamDefinition *par, unsigned int idx) +{ + av_assert0(idx < par->nb_subblocks); + return (void *)((uint8_t *)par + par->subblocks_offset + idx * par->subblock_size); +} + +/** + * @} + * @addtogroup lavu_iamf_audio + * @{ + */ + +enum AVIAMFAmbisonicsMode { + AV_IAMF_AMBISONICS_MODE_MONO, + AV_IAMF_AMBISONICS_MODE_PROJECTION, +}; + +/** + * Recon gain information for the layer is present in AVIAMFReconGain + */ +#define AV_IAMF_LAYER_FLAG_RECON_GAIN (1 << 0) + +/** + * A layer defining a Channel Layout in the Audio Element. + * + * When @ref AVIAMFAudioElement.audio_element_type "the parent's Audio Element type" + * is AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL, this corresponds to an Scalable Channel + * Layout layer as defined in section 3.6.2 of IAMF. + * For AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE, it is an Ambisonics channel + * layout as defined in section 3.6.3 of IAMF. + * + * @note The struct should be allocated with av_iamf_audio_element_add_layer() + * and its size is not a part of the public ABI. + */ +typedef struct AVIAMFLayer { + const AVClass *av_class; + + AVChannelLayout ch_layout; + + /** + * A bitmask which may contain a combination of AV_IAMF_LAYER_FLAG_* flags. + */ + unsigned int flags; + /** + * Output gain channel flags as defined in section 3.6.2 of IAMF. + * + * This field is defined only if @ref AVIAMFAudioElement.audio_element_type + * "the parent's Audio Element type" is AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL, + * must be 0 otherwise. + */ + unsigned int output_gain_flags; + /** + * Output gain as defined in section 3.6.2 of IAMF. + * + * Must be 0 if @ref output_gain_flags is 0. + */ + AVRational output_gain; + /** + * Ambisonics mode as defined in section 3.6.3 of IAMF. + * + * This field is defined only if @ref AVIAMFAudioElement.audio_element_type + * "the parent's Audio Element type" is AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE. + * + * If AV_IAMF_AMBISONICS_MODE_MONO, channel_mapping is defined implicitly + * (Ambisonic Order) or explicitly (Custom Order with ambi channels) in + * @ref ch_layout. + * If AV_IAMF_AMBISONICS_MODE_PROJECTION, @ref demixing_matrix must be set. + */ + enum AVIAMFAmbisonicsMode ambisonics_mode; + + /** + * Demixing matrix as defined in section 3.6.3 of IAMF. + * + * May be set only if @ref ambisonics_mode == AV_IAMF_AMBISONICS_MODE_PROJECTION, + * must be NULL otherwise. + */ + AVRational *demixing_matrix; + + /** + * The length of the Demixing matrix array. Must be ch_layout.nb_channels multiplied + * by the sum of the amount of streams in the group plus the amount of streams in + * the group that are stereo. + */ + unsigned int nb_demixing_matrix; +} AVIAMFLayer; + + +enum AVIAMFAudioElementType { + AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL, + AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE, +}; + +/** + * Information on how to combine one or more audio streams, as defined in + * section 3.6 of IAMF. + * + * @note The struct should be allocated with av_iamf_audio_element_alloc() + * and its size is not a part of the public ABI. + */ +typedef struct AVIAMFAudioElement { + const AVClass *av_class; + + AVIAMFLayer **layers; + /** + * Number of layers, or channel groups, in the Audio Element. + * There may be 6 layers at most, and for @ref audio_element_type + * AV_IAMF_AUDIO_ELEMENT_TYPE_SCENE, there may be exactly 1. + * + * Set by av_iamf_audio_element_add_layer(), must not be + * modified by any other code. + */ + unsigned int nb_layers; + + /** + * Demixing information used to reconstruct a scalable channel audio + * representation. + * The @ref AVIAMFParamDefinition.type "type" must be + * AV_IAMF_PARAMETER_DEFINITION_DEMIXING. + */ + AVIAMFParamDefinition *demixing_info; + /** + * Recon gain information used to reconstruct a scalable channel audio + * representation. + * The @ref AVIAMFParamDefinition.type "type" must be + * AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN. + */ + AVIAMFParamDefinition *recon_gain_info; + + /** + * Audio element type as defined in section 3.6 of IAMF. + */ + enum AVIAMFAudioElementType audio_element_type; + + /** + * Default weight value as defined in section 3.6 of IAMF. + */ + unsigned int default_w; +} AVIAMFAudioElement; + +const AVClass *av_iamf_audio_element_get_class(void); + +/** + * Allocates a AVIAMFAudioElement, and initializes its fields with default values. + * No layers are allocated. Must be freed with av_iamf_audio_element_free(). + * + * @see av_iamf_audio_element_add_layer() + */ +AVIAMFAudioElement *av_iamf_audio_element_alloc(void); + +/** + * Allocate a layer and add it to a given AVIAMFAudioElement. + * It is freed by av_iamf_audio_element_free() alongside the rest of the parent + * AVIAMFAudioElement. + * + * @return a pointer to the allocated layer. + */ +AVIAMFLayer *av_iamf_audio_element_add_layer(AVIAMFAudioElement *audio_element); + +/** + * Free an AVIAMFAudioElement and all its contents. + * + * @param audio_element pointer to pointer to an allocated AVIAMFAudioElement. + * upon return, *audio_element will be set to NULL. + */ +void av_iamf_audio_element_free(AVIAMFAudioElement **audio_element); + +/** + * @} + * @addtogroup lavu_iamf_mix + * @{ + */ + +enum AVIAMFHeadphonesMode { + /** + * The referenced Audio Element shall be rendered to stereo loudspeakers. + */ + AV_IAMF_HEADPHONES_MODE_STEREO, + /** + * The referenced Audio Element shall be rendered with a binaural renderer. + */ + AV_IAMF_HEADPHONES_MODE_BINAURAL, +}; + +/** + * Submix element as defined in section 3.7 of IAMF. + * + * @note The struct should be allocated with av_iamf_submix_add_element() + * and its size is not a part of the public ABI. + */ +typedef struct AVIAMFSubmixElement { + const AVClass *av_class; + + /** + * The id of the Audio Element this submix element references. + */ + unsigned int audio_element_id; + + /** + * Information required required for applying any processing to the + * referenced and rendered Audio Element before being summed with other + * processed Audio Elements. + * The @ref AVIAMFParamDefinition.type "type" must be + * AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN. + */ + AVIAMFParamDefinition *element_mix_config; + + /** + * Default mix gain value to apply when there are no AVIAMFParamDefinition + * with @ref element_mix_config "element_mix_config's" + * @ref AVIAMFParamDefinition.parameter_id "parameter_id" available for a + * given audio frame. + */ + AVRational default_mix_gain; + + /** + * A value that indicates whether the referenced channel-based Audio Element + * shall be rendered to stereo loudspeakers or spatialized with a binaural + * renderer when played back on headphones. + * If the Audio Element is not of @ref AVIAMFAudioElement.audio_element_type + * "type" AV_IAMF_AUDIO_ELEMENT_TYPE_CHANNEL, then this field is undefined. + */ + enum AVIAMFHeadphonesMode headphones_rendering_mode; + + /** + * A dictionary of strings describing the submix in different languages. + * Must have the same amount of entries as + * @ref AVIAMFMixPresentation.annotations "the mix's annotations", stored + * in the same order, and with the same key strings. + * + * @ref AVDictionaryEntry.key "key" is a string conforming to BCP-47 that + * specifies the language for the string stored in + * @ref AVDictionaryEntry.value "value". + */ + AVDictionary *annotations; +} AVIAMFSubmixElement; + +enum AVIAMFSubmixLayoutType { + /** + * The layout follows the loudspeaker sound system convention of ITU-2051-3. + * @ref AVIAMFSubmixLayout.sound_system must be set. + */ + AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS = 2, + /** + * The layout is binaural. + * + * @note @ref AVIAMFSubmixLayout.sound_system may be set to + * AV_CHANNEL_LAYOUT_BINAURAL to simplify API usage, but it's not mandatory. + */ + AV_IAMF_SUBMIX_LAYOUT_TYPE_BINAURAL = 3, +}; + +/** + * Submix layout as defined in section 3.7.6 of IAMF. + * + * @note The struct should be allocated with av_iamf_submix_add_layout() + * and its size is not a part of the public ABI. + */ +typedef struct AVIAMFSubmixLayout { + const AVClass *av_class; + + enum AVIAMFSubmixLayoutType layout_type; + + /** + * Channel layout matching one of Sound Systems A to J of ITU-2051-3, plus + * 7.1.2ch, 3.1.2ch, and binaural. + * If layout_type is not AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS or + * AV_IAMF_SUBMIX_LAYOUT_TYPE_BINAURAL, this field is undefined. + */ + AVChannelLayout sound_system; + /** + * The program integrated loudness information, as defined in + * ITU-1770-4. + */ + AVRational integrated_loudness; + /** + * The digital (sampled) peak value of the audio signal, as defined + * in ITU-1770-4. + */ + AVRational digital_peak; + /** + * The true peak of the audio signal, as defined in ITU-1770-4. + */ + AVRational true_peak; + /** + * The Dialogue loudness information, as defined in ITU-1770-4. + */ + AVRational dialogue_anchored_loudness; + /** + * The Album loudness information, as defined in ITU-1770-4. + */ + AVRational album_anchored_loudness; +} AVIAMFSubmixLayout; + +/** + * Submix layout as defined in section 3.7 of IAMF. + * + * @note The struct should be allocated with av_iamf_mix_presentation_add_submix() + * and its size is not a part of the public ABI. + */ +typedef struct AVIAMFSubmix { + const AVClass *av_class; + + /** + * Array of submix elements. + * + * Set by av_iamf_submix_add_element(), must not be modified by any + * other code. + */ + AVIAMFSubmixElement **elements; + /** + * Number of elements in the submix. + * + * Set by av_iamf_submix_add_element(), must not be modified by any + * other code. + */ + unsigned int nb_elements; + + /** + * Array of submix layouts. + * + * Set by av_iamf_submix_add_layout(), must not be modified by any + * other code. + */ + AVIAMFSubmixLayout **layouts; + /** + * Number of layouts in the submix. + * + * Set by av_iamf_submix_add_layout(), must not be modified by any + * other code. + */ + unsigned int nb_layouts; + + /** + * Information required for post-processing the mixed audio signal to + * generate the audio signal for playback. + * The @ref AVIAMFParamDefinition.type "type" must be + * AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN. + */ + AVIAMFParamDefinition *output_mix_config; + + /** + * Default mix gain value to apply when there are no AVIAMFParamDefinition + * with @ref output_mix_config "output_mix_config's" + * @ref AVIAMFParamDefinition.parameter_id "parameter_id" available for a + * given audio frame. + */ + AVRational default_mix_gain; +} AVIAMFSubmix; + +/** + * Information on how to render and mix one or more AVIAMFAudioElement to generate + * the final audio output, as defined in section 3.7 of IAMF. + * + * @note The struct should be allocated with av_iamf_mix_presentation_alloc() + * and its size is not a part of the public ABI. + */ +typedef struct AVIAMFMixPresentation { + const AVClass *av_class; + + /** + * Array of submixes. + * + * Set by av_iamf_mix_presentation_add_submix(), must not be modified + * by any other code. + */ + AVIAMFSubmix **submixes; + /** + * Number of submixes in the presentation. + * + * Set by av_iamf_mix_presentation_add_submix(), must not be modified + * by any other code. + */ + unsigned int nb_submixes; + + /** + * A dictionary of strings describing the mix in different languages. + * Must have the same amount of entries as every + * @ref AVIAMFSubmixElement.annotations "Submix element annotations", + * stored in the same order, and with the same key strings. + * + * @ref AVDictionaryEntry.key "key" is a string conforming to BCP-47 + * that specifies the language for the string stored in + * @ref AVDictionaryEntry.value "value". + */ + AVDictionary *annotations; +} AVIAMFMixPresentation; + +const AVClass *av_iamf_mix_presentation_get_class(void); + +/** + * Allocates a AVIAMFMixPresentation, and initializes its fields with default + * values. No submixes are allocated. + * Must be freed with av_iamf_mix_presentation_free(). + * + * @see av_iamf_mix_presentation_add_submix() + */ +AVIAMFMixPresentation *av_iamf_mix_presentation_alloc(void); + +/** + * Allocate a submix and add it to a given AVIAMFMixPresentation. + * It is freed by av_iamf_mix_presentation_free() alongside the rest of the + * parent AVIAMFMixPresentation. + * + * @return a pointer to the allocated submix. + */ +AVIAMFSubmix *av_iamf_mix_presentation_add_submix(AVIAMFMixPresentation *mix_presentation); + +/** + * Allocate a submix element and add it to a given AVIAMFSubmix. + * It is freed by av_iamf_mix_presentation_free() alongside the rest of the + * parent AVIAMFSubmix. + * + * @return a pointer to the allocated submix. + */ +AVIAMFSubmixElement *av_iamf_submix_add_element(AVIAMFSubmix *submix); + +/** + * Allocate a submix layout and add it to a given AVIAMFSubmix. + * It is freed by av_iamf_mix_presentation_free() alongside the rest of the + * parent AVIAMFSubmix. + * + * @return a pointer to the allocated submix. + */ +AVIAMFSubmixLayout *av_iamf_submix_add_layout(AVIAMFSubmix *submix); + +/** + * Free an AVIAMFMixPresentation and all its contents. + * + * @param mix_presentation pointer to pointer to an allocated AVIAMFMixPresentation. + * upon return, *mix_presentation will be set to NULL. + */ +void av_iamf_mix_presentation_free(AVIAMFMixPresentation **mix_presentation); + +/** + * @} + */ + +#endif /* AVUTIL_IAMF_H */ diff --git a/libs/ffmpeg/libavutil/imgutils.c b/libs/ffmpeg/libavutil/imgutils.c new file mode 100644 index 00000000000..8ff8a6be419 --- /dev/null +++ b/libs/ffmpeg/libavutil/imgutils.c @@ -0,0 +1,717 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * misc image utilities + */ + +#include "avassert.h" +#include "common.h" +#include "imgutils.h" +#include "imgutils_internal.h" +#include "intreadwrite.h" +#include "log.h" +#include "mathematics.h" +#include "mem.h" +#include "pixdesc.h" +#include "rational.h" + +void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4], + const AVPixFmtDescriptor *pixdesc) +{ + int i; + memset(max_pixsteps, 0, 4*sizeof(max_pixsteps[0])); + if (max_pixstep_comps) + memset(max_pixstep_comps, 0, 4*sizeof(max_pixstep_comps[0])); + + for (i = 0; i < 4; i++) { + const AVComponentDescriptor *comp = &(pixdesc->comp[i]); + if (comp->step > max_pixsteps[comp->plane]) { + max_pixsteps[comp->plane] = comp->step; + if (max_pixstep_comps) + max_pixstep_comps[comp->plane] = i; + } + } +} + +static inline +int image_get_linesize(int width, int plane, + int max_step, int max_step_comp, + const AVPixFmtDescriptor *desc) +{ + int s, shifted_w, linesize; + + if (!desc) + return AVERROR(EINVAL); + + if (width < 0) + return AVERROR(EINVAL); + s = (max_step_comp == 1 || max_step_comp == 2) ? desc->log2_chroma_w : 0; + shifted_w = AV_CEIL_RSHIFT(width, s); + if (shifted_w && max_step > INT_MAX / shifted_w) + return AVERROR(EINVAL); + linesize = max_step * shifted_w; + + if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) + linesize = (linesize + 7) >> 3; + return linesize; +} + +int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int max_step [4]; /* max pixel step for each plane */ + int max_step_comp[4]; /* the component for each plane which has the max pixel step */ + + if (!desc || desc->flags & AV_PIX_FMT_FLAG_HWACCEL) + return AVERROR(EINVAL); + + av_image_fill_max_pixsteps(max_step, max_step_comp, desc); + return image_get_linesize(width, plane, max_step[plane], max_step_comp[plane], desc); +} + +int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width) +{ + int i, ret; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int max_step [4]; /* max pixel step for each plane */ + int max_step_comp[4]; /* the component for each plane which has the max pixel step */ + + memset(linesizes, 0, 4*sizeof(linesizes[0])); + + if (!desc || desc->flags & AV_PIX_FMT_FLAG_HWACCEL) + return AVERROR(EINVAL); + + av_image_fill_max_pixsteps(max_step, max_step_comp, desc); + for (i = 0; i < 4; i++) { + if ((ret = image_get_linesize(width, i, max_step[i], max_step_comp[i], desc)) < 0) + return ret; + linesizes[i] = ret; + } + + return 0; +} + +int av_image_fill_plane_sizes(size_t sizes[4], enum AVPixelFormat pix_fmt, + int height, const ptrdiff_t linesizes[4]) +{ + int i, has_plane[4] = { 0 }; + + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + memset(sizes , 0, sizeof(sizes[0])*4); + + if (!desc || desc->flags & AV_PIX_FMT_FLAG_HWACCEL) + return AVERROR(EINVAL); + + if (linesizes[0] > SIZE_MAX / height) + return AVERROR(EINVAL); + sizes[0] = linesizes[0] * (size_t)height; + + if (desc->flags & AV_PIX_FMT_FLAG_PAL) { + sizes[1] = 256 * 4; /* palette is stored here as 256 32 bits words */ + return 0; + } + + for (i = 0; i < 4; i++) + has_plane[desc->comp[i].plane] = 1; + + for (i = 1; i < 4 && has_plane[i]; i++) { + int h, s = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; + h = AV_CEIL_RSHIFT(height, s); + if (linesizes[i] > SIZE_MAX / h) + return AVERROR(EINVAL); + sizes[i] = (size_t)h * linesizes[i]; + } + + return 0; +} + +int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height, + uint8_t *ptr, const int linesizes[4]) +{ + int i, ret; + ptrdiff_t linesizes1[4]; + size_t sizes[4]; + + memset(data , 0, sizeof(data[0])*4); + + for (i = 0; i < 4; i++) + linesizes1[i] = linesizes[i]; + + ret = av_image_fill_plane_sizes(sizes, pix_fmt, height, linesizes1); + if (ret < 0) + return ret; + + ret = 0; + for (i = 0; i < 4; i++) { + if (sizes[i] > INT_MAX - ret) + return AVERROR(EINVAL); + ret += sizes[i]; + } + + if (!ptr) + return ret; + + data[0] = ptr; + for (i = 1; i < 4 && sizes[i]; i++) + data[i] = data[i - 1] + sizes[i - 1]; + + return ret; +} + +int avpriv_set_systematic_pal2(uint32_t pal[256], enum AVPixelFormat pix_fmt) +{ + int i; + + for (i = 0; i < 256; i++) { + int r, g, b; + + switch (pix_fmt) { + case AV_PIX_FMT_RGB8: + r = (i>>5 )*36; + g = ((i>>2)&7)*36; + b = (i&3 )*85; + break; + case AV_PIX_FMT_BGR8: + b = (i>>6 )*85; + g = ((i>>3)&7)*36; + r = (i&7 )*36; + break; + case AV_PIX_FMT_RGB4_BYTE: + r = (i>>3 )*255; + g = ((i>>1)&3)*85; + b = (i&1 )*255; + break; + case AV_PIX_FMT_BGR4_BYTE: + b = (i>>3 )*255; + g = ((i>>1)&3)*85; + r = (i&1 )*255; + break; + case AV_PIX_FMT_GRAY8: + r = b = g = i; + break; + default: + return AVERROR(EINVAL); + } + pal[i] = b + (g << 8) + (r << 16) + (0xFFU << 24); + } + + return 0; +} + +int av_image_alloc(uint8_t *pointers[4], int linesizes[4], + int w, int h, enum AVPixelFormat pix_fmt, int align) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int i, ret; + ptrdiff_t linesizes1[4]; + size_t total_size, sizes[4]; + uint8_t *buf; + + if (!desc) + return AVERROR(EINVAL); + + if ((ret = av_image_check_size(w, h, 0, NULL)) < 0) + return ret; + if ((ret = av_image_fill_linesizes(linesizes, pix_fmt, align>7 ? FFALIGN(w, 8) : w)) < 0) + return ret; + + for (i = 0; i < 4; i++) { + linesizes[i] = FFALIGN(linesizes[i], align); + linesizes1[i] = linesizes[i]; + } + + if ((ret = av_image_fill_plane_sizes(sizes, pix_fmt, h, linesizes1)) < 0) + return ret; + total_size = align; + for (i = 0; i < 4; i++) { + if (total_size > SIZE_MAX - sizes[i]) + return AVERROR(EINVAL); + total_size += sizes[i]; + } + buf = av_malloc(total_size); + if (!buf) + return AVERROR(ENOMEM); + if ((ret = av_image_fill_pointers(pointers, pix_fmt, h, buf, linesizes)) < 0) { + av_free(buf); + return ret; + } + if (desc->flags & AV_PIX_FMT_FLAG_PAL) { + avpriv_set_systematic_pal2((uint32_t*)pointers[1], pix_fmt); + if (align < 4) { + av_log(NULL, AV_LOG_ERROR, "Formats with a palette require a minimum alignment of 4\n"); + av_free(buf); + return AVERROR(EINVAL); + } + } + + if (desc->flags & AV_PIX_FMT_FLAG_PAL && pointers[1] && + pointers[1] - pointers[0] > linesizes[0] * h) { + /* zero-initialize the padding before the palette */ + memset(pointers[0] + linesizes[0] * h, 0, + pointers[1] - pointers[0] - linesizes[0] * h); + } + + return ret; +} + +typedef struct ImgUtils { + const AVClass *class; + int log_offset; + void *log_ctx; +} ImgUtils; + +static const AVClass imgutils_class = { + .class_name = "IMGUTILS", + .item_name = av_default_item_name, + .option = NULL, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = offsetof(ImgUtils, log_offset), + .parent_log_context_offset = offsetof(ImgUtils, log_ctx), +}; + +int av_image_check_size2(unsigned int w, unsigned int h, int64_t max_pixels, enum AVPixelFormat pix_fmt, int log_offset, void *log_ctx) +{ + ImgUtils imgutils = { + .class = &imgutils_class, + .log_offset = log_offset, + .log_ctx = log_ctx, + }; + int64_t stride = av_image_get_linesize(pix_fmt, w, 0); + if (stride <= 0) + stride = 8LL*w; + stride += 128*8; + + if (w==0 || h==0 || w > INT32_MAX || h > INT32_MAX || stride >= INT_MAX || stride*(h + 128ULL) >= INT_MAX) { + av_log(&imgutils, AV_LOG_ERROR, "Picture size %ux%u is invalid\n", w, h); + return AVERROR(EINVAL); + } + + if (max_pixels < INT64_MAX) { + if (w*(int64_t)h > max_pixels) { + av_log(&imgutils, AV_LOG_ERROR, + "Picture size %ux%u exceeds specified max pixel count %"PRId64", see the documentation if you wish to increase it\n", + w, h, max_pixels); + return AVERROR(EINVAL); + } + } + + return 0; +} + +int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx) +{ + return av_image_check_size2(w, h, INT64_MAX, AV_PIX_FMT_NONE, log_offset, log_ctx); +} + +int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar) +{ + int64_t scaled_dim; + + if (sar.den <= 0 || sar.num < 0) + return AVERROR(EINVAL); + + if (!sar.num || sar.num == sar.den) + return 0; + + if (sar.num < sar.den) + scaled_dim = av_rescale_rnd(w, sar.num, sar.den, AV_ROUND_ZERO); + else + scaled_dim = av_rescale_rnd(h, sar.den, sar.num, AV_ROUND_ZERO); + + if (scaled_dim > 0) + return 0; + + return AVERROR(EINVAL); +} + +static void image_copy_plane(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height) +{ + if (!dst || !src) + return; + av_assert0(FFABS(src_linesize) >= bytewidth); + av_assert0(FFABS(dst_linesize) >= bytewidth); + for (;height > 0; height--) { + memcpy(dst, src, bytewidth); + dst += dst_linesize; + src += src_linesize; + } +} + +void av_image_copy_plane_uc_from(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height) +{ + int ret = -1; + +#if ARCH_X86 && HAVE_X86ASM + ret = ff_image_copy_plane_uc_from_x86(dst, dst_linesize, src, src_linesize, + bytewidth, height); +#endif + + if (ret < 0) + image_copy_plane(dst, dst_linesize, src, src_linesize, bytewidth, height); +} + +void av_image_copy_plane(uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize, + int bytewidth, int height) +{ + image_copy_plane(dst, dst_linesize, src, src_linesize, bytewidth, height); +} + +static void image_copy(uint8_t *const dst_data[4], const ptrdiff_t dst_linesizes[4], + const uint8_t *const src_data[4], const ptrdiff_t src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height, + void (*copy_plane)(uint8_t *, ptrdiff_t, const uint8_t *, + ptrdiff_t, ptrdiff_t, int)) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + + if (!desc || desc->flags & AV_PIX_FMT_FLAG_HWACCEL) + return; + + if (desc->flags & AV_PIX_FMT_FLAG_PAL) { + copy_plane(dst_data[0], dst_linesizes[0], + src_data[0], src_linesizes[0], + width, height); + /* copy the palette */ + if ((desc->flags & AV_PIX_FMT_FLAG_PAL) || (dst_data[1] && src_data[1])) + memcpy(dst_data[1], src_data[1], 4*256); + } else { + int i, planes_nb = 0; + + for (i = 0; i < desc->nb_components; i++) + planes_nb = FFMAX(planes_nb, desc->comp[i].plane + 1); + + for (i = 0; i < planes_nb; i++) { + int h = height; + ptrdiff_t bwidth = av_image_get_linesize(pix_fmt, width, i); + if (bwidth < 0) { + av_log(NULL, AV_LOG_ERROR, "av_image_get_linesize failed\n"); + return; + } + if (i == 1 || i == 2) { + h = AV_CEIL_RSHIFT(height, desc->log2_chroma_h); + } + copy_plane(dst_data[i], dst_linesizes[i], + src_data[i], src_linesizes[i], + bwidth, h); + } + } +} + +void av_image_copy(uint8_t *const dst_data[4], const int dst_linesizes[4], + const uint8_t * const src_data[4], const int src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height) +{ + ptrdiff_t dst_linesizes1[4], src_linesizes1[4]; + int i; + + for (i = 0; i < 4; i++) { + dst_linesizes1[i] = dst_linesizes[i]; + src_linesizes1[i] = src_linesizes[i]; + } + + image_copy(dst_data, dst_linesizes1, src_data, src_linesizes1, pix_fmt, + width, height, image_copy_plane); +} + +void av_image_copy_uc_from(uint8_t * const dst_data[4], const ptrdiff_t dst_linesizes[4], + const uint8_t * const src_data[4], const ptrdiff_t src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height) +{ + image_copy(dst_data, dst_linesizes, src_data, src_linesizes, pix_fmt, + width, height, av_image_copy_plane_uc_from); +} + +int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], + const uint8_t *src, enum AVPixelFormat pix_fmt, + int width, int height, int align) +{ + int ret, i; + + ret = av_image_check_size(width, height, 0, NULL); + if (ret < 0) + return ret; + + ret = av_image_fill_linesizes(dst_linesize, pix_fmt, width); + if (ret < 0) + return ret; + + for (i = 0; i < 4; i++) + dst_linesize[i] = FFALIGN(dst_linesize[i], align); + + return av_image_fill_pointers(dst_data, pix_fmt, height, (uint8_t *)src, dst_linesize); +} + +int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, + int width, int height, int align) +{ + int ret, i; + int linesize[4]; + ptrdiff_t aligned_linesize[4]; + size_t sizes[4]; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + if (!desc) + return AVERROR(EINVAL); + + ret = av_image_check_size(width, height, 0, NULL); + if (ret < 0) + return ret; + + ret = av_image_fill_linesizes(linesize, pix_fmt, width); + if (ret < 0) + return ret; + + for (i = 0; i < 4; i++) + aligned_linesize[i] = FFALIGN(linesize[i], align); + + ret = av_image_fill_plane_sizes(sizes, pix_fmt, height, aligned_linesize); + if (ret < 0) + return ret; + + ret = 0; + for (i = 0; i < 4; i++) { + if (sizes[i] > INT_MAX - ret) + return AVERROR(EINVAL); + ret += sizes[i]; + } + return ret; +} + +int av_image_copy_to_buffer(uint8_t *dst, int dst_size, + const uint8_t * const src_data[4], + const int src_linesize[4], + enum AVPixelFormat pix_fmt, + int width, int height, int align) +{ + int i, j, nb_planes = 0, linesize[4]; + int size = av_image_get_buffer_size(pix_fmt, width, height, align); + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int ret; + + if (size > dst_size || size < 0 || !desc) + return AVERROR(EINVAL); + + for (i = 0; i < desc->nb_components; i++) + nb_planes = FFMAX(desc->comp[i].plane, nb_planes); + + nb_planes++; + + ret = av_image_fill_linesizes(linesize, pix_fmt, width); + av_assert0(ret >= 0); // was checked previously + + for (i = 0; i < nb_planes; i++) { + int h, shift = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; + const uint8_t *src = src_data[i]; + h = AV_CEIL_RSHIFT(height, shift); + + for (j = 0; j < h; j++) { + memcpy(dst, src, linesize[i]); + dst += FFALIGN(linesize[i], align); + src += src_linesize[i]; + } + } + + if (desc->flags & AV_PIX_FMT_FLAG_PAL) { + uint32_t *d32 = (uint32_t *)dst; + + for (i = 0; i<256; i++) + AV_WL32(d32 + i, AV_RN32(src_data[1] + 4*i)); + } + + return size; +} + +// Fill dst[0..dst_size] with the bytes in clear[0..clear_size]. The clear +// bytes are repeated until dst_size is reached. If dst_size is unaligned (i.e. +// dst_size%clear_size!=0), the remaining data will be filled with the beginning +// of the clear data only. +static void memset_bytes(uint8_t *dst, size_t dst_size, uint8_t *clear, + size_t clear_size) +{ + int same = 1; + int i; + + if (!clear_size) + return; + + // Reduce to memset() if possible. + for (i = 0; i < clear_size; i++) { + if (clear[i] != clear[0]) { + same = 0; + break; + } + } + if (same) + clear_size = 1; + + if (clear_size == 1) { + memset(dst, clear[0], dst_size); + } else { + if (clear_size > dst_size) + clear_size = dst_size; + memcpy(dst, clear, clear_size); + av_memcpy_backptr(dst + clear_size, clear_size, dst_size - clear_size); + } +} + +// Maximum size in bytes of a plane element (usually a pixel, or multiple pixels +// if it's a subsampled packed format). +#define MAX_BLOCK_SIZE 32 + +int av_image_fill_color(uint8_t * const dst_data[4], const ptrdiff_t dst_linesize[4], + enum AVPixelFormat pix_fmt, const uint32_t color[4], + int width, int height, int flags) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int nb_planes = av_pix_fmt_count_planes(pix_fmt); + // A pixel or a group of pixels on each plane, with a value that represents the color. + // Consider e.g. AV_PIX_FMT_UYVY422 for non-trivial cases. + uint8_t clear_block[4][MAX_BLOCK_SIZE] = {{0}}; // clear padding with 0 + int clear_block_size[4] = {0}; + ptrdiff_t plane_line_bytes[4] = {0}; + int bitstream; + int plane, c; + + if (!desc || nb_planes < 1 || nb_planes > 4 || desc->flags & AV_PIX_FMT_FLAG_HWACCEL) + return AVERROR(EINVAL); + + bitstream = !!(desc->flags & AV_PIX_FMT_FLAG_BITSTREAM); + + for (c = 0; c < desc->nb_components; c++) { + const AVComponentDescriptor comp = desc->comp[c]; + + // We try to operate on entire non-subsampled pixel groups (for + // AV_PIX_FMT_UYVY422 this would mean two consecutive pixels). + clear_block_size[comp.plane] = FFMAX(clear_block_size[comp.plane], comp.step); + + if (clear_block_size[comp.plane] > MAX_BLOCK_SIZE) + return AVERROR(EINVAL); + } + + // Create a byte array for clearing 1 pixel (sometimes several pixels). + for (c = 0; c < desc->nb_components; c++) { + const AVComponentDescriptor comp = desc->comp[c]; + // (Multiple pixels happen e.g. with AV_PIX_FMT_UYVY422.) + int w = (bitstream ? 8 : 1) * clear_block_size[comp.plane] / comp.step; + uint8_t *c_data[4]; + const int c_linesize[4] = {0}; + uint32_t src_array[MAX_BLOCK_SIZE]; + int x; + + if (comp.depth > 32) + return AVERROR(EINVAL); + if (w < 1) + return AVERROR(EINVAL); + + for (x = 0; x < w; x++) + src_array[x] = color[c]; + + for (x = 0; x < 4; x++) + c_data[x] = &clear_block[x][0]; + + av_write_image_line2(src_array, c_data, c_linesize, desc, 0, 0, c, w, 4); + } + + for (plane = 0; plane < nb_planes; plane++) { + plane_line_bytes[plane] = av_image_get_linesize(pix_fmt, width, plane); + if (plane_line_bytes[plane] < 0) + return AVERROR(EINVAL); + } + + if (!dst_data) + return 0; + + for (plane = 0; plane < nb_planes; plane++) { + size_t bytewidth = plane_line_bytes[plane]; + uint8_t *data = dst_data[plane]; + int chroma_div = plane == 1 || plane == 2 ? desc->log2_chroma_h : 0; + int plane_h = AV_CEIL_RSHIFT(height, chroma_div); + + for (; plane_h > 0; plane_h--) { + memset_bytes(data, bytewidth, &clear_block[plane][0], clear_block_size[plane]); + data += dst_linesize[plane]; + } + } + + return 0; +} + +int av_image_fill_black(uint8_t * const dst_data[4], const ptrdiff_t dst_linesize[4], + enum AVPixelFormat pix_fmt, enum AVColorRange range, + int width, int height) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int nb_planes = av_pix_fmt_count_planes(pix_fmt); + int rgb, xyz, pal, limited, alpha, fltp; + uint32_t colors[4] = {0}; + + if (!desc || nb_planes < 1 || nb_planes > 4 || desc->flags & AV_PIX_FMT_FLAG_HWACCEL) + return AVERROR(EINVAL); + + rgb = !!(desc->flags & AV_PIX_FMT_FLAG_RGB); + xyz = !!(desc->flags & AV_PIX_FMT_FLAG_XYZ); + pal = !!(desc->flags & AV_PIX_FMT_FLAG_PAL); + limited = !rgb && !xyz && !pal && range != AVCOL_RANGE_JPEG; + alpha = !pal && !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA); + fltp = !!(desc->flags & AV_PIX_FMT_FLAG_FLOAT); + + for (int c = 0; c < desc->nb_components; c++) { + const AVComponentDescriptor comp = desc->comp[c]; + uint32_t color = 0; + + if (comp.depth > 32) + return AVERROR(EINVAL); + + if (pix_fmt == AV_PIX_FMT_MONOWHITE) { + color = 1; + } else if (c + 1 == desc->nb_components && alpha) { + // (Assume even limited YUV uses full range alpha.) + if (fltp) { + if (comp.depth != 16 && comp.depth != 32) + return AVERROR(EINVAL); + color = (comp.depth == 16 ? 0x3C00 : 0x3F800000); // 1.0 + } else { + color = (comp.depth == 32 ? 0 : (1 << comp.depth)) - 1; + } + } else if (c == 0 && limited && comp.depth > 1) { + if (comp.depth < 8 || (fltp && comp.depth != 16 && comp.depth != 32)) + return AVERROR(EINVAL); + if (fltp) + color = (comp.depth == 16 ? 0x2C00 : 0x3D800000); // 0.0625 + else + color = 16 << (comp.depth - 8); + } else if ((c == 1 || c == 2) && !rgb && !xyz) { + if (comp.depth < 8 || fltp && comp.depth != 16 && comp.depth != 32) + return AVERROR(EINVAL); + if (fltp) + color = (comp.depth == 16 ? 0x3800 : 0x3F000000); // 0.5 + else + color = 128 << (comp.depth - 8); + } + + colors[c] = color; + } + + return av_image_fill_color(dst_data, dst_linesize, pix_fmt, colors, width, height, 0); +} diff --git a/libs/ffmpeg/libavutil/imgutils.h b/libs/ffmpeg/libavutil/imgutils.h new file mode 100644 index 00000000000..123a9e5c0d2 --- /dev/null +++ b/libs/ffmpeg/libavutil/imgutils.h @@ -0,0 +1,377 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_IMGUTILS_H +#define AVUTIL_IMGUTILS_H + +/** + * @file + * misc image utilities + * + * @addtogroup lavu_picture + * @{ + */ + +#include <stddef.h> +#include <stdint.h> +#include "pixdesc.h" +#include "pixfmt.h" +#include "rational.h" + +/** + * Compute the max pixel step for each plane of an image with a + * format described by pixdesc. + * + * The pixel step is the distance in bytes between the first byte of + * the group of bytes which describe a pixel component and the first + * byte of the successive group in the same plane for the same + * component. + * + * @param max_pixsteps an array which is filled with the max pixel step + * for each plane. Since a plane may contain different pixel + * components, the computed max_pixsteps[plane] is relative to the + * component in the plane with the max pixel step. + * @param max_pixstep_comps an array which is filled with the component + * for each plane which has the max pixel step. May be NULL. + * @param pixdesc the AVPixFmtDescriptor for the image, describing its format + */ +void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4], + const AVPixFmtDescriptor *pixdesc); + +/** + * Compute the size of an image line with format pix_fmt and width + * width for the plane plane. + * + * @return the computed size in bytes + */ +int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane); + +/** + * Fill plane linesizes for an image with pixel format pix_fmt and + * width width. + * + * @param linesizes array to be filled with the linesize for each plane + * @param pix_fmt the AVPixelFormat of the image + * @param width width of the image in pixels + * @return >= 0 in case of success, a negative error code otherwise + */ +int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width); + +/** + * Fill plane sizes for an image with pixel format pix_fmt and height height. + * + * @param size the array to be filled with the size of each image plane + * @param pix_fmt the AVPixelFormat of the image + * @param height height of the image in pixels + * @param linesizes the array containing the linesize for each + * plane, should be filled by av_image_fill_linesizes() + * @return >= 0 in case of success, a negative error code otherwise + * + * @note The linesize parameters have the type ptrdiff_t here, while they are + * int for av_image_fill_linesizes(). + */ +int av_image_fill_plane_sizes(size_t size[4], enum AVPixelFormat pix_fmt, + int height, const ptrdiff_t linesizes[4]); + +/** + * Fill plane data pointers for an image with pixel format pix_fmt and + * height height. + * + * @param data pointers array to be filled with the pointer for each image plane + * @param pix_fmt the AVPixelFormat of the image + * @param height height of the image in pixels + * @param ptr the pointer to a buffer which will contain the image + * @param linesizes the array containing the linesize for each + * plane, should be filled by av_image_fill_linesizes() + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height, + uint8_t *ptr, const int linesizes[4]); + +/** + * Allocate an image with size w and h and pixel format pix_fmt, and + * fill pointers and linesizes accordingly. + * The allocated image buffer has to be freed by using + * av_freep(&pointers[0]). + * + * @param pointers array to be filled with the pointer for each image plane + * @param linesizes the array filled with the linesize for each plane + * @param w width of the image in pixels + * @param h height of the image in pixels + * @param pix_fmt the AVPixelFormat of the image + * @param align the value to use for buffer size alignment + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_alloc(uint8_t *pointers[4], int linesizes[4], + int w, int h, enum AVPixelFormat pix_fmt, int align); + +/** + * Copy image plane from src to dst. + * That is, copy "height" number of lines of "bytewidth" bytes each. + * The first byte of each successive line is separated by *_linesize + * bytes. + * + * bytewidth must be contained by both absolute values of dst_linesize + * and src_linesize, otherwise the function behavior is undefined. + * + * @param dst destination plane to copy to + * @param dst_linesize linesize for the image plane in dst + * @param src source plane to copy from + * @param src_linesize linesize for the image plane in src + * @param height height (number of lines) of the plane + */ +void av_image_copy_plane(uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize, + int bytewidth, int height); + +/** + * Copy image data located in uncacheable (e.g. GPU mapped) memory. Where + * available, this function will use special functionality for reading from such + * memory, which may result in greatly improved performance compared to plain + * av_image_copy_plane(). + * + * bytewidth must be contained by both absolute values of dst_linesize + * and src_linesize, otherwise the function behavior is undefined. + * + * @note The linesize parameters have the type ptrdiff_t here, while they are + * int for av_image_copy_plane(). + * @note On x86, the linesizes currently need to be aligned to the cacheline + * size (i.e. 64) to get improved performance. + */ +void av_image_copy_plane_uc_from(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height); + +/** + * Copy image in src_data to dst_data. + * + * @param dst_data destination image data buffer to copy to + * @param dst_linesizes linesizes for the image in dst_data + * @param src_data source image data buffer to copy from + * @param src_linesizes linesizes for the image in src_data + * @param pix_fmt the AVPixelFormat of the image + * @param width width of the image in pixels + * @param height height of the image in pixels + */ +void av_image_copy(uint8_t * const dst_data[4], const int dst_linesizes[4], + const uint8_t * const src_data[4], const int src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * Wrapper around av_image_copy() to workaround the limitation + * that the conversion from uint8_t * const * to const uint8_t * const * + * is not performed automatically in C. + * @see av_image_copy() + */ +static inline +void av_image_copy2(uint8_t * const dst_data[4], const int dst_linesizes[4], + uint8_t * const src_data[4], const int src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height) +{ + av_image_copy(dst_data, dst_linesizes, + (const uint8_t * const *)src_data, src_linesizes, + pix_fmt, width, height); +} + +/** + * Copy image data located in uncacheable (e.g. GPU mapped) memory. Where + * available, this function will use special functionality for reading from such + * memory, which may result in greatly improved performance compared to plain + * av_image_copy(). + * + * The data pointers and the linesizes must be aligned to the maximum required + * by the CPU architecture. + * + * @note The linesize parameters have the type ptrdiff_t here, while they are + * int for av_image_copy(). + * @note On x86, the linesizes currently need to be aligned to the cacheline + * size (i.e. 64) to get improved performance. + */ +void av_image_copy_uc_from(uint8_t * const dst_data[4], const ptrdiff_t dst_linesizes[4], + const uint8_t * const src_data[4], const ptrdiff_t src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * Setup the data pointers and linesizes based on the specified image + * parameters and the provided array. + * + * The fields of the given image are filled in by using the src + * address which points to the image data buffer. Depending on the + * specified pixel format, one or multiple image data pointers and + * line sizes will be set. If a planar format is specified, several + * pointers will be set pointing to the different picture planes and + * the line sizes of the different planes will be stored in the + * lines_sizes array. Call with src == NULL to get the required + * size for the src buffer. + * + * To allocate the buffer and fill in the dst_data and dst_linesize in + * one call, use av_image_alloc(). + * + * @param dst_data data pointers to be filled in + * @param dst_linesize linesizes for the image in dst_data to be filled in + * @param src buffer which will contain or contains the actual image data, can be NULL + * @param pix_fmt the pixel format of the image + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @param align the value used in src for linesize alignment + * @return the size in bytes required for src, a negative error code + * in case of failure + */ +int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], + const uint8_t *src, + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Return the size in bytes of the amount of data required to store an + * image with the given parameters. + * + * @param pix_fmt the pixel format of the image + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @param align the assumed linesize alignment + * @return the buffer size in bytes, a negative error code in case of failure + */ +int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Copy image data from an image into a buffer. + * + * av_image_get_buffer_size() can be used to compute the required size + * for the buffer to fill. + * + * @param dst a buffer into which picture data will be copied + * @param dst_size the size in bytes of dst + * @param src_data pointers containing the source image data + * @param src_linesize linesizes for the image in src_data + * @param pix_fmt the pixel format of the source image + * @param width the width of the source image in pixels + * @param height the height of the source image in pixels + * @param align the assumed linesize alignment for dst + * @return the number of bytes written to dst, or a negative value + * (error code) on error + */ +int av_image_copy_to_buffer(uint8_t *dst, int dst_size, + const uint8_t * const src_data[4], const int src_linesize[4], + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Check if the given dimension of an image is valid, meaning that all + * bytes of the image can be addressed with a signed int. + * + * @param w the width of the picture + * @param h the height of the picture + * @param log_offset the offset to sum to the log level for logging with log_ctx + * @param log_ctx the parent logging context, it may be NULL + * @return >= 0 if valid, a negative error code otherwise + */ +int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx); + +/** + * Check if the given dimension of an image is valid, meaning that all + * bytes of a plane of an image with the specified pix_fmt can be addressed + * with a signed int. + * + * @param w the width of the picture + * @param h the height of the picture + * @param max_pixels the maximum number of pixels the user wants to accept + * @param pix_fmt the pixel format, can be AV_PIX_FMT_NONE if unknown. + * @param log_offset the offset to sum to the log level for logging with log_ctx + * @param log_ctx the parent logging context, it may be NULL + * @return >= 0 if valid, a negative error code otherwise + */ +int av_image_check_size2(unsigned int w, unsigned int h, int64_t max_pixels, enum AVPixelFormat pix_fmt, int log_offset, void *log_ctx); + +/** + * Check if the given sample aspect ratio of an image is valid. + * + * It is considered invalid if the denominator is 0 or if applying the ratio + * to the image size would make the smaller dimension less than 1. If the + * sar numerator is 0, it is considered unknown and will return as valid. + * + * @param w width of the image + * @param h height of the image + * @param sar sample aspect ratio of the image + * @return 0 if valid, a negative AVERROR code otherwise + */ +int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar); + +/** + * Overwrite the image data with black. This is suitable for filling a + * sub-rectangle of an image, meaning the padding between the right most pixel + * and the left most pixel on the next line will not be overwritten. For some + * formats, the image size might be rounded up due to inherent alignment. + * + * If the pixel format has alpha, the alpha is cleared to opaque. + * + * This can return an error if the pixel format is not supported. Normally, all + * non-hwaccel pixel formats should be supported. + * + * Passing NULL for dst_data is allowed. Then the function returns whether the + * operation would have succeeded. (It can return an error if the pix_fmt is + * not supported.) + * + * @param dst_data data pointers to destination image + * @param dst_linesize linesizes for the destination image + * @param pix_fmt the pixel format of the image + * @param range the color range of the image (important for colorspaces such as YUV) + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @return 0 if the image data was cleared, a negative AVERROR code otherwise + */ +int av_image_fill_black(uint8_t * const dst_data[4], const ptrdiff_t dst_linesize[4], + enum AVPixelFormat pix_fmt, enum AVColorRange range, + int width, int height); + +/** + * Overwrite the image data with a color. This is suitable for filling a + * sub-rectangle of an image, meaning the padding between the right most pixel + * and the left most pixel on the next line will not be overwritten. For some + * formats, the image size might be rounded up due to inherent alignment. + * + * If the pixel format has alpha, it is also replaced. Color component values + * are interpreted as native integers (or intfloats) regardless of actual pixel + * format endianness. + * + * This can return an error if the pixel format is not supported. Normally, all + * non-hwaccel pixel formats should be supported. + * + * Passing NULL for dst_data is allowed. Then the function returns whether the + * operation would have succeeded. (It can return an error if the pix_fmt is + * not supported.) + * + * @param dst_data data pointers to destination image + * @param dst_linesize linesizes for the destination image + * @param pix_fmt the pixel format of the image + * @param color the color components to be used for the fill + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @param flags currently unused + * @return 0 if the image data was filled, a negative AVERROR code otherwise + */ +int av_image_fill_color(uint8_t * const dst_data[4], const ptrdiff_t dst_linesize[4], + enum AVPixelFormat pix_fmt, const uint32_t color[4], + int width, int height, int flags); + +/** + * @} + */ + + +#endif /* AVUTIL_IMGUTILS_H */ diff --git a/libs/ffmpeg/libavutil/imgutils_internal.h b/libs/ffmpeg/libavutil/imgutils_internal.h new file mode 100644 index 00000000000..3e47731a509 --- /dev/null +++ b/libs/ffmpeg/libavutil/imgutils_internal.h @@ -0,0 +1,34 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_IMGUTILS_INTERNAL_H +#define AVUTIL_IMGUTILS_INTERNAL_H + +#include <stddef.h> +#include <stdint.h> + +#include "pixfmt.h" + +int avpriv_set_systematic_pal2(uint32_t pal[256], enum AVPixelFormat pix_fmt); + +int ff_image_copy_plane_uc_from_x86(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + ptrdiff_t bytewidth, int height); + + +#endif /* AVUTIL_IMGUTILS_INTERNAL_H */ diff --git a/libs/ffmpeg/libavutil/integer.c b/libs/ffmpeg/libavutil/integer.c new file mode 100644 index 00000000000..ae87c467b2d --- /dev/null +++ b/libs/ffmpeg/libavutil/integer.c @@ -0,0 +1,166 @@ +/* + * arbitrary precision integers + * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * arbitrary precision integers + * @author Michael Niedermayer <michaelni@gmx.at> + */ + +#include <string.h> + +#include "integer.h" +#include "avassert.h" +#include "intmath.h" + +static const AVInteger zero_i; + +AVInteger av_add_i(AVInteger a, AVInteger b){ + int i, carry=0; + + for(i=0; i<AV_INTEGER_SIZE; i++){ + carry= (carry>>16) + a.v[i] + b.v[i]; + a.v[i]= carry; + } + return a; +} + +AVInteger av_sub_i(AVInteger a, AVInteger b){ + int i, carry=0; + + for(i=0; i<AV_INTEGER_SIZE; i++){ + carry= (carry>>16) + a.v[i] - b.v[i]; + a.v[i]= carry; + } + return a; +} + +int av_log2_i(AVInteger a){ + int i; + + for(i=AV_INTEGER_SIZE-1; i>=0; i--){ + if(a.v[i]) + return av_log2_16bit(a.v[i]) + 16*i; + } + return -1; +} + +AVInteger av_mul_i(AVInteger a, AVInteger b){ + AVInteger out; + int i, j; + int na= (av_log2_i(a)+16) >> 4; + int nb= (av_log2_i(b)+16) >> 4; + + memset(&out, 0, sizeof(out)); + + for(i=0; i<na; i++){ + unsigned int carry=0; + + if(a.v[i]) + for(j=i; j<AV_INTEGER_SIZE && j-i<=nb; j++){ + carry= (carry>>16) + out.v[j] + a.v[i]*(unsigned)b.v[j-i]; + out.v[j]= carry; + } + } + + return out; +} + +int av_cmp_i(AVInteger a, AVInteger b){ + int i; + int v= (int16_t)a.v[AV_INTEGER_SIZE-1] - (int16_t)b.v[AV_INTEGER_SIZE-1]; + if(v) return (v>>16)|1; + + for(i=AV_INTEGER_SIZE-2; i>=0; i--){ + int v= a.v[i] - b.v[i]; + if(v) return (v>>16)|1; + } + return 0; +} + +AVInteger av_shr_i(AVInteger a, int s){ + AVInteger out; + int i; + + for(i=0; i<AV_INTEGER_SIZE; i++){ + unsigned int index= i + (s>>4); + unsigned int v=0; + if (index + 1 < AV_INTEGER_SIZE) v = a.v[index + 1] * (1U << 16); + if (index < AV_INTEGER_SIZE) v |= a.v[index]; + out.v[i]= v >> (s&15); + } + return out; +} + +AVInteger av_mod_i(AVInteger *quot, AVInteger a, AVInteger b){ + int i= av_log2_i(a) - av_log2_i(b); + AVInteger quot_temp; + if(!quot) quot = "_temp; + + if ((int16_t)a.v[AV_INTEGER_SIZE-1] < 0) { + a = av_mod_i(quot, av_sub_i(zero_i, a), b); + *quot = av_sub_i(zero_i, *quot); + return av_sub_i(zero_i, a); + } + + av_assert2((int16_t)a.v[AV_INTEGER_SIZE-1] >= 0 && (int16_t)b.v[AV_INTEGER_SIZE-1] >= 0); + av_assert2(av_log2_i(b)>=0); + + if(i > 0) + b= av_shr_i(b, -i); + + memset(quot, 0, sizeof(AVInteger)); + + while(i-- >= 0){ + *quot= av_shr_i(*quot, -1); + if(av_cmp_i(a, b) >= 0){ + a= av_sub_i(a, b); + quot->v[0] += 1; + } + b= av_shr_i(b, 1); + } + return a; +} + +AVInteger av_div_i(AVInteger a, AVInteger b){ + AVInteger quot; + av_mod_i(", a, b); + return quot; +} + +AVInteger av_int2i(int64_t a){ + AVInteger out; + int i; + + for(i=0; i<AV_INTEGER_SIZE; i++){ + out.v[i]= a; + a>>=16; + } + return out; +} + +int64_t av_i2int(AVInteger a){ + uint64_t out = a.v[3]; + + for (int i = 2; i >= 0; i--) + out = (out << 16) | a.v[i]; + return out; +} diff --git a/libs/ffmpeg/libavutil/integer.h b/libs/ffmpeg/libavutil/integer.h new file mode 100644 index 00000000000..2d9b5bb10fa --- /dev/null +++ b/libs/ffmpeg/libavutil/integer.h @@ -0,0 +1,86 @@ +/* + * arbitrary precision integers + * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * arbitrary precision integers + * @author Michael Niedermayer <michaelni@gmx.at> + */ + +#ifndef AVUTIL_INTEGER_H +#define AVUTIL_INTEGER_H + +#include <stdint.h> +#include "attributes.h" + +#define AV_INTEGER_SIZE 8 + +typedef struct AVInteger{ + uint16_t v[AV_INTEGER_SIZE]; +} AVInteger; + +AVInteger av_add_i(AVInteger a, AVInteger b) av_const; +AVInteger av_sub_i(AVInteger a, AVInteger b) av_const; + +/** + * Return the rounded-down value of the base 2 logarithm of the given + * AVInteger. This is simply the index of the most significant bit + * which is 1, or 0 if all bits are 0. + */ +int av_log2_i(AVInteger a) av_const; +AVInteger av_mul_i(AVInteger a, AVInteger b) av_const; + +/** + * Return 0 if a==b, 1 if a>b and -1 if a<b. + */ +int av_cmp_i(AVInteger a, AVInteger b) av_const; + +/** + * bitwise shift + * @param s the number of bits by which the value should be shifted right, + may be negative for shifting left + */ +AVInteger av_shr_i(AVInteger a, int s) av_const; + +/** + * Return a % b. + * @param quot a/b will be stored here. + */ +AVInteger av_mod_i(AVInteger *quot, AVInteger a, AVInteger b); + +/** + * Return a/b. + */ +AVInteger av_div_i(AVInteger a, AVInteger b) av_const; + +/** + * Convert the given int64_t to an AVInteger. + */ +AVInteger av_int2i(int64_t a) av_const; + +/** + * Convert the given AVInteger to an int64_t. + * If the AVInteger is too large to fit into an int64_t, + * then only the least significant 64 bits will be used. + */ +int64_t av_i2int(AVInteger a) av_const; + +#endif /* AVUTIL_INTEGER_H */ diff --git a/libs/ffmpeg/libavutil/internal.h b/libs/ffmpeg/libavutil/internal.h new file mode 100644 index 00000000000..2a851707957 --- /dev/null +++ b/libs/ffmpeg/libavutil/internal.h @@ -0,0 +1,153 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * common internal API header + */ + +#ifndef AVUTIL_INTERNAL_H +#define AVUTIL_INTERNAL_H + +#if !defined(DEBUG) && !defined(NDEBUG) +# define NDEBUG +#endif + +// This can be enabled to allow detection of additional integer overflows with ubsan +//#define CHECKED + +#include <limits.h> +#include <stdint.h> +#include <stddef.h> +#include <assert.h> +#include <stdio.h> +#include "config.h" +#include "attributes.h" +#include "libm.h" +#include "macros.h" + +#ifndef attribute_align_arg +#if ARCH_X86_32 && AV_GCC_VERSION_AT_LEAST(4,2) +# define attribute_align_arg __attribute__((force_align_arg_pointer)) +#else +# define attribute_align_arg +#endif +#endif + +#if defined(_WIN32) && CONFIG_SHARED && !defined(BUILDING_avutil) +# define av_export_avutil __declspec(dllimport) +#else +# define av_export_avutil +#endif + +#if HAVE_PRAGMA_DEPRECATED +# if defined(__ICL) || defined (__INTEL_COMPILER) +# define FF_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:1478)) +# define FF_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop)) +# elif defined(_MSC_VER) +# define FF_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:4996)) +# define FF_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop)) +# else +# define FF_DISABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define FF_ENABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic pop") +# endif +#else +# define FF_DISABLE_DEPRECATION_WARNINGS +# define FF_ENABLE_DEPRECATION_WARNINGS +#endif + + +#define FF_ALLOC_TYPED_ARRAY(p, nelem) (p = av_malloc_array(nelem, sizeof(*p))) +#define FF_ALLOCZ_TYPED_ARRAY(p, nelem) (p = av_calloc(nelem, sizeof(*p))) + +#define FF_PTR_ADD(ptr, off) ((off) ? (ptr) + (off) : (ptr)) + +/** + * Access a field in a structure by its offset. + */ +#define FF_FIELD_AT(type, off, obj) (*(type *)((char *)&(obj) + (off))) + +/** + * Return NULL if CONFIG_SMALL is true, otherwise the argument + * without modification. Used to disable the definition of strings. + */ +#if CONFIG_SMALL +# define NULL_IF_CONFIG_SMALL(x) NULL +#else +# define NULL_IF_CONFIG_SMALL(x) x +#endif + +/** + * Log a generic warning message about a missing feature. + * + * @param[in] avc a pointer to an arbitrary struct of which the first + * field is a pointer to an AVClass struct + * @param[in] msg string containing the name of the missing feature + */ +void avpriv_report_missing_feature(void *avc, + const char *msg, ...) av_printf_format(2, 3); + +/** + * Log a generic warning message about a missing feature. + * Additionally request that a sample showcasing the feature be uploaded. + * + * @param[in] avc a pointer to an arbitrary struct of which the first field is + * a pointer to an AVClass struct + * @param[in] msg string containing the name of the missing feature + */ +void avpriv_request_sample(void *avc, + const char *msg, ...) av_printf_format(2, 3); + +#ifdef DEBUG +# define ff_dlog(ctx, ...) av_log(ctx, AV_LOG_DEBUG, __VA_ARGS__) +#else +# define ff_dlog(ctx, ...) do { if (0) av_log(ctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0) +#endif + +#ifdef TRACE +# define ff_tlog(ctx, ...) av_log(ctx, AV_LOG_TRACE, __VA_ARGS__) +#else +# define ff_tlog(ctx, ...) do { } while(0) +#endif + +// For debugging we use signed operations so overflows can be detected (by ubsan) +// For production we use unsigned so there are no undefined operations +#ifdef CHECKED +#define SUINT int +#define SUINT32 int32_t +#else +#define SUINT unsigned +#define SUINT32 uint32_t +#endif + +static av_always_inline av_const int avpriv_mirror(int x, int w) +{ + if (!w) + return 0; + + while ((unsigned)x > (unsigned)w) { + x = -x; + if (x < 0) + x += 2 * w; + } + return x; +} + +#endif /* AVUTIL_INTERNAL_H */ diff --git a/libs/ffmpeg/libavutil/intfloat.h b/libs/ffmpeg/libavutil/intfloat.h new file mode 100644 index 00000000000..fe3d7ec4a5b --- /dev/null +++ b/libs/ffmpeg/libavutil/intfloat.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTFLOAT_H +#define AVUTIL_INTFLOAT_H + +#include <stdint.h> +#include "attributes.h" + +union av_intfloat32 { + uint32_t i; + float f; +}; + +union av_intfloat64 { + uint64_t i; + double f; +}; + +/** + * Reinterpret a 32-bit integer as a float. + */ +static av_always_inline float av_int2float(uint32_t i) +{ + union av_intfloat32 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a float as a 32-bit integer. + */ +static av_always_inline uint32_t av_float2int(float f) +{ + union av_intfloat32 v; + v.f = f; + return v.i; +} + +/** + * Reinterpret a 64-bit integer as a double. + */ +static av_always_inline double av_int2double(uint64_t i) +{ + union av_intfloat64 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a double as a 64-bit integer. + */ +static av_always_inline uint64_t av_double2int(double f) +{ + union av_intfloat64 v; + v.f = f; + return v.i; +} + +#endif /* AVUTIL_INTFLOAT_H */ diff --git a/libs/ffmpeg/libavutil/intmath.c b/libs/ffmpeg/libavutil/intmath.c new file mode 100644 index 00000000000..b0c00e1cadd --- /dev/null +++ b/libs/ffmpeg/libavutil/intmath.c @@ -0,0 +1,34 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "intmath.h" + +/* undef these to get the function prototypes from common.h */ +#undef av_log2 +#undef av_log2_16bit +#include "common.h" + +int av_log2(unsigned v) +{ + return ff_log2(v); +} + +int av_log2_16bit(unsigned v) +{ + return ff_log2_16bit(v); +} diff --git a/libs/ffmpeg/libavutil/intmath.h b/libs/ffmpeg/libavutil/intmath.h new file mode 100644 index 00000000000..b177a848c69 --- /dev/null +++ b/libs/ffmpeg/libavutil/intmath.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2010 Mans Rullgard <mans@mansr.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTMATH_H +#define AVUTIL_INTMATH_H + +#include <stdint.h> + +#include "config.h" +#include "attributes.h" + +#if ARCH_ARM +# include "arm/intmath.h" +#elif ARCH_RISCV +# include "riscv/intmath.h" +#elif ARCH_X86 +# include "x86/intmath.h" +#endif + +#if HAVE_FAST_CLZ +#if AV_GCC_VERSION_AT_LEAST(3,4) || AV_HAS_BUILTIN(__builtin_clz) +#ifndef ff_log2 +# define ff_log2(x) (31 - __builtin_clz((x)|1)) +# ifndef ff_log2_16bit +# define ff_log2_16bit av_log2 +# endif +#endif /* ff_log2 */ +#endif /* AV_GCC_VERSION_AT_LEAST(3,4) */ +#endif + +extern const uint8_t ff_log2_tab[256]; + +#ifndef ff_log2 +#define ff_log2 ff_log2_c +static av_always_inline av_const int ff_log2_c(unsigned int v) +{ + int n = 0; + if (v & 0xffff0000) { + v >>= 16; + n += 16; + } + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} +#endif + +#ifndef ff_log2_16bit +#define ff_log2_16bit ff_log2_16bit_c +static av_always_inline av_const int ff_log2_16bit_c(unsigned int v) +{ + int n = 0; + if (v & 0xff00) { + v >>= 8; + n += 8; + } + n += ff_log2_tab[v]; + + return n; +} +#endif + +#define av_log2 ff_log2 +#define av_log2_16bit ff_log2_16bit + +/** + * @addtogroup lavu_math + * @{ + */ + +#if HAVE_FAST_CLZ +#if !defined(ff_ctz) && (AV_GCC_VERSION_AT_LEAST(3,4) || AV_HAS_BUILTIN(__builtin_ctz)) +#define ff_ctz(v) __builtin_ctz(v) +#endif +#if !defined(ff_ctzll) && (AV_GCC_VERSION_AT_LEAST(3,4) || AV_HAS_BUILTIN(__builtin_ctzll)) +#define ff_ctzll(v) __builtin_ctzll(v) +#endif +#if !defined(ff_clz) && (AV_GCC_VERSION_AT_LEAST(3,4) || AV_HAS_BUILTIN(__builtin_clz)) +#define ff_clz(v) __builtin_clz(v) +#endif +#endif + +#ifndef ff_ctz +#define ff_ctz ff_ctz_c +/** + * Trailing zero bit count. + * + * @param v input value. If v is 0, the result is undefined. + * @return the number of trailing 0-bits + */ +/* We use the De-Bruijn method outlined in: + * http://supertech.csail.mit.edu/papers/debruijn.pdf. */ +static av_always_inline av_const int ff_ctz_c(int v) +{ + static const uint8_t debruijn_ctz32[32] = { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 + }; + return debruijn_ctz32[(uint32_t)((v & -(uint32_t)v) * 0x077CB531U) >> 27]; +} +#endif + +#ifndef ff_ctzll +#define ff_ctzll ff_ctzll_c +/* We use the De-Bruijn method outlined in: + * http://supertech.csail.mit.edu/papers/debruijn.pdf. */ +static av_always_inline av_const int ff_ctzll_c(long long v) +{ + static const uint8_t debruijn_ctz64[64] = { + 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 + }; + return debruijn_ctz64[(uint64_t)((v & -(uint64_t)v) * 0x022FDD63CC95386DU) >> 58]; +} +#endif + +#ifndef ff_clz +#define ff_clz ff_clz_c +static av_always_inline av_const unsigned ff_clz_c(unsigned x) +{ + unsigned i = sizeof(x) * 8; + + while (x) { + x >>= 1; + i--; + } + + return i; +} +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,4) || AV_HAS_BUILTIN(__builtin_parity) +#ifndef av_parity +#define av_parity __builtin_parity +#endif +#endif + +/** + * @} + */ +#endif /* AVUTIL_INTMATH_H */ diff --git a/libs/ffmpeg/libavutil/intreadwrite.h b/libs/ffmpeg/libavutil/intreadwrite.h new file mode 100644 index 00000000000..ffd15a15029 --- /dev/null +++ b/libs/ffmpeg/libavutil/intreadwrite.h @@ -0,0 +1,677 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTREADWRITE_H +#define AVUTIL_INTREADWRITE_H + +#include <stdint.h> +#include "libavutil/avconfig.h" +#include "attributes.h" +#include "bswap.h" + +typedef union { + uint64_t u64; + uint32_t u32[2]; + uint16_t u16[4]; + uint8_t u8 [8]; + double f64; + float f32[2]; +} av_alias av_alias64; + +typedef union { + uint32_t u32; + uint16_t u16[2]; + uint8_t u8 [4]; + float f32; +} av_alias av_alias32; + +typedef union { + uint16_t u16; + uint8_t u8 [2]; +} av_alias av_alias16; + +/* + * Arch-specific headers can provide any combination of + * AV_[RW][BLN](16|24|32|48|64) and AV_(COPY|SWAP|ZERO)(64|128) macros. + * Preprocessor symbols must be defined, even if these are implemented + * as inline functions. + * + * R/W means read/write, B/L/N means big/little/native endianness. + * The following macros require aligned access, compared to their + * unaligned variants: AV_(COPY|SWAP|ZERO)(64|128), AV_[RW]N[8-64]A. + * Incorrect usage may range from abysmal performance to crash + * depending on the platform. + * + * The unaligned variants are AV_[RW][BLN][8-64] and AV_COPY*U. + */ + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_AARCH64 +# include "aarch64/intreadwrite.h" +#elif ARCH_MIPS +# include "mips/intreadwrite.h" +#elif ARCH_PPC +# include "ppc/intreadwrite.h" +#elif ARCH_X86 +# include "x86/intreadwrite.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +/* + * Map AV_RNXX <-> AV_R[BL]XX for all variants provided by per-arch headers. + */ + +#if AV_HAVE_BIGENDIAN + +# if defined(AV_RN16) && !defined(AV_RB16) +# define AV_RB16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RB16) +# define AV_RN16(p) AV_RB16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WB16) +# define AV_WB16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WB16) +# define AV_WN16(p, v) AV_WB16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RB24) +# define AV_RB24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RB24) +# define AV_RN24(p) AV_RB24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WB24) +# define AV_WB24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WB24) +# define AV_WN24(p, v) AV_WB24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RB32) +# define AV_RB32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RB32) +# define AV_RN32(p) AV_RB32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WB32) +# define AV_WB32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WB32) +# define AV_WN32(p, v) AV_WB32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RB48) +# define AV_RB48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RB48) +# define AV_RN48(p) AV_RB48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WB48) +# define AV_WB48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WB48) +# define AV_WN48(p, v) AV_WB48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RB64) +# define AV_RB64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RB64) +# define AV_RN64(p) AV_RB64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WB64) +# define AV_WB64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WB64) +# define AV_WN64(p, v) AV_WB64(p, v) +# endif + +#else /* AV_HAVE_BIGENDIAN */ + +# if defined(AV_RN16) && !defined(AV_RL16) +# define AV_RL16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RL16) +# define AV_RN16(p) AV_RL16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WL16) +# define AV_WL16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WL16) +# define AV_WN16(p, v) AV_WL16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RL24) +# define AV_RL24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RL24) +# define AV_RN24(p) AV_RL24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WL24) +# define AV_WL24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WL24) +# define AV_WN24(p, v) AV_WL24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RL32) +# define AV_RL32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RL32) +# define AV_RN32(p) AV_RL32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WL32) +# define AV_WL32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WL32) +# define AV_WN32(p, v) AV_WL32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RL48) +# define AV_RL48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RL48) +# define AV_RN48(p) AV_RL48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WL48) +# define AV_WL48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WL48) +# define AV_WN48(p, v) AV_WL48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RL64) +# define AV_RL64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RL64) +# define AV_RN64(p) AV_RL64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WL64) +# define AV_WL64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WL64) +# define AV_WN64(p, v) AV_WL64(p, v) +# endif + +#endif /* !AV_HAVE_BIGENDIAN */ + +/* + * Define AV_[RW]N helper macros to simplify definitions not provided + * by per-arch headers. + */ + +#if defined(__GNUC__) || defined(__clang__) + +union unaligned_64 { uint64_t l; } __attribute__((packed)) av_alias; +union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias; +union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; + +# define AV_RN(s, p) (((const union unaligned_##s *) (p))->l) +# define AV_WN(s, p, v) ((((union unaligned_##s *) (p))->l) = (v)) + +#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_X64) || defined(_M_ARM64)) && AV_HAVE_FAST_UNALIGNED + +# define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) +# define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) + +#elif AV_HAVE_FAST_UNALIGNED + +# define AV_RN(s, p) (((const av_alias##s*)(p))->u##s) +# define AV_WN(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#else + +#ifndef AV_RB16 +# define AV_RB16(x) \ + ((((const uint8_t*)(x))[0] << 8) | \ + ((const uint8_t*)(x))[1]) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, val) do { \ + uint16_t d = (val); \ + ((uint8_t*)(p))[1] = (d); \ + ((uint8_t*)(p))[0] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RL16 +# define AV_RL16(x) \ + ((((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, val) do { \ + uint16_t d = (val); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RB32 +# define AV_RB32(x) \ + (((uint32_t)((const uint8_t*)(x))[0] << 24) | \ + (((const uint8_t*)(x))[1] << 16) | \ + (((const uint8_t*)(x))[2] << 8) | \ + ((const uint8_t*)(x))[3]) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, val) do { \ + uint32_t d = (val); \ + ((uint8_t*)(p))[3] = (d); \ + ((uint8_t*)(p))[2] = (d)>>8; \ + ((uint8_t*)(p))[1] = (d)>>16; \ + ((uint8_t*)(p))[0] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RL32 +# define AV_RL32(x) \ + (((uint32_t)((const uint8_t*)(x))[3] << 24) | \ + (((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, val) do { \ + uint32_t d = (val); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RB64 +# define AV_RB64(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 8) | \ + (uint64_t)((const uint8_t*)(x))[7]) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, val) do { \ + uint64_t d = (val); \ + ((uint8_t*)(p))[7] = (d); \ + ((uint8_t*)(p))[6] = (d)>>8; \ + ((uint8_t*)(p))[5] = (d)>>16; \ + ((uint8_t*)(p))[4] = (d)>>24; \ + ((uint8_t*)(p))[3] = (d)>>32; \ + ((uint8_t*)(p))[2] = (d)>>40; \ + ((uint8_t*)(p))[1] = (d)>>48; \ + ((uint8_t*)(p))[0] = (d)>>56; \ + } while(0) +#endif + +#ifndef AV_RL64 +# define AV_RL64(x) \ + (((uint64_t)((const uint8_t*)(x))[7] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, val) do { \ + uint64_t d = (val); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + ((uint8_t*)(p))[6] = (d)>>48; \ + ((uint8_t*)(p))[7] = (d)>>56; \ + } while(0) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RN(s, p) AV_RB##s(p) +# define AV_WN(s, p, v) AV_WB##s(p, v) +#else +# define AV_RN(s, p) AV_RL##s(p) +# define AV_WN(s, p, v) AV_WL##s(p, v) +#endif + +#endif /* HAVE_FAST_UNALIGNED */ + +#ifndef AV_RN16 +# define AV_RN16(p) AV_RN(16, p) +#endif + +#ifndef AV_RN32 +# define AV_RN32(p) AV_RN(32, p) +#endif + +#ifndef AV_RN64 +# define AV_RN64(p) AV_RN(64, p) +#endif + +#ifndef AV_WN16 +# define AV_WN16(p, v) AV_WN(16, p, v) +#endif + +#ifndef AV_WN32 +# define AV_WN32(p, v) AV_WN(32, p, v) +#endif + +#ifndef AV_WN64 +# define AV_WN64(p, v) AV_WN(64, p, v) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RB(s, p) AV_RN##s(p) +# define AV_WB(s, p, v) AV_WN##s(p, v) +# define AV_RL(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WL(s, p, v) AV_WN##s(p, av_bswap##s(v)) +#else +# define AV_RB(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WB(s, p, v) AV_WN##s(p, av_bswap##s(v)) +# define AV_RL(s, p) AV_RN##s(p) +# define AV_WL(s, p, v) AV_WN##s(p, v) +#endif + +#define AV_RB8(x) (((const uint8_t*)(x))[0]) +#define AV_WB8(p, d) do { ((uint8_t*)(p))[0] = (d); } while(0) + +#define AV_RL8(x) AV_RB8(x) +#define AV_WL8(p, d) AV_WB8(p, d) + +#ifndef AV_RB16 +# define AV_RB16(p) AV_RB(16, p) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, v) AV_WB(16, p, v) +#endif + +#ifndef AV_RL16 +# define AV_RL16(p) AV_RL(16, p) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, v) AV_WL(16, p, v) +#endif + +#ifndef AV_RB32 +# define AV_RB32(p) AV_RB(32, p) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, v) AV_WB(32, p, v) +#endif + +#ifndef AV_RL32 +# define AV_RL32(p) AV_RL(32, p) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, v) AV_WL(32, p, v) +#endif + +#ifndef AV_RB64 +# define AV_RB64(p) AV_RB(64, p) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, v) AV_WB(64, p, v) +#endif + +#ifndef AV_RL64 +# define AV_RL64(p) AV_RL(64, p) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, v) AV_WL(64, p, v) +#endif + +#ifndef AV_RB24 +# define AV_RB24(x) \ + ((((const uint8_t*)(x))[0] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[2]) +#endif +#ifndef AV_WB24 +# define AV_WB24(p, d) do { \ + ((uint8_t*)(p))[2] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[0] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RL24 +# define AV_RL24(x) \ + ((((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL24 +# define AV_WL24(p, d) do { \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RB48 +# define AV_RB48(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 8) | \ + (uint64_t)((const uint8_t*)(x))[5]) +#endif +#ifndef AV_WB48 +# define AV_WB48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[5] = (d); \ + ((uint8_t*)(p))[4] = (d)>>8; \ + ((uint8_t*)(p))[3] = (d)>>16; \ + ((uint8_t*)(p))[2] = (d)>>24; \ + ((uint8_t*)(p))[1] = (d)>>32; \ + ((uint8_t*)(p))[0] = (d)>>40; \ + } while(0) +#endif + +#ifndef AV_RL48 +# define AV_RL48(x) \ + (((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL48 +# define AV_WL48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + } while(0) +#endif + +/* + * The AV_[RW]NA macros access naturally aligned data + * in a type-safe way. + */ + +#define AV_RNA(s, p) (((const av_alias##s*)(p))->u##s) +#define AV_WNA(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#ifndef AV_RN16A +# define AV_RN16A(p) AV_RNA(16, p) +#endif + +#ifndef AV_RN32A +# define AV_RN32A(p) AV_RNA(32, p) +#endif + +#ifndef AV_RN64A +# define AV_RN64A(p) AV_RNA(64, p) +#endif + +#ifndef AV_WN16A +# define AV_WN16A(p, v) AV_WNA(16, p, v) +#endif + +#ifndef AV_WN32A +# define AV_WN32A(p, v) AV_WNA(32, p, v) +#endif + +#ifndef AV_WN64A +# define AV_WN64A(p, v) AV_WNA(64, p, v) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RLA(s, p) av_bswap##s(AV_RN##s##A(p)) +# define AV_WLA(s, p, v) AV_WN##s##A(p, av_bswap##s(v)) +# define AV_RBA(s, p) AV_RN##s##A(p) +# define AV_WBA(s, p, v) AV_WN##s##A(p, v) +#else +# define AV_RLA(s, p) AV_RN##s##A(p) +# define AV_WLA(s, p, v) AV_WN##s##A(p, v) +# define AV_RBA(s, p) av_bswap##s(AV_RN##s##A(p)) +# define AV_WBA(s, p, v) AV_WN##s##A(p, av_bswap##s(v)) +#endif + +#ifndef AV_RL16A +# define AV_RL16A(p) AV_RLA(16, p) +#endif +#ifndef AV_WL16A +# define AV_WL16A(p, v) AV_WLA(16, p, v) +#endif + +#ifndef AV_RB16A +# define AV_RB16A(p) AV_RBA(16, p) +#endif +#ifndef AV_WB16A +# define AV_WB16A(p, v) AV_WBA(16, p, v) +#endif + +#ifndef AV_RL32A +# define AV_RL32A(p) AV_RLA(32, p) +#endif +#ifndef AV_WL32A +# define AV_WL32A(p, v) AV_WLA(32, p, v) +#endif + +#ifndef AV_RB32A +# define AV_RB32A(p) AV_RBA(32, p) +#endif +#ifndef AV_WB32A +# define AV_WB32A(p, v) AV_WBA(32, p, v) +#endif + +#ifndef AV_RL64A +# define AV_RL64A(p) AV_RLA(64, p) +#endif +#ifndef AV_WL64A +# define AV_WL64A(p, v) AV_WLA(64, p, v) +#endif + +#ifndef AV_RB64A +# define AV_RB64A(p) AV_RBA(64, p) +#endif +#ifndef AV_WB64A +# define AV_WB64A(p, v) AV_WBA(64, p, v) +#endif + +/* + * The AV_COPYxxU macros are suitable for copying data to/from unaligned + * memory locations. + */ + +#define AV_COPYU(n, d, s) AV_WN##n(d, AV_RN##n(s)); + +#ifndef AV_COPY16U +# define AV_COPY16U(d, s) AV_COPYU(16, d, s) +#endif + +#ifndef AV_COPY32U +# define AV_COPY32U(d, s) AV_COPYU(32, d, s) +#endif + +#ifndef AV_COPY64U +# define AV_COPY64U(d, s) AV_COPYU(64, d, s) +#endif + +#ifndef AV_COPY128U +# define AV_COPY128U(d, s) \ + do { \ + AV_COPY64U(d, s); \ + AV_COPY64U((char *)(d) + 8, (const char *)(s) + 8); \ + } while(0) +#endif + +/* Parameters for AV_COPY*, AV_SWAP*, AV_ZERO* must be + * naturally aligned. + */ + +#define AV_COPY(n, d, s) \ + (((av_alias##n*)(d))->u##n = ((const av_alias##n*)(s))->u##n) + +#ifndef AV_COPY16 +# define AV_COPY16(d, s) AV_COPY(16, d, s) +#endif + +#ifndef AV_COPY32 +# define AV_COPY32(d, s) AV_COPY(32, d, s) +#endif + +#ifndef AV_COPY64 +# define AV_COPY64(d, s) AV_COPY(64, d, s) +#endif + +#ifndef AV_COPY128 +# define AV_COPY128(d, s) \ + do { \ + AV_COPY64(d, s); \ + AV_COPY64((char*)(d)+8, (char*)(s)+8); \ + } while(0) +#endif + +#define AV_SWAP(n, a, b) FFSWAP(av_alias##n, *(av_alias##n*)(a), *(av_alias##n*)(b)) + +#ifndef AV_SWAP64 +# define AV_SWAP64(a, b) AV_SWAP(64, a, b) +#endif + +#define AV_ZERO(n, d) (((av_alias##n*)(d))->u##n = 0) + +#ifndef AV_ZERO16 +# define AV_ZERO16(d) AV_ZERO(16, d) +#endif + +#ifndef AV_ZERO32 +# define AV_ZERO32(d) AV_ZERO(32, d) +#endif + +#ifndef AV_ZERO64 +# define AV_ZERO64(d) AV_ZERO(64, d) +#endif + +#ifndef AV_ZERO128 +# define AV_ZERO128(d) \ + do { \ + AV_ZERO64(d); \ + AV_ZERO64((char*)(d)+8); \ + } while(0) +#endif + +#endif /* AVUTIL_INTREADWRITE_H */ diff --git a/libs/ffmpeg/libavutil/lfg.c b/libs/ffmpeg/libavutil/lfg.c new file mode 100644 index 00000000000..46b04d24039 --- /dev/null +++ b/libs/ffmpeg/libavutil/lfg.c @@ -0,0 +1,87 @@ +/* + * Lagged Fibonacci PRNG + * Copyright (c) 2008 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <inttypes.h> +#include <limits.h> +#include <math.h> +#include "lfg.h" +#include "crc.h" +#include "md5.h" +#include "error.h" +#include "intreadwrite.h" +#include "attributes.h" + +av_cold void av_lfg_init(AVLFG *c, unsigned int seed) +{ + uint8_t tmp[16] = { 0 }; + int i; + + for (i = 8; i < 64; i += 4) { + AV_WL32(tmp, seed); + tmp[4] = i; + av_md5_sum(tmp, tmp, 16); + c->state[i ] = AV_RL32(tmp); + c->state[i + 1] = AV_RL32(tmp + 4); + c->state[i + 2] = AV_RL32(tmp + 8); + c->state[i + 3] = AV_RL32(tmp + 12); + } + c->index = 0; +} + +void av_bmg_get(AVLFG *lfg, double out[2]) +{ + double x1, x2, w; + + do { + x1 = 2.0 / UINT_MAX * av_lfg_get(lfg) - 1.0; + x2 = 2.0 / UINT_MAX * av_lfg_get(lfg) - 1.0; + w = x1 * x1 + x2 * x2; + } while (w >= 1.0); + + w = sqrt((-2.0 * log(w)) / w); + out[0] = x1 * w; + out[1] = x2 * w; +} + +int av_lfg_init_from_data(AVLFG *c, const uint8_t *data, unsigned int length) { + unsigned int beg, end, segm; + const AVCRC *avcrc; + uint32_t crc = 1; + + /* avoid integer overflow in the loop below. */ + if (length > (UINT_MAX / 128U)) return AVERROR(EINVAL); + + c->index = 0; + avcrc = av_crc_get_table(AV_CRC_32_IEEE); /* This can't fail. It's a well-defined table in crc.c */ + + /* across 64 segments of the incoming data, + * do a running crc of each segment and store the crc as the state for that slot. + * this works even if the length of the segment is 0 bytes. */ + beg = 0; + for (segm = 0;segm < 64;segm++) { + end = (((segm + 1) * length) / 64); + crc = av_crc(avcrc, crc, data + beg, end - beg); + c->state[segm] = (unsigned int)crc; + beg = end; + } + + return 0; +} diff --git a/libs/ffmpeg/libavutil/lfg.h b/libs/ffmpeg/libavutil/lfg.h new file mode 100644 index 00000000000..043d0ab3430 --- /dev/null +++ b/libs/ffmpeg/libavutil/lfg.h @@ -0,0 +1,81 @@ +/* + * Lagged Fibonacci PRNG + * Copyright (c) 2008 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LFG_H +#define AVUTIL_LFG_H + +#include <stdint.h> + +/** + * Context structure for the Lagged Fibonacci PRNG. + * The exact layout, types and content of this struct may change and should + * not be accessed directly. Only its `sizeof()` is guaranteed to stay the same + * to allow easy instantiation. + */ +typedef struct AVLFG { + unsigned int state[64]; + int index; +} AVLFG; + +void av_lfg_init(AVLFG *c, unsigned int seed); + +/** + * Seed the state of the ALFG using binary data. + * + * @return 0 on success, negative value (AVERROR) on failure. + */ +int av_lfg_init_from_data(AVLFG *c, const uint8_t *data, unsigned int length); + +/** + * Get the next random unsigned 32-bit number using an ALFG. + * + * Please also consider a simple LCG like state= state*1664525+1013904223, + * it may be good enough and faster for your specific use case. + */ +static inline unsigned int av_lfg_get(AVLFG *c){ + unsigned a = c->state[c->index & 63] = c->state[(c->index-24) & 63] + c->state[(c->index-55) & 63]; + c->index += 1U; + return a; +} + +/** + * Get the next random unsigned 32-bit number using a MLFG. + * + * Please also consider av_lfg_get() above, it is faster. + */ +static inline unsigned int av_mlfg_get(AVLFG *c){ + unsigned int a= c->state[(c->index-55) & 63]; + unsigned int b= c->state[(c->index-24) & 63]; + a = c->state[c->index & 63] = 2*a*b+a+b; + c->index += 1U; + return a; +} + +/** + * Get the next two numbers generated by a Box-Muller Gaussian + * generator using the random numbers issued by lfg. + * + * @param lfg pointer to the context structure + * @param out array where the two generated numbers are placed + */ +void av_bmg_get(AVLFG *lfg, double out[2]); + +#endif /* AVUTIL_LFG_H */ diff --git a/libs/ffmpeg/libavutil/libm.h b/libs/ffmpeg/libavutil/libm.h new file mode 100644 index 00000000000..e560885d5d5 --- /dev/null +++ b/libs/ffmpeg/libavutil/libm.h @@ -0,0 +1,473 @@ +/* + * erf function: Copyright (c) 2006 John Maddock + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Replacements for frequently missing libm functions + */ + +#ifndef AVUTIL_LIBM_H +#define AVUTIL_LIBM_H + +#include <math.h> +#include "config.h" +#include "attributes.h" +#if !(HAVE_COPYSIGN && HAVE_HYPOT && HAVE_ISFINITE && HAVE_ISINF && HAVE_ISNAN) +#include "intfloat.h" +#endif +#include "mathematics.h" + +#if HAVE_MIPSFPU && HAVE_INLINE_ASM +#include "libavutil/mips/libm_mips.h" +#endif /* HAVE_MIPSFPU && HAVE_INLINE_ASM*/ + +#if !HAVE_ATANF +#undef atanf +#define atanf(x) ((float)atan(x)) +#endif /* HAVE_ATANF */ + +#if !HAVE_ATAN2F +#undef atan2f +#define atan2f(y, x) ((float)atan2(y, x)) +#endif /* HAVE_ATAN2F */ + +#if !HAVE_POWF +#undef powf +#define powf(x, y) ((float)pow(x, y)) +#endif /* HAVE_POWF */ + +#if !HAVE_CBRT +static av_always_inline double cbrt(double x) +{ + return x < 0 ? -pow(-x, 1.0 / 3.0) : pow(x, 1.0 / 3.0); +} +#endif /* HAVE_CBRT */ + +#if !HAVE_CBRTF +static av_always_inline float cbrtf(float x) +{ + return x < 0 ? -powf(-x, 1.0 / 3.0) : powf(x, 1.0 / 3.0); +} +#endif /* HAVE_CBRTF */ + +#if !HAVE_COPYSIGN +static av_always_inline double copysign(double x, double y) +{ + uint64_t vx = av_double2int(x); + uint64_t vy = av_double2int(y); + return av_int2double((vx & UINT64_C(0x7fffffffffffffff)) | (vy & UINT64_C(0x8000000000000000))); +} +#endif /* HAVE_COPYSIGN */ + +#if !HAVE_COSF +#undef cosf +#define cosf(x) ((float)cos(x)) +#endif /* HAVE_COSF */ + +#if !HAVE_ERF +static inline double ff_eval_poly(const double *coeff, int size, double x) { + double sum = coeff[size-1]; + int i; + for (i = size-2; i >= 0; --i) { + sum *= x; + sum += coeff[i]; + } + return sum; +} + +/** + * erf function + * Algorithm taken from the Boost project, source: + * http://www.boost.org/doc/libs/1_46_1/boost/math/special_functions/erf.hpp + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0 (see notice below). + * Boost Software License - Version 1.0 - August 17th, 2003 +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + */ +static inline double erf(double z) +{ +#ifndef FF_ARRAY_ELEMS +#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) +#endif + double result; + + /* handle the symmetry: erf(-x) = -erf(x) */ + if (z < 0) + return -erf(-z); + + /* branch based on range of z, and pick appropriate approximation */ + if (z == 0) + return 0; + else if (z < 1e-10) + return z * 1.125 + z * 0.003379167095512573896158903121545171688; + else if (z < 0.5) { + // Maximum Deviation Found: 1.561e-17 + // Expected Error Term: 1.561e-17 + // Maximum Relative Change in Control Points: 1.155e-04 + // Max Error found at double precision = 2.961182e-17 + + static const double y = 1.044948577880859375; + static const double p[] = { + 0.0834305892146531832907, + -0.338165134459360935041, + -0.0509990735146777432841, + -0.00772758345802133288487, + -0.000322780120964605683831, + }; + static const double q[] = { + 1, + 0.455004033050794024546, + 0.0875222600142252549554, + 0.00858571925074406212772, + 0.000370900071787748000569, + }; + double zz = z * z; + return z * (y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), zz) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), zz)); + } + /* here onwards compute erfc */ + else if (z < 1.5) { + // Maximum Deviation Found: 3.702e-17 + // Expected Error Term: 3.702e-17 + // Maximum Relative Change in Control Points: 2.845e-04 + // Max Error found at double precision = 4.841816e-17 + static const double y = 0.405935764312744140625; + static const double p[] = { + -0.098090592216281240205, + 0.178114665841120341155, + 0.191003695796775433986, + 0.0888900368967884466578, + 0.0195049001251218801359, + 0.00180424538297014223957, + }; + static const double q[] = { + 1, + 1.84759070983002217845, + 1.42628004845511324508, + 0.578052804889902404909, + 0.12385097467900864233, + 0.0113385233577001411017, + 0.337511472483094676155e-5, + }; + result = y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), z - 0.5) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), z - 0.5); + result *= exp(-z * z) / z; + return 1 - result; + } + else if (z < 2.5) { + // Max Error found at double precision = 6.599585e-18 + // Maximum Deviation Found: 3.909e-18 + // Expected Error Term: 3.909e-18 + // Maximum Relative Change in Control Points: 9.886e-05 + static const double y = 0.50672817230224609375; + static const double p[] = { + -0.0243500476207698441272, + 0.0386540375035707201728, + 0.04394818964209516296, + 0.0175679436311802092299, + 0.00323962406290842133584, + 0.000235839115596880717416, + }; + static const double q[] = { + 1, + 1.53991494948552447182, + 0.982403709157920235114, + 0.325732924782444448493, + 0.0563921837420478160373, + 0.00410369723978904575884, + }; + result = y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), z - 1.5) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), z - 1.5); + result *= exp(-z * z) / z; + return 1 - result; + } + else if (z < 4.5) { + // Maximum Deviation Found: 1.512e-17 + // Expected Error Term: 1.512e-17 + // Maximum Relative Change in Control Points: 2.222e-04 + // Max Error found at double precision = 2.062515e-17 + static const double y = 0.5405750274658203125; + static const double p[] = { + 0.00295276716530971662634, + 0.0137384425896355332126, + 0.00840807615555585383007, + 0.00212825620914618649141, + 0.000250269961544794627958, + 0.113212406648847561139e-4, + }; + static const double q[] = { + 1, + 1.04217814166938418171, + 0.442597659481563127003, + 0.0958492726301061423444, + 0.0105982906484876531489, + 0.000479411269521714493907, + }; + result = y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), z - 3.5) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), z - 3.5); + result *= exp(-z * z) / z; + return 1 - result; + } + /* differ from Boost here, the claim of underflow of erfc(x) past 5.8 is + * slightly incorrect, change to 5.92 + * (really somewhere between 5.9125 and 5.925 is when it saturates) */ + else if (z < 5.92) { + // Max Error found at double precision = 2.997958e-17 + // Maximum Deviation Found: 2.860e-17 + // Expected Error Term: 2.859e-17 + // Maximum Relative Change in Control Points: 1.357e-05 + static const double y = 0.5579090118408203125; + static const double p[] = { + 0.00628057170626964891937, + 0.0175389834052493308818, + -0.212652252872804219852, + -0.687717681153649930619, + -2.5518551727311523996, + -3.22729451764143718517, + -2.8175401114513378771, + }; + static const double q[] = { + 1, + 2.79257750980575282228, + 11.0567237927800161565, + 15.930646027911794143, + 22.9367376522880577224, + 13.5064170191802889145, + 5.48409182238641741584, + }; + result = y + ff_eval_poly(p, FF_ARRAY_ELEMS(p), 1 / z) / ff_eval_poly(q, FF_ARRAY_ELEMS(q), 1 / z); + result *= exp(-z * z) / z; + return 1 - result; + } + /* handle the nan case, but don't use isnan for max portability */ + else if (z != z) + return z; + /* finally return saturated result */ + else + return 1; +} +#endif /* HAVE_ERF */ + +#if !HAVE_EXPF +#undef expf +#define expf(x) ((float)exp(x)) +#endif /* HAVE_EXPF */ + +#if !HAVE_EXP2 +#undef exp2 +#define exp2(x) exp((x) * M_LN2) +#endif /* HAVE_EXP2 */ + +#if !HAVE_EXP2F +#undef exp2f +#define exp2f(x) ((float)exp2(x)) +#endif /* HAVE_EXP2F */ + +#if !HAVE_ISINF +#undef isinf +/* Note: these do not follow the BSD/Apple/GNU convention of returning -1 for +-Inf, +1 for Inf, 0 otherwise, but merely follow the POSIX/ISO mandated spec of +returning a non-zero value for +/-Inf, 0 otherwise. */ +static av_always_inline av_const int avpriv_isinff(float x) +{ + uint32_t v = av_float2int(x); + if ((v & 0x7f800000) != 0x7f800000) + return 0; + return !(v & 0x007fffff); +} + +static av_always_inline av_const int avpriv_isinf(double x) +{ + uint64_t v = av_double2int(x); + if ((v & 0x7ff0000000000000) != 0x7ff0000000000000) + return 0; + return !(v & 0x000fffffffffffff); +} + +#define isinf(x) \ + (sizeof(x) == sizeof(float) \ + ? avpriv_isinff(x) \ + : avpriv_isinf(x)) +#endif /* HAVE_ISINF */ + +#if !HAVE_ISNAN +static av_always_inline av_const int avpriv_isnanf(float x) +{ + uint32_t v = av_float2int(x); + if ((v & 0x7f800000) != 0x7f800000) + return 0; + return v & 0x007fffff; +} + +static av_always_inline av_const int avpriv_isnan(double x) +{ + uint64_t v = av_double2int(x); + if ((v & 0x7ff0000000000000) != 0x7ff0000000000000) + return 0; + return (v & 0x000fffffffffffff) && 1; +} + +#define isnan(x) \ + (sizeof(x) == sizeof(float) \ + ? avpriv_isnanf(x) \ + : avpriv_isnan(x)) +#endif /* HAVE_ISNAN */ + +#if !HAVE_ISFINITE +static av_always_inline av_const int avpriv_isfinitef(float x) +{ + uint32_t v = av_float2int(x); + return (v & 0x7f800000) != 0x7f800000; +} + +static av_always_inline av_const int avpriv_isfinite(double x) +{ + uint64_t v = av_double2int(x); + return (v & 0x7ff0000000000000) != 0x7ff0000000000000; +} + +#define isfinite(x) \ + (sizeof(x) == sizeof(float) \ + ? avpriv_isfinitef(x) \ + : avpriv_isfinite(x)) +#endif /* HAVE_ISFINITE */ + +#if !HAVE_HYPOT +static inline av_const double hypot(double x, double y) +{ + double temp; + x = fabs(x); + y = fabs(y); + + if (isinf(x) || isinf(y)) + return av_int2double(0x7ff0000000000000); + if (x == 0 || y == 0) + return x + y; + if (x < y) { + temp = x; + x = y; + y = temp; + } + + y = y/x; + return x*sqrt(1 + y*y); +} +#endif /* HAVE_HYPOT */ + +#if !HAVE_LDEXPF +#undef ldexpf +#define ldexpf(x, exp) ((float)ldexp(x, exp)) +#endif /* HAVE_LDEXPF */ + +#if !HAVE_LLRINT +#undef llrint +#define llrint(x) ((long long)rint(x)) +#endif /* HAVE_LLRINT */ + +#if !HAVE_LLRINTF +#undef llrintf +#define llrintf(x) ((long long)rint(x)) +#endif /* HAVE_LLRINT */ + +#if !HAVE_LOG2 +#undef log2 +#define log2(x) (log(x) * 1.44269504088896340736) +#endif /* HAVE_LOG2 */ + +#if !HAVE_LOG2F +#undef log2f +#define log2f(x) ((float)log2(x)) +#endif /* HAVE_LOG2F */ + +#if !HAVE_LOG10F +#undef log10f +#define log10f(x) ((float)log10(x)) +#endif /* HAVE_LOG10F */ + +#if !HAVE_SINF +#undef sinf +#define sinf(x) ((float)sin(x)) +#endif /* HAVE_SINF */ + +#if !HAVE_RINT +static inline double rint(double x) +{ + return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); +} +#endif /* HAVE_RINT */ + +#if !HAVE_LRINT +static av_always_inline av_const long int lrint(double x) +{ + return rint(x); +} +#endif /* HAVE_LRINT */ + +#if !HAVE_LRINTF +static av_always_inline av_const long int lrintf(float x) +{ + return (int)(rint(x)); +} +#endif /* HAVE_LRINTF */ + +#if !HAVE_ROUND +static av_always_inline av_const double round(double x) +{ + return (x > 0) ? floor(x + 0.5) : ceil(x - 0.5); +} +#endif /* HAVE_ROUND */ + +#if !HAVE_ROUNDF +static av_always_inline av_const float roundf(float x) +{ + return (x > 0) ? floor(x + 0.5) : ceil(x - 0.5); +} +#endif /* HAVE_ROUNDF */ + +#if !HAVE_TRUNC +static av_always_inline av_const double trunc(double x) +{ + return (x > 0) ? floor(x) : ceil(x); +} +#endif /* HAVE_TRUNC */ + +#if !HAVE_TRUNCF +static av_always_inline av_const float truncf(float x) +{ + return (x > 0) ? floor(x) : ceil(x); +} +#endif /* HAVE_TRUNCF */ + +#endif /* AVUTIL_LIBM_H */ diff --git a/libs/ffmpeg/libavutil/lls.c b/libs/ffmpeg/libavutil/lls.c new file mode 100644 index 00000000000..27168009c54 --- /dev/null +++ b/libs/ffmpeg/libavutil/lls.c @@ -0,0 +1,120 @@ +/* + * linear least squares model + * + * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * linear least squares model + */ + +#include <math.h> +#include <string.h> + +#include "config.h" +#include "attributes.h" +#include "float_dsp.h" +#include "lls.h" + +static void update_lls(LLSModel *m, const double *var) +{ + int i, j; + + for (i = 0; i <= m->indep_count; i++) { + for (j = i; j <= m->indep_count; j++) { + m->covariance[i][j] += var[i] * var[j]; + } + } +} + +void avpriv_solve_lls(LLSModel *m, double threshold, unsigned short min_order) +{ + int i, j, k; + double (*factor)[MAX_VARS_ALIGN] = (void *) &m->covariance[1][0]; + double (*covar) [MAX_VARS_ALIGN] = (void *) &m->covariance[1][1]; + double *covar_y = m->covariance[0]; + int count = m->indep_count; + + for (i = 0; i < count; i++) { + for (j = i; j < count; j++) { + double sum = covar[i][j]; + + for (k = 0; k <= i-1; k++) + sum -= factor[i][k] * factor[j][k]; + + if (i == j) { + if (sum < threshold) + sum = 1.0; + factor[i][i] = sqrt(sum); + } else { + factor[j][i] = sum / factor[i][i]; + } + } + } + + for (i = 0; i < count; i++) { + double sum = covar_y[i + 1]; + + for (k = 0; k <= i-1; k++) + sum -= factor[i][k] * m->coeff[0][k]; + + m->coeff[0][i] = sum / factor[i][i]; + } + + for (j = count - 1; j >= min_order; j--) { + for (i = j; i >= 0; i--) { + double sum = m->coeff[0][i]; + + for (k = i + 1; k <= j; k++) + sum -= factor[k][i] * m->coeff[j][k]; + + m->coeff[j][i] = sum / factor[i][i]; + } + + m->variance[j] = covar_y[0]; + + for (i = 0; i <= j; i++) { + double sum = m->coeff[j][i] * covar[i][i] - 2 * covar_y[i + 1]; + + for (k = 0; k < i; k++) + sum += 2 * m->coeff[j][k] * covar[k][i]; + + m->variance[j] += m->coeff[j][i] * sum; + } + } +} + +static double evaluate_lls(LLSModel *m, const double *param, int order) +{ + return ff_scalarproduct_double_c(m->coeff[order], param, order + 1); +} + +av_cold void avpriv_init_lls(LLSModel *m, int indep_count) +{ + memset(m, 0, sizeof(LLSModel)); + m->indep_count = indep_count; + m->update_lls = update_lls; + m->evaluate_lls = evaluate_lls; +#if ARCH_RISCV + ff_init_lls_riscv(m); +#elif ARCH_X86 && HAVE_X86ASM + ff_init_lls_x86(m); +#endif +} diff --git a/libs/ffmpeg/libavutil/lls.h b/libs/ffmpeg/libavutil/lls.h new file mode 100644 index 00000000000..7acef4eff88 --- /dev/null +++ b/libs/ffmpeg/libavutil/lls.h @@ -0,0 +1,64 @@ +/* + * linear least squares model + * + * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LLS_H +#define AVUTIL_LLS_H + +#include "macros.h" +#include "mem_internal.h" + +#define MAX_VARS 32 +#define MAX_VARS_ALIGN FFALIGN(MAX_VARS+1,4) + +//FIXME avoid direct access to LLSModel from outside + +/** + * Linear least squares model. + */ +typedef struct LLSModel { + DECLARE_ALIGNED(32, double, covariance[MAX_VARS_ALIGN][MAX_VARS_ALIGN]); + DECLARE_ALIGNED(32, double, coeff[MAX_VARS][MAX_VARS]); + double variance[MAX_VARS]; + int indep_count; + /** + * Take the outer-product of var[] with itself, and add to the covariance matrix. + * @param m this context + * @param var training samples, starting with the value to be predicted + * 32-byte aligned, and any padding elements must be initialized + * (i.e not denormal/nan). + */ + void (*update_lls)(struct LLSModel *m, const double *var); + /** + * Inner product of var[] and the LPC coefs. + * @param m this context + * @param var training samples, excluding the value to be predicted. unaligned. + * @param order lpc order + */ + double (*evaluate_lls)(struct LLSModel *m, const double *var, int order); +} LLSModel; + +void avpriv_init_lls(LLSModel *m, int indep_count); +void ff_init_lls_riscv(LLSModel *m); +void ff_init_lls_x86(LLSModel *m); +void avpriv_solve_lls(LLSModel *m, double threshold, unsigned short min_order); + +#endif /* AVUTIL_LLS_H */ diff --git a/libs/ffmpeg/libavutil/log.c b/libs/ffmpeg/libavutil/log.c new file mode 100644 index 00000000000..b5d3e46d6c5 --- /dev/null +++ b/libs/ffmpeg/libavutil/log.c @@ -0,0 +1,527 @@ +/* + * log functions + * Copyright (c) 2003 Michel Bardiaux + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * logging functions + */ + +#include "config.h" + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_IO_H +#include <io.h> +#endif +#include <inttypes.h> +#include <stdarg.h> +#include <stdatomic.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "bprint.h" +#include "common.h" +#include "internal.h" +#include "log.h" +#include "thread.h" +#include "time.h" +#include "time_internal.h" + +static AVMutex mutex = AV_MUTEX_INITIALIZER; + +#define LINE_SZ 1024 + +#if HAVE_VALGRIND_VALGRIND_H && CONFIG_VALGRIND_BACKTRACE +#include <valgrind/valgrind.h> +/* this is the log level at which valgrind will output a full backtrace */ +#define BACKTRACE_LOGLEVEL AV_LOG_ERROR +#endif + +static atomic_int av_log_level = AV_LOG_INFO; +static atomic_int av_log_flags = 0; + +#define NB_LEVELS 8 +#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE +#include <windows.h> +static const uint8_t color[16 + AV_CLASS_CATEGORY_NB] = { + [AV_LOG_PANIC /8] = 12, + [AV_LOG_FATAL /8] = 12, + [AV_LOG_ERROR /8] = 12, + [AV_LOG_WARNING/8] = 14, + [AV_LOG_INFO /8] = 7, + [AV_LOG_VERBOSE/8] = 10, + [AV_LOG_DEBUG /8] = 10, + [AV_LOG_TRACE /8] = 8, + [16+AV_CLASS_CATEGORY_NA ] = 7, + [16+AV_CLASS_CATEGORY_INPUT ] = 13, + [16+AV_CLASS_CATEGORY_OUTPUT ] = 5, + [16+AV_CLASS_CATEGORY_MUXER ] = 13, + [16+AV_CLASS_CATEGORY_DEMUXER ] = 5, + [16+AV_CLASS_CATEGORY_ENCODER ] = 11, + [16+AV_CLASS_CATEGORY_DECODER ] = 3, + [16+AV_CLASS_CATEGORY_FILTER ] = 10, + [16+AV_CLASS_CATEGORY_BITSTREAM_FILTER] = 9, + [16+AV_CLASS_CATEGORY_SWSCALER ] = 7, + [16+AV_CLASS_CATEGORY_SWRESAMPLER ] = 7, + [16+AV_CLASS_CATEGORY_HWDEVICE ] = 6, + [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT ] = 13, + [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT ] = 5, + [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT ] = 13, + [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT ] = 5, + [16+AV_CLASS_CATEGORY_DEVICE_OUTPUT ] = 13, + [16+AV_CLASS_CATEGORY_DEVICE_INPUT ] = 5, +}; + +static int16_t background, attr_orig; +static HANDLE con; +#else + +static const uint32_t color[16 + AV_CLASS_CATEGORY_NB] = { + [AV_LOG_PANIC /8] = 52 << 16 | 196 << 8 | 0x41, + [AV_LOG_FATAL /8] = 208 << 8 | 0x41, + [AV_LOG_ERROR /8] = 196 << 8 | 0x11, + [AV_LOG_WARNING/8] = 226 << 8 | 0x03, + [AV_LOG_INFO /8] = 253 << 8 | 0x09, + [AV_LOG_VERBOSE/8] = 40 << 8 | 0x02, + [AV_LOG_DEBUG /8] = 34 << 8 | 0x02, + [AV_LOG_TRACE /8] = 34 << 8 | 0x07, + [16+AV_CLASS_CATEGORY_NA ] = 250 << 8 | 0x09, + [16+AV_CLASS_CATEGORY_INPUT ] = 219 << 8 | 0x15, + [16+AV_CLASS_CATEGORY_OUTPUT ] = 201 << 8 | 0x05, + [16+AV_CLASS_CATEGORY_MUXER ] = 213 << 8 | 0x15, + [16+AV_CLASS_CATEGORY_DEMUXER ] = 207 << 8 | 0x05, + [16+AV_CLASS_CATEGORY_ENCODER ] = 51 << 8 | 0x16, + [16+AV_CLASS_CATEGORY_DECODER ] = 39 << 8 | 0x06, + [16+AV_CLASS_CATEGORY_FILTER ] = 155 << 8 | 0x12, + [16+AV_CLASS_CATEGORY_BITSTREAM_FILTER] = 192 << 8 | 0x14, + [16+AV_CLASS_CATEGORY_SWSCALER ] = 153 << 8 | 0x14, + [16+AV_CLASS_CATEGORY_SWRESAMPLER ] = 147 << 8 | 0x14, + [16+AV_CLASS_CATEGORY_HWDEVICE ] = 214 << 8 | 0x13, + [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT ] = 213 << 8 | 0x15, + [16+AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT ] = 207 << 8 | 0x05, + [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT ] = 213 << 8 | 0x15, + [16+AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT ] = 207 << 8 | 0x05, + [16+AV_CLASS_CATEGORY_DEVICE_OUTPUT ] = 213 << 8 | 0x15, + [16+AV_CLASS_CATEGORY_DEVICE_INPUT ] = 207 << 8 | 0x05, +}; + +#endif +static int use_color = -1; + +#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE +static void win_console_puts(const char *str) +{ + const uint8_t *q = str; + uint16_t line[LINE_SZ]; + + while (*q) { + uint16_t *buf = line; + DWORD nb_chars = 0; + DWORD written; + + while (*q && nb_chars < LINE_SZ - 1) { + uint32_t ch; + uint16_t tmp; + + GET_UTF8(ch, *q ? *q++ : 0, ch = 0xfffd; goto continue_on_invalid;) +continue_on_invalid: + PUT_UTF16(ch, tmp, *buf++ = tmp; nb_chars++;) + } + + WriteConsoleW(con, line, nb_chars, &written, NULL); + } +} +#endif + +static void check_color_terminal(void) +{ + char *term = getenv("TERM"); + +#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE + CONSOLE_SCREEN_BUFFER_INFO con_info; + DWORD dummy; + con = GetStdHandle(STD_ERROR_HANDLE); + if (con != INVALID_HANDLE_VALUE && !GetConsoleMode(con, &dummy)) + con = INVALID_HANDLE_VALUE; + if (con != INVALID_HANDLE_VALUE) { + GetConsoleScreenBufferInfo(con, &con_info); + attr_orig = con_info.wAttributes; + background = attr_orig & 0xF0; + } +#endif + + if (getenv("AV_LOG_FORCE_NOCOLOR")) { + use_color = 0; + } else if (getenv("AV_LOG_FORCE_COLOR")) { + use_color = 1; + } else { +#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE + use_color = (con != INVALID_HANDLE_VALUE); +#elif HAVE_ISATTY + use_color = (term && isatty(2)); +#else + use_color = 0; +#endif + } + + if (getenv("AV_LOG_FORCE_256COLOR") || term && strstr(term, "256color")) + use_color *= 256; +} + +static void ansi_fputs(int level, int tint, const char *str, int local_use_color) +{ + if (local_use_color == 1) { + fprintf(stderr, + "\033[%"PRIu32";3%"PRIu32"m%s\033[0m", + (color[level] >> 4) & 15, + color[level] & 15, + str); + } else if (tint && use_color == 256) { + fprintf(stderr, + "\033[48;5;%"PRIu32"m\033[38;5;%dm%s\033[0m", + (color[level] >> 16) & 0xff, + tint, + str); + } else if (local_use_color == 256) { + fprintf(stderr, + "\033[48;5;%"PRIu32"m\033[38;5;%"PRIu32"m%s\033[0m", + (color[level] >> 16) & 0xff, + (color[level] >> 8) & 0xff, + str); + } else + fputs(str, stderr); +} + +static void colored_fputs(int level, int tint, const char *str) +{ + int local_use_color; + if (!*str) + return; + + if (use_color < 0) + check_color_terminal(); + + if (level == AV_LOG_INFO/8) local_use_color = 0; + else local_use_color = use_color; + +#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE && HAVE_GETSTDHANDLE + if (con != INVALID_HANDLE_VALUE) { + if (local_use_color) + SetConsoleTextAttribute(con, background | color[level]); + win_console_puts(str); + if (local_use_color) + SetConsoleTextAttribute(con, attr_orig); + } else { + ansi_fputs(level, tint, str, local_use_color); + } +#else + ansi_fputs(level, tint, str, local_use_color); +#endif + +} + +const char *av_default_item_name(void *ptr) +{ + return (*(AVClass **) ptr)->class_name; +} + +AVClassCategory av_default_get_category(void *ptr) +{ + return (*(AVClass **) ptr)->category; +} + +static void sanitize(uint8_t *line){ + while(*line){ + if(*line < 0x08 || (*line > 0x0D && *line < 0x20)) + *line='?'; + line++; + } +} + +static int get_category(void *ptr){ + AVClass *avc = *(AVClass **) ptr; + if( !avc + || (avc->version&0xFF)<100 + || avc->version < (51 << 16 | 59 << 8) + || avc->category >= AV_CLASS_CATEGORY_NB) return AV_CLASS_CATEGORY_NA + 16; + + if(avc->get_category) + return avc->get_category(ptr) + 16; + + return avc->category + 16; +} + +static const char *get_level_str(int level) +{ + switch (level) { + case AV_LOG_QUIET: + return "quiet"; + case AV_LOG_DEBUG: + return "debug"; + case AV_LOG_TRACE: + return "trace"; + case AV_LOG_VERBOSE: + return "verbose"; + case AV_LOG_INFO: + return "info"; + case AV_LOG_WARNING: + return "warning"; + case AV_LOG_ERROR: + return "error"; + case AV_LOG_FATAL: + return "fatal"; + case AV_LOG_PANIC: + return "panic"; + default: + return ""; + } +} + +static const char *item_name(void *obj, const AVClass *cls) +{ + return (cls->item_name ? cls->item_name : av_default_item_name)(obj); +} + +static void format_date_now(AVBPrint* bp_time, int include_date) +{ + struct tm *ptm, tmbuf; + const int64_t time_us = av_gettime(); + const int64_t time_ms = time_us / 1000; + const time_t time_s = time_ms / 1000; + const int millisec = time_ms - (time_s * 1000); + ptm = localtime_r(&time_s, &tmbuf); + if (ptm) { + if (include_date) + av_bprint_strftime(bp_time, "%Y-%m-%d ", ptm); + + av_bprint_strftime(bp_time, "%H:%M:%S", ptm); + av_bprintf(bp_time, ".%03d ", millisec); + } +} + +static void format_line(void *avcl, int level, const char *fmt, va_list vl, + AVBPrint part[5], int *print_prefix, int type[2]) +{ + AVClass* avc = avcl ? *(AVClass **) avcl : NULL; + av_bprint_init(part+0, 0, AV_BPRINT_SIZE_AUTOMATIC); + av_bprint_init(part+1, 0, AV_BPRINT_SIZE_AUTOMATIC); + av_bprint_init(part+2, 0, AV_BPRINT_SIZE_AUTOMATIC); + av_bprint_init(part+3, 0, 65536); + av_bprint_init(part+4, 0, AV_BPRINT_SIZE_AUTOMATIC); + int flags = atomic_load_explicit(&av_log_flags, memory_order_relaxed); + + if(type) type[0] = type[1] = AV_CLASS_CATEGORY_NA + 16; + if (*print_prefix && avc) { + if (avc->parent_log_context_offset) { + AVClass** parent = *(AVClass ***) (((uint8_t *) avcl) + + avc->parent_log_context_offset); + if (parent && *parent) { + av_bprintf(part+0, "[%s @ %p] ", + item_name(parent, *parent), parent); + if(type) type[0] = get_category(parent); + } + } + av_bprintf(part+1, "[%s @ %p] ", + item_name(avcl, avc), avcl); + if(type) type[1] = get_category(avcl); + } + + if (*print_prefix && (level > AV_LOG_QUIET) && (flags & (AV_LOG_PRINT_TIME | AV_LOG_PRINT_DATETIME))) + format_date_now(&part[4], flags & AV_LOG_PRINT_DATETIME); + + if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL)) + av_bprintf(part+2, "[%s] ", get_level_str(level)); + + av_vbprintf(part+3, fmt, vl); + + if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) { + char lastc = part[3].len && part[3].len <= part[3].size ? part[3].str[part[3].len - 1] : 0; + *print_prefix = lastc == '\n' || lastc == '\r'; + } +} + +void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix) +{ + av_log_format_line2(ptr, level, fmt, vl, line, line_size, print_prefix); +} + +int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix) +{ + AVBPrint part[5]; + int ret; + + format_line(ptr, level, fmt, vl, part, print_prefix, NULL); + ret = snprintf(line, line_size, "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str); + av_bprint_finalize(part+3, NULL); + return ret; +} + +void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl) +{ + static int print_prefix = 1; + static int count; + static char prev[LINE_SZ]; + AVBPrint part[5]; + char line[LINE_SZ]; + static int is_atty; + int type[2]; + unsigned tint = 0; + + if (level >= 0) { + tint = level & 0xff00; + level &= 0xff; + } + + if (level > atomic_load_explicit(&av_log_level, memory_order_relaxed)) + return; + ff_mutex_lock(&mutex); + + format_line(ptr, level, fmt, vl, part, &print_prefix, type); + snprintf(line, sizeof(line), "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str); + +#if HAVE_ISATTY + if (!is_atty) + is_atty = isatty(2) ? 1 : -1; +#endif + + if (print_prefix && (atomic_load_explicit(&av_log_flags, memory_order_relaxed) & AV_LOG_SKIP_REPEATED) && !strcmp(line, prev) && + *line && line[strlen(line) - 1] != '\r'){ + count++; + if (is_atty == 1) + fprintf(stderr, " Last message repeated %d times\r", count); + goto end; + } + if (count > 0) { + fprintf(stderr, " Last message repeated %d times\n", count); + count = 0; + } + strcpy(prev, line); + + sanitize(part[4].str); + colored_fputs(7, 0, part[4].str); + sanitize(part[0].str); + colored_fputs(type[0], 0, part[0].str); + sanitize(part[1].str); + colored_fputs(type[1], 0, part[1].str); + sanitize(part[2].str); + colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[2].str); + sanitize(part[3].str); + colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[3].str); + +#if CONFIG_VALGRIND_BACKTRACE + if (level <= BACKTRACE_LOGLEVEL) + VALGRIND_PRINTF_BACKTRACE("%s", ""); +#endif +end: + av_bprint_finalize(part+3, NULL); + ff_mutex_unlock(&mutex); +} + +static atomic_uintptr_t av_log_callback = (uintptr_t)av_log_default_callback; + +void av_log(void* avcl, int level, const char *fmt, ...) +{ + va_list vl; + va_start(vl, fmt); + av_vlog(avcl, level, fmt, vl); + va_end(vl); +} + +void av_log_once(void* avcl, int initial_level, int subsequent_level, int *state, const char *fmt, ...) +{ + va_list vl; + va_start(vl, fmt); + av_vlog(avcl, *state ? subsequent_level : initial_level, fmt, vl); + va_end(vl); + *state = 1; +} + +void av_vlog(void* avcl, int level, const char *fmt, va_list vl) +{ + AVClass* avc = avcl ? *(AVClass **) avcl : NULL; + void (*log_callback)(void*, int, const char*, va_list) = + (void *)atomic_load_explicit(&av_log_callback, memory_order_relaxed); + if (avc && avc->version >= (50 << 16 | 15 << 8 | 2) && + avc->log_level_offset_offset && level >= AV_LOG_FATAL) + level += *(int *) (((uint8_t *) avcl) + avc->log_level_offset_offset); + if (log_callback) + log_callback(avcl, level, fmt, vl); +} + +int av_log_get_level(void) +{ + return atomic_load_explicit(&av_log_level, memory_order_relaxed); +} + +void av_log_set_level(int level) +{ + atomic_store_explicit(&av_log_level, level, memory_order_relaxed); +} + +void av_log_set_flags(int arg) +{ + atomic_store_explicit(&av_log_flags, arg, memory_order_relaxed); +} + +int av_log_get_flags(void) +{ + return atomic_load_explicit(&av_log_flags, memory_order_relaxed); +} + +void av_log_set_callback(void (*callback)(void*, int, const char*, va_list)) +{ + atomic_store_explicit(&av_log_callback, (uintptr_t)callback, memory_order_relaxed); +} + +static void missing_feature_sample(int sample, void *avc, const char *msg, + va_list argument_list) +{ + av_vlog(avc, AV_LOG_WARNING, msg, argument_list); + av_log(avc, AV_LOG_WARNING, " is not implemented. Update your FFmpeg " + "version to the newest one from Git. If the problem still " + "occurs, it means that your file has a feature which has not " + "been implemented.\n"); + if (sample) + av_log(avc, AV_LOG_WARNING, "If you want to help, upload a sample " + "of this file to https://streams.videolan.org/upload/ " + "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\n"); +} + +void avpriv_request_sample(void *avc, const char *msg, ...) +{ + va_list argument_list; + + va_start(argument_list, msg); + missing_feature_sample(1, avc, msg, argument_list); + va_end(argument_list); +} + +void avpriv_report_missing_feature(void *avc, const char *msg, ...) +{ + va_list argument_list; + + va_start(argument_list, msg); + missing_feature_sample(0, avc, msg, argument_list); + va_end(argument_list); +} diff --git a/libs/ffmpeg/libavutil/log.h b/libs/ffmpeg/libavutil/log.h new file mode 100644 index 00000000000..4a111ca9a5b --- /dev/null +++ b/libs/ffmpeg/libavutil/log.h @@ -0,0 +1,427 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LOG_H +#define AVUTIL_LOG_H + +#include <stdarg.h> +#include "attributes.h" +#include "version.h" + +typedef enum { + AV_CLASS_CATEGORY_NA = 0, + AV_CLASS_CATEGORY_INPUT, + AV_CLASS_CATEGORY_OUTPUT, + AV_CLASS_CATEGORY_MUXER, + AV_CLASS_CATEGORY_DEMUXER, + AV_CLASS_CATEGORY_ENCODER, + AV_CLASS_CATEGORY_DECODER, + AV_CLASS_CATEGORY_FILTER, + AV_CLASS_CATEGORY_BITSTREAM_FILTER, + AV_CLASS_CATEGORY_SWSCALER, + AV_CLASS_CATEGORY_SWRESAMPLER, + AV_CLASS_CATEGORY_HWDEVICE, + AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT = 40, + AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT, + AV_CLASS_CATEGORY_DEVICE_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_INPUT, + AV_CLASS_CATEGORY_NB ///< not part of ABI/API +}AVClassCategory; + +enum AVClassStateFlags { + /** + * Object initialization has finished and it is now in the 'runtime' stage. + * This affects e.g. what options can be set on the object (only + * AV_OPT_FLAG_RUNTIME_PARAM options can be set on initialized objects). + */ + AV_CLASS_STATE_INITIALIZED = (1 << 0), +}; + +#define AV_IS_INPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_INPUT)) + +#define AV_IS_OUTPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_OUTPUT)) + +struct AVOptionRanges; + +/** + * Describe the class of an AVClass context structure. That is an + * arbitrary struct of which the first field is a pointer to an + * AVClass struct (e.g. AVCodecContext, AVFormatContext etc.). + */ +typedef struct AVClass { + /** + * The name of the class; usually it is the same name as the + * context structure type to which the AVClass is associated. + */ + const char* class_name; + + /** + * A pointer to a function which returns the name of a context + * instance ctx associated with the class. + */ + const char* (*item_name)(void* ctx); + + /** + * An array of options for the structure or NULL. + * When non-NULL, the array must be terminated by an option with a NULL + * name. + * + * @see av_set_default_options() + */ + const struct AVOption *option; + + /** + * LIBAVUTIL_VERSION with which this structure was created. + * This is used to allow fields to be added to AVClass without requiring + * major version bumps everywhere. + */ + + int version; + + /** + * Offset in the structure where the log level offset is stored. The log + * level offset is an int added to the log level for logging with this + * object as the context. + * + * 0 means there is no such variable. + */ + int log_level_offset_offset; + + /** + * Offset in the structure where a pointer to the parent context for + * logging is stored. For example a decoder could pass its AVCodecContext + * to eval as such a parent context, which an ::av_log() implementation + * could then leverage to display the parent context. + * + * When the pointer is NULL, or this offset is zero, the object is assumed + * to have no parent. + */ + int parent_log_context_offset; + + /** + * Category used for visualization (like color). + * + * Only used when ::get_category() is NULL. Use this field when all + * instances of this class have the same category, use ::get_category() + * otherwise. + */ + AVClassCategory category; + + /** + * Callback to return the instance category. Use this callback when + * different instances of this class may have different categories, + * ::category otherwise. + */ + AVClassCategory (*get_category)(void* ctx); + + /** + * Callback to return the supported/allowed ranges. + */ + int (*query_ranges)(struct AVOptionRanges **, void *obj, const char *key, int flags); + + /** + * Return next AVOptions-enabled child or NULL + */ + void* (*child_next)(void *obj, void *prev); + + /** + * Iterate over the AVClasses corresponding to potential AVOptions-enabled + * children. + * + * @param iter pointer to opaque iteration state. The caller must initialize + * *iter to NULL before the first call. + * @return AVClass for the next AVOptions-enabled child or NULL if there are + * no more such children. + * + * @note The difference between ::child_next() and ::child_class_iterate() + * is that ::child_next() iterates over _actual_ children of an + * _existing_ object instance, while ::child_class_iterate() iterates + * over the classes of all _potential_ children of any possible + * instance of this class. + */ + const struct AVClass* (*child_class_iterate)(void **iter); + + /** + * When non-zero, offset in the object to an unsigned int holding object + * state flags, a combination of AVClassStateFlags values. The flags are + * updated by the object to signal its state to the generic code. + * + * Added in version 59.41.100. + */ + int state_flags_offset; +} AVClass; + +/** + * @addtogroup lavu_log + * + * @{ + * + * @defgroup lavu_log_constants Logging Constants + * + * @{ + */ + +/** + * Print no output. + */ +#define AV_LOG_QUIET -8 + +/** + * Something went really wrong and we will crash now. + */ +#define AV_LOG_PANIC 0 + +/** + * Something went wrong and recovery is not possible. + * For example, no header was found for a format which depends + * on headers or an illegal combination of parameters is used. + */ +#define AV_LOG_FATAL 8 + +/** + * Something went wrong and cannot losslessly be recovered. + * However, not all future data is affected. + */ +#define AV_LOG_ERROR 16 + +/** + * Something somehow does not look correct. This may or may not + * lead to problems. An example would be the use of '-vstrict -2'. + */ +#define AV_LOG_WARNING 24 + +/** + * Standard information. + */ +#define AV_LOG_INFO 32 + +/** + * Detailed information. + */ +#define AV_LOG_VERBOSE 40 + +/** + * Stuff which is only useful for libav* developers. + */ +#define AV_LOG_DEBUG 48 + +/** + * Extremely verbose debugging, useful for libav* development. + */ +#define AV_LOG_TRACE 56 + +#define AV_LOG_MAX_OFFSET (AV_LOG_TRACE - AV_LOG_QUIET) + +/** + * @} + */ + +/** + * Sets additional colors for extended debugging sessions. + * @code + av_log(ctx, AV_LOG_DEBUG|AV_LOG_C(134), "Message in purple\n"); + @endcode + * Requires 256color terminal support. Uses outside debugging is not + * recommended. + */ +#define AV_LOG_C(x) ((x) << 8) + +/** + * Send the specified message to the log if the level is less than or equal + * to the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log_set_callback + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct or NULL if general log. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + */ +void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4); + +/** + * Send the specified message to the log once with the initial_level and then with + * the subsequent_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct or NULL if general log. + * @param initial_level importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant" for the first occurrence. + * @param subsequent_level importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant" after the first occurrence. + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param state a variable to keep trak of if a message has already been printed + * this must be initialized to 0 before the first use. The same state + * must not be accessed by 2 Threads simultaneously. + */ +void av_log_once(void* avcl, int initial_level, int subsequent_level, int *state, const char *fmt, ...) av_printf_format(5, 6); + + +/** + * Send the specified message to the log if the level is less than or equal + * to the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log_set_callback + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_vlog(void *avcl, int level, const char *fmt, va_list vl); + +/** + * Get the current log level + * + * @see lavu_log_constants + * + * @return Current log level + */ +int av_log_get_level(void); + +/** + * Set the log level + * + * @see lavu_log_constants + * + * @param level Logging level + */ +void av_log_set_level(int level); + +/** + * Set the logging callback + * + * @note The callback must be thread safe, even if the application does not use + * threads itself as some codecs are multithreaded. + * + * @see av_log_default_callback + * + * @param callback A logging function with a compatible signature. + */ +void av_log_set_callback(void (*callback)(void*, int, const char*, va_list)); + +/** + * Default logging callback + * + * It prints the message to stderr, optionally colorizing it. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_log_default_callback(void *avcl, int level, const char *fmt, + va_list vl); + +/** + * Return the context name + * + * @param ctx The AVClass context + * + * @return The AVClass class_name + */ +const char* av_default_item_name(void* ctx); +AVClassCategory av_default_get_category(void *ptr); + +/** + * Format a line of log the same way as the default callback. + * @param line buffer to receive the formatted line + * @param line_size size of the buffer + * @param print_prefix used to store whether the prefix must be printed; + * must point to a persistent integer initially set to 1 + */ +void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix); + +/** + * Format a line of log the same way as the default callback. + * @param line buffer to receive the formatted line; + * may be NULL if line_size is 0 + * @param line_size size of the buffer; at most line_size-1 characters will + * be written to the buffer, plus one null terminator + * @param print_prefix used to store whether the prefix must be printed; + * must point to a persistent integer initially set to 1 + * @return Returns a negative value if an error occurred, otherwise returns + * the number of characters that would have been written for a + * sufficiently large buffer, not including the terminating null + * character. If the return value is not less than line_size, it means + * that the log message was truncated to fit the buffer. + */ +int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix); + +/** + * Skip repeated messages, this requires the user app to use av_log() instead of + * (f)printf as the 2 would otherwise interfere and lead to + * "Last message repeated x times" messages below (f)printf messages with some + * bad luck. + * Also to receive the last, "last repeated" line if any, the user app must + * call av_log(NULL, AV_LOG_QUIET, "%s", ""); at the end + */ +#define AV_LOG_SKIP_REPEATED 1 + +/** + * Include the log severity in messages originating from codecs. + * + * Results in messages such as: + * [rawvideo @ 0xDEADBEEF] [error] encode did not produce valid pts + */ +#define AV_LOG_PRINT_LEVEL 2 + +/** + * Include system time in log output. + */ +#define AV_LOG_PRINT_TIME 4 + +/** + * Include system date and time in log output. + */ +#define AV_LOG_PRINT_DATETIME 8 + +void av_log_set_flags(int arg); +int av_log_get_flags(void); + +/** + * @} + */ + +#endif /* AVUTIL_LOG_H */ diff --git a/libs/ffmpeg/libavutil/log2_tab.c b/libs/ffmpeg/libavutil/log2_tab.c new file mode 100644 index 00000000000..0dbf07d74c5 --- /dev/null +++ b/libs/ffmpeg/libavutil/log2_tab.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2003-2012 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdint.h> + +const uint8_t ff_log2_tab[256]={ + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; diff --git a/libs/ffmpeg/libavutil/loongarch/cpu.h b/libs/ffmpeg/libavutil/loongarch/cpu.h new file mode 100644 index 00000000000..1a445c69bcb --- /dev/null +++ b/libs/ffmpeg/libavutil/loongarch/cpu.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020 Loongson Technology Corporation Limited + * Contributed by Shiyou Yin <yinshiyou-hf@loongson.cn> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LOONGARCH_CPU_H +#define AVUTIL_LOONGARCH_CPU_H + +#include "libavutil/cpu.h" +#include "libavutil/cpu_internal.h" + +#define have_lsx(flags) CPUEXT(flags, LSX) +#define have_lasx(flags) CPUEXT(flags, LASX) + +#endif /* AVUTIL_LOONGARCH_CPU_H */ diff --git a/libs/ffmpeg/libavutil/lzo.c b/libs/ffmpeg/libavutil/lzo.c new file mode 100644 index 00000000000..bcbe2c861d7 --- /dev/null +++ b/libs/ffmpeg/libavutil/lzo.c @@ -0,0 +1,207 @@ +/* + * LZO 1x decompression + * Copyright (c) 2006 Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <limits.h> +#include <stdint.h> +#include <string.h> + +#include "avassert.h" +#include "intreadwrite.h" +#include "lzo.h" +#include "macros.h" +#include "mem.h" + +/// Define if we may write up to 12 bytes beyond the output buffer. +#define OUTBUF_PADDED 1 +/// Define if we may read up to 8 bytes beyond the input buffer. +#define INBUF_PADDED 1 + +typedef struct LZOContext { + const uint8_t *in, *in_end; + uint8_t *out_start, *out, *out_end; + int error; +} LZOContext; + +/** + * @brief Reads one byte from the input buffer, avoiding an overrun. + * @return byte read + */ +static inline int get_byte(LZOContext *c) +{ + if (c->in < c->in_end) + return *c->in++; + c->error |= AV_LZO_INPUT_DEPLETED; + return 1; +} + +#ifdef INBUF_PADDED +#define GETB(c) (*(c).in++) +#else +#define GETB(c) get_byte(&(c)) +#endif + +/** + * @brief Decodes a length value in the coding used by lzo. + * @param x previous byte value + * @param mask bits used from x + * @return decoded length value + */ +static inline int get_len(LZOContext *c, int x, int mask) +{ + int cnt = x & mask; + if (!cnt) { + while (!(x = get_byte(c))) { + if (cnt >= INT_MAX - 1000) { + c->error |= AV_LZO_ERROR; + break; + } + cnt += 255; + } + cnt += mask + x; + } + return cnt; +} + +/** + * @brief Copies bytes from input to output buffer with checking. + * @param cnt number of bytes to copy, must be >= 0 + */ +static inline void copy(LZOContext *c, int cnt) +{ + register const uint8_t *src = c->in; + register uint8_t *dst = c->out; + av_assert0(cnt >= 0); + if (cnt > c->in_end - src) { + cnt = FFMAX(c->in_end - src, 0); + c->error |= AV_LZO_INPUT_DEPLETED; + } + if (cnt > c->out_end - dst) { + cnt = FFMAX(c->out_end - dst, 0); + c->error |= AV_LZO_OUTPUT_FULL; + } +#if defined(INBUF_PADDED) && defined(OUTBUF_PADDED) + AV_COPY32U(dst, src); + src += 4; + dst += 4; + cnt -= 4; + if (cnt > 0) +#endif + memcpy(dst, src, cnt); + c->in = src + cnt; + c->out = dst + cnt; +} + +/** + * @brief Copies previously decoded bytes to current position. + * @param back how many bytes back we start, must be > 0 + * @param cnt number of bytes to copy, must be > 0 + * + * cnt > back is valid, this will copy the bytes we just copied, + * thus creating a repeating pattern with a period length of back. + */ +static inline void copy_backptr(LZOContext *c, int back, int cnt) +{ + register uint8_t *dst = c->out; + av_assert0(cnt > 0); + if (dst - c->out_start < back) { + c->error |= AV_LZO_INVALID_BACKPTR; + return; + } + if (cnt > c->out_end - dst) { + cnt = FFMAX(c->out_end - dst, 0); + c->error |= AV_LZO_OUTPUT_FULL; + } + av_memcpy_backptr(dst, back, cnt); + c->out = dst + cnt; +} + +int av_lzo1x_decode(void *out, int *outlen, const void *in, int *inlen) +{ + int state = 0; + int x; + LZOContext c; + if (*outlen <= 0 || *inlen <= 0) { + int res = 0; + if (*outlen <= 0) + res |= AV_LZO_OUTPUT_FULL; + if (*inlen <= 0) + res |= AV_LZO_INPUT_DEPLETED; + return res; + } + c.in = in; + c.in_end = (const uint8_t *)in + *inlen; + c.out = c.out_start = out; + c.out_end = (uint8_t *)out + *outlen; + c.error = 0; + x = GETB(c); + if (x > 17) { + copy(&c, x - 17); + x = GETB(c); + if (x < 16) + c.error |= AV_LZO_ERROR; + } + if (c.in > c.in_end) + c.error |= AV_LZO_INPUT_DEPLETED; + while (!c.error) { + int cnt, back; + if (x > 15) { + if (x > 63) { + cnt = (x >> 5) - 1; + back = (GETB(c) << 3) + ((x >> 2) & 7) + 1; + } else if (x > 31) { + cnt = get_len(&c, x, 31); + x = GETB(c); + back = (GETB(c) << 6) + (x >> 2) + 1; + } else { + cnt = get_len(&c, x, 7); + back = (1 << 14) + ((x & 8) << 11); + x = GETB(c); + back += (GETB(c) << 6) + (x >> 2); + if (back == (1 << 14)) { + if (cnt != 1) + c.error |= AV_LZO_ERROR; + break; + } + } + } else if (!state) { + cnt = get_len(&c, x, 15); + copy(&c, cnt + 3); + x = GETB(c); + if (x > 15) + continue; + cnt = 1; + back = (1 << 11) + (GETB(c) << 2) + (x >> 2) + 1; + } else { + cnt = 0; + back = (GETB(c) << 2) + (x >> 2) + 1; + } + copy_backptr(&c, back, cnt + 2); + state = + cnt = x & 3; + copy(&c, cnt); + x = GETB(c); + } + *inlen = c.in_end - c.in; + if (c.in > c.in_end) + *inlen = 0; + *outlen = c.out_end - c.out; + return c.error; +} diff --git a/libs/ffmpeg/libavutil/lzo.h b/libs/ffmpeg/libavutil/lzo.h new file mode 100644 index 00000000000..c03403992d5 --- /dev/null +++ b/libs/ffmpeg/libavutil/lzo.h @@ -0,0 +1,66 @@ +/* + * LZO 1x decompression + * copyright (c) 2006 Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LZO_H +#define AVUTIL_LZO_H + +/** + * @defgroup lavu_lzo LZO + * @ingroup lavu_crypto + * + * @{ + */ + +#include <stdint.h> + +/** @name Error flags returned by av_lzo1x_decode + * @{ */ +/// end of the input buffer reached before decoding finished +#define AV_LZO_INPUT_DEPLETED 1 +/// decoded data did not fit into output buffer +#define AV_LZO_OUTPUT_FULL 2 +/// a reference to previously decoded data was wrong +#define AV_LZO_INVALID_BACKPTR 4 +/// a non-specific error in the compressed bitstream +#define AV_LZO_ERROR 8 +/** @} */ + +#define AV_LZO_INPUT_PADDING 8 +#define AV_LZO_OUTPUT_PADDING 12 + +/** + * @brief Decodes LZO 1x compressed data. + * @param out output buffer + * @param outlen size of output buffer, number of bytes left are returned here + * @param in input buffer + * @param inlen size of input buffer, number of bytes left are returned here + * @return 0 on success, otherwise a combination of the error flags above + * + * Make sure all buffers are appropriately padded, in must provide + * AV_LZO_INPUT_PADDING, out must provide AV_LZO_OUTPUT_PADDING additional bytes. + */ +int av_lzo1x_decode(void *out, int *outlen, const void *in, int *inlen); + +/** + * @} + */ + +#endif /* AVUTIL_LZO_H */ diff --git a/libs/ffmpeg/libavutil/macros.h b/libs/ffmpeg/libavutil/macros.h new file mode 100644 index 00000000000..2a7567c3ea8 --- /dev/null +++ b/libs/ffmpeg/libavutil/macros.h @@ -0,0 +1,80 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu + * Utility Preprocessor macros + */ + +#ifndef AVUTIL_MACROS_H +#define AVUTIL_MACROS_H + +#include "libavutil/avconfig.h" + +#if AV_HAVE_BIGENDIAN +# define AV_NE(be, le) (be) +#else +# define AV_NE(be, le) (le) +#endif + +/** + * Comparator. + * For two numerical expressions x and y, gives 1 if x > y, -1 if x < y, and 0 + * if x == y. This is useful for instance in a qsort comparator callback. + * Furthermore, compilers are able to optimize this to branchless code, and + * there is no risk of overflow with signed types. + * As with many macros, this evaluates its argument multiple times, it thus + * must not have a side-effect. + */ +#define FFDIFFSIGN(x,y) (((x)>(y)) - ((x)<(y))) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) +#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c) + +#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) +#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) + +#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24)) +#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24)) + +/** + * @addtogroup preproc_misc Preprocessor String Macros + * + * String manipulation macros + * + * @{ + */ + +#define AV_STRINGIFY(s) AV_TOSTRING(s) +#define AV_TOSTRING(s) #s + +#define AV_GLUE(a, b) a ## b +#define AV_JOIN(a, b) AV_GLUE(a, b) + +/** + * @} + */ + +#define AV_PRAGMA(s) _Pragma(#s) + +#define FFALIGN(x, a) (((x)+(a)-1)&~((a)-1)) + +#endif /* AVUTIL_MACROS_H */ diff --git a/libs/ffmpeg/libavutil/mastering_display_metadata.c b/libs/ffmpeg/libavutil/mastering_display_metadata.c new file mode 100644 index 00000000000..dd37ed7d0e1 --- /dev/null +++ b/libs/ffmpeg/libavutil/mastering_display_metadata.c @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2016 Neil Birkbeck <neil.birkbeck@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include "mastering_display_metadata.h" +#include "mem.h" + +static void get_defaults(AVMasteringDisplayMetadata *mastering) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) + mastering->display_primaries[i][j] = (AVRational) { 0, 1 }; + mastering->white_point[0] = + mastering->white_point[1] = + mastering->min_luminance = + mastering->max_luminance = (AVRational) { 0, 1 }; +} + +AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc(void) +{ + return av_mastering_display_metadata_alloc_size(NULL); +} + +AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc_size(size_t *size) +{ + AVMasteringDisplayMetadata *mastering = av_mallocz(sizeof(AVMasteringDisplayMetadata)); + if (!mastering) + return NULL; + + get_defaults(mastering); + + if (size) + *size = sizeof(*mastering); + + return mastering; +} + +AVMasteringDisplayMetadata *av_mastering_display_metadata_create_side_data(AVFrame *frame) +{ + AVFrameSideData *side_data = av_frame_new_side_data(frame, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA, + sizeof(AVMasteringDisplayMetadata)); + if (!side_data) + return NULL; + + memset(side_data->data, 0, sizeof(AVMasteringDisplayMetadata)); + get_defaults((AVMasteringDisplayMetadata *)side_data->data); + + return (AVMasteringDisplayMetadata *)side_data->data; +} + +AVContentLightMetadata *av_content_light_metadata_alloc(size_t *size) +{ + AVContentLightMetadata *metadata = av_mallocz(sizeof(AVContentLightMetadata)); + + if (size) + *size = sizeof(*metadata); + + return metadata; +} + +AVContentLightMetadata *av_content_light_metadata_create_side_data(AVFrame *frame) +{ + AVFrameSideData *side_data = av_frame_new_side_data(frame, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, + sizeof(AVContentLightMetadata)); + if (!side_data) + return NULL; + + memset(side_data->data, 0, sizeof(AVContentLightMetadata)); + + return (AVContentLightMetadata *)side_data->data; +} diff --git a/libs/ffmpeg/libavutil/mastering_display_metadata.h b/libs/ffmpeg/libavutil/mastering_display_metadata.h new file mode 100644 index 00000000000..52fcef9e371 --- /dev/null +++ b/libs/ffmpeg/libavutil/mastering_display_metadata.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2016 Neil Birkbeck <neil.birkbeck@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MASTERING_DISPLAY_METADATA_H +#define AVUTIL_MASTERING_DISPLAY_METADATA_H + +#include "frame.h" +#include "rational.h" + + +/** + * Mastering display metadata capable of representing the color volume of + * the display used to master the content (SMPTE 2086:2014). + * + * To be used as payload of a AVFrameSideData or AVPacketSideData with the + * appropriate type. + * + * @note The struct should be allocated with av_mastering_display_metadata_alloc() + * and its size is not a part of the public ABI. + */ +typedef struct AVMasteringDisplayMetadata { + /** + * CIE 1931 xy chromaticity coords of color primaries (r, g, b order). + */ + AVRational display_primaries[3][2]; + + /** + * CIE 1931 xy chromaticity coords of white point. + */ + AVRational white_point[2]; + + /** + * Min luminance of mastering display (cd/m^2). + */ + AVRational min_luminance; + + /** + * Max luminance of mastering display (cd/m^2). + */ + AVRational max_luminance; + + /** + * Flag indicating whether the display primaries (and white point) are set. + */ + int has_primaries; + + /** + * Flag indicating whether the luminance (min_ and max_) have been set. + */ + int has_luminance; + +} AVMasteringDisplayMetadata; + +/** + * Allocate an AVMasteringDisplayMetadata structure and set its fields to + * default values. The resulting struct can be freed using av_freep(). + * + * @return An AVMasteringDisplayMetadata filled with default values or NULL + * on failure. + */ +AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc(void); + +/** + * Allocate an AVMasteringDisplayMetadata structure and set its fields to + * default values. The resulting struct can be freed using av_freep(). + * + * @return An AVMasteringDisplayMetadata filled with default values or NULL + * on failure. + */ +AVMasteringDisplayMetadata *av_mastering_display_metadata_alloc_size(size_t *size); + +/** + * Allocate a complete AVMasteringDisplayMetadata and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVMasteringDisplayMetadata structure to be filled by caller. + */ +AVMasteringDisplayMetadata *av_mastering_display_metadata_create_side_data(AVFrame *frame); + +/** + * Content light level needed by to transmit HDR over HDMI (CTA-861.3). + * + * To be used as payload of a AVFrameSideData or AVPacketSideData with the + * appropriate type. + * + * @note The struct should be allocated with av_content_light_metadata_alloc() + * and its size is not a part of the public ABI. + */ +typedef struct AVContentLightMetadata { + /** + * Max content light level (cd/m^2). + */ + unsigned MaxCLL; + + /** + * Max average light level per frame (cd/m^2). + */ + unsigned MaxFALL; +} AVContentLightMetadata; + +/** + * Allocate an AVContentLightMetadata structure and set its fields to + * default values. The resulting struct can be freed using av_freep(). + * + * @return An AVContentLightMetadata filled with default values or NULL + * on failure. + */ +AVContentLightMetadata *av_content_light_metadata_alloc(size_t *size); + +/** + * Allocate a complete AVContentLightMetadata and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVContentLightMetadata structure to be filled by caller. + */ +AVContentLightMetadata *av_content_light_metadata_create_side_data(AVFrame *frame); + +#endif /* AVUTIL_MASTERING_DISPLAY_METADATA_H */ diff --git a/libs/ffmpeg/libavutil/mathematics.c b/libs/ffmpeg/libavutil/mathematics.c new file mode 100644 index 00000000000..61aeb7c0292 --- /dev/null +++ b/libs/ffmpeg/libavutil/mathematics.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2005-2012 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * miscellaneous math routines and tables + */ + +#include <stdint.h> +#include <limits.h> + +#include "avutil.h" +#include "mathematics.h" +#include "libavutil/intmath.h" +#include "libavutil/common.h" +#include "avassert.h" + +/* Stein's binary GCD algorithm: + * https://en.wikipedia.org/wiki/Binary_GCD_algorithm */ +int64_t av_gcd(int64_t a, int64_t b) { + int za, zb, k; + int64_t u, v; + if (a == 0) + return b; + if (b == 0) + return a; + za = ff_ctzll(a); + zb = ff_ctzll(b); + k = FFMIN(za, zb); + u = llabs(a >> za); + v = llabs(b >> zb); + while (u != v) { + if (u > v) + FFSWAP(int64_t, v, u); + v -= u; + v >>= ff_ctzll(v); + } + return (uint64_t)u << k; +} + +int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd) +{ + int64_t r = 0; + av_assert2(c > 0); + av_assert2(b >=0); + av_assert2((unsigned)(rnd&~AV_ROUND_PASS_MINMAX)<=5 && (rnd&~AV_ROUND_PASS_MINMAX)!=4); + + if (c <= 0 || b < 0 || !((unsigned)(rnd&~AV_ROUND_PASS_MINMAX)<=5 && (rnd&~AV_ROUND_PASS_MINMAX)!=4)) + return INT64_MIN; + + if (rnd & AV_ROUND_PASS_MINMAX) { + if (a == INT64_MIN || a == INT64_MAX) + return a; + rnd -= AV_ROUND_PASS_MINMAX; + } + + if (a < 0) + return -(uint64_t)av_rescale_rnd(-FFMAX(a, -INT64_MAX), b, c, rnd ^ ((rnd >> 1) & 1)); + + if (rnd == AV_ROUND_NEAR_INF) + r = c / 2; + else if (rnd & 1) + r = c - 1; + + if (b <= INT_MAX && c <= INT_MAX) { + if (a <= INT_MAX) + return (a * b + r) / c; + else { + int64_t ad = a / c; + int64_t a2 = (a % c * b + r) / c; + if (ad >= INT32_MAX && b && ad > (INT64_MAX - a2) / b) + return INT64_MIN; + return ad * b + a2; + } + } else { +#if 1 + uint64_t a0 = a & 0xFFFFFFFF; + uint64_t a1 = a >> 32; + uint64_t b0 = b & 0xFFFFFFFF; + uint64_t b1 = b >> 32; + uint64_t t1 = a0 * b1 + a1 * b0; + uint64_t t1a = t1 << 32; + int i; + + a0 = a0 * b0 + t1a; + a1 = a1 * b1 + (t1 >> 32) + (a0 < t1a); + a0 += r; + a1 += a0 < r; + + for (i = 63; i >= 0; i--) { + a1 += a1 + ((a0 >> i) & 1); + t1 += t1; + if (c <= a1) { + a1 -= c; + t1++; + } + } + if (t1 > INT64_MAX) + return INT64_MIN; + return t1; +#else + /* reference code doing (a*b + r) / c, requires libavutil/integer.h */ + AVInteger ai; + ai = av_mul_i(av_int2i(a), av_int2i(b)); + ai = av_add_i(ai, av_int2i(r)); + + return av_i2int(av_div_i(ai, av_int2i(c))); +#endif + } +} + +int64_t av_rescale(int64_t a, int64_t b, int64_t c) +{ + return av_rescale_rnd(a, b, c, AV_ROUND_NEAR_INF); +} + +int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, + enum AVRounding rnd) +{ + int64_t b = bq.num * (int64_t)cq.den; + int64_t c = cq.num * (int64_t)bq.den; + return av_rescale_rnd(a, b, c, rnd); +} + +int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) +{ + return av_rescale_q_rnd(a, bq, cq, AV_ROUND_NEAR_INF); +} + +int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b) +{ + int64_t a = tb_a.num * (int64_t)tb_b.den; + int64_t b = tb_b.num * (int64_t)tb_a.den; + if ((FFABS64U(ts_a)|a|FFABS64U(ts_b)|b) <= INT_MAX) + return (ts_a*a > ts_b*b) - (ts_a*a < ts_b*b); + if (av_rescale_rnd(ts_a, a, b, AV_ROUND_DOWN) < ts_b) + return -1; + if (av_rescale_rnd(ts_b, b, a, AV_ROUND_DOWN) < ts_a) + return 1; + return 0; +} + +int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod) +{ + int64_t c = (a - b) & (mod - 1); + if (c > (mod >> 1)) + c -= mod; + return c; +} + +int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb){ + int64_t a, b, this; + + av_assert0(in_ts != AV_NOPTS_VALUE); + av_assert0(duration >= 0); + + if (*last == AV_NOPTS_VALUE || !duration || in_tb.num*(int64_t)out_tb.den <= out_tb.num*(int64_t)in_tb.den) { +simple_round: + *last = av_rescale_q(in_ts, in_tb, fs_tb) + duration; + return av_rescale_q(in_ts, in_tb, out_tb); + } + + a = av_rescale_q_rnd(2*in_ts-1, in_tb, fs_tb, AV_ROUND_DOWN) >>1; + b = (av_rescale_q_rnd(2*in_ts+1, in_tb, fs_tb, AV_ROUND_UP )+1)>>1; + if (*last < 2*a - b || *last > 2*b - a) + goto simple_round; + + this = av_clip64(*last, a, b); + *last = this + duration; + + return av_rescale_q(this, fs_tb, out_tb); +} + +int64_t av_add_stable(AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc) +{ + int64_t m, d; + + if (inc != 1) + inc_tb = av_mul_q(inc_tb, (AVRational) {inc, 1}); + + m = inc_tb.num * (int64_t)ts_tb.den; + d = inc_tb.den * (int64_t)ts_tb.num; + + if (m % d == 0 && ts <= INT64_MAX - m / d) + return ts + m / d; + if (m < d) + return ts; + + { + int64_t old = av_rescale_q(ts, ts_tb, inc_tb); + int64_t old_ts = av_rescale_q(old, inc_tb, ts_tb); + + if (old == INT64_MAX || old == AV_NOPTS_VALUE || old_ts == AV_NOPTS_VALUE) + return ts; + + return av_sat_add64(av_rescale_q(old + 1, inc_tb, ts_tb), ts - old_ts); + } +} + +static inline double eval_poly(const double *coeff, int size, double x) { + double sum = coeff[size-1]; + int i; + for (i = size-2; i >= 0; --i) { + sum *= x; + sum += coeff[i]; + } + return sum; +} + +/** + * 0th order modified bessel function of the first kind. + * Algorithm taken from the Boost project, source: + * https://searchcode.com/codesearch/view/14918379/ + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0 (see notice below). + * Boost Software License - Version 1.0 - August 17th, 2003 +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + */ + +double av_bessel_i0(double x) { +// Modified Bessel function of the first kind of order zero +// minimax rational approximations on intervals, see +// Blair and Edwards, Chalk River Report AECL-4928, 1974 + static const double p1[] = { + -2.2335582639474375249e+15, + -5.5050369673018427753e+14, + -3.2940087627407749166e+13, + -8.4925101247114157499e+11, + -1.1912746104985237192e+10, + -1.0313066708737980747e+08, + -5.9545626019847898221e+05, + -2.4125195876041896775e+03, + -7.0935347449210549190e+00, + -1.5453977791786851041e-02, + -2.5172644670688975051e-05, + -3.0517226450451067446e-08, + -2.6843448573468483278e-11, + -1.5982226675653184646e-14, + -5.2487866627945699800e-18, + }; + static const double q1[] = { + -2.2335582639474375245e+15, + 7.8858692566751002988e+12, + -1.2207067397808979846e+10, + 1.0377081058062166144e+07, + -4.8527560179962773045e+03, + 1.0, + }; + static const double p2[] = { + -2.2210262233306573296e-04, + 1.3067392038106924055e-02, + -4.4700805721174453923e-01, + 5.5674518371240761397e+00, + -2.3517945679239481621e+01, + 3.1611322818701131207e+01, + -9.6090021968656180000e+00, + }; + static const double q2[] = { + -5.5194330231005480228e-04, + 3.2547697594819615062e-02, + -1.1151759188741312645e+00, + 1.3982595353892851542e+01, + -6.0228002066743340583e+01, + 8.5539563258012929600e+01, + -3.1446690275135491500e+01, + 1.0, + }; + double y, r, factor; + if (x == 0) + return 1.0; + x = fabs(x); + if (x <= 15) { + y = x * x; + return eval_poly(p1, FF_ARRAY_ELEMS(p1), y) / eval_poly(q1, FF_ARRAY_ELEMS(q1), y); + } + else { + y = 1 / x - 1.0 / 15; + r = eval_poly(p2, FF_ARRAY_ELEMS(p2), y) / eval_poly(q2, FF_ARRAY_ELEMS(q2), y); + factor = exp(x) / sqrt(x); + return factor * r; + } +} diff --git a/libs/ffmpeg/libavutil/mathematics.h b/libs/ffmpeg/libavutil/mathematics.h new file mode 100644 index 00000000000..486de530f2e --- /dev/null +++ b/libs/ffmpeg/libavutil/mathematics.h @@ -0,0 +1,300 @@ +/* + * copyright (c) 2005-2012 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @addtogroup lavu_math + * Mathematical utilities for working with timestamp and time base. + */ + +#ifndef AVUTIL_MATHEMATICS_H +#define AVUTIL_MATHEMATICS_H + +#include <stdint.h> +#include <math.h> +#include "attributes.h" +#include "rational.h" +#include "intfloat.h" + +#ifndef M_E +#define M_E 2.7182818284590452354 /* e */ +#endif +#ifndef M_Ef +#define M_Ef 2.7182818284590452354f /* e */ +#endif +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 /* log_e 2 */ +#endif +#ifndef M_LN2f +#define M_LN2f 0.69314718055994530942f /* log_e 2 */ +#endif +#ifndef M_LN10 +#define M_LN10 2.30258509299404568402 /* log_e 10 */ +#endif +#ifndef M_LN10f +#define M_LN10f 2.30258509299404568402f /* log_e 10 */ +#endif +#ifndef M_LOG2_10 +#define M_LOG2_10 3.32192809488736234787 /* log_2 10 */ +#endif +#ifndef M_LOG2_10f +#define M_LOG2_10f 3.32192809488736234787f /* log_2 10 */ +#endif +#ifndef M_PHI +#define M_PHI 1.61803398874989484820 /* phi / golden ratio */ +#endif +#ifndef M_PHIf +#define M_PHIf 1.61803398874989484820f /* phi / golden ratio */ +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif +#ifndef M_PIf +#define M_PIf 3.14159265358979323846f /* pi */ +#endif +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#endif +#ifndef M_PI_2f +#define M_PI_2f 1.57079632679489661923f /* pi/2 */ +#endif +#ifndef M_PI_4 +#define M_PI_4 0.78539816339744830962 /* pi/4 */ +#endif +#ifndef M_PI_4f +#define M_PI_4f 0.78539816339744830962f /* pi/4 */ +#endif +#ifndef M_1_PI +#define M_1_PI 0.31830988618379067154 /* 1/pi */ +#endif +#ifndef M_1_PIf +#define M_1_PIf 0.31830988618379067154f /* 1/pi */ +#endif +#ifndef M_2_PI +#define M_2_PI 0.63661977236758134308 /* 2/pi */ +#endif +#ifndef M_2_PIf +#define M_2_PIf 0.63661977236758134308f /* 2/pi */ +#endif +#ifndef M_2_SQRTPI +#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ +#endif +#ifndef M_2_SQRTPIf +#define M_2_SQRTPIf 1.12837916709551257390f /* 2/sqrt(pi) */ +#endif +#ifndef M_SQRT1_2 +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ +#endif +#ifndef M_SQRT1_2f +#define M_SQRT1_2f 0.70710678118654752440f /* 1/sqrt(2) */ +#endif +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#endif +#ifndef M_SQRT2f +#define M_SQRT2f 1.41421356237309504880f /* sqrt(2) */ +#endif +#ifndef NAN +#define NAN av_int2float(0x7fc00000) +#endif +#ifndef INFINITY +#define INFINITY av_int2float(0x7f800000) +#endif + +/** + * @addtogroup lavu_math + * + * @{ + */ + +/** + * Rounding methods. + */ +enum AVRounding { + AV_ROUND_ZERO = 0, ///< Round toward zero. + AV_ROUND_INF = 1, ///< Round away from zero. + AV_ROUND_DOWN = 2, ///< Round toward -infinity. + AV_ROUND_UP = 3, ///< Round toward +infinity. + AV_ROUND_NEAR_INF = 5, ///< Round to nearest and halfway cases away from zero. + /** + * Flag telling rescaling functions to pass `INT64_MIN`/`MAX` through + * unchanged, avoiding special cases for #AV_NOPTS_VALUE. + * + * Unlike other values of the enumeration AVRounding, this value is a + * bitmask that must be used in conjunction with another value of the + * enumeration through a bitwise OR, in order to set behavior for normal + * cases. + * + * @code{.c} + * av_rescale_rnd(3, 1, 2, AV_ROUND_UP | AV_ROUND_PASS_MINMAX); + * // Rescaling 3: + * // Calculating 3 * 1 / 2 + * // 3 / 2 is rounded up to 2 + * // => 2 + * + * av_rescale_rnd(AV_NOPTS_VALUE, 1, 2, AV_ROUND_UP | AV_ROUND_PASS_MINMAX); + * // Rescaling AV_NOPTS_VALUE: + * // AV_NOPTS_VALUE == INT64_MIN + * // AV_NOPTS_VALUE is passed through + * // => AV_NOPTS_VALUE + * @endcode + */ + AV_ROUND_PASS_MINMAX = 8192, +}; + +/** + * Compute the greatest common divisor of two integer operands. + * + * @param a Operand + * @param b Operand + * @return GCD of a and b up to sign; if a >= 0 and b >= 0, return value is >= 0; + * if a == 0 and b == 0, returns 0. + */ +int64_t av_const av_gcd(int64_t a, int64_t b); + +/** + * Rescale a 64-bit integer with rounding to nearest. + * + * The operation is mathematically equivalent to `a * b / c`, but writing that + * directly can overflow. + * + * This function is equivalent to av_rescale_rnd() with #AV_ROUND_NEAR_INF. + * + * @see av_rescale_rnd(), av_rescale_q(), av_rescale_q_rnd() + */ +int64_t av_rescale(int64_t a, int64_t b, int64_t c) av_const; + +/** + * Rescale a 64-bit integer with specified rounding. + * + * The operation is mathematically equivalent to `a * b / c`, but writing that + * directly can overflow, and does not support different rounding methods. + * If the result is not representable then INT64_MIN is returned. + * + * @see av_rescale(), av_rescale_q(), av_rescale_q_rnd() + */ +int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding rnd) av_const; + +/** + * Rescale a 64-bit integer by 2 rational numbers. + * + * The operation is mathematically equivalent to `a * bq / cq`. + * + * This function is equivalent to av_rescale_q_rnd() with #AV_ROUND_NEAR_INF. + * + * @see av_rescale(), av_rescale_rnd(), av_rescale_q_rnd() + */ +int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const; + +/** + * Rescale a 64-bit integer by 2 rational numbers with specified rounding. + * + * The operation is mathematically equivalent to `a * bq / cq`. + * + * @see av_rescale(), av_rescale_rnd(), av_rescale_q() + */ +int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, + enum AVRounding rnd) av_const; + +/** + * Compare two timestamps each in its own time base. + * + * @return One of the following values: + * - -1 if `ts_a` is before `ts_b` + * - 1 if `ts_a` is after `ts_b` + * - 0 if they represent the same position + * + * @warning + * The result of the function is undefined if one of the timestamps is outside + * the `int64_t` range when represented in the other's timebase. + */ +int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b); + +/** + * Compare the remainders of two integer operands divided by a common divisor. + * + * In other words, compare the least significant `log2(mod)` bits of integers + * `a` and `b`. + * + * @code{.c} + * av_compare_mod(0x11, 0x02, 0x10) < 0 // since 0x11 % 0x10 (0x1) < 0x02 % 0x10 (0x2) + * av_compare_mod(0x11, 0x02, 0x20) > 0 // since 0x11 % 0x20 (0x11) > 0x02 % 0x20 (0x02) + * @endcode + * + * @param a Operand + * @param b Operand + * @param mod Divisor; must be a power of 2 + * @return + * - a negative value if `a % mod < b % mod` + * - a positive value if `a % mod > b % mod` + * - zero if `a % mod == b % mod` + */ +int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod); + +/** + * Rescale a timestamp while preserving known durations. + * + * This function is designed to be called per audio packet to scale the input + * timestamp to a different time base. Compared to a simple av_rescale_q() + * call, this function is robust against possible inconsistent frame durations. + * + * The `last` parameter is a state variable that must be preserved for all + * subsequent calls for the same stream. For the first call, `*last` should be + * initialized to #AV_NOPTS_VALUE. + * + * @param[in] in_tb Input time base + * @param[in] in_ts Input timestamp + * @param[in] fs_tb Duration time base; typically this is finer-grained + * (greater) than `in_tb` and `out_tb` + * @param[in] duration Duration till the next call to this function (i.e. + * duration of the current packet/frame) + * @param[in,out] last Pointer to a timestamp expressed in terms of + * `fs_tb`, acting as a state variable + * @param[in] out_tb Output timebase + * @return Timestamp expressed in terms of `out_tb` + * + * @note In the context of this function, "duration" is in term of samples, not + * seconds. + */ +int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb); + +/** + * Add a value to a timestamp. + * + * This function guarantees that when the same value is repeatedly added that + * no accumulation of rounding errors occurs. + * + * @param[in] ts Input timestamp + * @param[in] ts_tb Input timestamp time base + * @param[in] inc Value to be added + * @param[in] inc_tb Time base of `inc` + */ +int64_t av_add_stable(AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc); + +/** + * 0th order modified bessel function of the first kind. + */ +double av_bessel_i0(double x); + +/** + * @} + */ + +#endif /* AVUTIL_MATHEMATICS_H */ diff --git a/libs/ffmpeg/libavutil/md5.c b/libs/ffmpeg/libavutil/md5.c new file mode 100644 index 00000000000..c01820da2df --- /dev/null +++ b/libs/ffmpeg/libavutil/md5.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2006 Michael Niedermayer (michaelni@gmx.at) + * Copyright (C) 2003-2005 by Christopher R. Hertel (crh@ubiqx.mn.org) + * + * References: + * IETF RFC 1321: The MD5 Message-Digest Algorithm + * Ron Rivest. IETF, April, 1992 + * + * based on http://ubiqx.org/libcifs/source/Auth/MD5.c + * from Christopher R. Hertel (crh@ubiqx.mn.org) + * Simplified, cleaned and IMO redundant comments removed by Michael. + * + * If you use gcc, then version 4.1 or later and -fomit-frame-pointer is + * strongly recommended. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdint.h> +#include <string.h> + +#include "bswap.h" +#include "intreadwrite.h" +#include "macros.h" +#include "mem.h" +#include "md5.h" + +typedef struct AVMD5 { + uint64_t len; + uint8_t block[64]; + uint32_t ABCD[4]; +} AVMD5; + +const int av_md5_size = sizeof(AVMD5); + +struct AVMD5 *av_md5_alloc(void) +{ + return av_mallocz(sizeof(struct AVMD5)); +} + +static const uint8_t S[4][4] = { + { 7, 12, 17, 22 }, /* round 1 */ + { 5, 9, 14, 20 }, /* round 2 */ + { 4, 11, 16, 23 }, /* round 3 */ + { 6, 10, 15, 21 } /* round 4 */ +}; + +static const uint32_t T[64] = { // T[i]= fabs(sin(i+1)<<32) + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* round 1 */ + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* round 2 */ + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, /* round 3 */ + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, /* round 4 */ + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, +}; + +#define CORE(i, a, b, c, d) \ + do { \ + t = S[i >> 4][i & 3]; \ + a += T[i]; \ + \ + if (i < 32) { \ + if (i < 16) \ + a += (d ^ (b & (c ^ d))) + AV_RL32(X+( i & 15));\ + else \ + a += ((d & b) | (~d & c)) + AV_RL32(X+((1 + 5*i) & 15));\ + } else { \ + if (i < 48) \ + a += (b ^ c ^ d) + AV_RL32(X+((5 + 3*i) & 15));\ + else \ + a += (c ^ (b | ~d)) + AV_RL32(X+(( 7*i) & 15));\ + } \ + a = b + (a << t | a >> (32 - t)); \ + } while (0) + +static void body(uint32_t ABCD[4], const uint8_t *src, size_t nblocks) +{ + const uint32_t *X; + uint32_t a, b, c, d, t; + + for (size_t n = 0; n < nblocks; n++) { + a = ABCD[3]; + b = ABCD[2]; + c = ABCD[1]; + d = ABCD[0]; + + X = (const uint32_t *)src + n * 16; + +#if CONFIG_SMALL + for (int i = 0; i < 64; i++) { + CORE(i, a, b, c, d); + t = d; + d = c; + c = b; + b = a; + a = t; + } +#else +#define CORE2(i) \ + CORE(i, a, b, c, d); CORE((i + 1), d, a, b, c); \ + CORE((i + 2), c, d, a, b); CORE((i + 3), b, c, d, a) +#define CORE4(i) CORE2(i); CORE2((i + 4)); CORE2((i + 8)); CORE2((i + 12)) + CORE4(0); + CORE4(16); + CORE4(32); + CORE4(48); +#endif + + ABCD[0] += d; + ABCD[1] += c; + ABCD[2] += b; + ABCD[3] += a; + } +} + +void av_md5_init(AVMD5 *ctx) +{ + ctx->len = 0; + + ctx->ABCD[0] = 0x10325476; + ctx->ABCD[1] = 0x98badcfe; + ctx->ABCD[2] = 0xefcdab89; + ctx->ABCD[3] = 0x67452301; +} + +void av_md5_update(AVMD5 *ctx, const uint8_t *src, size_t len) +{ + const uint8_t *end; + int j; + + j = ctx->len & 63; + ctx->len += len; + + if (j) { + int cnt = FFMIN(len, 64 - j); + memcpy(ctx->block + j, src, cnt); + src += cnt; + len -= cnt; + if (j + cnt < 64) + return; + body(ctx->ABCD, ctx->block, 1); + } + + end = src + (len & ~63); + if (!HAVE_FAST_UNALIGNED && ((intptr_t)src & 3)) { + while (src < end) { + memcpy(ctx->block, src, 64); + body(ctx->ABCD, ctx->block, 1); + src += 64; + } + } else { + size_t nblocks = len / 64; + body(ctx->ABCD, src, nblocks); + src = end; + } + len &= 63; + if (len > 0) + memcpy(ctx->block, src, len); +} + +void av_md5_final(AVMD5 *ctx, uint8_t *dst) +{ + int i; + uint64_t finalcount = av_le2ne64(ctx->len << 3); + + av_md5_update(ctx, "\200", 1); + while ((ctx->len & 63) != 56) + av_md5_update(ctx, "", 1); + + av_md5_update(ctx, (uint8_t *) &finalcount, 8); + + for (i = 0; i < 4; i++) + AV_WL32(dst + 4 * i, ctx->ABCD[3 - i]); +} + +void av_md5_sum(uint8_t *dst, const uint8_t *src, size_t len) +{ + AVMD5 ctx; + + av_md5_init(&ctx); + av_md5_update(&ctx, src, len); + av_md5_final(&ctx, dst); +} diff --git a/libs/ffmpeg/libavutil/md5.h b/libs/ffmpeg/libavutil/md5.h new file mode 100644 index 00000000000..fc2eabdb162 --- /dev/null +++ b/libs/ffmpeg/libavutil/md5.h @@ -0,0 +1,89 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_md5 + * Public header for MD5 hash function implementation. + */ + +#ifndef AVUTIL_MD5_H +#define AVUTIL_MD5_H + +#include <stddef.h> +#include <stdint.h> + +#include "attributes.h" + +/** + * @defgroup lavu_md5 MD5 + * @ingroup lavu_hash + * MD5 hash function implementation. + * + * @{ + */ + +extern const int av_md5_size; + +struct AVMD5; + +/** + * Allocate an AVMD5 context. + */ +struct AVMD5 *av_md5_alloc(void); + +/** + * Initialize MD5 hashing. + * + * @param ctx pointer to the function context (of size av_md5_size) + */ +void av_md5_init(struct AVMD5 *ctx); + +/** + * Update hash value. + * + * @param ctx hash function context + * @param src input data to update hash with + * @param len input data length + */ +void av_md5_update(struct AVMD5 *ctx, const uint8_t *src, size_t len); + +/** + * Finish hashing and output digest value. + * + * @param ctx hash function context + * @param dst buffer where output digest value is stored + */ +void av_md5_final(struct AVMD5 *ctx, uint8_t *dst); + +/** + * Hash an array of data. + * + * @param dst The output buffer to write the digest into + * @param src The data to hash + * @param len The length of the data, in bytes + */ +void av_md5_sum(uint8_t *dst, const uint8_t *src, size_t len); + +/** + * @} + */ + +#endif /* AVUTIL_MD5_H */ diff --git a/libs/ffmpeg/libavutil/mem.c b/libs/ffmpeg/libavutil/mem.c new file mode 100644 index 00000000000..b205d3fb256 --- /dev/null +++ b/libs/ffmpeg/libavutil/mem.c @@ -0,0 +1,570 @@ +/* + * default memory allocator for libavutil + * Copyright (c) 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * default memory allocator for libavutil + */ + +#define _XOPEN_SOURCE 600 + +#include "config.h" + +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdatomic.h> +#include <string.h> +#if HAVE_MALLOC_H +#include <malloc.h> +#endif + +#include "attributes.h" +#include "avassert.h" +#include "dynarray.h" +#include "error.h" +#include "internal.h" +#include "intreadwrite.h" +#include "macros.h" +#include "mem.h" + +#ifdef MALLOC_PREFIX + +#define malloc AV_JOIN(MALLOC_PREFIX, malloc) +#define memalign AV_JOIN(MALLOC_PREFIX, memalign) +#define posix_memalign AV_JOIN(MALLOC_PREFIX, posix_memalign) +#define realloc AV_JOIN(MALLOC_PREFIX, realloc) +#define free AV_JOIN(MALLOC_PREFIX, free) + +void *malloc(size_t size); +void *memalign(size_t align, size_t size); +int posix_memalign(void **ptr, size_t align, size_t size); +void *realloc(void *ptr, size_t size); +void free(void *ptr); + +#endif /* MALLOC_PREFIX */ + +#define ALIGN (HAVE_SIMD_ALIGN_64 ? 64 : (HAVE_SIMD_ALIGN_32 ? 32 : 16)) + +#define FF_MEMORY_POISON 0x2a + +/* NOTE: if you want to override these functions with your own + * implementations (not recommended) you have to link libav* as + * dynamic libraries and remove -Wl,-Bsymbolic from the linker flags. + * Note that this will cost performance. */ + +static atomic_size_t max_alloc_size = INT_MAX; + +void av_max_alloc(size_t max){ + atomic_store_explicit(&max_alloc_size, max, memory_order_relaxed); +} + +static int size_mult(size_t a, size_t b, size_t *r) +{ + size_t t; + +#if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_mul_overflow) + if (__builtin_mul_overflow(a, b, &t)) + return AVERROR(EINVAL); +#else + t = a * b; + /* Hack inspired from glibc: don't try the division if nelem and elsize + * are both less than sqrt(SIZE_MAX). */ + if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b) + return AVERROR(EINVAL); +#endif + *r = t; + return 0; +} + +void *av_malloc(size_t size) +{ + void *ptr = NULL; + + if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed)) + return NULL; + +#if HAVE_POSIX_MEMALIGN + if (size) //OS X on SDK 10.6 has a broken posix_memalign implementation + if (posix_memalign(&ptr, ALIGN, size)) + ptr = NULL; +#elif HAVE_ALIGNED_MALLOC + ptr = _aligned_malloc(size, ALIGN); +#elif HAVE_MEMALIGN +#ifndef __DJGPP__ + ptr = memalign(ALIGN, size); +#else + ptr = memalign(size, ALIGN); +#endif + /* Why 64? + * Indeed, we should align it: + * on 4 for 386 + * on 16 for 486 + * on 32 for 586, PPro - K6-III + * on 64 for K7 (maybe for P3 too). + * Because L1 and L2 caches are aligned on those values. + * But I don't want to code such logic here! + */ + /* Why 32? + * For AVX ASM. SSE / NEON needs only 16. + * Why not larger? Because I did not see a difference in benchmarks ... + */ + /* benchmarks with P3 + * memalign(64) + 1 3071, 3051, 3032 + * memalign(64) + 2 3051, 3032, 3041 + * memalign(64) + 4 2911, 2896, 2915 + * memalign(64) + 8 2545, 2554, 2550 + * memalign(64) + 16 2543, 2572, 2563 + * memalign(64) + 32 2546, 2545, 2571 + * memalign(64) + 64 2570, 2533, 2558 + * + * BTW, malloc seems to do 8-byte alignment by default here. + */ +#else + ptr = malloc(size); +#endif + if(!ptr && !size) { + size = 1; + ptr= av_malloc(1); + } +#if CONFIG_MEMORY_POISONING + if (ptr) + memset(ptr, FF_MEMORY_POISON, size); +#endif + return ptr; +} + +void *av_realloc(void *ptr, size_t size) +{ + void *ret; + if (size > atomic_load_explicit(&max_alloc_size, memory_order_relaxed)) + return NULL; + +#if HAVE_ALIGNED_MALLOC + ret = _aligned_realloc(ptr, size + !size, ALIGN); +#else + ret = realloc(ptr, size + !size); +#endif +#if CONFIG_MEMORY_POISONING + if (ret && !ptr) + memset(ret, FF_MEMORY_POISON, size); +#endif + return ret; +} + +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize) +{ + size_t size; + void *r; + + if (size_mult(elsize, nelem, &size)) { + av_free(ptr); + return NULL; + } + r = av_realloc(ptr, size); + if (!r) + av_free(ptr); + return r; +} + +int av_reallocp(void *ptr, size_t size) +{ + void *val; + + if (!size) { + av_freep(ptr); + return 0; + } + + memcpy(&val, ptr, sizeof(val)); + val = av_realloc(val, size); + + if (!val) { + av_freep(ptr); + return AVERROR(ENOMEM); + } + + memcpy(ptr, &val, sizeof(val)); + return 0; +} + +void *av_malloc_array(size_t nmemb, size_t size) +{ + size_t result; + if (size_mult(nmemb, size, &result) < 0) + return NULL; + return av_malloc(result); +} + +void *av_realloc_array(void *ptr, size_t nmemb, size_t size) +{ + size_t result; + if (size_mult(nmemb, size, &result) < 0) + return NULL; + return av_realloc(ptr, result); +} + +int av_reallocp_array(void *ptr, size_t nmemb, size_t size) +{ + void *val; + + memcpy(&val, ptr, sizeof(val)); + val = av_realloc_f(val, nmemb, size); + memcpy(ptr, &val, sizeof(val)); + if (!val && nmemb && size) + return AVERROR(ENOMEM); + + return 0; +} + +void av_free(void *ptr) +{ +#if HAVE_ALIGNED_MALLOC + _aligned_free(ptr); +#else + free(ptr); +#endif +} + +void av_freep(void *arg) +{ + void *val; + + memcpy(&val, arg, sizeof(val)); + memcpy(arg, &(void *){ NULL }, sizeof(val)); + av_free(val); +} + +void *av_mallocz(size_t size) +{ + void *ptr = av_malloc(size); + if (ptr) + memset(ptr, 0, size); + return ptr; +} + +void *av_calloc(size_t nmemb, size_t size) +{ + size_t result; + if (size_mult(nmemb, size, &result) < 0) + return NULL; + return av_mallocz(result); +} + +char *av_strdup(const char *s) +{ + char *ptr = NULL; + if (s) { + size_t len = strlen(s) + 1; + ptr = av_realloc(NULL, len); + if (ptr) + memcpy(ptr, s, len); + } + return ptr; +} + +char *av_strndup(const char *s, size_t len) +{ + char *ret = NULL, *end; + + if (!s) + return NULL; + + end = memchr(s, 0, len); + if (end) + len = end - s; + + ret = av_realloc(NULL, len + 1); + if (!ret) + return NULL; + + memcpy(ret, s, len); + ret[len] = 0; + return ret; +} + +void *av_memdup(const void *p, size_t size) +{ + void *ptr = NULL; + if (p) { + ptr = av_malloc(size); + if (ptr) + memcpy(ptr, p, size); + } + return ptr; +} + +int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem) +{ + void **tab; + memcpy(&tab, tab_ptr, sizeof(tab)); + + FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, { + tab[*nb_ptr] = elem; + memcpy(tab_ptr, &tab, sizeof(tab)); + }, { + return AVERROR(ENOMEM); + }); + return 0; +} + +void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem) +{ + void **tab; + memcpy(&tab, tab_ptr, sizeof(tab)); + + FF_DYNARRAY_ADD(INT_MAX, sizeof(*tab), tab, *nb_ptr, { + tab[*nb_ptr] = elem; + memcpy(tab_ptr, &tab, sizeof(tab)); + }, { + *nb_ptr = 0; + av_freep(tab_ptr); + }); +} + +void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, + const uint8_t *elem_data) +{ + uint8_t *tab_elem_data = NULL; + + FF_DYNARRAY_ADD(INT_MAX, elem_size, *tab_ptr, *nb_ptr, { + tab_elem_data = (uint8_t *)*tab_ptr + (*nb_ptr) * elem_size; + if (elem_data) + memcpy(tab_elem_data, elem_data, elem_size); + else if (CONFIG_MEMORY_POISONING) + memset(tab_elem_data, FF_MEMORY_POISON, elem_size); + }, { + av_freep(tab_ptr); + *nb_ptr = 0; + }); + return tab_elem_data; +} + +static void fill16(uint8_t *dst, int len) +{ + uint32_t v = AV_RN16(dst - 2); + + v |= v << 16; + + while (len >= 4) { + AV_WN32(dst, v); + dst += 4; + len -= 4; + } + + while (len--) { + *dst = dst[-2]; + dst++; + } +} + +static void fill24(uint8_t *dst, int len) +{ +#if HAVE_BIGENDIAN + uint32_t v = AV_RB24(dst - 3); + uint32_t a = v << 8 | v >> 16; + uint32_t b = v << 16 | v >> 8; + uint32_t c = v << 24 | v; +#else + uint32_t v = AV_RL24(dst - 3); + uint32_t a = v | v << 24; + uint32_t b = v >> 8 | v << 16; + uint32_t c = v >> 16 | v << 8; +#endif + + while (len >= 12) { + AV_WN32(dst, a); + AV_WN32(dst + 4, b); + AV_WN32(dst + 8, c); + dst += 12; + len -= 12; + } + + if (len >= 4) { + AV_WN32(dst, a); + dst += 4; + len -= 4; + } + + if (len >= 4) { + AV_WN32(dst, b); + dst += 4; + len -= 4; + } + + while (len--) { + *dst = dst[-3]; + dst++; + } +} + +static void fill32(uint8_t *dst, int len) +{ + uint32_t v = AV_RN32(dst - 4); + +#if HAVE_FAST_64BIT + uint64_t v2= v + ((uint64_t)v<<32); + while (len >= 32) { + AV_WN64(dst , v2); + AV_WN64(dst+ 8, v2); + AV_WN64(dst+16, v2); + AV_WN64(dst+24, v2); + dst += 32; + len -= 32; + } +#endif + + while (len >= 4) { + AV_WN32(dst, v); + dst += 4; + len -= 4; + } + + while (len--) { + *dst = dst[-4]; + dst++; + } +} + +void av_memcpy_backptr(uint8_t *dst, int back, int cnt) +{ + const uint8_t *src = &dst[-back]; + if (!back) + return; + + if (back == 1) { + memset(dst, *src, cnt); + } else if (back == 2) { + fill16(dst, cnt); + } else if (back == 3) { + fill24(dst, cnt); + } else if (back == 4) { + fill32(dst, cnt); + } else { + if (cnt >= 16) { + int blocklen = back; + while (cnt > blocklen) { + memcpy(dst, src, blocklen); + dst += blocklen; + cnt -= blocklen; + blocklen <<= 1; + } + memcpy(dst, src, cnt); + return; + } + if (cnt >= 8) { + AV_COPY32U(dst, src); + AV_COPY32U(dst + 4, src + 4); + src += 8; + dst += 8; + cnt -= 8; + } + if (cnt >= 4) { + AV_COPY32U(dst, src); + src += 4; + dst += 4; + cnt -= 4; + } + if (cnt >= 2) { + AV_COPY16U(dst, src); + src += 2; + dst += 2; + cnt -= 2; + } + if (cnt) + *dst = *src; + } +} + +void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size) +{ + size_t max_size; + + if (min_size <= *size) + return ptr; + + max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed); + /* *size is an unsigned, so the real maximum is <= UINT_MAX. */ + max_size = FFMIN(max_size, UINT_MAX); + + if (min_size > max_size) { + *size = 0; + return NULL; + } + + min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size)); + + ptr = av_realloc(ptr, min_size); + /* we could set this to the unmodified min_size but this is safer + * if the user lost the ptr and uses NULL now + */ + if (!ptr) + min_size = 0; + + *size = min_size; + + return ptr; +} + +static inline void fast_malloc(void *ptr, unsigned int *size, size_t min_size, int zero_realloc) +{ + size_t max_size; + void *val; + + memcpy(&val, ptr, sizeof(val)); + if (min_size <= *size) { + av_assert0(val || !min_size); + return; + } + + max_size = atomic_load_explicit(&max_alloc_size, memory_order_relaxed); + /* *size is an unsigned, so the real maximum is <= UINT_MAX. */ + max_size = FFMIN(max_size, UINT_MAX); + + if (min_size > max_size) { + av_freep(ptr); + *size = 0; + return; + } + min_size = FFMIN(max_size, FFMAX(min_size + min_size / 16 + 32, min_size)); + av_freep(ptr); + val = zero_realloc ? av_mallocz(min_size) : av_malloc(min_size); + memcpy(ptr, &val, sizeof(val)); + if (!val) + min_size = 0; + *size = min_size; + return; +} + +void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size) +{ + fast_malloc(ptr, size, min_size, 0); +} + +void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size) +{ + fast_malloc(ptr, size, min_size, 1); +} + +int av_size_mult(size_t a, size_t b, size_t *r) +{ + return size_mult(a, b, r); +} diff --git a/libs/ffmpeg/libavutil/mem.h b/libs/ffmpeg/libavutil/mem.h new file mode 100644 index 00000000000..ab7648ac570 --- /dev/null +++ b/libs/ffmpeg/libavutil/mem.h @@ -0,0 +1,607 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_mem + * Memory handling functions + */ + +#ifndef AVUTIL_MEM_H +#define AVUTIL_MEM_H + +#include <stddef.h> +#include <stdint.h> + +#include "attributes.h" + +/** + * @addtogroup lavu_mem + * Utilities for manipulating memory. + * + * FFmpeg has several applications of memory that are not required of a typical + * program. For example, the computing-heavy components like video decoding and + * encoding can be sped up significantly through the use of aligned memory. + * + * However, for each of FFmpeg's applications of memory, there might not be a + * recognized or standardized API for that specific use. Memory alignment, for + * instance, varies wildly depending on operating systems, architectures, and + * compilers. Hence, this component of @ref libavutil is created to make + * dealing with memory consistently possible on all platforms. + * + * @{ + */ + +/** + * @defgroup lavu_mem_attrs Function Attributes + * Function attributes applicable to memory handling functions. + * + * These function attributes can help compilers emit more useful warnings, or + * generate better code. + * @{ + */ + +/** + * @def av_malloc_attrib + * Function attribute denoting a malloc-like function. + * + * @see <a href="https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-g_t_0040code_007bmalloc_007d-function-attribute-3251">Function attribute `malloc` in GCC's documentation</a> + */ + +#if AV_GCC_VERSION_AT_LEAST(3,1) + #define av_malloc_attrib __attribute__((__malloc__)) +#else + #define av_malloc_attrib +#endif + +/** + * @def av_alloc_size(...) + * Function attribute used on a function that allocates memory, whose size is + * given by the specified parameter(s). + * + * @code{.c} + * void *av_malloc(size_t size) av_alloc_size(1); + * void *av_calloc(size_t nmemb, size_t size) av_alloc_size(1, 2); + * @endcode + * + * @param ... One or two parameter indexes, separated by a comma + * + * @see <a href="https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-g_t_0040code_007balloc_005fsize_007d-function-attribute-3220">Function attribute `alloc_size` in GCC's documentation</a> + */ + +#if AV_GCC_VERSION_AT_LEAST(4,3) + #define av_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__))) +#else + #define av_alloc_size(...) +#endif + +/** + * @} + */ + +/** + * @defgroup lavu_mem_funcs Heap Management + * Functions responsible for allocating, freeing, and copying memory. + * + * All memory allocation functions have a built-in upper limit of `INT_MAX` + * bytes. This may be changed with av_max_alloc(), although exercise extreme + * caution when doing so. + * + * @{ + */ + +/** + * Allocate a memory block with alignment suitable for all memory accesses + * (including vectors if available on the CPU). + * + * @param size Size in bytes for the memory block to be allocated + * @return Pointer to the allocated block, or `NULL` if the block cannot + * be allocated + * @see av_mallocz() + */ +void *av_malloc(size_t size) av_malloc_attrib av_alloc_size(1); + +/** + * Allocate a memory block with alignment suitable for all memory accesses + * (including vectors if available on the CPU) and zero all the bytes of the + * block. + * + * @param size Size in bytes for the memory block to be allocated + * @return Pointer to the allocated block, or `NULL` if it cannot be allocated + * @see av_malloc() + */ +void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1); + +/** + * Allocate a memory block for an array with av_malloc(). + * + * The allocated memory will have size `size * nmemb` bytes. + * + * @param nmemb Number of element + * @param size Size of a single element + * @return Pointer to the allocated block, or `NULL` if the block cannot + * be allocated + * @see av_malloc() + */ +av_alloc_size(1, 2) void *av_malloc_array(size_t nmemb, size_t size); + +/** + * Allocate a memory block for an array with av_mallocz(). + * + * The allocated memory will have size `size * nmemb` bytes. + * + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to the allocated block, or `NULL` if the block cannot + * be allocated + * + * @see av_mallocz() + * @see av_malloc_array() + */ +void *av_calloc(size_t nmemb, size_t size) av_malloc_attrib av_alloc_size(1, 2); + +/** + * Allocate, reallocate, or free a block of memory. + * + * If `ptr` is `NULL` and `size` > 0, allocate a new block. Otherwise, expand or + * shrink that block of memory according to `size`. + * + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or `NULL` + * @param size Size in bytes of the memory block to be allocated or + * reallocated + * + * @return Pointer to a newly-reallocated block or `NULL` if the block + * cannot be reallocated + * + * @warning Unlike av_malloc(), the returned pointer is not guaranteed to be + * correctly aligned. The returned pointer must be freed after even + * if size is zero. + * @see av_fast_realloc() + * @see av_reallocp() + */ +void *av_realloc(void *ptr, size_t size) av_alloc_size(2); + +/** + * Allocate, reallocate, or free a block of memory through a pointer to a + * pointer. + * + * If `*ptr` is `NULL` and `size` > 0, allocate a new block. If `size` is + * zero, free the memory block pointed to by `*ptr`. Otherwise, expand or + * shrink that block of memory according to `size`. + * + * @param[in,out] ptr Pointer to a pointer to a memory block already allocated + * with av_realloc(), or a pointer to `NULL`. The pointer + * is updated on success, or freed on failure. + * @param[in] size Size in bytes for the memory block to be allocated or + * reallocated + * + * @return Zero on success, an AVERROR error code on failure + * + * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be + * correctly aligned. + */ +av_warn_unused_result +int av_reallocp(void *ptr, size_t size); + +/** + * Allocate, reallocate, or free a block of memory. + * + * This function does the same thing as av_realloc(), except: + * - It takes two size arguments and allocates `nelem * elsize` bytes, + * after checking the result of the multiplication for integer overflow. + * - It frees the input block in case of failure, thus avoiding the memory + * leak with the classic + * @code{.c} + * buf = realloc(buf); + * if (!buf) + * return -1; + * @endcode + * pattern. + */ +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize); + +/** + * Allocate, reallocate, or free an array. + * + * If `ptr` is `NULL` and `nmemb` > 0, allocate a new block. + * + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or `NULL` + * @param nmemb Number of elements in the array + * @param size Size of the single element of the array + * + * @return Pointer to a newly-reallocated block or NULL if the block + * cannot be reallocated + * + * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be + * correctly aligned. The returned pointer must be freed after even if + * nmemb is zero. + * @see av_reallocp_array() + */ +av_alloc_size(2, 3) void *av_realloc_array(void *ptr, size_t nmemb, size_t size); + +/** + * Allocate, reallocate an array through a pointer to a pointer. + * + * If `*ptr` is `NULL` and `nmemb` > 0, allocate a new block. + * + * @param[in,out] ptr Pointer to a pointer to a memory block already + * allocated with av_realloc(), or a pointer to `NULL`. + * The pointer is updated on success, or freed on failure. + * @param[in] nmemb Number of elements + * @param[in] size Size of the single element + * + * @return Zero on success, an AVERROR error code on failure + * + * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be + * correctly aligned. *ptr must be freed after even if nmemb is zero. + */ +int av_reallocp_array(void *ptr, size_t nmemb, size_t size); + +/** + * Reallocate the given buffer if it is not large enough, otherwise do nothing. + * + * If the given buffer is `NULL`, then a new uninitialized buffer is allocated. + * + * If the given buffer is not large enough, and reallocation fails, `NULL` is + * returned and `*size` is set to 0, but the original buffer is not changed or + * freed. + * + * A typical use pattern follows: + * + * @code{.c} + * uint8_t *buf = ...; + * uint8_t *new_buf = av_fast_realloc(buf, ¤t_size, size_needed); + * if (!new_buf) { + * // Allocation failed; clean up original buffer + * av_freep(&buf); + * return AVERROR(ENOMEM); + * } + * @endcode + * + * @param[in,out] ptr Already allocated buffer, or `NULL` + * @param[in,out] size Pointer to the size of buffer `ptr`. `*size` is + * updated to the new allocated size, in particular 0 + * in case of failure. + * @param[in] min_size Desired minimal size of buffer `ptr` + * @return `ptr` if the buffer is large enough, a pointer to newly reallocated + * buffer if the buffer was not large enough, or `NULL` in case of + * error + * @see av_realloc() + * @see av_fast_malloc() + */ +void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Allocate a buffer, reusing the given one if large enough. + * + * Contrary to av_fast_realloc(), the current buffer contents might not be + * preserved and on error the old buffer is freed, thus no special handling to + * avoid memleaks is necessary. + * + * `*ptr` is allowed to be `NULL`, in which case allocation always happens if + * `size_needed` is greater than 0. + * + * @code{.c} + * uint8_t *buf = ...; + * av_fast_malloc(&buf, ¤t_size, size_needed); + * if (!buf) { + * // Allocation failed; buf already freed + * return AVERROR(ENOMEM); + * } + * @endcode + * + * @param[in,out] ptr Pointer to pointer to an already allocated buffer. + * `*ptr` will be overwritten with pointer to new + * buffer on success or `NULL` on failure + * @param[in,out] size Pointer to the size of buffer `*ptr`. `*size` is + * updated to the new allocated size, in particular 0 + * in case of failure. + * @param[in] min_size Desired minimal size of buffer `*ptr` + * @see av_realloc() + * @see av_fast_mallocz() + */ +void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Allocate and clear a buffer, reusing the given one if large enough. + * + * Like av_fast_malloc(), but all newly allocated space is initially cleared. + * Reused buffer is not cleared. + * + * `*ptr` is allowed to be `NULL`, in which case allocation always happens if + * `size_needed` is greater than 0. + * + * @param[in,out] ptr Pointer to pointer to an already allocated buffer. + * `*ptr` will be overwritten with pointer to new + * buffer on success or `NULL` on failure + * @param[in,out] size Pointer to the size of buffer `*ptr`. `*size` is + * updated to the new allocated size, in particular 0 + * in case of failure. + * @param[in] min_size Desired minimal size of buffer `*ptr` + * @see av_fast_malloc() + */ +void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size); + +/** + * Free a memory block which has been allocated with a function of av_malloc() + * or av_realloc() family. + * + * @param ptr Pointer to the memory block which should be freed. + * + * @note `ptr = NULL` is explicitly allowed. + * @note It is recommended that you use av_freep() instead, to prevent leaving + * behind dangling pointers. + * @see av_freep() + */ +void av_free(void *ptr); + +/** + * Free a memory block which has been allocated with a function of av_malloc() + * or av_realloc() family, and set the pointer pointing to it to `NULL`. + * + * @code{.c} + * uint8_t *buf = av_malloc(16); + * av_free(buf); + * // buf now contains a dangling pointer to freed memory, and accidental + * // dereference of buf will result in a use-after-free, which may be a + * // security risk. + * + * uint8_t *buf = av_malloc(16); + * av_freep(&buf); + * // buf is now NULL, and accidental dereference will only result in a + * // NULL-pointer dereference. + * @endcode + * + * @param ptr Pointer to the pointer to the memory block which should be freed + * @note `*ptr = NULL` is safe and leads to no action. + * @see av_free() + */ +void av_freep(void *ptr); + +/** + * Duplicate a string. + * + * @param s String to be duplicated + * @return Pointer to a newly-allocated string containing a + * copy of `s` or `NULL` if the string cannot be allocated + * @see av_strndup() + */ +char *av_strdup(const char *s) av_malloc_attrib; + +/** + * Duplicate a substring of a string. + * + * @param s String to be duplicated + * @param len Maximum length of the resulting string (not counting the + * terminating byte) + * @return Pointer to a newly-allocated string containing a + * substring of `s` or `NULL` if the string cannot be allocated + */ +char *av_strndup(const char *s, size_t len) av_malloc_attrib; + +/** + * Duplicate a buffer with av_malloc(). + * + * @param p Buffer to be duplicated + * @param size Size in bytes of the buffer copied + * @return Pointer to a newly allocated buffer containing a + * copy of `p` or `NULL` if the buffer cannot be allocated + */ +void *av_memdup(const void *p, size_t size); + +/** + * Overlapping memcpy() implementation. + * + * @param dst Destination buffer + * @param back Number of bytes back to start copying (i.e. the initial size of + * the overlapping window); must be > 0 + * @param cnt Number of bytes to copy; must be >= 0 + * + * @note `cnt > back` is valid, this will copy the bytes we just copied, + * thus creating a repeating pattern with a period length of `back`. + */ +void av_memcpy_backptr(uint8_t *dst, int back, int cnt); + +/** + * @} + */ + +/** + * @defgroup lavu_mem_dynarray Dynamic Array + * + * Utilities to make an array grow when needed. + * + * Sometimes, the programmer would want to have an array that can grow when + * needed. The libavutil dynamic array utilities fill that need. + * + * libavutil supports two systems of appending elements onto a dynamically + * allocated array, the first one storing the pointer to the value in the + * array, and the second storing the value directly. In both systems, the + * caller is responsible for maintaining a variable containing the length of + * the array, as well as freeing of the array after use. + * + * The first system stores pointers to values in a block of dynamically + * allocated memory. Since only pointers are stored, the function does not need + * to know the size of the type. Both av_dynarray_add() and + * av_dynarray_add_nofree() implement this system. + * + * @code + * type **array = NULL; //< an array of pointers to values + * int nb = 0; //< a variable to keep track of the length of the array + * + * type to_be_added = ...; + * type to_be_added2 = ...; + * + * av_dynarray_add(&array, &nb, &to_be_added); + * if (nb == 0) + * return AVERROR(ENOMEM); + * + * av_dynarray_add(&array, &nb, &to_be_added2); + * if (nb == 0) + * return AVERROR(ENOMEM); + * + * // Now: + * // nb == 2 + * // &to_be_added == array[0] + * // &to_be_added2 == array[1] + * + * av_freep(&array); + * @endcode + * + * The second system stores the value directly in a block of memory. As a + * result, the function has to know the size of the type. av_dynarray2_add() + * implements this mechanism. + * + * @code + * type *array = NULL; //< an array of values + * int nb = 0; //< a variable to keep track of the length of the array + * + * type to_be_added = ...; + * type to_be_added2 = ...; + * + * type *addr = av_dynarray2_add((void **)&array, &nb, sizeof(*array), NULL); + * if (!addr) + * return AVERROR(ENOMEM); + * memcpy(addr, &to_be_added, sizeof(to_be_added)); + * + * // Shortcut of the above. + * type *addr = av_dynarray2_add((void **)&array, &nb, sizeof(*array), + * (const void *)&to_be_added2); + * if (!addr) + * return AVERROR(ENOMEM); + * + * // Now: + * // nb == 2 + * // to_be_added == array[0] + * // to_be_added2 == array[1] + * + * av_freep(&array); + * @endcode + * + * @{ + */ + +/** + * Add the pointer to an element to a dynamic array. + * + * The array to grow is supposed to be an array of pointers to + * structures, and the element to add must be a pointer to an already + * allocated structure. + * + * The array is reallocated when its size reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by `nb_ptr` + * is incremented. + * In case of failure, the array is freed, `*tab_ptr` is set to `NULL` and + * `*nb_ptr` is set to 0. + * + * @param[in,out] tab_ptr Pointer to the array to grow + * @param[in,out] nb_ptr Pointer to the number of elements in the array + * @param[in] elem Element to add + * @see av_dynarray_add_nofree(), av_dynarray2_add() + */ +void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element to a dynamic array. + * + * Function has the same functionality as av_dynarray_add(), + * but it doesn't free memory on fails. It returns error code + * instead and leave current buffer untouched. + * + * @return >=0 on success, negative otherwise + * @see av_dynarray_add(), av_dynarray2_add() + */ +av_warn_unused_result +int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element of size `elem_size` to a dynamic array. + * + * The array is reallocated when its number of elements reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by `nb_ptr` + * is incremented. + * In case of failure, the array is freed, `*tab_ptr` is set to `NULL` and + * `*nb_ptr` is set to 0. + * + * @param[in,out] tab_ptr Pointer to the array to grow + * @param[in,out] nb_ptr Pointer to the number of elements in the array + * @param[in] elem_size Size in bytes of an element in the array + * @param[in] elem_data Pointer to the data of the element to add. If + * `NULL`, the space of the newly added element is + * allocated but left uninitialized. + * + * @return Pointer to the data of the element to copy in the newly allocated + * space + * @see av_dynarray_add(), av_dynarray_add_nofree() + */ +void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, + const uint8_t *elem_data); + +/** + * @} + */ + +/** + * @defgroup lavu_mem_misc Miscellaneous Functions + * + * Other functions related to memory allocation. + * + * @{ + */ + +/** + * Multiply two `size_t` values checking for overflow. + * + * @param[in] a Operand of multiplication + * @param[in] b Operand of multiplication + * @param[out] r Pointer to the result of the operation + * @return 0 on success, AVERROR(EINVAL) on overflow + */ +int av_size_mult(size_t a, size_t b, size_t *r); + +/** + * Set the maximum size that may be allocated in one block. + * + * The value specified with this function is effective for all libavutil's @ref + * lavu_mem_funcs "heap management functions." + * + * By default, the max value is defined as `INT_MAX`. + * + * @param max Value to be set as the new maximum size + * + * @warning Exercise extreme caution when using this function. Don't touch + * this if you do not understand the full consequence of doing so. + */ +void av_max_alloc(size_t max); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_MEM_H */ diff --git a/libs/ffmpeg/libavutil/mem_internal.h b/libs/ffmpeg/libavutil/mem_internal.h new file mode 100644 index 00000000000..78adc4f4079 --- /dev/null +++ b/libs/ffmpeg/libavutil/mem_internal.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MEM_INTERNAL_H +#define AVUTIL_MEM_INTERNAL_H + +#include "config.h" + +#include <stdint.h> +#ifndef _MSC_VER +#include <stdalign.h> +#endif + +#include "attributes.h" +#include "macros.h" + +/** + * @def DECLARE_ALIGNED(n,t,v) + * Declare a variable that is aligned in memory. + * + * @code{.c} + * DECLARE_ALIGNED(16, uint16_t, aligned_int) = 42; + * DECLARE_ALIGNED(32, uint8_t, aligned_array)[128]; + * + * // The default-alignment equivalent would be + * uint16_t aligned_int = 42; + * uint8_t aligned_array[128]; + * @endcode + * + * @param n Minimum alignment in bytes + * @param t Type of the variable (or array element) + * @param v Name of the variable + */ + +/** + * @def DECLARE_ASM_ALIGNED(n,t,v) + * Declare an aligned variable appropriate for use in inline assembly code. + * + * @code{.c} + * DECLARE_ASM_ALIGNED(16, uint64_t, pw_08) = UINT64_C(0x0008000800080008); + * @endcode + * + * @param n Minimum alignment in bytes + * @param t Type of the variable (or array element) + * @param v Name of the variable + */ + +/** + * @def DECLARE_ASM_CONST(n,t,v) + * Declare a static constant aligned variable appropriate for use in inline + * assembly code. + * + * @code{.c} + * DECLARE_ASM_CONST(16, uint64_t, pw_08) = UINT64_C(0x0008000800080008); + * @endcode + * + * @param n Minimum alignment in bytes + * @param t Type of the variable (or array element) + * @param v Name of the variable + */ + +#if defined(__DJGPP__) + #define DECLARE_ALIGNED_T(n,t,v) alignas(FFMIN(n, 16)) t v + #define DECLARE_ASM_ALIGNED(n,t,v) alignas(FFMIN(n, 16)) t av_used v + #define DECLARE_ASM_CONST(n,t,v) alignas(FFMIN(n, 16)) static const t av_used v +#elif defined(_MSC_VER) + #define DECLARE_ALIGNED_T(n,t,v) __declspec(align(n)) t v + #define DECLARE_ASM_ALIGNED(n,t,v) __declspec(align(n)) t av_used v + #define DECLARE_ASM_CONST(n,t,v) __declspec(align(n)) static const t av_used v +#else + #define DECLARE_ALIGNED_T(n,t,v) alignas(n) t v + #define DECLARE_ASM_ALIGNED(n,t,v) alignas(n) t av_used v + #define DECLARE_ASM_CONST(n,t,v) alignas(n) static const t av_used v +#endif + +#if HAVE_SIMD_ALIGN_64 + #define ALIGN_64 64 + #define ALIGN_32 32 +#elif HAVE_SIMD_ALIGN_32 + #define ALIGN_64 32 + #define ALIGN_32 32 +#else + #define ALIGN_64 16 + #define ALIGN_32 16 +#endif + +#define DECLARE_ALIGNED(n,t,v) DECLARE_ALIGNED_V(n,t,v) + +// Macro needs to be double-wrapped in order to expand +// possible other macros being passed for n. +#define DECLARE_ALIGNED_V(n,t,v) DECLARE_ALIGNED_##n(t,v) + +#define DECLARE_ALIGNED_4(t,v) DECLARE_ALIGNED_T( 4, t, v) +#define DECLARE_ALIGNED_8(t,v) DECLARE_ALIGNED_T( 8, t, v) +#define DECLARE_ALIGNED_16(t,v) DECLARE_ALIGNED_T( 16, t, v) +#define DECLARE_ALIGNED_32(t,v) DECLARE_ALIGNED_T(ALIGN_32, t, v) +#define DECLARE_ALIGNED_64(t,v) DECLARE_ALIGNED_T(ALIGN_64, t, v) + +// Some broken preprocessors need a second expansion +// to be forced to tokenize __VA_ARGS__ +#define E1(x) x + +#define LOCAL_ALIGNED_D(a, t, v, s, o, ...) \ + DECLARE_ALIGNED(a, t, la_##v) s o; \ + t (*v) o = la_##v + +#define LOCAL_ALIGNED(a, t, v, ...) LOCAL_ALIGNED_##a(t, v, __VA_ARGS__) + +#define LOCAL_ALIGNED_4(t, v, ...) E1(LOCAL_ALIGNED_D(4, t, v, __VA_ARGS__,,)) + +#define LOCAL_ALIGNED_8(t, v, ...) E1(LOCAL_ALIGNED_D(8, t, v, __VA_ARGS__,,)) + +#define LOCAL_ALIGNED_16(t, v, ...) E1(LOCAL_ALIGNED_D(16, t, v, __VA_ARGS__,,)) + +#define LOCAL_ALIGNED_32(t, v, ...) E1(LOCAL_ALIGNED_D(32, t, v, __VA_ARGS__,,)) + +#define LOCAL_ALIGNED_64(t, v, ...) E1(LOCAL_ALIGNED_D(64, t, v, __VA_ARGS__,,)) + +#endif /* AVUTIL_MEM_INTERNAL_H */ diff --git a/libs/ffmpeg/libavutil/murmur3.c b/libs/ffmpeg/libavutil/murmur3.c new file mode 100644 index 00000000000..c88a236a0c2 --- /dev/null +++ b/libs/ffmpeg/libavutil/murmur3.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2013 Reimar Döffinger <Reimar.Doeffinger@gmx.de> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include "mem.h" +#include "intreadwrite.h" +#include "murmur3.h" + +typedef struct AVMurMur3 { + uint64_t h1, h2; + uint8_t state[16]; + int state_pos; + uint64_t len; +} AVMurMur3; + +AVMurMur3 *av_murmur3_alloc(void) +{ + return av_mallocz(sizeof(AVMurMur3)); +} + +void av_murmur3_init_seeded(AVMurMur3 *c, uint64_t seed) +{ + memset(c, 0, sizeof(*c)); + c->h1 = c->h2 = seed; +} + +void av_murmur3_init(AVMurMur3 *c) +{ + // arbitrary random number as seed + av_murmur3_init_seeded(c, 0x725acc55daddca55); +} + +static const uint64_t c1 = UINT64_C(0x87c37b91114253d5); +static const uint64_t c2 = UINT64_C(0x4cf5ad432745937f); + +#define ROT(a, b) (((a) << (b)) | ((a) >> (64 - (b)))) + +static uint64_t inline get_k1(const uint8_t *src) +{ + uint64_t k = AV_RL64(src); + k *= c1; + k = ROT(k, 31); + k *= c2; + return k; +} + +static inline uint64_t get_k2(const uint8_t *src) +{ + uint64_t k = AV_RL64(src + 8); + k *= c2; + k = ROT(k, 33); + k *= c1; + return k; +} + +static inline uint64_t update_h1(uint64_t k, uint64_t h1, uint64_t h2) +{ + k ^= h1; + k = ROT(k, 27); + k += h2; + k *= 5; + k += 0x52dce729; + return k; +} + +static inline uint64_t update_h2(uint64_t k, uint64_t h1, uint64_t h2) +{ + k ^= h2; + k = ROT(k, 31); + k += h1; + k *= 5; + k += 0x38495ab5; + return k; +} + +void av_murmur3_update(AVMurMur3 *c, const uint8_t *src, size_t len) +{ + const uint8_t *end; + uint64_t h1 = c->h1, h2 = c->h2; + uint64_t k1, k2; + if (len <= 0) return; + c->len += len; + if (c->state_pos > 0) { + while (c->state_pos < 16) { + c->state[c->state_pos++] = *src++; + if (--len <= 0) return; + } + c->state_pos = 0; + k1 = get_k1(c->state); + k2 = get_k2(c->state); + h1 = update_h1(k1, h1, h2); + h2 = update_h2(k2, h1, h2); + } + + end = src + (len & ~15); + while (src < end) { + // These could be done sequentially instead + // of interleaved, but like this is over 10% faster + k1 = get_k1(src); + k2 = get_k2(src); + h1 = update_h1(k1, h1, h2); + h2 = update_h2(k2, h1, h2); + src += 16; + } + c->h1 = h1; + c->h2 = h2; + + len &= 15; + if (len > 0) { + memcpy(c->state, src, len); + c->state_pos = len; + } +} + +static inline uint64_t fmix(uint64_t k) +{ + k ^= k >> 33; + k *= UINT64_C(0xff51afd7ed558ccd); + k ^= k >> 33; + k *= UINT64_C(0xc4ceb9fe1a85ec53); + k ^= k >> 33; + return k; +} + +void av_murmur3_final(AVMurMur3 *c, uint8_t dst[16]) +{ + uint64_t h1 = c->h1, h2 = c->h2; + memset(c->state + c->state_pos, 0, sizeof(c->state) - c->state_pos); + h1 ^= get_k1(c->state) ^ c->len; + h2 ^= get_k2(c->state) ^ c->len; + h1 += h2; + h2 += h1; + h1 = fmix(h1); + h2 = fmix(h2); + h1 += h2; + h2 += h1; + AV_WL64(dst, h1); + AV_WL64(dst + 8, h2); +} diff --git a/libs/ffmpeg/libavutil/murmur3.h b/libs/ffmpeg/libavutil/murmur3.h new file mode 100644 index 00000000000..d90bc2fcd13 --- /dev/null +++ b/libs/ffmpeg/libavutil/murmur3.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2013 Reimar Döffinger <Reimar.Doeffinger@gmx.de> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_murmur3 + * Public header for MurmurHash3 hash function implementation. + */ + +#ifndef AVUTIL_MURMUR3_H +#define AVUTIL_MURMUR3_H + +#include <stddef.h> +#include <stdint.h> + +/** + * @defgroup lavu_murmur3 Murmur3 + * @ingroup lavu_hash + * MurmurHash3 hash function implementation. + * + * MurmurHash3 is a non-cryptographic hash function, of which three + * incompatible versions were created by its inventor Austin Appleby: + * + * - 32-bit output + * - 128-bit output for 32-bit platforms + * - 128-bit output for 64-bit platforms + * + * FFmpeg only implements the last variant: 128-bit output designed for 64-bit + * platforms. Even though the hash function was designed for 64-bit platforms, + * the function in reality works on 32-bit systems too, only with reduced + * performance. + * + * @anchor lavu_murmur3_seedinfo + * By design, MurmurHash3 requires a seed to operate. In response to this, + * libavutil provides two functions for hash initiation, one that requires a + * seed (av_murmur3_init_seeded()) and one that uses a fixed arbitrary integer + * as the seed, and therefore does not (av_murmur3_init()). + * + * To make hashes comparable, you should provide the same seed for all calls to + * this hash function -- if you are supplying one yourself, that is. + * + * @{ + */ + +/** + * Allocate an AVMurMur3 hash context. + * + * @return Uninitialized hash context or `NULL` in case of error + */ +struct AVMurMur3 *av_murmur3_alloc(void); + +/** + * Initialize or reinitialize an AVMurMur3 hash context with a seed. + * + * @param[out] c Hash context + * @param[in] seed Random seed + * + * @see av_murmur3_init() + * @see @ref lavu_murmur3_seedinfo "Detailed description" on a discussion of + * seeds for MurmurHash3. + */ +void av_murmur3_init_seeded(struct AVMurMur3 *c, uint64_t seed); + +/** + * Initialize or reinitialize an AVMurMur3 hash context. + * + * Equivalent to av_murmur3_init_seeded() with a built-in seed. + * + * @param[out] c Hash context + * + * @see av_murmur3_init_seeded() + * @see @ref lavu_murmur3_seedinfo "Detailed description" on a discussion of + * seeds for MurmurHash3. + */ +void av_murmur3_init(struct AVMurMur3 *c); + +/** + * Update hash context with new data. + * + * @param[out] c Hash context + * @param[in] src Input data to update hash with + * @param[in] len Number of bytes to read from `src` + */ +void av_murmur3_update(struct AVMurMur3 *c, const uint8_t *src, size_t len); + +/** + * Finish hashing and output digest value. + * + * @param[in,out] c Hash context + * @param[out] dst Buffer where output digest value is stored + */ +void av_murmur3_final(struct AVMurMur3 *c, uint8_t dst[16]); + +/** + * @} + */ + +#endif /* AVUTIL_MURMUR3_H */ diff --git a/libs/ffmpeg/libavutil/opt.c b/libs/ffmpeg/libavutil/opt.c new file mode 100644 index 00000000000..7c6a01068a8 --- /dev/null +++ b/libs/ffmpeg/libavutil/opt.c @@ -0,0 +1,2803 @@ +/* + * AVOptions + * Copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AVOptions + * @author Michael Niedermayer <michaelni@gmx.at> + */ + +#include "avutil.h" +#include "avassert.h" +#include "avstring.h" +#include "channel_layout.h" +#include "dict.h" +#include "eval.h" +#include "log.h" +#include "mem.h" +#include "parseutils.h" +#include "pixdesc.h" +#include "mathematics.h" +#include "opt.h" +#include "samplefmt.h" +#include "bprint.h" +#include "version.h" + +#include <float.h> + +#define TYPE_BASE(type) ((type) & ~AV_OPT_TYPE_FLAG_ARRAY) + +const AVOption *av_opt_next(const void *obj, const AVOption *last) +{ + const AVClass *class; + if (!obj) + return NULL; + class = *(const AVClass**)obj; + if (!last && class && class->option && class->option[0].name) + return class->option; + if (last && last[1].name) + return ++last; + return NULL; +} + +static const struct { + size_t size; + const char *name; +} opt_type_desc[] = { + [AV_OPT_TYPE_FLAGS] = { sizeof(unsigned), "<flags>" }, + [AV_OPT_TYPE_INT] = { sizeof(int), "<int>" }, + [AV_OPT_TYPE_INT64] = { sizeof(int64_t), "<int64>" }, + [AV_OPT_TYPE_UINT] = { sizeof(unsigned), "<unsigned>" }, + [AV_OPT_TYPE_UINT64] = { sizeof(uint64_t), "<uint64>" }, + [AV_OPT_TYPE_DOUBLE] = { sizeof(double), "<double>" }, + [AV_OPT_TYPE_FLOAT] = { sizeof(float), "<float>" }, + [AV_OPT_TYPE_STRING] = { sizeof(char *), "<string>" }, + [AV_OPT_TYPE_RATIONAL] = { sizeof(AVRational), "<rational>" }, + [AV_OPT_TYPE_BINARY] = { sizeof(uint8_t *), "<binary>" }, + [AV_OPT_TYPE_DICT] = { sizeof(AVDictionary *), "<dictionary>" }, + [AV_OPT_TYPE_IMAGE_SIZE] = { sizeof(int[2]), "<image_size>" }, + [AV_OPT_TYPE_VIDEO_RATE] = { sizeof(AVRational), "<video_rate>" }, + [AV_OPT_TYPE_PIXEL_FMT] = { sizeof(int), "<pix_fmt>" }, + [AV_OPT_TYPE_SAMPLE_FMT] = { sizeof(int), "<sample_fmt>" }, + [AV_OPT_TYPE_DURATION] = { sizeof(int64_t), "<duration>" }, + [AV_OPT_TYPE_COLOR] = { sizeof(uint8_t[4]), "<color>" }, + [AV_OPT_TYPE_CHLAYOUT] = { sizeof(AVChannelLayout),"<channel_layout>" }, + [AV_OPT_TYPE_BOOL] = { sizeof(int), "<boolean>" }, +}; + +// option is plain old data +static int opt_is_pod(enum AVOptionType type) +{ + switch (type) { + case AV_OPT_TYPE_FLAGS: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_FLOAT: + case AV_OPT_TYPE_RATIONAL: + case AV_OPT_TYPE_UINT64: + case AV_OPT_TYPE_IMAGE_SIZE: + case AV_OPT_TYPE_PIXEL_FMT: + case AV_OPT_TYPE_SAMPLE_FMT: + case AV_OPT_TYPE_VIDEO_RATE: + case AV_OPT_TYPE_DURATION: + case AV_OPT_TYPE_COLOR: + case AV_OPT_TYPE_BOOL: + case AV_OPT_TYPE_UINT: + return 1; + } + return 0; +} + +static uint8_t opt_array_sep(const AVOption *o) +{ + const AVOptionArrayDef *d = o->default_val.arr; + av_assert1(o->type & AV_OPT_TYPE_FLAG_ARRAY); + return (d && d->sep) ? d->sep : ','; +} + +static void *opt_array_pelem(const AVOption *o, void *array, unsigned idx) +{ + av_assert1(o->type & AV_OPT_TYPE_FLAG_ARRAY); + return (uint8_t *)array + idx * opt_type_desc[TYPE_BASE(o->type)].size; +} + +static unsigned *opt_array_pcount(const void *parray) +{ + return (unsigned *)((const void * const *)parray + 1); +} + +static void opt_free_elem(enum AVOptionType type, void *ptr) +{ + switch (TYPE_BASE(type)) { + case AV_OPT_TYPE_STRING: + case AV_OPT_TYPE_BINARY: + av_freep(ptr); + break; + + case AV_OPT_TYPE_DICT: + av_dict_free((AVDictionary **)ptr); + break; + + case AV_OPT_TYPE_CHLAYOUT: + av_channel_layout_uninit((AVChannelLayout *)ptr); + break; + + default: + break; + } +} + +static void opt_free_array(const AVOption *o, void *parray, unsigned *count) +{ + for (unsigned i = 0; i < *count; i++) + opt_free_elem(o->type, opt_array_pelem(o, *(void **)parray, i)); + + av_freep(parray); + *count = 0; +} + +/** + * Perform common setup for option-setting functions. + * + * @param require_type when non-0, require the option to be of this type + * @param ptgt target object is written here + * @param po the option is written here + * @param pdst pointer to option value is written here + */ +static int opt_set_init(void *obj, const char *name, int search_flags, + int require_type, + void **ptgt, const AVOption **po, void **pdst) +{ + const AVOption *o; + void *tgt; + + o = av_opt_find2(obj, name, NULL, 0, search_flags, &tgt); + if (!o || !tgt) + return AVERROR_OPTION_NOT_FOUND; + + if (o->flags & AV_OPT_FLAG_READONLY) + return AVERROR(EINVAL); + + if (require_type && (o->type != require_type)) { + av_log(obj, AV_LOG_ERROR, + "Tried to set option '%s' of type %s from value of type %s, " + "this is not supported\n", o->name, opt_type_desc[o->type].name, + opt_type_desc[require_type].name); + return AVERROR(EINVAL); + } + + if (!(o->flags & AV_OPT_FLAG_RUNTIME_PARAM)) { + unsigned *state_flags = NULL; + const AVClass *class; + + // try state flags first from the target (child), then from its parent + class = *(const AVClass**)tgt; + if ( +#if LIBAVUTIL_VERSION_MAJOR < 60 + class->version >= AV_VERSION_INT(59, 41, 100) && +#endif + class->state_flags_offset) + state_flags = (unsigned*)((uint8_t*)tgt + class->state_flags_offset); + + if (!state_flags && obj != tgt) { + class = *(const AVClass**)obj; + if ( +#if LIBAVUTIL_VERSION_MAJOR < 60 + class->version >= AV_VERSION_INT(59, 41, 100) && +#endif + class->state_flags_offset) + state_flags = (unsigned*)((uint8_t*)obj + class->state_flags_offset); + } + + if (state_flags && (*state_flags & AV_CLASS_STATE_INITIALIZED)) { + av_log(obj, AV_LOG_ERROR, "Option '%s' is not a runtime option and " + "so cannot be set after the object has been initialized\n", + o->name); +#if LIBAVUTIL_VERSION_MAJOR >= 60 + return AVERROR(EINVAL); +#endif + } + } + + if (o->flags & AV_OPT_FLAG_DEPRECATED) + av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); + + if (po) + *po = o; + if (ptgt) + *ptgt = tgt; + if (pdst) + *pdst = ((uint8_t *)tgt) + o->offset; + + return 0; +} + +static AVRational double_to_rational(double d) +{ + AVRational r = av_d2q(d, 1 << 24); + if ((!r.num || !r.den) && d) + r = av_d2q(d, INT_MAX); + return r; +} + +static int read_number(const AVOption *o, const void *dst, double *num, int *den, int64_t *intnum) +{ + switch (TYPE_BASE(o->type)) { + case AV_OPT_TYPE_FLAGS: + *intnum = *(unsigned int*)dst; + return 0; + case AV_OPT_TYPE_PIXEL_FMT: + *intnum = *(enum AVPixelFormat *)dst; + return 0; + case AV_OPT_TYPE_SAMPLE_FMT: + *intnum = *(enum AVSampleFormat *)dst; + return 0; + case AV_OPT_TYPE_BOOL: + case AV_OPT_TYPE_INT: + *intnum = *(int *)dst; + return 0; + case AV_OPT_TYPE_UINT: + *intnum = *(unsigned int *)dst; + return 0; + case AV_OPT_TYPE_DURATION: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: + *intnum = *(int64_t *)dst; + return 0; + case AV_OPT_TYPE_FLOAT: + *num = *(float *)dst; + return 0; + case AV_OPT_TYPE_DOUBLE: + *num = *(double *)dst; + return 0; + case AV_OPT_TYPE_RATIONAL: + *intnum = ((AVRational *)dst)->num; + *den = ((AVRational *)dst)->den; + return 0; + case AV_OPT_TYPE_CONST: + *intnum = o->default_val.i64; + return 0; + } + return AVERROR(EINVAL); +} + +static int write_number(void *obj, const AVOption *o, void *dst, double num, int den, int64_t intnum) +{ + const enum AVOptionType type = TYPE_BASE(o->type); + + if (type != AV_OPT_TYPE_FLAGS && + (!den || o->max * den < num * intnum || o->min * den > num * intnum)) { + num = den ? num * intnum / den : (num && intnum ? INFINITY : NAN); + av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n", + num, o->name, o->min, o->max); + return AVERROR(ERANGE); + } + if (type == AV_OPT_TYPE_FLAGS) { + double d = num*intnum/den; + if (d < -1.5 || d > 0xFFFFFFFF+0.5 || (llrint(d*256) & 255)) { + av_log(obj, AV_LOG_ERROR, + "Value %f for parameter '%s' is not a valid set of 32bit integer flags\n", + num*intnum/den, o->name); + return AVERROR(ERANGE); + } + } + + switch (type) { + case AV_OPT_TYPE_PIXEL_FMT: + *(enum AVPixelFormat *)dst = llrint(num / den) * intnum; + break; + case AV_OPT_TYPE_SAMPLE_FMT: + *(enum AVSampleFormat *)dst = llrint(num / den) * intnum; + break; + case AV_OPT_TYPE_BOOL: + case AV_OPT_TYPE_FLAGS: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT: + *(int *)dst = llrint(num / den) * intnum; + break; + case AV_OPT_TYPE_DURATION: + case AV_OPT_TYPE_INT64:{ + double d = num / den; + if (intnum == 1 && d == (double)INT64_MAX) { + *(int64_t *)dst = INT64_MAX; + } else + *(int64_t *)dst = llrint(d) * intnum; + break;} + case AV_OPT_TYPE_UINT64:{ + double d = num / den; + // We must special case uint64_t here as llrint() does not support values + // outside the int64_t range and there is no portable function which does + // "INT64_MAX + 1ULL" is used as it is representable exactly as IEEE double + // while INT64_MAX is not + if (intnum == 1 && d == (double)UINT64_MAX) { + *(uint64_t *)dst = UINT64_MAX; + } else if (d > INT64_MAX + 1ULL) { + *(uint64_t *)dst = (llrint(d - (INT64_MAX + 1ULL)) + (INT64_MAX + 1ULL))*intnum; + } else { + *(uint64_t *)dst = llrint(d) * intnum; + } + break;} + case AV_OPT_TYPE_FLOAT: + *(float *)dst = num * intnum / den; + break; + case AV_OPT_TYPE_DOUBLE: + *(double *)dst = num * intnum / den; + break; + case AV_OPT_TYPE_RATIONAL: + case AV_OPT_TYPE_VIDEO_RATE: + if ((int) num == num) + *(AVRational *)dst = (AVRational) { num *intnum, den }; + else + *(AVRational *)dst = double_to_rational(num * intnum / den); + break; + default: + return AVERROR(EINVAL); + } + return 0; +} + +static int hexchar2int(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +static int set_string_binary(void *obj, const AVOption *o, const char *val, uint8_t **dst) +{ + int *lendst = (int *)(dst + 1); + uint8_t *bin, *ptr; + int len; + + av_freep(dst); + *lendst = 0; + + if (!val || !(len = strlen(val))) + return 0; + + if (len & 1) + return AVERROR(EINVAL); + len /= 2; + + ptr = bin = av_malloc(len); + if (!ptr) + return AVERROR(ENOMEM); + while (*val) { + int a = hexchar2int(*val++); + int b = hexchar2int(*val++); + if (a < 0 || b < 0) { + av_free(bin); + return AVERROR(EINVAL); + } + *ptr++ = (a << 4) | b; + } + *dst = bin; + *lendst = len; + + return 0; +} + +static int set_string(void *obj, const AVOption *o, const char *val, uint8_t **dst) +{ + av_freep(dst); + if (!val) + return 0; + *dst = av_strdup(val); + return *dst ? 0 : AVERROR(ENOMEM); +} + +#define DEFAULT_NUMVAL(opt) ((opt->type == AV_OPT_TYPE_INT64 || \ + opt->type == AV_OPT_TYPE_UINT64 || \ + opt->type == AV_OPT_TYPE_CONST || \ + opt->type == AV_OPT_TYPE_FLAGS || \ + opt->type == AV_OPT_TYPE_UINT || \ + opt->type == AV_OPT_TYPE_INT) \ + ? opt->default_val.i64 \ + : opt->default_val.dbl) + +static int set_string_number(void *obj, void *target_obj, const AVOption *o, const char *val, void *dst) +{ + const enum AVOptionType type = TYPE_BASE(o->type); + int ret = 0; + + if (type == AV_OPT_TYPE_RATIONAL || type == AV_OPT_TYPE_VIDEO_RATE) { + int num, den; + char c; + if (sscanf(val, "%d%*1[:/]%d%c", &num, &den, &c) == 2) { + if ((ret = write_number(obj, o, dst, 1, den, num)) >= 0) + return ret; + ret = 0; + } + } + + for (;;) { + int i = 0; + char buf[256]; + int cmd = 0; + double d; + int64_t intnum = 1; + + if (type == AV_OPT_TYPE_FLAGS) { + if (*val == '+' || *val == '-') + cmd = *(val++); + for (; i < sizeof(buf) - 1 && val[i] && val[i] != '+' && val[i] != '-'; i++) + buf[i] = val[i]; + buf[i] = 0; + } + + { + int res; + int ci = 0; + double const_values[64]; + const char * const_names[64]; + int search_flags = (o->flags & AV_OPT_FLAG_CHILD_CONSTS) ? AV_OPT_SEARCH_CHILDREN : 0; + const AVOption *o_named = av_opt_find(target_obj, i ? buf : val, o->unit, 0, search_flags); + if (o_named && o_named->type == AV_OPT_TYPE_CONST) { + d = DEFAULT_NUMVAL(o_named); + if (o_named->flags & AV_OPT_FLAG_DEPRECATED) + av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", + o_named->name, o_named->help); + } else { + if (o->unit) { + for (o_named = NULL; o_named = av_opt_next(target_obj, o_named); ) { + if (o_named->type == AV_OPT_TYPE_CONST && + o_named->unit && + !strcmp(o_named->unit, o->unit)) { + if (ci + 6 >= FF_ARRAY_ELEMS(const_values)) { + av_log(obj, AV_LOG_ERROR, "const_values array too small for %s\n", o->unit); + return AVERROR_PATCHWELCOME; + } + const_names [ci ] = o_named->name; + const_values[ci++] = DEFAULT_NUMVAL(o_named); + } + } + } + const_names [ci ] = "default"; + const_values[ci++] = DEFAULT_NUMVAL(o); + const_names [ci ] = "max"; + const_values[ci++] = o->max; + const_names [ci ] = "min"; + const_values[ci++] = o->min; + const_names [ci ] = "none"; + const_values[ci++] = 0; + const_names [ci ] = "all"; + const_values[ci++] = ~0; + const_names [ci] = NULL; + const_values[ci] = 0; + + res = av_expr_parse_and_eval(&d, i ? buf : val, const_names, + const_values, NULL, NULL, NULL, NULL, NULL, 0, obj); + if (res < 0) { + av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\"\n", o->name, val); + return res; + } + } + } + if (type == AV_OPT_TYPE_FLAGS) { + intnum = *(unsigned int*)dst; + if (cmd == '+') + d = intnum | (int64_t)d; + else if (cmd == '-') + d = intnum &~(int64_t)d; + } + + if ((ret = write_number(obj, o, dst, d, 1, 1)) < 0) + return ret; + val += i; + if (!i || !*val) + return 0; + } +} + +static int set_string_image_size(void *obj, const AVOption *o, const char *val, int *dst) +{ + int ret; + + if (!val || !strcmp(val, "none")) { + dst[0] = + dst[1] = 0; + return 0; + } + ret = av_parse_video_size(dst, dst + 1, val); + if (ret < 0) + av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as image size\n", o->name, val); + return ret; +} + +static int set_string_video_rate(void *obj, const AVOption *o, const char *val, AVRational *dst) +{ + int ret = av_parse_video_rate(dst, val); + if (ret < 0) + av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as video rate\n", o->name, val); + return ret; +} + +static int set_string_color(void *obj, const AVOption *o, const char *val, uint8_t *dst) +{ + int ret; + + if (!val) { + return 0; + } else { + ret = av_parse_color(dst, val, -1, obj); + if (ret < 0) + av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as color\n", o->name, val); + return ret; + } + return 0; +} + +static const char *get_bool_name(int val) +{ + if (val < 0) + return "auto"; + return val ? "true" : "false"; +} + +static int set_string_bool(void *obj, const AVOption *o, const char *val, int *dst) +{ + int n; + + if (!val) + return 0; + + if (!strcmp(val, "auto")) { + n = -1; + } else if (av_match_name(val, "true,y,yes,enable,enabled,on")) { + n = 1; + } else if (av_match_name(val, "false,n,no,disable,disabled,off")) { + n = 0; + } else { + char *end = NULL; + n = strtol(val, &end, 10); + if (val + strlen(val) != end) + goto fail; + } + + if (n < o->min || n > o->max) + goto fail; + + *dst = n; + return 0; + +fail: + av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as boolean\n", o->name, val); + return AVERROR(EINVAL); +} + +static int set_string_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst, + int fmt_nb, int ((*get_fmt)(const char *)), const char *desc) +{ + int fmt, min, max; + + if (!val || !strcmp(val, "none")) { + fmt = -1; + } else { + fmt = get_fmt(val); + if (fmt == -1) { + char *tail; + fmt = strtol(val, &tail, 0); + if (*tail || (unsigned)fmt >= fmt_nb) { + av_log(obj, AV_LOG_ERROR, + "Unable to parse \"%s\" option value \"%s\" as %s\n", o->name, val, desc); + return AVERROR(EINVAL); + } + } + } + + min = FFMAX(o->min, -1); + max = FFMIN(o->max, fmt_nb-1); + + // hack for compatibility with old ffmpeg + if(min == 0 && max == 0) { + min = -1; + max = fmt_nb-1; + } + + if (fmt < min || fmt > max) { + av_log(obj, AV_LOG_ERROR, + "Value %d for parameter '%s' out of %s format range [%d - %d]\n", + fmt, o->name, desc, min, max); + return AVERROR(ERANGE); + } + + *(int *)dst = fmt; + return 0; +} + +static int get_pix_fmt(const char *name) +{ + return av_get_pix_fmt(name); +} + +static int set_string_pixel_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst) +{ + return set_string_fmt(obj, o, val, dst, + AV_PIX_FMT_NB, get_pix_fmt, "pixel format"); +} + +static int get_sample_fmt(const char *name) +{ + return av_get_sample_fmt(name); +} + +static int set_string_sample_fmt(void *obj, const AVOption *o, const char *val, uint8_t *dst) +{ + return set_string_fmt(obj, o, val, dst, + AV_SAMPLE_FMT_NB, get_sample_fmt, "sample format"); +} + +static int set_string_dict(void *obj, const AVOption *o, const char *val, uint8_t **dst) +{ + AVDictionary *options = NULL; + + if (val) { + int ret = av_dict_parse_string(&options, val, "=", ":", 0); + if (ret < 0) { + av_dict_free(&options); + return ret; + } + } + + av_dict_free((AVDictionary **)dst); + *dst = (uint8_t *)options; + + return 0; +} + +static int set_string_channel_layout(void *obj, const AVOption *o, + const char *val, void *dst) +{ + AVChannelLayout *channel_layout = dst; + av_channel_layout_uninit(channel_layout); + if (!val) + return 0; + return av_channel_layout_from_string(channel_layout, val); +} + +static int opt_set_elem(void *obj, void *target_obj, const AVOption *o, + const char *val, void *dst) +{ + const enum AVOptionType type = TYPE_BASE(o->type); + int ret; + + if (!val && (type != AV_OPT_TYPE_STRING && + type != AV_OPT_TYPE_PIXEL_FMT && type != AV_OPT_TYPE_SAMPLE_FMT && + type != AV_OPT_TYPE_IMAGE_SIZE && + type != AV_OPT_TYPE_DURATION && type != AV_OPT_TYPE_COLOR && + type != AV_OPT_TYPE_BOOL)) + return AVERROR(EINVAL); + + switch (type) { + case AV_OPT_TYPE_BOOL: + return set_string_bool(obj, o, val, dst); + case AV_OPT_TYPE_STRING: + return set_string(obj, o, val, dst); + case AV_OPT_TYPE_BINARY: + return set_string_binary(obj, o, val, dst); + case AV_OPT_TYPE_FLAGS: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: + case AV_OPT_TYPE_FLOAT: + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_RATIONAL: + return set_string_number(obj, target_obj, o, val, dst); + case AV_OPT_TYPE_IMAGE_SIZE: + return set_string_image_size(obj, o, val, dst); + case AV_OPT_TYPE_VIDEO_RATE: { + AVRational tmp; + ret = set_string_video_rate(obj, o, val, &tmp); + if (ret < 0) + return ret; + return write_number(obj, o, dst, 1, tmp.den, tmp.num); + } + case AV_OPT_TYPE_PIXEL_FMT: + return set_string_pixel_fmt(obj, o, val, dst); + case AV_OPT_TYPE_SAMPLE_FMT: + return set_string_sample_fmt(obj, o, val, dst); + case AV_OPT_TYPE_DURATION: + { + int64_t usecs = 0; + if (val) { + if ((ret = av_parse_time(&usecs, val, 1)) < 0) { + av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as duration\n", o->name, val); + return ret; + } + } + if (usecs < o->min || usecs > o->max) { + av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n", + usecs / 1000000.0, o->name, o->min / 1000000.0, o->max / 1000000.0); + return AVERROR(ERANGE); + } + *(int64_t *)dst = usecs; + return 0; + } + case AV_OPT_TYPE_COLOR: + return set_string_color(obj, o, val, dst); + case AV_OPT_TYPE_CHLAYOUT: + ret = set_string_channel_layout(obj, o, val, dst); + if (ret < 0) { + av_log(obj, AV_LOG_ERROR, "Unable to parse \"%s\" option value \"%s\" as channel layout\n", o->name, val); + ret = AVERROR(EINVAL); + } + return ret; + case AV_OPT_TYPE_DICT: + return set_string_dict(obj, o, val, dst); + } + + av_log(obj, AV_LOG_ERROR, "Invalid option type.\n"); + return AVERROR(EINVAL); +} + +static int opt_set_array(void *obj, void *target_obj, const AVOption *o, + const char *val, void *dst) +{ + const AVOptionArrayDef *arr = o->default_val.arr; + const size_t elem_size = opt_type_desc[TYPE_BASE(o->type)].size; + const uint8_t sep = opt_array_sep(o); + uint8_t *str = NULL; + + void *elems = NULL; + unsigned nb_elems = 0; + int ret; + + if (val && *val) { + str = av_malloc(strlen(val) + 1); + if (!str) + return AVERROR(ENOMEM); + } + + // split and unescape the string + while (val && *val) { + uint8_t *p = str; + void *tmp; + + if (arr && arr->size_max && nb_elems >= arr->size_max) { + av_log(obj, AV_LOG_ERROR, + "Cannot assign more than %u elements to array option %s\n", + arr->size_max, o->name); + ret = AVERROR(EINVAL); + goto fail; + } + + for (; *val; val++, p++) { + if (*val == '\\' && val[1]) + val++; + else if (*val == sep) { + val++; + break; + } + *p = *val; + } + *p = 0; + + tmp = av_realloc_array(elems, nb_elems + 1, elem_size); + if (!tmp) { + ret = AVERROR(ENOMEM); + goto fail; + } + elems = tmp; + + tmp = opt_array_pelem(o, elems, nb_elems); + memset(tmp, 0, elem_size); + + ret = opt_set_elem(obj, target_obj, o, str, tmp); + if (ret < 0) + goto fail; + nb_elems++; + } + av_freep(&str); + + opt_free_array(o, dst, opt_array_pcount(dst)); + + if (arr && nb_elems < arr->size_min) { + av_log(obj, AV_LOG_ERROR, + "Cannot assign fewer than %u elements to array option %s\n", + arr->size_min, o->name); + ret = AVERROR(EINVAL); + goto fail; + } + + *((void **)dst) = elems; + *opt_array_pcount(dst) = nb_elems; + + return 0; +fail: + av_freep(&str); + opt_free_array(o, &elems, &nb_elems); + return ret; +} + +int av_opt_set(void *obj, const char *name, const char *val, int search_flags) +{ + void *dst, *target_obj; + const AVOption *o; + int ret; + + ret = opt_set_init(obj, name, search_flags, 0, &target_obj, &o, &dst); + if (ret < 0) + return ret; + + return ((o->type & AV_OPT_TYPE_FLAG_ARRAY) ? + opt_set_array : opt_set_elem)(obj, target_obj, o, val, dst); +} + +#define OPT_EVAL_NUMBER(name, opttype, vartype) \ +int av_opt_eval_ ## name(void *obj, const AVOption *o, \ + const char *val, vartype *name ## _out) \ +{ \ + if (!o || o->type != opttype || o->flags & AV_OPT_FLAG_READONLY) \ + return AVERROR(EINVAL); \ + return set_string_number(obj, obj, o, val, name ## _out); \ +} + +OPT_EVAL_NUMBER(flags, AV_OPT_TYPE_FLAGS, int) +OPT_EVAL_NUMBER(int, AV_OPT_TYPE_INT, int) +OPT_EVAL_NUMBER(uint, AV_OPT_TYPE_UINT, unsigned) +OPT_EVAL_NUMBER(int64, AV_OPT_TYPE_INT64, int64_t) +OPT_EVAL_NUMBER(float, AV_OPT_TYPE_FLOAT, float) +OPT_EVAL_NUMBER(double, AV_OPT_TYPE_DOUBLE, double) +OPT_EVAL_NUMBER(q, AV_OPT_TYPE_RATIONAL, AVRational) + +static int set_number(void *obj, const char *name, double num, int den, int64_t intnum, + int search_flags, int require_type) +{ + void *dst; + const AVOption *o; + int ret; + + ret = opt_set_init(obj, name, search_flags, require_type, NULL, &o, &dst); + if (ret < 0) + return ret; + + return write_number(obj, o, dst, num, den, intnum); +} + +int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags) +{ + return set_number(obj, name, 1, 1, val, search_flags, 0); +} + +int av_opt_set_double(void *obj, const char *name, double val, int search_flags) +{ + return set_number(obj, name, val, 1, 1, search_flags, 0); +} + +int av_opt_set_q(void *obj, const char *name, AVRational val, int search_flags) +{ + return set_number(obj, name, val.num, val.den, 1, search_flags, 0); +} + +int av_opt_set_bin(void *obj, const char *name, const uint8_t *val, int len, int search_flags) +{ + uint8_t *ptr; + uint8_t **dst; + int *lendst; + int ret; + + ret = opt_set_init(obj, name, search_flags, AV_OPT_TYPE_BINARY, + NULL, NULL, (void**)&dst); + if (ret < 0) + return ret; + + ptr = len ? av_malloc(len) : NULL; + if (len && !ptr) + return AVERROR(ENOMEM); + + lendst = (int *)(dst + 1); + + av_free(*dst); + *dst = ptr; + *lendst = len; + if (len) + memcpy(ptr, val, len); + + return 0; +} + +int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags) +{ + const AVOption *o; + int *dst; + int ret; + + ret = opt_set_init(obj, name, search_flags, AV_OPT_TYPE_IMAGE_SIZE, + NULL, &o, (void**)&dst); + if (ret < 0) + return ret; + + if (w<0 || h<0) { + av_log(obj, AV_LOG_ERROR, + "Invalid negative size value %dx%d for size '%s'\n", w, h, o->name); + return AVERROR(EINVAL); + } + + dst[0] = w; + dst[1] = h; + + return 0; +} + +int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags) +{ + return set_number(obj, name, val.num, val.den, 1, search_flags, AV_OPT_TYPE_VIDEO_RATE); +} + +static int set_format(void *obj, const char *name, int fmt, int search_flags, + enum AVOptionType type, const char *desc, int nb_fmts) +{ + const AVOption *o; + int *dst; + int min, max, ret; + + ret = opt_set_init(obj, name, search_flags, type, NULL, &o, (void**)&dst); + if (ret < 0) + return ret; + + min = FFMAX(o->min, -1); + max = FFMIN(o->max, nb_fmts-1); + + if (fmt < min || fmt > max) { + av_log(obj, AV_LOG_ERROR, + "Value %d for parameter '%s' out of %s format range [%d - %d]\n", + fmt, name, desc, min, max); + return AVERROR(ERANGE); + } + *dst = fmt; + return 0; +} + +int av_opt_set_pixel_fmt(void *obj, const char *name, enum AVPixelFormat fmt, int search_flags) +{ + return set_format(obj, name, fmt, search_flags, AV_OPT_TYPE_PIXEL_FMT, "pixel", AV_PIX_FMT_NB); +} + +int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags) +{ + return set_format(obj, name, fmt, search_flags, AV_OPT_TYPE_SAMPLE_FMT, "sample", AV_SAMPLE_FMT_NB); +} + +int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, + int search_flags) +{ + AVDictionary **dst; + int ret; + + ret = opt_set_init(obj, name, search_flags, AV_OPT_TYPE_DICT, NULL, NULL, + (void**)&dst); + if (ret < 0) + return ret; + + av_dict_free(dst); + + return av_dict_copy(dst, val, 0); +} + +int av_opt_set_chlayout(void *obj, const char *name, + const AVChannelLayout *channel_layout, + int search_flags) +{ + AVChannelLayout *dst; + int ret; + + ret = opt_set_init(obj, name, search_flags, AV_OPT_TYPE_CHLAYOUT, NULL, NULL, + (void**)&dst); + if (ret < 0) + return ret; + + return av_channel_layout_copy(dst, channel_layout); +} + +static void format_duration(char *buf, size_t size, int64_t d) +{ + char *e; + + av_assert0(size >= 25); + if (d < 0 && d != INT64_MIN) { + *(buf++) = '-'; + size--; + d = -d; + } + if (d == INT64_MAX) + snprintf(buf, size, "INT64_MAX"); + else if (d == INT64_MIN) + snprintf(buf, size, "INT64_MIN"); + else if (d > (int64_t)3600*1000000) + snprintf(buf, size, "%"PRId64":%02d:%02d.%06d", d / 3600000000, + (int)((d / 60000000) % 60), + (int)((d / 1000000) % 60), + (int)(d % 1000000)); + else if (d > 60*1000000) + snprintf(buf, size, "%d:%02d.%06d", + (int)(d / 60000000), + (int)((d / 1000000) % 60), + (int)(d % 1000000)); + else + snprintf(buf, size, "%d.%06d", + (int)(d / 1000000), + (int)(d % 1000000)); + e = buf + strlen(buf); + while (e > buf && e[-1] == '0') + *(--e) = 0; + if (e > buf && e[-1] == '.') + *(--e) = 0; +} + +static int opt_get_elem(const AVOption *o, uint8_t **pbuf, size_t buf_len, + const void *dst, int search_flags) +{ + int ret; + + switch (TYPE_BASE(o->type)) { + case AV_OPT_TYPE_BOOL: + ret = snprintf(*pbuf, buf_len, "%s", get_bool_name(*(int *)dst)); + break; + case AV_OPT_TYPE_FLAGS: + ret = snprintf(*pbuf, buf_len, "0x%08X", *(int *)dst); + break; + case AV_OPT_TYPE_INT: + ret = snprintf(*pbuf, buf_len, "%d", *(int *)dst); + break; + case AV_OPT_TYPE_UINT: + ret = snprintf(*pbuf, buf_len, "%u", *(unsigned *)dst); + break; + case AV_OPT_TYPE_INT64: + ret = snprintf(*pbuf, buf_len, "%"PRId64, *(int64_t *)dst); + break; + case AV_OPT_TYPE_UINT64: + ret = snprintf(*pbuf, buf_len, "%"PRIu64, *(uint64_t *)dst); + break; + case AV_OPT_TYPE_FLOAT: + ret = snprintf(*pbuf, buf_len, "%f", *(float *)dst); + break; + case AV_OPT_TYPE_DOUBLE: + ret = snprintf(*pbuf, buf_len, "%f", *(double *)dst); + break; + case AV_OPT_TYPE_VIDEO_RATE: + case AV_OPT_TYPE_RATIONAL: + ret = snprintf(*pbuf, buf_len, "%d/%d", ((AVRational *)dst)->num, ((AVRational *)dst)->den); + break; + case AV_OPT_TYPE_CONST: + ret = snprintf(*pbuf, buf_len, "%"PRId64, o->default_val.i64); + break; + case AV_OPT_TYPE_STRING: + if (*(uint8_t **)dst) { + *pbuf = av_strdup(*(uint8_t **)dst); + } else if (search_flags & AV_OPT_ALLOW_NULL) { + *pbuf = NULL; + return 0; + } else { + *pbuf = av_strdup(""); + } + return *pbuf ? 0 : AVERROR(ENOMEM); + case AV_OPT_TYPE_BINARY: { + const uint8_t *bin; + int len; + + if (!*(uint8_t **)dst && (search_flags & AV_OPT_ALLOW_NULL)) { + *pbuf = NULL; + return 0; + } + len = *(int *)(((uint8_t *)dst) + sizeof(uint8_t *)); + if ((uint64_t)len * 2 + 1 > INT_MAX) + return AVERROR(EINVAL); + if (!(*pbuf = av_malloc(len * 2 + 1))) + return AVERROR(ENOMEM); + if (!len) { + *pbuf[0] = '\0'; + return 0; + } + bin = *(uint8_t **)dst; + for (int i = 0; i < len; i++) + snprintf(*pbuf + i * 2, 3, "%02X", bin[i]); + return 0; + } + case AV_OPT_TYPE_IMAGE_SIZE: + ret = snprintf(*pbuf, buf_len, "%dx%d", ((int *)dst)[0], ((int *)dst)[1]); + break; + case AV_OPT_TYPE_PIXEL_FMT: + ret = snprintf(*pbuf, buf_len, "%s", (char *)av_x_if_null(av_get_pix_fmt_name(*(enum AVPixelFormat *)dst), "none")); + break; + case AV_OPT_TYPE_SAMPLE_FMT: + ret = snprintf(*pbuf, buf_len, "%s", (char *)av_x_if_null(av_get_sample_fmt_name(*(enum AVSampleFormat *)dst), "none")); + break; + case AV_OPT_TYPE_DURATION: { + int64_t i64 = *(int64_t *)dst; + format_duration(*pbuf, buf_len, i64); + ret = strlen(*pbuf); // no overflow possible, checked by an assert + break; + } + case AV_OPT_TYPE_COLOR: + ret = snprintf(*pbuf, buf_len, "0x%02x%02x%02x%02x", + (int)((uint8_t *)dst)[0], (int)((uint8_t *)dst)[1], + (int)((uint8_t *)dst)[2], (int)((uint8_t *)dst)[3]); + break; + case AV_OPT_TYPE_CHLAYOUT: + ret = av_channel_layout_describe(dst, *pbuf, buf_len); + break; + case AV_OPT_TYPE_DICT: + if (!*(AVDictionary **)dst && (search_flags & AV_OPT_ALLOW_NULL)) { + *pbuf = NULL; + return 0; + } + return av_dict_get_string(*(AVDictionary **)dst, (char **)pbuf, '=', ':'); + default: + return AVERROR(EINVAL); + } + + return ret; +} + +static int opt_get_array(const AVOption *o, void *dst, uint8_t **out_val) +{ + const unsigned count = *opt_array_pcount(dst); + const uint8_t sep = opt_array_sep(o); + + uint8_t *str = NULL; + size_t str_len = 0; + int ret; + + *out_val = NULL; + + for (unsigned i = 0; i < count; i++) { + uint8_t buf[128], *out = buf; + size_t out_len; + + ret = opt_get_elem(o, &out, sizeof(buf), + opt_array_pelem(o, *(void **)dst, i), 0); + if (ret < 0) + goto fail; + + out_len = strlen(out); + if (out_len > SIZE_MAX / 2 - !!i || + !!i + out_len * 2 > SIZE_MAX - str_len - 1) { + ret = AVERROR(ERANGE); + goto fail; + } + + // terminator escaping separator + // ↓ ↓ ↓ + ret = av_reallocp(&str, str_len + 1 + out_len * 2 + !!i); + if (ret < 0) + goto fail; + + // add separator if needed + if (i) + str[str_len++] = sep; + + // escape the element + for (unsigned j = 0; j < out_len; j++) { + uint8_t val = out[j]; + if (val == sep || val == '\\') + str[str_len++] = '\\'; + str[str_len++] = val; + } + str[str_len] = 0; + +fail: + if (out != buf) + av_freep(&out); + if (ret < 0) { + av_freep(&str); + return ret; + } + } + + *out_val = str; + + return 0; +} + +int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val) +{ + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + uint8_t *out, buf[128]; + int ret; + + if (!o || !target_obj || (o->offset<=0 && o->type != AV_OPT_TYPE_CONST)) + return AVERROR_OPTION_NOT_FOUND; + + if (o->flags & AV_OPT_FLAG_DEPRECATED) + av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); + + dst = (uint8_t *)target_obj + o->offset; + + if (o->type & AV_OPT_TYPE_FLAG_ARRAY) { + ret = opt_get_array(o, dst, out_val); + if (ret < 0) + return ret; + if (!*out_val && !(search_flags & AV_OPT_ALLOW_NULL)) { + *out_val = av_strdup(""); + if (!*out_val) + return AVERROR(ENOMEM); + } + return 0; + } + + buf[0] = 0; + out = buf; + ret = opt_get_elem(o, &out, sizeof(buf), dst, search_flags); + if (ret < 0) + return ret; + if (out != buf) { + *out_val = out; + return 0; + } + + if (ret >= sizeof(buf)) + return AVERROR(EINVAL); + *out_val = av_strdup(out); + return *out_val ? 0 : AVERROR(ENOMEM); +} + +static int get_number(void *obj, const char *name, double *num, int *den, int64_t *intnum, + int search_flags) +{ + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->type & AV_OPT_TYPE_FLAG_ARRAY) + return AVERROR(EINVAL); + + dst = ((uint8_t *)target_obj) + o->offset; + + return read_number(o, dst, num, den, intnum); +} + +int av_opt_get_int(void *obj, const char *name, int search_flags, int64_t *out_val) +{ + int64_t intnum = 1; + double num = 1; + int ret, den = 1; + + if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0) + return ret; + if (num == den) + *out_val = intnum; + else + *out_val = num * intnum / den; + return 0; +} + +int av_opt_get_double(void *obj, const char *name, int search_flags, double *out_val) +{ + int64_t intnum = 1; + double num = 1; + int ret, den = 1; + + if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0) + return ret; + *out_val = num * intnum / den; + return 0; +} + +int av_opt_get_q(void *obj, const char *name, int search_flags, AVRational *out_val) +{ + int64_t intnum = 1; + double num = 1; + int ret, den = 1; + + if ((ret = get_number(obj, name, &num, &den, &intnum, search_flags)) < 0) + return ret; + + if (num == 1.0 && (int)intnum == intnum) + *out_val = (AVRational){intnum, den}; + else + *out_val = double_to_rational(num*intnum/den); + return 0; +} + +int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_out, int *h_out) +{ + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->type != AV_OPT_TYPE_IMAGE_SIZE) { + av_log(obj, AV_LOG_ERROR, + "The value for option '%s' is not a image size.\n", name); + return AVERROR(EINVAL); + } + + dst = ((uint8_t*)target_obj) + o->offset; + if (w_out) *w_out = *(int *)dst; + if (h_out) *h_out = *((int *)dst+1); + return 0; +} + +int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val) +{ + return av_opt_get_q(obj, name, search_flags, out_val); +} + +static int get_format(void *obj, const char *name, int search_flags, void *out_fmt, + enum AVOptionType type, const char *desc) +{ + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->type != type) { + av_log(obj, AV_LOG_ERROR, + "The value for option '%s' is not a %s format.\n", desc, name); + return AVERROR(EINVAL); + } + + dst = ((uint8_t*)target_obj) + o->offset; + if (type == AV_OPT_TYPE_PIXEL_FMT) + *(enum AVPixelFormat *)out_fmt = *(enum AVPixelFormat *)dst; + else + *(enum AVSampleFormat*)out_fmt = *(enum AVSampleFormat*)dst; + + return 0; +} + +int av_opt_get_pixel_fmt(void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt) +{ + return get_format(obj, name, search_flags, out_fmt, AV_OPT_TYPE_PIXEL_FMT, "pixel"); +} + +int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt) +{ + return get_format(obj, name, search_flags, out_fmt, AV_OPT_TYPE_SAMPLE_FMT, "sample"); +} + +int av_opt_get_chlayout(void *obj, const char *name, int search_flags, AVChannelLayout *cl) +{ + void *dst, *target_obj; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->type != AV_OPT_TYPE_CHLAYOUT) { + av_log(obj, AV_LOG_ERROR, + "The value for option '%s' is not a channel layout.\n", name); + return AVERROR(EINVAL); + } + + dst = ((uint8_t*)target_obj) + o->offset; + return av_channel_layout_copy(cl, dst); +} + +int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val) +{ + void *target_obj; + AVDictionary *src; + const AVOption *o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (o->type != AV_OPT_TYPE_DICT) + return AVERROR(EINVAL); + + src = *(AVDictionary **)(((uint8_t *)target_obj) + o->offset); + + return av_dict_copy(out_val, src, 0); +} + +int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name) +{ + const AVOption *field = av_opt_find(obj, field_name, NULL, 0, 0); + const AVOption *flag = av_opt_find(obj, flag_name, + field ? field->unit : NULL, 0, 0); + int64_t res; + + if (!field || !flag || flag->type != AV_OPT_TYPE_CONST || + av_opt_get_int(obj, field_name, 0, &res) < 0) + return 0; + return res & flag->default_val.i64; +} + +static void log_int_value(void *av_log_obj, int level, int64_t i) +{ + if (i == INT_MAX) { + av_log(av_log_obj, level, "INT_MAX"); + } else if (i == INT_MIN) { + av_log(av_log_obj, level, "INT_MIN"); + } else if (i == UINT32_MAX) { + av_log(av_log_obj, level, "UINT32_MAX"); + } else if (i == INT64_MAX) { + av_log(av_log_obj, level, "I64_MAX"); + } else if (i == INT64_MIN) { + av_log(av_log_obj, level, "I64_MIN"); + } else { + av_log(av_log_obj, level, "%"PRId64, i); + } +} + +static void log_value(void *av_log_obj, int level, double d) +{ + if (d == INT_MAX) { + av_log(av_log_obj, level, "INT_MAX"); + } else if (d == INT_MIN) { + av_log(av_log_obj, level, "INT_MIN"); + } else if (d == UINT32_MAX) { + av_log(av_log_obj, level, "UINT32_MAX"); + } else if (d == (double)INT64_MAX) { + av_log(av_log_obj, level, "I64_MAX"); + } else if (d == INT64_MIN) { + av_log(av_log_obj, level, "I64_MIN"); + } else if (d == FLT_MAX) { + av_log(av_log_obj, level, "FLT_MAX"); + } else if (d == FLT_MIN) { + av_log(av_log_obj, level, "FLT_MIN"); + } else if (d == -FLT_MAX) { + av_log(av_log_obj, level, "-FLT_MAX"); + } else if (d == -FLT_MIN) { + av_log(av_log_obj, level, "-FLT_MIN"); + } else if (d == DBL_MAX) { + av_log(av_log_obj, level, "DBL_MAX"); + } else if (d == DBL_MIN) { + av_log(av_log_obj, level, "DBL_MIN"); + } else if (d == -DBL_MAX) { + av_log(av_log_obj, level, "-DBL_MAX"); + } else if (d == -DBL_MIN) { + av_log(av_log_obj, level, "-DBL_MIN"); + } else { + av_log(av_log_obj, level, "%g", d); + } +} + +static const char *get_opt_const_name(void *obj, const char *unit, int64_t value) +{ + const AVOption *opt = NULL; + + if (!unit) + return NULL; + while ((opt = av_opt_next(obj, opt))) + if (opt->type == AV_OPT_TYPE_CONST && !strcmp(opt->unit, unit) && + opt->default_val.i64 == value) + return opt->name; + return NULL; +} + +static char *get_opt_flags_string(void *obj, const char *unit, int64_t value) +{ + const AVOption *opt = NULL; + char flags[512]; + + flags[0] = 0; + if (!unit) + return NULL; + while ((opt = av_opt_next(obj, opt))) { + if (opt->type == AV_OPT_TYPE_CONST && !strcmp(opt->unit, unit) && + opt->default_val.i64 & value) { + if (flags[0]) + av_strlcatf(flags, sizeof(flags), "+"); + av_strlcatf(flags, sizeof(flags), "%s", opt->name); + } + } + if (flags[0]) + return av_strdup(flags); + return NULL; +} + +static void log_type(void *av_log_obj, const AVOption *o, + enum AVOptionType parent_type) +{ + const enum AVOptionType type = TYPE_BASE(o->type); + + if (o->type == AV_OPT_TYPE_CONST && (TYPE_BASE(parent_type) == AV_OPT_TYPE_INT || TYPE_BASE(parent_type) == AV_OPT_TYPE_INT64)) + av_log(av_log_obj, AV_LOG_INFO, "%-12"PRId64" ", o->default_val.i64); + else if (type < FF_ARRAY_ELEMS(opt_type_desc) && opt_type_desc[type].name) { + if (o->type & AV_OPT_TYPE_FLAG_ARRAY) + av_log(av_log_obj, AV_LOG_INFO, "[%-10s]", opt_type_desc[type].name); + else + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", opt_type_desc[type].name); + } + else + av_log(av_log_obj, AV_LOG_INFO, "%-12s ", ""); +} + +static void log_default(void *obj, void *av_log_obj, const AVOption *opt) +{ + if (opt->type == AV_OPT_TYPE_CONST || opt->type == AV_OPT_TYPE_BINARY) + return; + if ((opt->type == AV_OPT_TYPE_COLOR || + opt->type == AV_OPT_TYPE_IMAGE_SIZE || + opt->type == AV_OPT_TYPE_STRING || + opt->type == AV_OPT_TYPE_DICT || + opt->type == AV_OPT_TYPE_CHLAYOUT || + opt->type == AV_OPT_TYPE_VIDEO_RATE) && + !opt->default_val.str) + return; + + if (opt->type & AV_OPT_TYPE_FLAG_ARRAY) { + const AVOptionArrayDef *arr = opt->default_val.arr; + if (arr && arr->def) + av_log(av_log_obj, AV_LOG_INFO, " (default %s)", arr->def); + return; + } + + av_log(av_log_obj, AV_LOG_INFO, " (default "); + switch (opt->type) { + case AV_OPT_TYPE_BOOL: + av_log(av_log_obj, AV_LOG_INFO, "%s", get_bool_name(opt->default_val.i64)); + break; + case AV_OPT_TYPE_FLAGS: { + char *def_flags = get_opt_flags_string(obj, opt->unit, opt->default_val.i64); + if (def_flags) { + av_log(av_log_obj, AV_LOG_INFO, "%s", def_flags); + av_freep(&def_flags); + } else { + av_log(av_log_obj, AV_LOG_INFO, "%"PRIX64, opt->default_val.i64); + } + break; + } + case AV_OPT_TYPE_DURATION: { + char buf[25]; + format_duration(buf, sizeof(buf), opt->default_val.i64); + av_log(av_log_obj, AV_LOG_INFO, "%s", buf); + break; + } + case AV_OPT_TYPE_UINT: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT64: + case AV_OPT_TYPE_INT64: { + const char *def_const = get_opt_const_name(obj, opt->unit, opt->default_val.i64); + if (def_const) + av_log(av_log_obj, AV_LOG_INFO, "%s", def_const); + else + log_int_value(av_log_obj, AV_LOG_INFO, opt->default_val.i64); + break; + } + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_FLOAT: + log_value(av_log_obj, AV_LOG_INFO, opt->default_val.dbl); + break; + case AV_OPT_TYPE_RATIONAL: { + AVRational q = av_d2q(opt->default_val.dbl, INT_MAX); + av_log(av_log_obj, AV_LOG_INFO, "%d/%d", q.num, q.den); } + break; + case AV_OPT_TYPE_PIXEL_FMT: + av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_pix_fmt_name(opt->default_val.i64), "none")); + break; + case AV_OPT_TYPE_SAMPLE_FMT: + av_log(av_log_obj, AV_LOG_INFO, "%s", (char *)av_x_if_null(av_get_sample_fmt_name(opt->default_val.i64), "none")); + break; + case AV_OPT_TYPE_COLOR: + case AV_OPT_TYPE_IMAGE_SIZE: + case AV_OPT_TYPE_STRING: + case AV_OPT_TYPE_DICT: + case AV_OPT_TYPE_VIDEO_RATE: + case AV_OPT_TYPE_CHLAYOUT: + av_log(av_log_obj, AV_LOG_INFO, "\"%s\"", opt->default_val.str); + break; + } + av_log(av_log_obj, AV_LOG_INFO, ")"); +} + +static void opt_list(void *obj, void *av_log_obj, const char *unit, + int req_flags, int rej_flags, enum AVOptionType parent_type) +{ + const AVOption *opt = NULL; + AVOptionRanges *r; + int i; + + while ((opt = av_opt_next(obj, opt))) { + if (!(opt->flags & req_flags) || (opt->flags & rej_flags)) + continue; + + /* Don't print CONST's on level one. + * Don't print anything but CONST's on level two. + * Only print items from the requested unit. + */ + if (!unit && opt->type == AV_OPT_TYPE_CONST) + continue; + else if (unit && opt->type != AV_OPT_TYPE_CONST) + continue; + else if (unit && opt->type == AV_OPT_TYPE_CONST && strcmp(unit, opt->unit)) + continue; + else if (unit && opt->type == AV_OPT_TYPE_CONST) + av_log(av_log_obj, AV_LOG_INFO, " %-15s ", opt->name); + else + av_log(av_log_obj, AV_LOG_INFO, " %s%-17s ", + (opt->flags & AV_OPT_FLAG_FILTERING_PARAM) ? " " : "-", + opt->name); + + log_type(av_log_obj, opt, parent_type); + + av_log(av_log_obj, AV_LOG_INFO, "%c%c%c%c%c%c%c%c%c%c%c", + (opt->flags & AV_OPT_FLAG_ENCODING_PARAM) ? 'E' : '.', + (opt->flags & AV_OPT_FLAG_DECODING_PARAM) ? 'D' : '.', + (opt->flags & AV_OPT_FLAG_FILTERING_PARAM) ? 'F' : '.', + (opt->flags & AV_OPT_FLAG_VIDEO_PARAM) ? 'V' : '.', + (opt->flags & AV_OPT_FLAG_AUDIO_PARAM) ? 'A' : '.', + (opt->flags & AV_OPT_FLAG_SUBTITLE_PARAM) ? 'S' : '.', + (opt->flags & AV_OPT_FLAG_EXPORT) ? 'X' : '.', + (opt->flags & AV_OPT_FLAG_READONLY) ? 'R' : '.', + (opt->flags & AV_OPT_FLAG_BSF_PARAM) ? 'B' : '.', + (opt->flags & AV_OPT_FLAG_RUNTIME_PARAM) ? 'T' : '.', + (opt->flags & AV_OPT_FLAG_DEPRECATED) ? 'P' : '.'); + + if (opt->help) + av_log(av_log_obj, AV_LOG_INFO, " %s", opt->help); + + if (av_opt_query_ranges(&r, obj, opt->name, AV_OPT_SEARCH_FAKE_OBJ) >= 0) { + switch (opt->type) { + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_FLOAT: + case AV_OPT_TYPE_RATIONAL: + for (i = 0; i < r->nb_ranges; i++) { + av_log(av_log_obj, AV_LOG_INFO, " (from "); + log_value(av_log_obj, AV_LOG_INFO, r->range[i]->value_min); + av_log(av_log_obj, AV_LOG_INFO, " to "); + log_value(av_log_obj, AV_LOG_INFO, r->range[i]->value_max); + av_log(av_log_obj, AV_LOG_INFO, ")"); + } + break; + } + av_opt_freep_ranges(&r); + } + + log_default(obj, av_log_obj, opt); + + av_log(av_log_obj, AV_LOG_INFO, "\n"); + if (opt->unit && opt->type != AV_OPT_TYPE_CONST) + opt_list(obj, av_log_obj, opt->unit, req_flags, rej_flags, opt->type); + } +} + +int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags) +{ + if (!obj) + return -1; + + av_log(av_log_obj, AV_LOG_INFO, "%s AVOptions:\n", (*(AVClass **)obj)->class_name); + + opt_list(obj, av_log_obj, NULL, req_flags, rej_flags, -1); + + return 0; +} + +void av_opt_set_defaults(void *s) +{ + av_opt_set_defaults2(s, 0, 0); +} + +void av_opt_set_defaults2(void *s, int mask, int flags) +{ + const AVOption *opt = NULL; + while ((opt = av_opt_next(s, opt))) { + void *dst = ((uint8_t*)s) + opt->offset; + + if ((opt->flags & mask) != flags) + continue; + + if (opt->flags & AV_OPT_FLAG_READONLY) + continue; + + if (opt->type & AV_OPT_TYPE_FLAG_ARRAY) { + const AVOptionArrayDef *arr = opt->default_val.arr; + const char sep = opt_array_sep(opt); + + av_assert0(sep && sep != '\\' && + (sep < 'a' || sep > 'z') && + (sep < 'A' || sep > 'Z') && + (sep < '0' || sep > '9')); + + if (arr && arr->def) + opt_set_array(s, s, opt, arr->def, dst); + + continue; + } + + switch (opt->type) { + case AV_OPT_TYPE_CONST: + /* Nothing to be done here */ + break; + case AV_OPT_TYPE_BOOL: + case AV_OPT_TYPE_FLAGS: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: + case AV_OPT_TYPE_DURATION: + case AV_OPT_TYPE_PIXEL_FMT: + case AV_OPT_TYPE_SAMPLE_FMT: + write_number(s, opt, dst, 1, 1, opt->default_val.i64); + break; + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_FLOAT: { + double val; + val = opt->default_val.dbl; + write_number(s, opt, dst, val, 1, 1); + } + break; + case AV_OPT_TYPE_RATIONAL: { + AVRational val; + val = av_d2q(opt->default_val.dbl, INT_MAX); + write_number(s, opt, dst, 1, val.den, val.num); + } + break; + case AV_OPT_TYPE_COLOR: + set_string_color(s, opt, opt->default_val.str, dst); + break; + case AV_OPT_TYPE_STRING: + set_string(s, opt, opt->default_val.str, dst); + break; + case AV_OPT_TYPE_IMAGE_SIZE: + set_string_image_size(s, opt, opt->default_val.str, dst); + break; + case AV_OPT_TYPE_VIDEO_RATE: + set_string_video_rate(s, opt, opt->default_val.str, dst); + break; + case AV_OPT_TYPE_BINARY: + set_string_binary(s, opt, opt->default_val.str, dst); + break; + case AV_OPT_TYPE_CHLAYOUT: + set_string_channel_layout(s, opt, opt->default_val.str, dst); + break; + case AV_OPT_TYPE_DICT: + set_string_dict(s, opt, opt->default_val.str, dst); + break; + default: + av_log(s, AV_LOG_DEBUG, "AVOption type %d of option %s not implemented yet\n", + opt->type, opt->name); + } + } +} + +/** + * Store the value in the field in ctx that is named like key. + * ctx must be an AVClass context, storing is done using AVOptions. + * + * @param buf the string to parse, buf will be updated to point at the + * separator just after the parsed key/value pair + * @param key_val_sep a 0-terminated list of characters used to + * separate key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @return 0 if the key/value pair has been successfully parsed and + * set, or a negative value corresponding to an AVERROR code in case + * of error: + * AVERROR(EINVAL) if the key/value pair cannot be parsed, + * the error code issued by av_opt_set() if the key/value pair + * cannot be set + */ +static int parse_key_value_pair(void *ctx, const char **buf, + const char *key_val_sep, const char *pairs_sep) +{ + char *key = av_get_token(buf, key_val_sep); + char *val; + int ret; + + if (!key) + return AVERROR(ENOMEM); + + if (*key && strspn(*buf, key_val_sep)) { + (*buf)++; + val = av_get_token(buf, pairs_sep); + if (!val) { + av_freep(&key); + return AVERROR(ENOMEM); + } + } else { + av_log(ctx, AV_LOG_ERROR, "Missing key or no key/value separator found after key '%s'\n", key); + av_free(key); + return AVERROR(EINVAL); + } + + av_log(ctx, AV_LOG_DEBUG, "Setting entry with key '%s' to value '%s'\n", key, val); + + ret = av_opt_set(ctx, key, val, AV_OPT_SEARCH_CHILDREN); + if (ret == AVERROR_OPTION_NOT_FOUND) + av_log(ctx, AV_LOG_ERROR, "Key '%s' not found.\n", key); + + av_free(key); + av_free(val); + return ret; +} + +int av_set_options_string(void *ctx, const char *opts, + const char *key_val_sep, const char *pairs_sep) +{ + int ret, count = 0; + + if (!opts) + return 0; + + while (*opts) { + if ((ret = parse_key_value_pair(ctx, &opts, key_val_sep, pairs_sep)) < 0) + return ret; + count++; + + if (*opts) + opts++; + } + + return count; +} + +#define WHITESPACES " \n\t\r" + +static int is_key_char(char c) +{ + return (unsigned)((c | 32) - 'a') < 26 || + (unsigned)(c - '0') < 10 || + c == '-' || c == '_' || c == '/' || c == '.'; +} + +/** + * Read a key from a string. + * + * The key consists of is_key_char characters and must be terminated by a + * character from the delim string; spaces are ignored. + * + * @return 0 for success (even with ellipsis), <0 for failure + */ +static int get_key(const char **ropts, const char *delim, char **rkey) +{ + const char *opts = *ropts; + const char *key_start, *key_end; + + key_start = opts += strspn(opts, WHITESPACES); + while (is_key_char(*opts)) + opts++; + key_end = opts; + opts += strspn(opts, WHITESPACES); + if (!*opts || !strchr(delim, *opts)) + return AVERROR(EINVAL); + opts++; + if (!(*rkey = av_malloc(key_end - key_start + 1))) + return AVERROR(ENOMEM); + memcpy(*rkey, key_start, key_end - key_start); + (*rkey)[key_end - key_start] = 0; + *ropts = opts; + return 0; +} + +int av_opt_get_key_value(const char **ropts, + const char *key_val_sep, const char *pairs_sep, + unsigned flags, + char **rkey, char **rval) +{ + int ret; + char *key = NULL, *val; + const char *opts = *ropts; + + if ((ret = get_key(&opts, key_val_sep, &key)) < 0 && + !(flags & AV_OPT_FLAG_IMPLICIT_KEY)) + return AVERROR(EINVAL); + if (!(val = av_get_token(&opts, pairs_sep))) { + av_free(key); + return AVERROR(ENOMEM); + } + *ropts = opts; + *rkey = key; + *rval = val; + return 0; +} + +int av_opt_set_from_string(void *ctx, const char *opts, + const char *const *shorthand, + const char *key_val_sep, const char *pairs_sep) +{ + int ret, count = 0; + const char *dummy_shorthand = NULL; + const char *key; + + if (!opts) + return 0; + if (!shorthand) + shorthand = &dummy_shorthand; + + while (*opts) { + char *parsed_key, *value; + ret = av_opt_get_key_value(&opts, key_val_sep, pairs_sep, + *shorthand ? AV_OPT_FLAG_IMPLICIT_KEY : 0, + &parsed_key, &value); + if (ret < 0) { + if (ret == AVERROR(EINVAL)) + av_log(ctx, AV_LOG_ERROR, "No option name near '%s'\n", opts); + else + av_log(ctx, AV_LOG_ERROR, "Unable to parse '%s': %s\n", opts, + av_err2str(ret)); + return ret; + } + if (*opts) + opts++; + if (parsed_key) { + key = parsed_key; + while (*shorthand) /* discard all remaining shorthand */ + shorthand++; + } else { + key = *(shorthand++); + } + + av_log(ctx, AV_LOG_DEBUG, "Setting '%s' to value '%s'\n", key, value); + if ((ret = av_opt_set(ctx, key, value, 0)) < 0) { + if (ret == AVERROR_OPTION_NOT_FOUND) + av_log(ctx, AV_LOG_ERROR, "Option '%s' not found\n", key); + av_free(value); + av_free(parsed_key); + return ret; + } + + av_free(value); + av_free(parsed_key); + count++; + } + return count; +} + +void av_opt_free(void *obj) +{ + const AVOption *o = NULL; + while ((o = av_opt_next(obj, o))) { + void *pitem = (uint8_t *)obj + o->offset; + + if (o->type & AV_OPT_TYPE_FLAG_ARRAY) + opt_free_array(o, pitem, opt_array_pcount(pitem)); + else + opt_free_elem(o->type, pitem); + } +} + +int av_opt_set_dict2(void *obj, AVDictionary **options, int search_flags) +{ + const AVDictionaryEntry *t = NULL; + AVDictionary *tmp = NULL; + int ret; + + if (!options) + return 0; + + while ((t = av_dict_iterate(*options, t))) { + ret = av_opt_set(obj, t->key, t->value, search_flags); + if (ret == AVERROR_OPTION_NOT_FOUND) + ret = av_dict_set(&tmp, t->key, t->value, AV_DICT_MULTIKEY); + if (ret < 0) { + av_log(obj, AV_LOG_ERROR, "Error setting option %s to value %s.\n", t->key, t->value); + av_dict_free(&tmp); + return ret; + } + } + av_dict_free(options); + *options = tmp; + return 0; +} + +int av_opt_set_dict(void *obj, AVDictionary **options) +{ + return av_opt_set_dict2(obj, options, 0); +} + +const AVOption *av_opt_find(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags) +{ + return av_opt_find2(obj, name, unit, opt_flags, search_flags, NULL); +} + +const AVOption *av_opt_find2(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags, void **target_obj) +{ + const AVClass *c; + const AVOption *o = NULL; + + if(!obj) + return NULL; + + c= *(AVClass**)obj; + + if (!c) + return NULL; + + if (search_flags & AV_OPT_SEARCH_CHILDREN) { + if (search_flags & AV_OPT_SEARCH_FAKE_OBJ) { + void *iter = NULL; + const AVClass *child; + while (child = av_opt_child_class_iterate(c, &iter)) + if (o = av_opt_find2(&child, name, unit, opt_flags, search_flags, NULL)) + return o; + } else { + void *child = NULL; + while (child = av_opt_child_next(obj, child)) + if (o = av_opt_find2(child, name, unit, opt_flags, search_flags, target_obj)) + return o; + } + } + + while (o = av_opt_next(obj, o)) { + if (!strcmp(o->name, name) && (o->flags & opt_flags) == opt_flags && + ((!unit && o->type != AV_OPT_TYPE_CONST) || + (unit && o->type == AV_OPT_TYPE_CONST && o->unit && !strcmp(o->unit, unit)))) { + if (target_obj) { + if (!(search_flags & AV_OPT_SEARCH_FAKE_OBJ)) + *target_obj = obj; + else + *target_obj = NULL; + } + return o; + } + } + return NULL; +} + +void *av_opt_child_next(void *obj, void *prev) +{ + const AVClass *c = *(AVClass **)obj; + if (c->child_next) + return c->child_next(obj, prev); + return NULL; +} + +const AVClass *av_opt_child_class_iterate(const AVClass *parent, void **iter) +{ + if (parent->child_class_iterate) + return parent->child_class_iterate(iter); + return NULL; +} + +#if FF_API_OPT_PTR +void *av_opt_ptr(const AVClass *class, void *obj, const char *name) +{ + const AVOption *opt= av_opt_find2(&class, name, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ, NULL); + + // no direct access to array-type options + if (!opt || (opt->type & AV_OPT_TYPE_FLAG_ARRAY)) + return NULL; + return (uint8_t*)obj + opt->offset; +} +#endif + +static int opt_copy_elem(void *logctx, enum AVOptionType type, + void *dst, const void *src) +{ + if (type == AV_OPT_TYPE_STRING) { + const char *src_str = *(const char *const *)src; + char **dstp = (char **)dst; + if (*dstp != src_str) + av_freep(dstp); + if (src_str) { + *dstp = av_strdup(src_str); + if (!*dstp) + return AVERROR(ENOMEM); + } + } else if (type == AV_OPT_TYPE_BINARY) { + const uint8_t *const *src8 = (const uint8_t *const *)src; + uint8_t **dst8 = (uint8_t **)dst; + int len = *(const int *)(src8 + 1); + if (*dst8 != *src8) + av_freep(dst8); + *dst8 = av_memdup(*src8, len); + if (len && !*dst8) { + *(int *)(dst8 + 1) = 0; + return AVERROR(ENOMEM); + } + *(int *)(dst8 + 1) = len; + } else if (type == AV_OPT_TYPE_CONST) { + // do nothing + } else if (type == AV_OPT_TYPE_DICT) { + const AVDictionary *sdict = *(const AVDictionary * const *)src; + AVDictionary **ddictp = (AVDictionary **)dst; + if (sdict != *ddictp) + av_dict_free(ddictp); + *ddictp = NULL; + return av_dict_copy(ddictp, sdict, 0); + } else if (type == AV_OPT_TYPE_CHLAYOUT) { + if (dst != src) + return av_channel_layout_copy(dst, src); + } else if (opt_is_pod(type)) { + size_t size = opt_type_desc[type].size; + memcpy(dst, src, size); + } else { + av_log(logctx, AV_LOG_ERROR, "Unhandled option type: %d\n", type); + return AVERROR(EINVAL); + } + + return 0; +} + +static int opt_copy_array(void *logctx, const AVOption *o, + void **pdst, const void * const *psrc) +{ + unsigned nb_elems = *opt_array_pcount(psrc); + void *dst = NULL; + int ret; + + if (*pdst == *psrc) { + *pdst = NULL; + *opt_array_pcount(pdst) = 0; + } + + opt_free_array(o, pdst, opt_array_pcount(pdst)); + + dst = av_calloc(nb_elems, opt_type_desc[TYPE_BASE(o->type)].size); + if (!dst) + return AVERROR(ENOMEM); + + for (unsigned i = 0; i < nb_elems; i++) { + ret = opt_copy_elem(logctx, TYPE_BASE(o->type), + opt_array_pelem(o, dst, i), + opt_array_pelem(o, *(void**)psrc, i)); + if (ret < 0) { + opt_free_array(o, &dst, &nb_elems); + return ret; + } + } + + *pdst = dst; + *opt_array_pcount(pdst) = nb_elems; + + return 0; +} + +int av_opt_copy(void *dst, const void *src) +{ + const AVOption *o = NULL; + const AVClass *c; + int ret = 0; + + if (!src) + return AVERROR(EINVAL); + + c = *(AVClass **)src; + if (!c || c != *(AVClass **)dst) + return AVERROR(EINVAL); + + while ((o = av_opt_next(src, o))) { + void *field_dst = (uint8_t *)dst + o->offset; + void *field_src = (uint8_t *)src + o->offset; + + int err = (o->type & AV_OPT_TYPE_FLAG_ARRAY) ? + opt_copy_array(dst, o, field_dst, field_src) : + opt_copy_elem (dst, o->type, field_dst, field_src); + if (err < 0) + ret = err; + } + return ret; +} + +int av_opt_get_array_size(void *obj, const char *name, int search_flags, + unsigned int *out_val) +{ + void *target_obj, *parray; + const AVOption *o; + + o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (!(o->type & AV_OPT_TYPE_FLAG_ARRAY)) + return AVERROR(EINVAL); + + parray = (uint8_t *)target_obj + o->offset; + *out_val = *opt_array_pcount(parray); + + return 0; +} + +int av_opt_get_array(void *obj, const char *name, int search_flags, + unsigned int start_elem, unsigned int nb_elems, + enum AVOptionType out_type, void *out_val) +{ + const size_t elem_size_out = opt_type_desc[TYPE_BASE(out_type)].size; + + const AVOption *o; + void *target_obj; + + const void *parray; + unsigned array_size; + + int ret; + + o = av_opt_find2(obj, name, NULL, 0, search_flags, &target_obj); + if (!o || !target_obj) + return AVERROR_OPTION_NOT_FOUND; + if (!(o->type & AV_OPT_TYPE_FLAG_ARRAY) || + (out_type & AV_OPT_TYPE_FLAG_ARRAY)) + return AVERROR(EINVAL); + + parray = (uint8_t *)target_obj + o->offset; + array_size = *opt_array_pcount(parray); + + if (start_elem >= array_size || + array_size - start_elem < nb_elems) + return AVERROR(EINVAL); + + for (unsigned i = 0; i < nb_elems; i++) { + const void *src = opt_array_pelem(o, *(void**)parray, start_elem + i); + void *dst = (uint8_t*)out_val + i * elem_size_out; + + if (out_type == TYPE_BASE(o->type)) { + ret = opt_copy_elem(obj, out_type, dst, src); + if (ret < 0) + goto fail; + } else if (out_type == AV_OPT_TYPE_STRING) { + uint8_t buf[128], *out = buf; + + ret = opt_get_elem(o, &out, sizeof(buf), src, search_flags); + if (ret < 0) + goto fail; + + if (out == buf) { + out = av_strdup(buf); + if (!out) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + *(uint8_t**)dst = out; + } else if (out_type == AV_OPT_TYPE_INT64 || + out_type == AV_OPT_TYPE_DOUBLE || + out_type == AV_OPT_TYPE_RATIONAL) { + double num = 1.0; + int den = 1; + int64_t intnum = 1; + + ret = read_number(o, src, &num, &den, &intnum); + if (ret < 0) + goto fail; + + switch (out_type) { + case AV_OPT_TYPE_INT64: + *(int64_t*)dst = (num == den) ? intnum : num * intnum / den; + break; + case AV_OPT_TYPE_DOUBLE: + *(double*)dst = num * intnum / den; + break; + case AV_OPT_TYPE_RATIONAL: + *(AVRational*)dst = (num == 1.0 && (int)intnum == intnum) ? + (AVRational){ intnum, den } : + double_to_rational(num * intnum / den); + break; + default: av_assert0(0); + } + } else + return AVERROR(ENOSYS); + } + + return 0; +fail: + for (unsigned i = 0; i < nb_elems; i++) + opt_free_elem(out_type, (uint8_t*)out_val + i * elem_size_out); + return ret; +} + +int av_opt_set_array(void *obj, const char *name, int search_flags, + unsigned int start_elem, unsigned int nb_elems, + enum AVOptionType val_type, const void *val) +{ + const size_t elem_size_val = opt_type_desc[TYPE_BASE(val_type)].size; + + const AVOption *o; + const AVOptionArrayDef *arr; + void *target_obj; + + void *parray; + void *new_elems; + unsigned *array_size, new_size; + size_t elem_size; + + int ret = 0; + + ret = opt_set_init(obj, name, search_flags, 0, &target_obj, &o, &parray); + if (ret < 0) + return ret; + + if (!(o->type & AV_OPT_TYPE_FLAG_ARRAY) || + (val_type & AV_OPT_TYPE_FLAG_ARRAY)) + return AVERROR(EINVAL); + + arr = o->default_val.arr; + array_size = opt_array_pcount(parray); + elem_size = opt_type_desc[TYPE_BASE(o->type)].size; + + if (start_elem > *array_size) + return AVERROR(EINVAL); + + // compute new array size + if (!val) { + if (*array_size - start_elem < nb_elems) + return AVERROR(EINVAL); + + new_size = *array_size - nb_elems; + } else if (search_flags & AV_OPT_ARRAY_REPLACE) { + if (start_elem >= UINT_MAX - nb_elems) + return AVERROR(EINVAL); + + new_size = FFMAX(*array_size, start_elem + nb_elems); + } else { + if (nb_elems >= UINT_MAX - *array_size) + return AVERROR(EINVAL); + + new_size = *array_size + nb_elems; + } + + if (arr && + ((arr->size_max && new_size > arr->size_max) || + (arr->size_min && new_size < arr->size_min))) + return AVERROR(EINVAL); + + // desired operation is shrinking the array + if (!val) { + void *array = *(void**)parray; + + for (unsigned i = 0; i < nb_elems; i++) { + opt_free_elem(o->type, + opt_array_pelem(o, array, start_elem + i)); + } + + if (new_size > 0) { + memmove(opt_array_pelem(o, array, start_elem), + opt_array_pelem(o, array, start_elem + nb_elems), + elem_size * (*array_size - start_elem - nb_elems)); + + array = av_realloc_array(array, new_size, elem_size); + if (!array) + return AVERROR(ENOMEM); + + *(void**)parray = array; + } else + av_freep(parray); + + *array_size = new_size; + + return 0; + } + + // otherwise, desired operation is insert/replace; + // first, store new elements in a separate array to simplify + // rollback on failure + new_elems = av_calloc(nb_elems, elem_size); + if (!new_elems) + return AVERROR(ENOMEM); + + // convert/validate each new element + for (unsigned i = 0; i < nb_elems; i++) { + void *dst = opt_array_pelem(o, new_elems, i); + const void *src = (uint8_t*)val + i * elem_size_val; + + double num = 1.0; + int den = 1; + int64_t intnum = 1; + + if (val_type == TYPE_BASE(o->type)) { + int err; + + ret = opt_copy_elem(obj, val_type, dst, src); + if (ret < 0) + goto fail; + + // validate the range for numeric options + err = read_number(o, dst, &num, &den, &intnum); + if (err >= 0 && TYPE_BASE(o->type) != AV_OPT_TYPE_FLAGS && + (!den || o->max * den < num * intnum || o->min * den > num * intnum)) { + num = den ? num * intnum / den : (num && intnum ? INFINITY : NAN); + av_log(obj, AV_LOG_ERROR, "Cannot set array element %u for " + "parameter '%s': value %f out of range [%g - %g]\n", + start_elem + i, o->name, num, o->min, o->max); + ret = AVERROR(ERANGE); + goto fail; + } + } else if (val_type == AV_OPT_TYPE_STRING) { + ret = opt_set_elem(obj, target_obj, o, *(const char **)src, dst); + if (ret < 0) + goto fail; + } else if (val_type == AV_OPT_TYPE_INT || + val_type == AV_OPT_TYPE_INT64 || + val_type == AV_OPT_TYPE_FLOAT || + val_type == AV_OPT_TYPE_DOUBLE || + val_type == AV_OPT_TYPE_RATIONAL) { + + switch (val_type) { + case AV_OPT_TYPE_INT: intnum = *(int*)src; break; + case AV_OPT_TYPE_INT64: intnum = *(int64_t*)src; break; + case AV_OPT_TYPE_FLOAT: num = *(float*)src; break; + case AV_OPT_TYPE_DOUBLE: num = *(double*)src; break; + case AV_OPT_TYPE_RATIONAL: intnum = ((AVRational*)src)->num; + den = ((AVRational*)src)->den; break; + default: av_assert0(0); + } + + ret = write_number(obj, o, dst, num, den, intnum); + if (ret < 0) + goto fail; + } else { + ret = AVERROR(ENOSYS); + goto fail; + } + } + + // commit new elements to the array + if (start_elem == 0 && nb_elems == new_size) { + // replacing the existing array entirely + opt_free_array(o, parray, array_size); + *(void**)parray = new_elems; + *array_size = nb_elems; + + new_elems = NULL; + nb_elems = 0; + } else { + void *array = av_realloc_array(*(void**)parray, new_size, elem_size); + if (!array) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if (search_flags & AV_OPT_ARRAY_REPLACE) { + // free the elements being overwritten + for (unsigned i = start_elem; i < FFMIN(start_elem + nb_elems, *array_size); i++) + opt_free_elem(o->type, opt_array_pelem(o, array, i)); + } else { + // shift existing elements to the end + memmove(opt_array_pelem(o, array, start_elem + nb_elems), + opt_array_pelem(o, array, start_elem), + elem_size * (*array_size - start_elem)); + } + + memcpy((uint8_t*)array + elem_size * start_elem, new_elems, elem_size * nb_elems); + + av_freep(&new_elems); + nb_elems = 0; + + *(void**)parray = array; + *array_size = new_size; + } + +fail: + opt_free_array(o, &new_elems, &nb_elems); + + return ret; +} + +int av_opt_query_ranges(AVOptionRanges **ranges_arg, void *obj, const char *key, int flags) +{ + int ret; + const AVClass *c = *(AVClass**)obj; + int (*callback)(AVOptionRanges **, void *obj, const char *key, int flags) = c->query_ranges; + + if (!callback) + callback = av_opt_query_ranges_default; + + ret = callback(ranges_arg, obj, key, flags); + if (ret >= 0) { + if (!(flags & AV_OPT_MULTI_COMPONENT_RANGE)) + ret = 1; + (*ranges_arg)->nb_components = ret; + } + return ret; +} + +int av_opt_query_ranges_default(AVOptionRanges **ranges_arg, void *obj, const char *key, int flags) +{ + AVOptionRanges *ranges = av_mallocz(sizeof(*ranges)); + AVOptionRange **range_array = av_mallocz(sizeof(void*)); + AVOptionRange *range = av_mallocz(sizeof(*range)); + const AVOption *field = av_opt_find(obj, key, NULL, 0, flags); + int ret; + + *ranges_arg = NULL; + + if (!ranges || !range || !range_array || !field) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ranges->range = range_array; + ranges->range[0] = range; + ranges->nb_ranges = 1; + ranges->nb_components = 1; + range->is_range = 1; + range->value_min = field->min; + range->value_max = field->max; + + switch (field->type) { + case AV_OPT_TYPE_BOOL: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: + case AV_OPT_TYPE_PIXEL_FMT: + case AV_OPT_TYPE_SAMPLE_FMT: + case AV_OPT_TYPE_FLOAT: + case AV_OPT_TYPE_DOUBLE: + case AV_OPT_TYPE_DURATION: + case AV_OPT_TYPE_COLOR: + break; + case AV_OPT_TYPE_STRING: + range->component_min = 0; + range->component_max = 0x10FFFF; // max unicode value + range->value_min = -1; + range->value_max = INT_MAX; + break; + case AV_OPT_TYPE_RATIONAL: + range->component_min = INT_MIN; + range->component_max = INT_MAX; + break; + case AV_OPT_TYPE_IMAGE_SIZE: + range->component_min = 0; + range->component_max = INT_MAX/128/8; + range->value_min = 0; + range->value_max = INT_MAX/8; + break; + case AV_OPT_TYPE_VIDEO_RATE: + range->component_min = 1; + range->component_max = INT_MAX; + range->value_min = 1; + range->value_max = INT_MAX; + break; + default: + ret = AVERROR(ENOSYS); + goto fail; + } + + *ranges_arg = ranges; + return 1; +fail: + av_free(ranges); + av_free(range); + av_free(range_array); + return ret; +} + +void av_opt_freep_ranges(AVOptionRanges **rangesp) +{ + int i; + AVOptionRanges *ranges = *rangesp; + + if (!ranges) + return; + + for (i = 0; i < ranges->nb_ranges * ranges->nb_components; i++) { + AVOptionRange *range = ranges->range[i]; + if (range) { + av_freep(&range->str); + av_freep(&ranges->range[i]); + } + } + av_freep(&ranges->range); + av_freep(rangesp); +} + +int av_opt_is_set_to_default(void *obj, const AVOption *o) +{ + int64_t i64; + double d; + AVRational q; + int ret, w, h; + char *str; + void *dst; + + if (!o || !obj) + return AVERROR(EINVAL); + + dst = ((uint8_t*)obj) + o->offset; + + if (o->type & AV_OPT_TYPE_FLAG_ARRAY) { + const char *def = o->default_val.arr ? o->default_val.arr->def : NULL; + uint8_t *val; + + ret = opt_get_array(o, dst, &val); + if (ret < 0) + return ret; + + if (!!val != !!def) + ret = 0; + else if (val) + ret = !strcmp(val, def); + else + ret = 1; + + av_freep(&val); + + return ret; + } + + switch (o->type) { + case AV_OPT_TYPE_CONST: + return 1; + case AV_OPT_TYPE_BOOL: + case AV_OPT_TYPE_FLAGS: + case AV_OPT_TYPE_PIXEL_FMT: + case AV_OPT_TYPE_SAMPLE_FMT: + case AV_OPT_TYPE_INT: + case AV_OPT_TYPE_UINT: + case AV_OPT_TYPE_DURATION: + case AV_OPT_TYPE_INT64: + case AV_OPT_TYPE_UINT64: + read_number(o, dst, NULL, NULL, &i64); + return o->default_val.i64 == i64; + case AV_OPT_TYPE_CHLAYOUT: { + AVChannelLayout ch_layout = { 0 }; + if (o->default_val.str) { + if ((ret = av_channel_layout_from_string(&ch_layout, o->default_val.str)) < 0) + return ret; + } + ret = !av_channel_layout_compare((AVChannelLayout *)dst, &ch_layout); + av_channel_layout_uninit(&ch_layout); + return ret; + } + case AV_OPT_TYPE_STRING: + str = *(char **)dst; + if (str == o->default_val.str) //2 NULLs + return 1; + if (!str || !o->default_val.str) //1 NULL + return 0; + return !strcmp(str, o->default_val.str); + case AV_OPT_TYPE_DOUBLE: + d = *(double *)dst; + return o->default_val.dbl == d; + case AV_OPT_TYPE_FLOAT: + d = *(float *)dst; + return (float)o->default_val.dbl == d; + case AV_OPT_TYPE_RATIONAL: + q = av_d2q(o->default_val.dbl, INT_MAX); + return !av_cmp_q(*(AVRational*)dst, q); + case AV_OPT_TYPE_BINARY: { + struct { + uint8_t *data; + int size; + } tmp = {0}; + int opt_size = *(int *)((void **)dst + 1); + void *opt_ptr = *(void **)dst; + if (!opt_size && (!o->default_val.str || !strlen(o->default_val.str))) + return 1; + if (!opt_size || !o->default_val.str || !strlen(o->default_val.str )) + return 0; + if (opt_size != strlen(o->default_val.str) / 2) + return 0; + ret = set_string_binary(NULL, NULL, o->default_val.str, &tmp.data); + if (!ret) + ret = !memcmp(opt_ptr, tmp.data, tmp.size); + av_free(tmp.data); + return ret; + } + case AV_OPT_TYPE_DICT: { + AVDictionary *dict1 = NULL; + AVDictionary *dict2 = *(AVDictionary **)dst; + const AVDictionaryEntry *en1 = NULL; + const AVDictionaryEntry *en2 = NULL; + ret = av_dict_parse_string(&dict1, o->default_val.str, "=", ":", 0); + if (ret < 0) { + av_dict_free(&dict1); + return ret; + } + do { + en1 = av_dict_iterate(dict1, en1); + en2 = av_dict_iterate(dict2, en2); + } while (en1 && en2 && !strcmp(en1->key, en2->key) && !strcmp(en1->value, en2->value)); + av_dict_free(&dict1); + return (!en1 && !en2); + } + case AV_OPT_TYPE_IMAGE_SIZE: + if (!o->default_val.str || !strcmp(o->default_val.str, "none")) + w = h = 0; + else if ((ret = av_parse_video_size(&w, &h, o->default_val.str)) < 0) + return ret; + return (w == *(int *)dst) && (h == *((int *)dst+1)); + case AV_OPT_TYPE_VIDEO_RATE: + q = (AVRational){0, 0}; + if (o->default_val.str) { + if ((ret = av_parse_video_rate(&q, o->default_val.str)) < 0) + return ret; + } + return !av_cmp_q(*(AVRational*)dst, q); + case AV_OPT_TYPE_COLOR: { + uint8_t color[4] = {0, 0, 0, 0}; + if (o->default_val.str) { + if ((ret = av_parse_color(color, o->default_val.str, -1, NULL)) < 0) + return ret; + } + return !memcmp(color, dst, sizeof(color)); + } + default: + av_log(obj, AV_LOG_WARNING, "Not supported option type: %d, option name: %s\n", o->type, o->name); + break; + } + return AVERROR_PATCHWELCOME; +} + +int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_flags) +{ + const AVOption *o; + void *target; + if (!obj) + return AVERROR(EINVAL); + o = av_opt_find2(obj, name, NULL, 0, search_flags, &target); + if (!o) + return AVERROR_OPTION_NOT_FOUND; + return av_opt_is_set_to_default(target, o); +} + +static int opt_serialize(void *obj, int opt_flags, int flags, int *cnt, + AVBPrint *bprint, const char key_val_sep, const char pairs_sep) +{ + const AVOption *o = NULL; + void *child = NULL; + uint8_t *buf; + int ret; + const char special_chars[] = {pairs_sep, key_val_sep, '\0'}; + + if (flags & AV_OPT_SERIALIZE_SEARCH_CHILDREN) + while (child = av_opt_child_next(obj, child)) { + ret = opt_serialize(child, opt_flags, flags, cnt, bprint, + key_val_sep, pairs_sep); + if (ret < 0) + return ret; + } + + while (o = av_opt_next(obj, o)) { + if (o->type == AV_OPT_TYPE_CONST) + continue; + if ((flags & AV_OPT_SERIALIZE_OPT_FLAGS_EXACT) && o->flags != opt_flags) + continue; + else if (((o->flags & opt_flags) != opt_flags)) + continue; + if (flags & AV_OPT_SERIALIZE_SKIP_DEFAULTS && av_opt_is_set_to_default(obj, o) > 0) + continue; + if ((ret = av_opt_get(obj, o->name, 0, &buf)) < 0) { + av_bprint_finalize(bprint, NULL); + return ret; + } + if (buf) { + if ((*cnt)++) + av_bprint_append_data(bprint, &pairs_sep, 1); + av_bprint_escape(bprint, o->name, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); + av_bprint_append_data(bprint, &key_val_sep, 1); + av_bprint_escape(bprint, buf, special_chars, AV_ESCAPE_MODE_BACKSLASH, 0); + av_freep(&buf); + } + } + + return 0; +} + +int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer, + const char key_val_sep, const char pairs_sep) +{ + AVBPrint bprint; + int ret, cnt = 0; + + if (pairs_sep == '\0' || key_val_sep == '\0' || pairs_sep == key_val_sep || + pairs_sep == '\\' || key_val_sep == '\\') { + av_log(obj, AV_LOG_ERROR, "Invalid separator(s) found."); + return AVERROR(EINVAL); + } + + if (!obj || !buffer) + return AVERROR(EINVAL); + + *buffer = NULL; + av_bprint_init(&bprint, 64, AV_BPRINT_SIZE_UNLIMITED); + + ret = opt_serialize(obj, opt_flags, flags, &cnt, &bprint, + key_val_sep, pairs_sep); + if (ret < 0) + return ret; + + ret = av_bprint_finalize(&bprint, buffer); + if (ret < 0) + return ret; + return 0; +} diff --git a/libs/ffmpeg/libavutil/opt.h b/libs/ffmpeg/libavutil/opt.h new file mode 100644 index 00000000000..ab24fae7779 --- /dev/null +++ b/libs/ffmpeg/libavutil/opt.h @@ -0,0 +1,1194 @@ +/* + * AVOptions + * copyright (c) 2005 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_OPT_H +#define AVUTIL_OPT_H + +/** + * @file + * AVOptions + */ + +#include "rational.h" +#include "avutil.h" +#include "channel_layout.h" +#include "dict.h" +#include "log.h" +#include "pixfmt.h" +#include "samplefmt.h" + +/** + * @defgroup avoptions AVOptions + * @ingroup lavu_data + * @{ + * AVOptions provide a generic system to declare options on arbitrary structs + * ("objects"). An option can have a help text, a type and a range of possible + * values. Options may then be enumerated, read and written to. + * + * There are two modes of access to members of AVOption and its child structs. + * One is called 'native access', and refers to access from the code that + * declares the AVOption in question. The other is 'foreign access', and refers + * to access from other code. + * + * Certain struct members in this header are documented as 'native access only' + * or similar - it means that only the code that declared the AVOption in + * question is allowed to access the field. This allows us to extend the + * semantics of those fields without breaking API compatibility. + * + * @section avoptions_scope Scope of AVOptions + * + * AVOptions is designed to support any set of multimedia configuration options + * that can be defined at compile-time. Although it is mainly used to expose + * FFmpeg options, you are welcome to adapt it to your own use case. + * + * No single approach can ever fully solve the problem of configuration, + * but please submit a patch if you believe you have found a problem + * that is best solved by extending AVOptions. + * + * @section avoptions_implement Implementing AVOptions + * This section describes how to add AVOptions capabilities to a struct. + * + * All AVOptions-related information is stored in an AVClass. Therefore + * the first member of the struct should be a pointer to an AVClass describing it. + * The option field of the AVClass must be set to a NULL-terminated static array + * of AVOptions. Each AVOption must have a non-empty name, a type, a default + * value and for number-type AVOptions also a range of allowed values. It must + * also declare an offset in bytes from the start of the struct, where the field + * associated with this AVOption is located. Other fields in the AVOption struct + * should also be set when applicable, but are not required. + * + * The following example illustrates an AVOptions-enabled struct: + * @code + * typedef struct test_struct { + * const AVClass *class; + * int int_opt; + * char *str_opt; + * uint8_t *bin_opt; + * int bin_len; + * } test_struct; + * + * static const AVOption test_options[] = { + * { "test_int", "This is a test option of int type.", offsetof(test_struct, int_opt), + * AV_OPT_TYPE_INT, { .i64 = -1 }, INT_MIN, INT_MAX }, + * { "test_str", "This is a test option of string type.", offsetof(test_struct, str_opt), + * AV_OPT_TYPE_STRING }, + * { "test_bin", "This is a test option of binary type.", offsetof(test_struct, bin_opt), + * AV_OPT_TYPE_BINARY }, + * { NULL }, + * }; + * + * static const AVClass test_class = { + * .class_name = "test class", + * .item_name = av_default_item_name, + * .option = test_options, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * @endcode + * + * Next, when allocating your struct, you must ensure that the AVClass pointer + * is set to the correct value. Then, av_opt_set_defaults() can be called to + * initialize defaults. After that the struct is ready to be used with the + * AVOptions API. + * + * When cleaning up, you may use the av_opt_free() function to automatically + * free all the allocated string and binary options. + * + * Continuing with the above example: + * + * @code + * test_struct *alloc_test_struct(void) + * { + * test_struct *ret = av_mallocz(sizeof(*ret)); + * ret->class = &test_class; + * av_opt_set_defaults(ret); + * return ret; + * } + * void free_test_struct(test_struct **foo) + * { + * av_opt_free(*foo); + * av_freep(foo); + * } + * @endcode + * + * @subsection avoptions_implement_nesting Nesting + * It may happen that an AVOptions-enabled struct contains another + * AVOptions-enabled struct as a member (e.g. AVCodecContext in + * libavcodec exports generic options, while its priv_data field exports + * codec-specific options). In such a case, it is possible to set up the + * parent struct to export a child's options. To do that, simply + * implement AVClass.child_next() and AVClass.child_class_iterate() in the + * parent struct's AVClass. + * Assuming that the test_struct from above now also contains a + * child_struct field: + * + * @code + * typedef struct child_struct { + * AVClass *class; + * int flags_opt; + * } child_struct; + * static const AVOption child_opts[] = { + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX }, + * { NULL }, + * }; + * static const AVClass child_class = { + * .class_name = "child class", + * .item_name = av_default_item_name, + * .option = child_opts, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * + * void *child_next(void *obj, void *prev) + * { + * test_struct *t = obj; + * if (!prev && t->child_struct) + * return t->child_struct; + * return NULL + * } + * const AVClass child_class_iterate(void **iter) + * { + * const AVClass *c = *iter ? NULL : &child_class; + * *iter = (void*)(uintptr_t)c; + * return c; + * } + * @endcode + * Putting child_next() and child_class_iterate() as defined above into + * test_class will now make child_struct's options accessible through + * test_struct (again, proper setup as described above needs to be done on + * child_struct right after it is created). + * + * From the above example it might not be clear why both child_next() + * and child_class_iterate() are needed. The distinction is that child_next() + * iterates over actually existing objects, while child_class_iterate() + * iterates over all possible child classes. E.g. if an AVCodecContext + * was initialized to use a codec which has private options, then its + * child_next() will return AVCodecContext.priv_data and finish + * iterating. OTOH child_class_iterate() on AVCodecContext.av_class will + * iterate over all available codecs with private options. + * + * @subsection avoptions_implement_named_constants Named constants + * It is possible to create named constants for options. Simply set the unit + * field of the option the constants should apply to a string and + * create the constants themselves as options of type AV_OPT_TYPE_CONST + * with their unit field set to the same string. + * Their default_val field should contain the value of the named + * constant. + * For example, to add some named constants for the test_flags option + * above, put the following into the child_opts array: + * @code + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX, "test_unit" }, + * { "flag1", "This is a flag with value 16", 0, AV_OPT_TYPE_CONST, { .i64 = 16 }, 0, 0, "test_unit" }, + * @endcode + * + * @section avoptions_use Using AVOptions + * This section deals with accessing options in an AVOptions-enabled struct. + * Such structs in FFmpeg are e.g. AVCodecContext in libavcodec or + * AVFormatContext in libavformat. + * + * @subsection avoptions_use_examine Examining AVOptions + * The basic functions for examining options are av_opt_next(), which iterates + * over all options defined for one object, and av_opt_find(), which searches + * for an option with the given name. + * + * The situation is more complicated with nesting. An AVOptions-enabled struct + * may have AVOptions-enabled children. Passing the AV_OPT_SEARCH_CHILDREN flag + * to av_opt_find() will make the function search children recursively. + * + * For enumerating there are basically two cases. The first is when you want to + * get all options that may potentially exist on the struct and its children + * (e.g. when constructing documentation). In that case you should call + * av_opt_child_class_iterate() recursively on the parent struct's AVClass. The + * second case is when you have an already initialized struct with all its + * children and you want to get all options that can be actually written or read + * from it. In that case you should call av_opt_child_next() recursively (and + * av_opt_next() on each result). + * + * @subsection avoptions_use_get_set Reading and writing AVOptions + * When setting options, you often have a string read directly from the + * user. In such a case, simply passing it to av_opt_set() is enough. For + * non-string type options, av_opt_set() will parse the string according to the + * option type. + * + * Similarly av_opt_get() will read any option type and convert it to a string + * which will be returned. Do not forget that the string is allocated, so you + * have to free it with av_free(). + * + * In some cases it may be more convenient to put all options into an + * AVDictionary and call av_opt_set_dict() on it. A specific case of this + * are the format/codec open functions in lavf/lavc which take a dictionary + * filled with option as a parameter. This makes it possible to set some options + * that cannot be set otherwise, since e.g. the input file format is not known + * before the file is actually opened. + */ + +/** + * An option type determines: + * - for native access, the underlying C type of the field that an AVOption + * refers to; + * - for foreign access, the semantics of accessing the option through this API, + * e.g. which av_opt_get_*() and av_opt_set_*() functions can be called, or + * what format will av_opt_get()/av_opt_set() expect/produce. + */ +enum AVOptionType{ + /** + * Underlying C type is unsigned int. + */ + AV_OPT_TYPE_FLAGS = 1, + /** + * Underlying C type is int. + */ + AV_OPT_TYPE_INT, + /** + * Underlying C type is int64_t. + */ + AV_OPT_TYPE_INT64, + /** + * Underlying C type is double. + */ + AV_OPT_TYPE_DOUBLE, + /** + * Underlying C type is float. + */ + AV_OPT_TYPE_FLOAT, + /** + * Underlying C type is a uint8_t* that is either NULL or points to a C + * string allocated with the av_malloc() family of functions. + */ + AV_OPT_TYPE_STRING, + /** + * Underlying C type is AVRational. + */ + AV_OPT_TYPE_RATIONAL, + /** + * Underlying C type is a uint8_t* that is either NULL or points to an array + * allocated with the av_malloc() family of functions. The pointer is + * immediately followed by an int containing the array length in bytes. + */ + AV_OPT_TYPE_BINARY, + /** + * Underlying C type is AVDictionary*. + */ + AV_OPT_TYPE_DICT, + /** + * Underlying C type is uint64_t. + */ + AV_OPT_TYPE_UINT64, + /** + * Special option type for declaring named constants. Does not correspond to + * an actual field in the object, offset must be 0. + */ + AV_OPT_TYPE_CONST, + /** + * Underlying C type is two consecutive integers. + */ + AV_OPT_TYPE_IMAGE_SIZE, + /** + * Underlying C type is enum AVPixelFormat. + */ + AV_OPT_TYPE_PIXEL_FMT, + /** + * Underlying C type is enum AVSampleFormat. + */ + AV_OPT_TYPE_SAMPLE_FMT, + /** + * Underlying C type is AVRational. + */ + AV_OPT_TYPE_VIDEO_RATE, + /** + * Underlying C type is int64_t. + */ + AV_OPT_TYPE_DURATION, + /** + * Underlying C type is uint8_t[4]. + */ + AV_OPT_TYPE_COLOR, + /** + * Underlying C type is int. + */ + AV_OPT_TYPE_BOOL, + /** + * Underlying C type is AVChannelLayout. + */ + AV_OPT_TYPE_CHLAYOUT, + /** + * Underlying C type is unsigned int. + */ + AV_OPT_TYPE_UINT, + + /** + * May be combined with another regular option type to declare an array + * option. + * + * For array options, @ref AVOption.offset should refer to a pointer + * corresponding to the option type. The pointer should be immediately + * followed by an unsigned int that will store the number of elements in the + * array. + */ + AV_OPT_TYPE_FLAG_ARRAY = (1 << 16), +}; + +/** + * A generic parameter which can be set by the user for muxing or encoding. + */ +#define AV_OPT_FLAG_ENCODING_PARAM (1 << 0) +/** + * A generic parameter which can be set by the user for demuxing or decoding. + */ +#define AV_OPT_FLAG_DECODING_PARAM (1 << 1) +#define AV_OPT_FLAG_AUDIO_PARAM (1 << 3) +#define AV_OPT_FLAG_VIDEO_PARAM (1 << 4) +#define AV_OPT_FLAG_SUBTITLE_PARAM (1 << 5) +/** + * The option is intended for exporting values to the caller. + */ +#define AV_OPT_FLAG_EXPORT (1 << 6) +/** + * The option may not be set through the AVOptions API, only read. + * This flag only makes sense when AV_OPT_FLAG_EXPORT is also set. + */ +#define AV_OPT_FLAG_READONLY (1 << 7) +/** + * A generic parameter which can be set by the user for bit stream filtering. + */ +#define AV_OPT_FLAG_BSF_PARAM (1 << 8) + +/** + * A generic parameter which can be set by the user at runtime. + */ +#define AV_OPT_FLAG_RUNTIME_PARAM (1 << 15) +/** + * A generic parameter which can be set by the user for filtering. + */ +#define AV_OPT_FLAG_FILTERING_PARAM (1 << 16) +/** + * Set if option is deprecated, users should refer to AVOption.help text for + * more information. + */ +#define AV_OPT_FLAG_DEPRECATED (1 << 17) +/** + * Set if option constants can also reside in child objects. + */ +#define AV_OPT_FLAG_CHILD_CONSTS (1 << 18) + +/** + * May be set as default_val for AV_OPT_TYPE_FLAG_ARRAY options. + */ +typedef struct AVOptionArrayDef { + /** + * Native access only. + * + * Default value of the option, as would be serialized by av_opt_get() (i.e. + * using the value of sep as the separator). + */ + const char *def; + + /** + * Minimum number of elements in the array. When this field is non-zero, def + * must be non-NULL and contain at least this number of elements. + */ + unsigned size_min; + /** + * Maximum number of elements in the array, 0 when unlimited. + */ + unsigned size_max; + + /** + * Separator between array elements in string representations of this + * option, used by av_opt_set() and av_opt_get(). It must be a printable + * ASCII character, excluding alphanumeric and the backslash. A comma is + * used when sep=0. + * + * The separator and the backslash must be backslash-escaped in order to + * appear in string representations of the option value. + */ + char sep; +} AVOptionArrayDef; + +/** + * AVOption + */ +typedef struct AVOption { + const char *name; + + /** + * short English help text + * @todo What about other languages? + */ + const char *help; + + /** + * Native access only. + * + * The offset relative to the context structure where the option + * value is stored. It should be 0 for named constants. + */ + int offset; + enum AVOptionType type; + + /** + * Native access only, except when documented otherwise. + * the default value for scalar options + */ + union { + int64_t i64; + double dbl; + const char *str; + /* TODO those are unused now */ + AVRational q; + + /** + * Used for AV_OPT_TYPE_FLAG_ARRAY options. May be NULL. + * + * Foreign access to some members allowed, as noted in AVOptionArrayDef + * documentation. + */ + const AVOptionArrayDef *arr; + } default_val; + double min; ///< minimum valid value for the option + double max; ///< maximum valid value for the option + + /** + * A combination of AV_OPT_FLAG_*. + */ + int flags; + + /** + * The logical unit to which the option belongs. Non-constant + * options and corresponding named constants share the same + * unit. May be NULL. + */ + const char *unit; +} AVOption; + +/** + * A single allowed range of values, or a single allowed value. + */ +typedef struct AVOptionRange { + const char *str; + /** + * Value range. + * For string ranges this represents the min/max length. + * For dimensions this represents the min/max pixel count or width/height in multi-component case. + */ + double value_min, value_max; + /** + * Value's component range. + * For string this represents the unicode range for chars, 0-127 limits to ASCII. + */ + double component_min, component_max; + /** + * Range flag. + * If set to 1 the struct encodes a range, if set to 0 a single value. + */ + int is_range; +} AVOptionRange; + +/** + * List of AVOptionRange structs. + */ +typedef struct AVOptionRanges { + /** + * Array of option ranges. + * + * Most of option types use just one component. + * Following describes multi-component option types: + * + * AV_OPT_TYPE_IMAGE_SIZE: + * component index 0: range of pixel count (width * height). + * component index 1: range of width. + * component index 2: range of height. + * + * @note To obtain multi-component version of this structure, user must + * provide AV_OPT_MULTI_COMPONENT_RANGE to av_opt_query_ranges or + * av_opt_query_ranges_default function. + * + * Multi-component range can be read as in following example: + * + * @code + * int range_index, component_index; + * AVOptionRanges *ranges; + * AVOptionRange *range[3]; //may require more than 3 in the future. + * av_opt_query_ranges(&ranges, obj, key, AV_OPT_MULTI_COMPONENT_RANGE); + * for (range_index = 0; range_index < ranges->nb_ranges; range_index++) { + * for (component_index = 0; component_index < ranges->nb_components; component_index++) + * range[component_index] = ranges->range[ranges->nb_ranges * component_index + range_index]; + * //do something with range here. + * } + * av_opt_freep_ranges(&ranges); + * @endcode + */ + AVOptionRange **range; + /** + * Number of ranges per component. + */ + int nb_ranges; + /** + * Number of components. + */ + int nb_components; +} AVOptionRanges; + +/** + * @defgroup opt_mng AVOption (un)initialization and inspection. + * @{ + */ + +/** + * Set the values of all AVOption fields to their default values. + * + * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) + */ +void av_opt_set_defaults(void *s); + +/** + * Set the values of all AVOption fields to their default values. Only these + * AVOption fields for which (opt->flags & mask) == flags will have their + * default applied to s. + * + * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) + * @param mask combination of AV_OPT_FLAG_* + * @param flags combination of AV_OPT_FLAG_* + */ +void av_opt_set_defaults2(void *s, int mask, int flags); + +/** + * Free all allocated objects in obj. + */ +void av_opt_free(void *obj); + +/** + * Iterate over all AVOptions belonging to obj. + * + * @param obj an AVOptions-enabled struct or a double pointer to an + * AVClass describing it. + * @param prev result of the previous call to av_opt_next() on this object + * or NULL + * @return next AVOption or NULL + */ +const AVOption *av_opt_next(const void *obj, const AVOption *prev); + +/** + * Iterate over AVOptions-enabled children of obj. + * + * @param prev result of a previous call to this function or NULL + * @return next AVOptions-enabled child or NULL + */ +void *av_opt_child_next(void *obj, void *prev); + +/** + * Iterate over potential AVOptions-enabled children of parent. + * + * @param iter a pointer where iteration state is stored. + * @return AVClass corresponding to next potential child or NULL + */ +const AVClass *av_opt_child_class_iterate(const AVClass *parent, void **iter); + +#define AV_OPT_SEARCH_CHILDREN (1 << 0) /**< Search in possible children of the + given object first. */ +/** + * The obj passed to av_opt_find() is fake -- only a double pointer to AVClass + * instead of a required pointer to a struct containing AVClass. This is + * useful for searching for options without needing to allocate the corresponding + * object. + */ +#define AV_OPT_SEARCH_FAKE_OBJ (1 << 1) + +/** + * In av_opt_get, return NULL if the option has a pointer type and is set to NULL, + * rather than returning an empty string. + */ +#define AV_OPT_ALLOW_NULL (1 << 2) + +/** + * May be used with av_opt_set_array() to signal that new elements should + * replace the existing ones in the indicated range. + */ +#define AV_OPT_ARRAY_REPLACE (1 << 3) + +/** + * Allows av_opt_query_ranges and av_opt_query_ranges_default to return more than + * one component for certain option types. + * @see AVOptionRanges for details. + */ +#define AV_OPT_MULTI_COMPONENT_RANGE (1 << 12) + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return A pointer to the option found, or NULL if no option + * was found. + * + * @note Options found with AV_OPT_SEARCH_CHILDREN flag may not be settable + * directly with av_opt_set(). Use special calls which take an options + * AVDictionary (e.g. avformat_open_input()) to set options found with this + * flag. + */ +const AVOption *av_opt_find(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags); + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * @param[out] target_obj if non-NULL, an object to which the option belongs will be + * written here. It may be different from obj if AV_OPT_SEARCH_CHILDREN is present + * in search_flags. This parameter is ignored if search_flags contain + * AV_OPT_SEARCH_FAKE_OBJ. + * + * @return A pointer to the option found, or NULL if no option + * was found. + */ +const AVOption *av_opt_find2(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags, void **target_obj); + +/** + * Show the obj options. + * + * @param req_flags requested flags for the options to show. Show only the + * options for which it is opt->flags & req_flags. + * @param rej_flags rejected flags for the options to show. Show only the + * options for which it is !(opt->flags & req_flags). + * @param av_log_obj log context to use for showing the options + */ +int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags); + +/** + * Extract a key-value pair from the beginning of a string. + * + * @param ropts pointer to the options string, will be updated to + * point to the rest of the string (one of the pairs_sep + * or the final NUL) + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @param flags flags; see the AV_OPT_FLAG_* values below + * @param rkey parsed key; must be freed using av_free() + * @param rval parsed value; must be freed using av_free() + * + * @return >=0 for success, or a negative value corresponding to an + * AVERROR code in case of error; in particular: + * AVERROR(EINVAL) if no key is present + * + */ +int av_opt_get_key_value(const char **ropts, + const char *key_val_sep, const char *pairs_sep, + unsigned flags, + char **rkey, char **rval); + +enum { + + /** + * Accept to parse a value without a key; the key will then be returned + * as NULL. + */ + AV_OPT_FLAG_IMPLICIT_KEY = 1, +}; + +/** + * @} + */ + +/** + * @defgroup opt_write Setting and modifying option values + * @{ + */ + +/** + * Parse the key/value pairs list in opts. For each key/value pair + * found, stores the value in the field in ctx that is named like the + * key. ctx must be an AVClass context, storing is done using + * AVOptions. + * + * @param opts options string to parse, may be NULL + * @param key_val_sep a 0-terminated list of characters used to + * separate key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @return the number of successfully set key/value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_opt_set() if a key/value pair + * cannot be set + */ +int av_set_options_string(void *ctx, const char *opts, + const char *key_val_sep, const char *pairs_sep); + +/** + * Parse the key-value pairs list in opts. For each key=value pair found, + * set the value of the corresponding option in ctx. + * + * @param ctx the AVClass object to set options on + * @param opts the options string, key-value pairs separated by a + * delimiter + * @param shorthand a NULL-terminated array of options names for shorthand + * notation: if the first field in opts has no key part, + * the key is taken from the first element of shorthand; + * then again for the second, etc., until either opts is + * finished, shorthand is finished or a named option is + * found; after that, all options must be named + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @return the number of successfully set key=value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_set_string3() if a key/value pair + * cannot be set + * + * Options names must use only the following characters: a-z A-Z 0-9 - . / _ + * Separators must use characters distinct from option names and from each + * other. + */ +int av_opt_set_from_string(void *ctx, const char *opts, + const char *const *shorthand, + const char *key_val_sep, const char *pairs_sep); + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict(void *obj, struct AVDictionary **options); + + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict2(void *obj, struct AVDictionary **options, int search_flags); + +/** + * Copy options from src object into dest object. + * + * The underlying AVClass of both src and dest must coincide. The guarantee + * below does not apply if this is not fulfilled. + * + * Options that require memory allocation (e.g. string or binary) are malloc'ed in dest object. + * Original memory allocated for such options is freed unless both src and dest options points to the same memory. + * + * Even on error it is guaranteed that allocated options from src and dest + * no longer alias each other afterwards; in particular calling av_opt_free() + * on both src and dest is safe afterwards if dest has been memdup'ed from src. + * + * @param dest Object to copy from + * @param src Object to copy into + * @return 0 on success, negative on error + */ +int av_opt_copy(void *dest, const void *src); + +/** + * @defgroup opt_set_funcs Option setting functions + * @{ + * Those functions set the field of obj with the given name to value. + * + * @param[in] obj A struct whose first element is a pointer to an AVClass. + * @param[in] name the name of the field to set + * @param[in] val The value to set. In case of av_opt_set() if the field is not + * of a string type, then the given string is parsed. + * SI postfixes and some named scalars are supported. + * If the field is of a numeric type, it has to be a numeric or named + * scalar. Behavior with more than one scalar and +- infix operators + * is undefined. + * If the field is of a flags type, it has to be a sequence of numeric + * scalars or named flags separated by '+' or '-'. Prefixing a flag + * with '+' causes it to be set without affecting the other flags; + * similarly, '-' unsets a flag. + * If the field is of a dictionary type, it has to be a ':' separated list of + * key=value parameters. Values containing ':' special characters must be + * escaped. + * @param search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be set on a child of obj. + * + * @return 0 if the value has been set, or an AVERROR code in case of + * error: + * AVERROR_OPTION_NOT_FOUND if no matching option exists + * AVERROR(ERANGE) if the value is out of range + * AVERROR(EINVAL) if the value is not valid + */ +int av_opt_set (void *obj, const char *name, const char *val, int search_flags); +int av_opt_set_int (void *obj, const char *name, int64_t val, int search_flags); +int av_opt_set_double (void *obj, const char *name, double val, int search_flags); +int av_opt_set_q (void *obj, const char *name, AVRational val, int search_flags); +int av_opt_set_bin (void *obj, const char *name, const uint8_t *val, int size, int search_flags); +int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags); +int av_opt_set_pixel_fmt (void *obj, const char *name, enum AVPixelFormat fmt, int search_flags); +int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags); +int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags); +/** + * @note Any old chlayout present is discarded and replaced with a copy of the new one. The + * caller still owns layout and is responsible for uninitializing it. + */ +int av_opt_set_chlayout(void *obj, const char *name, const AVChannelLayout *layout, int search_flags); +/** + * @note Any old dictionary present is discarded and replaced with a copy of the new one. The + * caller still owns val is and responsible for freeing it. + */ +int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, int search_flags); + +#if FF_API_OPT_INT_LIST +/** + * Set a binary option to an integer list. + * + * @param obj AVClass object to set options on + * @param name name of the binary option + * @param val pointer to an integer list (must have the correct type with + * regard to the contents of the list) + * @param term list terminator (usually 0 or -1) + * @param flags search flags + */ +#define av_opt_set_int_list(obj, name, val, term, flags) \ + (av_int_list_length(val, term) > INT_MAX / sizeof(*(val)) ? \ + AVERROR(EINVAL) : \ + av_opt_set_bin(obj, name, (const uint8_t *)(val), \ + av_int_list_length(val, term) * sizeof(*(val)), flags)) +#endif + +/** + * Add, replace, or remove elements for an array option. Which of these + * operations is performed depends on the values of val and search_flags. + * + * @param start_elem Index of the first array element to modify; must not be + * larger than array size as returned by + * av_opt_get_array_size(). + * @param nb_elems number of array elements to modify; when val is NULL, + * start_elem+nb_elems must not be larger than array size as + * returned by av_opt_get_array_size() + * + * @param val_type Option type corresponding to the type of val, ignored when val is + * NULL. + * + * The effect of this function will will be as if av_opt_setX() + * was called for each element, where X is specified by type. + * E.g. AV_OPT_TYPE_STRING corresponds to av_opt_set(). + * + * Typically this should be the same as the scalarized type of + * the AVOption being set, but certain conversions are also + * possible - the same as those done by the corresponding + * av_opt_set*() function. E.g. any option type can be set from + * a string, numeric types can be set from int64, double, or + * rational, etc. + * + * @param val Array with nb_elems elements or NULL. + * + * When NULL, nb_elems array elements starting at start_elem are + * removed from the array. Any array elements remaining at the end + * are shifted by nb_elems towards the first element in order to keep + * the array contiguous. + * + * Otherwise (val is non-NULL), the type of val must match the + * underlying C type as documented for val_type. + * + * When AV_OPT_ARRAY_REPLACE is not set in search_flags, the array is + * enlarged by nb_elems, and the contents of val are inserted at + * start_elem. Previously existing array elements from start_elem + * onwards (if present) are shifted by nb_elems away from the first + * element in order to make space for the new elements. + * + * When AV_OPT_ARRAY_REPLACE is set in search_flags, the contents + * of val replace existing array elements from start_elem to + * start_elem+nb_elems (if present). New array size is + * max(start_elem + nb_elems, old array size). + */ +int av_opt_set_array(void *obj, const char *name, int search_flags, + unsigned int start_elem, unsigned int nb_elems, + enum AVOptionType val_type, const void *val); + +/** + * @} + * @} + */ + +/** + * @defgroup opt_read Reading option values + * @{ + */ + +/** + * @defgroup opt_get_funcs Option getting functions + * @{ + * Those functions get a value of the option with the given name from an object. + * + * @param[in] obj a struct whose first element is a pointer to an AVClass. + * @param[in] name name of the option to get. + * @param[in] search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be found in a child of obj. + * @param[out] out_val value of the option will be written here + * @return >=0 on success, a negative error code otherwise + */ +/** + * @note the returned string will be av_malloc()ed and must be av_free()ed by the caller + * + * @note if AV_OPT_ALLOW_NULL is set in search_flags in av_opt_get, and the + * option is of type AV_OPT_TYPE_STRING, AV_OPT_TYPE_BINARY or AV_OPT_TYPE_DICT + * and is set to NULL, *out_val will be set to NULL instead of an allocated + * empty string. + */ +int av_opt_get (void *obj, const char *name, int search_flags, uint8_t **out_val); +int av_opt_get_int (void *obj, const char *name, int search_flags, int64_t *out_val); +int av_opt_get_double (void *obj, const char *name, int search_flags, double *out_val); +int av_opt_get_q (void *obj, const char *name, int search_flags, AVRational *out_val); +int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_out, int *h_out); +int av_opt_get_pixel_fmt (void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt); +int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt); +int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val); +/** + * @param[out] layout The returned layout is a copy of the actual value and must + * be freed with av_channel_layout_uninit() by the caller + */ +int av_opt_get_chlayout(void *obj, const char *name, int search_flags, AVChannelLayout *layout); +/** + * @param[out] out_val The returned dictionary is a copy of the actual value and must + * be freed with av_dict_free() by the caller + */ +int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val); + +/** + * For an array-type option, get the number of elements in the array. + */ +int av_opt_get_array_size(void *obj, const char *name, int search_flags, + unsigned int *out_val); + +/** + * For an array-type option, retrieve the values of one or more array elements. + * + * @param start_elem index of the first array element to retrieve + * @param nb_elems number of array elements to retrieve; start_elem+nb_elems + * must not be larger than array size as returned by + * av_opt_get_array_size() + * + * @param out_type Option type corresponding to the desired output. + * + * The array elements produced by this function will + * will be as if av_opt_getX() was called for each element, + * where X is specified by out_type. E.g. AV_OPT_TYPE_STRING + * corresponds to av_opt_get(). + * + * Typically this should be the same as the scalarized type of + * the AVOption being retrieved, but certain conversions are + * also possible - the same as those done by the corresponding + * av_opt_get*() function. E.g. any option type can be retrieved + * as a string, numeric types can be retrieved as int64, double, + * or rational, etc. + * + * @param out_val Array with nb_elems members into which the output will be + * written. The array type must match the underlying C type as + * documented for out_type, and be zeroed on entry to this + * function. + * + * For dynamically allocated types (strings, binary, dicts, + * etc.), the result is owned and freed by the caller. + */ +int av_opt_get_array(void *obj, const char *name, int search_flags, + unsigned int start_elem, unsigned int nb_elems, + enum AVOptionType out_type, void *out_val); +/** + * @} + */ + +/** + * @defgroup opt_eval_funcs Evaluating option strings + * @{ + * This group of functions can be used to evaluate option strings + * and get numbers out of them. They do the same thing as av_opt_set(), + * except the result is written into the caller-supplied pointer. + * + * @param obj a struct whose first element is a pointer to AVClass. + * @param o an option for which the string is to be evaluated. + * @param val string to be evaluated. + * @param *_out value of the string will be written here. + * + * @return 0 on success, a negative number on failure. + */ +int av_opt_eval_flags (void *obj, const AVOption *o, const char *val, int *flags_out); +int av_opt_eval_int (void *obj, const AVOption *o, const char *val, int *int_out); +int av_opt_eval_uint (void *obj, const AVOption *o, const char *val, unsigned *uint_out); +int av_opt_eval_int64 (void *obj, const AVOption *o, const char *val, int64_t *int64_out); +int av_opt_eval_float (void *obj, const AVOption *o, const char *val, float *float_out); +int av_opt_eval_double(void *obj, const AVOption *o, const char *val, double *double_out); +int av_opt_eval_q (void *obj, const AVOption *o, const char *val, AVRational *q_out); +/** + * @} + */ + +#if FF_API_OPT_PTR +/** + * Gets a pointer to the requested field in a struct. + * This function allows accessing a struct even when its fields are moved or + * renamed since the application making the access has been compiled, + * + * @returns a pointer to the field, it can be cast to the correct type and read + * or written to. + * + * @deprecated direct access to AVOption-exported fields is not supported + */ +attribute_deprecated +void *av_opt_ptr(const AVClass *avclass, void *obj, const char *name); +#endif + +/** + * Check if given option is set to its default value. + * + * Options o must belong to the obj. This function must not be called to check child's options state. + * @see av_opt_is_set_to_default_by_name(). + * + * @param obj AVClass object to check option on + * @param o option to be checked + * @return >0 when option is set to its default, + * 0 when option is not set its default, + * <0 on error + */ +int av_opt_is_set_to_default(void *obj, const AVOption *o); + +/** + * Check if given option is set to its default value. + * + * @param obj AVClass object to check option on + * @param name option name + * @param search_flags combination of AV_OPT_SEARCH_* + * @return >0 when option is set to its default, + * 0 when option is not set its default, + * <0 on error + */ +int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_flags); + +/** + * Check whether a particular flag is set in a flags field. + * + * @param field_name the name of the flag field option + * @param flag_name the name of the flag to check + * @return non-zero if the flag is set, zero if the flag isn't set, + * isn't of the right type, or the flags field doesn't exist. + */ +int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name); + +#define AV_OPT_SERIALIZE_SKIP_DEFAULTS 0x00000001 ///< Serialize options that are not set to default values only. +#define AV_OPT_SERIALIZE_OPT_FLAGS_EXACT 0x00000002 ///< Serialize options that exactly match opt_flags only. +#define AV_OPT_SERIALIZE_SEARCH_CHILDREN 0x00000004 ///< Serialize options in possible children of the given object. + +/** + * Serialize object's options. + * + * Create a string containing object's serialized options. + * Such string may be passed back to av_opt_set_from_string() in order to restore option values. + * A key/value or pairs separator occurring in the serialized value or + * name string are escaped through the av_escape() function. + * + * @param[in] obj AVClass object to serialize + * @param[in] opt_flags serialize options with all the specified flags set (AV_OPT_FLAG) + * @param[in] flags combination of AV_OPT_SERIALIZE_* flags + * @param[out] buffer Pointer to buffer that will be allocated with string containing serialized options. + * Buffer must be freed by the caller when is no longer needed. + * @param[in] key_val_sep character used to separate key from value + * @param[in] pairs_sep character used to separate two pairs from each other + * @return >= 0 on success, negative on error + * @warning Separators cannot be neither '\\' nor '\0'. They also cannot be the same. + */ +int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer, + const char key_val_sep, const char pairs_sep); + +/** + * @} + */ + +/** + * Free an AVOptionRanges struct and set it to NULL. + */ +void av_opt_freep_ranges(AVOptionRanges **ranges); + +/** + * Get a list of allowed ranges for the given option. + * + * The returned list may depend on other fields in obj like for example profile. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_freep_ranges. + * + * @return number of components returned on success, a negative error code otherwise + */ +int av_opt_query_ranges(AVOptionRanges **, void *obj, const char *key, int flags); + +/** + * Get a default list of allowed ranges for the given option. + * + * This list is constructed without using the AVClass.query_ranges() callback + * and can be used as fallback from within the callback. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_free_ranges. + * + * @return number of components returned on success, a negative error code otherwise + */ +int av_opt_query_ranges_default(AVOptionRanges **, void *obj, const char *key, int flags); + +/** + * @} + */ + +#endif /* AVUTIL_OPT_H */ diff --git a/libs/ffmpeg/libavutil/parseutils.c b/libs/ffmpeg/libavutil/parseutils.c new file mode 100644 index 00000000000..9f57b16ec27 --- /dev/null +++ b/libs/ffmpeg/libavutil/parseutils.c @@ -0,0 +1,793 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * misc parsing utilities + */ + +#include <time.h> + +#include "avstring.h" +#include "avutil.h" +#include "common.h" +#include "eval.h" +#include "log.h" +#include "random_seed.h" +#include "time_internal.h" +#include "parseutils.h" +#include "time.h" + +#ifdef TEST + +#define av_get_random_seed av_get_random_seed_deterministic +static uint32_t av_get_random_seed_deterministic(void); + +#define av_gettime() 1331972053200000 + +#endif + +int av_parse_ratio(AVRational *q, const char *str, int max, + int log_offset, void *log_ctx) +{ + char c; + int ret; + + if (sscanf(str, "%d:%d%c", &q->num, &q->den, &c) != 2) { + double d; + ret = av_expr_parse_and_eval(&d, str, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, log_offset, log_ctx); + if (ret < 0) + return ret; + *q = av_d2q(d, max); + } else { + av_reduce(&q->num, &q->den, q->num, q->den, max); + } + + return 0; +} + +typedef struct VideoSizeAbbr { + const char *abbr; + int width, height; +} VideoSizeAbbr; + +typedef struct VideoRateAbbr { + const char *abbr; + AVRational rate; +} VideoRateAbbr; + +static const VideoSizeAbbr video_size_abbrs[] = { + { "ntsc", 720, 480 }, + { "pal", 720, 576 }, + { "qntsc", 352, 240 }, /* VCD compliant NTSC */ + { "qpal", 352, 288 }, /* VCD compliant PAL */ + { "sntsc", 640, 480 }, /* square pixel NTSC */ + { "spal", 768, 576 }, /* square pixel PAL */ + { "film", 352, 240 }, + { "ntsc-film", 352, 240 }, + { "sqcif", 128, 96 }, + { "qcif", 176, 144 }, + { "cif", 352, 288 }, + { "4cif", 704, 576 }, + { "16cif", 1408,1152 }, + { "qqvga", 160, 120 }, + { "qvga", 320, 240 }, + { "vga", 640, 480 }, + { "svga", 800, 600 }, + { "xga", 1024, 768 }, + { "uxga", 1600,1200 }, + { "qxga", 2048,1536 }, + { "sxga", 1280,1024 }, + { "qsxga", 2560,2048 }, + { "hsxga", 5120,4096 }, + { "wvga", 852, 480 }, + { "wxga", 1366, 768 }, + { "wsxga", 1600,1024 }, + { "wuxga", 1920,1200 }, + { "woxga", 2560,1600 }, + { "wqhd", 2560,1440 }, + { "wqsxga", 3200,2048 }, + { "wquxga", 3840,2400 }, + { "whsxga", 6400,4096 }, + { "whuxga", 7680,4800 }, + { "cga", 320, 200 }, + { "ega", 640, 350 }, + { "hd480", 852, 480 }, + { "hd720", 1280, 720 }, + { "hd1080", 1920,1080 }, + { "quadhd", 2560,1440 }, + { "2k", 2048,1080 }, /* Digital Cinema System Specification */ + { "2kdci", 2048,1080 }, + { "2kflat", 1998,1080 }, + { "2kscope", 2048, 858 }, + { "4k", 4096,2160 }, /* Digital Cinema System Specification */ + { "4kdci", 4096,2160 }, + { "4kflat", 3996,2160 }, + { "4kscope", 4096,1716 }, + { "nhd", 640,360 }, + { "hqvga", 240,160 }, + { "wqvga", 400,240 }, + { "fwqvga", 432,240 }, + { "hvga", 480,320 }, + { "qhd", 960,540 }, + { "uhd2160", 3840,2160 }, + { "uhd4320", 7680,4320 }, +}; + +static const VideoRateAbbr video_rate_abbrs[]= { + { "ntsc", { 30000, 1001 } }, + { "pal", { 25, 1 } }, + { "qntsc", { 30000, 1001 } }, /* VCD compliant NTSC */ + { "qpal", { 25, 1 } }, /* VCD compliant PAL */ + { "sntsc", { 30000, 1001 } }, /* square pixel NTSC */ + { "spal", { 25, 1 } }, /* square pixel PAL */ + { "film", { 24, 1 } }, + { "ntsc-film", { 24000, 1001 } }, +}; + +static const char *months[12] = { + "january", "february", "march", "april", "may", "june", "july", "august", + "september", "october", "november", "december" +}; + +int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str) +{ + int i; + int n = FF_ARRAY_ELEMS(video_size_abbrs); + const char *p; + int width = 0, height = 0; + + for (i = 0; i < n; i++) { + if (!strcmp(video_size_abbrs[i].abbr, str)) { + width = video_size_abbrs[i].width; + height = video_size_abbrs[i].height; + break; + } + } + if (i == n) { + width = strtol(str, (void*)&p, 10); + if (*p) + p++; + height = strtol(p, (void*)&p, 10); + + /* trailing extraneous data detected, like in 123x345foobar */ + if (*p) + return AVERROR(EINVAL); + } + if (width <= 0 || height <= 0) + return AVERROR(EINVAL); + *width_ptr = width; + *height_ptr = height; + return 0; +} + +int av_parse_video_rate(AVRational *rate, const char *arg) +{ + int i, ret; + int n = FF_ARRAY_ELEMS(video_rate_abbrs); + + /* First, we check our abbreviation table */ + for (i = 0; i < n; ++i) + if (!strcmp(video_rate_abbrs[i].abbr, arg)) { + *rate = video_rate_abbrs[i].rate; + return 0; + } + + /* Then, we try to parse it as fraction */ + if ((ret = av_parse_ratio_quiet(rate, arg, 1001000)) < 0) + return ret; + if (!rate->num || !rate->den) + if ((ret = av_parse_ratio_quiet(rate, arg, INT_MAX)) < 0) + return ret; + if (rate->num <= 0 || rate->den <= 0) + return AVERROR(EINVAL); + return 0; +} + +typedef struct ColorEntry { + const char *name; ///< a string representing the name of the color + uint8_t rgb_color[3]; ///< RGB values for the color +} ColorEntry; + +static const ColorEntry color_table[] = { + { "AliceBlue", { 0xF0, 0xF8, 0xFF } }, + { "AntiqueWhite", { 0xFA, 0xEB, 0xD7 } }, + { "Aqua", { 0x00, 0xFF, 0xFF } }, + { "Aquamarine", { 0x7F, 0xFF, 0xD4 } }, + { "Azure", { 0xF0, 0xFF, 0xFF } }, + { "Beige", { 0xF5, 0xF5, 0xDC } }, + { "Bisque", { 0xFF, 0xE4, 0xC4 } }, + { "Black", { 0x00, 0x00, 0x00 } }, + { "BlanchedAlmond", { 0xFF, 0xEB, 0xCD } }, + { "Blue", { 0x00, 0x00, 0xFF } }, + { "BlueViolet", { 0x8A, 0x2B, 0xE2 } }, + { "Brown", { 0xA5, 0x2A, 0x2A } }, + { "BurlyWood", { 0xDE, 0xB8, 0x87 } }, + { "CadetBlue", { 0x5F, 0x9E, 0xA0 } }, + { "Chartreuse", { 0x7F, 0xFF, 0x00 } }, + { "Chocolate", { 0xD2, 0x69, 0x1E } }, + { "Coral", { 0xFF, 0x7F, 0x50 } }, + { "CornflowerBlue", { 0x64, 0x95, 0xED } }, + { "Cornsilk", { 0xFF, 0xF8, 0xDC } }, + { "Crimson", { 0xDC, 0x14, 0x3C } }, + { "Cyan", { 0x00, 0xFF, 0xFF } }, + { "DarkBlue", { 0x00, 0x00, 0x8B } }, + { "DarkCyan", { 0x00, 0x8B, 0x8B } }, + { "DarkGoldenRod", { 0xB8, 0x86, 0x0B } }, + { "DarkGray", { 0xA9, 0xA9, 0xA9 } }, + { "DarkGreen", { 0x00, 0x64, 0x00 } }, + { "DarkKhaki", { 0xBD, 0xB7, 0x6B } }, + { "DarkMagenta", { 0x8B, 0x00, 0x8B } }, + { "DarkOliveGreen", { 0x55, 0x6B, 0x2F } }, + { "Darkorange", { 0xFF, 0x8C, 0x00 } }, + { "DarkOrchid", { 0x99, 0x32, 0xCC } }, + { "DarkRed", { 0x8B, 0x00, 0x00 } }, + { "DarkSalmon", { 0xE9, 0x96, 0x7A } }, + { "DarkSeaGreen", { 0x8F, 0xBC, 0x8F } }, + { "DarkSlateBlue", { 0x48, 0x3D, 0x8B } }, + { "DarkSlateGray", { 0x2F, 0x4F, 0x4F } }, + { "DarkTurquoise", { 0x00, 0xCE, 0xD1 } }, + { "DarkViolet", { 0x94, 0x00, 0xD3 } }, + { "DeepPink", { 0xFF, 0x14, 0x93 } }, + { "DeepSkyBlue", { 0x00, 0xBF, 0xFF } }, + { "DimGray", { 0x69, 0x69, 0x69 } }, + { "DodgerBlue", { 0x1E, 0x90, 0xFF } }, + { "FireBrick", { 0xB2, 0x22, 0x22 } }, + { "FloralWhite", { 0xFF, 0xFA, 0xF0 } }, + { "ForestGreen", { 0x22, 0x8B, 0x22 } }, + { "Fuchsia", { 0xFF, 0x00, 0xFF } }, + { "Gainsboro", { 0xDC, 0xDC, 0xDC } }, + { "GhostWhite", { 0xF8, 0xF8, 0xFF } }, + { "Gold", { 0xFF, 0xD7, 0x00 } }, + { "GoldenRod", { 0xDA, 0xA5, 0x20 } }, + { "Gray", { 0x80, 0x80, 0x80 } }, + { "Green", { 0x00, 0x80, 0x00 } }, + { "GreenYellow", { 0xAD, 0xFF, 0x2F } }, + { "HoneyDew", { 0xF0, 0xFF, 0xF0 } }, + { "HotPink", { 0xFF, 0x69, 0xB4 } }, + { "IndianRed", { 0xCD, 0x5C, 0x5C } }, + { "Indigo", { 0x4B, 0x00, 0x82 } }, + { "Ivory", { 0xFF, 0xFF, 0xF0 } }, + { "Khaki", { 0xF0, 0xE6, 0x8C } }, + { "Lavender", { 0xE6, 0xE6, 0xFA } }, + { "LavenderBlush", { 0xFF, 0xF0, 0xF5 } }, + { "LawnGreen", { 0x7C, 0xFC, 0x00 } }, + { "LemonChiffon", { 0xFF, 0xFA, 0xCD } }, + { "LightBlue", { 0xAD, 0xD8, 0xE6 } }, + { "LightCoral", { 0xF0, 0x80, 0x80 } }, + { "LightCyan", { 0xE0, 0xFF, 0xFF } }, + { "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } }, + { "LightGreen", { 0x90, 0xEE, 0x90 } }, + { "LightGrey", { 0xD3, 0xD3, 0xD3 } }, + { "LightPink", { 0xFF, 0xB6, 0xC1 } }, + { "LightSalmon", { 0xFF, 0xA0, 0x7A } }, + { "LightSeaGreen", { 0x20, 0xB2, 0xAA } }, + { "LightSkyBlue", { 0x87, 0xCE, 0xFA } }, + { "LightSlateGray", { 0x77, 0x88, 0x99 } }, + { "LightSteelBlue", { 0xB0, 0xC4, 0xDE } }, + { "LightYellow", { 0xFF, 0xFF, 0xE0 } }, + { "Lime", { 0x00, 0xFF, 0x00 } }, + { "LimeGreen", { 0x32, 0xCD, 0x32 } }, + { "Linen", { 0xFA, 0xF0, 0xE6 } }, + { "Magenta", { 0xFF, 0x00, 0xFF } }, + { "Maroon", { 0x80, 0x00, 0x00 } }, + { "MediumAquaMarine", { 0x66, 0xCD, 0xAA } }, + { "MediumBlue", { 0x00, 0x00, 0xCD } }, + { "MediumOrchid", { 0xBA, 0x55, 0xD3 } }, + { "MediumPurple", { 0x93, 0x70, 0xD8 } }, + { "MediumSeaGreen", { 0x3C, 0xB3, 0x71 } }, + { "MediumSlateBlue", { 0x7B, 0x68, 0xEE } }, + { "MediumSpringGreen", { 0x00, 0xFA, 0x9A } }, + { "MediumTurquoise", { 0x48, 0xD1, 0xCC } }, + { "MediumVioletRed", { 0xC7, 0x15, 0x85 } }, + { "MidnightBlue", { 0x19, 0x19, 0x70 } }, + { "MintCream", { 0xF5, 0xFF, 0xFA } }, + { "MistyRose", { 0xFF, 0xE4, 0xE1 } }, + { "Moccasin", { 0xFF, 0xE4, 0xB5 } }, + { "NavajoWhite", { 0xFF, 0xDE, 0xAD } }, + { "Navy", { 0x00, 0x00, 0x80 } }, + { "OldLace", { 0xFD, 0xF5, 0xE6 } }, + { "Olive", { 0x80, 0x80, 0x00 } }, + { "OliveDrab", { 0x6B, 0x8E, 0x23 } }, + { "Orange", { 0xFF, 0xA5, 0x00 } }, + { "OrangeRed", { 0xFF, 0x45, 0x00 } }, + { "Orchid", { 0xDA, 0x70, 0xD6 } }, + { "PaleGoldenRod", { 0xEE, 0xE8, 0xAA } }, + { "PaleGreen", { 0x98, 0xFB, 0x98 } }, + { "PaleTurquoise", { 0xAF, 0xEE, 0xEE } }, + { "PaleVioletRed", { 0xD8, 0x70, 0x93 } }, + { "PapayaWhip", { 0xFF, 0xEF, 0xD5 } }, + { "PeachPuff", { 0xFF, 0xDA, 0xB9 } }, + { "Peru", { 0xCD, 0x85, 0x3F } }, + { "Pink", { 0xFF, 0xC0, 0xCB } }, + { "Plum", { 0xDD, 0xA0, 0xDD } }, + { "PowderBlue", { 0xB0, 0xE0, 0xE6 } }, + { "Purple", { 0x80, 0x00, 0x80 } }, + { "Red", { 0xFF, 0x00, 0x00 } }, + { "RosyBrown", { 0xBC, 0x8F, 0x8F } }, + { "RoyalBlue", { 0x41, 0x69, 0xE1 } }, + { "SaddleBrown", { 0x8B, 0x45, 0x13 } }, + { "Salmon", { 0xFA, 0x80, 0x72 } }, + { "SandyBrown", { 0xF4, 0xA4, 0x60 } }, + { "SeaGreen", { 0x2E, 0x8B, 0x57 } }, + { "SeaShell", { 0xFF, 0xF5, 0xEE } }, + { "Sienna", { 0xA0, 0x52, 0x2D } }, + { "Silver", { 0xC0, 0xC0, 0xC0 } }, + { "SkyBlue", { 0x87, 0xCE, 0xEB } }, + { "SlateBlue", { 0x6A, 0x5A, 0xCD } }, + { "SlateGray", { 0x70, 0x80, 0x90 } }, + { "Snow", { 0xFF, 0xFA, 0xFA } }, + { "SpringGreen", { 0x00, 0xFF, 0x7F } }, + { "SteelBlue", { 0x46, 0x82, 0xB4 } }, + { "Tan", { 0xD2, 0xB4, 0x8C } }, + { "Teal", { 0x00, 0x80, 0x80 } }, + { "Thistle", { 0xD8, 0xBF, 0xD8 } }, + { "Tomato", { 0xFF, 0x63, 0x47 } }, + { "Turquoise", { 0x40, 0xE0, 0xD0 } }, + { "Violet", { 0xEE, 0x82, 0xEE } }, + { "Wheat", { 0xF5, 0xDE, 0xB3 } }, + { "White", { 0xFF, 0xFF, 0xFF } }, + { "WhiteSmoke", { 0xF5, 0xF5, 0xF5 } }, + { "Yellow", { 0xFF, 0xFF, 0x00 } }, + { "YellowGreen", { 0x9A, 0xCD, 0x32 } }, +}; + +static int color_table_compare(const void *lhs, const void *rhs) +{ + return av_strcasecmp(lhs, ((const ColorEntry *)rhs)->name); +} + +#define ALPHA_SEP '@' + +int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, + void *log_ctx) +{ + char *tail, color_string2[128]; + const ColorEntry *entry; + int len, hex_offset = 0; + + if (color_string[0] == '#') { + hex_offset = 1; + } else if (!strncmp(color_string, "0x", 2)) + hex_offset = 2; + + if (slen < 0) + slen = strlen(color_string); + av_strlcpy(color_string2, color_string + hex_offset, + FFMIN(slen-hex_offset+1, sizeof(color_string2))); + if ((tail = strchr(color_string2, ALPHA_SEP))) + *tail++ = 0; + len = strlen(color_string2); + rgba_color[3] = 255; + + if (!av_strcasecmp(color_string2, "random") || !av_strcasecmp(color_string2, "bikeshed")) { + int rgba = av_get_random_seed(); + rgba_color[0] = rgba >> 24; + rgba_color[1] = rgba >> 16; + rgba_color[2] = rgba >> 8; + rgba_color[3] = rgba; + } else if (hex_offset || + strspn(color_string2, "0123456789ABCDEFabcdef") == len) { + char *tail; + unsigned int rgba = strtoul(color_string2, &tail, 16); + + if (*tail || (len != 6 && len != 8)) { + av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string2); + return AVERROR(EINVAL); + } + if (len == 8) { + rgba_color[3] = rgba; + rgba >>= 8; + } + rgba_color[0] = rgba >> 16; + rgba_color[1] = rgba >> 8; + rgba_color[2] = rgba; + } else { + entry = bsearch(color_string2, + color_table, + FF_ARRAY_ELEMS(color_table), + sizeof(ColorEntry), + color_table_compare); + if (!entry) { + av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string2); + return AVERROR(EINVAL); + } + memcpy(rgba_color, entry->rgb_color, 3); + } + + if (tail) { + double alpha; + const char *alpha_string = tail; + if (!strncmp(alpha_string, "0x", 2)) { + alpha = strtoul(alpha_string, &tail, 16); + } else { + double norm_alpha = strtod(alpha_string, &tail); + if (norm_alpha < 0.0 || norm_alpha > 1.0) + alpha = 256; + else + alpha = 255 * norm_alpha; + } + + if (tail == alpha_string || *tail || alpha > 255 || alpha < 0) { + av_log(log_ctx, AV_LOG_ERROR, "Invalid alpha value specifier '%s' in '%s'\n", + alpha_string, color_string); + return AVERROR(EINVAL); + } + rgba_color[3] = alpha; + } + + return 0; +} + +const char *av_get_known_color_name(int color_idx, const uint8_t **rgbp) +{ + const ColorEntry *color; + + if ((unsigned)color_idx >= FF_ARRAY_ELEMS(color_table)) + return NULL; + + color = &color_table[color_idx]; + if (rgbp) + *rgbp = color->rgb_color; + + return color->name; +} + +/* get a positive number between n_min and n_max, for a maximum length + of len_max. Return -1 if error. */ +static int date_get_num(const char **pp, + int n_min, int n_max, int len_max) +{ + int i, val, c; + const char *p; + + p = *pp; + val = 0; + for(i = 0; i < len_max; i++) { + c = *p; + if (!av_isdigit(c)) + break; + val = (val * 10) + c - '0'; + p++; + } + /* no number read ? */ + if (p == *pp) + return -1; + if (val < n_min || val > n_max) + return -1; + *pp = p; + return val; +} + +static int date_get_month(const char **pp) { + int i = 0; + for (; i < 12; i++) { + if (!av_strncasecmp(*pp, months[i], 3)) { + const char *mo_full = months[i] + 3; + int len = strlen(mo_full); + *pp += 3; + if (len > 0 && !av_strncasecmp(*pp, mo_full, len)) + *pp += len; + return i; + } + } + return -1; +} + +char *av_small_strptime(const char *p, const char *fmt, struct tm *dt) +{ + int c, val; + + while((c = *fmt++)) { + if (c != '%') { + if (av_isspace(c)) + for (; *p && av_isspace(*p); p++); + else if (*p != c) + return NULL; + else p++; + continue; + } + + c = *fmt++; + switch(c) { + case 'H': + case 'J': + val = date_get_num(&p, 0, c == 'H' ? 23 : INT_MAX, c == 'H' ? 2 : 4); + + if (val == -1) + return NULL; + dt->tm_hour = val; + break; + case 'M': + val = date_get_num(&p, 0, 59, 2); + if (val == -1) + return NULL; + dt->tm_min = val; + break; + case 'S': + val = date_get_num(&p, 0, 59, 2); + if (val == -1) + return NULL; + dt->tm_sec = val; + break; + case 'Y': + val = date_get_num(&p, 0, 9999, 4); + if (val == -1) + return NULL; + dt->tm_year = val - 1900; + break; + case 'm': + val = date_get_num(&p, 1, 12, 2); + if (val == -1) + return NULL; + dt->tm_mon = val - 1; + break; + case 'd': + val = date_get_num(&p, 1, 31, 2); + if (val == -1) + return NULL; + dt->tm_mday = val; + break; + case 'T': + p = av_small_strptime(p, "%H:%M:%S", dt); + if (!p) + return NULL; + break; + case 'b': + case 'B': + case 'h': + val = date_get_month(&p); + if (val == -1) + return NULL; + dt->tm_mon = val; + break; + case '%': + if (*p++ != '%') + return NULL; + break; + default: + return NULL; + } + } + + return (char*)p; +} + +time_t av_timegm(struct tm *tm) +{ + time_t t; + + int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday; + + if (m < 3) { + m += 12; + y--; + } + + t = 86400LL * + (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 719469); + + t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec; + + return t; +} + +int av_parse_time(int64_t *timeval, const char *timestr, int duration) +{ + const char *p, *q; + int64_t t, now64; + time_t now; + struct tm dt = { 0 }, tmbuf; + int today = 0, negative = 0, microseconds = 0, suffix = 1000000; + int i; + static const char * const date_fmt[] = { + "%Y - %m - %d", + "%Y%m%d", + }; + static const char * const time_fmt[] = { + "%H:%M:%S", + "%H%M%S", + }; + static const char * const tz_fmt[] = { + "%H:%M", + "%H%M", + "%H", + }; + + p = timestr; + q = NULL; + *timeval = INT64_MIN; + if (!duration) { + now64 = av_gettime(); + now = now64 / 1000000; + + if (!av_strcasecmp(timestr, "now")) { + *timeval = now64; + return 0; + } + + /* parse the year-month-day part */ + for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) { + q = av_small_strptime(p, date_fmt[i], &dt); + if (q) + break; + } + + /* if the year-month-day part is missing, then take the + * current year-month-day time */ + if (!q) { + today = 1; + q = p; + } + p = q; + + if (*p == 'T' || *p == 't') + p++; + else + while (av_isspace(*p)) + p++; + + /* parse the hour-minute-second part */ + for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) { + q = av_small_strptime(p, time_fmt[i], &dt); + if (q) + break; + } + } else { + /* parse timestr as a duration */ + if (p[0] == '-') { + negative = 1; + ++p; + } + /* parse timestr as HH:MM:SS */ + q = av_small_strptime(p, "%J:%M:%S", &dt); + if (!q) { + /* parse timestr as MM:SS */ + q = av_small_strptime(p, "%M:%S", &dt); + dt.tm_hour = 0; + } + if (!q) { + char *o; + /* parse timestr as S+ */ + errno = 0; + t = strtoll(p, &o, 10); + if (o == p) /* the parsing didn't succeed */ + return AVERROR(EINVAL); + if (errno == ERANGE) + return AVERROR(ERANGE); + q = o; + } else { + t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec; + } + } + + /* Now we have all the fields that we can get */ + if (!q) + return AVERROR(EINVAL); + + /* parse the .m... part */ + if (*q == '.') { + int n; + q++; + for (n = 100000; n >= 1; n /= 10, q++) { + if (!av_isdigit(*q)) + break; + microseconds += n * (*q - '0'); + } + while (av_isdigit(*q)) + q++; + } + + if (duration) { + if (q[0] == 'm' && q[1] == 's') { + suffix = 1000; + microseconds /= 1000; + q += 2; + } else if (q[0] == 'u' && q[1] == 's') { + suffix = 1; + microseconds = 0; + q += 2; + } else if (*q == 's') + q++; + } else { + int is_utc = *q == 'Z' || *q == 'z'; + int tzoffset = 0; + q += is_utc; + if (!today && !is_utc && (*q == '+' || *q == '-')) { + struct tm tz = { 0 }; + int sign = (*q == '+' ? -1 : 1); + q++; + p = q; + for (i = 0; i < FF_ARRAY_ELEMS(tz_fmt); i++) { + q = av_small_strptime(p, tz_fmt[i], &tz); + if (q) + break; + } + if (!q) + return AVERROR(EINVAL); + tzoffset = sign * (tz.tm_hour * 60 + tz.tm_min) * 60; + is_utc = 1; + } + if (today) { /* fill in today's date */ + struct tm dt2 = is_utc ? *gmtime_r(&now, &tmbuf) : *localtime_r(&now, &tmbuf); + dt2.tm_hour = dt.tm_hour; + dt2.tm_min = dt.tm_min; + dt2.tm_sec = dt.tm_sec; + dt = dt2; + } + dt.tm_isdst = is_utc ? 0 : -1; + t = is_utc ? av_timegm(&dt) : mktime(&dt); + t += tzoffset; + } + + /* Check that we are at the end of the string */ + if (*q) + return AVERROR(EINVAL); + + if (INT64_MAX / suffix < t || t < INT64_MIN / suffix) + return AVERROR(ERANGE); + t *= suffix; + if (INT64_MAX - microseconds < t) + return AVERROR(ERANGE); + t += microseconds; + if (t == INT64_MIN && negative) + return AVERROR(ERANGE); + *timeval = negative ? -t : t; + return 0; +} + +int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info) +{ + const char *p; + char tag[128], *q; + + p = info; + if (*p == '?') + p++; + for(;;) { + q = tag; + while (*p != '\0' && *p != '=' && *p != '&') { + if ((q - tag) < sizeof(tag) - 1) + *q++ = *p; + p++; + } + *q = '\0'; + q = arg; + if (*p == '=') { + p++; + while (*p != '&' && *p != '\0') { + if ((q - arg) < arg_size - 1) { + if (*p == '+') + *q++ = ' '; + else + *q++ = *p; + } + p++; + } + } + *q = '\0'; + if (!strcmp(tag, tag1)) + return 1; + if (*p != '&') + break; + p++; + } + return 0; +} diff --git a/libs/ffmpeg/libavutil/parseutils.h b/libs/ffmpeg/libavutil/parseutils.h new file mode 100644 index 00000000000..dad5c2775b2 --- /dev/null +++ b/libs/ffmpeg/libavutil/parseutils.h @@ -0,0 +1,197 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PARSEUTILS_H +#define AVUTIL_PARSEUTILS_H + +#include <time.h> + +#include "rational.h" + +/** + * @file + * misc parsing utilities + */ + +/** + * Parse str and store the parsed ratio in q. + * + * Note that a ratio with infinite (1/0) or negative value is + * considered valid, so you should check on the returned value if you + * want to exclude those values. + * + * The undefined value can be expressed using the "0:0" string. + * + * @param[in,out] q pointer to the AVRational which will contain the ratio + * @param[in] str the string to parse: it has to be a string in the format + * num:den, a float number or an expression + * @param[in] max the maximum allowed numerator and denominator + * @param[in] log_offset log level offset which is applied to the log + * level of log_ctx + * @param[in] log_ctx parent logging context + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_ratio(AVRational *q, const char *str, int max, + int log_offset, void *log_ctx); + +#define av_parse_ratio_quiet(rate, str, max) \ + av_parse_ratio(rate, str, max, AV_LOG_MAX_OFFSET, NULL) + +/** + * Parse str and put in width_ptr and height_ptr the detected values. + * + * @param[in,out] width_ptr pointer to the variable which will contain the detected + * width value + * @param[in,out] height_ptr pointer to the variable which will contain the detected + * height value + * @param[in] str the string to parse: it has to be a string in the format + * width x height or a valid video size abbreviation. + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str); + +/** + * Parse str and store the detected values in *rate. + * + * @param[in,out] rate pointer to the AVRational which will contain the detected + * frame rate + * @param[in] str the string to parse: it has to be a string in the format + * rate_num / rate_den, a float number or a valid video rate abbreviation + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_rate(AVRational *rate, const char *str); + +/** + * Put the RGBA values that correspond to color_string in rgba_color. + * + * @param rgba_color 4-elements array of uint8_t values, where the respective + * red, green, blue and alpha component values are written. + * @param color_string a string specifying a color. It can be the name of + * a color (case insensitive match) or a [0x|#]RRGGBB[AA] sequence, + * possibly followed by "@" and a string representing the alpha + * component. + * The alpha component may be a string composed by "0x" followed by an + * hexadecimal number or a decimal number between 0.0 and 1.0, which + * represents the opacity value (0x00/0.0 means completely transparent, + * 0xff/1.0 completely opaque). + * If the alpha component is not specified then 0xff is assumed. + * The string "random" will result in a random color. + * @param slen length of the initial part of color_string containing the + * color. It can be set to -1 if color_string is a null terminated string + * containing nothing else than the color. + * @param log_ctx a pointer to an arbitrary struct of which the first field + * is a pointer to an AVClass struct (used for av_log()). Can be NULL. + * @return >= 0 in case of success, a negative value in case of + * failure (for example if color_string cannot be parsed). + */ +int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, + void *log_ctx); + +/** + * Get the name of a color from the internal table of hard-coded named + * colors. + * + * This function is meant to enumerate the color names recognized by + * av_parse_color(). + * + * @param color_idx index of the requested color, starting from 0 + * @param rgb if not NULL, will point to a 3-elements array with the color value in RGB + * @return the color name string or NULL if color_idx is not in the array + */ +const char *av_get_known_color_name(int color_idx, const uint8_t **rgb); + +/** + * Parse timestr and return in *time a corresponding number of + * microseconds. + * + * @param timeval puts here the number of microseconds corresponding + * to the string in timestr. If the string represents a duration, it + * is the number of microseconds contained in the time interval. If + * the string is a date, is the number of microseconds since 1st of + * January, 1970 up to the time of the parsed date. If timestr cannot + * be successfully parsed, set *time to INT64_MIN. + + * @param timestr a string representing a date or a duration. + * - If a date the syntax is: + * @code + * [{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH:MM:SS[.m...]]]}|{HHMMSS[.m...]]]}}[Z] + * now + * @endcode + * If the value is "now" it takes the current time. + * Time is local time unless Z is appended, in which case it is + * interpreted as UTC. + * If the year-month-day part is not specified it takes the current + * year-month-day. + * - If a duration the syntax is: + * @code + * [-][HH:]MM:SS[.m...] + * [-]S+[.m...] + * @endcode + * @param duration flag which tells how to interpret timestr, if not + * zero timestr is interpreted as a duration, otherwise as a date + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_parse_time(int64_t *timeval, const char *timestr, int duration); + +/** + * Attempt to find a specific tag in a URL. + * + * syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done. + * Return 1 if found. + */ +int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); + +/** + * Simplified version of strptime + * + * Parse the input string p according to the format string fmt and + * store its results in the structure dt. + * This implementation supports only a subset of the formats supported + * by the standard strptime(). + * + * The supported input field descriptors are listed below. + * - `%%H`: the hour as a decimal number, using a 24-hour clock, in the + * range '00' through '23' + * - `%%J`: hours as a decimal number, in the range '0' through INT_MAX + * - `%%M`: the minute as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - `%%S`: the second as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - `%%Y`: the year as a decimal number, using the Gregorian calendar + * - `%%m`: the month as a decimal number, in the range '1' through '12' + * - `%%d`: the day of the month as a decimal number, in the range '1' + * through '31' + * - `%%T`: alias for `%%H:%%M:%%S` + * - `%%`: a literal `%` + * + * @return a pointer to the first character not processed in this function + * call. In case the input string contains more characters than + * required by the format string the return value points right after + * the last consumed input character. In case the whole input string + * is consumed the return value points to the null byte at the end of + * the string. On failure NULL is returned. + */ +char *av_small_strptime(const char *p, const char *fmt, struct tm *dt); + +/** + * Convert the decomposed UTC time in tm to a time_t value. + */ +time_t av_timegm(struct tm *tm); + +#endif /* AVUTIL_PARSEUTILS_H */ diff --git a/libs/ffmpeg/libavutil/pixdesc.c b/libs/ffmpeg/libavutil/pixdesc.c new file mode 100644 index 00000000000..90f9596defd --- /dev/null +++ b/libs/ffmpeg/libavutil/pixdesc.c @@ -0,0 +1,3938 @@ +/* + * pixel format descriptor + * Copyright (c) 2009 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdio.h> +#include <string.h> + +#include "avstring.h" +#include "common.h" +#include "pixfmt.h" +#include "pixdesc.h" +#include "intreadwrite.h" + +void av_read_image_line2(void *dst, + const uint8_t *data[4], const int linesize[4], + const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, + int read_pal_component, + int dst_element_size) +{ + AVComponentDescriptor comp = desc->comp[c]; + int plane = comp.plane; + int depth = comp.depth; + unsigned mask = (1ULL << depth) - 1; + int shift = comp.shift; + int step = comp.step; + int flags = desc->flags; + uint16_t *dst16 = dst; + uint32_t *dst32 = dst; + + if (!depth) + return; + + if (flags & AV_PIX_FMT_FLAG_BITSTREAM) { + if (step > 8) { + // Assume all channels are packed into a 32bit value + const uint8_t *byte_p = data[plane] + y * linesize[plane]; + const uint32_t *p = (uint32_t *)byte_p; + + while (w--) { + int val = AV_RB32(p); + val = (val >> comp.offset) & mask; + if (read_pal_component) + val = data[1][4*val + c]; + if (dst_element_size == 4) *dst32++ = val; + else *dst16++ = val; + p++; + } + } else { + int skip = x * step + comp.offset; + const uint8_t *p = data[plane] + y * linesize[plane] + (skip >> 3); + int shift = 8 - depth - (skip & 7); + + while (w--) { + int val = (*p >> shift) & mask; + if (read_pal_component) + val = data[1][4*val + c]; + shift -= step; + p -= shift >> 3; + shift &= 7; + if (dst_element_size == 4) *dst32++ = val; + else *dst16++ = val; + } + } + } else { + const uint8_t *p = data[plane] + y * linesize[plane] + + x * step + comp.offset; + int is_8bit = shift + depth <= 8; + int is_16bit= shift + depth <=16; + + if (is_8bit) + p += !!(flags & AV_PIX_FMT_FLAG_BE); + + while (w--) { + unsigned val; + if (is_8bit) val = *p; + else if(is_16bit) val = flags & AV_PIX_FMT_FLAG_BE ? AV_RB16(p) : AV_RL16(p); + else val = flags & AV_PIX_FMT_FLAG_BE ? AV_RB32(p) : AV_RL32(p); + val = (val >> shift) & mask; + if (read_pal_component) + val = data[1][4 * val + c]; + p += step; + if (dst_element_size == 4) *dst32++ = val; + else *dst16++ = val; + } + } +} + +void av_read_image_line(uint16_t *dst, + const uint8_t *data[4], const int linesize[4], + const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, + int read_pal_component) +{ + av_read_image_line2(dst, data, linesize, desc,x, y, c, w, + read_pal_component, + 2); +} + +void av_write_image_line2(const void *src, + uint8_t *data[4], const int linesize[4], + const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int src_element_size) +{ + AVComponentDescriptor comp = desc->comp[c]; + int plane = comp.plane; + int depth = comp.depth; + int step = comp.step; + int flags = desc->flags; + const uint32_t *src32 = src; + const uint16_t *src16 = src; + + if (!depth) + return; + + if (flags & AV_PIX_FMT_FLAG_BITSTREAM) { + if (step > 8) { + // Assume all channels are packed into a 32bit value + const uint8_t *byte_p = data[plane] + y * linesize[plane]; + uint32_t *p = (uint32_t *)byte_p; + int offset = comp.offset; + uint32_t mask = ((1ULL << depth) - 1) << offset; + + while (w--) { + unsigned val = src_element_size == 4 ? *src32++ : *src16++; + AV_WB32(p, (AV_RB32(p) & ~mask) | (val << offset)); + p++; + } + } else { + int skip = x * step + comp.offset; + uint8_t *p = data[plane] + y * linesize[plane] + (skip >> 3); + int shift = 8 - depth - (skip & 7); + + while (w--) { + *p |= (src_element_size == 4 ? *src32++ : *src16++) << shift; + shift -= step; + p -= shift >> 3; + shift &= 7; + } + } + } else { + int shift = comp.shift; + uint8_t *p = data[plane] + y * linesize[plane] + + x * step + comp.offset; + + if (shift + depth <= 8) { + p += !!(flags & AV_PIX_FMT_FLAG_BE); + while (w--) { + *p |= ((src_element_size == 4 ? *src32++ : *src16++) << shift); + p += step; + } + } else { + while (w--) { + unsigned s = (src_element_size == 4 ? *src32++ : *src16++); + if (shift + depth <= 16) { + if (flags & AV_PIX_FMT_FLAG_BE) { + uint16_t val = AV_RB16(p) | (s << shift); + AV_WB16(p, val); + } else { + uint16_t val = AV_RL16(p) | (s << shift); + AV_WL16(p, val); + } + } else { + if (flags & AV_PIX_FMT_FLAG_BE) { + uint32_t val = AV_RB32(p) | (s << shift); + AV_WB32(p, val); + } else { + uint32_t val = AV_RL32(p) | (s << shift); + AV_WL32(p, val); + } + } + p += step; + } + } + } +} + +void av_write_image_line(const uint16_t *src, + uint8_t *data[4], const int linesize[4], + const AVPixFmtDescriptor *desc, + int x, int y, int c, int w) +{ + av_write_image_line2(src, data, linesize, desc, x, y, c, w, 2); +} + +static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { + [AV_PIX_FMT_YUV420P] = { + .name = "yuv420p", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUYV422] = { + .name = "yuyv422", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 8 }, /* Y */ + { 0, 4, 1, 0, 8 }, /* U */ + { 0, 4, 3, 0, 8 }, /* V */ + }, + }, + [AV_PIX_FMT_YVYU422] = { + .name = "yvyu422", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 8 }, /* Y */ + { 0, 4, 3, 0, 8 }, /* U */ + { 0, 4, 1, 0, 8 }, /* V */ + }, + }, + [AV_PIX_FMT_Y210LE] = { + .name = "y210le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 6, 10 }, /* Y */ + { 0, 8, 2, 6, 10 }, /* U */ + { 0, 8, 6, 6, 10 }, /* V */ + }, + }, + [AV_PIX_FMT_Y210BE] = { + .name = "y210be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 6, 10 }, /* Y */ + { 0, 8, 2, 6, 10 }, /* U */ + { 0, 8, 6, 6, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_RGB24] = { + .name = "rgb24", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 3, 0, 0, 8 }, /* R */ + { 0, 3, 1, 0, 8 }, /* G */ + { 0, 3, 2, 0, 8 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR24] = { + .name = "bgr24", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 3, 2, 0, 8 }, /* R */ + { 0, 3, 1, 0, 8 }, /* G */ + { 0, 3, 0, 0, 8 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_X2RGB10LE] = { + .name = "x2rgb10le", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 4, 2, 4, 10 }, /* R */ + { 0, 4, 1, 2, 10 }, /* G */ + { 0, 4, 0, 0, 10 }, /* B */ + { 0, 4, 3, 6, 2 }, /* X */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_X2RGB10BE] = { + .name = "x2rgb10be", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 4, 0, 4, 10 }, /* R */ + { 0, 4, 1, 2, 10 }, /* G */ + { 0, 4, 2, 0, 10 }, /* B */ + { 0, 4, 3, 6, 2 }, /* X */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_X2BGR10LE] = { + .name = "x2bgr10le", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 4, 0, 0, 10 }, /* R */ + { 0, 4, 1, 2, 10 }, /* G */ + { 0, 4, 2, 4, 10 }, /* B */ + { 0, 4, 3, 6, 2 }, /* X */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_X2BGR10BE] = { + .name = "x2bgr10be", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 4, 2, 0, 10 }, /* R */ + { 0, 4, 1, 2, 10 }, /* G */ + { 0, 4, 0, 4, 10 }, /* B */ + { 0, 4, 3, 6, 2 }, /* X */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_YUV422P] = { + .name = "yuv422p", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P] = { + .name = "yuv444p", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV410P] = { + .name = "yuv410p", + .nb_components = 3, + .log2_chroma_w = 2, + .log2_chroma_h = 2, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV411P] = { + .name = "yuv411p", + .nb_components = 3, + .log2_chroma_w = 2, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUVJ411P] = { + .name = "yuvj411p", + .nb_components = 3, + .log2_chroma_w = 2, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_GRAY8] = { + .name = "gray", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + }, + .alias = "gray8,y8", + }, + [AV_PIX_FMT_MONOWHITE] = { + .name = "monow", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BITSTREAM, + }, + [AV_PIX_FMT_MONOBLACK] = { + .name = "monob", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 7, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BITSTREAM, + }, + [AV_PIX_FMT_PAL8] = { + .name = "pal8", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8 }, + }, + .flags = AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVJ420P] = { + .name = "yuvj420p", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUVJ422P] = { + .name = "yuvj422p", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUVJ444P] = { + .name = "yuvj444p", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_UYVY422] = { + .name = "uyvy422", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 1, 0, 8 }, /* Y */ + { 0, 4, 0, 0, 8 }, /* U */ + { 0, 4, 2, 0, 8 }, /* V */ + }, + }, + [AV_PIX_FMT_UYYVYY411] = { + .name = "uyyvyy411", + .nb_components = 3, + .log2_chroma_w = 2, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 1, 0, 8 }, /* Y */ + { 0, 6, 0, 0, 8 }, /* U */ + { 0, 6, 3, 0, 8 }, /* V */ + }, + }, + [AV_PIX_FMT_BGR8] = { + .name = "bgr8", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 3 }, /* R */ + { 0, 1, 0, 3, 3 }, /* G */ + { 0, 1, 0, 6, 2 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR4] = { + .name = "bgr4", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 3, 0, 1 }, /* R */ + { 0, 4, 1, 0, 2 }, /* G */ + { 0, 4, 0, 0, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR4_BYTE] = { + .name = "bgr4_byte", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 1 }, /* R */ + { 0, 1, 0, 1, 2 }, /* G */ + { 0, 1, 0, 3, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB8] = { + .name = "rgb8", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 5, 3 }, /* R */ + { 0, 1, 0, 2, 3 }, /* G */ + { 0, 1, 0, 0, 2 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB4] = { + .name = "rgb4", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 1 }, /* R */ + { 0, 4, 1, 0, 2 }, /* G */ + { 0, 4, 3, 0, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB4_BYTE] = { + .name = "rgb4_byte", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 3, 1 }, /* R */ + { 0, 1, 0, 1, 2 }, /* G */ + { 0, 1, 0, 0, 1 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_NV12] = { + .name = "nv12", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 2, 0, 0, 8 }, /* U */ + { 1, 2, 1, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_NV21] = { + .name = "nv21", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 2, 1, 0, 8 }, /* U */ + { 1, 2, 0, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_ARGB] = { + .name = "argb", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 1, 0, 8 }, /* R */ + { 0, 4, 2, 0, 8 }, /* G */ + { 0, 4, 3, 0, 8 }, /* B */ + { 0, 4, 0, 0, 8 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_RGBA] = { + .name = "rgba", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 8 }, /* R */ + { 0, 4, 1, 0, 8 }, /* G */ + { 0, 4, 2, 0, 8 }, /* B */ + { 0, 4, 3, 0, 8 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_ABGR] = { + .name = "abgr", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 3, 0, 8 }, /* R */ + { 0, 4, 2, 0, 8 }, /* G */ + { 0, 4, 1, 0, 8 }, /* B */ + { 0, 4, 0, 0, 8 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_BGRA] = { + .name = "bgra", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 2, 0, 8 }, /* R */ + { 0, 4, 1, 0, 8 }, /* G */ + { 0, 4, 0, 0, 8 }, /* B */ + { 0, 4, 3, 0, 8 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_0RGB] = { + .name = "0rgb", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 4, 1, 0, 8 }, /* R */ + { 0, 4, 2, 0, 8 }, /* G */ + { 0, 4, 3, 0, 8 }, /* B */ + { 0, 4, 0, 0, 8 }, /* X */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB0] = { + .name = "rgb0", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 4, 0, 0, 8 }, /* R */ + { 0, 4, 1, 0, 8 }, /* G */ + { 0, 4, 2, 0, 8 }, /* B */ + { 0, 4, 3, 0, 8 }, /* X */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_0BGR] = { + .name = "0bgr", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 4, 3, 0, 8 }, /* R */ + { 0, 4, 2, 0, 8 }, /* G */ + { 0, 4, 1, 0, 8 }, /* B */ + { 0, 4, 0, 0, 8 }, /* X */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR0] = { + .name = "bgr0", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 4, 2, 0, 8 }, /* R */ + { 0, 4, 1, 0, 8 }, /* G */ + { 0, 4, 0, 0, 8 }, /* B */ + { 0, 4, 3, 0, 8 }, /* X */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GRAY9BE] = { + .name = "gray9be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y9be", + }, + [AV_PIX_FMT_GRAY9LE] = { + .name = "gray9le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + }, + .alias = "y9le", + }, + [AV_PIX_FMT_GRAY10BE] = { + .name = "gray10be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y10be", + }, + [AV_PIX_FMT_GRAY10LE] = { + .name = "gray10le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + }, + .alias = "y10le", + }, + [AV_PIX_FMT_GRAY12BE] = { + .name = "gray12be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y12be", + }, + [AV_PIX_FMT_GRAY12LE] = { + .name = "gray12le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + }, + .alias = "y12le", + }, + [AV_PIX_FMT_GRAY14BE] = { + .name = "gray14be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y14be", + }, + [AV_PIX_FMT_GRAY14LE] = { + .name = "gray14le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14 }, /* Y */ + }, + .alias = "y14le", + }, + [AV_PIX_FMT_GRAY16BE] = { + .name = "gray16be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y16be", + }, + [AV_PIX_FMT_GRAY16LE] = { + .name = "gray16le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + }, + .alias = "y16le", + }, + [AV_PIX_FMT_GRAY32BE] = { + .name = "gray32be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 32 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y32be", + }, + [AV_PIX_FMT_GRAY32LE] = { + .name = "gray32le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 32 }, /* Y */ + }, + .alias = "y32le", + }, + [AV_PIX_FMT_YUV440P] = { + .name = "yuv440p", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUVJ440P] = { + .name = "yuvj440p", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV440P10LE] = { + .name = "yuv440p10le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV440P10BE] = { + .name = "yuv440p10be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV440P12LE] = { + .name = "yuv440p12le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + { 1, 2, 0, 0, 12 }, /* U */ + { 2, 2, 0, 0, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV440P12BE] = { + .name = "yuv440p12be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + { 1, 2, 0, 0, 12 }, /* U */ + { 2, 2, 0, 0, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUVA420P] = { + .name = "yuva420p", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + { 3, 1, 0, 0, 8 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P] = { + .name = "yuva422p", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + { 3, 1, 0, 0, 8 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P] = { + .name = "yuva444p", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 1, 0, 0, 8 }, /* U */ + { 2, 1, 0, 0, 8 }, /* V */ + { 3, 1, 0, 0, 8 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA420P9BE] = { + .name = "yuva420p9be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + { 1, 2, 0, 0, 9 }, /* U */ + { 2, 2, 0, 0, 9 }, /* V */ + { 3, 2, 0, 0, 9 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA420P9LE] = { + .name = "yuva420p9le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + { 1, 2, 0, 0, 9 }, /* U */ + { 2, 2, 0, 0, 9 }, /* V */ + { 3, 2, 0, 0, 9 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P9BE] = { + .name = "yuva422p9be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + { 1, 2, 0, 0, 9 }, /* U */ + { 2, 2, 0, 0, 9 }, /* V */ + { 3, 2, 0, 0, 9 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P9LE] = { + .name = "yuva422p9le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + { 1, 2, 0, 0, 9 }, /* U */ + { 2, 2, 0, 0, 9 }, /* V */ + { 3, 2, 0, 0, 9 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P9BE] = { + .name = "yuva444p9be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + { 1, 2, 0, 0, 9 }, /* U */ + { 2, 2, 0, 0, 9 }, /* V */ + { 3, 2, 0, 0, 9 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P9LE] = { + .name = "yuva444p9le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + { 1, 2, 0, 0, 9 }, /* U */ + { 2, 2, 0, 0, 9 }, /* V */ + { 3, 2, 0, 0, 9 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA420P10BE] = { + .name = "yuva420p10be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + { 3, 2, 0, 0, 10 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA420P10LE] = { + .name = "yuva420p10le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + { 3, 2, 0, 0, 10 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P10BE] = { + .name = "yuva422p10be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + { 3, 2, 0, 0, 10 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P10LE] = { + .name = "yuva422p10le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + { 3, 2, 0, 0, 10 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P10BE] = { + .name = "yuva444p10be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + { 3, 2, 0, 0, 10 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P10LE] = { + .name = "yuva444p10le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + { 3, 2, 0, 0, 10 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA420P16BE] = { + .name = "yuva420p16be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 2, 0, 0, 16 }, /* U */ + { 2, 2, 0, 0, 16 }, /* V */ + { 3, 2, 0, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA420P16LE] = { + .name = "yuva420p16le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 2, 0, 0, 16 }, /* U */ + { 2, 2, 0, 0, 16 }, /* V */ + { 3, 2, 0, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P16BE] = { + .name = "yuva422p16be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 2, 0, 0, 16 }, /* U */ + { 2, 2, 0, 0, 16 }, /* V */ + { 3, 2, 0, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P16LE] = { + .name = "yuva422p16le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 2, 0, 0, 16 }, /* U */ + { 2, 2, 0, 0, 16 }, /* V */ + { 3, 2, 0, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P16BE] = { + .name = "yuva444p16be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 2, 0, 0, 16 }, /* U */ + { 2, 2, 0, 0, 16 }, /* V */ + { 3, 2, 0, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P16LE] = { + .name = "yuva444p16le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 2, 0, 0, 16 }, /* U */ + { 2, 2, 0, 0, 16 }, /* V */ + { 3, 2, 0, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_RGB48BE] = { + .name = "rgb48be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 0, 0, 16 }, /* R */ + { 0, 6, 2, 0, 16 }, /* G */ + { 0, 6, 4, 0, 16 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_RGB48LE] = { + .name = "rgb48le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 0, 0, 16 }, /* R */ + { 0, 6, 2, 0, 16 }, /* G */ + { 0, 6, 4, 0, 16 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGBA64BE] = { + .name = "rgba64be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 0, 0, 16 }, /* R */ + { 0, 8, 2, 0, 16 }, /* G */ + { 0, 8, 4, 0, 16 }, /* B */ + { 0, 8, 6, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_RGBA64LE] = { + .name = "rgba64le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 0, 0, 16 }, /* R */ + { 0, 8, 2, 0, 16 }, /* G */ + { 0, 8, 4, 0, 16 }, /* B */ + { 0, 8, 6, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_RGB565BE] = { + .name = "rgb565be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, -1, 3, 5 }, /* R */ + { 0, 2, 0, 5, 6 }, /* G */ + { 0, 2, 0, 0, 5 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB565LE] = { + .name = "rgb565le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 1, 3, 5 }, /* R */ + { 0, 2, 0, 5, 6 }, /* G */ + { 0, 2, 0, 0, 5 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB555BE] = { + .name = "rgb555be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, -1, 2, 5 }, /* R */ + { 0, 2, 0, 5, 5 }, /* G */ + { 0, 2, 0, 0, 5 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB555LE] = { + .name = "rgb555le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 1, 2, 5 }, /* R */ + { 0, 2, 0, 5, 5 }, /* G */ + { 0, 2, 0, 0, 5 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB444BE] = { + .name = "rgb444be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, -1, 0, 4 }, /* R */ + { 0, 2, 0, 4, 4 }, /* G */ + { 0, 2, 0, 0, 4 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB444LE] = { + .name = "rgb444le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 1, 0, 4 }, /* R */ + { 0, 2, 0, 4, 4 }, /* G */ + { 0, 2, 0, 0, 4 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR48BE] = { + .name = "bgr48be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 4, 0, 16 }, /* R */ + { 0, 6, 2, 0, 16 }, /* G */ + { 0, 6, 0, 0, 16 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR48LE] = { + .name = "bgr48le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 4, 0, 16 }, /* R */ + { 0, 6, 2, 0, 16 }, /* G */ + { 0, 6, 0, 0, 16 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGRA64BE] = { + .name = "bgra64be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 4, 0, 16 }, /* R */ + { 0, 8, 2, 0, 16 }, /* G */ + { 0, 8, 0, 0, 16 }, /* B */ + { 0, 8, 6, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_BGRA64LE] = { + .name = "bgra64le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 4, 0, 16 }, /* R */ + { 0, 8, 2, 0, 16 }, /* G */ + { 0, 8, 0, 0, 16 }, /* B */ + { 0, 8, 6, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_BGR565BE] = { + .name = "bgr565be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 5 }, /* R */ + { 0, 2, 0, 5, 6 }, /* G */ + { 0, 2, -1, 3, 5 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR565LE] = { + .name = "bgr565le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 5 }, /* R */ + { 0, 2, 0, 5, 6 }, /* G */ + { 0, 2, 1, 3, 5 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR555BE] = { + .name = "bgr555be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 5 }, /* R */ + { 0, 2, 0, 5, 5 }, /* G */ + { 0, 2, -1, 2, 5 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR555LE] = { + .name = "bgr555le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 5 }, /* R */ + { 0, 2, 0, 5, 5 }, /* G */ + { 0, 2, 1, 2, 5 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR444BE] = { + .name = "bgr444be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 4 }, /* R */ + { 0, 2, 0, 4, 4 }, /* G */ + { 0, 2, -1, 0, 4 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_BGR444LE] = { + .name = "bgr444le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 4 }, /* R */ + { 0, 2, 0, 4, 4 }, /* G */ + { 0, 2, 1, 0, 4 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_VAAPI] = { + .name = "vaapi", + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_YUV420P9LE] = { + .name = "yuv420p9le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + { 1, 2, 0, 0, 9 }, /* U */ + { 2, 2, 0, 0, 9 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P9BE] = { + .name = "yuv420p9be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + { 1, 2, 0, 0, 9 }, /* U */ + { 2, 2, 0, 0, 9 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P10LE] = { + .name = "yuv420p10le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P10BE] = { + .name = "yuv420p10be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P12LE] = { + .name = "yuv420p12le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + { 1, 2, 0, 0, 12 }, /* U */ + { 2, 2, 0, 0, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P12BE] = { + .name = "yuv420p12be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + { 1, 2, 0, 0, 12 }, /* U */ + { 2, 2, 0, 0, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P14LE] = { + .name = "yuv420p14le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 14 }, /* Y */ + { 1, 2, 0, 0, 14 }, /* U */ + { 2, 2, 0, 0, 14 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P14BE] = { + .name = "yuv420p14be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 14 }, /* Y */ + { 1, 2, 0, 0, 14 }, /* U */ + { 2, 2, 0, 0, 14 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P16LE] = { + .name = "yuv420p16le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 2, 0, 0, 16 }, /* U */ + { 2, 2, 0, 0, 16 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV420P16BE] = { + .name = "yuv420p16be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 2, 0, 0, 16 }, /* U */ + { 2, 2, 0, 0, 16 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P9LE] = { + .name = "yuv422p9le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + { 1, 2, 0, 0, 9 }, /* U */ + { 2, 2, 0, 0, 9 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P9BE] = { + .name = "yuv422p9be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + { 1, 2, 0, 0, 9 }, /* U */ + { 2, 2, 0, 0, 9 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P10LE] = { + .name = "yuv422p10le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P10BE] = { + .name = "yuv422p10be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P12LE] = { + .name = "yuv422p12le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + { 1, 2, 0, 0, 12 }, /* U */ + { 2, 2, 0, 0, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P12BE] = { + .name = "yuv422p12be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + { 1, 2, 0, 0, 12 }, /* U */ + { 2, 2, 0, 0, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P14LE] = { + .name = "yuv422p14le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14 }, /* Y */ + { 1, 2, 0, 0, 14 }, /* U */ + { 2, 2, 0, 0, 14 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P14BE] = { + .name = "yuv422p14be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14 }, /* Y */ + { 1, 2, 0, 0, 14 }, /* U */ + { 2, 2, 0, 0, 14 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P16LE] = { + .name = "yuv422p16le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 2, 0, 0, 16 }, /* U */ + { 2, 2, 0, 0, 16 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV422P16BE] = { + .name = "yuv422p16be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 2, 0, 0, 16 }, /* U */ + { 2, 2, 0, 0, 16 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P16LE] = { + .name = "yuv444p16le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 2, 0, 0, 16 }, /* U */ + { 2, 2, 0, 0, 16 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P16BE] = { + .name = "yuv444p16be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 2, 0, 0, 16 }, /* U */ + { 2, 2, 0, 0, 16 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P10LE] = { + .name = "yuv444p10le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P10BE] = { + .name = "yuv444p10be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 2, 0, 0, 10 }, /* U */ + { 2, 2, 0, 0, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P10MSBLE] = { + .name = "yuv444p10msble", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 6, 10 }, /* Y */ + { 1, 2, 0, 6, 10 }, /* U */ + { 2, 2, 0, 6, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P10MSBBE] = { + .name = "yuv444p10msbbe", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 6, 10 }, /* Y */ + { 1, 2, 0, 6, 10 }, /* U */ + { 2, 2, 0, 6, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P9LE] = { + .name = "yuv444p9le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + { 1, 2, 0, 0, 9 }, /* U */ + { 2, 2, 0, 0, 9 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P9BE] = { + .name = "yuv444p9be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 9 }, /* Y */ + { 1, 2, 0, 0, 9 }, /* U */ + { 2, 2, 0, 0, 9 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P12LE] = { + .name = "yuv444p12le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + { 1, 2, 0, 0, 12 }, /* U */ + { 2, 2, 0, 0, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P12BE] = { + .name = "yuv444p12be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + { 1, 2, 0, 0, 12 }, /* U */ + { 2, 2, 0, 0, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P12MSBLE] = { + .name = "yuv444p12msble", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 4, 12 }, /* Y */ + { 1, 2, 0, 4, 12 }, /* U */ + { 2, 2, 0, 4, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P12MSBBE] = { + .name = "yuv444p12msbbe", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 4, 12 }, /* Y */ + { 1, 2, 0, 4, 12 }, /* U */ + { 2, 2, 0, 4, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P14LE] = { + .name = "yuv444p14le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14 }, /* Y */ + { 1, 2, 0, 0, 14 }, /* U */ + { 2, 2, 0, 0, 14 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_YUV444P14BE] = { + .name = "yuv444p14be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14 }, /* Y */ + { 1, 2, 0, 0, 14 }, /* U */ + { 2, 2, 0, 0, 14 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_D3D11VA_VLD] = { + .name = "d3d11va_vld", + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_DXVA2_VLD] = { + .name = "dxva2_vld", + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_YA8] = { + .name = "ya8", + .nb_components = 2, + .comp = { + { 0, 2, 0, 0, 8 }, /* Y */ + { 0, 2, 1, 0, 8 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_ALPHA, + .alias = "gray8a", + }, + [AV_PIX_FMT_YA16LE] = { + .name = "ya16le", + .nb_components = 2, + .comp = { + { 0, 4, 0, 0, 16 }, /* Y */ + { 0, 4, 2, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YA16BE] = { + .name = "ya16be", + .nb_components = 2, + .comp = { + { 0, 4, 0, 0, 16 }, /* Y */ + { 0, 4, 2, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_VIDEOTOOLBOX] = { + .name = "videotoolbox_vld", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_GBRP] = { + .name = "gbrp", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 1, 0, 0, 8 }, /* R */ + { 0, 1, 0, 0, 8 }, /* G */ + { 1, 1, 0, 0, 8 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP9LE] = { + .name = "gbrp9le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 9 }, /* R */ + { 0, 2, 0, 0, 9 }, /* G */ + { 1, 2, 0, 0, 9 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP9BE] = { + .name = "gbrp9be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 9 }, /* R */ + { 0, 2, 0, 0, 9 }, /* G */ + { 1, 2, 0, 0, 9 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP10LE] = { + .name = "gbrp10le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 10 }, /* R */ + { 0, 2, 0, 0, 10 }, /* G */ + { 1, 2, 0, 0, 10 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP10BE] = { + .name = "gbrp10be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 10 }, /* R */ + { 0, 2, 0, 0, 10 }, /* G */ + { 1, 2, 0, 0, 10 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP10MSBLE] = { + .name = "gbrp10msble", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 6, 10 }, /* R */ + { 0, 2, 0, 6, 10 }, /* G */ + { 1, 2, 0, 6, 10 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP10MSBBE] = { + .name = "gbrp10msbbe", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 6, 10 }, /* R */ + { 0, 2, 0, 6, 10 }, /* G */ + { 1, 2, 0, 6, 10 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP12LE] = { + .name = "gbrp12le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 12 }, /* R */ + { 0, 2, 0, 0, 12 }, /* G */ + { 1, 2, 0, 0, 12 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP12BE] = { + .name = "gbrp12be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 12 }, /* R */ + { 0, 2, 0, 0, 12 }, /* G */ + { 1, 2, 0, 0, 12 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP12MSBLE] = { + .name = "gbrp12msble", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 4, 12 }, /* R */ + { 0, 2, 0, 4, 12 }, /* G */ + { 1, 2, 0, 4, 12 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP12MSBBE] = { + .name = "gbrp12msbbe", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 4, 12 }, /* R */ + { 0, 2, 0, 4, 12 }, /* G */ + { 1, 2, 0, 4, 12 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP14LE] = { + .name = "gbrp14le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 14 }, /* R */ + { 0, 2, 0, 0, 14 }, /* G */ + { 1, 2, 0, 0, 14 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP14BE] = { + .name = "gbrp14be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 14 }, /* R */ + { 0, 2, 0, 0, 14 }, /* G */ + { 1, 2, 0, 0, 14 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP16LE] = { + .name = "gbrp16le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 16 }, /* R */ + { 0, 2, 0, 0, 16 }, /* G */ + { 1, 2, 0, 0, 16 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRP16BE] = { + .name = "gbrp16be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 16 }, /* R */ + { 0, 2, 0, 0, 16 }, /* G */ + { 1, 2, 0, 0, 16 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRAP] = { + .name = "gbrap", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 1, 0, 0, 8 }, /* R */ + { 0, 1, 0, 0, 8 }, /* G */ + { 1, 1, 0, 0, 8 }, /* B */ + { 3, 1, 0, 0, 8 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP16LE] = { + .name = "gbrap16le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 16 }, /* R */ + { 0, 2, 0, 0, 16 }, /* G */ + { 1, 2, 0, 0, 16 }, /* B */ + { 3, 2, 0, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP16BE] = { + .name = "gbrap16be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 16 }, /* R */ + { 0, 2, 0, 0, 16 }, /* G */ + { 1, 2, 0, 0, 16 }, /* B */ + { 3, 2, 0, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP32LE] = { + .name = "gbrap32le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32 }, /* R */ + { 0, 4, 0, 0, 32 }, /* G */ + { 1, 4, 0, 0, 32 }, /* B */ + { 3, 4, 0, 0, 32 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP32BE] = { + .name = "gbrap32be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32 }, /* R */ + { 0, 4, 0, 0, 32 }, /* G */ + { 1, 4, 0, 0, 32 }, /* B */ + { 3, 4, 0, 0, 32 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_VDPAU] = { + .name = "vdpau", + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_XYZ12LE] = { + .name = "xyz12le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 0, 4, 12 }, /* X */ + { 0, 6, 2, 4, 12 }, /* Y */ + { 0, 6, 4, 4, 12 }, /* Z */ + }, + .flags = AV_PIX_FMT_FLAG_XYZ, + }, + [AV_PIX_FMT_XYZ12BE] = { + .name = "xyz12be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 0, 4, 12 }, /* X */ + { 0, 6, 2, 4, 12 }, /* Y */ + { 0, 6, 4, 4, 12 }, /* Z */ + }, + .flags = AV_PIX_FMT_FLAG_XYZ | AV_PIX_FMT_FLAG_BE, + }, + +#define BAYER8_DESC_COMMON \ + .nb_components= 3, \ + .log2_chroma_w= 0, \ + .log2_chroma_h= 0, \ + .comp = { \ + { 0, 1, 0, 0, 2 }, \ + { 0, 1, 0, 0, 4 }, \ + { 0, 1, 0, 0, 2 }, \ + }, \ + +#define BAYER16_DESC_COMMON \ + .nb_components= 3, \ + .log2_chroma_w= 0, \ + .log2_chroma_h= 0, \ + .comp = { \ + { 0, 2, 0, 0, 4 }, \ + { 0, 2, 0, 0, 8 }, \ + { 0, 2, 0, 0, 4 }, \ + }, \ + + [AV_PIX_FMT_BAYER_BGGR8] = { + .name = "bayer_bggr8", + BAYER8_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_BGGR16LE] = { + .name = "bayer_bggr16le", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_BGGR16BE] = { + .name = "bayer_bggr16be", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_RGGB8] = { + .name = "bayer_rggb8", + BAYER8_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_RGGB16LE] = { + .name = "bayer_rggb16le", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_RGGB16BE] = { + .name = "bayer_rggb16be", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_GBRG8] = { + .name = "bayer_gbrg8", + BAYER8_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_GBRG16LE] = { + .name = "bayer_gbrg16le", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_GBRG16BE] = { + .name = "bayer_gbrg16be", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_GRBG8] = { + .name = "bayer_grbg8", + BAYER8_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_GRBG16LE] = { + .name = "bayer_grbg16le", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_BAYER_GRBG16BE] = { + .name = "bayer_grbg16be", + BAYER16_DESC_COMMON + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_BAYER, + }, + [AV_PIX_FMT_NV16] = { + .name = "nv16", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 2, 0, 0, 8 }, /* U */ + { 1, 2, 1, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_NV20LE] = { + .name = "nv20le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 4, 0, 0, 10 }, /* U */ + { 1, 4, 2, 0, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_NV20BE] = { + .name = "nv20be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 10 }, /* Y */ + { 1, 4, 0, 0, 10 }, /* U */ + { 1, 4, 2, 0, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_QSV] = { + .name = "qsv", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_MEDIACODEC] = { + .name = "mediacodec", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_MMAL] = { + .name = "mmal", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_CUDA] = { + .name = "cuda", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_AMF_SURFACE] = { + .name = "amf", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_VYU444] = { + .name = "vyu444", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 3, 1, 0, 8 }, /* Y */ + { 0, 3, 2, 0, 8 }, /* U */ + { 0, 3, 0, 0, 8 }, /* V */ + }, + }, + [AV_PIX_FMT_UYVA] = { + .name = "uyva", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 1, 0, 8 }, /* Y */ + { 0, 4, 0, 0, 8 }, /* U */ + { 0, 4, 2, 0, 8 }, /* V */ + { 0, 4, 3, 0, 8 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_AYUV] = { + .name = "ayuv", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 1, 0, 8 }, /* Y */ + { 0, 4, 2, 0, 8 }, /* U */ + { 0, 4, 3, 0, 8 }, /* V */ + { 0, 4, 0, 0, 8 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_AYUV64LE] = { + .name = "ayuv64le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 2, 0, 16 }, /* Y */ + { 0, 8, 4, 0, 16 }, /* U */ + { 0, 8, 6, 0, 16 }, /* V */ + { 0, 8, 0, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_AYUV64BE] = { + .name = "ayuv64be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 2, 0, 16 }, /* Y */ + { 0, 8, 4, 0, 16 }, /* U */ + { 0, 8, 6, 0, 16 }, /* V */ + { 0, 8, 0, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_P010LE] = { + .name = "p010le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 6, 10 }, /* Y */ + { 1, 4, 0, 6, 10 }, /* U */ + { 1, 4, 2, 6, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_P010BE] = { + .name = "p010be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 6, 10 }, /* Y */ + { 1, 4, 0, 6, 10 }, /* U */ + { 1, 4, 2, 6, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_P012LE] = { + .name = "p012le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 4, 12 }, /* Y */ + { 1, 4, 0, 4, 12 }, /* U */ + { 1, 4, 2, 4, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_P012BE] = { + .name = "p012be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 4, 12 }, /* Y */ + { 1, 4, 0, 4, 12 }, /* U */ + { 1, 4, 2, 4, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_P016LE] = { + .name = "p016le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 4, 0, 0, 16 }, /* U */ + { 1, 4, 2, 0, 16 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_P016BE] = { + .name = "p016be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 1, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 4, 0, 0, 16 }, /* U */ + { 1, 4, 2, 0, 16 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_GBRAP14LE] = { + .name = "gbrap14le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 14 }, /* R */ + { 0, 2, 0, 0, 14 }, /* G */ + { 1, 2, 0, 0, 14 }, /* B */ + { 3, 2, 0, 0, 14 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP14BE] = { + .name = "gbrap14be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 14 }, /* R */ + { 0, 2, 0, 0, 14 }, /* G */ + { 1, 2, 0, 0, 14 }, /* B */ + { 3, 2, 0, 0, 14 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP12LE] = { + .name = "gbrap12le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 12 }, /* R */ + { 0, 2, 0, 0, 12 }, /* G */ + { 1, 2, 0, 0, 12 }, /* B */ + { 3, 2, 0, 0, 12 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP12BE] = { + .name = "gbrap12be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 12 }, /* R */ + { 0, 2, 0, 0, 12 }, /* G */ + { 1, 2, 0, 0, 12 }, /* B */ + { 3, 2, 0, 0, 12 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP10LE] = { + .name = "gbrap10le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 10 }, /* R */ + { 0, 2, 0, 0, 10 }, /* G */ + { 1, 2, 0, 0, 10 }, /* B */ + { 3, 2, 0, 0, 10 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_GBRAP10BE] = { + .name = "gbrap10be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 10 }, /* R */ + { 0, 2, 0, 0, 10 }, /* G */ + { 1, 2, 0, 0, 10 }, /* B */ + { 3, 2, 0, 0, 10 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_D3D11] = { + .name = "d3d11", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_D3D12] = { + .name = "d3d12", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_GBRPF32BE] = { + .name = "gbrpf32be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32 }, /* R */ + { 0, 4, 0, 0, 32 }, /* G */ + { 1, 4, 0, 0, 32 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_GBRPF32LE] = { + .name = "gbrpf32le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32 }, /* R */ + { 0, 4, 0, 0, 32 }, /* G */ + { 1, 4, 0, 0, 32 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_FLOAT | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRAPF32BE] = { + .name = "gbrapf32be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32 }, /* R */ + { 0, 4, 0, 0, 32 }, /* G */ + { 1, 4, 0, 0, 32 }, /* B */ + { 3, 4, 0, 0, 32 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_ALPHA | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_GBRAPF32LE] = { + .name = "gbrapf32le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 4, 0, 0, 32 }, /* R */ + { 0, 4, 0, 0, 32 }, /* G */ + { 1, 4, 0, 0, 32 }, /* B */ + { 3, 4, 0, 0, 32 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_GBRPF16BE] = { + .name = "gbrpf16be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 16 }, /* R */ + { 0, 2, 0, 0, 16 }, /* G */ + { 1, 2, 0, 0, 16 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_GBRPF16LE] = { + .name = "gbrpf16le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 16 }, /* R */ + { 0, 2, 0, 0, 16 }, /* G */ + { 1, 2, 0, 0, 16 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_FLOAT | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_GBRAPF16BE] = { + .name = "gbrapf16be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 16 }, /* R */ + { 0, 2, 0, 0, 16 }, /* G */ + { 1, 2, 0, 0, 16 }, /* B */ + { 3, 2, 0, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | + AV_PIX_FMT_FLAG_ALPHA | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_GBRAPF16LE] = { + .name = "gbrapf16le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 2, 2, 0, 0, 16 }, /* R */ + { 0, 2, 0, 0, 16 }, /* G */ + { 1, 2, 0, 0, 16 }, /* B */ + { 3, 2, 0, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA | + AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_DRM_PRIME] = { + .name = "drm_prime", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_OPENCL] = { + .name = "opencl", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_GRAYF32BE] = { + .name = "grayf32be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 32 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_FLOAT, + .alias = "yf32be", + }, + [AV_PIX_FMT_GRAYF32LE] = { + .name = "grayf32le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 32 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_FLOAT, + .alias = "yf32le", + }, + [AV_PIX_FMT_GRAYF16BE] = { + .name = "grayf16be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_GRAYF16LE] = { + .name = "grayf16le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_YAF32BE] = { + .name = "yaf32be", + .nb_components = 2, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 0, 0, 32 }, /* Y */ + { 0, 8, 4, 0, 32 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_FLOAT | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YAF32LE] = { + .name = "yaf32le", + .nb_components = 2, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 0, 0, 32 }, /* Y */ + { 0, 8, 4, 0, 32 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_FLOAT | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YAF16BE] = { + .name = "yaf16be", + .nb_components = 2, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 16 }, /* Y */ + { 0, 4, 2, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_FLOAT | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YAF16LE] = { + .name = "yaf16le", + .nb_components = 2, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 16 }, /* Y */ + { 0, 4, 2, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_FLOAT | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P12BE] = { + .name = "yuva422p12be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + { 1, 2, 0, 0, 12 }, /* U */ + { 2, 2, 0, 0, 12 }, /* V */ + { 3, 2, 0, 0, 12 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P12LE] = { + .name = "yuva422p12le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + { 1, 2, 0, 0, 12 }, /* U */ + { 2, 2, 0, 0, 12 }, /* V */ + { 3, 2, 0, 0, 12 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P12BE] = { + .name = "yuva444p12be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + { 1, 2, 0, 0, 12 }, /* U */ + { 2, 2, 0, 0, 12 }, /* V */ + { 3, 2, 0, 0, 12 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P12LE] = { + .name = "yuva444p12le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12 }, /* Y */ + { 1, 2, 0, 0, 12 }, /* U */ + { 2, 2, 0, 0, 12 }, /* V */ + { 3, 2, 0, 0, 12 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_NV24] = { + .name = "nv24", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 2, 0, 0, 8 }, /* U */ + { 1, 2, 1, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_NV42] = { + .name = "nv42", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8 }, /* Y */ + { 1, 2, 1, 0, 8 }, /* U */ + { 1, 2, 0, 0, 8 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_VULKAN] = { + .name = "vulkan", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, + [AV_PIX_FMT_P210BE] = { + .name = "p210be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 6, 10 }, /* Y */ + { 1, 4, 0, 6, 10 }, /* U */ + { 1, 4, 2, 6, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_P210LE] = { + .name = "p210le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 6, 10 }, /* Y */ + { 1, 4, 0, 6, 10 }, /* U */ + { 1, 4, 2, 6, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_P410BE] = { + .name = "p410be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 6, 10 }, /* Y */ + { 1, 4, 0, 6, 10 }, /* U */ + { 1, 4, 2, 6, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_P410LE] = { + .name = "p410le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 6, 10 }, /* Y */ + { 1, 4, 0, 6, 10 }, /* U */ + { 1, 4, 2, 6, 10 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_P216BE] = { + .name = "p216be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 4, 0, 0, 16 }, /* U */ + { 1, 4, 2, 0, 16 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_P216LE] = { + .name = "p216le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 4, 0, 0, 16 }, /* U */ + { 1, 4, 2, 0, 16 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_P416BE] = { + .name = "p416be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 4, 0, 0, 16 }, /* U */ + { 1, 4, 2, 0, 16 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_P416LE] = { + .name = "p416le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 16 }, /* Y */ + { 1, 4, 0, 0, 16 }, /* U */ + { 1, 4, 2, 0, 16 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_VUYA] = { + .name = "vuya", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 2, 0, 8 }, /* Y */ + { 0, 4, 1, 0, 8 }, /* U */ + { 0, 4, 0, 0, 8 }, /* V */ + { 0, 4, 3, 0, 8 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_VUYX] = { + .name = "vuyx", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 2, 0, 8 }, /* Y */ + { 0, 4, 1, 0, 8 }, /* U */ + { 0, 4, 0, 0, 8 }, /* V */ + { 0, 4, 3, 0, 8 }, /* X */ + }, + }, + [AV_PIX_FMT_RGBF16BE] = { + .name = "rgbf16be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 0, 0, 16 }, /* R */ + { 0, 6, 2, 0, 16 }, /* G */ + { 0, 6, 4, 0, 16 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_RGBF16LE] = { + .name = "rgbf16le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 6, 0, 0, 16 }, /* R */ + { 0, 6, 2, 0, 16 }, /* G */ + { 0, 6, 4, 0, 16 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT + }, + [AV_PIX_FMT_RGBAF16BE] = { + .name = "rgbaf16be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 0, 0, 16 }, /* R */ + { 0, 8, 2, 0, 16 }, /* G */ + { 0, 8, 4, 0, 16 }, /* B */ + { 0, 8, 6, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_ALPHA | AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_RGBAF16LE] = { + .name = "rgbaf16le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 0, 0, 16 }, /* R */ + { 0, 8, 2, 0, 16 }, /* G */ + { 0, 8, 4, 0, 16 }, /* B */ + { 0, 8, 6, 0, 16 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA | + AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_Y212LE] = { + .name = "y212le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 4, 12 }, /* Y */ + { 0, 8, 2, 4, 12 }, /* U */ + { 0, 8, 6, 4, 12 }, /* V */ + }, + }, + [AV_PIX_FMT_Y212BE] = { + .name = "y212be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 4, 12 }, /* Y */ + { 0, 8, 2, 4, 12 }, /* U */ + { 0, 8, 6, 4, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_XV30LE] = { + .name = "xv30le", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 4, 1, 2, 10 }, /* Y */ + { 0, 4, 0, 0, 10 }, /* U */ + { 0, 4, 2, 4, 10 }, /* V */ + { 0, 4, 3, 6, 2 }, /* X */ + }, + }, + [AV_PIX_FMT_XV30BE] = { + .name = "xv30be", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 32, 10, 0, 10 }, /* Y */ + { 0, 32, 0, 0, 10 }, /* U */ + { 0, 32, 20, 0, 10 }, /* V */ + { 0, 32, 30, 0, 2 }, /* X */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_BITSTREAM, + }, + [AV_PIX_FMT_XV36LE] = { + .name = "xv36le", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 8, 2, 4, 12 }, /* Y */ + { 0, 8, 0, 4, 12 }, /* U */ + { 0, 8, 4, 4, 12 }, /* V */ + { 0, 8, 6, 4, 12 }, /* X */ + }, + }, + [AV_PIX_FMT_XV36BE] = { + .name = "xv36be", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 8, 2, 4, 12 }, /* Y */ + { 0, 8, 0, 4, 12 }, /* U */ + { 0, 8, 4, 4, 12 }, /* V */ + { 0, 8, 6, 4, 12 }, /* X */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_XV48LE] = { + .name = "xv48le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 2, 0, 16 }, /* Y */ + { 0, 8, 0, 0, 16 }, /* U */ + { 0, 8, 4, 0, 16 }, /* V */ + { 0, 8, 6, 0, 16 }, /* X */ + }, + }, + [AV_PIX_FMT_XV48BE] = { + .name = "xv48be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 8, 2, 0, 16 }, /* Y */ + { 0, 8, 0, 0, 16 }, /* U */ + { 0, 8, 4, 0, 16 }, /* V */ + { 0, 8, 6, 0, 16 }, /* X */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_V30XLE] = { + .name = "v30xle", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 1, 4, 10 }, /* Y */ + { 0, 4, 0, 2, 10 }, /* U */ + { 0, 4, 2, 6, 10 }, /* V */ + { 0, 4, 0, 0, 2 }, /* X */ + }, + }, + [AV_PIX_FMT_V30XBE] = { + .name = "v30xbe", + .nb_components= 3, + .log2_chroma_w= 0, + .log2_chroma_h= 0, + .comp = { + { 0, 32, 12, 0, 10 }, /* Y */ + { 0, 32, 2, 0, 10 }, /* U */ + { 0, 32, 22, 0, 10 }, /* V */ + { 0, 32, 0, 0, 2 }, /* X */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_BITSTREAM, + }, + [AV_PIX_FMT_RGBF32BE] = { + .name = "rgbf32be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 12, 0, 0, 32 }, /* R */ + { 0, 12, 4, 0, 32 }, /* G */ + { 0, 12, 8, 0, 32 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_RGBF32LE] = { + .name = "rgbf32le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 12, 0, 0, 32 }, /* R */ + { 0, 12, 4, 0, 32 }, /* G */ + { 0, 12, 8, 0, 32 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT, + }, + [AV_PIX_FMT_RGB96BE] = { + .name = "rgb96be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 12, 0, 0, 32 }, /* R */ + { 0, 12, 4, 0, 32 }, /* G */ + { 0, 12, 8, 0, 32 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGB96LE] = { + .name = "rgb96le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 12, 0, 0, 32 }, /* R */ + { 0, 12, 4, 0, 32 }, /* G */ + { 0, 12, 8, 0, 32 }, /* B */ + }, + .flags = AV_PIX_FMT_FLAG_RGB, + }, + [AV_PIX_FMT_RGBAF32BE] = { + .name = "rgbaf32be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 16, 0, 0, 32 }, /* R */ + { 0, 16, 4, 0, 32 }, /* G */ + { 0, 16, 8, 0, 32 }, /* B */ + { 0, 16, 12, 0, 32 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_FLOAT | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_RGBAF32LE] = { + .name = "rgbaf32le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 16, 0, 0, 32 }, /* R */ + { 0, 16, 4, 0, 32 }, /* G */ + { 0, 16, 8, 0, 32 }, /* B */ + { 0, 16, 12, 0, 32 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_FLOAT | + AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_RGBA128BE] = { + .name = "rgba128be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 16, 0, 0, 32 }, /* R */ + { 0, 16, 4, 0, 32 }, /* G */ + { 0, 16, 8, 0, 32 }, /* B */ + { 0, 16, 12, 0, 32 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_RGB | + AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_RGBA128LE] = { + .name = "rgba128le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 16, 0, 0, 32 }, /* R */ + { 0, 16, 4, 0, 32 }, /* G */ + { 0, 16, 8, 0, 32 }, /* B */ + { 0, 16, 12, 0, 32 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_P212BE] = { + .name = "p212be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 4, 12 }, /* Y */ + { 1, 4, 0, 4, 12 }, /* U */ + { 1, 4, 2, 4, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_P212LE] = { + .name = "p212le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 4, 12 }, /* Y */ + { 1, 4, 0, 4, 12 }, /* U */ + { 1, 4, 2, 4, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_P412BE] = { + .name = "p412be", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 4, 12 }, /* Y */ + { 1, 4, 0, 4, 12 }, /* U */ + { 1, 4, 2, 4, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_P412LE] = { + .name = "p412le", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 4, 12 }, /* Y */ + { 1, 4, 0, 4, 12 }, /* U */ + { 1, 4, 2, 4, 12 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_Y216LE] = { + .name = "y216le", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 16 }, /* Y */ + { 0, 8, 2, 0, 16 }, /* U */ + { 0, 8, 6, 0, 16 }, /* V */ + }, + }, + [AV_PIX_FMT_Y216BE] = { + .name = "y216be", + .nb_components = 3, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 16 }, /* Y */ + { 0, 8, 2, 0, 16 }, /* U */ + { 0, 8, 6, 0, 16 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + }, + [AV_PIX_FMT_OHCODEC] = { + .name = "ohcodec", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, +}; + +static const char * const color_range_names[] = { + [AVCOL_RANGE_UNSPECIFIED] = "unknown", + [AVCOL_RANGE_MPEG] = "tv", + [AVCOL_RANGE_JPEG] = "pc", +}; + +static const char * const color_primaries_names[AVCOL_PRI_NB] = { + [AVCOL_PRI_RESERVED0] = "reserved", + [AVCOL_PRI_BT709] = "bt709", + [AVCOL_PRI_UNSPECIFIED] = "unknown", + [AVCOL_PRI_RESERVED] = "reserved", + [AVCOL_PRI_BT470M] = "bt470m", + [AVCOL_PRI_BT470BG] = "bt470bg", + [AVCOL_PRI_SMPTE170M] = "smpte170m", + [AVCOL_PRI_SMPTE240M] = "smpte240m", + [AVCOL_PRI_FILM] = "film", + [AVCOL_PRI_BT2020] = "bt2020", + [AVCOL_PRI_SMPTE428] = "smpte428", + [AVCOL_PRI_SMPTE431] = "smpte431", + [AVCOL_PRI_SMPTE432] = "smpte432", + [AVCOL_PRI_EBU3213] = "ebu3213", +}; + +static const char * const color_primaries_names_ext[AVCOL_PRI_EXT_NB - + AVCOL_PRI_EXT_BASE] = { + [AVCOL_PRI_V_GAMUT - AVCOL_PRI_EXT_BASE] = "vgamut", +}; + +static const char * const color_transfer_names[] = { + [AVCOL_TRC_RESERVED0] = "reserved", + [AVCOL_TRC_BT709] = "bt709", + [AVCOL_TRC_UNSPECIFIED] = "unknown", + [AVCOL_TRC_RESERVED] = "reserved", + [AVCOL_TRC_GAMMA22] = "bt470m", + [AVCOL_TRC_GAMMA28] = "bt470bg", + [AVCOL_TRC_SMPTE170M] = "smpte170m", + [AVCOL_TRC_SMPTE240M] = "smpte240m", + [AVCOL_TRC_LINEAR] = "linear", + [AVCOL_TRC_LOG] = "log100", + [AVCOL_TRC_LOG_SQRT] = "log316", + [AVCOL_TRC_IEC61966_2_4] = "iec61966-2-4", + [AVCOL_TRC_BT1361_ECG] = "bt1361e", + [AVCOL_TRC_IEC61966_2_1] = "iec61966-2-1", + [AVCOL_TRC_BT2020_10] = "bt2020-10", + [AVCOL_TRC_BT2020_12] = "bt2020-12", + [AVCOL_TRC_SMPTE2084] = "smpte2084", + [AVCOL_TRC_SMPTE428] = "smpte428", + [AVCOL_TRC_ARIB_STD_B67] = "arib-std-b67", +}; + +static const char * const color_transfer_names_ext[] = { + [AVCOL_TRC_V_LOG - AVCOL_TRC_EXT_BASE] = "vlog", +}; + +static const char * const color_space_names[] = { + [AVCOL_SPC_RGB] = "gbr", + [AVCOL_SPC_BT709] = "bt709", + [AVCOL_SPC_UNSPECIFIED] = "unknown", + [AVCOL_SPC_RESERVED] = "reserved", + [AVCOL_SPC_FCC] = "fcc", + [AVCOL_SPC_BT470BG] = "bt470bg", + [AVCOL_SPC_SMPTE170M] = "smpte170m", + [AVCOL_SPC_SMPTE240M] = "smpte240m", + [AVCOL_SPC_YCGCO] = "ycgco", + [AVCOL_SPC_BT2020_NCL] = "bt2020nc", + [AVCOL_SPC_BT2020_CL] = "bt2020c", + [AVCOL_SPC_SMPTE2085] = "smpte2085", + [AVCOL_SPC_CHROMA_DERIVED_NCL] = "chroma-derived-nc", + [AVCOL_SPC_CHROMA_DERIVED_CL] = "chroma-derived-c", + [AVCOL_SPC_ICTCP] = "ictcp", + [AVCOL_SPC_IPT_C2] = "ipt-c2", + [AVCOL_SPC_YCGCO_RE] = "ycgco-re", + [AVCOL_SPC_YCGCO_RO] = "ycgco-ro", +}; + +static const char * const chroma_location_names[] = { + [AVCHROMA_LOC_UNSPECIFIED] = "unspecified", + [AVCHROMA_LOC_LEFT] = "left", + [AVCHROMA_LOC_CENTER] = "center", + [AVCHROMA_LOC_TOPLEFT] = "topleft", + [AVCHROMA_LOC_TOP] = "top", + [AVCHROMA_LOC_BOTTOMLEFT] = "bottomleft", + [AVCHROMA_LOC_BOTTOM] = "bottom", +}; + +static const char * const alpha_mode_names[] = { + [AVALPHA_MODE_UNSPECIFIED] = "unspecified", + [AVALPHA_MODE_PREMULTIPLIED] = "premultiplied", + [AVALPHA_MODE_STRAIGHT] = "straight", +}; + +static enum AVPixelFormat get_pix_fmt_internal(const char *name) +{ + enum AVPixelFormat pix_fmt; + + for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++) + if (av_pix_fmt_descriptors[pix_fmt].name && + (!strcmp(av_pix_fmt_descriptors[pix_fmt].name, name) || + av_match_name(name, av_pix_fmt_descriptors[pix_fmt].alias))) + return pix_fmt; + + return AV_PIX_FMT_NONE; +} + +const char *av_get_pix_fmt_name(enum AVPixelFormat pix_fmt) +{ + return (unsigned)pix_fmt < AV_PIX_FMT_NB ? + av_pix_fmt_descriptors[pix_fmt].name : NULL; +} + +#if HAVE_BIGENDIAN +# define X_NE(be, le) be +#else +# define X_NE(be, le) le +#endif + +enum AVPixelFormat av_get_pix_fmt(const char *name) +{ + enum AVPixelFormat pix_fmt; + + if (!strcmp(name, "rgb32")) + name = X_NE("argb", "bgra"); + else if (!strcmp(name, "bgr32")) + name = X_NE("abgr", "rgba"); + + pix_fmt = get_pix_fmt_internal(name); + if (pix_fmt == AV_PIX_FMT_NONE) { + char name2[32]; + + snprintf(name2, sizeof(name2), "%s%s", name, X_NE("be", "le")); + pix_fmt = get_pix_fmt_internal(name2); + } + + return pix_fmt; +} + +int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc) +{ + int c, bits = 0; + int log2_pixels = pixdesc->log2_chroma_w + pixdesc->log2_chroma_h; + + for (c = 0; c < pixdesc->nb_components; c++) { + int s = c == 1 || c == 2 ? 0 : log2_pixels; + bits += pixdesc->comp[c].depth << s; + } + + return bits >> log2_pixels; +} + +int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc) +{ + int c, bits = 0; + int log2_pixels = pixdesc->log2_chroma_w + pixdesc->log2_chroma_h; + int steps[4] = {0}; + + for (c = 0; c < pixdesc->nb_components; c++) { + const AVComponentDescriptor *comp = &pixdesc->comp[c]; + int s = c == 1 || c == 2 ? 0 : log2_pixels; + steps[comp->plane] = comp->step << s; + } + for (c = 0; c < 4; c++) + bits += steps[c]; + + if(!(pixdesc->flags & AV_PIX_FMT_FLAG_BITSTREAM)) + bits *= 8; + + return bits >> log2_pixels; +} + +char *av_get_pix_fmt_string(char *buf, int buf_size, + enum AVPixelFormat pix_fmt) +{ + /* print header */ + if (pix_fmt < 0) { + snprintf (buf, buf_size, "name" " nb_components" " nb_bits"); + } else { + const AVPixFmtDescriptor *pixdesc = &av_pix_fmt_descriptors[pix_fmt]; + snprintf(buf, buf_size, "%-11s %7d %10d", pixdesc->name, + pixdesc->nb_components, av_get_bits_per_pixel(pixdesc)); + } + + return buf; +} + +const AVPixFmtDescriptor *av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt) +{ + if (pix_fmt < 0 || pix_fmt >= AV_PIX_FMT_NB) + return NULL; + return &av_pix_fmt_descriptors[pix_fmt]; +} + +const AVPixFmtDescriptor *av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev) +{ + if (!prev) + return &av_pix_fmt_descriptors[0]; + while (prev - av_pix_fmt_descriptors < FF_ARRAY_ELEMS(av_pix_fmt_descriptors) - 1) { + prev++; + if (prev->name) + return prev; + } + return NULL; +} + +enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc) +{ + if (desc < av_pix_fmt_descriptors || + desc >= av_pix_fmt_descriptors + FF_ARRAY_ELEMS(av_pix_fmt_descriptors)) + return AV_PIX_FMT_NONE; + + return desc - av_pix_fmt_descriptors; +} + +int av_pix_fmt_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, + int *h_shift, int *v_shift) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + if (!desc) + return AVERROR(ENOSYS); + *h_shift = desc->log2_chroma_w; + *v_shift = desc->log2_chroma_h; + + return 0; +} + +int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int i, planes[4] = { 0 }, ret = 0; + + if (!desc) + return AVERROR(EINVAL); + + for (i = 0; i < desc->nb_components; i++) + planes[desc->comp[i].plane] = 1; + for (i = 0; i < FF_ARRAY_ELEMS(planes); i++) + ret += planes[i]; + return ret; +} + +enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + char name[16]; + int i; + + if (!desc || strlen(desc->name) < 2) + return AV_PIX_FMT_NONE; + av_strlcpy(name, desc->name, sizeof(name)); + i = strlen(name) - 2; + if (strcmp(name + i, "be") && strcmp(name + i, "le")) + return AV_PIX_FMT_NONE; + + name[i] ^= 'b' ^ 'l'; + + return get_pix_fmt_internal(name); +} + +#define FF_COLOR_NA -1 +#define FF_COLOR_RGB 0 /**< RGB color space */ +#define FF_COLOR_GRAY 1 /**< gray color space */ +#define FF_COLOR_YUV 2 /**< YUV color space. 16 <= Y <= 235, 16 <= U, V <= 240 */ +#define FF_COLOR_YUV_JPEG 3 /**< YUV color space. 0 <= Y <= 255, 0 <= U, V <= 255 */ +#define FF_COLOR_XYZ 4 + +#define pixdesc_has_alpha(pixdesc) \ + ((pixdesc)->flags & AV_PIX_FMT_FLAG_ALPHA) + + +static int get_color_type(const AVPixFmtDescriptor *desc) { + if (desc->flags & AV_PIX_FMT_FLAG_PAL) + return FF_COLOR_RGB; + + if(desc->nb_components == 1 || desc->nb_components == 2) + return FF_COLOR_GRAY; + + if (desc->name) { + if (av_strstart(desc->name, "yuvj", NULL)) + return FF_COLOR_YUV_JPEG; + } + + if(desc->flags & AV_PIX_FMT_FLAG_RGB) + return FF_COLOR_RGB; + + if(desc->flags & AV_PIX_FMT_FLAG_XYZ) + return FF_COLOR_XYZ; + + if(desc->nb_components == 0) + return FF_COLOR_NA; + + return FF_COLOR_YUV; +} + +static int get_pix_fmt_depth(int *min, int *max, enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int i; + + if (!desc || !desc->nb_components) { + *min = *max = 0; + return AVERROR(EINVAL); + } + + *min = INT_MAX, *max = -INT_MAX; + for (i = 0; i < desc->nb_components; i++) { + *min = FFMIN(desc->comp[i].depth, *min); + *max = FFMAX(desc->comp[i].depth, *max); + } + return 0; +} + +static int get_pix_fmt_score(enum AVPixelFormat dst_pix_fmt, + enum AVPixelFormat src_pix_fmt, + unsigned *lossp, unsigned consider) +{ + const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(src_pix_fmt); + const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(dst_pix_fmt); + int src_color, dst_color; + int src_min_depth, src_max_depth, dst_min_depth, dst_max_depth; + int ret, loss, i, nb_components; + int score = INT_MAX - 1; + + if (!src_desc || !dst_desc) + return -4; + + if ((src_desc->flags & AV_PIX_FMT_FLAG_HWACCEL) || + (dst_desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) { + if (dst_pix_fmt == src_pix_fmt) + return -1; + else + return -2; + } + + /* compute loss */ + *lossp = loss = 0; + + if (dst_pix_fmt == src_pix_fmt) + return INT_MAX; + + if ((ret = get_pix_fmt_depth(&src_min_depth, &src_max_depth, src_pix_fmt)) < 0) + return -3; + if ((ret = get_pix_fmt_depth(&dst_min_depth, &dst_max_depth, dst_pix_fmt)) < 0) + return -3; + + src_color = get_color_type(src_desc); + dst_color = get_color_type(dst_desc); + if (dst_pix_fmt == AV_PIX_FMT_PAL8) + nb_components = FFMIN(src_desc->nb_components, 4); + else + nb_components = FFMIN(src_desc->nb_components, dst_desc->nb_components); + + for (i = 0; i < nb_components; i++) { + int depth_minus1 = (dst_pix_fmt == AV_PIX_FMT_PAL8) ? 7/nb_components : (dst_desc->comp[i].depth - 1); + int depth_delta = src_desc->comp[i].depth - 1 - depth_minus1; + if (depth_delta > 0 && (consider & FF_LOSS_DEPTH)) { + loss |= FF_LOSS_DEPTH; + score -= 65536 >> depth_minus1; + } else if (depth_delta < 0 && (consider & FF_LOSS_EXCESS_DEPTH)) { + // Favour formats where bit depth exactly matches. If all other + // scoring is equal, we'd rather use the bit depth that most closely + // matches the source. + loss |= FF_LOSS_EXCESS_DEPTH; + score += depth_delta; + } + } + + if (consider & FF_LOSS_RESOLUTION) { + if (dst_desc->log2_chroma_w > src_desc->log2_chroma_w) { + loss |= FF_LOSS_RESOLUTION; + score -= 256 << dst_desc->log2_chroma_w; + } + if (dst_desc->log2_chroma_h > src_desc->log2_chroma_h) { + loss |= FF_LOSS_RESOLUTION; + score -= 256 << dst_desc->log2_chroma_h; + } + // don't favor 422 over 420 if downsampling is needed, because 420 has much better support on the decoder side + if (dst_desc->log2_chroma_w == 1 && src_desc->log2_chroma_w == 0 && + dst_desc->log2_chroma_h == 1 && src_desc->log2_chroma_h == 0 ) { + score += 512; + } + } + + if (consider & FF_LOSS_EXCESS_RESOLUTION) { + // Favour formats where chroma subsampling exactly matches. If all other + // scoring is equal, we'd rather use the subsampling that most closely + // matches the source. + if (dst_desc->log2_chroma_w < src_desc->log2_chroma_w) { + loss |= FF_LOSS_EXCESS_RESOLUTION; + score -= 1 << (src_desc->log2_chroma_w - dst_desc->log2_chroma_w); + } + + if (dst_desc->log2_chroma_h < src_desc->log2_chroma_h) { + loss |= FF_LOSS_EXCESS_RESOLUTION; + score -= 1 << (src_desc->log2_chroma_h - dst_desc->log2_chroma_h); + } + + // don't favour 411 over 420, because 420 has much better support on the + // decoder side. + if (dst_desc->log2_chroma_w == 1 && src_desc->log2_chroma_w == 2 && + dst_desc->log2_chroma_h == 1 && src_desc->log2_chroma_h == 2) { + score += 4; + } + } + + if(consider & FF_LOSS_COLORSPACE) + switch(dst_color) { + case FF_COLOR_RGB: + if (src_color != FF_COLOR_RGB && + src_color != FF_COLOR_GRAY) + loss |= FF_LOSS_COLORSPACE; + break; + case FF_COLOR_GRAY: + if (src_color != FF_COLOR_GRAY) + loss |= FF_LOSS_COLORSPACE; + break; + case FF_COLOR_YUV: + if (src_color != FF_COLOR_YUV) + loss |= FF_LOSS_COLORSPACE; + break; + case FF_COLOR_YUV_JPEG: + if (src_color != FF_COLOR_YUV_JPEG && + src_color != FF_COLOR_YUV && + src_color != FF_COLOR_GRAY) + loss |= FF_LOSS_COLORSPACE; + break; + default: + /* fail safe test */ + if (src_color != dst_color) + loss |= FF_LOSS_COLORSPACE; + break; + } + if(loss & FF_LOSS_COLORSPACE) + score -= (nb_components * 65536) >> FFMIN(dst_desc->comp[0].depth - 1, src_desc->comp[0].depth - 1); + + if (dst_color == FF_COLOR_GRAY && + src_color != FF_COLOR_GRAY && (consider & FF_LOSS_CHROMA)) { + loss |= FF_LOSS_CHROMA; + score -= 2 * 65536; + } + if (!pixdesc_has_alpha(dst_desc) && (pixdesc_has_alpha(src_desc) && (consider & FF_LOSS_ALPHA))) { + loss |= FF_LOSS_ALPHA; + score -= 65536; + } + if (dst_pix_fmt == AV_PIX_FMT_PAL8 && (consider & FF_LOSS_COLORQUANT) && + (src_pix_fmt != AV_PIX_FMT_PAL8 && (src_color != FF_COLOR_GRAY || (pixdesc_has_alpha(src_desc) && (consider & FF_LOSS_ALPHA))))) { + loss |= FF_LOSS_COLORQUANT; + score -= 65536; + } + + *lossp = loss; + return score; +} + +int av_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, + enum AVPixelFormat src_pix_fmt, + int has_alpha) +{ + int loss; + int ret = get_pix_fmt_score(dst_pix_fmt, src_pix_fmt, &loss, has_alpha ? ~0 : ~FF_LOSS_ALPHA); + if (ret < 0) + return ret; + return loss; +} + +enum AVPixelFormat av_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr) +{ + enum AVPixelFormat dst_pix_fmt; + int loss1, loss2, loss_mask; + const AVPixFmtDescriptor *desc1 = av_pix_fmt_desc_get(dst_pix_fmt1); + const AVPixFmtDescriptor *desc2 = av_pix_fmt_desc_get(dst_pix_fmt2); + int score1, score2; + + if (!desc1) { + dst_pix_fmt = dst_pix_fmt2; + } else if (!desc2) { + dst_pix_fmt = dst_pix_fmt1; + } else { + loss_mask= loss_ptr?~*loss_ptr:~0; /* use loss mask if provided */ + if(!has_alpha) + loss_mask &= ~FF_LOSS_ALPHA; + + score1 = get_pix_fmt_score(dst_pix_fmt1, src_pix_fmt, &loss1, loss_mask); + score2 = get_pix_fmt_score(dst_pix_fmt2, src_pix_fmt, &loss2, loss_mask); + + if (score1 == score2) { + if(av_get_padded_bits_per_pixel(desc2) != av_get_padded_bits_per_pixel(desc1)) { + dst_pix_fmt = av_get_padded_bits_per_pixel(desc2) < av_get_padded_bits_per_pixel(desc1) ? dst_pix_fmt2 : dst_pix_fmt1; + } else { + dst_pix_fmt = desc2->nb_components < desc1->nb_components ? dst_pix_fmt2 : dst_pix_fmt1; + } + } else { + dst_pix_fmt = score1 < score2 ? dst_pix_fmt2 : dst_pix_fmt1; + } + } + + if (loss_ptr) + *loss_ptr = av_get_pix_fmt_loss(dst_pix_fmt, src_pix_fmt, has_alpha); + return dst_pix_fmt; +} + +const char *av_color_range_name(enum AVColorRange range) +{ + return (unsigned) range < AVCOL_RANGE_NB ? + color_range_names[range] : NULL; +} + +int av_color_range_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(color_range_names); i++) { + if (av_strstart(name, color_range_names[i], NULL)) + return i; + } + + return AVERROR(EINVAL); +} + +const char *av_color_primaries_name(enum AVColorPrimaries primaries) +{ + if ((unsigned)primaries < AVCOL_PRI_NB) + return color_primaries_names[primaries]; + else if (((unsigned)primaries >= AVCOL_PRI_EXT_BASE) && + ((unsigned)primaries < AVCOL_PRI_EXT_NB)) + return color_primaries_names_ext[primaries - AVCOL_TRC_EXT_BASE]; + return NULL; +} + +int av_color_primaries_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(color_primaries_names); i++) { + if (!color_primaries_names[i]) + continue; + + if (av_strstart(name, color_primaries_names[i], NULL)) + return i; + } + + for (i = 0; i < FF_ARRAY_ELEMS(color_primaries_names_ext); i++) { + if (!color_primaries_names_ext[i]) + continue; + + if (av_strstart(name, color_primaries_names_ext[i], NULL)) + return AVCOL_PRI_EXT_BASE + i; + } + + return AVERROR(EINVAL); +} + +const char *av_color_transfer_name(enum AVColorTransferCharacteristic transfer) +{ + if ((unsigned)transfer < AVCOL_TRC_NB) + return color_transfer_names[transfer]; + else if (((unsigned)transfer >= AVCOL_TRC_EXT_BASE) && + ((unsigned)transfer < AVCOL_TRC_EXT_NB)) + return color_transfer_names_ext[transfer - AVCOL_TRC_EXT_BASE]; + return NULL; +} + +int av_color_transfer_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(color_transfer_names); i++) { + if (!color_transfer_names[i]) + continue; + + if (av_strstart(name, color_transfer_names[i], NULL)) + return i; + } + + for (i = 0; i < FF_ARRAY_ELEMS(color_transfer_names_ext); i++) { + if (!color_transfer_names_ext[i]) + continue; + + if (av_strstart(name, color_transfer_names_ext[i], NULL)) + return AVCOL_TRC_EXT_BASE + i; + } + + return AVERROR(EINVAL); +} + +const char *av_color_space_name(enum AVColorSpace space) +{ + return (unsigned) space < AVCOL_SPC_NB ? + color_space_names[space] : NULL; +} + +int av_color_space_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(color_space_names); i++) { + if (!color_space_names[i]) + continue; + + if (av_strstart(name, color_space_names[i], NULL)) + return i; + } + + return AVERROR(EINVAL); +} + +const char *av_chroma_location_name(enum AVChromaLocation location) +{ + return (unsigned) location < AVCHROMA_LOC_NB ? + chroma_location_names[location] : NULL; +} + +int av_chroma_location_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(chroma_location_names); i++) { + if (!chroma_location_names[i]) + continue; + + if (av_strstart(name, chroma_location_names[i], NULL)) + return i; + } + + return AVERROR(EINVAL); +} + +int av_chroma_location_enum_to_pos(int *xpos, int *ypos, enum AVChromaLocation pos) +{ + if (pos <= AVCHROMA_LOC_UNSPECIFIED || pos >= AVCHROMA_LOC_NB) + return AVERROR(EINVAL); + pos--; + + *xpos = (pos&1) * 128; + *ypos = ((pos>>1)^(pos<4)) * 128; + + return 0; +} + +enum AVChromaLocation av_chroma_location_pos_to_enum(int xpos, int ypos) +{ + int pos, xout, yout; + + for (pos = AVCHROMA_LOC_UNSPECIFIED + 1; pos < AVCHROMA_LOC_NB; pos++) { + if (av_chroma_location_enum_to_pos(&xout, &yout, pos) == 0 && xout == xpos && yout == ypos) + return pos; + } + return AVCHROMA_LOC_UNSPECIFIED; +} + +const char *av_alpha_mode_name(enum AVAlphaMode mode) +{ + return (unsigned) mode < AVALPHA_MODE_NB ? + alpha_mode_names[mode] : NULL; +} + +enum AVAlphaMode av_alpha_mode_from_name(const char *name) +{ + for (int i = 0; i < FF_ARRAY_ELEMS(alpha_mode_names); i++) { + if (!alpha_mode_names[i]) + continue; + + if (av_strstart(name, alpha_mode_names[i], NULL)) + return i; + } + + return AVERROR(EINVAL); +} diff --git a/libs/ffmpeg/libavutil/pixdesc.h b/libs/ffmpeg/libavutil/pixdesc.h new file mode 100644 index 00000000000..0cc70eb64c6 --- /dev/null +++ b/libs/ffmpeg/libavutil/pixdesc.h @@ -0,0 +1,450 @@ +/* + * pixel format descriptor + * Copyright (c) 2009 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXDESC_H +#define AVUTIL_PIXDESC_H + +#include <inttypes.h> + +#include "attributes.h" +#include "pixfmt.h" + +typedef struct AVComponentDescriptor { + /** + * Which of the 4 planes contains the component. + */ + int plane; + + /** + * Number of elements between 2 horizontally consecutive pixels. + * Elements are bits for bitstream formats, bytes otherwise. + */ + int step; + + /** + * Number of elements before the component of the first pixel. + * Elements are bits for bitstream formats, bytes otherwise. + */ + int offset; + + /** + * Number of least significant bits that must be shifted away + * to get the value. + */ + int shift; + + /** + * Number of bits in the component. + */ + int depth; +} AVComponentDescriptor; + +/** + * Descriptor that unambiguously describes how the bits of a pixel are + * stored in the up to 4 data planes of an image. It also stores the + * subsampling factors and number of components. + * + * @note This is separate of the colorspace (RGB, YCbCr, YPbPr, JPEG-style YUV + * and all the YUV variants) AVPixFmtDescriptor just stores how values + * are stored not what these values represent. + */ +typedef struct AVPixFmtDescriptor { + const char *name; + uint8_t nb_components; ///< The number of components each pixel has, (1-4) + + /** + * Amount to shift the luma width right to find the chroma width. + * For YV12 this is 1 for example. + * chroma_width = AV_CEIL_RSHIFT(luma_width, log2_chroma_w) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_w; + + /** + * Amount to shift the luma height right to find the chroma height. + * For YV12 this is 1 for example. + * chroma_height= AV_CEIL_RSHIFT(luma_height, log2_chroma_h) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_h; + + /** + * Combination of AV_PIX_FMT_FLAG_... flags. + */ + uint64_t flags; + + /** + * Parameters that describe how pixels are packed. + * If the format has 1 or 2 components, then luma is 0. + * If the format has 3 or 4 components: + * if the RGB flag is set then 0 is red, 1 is green and 2 is blue; + * otherwise 0 is luma, 1 is chroma-U and 2 is chroma-V. + * + * If present, the Alpha channel is always the last component. + */ + AVComponentDescriptor comp[4]; + + /** + * Alternative comma-separated names. + */ + const char *alias; +} AVPixFmtDescriptor; + +/** + * Pixel format is big-endian. + */ +#define AV_PIX_FMT_FLAG_BE (1 << 0) +/** + * Pixel format has a palette in data[1], values are indexes in this palette. + */ +#define AV_PIX_FMT_FLAG_PAL (1 << 1) +/** + * All values of a component are bit-wise packed end to end. + */ +#define AV_PIX_FMT_FLAG_BITSTREAM (1 << 2) +/** + * Pixel format is an HW accelerated format. + */ +#define AV_PIX_FMT_FLAG_HWACCEL (1 << 3) +/** + * At least one pixel component is not in the first data plane. + */ +#define AV_PIX_FMT_FLAG_PLANAR (1 << 4) +/** + * The pixel format contains RGB-like data (as opposed to YUV/grayscale). + */ +#define AV_PIX_FMT_FLAG_RGB (1 << 5) + +/** + * The pixel format has an alpha channel. This is set on all formats that + * support alpha in some way, including AV_PIX_FMT_PAL8. The alpha is always + * straight, never pre-multiplied. + * + * If a codec or a filter does not support alpha, it should set all alpha to + * opaque, or use the equivalent pixel formats without alpha component, e.g. + * AV_PIX_FMT_RGB0 (or AV_PIX_FMT_RGB24 etc.) instead of AV_PIX_FMT_RGBA. + */ +#define AV_PIX_FMT_FLAG_ALPHA (1 << 7) + +/** + * The pixel format is following a Bayer pattern + */ +#define AV_PIX_FMT_FLAG_BAYER (1 << 8) + +/** + * The pixel format contains IEEE-754 floating point values. Precision (double, + * single, or half) should be determined by the pixel size (64, 32, or 16 bits). + */ +#define AV_PIX_FMT_FLAG_FLOAT (1 << 9) + +/** + * The pixel format contains XYZ-like data (as opposed to YUV/RGB/grayscale). + */ +#define AV_PIX_FMT_FLAG_XYZ (1 << 10) + +/** + * Return the number of bits per pixel used by the pixel format + * described by pixdesc. Note that this is not the same as the number + * of bits per sample. + * + * The returned number of bits refers to the number of bits actually + * used for storing the pixel information, that is padding bits are + * not counted. + */ +int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * Return the number of bits per pixel for the pixel format + * described by pixdesc, including any padding or unused bits. + */ +int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * @return a pixel format descriptor for provided pixel format or NULL if + * this pixel format is unknown. + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt); + +/** + * Iterate over all pixel format descriptors known to libavutil. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev); + +/** + * @return an AVPixelFormat id described by desc, or AV_PIX_FMT_NONE if desc + * is not a valid pointer to a pixel format descriptor. + */ +enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc); + +/** + * Utility function to access log2_chroma_w log2_chroma_h from + * the pixel format AVPixFmtDescriptor. + * + * @param[in] pix_fmt the pixel format + * @param[out] h_shift store log2_chroma_w (horizontal/width shift) + * @param[out] v_shift store log2_chroma_h (vertical/height shift) + * + * @return 0 on success, AVERROR(ENOSYS) on invalid or unknown pixel format + */ +int av_pix_fmt_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, + int *h_shift, int *v_shift); + +/** + * @return number of planes in pix_fmt, a negative AVERROR if pix_fmt is not a + * valid pixel format. + */ +int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt); + +/** + * @return the name for provided color range or NULL if unknown. + */ +const char *av_color_range_name(enum AVColorRange range); + +/** + * @return the AVColorRange value for name or an AVError if not found. + */ +int av_color_range_from_name(const char *name); + +/** + * @return the name for provided color primaries or NULL if unknown. + */ +const char *av_color_primaries_name(enum AVColorPrimaries primaries); + +/** + * @return the AVColorPrimaries value for name or an AVError if not found. + */ +int av_color_primaries_from_name(const char *name); + +/** + * @return the name for provided color transfer or NULL if unknown. + */ +const char *av_color_transfer_name(enum AVColorTransferCharacteristic transfer); + +/** + * @return the AVColorTransferCharacteristic value for name or an AVError if not found. + */ +int av_color_transfer_from_name(const char *name); + +/** + * @return the name for provided color space or NULL if unknown. + */ +const char *av_color_space_name(enum AVColorSpace space); + +/** + * @return the AVColorSpace value for name or an AVError if not found. + */ +int av_color_space_from_name(const char *name); + +/** + * @return the name for provided chroma location or NULL if unknown. + */ +const char *av_chroma_location_name(enum AVChromaLocation location); + +/** + * @return the AVChromaLocation value for name or an AVError if not found. + */ +int av_chroma_location_from_name(const char *name); + +/** + * Converts AVChromaLocation to swscale x/y chroma position. + * + * The positions represent the chroma (0,0) position in a coordinates system + * with luma (0,0) representing the origin and luma(1,1) representing 256,256 + * + * @param xpos horizontal chroma sample position + * @param ypos vertical chroma sample position + */ +int av_chroma_location_enum_to_pos(int *xpos, int *ypos, enum AVChromaLocation pos); + +/** + * Converts swscale x/y chroma position to AVChromaLocation. + * + * The positions represent the chroma (0,0) position in a coordinates system + * with luma (0,0) representing the origin and luma(1,1) representing 256,256 + * + * @param xpos horizontal chroma sample position + * @param ypos vertical chroma sample position + */ +enum AVChromaLocation av_chroma_location_pos_to_enum(int xpos, int ypos); + +/** + * @return the name for provided alpha mode or NULL if unknown. + */ +const char *av_alpha_mode_name(enum AVAlphaMode mode); + +/** + * @return the AVAlphaMode value for name or an AVError if not found. + */ +enum AVAlphaMode av_alpha_mode_from_name(const char *name); + +/** + * Return the pixel format corresponding to name. + * + * If there is no pixel format with name name, then looks for a + * pixel format with the name corresponding to the native endian + * format of name. + * For example in a little-endian system, first looks for "gray16", + * then for "gray16le". + * + * Finally if no pixel format has been found, returns AV_PIX_FMT_NONE. + */ +enum AVPixelFormat av_get_pix_fmt(const char *name); + +/** + * Return the short name for a pixel format, NULL in case pix_fmt is + * unknown. + * + * @see av_get_pix_fmt(), av_get_pix_fmt_string() + */ +const char *av_get_pix_fmt_name(enum AVPixelFormat pix_fmt); + +/** + * Print in buf the string corresponding to the pixel format with + * number pix_fmt, or a header if pix_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param pix_fmt the number of the pixel format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + */ +char *av_get_pix_fmt_string(char *buf, int buf_size, + enum AVPixelFormat pix_fmt); + +/** + * Read a line from an image, and write the values of the + * pixel format component c to dst. + * + * @param data the array containing the pointers to the planes of the image + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to read + * @param y the vertical coordinate of the first pixel to read + * @param w the width of the line to read, that is the number of + * values to write to dst + * @param read_pal_component if not zero and the format is a paletted + * format writes the values corresponding to the palette + * component c in data[1] to dst, rather than the palette indexes in + * data[0]. The behavior is undefined if the format is not paletted. + * @param dst_element_size size of elements in dst array (2 or 4 byte) + */ +void av_read_image_line2(void *dst, const uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int read_pal_component, + int dst_element_size); + +void av_read_image_line(uint16_t *dst, const uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int read_pal_component); + +/** + * Write the values from src to the pixel format component c of an + * image line. + * + * @param src array containing the values to write + * @param data the array containing the pointers to the planes of the + * image to write into. It is supposed to be zeroed. + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to write + * @param y the vertical coordinate of the first pixel to write + * @param w the width of the line to write, that is the number of + * values to write to the image line + * @param src_element_size size of elements in src array (2 or 4 byte) + */ +void av_write_image_line2(const void *src, uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int src_element_size); + +void av_write_image_line(const uint16_t *src, uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w); + +/** + * Utility function to swap the endianness of a pixel format. + * + * @param[in] pix_fmt the pixel format + * + * @return pixel format with swapped endianness if it exists, + * otherwise AV_PIX_FMT_NONE + */ +enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt); + +#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */ +#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */ +#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */ +#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */ +#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */ +#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */ +#define FF_LOSS_EXCESS_RESOLUTION 0x0040 /**< loss due to unneeded extra resolution */ +#define FF_LOSS_EXCESS_DEPTH 0x0080 /**< loss due to unneeded extra color depth */ + + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +int av_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, + enum AVPixelFormat src_pix_fmt, + int has_alpha); + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +enum AVPixelFormat av_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); + +#endif /* AVUTIL_PIXDESC_H */ diff --git a/libs/ffmpeg/libavutil/pixelutils.c b/libs/ffmpeg/libavutil/pixelutils.c new file mode 100644 index 00000000000..8e91f0a2cca --- /dev/null +++ b/libs/ffmpeg/libavutil/pixelutils.c @@ -0,0 +1,95 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stddef.h> + +#include "config.h" +#include "pixelutils.h" + +#if CONFIG_PIXELUTILS +#include <stdlib.h> +#include <string.h> + +#include "attributes.h" +#include "macros.h" + +#include "x86/pixelutils.h" + +static av_always_inline int sad_wxh(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2, + int w, int h) +{ + int x, y, sum = 0; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) + sum += abs(src1[x] - src2[x]); + src1 += stride1; + src2 += stride2; + } + return sum; +} + +#define DECLARE_BLOCK_FUNCTIONS(size) \ +static int block_sad_##size##x##size##_c(const uint8_t *src1, ptrdiff_t stride1, \ + const uint8_t *src2, ptrdiff_t stride2) \ +{ \ + return sad_wxh(src1, stride1, src2, stride2, size, size); \ +} + +DECLARE_BLOCK_FUNCTIONS(2) +DECLARE_BLOCK_FUNCTIONS(4) +DECLARE_BLOCK_FUNCTIONS(8) +DECLARE_BLOCK_FUNCTIONS(16) +DECLARE_BLOCK_FUNCTIONS(32) + +static const av_pixelutils_sad_fn sad_c[] = { + block_sad_2x2_c, + block_sad_4x4_c, + block_sad_8x8_c, + block_sad_16x16_c, + block_sad_32x32_c, +}; +#else +#include "log.h" +#endif /* CONFIG_PIXELUTILS */ + +av_pixelutils_sad_fn av_pixelutils_get_sad_fn(int w_bits, int h_bits, int aligned, void *log_ctx) +{ +#if !CONFIG_PIXELUTILS + av_log(log_ctx, AV_LOG_ERROR, "pixelutils support is required " + "but libavutil is not compiled with it\n"); + return NULL; +#else + av_pixelutils_sad_fn sad[FF_ARRAY_ELEMS(sad_c)]; + + memcpy(sad, sad_c, sizeof(sad)); + + if (w_bits < 1 || w_bits > FF_ARRAY_ELEMS(sad) || + h_bits < 1 || h_bits > FF_ARRAY_ELEMS(sad)) + return NULL; + if (w_bits != h_bits) // only squared sad for now + return NULL; + +#if ARCH_X86 && HAVE_X86ASM + ff_pixelutils_sad_init_x86(sad, aligned); +#endif + + return sad[w_bits - 1]; +#endif +} diff --git a/libs/ffmpeg/libavutil/pixelutils.h b/libs/ffmpeg/libavutil/pixelutils.h new file mode 100644 index 00000000000..7a997cde1c8 --- /dev/null +++ b/libs/ffmpeg/libavutil/pixelutils.h @@ -0,0 +1,51 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXELUTILS_H +#define AVUTIL_PIXELUTILS_H + +#include <stddef.h> +#include <stdint.h> + +/** + * Sum of abs(src1[x] - src2[x]) + */ +typedef int (*av_pixelutils_sad_fn)(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); + +/** + * Get a potentially optimized pointer to a Sum-of-absolute-differences + * function (see the av_pixelutils_sad_fn prototype). + * + * @param w_bits 1<<w_bits is the requested width of the block size + * @param h_bits 1<<h_bits is the requested height of the block size + * @param aligned If set to 2, the returned sad function will assume src1 and + * src2 addresses are aligned on the block size. + * If set to 1, the returned sad function will assume src1 is + * aligned on the block size. + * If set to 0, the returned sad function assume no particular + * alignment. + * @param log_ctx context used for logging, can be NULL + * + * @return a pointer to the SAD function or NULL in case of error (because of + * invalid parameters) + */ +av_pixelutils_sad_fn av_pixelutils_get_sad_fn(int w_bits, int h_bits, + int aligned, void *log_ctx); + +#endif /* AVUTIL_PIXELUTILS_H */ diff --git a/libs/ffmpeg/libavutil/pixfmt.h b/libs/ffmpeg/libavutil/pixfmt.h new file mode 100644 index 00000000000..2e7b6457e02 --- /dev/null +++ b/libs/ffmpeg/libavutil/pixfmt.h @@ -0,0 +1,817 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXFMT_H +#define AVUTIL_PIXFMT_H + +/** + * @file + * pixel format definitions + */ + +#include "libavutil/avconfig.h" +#include "version.h" + +#define AVPALETTE_SIZE 1024 +#define AVPALETTE_COUNT 256 + +/** + * Maximum number of planes in any pixel format. + * This should be used when a maximum is needed, but code should not + * be written to require a maximum for no good reason. + */ +#define AV_VIDEO_MAX_PLANES 4 + +/** + * Pixel format. + * + * @note + * AV_PIX_FMT_RGB32 is handled in an endian-specific manner. An RGBA + * color is put together as: + * (A << 24) | (R << 16) | (G << 8) | B + * This is stored as BGRA on little-endian CPU architectures and ARGB on + * big-endian CPUs. + * + * @note + * If the resolution is not a multiple of the chroma subsampling factor + * then the chroma plane resolution must be rounded up. + * + * @par + * When the pixel format is palettized RGB32 (AV_PIX_FMT_PAL8), the palettized + * image data is stored in AVFrame.data[0]. The palette is transported in + * AVFrame.data[1], is 1024 bytes long (256 4-byte entries) and is + * formatted the same as in AV_PIX_FMT_RGB32 described above (i.e., it is + * also endian-specific). Note also that the individual RGB32 palette + * components stored in AVFrame.data[1] should be in the range 0..255. + * This is important as many custom PAL8 video codecs that were designed + * to run on the IBM VGA graphics adapter use 6-bit palette components. + * + * @par + * For all the 8 bits per pixel formats, an RGB32 palette is in data[1] like + * for pal8. This palette is filled in automatically by the function + * allocating the picture. + */ +enum AVPixelFormat { + AV_PIX_FMT_NONE = -1, + AV_PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) + AV_PIX_FMT_YUYV422, ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr + AV_PIX_FMT_RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB... + AV_PIX_FMT_BGR24, ///< packed RGB 8:8:8, 24bpp, BGRBGR... + AV_PIX_FMT_YUV422P, ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + AV_PIX_FMT_YUV444P, ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) + AV_PIX_FMT_YUV410P, ///< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) + AV_PIX_FMT_YUV411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) + AV_PIX_FMT_GRAY8, ///< Y , 8bpp + AV_PIX_FMT_MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb + AV_PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb + AV_PIX_FMT_PAL8, ///< 8 bits with AV_PIX_FMT_RGB32 palette + AV_PIX_FMT_YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting color_range + AV_PIX_FMT_YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting color_range + AV_PIX_FMT_YUVJ444P, ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting color_range + AV_PIX_FMT_UYVY422, ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 + AV_PIX_FMT_UYYVYY411, ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 + AV_PIX_FMT_BGR8, ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) + AV_PIX_FMT_BGR4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1B 2G 1R(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + AV_PIX_FMT_BGR4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb) + AV_PIX_FMT_RGB8, ///< packed RGB 3:3:2, 8bpp, (msb)3R 3G 2B(lsb) + AV_PIX_FMT_RGB4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1R 2G 1B(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + AV_PIX_FMT_RGB4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1R 2G 1B(lsb) + AV_PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + AV_PIX_FMT_NV21, ///< as above, but U and V bytes are swapped + + AV_PIX_FMT_ARGB, ///< packed ARGB 8:8:8:8, 32bpp, ARGBARGB... + AV_PIX_FMT_RGBA, ///< packed RGBA 8:8:8:8, 32bpp, RGBARGBA... + AV_PIX_FMT_ABGR, ///< packed ABGR 8:8:8:8, 32bpp, ABGRABGR... + AV_PIX_FMT_BGRA, ///< packed BGRA 8:8:8:8, 32bpp, BGRABGRA... + + AV_PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian + AV_PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian + AV_PIX_FMT_YUV440P, ///< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples) + AV_PIX_FMT_YUVJ440P, ///< planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range + AV_PIX_FMT_YUVA420P, ///< planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples) + AV_PIX_FMT_RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as big-endian + AV_PIX_FMT_RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as little-endian + + AV_PIX_FMT_RGB565BE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian + AV_PIX_FMT_RGB565LE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian + AV_PIX_FMT_RGB555BE, ///< packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), big-endian , X=unused/undefined + AV_PIX_FMT_RGB555LE, ///< packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), little-endian, X=unused/undefined + + AV_PIX_FMT_BGR565BE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian + AV_PIX_FMT_BGR565LE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian + AV_PIX_FMT_BGR555BE, ///< packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), big-endian , X=unused/undefined + AV_PIX_FMT_BGR555LE, ///< packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), little-endian, X=unused/undefined + + /** + * Hardware acceleration through VA-API, data[3] contains a + * VASurfaceID. + */ + AV_PIX_FMT_VAAPI, + + AV_PIX_FMT_YUV420P16LE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P16BE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV422P16LE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV422P16BE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV444P16LE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer + + AV_PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4X 4R 4G 4B(lsb), little-endian, X=unused/undefined + AV_PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4X 4R 4G 4B(lsb), big-endian, X=unused/undefined + AV_PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4X 4B 4G 4R(lsb), little-endian, X=unused/undefined + AV_PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4X 4B 4G 4R(lsb), big-endian, X=unused/undefined + AV_PIX_FMT_YA8, ///< 8 bits gray, 8 bits alpha + + AV_PIX_FMT_Y400A = AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8 + AV_PIX_FMT_GRAY8A= AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8 + + AV_PIX_FMT_BGR48BE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big-endian + AV_PIX_FMT_BGR48LE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as little-endian + + /** + * The following 12 formats have the disadvantage of needing 1 format for each bit depth. + * Notice that each 9/10 bits sample is stored in 16 bits with extra padding. + * If you want to support multiple bit depths, then using AV_PIX_FMT_YUV420P16* with the bpp stored separately is better. + */ + AV_PIX_FMT_YUV420P9BE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P9LE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P10BE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P10LE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV422P10BE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P10LE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV444P9BE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P9LE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P10BE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P10LE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV422P9BE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P9LE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_GBRP, ///< planar GBR 4:4:4 24bpp + AV_PIX_FMT_GBR24P = AV_PIX_FMT_GBRP, // alias for #AV_PIX_FMT_GBRP + AV_PIX_FMT_GBRP9BE, ///< planar GBR 4:4:4 27bpp, big-endian + AV_PIX_FMT_GBRP9LE, ///< planar GBR 4:4:4 27bpp, little-endian + AV_PIX_FMT_GBRP10BE, ///< planar GBR 4:4:4 30bpp, big-endian + AV_PIX_FMT_GBRP10LE, ///< planar GBR 4:4:4 30bpp, little-endian + AV_PIX_FMT_GBRP16BE, ///< planar GBR 4:4:4 48bpp, big-endian + AV_PIX_FMT_GBRP16LE, ///< planar GBR 4:4:4 48bpp, little-endian + AV_PIX_FMT_YUVA422P, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples) + AV_PIX_FMT_YUVA444P, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples) + AV_PIX_FMT_YUVA420P9BE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), big-endian + AV_PIX_FMT_YUVA420P9LE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), little-endian + AV_PIX_FMT_YUVA422P9BE, ///< planar YUV 4:2:2 27bpp, (1 Cr & Cb sample per 2x1 Y & A samples), big-endian + AV_PIX_FMT_YUVA422P9LE, ///< planar YUV 4:2:2 27bpp, (1 Cr & Cb sample per 2x1 Y & A samples), little-endian + AV_PIX_FMT_YUVA444P9BE, ///< planar YUV 4:4:4 36bpp, (1 Cr & Cb sample per 1x1 Y & A samples), big-endian + AV_PIX_FMT_YUVA444P9LE, ///< planar YUV 4:4:4 36bpp, (1 Cr & Cb sample per 1x1 Y & A samples), little-endian + AV_PIX_FMT_YUVA420P10BE, ///< planar YUV 4:2:0 25bpp, (1 Cr & Cb sample per 2x2 Y & A samples, big-endian) + AV_PIX_FMT_YUVA420P10LE, ///< planar YUV 4:2:0 25bpp, (1 Cr & Cb sample per 2x2 Y & A samples, little-endian) + AV_PIX_FMT_YUVA422P10BE, ///< planar YUV 4:2:2 30bpp, (1 Cr & Cb sample per 2x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA422P10LE, ///< planar YUV 4:2:2 30bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA444P10BE, ///< planar YUV 4:4:4 40bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA444P10LE, ///< planar YUV 4:4:4 40bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA420P16BE, ///< planar YUV 4:2:0 40bpp, (1 Cr & Cb sample per 2x2 Y & A samples, big-endian) + AV_PIX_FMT_YUVA420P16LE, ///< planar YUV 4:2:0 40bpp, (1 Cr & Cb sample per 2x2 Y & A samples, little-endian) + AV_PIX_FMT_YUVA422P16BE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA422P16LE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA444P16BE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA444P16LE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian) + + AV_PIX_FMT_VDPAU, ///< HW acceleration through VDPAU, Picture.data[3] contains a VdpVideoSurface + + AV_PIX_FMT_XYZ12LE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as little-endian, the 4 lower bits are set to 0 + AV_PIX_FMT_XYZ12BE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as big-endian, the 4 lower bits are set to 0 + AV_PIX_FMT_NV16, ///< interleaved chroma YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + AV_PIX_FMT_NV20LE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_NV20BE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + + AV_PIX_FMT_RGBA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + AV_PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + + AV_PIX_FMT_YVYU422, ///< packed YUV 4:2:2, 16bpp, Y0 Cr Y1 Cb + + AV_PIX_FMT_YA16BE, ///< 16 bits gray, 16 bits alpha (big-endian) + AV_PIX_FMT_YA16LE, ///< 16 bits gray, 16 bits alpha (little-endian) + + AV_PIX_FMT_GBRAP, ///< planar GBRA 4:4:4:4 32bpp + AV_PIX_FMT_GBRAP16BE, ///< planar GBRA 4:4:4:4 64bpp, big-endian + AV_PIX_FMT_GBRAP16LE, ///< planar GBRA 4:4:4:4 64bpp, little-endian + /** + * HW acceleration through QSV, data[3] contains a pointer to the + * mfxFrameSurface1 structure. + * + * Before FFmpeg 5.0: + * mfxFrameSurface1.Data.MemId contains a pointer when importing + * the following frames as QSV frames: + * + * VAAPI: + * mfxFrameSurface1.Data.MemId contains a pointer to VASurfaceID + * + * DXVA2: + * mfxFrameSurface1.Data.MemId contains a pointer to IDirect3DSurface9 + * + * FFmpeg 5.0 and above: + * mfxFrameSurface1.Data.MemId contains a pointer to the mfxHDLPair + * structure when importing the following frames as QSV frames: + * + * VAAPI: + * mfxHDLPair.first contains a VASurfaceID pointer. + * mfxHDLPair.second is always MFX_INFINITE. + * + * DXVA2: + * mfxHDLPair.first contains IDirect3DSurface9 pointer. + * mfxHDLPair.second is always MFX_INFINITE. + * + * D3D11: + * mfxHDLPair.first contains a ID3D11Texture2D pointer. + * mfxHDLPair.second contains the texture array index of the frame if the + * ID3D11Texture2D is an array texture, or always MFX_INFINITE if it is a + * normal texture. + */ + AV_PIX_FMT_QSV, + /** + * HW acceleration though MMAL, data[3] contains a pointer to the + * MMAL_BUFFER_HEADER_T structure. + */ + AV_PIX_FMT_MMAL, + + AV_PIX_FMT_D3D11VA_VLD, ///< HW decoding through Direct3D11 via old API, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer + + /** + * HW acceleration through CUDA. data[i] contain CUdeviceptr pointers + * exactly as for system memory frames. + */ + AV_PIX_FMT_CUDA, + + AV_PIX_FMT_0RGB, ///< packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined + AV_PIX_FMT_RGB0, ///< packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined + AV_PIX_FMT_0BGR, ///< packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined + AV_PIX_FMT_BGR0, ///< packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined + + AV_PIX_FMT_YUV420P12BE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P12LE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P14BE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P14LE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV422P14BE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P14LE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P14BE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P14LE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_GBRP12BE, ///< planar GBR 4:4:4 36bpp, big-endian + AV_PIX_FMT_GBRP12LE, ///< planar GBR 4:4:4 36bpp, little-endian + AV_PIX_FMT_GBRP14BE, ///< planar GBR 4:4:4 42bpp, big-endian + AV_PIX_FMT_GBRP14LE, ///< planar GBR 4:4:4 42bpp, little-endian + AV_PIX_FMT_YUVJ411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV411P and setting color_range + + AV_PIX_FMT_BAYER_BGGR8, ///< bayer, BGBG..(odd line), GRGR..(even line), 8-bit samples + AV_PIX_FMT_BAYER_RGGB8, ///< bayer, RGRG..(odd line), GBGB..(even line), 8-bit samples + AV_PIX_FMT_BAYER_GBRG8, ///< bayer, GBGB..(odd line), RGRG..(even line), 8-bit samples + AV_PIX_FMT_BAYER_GRBG8, ///< bayer, GRGR..(odd line), BGBG..(even line), 8-bit samples + AV_PIX_FMT_BAYER_BGGR16LE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, little-endian + AV_PIX_FMT_BAYER_BGGR16BE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, big-endian + AV_PIX_FMT_BAYER_RGGB16LE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, little-endian + AV_PIX_FMT_BAYER_RGGB16BE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, big-endian + AV_PIX_FMT_BAYER_GBRG16LE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, little-endian + AV_PIX_FMT_BAYER_GBRG16BE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, big-endian + AV_PIX_FMT_BAYER_GRBG16LE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, little-endian + AV_PIX_FMT_BAYER_GRBG16BE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, big-endian + + AV_PIX_FMT_YUV440P10LE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian + AV_PIX_FMT_YUV440P10BE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), big-endian + AV_PIX_FMT_YUV440P12LE, ///< planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian + AV_PIX_FMT_YUV440P12BE, ///< planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), big-endian + AV_PIX_FMT_AYUV64LE, ///< packed AYUV 4:4:4,64bpp (1 Cr & Cb sample per 1x1 Y & A samples), little-endian + AV_PIX_FMT_AYUV64BE, ///< packed AYUV 4:4:4,64bpp (1 Cr & Cb sample per 1x1 Y & A samples), big-endian + + AV_PIX_FMT_VIDEOTOOLBOX, ///< hardware decoding through Videotoolbox + + AV_PIX_FMT_P010LE, ///< like NV12, with 10bpp per component, data in the high bits, zeros in the low bits, little-endian + AV_PIX_FMT_P010BE, ///< like NV12, with 10bpp per component, data in the high bits, zeros in the low bits, big-endian + + AV_PIX_FMT_GBRAP12BE, ///< planar GBR 4:4:4:4 48bpp, big-endian + AV_PIX_FMT_GBRAP12LE, ///< planar GBR 4:4:4:4 48bpp, little-endian + + AV_PIX_FMT_GBRAP10BE, ///< planar GBR 4:4:4:4 40bpp, big-endian + AV_PIX_FMT_GBRAP10LE, ///< planar GBR 4:4:4:4 40bpp, little-endian + + AV_PIX_FMT_MEDIACODEC, ///< hardware decoding through MediaCodec + + AV_PIX_FMT_GRAY12BE, ///< Y , 12bpp, big-endian + AV_PIX_FMT_GRAY12LE, ///< Y , 12bpp, little-endian + AV_PIX_FMT_GRAY10BE, ///< Y , 10bpp, big-endian + AV_PIX_FMT_GRAY10LE, ///< Y , 10bpp, little-endian + + AV_PIX_FMT_P016LE, ///< like NV12, with 16bpp per component, little-endian + AV_PIX_FMT_P016BE, ///< like NV12, with 16bpp per component, big-endian + + /** + * Hardware surfaces for Direct3D11. + * + * This is preferred over the legacy AV_PIX_FMT_D3D11VA_VLD. The new D3D11 + * hwaccel API and filtering support AV_PIX_FMT_D3D11 only. + * + * data[0] contains a ID3D11Texture2D pointer, and data[1] contains the + * texture array index of the frame as intptr_t if the ID3D11Texture2D is + * an array texture (or always 0 if it's a normal texture). + */ + AV_PIX_FMT_D3D11, + + AV_PIX_FMT_GRAY9BE, ///< Y , 9bpp, big-endian + AV_PIX_FMT_GRAY9LE, ///< Y , 9bpp, little-endian + + AV_PIX_FMT_GBRPF32BE, ///< IEEE-754 single precision planar GBR 4:4:4, 96bpp, big-endian + AV_PIX_FMT_GBRPF32LE, ///< IEEE-754 single precision planar GBR 4:4:4, 96bpp, little-endian + AV_PIX_FMT_GBRAPF32BE, ///< IEEE-754 single precision planar GBRA 4:4:4:4, 128bpp, big-endian + AV_PIX_FMT_GBRAPF32LE, ///< IEEE-754 single precision planar GBRA 4:4:4:4, 128bpp, little-endian + + /** + * DRM-managed buffers exposed through PRIME buffer sharing. + * + * data[0] points to an AVDRMFrameDescriptor. + */ + AV_PIX_FMT_DRM_PRIME, + /** + * Hardware surfaces for OpenCL. + * + * data[i] contain 2D image objects (typed in C as cl_mem, used + * in OpenCL as image2d_t) for each plane of the surface. + */ + AV_PIX_FMT_OPENCL, + + AV_PIX_FMT_GRAY14BE, ///< Y , 14bpp, big-endian + AV_PIX_FMT_GRAY14LE, ///< Y , 14bpp, little-endian + + AV_PIX_FMT_GRAYF32BE, ///< IEEE-754 single precision Y, 32bpp, big-endian + AV_PIX_FMT_GRAYF32LE, ///< IEEE-754 single precision Y, 32bpp, little-endian + + AV_PIX_FMT_YUVA422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), 12b alpha, big-endian + AV_PIX_FMT_YUVA422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), 12b alpha, little-endian + AV_PIX_FMT_YUVA444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), 12b alpha, big-endian + AV_PIX_FMT_YUVA444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), 12b alpha, little-endian + + AV_PIX_FMT_NV24, ///< planar YUV 4:4:4, 24bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + AV_PIX_FMT_NV42, ///< as above, but U and V bytes are swapped + + /** + * Vulkan hardware images. + * + * data[0] points to an AVVkFrame + */ + AV_PIX_FMT_VULKAN, + + AV_PIX_FMT_Y210BE, ///< packed YUV 4:2:2 like YUYV422, 20bpp, data in the high bits, big-endian + AV_PIX_FMT_Y210LE, ///< packed YUV 4:2:2 like YUYV422, 20bpp, data in the high bits, little-endian + + AV_PIX_FMT_X2RGB10LE, ///< packed RGB 10:10:10, 30bpp, (msb)2X 10R 10G 10B(lsb), little-endian, X=unused/undefined + AV_PIX_FMT_X2RGB10BE, ///< packed RGB 10:10:10, 30bpp, (msb)2X 10R 10G 10B(lsb), big-endian, X=unused/undefined + AV_PIX_FMT_X2BGR10LE, ///< packed BGR 10:10:10, 30bpp, (msb)2X 10B 10G 10R(lsb), little-endian, X=unused/undefined + AV_PIX_FMT_X2BGR10BE, ///< packed BGR 10:10:10, 30bpp, (msb)2X 10B 10G 10R(lsb), big-endian, X=unused/undefined + + AV_PIX_FMT_P210BE, ///< interleaved chroma YUV 4:2:2, 20bpp, data in the high bits, big-endian + AV_PIX_FMT_P210LE, ///< interleaved chroma YUV 4:2:2, 20bpp, data in the high bits, little-endian + + AV_PIX_FMT_P410BE, ///< interleaved chroma YUV 4:4:4, 30bpp, data in the high bits, big-endian + AV_PIX_FMT_P410LE, ///< interleaved chroma YUV 4:4:4, 30bpp, data in the high bits, little-endian + + AV_PIX_FMT_P216BE, ///< interleaved chroma YUV 4:2:2, 32bpp, big-endian + AV_PIX_FMT_P216LE, ///< interleaved chroma YUV 4:2:2, 32bpp, little-endian + + AV_PIX_FMT_P416BE, ///< interleaved chroma YUV 4:4:4, 48bpp, big-endian + AV_PIX_FMT_P416LE, ///< interleaved chroma YUV 4:4:4, 48bpp, little-endian + + AV_PIX_FMT_VUYA, ///< packed VUYA 4:4:4:4, 32bpp (1 Cr & Cb sample per 1x1 Y & A samples), VUYAVUYA... + + AV_PIX_FMT_RGBAF16BE, ///< IEEE-754 half precision packed RGBA 16:16:16:16, 64bpp, RGBARGBA..., big-endian + AV_PIX_FMT_RGBAF16LE, ///< IEEE-754 half precision packed RGBA 16:16:16:16, 64bpp, RGBARGBA..., little-endian + + AV_PIX_FMT_VUYX, ///< packed VUYX 4:4:4:4, 32bpp, Variant of VUYA where alpha channel is left undefined + + AV_PIX_FMT_P012LE, ///< like NV12, with 12bpp per component, data in the high bits, zeros in the low bits, little-endian + AV_PIX_FMT_P012BE, ///< like NV12, with 12bpp per component, data in the high bits, zeros in the low bits, big-endian + + AV_PIX_FMT_Y212BE, ///< packed YUV 4:2:2 like YUYV422, 24bpp, data in the high bits, zeros in the low bits, big-endian + AV_PIX_FMT_Y212LE, ///< packed YUV 4:2:2 like YUYV422, 24bpp, data in the high bits, zeros in the low bits, little-endian + + AV_PIX_FMT_XV30BE, ///< packed XVYU 4:4:4, 32bpp, (msb)2X 10V 10Y 10U(lsb), big-endian, variant of Y410 where alpha channel is left undefined + AV_PIX_FMT_XV30LE, ///< packed XVYU 4:4:4, 32bpp, (msb)2X 10V 10Y 10U(lsb), little-endian, variant of Y410 where alpha channel is left undefined + + AV_PIX_FMT_XV36BE, ///< packed XVYU 4:4:4, 48bpp, data in the high bits, zeros in the low bits, big-endian, variant of Y412 where alpha channel is left undefined + AV_PIX_FMT_XV36LE, ///< packed XVYU 4:4:4, 48bpp, data in the high bits, zeros in the low bits, little-endian, variant of Y412 where alpha channel is left undefined + + AV_PIX_FMT_RGBF32BE, ///< IEEE-754 single precision packed RGB 32:32:32, 96bpp, RGBRGB..., big-endian + AV_PIX_FMT_RGBF32LE, ///< IEEE-754 single precision packed RGB 32:32:32, 96bpp, RGBRGB..., little-endian + + AV_PIX_FMT_RGBAF32BE, ///< IEEE-754 single precision packed RGBA 32:32:32:32, 128bpp, RGBARGBA..., big-endian + AV_PIX_FMT_RGBAF32LE, ///< IEEE-754 single precision packed RGBA 32:32:32:32, 128bpp, RGBARGBA..., little-endian + + AV_PIX_FMT_P212BE, ///< interleaved chroma YUV 4:2:2, 24bpp, data in the high bits, big-endian + AV_PIX_FMT_P212LE, ///< interleaved chroma YUV 4:2:2, 24bpp, data in the high bits, little-endian + + AV_PIX_FMT_P412BE, ///< interleaved chroma YUV 4:4:4, 36bpp, data in the high bits, big-endian + AV_PIX_FMT_P412LE, ///< interleaved chroma YUV 4:4:4, 36bpp, data in the high bits, little-endian + + AV_PIX_FMT_GBRAP14BE, ///< planar GBR 4:4:4:4 56bpp, big-endian + AV_PIX_FMT_GBRAP14LE, ///< planar GBR 4:4:4:4 56bpp, little-endian + + /** + * Hardware surfaces for Direct3D 12. + * + * data[0] points to an AVD3D12VAFrame + */ + AV_PIX_FMT_D3D12, + + AV_PIX_FMT_AYUV, ///< packed AYUV 4:4:4:4, 32bpp (1 Cr & Cb sample per 1x1 Y & A samples), AYUVAYUV... + + AV_PIX_FMT_UYVA, ///< packed UYVA 4:4:4:4, 32bpp (1 Cr & Cb sample per 1x1 Y & A samples), UYVAUYVA... + + AV_PIX_FMT_VYU444, ///< packed VYU 4:4:4, 24bpp (1 Cr & Cb sample per 1x1 Y), VYUVYU... + + AV_PIX_FMT_V30XBE, ///< packed VYUX 4:4:4 like XV30, 32bpp, (msb)10V 10Y 10U 2X(lsb), big-endian + AV_PIX_FMT_V30XLE, ///< packed VYUX 4:4:4 like XV30, 32bpp, (msb)10V 10Y 10U 2X(lsb), little-endian + + AV_PIX_FMT_RGBF16BE, ///< IEEE-754 half precision packed RGB 16:16:16, 48bpp, RGBRGB..., big-endian + AV_PIX_FMT_RGBF16LE, ///< IEEE-754 half precision packed RGB 16:16:16, 48bpp, RGBRGB..., little-endian + + AV_PIX_FMT_RGBA128BE, ///< packed RGBA 32:32:32:32, 128bpp, RGBARGBA..., big-endian + AV_PIX_FMT_RGBA128LE, ///< packed RGBA 32:32:32:32, 128bpp, RGBARGBA..., little-endian + + AV_PIX_FMT_RGB96BE, ///< packed RGBA 32:32:32, 96bpp, RGBRGB..., big-endian + AV_PIX_FMT_RGB96LE, ///< packed RGBA 32:32:32, 96bpp, RGBRGB..., little-endian + + AV_PIX_FMT_Y216BE, ///< packed YUV 4:2:2 like YUYV422, 32bpp, big-endian + AV_PIX_FMT_Y216LE, ///< packed YUV 4:2:2 like YUYV422, 32bpp, little-endian + + AV_PIX_FMT_XV48BE, ///< packed XVYU 4:4:4, 64bpp, big-endian, variant of Y416 where alpha channel is left undefined + AV_PIX_FMT_XV48LE, ///< packed XVYU 4:4:4, 64bpp, little-endian, variant of Y416 where alpha channel is left undefined + + AV_PIX_FMT_GBRPF16BE, ///< IEEE-754 half precision planer GBR 4:4:4, 48bpp, big-endian + AV_PIX_FMT_GBRPF16LE, ///< IEEE-754 half precision planer GBR 4:4:4, 48bpp, little-endian + AV_PIX_FMT_GBRAPF16BE, ///< IEEE-754 half precision planar GBRA 4:4:4:4, 64bpp, big-endian + AV_PIX_FMT_GBRAPF16LE, ///< IEEE-754 half precision planar GBRA 4:4:4:4, 64bpp, little-endian + + AV_PIX_FMT_GRAYF16BE, ///< IEEE-754 half precision Y, 16bpp, big-endian + AV_PIX_FMT_GRAYF16LE, ///< IEEE-754 half precision Y, 16bpp, little-endian + + /** + * HW acceleration through AMF. data[0] contain AMFSurface pointer + */ + AV_PIX_FMT_AMF_SURFACE, + + AV_PIX_FMT_GRAY32BE, ///< Y , 32bpp, big-endian + AV_PIX_FMT_GRAY32LE, ///< Y , 32bpp, little-endian + + AV_PIX_FMT_YAF32BE, ///< IEEE-754 single precision packed YA, 32 bits gray, 32 bits alpha, 64bpp, big-endian + AV_PIX_FMT_YAF32LE, ///< IEEE-754 single precision packed YA, 32 bits gray, 32 bits alpha, 64bpp, little-endian + + AV_PIX_FMT_YAF16BE, ///< IEEE-754 half precision packed YA, 16 bits gray, 16 bits alpha, 32bpp, big-endian + AV_PIX_FMT_YAF16LE, ///< IEEE-754 half precision packed YA, 16 bits gray, 16 bits alpha, 32bpp, little-endian + + AV_PIX_FMT_GBRAP32BE, ///< planar GBRA 4:4:4:4 128bpp, big-endian + AV_PIX_FMT_GBRAP32LE, ///< planar GBRA 4:4:4:4 128bpp, little-endian + + AV_PIX_FMT_YUV444P10MSBBE, ///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), lowest bits zero, big-endian + AV_PIX_FMT_YUV444P10MSBLE, ///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), lowest bits zero, little-endian + AV_PIX_FMT_YUV444P12MSBBE, ///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), lowest bits zero, big-endian + AV_PIX_FMT_YUV444P12MSBLE, ///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), lowest bits zero, little-endian + AV_PIX_FMT_GBRP10MSBBE, ///< planar GBR 4:4:4 30bpp, lowest bits zero, big-endian + AV_PIX_FMT_GBRP10MSBLE, ///< planar GBR 4:4:4 30bpp, lowest bits zero, little-endian + AV_PIX_FMT_GBRP12MSBBE, ///< planar GBR 4:4:4 36bpp, lowest bits zero, big-endian + AV_PIX_FMT_GBRP12MSBLE, ///< planar GBR 4:4:4 36bpp, lowest bits zero, little-endian + + AV_PIX_FMT_OHCODEC, /// hardware decoding through openharmony + + AV_PIX_FMT_NB ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions +}; + +#if AV_HAVE_BIGENDIAN +# define AV_PIX_FMT_NE(be, le) AV_PIX_FMT_##be +#else +# define AV_PIX_FMT_NE(be, le) AV_PIX_FMT_##le +#endif + +#define AV_PIX_FMT_RGB32 AV_PIX_FMT_NE(ARGB, BGRA) +#define AV_PIX_FMT_RGB32_1 AV_PIX_FMT_NE(RGBA, ABGR) +#define AV_PIX_FMT_BGR32 AV_PIX_FMT_NE(ABGR, RGBA) +#define AV_PIX_FMT_BGR32_1 AV_PIX_FMT_NE(BGRA, ARGB) +#define AV_PIX_FMT_0RGB32 AV_PIX_FMT_NE(0RGB, BGR0) +#define AV_PIX_FMT_0BGR32 AV_PIX_FMT_NE(0BGR, RGB0) + +#define AV_PIX_FMT_GRAY9 AV_PIX_FMT_NE(GRAY9BE, GRAY9LE) +#define AV_PIX_FMT_GRAY10 AV_PIX_FMT_NE(GRAY10BE, GRAY10LE) +#define AV_PIX_FMT_GRAY12 AV_PIX_FMT_NE(GRAY12BE, GRAY12LE) +#define AV_PIX_FMT_GRAY14 AV_PIX_FMT_NE(GRAY14BE, GRAY14LE) +#define AV_PIX_FMT_GRAY16 AV_PIX_FMT_NE(GRAY16BE, GRAY16LE) +#define AV_PIX_FMT_GRAY32 AV_PIX_FMT_NE(GRAY32BE, GRAY32LE) +#define AV_PIX_FMT_YA16 AV_PIX_FMT_NE(YA16BE, YA16LE) +#define AV_PIX_FMT_RGB48 AV_PIX_FMT_NE(RGB48BE, RGB48LE) +#define AV_PIX_FMT_RGB565 AV_PIX_FMT_NE(RGB565BE, RGB565LE) +#define AV_PIX_FMT_RGB555 AV_PIX_FMT_NE(RGB555BE, RGB555LE) +#define AV_PIX_FMT_RGB444 AV_PIX_FMT_NE(RGB444BE, RGB444LE) +#define AV_PIX_FMT_RGBA64 AV_PIX_FMT_NE(RGBA64BE, RGBA64LE) +#define AV_PIX_FMT_BGR48 AV_PIX_FMT_NE(BGR48BE, BGR48LE) +#define AV_PIX_FMT_BGR565 AV_PIX_FMT_NE(BGR565BE, BGR565LE) +#define AV_PIX_FMT_BGR555 AV_PIX_FMT_NE(BGR555BE, BGR555LE) +#define AV_PIX_FMT_BGR444 AV_PIX_FMT_NE(BGR444BE, BGR444LE) +#define AV_PIX_FMT_BGRA64 AV_PIX_FMT_NE(BGRA64BE, BGRA64LE) + +#define AV_PIX_FMT_YUV420P9 AV_PIX_FMT_NE(YUV420P9BE , YUV420P9LE) +#define AV_PIX_FMT_YUV422P9 AV_PIX_FMT_NE(YUV422P9BE , YUV422P9LE) +#define AV_PIX_FMT_YUV444P9 AV_PIX_FMT_NE(YUV444P9BE , YUV444P9LE) +#define AV_PIX_FMT_YUV420P10 AV_PIX_FMT_NE(YUV420P10BE, YUV420P10LE) +#define AV_PIX_FMT_YUV422P10 AV_PIX_FMT_NE(YUV422P10BE, YUV422P10LE) +#define AV_PIX_FMT_YUV440P10 AV_PIX_FMT_NE(YUV440P10BE, YUV440P10LE) +#define AV_PIX_FMT_YUV444P10 AV_PIX_FMT_NE(YUV444P10BE, YUV444P10LE) +#define AV_PIX_FMT_YUV420P12 AV_PIX_FMT_NE(YUV420P12BE, YUV420P12LE) +#define AV_PIX_FMT_YUV422P12 AV_PIX_FMT_NE(YUV422P12BE, YUV422P12LE) +#define AV_PIX_FMT_YUV440P12 AV_PIX_FMT_NE(YUV440P12BE, YUV440P12LE) +#define AV_PIX_FMT_YUV444P12 AV_PIX_FMT_NE(YUV444P12BE, YUV444P12LE) +#define AV_PIX_FMT_YUV420P14 AV_PIX_FMT_NE(YUV420P14BE, YUV420P14LE) +#define AV_PIX_FMT_YUV422P14 AV_PIX_FMT_NE(YUV422P14BE, YUV422P14LE) +#define AV_PIX_FMT_YUV444P14 AV_PIX_FMT_NE(YUV444P14BE, YUV444P14LE) +#define AV_PIX_FMT_YUV420P16 AV_PIX_FMT_NE(YUV420P16BE, YUV420P16LE) +#define AV_PIX_FMT_YUV422P16 AV_PIX_FMT_NE(YUV422P16BE, YUV422P16LE) +#define AV_PIX_FMT_YUV444P16 AV_PIX_FMT_NE(YUV444P16BE, YUV444P16LE) + +#define AV_PIX_FMT_YUV444P10MSB AV_PIX_FMT_NE(YUV444P10MSBBE, YUV444P10MSBLE) +#define AV_PIX_FMT_YUV444P12MSB AV_PIX_FMT_NE(YUV444P12MSBBE, YUV444P12MSBLE) + +#define AV_PIX_FMT_GBRP9 AV_PIX_FMT_NE(GBRP9BE , GBRP9LE) +#define AV_PIX_FMT_GBRP10 AV_PIX_FMT_NE(GBRP10BE, GBRP10LE) +#define AV_PIX_FMT_GBRP12 AV_PIX_FMT_NE(GBRP12BE, GBRP12LE) +#define AV_PIX_FMT_GBRP14 AV_PIX_FMT_NE(GBRP14BE, GBRP14LE) +#define AV_PIX_FMT_GBRP16 AV_PIX_FMT_NE(GBRP16BE, GBRP16LE) +#define AV_PIX_FMT_GBRAP10 AV_PIX_FMT_NE(GBRAP10BE, GBRAP10LE) +#define AV_PIX_FMT_GBRAP12 AV_PIX_FMT_NE(GBRAP12BE, GBRAP12LE) +#define AV_PIX_FMT_GBRAP14 AV_PIX_FMT_NE(GBRAP14BE, GBRAP14LE) +#define AV_PIX_FMT_GBRAP16 AV_PIX_FMT_NE(GBRAP16BE, GBRAP16LE) +#define AV_PIX_FMT_GBRAP32 AV_PIX_FMT_NE(GBRAP32BE, GBRAP32LE) + +#define AV_PIX_FMT_GBRP10MSB AV_PIX_FMT_NE(GBRP10MSBBE, GBRP10MSBLE) +#define AV_PIX_FMT_GBRP12MSB AV_PIX_FMT_NE(GBRP12MSBBE, GBRP12MSBLE) + +#define AV_PIX_FMT_BAYER_BGGR16 AV_PIX_FMT_NE(BAYER_BGGR16BE, BAYER_BGGR16LE) +#define AV_PIX_FMT_BAYER_RGGB16 AV_PIX_FMT_NE(BAYER_RGGB16BE, BAYER_RGGB16LE) +#define AV_PIX_FMT_BAYER_GBRG16 AV_PIX_FMT_NE(BAYER_GBRG16BE, BAYER_GBRG16LE) +#define AV_PIX_FMT_BAYER_GRBG16 AV_PIX_FMT_NE(BAYER_GRBG16BE, BAYER_GRBG16LE) + +#define AV_PIX_FMT_GBRPF16 AV_PIX_FMT_NE(GBRPF16BE, GBRPF16LE) +#define AV_PIX_FMT_GBRAPF16 AV_PIX_FMT_NE(GBRAPF16BE, GBRAPF16LE) +#define AV_PIX_FMT_GBRPF32 AV_PIX_FMT_NE(GBRPF32BE, GBRPF32LE) +#define AV_PIX_FMT_GBRAPF32 AV_PIX_FMT_NE(GBRAPF32BE, GBRAPF32LE) + +#define AV_PIX_FMT_GRAYF16 AV_PIX_FMT_NE(GRAYF16BE, GRAYF16LE) +#define AV_PIX_FMT_GRAYF32 AV_PIX_FMT_NE(GRAYF32BE, GRAYF32LE) + +#define AV_PIX_FMT_YAF16 AV_PIX_FMT_NE(YAF16BE, YAF16LE) +#define AV_PIX_FMT_YAF32 AV_PIX_FMT_NE(YAF32BE, YAF32LE) + +#define AV_PIX_FMT_YUVA420P9 AV_PIX_FMT_NE(YUVA420P9BE , YUVA420P9LE) +#define AV_PIX_FMT_YUVA422P9 AV_PIX_FMT_NE(YUVA422P9BE , YUVA422P9LE) +#define AV_PIX_FMT_YUVA444P9 AV_PIX_FMT_NE(YUVA444P9BE , YUVA444P9LE) +#define AV_PIX_FMT_YUVA420P10 AV_PIX_FMT_NE(YUVA420P10BE, YUVA420P10LE) +#define AV_PIX_FMT_YUVA422P10 AV_PIX_FMT_NE(YUVA422P10BE, YUVA422P10LE) +#define AV_PIX_FMT_YUVA444P10 AV_PIX_FMT_NE(YUVA444P10BE, YUVA444P10LE) +#define AV_PIX_FMT_YUVA422P12 AV_PIX_FMT_NE(YUVA422P12BE, YUVA422P12LE) +#define AV_PIX_FMT_YUVA444P12 AV_PIX_FMT_NE(YUVA444P12BE, YUVA444P12LE) +#define AV_PIX_FMT_YUVA420P16 AV_PIX_FMT_NE(YUVA420P16BE, YUVA420P16LE) +#define AV_PIX_FMT_YUVA422P16 AV_PIX_FMT_NE(YUVA422P16BE, YUVA422P16LE) +#define AV_PIX_FMT_YUVA444P16 AV_PIX_FMT_NE(YUVA444P16BE, YUVA444P16LE) + +#define AV_PIX_FMT_XYZ12 AV_PIX_FMT_NE(XYZ12BE, XYZ12LE) +#define AV_PIX_FMT_NV20 AV_PIX_FMT_NE(NV20BE, NV20LE) +#define AV_PIX_FMT_AYUV64 AV_PIX_FMT_NE(AYUV64BE, AYUV64LE) +#define AV_PIX_FMT_P010 AV_PIX_FMT_NE(P010BE, P010LE) +#define AV_PIX_FMT_P012 AV_PIX_FMT_NE(P012BE, P012LE) +#define AV_PIX_FMT_P016 AV_PIX_FMT_NE(P016BE, P016LE) + +#define AV_PIX_FMT_Y210 AV_PIX_FMT_NE(Y210BE, Y210LE) +#define AV_PIX_FMT_Y212 AV_PIX_FMT_NE(Y212BE, Y212LE) +#define AV_PIX_FMT_Y216 AV_PIX_FMT_NE(Y216BE, Y216LE) +#define AV_PIX_FMT_XV30 AV_PIX_FMT_NE(XV30BE, XV30LE) +#define AV_PIX_FMT_XV36 AV_PIX_FMT_NE(XV36BE, XV36LE) +#define AV_PIX_FMT_XV48 AV_PIX_FMT_NE(XV48BE, XV48LE) +#define AV_PIX_FMT_V30X AV_PIX_FMT_NE(V30XBE, V30XLE) +#define AV_PIX_FMT_X2RGB10 AV_PIX_FMT_NE(X2RGB10BE, X2RGB10LE) +#define AV_PIX_FMT_X2BGR10 AV_PIX_FMT_NE(X2BGR10BE, X2BGR10LE) + +#define AV_PIX_FMT_P210 AV_PIX_FMT_NE(P210BE, P210LE) +#define AV_PIX_FMT_P410 AV_PIX_FMT_NE(P410BE, P410LE) +#define AV_PIX_FMT_P212 AV_PIX_FMT_NE(P212BE, P212LE) +#define AV_PIX_FMT_P412 AV_PIX_FMT_NE(P412BE, P412LE) +#define AV_PIX_FMT_P216 AV_PIX_FMT_NE(P216BE, P216LE) +#define AV_PIX_FMT_P416 AV_PIX_FMT_NE(P416BE, P416LE) + +#define AV_PIX_FMT_RGBF16 AV_PIX_FMT_NE(RGBF16BE, RGBF16LE) +#define AV_PIX_FMT_RGBAF16 AV_PIX_FMT_NE(RGBAF16BE, RGBAF16LE) + +#define AV_PIX_FMT_RGBF32 AV_PIX_FMT_NE(RGBF32BE, RGBF32LE) +#define AV_PIX_FMT_RGBAF32 AV_PIX_FMT_NE(RGBAF32BE, RGBAF32LE) + +#define AV_PIX_FMT_RGB96 AV_PIX_FMT_NE(RGB96BE, RGB96LE) +#define AV_PIX_FMT_RGBA128 AV_PIX_FMT_NE(RGBA128BE, RGBA128LE) + +/** + * Chromaticity coordinates of the source primaries. + * These values match the ones defined by ISO/IEC 23091-2_2019 subclause 8.1 and ITU-T H.273. + */ +enum AVColorPrimaries { + AVCOL_PRI_RESERVED0 = 0, + AVCOL_PRI_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP 177 Annex B + AVCOL_PRI_UNSPECIFIED = 2, + AVCOL_PRI_RESERVED = 3, + AVCOL_PRI_BT470M = 4, ///< also FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + + AVCOL_PRI_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM + AVCOL_PRI_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_PRI_SMPTE240M = 7, ///< identical to above, also called "SMPTE C" even though it uses D65 + AVCOL_PRI_FILM = 8, ///< colour filters using Illuminant C + AVCOL_PRI_BT2020 = 9, ///< ITU-R BT2020 + AVCOL_PRI_SMPTE428 = 10, ///< SMPTE ST 428-1 (CIE 1931 XYZ) + AVCOL_PRI_SMPTEST428_1 = AVCOL_PRI_SMPTE428, + AVCOL_PRI_SMPTE431 = 11, ///< SMPTE ST 431-2 (2011) / DCI P3 + AVCOL_PRI_SMPTE432 = 12, ///< SMPTE ST 432-1 (2010) / P3 D65 / Display P3 + AVCOL_PRI_EBU3213 = 22, ///< EBU Tech. 3213-E (nothing there) / one of JEDEC P22 group phosphors + AVCOL_PRI_JEDEC_P22 = AVCOL_PRI_EBU3213, + AVCOL_PRI_NB, ///< Not part of ABI + + /* The following entries are not part of H.273, but custom extensions */ + AVCOL_PRI_EXT_BASE = 256, + AVCOL_PRI_V_GAMUT = AVCOL_PRI_EXT_BASE, + AVCOL_PRI_EXT_NB ///< Not part of ABI +}; + +/** + * Color Transfer Characteristic. + * These values match the ones defined by ISO/IEC 23091-2_2019 subclause 8.2. + */ +enum AVColorTransferCharacteristic { + AVCOL_TRC_RESERVED0 = 0, + AVCOL_TRC_BT709 = 1, ///< also ITU-R BT1361 + AVCOL_TRC_UNSPECIFIED = 2, + AVCOL_TRC_RESERVED = 3, + AVCOL_TRC_GAMMA22 = 4, ///< also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM + AVCOL_TRC_GAMMA28 = 5, ///< also ITU-R BT470BG + AVCOL_TRC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC + AVCOL_TRC_SMPTE240M = 7, + AVCOL_TRC_LINEAR = 8, ///< "Linear transfer characteristics" + AVCOL_TRC_LOG = 9, ///< "Logarithmic transfer characteristic (100:1 range)" + AVCOL_TRC_LOG_SQRT = 10, ///< "Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range)" + AVCOL_TRC_IEC61966_2_4 = 11, ///< IEC 61966-2-4 + AVCOL_TRC_BT1361_ECG = 12, ///< ITU-R BT1361 Extended Colour Gamut + AVCOL_TRC_IEC61966_2_1 = 13, ///< IEC 61966-2-1 (sRGB or sYCC) + AVCOL_TRC_BT2020_10 = 14, ///< ITU-R BT2020 for 10-bit system + AVCOL_TRC_BT2020_12 = 15, ///< ITU-R BT2020 for 12-bit system + AVCOL_TRC_SMPTE2084 = 16, ///< SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems + AVCOL_TRC_SMPTEST2084 = AVCOL_TRC_SMPTE2084, + AVCOL_TRC_SMPTE428 = 17, ///< SMPTE ST 428-1 + AVCOL_TRC_SMPTEST428_1 = AVCOL_TRC_SMPTE428, + AVCOL_TRC_ARIB_STD_B67 = 18, ///< ARIB STD-B67, known as "Hybrid log-gamma" + AVCOL_TRC_NB, ///< Not part of ABI + + /* The following entries are not part of H.273, but custom extensions */ + AVCOL_TRC_EXT_BASE = 256, + AVCOL_TRC_V_LOG = AVCOL_TRC_EXT_BASE, + AVCOL_TRC_EXT_NB ///< Not part of ABI +}; + +/** + * YUV colorspace type. + * These values match the ones defined by ISO/IEC 23091-2_2019 subclause 8.3. + */ +enum AVColorSpace { + AVCOL_SPC_RGB = 0, ///< order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB), YZX and ST 428-1 + AVCOL_SPC_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / derived in SMPTE RP 177 Annex B + AVCOL_SPC_UNSPECIFIED = 2, + AVCOL_SPC_RESERVED = 3, ///< reserved for future use by ITU-T and ISO/IEC just like 15-255 are + AVCOL_SPC_FCC = 4, ///< FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + AVCOL_SPC_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601 + AVCOL_SPC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC / functionally identical to above + AVCOL_SPC_SMPTE240M = 7, ///< derived from 170M primaries and D65 white point, 170M is derived from BT470 System M's primaries + AVCOL_SPC_YCGCO = 8, ///< used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16 + AVCOL_SPC_YCOCG = AVCOL_SPC_YCGCO, + AVCOL_SPC_BT2020_NCL = 9, ///< ITU-R BT2020 non-constant luminance system + AVCOL_SPC_BT2020_CL = 10, ///< ITU-R BT2020 constant luminance system + AVCOL_SPC_SMPTE2085 = 11, ///< SMPTE 2085, Y'D'zD'x + AVCOL_SPC_CHROMA_DERIVED_NCL = 12, ///< Chromaticity-derived non-constant luminance system + AVCOL_SPC_CHROMA_DERIVED_CL = 13, ///< Chromaticity-derived constant luminance system + AVCOL_SPC_ICTCP = 14, ///< ITU-R BT.2100-0, ICtCp + AVCOL_SPC_IPT_C2 = 15, ///< SMPTE ST 2128, IPT-C2 + AVCOL_SPC_YCGCO_RE = 16, ///< YCgCo-R, even addition of bits + AVCOL_SPC_YCGCO_RO = 17, ///< YCgCo-R, odd addition of bits + AVCOL_SPC_NB ///< Not part of ABI +}; + +/** + * Visual content value range. + * + * These values are based on definitions that can be found in multiple + * specifications, such as ITU-T BT.709 (3.4 - Quantization of RGB, luminance + * and colour-difference signals), ITU-T BT.2020 (Table 5 - Digital + * Representation) as well as ITU-T BT.2100 (Table 9 - Digital 10- and 12-bit + * integer representation). At the time of writing, the BT.2100 one is + * recommended, as it also defines the full range representation. + * + * Common definitions: + * - For RGB and luma planes such as Y in YCbCr and I in ICtCp, + * 'E' is the original value in range of 0.0 to 1.0. + * - For chroma planes such as Cb,Cr and Ct,Cp, 'E' is the original + * value in range of -0.5 to 0.5. + * - 'n' is the output bit depth. + * - For additional definitions such as rounding and clipping to valid n + * bit unsigned integer range, please refer to BT.2100 (Table 9). + */ +enum AVColorRange { + AVCOL_RANGE_UNSPECIFIED = 0, + + /** + * Narrow or limited range content. + * + * - For luma planes: + * + * (219 * E + 16) * 2^(n-8) + * + * F.ex. the range of 16-235 for 8 bits + * + * - For chroma planes: + * + * (224 * E + 128) * 2^(n-8) + * + * F.ex. the range of 16-240 for 8 bits + */ + AVCOL_RANGE_MPEG = 1, + + /** + * Full range content. + * + * - For RGB and luma planes: + * + * (2^n - 1) * E + * + * F.ex. the range of 0-255 for 8 bits + * + * - For chroma planes: + * + * (2^n - 1) * E + 2^(n - 1) + * + * F.ex. the range of 1-255 for 8 bits + */ + AVCOL_RANGE_JPEG = 2, + AVCOL_RANGE_NB ///< Not part of ABI +}; + +/** + * Location of chroma samples. + * + * Illustration showing the location of the first (top left) chroma sample of the + * image, the left shows only luma, the right + * shows the location of the chroma sample, the 2 could be imagined to overlay + * each other but are drawn separately due to limitations of ASCII + * + * 1st 2nd 1st 2nd horizontal luma sample positions + * v v v v + * ______ ______ + *1st luma line > |X X ... |3 4 X ... X are luma samples, + * | |1 2 1-6 are possible chroma positions + *2nd luma line > |X X ... |5 6 X ... 0 is undefined/unknown position + */ +enum AVChromaLocation { + AVCHROMA_LOC_UNSPECIFIED = 0, + AVCHROMA_LOC_LEFT = 1, ///< MPEG-2/4 4:2:0, H.264 default for 4:2:0 + AVCHROMA_LOC_CENTER = 2, ///< MPEG-1 4:2:0, JPEG 4:2:0, H.263 4:2:0 + AVCHROMA_LOC_TOPLEFT = 3, ///< ITU-R 601, SMPTE 274M 296M S314M(DV 4:1:1), mpeg2 4:2:2 + AVCHROMA_LOC_TOP = 4, + AVCHROMA_LOC_BOTTOMLEFT = 5, + AVCHROMA_LOC_BOTTOM = 6, + AVCHROMA_LOC_NB ///< Not part of ABI +}; + +/** + * Correlation between the alpha channel and color values. + */ +enum AVAlphaMode { + AVALPHA_MODE_UNSPECIFIED = 0, ///< Unknown alpha handling, or no alpha channel + AVALPHA_MODE_PREMULTIPLIED = 1, ///< Alpha channel is multiplied into color values + AVALPHA_MODE_STRAIGHT = 2, ///< Alpha channel is independent of color values + AVALPHA_MODE_NB ///< Not part of ABI +}; + +#endif /* AVUTIL_PIXFMT_H */ diff --git a/libs/ffmpeg/libavutil/ppc/cpu.h b/libs/ffmpeg/libavutil/ppc/cpu.h new file mode 100644 index 00000000000..36973a54ea0 --- /dev/null +++ b/libs/ffmpeg/libavutil/ppc/cpu.h @@ -0,0 +1,29 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PPC_CPU_H +#define AVUTIL_PPC_CPU_H + +#include "libavutil/cpu.h" +#include "libavutil/cpu_internal.h" + +#define PPC_ALTIVEC(flags) CPUEXT(flags, ALTIVEC) +#define PPC_VSX(flags) CPUEXT(flags, VSX) +#define PPC_POWER8(flags) CPUEXT(flags, POWER8) + +#endif /* AVUTIL_PPC_CPU_H */ diff --git a/libs/ffmpeg/libavutil/qsort.h b/libs/ffmpeg/libavutil/qsort.h new file mode 100644 index 00000000000..6014f88be32 --- /dev/null +++ b/libs/ffmpeg/libavutil/qsort.h @@ -0,0 +1,122 @@ +/* + * copyright (c) 2012 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_QSORT_H +#define AVUTIL_QSORT_H + +#include "macros.h" + + +/** + * Quicksort + * This sort is fast, and fully inplace but not stable and it is possible + * to construct input that requires O(n^2) time but this is very unlikely to + * happen with non constructed input. + */ +#define AV_QSORT(p, num, type, cmp) do {\ + void *stack[64][2];\ + int sp= 1;\ + stack[0][0] = p;\ + stack[0][1] = (p)+(num)-1;\ + while(sp){\ + type *start= stack[--sp][0];\ + type *end = stack[ sp][1];\ + while(start < end){\ + if(start < end-1) {\ + int checksort=0;\ + type *right = end-2;\ + type *left = start+1;\ + type *mid = start + ((end-start)>>1);\ + if(cmp(start, end) > 0) {\ + if(cmp( end, mid) > 0) FFSWAP(type, *start, *mid);\ + else FFSWAP(type, *start, *end);\ + }else{\ + if(cmp(start, mid) > 0) FFSWAP(type, *start, *mid);\ + else checksort= 1;\ + }\ + if(cmp(mid, end) > 0){ \ + FFSWAP(type, *mid, *end);\ + checksort=0;\ + }\ + if(start == end-2) break;\ + FFSWAP(type, end[-1], *mid);\ + while(left <= right){\ + while(left<=right && cmp(left, end-1) < 0)\ + left++;\ + while(left<=right && cmp(right, end-1) > 0)\ + right--;\ + if(left <= right){\ + FFSWAP(type, *left, *right);\ + left++;\ + right--;\ + }\ + }\ + FFSWAP(type, end[-1], *left);\ + if(checksort && (mid == left-1 || mid == left)){\ + mid= start;\ + while(mid<end && cmp(mid, mid+1) <= 0)\ + mid++;\ + if(mid==end)\ + break;\ + }\ + if(end-left < left-start){\ + stack[sp ][0]= start;\ + stack[sp++][1]= right;\ + start = left+1;\ + }else{\ + stack[sp ][0]= left+1;\ + stack[sp++][1]= end;\ + end = right;\ + }\ + }else{\ + if(cmp(start, end) > 0)\ + FFSWAP(type, *start, *end);\ + break;\ + }\ + }\ + }\ +} while (0) + +/** + * Merge sort, this sort requires a temporary buffer and is stable, its worst + * case time is O(n log n) + * @param p must be a lvalue pointer, this function may exchange it with tmp + * @param tmp must be a lvalue pointer, this function may exchange it with p + */ +#define AV_MSORT(p, tmp, num, type, cmp) do {\ + unsigned i, j, step;\ + for(step=1; step<(num); step+=step){\ + for(i=0; i<(num); i+=2*step){\ + unsigned a[2] = {i, i+step};\ + unsigned end = FFMIN(i+2*step, (num));\ + for(j=i; a[0]<i+step && a[1]<end; j++){\ + int idx= cmp(p+a[0], p+a[1]) > 0;\ + tmp[j] = p[ a[idx]++ ];\ + }\ + if(a[0]>=i+step) a[0] = a[1];\ + for(; j<end; j++){\ + tmp[j] = p[ a[0]++ ];\ + }\ + }\ + FFSWAP(type*, p, tmp);\ + }\ +} while (0) + +#endif /* AVUTIL_QSORT_H */ diff --git a/libs/ffmpeg/libavutil/random_seed.c b/libs/ffmpeg/libavutil/random_seed.c new file mode 100644 index 00000000000..e08ab7b12e8 --- /dev/null +++ b/libs/ffmpeg/libavutil/random_seed.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2009 Baptiste Coudurier <baptiste.coudurier@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_IO_H +#include <io.h> +#endif +#if HAVE_BCRYPT +#include <windows.h> +#include <bcrypt.h> +#endif +#if CONFIG_GCRYPT +#include <gcrypt.h> +#elif CONFIG_OPENSSL +#include <openssl/rand.h> +#endif +#include <fcntl.h> +#include <math.h> +#include <time.h> +#include <string.h> +#include "avassert.h" +#include "file_open.h" +#include "internal.h" +#include "intreadwrite.h" +#include "timer.h" +#include "random_seed.h" +#include "sha.h" + +#ifndef TEST +#define TEST 0 +#endif + +static int read_random(uint8_t *dst, size_t len, const char *file) +{ +#if HAVE_UNISTD_H + FILE *fp = avpriv_fopen_utf8(file, "r"); + size_t err; + + if (!fp) + return AVERROR_UNKNOWN; + setvbuf(fp, NULL, _IONBF, 0); + err = fread(dst, 1, len, fp); + fclose(fp); + + if (err != len) + return AVERROR_UNKNOWN; + + return 0; +#else + return AVERROR(ENOSYS); +#endif +} + +static uint32_t get_generic_seed(void) +{ + uint64_t tmp[120/8]; + struct AVSHA *sha = (void*)tmp; + clock_t last_t = 0; + clock_t last_td = 0; + clock_t init_t = 0; + static uint64_t i = 0; + static uint32_t buffer[512] = { 0 }; + unsigned char digest[20]; + uint64_t last_i = i; + int repeats[3] = { 0 }; + + av_assert0(sizeof(tmp) >= av_sha_size); + + if(TEST){ + memset(buffer, 0, sizeof(buffer)); + last_i = i = 0; + }else{ +#ifdef AV_READ_TIME + buffer[13] ^= AV_READ_TIME(); + buffer[41] ^= AV_READ_TIME()>>32; +#endif + } + + for (;;) { + clock_t t = clock(); + int incremented_i = 0; + int cur_td = t - last_t; + if (last_t + 2*last_td + (CLOCKS_PER_SEC > 1000) < t) { + // If the timer incremented by more than 2*last_td at once, + // we may e.g. have had a context switch. If the timer resolution + // is high (CLOCKS_PER_SEC > 1000), require that the timer + // incremented by more than 1. If the timer resolution is low, + // it is enough that the timer incremented at all. + buffer[++i & 511] += cur_td % 3294638521U; + incremented_i = 1; + } else if (t != last_t && repeats[0] > 0 && repeats[1] > 0 && + repeats[2] > 0 && repeats[0] != repeats[1] && + repeats[0] != repeats[2]) { + // If the timer resolution is high, and we get the same timer + // value multiple times, use variances in the number of repeats + // of each timer value as entropy. If we get a different number of + // repeats than the last two unique cases, count that as entropy + // and proceed to the next index. + buffer[++i & 511] += (repeats[0] + repeats[1] + repeats[2]) % 3294638521U; + incremented_i = 1; + } else { + buffer[i & 511] = 1664525*buffer[i & 511] + 1013904223 + (cur_td % 3294638521U); + } + if (incremented_i && (t - init_t) >= CLOCKS_PER_SEC>>5) { + if (last_i && i - last_i > 4 || i - last_i > 64 || TEST && i - last_i > 8) + break; + } + if (t == last_t) { + repeats[0]++; + } else { + // If we got a new unique number of repeats, update the history. + if (repeats[0] != repeats[1]) { + repeats[2] = repeats[1]; + repeats[1] = repeats[0]; + } + repeats[0] = 0; + } + last_t = t; + last_td = cur_td; + if (!init_t) + init_t = t; + } + + if(TEST) { + buffer[0] = buffer[1] = 0; + } else { +#ifdef AV_READ_TIME + buffer[111] += AV_READ_TIME(); +#endif + } + + av_sha_init(sha, 160); + av_sha_update(sha, (const uint8_t *)buffer, sizeof(buffer)); + av_sha_final(sha, digest); + return AV_RB32(digest) + AV_RB32(digest + 16); +} + +int av_random_bytes(uint8_t* buf, size_t len) +{ + int err; + +#if HAVE_BCRYPT + BCRYPT_ALG_HANDLE algo_handle; + NTSTATUS ret = BCryptOpenAlgorithmProvider(&algo_handle, BCRYPT_RNG_ALGORITHM, + MS_PRIMITIVE_PROVIDER, 0); + if (BCRYPT_SUCCESS(ret)) { + NTSTATUS ret = BCryptGenRandom(algo_handle, (PUCHAR)buf, len, 0); + BCryptCloseAlgorithmProvider(algo_handle, 0); + if (BCRYPT_SUCCESS(ret)) + return 0; + } +#endif + +#if HAVE_ARC4RANDOM_BUF + arc4random_buf(buf, len); + return 0; +#endif + + err = read_random(buf, len, "/dev/urandom"); + if (!err) + return err; + +#if CONFIG_GCRYPT + gcry_randomize(buf, len, GCRY_VERY_STRONG_RANDOM); + return 0; +#elif CONFIG_OPENSSL + if (RAND_bytes(buf, len) == 1) + return 0; + return AVERROR_EXTERNAL; +#else + return err; +#endif +} + +uint32_t av_get_random_seed(void) +{ + uint32_t seed; + + if (av_random_bytes((uint8_t *)&seed, sizeof(seed)) < 0) + return get_generic_seed(); + + return seed; +} diff --git a/libs/ffmpeg/libavutil/random_seed.h b/libs/ffmpeg/libavutil/random_seed.h new file mode 100644 index 00000000000..8a47be96796 --- /dev/null +++ b/libs/ffmpeg/libavutil/random_seed.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009 Baptiste Coudurier <baptiste.coudurier@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RANDOM_SEED_H +#define AVUTIL_RANDOM_SEED_H + +#include <stddef.h> +#include <stdint.h> +/** + * @addtogroup lavu_crypto + * @{ + */ + +/** + * Get a seed to use in conjunction with random functions. + * This function tries to provide a good seed at a best effort bases. + * Its possible to call this function multiple times if more bits are needed. + * It can be quite slow, which is why it should only be used as seed for a faster + * PRNG. The quality of the seed depends on the platform. + */ +uint32_t av_get_random_seed(void); + +/** + * Generate cryptographically secure random data, i.e. suitable for use as + * encryption keys and similar. + * + * @param buf buffer into which the random data will be written + * @param len size of buf in bytes + * + * @retval 0 success, len bytes of random data was written + * into buf + * @retval "a negative AVERROR code" random data could not be generated + */ +int av_random_bytes(uint8_t *buf, size_t len); + +/** + * @} + */ + +#endif /* AVUTIL_RANDOM_SEED_H */ diff --git a/libs/ffmpeg/libavutil/rational.c b/libs/ffmpeg/libavutil/rational.c new file mode 100644 index 00000000000..1b7c6350e99 --- /dev/null +++ b/libs/ffmpeg/libavutil/rational.c @@ -0,0 +1,191 @@ +/* + * rational numbers + * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * rational numbers + * @author Michael Niedermayer <michaelni@gmx.at> + */ + +#include "avassert.h" +#include <limits.h> + +#include "common.h" +#include "mathematics.h" +#include "rational.h" + +int av_reduce(int *dst_num, int *dst_den, + int64_t num, int64_t den, int64_t max) +{ + AVRational a0 = { 0, 1 }, a1 = { 1, 0 }; + int sign = (num < 0) ^ (den < 0); + int64_t gcd = av_gcd(FFABS(num), FFABS(den)); + + if (gcd) { + num = FFABS(num) / gcd; + den = FFABS(den) / gcd; + } + if (num <= max && den <= max) { + a1 = (AVRational) { num, den }; + den = 0; + } + + while (den) { + uint64_t x = num / den; + int64_t next_den = num - den * x; + int64_t a2n = x * a1.num + a0.num; + int64_t a2d = x * a1.den + a0.den; + + if (a2n > max || a2d > max) { + if (a1.num) x = (max - a0.num) / a1.num; + if (a1.den) x = FFMIN(x, (max - a0.den) / a1.den); + + if (den * (2 * x * a1.den + a0.den) > num * a1.den) + a1 = (AVRational) { x * a1.num + a0.num, x * a1.den + a0.den }; + break; + } + + a0 = a1; + a1 = (AVRational) { a2n, a2d }; + num = den; + den = next_den; + } + av_assert2(av_gcd(a1.num, a1.den) <= 1U); + av_assert2(a1.num <= max && a1.den <= max); + + *dst_num = sign ? -a1.num : a1.num; + *dst_den = a1.den; + + return den == 0; +} + +AVRational av_mul_q(AVRational b, AVRational c) +{ + av_reduce(&b.num, &b.den, + b.num * (int64_t) c.num, + b.den * (int64_t) c.den, INT_MAX); + return b; +} + +AVRational av_div_q(AVRational b, AVRational c) +{ + return av_mul_q(b, (AVRational) { c.den, c.num }); +} + +AVRational av_add_q(AVRational b, AVRational c) { + av_reduce(&b.num, &b.den, + b.num * (int64_t) c.den + + c.num * (int64_t) b.den, + b.den * (int64_t) c.den, INT_MAX); + return b; +} + +AVRational av_sub_q(AVRational b, AVRational c) +{ + return av_add_q(b, (AVRational) { -c.num, c.den }); +} + +AVRational av_d2q(double d, int max) +{ + AVRational a; + int exponent; + int64_t den; + if (isnan(d)) + return (AVRational) { 0,0 }; + if (fabs(d) > INT_MAX + 3LL) + return (AVRational) { d < 0 ? -1 : 1, 0 }; + frexp(d, &exponent); + exponent = FFMAX(exponent-1, 0); + den = 1LL << (62 - exponent); + // (int64_t)rint() and llrint() do not work with gcc on ia64 and sparc64, + // see Ticket2713 for affected gcc/glibc versions + av_reduce(&a.num, &a.den, floor(d * den + 0.5), den, max); + + return a; +} + +int av_nearer_q(AVRational q, AVRational q1, AVRational q2) +{ + /* n/d is q, a/b is the median between q1 and q2 */ + int64_t a = q1.num * (int64_t)q2.den + q2.num * (int64_t)q1.den; + int64_t b = 2 * (int64_t)q1.den * q2.den; + + /* rnd_up(a*d/b) > n => a*d/b > n */ + int64_t x_up = av_rescale_rnd(a, q.den, b, AV_ROUND_UP); + + /* rnd_down(a*d/b) < n => a*d/b < n */ + int64_t x_down = av_rescale_rnd(a, q.den, b, AV_ROUND_DOWN); + + return ((x_up > q.num) - (x_down < q.num)) * av_cmp_q(q2, q1); +} + +int av_find_nearest_q_idx(AVRational q, const AVRational* q_list) +{ + int i, nearest_q_idx = 0; + for (i = 0; q_list[i].den; i++) + if (av_nearer_q(q, q_list[i], q_list[nearest_q_idx]) > 0) + nearest_q_idx = i; + + return nearest_q_idx; +} + +uint32_t av_q2intfloat(AVRational q) { + int64_t n; + int shift; + int sign = 0; + + if (q.den < 0) { + q.den *= -1; + q.num *= -1; + } + if (q.num < 0) { + q.num *= -1; + sign = 1; + } + + if (!q.num && !q.den) return 0xFFC00000; + if (!q.num) return 0; + if (!q.den) return 0x7F800000 | (q.num & 0x80000000); + + shift = 23 + av_log2(q.den) - av_log2(q.num); + if (shift >= 0) n = av_rescale(q.num, 1LL<<shift, q.den); + else n = av_rescale(q.num, 1, ((int64_t)q.den) << -shift); + + shift -= n >= (1<<24); + shift += n < (1<<23); + + if (shift >= 0) n = av_rescale(q.num, 1LL<<shift, q.den); + else n = av_rescale(q.num, 1, ((int64_t)q.den) << -shift); + + av_assert1(n < (1<<24)); + av_assert1(n >= (1<<23)); + + return sign<<31 | (150-shift)<<23 | (n - (1<<23)); +} + +AVRational av_gcd_q(AVRational a, AVRational b, int max_den, AVRational def) +{ + int64_t gcd, lcm; + + gcd = av_gcd(a.den, b.den); + lcm = (a.den / gcd) * b.den; + return lcm < max_den ? av_make_q(av_gcd(a.num, b.num), lcm) : def; +} diff --git a/libs/ffmpeg/libavutil/rational.h b/libs/ffmpeg/libavutil/rational.h new file mode 100644 index 00000000000..30ac2aced76 --- /dev/null +++ b/libs/ffmpeg/libavutil/rational.h @@ -0,0 +1,225 @@ +/* + * rational numbers + * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_math_rational + * Utilities for rational number calculation. + * @author Michael Niedermayer <michaelni@gmx.at> + */ + +#ifndef AVUTIL_RATIONAL_H +#define AVUTIL_RATIONAL_H + +#include <stdint.h> +#include <limits.h> +#include "attributes.h" + +/** + * @defgroup lavu_math_rational AVRational + * @ingroup lavu_math + * Rational number calculation. + * + * While rational numbers can be expressed as floating-point numbers, the + * conversion process is a lossy one, so are floating-point operations. On the + * other hand, the nature of FFmpeg demands highly accurate calculation of + * timestamps. This set of rational number utilities serves as a generic + * interface for manipulating rational numbers as pairs of numerators and + * denominators. + * + * Many of the functions that operate on AVRational's have the suffix `_q`, in + * reference to the mathematical symbol "ℚ" (Q) which denotes the set of all + * rational numbers. + * + * @{ + */ + +/** + * Rational number (pair of numerator and denominator). + */ +typedef struct AVRational{ + int num; ///< Numerator + int den; ///< Denominator +} AVRational; + +/** + * Create an AVRational. + * + * Useful for compilers that do not support compound literals. + * + * @note The return value is not reduced. + * @see av_reduce() + */ +static inline AVRational av_make_q(int num, int den) +{ + AVRational r = { num, den }; + return r; +} + +/** + * Compare two rationals. + * + * @param a First rational + * @param b Second rational + * + * @return One of the following values: + * - 0 if `a == b` + * - 1 if `a > b` + * - -1 if `a < b` + * - `INT_MIN` if one of the values is of the form `0 / 0` + */ +static inline int av_cmp_q(AVRational a, AVRational b){ + const int64_t tmp= a.num * (int64_t)b.den - b.num * (int64_t)a.den; + + if(tmp) return (int)((tmp ^ a.den ^ b.den)>>63)|1; + else if(b.den && a.den) return 0; + else if(a.num && b.num) return (a.num>>31) - (b.num>>31); + else return INT_MIN; +} + +/** + * Convert an AVRational to a `double`. + * @param a AVRational to convert + * @return `a` in floating-point form + * @see av_d2q() + */ +static inline double av_q2d(AVRational a){ + return a.num / (double) a.den; +} + +/** + * Reduce a fraction. + * + * This is useful for framerate calculations. + * + * @param[out] dst_num Destination numerator + * @param[out] dst_den Destination denominator + * @param[in] num Source numerator + * @param[in] den Source denominator + * @param[in] max Maximum allowed values for `dst_num` & `dst_den` + * @return 1 if the operation is exact, 0 otherwise + */ +int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max); + +/** + * Multiply two rationals. + * @param b First rational + * @param c Second rational + * @return b*c + */ +AVRational av_mul_q(AVRational b, AVRational c) av_const; + +/** + * Divide one rational by another. + * @param b First rational + * @param c Second rational + * @return b/c + */ +AVRational av_div_q(AVRational b, AVRational c) av_const; + +/** + * Add two rationals. + * @param b First rational + * @param c Second rational + * @return b+c + */ +AVRational av_add_q(AVRational b, AVRational c) av_const; + +/** + * Subtract one rational from another. + * @param b First rational + * @param c Second rational + * @return b-c + */ +AVRational av_sub_q(AVRational b, AVRational c) av_const; + +/** + * Invert a rational. + * @param q value + * @return 1 / q + */ +static av_always_inline AVRational av_inv_q(AVRational q) +{ + AVRational r = { q.den, q.num }; + return r; +} + +/** + * Convert a double precision floating point number to a rational. + * + * In case of infinity, the returned value is expressed as `{1, 0}` or + * `{-1, 0}` depending on the sign. + * + * In general rational numbers with |num| <= 1<<26 && |den| <= 1<<26 + * can be recovered exactly from their double representation. + * (no exceptions were found within 1B random ones) + * + * @param d `double` to convert + * @param max Maximum allowed numerator and denominator + * @return `d` in AVRational form + * @see av_q2d() + */ +AVRational av_d2q(double d, int max) av_const; + +/** + * Find which of the two rationals is closer to another rational. + * + * @param q Rational to be compared against + * @param q1 Rational to be tested + * @param q2 Rational to be tested + * @return One of the following values: + * - 1 if `q1` is nearer to `q` than `q2` + * - -1 if `q2` is nearer to `q` than `q1` + * - 0 if they have the same distance + */ +int av_nearer_q(AVRational q, AVRational q1, AVRational q2); + +/** + * Find the value in a list of rationals nearest a given reference rational. + * + * @param q Reference rational + * @param q_list Array of rationals terminated by `{0, 0}` + * @return Index of the nearest value found in the array + */ +int av_find_nearest_q_idx(AVRational q, const AVRational* q_list); + +/** + * Convert an AVRational to a IEEE 32-bit `float` expressed in fixed-point + * format. + * + * @param q Rational to be converted + * @return Equivalent floating-point value, expressed as an unsigned 32-bit + * integer. + * @note The returned value is platform-indepedant. + */ +uint32_t av_q2intfloat(AVRational q); + +/** + * Return the best rational so that a and b are multiple of it. + * If the resulting denominator is larger than max_den, return def. + */ +AVRational av_gcd_q(AVRational a, AVRational b, int max_den, AVRational def); + +/** + * @} + */ + +#endif /* AVUTIL_RATIONAL_H */ diff --git a/libs/ffmpeg/libavutil/rc4.c b/libs/ffmpeg/libavutil/rc4.c new file mode 100644 index 00000000000..74c1f4892e6 --- /dev/null +++ b/libs/ffmpeg/libavutil/rc4.c @@ -0,0 +1,66 @@ +/* + * RC4 encryption/decryption/pseudo-random number generator + * Copyright (c) 2007 Reimar Doeffinger + * + * loosely based on LibTomCrypt by Tom St Denis + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "error.h" +#include "macros.h" +#include "mem.h" +#include "rc4.h" + +AVRC4 *av_rc4_alloc(void) +{ + return av_mallocz(sizeof(struct AVRC4)); +} + +int av_rc4_init(AVRC4 *r, const uint8_t *key, int key_bits, int decrypt) { + int i, j; + uint8_t y; + uint8_t *state = r->state; + int keylen = key_bits >> 3; + if (key_bits & 7) + return AVERROR(EINVAL); + for (i = 0; i < 256; i++) + state[i] = i; + y = 0; + // j is i % keylen + for (j = 0, i = 0; i < 256; i++, j++) { + if (j == keylen) j = 0; + y += state[i] + key[j]; + FFSWAP(uint8_t, state[i], state[y]); + } + r->x = 1; + r->y = state[1]; + return 0; +} + +void av_rc4_crypt(AVRC4 *r, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt) { + uint8_t x = r->x, y = r->y; + uint8_t *state = r->state; + while (count-- > 0) { + uint8_t sum = state[x] + state[y]; + FFSWAP(uint8_t, state[x], state[y]); + *dst++ = src ? *src++ ^ state[sum] : state[sum]; + x++; + y += state[x]; + } + r->x = x; r->y = y; +} diff --git a/libs/ffmpeg/libavutil/rc4.h b/libs/ffmpeg/libavutil/rc4.h new file mode 100644 index 00000000000..0c72a88ecd7 --- /dev/null +++ b/libs/ffmpeg/libavutil/rc4.h @@ -0,0 +1,69 @@ +/* + * RC4 encryption/decryption/pseudo-random number generator + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RC4_H +#define AVUTIL_RC4_H + +#include <stdint.h> + +/** + * @defgroup lavu_rc4 RC4 + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVRC4 { + uint8_t state[256]; + int x, y; +} AVRC4; + +/** + * Allocate an AVRC4 context. + */ +AVRC4 *av_rc4_alloc(void); + +/** + * @brief Initializes an AVRC4 context. + * + * @param d pointer to the AVRC4 context + * @param key buffer containing the key + * @param key_bits must be a multiple of 8 + * @param decrypt 0 for encryption, 1 for decryption, currently has no effect + * @return zero on success, negative value otherwise + */ +int av_rc4_init(struct AVRC4 *d, const uint8_t *key, int key_bits, int decrypt); + +/** + * @brief Encrypts / decrypts using the RC4 algorithm. + * + * @param d pointer to the AVRC4 context + * @param count number of bytes + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst, may be NULL + * @param iv not (yet) used for RC4, should be NULL + * @param decrypt 0 for encryption, 1 for decryption, not (yet) used + */ +void av_rc4_crypt(struct AVRC4 *d, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_RC4_H */ diff --git a/libs/ffmpeg/libavutil/refstruct.c b/libs/ffmpeg/libavutil/refstruct.c new file mode 100644 index 00000000000..7a5eb248266 --- /dev/null +++ b/libs/ffmpeg/libavutil/refstruct.c @@ -0,0 +1,386 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdatomic.h> +#include <stdint.h> +#include <string.h> + +#include "refstruct.h" + +#include "avassert.h" +#include "error.h" +#include "macros.h" +#include "mem.h" +#include "mem_internal.h" +#include "thread.h" + +#ifndef REFSTRUCT_CHECKED +#ifndef ASSERT_LEVEL +#define ASSERT_LEVEL 0 +#endif +#define REFSTRUCT_CHECKED (ASSERT_LEVEL >= 1) +#endif + +#if REFSTRUCT_CHECKED +#define ff_assert(cond) av_assert0(cond) +#else +#define ff_assert(cond) ((void)0) +#endif + +#define REFSTRUCT_COOKIE AV_NE((uint64_t)MKBETAG('R', 'e', 'f', 'S') << 32 | MKBETAG('t', 'r', 'u', 'c'), \ + MKTAG('R', 'e', 'f', 'S') | (uint64_t)MKTAG('t', 'r', 'u', 'c') << 32) + +#ifndef _MSC_VER +#define REFCOUNT_OFFSET FFALIGN(sizeof(RefCount), FFMAX(ALIGN_64, _Alignof(max_align_t))) +#else +#define REFCOUNT_OFFSET FFALIGN(sizeof(RefCount), ALIGN_64) +#endif + +typedef struct RefCount { + /** + * An uintptr_t is big enough to hold the address of every reference, + * so no overflow can happen when incrementing the refcount as long as + * the user does not throw away references. + */ + atomic_uintptr_t refcount; + AVRefStructOpaque opaque; + void (*free_cb)(AVRefStructOpaque opaque, void *obj); + void (*free)(void *ref); + +#if REFSTRUCT_CHECKED + uint64_t cookie; +#endif +} RefCount; + +static RefCount *get_refcount(void *obj) +{ + RefCount *ref = (RefCount*)((char*)obj - REFCOUNT_OFFSET); + ff_assert(ref->cookie == REFSTRUCT_COOKIE); + return ref; +} + +static const RefCount *cget_refcount(const void *obj) +{ + const RefCount *ref = (const RefCount*)((const char*)obj - REFCOUNT_OFFSET); + ff_assert(ref->cookie == REFSTRUCT_COOKIE); + return ref; +} + +static void *get_userdata(void *buf) +{ + return (char*)buf + REFCOUNT_OFFSET; +} + +static void refcount_init(RefCount *ref, AVRefStructOpaque opaque, + void (*free_cb)(AVRefStructOpaque opaque, void *obj)) +{ + atomic_init(&ref->refcount, 1); + ref->opaque = opaque; + ref->free_cb = free_cb; + ref->free = av_free; + +#if REFSTRUCT_CHECKED + ref->cookie = REFSTRUCT_COOKIE; +#endif +} + +void *av_refstruct_alloc_ext_c(size_t size, unsigned flags, AVRefStructOpaque opaque, + void (*free_cb)(AVRefStructOpaque opaque, void *obj)) +{ + void *buf, *obj; + + if (size > SIZE_MAX - REFCOUNT_OFFSET) + return NULL; + buf = av_malloc(size + REFCOUNT_OFFSET); + if (!buf) + return NULL; + refcount_init(buf, opaque, free_cb); + obj = get_userdata(buf); + if (!(flags & AV_REFSTRUCT_FLAG_NO_ZEROING)) + memset(obj, 0, size); + + return obj; +} + +void av_refstruct_unref(void *objp) +{ + void *obj; + RefCount *ref; + + memcpy(&obj, objp, sizeof(obj)); + if (!obj) + return; + memcpy(objp, &(void *){ NULL }, sizeof(obj)); + + ref = get_refcount(obj); + if (atomic_fetch_sub_explicit(&ref->refcount, 1, memory_order_acq_rel) == 1) { + if (ref->free_cb) + ref->free_cb(ref->opaque, obj); + ref->free(ref); + } + + return; +} + +void *av_refstruct_ref(void *obj) +{ + RefCount *ref = get_refcount(obj); + + atomic_fetch_add_explicit(&ref->refcount, 1, memory_order_relaxed); + + return obj; +} + +const void *av_refstruct_ref_c(const void *obj) +{ + /* Casting const away here is fine, as it is only supposed + * to apply to the user's data and not our bookkeeping data. */ + RefCount *ref = get_refcount((void*)obj); + + atomic_fetch_add_explicit(&ref->refcount, 1, memory_order_relaxed); + + return obj; +} + +void av_refstruct_replace(void *dstp, const void *src) +{ + const void *dst; + memcpy(&dst, dstp, sizeof(dst)); + + if (src == dst) + return; + av_refstruct_unref(dstp); + if (src) { + dst = av_refstruct_ref_c(src); + memcpy(dstp, &dst, sizeof(dst)); + } +} + +int av_refstruct_exclusive(const void *obj) +{ + const RefCount *ref = cget_refcount(obj); + /* Casting const away here is safe, because it is a load. + * It is necessary because atomic_load_explicit() does not + * accept const atomics in C11 (see also N1807). */ + return atomic_load_explicit((atomic_uintptr_t*)&ref->refcount, memory_order_acquire) == 1; +} + +struct AVRefStructPool { + size_t size; + AVRefStructOpaque opaque; + int (*init_cb)(AVRefStructOpaque opaque, void *obj); + void (*reset_cb)(AVRefStructOpaque opaque, void *obj); + void (*free_entry_cb)(AVRefStructOpaque opaque, void *obj); + void (*free_cb)(AVRefStructOpaque opaque); + + int uninited; + unsigned entry_flags; + unsigned pool_flags; + + /** The number of outstanding entries not in available_entries. */ + atomic_uintptr_t refcount; + /** + * This is a linked list of available entries; + * the RefCount's opaque pointer is used as next pointer + * for available entries. + * While the entries are in use, the opaque is a pointer + * to the corresponding AVRefStructPool. + */ + RefCount *available_entries; + AVMutex mutex; +}; + +static void pool_free(AVRefStructPool *pool) +{ + ff_mutex_destroy(&pool->mutex); + if (pool->free_cb) + pool->free_cb(pool->opaque); + av_free(get_refcount(pool)); +} + +static void pool_free_entry(AVRefStructPool *pool, RefCount *ref) +{ + if (pool->free_entry_cb) + pool->free_entry_cb(pool->opaque, get_userdata(ref)); + av_free(ref); +} + +static void pool_return_entry(void *ref_) +{ + RefCount *ref = ref_; + AVRefStructPool *pool = ref->opaque.nc; + + ff_mutex_lock(&pool->mutex); + if (!pool->uninited) { + ref->opaque.nc = pool->available_entries; + pool->available_entries = ref; + ref = NULL; + } + ff_mutex_unlock(&pool->mutex); + + if (ref) + pool_free_entry(pool, ref); + + if (atomic_fetch_sub_explicit(&pool->refcount, 1, memory_order_acq_rel) == 1) + pool_free(pool); +} + +static void pool_reset_entry(AVRefStructOpaque opaque, void *entry) +{ + AVRefStructPool *pool = opaque.nc; + + pool->reset_cb(pool->opaque, entry); +} + +static int refstruct_pool_get_ext(void *datap, AVRefStructPool *pool) +{ + void *ret = NULL; + + memcpy(datap, &(void *){ NULL }, sizeof(void*)); + + ff_mutex_lock(&pool->mutex); + ff_assert(!pool->uninited); + if (pool->available_entries) { + RefCount *ref = pool->available_entries; + ret = get_userdata(ref); + pool->available_entries = ref->opaque.nc; + ref->opaque.nc = pool; + atomic_init(&ref->refcount, 1); + } + ff_mutex_unlock(&pool->mutex); + + if (!ret) { + RefCount *ref; + ret = av_refstruct_alloc_ext(pool->size, pool->entry_flags, pool, + pool->reset_cb ? pool_reset_entry : NULL); + if (!ret) + return AVERROR(ENOMEM); + ref = get_refcount(ret); + ref->free = pool_return_entry; + if (pool->init_cb) { + int err = pool->init_cb(pool->opaque, ret); + if (err < 0) { + if (pool->pool_flags & AV_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR) + pool->reset_cb(pool->opaque, ret); + if (pool->pool_flags & AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR) + pool->free_entry_cb(pool->opaque, ret); + av_free(ref); + return err; + } + } + } + atomic_fetch_add_explicit(&pool->refcount, 1, memory_order_relaxed); + + if (pool->pool_flags & AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME) + memset(ret, 0, pool->size); + + memcpy(datap, &ret, sizeof(ret)); + + return 0; +} + +void *av_refstruct_pool_get(AVRefStructPool *pool) +{ + void *ret; + refstruct_pool_get_ext(&ret, pool); + return ret; +} + +/** + * Hint: The content of pool_unref() and refstruct_pool_uninit() + * could currently be merged; they are only separate functions + * in case we would ever introduce weak references. + */ +static void pool_unref(void *ref) +{ + AVRefStructPool *pool = get_userdata(ref); + if (atomic_fetch_sub_explicit(&pool->refcount, 1, memory_order_acq_rel) == 1) + pool_free(pool); +} + +static void refstruct_pool_uninit(AVRefStructOpaque unused, void *obj) +{ + AVRefStructPool *pool = obj; + RefCount *entry; + + ff_mutex_lock(&pool->mutex); + ff_assert(!pool->uninited); + pool->uninited = 1; + entry = pool->available_entries; + pool->available_entries = NULL; + ff_mutex_unlock(&pool->mutex); + + while (entry) { + void *next = entry->opaque.nc; + pool_free_entry(pool, entry); + entry = next; + } +} + +AVRefStructPool *av_refstruct_pool_alloc(size_t size, unsigned flags) +{ + return av_refstruct_pool_alloc_ext(size, flags, NULL, NULL, NULL, NULL, NULL); +} + +AVRefStructPool *av_refstruct_pool_alloc_ext_c(size_t size, unsigned flags, + AVRefStructOpaque opaque, + int (*init_cb)(AVRefStructOpaque opaque, void *obj), + void (*reset_cb)(AVRefStructOpaque opaque, void *obj), + void (*free_entry_cb)(AVRefStructOpaque opaque, void *obj), + void (*free_cb)(AVRefStructOpaque opaque)) +{ + AVRefStructPool *pool = av_refstruct_alloc_ext(sizeof(*pool), 0, NULL, + refstruct_pool_uninit); + int err; + + if (!pool) + return NULL; + get_refcount(pool)->free = pool_unref; + + pool->size = size; + pool->opaque = opaque; + pool->init_cb = init_cb; + pool->reset_cb = reset_cb; + pool->free_entry_cb = free_entry_cb; + pool->free_cb = free_cb; +#define COMMON_FLAGS AV_REFSTRUCT_POOL_FLAG_NO_ZEROING + pool->entry_flags = flags & COMMON_FLAGS; + // Filter out nonsense combinations to avoid checks later. + if (!pool->reset_cb) + flags &= ~AV_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR; + if (!pool->free_entry_cb) + flags &= ~AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR; + pool->pool_flags = flags; + + if (flags & AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME) { + // We will zero the buffer before every use, so zeroing + // upon allocating the buffer is unnecessary. + pool->entry_flags |= AV_REFSTRUCT_FLAG_NO_ZEROING; + } + + atomic_init(&pool->refcount, 1); + + err = ff_mutex_init(&pool->mutex, NULL); + if (err) { + // Don't call av_refstruct_uninit() on pool, as it hasn't been properly + // set up and is just a POD right now. + av_free(get_refcount(pool)); + return NULL; + } + return pool; +} diff --git a/libs/ffmpeg/libavutil/refstruct.h b/libs/ffmpeg/libavutil/refstruct.h new file mode 100644 index 00000000000..4e9d78eb0ad --- /dev/null +++ b/libs/ffmpeg/libavutil/refstruct.h @@ -0,0 +1,297 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_REFSTRUCT_H +#define AVUTIL_REFSTRUCT_H + +#include <stddef.h> + +/** + * RefStruct is an API for creating reference-counted objects + * with minimal overhead. The API is designed for objects, + * not buffers like the AVBuffer API. The main differences + * to the AVBuffer API are as follows: + * + * - It uses void* instead of uint8_t* as its base type due to + * its focus on objects. + * - There are no equivalents of AVBuffer and AVBufferRef. + * E.g. there is no way to get the usable size of the object: + * The user is supposed to know what is at the other end of + * the pointer. It also avoids one level of indirection. + * - Custom allocators are not supported. This allows to simplify + * the implementation and reduce the amount of allocations. + * - It also has the advantage that the user's free callback need + * only free the resources owned by the object, but not the + * object itself. + * - Because referencing (and replacing) an object managed by the + * RefStruct API does not involve allocations, they can not fail + * and therefore need not be checked. + * + * @note Referencing and unreferencing the buffers is thread-safe and thus + * may be done from multiple threads simultaneously without any need for + * additional locking. + */ + +/** + * This union is used for all opaque parameters in this API to spare the user + * to cast const away in case the opaque to use is const-qualified. + * + * The functions provided by this API with an AVRefStructOpaque come in pairs + * named foo_c and foo. The foo function accepts void* as opaque and is just + * a wrapper around the foo_c function; "_c" means "(potentially) const". + */ +typedef union { + void *nc; + const void *c; +} AVRefStructOpaque; + +/** + * If this flag is set in av_refstruct_alloc_ext_c(), the object will not + * be initially zeroed. + */ +#define AV_REFSTRUCT_FLAG_NO_ZEROING (1 << 0) + +/** + * Allocate a refcounted object of usable size `size` managed via + * the RefStruct API. + * + * By default (in the absence of flags to the contrary), + * the returned object is initially zeroed. + * + * @param size Desired usable size of the returned object. + * @param flags A bitwise combination of AV_REFSTRUCT_FLAG_* flags. + * @param opaque A pointer that will be passed to the free_cb callback. + * @param free_cb A callback for freeing this object's content + * when its reference count reaches zero; + * it must not free the object itself. + * @return A pointer to an object of the desired size or NULL on failure. + */ +void *av_refstruct_alloc_ext_c(size_t size, unsigned flags, AVRefStructOpaque opaque, + void (*free_cb)(AVRefStructOpaque opaque, void *obj)); + +/** + * A wrapper around av_refstruct_alloc_ext_c() for the common case + * of a non-const qualified opaque. + * + * @see av_refstruct_alloc_ext_c() + */ +static inline +void *av_refstruct_alloc_ext(size_t size, unsigned flags, void *opaque, + void (*free_cb)(AVRefStructOpaque opaque, void *obj)) +{ + return av_refstruct_alloc_ext_c(size, flags, (AVRefStructOpaque){.nc = opaque}, + free_cb); +} + +/** + * Equivalent to av_refstruct_alloc_ext(size, 0, NULL, NULL) + */ +static inline +void *av_refstruct_allocz(size_t size) +{ + return av_refstruct_alloc_ext(size, 0, NULL, NULL); +} + +/** + * Decrement the reference count of the underlying object and automatically + * free the object if there are no more references to it. + * + * `*objp == NULL` is legal and a no-op. + * + * @param objp Pointer to a pointer that is either NULL or points to an object + * managed via this API. `*objp` is set to NULL on return. + */ +void av_refstruct_unref(void *objp); + +/** + * Create a new reference to an object managed via this API, + * i.e. increment the reference count of the underlying object + * and return obj. + * @return a pointer equal to obj. + */ +void *av_refstruct_ref(void *obj); + +/** + * Analog of av_refstruct_ref(), but for constant objects. + * @see av_refstruct_ref() + */ +const void *av_refstruct_ref_c(const void *obj); + +/** + * Ensure `*dstp` refers to the same object as src. + * + * If `*dstp` is already equal to src, do nothing. Otherwise unreference `*dstp` + * and replace it with a new reference to src in case `src != NULL` (this + * involves incrementing the reference count of src's underlying object) or + * with NULL otherwise. + * + * @param dstp Pointer to a pointer that is either NULL or points to an object + * managed via this API. + * @param src A pointer to an object managed via this API or NULL. + */ +void av_refstruct_replace(void *dstp, const void *src); + +/** + * Check whether the reference count of an object managed + * via this API is 1. + * + * @param obj A pointer to an object managed via this API. + * @return 1 if the reference count of obj is 1; 0 otherwise. + */ +int av_refstruct_exclusive(const void *obj); + +/** + * AVRefStructPool is an API for a thread-safe pool of objects managed + * via the RefStruct API. + * + * Frequently allocating and freeing large or complicated objects may be slow + * and wasteful. This API is meant to solve this in cases when the caller + * needs a set of interchangeable objects. + * + * At the beginning, the user must call allocate the pool via + * av_refstruct_pool_alloc() or its analogue av_refstruct_pool_alloc_ext(). + * Then whenever an object is needed, call av_refstruct_pool_get() to + * get a new or reused object from the pool. This new object works in all + * aspects the same way as the ones created by av_refstruct_alloc_ext(). + * However, when the last reference to this object is unreferenced, it is + * (optionally) reset and returned to the pool instead of being freed and + * will be reused for subsequent av_refstruct_pool_get() calls. + * + * When the caller is done with the pool and no longer needs to create any new + * objects, av_refstruct_pool_uninit() must be called to mark the pool as + * freeable. Then entries returned to the pool will then be freed. + * Once all the entries are freed, the pool will automatically be freed. + * + * Allocating and releasing objects with this API is thread-safe as long as + * the user-supplied callbacks (if provided) are thread-safe. + */ + +/** + * The buffer pool. This structure is opaque and not meant to be accessed + * directly. It is allocated with the allocators below and freed with + * av_refstruct_pool_uninit(). + */ +typedef struct AVRefStructPool AVRefStructPool; + +/** + * If this flag is not set, every object in the pool will be zeroed before + * the init callback is called or before it is turned over to the user + * for the first time if no init callback has been provided. + */ +#define AV_REFSTRUCT_POOL_FLAG_NO_ZEROING AV_REFSTRUCT_FLAG_NO_ZEROING +/** + * If this flag is set and both init_cb and reset_cb callbacks are provided, + * then reset_cb will be called if init_cb fails. + * The object passed to reset_cb will be in the state left by init_cb. + */ +#define AV_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR (1 << 16) +/** + * If this flag is set and both init_cb and free_entry_cb callbacks are + * provided, then free_cb will be called if init_cb fails. + * + * It will be called after reset_cb in case reset_cb and the + * AV_REFSTRUCT_POOL_FLAG_RESET_ON_INIT_ERROR flag are also set. + * + * The object passed to free_cb will be in the state left by + * the callbacks applied earlier (init_cb potentially followed by reset_cb). + */ +#define AV_REFSTRUCT_POOL_FLAG_FREE_ON_INIT_ERROR (1 << 17) +/** + * If this flag is set, the entries will be zeroed before + * being returned to the user (after the init or reset callbacks + * have been called (if provided)). Furthermore, to avoid zeroing twice + * it also makes the pool behave as if the AV_REFSTRUCT_POOL_FLAG_NO_ZEROING + * flag had been provided. + */ +#define AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME (1 << 18) + +/** + * Equivalent to av_refstruct_pool_alloc(size, flags, NULL, NULL, NULL, NULL, NULL) + */ +AVRefStructPool *av_refstruct_pool_alloc(size_t size, unsigned flags); + +/** + * Allocate an AVRefStructPool, potentially using complex callbacks. + * + * @param size size of the entries of the pool + * @param flags a bitwise combination of AV_REFSTRUCT_POOL_FLAG_* flags + * @param opaque A pointer that will be passed to the callbacks below. + * @param init A callback that will be called directly after a new entry + * has been allocated. obj has already been zeroed unless + * the AV_REFSTRUCT_POOL_FLAG_NO_ZEROING flag is in use. + * @param reset A callback that will be called after an entry has been + * returned to the pool and before it is reused. + * @param free_entry A callback that will be called when an entry is freed + * after the pool has been marked as to be uninitialized. + * @param free A callback that will be called when the pool itself is + * freed (after the last entry has been returned and freed). + */ +AVRefStructPool *av_refstruct_pool_alloc_ext_c(size_t size, unsigned flags, + AVRefStructOpaque opaque, + int (*init_cb)(AVRefStructOpaque opaque, void *obj), + void (*reset_cb)(AVRefStructOpaque opaque, void *obj), + void (*free_entry_cb)(AVRefStructOpaque opaque, void *obj), + void (*free_cb)(AVRefStructOpaque opaque)); + +/** + * A wrapper around av_refstruct_pool_alloc_ext_c() for the common case + * of a non-const qualified opaque. + * + * @see av_refstruct_pool_alloc_ext_c() + */ +static inline +AVRefStructPool *av_refstruct_pool_alloc_ext(size_t size, unsigned flags, + void *opaque, + int (*init_cb)(AVRefStructOpaque opaque, void *obj), + void (*reset_cb)(AVRefStructOpaque opaque, void *obj), + void (*free_entry_cb)(AVRefStructOpaque opaque, void *obj), + void (*free_cb)(AVRefStructOpaque opaque)) +{ + return av_refstruct_pool_alloc_ext_c(size, flags, (AVRefStructOpaque){.nc = opaque}, + init_cb, reset_cb, free_entry_cb, free_cb); +} + +/** + * Get an object from the pool, reusing an old one from the pool when + * available. + * + * Every call to this function must happen before av_refstruct_pool_uninit(). + * Otherwise undefined behaviour may occur. + * + * @param pool the pool from which to get the object + * @return a reference to the object on success, NULL on error. + */ +void *av_refstruct_pool_get(AVRefStructPool *pool); + +/** + * Mark the pool as being available for freeing. It will actually be freed + * only once all the allocated buffers associated with the pool are released. + * Thus it is safe to call this function while some of the allocated buffers + * are still in use. + * + * It is illegal to try to get a new entry after this function has been called. + * + * @param poolp pointer to a pointer to either NULL or a pool to be freed. + * `*poolp` will be set to NULL. + */ +static inline void av_refstruct_pool_uninit(AVRefStructPool **poolp) +{ + av_refstruct_unref(poolp); +} + +#endif /* AVUTIL_REFSTRUCT_H */ diff --git a/libs/ffmpeg/libavutil/reverse.c b/libs/ffmpeg/libavutil/reverse.c new file mode 100644 index 00000000000..105eb03dda4 --- /dev/null +++ b/libs/ffmpeg/libavutil/reverse.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdint.h> + +const uint8_t ff_reverse[256] = { +0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, +0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, +0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, +0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, +0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, +0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, +0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, +0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, +0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, +0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, +0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, +0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, +0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, +0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, +0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, +0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF, +}; diff --git a/libs/ffmpeg/libavutil/reverse.h b/libs/ffmpeg/libavutil/reverse.h new file mode 100644 index 00000000000..4eb61239328 --- /dev/null +++ b/libs/ffmpeg/libavutil/reverse.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_REVERSE_H +#define AVUTIL_REVERSE_H + +#include <stdint.h> + +extern const uint8_t ff_reverse[256]; + +#endif /* AVUTIL_REVERSE_H */ diff --git a/libs/ffmpeg/libavutil/ripemd.c b/libs/ffmpeg/libavutil/ripemd.c new file mode 100644 index 00000000000..e3104efc9fa --- /dev/null +++ b/libs/ffmpeg/libavutil/ripemd.c @@ -0,0 +1,559 @@ +/* + * Copyright (C) 2007 Michael Niedermayer <michaelni@gmx.at> + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stddef.h> +#include <string.h> + +#include "config.h" +#include "attributes.h" +#include "bswap.h" +#include "error.h" +#include "intreadwrite.h" +#include "macros.h" +#include "ripemd.h" +#include "mem.h" + +/** hash context */ +typedef struct AVRIPEMD { + uint8_t digest_len; ///< digest length in 32-bit words + uint64_t count; ///< number of bytes in buffer + uint8_t buffer[64]; ///< 512-bit buffer of input values used in hash updating + uint32_t state[10]; ///< current hash value + /** function used to update hash for 512-bit input block */ + void (*transform)(uint32_t *state, const uint8_t buffer[64]); +} AVRIPEMD; + +const int av_ripemd_size = sizeof(AVRIPEMD); + +struct AVRIPEMD *av_ripemd_alloc(void) +{ + return av_mallocz(sizeof(struct AVRIPEMD)); +} + +static const uint32_t KA[4] = { + 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e +}; + +static const uint32_t KB[4] = { + 0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9 +}; + +static const int ROTA[80] = { + 11, 14, 15, 12, 5, 8, 7 , 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7 , 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 +}; + +static const int ROTB[80] = { + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 +}; + +static const int WA[80] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 +}; + +static const int WB[80] = { + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 +}; + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +#define ROUND128_0_TO_15(a,b,c,d,e,f,g,h) \ + a = rol(a + (( b ^ c ^ d) + block[WA[n]]), ROTA[n]); \ + e = rol(e + ((((f ^ g) & h) ^ g) + block[WB[n]] + KB[0]), ROTB[n]); \ + n++ + +#define ROUND128_16_TO_31(a,b,c,d,e,f,g,h) \ + a = rol(a + ((((c ^ d) & b) ^ d) + block[WA[n]] + KA[0]), ROTA[n]); \ + e = rol(e + (((~g | f) ^ h) + block[WB[n]] + KB[1]), ROTB[n]); \ + n++ + +#define ROUND128_32_TO_47(a,b,c,d,e,f,g,h) \ + a = rol(a + (((~c | b) ^ d) + block[WA[n]] + KA[1]), ROTA[n]); \ + e = rol(e + ((((g ^ h) & f) ^ h) + block[WB[n]] + KB[2]), ROTB[n]); \ + n++ + +#define ROUND128_48_TO_63(a,b,c,d,e,f,g,h) \ + a = rol(a + ((((b ^ c) & d) ^ c) + block[WA[n]] + KA[2]), ROTA[n]); \ + e = rol(e + (( f ^ g ^ h) + block[WB[n]]), ROTB[n]); \ + n++ + +#define R128_0 \ + ROUND128_0_TO_15(a,b,c,d,e,f,g,h); \ + ROUND128_0_TO_15(d,a,b,c,h,e,f,g); \ + ROUND128_0_TO_15(c,d,a,b,g,h,e,f); \ + ROUND128_0_TO_15(b,c,d,a,f,g,h,e) + +#define R128_16 \ + ROUND128_16_TO_31(a,b,c,d,e,f,g,h); \ + ROUND128_16_TO_31(d,a,b,c,h,e,f,g); \ + ROUND128_16_TO_31(c,d,a,b,g,h,e,f); \ + ROUND128_16_TO_31(b,c,d,a,f,g,h,e) + +#define R128_32 \ + ROUND128_32_TO_47(a,b,c,d,e,f,g,h); \ + ROUND128_32_TO_47(d,a,b,c,h,e,f,g); \ + ROUND128_32_TO_47(c,d,a,b,g,h,e,f); \ + ROUND128_32_TO_47(b,c,d,a,f,g,h,e) + +#define R128_48 \ + ROUND128_48_TO_63(a,b,c,d,e,f,g,h); \ + ROUND128_48_TO_63(d,a,b,c,h,e,f,g); \ + ROUND128_48_TO_63(c,d,a,b,g,h,e,f); \ + ROUND128_48_TO_63(b,c,d,a,f,g,h,e) + +static void ripemd128_transform(uint32_t *state, const uint8_t buffer[64]) +{ + uint32_t a, b, c, d, e, f, g, h, t av_unused; + uint32_t block[16]; + int n; + + a = e = state[0]; + b = f = state[1]; + c = g = state[2]; + d = h = state[3]; + + for (n = 0; n < 16; n++) + block[n] = AV_RL32(buffer + 4 * n); + n = 0; + +#if CONFIG_SMALL + for (; n < 16;) { + ROUND128_0_TO_15(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + + for (; n < 32;) { + ROUND128_16_TO_31(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + + for (; n < 48;) { + ROUND128_32_TO_47(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + + for (; n < 64;) { + ROUND128_48_TO_63(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } +#else + + R128_0; R128_0; R128_0; R128_0; + + R128_16; R128_16; R128_16; R128_16; + + R128_32; R128_32; R128_32; R128_32; + + R128_48; R128_48; R128_48; R128_48; +#endif + + h += c + state[1]; + state[1] = state[2] + d + e; + state[2] = state[3] + a + f; + state[3] = state[0] + b + g; + state[0] = h; +} + +static void ripemd256_transform(uint32_t *state, const uint8_t buffer[64]) +{ + uint32_t a, b, c, d, e, f, g, h, t av_unused; + uint32_t block[16]; + int n; + + a = state[0]; b = state[1]; c = state[2]; d = state[3]; + e = state[4]; f = state[5]; g = state[6]; h = state[7]; + + for (n = 0; n < 16; n++) + block[n] = AV_RL32(buffer + 4 * n); + n = 0; + +#if CONFIG_SMALL + for (; n < 16;) { + ROUND128_0_TO_15(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + FFSWAP(uint32_t, a, e); + + for (; n < 32;) { + ROUND128_16_TO_31(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + FFSWAP(uint32_t, b, f); + + for (; n < 48;) { + ROUND128_32_TO_47(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + FFSWAP(uint32_t, c, g); + + for (; n < 64;) { + ROUND128_48_TO_63(a,b,c,d,e,f,g,h); + t = d; d = c; c = b; b = a; a = t; + t = h; h = g; g = f; f = e; e = t; + } + FFSWAP(uint32_t, d, h); +#else + + R128_0; R128_0; R128_0; R128_0; + FFSWAP(uint32_t, a, e); + + R128_16; R128_16; R128_16; R128_16; + FFSWAP(uint32_t, b, f); + + R128_32; R128_32; R128_32; R128_32; + FFSWAP(uint32_t, c, g); + + R128_48; R128_48; R128_48; R128_48; + FFSWAP(uint32_t, d, h); +#endif + + state[0] += a; state[1] += b; state[2] += c; state[3] += d; + state[4] += e; state[5] += f; state[6] += g; state[7] += h; +} + +#define ROTATE(x,y) \ + x = rol(x, 10); \ + y = rol(y, 10); \ + n++ + +#define ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j) \ + a = rol(a + (( b ^ c ^ d) + block[WA[n]]), ROTA[n]) + e; \ + f = rol(f + (((~i | h) ^ g) + block[WB[n]] + KB[0]), ROTB[n]) + j; \ + ROTATE(c,h) + +#define ROUND160_16_TO_31(a,b,c,d,e,f,g,h,i,j) \ + a = rol(a + ((((c ^ d) & b) ^ d) + block[WA[n]] + KA[0]), ROTA[n]) + e; \ + f = rol(f + ((((g ^ h) & i) ^ h) + block[WB[n]] + KB[1]), ROTB[n]) + j; \ + ROTATE(c,h) + +#define ROUND160_32_TO_47(a,b,c,d,e,f,g,h,i,j) \ + a = rol(a + (((~c | b) ^ d) + block[WA[n]] + KA[1]), ROTA[n]) + e; \ + f = rol(f + (((~h | g) ^ i) + block[WB[n]] + KB[2]), ROTB[n]) + j; \ + ROTATE(c,h) + +#define ROUND160_48_TO_63(a,b,c,d,e,f,g,h,i,j) \ + a = rol(a + ((((b ^ c) & d) ^ c) + block[WA[n]] + KA[2]), ROTA[n]) + e; \ + f = rol(f + ((((h ^ i) & g) ^ i) + block[WB[n]] + KB[3]), ROTB[n]) + j; \ + ROTATE(c,h) + +#define ROUND160_64_TO_79(a,b,c,d,e,f,g,h,i,j) \ + a = rol(a + (((~d | c) ^ b) + block[WA[n]] + KA[3]), ROTA[n]) + e; \ + f = rol(f + (( g ^ h ^ i) + block[WB[n]]), ROTB[n]) + j; \ + ROTATE(c,h) + +#define R160_0 \ + ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j); \ + ROUND160_0_TO_15(e,a,b,c,d,j,f,g,h,i); \ + ROUND160_0_TO_15(d,e,a,b,c,i,j,f,g,h); \ + ROUND160_0_TO_15(c,d,e,a,b,h,i,j,f,g); \ + ROUND160_0_TO_15(b,c,d,e,a,g,h,i,j,f) + +#define R160_16 \ + ROUND160_16_TO_31(e,a,b,c,d,j,f,g,h,i); \ + ROUND160_16_TO_31(d,e,a,b,c,i,j,f,g,h); \ + ROUND160_16_TO_31(c,d,e,a,b,h,i,j,f,g); \ + ROUND160_16_TO_31(b,c,d,e,a,g,h,i,j,f); \ + ROUND160_16_TO_31(a,b,c,d,e,f,g,h,i,j) + +#define R160_32 \ + ROUND160_32_TO_47(d,e,a,b,c,i,j,f,g,h); \ + ROUND160_32_TO_47(c,d,e,a,b,h,i,j,f,g); \ + ROUND160_32_TO_47(b,c,d,e,a,g,h,i,j,f); \ + ROUND160_32_TO_47(a,b,c,d,e,f,g,h,i,j); \ + ROUND160_32_TO_47(e,a,b,c,d,j,f,g,h,i) + +#define R160_48 \ + ROUND160_48_TO_63(c,d,e,a,b,h,i,j,f,g); \ + ROUND160_48_TO_63(b,c,d,e,a,g,h,i,j,f); \ + ROUND160_48_TO_63(a,b,c,d,e,f,g,h,i,j); \ + ROUND160_48_TO_63(e,a,b,c,d,j,f,g,h,i); \ + ROUND160_48_TO_63(d,e,a,b,c,i,j,f,g,h) + +#define R160_64 \ + ROUND160_64_TO_79(b,c,d,e,a,g,h,i,j,f); \ + ROUND160_64_TO_79(a,b,c,d,e,f,g,h,i,j); \ + ROUND160_64_TO_79(e,a,b,c,d,j,f,g,h,i); \ + ROUND160_64_TO_79(d,e,a,b,c,i,j,f,g,h); \ + ROUND160_64_TO_79(c,d,e,a,b,h,i,j,f,g) + +static void ripemd160_transform(uint32_t *state, const uint8_t buffer[64]) +{ + uint32_t a, b, c, d, e, f, g, h, i, j, t av_unused; + uint32_t block[16]; + int n; + + a = f = state[0]; + b = g = state[1]; + c = h = state[2]; + d = i = state[3]; + e = j = state[4]; + + for (n = 0; n < 16; n++) + block[n] = AV_RL32(buffer + 4 * n); + n = 0; + +#if CONFIG_SMALL + for (; n < 16;) { + ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + + for (; n < 32;) { + ROUND160_16_TO_31(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + + for (; n < 48;) { + ROUND160_32_TO_47(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + + for (; n < 64;) { + ROUND160_48_TO_63(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + + for (; n < 80;) { + ROUND160_64_TO_79(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } +#else + + R160_0; R160_0; R160_0; + ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j); + + R160_16; R160_16; R160_16; + ROUND160_16_TO_31(e,a,b,c,d,j,f,g,h,i); + + R160_32; R160_32; R160_32; + ROUND160_32_TO_47(d,e,a,b,c,i,j,f,g,h); + + R160_48; R160_48; R160_48; + ROUND160_48_TO_63(c,d,e,a,b,h,i,j,f,g); + + R160_64; R160_64; R160_64; + ROUND160_64_TO_79(b,c,d,e,a,g,h,i,j,f); +#endif + + i += c + state[1]; + state[1] = state[2] + d + j; + state[2] = state[3] + e + f; + state[3] = state[4] + a + g; + state[4] = state[0] + b + h; + state[0] = i; +} + +static void ripemd320_transform(uint32_t *state, const uint8_t buffer[64]) +{ + uint32_t a, b, c, d, e, f, g, h, i, j, t av_unused; + uint32_t block[16]; + int n; + + a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; + f = state[5]; g = state[6]; h = state[7]; i = state[8]; j = state[9]; + + for (n = 0; n < 16; n++) + block[n] = AV_RL32(buffer + 4 * n); + n = 0; + +#if CONFIG_SMALL + for (; n < 16;) { + ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + FFSWAP(uint32_t, b, g); + + for (; n < 32;) { + ROUND160_16_TO_31(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + FFSWAP(uint32_t, d, i); + + for (; n < 48;) { + ROUND160_32_TO_47(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + FFSWAP(uint32_t, a, f); + + for (; n < 64;) { + ROUND160_48_TO_63(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + FFSWAP(uint32_t, c, h); + + for (; n < 80;) { + ROUND160_64_TO_79(a,b,c,d,e,f,g,h,i,j); + t = e; e = d; d = c; c = b; b = a; a = t; + t = j; j = i; i = h; h = g; g = f; f = t; + } + FFSWAP(uint32_t, e, j); +#else + + R160_0; R160_0; R160_0; + ROUND160_0_TO_15(a,b,c,d,e,f,g,h,i,j); + FFSWAP(uint32_t, a, f); + + R160_16; R160_16; R160_16; + ROUND160_16_TO_31(e,a,b,c,d,j,f,g,h,i); + FFSWAP(uint32_t, b, g); + + R160_32; R160_32; R160_32; + ROUND160_32_TO_47(d,e,a,b,c,i,j,f,g,h); + FFSWAP(uint32_t, c, h); + + R160_48; R160_48; R160_48; + ROUND160_48_TO_63(c,d,e,a,b,h,i,j,f,g); + FFSWAP(uint32_t, d, i); + + R160_64; R160_64; R160_64; + ROUND160_64_TO_79(b,c,d,e,a,g,h,i,j,f); + FFSWAP(uint32_t, e, j); +#endif + + state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; + state[5] += f; state[6] += g; state[7] += h; state[8] += i; state[9] += j; +} + +av_cold int av_ripemd_init(AVRIPEMD *ctx, int bits) +{ + ctx->digest_len = bits >> 5; + switch (bits) { + case 128: // RIPEMD-128 + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->transform = ripemd128_transform; + break; + case 160: // RIPEMD-160 + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + ctx->transform = ripemd160_transform; + break; + case 256: // RIPEMD-256 + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0x76543210; + ctx->state[5] = 0xFEDCBA98; + ctx->state[6] = 0x89ABCDEF; + ctx->state[7] = 0x01234567; + ctx->transform = ripemd256_transform; + break; + case 320: // RIPEMD-320 + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + ctx->state[5] = 0x76543210; + ctx->state[6] = 0xFEDCBA98; + ctx->state[7] = 0x89ABCDEF; + ctx->state[8] = 0x01234567; + ctx->state[9] = 0x3C2D1E0F; + ctx->transform = ripemd320_transform; + break; + default: + return AVERROR(EINVAL); + } + ctx->count = 0; + return 0; +} + +void av_ripemd_update(AVRIPEMD* ctx, const uint8_t* data, size_t len) +{ + unsigned int j; + size_t i; + + j = ctx->count & 63; + ctx->count += len; +#if CONFIG_SMALL + for (i = 0; i < len; i++) { + ctx->buffer[j++] = data[i]; + if (64 == j) { + ctx->transform(ctx->state, ctx->buffer); + j = 0; + } + } +#else + if (len >= 64 - j) { + const uint8_t *end; + memcpy(&ctx->buffer[j], data, (i = 64 - j)); + ctx->transform(ctx->state, ctx->buffer); + data += i; + len -= i; + end = data + (len & ~63); + len = len % 64; + for (; data < end; data += 64) + ctx->transform(ctx->state, data); + j = 0; + } + memcpy(&ctx->buffer[j], data, len); +#endif +} + +void av_ripemd_final(AVRIPEMD* ctx, uint8_t *digest) +{ + int i; + uint64_t finalcount = av_le2ne64(ctx->count << 3); + + av_ripemd_update(ctx, "\200", 1); + while ((ctx->count & 63) != 56) + av_ripemd_update(ctx, "", 1); + av_ripemd_update(ctx, (uint8_t *)&finalcount, 8); /* Should cause a transform() */ + for (i = 0; i < ctx->digest_len; i++) + AV_WL32(digest + i*4, ctx->state[i]); +} diff --git a/libs/ffmpeg/libavutil/ripemd.h b/libs/ffmpeg/libavutil/ripemd.h new file mode 100644 index 00000000000..9df9f905f3d --- /dev/null +++ b/libs/ffmpeg/libavutil/ripemd.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2007 Michael Niedermayer <michaelni@gmx.at> + * Copyright (C) 2013 James Almer <jamrial@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_ripemd + * Public header for RIPEMD hash function implementation. + */ + +#ifndef AVUTIL_RIPEMD_H +#define AVUTIL_RIPEMD_H + +#include <stddef.h> +#include <stdint.h> + +#include "attributes.h" + +/** + * @defgroup lavu_ripemd RIPEMD + * @ingroup lavu_hash + * RIPEMD hash function implementation. + * + * @{ + */ + +extern const int av_ripemd_size; + +struct AVRIPEMD; + +/** + * Allocate an AVRIPEMD context. + */ +struct AVRIPEMD *av_ripemd_alloc(void); + +/** + * Initialize RIPEMD hashing. + * + * @param context pointer to the function context (of size av_ripemd_size) + * @param bits number of bits in digest (128, 160, 256 or 320 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_ripemd_init(struct AVRIPEMD* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_ripemd_update(struct AVRIPEMD* context, const uint8_t* data, size_t len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_ripemd_final(struct AVRIPEMD* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_RIPEMD_H */ diff --git a/libs/ffmpeg/libavutil/samplefmt.c b/libs/ffmpeg/libavutil/samplefmt.c new file mode 100644 index 00000000000..e1be5f0547a --- /dev/null +++ b/libs/ffmpeg/libavutil/samplefmt.c @@ -0,0 +1,263 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "error.h" +#include "macros.h" +#include "mem.h" +#include "samplefmt.h" + +#include <limits.h> +#include <stdio.h> +#include <string.h> + +typedef struct SampleFmtInfo { + char name[8]; + int bits; + int planar; + enum AVSampleFormat altform; ///< planar<->packed alternative form +} SampleFmtInfo; + +/** this table gives more information about formats */ +static const SampleFmtInfo sample_fmt_info[AV_SAMPLE_FMT_NB] = { + [AV_SAMPLE_FMT_U8] = { .name = "u8", .bits = 8, .planar = 0, .altform = AV_SAMPLE_FMT_U8P }, + [AV_SAMPLE_FMT_S16] = { .name = "s16", .bits = 16, .planar = 0, .altform = AV_SAMPLE_FMT_S16P }, + [AV_SAMPLE_FMT_S32] = { .name = "s32", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_S32P }, + [AV_SAMPLE_FMT_S64] = { .name = "s64", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_S64P }, + [AV_SAMPLE_FMT_FLT] = { .name = "flt", .bits = 32, .planar = 0, .altform = AV_SAMPLE_FMT_FLTP }, + [AV_SAMPLE_FMT_DBL] = { .name = "dbl", .bits = 64, .planar = 0, .altform = AV_SAMPLE_FMT_DBLP }, + [AV_SAMPLE_FMT_U8P] = { .name = "u8p", .bits = 8, .planar = 1, .altform = AV_SAMPLE_FMT_U8 }, + [AV_SAMPLE_FMT_S16P] = { .name = "s16p", .bits = 16, .planar = 1, .altform = AV_SAMPLE_FMT_S16 }, + [AV_SAMPLE_FMT_S32P] = { .name = "s32p", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_S32 }, + [AV_SAMPLE_FMT_S64P] = { .name = "s64p", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_S64 }, + [AV_SAMPLE_FMT_FLTP] = { .name = "fltp", .bits = 32, .planar = 1, .altform = AV_SAMPLE_FMT_FLT }, + [AV_SAMPLE_FMT_DBLP] = { .name = "dblp", .bits = 64, .planar = 1, .altform = AV_SAMPLE_FMT_DBL }, +}; + +const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt) +{ + if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) + return NULL; + return sample_fmt_info[sample_fmt].name; +} + +enum AVSampleFormat av_get_sample_fmt(const char *name) +{ + int i; + + for (i = 0; i < AV_SAMPLE_FMT_NB; i++) + if (!strcmp(sample_fmt_info[i].name, name)) + return i; + return AV_SAMPLE_FMT_NONE; +} + +enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar) +{ + if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) + return AV_SAMPLE_FMT_NONE; + if (sample_fmt_info[sample_fmt].planar == planar) + return sample_fmt; + return sample_fmt_info[sample_fmt].altform; +} + +enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt) +{ + if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) + return AV_SAMPLE_FMT_NONE; + if (sample_fmt_info[sample_fmt].planar) + return sample_fmt_info[sample_fmt].altform; + return sample_fmt; +} + +enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt) +{ + if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) + return AV_SAMPLE_FMT_NONE; + if (sample_fmt_info[sample_fmt].planar) + return sample_fmt; + return sample_fmt_info[sample_fmt].altform; +} + +char *av_get_sample_fmt_string (char *buf, int buf_size, enum AVSampleFormat sample_fmt) +{ + /* print header */ + if (sample_fmt < 0) + snprintf(buf, buf_size, "name " " depth"); + else if (sample_fmt < AV_SAMPLE_FMT_NB) { + SampleFmtInfo info = sample_fmt_info[sample_fmt]; + snprintf (buf, buf_size, "%-6s" " %2d ", info.name, info.bits); + } + + return buf; +} + +int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt) +{ + return sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB ? + 0 : sample_fmt_info[sample_fmt].bits >> 3; +} + +int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt) +{ + if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB) + return 0; + return sample_fmt_info[sample_fmt].planar; +} + +int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align) +{ + int line_size; + int sample_size = av_get_bytes_per_sample(sample_fmt); + int planar = av_sample_fmt_is_planar(sample_fmt); + + /* validate parameter ranges */ + if (!sample_size || nb_samples <= 0 || nb_channels <= 0) + return AVERROR(EINVAL); + + /* auto-select alignment if not specified */ + if (!align) { + if (nb_samples > INT_MAX - 31) + return AVERROR(EINVAL); + align = 1; + nb_samples = FFALIGN(nb_samples, 32); + } + + /* check for integer overflow */ + if (nb_channels > INT_MAX / align || + (int64_t)nb_channels * nb_samples > (INT_MAX - (align * nb_channels)) / sample_size) + return AVERROR(EINVAL); + + line_size = planar ? FFALIGN(nb_samples * sample_size, align) : + FFALIGN(nb_samples * sample_size * nb_channels, align); + if (linesize) + *linesize = line_size; + + return planar ? line_size * nb_channels : line_size; +} + +int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, + const uint8_t *buf, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align) +{ + int ch, planar, buf_size, line_size; + + planar = av_sample_fmt_is_planar(sample_fmt); + buf_size = av_samples_get_buffer_size(&line_size, nb_channels, nb_samples, + sample_fmt, align); + if (buf_size < 0) + return buf_size; + + if (linesize) + *linesize = line_size; + + memset(audio_data, 0, planar + ? sizeof(*audio_data) * nb_channels + : sizeof(*audio_data)); + + if (!buf) + return buf_size; + + audio_data[0] = (uint8_t *)buf; + for (ch = 1; planar && ch < nb_channels; ch++) + audio_data[ch] = audio_data[ch-1] + line_size; + + return buf_size; +} + +int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align) +{ + uint8_t *buf; + int size = av_samples_get_buffer_size(NULL, nb_channels, nb_samples, + sample_fmt, align); + if (size < 0) + return size; + + buf = av_malloc(size); + if (!buf) + return AVERROR(ENOMEM); + + size = av_samples_fill_arrays(audio_data, linesize, buf, nb_channels, + nb_samples, sample_fmt, align); + if (size < 0) { + av_free(buf); + return size; + } + + av_samples_set_silence(audio_data, 0, nb_samples, nb_channels, sample_fmt); + + return size; +} + +int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align) +{ + int ret, nb_planes = av_sample_fmt_is_planar(sample_fmt) ? nb_channels : 1; + + *audio_data = av_calloc(nb_planes, sizeof(**audio_data)); + if (!*audio_data) + return AVERROR(ENOMEM); + ret = av_samples_alloc(*audio_data, linesize, nb_channels, + nb_samples, sample_fmt, align); + if (ret < 0) + av_freep(audio_data); + return ret; +} + +int av_samples_copy(uint8_t * const *dst, uint8_t * const *src, int dst_offset, + int src_offset, int nb_samples, int nb_channels, + enum AVSampleFormat sample_fmt) +{ + int planar = av_sample_fmt_is_planar(sample_fmt); + int planes = planar ? nb_channels : 1; + int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels); + int data_size = nb_samples * block_align; + int i; + + dst_offset *= block_align; + src_offset *= block_align; + + if((dst[0] < src[0] ? src[0] - dst[0] : dst[0] - src[0]) >= data_size) { + for (i = 0; i < planes; i++) + memcpy(dst[i] + dst_offset, src[i] + src_offset, data_size); + } else { + for (i = 0; i < planes; i++) + memmove(dst[i] + dst_offset, src[i] + src_offset, data_size); + } + + return 0; +} + +int av_samples_set_silence(uint8_t * const *audio_data, int offset, int nb_samples, + int nb_channels, enum AVSampleFormat sample_fmt) +{ + int planar = av_sample_fmt_is_planar(sample_fmt); + int planes = planar ? nb_channels : 1; + int block_align = av_get_bytes_per_sample(sample_fmt) * (planar ? 1 : nb_channels); + int data_size = nb_samples * block_align; + int fill_char = (sample_fmt == AV_SAMPLE_FMT_U8 || + sample_fmt == AV_SAMPLE_FMT_U8P) ? 0x80 : 0x00; + int i; + + offset *= block_align; + + for (i = 0; i < planes; i++) + memset(audio_data[i] + offset, fill_char, data_size); + + return 0; +} diff --git a/libs/ffmpeg/libavutil/samplefmt.h b/libs/ffmpeg/libavutil/samplefmt.h new file mode 100644 index 00000000000..6e55d711401 --- /dev/null +++ b/libs/ffmpeg/libavutil/samplefmt.h @@ -0,0 +1,268 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SAMPLEFMT_H +#define AVUTIL_SAMPLEFMT_H + +#include <stdint.h> + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_sampfmts Audio sample formats + * + * Audio sample format enumeration and related convenience functions. + * @{ + */ + +/** + * Audio sample formats + * + * - The data described by the sample format is always in native-endian order. + * Sample values can be expressed by native C types, hence the lack of a signed + * 24-bit sample format even though it is a common raw audio data format. + * + * - The floating-point formats are based on full volume being in the range + * [-1.0, 1.0]. Any values outside this range are beyond full volume level. + * + * - The data layout as used in av_samples_fill_arrays() and elsewhere in FFmpeg + * (such as AVFrame in libavcodec) is as follows: + * + * @par + * For planar sample formats, each audio channel is in a separate data plane, + * and linesize is the buffer size, in bytes, for a single plane. All data + * planes must be the same size. For packed sample formats, only the first data + * plane is used, and samples for each channel are interleaved. In this case, + * linesize is the buffer size, in bytes, for the 1 plane. + * + */ +enum AVSampleFormat { + AV_SAMPLE_FMT_NONE = -1, + AV_SAMPLE_FMT_U8, ///< unsigned 8 bits + AV_SAMPLE_FMT_S16, ///< signed 16 bits + AV_SAMPLE_FMT_S32, ///< signed 32 bits + AV_SAMPLE_FMT_FLT, ///< float + AV_SAMPLE_FMT_DBL, ///< double + + AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar + AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar + AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar + AV_SAMPLE_FMT_FLTP, ///< float, planar + AV_SAMPLE_FMT_DBLP, ///< double, planar + AV_SAMPLE_FMT_S64, ///< signed 64 bits + AV_SAMPLE_FMT_S64P, ///< signed 64 bits, planar + + AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically +}; + +/** + * Return the name of sample_fmt, or NULL if sample_fmt is not + * recognized. + */ +const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt); + +/** + * Return a sample format corresponding to name, or AV_SAMPLE_FMT_NONE + * on error. + */ +enum AVSampleFormat av_get_sample_fmt(const char *name); + +/** + * Return the planar<->packed alternative form of the given sample format, or + * AV_SAMPLE_FMT_NONE on error. If the passed sample_fmt is already in the + * requested planar/packed format, the format returned is the same as the + * input. + */ +enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar); + +/** + * Get the packed alternative form of the given sample format. + * + * If the passed sample_fmt is already in packed format, the format returned is + * the same as the input. + * + * @return the packed alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Get the planar alternative form of the given sample format. + * + * If the passed sample_fmt is already in planar format, the format returned is + * the same as the input. + * + * @return the planar alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Generate a string corresponding to the sample format with + * sample_fmt, or a header if sample_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param sample_fmt the number of the sample format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + * @return the pointer to the filled buffer or NULL in case of other errors + */ +char *av_get_sample_fmt_string(char *buf, int buf_size, enum AVSampleFormat sample_fmt); + +/** + * Return number of bytes per sample. + * + * @param sample_fmt the sample format + * @return number of bytes per sample or zero if unknown for the given + * sample format + */ +int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt); + +/** + * Check if the sample format is planar. + * + * @param sample_fmt the sample format to inspect + * @return 1 if the sample format is planar, 0 if it is interleaved + */ +int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt); + +/** + * Get the required buffer size for the given audio parameters. + * + * @param[out] linesize calculated linesize, may be NULL + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return required buffer size, or negative error code on failure + */ +int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * @} + * + * @defgroup lavu_sampmanip Samples manipulation + * + * Functions that manipulate audio samples + * @{ + */ + +/** + * Fill plane data pointers and linesize for samples with sample + * format sample_fmt. + * + * The audio_data array is filled with the pointers to the samples data planes: + * for planar, set the start point of each channel's data within the buffer, + * for packed, set the start point of the entire buffer only. + * + * The value pointed to by linesize is set to the aligned size of each + * channel's data buffer for planar layout, or to the aligned size of the + * buffer for all channels for packed layout. + * + * The buffer in buf must be big enough to contain all the samples + * (use av_samples_get_buffer_size() to compute its minimum size), + * otherwise the audio_data pointers will point to invalid data. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize calculated linesize, may be NULL + * @param buf the pointer to a buffer containing the samples + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return minimum size in bytes required for the buffer on success, + * or a negative error code on failure + */ +int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, + const uint8_t *buf, + int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a samples buffer for nb_samples samples, and fill data pointers and + * linesize accordingly. + * The allocated samples buffer can be freed by using av_freep(&audio_data[0]) + * Allocated data will be initialized to silence. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize aligned size for audio buffer(s), may be NULL + * @param nb_channels number of audio channels + * @param nb_samples number of samples per channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return >=0 on success or a negative error code on failure + * @todo return the size of the allocated buffer in case of success at the next bump + * @see av_samples_fill_arrays() + * @see av_samples_alloc_array_and_samples() + */ +int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a data pointers array, samples buffer for nb_samples + * samples, and fill data pointers and linesize accordingly. + * + * This is the same as av_samples_alloc(), but also allocates the data + * pointers array. + * + * @see av_samples_alloc() + */ +int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Copy samples from src to dst. + * + * @param dst destination array of pointers to data planes + * @param src source array of pointers to data planes + * @param dst_offset offset in samples at which the data will be written to dst + * @param src_offset offset in samples at which the data will be read from src + * @param nb_samples number of samples to be copied + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_copy(uint8_t * const *dst, uint8_t * const *src, int dst_offset, + int src_offset, int nb_samples, int nb_channels, + enum AVSampleFormat sample_fmt); + +/** + * Fill an audio buffer with silence. + * + * @param audio_data array of pointers to data planes + * @param offset offset in samples at which to start filling + * @param nb_samples number of samples to fill + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_set_silence(uint8_t * const *audio_data, int offset, int nb_samples, + int nb_channels, enum AVSampleFormat sample_fmt); + +/** + * @} + * @} + */ +#endif /* AVUTIL_SAMPLEFMT_H */ diff --git a/libs/ffmpeg/libavutil/sfc64.h b/libs/ffmpeg/libavutil/sfc64.h new file mode 100644 index 00000000000..a1593a0a7bf --- /dev/null +++ b/libs/ffmpeg/libavutil/sfc64.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024 Michael Niedermayer <michael-ffmpeg@niedermayer.cc> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/** + * @file + * simple Pseudo Random Number Generator + * + * This is a implementation of SFC64, a 64-bit PRNG by Chris Doty-Humphrey. + * + * This Generator is much faster (0m1.872s) than 64bit KISS (0m3.823s) and PCG-XSH-RR-64/32 (0m2.700s) + * And passes testu01 and practrand test suits. + */ + +#ifndef AVUTIL_SFC64_H +#define AVUTIL_SFC64_H + +#include <inttypes.h> + +typedef struct FFSFC64 { + uint64_t a,b,c,counter; +} FFSFC64; + +static inline uint64_t ff_sfc64_get(FFSFC64 *s) { + uint64_t tmp = s->a + s->b + s->counter++; + s->a = s->b ^ (s->b >> 11); + s->b = s->c + (s->c << 3); // This is a multiply by 9 + s->c = (s->c << 24 | s->c >> 40) + tmp; + return tmp; +} + +/** + * Return the previous random value, and step the generator backward. + * + * It is safe to take values before the first, but such values can be highly + * correlated to the seeds. + */ +static inline uint64_t ff_sfc64_reverse_get(FFSFC64 *s) { + uint64_t prev_c = s->b * 0x8E38E38E38E38E39; + uint64_t tmp = s->c - (prev_c << 24 | prev_c >> 40); + s->b = s->a ^ (s->a >> 11); + s->b ^= s->b >> 22; + s->b ^= s->b >> 44; + + s->a = tmp - s->b - --s->counter; + s->c = prev_c; + + return tmp; +} + +/** + * Initialize sfc64 with up to 3 seeds. + * + * @param rounds number of rounds mixing up state during init. Generally 8-18, larger numbers will help with bad quality seeds. + * 12 is a good choice if all 3 seeds are equal + * + */ +static inline void ff_sfc64_init(FFSFC64 *s, uint64_t seeda, uint64_t seedb, uint64_t seedc, int rounds) { + s->a = seeda; + s->b = seedb; + s->c = seedc; + s->counter = 1; + while (rounds--) + ff_sfc64_get(s); +} + +#endif // AVUTIL_SFC64_H diff --git a/libs/ffmpeg/libavutil/sha.c b/libs/ffmpeg/libavutil/sha.c new file mode 100644 index 00000000000..0df044032fb --- /dev/null +++ b/libs/ffmpeg/libavutil/sha.c @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2007 Michael Niedermayer <michaelni@gmx.at> + * Copyright (C) 2009 Konstantin Shishkov + * based on public domain SHA-1 code by Steve Reid <steve@edmweb.com> + * and on BSD-licensed SHA-2 code by Aaron D. Gifford + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> + +#include "config.h" +#include "attributes.h" +#include "bswap.h" +#include "error.h" +#include "sha.h" +#include "intreadwrite.h" +#include "mem.h" + +/** hash context */ +typedef struct AVSHA { + uint8_t digest_len; ///< digest length in 32-bit words + uint64_t count; ///< number of bytes in buffer + uint8_t buffer[64]; ///< 512-bit buffer of input values used in hash updating + uint32_t state[8]; ///< current hash value + /** function used to update hash for 512-bit input block */ + void (*transform)(uint32_t *state, const uint8_t buffer[64]); +} AVSHA; + +const int av_sha_size = sizeof(AVSHA); + +struct AVSHA *av_sha_alloc(void) +{ + return av_mallocz(sizeof(struct AVSHA)); +} + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define blk0(i) (block[i] = AV_RB32(buffer + 4 * (i))) +#define blk(i) (block[i] = rol(block[(i)-3] ^ block[(i)-8] ^ block[(i)-14] ^ block[(i)-16], 1)) + +#define R0(v,w,x,y,z,i) z += (((w)&((x)^(y)))^(y)) + blk0(i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); +#define R1(v,w,x,y,z,i) z += (((w)&((x)^(y)))^(y)) + blk (i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); +#define R2(v,w,x,y,z,i) z += ( (w)^(x) ^(y)) + blk (i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); +#define R3(v,w,x,y,z,i) z += ((((w)|(x))&(y))|((w)&(x))) + blk (i) + 0x8F1BBCDC + rol(v, 5); w = rol(w, 30); +#define R4(v,w,x,y,z,i) z += ( (w)^(x) ^(y)) + blk (i) + 0xCA62C1D6 + rol(v, 5); w = rol(w, 30); + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +static void sha1_transform(uint32_t state[5], const uint8_t buffer[64]) +{ + uint32_t block[80]; + unsigned int i, a, b, c, d, e; + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; +#if CONFIG_SMALL + for (i = 0; i < 80; i++) { + int t; + if (i < 16) + t = AV_RB32(buffer + 4 * i); + else + t = rol(block[i-3] ^ block[i-8] ^ block[i-14] ^ block[i-16], 1); + block[i] = t; + t += e + rol(a, 5); + if (i < 40) { + if (i < 20) + t += ((b&(c^d))^d) + 0x5A827999; + else + t += ( b^c ^d) + 0x6ED9EBA1; + } else { + if (i < 60) + t += (((b|c)&d)|(b&c)) + 0x8F1BBCDC; + else + t += ( b^c ^d) + 0xCA62C1D6; + } + e = d; + d = c; + c = rol(b, 30); + b = a; + a = t; + } +#else + +#define R1_0 \ + R0(a, b, c, d, e, 0 + i); \ + R0(e, a, b, c, d, 1 + i); \ + R0(d, e, a, b, c, 2 + i); \ + R0(c, d, e, a, b, 3 + i); \ + R0(b, c, d, e, a, 4 + i); \ + i += 5 + + i = 0; + R1_0; R1_0; R1_0; + R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); + R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); + R1(b, c, d, e, a, 19); + +#define R1_20 \ + R2(a, b, c, d, e, 0 + i); \ + R2(e, a, b, c, d, 1 + i); \ + R2(d, e, a, b, c, 2 + i); \ + R2(c, d, e, a, b, 3 + i); \ + R2(b, c, d, e, a, 4 + i); \ + i += 5 + + i = 20; + R1_20; R1_20; R1_20; R1_20; + +#define R1_40 \ + R3(a, b, c, d, e, 0 + i); \ + R3(e, a, b, c, d, 1 + i); \ + R3(d, e, a, b, c, 2 + i); \ + R3(c, d, e, a, b, 3 + i); \ + R3(b, c, d, e, a, 4 + i); \ + i += 5 + + R1_40; R1_40; R1_40; R1_40; + +#define R1_60 \ + R4(a, b, c, d, e, 0 + i); \ + R4(e, a, b, c, d, 1 + i); \ + R4(d, e, a, b, c, 2 + i); \ + R4(c, d, e, a, b, 3 + i); \ + R4(b, c, d, e, a, 4 + i); \ + i += 5 + + R1_60; R1_60; R1_60; R1_60; +#endif + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; +} + +static const uint32_t K256[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + + +#define Ch(x,y,z) (((x) & ((y) ^ (z))) ^ (z)) +#define Maj(z,y,x) ((((x) | (y)) & (z)) | ((x) & (y))) + +#define Sigma0_256(x) (rol((x), 30) ^ rol((x), 19) ^ rol((x), 10)) +#define Sigma1_256(x) (rol((x), 26) ^ rol((x), 21) ^ rol((x), 7)) +#define sigma0_256(x) (rol((x), 25) ^ rol((x), 14) ^ ((x) >> 3)) +#define sigma1_256(x) (rol((x), 15) ^ rol((x), 13) ^ ((x) >> 10)) + +#undef blk +#define blk(i) (block[i] = block[i - 16] + sigma0_256(block[i - 15]) + \ + sigma1_256(block[i - 2]) + block[i - 7]) + +#define ROUND256(a,b,c,d,e,f,g,h) \ + T1 += (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[i]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + i++ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = blk0(i); \ + ROUND256(a,b,c,d,e,f,g,h) + +#define ROUND256_16_TO_63(a,b,c,d,e,f,g,h) \ + T1 = blk(i); \ + ROUND256(a,b,c,d,e,f,g,h) + +static void sha256_transform(uint32_t *state, const uint8_t buffer[64]) +{ + unsigned int i, a, b, c, d, e, f, g, h; + uint32_t block[64]; + uint32_t T1; + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; +#if CONFIG_SMALL + for (i = 0; i < 64; i++) { + uint32_t T2; + if (i < 16) + T1 = blk0(i); + else + T1 = blk(i); + T1 += h + Sigma1_256(e) + Ch(e, f, g) + K256[i]; + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } +#else + + i = 0; +#define R256_0 \ + ROUND256_0_TO_15(a, b, c, d, e, f, g, h); \ + ROUND256_0_TO_15(h, a, b, c, d, e, f, g); \ + ROUND256_0_TO_15(g, h, a, b, c, d, e, f); \ + ROUND256_0_TO_15(f, g, h, a, b, c, d, e); \ + ROUND256_0_TO_15(e, f, g, h, a, b, c, d); \ + ROUND256_0_TO_15(d, e, f, g, h, a, b, c); \ + ROUND256_0_TO_15(c, d, e, f, g, h, a, b); \ + ROUND256_0_TO_15(b, c, d, e, f, g, h, a) + + R256_0; R256_0; + +#define R256_16 \ + ROUND256_16_TO_63(a, b, c, d, e, f, g, h); \ + ROUND256_16_TO_63(h, a, b, c, d, e, f, g); \ + ROUND256_16_TO_63(g, h, a, b, c, d, e, f); \ + ROUND256_16_TO_63(f, g, h, a, b, c, d, e); \ + ROUND256_16_TO_63(e, f, g, h, a, b, c, d); \ + ROUND256_16_TO_63(d, e, f, g, h, a, b, c); \ + ROUND256_16_TO_63(c, d, e, f, g, h, a, b); \ + ROUND256_16_TO_63(b, c, d, e, f, g, h, a) + + R256_16; R256_16; R256_16; + R256_16; R256_16; R256_16; +#endif + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + state[5] += f; + state[6] += g; + state[7] += h; +} + + +av_cold int av_sha_init(AVSHA *ctx, int bits) +{ + ctx->digest_len = bits >> 5; + switch (bits) { + case 160: // SHA-1 + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + ctx->transform = sha1_transform; + break; + case 224: // SHA-224 + ctx->state[0] = 0xC1059ED8; + ctx->state[1] = 0x367CD507; + ctx->state[2] = 0x3070DD17; + ctx->state[3] = 0xF70E5939; + ctx->state[4] = 0xFFC00B31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64F98FA7; + ctx->state[7] = 0xBEFA4FA4; + ctx->transform = sha256_transform; + break; + case 256: // SHA-256 + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; + ctx->transform = sha256_transform; + break; + default: + return AVERROR(EINVAL); + } + ctx->count = 0; + return 0; +} + +void av_sha_update(struct AVSHA *ctx, const uint8_t *data, size_t len) +{ + unsigned int j; + size_t i; + + j = ctx->count & 63; + ctx->count += len; +#if CONFIG_SMALL + for (i = 0; i < len; i++) { + ctx->buffer[j++] = data[i]; + if (64 == j) { + ctx->transform(ctx->state, ctx->buffer); + j = 0; + } + } +#else + if (len >= 64 - j) { + const uint8_t *end; + memcpy(&ctx->buffer[j], data, (i = 64 - j)); + ctx->transform(ctx->state, ctx->buffer); + data += i; + len -= i; + end = data + (len & ~63); + len = len % 64; + for (; data < end; data += 64) + ctx->transform(ctx->state, data); + j = 0; + } + memcpy(&ctx->buffer[j], data, len); +#endif +} + +void av_sha_final(AVSHA* ctx, uint8_t *digest) +{ + int i; + uint64_t finalcount = av_be2ne64(ctx->count << 3); + + av_sha_update(ctx, "\200", 1); + while ((ctx->count & 63) != 56) + av_sha_update(ctx, "", 1); + av_sha_update(ctx, (uint8_t *)&finalcount, 8); /* Should cause a transform() */ + for (i = 0; i < ctx->digest_len; i++) + AV_WB32(digest + i*4, ctx->state[i]); +} diff --git a/libs/ffmpeg/libavutil/sha.h b/libs/ffmpeg/libavutil/sha.h new file mode 100644 index 00000000000..2e1220abd12 --- /dev/null +++ b/libs/ffmpeg/libavutil/sha.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2007 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_sha + * Public header for SHA-1 & SHA-256 hash function implementations. + */ + +#ifndef AVUTIL_SHA_H +#define AVUTIL_SHA_H + +#include <stddef.h> +#include <stdint.h> + +#include "attributes.h" + +/** + * @defgroup lavu_sha SHA + * @ingroup lavu_hash + * SHA-1 and SHA-256 (Secure Hash Algorithm) hash function implementations. + * + * This module supports the following SHA hash functions: + * + * - SHA-1: 160 bits + * - SHA-224: 224 bits, as a variant of SHA-2 + * - SHA-256: 256 bits, as a variant of SHA-2 + * + * @see For SHA-384, SHA-512, and variants thereof, see @ref lavu_sha512. + * + * @{ + */ + +extern const int av_sha_size; + +struct AVSHA; + +/** + * Allocate an AVSHA context. + */ +struct AVSHA *av_sha_alloc(void); + +/** + * Initialize SHA-1 or SHA-2 hashing. + * + * @param context pointer to the function context (of size av_sha_size) + * @param bits number of bits in digest (SHA-1 - 160 bits, SHA-2 224 or 256 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha_init(struct AVSHA* context, int bits); + +/** + * Update hash value. + * + * @param ctx hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_sha_update(struct AVSHA *ctx, const uint8_t *data, size_t len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha_final(struct AVSHA* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA_H */ diff --git a/libs/ffmpeg/libavutil/sha512.c b/libs/ffmpeg/libavutil/sha512.c new file mode 100644 index 00000000000..0574a46f94d --- /dev/null +++ b/libs/ffmpeg/libavutil/sha512.c @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2007 Michael Niedermayer <michaelni@gmx.at> + * Copyright (C) 2009 Konstantin Shishkov + * Copyright (C) 2013 James Almer + * based on BSD-licensed SHA-2 code by Aaron D. Gifford + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> + +#include "config.h" +#include "attributes.h" +#include "bswap.h" +#include "error.h" +#include "sha512.h" +#include "intreadwrite.h" +#include "mem.h" + +/** hash context */ +typedef struct AVSHA512 { + uint8_t digest_len; ///< digest length in 64-bit words + uint64_t count; ///< number of bytes in buffer + uint8_t buffer[128]; ///< 1024-bit buffer of input values used in hash updating + uint64_t state[8]; ///< current hash value +} AVSHA512; + +const int av_sha512_size = sizeof(AVSHA512); + +struct AVSHA512 *av_sha512_alloc(void) +{ + return av_mallocz(sizeof(struct AVSHA512)); +} + +static const uint64_t K512[80] = { + UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), + UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc), + UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019), + UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118), + UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe), + UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2), + UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1), + UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694), + UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3), + UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65), + UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483), + UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5), + UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210), + UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4), + UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725), + UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70), + UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926), + UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df), + UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8), + UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b), + UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001), + UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30), + UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910), + UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8), + UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53), + UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8), + UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb), + UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3), + UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60), + UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec), + UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9), + UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b), + UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207), + UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178), + UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6), + UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b), + UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493), + UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c), + UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a), + UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817), +}; + +#define ror(value, bits) (((value) >> (bits)) | ((value) << (64 - (bits)))) + +#define Ch(x,y,z) (((x) & ((y) ^ (z))) ^ (z)) +#define Maj(z,y,x) ((((x) | (y)) & (z)) | ((x) & (y))) + +#define Sigma0_512(x) (ror((x), 28) ^ ror((x), 34) ^ ror((x), 39)) +#define Sigma1_512(x) (ror((x), 14) ^ ror((x), 18) ^ ror((x), 41)) +#define sigma0_512(x) (ror((x), 1) ^ ror((x), 8) ^ ((x) >> 7)) +#define sigma1_512(x) (ror((x), 19) ^ ror((x), 61) ^ ((x) >> 6)) + +#define blk0(i) (block[i] = AV_RB64(buffer + 8 * (i))) +#define blk(i) (block[i] = block[i - 16] + sigma0_512(block[i - 15]) + \ + sigma1_512(block[i - 2]) + block[i - 7]) + +#define ROUND512(a,b,c,d,e,f,g,h) \ + T1 += (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[i]; \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + i++ + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = blk0(i); \ + ROUND512(a,b,c,d,e,f,g,h) + +#define ROUND512_16_TO_80(a,b,c,d,e,f,g,h) \ + T1 = blk(i); \ + ROUND512(a,b,c,d,e,f,g,h) + +static void sha512_transform(uint64_t *state, const uint8_t buffer[128]) +{ + uint64_t a, b, c, d, e, f, g, h; + uint64_t block[80]; + uint64_t T1; + int i; + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + f = state[5]; + g = state[6]; + h = state[7]; +#if CONFIG_SMALL + for (i = 0; i < 80; i++) { + uint64_t T2; + if (i < 16) + T1 = blk0(i); + else + T1 = blk(i); + T1 += h + Sigma1_512(e) + Ch(e, f, g) + K512[i]; + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } +#else + +#define R512_0 \ + ROUND512_0_TO_15(a, b, c, d, e, f, g, h); \ + ROUND512_0_TO_15(h, a, b, c, d, e, f, g); \ + ROUND512_0_TO_15(g, h, a, b, c, d, e, f); \ + ROUND512_0_TO_15(f, g, h, a, b, c, d, e); \ + ROUND512_0_TO_15(e, f, g, h, a, b, c, d); \ + ROUND512_0_TO_15(d, e, f, g, h, a, b, c); \ + ROUND512_0_TO_15(c, d, e, f, g, h, a, b); \ + ROUND512_0_TO_15(b, c, d, e, f, g, h, a) + + i = 0; + R512_0; R512_0; + +#define R512_16 \ + ROUND512_16_TO_80(a, b, c, d, e, f, g, h); \ + ROUND512_16_TO_80(h, a, b, c, d, e, f, g); \ + ROUND512_16_TO_80(g, h, a, b, c, d, e, f); \ + ROUND512_16_TO_80(f, g, h, a, b, c, d, e); \ + ROUND512_16_TO_80(e, f, g, h, a, b, c, d); \ + ROUND512_16_TO_80(d, e, f, g, h, a, b, c); \ + ROUND512_16_TO_80(c, d, e, f, g, h, a, b); \ + ROUND512_16_TO_80(b, c, d, e, f, g, h, a) + + R512_16; R512_16; R512_16; R512_16; + R512_16; R512_16; R512_16; R512_16; +#endif + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + state[5] += f; + state[6] += g; + state[7] += h; +} + + +av_cold int av_sha512_init(AVSHA512 *ctx, int bits) +{ + ctx->digest_len = bits >> 6; + switch (bits) { + case 224: // SHA-512/224 + ctx->state[0] = UINT64_C(0x8C3D37C819544DA2); + ctx->state[1] = UINT64_C(0x73E1996689DCD4D6); + ctx->state[2] = UINT64_C(0x1DFAB7AE32FF9C82); + ctx->state[3] = UINT64_C(0x679DD514582F9FCF); + ctx->state[4] = UINT64_C(0x0F6D2B697BD44DA8); + ctx->state[5] = UINT64_C(0x77E36F7304C48942); + ctx->state[6] = UINT64_C(0x3F9D85A86A1D36C8); + ctx->state[7] = UINT64_C(0x1112E6AD91D692A1); + break; + case 256: // SHA-512/256 + ctx->state[0] = UINT64_C(0x22312194FC2BF72C); + ctx->state[1] = UINT64_C(0x9F555FA3C84C64C2); + ctx->state[2] = UINT64_C(0x2393B86B6F53B151); + ctx->state[3] = UINT64_C(0x963877195940EABD); + ctx->state[4] = UINT64_C(0x96283EE2A88EFFE3); + ctx->state[5] = UINT64_C(0xBE5E1E2553863992); + ctx->state[6] = UINT64_C(0x2B0199FC2C85B8AA); + ctx->state[7] = UINT64_C(0x0EB72DDC81C52CA2); + break; + case 384: // SHA-384 + ctx->state[0] = UINT64_C(0xCBBB9D5DC1059ED8); + ctx->state[1] = UINT64_C(0x629A292A367CD507); + ctx->state[2] = UINT64_C(0x9159015A3070DD17); + ctx->state[3] = UINT64_C(0x152FECD8F70E5939); + ctx->state[4] = UINT64_C(0x67332667FFC00B31); + ctx->state[5] = UINT64_C(0x8EB44A8768581511); + ctx->state[6] = UINT64_C(0xDB0C2E0D64F98FA7); + ctx->state[7] = UINT64_C(0x47B5481DBEFA4FA4); + break; + case 512: // SHA-512 + ctx->state[0] = UINT64_C(0x6A09E667F3BCC908); + ctx->state[1] = UINT64_C(0xBB67AE8584CAA73B); + ctx->state[2] = UINT64_C(0x3C6EF372FE94F82B); + ctx->state[3] = UINT64_C(0xA54FF53A5F1D36F1); + ctx->state[4] = UINT64_C(0x510E527FADE682D1); + ctx->state[5] = UINT64_C(0x9B05688C2B3E6C1F); + ctx->state[6] = UINT64_C(0x1F83D9ABFB41BD6B); + ctx->state[7] = UINT64_C(0x5BE0CD19137E2179); + break; + default: + return AVERROR(EINVAL); + } + ctx->count = 0; + return 0; +} + +void av_sha512_update(AVSHA512* ctx, const uint8_t* data, size_t len) +{ + unsigned int j; + size_t i; + + j = ctx->count & 127; + ctx->count += len; +#if CONFIG_SMALL + for (i = 0; i < len; i++) { + ctx->buffer[j++] = data[i]; + if (128 == j) { + sha512_transform(ctx->state, ctx->buffer); + j = 0; + } + } +#else + if (len >= 128 - j) { + const uint8_t *end; + memcpy(&ctx->buffer[j], data, (i = 128 - j)); + sha512_transform(ctx->state, ctx->buffer); + data += i; + len -= i; + end = data + (len & ~127); + len = len % 128; + for (; data < end; data += 128) + sha512_transform(ctx->state, data); + j = 0; + } + memcpy(&ctx->buffer[j], data, len); +#endif +} + +void av_sha512_final(AVSHA512* ctx, uint8_t *digest) +{ + uint64_t i = 0; + uint64_t finalcount = av_be2ne64(ctx->count << 3); + + av_sha512_update(ctx, "\200", 1); + while ((ctx->count & 127) != 112) + av_sha512_update(ctx, "", 1); + av_sha512_update(ctx, (uint8_t *)&i, 8); + av_sha512_update(ctx, (uint8_t *)&finalcount, 8); /* Should cause a transform() */ + for (i = 0; i < ctx->digest_len; i++) + AV_WB64(digest + i*8, ctx->state[i]); + if (ctx->digest_len & 1) /* SHA512/224 is 28 bytes, and is not divisible by 8. */ + AV_WB32(digest + i*8, ctx->state[i] >> 32); +} diff --git a/libs/ffmpeg/libavutil/sha512.h b/libs/ffmpeg/libavutil/sha512.h new file mode 100644 index 00000000000..a4a3f23db30 --- /dev/null +++ b/libs/ffmpeg/libavutil/sha512.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2007 Michael Niedermayer <michaelni@gmx.at> + * Copyright (C) 2013 James Almer <jamrial@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_sha512 + * Public header for SHA-512 implementation. + */ + +#ifndef AVUTIL_SHA512_H +#define AVUTIL_SHA512_H + +#include <stddef.h> +#include <stdint.h> + +#include "attributes.h" + +/** + * @defgroup lavu_sha512 SHA-512 + * @ingroup lavu_hash + * SHA-512 (Secure Hash Algorithm) hash function implementations. + * + * This module supports the following SHA-2 hash functions: + * + * - SHA-512/224: 224 bits + * - SHA-512/256: 256 bits + * - SHA-384: 384 bits + * - SHA-512: 512 bits + * + * @see For SHA-1, SHA-256, and variants thereof, see @ref lavu_sha. + * + * @{ + */ + +extern const int av_sha512_size; + +struct AVSHA512; + +/** + * Allocate an AVSHA512 context. + */ +struct AVSHA512 *av_sha512_alloc(void); + +/** + * Initialize SHA-2 512 hashing. + * + * @param context pointer to the function context (of size av_sha512_size) + * @param bits number of bits in digest (224, 256, 384 or 512 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha512_init(struct AVSHA512* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_sha512_update(struct AVSHA512* context, const uint8_t* data, size_t len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha512_final(struct AVSHA512* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA512_H */ diff --git a/libs/ffmpeg/libavutil/side_data.c b/libs/ffmpeg/libavutil/side_data.c new file mode 100644 index 00000000000..bbbeb70ecd1 --- /dev/null +++ b/libs/ffmpeg/libavutil/side_data.c @@ -0,0 +1,315 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avassert.h" +#include "buffer.h" +#include "common.h" +#include "dict.h" +#include "frame.h" +#include "mem.h" +#include "side_data.h" + +static const AVSideDataDescriptor sd_props[] = { + [AV_FRAME_DATA_PANSCAN] = { "AVPanScan", AV_SIDE_DATA_PROP_SIZE_DEPENDENT }, + [AV_FRAME_DATA_A53_CC] = { "ATSC A53 Part 4 Closed Captions" }, + [AV_FRAME_DATA_MATRIXENCODING] = { "AVMatrixEncoding", AV_SIDE_DATA_PROP_CHANNEL_DEPENDENT }, + [AV_FRAME_DATA_DOWNMIX_INFO] = { "Metadata relevant to a downmix procedure", AV_SIDE_DATA_PROP_CHANNEL_DEPENDENT }, + [AV_FRAME_DATA_AFD] = { "Active format description" }, + [AV_FRAME_DATA_MOTION_VECTORS] = { "Motion vectors", AV_SIDE_DATA_PROP_SIZE_DEPENDENT }, + [AV_FRAME_DATA_SKIP_SAMPLES] = { "Skip samples" }, + [AV_FRAME_DATA_GOP_TIMECODE] = { "GOP timecode" }, + [AV_FRAME_DATA_S12M_TIMECODE] = { "SMPTE 12-1 timecode" }, + [AV_FRAME_DATA_DYNAMIC_HDR_PLUS] = { "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)", AV_SIDE_DATA_PROP_COLOR_DEPENDENT }, + [AV_FRAME_DATA_DYNAMIC_HDR_VIVID] = { "HDR Dynamic Metadata CUVA 005.1 2021 (Vivid)", AV_SIDE_DATA_PROP_COLOR_DEPENDENT }, + [AV_FRAME_DATA_REGIONS_OF_INTEREST] = { "Regions Of Interest", AV_SIDE_DATA_PROP_SIZE_DEPENDENT }, + [AV_FRAME_DATA_VIDEO_ENC_PARAMS] = { "Video encoding parameters" }, + [AV_FRAME_DATA_FILM_GRAIN_PARAMS] = { "Film grain parameters" }, + [AV_FRAME_DATA_DETECTION_BBOXES] = { "Bounding boxes for object detection and classification", AV_SIDE_DATA_PROP_SIZE_DEPENDENT }, + [AV_FRAME_DATA_DOVI_RPU_BUFFER] = { "Dolby Vision RPU Data", AV_SIDE_DATA_PROP_COLOR_DEPENDENT }, + [AV_FRAME_DATA_DOVI_METADATA] = { "Dolby Vision Metadata", AV_SIDE_DATA_PROP_COLOR_DEPENDENT }, + [AV_FRAME_DATA_LCEVC] = { "LCEVC NAL data", AV_SIDE_DATA_PROP_SIZE_DEPENDENT }, + [AV_FRAME_DATA_VIEW_ID] = { "View ID" }, + [AV_FRAME_DATA_STEREO3D] = { "Stereo 3D", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_REPLAYGAIN] = { "AVReplayGain", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_DISPLAYMATRIX] = { "3x3 displaymatrix", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_AUDIO_SERVICE_TYPE] = { "Audio service type", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_MASTERING_DISPLAY_METADATA] = { "Mastering display metadata", AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT }, + [AV_FRAME_DATA_CONTENT_LIGHT_LEVEL] = { "Content light level metadata", AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT }, + [AV_FRAME_DATA_AMBIENT_VIEWING_ENVIRONMENT] = { "Ambient viewing environment", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_SPHERICAL] = { "Spherical Mapping", AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_SIZE_DEPENDENT }, + [AV_FRAME_DATA_ICC_PROFILE] = { "ICC profile", AV_SIDE_DATA_PROP_GLOBAL | AV_SIDE_DATA_PROP_COLOR_DEPENDENT }, + [AV_FRAME_DATA_EXIF] = { "EXIF metadata", AV_SIDE_DATA_PROP_GLOBAL }, + [AV_FRAME_DATA_SEI_UNREGISTERED] = { "H.26[45] User Data Unregistered SEI message", AV_SIDE_DATA_PROP_MULTI }, + [AV_FRAME_DATA_VIDEO_HINT] = { "Encoding video hint", AV_SIDE_DATA_PROP_SIZE_DEPENDENT }, + [AV_FRAME_DATA_3D_REFERENCE_DISPLAYS] = { "3D Reference Displays Information", AV_SIDE_DATA_PROP_GLOBAL }, +}; + +const AVSideDataDescriptor *av_frame_side_data_desc(enum AVFrameSideDataType type) +{ + unsigned t = type; + if (t < FF_ARRAY_ELEMS(sd_props) && sd_props[t].name) + return &sd_props[t]; + return NULL; +} + +const char *av_frame_side_data_name(enum AVFrameSideDataType type) +{ + const AVSideDataDescriptor *desc = av_frame_side_data_desc(type); + return desc ? desc->name : NULL; +} + +static void free_side_data_entry(AVFrameSideData **ptr_sd) +{ + AVFrameSideData *sd = *ptr_sd; + + av_buffer_unref(&sd->buf); + av_dict_free(&sd->metadata); + av_freep(ptr_sd); +} + +static void remove_side_data_by_entry(AVFrameSideData ***sd, int *nb_sd, + const AVFrameSideData *target) +{ + for (int i = *nb_sd - 1; i >= 0; i--) { + AVFrameSideData *entry = ((*sd)[i]); + if (entry != target) + continue; + + free_side_data_entry(&entry); + + ((*sd)[i]) = ((*sd)[*nb_sd - 1]); + (*nb_sd)--; + + return; + } +} + +void av_frame_side_data_remove(AVFrameSideData ***sd, int *nb_sd, + enum AVFrameSideDataType type) +{ + for (int i = *nb_sd - 1; i >= 0; i--) { + AVFrameSideData *entry = ((*sd)[i]); + if (entry->type != type) + continue; + + free_side_data_entry(&entry); + + ((*sd)[i]) = ((*sd)[*nb_sd - 1]); + (*nb_sd)--; + } +} + +void av_frame_side_data_remove_by_props(AVFrameSideData ***sd, int *nb_sd, + int props) +{ + for (int i = *nb_sd - 1; i >= 0; i--) { + AVFrameSideData *entry = ((*sd)[i]); + const AVSideDataDescriptor *desc = av_frame_side_data_desc(entry->type); + if (!desc || !(desc->props & props)) + continue; + + free_side_data_entry(&entry); + + ((*sd)[i]) = ((*sd)[*nb_sd - 1]); + (*nb_sd)--; + } +} + +void av_frame_side_data_free(AVFrameSideData ***sd, int *nb_sd) +{ + for (int i = 0; i < *nb_sd; i++) + free_side_data_entry(&((*sd)[i])); + *nb_sd = 0; + + av_freep(sd); +} + +static AVFrameSideData *add_side_data_from_buf_ext(AVFrameSideData ***sd, + int *nb_sd, + enum AVFrameSideDataType type, + AVBufferRef *buf, uint8_t *data, + size_t size) +{ + AVFrameSideData *ret, **tmp; + + // *nb_sd + 1 needs to fit into an int and a size_t. + if ((unsigned)*nb_sd >= FFMIN(INT_MAX, SIZE_MAX)) + return NULL; + + tmp = av_realloc_array(*sd, *nb_sd + 1, sizeof(**sd)); + if (!tmp) + return NULL; + *sd = tmp; + + ret = av_mallocz(sizeof(*ret)); + if (!ret) + return NULL; + + ret->buf = buf; + ret->data = data; + ret->size = size; + ret->type = type; + + (*sd)[(*nb_sd)++] = ret; + + return ret; +} + +AVFrameSideData *ff_frame_side_data_add_from_buf(AVFrameSideData ***sd, + int *nb_sd, + enum AVFrameSideDataType type, + AVBufferRef *buf) +{ + if (!buf) + return NULL; + + return add_side_data_from_buf_ext(sd, nb_sd, type, buf, buf->data, buf->size); +} + +static AVFrameSideData *replace_side_data_from_buf(AVFrameSideData *dst, + AVBufferRef *buf, int flags) +{ + if (!(flags & AV_FRAME_SIDE_DATA_FLAG_REPLACE)) + return NULL; + + av_dict_free(&dst->metadata); + av_buffer_unref(&dst->buf); + dst->buf = buf; + dst->data = buf->data; + dst->size = buf->size; + return dst; +} + +AVFrameSideData *av_frame_side_data_new(AVFrameSideData ***sd, int *nb_sd, + enum AVFrameSideDataType type, + size_t size, unsigned int flags) +{ + const AVSideDataDescriptor *desc = av_frame_side_data_desc(type); + AVBufferRef *buf = av_buffer_alloc(size); + AVFrameSideData *ret = NULL; + + if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE) + av_frame_side_data_remove(sd, nb_sd, type); + if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) && + (ret = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, type))) { + ret = replace_side_data_from_buf(ret, buf, flags); + if (!ret) + av_buffer_unref(&buf); + return ret; + } + + ret = ff_frame_side_data_add_from_buf(sd, nb_sd, type, buf); + if (!ret) + av_buffer_unref(&buf); + + return ret; +} + +AVFrameSideData *av_frame_side_data_add(AVFrameSideData ***sd, int *nb_sd, + enum AVFrameSideDataType type, + AVBufferRef **pbuf, unsigned int flags) +{ + const AVSideDataDescriptor *desc = av_frame_side_data_desc(type); + AVFrameSideData *sd_dst = NULL; + AVBufferRef *buf = *pbuf; + + if ((flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF) && !(buf = av_buffer_ref(*pbuf))) + return NULL; + if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE) + av_frame_side_data_remove(sd, nb_sd, type); + if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) && + (sd_dst = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, type))) { + sd_dst = replace_side_data_from_buf(sd_dst, buf, flags); + } else + sd_dst = ff_frame_side_data_add_from_buf(sd, nb_sd, type, buf); + + if (sd_dst && !(flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF)) + *pbuf = NULL; + else if (!sd_dst && (flags & AV_FRAME_SIDE_DATA_FLAG_NEW_REF)) + av_buffer_unref(&buf); + return sd_dst; +} + +int av_frame_side_data_clone(AVFrameSideData ***sd, int *nb_sd, + const AVFrameSideData *src, unsigned int flags) +{ + const AVSideDataDescriptor *desc; + AVBufferRef *buf = NULL; + AVFrameSideData *sd_dst = NULL; + int ret = AVERROR_BUG; + + if (!sd || !src || !nb_sd || (*nb_sd && !*sd)) + return AVERROR(EINVAL); + + desc = av_frame_side_data_desc(src->type); + if (flags & AV_FRAME_SIDE_DATA_FLAG_UNIQUE) + av_frame_side_data_remove(sd, nb_sd, src->type); + if ((!desc || !(desc->props & AV_SIDE_DATA_PROP_MULTI)) && + (sd_dst = (AVFrameSideData *)av_frame_side_data_get(*sd, *nb_sd, src->type))) { + AVDictionary *dict = NULL; + + if (!(flags & AV_FRAME_SIDE_DATA_FLAG_REPLACE)) + return AVERROR(EEXIST); + + ret = av_dict_copy(&dict, src->metadata, 0); + if (ret < 0) + return ret; + + ret = av_buffer_replace(&sd_dst->buf, src->buf); + if (ret < 0) { + av_dict_free(&dict); + return ret; + } + + av_dict_free(&sd_dst->metadata); + sd_dst->metadata = dict; + sd_dst->data = src->data; + sd_dst->size = src->size; + return 0; + } + + buf = av_buffer_ref(src->buf); + if (!buf) + return AVERROR(ENOMEM); + + sd_dst = add_side_data_from_buf_ext(sd, nb_sd, src->type, buf, + src->data, src->size); + if (!sd_dst) { + av_buffer_unref(&buf); + return AVERROR(ENOMEM); + } + + ret = av_dict_copy(&sd_dst->metadata, src->metadata, 0); + if (ret < 0) { + remove_side_data_by_entry(sd, nb_sd, sd_dst); + return ret; + } + + return 0; +} + +const AVFrameSideData *av_frame_side_data_get_c(const AVFrameSideData * const *sd, + const int nb_sd, + enum AVFrameSideDataType type) +{ + for (int i = 0; i < nb_sd; i++) { + if (sd[i]->type == type) + return sd[i]; + } + return NULL; +} diff --git a/libs/ffmpeg/libavutil/side_data.h b/libs/ffmpeg/libavutil/side_data.h new file mode 100644 index 00000000000..8275aa35a5c --- /dev/null +++ b/libs/ffmpeg/libavutil/side_data.h @@ -0,0 +1,30 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SIDE_DATA_H +#define AVUTIL_SIDE_DATA_H + +#include "buffer.h" +#include "frame.h" + +AVFrameSideData *ff_frame_side_data_add_from_buf(AVFrameSideData ***sd, + int *nb_sd, + enum AVFrameSideDataType type, + AVBufferRef *buf); + +#endif // AVUTIL_SIDE_DATA_H diff --git a/libs/ffmpeg/libavutil/slicethread.c b/libs/ffmpeg/libavutil/slicethread.c new file mode 100644 index 00000000000..7650fc66ad7 --- /dev/null +++ b/libs/ffmpeg/libavutil/slicethread.c @@ -0,0 +1,281 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdatomic.h> +#include "cpu.h" +#include "internal.h" +#include "slicethread.h" +#include "mem.h" +#include "thread.h" +#include "avassert.h" + +#define MAX_AUTO_THREADS 16 + +#if HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS2THREADS + +typedef struct WorkerContext { + AVSliceThread *ctx; + pthread_mutex_t mutex; + pthread_cond_t cond; + pthread_t thread; + int done; +} WorkerContext; + +struct AVSliceThread { + WorkerContext *workers; + int nb_threads; + int nb_active_threads; + int nb_jobs; + + atomic_uint first_job; + atomic_uint current_job; + pthread_mutex_t done_mutex; + pthread_cond_t done_cond; + int done; + int finished; + + void *priv; + void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads); + void (*main_func)(void *priv); +}; + +static int run_jobs(AVSliceThread *ctx) +{ + unsigned nb_jobs = ctx->nb_jobs; + unsigned nb_active_threads = ctx->nb_active_threads; + unsigned first_job = atomic_fetch_add_explicit(&ctx->first_job, 1, memory_order_acq_rel); + unsigned current_job = first_job; + + do { + ctx->worker_func(ctx->priv, current_job, first_job, nb_jobs, nb_active_threads); + } while ((current_job = atomic_fetch_add_explicit(&ctx->current_job, 1, memory_order_acq_rel)) < nb_jobs); + + return current_job == nb_jobs + nb_active_threads - 1; +} + +static void *attribute_align_arg thread_worker(void *v) +{ + WorkerContext *w = v; + AVSliceThread *ctx = w->ctx; + + pthread_mutex_lock(&w->mutex); + pthread_cond_signal(&w->cond); + + while (1) { + w->done = 1; + while (w->done) + pthread_cond_wait(&w->cond, &w->mutex); + + if (ctx->finished) { + pthread_mutex_unlock(&w->mutex); + return NULL; + } + + if (run_jobs(ctx)) { + pthread_mutex_lock(&ctx->done_mutex); + ctx->done = 1; + pthread_cond_signal(&ctx->done_cond); + pthread_mutex_unlock(&ctx->done_mutex); + } + } +} + +av_cold +int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, + void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads), + void (*main_func)(void *priv), + int nb_threads) +{ + AVSliceThread *ctx; + int nb_workers, i; + int ret; + + av_assert0(nb_threads >= 0); + if (!nb_threads) { + int nb_cpus = av_cpu_count(); + if (nb_cpus > 1) + nb_threads = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS); + else + nb_threads = 1; + } + + nb_workers = nb_threads; + if (!main_func) + nb_workers--; + + *pctx = ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return AVERROR(ENOMEM); + + if (nb_workers && !(ctx->workers = av_calloc(nb_workers, sizeof(*ctx->workers)))) { + av_freep(pctx); + return AVERROR(ENOMEM); + } + + ctx->priv = priv; + ctx->worker_func = worker_func; + ctx->main_func = main_func; + ctx->nb_threads = nb_threads; + ctx->nb_active_threads = 0; + ctx->nb_jobs = 0; + ctx->finished = 0; + + atomic_init(&ctx->first_job, 0); + atomic_init(&ctx->current_job, 0); + ret = pthread_mutex_init(&ctx->done_mutex, NULL); + if (ret) { + av_freep(&ctx->workers); + av_freep(pctx); + return AVERROR(ret); + } + ret = pthread_cond_init(&ctx->done_cond, NULL); + if (ret) { + ctx->nb_threads = main_func ? 0 : 1; + avpriv_slicethread_free(pctx); + return AVERROR(ret); + } + ctx->done = 0; + + for (i = 0; i < nb_workers; i++) { + WorkerContext *w = &ctx->workers[i]; + int ret; + w->ctx = ctx; + ret = pthread_mutex_init(&w->mutex, NULL); + if (ret) { + ctx->nb_threads = main_func ? i : i + 1; + avpriv_slicethread_free(pctx); + return AVERROR(ret); + } + ret = pthread_cond_init(&w->cond, NULL); + if (ret) { + pthread_mutex_destroy(&w->mutex); + ctx->nb_threads = main_func ? i : i + 1; + avpriv_slicethread_free(pctx); + return AVERROR(ret); + } + pthread_mutex_lock(&w->mutex); + w->done = 0; + + if (ret = pthread_create(&w->thread, NULL, thread_worker, w)) { + ctx->nb_threads = main_func ? i : i + 1; + pthread_mutex_unlock(&w->mutex); + pthread_cond_destroy(&w->cond); + pthread_mutex_destroy(&w->mutex); + avpriv_slicethread_free(pctx); + return AVERROR(ret); + } + + while (!w->done) + pthread_cond_wait(&w->cond, &w->mutex); + pthread_mutex_unlock(&w->mutex); + } + + return nb_threads; +} + +void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main) +{ + int nb_workers, i, is_last = 0; + + av_assert0(nb_jobs > 0); + ctx->nb_jobs = nb_jobs; + ctx->nb_active_threads = FFMIN(nb_jobs, ctx->nb_threads); + atomic_store_explicit(&ctx->first_job, 0, memory_order_relaxed); + atomic_store_explicit(&ctx->current_job, ctx->nb_active_threads, memory_order_relaxed); + nb_workers = ctx->nb_active_threads; + if (!ctx->main_func || !execute_main) + nb_workers--; + + for (i = 0; i < nb_workers; i++) { + WorkerContext *w = &ctx->workers[i]; + pthread_mutex_lock(&w->mutex); + w->done = 0; + pthread_cond_signal(&w->cond); + pthread_mutex_unlock(&w->mutex); + } + + if (ctx->main_func && execute_main) + ctx->main_func(ctx->priv); + else + is_last = run_jobs(ctx); + + if (!is_last) { + pthread_mutex_lock(&ctx->done_mutex); + while (!ctx->done) + pthread_cond_wait(&ctx->done_cond, &ctx->done_mutex); + ctx->done = 0; + pthread_mutex_unlock(&ctx->done_mutex); + } +} + +av_cold void avpriv_slicethread_free(AVSliceThread **pctx) +{ + AVSliceThread *ctx = *pctx; + int nb_workers, i; + + if (!ctx) + return; + + nb_workers = ctx->nb_threads; + if (!ctx->main_func) + nb_workers--; + + ctx->finished = 1; + for (i = 0; i < nb_workers; i++) { + WorkerContext *w = &ctx->workers[i]; + pthread_mutex_lock(&w->mutex); + w->done = 0; + pthread_cond_signal(&w->cond); + pthread_mutex_unlock(&w->mutex); + } + + for (i = 0; i < nb_workers; i++) { + WorkerContext *w = &ctx->workers[i]; + pthread_join(w->thread, NULL); + pthread_cond_destroy(&w->cond); + pthread_mutex_destroy(&w->mutex); + } + + pthread_cond_destroy(&ctx->done_cond); + pthread_mutex_destroy(&ctx->done_mutex); + av_freep(&ctx->workers); + av_freep(pctx); +} + +#else /* HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS32THREADS */ + +int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, + void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads), + void (*main_func)(void *priv), + int nb_threads) +{ + *pctx = NULL; + return AVERROR(ENOSYS); +} + +void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main) +{ + av_assert0(0); +} + +void avpriv_slicethread_free(AVSliceThread **pctx) +{ + av_assert0(!pctx || !*pctx); +} + +#endif /* HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS32THREADS */ diff --git a/libs/ffmpeg/libavutil/slicethread.h b/libs/ffmpeg/libavutil/slicethread.h new file mode 100644 index 00000000000..f6f6f302c44 --- /dev/null +++ b/libs/ffmpeg/libavutil/slicethread.h @@ -0,0 +1,52 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SLICETHREAD_H +#define AVUTIL_SLICETHREAD_H + +typedef struct AVSliceThread AVSliceThread; + +/** + * Create slice threading context. + * @param pctx slice threading context returned here + * @param priv private pointer to be passed to callback function + * @param worker_func callback function to be executed + * @param main_func special callback function, called from main thread, may be NULL + * @param nb_threads number of threads, 0 for automatic, must be >= 0 + * @return return number of threads or negative AVERROR on failure + */ +int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, + void (*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads), + void (*main_func)(void *priv), + int nb_threads); + +/** + * Execute slice threading. + * @param ctx slice threading context + * @param nb_jobs number of jobs, must be > 0 + * @param execute_main also execute main_func + */ +void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main); + +/** + * Destroy slice threading context. + * @param pctx pointer to context + */ +void avpriv_slicethread_free(AVSliceThread **pctx); + +#endif diff --git a/libs/ffmpeg/libavutil/spherical.c b/libs/ffmpeg/libavutil/spherical.c new file mode 100644 index 00000000000..71342faea9a --- /dev/null +++ b/libs/ffmpeg/libavutil/spherical.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016 Vittorio Giovara <vittorio.giovara@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avstring.h" +#include "macros.h" +#include "mem.h" +#include "spherical.h" + +AVSphericalMapping *av_spherical_alloc(size_t *size) +{ + AVSphericalMapping *spherical = av_mallocz(sizeof(AVSphericalMapping)); + if (!spherical) + return NULL; + + spherical->projection = AV_SPHERICAL_RECTILINEAR; + + if (size) + *size = sizeof(*spherical); + + return spherical; +} + +void av_spherical_tile_bounds(const AVSphericalMapping *map, + size_t width, size_t height, + size_t *left, size_t *top, + size_t *right, size_t *bottom) +{ + /* conversion from 0.32 coordinates to pixels */ + uint64_t orig_width = (uint64_t) width * UINT32_MAX / + (UINT32_MAX - map->bound_right - map->bound_left); + uint64_t orig_height = (uint64_t) height * UINT32_MAX / + (UINT32_MAX - map->bound_bottom - map->bound_top); + + /* add a (UINT32_MAX - 1) to round up integer division */ + *left = (orig_width * map->bound_left + UINT32_MAX - 1) / UINT32_MAX; + *top = (orig_height * map->bound_top + UINT32_MAX - 1) / UINT32_MAX; + *right = orig_width - width - *left; + *bottom = orig_height - height - *top; +} + +static const char *const spherical_projection_names[] = { + [AV_SPHERICAL_EQUIRECTANGULAR] = "equirectangular", + [AV_SPHERICAL_CUBEMAP] = "cubemap", + [AV_SPHERICAL_EQUIRECTANGULAR_TILE] = "tiled equirectangular", + [AV_SPHERICAL_HALF_EQUIRECTANGULAR] = "half equirectangular", + [AV_SPHERICAL_RECTILINEAR] = "rectilinear", + [AV_SPHERICAL_FISHEYE] = "fisheye", + [AV_SPHERICAL_PARAMETRIC_IMMERSIVE] = "parametric immersive", +}; + +const char *av_spherical_projection_name(enum AVSphericalProjection projection) +{ + if ((unsigned)projection >= FF_ARRAY_ELEMS(spherical_projection_names)) + return "unknown"; + + return spherical_projection_names[projection]; +} + +int av_spherical_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(spherical_projection_names); i++) { + if (av_strstart(name, spherical_projection_names[i], NULL)) + return i; + } + + return -1; +} diff --git a/libs/ffmpeg/libavutil/spherical.h b/libs/ffmpeg/libavutil/spherical.h new file mode 100644 index 00000000000..4b78978eb94 --- /dev/null +++ b/libs/ffmpeg/libavutil/spherical.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2016 Vittorio Giovara <vittorio.giovara@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_video_spherical + * Spherical video + */ + +#ifndef AVUTIL_SPHERICAL_H +#define AVUTIL_SPHERICAL_H + +#include <stddef.h> +#include <stdint.h> + +/** + * @defgroup lavu_video_spherical Spherical video mapping + * @ingroup lavu_video + * + * A spherical video file contains surfaces that need to be mapped onto a + * sphere. Depending on how the frame was converted, a different distortion + * transformation or surface recomposition function needs to be applied before + * the video should be mapped and displayed. + * @{ + */ + +/** + * Projection of the video surface(s) on a sphere. + */ +enum AVSphericalProjection { + /** + * Video represents a sphere mapped on a flat surface using + * equirectangular projection. + */ + AV_SPHERICAL_EQUIRECTANGULAR, + + /** + * Video frame is split into 6 faces of a cube, and arranged on a + * 3x2 layout. Faces are oriented upwards for the front, left, right, + * and back faces. The up face is oriented so the top of the face is + * forwards and the down face is oriented so the top of the face is + * to the back. + */ + AV_SPHERICAL_CUBEMAP, + + /** + * Video represents a portion of a sphere mapped on a flat surface + * using equirectangular projection. The @ref bounding fields indicate + * the position of the current video in a larger surface. + */ + AV_SPHERICAL_EQUIRECTANGULAR_TILE, + + /** + * Video frame displays as a 180 degree equirectangular projection. + */ + AV_SPHERICAL_HALF_EQUIRECTANGULAR, + + /** + * Video frame displays on a flat, rectangular 2D surface. + */ + AV_SPHERICAL_RECTILINEAR, + + /** + * Fisheye projection (Apple). + * See: https://developer.apple.com/documentation/coremedia/cmprojectiontype/fisheye + */ + AV_SPHERICAL_FISHEYE, + + /** + * Parametric Immersive projection (Apple). + * See: https://developer.apple.com/documentation/coremedia/cmprojectiontype/paramet... + */ + AV_SPHERICAL_PARAMETRIC_IMMERSIVE, +}; + +/** + * This structure describes how to handle spherical videos, outlining + * information about projection, initial layout, and any other view modifier. + * + * @note The struct must be allocated with av_spherical_alloc() and + * its size is not a part of the public ABI. + */ +typedef struct AVSphericalMapping { + /** + * Projection type. + */ + enum AVSphericalProjection projection; + + /** + * @name Initial orientation + * @{ + * There fields describe additional rotations applied to the sphere after + * the video frame is mapped onto it. The sphere is rotated around the + * viewer, who remains stationary. The order of transformation is always + * yaw, followed by pitch, and finally by roll. + * + * The coordinate system matches the one defined in OpenGL, where the + * forward vector (z) is coming out of screen, and it is equivalent to + * a rotation matrix of R = r_y(yaw) * r_x(pitch) * r_z(roll). + * + * A positive yaw rotates the portion of the sphere in front of the viewer + * toward their right. A positive pitch rotates the portion of the sphere + * in front of the viewer upwards. A positive roll tilts the portion of + * the sphere in front of the viewer to the viewer's right. + * + * These values are exported as 16.16 fixed point. + * + * See this equirectangular projection as example: + * + * @code{.unparsed} + * Yaw + * -180 0 180 + * 90 +-------------+-------------+ 180 + * | | | up + * P | | | y| forward + * i | ^ | | /z + * t 0 +-------------X-------------+ 0 Roll | / + * c | | | | / + * h | | | 0|/_____right + * | | | x + * -90 +-------------+-------------+ -180 + * + * X - the default camera center + * ^ - the default up vector + * @endcode + */ + int32_t yaw; ///< Rotation around the up vector [-180, 180]. + int32_t pitch; ///< Rotation around the right vector [-90, 90]. + int32_t roll; ///< Rotation around the forward vector [-180, 180]. + /** + * @} + */ + + /** + * @name Bounding rectangle + * @anchor bounding + * @{ + * These fields indicate the location of the current tile, and where + * it should be mapped relative to the original surface. They are + * exported as 0.32 fixed point, and can be converted to classic + * pixel values with av_spherical_bounds(). + * + * @code{.unparsed} + * +----------------+----------+ + * | |bound_top | + * | +--------+ | + * | bound_left |tile | | + * +<---------->| |<--->+bound_right + * | +--------+ | + * | | | + * | bound_bottom| | + * +----------------+----------+ + * @endcode + * + * If needed, the original video surface dimensions can be derived + * by adding the current stream or frame size to the related bounds, + * like in the following example: + * + * @code{c} + * original_width = tile->width + bound_left + bound_right; + * original_height = tile->height + bound_top + bound_bottom; + * @endcode + * + * @note These values are valid only for the tiled equirectangular + * projection type (@ref AV_SPHERICAL_EQUIRECTANGULAR_TILE), + * and should be ignored in all other cases. + */ + uint32_t bound_left; ///< Distance from the left edge + uint32_t bound_top; ///< Distance from the top edge + uint32_t bound_right; ///< Distance from the right edge + uint32_t bound_bottom; ///< Distance from the bottom edge + /** + * @} + */ + + /** + * Number of pixels to pad from the edge of each cube face. + * + * @note This value is valid for only for the cubemap projection type + * (@ref AV_SPHERICAL_CUBEMAP), and should be ignored in all other + * cases. + */ + uint32_t padding; +} AVSphericalMapping; + +/** + * Allocate a AVSphericalVideo structure and initialize its fields to default + * values. + * + * @return the newly allocated struct or NULL on failure + */ +AVSphericalMapping *av_spherical_alloc(size_t *size); + +/** + * Convert the @ref bounding fields from an AVSphericalVideo + * from 0.32 fixed point to pixels. + * + * @param map The AVSphericalVideo map to read bound values from. + * @param width Width of the current frame or stream. + * @param height Height of the current frame or stream. + * @param left Pixels from the left edge. + * @param top Pixels from the top edge. + * @param right Pixels from the right edge. + * @param bottom Pixels from the bottom edge. + */ +void av_spherical_tile_bounds(const AVSphericalMapping *map, + size_t width, size_t height, + size_t *left, size_t *top, + size_t *right, size_t *bottom); + +/** + * Provide a human-readable name of a given AVSphericalProjection. + * + * @param projection The input AVSphericalProjection. + * + * @return The name of the AVSphericalProjection, or "unknown". + */ +const char *av_spherical_projection_name(enum AVSphericalProjection projection); + +/** + * Get the AVSphericalProjection form a human-readable name. + * + * @param name The input string. + * + * @return The AVSphericalProjection value, or -1 if not found. + */ +int av_spherical_from_name(const char *name); +/** + * @} + */ + +#endif /* AVUTIL_SPHERICAL_H */ diff --git a/libs/ffmpeg/libavutil/stereo3d.c b/libs/ffmpeg/libavutil/stereo3d.c new file mode 100644 index 00000000000..d6de4765328 --- /dev/null +++ b/libs/ffmpeg/libavutil/stereo3d.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2013 Vittorio Giovara <vittorio.giovara@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> + +#include "avstring.h" +#include "frame.h" +#include "macros.h" +#include "mem.h" +#include "stereo3d.h" + +static void get_defaults(AVStereo3D *stereo) +{ + stereo->horizontal_disparity_adjustment = (AVRational) { 0, 1 }; + stereo->horizontal_field_of_view = (AVRational) { 0, 1 }; +} + +AVStereo3D *av_stereo3d_alloc(void) +{ + return av_stereo3d_alloc_size(NULL); +} + +AVStereo3D *av_stereo3d_alloc_size(size_t *size) +{ + AVStereo3D *stereo = av_mallocz(sizeof(AVStereo3D)); + if (!stereo) + return NULL; + + get_defaults(stereo); + + if (size) + *size = sizeof(*stereo); + + return stereo; +} + +AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame) +{ + AVFrameSideData *side_data = av_frame_new_side_data(frame, + AV_FRAME_DATA_STEREO3D, + sizeof(AVStereo3D)); + if (!side_data) + return NULL; + + memset(side_data->data, 0, sizeof(AVStereo3D)); + get_defaults((AVStereo3D *)side_data->data); + + return (AVStereo3D *)side_data->data; +} + +static const char * const stereo3d_type_names[] = { + [AV_STEREO3D_2D] = "2D", + [AV_STEREO3D_SIDEBYSIDE] = "side by side", + [AV_STEREO3D_TOPBOTTOM] = "top and bottom", + [AV_STEREO3D_FRAMESEQUENCE] = "frame alternate", + [AV_STEREO3D_CHECKERBOARD] = "checkerboard", + [AV_STEREO3D_SIDEBYSIDE_QUINCUNX] = "side by side (quincunx subsampling)", + [AV_STEREO3D_LINES] = "interleaved lines", + [AV_STEREO3D_COLUMNS] = "interleaved columns", + [AV_STEREO3D_UNSPEC] = "unspecified", +}; + +static const char * const stereo3d_view_names[] = { + [AV_STEREO3D_VIEW_PACKED] = "packed", + [AV_STEREO3D_VIEW_LEFT] = "left", + [AV_STEREO3D_VIEW_RIGHT] = "right", + [AV_STEREO3D_VIEW_UNSPEC] = "unspecified", +}; + +static const char * const stereo3d_primary_eye_names[] = { + [AV_PRIMARY_EYE_NONE] = "none", + [AV_PRIMARY_EYE_LEFT] = "left", + [AV_PRIMARY_EYE_RIGHT] = "right", +}; + +const char *av_stereo3d_type_name(unsigned int type) +{ + if (type >= FF_ARRAY_ELEMS(stereo3d_type_names)) + return "unknown"; + + return stereo3d_type_names[type]; +} + +int av_stereo3d_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(stereo3d_type_names); i++) { + if (av_strstart(name, stereo3d_type_names[i], NULL)) + return i; + } + + return -1; +} + +const char *av_stereo3d_view_name(unsigned int view) +{ + if (view >= FF_ARRAY_ELEMS(stereo3d_view_names)) + return "unknown"; + + return stereo3d_view_names[view]; +} + +int av_stereo3d_view_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(stereo3d_view_names); i++) { + if (av_strstart(name, stereo3d_view_names[i], NULL)) + return i; + } + + return -1; +} + +const char *av_stereo3d_primary_eye_name(unsigned int eye) +{ + if (eye >= FF_ARRAY_ELEMS(stereo3d_primary_eye_names)) + return "unknown"; + + return stereo3d_primary_eye_names[eye]; +} + +int av_stereo3d_primary_eye_from_name(const char *name) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(stereo3d_primary_eye_names); i++) { + if (av_strstart(name, stereo3d_primary_eye_names[i], NULL)) + return i; + } + + return -1; +} diff --git a/libs/ffmpeg/libavutil/stereo3d.h b/libs/ffmpeg/libavutil/stereo3d.h new file mode 100644 index 00000000000..c0a4ab3f2d3 --- /dev/null +++ b/libs/ffmpeg/libavutil/stereo3d.h @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2013 Vittorio Giovara <vittorio.giovara@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_video_stereo3d + * Stereoscopic video + */ + +#ifndef AVUTIL_STEREO3D_H +#define AVUTIL_STEREO3D_H + +#include <stdint.h> + +#include "frame.h" + +/** + * @defgroup lavu_video_stereo3d Stereo3D types and functions + * @ingroup lavu_video + * + * A stereoscopic video file consists in multiple views embedded in a single + * frame, usually describing two views of a scene. This file describes all + * possible codec-independent view arrangements. + * + * @{ + */ + +/** + * List of possible 3D Types + */ +enum AVStereo3DType { + /** + * Video is not stereoscopic (and metadata has to be there). + */ + AV_STEREO3D_2D, + + /** + * Views are next to each other. + * + * @code{.unparsed} + * LLLLRRRR + * LLLLRRRR + * LLLLRRRR + * ... + * @endcode + */ + AV_STEREO3D_SIDEBYSIDE, + + /** + * Views are on top of each other. + * + * @code{.unparsed} + * LLLLLLLL + * LLLLLLLL + * RRRRRRRR + * RRRRRRRR + * @endcode + */ + AV_STEREO3D_TOPBOTTOM, + + /** + * Views are alternated temporally. + * + * @code{.unparsed} + * frame0 frame1 frame2 ... + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * ... ... ... + * @endcode + */ + AV_STEREO3D_FRAMESEQUENCE, + + /** + * Views are packed in a checkerboard-like structure per pixel. + * + * @code{.unparsed} + * LRLRLRLR + * RLRLRLRL + * LRLRLRLR + * ... + * @endcode + */ + AV_STEREO3D_CHECKERBOARD, + + /** + * Views are next to each other, but when upscaling + * apply a checkerboard pattern. + * + * @code{.unparsed} + * LLLLRRRR L L L L R R R R + * LLLLRRRR => L L L L R R R R + * LLLLRRRR L L L L R R R R + * LLLLRRRR L L L L R R R R + * @endcode + */ + AV_STEREO3D_SIDEBYSIDE_QUINCUNX, + + /** + * Views are packed per line, as if interlaced. + * + * @code{.unparsed} + * LLLLLLLL + * RRRRRRRR + * LLLLLLLL + * ... + * @endcode + */ + AV_STEREO3D_LINES, + + /** + * Views are packed per column. + * + * @code{.unparsed} + * LRLRLRLR + * LRLRLRLR + * LRLRLRLR + * ... + * @endcode + */ + AV_STEREO3D_COLUMNS, + + /** + * Video is stereoscopic but the packing is unspecified. + */ + AV_STEREO3D_UNSPEC, +}; + +/** + * List of possible view types. + */ +enum AVStereo3DView { + /** + * Frame contains two packed views. + */ + AV_STEREO3D_VIEW_PACKED, + + /** + * Frame contains only the left view. + */ + AV_STEREO3D_VIEW_LEFT, + + /** + * Frame contains only the right view. + */ + AV_STEREO3D_VIEW_RIGHT, + + /** + * Content is unspecified. + */ + AV_STEREO3D_VIEW_UNSPEC, +}; + +/** + * List of possible primary eyes. + */ +enum AVStereo3DPrimaryEye { + /** + * Neither eye. + */ + AV_PRIMARY_EYE_NONE, + + /** + * Left eye. + */ + AV_PRIMARY_EYE_LEFT, + + /** + * Right eye + */ + AV_PRIMARY_EYE_RIGHT, +}; + +/** + * Inverted views, Right/Bottom represents the left view. + */ +#define AV_STEREO3D_FLAG_INVERT (1 << 0) + +/** + * Stereo 3D type: this structure describes how two videos are packed + * within a single video surface, with additional information as needed. + * + * @note The struct must be allocated with av_stereo3d_alloc() and + * its size is not a part of the public ABI. + */ +typedef struct AVStereo3D { + /** + * How views are packed within the video. + */ + enum AVStereo3DType type; + + /** + * Additional information about the frame packing. + */ + int flags; + + /** + * Determines which views are packed. + */ + enum AVStereo3DView view; + + /** + * Which eye is the primary eye when rendering in 2D. + */ + enum AVStereo3DPrimaryEye primary_eye; + + /** + * The distance between the centres of the lenses of the camera system, + * in micrometers. Zero if unset. + */ + uint32_t baseline; + + /** + * Relative shift of the left and right images, which changes the zero parallax plane. + * Range is -1.0 to 1.0. Zero if unset. + */ + AVRational horizontal_disparity_adjustment; + + /** + * Horizontal field of view, in degrees. Zero if unset. + */ + AVRational horizontal_field_of_view; +} AVStereo3D; + +/** + * Allocate an AVStereo3D structure and set its fields to default values. + * The resulting struct can be freed using av_freep(). + * + * @return An AVStereo3D filled with default values or NULL on failure. + */ +AVStereo3D *av_stereo3d_alloc(void); + +/** + * Allocate an AVStereo3D structure and set its fields to default values. + * The resulting struct can be freed using av_freep(). + * + * @return An AVStereo3D filled with default values or NULL on failure. + */ +AVStereo3D *av_stereo3d_alloc_size(size_t *size); + +/** + * Allocate a complete AVFrameSideData and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVStereo3D structure to be filled by caller. + */ +AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame); + +/** + * Provide a human-readable name of a given stereo3d type. + * + * @param type The input stereo3d type value. + * + * @return The name of the stereo3d value, or "unknown". + */ +const char *av_stereo3d_type_name(unsigned int type); + +/** + * Get the AVStereo3DType form a human-readable name. + * + * @param name The input string. + * + * @return The AVStereo3DType value, or -1 if not found. + */ +int av_stereo3d_from_name(const char *name); + +/** + * Provide a human-readable name of a given stereo3d view. + * + * @param type The input stereo3d view value. + * + * @return The name of the stereo3d view value, or "unknown". + */ +const char *av_stereo3d_view_name(unsigned int view); + +/** + * Get the AVStereo3DView form a human-readable name. + * + * @param name The input string. + * + * @return The AVStereo3DView value, or -1 if not found. + */ +int av_stereo3d_view_from_name(const char *name); + +/** + * Provide a human-readable name of a given stereo3d primary eye. + * + * @param type The input stereo3d primary eye value. + * + * @return The name of the stereo3d primary eye value, or "unknown". + */ +const char *av_stereo3d_primary_eye_name(unsigned int eye); + +/** + * Get the AVStereo3DPrimaryEye form a human-readable name. + * + * @param name The input string. + * + * @return The AVStereo3DPrimaryEye value, or -1 if not found. + */ +int av_stereo3d_primary_eye_from_name(const char *name); + +/** + * @} + */ + +#endif /* AVUTIL_STEREO3D_H */ diff --git a/libs/ffmpeg/libavutil/tdrdi.c b/libs/ffmpeg/libavutil/tdrdi.c new file mode 100644 index 00000000000..26192a1d2f5 --- /dev/null +++ b/libs/ffmpeg/libavutil/tdrdi.c @@ -0,0 +1,51 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stddef.h> +#include <stdint.h> + +#include "mem.h" +#include "tdrdi.h" + +AV3DReferenceDisplaysInfo *av_tdrdi_alloc(unsigned int nb_displays, size_t *out_size) +{ + struct TestStruct { + AV3DReferenceDisplaysInfo p; + AV3DReferenceDisplay b; + }; + const size_t entries_offset = offsetof(struct TestStruct, b); + size_t size = entries_offset; + AV3DReferenceDisplaysInfo *tdrdi; + + if (nb_displays > (SIZE_MAX - size) / sizeof(AV3DReferenceDisplay)) + return NULL; + size += sizeof(AV3DReferenceDisplay) * nb_displays; + + tdrdi = av_mallocz(size); + if (!tdrdi) + return NULL; + + tdrdi->num_ref_displays = nb_displays; + tdrdi->entry_size = sizeof(AV3DReferenceDisplay); + tdrdi->entries_offset = entries_offset; + + if (out_size) + *out_size = size; + + return tdrdi; +} diff --git a/libs/ffmpeg/libavutil/tdrdi.h b/libs/ffmpeg/libavutil/tdrdi.h new file mode 100644 index 00000000000..8629775a2b5 --- /dev/null +++ b/libs/ffmpeg/libavutil/tdrdi.h @@ -0,0 +1,164 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_video_3d_reference_displays_info + * Spherical video + */ + +#ifndef AVUTIL_TDRDI_H +#define AVUTIL_TDRDI_H + +#include <stddef.h> +#include <stdint.h> + +#include "libavutil/avassert.h" + +/** + * @defgroup lavu_video_3d_reference_displays_info 3D Reference Displays Information + * @ingroup lavu_video + * + * The 3D Reference Displays Information describes information about the reference display + * width(s) and reference viewing distance(s) as well as information about the corresponding + * reference stereo pair(s). + * @{ + */ + +#define AV_TDRDI_MAX_NUM_REF_DISPLAY 32 + +/** + * This structure describes information about the reference display width(s) and reference + * viewing distance(s) as well as information about the corresponding reference stereo pair(s). + * See section G.14.3.2.3 of ITU-T H.265 for more information. + * + * @note The struct must be allocated with av_tdrdi_alloc() and + * its size is not a part of the public ABI. + */ +typedef struct AV3DReferenceDisplaysInfo { + /** + * The exponent of the maximum allowable truncation error for + * {exponent,mantissa}_ref_display_width as given by 2<sup>(-prec_ref_display_width)</sup>. + */ + uint8_t prec_ref_display_width; + + /** + * A flag to indicate the presence of reference viewing distance. + * If false, the values of prec_ref_viewing_dist, exponent_ref_viewing_distance, + * and mantissa_ref_viewing_distance are undefined. + */ + uint8_t ref_viewing_distance_flag; + + /** + * The exponent of the maximum allowable truncation error for + * {exponent,mantissa}_ref_viewing_distance as given by 2<sup>^(-prec_ref_viewing_dist)</sup>. + * The value of prec_ref_viewing_dist shall be in the range of 0 to 31, inclusive. + */ + uint8_t prec_ref_viewing_dist; + + /** + * The number of reference displays that are signalled in this struct. + * Allowed range is 1 to 32, inclusive. + */ + uint8_t num_ref_displays; + + /** + * Offset in bytes from the beginning of this structure at which the array + * of reference displays starts. + */ + size_t entries_offset; + + /** + * Size of each entry in bytes. May not match sizeof(AV3DReferenceDisplay). + */ + size_t entry_size; +} AV3DReferenceDisplaysInfo; + +/** + * Data structure for single deference display information. + * It is allocated as a part of AV3DReferenceDisplaysInfo and should be retrieved with + * av_tdrdi_get_display(). + * + * sizeof(AV3DReferenceDisplay) is not a part of the ABI and new fields may be + * added to it. +*/ +typedef struct AV3DReferenceDisplay { + /** + * The ViewId of the left view of a stereo pair corresponding to the n-th reference display. + */ + uint16_t left_view_id; + + /** + * The ViewId of the left view of a stereo pair corresponding to the n-th reference display. + */ + uint16_t right_view_id; + + /** + * The exponent part of the reference display width of the n-th reference display. + */ + uint8_t exponent_ref_display_width; + + /** + * The mantissa part of the reference display width of the n-th reference display. + */ + uint8_t mantissa_ref_display_width; + + /** + * The exponent part of the reference viewing distance of the n-th reference display. + */ + uint8_t exponent_ref_viewing_distance; + + /** + * The mantissa part of the reference viewing distance of the n-th reference display. + */ + uint8_t mantissa_ref_viewing_distance; + + /** + * An array of flags to indicates that the information about additional horizontal shift of + * the left and right views for the n-th reference display is present. + */ + uint8_t additional_shift_present_flag; + + /** + * The recommended additional horizontal shift for a stereo pair corresponding to the n-th + * reference baseline and the n-th reference display. + */ + int16_t num_sample_shift; +} AV3DReferenceDisplay; + +static av_always_inline AV3DReferenceDisplay* +av_tdrdi_get_display(AV3DReferenceDisplaysInfo *tdrdi, unsigned int idx) +{ + av_assert0(idx < tdrdi->num_ref_displays); + return (AV3DReferenceDisplay *)((uint8_t *)tdrdi + tdrdi->entries_offset + + idx * tdrdi->entry_size); +} + +/** + * Allocate a AV3DReferenceDisplaysInfo structure and initialize its fields to default + * values. + * + * @return the newly allocated struct or NULL on failure + */ +AV3DReferenceDisplaysInfo *av_tdrdi_alloc(unsigned int nb_displays, size_t *size); + +/** + * @} + */ + +#endif /* AVUTIL_TDRDI_H */ diff --git a/libs/ffmpeg/libavutil/tea.c b/libs/ffmpeg/libavutil/tea.c new file mode 100644 index 00000000000..93a3795368e --- /dev/null +++ b/libs/ffmpeg/libavutil/tea.c @@ -0,0 +1,121 @@ +/* + * A 32-bit implementation of the TEA algorithm + * Copyright (c) 2015 Vesselin Bontchev + * + * Loosely based on the implementation of David Wheeler and Roger Needham, + * https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm#Reference_code + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> +#include "intreadwrite.h" +#include "mem.h" +#include "tea.h" + +typedef struct AVTEA { + uint32_t key[16]; + int rounds; +} AVTEA; + +struct AVTEA *av_tea_alloc(void) +{ + return av_mallocz(sizeof(struct AVTEA)); +} + +const int av_tea_size = sizeof(AVTEA); + +void av_tea_init(AVTEA *ctx, const uint8_t key[16], int rounds) +{ + int i; + + for (i = 0; i < 4; i++) + ctx->key[i] = AV_RB32(key + (i << 2)); + + ctx->rounds = rounds; +} + +static void tea_crypt_ecb(AVTEA *ctx, uint8_t *dst, const uint8_t *src, + int decrypt, uint8_t *iv) +{ + uint32_t v0, v1; + int rounds = ctx->rounds; + uint32_t k0, k1, k2, k3; + k0 = ctx->key[0]; + k1 = ctx->key[1]; + k2 = ctx->key[2]; + k3 = ctx->key[3]; + + v0 = AV_RB32(src); + v1 = AV_RB32(src + 4); + + if (decrypt) { + int i; + uint32_t delta = 0x9E3779B9U, sum = delta * (rounds / 2); + + for (i = 0; i < rounds / 2; i++) { + v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3); + v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1); + sum -= delta; + } + if (iv) { + v0 ^= AV_RB32(iv); + v1 ^= AV_RB32(iv + 4); + memcpy(iv, src, 8); + } + } else { + int i; + uint32_t sum = 0, delta = 0x9E3779B9U; + + for (i = 0; i < rounds / 2; i++) { + sum += delta; + v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1); + v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3); + } + } + + AV_WB32(dst, v0); + AV_WB32(dst + 4, v1); +} + +void av_tea_crypt(AVTEA *ctx, uint8_t *dst, const uint8_t *src, int count, + uint8_t *iv, int decrypt) +{ + int i; + + if (decrypt) { + while (count--) { + tea_crypt_ecb(ctx, dst, src, decrypt, iv); + + src += 8; + dst += 8; + } + } else { + while (count--) { + if (iv) { + for (i = 0; i < 8; i++) + dst[i] = src[i] ^ iv[i]; + tea_crypt_ecb(ctx, dst, dst, decrypt, NULL); + memcpy(iv, dst, 8); + } else { + tea_crypt_ecb(ctx, dst, src, decrypt, NULL); + } + src += 8; + dst += 8; + } + } +} diff --git a/libs/ffmpeg/libavutil/tea.h b/libs/ffmpeg/libavutil/tea.h new file mode 100644 index 00000000000..dd929bdafdc --- /dev/null +++ b/libs/ffmpeg/libavutil/tea.h @@ -0,0 +1,71 @@ +/* + * A 32-bit implementation of the TEA algorithm + * Copyright (c) 2015 Vesselin Bontchev + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TEA_H +#define AVUTIL_TEA_H + +#include <stdint.h> + +/** + * @file + * @brief Public header for libavutil TEA algorithm + * @defgroup lavu_tea TEA + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_tea_size; + +struct AVTEA; + +/** + * Allocate an AVTEA context + * To free the struct: av_free(ptr) + */ +struct AVTEA *av_tea_alloc(void); + +/** + * Initialize an AVTEA context. + * + * @param ctx an AVTEA context + * @param key a key of 16 bytes used for encryption/decryption + * @param rounds the number of rounds in TEA (64 is the "standard") + */ +void av_tea_init(struct AVTEA *ctx, const uint8_t key[16], int rounds); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_tea_crypt(struct AVTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_TEA_H */ diff --git a/libs/ffmpeg/libavutil/thread.h b/libs/ffmpeg/libavutil/thread.h new file mode 100644 index 00000000000..184e2d8c5f6 --- /dev/null +++ b/libs/ffmpeg/libavutil/thread.h @@ -0,0 +1,241 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// This header should only be used to simplify code where +// threading is optional, not as a generic threading abstraction. + +#ifndef AVUTIL_THREAD_H +#define AVUTIL_THREAD_H + +#include "config.h" + +#if HAVE_PRCTL +#include <sys/prctl.h> +#elif (HAVE_PTHREAD_SETNAME_NP || HAVE_PTHREAD_SET_NAME_NP) && HAVE_PTHREAD_NP_H +#include <pthread_np.h> +#endif + +#include "error.h" + +#if HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS2THREADS + +#if HAVE_PTHREADS +#include <pthread.h> + +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 + +#include <stdlib.h> + +#include "log.h" +#include "macros.h" + +#define ASSERT_PTHREAD_ABORT(func, ret) do { \ + char errbuf[AV_ERROR_MAX_STRING_SIZE] = ""; \ + av_log(NULL, AV_LOG_FATAL, AV_STRINGIFY(func) \ + " failed with error: %s\n", \ + av_make_error_string(errbuf, AV_ERROR_MAX_STRING_SIZE, \ + AVERROR(ret))); \ + abort(); \ +} while (0) + +#define ASSERT_PTHREAD_NORET(func, ...) do { \ + int ret = func(__VA_ARGS__); \ + if (ret) \ + ASSERT_PTHREAD_ABORT(func, ret); \ +} while (0) + +#define ASSERT_PTHREAD(func, ...) do { \ + ASSERT_PTHREAD_NORET(func, __VA_ARGS__); \ + return 0; \ +} while (0) + +static inline int strict_pthread_join(pthread_t thread, void **value_ptr) +{ + ASSERT_PTHREAD(pthread_join, thread, value_ptr); +} + +static inline int strict_pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) +{ + if (attr) { + ASSERT_PTHREAD_NORET(pthread_mutex_init, mutex, attr); + } else { + pthread_mutexattr_t local_attr; + ASSERT_PTHREAD_NORET(pthread_mutexattr_init, &local_attr); + ASSERT_PTHREAD_NORET(pthread_mutexattr_settype, &local_attr, PTHREAD_MUTEX_ERRORCHECK); + ASSERT_PTHREAD_NORET(pthread_mutex_init, mutex, &local_attr); + ASSERT_PTHREAD_NORET(pthread_mutexattr_destroy, &local_attr); + } + return 0; +} + +static inline int strict_pthread_mutex_destroy(pthread_mutex_t *mutex) +{ + ASSERT_PTHREAD(pthread_mutex_destroy, mutex); +} + +static inline int strict_pthread_mutex_lock(pthread_mutex_t *mutex) +{ + ASSERT_PTHREAD(pthread_mutex_lock, mutex); +} + +static inline int strict_pthread_mutex_unlock(pthread_mutex_t *mutex) +{ + ASSERT_PTHREAD(pthread_mutex_unlock, mutex); +} + +static inline int strict_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) +{ + ASSERT_PTHREAD(pthread_cond_init, cond, attr); +} + +static inline int strict_pthread_cond_destroy(pthread_cond_t *cond) +{ + ASSERT_PTHREAD(pthread_cond_destroy, cond); +} + +static inline int strict_pthread_cond_signal(pthread_cond_t *cond) +{ + ASSERT_PTHREAD(pthread_cond_signal, cond); +} + +static inline int strict_pthread_cond_broadcast(pthread_cond_t *cond) +{ + ASSERT_PTHREAD(pthread_cond_broadcast, cond); +} + +static inline int strict_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + ASSERT_PTHREAD(pthread_cond_wait, cond, mutex); +} + +static inline int strict_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + int ret = pthread_cond_timedwait(cond, mutex, abstime); + if (ret && ret != ETIMEDOUT) + ASSERT_PTHREAD_ABORT(pthread_cond_timedwait, ret); + return ret; +} + +static inline int strict_pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) +{ + ASSERT_PTHREAD(pthread_once, once_control, init_routine); +} + +#define pthread_join strict_pthread_join +#define pthread_mutex_init strict_pthread_mutex_init +#define pthread_mutex_destroy strict_pthread_mutex_destroy +#define pthread_mutex_lock strict_pthread_mutex_lock +#define pthread_mutex_unlock strict_pthread_mutex_unlock +#define pthread_cond_init strict_pthread_cond_init +#define pthread_cond_destroy strict_pthread_cond_destroy +#define pthread_cond_signal strict_pthread_cond_signal +#define pthread_cond_broadcast strict_pthread_cond_broadcast +#define pthread_cond_wait strict_pthread_cond_wait +#define pthread_cond_timedwait strict_pthread_cond_timedwait +#define pthread_once strict_pthread_once +#endif + +#elif HAVE_OS2THREADS +#include "compat/os2threads.h" +#else +#include "compat/w32pthreads.h" +#endif + +#define AVMutex pthread_mutex_t +#define AV_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + +#define ff_mutex_init pthread_mutex_init +#define ff_mutex_lock pthread_mutex_lock +#define ff_mutex_unlock pthread_mutex_unlock +#define ff_mutex_destroy pthread_mutex_destroy + +#define AVCond pthread_cond_t + +#define ff_cond_init pthread_cond_init +#define ff_cond_destroy pthread_cond_destroy +#define ff_cond_signal pthread_cond_signal +#define ff_cond_broadcast pthread_cond_broadcast +#define ff_cond_wait pthread_cond_wait +#define ff_cond_timedwait pthread_cond_timedwait + +#define AVOnce pthread_once_t +#define AV_ONCE_INIT PTHREAD_ONCE_INIT + +#define ff_thread_once(control, routine) pthread_once(control, routine) + +#else + +#define AVMutex char +#define AV_MUTEX_INITIALIZER 0 + +static inline int ff_mutex_init(AVMutex *mutex, const void *attr){ return 0; } +static inline int ff_mutex_lock(AVMutex *mutex){ return 0; } +static inline int ff_mutex_unlock(AVMutex *mutex){ return 0; } +static inline int ff_mutex_destroy(AVMutex *mutex){ return 0; } + +#define AVCond char + +static inline int ff_cond_init(AVCond *cond, const void *attr){ return 0; } +static inline int ff_cond_destroy(AVCond *cond){ return 0; } +static inline int ff_cond_signal(AVCond *cond){ return 0; } +static inline int ff_cond_broadcast(AVCond *cond){ return 0; } +static inline int ff_cond_wait(AVCond *cond, AVMutex *mutex){ return 0; } +static inline int ff_cond_timedwait(AVCond *cond, AVMutex *mutex, + const void *abstime){ return 0; } + +#define AVOnce char +#define AV_ONCE_INIT 0 + +static inline int ff_thread_once(char *control, void (*routine)(void)) +{ + if (!*control) { + routine(); + *control = 1; + } + return 0; +} + +#endif + +static inline int ff_thread_setname(const char *name) +{ + int ret = 0; + +#if HAVE_PRCTL + ret = AVERROR(prctl(PR_SET_NAME, name)); +#elif HAVE_PTHREAD_SETNAME_NP +#if defined(__APPLE__) + ret = AVERROR(pthread_setname_np(name)); +#elif defined(__NetBSD__) + ret = AVERROR(pthread_setname_np(pthread_self(), "%s", name)); +#else + ret = AVERROR(pthread_setname_np(pthread_self(), name)); +#endif +#elif HAVE_PTHREAD_SET_NAME_NP + pthread_set_name_np(pthread_self(), name); +#elif HAVE_W32THREADS + ret = win32_thread_setname(name); +#else + ret = AVERROR(ENOSYS); +#endif + + return ret; +} + +#endif /* AVUTIL_THREAD_H */ diff --git a/libs/ffmpeg/libavutil/threadmessage.c b/libs/ffmpeg/libavutil/threadmessage.c new file mode 100644 index 00000000000..20b3882033d --- /dev/null +++ b/libs/ffmpeg/libavutil/threadmessage.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2014 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <limits.h> +#include <stddef.h> + +#include "error.h" +#include "fifo.h" +#include "mem.h" +#include "threadmessage.h" +#include "thread.h" + +struct AVThreadMessageQueue { +#if HAVE_THREADS + AVFifo *fifo; + pthread_mutex_t lock; + pthread_cond_t cond_recv; + pthread_cond_t cond_send; + int err_send; + int err_recv; + unsigned elsize; + void (*free_func)(void *msg); +#else + int dummy; +#endif +}; + +int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, + unsigned nelem, + unsigned elsize) +{ +#if HAVE_THREADS + AVThreadMessageQueue *rmq; + int ret = 0; + + if (nelem > INT_MAX / elsize) + return AVERROR(EINVAL); + if (!(rmq = av_mallocz(sizeof(*rmq)))) + return AVERROR(ENOMEM); + if ((ret = pthread_mutex_init(&rmq->lock, NULL))) { + av_free(rmq); + return AVERROR(ret); + } + if ((ret = pthread_cond_init(&rmq->cond_recv, NULL))) { + pthread_mutex_destroy(&rmq->lock); + av_free(rmq); + return AVERROR(ret); + } + if ((ret = pthread_cond_init(&rmq->cond_send, NULL))) { + pthread_cond_destroy(&rmq->cond_recv); + pthread_mutex_destroy(&rmq->lock); + av_free(rmq); + return AVERROR(ret); + } + if (!(rmq->fifo = av_fifo_alloc2(nelem, elsize, 0))) { + pthread_cond_destroy(&rmq->cond_send); + pthread_cond_destroy(&rmq->cond_recv); + pthread_mutex_destroy(&rmq->lock); + av_free(rmq); + return AVERROR(ENOMEM); + } + rmq->elsize = elsize; + *mq = rmq; + return 0; +#else + *mq = NULL; + return AVERROR(ENOSYS); +#endif /* HAVE_THREADS */ +} + +void av_thread_message_queue_set_free_func(AVThreadMessageQueue *mq, + void (*free_func)(void *msg)) +{ +#if HAVE_THREADS + mq->free_func = free_func; +#endif +} + +void av_thread_message_queue_free(AVThreadMessageQueue **mq) +{ +#if HAVE_THREADS + if (*mq) { + av_thread_message_flush(*mq); + av_fifo_freep2(&(*mq)->fifo); + pthread_cond_destroy(&(*mq)->cond_send); + pthread_cond_destroy(&(*mq)->cond_recv); + pthread_mutex_destroy(&(*mq)->lock); + av_freep(mq); + } +#endif +} + +int av_thread_message_queue_nb_elems(AVThreadMessageQueue *mq) +{ +#if HAVE_THREADS + int ret; + pthread_mutex_lock(&mq->lock); + ret = av_fifo_can_read(mq->fifo); + pthread_mutex_unlock(&mq->lock); + return ret; +#else + return AVERROR(ENOSYS); +#endif +} + +#if HAVE_THREADS + +static int av_thread_message_queue_send_locked(AVThreadMessageQueue *mq, + void *msg, + unsigned flags) +{ + while (!mq->err_send && !av_fifo_can_write(mq->fifo)) { + if ((flags & AV_THREAD_MESSAGE_NONBLOCK)) + return AVERROR(EAGAIN); + pthread_cond_wait(&mq->cond_send, &mq->lock); + } + if (mq->err_send) + return mq->err_send; + av_fifo_write(mq->fifo, msg, 1); + /* one message is sent, signal one receiver */ + pthread_cond_signal(&mq->cond_recv); + return 0; +} + +static int av_thread_message_queue_recv_locked(AVThreadMessageQueue *mq, + void *msg, + unsigned flags) +{ + while (!mq->err_recv && !av_fifo_can_read(mq->fifo)) { + if ((flags & AV_THREAD_MESSAGE_NONBLOCK)) + return AVERROR(EAGAIN); + pthread_cond_wait(&mq->cond_recv, &mq->lock); + } + if (!av_fifo_can_read(mq->fifo)) + return mq->err_recv; + av_fifo_read(mq->fifo, msg, 1); + /* one message space appeared, signal one sender */ + pthread_cond_signal(&mq->cond_send); + return 0; +} + +#endif /* HAVE_THREADS */ + +int av_thread_message_queue_send(AVThreadMessageQueue *mq, + void *msg, + unsigned flags) +{ +#if HAVE_THREADS + int ret; + + pthread_mutex_lock(&mq->lock); + ret = av_thread_message_queue_send_locked(mq, msg, flags); + pthread_mutex_unlock(&mq->lock); + return ret; +#else + return AVERROR(ENOSYS); +#endif /* HAVE_THREADS */ +} + +int av_thread_message_queue_recv(AVThreadMessageQueue *mq, + void *msg, + unsigned flags) +{ +#if HAVE_THREADS + int ret; + + pthread_mutex_lock(&mq->lock); + ret = av_thread_message_queue_recv_locked(mq, msg, flags); + pthread_mutex_unlock(&mq->lock); + return ret; +#else + return AVERROR(ENOSYS); +#endif /* HAVE_THREADS */ +} + +void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq, + int err) +{ +#if HAVE_THREADS + pthread_mutex_lock(&mq->lock); + mq->err_send = err; + pthread_cond_broadcast(&mq->cond_send); + pthread_mutex_unlock(&mq->lock); +#endif /* HAVE_THREADS */ +} + +void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, + int err) +{ +#if HAVE_THREADS + pthread_mutex_lock(&mq->lock); + mq->err_recv = err; + pthread_cond_broadcast(&mq->cond_recv); + pthread_mutex_unlock(&mq->lock); +#endif /* HAVE_THREADS */ +} + +#if HAVE_THREADS +static int free_func_wrap(void *arg, void *buf, size_t *nb_elems) +{ + AVThreadMessageQueue *mq = arg; + uint8_t *msg = buf; + for (size_t i = 0; i < *nb_elems; i++) + mq->free_func(msg + i * mq->elsize); + return 0; +} +#endif + +void av_thread_message_flush(AVThreadMessageQueue *mq) +{ +#if HAVE_THREADS + size_t used; + + pthread_mutex_lock(&mq->lock); + used = av_fifo_can_read(mq->fifo); + if (mq->free_func) + av_fifo_read_to_cb(mq->fifo, free_func_wrap, mq, &used); + /* only the senders need to be notified since the queue is empty and there + * is nothing to read */ + pthread_cond_broadcast(&mq->cond_send); + pthread_mutex_unlock(&mq->lock); +#endif /* HAVE_THREADS */ +} diff --git a/libs/ffmpeg/libavutil/threadmessage.h b/libs/ffmpeg/libavutil/threadmessage.h new file mode 100644 index 00000000000..42ce655f365 --- /dev/null +++ b/libs/ffmpeg/libavutil/threadmessage.h @@ -0,0 +1,115 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_THREADMESSAGE_H +#define AVUTIL_THREADMESSAGE_H + +typedef struct AVThreadMessageQueue AVThreadMessageQueue; + +typedef enum AVThreadMessageFlags { + + /** + * Perform non-blocking operation. + * If this flag is set, send and recv operations are non-blocking and + * return AVERROR(EAGAIN) immediately if they can not proceed. + */ + AV_THREAD_MESSAGE_NONBLOCK = 1, + +} AVThreadMessageFlags; + +/** + * Allocate a new message queue. + * + * @param mq pointer to the message queue + * @param nelem maximum number of elements in the queue + * @param elsize size of each element in the queue + * @return >=0 for success; <0 for error, in particular AVERROR(ENOSYS) if + * lavu was built without thread support + */ +int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, + unsigned nelem, + unsigned elsize); + +/** + * Free a message queue. + * + * The message queue must no longer be in use by another thread. + */ +void av_thread_message_queue_free(AVThreadMessageQueue **mq); + +/** + * Send a message on the queue. + */ +int av_thread_message_queue_send(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Receive a message from the queue. + */ +int av_thread_message_queue_recv(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Set the sending error code. + * + * If the error code is set to non-zero, av_thread_message_queue_send() will + * return it immediately. Conventional values, such as AVERROR_EOF or + * AVERROR(EAGAIN), can be used to cause the sending thread to stop or + * suspend its operation. + */ +void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq, + int err); + +/** + * Set the receiving error code. + * + * If the error code is set to non-zero, av_thread_message_queue_recv() will + * return it immediately when there are no longer available messages. + * Conventional values, such as AVERROR_EOF or AVERROR(EAGAIN), can be used + * to cause the receiving thread to stop or suspend its operation. + */ +void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, + int err); + +/** + * Set the optional free message callback function which will be called if an + * operation is removing messages from the queue. + */ +void av_thread_message_queue_set_free_func(AVThreadMessageQueue *mq, + void (*free_func)(void *msg)); + +/** + * Return the current number of messages in the queue. + * + * @return the current number of messages or AVERROR(ENOSYS) if lavu was built + * without thread support + */ +int av_thread_message_queue_nb_elems(AVThreadMessageQueue *mq); + +/** + * Flush the message queue + * + * This function is mostly equivalent to reading and free-ing every message + * except that it will be done in a single operation (no lock/unlock between + * reads). + */ +void av_thread_message_flush(AVThreadMessageQueue *mq); + +#endif /* AVUTIL_THREADMESSAGE_H */ diff --git a/libs/ffmpeg/libavutil/time.c b/libs/ffmpeg/libavutil/time.c new file mode 100644 index 00000000000..740afc47850 --- /dev/null +++ b/libs/ffmpeg/libavutil/time.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2000-2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include <stddef.h> +#include <stdint.h> +#include <time.h> +#if HAVE_GETTIMEOFDAY +#include <sys/time.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_WINDOWS_H +#include <windows.h> +#endif + +#include "time.h" +#include "error.h" + +int64_t av_gettime(void) +{ +#if HAVE_GETTIMEOFDAY + struct timeval tv; + gettimeofday(&tv, NULL); + return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; +#elif HAVE_GETSYSTEMTIMEASFILETIME + FILETIME ft; + int64_t t; + GetSystemTimeAsFileTime(&ft); + t = (int64_t)ft.dwHighDateTime << 32 | ft.dwLowDateTime; + return t / 10 - 11644473600000000; /* Jan 1, 1601 */ +#else + return -1; +#endif +} + +int64_t av_gettime_relative(void) +{ +#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) +#ifdef __APPLE__ + if (&clock_gettime) +#endif + { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (int64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000; + } +#endif + return av_gettime() + 42 * 60 * 60 * INT64_C(1000000); +} + +int av_gettime_relative_is_monotonic(void) +{ +#if HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) +#ifdef __APPLE__ + if (!&clock_gettime) + return 0; +#endif + return 1; +#else + return 0; +#endif +} + +int av_usleep(unsigned usec) +{ +#if HAVE_NANOSLEEP + struct timespec ts = { usec / 1000000, usec % 1000000 * 1000 }; + while (nanosleep(&ts, &ts) < 0 && errno == EINTR); + return 0; +#elif HAVE_USLEEP + return usleep(usec); +#elif HAVE_SLEEP + Sleep(usec / 1000); + return 0; +#else + return AVERROR(ENOSYS); +#endif +} diff --git a/libs/ffmpeg/libavutil/time.h b/libs/ffmpeg/libavutil/time.h new file mode 100644 index 00000000000..dc169b064a0 --- /dev/null +++ b/libs/ffmpeg/libavutil/time.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000-2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TIME_H +#define AVUTIL_TIME_H + +#include <stdint.h> + +/** + * Get the current time in microseconds. + */ +int64_t av_gettime(void); + +/** + * Get the current time in microseconds since some unspecified starting point. + * On platforms that support it, the time comes from a monotonic clock + * This property makes this time source ideal for measuring relative time. + * The returned values may not be monotonic on platforms where a monotonic + * clock is not available. + */ +int64_t av_gettime_relative(void); + +/** + * Indicates with a boolean result if the av_gettime_relative() time source + * is monotonic. + */ +int av_gettime_relative_is_monotonic(void); + +/** + * Sleep for a period of time. Although the duration is expressed in + * microseconds, the actual delay may be rounded to the precision of the + * system timer. + * + * @param usec Number of microseconds to sleep. + * @return zero on success or (negative) error code. + */ +int av_usleep(unsigned usec); + +#endif /* AVUTIL_TIME_H */ diff --git a/libs/ffmpeg/libavutil/time_internal.h b/libs/ffmpeg/libavutil/time_internal.h new file mode 100644 index 00000000000..d0f007ab1c4 --- /dev/null +++ b/libs/ffmpeg/libavutil/time_internal.h @@ -0,0 +1,49 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TIME_INTERNAL_H +#define AVUTIL_TIME_INTERNAL_H + +#include <time.h> +#include "config.h" + +#if !HAVE_GMTIME_R && !defined(gmtime_r) +static inline struct tm *ff_gmtime_r(const time_t* clock, struct tm *result) +{ + struct tm *ptr = gmtime(clock); + if (!ptr) + return NULL; + *result = *ptr; + return result; +} +#define gmtime_r ff_gmtime_r +#endif + +#if !HAVE_LOCALTIME_R && !defined(localtime_r) +static inline struct tm *ff_localtime_r(const time_t* clock, struct tm *result) +{ + struct tm *ptr = localtime(clock); + if (!ptr) + return NULL; + *result = *ptr; + return result; +} +#define localtime_r ff_localtime_r +#endif + +#endif /* AVUTIL_TIME_INTERNAL_H */ diff --git a/libs/ffmpeg/libavutil/timecode.c b/libs/ffmpeg/libavutil/timecode.c new file mode 100644 index 00000000000..316100759e0 --- /dev/null +++ b/libs/ffmpeg/libavutil/timecode.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier <baptiste.coudurier@gmail.com> + * Copyright (c) 2011-2012 Smartjog S.A.S, Clément Bœsch <clement.boesch@smartjog.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Timecode helpers + * @see https://en.wikipedia.org/wiki/SMPTE_time_code + * @see http://www.dropframetimecode.org + */ + +#include <stdio.h> +#include "common.h" +#include "timecode.h" +#include "timecode_internal.h" +#include "log.h" +#include "error.h" + +int av_timecode_adjust_ntsc_framenum2(int framenum, int fps) +{ + /* only works for multiples of NTSC 29.97 */ + int drop_frames = 0; + int d, m, frames_per_10mins; + + if (fps && fps % 30 == 0) { + drop_frames = fps / 30 * 2; + frames_per_10mins = fps / 30 * 17982; + } else + return framenum; + + d = framenum / frames_per_10mins; + m = framenum % frames_per_10mins; + + return framenum + 9U * drop_frames * d + drop_frames * ((m - drop_frames) / (frames_per_10mins / 10)); +} + +uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum) +{ + unsigned fps = tc->fps; + int drop = !!(tc->flags & AV_TIMECODE_FLAG_DROPFRAME); + int hh, mm, ss, ff; + + framenum += tc->start; + if (drop) + framenum = av_timecode_adjust_ntsc_framenum2(framenum, tc->fps); + ff = framenum % fps; + ss = framenum / fps % 60; + mm = framenum / (fps*60LL) % 60; + hh = framenum / (fps*3600LL) % 24; + return av_timecode_get_smpte(tc->rate, drop, hh, mm, ss, ff); +} + +uint32_t av_timecode_get_smpte(AVRational rate, int drop, int hh, int mm, int ss, int ff) +{ + uint32_t tc = 0; + + /* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS. + See SMPTE ST 12-1:2014 Sec 12.1 for more info. */ + if (av_cmp_q(rate, (AVRational) {30, 1}) == 1) { + if (ff % 2 == 1) { + if (av_cmp_q(rate, (AVRational) {50, 1}) == 0) + tc |= (1 << 7); + else + tc |= (1 << 23); + } + ff /= 2; + } + + hh = hh % 24; + mm = av_clip(mm, 0, 59); + ss = av_clip(ss, 0, 59); + ff = ff % 40; + + tc |= drop << 30; + tc |= (ff / 10) << 28; + tc |= (ff % 10) << 24; + tc |= (ss / 10) << 20; + tc |= (ss % 10) << 16; + tc |= (mm / 10) << 12; + tc |= (mm % 10) << 8; + tc |= (hh / 10) << 4; + tc |= (hh % 10); + + return tc; +} + +char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum_arg) +{ + unsigned fps = tc->fps; + int drop = tc->flags & AV_TIMECODE_FLAG_DROPFRAME; + int hh, mm, ss, ff, ff_len, neg = 0; + int64_t framenum = framenum_arg; + + framenum += tc->start; + if (drop) + framenum = av_timecode_adjust_ntsc_framenum2(framenum, fps); + if (framenum < 0) { + framenum = -framenum; + neg = tc->flags & AV_TIMECODE_FLAG_ALLOWNEGATIVE; + } + ff = framenum % fps; + ss = framenum / fps % 60; + mm = framenum / (fps*60LL) % 60; + hh = framenum / (fps*3600LL); + if (tc->flags & AV_TIMECODE_FLAG_24HOURSMAX) + hh = hh % 24; + ff_len = fps > 10000 ? 5 : fps > 1000 ? 4 : fps > 100 ? 3 : fps > 10 ? 2 : 1; + snprintf(buf, AV_TIMECODE_STR_SIZE, "%s%02d:%02d:%02d%c%0*d", + neg ? "-" : "", + hh, mm, ss, drop ? ';' : ':', ff_len, ff); + return buf; +} + +char *av_timecode_make_smpte_tc_string2(char *buf, AVRational rate, uint32_t tcsmpte, int prevent_df, int skip_field) +{ + unsigned hh, mm, ss, ff, drop; + ff_timecode_set_smpte(&drop, &hh, &mm, &ss, &ff, rate, tcsmpte, prevent_df, skip_field); + + snprintf(buf, AV_TIMECODE_STR_SIZE, "%02u:%02u:%02u%c%02u", + hh, mm, ss, drop ? ';' : ':', ff); + return buf; + +} + +char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df) +{ + return av_timecode_make_smpte_tc_string2(buf, (AVRational){30, 1}, tcsmpte, prevent_df, 1); +} + +char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit) +{ + snprintf(buf, AV_TIMECODE_STR_SIZE, + "%02"PRIu32":%02"PRIu32":%02"PRIu32"%c%02"PRIu32, + tc25bit>>19 & 0x1f, // 5-bit hours + tc25bit>>13 & 0x3f, // 6-bit minutes + tc25bit>>6 & 0x3f, // 6-bit seconds + tc25bit & 1<<24 ? ';' : ':', // 1-bit drop flag + tc25bit & 0x3f); // 6-bit frames + return buf; +} + +static int check_fps(int fps) +{ + int i; + static const int supported_fps[] = { + 24, 25, 30, 48, 50, 60, 100, 120, 150, + }; + + for (i = 0; i < FF_ARRAY_ELEMS(supported_fps); i++) + if (fps == supported_fps[i]) + return 0; + return -1; +} + +static int check_timecode(void *log_ctx, AVTimecode *tc) +{ + if ((int)tc->fps <= 0) { + av_log(log_ctx, AV_LOG_ERROR, "Valid timecode frame rate must be specified. Minimum value is 1\n"); + return AVERROR(EINVAL); + } + if ((tc->flags & AV_TIMECODE_FLAG_DROPFRAME) && tc->fps % 30 != 0) { + av_log(log_ctx, AV_LOG_ERROR, "Drop frame is only allowed with multiples of 30000/1001 FPS\n"); + return AVERROR(EINVAL); + } + if (check_fps(tc->fps) < 0) { + av_log(log_ctx, AV_LOG_WARNING, "Using non-standard frame rate %d/%d\n", + tc->rate.num, tc->rate.den); + } + return 0; +} + +static int fps_from_frame_rate(AVRational rate) +{ + if (!rate.den || !rate.num) + return -1; + return (rate.num + rate.den/2LL) / rate.den; +} + +int av_timecode_check_frame_rate(AVRational rate) +{ + return check_fps(fps_from_frame_rate(rate)); +} + +int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx) +{ + memset(tc, 0, sizeof(*tc)); + tc->start = frame_start; + tc->flags = flags; + tc->rate = rate; + tc->fps = fps_from_frame_rate(rate); + return check_timecode(log_ctx, tc); +} + +int av_timecode_init_from_components(AVTimecode *tc, AVRational rate, int flags, int hh, int mm, int ss, int ff, void *log_ctx) +{ + int ret; + int64_t s; + + memset(tc, 0, sizeof(*tc)); + tc->flags = flags; + tc->rate = rate; + tc->fps = fps_from_frame_rate(rate); + + ret = check_timecode(log_ctx, tc); + if (ret < 0) + return ret; + + s = hh*3600LL + mm*60LL + ss; + if (s != (int32_t)s) + return AVERROR(EINVAL); + + s = s * tc->fps + ff; + if (s != (int32_t)s) + return AVERROR(EINVAL); + tc->start = s; + + if (tc->flags & AV_TIMECODE_FLAG_DROPFRAME) { /* adjust frame number */ + int tmins = 60*hh + mm; + tc->start -= (tc->fps / 30 * 2) * (tmins - tmins/10); + } + return 0; +} + +int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx) +{ + char c; + int hh, mm, ss, ff, flags; + + if (sscanf(str, "%d:%d:%d%c%d", &hh, &mm, &ss, &c, &ff) != 5) { + av_log(log_ctx, AV_LOG_ERROR, "Unable to parse timecode, " + "syntax: hh:mm:ss[:;.]ff\n"); + return AVERROR_INVALIDDATA; + } + flags = c != ':' ? AV_TIMECODE_FLAG_DROPFRAME : 0; // drop if ';', '.', ... + + return av_timecode_init_from_components(tc, rate, flags, hh, mm, ss, ff, log_ctx); +} diff --git a/libs/ffmpeg/libavutil/timecode.h b/libs/ffmpeg/libavutil/timecode.h new file mode 100644 index 00000000000..fe0fc835764 --- /dev/null +++ b/libs/ffmpeg/libavutil/timecode.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier <baptiste.coudurier@gmail.com> + * Copyright (c) 2011-2012 Smartjog S.A.S, Clément Bœsch <clement.boesch@smartjog.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Timecode helpers header + */ + +#ifndef AVUTIL_TIMECODE_H +#define AVUTIL_TIMECODE_H + +#include <stdint.h> +#include "rational.h" + +#define AV_TIMECODE_STR_SIZE 23 + +enum AVTimecodeFlag { + AV_TIMECODE_FLAG_DROPFRAME = 1<<0, ///< timecode is drop frame + AV_TIMECODE_FLAG_24HOURSMAX = 1<<1, ///< timecode wraps after 24 hours + AV_TIMECODE_FLAG_ALLOWNEGATIVE = 1<<2, ///< negative time values are allowed +}; + +typedef struct { + int start; ///< timecode frame start (first base frame number) + uint32_t flags; ///< flags such as drop frame, +24 hours support, ... + AVRational rate; ///< frame rate in rational form + unsigned fps; ///< frame per second; must be consistent with the rate field +} AVTimecode; + +/** + * Adjust frame number for NTSC drop frame time code. + * + * @param framenum frame number to adjust + * @param fps frame per second, multiples of 30 + * @return adjusted frame number + * @warning adjustment is only valid for multiples of NTSC 29.97 + */ +int av_timecode_adjust_ntsc_framenum2(int framenum, int fps); + +/** + * Convert frame number to SMPTE 12M binary representation. + * + * @param tc timecode data correctly initialized + * @param framenum frame number + * @return the SMPTE binary representation + * + * See SMPTE ST 314M-2005 Sec 4.4.2.2.1 "Time code pack (TC)" + * the format description as follows: + * bits 0-5: hours, in BCD(6bits) + * bits 6: BGF1 + * bits 7: BGF2 (NTSC) or FIELD (PAL) + * bits 8-14: minutes, in BCD(7bits) + * bits 15: BGF0 (NTSC) or BGF2 (PAL) + * bits 16-22: seconds, in BCD(7bits) + * bits 23: FIELD (NTSC) or BGF0 (PAL) + * bits 24-29: frames, in BCD(6bits) + * bits 30: drop frame flag (0: non drop, 1: drop) + * bits 31: color frame flag (0: unsync mode, 1: sync mode) + * @note BCD numbers (6 or 7 bits): 4 or 5 lower bits for units, 2 higher bits for tens. + * @note Frame number adjustment is automatically done in case of drop timecode, + * you do NOT have to call av_timecode_adjust_ntsc_framenum2(). + * @note The frame number is relative to tc->start. + * @note Color frame (CF) and binary group flags (BGF) bits are set to zero. + */ +uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum); + +/** + * Convert sei info to SMPTE 12M binary representation. + * + * @param rate frame rate in rational form + * @param drop drop flag + * @param hh hour + * @param mm minute + * @param ss second + * @param ff frame number + * @return the SMPTE binary representation + */ +uint32_t av_timecode_get_smpte(AVRational rate, int drop, int hh, int mm, int ss, int ff); + +/** + * Load timecode string in buf. + * + * @param tc timecode data correctly initialized + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param framenum frame number + * @return the buf parameter + * + * @note Timecode representation can be a negative timecode and have more than + * 24 hours, but will only be honored if the flags are correctly set. + * @note The frame number is relative to tc->start. + */ +char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum); + +/** + * Get the timecode string from the SMPTE timecode format. + * + * In contrast to av_timecode_make_smpte_tc_string this function supports 50/60 + * fps timecodes by using the field bit. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param rate frame rate of the timecode + * @param tcsmpte the 32-bit SMPTE timecode + * @param prevent_df prevent the use of a drop flag when it is known the DF bit + * is arbitrary + * @param skip_field prevent the use of a field flag when it is known the field + * bit is arbitrary (e.g. because it is used as PC flag) + * @return the buf parameter + */ +char *av_timecode_make_smpte_tc_string2(char *buf, AVRational rate, uint32_t tcsmpte, int prevent_df, int skip_field); + +/** + * Get the timecode string from the SMPTE timecode format. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tcsmpte the 32-bit SMPTE timecode + * @param prevent_df prevent the use of a drop flag when it is known the DF bit + * is arbitrary + * @return the buf parameter + */ +char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df); + +/** + * Get the timecode string from the 25-bit timecode format (MPEG GOP format). + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tc25bit the 25-bits timecode + * @return the buf parameter + */ +char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit); + +/** + * Init a timecode struct with the passed parameters. + * + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param flags miscellaneous flags such as drop frame, +24 hours, ... + * (see AVTimecodeFlag) + * @param frame_start the first frame number + * @param log_ctx a pointer to an arbitrary struct of which the first field + * is a pointer to an AVClass struct (used for av_log) + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx); + +/** + * Init a timecode struct from the passed timecode components. + * + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param flags miscellaneous flags such as drop frame, +24 hours, ... + * (see AVTimecodeFlag) + * @param hh hours + * @param mm minutes + * @param ss seconds + * @param ff frames + * @param log_ctx a pointer to an arbitrary struct of which the first field + * is a pointer to an AVClass struct (used for av_log) + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init_from_components(AVTimecode *tc, AVRational rate, int flags, int hh, int mm, int ss, int ff, void *log_ctx); + +/** + * Parse timecode representation (hh:mm:ss[:;.]ff). + * + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param str timecode string which will determine the frame start + * @param log_ctx a pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct (used for av_log). + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx); + +/** + * Check if the timecode feature is available for the given frame rate + * + * @return 0 if supported, <0 otherwise + */ +int av_timecode_check_frame_rate(AVRational rate); + +#endif /* AVUTIL_TIMECODE_H */ diff --git a/libs/ffmpeg/libavutil/timecode_internal.c b/libs/ffmpeg/libavutil/timecode_internal.c new file mode 100644 index 00000000000..259ebf16646 --- /dev/null +++ b/libs/ffmpeg/libavutil/timecode_internal.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier <baptiste.coudurier@gmail.com> + * Copyright (c) 2011-2012 Smartjog S.A.S, Clément Bœsch <clement.boesch@smartjog.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "timecode_internal.h" + +static unsigned bcd2uint(uint8_t bcd) +{ + unsigned low = bcd & 0xf; + unsigned high = bcd >> 4; + if (low > 9 || high > 9) + return 0; + return low + 10*high; +} + +void ff_timecode_set_smpte(unsigned *drop, unsigned *hh, unsigned *mm, unsigned *ss, unsigned *ff, + AVRational rate, uint32_t tcsmpte, int prevent_df, int skip_field) +{ + *hh = bcd2uint(tcsmpte & 0x3f); // 6-bit hours + *mm = bcd2uint(tcsmpte>>8 & 0x7f); // 7-bit minutes + *ss = bcd2uint(tcsmpte>>16 & 0x7f); // 7-bit seconds + *ff = bcd2uint(tcsmpte>>24 & 0x3f); // 6-bit frames + *drop = tcsmpte & 1<<30 && !prevent_df; // 1-bit drop if not arbitrary bit + + if (av_cmp_q(rate, (AVRational) {30, 1}) == 1) { + *ff <<= 1; + if (!skip_field) { + if (av_cmp_q(rate, (AVRational) {50, 1}) == 0) + *ff += !!(tcsmpte & 1 << 7); + else + *ff += !!(tcsmpte & 1 << 23); + } + } +} diff --git a/libs/ffmpeg/libavutil/timecode_internal.h b/libs/ffmpeg/libavutil/timecode_internal.h new file mode 100644 index 00000000000..8ef43d1f98c --- /dev/null +++ b/libs/ffmpeg/libavutil/timecode_internal.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier <baptiste.coudurier@gmail.com> + * Copyright (c) 2011-2012 Smartjog S.A.S, Clément Bœsch <clement.boesch@smartjog.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Timecode helpers header + */ + +#ifndef AVUTIL_TIMECODE_INTERNAL_H +#define AVUTIL_TIMECODE_INTERNAL_H + +#include <stdint.h> +#include "rational.h" + +/** + * Convert SMPTE 12M binary representation to sei info. + * + * @param drop drop flag output + * @param hh hour output + * @param mm minute output + * @param ss second output + * @param ff frame number output + * @param rate frame rate of the timecode + * @param tcsmpte the 32-bit SMPTE timecode + * @param prevent_df prevent the use of a drop flag when it is known the DF bit + * is arbitrary + * @param skip_field prevent the use of a field flag when it is known the field + * bit is arbitrary (e.g. because it is used as PC flag) + */ +void ff_timecode_set_smpte(unsigned *drop, unsigned *hh, unsigned *mm, unsigned *ss, unsigned *ff, + AVRational rate, uint32_t tcsmpte, int prevent_df, int skip_field); + +#endif /* AVUTIL_TIMECODE_INTERNAL_H */ diff --git a/libs/ffmpeg/libavutil/timer.h b/libs/ffmpeg/libavutil/timer.h new file mode 100644 index 00000000000..03706b0d103 --- /dev/null +++ b/libs/ffmpeg/libavutil/timer.h @@ -0,0 +1,169 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * high precision timer, useful to profile code + */ + +#ifndef AVUTIL_TIMER_H +#define AVUTIL_TIMER_H + +#include "config.h" + +#if CONFIG_LINUX_PERF +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +# include <unistd.h> // read(3) +# include <sys/ioctl.h> +# include <asm/unistd.h> +# include <linux/perf_event.h> +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> + +#if CONFIG_MACOS_KPERF +#include "macos_kperf.h" +#endif + +#if HAVE_MACH_ABSOLUTE_TIME +#include <mach/mach_time.h> +#elif HAVE_CLOCK_GETTIME +#include <time.h> +#endif + +#include "common.h" +#include "log.h" + +#if ARCH_AARCH64 +# include "aarch64/timer.h" +#elif ARCH_ARM +# include "arm/timer.h" +#elif ARCH_PPC +# include "ppc/timer.h" +#elif ARCH_X86 +# include "x86/timer.h" +#elif ARCH_LOONGARCH +# include "loongarch/timer.h" +#endif + +#if !defined(AV_READ_TIME) +# if HAVE_GETHRTIME +# define AV_READ_TIME gethrtime +# elif HAVE_MACH_ABSOLUTE_TIME +# define AV_READ_TIME mach_absolute_time +# elif HAVE_CLOCK_GETTIME && defined(CLOCK_MONOTONIC) + static inline int64_t ff_read_time(void) + { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * INT64_C(1000000000) + ts.tv_nsec; + } +# define AV_READ_TIME ff_read_time +# define FF_TIMER_UNITS "ns" +# endif +#endif + +#ifndef FF_TIMER_UNITS +# define FF_TIMER_UNITS "UNITS" +#endif + +#define TIMER_REPORT(id, tdiff) \ + { \ + static uint64_t tsum = 0; \ + static int tcount = 0; \ + static int tskip_count = 0; \ + static int thistogram[32] = {0}; \ + thistogram[av_log2(tdiff)]++; \ + if (tcount < 2 || \ + (tdiff) < 8 * tsum / tcount || \ + (tdiff) < 2000) { \ + tsum += (tdiff); \ + tcount++; \ + } else \ + tskip_count++; \ + if (((tcount + tskip_count) & (tcount + tskip_count - 1)) == 0) { \ + int i; \ + av_log(NULL, AV_LOG_ERROR, \ + "%7" PRIu64 " " FF_TIMER_UNITS " in %s,%8d runs,%7d skips",\ + tsum * 10 / tcount, id, tcount, tskip_count); \ + for (i = 0; i < 32; i++) \ + av_log(NULL, AV_LOG_VERBOSE, " %2d", av_log2(2*thistogram[i]));\ + av_log(NULL, AV_LOG_ERROR, "\n"); \ + } \ + } + +#if CONFIG_LINUX_PERF + +#define START_TIMER \ + static int linux_perf_fd = -1; \ + uint64_t tperf; \ + if (linux_perf_fd == -1) { \ + struct perf_event_attr attr = { \ + .type = PERF_TYPE_HARDWARE, \ + .size = sizeof(struct perf_event_attr), \ + .config = PERF_COUNT_HW_CPU_CYCLES, \ + .disabled = 1, \ + .exclude_kernel = 1, \ + .exclude_hv = 1, \ + }; \ + linux_perf_fd = syscall(__NR_perf_event_open, &attr, \ + 0, -1, -1, 0); \ + } \ + if (linux_perf_fd == -1) { \ + av_log(NULL, AV_LOG_ERROR, "perf_event_open failed: %s\n", \ + av_err2str(AVERROR(errno))); \ + } else { \ + ioctl(linux_perf_fd, PERF_EVENT_IOC_RESET, 0); \ + ioctl(linux_perf_fd, PERF_EVENT_IOC_ENABLE, 0); \ + } + +#define STOP_TIMER(id) \ + ioctl(linux_perf_fd, PERF_EVENT_IOC_DISABLE, 0); \ + read(linux_perf_fd, &tperf, sizeof(tperf)); \ + TIMER_REPORT(id, tperf) + +#elif CONFIG_MACOS_KPERF + +#define START_TIMER \ + uint64_t tperf; \ + ff_kperf_init(); \ + tperf = ff_kperf_cycles(); + +#define STOP_TIMER(id) \ + TIMER_REPORT(id, ff_kperf_cycles() - tperf); + +#elif defined(AV_READ_TIME) +#define START_TIMER \ + uint64_t tend; \ + uint64_t tstart = AV_READ_TIME(); \ + +#define STOP_TIMER(id) \ + tend = AV_READ_TIME(); \ + TIMER_REPORT(id, tend - tstart) +#else +#define START_TIMER +#define STOP_TIMER(id) { } +#endif + +#endif /* AVUTIL_TIMER_H */ diff --git a/libs/ffmpeg/libavutil/timestamp.c b/libs/ffmpeg/libavutil/timestamp.c new file mode 100644 index 00000000000..6c231a517d3 --- /dev/null +++ b/libs/ffmpeg/libavutil/timestamp.c @@ -0,0 +1,36 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "timestamp.h" + +char *av_ts_make_time_string2(char *buf, int64_t ts, AVRational tb) +{ + if (ts == AV_NOPTS_VALUE) { + snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + } else { + double val = av_q2d(tb) * ts; + double log = (fpclassify(val) == FP_ZERO ? -INFINITY : floor(log10(fabs(val)))); + int precision = (isfinite(log) && log < 0) ? -log + 5 : 6; + int last = snprintf(buf, AV_TS_MAX_STRING_SIZE, "%.*f", precision, val); + last = FFMIN(last, AV_TS_MAX_STRING_SIZE - 1) - 1; + for (; last && buf[last] == '0'; last--); + for (; last && buf[last] != 'f' && (buf[last] < '0' || buf[0] > '9'); last--); + buf[last + 1] = '\0'; + } + return buf; +} diff --git a/libs/ffmpeg/libavutil/timestamp.h b/libs/ffmpeg/libavutil/timestamp.h new file mode 100644 index 00000000000..fa53a46b987 --- /dev/null +++ b/libs/ffmpeg/libavutil/timestamp.h @@ -0,0 +1,85 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * timestamp utils, mostly useful for debugging/logging purposes + */ + +#ifndef AVUTIL_TIMESTAMP_H +#define AVUTIL_TIMESTAMP_H + +#include "avutil.h" + +#if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS) && !defined(PRId64) +#error missing -D__STDC_FORMAT_MACROS / #define __STDC_FORMAT_MACROS +#endif + +#define AV_TS_MAX_STRING_SIZE 32 + +/** + * Fill the provided buffer with a string containing a timestamp + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @return the buffer in input + */ +static inline char *av_ts_make_string(char *buf, int64_t ts) +{ + if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%" PRId64, ts); + return buf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2str(ts) av_ts_make_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts) + +/** + * Fill the provided buffer with a string containing a timestamp time + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @param tb the timebase of the timestamp + * @return the buffer in input + */ +char *av_ts_make_time_string2(char *buf, int64_t ts, AVRational tb); + +/** + * Fill the provided buffer with a string containing a timestamp + * representation. + * + * @see av_ts_make_time_string2 + */ +static inline char *av_ts_make_time_string(char *buf, int64_t ts, + const AVRational *tb) +{ + return av_ts_make_time_string2(buf, ts, *tb); +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2timestr(ts, tb) av_ts_make_time_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts, tb) + +#endif /* AVUTIL_TIMESTAMP_H */ diff --git a/libs/ffmpeg/libavutil/tree.c b/libs/ffmpeg/libavutil/tree.c new file mode 100644 index 00000000000..7b57b2d39a7 --- /dev/null +++ b/libs/ffmpeg/libavutil/tree.c @@ -0,0 +1,168 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "error.h" +#include "log.h" +#include "mem.h" +#include "tree.h" + +typedef struct AVTreeNode { + struct AVTreeNode *child[2]; + void *elem; + int state; +} AVTreeNode; + +const int av_tree_node_size = sizeof(AVTreeNode); + +struct AVTreeNode *av_tree_node_alloc(void) +{ + return av_mallocz(sizeof(struct AVTreeNode)); +} + +void *av_tree_find(const AVTreeNode *t, void *key, + int (*cmp)(const void *key, const void *b), void *next[2]) +{ + if (t) { + unsigned int v = cmp(key, t->elem); + if (v) { + if (next) + next[v >> 31] = t->elem; + return av_tree_find(t->child[(v >> 31) ^ 1], key, cmp, next); + } else { + if (next) { + av_tree_find(t->child[0], key, cmp, next); + av_tree_find(t->child[1], key, cmp, next); + } + return t->elem; + } + } + return NULL; +} + +void *av_tree_insert(AVTreeNode **tp, void *key, + int (*cmp)(const void *key, const void *b), AVTreeNode **next) +{ + AVTreeNode *t = *tp; + if (t) { + unsigned int v = cmp(t->elem, key); + void *ret; + if (!v) { + if (*next) + return t->elem; + else if (t->child[0] || t->child[1]) { + int i = !t->child[0]; + void *next_elem[2]; + av_tree_find(t->child[i], key, cmp, next_elem); + key = t->elem = next_elem[i]; + v = -i; + } else { + *next = t; + *tp = NULL; + return NULL; + } + } + ret = av_tree_insert(&t->child[v >> 31], key, cmp, next); + if (!ret) { + int i = (v >> 31) ^ !!*next; + AVTreeNode **child = &t->child[i]; + t->state += 2 * i - 1; + + if (!(t->state & 1)) { + if (t->state) { + /* The following code is equivalent to + * if ((*child)->state * 2 == -t->state) + * rotate(child, i ^ 1); + * rotate(tp, i); + * + * with rotate(): + * static void rotate(AVTreeNode **tp, int i) + * { + * AVTreeNode *t= *tp; + * + * *tp = t->child[i]; + * t->child[i] = t->child[i]->child[i ^ 1]; + * (*tp)->child[i ^ 1] = t; + * i = 4 * t->state + 2 * (*tp)->state + 12; + * t->state = ((0x614586 >> i) & 3) - 1; + * (*tp)->state = ((0x400EEA >> i) & 3) - 1 + + * ((*tp)->state >> 1); + * } + * but such a rotate function is both bigger and slower + */ + if ((*child)->state * 2 == -t->state) { + *tp = (*child)->child[i ^ 1]; + (*child)->child[i ^ 1] = (*tp)->child[i]; + (*tp)->child[i] = *child; + *child = (*tp)->child[i ^ 1]; + (*tp)->child[i ^ 1] = t; + + (*tp)->child[0]->state = -((*tp)->state > 0); + (*tp)->child[1]->state = (*tp)->state < 0; + (*tp)->state = 0; + } else { + *tp = *child; + *child = (*child)->child[i ^ 1]; + (*tp)->child[i ^ 1] = t; + if ((*tp)->state) + t->state = 0; + else + t->state >>= 1; + (*tp)->state = -t->state; + } + } + } + if (!(*tp)->state ^ !!*next) + return key; + } + return ret; + } else { + *tp = *next; + *next = NULL; + if (*tp) { + (*tp)->elem = key; + return NULL; + } else + return key; + } +} + +void av_tree_destroy(AVTreeNode *t) +{ + if (t) { + av_tree_destroy(t->child[0]); + av_tree_destroy(t->child[1]); + av_free(t); + } +} + +void av_tree_enumerate(AVTreeNode *t, void *opaque, + int (*cmp)(void *opaque, void *elem), + int (*enu)(void *opaque, void *elem)) +{ + if (t) { + int v = cmp ? cmp(opaque, t->elem) : 0; + if (v >= 0) + av_tree_enumerate(t->child[0], opaque, cmp, enu); + if (v == 0) + enu(opaque, t->elem); + if (v <= 0) + av_tree_enumerate(t->child[1], opaque, cmp, enu); + } +} diff --git a/libs/ffmpeg/libavutil/tree.h b/libs/ffmpeg/libavutil/tree.h new file mode 100644 index 00000000000..bbb8fbb1262 --- /dev/null +++ b/libs/ffmpeg/libavutil/tree.h @@ -0,0 +1,137 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * A tree container. + * @author Michael Niedermayer <michaelni@gmx.at> + */ + +#ifndef AVUTIL_TREE_H +#define AVUTIL_TREE_H + +#include "attributes.h" + +/** + * @addtogroup lavu_tree AVTree + * @ingroup lavu_data + * + * Low-complexity tree container + * + * Insertion, removal, finding equal, largest which is smaller than and + * smallest which is larger than, all have O(log n) worst-case complexity. + * @{ + */ + + +struct AVTreeNode; +extern const int av_tree_node_size; + +/** + * Allocate an AVTreeNode. + */ +struct AVTreeNode *av_tree_node_alloc(void); + +/** + * Find an element. + * @param root a pointer to the root node of the tree + * @param next If next is not NULL, then next[0] will contain the previous + * element and next[1] the next element. If either does not exist, + * then the corresponding entry in next is unchanged. + * @param cmp compare function used to compare elements in the tree, + * API identical to that of Standard C's qsort + * It is guaranteed that the first and only the first argument to cmp() + * will be the key parameter to av_tree_find(), thus it could if the + * user wants, be a different type (like an opaque context). + * @return An element with cmp(key, elem) == 0 or NULL if no such element + * exists in the tree. + */ +void *av_tree_find(const struct AVTreeNode *root, void *key, + int (*cmp)(const void *key, const void *b), void *next[2]); + +/** + * Insert or remove an element. + * + * If *next is NULL, then the supplied element will be removed if it exists. + * If *next is non-NULL, then the supplied element will be inserted, unless + * it already exists in the tree. + * + * @param rootp A pointer to a pointer to the root node of the tree; note that + * the root node can change during insertions, this is required + * to keep the tree balanced. + * @param key pointer to the element key to insert in the tree + * @param next Used to allocate and free AVTreeNodes. For insertion the user + * must set it to an allocated and zeroed object of at least + * av_tree_node_size bytes size. av_tree_insert() will set it to + * NULL if it has been consumed. + * For deleting elements *next is set to NULL by the user and + * av_tree_insert() will set it to the AVTreeNode which was + * used for the removed element. + * This allows the use of flat arrays, which have + * lower overhead compared to many malloced elements. + * You might want to define a function like: + * @code + * void *tree_insert(struct AVTreeNode **rootp, void *key, + * int (*cmp)(void *key, const void *b), + * AVTreeNode **next) + * { + * if (!*next) + * *next = av_mallocz(av_tree_node_size); + * return av_tree_insert(rootp, key, cmp, next); + * } + * void *tree_remove(struct AVTreeNode **rootp, void *key, + * int (*cmp)(void *key, const void *b, AVTreeNode **next)) + * { + * av_freep(next); + * return av_tree_insert(rootp, key, cmp, next); + * } + * @endcode + * @param cmp compare function used to compare elements in the tree, API identical + * to that of Standard C's qsort + * @return If no insertion happened, the found element; if an insertion or + * removal happened, then either key or NULL will be returned. + * Which one it is depends on the tree state and the implementation. You + * should make no assumptions that it's one or the other in the code. + */ +void *av_tree_insert(struct AVTreeNode **rootp, void *key, + int (*cmp)(const void *key, const void *b), + struct AVTreeNode **next); + +void av_tree_destroy(struct AVTreeNode *t); + +/** + * Apply enu(opaque, &elem) to all the elements in the tree in a given range. + * + * @param cmp a comparison function that returns < 0 for an element below the + * range, > 0 for an element above the range and == 0 for an + * element inside the range + * + * @note The cmp function should use the same ordering used to construct the + * tree. + */ +void av_tree_enumerate(struct AVTreeNode *t, void *opaque, + int (*cmp)(void *opaque, void *elem), + int (*enu)(void *opaque, void *elem)); + +/** + * @} + */ + +#endif /* AVUTIL_TREE_H */ diff --git a/libs/ffmpeg/libavutil/twofish.c b/libs/ffmpeg/libavutil/twofish.c new file mode 100644 index 00000000000..9f9687eccba --- /dev/null +++ b/libs/ffmpeg/libavutil/twofish.c @@ -0,0 +1,335 @@ +/* + * An implementation of the TwoFish algorithm + * Copyright (c) 2015 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> + +#include "twofish.h" +#include "error.h" +#include "intreadwrite.h" +#include "mem.h" +#include "attributes.h" + +#define LR(x, n) ((x) << (n) | (x) >> (32 - (n))) +#define RR(x, n) ((x) >> (n) | (x) << (32 - (n))) + +typedef struct AVTWOFISH { + uint32_t K[40]; + uint32_t S[4]; + int ksize; + uint32_t MDS1[256]; + uint32_t MDS2[256]; + uint32_t MDS3[256]; + uint32_t MDS4[256]; +} AVTWOFISH; + +static const uint8_t MD1[256] = { + 0x00, 0x5b, 0xb6, 0xed, 0x05, 0x5e, 0xb3, 0xe8, 0x0a, 0x51, 0xbc, 0xe7, 0x0f, 0x54, 0xb9, 0xe2, + 0x14, 0x4f, 0xa2, 0xf9, 0x11, 0x4a, 0xa7, 0xfc, 0x1e, 0x45, 0xa8, 0xf3, 0x1b, 0x40, 0xad, 0xf6, + 0x28, 0x73, 0x9e, 0xc5, 0x2d, 0x76, 0x9b, 0xc0, 0x22, 0x79, 0x94, 0xcf, 0x27, 0x7c, 0x91, 0xca, + 0x3c, 0x67, 0x8a, 0xd1, 0x39, 0x62, 0x8f, 0xd4, 0x36, 0x6d, 0x80, 0xdb, 0x33, 0x68, 0x85, 0xde, + 0x50, 0x0b, 0xe6, 0xbd, 0x55, 0x0e, 0xe3, 0xb8, 0x5a, 0x01, 0xec, 0xb7, 0x5f, 0x04, 0xe9, 0xb2, + 0x44, 0x1f, 0xf2, 0xa9, 0x41, 0x1a, 0xf7, 0xac, 0x4e, 0x15, 0xf8, 0xa3, 0x4b, 0x10, 0xfd, 0xa6, + 0x78, 0x23, 0xce, 0x95, 0x7d, 0x26, 0xcb, 0x90, 0x72, 0x29, 0xc4, 0x9f, 0x77, 0x2c, 0xc1, 0x9a, + 0x6c, 0x37, 0xda, 0x81, 0x69, 0x32, 0xdf, 0x84, 0x66, 0x3d, 0xd0, 0x8b, 0x63, 0x38, 0xd5, 0x8e, + 0xa0, 0xfb, 0x16, 0x4d, 0xa5, 0xfe, 0x13, 0x48, 0xaa, 0xf1, 0x1c, 0x47, 0xaf, 0xf4, 0x19, 0x42, + 0xb4, 0xef, 0x02, 0x59, 0xb1, 0xea, 0x07, 0x5c, 0xbe, 0xe5, 0x08, 0x53, 0xbb, 0xe0, 0x0d, 0x56, + 0x88, 0xd3, 0x3e, 0x65, 0x8d, 0xd6, 0x3b, 0x60, 0x82, 0xd9, 0x34, 0x6f, 0x87, 0xdc, 0x31, 0x6a, + 0x9c, 0xc7, 0x2a, 0x71, 0x99, 0xc2, 0x2f, 0x74, 0x96, 0xcd, 0x20, 0x7b, 0x93, 0xc8, 0x25, 0x7e, + 0xf0, 0xab, 0x46, 0x1d, 0xf5, 0xae, 0x43, 0x18, 0xfa, 0xa1, 0x4c, 0x17, 0xff, 0xa4, 0x49, 0x12, + 0xe4, 0xbf, 0x52, 0x09, 0xe1, 0xba, 0x57, 0x0c, 0xee, 0xb5, 0x58, 0x03, 0xeb, 0xb0, 0x5d, 0x06, + 0xd8, 0x83, 0x6e, 0x35, 0xdd, 0x86, 0x6b, 0x30, 0xd2, 0x89, 0x64, 0x3f, 0xd7, 0x8c, 0x61, 0x3a, + 0xcc, 0x97, 0x7a, 0x21, 0xc9, 0x92, 0x7f, 0x24, 0xc6, 0x9d, 0x70, 0x2b, 0xc3, 0x98, 0x75, 0x2e +}; + +static const uint8_t MD2[256] = { + 0x00, 0xef, 0xb7, 0x58, 0x07, 0xe8, 0xb0, 0x5f, 0x0e, 0xe1, 0xb9, 0x56, 0x09, 0xe6, 0xbe, 0x51, + 0x1c, 0xf3, 0xab, 0x44, 0x1b, 0xf4, 0xac, 0x43, 0x12, 0xfd, 0xa5, 0x4a, 0x15, 0xfa, 0xa2, 0x4d, + 0x38, 0xd7, 0x8f, 0x60, 0x3f, 0xd0, 0x88, 0x67, 0x36, 0xd9, 0x81, 0x6e, 0x31, 0xde, 0x86, 0x69, + 0x24, 0xcb, 0x93, 0x7c, 0x23, 0xcc, 0x94, 0x7b, 0x2a, 0xc5, 0x9d, 0x72, 0x2d, 0xc2, 0x9a, 0x75, + 0x70, 0x9f, 0xc7, 0x28, 0x77, 0x98, 0xc0, 0x2f, 0x7e, 0x91, 0xc9, 0x26, 0x79, 0x96, 0xce, 0x21, + 0x6c, 0x83, 0xdb, 0x34, 0x6b, 0x84, 0xdc, 0x33, 0x62, 0x8d, 0xd5, 0x3a, 0x65, 0x8a, 0xd2, 0x3d, + 0x48, 0xa7, 0xff, 0x10, 0x4f, 0xa0, 0xf8, 0x17, 0x46, 0xa9, 0xf1, 0x1e, 0x41, 0xae, 0xf6, 0x19, + 0x54, 0xbb, 0xe3, 0x0c, 0x53, 0xbc, 0xe4, 0x0b, 0x5a, 0xb5, 0xed, 0x02, 0x5d, 0xb2, 0xea, 0x05, + 0xe0, 0x0f, 0x57, 0xb8, 0xe7, 0x08, 0x50, 0xbf, 0xee, 0x01, 0x59, 0xb6, 0xe9, 0x06, 0x5e, 0xb1, + 0xfc, 0x13, 0x4b, 0xa4, 0xfb, 0x14, 0x4c, 0xa3, 0xf2, 0x1d, 0x45, 0xaa, 0xf5, 0x1a, 0x42, 0xad, + 0xd8, 0x37, 0x6f, 0x80, 0xdf, 0x30, 0x68, 0x87, 0xd6, 0x39, 0x61, 0x8e, 0xd1, 0x3e, 0x66, 0x89, + 0xc4, 0x2b, 0x73, 0x9c, 0xc3, 0x2c, 0x74, 0x9b, 0xca, 0x25, 0x7d, 0x92, 0xcd, 0x22, 0x7a, 0x95, + 0x90, 0x7f, 0x27, 0xc8, 0x97, 0x78, 0x20, 0xcf, 0x9e, 0x71, 0x29, 0xc6, 0x99, 0x76, 0x2e, 0xc1, + 0x8c, 0x63, 0x3b, 0xd4, 0x8b, 0x64, 0x3c, 0xd3, 0x82, 0x6d, 0x35, 0xda, 0x85, 0x6a, 0x32, 0xdd, + 0xa8, 0x47, 0x1f, 0xf0, 0xaf, 0x40, 0x18, 0xf7, 0xa6, 0x49, 0x11, 0xfe, 0xa1, 0x4e, 0x16, 0xf9, + 0xb4, 0x5b, 0x03, 0xec, 0xb3, 0x5c, 0x04, 0xeb, 0xba, 0x55, 0x0d, 0xe2, 0xbd, 0x52, 0x0a, 0xe5 +}; + +static const uint8_t q0[256] = { + 0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38, + 0x0d, 0xc6, 0x35, 0x98, 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, 0x94, 0x48, + 0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82, + 0x63, 0x01, 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, 0x16, 0x0c, 0xe3, 0x61, + 0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1, + 0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95, 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7, + 0xfb, 0xc3, 0x8e, 0xb5, 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, 0x62, 0x71, + 0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7, + 0xa1, 0x1d, 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, 0x31, 0xc2, 0x27, 0x90, + 0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef, + 0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64, + 0x2a, 0xce, 0xcb, 0x2f, 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, 0xa7, 0x5a, + 0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d, + 0x57, 0xc7, 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, + 0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4, + 0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0 +}; + +static const uint8_t q1[256] = { + 0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b, + 0xd6, 0x32, 0xd8, 0xfd, 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, 0x06, 0x3f, + 0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5, + 0xa0, 0x84, 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, 0x92, 0x74, 0x36, 0x51, + 0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c, + 0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8, + 0xa6, 0x83, 0x20, 0xff, 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, 0x2b, 0xe2, + 0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17, + 0x66, 0x94, 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, 0xef, 0xd1, 0x53, 0x3e, + 0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9, + 0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48, + 0x4f, 0xf2, 0x65, 0x8e, 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, 0x05, 0x64, + 0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69, + 0x29, 0x2e, 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, 0x35, 0x6a, 0xcf, 0xdc, + 0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9, + 0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91 +}; + +struct AVTWOFISH *av_twofish_alloc(void) +{ + return av_mallocz(sizeof(struct AVTWOFISH)); +} + +const int av_twofish_size = sizeof(AVTWOFISH); + +static uint8_t gfmul(uint8_t a, uint8_t b) +{ + uint8_t r = 0, t; + while (a && b) { + if (a & 1) + r = r ^ b; + t = b & 0x80; + b = b << 1; + if (t) + b = b ^ 0x4d; + a = a >> 1; + } + return r; +} + +static uint32_t tf_RS(uint32_t k0, uint32_t k1) +{ + uint8_t s[4], m[8]; + AV_WL32(m, k0); + AV_WL32(m + 4, k1); + s[0] = gfmul(0x01, m[0]) ^ gfmul(0xa4, m[1]) ^ gfmul(0x55, m[2]) ^ gfmul(0x87, m[3]) ^ gfmul(0x5a, m[4]) ^ gfmul(0x58, m[5]) ^ gfmul(0xdb, m[6]) ^ gfmul(0x9e, m[7]); + s[1] = gfmul(0xa4, m[0]) ^ gfmul(0x56, m[1]) ^ gfmul(0x82, m[2]) ^ gfmul(0xf3, m[3]) ^ gfmul(0x1e, m[4]) ^ gfmul(0xc6, m[5]) ^ gfmul(0x68, m[6]) ^ gfmul(0xe5, m[7]); + s[2] = gfmul(0x02, m[0]) ^ gfmul(0xa1, m[1]) ^ gfmul(0xfc, m[2]) ^ gfmul(0xc1, m[3]) ^ gfmul(0x47, m[4]) ^ gfmul(0xae, m[5]) ^ gfmul(0x3d, m[6]) ^ gfmul(0x19, m[7]); + s[3] = gfmul(0xa4, m[0]) ^ gfmul(0x55, m[1]) ^ gfmul(0x87, m[2]) ^ gfmul(0x5a, m[3]) ^ gfmul(0x58, m[4]) ^ gfmul(0xdb, m[5]) ^ gfmul(0x9e, m[6]) ^ gfmul(0x03, m[7]); + return AV_RL32(s); +} + +static void tf_h0(uint8_t y[4], uint32_t L[4], int k) +{ + uint8_t l[4]; + if (k == 4) { + AV_WL32(l, L[3]); + y[0] = q1[y[0]] ^ l[0]; + y[1] = q0[y[1]] ^ l[1]; + y[2] = q0[y[2]] ^ l[2]; + y[3] = q1[y[3]] ^ l[3]; + } + if (k >= 3) { + AV_WL32(l, L[2]); + y[0] = q1[y[0]] ^ l[0]; + y[1] = q1[y[1]] ^ l[1]; + y[2] = q0[y[2]] ^ l[2]; + y[3] = q0[y[3]] ^ l[3]; + } + AV_WL32(l, L[1]); + y[0] = q1[q0[q0[y[0]] ^ l[0]] ^ (L[0] & 0xff)]; + y[1] = q0[q0[q1[y[1]] ^ l[1]] ^ ((L[0] >> 8) & 0xff)]; + y[2] = q1[q1[q0[y[2]] ^ l[2]] ^ ((L[0] >> 16) & 0xff)]; + y[3] = q0[q1[q1[y[3]] ^ l[3]] ^ (L[0] >> 24)]; +} + +static uint32_t tf_h(uint32_t X, uint32_t L[4], int k) +{ + uint8_t y[4], l[4]; + AV_WL32(y, X); + tf_h0(y, L, k); + + l[0] = y[0] ^ MD2[y[1]] ^ MD1[y[2]] ^ MD1[y[3]]; + l[1] = MD1[y[0]] ^ MD2[y[1]] ^ MD2[y[2]] ^ y[3]; + l[2] = MD2[y[0]] ^ MD1[y[1]] ^ y[2] ^ MD2[y[3]]; + l[3] = MD2[y[0]] ^ y[1] ^ MD2[y[2]] ^ MD1[y[3]]; + + return AV_RL32(l); +} + +static uint32_t MDS_mul(AVTWOFISH *cs, uint32_t X) +{ + return cs->MDS1[(X) & 0xff] ^ cs->MDS2[((X) >> 8) & 0xff] ^ cs->MDS3[((X) >> 16) & 0xff] ^ cs->MDS4[(X) >> 24]; +} + +static void precomputeMDS(AVTWOFISH *cs) +{ + uint8_t y[4]; + int i; + for (i = 0; i < 256; i++) { + y[0] = y[1] = y[2] = y[3] = i; + tf_h0(y, cs->S, cs->ksize); + cs->MDS1[i] = ((uint32_t)y[0]) ^ ((uint32_t)MD1[y[0]] << 8) ^ ((uint32_t)MD2[y[0]] << 16) ^ ((uint32_t)MD2[y[0]] << 24); + cs->MDS2[i] = ((uint32_t)MD2[y[1]]) ^ ((uint32_t)MD2[y[1]] << 8) ^ ((uint32_t)MD1[y[1]] << 16) ^ ((uint32_t)y[1] << 24); + cs->MDS3[i] = ((uint32_t)MD1[y[2]]) ^ ((uint32_t)MD2[y[2]] << 8) ^ ((uint32_t)y[2] << 16) ^ ((uint32_t)MD2[y[2]] << 24); + cs->MDS4[i] = ((uint32_t)MD1[y[3]]) ^ ((uint32_t)y[3] << 8) ^ ((uint32_t)MD2[y[3]] << 16) ^ ((uint32_t)MD1[y[3]] << 24); + } +} + +static void twofish_encrypt(AVTWOFISH *cs, uint8_t *dst, const uint8_t *src) +{ + uint32_t P[4], t0, t1; + int i; + P[0] = AV_RL32(src) ^ cs->K[0]; + P[1] = AV_RL32(src + 4) ^ cs->K[1]; + P[2] = AV_RL32(src + 8) ^ cs->K[2]; + P[3] = AV_RL32(src + 12) ^ cs->K[3]; + for (i = 0; i < 16; i += 2) { + t0 = MDS_mul(cs, P[0]); + t1 = MDS_mul(cs, LR(P[1], 8)); + P[2] = RR(P[2] ^ (t0 + t1 + cs->K[2 * i + 8]), 1); + P[3] = LR(P[3], 1) ^ (t0 + 2 * t1 + cs->K[2 * i + 9]); + t0 = MDS_mul(cs, P[2]); + t1 = MDS_mul(cs, LR(P[3], 8)); + P[0] = RR(P[0] ^ (t0 + t1 + cs->K[2 * i + 10]), 1); + P[1] = LR(P[1], 1) ^ (t0 + 2 * t1 + cs->K[2 * i + 11]); + } + P[2] ^= cs->K[4]; + P[3] ^= cs->K[5]; + P[0] ^= cs->K[6]; + P[1] ^= cs->K[7]; + AV_WL32(dst, P[2]); + AV_WL32(dst + 4, P[3]); + AV_WL32(dst + 8, P[0]); + AV_WL32(dst + 12, P[1]); +} + +static void twofish_decrypt(AVTWOFISH *cs, uint8_t *dst, const uint8_t *src, uint8_t *iv) +{ + uint32_t P[4], t0, t1; + int i; + P[2] = AV_RL32(src) ^ cs->K[4]; + P[3] = AV_RL32(src + 4) ^ cs->K[5]; + P[0] = AV_RL32(src + 8) ^ cs->K[6]; + P[1] = AV_RL32(src + 12) ^ cs->K[7]; + for (i = 15; i >= 0; i -= 2) { + t0 = MDS_mul(cs, P[2]); + t1 = MDS_mul(cs, LR(P[3], 8)); + P[0] = LR(P[0], 1) ^ (t0 + t1 + cs->K[2 * i + 8]); + P[1] = RR(P[1] ^ (t0 + 2 * t1 + cs->K[2 * i + 9]), 1); + t0 = MDS_mul(cs, P[0]); + t1 = MDS_mul(cs, LR(P[1], 8)); + P[2] = LR(P[2], 1) ^ (t0 + t1 + cs->K[2 * i + 6]); + P[3] = RR(P[3] ^ (t0 + 2 * t1 + cs->K[2 * i + 7]), 1); + } + P[0] ^= cs->K[0]; + P[1] ^= cs->K[1]; + P[2] ^= cs->K[2]; + P[3] ^= cs->K[3]; + if (iv) { + P[0] ^= AV_RL32(iv); + P[1] ^= AV_RL32(iv + 4); + P[2] ^= AV_RL32(iv + 8); + P[3] ^= AV_RL32(iv + 12); + memcpy(iv, src, 16); + } + AV_WL32(dst, P[0]); + AV_WL32(dst + 4, P[1]); + AV_WL32(dst + 8, P[2]); + AV_WL32(dst + 12, P[3]); +} + +av_cold int av_twofish_init(AVTWOFISH *cs, const uint8_t *key, int key_bits) +{ + int i; + uint8_t keypad[32]; + uint32_t Key[8], Me[4], Mo[4], A, B; + const uint32_t rho = 0x01010101; + if (key_bits < 0) + return AVERROR(EINVAL); + if (key_bits <= 128) { + cs->ksize = 2; + } else if (key_bits <= 192) { + cs->ksize = 3; + } else { + cs->ksize = 4; + } + memset(keypad, 0, sizeof(keypad)); + if (key_bits <= 256) { + memcpy(keypad, key, key_bits >> 3); + } else { + memcpy(keypad, key, 32); + } + for (i = 0; i < 2 * cs->ksize ; i++) + Key[i] = AV_RL32(keypad + 4 * i); + for (i = 0; i < cs->ksize; i++) { + Me[i] = Key[2 * i]; + Mo[i] = Key[2 * i + 1]; + cs->S[cs->ksize - i - 1] = tf_RS(Me[i], Mo[i]); + } + precomputeMDS(cs); + for (i = 0; i < 20; i++) { + A = tf_h((2 * i) * rho, Me, cs->ksize); + B = tf_h((2 * i + 1) * rho, Mo, cs->ksize); + B = LR(B, 8); + cs->K[2 * i] = A + B; + cs->K[2 * i + 1] = LR((A + (2 * B)), 9); + } + if (cs->ksize << 6 != key_bits) { + return 1; + } else { + return 0; + } +} + +void av_twofish_crypt(AVTWOFISH *cs, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt) +{ + int i; + while (count--) { + if (decrypt) { + twofish_decrypt(cs, dst, src, iv); + } else { + if (iv) { + for (i = 0; i < 16; i++) + dst[i] = src[i] ^ iv[i]; + twofish_encrypt(cs, dst, dst); + memcpy(iv, dst, 16); + } else { + twofish_encrypt(cs, dst, src); + } + } + src = src + 16; + dst = dst + 16; + } +} diff --git a/libs/ffmpeg/libavutil/twofish.h b/libs/ffmpeg/libavutil/twofish.h new file mode 100644 index 00000000000..67f359e88c2 --- /dev/null +++ b/libs/ffmpeg/libavutil/twofish.h @@ -0,0 +1,70 @@ +/* + * An implementation of the TwoFish algorithm + * Copyright (c) 2015 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TWOFISH_H +#define AVUTIL_TWOFISH_H + +#include <stdint.h> + + +/** + * @file + * @brief Public header for libavutil TWOFISH algorithm + * @defgroup lavu_twofish TWOFISH + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_twofish_size; + +struct AVTWOFISH; + +/** + * Allocate an AVTWOFISH context + * To free the struct: av_free(ptr) + */ +struct AVTWOFISH *av_twofish_alloc(void); + +/** + * Initialize an AVTWOFISH context. + * + * @param ctx an AVTWOFISH context + * @param key a key of size ranging from 1 to 32 bytes used for encryption/decryption + * @param key_bits number of keybits: 128, 192, 256 If less than the required, padded with zeroes to nearest valid value; return value is 0 if key_bits is 128/192/256, -1 if less than 0, 1 otherwise + */ +int av_twofish_init(struct AVTWOFISH *ctx, const uint8_t *key, int key_bits); + +/** + * Encrypt or decrypt a buffer using a previously initialized context + * + * @param ctx an AVTWOFISH context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 16 byte blocks + * @param iv initialization vector for CBC mode, NULL for ECB mode + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_twofish_crypt(struct AVTWOFISH *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t* iv, int decrypt); + +/** + * @} + */ +#endif /* AVUTIL_TWOFISH_H */ diff --git a/libs/ffmpeg/libavutil/tx.c b/libs/ffmpeg/libavutil/tx.c new file mode 100644 index 00000000000..05c132ada17 --- /dev/null +++ b/libs/ffmpeg/libavutil/tx.c @@ -0,0 +1,939 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avassert.h" +#include "intmath.h" +#include "cpu.h" +#include "mem.h" +#include "qsort.h" +#include "bprint.h" + +#include "tx_priv.h" + +#define TYPE_IS(type, x) \ + (((x) == AV_TX_FLOAT_ ## type) || \ + ((x) == AV_TX_DOUBLE_ ## type) || \ + ((x) == AV_TX_INT32_ ## type)) + +/* Calculates the modular multiplicative inverse */ +static av_always_inline int mulinv(int n, int m) +{ + n = n % m; + for (int x = 1; x < m; x++) + if (((n * x) % m) == 1) + return x; + av_assert0(0); /* Never reached */ + return 0; +} + +int ff_tx_gen_pfa_input_map(AVTXContext *s, FFTXCodeletOptions *opts, + int d1, int d2) +{ + const int sl = d1*d2; + + s->map = av_malloc(s->len*sizeof(*s->map)); + if (!s->map) + return AVERROR(ENOMEM); + + for (int k = 0; k < s->len; k += sl) { + if (s->inv || (opts && opts->map_dir == FF_TX_MAP_SCATTER)) { + for (int m = 0; m < d2; m++) + for (int n = 0; n < d1; n++) + s->map[k + ((m*d1 + n*d2) % (sl))] = m*d1 + n; + } else { + for (int m = 0; m < d2; m++) + for (int n = 0; n < d1; n++) + s->map[k + m*d1 + n] = (m*d1 + n*d2) % (sl); + } + + if (s->inv) + for (int w = 1; w <= ((sl) >> 1); w++) + FFSWAP(int, s->map[k + w], s->map[k + sl - w]); + } + + s->map_dir = opts ? opts->map_dir : FF_TX_MAP_GATHER; + + return 0; +} + +/* Guaranteed to work for any n, m where gcd(n, m) == 1 */ +int ff_tx_gen_compound_mapping(AVTXContext *s, FFTXCodeletOptions *opts, + int inv, int n, int m) +{ + int *in_map, *out_map; + const int len = n*m; /* Will not be equal to s->len for MDCTs */ + int m_inv, n_inv; + + /* Make sure the numbers are coprime */ + if (av_gcd(n, m) != 1) + return AVERROR(EINVAL); + + m_inv = mulinv(m, n); + n_inv = mulinv(n, m); + + if (!(s->map = av_malloc(2*len*sizeof(*s->map)))) + return AVERROR(ENOMEM); + + in_map = s->map; + out_map = s->map + len; + + /* Ruritanian map for input, CRT map for output, can be swapped */ + if (opts && opts->map_dir == FF_TX_MAP_SCATTER) { + for (int j = 0; j < m; j++) { + for (int i = 0; i < n; i++) { + in_map[(i*m + j*n) % len] = j*n + i; + out_map[(i*m*m_inv + j*n*n_inv) % len] = i*m + j; + } + } + } else { + for (int j = 0; j < m; j++) { + for (int i = 0; i < n; i++) { + in_map[j*n + i] = (i*m + j*n) % len; + out_map[(i*m*m_inv + j*n*n_inv) % len] = i*m + j; + } + } + } + + if (inv) { + for (int i = 0; i < m; i++) { + int *in = &in_map[i*n + 1]; /* Skip the DC */ + for (int j = 0; j < ((n - 1) >> 1); j++) + FFSWAP(int, in[j], in[n - j - 2]); + } + } + + s->map_dir = opts ? opts->map_dir : FF_TX_MAP_GATHER; + + return 0; +} + +static inline int split_radix_permutation(int i, int len, int inv) +{ + len >>= 1; + if (len <= 1) + return i & 1; + if (!(i & len)) + return split_radix_permutation(i, len, inv) * 2; + len >>= 1; + return split_radix_permutation(i, len, inv) * 4 + 1 - 2*(!(i & len) ^ inv); +} + +int ff_tx_gen_ptwo_revtab(AVTXContext *s, FFTXCodeletOptions *opts) +{ + int len = s->len; + + if (!(s->map = av_malloc(len*sizeof(*s->map)))) + return AVERROR(ENOMEM); + + if (opts && opts->map_dir == FF_TX_MAP_SCATTER) { + for (int i = 0; i < s->len; i++) + s->map[-split_radix_permutation(i, len, s->inv) & (len - 1)] = i; + } else { + for (int i = 0; i < s->len; i++) + s->map[i] = -split_radix_permutation(i, len, s->inv) & (len - 1); + } + + s->map_dir = opts ? opts->map_dir : FF_TX_MAP_GATHER; + + return 0; +} + +int ff_tx_gen_inplace_map(AVTXContext *s, int len) +{ + int *src_map, out_map_idx = 0; + + if (!s->sub || !s->sub->map) + return AVERROR(EINVAL); + + if (!(s->map = av_mallocz(len*sizeof(*s->map)))) + return AVERROR(ENOMEM); + + src_map = s->sub->map; + + /* The first coefficient is always already in-place */ + for (int src = 1; src < s->len; src++) { + int dst = src_map[src]; + int found = 0; + + if (dst <= src) + continue; + + /* This just checks if a closed loop has been encountered before, + * and if so, skips it, since to fully permute a loop we must only + * enter it once. */ + do { + for (int j = 0; j < out_map_idx; j++) { + if (dst == s->map[j]) { + found = 1; + break; + } + } + dst = src_map[dst]; + } while (dst != src && !found); + + if (!found) + s->map[out_map_idx++] = src; + } + + s->map[out_map_idx++] = 0; + + return 0; +} + +static void parity_revtab_generator(int *revtab, int n, int inv, int offset, + int is_dual, int dual_high, int len, + int basis, int dual_stride, int inv_lookup) +{ + len >>= 1; + + if (len <= basis) { + int k1, k2, stride, even_idx, odd_idx; + + is_dual = is_dual && dual_stride; + dual_high = is_dual & dual_high; + stride = is_dual ? FFMIN(dual_stride, len) : 0; + + even_idx = offset + dual_high*(stride - 2*len); + odd_idx = even_idx + len + (is_dual && !dual_high)*len + dual_high*len; + + for (int i = 0; i < len; i++) { + k1 = -split_radix_permutation(offset + i*2 + 0, n, inv) & (n - 1); + k2 = -split_radix_permutation(offset + i*2 + 1, n, inv) & (n - 1); + if (inv_lookup) { + revtab[even_idx++] = k1; + revtab[odd_idx++] = k2; + } else { + revtab[k1] = even_idx++; + revtab[k2] = odd_idx++; + } + if (stride && !((i + 1) % stride)) { + even_idx += stride; + odd_idx += stride; + } + } + + return; + } + + parity_revtab_generator(revtab, n, inv, offset, + 0, 0, len >> 0, basis, dual_stride, inv_lookup); + parity_revtab_generator(revtab, n, inv, offset + (len >> 0), + 1, 0, len >> 1, basis, dual_stride, inv_lookup); + parity_revtab_generator(revtab, n, inv, offset + (len >> 0) + (len >> 1), + 1, 1, len >> 1, basis, dual_stride, inv_lookup); +} + +int ff_tx_gen_split_radix_parity_revtab(AVTXContext *s, int len, int inv, + FFTXCodeletOptions *opts, + int basis, int dual_stride) +{ + basis >>= 1; + if (len < basis) + return AVERROR(EINVAL); + + if (!(s->map = av_mallocz(len*sizeof(*s->map)))) + return AVERROR(ENOMEM); + + av_assert0(!dual_stride || !(dual_stride & (dual_stride - 1))); + av_assert0(dual_stride <= basis); + + parity_revtab_generator(s->map, len, inv, 0, 0, 0, len, + basis, dual_stride, + opts ? opts->map_dir == FF_TX_MAP_GATHER : FF_TX_MAP_GATHER); + + s->map_dir = opts ? opts->map_dir : FF_TX_MAP_GATHER; + + return 0; +} + +static void reset_ctx(AVTXContext *s, int free_sub) +{ + if (!s) + return; + + if (s->sub) + for (int i = 0; i < TX_MAX_SUB; i++) + reset_ctx(&s->sub[i], free_sub + 1); + + if (s->cd_self && s->cd_self->uninit) + s->cd_self->uninit(s); + + if (free_sub) + av_freep(&s->sub); + + av_freep(&s->map); + av_freep(&s->exp); + av_freep(&s->tmp); + + /* Nothing else needs to be reset, it gets overwritten if another + * ff_tx_init_subtx() call is made. */ + s->nb_sub = 0; + s->opaque = NULL; + memset(s->fn, 0, sizeof(s->fn)); +} + +void ff_tx_clear_ctx(AVTXContext *s) +{ + reset_ctx(s, 0); +} + +av_cold void av_tx_uninit(AVTXContext **ctx) +{ + if (!(*ctx)) + return; + + reset_ctx(*ctx, 1); + av_freep(ctx); +} + +static av_cold int ff_tx_null_init(AVTXContext *s, const FFTXCodelet *cd, + uint64_t flags, FFTXCodeletOptions *opts, + int len, int inv, const void *scale) +{ + /* Can only handle one sample+type to one sample+type transforms */ + if (TYPE_IS(MDCT, s->type) || TYPE_IS(RDFT, s->type)) + return AVERROR(EINVAL); + return 0; +} + +/* Null transform when the length is 1 */ +static void ff_tx_null(AVTXContext *s, void *_out, void *_in, ptrdiff_t stride) +{ + memcpy(_out, _in, stride); +} + +static const FFTXCodelet ff_tx_null_def = { + .name = NULL_IF_CONFIG_SMALL("null"), + .function = ff_tx_null, + .type = TX_TYPE_ANY, + .flags = AV_TX_UNALIGNED | FF_TX_ALIGNED | + FF_TX_OUT_OF_PLACE | AV_TX_INPLACE, + .factors[0] = TX_FACTOR_ANY, + .min_len = 1, + .max_len = 1, + .init = ff_tx_null_init, + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_MAX, +}; + +static const FFTXCodelet * const ff_tx_null_list[] = { + &ff_tx_null_def, + NULL, +}; + +/* Array of all compiled codelet lists. Order is irrelevant. */ +static const FFTXCodelet * const * const codelet_list[] = { + ff_tx_codelet_list_float_c, + ff_tx_codelet_list_double_c, + ff_tx_codelet_list_int32_c, + ff_tx_null_list, +#if HAVE_X86ASM + ff_tx_codelet_list_float_x86, +#endif +#if ARCH_AARCH64 + ff_tx_codelet_list_float_aarch64, +#endif +}; +static const int codelet_list_num = FF_ARRAY_ELEMS(codelet_list); + +static const int cpu_slow_mask = AV_CPU_FLAG_SSE2SLOW | AV_CPU_FLAG_SSE3SLOW | + AV_CPU_FLAG_ATOM | AV_CPU_FLAG_SSSE3SLOW | + AV_CPU_FLAG_AVXSLOW | AV_CPU_FLAG_SLOW_GATHER; + +static const int cpu_slow_penalties[][2] = { + { AV_CPU_FLAG_SSE2SLOW, 1 + 64 }, + { AV_CPU_FLAG_SSE3SLOW, 1 + 64 }, + { AV_CPU_FLAG_SSSE3SLOW, 1 + 64 }, + { AV_CPU_FLAG_ATOM, 1 + 128 }, + { AV_CPU_FLAG_AVXSLOW, 1 + 128 }, + { AV_CPU_FLAG_SLOW_GATHER, 1 + 32 }, +}; + +static int get_codelet_prio(const FFTXCodelet *cd, int cpu_flags, int len) +{ + int prio = cd->prio; + int max_factor = 0; + + /* If the CPU has a SLOW flag, and the instruction is also flagged + * as being slow for such, reduce its priority */ + for (int i = 0; i < FF_ARRAY_ELEMS(cpu_slow_penalties); i++) { + if ((cpu_flags & cd->cpu_flags) & cpu_slow_penalties[i][0]) + prio -= cpu_slow_penalties[i][1]; + } + + /* Prioritize aligned-only codelets */ + if ((cd->flags & FF_TX_ALIGNED) && !(cd->flags & AV_TX_UNALIGNED)) + prio += 64; + + /* Codelets for specific lengths are generally faster */ + if ((len == cd->min_len) && (len == cd->max_len)) + prio += 64; + + /* Forward-only or inverse-only transforms are generally better */ + if ((cd->flags & (FF_TX_FORWARD_ONLY | FF_TX_INVERSE_ONLY))) + prio += 64; + + /* Larger factors are generally better */ + for (int i = 0; i < TX_MAX_SUB; i++) + max_factor = FFMAX(cd->factors[i], max_factor); + if (max_factor) + prio += 16*max_factor; + + return prio; +} + +typedef struct FFTXLenDecomp { + int len; + int len2; + int prio; + const FFTXCodelet *cd; +} FFTXLenDecomp; + +static int cmp_decomp(FFTXLenDecomp *a, FFTXLenDecomp *b) +{ + return FFDIFFSIGN(b->prio, a->prio); +} + +int ff_tx_decompose_length(int dst[TX_MAX_DECOMPOSITIONS], enum AVTXType type, + int len, int inv) +{ + int nb_decomp = 0; + FFTXLenDecomp ld[TX_MAX_DECOMPOSITIONS]; + int codelet_list_idx = codelet_list_num; + + const int cpu_flags = av_get_cpu_flags(); + + /* Loop through all codelets in all codelet lists to find matches + * to the requirements */ + while (codelet_list_idx--) { + const FFTXCodelet * const * list = codelet_list[codelet_list_idx]; + const FFTXCodelet *cd = NULL; + + while ((cd = *list++)) { + int fl = len; + int skip = 0, prio; + int factors_product = 1, factors_mod = 0; + + if (nb_decomp >= TX_MAX_DECOMPOSITIONS) + goto sort; + + /* Check if the type matches */ + if (cd->type != TX_TYPE_ANY && type != cd->type) + continue; + + /* Check direction for non-orthogonal codelets */ + if (((cd->flags & FF_TX_FORWARD_ONLY) && inv) || + ((cd->flags & (FF_TX_INVERSE_ONLY | AV_TX_FULL_IMDCT)) && !inv) || + ((cd->flags & (FF_TX_FORWARD_ONLY | AV_TX_REAL_TO_REAL)) && inv) || + ((cd->flags & (FF_TX_FORWARD_ONLY | AV_TX_REAL_TO_IMAGINARY)) && inv)) + continue; + + /* Check if the CPU supports the required ISA */ + if (cd->cpu_flags != FF_TX_CPU_FLAGS_ALL && + !(cpu_flags & (cd->cpu_flags & ~cpu_slow_mask))) + continue; + + for (int i = 0; i < TX_MAX_FACTORS; i++) { + if (!cd->factors[i] || (fl == 1)) + break; + + if (cd->factors[i] == TX_FACTOR_ANY) { + factors_mod++; + factors_product *= fl; + } else if (!(fl % cd->factors[i])) { + factors_mod++; + if (cd->factors[i] == 2) { + int b = ff_ctz(fl); + fl >>= b; + factors_product <<= b; + } else { + do { + fl /= cd->factors[i]; + factors_product *= cd->factors[i]; + } while (!(fl % cd->factors[i])); + } + } + } + + /* Disqualify if factor requirements are not satisfied or if trivial */ + if ((factors_mod < cd->nb_factors) || (len == factors_product)) + continue; + + if (av_gcd(factors_product, fl) != 1) + continue; + + /* Check if length is supported and factorization was successful */ + if ((factors_product < cd->min_len) || + (cd->max_len != TX_LEN_UNLIMITED && (factors_product > cd->max_len))) + continue; + + prio = get_codelet_prio(cd, cpu_flags, factors_product) * factors_product; + + /* Check for duplicates */ + for (int i = 0; i < nb_decomp; i++) { + if (factors_product == ld[i].len) { + /* Update priority if new one is higher */ + if (prio > ld[i].prio) + ld[i].prio = prio; + skip = 1; + break; + } + } + + /* Add decomposition if unique */ + if (!skip) { + ld[nb_decomp].cd = cd; + ld[nb_decomp].len = factors_product; + ld[nb_decomp].len2 = fl; + ld[nb_decomp].prio = prio; + nb_decomp++; + } + } + } + + if (!nb_decomp) + return AVERROR(EINVAL); + +sort: + AV_QSORT(ld, nb_decomp, FFTXLenDecomp, cmp_decomp); + + for (int i = 0; i < nb_decomp; i++) { + if (ld[i].cd->nb_factors > 1) + dst[i] = ld[i].len2; + else + dst[i] = ld[i].len; + } + + return nb_decomp; +} + +int ff_tx_gen_default_map(AVTXContext *s, FFTXCodeletOptions *opts) +{ + s->map = av_malloc(s->len*sizeof(*s->map)); + if (!s->map) + return AVERROR(ENOMEM); + + s->map[0] = 0; /* DC is always at the start */ + if (s->inv) /* Reversing the ACs flips the transform direction */ + for (int i = 1; i < s->len; i++) + s->map[i] = s->len - i; + else + for (int i = 1; i < s->len; i++) + s->map[i] = i; + + s->map_dir = FF_TX_MAP_GATHER; + + return 0; +} + +#if !CONFIG_SMALL +static void print_flags(AVBPrint *bp, uint64_t f) +{ + int prev = 0; + const char *sep = ", "; + av_bprintf(bp, "flags: ["); + if ((f & FF_TX_ALIGNED) && ++prev) + av_bprintf(bp, "aligned"); + if ((f & AV_TX_UNALIGNED) && ++prev) + av_bprintf(bp, "%sunaligned", prev > 1 ? sep : ""); + if ((f & AV_TX_INPLACE) && ++prev) + av_bprintf(bp, "%sinplace", prev > 1 ? sep : ""); + if ((f & FF_TX_OUT_OF_PLACE) && ++prev) + av_bprintf(bp, "%sout_of_place", prev > 1 ? sep : ""); + if ((f & FF_TX_FORWARD_ONLY) && ++prev) + av_bprintf(bp, "%sfwd_only", prev > 1 ? sep : ""); + if ((f & FF_TX_INVERSE_ONLY) && ++prev) + av_bprintf(bp, "%sinv_only", prev > 1 ? sep : ""); + if ((f & FF_TX_PRESHUFFLE) && ++prev) + av_bprintf(bp, "%spreshuf", prev > 1 ? sep : ""); + if ((f & AV_TX_FULL_IMDCT) && ++prev) + av_bprintf(bp, "%simdct_full", prev > 1 ? sep : ""); + if ((f & AV_TX_REAL_TO_REAL) && ++prev) + av_bprintf(bp, "%sreal_to_real", prev > 1 ? sep : ""); + if ((f & AV_TX_REAL_TO_IMAGINARY) && ++prev) + av_bprintf(bp, "%sreal_to_imaginary", prev > 1 ? sep : ""); + if ((f & FF_TX_ASM_CALL) && ++prev) + av_bprintf(bp, "%sasm_call", prev > 1 ? sep : ""); + av_bprintf(bp, "]"); +} + +static void print_type(AVBPrint *bp, enum AVTXType type) +{ + av_bprintf(bp, "%s", + type == TX_TYPE_ANY ? "any" : + type == AV_TX_FLOAT_FFT ? "fft_float" : + type == AV_TX_FLOAT_MDCT ? "mdct_float" : + type == AV_TX_FLOAT_RDFT ? "rdft_float" : + type == AV_TX_FLOAT_DCT_I ? "dctI_float" : + type == AV_TX_FLOAT_DST_I ? "dstI_float" : + type == AV_TX_DOUBLE_FFT ? "fft_double" : + type == AV_TX_DOUBLE_MDCT ? "mdct_double" : + type == AV_TX_DOUBLE_RDFT ? "rdft_double" : + type == AV_TX_DOUBLE_DCT_I ? "dctI_double" : + type == AV_TX_DOUBLE_DST_I ? "dstI_double" : + type == AV_TX_INT32_FFT ? "fft_int32" : + type == AV_TX_INT32_MDCT ? "mdct_int32" : + type == AV_TX_INT32_RDFT ? "rdft_int32" : + type == AV_TX_INT32_DCT_I ? "dctI_int32" : + type == AV_TX_INT32_DST_I ? "dstI_int32" : + "unknown"); +} + +static void print_cd_info(const FFTXCodelet *cd, int prio, int len, int print_prio, + int log_level) +{ + AVBPrint bp; + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); + + av_bprintf(&bp, "%s - type: ", cd->name); + + print_type(&bp, cd->type); + + av_bprintf(&bp, ", len: "); + if (!len) { + if (cd->min_len != cd->max_len) + av_bprintf(&bp, "[%i, ", cd->min_len); + + if (cd->max_len == TX_LEN_UNLIMITED) + av_bprintf(&bp, "∞"); + else + av_bprintf(&bp, "%i", cd->max_len); + } else { + av_bprintf(&bp, "%i", len); + } + + if (cd->factors[1]) { + av_bprintf(&bp, "%s, factors", !len && cd->min_len != cd->max_len ? "]" : ""); + if (!cd->nb_factors) + av_bprintf(&bp, ": ["); + else + av_bprintf(&bp, "[%i]: [", cd->nb_factors); + + for (int i = 0; i < TX_MAX_FACTORS; i++) { + if (i && cd->factors[i]) + av_bprintf(&bp, ", "); + if (cd->factors[i] == TX_FACTOR_ANY) + av_bprintf(&bp, "any"); + else if (cd->factors[i]) + av_bprintf(&bp, "%i", cd->factors[i]); + else + break; + } + + av_bprintf(&bp, "], "); + } else { + av_bprintf(&bp, "%s, factor: %i, ", + !len && cd->min_len != cd->max_len ? "]" : "", cd->factors[0]); + } + print_flags(&bp, cd->flags); + + if (print_prio) + av_bprintf(&bp, ", prio: %i", prio); + + av_log(NULL, log_level, "%s\n", bp.str); +} + +static void print_tx_structure(AVTXContext *s, int depth) +{ + const FFTXCodelet *cd = s->cd_self; + + for (int i = 0; i <= depth; i++) + av_log(NULL, AV_LOG_DEBUG, " "); + + print_cd_info(cd, cd->prio, s->len, 0, AV_LOG_DEBUG); + + for (int i = 0; i < s->nb_sub; i++) + print_tx_structure(&s->sub[i], depth + 1); +} +#endif /* CONFIG_SMALL */ + +typedef struct TXCodeletMatch { + const FFTXCodelet *cd; + int prio; +} TXCodeletMatch; + +static int cmp_matches(TXCodeletMatch *a, TXCodeletMatch *b) +{ + return FFDIFFSIGN(b->prio, a->prio); +} + +/* We want all factors to completely cover the length */ +static inline int check_cd_factors(const FFTXCodelet *cd, int len) +{ + int matches = 0, any_flag = 0; + + for (int i = 0; i < TX_MAX_FACTORS; i++) { + int factor = cd->factors[i]; + + if (factor == TX_FACTOR_ANY) { + any_flag = 1; + matches++; + continue; + } else if (len <= 1 || !factor) { + break; + } else if (factor == 2) { /* Fast path */ + int bits_2 = ff_ctz(len); + if (!bits_2) + continue; /* Factor not supported */ + + len >>= bits_2; + matches++; + } else { + int res = len % factor; + if (res) + continue; /* Factor not supported */ + + while (!res) { + len /= factor; + res = len % factor; + } + matches++; + } + } + + return (cd->nb_factors <= matches) && (any_flag || len == 1); +} + +av_cold int ff_tx_init_subtx(AVTXContext *s, enum AVTXType type, + uint64_t flags, FFTXCodeletOptions *opts, + int len, int inv, const void *scale) +{ + int ret = 0; + AVTXContext *sub = NULL; + TXCodeletMatch *cd_tmp, *cd_matches = NULL; + unsigned int cd_matches_size = 0; + int codelet_list_idx = codelet_list_num; + int nb_cd_matches = 0; +#if !CONFIG_SMALL + AVBPrint bp; +#endif + + /* We still accept functions marked with SLOW, even if the CPU is + * marked with the same flag, but we give them lower priority. */ + const int cpu_flags = av_get_cpu_flags(); + + /* Flags the transform wants */ + uint64_t req_flags = flags; + + /* Flags the codelet may require to be present */ + uint64_t inv_req_mask = AV_TX_FULL_IMDCT | + AV_TX_REAL_TO_REAL | + AV_TX_REAL_TO_IMAGINARY | + FF_TX_PRESHUFFLE | + FF_TX_ASM_CALL; + + /* Unaligned codelets are compatible with the aligned flag */ + if (req_flags & FF_TX_ALIGNED) + req_flags |= AV_TX_UNALIGNED; + + /* If either flag is set, both are okay, so don't check for an exact match */ + if ((req_flags & AV_TX_INPLACE) && (req_flags & FF_TX_OUT_OF_PLACE)) + req_flags &= ~(AV_TX_INPLACE | FF_TX_OUT_OF_PLACE); + if ((req_flags & FF_TX_ALIGNED) && (req_flags & AV_TX_UNALIGNED)) + req_flags &= ~(FF_TX_ALIGNED | AV_TX_UNALIGNED); + + /* Loop through all codelets in all codelet lists to find matches + * to the requirements */ + while (codelet_list_idx--) { + const FFTXCodelet * const * list = codelet_list[codelet_list_idx]; + const FFTXCodelet *cd = NULL; + + while ((cd = *list++)) { + /* Check if the type matches */ + if (cd->type != TX_TYPE_ANY && type != cd->type) + continue; + + /* Check direction for non-orthogonal codelets */ + if (((cd->flags & FF_TX_FORWARD_ONLY) && inv) || + ((cd->flags & (FF_TX_INVERSE_ONLY | AV_TX_FULL_IMDCT)) && !inv) || + ((cd->flags & (FF_TX_FORWARD_ONLY | AV_TX_REAL_TO_REAL)) && inv) || + ((cd->flags & (FF_TX_FORWARD_ONLY | AV_TX_REAL_TO_IMAGINARY)) && inv)) + continue; + + /* Check if the requested flags match from both sides */ + if (((req_flags & cd->flags) != (req_flags)) || + ((inv_req_mask & cd->flags) != (req_flags & inv_req_mask))) + continue; + + /* Check if length is supported */ + if ((len < cd->min_len) || (cd->max_len != -1 && (len > cd->max_len))) + continue; + + /* Check if the CPU supports the required ISA */ + if (cd->cpu_flags != FF_TX_CPU_FLAGS_ALL && + !(cpu_flags & (cd->cpu_flags & ~cpu_slow_mask))) + continue; + + /* Check for factors */ + if (!check_cd_factors(cd, len)) + continue; + + /* Realloc array and append */ + cd_tmp = av_fast_realloc(cd_matches, &cd_matches_size, + sizeof(*cd_tmp) * (nb_cd_matches + 1)); + if (!cd_tmp) { + av_free(cd_matches); + return AVERROR(ENOMEM); + } + + cd_matches = cd_tmp; + cd_matches[nb_cd_matches].cd = cd; + cd_matches[nb_cd_matches].prio = get_codelet_prio(cd, cpu_flags, len); + nb_cd_matches++; + } + } + +#if !CONFIG_SMALL + /* Print debugging info */ + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); + av_bprintf(&bp, "For transform of length %i, %s, ", len, + inv ? "inverse" : "forward"); + print_type(&bp, type); + av_bprintf(&bp, ", "); + print_flags(&bp, flags); + av_bprintf(&bp, ", found %i matches%s", nb_cd_matches, + nb_cd_matches ? ":" : "."); +#endif + + /* No matches found */ + if (!nb_cd_matches) + return AVERROR(ENOSYS); + + /* Sort the list */ + AV_QSORT(cd_matches, nb_cd_matches, TXCodeletMatch, cmp_matches); + +#if !CONFIG_SMALL + av_log(NULL, AV_LOG_TRACE, "%s\n", bp.str); + + for (int i = 0; i < nb_cd_matches; i++) { + av_log(NULL, AV_LOG_TRACE, " %i: ", i + 1); + print_cd_info(cd_matches[i].cd, cd_matches[i].prio, 0, 1, AV_LOG_TRACE); + } +#endif + + if (!s->sub) { + s->sub = sub = av_mallocz(TX_MAX_SUB*sizeof(*sub)); + if (!sub) { + ret = AVERROR(ENOMEM); + goto end; + } + } + + /* Attempt to initialize each */ + for (int i = 0; i < nb_cd_matches; i++) { + const FFTXCodelet *cd = cd_matches[i].cd; + AVTXContext *sctx = &s->sub[s->nb_sub]; + + sctx->len = len; + sctx->inv = inv; + sctx->type = type; + sctx->flags = cd->flags | flags; + sctx->cd_self = cd; + + s->fn[s->nb_sub] = cd->function; + s->cd[s->nb_sub] = cd; + + ret = 0; + if (cd->init) + ret = cd->init(sctx, cd, flags, opts, len, inv, scale); + + if (ret >= 0) { + if (opts && opts->map_dir != FF_TX_MAP_NONE && + sctx->map_dir == FF_TX_MAP_NONE) { + /* If a specific map direction was requested, and it doesn't + * exist, create one.*/ + sctx->map = av_malloc(len*sizeof(*sctx->map)); + if (!sctx->map) { + ret = AVERROR(ENOMEM); + goto end; + } + + for (int i = 0; i < len; i++) + sctx->map[i] = i; + } else if (opts && (opts->map_dir != sctx->map_dir)) { + int *tmp = av_malloc(len*sizeof(*sctx->map)); + if (!tmp) { + ret = AVERROR(ENOMEM); + goto end; + } + + memcpy(tmp, sctx->map, len*sizeof(*sctx->map)); + + for (int i = 0; i < len; i++) + sctx->map[tmp[i]] = i; + + av_free(tmp); + } + + s->nb_sub++; + goto end; + } + + s->fn[s->nb_sub] = NULL; + s->cd[s->nb_sub] = NULL; + + reset_ctx(sctx, 0); + if (ret == AVERROR(ENOMEM)) + break; + } + + if (!s->nb_sub) + av_freep(&s->sub); + +end: + av_free(cd_matches); + return ret; +} + +av_cold int av_tx_init(AVTXContext **ctx, av_tx_fn *tx, enum AVTXType type, + int inv, int len, const void *scale, uint64_t flags) +{ + int ret; + AVTXContext tmp = { 0 }; + const double default_scale_d = 1.0; + const float default_scale_f = 1.0f; + + if (!len || type >= AV_TX_NB || !ctx || !tx) + return AVERROR(EINVAL); + + if (!(flags & AV_TX_UNALIGNED)) + flags |= FF_TX_ALIGNED; + if (!(flags & AV_TX_INPLACE)) + flags |= FF_TX_OUT_OF_PLACE; + + if (!scale && ((type == AV_TX_DOUBLE_MDCT) || (type == AV_TX_DOUBLE_DCT) || + (type == AV_TX_DOUBLE_DCT_I) || (type == AV_TX_DOUBLE_DST_I) || + (type == AV_TX_DOUBLE_RDFT))) + scale = &default_scale_d; + else if (!scale && !TYPE_IS(FFT, type)) + scale = &default_scale_f; + + ret = ff_tx_init_subtx(&tmp, type, flags, NULL, len, inv, scale); + if (ret < 0) + return ret; + + *ctx = &tmp.sub[0]; + *tx = tmp.fn[0]; + +#if !CONFIG_SMALL + av_log(NULL, AV_LOG_DEBUG, "Transform tree:\n"); + print_tx_structure(*ctx, 0); +#endif + + return ret; +} diff --git a/libs/ffmpeg/libavutil/tx.h b/libs/ffmpeg/libavutil/tx.h new file mode 100644 index 00000000000..c950095735d --- /dev/null +++ b/libs/ffmpeg/libavutil/tx.h @@ -0,0 +1,210 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TX_H +#define AVUTIL_TX_H + +#include <stdint.h> +#include <stddef.h> + +typedef struct AVTXContext AVTXContext; + +typedef struct AVComplexFloat { + float re, im; +} AVComplexFloat; + +typedef struct AVComplexDouble { + double re, im; +} AVComplexDouble; + +typedef struct AVComplexInt32 { + int32_t re, im; +} AVComplexInt32; + +enum AVTXType { + /** + * Standard complex to complex FFT with sample data type of AVComplexFloat, + * AVComplexDouble or AVComplexInt32, for each respective variant. + * + * Output is not 1/len normalized. Scaling currently unsupported. + * The stride parameter must be set to the size of a single sample in bytes. + */ + AV_TX_FLOAT_FFT = 0, + AV_TX_DOUBLE_FFT = 2, + AV_TX_INT32_FFT = 4, + + /** + * Standard MDCT with a sample data type of float, double or int32_t, + * respectively. For the float and int32 variants, the scale type is + * 'float', while for the double variant, it's 'double'. + * If scale is NULL, 1.0 will be used as a default. + * + * Length is the frame size, not the window size (which is 2x frame). + * For forward transforms, the stride specifies the spacing between each + * sample in the output array in bytes. The input must be a flat array. + * + * For inverse transforms, the stride specifies the spacing between each + * sample in the input array in bytes. The output must be a flat array. + * + * NOTE: the inverse transform is half-length, meaning the output will not + * contain redundant data. This is what most codecs work with. To do a full + * inverse transform, set the AV_TX_FULL_IMDCT flag on init. + */ + AV_TX_FLOAT_MDCT = 1, + AV_TX_DOUBLE_MDCT = 3, + AV_TX_INT32_MDCT = 5, + + /** + * Real to complex and complex to real DFTs. + * For the float and int32 variants, the scale type is 'float', while for + * the double variant, it's a 'double'. If scale is NULL, 1.0 will be used + * as a default. + * + * For forward transforms (R2C), stride must be the spacing between two + * samples in bytes. For inverse transforms, the stride must be set + * to the spacing between two complex values in bytes. + * + * The forward transform performs a real-to-complex DFT of N samples to + * N/2+1 complex values. + * + * The inverse transform performs a complex-to-real DFT of N/2+1 complex + * values to N real samples. The output is not normalized, but can be + * made so by setting the scale value to 1.0/len. + * NOTE: the inverse transform always overwrites the input. + */ + AV_TX_FLOAT_RDFT = 6, + AV_TX_DOUBLE_RDFT = 7, + AV_TX_INT32_RDFT = 8, + + /** + * Real to real (DCT) transforms. + * + * The forward transform is a DCT-II. + * The inverse transform is a DCT-III. + * + * The input array is always overwritten. DCT-III requires that the + * input be padded with 2 extra samples. Stride must be set to the + * spacing between two samples in bytes. + */ + AV_TX_FLOAT_DCT = 9, + AV_TX_DOUBLE_DCT = 10, + AV_TX_INT32_DCT = 11, + + /** + * Discrete Cosine Transform I + * + * The forward transform is a DCT-I. + * The inverse transform is a DCT-I multiplied by 2/(N + 1). + * + * The input array is always overwritten. + */ + AV_TX_FLOAT_DCT_I = 12, + AV_TX_DOUBLE_DCT_I = 13, + AV_TX_INT32_DCT_I = 14, + + /** + * Discrete Sine Transform I + * + * The forward transform is a DST-I. + * The inverse transform is a DST-I multiplied by 2/(N + 1). + * + * The input array is always overwritten. + */ + AV_TX_FLOAT_DST_I = 15, + AV_TX_DOUBLE_DST_I = 16, + AV_TX_INT32_DST_I = 17, + + /* Not part of the API, do not use */ + AV_TX_NB, +}; + +/** + * Function pointer to a function to perform the transform. + * + * @note Using a different context than the one allocated during av_tx_init() + * is not allowed. + * + * @param s the transform context + * @param out the output array + * @param in the input array + * @param stride the input or output stride in bytes + * + * The out and in arrays must be aligned to the maximum required by the CPU + * architecture unless the AV_TX_UNALIGNED flag was set in av_tx_init(). + * The stride must follow the constraints the transform type has specified. + */ +typedef void (*av_tx_fn)(AVTXContext *s, void *out, void *in, ptrdiff_t stride); + +/** + * Flags for av_tx_init() + */ +enum AVTXFlags { + /** + * Allows for in-place transformations, where input == output. + * May be unsupported or slower for some transform types. + */ + AV_TX_INPLACE = 1ULL << 0, + + /** + * Relaxes alignment requirement for the in and out arrays of av_tx_fn(). + * May be slower with certain transform types. + */ + AV_TX_UNALIGNED = 1ULL << 1, + + /** + * Performs a full inverse MDCT rather than leaving out samples that can be + * derived through symmetry. Requires an output array of 'len' floats, + * rather than the usual 'len/2' floats. + * Ignored for all transforms but inverse MDCTs. + */ + AV_TX_FULL_IMDCT = 1ULL << 2, + + /** + * Perform a real to half-complex RDFT. + * Only the real, or imaginary coefficients will + * be output, depending on the flag used. Only available for forward RDFTs. + * Output array must have enough space to hold N complex values + * (regular size for a real to complex transform). + */ + AV_TX_REAL_TO_REAL = 1ULL << 3, + AV_TX_REAL_TO_IMAGINARY = 1ULL << 4, +}; + +/** + * Initialize a transform context with the given configuration + * (i)MDCTs with an odd length are currently not supported. + * + * @param ctx the context to allocate, will be NULL on error + * @param tx pointer to the transform function pointer to set + * @param type type the type of transform + * @param inv whether to do an inverse or a forward transform + * @param len the size of the transform in samples + * @param scale pointer to the value to scale the output if supported by type + * @param flags a bitmask of AVTXFlags or 0 + * + * @return 0 on success, negative error code on failure + */ +int av_tx_init(AVTXContext **ctx, av_tx_fn *tx, enum AVTXType type, + int inv, int len, const void *scale, uint64_t flags); + +/** + * Frees a context and sets *ctx to NULL, does nothing when *ctx == NULL. + */ +void av_tx_uninit(AVTXContext **ctx); + +#endif /* AVUTIL_TX_H */ diff --git a/libs/ffmpeg/libavutil/tx_double.c b/libs/ffmpeg/libavutil/tx_double.c new file mode 100644 index 00000000000..7ea4283c947 --- /dev/null +++ b/libs/ffmpeg/libavutil/tx_double.c @@ -0,0 +1,21 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define TX_DOUBLE +#include "tx_priv.h" +#include "tx_template.c" diff --git a/libs/ffmpeg/libavutil/tx_float.c b/libs/ffmpeg/libavutil/tx_float.c new file mode 100644 index 00000000000..018f2a21acc --- /dev/null +++ b/libs/ffmpeg/libavutil/tx_float.c @@ -0,0 +1,21 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define TX_FLOAT +#include "tx_priv.h" +#include "tx_template.c" diff --git a/libs/ffmpeg/libavutil/tx_int32.c b/libs/ffmpeg/libavutil/tx_int32.c new file mode 100644 index 00000000000..9261013bf61 --- /dev/null +++ b/libs/ffmpeg/libavutil/tx_int32.c @@ -0,0 +1,21 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define TX_INT32 +#include "tx_priv.h" +#include "tx_template.c" diff --git a/libs/ffmpeg/libavutil/tx_priv.h b/libs/ffmpeg/libavutil/tx_priv.h new file mode 100644 index 00000000000..d3fcdbf5634 --- /dev/null +++ b/libs/ffmpeg/libavutil/tx_priv.h @@ -0,0 +1,392 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TX_PRIV_H +#define AVUTIL_TX_PRIV_H + +#include "tx.h" +#include "thread.h" +#include "mem_internal.h" +#include "common.h" +#include "attributes.h" + +#ifdef TX_FLOAT +#define TX_TAB(x) x ## _float +#define TX_NAME(x) x ## _float_c +#define TX_NAME_STR(x) NULL_IF_CONFIG_SMALL(x "_float_c") +#define TX_TYPE(x) AV_TX_FLOAT_ ## x +#define TX_FN_NAME(fn, suffix) ff_tx_ ## fn ## _float_ ## suffix +#define TX_FN_NAME_STR(fn, suffix) NULL_IF_CONFIG_SMALL(#fn "_float_" #suffix) +#define MULT(x, m) ((x) * (m)) +#define SCALE_TYPE float +typedef float TXSample; +typedef float TXUSample; +typedef AVComplexFloat TXComplex; +#elif defined(TX_DOUBLE) +#define TX_TAB(x) x ## _double +#define TX_NAME(x) x ## _double_c +#define TX_NAME_STR(x) NULL_IF_CONFIG_SMALL(x "_double_c") +#define TX_TYPE(x) AV_TX_DOUBLE_ ## x +#define TX_FN_NAME(fn, suffix) ff_tx_ ## fn ## _double_ ## suffix +#define TX_FN_NAME_STR(fn, suffix) NULL_IF_CONFIG_SMALL(#fn "_double_" #suffix) +#define MULT(x, m) ((x) * (m)) +#define SCALE_TYPE double +typedef double TXSample; +typedef double TXUSample; +typedef AVComplexDouble TXComplex; +#elif defined(TX_INT32) +#define TX_TAB(x) x ## _int32 +#define TX_NAME(x) x ## _int32_c +#define TX_NAME_STR(x) NULL_IF_CONFIG_SMALL(x "_int32_c") +#define TX_TYPE(x) AV_TX_INT32_ ## x +#define TX_FN_NAME(fn, suffix) ff_tx_ ## fn ## _int32_ ## suffix +#define TX_FN_NAME_STR(fn, suffix) NULL_IF_CONFIG_SMALL(#fn "_int32_" #suffix) +#define MULT(x, m) (((((int64_t)(x)) * (int64_t)(m)) + 0x40000000) >> 31) +#define SCALE_TYPE float +typedef int32_t TXSample; +typedef uint32_t TXUSample; +typedef AVComplexInt32 TXComplex; +#else +typedef void TXComplex; +#endif + +#define TX_DECL_FN(fn, suffix) \ + void TX_FN_NAME(fn, suffix)(AVTXContext *s, void *o, void *i, ptrdiff_t st); + +#define TX_DEF(fn, tx_type, len_min, len_max, f1, f2, \ + p, init_fn, suffix, cf, cd_flags, cf2) \ + &(const FFTXCodelet){ \ + .name = TX_FN_NAME_STR(fn, suffix), \ + .function = TX_FN_NAME(fn, suffix), \ + .type = TX_TYPE(tx_type), \ + .flags = FF_TX_ALIGNED | FF_TX_OUT_OF_PLACE | cd_flags, \ + .factors = { (f1), (f2) }, \ + .nb_factors = !!(f1) + !!(f2), \ + .min_len = len_min, \ + .max_len = len_max, \ + .init = init_fn, \ + .cpu_flags = cf2 | AV_CPU_FLAG_ ## cf, \ + .prio = p, \ + } + +#if defined(TX_FLOAT) || defined(TX_DOUBLE) + +#define CMUL(dre, dim, are, aim, bre, bim) \ + do { \ + (dre) = (are) * (bre) - (aim) * (bim); \ + (dim) = (are) * (bim) + (aim) * (bre); \ + } while (0) + +#define SMUL(dre, dim, are, aim, bre, bim) \ + do { \ + (dre) = (are) * (bre) - (aim) * (bim); \ + (dim) = (are) * (bim) - (aim) * (bre); \ + } while (0) + +#define UNSCALE(x) (x) +#define RESCALE(x) (x) + +#define FOLD(a, b) ((a) + (b)) + +#define BF(x, y, a, b) \ + do { \ + x = (a) - (b); \ + y = (a) + (b); \ + } while (0) + +#elif defined(TX_INT32) + +/* Properly rounds the result */ +#define CMUL(dre, dim, are, aim, bre, bim) \ + do { \ + int64_t accu; \ + (accu) = (int64_t)(bre) * (are); \ + (accu) -= (int64_t)(bim) * (aim); \ + (dre) = (int)(((accu) + 0x40000000) >> 31); \ + (accu) = (int64_t)(bim) * (are); \ + (accu) += (int64_t)(bre) * (aim); \ + (dim) = (int)(((accu) + 0x40000000) >> 31); \ + } while (0) + +#define SMUL(dre, dim, are, aim, bre, bim) \ + do { \ + int64_t accu; \ + (accu) = (int64_t)(bre) * (are); \ + (accu) -= (int64_t)(bim) * (aim); \ + (dre) = (int)(((accu) + 0x40000000) >> 31); \ + (accu) = (int64_t)(bim) * (are); \ + (accu) -= (int64_t)(bre) * (aim); \ + (dim) = (int)(((accu) + 0x40000000) >> 31); \ + } while (0) + +#define UNSCALE(x) ((double)(x)/2147483648.0) +#define RESCALE(x) (av_clip64(llrintf((x) * 2147483648.0), INT32_MIN, INT32_MAX)) + +#define FOLD(x, y) ((int32_t)((x) + (unsigned)(y) + 32) >> 6) + +#define BF(x, y, a, b) \ + do { \ + x = (a) - (unsigned)(b); \ + y = (a) + (unsigned)(b); \ + } while (0) + +#endif /* TX_INT32 */ + +#define CMUL3(c, a, b) CMUL((c).re, (c).im, (a).re, (a).im, (b).re, (b).im) + +/* Codelet flags, used to pick codelets. Must be a superset of enum AVTXFlags, + * but if it runs out of bits, it can be made separate. */ +#define FF_TX_OUT_OF_PLACE (1ULL << 63) /* Can be OR'd with AV_TX_INPLACE */ +#define FF_TX_ALIGNED (1ULL << 62) /* Cannot be OR'd with AV_TX_UNALIGNED */ +#define FF_TX_PRESHUFFLE (1ULL << 61) /* Codelet expects permuted coeffs */ +#define FF_TX_INVERSE_ONLY (1ULL << 60) /* For non-orthogonal inverse-only transforms */ +#define FF_TX_FORWARD_ONLY (1ULL << 59) /* For non-orthogonal forward-only transforms */ +#define FF_TX_ASM_CALL (1ULL << 58) /* For asm->asm functions only */ + +typedef enum FFTXCodeletPriority { + FF_TX_PRIO_BASE = 0, /* Baseline priority */ + + /* For SIMD, set base prio to the register size in bits and increment in + * steps of 64 depending on faster/slower features, like FMA. */ + + FF_TX_PRIO_MIN = -131072, /* For naive implementations */ + FF_TX_PRIO_MAX = 32768, /* For custom implementations/ASICs */ +} FFTXCodeletPriority; + +typedef enum FFTXMapDirection { + /* No map. Make a map up. */ + FF_TX_MAP_NONE = 0, + + /* Lookup table must be applied via dst[i] = src[lut[i]]; */ + FF_TX_MAP_GATHER, + + /* Lookup table must be applied via dst[lut[i]] = src[i]; */ + FF_TX_MAP_SCATTER, +} FFTXMapDirection; + +/* Codelet options */ +typedef struct FFTXCodeletOptions { + /* Request a specific lookup table direction. Codelets MUST put the + * direction in AVTXContext. If the codelet does not respect this, a + * conversion will be performed. */ + FFTXMapDirection map_dir; +} FFTXCodeletOptions; + +/* Maximum number of factors a codelet may have. Arbitrary. */ +#define TX_MAX_FACTORS 16 + +/* Maximum amount of subtransform functions, subtransforms and factors. Arbitrary. */ +#define TX_MAX_SUB 4 + +/* Maximum number of returned results for ff_tx_decompose_length. Arbitrary. */ +#define TX_MAX_DECOMPOSITIONS 512 + +typedef struct FFTXCodelet { + const char *name; /* Codelet name, for debugging */ + av_tx_fn function; /* Codelet function, != NULL */ + enum AVTXType type; /* Type of codelet transform */ +#define TX_TYPE_ANY INT32_MAX /* Special type to allow all types */ + + uint64_t flags; /* A combination of AVTXFlags and codelet + * flags that describe its properties. */ + + int factors[TX_MAX_FACTORS]; /* Length factors. MUST be coprime. */ +#define TX_FACTOR_ANY -1 /* When used alone, signals that the codelet + * supports all factors. Otherwise, if other + * factors are present, it signals that whatever + * remains will be supported, as long as the + * other factors are a component of the length */ + + int nb_factors; /* Minimum number of factors that have to + * be a modulo of the length. Must not be 0. */ + + int min_len; /* Minimum length of transform, must be >= 1 */ + int max_len; /* Maximum length of transform */ +#define TX_LEN_UNLIMITED -1 /* Special length value to permit all lengths */ + + int (*init)(AVTXContext *s, /* Optional callback for current context initialization. */ + const struct FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale); + + int (*uninit)(AVTXContext *s); /* Optional callback for uninitialization. */ + + int cpu_flags; /* CPU flags. If any negative flags like + * SLOW are present, will avoid picking. + * 0x0 to signal it's a C codelet */ +#define FF_TX_CPU_FLAGS_ALL 0x0 /* Special CPU flag for C */ + + int prio; /* < 0 = least, 0 = no pref, > 0 = prefer */ +} FFTXCodelet; + +struct AVTXContext { + /* Fields the root transform and subtransforms use or may use. + * NOTE: This section is used by assembly, do not reorder or change */ + int len; /* Length of the transform */ + int inv; /* If transform is inverse */ + int *map; /* Lookup table(s) */ + TXComplex *exp; /* Any non-pre-baked multiplication factors, + * or extra temporary buffer */ + TXComplex *tmp; /* Temporary buffer, if needed */ + + AVTXContext *sub; /* Subtransform context(s), if needed */ + av_tx_fn fn[TX_MAX_SUB]; /* Function(s) for the subtransforms */ + int nb_sub; /* Number of subtransforms. + * The reason all of these are set here + * rather than in each separate context + * is to eliminate extra pointer + * dereferences. */ + + /* Fields mainly useul/applicable for the root transform or initialization. + * Fields below are not used by assembly code. */ + const FFTXCodelet *cd[TX_MAX_SUB]; /* Subtransform codelets */ + const FFTXCodelet *cd_self; /* Codelet for the current context */ + enum AVTXType type; /* Type of transform */ + uint64_t flags; /* A combination of AVTXFlags and + * codelet flags used when creating */ + FFTXMapDirection map_dir; /* Direction of AVTXContext->map */ + float scale_f; + double scale_d; + void *opaque; /* Free to use by implementations */ +}; + +/* This function embeds a Ruritanian PFA input map into an existing lookup table + * to avoid double permutation. This allows for compound factors to be + * synthesized as fast PFA FFTs and embedded into either other or standalone + * transforms. + * The output CRT map must still be pre-baked into the transform. */ +#define TX_EMBED_INPUT_PFA_MAP(map, tot_len, d1, d2) \ + do { \ + int mtmp[(d1)*(d2)]; \ + for (int k = 0; k < tot_len; k += (d1)*(d2)) { \ + memcpy(mtmp, &map[k], (d1)*(d2)*sizeof(*mtmp)); \ + for (int m = 0; m < (d2); m++) \ + for (int n = 0; n < (d1); n++) \ + map[k + m*(d1) + n] = mtmp[(m*(d1) + n*(d2)) % ((d1)*(d2))]; \ + } \ + } while (0) + +/* This function generates a Ruritanian PFA input map into s->map. */ +int ff_tx_gen_pfa_input_map(AVTXContext *s, FFTXCodeletOptions *opts, + int d1, int d2); + +/* Create a subtransform in the current context with the given parameters. + * The flags parameter from FFTXCodelet.init() should be preserved as much + * as that's possible. + * MUST be called during the sub() callback of each codelet. */ +int ff_tx_init_subtx(AVTXContext *s, enum AVTXType type, + uint64_t flags, FFTXCodeletOptions *opts, + int len, int inv, const void *scale); + +/* Clear the context by freeing all tables, maps and subtransforms. */ +void ff_tx_clear_ctx(AVTXContext *s); + +/* Attempt to factorize a length into 2 integers such that + * len / dst1 == dst2, where dst1 and dst2 are coprime. */ +int ff_tx_decompose_length(int dst[TX_MAX_DECOMPOSITIONS], enum AVTXType type, + int len, int inv); + +/* Generate a default map (0->len or 0, (len-1)->1 for inverse transforms) + * for a context. */ +int ff_tx_gen_default_map(AVTXContext *s, FFTXCodeletOptions *opts); + +/* + * Generates the PFA permutation table into AVTXContext->pfatab. The end table + * is appended to the start table. + * The `inv` flag should only be enabled if the lookup tables of subtransforms + * won't get flattened. + */ +int ff_tx_gen_compound_mapping(AVTXContext *s, FFTXCodeletOptions *opts, + int inv, int n, int m); + +/* + * Generates a standard-ish (slightly modified) Split-Radix revtab into + * AVTXContext->map. Invert lookup changes how the mapping needs to be applied. + * If it's set to 0, it has to be applied like out[map[i]] = in[i], otherwise + * if it's set to 1, has to be applied as out[i] = in[map[i]] + */ +int ff_tx_gen_ptwo_revtab(AVTXContext *s, FFTXCodeletOptions *opts); + +/* + * Generates an index into AVTXContext->inplace_idx that if followed in the + * specific order, allows the revtab to be done in-place. The sub-transform + * and its map should already be initialized. + */ +int ff_tx_gen_inplace_map(AVTXContext *s, int len); + +/* + * This generates a parity-based revtab of length len and direction inv. + * + * Parity means even and odd complex numbers will be split, e.g. the even + * coefficients will come first, after which the odd coefficients will be + * placed. For example, a 4-point transform's coefficients after reordering: + * z[0].re, z[0].im, z[2].re, z[2].im, z[1].re, z[1].im, z[3].re, z[3].im + * + * The basis argument is the length of the largest non-composite transform + * supported, and also implies that the basis/2 transform is supported as well, + * as the split-radix algorithm requires it to be. + * + * The dual_stride argument indicates that both the basis, as well as the + * basis/2 transforms support doing two transforms at once, and the coefficients + * will be interleaved between each pair in a split-radix like so (stride == 2): + * tx1[0], tx1[2], tx2[0], tx2[2], tx1[1], tx1[3], tx2[1], tx2[3] + * A non-zero number switches this on, with the value indicating the stride + * (how many values of 1 transform to put first before switching to the other). + * Must be a power of two or 0. Must be less than the basis. + * Value will be clipped to the transform size, so for a basis of 16 and a + * dual_stride of 8, dual 8-point transforms will be laid out as if dual_stride + * was set to 4. + * Usually you'll set this to half the complex numbers that fit in a single + * register or 0. This allows to reuse SSE functions as dual-transform + * functions in AVX mode. + * + * If length is smaller than basis/2 this function will not do anything. + * + * If inv_lookup is set to 1, it will flip the lookup from out[map[i]] = src[i] + * to out[i] = src[map[i]]. + */ +int ff_tx_gen_split_radix_parity_revtab(AVTXContext *s, int len, int inv, + FFTXCodeletOptions *opts, + int basis, int dual_stride); + +/* Typed init function to initialize shared tables. Will initialize all tables + * for all factors of a length. */ +void ff_tx_init_tabs_float (int len); +void ff_tx_init_tabs_double(int len); +void ff_tx_init_tabs_int32 (int len); + +/* Typed init function to initialize an MDCT exptab in a context. + * If pre_tab is set, duplicates the entire table, with the first + * copy being shuffled according to pre_tab, and the second copy + * being the original. */ +int ff_tx_mdct_gen_exp_float (AVTXContext *s, int *pre_tab); +int ff_tx_mdct_gen_exp_double(AVTXContext *s, int *pre_tab); +int ff_tx_mdct_gen_exp_int32 (AVTXContext *s, int *pre_tab); + +/* Lists of codelets */ +extern const FFTXCodelet * const ff_tx_codelet_list_float_c []; +extern const FFTXCodelet * const ff_tx_codelet_list_float_x86 []; +extern const FFTXCodelet * const ff_tx_codelet_list_float_aarch64 []; + +extern const FFTXCodelet * const ff_tx_codelet_list_double_c []; + +extern const FFTXCodelet * const ff_tx_codelet_list_int32_c []; + +#endif /* AVUTIL_TX_PRIV_H */ diff --git a/libs/ffmpeg/libavutil/tx_template.c b/libs/ffmpeg/libavutil/tx_template.c new file mode 100644 index 00000000000..26b9d74b584 --- /dev/null +++ b/libs/ffmpeg/libavutil/tx_template.c @@ -0,0 +1,2208 @@ +/* + * Copyright (c) Lynne + * + * Power of two FFT: + * Copyright (c) Lynne + * Copyright (c) 2008 Loren Merritt + * Copyright (c) 2002 Fabrice Bellard + * Partly based on libdjbfft by D. J. Bernstein + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if 0 +#pragma makedep header +#endif + +#include "mem.h" + +#define TABLE_DEF(name, size) \ + DECLARE_ALIGNED(32, TXSample, TX_TAB(ff_tx_tab_ ##name))[size] + +#define SR_POW2_TABLES \ + SR_TABLE(8) \ + SR_TABLE(16) \ + SR_TABLE(32) \ + SR_TABLE(64) \ + SR_TABLE(128) \ + SR_TABLE(256) \ + SR_TABLE(512) \ + SR_TABLE(1024) \ + SR_TABLE(2048) \ + SR_TABLE(4096) \ + SR_TABLE(8192) \ + SR_TABLE(16384) \ + SR_TABLE(32768) \ + SR_TABLE(65536) \ + SR_TABLE(131072) \ + +#define SR_TABLE(len) \ + TABLE_DEF(len, len/4 + 1); +/* Power of two tables */ +SR_POW2_TABLES +#undef SR_TABLE + +/* Other factors' tables */ +TABLE_DEF(53, 12); +TABLE_DEF( 7, 6); +TABLE_DEF( 9, 8); + +typedef struct FFTabInitData { + void (*func)(void); + int factors[TX_MAX_SUB]; /* Must be sorted high -> low */ +} FFTabInitData; + +#define SR_TABLE(len) \ +static av_cold void TX_TAB(ff_tx_init_tab_ ##len)(void) \ +{ \ + double freq = 2*M_PI/len; \ + TXSample *tab = TX_TAB(ff_tx_tab_ ##len); \ + \ + for (int i = 0; i < len/4; i++) \ + *tab++ = RESCALE(cos(i*freq)); \ + \ + *tab = 0; \ +} +SR_POW2_TABLES +#undef SR_TABLE + +static void (*const sr_tabs_init_funcs[])(void) = { +#define SR_TABLE(len) TX_TAB(ff_tx_init_tab_ ##len), + SR_POW2_TABLES +#undef SR_TABLE +}; + +static AVOnce sr_tabs_init_once[] = { +#define SR_TABLE(len) AV_ONCE_INIT, + SR_POW2_TABLES +#undef SR_TABLE +}; + +static av_cold void TX_TAB(ff_tx_init_tab_53)(void) +{ + /* 5pt, doubled to eliminate AVX lane shuffles */ + TX_TAB(ff_tx_tab_53)[0] = RESCALE(cos(2 * M_PI / 5)); + TX_TAB(ff_tx_tab_53)[1] = RESCALE(cos(2 * M_PI / 5)); + TX_TAB(ff_tx_tab_53)[2] = RESCALE(cos(2 * M_PI / 10)); + TX_TAB(ff_tx_tab_53)[3] = RESCALE(cos(2 * M_PI / 10)); + TX_TAB(ff_tx_tab_53)[4] = RESCALE(sin(2 * M_PI / 5)); + TX_TAB(ff_tx_tab_53)[5] = RESCALE(sin(2 * M_PI / 5)); + TX_TAB(ff_tx_tab_53)[6] = RESCALE(sin(2 * M_PI / 10)); + TX_TAB(ff_tx_tab_53)[7] = RESCALE(sin(2 * M_PI / 10)); + + /* 3pt */ + TX_TAB(ff_tx_tab_53)[ 8] = RESCALE(cos(2 * M_PI / 12)); + TX_TAB(ff_tx_tab_53)[ 9] = RESCALE(cos(2 * M_PI / 12)); + TX_TAB(ff_tx_tab_53)[10] = RESCALE(cos(2 * M_PI / 6)); + TX_TAB(ff_tx_tab_53)[11] = RESCALE(cos(8 * M_PI / 6)); +} + +static av_cold void TX_TAB(ff_tx_init_tab_7)(void) +{ + TX_TAB(ff_tx_tab_7)[0] = RESCALE(cos(2 * M_PI / 7)); + TX_TAB(ff_tx_tab_7)[1] = RESCALE(sin(2 * M_PI / 7)); + TX_TAB(ff_tx_tab_7)[2] = RESCALE(sin(2 * M_PI / 28)); + TX_TAB(ff_tx_tab_7)[3] = RESCALE(cos(2 * M_PI / 28)); + TX_TAB(ff_tx_tab_7)[4] = RESCALE(cos(2 * M_PI / 14)); + TX_TAB(ff_tx_tab_7)[5] = RESCALE(sin(2 * M_PI / 14)); +} + +static av_cold void TX_TAB(ff_tx_init_tab_9)(void) +{ + TX_TAB(ff_tx_tab_9)[0] = RESCALE(cos(2 * M_PI / 3)); + TX_TAB(ff_tx_tab_9)[1] = RESCALE(sin(2 * M_PI / 3)); + TX_TAB(ff_tx_tab_9)[2] = RESCALE(cos(2 * M_PI / 9)); + TX_TAB(ff_tx_tab_9)[3] = RESCALE(sin(2 * M_PI / 9)); + TX_TAB(ff_tx_tab_9)[4] = RESCALE(cos(2 * M_PI / 36)); + TX_TAB(ff_tx_tab_9)[5] = RESCALE(sin(2 * M_PI / 36)); + TX_TAB(ff_tx_tab_9)[6] = TX_TAB(ff_tx_tab_9)[2] + TX_TAB(ff_tx_tab_9)[5]; + TX_TAB(ff_tx_tab_9)[7] = TX_TAB(ff_tx_tab_9)[3] - TX_TAB(ff_tx_tab_9)[4]; +} + +static const FFTabInitData nptwo_tabs_init_data[] = { + { TX_TAB(ff_tx_init_tab_53), { 15, 5, 3 } }, + { TX_TAB(ff_tx_init_tab_9), { 9 } }, + { TX_TAB(ff_tx_init_tab_7), { 7 } }, +}; + +static AVOnce nptwo_tabs_init_once[] = { + AV_ONCE_INIT, + AV_ONCE_INIT, + AV_ONCE_INIT, +}; + +av_cold void TX_TAB(ff_tx_init_tabs)(int len) +{ + int factor_2 = ff_ctz(len); + if (factor_2) { + int idx = factor_2 - 3; + for (int i = 0; i <= idx; i++) + ff_thread_once(&sr_tabs_init_once[i], + sr_tabs_init_funcs[i]); + len >>= factor_2; + } + + for (int i = 0; i < FF_ARRAY_ELEMS(nptwo_tabs_init_data); i++) { + int f, f_idx = 0; + + if (len <= 1) + return; + + while ((f = nptwo_tabs_init_data[i].factors[f_idx++])) { + if (f % len) + continue; + + ff_thread_once(&nptwo_tabs_init_once[i], + nptwo_tabs_init_data[i].func); + len /= f; + break; + } + } +} + +static av_always_inline void fft3(TXComplex *out, TXComplex *in, + ptrdiff_t stride) +{ + TXComplex tmp[3]; + const TXSample *tab = TX_TAB(ff_tx_tab_53); +#ifdef TX_INT32 + int64_t mtmp[4]; +#endif + + tmp[0] = in[0]; + BF(tmp[1].re, tmp[2].im, in[1].im, in[2].im); + BF(tmp[1].im, tmp[2].re, in[1].re, in[2].re); + +#ifdef TX_INT32 + out[0*stride].re = (int64_t)tmp[0].re + tmp[2].re; + out[0*stride].im = (int64_t)tmp[0].im + tmp[2].im; + mtmp[0] = (int64_t)tab[ 8] * tmp[1].re; + mtmp[1] = (int64_t)tab[ 9] * tmp[1].im; + mtmp[2] = (int64_t)tab[10] * tmp[2].re; + mtmp[3] = (int64_t)tab[10] * tmp[2].im; + out[1*stride].re = tmp[0].re - (mtmp[2] + mtmp[0] + 0x40000000 >> 31); + out[1*stride].im = tmp[0].im - (mtmp[3] - mtmp[1] + 0x40000000 >> 31); + out[2*stride].re = tmp[0].re - (mtmp[2] - mtmp[0] + 0x40000000 >> 31); + out[2*stride].im = tmp[0].im - (mtmp[3] + mtmp[1] + 0x40000000 >> 31); +#else + out[0*stride].re = tmp[0].re + tmp[2].re; + out[0*stride].im = tmp[0].im + tmp[2].im; + tmp[1].re = tab[ 8] * tmp[1].re; + tmp[1].im = tab[ 9] * tmp[1].im; + tmp[2].re = tab[10] * tmp[2].re; + tmp[2].im = tab[10] * tmp[2].im; + out[1*stride].re = tmp[0].re - tmp[2].re + tmp[1].re; + out[1*stride].im = tmp[0].im - tmp[2].im - tmp[1].im; + out[2*stride].re = tmp[0].re - tmp[2].re - tmp[1].re; + out[2*stride].im = tmp[0].im - tmp[2].im + tmp[1].im; +#endif +} + +#define DECL_FFT5(NAME, D0, D1, D2, D3, D4) \ +static av_always_inline void NAME(TXComplex *out, TXComplex *in, \ + ptrdiff_t stride) \ +{ \ + TXComplex dc, z0[4], t[6]; \ + const TXSample *tab = TX_TAB(ff_tx_tab_53); \ + \ + dc = in[0]; \ + BF(t[1].im, t[0].re, in[1].re, in[4].re); \ + BF(t[1].re, t[0].im, in[1].im, in[4].im); \ + BF(t[3].im, t[2].re, in[2].re, in[3].re); \ + BF(t[3].re, t[2].im, in[2].im, in[3].im); \ + \ + out[D0*stride].re = dc.re + (TXUSample)t[0].re + t[2].re; \ + out[D0*stride].im = dc.im + (TXUSample)t[0].im + t[2].im; \ + \ + SMUL(t[4].re, t[0].re, tab[0], tab[2], t[2].re, t[0].re); \ + SMUL(t[4].im, t[0].im, tab[0], tab[2], t[2].im, t[0].im); \ + CMUL(t[5].re, t[1].re, tab[4], tab[6], t[3].re, t[1].re); \ + CMUL(t[5].im, t[1].im, tab[4], tab[6], t[3].im, t[1].im); \ + \ + BF(z0[0].re, z0[3].re, t[0].re, t[1].re); \ + BF(z0[0].im, z0[3].im, t[0].im, t[1].im); \ + BF(z0[2].re, z0[1].re, t[4].re, t[5].re); \ + BF(z0[2].im, z0[1].im, t[4].im, t[5].im); \ + \ + out[D1*stride].re = dc.re + (TXUSample)z0[3].re; \ + out[D1*stride].im = dc.im + (TXUSample)z0[0].im; \ + out[D2*stride].re = dc.re + (TXUSample)z0[2].re; \ + out[D2*stride].im = dc.im + (TXUSample)z0[1].im; \ + out[D3*stride].re = dc.re + (TXUSample)z0[1].re; \ + out[D3*stride].im = dc.im + (TXUSample)z0[2].im; \ + out[D4*stride].re = dc.re + (TXUSample)z0[0].re; \ + out[D4*stride].im = dc.im + (TXUSample)z0[3].im; \ +} + +DECL_FFT5(fft5, 0, 1, 2, 3, 4) +DECL_FFT5(fft5_m1, 0, 6, 12, 3, 9) +DECL_FFT5(fft5_m2, 10, 1, 7, 13, 4) +DECL_FFT5(fft5_m3, 5, 11, 2, 8, 14) + +static av_always_inline void fft7(TXComplex *out, TXComplex *in, + ptrdiff_t stride) +{ + TXComplex dc, t[6], z[3]; + const TXComplex *tab = (const TXComplex *)TX_TAB(ff_tx_tab_7); +#ifdef TX_INT32 + int64_t mtmp[12]; +#endif + + dc = in[0]; + BF(t[1].re, t[0].re, in[1].re, in[6].re); + BF(t[1].im, t[0].im, in[1].im, in[6].im); + BF(t[3].re, t[2].re, in[2].re, in[5].re); + BF(t[3].im, t[2].im, in[2].im, in[5].im); + BF(t[5].re, t[4].re, in[3].re, in[4].re); + BF(t[5].im, t[4].im, in[3].im, in[4].im); + + out[0*stride].re = dc.re + t[0].re + t[2].re + t[4].re; + out[0*stride].im = dc.im + t[0].im + t[2].im + t[4].im; + +#ifdef TX_INT32 /* NOTE: it's possible to do this with 16 mults but 72 adds */ + mtmp[ 0] = ((int64_t)tab[0].re)*t[0].re - ((int64_t)tab[2].re)*t[4].re; + mtmp[ 1] = ((int64_t)tab[0].re)*t[4].re - ((int64_t)tab[1].re)*t[0].re; + mtmp[ 2] = ((int64_t)tab[0].re)*t[2].re - ((int64_t)tab[2].re)*t[0].re; + mtmp[ 3] = ((int64_t)tab[0].re)*t[0].im - ((int64_t)tab[1].re)*t[2].im; + mtmp[ 4] = ((int64_t)tab[0].re)*t[4].im - ((int64_t)tab[1].re)*t[0].im; + mtmp[ 5] = ((int64_t)tab[0].re)*t[2].im - ((int64_t)tab[2].re)*t[0].im; + + mtmp[ 6] = ((int64_t)tab[2].im)*t[1].im + ((int64_t)tab[1].im)*t[5].im; + mtmp[ 7] = ((int64_t)tab[0].im)*t[5].im + ((int64_t)tab[2].im)*t[3].im; + mtmp[ 8] = ((int64_t)tab[2].im)*t[5].im + ((int64_t)tab[1].im)*t[3].im; + mtmp[ 9] = ((int64_t)tab[0].im)*t[1].re + ((int64_t)tab[1].im)*t[3].re; + mtmp[10] = ((int64_t)tab[2].im)*t[3].re + ((int64_t)tab[0].im)*t[5].re; + mtmp[11] = ((int64_t)tab[2].im)*t[1].re + ((int64_t)tab[1].im)*t[5].re; + + z[0].re = (int32_t)(mtmp[ 0] - ((int64_t)tab[1].re)*t[2].re + 0x40000000 >> 31); + z[1].re = (int32_t)(mtmp[ 1] - ((int64_t)tab[2].re)*t[2].re + 0x40000000 >> 31); + z[2].re = (int32_t)(mtmp[ 2] - ((int64_t)tab[1].re)*t[4].re + 0x40000000 >> 31); + z[0].im = (int32_t)(mtmp[ 3] - ((int64_t)tab[2].re)*t[4].im + 0x40000000 >> 31); + z[1].im = (int32_t)(mtmp[ 4] - ((int64_t)tab[2].re)*t[2].im + 0x40000000 >> 31); + z[2].im = (int32_t)(mtmp[ 5] - ((int64_t)tab[1].re)*t[4].im + 0x40000000 >> 31); + + t[0].re = (int32_t)(mtmp[ 6] - ((int64_t)tab[0].im)*t[3].im + 0x40000000 >> 31); + t[2].re = (int32_t)(mtmp[ 7] - ((int64_t)tab[1].im)*t[1].im + 0x40000000 >> 31); + t[4].re = (int32_t)(mtmp[ 8] + ((int64_t)tab[0].im)*t[1].im + 0x40000000 >> 31); + t[0].im = (int32_t)(mtmp[ 9] + ((int64_t)tab[2].im)*t[5].re + 0x40000000 >> 31); + t[2].im = (int32_t)(mtmp[10] - ((int64_t)tab[1].im)*t[1].re + 0x40000000 >> 31); + t[4].im = (int32_t)(mtmp[11] - ((int64_t)tab[0].im)*t[3].re + 0x40000000 >> 31); +#else + z[0].re = tab[0].re*t[0].re - tab[2].re*t[4].re - tab[1].re*t[2].re; + z[1].re = tab[0].re*t[4].re - tab[1].re*t[0].re - tab[2].re*t[2].re; + z[2].re = tab[0].re*t[2].re - tab[2].re*t[0].re - tab[1].re*t[4].re; + z[0].im = tab[0].re*t[0].im - tab[1].re*t[2].im - tab[2].re*t[4].im; + z[1].im = tab[0].re*t[4].im - tab[1].re*t[0].im - tab[2].re*t[2].im; + z[2].im = tab[0].re*t[2].im - tab[2].re*t[0].im - tab[1].re*t[4].im; + + /* It's possible to do t[4].re and t[0].im with 2 multiplies only by + * multiplying the sum of all with the average of the twiddles */ + + t[0].re = tab[2].im*t[1].im + tab[1].im*t[5].im - tab[0].im*t[3].im; + t[2].re = tab[0].im*t[5].im + tab[2].im*t[3].im - tab[1].im*t[1].im; + t[4].re = tab[2].im*t[5].im + tab[1].im*t[3].im + tab[0].im*t[1].im; + t[0].im = tab[0].im*t[1].re + tab[1].im*t[3].re + tab[2].im*t[5].re; + t[2].im = tab[2].im*t[3].re + tab[0].im*t[5].re - tab[1].im*t[1].re; + t[4].im = tab[2].im*t[1].re + tab[1].im*t[5].re - tab[0].im*t[3].re; +#endif + + BF(t[1].re, z[0].re, z[0].re, t[4].re); + BF(t[3].re, z[1].re, z[1].re, t[2].re); + BF(t[5].re, z[2].re, z[2].re, t[0].re); + BF(t[1].im, z[0].im, z[0].im, t[0].im); + BF(t[3].im, z[1].im, z[1].im, t[2].im); + BF(t[5].im, z[2].im, z[2].im, t[4].im); + + out[1*stride].re = dc.re + z[0].re; + out[1*stride].im = dc.im + t[1].im; + out[2*stride].re = dc.re + t[3].re; + out[2*stride].im = dc.im + z[1].im; + out[3*stride].re = dc.re + z[2].re; + out[3*stride].im = dc.im + t[5].im; + out[4*stride].re = dc.re + t[5].re; + out[4*stride].im = dc.im + z[2].im; + out[5*stride].re = dc.re + z[1].re; + out[5*stride].im = dc.im + t[3].im; + out[6*stride].re = dc.re + t[1].re; + out[6*stride].im = dc.im + z[0].im; +} + +static av_always_inline void fft9(TXComplex *out, TXComplex *in, + ptrdiff_t stride) +{ + const TXComplex *tab = (const TXComplex *)TX_TAB(ff_tx_tab_9); + TXComplex dc, t[16], w[4], x[5], y[5], z[2]; +#ifdef TX_INT32 + int64_t mtmp[12]; +#endif + + dc = in[0]; + BF(t[1].re, t[0].re, in[1].re, in[8].re); + BF(t[1].im, t[0].im, in[1].im, in[8].im); + BF(t[3].re, t[2].re, in[2].re, in[7].re); + BF(t[3].im, t[2].im, in[2].im, in[7].im); + BF(t[5].re, t[4].re, in[3].re, in[6].re); + BF(t[5].im, t[4].im, in[3].im, in[6].im); + BF(t[7].re, t[6].re, in[4].re, in[5].re); + BF(t[7].im, t[6].im, in[4].im, in[5].im); + + w[0].re = t[0].re - t[6].re; + w[0].im = t[0].im - t[6].im; + w[1].re = t[2].re - t[6].re; + w[1].im = t[2].im - t[6].im; + w[2].re = t[1].re - t[7].re; + w[2].im = t[1].im - t[7].im; + w[3].re = t[3].re + t[7].re; + w[3].im = t[3].im + t[7].im; + + z[0].re = dc.re + t[4].re; + z[0].im = dc.im + t[4].im; + + z[1].re = t[0].re + t[2].re + t[6].re; + z[1].im = t[0].im + t[2].im + t[6].im; + + out[0*stride].re = z[0].re + z[1].re; + out[0*stride].im = z[0].im + z[1].im; + +#ifdef TX_INT32 + mtmp[0] = t[1].re - t[3].re + t[7].re; + mtmp[1] = t[1].im - t[3].im + t[7].im; + + y[3].re = (int32_t)(((int64_t)tab[0].im)*mtmp[0] + 0x40000000 >> 31); + y[3].im = (int32_t)(((int64_t)tab[0].im)*mtmp[1] + 0x40000000 >> 31); + + mtmp[0] = (int32_t)(((int64_t)tab[0].re)*z[1].re + 0x40000000 >> 31); + mtmp[1] = (int32_t)(((int64_t)tab[0].re)*z[1].im + 0x40000000 >> 31); + mtmp[2] = (int32_t)(((int64_t)tab[0].re)*t[4].re + 0x40000000 >> 31); + mtmp[3] = (int32_t)(((int64_t)tab[0].re)*t[4].im + 0x40000000 >> 31); + + x[3].re = z[0].re + (int32_t)mtmp[0]; + x[3].im = z[0].im + (int32_t)mtmp[1]; + z[0].re = in[0].re + (int32_t)mtmp[2]; + z[0].im = in[0].im + (int32_t)mtmp[3]; + + mtmp[0] = ((int64_t)tab[1].re)*w[0].re; + mtmp[1] = ((int64_t)tab[1].re)*w[0].im; + mtmp[2] = ((int64_t)tab[2].im)*w[0].re; + mtmp[3] = ((int64_t)tab[2].im)*w[0].im; + mtmp[4] = ((int64_t)tab[1].im)*w[2].re; + mtmp[5] = ((int64_t)tab[1].im)*w[2].im; + mtmp[6] = ((int64_t)tab[2].re)*w[2].re; + mtmp[7] = ((int64_t)tab[2].re)*w[2].im; + + x[1].re = (int32_t)(mtmp[0] + ((int64_t)tab[2].im)*w[1].re + 0x40000000 >> 31); + x[1].im = (int32_t)(mtmp[1] + ((int64_t)tab[2].im)*w[1].im + 0x40000000 >> 31); + x[2].re = (int32_t)(mtmp[2] - ((int64_t)tab[3].re)*w[1].re + 0x40000000 >> 31); + x[2].im = (int32_t)(mtmp[3] - ((int64_t)tab[3].re)*w[1].im + 0x40000000 >> 31); + y[1].re = (int32_t)(mtmp[4] + ((int64_t)tab[2].re)*w[3].re + 0x40000000 >> 31); + y[1].im = (int32_t)(mtmp[5] + ((int64_t)tab[2].re)*w[3].im + 0x40000000 >> 31); + y[2].re = (int32_t)(mtmp[6] - ((int64_t)tab[3].im)*w[3].re + 0x40000000 >> 31); + y[2].im = (int32_t)(mtmp[7] - ((int64_t)tab[3].im)*w[3].im + 0x40000000 >> 31); + + y[0].re = (int32_t)(((int64_t)tab[0].im)*t[5].re + 0x40000000 >> 31); + y[0].im = (int32_t)(((int64_t)tab[0].im)*t[5].im + 0x40000000 >> 31); + +#else + y[3].re = tab[0].im*(t[1].re - t[3].re + t[7].re); + y[3].im = tab[0].im*(t[1].im - t[3].im + t[7].im); + + x[3].re = z[0].re + tab[0].re*z[1].re; + x[3].im = z[0].im + tab[0].re*z[1].im; + z[0].re = dc.re + tab[0].re*t[4].re; + z[0].im = dc.im + tab[0].re*t[4].im; + + x[1].re = tab[1].re*w[0].re + tab[2].im*w[1].re; + x[1].im = tab[1].re*w[0].im + tab[2].im*w[1].im; + x[2].re = tab[2].im*w[0].re - tab[3].re*w[1].re; + x[2].im = tab[2].im*w[0].im - tab[3].re*w[1].im; + y[1].re = tab[1].im*w[2].re + tab[2].re*w[3].re; + y[1].im = tab[1].im*w[2].im + tab[2].re*w[3].im; + y[2].re = tab[2].re*w[2].re - tab[3].im*w[3].re; + y[2].im = tab[2].re*w[2].im - tab[3].im*w[3].im; + + y[0].re = tab[0].im*t[5].re; + y[0].im = tab[0].im*t[5].im; +#endif + + x[4].re = x[1].re + x[2].re; + x[4].im = x[1].im + x[2].im; + + y[4].re = y[1].re - y[2].re; + y[4].im = y[1].im - y[2].im; + x[1].re = z[0].re + x[1].re; + x[1].im = z[0].im + x[1].im; + y[1].re = y[0].re + y[1].re; + y[1].im = y[0].im + y[1].im; + x[2].re = z[0].re + x[2].re; + x[2].im = z[0].im + x[2].im; + y[2].re = y[2].re - y[0].re; + y[2].im = y[2].im - y[0].im; + x[4].re = z[0].re - x[4].re; + x[4].im = z[0].im - x[4].im; + y[4].re = y[0].re - y[4].re; + y[4].im = y[0].im - y[4].im; + + out[1*stride] = (TXComplex){ x[1].re + y[1].im, x[1].im - y[1].re }; + out[2*stride] = (TXComplex){ x[2].re + y[2].im, x[2].im - y[2].re }; + out[3*stride] = (TXComplex){ x[3].re + y[3].im, x[3].im - y[3].re }; + out[4*stride] = (TXComplex){ x[4].re + y[4].im, x[4].im - y[4].re }; + out[5*stride] = (TXComplex){ x[4].re - y[4].im, x[4].im + y[4].re }; + out[6*stride] = (TXComplex){ x[3].re - y[3].im, x[3].im + y[3].re }; + out[7*stride] = (TXComplex){ x[2].re - y[2].im, x[2].im + y[2].re }; + out[8*stride] = (TXComplex){ x[1].re - y[1].im, x[1].im + y[1].re }; +} + +static av_always_inline void fft15(TXComplex *out, TXComplex *in, + ptrdiff_t stride) +{ + TXComplex tmp[15]; + + for (int i = 0; i < 5; i++) + fft3(tmp + i, in + i*3, 5); + + fft5_m1(out, tmp + 0, stride); + fft5_m2(out, tmp + 5, stride); + fft5_m3(out, tmp + 10, stride); +} + +static av_cold int TX_NAME(ff_tx_fft_factor_init)(AVTXContext *s, + const FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale) +{ + int ret = 0; + TX_TAB(ff_tx_init_tabs)(len); + + if (len == 15) + ret = ff_tx_gen_pfa_input_map(s, opts, 3, 5); + else if (flags & FF_TX_PRESHUFFLE) + ret = ff_tx_gen_default_map(s, opts); + + return ret; +} + +#define DECL_FACTOR_S(n) \ +static void TX_NAME(ff_tx_fft##n)(AVTXContext *s, void *dst, \ + void *src, ptrdiff_t stride) \ +{ \ + fft##n((TXComplex *)dst, (TXComplex *)src, stride / sizeof(TXComplex)); \ +} \ +static const FFTXCodelet TX_NAME(ff_tx_fft##n##_ns_def) = { \ + .name = TX_NAME_STR("fft" #n "_ns"), \ + .function = TX_NAME(ff_tx_fft##n), \ + .type = TX_TYPE(FFT), \ + .flags = AV_TX_INPLACE | FF_TX_OUT_OF_PLACE | \ + AV_TX_UNALIGNED | FF_TX_PRESHUFFLE, \ + .factors[0] = n, \ + .nb_factors = 1, \ + .min_len = n, \ + .max_len = n, \ + .init = TX_NAME(ff_tx_fft_factor_init), \ + .cpu_flags = FF_TX_CPU_FLAGS_ALL, \ + .prio = FF_TX_PRIO_BASE, \ +}; + +#define DECL_FACTOR_F(n) \ +DECL_FACTOR_S(n) \ +static const FFTXCodelet TX_NAME(ff_tx_fft##n##_fwd_def) = { \ + .name = TX_NAME_STR("fft" #n "_fwd"), \ + .function = TX_NAME(ff_tx_fft##n), \ + .type = TX_TYPE(FFT), \ + .flags = AV_TX_INPLACE | FF_TX_OUT_OF_PLACE | \ + AV_TX_UNALIGNED | FF_TX_FORWARD_ONLY, \ + .factors[0] = n, \ + .nb_factors = 1, \ + .min_len = n, \ + .max_len = n, \ + .init = TX_NAME(ff_tx_fft_factor_init), \ + .cpu_flags = FF_TX_CPU_FLAGS_ALL, \ + .prio = FF_TX_PRIO_BASE, \ +}; + +DECL_FACTOR_F(3) +DECL_FACTOR_F(5) +DECL_FACTOR_F(7) +DECL_FACTOR_F(9) +DECL_FACTOR_S(15) + +#define BUTTERFLIES(a0, a1, a2, a3) \ + do { \ + r0=a0.re; \ + i0=a0.im; \ + r1=a1.re; \ + i1=a1.im; \ + BF(t3, t5, t5, t1); \ + BF(a2.re, a0.re, r0, t5); \ + BF(a3.im, a1.im, i1, t3); \ + BF(t4, t6, t2, t6); \ + BF(a3.re, a1.re, r1, t4); \ + BF(a2.im, a0.im, i0, t6); \ + } while (0) + +#define TRANSFORM(a0, a1, a2, a3, wre, wim) \ + do { \ + CMUL(t1, t2, a2.re, a2.im, wre, -wim); \ + CMUL(t5, t6, a3.re, a3.im, wre, wim); \ + BUTTERFLIES(a0, a1, a2, a3); \ + } while (0) + +/* z[0...8n-1], w[1...2n-1] */ +static inline void TX_NAME(ff_tx_fft_sr_combine)(TXComplex *z, + const TXSample *cos, int len) +{ + int o1 = 2*len; + int o2 = 4*len; + int o3 = 6*len; + const TXSample *wim = cos + o1 - 7; + TXUSample t1, t2, t3, t4, t5, t6, r0, i0, r1, i1; + + for (int i = 0; i < len; i += 4) { + TRANSFORM(z[0], z[o1 + 0], z[o2 + 0], z[o3 + 0], cos[0], wim[7]); + TRANSFORM(z[2], z[o1 + 2], z[o2 + 2], z[o3 + 2], cos[2], wim[5]); + TRANSFORM(z[4], z[o1 + 4], z[o2 + 4], z[o3 + 4], cos[4], wim[3]); + TRANSFORM(z[6], z[o1 + 6], z[o2 + 6], z[o3 + 6], cos[6], wim[1]); + + TRANSFORM(z[1], z[o1 + 1], z[o2 + 1], z[o3 + 1], cos[1], wim[6]); + TRANSFORM(z[3], z[o1 + 3], z[o2 + 3], z[o3 + 3], cos[3], wim[4]); + TRANSFORM(z[5], z[o1 + 5], z[o2 + 5], z[o3 + 5], cos[5], wim[2]); + TRANSFORM(z[7], z[o1 + 7], z[o2 + 7], z[o3 + 7], cos[7], wim[0]); + + z += 2*4; + cos += 2*4; + wim -= 2*4; + } +} + +static av_cold int TX_NAME(ff_tx_fft_sr_codelet_init)(AVTXContext *s, + const FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale) +{ + TX_TAB(ff_tx_init_tabs)(len); + return ff_tx_gen_ptwo_revtab(s, opts); +} + +#define DECL_SR_CODELET_DEF(n) \ +static const FFTXCodelet TX_NAME(ff_tx_fft##n##_ns_def) = { \ + .name = TX_NAME_STR("fft" #n "_ns"), \ + .function = TX_NAME(ff_tx_fft##n##_ns), \ + .type = TX_TYPE(FFT), \ + .flags = FF_TX_OUT_OF_PLACE | AV_TX_INPLACE | \ + AV_TX_UNALIGNED | FF_TX_PRESHUFFLE, \ + .factors[0] = 2, \ + .nb_factors = 1, \ + .min_len = n, \ + .max_len = n, \ + .init = TX_NAME(ff_tx_fft_sr_codelet_init), \ + .cpu_flags = FF_TX_CPU_FLAGS_ALL, \ + .prio = FF_TX_PRIO_BASE, \ +}; + +#define DECL_SR_CODELET(n, n2, n4) \ +static void TX_NAME(ff_tx_fft##n##_ns)(AVTXContext *s, void *_dst, \ + void *_src, ptrdiff_t stride) \ +{ \ + TXComplex *src = _src; \ + TXComplex *dst = _dst; \ + const TXSample *cos = TX_TAB(ff_tx_tab_##n); \ + \ + TX_NAME(ff_tx_fft##n2##_ns)(s, dst, src, stride); \ + TX_NAME(ff_tx_fft##n4##_ns)(s, dst + n4*2, src + n4*2, stride); \ + TX_NAME(ff_tx_fft##n4##_ns)(s, dst + n4*3, src + n4*3, stride); \ + TX_NAME(ff_tx_fft_sr_combine)(dst, cos, n4 >> 1); \ +} \ + \ +DECL_SR_CODELET_DEF(n) + +static void TX_NAME(ff_tx_fft2_ns)(AVTXContext *s, void *_dst, + void *_src, ptrdiff_t stride) +{ + TXComplex *src = _src; + TXComplex *dst = _dst; + TXComplex tmp; + + BF(tmp.re, dst[0].re, src[0].re, src[1].re); + BF(tmp.im, dst[0].im, src[0].im, src[1].im); + dst[1] = tmp; +} + +static void TX_NAME(ff_tx_fft4_ns)(AVTXContext *s, void *_dst, + void *_src, ptrdiff_t stride) +{ + TXComplex *src = _src; + TXComplex *dst = _dst; + TXSample t1, t2, t3, t4, t5, t6, t7, t8; + + BF(t3, t1, src[0].re, src[1].re); + BF(t8, t6, src[3].re, src[2].re); + BF(dst[2].re, dst[0].re, t1, t6); + BF(t4, t2, src[0].im, src[1].im); + BF(t7, t5, src[2].im, src[3].im); + BF(dst[3].im, dst[1].im, t4, t8); + BF(dst[3].re, dst[1].re, t3, t7); + BF(dst[2].im, dst[0].im, t2, t5); +} + +static void TX_NAME(ff_tx_fft8_ns)(AVTXContext *s, void *_dst, + void *_src, ptrdiff_t stride) +{ + TXComplex *src = _src; + TXComplex *dst = _dst; + TXUSample t1, t2, t3, t4, t5, t6, r0, i0, r1, i1; + const TXSample cos = TX_TAB(ff_tx_tab_8)[1]; + + TX_NAME(ff_tx_fft4_ns)(s, dst, src, stride); + + BF(t1, dst[5].re, src[4].re, -src[5].re); + BF(t2, dst[5].im, src[4].im, -src[5].im); + BF(t5, dst[7].re, src[6].re, -src[7].re); + BF(t6, dst[7].im, src[6].im, -src[7].im); + + BUTTERFLIES(dst[0], dst[2], dst[4], dst[6]); + TRANSFORM(dst[1], dst[3], dst[5], dst[7], cos, cos); +} + +static void TX_NAME(ff_tx_fft16_ns)(AVTXContext *s, void *_dst, + void *_src, ptrdiff_t stride) +{ + TXComplex *src = _src; + TXComplex *dst = _dst; + const TXSample *cos = TX_TAB(ff_tx_tab_16); + + TXUSample t1, t2, t3, t4, t5, t6, r0, i0, r1, i1; + TXSample cos_16_1 = cos[1]; + TXSample cos_16_2 = cos[2]; + TXSample cos_16_3 = cos[3]; + + TX_NAME(ff_tx_fft8_ns)(s, dst + 0, src + 0, stride); + TX_NAME(ff_tx_fft4_ns)(s, dst + 8, src + 8, stride); + TX_NAME(ff_tx_fft4_ns)(s, dst + 12, src + 12, stride); + + t1 = dst[ 8].re; + t2 = dst[ 8].im; + t5 = dst[12].re; + t6 = dst[12].im; + BUTTERFLIES(dst[0], dst[4], dst[8], dst[12]); + + TRANSFORM(dst[ 2], dst[ 6], dst[10], dst[14], cos_16_2, cos_16_2); + TRANSFORM(dst[ 1], dst[ 5], dst[ 9], dst[13], cos_16_1, cos_16_3); + TRANSFORM(dst[ 3], dst[ 7], dst[11], dst[15], cos_16_3, cos_16_1); +} + +DECL_SR_CODELET_DEF(2) +DECL_SR_CODELET_DEF(4) +DECL_SR_CODELET_DEF(8) +DECL_SR_CODELET_DEF(16) +DECL_SR_CODELET(32,16,8) +DECL_SR_CODELET(64,32,16) +DECL_SR_CODELET(128,64,32) +DECL_SR_CODELET(256,128,64) +DECL_SR_CODELET(512,256,128) +DECL_SR_CODELET(1024,512,256) +DECL_SR_CODELET(2048,1024,512) +DECL_SR_CODELET(4096,2048,1024) +DECL_SR_CODELET(8192,4096,2048) +DECL_SR_CODELET(16384,8192,4096) +DECL_SR_CODELET(32768,16384,8192) +DECL_SR_CODELET(65536,32768,16384) +DECL_SR_CODELET(131072,65536,32768) + +static av_cold int TX_NAME(ff_tx_fft_init)(AVTXContext *s, + const FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale) +{ + int ret; + int is_inplace = !!(flags & AV_TX_INPLACE); + FFTXCodeletOptions sub_opts = { + .map_dir = is_inplace ? FF_TX_MAP_SCATTER : FF_TX_MAP_GATHER, + }; + + flags &= ~FF_TX_OUT_OF_PLACE; /* We want the subtransform to be */ + flags |= AV_TX_INPLACE; /* in-place */ + flags |= FF_TX_PRESHUFFLE; /* This function handles the permute step */ + + if ((ret = ff_tx_init_subtx(s, TX_TYPE(FFT), flags, &sub_opts, len, inv, scale))) + return ret; + + if (is_inplace && (ret = ff_tx_gen_inplace_map(s, len))) + return ret; + + return 0; +} + +static av_cold int TX_NAME(ff_tx_fft_inplace_small_init)(AVTXContext *s, + const FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale) +{ + if (!(s->tmp = av_malloc(len*sizeof(*s->tmp)))) + return AVERROR(ENOMEM); + flags &= ~AV_TX_INPLACE; + return TX_NAME(ff_tx_fft_init)(s, cd, flags, opts, len, inv, scale); +} + +static void TX_NAME(ff_tx_fft)(AVTXContext *s, void *_dst, + void *_src, ptrdiff_t stride) +{ + TXComplex *src = _src; + TXComplex *dst1 = s->flags & AV_TX_INPLACE ? s->tmp : _dst; + TXComplex *dst2 = _dst; + int *map = s->sub[0].map; + int len = s->len; + + /* Compilers can't vectorize this anyway without assuming AVX2, which they + * generally don't, at least without -march=native -mtune=native */ + for (int i = 0; i < len; i++) + dst1[i] = src[map[i]]; + + s->fn[0](&s->sub[0], dst2, dst1, stride); +} + +static void TX_NAME(ff_tx_fft_inplace)(AVTXContext *s, void *_dst, + void *_src, ptrdiff_t stride) +{ + TXComplex *src = _src; + TXComplex *dst = _dst; + TXComplex tmp; + const int *map = s->sub->map; + const int *inplace_idx = s->map; + int src_idx, dst_idx; + + src_idx = *inplace_idx++; + do { + tmp = src[src_idx]; + dst_idx = map[src_idx]; + do { + FFSWAP(TXComplex, tmp, src[dst_idx]); + dst_idx = map[dst_idx]; + } while (dst_idx != src_idx); /* Can be > as well, but was less predictable */ + src[dst_idx] = tmp; + } while ((src_idx = *inplace_idx++)); + + s->fn[0](&s->sub[0], dst, src, stride); +} + +static const FFTXCodelet TX_NAME(ff_tx_fft_def) = { + .name = TX_NAME_STR("fft"), + .function = TX_NAME(ff_tx_fft), + .type = TX_TYPE(FFT), + .flags = AV_TX_UNALIGNED | FF_TX_OUT_OF_PLACE, + .factors[0] = TX_FACTOR_ANY, + .nb_factors = 1, + .min_len = 2, + .max_len = TX_LEN_UNLIMITED, + .init = TX_NAME(ff_tx_fft_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_BASE, +}; + +static const FFTXCodelet TX_NAME(ff_tx_fft_inplace_small_def) = { + .name = TX_NAME_STR("fft_inplace_small"), + .function = TX_NAME(ff_tx_fft), + .type = TX_TYPE(FFT), + .flags = AV_TX_UNALIGNED | FF_TX_OUT_OF_PLACE | AV_TX_INPLACE, + .factors[0] = TX_FACTOR_ANY, + .nb_factors = 1, + .min_len = 2, + .max_len = 65536, + .init = TX_NAME(ff_tx_fft_inplace_small_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_BASE - 256, +}; + +static const FFTXCodelet TX_NAME(ff_tx_fft_inplace_def) = { + .name = TX_NAME_STR("fft_inplace"), + .function = TX_NAME(ff_tx_fft_inplace), + .type = TX_TYPE(FFT), + .flags = AV_TX_UNALIGNED | FF_TX_OUT_OF_PLACE | AV_TX_INPLACE, + .factors[0] = TX_FACTOR_ANY, + .nb_factors = 1, + .min_len = 2, + .max_len = TX_LEN_UNLIMITED, + .init = TX_NAME(ff_tx_fft_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_BASE - 512, +}; + +static av_cold int TX_NAME(ff_tx_fft_init_naive_small)(AVTXContext *s, + const FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale) +{ + const double phase = s->inv ? 2.0*M_PI/len : -2.0*M_PI/len; + + if (!(s->exp = av_malloc(len*len*sizeof(*s->exp)))) + return AVERROR(ENOMEM); + + for (int i = 0; i < len; i++) { + for (int j = 0; j < len; j++) { + const double factor = phase*i*j; + s->exp[i*j] = (TXComplex){ + RESCALE(cos(factor)), + RESCALE(sin(factor)), + }; + } + } + + return 0; +} + +static void TX_NAME(ff_tx_fft_naive)(AVTXContext *s, void *_dst, void *_src, + ptrdiff_t stride) +{ + TXComplex *src = _src; + TXComplex *dst = _dst; + const int n = s->len; + double phase = s->inv ? 2.0*M_PI/n : -2.0*M_PI/n; + + stride /= sizeof(*dst); + + for (int i = 0; i < n; i++) { + TXComplex tmp = { 0 }; + for (int j = 0; j < n; j++) { + const double factor = phase*i*j; + const TXComplex mult = { + RESCALE(cos(factor)), + RESCALE(sin(factor)), + }; + TXComplex res; + CMUL3(res, src[j], mult); + tmp.re += res.re; + tmp.im += res.im; + } + dst[i*stride] = tmp; + } +} + +static void TX_NAME(ff_tx_fft_naive_small)(AVTXContext *s, void *_dst, void *_src, + ptrdiff_t stride) +{ + TXComplex *src = _src; + TXComplex *dst = _dst; + const int n = s->len; + + stride /= sizeof(*dst); + + for (int i = 0; i < n; i++) { + TXComplex tmp = { 0 }; + for (int j = 0; j < n; j++) { + TXComplex res; + const TXComplex mult = s->exp[i*j]; + CMUL3(res, src[j], mult); + tmp.re += res.re; + tmp.im += res.im; + } + dst[i*stride] = tmp; + } +} + +static const FFTXCodelet TX_NAME(ff_tx_fft_naive_small_def) = { + .name = TX_NAME_STR("fft_naive_small"), + .function = TX_NAME(ff_tx_fft_naive_small), + .type = TX_TYPE(FFT), + .flags = AV_TX_UNALIGNED | FF_TX_OUT_OF_PLACE, + .factors[0] = TX_FACTOR_ANY, + .nb_factors = 1, + .min_len = 2, + .max_len = 1024, + .init = TX_NAME(ff_tx_fft_init_naive_small), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_MIN/2, +}; + +static const FFTXCodelet TX_NAME(ff_tx_fft_naive_def) = { + .name = TX_NAME_STR("fft_naive"), + .function = TX_NAME(ff_tx_fft_naive), + .type = TX_TYPE(FFT), + .flags = AV_TX_UNALIGNED | FF_TX_OUT_OF_PLACE, + .factors[0] = TX_FACTOR_ANY, + .nb_factors = 1, + .min_len = 2, + .max_len = TX_LEN_UNLIMITED, + .init = NULL, + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_MIN, +}; + +static av_cold int TX_NAME(ff_tx_fft_pfa_init)(AVTXContext *s, + const FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale) +{ + int ret, *tmp, ps = flags & FF_TX_PRESHUFFLE; + FFTXCodeletOptions sub_opts = { .map_dir = FF_TX_MAP_GATHER }; + size_t extra_tmp_len = 0; + int len_list[TX_MAX_DECOMPOSITIONS]; + + if ((ret = ff_tx_decompose_length(len_list, TX_TYPE(FFT), len, inv)) < 0) + return ret; + + /* Two iterations to test both orderings. */ + for (int i = 0; i < ret; i++) { + int len1 = len_list[i]; + int len2 = len / len1; + + /* Our ptwo transforms don't support striding the output. */ + if (len2 & (len2 - 1)) + FFSWAP(int, len1, len2); + + ff_tx_clear_ctx(s); + + /* First transform */ + sub_opts.map_dir = FF_TX_MAP_GATHER; + flags &= ~AV_TX_INPLACE; + flags |= FF_TX_OUT_OF_PLACE; + flags |= FF_TX_PRESHUFFLE; /* This function handles the permute step */ + ret = ff_tx_init_subtx(s, TX_TYPE(FFT), flags, &sub_opts, + len1, inv, scale); + + if (ret == AVERROR(ENOMEM)) { + return ret; + } else if (ret < 0) { /* Try again without a preshuffle flag */ + flags &= ~FF_TX_PRESHUFFLE; + ret = ff_tx_init_subtx(s, TX_TYPE(FFT), flags, &sub_opts, + len1, inv, scale); + if (ret == AVERROR(ENOMEM)) + return ret; + else if (ret < 0) + continue; + } + + /* Second transform. */ + sub_opts.map_dir = FF_TX_MAP_SCATTER; + flags |= FF_TX_PRESHUFFLE; +retry: + flags &= ~FF_TX_OUT_OF_PLACE; + flags |= AV_TX_INPLACE; + ret = ff_tx_init_subtx(s, TX_TYPE(FFT), flags, &sub_opts, + len2, inv, scale); + + if (ret == AVERROR(ENOMEM)) { + return ret; + } else if (ret < 0) { /* Try again with an out-of-place transform */ + flags |= FF_TX_OUT_OF_PLACE; + flags &= ~AV_TX_INPLACE; + ret = ff_tx_init_subtx(s, TX_TYPE(FFT), flags, &sub_opts, + len2, inv, scale); + if (ret == AVERROR(ENOMEM)) { + return ret; + } else if (ret < 0) { + if (flags & FF_TX_PRESHUFFLE) { /* Retry again without a preshuf flag */ + flags &= ~FF_TX_PRESHUFFLE; + goto retry; + } else { + continue; + } + } + } + + /* Success */ + break; + } + + /* If nothing was successful, error out */ + if (ret < 0) + return ret; + + /* Generate PFA map */ + if ((ret = ff_tx_gen_compound_mapping(s, opts, 0, + s->sub[0].len, s->sub[1].len))) + return ret; + + if (!(s->tmp = av_malloc(len*sizeof(*s->tmp)))) + return AVERROR(ENOMEM); + + /* Flatten input map */ + tmp = (int *)s->tmp; + for (int k = 0; k < len; k += s->sub[0].len) { + memcpy(tmp, &s->map[k], s->sub[0].len*sizeof(*tmp)); + for (int i = 0; i < s->sub[0].len; i++) + s->map[k + i] = tmp[s->sub[0].map[i]]; + } + + /* Only allocate extra temporary memory if we need it */ + if (!(s->sub[1].flags & AV_TX_INPLACE)) + extra_tmp_len = len; + else if (!ps) + extra_tmp_len = s->sub[0].len; + + if (extra_tmp_len && !(s->exp = av_malloc(extra_tmp_len*sizeof(*s->exp)))) + return AVERROR(ENOMEM); + + return 0; +} + +static void TX_NAME(ff_tx_fft_pfa)(AVTXContext *s, void *_out, + void *_in, ptrdiff_t stride) +{ + const int n = s->sub[0].len, m = s->sub[1].len, l = s->len; + const int *in_map = s->map, *out_map = in_map + l; + const int *sub_map = s->sub[1].map; + TXComplex *tmp1 = s->sub[1].flags & AV_TX_INPLACE ? s->tmp : s->exp; + TXComplex *in = _in, *out = _out; + + stride /= sizeof(*out); + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) + s->exp[j] = in[in_map[i*n + j]]; + s->fn[0](&s->sub[0], &s->tmp[sub_map[i]], s->exp, m*sizeof(TXComplex)); + } + + for (int i = 0; i < n; i++) + s->fn[1](&s->sub[1], &tmp1[m*i], &s->tmp[m*i], sizeof(TXComplex)); + + for (int i = 0; i < l; i++) + out[i*stride] = tmp1[out_map[i]]; +} + +static void TX_NAME(ff_tx_fft_pfa_ns)(AVTXContext *s, void *_out, + void *_in, ptrdiff_t stride) +{ + const int n = s->sub[0].len, m = s->sub[1].len, l = s->len; + const int *in_map = s->map, *out_map = in_map + l; + const int *sub_map = s->sub[1].map; + TXComplex *tmp1 = s->sub[1].flags & AV_TX_INPLACE ? s->tmp : s->exp; + TXComplex *in = _in, *out = _out; + + stride /= sizeof(*out); + + for (int i = 0; i < m; i++) + s->fn[0](&s->sub[0], &s->tmp[sub_map[i]], &in[i*n], m*sizeof(TXComplex)); + + for (int i = 0; i < n; i++) + s->fn[1](&s->sub[1], &tmp1[m*i], &s->tmp[m*i], sizeof(TXComplex)); + + for (int i = 0; i < l; i++) + out[i*stride] = tmp1[out_map[i]]; +} + +static const FFTXCodelet TX_NAME(ff_tx_fft_pfa_def) = { + .name = TX_NAME_STR("fft_pfa"), + .function = TX_NAME(ff_tx_fft_pfa), + .type = TX_TYPE(FFT), + .flags = AV_TX_UNALIGNED | AV_TX_INPLACE | FF_TX_OUT_OF_PLACE, + .factors = { 7, 5, 3, 2, TX_FACTOR_ANY }, + .nb_factors = 2, + .min_len = 2*3, + .max_len = TX_LEN_UNLIMITED, + .init = TX_NAME(ff_tx_fft_pfa_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_BASE, +}; + +static const FFTXCodelet TX_NAME(ff_tx_fft_pfa_ns_def) = { + .name = TX_NAME_STR("fft_pfa_ns"), + .function = TX_NAME(ff_tx_fft_pfa_ns), + .type = TX_TYPE(FFT), + .flags = AV_TX_UNALIGNED | AV_TX_INPLACE | FF_TX_OUT_OF_PLACE | + FF_TX_PRESHUFFLE, + .factors = { 7, 5, 3, 2, TX_FACTOR_ANY }, + .nb_factors = 2, + .min_len = 2*3, + .max_len = TX_LEN_UNLIMITED, + .init = TX_NAME(ff_tx_fft_pfa_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_BASE, +}; + +static av_cold int TX_NAME(ff_tx_mdct_naive_init)(AVTXContext *s, + const FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale) +{ + s->scale_d = *((SCALE_TYPE *)scale); + s->scale_f = s->scale_d; + return 0; +} + +static void TX_NAME(ff_tx_mdct_naive_fwd)(AVTXContext *s, void *_dst, + void *_src, ptrdiff_t stride) +{ + TXSample *src = _src; + TXSample *dst = _dst; + double scale = s->scale_d; + int len = s->len; + const double phase = M_PI/(4.0*len); + + stride /= sizeof(*dst); + + for (int i = 0; i < len; i++) { + double sum = 0.0; + for (int j = 0; j < len*2; j++) { + int a = (2*j + 1 + len) * (2*i + 1); + sum += UNSCALE(src[j]) * cos(a * phase); + } + dst[i*stride] = RESCALE(sum*scale); + } +} + +static void TX_NAME(ff_tx_mdct_naive_inv)(AVTXContext *s, void *_dst, + void *_src, ptrdiff_t stride) +{ + TXSample *src = _src; + TXSample *dst = _dst; + double scale = s->scale_d; + int len = s->len >> 1; + int len2 = len*2; + const double phase = M_PI/(4.0*len2); + + stride /= sizeof(*src); + + for (int i = 0; i < len; i++) { + double sum_d = 0.0; + double sum_u = 0.0; + double i_d = phase * (4*len - 2*i - 1); + double i_u = phase * (3*len2 + 2*i + 1); + for (int j = 0; j < len2; j++) { + double a = (2 * j + 1); + double a_d = cos(a * i_d); + double a_u = cos(a * i_u); + double val = UNSCALE(src[j*stride]); + sum_d += a_d * val; + sum_u += a_u * val; + } + dst[i + 0] = RESCALE( sum_d*scale); + dst[i + len] = RESCALE(-sum_u*scale); + } +} + +static const FFTXCodelet TX_NAME(ff_tx_mdct_naive_fwd_def) = { + .name = TX_NAME_STR("mdct_naive_fwd"), + .function = TX_NAME(ff_tx_mdct_naive_fwd), + .type = TX_TYPE(MDCT), + .flags = AV_TX_UNALIGNED | FF_TX_OUT_OF_PLACE | FF_TX_FORWARD_ONLY, + .factors = { 2, TX_FACTOR_ANY }, /* MDCTs need an even length */ + .nb_factors = 2, + .min_len = 2, + .max_len = TX_LEN_UNLIMITED, + .init = TX_NAME(ff_tx_mdct_naive_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_MIN, +}; + +static const FFTXCodelet TX_NAME(ff_tx_mdct_naive_inv_def) = { + .name = TX_NAME_STR("mdct_naive_inv"), + .function = TX_NAME(ff_tx_mdct_naive_inv), + .type = TX_TYPE(MDCT), + .flags = AV_TX_UNALIGNED | FF_TX_OUT_OF_PLACE | FF_TX_INVERSE_ONLY, + .factors = { 2, TX_FACTOR_ANY }, + .nb_factors = 2, + .min_len = 2, + .max_len = TX_LEN_UNLIMITED, + .init = TX_NAME(ff_tx_mdct_naive_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_MIN, +}; + +static av_cold int TX_NAME(ff_tx_mdct_init)(AVTXContext *s, + const FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale) +{ + int ret; + FFTXCodeletOptions sub_opts = { + .map_dir = !inv ? FF_TX_MAP_SCATTER : FF_TX_MAP_GATHER, + }; + + s->scale_d = *((SCALE_TYPE *)scale); + s->scale_f = s->scale_d; + + flags &= ~FF_TX_OUT_OF_PLACE; /* We want the subtransform to be */ + flags |= AV_TX_INPLACE; /* in-place */ + flags |= FF_TX_PRESHUFFLE; /* First try with an in-place transform */ + + if ((ret = ff_tx_init_subtx(s, TX_TYPE(FFT), flags, &sub_opts, len >> 1, + inv, scale))) { + flags &= ~FF_TX_PRESHUFFLE; /* Now try with a generic FFT */ + if ((ret = ff_tx_init_subtx(s, TX_TYPE(FFT), flags, &sub_opts, len >> 1, + inv, scale))) + return ret; + } + + s->map = av_malloc((len >> 1)*sizeof(*s->map)); + if (!s->map) + return AVERROR(ENOMEM); + + /* If we need to preshuffle copy the map from the subcontext */ + if (s->sub[0].flags & FF_TX_PRESHUFFLE) { + memcpy(s->map, s->sub->map, (len >> 1)*sizeof(*s->map)); + } else { + for (int i = 0; i < len >> 1; i++) + s->map[i] = i; + } + + if ((ret = TX_TAB(ff_tx_mdct_gen_exp)(s, inv ? s->map : NULL))) + return ret; + + /* Saves a multiply in a hot path. */ + if (inv) + for (int i = 0; i < (s->len >> 1); i++) + s->map[i] <<= 1; + + return 0; +} + +static void TX_NAME(ff_tx_mdct_fwd)(AVTXContext *s, void *_dst, void *_src, + ptrdiff_t stride) +{ + TXSample *src = _src, *dst = _dst; + TXComplex *exp = s->exp, tmp, *z = _dst; + const int len2 = s->len >> 1; + const int len4 = s->len >> 2; + const int len3 = len2 * 3; + const int *sub_map = s->map; + + stride /= sizeof(*dst); + + for (int i = 0; i < len2; i++) { /* Folding and pre-reindexing */ + const int k = 2*i; + const int idx = sub_map[i]; + if (k < len2) { + tmp.re = FOLD(-src[ len2 + k], src[1*len2 - 1 - k]); + tmp.im = FOLD(-src[ len3 + k], -src[1*len3 - 1 - k]); + } else { + tmp.re = FOLD(-src[ len2 + k], -src[5*len2 - 1 - k]); + tmp.im = FOLD( src[-len2 + k], -src[1*len3 - 1 - k]); + } + CMUL(z[idx].im, z[idx].re, tmp.re, tmp.im, exp[i].re, exp[i].im); + } + + s->fn[0](&s->sub[0], z, z, sizeof(TXComplex)); + + for (int i = 0; i < len4; i++) { + const int i0 = len4 + i, i1 = len4 - i - 1; + TXComplex src1 = { z[i1].re, z[i1].im }; + TXComplex src0 = { z[i0].re, z[i0].im }; + + CMUL(dst[2*i1*stride + stride], dst[2*i0*stride], src0.re, src0.im, + exp[i0].im, exp[i0].re); + CMUL(dst[2*i0*stride + stride], dst[2*i1*stride], src1.re, src1.im, + exp[i1].im, exp[i1].re); + } +} + +static void TX_NAME(ff_tx_mdct_inv)(AVTXContext *s, void *_dst, void *_src, + ptrdiff_t stride) +{ + TXComplex *z = _dst, *exp = s->exp; + const TXSample *src = _src, *in1, *in2; + const int len2 = s->len >> 1; + const int len4 = s->len >> 2; + const int *sub_map = s->map; + + stride /= sizeof(*src); + in1 = src; + in2 = src + ((len2*2) - 1) * stride; + + for (int i = 0; i < len2; i++) { + int k = sub_map[i]; + TXComplex tmp = { in2[-k*stride], in1[k*stride] }; + CMUL3(z[i], tmp, exp[i]); + } + + s->fn[0](&s->sub[0], z, z, sizeof(TXComplex)); + + exp += len2; + for (int i = 0; i < len4; i++) { + const int i0 = len4 + i, i1 = len4 - i - 1; + TXComplex src1 = { z[i1].im, z[i1].re }; + TXComplex src0 = { z[i0].im, z[i0].re }; + + CMUL(z[i1].re, z[i0].im, src1.re, src1.im, exp[i1].im, exp[i1].re); + CMUL(z[i0].re, z[i1].im, src0.re, src0.im, exp[i0].im, exp[i0].re); + } +} + +static const FFTXCodelet TX_NAME(ff_tx_mdct_fwd_def) = { + .name = TX_NAME_STR("mdct_fwd"), + .function = TX_NAME(ff_tx_mdct_fwd), + .type = TX_TYPE(MDCT), + .flags = AV_TX_UNALIGNED | FF_TX_OUT_OF_PLACE | FF_TX_FORWARD_ONLY, + .factors = { 2, TX_FACTOR_ANY }, + .nb_factors = 2, + .min_len = 2, + .max_len = TX_LEN_UNLIMITED, + .init = TX_NAME(ff_tx_mdct_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_BASE, +}; + +static const FFTXCodelet TX_NAME(ff_tx_mdct_inv_def) = { + .name = TX_NAME_STR("mdct_inv"), + .function = TX_NAME(ff_tx_mdct_inv), + .type = TX_TYPE(MDCT), + .flags = AV_TX_UNALIGNED | FF_TX_OUT_OF_PLACE | FF_TX_INVERSE_ONLY, + .factors = { 2, TX_FACTOR_ANY }, + .nb_factors = 2, + .min_len = 2, + .max_len = TX_LEN_UNLIMITED, + .init = TX_NAME(ff_tx_mdct_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_BASE, +}; + +static av_cold int TX_NAME(ff_tx_mdct_inv_full_init)(AVTXContext *s, + const FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale) +{ + int ret; + + s->scale_d = *((SCALE_TYPE *)scale); + s->scale_f = s->scale_d; + + flags &= ~AV_TX_FULL_IMDCT; + + if ((ret = ff_tx_init_subtx(s, TX_TYPE(MDCT), flags, NULL, len, 1, scale))) + return ret; + + return 0; +} + +static void TX_NAME(ff_tx_mdct_inv_full)(AVTXContext *s, void *_dst, + void *_src, ptrdiff_t stride) +{ + int len = s->len << 1; + int len2 = len >> 1; + int len4 = len >> 2; + TXSample *dst = _dst; + + s->fn[0](&s->sub[0], dst + len4, _src, stride); + + stride /= sizeof(*dst); + + for (int i = 0; i < len4; i++) { + dst[ i*stride] = -dst[(len2 - i - 1)*stride]; + dst[(len - i - 1)*stride] = dst[(len2 + i + 0)*stride]; + } +} + +static const FFTXCodelet TX_NAME(ff_tx_mdct_inv_full_def) = { + .name = TX_NAME_STR("mdct_inv_full"), + .function = TX_NAME(ff_tx_mdct_inv_full), + .type = TX_TYPE(MDCT), + .flags = AV_TX_UNALIGNED | AV_TX_INPLACE | + FF_TX_OUT_OF_PLACE | AV_TX_FULL_IMDCT, + .factors = { 2, TX_FACTOR_ANY }, + .nb_factors = 2, + .min_len = 2, + .max_len = TX_LEN_UNLIMITED, + .init = TX_NAME(ff_tx_mdct_inv_full_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_BASE, +}; + +static av_cold int TX_NAME(ff_tx_mdct_pfa_init)(AVTXContext *s, + const FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale) +{ + int ret, sub_len; + FFTXCodeletOptions sub_opts = { .map_dir = FF_TX_MAP_SCATTER }; + + len >>= 1; + sub_len = len / cd->factors[0]; + + s->scale_d = *((SCALE_TYPE *)scale); + s->scale_f = s->scale_d; + + flags &= ~FF_TX_OUT_OF_PLACE; /* We want the subtransform to be */ + flags |= AV_TX_INPLACE; /* in-place */ + flags |= FF_TX_PRESHUFFLE; /* This function handles the permute step */ + + if ((ret = ff_tx_init_subtx(s, TX_TYPE(FFT), flags, &sub_opts, + sub_len, inv, scale))) + return ret; + + if ((ret = ff_tx_gen_compound_mapping(s, opts, s->inv, cd->factors[0], sub_len))) + return ret; + + /* Our 15-point transform is also a compound one, so embed its input map */ + if (cd->factors[0] == 15) + TX_EMBED_INPUT_PFA_MAP(s->map, len, 3, 5); + + if ((ret = TX_TAB(ff_tx_mdct_gen_exp)(s, inv ? s->map : NULL))) + return ret; + + /* Saves multiplies in loops. */ + for (int i = 0; i < len; i++) + s->map[i] <<= 1; + + if (!(s->tmp = av_malloc(len*sizeof(*s->tmp)))) + return AVERROR(ENOMEM); + + TX_TAB(ff_tx_init_tabs)(len / sub_len); + + return 0; +} + +#define DECL_COMP_IMDCT(N) \ +static void TX_NAME(ff_tx_mdct_pfa_##N##xM_inv)(AVTXContext *s, void *_dst, \ + void *_src, ptrdiff_t stride) \ +{ \ + TXComplex fft##N##in[N]; \ + TXComplex *z = _dst, *exp = s->exp; \ + const TXSample *src = _src, *in1, *in2; \ + const int len4 = s->len >> 2; \ + const int len2 = s->len >> 1; \ + const int m = s->sub->len; \ + const int *in_map = s->map, *out_map = in_map + N*m; \ + const int *sub_map = s->sub->map; \ + \ + stride /= sizeof(*src); /* To convert it from bytes */ \ + in1 = src; \ + in2 = src + ((N*m*2) - 1) * stride; \ + \ + for (int i = 0; i < len2; i += N) { \ + for (int j = 0; j < N; j++) { \ + const int k = in_map[j]; \ + TXComplex tmp = { in2[-k*stride], in1[k*stride] }; \ + CMUL3(fft##N##in[j], tmp, exp[j]); \ + } \ + fft##N(s->tmp + *(sub_map++), fft##N##in, m); \ + exp += N; \ + in_map += N; \ + } \ + \ + for (int i = 0; i < N; i++) \ + s->fn[0](&s->sub[0], s->tmp + m*i, s->tmp + m*i, sizeof(TXComplex)); \ + \ + for (int i = 0; i < len4; i++) { \ + const int i0 = len4 + i, i1 = len4 - i - 1; \ + const int s0 = out_map[i0], s1 = out_map[i1]; \ + TXComplex src1 = { s->tmp[s1].im, s->tmp[s1].re }; \ + TXComplex src0 = { s->tmp[s0].im, s->tmp[s0].re }; \ + \ + CMUL(z[i1].re, z[i0].im, src1.re, src1.im, exp[i1].im, exp[i1].re); \ + CMUL(z[i0].re, z[i1].im, src0.re, src0.im, exp[i0].im, exp[i0].re); \ + } \ +} \ + \ +static const FFTXCodelet TX_NAME(ff_tx_mdct_pfa_##N##xM_inv_def) = { \ + .name = TX_NAME_STR("mdct_pfa_" #N "xM_inv"), \ + .function = TX_NAME(ff_tx_mdct_pfa_##N##xM_inv), \ + .type = TX_TYPE(MDCT), \ + .flags = AV_TX_UNALIGNED | FF_TX_OUT_OF_PLACE | FF_TX_INVERSE_ONLY, \ + .factors = { N, TX_FACTOR_ANY }, \ + .nb_factors = 2, \ + .min_len = N*2, \ + .max_len = TX_LEN_UNLIMITED, \ + .init = TX_NAME(ff_tx_mdct_pfa_init), \ + .cpu_flags = FF_TX_CPU_FLAGS_ALL, \ + .prio = FF_TX_PRIO_BASE, \ +}; + +DECL_COMP_IMDCT(3) +DECL_COMP_IMDCT(5) +DECL_COMP_IMDCT(7) +DECL_COMP_IMDCT(9) +DECL_COMP_IMDCT(15) + +#define DECL_COMP_MDCT(N) \ +static void TX_NAME(ff_tx_mdct_pfa_##N##xM_fwd)(AVTXContext *s, void *_dst, \ + void *_src, ptrdiff_t stride) \ +{ \ + TXComplex fft##N##in[N]; \ + TXSample *src = _src, *dst = _dst; \ + TXComplex *exp = s->exp, tmp; \ + const int m = s->sub->len; \ + const int len4 = N*m; \ + const int len3 = len4 * 3; \ + const int len8 = s->len >> 2; \ + const int *in_map = s->map, *out_map = in_map + N*m; \ + const int *sub_map = s->sub->map; \ + \ + stride /= sizeof(*dst); \ + \ + for (int i = 0; i < m; i++) { /* Folding and pre-reindexing */ \ + for (int j = 0; j < N; j++) { \ + const int k = in_map[i*N + j]; \ + if (k < len4) { \ + tmp.re = FOLD(-src[ len4 + k], src[1*len4 - 1 - k]); \ + tmp.im = FOLD(-src[ len3 + k], -src[1*len3 - 1 - k]); \ + } else { \ + tmp.re = FOLD(-src[ len4 + k], -src[5*len4 - 1 - k]); \ + tmp.im = FOLD( src[-len4 + k], -src[1*len3 - 1 - k]); \ + } \ + CMUL(fft##N##in[j].im, fft##N##in[j].re, tmp.re, tmp.im, \ + exp[k >> 1].re, exp[k >> 1].im); \ + } \ + fft##N(s->tmp + sub_map[i], fft##N##in, m); \ + } \ + \ + for (int i = 0; i < N; i++) \ + s->fn[0](&s->sub[0], s->tmp + m*i, s->tmp + m*i, sizeof(TXComplex)); \ + \ + for (int i = 0; i < len8; i++) { \ + const int i0 = len8 + i, i1 = len8 - i - 1; \ + const int s0 = out_map[i0], s1 = out_map[i1]; \ + TXComplex src1 = { s->tmp[s1].re, s->tmp[s1].im }; \ + TXComplex src0 = { s->tmp[s0].re, s->tmp[s0].im }; \ + \ + CMUL(dst[2*i1*stride + stride], dst[2*i0*stride], src0.re, src0.im, \ + exp[i0].im, exp[i0].re); \ + CMUL(dst[2*i0*stride + stride], dst[2*i1*stride], src1.re, src1.im, \ + exp[i1].im, exp[i1].re); \ + } \ +} \ + \ +static const FFTXCodelet TX_NAME(ff_tx_mdct_pfa_##N##xM_fwd_def) = { \ + .name = TX_NAME_STR("mdct_pfa_" #N "xM_fwd"), \ + .function = TX_NAME(ff_tx_mdct_pfa_##N##xM_fwd), \ + .type = TX_TYPE(MDCT), \ + .flags = AV_TX_UNALIGNED | FF_TX_OUT_OF_PLACE | FF_TX_FORWARD_ONLY, \ + .factors = { N, TX_FACTOR_ANY }, \ + .nb_factors = 2, \ + .min_len = N*2, \ + .max_len = TX_LEN_UNLIMITED, \ + .init = TX_NAME(ff_tx_mdct_pfa_init), \ + .cpu_flags = FF_TX_CPU_FLAGS_ALL, \ + .prio = FF_TX_PRIO_BASE, \ +}; + +DECL_COMP_MDCT(3) +DECL_COMP_MDCT(5) +DECL_COMP_MDCT(7) +DECL_COMP_MDCT(9) +DECL_COMP_MDCT(15) + +static av_cold int TX_NAME(ff_tx_rdft_init)(AVTXContext *s, + const FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale) +{ + int ret; + double f, m; + TXSample *tab; + uint64_t r2r = flags & AV_TX_REAL_TO_REAL; + int len4 = FFALIGN(len, 4) / 4; + + s->scale_d = *((SCALE_TYPE *)scale); + s->scale_f = s->scale_d; + + flags &= ~(AV_TX_REAL_TO_REAL | AV_TX_REAL_TO_IMAGINARY); + + if ((ret = ff_tx_init_subtx(s, TX_TYPE(FFT), flags, NULL, len >> 1, inv, scale))) + return ret; + + if (!(s->exp = av_mallocz((8 + 2*len4)*sizeof(*s->exp)))) + return AVERROR(ENOMEM); + + tab = (TXSample *)s->exp; + + f = 2*M_PI/len; + + m = (inv ? 2*s->scale_d : s->scale_d); + + *tab++ = RESCALE((inv ? 0.5 : 1.0) * m); + *tab++ = RESCALE(inv ? 0.5*m : 1.0*m); + *tab++ = RESCALE( m); + *tab++ = RESCALE(-m); + + *tab++ = RESCALE( (0.5 - 0.0) * m); + if (r2r) + *tab++ = 1 / s->scale_f; + else + *tab++ = RESCALE( (0.0 - 0.5) * m); + *tab++ = RESCALE( (0.5 - inv) * m); + *tab++ = RESCALE(-(0.5 - inv) * m); + + for (int i = 0; i < len4; i++) + *tab++ = RESCALE(cos(i*f)); + + tab = ((TXSample *)s->exp) + len4 + 8; + + for (int i = 0; i < len4; i++) + *tab++ = RESCALE(cos(((len - i*4)/4.0)*f)) * (inv ? 1 : -1); + + return 0; +} + +#define DECL_RDFT(n, inv) \ +static void TX_NAME(ff_tx_rdft_ ##n)(AVTXContext *s, void *_dst, \ + void *_src, ptrdiff_t stride) \ +{ \ + const int len2 = s->len >> 1; \ + const int len4 = s->len >> 2; \ + const TXSample *fact = (void *)s->exp; \ + const TXSample *tcos = fact + 8; \ + const TXSample *tsin = tcos + len4; \ + TXComplex *data = inv ? _src : _dst; \ + TXComplex t[3]; \ + \ + if (!inv) \ + s->fn[0](&s->sub[0], data, _src, sizeof(TXComplex)); \ + else \ + data[0].im = data[len2].re; \ + \ + /* The DC value's both components are real, but we need to change them \ + * into complex values. Also, the middle of the array is special-cased. \ + * These operations can be done before or after the loop. */ \ + t[0].re = data[0].re; \ + data[0].re = t[0].re + data[0].im; \ + data[0].im = t[0].re - data[0].im; \ + data[ 0].re = MULT(fact[0], data[ 0].re); \ + data[ 0].im = MULT(fact[1], data[ 0].im); \ + data[len4].re = MULT(fact[2], data[len4].re); \ + data[len4].im = MULT(fact[3], data[len4].im); \ + \ + for (int i = 1; i < len4; i++) { \ + /* Separate even and odd FFTs */ \ + t[0].re = MULT(fact[4], (data[i].re + data[len2 - i].re)); \ + t[0].im = MULT(fact[5], (data[i].im - data[len2 - i].im)); \ + t[1].re = MULT(fact[6], (data[i].im + data[len2 - i].im)); \ + t[1].im = MULT(fact[7], (data[i].re - data[len2 - i].re)); \ + \ + /* Apply twiddle factors to the odd FFT and add to the even FFT */ \ + CMUL(t[2].re, t[2].im, t[1].re, t[1].im, tcos[i], tsin[i]); \ + \ + data[ i].re = t[0].re + t[2].re; \ + data[ i].im = t[2].im - t[0].im; \ + data[len2 - i].re = t[0].re - t[2].re; \ + data[len2 - i].im = t[2].im + t[0].im; \ + } \ + \ + if (inv) { \ + s->fn[0](&s->sub[0], _dst, data, sizeof(TXComplex)); \ + } else { \ + /* Move [0].im to the last position, as convention requires */ \ + data[len2].re = data[0].im; \ + data[ 0].im = data[len2].im = 0; \ + } \ +} \ + \ +static const FFTXCodelet TX_NAME(ff_tx_rdft_ ##n## _def) = { \ + .name = TX_NAME_STR("rdft_" #n), \ + .function = TX_NAME(ff_tx_rdft_ ##n), \ + .type = TX_TYPE(RDFT), \ + .flags = AV_TX_UNALIGNED | AV_TX_INPLACE | FF_TX_OUT_OF_PLACE | \ + (inv ? FF_TX_INVERSE_ONLY : FF_TX_FORWARD_ONLY), \ + .factors = { 4, TX_FACTOR_ANY }, \ + .nb_factors = 2, \ + .min_len = 4, \ + .max_len = TX_LEN_UNLIMITED, \ + .init = TX_NAME(ff_tx_rdft_init), \ + .cpu_flags = FF_TX_CPU_FLAGS_ALL, \ + .prio = FF_TX_PRIO_BASE, \ +}; + +DECL_RDFT(r2c, 0) +DECL_RDFT(c2r, 1) + +#define DECL_RDFT_HALF(n, mode, mod2) \ +static void TX_NAME(ff_tx_rdft_ ##n)(AVTXContext *s, void *_dst, \ + void *_src, ptrdiff_t stride) \ +{ \ + const int len = s->len; \ + const int len2 = len >> 1; \ + const int len4 = len >> 2; \ + const int aligned_len4 = FFALIGN(len, 4)/4; \ + const TXSample *fact = (void *)s->exp; \ + const TXSample *tcos = fact + 8; \ + const TXSample *tsin = tcos + aligned_len4; \ + TXComplex *data = _dst; \ + TXSample *out = _dst; /* Half-complex is forward-only */ \ + TXSample tmp_dc; \ + av_unused TXSample tmp_mid; \ + TXSample tmp[4]; \ + TXComplex sf, sl; \ + \ + s->fn[0](&s->sub[0], _dst, _src, sizeof(TXComplex)); \ + \ + tmp_dc = data[0].re; \ + data[ 0].re = tmp_dc + data[0].im; \ + tmp_dc = tmp_dc - data[0].im; \ + \ + data[ 0].re = MULT(fact[0], data[ 0].re); \ + tmp_dc = MULT(fact[1], tmp_dc); \ + data[len4].re = MULT(fact[2], data[len4].re); \ + \ + if (!mod2) { \ + data[len4].im = MULT(fact[3], data[len4].im); \ + } else { \ + sf = data[len4]; \ + sl = data[len4 + 1]; \ + if (mode == AV_TX_REAL_TO_REAL) \ + tmp[0] = MULT(fact[4], (sf.re + sl.re)); \ + else \ + tmp[0] = MULT(fact[5], (sf.im - sl.im)); \ + tmp[1] = MULT(fact[6], (sf.im + sl.im)); \ + tmp[2] = MULT(fact[7], (sf.re - sl.re)); \ + \ + if (mode == AV_TX_REAL_TO_REAL) { \ + tmp[3] = tmp[1]*tcos[len4] - tmp[2]*tsin[len4]; \ + tmp_mid = (tmp[0] - tmp[3]); \ + } else { \ + tmp[3] = tmp[1]*tsin[len4] + tmp[2]*tcos[len4]; \ + tmp_mid = (tmp[0] + tmp[3]); \ + } \ + } \ + \ + /* NOTE: unrolling this breaks non-mod8 lengths */ \ + for (int i = 1; i <= len4; i++) { \ + TXSample tmp[4]; \ + TXComplex sf = data[i]; \ + TXComplex sl = data[len2 - i]; \ + \ + if (mode == AV_TX_REAL_TO_REAL) \ + tmp[0] = MULT(fact[4], (sf.re + sl.re)); \ + else \ + tmp[0] = MULT(fact[5], (sf.im - sl.im)); \ + \ + tmp[1] = MULT(fact[6], (sf.im + sl.im)); \ + tmp[2] = MULT(fact[7], (sf.re - sl.re)); \ + \ + if (mode == AV_TX_REAL_TO_REAL) { \ + tmp[3] = tmp[1]*tcos[i] - tmp[2]*tsin[i]; \ + out[i] = (tmp[0] + tmp[3]); \ + out[len - i] = (tmp[0] - tmp[3]); \ + } else { \ + tmp[3] = tmp[1]*tsin[i] + tmp[2]*tcos[i]; \ + out[i - 1] = (tmp[3] - tmp[0]); \ + out[len - i - 1] = (tmp[0] + tmp[3]); \ + } \ + } \ + \ + for (int i = 1; i < (len4 + (mode == AV_TX_REAL_TO_IMAGINARY)); i++) \ + out[len2 - i] = out[len - i]; \ + \ + if (mode == AV_TX_REAL_TO_REAL) { \ + out[len2] = tmp_dc; \ + if (mod2) \ + out[len4 + 1] = tmp_mid * fact[5]; \ + } else if (mod2) { \ + out[len4] = tmp_mid; \ + } \ +} \ + \ +static const FFTXCodelet TX_NAME(ff_tx_rdft_ ##n## _def) = { \ + .name = TX_NAME_STR("rdft_" #n), \ + .function = TX_NAME(ff_tx_rdft_ ##n), \ + .type = TX_TYPE(RDFT), \ + .flags = AV_TX_UNALIGNED | AV_TX_INPLACE | mode | \ + FF_TX_OUT_OF_PLACE | FF_TX_FORWARD_ONLY, \ + .factors = { 2 + 2*(!mod2), TX_FACTOR_ANY }, \ + .nb_factors = 2, \ + .min_len = 2 + 2*(!mod2), \ + .max_len = TX_LEN_UNLIMITED, \ + .init = TX_NAME(ff_tx_rdft_init), \ + .cpu_flags = FF_TX_CPU_FLAGS_ALL, \ + .prio = FF_TX_PRIO_BASE, \ +}; + +DECL_RDFT_HALF(r2r, AV_TX_REAL_TO_REAL, 0) +DECL_RDFT_HALF(r2r_mod2, AV_TX_REAL_TO_REAL, 1) +DECL_RDFT_HALF(r2i, AV_TX_REAL_TO_IMAGINARY, 0) +DECL_RDFT_HALF(r2i_mod2, AV_TX_REAL_TO_IMAGINARY, 1) + +static av_cold int TX_NAME(ff_tx_dct_init)(AVTXContext *s, + const FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale) +{ + int ret; + double freq; + TXSample *tab; + SCALE_TYPE rsc = *((SCALE_TYPE *)scale); + + if (inv) { + len *= 2; + s->len *= 2; + rsc *= 0.5; + } + + if ((ret = ff_tx_init_subtx(s, TX_TYPE(RDFT), flags, NULL, len, inv, &rsc))) + return ret; + + s->exp = av_malloc((len/2)*3*sizeof(TXSample)); + if (!s->exp) + return AVERROR(ENOMEM); + + tab = (TXSample *)s->exp; + + freq = M_PI/(len*2); + + for (int i = 0; i < len; i++) + tab[i] = RESCALE(cos(i*freq)*(!inv + 1)); + + if (inv) { + for (int i = 0; i < len/2; i++) + tab[len + i] = RESCALE(0.5 / sin((2*i + 1)*freq)); + } else { + for (int i = 0; i < len/2; i++) + tab[len + i] = RESCALE(cos((len - 2*i - 1)*freq)); + } + + return 0; +} + +static void TX_NAME(ff_tx_dctII)(AVTXContext *s, void *_dst, + void *_src, ptrdiff_t stride) +{ + TXSample *dst = _dst; + TXSample *src = _src; + const int len = s->len; + const int len2 = len >> 1; + const TXSample *exp = (void *)s->exp; + TXSample next; +#ifdef TX_INT32 + int64_t tmp1, tmp2; +#else + TXSample tmp1, tmp2; +#endif + + for (int i = 0; i < len2; i++) { + TXSample in1 = src[i]; + TXSample in2 = src[len - i - 1]; + TXSample s = exp[len + i]; + +#ifdef TX_INT32 + tmp1 = in1 + in2; + tmp2 = in1 - in2; + + tmp1 >>= 1; + tmp2 *= s; + + tmp2 = (tmp2 + 0x40000000) >> 31; +#else + tmp1 = (in1 + in2)*0.5; + tmp2 = (in1 - in2)*s; +#endif + + src[i] = tmp1 + tmp2; + src[len - i - 1] = tmp1 - tmp2; + } + + s->fn[0](&s->sub[0], dst, src, sizeof(TXComplex)); + + next = dst[len]; + + for (int i = len - 2; i > 0; i -= 2) { + TXSample tmp; + + CMUL(tmp, dst[i], exp[len - i], exp[i], dst[i + 0], dst[i + 1]); + + dst[i + 1] = next; + + next += tmp; + } + +#ifdef TX_INT32 + tmp1 = ((int64_t)exp[0]) * ((int64_t)dst[0]); + dst[0] = (tmp1 + 0x40000000) >> 31; +#else + dst[0] = exp[0] * dst[0]; +#endif + dst[1] = next; +} + +static void TX_NAME(ff_tx_dctIII)(AVTXContext *s, void *_dst, + void *_src, ptrdiff_t stride) +{ + TXSample *dst = _dst; + TXSample *src = _src; + const int len = s->len; + const int len2 = len >> 1; + const TXSample *exp = (void *)s->exp; +#ifdef TX_INT32 + int64_t tmp1, tmp2 = src[len - 1]; + tmp2 = (2*tmp2 + 0x40000000) >> 31; +#else + TXSample tmp1, tmp2 = 2*src[len - 1]; +#endif + + src[len] = tmp2; + + for (int i = len - 2; i >= 2; i -= 2) { + TXSample val1 = src[i - 0]; + TXSample val2 = src[i - 1] - src[i + 1]; + + CMUL(src[i + 1], src[i], exp[len - i], exp[i], val1, val2); + } + + s->fn[0](&s->sub[0], dst, src, sizeof(float)); + + for (int i = 0; i < len2; i++) { + TXSample in1 = dst[i]; + TXSample in2 = dst[len - i - 1]; + TXSample c = exp[len + i]; + + tmp1 = in1 + in2; + tmp2 = in1 - in2; + tmp2 *= c; +#ifdef TX_INT32 + tmp2 = (tmp2 + 0x40000000) >> 31; +#endif + + dst[i] = tmp1 + tmp2; + dst[len - i - 1] = tmp1 - tmp2; + } +} + +static const FFTXCodelet TX_NAME(ff_tx_dctII_def) = { + .name = TX_NAME_STR("dctII"), + .function = TX_NAME(ff_tx_dctII), + .type = TX_TYPE(DCT), + .flags = AV_TX_UNALIGNED | AV_TX_INPLACE | + FF_TX_OUT_OF_PLACE | FF_TX_FORWARD_ONLY, + .factors = { 2, TX_FACTOR_ANY }, + .min_len = 2, + .max_len = TX_LEN_UNLIMITED, + .init = TX_NAME(ff_tx_dct_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_BASE, +}; + +static const FFTXCodelet TX_NAME(ff_tx_dctIII_def) = { + .name = TX_NAME_STR("dctIII"), + .function = TX_NAME(ff_tx_dctIII), + .type = TX_TYPE(DCT), + .flags = AV_TX_UNALIGNED | AV_TX_INPLACE | + FF_TX_OUT_OF_PLACE | FF_TX_INVERSE_ONLY, + .factors = { 2, TX_FACTOR_ANY }, + .min_len = 2, + .max_len = TX_LEN_UNLIMITED, + .init = TX_NAME(ff_tx_dct_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_BASE, +}; + +static av_cold int TX_NAME(ff_tx_dcstI_init)(AVTXContext *s, + const FFTXCodelet *cd, + uint64_t flags, + FFTXCodeletOptions *opts, + int len, int inv, + const void *scale) +{ + int ret; + SCALE_TYPE rsc = *((SCALE_TYPE *)scale); + + if (inv) { + len *= 2; + s->len *= 2; + rsc *= 0.5; + } + + /* We want a half-complex RDFT */ + flags |= cd->type == TX_TYPE(DCT_I) ? AV_TX_REAL_TO_REAL : + AV_TX_REAL_TO_IMAGINARY; + + if ((ret = ff_tx_init_subtx(s, TX_TYPE(RDFT), flags, NULL, + (len - 1 + 2*(cd->type == TX_TYPE(DST_I)))*2, + 0, &rsc))) + return ret; + + s->tmp = av_mallocz((len + 1)*2*sizeof(TXSample)); + if (!s->tmp) + return AVERROR(ENOMEM); + + return 0; +} + +static void TX_NAME(ff_tx_dctI)(AVTXContext *s, void *_dst, + void *_src, ptrdiff_t stride) +{ + TXSample *dst = _dst; + TXSample *src = _src; + const int len = s->len - 1; + TXSample *tmp = (TXSample *)s->tmp; + + stride /= sizeof(TXSample); + + for (int i = 0; i < len; i++) + tmp[i] = tmp[2*len - i] = src[i * stride]; + + tmp[len] = src[len * stride]; /* Middle */ + + s->fn[0](&s->sub[0], dst, tmp, sizeof(TXSample)); +} + +static void TX_NAME(ff_tx_dstI)(AVTXContext *s, void *_dst, + void *_src, ptrdiff_t stride) +{ + TXSample *dst = _dst; + TXSample *src = _src; + const int len = s->len + 1; + TXSample *tmp = (void *)s->tmp; + + stride /= sizeof(TXSample); + + tmp[0] = 0; + + for (int i = 1; i < len; i++) { + TXSample a = src[(i - 1) * stride]; + tmp[i] = -a; + tmp[2*len - i] = a; + } + + tmp[len] = 0; /* i == n, Nyquist */ + + s->fn[0](&s->sub[0], dst, tmp, sizeof(float)); +} + +static const FFTXCodelet TX_NAME(ff_tx_dctI_def) = { + .name = TX_NAME_STR("dctI"), + .function = TX_NAME(ff_tx_dctI), + .type = TX_TYPE(DCT_I), + .flags = AV_TX_UNALIGNED | AV_TX_INPLACE | FF_TX_OUT_OF_PLACE, + .factors = { 2, TX_FACTOR_ANY }, + .nb_factors = 2, + .min_len = 2, + .max_len = TX_LEN_UNLIMITED, + .init = TX_NAME(ff_tx_dcstI_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_BASE, +}; + +static const FFTXCodelet TX_NAME(ff_tx_dstI_def) = { + .name = TX_NAME_STR("dstI"), + .function = TX_NAME(ff_tx_dstI), + .type = TX_TYPE(DST_I), + .flags = AV_TX_UNALIGNED | AV_TX_INPLACE | FF_TX_OUT_OF_PLACE, + .factors = { 2, TX_FACTOR_ANY }, + .nb_factors = 2, + .min_len = 2, + .max_len = TX_LEN_UNLIMITED, + .init = TX_NAME(ff_tx_dcstI_init), + .cpu_flags = FF_TX_CPU_FLAGS_ALL, + .prio = FF_TX_PRIO_BASE, +}; + +int TX_TAB(ff_tx_mdct_gen_exp)(AVTXContext *s, int *pre_tab) +{ + int off = 0; + int len4 = s->len >> 1; + double scale = s->scale_d; + const double theta = (scale < 0 ? len4 : 0) + 1.0/8.0; + size_t alloc = pre_tab ? 2*len4 : len4; + + if (!(s->exp = av_malloc_array(alloc, sizeof(*s->exp)))) + return AVERROR(ENOMEM); + + scale = sqrt(fabs(scale)); + + if (pre_tab) + off = len4; + + for (int i = 0; i < len4; i++) { + const double alpha = M_PI_2 * (i + theta) / len4; + s->exp[off + i] = (TXComplex){ RESCALE(cos(alpha) * scale), + RESCALE(sin(alpha) * scale) }; + } + + if (pre_tab) + for (int i = 0; i < len4; i++) + s->exp[i] = s->exp[len4 + pre_tab[i]]; + + return 0; +} + +const FFTXCodelet * const TX_NAME(ff_tx_codelet_list)[] = { + /* Split-Radix codelets */ + &TX_NAME(ff_tx_fft2_ns_def), + &TX_NAME(ff_tx_fft4_ns_def), + &TX_NAME(ff_tx_fft8_ns_def), + &TX_NAME(ff_tx_fft16_ns_def), + &TX_NAME(ff_tx_fft32_ns_def), + &TX_NAME(ff_tx_fft64_ns_def), + &TX_NAME(ff_tx_fft128_ns_def), + &TX_NAME(ff_tx_fft256_ns_def), + &TX_NAME(ff_tx_fft512_ns_def), + &TX_NAME(ff_tx_fft1024_ns_def), + &TX_NAME(ff_tx_fft2048_ns_def), + &TX_NAME(ff_tx_fft4096_ns_def), + &TX_NAME(ff_tx_fft8192_ns_def), + &TX_NAME(ff_tx_fft16384_ns_def), + &TX_NAME(ff_tx_fft32768_ns_def), + &TX_NAME(ff_tx_fft65536_ns_def), + &TX_NAME(ff_tx_fft131072_ns_def), + + /* Prime factor codelets */ + &TX_NAME(ff_tx_fft3_ns_def), + &TX_NAME(ff_tx_fft5_ns_def), + &TX_NAME(ff_tx_fft7_ns_def), + &TX_NAME(ff_tx_fft9_ns_def), + &TX_NAME(ff_tx_fft15_ns_def), + + /* We get these for free */ + &TX_NAME(ff_tx_fft3_fwd_def), + &TX_NAME(ff_tx_fft5_fwd_def), + &TX_NAME(ff_tx_fft7_fwd_def), + &TX_NAME(ff_tx_fft9_fwd_def), + + /* Standalone transforms */ + &TX_NAME(ff_tx_fft_def), + &TX_NAME(ff_tx_fft_inplace_def), + &TX_NAME(ff_tx_fft_inplace_small_def), + &TX_NAME(ff_tx_fft_pfa_def), + &TX_NAME(ff_tx_fft_pfa_ns_def), + &TX_NAME(ff_tx_fft_naive_def), + &TX_NAME(ff_tx_fft_naive_small_def), + &TX_NAME(ff_tx_mdct_fwd_def), + &TX_NAME(ff_tx_mdct_inv_def), + &TX_NAME(ff_tx_mdct_pfa_3xM_fwd_def), + &TX_NAME(ff_tx_mdct_pfa_5xM_fwd_def), + &TX_NAME(ff_tx_mdct_pfa_7xM_fwd_def), + &TX_NAME(ff_tx_mdct_pfa_9xM_fwd_def), + &TX_NAME(ff_tx_mdct_pfa_15xM_fwd_def), + &TX_NAME(ff_tx_mdct_pfa_3xM_inv_def), + &TX_NAME(ff_tx_mdct_pfa_5xM_inv_def), + &TX_NAME(ff_tx_mdct_pfa_7xM_inv_def), + &TX_NAME(ff_tx_mdct_pfa_9xM_inv_def), + &TX_NAME(ff_tx_mdct_pfa_15xM_inv_def), + &TX_NAME(ff_tx_mdct_naive_fwd_def), + &TX_NAME(ff_tx_mdct_naive_inv_def), + &TX_NAME(ff_tx_mdct_inv_full_def), + &TX_NAME(ff_tx_rdft_r2c_def), + &TX_NAME(ff_tx_rdft_r2r_def), + &TX_NAME(ff_tx_rdft_r2r_mod2_def), + &TX_NAME(ff_tx_rdft_r2i_def), + &TX_NAME(ff_tx_rdft_r2i_mod2_def), + &TX_NAME(ff_tx_rdft_c2r_def), + &TX_NAME(ff_tx_dctII_def), + &TX_NAME(ff_tx_dctIII_def), + &TX_NAME(ff_tx_dctI_def), + &TX_NAME(ff_tx_dstI_def), + + NULL, +}; diff --git a/libs/ffmpeg/libavutil/utils.c b/libs/ffmpeg/libavutil/utils.c new file mode 100644 index 00000000000..fc431fdd60c --- /dev/null +++ b/libs/ffmpeg/libavutil/utils.c @@ -0,0 +1,115 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "avutil.h" +#include "avassert.h" + +/** + * @file + * various utility functions + */ + +const char *av_get_media_type_string(enum AVMediaType media_type) +{ + switch (media_type) { + case AVMEDIA_TYPE_VIDEO: return "video"; + case AVMEDIA_TYPE_AUDIO: return "audio"; + case AVMEDIA_TYPE_DATA: return "data"; + case AVMEDIA_TYPE_SUBTITLE: return "subtitle"; + case AVMEDIA_TYPE_ATTACHMENT: return "attachment"; + default: return NULL; + } +} + +char av_get_picture_type_char(enum AVPictureType pict_type) +{ + switch (pict_type) { + case AV_PICTURE_TYPE_I: return 'I'; + case AV_PICTURE_TYPE_P: return 'P'; + case AV_PICTURE_TYPE_B: return 'B'; + case AV_PICTURE_TYPE_S: return 'S'; + case AV_PICTURE_TYPE_SI: return 'i'; + case AV_PICTURE_TYPE_SP: return 'p'; + case AV_PICTURE_TYPE_BI: return 'b'; + default: return '?'; + } +} + +#if FF_API_OPT_INT_LIST +unsigned av_int_list_length_for_size(unsigned elsize, + const void *list, uint64_t term) +{ + unsigned i; + + if (!list) + return 0; +#define LIST_LENGTH(type) \ + { type t = term, *l = (type *)list; for (i = 0; l[i] != t; i++); } + switch (elsize) { + case 1: LIST_LENGTH(uint8_t); break; + case 2: LIST_LENGTH(uint16_t); break; + case 4: LIST_LENGTH(uint32_t); break; + case 8: LIST_LENGTH(uint64_t); break; + default: av_assert0(!"valid element size"); + } + return i; +} +#endif + +char *av_fourcc_make_string(char *buf, uint32_t fourcc) +{ + int i; + char *orig_buf = buf; + size_t buf_size = AV_FOURCC_MAX_STRING_SIZE; + + for (i = 0; i < 4; i++) { + const int c = fourcc & 0xff; + const int print_chr = (c >= '0' && c <= '9') || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c && strchr(". -_", c)); + const int len = snprintf(buf, buf_size, print_chr ? "%c" : "[%d]", c); + if (len < 0) + break; + buf += len; + buf_size = buf_size > len ? buf_size - len : 0; + fourcc >>= 8; + } + + return orig_buf; +} + +AVRational av_get_time_base_q(void) +{ + return (AVRational){1, AV_TIME_BASE}; +} +#if FF_API_ASSERT_FPU +void av_assert0_fpu(void) { +#if HAVE_MMX_INLINE + uint16_t state[14]; + __asm__ volatile ( + "fstenv %0 \n\t" + : "+m" (state) + : + : "memory" + ); + av_assert0((state[4] & 3) == 3); +#endif +} +#endif diff --git a/libs/ffmpeg/libavutil/uuid.c b/libs/ffmpeg/libavutil/uuid.c new file mode 100644 index 00000000000..3f5075c0660 --- /dev/null +++ b/libs/ffmpeg/libavutil/uuid.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2022 Pierre-Anthony Lemieux <pal@palemieux.com> + * Zane van Iperen <zane@zanevaniperen.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Copyright (C) 1996, 1997 Theodore Ts'o. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +/** + * @file + * UUID parsing and serialization utilities. + * The library treat the UUID as an opaque sequence of 16 unsigned bytes, + * i.e. ignoring the internal layout of the UUID, which depends on the type + * of the UUID. + * + * @author Pierre-Anthony Lemieux <pal@palemieux.com> + * @author Zane van Iperen <zane@zanevaniperen.com> + */ + +#include "attributes_internal.h" +#include "uuid.h" +#include "error.h" +#include "avstring.h" + +int av_uuid_parse(const char *in, AVUUID uu) +{ + if (strlen(in) != 36) + return AVERROR(EINVAL); + + return av_uuid_parse_range(in, in + 36, uu); +} + +static int xdigit_to_int(char c) +{ + c = av_tolower(c); + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + if (c >= '0' && c <= '9') + return c - '0'; + + return -1; +} + +int av_uuid_parse_range(const char *in_start, const char *in_end, AVUUID uu) +{ + int i; + const char *cp; + + if ((in_end - in_start) != 36) + return AVERROR(EINVAL); + + for (i = 0, cp = in_start; i < 16; i++) { + int hi; + int lo; + + if (i == 4 || i == 6 || i == 8 || i == 10) + cp++; + + hi = xdigit_to_int(*cp++); + lo = xdigit_to_int(*cp++); + + if (hi == -1 || lo == -1) + return AVERROR(EINVAL); + + uu[i] = (hi << 4) + lo; + } + + return 0; +} + +static attribute_nonstring const char hexdigits_lower[16] = "0123456789abcdef"; + +void av_uuid_unparse(const AVUUID uuid, char *out) +{ + char *p = out; + + for (int i = 0; i < 16; i++) { + uint8_t tmp; + + if (i == 4 || i == 6 || i == 8 || i == 10) + *p++ = '-'; + + tmp = uuid[i]; + *p++ = hexdigits_lower[tmp >> 4]; + *p++ = hexdigits_lower[tmp & 15]; + } + + *p = '\0'; +} + +int av_uuid_urn_parse(const char *in, AVUUID uu) +{ + if (av_stristr(in, "urn:uuid:") != in) + return AVERROR(EINVAL); + + return av_uuid_parse(in + 9, uu); +} diff --git a/libs/ffmpeg/libavutil/uuid.h b/libs/ffmpeg/libavutil/uuid.h new file mode 100644 index 00000000000..748b7ed3c94 --- /dev/null +++ b/libs/ffmpeg/libavutil/uuid.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2022 Pierre-Anthony Lemieux <pal@palemieux.com> + * Zane van Iperen <zane@zanevaniperen.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * UUID parsing and serialization utilities. + * The library treats the UUID as an opaque sequence of 16 unsigned bytes, + * i.e. ignoring the internal layout of the UUID, which depends on the type + * of the UUID. + * + * @author Pierre-Anthony Lemieux <pal@palemieux.com> + * @author Zane van Iperen <zane@zanevaniperen.com> + */ + +#ifndef AVUTIL_UUID_H +#define AVUTIL_UUID_H + +#include <stdint.h> +#include <string.h> + +#define AV_PRI_UUID \ + "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-" \ + "%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" + +#define AV_PRI_URN_UUID \ + "urn:uuid:%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-" \ + "%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" + +/* AV_UUID_ARG() is used together with AV_PRI_UUID() or AV_PRI_URN_UUID + * to print UUIDs, e.g. + * av_log(NULL, AV_LOG_DEBUG, "UUID: " AV_PRI_UUID, AV_UUID_ARG(uuid)); + */ +#define AV_UUID_ARG(x) \ + (x)[ 0], (x)[ 1], (x)[ 2], (x)[ 3], \ + (x)[ 4], (x)[ 5], (x)[ 6], (x)[ 7], \ + (x)[ 8], (x)[ 9], (x)[10], (x)[11], \ + (x)[12], (x)[13], (x)[14], (x)[15] + +#define AV_UUID_LEN 16 + +/* Binary representation of a UUID */ +typedef uint8_t AVUUID[AV_UUID_LEN]; + +/** + * Parses a string representation of a UUID formatted according to IETF RFC 4122 + * into an AVUUID. The parsing is case-insensitive. The string must be 37 + * characters long, including the terminating NUL character. + * + * Example string representation: "2fceebd0-7017-433d-bafb-d073a7116696" + * + * @param[in] in String representation of a UUID, + * e.g. 2fceebd0-7017-433d-bafb-d073a7116696 + * @param[out] uu AVUUID + * @return A non-zero value in case of an error. + */ +int av_uuid_parse(const char *in, AVUUID uu); + +/** + * Parses a URN representation of a UUID, as specified at IETF RFC 4122, + * into an AVUUID. The parsing is case-insensitive. The string must be 46 + * characters long, including the terminating NUL character. + * + * Example string representation: "urn:uuid:2fceebd0-7017-433d-bafb-d073a7116696" + * + * @param[in] in URN UUID + * @param[out] uu AVUUID + * @return A non-zero value in case of an error. + */ +int av_uuid_urn_parse(const char *in, AVUUID uu); + +/** + * Parses a string representation of a UUID formatted according to IETF RFC 4122 + * into an AVUUID. The parsing is case-insensitive. + * + * @param[in] in_start Pointer to the first character of the string representation + * @param[in] in_end Pointer to the character after the last character of the + * string representation. That memory location is never + * accessed. It is an error if `in_end - in_start != 36`. + * @param[out] uu AVUUID + * @return A non-zero value in case of an error. + */ +int av_uuid_parse_range(const char *in_start, const char *in_end, AVUUID uu); + +/** + * Serializes a AVUUID into a string representation according to IETF RFC 4122. + * The string is lowercase and always 37 characters long, including the + * terminating NUL character. + * + * @param[in] uu AVUUID + * @param[out] out Pointer to an array of no less than 37 characters. + */ +void av_uuid_unparse(const AVUUID uu, char *out); + +/** + * Compares two UUIDs for equality. + * + * @param[in] uu1 AVUUID + * @param[in] uu2 AVUUID + * @return Nonzero if uu1 and uu2 are identical, 0 otherwise + */ +static inline int av_uuid_equal(const AVUUID uu1, const AVUUID uu2) +{ + return memcmp(uu1, uu2, AV_UUID_LEN) == 0; +} + +/** + * Copies the bytes of src into dest. + * + * @param[out] dest AVUUID + * @param[in] src AVUUID + */ +static inline void av_uuid_copy(AVUUID dest, const AVUUID src) +{ + memcpy(dest, src, AV_UUID_LEN); +} + +/** + * Sets a UUID to the nil UUID, i.e. a UUID with have all + * its 128 bits set to zero. + * + * @param[in,out] uu UUID to be set to the nil UUID + */ +static inline void av_uuid_nil(AVUUID uu) +{ + memset(uu, 0, AV_UUID_LEN); +} + +#endif /* AVUTIL_UUID_H */ diff --git a/libs/ffmpeg/libavutil/version.c b/libs/ffmpeg/libavutil/version.c new file mode 100644 index 00000000000..afab190336f --- /dev/null +++ b/libs/ffmpeg/libavutil/version.c @@ -0,0 +1,56 @@ +/* + * Version functions. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <assert.h> + +#include "config.h" +#include "avutil.h" +#include "samplefmt.h" +#include "version.h" + +#include "libavutil/ffversion.h" +const char av_util_ffversion[] = "FFmpeg version " FFMPEG_VERSION; + +const char *av_version_info(void) +{ + return FFMPEG_VERSION; +} + +unsigned avutil_version(void) +{ + static_assert(AV_SAMPLE_FMT_S64P == 11 && + AVMEDIA_TYPE_ATTACHMENT == 4 && + AV_PICTURE_TYPE_BI == 7, + "Don't insert new sample/media/picture types in the middle of the list"); + static_assert(LIBAVUTIL_VERSION_MICRO >= 100, "micro version starts at 100"); + + return LIBAVUTIL_VERSION_INT; +} + +const char *avutil_configuration(void) +{ + return FFMPEG_CONFIGURATION; +} + +const char *avutil_license(void) +{ +#define LICENSE_PREFIX "libavutil license: " + return &LICENSE_PREFIX FFMPEG_LICENSE[sizeof(LICENSE_PREFIX) - 1]; +} diff --git a/libs/ffmpeg/libavutil/version.h b/libs/ffmpeg/libavutil/version.h new file mode 100644 index 00000000000..c61f6b0e9cd --- /dev/null +++ b/libs/ffmpeg/libavutil/version.h @@ -0,0 +1,123 @@ +/* + * copyright (c) 2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu + * Libavutil version macros + */ + +#ifndef AVUTIL_VERSION_H +#define AVUTIL_VERSION_H + +#include "macros.h" + +/** + * @addtogroup version_utils + * + * Useful to check and match library version in order to maintain + * backward compatibility. + * + * The FFmpeg libraries follow a versioning scheme very similar to + * Semantic Versioning (http://semver.org/) + * The difference is that the component called PATCH is called MICRO in FFmpeg + * and its value is reset to 100 instead of 0 to keep it above or equal to 100. + * Also we do not increase MICRO for every bugfix or change in git master. + * + * Prior to FFmpeg 3.2 point releases did not change any lib version number to + * avoid aliassing different git master checkouts. + * Starting with FFmpeg 3.2, the released library versions will occupy + * a separate MAJOR.MINOR that is not used on the master development branch. + * That is if we branch a release of master 55.10.123 we will bump to 55.11.100 + * for the release and master will continue at 55.12.100 after it. Each new + * point release will then bump the MICRO improving the usefulness of the lib + * versions. + * + * @{ + */ + +#define AV_VERSION_INT(a, b, c) ((a)<<16 | (b)<<8 | (c)) +#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c +#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c) + +/** + * Extract version components from the full ::AV_VERSION_INT int as returned + * by functions like ::avformat_version() and ::avcodec_version() + */ +#define AV_VERSION_MAJOR(a) ((a) >> 16) +#define AV_VERSION_MINOR(a) (((a) & 0x00FF00) >> 8) +#define AV_VERSION_MICRO(a) ((a) & 0xFF) + +/** + * @} + */ + +/** + * @defgroup lavu_ver Version and Build diagnostics + * + * Macros and function useful to check at compile time and at runtime + * which version of libavutil is in use. + * + * @{ + */ + +#define LIBAVUTIL_VERSION_MAJOR 60 +#define LIBAVUTIL_VERSION_MINOR 26 +#define LIBAVUTIL_VERSION_MICRO 101 + +#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_VERSION AV_VERSION(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT + +#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION) + +/** + * @defgroup lavu_depr_guards Deprecation Guards + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + * + * @note, when bumping the major version it is recommended to manually + * disable each FF_API_* in its own commit instead of disabling them all + * at once through the bump. This improves the git bisect-ability of the change. + * + * @{ + */ + +#define FF_API_MOD_UINTP2 (LIBAVUTIL_VERSION_MAJOR < 61) +#define FF_API_RISCV_FD_ZBA (LIBAVUTIL_VERSION_MAJOR < 61) +#define FF_API_VULKAN_FIXED_QUEUES (LIBAVUTIL_VERSION_MAJOR < 61) +#define FF_API_OPT_INT_LIST (LIBAVUTIL_VERSION_MAJOR < 61) +#define FF_API_OPT_PTR (LIBAVUTIL_VERSION_MAJOR < 61) +#define FF_API_CPU_FLAG_FORCE (LIBAVUTIL_VERSION_MAJOR < 61) +#define FF_API_DOVI_L11_INVALID_PROPS (LIBAVUTIL_VERSION_MAJOR < 61) +#define FF_API_ASSERT_FPU (LIBAVUTIL_VERSION_MAJOR < 61) +#define FF_API_VULKAN_SYNC_QUEUES (LIBAVUTIL_VERSION_MAJOR < 62) + +/** + * @} + * @} + */ + +#endif /* AVUTIL_VERSION_H */ diff --git a/libs/ffmpeg/libavutil/version_major.h b/libs/ffmpeg/libavutil/version_major.h new file mode 100644 index 00000000000..e4db2e34dbe --- /dev/null +++ b/libs/ffmpeg/libavutil/version_major.h @@ -0,0 +1,25 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_VERSION_MAJOR_H +#define AVUTIL_VERSION_MAJOR_H + +/* This file is intentionally empty; it's only kept to fulfill make + * dependencies for ffbuild/libversion.sh. It is not installed. */ + +#endif /* AVUTIL_VERSION_MAJOR_H */ diff --git a/libs/ffmpeg/libavutil/video_enc_params.c b/libs/ffmpeg/libavutil/video_enc_params.c new file mode 100644 index 00000000000..33592dc1284 --- /dev/null +++ b/libs/ffmpeg/libavutil/video_enc_params.c @@ -0,0 +1,80 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stddef.h> +#include <stdint.h> + +#include "buffer.h" +#include "frame.h" +#include "mem.h" +#include "video_enc_params.h" + +AVVideoEncParams *av_video_enc_params_alloc(enum AVVideoEncParamsType type, + unsigned int nb_blocks, size_t *out_size) +{ + struct TestStruct { + AVVideoEncParams p; + AVVideoBlockParams b; + }; + const size_t blocks_offset = offsetof(struct TestStruct, b); + size_t size = blocks_offset; + AVVideoEncParams *par; + + if (nb_blocks > (SIZE_MAX - size) / sizeof(AVVideoBlockParams)) + return NULL; + size += sizeof(AVVideoBlockParams) * nb_blocks; + + par = av_mallocz(size); + if (!par) + return NULL; + + par->type = type; + par->nb_blocks = nb_blocks; + par->block_size = sizeof(AVVideoBlockParams); + par->blocks_offset = blocks_offset; + + if (out_size) + *out_size = size; + + return par; +} + +AVVideoEncParams* +av_video_enc_params_create_side_data(AVFrame *frame, enum AVVideoEncParamsType type, + unsigned int nb_blocks) +{ + AVBufferRef *buf; + AVVideoEncParams *par; + size_t size; + + par = av_video_enc_params_alloc(type, nb_blocks, &size); + if (!par) + return NULL; + buf = av_buffer_create((uint8_t *)par, size, NULL, NULL, 0); + if (!buf) { + av_freep(&par); + return NULL; + } + + if (!av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_VIDEO_ENC_PARAMS, buf)) { + av_buffer_unref(&buf); + return NULL; + } + + return par; +} diff --git a/libs/ffmpeg/libavutil/video_enc_params.h b/libs/ffmpeg/libavutil/video_enc_params.h new file mode 100644 index 00000000000..62265a5c064 --- /dev/null +++ b/libs/ffmpeg/libavutil/video_enc_params.h @@ -0,0 +1,171 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_VIDEO_ENC_PARAMS_H +#define AVUTIL_VIDEO_ENC_PARAMS_H + +#include <stddef.h> +#include <stdint.h> + +#include "libavutil/avassert.h" +#include "libavutil/frame.h" + +enum AVVideoEncParamsType { + AV_VIDEO_ENC_PARAMS_NONE = -1, + /** + * VP9 stores: + * - per-frame base (luma AC) quantizer index, exported as AVVideoEncParams.qp + * - deltas for luma DC, chroma AC and chroma DC, exported in the + * corresponding entries in AVVideoEncParams.delta_qp + * - per-segment delta, exported as for each block as AVVideoBlockParams.delta_qp + * + * To compute the resulting quantizer index for a block: + * - for luma AC, add the base qp and the per-block delta_qp, saturating to + * unsigned 8-bit. + * - for luma DC and chroma AC/DC, add the corresponding + * AVVideoBlockParams.delta_qp to the luma AC index, again saturating to + * unsigned 8-bit. + */ + AV_VIDEO_ENC_PARAMS_VP9, + + /** + * H.264 stores: + * - in PPS (per-picture): + * * initial QP_Y (luma) value, exported as AVVideoEncParams.qp + * * delta(s) for chroma QP values (same for both, or each separately), + * exported as in the corresponding entries in AVVideoEncParams.delta_qp + * - per-slice QP delta, not exported directly, added to the per-MB value + * - per-MB delta; not exported directly; the final per-MB quantizer + * parameter - QP_Y - minus the value in AVVideoEncParams.qp is exported + * as AVVideoBlockParams.qp_delta. + */ + AV_VIDEO_ENC_PARAMS_H264, + + /* + * MPEG-2-compatible quantizer. + * + * Summing the frame-level qp with the per-block delta_qp gives the + * resulting quantizer for the block. + */ + AV_VIDEO_ENC_PARAMS_MPEG2, +}; + +/** + * Video encoding parameters for a given frame. This struct is allocated along + * with an optional array of per-block AVVideoBlockParams descriptors. + * Must be allocated with av_video_enc_params_alloc(). + */ +typedef struct AVVideoEncParams { + /** + * Number of blocks in the array. + * + * May be 0, in which case no per-block information is present. In this case + * the values of blocks_offset / block_size are unspecified and should not + * be accessed. + */ + unsigned int nb_blocks; + /** + * Offset in bytes from the beginning of this structure at which the array + * of blocks starts. + */ + size_t blocks_offset; + /* + * Size of each block in bytes. May not match sizeof(AVVideoBlockParams). + */ + size_t block_size; + + /** + * Type of the parameters (the codec they are used with). + */ + enum AVVideoEncParamsType type; + + /** + * Base quantisation parameter for the frame. The final quantiser for a + * given block in a given plane is obtained from this value, possibly + * combined with {@code delta_qp} and the per-block delta in a manner + * documented for each type. + */ + int32_t qp; + + /** + * Quantisation parameter offset from the base (per-frame) qp for a given + * plane (first index) and AC/DC coefficients (second index). + */ + int32_t delta_qp[4][2]; +} AVVideoEncParams; + +/** + * Data structure for storing block-level encoding information. + * It is allocated as a part of AVVideoEncParams and should be retrieved with + * av_video_enc_params_block(). + * + * sizeof(AVVideoBlockParams) is not a part of the ABI and new fields may be + * added to it. + */ +typedef struct AVVideoBlockParams { + /** + * Distance in luma pixels from the top-left corner of the visible frame + * to the top-left corner of the block. + * Can be negative if top/right padding is present on the coded frame. + */ + int src_x, src_y; + /** + * Width and height of the block in luma pixels. + */ + int w, h; + + /** + * Difference between this block's final quantization parameter and the + * corresponding per-frame value. + */ + int32_t delta_qp; +} AVVideoBlockParams; + +/** + * Get the block at the specified {@code idx}. Must be between 0 and nb_blocks - 1. + */ +static av_always_inline AVVideoBlockParams* +av_video_enc_params_block(AVVideoEncParams *par, unsigned int idx) +{ + av_assert0(idx < par->nb_blocks); + return (AVVideoBlockParams *)((uint8_t *)par + par->blocks_offset + + idx * par->block_size); +} + +/** + * Allocates memory for AVVideoEncParams of the given type, plus an array of + * {@code nb_blocks} AVVideoBlockParams and initializes the variables. Can be + * freed with a normal av_free() call. + * + * @param out_size if non-NULL, the size in bytes of the resulting data array is + * written here. + */ +AVVideoEncParams *av_video_enc_params_alloc(enum AVVideoEncParamsType type, + unsigned int nb_blocks, size_t *out_size); + +/** + * Allocates memory for AVEncodeInfoFrame plus an array of + * {@code nb_blocks} AVEncodeInfoBlock in the given AVFrame {@code frame} + * as AVFrameSideData of type AV_FRAME_DATA_VIDEO_ENC_PARAMS + * and initializes the variables. + */ +AVVideoEncParams* +av_video_enc_params_create_side_data(AVFrame *frame, enum AVVideoEncParamsType type, + unsigned int nb_blocks); + +#endif /* AVUTIL_VIDEO_ENC_PARAMS_H */ diff --git a/libs/ffmpeg/libavutil/video_hint.c b/libs/ffmpeg/libavutil/video_hint.c new file mode 100644 index 00000000000..431716ab675 --- /dev/null +++ b/libs/ffmpeg/libavutil/video_hint.c @@ -0,0 +1,81 @@ +/* + * Copyright 2023 Elias Carotti <eliascrt at amazon dot it> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <string.h> + +#include "avstring.h" +#include "frame.h" +#include "macros.h" +#include "mem.h" +#include "video_hint.h" + +AVVideoHint *av_video_hint_alloc(size_t nb_rects, + size_t *out_size) +{ + struct TestStruct { + AVVideoHint hint; + AVVideoRect rect; + }; + const size_t rect_offset = offsetof(struct TestStruct, rect); + size_t size = rect_offset; + AVVideoHint *hint; + + *out_size = 0; + if (nb_rects > (SIZE_MAX - size) / sizeof(AVVideoRect)) + return NULL; + size += sizeof(AVVideoRect) * nb_rects; + + hint = av_mallocz(size); + if (!hint) + return NULL; + + hint->nb_rects = nb_rects; + hint->rect_offset = rect_offset; + hint->rect_size = sizeof(AVVideoRect); + + *out_size = size; + + return hint; +} + +AVVideoHint *av_video_hint_create_side_data(AVFrame *frame, + size_t nb_rects) +{ + AVVideoHint *hint; + AVBufferRef *buf; + size_t size = 0; + + hint = av_video_hint_alloc(nb_rects, &size); + if (!hint) + return NULL; + + buf = av_buffer_create((uint8_t *)hint, size, NULL, NULL, 0); + if (!buf) { + av_freep(&hint); + return NULL; + } + + if (!av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_VIDEO_HINT, buf)) { + av_buffer_unref(&buf); + return NULL; + } + + return hint; +} diff --git a/libs/ffmpeg/libavutil/video_hint.h b/libs/ffmpeg/libavutil/video_hint.h new file mode 100644 index 00000000000..8e8af0ae90c --- /dev/null +++ b/libs/ffmpeg/libavutil/video_hint.h @@ -0,0 +1,107 @@ +/** + * Copyright 2023 Elias Carotti <eliascrt at amazon dot it> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_VIDEO_HINT_H +#define AVUTIL_VIDEO_HINT_H + +#include <stddef.h> +#include <stdint.h> +#include "libavutil/avassert.h" +#include "libavutil/frame.h" + +typedef struct AVVideoRect { + uint32_t x, y; + uint32_t width, height; +} AVVideoRect; + +typedef enum AVVideoHintType { + /* rectangled delimit the constant areas (unchanged), default is changed */ + AV_VIDEO_HINT_TYPE_CONSTANT, + + /* rectangled delimit the constant areas (changed), default is not changed */ + AV_VIDEO_HINT_TYPE_CHANGED, +} AVVideoHintType; + +typedef struct AVVideoHint { + /** + * Number of AVVideoRect present. + * + * May be 0, in which case no per-rectangle information is present. In this + * case the values of rect_offset / rect_size are unspecified and should + * not be accessed. + */ + size_t nb_rects; + + /** + * Offset in bytes from the beginning of this structure at which the array + * of AVVideoRect starts. + */ + size_t rect_offset; + + /** + * Size in bytes of AVVideoRect. + */ + size_t rect_size; + + AVVideoHintType type; +} AVVideoHint; + +static av_always_inline AVVideoRect * +av_video_hint_rects(const AVVideoHint *hints) { + return (AVVideoRect *)((uint8_t *)hints + hints->rect_offset); +} + +static av_always_inline AVVideoRect * +av_video_hint_get_rect(const AVVideoHint *hints, size_t idx) { + return (AVVideoRect *)((uint8_t *)hints + hints->rect_offset + idx * hints->rect_size); +} + +/** + * Allocate memory for the AVVideoHint struct along with an nb_rects-sized + * arrays of AVVideoRect. + * + * The side data contains a list of rectangles for the portions of the frame + * which changed from the last encoded one (and the remainder are assumed to be + * changed), or, alternately (depending on the type parameter) the unchanged + * ones (and the remaining ones are those which changed). + * Macroblocks will thus be hinted either to be P_SKIP-ped or go through the + * regular encoding procedure. + * + * It's responsibility of the caller to fill the AVRects accordingly, and to set + * the proper AVVideoHintType field. + * + * @param out_size if non-NULL, the size in bytes of the resulting data array is + * written here + * + * @return newly allocated AVVideoHint struct (must be freed by the caller using + * av_free()) on success, NULL on memory allocation failure + */ +AVVideoHint *av_video_hint_alloc(size_t nb_rects, + size_t *out_size); + +/** + * Same as av_video_hint_alloc(), except newly-allocated AVVideoHint is attached + * as side data of type AV_FRAME_DATA_VIDEO_HINT_INFO to frame. + */ +AVVideoHint *av_video_hint_create_side_data(AVFrame *frame, + size_t nb_rects); + + +#endif /* AVUTIL_VIDEO_HINT_H */ diff --git a/libs/ffmpeg/libavutil/wchar_filename.h b/libs/ffmpeg/libavutil/wchar_filename.h new file mode 100644 index 00000000000..1370a084c91 --- /dev/null +++ b/libs/ffmpeg/libavutil/wchar_filename.h @@ -0,0 +1,281 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_WCHAR_FILENAME_H +#define AVUTIL_WCHAR_FILENAME_H + +#ifdef _WIN32 + +#include <errno.h> +#include <stddef.h> +#include <windows.h> +#include "mem.h" + +av_warn_unused_result +static inline int utf8towchar(const char *filename_utf8, wchar_t **filename_w) +{ + int num_chars; + num_chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename_utf8, -1, NULL, 0); + if (num_chars <= 0) { + *filename_w = NULL; + errno = EINVAL; + return -1; + } + *filename_w = (wchar_t *)av_calloc(num_chars, sizeof(wchar_t)); + if (!*filename_w) { + errno = ENOMEM; + return -1; + } + MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, *filename_w, num_chars); + return 0; +} + +av_warn_unused_result +static inline int wchartocp(unsigned int code_page, const wchar_t *filename_w, + char **filename) +{ + DWORD flags = code_page == CP_UTF8 ? WC_ERR_INVALID_CHARS : 0; + int num_chars = WideCharToMultiByte(code_page, flags, filename_w, -1, + NULL, 0, NULL, NULL); + if (num_chars <= 0) { + *filename = NULL; + errno = EINVAL; + return -1; + } + *filename = (char *)av_malloc_array(num_chars, sizeof **filename); + if (!*filename) { + errno = ENOMEM; + return -1; + } + WideCharToMultiByte(code_page, flags, filename_w, -1, + *filename, num_chars, NULL, NULL); + return 0; +} + +av_warn_unused_result +static inline int wchartoutf8(const wchar_t *filename_w, char **filename) +{ + return wchartocp(CP_UTF8, filename_w, filename); +} + +av_warn_unused_result +static inline int wchartoansi(const wchar_t *filename_w, char **filename) +{ + return wchartocp(CP_ACP, filename_w, filename); +} + +av_warn_unused_result +static inline int utf8toansi(const char *filename_utf8, char **filename) +{ + wchar_t *filename_w = NULL; + int ret = -1; + if (utf8towchar(filename_utf8, &filename_w)) + return -1; + + if (!filename_w) { + *filename = NULL; + return 0; + } + + ret = wchartoansi(filename_w, filename); + av_free(filename_w); + return ret; +} + +/** + * Checks for extended path prefixes for which normalization needs to be skipped. + * see .NET6: PathInternal.IsExtended() + * https://github.com/dotnet/runtime/blob/9260c249140ef90b4299d0fe1aa3037e25228... + */ +static inline int path_is_extended(const wchar_t *path) +{ + if (path[0] == L'\\' && (path[1] == L'\\' || path[1] == L'?') && path[2] == L'?' && path[3] == L'\\') + return 1; + + return 0; +} + +/** + * Checks for a device path prefix. + * see .NET6: PathInternal.IsDevice() + * we don't check forward slashes and extended paths (as already done) + * https://github.com/dotnet/runtime/blob/9260c249140ef90b4299d0fe1aa3037e25228... + */ +static inline int path_is_device_path(const wchar_t *path) +{ + if (path[0] == L'\\' && path[1] == L'\\' && path[2] == L'.' && path[3] == L'\\') + return 1; + + return 0; +} + +/** + * Performs path normalization by calling GetFullPathNameW(). + * see .NET6: PathHelper.GetFullPathName() + * https://github.com/dotnet/runtime/blob/2a99e18eedabcf1add064c099da59d9301ce4... + */ +static inline int get_full_path_name(wchar_t **ppath_w) +{ + int num_chars; + wchar_t *temp_w; + + num_chars = GetFullPathNameW(*ppath_w, 0, NULL, NULL); + if (num_chars <= 0) { + errno = EINVAL; + return -1; + } + + temp_w = (wchar_t *)av_calloc(num_chars, sizeof(wchar_t)); + if (!temp_w) { + errno = ENOMEM; + return -1; + } + + num_chars = GetFullPathNameW(*ppath_w, num_chars, temp_w, NULL); + if (num_chars <= 0) { + av_free(temp_w); + errno = EINVAL; + return -1; + } + + av_freep(ppath_w); + *ppath_w = temp_w; + + return 0; +} + +/** + * Normalizes a Windows file or folder path. + * Expansion of short paths (with 8.3 path components) is currently omitted + * as it is not required for accessing long paths. + * see .NET6: PathHelper.Normalize() + * https://github.com/dotnet/runtime/blob/2a99e18eedabcf1add064c099da59d9301ce4... + */ +static inline int path_normalize(wchar_t **ppath_w) +{ + int ret; + + if ((ret = get_full_path_name(ppath_w)) < 0) + return ret; + + /* What .NET does at this point is to call PathHelper.TryExpandShortFileName() + * in case the path contains a '~' character. + * We don't need to do this as we don't need to normalize the file name + * for presentation, and the extended path prefix works with 8.3 path + * components as well + */ + return 0; +} + +/** + * Adds an extended path or UNC prefix to longs paths or paths ending + * with a space or a dot. (' ' or '.'). + * This function expects that the path has been normalized before by + * calling path_normalize() and it doesn't check whether the path is + * actually long (> MAX_PATH). + * see .NET6: PathInternal.EnsureExtendedPrefix() + * https://github.com/dotnet/runtime/blob/9260c249140ef90b4299d0fe1aa3037e25228... + */ +static inline int add_extended_prefix(wchar_t **ppath_w) +{ + const wchar_t *unc_prefix = L"\\\\?\\UNC\\"; + const wchar_t *extended_path_prefix = L"\\\\?\\"; + const wchar_t *path_w = *ppath_w; + const size_t len = wcslen(path_w); + wchar_t *temp_w; + + /* We're skipping the check IsPartiallyQualified() because + * we expect to have called GetFullPathNameW() already. */ + if (len < 2 || path_is_extended(*ppath_w) || path_is_device_path(*ppath_w)) { + return 0; + } + + if (path_w[0] == L'\\' && path_w[1] == L'\\') { + /* unc_prefix length is 8 plus 1 for terminating zeros, + * we subtract 2 for the leading '\\' of the original path */ + temp_w = (wchar_t *)av_calloc(len - 2 + 8 + 1, sizeof(wchar_t)); + if (!temp_w) { + errno = ENOMEM; + return -1; + } + wcscpy(temp_w, unc_prefix); + wcscat(temp_w, path_w + 2); + } else { + // The length of extended_path_prefix is 4 plus 1 for terminating zeros + temp_w = (wchar_t *)av_calloc(len + 4 + 1, sizeof(wchar_t)); + if (!temp_w) { + errno = ENOMEM; + return -1; + } + wcscpy(temp_w, extended_path_prefix); + wcscat(temp_w, path_w); + } + + av_freep(ppath_w); + *ppath_w = temp_w; + + return 0; +} + +/** + * Converts a file or folder path to wchar_t for use with Windows file + * APIs. Paths with extended path prefix (either '\\?\' or \??\') are + * left unchanged. + * All other paths are normalized and converted to absolute paths. + * Longs paths (>= MAX_PATH) are prefixed with the extended path or extended + * UNC path prefix. + * see .NET6: Path.GetFullPath() and Path.GetFullPathInternal() + * https://github.com/dotnet/runtime/blob/2a99e18eedabcf1add064c099da59d9301ce4... + */ +static inline int get_extended_win32_path(const char *path, wchar_t **ppath_w) +{ + int ret; + size_t len; + + if ((ret = utf8towchar(path, ppath_w)) < 0) + return ret; + + if (path_is_extended(*ppath_w)) { + /* Paths prefixed with '\\?\' or \??\' are considered normalized by definition. + * Windows doesn't normalize those paths and neither should we. + */ + return 0; + } + + if ((ret = path_normalize(ppath_w)) < 0) { + av_freep(ppath_w); + return ret; + } + + /* see .NET6: PathInternal.EnsureExtendedPrefixIfNeeded() + * https://github.com/dotnet/runtime/blob/9260c249140ef90b4299d0fe1aa3037e25228... + */ + len = wcslen(*ppath_w); + if (len >= MAX_PATH) { + if ((ret = add_extended_prefix(ppath_w)) < 0) { + av_freep(ppath_w); + return ret; + } + } + + return 0; +} + +#endif + +#endif /* AVUTIL_WCHAR_FILENAME_H */ diff --git a/libs/ffmpeg/libavutil/x86/asm.h b/libs/ffmpeg/libavutil/x86/asm.h new file mode 100644 index 00000000000..f06ea250352 --- /dev/null +++ b/libs/ffmpeg/libavutil/x86/asm.h @@ -0,0 +1,153 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_ASM_H +#define AVUTIL_X86_ASM_H + +#include <stdint.h> +#include "config.h" + +typedef struct xmm_reg { uint64_t a, b; } xmm_reg; +typedef struct ymm_reg { uint64_t a, b, c, d; } ymm_reg; + +#if ARCH_X86_64 +# define FF_OPSIZE "q" +# define FF_REG_a "rax" +# define FF_REG_b "rbx" +# define FF_REG_c "rcx" +# define FF_REG_d "rdx" +# define FF_REG_D "rdi" +# define FF_REG_S "rsi" +# define FF_PTR_SIZE "8" +typedef int64_t x86_reg; + +# define FF_REG_SP "rsp" +# define FF_REG_BP "rbp" +# define FF_REGBP rbp +# define FF_REGa rax +# define FF_REGb rbx +# define FF_REGc rcx +# define FF_REGd rdx +# define FF_REGSP rsp + +#elif ARCH_X86_32 + +# define FF_OPSIZE "l" +# define FF_REG_a "eax" +# define FF_REG_b "ebx" +# define FF_REG_c "ecx" +# define FF_REG_d "edx" +# define FF_REG_D "edi" +# define FF_REG_S "esi" +# define FF_PTR_SIZE "4" +typedef int32_t x86_reg; + +# define FF_REG_SP "esp" +# define FF_REG_BP "ebp" +# define FF_REGBP ebp +# define FF_REGa eax +# define FF_REGb ebx +# define FF_REGc ecx +# define FF_REGd edx +# define FF_REGSP esp +#else +typedef int x86_reg; +#endif + +#define HAVE_7REGS (ARCH_X86_64 || (HAVE_EBX_AVAILABLE && HAVE_EBP_AVAILABLE)) +#define HAVE_6REGS (ARCH_X86_64 || (HAVE_EBX_AVAILABLE || HAVE_EBP_AVAILABLE)) + +#if ARCH_X86_64 && defined(PIC) +# define BROKEN_RELOCATIONS 1 +#endif + +/* + * If gcc is not set to support sse (-msse) it will not accept xmm registers + * in the clobber list for inline asm. XMM_CLOBBERS takes a list of xmm + * registers to be marked as clobbered and evaluates to nothing if they are + * not supported, or to the list itself if they are supported. Since a clobber + * list may not be empty, XMM_CLOBBERS_ONLY should be used if the xmm + * registers are the only in the clobber list. + * For example a list with "eax" and "xmm0" as clobbers should become: + * : XMM_CLOBBERS("xmm0",) "eax" + * and a list with only "xmm0" should become: + * XMM_CLOBBERS_ONLY("xmm0") + */ +#if HAVE_XMM_CLOBBERS +# define XMM_CLOBBERS(...) __VA_ARGS__ +# define XMM_CLOBBERS_ONLY(...) : __VA_ARGS__ +#else +# define XMM_CLOBBERS(...) +# define XMM_CLOBBERS_ONLY(...) +#endif + +/* Use to export labels from asm. */ +#define LABEL_MANGLE(a) EXTERN_PREFIX #a + +// Use rip-relative addressing if compiling PIC code on x86-64. +#if ARCH_X86_64 && defined(PIC) +# define LOCAL_MANGLE(a) #a "(%%rip)" +#else +# define LOCAL_MANGLE(a) #a +#endif + +#if HAVE_INLINE_ASM_DIRECT_SYMBOL_REFS +# define MANGLE(a) EXTERN_PREFIX LOCAL_MANGLE(a) +# define NAMED_CONSTRAINTS_ADD(...) +# define NAMED_CONSTRAINTS(...) +# define NAMED_CONSTRAINTS_ARRAY_ADD(...) +# define NAMED_CONSTRAINTS_ARRAY(...) +#else + /* When direct symbol references are used in code passed to a compiler that does not support them + * then these references need to be converted to named asm constraints instead. + * Instead of returning a direct symbol MANGLE now returns a named constraint for that specific symbol. + * In order for this to work there must also be a corresponding entry in the asm-interface. To add this + * entry use the macro NAMED_CONSTRAINTS() and pass in a list of each symbol reference used in the + * corresponding block of code. (e.g. NAMED_CONSTRAINTS(var1,var2,var3) where var1 is the first symbol etc. ). + * If there are already existing constraints then use NAMED_CONSTRAINTS_ADD to add to the existing constraint list. + */ +# define MANGLE(a) "%["#a"]" + // Intel/MSVC does not correctly expand va-args so we need a rather ugly hack in order to get it to work +# define FE_0(P,X) P(X) +# define FE_1(P,X,X1) P(X), FE_0(P,X1) +# define FE_2(P,X,X1,X2) P(X), FE_1(P,X1,X2) +# define FE_3(P,X,X1,X2,X3) P(X), FE_2(P,X1,X2,X3) +# define FE_4(P,X,X1,X2,X3,X4) P(X), FE_3(P,X1,X2,X3,X4) +# define FE_5(P,X,X1,X2,X3,X4,X5) P(X), FE_4(P,X1,X2,X3,X4,X5) +# define FE_6(P,X,X1,X2,X3,X4,X5,X6) P(X), FE_5(P,X1,X2,X3,X4,X5,X6) +# define FE_7(P,X,X1,X2,X3,X4,X5,X6,X7) P(X), FE_6(P,X1,X2,X3,X4,X5,X6,X7) +# define FE_8(P,X,X1,X2,X3,X4,X5,X6,X7,X8) P(X), FE_7(P,X1,X2,X3,X4,X5,X6,X7,X8) +# define FE_9(P,X,X1,X2,X3,X4,X5,X6,X7,X8,X9) P(X), FE_8(P,X1,X2,X3,X4,X5,X6,X7,X8,X9) +# define GET_FE_IMPL(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,NAME,...) NAME +# define GET_FE(A) GET_FE_IMPL A +# define GET_FE_GLUE(x, y) x y +# define FOR_EACH_VA(P,...) GET_FE_GLUE(GET_FE((__VA_ARGS__,FE_9,FE_8,FE_7,FE_6,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)), (P,__VA_ARGS__)) +# define NAME_CONSTRAINT(x) [x] "m"(x) + // Parameters are a list of each symbol reference required +# define NAMED_CONSTRAINTS_ADD(...) , FOR_EACH_VA(NAME_CONSTRAINT,__VA_ARGS__) + // Same but without comma for when there are no previously defined constraints +# define NAMED_CONSTRAINTS(...) FOR_EACH_VA(NAME_CONSTRAINT,__VA_ARGS__) + // Same as above NAMED_CONSTRAINTS except used for passing arrays/pointers instead of normal variables +# define NAME_CONSTRAINT_ARRAY(x) [x] "m"(*x) +# define NAMED_CONSTRAINTS_ARRAY_ADD(...) , FOR_EACH_VA(NAME_CONSTRAINT_ARRAY,__VA_ARGS__) +# define NAMED_CONSTRAINTS_ARRAY(...) FOR_EACH_VA(NAME_CONSTRAINT_ARRAY,__VA_ARGS__) +#endif + +#endif /* AVUTIL_X86_ASM_H */ diff --git a/libs/ffmpeg/libavutil/x86/bswap.h b/libs/ffmpeg/libavutil/x86/bswap.h new file mode 100644 index 00000000000..1ce9dcfc650 --- /dev/null +++ b/libs/ffmpeg/libavutil/x86/bswap.h @@ -0,0 +1,79 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * byte swapping routines + */ + +#ifndef AVUTIL_X86_BSWAP_H +#define AVUTIL_X86_BSWAP_H + +#include <stdint.h> +#if defined(_MSC_VER) +#include <stdlib.h> +#include <intrin.h> +#endif +#include "config.h" +#include "libavutil/attributes.h" + +#if defined(_MSC_VER) + +#define av_bswap16 av_bswap16 +static av_always_inline av_const uint16_t av_bswap16(uint16_t x) +{ + return _rotr16(x, 8); +} + +#define av_bswap32 av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + return _byteswap_ulong(x); +} + +#if ARCH_X86_64 +#define av_bswap64 av_bswap64 +static inline uint64_t av_const av_bswap64(uint64_t x) +{ + return _byteswap_uint64(x); +} +#endif + + +#elif HAVE_INLINE_ASM + +#ifdef __INTEL_COMPILER +#define av_bswap32 av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + __asm__("bswap %0" : "+r" (x)); + return x; +} + +#if ARCH_X86_64 +#define av_bswap64 av_bswap64 +static inline uint64_t av_const av_bswap64(uint64_t x) +{ + __asm__("bswap %0": "=r" (x) : "0" (x)); + return x; +} +#endif +#endif /* __INTEL_COMPILER */ + +#endif /* HAVE_INLINE_ASM */ +#endif /* AVUTIL_X86_BSWAP_H */ diff --git a/libs/ffmpeg/libavutil/x86/cpu.h b/libs/ffmpeg/libavutil/x86/cpu.h new file mode 100644 index 00000000000..af081b2ed8c --- /dev/null +++ b/libs/ffmpeg/libavutil/x86/cpu.h @@ -0,0 +1,107 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_CPU_H +#define AVUTIL_X86_CPU_H + +#include "libavutil/cpu.h" +#include "libavutil/cpu_internal.h" + +#define X86_MMX(flags) CPUEXT(flags, MMX) +#define X86_MMXEXT(flags) CPUEXT(flags, MMXEXT) +#define X86_SSE(flags) CPUEXT(flags, SSE) +#define X86_SSE2(flags) CPUEXT(flags, SSE2) +#define X86_SSE2_FAST(flags) CPUEXT_FAST(flags, SSE2) +#define X86_SSE2_SLOW(flags) CPUEXT_SLOW(flags, SSE2) +#define X86_SSE3(flags) CPUEXT(flags, SSE3) +#define X86_SSE3_FAST(flags) CPUEXT_FAST(flags, SSE3) +#define X86_SSE3_SLOW(flags) CPUEXT_SLOW(flags, SSE3) +#define X86_SSSE3(flags) CPUEXT(flags, SSSE3) +#define X86_SSSE3_FAST(flags) CPUEXT_FAST(flags, SSSE3) +#define X86_SSSE3_SLOW(flags) CPUEXT_SLOW(flags, SSSE3) +#define X86_SSE4(flags) CPUEXT(flags, SSE4) +#define X86_SSE42(flags) CPUEXT(flags, SSE42) +#define X86_AVX(flags) CPUEXT(flags, AVX) +#define X86_AVX_FAST(flags) CPUEXT_FAST(flags, AVX) +#define X86_AVX_SLOW(flags) CPUEXT_SLOW(flags, AVX) +#define X86_XOP(flags) CPUEXT(flags, XOP) +#define X86_FMA3(flags) CPUEXT(flags, FMA3) +#define X86_FMA4(flags) CPUEXT(flags, FMA4) +#define X86_AVX2(flags) CPUEXT(flags, AVX2) +#define X86_AESNI(flags) CPUEXT(flags, AESNI) +#define X86_CLMUL(flags) CPUEXT(flags, CLMUL) +#define X86_AVX512(flags) CPUEXT(flags, AVX512) + +#define EXTERNAL_MMX(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, MMX) +#define EXTERNAL_MMXEXT(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, MMXEXT) +#define EXTERNAL_SSE(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSE) +#define EXTERNAL_SSE2(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSE2) +#define EXTERNAL_SSE2_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _EXTERNAL, SSE2) +#define EXTERNAL_SSE2_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _EXTERNAL, SSE2) +#define EXTERNAL_SSE3(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSE3) +#define EXTERNAL_SSE3_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _EXTERNAL, SSE3) +#define EXTERNAL_SSE3_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _EXTERNAL, SSE3) +#define EXTERNAL_SSSE3(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSSE3) +#define EXTERNAL_SSSE3_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _EXTERNAL, SSSE3) +#define EXTERNAL_SSSE3_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _EXTERNAL, SSSE3) +#define EXTERNAL_SSE4(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSE4) +#define EXTERNAL_SSE42(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, SSE42) +#define EXTERNAL_AVX(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AVX) +#define EXTERNAL_AVX_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _EXTERNAL, AVX) +#define EXTERNAL_AVX_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _EXTERNAL, AVX) +#define EXTERNAL_XOP(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, XOP) +#define EXTERNAL_FMA3(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, FMA3) +#define EXTERNAL_FMA3_FAST(flags) CPUEXT_SUFFIX_FAST2(flags, _EXTERNAL, FMA3, AVX) +#define EXTERNAL_FMA3_SLOW(flags) CPUEXT_SUFFIX_SLOW2(flags, _EXTERNAL, FMA3, AVX) +#define EXTERNAL_FMA4(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, FMA4) +#define EXTERNAL_AVX2(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AVX2) +#define EXTERNAL_AVX2_FAST(flags) CPUEXT_SUFFIX_FAST2(flags, _EXTERNAL, AVX2, AVX) +#define EXTERNAL_AVX2_SLOW(flags) CPUEXT_SUFFIX_SLOW2(flags, _EXTERNAL, AVX2, AVX) +#define EXTERNAL_AESNI(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AESNI) +#define EXTERNAL_CLMUL(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, CLMUL) +#define EXTERNAL_AVX512(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AVX512) +#define EXTERNAL_AVX512ICL(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AVX512ICL) + +#define INLINE_MMX(flags) CPUEXT_SUFFIX(flags, _INLINE, MMX) +#define INLINE_MMXEXT(flags) CPUEXT_SUFFIX(flags, _INLINE, MMXEXT) +#define INLINE_SSE(flags) CPUEXT_SUFFIX(flags, _INLINE, SSE) +#define INLINE_SSE2(flags) CPUEXT_SUFFIX(flags, _INLINE, SSE2) +#define INLINE_SSE2_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _INLINE, SSE2) +#define INLINE_SSE2_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _INLINE, SSE2) +#define INLINE_SSE3(flags) CPUEXT_SUFFIX(flags, _INLINE, SSE3) +#define INLINE_SSE3_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _INLINE, SSE3) +#define INLINE_SSE3_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _INLINE, SSE3) +#define INLINE_SSSE3(flags) CPUEXT_SUFFIX(flags, _INLINE, SSSE3) +#define INLINE_SSSE3_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _INLINE, SSSE3) +#define INLINE_SSSE3_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _INLINE, SSSE3) +#define INLINE_SSE4(flags) CPUEXT_SUFFIX(flags, _INLINE, SSE4) +#define INLINE_SSE42(flags) CPUEXT_SUFFIX(flags, _INLINE, SSE42) +#define INLINE_AVX(flags) CPUEXT_SUFFIX(flags, _INLINE, AVX) +#define INLINE_AVX_FAST(flags) CPUEXT_SUFFIX_FAST(flags, _INLINE, AVX) +#define INLINE_AVX_SLOW(flags) CPUEXT_SUFFIX_SLOW(flags, _INLINE, AVX) +#define INLINE_XOP(flags) CPUEXT_SUFFIX(flags, _INLINE, XOP) +#define INLINE_FMA3(flags) CPUEXT_SUFFIX(flags, _INLINE, FMA3) +#define INLINE_FMA4(flags) CPUEXT_SUFFIX(flags, _INLINE, FMA4) +#define INLINE_AVX2(flags) CPUEXT_SUFFIX(flags, _INLINE, AVX2) +#define INLINE_AESNI(flags) CPUEXT_SUFFIX(flags, _INLINE, AESNI) + +void ff_cpu_cpuid(int index, int *eax, int *ebx, int *ecx, int *edx); +void ff_cpu_xgetbv(int op, int *eax, int *edx); +int ff_cpu_cpuid_test(void); + +#endif /* AVUTIL_X86_CPU_H */ diff --git a/libs/ffmpeg/libavutil/x86/crc.h b/libs/ffmpeg/libavutil/x86/crc.h new file mode 100644 index 00000000000..c836c090c62 --- /dev/null +++ b/libs/ffmpeg/libavutil/x86/crc.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2025 Shreesh Adiga <16567adigashreesh@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_CRC_H +#define AVUTIL_X86_CRC_H + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/attributes_internal.h" +#include "libavutil/avassert.h" +#include "libavutil/cpu.h" +#include "libavutil/crc.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/reverse.h" +#include "libavutil/x86/cpu.h" + +#if HAVE_CLMUL_EXTERNAL +FF_VISIBILITY_PUSH_HIDDEN +uint32_t ff_crc_clmul(const AVCRC *ctx, uint32_t crc, + const uint8_t *buffer, size_t length); +uint32_t ff_crc_le_clmul(const AVCRC *ctx, uint32_t crc, + const uint8_t *buffer, size_t length); +FF_VISIBILITY_POP_HIDDEN + +enum { + CRC_C = 0, + CLMUL_BE, + CLMUL_LE, +}; + +static const AVCRC crc_table_clmul[AV_CRC_MAX][17] = { + [AV_CRC_8_ATM] = { + CLMUL_BE, + 0x32000000, 0x0, 0xbc000000, 0x0, + 0xc4000000, 0x0, 0x94000000, 0x0, + 0x62000000, 0x0, 0x79000000, 0x0, + 0x07156a16, 0x1, 0x07000000, 0x1, + }, + [AV_CRC_8_EBU] = { + CLMUL_BE, + 0xb5000000, 0x0, 0xf3000000, 0x0, + 0xfc000000, 0x0, 0x0d000000, 0x0, + 0x6a000000, 0x0, 0x65000000, 0x0, + 0x1c4b8192, 0x1, 0x1d000000, 0x1, + }, + [AV_CRC_16_ANSI] = { + CLMUL_BE, + 0xf9e30000, 0x0, 0x807d0000, 0x0, + 0xf9130000, 0x0, 0xff830000, 0x0, + 0x807b0000, 0x0, 0x86630000, 0x0, + 0xfffbffe7, 0x1, 0x80050000, 0x1, + }, + [AV_CRC_16_CCITT] = { + CLMUL_BE, + 0x60190000, 0x0, 0x59b00000, 0x0, + 0xd5f60000, 0x0, 0x45630000, 0x0, + 0xaa510000, 0x0, 0xeb230000, 0x0, + 0x11303471, 0x1, 0x10210000, 0x1, + }, + [AV_CRC_24_IEEE] = { + CLMUL_BE, + 0x1f428700, 0x0, 0x467d2400, 0x0, + 0x2c8c9d00, 0x0, 0x64e4d700, 0x0, + 0xd9fe8c00, 0x0, 0xfd7e0c00, 0x0, + 0xf845fe24, 0x1, 0x864cfb00, 0x1, + }, + [AV_CRC_32_IEEE] = { + CLMUL_BE, + 0x8833794c, 0x0, 0xe6228b11, 0x0, + 0xc5b9cd4c, 0x0, 0xe8a45605, 0x0, + 0x490d678d, 0x0, 0xf200aa66, 0x0, + 0x04d101df, 0x1, 0x04c11db7, 0x1, + }, + [AV_CRC_32_IEEE_LE] = { + CLMUL_LE, + 0xc6e41596, 0x1, 0x54442bd4, 0x1, + 0xccaa009e, 0x0, 0x751997d0, 0x1, + 0xccaa009e, 0x0, 0x63cd6124, 0x1, + 0xf7011640, 0x1, 0xdb710641, 0x1, + }, + [AV_CRC_16_ANSI_LE] = { + CLMUL_LE, + 0x0000bffa, 0x0, 0x1b0c2, 0x0, + 0x00018cc2, 0x0, 0x1d0c2, 0x0, + 0x00018cc2, 0x0, 0x1bc02, 0x0, + 0xcfffbffe, 0x1, 0x14003, 0x0, + }, +}; + +static uint64_t reverse(uint64_t p, unsigned int deg) +{ + uint64_t ret = 0; + int i; + for (i = 0; i < (deg / 8); i += 1) { + ret = (ret << 8) | (ff_reverse[p & 0xff]); + p >>= 8; + } + int rem = (deg + 1) - 8 * i; + ret = (ret << rem) | (ff_reverse[p & 0xff] >> (8 - rem)); + return ret; +} + +static uint64_t xnmodp(unsigned n, uint64_t poly, unsigned deg, uint64_t *div, int bitreverse) +{ + uint64_t mod, mask, high; + + if (n < deg) { + *div = 0; + return poly; + } + mask = ((uint64_t)1 << deg) - 1; + poly &= mask; + mod = poly; + *div = 1; + deg--; + while (--n > deg) { + high = (mod >> deg) & 1; + *div = (*div << 1) | high; + mod <<= 1; + if (high) + mod ^= poly; + } + uint64_t ret = mod & mask; + if (bitreverse) { + *div = reverse(*div, deg) << 1; + return reverse(ret, deg) << 1; + } + return ret; +} + +static inline void crc_init_x86(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size) +{ + uint64_t poly_; + if (le) { + // convert the reversed representation to regular form + poly = reverse(poly, bits) >> 1; + } + // convert to 32 degree polynomial + poly_ = ((uint64_t)poly) << (32 - bits); + + uint64_t div; + uint8_t *dst = (uint8_t*)(ctx + 1); + if (le) { + ctx[0] = CLMUL_LE; + AV_WN64(dst, xnmodp(4 * 128 - 32, poly_, 32, &div, le)); + AV_WN64(dst + 8, xnmodp(4 * 128 + 32, poly_, 32, &div, le)); + uint64_t tmp = xnmodp(128 - 32, poly_, 32, &div, le); + AV_WN64(dst + 16, tmp); + AV_WN64(dst + 24, xnmodp(128 + 32, poly_, 32, &div, le)); + AV_WN64(dst + 32, tmp); + AV_WN64(dst + 40, xnmodp(64, poly_, 32, &div, le)); + AV_WN64(dst + 48, div); + AV_WN64(dst + 56, reverse(poly_ | (1ULL << 32), 32)); + } else { + ctx[0] = CLMUL_BE; + AV_WN64(dst, xnmodp(4 * 128 + 64, poly_, 32, &div, le)); + AV_WN64(dst + 8, xnmodp(4 * 128, poly_, 32, &div, le)); + AV_WN64(dst + 16, xnmodp(128 + 64, poly_, 32, &div, le)); + AV_WN64(dst + 24, xnmodp(128, poly_, 32, &div, le)); + AV_WN64(dst + 32, xnmodp(64, poly_, 32, &div, le)); + AV_WN64(dst + 48, div); + AV_WN64(dst + 40, xnmodp(96, poly_, 32, &div, le)); + AV_WN64(dst + 56, poly_ | (1ULL << 32)); + } +} +#endif + +static inline const AVCRC *ff_crc_get_table_x86(AVCRCId crc_id) +{ +#if HAVE_CLMUL_EXTERNAL + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_CLMUL(cpu_flags)) { + return crc_table_clmul[crc_id]; + } +#endif + return NULL; +} + +static inline av_cold int ff_crc_init_x86(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size) +{ +#if HAVE_CLMUL_EXTERNAL + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_CLMUL(cpu_flags)) { + crc_init_x86(ctx, le, bits, poly, ctx_size); + return 1; + } +#endif + return 0; +} + +static inline uint32_t ff_crc_x86(const AVCRC *ctx, uint32_t crc, + const uint8_t *buffer, size_t length) +{ + switch (ctx[0]) { +#if HAVE_CLMUL_EXTERNAL + case CLMUL_BE: return ff_crc_clmul(ctx, crc, buffer, length); + case CLMUL_LE: return ff_crc_le_clmul(ctx, crc, buffer, length); +#endif + default: av_unreachable("x86 CRC only uses CLMUL_BE and CLMUL_LE"); + } + return 0; +} + +#endif /* AVUTIL_X86_CRC_H */ diff --git a/libs/ffmpeg/libavutil/x86/intmath.h b/libs/ffmpeg/libavutil/x86/intmath.h new file mode 100644 index 00000000000..d8d1f19b243 --- /dev/null +++ b/libs/ffmpeg/libavutil/x86/intmath.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_INTMATH_H +#define AVUTIL_X86_INTMATH_H + +#include <stdint.h> +#include <stdlib.h> +#if HAVE_FAST_CLZ +#if defined(_MSC_VER) +#include <intrin.h> +#elif defined(__INTEL_COMPILER) +#include <immintrin.h> +#endif +#endif +#include "config.h" + +#if HAVE_FAST_CLZ +#if (defined(__INTEL_COMPILER) && (__INTEL_COMPILER>=1216)) || defined(_MSC_VER) +# if defined(__INTEL_COMPILER) +# define ff_log2(x) (_bit_scan_reverse((x)|1)) +# else +# define ff_log2 ff_log2_x86 +static av_always_inline av_const int ff_log2_x86(unsigned int v) +{ + unsigned long n; + _BitScanReverse(&n, v|1); + return n; +} +# endif +# define ff_log2_16bit av_log2 + +#if defined(__INTEL_COMPILER) || (defined(_MSC_VER) && (_MSC_VER >= 1700) && \ + (defined(__BMI__) || !defined(__clang__))) +# define ff_ctz(v) _tzcnt_u32(v) + +# if ARCH_X86_64 +# define ff_ctzll(v) _tzcnt_u64(v) +# else +# define ff_ctzll ff_ctzll_x86 +static av_always_inline av_const int ff_ctzll_x86(long long v) +{ + return ((uint32_t)v == 0) ? _tzcnt_u32((uint32_t)(v >> 32)) + 32 : _tzcnt_u32((uint32_t)v); +} +# endif +#endif /* _MSC_VER */ + +#endif /* __INTEL_COMPILER */ + +#endif /* HAVE_FAST_CLZ */ + +#if defined(__GNUC__) || defined(__clang__) + +/* Our generic version of av_popcount is faster than GCC's built-in on + * CPUs that don't support the popcnt instruction. + */ +#if defined(__POPCNT__) + #define av_popcount __builtin_popcount +#if ARCH_X86_64 + #define av_popcount64 __builtin_popcountll +#endif + +#endif /* __POPCNT__ */ + +#if defined(__BMI2__) + +#if AV_GCC_VERSION_AT_LEAST(5,1) || AV_HAS_BUILTIN(__builtin_ia32_bzhi_si) +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 +#define av_zero_extend av_zero_extend_bmi2 +static av_always_inline av_const unsigned av_zero_extend_bmi2(unsigned a, unsigned p) +{ + if (p > 31) abort(); + return __builtin_ia32_bzhi_si(a, p); +} +#else +#define av_zero_extend __builtin_ia32_bzhi_si +#endif +#elif HAVE_INLINE_ASM +/* GCC releases before 5.1.0 have a broken bzhi builtin, so for those we + * implement it using inline assembly + */ +#define av_zero_extend av_zero_extend_bmi2 +static av_always_inline av_const unsigned av_zero_extend_bmi2(unsigned a, unsigned p) +{ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (p > 31) abort(); +#endif + if (av_builtin_constant_p(p)) + return a & ((1U << p) - 1); + else { + unsigned x; + __asm__ ("bzhi %2, %1, %0 \n\t" : "=r"(x) : "rm"(a), "r"(p)); + return x; + } +} +#endif /* AV_GCC_VERSION_AT_LEAST */ + +#endif /* __BMI2__ */ + +#endif /* __GNUC__ */ + +#endif /* AVUTIL_X86_INTMATH_H */ diff --git a/libs/ffmpeg/libavutil/x86/intreadwrite.h b/libs/ffmpeg/libavutil/x86/intreadwrite.h new file mode 100644 index 00000000000..c92b75ed124 --- /dev/null +++ b/libs/ffmpeg/libavutil/x86/intreadwrite.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010 Alexander Strange <astrange@ithinksw.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_INTREADWRITE_H +#define AVUTIL_X86_INTREADWRITE_H + +#include <stdint.h> +#include "config.h" +#if HAVE_INTRINSICS_SSE2 && defined(__SSE2__) +#include <emmintrin.h> +#endif +#include "libavutil/attributes.h" + +#if HAVE_INTRINSICS_SSE2 && defined(__SSE2__) + +#define AV_COPY128 AV_COPY128 +static av_always_inline void AV_COPY128(void *d, const void *s) +{ + __m128i tmp = _mm_load_si128((const __m128i *)s); + _mm_store_si128((__m128i *)d, tmp); +} + +#define AV_COPY128U AV_COPY128U +static av_always_inline void AV_COPY128U(void *d, const void *s) +{ + __m128i tmp = _mm_loadu_si128((const __m128i *)s); + _mm_storeu_si128((__m128i *)d, tmp); +} + +#define AV_ZERO128 AV_ZERO128 +static av_always_inline void AV_ZERO128(void *d) +{ + __m128i zero = _mm_setzero_si128(); + _mm_store_si128((__m128i *)d, zero); +} + +#endif /* HAVE_INTRINSICS_SSE2 && defined(__SSE2__) */ + +#endif /* AVUTIL_X86_INTREADWRITE_H */ diff --git a/libs/ffmpeg/libavutil/x86/pixelutils.h b/libs/ffmpeg/libavutil/x86/pixelutils.h new file mode 100644 index 00000000000..876cf46053b --- /dev/null +++ b/libs/ffmpeg/libavutil/x86/pixelutils.h @@ -0,0 +1,26 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_PIXELUTILS_H +#define AVUTIL_X86_PIXELUTILS_H + +#include "libavutil/pixelutils.h" + +void ff_pixelutils_sad_init_x86(av_pixelutils_sad_fn *sad, int aligned); + +#endif /* AVUTIL_X86_PIXELUTILS_H */ diff --git a/libs/ffmpeg/libavutil/x86/timer.h b/libs/ffmpeg/libavutil/x86/timer.h new file mode 100644 index 00000000000..4d1e88def0d --- /dev/null +++ b/libs/ffmpeg/libavutil/x86/timer.h @@ -0,0 +1,50 @@ +/* + * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_X86_TIMER_H +#define AVUTIL_X86_TIMER_H + +#include <stdint.h> + +#if HAVE_INLINE_ASM + +#define FF_TIMER_UNITS "decicycles" +#define AV_READ_TIME read_time + +static inline uint64_t read_time(void) +{ + uint32_t a, d; + __asm__ volatile( +#if ARCH_X86_64 || defined(__SSE2__) + "lfence \n\t" +#endif + "rdtsc \n\t" + : "=a" (a), "=d" (d)); + return ((uint64_t)d << 32) + a; +} + +#elif HAVE_RDTSC + +#include <intrin.h> +#define AV_READ_TIME __rdtsc + +#endif /* HAVE_INLINE_ASM */ + +#endif /* AVUTIL_X86_TIMER_H */ diff --git a/libs/ffmpeg/libavutil/xga_font_data.c b/libs/ffmpeg/libavutil/xga_font_data.c new file mode 100644 index 00000000000..e4b21760f8b --- /dev/null +++ b/libs/ffmpeg/libavutil/xga_font_data.c @@ -0,0 +1,433 @@ +/* + * CGA/EGA/VGA ROM font data + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * CGA/EGA/VGA ROM font data + */ + +#include <stdint.h> +#include "xga_font_data.h" + +#if LIBAVUTIL_VERSION_MAJOR > 60 +static +#endif +const uint8_t avpriv_cga_font[2048] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, + 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c, + 0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, + 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, + 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, + 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0, + 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0, 0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99, + 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, 0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78, + 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff, + 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, + 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, + 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, + 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00, 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00, + 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, + 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00, 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00, + 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00, 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00, + 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00, + 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00, 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00, + 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60, + 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00, 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00, + 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00, + 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, + 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, + 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00, + 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00, + 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00, + 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, + 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00, + 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, + 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, + 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00, + 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, + 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00, + 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00, + 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00, + 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00, + 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, + 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78, 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00, + 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, + 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38, + 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, + 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00, + 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00, 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00, + 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00, 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, + 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00, + 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18, + 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00, 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30, + 0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7, 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70, + 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, + 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00, 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00, + 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, + 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f, + 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00, 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00, + 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, + 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00, 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0, + 0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, + 0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00, + 0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00, + 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00, 0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0, + 0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, + 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00, + 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00, + 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, + 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, + 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c, + 0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const uint8_t *avpriv_cga_font_get(void) +{ + return avpriv_cga_font; +} + +#if LIBAVUTIL_VERSION_MAJOR > 60 +static +#endif +const uint8_t avpriv_vga16_font[4096] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb, 0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, + 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x7e, 0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x66, 0x66, 0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 0x0c, 0x1f, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t *avpriv_vga16_font_get(void) +{ + return avpriv_vga16_font; +} diff --git a/libs/ffmpeg/libavutil/xga_font_data.h b/libs/ffmpeg/libavutil/xga_font_data.h new file mode 100644 index 00000000000..90d3cec4cef --- /dev/null +++ b/libs/ffmpeg/libavutil/xga_font_data.h @@ -0,0 +1,41 @@ +/* + * CGA/EGA/VGA ROM font data + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * CGA/EGA/VGA ROM font data + */ + +#ifndef AVUTIL_XGA_FONT_DATA_H +#define AVUTIL_XGA_FONT_DATA_H + +#include <stdint.h> +#include "internal.h" +#include "version.h" + +#if LIBAVUTIL_VERSION_MAJOR < 61 +extern av_export_avutil const uint8_t avpriv_cga_font[2048]; +extern av_export_avutil const uint8_t avpriv_vga16_font[4096]; +#endif + +const uint8_t *avpriv_cga_font_get(void); +const uint8_t *avpriv_vga16_font_get(void); + +#endif /* AVUTIL_XGA_FONT_DATA_H */ diff --git a/libs/ffmpeg/libavutil/xtea.c b/libs/ffmpeg/libavutil/xtea.c new file mode 100644 index 00000000000..6f376c365c3 --- /dev/null +++ b/libs/ffmpeg/libavutil/xtea.c @@ -0,0 +1,253 @@ +/* + * A 32-bit implementation of the XTEA algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * loosely based on the implementation of David Wheeler and Roger Needham + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @brief XTEA 32-bit implementation + * @author Samuel Pitoiset + * @ingroup lavu_xtea + */ + +#include <string.h> +#include "config.h" +#include "intreadwrite.h" +#include "mem.h" +#include "xtea.h" + +AVXTEA *av_xtea_alloc(void) +{ + return av_mallocz(sizeof(struct AVXTEA)); +} + +void av_xtea_init(AVXTEA *ctx, const uint8_t key[16]) +{ + int i; + + for (i = 0; i < 4; i++) + ctx->key[i] = AV_RB32(key + (i << 2)); +} + +void av_xtea_le_init(AVXTEA *ctx, const uint8_t key[16]) +{ + int i; + + for (i = 0; i < 4; i++) + ctx->key[i] = AV_RL32(key + (i << 2)); +} + +static void xtea_crypt_ecb(AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int decrypt, uint8_t *iv) +{ + uint32_t v0, v1; +#if !CONFIG_SMALL + uint32_t k0 = ctx->key[0]; + uint32_t k1 = ctx->key[1]; + uint32_t k2 = ctx->key[2]; + uint32_t k3 = ctx->key[3]; +#endif + + v0 = AV_RB32(src); + v1 = AV_RB32(src + 4); + + if (decrypt) { +#if CONFIG_SMALL + int i; + uint32_t delta = 0x9E3779B9U, sum = delta * 32; + + for (i = 0; i < 32; i++) { + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + ctx->key[(sum >> 11) & 3]); + sum -= delta; + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + ctx->key[sum & 3]); + } +#else +#define DSTEP(SUM, K0, K1) \ + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (SUM + K0); \ + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (SUM - 0x9E3779B9U + K1) + + DSTEP(0xC6EF3720U, k2, k3); + DSTEP(0x28B7BD67U, k3, k2); + DSTEP(0x8A8043AEU, k0, k1); + DSTEP(0xEC48C9F5U, k1, k0); + DSTEP(0x4E11503CU, k2, k3); + DSTEP(0xAFD9D683U, k2, k2); + DSTEP(0x11A25CCAU, k3, k1); + DSTEP(0x736AE311U, k0, k0); + DSTEP(0xD5336958U, k1, k3); + DSTEP(0x36FBEF9FU, k1, k2); + DSTEP(0x98C475E6U, k2, k1); + DSTEP(0xFA8CFC2DU, k3, k0); + DSTEP(0x5C558274U, k0, k3); + DSTEP(0xBE1E08BBU, k1, k2); + DSTEP(0x1FE68F02U, k1, k1); + DSTEP(0x81AF1549U, k2, k0); + DSTEP(0xE3779B90U, k3, k3); + DSTEP(0x454021D7U, k0, k2); + DSTEP(0xA708A81EU, k1, k1); + DSTEP(0x08D12E65U, k1, k0); + DSTEP(0x6A99B4ACU, k2, k3); + DSTEP(0xCC623AF3U, k3, k2); + DSTEP(0x2E2AC13AU, k0, k1); + DSTEP(0x8FF34781U, k0, k0); + DSTEP(0xF1BBCDC8U, k1, k3); + DSTEP(0x5384540FU, k2, k2); + DSTEP(0xB54CDA56U, k3, k1); + DSTEP(0x1715609DU, k0, k0); + DSTEP(0x78DDE6E4U, k0, k3); + DSTEP(0xDAA66D2BU, k1, k2); + DSTEP(0x3C6EF372U, k2, k1); + DSTEP(0x9E3779B9U, k3, k0); +#endif + if (iv) { + v0 ^= AV_RB32(iv); + v1 ^= AV_RB32(iv + 4); + memcpy(iv, src, 8); + } + } else { +#if CONFIG_SMALL + int i; + uint32_t sum = 0, delta = 0x9E3779B9U; + + for (i = 0; i < 32; i++) { + v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + ctx->key[sum & 3]); + sum += delta; + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + ctx->key[(sum >> 11) & 3]); + } +#else +#define ESTEP(SUM, K0, K1) \ + v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (SUM + K0);\ + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (SUM + 0x9E3779B9U + K1) + ESTEP(0x00000000U, k0, k3); + ESTEP(0x9E3779B9U, k1, k2); + ESTEP(0x3C6EF372U, k2, k1); + ESTEP(0xDAA66D2BU, k3, k0); + ESTEP(0x78DDE6E4U, k0, k0); + ESTEP(0x1715609DU, k1, k3); + ESTEP(0xB54CDA56U, k2, k2); + ESTEP(0x5384540FU, k3, k1); + ESTEP(0xF1BBCDC8U, k0, k0); + ESTEP(0x8FF34781U, k1, k0); + ESTEP(0x2E2AC13AU, k2, k3); + ESTEP(0xCC623AF3U, k3, k2); + ESTEP(0x6A99B4ACU, k0, k1); + ESTEP(0x08D12E65U, k1, k1); + ESTEP(0xA708A81EU, k2, k0); + ESTEP(0x454021D7U, k3, k3); + ESTEP(0xE3779B90U, k0, k2); + ESTEP(0x81AF1549U, k1, k1); + ESTEP(0x1FE68F02U, k2, k1); + ESTEP(0xBE1E08BBU, k3, k0); + ESTEP(0x5C558274U, k0, k3); + ESTEP(0xFA8CFC2DU, k1, k2); + ESTEP(0x98C475E6U, k2, k1); + ESTEP(0x36FBEF9FU, k3, k1); + ESTEP(0xD5336958U, k0, k0); + ESTEP(0x736AE311U, k1, k3); + ESTEP(0x11A25CCAU, k2, k2); + ESTEP(0xAFD9D683U, k3, k2); + ESTEP(0x4E11503CU, k0, k1); + ESTEP(0xEC48C9F5U, k1, k0); + ESTEP(0x8A8043AEU, k2, k3); + ESTEP(0x28B7BD67U, k3, k2); +#endif + } + + AV_WB32(dst, v0); + AV_WB32(dst + 4, v1); +} + +static void xtea_le_crypt_ecb(AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int decrypt, uint8_t *iv) +{ + uint32_t v0, v1; + int i; + + v0 = AV_RL32(src); + v1 = AV_RL32(src + 4); + + if (decrypt) { + uint32_t delta = 0x9E3779B9, sum = delta * 32; + + for (i = 0; i < 32; i++) { + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + ctx->key[(sum >> 11) & 3]); + sum -= delta; + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + ctx->key[sum & 3]); + } + if (iv) { + v0 ^= AV_RL32(iv); + v1 ^= AV_RL32(iv + 4); + memcpy(iv, src, 8); + } + } else { + uint32_t sum = 0, delta = 0x9E3779B9; + + for (i = 0; i < 32; i++) { + v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + ctx->key[sum & 3]); + sum += delta; + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + ctx->key[(sum >> 11) & 3]); + } + } + + AV_WL32(dst, v0); + AV_WL32(dst + 4, v1); +} + +static void xtea_crypt(AVXTEA *ctx, uint8_t *dst, const uint8_t *src, int count, + uint8_t *iv, int decrypt, + void (*crypt)(AVXTEA *, uint8_t *, const uint8_t *, int, uint8_t *)) +{ + int i; + + if (decrypt) { + while (count--) { + crypt(ctx, dst, src, decrypt, iv); + + src += 8; + dst += 8; + } + } else { + while (count--) { + if (iv) { + for (i = 0; i < 8; i++) + dst[i] = src[i] ^ iv[i]; + crypt(ctx, dst, dst, decrypt, NULL); + memcpy(iv, dst, 8); + } else { + crypt(ctx, dst, src, decrypt, NULL); + } + src += 8; + dst += 8; + } + } +} + +void av_xtea_crypt(AVXTEA *ctx, uint8_t *dst, const uint8_t *src, int count, + uint8_t *iv, int decrypt) +{ + xtea_crypt(ctx, dst, src, count, iv, decrypt, xtea_crypt_ecb); +} + +void av_xtea_le_crypt(AVXTEA *ctx, uint8_t *dst, const uint8_t *src, int count, + uint8_t *iv, int decrypt) +{ + xtea_crypt(ctx, dst, src, count, iv, decrypt, xtea_le_crypt_ecb); +} diff --git a/libs/ffmpeg/libavutil/xtea.h b/libs/ffmpeg/libavutil/xtea.h new file mode 100644 index 00000000000..735427c109a --- /dev/null +++ b/libs/ffmpeg/libavutil/xtea.h @@ -0,0 +1,94 @@ +/* + * A 32-bit implementation of the XTEA algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_XTEA_H +#define AVUTIL_XTEA_H + +#include <stdint.h> + +/** + * @file + * @brief Public header for libavutil XTEA algorithm + * @defgroup lavu_xtea XTEA + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVXTEA { + uint32_t key[16]; +} AVXTEA; + +/** + * Allocate an AVXTEA context. + */ +AVXTEA *av_xtea_alloc(void); + +/** + * Initialize an AVXTEA context. + * + * @param ctx an AVXTEA context + * @param key a key of 16 bytes used for encryption/decryption, + * interpreted as big endian 32 bit numbers + */ +void av_xtea_init(struct AVXTEA *ctx, const uint8_t key[16]); + +/** + * Initialize an AVXTEA context. + * + * @param ctx an AVXTEA context + * @param key a key of 16 bytes used for encryption/decryption, + * interpreted as little endian 32 bit numbers + */ +void av_xtea_le_init(struct AVXTEA *ctx, const uint8_t key[16]); + +/** + * Encrypt or decrypt a buffer using a previously initialized context, + * in big endian format. + * + * @param ctx an AVXTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_xtea_crypt(struct AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context, + * in little endian format. + * + * @param ctx an AVXTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_xtea_le_crypt(struct AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_XTEA_H */ diff --git a/libs/ffmpeg/libswresample/audioconvert.c b/libs/ffmpeg/libswresample/audioconvert.c new file mode 100644 index 00000000000..f8bac98ca56 --- /dev/null +++ b/libs/ffmpeg/libswresample/audioconvert.c @@ -0,0 +1,251 @@ +/* + * audio conversion + * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * audio conversion + * @author Michael Niedermayer <michaelni@gmx.at> + */ + +#include "libavutil/avassert.h" +#include "libavutil/libm.h" +#include "libavutil/mem.h" +#include "libavutil/samplefmt.h" +#include "audioconvert.h" + + +#define CONV_FUNC_NAME(dst_fmt, src_fmt) conv_ ## src_fmt ## _to_ ## dst_fmt + +//FIXME rounding ? +#define CONV_FUNC(ofmt, otype, ifmt, expr)\ +static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end)\ +{\ + uint8_t *end2 = end - 3*os;\ + while(po < end2){\ + *(otype*)po = expr; pi += is; po += os;\ + *(otype*)po = expr; pi += is; po += os;\ + *(otype*)po = expr; pi += is; po += os;\ + *(otype*)po = expr; pi += is; po += os;\ + }\ + while(po < end){\ + *(otype*)po = expr; pi += is; po += os;\ + }\ +} + +//FIXME put things below under ifdefs so we do not waste space for cases no codec will need +CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_U8 , *(const uint8_t*)pi) +CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80U)<<8) +CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80U)<<24) +CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_U8 , (uint64_t)((*(const uint8_t*)pi - 0x80U))<<56) +CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0f/ (1<<7))) +CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7))) +CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S16, (*(const int16_t*)pi>>8) + 0x80) +CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi) +CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi * (1 << 16)) +CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S16, (uint64_t)(*(const int16_t*)pi)<<48) +CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0f/ (1<<15))) +CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15))) +CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S32, (*(const int32_t*)pi>>24) + 0x80) +CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi>>16) +CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi) +CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S32, (uint64_t)(*(const int32_t*)pi)<<32) +CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0f/ (1U<<31))) +CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31))) +CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S64, (*(const int64_t*)pi>>56) + 0x80) +CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S64, *(const int64_t*)pi>>48) +CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S64, *(const int64_t*)pi>>32) +CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_S64, *(const int64_t*)pi) +CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S64, *(const int64_t*)pi*(1.0f/ (UINT64_C(1)<<63))) +CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S64, *(const int64_t*)pi*(1.0 / (UINT64_C(1)<<63))) +CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8( lrintf(*(const float*)pi * (1<<7)) + 0x80)) +CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16( lrintf(*(const float*)pi * (1<<15)))) +CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float*)pi * (1U<<31)))) +CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_FLT, llrintf(*(const float*)pi * (UINT64_C(1)<<63))) +CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_FLT, *(const float*)pi) +CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_FLT, *(const float*)pi) +CONV_FUNC(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8( lrint(*(const double*)pi * (1<<7)) + 0x80)) +CONV_FUNC(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16( lrint(*(const double*)pi * (1<<15)))) +CONV_FUNC(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double*)pi * (1U<<31)))) +CONV_FUNC(AV_SAMPLE_FMT_S64, int64_t, AV_SAMPLE_FMT_DBL, llrint(*(const double*)pi * (UINT64_C(1)<<63))) +CONV_FUNC(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_DBL, *(const double*)pi) +CONV_FUNC(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_DBL, *(const double*)pi) + +#define FMT_PAIR_FUNC(out, in) [(out) + AV_SAMPLE_FMT_NB*(in)] = CONV_FUNC_NAME(out, in) + +static conv_func_type * const fmt_pair_to_conv_functions[AV_SAMPLE_FMT_NB*AV_SAMPLE_FMT_NB] = { + FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_U8 ), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8 ), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8 ), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8 ), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8 ), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_U8 ), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_S16), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S16), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_S32), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S32), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_FLT), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_FLT), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_DBL), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_DBL), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_U8 , AV_SAMPLE_FMT_S64), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S64), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S64), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S64), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S64), + FMT_PAIR_FUNC(AV_SAMPLE_FMT_S64, AV_SAMPLE_FMT_S64), +}; + +static void cpy1(uint8_t **dst, const uint8_t **src, int len){ + memcpy(*dst, *src, len); +} +static void cpy2(uint8_t **dst, const uint8_t **src, int len){ + memcpy(*dst, *src, 2*len); +} +static void cpy4(uint8_t **dst, const uint8_t **src, int len){ + memcpy(*dst, *src, 4*len); +} +static void cpy8(uint8_t **dst, const uint8_t **src, int len){ + memcpy(*dst, *src, 8*len); +} + +AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, + enum AVSampleFormat in_fmt, + int channels, const int *ch_map, + int flags) +{ + AudioConvert *ctx; + conv_func_type *f = fmt_pair_to_conv_functions[av_get_packed_sample_fmt(out_fmt) + AV_SAMPLE_FMT_NB*av_get_packed_sample_fmt(in_fmt)]; + + if (!f) + return NULL; + ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return NULL; + + if(channels == 1){ + in_fmt = av_get_planar_sample_fmt( in_fmt); + out_fmt = av_get_planar_sample_fmt(out_fmt); + } + + ctx->channels = channels; + ctx->conv_f = f; + ctx->ch_map = ch_map; + if (in_fmt == AV_SAMPLE_FMT_U8 || in_fmt == AV_SAMPLE_FMT_U8P) + memset(ctx->silence, 0x80, sizeof(ctx->silence)); + + if(out_fmt == in_fmt && !ch_map) { + switch(av_get_bytes_per_sample(in_fmt)){ + case 1:ctx->simd_f = cpy1; break; + case 2:ctx->simd_f = cpy2; break; + case 4:ctx->simd_f = cpy4; break; + case 8:ctx->simd_f = cpy8; break; + } + } + +#if ARCH_X86 && HAVE_X86ASM + swri_audio_convert_init_x86(ctx, out_fmt, in_fmt, channels); +#elif ARCH_ARM + swri_audio_convert_init_arm(ctx, out_fmt, in_fmt, channels); +#elif ARCH_AARCH64 + swri_audio_convert_init_aarch64(ctx, out_fmt, in_fmt, channels); +#endif + + return ctx; +} + +void swri_audio_convert_free(AudioConvert **ctx) +{ + av_freep(ctx); +} + +int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len) +{ + int ch; + int off=0; + const int os= (out->planar ? 1 :out->ch_count) *out->bps; + unsigned misaligned = 0; + + av_assert0(ctx->channels == out->ch_count); + + if (ctx->in_simd_align_mask) { + int planes = in->planar ? in->ch_count : 1; + unsigned m = 0; + for (ch = 0; ch < planes; ch++) + m |= (intptr_t)in->ch[ch]; + misaligned |= m & ctx->in_simd_align_mask; + } + if (ctx->out_simd_align_mask) { + int planes = out->planar ? out->ch_count : 1; + unsigned m = 0; + for (ch = 0; ch < planes; ch++) + m |= (intptr_t)out->ch[ch]; + misaligned |= m & ctx->out_simd_align_mask; + } + + //FIXME optimize common cases + + if(ctx->simd_f && !ctx->ch_map && !misaligned){ + off = len&~15; + av_assert1(off>=0); + av_assert1(off<=len); + av_assert2(ctx->channels == SWR_CH_MAX || !in->ch[ctx->channels]); + if(off>0){ + if(out->planar == in->planar){ + int planes = out->planar ? out->ch_count : 1; + for(ch=0; ch<planes; ch++){ + ctx->simd_f(out->ch+ch, (const uint8_t **)in->ch+ch, off * (out->planar ? 1 :out->ch_count)); + } + }else{ + ctx->simd_f(out->ch, (const uint8_t **)in->ch, off); + } + } + if(off == len) + return 0; + } + + for(ch=0; ch<ctx->channels; ch++){ + const int ich= ctx->ch_map ? ctx->ch_map[ch] : ch; + const int is= ich < 0 ? 0 : (in->planar ? 1 : in->ch_count) * in->bps; + const uint8_t *pi= ich < 0 ? ctx->silence : in->ch[ich]; + uint8_t *end, *po = out->ch[ch]; + if(!po) + continue; + end = po + os * len; + ctx->conv_f(po+off*os, pi+off*is, is, os, end); + } + return 0; +} diff --git a/libs/ffmpeg/libswresample/audioconvert.h b/libs/ffmpeg/libswresample/audioconvert.h new file mode 100644 index 00000000000..bb143a876de --- /dev/null +++ b/libs/ffmpeg/libswresample/audioconvert.h @@ -0,0 +1,77 @@ +/* + * audio conversion + * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> + * Copyright (c) 2008 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWRESAMPLE_AUDIOCONVERT_H +#define SWRESAMPLE_AUDIOCONVERT_H + +/** + * @file + * Audio format conversion routines + */ + + +#include "swresample_internal.h" + + +typedef void (conv_func_type)(uint8_t *po, const uint8_t *pi, int is, int os, uint8_t *end); +typedef void (simd_func_type)(uint8_t **dst, const uint8_t **src, int len); + +typedef struct AudioConvert { + int channels; + int in_simd_align_mask; + int out_simd_align_mask; + conv_func_type *conv_f; + simd_func_type *simd_f; + const int *ch_map; + uint8_t silence[8]; ///< silence input sample +}AudioConvert; + +/** + * Create an audio sample format converter context + * @param out_fmt Output sample format + * @param in_fmt Input sample format + * @param channels Number of channels + * @param flags See AV_CPU_FLAG_xx + * @param ch_map list of the channels id to pick from the source stream, NULL + * if all channels must be selected + * @return NULL on error + */ +AudioConvert *swri_audio_convert_alloc(enum AVSampleFormat out_fmt, + enum AVSampleFormat in_fmt, + int channels, const int *ch_map, + int flags); + +/** + * Free audio sample format converter context. + * and set the pointer to NULL + */ +void swri_audio_convert_free(AudioConvert **ctx); + +/** + * Convert between audio sample formats + * @param[in] out array of output buffers for each channel. set to NULL to ignore processing of the given channel. + * @param[in] in array of input buffers for each channel + * @param len length of audio frame size (measured in samples) + */ +int swri_audio_convert(AudioConvert *ctx, AudioData *out, AudioData *in, int len); + +#endif /* SWRESAMPLE_AUDIOCONVERT_H */ diff --git a/libs/ffmpeg/libswresample/dither.c b/libs/ffmpeg/libswresample/dither.c new file mode 100644 index 00000000000..61151a26ea4 --- /dev/null +++ b/libs/ffmpeg/libswresample/dither.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2012-2013 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/mem.h" +#include "swresample_internal.h" + +#include "noise_shaping_data.c" + +int swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSampleFormat noise_fmt) { + double scale = s->dither.noise_scale; +#define TMP_EXTRA 2 + double *tmp = av_malloc_array(len + TMP_EXTRA, sizeof(double)); + int i; + + if (!tmp) + return AVERROR(ENOMEM); + + for(i=0; i<len + TMP_EXTRA; i++){ + double v; + seed = seed* 1664525 + 1013904223; + + switch(s->dither.method){ + case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break; + default: + av_assert0(s->dither.method < SWR_DITHER_NB); + v = ((double)seed) / UINT_MAX; + seed = seed*1664525 + 1013904223; + v-= ((double)seed) / UINT_MAX; + break; + } + tmp[i] = v; + } + + for(i=0; i<len; i++){ + double v; + + switch(s->dither.method){ + default: + av_assert0(s->dither.method < SWR_DITHER_NB); + v = tmp[i]; + break; + case SWR_DITHER_TRIANGULAR_HIGHPASS : + v = (- tmp[i] + 2*tmp[i+1] - tmp[i+2]) / sqrt(6); + break; + } + + v*= scale; + + switch(noise_fmt){ + case AV_SAMPLE_FMT_S16P: ((int16_t*)dst)[i] = v; break; + case AV_SAMPLE_FMT_S32P: ((int32_t*)dst)[i] = v; break; + case AV_SAMPLE_FMT_FLTP: ((float *)dst)[i] = v; break; + case AV_SAMPLE_FMT_DBLP: ((double *)dst)[i] = v; break; + default: av_assert0(0); + } + } + + av_free(tmp); + return 0; +} + +av_cold int swri_dither_init(SwrContext *s, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt) +{ + int i; + double scale = 0; + + if (s->dither.method > SWR_DITHER_TRIANGULAR_HIGHPASS && s->dither.method <= SWR_DITHER_NS) + return AVERROR(EINVAL); + + out_fmt = av_get_packed_sample_fmt(out_fmt); + in_fmt = av_get_packed_sample_fmt( in_fmt); + + if(in_fmt == AV_SAMPLE_FMT_FLT || in_fmt == AV_SAMPLE_FMT_DBL){ + if(out_fmt == AV_SAMPLE_FMT_S32) scale = 1.0/(1LL<<31); + if(out_fmt == AV_SAMPLE_FMT_S16) scale = 1.0/(1LL<<15); + if(out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1.0/(1LL<< 7); + } + if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S32 && (s->dither.output_sample_bits&31)) scale = 1; + if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_S16) scale = 1<<16; + if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1<<24; + if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1<<8; + + scale *= s->dither.scale; + + if (out_fmt == AV_SAMPLE_FMT_S32 && s->dither.output_sample_bits) + scale *= 1<<(32-s->dither.output_sample_bits); + + if (scale == 0) { + s->dither.method = 0; + return 0; + } + + s->dither.ns_pos = 0; + s->dither.noise_scale= scale; + s->dither.ns_scale = scale; + s->dither.ns_scale_1 = scale ? 1/scale : 0; + memset(s->dither.ns_errors, 0, sizeof(s->dither.ns_errors)); + for (i=0; filters[i].coefs; i++) { + const filter_t *f = &filters[i]; + if (llabs(s->out_sample_rate - f->rate)*20 <= f->rate && f->name == s->dither.method) { + int j; + s->dither.ns_taps = f->len; + for (j=0; j<f->len; j++) + s->dither.ns_coeffs[j] = f->coefs[j]; + s->dither.ns_scale_1 *= 1 - exp(f->gain_cB * M_LN10 * 0.005) * 2 / (1<<(8*av_get_bytes_per_sample(out_fmt))); + break; + } + } + if (!filters[i].coefs && s->dither.method > SWR_DITHER_NS) { + av_log(s, AV_LOG_WARNING, "Requested noise shaping dither not available at this sampling rate, using triangular hp dither\n"); + s->dither.method = SWR_DITHER_TRIANGULAR_HIGHPASS; + } + + return 0; +} + +#define TEMPLATE_DITHER_S16 +#include "dither_template.c" +#undef TEMPLATE_DITHER_S16 + +#define TEMPLATE_DITHER_S32 +#include "dither_template.c" +#undef TEMPLATE_DITHER_S32 + +#define TEMPLATE_DITHER_FLT +#include "dither_template.c" +#undef TEMPLATE_DITHER_FLT + +#define TEMPLATE_DITHER_DBL +#include "dither_template.c" +#undef TEMPLATE_DITHER_DBL diff --git a/libs/ffmpeg/libswresample/dither_template.c b/libs/ffmpeg/libswresample/dither_template.c new file mode 100644 index 00000000000..947eb717a41 --- /dev/null +++ b/libs/ffmpeg/libswresample/dither_template.c @@ -0,0 +1,88 @@ +/* + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if 0 +#pragma makedep header +#endif + +#if defined(TEMPLATE_DITHER_DBL) +# define RENAME(N) N ## _double +# define DELEM double +# define CLIP(v) while(0) + +#elif defined(TEMPLATE_DITHER_FLT) +# define RENAME(N) N ## _float +# define DELEM float +# define CLIP(v) while(0) + +#elif defined(TEMPLATE_DITHER_S32) +# define RENAME(N) N ## _int32 +# define DELEM int32_t +# define CLIP(v) v = FFMAX(FFMIN(v, INT32_MAX), INT32_MIN) + +#elif defined(TEMPLATE_DITHER_S16) +# define RENAME(N) N ## _int16 +# define DELEM int16_t +# define CLIP(v) v = FFMAX(FFMIN(v, INT16_MAX), INT16_MIN) + +#else +ERROR +#endif + +void RENAME(swri_noise_shaping)(SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count){ + int pos = s->dither.ns_pos; + int i, j, ch; + int taps = s->dither.ns_taps; + float S = s->dither.ns_scale; + float S_1 = s->dither.ns_scale_1; + + av_assert2((taps&3) != 2); + av_assert2((taps&3) != 3 || s->dither.ns_coeffs[taps] == 0); + + for (ch=0; ch<srcs->ch_count; ch++) { + const float *noise = ((const float *)noises->ch[ch]) + s->dither.noise_pos; + const DELEM *src = (const DELEM*)srcs->ch[ch]; + DELEM *dst = (DELEM*)dsts->ch[ch]; + float *ns_errors = s->dither.ns_errors[ch]; + const float *ns_coeffs = s->dither.ns_coeffs; + pos = s->dither.ns_pos; + for (i=0; i<count; i++) { + double d1, d = src[i]*S_1; + for(j=0; j<taps-2; j+=4) { + d -= ns_coeffs[j ] * ns_errors[pos + j ] + +ns_coeffs[j + 1] * ns_errors[pos + j + 1] + +ns_coeffs[j + 2] * ns_errors[pos + j + 2] + +ns_coeffs[j + 3] * ns_errors[pos + j + 3]; + } + if(j < taps) + d -= ns_coeffs[j] * ns_errors[pos + j]; + pos = pos ? pos - 1 : taps - 1; + d1 = rint(d + noise[i]); + ns_errors[pos + taps] = ns_errors[pos] = d1 - d; + d1 *= S; + CLIP(d1); + dst[i] = d1; + } + } + + s->dither.ns_pos = pos; +} + +#undef RENAME +#undef DELEM +#undef CLIP diff --git a/libs/ffmpeg/libswresample/log2_tab.c b/libs/ffmpeg/libswresample/log2_tab.c new file mode 100644 index 00000000000..47a1df03b74 --- /dev/null +++ b/libs/ffmpeg/libswresample/log2_tab.c @@ -0,0 +1 @@ +#include "libavutil/log2_tab.c" diff --git a/libs/ffmpeg/libswresample/noise_shaping_data.c b/libs/ffmpeg/libswresample/noise_shaping_data.c new file mode 100644 index 00000000000..ef9db8a56ea --- /dev/null +++ b/libs/ffmpeg/libswresample/noise_shaping_data.c @@ -0,0 +1,224 @@ +/* Effect: dither/noise-shape Copyright (c) 2008-9 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if 0 +#pragma makedep header +#endif + +typedef struct { + int rate; + enum {fir, iir} type; + size_t len; + int gain_cB; /* Chosen so clips are few if any, but not guaranteed none. */ + double const * coefs; + enum SwrDitherType name; +} filter_t; + +static double const lip44[] = {2.033, -2.165, 1.959, -1.590, .6149}; +static double const fwe44[] = { + 2.412, -3.370, 3.937, -4.174, 3.353, -2.205, 1.281, -.569, .0847}; +static double const mew44[] = { + 1.662, -1.263, .4827, -.2913, .1268, -.1124, .03252, -.01265, -.03524}; +static double const iew44[] = { + 2.847, -4.685, 6.214, -7.184, 6.639, -5.032, 3.263, -1.632, .4191}; + +static double const shi48[] = { + 2.8720729351043701172, -5.0413231849670410156, 6.2442994117736816406, + -5.8483986854553222656, 3.7067542076110839844, -1.0495119094848632812, + -1.1830236911773681641, 2.1126792430877685547, -1.9094531536102294922, + 0.99913084506988525391, -0.17090806365013122559, -0.32615602016448974609, + 0.39127644896507263184, -0.26876461505889892578, 0.097676105797290802002, + -0.023473845794796943665, +}; +static double const shi44[] = { + 2.6773197650909423828, -4.8308925628662109375, 6.570110321044921875, + -7.4572014808654785156, 6.7263274192810058594, -4.8481650352478027344, + 2.0412089824676513672, 0.7006359100341796875, -2.9537565708160400391, + 4.0800385475158691406, -4.1845216751098632812, 3.3311812877655029297, + -2.1179926395416259766, 0.879302978515625, -0.031759146600961685181, + -0.42382788658142089844, 0.47882103919982910156, -0.35490813851356506348, + 0.17496839165687561035, -0.060908168554306030273, +}; +static double const shi38[] = { + 1.6335992813110351562, -2.2615492343902587891, 2.4077029228210449219, + -2.6341717243194580078, 2.1440362930297851562, -1.8153258562088012695, + 1.0816224813461303711, -0.70302653312683105469, 0.15991993248462677002, + 0.041549518704414367676, -0.29416576027870178223, 0.2518316805362701416, + -0.27766478061676025391, 0.15785403549671173096, -0.10165894031524658203, + 0.016833892092108726501, +}; +static double const shi32[] = +{ /* dmaker 32000: bestmax=4.99659 (inverted) */ +0.82118552923202515, +-1.0063692331314087, +0.62341964244842529, +-1.0447187423706055, +0.64532512426376343, +-0.87615132331848145, +0.52219754457473755, +-0.67434263229370117, +0.44954317808151245, +-0.52557498216629028, +0.34567299485206604, +-0.39618203043937683, +0.26791760325431824, +-0.28936097025871277, +0.1883765310049057, +-0.19097308814525604, +0.10431359708309174, +-0.10633844882249832, +0.046832218766212463, +-0.039653312414884567, +}; +static double const shi22[] = +{ /* dmaker 22050: bestmax=5.77762 (inverted) */ +0.056581053882837296, +-0.56956905126571655, +-0.40727734565734863, +-0.33870288729667664, +-0.29810553789138794, +-0.19039161503314972, +-0.16510021686553955, +-0.13468159735202789, +-0.096633769571781158, +-0.081049129366874695, +-0.064953058958053589, +-0.054459091275930405, +-0.043378707021474838, +-0.03660014271736145, +-0.026256965473294258, +-0.018786206841468811, +-0.013387725688517094, +-0.0090983230620622635, +-0.0026585909072309732, +-0.00042083300650119781, +}; +static double const shi16[] = +{ /* dmaker 16000: bestmax=5.97128 (inverted) */ +-0.37251132726669312, +-0.81423574686050415, +-0.55010956525802612, +-0.47405767440795898, +-0.32624706625938416, +-0.3161766529083252, +-0.2286367267370224, +-0.22916607558727264, +-0.19565616548061371, +-0.18160104751586914, +-0.15423151850700378, +-0.14104481041431427, +-0.11844276636838913, +-0.097583092749118805, +-0.076493598520755768, +-0.068106919527053833, +-0.041881654411554337, +-0.036922425031661987, +-0.019364040344953537, +-0.014994367957115173, +}; +static double const shi11[] = +{ /* dmaker 11025: bestmax=5.9406 (inverted) */ +-0.9264228343963623, +-0.98695987462997437, +-0.631156325340271, +-0.51966935396194458, +-0.39738872647285461, +-0.35679301619529724, +-0.29720726609230042, +-0.26310476660728455, +-0.21719355881214142, +-0.18561814725399017, +-0.15404847264289856, +-0.12687471508979797, +-0.10339745879173279, +-0.083688631653785706, +-0.05875682458281517, +-0.046893671154975891, +-0.027950936928391457, +-0.020740609616041183, +-0.009366452693939209, +-0.0060260160826146603, +}; +static double const shi08[] = +{ /* dmaker 8000: bestmax=5.56234 (inverted) */ +-1.202863335609436, +-0.94103097915649414, +-0.67878556251525879, +-0.57650017738342285, +-0.50004476308822632, +-0.44349345564842224, +-0.37833768129348755, +-0.34028723835945129, +-0.29413089156150818, +-0.24994957447052002, +-0.21715600788593292, +-0.18792112171649933, +-0.15268312394618988, +-0.12135542929172516, +-0.099610626697540283, +-0.075273610651493073, +-0.048787496984004974, +-0.042586319148540497, +-0.028991291299462318, +-0.011869125068187714, +}; +static double const shl48[] = { + 2.3925774097442626953, -3.4350297451019287109, 3.1853709220886230469, + -1.8117271661758422852, -0.20124770700931549072, 1.4759907722473144531, + -1.7210904359817504883, 0.97746700048446655273, -0.13790138065814971924, + -0.38185903429985046387, 0.27421241998672485352, 0.066584214568138122559, + -0.35223302245140075684, 0.37672343850135803223, -0.23964276909828186035, + 0.068674825131893157959, +}; +static double const shl44[] = { + 2.0833916664123535156, -3.0418450832366943359, 3.2047898769378662109, + -2.7571926116943359375, 1.4978630542755126953, -0.3427594602108001709, + -0.71733748912811279297, 1.0737057924270629883, -1.0225815773010253906, + 0.56649994850158691406, -0.20968692004680633545, -0.065378531813621520996, + 0.10322438180446624756, -0.067442022264003753662, -0.00495197344571352005, + 0, +}; +static double const shh44[] = { + 3.0259189605712890625, -6.0268716812133789062, 9.195003509521484375, + -11.824929237365722656, 12.767142295837402344, -11.917946815490722656, + 9.1739168167114257812, -5.3712320327758789062, 1.1393624544143676758, + 2.4484779834747314453, -4.9719839096069335938, 6.0392003059387207031, + -5.9359521865844726562, 4.903278350830078125, -3.5527443885803222656, + 2.1909697055816650391, -1.1672389507293701172, 0.4903914332389831543, + -0.16519790887832641602, 0.023217858746647834778, +}; + +static const filter_t filters[] = { + {44100, fir, 5, 210, lip44, SWR_DITHER_NS_LIPSHITZ}, + {46000, fir, 9, 276, fwe44, SWR_DITHER_NS_F_WEIGHTED}, + {46000, fir, 9, 160, mew44, SWR_DITHER_NS_MODIFIED_E_WEIGHTED}, + {46000, fir, 9, 321, iew44, SWR_DITHER_NS_IMPROVED_E_WEIGHTED}, +// {48000, iir, 4, 220, ges48, SWR_DITHER_NS_GESEMANN}, +// {44100, iir, 4, 230, ges44, SWR_DITHER_NS_GESEMANN}, + {48000, fir, 16, 301, shi48, SWR_DITHER_NS_SHIBATA}, + {44100, fir, 20, 333, shi44, SWR_DITHER_NS_SHIBATA}, + {37800, fir, 16, 240, shi38, SWR_DITHER_NS_SHIBATA}, + {32000, fir, 20, 240/*TBD*/, shi32, SWR_DITHER_NS_SHIBATA}, + {22050, fir, 20, 240/*TBD*/, shi22, SWR_DITHER_NS_SHIBATA}, + {16000, fir, 20, 240/*TBD*/, shi16, SWR_DITHER_NS_SHIBATA}, + {11025, fir, 20, 240/*TBD*/, shi11, SWR_DITHER_NS_SHIBATA}, + { 8000, fir, 20, 240/*TBD*/, shi08, SWR_DITHER_NS_SHIBATA}, + {48000, fir, 16, 250, shl48, SWR_DITHER_NS_LOW_SHIBATA}, + {44100, fir, 15, 250, shl44, SWR_DITHER_NS_LOW_SHIBATA}, + {44100, fir, 20, 383, shh44, SWR_DITHER_NS_HIGH_SHIBATA}, + { 0, fir, 0, 0, NULL, SWR_DITHER_NONE}, +}; diff --git a/libs/ffmpeg/libswresample/options.c b/libs/ffmpeg/libswresample/options.c new file mode 100644 index 00000000000..11b2884e3c5 --- /dev/null +++ b/libs/ffmpeg/libswresample/options.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/channel_layout.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "swresample_internal.h" + +#include <float.h> + +#define C30DB M_SQRT2 +#define C15DB 1.189207115 +#define C__0DB 1.0 +#define C_15DB 0.840896415 +#define C_30DB M_SQRT1_2 +#define C_45DB 0.594603558 +#define C_60DB 0.5 + +#define OFFSET(x) offsetof(SwrContext,x) +#define PARAM AV_OPT_FLAG_AUDIO_PARAM +#define DEPREC AV_OPT_FLAG_DEPRECATED + +static const AVOption options[]={ +{"isr" , "set input sample rate" , OFFSET( in_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM}, +{"in_sample_rate" , "set input sample rate" , OFFSET( in_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM}, +{"osr" , "set output sample rate" , OFFSET(out_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM}, +{"out_sample_rate" , "set output sample rate" , OFFSET(out_sample_rate), AV_OPT_TYPE_INT , {.i64=0 }, 0 , INT_MAX , PARAM}, +{"isf" , "set input sample format" , OFFSET( in_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM}, +{"in_sample_fmt" , "set input sample format" , OFFSET( in_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM}, +{"osf" , "set output sample format" , OFFSET(out_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM}, +{"out_sample_fmt" , "set output sample format" , OFFSET(out_sample_fmt ), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM}, +{"tsf" , "set internal sample format" , OFFSET(user_int_sample_fmt), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM}, +{"internal_sample_fmt" , "set internal sample format" , OFFSET(user_int_sample_fmt), AV_OPT_TYPE_SAMPLE_FMT , {.i64=AV_SAMPLE_FMT_NONE}, -1 , INT_MAX, PARAM}, +{"ichl" , "set input channel layout" , OFFSET(user_in_chlayout ), AV_OPT_TYPE_CHLAYOUT, {.str=NULL }, 0, 0 , PARAM, .unit = "chlayout"}, +{"in_chlayout" , "set input channel layout" , OFFSET(user_in_chlayout ), AV_OPT_TYPE_CHLAYOUT, {.str=NULL }, 0, 0 , PARAM, .unit = "chlayout"}, +{"ochl" , "set output channel layout" , OFFSET(user_out_chlayout), AV_OPT_TYPE_CHLAYOUT, {.str=NULL }, 0, 0 , PARAM, .unit = "chlayout"}, +{"out_chlayout" , "set output channel layout" , OFFSET(user_out_chlayout), AV_OPT_TYPE_CHLAYOUT, {.str=NULL }, 0, 0 , PARAM, .unit = "chlayout"}, +{"uchl" , "set used channel layout" , OFFSET(user_used_chlayout), AV_OPT_TYPE_CHLAYOUT, {.str=NULL }, 0, 0 , PARAM, .unit = "chlayout"}, +{"used_chlayout" , "set used channel layout" , OFFSET(user_used_chlayout), AV_OPT_TYPE_CHLAYOUT, {.str=NULL }, 0, 0 , PARAM, .unit = "chlayout"}, +{"clev" , "set center mix level" , OFFSET(clev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM}, +{"center_mix_level" , "set center mix level" , OFFSET(clev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM}, +{"slev" , "set surround mix level" , OFFSET(slev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM}, +{"surround_mix_level" , "set surround mix Level" , OFFSET(slev ), AV_OPT_TYPE_FLOAT, {.dbl=C_30DB }, -32 , 32 , PARAM}, +{"lfe_mix_level" , "set LFE mix level" , OFFSET(lfe_mix_level ), AV_OPT_TYPE_FLOAT, {.dbl=0 }, -32 , 32 , PARAM}, +{"rmvol" , "set rematrix volume" , OFFSET(rematrix_volume), AV_OPT_TYPE_FLOAT, {.dbl=1.0 }, -1000 , 1000 , PARAM}, +{"rematrix_volume" , "set rematrix volume" , OFFSET(rematrix_volume), AV_OPT_TYPE_FLOAT, {.dbl=1.0 }, -1000 , 1000 , PARAM}, +{"rematrix_maxval" , "set rematrix maxval" , OFFSET(rematrix_maxval), AV_OPT_TYPE_FLOAT, {.dbl=0.0 }, 0 , 1000 , PARAM}, + +{"flags" , "set flags" , OFFSET(flags ), AV_OPT_TYPE_FLAGS, {.i64=0 }, 0 , UINT_MAX , PARAM, .unit = "flags"}, +{"swr_flags" , "set flags" , OFFSET(flags ), AV_OPT_TYPE_FLAGS, {.i64=0 }, 0 , UINT_MAX , PARAM, .unit = "flags"}, +{"res" , "force resampling" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_FLAG_RESAMPLE }, INT_MIN, INT_MAX , PARAM, .unit = "flags"}, + +{"dither_scale" , "set dither scale" , OFFSET(dither.scale ), AV_OPT_TYPE_FLOAT, {.dbl=1 }, 0 , INT_MAX , PARAM}, + +{"dither_method" , "set dither method" , OFFSET(user_dither_method),AV_OPT_TYPE_INT, {.i64=0 }, 0 , SWR_DITHER_NB-1, PARAM, .unit = "dither_method"}, +{"rectangular" , "select rectangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_RECTANGULAR}, INT_MIN, INT_MAX , PARAM, .unit = "dither_method"}, +{"triangular" , "select triangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR }, INT_MIN, INT_MAX , PARAM, .unit = "dither_method"}, +{"triangular_hp" , "select triangular dither with high pass" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR_HIGHPASS }, INT_MIN, INT_MAX, PARAM, .unit = "dither_method"}, +{"lipshitz" , "select Lipshitz noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_LIPSHITZ}, INT_MIN, INT_MAX, PARAM, .unit = "dither_method"}, +{"shibata" , "select Shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_SHIBATA }, INT_MIN, INT_MAX, PARAM, .unit = "dither_method"}, +{"low_shibata" , "select low Shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_LOW_SHIBATA }, INT_MIN, INT_MAX, PARAM, .unit = "dither_method"}, +{"high_shibata" , "select high Shibata noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_HIGH_SHIBATA }, INT_MIN, INT_MAX, PARAM, .unit = "dither_method"}, +{"f_weighted" , "select f-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_F_WEIGHTED }, INT_MIN, INT_MAX, PARAM, .unit = "dither_method"}, +{"modified_e_weighted" , "select modified-e-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_MODIFIED_E_WEIGHTED }, INT_MIN, INT_MAX, PARAM, .unit = "dither_method"}, +{"improved_e_weighted" , "select improved-e-weighted noise shaping dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_NS_IMPROVED_E_WEIGHTED }, INT_MIN, INT_MAX, PARAM, .unit = "dither_method"}, + +{"filter_size" , "set swr resampling filter size", OFFSET(filter_size) , AV_OPT_TYPE_INT , {.i64=32 }, 0 , INT_MAX , PARAM }, +{"phase_shift" , "set swr resampling phase shift", OFFSET(phase_shift) , AV_OPT_TYPE_INT , {.i64=10 }, 0 , 24 , PARAM }, +{"linear_interp" , "enable linear interpolation" , OFFSET(linear_interp) , AV_OPT_TYPE_BOOL , {.i64=1 }, 0 , 1 , PARAM }, +{"exact_rational" , "enable exact rational" , OFFSET(exact_rational) , AV_OPT_TYPE_BOOL , {.i64=1 }, 0 , 1 , PARAM }, +{"cutoff" , "set cutoff frequency ratio" , OFFSET(cutoff) , AV_OPT_TYPE_DOUBLE,{.dbl=0. }, 0 , 1 , PARAM }, + +/* duplicate option in order to work with avconv */ +{"resample_cutoff" , "set cutoff frequency ratio" , OFFSET(cutoff) , AV_OPT_TYPE_DOUBLE,{.dbl=0. }, 0 , 1 , PARAM }, + +{"resampler" , "set resampling Engine" , OFFSET(engine) , AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_ENGINE_NB-1, PARAM, .unit = "resampler"}, +{"swr" , "select SW Resampler" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_ENGINE_SWR }, INT_MIN, INT_MAX , PARAM, .unit = "resampler"}, +{"soxr" , "select SoX Resampler" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_ENGINE_SOXR }, INT_MIN, INT_MAX , PARAM, .unit = "resampler"}, +{"precision" , "set soxr resampling precision (in bits)" + , OFFSET(precision) , AV_OPT_TYPE_DOUBLE,{.dbl=20.0 }, 15.0 , 33.0 , PARAM }, +{"cheby" , "enable soxr Chebyshev passband & higher-precision irrational ratio approximation" + , OFFSET(cheby) , AV_OPT_TYPE_BOOL , {.i64=0 }, 0 , 1 , PARAM }, +{"min_comp" , "set minimum difference between timestamps and audio data (in seconds) below which no timestamp compensation of either kind is applied" + , OFFSET(min_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=FLT_MAX }, 0 , FLT_MAX , PARAM }, +{"min_hard_comp" , "set minimum difference between timestamps and audio data (in seconds) to trigger padding/trimming the data." + , OFFSET(min_hard_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=0.1 }, 0 , INT_MAX , PARAM }, +{"comp_duration" , "set duration (in seconds) over which data is stretched/squeezed to make it match the timestamps." + , OFFSET(soft_compensation_duration),AV_OPT_TYPE_FLOAT ,{.dbl=1 }, 0 , INT_MAX , PARAM }, +{"max_soft_comp" , "set maximum factor by which data is stretched/squeezed to make it match the timestamps." + , OFFSET(max_soft_compensation),AV_OPT_TYPE_FLOAT ,{.dbl=0 }, INT_MIN, INT_MAX , PARAM }, +{"async" , "simplified 1 parameter audio timestamp matching, 0(disabled), 1(filling and trimming), >1(maximum stretch/squeeze in samples per second)" + , OFFSET(async) , AV_OPT_TYPE_FLOAT ,{.dbl=0 }, INT_MIN, INT_MAX , PARAM }, +{"first_pts" , "Assume the first pts should be this value (in samples)." + , OFFSET(firstpts_in_samples), AV_OPT_TYPE_INT64 ,{.i64=AV_NOPTS_VALUE }, INT64_MIN,INT64_MAX, PARAM }, + +{ "matrix_encoding" , "set matrixed stereo encoding" , OFFSET(matrix_encoding), AV_OPT_TYPE_INT ,{.i64 = AV_MATRIX_ENCODING_NONE}, AV_MATRIX_ENCODING_NONE, AV_MATRIX_ENCODING_NB-1, PARAM, .unit = "matrix_encoding" }, + { "none", "select none", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_NONE }, INT_MIN, INT_MAX, PARAM, .unit = "matrix_encoding" }, + { "dolby", "select Dolby", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DOLBY }, INT_MIN, INT_MAX, PARAM, .unit = "matrix_encoding" }, + { "dplii", "select Dolby Pro Logic II", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DPLII }, INT_MIN, INT_MAX, PARAM, .unit = "matrix_encoding" }, + +{ "filter_type" , "select swr filter type" , OFFSET(filter_type) , AV_OPT_TYPE_INT , { .i64 = SWR_FILTER_TYPE_KAISER }, SWR_FILTER_TYPE_CUBIC, SWR_FILTER_TYPE_KAISER, PARAM, .unit = "filter_type" }, + { "cubic" , "select cubic" , 0 , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_CUBIC }, INT_MIN, INT_MAX, PARAM, .unit = "filter_type" }, + { "blackman_nuttall", "select Blackman Nuttall windowed sinc", 0 , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_BLACKMAN_NUTTALL }, INT_MIN, INT_MAX, PARAM, .unit = "filter_type" }, + { "kaiser" , "select Kaiser windowed sinc" , 0 , AV_OPT_TYPE_CONST, { .i64 = SWR_FILTER_TYPE_KAISER }, INT_MIN, INT_MAX, PARAM, .unit = "filter_type" }, + +{ "kaiser_beta" , "set swr Kaiser window beta" , OFFSET(kaiser_beta) , AV_OPT_TYPE_DOUBLE , {.dbl=9 }, 2 , 16 , PARAM }, + +{ "output_sample_bits" , "set swr number of output sample bits", OFFSET(dither.output_sample_bits), AV_OPT_TYPE_INT , {.i64=0 }, 0 , 64 , PARAM }, +{0} +}; + +static const char* context_to_name(void* ptr) { + return "SWR"; +} + +static const AVClass av_class = { + .class_name = "SWResampler", + .item_name = context_to_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = OFFSET(log_level_offset), + .parent_log_context_offset = OFFSET(log_ctx), + .category = AV_CLASS_CATEGORY_SWRESAMPLER, +}; + +const AVClass *swr_get_class(void) +{ + return &av_class; +} + +av_cold struct SwrContext *swr_alloc(void){ + SwrContext *s= av_mallocz(sizeof(SwrContext)); + if(s){ + s->av_class= &av_class; + av_opt_set_defaults(s); + s->firstpts = AV_NOPTS_VALUE; + } + return s; +} diff --git a/libs/ffmpeg/libswresample/rematrix.c b/libs/ffmpeg/libswresample/rematrix.c new file mode 100644 index 00000000000..a4911a29221 --- /dev/null +++ b/libs/ffmpeg/libswresample/rematrix.c @@ -0,0 +1,649 @@ +/* + * Copyright (C) 2011-2012 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "swresample_internal.h" +#include "libavutil/avassert.h" +#include "libavutil/channel_layout.h" +#include "libavutil/mem.h" + +#define TEMPLATE_REMATRIX_FLT +#include "rematrix_template.c" +#undef TEMPLATE_REMATRIX_FLT + +#define TEMPLATE_REMATRIX_DBL +#include "rematrix_template.c" +#undef TEMPLATE_REMATRIX_DBL + +#define TEMPLATE_REMATRIX_S16 +#include "rematrix_template.c" +#define TEMPLATE_CLIP +#include "rematrix_template.c" +#undef TEMPLATE_CLIP +#undef TEMPLATE_REMATRIX_S16 + +#define TEMPLATE_REMATRIX_S32 +#include "rematrix_template.c" +#undef TEMPLATE_REMATRIX_S32 + +#define FRONT_LEFT 0 +#define FRONT_RIGHT 1 +#define FRONT_CENTER 2 +#define LOW_FREQUENCY 3 +#define BACK_LEFT 4 +#define BACK_RIGHT 5 +#define FRONT_LEFT_OF_CENTER 6 +#define FRONT_RIGHT_OF_CENTER 7 +#define BACK_CENTER 8 +#define SIDE_LEFT 9 +#define SIDE_RIGHT 10 +#define TOP_CENTER 11 +#define TOP_FRONT_LEFT 12 +#define TOP_FRONT_CENTER 13 +#define TOP_FRONT_RIGHT 14 +#define TOP_BACK_LEFT 15 +#define TOP_BACK_CENTER 16 +#define TOP_BACK_RIGHT 17 +#define NUM_NAMED_CHANNELS 18 + +int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride) +{ + int nb_in, nb_out, in, out; + + if (!s || s->in_convert || // s needs to be allocated but not initialized + swri_check_chlayout(s, &s->user_in_chlayout , "input") || + swri_check_chlayout(s, &s->user_out_chlayout, "output") + ) + return AVERROR(EINVAL); + memset(s->matrix, 0, sizeof(s->matrix)); + + nb_in = s->user_in_chlayout.nb_channels; + nb_out = s->user_out_chlayout.nb_channels; + for (out = 0; out < nb_out; out++) { + for (in = 0; in < nb_in; in++) + s->matrix[out][in] = matrix[in]; + matrix += stride; + } + s->rematrix_custom = 1; + return 0; +} + +static int even(int64_t layout){ + if(!layout) return 1; + if(layout&(layout-1)) return 1; + return 0; +} + +static int clean_layout(AVChannelLayout *out, const AVChannelLayout *in, void *s) +{ + int ret = 0; + + if (av_channel_layout_index_from_channel(in, AV_CHAN_FRONT_CENTER) < 0 && in->nb_channels == 1) { + char buf[128]; + av_channel_layout_describe(in, buf, sizeof(buf)); + av_log(s, AV_LOG_VERBOSE, "Treating %s as mono\n", buf); + *out = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; + } else + ret = av_channel_layout_copy(out, in); + + return ret; +} + +static int sane_layout(AVChannelLayout *ch_layout) { + if(ch_layout->nb_channels >= SWR_CH_MAX) + return 0; + if(ch_layout->order == AV_CHANNEL_ORDER_CUSTOM) + for (int i = 0; i < ch_layout->nb_channels; i++) { + if (ch_layout->u.map[i].id >= 64) + return 0; + } + else if (ch_layout->order != AV_CHANNEL_ORDER_NATIVE) + return 0; + if(!av_channel_layout_subset(ch_layout, AV_CH_LAYOUT_SURROUND)) // at least 1 front speaker + return 0; + if(!even(av_channel_layout_subset(ch_layout, (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT)))) // no asymmetric front + return 0; + if(!even(av_channel_layout_subset(ch_layout, (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT)))) // no asymmetric side + return 0; + if(!even(av_channel_layout_subset(ch_layout, (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT)))) + return 0; + if(!even(av_channel_layout_subset(ch_layout, (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER)))) + return 0; + if(!even(av_channel_layout_subset(ch_layout, (AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT)))) + return 0; + + return 1; +} + +static void build_matrix(const AVChannelLayout *in_ch_layout, const AVChannelLayout *out_ch_layout, + double center_mix_level, double surround_mix_level, + double lfe_mix_level, double maxval, double rematrix_volume, double *matrix_param, + ptrdiff_t stride, enum AVMatrixEncoding matrix_encoding) +{ + double matrix[NUM_NAMED_CHANNELS][NUM_NAMED_CHANNELS]={{0}}; + uint64_t unaccounted = av_channel_layout_subset(in_ch_layout, UINT64_MAX) & + ~av_channel_layout_subset(out_ch_layout, UINT64_MAX); + double maxcoef=0; + int i, j; + + for(i=0; i<FF_ARRAY_ELEMS(matrix); i++){ + if( av_channel_layout_index_from_channel(in_ch_layout, i) >= 0 + && av_channel_layout_index_from_channel(out_ch_layout, i) >= 0) + matrix[i][i]= 1.0; + } + +//FIXME implement dolby surround +//FIXME implement full ac3 + + if(unaccounted & AV_CH_FRONT_CENTER){ + if (av_channel_layout_subset(out_ch_layout, AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO) { + if (av_channel_layout_subset(in_ch_layout, AV_CH_LAYOUT_STEREO)) { + matrix[ FRONT_LEFT][FRONT_CENTER]+= center_mix_level; + matrix[FRONT_RIGHT][FRONT_CENTER]+= center_mix_level; + } else { + matrix[ FRONT_LEFT][FRONT_CENTER]+= M_SQRT1_2; + matrix[FRONT_RIGHT][FRONT_CENTER]+= M_SQRT1_2; + } + }else + av_assert0(0); + } + if(unaccounted & AV_CH_LAYOUT_STEREO){ + if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_FRONT_CENTER) >= 0) { + matrix[FRONT_CENTER][ FRONT_LEFT]+= M_SQRT1_2; + matrix[FRONT_CENTER][FRONT_RIGHT]+= M_SQRT1_2; + if (av_channel_layout_index_from_channel(in_ch_layout, AV_CHAN_FRONT_CENTER) >= 0) + matrix[FRONT_CENTER][ FRONT_CENTER] = center_mix_level*sqrt(2); + }else + av_assert0(0); + } + + if(unaccounted & AV_CH_BACK_CENTER){ + if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_BACK_LEFT) >= 0) { + matrix[ BACK_LEFT][BACK_CENTER]+= M_SQRT1_2; + matrix[BACK_RIGHT][BACK_CENTER]+= M_SQRT1_2; + } else if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_SIDE_LEFT) >= 0) { + matrix[ SIDE_LEFT][BACK_CENTER]+= M_SQRT1_2; + matrix[SIDE_RIGHT][BACK_CENTER]+= M_SQRT1_2; + } else if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_FRONT_LEFT) >= 0) { + if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY || + matrix_encoding == AV_MATRIX_ENCODING_DPLII) { + if (unaccounted & (AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT)) { + matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level * M_SQRT1_2; + matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2; + } else { + matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level; + matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level; + } + } else { + matrix[ FRONT_LEFT][BACK_CENTER]+= surround_mix_level * M_SQRT1_2; + matrix[FRONT_RIGHT][BACK_CENTER]+= surround_mix_level * M_SQRT1_2; + } + } else if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_FRONT_CENTER) >= 0) { + matrix[ FRONT_CENTER][BACK_CENTER]+= surround_mix_level * M_SQRT1_2; + }else + av_assert0(0); + } + if(unaccounted & AV_CH_BACK_LEFT){ + if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_BACK_CENTER) >= 0) { + matrix[BACK_CENTER][ BACK_LEFT]+= M_SQRT1_2; + matrix[BACK_CENTER][BACK_RIGHT]+= M_SQRT1_2; + } else if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_SIDE_LEFT) >= 0) { + if (av_channel_layout_index_from_channel(in_ch_layout, AV_CHAN_SIDE_LEFT) >= 0) { + matrix[ SIDE_LEFT][ BACK_LEFT]+= M_SQRT1_2; + matrix[SIDE_RIGHT][BACK_RIGHT]+= M_SQRT1_2; + }else{ + matrix[ SIDE_LEFT][ BACK_LEFT]+= 1.0; + matrix[SIDE_RIGHT][BACK_RIGHT]+= 1.0; + } + } else if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_FRONT_LEFT) >= 0) { + if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { + matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * M_SQRT1_2; + matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2; + matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; + matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * M_SQRT1_2; + } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { + matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * SQRT3_2; + matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2; + matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; + matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * SQRT3_2; + } else { + matrix[ FRONT_LEFT][ BACK_LEFT] += surround_mix_level; + matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level; + } + } else if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_FRONT_CENTER) >= 0) { + matrix[ FRONT_CENTER][BACK_LEFT ]+= surround_mix_level*M_SQRT1_2; + matrix[ FRONT_CENTER][BACK_RIGHT]+= surround_mix_level*M_SQRT1_2; + }else + av_assert0(0); + } + + if(unaccounted & AV_CH_SIDE_LEFT){ + if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_BACK_LEFT) >= 0) { + /* if back channels do not exist in the input, just copy side + channels to back channels, otherwise mix side into back */ + if (av_channel_layout_index_from_channel(in_ch_layout, AV_CHAN_BACK_LEFT) >= 0) { + matrix[BACK_LEFT ][SIDE_LEFT ] += M_SQRT1_2; + matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2; + } else { + matrix[BACK_LEFT ][SIDE_LEFT ] += 1.0; + matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0; + } + } else if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_BACK_CENTER) >= 0) { + matrix[BACK_CENTER][ SIDE_LEFT]+= M_SQRT1_2; + matrix[BACK_CENTER][SIDE_RIGHT]+= M_SQRT1_2; + } else if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_FRONT_LEFT) >= 0) { + if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { + matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * M_SQRT1_2; + matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2; + matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; + matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2; + } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { + matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * SQRT3_2; + matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2; + matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; + matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * SQRT3_2; + } else { + matrix[ FRONT_LEFT][ SIDE_LEFT] += surround_mix_level; + matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level; + } + } else if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_FRONT_CENTER) >= 0) { + matrix[ FRONT_CENTER][SIDE_LEFT ]+= surround_mix_level * M_SQRT1_2; + matrix[ FRONT_CENTER][SIDE_RIGHT]+= surround_mix_level * M_SQRT1_2; + }else + av_assert0(0); + } + + if(unaccounted & AV_CH_FRONT_LEFT_OF_CENTER){ + if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_FRONT_LEFT) >= 0) { + matrix[ FRONT_LEFT][ FRONT_LEFT_OF_CENTER]+= 1.0; + matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER]+= 1.0; + } else if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_FRONT_CENTER) >= 0) { + matrix[ FRONT_CENTER][ FRONT_LEFT_OF_CENTER]+= M_SQRT1_2; + matrix[ FRONT_CENTER][FRONT_RIGHT_OF_CENTER]+= M_SQRT1_2; + }else + av_assert0(0); + } + + if (unaccounted & AV_CH_TOP_FRONT_LEFT) { + if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_TOP_FRONT_CENTER) >= 0) { + matrix[TOP_FRONT_CENTER][TOP_FRONT_LEFT ] += M_SQRT1_2; + matrix[TOP_FRONT_CENTER][TOP_FRONT_RIGHT] += M_SQRT1_2; + if (av_channel_layout_index_from_channel(in_ch_layout, AV_CHAN_TOP_FRONT_CENTER) >= 0) + matrix[TOP_FRONT_CENTER][TOP_FRONT_CENTER] = center_mix_level * sqrt(2); + } else if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_FRONT_LEFT) >= 0) { + if (av_channel_layout_index_from_channel(in_ch_layout, AV_CHAN_FRONT_LEFT) >= 0) { + matrix[FRONT_LEFT ][TOP_FRONT_LEFT ] += M_SQRT1_2; + matrix[FRONT_RIGHT][TOP_FRONT_RIGHT] += M_SQRT1_2; + } else { + matrix[FRONT_LEFT ][TOP_FRONT_LEFT ] += 1.0; + matrix[FRONT_RIGHT][TOP_FRONT_RIGHT] += 1.0; + } + } else if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_FRONT_CENTER) >= 0) { + matrix[FRONT_CENTER][TOP_FRONT_LEFT ] += M_SQRT1_2; + matrix[FRONT_CENTER][TOP_FRONT_RIGHT] += M_SQRT1_2; + } else + av_assert0(0); + } + + /* mix LFE into front left/right or center */ + if (unaccounted & AV_CH_LOW_FREQUENCY) { + if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_FRONT_CENTER) >= 0) { + matrix[FRONT_CENTER][LOW_FREQUENCY] += lfe_mix_level; + } else if (av_channel_layout_index_from_channel(out_ch_layout, AV_CHAN_FRONT_LEFT) >= 0) { + matrix[FRONT_LEFT ][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2; + matrix[FRONT_RIGHT][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2; + } else + av_assert0(0); + } + + + for (i = 0; i < 64; i++) { + double sum=0; + int out_i = av_channel_layout_index_from_channel(out_ch_layout, i); + if (out_i < 0) + continue; + for(j=0; j<64; j++){ + int in_i = av_channel_layout_index_from_channel(in_ch_layout, j); + if (in_i < 0) + continue; + if (i < FF_ARRAY_ELEMS(matrix) && j < FF_ARRAY_ELEMS(matrix[0])) + matrix_param[stride*out_i + in_i] = matrix[i][j]; + else + matrix_param[stride*out_i + in_i] = i == j && + ( av_channel_layout_index_from_channel(in_ch_layout, i) >= 0 + && av_channel_layout_index_from_channel(out_ch_layout, i) >= 0); + sum += fabs(matrix_param[stride*out_i + in_i]); + } + maxcoef= FFMAX(maxcoef, sum); + } + if(rematrix_volume < 0) + maxcoef = -rematrix_volume; + + if(maxcoef > maxval || rematrix_volume < 0){ + maxcoef /= maxval; + for(i=0; i<SWR_CH_MAX; i++) + for(j=0; j<SWR_CH_MAX; j++){ + matrix_param[stride*i + j] /= maxcoef; + } + } +} + +av_cold int swr_build_matrix2(const AVChannelLayout *in_layout, const AVChannelLayout *out_layout, + double center_mix_level, double surround_mix_level, + double lfe_mix_level, double maxval, + double rematrix_volume, double *matrix_param, + ptrdiff_t stride, enum AVMatrixEncoding matrix_encoding, void *log_context) +{ + int i, j, ret; + AVChannelLayout in_ch_layout = { 0 }, out_ch_layout = { 0 }; + char buf[128]; + + ret = clean_layout(&in_ch_layout, in_layout, log_context); + ret |= clean_layout(&out_ch_layout, out_layout, log_context); + if (ret < 0) + goto fail; + + if( !av_channel_layout_compare(&out_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO_DOWNMIX) + && !av_channel_layout_subset(&in_ch_layout, AV_CH_LAYOUT_STEREO_DOWNMIX) + ) { + av_channel_layout_uninit(&out_ch_layout); + out_ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; + } + if( !av_channel_layout_compare(&in_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO_DOWNMIX) + && !av_channel_layout_subset(&out_ch_layout, AV_CH_LAYOUT_STEREO_DOWNMIX) + ) { + av_channel_layout_uninit(&in_ch_layout); + in_ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; + } + if (!av_channel_layout_compare(&in_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_22POINT2) && + av_channel_layout_compare(&out_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_22POINT2)) { + av_channel_layout_from_mask(&in_ch_layout, (AV_CH_LAYOUT_7POINT1_WIDE_BACK|AV_CH_BACK_CENTER)); + av_channel_layout_describe(&in_ch_layout, buf, sizeof(buf)); + av_log(log_context, AV_LOG_WARNING, + "Full-on remixing from 22.2 has not yet been implemented! " + "Processing the input as '%s'\n", + buf); + } + + if(!av_channel_layout_check(&in_ch_layout)) { + av_log(log_context, AV_LOG_ERROR, "Input channel layout is invalid\n"); + ret = AVERROR(EINVAL); + goto fail; + } + if(!sane_layout(&in_ch_layout)) { + av_channel_layout_describe(&in_ch_layout, buf, sizeof(buf)); + av_log(log_context, AV_LOG_ERROR, "Input channel layout '%s' is not supported\n", buf); + ret = AVERROR(EINVAL); + goto fail; + } + + if(!av_channel_layout_check(&out_ch_layout)) { + av_log(log_context, AV_LOG_ERROR, "Output channel layout is invalid\n"); + ret = AVERROR(EINVAL); + goto fail; + } + if(!sane_layout(&out_ch_layout)) { + av_channel_layout_describe(&out_ch_layout, buf, sizeof(buf)); + av_log(log_context, AV_LOG_ERROR, "Output channel layout '%s' is not supported\n", buf); + ret = AVERROR(EINVAL); + goto fail; + } + + build_matrix(&in_ch_layout, &out_ch_layout, center_mix_level, + surround_mix_level, lfe_mix_level, maxval, rematrix_volume, + matrix_param, stride, matrix_encoding); + + if(rematrix_volume > 0){ + for(i=0; i<SWR_CH_MAX; i++) + for(j=0; j<SWR_CH_MAX; j++){ + matrix_param[stride*i + j] *= rematrix_volume; + } + } + + av_log(log_context, AV_LOG_DEBUG, "Matrix coefficients:\n"); + for (i = 0; i < out_ch_layout.nb_channels; i++){ + av_channel_name(buf, sizeof(buf), av_channel_layout_channel_from_index(&out_ch_layout, i)); + av_log(log_context, AV_LOG_DEBUG, "%s: ", buf); + for (j = 0; j < in_ch_layout.nb_channels; j++){ + av_channel_name(buf, sizeof(buf), av_channel_layout_channel_from_index(&in_ch_layout, j)); + av_log(log_context, AV_LOG_DEBUG, "%s:%f ", buf, matrix_param[stride*i + j]); + } + av_log(log_context, AV_LOG_DEBUG, "\n"); + } + + ret = 0; +fail: + av_channel_layout_uninit(&in_ch_layout); + av_channel_layout_uninit(&out_ch_layout); + + return ret; +} + +av_cold static int auto_matrix(SwrContext *s) +{ + double maxval; + + if (s->rematrix_maxval > 0) { + maxval = s->rematrix_maxval; + } else if ( av_get_packed_sample_fmt(s->out_sample_fmt) < AV_SAMPLE_FMT_FLT + || av_get_packed_sample_fmt(s->int_sample_fmt) < AV_SAMPLE_FMT_FLT) { + maxval = 1.0; + } else + maxval = INT_MAX; + + memset(s->matrix, 0, sizeof(s->matrix)); + return swr_build_matrix2(&s->in_ch_layout, &s->out_ch_layout, + s->clev, s->slev, s->lfe_mix_level, + maxval, s->rematrix_volume, (double*)s->matrix, + s->matrix[1] - s->matrix[0], s->matrix_encoding, s); +} + +av_cold int swri_rematrix_init(SwrContext *s){ + int i, j; + int nb_in = s->used_ch_layout.nb_channels; + int nb_out = s->out.ch_count; + + s->mix_any_f = NULL; + + if (!s->rematrix_custom) { + int r = auto_matrix(s); + if (r) + return r; + } + if (s->midbuf.fmt == AV_SAMPLE_FMT_S16P){ + int maxsum = 0; + s->native_matrix = av_calloc(nb_in * nb_out, sizeof(int)); + if (!s->native_matrix) + return AVERROR(ENOMEM); + for (i = 0; i < nb_out; i++) { + double rem = 0; + int sum = 0; + + for (j = 0; j < nb_in; j++) { + double target = s->matrix[i][j] * 32768 + rem; + ((int*)s->native_matrix)[i * nb_in + j] = lrintf(target); + rem += target - ((int*)s->native_matrix)[i * nb_in + j]; + sum += FFABS(((int*)s->native_matrix)[i * nb_in + j]); + } + maxsum = FFMAX(maxsum, sum); + } + s->native_one.i = 32768; + if (maxsum <= 32768) { + s->mix_1_1_f = copy_s16; + s->mix_2_1_f = sum2_s16; + s->mix_any_f = get_mix_any_func_s16(s); + } else { + s->mix_1_1_f = copy_clip_s16; + s->mix_2_1_f = sum2_clip_s16; + s->mix_any_f = get_mix_any_func_clip_s16(s); + } + }else if(s->midbuf.fmt == AV_SAMPLE_FMT_FLTP){ + s->native_matrix = av_calloc(nb_in * nb_out, sizeof(float)); + if (!s->native_matrix) + return AVERROR(ENOMEM); + for (i = 0; i < nb_out; i++) + for (j = 0; j < nb_in; j++) + ((float*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j]; + s->native_one.f = 1.0; + s->mix_1_1_f = copy_float; + s->mix_2_1_f = sum2_float; + s->mix_any_f = get_mix_any_func_float(s); + }else if(s->midbuf.fmt == AV_SAMPLE_FMT_DBLP){ + s->native_matrix = av_calloc(nb_in * nb_out, sizeof(double)); + if (!s->native_matrix) + return AVERROR(ENOMEM); + for (i = 0; i < nb_out; i++) + for (j = 0; j < nb_in; j++) + ((double*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j]; + s->native_one.d = 1.0; + s->mix_1_1_f = copy_double; + s->mix_2_1_f = sum2_double; + s->mix_any_f = get_mix_any_func_double(s); + }else if(s->midbuf.fmt == AV_SAMPLE_FMT_S32P){ + s->native_matrix = av_calloc(nb_in * nb_out, sizeof(int)); + if (!s->native_matrix) + return AVERROR(ENOMEM); + for (i = 0; i < nb_out; i++) { + double rem = 0; + + for (j = 0; j < nb_in; j++) { + double target = s->matrix[i][j] * 32768 + rem; + ((int*)s->native_matrix)[i * nb_in + j] = lrintf(target); + rem += target - ((int*)s->native_matrix)[i * nb_in + j]; + } + } + s->native_one.i = 32768; + s->mix_1_1_f = copy_s32; + s->mix_2_1_f = sum2_s32; + s->mix_any_f = get_mix_any_func_s32(s); + }else + av_assert0(0); + //FIXME quantize for integeres + for (i = 0; i < SWR_CH_MAX; i++) { + int ch_in=0; + for (j = 0; j < SWR_CH_MAX; j++) { + const double coeff = s->matrix[i][j]; + if (coeff) + s->matrix_ch[i][++ch_in]= j; + switch (s->int_sample_fmt) { + case AV_SAMPLE_FMT_FLTP: + s->matrix_flt[i][j] = coeff; + break; + case AV_SAMPLE_FMT_DBLP: + break; + default: + s->matrix32[i][j] = lrintf(coeff * 32768); + break; + } + } + s->matrix_ch[i][0]= ch_in; + } + +#if ARCH_X86 && HAVE_X86ASM + return swri_rematrix_init_x86(s); +#endif + + return 0; +} + +av_cold void swri_rematrix_free(SwrContext *s){ + av_freep(&s->native_matrix); + av_freep(&s->native_simd_matrix); +} + +int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy){ + int out_i, in_i, i, j; + int len1 = 0; + int off = 0; + + if(s->mix_any_f) { + s->mix_any_f(out->ch, (const uint8_t *const *)in->ch, s->native_matrix, len); + return 0; + } + + if(s->mix_2_1_simd || s->mix_1_1_simd){ + len1= len&~15; + off = len1 * out->bps; + } + + av_assert0(s->out_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC || out->ch_count == s->out_ch_layout.nb_channels); + av_assert0(s-> in_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC || in ->ch_count == s->in_ch_layout.nb_channels); + + for(out_i=0; out_i<out->ch_count; out_i++){ + switch(s->matrix_ch[out_i][0]){ + case 0: + if(mustcopy) + memset(out->ch[out_i], 0, len * av_get_bytes_per_sample(s->int_sample_fmt)); + break; + case 1: + in_i= s->matrix_ch[out_i][1]; + if(s->matrix[out_i][in_i]!=1.0){ + if(s->mix_1_1_simd && len1) + s->mix_1_1_simd(out->ch[out_i] , in->ch[in_i] , s->native_simd_matrix, in->ch_count*out_i + in_i, len1); + if(len != len1) + s->mix_1_1_f (out->ch[out_i]+off, in->ch[in_i]+off, s->native_matrix, in->ch_count*out_i + in_i, len-len1); + }else if(mustcopy){ + memcpy(out->ch[out_i], in->ch[in_i], len*out->bps); + }else{ + out->ch[out_i]= in->ch[in_i]; + } + break; + case 2: { + int in_i1 = s->matrix_ch[out_i][1]; + int in_i2 = s->matrix_ch[out_i][2]; + if(s->mix_2_1_simd && len1) + s->mix_2_1_simd(out->ch[out_i] , in->ch[in_i1] , in->ch[in_i2] , s->native_simd_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len1); + else + s->mix_2_1_f (out->ch[out_i] , in->ch[in_i1] , in->ch[in_i2] , s->native_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len1); + if(len != len1) + s->mix_2_1_f (out->ch[out_i]+off, in->ch[in_i1]+off, in->ch[in_i2]+off, s->native_matrix, in->ch_count*out_i + in_i1, in->ch_count*out_i + in_i2, len-len1); + break;} + default: + if(s->int_sample_fmt == AV_SAMPLE_FMT_FLTP){ + for(i=0; i<len; i++){ + float v=0; + for(j=0; j<s->matrix_ch[out_i][0]; j++){ + in_i= s->matrix_ch[out_i][1+j]; + v+= ((float*)in->ch[in_i])[i] * s->matrix_flt[out_i][in_i]; + } + ((float*)out->ch[out_i])[i]= v; + } + }else if(s->int_sample_fmt == AV_SAMPLE_FMT_DBLP){ + for(i=0; i<len; i++){ + double v=0; + for(j=0; j<s->matrix_ch[out_i][0]; j++){ + in_i= s->matrix_ch[out_i][1+j]; + v+= ((double*)in->ch[in_i])[i] * s->matrix[out_i][in_i]; + } + ((double*)out->ch[out_i])[i]= v; + } + }else{ + for(i=0; i<len; i++){ + int v=0; + for(j=0; j<s->matrix_ch[out_i][0]; j++){ + in_i= s->matrix_ch[out_i][1+j]; + v+= ((int16_t*)in->ch[in_i])[i] * s->matrix32[out_i][in_i]; + } + ((int16_t*)out->ch[out_i])[i]= (v + 16384)>>15; + } + } + } + } + return 0; +} diff --git a/libs/ffmpeg/libswresample/rematrix_template.c b/libs/ffmpeg/libswresample/rematrix_template.c new file mode 100644 index 00000000000..a18f82a3f1b --- /dev/null +++ b/libs/ffmpeg/libswresample/rematrix_template.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2011-2012 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if 0 +#pragma makedep header +#endif + +#if defined(TEMPLATE_REMATRIX_FLT) +# define R(x) x +# define SAMPLE float +# define COEFF float +# define INTER float +# define RENAME(x) x ## _float +#elif defined(TEMPLATE_REMATRIX_DBL) +# define R(x) x +# define SAMPLE double +# define COEFF double +# define INTER double +# define RENAME(x) x ## _double +#elif defined(TEMPLATE_REMATRIX_S16) +# define SAMPLE int16_t +# define COEFF int +# define INTER int +# ifdef TEMPLATE_CLIP +# define R(x) av_clip_int16(((x) + 16384)>>15) +# define RENAME(x) x ## _clip_s16 +# else +# define R(x) (((x) + 16384)>>15) +# define RENAME(x) x ## _s16 +# endif +#elif defined(TEMPLATE_REMATRIX_S32) +# define R(x) (((x) + 16384)>>15) +# define SAMPLE int32_t +# define COEFF int +# define INTER int64_t +# define RENAME(x) x ## _s32 +#endif + +static void RENAME(sum2)(void *out_, const void *in1_, const void *in2_, + const void *coeffp_, integer index1, integer index2, integer len) +{ + const SAMPLE *in1 = in1_, *in2 = in2_; + const COEFF *coeffp = coeffp_; + SAMPLE *out = out_; + int i; + INTER coeff1 = coeffp[index1]; + INTER coeff2 = coeffp[index2]; + + for(i=0; i<len; i++) + out[i] = R(coeff1*in1[i] + coeff2*in2[i]); +} + +static void RENAME(copy)(void *out_, const void *in_, const void *coeffp_, + integer index, integer len) +{ + const COEFF *coeffp = coeffp_; + const SAMPLE *in = in_; + SAMPLE *out = out_; + int i; + INTER coeff = coeffp[index]; + for(i=0; i<len; i++) + out[i] = R(coeff*in[i]); +} + +static void RENAME(mix6to2)(uint8_t *const *out_, const uint8_t *const *in_, + const void *coeffp_, integer len) +{ + const SAMPLE *const *const in = (const SAMPLE *const *)in_; + SAMPLE *const *const out = (SAMPLE *const*)out_; + const COEFF *coeffp = coeffp_; + int i; + + for(i=0; i<len; i++) { + INTER t = in[2][i]*(INTER)coeffp[0*6+2] + in[3][i]*(INTER)coeffp[0*6+3]; + out[0][i] = R(t + in[0][i]*(INTER)coeffp[0*6+0] + in[4][i]*(INTER)coeffp[0*6+4]); + out[1][i] = R(t + in[1][i]*(INTER)coeffp[1*6+1] + in[5][i]*(INTER)coeffp[1*6+5]); + } +} + +static void RENAME(mix8to2)(uint8_t *const *out_, const uint8_t *const *in_, + const void *coeffp_, integer len) +{ + const SAMPLE *const *const in = (const SAMPLE *const *)in_; + SAMPLE *const *const out = (SAMPLE *const*)out_; + const COEFF *coeffp = coeffp_; + int i; + + for(i=0; i<len; i++) { + INTER t = in[2][i]*(INTER)coeffp[0*8+2] + in[3][i]*(INTER)coeffp[0*8+3]; + out[0][i] = R(t + in[0][i]*(INTER)coeffp[0*8+0] + in[4][i]*(INTER)coeffp[0*8+4] + in[6][i]*(INTER)coeffp[0*8+6]); + out[1][i] = R(t + in[1][i]*(INTER)coeffp[1*8+1] + in[5][i]*(INTER)coeffp[1*8+5] + in[7][i]*(INTER)coeffp[1*8+7]); + } +} + +static mix_any_func_type *RENAME(get_mix_any_func)(const SwrContext *s) +{ + if ( !av_channel_layout_compare(&s->out_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO) + && ( !av_channel_layout_compare(&s->in_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1) + || !av_channel_layout_compare(&s->in_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1_BACK)) + && s->matrix[0][2] == s->matrix[1][2] && s->matrix[0][3] == s->matrix[1][3] + && !s->matrix[0][1] && !s->matrix[0][5] && !s->matrix[1][0] && !s->matrix[1][4] + ) + return RENAME(mix6to2); + + if ( !av_channel_layout_compare(&s->out_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO) + && !av_channel_layout_compare(&s->in_ch_layout, &(AVChannelLayout)AV_CHANNEL_LAYOUT_7POINT1) + && s->matrix[0][2] == s->matrix[1][2] && s->matrix[0][3] == s->matrix[1][3] + && !s->matrix[0][1] && !s->matrix[0][5] && !s->matrix[1][0] && !s->matrix[1][4] + && !s->matrix[0][7] && !s->matrix[1][6] + ) + return RENAME(mix8to2); + + return NULL; +} + +#undef R +#undef SAMPLE +#undef COEFF +#undef INTER +#undef RENAME diff --git a/libs/ffmpeg/libswresample/resample.c b/libs/ffmpeg/libswresample/resample.c new file mode 100644 index 00000000000..16d48e93daf --- /dev/null +++ b/libs/ffmpeg/libswresample/resample.c @@ -0,0 +1,513 @@ +/* + * audio resampling + * Copyright (c) 2004-2012 Michael Niedermayer <michaelni@gmx.at> + * bessel function: Copyright (c) 2006 Xiaogang Zhang + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * audio resampling + * @author Michael Niedermayer <michaelni@gmx.at> + */ + +#include "libavutil/avassert.h" +#include "libavutil/mem.h" +#include "resample.h" + +/** + * builds a polyphase filterbank. + * @param factor resampling factor + * @param scale wanted sum of coefficients for each filter + * @param filter_type filter type + * @param kaiser_beta kaiser window beta + * @return 0 on success, negative on error + */ +static int build_filter(ResampleContext *c, void *filter, double factor, int tap_count, int alloc, int phase_count, int scale, + int filter_type, double kaiser_beta){ + int ph, i; + int ph_nb = phase_count % 2 ? phase_count : phase_count / 2 + 1; + double x, y, w, t, s; + double *tab = av_malloc_array(tap_count+1, sizeof(*tab)); + double *sin_lut = av_malloc_array(ph_nb, sizeof(*sin_lut)); + const int center= (tap_count-1)/2; + double norm = 0; + int ret = AVERROR(ENOMEM); + + if (!tab || !sin_lut) + goto fail; + + av_assert0(tap_count == 1 || tap_count % 2 == 0); + + /* if upsampling, only need to interpolate, no filter */ + if (factor > 1.0) + factor = 1.0; + + if (factor == 1.0) { + for (ph = 0; ph < ph_nb; ph++) + sin_lut[ph] = sin(M_PI * ph / phase_count) * (center & 1 ? 1 : -1); + } + for(ph = 0; ph < ph_nb; ph++) { + s = sin_lut[ph]; + for(i=0;i<tap_count;i++) { + x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor; + if (x == 0) y = 1.0; + else if (factor == 1.0) + y = s / x; + else + y = sin(x) / x; + switch(filter_type){ + case SWR_FILTER_TYPE_CUBIC:{ + const float d= -0.5; //first order derivative = -0.5 + x = fabs(((double)(i - center) - (double)ph / phase_count) * factor); + if(x<1.0) y= 1 - 3*x*x + 2*x*x*x + d*( -x*x + x*x*x); + else y= d*(-4 + 8*x - 5*x*x + x*x*x); + break;} + case SWR_FILTER_TYPE_BLACKMAN_NUTTALL: + w = 2.0*x / (factor*tap_count); + t = -cos(w); + y *= 0.3635819 - 0.4891775 * t + 0.1365995 * (2*t*t-1) - 0.0106411 * (4*t*t*t - 3*t); + break; + case SWR_FILTER_TYPE_KAISER: + w = 2.0*x / (factor*tap_count*M_PI); + y *= av_bessel_i0(kaiser_beta*sqrt(FFMAX(1-w*w, 0))); + break; + default: + av_assert0(0); + } + + tab[i] = y; + s = -s; + if (!ph) + norm += y; + } + + /* normalize so that an uniform color remains the same */ + switch(c->format){ + case AV_SAMPLE_FMT_S16P: + for(i=0;i<tap_count;i++) + ((int16_t*)filter)[ph * alloc + i] = av_clip_int16(lrintf(tab[i] * scale / norm)); + if (phase_count % 2) break; + for (i = 0; i < tap_count; i++) + ((int16_t*)filter)[(phase_count-ph) * alloc + tap_count-1-i] = ((int16_t*)filter)[ph * alloc + i]; + break; + case AV_SAMPLE_FMT_S32P: + for(i=0;i<tap_count;i++) + ((int32_t*)filter)[ph * alloc + i] = av_clipl_int32(llrint(tab[i] * scale / norm)); + if (phase_count % 2) break; + for (i = 0; i < tap_count; i++) + ((int32_t*)filter)[(phase_count-ph) * alloc + tap_count-1-i] = ((int32_t*)filter)[ph * alloc + i]; + break; + case AV_SAMPLE_FMT_FLTP: + for(i=0;i<tap_count;i++) + ((float*)filter)[ph * alloc + i] = tab[i] * scale / norm; + if (phase_count % 2) break; + for (i = 0; i < tap_count; i++) + ((float*)filter)[(phase_count-ph) * alloc + tap_count-1-i] = ((float*)filter)[ph * alloc + i]; + break; + case AV_SAMPLE_FMT_DBLP: + for(i=0;i<tap_count;i++) + ((double*)filter)[ph * alloc + i] = tab[i] * scale / norm; + if (phase_count % 2) break; + for (i = 0; i < tap_count; i++) + ((double*)filter)[(phase_count-ph) * alloc + tap_count-1-i] = ((double*)filter)[ph * alloc + i]; + break; + } + } +#if 0 + { +#define LEN 1024 + int j,k; + double sine[LEN + tap_count]; + double filtered[LEN]; + double maxff=-2, minff=2, maxsf=-2, minsf=2; + for(i=0; i<LEN; i++){ + double ss=0, sf=0, ff=0; + for(j=0; j<LEN+tap_count; j++) + sine[j]= cos(i*j*M_PI/LEN); + for(j=0; j<LEN; j++){ + double sum=0; + ph=0; + for(k=0; k<tap_count; k++) + sum += filter[ph * tap_count + k] * sine[k+j]; + filtered[j]= sum / (1<<FILTER_SHIFT); + ss+= sine[j + center] * sine[j + center]; + ff+= filtered[j] * filtered[j]; + sf+= sine[j + center] * filtered[j]; + } + ss= sqrt(2*ss/LEN); + ff= sqrt(2*ff/LEN); + sf= 2*sf/LEN; + maxff= FFMAX(maxff, ff); + minff= FFMIN(minff, ff); + maxsf= FFMAX(maxsf, sf); + minsf= FFMIN(minsf, sf); + if(i%11==0){ + av_log(NULL, AV_LOG_ERROR, "i:%4d ss:%f ff:%13.6e-%13.6e sf:%13.6e-%13.6e\n", i, ss, maxff, minff, maxsf, minsf); + minff=minsf= 2; + maxff=maxsf= -2; + } + } + } +#endif + + ret = 0; +fail: + av_free(tab); + av_free(sin_lut); + return ret; +} + +static void resample_free(ResampleContext **cc){ + ResampleContext *c = *cc; + if(!c) + return; + av_freep(&c->filter_bank); + av_freep(cc); +} + +static ResampleContext *resample_init(ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, + double cutoff0, enum AVSampleFormat format, enum SwrFilterType filter_type, double kaiser_beta, + double precision, int cheby, int exact_rational) +{ + double cutoff = cutoff0? cutoff0 : 0.97; + double factor= FFMIN(out_rate * cutoff / in_rate, 1.0); + int phase_count= 1<<phase_shift; + int phase_count_compensation = phase_count; + int filter_length = FFMAX((int)ceil(filter_size/factor), 1); + + if (filter_length > 1) + filter_length = FFALIGN(filter_length, 2); + + if (exact_rational) { + int phase_count_exact, phase_count_exact_den; + + av_reduce(&phase_count_exact, &phase_count_exact_den, out_rate, in_rate, INT_MAX); + if (phase_count_exact <= phase_count) { + phase_count_compensation = phase_count_exact * (phase_count / phase_count_exact); + phase_count = phase_count_exact; + } + } + + if (!c || c->phase_count != phase_count || c->linear!=linear || c->factor != factor + || c->filter_length != filter_length || c->format != format + || c->filter_type != filter_type || c->kaiser_beta != kaiser_beta) { + resample_free(&c); + c = av_mallocz(sizeof(*c)); + if (!c) + return NULL; + + c->format= format; + + c->felem_size= av_get_bytes_per_sample(c->format); + + switch(c->format){ + case AV_SAMPLE_FMT_S16P: + c->filter_shift = 15; + break; + case AV_SAMPLE_FMT_S32P: + c->filter_shift = 30; + break; + case AV_SAMPLE_FMT_FLTP: + case AV_SAMPLE_FMT_DBLP: + c->filter_shift = 0; + break; + default: + av_log(NULL, AV_LOG_ERROR, "Unsupported sample format\n"); + av_assert0(0); + } + + if (filter_size/factor > INT32_MAX/256) { + av_log(NULL, AV_LOG_ERROR, "Filter length too large\n"); + goto error; + } + + c->phase_count = phase_count; + c->linear = linear; + c->factor = factor; + c->filter_length = filter_length; + c->filter_alloc = FFALIGN(c->filter_length, 8); + c->filter_bank = av_calloc(c->filter_alloc, (phase_count+1)*c->felem_size); + c->filter_type = filter_type; + c->kaiser_beta = kaiser_beta; + c->phase_count_compensation = phase_count_compensation; + if (!c->filter_bank) + goto error; + if (build_filter(c, (void*)c->filter_bank, factor, c->filter_length, c->filter_alloc, phase_count, 1<<c->filter_shift, filter_type, kaiser_beta)) + goto error; + memcpy(c->filter_bank + (c->filter_alloc*phase_count+1)*c->felem_size, c->filter_bank, (c->filter_alloc-1)*c->felem_size); + memcpy(c->filter_bank + (c->filter_alloc*phase_count )*c->felem_size, c->filter_bank + (c->filter_alloc - 1)*c->felem_size, c->felem_size); + } + + c->compensation_distance= 0; + if(!av_reduce(&c->src_incr, &c->dst_incr, out_rate, in_rate * (int64_t)phase_count, INT32_MAX/2)) + goto error; + while (c->dst_incr < (1<<20) && c->src_incr < (1<<20)) { + c->dst_incr *= 2; + c->src_incr *= 2; + } + c->ideal_dst_incr = c->dst_incr; + c->dst_incr_div = c->dst_incr / c->src_incr; + c->dst_incr_mod = c->dst_incr % c->src_incr; + + c->index= -phase_count*((c->filter_length-1)/2); + c->frac= 0; + + swri_resample_dsp_init(c); + + return c; +error: + av_freep(&c->filter_bank); + av_free(c); + return NULL; +} + +static int rebuild_filter_bank_with_compensation(ResampleContext *c) +{ + uint8_t *new_filter_bank; + int new_src_incr, new_dst_incr; + int phase_count = c->phase_count_compensation; + int ret; + + if (phase_count == c->phase_count) + return 0; + + av_assert0(!c->frac && !c->dst_incr_mod); + + new_filter_bank = av_calloc(c->filter_alloc, (phase_count + 1) * c->felem_size); + if (!new_filter_bank) + return AVERROR(ENOMEM); + + ret = build_filter(c, new_filter_bank, c->factor, c->filter_length, c->filter_alloc, + phase_count, 1 << c->filter_shift, c->filter_type, c->kaiser_beta); + if (ret < 0) { + av_freep(&new_filter_bank); + return ret; + } + memcpy(new_filter_bank + (c->filter_alloc*phase_count+1)*c->felem_size, new_filter_bank, (c->filter_alloc-1)*c->felem_size); + memcpy(new_filter_bank + (c->filter_alloc*phase_count )*c->felem_size, new_filter_bank + (c->filter_alloc - 1)*c->felem_size, c->felem_size); + + if (!av_reduce(&new_src_incr, &new_dst_incr, c->src_incr, + c->dst_incr * (int64_t)(phase_count/c->phase_count), INT32_MAX/2)) + { + av_freep(&new_filter_bank); + return AVERROR(EINVAL); + } + + c->src_incr = new_src_incr; + c->dst_incr = new_dst_incr; + while (c->dst_incr < (1<<20) && c->src_incr < (1<<20)) { + c->dst_incr *= 2; + c->src_incr *= 2; + } + c->ideal_dst_incr = c->dst_incr; + c->dst_incr_div = c->dst_incr / c->src_incr; + c->dst_incr_mod = c->dst_incr % c->src_incr; + c->index *= phase_count / c->phase_count; + c->phase_count = phase_count; + av_freep(&c->filter_bank); + c->filter_bank = new_filter_bank; + return 0; +} + +static int set_compensation(ResampleContext *c, int sample_delta, int compensation_distance){ + int ret; + + if (compensation_distance && sample_delta) { + ret = rebuild_filter_bank_with_compensation(c); + if (ret < 0) + return ret; + } + + c->compensation_distance= compensation_distance; + if (compensation_distance) + c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delta / compensation_distance; + else + c->dst_incr = c->ideal_dst_incr; + + c->dst_incr_div = c->dst_incr / c->src_incr; + c->dst_incr_mod = c->dst_incr % c->src_incr; + + return 0; +} + +static int multiple_resample(ResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed){ + int i; + int64_t max_src_size = (INT64_MAX/2 / c->phase_count) / c->src_incr; + + if (c->compensation_distance) + dst_size = FFMIN(dst_size, c->compensation_distance); + src_size = FFMIN(src_size, max_src_size); + + *consumed = 0; + + if (c->filter_length == 1 && c->phase_count == 1) { + int64_t index2= (1LL<<32)*c->frac/c->src_incr + (1LL<<32)*c->index + 1; + int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr + 1; + int new_size = (src_size * (int64_t)c->src_incr - c->frac + c->dst_incr - 1) / c->dst_incr; + + dst_size = FFMAX(FFMIN(dst_size, new_size), 0); + if (dst_size > 0) { + for (i = 0; i < dst->ch_count; i++) { + c->dsp.resample_one(dst->ch[i], src->ch[i], dst_size, index2, incr); + if (i+1 == dst->ch_count) { + c->index += dst_size * c->dst_incr_div; + c->index += (c->frac + dst_size * (int64_t)c->dst_incr_mod) / c->src_incr; + av_assert2(c->index >= 0); + *consumed = c->index; + c->frac = (c->frac + dst_size * (int64_t)c->dst_incr_mod) % c->src_incr; + c->index = 0; + } + } + } + } else { + int64_t end_index = (1LL + src_size - c->filter_length) * c->phase_count; + int64_t delta_frac = (end_index - c->index) * c->src_incr - c->frac; + int delta_n = (delta_frac + c->dst_incr - 1) / c->dst_incr; + int (*resample_func)(struct ResampleContext *c, void *dst, + const void *src, int n, int update_ctx); + + dst_size = FFMAX(FFMIN(dst_size, delta_n), 0); + if (dst_size > 0) { + /* resample_linear and resample_common should have same behavior + * when frac and dst_incr_mod are zero */ + resample_func = (c->linear && (c->frac || c->dst_incr_mod)) ? + c->dsp.resample_linear : c->dsp.resample_common; + for (i = 0; i < dst->ch_count; i++) + *consumed = resample_func(c, dst->ch[i], src->ch[i], dst_size, i+1 == dst->ch_count); + } + } + + if (c->compensation_distance) { + c->compensation_distance -= dst_size; + if (!c->compensation_distance) { + c->dst_incr = c->ideal_dst_incr; + c->dst_incr_div = c->dst_incr / c->src_incr; + c->dst_incr_mod = c->dst_incr % c->src_incr; + } + } + + return dst_size; +} + +static int64_t get_delay(struct SwrContext *s, int64_t base){ + ResampleContext *c = s->resample; + int64_t num = s->in_buffer_count - (c->filter_length-1)/2; + num *= c->phase_count; + num -= c->index; + num *= c->src_incr; + num -= c->frac; + return av_rescale(num, base, s->in_sample_rate*(int64_t)c->src_incr * c->phase_count); +} + +static int64_t get_out_samples(struct SwrContext *s, int in_samples) { + ResampleContext *c = s->resample; + // The + 2 are added to allow implementations to be slightly inaccurate, they should not be needed currently. + // They also make it easier to proof that changes and optimizations do not + // break the upper bound. + int64_t num = s->in_buffer_count + 2LL + in_samples; + num *= c->phase_count; + num -= c->index; + num = av_rescale_rnd(num, s->out_sample_rate, ((int64_t)s->in_sample_rate) * c->phase_count, AV_ROUND_UP) + 2; + + if (c->compensation_distance) { + if (num > INT_MAX) + return AVERROR(EINVAL); + + num = FFMAX(num, (num * c->ideal_dst_incr - 1) / c->dst_incr + 1); + } + return num; +} + +static int resample_flush(struct SwrContext *s) { + ResampleContext *c = s->resample; + AudioData *a= &s->in_buffer; + int i, j, ret; + int reflection = (FFMIN(s->in_buffer_count, c->filter_length) + 1) / 2; + + if((ret = swri_realloc_audio(a, s->in_buffer_index + s->in_buffer_count + reflection)) < 0) + return ret; + av_assert0(a->planar); + for(i=0; i<a->ch_count; i++){ + for(j=0; j<reflection; j++){ + memcpy(a->ch[i] + (s->in_buffer_index+s->in_buffer_count+j )*a->bps, + a->ch[i] + (s->in_buffer_index+s->in_buffer_count-j-1)*a->bps, a->bps); + } + } + s->in_buffer_count += reflection; + return 0; +} + +// in fact the whole handle multiple ridiculously small buffers might need more thinking... +static int invert_initial_buffer(ResampleContext *c, AudioData *dst, const AudioData *src, + int in_count, int *out_idx, int *out_sz) +{ + int n, ch, num = FFMIN(in_count + *out_sz, c->filter_length + 1), res; + + if (c->index >= 0) + return 0; + + if ((res = swri_realloc_audio(dst, c->filter_length * 2 + 1)) < 0) + return res; + + // copy + for (n = *out_sz; n < num; n++) { + for (ch = 0; ch < src->ch_count; ch++) { + memcpy(dst->ch[ch] + ((c->filter_length + n) * c->felem_size), + src->ch[ch] + ((n - *out_sz) * c->felem_size), c->felem_size); + } + } + + // if not enough data is in, return and wait for more + if (num < c->filter_length + 1) { + *out_sz = num; + *out_idx = c->filter_length; + return INT_MAX; + } + + // else invert + for (n = 1; n <= c->filter_length; n++) { + for (ch = 0; ch < src->ch_count; ch++) { + memcpy(dst->ch[ch] + ((c->filter_length - n) * c->felem_size), + dst->ch[ch] + ((c->filter_length + n) * c->felem_size), + c->felem_size); + } + } + + res = num - *out_sz; + *out_idx = c->filter_length; + while (c->index < 0) { + --*out_idx; + c->index += c->phase_count; + } + *out_sz = FFMAX(*out_sz + c->filter_length, + 1 + c->filter_length * 2) - *out_idx; + + return FFMAX(res, 0); +} + +const struct Resampler swri_resampler = { + .init = resample_init, + .free = resample_free, + .multiple_resample = multiple_resample, + .flush = resample_flush, + .set_compensation = set_compensation, + .get_delay = get_delay, + .invert_initial_buffer = invert_initial_buffer, + .get_out_samples = get_out_samples, +}; diff --git a/libs/ffmpeg/libswresample/resample.h b/libs/ffmpeg/libswresample/resample.h new file mode 100644 index 00000000000..1731dad3cf8 --- /dev/null +++ b/libs/ffmpeg/libswresample/resample.h @@ -0,0 +1,68 @@ +/* + * audio resampling + * Copyright (c) 2004-2012 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWRESAMPLE_RESAMPLE_H +#define SWRESAMPLE_RESAMPLE_H + +#include "libavutil/log.h" +#include "libavutil/samplefmt.h" + +#include "swresample_internal.h" + +typedef struct ResampleContext { + const AVClass *av_class; + uint8_t *filter_bank; + int filter_length; + int filter_alloc; + int ideal_dst_incr; + int dst_incr; + int dst_incr_div; + int dst_incr_mod; + int index; + int frac; + int src_incr; + int compensation_distance; + int phase_count; + int linear; + enum SwrFilterType filter_type; + double kaiser_beta; + double factor; + enum AVSampleFormat format; + int felem_size; + int filter_shift; + int phase_count_compensation; /* desired phase_count when compensation is enabled */ + + struct { + void (*resample_one)(void *dst, const void *src, + int n, int64_t index, int64_t incr); + int (*resample_common)(struct ResampleContext *c, void *dst, + const void *src, int n, int update_ctx); + int (*resample_linear)(struct ResampleContext *c, void *dst, + const void *src, int n, int update_ctx); + } dsp; +} ResampleContext; + +void swri_resample_dsp_init(ResampleContext *c); +void swri_resample_dsp_x86_init(ResampleContext *c); +void swri_resample_dsp_arm_init(ResampleContext *c); +void swri_resample_dsp_aarch64_init(ResampleContext *c); + +#endif /* SWRESAMPLE_RESAMPLE_H */ diff --git a/libs/ffmpeg/libswresample/resample_dsp.c b/libs/ffmpeg/libswresample/resample_dsp.c new file mode 100644 index 00000000000..96f567fe323 --- /dev/null +++ b/libs/ffmpeg/libswresample/resample_dsp.c @@ -0,0 +1,78 @@ +/* + * audio resampling + * Copyright (c) 2004-2012 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * audio resampling + * @author Michael Niedermayer <michaelni@gmx.at> + */ + +#include "resample.h" + +#define TEMPLATE_RESAMPLE_S16 +#include "resample_template.c" +#undef TEMPLATE_RESAMPLE_S16 + +#define TEMPLATE_RESAMPLE_S32 +#include "resample_template.c" +#undef TEMPLATE_RESAMPLE_S32 + +#define TEMPLATE_RESAMPLE_FLT +#include "resample_template.c" +#undef TEMPLATE_RESAMPLE_FLT + +#define TEMPLATE_RESAMPLE_DBL +#include "resample_template.c" +#undef TEMPLATE_RESAMPLE_DBL + +void swri_resample_dsp_init(ResampleContext *c) +{ + switch(c->format){ + case AV_SAMPLE_FMT_S16P: + c->dsp.resample_one = resample_one_int16; + c->dsp.resample_common = resample_common_int16; + c->dsp.resample_linear = resample_linear_int16; + break; + case AV_SAMPLE_FMT_S32P: + c->dsp.resample_one = resample_one_int32; + c->dsp.resample_common = resample_common_int32; + c->dsp.resample_linear = resample_linear_int32; + break; + case AV_SAMPLE_FMT_FLTP: + c->dsp.resample_one = resample_one_float; + c->dsp.resample_common = resample_common_float; + c->dsp.resample_linear = resample_linear_float; + break; + case AV_SAMPLE_FMT_DBLP: + c->dsp.resample_one = resample_one_double; + c->dsp.resample_common = resample_common_double; + c->dsp.resample_linear = resample_linear_double; + break; + } + +#if ARCH_X86 && HAVE_X86ASM + swri_resample_dsp_x86_init(c); +#elif ARCH_ARM + swri_resample_dsp_arm_init(c); +#elif ARCH_AARCH64 + swri_resample_dsp_aarch64_init(c); +#endif +} diff --git a/libs/ffmpeg/libswresample/resample_template.c b/libs/ffmpeg/libswresample/resample_template.c new file mode 100644 index 00000000000..65682cc3875 --- /dev/null +++ b/libs/ffmpeg/libswresample/resample_template.c @@ -0,0 +1,223 @@ +/* + * audio resampling + * Copyright (c) 2004-2012 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if 0 +#pragma makedep header +#endif + +/** + * @file + * audio resampling + * @author Michael Niedermayer <michaelni@gmx.at> + */ + +// FELEM2U, a variant of FELEM2 which does not produce undefined overflow + +#if defined(TEMPLATE_RESAMPLE_DBL) + +# define RENAME(N) N ## _double +# define FILTER_SHIFT 0 +# define DELEM double +# define FELEM double +# define FELEM2 double +# define FELEM2U double +# define FOFFSET 0 +# define OUT(d, v) d = v + +#elif defined(TEMPLATE_RESAMPLE_FLT) + +# define RENAME(N) N ## _float +# define FILTER_SHIFT 0 +# define DELEM float +# define FELEM float +# define FELEM2 float +# define FELEM2U float +# define FOFFSET 0 +# define OUT(d, v) d = v + +#elif defined(TEMPLATE_RESAMPLE_S32) + +# define RENAME(N) N ## _int32 +# define FILTER_SHIFT 30 +# define DELEM int32_t +# define FELEM int32_t +# define FELEM2 int64_t +# define FELEM2U uint64_t +# define FELEM_MAX INT32_MAX +# define FELEM_MIN INT32_MIN +# define FOFFSET (1<<(FILTER_SHIFT-1)) +# define OUT(d, v) (d) = av_clipl_int32((v)>>FILTER_SHIFT) + +#elif defined(TEMPLATE_RESAMPLE_S16) + +# define RENAME(N) N ## _int16 +# define FILTER_SHIFT 15 +# define DELEM int16_t +# define FELEM int16_t +# define FELEM2 int32_t +# define FELEM2U uint32_t +# define FELEML int64_t +# define FELEM_MAX INT16_MAX +# define FELEM_MIN INT16_MIN +# define FOFFSET (1<<(FILTER_SHIFT-1)) +# define OUT(d, v) (d) = av_clip_int16((v)>>FILTER_SHIFT) + +#endif + +static void RENAME(resample_one)(void *dest, const void *source, + int dst_size, int64_t index2, int64_t incr) +{ + DELEM *dst = dest; + const DELEM *src = source; + int dst_index; + + for (dst_index = 0; dst_index < dst_size; dst_index++) { + dst[dst_index] = src[index2 >> 32]; + index2 += incr; + } +} + +static int RENAME(resample_common)(ResampleContext *c, + void *dest, const void *source, + int n, int update_ctx) +{ + DELEM *dst = dest; + const DELEM *src = source; + int dst_index; + int index= c->index; + int frac= c->frac; + int sample_index = 0; + + while (index >= c->phase_count) { + sample_index++; + index -= c->phase_count; + } + + for (dst_index = 0; dst_index < n; dst_index++) { + FELEM *filter = ((FELEM *) c->filter_bank) + c->filter_alloc * index; + + FELEM2 val = FOFFSET; + FELEM2 val2= 0; + int i; + for (i = 0; i + 1 < c->filter_length; i+=2) { + val += src[sample_index + i ] * (FELEM2)filter[i ]; + val2 += src[sample_index + i + 1] * (FELEM2)filter[i + 1]; + } + if (i < c->filter_length) + val += src[sample_index + i ] * (FELEM2)filter[i ]; +#ifdef FELEML + OUT(dst[dst_index], val + (FELEML)val2); +#else + OUT(dst[dst_index], val + val2); +#endif + + frac += c->dst_incr_mod; + index += c->dst_incr_div; + if (frac >= c->src_incr) { + frac -= c->src_incr; + index++; + } + + while (index >= c->phase_count) { + sample_index++; + index -= c->phase_count; + } + } + + if(update_ctx){ + c->frac= frac; + c->index= index; + } + + return sample_index; +} + +static int RENAME(resample_linear)(ResampleContext *c, + void *dest, const void *source, + int n, int update_ctx) +{ + DELEM *dst = dest; + const DELEM *src = source; + int dst_index; + int index= c->index; + int frac= c->frac; + int sample_index = 0; +#if FILTER_SHIFT == 0 + double inv_src_incr = 1.0 / c->src_incr; +#endif + + while (index >= c->phase_count) { + sample_index++; + index -= c->phase_count; + } + + for (dst_index = 0; dst_index < n; dst_index++) { + FELEM *filter = ((FELEM *) c->filter_bank) + c->filter_alloc * index; + FELEM2U val = FOFFSET, v2 = FOFFSET; + + int i; + for (i = 0; i < c->filter_length; i++) { + val += src[sample_index + i] * (FELEM2)filter[i]; + v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_alloc]; + } +#ifdef FELEML + val += (FELEM2)(v2 - val) * (FELEML) frac / c->src_incr; +#else +# if FILTER_SHIFT == 0 + val += (FELEM2)(v2 - val) * inv_src_incr * frac; +# else + val += (FELEM2)(v2 - val) / c->src_incr * frac; +# endif +#endif + OUT(dst[dst_index], (FELEM2)val); + + frac += c->dst_incr_mod; + index += c->dst_incr_div; + if (frac >= c->src_incr) { + frac -= c->src_incr; + index++; + } + + while (index >= c->phase_count) { + sample_index++; + index -= c->phase_count; + } + } + + if(update_ctx){ + c->frac= frac; + c->index= index; + } + + return sample_index; +} + +#undef RENAME +#undef FILTER_SHIFT +#undef DELEM +#undef FELEM +#undef FELEM2 +#undef FELEM2U +#undef FELEML +#undef FELEM_MAX +#undef FELEM_MIN +#undef OUT +#undef FOFFSET diff --git a/libs/ffmpeg/libswresample/swresample.c b/libs/ffmpeg/libswresample/swresample.c new file mode 100644 index 00000000000..d777efd802f --- /dev/null +++ b/libs/ffmpeg/libswresample/swresample.c @@ -0,0 +1,961 @@ +/* + * Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "swresample_internal.h" +#include "audioconvert.h" +#include "libavutil/avassert.h" +#include "libavutil/channel_layout.h" +#include "libavutil/internal.h" + +#include <float.h> + +#define ALIGN 32 + +int swri_check_chlayout(struct SwrContext *s, const AVChannelLayout *chl, const char *name) { + char l1[1024]; + int ret; + + if (!(ret = av_channel_layout_check(chl)) || chl->nb_channels > SWR_CH_MAX) { + if (ret) + av_channel_layout_describe(chl, l1, sizeof(l1)); + av_log(s, AV_LOG_WARNING, "%s channel layout \"%s\" is invalid or unsupported.\n", name, ret ? l1 : ""); + return AVERROR(EINVAL); + } + + return 0; +} + +int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map){ + if(!s || s->in_convert) // s needs to be allocated but not initialized + return AVERROR(EINVAL); + s->channel_map = channel_map; + return 0; +} + +int swr_alloc_set_opts2(struct SwrContext **ps, + const AVChannelLayout *out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, + const AVChannelLayout *in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, + int log_offset, void *log_ctx) { + struct SwrContext *s = *ps; + int ret; + + if (!s) s = swr_alloc(); + if (!s) return AVERROR(ENOMEM); + + *ps = s; + + s->log_level_offset = log_offset; + s->log_ctx = log_ctx; + + if ((ret = av_opt_set_chlayout(s, "ochl", out_ch_layout, 0)) < 0) + goto fail; + if ((ret = swri_check_chlayout(s, out_ch_layout, "ochl")) < 0) + goto fail; + + if ((ret = av_opt_set_int(s, "osf", out_sample_fmt, 0)) < 0) + goto fail; + + if ((ret = av_opt_set_int(s, "osr", out_sample_rate, 0)) < 0) + goto fail; + + if ((ret = av_opt_set_chlayout(s, "ichl", in_ch_layout, 0)) < 0) + goto fail; + if ((ret = swri_check_chlayout(s, in_ch_layout, "ichl")) < 0) + goto fail; + + if ((ret = av_opt_set_int(s, "isf", in_sample_fmt, 0)) < 0) + goto fail; + + if ((ret = av_opt_set_int(s, "isr", in_sample_rate, 0)) < 0) + goto fail; + + return 0; +fail: + av_log(s, AV_LOG_ERROR, "Failed to set option\n"); + swr_free(ps); + return ret; +} + +static void set_audiodata_fmt(AudioData *a, enum AVSampleFormat fmt){ + a->fmt = fmt; + a->bps = av_get_bytes_per_sample(fmt); + a->planar= av_sample_fmt_is_planar(fmt); + if (a->ch_count == 1) + a->planar = 1; +} + +static void free_temp(AudioData *a){ + av_free(a->data); + memset(a, 0, sizeof(*a)); +} + +static void clear_context(SwrContext *s){ + s->in_buffer_index= 0; + s->in_buffer_count= 0; + s->resample_in_constraint= 0; + memset(s->in.ch, 0, sizeof(s->in.ch)); + memset(s->out.ch, 0, sizeof(s->out.ch)); + free_temp(&s->postin); + free_temp(&s->midbuf); + free_temp(&s->preout); + free_temp(&s->in_buffer); + free_temp(&s->silence); + free_temp(&s->drop_temp); + free_temp(&s->dither.noise); + free_temp(&s->dither.temp); + av_channel_layout_uninit(&s->in_ch_layout); + av_channel_layout_uninit(&s->out_ch_layout); + av_channel_layout_uninit(&s->used_ch_layout); + swri_audio_convert_free(&s-> in_convert); + swri_audio_convert_free(&s->out_convert); + swri_audio_convert_free(&s->full_convert); + swri_rematrix_free(s); + + s->delayed_samples_fixup = 0; + s->flushed = 0; +} + +av_cold void swr_free(SwrContext **ss){ + SwrContext *s= *ss; + if(s){ + clear_context(s); + av_channel_layout_uninit(&s->user_in_chlayout); + av_channel_layout_uninit(&s->user_out_chlayout); + av_channel_layout_uninit(&s->user_used_chlayout); + + if (s->resampler) + s->resampler->free(&s->resample); + } + + av_freep(ss); +} + +av_cold void swr_close(SwrContext *s){ + clear_context(s); +} + +av_cold int swr_init(struct SwrContext *s){ + int ret; + char l1[1024], l2[1024]; + + clear_context(s); + + if((unsigned) s-> in_sample_fmt >= AV_SAMPLE_FMT_NB){ + av_log(s, AV_LOG_ERROR, "Requested input sample format %d is invalid\n", s->in_sample_fmt); + return AVERROR(EINVAL); + } + if((unsigned) s->out_sample_fmt >= AV_SAMPLE_FMT_NB){ + av_log(s, AV_LOG_ERROR, "Requested output sample format %d is invalid\n", s->out_sample_fmt); + return AVERROR(EINVAL); + } + + if(s-> in_sample_rate <= 0){ + av_log(s, AV_LOG_ERROR, "Requested input sample rate %d is invalid\n", s->in_sample_rate); + return AVERROR(EINVAL); + } + if(s->out_sample_rate <= 0){ + av_log(s, AV_LOG_ERROR, "Requested output sample rate %d is invalid\n", s->out_sample_rate); + return AVERROR(EINVAL); + } + + s->out.ch_count = s-> user_out_chlayout.nb_channels; + s-> in.ch_count = s-> user_in_chlayout.nb_channels; + + if (swri_check_chlayout(s, &s->user_in_chlayout , "input") || + swri_check_chlayout(s, &s->user_out_chlayout, "output")) + return AVERROR(EINVAL); + + ret = av_channel_layout_copy(&s->in_ch_layout, &s->user_in_chlayout); + ret |= av_channel_layout_copy(&s->out_ch_layout, &s->user_out_chlayout); + ret |= av_channel_layout_copy(&s->used_ch_layout, &s->user_used_chlayout); + if (ret < 0) + return ret; + + s->int_sample_fmt= s->user_int_sample_fmt; + + s->dither.method = s->user_dither_method; + + switch(s->engine){ +#if CONFIG_LIBSOXR + case SWR_ENGINE_SOXR: s->resampler = &swri_soxr_resampler; break; +#endif + case SWR_ENGINE_SWR : s->resampler = &swri_resampler; break; + default: + av_log(s, AV_LOG_ERROR, "Requested resampling engine is unavailable\n"); + return AVERROR(EINVAL); + } + + if (!av_channel_layout_check(&s->used_ch_layout)) + av_channel_layout_default(&s->used_ch_layout, s->in.ch_count); + + if (s->used_ch_layout.nb_channels != s->in_ch_layout.nb_channels) + av_channel_layout_uninit(&s->in_ch_layout); + + if (s->used_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) + av_channel_layout_default(&s->used_ch_layout, s->used_ch_layout.nb_channels); + if (s->in_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) { + ret = av_channel_layout_copy(&s->in_ch_layout, &s->used_ch_layout); + if (ret < 0) + return ret; + } + if (s->out_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) + av_channel_layout_default(&s->out_ch_layout, s->out.ch_count); + + s->rematrix = av_channel_layout_compare(&s->out_ch_layout, &s->in_ch_layout) || + s->rematrix_volume!=1.0 || + s->rematrix_custom; + + if(s->int_sample_fmt == AV_SAMPLE_FMT_NONE){ + // 16bit or less to 16bit or less with the same sample rate + if( av_get_bytes_per_sample(s-> in_sample_fmt) <= 2 + && av_get_bytes_per_sample(s->out_sample_fmt) <= 2 + && s->out_sample_rate==s->in_sample_rate) { + s->int_sample_fmt= AV_SAMPLE_FMT_S16P; + // 8 -> 8, 16->8, 8->16bit + } else if( av_get_bytes_per_sample(s-> in_sample_fmt) + +av_get_bytes_per_sample(s->out_sample_fmt) <= 3 ) { + s->int_sample_fmt= AV_SAMPLE_FMT_S16P; + }else if( av_get_bytes_per_sample(s-> in_sample_fmt) <= 2 + && !s->rematrix + && s->out_sample_rate==s->in_sample_rate + && !(s->flags & SWR_FLAG_RESAMPLE)){ + s->int_sample_fmt= AV_SAMPLE_FMT_S16P; + }else if( av_get_planar_sample_fmt(s-> in_sample_fmt) == AV_SAMPLE_FMT_S32P + && av_get_planar_sample_fmt(s->out_sample_fmt) == AV_SAMPLE_FMT_S32P + && !s->rematrix + && s->out_sample_rate == s->in_sample_rate + && !(s->flags & SWR_FLAG_RESAMPLE) + && s->engine != SWR_ENGINE_SOXR){ + s->int_sample_fmt= AV_SAMPLE_FMT_S32P; + }else if(av_get_bytes_per_sample(s->in_sample_fmt) <= 4){ + s->int_sample_fmt= AV_SAMPLE_FMT_FLTP; + }else{ + s->int_sample_fmt= AV_SAMPLE_FMT_DBLP; + } + } + av_log(s, AV_LOG_DEBUG, "Using %s internally between filters\n", av_get_sample_fmt_name(s->int_sample_fmt)); + + if( s->int_sample_fmt != AV_SAMPLE_FMT_S16P + &&s->int_sample_fmt != AV_SAMPLE_FMT_S32P + &&s->int_sample_fmt != AV_SAMPLE_FMT_S64P + &&s->int_sample_fmt != AV_SAMPLE_FMT_FLTP + &&s->int_sample_fmt != AV_SAMPLE_FMT_DBLP){ + av_log(s, AV_LOG_ERROR, "Requested sample format %s is not supported internally, s16p/s32p/s64p/fltp/dblp are supported\n", av_get_sample_fmt_name(s->int_sample_fmt)); + return AVERROR(EINVAL); + } + + set_audiodata_fmt(&s-> in, s-> in_sample_fmt); + set_audiodata_fmt(&s->out, s->out_sample_fmt); + + if (s->firstpts_in_samples != AV_NOPTS_VALUE) { + if (!s->async && s->min_compensation >= FLT_MAX/2) + s->async = 1; + if (s->firstpts == AV_NOPTS_VALUE) + s->firstpts = + s->outpts = s->firstpts_in_samples * s->out_sample_rate; + } else + s->firstpts = AV_NOPTS_VALUE; + + if (s->async) { + if (s->min_compensation >= FLT_MAX/2) + s->min_compensation = 0.001; + if (s->async > 1.0001) { + s->max_soft_compensation = s->async / (double) s->in_sample_rate; + } + } + + if (s->out_sample_rate!=s->in_sample_rate || (s->flags & SWR_FLAG_RESAMPLE)){ + s->resample = s->resampler->init(s->resample, s->out_sample_rate, s->in_sample_rate, s->filter_size, s->phase_shift, s->linear_interp, s->cutoff, s->int_sample_fmt, s->filter_type, s->kaiser_beta, s->precision, s->cheby, s->exact_rational); + if (!s->resample) { + av_log(s, AV_LOG_ERROR, "Failed to initialize resampler\n"); + return AVERROR(ENOMEM); + } + }else + s->resampler->free(&s->resample); + if( s->int_sample_fmt != AV_SAMPLE_FMT_S16P + && s->int_sample_fmt != AV_SAMPLE_FMT_S32P + && s->int_sample_fmt != AV_SAMPLE_FMT_FLTP + && s->int_sample_fmt != AV_SAMPLE_FMT_DBLP + && s->resample){ + av_log(s, AV_LOG_ERROR, "Resampling only supported with internal s16p/s32p/fltp/dblp\n"); + ret = AVERROR(EINVAL); + goto fail; + } + +#define RSC 1 //FIXME finetune + if(!s-> in.ch_count) + s-> in.ch_count = s->in_ch_layout.nb_channels; + if (!av_channel_layout_check(&s->used_ch_layout)) + av_channel_layout_default(&s->used_ch_layout, s->in.ch_count); + if(!s->out.ch_count) + s->out.ch_count = s->out_ch_layout.nb_channels; + + if(!s-> in.ch_count){ + av_assert0(s->in_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC); + av_log(s, AV_LOG_ERROR, "Input channel count and layout are unset\n"); + ret = AVERROR(EINVAL); + goto fail; + } + + av_channel_layout_describe(&s->out_ch_layout, l2, sizeof(l2)); + av_channel_layout_describe(&s->in_ch_layout, l1, sizeof(l1)); + if (s->in_ch_layout.order != AV_CHANNEL_ORDER_UNSPEC && s->used_ch_layout.nb_channels != s->in_ch_layout.nb_channels) { + av_log(s, AV_LOG_ERROR, "Input channel layout %s mismatches specified channel count %d\n", l1, s->used_ch_layout.nb_channels); + ret = AVERROR(EINVAL); + goto fail; + } + + if (( s->out_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC + || s-> in_ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) && s->used_ch_layout.nb_channels != s->out.ch_count && !s->rematrix_custom) { + av_log(s, AV_LOG_ERROR, "Rematrix is needed between %s and %s " + "but there is not enough information to do it\n", l1, l2); + ret = AVERROR(EINVAL); + goto fail; + } + +av_assert0(s->used_ch_layout.nb_channels); +av_assert0(s->out.ch_count); + s->resample_first= RSC*s->out.ch_count/s->used_ch_layout.nb_channels - RSC < s->out_sample_rate/(float)s-> in_sample_rate - 1.0; + + s->in_buffer= s->in; + s->silence = s->in; + s->drop_temp= s->out; + + if ((ret = swri_dither_init(s, s->out_sample_fmt, s->int_sample_fmt)) < 0) + goto fail; + + if(!s->resample && !s->rematrix && !s->channel_map && !s->dither.method){ + s->full_convert = swri_audio_convert_alloc(s->out_sample_fmt, + s-> in_sample_fmt, s-> in.ch_count, NULL, 0); + return 0; + } + + s->in_convert = swri_audio_convert_alloc(s->int_sample_fmt, + s-> in_sample_fmt, s->used_ch_layout.nb_channels, s->channel_map, 0); + s->out_convert= swri_audio_convert_alloc(s->out_sample_fmt, + s->int_sample_fmt, s->out.ch_count, NULL, 0); + + if (!s->in_convert || !s->out_convert) { + ret = AVERROR(ENOMEM); + goto fail; + } + + s->postin= s->in; + s->preout= s->out; + s->midbuf= s->in; + + if(s->channel_map){ + s->postin.ch_count= + s->midbuf.ch_count= s->used_ch_layout.nb_channels; + if(s->resample) + s->in_buffer.ch_count= s->used_ch_layout.nb_channels; + } + if(!s->resample_first){ + s->midbuf.ch_count= s->out.ch_count; + if(s->resample) + s->in_buffer.ch_count = s->out.ch_count; + } + + set_audiodata_fmt(&s->postin, s->int_sample_fmt); + set_audiodata_fmt(&s->midbuf, s->int_sample_fmt); + set_audiodata_fmt(&s->preout, s->int_sample_fmt); + + if(s->resample){ + set_audiodata_fmt(&s->in_buffer, s->int_sample_fmt); + } + + av_assert0(!s->preout.count); + s->dither.noise = s->preout; + s->dither.temp = s->preout; + if (s->dither.method > SWR_DITHER_NS) { + s->dither.noise.bps = 4; + s->dither.noise.fmt = AV_SAMPLE_FMT_FLTP; + s->dither.noise_scale = 1; + } + + if(s->rematrix || s->dither.method) { + ret = swri_rematrix_init(s); + if (ret < 0) + goto fail; + } + + return 0; +fail: + swr_close(s); + return ret; + +} + +int swri_realloc_audio(AudioData *a, int count){ + int i, countb; + AudioData old; + + if(count < 0 || count > INT_MAX/2/a->bps/a->ch_count) + return AVERROR(EINVAL); + + if(a->count >= count) + return 0; + + count*=2; + + countb= FFALIGN(count*a->bps, ALIGN); + old= *a; + + av_assert0(a->bps); + av_assert0(a->ch_count); + + a->data = av_calloc(countb, a->ch_count); + if(!a->data) + return AVERROR(ENOMEM); + for(i=0; i<a->ch_count; i++){ + a->ch[i]= a->data + i*(a->planar ? countb : a->bps); + if(a->count && a->planar) memcpy(a->ch[i], old.ch[i], a->count*a->bps); + } + if(a->count && !a->planar) memcpy(a->ch[0], old.ch[0], a->count*a->ch_count*a->bps); + av_freep(&old.data); + a->count= count; + + return 1; +} + +static void copy(AudioData *out, AudioData *in, + int count){ + av_assert0(out->planar == in->planar); + av_assert0(out->bps == in->bps); + av_assert0(out->ch_count == in->ch_count); + if(out->planar){ + int ch; + for(ch=0; ch<out->ch_count; ch++) + memcpy(out->ch[ch], in->ch[ch], count*out->bps); + }else + memcpy(out->ch[0], in->ch[0], count*out->ch_count*out->bps); +} + +static void fill_audiodata(AudioData *out, uint8_t *const in_arg [SWR_CH_MAX]) +{ + int i; + if(!in_arg){ + memset(out->ch, 0, sizeof(out->ch)); + }else if(out->planar){ + for(i=0; i<out->ch_count; i++) + out->ch[i]= in_arg[i]; + }else{ + for(i=0; i<out->ch_count; i++) + out->ch[i]= in_arg[0] + i*out->bps; + } +} + +static void reversefill_audiodata(AudioData *out, uint8_t *in_arg [SWR_CH_MAX]){ + int i; + if(out->planar){ + for(i=0; i<out->ch_count; i++) + in_arg[i]= out->ch[i]; + }else{ + in_arg[0]= out->ch[0]; + } +} + +/** + * + * out may be equal in. + */ +static void buf_set(AudioData *out, AudioData *in, int count){ + int ch; + if(in->planar){ + for(ch=0; ch<out->ch_count; ch++) + out->ch[ch]= in->ch[ch] + count*out->bps; + }else{ + for(ch=out->ch_count-1; ch>=0; ch--) + out->ch[ch]= in->ch[0] + (ch + count*out->ch_count) * out->bps; + } +} + +/** + * + * @return number of samples output per channel + */ +static int resample(SwrContext *s, AudioData *out_param, int out_count, + const AudioData * in_param, int in_count){ + AudioData in, out, tmp; + int ret_sum=0; + int border=0; + int padless = ARCH_X86 && s->engine == SWR_ENGINE_SWR ? 7 : 0; + + av_assert1(s->in_buffer.ch_count == in_param->ch_count); + av_assert1(s->in_buffer.planar == in_param->planar); + av_assert1(s->in_buffer.fmt == in_param->fmt); + + tmp=out=*out_param; + in = *in_param; + + border = s->resampler->invert_initial_buffer(s->resample, &s->in_buffer, + &in, in_count, &s->in_buffer_index, &s->in_buffer_count); + if (border == INT_MAX) { + return 0; + } else if (border < 0) { + return border; + } else if (border) { + buf_set(&in, &in, border); + in_count -= border; + s->resample_in_constraint = 0; + } + + do{ + int ret, size, consumed; + if(!s->resample_in_constraint && s->in_buffer_count){ + buf_set(&tmp, &s->in_buffer, s->in_buffer_index); + ret= s->resampler->multiple_resample(s->resample, &out, out_count, &tmp, s->in_buffer_count, &consumed); + out_count -= ret; + ret_sum += ret; + buf_set(&out, &out, ret); + s->in_buffer_count -= consumed; + s->in_buffer_index += consumed; + + if(!in_count) + break; + if(s->in_buffer_count <= border){ + buf_set(&in, &in, -s->in_buffer_count); + in_count += s->in_buffer_count; + s->in_buffer_count=0; + s->in_buffer_index=0; + border = 0; + } + } + + if((s->flushed || in_count > padless) && !s->in_buffer_count){ + s->in_buffer_index=0; + ret= s->resampler->multiple_resample(s->resample, &out, out_count, &in, FFMAX(in_count-padless, 0), &consumed); + out_count -= ret; + ret_sum += ret; + buf_set(&out, &out, ret); + in_count -= consumed; + buf_set(&in, &in, consumed); + } + + //TODO is this check sane considering the advanced copy avoidance below + size= s->in_buffer_index + s->in_buffer_count + in_count; + if( size > s->in_buffer.count + && s->in_buffer_count + in_count <= s->in_buffer_index){ + buf_set(&tmp, &s->in_buffer, s->in_buffer_index); + copy(&s->in_buffer, &tmp, s->in_buffer_count); + s->in_buffer_index=0; + }else + if((ret=swri_realloc_audio(&s->in_buffer, size)) < 0) + return ret; + + if(in_count){ + int count= in_count; + if(s->in_buffer_count && s->in_buffer_count+2 < count && out_count) count= s->in_buffer_count+2; + + buf_set(&tmp, &s->in_buffer, s->in_buffer_index + s->in_buffer_count); + copy(&tmp, &in, /*in_*/count); + s->in_buffer_count += count; + in_count -= count; + border += count; + buf_set(&in, &in, count); + s->resample_in_constraint= 0; + if(s->in_buffer_count != count || in_count) + continue; + if (padless) { + padless = 0; + continue; + } + } + break; + }while(1); + + s->resample_in_constraint= !!out_count; + + return ret_sum; +} + +static int swr_convert_internal(struct SwrContext *s, AudioData *out, int out_count, + AudioData *in , int in_count){ + AudioData *postin, *midbuf, *preout; + int ret/*, in_max*/; + AudioData preout_tmp, midbuf_tmp; + + if(s->full_convert){ + av_assert0(!s->resample); + swri_audio_convert(s->full_convert, out, in, in_count); + return out_count; + } + +// in_max= out_count*(int64_t)s->in_sample_rate / s->out_sample_rate + resample_filter_taps; +// in_count= FFMIN(in_count, in_in + 2 - s->hist_buffer_count); + + if((ret=swri_realloc_audio(&s->postin, in_count))<0) + return ret; + if(s->resample_first){ + av_assert0(s->midbuf.ch_count == s->used_ch_layout.nb_channels); + if((ret=swri_realloc_audio(&s->midbuf, out_count))<0) + return ret; + }else{ + av_assert0(s->midbuf.ch_count == s->out.ch_count); + if((ret=swri_realloc_audio(&s->midbuf, in_count))<0) + return ret; + } + if((ret=swri_realloc_audio(&s->preout, out_count))<0) + return ret; + + postin= &s->postin; + + midbuf_tmp= s->midbuf; + midbuf= &midbuf_tmp; + preout_tmp= s->preout; + preout= &preout_tmp; + + if(s->int_sample_fmt == s-> in_sample_fmt && s->in.planar && !s->channel_map) + postin= in; + + if(s->resample_first ? !s->resample : !s->rematrix) + midbuf= postin; + + if(s->resample_first ? !s->rematrix : !s->resample) + preout= midbuf; + + if(s->int_sample_fmt == s->out_sample_fmt && s->out.planar + && !(s->out_sample_fmt==AV_SAMPLE_FMT_S32P && (s->dither.output_sample_bits&31))){ + if(preout==in){ + out_count= FFMIN(out_count, in_count); //TODO check at the end if this is needed or redundant + av_assert0(s->in.planar); //we only support planar internally so it has to be, we support copying non planar though + copy(out, in, out_count); + return out_count; + } + else if(preout==postin) preout= midbuf= postin= out; + else if(preout==midbuf) preout= midbuf= out; + else preout= out; + } + + if(in != postin){ + swri_audio_convert(s->in_convert, postin, in, in_count); + } + + if(s->resample_first){ + if(postin != midbuf) + if ((out_count = resample(s, midbuf, out_count, postin, in_count)) < 0) + return out_count; + if(midbuf != preout) + swri_rematrix(s, preout, midbuf, out_count, preout==out); + }else{ + if(postin != midbuf) + swri_rematrix(s, midbuf, postin, in_count, midbuf==out); + if(midbuf != preout) + if ((out_count = resample(s, preout, out_count, midbuf, in_count)) < 0) + return out_count; + } + + if(preout != out && out_count){ + AudioData *conv_src = preout; + if(s->dither.method){ + int ch; + int dither_count= FFMAX(out_count, 1<<16); + + if (preout == in) { + conv_src = &s->dither.temp; + if((ret=swri_realloc_audio(&s->dither.temp, dither_count))<0) + return ret; + } + + if((ret=swri_realloc_audio(&s->dither.noise, dither_count))<0) + return ret; + if(ret) + for(ch=0; ch<s->dither.noise.ch_count; ch++) + if((ret=swri_get_dither(s, s->dither.noise.ch[ch], s->dither.noise.count, (12345678913579ULL*ch + 3141592) % 2718281828U, s->dither.noise.fmt))<0) + return ret; + av_assert0(s->dither.noise.ch_count == preout->ch_count); + + if(s->dither.noise_pos + out_count > s->dither.noise.count) + s->dither.noise_pos = 0; + + if (s->dither.method < SWR_DITHER_NS){ + if (s->mix_2_1_simd) { + int len1= out_count&~15; + int off = len1 * preout->bps; + + if(len1) + for(ch=0; ch<preout->ch_count; ch++) + s->mix_2_1_simd(conv_src->ch[ch], preout->ch[ch], s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos, &s->native_simd_one, 0, 0, len1); + if(out_count != len1) + for(ch=0; ch<preout->ch_count; ch++) + s->mix_2_1_f(conv_src->ch[ch] + off, preout->ch[ch] + off, s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos + off, &s->native_one, 0, 0, out_count - len1); + } else { + for(ch=0; ch<preout->ch_count; ch++) + s->mix_2_1_f(conv_src->ch[ch], preout->ch[ch], s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos, &s->native_one, 0, 0, out_count); + } + } else { + switch(s->int_sample_fmt) { + case AV_SAMPLE_FMT_S16P :swri_noise_shaping_int16(s, conv_src, preout, &s->dither.noise, out_count); break; + case AV_SAMPLE_FMT_S32P :swri_noise_shaping_int32(s, conv_src, preout, &s->dither.noise, out_count); break; + case AV_SAMPLE_FMT_FLTP :swri_noise_shaping_float(s, conv_src, preout, &s->dither.noise, out_count); break; + case AV_SAMPLE_FMT_DBLP :swri_noise_shaping_double(s,conv_src, preout, &s->dither.noise, out_count); break; + } + } + s->dither.noise_pos += out_count; + } +//FIXME packed doesn't need more than 1 chan here! + swri_audio_convert(s->out_convert, out, conv_src, out_count); + } + return out_count; +} + +int swr_is_initialized(struct SwrContext *s) { + return !!s->in_buffer.ch_count; +} + +int attribute_align_arg swr_convert(struct SwrContext *s, + uint8_t * const *out_arg, int out_count, + const uint8_t * const *in_arg, int in_count) +{ + AudioData * in= &s->in; + AudioData *out= &s->out; + + if (!swr_is_initialized(s)) { + av_log(s, AV_LOG_ERROR, "Context has not been initialized\n"); + return AVERROR(EINVAL); + } +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL >1 + int max_output = swr_get_out_samples(s, in_count); +#endif + + while(s->drop_output > 0){ + int ret; + uint8_t *tmp_arg[SWR_CH_MAX]; +#define MAX_DROP_STEP 16384 + if((ret=swri_realloc_audio(&s->drop_temp, FFMIN(s->drop_output, MAX_DROP_STEP)))<0) + return ret; + + reversefill_audiodata(&s->drop_temp, tmp_arg); + s->drop_output *= -1; //FIXME find a less hackish solution + ret = swr_convert(s, tmp_arg, FFMIN(-s->drop_output, MAX_DROP_STEP), in_arg, in_count); //FIXME optimize but this is as good as never called so maybe it doesn't matter + s->drop_output *= -1; + in_count = 0; + if(ret>0) { + s->drop_output -= ret; + if (!s->drop_output && !out_arg) + return 0; + continue; + } + + av_assert0(s->drop_output); + return 0; + } + + if(!in_arg){ + if(s->resample){ + if (!s->flushed) + s->resampler->flush(s); + s->resample_in_constraint = 0; + s->flushed = 1; + }else if(!s->in_buffer_count){ + return 0; + } + }else + fill_audiodata(in , (void*)in_arg); + + fill_audiodata(out, out_arg); + + if(s->resample){ + int ret = swr_convert_internal(s, out, out_count, in, in_count); + if(ret>0 && !s->drop_output) + s->outpts += ret * (int64_t)s->in_sample_rate; + + av_assert2(max_output < 0 || ret <= max_output); + + return ret; + }else{ + AudioData tmp= *in; + int ret2=0; + int ret, size; + size = FFMIN(out_count, s->in_buffer_count); + if(size){ + buf_set(&tmp, &s->in_buffer, s->in_buffer_index); + ret= swr_convert_internal(s, out, size, &tmp, size); + if(ret<0) + return ret; + ret2= ret; + s->in_buffer_count -= ret; + s->in_buffer_index += ret; + buf_set(out, out, ret); + out_count -= ret; + if(!s->in_buffer_count) + s->in_buffer_index = 0; + } + + if(in_count){ + size= s->in_buffer_index + s->in_buffer_count + in_count - out_count; + + if(in_count > out_count) { //FIXME move after swr_convert_internal + if( size > s->in_buffer.count + && s->in_buffer_count + in_count - out_count <= s->in_buffer_index){ + buf_set(&tmp, &s->in_buffer, s->in_buffer_index); + copy(&s->in_buffer, &tmp, s->in_buffer_count); + s->in_buffer_index=0; + }else + if((ret=swri_realloc_audio(&s->in_buffer, size)) < 0) + return ret; + } + + if(out_count){ + size = FFMIN(in_count, out_count); + ret= swr_convert_internal(s, out, size, in, size); + if(ret<0) + return ret; + buf_set(in, in, ret); + in_count -= ret; + ret2 += ret; + } + if(in_count){ + buf_set(&tmp, &s->in_buffer, s->in_buffer_index + s->in_buffer_count); + copy(&tmp, in, in_count); + s->in_buffer_count += in_count; + } + } + if(ret2>0 && !s->drop_output) + s->outpts += ret2 * (int64_t)s->in_sample_rate; + av_assert2(max_output < 0 || ret2 < 0 || ret2 <= max_output); + return ret2; + } +} + +int swr_drop_output(struct SwrContext *s, int count){ + const uint8_t *tmp_arg[SWR_CH_MAX]; + s->drop_output += count; + + if(s->drop_output <= 0) + return 0; + + av_log(s, AV_LOG_VERBOSE, "discarding %d audio samples\n", count); + return swr_convert(s, NULL, s->drop_output, tmp_arg, 0); +} + +int swr_inject_silence(struct SwrContext *s, int count){ + int ret, i; + uint8_t *tmp_arg[SWR_CH_MAX]; + + if(count <= 0) + return 0; + +#define MAX_SILENCE_STEP 16384 + while (count > MAX_SILENCE_STEP) { + if ((ret = swr_inject_silence(s, MAX_SILENCE_STEP)) < 0) + return ret; + count -= MAX_SILENCE_STEP; + } + + if((ret=swri_realloc_audio(&s->silence, count))<0) + return ret; + + if(s->silence.planar) for(i=0; i<s->silence.ch_count; i++) { + memset(s->silence.ch[i], s->silence.bps==1 ? 0x80 : 0, count*s->silence.bps); + } else + memset(s->silence.ch[0], s->silence.bps==1 ? 0x80 : 0, count*s->silence.bps*s->silence.ch_count); + + reversefill_audiodata(&s->silence, tmp_arg); + av_log(s, AV_LOG_VERBOSE, "adding %d audio samples of silence\n", count); + ret = swr_convert(s, NULL, 0, (const uint8_t**)tmp_arg, count); + return ret; +} + +int64_t swr_get_delay(struct SwrContext *s, int64_t base){ + if (s->resampler && s->resample){ + return s->resampler->get_delay(s, base); + }else{ + return (s->in_buffer_count*base + (s->in_sample_rate>>1))/ s->in_sample_rate; + } +} + +int swr_get_out_samples(struct SwrContext *s, int in_samples) +{ + int64_t out_samples; + + if (in_samples < 0) + return AVERROR(EINVAL); + + if (s->resampler && s->resample) { + if (!s->resampler->get_out_samples) + return AVERROR(ENOSYS); + out_samples = s->resampler->get_out_samples(s, in_samples); + } else { + out_samples = s->in_buffer_count + in_samples; + av_assert0(s->out_sample_rate == s->in_sample_rate); + } + + if (out_samples > INT_MAX) + return AVERROR(EINVAL); + + return out_samples; +} + +int swr_set_compensation(struct SwrContext *s, int sample_delta, int compensation_distance){ + int ret; + + if (!s || compensation_distance < 0) + return AVERROR(EINVAL); + if (!compensation_distance && sample_delta) + return AVERROR(EINVAL); + if (!s->resample) { + s->flags |= SWR_FLAG_RESAMPLE; + ret = swr_init(s); + if (ret < 0) + return ret; + } + if (!s->resampler->set_compensation){ + return AVERROR(EINVAL); + }else{ + return s->resampler->set_compensation(s->resample, sample_delta, compensation_distance); + } +} + +int64_t swr_next_pts(struct SwrContext *s, int64_t pts){ + if(pts == INT64_MIN) + return s->outpts; + + if (s->firstpts == AV_NOPTS_VALUE) + s->outpts = s->firstpts = pts; + + if(s->min_compensation >= FLT_MAX) { + return (s->outpts = pts - swr_get_delay(s, s->in_sample_rate * (int64_t)s->out_sample_rate)); + } else { + int64_t delta = pts - swr_get_delay(s, s->in_sample_rate * (int64_t)s->out_sample_rate) - s->outpts + s->drop_output*(int64_t)s->in_sample_rate; + double fdelta = delta /(double)(s->in_sample_rate * (int64_t)s->out_sample_rate); + + if(fabs(fdelta) > s->min_compensation) { + if(s->outpts == s->firstpts || fabs(fdelta) > s->min_hard_compensation){ + int ret; + if(delta > 0) ret = swr_inject_silence(s, delta / s->out_sample_rate); + else ret = swr_drop_output (s, -delta / s-> in_sample_rate); + if(ret<0){ + av_log(s, AV_LOG_ERROR, "Failed to compensate for timestamp delta of %f\n", fdelta); + } + } else if(s->soft_compensation_duration && s->max_soft_compensation) { + int duration = s->out_sample_rate * s->soft_compensation_duration; + double max_soft_compensation = s->max_soft_compensation / (s->max_soft_compensation < 0 ? -s->in_sample_rate : 1); + int comp = av_clipf(fdelta, -max_soft_compensation, max_soft_compensation) * duration ; + av_log(s, AV_LOG_VERBOSE, "compensating audio timestamp drift:%f compensation:%d in:%d\n", fdelta, comp, duration); + swr_set_compensation(s, comp, duration); + } + } + + return s->outpts; + } +} diff --git a/libs/ffmpeg/libswresample/swresample.h b/libs/ffmpeg/libswresample/swresample.h new file mode 100644 index 00000000000..052089acca5 --- /dev/null +++ b/libs/ffmpeg/libswresample/swresample.h @@ -0,0 +1,587 @@ +/* + * Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWRESAMPLE_SWRESAMPLE_H +#define SWRESAMPLE_SWRESAMPLE_H + +/** + * @file + * @ingroup lswr + * libswresample public header + */ + +/** + * @defgroup lswr libswresample + * @{ + * + * Audio resampling, sample format conversion and mixing library. + * + * Interaction with lswr is done through SwrContext, which is + * allocated with swr_alloc() or swr_alloc_set_opts2(). It is opaque, so all parameters + * must be set with the @ref avoptions API. + * + * The first thing you will need to do in order to use lswr is to allocate + * SwrContext. This can be done with swr_alloc() or swr_alloc_set_opts2(). If you + * are using the former, you must set options through the @ref avoptions API. + * The latter function provides the same feature, but it allows you to set some + * common options in the same statement. + * + * For example the following code will setup conversion from planar float sample + * format to interleaved signed 16-bit integer, downsampling from 48kHz to + * 44.1kHz and downmixing from 5.1 channels to stereo (using the default mixing + * matrix). This is using the swr_alloc() function. + * @code + * SwrContext *swr = swr_alloc(); + * av_opt_set_chlayout(swr, "in_chlayout", &(AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1, 0); + * av_opt_set_chlayout(swr, "out_chlayout", &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO, 0); + * av_opt_set_int(swr, "in_sample_rate", 48000, 0); + * av_opt_set_int(swr, "out_sample_rate", 44100, 0); + * av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); + * av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); + * @endcode + * + * The same job can be done using swr_alloc_set_opts2() as well: + * @code + * SwrContext *swr = NULL; + * int ret = swr_alloc_set_opts2(&swr, // we're allocating a new context + * &(AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO, // out_ch_layout + * AV_SAMPLE_FMT_S16, // out_sample_fmt + * 44100, // out_sample_rate + * &(AVChannelLayout)AV_CHANNEL_LAYOUT_5POINT1, // in_ch_layout + * AV_SAMPLE_FMT_FLTP, // in_sample_fmt + * 48000, // in_sample_rate + * 0, // log_offset + * NULL); // log_ctx + * @endcode + * + * Once all values have been set, it must be initialized with swr_init(). If + * you need to change the conversion parameters, you can change the parameters + * using @ref avoptions, as described above in the first example; or by using + * swr_alloc_set_opts2(), but with the first argument the allocated context. + * You must then call swr_init() again. + * + * The conversion itself is done by repeatedly calling swr_convert(). + * Note that the samples may get buffered in swr if you provide insufficient + * output space or if sample rate conversion is done, which requires "future" + * samples. Samples that do not require future input can be retrieved at any + * time by using swr_convert() (in_count can be set to 0). + * At the end of conversion the resampling buffer can be flushed by calling + * swr_convert() with NULL in and 0 in_count. + * + * The samples used in the conversion process can be managed with the libavutil + * @ref lavu_sampmanip "samples manipulation" API, including av_samples_alloc() + * function used in the following example. + * + * The delay between input and output, can at any time be found by using + * swr_get_delay(). + * + * The following code demonstrates the conversion loop assuming the parameters + * from above and caller-defined functions get_input() and handle_output(): + * @code + * uint8_t **input; + * int in_samples; + * + * while (get_input(&input, &in_samples)) { + * uint8_t *output; + * int out_samples = av_rescale_rnd(swr_get_delay(swr, 48000) + + * in_samples, 44100, 48000, AV_ROUND_UP); + * av_samples_alloc(&output, NULL, 2, out_samples, + * AV_SAMPLE_FMT_S16, 0); + * out_samples = swr_convert(swr, &output, out_samples, + * input, in_samples); + * handle_output(output, out_samples); + * av_freep(&output); + * } + * @endcode + * + * When the conversion is finished, the conversion + * context and everything associated with it must be freed with swr_free(). + * A swr_close() function is also available, but it exists mainly for + * compatibility with libavresample, and is not required to be called. + * + * There will be no memory leak if the data is not completely flushed before + * swr_free(). + */ + +#include <stdint.h> +#include "libavutil/channel_layout.h" +#include "libavutil/frame.h" +#include "libavutil/samplefmt.h" + +#include "libswresample/version_major.h" +#ifndef HAVE_AV_CONFIG_H +/* When included as part of the ffmpeg build, only include the major version + * to avoid unnecessary rebuilds. When included externally, keep including + * the full version information. */ +#include "libswresample/version.h" +#endif + +/** + * @name Option constants + * These constants are used for the @ref avoptions interface for lswr. + * @{ + * + */ + +#define SWR_FLAG_RESAMPLE 1 ///< Force resampling even if equal sample rate +//TODO use int resample ? +//long term TODO can we enable this dynamically? + +/** Dithering algorithms */ +enum SwrDitherType { + SWR_DITHER_NONE = 0, + SWR_DITHER_RECTANGULAR, + SWR_DITHER_TRIANGULAR, + SWR_DITHER_TRIANGULAR_HIGHPASS, + + SWR_DITHER_NS = 64, ///< not part of API/ABI + SWR_DITHER_NS_LIPSHITZ, + SWR_DITHER_NS_F_WEIGHTED, + SWR_DITHER_NS_MODIFIED_E_WEIGHTED, + SWR_DITHER_NS_IMPROVED_E_WEIGHTED, + SWR_DITHER_NS_SHIBATA, + SWR_DITHER_NS_LOW_SHIBATA, + SWR_DITHER_NS_HIGH_SHIBATA, + SWR_DITHER_NB, ///< not part of API/ABI +}; + +/** Resampling Engines */ +enum SwrEngine { + SWR_ENGINE_SWR, /**< SW Resampler */ + SWR_ENGINE_SOXR, /**< SoX Resampler */ + SWR_ENGINE_NB, ///< not part of API/ABI +}; + +/** Resampling Filter Types */ +enum SwrFilterType { + SWR_FILTER_TYPE_CUBIC, /**< Cubic */ + SWR_FILTER_TYPE_BLACKMAN_NUTTALL, /**< Blackman Nuttall windowed sinc */ + SWR_FILTER_TYPE_KAISER, /**< Kaiser windowed sinc */ +}; + +/** + * @} + */ + +/** + * The libswresample context. Unlike libavcodec and libavformat, this structure + * is opaque. This means that if you would like to set options, you must use + * the @ref avoptions API and cannot directly set values to members of the + * structure. + */ +typedef struct SwrContext SwrContext; + +/** + * Get the AVClass for SwrContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + * @return the AVClass of SwrContext + */ +const AVClass *swr_get_class(void); + +/** + * @name SwrContext constructor functions + * @{ + */ + +/** + * Allocate SwrContext. + * + * If you use this function you will need to set the parameters (manually or + * with swr_alloc_set_opts2()) before calling swr_init(). + * + * @see swr_alloc_set_opts2(), swr_init(), swr_free() + * @return NULL on error, allocated context otherwise + */ +struct SwrContext *swr_alloc(void); + +/** + * Initialize context after user parameters have been set. + * @note The context must be configured using the AVOption API. + * + * @see av_opt_set_int() + * @see av_opt_set_dict() + * + * @param[in,out] s Swr context to initialize + * @return AVERROR error code in case of failure. + */ +int swr_init(struct SwrContext *s); + +/** + * Check whether an swr context has been initialized or not. + * + * @param[in] s Swr context to check + * @see swr_init() + * @return positive if it has been initialized, 0 if not initialized + */ +int swr_is_initialized(struct SwrContext *s); + +/** + * Allocate SwrContext if needed and set/reset common parameters. + * + * This function does not require *ps to be allocated with swr_alloc(). On the + * other hand, swr_alloc() can use swr_alloc_set_opts2() to set the parameters + * on the allocated context. + * + * @param ps Pointer to an existing Swr context if available, or to NULL if not. + * On success, *ps will be set to the allocated context. + * @param out_ch_layout output channel layout (e.g. AV_CHANNEL_LAYOUT_*) + * @param out_sample_fmt output sample format (AV_SAMPLE_FMT_*). + * @param out_sample_rate output sample rate (frequency in Hz) + * @param in_ch_layout input channel layout (e.g. AV_CHANNEL_LAYOUT_*) + * @param in_sample_fmt input sample format (AV_SAMPLE_FMT_*). + * @param in_sample_rate input sample rate (frequency in Hz) + * @param log_offset logging level offset + * @param log_ctx parent logging context, can be NULL + * + * @see swr_init(), swr_free() + * @return 0 on success, a negative AVERROR code on error. + * On error, the Swr context is freed and *ps set to NULL. + */ +int swr_alloc_set_opts2(struct SwrContext **ps, + const AVChannelLayout *out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate, + const AVChannelLayout *in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate, + int log_offset, void *log_ctx); +/** + * @} + * + * @name SwrContext destructor functions + * @{ + */ + +/** + * Free the given SwrContext and set the pointer to NULL. + * + * @param[in] s a pointer to a pointer to Swr context + */ +void swr_free(struct SwrContext **s); + +/** + * Closes the context so that swr_is_initialized() returns 0. + * + * The context can be brought back to life by running swr_init(), + * swr_init() can also be used without swr_close(). + * This function is mainly provided for simplifying the usecase + * where one tries to support libavresample and libswresample. + * + * @param[in,out] s Swr context to be closed + */ +void swr_close(struct SwrContext *s); + +/** + * @} + * + * @name Core conversion functions + * @{ + */ + +/** Convert audio. + * + * in and in_count can be set to 0 to flush the last few samples out at the + * end. + * + * If more input is provided than output space, then the input will be buffered. + * You can avoid this buffering by using swr_get_out_samples() to retrieve an + * upper bound on the required number of output samples for the given number of + * input samples. Conversion will run directly without copying whenever possible. + * + * @param s allocated Swr context, with parameters set + * @param out output buffers, only the first one need be set in case of packed audio + * @param out_count amount of space available for output in samples per channel + * @param in input buffers, only the first one need to be set in case of packed audio + * @param in_count number of input samples available in one channel + * + * @return number of samples output per channel, negative value on error + */ +int swr_convert(struct SwrContext *s, uint8_t * const *out, int out_count, + const uint8_t * const *in , int in_count); + +/** + * Convert the next timestamp from input to output + * timestamps are in 1/(in_sample_rate * out_sample_rate) units. + * + * @note There are 2 slightly differently behaving modes. + * @li When automatic timestamp compensation is not used, (min_compensation >= FLT_MAX) + * in this case timestamps will be passed through with delays compensated + * @li When automatic timestamp compensation is used, (min_compensation < FLT_MAX) + * in this case the output timestamps will match output sample numbers. + * See ffmpeg-resampler(1) for the two modes of compensation. + * + * @param[in] s initialized Swr context + * @param[in] pts timestamp for the next input sample, INT64_MIN if unknown + * @see swr_set_compensation(), swr_drop_output(), and swr_inject_silence() are + * function used internally for timestamp compensation. + * @return the output timestamp for the next output sample + */ +int64_t swr_next_pts(struct SwrContext *s, int64_t pts); + +/** + * @} + * + * @name Low-level option setting functions + * These functions provide a means to set low-level options that is not possible + * with the AVOption API. + * @{ + */ + +/** + * Activate resampling compensation ("soft" compensation). This function is + * internally called when needed in swr_next_pts(). + * + * @param[in,out] s allocated Swr context. If it is not initialized, + * or SWR_FLAG_RESAMPLE is not set, swr_init() is + * called with the flag set. + * @param[in] sample_delta delta in PTS per sample + * @param[in] compensation_distance number of samples to compensate for + * @return >= 0 on success, AVERROR error codes if: + * @li @c s is NULL, + * @li @c compensation_distance is less than 0, + * @li @c compensation_distance is 0 but sample_delta is not, + * @li compensation unsupported by resampler, or + * @li swr_init() fails when called. + */ +int swr_set_compensation(struct SwrContext *s, int sample_delta, int compensation_distance); + +/** + * Set a customized input channel mapping. + * + * @param[in,out] s allocated Swr context, not yet initialized + * @param[in] channel_map customized input channel mapping (array of channel + * indexes, -1 for a muted channel) + * @return >= 0 on success, or AVERROR error code in case of failure. + */ +int swr_set_channel_mapping(struct SwrContext *s, const int *channel_map); + +/** + * Generate a channel mixing matrix. + * + * This function is the one used internally by libswresample for building the + * default mixing matrix. It is made public just as a utility function for + * building custom matrices. + * + * @param in_layout input channel layout + * @param out_layout output channel layout + * @param center_mix_level mix level for the center channel + * @param surround_mix_level mix level for the surround channel(s) + * @param lfe_mix_level mix level for the low-frequency effects channel + * @param rematrix_maxval if 1.0, coefficients will be normalized to prevent + * overflow. if INT_MAX, coefficients will not be + * normalized. + * @param[out] matrix mixing coefficients; matrix[i + stride * o] is + * the weight of input channel i in output channel o. + * @param stride distance between adjacent input channels in the + * matrix array + * @param matrix_encoding matrixed stereo downmix mode (e.g. dplii) + * @param log_ctx parent logging context, can be NULL + * @return 0 on success, negative AVERROR code on failure + */ +int swr_build_matrix2(const AVChannelLayout *in_layout, const AVChannelLayout *out_layout, + double center_mix_level, double surround_mix_level, + double lfe_mix_level, double maxval, + double rematrix_volume, double *matrix, + ptrdiff_t stride, enum AVMatrixEncoding matrix_encoding, + void *log_context); + +/** + * Set a customized remix matrix. + * + * @param s allocated Swr context, not yet initialized + * @param matrix remix coefficients; matrix[i + stride * o] is + * the weight of input channel i in output channel o + * @param stride offset between lines of the matrix + * @return >= 0 on success, or AVERROR error code in case of failure. + */ +int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride); + +/** + * @} + * + * @name Sample handling functions + * @{ + */ + +/** + * Drops the specified number of output samples. + * + * This function, along with swr_inject_silence(), is called by swr_next_pts() + * if needed for "hard" compensation. + * + * @param s allocated Swr context + * @param count number of samples to be dropped + * + * @return >= 0 on success, or a negative AVERROR code on failure + */ +int swr_drop_output(struct SwrContext *s, int count); + +/** + * Injects the specified number of silence samples. + * + * This function, along with swr_drop_output(), is called by swr_next_pts() + * if needed for "hard" compensation. + * + * @param s allocated Swr context + * @param count number of samples to be dropped + * + * @return >= 0 on success, or a negative AVERROR code on failure + */ +int swr_inject_silence(struct SwrContext *s, int count); + +/** + * Gets the delay the next input sample will experience relative to the next output sample. + * + * Swresample can buffer data if more input has been provided than available + * output space, also converting between sample rates needs a delay. + * This function returns the sum of all such delays. + * The exact delay is not necessarily an integer value in either input or + * output sample rate. Especially when downsampling by a large value, the + * output sample rate may be a poor choice to represent the delay, similarly + * for upsampling and the input sample rate. + * + * @param s swr context + * @param base timebase in which the returned delay will be: + * @li if it's set to 1 the returned delay is in seconds + * @li if it's set to 1000 the returned delay is in milliseconds + * @li if it's set to the input sample rate then the returned + * delay is in input samples + * @li if it's set to the output sample rate then the returned + * delay is in output samples + * @li if it's the least common multiple of in_sample_rate and + * out_sample_rate then an exact rounding-free delay will be + * returned + * @returns the delay in 1 / @c base units. + */ +int64_t swr_get_delay(struct SwrContext *s, int64_t base); + +/** + * Find an upper bound on the number of samples that the next swr_convert + * call will output, if called with in_samples of input samples. This + * depends on the internal state, and anything changing the internal state + * (like further swr_convert() calls) will may change the number of samples + * swr_get_out_samples() returns for the same number of input samples. + * + * @param in_samples number of input samples. + * @note any call to swr_inject_silence(), swr_convert(), swr_next_pts() + * or swr_set_compensation() invalidates this limit + * @note it is recommended to pass the correct available buffer size + * to all functions like swr_convert() even if swr_get_out_samples() + * indicates that less would be used. + * @returns an upper bound on the number of samples that the next swr_convert + * will output or a negative value to indicate an error + */ +int swr_get_out_samples(struct SwrContext *s, int in_samples); + +/** + * @} + * + * @name Configuration accessors + * @{ + */ + +/** + * Return the @ref LIBSWRESAMPLE_VERSION_INT constant. + * + * This is useful to check if the build-time libswresample has the same version + * as the run-time one. + * + * @returns the unsigned int-typed version + */ +unsigned swresample_version(void); + +/** + * Return the swr build-time configuration. + * + * @returns the build-time @c ./configure flags + */ +const char *swresample_configuration(void); + +/** + * Return the swr license. + * + * @returns the license of libswresample, determined at build-time + */ +const char *swresample_license(void); + +/** + * @} + * + * @name AVFrame based API + * @{ + */ + +/** + * Convert the samples in the input AVFrame and write them to the output AVFrame. + * + * Input and output AVFrames must have channel_layout, sample_rate and format set. + * + * If the output AVFrame does not have the data pointers allocated the nb_samples + * field will be set using av_frame_get_buffer() + * is called to allocate the frame. + * + * The output AVFrame can be NULL or have fewer allocated samples than required. + * In this case, any remaining samples not written to the output will be added + * to an internal FIFO buffer, to be returned at the next call to this function + * or to swr_convert(). + * + * If converting sample rate, there may be data remaining in the internal + * resampling delay buffer. swr_get_delay() tells the number of + * remaining samples. To get this data as output, call this function or + * swr_convert() with NULL input. + * + * If the SwrContext configuration does not match the output and + * input AVFrame settings the conversion does not take place and depending on + * which AVFrame is not matching AVERROR_OUTPUT_CHANGED, AVERROR_INPUT_CHANGED + * or the result of a bitwise-OR of them is returned. + * + * @see swr_delay() + * @see swr_convert() + * @see swr_get_delay() + * + * @param swr audio resample context + * @param output output AVFrame + * @param input input AVFrame + * @return 0 on success, AVERROR on failure or nonmatching + * configuration. + */ +int swr_convert_frame(SwrContext *swr, + AVFrame *output, const AVFrame *input); + +/** + * Configure or reconfigure the SwrContext using the information + * provided by the AVFrames. + * + * The original resampling context is reset even on failure. + * The function calls swr_close() internally if the context is open. + * + * @see swr_close(); + * + * @param swr audio resample context + * @param out output AVFrame + * @param in input AVFrame + * @return 0 on success, AVERROR on failure. + */ +int swr_config_frame(SwrContext *swr, const AVFrame *out, const AVFrame *in); + +/** + * @} + * @} + */ + +#endif /* SWRESAMPLE_SWRESAMPLE_H */ diff --git a/libs/ffmpeg/libswresample/swresample_frame.c b/libs/ffmpeg/libswresample/swresample_frame.c new file mode 100644 index 00000000000..1334f462a45 --- /dev/null +++ b/libs/ffmpeg/libswresample/swresample_frame.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2014 Luca Barbato <lu_zero@gentoo.org> + * Copyright (c) 2014 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "swresample_internal.h" +#include "libavutil/channel_layout.h" +#include "libavutil/frame.h" +#include "libavutil/opt.h" + +int swr_config_frame(SwrContext *s, const AVFrame *out, const AVFrame *in) +{ + AVChannelLayout ch_layout = { 0 }; + int ret; + + swr_close(s); + + if (in) { + if ((ret = av_channel_layout_copy(&ch_layout, &in->ch_layout)) < 0) + goto fail; + if ((ret = av_opt_set_chlayout(s, "ichl", &ch_layout, 0)) < 0) + goto fail; + if ((ret = av_opt_set_int(s, "isf", in->format, 0)) < 0) + goto fail; + if ((ret = av_opt_set_int(s, "isr", in->sample_rate, 0)) < 0) + goto fail; + } + + if (out) { + if ((ret = av_channel_layout_copy(&ch_layout, &out->ch_layout)) < 0) + goto fail; + if ((ret = av_opt_set_chlayout(s, "ochl", &ch_layout, 0)) < 0) + goto fail; + if ((ret = av_opt_set_int(s, "osf", out->format, 0)) < 0) + goto fail; + if ((ret = av_opt_set_int(s, "osr", out->sample_rate, 0)) < 0) + goto fail; + } + + ret = 0; +fail: + if (ret < 0) + av_log(s, AV_LOG_ERROR, "Failed to set option\n"); + av_channel_layout_uninit(&ch_layout); + return ret; +} + +static int config_changed(SwrContext *s, + const AVFrame *out, const AVFrame *in) +{ + AVChannelLayout ch_layout = { 0 }; + int ret = 0, err; + + if (in) { + if ((err = av_channel_layout_copy(&ch_layout, &in->ch_layout)) < 0) + return err; + if (av_channel_layout_compare(&s->in_ch_layout, &ch_layout) || + s->in_sample_rate != in->sample_rate || + s->in_sample_fmt != in->format) { + ret |= AVERROR_INPUT_CHANGED; + } + } + + if (out) { + if ((err = av_channel_layout_copy(&ch_layout, &out->ch_layout)) < 0) + return err; + if (av_channel_layout_compare(&s->out_ch_layout, &ch_layout) || + s->out_sample_rate != out->sample_rate || + s->out_sample_fmt != out->format) { + ret |= AVERROR_OUTPUT_CHANGED; + } + } + av_channel_layout_uninit(&ch_layout); + + return ret; +} + +static inline int convert_frame(SwrContext *s, + AVFrame *out, const AVFrame *in) +{ + int ret; + uint8_t **out_data = NULL; + const uint8_t **in_data = NULL; + int out_nb_samples = 0, in_nb_samples = 0; + + if (out) { + out_data = out->extended_data; + out_nb_samples = out->nb_samples; + } + + if (in) { + in_data = (const uint8_t **)in->extended_data; + in_nb_samples = in->nb_samples; + } + + ret = swr_convert(s, out_data, out_nb_samples, in_data, in_nb_samples); + + if (ret < 0) { + if (out) + out->nb_samples = 0; + return ret; + } + + if (out) + out->nb_samples = ret; + + return 0; +} + +static inline int available_samples(AVFrame *out) +{ + int bytes_per_sample = av_get_bytes_per_sample(out->format); + int samples = out->linesize[0] / bytes_per_sample; + + if (av_sample_fmt_is_planar(out->format)) { + return samples; + } else { + int channels = out->ch_layout.nb_channels; + return samples / channels; + } +} + +int swr_convert_frame(SwrContext *s, + AVFrame *out, const AVFrame *in) +{ + int ret, setup = 0; + + if (!swr_is_initialized(s)) { + if ((ret = swr_config_frame(s, out, in)) < 0) + return ret; + if ((ret = swr_init(s)) < 0) + return ret; + setup = 1; + } else { + // return as is or reconfigure for input changes? + if ((ret = config_changed(s, out, in))) + return ret; + } + + if (out) { + if (!out->linesize[0]) { + out->nb_samples = swr_get_delay(s, s->out_sample_rate) + 3; + if (in) { + out->nb_samples += in->nb_samples*(int64_t)s->out_sample_rate / s->in_sample_rate; + } + if ((ret = av_frame_get_buffer(out, 0)) < 0) { + if (setup) + swr_close(s); + return ret; + } + } else { + if (!out->nb_samples) + out->nb_samples = available_samples(out); + } + } + + return convert_frame(s, out, in); +} diff --git a/libs/ffmpeg/libswresample/swresample_internal.h b/libs/ffmpeg/libswresample/swresample_internal.h new file mode 100644 index 00000000000..ca2e0d75344 --- /dev/null +++ b/libs/ffmpeg/libswresample/swresample_internal.h @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2011-2013 Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWRESAMPLE_SWRESAMPLE_INTERNAL_H +#define SWRESAMPLE_SWRESAMPLE_INTERNAL_H + +#include "swresample.h" +#include "libavutil/channel_layout.h" +#include "config.h" + +#define SWR_CH_MAX 64 + +#define SQRT3_2 1.22474487139158904909 /* sqrt(3/2) */ + +#define NS_TAPS 20 + +#if ARCH_X86_64 +typedef int64_t integer; +#else +typedef int integer; +#endif + +typedef void (mix_1_1_func_type)(void *out, const void *in, const void *coeffp, integer index, integer len); +typedef void (mix_2_1_func_type)(void *out, const void *in1, const void *in2, const void *coeffp, integer index1, integer index2, integer len); + +typedef void (mix_any_func_type)(uint8_t *const *out, const uint8_t *const *in1, const void *coeffp, integer len); + +typedef struct AudioData{ + uint8_t *ch[SWR_CH_MAX]; ///< samples buffer per channel + uint8_t *data; ///< samples buffer + int ch_count; ///< number of channels + int bps; ///< bytes per sample + int count; ///< number of samples + int planar; ///< 1 if planar audio, 0 otherwise + enum AVSampleFormat fmt; ///< sample format +} AudioData; + +struct DitherContext { + int method; + int noise_pos; + float scale; + float noise_scale; ///< Noise scale + int ns_taps; ///< Noise shaping dither taps + float ns_scale; ///< Noise shaping dither scale + float ns_scale_1; ///< Noise shaping dither scale^-1 + int ns_pos; ///< Noise shaping dither position + float ns_coeffs[NS_TAPS]; ///< Noise shaping filter coefficients + float ns_errors[SWR_CH_MAX][2*NS_TAPS]; + AudioData noise; ///< noise used for dithering + AudioData temp; ///< temporary storage when writing into the input buffer isn't possible + int output_sample_bits; ///< the number of used output bits, needed to scale dither correctly +}; + +typedef struct ResampleContext * (* resample_init_func)(struct ResampleContext *c, int out_rate, int in_rate, int filter_size, int phase_shift, int linear, + double cutoff, enum AVSampleFormat format, enum SwrFilterType filter_type, double kaiser_beta, double precision, int cheby, int exact_rational); +typedef void (* resample_free_func)(struct ResampleContext **c); +typedef int (* multiple_resample_func)(struct ResampleContext *c, AudioData *dst, int dst_size, AudioData *src, int src_size, int *consumed); +typedef int (* resample_flush_func)(struct SwrContext *c); +typedef int (* set_compensation_func)(struct ResampleContext *c, int sample_delta, int compensation_distance); +typedef int64_t (* get_delay_func)(struct SwrContext *s, int64_t base); +typedef int (* invert_initial_buffer_func)(struct ResampleContext *c, AudioData *dst, const AudioData *src, int src_size, int *dst_idx, int *dst_count); +typedef int64_t (* get_out_samples_func)(struct SwrContext *s, int in_samples); + +struct Resampler { + resample_init_func init; + resample_free_func free; + multiple_resample_func multiple_resample; + resample_flush_func flush; + set_compensation_func set_compensation; + get_delay_func get_delay; + invert_initial_buffer_func invert_initial_buffer; + get_out_samples_func get_out_samples; +}; + +extern struct Resampler const swri_resampler; +extern struct Resampler const swri_soxr_resampler; + +struct SwrContext { + const AVClass *av_class; ///< AVClass used for AVOption and av_log() + int log_level_offset; ///< logging level offset + void *log_ctx; ///< parent logging context + enum AVSampleFormat in_sample_fmt; ///< input sample format + enum AVSampleFormat int_sample_fmt; ///< internal sample format (AV_SAMPLE_FMT_FLTP or AV_SAMPLE_FMT_S16P) + enum AVSampleFormat out_sample_fmt; ///< output sample format + AVChannelLayout used_ch_layout; ///< number of used input channels (mapped channel count if channel_map, otherwise in.ch_count) + AVChannelLayout in_ch_layout; ///< input channel layout + AVChannelLayout out_ch_layout; ///< output channel layout + int in_sample_rate; ///< input sample rate + int out_sample_rate; ///< output sample rate + int flags; ///< miscellaneous flags such as SWR_FLAG_RESAMPLE + float slev; ///< surround mixing level + float clev; ///< center mixing level + float lfe_mix_level; ///< LFE mixing level + float rematrix_volume; ///< rematrixing volume coefficient + float rematrix_maxval; ///< maximum value for rematrixing output + int matrix_encoding; /**< matrixed stereo encoding */ + const int *channel_map; ///< channel index (or -1 if muted channel) map + int engine; + + AVChannelLayout user_used_chlayout; ///< User set used channel layout + AVChannelLayout user_in_chlayout; ///< User set input channel layout + AVChannelLayout user_out_chlayout; ///< User set output channel layout + enum AVSampleFormat user_int_sample_fmt; ///< User set internal sample format + int user_dither_method; ///< User set dither method + + struct DitherContext dither; + + int filter_size; /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */ + int phase_shift; /**< log2 of the number of entries in the resampling polyphase filterbank */ + int linear_interp; /**< if 1 then the resampling FIR filter will be linearly interpolated */ + int exact_rational; /**< if 1 then enable non power of 2 phase_count */ + double cutoff; /**< resampling cutoff frequency (swr: 6dB point; soxr: 0dB point). 1.0 corresponds to half the output sample rate */ + int filter_type; /**< swr resampling filter type */ + double kaiser_beta; /**< swr beta value for Kaiser window (only applicable if filter_type == AV_FILTER_TYPE_KAISER) */ + double precision; /**< soxr resampling precision (in bits) */ + int cheby; /**< soxr: if 1 then passband rolloff will be none (Chebyshev) & irrational ratio approximation precision will be higher */ + + float min_compensation; ///< swr minimum below which no compensation will happen + float min_hard_compensation; ///< swr minimum below which no silence inject / sample drop will happen + float soft_compensation_duration; ///< swr duration over which soft compensation is applied + float max_soft_compensation; ///< swr maximum soft compensation in seconds over soft_compensation_duration + float async; ///< swr simple 1 parameter async, similar to ffmpegs -async + int64_t firstpts_in_samples; ///< swr first pts in samples + + int resample_first; ///< 1 if resampling must come first, 0 if rematrixing + int rematrix; ///< flag to indicate if rematrixing is needed (basically if input and output layouts mismatch) + int rematrix_custom; ///< flag to indicate that a custom matrix has been defined + + AudioData in; ///< input audio data + AudioData postin; ///< post-input audio data: used for rematrix/resample + AudioData midbuf; ///< intermediate audio data (postin/preout) + AudioData preout; ///< pre-output audio data: used for rematrix/resample + AudioData out; ///< converted output audio data + AudioData in_buffer; ///< cached audio data (convert and resample purpose) + AudioData silence; ///< temporary with silence + AudioData drop_temp; ///< temporary used to discard output + int in_buffer_index; ///< cached buffer position + int in_buffer_count; ///< cached buffer length + int resample_in_constraint; ///< 1 if the input end was reach before the output end, 0 otherwise + int flushed; ///< 1 if data is to be flushed and no further input is expected + int64_t outpts; ///< output PTS + int64_t firstpts; ///< first PTS + int drop_output; ///< number of output samples to drop + double delayed_samples_fixup; ///< soxr 0.1.1: needed to fixup delayed_samples after flush has been called. + + struct AudioConvert *in_convert; ///< input conversion context + struct AudioConvert *out_convert; ///< output conversion context + struct AudioConvert *full_convert; ///< full conversion context (single conversion for input and output) + struct ResampleContext *resample; ///< resampling context + struct Resampler const *resampler; ///< resampler virtual function table + + double matrix[SWR_CH_MAX][SWR_CH_MAX]; ///< floating point rematrixing coefficients + union { + float matrix_flt[SWR_CH_MAX][SWR_CH_MAX]; ///< single precision floating point rematrixing coefficients + ///< valid iff int_sample_fmt is AV_SAMPLE_FMT_FLTP + int32_t matrix32[SWR_CH_MAX][SWR_CH_MAX]; ///< 17.15 fixed point rematrixing coefficients + ///< valid iff int_sample_fmt is != AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP + }; + union { + int i; + float f; + double d; + } native_one; + uint8_t *native_matrix; + union { + int16_t i16[2]; + float f; + } native_simd_one; + uint8_t *native_simd_matrix; + uint8_t matrix_ch[SWR_CH_MAX][SWR_CH_MAX+1]; ///< Lists of input channels per output channel that have non zero rematrixing coefficients + mix_1_1_func_type *mix_1_1_f; + mix_1_1_func_type *mix_1_1_simd; + + mix_2_1_func_type *mix_2_1_f; + mix_2_1_func_type *mix_2_1_simd; + + mix_any_func_type *mix_any_f; + + /* TODO: callbacks for ASM optimizations */ +}; + +av_warn_unused_result +int swri_realloc_audio(AudioData *a, int count); +int swri_check_chlayout(struct SwrContext *s, const AVChannelLayout *chl, const char *name); + +void swri_noise_shaping_int16 (SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count); +void swri_noise_shaping_int32 (SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count); +void swri_noise_shaping_float (SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count); +void swri_noise_shaping_double(SwrContext *s, AudioData *dsts, const AudioData *srcs, const AudioData *noises, int count); + +av_warn_unused_result +int swri_rematrix_init(SwrContext *s); +void swri_rematrix_free(SwrContext *s); +int swri_rematrix(SwrContext *s, AudioData *out, AudioData *in, int len, int mustcopy); +int swri_rematrix_init_x86(struct SwrContext *s); + +av_warn_unused_result +int swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSampleFormat noise_fmt); +av_warn_unused_result +int swri_dither_init(SwrContext *s, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt); + +void swri_audio_convert_init_aarch64(struct AudioConvert *ac, + enum AVSampleFormat out_fmt, + enum AVSampleFormat in_fmt, + int channels); +void swri_audio_convert_init_arm(struct AudioConvert *ac, + enum AVSampleFormat out_fmt, + enum AVSampleFormat in_fmt, + int channels); +void swri_audio_convert_init_x86(struct AudioConvert *ac, + enum AVSampleFormat out_fmt, + enum AVSampleFormat in_fmt, + int channels); + +#endif diff --git a/libs/ffmpeg/libswresample/swresampleres.rc b/libs/ffmpeg/libswresample/swresampleres.rc new file mode 100644 index 00000000000..1320f78b9a4 --- /dev/null +++ b/libs/ffmpeg/libswresample/swresampleres.rc @@ -0,0 +1,55 @@ +/* + * Windows resource file for libswresample + * + * Copyright (C) 2012 James Almer + * Copyright (C) 2013 Tiancheng "Timothy" Gu + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <windows.h> +#include "libswresample/version.h" +#include "libavutil/ffversion.h" +#include "config.h" + +1 VERSIONINFO +FILEVERSION LIBSWRESAMPLE_VERSION_MAJOR, LIBSWRESAMPLE_VERSION_MINOR, LIBSWRESAMPLE_VERSION_MICRO, 0 +PRODUCTVERSION LIBSWRESAMPLE_VERSION_MAJOR, LIBSWRESAMPLE_VERSION_MINOR, LIBSWRESAMPLE_VERSION_MICRO, 0 +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_DLL +{ + BLOCK "StringFileInfo" + { + BLOCK "040904B0" + { + VALUE "CompanyName", "FFmpeg Project" + VALUE "FileDescription", "FFmpeg audio resampling library" + VALUE "FileVersion", AV_STRINGIFY(LIBSWRESAMPLE_VERSION) + VALUE "InternalName", "libswresample" + VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project" + VALUE "OriginalFilename", "swresample" BUILDSUF "-" AV_STRINGIFY(LIBSWRESAMPLE_VERSION_MAJOR) SLIBSUF + VALUE "ProductName", "FFmpeg" + VALUE "ProductVersion", FFMPEG_VERSION + } + } + + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x0409, 0x04B0 + } +} diff --git a/libs/ffmpeg/libswresample/version.c b/libs/ffmpeg/libswresample/version.c new file mode 100644 index 00000000000..06c3d60636a --- /dev/null +++ b/libs/ffmpeg/libswresample/version.c @@ -0,0 +1,45 @@ +/* + * Version functions. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <assert.h> + +#include "config.h" +#include "swresample.h" +#include "version.h" + +#include "libavutil/ffversion.h" +const char swr_ffversion[] = "FFmpeg version " FFMPEG_VERSION; + +unsigned swresample_version(void) +{ + static_assert(LIBSWRESAMPLE_VERSION_MICRO >= 100, "micro version starts at 100"); + return LIBSWRESAMPLE_VERSION_INT; +} + +const char *swresample_configuration(void) +{ + return FFMPEG_CONFIGURATION; +} + +const char *swresample_license(void) +{ +#define LICENSE_PREFIX "libswresample license: " + return &LICENSE_PREFIX FFMPEG_LICENSE[sizeof(LICENSE_PREFIX) - 1]; +} diff --git a/libs/ffmpeg/libswresample/version.h b/libs/ffmpeg/libswresample/version.h new file mode 100644 index 00000000000..403be6227a0 --- /dev/null +++ b/libs/ffmpeg/libswresample/version.h @@ -0,0 +1,46 @@ +/* + * Version macros. + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWRESAMPLE_VERSION_H +#define SWRESAMPLE_VERSION_H + +/** + * @file + * Libswresample version macros + */ + +#include "libavutil/version.h" + +#include "version_major.h" + +#define LIBSWRESAMPLE_VERSION_MINOR 3 +#define LIBSWRESAMPLE_VERSION_MICRO 101 + +#define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ + LIBSWRESAMPLE_VERSION_MINOR, \ + LIBSWRESAMPLE_VERSION_MICRO) +#define LIBSWRESAMPLE_VERSION AV_VERSION(LIBSWRESAMPLE_VERSION_MAJOR, \ + LIBSWRESAMPLE_VERSION_MINOR, \ + LIBSWRESAMPLE_VERSION_MICRO) +#define LIBSWRESAMPLE_BUILD LIBSWRESAMPLE_VERSION_INT + +#define LIBSWRESAMPLE_IDENT "SwR" AV_STRINGIFY(LIBSWRESAMPLE_VERSION) + +#endif /* SWRESAMPLE_VERSION_H */ diff --git a/libs/ffmpeg/libswresample/version_major.h b/libs/ffmpeg/libswresample/version_major.h new file mode 100644 index 00000000000..4e0bc0ab199 --- /dev/null +++ b/libs/ffmpeg/libswresample/version_major.h @@ -0,0 +1,31 @@ +/* + * Version macros. + * + * This file is part of libswresample + * + * libswresample is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libswresample is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libswresample; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWRESAMPLE_VERSION_MAJOR_H +#define SWRESAMPLE_VERSION_MAJOR_H + +/** + * @file + * Libswresample version macros + */ + +#define LIBSWRESAMPLE_VERSION_MAJOR 6 + +#endif /* SWRESAMPLE_VERSION_MAJOR_H */ diff --git a/libs/ffmpeg/libswscale/alphablend.c b/libs/ffmpeg/libswscale/alphablend.c new file mode 100644 index 00000000000..45db5189d2b --- /dev/null +++ b/libs/ffmpeg/libswscale/alphablend.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2015 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "swscale_internal.h" + +int ff_sws_alphablendaway(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format); + const int lum_w = c->opts.src_w; + const int lum_h = c->opts.src_h; + int nb_components = desc->nb_components; + int plane, x, ysrc; + int plane_count = isGray(c->opts.src_format) ? 1 : 3; + int sixteen_bits = desc->comp[0].depth >= 9; + unsigned off = 1<<(desc->comp[0].depth - 1); + unsigned shift = desc->comp[0].depth; + unsigned max = (1<<shift) - 1; + int target_table[2][3]; + + for (plane = 0; plane < plane_count; plane++) { + int a = 0, b = 0; + if (c->opts.alpha_blend == SWS_ALPHA_BLEND_CHECKERBOARD) { + a = (1<<(desc->comp[0].depth - 1))/2; + b = 3*(1<<(desc->comp[0].depth-1))/2; + } + target_table[0][plane] = plane && !(desc->flags & AV_PIX_FMT_FLAG_RGB) ? 1<<(desc->comp[0].depth - 1) : a; + target_table[1][plane] = plane && !(desc->flags & AV_PIX_FMT_FLAG_RGB) ? 1<<(desc->comp[0].depth - 1) : b; + } + + av_assert0(plane_count == nb_components - 1); + if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) { + for (plane = 0; plane < plane_count; plane++) { + int w = plane ? c->chrSrcW : c->opts.src_w; + int x_subsample = plane ? desc->log2_chroma_w: 0; + int y_subsample = plane ? desc->log2_chroma_h: 0; + for (ysrc = 0; ysrc < AV_CEIL_RSHIFT(srcSliceH, y_subsample); ysrc++) { + int y = ysrc + (srcSliceY >> y_subsample); + int subsample_row = y_subsample && (y << y_subsample) + 1 < lum_h; + if (x_subsample || subsample_row) { + int alpha; + unsigned u; + if (sixteen_bits) { + ptrdiff_t alpha_step = srcStride[plane_count] >> 1; + const uint16_t *s = (const uint16_t *)(src[plane ] + srcStride[plane ] * ysrc); + const uint16_t *a = (const uint16_t *)(src[plane_count] + (srcStride[plane_count] * ysrc << y_subsample)); + uint16_t *d = ( uint16_t *)(dst[plane ] + dstStride[plane ] * y); + if ((!isBE(c->opts.src_format)) == !HAVE_BIGENDIAN) { + for (x = 0; x < w; x++) { + const int xnext = FFMIN(2*x + 1, lum_w - 1); + if (subsample_row) { + alpha = (a[2*x] + a[xnext] + 2 + + a[2*x + alpha_step] + a[xnext + alpha_step]) >> 2; + } else + alpha = (a[2*x] + a[xnext]) >> 1; + u = s[x]*alpha + target_table[((x^y)>>5)&1][plane]*(max-alpha) + off; + d[x] = av_clip((u + (u >> shift)) >> shift, 0, max); + } + } else { + for (x = 0; x < w; x++) { + const int xnext = FFMIN(2*x + 1, lum_w - 1); + if (subsample_row) { + alpha = (av_bswap16(a[2*x]) + av_bswap16(a[xnext]) + 2 + + av_bswap16(a[2*x + alpha_step]) + av_bswap16(a[xnext + alpha_step])) >> 2; + } else + alpha = (av_bswap16(a[2*x]) + av_bswap16(a[xnext])) >> 1; + u = av_bswap16(s[x])*alpha + target_table[((x^y)>>5)&1][plane]*(max-alpha) + off; + d[x] = av_clip((u + (u >> shift)) >> shift, 0, max); + } + } + } else { + ptrdiff_t alpha_step = srcStride[plane_count]; + const uint8_t *s = src[plane ] + srcStride[plane] * ysrc; + const uint8_t *a = src[plane_count] + (srcStride[plane_count] * ysrc << y_subsample); + uint8_t *d = dst[plane ] + dstStride[plane] * y; + for (x = 0; x < w; x++) { + const int xnext = FFMIN(2*x + 1, lum_w - 1); + if (subsample_row) { + alpha = (a[2*x] + a[xnext] + 2 + + a[2*x + alpha_step] + a[xnext + alpha_step]) >> 2; + } else + alpha = (a[2*x] + a[xnext]) >> 1; + u = s[x]*alpha + target_table[((x^y)>>5)&1][plane]*(255-alpha) + 128; + d[x] = (257*u) >> 16; + } + } + } else { + if (sixteen_bits) { + const uint16_t *s = (const uint16_t *)(src[plane ] + srcStride[plane ] * ysrc); + const uint16_t *a = (const uint16_t *)(src[plane_count] + srcStride[plane_count] * ysrc); + uint16_t *d = ( uint16_t *)(dst[plane ] + dstStride[plane ] * y); + if ((!isBE(c->opts.src_format)) == !HAVE_BIGENDIAN) { + for (x = 0; x < w; x++) { + unsigned u = s[x]*a[x] + target_table[((x^y)>>5)&1][plane]*(max-a[x]) + off; + d[x] = av_clip((u + (u >> shift)) >> shift, 0, max); + } + } else { + for (x = 0; x < w; x++) { + unsigned aswap =av_bswap16(a[x]); + unsigned u = av_bswap16(s[x])*aswap + target_table[((x^y)>>5)&1][plane]*(max-aswap) + off; + d[x] = av_clip((u + (u >> shift)) >> shift, 0, max); + } + } + } else { + const uint8_t *s = src[plane ] + srcStride[plane] * ysrc; + const uint8_t *a = src[plane_count] + srcStride[plane_count] * ysrc; + uint8_t *d = dst[plane ] + dstStride[plane] * y; + for (x = 0; x < w; x++) { + unsigned u = s[x]*a[x] + target_table[((x^y)>>5)&1][plane]*(255-a[x]) + 128; + d[x] = (257*u) >> 16; + } + } + } + } + } + } else { + int alpha_pos = desc->comp[plane_count].offset; + int w = c->opts.src_w; + for (ysrc = 0; ysrc < srcSliceH; ysrc++) { + int y = ysrc + srcSliceY; + if (sixteen_bits) { + const uint16_t *s = (const uint16_t *)(src[0] + srcStride[0] * ysrc + 2*!alpha_pos); + const uint16_t *a = (const uint16_t *)(src[0] + srcStride[0] * ysrc + alpha_pos); + uint16_t *d = ( uint16_t *)(dst[0] + dstStride[0] * y); + if ((!isBE(c->opts.src_format)) == !HAVE_BIGENDIAN) { + for (x = 0; x < w; x++) { + for (plane = 0; plane < plane_count; plane++) { + int x_index = (plane_count + 1) * x; + unsigned u = s[x_index + plane]*a[x_index] + target_table[((x^y)>>5)&1][plane]*(max-a[x_index]) + off; + d[plane_count*x + plane] = av_clip((u + (u >> shift)) >> shift, 0, max); + } + } + } else { + for (x = 0; x < w; x++) { + for (plane = 0; plane < plane_count; plane++) { + int x_index = (plane_count + 1) * x; + unsigned aswap =av_bswap16(a[x_index]); + unsigned u = av_bswap16(s[x_index + plane])*aswap + target_table[((x^y)>>5)&1][plane]*(max-aswap) + off; + d[plane_count*x + plane] = av_clip((u + (u >> shift)) >> shift, 0, max); + } + } + } + } else { + const uint8_t *s = src[0] + srcStride[0] * ysrc + !alpha_pos; + const uint8_t *a = src[0] + srcStride[0] * ysrc + alpha_pos; + uint8_t *d = dst[0] + dstStride[0] * y; + for (x = 0; x < w; x++) { + for (plane = 0; plane < plane_count; plane++) { + int x_index = (plane_count + 1) * x; + unsigned u = s[x_index + plane]*a[x_index] + target_table[((x^y)>>5)&1][plane]*(255-a[x_index]) + 128; + d[plane_count*x + plane] = (257*u) >> 16; + } + } + } + } + } + + return 0; +} diff --git a/libs/ffmpeg/libswscale/bayer_template.c b/libs/ffmpeg/libswscale/bayer_template.c new file mode 100644 index 00000000000..82fe8ffde81 --- /dev/null +++ b/libs/ffmpeg/libswscale/bayer_template.c @@ -0,0 +1,342 @@ +/* + * Bayer-to-RGB/YV12 template + * Copyright (c) 2011-2014 Peter Ross <pross@xvid.org> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if 0 +#pragma makedep header +#endif + +#if defined(BAYER_BGGR) || defined(BAYER_GBRG) +#define BAYER_R 0 +#define BAYER_G 1 +#define BAYER_B 2 +#endif +#if defined(BAYER_RGGB) || defined(BAYER_GRBG) +#define BAYER_R 2 +#define BAYER_G 1 +#define BAYER_B 0 +#endif + +#if defined(BAYER_8) +#define BAYER_READ(x) (x) +#define BAYER_SIZEOF 1 +#define BAYER_SHIFT 0 +#endif +#if defined(BAYER_16LE) +#define BAYER_READ(x) AV_RL16(&(x)) +#define BAYER_SIZEOF 2 +#define BAYER_SHIFT 8 +#endif +#if defined(BAYER_16BE) +#define BAYER_READ(x) AV_RB16(&(x)) +#define BAYER_SIZEOF 2 +#define BAYER_SHIFT 8 +#endif + +#define S(y, x) BAYER_READ(src[(y)*src_stride + BAYER_SIZEOF*(x)]) +#define T(y, x) (unsigned int)S(y, x) +#define R(y, x) dst[(y)*dst_stride + (x)*3 + BAYER_R] +#define G(y, x) dst[(y)*dst_stride + (x)*3 + BAYER_G] +#define B(y, x) dst[(y)*dst_stride + (x)*3 + BAYER_B] + +#if defined(BAYER_BGGR) || defined(BAYER_RGGB) +#define BAYER_TO_RGB24_COPY \ + R(0, 0) = \ + R(0, 1) = \ + R(1, 1) = \ + R(1, 0) = S(1, 1) >> BAYER_SHIFT; \ + \ + G(0, 1) = S(0, 1) >> BAYER_SHIFT; \ + G(0, 0) = \ + G(1, 1) = (T(0, 1) + T(1, 0)) >> (1 + BAYER_SHIFT); \ + G(1, 0) = S(1, 0) >> BAYER_SHIFT; \ + \ + B(1, 1) = \ + B(0, 0) = \ + B(0, 1) = \ + B(1, 0) = S(0, 0) >> BAYER_SHIFT; +#define BAYER_TO_RGB24_INTERPOLATE \ + R(0, 0) = (T(-1, -1) + T(-1, 1) + T(1, -1) + T(1, 1)) >> (2 + BAYER_SHIFT); \ + G(0, 0) = (T(-1, 0) + T( 0, -1) + T(0, 1) + T(1, 0)) >> (2 + BAYER_SHIFT); \ + B(0, 0) = S(0, 0) >> BAYER_SHIFT; \ + \ + R(0, 1) = (T(-1, 1) + T(1, 1)) >> (1 + BAYER_SHIFT); \ + G(0, 1) = S(0, 1) >> BAYER_SHIFT; \ + B(0, 1) = (T(0, 0) + T(0, 2)) >> (1 + BAYER_SHIFT); \ + \ + R(1, 0) = (T(1, -1) + T(1, 1)) >> (1 + BAYER_SHIFT); \ + G(1, 0) = S(1, 0) >> BAYER_SHIFT; \ + B(1, 0) = (T(0, 0) + T(2, 0)) >> (1 + BAYER_SHIFT); \ + \ + R(1, 1) = S(1, 1) >> BAYER_SHIFT; \ + G(1, 1) = (T(0, 1) + T(1, 0) + T(1, 2) + T(2, 1)) >> (2 + BAYER_SHIFT); \ + B(1, 1) = (T(0, 0) + T(0, 2) + T(2, 0) + T(2, 2)) >> (2 + BAYER_SHIFT); +#else +#define BAYER_TO_RGB24_COPY \ + R(0, 0) = \ + R(0, 1) = \ + R(1, 1) = \ + R(1, 0) = S(1, 0) >> BAYER_SHIFT; \ + \ + G(0, 0) = S(0, 0) >> BAYER_SHIFT; \ + G(1, 1) = S(1, 1) >> BAYER_SHIFT; \ + G(0, 1) = \ + G(1, 0) = (T(0, 0) + T(1, 1)) >> (1 + BAYER_SHIFT); \ + \ + B(1, 1) = \ + B(0, 0) = \ + B(0, 1) = \ + B(1, 0) = S(0, 1) >> BAYER_SHIFT; +#define BAYER_TO_RGB24_INTERPOLATE \ + R(0, 0) = (T(-1, 0) + T(1, 0)) >> (1 + BAYER_SHIFT); \ + G(0, 0) = S(0, 0) >> BAYER_SHIFT; \ + B(0, 0) = (T(0, -1) + T(0, 1)) >> (1 + BAYER_SHIFT); \ + \ + R(0, 1) = (T(-1, 0) + T(-1, 2) + T(1, 0) + T(1, 2)) >> (2 + BAYER_SHIFT); \ + G(0, 1) = (T(-1, 1) + T(0, 0) + T(0, 2) + T(1, 1)) >> (2 + BAYER_SHIFT); \ + B(0, 1) = S(0, 1) >> BAYER_SHIFT; \ + \ + R(1, 0) = S(1, 0) >> BAYER_SHIFT; \ + G(1, 0) = (T(0, 0) + T(1, -1) + T(1, 1) + T(2, 0)) >> (2 + BAYER_SHIFT); \ + B(1, 0) = (T(0, -1) + T(0, 1) + T(2, -1) + T(2, 1)) >> (2 + BAYER_SHIFT); \ + \ + R(1, 1) = (T(1, 0) + T(1, 2)) >> (1 + BAYER_SHIFT); \ + G(1, 1) = S(1, 1) >> BAYER_SHIFT; \ + B(1, 1) = (T(0, 1) + T(2, 1)) >> (1 + BAYER_SHIFT); +#endif + +#if defined(BAYER_BGGR) || defined(BAYER_RGGB) +#define BAYER_TO_RGB48_COPY \ + R(0, 0) = \ + R(0, 1) = \ + R(1, 1) = \ + R(1, 0) = S(1, 1); \ + \ + G(0, 1) = S(0, 1); \ + G(0, 0) = \ + G(1, 1) = (T(0, 1) + T(1, 0)) >> 1; \ + G(1, 0) = S(1, 0); \ + \ + B(1, 1) = \ + B(0, 0) = \ + B(0, 1) = \ + B(1, 0) = S(0, 0); +#define BAYER_TO_RGB48_INTERPOLATE \ + R(0, 0) = (T(-1, -1) + T(-1, 1) + T(1, -1) + T(1, 1)) >> 2; \ + G(0, 0) = (T(-1, 0) + T( 0, -1) + T(0, 1) + T(1, 0)) >> 2; \ + B(0, 0) = S(0, 0); \ + \ + R(0, 1) = (T(-1, 1) + T(1, 1)) >> 1; \ + G(0, 1) = S(0, 1); \ + B(0, 1) = (T(0, 0) + T(0, 2)) >> 1; \ + \ + R(1, 0) = (T(1, -1) + T(1, 1)) >> 1; \ + G(1, 0) = S(1, 0); \ + B(1, 0) = (T(0, 0) + T(2, 0)) >> 1; \ + \ + R(1, 1) = S(1, 1); \ + G(1, 1) = (T(0, 1) + T(1, 0) + T(1, 2) + T(2, 1)) >> 2; \ + B(1, 1) = (T(0, 0) + T(0, 2) + T(2, 0) + T(2, 2)) >> 2; +#else +#define BAYER_TO_RGB48_COPY \ + R(0, 0) = \ + R(0, 1) = \ + R(1, 1) = \ + R(1, 0) = S(1, 0); \ + \ + G(0, 0) = S(0, 0); \ + G(1, 1) = S(1, 1); \ + G(0, 1) = \ + G(1, 0) = (T(0, 0) + T(1, 1)) >> 1; \ + \ + B(1, 1) = \ + B(0, 0) = \ + B(0, 1) = \ + B(1, 0) = S(0, 1); +#define BAYER_TO_RGB48_INTERPOLATE \ + R(0, 0) = (T(-1, 0) + T(1, 0)) >> 1; \ + G(0, 0) = S(0, 0); \ + B(0, 0) = (T(0, -1) + T(0, 1)) >> 1; \ + \ + R(0, 1) = (T(-1, 0) + T(-1, 2) + T(1, 0) + T(1, 2)) >> 2; \ + G(0, 1) = (T(-1, 1) + T(0, 0) + T(0, 2) + T(1, 1)) >> 2; \ + B(0, 1) = S(0, 1); \ + \ + R(1, 0) = S(1, 0); \ + G(1, 0) = (T(0, 0) + T(1, -1) + T(1, 1) + T(2, 0)) >> 2; \ + B(1, 0) = (T(0, -1) + T(0, 1) + T(2, -1) + T(2, 1)) >> 2; \ + \ + R(1, 1) = (T(1, 0) + T(1, 2)) >> 1; \ + G(1, 1) = S(1, 1); \ + B(1, 1) = (T(0, 1) + T(2, 1)) >> 1; +#endif + +/** + * invoke ff_rgb24toyv12 for 2x2 pixels + */ +#define rgb24toyv12_2x2(src, dstY, dstU, dstV, luma_stride, src_stride, rgb2yuv) \ + ff_rgb24toyv12(src, dstY, dstV, dstU, 2, 2, luma_stride, 0, src_stride, rgb2yuv) + +static void BAYER_RENAME(rgb24_copy)(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width) +{ + int i; + for (i = 0 ; i < width; i+= 2) { + BAYER_TO_RGB24_COPY + src += 2 * BAYER_SIZEOF; + dst += 6; + } +} + +static void BAYER_RENAME(rgb24_interpolate)(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width) +{ + int i; + + BAYER_TO_RGB24_COPY + src += 2 * BAYER_SIZEOF; + dst += 6; + + for (i = 2 ; i < width - 2; i+= 2) { + BAYER_TO_RGB24_INTERPOLATE + src += 2 * BAYER_SIZEOF; + dst += 6; + } + + if (width > 2) { + BAYER_TO_RGB24_COPY + } +} + +static void BAYER_RENAME(rgb48_copy)(const uint8_t *src, int src_stride, uint8_t *ddst, int dst_stride, int width) +{ + uint16_t *dst = (uint16_t *)ddst; + int i; + + dst_stride /= 2; + for (i = 0 ; i < width; i+= 2) { + BAYER_TO_RGB48_COPY + src += 2 * BAYER_SIZEOF; + dst += 6; + } +} + +static void BAYER_RENAME(rgb48_interpolate)(const uint8_t *src, int src_stride, uint8_t *ddst, int dst_stride, int width) +{ + uint16_t *dst = (uint16_t *)ddst; + int i; + + dst_stride /= 2; + BAYER_TO_RGB48_COPY + src += 2 * BAYER_SIZEOF; + dst += 6; + + for (i = 2 ; i < width - 2; i+= 2) { + BAYER_TO_RGB48_INTERPOLATE + src += 2 * BAYER_SIZEOF; + dst += 6; + } + + if (width > 2) { + BAYER_TO_RGB48_COPY + } +} + +static void BAYER_RENAME(yv12_copy)(const uint8_t *src, int src_stride, uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, int luma_stride, int width, const int32_t *rgb2yuv) +{ + uint8_t dst[12]; + const int dst_stride = 6; + int i; + for (i = 0 ; i < width; i+= 2) { + BAYER_TO_RGB24_COPY + rgb24toyv12_2x2(dst, dstY, dstU, dstV, luma_stride, dst_stride, rgb2yuv); + src += 2 * BAYER_SIZEOF; + dstY += 2; + dstU++; + dstV++; + } +} + +static void BAYER_RENAME(yv12_interpolate)(const uint8_t *src, int src_stride, uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, int luma_stride, int width, const int32_t *rgb2yuv) +{ + uint8_t dst[12]; + const int dst_stride = 6; + int i; + + BAYER_TO_RGB24_COPY + rgb24toyv12_2x2(dst, dstY, dstU, dstV, luma_stride, dst_stride, rgb2yuv); + src += 2 * BAYER_SIZEOF; + dstY += 2; + dstU++; + dstV++; + + for (i = 2 ; i < width - 2; i+= 2) { + BAYER_TO_RGB24_INTERPOLATE + rgb24toyv12_2x2(dst, dstY, dstU, dstV, luma_stride, dst_stride, rgb2yuv); + src += 2 * BAYER_SIZEOF; + dstY += 2; + dstU++; + dstV++; + } + + if (width > 2) { + BAYER_TO_RGB24_COPY + rgb24toyv12_2x2(dst, dstY, dstU, dstV, luma_stride, dst_stride, rgb2yuv); + } +} + +#undef S +#undef T +#undef R +#undef G +#undef B +#undef BAYER_TO_RGB24_COPY +#undef BAYER_TO_RGB24_INTERPOLATE +#undef BAYER_TO_RGB48_COPY +#undef BAYER_TO_RGB48_INTERPOLATE + +#undef BAYER_RENAME + +#undef BAYER_R +#undef BAYER_G +#undef BAYER_B +#undef BAYER_READ +#undef BAYER_SIZEOF +#undef BAYER_SHIFT + +#if defined(BAYER_BGGR) +#undef BAYER_BGGR +#endif +#if defined(BAYER_RGGB) +#undef BAYER_RGGB +#endif +#if defined(BAYER_GBRG) +#undef BAYER_GBRG +#endif +#if defined(BAYER_GRBG) +#undef BAYER_GRBG +#endif +#if defined(BAYER_8) +#undef BAYER_8 +#endif +#if defined(BAYER_16LE) +#undef BAYER_16LE +#endif +#if defined(BAYER_16BE) +#undef BAYER_16BE +#endif diff --git a/libs/ffmpeg/libswscale/cms.c b/libs/ffmpeg/libswscale/cms.c new file mode 100644 index 00000000000..3a1a438c496 --- /dev/null +++ b/libs/ffmpeg/libswscale/cms.c @@ -0,0 +1,766 @@ +/* + * Copyright (C) 2024 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <math.h> +#include <string.h> + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/csp.h" +#include "libavutil/slicethread.h" + +#include "cms.h" +#include "csputils.h" +#include "libswscale/swscale.h" +#include "format.h" + +bool ff_sws_color_map_noop(const SwsColorMap *map) +{ + /* If the encoding space is different, we must go through a conversion */ + if (map->src.prim != map->dst.prim || map->src.trc != map->dst.trc) + return false; + + /* If the black point changes, we have to perform black point compensation */ + if (av_cmp_q(map->src.min_luma, map->dst.min_luma)) + return false; + + switch (map->intent) { + case SWS_INTENT_ABSOLUTE_COLORIMETRIC: + case SWS_INTENT_RELATIVE_COLORIMETRIC: + return ff_prim_superset(&map->dst.gamut, &map->src.gamut) && + av_cmp_q(map->src.max_luma, map->dst.max_luma) <= 0; + case SWS_INTENT_PERCEPTUAL: + case SWS_INTENT_SATURATION: + return ff_prim_equal(&map->dst.gamut, &map->src.gamut) && + !av_cmp_q(map->src.max_luma, map->dst.max_luma); + default: + av_assert0(!"Invalid gamut mapping intent?"); + return true; + } +} + +/* Approximation of gamut hull at a given intensity level */ +static const float hull(float I) +{ + return ((I - 6.0f) * I + 9.0f) * I; +} + +/* For some minimal type safety, and code cleanliness */ +typedef struct RGB { + float R, G, B; /* nits */ +} RGB; + +typedef struct IPT { + float I, P, T; +} IPT; + +typedef struct ICh { + float I, C, h; +} ICh; + +static av_always_inline ICh ipt2ich(IPT c) +{ + return (ICh) { + .I = c.I, + .C = sqrtf(c.P * c.P + c.T * c.T), + .h = atan2f(c.T, c.P), + }; +} + +static av_always_inline IPT ich2ipt(ICh c) +{ + return (IPT) { + .I = c.I, + .P = c.C * cosf(c.h), + .T = c.C * sinf(c.h), + }; +} + +/* Helper struct containing pre-computed cached values describing a gamut */ +typedef struct Gamut { + SwsMatrix3x3 encoding2lms; + SwsMatrix3x3 lms2encoding; + SwsMatrix3x3 lms2content; + SwsMatrix3x3 content2lms; + av_csp_eotf_function eotf; + av_csp_eotf_function eotf_inv; + float Iavg_frame; + float Imax_frame; + float Imin, Imax; + float Lb, Lw; + AVCIExy wp; + ICh peak; /* updated as needed in loop body when hue changes */ +} Gamut; + +static Gamut gamut_from_colorspace(SwsColor fmt) +{ + const AVColorPrimariesDesc *encoding = av_csp_primaries_desc_from_id(fmt.prim); + const AVColorPrimariesDesc content = { + .prim = fmt.gamut, + .wp = encoding->wp, + }; + + const float Lw = av_q2d(fmt.max_luma), Lb = av_q2d(fmt.min_luma); + const float Imax = pq_oetf(Lw); + + return (Gamut) { + .encoding2lms = ff_sws_ipt_rgb2lms(encoding), + .lms2encoding = ff_sws_ipt_lms2rgb(encoding), + .lms2content = ff_sws_ipt_lms2rgb(&content), + .content2lms = ff_sws_ipt_rgb2lms(&content), + .eotf = av_csp_itu_eotf(fmt.trc), + .eotf_inv = av_csp_itu_eotf_inv(fmt.trc), + .wp = encoding->wp, + .Imin = pq_oetf(Lb), + .Imax = Imax, + .Imax_frame = fmt.frame_peak.den ? pq_oetf(av_q2d(fmt.frame_peak)) : Imax, + .Iavg_frame = fmt.frame_avg.den ? pq_oetf(av_q2d(fmt.frame_avg)) : 0.0f, + .Lb = Lb, + .Lw = Lw, + }; +} + +static av_always_inline IPT rgb2ipt(RGB c, const SwsMatrix3x3 rgb2lms) +{ + const float L = rgb2lms.m[0][0] * c.R + + rgb2lms.m[0][1] * c.G + + rgb2lms.m[0][2] * c.B; + const float M = rgb2lms.m[1][0] * c.R + + rgb2lms.m[1][1] * c.G + + rgb2lms.m[1][2] * c.B; + const float S = rgb2lms.m[2][0] * c.R + + rgb2lms.m[2][1] * c.G + + rgb2lms.m[2][2] * c.B; + const float Lp = pq_oetf(L); + const float Mp = pq_oetf(M); + const float Sp = pq_oetf(S); + return (IPT) { + .I = 0.4000f * Lp + 0.4000f * Mp + 0.2000f * Sp, + .P = 4.4550f * Lp - 4.8510f * Mp + 0.3960f * Sp, + .T = 0.8056f * Lp + 0.3572f * Mp - 1.1628f * Sp, + }; +} + +static av_always_inline RGB ipt2rgb(IPT c, const SwsMatrix3x3 lms2rgb) +{ + const float Lp = c.I + 0.0975689f * c.P + 0.205226f * c.T; + const float Mp = c.I - 0.1138760f * c.P + 0.133217f * c.T; + const float Sp = c.I + 0.0326151f * c.P - 0.676887f * c.T; + const float L = pq_eotf(Lp); + const float M = pq_eotf(Mp); + const float S = pq_eotf(Sp); + return (RGB) { + .R = lms2rgb.m[0][0] * L + + lms2rgb.m[0][1] * M + + lms2rgb.m[0][2] * S, + .G = lms2rgb.m[1][0] * L + + lms2rgb.m[1][1] * M + + lms2rgb.m[1][2] * S, + .B = lms2rgb.m[2][0] * L + + lms2rgb.m[2][1] * M + + lms2rgb.m[2][2] * S, + }; +} + +static inline bool ingamut(IPT c, Gamut gamut) +{ + const float min_rgb = gamut.Lb - 1e-4f; + const float max_rgb = gamut.Lw + 1e-2f; + const float Lp = c.I + 0.0975689f * c.P + 0.205226f * c.T; + const float Mp = c.I - 0.1138760f * c.P + 0.133217f * c.T; + const float Sp = c.I + 0.0326151f * c.P - 0.676887f * c.T; + if (Lp < gamut.Imin || Lp > gamut.Imax || + Mp < gamut.Imin || Mp > gamut.Imax || + Sp < gamut.Imin || Sp > gamut.Imax) + { + /* Values outside legal LMS range */ + return false; + } else { + const float L = pq_eotf(Lp); + const float M = pq_eotf(Mp); + const float S = pq_eotf(Sp); + RGB rgb = { + .R = gamut.lms2content.m[0][0] * L + + gamut.lms2content.m[0][1] * M + + gamut.lms2content.m[0][2] * S, + .G = gamut.lms2content.m[1][0] * L + + gamut.lms2content.m[1][1] * M + + gamut.lms2content.m[1][2] * S, + .B = gamut.lms2content.m[2][0] * L + + gamut.lms2content.m[2][1] * M + + gamut.lms2content.m[2][2] * S, + }; + return rgb.R >= min_rgb && rgb.R <= max_rgb && + rgb.G >= min_rgb && rgb.G <= max_rgb && + rgb.B >= min_rgb && rgb.B <= max_rgb; + } +} + +static const float maxDelta = 5e-5f; + +// Find gamut intersection using specified bounds +static inline ICh +desat_bounded(float I, float h, float Cmin, float Cmax, Gamut gamut) +{ + if (I <= gamut.Imin) + return (ICh) { .I = gamut.Imin, .C = 0, .h = h }; + else if (I >= gamut.Imax) + return (ICh) { .I = gamut.Imax, .C = 0, .h = h }; + else { + const float maxDI = I * maxDelta; + ICh res = { .I = I, .C = (Cmin + Cmax) / 2, .h = h }; + do { + if (ingamut(ich2ipt(res), gamut)) { + Cmin = res.C; + } else { + Cmax = res.C; + } + res.C = (Cmin + Cmax) / 2; + } while (Cmax - Cmin > maxDI); + + return res; + } +} + +// Finds maximally saturated in-gamut color (for given hue) +static inline ICh saturate(float hue, Gamut gamut) +{ + static const float invphi = 0.6180339887498948f; + static const float invphi2 = 0.38196601125010515f; + + ICh lo = { .I = gamut.Imin, .h = hue }; + ICh hi = { .I = gamut.Imax, .h = hue }; + float de = hi.I - lo.I; + ICh a = { .I = lo.I + invphi2 * de }; + ICh b = { .I = lo.I + invphi * de }; + a = desat_bounded(a.I, hue, 0.0f, 0.5f, gamut); + b = desat_bounded(b.I, hue, 0.0f, 0.5f, gamut); + + while (de > maxDelta) { + de *= invphi; + if (a.C > b.C) { + hi = b; + b = a; + a.I = lo.I + invphi2 * de; + a = desat_bounded(a.I, hue, lo.C - maxDelta, 0.5f, gamut); + } else { + lo = a; + a = b; + b.I = lo.I + invphi * de; + b = desat_bounded(b.I, hue, hi.C - maxDelta, 0.5f, gamut); + } + } + + return a.C > b.C ? a : b; +} + +static float softclip(float value, float source, float target) +{ + const float j = SOFTCLIP_KNEE; + float peak, x, a, b, scale; + if (!target) + return 0.0f; + + peak = source / target; + x = fminf(value / target, peak); + if (x <= j || peak <= 1.0) + return value; + + /* Apply simple mobius function */ + a = -j*j * (peak - 1.0f) / (j*j - 2.0f * j + peak); + b = (j*j - 2.0f * j * peak + peak) / fmaxf(1e-6f, peak - 1.0f); + scale = (b*b + 2.0f * b*j + j*j) / (b - a); + + return scale * (x + a) / (x + b) * target; +} + +/** + * Something like fmixf(base, c, x) but follows an exponential curve, note + * that this can be used to extend 'c' outwards for x > 1 + */ +static inline ICh mix_exp(ICh c, float x, float gamma, float base) +{ + return (ICh) { + .I = base + (c.I - base) * powf(x, gamma), + .C = c.C * x, + .h = c.h, + }; +} + +/** + * Drop gamma for colors approaching black and achromatic to avoid numerical + * instabilities, and excessive brightness boosting of grain, while also + * strongly boosting gamma for values exceeding the target peak + */ +static inline float scale_gamma(float gamma, ICh ich, Gamut gamut) +{ + const float Imin = gamut.Imin; + const float Irel = fmaxf((ich.I - Imin) / (gamut.peak.I - Imin), 0.0f); + return gamma * powf(Irel, 3) * fminf(ich.C / gamut.peak.C, 1.0f); +} + +/* Clip a color along the exponential curve given by `gamma` */ +static inline IPT clip_gamma(IPT ipt, float gamma, Gamut gamut) +{ + float lo = 0.0f, hi = 1.0f, x = 0.5f; + const float maxDI = fmaxf(ipt.I * maxDelta, 1e-7f); + ICh ich; + + if (ipt.I <= gamut.Imin) + return (IPT) { .I = gamut.Imin }; + if (ingamut(ipt, gamut)) + return ipt; + + ich = ipt2ich(ipt); + if (!gamma) + return ich2ipt(desat_bounded(ich.I, ich.h, 0.0f, ich.C, gamut)); + + gamma = scale_gamma(gamma, ich, gamut); + do { + ICh test = mix_exp(ich, x, gamma, gamut.peak.I); + if (ingamut(ich2ipt(test), gamut)) { + lo = x; + } else { + hi = x; + } + x = (lo + hi) / 2.0f; + } while (hi - lo > maxDI); + + return ich2ipt(mix_exp(ich, x, gamma, gamut.peak.I)); +} + +typedef struct CmsCtx CmsCtx; +struct CmsCtx { + /* Tone mapping parameters */ + float Qa, Qb, Qc, Pa, Pb, src_knee, dst_knee; /* perceptual */ + float I_scale, I_offset; /* linear methods */ + + /* Colorspace parameters */ + Gamut src; + Gamut tmp; /* after tone mapping */ + Gamut dst; + SwsMatrix3x3 adaptation; /* for absolute intent */ + + /* Invocation parameters */ + SwsColorMap map; + float (*tone_map)(const CmsCtx *ctx, float I); + IPT (*adapt_colors)(const CmsCtx *ctx, IPT ipt); + v3u16_t *input; + v3u16_t *output; + + /* Threading parameters */ + int slice_size; + int size_input; + int size_output_I; + int size_output_PT; +}; + +/** + * Helper function to pick a knee point based on the * HDR10+ brightness + * metadata and scene brightness average matching. + * + * Inspired by SMPTE ST2094-10, with some modifications + */ +static void st2094_pick_knee(float src_max, float src_min, float src_avg, + float dst_max, float dst_min, + float *out_src_knee, float *out_dst_knee) +{ + const float min_knee = PERCEPTUAL_KNEE_MIN; + const float max_knee = PERCEPTUAL_KNEE_MAX; + const float def_knee = PERCEPTUAL_KNEE_DEF; + const float src_knee_min = fmixf(src_min, src_max, min_knee); + const float src_knee_max = fmixf(src_min, src_max, max_knee); + const float dst_knee_min = fmixf(dst_min, dst_max, min_knee); + const float dst_knee_max = fmixf(dst_min, dst_max, max_knee); + float src_knee, target, adapted, tuning, adaptation, dst_knee; + + /* Choose source knee based on dynamic source scene brightness */ + src_knee = src_avg ? src_avg : fmixf(src_min, src_max, def_knee); + src_knee = av_clipf(src_knee, src_knee_min, src_knee_max); + + /* Choose target adaptation point based on linearly re-scaling source knee */ + target = (src_knee - src_min) / (src_max - src_min); + adapted = fmixf(dst_min, dst_max, target); + + /** + * Choose the destination knee by picking the perceptual adaptation point + * between the source knee and the desired target. This moves the knee + * point, on the vertical axis, closer to the 1:1 (neutral) line. + * + * Adjust the adaptation strength towards 1 based on how close the knee + * point is to its extreme values (min/max knee) + */ + tuning = smoothstepf(max_knee, def_knee, target) * + smoothstepf(min_knee, def_knee, target); + adaptation = fmixf(1.0f, PERCEPTUAL_ADAPTATION, tuning); + dst_knee = fmixf(src_knee, adapted, adaptation); + dst_knee = av_clipf(dst_knee, dst_knee_min, dst_knee_max); + + *out_src_knee = src_knee; + *out_dst_knee = dst_knee; +} + +static void tone_map_setup(CmsCtx *ctx, bool dynamic) +{ + const float dst_min = ctx->dst.Imin; + const float dst_max = ctx->dst.Imax; + const float src_min = ctx->src.Imin; + const float src_max = dynamic ? ctx->src.Imax_frame : ctx->src.Imax; + const float src_avg = dynamic ? ctx->src.Iavg_frame : 0.0f; + float slope, ratio, in_min, in_max, out_min, out_max, t; + + switch (ctx->map.intent) { + case SWS_INTENT_PERCEPTUAL: + st2094_pick_knee(src_max, src_min, src_avg, dst_max, dst_min, + &ctx->src_knee, &ctx->dst_knee); + + /* Solve for linear knee (Pa = 0) */ + slope = (ctx->dst_knee - dst_min) / (ctx->src_knee - src_min); + + /** + * Tune the slope at the knee point slightly: raise it to a user-provided + * gamma exponent, multiplied by an extra tuning coefficient designed to + * make the slope closer to 1.0 when the difference in peaks is low, and + * closer to linear when the difference between peaks is high. + */ + ratio = src_max / dst_max - 1.0f; + ratio = av_clipf(SLOPE_TUNING * ratio, SLOPE_OFFSET, 1.0f + SLOPE_OFFSET); + slope = powf(slope, (1.0f - PERCEPTUAL_CONTRAST) * ratio); + + /* Normalize everything the pivot to make the math easier */ + in_min = src_min - ctx->src_knee; + in_max = src_max - ctx->src_knee; + out_min = dst_min - ctx->dst_knee; + out_max = dst_max - ctx->dst_knee; + + /** + * Solve P of order 2 for: + * P(in_min) = out_min + * P'(0.0) = slope + * P(0.0) = 0.0 + */ + ctx->Pa = (out_min - slope * in_min) / (in_min * in_min); + ctx->Pb = slope; + + /** + * Solve Q of order 3 for: + * Q(in_max) = out_max + * Q''(in_max) = 0.0 + * Q(0.0) = 0.0 + * Q'(0.0) = slope + */ + t = 2 * in_max * in_max; + ctx->Qa = (slope * in_max - out_max) / (in_max * t); + ctx->Qb = -3 * (slope * in_max - out_max) / t; + ctx->Qc = slope; + break; + case SWS_INTENT_SATURATION: + /* Linear stretch */ + ctx->I_scale = (dst_max - dst_min) / (src_max - src_min); + ctx->I_offset = dst_min - src_min * ctx->I_scale; + break; + case SWS_INTENT_RELATIVE_COLORIMETRIC: + /* Pure black point adaptation */ + ctx->I_scale = src_max / (src_max - src_min) / + (dst_max / (dst_max - dst_min)); + ctx->I_offset = dst_min - src_min * ctx->I_scale; + break; + case SWS_INTENT_ABSOLUTE_COLORIMETRIC: + /* Hard clip */ + ctx->I_scale = 1.0f; + ctx->I_offset = 0.0f; + break; + } +} + +static av_always_inline IPT tone_map_apply(const CmsCtx *ctx, IPT ipt) +{ + float I = ipt.I, desat; + + if (ctx->map.intent == SWS_INTENT_PERCEPTUAL) { + const float Pa = ctx->Pa, Pb = ctx->Pb; + const float Qa = ctx->Qa, Qb = ctx->Qb, Qc = ctx->Qc; + I -= ctx->src_knee; + I = I > 0 ? ((Qa * I + Qb) * I + Qc) * I : (Pa * I + Pb) * I; + I += ctx->dst_knee; + } else { + I = ctx->I_scale * I + ctx->I_offset; + } + + /** + * Avoids raising saturation excessively when raising brightness, and + * also desaturates when reducing brightness greatly to account for the + * reduction in gamut volume. + */ + desat = fminf(ipt.I / I, hull(I) / hull(ipt.I)); + return (IPT) { + .I = I, + .P = ipt.P * desat, + .T = ipt.T * desat, + }; +} + +static IPT perceptual(const CmsCtx *ctx, IPT ipt) +{ + ICh ich = ipt2ich(ipt); + IPT mapped = rgb2ipt(ipt2rgb(ipt, ctx->tmp.lms2content), ctx->dst.content2lms); + RGB rgb; + float maxRGB; + + /* Protect in gamut region */ + const float maxC = fmaxf(ctx->tmp.peak.C, ctx->dst.peak.C); + float k = smoothstepf(PERCEPTUAL_DEADZONE, 1.0f, ich.C / maxC); + k *= PERCEPTUAL_STRENGTH; + ipt.I = fmixf(ipt.I, mapped.I, k); + ipt.P = fmixf(ipt.P, mapped.P, k); + ipt.T = fmixf(ipt.T, mapped.T, k); + + rgb = ipt2rgb(ipt, ctx->dst.lms2content); + maxRGB = fmaxf(rgb.R, fmaxf(rgb.G, rgb.B)); + rgb.R = fmaxf(softclip(rgb.R, maxRGB, ctx->dst.Lw), ctx->dst.Lb); + rgb.G = fmaxf(softclip(rgb.G, maxRGB, ctx->dst.Lw), ctx->dst.Lb); + rgb.B = fmaxf(softclip(rgb.B, maxRGB, ctx->dst.Lw), ctx->dst.Lb); + + return rgb2ipt(rgb, ctx->dst.content2lms); +} + +static IPT relative(const CmsCtx *ctx, IPT ipt) +{ + return clip_gamma(ipt, COLORIMETRIC_GAMMA, ctx->dst); +} + +static IPT absolute(const CmsCtx *ctx, IPT ipt) +{ + RGB rgb = ipt2rgb(ipt, ctx->dst.lms2encoding); + float c[3] = { rgb.R, rgb.G, rgb.B }; + ff_sws_matrix3x3_apply(&ctx->adaptation, c); + ipt = rgb2ipt((RGB) { c[0], c[1], c[2] }, ctx->dst.encoding2lms); + + return clip_gamma(ipt, COLORIMETRIC_GAMMA, ctx->dst); +} + +static IPT saturation(const CmsCtx * ctx, IPT ipt) +{ + RGB rgb = ipt2rgb(ipt, ctx->tmp.lms2content); + return rgb2ipt(rgb, ctx->dst.content2lms); +} + +static av_always_inline av_const uint16_t av_round16f(float x) +{ + return av_clip_uint16(x * (UINT16_MAX - 1) + 0.5f); +} + +/* Call this whenever the hue changes inside the loop body */ +static av_always_inline void update_hue_peaks(CmsCtx *ctx, float P, float T) +{ + const float hue = atan2f(T, P); + switch (ctx->map.intent) { + case SWS_INTENT_PERCEPTUAL: + ctx->tmp.peak = saturate(hue, ctx->tmp); + /* fall through */ + case SWS_INTENT_RELATIVE_COLORIMETRIC: + case SWS_INTENT_ABSOLUTE_COLORIMETRIC: + ctx->dst.peak = saturate(hue, ctx->dst); + return; + default: + return; + } +} + +static void generate_slice(void *priv, int jobnr, int threadnr, int nb_jobs, + int nb_threads) +{ + CmsCtx ctx = *(const CmsCtx *) priv; + + const int slice_start = jobnr * ctx.slice_size; + const int slice_stride = ctx.size_input * ctx.size_input; + const int slice_end = FFMIN((jobnr + 1) * ctx.slice_size, ctx.size_input); + v3u16_t *input = &ctx.input[slice_start * slice_stride]; + + const int output_slice_h = (ctx.size_output_PT + nb_jobs - 1) / nb_jobs; + const int output_start = jobnr * output_slice_h; + const int output_stride = ctx.size_output_PT * ctx.size_output_I; + const int output_end = FFMIN((jobnr + 1) * output_slice_h, ctx.size_output_PT); + v3u16_t *output = ctx.output ? &ctx.output[output_start * output_stride] : NULL; + + const float I_scale = 1.0f / (ctx.src.Imax - ctx.src.Imin); + const float I_offset = -ctx.src.Imin * I_scale; + const float PT_offset = (float) (1 << 15) / (UINT16_MAX - 1); + + const float input_scale = 1.0f / (ctx.size_input - 1); + const float output_scale_PT = 1.0f / (ctx.size_output_PT - 1); + const float output_scale_I = (ctx.tmp.Imax - ctx.tmp.Imin) / + (ctx.size_output_I - 1); + + for (int Bx = slice_start; Bx < slice_end; Bx++) { + const float B = input_scale * Bx; + for (int Gx = 0; Gx < ctx.size_input; Gx++) { + const float G = input_scale * Gx; + for (int Rx = 0; Rx < ctx.size_input; Rx++) { + double c[3] = { input_scale * Rx, G, B }; + RGB rgb; + IPT ipt; + + ctx.src.eotf(ctx.src.Lw, ctx.src.Lb, c); + rgb = (RGB) { c[0], c[1], c[2] }; + ipt = rgb2ipt(rgb, ctx.src.encoding2lms); + + if (output) { + /* Save intermediate value to 3DLUT */ + *input++ = (v3u16_t) { + av_round16f(I_scale * ipt.I + I_offset), + av_round16f(ipt.P + PT_offset), + av_round16f(ipt.T + PT_offset), + }; + } else { + update_hue_peaks(&ctx, ipt.P, ipt.T); + + ipt = tone_map_apply(&ctx, ipt); + ipt = ctx.adapt_colors(&ctx, ipt); + rgb = ipt2rgb(ipt, ctx.dst.lms2encoding); + + c[0] = rgb.R; + c[1] = rgb.G; + c[2] = rgb.B; + ctx.dst.eotf_inv(ctx.dst.Lw, ctx.dst.Lb, c); + *input++ = (v3u16_t) { + av_round16f(c[0]), + av_round16f(c[1]), + av_round16f(c[2]), + }; + } + } + } + } + + if (!output) + return; + + /* Generate split gamut mapping LUT */ + for (int Tx = output_start; Tx < output_end; Tx++) { + const float T = output_scale_PT * Tx - PT_offset; + for (int Px = 0; Px < ctx.size_output_PT; Px++) { + const float P = output_scale_PT * Px - PT_offset; + update_hue_peaks(&ctx, P, T); + + for (int Ix = 0; Ix < ctx.size_output_I; Ix++) { + const float I = output_scale_I * Ix + ctx.tmp.Imin; + IPT ipt = ctx.adapt_colors(&ctx, (IPT) { I, P, T }); + RGB rgb = ipt2rgb(ipt, ctx.dst.lms2encoding); + double c[3] = { rgb.R, rgb.G, rgb.B }; + ctx.dst.eotf_inv(ctx.dst.Lw, ctx.dst.Lb, c); + *output++ = (v3u16_t) { + av_round16f(c[0]), + av_round16f(c[1]), + av_round16f(c[2]), + }; + } + } + } +} + +int ff_sws_color_map_generate_static(v3u16_t *lut, int size, const SwsColorMap *map) +{ + return ff_sws_color_map_generate_dynamic(lut, NULL, size, 1, 1, map); +} + +int ff_sws_color_map_generate_dynamic(v3u16_t *input, v3u16_t *output, + int size_input, int size_I, int size_PT, + const SwsColorMap *map) +{ + AVSliceThread *slicethread; + int ret, num_slices; + + CmsCtx ctx = { + .map = *map, + .input = input, + .output = output, + .size_input = size_input, + .size_output_I = size_I, + .size_output_PT = size_PT, + .src = gamut_from_colorspace(map->src), + .dst = gamut_from_colorspace(map->dst), + }; + + switch (ctx.map.intent) { + case SWS_INTENT_PERCEPTUAL: ctx.adapt_colors = perceptual; break; + case SWS_INTENT_RELATIVE_COLORIMETRIC: ctx.adapt_colors = relative; break; + case SWS_INTENT_SATURATION: ctx.adapt_colors = saturation; break; + case SWS_INTENT_ABSOLUTE_COLORIMETRIC: ctx.adapt_colors = absolute; break; + default: return AVERROR(EINVAL); + } + + if (!output) { + /* Tone mapping is handled in a separate step when using dynamic TM */ + tone_map_setup(&ctx, false); + } + + /* Intermediate color space after tone mapping */ + ctx.tmp = ctx.src; + ctx.tmp.Lb = ctx.dst.Lb; + ctx.tmp.Lw = ctx.dst.Lw; + ctx.tmp.Imin = ctx.dst.Imin; + ctx.tmp.Imax = ctx.dst.Imax; + + if (ctx.map.intent == SWS_INTENT_ABSOLUTE_COLORIMETRIC) { + /** + * The IPT transform already implies an explicit white point adaptation + * from src to dst, so to get absolute colorimetric semantics we have + * to explicitly undo this adaptation with a * corresponding inverse. + */ + ctx.adaptation = ff_sws_get_adaptation(&ctx.map.dst.gamut, + ctx.dst.wp, ctx.src.wp); + } + + ret = avpriv_slicethread_create(&slicethread, &ctx, generate_slice, NULL, 0); + if (ret < 0) + return ret; + + ctx.slice_size = (ctx.size_input + ret - 1) / ret; + num_slices = (ctx.size_input + ctx.slice_size - 1) / ctx.slice_size; + avpriv_slicethread_execute(slicethread, num_slices, 0); + avpriv_slicethread_free(&slicethread); + return 0; +} + +void ff_sws_tone_map_generate(v2u16_t *lut, int size, const SwsColorMap *map) +{ + CmsCtx ctx = { + .map = *map, + .src = gamut_from_colorspace(map->src), + .dst = gamut_from_colorspace(map->dst), + }; + + const float src_scale = (ctx.src.Imax - ctx.src.Imin) / (size - 1); + const float src_offset = ctx.src.Imin; + const float dst_scale = 1.0f / (ctx.dst.Imax - ctx.dst.Imin); + const float dst_offset = -ctx.dst.Imin * dst_scale; + + tone_map_setup(&ctx, true); + + for (int i = 0; i < size; i++) { + const float I = src_scale * i + src_offset; + IPT ipt = tone_map_apply(&ctx, (IPT) { I, 1.0f }); + lut[i] = (v2u16_t) { + av_round16f(dst_scale * ipt.I + dst_offset), + av_clip_uint16(ipt.P * (1 << 15) + 0.5f), + }; + } +} diff --git a/libs/ffmpeg/libswscale/cms.h b/libs/ffmpeg/libswscale/cms.h new file mode 100644 index 00000000000..5323a27260b --- /dev/null +++ b/libs/ffmpeg/libswscale/cms.h @@ -0,0 +1,105 @@ + /* + * Copyright (C) 2024 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_CMS_H +#define SWSCALE_CMS_H + +#include <stdbool.h> + +#include "libavutil/csp.h" + +#include "csputils.h" +#include "swscale.h" +#include "format.h" + +/* Minimum, maximum, and default knee point for perceptual tone mapping [0,1] */ +#define PERCEPTUAL_KNEE_MIN 0.10f +#define PERCEPTUAL_KNEE_MAX 0.80f +#define PERCEPTUAL_KNEE_DEF 0.40f + +/* Ratio between source average and target average. */ +#define PERCEPTUAL_ADAPTATION 0.40f + +/* (Relative) chromaticity protection zone for perceptual mapping [0,1] */ +#define PERCEPTUAL_DEADZONE 0.30f + +/* Contrast setting for perceptual tone mapping. [0,1.5] */ +#define PERCEPTUAL_CONTRAST 0.50f + +/* Tuning constants for overriding the contrast near extremes */ +#define SLOPE_TUNING 1.50f /* [0,10] */ +#define SLOPE_OFFSET 0.20f /* [0,1] */ + +/* Strength of the perceptual saturation mapping component [0,1] */ +#define PERCEPTUAL_STRENGTH 0.80f + +/* Knee point to use for perceptual soft clipping [0,1] */ +#define SOFTCLIP_KNEE 0.70f + +/* I vs C curve gamma to use for colorimetric clipping [0,10] */ +#define COLORIMETRIC_GAMMA 1.80f + +/* Struct describing a color mapping operation */ +typedef struct SwsColorMap { + SwsColor src; + SwsColor dst; + SwsIntent intent; +} SwsColorMap; + +/** + * Returns true if the given color map is a semantic no-op - that is, + * the overall RGB end to end transform would an identity mapping. + */ +bool ff_sws_color_map_noop(const SwsColorMap *map); + +/** + * Generates a single end-to-end color mapping 3DLUT embedding a static tone + * mapping curve. + * + * Returns 0 on success, or a negative error code on failure. + */ +int ff_sws_color_map_generate_static(v3u16_t *lut, int size, const SwsColorMap *map); + +/** + * Generates a split pair of 3DLUTS, going to IPT and back, allowing an + * arbitrary dynamic EETF to be nestled in between these two operations. + * + * See ff_sws_tone_map_generate(). + * + * Returns 0 on success, or a negative error code on failure. + */ +int ff_sws_color_map_generate_dynamic(v3u16_t *input, v3u16_t *output, + int size_input, int size_I, int size_PT, + const SwsColorMap *map); + +/** + * Generate a 1D LUT of size `size` adapting intensity (I) levels from the + * source to the destination color space. The LUT is normalized to the + * relevant intensity range directly. The second channel of each entry returns + * the corresponding 15-bit scaling factor for the P/T channels. The scaling + * factor k may be applied as `(1 << 15) - k + (PT * k >> 15)`. + * + * This is designed to be used with sws_gamut_map_generate_dynamic(). + * + * Returns 0 on success, or a negative error code on failure. + */ +void ff_sws_tone_map_generate(v2u16_t *lut, int size, const SwsColorMap *map); + +#endif // SWSCALE_GAMUT_MAPPING_H diff --git a/libs/ffmpeg/libswscale/csputils.c b/libs/ffmpeg/libswscale/csputils.c new file mode 100644 index 00000000000..6ab6ac3f7a8 --- /dev/null +++ b/libs/ffmpeg/libswscale/csputils.c @@ -0,0 +1,405 @@ +/* + * Copyright (C) 2024 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/csp.h" + +#include "csputils.h" +#include "format.h" + +void ff_sws_matrix3x3_mul(SwsMatrix3x3 *a, const SwsMatrix3x3 *b) +{ + float a00 = a->m[0][0], a01 = a->m[0][1], a02 = a->m[0][2], + a10 = a->m[1][0], a11 = a->m[1][1], a12 = a->m[1][2], + a20 = a->m[2][0], a21 = a->m[2][1], a22 = a->m[2][2]; + + for (int i = 0; i < 3; i++) { + a->m[0][i] = a00 * b->m[0][i] + a01 * b->m[1][i] + a02 * b->m[2][i]; + a->m[1][i] = a10 * b->m[0][i] + a11 * b->m[1][i] + a12 * b->m[2][i]; + a->m[2][i] = a20 * b->m[0][i] + a21 * b->m[1][i] + a22 * b->m[2][i]; + } +} + +void ff_sws_matrix3x3_invert(SwsMatrix3x3 *mat) +{ + double m00 = mat->m[0][0], m01 = mat->m[0][1], m02 = mat->m[0][2], + m10 = mat->m[1][0], m11 = mat->m[1][1], m12 = mat->m[1][2], + m20 = mat->m[2][0], m21 = mat->m[2][1], m22 = mat->m[2][2]; + + // calculate the adjoint + double a00 = (m11 * m22 - m21 * m12); + double a01 = -(m01 * m22 - m21 * m02); + double a02 = (m01 * m12 - m11 * m02); + double a10 = -(m10 * m22 - m20 * m12); + double a11 = (m00 * m22 - m20 * m02); + double a12 = -(m00 * m12 - m10 * m02); + double a20 = (m10 * m21 - m20 * m11); + double a21 = -(m00 * m21 - m20 * m01); + double a22 = (m00 * m11 - m10 * m01); + + // calculate the determinant (as inverse == 1/det * adjoint, + // adjoint * m == identity * det, so this calculates the det) + double det = m00 * a00 + m10 * a01 + m20 * a02; + det = 1.0 / det; + + mat->m[0][0] = det * a00; + mat->m[0][1] = det * a01; + mat->m[0][2] = det * a02; + mat->m[1][0] = det * a10; + mat->m[1][1] = det * a11; + mat->m[1][2] = det * a12; + mat->m[2][0] = det * a20; + mat->m[2][1] = det * a21; + mat->m[2][2] = det * a22; +} + +void ff_sws_matrix3x3_apply(const SwsMatrix3x3 *mat, float vec[3]) +{ + float x = vec[0], y = vec[1], z = vec[2]; + + for (int i = 0; i < 3; i++) + vec[i] = mat->m[i][0] * x + mat->m[i][1] * y + mat->m[i][2] * z; +} + +/* Recovers (X / Y) from a CIE xy value. */ +static inline AVRational cie_X(AVCIExy xy) +{ + return av_div_q(xy.x, xy.y); +} + +/* Recovers (Z / Y) from a CIE xy value. */ +static inline AVRational cie_Z(AVCIExy xy) +{ + return av_div_q(av_sub_q(av_sub_q(av_make_q(1, 1), xy.x), xy.y), xy.y); +} + +SwsMatrix3x3 ff_sws_rgb2xyz(const AVColorPrimariesDesc *desc) +{ + SwsMatrix3x3 out = {{{0}}}; + float S[3], X[3], Z[3], Xw, Zw; + + X[0] = av_q2d(cie_X(desc->prim.r)); + X[1] = av_q2d(cie_X(desc->prim.g)); + X[2] = av_q2d(cie_X(desc->prim.b)); + + Z[0] = av_q2d(cie_Z(desc->prim.r)); + Z[1] = av_q2d(cie_Z(desc->prim.g)); + Z[2] = av_q2d(cie_Z(desc->prim.b)); + + Xw = av_q2d(cie_X(desc->wp)); + Zw = av_q2d(cie_Z(desc->wp)); + + /* S = XYZ^-1 * W */ + for (int i = 0; i < 3; i++) { + out.m[0][i] = X[i]; + out.m[1][i] = 1.0f; + out.m[2][i] = Z[i]; + } + + ff_sws_matrix3x3_invert(&out); + + for (int i = 0; i < 3; i++) + S[i] = out.m[i][0] * Xw + out.m[i][1] + out.m[i][2] * Zw; + + /* M = [Sc * XYZc] */ + for (int i = 0; i < 3; i++) { + out.m[0][i] = S[i] * X[i]; + out.m[1][i] = S[i]; + out.m[2][i] = S[i] * Z[i]; + } + + return out; +} + +SwsMatrix3x3 ff_sws_xyz2rgb(const AVColorPrimariesDesc *prim) +{ + SwsMatrix3x3 out = ff_sws_rgb2xyz(prim); + ff_sws_matrix3x3_invert(&out); + return out; +} + +/* Matrix used in CAT16, a revised one-step linear transform method */ +static const SwsMatrix3x3 m_cat16 = {{ + { 0.401288f, 0.650173f, -0.051461f }, + { -0.250268f, 1.204414f, 0.045854f }, + { -0.002079f, 0.048952f, 0.953127f }, +}}; + +static const SwsMatrix3x3 m_cat16_inv = {{ + { 1.862068f, -1.011255f, 0.149187f }, + { 0.387527f, 0.621447f, -0.008974f }, + { -0.015841f, -0.034123f, 1.049964f }, +}}; + +// M := M * XYZd<-XYZs +static void apply_chromatic_adaptation(AVWhitepointCoefficients src, + AVWhitepointCoefficients dst, + SwsMatrix3x3 *mat) +{ + SwsMatrix3x3 tmp = {0}; + float C[3][2]; + const float srcX = av_q2d(cie_X(src)), + srcZ = av_q2d(cie_Z(src)), + dstX = av_q2d(cie_X(dst)), + dstZ = av_q2d(cie_Z(dst)); + + if (ff_cie_xy_equal(src, dst)) + return; + + // Linear "von Kries" method, adapted from CIECAM16 + // http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html + + for (int i = 0; i < 3; i++) { + // source cone + C[i][0] = m_cat16.m[i][0] * srcX + + m_cat16.m[i][1] * 1 + + m_cat16.m[i][2] * srcZ, + + // dest cone + C[i][1] = m_cat16.m[i][0] * dstX + + m_cat16.m[i][1] * 1 + + m_cat16.m[i][2] * dstZ; + } + + // tmp := I * [Cd/Cs] * Ma + for (int i = 0; i < 3; i++) + tmp.m[i][i] = C[i][1] / C[i][0]; + + ff_sws_matrix3x3_mul(&tmp, &m_cat16); + + // M := M * Ma^-1 * tmp + ff_sws_matrix3x3_mul(mat, &m_cat16_inv); + ff_sws_matrix3x3_mul(mat, &tmp); +} + +SwsMatrix3x3 ff_sws_get_adaptation(const AVPrimaryCoefficients *prim, + AVWhitepointCoefficients from, + AVWhitepointCoefficients to) +{ + SwsMatrix3x3 rgb2xyz, xyz2rgb; + const AVColorPrimariesDesc csp = { + .prim = *prim, + .wp = from, + }; + + rgb2xyz = ff_sws_rgb2xyz(&csp); + xyz2rgb = ff_sws_xyz2rgb(&csp); + apply_chromatic_adaptation(from, to, &xyz2rgb); + ff_sws_matrix3x3_mul(&xyz2rgb, &rgb2xyz); + return xyz2rgb; +} + +static const AVWhitepointCoefficients d65 = { + .x = {3127, 10000}, + .y = {3290, 10000} +}; + +static const SwsMatrix3x3 hpe = {{ /* HPE XYZ->LMS (D65) method */ + { 0.40024f, 0.70760f, -0.08081f }, + { -0.22630f, 1.16532f, 0.04570f }, + { 0.00000f, 0.00000f, 0.91822f }, +}}; + +SwsMatrix3x3 ff_sws_ipt_rgb2lms(const AVColorPrimariesDesc *prim) +{ + const float c = 0.04f; // 4% crosstalk + SwsMatrix3x3 rgb2xyz; + SwsMatrix3x3 m = {{ + { 1 - 2*c, c, c }, + { c, 1 - 2*c, c }, + { c, c, 1 - 2*c }, + }}; + + ff_sws_matrix3x3_mul(&m, &hpe); + + // Apply chromatic adaptation to D65 if the input white point differs + apply_chromatic_adaptation(prim->wp, d65, &m); + + rgb2xyz = ff_sws_rgb2xyz(prim); + ff_sws_matrix3x3_mul(&m, &rgb2xyz); + return m; +} + +SwsMatrix3x3 ff_sws_ipt_lms2rgb(const AVColorPrimariesDesc *prim) +{ + SwsMatrix3x3 rgb2lms = ff_sws_ipt_rgb2lms(prim); + ff_sws_matrix3x3_invert(&rgb2lms); + return rgb2lms; +} + +/* Test the sign of 'p' relative to the line 'ab' (barycentric coordinates) */ +static int test_point_line(AVCIExy p, AVCIExy a, AVCIExy b) +{ + return av_cmp_q(av_mul_q(av_sub_q(p.x, b.x), av_sub_q(a.y, b.y)), + av_mul_q(av_sub_q(a.x, b.x), av_sub_q(p.y, b.y))); +} + + +/* Test if a point is entirely inside a gamut */ +static float test_point_gamut(const AVCIExy point, + const AVPrimaryCoefficients *prim) +{ + int d1 = test_point_line(point, prim->r, prim->g), + d2 = test_point_line(point, prim->g, prim->b), + d3 = test_point_line(point, prim->b, prim->r); + + bool has_neg = d1 < 0 || d2 < 0 || d3 < 0, + has_pos = d1 > 0 || d2 > 0 || d3 > 0; + + return !(has_neg && has_pos); +} + +bool ff_prim_superset(const AVPrimaryCoefficients *a, const AVPrimaryCoefficients *b) +{ + return test_point_gamut(b->r, a) && + test_point_gamut(b->g, a) && + test_point_gamut(b->b, a); +} + +const float ff_pq_eotf_lut[PQ_LUT_SIZE+1] = { + 0.0000000e+00f, 4.0422718e-05f, 1.3111372e-04f, 2.6236826e-04f, 4.3151495e-04f, 6.3746885e-04f, 8.7982383e-04f, 1.1585362e-03f, + 1.4737819e-03f, 1.8258818e-03f, 2.2152586e-03f, 2.6424098e-03f, 3.1078907e-03f, 3.6123021e-03f, 4.1562821e-03f, 4.7405001e-03f, + 5.3656521e-03f, 6.0324583e-03f, 6.7416568e-03f, 7.4940095e-03f, 8.2902897e-03f, 9.1312924e-03f, 1.0017822e-02f, 1.0950702e-02f, + 1.1930764e-02f, 1.2958861e-02f, 1.4035847e-02f, 1.5162600e-02f, 1.6340000e-02f, 1.7568948e-02f, 1.8850346e-02f, 2.0185119e-02f, + 2.1574192e-02f, 2.3018509e-02f, 2.4519029e-02f, 2.6076704e-02f, 2.7692516e-02f, 2.9367449e-02f, 3.1102509e-02f, 3.2898690e-02f, + 3.4757019e-02f, 3.6678526e-02f, 3.8664261e-02f, 4.0715262e-02f, 4.2832601e-02f, 4.5017354e-02f, 4.7270617e-02f, 4.9593473e-02f, + 5.1987040e-02f, 5.4452441e-02f, 5.6990819e-02f, 5.9603301e-02f, 6.2291055e-02f, 6.5055251e-02f, 6.7897080e-02f, 7.0817717e-02f, + 7.3818379e-02f, 7.6900283e-02f, 8.0064675e-02f, 8.3312774e-02f, 8.6645849e-02f, 9.0065169e-02f, 9.3572031e-02f, 9.7167704e-02f, + 1.0085351e-01f, 1.0463077e-01f, 1.0850082e-01f, 1.1246501e-01f, 1.1652473e-01f, 1.2068130e-01f, 1.2493614e-01f, 1.2929066e-01f, + 1.3374626e-01f, 1.3830439e-01f, 1.4296648e-01f, 1.4773401e-01f, 1.5260848e-01f, 1.5759132e-01f, 1.6268405e-01f, 1.6788821e-01f, + 1.7320534e-01f, 1.7863697e-01f, 1.8418467e-01f, 1.8985004e-01f, 1.9563470e-01f, 2.0154019e-01f, 2.0756818e-01f, 2.1372031e-01f, + 2.1999824e-01f, 2.2640365e-01f, 2.3293824e-01f, 2.3960372e-01f, 2.4640186e-01f, 2.5333431e-01f, 2.6040288e-01f, 2.6760935e-01f, + 2.7495552e-01f, 2.8244319e-01f, 2.9007421e-01f, 2.9785041e-01f, 3.0577373e-01f, 3.1384594e-01f, 3.2206899e-01f, 3.3044481e-01f, + 3.3897533e-01f, 3.4766253e-01f, 3.5650838e-01f, 3.6551487e-01f, 3.7468409e-01f, 3.8401794e-01f, 3.9351855e-01f, 4.0318799e-01f, + 4.1302836e-01f, 4.2304177e-01f, 4.3323036e-01f, 4.4359629e-01f, 4.5414181e-01f, 4.6486897e-01f, 4.7578006e-01f, 4.8687732e-01f, + 4.9816302e-01f, 5.0963944e-01f, 5.2130889e-01f, 5.3317369e-01f, 5.4523628e-01f, 5.5749886e-01f, 5.6996391e-01f, 5.8263384e-01f, + 5.9551111e-01f, 6.0859816e-01f, 6.2189750e-01f, 6.3541162e-01f, 6.4914307e-01f, 6.6309439e-01f, 6.7726819e-01f, 6.9166705e-01f, + 7.0629384e-01f, 7.2115077e-01f, 7.3624074e-01f, 7.5156646e-01f, 7.6713065e-01f, 7.8293608e-01f, 7.9898553e-01f, 8.1528181e-01f, + 8.3182776e-01f, 8.4862623e-01f, 8.6568012e-01f, 8.8299235e-01f, 9.0056585e-01f, 9.1840360e-01f, 9.3650860e-01f, 9.5488388e-01f, + 9.7353277e-01f, 9.9245779e-01f, 1.0116623e+00f, 1.0311496e+00f, 1.0509226e+00f, 1.0709847e+00f, 1.0913391e+00f, 1.1119889e+00f, + 1.1329376e+00f, 1.1541885e+00f, 1.1757448e+00f, 1.1976100e+00f, 1.2197875e+00f, 1.2422807e+00f, 1.2650931e+00f, 1.2882282e+00f, + 1.3116900e+00f, 1.3354812e+00f, 1.3596059e+00f, 1.3840676e+00f, 1.4088701e+00f, 1.4340170e+00f, 1.4595121e+00f, 1.4853593e+00f, + 1.5115622e+00f, 1.5381247e+00f, 1.5650507e+00f, 1.5923442e+00f, 1.6200090e+00f, 1.6480492e+00f, 1.6764688e+00f, 1.7052718e+00f, + 1.7344629e+00f, 1.7640451e+00f, 1.7940233e+00f, 1.8244015e+00f, 1.8551840e+00f, 1.8863752e+00f, 1.9179792e+00f, 1.9500006e+00f, + 1.9824437e+00f, 2.0153130e+00f, 2.0486129e+00f, 2.0823479e+00f, 2.1165227e+00f, 2.1511419e+00f, 2.1862101e+00f, 2.2217319e+00f, + 2.2577128e+00f, 2.2941563e+00f, 2.3310679e+00f, 2.3684523e+00f, 2.4063146e+00f, 2.4446597e+00f, 2.4834925e+00f, 2.5228182e+00f, + 2.5626417e+00f, 2.6029683e+00f, 2.6438031e+00f, 2.6851514e+00f, 2.7270184e+00f, 2.7694094e+00f, 2.8123299e+00f, 2.8557852e+00f, + 2.8997815e+00f, 2.9443230e+00f, 2.9894159e+00f, 3.0350657e+00f, 3.0812783e+00f, 3.1280593e+00f, 3.1754144e+00f, 3.2233495e+00f, + 3.2718705e+00f, 3.3209833e+00f, 3.3706938e+00f, 3.4210082e+00f, 3.4719324e+00f, 3.5234727e+00f, 3.5756351e+00f, 3.6284261e+00f, + 3.6818526e+00f, 3.7359195e+00f, 3.7906340e+00f, 3.8460024e+00f, 3.9020315e+00f, 3.9587277e+00f, 4.0160977e+00f, 4.0741483e+00f, + 4.1328861e+00f, 4.1923181e+00f, 4.2524511e+00f, 4.3132921e+00f, 4.3748480e+00f, 4.4371260e+00f, 4.5001332e+00f, 4.5638768e+00f, + 4.6283650e+00f, 4.6936032e+00f, 4.7595999e+00f, 4.8263624e+00f, 4.8938982e+00f, 4.9622151e+00f, 5.0313205e+00f, 5.1012223e+00f, + 5.1719283e+00f, 5.2434463e+00f, 5.3157843e+00f, 5.3889502e+00f, 5.4629521e+00f, 5.5377982e+00f, 5.6134968e+00f, 5.6900560e+00f, + 5.7674843e+00f, 5.8457900e+00f, 5.9249818e+00f, 6.0050682e+00f, 6.0860578e+00f, 6.1679595e+00f, 6.2507819e+00f, 6.3345341e+00f, + 6.4192275e+00f, 6.5048661e+00f, 6.5914616e+00f, 6.6790231e+00f, 6.7675600e+00f, 6.8570816e+00f, 6.9475975e+00f, 7.0391171e+00f, + 7.1316500e+00f, 7.2252060e+00f, 7.3197948e+00f, 7.4154264e+00f, 7.5121107e+00f, 7.6098577e+00f, 7.7086777e+00f, 7.8085807e+00f, + 7.9095772e+00f, 8.0116775e+00f, 8.1148922e+00f, 8.2192318e+00f, 8.3247071e+00f, 8.4313287e+00f, 8.5391076e+00f, 8.6480548e+00f, + 8.7581812e+00f, 8.8694982e+00f, 8.9820168e+00f, 9.0957485e+00f, 9.2107048e+00f, 9.3268971e+00f, 9.4443372e+00f, 9.5630368e+00f, + 9.6830115e+00f, 9.8042658e+00f, 9.9268155e+00f, 1.0050673e+01f, 1.0175850e+01f, 1.0302359e+01f, 1.0430213e+01f, 1.0559425e+01f, + 1.0690006e+01f, 1.0821970e+01f, 1.0955331e+01f, 1.1090100e+01f, 1.1226290e+01f, 1.1363917e+01f, 1.1502992e+01f, 1.1643529e+01f, + 1.1785542e+01f, 1.1929044e+01f, 1.2074050e+01f, 1.2220573e+01f, 1.2368628e+01f, 1.2518229e+01f, 1.2669390e+01f, 1.2822125e+01f, + 1.2976449e+01f, 1.3132377e+01f, 1.3289925e+01f, 1.3449105e+01f, 1.3609935e+01f, 1.3772429e+01f, 1.3936602e+01f, 1.4102470e+01f, + 1.4270054e+01f, 1.4439360e+01f, 1.4610407e+01f, 1.4783214e+01f, 1.4957794e+01f, 1.5134166e+01f, 1.5312345e+01f, 1.5492348e+01f, + 1.5674192e+01f, 1.5857894e+01f, 1.6043471e+01f, 1.6230939e+01f, 1.6420317e+01f, 1.6611622e+01f, 1.6804871e+01f, 1.7000083e+01f, + 1.7197275e+01f, 1.7396465e+01f, 1.7597672e+01f, 1.7800914e+01f, 1.8006210e+01f, 1.8213578e+01f, 1.8423038e+01f, 1.8634608e+01f, + 1.8848308e+01f, 1.9064157e+01f, 1.9282175e+01f, 1.9502381e+01f, 1.9724796e+01f, 1.9949439e+01f, 2.0176331e+01f, 2.0405492e+01f, + 2.0636950e+01f, 2.0870711e+01f, 2.1106805e+01f, 2.1345250e+01f, 2.1586071e+01f, 2.1829286e+01f, 2.2074919e+01f, 2.2322992e+01f, + 2.2573525e+01f, 2.2826542e+01f, 2.3082066e+01f, 2.3340118e+01f, 2.3600721e+01f, 2.3863900e+01f, 2.4129676e+01f, 2.4398074e+01f, + 2.4669117e+01f, 2.4942828e+01f, 2.5219233e+01f, 2.5498355e+01f, 2.5780219e+01f, 2.6064849e+01f, 2.6352271e+01f, 2.6642509e+01f, + 2.6935589e+01f, 2.7231536e+01f, 2.7530377e+01f, 2.7832137e+01f, 2.8136843e+01f, 2.8444520e+01f, 2.8755196e+01f, 2.9068898e+01f, + 2.9385662e+01f, 2.9705496e+01f, 3.0028439e+01f, 3.0354517e+01f, 3.0683758e+01f, 3.1016192e+01f, 3.1351846e+01f, 3.1690750e+01f, + 3.2032932e+01f, 3.2378422e+01f, 3.2727250e+01f, 3.3079445e+01f, 3.3435038e+01f, 3.3794058e+01f, 3.4156537e+01f, 3.4522505e+01f, + 3.4891993e+01f, 3.5265034e+01f, 3.5641658e+01f, 3.6021897e+01f, 3.6405785e+01f, 3.6793353e+01f, 3.7184634e+01f, 3.7579661e+01f, + 3.7978468e+01f, 3.8381088e+01f, 3.8787555e+01f, 3.9197904e+01f, 3.9612169e+01f, 4.0030385e+01f, 4.0452587e+01f, 4.0878810e+01f, + 4.1309104e+01f, 4.1743478e+01f, 4.2181981e+01f, 4.2624651e+01f, 4.3071525e+01f, 4.3522639e+01f, 4.3978031e+01f, 4.4437739e+01f, + 4.4901803e+01f, 4.5370259e+01f, 4.5843148e+01f, 4.6320508e+01f, 4.6802379e+01f, 4.7288801e+01f, 4.7779815e+01f, 4.8275461e+01f, + 4.8775780e+01f, 4.9280813e+01f, 4.9790603e+01f, 5.0305191e+01f, 5.0824620e+01f, 5.1348933e+01f, 5.1878172e+01f, 5.2412382e+01f, + 5.2951607e+01f, 5.3495890e+01f, 5.4045276e+01f, 5.4599811e+01f, 5.5159540e+01f, 5.5724510e+01f, 5.6294765e+01f, 5.6870353e+01f, + 5.7451339e+01f, 5.8037735e+01f, 5.8629606e+01f, 5.9227001e+01f, 5.9829968e+01f, 6.0438557e+01f, 6.1052818e+01f, 6.1672799e+01f, + 6.2298552e+01f, 6.2930128e+01f, 6.3567578e+01f, 6.4210953e+01f, 6.4860306e+01f, 6.5515690e+01f, 6.6177157e+01f, 6.6844762e+01f, + 6.7518558e+01f, 6.8198599e+01f, 6.8884942e+01f, 6.9577641e+01f, 7.0276752e+01f, 7.0982332e+01f, 7.1694438e+01f, 7.2413127e+01f, + 7.3138457e+01f, 7.3870486e+01f, 7.4609273e+01f, 7.5354878e+01f, 7.6107361e+01f, 7.6866782e+01f, 7.7633203e+01f, 7.8406684e+01f, + 7.9187312e+01f, 7.9975101e+01f, 8.0770139e+01f, 8.1572490e+01f, 8.2382216e+01f, 8.3199385e+01f, 8.4024059e+01f, 8.4856307e+01f, + 8.5696193e+01f, 8.6543786e+01f, 8.7399153e+01f, 8.8262362e+01f, 8.9133482e+01f, 9.0012582e+01f, 9.0899733e+01f, 9.1795005e+01f, + 9.2698470e+01f, 9.3610199e+01f, 9.4530265e+01f, 9.5458741e+01f, 9.6395701e+01f, 9.7341219e+01f, 9.8295370e+01f, 9.9258231e+01f, + 1.0022988e+02f, 1.0121039e+02f, 1.0219984e+02f, 1.0319830e+02f, 1.0420587e+02f, 1.0522261e+02f, 1.0624862e+02f, 1.0728396e+02f, + 1.0832872e+02f, 1.0938299e+02f, 1.1044684e+02f, 1.1152036e+02f, 1.1260365e+02f, 1.1369677e+02f, 1.1479982e+02f, 1.1591288e+02f, + 1.1703605e+02f, 1.1816941e+02f, 1.1931305e+02f, 1.2046706e+02f, 1.2163153e+02f, 1.2280656e+02f, 1.2399223e+02f, 1.2518864e+02f, + 1.2639596e+02f, 1.2761413e+02f, 1.2884333e+02f, 1.3008365e+02f, 1.3133519e+02f, 1.3259804e+02f, 1.3387231e+02f, 1.3515809e+02f, + 1.3645549e+02f, 1.3776461e+02f, 1.3908555e+02f, 1.4041841e+02f, 1.4176331e+02f, 1.4312034e+02f, 1.4448961e+02f, 1.4587123e+02f, + 1.4726530e+02f, 1.4867194e+02f, 1.5009126e+02f, 1.5152336e+02f, 1.5296837e+02f, 1.5442638e+02f, 1.5589753e+02f, 1.5738191e+02f, + 1.5887965e+02f, 1.6039087e+02f, 1.6191567e+02f, 1.6345419e+02f, 1.6500655e+02f, 1.6657285e+02f, 1.6815323e+02f, 1.6974781e+02f, + 1.7135672e+02f, 1.7298007e+02f, 1.7461800e+02f, 1.7627063e+02f, 1.7793810e+02f, 1.7962053e+02f, 1.8131805e+02f, 1.8303080e+02f, + 1.8475891e+02f, 1.8650252e+02f, 1.8826176e+02f, 1.9003676e+02f, 1.9182767e+02f, 1.9363463e+02f, 1.9545777e+02f, 1.9729724e+02f, + 1.9915319e+02f, 2.0102575e+02f, 2.0291507e+02f, 2.0482131e+02f, 2.0674460e+02f, 2.0868510e+02f, 2.1064296e+02f, 2.1261833e+02f, + 2.1461136e+02f, 2.1662222e+02f, 2.1865105e+02f, 2.2069802e+02f, 2.2276328e+02f, 2.2484700e+02f, 2.2694934e+02f, 2.2907045e+02f, + 2.3121064e+02f, 2.3336982e+02f, 2.3554827e+02f, 2.3774618e+02f, 2.3996370e+02f, 2.4220102e+02f, 2.4445831e+02f, 2.4673574e+02f, + 2.4903349e+02f, 2.5135174e+02f, 2.5369067e+02f, 2.5605046e+02f, 2.5843129e+02f, 2.6083336e+02f, 2.6325684e+02f, 2.6570192e+02f, + 2.6816880e+02f, 2.7065767e+02f, 2.7316872e+02f, 2.7570215e+02f, 2.7825815e+02f, 2.8083692e+02f, 2.8343867e+02f, 2.8606359e+02f, + 2.8871189e+02f, 2.9138378e+02f, 2.9407946e+02f, 2.9679914e+02f, 2.9954304e+02f, 3.0231137e+02f, 3.0510434e+02f, 3.0792217e+02f, + 3.1076508e+02f, 3.1363330e+02f, 3.1652704e+02f, 3.1944653e+02f, 3.2239199e+02f, 3.2536367e+02f, 3.2836178e+02f, 3.3138657e+02f, + 3.3443826e+02f, 3.3751710e+02f, 3.4062333e+02f, 3.4375718e+02f, 3.4691890e+02f, 3.5010874e+02f, 3.5332694e+02f, 3.5657377e+02f, + 3.5984946e+02f, 3.6315428e+02f, 3.6648848e+02f, 3.6985233e+02f, 3.7324608e+02f, 3.7667000e+02f, 3.8012436e+02f, 3.8360942e+02f, + 3.8712547e+02f, 3.9067276e+02f, 3.9425159e+02f, 3.9786223e+02f, 4.0150496e+02f, 4.0518006e+02f, 4.0888783e+02f, 4.1262855e+02f, + 4.1640274e+02f, 4.2021025e+02f, 4.2405159e+02f, 4.2792707e+02f, 4.3183699e+02f, 4.3578166e+02f, 4.3976138e+02f, 4.4377647e+02f, + 4.4782724e+02f, 4.5191401e+02f, 4.5603709e+02f, 4.6019681e+02f, 4.6439350e+02f, 4.6862749e+02f, 4.7289910e+02f, 4.7720867e+02f, + 4.8155654e+02f, 4.8594305e+02f, 4.9036854e+02f, 4.9483336e+02f, 4.9933787e+02f, 5.0388240e+02f, 5.0846733e+02f, 5.1309301e+02f, + 5.1775981e+02f, 5.2246808e+02f, 5.2721821e+02f, 5.3201056e+02f, 5.3684551e+02f, 5.4172344e+02f, 5.4664473e+02f, 5.5160978e+02f, + 5.5661897e+02f, 5.6167269e+02f, 5.6677135e+02f, 5.7191535e+02f, 5.7710508e+02f, 5.8234097e+02f, 5.8762342e+02f, 5.9295285e+02f, + 5.9832968e+02f, 6.0375433e+02f, 6.0922723e+02f, 6.1474882e+02f, 6.2031952e+02f, 6.2593979e+02f, 6.3161006e+02f, 6.3733078e+02f, + 6.4310241e+02f, 6.4892540e+02f, 6.5480021e+02f, 6.6072730e+02f, 6.6670715e+02f, 6.7274023e+02f, 6.7882702e+02f, 6.8496800e+02f, + 6.9116365e+02f, 6.9741447e+02f, 7.0372096e+02f, 7.1008361e+02f, 7.1650293e+02f, 7.2297942e+02f, 7.2951361e+02f, 7.3610602e+02f, + 7.4275756e+02f, 7.4946797e+02f, 7.5623818e+02f, 7.6306873e+02f, 7.6996016e+02f, 7.7691302e+02f, 7.8392787e+02f, 7.9100526e+02f, + 7.9814576e+02f, 8.0534993e+02f, 8.1261837e+02f, 8.1995163e+02f, 8.2735032e+02f, 8.3481501e+02f, 8.4234632e+02f, 8.4994483e+02f, + 8.5761116e+02f, 8.6534592e+02f, 8.7314974e+02f, 8.8102323e+02f, 8.8896702e+02f, 8.9698176e+02f, 9.0506809e+02f, 9.1322665e+02f, + 9.2145810e+02f, 9.2976310e+02f, 9.3814232e+02f, 9.4659643e+02f, 9.5512612e+02f, 9.6373206e+02f, 9.7241496e+02f, 9.8117550e+02f, + 9.9001441e+02f, 9.9893238e+02f, 1.0079301e+03f, 1.0170084e+03f, 1.0261679e+03f, 1.0354094e+03f, 1.0447337e+03f, 1.0541414e+03f, + 1.0636334e+03f, 1.0732104e+03f, 1.0828731e+03f, 1.0926225e+03f, 1.1024592e+03f, 1.1123841e+03f, 1.1223979e+03f, 1.1325016e+03f, + 1.1426958e+03f, 1.1529814e+03f, 1.1633594e+03f, 1.1738304e+03f, 1.1843954e+03f, 1.1950552e+03f, 1.2058107e+03f, 1.2166627e+03f, + 1.2276122e+03f, 1.2386601e+03f, 1.2498072e+03f, 1.2610544e+03f, 1.2724027e+03f, 1.2838531e+03f, 1.2954063e+03f, 1.3070635e+03f, + 1.3188262e+03f, 1.3306940e+03f, 1.3426686e+03f, 1.3547509e+03f, 1.3669420e+03f, 1.3792428e+03f, 1.3916544e+03f, 1.4041778e+03f, + 1.4168140e+03f, 1.4295640e+03f, 1.4424289e+03f, 1.4554098e+03f, 1.4685078e+03f, 1.4817238e+03f, 1.4950591e+03f, 1.5085147e+03f, + 1.5220916e+03f, 1.5357912e+03f, 1.5496144e+03f, 1.5635624e+03f, 1.5776364e+03f, 1.5918375e+03f, 1.6061670e+03f, 1.6206260e+03f, + 1.6352156e+03f, 1.6499372e+03f, 1.6647920e+03f, 1.6797811e+03f, 1.6949059e+03f, 1.7101676e+03f, 1.7255674e+03f, 1.7411067e+03f, + 1.7567867e+03f, 1.7726087e+03f, 1.7885742e+03f, 1.8046844e+03f, 1.8209406e+03f, 1.8373443e+03f, 1.8538967e+03f, 1.8705994e+03f, + 1.8874536e+03f, 1.9044608e+03f, 1.9216225e+03f, 1.9389401e+03f, 1.9564150e+03f, 1.9740486e+03f, 1.9918426e+03f, 2.0097984e+03f, + 2.0279175e+03f, 2.0462014e+03f, 2.0646517e+03f, 2.0832699e+03f, 2.1020577e+03f, 2.1210165e+03f, 2.1401481e+03f, 2.1594540e+03f, + 2.1789359e+03f, 2.1985954e+03f, 2.2184342e+03f, 2.2384540e+03f, 2.2586565e+03f, 2.2790434e+03f, 2.2996165e+03f, 2.3203774e+03f, + 2.3413293e+03f, 2.3624714e+03f, 2.3838068e+03f, 2.4053372e+03f, 2.4270646e+03f, 2.4489908e+03f, 2.4711177e+03f, 2.4934471e+03f, + 2.5159811e+03f, 2.5387214e+03f, 2.5616702e+03f, 2.5848293e+03f, 2.6082007e+03f, 2.6317866e+03f, 2.6555888e+03f, 2.6796095e+03f, + 2.7038507e+03f, 2.7283145e+03f, 2.7530031e+03f, 2.7779186e+03f, 2.8030631e+03f, 2.8284388e+03f, 2.8540479e+03f, 2.8798927e+03f, + 2.9059754e+03f, 2.9322983e+03f, 2.9588635e+03f, 2.9856736e+03f, 3.0127308e+03f, 3.0400374e+03f, 3.0675959e+03f, 3.0954086e+03f, + 3.1234780e+03f, 3.1518066e+03f, 3.1803969e+03f, 3.2092512e+03f, 3.2383723e+03f, 3.2677625e+03f, 3.2974246e+03f, 3.3273611e+03f, + 3.3575747e+03f, 3.3880680e+03f, 3.4188437e+03f, 3.4499045e+03f, 3.4812533e+03f, 3.5128926e+03f, 3.5448255e+03f, 3.5770546e+03f, + 3.6095828e+03f, 3.6424131e+03f, 3.6755483e+03f, 3.7089914e+03f, 3.7427454e+03f, 3.7768132e+03f, 3.8111979e+03f, 3.8459027e+03f, + 3.8809304e+03f, 3.9162844e+03f, 3.9519678e+03f, 3.9879837e+03f, 4.0243354e+03f, 4.0610261e+03f, 4.0980592e+03f, 4.1354380e+03f, + 4.1731681e+03f, 4.2112483e+03f, 4.2496844e+03f, 4.2884798e+03f, 4.3276381e+03f, 4.3671627e+03f, 4.4070572e+03f, 4.4473253e+03f, + 4.4879706e+03f, 4.5289968e+03f, 4.5704076e+03f, 4.6122068e+03f, 4.6543981e+03f, 4.6969854e+03f, 4.7399727e+03f, 4.7833637e+03f, + 4.8271625e+03f, 4.8713731e+03f, 4.9159995e+03f, 4.9610458e+03f, 5.0065162e+03f, 5.0524147e+03f, 5.0987457e+03f, 5.1455133e+03f, + 5.1927219e+03f, 5.2403759e+03f, 5.2884795e+03f, 5.3370373e+03f, 5.3860537e+03f, 5.4355333e+03f, 5.4854807e+03f, 5.5359004e+03f, + 5.5867972e+03f, 5.6381757e+03f, 5.6900408e+03f, 5.7423972e+03f, 5.7952499e+03f, 5.8486037e+03f, 5.9024637e+03f, 5.9568349e+03f, + 6.0117223e+03f, 6.0671311e+03f, 6.1230664e+03f, 6.1795336e+03f, 6.2365379e+03f, 6.2940847e+03f, 6.3521793e+03f, 6.4108273e+03f, + 6.4700342e+03f, 6.5298056e+03f, 6.5901471e+03f, 6.6510643e+03f, 6.7125632e+03f, 6.7746495e+03f, 6.8373290e+03f, 6.9006078e+03f, + 6.9644918e+03f, 7.0289872e+03f, 7.0941001e+03f, 7.1598366e+03f, 7.2262031e+03f, 7.2932059e+03f, 7.3608513e+03f, 7.4291460e+03f, + 7.4981006e+03f, 7.5677134e+03f, 7.6379952e+03f, 7.7089527e+03f, 7.7805929e+03f, 7.8529226e+03f, 7.9259489e+03f, 7.9996786e+03f, + 8.0741191e+03f, 8.1492774e+03f, 8.2251609e+03f, 8.3017769e+03f, 8.3791329e+03f, 8.4572364e+03f, 8.5360950e+03f, 8.6157163e+03f, + 8.6961082e+03f, 8.7772786e+03f, 8.8592352e+03f, 8.9419862e+03f, 9.0255397e+03f, 9.1099038e+03f, 9.1950869e+03f, 9.2810973e+03f, + 9.3679435e+03f, 9.4556340e+03f, 9.5441776e+03f, 9.6335829e+03f, 9.7238588e+03f, 9.8150143e+03f, 9.9070583e+03f, 1.0000000e+04f, + 1e4f, /* extra padding to avoid out of bounds access */ +}; diff --git a/libs/ffmpeg/libswscale/csputils.h b/libs/ffmpeg/libswscale/csputils.h new file mode 100644 index 00000000000..c28e4ac7aed --- /dev/null +++ b/libs/ffmpeg/libswscale/csputils.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2024 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_CSPUTILS_H +#define SWSCALE_CSPUTILS_H + +#include <stdint.h> +#include <stdbool.h> +#include <math.h> + +#include "libavutil/attributes.h" +#include "libavutil/common.h" +#include "libavutil/csp.h" +#include "libavutil/pixfmt.h" + +/* Shared constants and helpers for colorspace mapping */ + +#define fmixf(a, b, x) ((b) * (x) + (a) * (1 - (x))) + +static inline float smoothstepf(float edge0, float edge1, float x) +{ + if (edge0 == edge1) + return x >= edge0; + x = (x - edge0) / (edge1 - edge0); + x = av_clipf(x, 0.0f, 1.0f); + return x * x * (3.0f - 2.0f * x); +} + +/* 3x3 matrix math */ +typedef struct SwsMatrix3x3 { + float m[3][3]; +} SwsMatrix3x3; + +void ff_sws_matrix3x3_mul(SwsMatrix3x3 *a, const SwsMatrix3x3 *b); +void ff_sws_matrix3x3_invert(SwsMatrix3x3 *mat); +void ff_sws_matrix3x3_apply(const SwsMatrix3x3 *mat, float vec[3]); + +SwsMatrix3x3 ff_sws_ipt_rgb2lms(const AVColorPrimariesDesc *prim); +SwsMatrix3x3 ff_sws_ipt_lms2rgb(const AVColorPrimariesDesc *prim); + +/* Converts to/from XYZ (relative to the given white point, no adaptation) */ +SwsMatrix3x3 ff_sws_rgb2xyz(const AVColorPrimariesDesc *prim); +SwsMatrix3x3 ff_sws_xyz2rgb(const AVColorPrimariesDesc *prim); + +/* Returns an RGB -> RGB adaptation matrix */ +SwsMatrix3x3 ff_sws_get_adaptation(const AVPrimaryCoefficients *prim, + AVWhitepointCoefficients from, + AVWhitepointCoefficients to); + +/* Integer math definitions / helpers */ +typedef struct v3u8_t { + uint8_t x, y, z; +} v3u8_t; + +typedef struct v2u16_t { + uint16_t x, y; +} v2u16_t; + +typedef struct v3u16_t { + uint16_t x, y, z; +} v3u16_t; + +/* Fast perceptual quantizer */ +static const float PQ_M1 = 2610./4096 * 1./4, + PQ_M2 = 2523./4096 * 128, + PQ_C1 = 3424./4096, + PQ_C2 = 2413./4096 * 32, + PQ_C3 = 2392./4096 * 32; + +enum { PQ_LUT_SIZE = 1024 }; +extern const float ff_pq_eotf_lut[PQ_LUT_SIZE+1]; + +static inline float pq_eotf(float x) +{ + float idxf = av_clipf(x, 0.0f, 1.0f) * (PQ_LUT_SIZE - 1); + int ipart = floorf(idxf); + float fpart = idxf - ipart; + return fmixf(ff_pq_eotf_lut[ipart], ff_pq_eotf_lut[ipart + 1], fpart); +} + +static inline float pq_oetf(float x) +{ + x = powf(fmaxf(x * 1e-4f, 0.0f), PQ_M1); + x = (PQ_C1 + PQ_C2 * x) / (1.0f + PQ_C3 * x); + return powf(x, PQ_M2); +} + +/* Misc colorspace math / helpers */ + +/** + * Returns true if 'b' is entirely contained in 'a'. Useful for figuring out if + * colorimetric clipping will occur or not. + */ +bool ff_prim_superset(const AVPrimaryCoefficients *a, const AVPrimaryCoefficients *b); + +#endif /* SWSCALE_CSPUTILS_H */ diff --git a/libs/ffmpeg/libswscale/format.c b/libs/ffmpeg/libswscale/format.c new file mode 100644 index 00000000000..3464a8af7c6 --- /dev/null +++ b/libs/ffmpeg/libswscale/format.c @@ -0,0 +1,1522 @@ +/* + * Copyright (C) 2024 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/hdr_dynamic_metadata.h" +#include "libavutil/mastering_display_metadata.h" +#include "libavutil/refstruct.h" + +#include "format.h" +#include "csputils.h" +#include "ops_internal.h" +#include "config_components.h" + +#if CONFIG_UNSTABLE +#include "libavutil/hwcontext.h" +#endif + +#define Q(N) ((AVRational) { N, 1 }) +#define Q0 Q(0) +#define Q1 Q(1) + +#define RET(x) \ + do { \ + int _ret = (x); \ + if (_ret < 0) \ + return _ret; \ + } while (0) + +typedef struct LegacyFormatEntry { + uint8_t is_supported_in :1; + uint8_t is_supported_out :1; + uint8_t is_supported_endianness :1; +} LegacyFormatEntry; + +/* Format support table for legacy swscale */ +static const LegacyFormatEntry legacy_format_entries[] = { + [AV_PIX_FMT_YUV420P] = { 1, 1 }, + [AV_PIX_FMT_YUYV422] = { 1, 1 }, + [AV_PIX_FMT_RGB24] = { 1, 1 }, + [AV_PIX_FMT_BGR24] = { 1, 1 }, + [AV_PIX_FMT_YUV422P] = { 1, 1 }, + [AV_PIX_FMT_YUV444P] = { 1, 1 }, + [AV_PIX_FMT_YUV410P] = { 1, 1 }, + [AV_PIX_FMT_YUV411P] = { 1, 1 }, + [AV_PIX_FMT_GRAY8] = { 1, 1 }, + [AV_PIX_FMT_MONOWHITE] = { 1, 1 }, + [AV_PIX_FMT_MONOBLACK] = { 1, 1 }, + [AV_PIX_FMT_PAL8] = { 1, 0 }, + [AV_PIX_FMT_YUVJ420P] = { 1, 1 }, + [AV_PIX_FMT_YUVJ411P] = { 1, 1 }, + [AV_PIX_FMT_YUVJ422P] = { 1, 1 }, + [AV_PIX_FMT_YUVJ444P] = { 1, 1 }, + [AV_PIX_FMT_YVYU422] = { 1, 1 }, + [AV_PIX_FMT_UYVY422] = { 1, 1 }, + [AV_PIX_FMT_UYYVYY411] = { 1, 0 }, + [AV_PIX_FMT_BGR8] = { 1, 1 }, + [AV_PIX_FMT_BGR4] = { 0, 1 }, + [AV_PIX_FMT_BGR4_BYTE] = { 1, 1 }, + [AV_PIX_FMT_RGB8] = { 1, 1 }, + [AV_PIX_FMT_RGB4] = { 0, 1 }, + [AV_PIX_FMT_RGB4_BYTE] = { 1, 1 }, + [AV_PIX_FMT_NV12] = { 1, 1 }, + [AV_PIX_FMT_NV21] = { 1, 1 }, + [AV_PIX_FMT_ARGB] = { 1, 1 }, + [AV_PIX_FMT_RGBA] = { 1, 1 }, + [AV_PIX_FMT_ABGR] = { 1, 1 }, + [AV_PIX_FMT_BGRA] = { 1, 1 }, + [AV_PIX_FMT_0RGB] = { 1, 1 }, + [AV_PIX_FMT_RGB0] = { 1, 1 }, + [AV_PIX_FMT_0BGR] = { 1, 1 }, + [AV_PIX_FMT_BGR0] = { 1, 1 }, + [AV_PIX_FMT_GRAY9BE] = { 1, 1 }, + [AV_PIX_FMT_GRAY9LE] = { 1, 1 }, + [AV_PIX_FMT_GRAY10BE] = { 1, 1 }, + [AV_PIX_FMT_GRAY10LE] = { 1, 1 }, + [AV_PIX_FMT_GRAY12BE] = { 1, 1 }, + [AV_PIX_FMT_GRAY12LE] = { 1, 1 }, + [AV_PIX_FMT_GRAY14BE] = { 1, 1 }, + [AV_PIX_FMT_GRAY14LE] = { 1, 1 }, + [AV_PIX_FMT_GRAY16BE] = { 1, 1 }, + [AV_PIX_FMT_GRAY16LE] = { 1, 1 }, + [AV_PIX_FMT_YUV440P] = { 1, 1 }, + [AV_PIX_FMT_YUVJ440P] = { 1, 1 }, + [AV_PIX_FMT_YUV440P10LE] = { 1, 1 }, + [AV_PIX_FMT_YUV440P10BE] = { 1, 1 }, + [AV_PIX_FMT_YUV440P12LE] = { 1, 1 }, + [AV_PIX_FMT_YUV440P12BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA420P] = { 1, 1 }, + [AV_PIX_FMT_YUVA422P] = { 1, 1 }, + [AV_PIX_FMT_YUVA444P] = { 1, 1 }, + [AV_PIX_FMT_YUVA420P9BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA420P9LE] = { 1, 1 }, + [AV_PIX_FMT_YUVA422P9BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA422P9LE] = { 1, 1 }, + [AV_PIX_FMT_YUVA444P9BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA444P9LE] = { 1, 1 }, + [AV_PIX_FMT_YUVA420P10BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA420P10LE] = { 1, 1 }, + [AV_PIX_FMT_YUVA422P10BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA422P10LE] = { 1, 1 }, + [AV_PIX_FMT_YUVA444P10BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA444P10LE] = { 1, 1 }, + [AV_PIX_FMT_YUVA420P16BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA420P16LE] = { 1, 1 }, + [AV_PIX_FMT_YUVA422P16BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA422P16LE] = { 1, 1 }, + [AV_PIX_FMT_YUVA444P16BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA444P16LE] = { 1, 1 }, + [AV_PIX_FMT_RGB48BE] = { 1, 1 }, + [AV_PIX_FMT_RGB48LE] = { 1, 1 }, + [AV_PIX_FMT_RGBA64BE] = { 1, 1, 1 }, + [AV_PIX_FMT_RGBA64LE] = { 1, 1, 1 }, + [AV_PIX_FMT_RGB565BE] = { 1, 1 }, + [AV_PIX_FMT_RGB565LE] = { 1, 1 }, + [AV_PIX_FMT_RGB555BE] = { 1, 1 }, + [AV_PIX_FMT_RGB555LE] = { 1, 1 }, + [AV_PIX_FMT_BGR565BE] = { 1, 1 }, + [AV_PIX_FMT_BGR565LE] = { 1, 1 }, + [AV_PIX_FMT_BGR555BE] = { 1, 1 }, + [AV_PIX_FMT_BGR555LE] = { 1, 1 }, + [AV_PIX_FMT_YUV420P16LE] = { 1, 1 }, + [AV_PIX_FMT_YUV420P16BE] = { 1, 1 }, + [AV_PIX_FMT_YUV422P16LE] = { 1, 1 }, + [AV_PIX_FMT_YUV422P16BE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P16LE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P16BE] = { 1, 1 }, + [AV_PIX_FMT_RGB444LE] = { 1, 1 }, + [AV_PIX_FMT_RGB444BE] = { 1, 1 }, + [AV_PIX_FMT_BGR444LE] = { 1, 1 }, + [AV_PIX_FMT_BGR444BE] = { 1, 1 }, + [AV_PIX_FMT_YA8] = { 1, 1 }, + [AV_PIX_FMT_YA16BE] = { 1, 1 }, + [AV_PIX_FMT_YA16LE] = { 1, 1 }, + [AV_PIX_FMT_BGR48BE] = { 1, 1 }, + [AV_PIX_FMT_BGR48LE] = { 1, 1 }, + [AV_PIX_FMT_BGRA64BE] = { 1, 1, 1 }, + [AV_PIX_FMT_BGRA64LE] = { 1, 1, 1 }, + [AV_PIX_FMT_YUV420P9BE] = { 1, 1 }, + [AV_PIX_FMT_YUV420P9LE] = { 1, 1 }, + [AV_PIX_FMT_YUV420P10BE] = { 1, 1 }, + [AV_PIX_FMT_YUV420P10LE] = { 1, 1 }, + [AV_PIX_FMT_YUV420P12BE] = { 1, 1 }, + [AV_PIX_FMT_YUV420P12LE] = { 1, 1 }, + [AV_PIX_FMT_YUV420P14BE] = { 1, 1 }, + [AV_PIX_FMT_YUV420P14LE] = { 1, 1 }, + [AV_PIX_FMT_YUV422P9BE] = { 1, 1 }, + [AV_PIX_FMT_YUV422P9LE] = { 1, 1 }, + [AV_PIX_FMT_YUV422P10BE] = { 1, 1 }, + [AV_PIX_FMT_YUV422P10LE] = { 1, 1 }, + [AV_PIX_FMT_YUV422P12BE] = { 1, 1 }, + [AV_PIX_FMT_YUV422P12LE] = { 1, 1 }, + [AV_PIX_FMT_YUV422P14BE] = { 1, 1 }, + [AV_PIX_FMT_YUV422P14LE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P9BE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P9LE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P10BE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P10LE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P12BE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P12LE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P14BE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P14LE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P10MSBBE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P10MSBLE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P12MSBBE] = { 1, 1 }, + [AV_PIX_FMT_YUV444P12MSBLE] = { 1, 1 }, + [AV_PIX_FMT_GBRP] = { 1, 1 }, + [AV_PIX_FMT_GBRP9LE] = { 1, 1 }, + [AV_PIX_FMT_GBRP9BE] = { 1, 1 }, + [AV_PIX_FMT_GBRP10LE] = { 1, 1 }, + [AV_PIX_FMT_GBRP10BE] = { 1, 1 }, + [AV_PIX_FMT_GBRAP10LE] = { 1, 1 }, + [AV_PIX_FMT_GBRAP10BE] = { 1, 1 }, + [AV_PIX_FMT_GBRP10MSBLE] = { 1, 1 }, + [AV_PIX_FMT_GBRP10MSBBE] = { 1, 1 }, + [AV_PIX_FMT_GBRP12LE] = { 1, 1 }, + [AV_PIX_FMT_GBRP12BE] = { 1, 1 }, + [AV_PIX_FMT_GBRP12MSBLE] = { 1, 1 }, + [AV_PIX_FMT_GBRP12MSBBE] = { 1, 1 }, + [AV_PIX_FMT_GBRAP12LE] = { 1, 1 }, + [AV_PIX_FMT_GBRAP12BE] = { 1, 1 }, + [AV_PIX_FMT_GBRP14LE] = { 1, 1 }, + [AV_PIX_FMT_GBRP14BE] = { 1, 1 }, + [AV_PIX_FMT_GBRAP14LE] = { 1, 1 }, + [AV_PIX_FMT_GBRAP14BE] = { 1, 1 }, + [AV_PIX_FMT_GBRP16LE] = { 1, 1 }, + [AV_PIX_FMT_GBRP16BE] = { 1, 1 }, + [AV_PIX_FMT_GBRPF32LE] = { 1, 1 }, + [AV_PIX_FMT_GBRPF32BE] = { 1, 1 }, + [AV_PIX_FMT_GBRAPF32LE] = { 1, 1 }, + [AV_PIX_FMT_GBRAPF32BE] = { 1, 1 }, + [AV_PIX_FMT_GBRPF16LE] = { 1, 0 }, + [AV_PIX_FMT_GBRPF16BE] = { 1, 0 }, + [AV_PIX_FMT_GBRAPF16LE] = { 1, 0 }, + [AV_PIX_FMT_GBRAPF16BE] = { 1, 0 }, + [AV_PIX_FMT_GBRAP] = { 1, 1 }, + [AV_PIX_FMT_GBRAP16LE] = { 1, 1 }, + [AV_PIX_FMT_GBRAP16BE] = { 1, 1 }, + [AV_PIX_FMT_BAYER_BGGR8] = { 1, 0 }, + [AV_PIX_FMT_BAYER_RGGB8] = { 1, 0 }, + [AV_PIX_FMT_BAYER_GBRG8] = { 1, 0 }, + [AV_PIX_FMT_BAYER_GRBG8] = { 1, 0 }, + [AV_PIX_FMT_BAYER_BGGR16LE] = { 1, 0 }, + [AV_PIX_FMT_BAYER_BGGR16BE] = { 1, 0 }, + [AV_PIX_FMT_BAYER_RGGB16LE] = { 1, 0 }, + [AV_PIX_FMT_BAYER_RGGB16BE] = { 1, 0 }, + [AV_PIX_FMT_BAYER_GBRG16LE] = { 1, 0 }, + [AV_PIX_FMT_BAYER_GBRG16BE] = { 1, 0 }, + [AV_PIX_FMT_BAYER_GRBG16LE] = { 1, 0 }, + [AV_PIX_FMT_BAYER_GRBG16BE] = { 1, 0 }, + [AV_PIX_FMT_XYZ12BE] = { 1, 1, 1 }, + [AV_PIX_FMT_XYZ12LE] = { 1, 1, 1 }, + [AV_PIX_FMT_AYUV64LE] = { 1, 1}, + [AV_PIX_FMT_AYUV64BE] = { 1, 1 }, + [AV_PIX_FMT_P010LE] = { 1, 1 }, + [AV_PIX_FMT_P010BE] = { 1, 1 }, + [AV_PIX_FMT_P012LE] = { 1, 1 }, + [AV_PIX_FMT_P012BE] = { 1, 1 }, + [AV_PIX_FMT_P016LE] = { 1, 1 }, + [AV_PIX_FMT_P016BE] = { 1, 1 }, + [AV_PIX_FMT_GRAYF32LE] = { 1, 1 }, + [AV_PIX_FMT_GRAYF32BE] = { 1, 1 }, + [AV_PIX_FMT_GRAYF16LE] = { 1, 0 }, + [AV_PIX_FMT_GRAYF16BE] = { 1, 0 }, + [AV_PIX_FMT_YAF32LE] = { 1, 0 }, + [AV_PIX_FMT_YAF32BE] = { 1, 0 }, + [AV_PIX_FMT_YAF16LE] = { 1, 0 }, + [AV_PIX_FMT_YAF16BE] = { 1, 0 }, + [AV_PIX_FMT_YUVA422P12BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA422P12LE] = { 1, 1 }, + [AV_PIX_FMT_YUVA444P12BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA444P12LE] = { 1, 1 }, + [AV_PIX_FMT_NV24] = { 1, 1 }, + [AV_PIX_FMT_NV42] = { 1, 1 }, + [AV_PIX_FMT_Y210LE] = { 1, 1 }, + [AV_PIX_FMT_Y212LE] = { 1, 1 }, + [AV_PIX_FMT_Y216LE] = { 1, 1 }, + [AV_PIX_FMT_X2RGB10LE] = { 1, 1 }, + [AV_PIX_FMT_X2BGR10LE] = { 1, 1 }, + [AV_PIX_FMT_NV20BE] = { 1, 1 }, + [AV_PIX_FMT_NV20LE] = { 1, 1 }, + [AV_PIX_FMT_P210BE] = { 1, 1 }, + [AV_PIX_FMT_P210LE] = { 1, 1 }, + [AV_PIX_FMT_P212BE] = { 1, 1 }, + [AV_PIX_FMT_P212LE] = { 1, 1 }, + [AV_PIX_FMT_P410BE] = { 1, 1 }, + [AV_PIX_FMT_P410LE] = { 1, 1 }, + [AV_PIX_FMT_P412BE] = { 1, 1 }, + [AV_PIX_FMT_P412LE] = { 1, 1 }, + [AV_PIX_FMT_P216BE] = { 1, 1 }, + [AV_PIX_FMT_P216LE] = { 1, 1 }, + [AV_PIX_FMT_P416BE] = { 1, 1 }, + [AV_PIX_FMT_P416LE] = { 1, 1 }, + [AV_PIX_FMT_NV16] = { 1, 1 }, + [AV_PIX_FMT_VUYA] = { 1, 1 }, + [AV_PIX_FMT_VUYX] = { 1, 1 }, + [AV_PIX_FMT_RGBAF16BE] = { 1, 0 }, + [AV_PIX_FMT_RGBAF16LE] = { 1, 0 }, + [AV_PIX_FMT_RGBF16BE] = { 1, 0 }, + [AV_PIX_FMT_RGBF16LE] = { 1, 0 }, + [AV_PIX_FMT_RGBF32BE] = { 1, 0 }, + [AV_PIX_FMT_RGBF32LE] = { 1, 0 }, + [AV_PIX_FMT_XV30LE] = { 1, 1 }, + [AV_PIX_FMT_XV36LE] = { 1, 1 }, + [AV_PIX_FMT_XV36BE] = { 1, 1 }, + [AV_PIX_FMT_XV48LE] = { 1, 1 }, + [AV_PIX_FMT_XV48BE] = { 1, 1 }, + [AV_PIX_FMT_AYUV] = { 1, 1 }, + [AV_PIX_FMT_UYVA] = { 1, 1 }, + [AV_PIX_FMT_VYU444] = { 1, 1 }, + [AV_PIX_FMT_V30XLE] = { 1, 1 }, +}; + +int sws_isSupportedInput(enum AVPixelFormat pix_fmt) +{ + return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ? + legacy_format_entries[pix_fmt].is_supported_in : 0; +} + +int sws_isSupportedOutput(enum AVPixelFormat pix_fmt) +{ + return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ? + legacy_format_entries[pix_fmt].is_supported_out : 0; +} + +int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt) +{ + return (unsigned)pix_fmt < FF_ARRAY_ELEMS(legacy_format_entries) ? + legacy_format_entries[pix_fmt].is_supported_endianness : 0; +} + +/** + * This function also sanitizes and strips the input data, removing irrelevant + * fields for certain formats. + */ +SwsFormat ff_fmt_from_frame(const AVFrame *frame, int field) +{ + const AVColorPrimariesDesc *primaries; + AVFrameSideData *sd; + + enum AVPixelFormat format = frame->format; + enum AVPixelFormat hw_format = AV_PIX_FMT_NONE; + +#if CONFIG_UNSTABLE + if (frame->hw_frames_ctx) { + AVHWFramesContext *hwfc = (AVHWFramesContext *)frame->hw_frames_ctx->data; + hw_format = frame->format; + format = hwfc->sw_format; + } +#endif + + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format); + + SwsFormat fmt = { + .width = frame->width, + .height = frame->height, + .format = format, + .hw_format = hw_format, + .range = frame->color_range, + .csp = frame->colorspace, + .loc = frame->chroma_location, + .desc = desc, + .color = { + .prim = frame->color_primaries, + .trc = frame->color_trc, + }, + }; + + av_assert1(fmt.width > 0); + av_assert1(fmt.height > 0); + av_assert1(fmt.format != AV_PIX_FMT_NONE); + av_assert0(desc); + if (desc->flags & (AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_BAYER)) { + /* RGB-like family */ + fmt.csp = AVCOL_SPC_RGB; + fmt.range = AVCOL_RANGE_JPEG; + } else if (desc->flags & AV_PIX_FMT_FLAG_XYZ) { + fmt.csp = AVCOL_SPC_UNSPECIFIED; + fmt.color = (SwsColor) { + .prim = AVCOL_PRI_BT709, /* swscale currently hard-codes this XYZ matrix */ + .trc = AVCOL_TRC_SMPTE428, + }; + } else if (desc->nb_components < 3) { + /* Grayscale formats */ + fmt.color.prim = AVCOL_PRI_UNSPECIFIED; + fmt.csp = AVCOL_SPC_UNSPECIFIED; + if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) + fmt.range = AVCOL_RANGE_UNSPECIFIED; + else + fmt.range = AVCOL_RANGE_JPEG; // FIXME: this restriction should be lifted + } + + switch (frame->format) { + case AV_PIX_FMT_YUVJ420P: + case AV_PIX_FMT_YUVJ411P: + case AV_PIX_FMT_YUVJ422P: + case AV_PIX_FMT_YUVJ444P: + case AV_PIX_FMT_YUVJ440P: + fmt.range = AVCOL_RANGE_JPEG; + break; + } + + if (!desc->log2_chroma_w && !desc->log2_chroma_h) + fmt.loc = AVCHROMA_LOC_UNSPECIFIED; + + if (frame->flags & AV_FRAME_FLAG_INTERLACED) { + fmt.height = (fmt.height + (field == FIELD_TOP)) >> 1; + fmt.interlaced = 1; + } + + /* Set luminance and gamut information */ + fmt.color.min_luma = av_make_q(0, 1); + switch (fmt.color.trc) { + case AVCOL_TRC_SMPTE2084: + fmt.color.max_luma = av_make_q(10000, 1); break; + case AVCOL_TRC_ARIB_STD_B67: + fmt.color.max_luma = av_make_q( 1000, 1); break; /* HLG reference display */ + default: + fmt.color.max_luma = av_make_q( 203, 1); break; /* SDR reference brightness */ + } + + primaries = av_csp_primaries_desc_from_id(fmt.color.prim); + if (primaries) + fmt.color.gamut = primaries->prim; + + if ((sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA))) { + const AVMasteringDisplayMetadata *mdm = (const AVMasteringDisplayMetadata *) sd->data; + if (mdm->has_luminance) { + fmt.color.min_luma = mdm->min_luminance; + fmt.color.max_luma = mdm->max_luminance; + } + + if (mdm->has_primaries) { + /* Ignore mastering display white point as it has no bearance on + * the underlying content */ + fmt.color.gamut.r.x = mdm->display_primaries[0][0]; + fmt.color.gamut.r.y = mdm->display_primaries[0][1]; + fmt.color.gamut.g.x = mdm->display_primaries[1][0]; + fmt.color.gamut.g.y = mdm->display_primaries[1][1]; + fmt.color.gamut.b.x = mdm->display_primaries[2][0]; + fmt.color.gamut.b.y = mdm->display_primaries[2][1]; + } + } + + if ((sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DYNAMIC_HDR_PLUS))) { + const AVDynamicHDRPlus *dhp = (const AVDynamicHDRPlus *) sd->data; + const AVHDRPlusColorTransformParams *pars = &dhp->params[0]; + const AVRational nits = av_make_q(10000, 1); + AVRational maxrgb = pars->maxscl[0]; + + if (!dhp->num_windows || dhp->application_version > 1) + goto skip_hdr10; + + /* Maximum of MaxSCL components */ + if (av_cmp_q(pars->maxscl[1], maxrgb) > 0) + maxrgb = pars->maxscl[1]; + if (av_cmp_q(pars->maxscl[2], maxrgb) > 0) + maxrgb = pars->maxscl[2]; + + if (maxrgb.num > 0) { + /* Estimate true luminance from MaxSCL */ + const AVLumaCoefficients *luma = av_csp_luma_coeffs_from_avcsp(fmt.csp); + if (!luma) + goto skip_hdr10; + fmt.color.frame_peak = av_add_q(av_mul_q(luma->cr, pars->maxscl[0]), + av_add_q(av_mul_q(luma->cg, pars->maxscl[1]), + av_mul_q(luma->cb, pars->maxscl[2]))); + /* Scale the scene average brightness by the ratio between the + * maximum luminance and the MaxRGB values */ + fmt.color.frame_avg = av_mul_q(pars->average_maxrgb, + av_div_q(fmt.color.frame_peak, maxrgb)); + } else { + /** + * Calculate largest value from histogram to use as fallback for + * clips with missing MaxSCL information. Note that this may end + * up picking the "reserved" value at the 5% percentile, which in + * practice appears to track the brightest pixel in the scene. + */ + for (int i = 0; i < pars->num_distribution_maxrgb_percentiles; i++) { + const AVRational pct = pars->distribution_maxrgb[i].percentile; + if (av_cmp_q(pct, maxrgb) > 0) + maxrgb = pct; + fmt.color.frame_peak = maxrgb; + fmt.color.frame_avg = pars->average_maxrgb; + } + } + + /* Rescale to nits */ + fmt.color.frame_peak = av_mul_q(nits, fmt.color.frame_peak); + fmt.color.frame_avg = av_mul_q(nits, fmt.color.frame_avg); + } +skip_hdr10: + + /* PQ is always scaled down to absolute zero, so ignore mastering metadata */ + if (fmt.color.trc == AVCOL_TRC_SMPTE2084) + fmt.color.min_luma = av_make_q(0, 1); + + return fmt; +} + +static int infer_prim_ref(SwsColor *csp, const SwsColor *ref) +{ + if (csp->prim != AVCOL_PRI_UNSPECIFIED) + return 0; + + /* Reuse the reference gamut only for "safe", similar primaries */ + switch (ref->prim) { + case AVCOL_PRI_BT709: + case AVCOL_PRI_BT470M: + case AVCOL_PRI_BT470BG: + case AVCOL_PRI_SMPTE170M: + case AVCOL_PRI_SMPTE240M: + csp->prim = ref->prim; + csp->gamut = ref->gamut; + break; + default: + csp->prim = AVCOL_PRI_BT709; + csp->gamut = av_csp_primaries_desc_from_id(csp->prim)->prim; + break; + } + + return 1; +} + +static int infer_trc_ref(SwsColor *csp, const SwsColor *ref) +{ + if (csp->trc != AVCOL_TRC_UNSPECIFIED) + return 0; + + /* Pick a suitable SDR transfer function, to try and minimize conversions */ + switch (ref->trc) { + case AVCOL_TRC_UNSPECIFIED: + /* HDR curves, never default to these */ + case AVCOL_TRC_SMPTE2084: + case AVCOL_TRC_ARIB_STD_B67: + csp->trc = AVCOL_TRC_BT709; + csp->min_luma = av_make_q(0, 1); + csp->max_luma = av_make_q(203, 1); + break; + default: + csp->trc = ref->trc; + csp->min_luma = ref->min_luma; + csp->max_luma = ref->max_luma; + break; + } + + return 1; +} + +bool ff_infer_colors(SwsColor *src, SwsColor *dst) +{ + int incomplete = 0; + + incomplete |= infer_prim_ref(dst, src); + incomplete |= infer_prim_ref(src, dst); + av_assert0(src->prim != AVCOL_PRI_UNSPECIFIED); + av_assert0(dst->prim != AVCOL_PRI_UNSPECIFIED); + + incomplete |= infer_trc_ref(dst, src); + incomplete |= infer_trc_ref(src, dst); + av_assert0(src->trc != AVCOL_TRC_UNSPECIFIED); + av_assert0(dst->trc != AVCOL_TRC_UNSPECIFIED); + + return incomplete; +} + +int sws_test_format(enum AVPixelFormat format, int output) +{ + return output ? sws_isSupportedOutput(format) : sws_isSupportedInput(format); +} + +int sws_test_hw_format(enum AVPixelFormat format) +{ + switch (format) { + case AV_PIX_FMT_NONE: return 1; +#if CONFIG_VULKAN + case AV_PIX_FMT_VULKAN: return 1; +#endif + default: return 0; + } +} + +int sws_test_colorspace(enum AVColorSpace csp, int output) +{ + switch (csp) { + case AVCOL_SPC_UNSPECIFIED: + case AVCOL_SPC_RGB: + case AVCOL_SPC_BT709: + case AVCOL_SPC_BT470BG: + case AVCOL_SPC_SMPTE170M: + case AVCOL_SPC_FCC: + case AVCOL_SPC_SMPTE240M: + case AVCOL_SPC_BT2020_NCL: + return 1; + default: + return 0; + } +} + +int sws_test_primaries(enum AVColorPrimaries prim, int output) +{ + return ((prim > AVCOL_PRI_RESERVED0 && prim < AVCOL_PRI_NB) || + (prim >= AVCOL_PRI_EXT_BASE && prim < AVCOL_PRI_EXT_NB)) && + prim != AVCOL_PRI_RESERVED; +} + +int sws_test_transfer(enum AVColorTransferCharacteristic trc, int output) +{ + av_csp_eotf_function eotf = output ? av_csp_itu_eotf_inv(trc) + : av_csp_itu_eotf(trc); + return trc == AVCOL_TRC_UNSPECIFIED || eotf != NULL; +} + +static int test_range(enum AVColorRange range) +{ + return (unsigned)range < AVCOL_RANGE_NB; +} + +static int test_loc(enum AVChromaLocation loc) +{ + return (unsigned)loc < AVCHROMA_LOC_NB; +} + +int ff_test_fmt(const SwsFormat *fmt, int output) +{ + return fmt->width > 0 && fmt->height > 0 && + sws_test_format (fmt->format, output) && + sws_test_colorspace(fmt->csp, output) && + sws_test_primaries (fmt->color.prim, output) && + sws_test_transfer (fmt->color.trc, output) && + sws_test_hw_format (fmt->hw_format) && + test_range (fmt->range) && + test_loc (fmt->loc); +} + +int sws_test_frame(const AVFrame *frame, int output) +{ + for (int field = 0; field < 2; field++) { + const SwsFormat fmt = ff_fmt_from_frame(frame, field); + if (!ff_test_fmt(&fmt, output)) + return 0; + if (!fmt.interlaced) + break; + } + + return 1; +} + +int sws_is_noop(const AVFrame *dst, const AVFrame *src) +{ + for (int field = 0; field < 2; field++) { + SwsFormat dst_fmt = ff_fmt_from_frame(dst, field); + SwsFormat src_fmt = ff_fmt_from_frame(src, field); + if (!ff_fmt_equal(&dst_fmt, &src_fmt)) + return 0; + if (!dst_fmt.interlaced) + break; + } + + return 1; +} + +void ff_sws_frame_from_avframe(SwsFrame *dst, const AVFrame *src) +{ + dst->format = src->format; + dst->width = src->width; + dst->height = src->height; + dst->avframe = src; + for (int i = 0; i < FF_ARRAY_ELEMS(dst->data); i++) { + dst->data[i] = src->data[i]; + dst->linesize[i] = src->linesize[i]; + } +} + +#if CONFIG_UNSTABLE + +/* Returns the type suitable for a pixel after fully decoding/unpacking it */ +static SwsPixelType fmt_pixel_type(enum AVPixelFormat fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + const int bits = FFALIGN(desc->comp[0].depth, 8); + if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { + switch (bits) { + case 32: return SWS_PIXEL_F32; + /* TODO: no support for 16-bit float yet */ + } + } else { + switch (bits) { + case 8: return SWS_PIXEL_U8; + case 16: return SWS_PIXEL_U16; + /* TODO: AVRational cannot represent UINT32_MAX */ + } + } + + return SWS_PIXEL_NONE; +} + +/* A regular format is defined as any format that contains only a single + * component per elementary data type (i.e. no sub-byte pack/unpack needed), + * and whose components map 1:1 onto elementary data units */ +static int is_regular_fmt(enum AVPixelFormat fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + if (desc->flags & (AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_BAYER)) + return 0; /* no 1:1 correspondence between components and data units */ + if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM)) + return 0; /* bitstream formats are packed by definition */ + if ((desc->flags & AV_PIX_FMT_FLAG_PLANAR) || desc->nb_components == 1) + return 1; /* planar formats are regular by definition */ + + const int step = desc->comp[0].step; + int total_bits = 0; + + for (int i = 0; i < desc->nb_components; i++) { + if (desc->comp[i].shift || desc->comp[i].step != step) + return 0; /* irregular/packed format */ + total_bits += desc->comp[i].depth; + } + + /* Exclude formats with missing components like RGB0, 0RGB, etc. */ + return total_bits == step * 8; +} + +typedef struct FmtInfo { + SwsReadWriteOp rw; + SwsSwizzleOp swizzle; + SwsPackOp pack; + int shift; +} FmtInfo; + +#define BITSTREAM_FMT(SWIZ, FRAC, PACKED, ...) (FmtInfo) { \ + .rw = { .elems = 1, .frac = FRAC, .packed = PACKED }, \ + .swizzle = SWIZ, \ + __VA_ARGS__ \ +} + +#define SUBPACKED_FMT(SWIZ, ...) (FmtInfo) { \ + .rw = { .elems = 1, .packed = true }, \ + .swizzle = SWIZ, \ + .pack.pattern = {__VA_ARGS__}, \ +} + +#define PACKED_FMT(SWIZ, N, ...) (FmtInfo) { \ + .rw = { .elems = N, .packed = (N) > 1 }, \ + .swizzle = SWIZ, \ + __VA_ARGS__ \ +} + +#define RGBA SWS_SWIZZLE(0, 1, 2, 3) +#define BGRA SWS_SWIZZLE(2, 1, 0, 3) +#define ARGB SWS_SWIZZLE(3, 0, 1, 2) +#define ABGR SWS_SWIZZLE(3, 2, 1, 0) +#define AVYU SWS_SWIZZLE(3, 2, 0, 1) +#define VYUA SWS_SWIZZLE(2, 0, 1, 3) +#define UYVA SWS_SWIZZLE(1, 0, 2, 3) +#define VUYA BGRA + +static FmtInfo fmt_info_irregular(enum AVPixelFormat fmt) +{ + switch (fmt) { + /* Bitstream formats */ + case AV_PIX_FMT_MONOWHITE: + case AV_PIX_FMT_MONOBLACK: + return BITSTREAM_FMT(RGBA, 3, false); + case AV_PIX_FMT_RGB4: return BITSTREAM_FMT(RGBA, 1, true, .pack = {{ 1, 2, 1 }}); + case AV_PIX_FMT_BGR4: return BITSTREAM_FMT(BGRA, 1, true, .pack = {{ 1, 2, 1 }}); + + /* Sub-packed 8-bit aligned formats */ + case AV_PIX_FMT_RGB4_BYTE: return SUBPACKED_FMT(RGBA, 1, 2, 1); + case AV_PIX_FMT_BGR4_BYTE: return SUBPACKED_FMT(BGRA, 1, 2, 1); + case AV_PIX_FMT_RGB8: return SUBPACKED_FMT(RGBA, 3, 3, 2); + case AV_PIX_FMT_BGR8: return SUBPACKED_FMT(BGRA, 2, 3, 3); + + /* Sub-packed 16-bit aligned formats */ + case AV_PIX_FMT_RGB565LE: + case AV_PIX_FMT_RGB565BE: + return SUBPACKED_FMT(RGBA, 5, 6, 5); + case AV_PIX_FMT_BGR565LE: + case AV_PIX_FMT_BGR565BE: + return SUBPACKED_FMT(BGRA, 5, 6, 5); + case AV_PIX_FMT_RGB555LE: + case AV_PIX_FMT_RGB555BE: + return SUBPACKED_FMT(RGBA, 5, 5, 5); + case AV_PIX_FMT_BGR555LE: + case AV_PIX_FMT_BGR555BE: + return SUBPACKED_FMT(BGRA, 5, 5, 5); + case AV_PIX_FMT_RGB444LE: + case AV_PIX_FMT_RGB444BE: + return SUBPACKED_FMT(RGBA, 4, 4, 4); + case AV_PIX_FMT_BGR444LE: + case AV_PIX_FMT_BGR444BE: + return SUBPACKED_FMT(BGRA, 4, 4, 4); + + /* Sub-packed 32-bit aligned formats */ + case AV_PIX_FMT_X2RGB10LE: + case AV_PIX_FMT_X2RGB10BE: + return SUBPACKED_FMT(ARGB, 2, 10, 10, 10); + case AV_PIX_FMT_X2BGR10LE: + case AV_PIX_FMT_X2BGR10BE: + return SUBPACKED_FMT(ABGR, 2, 10, 10, 10); + case AV_PIX_FMT_XV30LE: + case AV_PIX_FMT_XV30BE: + return SUBPACKED_FMT(AVYU, 2, 10, 10, 10); + case AV_PIX_FMT_V30XLE: + case AV_PIX_FMT_V30XBE: + return SUBPACKED_FMT(VYUA, 10, 10, 10, 2); + + /* 3-component formats with extra padding */ + case AV_PIX_FMT_RGB0: return PACKED_FMT(RGBA, 4); + case AV_PIX_FMT_BGR0: return PACKED_FMT(BGRA, 4); + case AV_PIX_FMT_0RGB: return PACKED_FMT(ARGB, 4); + case AV_PIX_FMT_0BGR: return PACKED_FMT(ABGR, 4); + case AV_PIX_FMT_VUYX: return PACKED_FMT(VUYA, 4); + case AV_PIX_FMT_XV36LE: + case AV_PIX_FMT_XV36BE: + return PACKED_FMT(UYVA, 4, .shift = 4); + case AV_PIX_FMT_XV48LE: + case AV_PIX_FMT_XV48BE: + return PACKED_FMT(UYVA, 4); + } + + return (FmtInfo) {0}; +} + +struct comp { + int index; + int plane; + int offset; +}; + +/* Compare by (plane, offset) */ +static int cmp_comp(const void *a, const void *b) { + const struct comp *ca = a; + const struct comp *cb = b; + if (ca->plane != cb->plane) + return ca->plane - cb->plane; + return ca->offset - cb->offset; +} + +static int fmt_analyze_regular(const AVPixFmtDescriptor *desc, SwsReadWriteOp *rw_op, + SwsSwizzleOp *swizzle, int *shift) +{ + if (desc->nb_components == 2) { + /* YA formats */ + *swizzle = SWS_SWIZZLE(0, 3, 1, 2); + } else { + /* Sort by increasing component order */ + struct comp sorted[4] = { {0}, {1}, {2}, {3} }; + for (int i = 0; i < desc->nb_components; i++) { + sorted[i].plane = desc->comp[i].plane; + sorted[i].offset = desc->comp[i].offset; + } + + qsort(sorted, desc->nb_components, sizeof(struct comp), cmp_comp); + + SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3); + for (int i = 0; i < desc->nb_components; i++) + swiz.in[i] = sorted[i].index; + *swizzle = swiz; + } + + *shift = desc->comp[0].shift; + *rw_op = (SwsReadWriteOp) { + .elems = desc->nb_components, + .packed = desc->nb_components > 1 && !(desc->flags & AV_PIX_FMT_FLAG_PLANAR), + }; + return 0; +} + +static int fmt_analyze(enum AVPixelFormat fmt, SwsReadWriteOp *rw_op, + SwsPackOp *pack_op, SwsSwizzleOp *swizzle, int *shift, + SwsPixelType *pixel_type, SwsPixelType *raw_type) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + if (!desc) + return AVERROR(EINVAL); + + /* No support for subsampled formats at the moment */ + if (desc->log2_chroma_w || desc->log2_chroma_h) + return AVERROR(ENOTSUP); + + /* No support for semi-planar formats at the moment */ + if (desc->flags & AV_PIX_FMT_FLAG_PLANAR && + av_pix_fmt_count_planes(fmt) < desc->nb_components) + return AVERROR(ENOTSUP); + + *pixel_type = *raw_type = fmt_pixel_type(fmt); + if (!*pixel_type) + return AVERROR(ENOTSUP); + + if (is_regular_fmt(fmt)) { + *pack_op = (SwsPackOp) {0}; + return fmt_analyze_regular(desc, rw_op, swizzle, shift); + } + + FmtInfo info = fmt_info_irregular(fmt); + if (!info.rw.elems) + return AVERROR(ENOTSUP); + + *rw_op = info.rw; + *pack_op = info.pack; + *swizzle = info.swizzle; + *shift = info.shift; + + if (info.pack.pattern[0]) { + const int sum = info.pack.pattern[0] + info.pack.pattern[1] + + info.pack.pattern[2] + info.pack.pattern[3]; + if (sum > 16) + *raw_type = SWS_PIXEL_U32; + else if (sum > 8) + *raw_type = SWS_PIXEL_U16; + else + *raw_type = SWS_PIXEL_U8; + } + + return 0; +} + +static SwsSwizzleOp swizzle_inv(SwsSwizzleOp swiz) { + /* Input[x] =: Output[swizzle.x] */ + unsigned out[4]; + out[swiz.x] = 0; + out[swiz.y] = 1; + out[swiz.z] = 2; + out[swiz.w] = 3; + return (SwsSwizzleOp) {{ .x = out[0], out[1], out[2], out[3] }}; +} + +/** + * This initializes all absent components explicitly to zero. There is no + * need to worry about the correct neutral value as fmt_decode() will + * implicitly ignore and overwrite absent components in any case. This function + * is just to ensure that we don't operate on undefined memory. In most cases, + * it will end up getting pushed towards the output or optimized away entirely + * by the optimization pass. + */ +static SwsConst fmt_clear(enum AVPixelFormat fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + const bool has_chroma = desc->nb_components >= 3; + const bool has_alpha = desc->flags & AV_PIX_FMT_FLAG_ALPHA; + + SwsConst c = {0}; + if (!has_chroma) + c.q4[1] = c.q4[2] = Q0; + if (!has_alpha) + c.q4[3] = Q0; + + return c; +} + +#if HAVE_BIGENDIAN +# define NATIVE_ENDIAN_FLAG AV_PIX_FMT_FLAG_BE +#else +# define NATIVE_ENDIAN_FLAG 0 +#endif + +int ff_sws_decode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + SwsPixelType pixel_type, raw_type; + SwsReadWriteOp rw_op; + SwsSwizzleOp swizzle; + SwsPackOp unpack; + SwsComps *comps = &ops->comps_src; + int shift; + + RET(fmt_analyze(fmt, &rw_op, &unpack, &swizzle, &shift, + &pixel_type, &raw_type)); + + swizzle = swizzle_inv(swizzle); + + /* Set baseline pixel content flags */ + const int integer = ff_sws_pixel_type_is_int(raw_type); + const int swapped = ff_sws_pixel_type_size(raw_type) > 1 && + (desc->flags & AV_PIX_FMT_FLAG_BE) != NATIVE_ENDIAN_FLAG; + for (int i = 0; i < rw_op.elems; i++) { + comps->flags[i] = (integer ? SWS_COMP_EXACT : 0) | + (swapped ? SWS_COMP_SWAPPED : 0); + } + + /* Generate value range information for simple unpacked formats */ + if (integer && !unpack.pattern[0]) { + /* YA formats have desc->comp[] in the order {Y, A} instead of the + * canonical order {Y, U, V, A} */ + const int is_ya = desc->nb_components == 2; + for (int c = 0; c < desc->nb_components; c++) { + const int bits = desc->comp[c].depth + shift; + const int idx = swizzle.in[is_ya ? 3 * c : c]; + comps->min[idx] = Q0; + if (bits < 32) /* FIXME: AVRational is limited to INT_MAX */ + comps->max[idx] = Q((1ULL << bits) - 1); + } + } + + /* TODO: handle subsampled or semipacked input formats */ + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_READ, + .type = raw_type, + .rw = rw_op, + })); + + if (swapped) { + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_SWAP_BYTES, + .type = raw_type, + })); + } + + if (unpack.pattern[0]) { + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_UNPACK, + .type = raw_type, + .pack = unpack, + })); + + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_CONVERT, + .type = raw_type, + .convert.to = pixel_type, + })); + } + + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_SWIZZLE, + .type = pixel_type, + .swizzle = swizzle, + })); + + if (shift) { + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_RSHIFT, + .type = pixel_type, + .c.u = shift, + })); + } + + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_CLEAR, + .type = pixel_type, + .c = fmt_clear(fmt), + })); + + return 0; +} + +int ff_sws_encode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + SwsPixelType pixel_type, raw_type; + SwsReadWriteOp rw_op; + SwsSwizzleOp swizzle; + SwsPackOp pack; + int shift; + + RET(fmt_analyze(fmt, &rw_op, &pack, &swizzle, &shift, + &pixel_type, &raw_type)); + + if (shift) { + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_LSHIFT, + .type = pixel_type, + .c.u = shift, + })); + } + + if (rw_op.elems > desc->nb_components) { + /* Format writes unused alpha channel, clear it explicitly for sanity */ + av_assert1(!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)); + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_CLEAR, + .type = pixel_type, + .c.q4[3] = Q0, + })); + } + + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_SWIZZLE, + .type = pixel_type, + .swizzle = swizzle, + })); + + if (pack.pattern[0]) { + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_CONVERT, + .type = pixel_type, + .convert.to = raw_type, + })); + + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_PACK, + .type = raw_type, + .pack = pack, + })); + } + + if (ff_sws_pixel_type_size(raw_type) > 1 && + (desc->flags & AV_PIX_FMT_FLAG_BE) != NATIVE_ENDIAN_FLAG) { + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_SWAP_BYTES, + .type = raw_type, + })); + } + + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_WRITE, + .type = raw_type, + .rw = rw_op, + })); + + return 0; +} + +static inline AVRational av_neg_q(AVRational x) +{ + return (AVRational) { -x.num, x.den }; +} + +static SwsLinearOp fmt_encode_range(const SwsFormat *fmt, bool *incomplete) +{ + SwsLinearOp c = { .m = { + { Q1, Q0, Q0, Q0, Q0 }, + { Q0, Q1, Q0, Q0, Q0 }, + { Q0, Q0, Q1, Q0, Q0 }, + { Q0, Q0, Q0, Q1, Q0 }, + }}; + + const int depth0 = fmt->desc->comp[0].depth; + const int depth1 = fmt->desc->comp[1].depth; + const int depth2 = fmt->desc->comp[2].depth; + const int depth3 = fmt->desc->comp[3].depth; + + if (fmt->desc->flags & AV_PIX_FMT_FLAG_FLOAT) + return c; /* floats are directly output as-is */ + + av_assert0(depth0 < 32 && depth1 < 32 && depth2 < 32 && depth3 < 32); + if (fmt->csp == AVCOL_SPC_RGB || (fmt->desc->flags & AV_PIX_FMT_FLAG_XYZ)) { + c.m[0][0] = Q((1 << depth0) - 1); + c.m[1][1] = Q((1 << depth1) - 1); + c.m[2][2] = Q((1 << depth2) - 1); + } else if (fmt->range == AVCOL_RANGE_JPEG) { + /* Full range YUV */ + c.m[0][0] = Q((1 << depth0) - 1); + if (fmt->desc->nb_components >= 3) { + /* This follows the ITU-R convention, which is slightly different + * from the JFIF convention. */ + c.m[1][1] = Q((1 << depth1) - 1); + c.m[2][2] = Q((1 << depth2) - 1); + c.m[1][4] = Q(1 << (depth1 - 1)); + c.m[2][4] = Q(1 << (depth2 - 1)); + } + } else { + /* Limited range YUV */ + if (fmt->range == AVCOL_RANGE_UNSPECIFIED) + *incomplete = true; + c.m[0][0] = Q(219 << (depth0 - 8)); + c.m[0][4] = Q( 16 << (depth0 - 8)); + if (fmt->desc->nb_components >= 3) { + c.m[1][1] = Q(224 << (depth1 - 8)); + c.m[2][2] = Q(224 << (depth2 - 8)); + c.m[1][4] = Q(128 << (depth1 - 8)); + c.m[2][4] = Q(128 << (depth2 - 8)); + } + } + + if (fmt->desc->flags & AV_PIX_FMT_FLAG_ALPHA) { + const bool is_ya = fmt->desc->nb_components == 2; + c.m[3][3] = Q((1 << (is_ya ? depth1 : depth3)) - 1); + } + + if (fmt->format == AV_PIX_FMT_MONOWHITE) { + /* This format is inverted, 0 = white, 1 = black */ + c.m[0][4] = av_add_q(c.m[0][4], c.m[0][0]); + c.m[0][0] = av_neg_q(c.m[0][0]); + } + + c.mask = ff_sws_linear_mask(c); + return c; +} + +static SwsLinearOp fmt_decode_range(const SwsFormat *fmt, bool *incomplete) +{ + SwsLinearOp c = fmt_encode_range(fmt, incomplete); + + /* Invert main diagonal + offset: x = s * y + k ==> y = (x - k) / s */ + for (int i = 0; i < 4; i++) { + av_assert1(c.m[i][i].num); + c.m[i][i] = av_inv_q(c.m[i][i]); + c.m[i][4] = av_mul_q(c.m[i][4], av_neg_q(c.m[i][i])); + } + + /* Explicitly initialize alpha for sanity */ + if (!(fmt->desc->flags & AV_PIX_FMT_FLAG_ALPHA)) + c.m[3][4] = Q1; + + c.mask = ff_sws_linear_mask(c); + return c; +} + +static AVRational *generate_bayer_matrix(const int size_log2) +{ + const int size = 1 << size_log2; + const int num_entries = size * size; + AVRational *m = av_refstruct_allocz(sizeof(*m) * num_entries); + av_assert1(size_log2 < 16); + if (!m) + return NULL; + + /* Start with a 1x1 matrix */ + m[0] = Q0; + + /* Generate three copies of the current, appropriately scaled and offset */ + for (int sz = 1; sz < size; sz <<= 1) { + const int den = 4 * sz * sz; + for (int y = 0; y < sz; y++) { + for (int x = 0; x < sz; x++) { + const AVRational cur = m[y * size + x]; + m[(y + sz) * size + x + sz] = av_add_q(cur, av_make_q(1, den)); + m[(y ) * size + x + sz] = av_add_q(cur, av_make_q(2, den)); + m[(y + sz) * size + x ] = av_add_q(cur, av_make_q(3, den)); + } + } + } + + /** + * To correctly round, we need to evenly distribute the result on [0, 1), + * giving an average value of 1/2. + * + * After the above construction, we have a matrix with average value: + * [ 0/N + 1/N + 2/N + ... (N-1)/N ] / N = (N-1)/(2N) + * where N = size * size is the total number of entries. + * + * To make the average value equal to 1/2 = N/(2N), add a bias of 1/(2N). + */ + for (int i = 0; i < num_entries; i++) + m[i] = av_add_q(m[i], av_make_q(1, 2 * num_entries)); + + return m; +} + +static bool trc_is_hdr(enum AVColorTransferCharacteristic trc) +{ + static_assert(AVCOL_TRC_NB == 19, "Update this list when adding TRCs"); + static_assert(AVCOL_TRC_EXT_NB == 257, "Update this list when adding TRCs"); + switch (trc) { + case AVCOL_TRC_LOG: + case AVCOL_TRC_LOG_SQRT: + case AVCOL_TRC_V_LOG: + case AVCOL_TRC_SMPTEST2084: + case AVCOL_TRC_ARIB_STD_B67: + return true; + default: + return false; + } +} + +static int fmt_dither(SwsContext *ctx, SwsOpList *ops, + const SwsPixelType type, + const SwsFormat *src, const SwsFormat *dst) +{ + SwsDither mode = ctx->dither; + SwsDitherOp dither; + const int bpc = dst->desc->comp[0].depth; + + if (mode == SWS_DITHER_AUTO) { + /* Visual threshold of perception: 12 bits for SDR, 14 bits for HDR */ + const int jnd_bits = trc_is_hdr(dst->color.trc) ? 14 : 12; + mode = bpc >= jnd_bits ? SWS_DITHER_NONE : SWS_DITHER_BAYER; + } + + switch (mode) { + case SWS_DITHER_NONE: + if (ctx->flags & SWS_ACCURATE_RND) { + /* Add constant 0.5 for correct rounding */ + AVRational *bias = av_refstruct_allocz(sizeof(*bias)); + if (!bias) + return AVERROR(ENOMEM); + *bias = (AVRational) {1, 2}; + return ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_DITHER, + .type = type, + .dither.matrix = bias, + }); + } else { + return 0; /* No-op */ + } + case SWS_DITHER_BAYER: + /* Hardcode 16x16 matrix for now; in theory we could adjust this + * based on the expected level of precision in the output, since lower + * bit depth outputs can suffice with smaller dither matrices; however + * in practice we probably want to use error diffusion for such low bit + * depths anyway */ + dither.size_log2 = 4; + dither.matrix = generate_bayer_matrix(dither.size_log2); + if (!dither.matrix) + return AVERROR(ENOMEM); + + /* Brute-forced offsets; minimizes quantization error across a 16x16 + * bayer dither pattern for standard RGBA and YUVA pixel formats */ + const int offsets_16x16[4] = {0, 3, 2, 5}; + for (int i = 0; i < 4; i++) { + av_assert0(offsets_16x16[i] <= INT8_MAX); + dither.y_offset[i] = offsets_16x16[i]; + } + + if (src->desc->nb_components < 3 && bpc >= 8) { + /** + * For high-bit-depth sources without chroma, use same matrix + * offset for all color channels. This prevents introducing color + * noise in grayscale images; and also allows optimizing the dither + * operation. Skipped for low bit depth (<8 bpc) as the loss in + * PSNR, from the inability to diffuse error among all three + * channels, can be substantial. + * + * This shifts: { X, Y, Z, W } -> { X, X, X, Y } + */ + dither.y_offset[3] = dither.y_offset[1]; + dither.y_offset[1] = dither.y_offset[2] = dither.y_offset[0]; + } + + return ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_DITHER, + .type = type, + .dither = dither, + }); + case SWS_DITHER_ED: + case SWS_DITHER_A_DITHER: + case SWS_DITHER_X_DITHER: + return AVERROR(ENOTSUP); + + case SWS_DITHER_NB: + break; + } + + av_unreachable("Invalid dither mode"); + return AVERROR(EINVAL); +} + +static inline SwsLinearOp +linear_mat3(const AVRational m00, const AVRational m01, const AVRational m02, + const AVRational m10, const AVRational m11, const AVRational m12, + const AVRational m20, const AVRational m21, const AVRational m22) +{ + SwsLinearOp c = {{ + { m00, m01, m02, Q0, Q0 }, + { m10, m11, m12, Q0, Q0 }, + { m20, m21, m22, Q0, Q0 }, + { Q0, Q0, Q0, Q1, Q0 }, + }}; + + c.mask = ff_sws_linear_mask(c); + return c; +} + +int ff_sws_decode_colors(SwsContext *ctx, SwsPixelType type, + SwsOpList *ops, const SwsFormat *fmt, bool *incomplete) +{ + const AVLumaCoefficients *c = av_csp_luma_coeffs_from_avcsp(fmt->csp); + const SwsPixelType pixel_type = fmt_pixel_type(fmt->format); + if (!pixel_type) + return AVERROR(ENOTSUP); + + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_CONVERT, + .type = pixel_type, + .convert.to = type, + })); + + /* Decode pixel format into standardized range */ + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .type = type, + .op = SWS_OP_LINEAR, + .lin = fmt_decode_range(fmt, incomplete), + })); + + /* Final step, decode colorspace */ + switch (fmt->csp) { + case AVCOL_SPC_RGB: + return 0; + case AVCOL_SPC_UNSPECIFIED: + c = av_csp_luma_coeffs_from_avcsp(AVCOL_SPC_BT470BG); + *incomplete = true; + /* fall through */ + case AVCOL_SPC_FCC: + case AVCOL_SPC_BT470BG: + case AVCOL_SPC_SMPTE170M: + case AVCOL_SPC_BT709: + case AVCOL_SPC_SMPTE240M: + case AVCOL_SPC_BT2020_NCL: { + AVRational crg = av_sub_q(Q0, av_div_q(c->cr, c->cg)); + AVRational cbg = av_sub_q(Q0, av_div_q(c->cb, c->cg)); + AVRational m02 = av_mul_q(Q(2), av_sub_q(Q1, c->cr)); + AVRational m21 = av_mul_q(Q(2), av_sub_q(Q1, c->cb)); + AVRational m11 = av_mul_q(cbg, m21); + AVRational m12 = av_mul_q(crg, m02); + + return ff_sws_op_list_append(ops, &(SwsOp) { + .type = type, + .op = SWS_OP_LINEAR, + .lin = linear_mat3( + Q1, Q0, m02, + Q1, m11, m12, + Q1, m21, Q0 + ), + }); + } + + case AVCOL_SPC_YCGCO: + return ff_sws_op_list_append(ops, &(SwsOp) { + .type = type, + .op = SWS_OP_LINEAR, + .lin = linear_mat3( + Q1, Q(-1), Q( 1), + Q1, Q( 1), Q( 0), + Q1, Q(-1), Q(-1) + ), + }); + + case AVCOL_SPC_BT2020_CL: + case AVCOL_SPC_SMPTE2085: + case AVCOL_SPC_CHROMA_DERIVED_NCL: + case AVCOL_SPC_CHROMA_DERIVED_CL: + case AVCOL_SPC_ICTCP: + case AVCOL_SPC_IPT_C2: + case AVCOL_SPC_YCGCO_RE: + case AVCOL_SPC_YCGCO_RO: + return AVERROR(ENOTSUP); + + case AVCOL_SPC_RESERVED: + return AVERROR(EINVAL); + + case AVCOL_SPC_NB: + break; + } + + av_unreachable("Corrupt AVColorSpace value?"); + return AVERROR(EINVAL); +} + +int ff_sws_encode_colors(SwsContext *ctx, SwsPixelType type, + SwsOpList *ops, const SwsFormat *src, + const SwsFormat *dst, bool *incomplete) +{ + const AVLumaCoefficients *c = av_csp_luma_coeffs_from_avcsp(dst->csp); + const SwsPixelType pixel_type = fmt_pixel_type(dst->format); + if (!pixel_type) + return AVERROR(ENOTSUP); + + switch (dst->csp) { + case AVCOL_SPC_RGB: + break; + case AVCOL_SPC_UNSPECIFIED: + c = av_csp_luma_coeffs_from_avcsp(AVCOL_SPC_BT470BG); + *incomplete = true; + /* fall through */ + case AVCOL_SPC_FCC: + case AVCOL_SPC_BT470BG: + case AVCOL_SPC_SMPTE170M: + case AVCOL_SPC_BT709: + case AVCOL_SPC_SMPTE240M: + case AVCOL_SPC_BT2020_NCL: { + AVRational cb1 = av_sub_q(c->cb, Q1); + AVRational cr1 = av_sub_q(c->cr, Q1); + AVRational m20 = av_make_q(1,2); + AVRational m10 = av_mul_q(m20, av_div_q(c->cr, cb1)); + AVRational m11 = av_mul_q(m20, av_div_q(c->cg, cb1)); + AVRational m21 = av_mul_q(m20, av_div_q(c->cg, cr1)); + AVRational m22 = av_mul_q(m20, av_div_q(c->cb, cr1)); + + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .type = type, + .op = SWS_OP_LINEAR, + .lin = linear_mat3( + c->cr, c->cg, c->cb, + m10, m11, m20, + m20, m21, m22 + ), + })); + break; + } + + case AVCOL_SPC_YCGCO: + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .type = type, + .op = SWS_OP_LINEAR, + .lin = linear_mat3( + av_make_q( 1, 4), av_make_q(1, 2), av_make_q( 1, 4), + av_make_q( 1, 2), av_make_q(0, 1), av_make_q(-1, 2), + av_make_q(-1, 4), av_make_q(1, 2), av_make_q(-1, 4) + ), + })); + break; + + case AVCOL_SPC_BT2020_CL: + case AVCOL_SPC_SMPTE2085: + case AVCOL_SPC_CHROMA_DERIVED_NCL: + case AVCOL_SPC_CHROMA_DERIVED_CL: + case AVCOL_SPC_ICTCP: + case AVCOL_SPC_IPT_C2: + case AVCOL_SPC_YCGCO_RE: + case AVCOL_SPC_YCGCO_RO: + return AVERROR(ENOTSUP); + + case AVCOL_SPC_RESERVED: + case AVCOL_SPC_NB: + return AVERROR(EINVAL); + } + + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .type = type, + .op = SWS_OP_LINEAR, + .lin = fmt_encode_range(dst, incomplete), + })); + + if (!(dst->desc->flags & AV_PIX_FMT_FLAG_FLOAT)) { + SwsConst range = {0}; + + const bool is_ya = dst->desc->nb_components == 2; + for (int i = 0; i < dst->desc->nb_components; i++) { + /* Clamp to legal pixel range */ + const int idx = i * (is_ya ? 3 : 1); + range.q4[idx] = Q((1 << dst->desc->comp[i].depth) - 1); + } + + RET(fmt_dither(ctx, ops, type, src, dst)); + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_MAX, + .type = type, + .c.q4 = { Q0, Q0, Q0, Q0 }, + })); + + RET(ff_sws_op_list_append(ops, &(SwsOp) { + .op = SWS_OP_MIN, + .type = type, + .c = range, + })); + } + + return ff_sws_op_list_append(ops, &(SwsOp) { + .type = type, + .op = SWS_OP_CONVERT, + .convert.to = pixel_type, + }); +} + +#endif /* CONFIG_UNSTABLE */ diff --git a/libs/ffmpeg/libswscale/format.h b/libs/ffmpeg/libswscale/format.h new file mode 100644 index 00000000000..d66851893fe --- /dev/null +++ b/libs/ffmpeg/libswscale/format.h @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2024 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_FORMAT_H +#define SWSCALE_FORMAT_H + +#include <stdbool.h> + +#include "libavutil/csp.h" +#include "libavutil/pixdesc.h" + +#include "swscale.h" + +static inline int ff_q_isnan(const AVRational a) +{ + return !a.num && !a.den; +} + +/* Like av_cmp_q but considers NaN == NaN */ +static inline int ff_q_equal(const AVRational a, const AVRational b) +{ + return (ff_q_isnan(a) && ff_q_isnan(b)) || !av_cmp_q(a, b); +} + +static inline int ff_cie_xy_equal(const AVCIExy a, const AVCIExy b) +{ + return ff_q_equal(a.x, b.x) && ff_q_equal(a.y, b.y); +} + +static inline int ff_prim_equal(const AVPrimaryCoefficients *a, + const AVPrimaryCoefficients *b) +{ + return ff_cie_xy_equal(a->r, b->r) && + ff_cie_xy_equal(a->g, b->g) && + ff_cie_xy_equal(a->b, b->b); +} + +enum { + FIELD_TOP, /* top/even rows, or progressive */ + FIELD_BOTTOM, /* bottom/odd rows */ +}; + +typedef struct SwsColor { + enum AVColorPrimaries prim; + enum AVColorTransferCharacteristic trc; + AVPrimaryCoefficients gamut; /* mastering display gamut */ + AVRational min_luma; /* minimum luminance in nits */ + AVRational max_luma; /* maximum luminance in nits */ + AVRational frame_peak; /* per-frame/scene peak luminance, or 0 */ + AVRational frame_avg; /* per-frame/scene average luminance, or 0 */ +} SwsColor; + +static inline void ff_color_update_dynamic(SwsColor *dst, const SwsColor *src) +{ + dst->frame_peak = src->frame_peak; + dst->frame_avg = src->frame_avg; +} + +/* Subset of AVFrame parameters that uniquely determine pixel representation */ +typedef struct SwsFormat { + int width, height; + int interlaced; + enum AVPixelFormat format; + enum AVPixelFormat hw_format; + enum AVColorRange range; + enum AVColorSpace csp; + enum AVChromaLocation loc; + const AVPixFmtDescriptor *desc; /* convenience */ + SwsColor color; +} SwsFormat; + +static inline void ff_fmt_clear(SwsFormat *fmt) +{ + *fmt = (SwsFormat) { + .format = AV_PIX_FMT_NONE, + .range = AVCOL_RANGE_UNSPECIFIED, + .csp = AVCOL_SPC_UNSPECIFIED, + .loc = AVCHROMA_LOC_UNSPECIFIED, + .color = { + .prim = AVCOL_PRI_UNSPECIFIED, + .trc = AVCOL_TRC_UNSPECIFIED, + }, + }; +} + +/** + * This function also sanitizes and strips the input data, removing irrelevant + * fields for certain formats. + */ +SwsFormat ff_fmt_from_frame(const AVFrame *frame, int field); + +static inline int ff_color_equal(const SwsColor *c1, const SwsColor *c2) +{ + return c1->prim == c2->prim && + c1->trc == c2->trc && + ff_q_equal(c1->min_luma, c2->min_luma) && + ff_q_equal(c1->max_luma, c2->max_luma) && + ff_prim_equal(&c1->gamut, &c2->gamut); +} + +/* Tests only the static components of a colorspace, ignoring dimensions and per-frame data */ +static inline int ff_props_equal(const SwsFormat *fmt1, const SwsFormat *fmt2) +{ + return fmt1->interlaced == fmt2->interlaced && + fmt1->format == fmt2->format && + fmt1->range == fmt2->range && + fmt1->csp == fmt2->csp && + fmt1->loc == fmt2->loc && + ff_color_equal(&fmt1->color, &fmt2->color); +} + +/* Tests only the static components of a colorspace, ignoring per-frame data */ +static inline int ff_fmt_equal(const SwsFormat *fmt1, const SwsFormat *fmt2) +{ + return fmt1->width == fmt2->width && + fmt1->height == fmt2->height && + ff_props_equal(fmt1, fmt2); +} + +static inline int ff_fmt_align(enum AVPixelFormat fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + if (desc->flags & AV_PIX_FMT_FLAG_BAYER) { + return 2; + } else { + return 1 << desc->log2_chroma_h; + } +} + +int ff_test_fmt(const SwsFormat *fmt, int output); + +/* Returns true if the formats are incomplete, false otherwise */ +bool ff_infer_colors(SwsColor *src, SwsColor *dst); + +typedef struct SwsOpList SwsOpList; +typedef enum SwsPixelType SwsPixelType; + +/** + * Append a set of operations for decoding/encoding raw pixels. This will + * handle input read/write, swizzling, shifting and byte swapping. + * + * Returns 0 on success, or a negative error code on failure. + */ +int ff_sws_decode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt); +int ff_sws_encode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt); + +/** + * Append a set of operations for transforming decoded pixel values to/from + * normalized RGB in the specified gamut and pixel type. + * + * Returns 0 on success, or a negative error code on failure. + */ +int ff_sws_decode_colors(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, + const SwsFormat *fmt, bool *incomplete); +int ff_sws_encode_colors(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, + const SwsFormat *src, const SwsFormat *dst, + bool *incomplete); + +/** + * Represents a view into a single field of frame data. + * + * Ostensibly, this is a (non-compatible) subset of AVFrame, however, the + * semantics are VERY different. + * + * Unlike AVFrame, this struct does NOT own any data references. All buffers + * referenced by a SwsFrame are managed externally. This merely represents + * a view into data. + * + * This struct is not refcounted, and may be freely copied onto the stack. + */ +typedef struct SwsFrame { + /* Data buffers and line stride */ + uint8_t *data[4]; + int linesize[4]; + + /** + * Dimensions and format + */ + int width, height; + enum AVPixelFormat format; + + /** + * Pointer to the original AVFrame, if there is a 1:1 correspondence. + **/ + const AVFrame *avframe; +} SwsFrame; + +/** + * Initialize a SwsFrame from an AVFrame. + */ +void ff_sws_frame_from_avframe(SwsFrame *dst, const AVFrame *src); + +#endif /* SWSCALE_FORMAT_H */ diff --git a/libs/ffmpeg/libswscale/gamma.c b/libs/ffmpeg/libswscale/gamma.c new file mode 100644 index 00000000000..7fb1b7763f1 --- /dev/null +++ b/libs/ffmpeg/libswscale/gamma.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 Pedro Arthur <bygrandao@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/mem.h" +#include "swscale_internal.h" + +typedef struct GammaContext +{ + uint16_t *table; +} GammaContext; + +// gamma_convert expects 16 bit rgb format +// it writes directly in src slice thus it must be modifiable (done through cascade context) +static int gamma_convert(SwsInternal *c, SwsFilterDescriptor *desc, int sliceY, int sliceH) +{ + GammaContext *instance = desc->instance; + uint16_t *table = instance->table; + int srcW = desc->src->width; + + int i; + for (i = 0; i < sliceH; ++i) { + uint8_t ** src = desc->src->plane[0].line; + int src_pos = sliceY+i - desc->src->plane[0].sliceY; + + uint16_t *src1 = (uint16_t*)*(src+src_pos); + int j; + for (j = 0; j < srcW; ++j) { + uint16_t r = AV_RL16(src1 + j*4 + 0); + uint16_t g = AV_RL16(src1 + j*4 + 1); + uint16_t b = AV_RL16(src1 + j*4 + 2); + + AV_WL16(src1 + j*4 + 0, table[r]); + AV_WL16(src1 + j*4 + 1, table[g]); + AV_WL16(src1 + j*4 + 2, table[b]); + } + + } + return sliceH; +} + + +int ff_init_gamma_convert(SwsFilterDescriptor *desc, SwsSlice * src, uint16_t *table) +{ + GammaContext *li = av_malloc(sizeof(GammaContext)); + if (!li) + return AVERROR(ENOMEM); + li->table = table; + + desc->instance = li; + desc->src = src; + desc->dst = NULL; + desc->process = &gamma_convert; + + return 0; +} diff --git a/libs/ffmpeg/libswscale/graph.c b/libs/ffmpeg/libswscale/graph.c new file mode 100644 index 00000000000..8e8fb01f95f --- /dev/null +++ b/libs/ffmpeg/libswscale/graph.c @@ -0,0 +1,921 @@ +/* + * Copyright (C) 2024 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/cpu.h" +#include "libavutil/error.h" +#include "libavutil/imgutils.h" +#include "libavutil/macros.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/refstruct.h" +#include "libavutil/slicethread.h" + +#include "libswscale/swscale.h" +#include "libswscale/format.h" + +#include "cms.h" +#include "lut3d.h" +#include "swscale_internal.h" +#include "graph.h" +#include "ops.h" + +/* Allocates one buffer per plane */ +static int frame_alloc_planes(AVFrame *dst) +{ + int ret = av_image_check_size2(dst->width, dst->height, INT64_MAX, + dst->format, 0, NULL); + if (ret < 0) + return ret; + + const int align = av_cpu_max_align(); + const int aligned_w = FFALIGN(dst->width, align); + ret = av_image_fill_linesizes(dst->linesize, dst->format, aligned_w); + if (ret < 0) + return ret; + + ptrdiff_t linesize1[4]; + for (int i = 0; i < 4; i++) + linesize1[i] = dst->linesize[i] = FFALIGN(dst->linesize[i], align); + + size_t sizes[4]; + ret = av_image_fill_plane_sizes(sizes, dst->format, dst->height, linesize1); + if (ret < 0) + return ret; + + for (int i = 0; i < 4; i++) { + if (!sizes[i]) + break; + AVBufferRef *buf = av_buffer_alloc(sizes[i]); + if (!buf) + return AVERROR(ENOMEM); + dst->data[i] = buf->data; + dst->buf[i] = buf; + } + + return 0; +} + +static int pass_alloc_output(SwsPass *pass) +{ + if (!pass || pass->output->avframe) + return 0; + + SwsPassBuffer *buffer = pass->output; + AVFrame *avframe = av_frame_alloc(); + if (!avframe) + return AVERROR(ENOMEM); + avframe->format = pass->format; + avframe->width = buffer->width; + avframe->height = buffer->height; + + int ret = frame_alloc_planes(avframe); + if (ret < 0) { + av_frame_free(&avframe); + return ret; + } + + buffer->avframe = avframe; + ff_sws_frame_from_avframe(&buffer->frame, avframe); + return 0; +} + +static void free_buffer(AVRefStructOpaque opaque, void *obj) +{ + SwsPassBuffer *buffer = obj; + av_frame_free(&buffer->avframe); +} + +int ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt, + int width, int height, SwsPass *input, + int align, void *priv, sws_filter_run_t run, + SwsPass **out_pass) +{ + int ret; + SwsPass *pass = av_mallocz(sizeof(*pass)); + if (!pass) + return AVERROR(ENOMEM); + + pass->graph = graph; + pass->run = run; + pass->priv = priv; + pass->format = fmt; + pass->width = width; + pass->height = height; + pass->input = input; + pass->output = av_refstruct_alloc_ext(sizeof(*pass->output), 0, NULL, free_buffer); + if (!pass->output) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = pass_alloc_output(input); + if (ret < 0) + goto fail; + + if (!align) { + pass->slice_h = pass->height; + pass->num_slices = 1; + } else { + pass->slice_h = (pass->height + graph->num_threads - 1) / graph->num_threads; + pass->slice_h = FFALIGN(pass->slice_h, align); + pass->num_slices = (pass->height + pass->slice_h - 1) / pass->slice_h; + } + + /* Align output buffer to include extra slice padding */ + pass->output->width = pass->width; + pass->output->height = pass->slice_h * pass->num_slices; + + ret = av_dynarray_add_nofree(&graph->passes, &graph->num_passes, pass); + if (ret < 0) + goto fail; + + *out_pass = pass; + return 0; + +fail: + av_refstruct_unref(&pass->output); + av_free(pass); + return ret; +} + +static void frame_shift(const SwsFrame *f, const int y, uint8_t *data[4]) +{ + for (int i = 0; i < 4; i++) { + if (f->data[i]) + data[i] = f->data[i] + (y >> ff_fmt_vshift(f->format, i)) * f->linesize[i]; + else + data[i] = NULL; + } +} + +static void run_copy(const SwsFrame *out, const SwsFrame *in, int y, int h, + const SwsPass *pass) +{ + uint8_t *in_data[4], *out_data[4]; + frame_shift(in, y, in_data); + frame_shift(out, y, out_data); + + for (int i = 0; i < 4 && out_data[i]; i++) { + const int lines = h >> ff_fmt_vshift(in->format, i); + av_assert1(in_data[i]); + + if (in_data[i] == out_data[i]) { + av_assert0(in->linesize[i] == out->linesize[i]); + } else if (in->linesize[i] == out->linesize[i]) { + memcpy(out_data[i], in_data[i], lines * out->linesize[i]); + } else { + const int linesize = FFMIN(out->linesize[i], in->linesize[i]); + for (int j = 0; j < lines; j++) { + memcpy(out_data[i], in_data[i], linesize); + in_data[i] += in->linesize[i]; + out_data[i] += out->linesize[i]; + } + } + } +} + +static void run_rgb0(const SwsFrame *out, const SwsFrame *in, int y, int h, + const SwsPass *pass) +{ + SwsInternal *c = pass->priv; + const int x0 = c->src0Alpha - 1; + const int w4 = 4 * pass->width; + const int src_stride = in->linesize[0]; + const int dst_stride = out->linesize[0]; + const uint8_t *src = in->data[0] + y * src_stride; + uint8_t *dst = out->data[0] + y * dst_stride; + + for (int y = 0; y < h; y++) { + memcpy(dst, src, w4 * sizeof(*dst)); + for (int x = x0; x < w4; x += 4) + dst[x] = 0xFF; + + src += src_stride; + dst += dst_stride; + } +} + +static void run_xyz2rgb(const SwsFrame *out, const SwsFrame *in, int y, int h, + const SwsPass *pass) +{ + const SwsInternal *c = pass->priv; + c->xyz12Torgb48(c, out->data[0] + y * out->linesize[0], out->linesize[0], + in->data[0] + y * in->linesize[0], in->linesize[0], + pass->width, h); +} + +static void run_rgb2xyz(const SwsFrame *out, const SwsFrame *in, int y, int h, + const SwsPass *pass) +{ + const SwsInternal *c = pass->priv; + c->rgb48Toxyz12(c, out->data[0] + y * out->linesize[0], out->linesize[0], + in->data[0] + y * in->linesize[0], in->linesize[0], + pass->width, h); +} + +/*********************************************************************** + * Internal ff_swscale() wrapper. This reuses the legacy scaling API. * + * This is considered fully deprecated, and will be replaced by a full * + * reimplementation ASAP. * + ***********************************************************************/ + +static void free_legacy_swscale(void *priv) +{ + SwsContext *sws = priv; + sws_free_context(&sws); +} + +static void setup_legacy_swscale(const SwsFrame *out, const SwsFrame *in, + const SwsPass *pass) +{ + SwsContext *sws = pass->priv; + SwsInternal *c = sws_internal(sws); + if (sws->flags & SWS_BITEXACT && sws->dither == SWS_DITHER_ED && c->dither_error[0]) { + for (int i = 0; i < 4; i++) + memset(c->dither_error[i], 0, sizeof(c->dither_error[0][0]) * (sws->dst_w + 2)); + } + + if (usePal(sws->src_format)) + ff_update_palette(c, (const uint32_t *) in->data[1]); +} + +static inline SwsContext *slice_ctx(const SwsPass *pass, int y) +{ + SwsContext *sws = pass->priv; + SwsInternal *parent = sws_internal(sws); + if (pass->num_slices == 1) + return sws; + + av_assert1(parent->nb_slice_ctx == pass->num_slices); + sws = parent->slice_ctx[y / pass->slice_h]; + + if (usePal(sws->src_format)) { + SwsInternal *sub = sws_internal(sws); + memcpy(sub->pal_yuv, parent->pal_yuv, sizeof(sub->pal_yuv)); + memcpy(sub->pal_rgb, parent->pal_rgb, sizeof(sub->pal_rgb)); + } + + return sws; +} + +static void run_legacy_unscaled(const SwsFrame *out, const SwsFrame *in, + int y, int h, const SwsPass *pass) +{ + SwsContext *sws = slice_ctx(pass, y); + SwsInternal *c = sws_internal(sws); + uint8_t *in_data[4]; + frame_shift(in, y, in_data); + + c->convert_unscaled(c, (const uint8_t *const *) in_data, in->linesize, y, h, + out->data, out->linesize); +} + +static void run_legacy_swscale(const SwsFrame *out, const SwsFrame *in, + int y, int h, const SwsPass *pass) +{ + SwsContext *sws = slice_ctx(pass, y); + SwsInternal *c = sws_internal(sws); + uint8_t *out_data[4]; + frame_shift(out, y, out_data); + + ff_swscale(c, (const uint8_t *const *) in->data, in->linesize, 0, + sws->src_h, out_data, out->linesize, y, h); +} + +static void get_chroma_pos(SwsGraph *graph, int *h_chr_pos, int *v_chr_pos, + const SwsFormat *fmt) +{ + enum AVChromaLocation chroma_loc = fmt->loc; + const int sub_x = fmt->desc->log2_chroma_w; + const int sub_y = fmt->desc->log2_chroma_h; + int x_pos, y_pos; + + /* Explicitly default to center siting for compatibility with swscale */ + if (chroma_loc == AVCHROMA_LOC_UNSPECIFIED) { + chroma_loc = AVCHROMA_LOC_CENTER; + graph->incomplete |= sub_x || sub_y; + } + + /* av_chroma_location_enum_to_pos() always gives us values in the range from + * 0 to 256, but we need to adjust this to the true value range of the + * subsampling grid, which may be larger for h/v_sub > 1 */ + av_chroma_location_enum_to_pos(&x_pos, &y_pos, chroma_loc); + x_pos *= (1 << sub_x) - 1; + y_pos *= (1 << sub_y) - 1; + + /* Fix vertical chroma position for interlaced frames */ + if (sub_y && fmt->interlaced) { + /* When vertically subsampling, chroma samples are effectively only + * placed next to even rows. To access them from the odd field, we need + * to account for this shift by offsetting the distance of one luma row. + * + * For 4x vertical subsampling (v_sub == 2), they are only placed + * next to every *other* even row, so we need to shift by three luma + * rows to get to the chroma sample. */ + if (graph->field == FIELD_BOTTOM) + y_pos += (256 << sub_y) - 256; + + /* Luma row distance is doubled for fields, so halve offsets */ + y_pos >>= 1; + } + + /* Explicitly strip chroma offsets when not subsampling, because it + * interferes with the operation of flags like SWS_FULL_CHR_H_INP */ + *h_chr_pos = sub_x ? x_pos : -513; + *v_chr_pos = sub_y ? y_pos : -513; +} + +static void legacy_chr_pos(SwsGraph *graph, int *chr_pos, int override, int *warned) +{ + if (override == -513 || override == *chr_pos) + return; + + if (!*warned) { + av_log(NULL, AV_LOG_WARNING, + "Setting chroma position directly is deprecated, make sure " + "the frame is tagged with the correct chroma location.\n"); + *warned = 1; + } + + *chr_pos = override; +} + +/* Takes over ownership of `sws` */ +static int init_legacy_subpass(SwsGraph *graph, SwsContext *sws, + SwsPass *input, SwsPass **output) +{ + SwsInternal *c = sws_internal(sws); + const int src_w = sws->src_w, src_h = sws->src_h; + const int dst_w = sws->dst_w, dst_h = sws->dst_h; + const int unscaled = src_w == dst_w && src_h == dst_h; + int align = c->dst_slice_align; + SwsPass *pass = NULL; + int ret; + + if (c->cascaded_context[0]) { + const int num_cascaded = c->cascaded_context[2] ? 3 : 2; + for (int i = 0; i < num_cascaded; i++) { + const int is_last = i + 1 == num_cascaded; + + /* Steal cascaded context, so we can manage its lifetime independently */ + SwsContext *sub = c->cascaded_context[i]; + c->cascaded_context[i] = NULL; + + ret = init_legacy_subpass(graph, sub, input, is_last ? output : &input); + if (ret < 0) + break; + } + + sws_free_context(&sws); + return ret; + } + + if (sws->dither == SWS_DITHER_ED && !c->convert_unscaled) + align = 0; /* disable slice threading */ + + if (c->src0Alpha && !c->dst0Alpha && isALPHA(sws->dst_format)) { + ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGBA, src_w, src_h, input, + 1, c, run_rgb0, &input); + if (ret < 0) { + sws_free_context(&sws); + return ret; + } + } + + if (c->srcXYZ && !(c->dstXYZ && unscaled)) { + ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGB48, src_w, src_h, input, + 1, c, run_xyz2rgb, &input); + if (ret < 0) { + sws_free_context(&sws); + return ret; + } + } + + ret = ff_sws_graph_add_pass(graph, sws->dst_format, dst_w, dst_h, input, align, sws, + c->convert_unscaled ? run_legacy_unscaled : run_legacy_swscale, + &pass); + if (ret < 0) { + sws_free_context(&sws); + return ret; + } + pass->setup = setup_legacy_swscale; + pass->free = free_legacy_swscale; + + /** + * For slice threading, we need to create sub contexts, similar to how + * swscale normally handles it internally. The most important difference + * is that we handle cascaded contexts before threaded contexts; whereas + * context_init_threaded() does it the other way around. + */ + + if (pass->num_slices > 1) { + c->slice_ctx = av_calloc(pass->num_slices, sizeof(*c->slice_ctx)); + if (!c->slice_ctx) + return AVERROR(ENOMEM); + + for (int i = 0; i < pass->num_slices; i++) { + SwsContext *slice; + SwsInternal *c2; + slice = c->slice_ctx[i] = sws_alloc_context(); + if (!slice) + return AVERROR(ENOMEM); + c->nb_slice_ctx++; + + c2 = sws_internal(slice); + c2->parent = sws; + + ret = av_opt_copy(slice, sws); + if (ret < 0) + return ret; + + ret = ff_sws_init_single_context(slice, NULL, NULL); + if (ret < 0) + return ret; + + sws_setColorspaceDetails(slice, c->srcColorspaceTable, + slice->src_range, c->dstColorspaceTable, + slice->dst_range, c->brightness, c->contrast, + c->saturation); + + for (int i = 0; i < FF_ARRAY_ELEMS(c->srcColorspaceTable); i++) { + c2->srcColorspaceTable[i] = c->srcColorspaceTable[i]; + c2->dstColorspaceTable[i] = c->dstColorspaceTable[i]; + } + } + } + + if (c->dstXYZ && !(c->srcXYZ && unscaled)) { + ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGB48, dst_w, dst_h, pass, + 1, c, run_rgb2xyz, &pass); + if (ret < 0) + return ret; + } + + *output = pass; + return 0; +} + +static int add_legacy_sws_pass(SwsGraph *graph, const SwsFormat *src, + const SwsFormat *dst, SwsPass *input, + SwsPass **output) +{ + int ret, warned = 0; + SwsContext *const ctx = graph->ctx; + if (src->hw_format != AV_PIX_FMT_NONE || dst->hw_format != AV_PIX_FMT_NONE) + return AVERROR(ENOTSUP); + + SwsContext *sws = sws_alloc_context(); + if (!sws) + return AVERROR(ENOMEM); + + sws->flags = ctx->flags; + sws->dither = ctx->dither; + sws->alpha_blend = ctx->alpha_blend; + sws->gamma_flag = ctx->gamma_flag; + + sws->src_w = src->width; + sws->src_h = src->height; + sws->src_format = src->format; + sws->src_range = src->range == AVCOL_RANGE_JPEG; + + sws->dst_w = dst->width; + sws->dst_h = dst->height; + sws->dst_format = dst->format; + sws->dst_range = dst->range == AVCOL_RANGE_JPEG; + get_chroma_pos(graph, &sws->src_h_chr_pos, &sws->src_v_chr_pos, src); + get_chroma_pos(graph, &sws->dst_h_chr_pos, &sws->dst_v_chr_pos, dst); + + graph->incomplete |= src->range == AVCOL_RANGE_UNSPECIFIED; + graph->incomplete |= dst->range == AVCOL_RANGE_UNSPECIFIED; + + /* Allow overriding chroma position with the legacy API */ + legacy_chr_pos(graph, &sws->src_h_chr_pos, ctx->src_h_chr_pos, &warned); + legacy_chr_pos(graph, &sws->src_v_chr_pos, ctx->src_v_chr_pos, &warned); + legacy_chr_pos(graph, &sws->dst_h_chr_pos, ctx->dst_h_chr_pos, &warned); + legacy_chr_pos(graph, &sws->dst_v_chr_pos, ctx->dst_v_chr_pos, &warned); + + sws->scaler_params[0] = ctx->scaler_params[0]; + sws->scaler_params[1] = ctx->scaler_params[1]; + + ret = sws_init_context(sws, NULL, NULL); + if (ret < 0) { + sws_free_context(&sws); + return ret; + } + + /* Set correct color matrices */ + { + int in_full, out_full, brightness, contrast, saturation; + const int *inv_table, *table; + sws_getColorspaceDetails(sws, (int **)&inv_table, &in_full, + (int **)&table, &out_full, + &brightness, &contrast, &saturation); + + inv_table = sws_getCoefficients(src->csp); + table = sws_getCoefficients(dst->csp); + + graph->incomplete |= src->csp != dst->csp && + (src->csp == AVCOL_SPC_UNSPECIFIED || + dst->csp == AVCOL_SPC_UNSPECIFIED); + + sws_setColorspaceDetails(sws, inv_table, in_full, table, out_full, + brightness, contrast, saturation); + } + + return init_legacy_subpass(graph, sws, input, output); +} + +/********************* + * Format conversion * + *********************/ + +#if CONFIG_UNSTABLE +static int add_convert_pass(SwsGraph *graph, const SwsFormat *src, + const SwsFormat *dst, SwsPass *input, + SwsPass **output) +{ + const SwsPixelType type = SWS_PIXEL_F32; + + SwsContext *ctx = graph->ctx; + SwsOpList *ops = NULL; + int ret = AVERROR(ENOTSUP); + + /* Mark the entire new ops infrastructure as experimental for now */ + if (!(ctx->flags & SWS_UNSTABLE)) + goto fail; + + /* The new format conversion layer cannot scale for now */ + if (src->width != dst->width || src->height != dst->height || + src->desc->log2_chroma_h || src->desc->log2_chroma_w || + dst->desc->log2_chroma_h || dst->desc->log2_chroma_w) + goto fail; + + /* The new code does not yet support alpha blending */ + if (src->desc->flags & AV_PIX_FMT_FLAG_ALPHA && + ctx->alpha_blend != SWS_ALPHA_BLEND_NONE) + goto fail; + + ops = ff_sws_op_list_alloc(); + if (!ops) + return AVERROR(ENOMEM); + ops->src = *src; + ops->dst = *dst; + + ret = ff_sws_decode_pixfmt(ops, src->format); + if (ret < 0) + goto fail; + ret = ff_sws_decode_colors(ctx, type, ops, src, &graph->incomplete); + if (ret < 0) + goto fail; + ret = ff_sws_encode_colors(ctx, type, ops, src, dst, &graph->incomplete); + if (ret < 0) + goto fail; + ret = ff_sws_encode_pixfmt(ops, dst->format); + if (ret < 0) + goto fail; + + av_log(ctx, AV_LOG_VERBOSE, "Conversion pass for %s -> %s:\n", + av_get_pix_fmt_name(src->format), av_get_pix_fmt_name(dst->format)); + + av_log(ctx, AV_LOG_DEBUG, "Unoptimized operation list:\n"); + ff_sws_op_list_print(ctx, AV_LOG_DEBUG, AV_LOG_TRACE, ops); + av_log(ctx, AV_LOG_DEBUG, "Optimized operation list:\n"); + ff_sws_op_list_optimize(ops); + ff_sws_op_list_print(ctx, AV_LOG_VERBOSE, AV_LOG_TRACE, ops); + + ret = ff_sws_compile_pass(graph, ops, 0, dst, input, output); + if (ret < 0) + goto fail; + + ret = 0; + /* fall through */ + +fail: + ff_sws_op_list_free(&ops); + if (ret == AVERROR(ENOTSUP)) + return add_legacy_sws_pass(graph, src, dst, input, output); + return ret; +} +#else +#define add_convert_pass add_legacy_sws_pass +#endif + + +/************************** + * Gamut and tone mapping * + **************************/ + +static void free_lut3d(void *priv) +{ + SwsLut3D *lut = priv; + ff_sws_lut3d_free(&lut); +} + +static void setup_lut3d(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass) +{ + SwsLut3D *lut = pass->priv; + + /* Update dynamic frame metadata from the original source frame */ + ff_sws_lut3d_update(lut, &pass->graph->src.color); +} + +static void run_lut3d(const SwsFrame *out, const SwsFrame *in, int y, int h, + const SwsPass *pass) +{ + SwsLut3D *lut = pass->priv; + uint8_t *in_data[4], *out_data[4]; + frame_shift(in, y, in_data); + frame_shift(out, y, out_data); + + ff_sws_lut3d_apply(lut, in_data[0], in->linesize[0], out_data[0], + out->linesize[0], pass->width, h); +} + +static int adapt_colors(SwsGraph *graph, SwsFormat src, SwsFormat dst, + SwsPass *input, SwsPass **output) +{ + enum AVPixelFormat fmt_in, fmt_out; + SwsColorMap map = {0}; + SwsLut3D *lut; + SwsPass *pass; + int ret; + + /** + * Grayspace does not really have primaries, so just force the use of + * the equivalent other primary set to avoid a conversion. Technically, + * this does affect the weights used for the Grayscale conversion, but + * in practise, that should give the expected results more often than not. + */ + if (isGray(dst.format)) { + dst.color = src.color; + } else if (isGray(src.format)) { + src.color = dst.color; + } + + /* Fully infer color spaces before color mapping logic */ + graph->incomplete |= ff_infer_colors(&src.color, &dst.color); + + map.intent = graph->ctx->intent; + map.src = src.color; + map.dst = dst.color; + + if (ff_sws_color_map_noop(&map)) + return 0; + + if (src.hw_format != AV_PIX_FMT_NONE || dst.hw_format != AV_PIX_FMT_NONE) + return AVERROR(ENOTSUP); + + lut = ff_sws_lut3d_alloc(); + if (!lut) + return AVERROR(ENOMEM); + + fmt_in = ff_sws_lut3d_pick_pixfmt(src, 0); + fmt_out = ff_sws_lut3d_pick_pixfmt(dst, 1); + if (fmt_in != src.format) { + SwsFormat tmp = src; + tmp.format = fmt_in; + ret = add_convert_pass(graph, &src, &tmp, input, &input); + if (ret < 0) + return ret; + } + + ret = ff_sws_lut3d_generate(lut, fmt_in, fmt_out, &map); + if (ret < 0) { + ff_sws_lut3d_free(&lut); + return ret; + } + + ret = ff_sws_graph_add_pass(graph, fmt_out, src.width, src.height, + input, 1, lut, run_lut3d, &pass); + if (ret < 0) { + ff_sws_lut3d_free(&lut); + return ret; + } + pass->setup = setup_lut3d; + pass->free = free_lut3d; + + *output = pass; + return 0; +} + +/*************************************** + * Main filter graph construction code * + ***************************************/ + +static int init_passes(SwsGraph *graph) +{ + SwsFormat src = graph->src; + SwsFormat dst = graph->dst; + SwsPass *pass = NULL; /* read from main input image */ + int ret; + + ret = adapt_colors(graph, src, dst, pass, &pass); + if (ret < 0) + return ret; + src.format = pass ? pass->format : src.format; + src.color = dst.color; + + if (!ff_fmt_equal(&src, &dst)) { + ret = add_convert_pass(graph, &src, &dst, pass, &pass); + if (ret < 0) + return ret; + } + + if (!pass) { + /* No passes were added, so no operations were necessary */ + graph->noop = 1; + + /* Add threaded memcpy pass */ + ret = ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height, + pass, 1, NULL, run_copy, &pass); + if (ret < 0) + return ret; + } + + return 0; +} + +static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs, + int nb_threads) +{ + SwsGraph *graph = priv; + const SwsPass *pass = graph->exec.pass; + const int slice_y = jobnr * pass->slice_h; + const int slice_h = FFMIN(pass->slice_h, pass->height - slice_y); + + pass->run(graph->exec.output, graph->exec.input, slice_y, slice_h, pass); +} + +int ff_sws_graph_create(SwsContext *ctx, const SwsFormat *dst, const SwsFormat *src, + int field, SwsGraph **out_graph) +{ + int ret; + SwsGraph *graph = av_mallocz(sizeof(*graph)); + if (!graph) + return AVERROR(ENOMEM); + + graph->ctx = ctx; + graph->src = *src; + graph->dst = *dst; + graph->field = field; + graph->opts_copy = *ctx; + + if (ctx->threads == 1) { + graph->num_threads = 1; + } else { + ret = avpriv_slicethread_create(&graph->slicethread, (void *) graph, + sws_graph_worker, NULL, ctx->threads); + if (ret == AVERROR(ENOSYS)) { + /* Fall back to single threaded operation */ + graph->num_threads = 1; + } else if (ret < 0) { + goto error; + } else { + graph->num_threads = ret; + } + } + + ret = init_passes(graph); + if (ret < 0) + goto error; + + *out_graph = graph; + return 0; + +error: + ff_sws_graph_free(&graph); + return ret; +} + +void ff_sws_graph_free(SwsGraph **pgraph) +{ + SwsGraph *graph = *pgraph; + if (!graph) + return; + + avpriv_slicethread_free(&graph->slicethread); + + for (int i = 0; i < graph->num_passes; i++) { + SwsPass *pass = graph->passes[i]; + if (pass->free) + pass->free(pass->priv); + av_refstruct_unref(&pass->output); + av_free(pass); + } + av_free(graph->passes); + + av_free(graph); + *pgraph = NULL; +} + +/* Tests only options relevant to SwsGraph */ +static int opts_equal(const SwsContext *c1, const SwsContext *c2) +{ + return c1->flags == c2->flags && + c1->threads == c2->threads && + c1->dither == c2->dither && + c1->alpha_blend == c2->alpha_blend && + c1->gamma_flag == c2->gamma_flag && + c1->src_h_chr_pos == c2->src_h_chr_pos && + c1->src_v_chr_pos == c2->src_v_chr_pos && + c1->dst_h_chr_pos == c2->dst_h_chr_pos && + c1->dst_v_chr_pos == c2->dst_v_chr_pos && + c1->intent == c2->intent && + !memcmp(c1->scaler_params, c2->scaler_params, sizeof(c1->scaler_params)); + +} + +int ff_sws_graph_reinit(SwsContext *ctx, const SwsFormat *dst, const SwsFormat *src, + int field, SwsGraph **out_graph) +{ + SwsGraph *graph = *out_graph; + if (graph && ff_fmt_equal(&graph->src, src) && + ff_fmt_equal(&graph->dst, dst) && + opts_equal(ctx, &graph->opts_copy)) + { + ff_sws_graph_update_metadata(graph, &src->color); + return 0; + } + + ff_sws_graph_free(out_graph); + return ff_sws_graph_create(ctx, dst, src, field, out_graph); +} + +void ff_sws_graph_update_metadata(SwsGraph *graph, const SwsColor *color) +{ + if (!color) + return; + + ff_color_update_dynamic(&graph->src.color, color); +} + +static void get_field(SwsGraph *graph, const AVFrame *avframe, SwsFrame *frame) +{ + ff_sws_frame_from_avframe(frame, avframe); + + if (!(avframe->flags & AV_FRAME_FLAG_INTERLACED)) { + av_assert1(!graph->field); + return; + } + + if (graph->field == FIELD_BOTTOM) { + /* Odd rows, offset by one line */ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + for (int i = 0; i < 4; i++) { + if (frame->data[i]) + frame->data[i] += frame->linesize[i]; + if (desc->flags & AV_PIX_FMT_FLAG_PAL) + break; + } + } + + /* Take only every second line */ + for (int i = 0; i < 4; i++) + frame->linesize[i] <<= 1; + + frame->height = (frame->height + (graph->field == FIELD_TOP)) >> 1; +} + +void ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, const AVFrame *src) +{ + av_assert0(dst->format == graph->dst.hw_format || dst->format == graph->dst.format); + av_assert0(src->format == graph->src.hw_format || src->format == graph->src.format); + + SwsFrame src_field, dst_field; + get_field(graph, dst, &dst_field); + get_field(graph, src, &src_field); + + for (int i = 0; i < graph->num_passes; i++) { + const SwsPass *pass = graph->passes[i]; + graph->exec.pass = pass; + graph->exec.input = pass->input ? &pass->input->output->frame : &src_field; + graph->exec.output = pass->output->avframe ? &pass->output->frame : &dst_field; + if (pass->setup) + pass->setup(graph->exec.output, graph->exec.input, pass); + + if (graph->num_threads == 1) { + pass->run(graph->exec.output, graph->exec.input, 0, pass->height, pass); + } else { + avpriv_slicethread_execute(graph->slicethread, pass->num_slices, 0); + } + } +} diff --git a/libs/ffmpeg/libswscale/graph.h b/libs/ffmpeg/libswscale/graph.h new file mode 100644 index 00000000000..676f8cb46ac --- /dev/null +++ b/libs/ffmpeg/libswscale/graph.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2024 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_GRAPH_H +#define SWSCALE_GRAPH_H + +#include <stdbool.h> + +#include "libavutil/slicethread.h" +#include "libavutil/buffer.h" + +#include "swscale.h" +#include "format.h" + +static av_always_inline av_const int ff_fmt_vshift(enum AVPixelFormat fmt, int plane) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + return (plane == 1 || plane == 2) ? desc->log2_chroma_h : 0; +} + +typedef struct SwsPass SwsPass; +typedef struct SwsGraph SwsGraph; + +/** + * Output `h` lines of filtered data. `out` and `in` point to the + * start of the image buffer for this pass. + */ +typedef void (*sws_filter_run_t)(const SwsFrame *out, const SwsFrame *in, + int y, int h, const SwsPass *pass); + +/** + * Represents an allocated output buffer for a filter pass. + */ +typedef struct SwsPassBuffer { + SwsFrame frame; + + int width, height; /* dimensions of this buffer */ + AVFrame *avframe; /* backing storage for `frame` */ +} SwsPassBuffer; + +/** + * Represents a single filter pass in the scaling graph. Each filter will + * read from some previous pass's output, and write to a buffer associated + * with the pass (or into the final output image). + */ +struct SwsPass { + const SwsGraph *graph; + + /** + * Filter main execution function. Called from multiple threads, with + * the granularity dictated by `slice_h`. Individual slices sent to `run` + * are always equal to (or smaller than, for the last slice) `slice_h`. + */ + sws_filter_run_t run; + enum AVPixelFormat format; /* new pixel format */ + int width, height; /* new output size */ + int slice_h; /* filter granularity */ + int num_slices; + + /** + * Filter input. This pass's output will be resolved to form this pass's. + * input. If NULL, the original input image is used. + */ + const SwsPass *input; + + /** + * Filter output buffer. Allocated on demand and freed automatically. + */ + SwsPassBuffer *output; /* refstruct */ + + /** + * Called once from the main thread before running the filter. Optional. + */ + void (*setup)(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass); + + /** + * Optional private state and associated free() function. + */ + void (*free)(void *priv); + void *priv; +}; + +/** + * Filter graph, which represents a 'baked' pixel format conversion. + */ +typedef struct SwsGraph { + SwsContext *ctx; + AVSliceThread *slicethread; + int num_threads; /* resolved at init() time */ + bool incomplete; /* set during init() if formats had to be inferred */ + bool noop; /* set during init() if the graph is a no-op */ + + AVBufferRef *hw_frames_ref; + + /** Sorted sequence of filter passes to apply */ + SwsPass **passes; + int num_passes; + + /** + * Cached copy of the public options that were used to construct this + * SwsGraph. Used only to detect when the graph needs to be reinitialized. + */ + SwsContext opts_copy; + + /** + * Currently active format and processing parameters. + */ + SwsFormat src, dst; + int field; + + /** + * Temporary execution state inside ff_sws_graph_run(); used to pass + * data to worker threads. + */ + struct { + const SwsPass *pass; /* current filter pass */ + const SwsFrame *input; /* current filter pass input/output */ + const SwsFrame *output; + } exec; +} SwsGraph; + +/** + * Allocate and initialize the filter graph. Returns 0 or a negative error. + */ +int ff_sws_graph_create(SwsContext *ctx, const SwsFormat *dst, const SwsFormat *src, + int field, SwsGraph **out_graph); + + +/** + * Allocate and add a new pass to the filter graph. + * + * @param graph Filter graph to add the pass to. + * @param fmt Pixel format of the output image. + * @param w Width of the output image. + * @param h Height of the output image. + * @param input Previous pass to read from, or NULL for the input image. + * @param align Minimum slice alignment for this pass, or 0 for no threading. + * @param priv Private state for the filter run function. + * @param run Filter function to run. + * @param out_pass The newly added pass will be written here on success. + * @return 0 or a negative error code + */ +int ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt, + int width, int height, SwsPass *input, + int align, void *priv, sws_filter_run_t run, + SwsPass **out_pass); + +/** + * Uninitialize any state associate with this filter graph and free it. + */ +void ff_sws_graph_free(SwsGraph **graph); + +/** + * Update dynamic per-frame HDR metadata without requiring a full reinit. + */ +void ff_sws_graph_update_metadata(SwsGraph *graph, const SwsColor *color); + +/** + * Wrapper around ff_sws_graph_create() that reuses the existing graph if the + * format is compatible. This will also update dynamic per-frame metadata. + * Must be called after changing any of the fields in `ctx`, or else they will + * have no effect. + */ +int ff_sws_graph_reinit(SwsContext *ctx, const SwsFormat *dst, const SwsFormat *src, + int field, SwsGraph **graph); + +/** + * Dispatch the filter graph on a single field of the given frames. Internally + * threaded. + */ +void ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, const AVFrame *src); + +#endif /* SWSCALE_GRAPH_H */ diff --git a/libs/ffmpeg/libswscale/half2float.c b/libs/ffmpeg/libswscale/half2float.c new file mode 100644 index 00000000000..1b023f96a54 --- /dev/null +++ b/libs/ffmpeg/libswscale/half2float.c @@ -0,0 +1,19 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/half2float.c" diff --git a/libs/ffmpeg/libswscale/hscale.c b/libs/ffmpeg/libswscale/hscale.c new file mode 100644 index 00000000000..6e09181048a --- /dev/null +++ b/libs/ffmpeg/libswscale/hscale.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2015 Pedro Arthur <bygrandao@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/mem.h" +#include "swscale_internal.h" + +/// Scaler instance data +typedef struct FilterContext +{ + uint16_t *filter; + int *filter_pos; + int filter_size; + int xInc; +} FilterContext; + +/// Color conversion instance data +typedef struct ColorContext +{ + uint32_t *pal; +} ColorContext; + +static int lum_h_scale(SwsInternal *c, SwsFilterDescriptor *desc, int sliceY, int sliceH) +{ + FilterContext *instance = desc->instance; + int srcW = desc->src->width; + int dstW = desc->dst->width; + int xInc = instance->xInc; + + int i; + for (i = 0; i < sliceH; ++i) { + uint8_t ** src = desc->src->plane[0].line; + uint8_t ** dst = desc->dst->plane[0].line; + int src_pos = sliceY+i - desc->src->plane[0].sliceY; + int dst_pos = sliceY+i - desc->dst->plane[0].sliceY; + + + if (c->hyscale_fast) { + c->hyscale_fast(c, (int16_t*)dst[dst_pos], dstW, src[src_pos], srcW, xInc); + } else { + c->hyScale(c, (int16_t*)dst[dst_pos], dstW, (const uint8_t *)src[src_pos], instance->filter, + instance->filter_pos, instance->filter_size); + } + + if (c->lumConvertRange) + c->lumConvertRange((int16_t*)dst[dst_pos], dstW, + c->lumConvertRange_coeff, c->lumConvertRange_offset); + + desc->dst->plane[0].sliceH += 1; + + if (desc->alpha) { + src = desc->src->plane[3].line; + dst = desc->dst->plane[3].line; + + src_pos = sliceY+i - desc->src->plane[3].sliceY; + dst_pos = sliceY+i - desc->dst->plane[3].sliceY; + + desc->dst->plane[3].sliceH += 1; + + if (c->hyscale_fast) { + c->hyscale_fast(c, (int16_t*)dst[dst_pos], dstW, src[src_pos], srcW, xInc); + } else { + c->hyScale(c, (int16_t*)dst[dst_pos], dstW, (const uint8_t *)src[src_pos], instance->filter, + instance->filter_pos, instance->filter_size); + } + } + } + + return sliceH; +} + +static int lum_convert(SwsInternal *c, SwsFilterDescriptor *desc, int sliceY, int sliceH) +{ + int srcW = desc->src->width; + ColorContext * instance = desc->instance; + uint32_t * pal = instance->pal; + int i; + + desc->dst->plane[0].sliceY = sliceY; + desc->dst->plane[0].sliceH = sliceH; + desc->dst->plane[3].sliceY = sliceY; + desc->dst->plane[3].sliceH = sliceH; + + for (i = 0; i < sliceH; ++i) { + int sp0 = sliceY+i - desc->src->plane[0].sliceY; + int sp1 = ((sliceY+i) >> desc->src->v_chr_sub_sample) - desc->src->plane[1].sliceY; + const uint8_t * src[4] = { desc->src->plane[0].line[sp0], + desc->src->plane[1].line[sp1], + desc->src->plane[2].line[sp1], + desc->src->plane[3].line[sp0]}; + uint8_t * dst = desc->dst->plane[0].line[i]; + + if (c->lumToYV12) { + c->lumToYV12(dst, src[0], src[1], src[2], srcW, pal, c->input_opaque); + } else if (c->readLumPlanar) { + c->readLumPlanar(dst, src, srcW, c->input_rgb2yuv_table, c->input_opaque); + } + + + if (desc->alpha) { + dst = desc->dst->plane[3].line[i]; + if (c->alpToYV12) { + c->alpToYV12(dst, src[3], src[1], src[2], srcW, pal, c->input_opaque); + } else if (c->readAlpPlanar) { + c->readAlpPlanar(dst, src, srcW, NULL, c->input_opaque); + } + } + } + + return sliceH; +} + +int ff_init_desc_fmt_convert(SwsFilterDescriptor *desc, SwsSlice * src, SwsSlice *dst, uint32_t *pal) +{ + ColorContext * li = av_malloc(sizeof(ColorContext)); + if (!li) + return AVERROR(ENOMEM); + li->pal = pal; + desc->instance = li; + + desc->alpha = isALPHA(src->fmt) && isALPHA(dst->fmt); + desc->src =src; + desc->dst = dst; + desc->process = &lum_convert; + + return 0; +} + + +int ff_init_desc_hscale(SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst, uint16_t *filter, int * filter_pos, int filter_size, int xInc) +{ + FilterContext *li = av_malloc(sizeof(FilterContext)); + if (!li) + return AVERROR(ENOMEM); + + li->filter = filter; + li->filter_pos = filter_pos; + li->filter_size = filter_size; + li->xInc = xInc; + + desc->instance = li; + + desc->alpha = isALPHA(src->fmt) && isALPHA(dst->fmt); + desc->src = src; + desc->dst = dst; + + desc->process = &lum_h_scale; + + return 0; +} + +static int chr_h_scale(SwsInternal *c, SwsFilterDescriptor *desc, int sliceY, int sliceH) +{ + FilterContext *instance = desc->instance; + int srcW = AV_CEIL_RSHIFT(desc->src->width, desc->src->h_chr_sub_sample); + int dstW = AV_CEIL_RSHIFT(desc->dst->width, desc->dst->h_chr_sub_sample); + int xInc = instance->xInc; + + uint8_t ** src1 = desc->src->plane[1].line; + uint8_t ** dst1 = desc->dst->plane[1].line; + uint8_t ** src2 = desc->src->plane[2].line; + uint8_t ** dst2 = desc->dst->plane[2].line; + + int src_pos1 = sliceY - desc->src->plane[1].sliceY; + int dst_pos1 = sliceY - desc->dst->plane[1].sliceY; + + int src_pos2 = sliceY - desc->src->plane[2].sliceY; + int dst_pos2 = sliceY - desc->dst->plane[2].sliceY; + + int i; + for (i = 0; i < sliceH; ++i) { + if (c->hcscale_fast) { + c->hcscale_fast(c, (uint16_t*)dst1[dst_pos1+i], (uint16_t*)dst2[dst_pos2+i], dstW, src1[src_pos1+i], src2[src_pos2+i], srcW, xInc); + } else { + c->hcScale(c, (uint16_t*)dst1[dst_pos1+i], dstW, src1[src_pos1+i], instance->filter, instance->filter_pos, instance->filter_size); + c->hcScale(c, (uint16_t*)dst2[dst_pos2+i], dstW, src2[src_pos2+i], instance->filter, instance->filter_pos, instance->filter_size); + } + + if (c->chrConvertRange) + c->chrConvertRange((uint16_t*)dst1[dst_pos1+i], (uint16_t*)dst2[dst_pos2+i], dstW, + c->chrConvertRange_coeff, c->chrConvertRange_offset); + + desc->dst->plane[1].sliceH += 1; + desc->dst->plane[2].sliceH += 1; + } + return sliceH; +} + +static int chr_convert(SwsInternal *c, SwsFilterDescriptor *desc, int sliceY, int sliceH) +{ + int srcW = AV_CEIL_RSHIFT(desc->src->width, desc->src->h_chr_sub_sample); + ColorContext * instance = desc->instance; + uint32_t * pal = instance->pal; + + int sp0 = (sliceY - (desc->src->plane[0].sliceY >> desc->src->v_chr_sub_sample)) << desc->src->v_chr_sub_sample; + int sp1 = sliceY - desc->src->plane[1].sliceY; + + int i; + + desc->dst->plane[1].sliceY = sliceY; + desc->dst->plane[1].sliceH = sliceH; + desc->dst->plane[2].sliceY = sliceY; + desc->dst->plane[2].sliceH = sliceH; + + for (i = 0; i < sliceH; ++i) { + const uint8_t * src[4] = { desc->src->plane[0].line[sp0+i], + desc->src->plane[1].line[sp1+i], + desc->src->plane[2].line[sp1+i], + desc->src->plane[3].line[sp0+i]}; + + uint8_t * dst1 = desc->dst->plane[1].line[i]; + uint8_t * dst2 = desc->dst->plane[2].line[i]; + if (c->chrToYV12) { + c->chrToYV12(dst1, dst2, src[0], src[1], src[2], srcW, pal, c->input_opaque); + } else if (c->readChrPlanar) { + c->readChrPlanar(dst1, dst2, src, srcW, c->input_rgb2yuv_table, c->input_opaque); + } + } + return sliceH; +} + +int ff_init_desc_cfmt_convert(SwsFilterDescriptor *desc, SwsSlice * src, SwsSlice *dst, uint32_t *pal) +{ + ColorContext * li = av_malloc(sizeof(ColorContext)); + if (!li) + return AVERROR(ENOMEM); + li->pal = pal; + desc->instance = li; + + desc->src =src; + desc->dst = dst; + desc->process = &chr_convert; + + return 0; +} + +int ff_init_desc_chscale(SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst, uint16_t *filter, int * filter_pos, int filter_size, int xInc) +{ + FilterContext *li = av_malloc(sizeof(FilterContext)); + if (!li) + return AVERROR(ENOMEM); + + li->filter = filter; + li->filter_pos = filter_pos; + li->filter_size = filter_size; + li->xInc = xInc; + + desc->instance = li; + + desc->alpha = isALPHA(src->fmt) && isALPHA(dst->fmt); + desc->src = src; + desc->dst = dst; + + desc->process = &chr_h_scale; + + return 0; +} + +static int no_chr_scale(SwsInternal *c, SwsFilterDescriptor *desc, int sliceY, int sliceH) +{ + desc->dst->plane[1].sliceY = sliceY + sliceH - desc->dst->plane[1].available_lines; + desc->dst->plane[1].sliceH = desc->dst->plane[1].available_lines; + desc->dst->plane[2].sliceY = sliceY + sliceH - desc->dst->plane[2].available_lines; + desc->dst->plane[2].sliceH = desc->dst->plane[2].available_lines; + return 0; +} + +int ff_init_desc_no_chr(SwsFilterDescriptor *desc, SwsSlice * src, SwsSlice *dst) +{ + desc->src = src; + desc->dst = dst; + desc->alpha = 0; + desc->instance = NULL; + desc->process = &no_chr_scale; + return 0; +} diff --git a/libs/ffmpeg/libswscale/hscale_fast_bilinear.c b/libs/ffmpeg/libswscale/hscale_fast_bilinear.c new file mode 100644 index 00000000000..abcfb95e2cc --- /dev/null +++ b/libs/ffmpeg/libswscale/hscale_fast_bilinear.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "swscale_internal.h" + +void ff_hyscale_fast_c(SwsInternal *c, int16_t *dst, int dstWidth, + const uint8_t *src, int srcW, int xInc) +{ + int i; + unsigned int xpos = 0; + for (i = 0; i < dstWidth; i++) { + register unsigned int xx = xpos >> 16; + register unsigned int xalpha = (xpos & 0xFFFF) >> 9; + dst[i] = (src[xx] << 7) + (src[xx + 1] - src[xx]) * xalpha; + xpos += xInc; + } + for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--) + dst[i] = src[srcW-1]*128; +} + +void ff_hcscale_fast_c(SwsInternal *c, int16_t *dst1, int16_t *dst2, + int dstWidth, const uint8_t *src1, + const uint8_t *src2, int srcW, int xInc) +{ + int i; + unsigned int xpos = 0; + for (i = 0; i < dstWidth; i++) { + register unsigned int xx = xpos >> 16; + register unsigned int xalpha = (xpos & 0xFFFF) >> 9; + dst1[i] = (src1[xx] * (xalpha ^ 127) + src1[xx + 1] * xalpha); + dst2[i] = (src2[xx] * (xalpha ^ 127) + src2[xx + 1] * xalpha); + xpos += xInc; + } + for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--) { + dst1[i] = src1[srcW-1]*128; + dst2[i] = src2[srcW-1]*128; + } +} diff --git a/libs/ffmpeg/libswscale/input.c b/libs/ffmpeg/libswscale/input.c new file mode 100644 index 00000000000..175ed705f24 --- /dev/null +++ b/libs/ffmpeg/libswscale/input.c @@ -0,0 +1,2770 @@ +/* + * Copyright (C) 2001-2012 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <math.h> +#include <stddef.h> +#include <stdint.h> + +#include "libavutil/bswap.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/avassert.h" +#include "libavutil/intfloat.h" +#include "config.h" +#include "swscale_internal.h" + +#define input_pixel(pos) (is_be ? AV_RB16(pos) : AV_RL16(pos)) + +#define IS_BE_LE 0 +#define IS_BE_BE 1 +#define IS_BE_ 0 +/* ENDIAN_IDENTIFIER needs to be "BE", "LE" or "". The latter is intended + * for single-byte cases where the concept of endianness does not apply. */ +#define IS_BE(ENDIAN_IDENTIFIER) IS_BE_ ## ENDIAN_IDENTIFIER + +#define r ((origin == AV_PIX_FMT_BGR48BE || origin == AV_PIX_FMT_BGR48LE || origin == AV_PIX_FMT_BGRA64BE || origin == AV_PIX_FMT_BGRA64LE) ? b_r : r_b) +#define b ((origin == AV_PIX_FMT_BGR48BE || origin == AV_PIX_FMT_BGR48LE || origin == AV_PIX_FMT_BGRA64BE || origin == AV_PIX_FMT_BGRA64LE) ? r_b : b_r) + +static av_always_inline void +rgb64ToY_c_template(uint16_t *dst, const uint16_t *src, int width, + enum AVPixelFormat origin, int32_t *rgb2yuv, int is_be) +{ + int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX]; + int i; + for (i = 0; i < width; i++) { + unsigned int r_b = input_pixel(&src[i*4+0]); + unsigned int g = input_pixel(&src[i*4+1]); + unsigned int b_r = input_pixel(&src[i*4+2]); + + dst[i] = (ry*r + gy*g + by*b + (0x2001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + } +} + +static av_always_inline void +rgb64ToUV_c_template(uint16_t *dstU, uint16_t *dstV, + const uint16_t *src1, const uint16_t *src2, + int width, enum AVPixelFormat origin, int32_t *rgb2yuv, int is_be) +{ + int i; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + av_assert1(src1==src2); + for (i = 0; i < width; i++) { + unsigned int r_b = input_pixel(&src1[i*4+0]); + unsigned int g = input_pixel(&src1[i*4+1]); + unsigned int b_r = input_pixel(&src1[i*4+2]); + + dstU[i] = (ru*r + gu*g + bu*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + dstV[i] = (rv*r + gv*g + bv*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + } +} + +static av_always_inline void +rgb64ToUV_half_c_template(uint16_t *dstU, uint16_t *dstV, + const uint16_t *src1, const uint16_t *src2, + int width, enum AVPixelFormat origin, int32_t *rgb2yuv, int is_be) +{ + int i; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + av_assert1(src1==src2); + for (i = 0; i < width; i++) { + unsigned r_b = (input_pixel(&src1[8 * i + 0]) + input_pixel(&src1[8 * i + 4]) + 1) >> 1; + unsigned g = (input_pixel(&src1[8 * i + 1]) + input_pixel(&src1[8 * i + 5]) + 1) >> 1; + unsigned b_r = (input_pixel(&src1[8 * i + 2]) + input_pixel(&src1[8 * i + 6]) + 1) >> 1; + + dstU[i]= (ru*r + gu*g + bu*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + dstV[i]= (rv*r + gv*g + bv*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + } +} + +#define RGB64FUNCS_EXT(pattern, BE_LE, origin, is_be) \ +static void pattern ## 64 ## BE_LE ## ToY_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused0, const uint8_t *unused1,\ + int width, uint32_t *rgb2yuv, void *opq) \ +{ \ + const uint16_t *src = (const uint16_t *) _src; \ + uint16_t *dst = (uint16_t *) _dst; \ + rgb64ToY_c_template(dst, src, width, origin, rgb2yuv, is_be); \ +} \ + \ +static void pattern ## 64 ## BE_LE ## ToUV_c(uint8_t *_dstU, uint8_t *_dstV, \ + const uint8_t *unused0, const uint8_t *_src1, const uint8_t *_src2, \ + int width, uint32_t *rgb2yuv, void *opq) \ +{ \ + const uint16_t *src1 = (const uint16_t *) _src1, \ + *src2 = (const uint16_t *) _src2; \ + uint16_t *dstU = (uint16_t *) _dstU, *dstV = (uint16_t *) _dstV; \ + rgb64ToUV_c_template(dstU, dstV, src1, src2, width, origin, rgb2yuv, is_be); \ +} \ + \ +static void pattern ## 64 ## BE_LE ## ToUV_half_c(uint8_t *_dstU, uint8_t *_dstV, \ + const uint8_t *unused0, const uint8_t *_src1, const uint8_t *_src2, \ + int width, uint32_t *rgb2yuv, void *opq) \ +{ \ + const uint16_t *src1 = (const uint16_t *) _src1, \ + *src2 = (const uint16_t *) _src2; \ + uint16_t *dstU = (uint16_t *) _dstU, *dstV = (uint16_t *) _dstV; \ + rgb64ToUV_half_c_template(dstU, dstV, src1, src2, width, origin, rgb2yuv, is_be); \ +} +#define RGB64FUNCS(pattern, endianness, base_fmt) \ + RGB64FUNCS_EXT(pattern, endianness, base_fmt ## endianness, IS_BE(endianness)) + +RGB64FUNCS(rgb, LE, AV_PIX_FMT_RGBA64) +RGB64FUNCS(rgb, BE, AV_PIX_FMT_RGBA64) +RGB64FUNCS(bgr, LE, AV_PIX_FMT_BGRA64) +RGB64FUNCS(bgr, BE, AV_PIX_FMT_BGRA64) + +static av_always_inline void rgb48ToY_c_template(uint16_t *dst, + const uint16_t *src, int width, + enum AVPixelFormat origin, + int32_t *rgb2yuv, int is_be) +{ + int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX]; + int i; + for (i = 0; i < width; i++) { + unsigned int r_b = input_pixel(&src[i * 3 + 0]); + unsigned int g = input_pixel(&src[i * 3 + 1]); + unsigned int b_r = input_pixel(&src[i * 3 + 2]); + + dst[i] = (ry*r + gy*g + by*b + (0x2001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT; + } +} + +static av_always_inline void rgb48ToUV_c_template(uint16_t *dstU, + uint16_t *dstV, + const uint16_t *src1, + const uint16_t *src2, + int width, + enum AVPixelFormat origin, + int32_t *rgb2yuv, int is_be) +{ + int i; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + av_assert1(src1 == src2); + for (i = 0; i < width; i++) { + unsigned r_b = input_pixel(&src1[i * 3 + 0]); + unsigned g = input_pixel(&src1[i * 3 + 1]); + unsigned b_r = input_pixel(&src1[i * 3 + 2]); + + dstU[i] = (ru*r + gu*g + bu*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT; + dstV[i] = (rv*r + gv*g + bv*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT; + } +} + +static av_always_inline void rgb48ToUV_half_c_template(uint16_t *dstU, + uint16_t *dstV, + const uint16_t *src1, + const uint16_t *src2, + int width, + enum AVPixelFormat origin, + int32_t *rgb2yuv, int is_be) +{ + int i; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + av_assert1(src1 == src2); + for (i = 0; i < width; i++) { + unsigned r_b = (input_pixel(&src1[6 * i + 0]) + + input_pixel(&src1[6 * i + 3]) + 1) >> 1; + unsigned g = (input_pixel(&src1[6 * i + 1]) + + input_pixel(&src1[6 * i + 4]) + 1) >> 1; + unsigned b_r = (input_pixel(&src1[6 * i + 2]) + + input_pixel(&src1[6 * i + 5]) + 1) >> 1; + + dstU[i] = (ru*r + gu*g + bu*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT; + dstV[i] = (rv*r + gv*g + bv*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT; + } +} + +#undef r +#undef b +#undef input_pixel + +#define RGB48FUNCS_EXT(pattern, BE_LE, origin, is_be) \ +static void pattern ## 48 ## BE_LE ## ToY_c(uint8_t *_dst, \ + const uint8_t *_src, \ + const uint8_t *unused0, const uint8_t *unused1,\ + int width, \ + uint32_t *rgb2yuv, \ + void *opq) \ +{ \ + const uint16_t *src = (const uint16_t *)_src; \ + uint16_t *dst = (uint16_t *)_dst; \ + rgb48ToY_c_template(dst, src, width, origin, rgb2yuv, is_be); \ +} \ + \ +static void pattern ## 48 ## BE_LE ## ToUV_c(uint8_t *_dstU, \ + uint8_t *_dstV, \ + const uint8_t *unused0, \ + const uint8_t *_src1, \ + const uint8_t *_src2, \ + int width, \ + uint32_t *rgb2yuv, \ + void *opq) \ +{ \ + const uint16_t *src1 = (const uint16_t *)_src1, \ + *src2 = (const uint16_t *)_src2; \ + uint16_t *dstU = (uint16_t *)_dstU, \ + *dstV = (uint16_t *)_dstV; \ + rgb48ToUV_c_template(dstU, dstV, src1, src2, width, origin, rgb2yuv, is_be); \ +} \ + \ +static void pattern ## 48 ## BE_LE ## ToUV_half_c(uint8_t *_dstU, \ + uint8_t *_dstV, \ + const uint8_t *unused0, \ + const uint8_t *_src1, \ + const uint8_t *_src2, \ + int width, \ + uint32_t *rgb2yuv, \ + void *opq) \ +{ \ + const uint16_t *src1 = (const uint16_t *)_src1, \ + *src2 = (const uint16_t *)_src2; \ + uint16_t *dstU = (uint16_t *)_dstU, \ + *dstV = (uint16_t *)_dstV; \ + rgb48ToUV_half_c_template(dstU, dstV, src1, src2, width, origin, rgb2yuv, is_be); \ +} +#define RGB48FUNCS(pattern, endianness, base_fmt) \ + RGB48FUNCS_EXT(pattern, endianness, base_fmt ## endianness, IS_BE(endianness)) + +RGB48FUNCS(rgb, LE, AV_PIX_FMT_RGB48) +RGB48FUNCS(rgb, BE, AV_PIX_FMT_RGB48) +RGB48FUNCS(bgr, LE, AV_PIX_FMT_BGR48) +RGB48FUNCS(bgr, BE, AV_PIX_FMT_BGR48) + +#define input_pixel(i) ((origin == AV_PIX_FMT_RGBA || \ + origin == AV_PIX_FMT_BGRA || \ + origin == AV_PIX_FMT_ARGB || \ + origin == AV_PIX_FMT_ABGR) \ + ? AV_RN32A(&src[(i) * 4]) \ + : ((origin == AV_PIX_FMT_X2RGB10LE || \ + origin == AV_PIX_FMT_X2BGR10LE) \ + ? AV_RL32(&src[(i) * 4]) \ + : (is_be ? AV_RB16(&src[(i) * 2]) \ + : AV_RL16(&src[(i) * 2])))) + +static av_always_inline void rgb16_32ToY_c_template(int16_t *dst, + const uint8_t *src, + int width, + enum AVPixelFormat origin, + int shr, int shg, + int shb, int shp, + int maskr, int maskg, + int maskb, int rsh, + int gsh, int bsh, int S, + int32_t *rgb2yuv, int is_be) +{ + const int ry = rgb2yuv[RY_IDX]<<rsh, gy = rgb2yuv[GY_IDX]<<gsh, by = rgb2yuv[BY_IDX]<<bsh; + const unsigned rnd = (32<<((S)-1)) + (1<<(S-7)); + int i; + + for (i = 0; i < width; i++) { + int px = input_pixel(i) >> shp; + int b = (px & maskb) >> shb; + int g = (px & maskg) >> shg; + int r = (px & maskr) >> shr; + + dst[i] = (ry * r + gy * g + by * b + rnd) >> ((S)-6); + } +} + +static av_always_inline void rgb16_32ToUV_c_template(int16_t *dstU, + int16_t *dstV, + const uint8_t *src, + int width, + enum AVPixelFormat origin, + int shr, int shg, + int shb, int shp, + int maskr, int maskg, + int maskb, int rsh, + int gsh, int bsh, int S, + int32_t *rgb2yuv, int is_be) +{ + const int ru = rgb2yuv[RU_IDX] * (1 << rsh), gu = rgb2yuv[GU_IDX] * (1 << gsh), bu = rgb2yuv[BU_IDX] * (1 << bsh), + rv = rgb2yuv[RV_IDX] * (1 << rsh), gv = rgb2yuv[GV_IDX] * (1 << gsh), bv = rgb2yuv[BV_IDX] * (1 << bsh); + const unsigned rnd = (256u<<((S)-1)) + (1<<(S-7)); + int i; + + for (i = 0; i < width; i++) { + int px = input_pixel(i) >> shp; + int b = (px & maskb) >> shb; + int g = (px & maskg) >> shg; + int r = (px & maskr) >> shr; + + dstU[i] = (ru * r + gu * g + bu * b + rnd) >> ((S)-6); + dstV[i] = (rv * r + gv * g + bv * b + rnd) >> ((S)-6); + } +} + +static av_always_inline void rgb16_32ToUV_half_c_template(int16_t *dstU, + int16_t *dstV, + const uint8_t *src, + int width, + enum AVPixelFormat origin, + int shr, int shg, + int shb, int shp, + int maskr, int maskg, + int maskb, int rsh, + int gsh, int bsh, int S, + int32_t *rgb2yuv, int is_be) +{ + const int ru = rgb2yuv[RU_IDX] * (1 << rsh), gu = rgb2yuv[GU_IDX] * (1 << gsh), bu = rgb2yuv[BU_IDX] * (1 << bsh), + rv = rgb2yuv[RV_IDX] * (1 << rsh), gv = rgb2yuv[GV_IDX] * (1 << gsh), bv = rgb2yuv[BV_IDX] * (1 << bsh), + maskgx = ~(maskr | maskb); + const unsigned rnd = (256U<<(S)) + (1<<(S-6)); + int i; + + maskr |= maskr << 1; + maskb |= maskb << 1; + maskg |= maskg << 1; + for (i = 0; i < width; i++) { + unsigned px0 = input_pixel(2 * i + 0) >> shp; + unsigned px1 = input_pixel(2 * i + 1) >> shp; + int b, r, g = (px0 & maskgx) + (px1 & maskgx); + int rb = px0 + px1 - g; + + b = (rb & maskb) >> shb; + if (shp || + origin == AV_PIX_FMT_BGR565LE || origin == AV_PIX_FMT_BGR565BE || + origin == AV_PIX_FMT_RGB565LE || origin == AV_PIX_FMT_RGB565BE) { + g >>= shg; + } else { + g = (g & maskg) >> shg; + } + r = (rb & maskr) >> shr; + + dstU[i] = (ru * r + gu * g + bu * b + (unsigned)rnd) >> ((S)-6+1); + dstV[i] = (rv * r + gv * g + bv * b + (unsigned)rnd) >> ((S)-6+1); + } +} + +#undef input_pixel + +#define RGB16_32FUNCS_EXT(fmt, name, shr, shg, shb, shp, maskr, \ + maskg, maskb, rsh, gsh, bsh, S, is_be) \ +static void name ## ToY_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, \ + int width, uint32_t *tab, void *opq) \ +{ \ + rgb16_32ToY_c_template((int16_t*)dst, src, width, fmt, shr, shg, shb, shp, \ + maskr, maskg, maskb, rsh, gsh, bsh, S, tab, is_be); \ +} \ + \ +static void name ## ToUV_c(uint8_t *dstU, uint8_t *dstV, \ + const uint8_t *unused0, const uint8_t *src, const uint8_t *dummy, \ + int width, uint32_t *tab, void *opq) \ +{ \ + rgb16_32ToUV_c_template((int16_t*)dstU, (int16_t*)dstV, src, width, fmt, \ + shr, shg, shb, shp, \ + maskr, maskg, maskb, rsh, gsh, bsh, S, tab, is_be); \ +} \ + \ +static void name ## ToUV_half_c(uint8_t *dstU, uint8_t *dstV, \ + const uint8_t *unused0, const uint8_t *src, \ + const uint8_t *dummy, \ + int width, uint32_t *tab, void *opq) \ +{ \ + rgb16_32ToUV_half_c_template((int16_t*)dstU, (int16_t*)dstV, src, width, fmt, \ + shr, shg, shb, shp, \ + maskr, maskg, maskb, \ + rsh, gsh, bsh, S, tab, is_be); \ +} + +#define RGB16_32FUNCS(base_fmt, endianness, name, shr, shg, shb, shp, maskr, \ + maskg, maskb, rsh, gsh, bsh, S) \ + RGB16_32FUNCS_EXT(base_fmt ## endianness, name, shr, shg, shb, shp, maskr, \ + maskg, maskb, rsh, gsh, bsh, S, IS_BE(endianness)) + +RGB16_32FUNCS(AV_PIX_FMT_BGR32, , bgr32, 16, 0, 0, 0, 0xFF0000, 0xFF00, 0x00FF, 8, 0, 8, RGB2YUV_SHIFT + 8) +RGB16_32FUNCS(AV_PIX_FMT_BGR32_1, , bgr321, 16, 0, 0, 8, 0xFF0000, 0xFF00, 0x00FF, 8, 0, 8, RGB2YUV_SHIFT + 8) +RGB16_32FUNCS(AV_PIX_FMT_RGB32, , rgb32, 0, 0, 16, 0, 0x00FF, 0xFF00, 0xFF0000, 8, 0, 8, RGB2YUV_SHIFT + 8) +RGB16_32FUNCS(AV_PIX_FMT_RGB32_1, , rgb321, 0, 0, 16, 8, 0x00FF, 0xFF00, 0xFF0000, 8, 0, 8, RGB2YUV_SHIFT + 8) +RGB16_32FUNCS(AV_PIX_FMT_BGR565, LE, bgr16le, 0, 0, 0, 0, 0x001F, 0x07E0, 0xF800, 11, 5, 0, RGB2YUV_SHIFT + 8) +RGB16_32FUNCS(AV_PIX_FMT_BGR555, LE, bgr15le, 0, 0, 0, 0, 0x001F, 0x03E0, 0x7C00, 10, 5, 0, RGB2YUV_SHIFT + 7) +RGB16_32FUNCS(AV_PIX_FMT_BGR444, LE, bgr12le, 0, 0, 0, 0, 0x000F, 0x00F0, 0x0F00, 8, 4, 0, RGB2YUV_SHIFT + 4) +RGB16_32FUNCS(AV_PIX_FMT_RGB565, LE, rgb16le, 0, 0, 0, 0, 0xF800, 0x07E0, 0x001F, 0, 5, 11, RGB2YUV_SHIFT + 8) +RGB16_32FUNCS(AV_PIX_FMT_RGB555, LE, rgb15le, 0, 0, 0, 0, 0x7C00, 0x03E0, 0x001F, 0, 5, 10, RGB2YUV_SHIFT + 7) +RGB16_32FUNCS(AV_PIX_FMT_RGB444, LE, rgb12le, 0, 0, 0, 0, 0x0F00, 0x00F0, 0x000F, 0, 4, 8, RGB2YUV_SHIFT + 4) +RGB16_32FUNCS(AV_PIX_FMT_BGR565, BE, bgr16be, 0, 0, 0, 0, 0x001F, 0x07E0, 0xF800, 11, 5, 0, RGB2YUV_SHIFT + 8) +RGB16_32FUNCS(AV_PIX_FMT_BGR555, BE, bgr15be, 0, 0, 0, 0, 0x001F, 0x03E0, 0x7C00, 10, 5, 0, RGB2YUV_SHIFT + 7) +RGB16_32FUNCS(AV_PIX_FMT_BGR444, BE, bgr12be, 0, 0, 0, 0, 0x000F, 0x00F0, 0x0F00, 8, 4, 0, RGB2YUV_SHIFT + 4) +RGB16_32FUNCS(AV_PIX_FMT_RGB565, BE, rgb16be, 0, 0, 0, 0, 0xF800, 0x07E0, 0x001F, 0, 5, 11, RGB2YUV_SHIFT + 8) +RGB16_32FUNCS(AV_PIX_FMT_RGB555, BE, rgb15be, 0, 0, 0, 0, 0x7C00, 0x03E0, 0x001F, 0, 5, 10, RGB2YUV_SHIFT + 7) +RGB16_32FUNCS(AV_PIX_FMT_RGB444, BE, rgb12be, 0, 0, 0, 0, 0x0F00, 0x00F0, 0x000F, 0, 4, 8, RGB2YUV_SHIFT + 4) +RGB16_32FUNCS(AV_PIX_FMT_X2RGB10, LE, rgb30le, 16, 6, 0, 0, 0x3FF00000, 0xFFC00, 0x3FF, 0, 0, 4, RGB2YUV_SHIFT + 6) +RGB16_32FUNCS(AV_PIX_FMT_X2BGR10, LE, bgr30le, 0, 6, 16, 0, 0x3FF, 0xFFC00, 0x3FF00000, 4, 0, 0, RGB2YUV_SHIFT + 6) + +static void gbr24pToUV_half_c(uint8_t *_dstU, uint8_t *_dstV, + const uint8_t *gsrc, const uint8_t *bsrc, const uint8_t *rsrc, + int width, uint32_t *rgb2yuv, void *opq) +{ + uint16_t *dstU = (uint16_t *)_dstU; + uint16_t *dstV = (uint16_t *)_dstV; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + + int i; + for (i = 0; i < width; i++) { + unsigned int g = gsrc[2*i] + gsrc[2*i+1]; + unsigned int b = bsrc[2*i] + bsrc[2*i+1]; + unsigned int r = rsrc[2*i] + rsrc[2*i+1]; + + dstU[i] = (ru*r + gu*g + bu*b + (0x4001<<(RGB2YUV_SHIFT-6))) >> (RGB2YUV_SHIFT-6+1); + dstV[i] = (rv*r + gv*g + bv*b + (0x4001<<(RGB2YUV_SHIFT-6))) >> (RGB2YUV_SHIFT-6+1); + } +} + +static void rgba64leToA_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused, void *opq) +{ + int16_t *dst = (int16_t *)_dst; + const uint16_t *src = (const uint16_t *)_src; + int i; + for (i = 0; i < width; i++) + dst[i] = AV_RL16(src + 4 * i + 3); +} + +static void rgba64beToA_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused, void *opq) +{ + int16_t *dst = (int16_t *)_dst; + const uint16_t *src = (const uint16_t *)_src; + int i; + for (i = 0; i < width; i++) + dst[i] = AV_RB16(src + 4 * i + 3); +} + +static void abgrToA_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused, void *opq) +{ + int16_t *dst = (int16_t *)_dst; + int i; + for (i=0; i<width; i++) { + dst[i]= src[4*i]<<6 | src[4*i]>>2; + } +} + +static void rgbaToA_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused, void *opq) +{ + int16_t *dst = (int16_t *)_dst; + int i; + for (i=0; i<width; i++) { + dst[i]= src[4*i+3]<<6 | src[4*i+3]>>2; + } +} + +static void palToA_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *pal, void *opq) +{ + int16_t *dst = (int16_t *)_dst; + int i; + for (i=0; i<width; i++) { + int d= src[i]; + + dst[i]= (pal[d] >> 24)<<6 | pal[d]>>26; + } +} + +static void palToY_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *pal, void *opq) +{ + int16_t *dst = (int16_t *)_dst; + int i; + for (i = 0; i < width; i++) { + int d = src[i]; + + dst[i] = (pal[d] & 0xFF)<<6; + } +} + +static void palToUV_c(uint8_t *_dstU, uint8_t *_dstV, + const uint8_t *unused0, const uint8_t *src1, const uint8_t *src2, + int width, uint32_t *pal, void *opq) +{ + uint16_t *dstU = (uint16_t *)_dstU; + int16_t *dstV = (int16_t *)_dstV; + int i; + av_assert1(src1 == src2); + for (i = 0; i < width; i++) { + int p = pal[src1[i]]; + + dstU[i] = (uint8_t)(p>> 8)<<6; + dstV[i] = (uint8_t)(p>>16)<<6; + } +} + +static void monowhite2Y_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused, void *opq) +{ + int16_t *dst = (int16_t *)_dst; + int i, j; + width = (width + 7) >> 3; + for (i = 0; i < width; i++) { + int d = ~src[i]; + for (j = 0; j < 8; j++) + dst[8*i+j]= ((d>>(7-j))&1) * 16383; + } + if(width&7){ + int d= ~src[i]; + for (j = 0; j < (width&7); j++) + dst[8*i+j]= ((d>>(7-j))&1) * 16383; + } +} + +static void monoblack2Y_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused, void *opq) +{ + int16_t *dst = (int16_t *)_dst; + int i, j; + width = (width + 7) >> 3; + for (i = 0; i < width; i++) { + int d = src[i]; + for (j = 0; j < 8; j++) + dst[8*i+j]= ((d>>(7-j))&1) * 16383; + } + if(width&7){ + int d = src[i]; + for (j = 0; j < (width&7); j++) + dst[8*i+j] = ((d>>(7-j))&1) * 16383; + } +} + +static void yuy2ToY_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width, + uint32_t *unused, void *opq) +{ + int i; + for (i = 0; i < width; i++) + dst[i] = src[2 * i]; +} + +static void yuy2ToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq) +{ + int i; + for (i = 0; i < width; i++) { + dstU[i] = src1[4 * i + 1]; + dstV[i] = src1[4 * i + 3]; + } + av_assert1(src1 == src2); +} + +static void yvy2ToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq) +{ + int i; + for (i = 0; i < width; i++) { + dstV[i] = src1[4 * i + 1]; + dstU[i] = src1[4 * i + 3]; + } + av_assert1(src1 == src2); +} + +#define y21xle_wrapper(bits, shift) \ + static void y2 ## bits ## le_UV_c(uint8_t *dstU, uint8_t *dstV, \ + const uint8_t *unused0, \ + const uint8_t *src, \ + const uint8_t *unused1, int width, \ + uint32_t *unused2, void *opq) \ + { \ + int i; \ + for (i = 0; i < width; i++) { \ + AV_WN16(dstU + i * 2, AV_RL16(src + i * 8 + 2) >> shift); \ + AV_WN16(dstV + i * 2, AV_RL16(src + i * 8 + 6) >> shift); \ + } \ + } \ + \ + static void y2 ## bits ## le_Y_c(uint8_t *dst, const uint8_t *src, \ + const uint8_t *unused0, \ + const uint8_t *unused1, int width, \ + uint32_t *unused2, void *opq) \ + { \ + int i; \ + for (i = 0; i < width; i++) \ + AV_WN16(dst + i * 2, AV_RL16(src + i * 4) >> shift); \ + } + +y21xle_wrapper(10, 6) +y21xle_wrapper(12, 4) +y21xle_wrapper(16, 0) + +static void bswap16Y_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused1, const uint8_t *unused2, int width, + uint32_t *unused, void *opq) +{ + int i; + const uint16_t *src = (const uint16_t *)_src; + uint16_t *dst = (uint16_t *)_dst; + for (i = 0; i < width; i++) + dst[i] = av_bswap16(src[i]); +} + +static void bswap16UV_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused0, const uint8_t *_src1, + const uint8_t *_src2, int width, uint32_t *unused, void *opq) +{ + int i; + const uint16_t *src1 = (const uint16_t *)_src1, + *src2 = (const uint16_t *)_src2; + uint16_t *dstU = (uint16_t *)_dstU, *dstV = (uint16_t *)_dstV; + for (i = 0; i < width; i++) { + dstU[i] = av_bswap16(src1[i]); + dstV[i] = av_bswap16(src2[i]); + } +} + +static void read_ya16le_gray_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width, + uint32_t *unused, void *opq) +{ + int i; + for (i = 0; i < width; i++) + AV_WN16(dst + i * 2, AV_RL16(src + i * 4)); +} + +static void read_ya16le_alpha_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width, + uint32_t *unused, void *opq) +{ + int i; + for (i = 0; i < width; i++) + AV_WN16(dst + i * 2, AV_RL16(src + i * 4 + 2)); +} + +static void read_ya16be_gray_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width, + uint32_t *unused, void *opq) +{ + int i; + for (i = 0; i < width; i++) + AV_WN16(dst + i * 2, AV_RB16(src + i * 4)); +} + +static void read_ya16be_alpha_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width, + uint32_t *unused, void *opq) +{ + int i; + for (i = 0; i < width; i++) + AV_WN16(dst + i * 2, AV_RB16(src + i * 4 + 2)); +} + +static void read_ayuv64le_Y_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused0, const uint8_t *unused1, int width, + uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) + AV_WN16(dst + i * 2, AV_RL16(src + i * 8 + 2)); +} + +static void read_ayuv64be_Y_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused0, const uint8_t *unused1, int width, + uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) + AV_WN16(dst + i * 2, AV_RB16(src + i * 8 + 2)); +} + +static av_always_inline void ayuv64le_UV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src, int width, + int u_offset, int v_offset) +{ + int i; + for (i = 0; i < width; i++) { + AV_WN16(dstU + i * 2, AV_RL16(src + i * 8 + u_offset)); + AV_WN16(dstV + i * 2, AV_RL16(src + i * 8 + v_offset)); + } +} + +static av_always_inline void ayuv64be_UV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src, int width, + int u_offset, int v_offset) +{ + int i; + for (i = 0; i < width; i++) { + AV_WN16(dstU + i * 2, AV_RB16(src + i * 8 + u_offset)); + AV_WN16(dstV + i * 2, AV_RB16(src + i * 8 + v_offset)); + } +} + +#define ayuv64_UV_funcs(pixfmt, U, V) \ +static void read_ ## pixfmt ## le_UV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src, \ + const uint8_t *unused1, int width, uint32_t *unused2, void *opq) \ +{ \ + ayuv64le_UV_c(dstU, dstV, src, width, U, V); \ +} \ + \ +static void read_ ## pixfmt ## be_UV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src, \ + const uint8_t *unused1, int width, uint32_t *unused2, void *opq) \ +{ \ + ayuv64be_UV_c(dstU, dstV, src, width, U, V); \ +} + +ayuv64_UV_funcs(ayuv64, 4, 6) +ayuv64_UV_funcs(xv48, 0, 4) + +static void read_ayuv64le_A_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused0, const uint8_t *unused1, int width, + uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) + AV_WN16(dst + i * 2, AV_RL16(src + i * 8)); +} + +static void read_ayuv64be_A_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused0, const uint8_t *unused1, int width, + uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) + AV_WN16(dst + i * 2, AV_RB16(src + i * 8)); +} + +static void read_vuyx_UV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src, + const uint8_t *unused1, int width, uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) { + dstU[i] = src[i * 4 + 1]; + dstV[i] = src[i * 4]; + } +} + +static void read_vuyx_Y_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused0, const uint8_t *unused1, int width, + uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) + dst[i] = src[i * 4 + 2]; +} + +static void read_vuya_A_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused0, const uint8_t *unused1, int width, + uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) + dst[i] = src[i * 4 + 3]; +} + +static void read_ayuv_UV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src, + const uint8_t *unused1, int width, uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) { + dstU[i] = src[i * 4 + 2]; + dstV[i] = src[i * 4 + 3]; + } +} + +static void read_ayuv_Y_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused0, const uint8_t *unused1, int width, + uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) + dst[i] = src[i * 4 + 1]; +} + +static void read_ayuv_A_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused0, const uint8_t *unused1, int width, + uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) + dst[i] = src[i * 4]; +} + +static void read_uyva_UV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src, + const uint8_t *unused1, int width, uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) { + dstU[i] = src[i * 4]; + dstV[i] = src[i * 4 + 2]; + } +} + +static void vyuToY_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused0, const uint8_t *unused1, int width, + uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) + dst[i] = src[i * 3 + 1]; +} + +static void vyuToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src, + const uint8_t *unused1, int width, uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) { + dstU[i] = src[i * 3 + 2]; + dstV[i] = src[i * 3]; + } +} + +static void read_v30xle_Y_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused0, const uint8_t *unused1, int width, + uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) + AV_WN16(dst + i * 2, (AV_RL32(src + i * 4) >> 12) & 0x3FFu); +} + + +static void read_v30xle_UV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src, + const uint8_t *unused1, int width, uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) { + unsigned int uv = AV_RL32(src + i * 4); + AV_WN16(dstU + i * 2, (uv >> 2) & 0x3FFu); + AV_WN16(dstV + i * 2, (uv >> 22) & 0x3FFu); + } +} + +static void read_xv30le_Y_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused0, const uint8_t *unused1, int width, + uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) + AV_WN16(dst + i * 2, (AV_RL32(src + i * 4) >> 10) & 0x3FFu); +} + + +static void read_xv30le_UV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src, + const uint8_t *unused1, int width, uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) { + AV_WN16(dstU + i * 2, AV_RL32(src + i * 4) & 0x3FFu); + AV_WN16(dstV + i * 2, (AV_RL32(src + i * 4) >> 20) & 0x3FFu); + } +} + +static void read_xv36le_Y_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused0, const uint8_t *unused1, int width, + uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) + AV_WN16(dst + i * 2, AV_RL16(src + i * 8 + 2) >> 4); +} + + +static void read_xv36le_UV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src, + const uint8_t *unused1, int width, uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) { + AV_WN16(dstU + i * 2, AV_RL16(src + i * 8 + 0) >> 4); + AV_WN16(dstV + i * 2, AV_RL16(src + i * 8 + 4) >> 4); + } +} + +static void read_xv36be_Y_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused0, const uint8_t *unused1, int width, + uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) + AV_WN16(dst + i * 2, AV_RB16(src + i * 8 + 2) >> 4); +} + + +static void read_xv36be_UV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src, + const uint8_t *unused1, int width, uint32_t *unused2, void *opq) +{ + int i; + for (i = 0; i < width; i++) { + AV_WN16(dstU + i * 2, AV_RB16(src + i * 8 + 0) >> 4); + AV_WN16(dstV + i * 2, AV_RB16(src + i * 8 + 4) >> 4); + } +} + +/* This is almost identical to the previous, end exists only because + * yuy2ToY/UV)(dst, src + 1, ...) would have 100% unaligned accesses. */ +static void uyvyToY_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width, + uint32_t *unused, void *opq) +{ + int i; + for (i = 0; i < width; i++) + dst[i] = src[2 * i + 1]; +} + +static void uyvyToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq) +{ + int i; + for (i = 0; i < width; i++) { + dstU[i] = src1[4 * i + 0]; + dstV[i] = src1[4 * i + 2]; + } + av_assert1(src1 == src2); +} + +static void uyyvyyToY_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, + int width, uint32_t *unused, void *opq) +{ + for (int i = 0; i < width; i++) + dst[i] = src[3 * (i >> 1) + 1 + (i & 1)]; +} + +static void uyyvyyToUV_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *unused, void *opq) +{ + for (int i = 0; i < width; i++) { + dstU[i] = src1[6 * i + 0]; + dstV[i] = src1[6 * i + 3]; + } + av_assert1(src1 == src2); +} + +static av_always_inline void nvXXtoUV_c(uint8_t *dst1, uint8_t *dst2, + const uint8_t *src, int width) +{ + int i; + for (i = 0; i < width; i++) { + dst1[i] = src[2 * i + 0]; + dst2[i] = src[2 * i + 1]; + } +} + +static void nv12ToUV_c(uint8_t *dstU, uint8_t *dstV, + const uint8_t *unused0, const uint8_t *src1, const uint8_t *src2, + int width, uint32_t *unused, void *opq) +{ + nvXXtoUV_c(dstU, dstV, src1, width); +} + +static void nv21ToUV_c(uint8_t *dstU, uint8_t *dstV, + const uint8_t *unused0, const uint8_t *src1, const uint8_t *src2, + int width, uint32_t *unused, void *opq) +{ + nvXXtoUV_c(dstV, dstU, src1, width); +} + +#define p01x_uv_wrapper(fmt, shift) \ + static void fmt ## LEToUV ## _c(uint8_t *dstU, \ + uint8_t *dstV, \ + const uint8_t *unused0, \ + const uint8_t *src1, \ + const uint8_t *src2, int width, \ + uint32_t *unused, void *opq) \ + { \ + int i; \ + for (i = 0; i < width; i++) { \ + AV_WN16(dstU + i * 2, AV_RL16(src1 + i * 4 + 0) >> shift); \ + AV_WN16(dstV + i * 2, AV_RL16(src1 + i * 4 + 2) >> shift); \ + } \ + } \ + \ + static void fmt ## BEToUV ## _c(uint8_t *dstU, \ + uint8_t *dstV, \ + const uint8_t *unused0, \ + const uint8_t *src1, \ + const uint8_t *src2, int width, \ + uint32_t *unused, void *opq) \ + { \ + int i; \ + for (i = 0; i < width; i++) { \ + AV_WN16(dstU + i * 2, AV_RB16(src1 + i * 4 + 0) >> shift); \ + AV_WN16(dstV + i * 2, AV_RB16(src1 + i * 4 + 2) >> shift); \ + } \ + } + +#define p01x_wrapper(fmt, shift) \ + static void fmt ## LEToY ## _c(uint8_t *dst, \ + const uint8_t *src, \ + const uint8_t *unused1, \ + const uint8_t *unused2, int width, \ + uint32_t *unused, void *opq) \ + { \ + int i; \ + for (i = 0; i < width; i++) { \ + AV_WN16(dst + i * 2, AV_RL16(src + i * 2) >> shift); \ + } \ + } \ + \ + static void fmt ## BEToY ## _c(uint8_t *dst, \ + const uint8_t *src, \ + const uint8_t *unused1, \ + const uint8_t *unused2, int width, \ + uint32_t *unused, void *opq) \ + { \ + int i; \ + for (i = 0; i < width; i++) { \ + AV_WN16(dst + i * 2, AV_RB16(src + i * 2) >> shift); \ + } \ + } \ + p01x_uv_wrapper(fmt, shift) + +p01x_wrapper(nv20, 0) +p01x_wrapper(p010, 6) +p01x_wrapper(p012, 4) +p01x_uv_wrapper(p016, 0) + +#define shf16_uv_wrapper(shift) \ + static void shf16_ ## shift ## LEToUV_c(uint8_t *dstU, \ + uint8_t *dstV, \ + const uint8_t *unused0, \ + const uint8_t *src1, \ + const uint8_t *src2, int width, \ + uint32_t *unused, void *opq) \ + { \ + int i; \ + for (i = 0; i < width; i++) { \ + AV_WN16(dstU + i * 2, AV_RL16(src1 + i * 2) >> (16 - shift)); \ + AV_WN16(dstV + i * 2, AV_RL16(src2 + i * 2) >> (16 - shift)); \ + } \ + } \ + \ + static void shf16_ ## shift ## BEToUV_c(uint8_t *dstU, \ + uint8_t *dstV, \ + const uint8_t *unused0, \ + const uint8_t *src1, \ + const uint8_t *src2, int width, \ + uint32_t *unused, void *opq) \ + { \ + int i; \ + for (i = 0; i < width; i++) { \ + AV_WN16(dstU + i * 2, AV_RB16(src1 + i * 2) >> (16 - shift)); \ + AV_WN16(dstV + i * 2, AV_RB16(src2 + i * 2) >> (16 - shift)); \ + } \ + } + +#define shf16_wrapper(shift) \ + static void shf16_ ## shift ## LEToY_c(uint8_t *dst, \ + const uint8_t *src, \ + const uint8_t *unused1, \ + const uint8_t *unused2, int width, \ + uint32_t *unused, void *opq) \ + { \ + int i; \ + for (i = 0; i < width; i++) { \ + AV_WN16(dst + i * 2, AV_RL16(src + i * 2) >> (16 - shift)); \ + } \ + } \ + \ + static void shf16_ ## shift ## BEToY_c(uint8_t *dst, \ + const uint8_t *src, \ + const uint8_t *unused1, \ + const uint8_t *unused2, int width, \ + uint32_t *unused, void *opq) \ + { \ + int i; \ + for (i = 0; i < width; i++) { \ + AV_WN16(dst + i * 2, AV_RB16(src + i * 2) >> (16 - shift)); \ + } \ + } \ + shf16_uv_wrapper(shift) + +shf16_wrapper(10) +shf16_wrapper(12) + +static void bgr24ToY_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, + int width, uint32_t *rgb2yuv, void *opq) +{ + int16_t *dst = (int16_t *)_dst; + int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX]; + int i; + for (i = 0; i < width; i++) { + int b = src[i * 3 + 0]; + int g = src[i * 3 + 1]; + int r = src[i * 3 + 2]; + + dst[i] = ((ry*r + gy*g + by*b + (32<<(RGB2YUV_SHIFT-1)) + (1<<(RGB2YUV_SHIFT-7)))>>(RGB2YUV_SHIFT-6)); + } +} + +static void bgr24ToUV_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *rgb2yuv, void *opq) +{ + int16_t *dstU = (int16_t *)_dstU; + int16_t *dstV = (int16_t *)_dstV; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + int i; + for (i = 0; i < width; i++) { + int b = src1[3 * i + 0]; + int g = src1[3 * i + 1]; + int r = src1[3 * i + 2]; + + dstU[i] = (ru*r + gu*g + bu*b + (256<<(RGB2YUV_SHIFT-1)) + (1<<(RGB2YUV_SHIFT-7)))>>(RGB2YUV_SHIFT-6); + dstV[i] = (rv*r + gv*g + bv*b + (256<<(RGB2YUV_SHIFT-1)) + (1<<(RGB2YUV_SHIFT-7)))>>(RGB2YUV_SHIFT-6); + } + av_assert1(src1 == src2); +} + +static void bgr24ToUV_half_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *rgb2yuv, void *opq) +{ + int16_t *dstU = (int16_t *)_dstU; + int16_t *dstV = (int16_t *)_dstV; + int i; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + for (i = 0; i < width; i++) { + int b = src1[6 * i + 0] + src1[6 * i + 3]; + int g = src1[6 * i + 1] + src1[6 * i + 4]; + int r = src1[6 * i + 2] + src1[6 * i + 5]; + + dstU[i] = (ru*r + gu*g + bu*b + (256<<RGB2YUV_SHIFT) + (1<<(RGB2YUV_SHIFT-6)))>>(RGB2YUV_SHIFT-5); + dstV[i] = (rv*r + gv*g + bv*b + (256<<RGB2YUV_SHIFT) + (1<<(RGB2YUV_SHIFT-6)))>>(RGB2YUV_SHIFT-5); + } + av_assert1(src1 == src2); +} + +static void rgb24ToY_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2, int width, + uint32_t *rgb2yuv, void *opq) +{ + int16_t *dst = (int16_t *)_dst; + int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX]; + int i; + for (i = 0; i < width; i++) { + int r = src[i * 3 + 0]; + int g = src[i * 3 + 1]; + int b = src[i * 3 + 2]; + + dst[i] = ((ry*r + gy*g + by*b + (32<<(RGB2YUV_SHIFT-1)) + (1<<(RGB2YUV_SHIFT-7)))>>(RGB2YUV_SHIFT-6)); + } +} + +static void rgb24ToUV_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *rgb2yuv, void *opq) +{ + int16_t *dstU = (int16_t *)_dstU; + int16_t *dstV = (int16_t *)_dstV; + int i; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + av_assert1(src1 == src2); + for (i = 0; i < width; i++) { + int r = src1[3 * i + 0]; + int g = src1[3 * i + 1]; + int b = src1[3 * i + 2]; + + dstU[i] = (ru*r + gu*g + bu*b + (256<<(RGB2YUV_SHIFT-1)) + (1<<(RGB2YUV_SHIFT-7)))>>(RGB2YUV_SHIFT-6); + dstV[i] = (rv*r + gv*g + bv*b + (256<<(RGB2YUV_SHIFT-1)) + (1<<(RGB2YUV_SHIFT-7)))>>(RGB2YUV_SHIFT-6); + } +} + +static void rgb24ToUV_half_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused0, const uint8_t *src1, + const uint8_t *src2, int width, uint32_t *rgb2yuv, void *opq) +{ + int16_t *dstU = (int16_t *)_dstU; + int16_t *dstV = (int16_t *)_dstV; + int i; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + av_assert1(src1 == src2); + for (i = 0; i < width; i++) { + int r = src1[6 * i + 0] + src1[6 * i + 3]; + int g = src1[6 * i + 1] + src1[6 * i + 4]; + int b = src1[6 * i + 2] + src1[6 * i + 5]; + + dstU[i] = (ru*r + gu*g + bu*b + (256<<RGB2YUV_SHIFT) + (1<<(RGB2YUV_SHIFT-6)))>>(RGB2YUV_SHIFT-5); + dstV[i] = (rv*r + gv*g + bv*b + (256<<RGB2YUV_SHIFT) + (1<<(RGB2YUV_SHIFT-6)))>>(RGB2YUV_SHIFT-5); + } +} + +static void planar_rgb_to_y(uint8_t *_dst, const uint8_t *src[4], int width, int32_t *rgb2yuv, void *opq) +{ + uint16_t *dst = (uint16_t *)_dst; + int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX]; + int i; + for (i = 0; i < width; i++) { + int g = src[0][i]; + int b = src[1][i]; + int r = src[2][i]; + + dst[i] = (int)((unsigned)ry*r + (unsigned)gy*g + (unsigned)by*b + (0x801<<(RGB2YUV_SHIFT-7))) >> (RGB2YUV_SHIFT-6); + } +} + +static void planar_rgb_to_a(uint8_t *_dst, const uint8_t *src[4], int width, int32_t *unused, void *opq) +{ + uint16_t *dst = (uint16_t *)_dst; + int i; + for (i = 0; i < width; i++) + dst[i] = src[3][i] << 6; +} + +static void planar_rgb_to_uv(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *src[4], int width, int32_t *rgb2yuv, void *opq) +{ + uint16_t *dstU = (uint16_t *)_dstU; + uint16_t *dstV = (uint16_t *)_dstV; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + int i; + for (i = 0; i < width; i++) { + int g = src[0][i]; + int b = src[1][i]; + int r = src[2][i]; + + dstU[i] = (int)((unsigned)ru*r + (unsigned)gu*g + (unsigned)bu*b + (0x4001<<(RGB2YUV_SHIFT-7))) >> (RGB2YUV_SHIFT-6); + dstV[i] = (int)((unsigned)rv*r + (unsigned)gv*g + (unsigned)bv*b + (0x4001<<(RGB2YUV_SHIFT-7))) >> (RGB2YUV_SHIFT-6); + } +} + +#define rdpx(src) \ + (is_be ? AV_RB16(src) : AV_RL16(src)) + +#define shifted_planar_rgb16_to_y(rdpx_shift) \ + static av_always_inline void planar_rgb16_s ## rdpx_shift ## _to_y(uint8_t *_dst, const uint8_t *_src[4], \ + int width, int bpc, int is_be, int32_t *rgb2yuv) \ + { \ + int i; \ + const uint16_t **src = (const uint16_t **)_src; \ + uint16_t *dst = (uint16_t *)_dst; \ + int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX]; \ + int shift = bpc < 16 ? bpc : 14; \ + for (i = 0; i < width; i++) { \ + int g = rdpx(src[0] + i) >> (16 - rdpx_shift); \ + int b = rdpx(src[1] + i) >> (16 - rdpx_shift); \ + int r = rdpx(src[2] + i) >> (16 - rdpx_shift); \ + \ + dst[i] = (int)((unsigned)ry*r + (unsigned)gy*g + (unsigned)by*b + (16 << (RGB2YUV_SHIFT + bpc - 8)) \ + + (1 << (RGB2YUV_SHIFT + shift - 15))) >> (RGB2YUV_SHIFT + shift - 14); \ + } \ + } + +#define shifted_planar_rgb16_to_a(rdpx_shift) \ + static av_always_inline void planar_rgb16_s ## rdpx_shift ## _to_a(uint8_t *_dst, const uint8_t *_src[4], \ + int width, int bpc, int is_be, int32_t *rgb2yuv) \ + { \ + int i; \ + const uint16_t **src = (const uint16_t **)_src; \ + uint16_t *dst = (uint16_t *)_dst; \ + int shift = (bpc < 16 ? bpc : 14) + 16 - rdpx_shift; \ + \ + for (i = 0; i < width; i++) { \ + dst[i] = rdpx(src[3] + i) << (14 - shift); \ + } \ + } \ + +#define shifted_planar_rgb16_to_uv(rdpx_shift) \ + static av_always_inline void planar_rgb16_s ## rdpx_shift ## _to_uv(uint8_t *_dstU, uint8_t *_dstV, \ + const uint8_t *_src[4], int width, \ + int bpc, int is_be, int32_t *rgb2yuv) \ + { \ + int i; \ + const uint16_t **src = (const uint16_t **)_src; \ + uint16_t *dstU = (uint16_t *)_dstU; \ + uint16_t *dstV = (uint16_t *)_dstV; \ + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; \ + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; \ + int shift = bpc < 16 ? bpc : 14; \ + for (i = 0; i < width; i++) { \ + int g = rdpx(src[0] + i) >> (16 - rdpx_shift); \ + int b = rdpx(src[1] + i) >> (16 - rdpx_shift); \ + int r = rdpx(src[2] + i) >> (16 - rdpx_shift); \ + \ + dstU[i] = (int)((unsigned)ru*r + (unsigned)gu*g + (unsigned)bu*b + (128 << (RGB2YUV_SHIFT + bpc - 8)) \ + + (1 << (RGB2YUV_SHIFT + shift - 15))) >> (RGB2YUV_SHIFT + shift - 14); \ + dstV[i] = (int)((unsigned)rv*r + (unsigned)gv*g + (unsigned)bv*b + (128 << (RGB2YUV_SHIFT + bpc - 8)) \ + + (1 << (RGB2YUV_SHIFT + shift - 15))) >> (RGB2YUV_SHIFT + shift - 14); \ + } \ + } + +#define shifted_planar_rgb16_to_y_uv(rdpx_shift) \ + shifted_planar_rgb16_to_y(rdpx_shift) \ + shifted_planar_rgb16_to_uv(rdpx_shift) + +#define shifted_planar_rgb16(rdpx_shift) \ + shifted_planar_rgb16_to_y_uv(rdpx_shift) \ + shifted_planar_rgb16_to_a(rdpx_shift) + +shifted_planar_rgb16(16) +shifted_planar_rgb16_to_y_uv(12) +shifted_planar_rgb16_to_y_uv(10) + +#undef rdpx + +#define rdpx(src) (is_be ? av_int2float(AV_RB32(src)): av_int2float(AV_RL32(src))) + +static av_always_inline void planar_rgbf32_to_a(uint8_t *_dst, const uint8_t *_src[4], int width, int is_be, int32_t *rgb2yuv) +{ + int i; + const float **src = (const float **)_src; + uint16_t *dst = (uint16_t *)_dst; + + for (i = 0; i < width; i++) { + dst[i] = lrintf(av_clipf(65535.0f * rdpx(src[3] + i), 0.0f, 65535.0f)); + } +} + +static av_always_inline void planar_rgbf32_to_uv(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *_src[4], int width, int is_be, int32_t *rgb2yuv) +{ + int i; + const float **src = (const float **)_src; + uint16_t *dstU = (uint16_t *)_dstU; + uint16_t *dstV = (uint16_t *)_dstV; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + + for (i = 0; i < width; i++) { + int g = lrintf(av_clipf(65535.0f * rdpx(src[0] + i), 0.0f, 65535.0f)); + int b = lrintf(av_clipf(65535.0f * rdpx(src[1] + i), 0.0f, 65535.0f)); + int r = lrintf(av_clipf(65535.0f * rdpx(src[2] + i), 0.0f, 65535.0f)); + + dstU[i] = (int)((unsigned)ru*r + (unsigned)gu*g + (unsigned)bu*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT; + dstV[i] = (int)((unsigned)rv*r + (unsigned)gv*g + (unsigned)bv*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT; + } +} + +static av_always_inline void planar_rgbf32_to_y(uint8_t *_dst, const uint8_t *_src[4], int width, int is_be, int32_t *rgb2yuv) +{ + int i; + const float **src = (const float **)_src; + uint16_t *dst = (uint16_t *)_dst; + + int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX]; + + for (i = 0; i < width; i++) { + int g = lrintf(av_clipf(65535.0f * rdpx(src[0] + i), 0.0f, 65535.0f)); + int b = lrintf(av_clipf(65535.0f * rdpx(src[1] + i), 0.0f, 65535.0f)); + int r = lrintf(av_clipf(65535.0f * rdpx(src[2] + i), 0.0f, 65535.0f)); + + dst[i] = (int)((unsigned)ry*r + (unsigned)gy*g + (unsigned)by*b + (0x2001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT; + } +} + +static av_always_inline void rgbf32_to_uv_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused1, + const uint8_t *_src, const uint8_t *unused2, + int width, int is_be, int32_t *rgb2yuv) +{ + int i; + const float *src = (const float *)_src; + uint16_t *dstU = (uint16_t *)_dstU; + uint16_t *dstV = (uint16_t *)_dstV; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + + for (i = 0; i < width; i++) { + int r = lrintf(av_clipf(65535.0f * rdpx(&src[3*i]), 0.0f, 65535.0f)); + int g = lrintf(av_clipf(65535.0f * rdpx(&src[3*i + 1]), 0.0f, 65535.0f)); + int b = lrintf(av_clipf(65535.0f * rdpx(&src[3*i + 2]), 0.0f, 65535.0f)); + + dstU[i] = (ru*r + gu*g + bu*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT; + dstV[i] = (rv*r + gv*g + bv*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT; + } +} + +static av_always_inline void rgbf32_to_y_c(uint8_t *_dst, const uint8_t *_src, + const uint8_t *unused1, const uint8_t *unused2, + int width, int is_be, int32_t *rgb2yuv) +{ + int i; + const float *src = (const float *)_src; + uint16_t *dst = (uint16_t *)_dst; + + int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX]; + + for (i = 0; i < width; i++) { + int r = lrintf(av_clipf(65535.0f * rdpx(&src[3*i]), 0.0f, 65535.0f)); + int g = lrintf(av_clipf(65535.0f * rdpx(&src[3*i + 1]), 0.0f, 65535.0f)); + int b = lrintf(av_clipf(65535.0f * rdpx(&src[3*i + 2]), 0.0f, 65535.0f)); + + dst[i] = (ry*r + gy*g + by*b + (0x2001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT; + } +} + +static av_always_inline void grayf32ToY16_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused1, + const uint8_t *unused2, int width, int is_be, uint32_t *unused) +{ + int i; + const float *src = (const float *)_src; + uint16_t *dst = (uint16_t *)_dst; + + for (i = 0; i < width; ++i){ + dst[i] = lrintf(av_clipf(65535.0f * rdpx(src + i), 0.0f, 65535.0f)); + } +} + +static av_always_inline void read_yaf32_gray_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused1, + const uint8_t *unused2, int width, int is_be, uint32_t *unused) +{ + int i; + const float *src = (const float *)_src; + uint16_t *dst = (uint16_t *)_dst; + + for (i = 0; i < width; ++i) + dst[i] = lrintf(av_clipf(65535.0f * rdpx(src + i*2), 0.0f, 65535.0f)); +} + +static av_always_inline void read_yaf32_alpha_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused1, + const uint8_t *unused2, int width, int is_be, uint32_t *unused) +{ + int i; + const float *src = (const float *)_src; + uint16_t *dst = (uint16_t *)_dst; + + for (i = 0; i < width; ++i) + dst[i] = lrintf(av_clipf(65535.0f * rdpx(src + i*2 + 1), 0.0f, 65535.0f)); +} + +#undef rdpx + +#define rgb9plus_planar_funcs_endian(nbits, endian_name, endian) \ +static void planar_rgb##nbits##endian_name##_to_y(uint8_t *dst, const uint8_t *src[4], \ + int w, int32_t *rgb2yuv, void *opq) \ +{ \ + planar_rgb16_s16_to_y(dst, src, w, nbits, endian, rgb2yuv); \ +} \ +static void planar_rgb##nbits##endian_name##_to_uv(uint8_t *dstU, uint8_t *dstV, \ + const uint8_t *src[4], int w, int32_t *rgb2yuv, \ + void *opq) \ +{ \ + planar_rgb16_s16_to_uv(dstU, dstV, src, w, nbits, endian, rgb2yuv); \ +} \ + +#define rgb9plus_planar_transparency_funcs(nbits) \ +static void planar_rgb##nbits##le_to_a(uint8_t *dst, const uint8_t *src[4], \ + int w, int32_t *rgb2yuv, \ + void *opq) \ +{ \ + planar_rgb16_s16_to_a(dst, src, w, nbits, 0, rgb2yuv); \ +} \ +static void planar_rgb##nbits##be_to_a(uint8_t *dst, const uint8_t *src[4], \ + int w, int32_t *rgb2yuv, \ + void *opq) \ +{ \ + planar_rgb16_s16_to_a(dst, src, w, nbits, 1, rgb2yuv); \ +} + +#define rgb9plus_msb_planar_funcs_endian(nbits, endian_name, endian) \ +static void msb_planar_rgb##nbits##endian_name##_to_y(uint8_t *dst, const uint8_t *src[4], \ + int w, int32_t *rgb2yuv, void *opq) \ +{ \ + planar_rgb16_s##nbits##_to_y(dst, src, w, nbits, endian, rgb2yuv); \ +} \ +static void msb_planar_rgb##nbits##endian_name##_to_uv(uint8_t *dstU, uint8_t *dstV, \ + const uint8_t *src[4], int w, int32_t *rgb2yuv, \ + void *opq) \ +{ \ + planar_rgb16_s##nbits##_to_uv(dstU, dstV, src, w, nbits, endian, rgb2yuv); \ +} + +#define rgb9plus_planar_funcs(nbits) \ + rgb9plus_planar_funcs_endian(nbits, le, 0) \ + rgb9plus_planar_funcs_endian(nbits, be, 1) + +#define rgb9plus_msb_planar_funcs(nbits) \ + rgb9plus_msb_planar_funcs_endian(nbits, le, 0) \ + rgb9plus_msb_planar_funcs_endian(nbits, be, 1) + +rgb9plus_planar_funcs(9) +rgb9plus_planar_funcs(10) +rgb9plus_planar_funcs(12) +rgb9plus_planar_funcs(14) +rgb9plus_planar_funcs(16) + +rgb9plus_planar_transparency_funcs(10) +rgb9plus_planar_transparency_funcs(12) +rgb9plus_planar_transparency_funcs(14) +rgb9plus_planar_transparency_funcs(16) + +rgb9plus_msb_planar_funcs(10) +rgb9plus_msb_planar_funcs(12) + +#define rgbf32_funcs_endian(endian_name, endian) \ +static void planar_rgbf32##endian_name##_to_y(uint8_t *dst, const uint8_t *src[4], \ + int w, int32_t *rgb2yuv, void *opq) \ +{ \ + planar_rgbf32_to_y(dst, src, w, endian, rgb2yuv); \ +} \ +static void planar_rgbf32##endian_name##_to_uv(uint8_t *dstU, uint8_t *dstV, \ + const uint8_t *src[4], int w, int32_t *rgb2yuv, \ + void *opq) \ +{ \ + planar_rgbf32_to_uv(dstU, dstV, src, w, endian, rgb2yuv); \ +} \ +static void planar_rgbf32##endian_name##_to_a(uint8_t *dst, const uint8_t *src[4], \ + int w, int32_t *rgb2yuv, void *opq) \ +{ \ + planar_rgbf32_to_a(dst, src, w, endian, rgb2yuv); \ +} \ +static void rgbf32##endian_name##_to_y_c(uint8_t *dst, const uint8_t *src, \ + const uint8_t *unused1, const uint8_t *unused2, \ + int w, uint32_t *rgb2yuv, void *opq) \ +{ \ + rgbf32_to_y_c(dst, src, unused1, unused2, w, endian, rgb2yuv); \ +} \ +static void rgbf32##endian_name##_to_uv_c(uint8_t *dstU, uint8_t *dstV, \ + const uint8_t *unused1, \ + const uint8_t *src, const uint8_t *unused2, \ + int w, uint32_t *rgb2yuv, \ + void *opq) \ +{ \ + rgbf32_to_uv_c(dstU, dstV, unused1, src, unused2, w, endian, rgb2yuv); \ +} \ +static void grayf32##endian_name##ToY16_c(uint8_t *dst, const uint8_t *src, \ + const uint8_t *unused1, const uint8_t *unused2, \ + int width, uint32_t *unused, void *opq) \ +{ \ + grayf32ToY16_c(dst, src, unused1, unused2, width, endian, unused); \ +} \ +static void read_yaf32##endian_name##_gray_c(uint8_t *dst, const uint8_t *src, \ + const uint8_t *unused1, const uint8_t *unused2, \ + int width, uint32_t *unused, void *opq) \ +{ \ + read_yaf32_gray_c(dst, src, unused1, unused2, width, endian, unused); \ +} \ +static void read_yaf32##endian_name##_alpha_c(uint8_t *dst, const uint8_t *src, \ + const uint8_t *unused1, const uint8_t *unused2, \ + int width, uint32_t *unused, void *opq) \ +{ \ + read_yaf32_alpha_c(dst, src, unused1, unused2, width, endian, unused); \ +} + +rgbf32_funcs_endian(le, 0) +rgbf32_funcs_endian(be, 1) + +#define rdpx(src) av_int2float(half2float(is_be ? AV_RB16(&src) : AV_RL16(&src), h2f_tbl)) +#define rdpx2(src) av_int2float(half2float(is_be ? AV_RB16(src) : AV_RL16(src), h2f_tbl)) + +static av_always_inline void planar_rgbf16_to_a(uint8_t *dst, const uint8_t *src[4], int width, int is_be, int32_t *rgb2yuv, Half2FloatTables *h2f_tbl) +{ + int i; + + for (i = 0; i < width; i++) { + AV_WN16(dst + 2*i, lrintf(av_clipf(65535.0f * rdpx2(src[3] + 2*i), 0.0f, 65535.0f))); + } +} + +static av_always_inline void planar_rgbf16_to_uv(uint8_t *dstU, uint8_t *dstV, const uint8_t *src[4], int width, int is_be, int32_t *rgb2yuv, Half2FloatTables *h2f_tbl) +{ + int i; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + + for (i = 0; i < width; i++) { + int g = lrintf(av_clipf(65535.0f * rdpx2(src[0] + 2*i), 0.0f, 65535.0f)); + int b = lrintf(av_clipf(65535.0f * rdpx2(src[1] + 2*i), 0.0f, 65535.0f)); + int r = lrintf(av_clipf(65535.0f * rdpx2(src[2] + 2*i), 0.0f, 65535.0f)); + + AV_WN16(dstU + 2*i, (ru*r + gu*g + bu*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT); + AV_WN16(dstV + 2*i, (rv*r + gv*g + bv*b + (0x10001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT); + } +} + +static av_always_inline void planar_rgbf16_to_y(uint8_t *dst, const uint8_t *src[4], int width, int is_be, int32_t *rgb2yuv, Half2FloatTables *h2f_tbl) +{ + int i; + + int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX]; + + for (i = 0; i < width; i++) { + int g = lrintf(av_clipf(65535.0f * rdpx2(src[0] + 2*i), 0.0f, 65535.0f)); + int b = lrintf(av_clipf(65535.0f * rdpx2(src[1] + 2*i), 0.0f, 65535.0f)); + int r = lrintf(av_clipf(65535.0f * rdpx2(src[2] + 2*i), 0.0f, 65535.0f)); + + AV_WN16(dst + 2*i, (ry*r + gy*g + by*b + (0x2001 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT); + } +} + +static av_always_inline void grayf16ToY16_c(uint8_t *dst, const uint8_t *src, const uint8_t *unused1, + const uint8_t *unused2, int width, int is_be, uint32_t *unused, Half2FloatTables *h2f_tbl) +{ + int i; + + for (i = 0; i < width; ++i){ + AV_WN16(dst + 2*i, lrintf(av_clipf(65535.0f * rdpx2(src + 2*i), 0.0f, 65535.0f))); + } +} + +static av_always_inline void read_yaf16_gray_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + const uint8_t *unused2, int width, int is_be, uint32_t *unused, Half2FloatTables *h2f_tbl) +{ + uint16_t *dst = (uint16_t *)_dst; + + for (int i = 0; i < width; i++) + dst[i] = lrintf(av_clipf(65535.0f * rdpx2(src + 4*i), 0.0f, 65535.0f)); +} + +static av_always_inline void read_yaf16_alpha_c(uint8_t *_dst, const uint8_t *src, const uint8_t *unused1, + const uint8_t *unused2, int width, int is_be, uint32_t *unused, Half2FloatTables *h2f_tbl) +{ + uint16_t *dst = (uint16_t *)_dst; + + for (int i = 0; i < width; i++) + dst[i] = lrintf(av_clipf(65535.0f * rdpx2(src + 4*i + 2), 0.0f, 65535.0f)); +} + +static av_always_inline void rgbaf16ToUV_half_endian(uint16_t *dstU, uint16_t *dstV, int is_be, + const uint16_t *src, int width, + int32_t *rgb2yuv, Half2FloatTables *h2f_tbl) +{ + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + int i; + for (i = 0; i < width; i++) { + int r = (lrintf(av_clipf(65535.0f * rdpx(src[i*8+0]), 0.0f, 65535.0f)) + + lrintf(av_clipf(65535.0f * rdpx(src[i*8+4]), 0.0f, 65535.0f))) >> 1; + int g = (lrintf(av_clipf(65535.0f * rdpx(src[i*8+1]), 0.0f, 65535.0f)) + + lrintf(av_clipf(65535.0f * rdpx(src[i*8+5]), 0.0f, 65535.0f))) >> 1; + int b = (lrintf(av_clipf(65535.0f * rdpx(src[i*8+2]), 0.0f, 65535.0f)) + + lrintf(av_clipf(65535.0f * rdpx(src[i*8+6]), 0.0f, 65535.0f))) >> 1; + + dstU[i] = (ru*r + gu*g + bu*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + dstV[i] = (rv*r + gv*g + bv*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + } +} + +static av_always_inline void rgbaf16ToUV_endian(uint16_t *dstU, uint16_t *dstV, int is_be, + const uint16_t *src, int width, + int32_t *rgb2yuv, Half2FloatTables *h2f_tbl) +{ + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + int i; + for (i = 0; i < width; i++) { + int r = lrintf(av_clipf(65535.0f * rdpx(src[i*4+0]), 0.0f, 65535.0f)); + int g = lrintf(av_clipf(65535.0f * rdpx(src[i*4+1]), 0.0f, 65535.0f)); + int b = lrintf(av_clipf(65535.0f * rdpx(src[i*4+2]), 0.0f, 65535.0f)); + + dstU[i] = (ru*r + gu*g + bu*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + dstV[i] = (rv*r + gv*g + bv*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + } +} + +static av_always_inline void rgbaf16ToY_endian(uint16_t *dst, const uint16_t *src, int is_be, + int width, int32_t *rgb2yuv, Half2FloatTables *h2f_tbl) +{ + int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX]; + int i; + for (i = 0; i < width; i++) { + int r = lrintf(av_clipf(65535.0f * rdpx(src[i*4+0]), 0.0f, 65535.0f)); + int g = lrintf(av_clipf(65535.0f * rdpx(src[i*4+1]), 0.0f, 65535.0f)); + int b = lrintf(av_clipf(65535.0f * rdpx(src[i*4+2]), 0.0f, 65535.0f)); + + dst[i] = (ry*r + gy*g + by*b + (0x2001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + } +} + +static av_always_inline void rgbaf16ToA_endian(uint16_t *dst, const uint16_t *src, int is_be, + int width, Half2FloatTables *h2f_tbl) +{ + int i; + for (i=0; i<width; i++) { + dst[i] = lrintf(av_clipf(65535.0f * rdpx(src[i*4+3]), 0.0f, 65535.0f)); + } +} + +static av_always_inline void rgbf16ToUV_half_endian(uint16_t *dstU, uint16_t *dstV, int is_be, + const uint16_t *src, int width, + int32_t *rgb2yuv, Half2FloatTables *h2f_tbl) +{ + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + int i; + for (i = 0; i < width; i++) { + int r = (lrintf(av_clipf(65535.0f * rdpx(src[i*6+0]), 0.0f, 65535.0f)) + + lrintf(av_clipf(65535.0f * rdpx(src[i*6+3]), 0.0f, 65535.0f))) >> 1; + int g = (lrintf(av_clipf(65535.0f * rdpx(src[i*6+1]), 0.0f, 65535.0f)) + + lrintf(av_clipf(65535.0f * rdpx(src[i*6+4]), 0.0f, 65535.0f))) >> 1; + int b = (lrintf(av_clipf(65535.0f * rdpx(src[i*6+2]), 0.0f, 65535.0f)) + + lrintf(av_clipf(65535.0f * rdpx(src[i*6+5]), 0.0f, 65535.0f))) >> 1; + + dstU[i] = (ru*r + gu*g + bu*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + dstV[i] = (rv*r + gv*g + bv*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + } +} + +static av_always_inline void rgbf16ToUV_endian(uint16_t *dstU, uint16_t *dstV, int is_be, + const uint16_t *src, int width, + int32_t *rgb2yuv, Half2FloatTables *h2f_tbl) +{ + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + int i; + for (i = 0; i < width; i++) { + int r = lrintf(av_clipf(65535.0f * rdpx(src[i*3+0]), 0.0f, 65535.0f)); + int g = lrintf(av_clipf(65535.0f * rdpx(src[i*3+1]), 0.0f, 65535.0f)); + int b = lrintf(av_clipf(65535.0f * rdpx(src[i*3+2]), 0.0f, 65535.0f)); + + dstU[i] = (ru*r + gu*g + bu*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + dstV[i] = (rv*r + gv*g + bv*b + (0x10001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + } +} + +static av_always_inline void rgbf16ToY_endian(uint16_t *dst, const uint16_t *src, int is_be, + int width, int32_t *rgb2yuv, Half2FloatTables *h2f_tbl) +{ + int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX]; + int i; + for (i = 0; i < width; i++) { + int r = lrintf(av_clipf(65535.0f * rdpx(src[i*3+0]), 0.0f, 65535.0f)); + int g = lrintf(av_clipf(65535.0f * rdpx(src[i*3+1]), 0.0f, 65535.0f)); + int b = lrintf(av_clipf(65535.0f * rdpx(src[i*3+2]), 0.0f, 65535.0f)); + + dst[i] = (ry*r + gy*g + by*b + (0x2001<<(RGB2YUV_SHIFT-1))) >> RGB2YUV_SHIFT; + } +} + +#undef rdpx + +#define rgbaf16_funcs_endian(endian_name, endian) \ +static void planar_rgbf16##endian_name##_to_y(uint8_t *dst, const uint8_t *src[4], \ + int w, int32_t *rgb2yuv, void *opq) \ +{ \ + planar_rgbf16_to_y(dst, src, w, endian, rgb2yuv, opq); \ +} \ +static void planar_rgbf16##endian_name##_to_uv(uint8_t *dstU, uint8_t *dstV, \ + const uint8_t *src[4], int w, int32_t *rgb2yuv, \ + void *opq) \ +{ \ + planar_rgbf16_to_uv(dstU, dstV, src, w, endian, rgb2yuv, opq); \ +} \ +static void planar_rgbf16##endian_name##_to_a(uint8_t *dst, const uint8_t *src[4], \ + int w, int32_t *rgb2yuv, void *opq) \ +{ \ + planar_rgbf16_to_a(dst, src, w, endian, rgb2yuv, opq); \ +} \ +static void grayf16##endian_name##ToY16_c(uint8_t *dst, const uint8_t *src, \ + const uint8_t *unused1, const uint8_t *unused2, \ + int width, uint32_t *unused, void *opq) \ +{ \ + grayf16ToY16_c(dst, src, unused1, unused2, width, endian, unused, opq); \ +} \ +static void read_yaf16##endian_name##_gray_c(uint8_t *dst, const uint8_t *src, \ + const uint8_t *unused1, const uint8_t *unused2, \ + int width, uint32_t *unused, void *opq) \ +{ \ + read_yaf16_gray_c(dst, src, unused1, unused2, width, endian, unused, opq); \ +} \ +static void read_yaf16##endian_name##_alpha_c(uint8_t *dst, const uint8_t *src, \ + const uint8_t *unused1, const uint8_t *unused2, \ + int width, uint32_t *unused, void *opq) \ +{ \ + read_yaf16_alpha_c(dst, src, unused1, unused2, width, endian, unused, opq); \ +} \ + \ +static void rgbaf16##endian_name##ToUV_half_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused, \ + const uint8_t *src1, const uint8_t *src2, \ + int width, uint32_t *_rgb2yuv, void *opq) \ +{ \ + const uint16_t *src = (const uint16_t*)src1; \ + uint16_t *dstU = (uint16_t*)_dstU; \ + uint16_t *dstV = (uint16_t*)_dstV; \ + int32_t *rgb2yuv = (int32_t*)_rgb2yuv; \ + av_assert1(src1==src2); \ + rgbaf16ToUV_half_endian(dstU, dstV, endian, src, width, rgb2yuv, opq); \ +} \ +static void rgbaf16##endian_name##ToUV_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused, \ + const uint8_t *src1, const uint8_t *src2, \ + int width, uint32_t *_rgb2yuv, void *opq) \ +{ \ + const uint16_t *src = (const uint16_t*)src1; \ + uint16_t *dstU = (uint16_t*)_dstU; \ + uint16_t *dstV = (uint16_t*)_dstV; \ + int32_t *rgb2yuv = (int32_t*)_rgb2yuv; \ + av_assert1(src1==src2); \ + rgbaf16ToUV_endian(dstU, dstV, endian, src, width, rgb2yuv, opq); \ +} \ +static void rgbaf16##endian_name##ToY_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused0, \ + const uint8_t *unused1, int width, uint32_t *_rgb2yuv, void *opq) \ +{ \ + const uint16_t *src = (const uint16_t*)_src; \ + uint16_t *dst = (uint16_t*)_dst; \ + int32_t *rgb2yuv = (int32_t*)_rgb2yuv; \ + rgbaf16ToY_endian(dst, src, endian, width, rgb2yuv, opq); \ +} \ +static void rgbaf16##endian_name##ToA_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused0, \ + const uint8_t *unused1, int width, uint32_t *unused2, void *opq) \ +{ \ + const uint16_t *src = (const uint16_t*)_src; \ + uint16_t *dst = (uint16_t*)_dst; \ + rgbaf16ToA_endian(dst, src, endian, width, opq); \ +} \ +static void rgbf16##endian_name##ToUV_half_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused, \ + const uint8_t *src1, const uint8_t *src2, \ + int width, uint32_t *_rgb2yuv, void *opq) \ +{ \ + const uint16_t *src = (const uint16_t*)src1; \ + uint16_t *dstU = (uint16_t*)_dstU; \ + uint16_t *dstV = (uint16_t*)_dstV; \ + int32_t *rgb2yuv = (int32_t*)_rgb2yuv; \ + av_assert1(src1==src2); \ + rgbf16ToUV_half_endian(dstU, dstV, endian, src, width, rgb2yuv, opq); \ +} \ +static void rgbf16##endian_name##ToUV_c(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *unused, \ + const uint8_t *src1, const uint8_t *src2, \ + int width, uint32_t *_rgb2yuv, void *opq) \ +{ \ + const uint16_t *src = (const uint16_t*)src1; \ + uint16_t *dstU = (uint16_t*)_dstU; \ + uint16_t *dstV = (uint16_t*)_dstV; \ + int32_t *rgb2yuv = (int32_t*)_rgb2yuv; \ + av_assert1(src1==src2); \ + rgbf16ToUV_endian(dstU, dstV, endian, src, width, rgb2yuv, opq); \ +} \ +static void rgbf16##endian_name##ToY_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused0, \ + const uint8_t *unused1, int width, uint32_t *_rgb2yuv, void *opq) \ +{ \ + const uint16_t *src = (const uint16_t*)_src; \ + uint16_t *dst = (uint16_t*)_dst; \ + int32_t *rgb2yuv = (int32_t*)_rgb2yuv; \ + rgbf16ToY_endian(dst, src, endian, width, rgb2yuv, opq); \ +} \ + +rgbaf16_funcs_endian(le, 0) +rgbaf16_funcs_endian(be, 1) + +av_cold void ff_sws_init_input_funcs(SwsInternal *c, + planar1_YV12_fn *lumToYV12, + planar1_YV12_fn *alpToYV12, + planar2_YV12_fn *chrToYV12, + planarX_YV12_fn *readLumPlanar, + planarX_YV12_fn *readAlpPlanar, + planarX2_YV12_fn *readChrPlanar) +{ + enum AVPixelFormat srcFormat = c->opts.src_format; + + *chrToYV12 = NULL; + switch (srcFormat) { + case AV_PIX_FMT_YUYV422: + *chrToYV12 = yuy2ToUV_c; + break; + case AV_PIX_FMT_YVYU422: + *chrToYV12 = yvy2ToUV_c; + break; + case AV_PIX_FMT_UYVY422: + *chrToYV12 = uyvyToUV_c; + break; + case AV_PIX_FMT_UYYVYY411: + *chrToYV12 = uyyvyyToUV_c; + break; + case AV_PIX_FMT_VYU444: + *chrToYV12 = vyuToUV_c; + break; + case AV_PIX_FMT_NV12: + case AV_PIX_FMT_NV16: + case AV_PIX_FMT_NV24: + *chrToYV12 = nv12ToUV_c; + break; + case AV_PIX_FMT_NV21: + case AV_PIX_FMT_NV42: + *chrToYV12 = nv21ToUV_c; + break; + case AV_PIX_FMT_RGB8: + case AV_PIX_FMT_BGR8: + case AV_PIX_FMT_PAL8: + case AV_PIX_FMT_BGR4_BYTE: + case AV_PIX_FMT_RGB4_BYTE: + *chrToYV12 = palToUV_c; + break; + case AV_PIX_FMT_GBRP9LE: + *readChrPlanar = planar_rgb9le_to_uv; + break; + case AV_PIX_FMT_GBRAP10LE: + case AV_PIX_FMT_GBRP10LE: + *readChrPlanar = planar_rgb10le_to_uv; + break; + case AV_PIX_FMT_GBRAP12LE: + case AV_PIX_FMT_GBRP12LE: + *readChrPlanar = planar_rgb12le_to_uv; + break; + case AV_PIX_FMT_GBRAP14LE: + case AV_PIX_FMT_GBRP14LE: + *readChrPlanar = planar_rgb14le_to_uv; + break; + case AV_PIX_FMT_GBRAP16LE: + case AV_PIX_FMT_GBRP16LE: + *readChrPlanar = planar_rgb16le_to_uv; + break; + case AV_PIX_FMT_GBRAPF32LE: + case AV_PIX_FMT_GBRPF32LE: + *readChrPlanar = planar_rgbf32le_to_uv; + break; + case AV_PIX_FMT_GBRAPF16LE: + case AV_PIX_FMT_GBRPF16LE: + *readChrPlanar = planar_rgbf16le_to_uv; + break; + case AV_PIX_FMT_GBRP10MSBLE: + *readChrPlanar = msb_planar_rgb10le_to_uv; + break; + case AV_PIX_FMT_GBRP12MSBLE: + *readChrPlanar = msb_planar_rgb12le_to_uv; + break; + case AV_PIX_FMT_GBRP9BE: + *readChrPlanar = planar_rgb9be_to_uv; + break; + case AV_PIX_FMT_GBRAP10BE: + case AV_PIX_FMT_GBRP10BE: + *readChrPlanar = planar_rgb10be_to_uv; + break; + case AV_PIX_FMT_GBRAP12BE: + case AV_PIX_FMT_GBRP12BE: + *readChrPlanar = planar_rgb12be_to_uv; + break; + case AV_PIX_FMT_GBRAP14BE: + case AV_PIX_FMT_GBRP14BE: + *readChrPlanar = planar_rgb14be_to_uv; + break; + case AV_PIX_FMT_GBRAP16BE: + case AV_PIX_FMT_GBRP16BE: + *readChrPlanar = planar_rgb16be_to_uv; + break; + case AV_PIX_FMT_GBRAPF32BE: + case AV_PIX_FMT_GBRPF32BE: + *readChrPlanar = planar_rgbf32be_to_uv; + break; + case AV_PIX_FMT_GBRAPF16BE: + case AV_PIX_FMT_GBRPF16BE: + *readChrPlanar = planar_rgbf16be_to_uv; + break; + case AV_PIX_FMT_GBRP10MSBBE: + *readChrPlanar = msb_planar_rgb10be_to_uv; + break; + case AV_PIX_FMT_GBRP12MSBBE: + *readChrPlanar = msb_planar_rgb12be_to_uv; + break; + case AV_PIX_FMT_GBRAP: + case AV_PIX_FMT_GBRP: + *readChrPlanar = planar_rgb_to_uv; + break; +#if HAVE_BIGENDIAN + case AV_PIX_FMT_YUV420P9LE: + case AV_PIX_FMT_YUV422P9LE: + case AV_PIX_FMT_YUV444P9LE: + case AV_PIX_FMT_YUV420P10LE: + case AV_PIX_FMT_YUV422P10LE: + case AV_PIX_FMT_YUV440P10LE: + case AV_PIX_FMT_YUV444P10LE: + case AV_PIX_FMT_YUV420P12LE: + case AV_PIX_FMT_YUV422P12LE: + case AV_PIX_FMT_YUV440P12LE: + case AV_PIX_FMT_YUV444P12LE: + case AV_PIX_FMT_YUV420P14LE: + case AV_PIX_FMT_YUV422P14LE: + case AV_PIX_FMT_YUV444P14LE: + case AV_PIX_FMT_YUV420P16LE: + case AV_PIX_FMT_YUV422P16LE: + case AV_PIX_FMT_YUV444P16LE: + + case AV_PIX_FMT_YUVA420P9LE: + case AV_PIX_FMT_YUVA422P9LE: + case AV_PIX_FMT_YUVA444P9LE: + case AV_PIX_FMT_YUVA420P10LE: + case AV_PIX_FMT_YUVA422P10LE: + case AV_PIX_FMT_YUVA444P10LE: + case AV_PIX_FMT_YUVA422P12LE: + case AV_PIX_FMT_YUVA444P12LE: + case AV_PIX_FMT_YUVA420P16LE: + case AV_PIX_FMT_YUVA422P16LE: + case AV_PIX_FMT_YUVA444P16LE: + *chrToYV12 = bswap16UV_c; + break; +#else + case AV_PIX_FMT_YUV420P9BE: + case AV_PIX_FMT_YUV422P9BE: + case AV_PIX_FMT_YUV444P9BE: + case AV_PIX_FMT_YUV420P10BE: + case AV_PIX_FMT_YUV422P10BE: + case AV_PIX_FMT_YUV440P10BE: + case AV_PIX_FMT_YUV444P10BE: + case AV_PIX_FMT_YUV420P12BE: + case AV_PIX_FMT_YUV422P12BE: + case AV_PIX_FMT_YUV440P12BE: + case AV_PIX_FMT_YUV444P12BE: + case AV_PIX_FMT_YUV420P14BE: + case AV_PIX_FMT_YUV422P14BE: + case AV_PIX_FMT_YUV444P14BE: + case AV_PIX_FMT_YUV420P16BE: + case AV_PIX_FMT_YUV422P16BE: + case AV_PIX_FMT_YUV444P16BE: + + case AV_PIX_FMT_YUVA420P9BE: + case AV_PIX_FMT_YUVA422P9BE: + case AV_PIX_FMT_YUVA444P9BE: + case AV_PIX_FMT_YUVA420P10BE: + case AV_PIX_FMT_YUVA422P10BE: + case AV_PIX_FMT_YUVA444P10BE: + case AV_PIX_FMT_YUVA422P12BE: + case AV_PIX_FMT_YUVA444P12BE: + case AV_PIX_FMT_YUVA420P16BE: + case AV_PIX_FMT_YUVA422P16BE: + case AV_PIX_FMT_YUVA444P16BE: + *chrToYV12 = bswap16UV_c; + break; +#endif + case AV_PIX_FMT_YUV444P10MSBLE: + *chrToYV12 = shf16_10LEToUV_c; + break; + case AV_PIX_FMT_YUV444P12MSBLE: + *chrToYV12 = shf16_12LEToUV_c; + break; + case AV_PIX_FMT_YUV444P10MSBBE: + *chrToYV12 = shf16_10BEToUV_c; + break; + case AV_PIX_FMT_YUV444P12MSBBE: + *chrToYV12 = shf16_12BEToUV_c; + break; + case AV_PIX_FMT_VUYA: + case AV_PIX_FMT_VUYX: + *chrToYV12 = read_vuyx_UV_c; + break; + case AV_PIX_FMT_XV30LE: + *chrToYV12 = read_xv30le_UV_c; + break; + case AV_PIX_FMT_V30XLE: + *chrToYV12 = read_v30xle_UV_c; + break; + case AV_PIX_FMT_AYUV: + *chrToYV12 = read_ayuv_UV_c; + break; + case AV_PIX_FMT_AYUV64LE: + *chrToYV12 = read_ayuv64le_UV_c; + break; + case AV_PIX_FMT_AYUV64BE: + *chrToYV12 = read_ayuv64be_UV_c; + break; + case AV_PIX_FMT_UYVA: + *chrToYV12 = read_uyva_UV_c; + break; + case AV_PIX_FMT_XV36LE: + *chrToYV12 = read_xv36le_UV_c; + break; + case AV_PIX_FMT_XV36BE: + *chrToYV12 = read_xv36be_UV_c; + break; + case AV_PIX_FMT_XV48LE: + *chrToYV12 = read_xv48le_UV_c; + break; + case AV_PIX_FMT_XV48BE: + *chrToYV12 = read_xv48be_UV_c; + break; + case AV_PIX_FMT_NV20LE: + *chrToYV12 = nv20LEToUV_c; + break; + case AV_PIX_FMT_P010LE: + case AV_PIX_FMT_P210LE: + case AV_PIX_FMT_P410LE: + *chrToYV12 = p010LEToUV_c; + break; + case AV_PIX_FMT_NV20BE: + *chrToYV12 = nv20BEToUV_c; + break; + case AV_PIX_FMT_P010BE: + case AV_PIX_FMT_P210BE: + case AV_PIX_FMT_P410BE: + *chrToYV12 = p010BEToUV_c; + break; + case AV_PIX_FMT_P012LE: + case AV_PIX_FMT_P212LE: + case AV_PIX_FMT_P412LE: + *chrToYV12 = p012LEToUV_c; + break; + case AV_PIX_FMT_P012BE: + case AV_PIX_FMT_P212BE: + case AV_PIX_FMT_P412BE: + *chrToYV12 = p012BEToUV_c; + break; + case AV_PIX_FMT_P016LE: + case AV_PIX_FMT_P216LE: + case AV_PIX_FMT_P416LE: + *chrToYV12 = p016LEToUV_c; + break; + case AV_PIX_FMT_P016BE: + case AV_PIX_FMT_P216BE: + case AV_PIX_FMT_P416BE: + *chrToYV12 = p016BEToUV_c; + break; + case AV_PIX_FMT_Y210LE: + *chrToYV12 = y210le_UV_c; + break; + case AV_PIX_FMT_Y212LE: + *chrToYV12 = y212le_UV_c; + break; + case AV_PIX_FMT_Y216LE: + *chrToYV12 = y216le_UV_c; + break; + case AV_PIX_FMT_RGBF32LE: + *chrToYV12 = rgbf32le_to_uv_c; + break; + case AV_PIX_FMT_RGBF32BE: + *chrToYV12 = rgbf32be_to_uv_c; + break; + } + if (c->chrSrcHSubSample) { + switch (srcFormat) { + case AV_PIX_FMT_RGBA64BE: + *chrToYV12 = rgb64BEToUV_half_c; + break; + case AV_PIX_FMT_RGBA64LE: + *chrToYV12 = rgb64LEToUV_half_c; + break; + case AV_PIX_FMT_BGRA64BE: + *chrToYV12 = bgr64BEToUV_half_c; + break; + case AV_PIX_FMT_BGRA64LE: + *chrToYV12 = bgr64LEToUV_half_c; + break; + case AV_PIX_FMT_RGB48BE: + *chrToYV12 = rgb48BEToUV_half_c; + break; + case AV_PIX_FMT_RGB48LE: + *chrToYV12 = rgb48LEToUV_half_c; + break; + case AV_PIX_FMT_BGR48BE: + *chrToYV12 = bgr48BEToUV_half_c; + break; + case AV_PIX_FMT_BGR48LE: + *chrToYV12 = bgr48LEToUV_half_c; + break; + case AV_PIX_FMT_RGB32: + *chrToYV12 = bgr32ToUV_half_c; + break; + case AV_PIX_FMT_RGB32_1: + *chrToYV12 = bgr321ToUV_half_c; + break; + case AV_PIX_FMT_BGR24: + *chrToYV12 = bgr24ToUV_half_c; + break; + case AV_PIX_FMT_BGR565LE: + *chrToYV12 = bgr16leToUV_half_c; + break; + case AV_PIX_FMT_BGR565BE: + *chrToYV12 = bgr16beToUV_half_c; + break; + case AV_PIX_FMT_BGR555LE: + *chrToYV12 = bgr15leToUV_half_c; + break; + case AV_PIX_FMT_BGR555BE: + *chrToYV12 = bgr15beToUV_half_c; + break; + case AV_PIX_FMT_GBRAP: + case AV_PIX_FMT_GBRP: + *chrToYV12 = gbr24pToUV_half_c; + break; + case AV_PIX_FMT_BGR444LE: + *chrToYV12 = bgr12leToUV_half_c; + break; + case AV_PIX_FMT_BGR444BE: + *chrToYV12 = bgr12beToUV_half_c; + break; + case AV_PIX_FMT_BGR32: + *chrToYV12 = rgb32ToUV_half_c; + break; + case AV_PIX_FMT_BGR32_1: + *chrToYV12 = rgb321ToUV_half_c; + break; + case AV_PIX_FMT_RGB24: + *chrToYV12 = rgb24ToUV_half_c; + break; + case AV_PIX_FMT_RGB565LE: + *chrToYV12 = rgb16leToUV_half_c; + break; + case AV_PIX_FMT_RGB565BE: + *chrToYV12 = rgb16beToUV_half_c; + break; + case AV_PIX_FMT_RGB555LE: + *chrToYV12 = rgb15leToUV_half_c; + break; + case AV_PIX_FMT_RGB555BE: + *chrToYV12 = rgb15beToUV_half_c; + break; + case AV_PIX_FMT_RGB444LE: + *chrToYV12 = rgb12leToUV_half_c; + break; + case AV_PIX_FMT_RGB444BE: + *chrToYV12 = rgb12beToUV_half_c; + break; + case AV_PIX_FMT_X2RGB10LE: + *chrToYV12 = rgb30leToUV_half_c; + break; + case AV_PIX_FMT_X2BGR10LE: + *chrToYV12 = bgr30leToUV_half_c; + break; + case AV_PIX_FMT_RGBAF16BE: + *chrToYV12 = rgbaf16beToUV_half_c; + break; + case AV_PIX_FMT_RGBAF16LE: + *chrToYV12 = rgbaf16leToUV_half_c; + break; + case AV_PIX_FMT_RGBF16BE: + *chrToYV12 = rgbf16beToUV_half_c; + break; + case AV_PIX_FMT_RGBF16LE: + *chrToYV12 = rgbf16leToUV_half_c; + break; + } + } else { + switch (srcFormat) { + case AV_PIX_FMT_RGBA64BE: + *chrToYV12 = rgb64BEToUV_c; + break; + case AV_PIX_FMT_RGBA64LE: + *chrToYV12 = rgb64LEToUV_c; + break; + case AV_PIX_FMT_BGRA64BE: + *chrToYV12 = bgr64BEToUV_c; + break; + case AV_PIX_FMT_BGRA64LE: + *chrToYV12 = bgr64LEToUV_c; + break; + case AV_PIX_FMT_RGB48BE: + *chrToYV12 = rgb48BEToUV_c; + break; + case AV_PIX_FMT_RGB48LE: + *chrToYV12 = rgb48LEToUV_c; + break; + case AV_PIX_FMT_BGR48BE: + *chrToYV12 = bgr48BEToUV_c; + break; + case AV_PIX_FMT_BGR48LE: + *chrToYV12 = bgr48LEToUV_c; + break; + case AV_PIX_FMT_RGB32: + *chrToYV12 = bgr32ToUV_c; + break; + case AV_PIX_FMT_RGB32_1: + *chrToYV12 = bgr321ToUV_c; + break; + case AV_PIX_FMT_BGR24: + *chrToYV12 = bgr24ToUV_c; + break; + case AV_PIX_FMT_BGR565LE: + *chrToYV12 = bgr16leToUV_c; + break; + case AV_PIX_FMT_BGR565BE: + *chrToYV12 = bgr16beToUV_c; + break; + case AV_PIX_FMT_BGR555LE: + *chrToYV12 = bgr15leToUV_c; + break; + case AV_PIX_FMT_BGR555BE: + *chrToYV12 = bgr15beToUV_c; + break; + case AV_PIX_FMT_BGR444LE: + *chrToYV12 = bgr12leToUV_c; + break; + case AV_PIX_FMT_BGR444BE: + *chrToYV12 = bgr12beToUV_c; + break; + case AV_PIX_FMT_BGR32: + *chrToYV12 = rgb32ToUV_c; + break; + case AV_PIX_FMT_BGR32_1: + *chrToYV12 = rgb321ToUV_c; + break; + case AV_PIX_FMT_RGB24: + *chrToYV12 = rgb24ToUV_c; + break; + case AV_PIX_FMT_RGB565LE: + *chrToYV12 = rgb16leToUV_c; + break; + case AV_PIX_FMT_RGB565BE: + *chrToYV12 = rgb16beToUV_c; + break; + case AV_PIX_FMT_RGB555LE: + *chrToYV12 = rgb15leToUV_c; + break; + case AV_PIX_FMT_RGB555BE: + *chrToYV12 = rgb15beToUV_c; + break; + case AV_PIX_FMT_RGB444LE: + *chrToYV12 = rgb12leToUV_c; + break; + case AV_PIX_FMT_RGB444BE: + *chrToYV12 = rgb12beToUV_c; + break; + case AV_PIX_FMT_X2RGB10LE: + *chrToYV12 = rgb30leToUV_c; + break; + case AV_PIX_FMT_X2BGR10LE: + *chrToYV12 = bgr30leToUV_c; + break; + case AV_PIX_FMT_RGBAF16BE: + *chrToYV12 = rgbaf16beToUV_c; + break; + case AV_PIX_FMT_RGBAF16LE: + *chrToYV12 = rgbaf16leToUV_c; + break; + case AV_PIX_FMT_RGBF16BE: + *chrToYV12 = rgbf16beToUV_c; + break; + case AV_PIX_FMT_RGBF16LE: + *chrToYV12 = rgbf16leToUV_c; + break; + } + } + + *lumToYV12 = NULL; + *alpToYV12 = NULL; + switch (srcFormat) { + case AV_PIX_FMT_GBRP9LE: + *readLumPlanar = planar_rgb9le_to_y; + break; + case AV_PIX_FMT_GBRAP10LE: + *readAlpPlanar = planar_rgb10le_to_a; + case AV_PIX_FMT_GBRP10LE: + *readLumPlanar = planar_rgb10le_to_y; + break; + case AV_PIX_FMT_GBRAP12LE: + *readAlpPlanar = planar_rgb12le_to_a; + case AV_PIX_FMT_GBRP12LE: + *readLumPlanar = planar_rgb12le_to_y; + break; + case AV_PIX_FMT_GBRAP14LE: + *readAlpPlanar = planar_rgb14le_to_a; + case AV_PIX_FMT_GBRP14LE: + *readLumPlanar = planar_rgb14le_to_y; + break; + case AV_PIX_FMT_GBRAP16LE: + *readAlpPlanar = planar_rgb16le_to_a; + case AV_PIX_FMT_GBRP16LE: + *readLumPlanar = planar_rgb16le_to_y; + break; + case AV_PIX_FMT_GBRAPF32LE: + *readAlpPlanar = planar_rgbf32le_to_a; + case AV_PIX_FMT_GBRPF32LE: + *readLumPlanar = planar_rgbf32le_to_y; + break; + case AV_PIX_FMT_GBRAPF16LE: + *readAlpPlanar = planar_rgbf16le_to_a; + case AV_PIX_FMT_GBRPF16LE: + *readLumPlanar = planar_rgbf16le_to_y; + break; + case AV_PIX_FMT_GBRP10MSBLE: + *readLumPlanar = msb_planar_rgb10le_to_y; + break; + case AV_PIX_FMT_GBRP12MSBLE: + *readLumPlanar = msb_planar_rgb12le_to_y; + break; + case AV_PIX_FMT_GBRP9BE: + *readLumPlanar = planar_rgb9be_to_y; + break; + case AV_PIX_FMT_GBRAP10BE: + *readAlpPlanar = planar_rgb10be_to_a; + case AV_PIX_FMT_GBRP10BE: + *readLumPlanar = planar_rgb10be_to_y; + break; + case AV_PIX_FMT_GBRAP12BE: + *readAlpPlanar = planar_rgb12be_to_a; + case AV_PIX_FMT_GBRP12BE: + *readLumPlanar = planar_rgb12be_to_y; + break; + case AV_PIX_FMT_GBRAP14BE: + *readAlpPlanar = planar_rgb14be_to_a; + case AV_PIX_FMT_GBRP14BE: + *readLumPlanar = planar_rgb14be_to_y; + break; + case AV_PIX_FMT_GBRAP16BE: + *readAlpPlanar = planar_rgb16be_to_a; + case AV_PIX_FMT_GBRP16BE: + *readLumPlanar = planar_rgb16be_to_y; + break; + case AV_PIX_FMT_GBRAPF32BE: + *readAlpPlanar = planar_rgbf32be_to_a; + case AV_PIX_FMT_GBRPF32BE: + *readLumPlanar = planar_rgbf32be_to_y; + break; + case AV_PIX_FMT_GBRAPF16BE: + *readAlpPlanar = planar_rgbf16be_to_a; + case AV_PIX_FMT_GBRPF16BE: + *readLumPlanar = planar_rgbf16be_to_y; + break; + case AV_PIX_FMT_GBRP10MSBBE: + *readLumPlanar = msb_planar_rgb10be_to_y; + break; + case AV_PIX_FMT_GBRP12MSBBE: + *readLumPlanar = msb_planar_rgb12be_to_y; + break; + case AV_PIX_FMT_GBRAP: + *readAlpPlanar = planar_rgb_to_a; + case AV_PIX_FMT_GBRP: + *readLumPlanar = planar_rgb_to_y; + break; +#if HAVE_BIGENDIAN + case AV_PIX_FMT_YUV420P9LE: + case AV_PIX_FMT_YUV422P9LE: + case AV_PIX_FMT_YUV444P9LE: + case AV_PIX_FMT_YUV420P10LE: + case AV_PIX_FMT_YUV422P10LE: + case AV_PIX_FMT_YUV440P10LE: + case AV_PIX_FMT_YUV444P10LE: + case AV_PIX_FMT_YUV420P12LE: + case AV_PIX_FMT_YUV422P12LE: + case AV_PIX_FMT_YUV440P12LE: + case AV_PIX_FMT_YUV444P12LE: + case AV_PIX_FMT_YUV420P14LE: + case AV_PIX_FMT_YUV422P14LE: + case AV_PIX_FMT_YUV444P14LE: + case AV_PIX_FMT_YUV420P16LE: + case AV_PIX_FMT_YUV422P16LE: + case AV_PIX_FMT_YUV444P16LE: + + case AV_PIX_FMT_GRAY9LE: + case AV_PIX_FMT_GRAY10LE: + case AV_PIX_FMT_GRAY12LE: + case AV_PIX_FMT_GRAY14LE: + case AV_PIX_FMT_GRAY16LE: + + case AV_PIX_FMT_P016LE: + case AV_PIX_FMT_P216LE: + case AV_PIX_FMT_P416LE: + *lumToYV12 = bswap16Y_c; + break; + case AV_PIX_FMT_YUVA420P9LE: + case AV_PIX_FMT_YUVA422P9LE: + case AV_PIX_FMT_YUVA444P9LE: + case AV_PIX_FMT_YUVA420P10LE: + case AV_PIX_FMT_YUVA422P10LE: + case AV_PIX_FMT_YUVA444P10LE: + case AV_PIX_FMT_YUVA422P12LE: + case AV_PIX_FMT_YUVA444P12LE: + case AV_PIX_FMT_YUVA420P16LE: + case AV_PIX_FMT_YUVA422P16LE: + case AV_PIX_FMT_YUVA444P16LE: + *lumToYV12 = bswap16Y_c; + *alpToYV12 = bswap16Y_c; + break; +#else + case AV_PIX_FMT_YUV420P9BE: + case AV_PIX_FMT_YUV422P9BE: + case AV_PIX_FMT_YUV444P9BE: + case AV_PIX_FMT_YUV420P10BE: + case AV_PIX_FMT_YUV422P10BE: + case AV_PIX_FMT_YUV440P10BE: + case AV_PIX_FMT_YUV444P10BE: + case AV_PIX_FMT_YUV420P12BE: + case AV_PIX_FMT_YUV422P12BE: + case AV_PIX_FMT_YUV440P12BE: + case AV_PIX_FMT_YUV444P12BE: + case AV_PIX_FMT_YUV420P14BE: + case AV_PIX_FMT_YUV422P14BE: + case AV_PIX_FMT_YUV444P14BE: + case AV_PIX_FMT_YUV420P16BE: + case AV_PIX_FMT_YUV422P16BE: + case AV_PIX_FMT_YUV444P16BE: + + case AV_PIX_FMT_GRAY9BE: + case AV_PIX_FMT_GRAY10BE: + case AV_PIX_FMT_GRAY12BE: + case AV_PIX_FMT_GRAY14BE: + case AV_PIX_FMT_GRAY16BE: + + case AV_PIX_FMT_P016BE: + case AV_PIX_FMT_P216BE: + case AV_PIX_FMT_P416BE: + *lumToYV12 = bswap16Y_c; + break; + case AV_PIX_FMT_YUVA420P9BE: + case AV_PIX_FMT_YUVA422P9BE: + case AV_PIX_FMT_YUVA444P9BE: + case AV_PIX_FMT_YUVA420P10BE: + case AV_PIX_FMT_YUVA422P10BE: + case AV_PIX_FMT_YUVA444P10BE: + case AV_PIX_FMT_YUVA422P12BE: + case AV_PIX_FMT_YUVA444P12BE: + case AV_PIX_FMT_YUVA420P16BE: + case AV_PIX_FMT_YUVA422P16BE: + case AV_PIX_FMT_YUVA444P16BE: + *lumToYV12 = bswap16Y_c; + *alpToYV12 = bswap16Y_c; + break; +#endif + case AV_PIX_FMT_YUV444P10MSBLE: + *lumToYV12 = shf16_10LEToY_c; + break; + case AV_PIX_FMT_YUV444P12MSBLE: + *lumToYV12 = shf16_12LEToY_c; + break; + case AV_PIX_FMT_YUV444P10MSBBE: + *lumToYV12 = shf16_10BEToY_c; + break; + case AV_PIX_FMT_YUV444P12MSBBE: + *lumToYV12 = shf16_12BEToY_c; + break; + case AV_PIX_FMT_YA16LE: + *lumToYV12 = read_ya16le_gray_c; + break; + case AV_PIX_FMT_YA16BE: + *lumToYV12 = read_ya16be_gray_c; + break; + case AV_PIX_FMT_YAF16LE: + *lumToYV12 = read_yaf16le_gray_c; + break; + case AV_PIX_FMT_YAF16BE: + *lumToYV12 = read_yaf16be_gray_c; + break; + case AV_PIX_FMT_VUYA: + case AV_PIX_FMT_VUYX: + *lumToYV12 = read_vuyx_Y_c; + break; + case AV_PIX_FMT_XV30LE: + *lumToYV12 = read_xv30le_Y_c; + break; + case AV_PIX_FMT_V30XLE: + *lumToYV12 = read_v30xle_Y_c; + break; + case AV_PIX_FMT_AYUV: + case AV_PIX_FMT_UYVA: + *lumToYV12 = read_ayuv_Y_c; + break; + case AV_PIX_FMT_AYUV64LE: + case AV_PIX_FMT_XV48LE: + *lumToYV12 = read_ayuv64le_Y_c; + break; + case AV_PIX_FMT_AYUV64BE: + case AV_PIX_FMT_XV48BE: + *lumToYV12 = read_ayuv64be_Y_c; + break; + case AV_PIX_FMT_XV36LE: + *lumToYV12 = read_xv36le_Y_c; + break; + case AV_PIX_FMT_XV36BE: + *lumToYV12 = read_xv36be_Y_c; + break; + case AV_PIX_FMT_YUYV422: + case AV_PIX_FMT_YVYU422: + case AV_PIX_FMT_YA8: + *lumToYV12 = yuy2ToY_c; + break; + case AV_PIX_FMT_UYVY422: + *lumToYV12 = uyvyToY_c; + break; + case AV_PIX_FMT_UYYVYY411: + *lumToYV12 = uyyvyyToY_c; + break; + case AV_PIX_FMT_VYU444: + *lumToYV12 = vyuToY_c; + break; + case AV_PIX_FMT_BGR24: + *lumToYV12 = bgr24ToY_c; + break; + case AV_PIX_FMT_BGR565LE: + *lumToYV12 = bgr16leToY_c; + break; + case AV_PIX_FMT_BGR565BE: + *lumToYV12 = bgr16beToY_c; + break; + case AV_PIX_FMT_BGR555LE: + *lumToYV12 = bgr15leToY_c; + break; + case AV_PIX_FMT_BGR555BE: + *lumToYV12 = bgr15beToY_c; + break; + case AV_PIX_FMT_BGR444LE: + *lumToYV12 = bgr12leToY_c; + break; + case AV_PIX_FMT_BGR444BE: + *lumToYV12 = bgr12beToY_c; + break; + case AV_PIX_FMT_RGB24: + *lumToYV12 = rgb24ToY_c; + break; + case AV_PIX_FMT_RGB565LE: + *lumToYV12 = rgb16leToY_c; + break; + case AV_PIX_FMT_RGB565BE: + *lumToYV12 = rgb16beToY_c; + break; + case AV_PIX_FMT_RGB555LE: + *lumToYV12 = rgb15leToY_c; + break; + case AV_PIX_FMT_RGB555BE: + *lumToYV12 = rgb15beToY_c; + break; + case AV_PIX_FMT_RGB444LE: + *lumToYV12 = rgb12leToY_c; + break; + case AV_PIX_FMT_RGB444BE: + *lumToYV12 = rgb12beToY_c; + break; + case AV_PIX_FMT_RGB8: + case AV_PIX_FMT_BGR8: + case AV_PIX_FMT_PAL8: + case AV_PIX_FMT_BGR4_BYTE: + case AV_PIX_FMT_RGB4_BYTE: + *lumToYV12 = palToY_c; + break; + case AV_PIX_FMT_MONOBLACK: + *lumToYV12 = monoblack2Y_c; + break; + case AV_PIX_FMT_MONOWHITE: + *lumToYV12 = monowhite2Y_c; + break; + case AV_PIX_FMT_RGB32: + *lumToYV12 = bgr32ToY_c; + break; + case AV_PIX_FMT_RGB32_1: + *lumToYV12 = bgr321ToY_c; + break; + case AV_PIX_FMT_BGR32: + *lumToYV12 = rgb32ToY_c; + break; + case AV_PIX_FMT_BGR32_1: + *lumToYV12 = rgb321ToY_c; + break; + case AV_PIX_FMT_RGB48BE: + *lumToYV12 = rgb48BEToY_c; + break; + case AV_PIX_FMT_RGB48LE: + *lumToYV12 = rgb48LEToY_c; + break; + case AV_PIX_FMT_BGR48BE: + *lumToYV12 = bgr48BEToY_c; + break; + case AV_PIX_FMT_BGR48LE: + *lumToYV12 = bgr48LEToY_c; + break; + case AV_PIX_FMT_RGBA64BE: + *lumToYV12 = rgb64BEToY_c; + break; + case AV_PIX_FMT_RGBA64LE: + *lumToYV12 = rgb64LEToY_c; + break; + case AV_PIX_FMT_BGRA64BE: + *lumToYV12 = bgr64BEToY_c; + break; + case AV_PIX_FMT_BGRA64LE: + *lumToYV12 = bgr64LEToY_c; + break; + case AV_PIX_FMT_NV20LE: + *lumToYV12 = nv20LEToY_c; + break; + case AV_PIX_FMT_P010LE: + case AV_PIX_FMT_P210LE: + case AV_PIX_FMT_P410LE: + *lumToYV12 = p010LEToY_c; + break; + case AV_PIX_FMT_NV20BE: + *lumToYV12 = nv20BEToY_c; + break; + case AV_PIX_FMT_P010BE: + case AV_PIX_FMT_P210BE: + case AV_PIX_FMT_P410BE: + *lumToYV12 = p010BEToY_c; + break; + case AV_PIX_FMT_P012LE: + case AV_PIX_FMT_P212LE: + case AV_PIX_FMT_P412LE: + *lumToYV12 = p012LEToY_c; + break; + case AV_PIX_FMT_P012BE: + case AV_PIX_FMT_P212BE: + case AV_PIX_FMT_P412BE: + *lumToYV12 = p012BEToY_c; + break; + case AV_PIX_FMT_GRAYF32LE: + *lumToYV12 = grayf32leToY16_c; + break; + case AV_PIX_FMT_GRAYF32BE: + *lumToYV12 = grayf32beToY16_c; + break; + case AV_PIX_FMT_YAF32LE: + *lumToYV12 = read_yaf32le_gray_c; + break; + case AV_PIX_FMT_YAF32BE: + *lumToYV12 = read_yaf32be_gray_c; + break; + case AV_PIX_FMT_GRAYF16LE: + *lumToYV12 = grayf16leToY16_c; + break; + case AV_PIX_FMT_GRAYF16BE: + *lumToYV12 = grayf16beToY16_c; + break; + case AV_PIX_FMT_Y210LE: + *lumToYV12 = y210le_Y_c; + break; + case AV_PIX_FMT_Y212LE: + *lumToYV12 = y212le_Y_c; + break; + case AV_PIX_FMT_Y216LE: + *lumToYV12 = y216le_Y_c; + break; + case AV_PIX_FMT_X2RGB10LE: + *lumToYV12 = rgb30leToY_c; + break; + case AV_PIX_FMT_X2BGR10LE: + *lumToYV12 = bgr30leToY_c; + break; + case AV_PIX_FMT_RGBAF16BE: + *lumToYV12 = rgbaf16beToY_c; + break; + case AV_PIX_FMT_RGBAF16LE: + *lumToYV12 = rgbaf16leToY_c; + break; + case AV_PIX_FMT_RGBF16BE: + *lumToYV12 = rgbf16beToY_c; + break; + case AV_PIX_FMT_RGBF16LE: + *lumToYV12 = rgbf16leToY_c; + break; + case AV_PIX_FMT_RGBF32LE: + *lumToYV12 = rgbf32le_to_y_c; + break; + case AV_PIX_FMT_RGBF32BE: + *lumToYV12 = rgbf32be_to_y_c; + break; + } + if (c->needAlpha) { + if (is16BPS(srcFormat) || isNBPS(srcFormat)) { + if (HAVE_BIGENDIAN == !isBE(srcFormat) && !*readAlpPlanar) + *alpToYV12 = bswap16Y_c; + } + switch (srcFormat) { + case AV_PIX_FMT_BGRA64LE: + case AV_PIX_FMT_RGBA64LE: *alpToYV12 = rgba64leToA_c; break; + case AV_PIX_FMT_BGRA64BE: + case AV_PIX_FMT_RGBA64BE: *alpToYV12 = rgba64beToA_c; break; + case AV_PIX_FMT_BGRA: + case AV_PIX_FMT_RGBA: + *alpToYV12 = rgbaToA_c; + break; + case AV_PIX_FMT_ABGR: + case AV_PIX_FMT_ARGB: + *alpToYV12 = abgrToA_c; + break; + case AV_PIX_FMT_RGBAF16BE: + *alpToYV12 = rgbaf16beToA_c; + break; + case AV_PIX_FMT_RGBAF16LE: + *alpToYV12 = rgbaf16leToA_c; + break; + case AV_PIX_FMT_YA8: + *alpToYV12 = uyvyToY_c; + break; + case AV_PIX_FMT_YA16LE: + *alpToYV12 = read_ya16le_alpha_c; + break; + case AV_PIX_FMT_YA16BE: + *alpToYV12 = read_ya16be_alpha_c; + break; + case AV_PIX_FMT_YAF16LE: + *alpToYV12 = read_yaf16le_alpha_c; + break; + case AV_PIX_FMT_YAF16BE: + *alpToYV12 = read_yaf16be_alpha_c; + break; + case AV_PIX_FMT_YAF32LE: + *alpToYV12 = read_yaf32le_alpha_c; + break; + case AV_PIX_FMT_YAF32BE: + *alpToYV12 = read_yaf32be_alpha_c; + break; + case AV_PIX_FMT_VUYA: + case AV_PIX_FMT_UYVA: + *alpToYV12 = read_vuya_A_c; + break; + case AV_PIX_FMT_AYUV: + *alpToYV12 = read_ayuv_A_c; + break; + case AV_PIX_FMT_AYUV64LE: + *alpToYV12 = read_ayuv64le_A_c; + break; + case AV_PIX_FMT_AYUV64BE: + *alpToYV12 = read_ayuv64be_A_c; + break; + case AV_PIX_FMT_PAL8 : + *alpToYV12 = palToA_c; + break; + } + } +} diff --git a/libs/ffmpeg/libswscale/log2_tab.c b/libs/ffmpeg/libswscale/log2_tab.c new file mode 100644 index 00000000000..47a1df03b74 --- /dev/null +++ b/libs/ffmpeg/libswscale/log2_tab.c @@ -0,0 +1 @@ +#include "libavutil/log2_tab.c" diff --git a/libs/ffmpeg/libswscale/lut3d.c b/libs/ffmpeg/libswscale/lut3d.c new file mode 100644 index 00000000000..535694e61c1 --- /dev/null +++ b/libs/ffmpeg/libswscale/lut3d.c @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2024 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <assert.h> +#include <string.h> + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/mem.h" + +#include "cms.h" +#include "csputils.h" +#include "lut3d.h" + +SwsLut3D *ff_sws_lut3d_alloc(void) +{ + SwsLut3D *lut3d = av_malloc(sizeof(*lut3d)); + if (!lut3d) + return NULL; + + lut3d->dynamic = false; + return lut3d; +} + +void ff_sws_lut3d_free(SwsLut3D **plut3d) +{ + av_freep(plut3d); +} + +bool ff_sws_lut3d_test_fmt(enum AVPixelFormat fmt, int output) +{ + return fmt == AV_PIX_FMT_RGBA64; +} + +enum AVPixelFormat ff_sws_lut3d_pick_pixfmt(SwsFormat fmt, int output) +{ + return AV_PIX_FMT_RGBA64; +} + +/** + * v0 and v1 are 'black' and 'white' + * v2 and v3 are closest RGB/CMY vertices + * x >= y >= z are relative weights + */ +static av_always_inline +v3u16_t barycentric(int shift, int x, int y, int z, + v3u16_t v0, v3u16_t v1, v3u16_t v2, v3u16_t v3) +{ + const int a = (1 << shift) - x; + const int b = x - y; + const int c = y - z; + const int d = z; + av_assert2(x >= y); + av_assert2(y >= z); + + return (v3u16_t) { + (a * v0.x + b * v1.x + c * v2.x + d * v3.x) >> shift, + (a * v0.y + b * v1.y + c * v2.y + d * v3.y) >> shift, + (a * v0.z + b * v1.z + c * v2.z + d * v3.z) >> shift, + }; +} + +static av_always_inline +v3u16_t tetrahedral(const SwsLut3D *lut3d, int Rx, int Gx, int Bx, + int Rf, int Gf, int Bf) +{ + const int shift = 16 - INPUT_LUT_BITS; + const int Rn = FFMIN(Rx + 1, INPUT_LUT_SIZE - 1); + const int Gn = FFMIN(Gx + 1, INPUT_LUT_SIZE - 1); + const int Bn = FFMIN(Bx + 1, INPUT_LUT_SIZE - 1); + + const v3u16_t c000 = lut3d->input[Bx][Gx][Rx]; + const v3u16_t c111 = lut3d->input[Bn][Gn][Rn]; + if (Rf > Gf) { + if (Gf > Bf) { + const v3u16_t c100 = lut3d->input[Bx][Gx][Rn]; + const v3u16_t c110 = lut3d->input[Bx][Gn][Rn]; + return barycentric(shift, Rf, Gf, Bf, c000, c100, c110, c111); + } else if (Rf > Bf) { + const v3u16_t c100 = lut3d->input[Bx][Gx][Rn]; + const v3u16_t c101 = lut3d->input[Bn][Gx][Rn]; + return barycentric(shift, Rf, Bf, Gf, c000, c100, c101, c111); + } else { + const v3u16_t c001 = lut3d->input[Bn][Gx][Rx]; + const v3u16_t c101 = lut3d->input[Bn][Gx][Rn]; + return barycentric(shift, Bf, Rf, Gf, c000, c001, c101, c111); + } + } else { + if (Bf > Gf) { + const v3u16_t c001 = lut3d->input[Bn][Gx][Rx]; + const v3u16_t c011 = lut3d->input[Bn][Gn][Rx]; + return barycentric(shift, Bf, Gf, Rf, c000, c001, c011, c111); + } else if (Bf > Rf) { + const v3u16_t c010 = lut3d->input[Bx][Gn][Rx]; + const v3u16_t c011 = lut3d->input[Bn][Gn][Rx]; + return barycentric(shift, Gf, Bf, Rf, c000, c010, c011, c111); + } else { + const v3u16_t c010 = lut3d->input[Bx][Gn][Rx]; + const v3u16_t c110 = lut3d->input[Bx][Gn][Rn]; + return barycentric(shift, Gf, Rf, Bf, c000, c010, c110, c111); + } + } +} + +static av_always_inline v3u16_t lookup_input16(const SwsLut3D *lut3d, v3u16_t rgb) +{ + const int shift = 16 - INPUT_LUT_BITS; + const int Rx = rgb.x >> shift; + const int Gx = rgb.y >> shift; + const int Bx = rgb.z >> shift; + const int Rf = rgb.x & ((1 << shift) - 1); + const int Gf = rgb.y & ((1 << shift) - 1); + const int Bf = rgb.z & ((1 << shift) - 1); + return tetrahedral(lut3d, Rx, Gx, Bx, Rf, Gf, Bf); +} + +/** + * Note: These functions are scaled such that x == (1 << shift) corresponds to + * a value of 1.0. This makes them suitable for use when interpolation LUT + * entries with a fractional part that is just masked away from the index, + * since a fractional coordinate of e.g. 0xFFFF corresponds to a mix weight of + * just slightly *less* than 1.0. + */ +static av_always_inline v2u16_t lerp2u16(v2u16_t a, v2u16_t b, int x, int shift) +{ + const int xi = (1 << shift) - x; + return (v2u16_t) { + (a.x * xi + b.x * x) >> shift, + (a.y * xi + b.y * x) >> shift, + }; +} + +static av_always_inline v3u16_t lerp3u16(v3u16_t a, v3u16_t b, int x, int shift) +{ + const int xi = (1 << shift) - x; + return (v3u16_t) { + (a.x * xi + b.x * x) >> shift, + (a.y * xi + b.y * x) >> shift, + (a.z * xi + b.z * x) >> shift, + }; +} + +static av_always_inline v3u16_t lookup_output(const SwsLut3D *lut3d, v3u16_t ipt) +{ + const int Ishift = 16 - OUTPUT_LUT_BITS_I; + const int Cshift = 16 - OUTPUT_LUT_BITS_PT; + const int Ix = ipt.x >> Ishift; + const int Px = ipt.y >> Cshift; + const int Tx = ipt.z >> Cshift; + const int If = ipt.x & ((1 << Ishift) - 1); + const int Pf = ipt.y & ((1 << Cshift) - 1); + const int Tf = ipt.z & ((1 << Cshift) - 1); + const int In = FFMIN(Ix + 1, OUTPUT_LUT_SIZE_I - 1); + const int Pn = FFMIN(Px + 1, OUTPUT_LUT_SIZE_PT - 1); + const int Tn = FFMIN(Tx + 1, OUTPUT_LUT_SIZE_PT - 1); + + /* Trilinear interpolation */ + const v3u16_t c000 = lut3d->output[Tx][Px][Ix]; + const v3u16_t c001 = lut3d->output[Tx][Px][In]; + const v3u16_t c010 = lut3d->output[Tx][Pn][Ix]; + const v3u16_t c011 = lut3d->output[Tx][Pn][In]; + const v3u16_t c100 = lut3d->output[Tn][Px][Ix]; + const v3u16_t c101 = lut3d->output[Tn][Px][In]; + const v3u16_t c110 = lut3d->output[Tn][Pn][Ix]; + const v3u16_t c111 = lut3d->output[Tn][Pn][In]; + const v3u16_t c00 = lerp3u16(c000, c100, Tf, Cshift); + const v3u16_t c10 = lerp3u16(c010, c110, Tf, Cshift); + const v3u16_t c01 = lerp3u16(c001, c101, Tf, Cshift); + const v3u16_t c11 = lerp3u16(c011, c111, Tf, Cshift); + const v3u16_t c0 = lerp3u16(c00, c10, Pf, Cshift); + const v3u16_t c1 = lerp3u16(c01, c11, Pf, Cshift); + const v3u16_t c = lerp3u16(c0, c1, If, Ishift); + return c; +} + +static av_always_inline v3u16_t apply_tone_map(const SwsLut3D *lut3d, v3u16_t ipt) +{ + const int shift = 16 - TONE_LUT_BITS; + const int Ix = ipt.x >> shift; + const int If = ipt.x & ((1 << shift) - 1); + const int In = FFMIN(Ix + 1, TONE_LUT_SIZE - 1); + + const v2u16_t w0 = lut3d->tone_map[Ix]; + const v2u16_t w1 = lut3d->tone_map[In]; + const v2u16_t w = lerp2u16(w0, w1, If, shift); + const int base = (1 << 15) - w.y; + + ipt.x = w.x; + ipt.y = base + (ipt.y * w.y >> 15); + ipt.z = base + (ipt.z * w.y >> 15); + return ipt; +} + +int ff_sws_lut3d_generate(SwsLut3D *lut3d, enum AVPixelFormat fmt_in, + enum AVPixelFormat fmt_out, const SwsColorMap *map) +{ + int ret; + + if (!ff_sws_lut3d_test_fmt(fmt_in, 0) || !ff_sws_lut3d_test_fmt(fmt_out, 1)) + return AVERROR(EINVAL); + + lut3d->dynamic = map->src.frame_peak.num > 0; + lut3d->map = *map; + + if (lut3d->dynamic) { + ret = ff_sws_color_map_generate_dynamic(&lut3d->input[0][0][0], + &lut3d->output[0][0][0], + INPUT_LUT_SIZE, OUTPUT_LUT_SIZE_I, + OUTPUT_LUT_SIZE_PT, map); + if (ret < 0) + return ret; + + /* Make sure initial state is valid */ + ff_sws_lut3d_update(lut3d, &map->src); + return 0; + } else { + return ff_sws_color_map_generate_static(&lut3d->input[0][0][0], + INPUT_LUT_SIZE, map); + } +} + +void ff_sws_lut3d_update(SwsLut3D *lut3d, const SwsColor *new_src) +{ + if (!new_src || !lut3d->dynamic) + return; + + lut3d->map.src.frame_peak = new_src->frame_peak; + lut3d->map.src.frame_avg = new_src->frame_avg; + + ff_sws_tone_map_generate(lut3d->tone_map, TONE_LUT_SIZE, &lut3d->map); +} + +void ff_sws_lut3d_apply(const SwsLut3D *lut3d, const uint8_t *in, int in_stride, + uint8_t *out, int out_stride, int w, int h) +{ + while (h--) { + const uint16_t *in16 = (const uint16_t *) in; + uint16_t *out16 = (uint16_t *) out; + + for (int x = 0; x < w; x++) { + v3u16_t c = { in16[0], in16[1], in16[2] }; + c = lookup_input16(lut3d, c); + + if (lut3d->dynamic) { + c = apply_tone_map(lut3d, c); + c = lookup_output(lut3d, c); + } + + out16[0] = c.x; + out16[1] = c.y; + out16[2] = c.z; + out16[3] = in16[3]; + in16 += 4; + out16 += 4; + } + + in += in_stride; + out += out_stride; + } +} diff --git a/libs/ffmpeg/libswscale/lut3d.h b/libs/ffmpeg/libswscale/lut3d.h new file mode 100644 index 00000000000..273059f9a11 --- /dev/null +++ b/libs/ffmpeg/libswscale/lut3d.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2024 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_LUT3D_H +#define SWSCALE_LUT3D_H + +#include <stdint.h> + +#include "libavutil/csp.h" +#include "libavutil/pixfmt.h" + +#include "cms.h" +#include "csputils.h" +#include "format.h" + +enum { + /* Input LUT size. This is only calculated once. */ + INPUT_LUT_BITS = 6, + INPUT_LUT_SIZE = (1 << INPUT_LUT_BITS) + 1, /* +1 to simplify interpolation */ + + /* Tone mapping LUT size. This is regenerated possibly per frame. */ + TONE_LUT_BITS = 8, + TONE_LUT_SIZE = (1 << TONE_LUT_BITS) + 1, + + /* Output LUT size (for dynamic tone mapping). This is only calculated once. */ + OUTPUT_LUT_BITS_I = 6, + OUTPUT_LUT_BITS_PT = 7, + + OUTPUT_LUT_SIZE_I = (1 << OUTPUT_LUT_BITS_I) + 1, + OUTPUT_LUT_SIZE_PT = (1 << OUTPUT_LUT_BITS_PT) + 1, +}; + +typedef struct SwsLut3D { + SwsColorMap map; + bool dynamic; + + /* Gamut mapping 3DLUT(s) */ + v3u16_t input[INPUT_LUT_SIZE][INPUT_LUT_SIZE][INPUT_LUT_SIZE]; + v3u16_t output[OUTPUT_LUT_SIZE_PT][OUTPUT_LUT_SIZE_PT][OUTPUT_LUT_SIZE_I]; + + /* Split tone mapping LUT (for dynamic tone mapping) */ + v2u16_t tone_map[TONE_LUT_SIZE]; /* new luma, desaturation */ +} SwsLut3D; + +SwsLut3D *ff_sws_lut3d_alloc(void); +void ff_sws_lut3d_free(SwsLut3D **lut3d); + +/** + * Test to see if a given format is supported by the 3DLUT input/output code. + */ +bool ff_sws_lut3d_test_fmt(enum AVPixelFormat fmt, int output); + +/** + * Pick the best compatible pixfmt for a given SwsFormat. + */ +enum AVPixelFormat ff_sws_lut3d_pick_pixfmt(SwsFormat fmt, int output); + +/** + * Recalculate the (static) 3DLUT state with new settings. This will recompute + * everything. To only update per-frame tone mapping state, instead call + * ff_sws_lut3d_update(). + * + * Returns 0 or a negative error code. + */ +int ff_sws_lut3d_generate(SwsLut3D *lut3d, enum AVPixelFormat fmt_in, + enum AVPixelFormat fmt_out, const SwsColorMap *map); + +/** + * Update the tone mapping state. This will only use per-frame metadata. The + * static metadata is ignored. + */ +void ff_sws_lut3d_update(SwsLut3D *lut3d, const SwsColor *new_src); + +/** + * Applies a color transformation to a plane. The format must match the format + * provided during ff_sws_lut3d_update(). + */ +void ff_sws_lut3d_apply(const SwsLut3D *lut3d, const uint8_t *in, int in_stride, + uint8_t *out, int out_stride, int w, int h); + +#endif /* SWSCALE_LUT3D_H */ diff --git a/libs/ffmpeg/libswscale/ops.c b/libs/ffmpeg/libswscale/ops.c new file mode 100644 index 00000000000..9961f4f7912 --- /dev/null +++ b/libs/ffmpeg/libswscale/ops.c @@ -0,0 +1,859 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/bswap.h" +#include "libavutil/mem.h" +#include "libavutil/rational.h" +#include "libavutil/refstruct.h" + +#include "ops.h" +#include "ops_internal.h" + +extern const SwsOpBackend backend_c; +extern const SwsOpBackend backend_murder; +extern const SwsOpBackend backend_x86; +extern const SwsOpBackend backend_vulkan; + +const SwsOpBackend * const ff_sws_op_backends[] = { + &backend_murder, +#if ARCH_X86_64 && HAVE_X86ASM + &backend_x86, +#endif + &backend_c, +#if CONFIG_VULKAN + &backend_vulkan, +#endif + NULL +}; + +const char *ff_sws_pixel_type_name(SwsPixelType type) +{ + switch (type) { + case SWS_PIXEL_U8: return "u8"; + case SWS_PIXEL_U16: return "u16"; + case SWS_PIXEL_U32: return "u32"; + case SWS_PIXEL_F32: return "f32"; + case SWS_PIXEL_NONE: return "none"; + case SWS_PIXEL_TYPE_NB: break; + } + + av_unreachable("Invalid pixel type!"); + return "ERR"; +} + +int ff_sws_pixel_type_size(SwsPixelType type) +{ + switch (type) { + case SWS_PIXEL_U8: return sizeof(uint8_t); + case SWS_PIXEL_U16: return sizeof(uint16_t); + case SWS_PIXEL_U32: return sizeof(uint32_t); + case SWS_PIXEL_F32: return sizeof(float); + case SWS_PIXEL_NONE: break; + case SWS_PIXEL_TYPE_NB: break; + } + + av_unreachable("Invalid pixel type!"); + return 0; +} + +bool ff_sws_pixel_type_is_int(SwsPixelType type) +{ + switch (type) { + case SWS_PIXEL_U8: + case SWS_PIXEL_U16: + case SWS_PIXEL_U32: + return true; + case SWS_PIXEL_F32: + return false; + case SWS_PIXEL_NONE: + case SWS_PIXEL_TYPE_NB: break; + } + + av_unreachable("Invalid pixel type!"); + return false; +} + +/* biased towards `a` */ +static AVRational av_min_q(AVRational a, AVRational b) +{ + return av_cmp_q(a, b) == 1 ? b : a; +} + +static AVRational av_max_q(AVRational a, AVRational b) +{ + return av_cmp_q(a, b) == -1 ? b : a; +} + +void ff_sws_apply_op_q(const SwsOp *op, AVRational x[4]) +{ + uint64_t mask[4]; + int shift[4]; + + switch (op->op) { + case SWS_OP_READ: + case SWS_OP_WRITE: + return; + case SWS_OP_UNPACK: { + av_assert1(ff_sws_pixel_type_is_int(op->type)); + ff_sws_pack_op_decode(op, mask, shift); + unsigned val = x[0].num; + for (int i = 0; i < 4; i++) + x[i] = Q((val >> shift[i]) & mask[i]); + return; + } + case SWS_OP_PACK: { + av_assert1(ff_sws_pixel_type_is_int(op->type)); + ff_sws_pack_op_decode(op, mask, shift); + unsigned val = 0; + for (int i = 0; i < 4; i++) + val |= (x[i].num & mask[i]) << shift[i]; + x[0] = Q(val); + return; + } + case SWS_OP_SWAP_BYTES: + av_assert1(ff_sws_pixel_type_is_int(op->type)); + switch (ff_sws_pixel_type_size(op->type)) { + case 2: + for (int i = 0; i < 4; i++) + x[i].num = av_bswap16(x[i].num); + break; + case 4: + for (int i = 0; i < 4; i++) + x[i].num = av_bswap32(x[i].num); + break; + } + return; + case SWS_OP_CLEAR: + for (int i = 0; i < 4; i++) { + if (op->c.q4[i].den) + x[i] = op->c.q4[i]; + } + return; + case SWS_OP_LSHIFT: { + av_assert1(ff_sws_pixel_type_is_int(op->type)); + AVRational mult = Q(1 << op->c.u); + for (int i = 0; i < 4; i++) + x[i] = x[i].den ? av_mul_q(x[i], mult) : x[i]; + return; + } + case SWS_OP_RSHIFT: { + av_assert1(ff_sws_pixel_type_is_int(op->type)); + for (int i = 0; i < 4; i++) + x[i] = x[i].den ? Q((x[i].num / x[i].den) >> op->c.u) : x[i]; + return; + } + case SWS_OP_SWIZZLE: { + const AVRational orig[4] = { x[0], x[1], x[2], x[3] }; + for (int i = 0; i < 4; i++) + x[i] = orig[op->swizzle.in[i]]; + return; + } + case SWS_OP_CONVERT: + if (ff_sws_pixel_type_is_int(op->convert.to)) { + const AVRational scale = ff_sws_pixel_expand(op->type, op->convert.to); + for (int i = 0; i < 4; i++) { + x[i] = x[i].den ? Q(x[i].num / x[i].den) : x[i]; + if (op->convert.expand) + x[i] = av_mul_q(x[i], scale); + } + } + return; + case SWS_OP_DITHER: + av_assert1(!ff_sws_pixel_type_is_int(op->type)); + for (int i = 0; i < 4; i++) { + if (op->dither.y_offset[i] >= 0 && x[i].den) + x[i] = av_add_q(x[i], av_make_q(1, 2)); + } + return; + case SWS_OP_MIN: + for (int i = 0; i < 4; i++) + x[i] = av_min_q(x[i], op->c.q4[i]); + return; + case SWS_OP_MAX: + for (int i = 0; i < 4; i++) + x[i] = av_max_q(x[i], op->c.q4[i]); + return; + case SWS_OP_LINEAR: { + av_assert1(!ff_sws_pixel_type_is_int(op->type)); + const AVRational orig[4] = { x[0], x[1], x[2], x[3] }; + for (int i = 0; i < 4; i++) { + AVRational sum = op->lin.m[i][4]; + for (int j = 0; j < 4; j++) + sum = av_add_q(sum, av_mul_q(orig[j], op->lin.m[i][j])); + x[i] = sum; + } + return; + } + case SWS_OP_SCALE: + for (int i = 0; i < 4; i++) + x[i] = x[i].den ? av_mul_q(x[i], op->c.q) : x[i]; + return; + } + + av_unreachable("Invalid operation type!"); +} + +/* merge_comp_flags() forms a monoid with flags_identity as the null element */ +static const unsigned flags_identity = SWS_COMP_ZERO | SWS_COMP_EXACT; +static unsigned merge_comp_flags(unsigned a, unsigned b) +{ + const unsigned flags_or = SWS_COMP_GARBAGE; + const unsigned flags_and = SWS_COMP_ZERO | SWS_COMP_EXACT; + return ((a & b) & flags_and) | ((a | b) & flags_or); +} + +/* Linearly propagate flags per component */ +static void propagate_flags(SwsOp *op, const SwsComps *prev) +{ + for (int i = 0; i < 4; i++) + op->comps.flags[i] = prev->flags[i]; +} + +/* Clear undefined values in dst with src */ +static void clear_undefined_values(AVRational dst[4], const AVRational src[4]) +{ + for (int i = 0; i < 4; i++) { + if (dst[i].den == 0) + dst[i] = src[i]; + } +} + +/* Infer + propagate known information about components */ +void ff_sws_op_list_update_comps(SwsOpList *ops) +{ + SwsComps next = { .unused = {true, true, true, true} }; + SwsComps prev = { .flags = { + SWS_COMP_GARBAGE, SWS_COMP_GARBAGE, SWS_COMP_GARBAGE, SWS_COMP_GARBAGE, + }}; + + /* Forwards pass, propagates knowledge about the incoming pixel values */ + for (int n = 0; n < ops->num_ops; n++) { + SwsOp *op = &ops->ops[n]; + + switch (op->op) { + case SWS_OP_READ: + case SWS_OP_LINEAR: + case SWS_OP_SWAP_BYTES: + case SWS_OP_UNPACK: + break; /* special cases, handled below */ + default: + memcpy(op->comps.min, prev.min, sizeof(prev.min)); + memcpy(op->comps.max, prev.max, sizeof(prev.max)); + ff_sws_apply_op_q(op, op->comps.min); + ff_sws_apply_op_q(op, op->comps.max); + break; + } + + switch (op->op) { + case SWS_OP_READ: + /* Active components are taken from the user-provided values, + * other components are explicitly stripped */ + for (int i = 0; i < op->rw.elems; i++) { + const int idx = op->rw.packed ? i : ops->order_src.in[i]; + op->comps.flags[i] = ops->comps_src.flags[idx]; + op->comps.min[i] = ops->comps_src.min[idx]; + op->comps.max[i] = ops->comps_src.max[idx]; + } + for (int i = op->rw.elems; i < 4; i++) { + op->comps.flags[i] = prev.flags[i]; + op->comps.min[i] = prev.min[i]; + op->comps.max[i] = prev.max[i]; + } + break; + case SWS_OP_SWAP_BYTES: + for (int i = 0; i < 4; i++) { + op->comps.flags[i] = prev.flags[i] ^ SWS_COMP_SWAPPED; + op->comps.min[i] = prev.min[i]; + op->comps.max[i] = prev.max[i]; + } + break; + case SWS_OP_WRITE: + for (int i = 0; i < op->rw.elems; i++) + av_assert1(!(prev.flags[i] & SWS_COMP_GARBAGE)); + /* fall through */ + case SWS_OP_LSHIFT: + case SWS_OP_RSHIFT: + propagate_flags(op, &prev); + break; + case SWS_OP_MIN: + propagate_flags(op, &prev); + clear_undefined_values(op->comps.max, op->c.q4); + break; + case SWS_OP_MAX: + propagate_flags(op, &prev); + clear_undefined_values(op->comps.min, op->c.q4); + break; + case SWS_OP_DITHER: + /* Strip zero flag because of the nonzero dithering offset */ + for (int i = 0; i < 4; i++) + op->comps.flags[i] = prev.flags[i] & ~SWS_COMP_ZERO; + break; + case SWS_OP_UNPACK: + for (int i = 0; i < 4; i++) { + const int pattern = op->pack.pattern[i]; + if (pattern) { + av_assert1(pattern < 32); + op->comps.flags[i] = prev.flags[0]; + op->comps.min[i] = Q(0); + op->comps.max[i] = Q((1ULL << pattern) - 1); + } else + op->comps.flags[i] = SWS_COMP_GARBAGE; + } + break; + case SWS_OP_PACK: { + unsigned flags = flags_identity; + for (int i = 0; i < 4; i++) { + if (op->pack.pattern[i]) + flags = merge_comp_flags(flags, prev.flags[i]); + if (i > 0) /* clear remaining comps for sanity */ + op->comps.flags[i] = SWS_COMP_GARBAGE; + } + op->comps.flags[0] = flags; + break; + } + case SWS_OP_CLEAR: + for (int i = 0; i < 4; i++) { + if (op->c.q4[i].den) { + op->comps.flags[i] = 0; + if (op->c.q4[i].num == 0) + op->comps.flags[i] |= SWS_COMP_ZERO; + if (op->c.q4[i].den == 1) + op->comps.flags[i] |= SWS_COMP_EXACT; + } else { + op->comps.flags[i] = prev.flags[i]; + } + } + break; + case SWS_OP_SWIZZLE: + for (int i = 0; i < 4; i++) + op->comps.flags[i] = prev.flags[op->swizzle.in[i]]; + break; + case SWS_OP_CONVERT: + for (int i = 0; i < 4; i++) { + op->comps.flags[i] = prev.flags[i]; + if (ff_sws_pixel_type_is_int(op->convert.to)) + op->comps.flags[i] |= SWS_COMP_EXACT; + } + break; + case SWS_OP_LINEAR: + for (int i = 0; i < 4; i++) { + unsigned flags = flags_identity; + AVRational min = Q(0), max = Q(0); + for (int j = 0; j < 4; j++) { + const AVRational k = op->lin.m[i][j]; + AVRational mink = av_mul_q(prev.min[j], k); + AVRational maxk = av_mul_q(prev.max[j], k); + if (k.num) { + flags = merge_comp_flags(flags, prev.flags[j]); + if (k.den != 1) /* fractional coefficient */ + flags &= ~SWS_COMP_EXACT; + if (k.num < 0) + FFSWAP(AVRational, mink, maxk); + min = av_add_q(min, mink); + max = av_add_q(max, maxk); + } + } + if (op->lin.m[i][4].num) { /* nonzero offset */ + flags &= ~SWS_COMP_ZERO; + if (op->lin.m[i][4].den != 1) /* fractional offset */ + flags &= ~SWS_COMP_EXACT; + min = av_add_q(min, op->lin.m[i][4]); + max = av_add_q(max, op->lin.m[i][4]); + } + op->comps.flags[i] = flags; + op->comps.min[i] = min; + op->comps.max[i] = max; + } + break; + case SWS_OP_SCALE: + for (int i = 0; i < 4; i++) { + op->comps.flags[i] = prev.flags[i]; + if (op->c.q.den != 1) /* fractional scale */ + op->comps.flags[i] &= ~SWS_COMP_EXACT; + if (op->c.q.num < 0) + FFSWAP(AVRational, op->comps.min[i], op->comps.max[i]); + } + break; + + case SWS_OP_INVALID: + case SWS_OP_TYPE_NB: + av_unreachable("Invalid operation type!"); + } + + prev = op->comps; + } + + /* Backwards pass, solves for component dependencies */ + for (int n = ops->num_ops - 1; n >= 0; n--) { + SwsOp *op = &ops->ops[n]; + + switch (op->op) { + case SWS_OP_READ: + case SWS_OP_WRITE: + for (int i = 0; i < op->rw.elems; i++) + op->comps.unused[i] = op->op == SWS_OP_READ; + for (int i = op->rw.elems; i < 4; i++) + op->comps.unused[i] = next.unused[i]; + break; + case SWS_OP_SWAP_BYTES: + case SWS_OP_LSHIFT: + case SWS_OP_RSHIFT: + case SWS_OP_CONVERT: + case SWS_OP_DITHER: + case SWS_OP_MIN: + case SWS_OP_MAX: + case SWS_OP_SCALE: + for (int i = 0; i < 4; i++) + op->comps.unused[i] = next.unused[i]; + break; + case SWS_OP_UNPACK: { + bool unused = true; + for (int i = 0; i < 4; i++) { + if (op->pack.pattern[i]) + unused &= next.unused[i]; + op->comps.unused[i] = i > 0; + } + op->comps.unused[0] = unused; + break; + } + case SWS_OP_PACK: + for (int i = 0; i < 4; i++) { + if (op->pack.pattern[i]) + op->comps.unused[i] = next.unused[0]; + else + op->comps.unused[i] = true; + } + break; + case SWS_OP_CLEAR: + for (int i = 0; i < 4; i++) { + if (op->c.q4[i].den) + op->comps.unused[i] = true; + else + op->comps.unused[i] = next.unused[i]; + } + break; + case SWS_OP_SWIZZLE: { + bool unused[4] = { true, true, true, true }; + for (int i = 0; i < 4; i++) + unused[op->swizzle.in[i]] &= next.unused[i]; + for (int i = 0; i < 4; i++) + op->comps.unused[i] = unused[i]; + break; + } + case SWS_OP_LINEAR: + for (int j = 0; j < 4; j++) { + bool unused = true; + for (int i = 0; i < 4; i++) { + if (op->lin.m[i][j].num) + unused &= next.unused[i]; + } + op->comps.unused[j] = unused; + } + break; + } + + next = op->comps; + } +} + +static void op_uninit(SwsOp *op) +{ + switch (op->op) { + case SWS_OP_DITHER: + av_refstruct_unref(&op->dither.matrix); + break; + } + + *op = (SwsOp) {0}; +} + +SwsOpList *ff_sws_op_list_alloc(void) +{ + SwsOpList *ops = av_mallocz(sizeof(SwsOpList)); + if (!ops) + return NULL; + + ops->order_src = ops->order_dst = SWS_SWIZZLE(0, 1, 2, 3); + ff_fmt_clear(&ops->src); + ff_fmt_clear(&ops->dst); + return ops; +} + +void ff_sws_op_list_free(SwsOpList **p_ops) +{ + SwsOpList *ops = *p_ops; + if (!ops) + return; + + for (int i = 0; i < ops->num_ops; i++) + op_uninit(&ops->ops[i]); + + av_freep(&ops->ops); + av_free(ops); + *p_ops = NULL; +} + +SwsOpList *ff_sws_op_list_duplicate(const SwsOpList *ops) +{ + SwsOpList *copy = av_malloc(sizeof(*copy)); + if (!copy) + return NULL; + + int num = ops->num_ops; + if (num) + num = 1 << av_ceil_log2(num); + + *copy = *ops; + copy->ops = av_memdup(ops->ops, num * sizeof(ops->ops[0])); + if (!copy->ops) { + av_free(copy); + return NULL; + } + + for (int i = 0; i < ops->num_ops; i++) { + const SwsOp *op = &ops->ops[i]; + switch (op->op) { + case SWS_OP_DITHER: + av_refstruct_ref(copy->ops[i].dither.matrix); + break; + } + } + + return copy; +} + +const SwsOp *ff_sws_op_list_input(const SwsOpList *ops) +{ + if (!ops->num_ops) + return NULL; + + const SwsOp *read = &ops->ops[0]; + return read->op == SWS_OP_READ ? read : NULL; +} + +const SwsOp *ff_sws_op_list_output(const SwsOpList *ops) +{ + if (!ops->num_ops) + return NULL; + + const SwsOp *write = &ops->ops[ops->num_ops - 1]; + return write->op == SWS_OP_WRITE ? write : NULL; +} + +void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count) +{ + const int end = ops->num_ops - count; + av_assert2(index >= 0 && count >= 0 && index + count <= ops->num_ops); + op_uninit(&ops->ops[index]); + for (int i = index; i < end; i++) + ops->ops[i] = ops->ops[i + count]; + ops->num_ops = end; +} + +int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op) +{ + void *ret = av_dynarray2_add((void **) &ops->ops, &ops->num_ops, sizeof(*op), NULL); + if (!ret) { + op_uninit(op); + return AVERROR(ENOMEM); + } + + for (int i = ops->num_ops - 1; i > index; i--) + ops->ops[i] = ops->ops[i - 1]; + ops->ops[index] = *op; + return 0; +} + +int ff_sws_op_list_append(SwsOpList *ops, SwsOp *op) +{ + return ff_sws_op_list_insert_at(ops, ops->num_ops, op); +} + +bool ff_sws_op_list_is_noop(const SwsOpList *ops) +{ + if (!ops->num_ops) + return true; + + const SwsOp *read = ff_sws_op_list_input(ops); + const SwsOp *write = ff_sws_op_list_output(ops); + if (!read || !write || ops->num_ops > 2 || + read->type != write->type || + read->rw.packed != write->rw.packed || + read->rw.elems != write->rw.elems || + read->rw.frac != write->rw.frac) + return false; + + /** + * Note that this check is unlikely to ever be hit in practice, since it + * would imply the existence of planar formats with different plane orders + * between them, e.g. rgbap <-> gbrap, which doesn't currently exist. + * However, the check is cheap and lets me sleep at night. + */ + const int num_planes = read->rw.packed ? 1 : read->rw.elems; + for (int i = 0; i < num_planes; i++) { + if (ops->order_src.in[i] != ops->order_dst.in[i]) + return false; + } + + return true; +} + +int ff_sws_op_list_max_size(const SwsOpList *ops) +{ + int max_size = 0; + for (int i = 0; i < ops->num_ops; i++) { + const int size = ff_sws_pixel_type_size(ops->ops[i].type); + max_size = FFMAX(max_size, size); + } + + return max_size; +} + +uint32_t ff_sws_linear_mask(const SwsLinearOp c) +{ + uint32_t mask = 0; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 5; j++) { + if (av_cmp_q(c.m[i][j], Q(i == j))) + mask |= SWS_MASK(i, j); + } + } + return mask; +} + +static const char *describe_lin_mask(uint32_t mask) +{ + /* Try to be fairly descriptive without assuming too much */ + static const struct { + char name[24]; + uint32_t mask; + } patterns[] = { + { "noop", 0 }, + { "luma", SWS_MASK_LUMA }, + { "alpha", SWS_MASK_ALPHA }, + { "luma+alpha", SWS_MASK_LUMA | SWS_MASK_ALPHA }, + { "dot3", 0x7 }, + { "dot4", 0xF }, + { "row0", SWS_MASK_ROW(0) }, + { "row0+alpha", SWS_MASK_ROW(0) | SWS_MASK_ALPHA }, + { "col0", SWS_MASK_COL(0) }, + { "col0+off3", SWS_MASK_COL(0) | SWS_MASK_OFF3 }, + { "off3", SWS_MASK_OFF3 }, + { "off3+alpha", SWS_MASK_OFF3 | SWS_MASK_ALPHA }, + { "diag3", SWS_MASK_DIAG3 }, + { "diag4", SWS_MASK_DIAG4 }, + { "diag3+alpha", SWS_MASK_DIAG3 | SWS_MASK_ALPHA }, + { "diag3+off3", SWS_MASK_DIAG3 | SWS_MASK_OFF3 }, + { "diag3+off3+alpha", SWS_MASK_DIAG3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA }, + { "diag4+off4", SWS_MASK_DIAG4 | SWS_MASK_OFF4 }, + { "matrix3", SWS_MASK_MAT3 }, + { "matrix3+off3", SWS_MASK_MAT3 | SWS_MASK_OFF3 }, + { "matrix3+off3+alpha", SWS_MASK_MAT3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA }, + { "matrix4", SWS_MASK_MAT4 }, + { "matrix4+off4", SWS_MASK_MAT4 | SWS_MASK_OFF4 }, + }; + + for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) { + if (!(mask & ~patterns[i].mask)) + return patterns[i].name; + } + + av_unreachable("Invalid linear mask!"); + return "ERR"; +} + +static char describe_comp_flags(unsigned flags) +{ + if (flags & SWS_COMP_GARBAGE) + return 'X'; + else if (flags & SWS_COMP_ZERO) + return '0'; + else if (flags & SWS_COMP_SWAPPED) + return 'z'; + else if (flags & SWS_COMP_EXACT) + return '+'; + else + return '.'; +} + +static const char *describe_order(SwsSwizzleOp order, int planes, char buf[32]) +{ + if (order.mask == SWS_SWIZZLE(0, 1, 2, 3).mask) + return ""; + + av_strlcpy(buf, ", via {", 32); + for (int i = 0; i < planes; i++) + av_strlcatf(buf, 32, "%s%d", i ? ", " : "", order.in[i]); + av_strlcat(buf, "}", 32); + return buf; +} + +static const char *print_q(const AVRational q, char buf[], int buf_len) +{ + if (!q.den) { + return q.num > 0 ? "inf" : q.num < 0 ? "-inf" : "nan"; + } else if (q.den == 1) { + snprintf(buf, buf_len, "%d", q.num); + return buf; + } else if (abs(q.num) > 1000 || abs(q.den) > 1000) { + snprintf(buf, buf_len, "%f", av_q2d(q)); + return buf; + } else { + snprintf(buf, buf_len, "%d/%d", q.num, q.den); + return buf; + } +} + +#define PRINTQ(q) print_q(q, (char[32]){0}, sizeof(char[32])) + +void ff_sws_op_list_print(void *log, int lev, int lev_extra, + const SwsOpList *ops) +{ + if (!ops->num_ops) { + av_log(log, lev, " (empty)\n"); + return; + } + + for (int i = 0; i < ops->num_ops; i++) { + const SwsOp *op = &ops->ops[i]; + const SwsOp *next = i + 1 < ops->num_ops ? &ops->ops[i + 1] : op; + char buf[32]; + + av_log(log, lev, " [%3s %c%c%c%c -> %c%c%c%c] ", + ff_sws_pixel_type_name(op->type), + op->comps.unused[0] ? 'X' : '.', + op->comps.unused[1] ? 'X' : '.', + op->comps.unused[2] ? 'X' : '.', + op->comps.unused[3] ? 'X' : '.', + next->comps.unused[0] ? 'X' : describe_comp_flags(op->comps.flags[0]), + next->comps.unused[1] ? 'X' : describe_comp_flags(op->comps.flags[1]), + next->comps.unused[2] ? 'X' : describe_comp_flags(op->comps.flags[2]), + next->comps.unused[3] ? 'X' : describe_comp_flags(op->comps.flags[3])); + + switch (op->op) { + case SWS_OP_INVALID: + av_log(log, lev, "SWS_OP_INVALID\n"); + break; + case SWS_OP_READ: + case SWS_OP_WRITE: + av_log(log, lev, "%-20s: %d elem(s) %s >> %d%s\n", + op->op == SWS_OP_READ ? "SWS_OP_READ" + : "SWS_OP_WRITE", + op->rw.elems, op->rw.packed ? "packed" : "planar", + op->rw.frac, + describe_order(op->op == SWS_OP_READ ? ops->order_src + : ops->order_dst, + op->rw.packed ? 1 : op->rw.elems, buf)); + break; + case SWS_OP_SWAP_BYTES: + av_log(log, lev, "SWS_OP_SWAP_BYTES\n"); + break; + case SWS_OP_LSHIFT: + av_log(log, lev, "%-20s: << %u\n", "SWS_OP_LSHIFT", op->c.u); + break; + case SWS_OP_RSHIFT: + av_log(log, lev, "%-20s: >> %u\n", "SWS_OP_RSHIFT", op->c.u); + break; + case SWS_OP_PACK: + case SWS_OP_UNPACK: + av_log(log, lev, "%-20s: {%d %d %d %d}\n", + op->op == SWS_OP_PACK ? "SWS_OP_PACK" + : "SWS_OP_UNPACK", + op->pack.pattern[0], op->pack.pattern[1], + op->pack.pattern[2], op->pack.pattern[3]); + break; + case SWS_OP_CLEAR: + av_log(log, lev, "%-20s: {%s %s %s %s}\n", "SWS_OP_CLEAR", + op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_", + op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_", + op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_", + op->c.q4[3].den ? PRINTQ(op->c.q4[3]) : "_"); + break; + case SWS_OP_SWIZZLE: + av_log(log, lev, "%-20s: %d%d%d%d\n", "SWS_OP_SWIZZLE", + op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w); + break; + case SWS_OP_CONVERT: + av_log(log, lev, "%-20s: %s -> %s%s\n", "SWS_OP_CONVERT", + ff_sws_pixel_type_name(op->type), + ff_sws_pixel_type_name(op->convert.to), + op->convert.expand ? " (expand)" : ""); + break; + case SWS_OP_DITHER: + av_log(log, lev, "%-20s: %dx%d matrix + {%d %d %d %d}\n", "SWS_OP_DITHER", + 1 << op->dither.size_log2, 1 << op->dither.size_log2, + op->dither.y_offset[0], op->dither.y_offset[1], + op->dither.y_offset[2], op->dither.y_offset[3]); + break; + case SWS_OP_MIN: + av_log(log, lev, "%-20s: x <= {%s %s %s %s}\n", "SWS_OP_MIN", + op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_", + op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_", + op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_", + op->c.q4[3].den ? PRINTQ(op->c.q4[3]) : "_"); + break; + case SWS_OP_MAX: + av_log(log, lev, "%-20s: {%s %s %s %s} <= x\n", "SWS_OP_MAX", + op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_", + op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_", + op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_", + op->c.q4[3].den ? PRINTQ(op->c.q4[3]) : "_"); + break; + case SWS_OP_LINEAR: + av_log(log, lev, "%-20s: %s [[%s %s %s %s %s] " + "[%s %s %s %s %s] " + "[%s %s %s %s %s] " + "[%s %s %s %s %s]]\n", + "SWS_OP_LINEAR", describe_lin_mask(op->lin.mask), + PRINTQ(op->lin.m[0][0]), PRINTQ(op->lin.m[0][1]), PRINTQ(op->lin.m[0][2]), PRINTQ(op->lin.m[0][3]), PRINTQ(op->lin.m[0][4]), + PRINTQ(op->lin.m[1][0]), PRINTQ(op->lin.m[1][1]), PRINTQ(op->lin.m[1][2]), PRINTQ(op->lin.m[1][3]), PRINTQ(op->lin.m[1][4]), + PRINTQ(op->lin.m[2][0]), PRINTQ(op->lin.m[2][1]), PRINTQ(op->lin.m[2][2]), PRINTQ(op->lin.m[2][3]), PRINTQ(op->lin.m[2][4]), + PRINTQ(op->lin.m[3][0]), PRINTQ(op->lin.m[3][1]), PRINTQ(op->lin.m[3][2]), PRINTQ(op->lin.m[3][3]), PRINTQ(op->lin.m[3][4])); + break; + case SWS_OP_SCALE: + av_log(log, lev, "%-20s: * %s\n", "SWS_OP_SCALE", + PRINTQ(op->c.q)); + break; + case SWS_OP_TYPE_NB: + break; + } + + if (op->comps.min[0].den || op->comps.min[1].den || + op->comps.min[2].den || op->comps.min[3].den || + op->comps.max[0].den || op->comps.max[1].den || + op->comps.max[2].den || op->comps.max[3].den) + { + av_log(log, lev_extra, " min: {%s, %s, %s, %s}, max: {%s, %s, %s, %s}\n", + next->comps.unused[0] ? "_" : PRINTQ(op->comps.min[0]), + next->comps.unused[1] ? "_" : PRINTQ(op->comps.min[1]), + next->comps.unused[2] ? "_" : PRINTQ(op->comps.min[2]), + next->comps.unused[3] ? "_" : PRINTQ(op->comps.min[3]), + next->comps.unused[0] ? "_" : PRINTQ(op->comps.max[0]), + next->comps.unused[1] ? "_" : PRINTQ(op->comps.max[1]), + next->comps.unused[2] ? "_" : PRINTQ(op->comps.max[2]), + next->comps.unused[3] ? "_" : PRINTQ(op->comps.max[3])); + } + + } + + av_log(log, lev, " (X = unused, z = byteswapped, + = exact, 0 = zero)\n"); +} diff --git a/libs/ffmpeg/libswscale/ops.h b/libs/ffmpeg/libswscale/ops.h new file mode 100644 index 00000000000..64a4a6dd61d --- /dev/null +++ b/libs/ffmpeg/libswscale/ops.h @@ -0,0 +1,318 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_OPS_H +#define SWSCALE_OPS_H + +#include <assert.h> +#include <stdbool.h> +#include <stdalign.h> + +#include "graph.h" + +typedef enum SwsPixelType { + SWS_PIXEL_NONE = 0, + SWS_PIXEL_U8, + SWS_PIXEL_U16, + SWS_PIXEL_U32, + SWS_PIXEL_F32, + SWS_PIXEL_TYPE_NB +} SwsPixelType; + +const char *ff_sws_pixel_type_name(SwsPixelType type); +int ff_sws_pixel_type_size(SwsPixelType type) av_const; +bool ff_sws_pixel_type_is_int(SwsPixelType type) av_const; + +typedef enum SwsOpType { + SWS_OP_INVALID = 0, + + /* Defined for all types; but implemented for integers only */ + SWS_OP_READ, /* gather raw pixels from planes */ + SWS_OP_WRITE, /* write raw pixels to planes */ + SWS_OP_SWAP_BYTES, /* swap byte order (for differing endianness) */ + SWS_OP_SWIZZLE, /* rearrange channel order, or duplicate channels */ + + /* Bit manipulation operations. Defined for integers only. */ + SWS_OP_UNPACK, /* split tightly packed data into components */ + SWS_OP_PACK, /* compress components into tightly packed data */ + SWS_OP_LSHIFT, /* logical left shift of raw pixel values by (u8) */ + SWS_OP_RSHIFT, /* right shift of raw pixel values by (u8) */ + + /* Generic arithmetic. Defined and implemented for all types */ + SWS_OP_CLEAR, /* clear pixel values */ + SWS_OP_CONVERT, /* convert (cast) between formats */ + SWS_OP_MIN, /* numeric minimum (q4) */ + SWS_OP_MAX, /* numeric maximum (q4) */ + SWS_OP_SCALE, /* multiplication by scalar (q) */ + + /* Floating-point only arithmetic operations. */ + SWS_OP_LINEAR, /* generalized linear affine transform */ + SWS_OP_DITHER, /* add dithering noise */ + + SWS_OP_TYPE_NB, +} SwsOpType; + +enum SwsCompFlags { + SWS_COMP_GARBAGE = 1 << 0, /* contents are undefined / garbage data */ + SWS_COMP_EXACT = 1 << 1, /* value is an exact integer */ + SWS_COMP_ZERO = 1 << 2, /* known to be a constant zero */ + SWS_COMP_SWAPPED = 1 << 3, /* byte order is swapped */ +}; + +typedef union SwsConst { + /* Generic constant value */ + AVRational q4[4]; + AVRational q; + unsigned u; +} SwsConst; + +static_assert(sizeof(SwsConst) == sizeof(AVRational) * 4, + "First field of SwsConst should span the entire union"); + +typedef struct SwsComps { + unsigned flags[4]; /* knowledge about (output) component contents */ + bool unused[4]; /* which input components are definitely unused */ + + /* Keeps track of the known possible value range, or {0, 0} for undefined + * or (unknown range) floating point inputs */ + AVRational min[4], max[4]; +} SwsComps; + +typedef struct SwsReadWriteOp { + uint8_t elems; /* number of elements (of type `op.type`) to read/write */ + uint8_t frac; /* fractional pixel step factor (log2) */ + bool packed; /* read multiple elements from a single plane */ + + /** Examples: + * rgba = 4x u8 packed + * yuv444p = 3x u8 + * rgb565 = 1x u16 <- use SWS_OP_UNPACK to unpack + * monow = 1x u8 (frac 3) + * rgb4 = 1x u8 (frac 1) + */ +} SwsReadWriteOp; + +typedef struct SwsPackOp { + /** + * Packed bits are assumed to be LSB-aligned within the underlying + * integer type; i.e. (msb) 0 ... X Y Z W (lsb). + */ + uint8_t pattern[4]; /* bit depth pattern, from MSB to LSB */ +} SwsPackOp; + +typedef struct SwsSwizzleOp { + /** + * Input component for each output component: + * Out[x] := In[swizzle.in[x]] + */ + union { + uint32_t mask; + uint8_t in[4]; + struct { uint8_t x, y, z, w; }; + }; +} SwsSwizzleOp; + +#define SWS_SWIZZLE(X,Y,Z,W) ((SwsSwizzleOp) { .in = {X, Y, Z, W} }) + +typedef struct SwsConvertOp { + SwsPixelType to; /* type of pixel to convert to */ + bool expand; /* if true, integers are expanded to the full range */ +} SwsConvertOp; + +typedef struct SwsDitherOp { + AVRational *matrix; /* tightly packed dither matrix (refstruct) */ + int size_log2; /* size (in bits) of the dither matrix */ + int8_t y_offset[4]; /* row offset for each component, or -1 for ignored */ +} SwsDitherOp; + +typedef struct SwsLinearOp { + /** + * Generalized 5x5 affine transformation: + * [ Out.x ] = [ A B C D E ] + * [ Out.y ] = [ F G H I J ] * [ x y z w 1 ] + * [ Out.z ] = [ K L M N O ] + * [ Out.w ] = [ P Q R S T ] + * + * The mask keeps track of which components differ from an identity matrix. + * There may be more efficient implementations of particular subsets, for + * example the common subset of {A, E, G, J, M, O} can be implemented with + * just three fused multiply-add operations. + */ + AVRational m[4][5]; + uint32_t mask; /* m[i][j] <-> 1 << (5 * i + j) */ +} SwsLinearOp; + +#define SWS_MASK(I, J) (1 << (5 * (I) + (J))) +#define SWS_MASK_OFF(I) SWS_MASK(I, 4) +#define SWS_MASK_ROW(I) (0x1F << (5 * (I))) +#define SWS_MASK_COL(J) (0x8421 << J) + +enum { + SWS_MASK_ALL = (1 << 20) - 1, + SWS_MASK_LUMA = SWS_MASK(0, 0) | SWS_MASK_OFF(0), + SWS_MASK_ALPHA = SWS_MASK(3, 3) | SWS_MASK_OFF(3), + + SWS_MASK_DIAG3 = SWS_MASK(0, 0) | SWS_MASK(1, 1) | SWS_MASK(2, 2), + SWS_MASK_OFF3 = SWS_MASK_OFF(0) | SWS_MASK_OFF(1) | SWS_MASK_OFF(2), + SWS_MASK_MAT3 = SWS_MASK(0, 0) | SWS_MASK(0, 1) | SWS_MASK(0, 2) | + SWS_MASK(1, 0) | SWS_MASK(1, 1) | SWS_MASK(1, 2) | + SWS_MASK(2, 0) | SWS_MASK(2, 1) | SWS_MASK(2, 2), + + SWS_MASK_DIAG4 = SWS_MASK_DIAG3 | SWS_MASK(3, 3), + SWS_MASK_OFF4 = SWS_MASK_OFF3 | SWS_MASK_OFF(3), + SWS_MASK_MAT4 = SWS_MASK_ALL & ~SWS_MASK_OFF4, +}; + +/* Helper function to compute the correct mask */ +uint32_t ff_sws_linear_mask(SwsLinearOp); + +typedef struct SwsOp { + SwsOpType op; /* operation to perform */ + SwsPixelType type; /* pixel type to operate on */ + union { + SwsLinearOp lin; + SwsReadWriteOp rw; + SwsPackOp pack; + SwsSwizzleOp swizzle; + SwsConvertOp convert; + SwsDitherOp dither; + SwsConst c; + }; + + /** + * Metadata about the operation's input/output components. Discarded + * and regenerated automatically by `ff_sws_op_list_update_comps()`. + * + * Note that backends may rely on the presence and accuracy of this + * metadata for all operations, during ff_sws_ops_compile(). + */ + SwsComps comps; +} SwsOp; + +/** + * Frees any allocations associated with an SwsOp and sets it to {0}. + */ +void ff_sws_op_uninit(SwsOp *op); + +/** + * Apply an operation to an AVRational. No-op for read/write operations. + */ +void ff_sws_apply_op_q(const SwsOp *op, AVRational x[4]); + +/** + * Helper struct for representing a list of operations. + */ +typedef struct SwsOpList { + SwsOp *ops; + int num_ops; + + /* Purely informative metadata associated with this operation list */ + SwsFormat src, dst; + + /* Input/output plane pointer swizzle mask */ + SwsSwizzleOp order_src, order_dst; + + /** + * Source component metadata associated with pixel values from each + * corresponding component (in plane/memory order, i.e. not affected by + * `order_src`). Lets the optimizer know additional information about + * the value range and/or pixel data to expect. + * + * The default value of {0} is safe to pass in the case that no additional + * information is known. + */ + SwsComps comps_src; +} SwsOpList; + +SwsOpList *ff_sws_op_list_alloc(void); +void ff_sws_op_list_free(SwsOpList **ops); + +/** + * Returns a duplicate of `ops`, or NULL on OOM. + */ +SwsOpList *ff_sws_op_list_duplicate(const SwsOpList *ops); + +/** + * Returns the input operation for a given op list, or NULL if there is none + * (e.g. for a pure CLEAR-only operation list). + * + * This will always be an op of type SWS_OP_READ. + */ +const SwsOp *ff_sws_op_list_input(const SwsOpList *ops); + +/** + * Returns the output operation for a given op list, or NULL if there is none. + * + * This will always be an op of type SWS_OP_WRITE. + */ +const SwsOp *ff_sws_op_list_output(const SwsOpList *ops); + +/** + * Returns whether an op list represents a true no-op operation, i.e. may be + * eliminated entirely from an execution graph. + */ +bool ff_sws_op_list_is_noop(const SwsOpList *ops); + +/** + * Returns the size of the largest pixel type used in `ops`. + */ +int ff_sws_op_list_max_size(const SwsOpList *ops); + +/** + * These will take over ownership of `op` and set it to {0}, even on failure. + */ +int ff_sws_op_list_append(SwsOpList *ops, SwsOp *op); +int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op); + +void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count); + +/** + * Print out the contents of an operation list. + */ +void ff_sws_op_list_print(void *log_ctx, int log_level, int log_level_extra, + const SwsOpList *ops); + +/** + * Infer + propagate known information about components. Called automatically + * when needed by the optimizer and compiler. + */ +void ff_sws_op_list_update_comps(SwsOpList *ops); + +/** + * Fuse compatible and eliminate redundant operations, as well as replacing + * some operations with more efficient alternatives. + */ +int ff_sws_op_list_optimize(SwsOpList *ops); + +enum SwsOpCompileFlags { + /* Automatically optimize the operations when compiling */ + SWS_OP_FLAG_OPTIMIZE = 1 << 0, +}; + +/** + * Resolves an operation list to a graph pass. The first and last operations + * must be a read/write respectively. `flags` is a list of SwsOpCompileFlags. + * + * Note: `ops` may be modified by this function. + */ +int ff_sws_compile_pass(SwsGraph *graph, SwsOpList *ops, int flags, + const SwsFormat *dst, SwsPass *input, SwsPass **output); + +#endif diff --git a/libs/ffmpeg/libswscale/ops_backend.c b/libs/ffmpeg/libswscale/ops_backend.c new file mode 100644 index 00000000000..ceecae4f991 --- /dev/null +++ b/libs/ffmpeg/libswscale/ops_backend.c @@ -0,0 +1,108 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ops_backend.h" + +#if AV_GCC_VERSION_AT_LEAST(4, 4) +#pragma GCC optimize ("finite-math-only") +#endif + +/* Array-based reference implementation */ + +#ifndef SWS_BLOCK_SIZE +# define SWS_BLOCK_SIZE 32 +#endif + +typedef uint8_t u8block_t[SWS_BLOCK_SIZE]; +typedef uint16_t u16block_t[SWS_BLOCK_SIZE]; +typedef uint32_t u32block_t[SWS_BLOCK_SIZE]; +typedef float f32block_t[SWS_BLOCK_SIZE]; + +#define BIT_DEPTH 8 +# include "ops_tmpl_int.c" +#undef BIT_DEPTH + +#define BIT_DEPTH 16 +# include "ops_tmpl_int.c" +#undef BIT_DEPTH + +#define BIT_DEPTH 32 +# include "ops_tmpl_int.c" +# include "ops_tmpl_float.c" +#undef BIT_DEPTH + +static const SwsOpTable *const tables[] = { + &bitfn(op_table_int, u8), + &bitfn(op_table_int, u16), + &bitfn(op_table_int, u32), + &bitfn(op_table_float, f32), +}; + +static int compile(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out) +{ + int ret; + + SwsOpChain *chain = ff_sws_op_chain_alloc(); + if (!chain) + return AVERROR(ENOMEM); + + av_assert0(ops->num_ops > 0); + const SwsPixelType read_type = ops->ops[0].type; + + /* Make on-stack copy of `ops` to iterate over */ + SwsOpList rest = *ops; + do { + ret = ff_sws_op_compile_tables(tables, FF_ARRAY_ELEMS(tables), &rest, + SWS_BLOCK_SIZE, chain); + } while (ret == AVERROR(EAGAIN)); + + if (ret < 0) { + ff_sws_op_chain_free(chain); + if (rest.num_ops < ops->num_ops) { + av_log(ctx, AV_LOG_TRACE, "Uncompiled remainder:\n"); + ff_sws_op_list_print(ctx, AV_LOG_TRACE, AV_LOG_TRACE, &rest); + } + return ret; + } + + *out = (SwsCompiledOp) { + .slice_align = 1, + .block_size = SWS_BLOCK_SIZE, + .cpu_flags = chain->cpu_flags, + .priv = chain, + .free = ff_sws_op_chain_free_cb, + }; + + switch (read_type) { + case SWS_PIXEL_U8: out->func = process_u8; break; + case SWS_PIXEL_U16: out->func = process_u16; break; + case SWS_PIXEL_U32: out->func = process_u32; break; + case SWS_PIXEL_F32: out->func = process_f32; break; + default: av_unreachable("Invalid pixel type!"); + } + + return 0; +} + +const SwsOpBackend backend_c = { + .name = "c", + .compile = compile, + .hw_format = AV_PIX_FMT_NONE, +}; diff --git a/libs/ffmpeg/libswscale/ops_backend.h b/libs/ffmpeg/libswscale/ops_backend.h new file mode 100644 index 00000000000..b1616f6b020 --- /dev/null +++ b/libs/ffmpeg/libswscale/ops_backend.h @@ -0,0 +1,162 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_OPS_BACKEND_H +#define SWSCALE_OPS_BACKEND_H + +/** + * Helper macros for the C-based backend. + * + * To use these macros, the following types must be defined: + * - PIXEL_TYPE should be one of SWS_PIXEL_* + * - pixel_t should be the type of pixels + * - block_t should be the type of blocks (groups of pixels) + */ + +#include <assert.h> +#include <float.h> +#include <stdint.h> + +#include "libavutil/attributes.h" +#include "libavutil/mem.h" + +#include "ops_chain.h" + +/** + * Internal context holding per-iter execution data. The data pointers will be + * directly incremented by the corresponding read/write functions. + */ +typedef struct SwsOpIter { + const uint8_t *in[4]; + uint8_t *out[4]; + int x, y; +} SwsOpIter; + +#ifdef __clang__ +# define SWS_FUNC +# define SWS_LOOP AV_PRAGMA(clang loop vectorize(assume_safety)) +#elif defined(__GNUC__) +# define SWS_FUNC __attribute__((optimize("tree-vectorize"))) +# define SWS_LOOP AV_PRAGMA(GCC ivdep) +#else +# define SWS_FUNC +# define SWS_LOOP +#endif + +/* Miscellaneous helpers */ +#define bitfn2(name, ext) name ## _ ## ext +#define bitfn(name, ext) bitfn2(name, ext) + +#define FN_SUFFIX AV_JOIN(FMT_CHAR, BIT_DEPTH) +#define fn(name) bitfn(name, FN_SUFFIX) + +#define av_q2pixel(q) ((q).den ? (pixel_t) (q).num / (q).den : 0) + +/* Helper macros to make writing common function signatures less painful */ +#define DECL_FUNC(NAME, ...) \ + static av_always_inline void fn(NAME)(SwsOpIter *restrict iter, \ + const SwsOpImpl *restrict impl, \ + block_t x, block_t y, \ + block_t z, block_t w, \ + __VA_ARGS__) + +#define DECL_READ(NAME, ...) \ + DECL_FUNC(NAME, const pixel_t *restrict in0, const pixel_t *restrict in1, \ + const pixel_t *restrict in2, const pixel_t *restrict in3, \ + __VA_ARGS__) + +#define DECL_WRITE(NAME, ...) \ + DECL_FUNC(NAME, pixel_t *restrict out0, pixel_t *restrict out1, \ + pixel_t *restrict out2, pixel_t *restrict out3, \ + __VA_ARGS__) + +/* Helper macros to call into functions declared with DECL_FUNC_* */ +#define CALL(FUNC, ...) \ + fn(FUNC)(iter, impl, x, y, z, w, __VA_ARGS__) + +#define CALL_READ(FUNC, ...) \ + CALL(FUNC, (const pixel_t *) iter->in[0], (const pixel_t *) iter->in[1], \ + (const pixel_t *) iter->in[2], (const pixel_t *) iter->in[3], \ + __VA_ARGS__) + +#define CALL_WRITE(FUNC, ...) \ + CALL(FUNC, (pixel_t *) iter->out[0], (pixel_t *) iter->out[1], \ + (pixel_t *) iter->out[2], (pixel_t *) iter->out[3], __VA_ARGS__) + +/* Helper macros to declare continuation functions */ +#define DECL_IMPL(NAME) \ + static SWS_FUNC void fn(NAME)(SwsOpIter *restrict iter, \ + const SwsOpImpl *restrict impl, \ + block_t x, block_t y, \ + block_t z, block_t w) + +/* Helper macro to call into the next continuation with a given type */ +#define CONTINUE(TYPE, ...) \ + ((void (*)(SwsOpIter *, const SwsOpImpl *, \ + TYPE x, TYPE y, TYPE z, TYPE w)) impl->cont) \ + (iter, &impl[1], __VA_ARGS__) + +/* Helper macros for common op setup code */ +#define DECL_SETUP(NAME) \ + static int fn(NAME)(const SwsOp *op, SwsOpPriv *out) + +#define SETUP_MEMDUP(c) ff_setup_memdup(&(c), sizeof(c), out) +static inline int ff_setup_memdup(const void *c, size_t size, SwsOpPriv *out) +{ + out->ptr = av_memdup(c, size); + return out->ptr ? 0 : AVERROR(ENOMEM); +} + +/* Helper macro for declaring op table entries */ +#define DECL_ENTRY(NAME, ...) \ + static const SwsOpEntry fn(op_##NAME) = { \ + .func = (SwsFuncPtr) fn(NAME), \ + .type = PIXEL_TYPE, \ + __VA_ARGS__ \ + } + +/* Helpers to define functions for common subsets of components */ +#define DECL_PATTERN(NAME) \ + DECL_FUNC(NAME, const bool X, const bool Y, const bool Z, const bool W) + +#define WRAP_PATTERN(FUNC, X, Y, Z, W, ...) \ + DECL_IMPL(FUNC##_##X##Y##Z##W) \ + { \ + CALL(FUNC, X, Y, Z, W); \ + } \ + \ + DECL_ENTRY(FUNC##_##X##Y##Z##W, \ + .unused = { !X, !Y, !Z, !W }, \ + __VA_ARGS__ \ + ) + +#define WRAP_COMMON_PATTERNS(FUNC, ...) \ + WRAP_PATTERN(FUNC, 1, 0, 0, 0, __VA_ARGS__); \ + WRAP_PATTERN(FUNC, 1, 0, 0, 1, __VA_ARGS__); \ + WRAP_PATTERN(FUNC, 1, 1, 1, 0, __VA_ARGS__); \ + WRAP_PATTERN(FUNC, 1, 1, 1, 1, __VA_ARGS__) + +#define REF_COMMON_PATTERNS(NAME) \ + &fn(op_##NAME##_1000), \ + &fn(op_##NAME##_1001), \ + &fn(op_##NAME##_1110), \ + &fn(op_##NAME##_1111) + +#endif diff --git a/libs/ffmpeg/libswscale/ops_chain.c b/libs/ffmpeg/libswscale/ops_chain.c new file mode 100644 index 00000000000..24451541866 --- /dev/null +++ b/libs/ffmpeg/libswscale/ops_chain.c @@ -0,0 +1,292 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/mem.h" +#include "libavutil/rational.h" + +#include "ops_chain.h" + +#define Q(N) ((AVRational) { N, 1 }) + +SwsOpChain *ff_sws_op_chain_alloc(void) +{ + return av_mallocz(sizeof(SwsOpChain)); +} + +void ff_sws_op_chain_free_cb(void *ptr) +{ + if (!ptr) + return; + + SwsOpChain *chain = ptr; + for (int i = 0; i < chain->num_impl + 1; i++) { + if (chain->free[i]) + chain->free[i](chain->impl[i].priv.ptr); + } + + av_free(chain); +} + +int ff_sws_op_chain_append(SwsOpChain *chain, SwsFuncPtr func, + void (*free)(void *), const SwsOpPriv *priv) +{ + const int idx = chain->num_impl; + if (idx == SWS_MAX_OPS) + return AVERROR(EINVAL); + + av_assert1(func); + chain->impl[idx].cont = func; + chain->impl[idx + 1].priv = *priv; + chain->free[idx + 1] = free; + chain->num_impl++; + return 0; +} + +/** + * Match an operation against a reference operation. Returns a score for how + * well the reference matches the operation, or 0 if there is no match. + * + * If `ref->comps` has any flags set, they must be set in `op` as well. + * Likewise, if `ref->comps` has any components marked as unused, they must be + * marked as unused in `ops` as well. + * + * For SWS_OP_LINEAR, `ref->linear.mask` must be a strict superset of + * `op->linear.mask`, but may not contain any columns explicitly ignored by + * `op->comps.unused`. + * + * For SWS_OP_READ, SWS_OP_WRITE, SWS_OP_SWAP_BYTES and SWS_OP_SWIZZLE, the + * exact type is not checked, just the size. + * + * Components set in `next.unused` are ignored when matching. If `flexible` + * is true, the op body is ignored - only the operation, pixel type, and + * component masks are checked. + */ +static int op_match(const SwsOp *op, const SwsOpEntry *entry, const SwsComps next) +{ + int score = 10; + if (op->op != entry->op) + return 0; + + switch (op->op) { + case SWS_OP_READ: + case SWS_OP_WRITE: + case SWS_OP_SWAP_BYTES: + case SWS_OP_SWIZZLE: + /* Only the size matters for these operations */ + if (ff_sws_pixel_type_size(op->type) != ff_sws_pixel_type_size(entry->type)) + return 0; + break; + default: + if (op->type != entry->type) + return 0; + break; + } + + for (int i = 0; i < 4; i++) { + if (entry->unused[i]) { + if (op->comps.unused[i]) + score += 1; /* Operating on fewer components is better .. */ + else + return 0; /* .. but not too few! */ + } + } + + if (op->op == SWS_OP_CLEAR) { + /* Clear pattern must match exactly, regardless of `entry->flexible` */ + for (int i = 0; i < 4; i++) { + if (!next.unused[i] && entry->unused[i] != !!op->c.q4[i].den) + return 0; + } + } + + /* Flexible variants always match, but lower the score to prioritize more + * specific implementations if they exist */ + if (entry->flexible) + return score - 5; + + switch (op->op) { + case SWS_OP_INVALID: + return 0; + case SWS_OP_READ: + case SWS_OP_WRITE: + if (op->rw.elems != entry->rw.elems || + op->rw.frac != entry->rw.frac || + (op->rw.elems > 1 && op->rw.packed != entry->rw.packed)) + return 0; + return score; + case SWS_OP_SWAP_BYTES: + return score; + case SWS_OP_PACK: + case SWS_OP_UNPACK: + for (int i = 0; i < 4 && op->pack.pattern[i]; i++) { + if (op->pack.pattern[i] != entry->pack.pattern[i]) + return 0; + } + return score; + case SWS_OP_CLEAR: + for (int i = 0; i < 4; i++) { + if (!op->c.q4[i].den) + continue; + if (av_cmp_q(op->c.q4[i], Q(entry->clear_value)) && !next.unused[i]) + return 0; + } + return score; + case SWS_OP_LSHIFT: + case SWS_OP_RSHIFT: + av_assert1(entry->flexible); + break; + case SWS_OP_SWIZZLE: + for (int i = 0; i < 4; i++) { + if (op->swizzle.in[i] != entry->swizzle.in[i] && !next.unused[i]) + return 0; + } + return score; + case SWS_OP_CONVERT: + if (op->convert.to != entry->convert.to || + op->convert.expand != entry->convert.expand) + return 0; + return score; + case SWS_OP_DITHER: + return op->dither.size_log2 == entry->dither_size ? score : 0; + case SWS_OP_MIN: + case SWS_OP_MAX: + av_assert1(entry->flexible); + break; + case SWS_OP_LINEAR: + /* All required elements must be present */ + if (op->lin.mask & ~entry->linear_mask) + return 0; + /* To avoid operating on possibly undefined memory, filter out + * implementations that operate on more input components */ + for (int i = 0; i < 4; i++) { + if ((entry->linear_mask & SWS_MASK_COL(i)) && op->comps.unused[i]) + return 0; + } + /* Prioritize smaller implementations */ + score += av_popcount(SWS_MASK_ALL ^ entry->linear_mask); + return score; + case SWS_OP_SCALE: + return av_cmp_q(op->c.q, entry->scale) ? 0 : score; + case SWS_OP_TYPE_NB: + break; + } + + av_unreachable("Invalid operation type!"); + return 0; +} + +int ff_sws_op_compile_tables(const SwsOpTable *const tables[], int num_tables, + SwsOpList *ops, const int block_size, + SwsOpChain *chain) +{ + static const SwsOp dummy = { .comps.unused = { true, true, true, true }}; + const SwsOp *next = ops->num_ops > 1 ? &ops->ops[1] : &dummy; + const unsigned cpu_flags = av_get_cpu_flags(); + const SwsOpEntry *best = NULL; + const SwsOp *op = &ops->ops[0]; + int ret, best_score = 0, best_cpu_flags; + SwsOpPriv priv = {0}; + + for (int n = 0; n < num_tables; n++) { + const SwsOpTable *table = tables[n]; + if (table->block_size && table->block_size != block_size || + table->cpu_flags & ~cpu_flags) + continue; + + for (int i = 0; table->entries[i]; i++) { + const SwsOpEntry *entry = table->entries[i]; + int score = op_match(op, entry, next->comps); + if (score > best_score) { + best_score = score; + best_cpu_flags = table->cpu_flags; + best = entry; + } + } + } + + if (!best) + return AVERROR(ENOTSUP); + + if (best->setup) { + ret = best->setup(op, &priv); + if (ret < 0) + return ret; + } + + chain->cpu_flags |= best_cpu_flags; + ret = ff_sws_op_chain_append(chain, best->func, best->free, &priv); + if (ret < 0) { + if (best->free) + best->free(priv.ptr); + return ret; + } + + ops->ops++; + ops->num_ops--; + return ops->num_ops ? AVERROR(EAGAIN) : 0; +} + +#define q2pixel(type, q) ((q).den ? (type) (q).num / (q).den : 0) + +int ff_sws_setup_u8(const SwsOp *op, SwsOpPriv *out) +{ + out->u8[0] = op->c.u; + return 0; +} + +int ff_sws_setup_u(const SwsOp *op, SwsOpPriv *out) +{ + switch (op->type) { + case SWS_PIXEL_U8: out->u8[0] = op->c.u; return 0; + case SWS_PIXEL_U16: out->u16[0] = op->c.u; return 0; + case SWS_PIXEL_U32: out->u32[0] = op->c.u; return 0; + case SWS_PIXEL_F32: out->f32[0] = op->c.u; return 0; + default: return AVERROR(EINVAL); + } +} + +int ff_sws_setup_q(const SwsOp *op, SwsOpPriv *out) +{ + switch (op->type) { + case SWS_PIXEL_U8: out->u8[0] = q2pixel(uint8_t, op->c.q); return 0; + case SWS_PIXEL_U16: out->u16[0] = q2pixel(uint16_t, op->c.q); return 0; + case SWS_PIXEL_U32: out->u32[0] = q2pixel(uint32_t, op->c.q); return 0; + case SWS_PIXEL_F32: out->f32[0] = q2pixel(float, op->c.q); return 0; + default: return AVERROR(EINVAL); + } + + return 0; +} + +int ff_sws_setup_q4(const SwsOp *op, SwsOpPriv *out) +{ + for (int i = 0; i < 4; i++) { + switch (op->type) { + case SWS_PIXEL_U8: out->u8[i] = q2pixel(uint8_t, op->c.q4[i]); break; + case SWS_PIXEL_U16: out->u16[i] = q2pixel(uint16_t, op->c.q4[i]); break; + case SWS_PIXEL_U32: out->u32[i] = q2pixel(uint32_t, op->c.q4[i]); break; + case SWS_PIXEL_F32: out->f32[i] = q2pixel(float, op->c.q4[i]); break; + default: return AVERROR(EINVAL); + } + } + + return 0; +} diff --git a/libs/ffmpeg/libswscale/ops_chain.h b/libs/ffmpeg/libswscale/ops_chain.h new file mode 100644 index 00000000000..532622fd2ce --- /dev/null +++ b/libs/ffmpeg/libswscale/ops_chain.h @@ -0,0 +1,141 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_OPS_CHAIN_H +#define SWSCALE_OPS_CHAIN_H + +#include "libavutil/cpu.h" + +#include "ops_internal.h" + +/** + * Helpers for SIMD implementations based on chained kernels, using a + * continuation passing style to link them together. + * + * The basic idea here is to "link" together a series of different operation + * kernels by constructing a list of kernel addresses into an SwsOpChain. Each + * kernel will load the address of the next kernel (the "continuation") from + * this struct, and jump directly into it; using an internal function signature + * that is an implementation detail of the specific backend. + */ + +/** + * Private data for each kernel. + */ +typedef union SwsOpPriv { + DECLARE_ALIGNED_16(char, data)[16]; + + /* Common types */ + void *ptr; + int8_t i8[16]; + uint8_t u8[16]; + uint16_t u16[8]; + int16_t i16[8]; + uint32_t u32[4]; + float f32[4]; +} SwsOpPriv; + +static_assert(sizeof(SwsOpPriv) == 16, "SwsOpPriv size mismatch"); + +/* Setup helpers */ +int ff_sws_setup_u(const SwsOp *op, SwsOpPriv *out); +int ff_sws_setup_u8(const SwsOp *op, SwsOpPriv *out); +int ff_sws_setup_q(const SwsOp *op, SwsOpPriv *out); +int ff_sws_setup_q4(const SwsOp *op, SwsOpPriv *out); + +/** + * Per-kernel execution context. + * + * Note: This struct is hard-coded in assembly, so do not change the layout. + */ +typedef void (*SwsFuncPtr)(void); +typedef struct SwsOpImpl { + SwsFuncPtr cont; /* [offset = 0] Continuation for this operation. */ + SwsOpPriv priv; /* [offset = 16] Private data for this operation. */ +} SwsOpImpl; + +static_assert(sizeof(SwsOpImpl) == 32, "SwsOpImpl layout mismatch"); +static_assert(offsetof(SwsOpImpl, priv) == 16, "SwsOpImpl layout mismatch"); + +/** + * Compiled "chain" of operations, which can be dispatched efficiently. + * Effectively just a list of function pointers, alongside a small amount of + * private data for each operation. + */ +typedef struct SwsOpChain { +#define SWS_MAX_OPS 16 + SwsOpImpl impl[SWS_MAX_OPS + 1]; /* reserve extra space for the entrypoint */ + void (*free[SWS_MAX_OPS + 1])(void *); + int num_impl; + int cpu_flags; /* set of all used CPU flags */ +} SwsOpChain; + +SwsOpChain *ff_sws_op_chain_alloc(void); +void ff_sws_op_chain_free_cb(void *chain); +static inline void ff_sws_op_chain_free(SwsOpChain *chain) +{ + ff_sws_op_chain_free_cb(chain); +} + +/* Returns 0 on success, or a negative error code. */ +int ff_sws_op_chain_append(SwsOpChain *chain, SwsFuncPtr func, + void (*free)(void *), const SwsOpPriv *priv); + +typedef struct SwsOpEntry { + /* Kernel metadata; reduced size subset of SwsOp */ + SwsOpType op; + SwsPixelType type; + bool flexible; /* if true, only the type and op are matched */ + bool unused[4]; /* for kernels which operate on a subset of components */ + + union { /* extra data defining the operation, unless `flexible` is true */ + SwsReadWriteOp rw; + SwsPackOp pack; + SwsSwizzleOp swizzle; + SwsConvertOp convert; + uint32_t linear_mask; /* subset of SwsLinearOp */ + int dither_size; /* subset of SwsDitherOp */ + int clear_value; /* clear value for integer clears */ + AVRational scale; /* scale factor for SWS_OP_SCALE */ + }; + + /* Kernel implementation */ + SwsFuncPtr func; + int (*setup)(const SwsOp *op, SwsOpPriv *out); /* optional */ + void (*free)(void *priv); +} SwsOpEntry; + +typedef struct SwsOpTable { + unsigned cpu_flags; /* required CPU flags for this table */ + int block_size; /* fixed block size of this table */ + const SwsOpEntry *entries[]; /* terminated by NULL */ +} SwsOpTable; + +/** + * "Compile" a single op by looking it up in a list of fixed size op tables. + * See `op_match` in `ops_chain.c` for details on how the matching works. + * + * Returns 0, AVERROR(EAGAIN), or a negative error code. + */ +int ff_sws_op_compile_tables(const SwsOpTable *const tables[], int num_tables, + SwsOpList *ops, const int block_size, + SwsOpChain *chain); + +#endif diff --git a/libs/ffmpeg/libswscale/ops_dispatch.c b/libs/ffmpeg/libswscale/ops_dispatch.c new file mode 100644 index 00000000000..67ce225b829 --- /dev/null +++ b/libs/ffmpeg/libswscale/ops_dispatch.c @@ -0,0 +1,395 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/mem.h" +#include "libavutil/mem_internal.h" + +#include "ops.h" +#include "ops_internal.h" +#include "ops_dispatch.h" + +typedef struct SwsOpPass { + SwsCompiledOp comp; + SwsOpExec exec_base; + int num_blocks; + int tail_off_in; + int tail_off_out; + int tail_size_in; + int tail_size_out; + int planes_in; + int planes_out; + int pixel_bits_in; + int pixel_bits_out; + int idx_in[4]; + int idx_out[4]; + bool memcpy_in; + bool memcpy_out; +} SwsOpPass; + +int ff_sws_ops_compile_backend(SwsContext *ctx, const SwsOpBackend *backend, + const SwsOpList *ops, SwsCompiledOp *out) +{ + SwsOpList *copy; + SwsCompiledOp compiled = {0}; + int ret = 0; + + copy = ff_sws_op_list_duplicate(ops); + if (!copy) + return AVERROR(ENOMEM); + + /* Ensure these are always set during compilation */ + ff_sws_op_list_update_comps(copy); + + ret = backend->compile(ctx, copy, &compiled); + if (ret < 0) { + int msg_lev = ret == AVERROR(ENOTSUP) ? AV_LOG_TRACE : AV_LOG_ERROR; + av_log(ctx, msg_lev, "Backend '%s' failed to compile operations: %s\n", + backend->name, av_err2str(ret)); + } else { + *out = compiled; + } + + ff_sws_op_list_free(©); + return ret; +} + +int ff_sws_ops_compile(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out) +{ + for (int n = 0; ff_sws_op_backends[n]; n++) { + const SwsOpBackend *backend = ff_sws_op_backends[n]; + if (ops->src.hw_format != backend->hw_format || + ops->dst.hw_format != backend->hw_format) + continue; + if (ff_sws_ops_compile_backend(ctx, backend, ops, out) < 0) + continue; + + av_log(ctx, AV_LOG_VERBOSE, "Compiled using backend '%s': " + "block size = %d, over-read = %d, over-write = %d, cpu flags = 0x%x\n", + backend->name, out->block_size, out->over_read, out->over_write, + out->cpu_flags); + return 0; + } + + av_log(ctx, AV_LOG_WARNING, "No backend found for operations:\n"); + ff_sws_op_list_print(ctx, AV_LOG_WARNING, AV_LOG_TRACE, ops); + return AVERROR(ENOTSUP); +} + +static void op_pass_free(void *ptr) +{ + SwsOpPass *p = ptr; + if (!p) + return; + + if (p->comp.free) + p->comp.free(p->comp.priv); + + av_free(p); +} + +static inline void get_row_data(const SwsOpPass *p, const int y, + const uint8_t *in[4], uint8_t *out[4]) +{ + const SwsOpExec *base = &p->exec_base; + for (int i = 0; i < p->planes_in; i++) + in[i] = base->in[i] + (y >> base->in_sub_y[i]) * base->in_stride[i]; + for (int i = 0; i < p->planes_out; i++) + out[i] = base->out[i] + (y >> base->out_sub_y[i]) * base->out_stride[i]; +} + +static void op_pass_setup(const SwsFrame *out, const SwsFrame *in, + const SwsPass *pass) +{ + const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(in->format); + const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out->format); + + SwsOpPass *p = pass->priv; + SwsOpExec *exec = &p->exec_base; + const SwsCompiledOp *comp = &p->comp; + const int block_size = comp->block_size; + p->num_blocks = (pass->width + block_size - 1) / block_size; + + /* Set up main loop parameters */ + const int aligned_w = p->num_blocks * block_size; + const int safe_width = (p->num_blocks - 1) * block_size; + const int tail_size = pass->width - safe_width; + p->tail_off_in = safe_width * p->pixel_bits_in >> 3; + p->tail_off_out = safe_width * p->pixel_bits_out >> 3; + p->tail_size_in = tail_size * p->pixel_bits_in >> 3; + p->tail_size_out = tail_size * p->pixel_bits_out >> 3; + p->memcpy_in = false; + p->memcpy_out = false; + + for (int i = 0; i < p->planes_in; i++) { + const int idx = p->idx_in[i]; + const int chroma = idx == 1 || idx == 2; + const int sub_x = chroma ? indesc->log2_chroma_w : 0; + const int sub_y = chroma ? indesc->log2_chroma_h : 0; + const int plane_w = (aligned_w + sub_x) >> sub_x; + const int plane_pad = (comp->over_read + sub_x) >> sub_x; + const int plane_size = plane_w * p->pixel_bits_in >> 3; + if (comp->slice_align) + p->memcpy_in |= plane_size + plane_pad > in->linesize[idx]; + exec->in[i] = in->data[idx]; + exec->in_stride[i] = in->linesize[idx]; + exec->in_sub_y[i] = sub_y; + exec->in_sub_x[i] = sub_x; + } + + for (int i = 0; i < p->planes_out; i++) { + const int idx = p->idx_out[i]; + const int chroma = idx == 1 || idx == 2; + const int sub_x = chroma ? outdesc->log2_chroma_w : 0; + const int sub_y = chroma ? outdesc->log2_chroma_h : 0; + const int plane_w = (aligned_w + sub_x) >> sub_x; + const int plane_pad = (comp->over_write + sub_x) >> sub_x; + const int plane_size = plane_w * p->pixel_bits_out >> 3; + if (comp->slice_align) + p->memcpy_out |= plane_size + plane_pad > out->linesize[idx]; + exec->out[i] = out->data[idx]; + exec->out_stride[i] = out->linesize[idx]; + exec->out_sub_y[i] = sub_y; + exec->out_sub_x[i] = sub_x; + } + + /* Pre-fill pointer bump for the main section only; this value does not + * matter at all for the tail / last row handlers because they only ever + * process a single line */ + const int blocks_main = p->num_blocks - p->memcpy_out; + for (int i = 0; i < 4; i++) { + exec->in_bump[i] = exec->in_stride[i] - blocks_main * exec->block_size_in; + exec->out_bump[i] = exec->out_stride[i] - blocks_main * exec->block_size_out; + } + + exec->in_frame = in; + exec->out_frame = out; +} + +/* Dispatch kernel over the last column of the image using memcpy */ +static av_always_inline void +handle_tail(const SwsOpPass *p, SwsOpExec *exec, + const bool copy_out, const bool copy_in, + int y, const int h) +{ + DECLARE_ALIGNED_64(uint8_t, tmp)[2][4][sizeof(uint32_t[128])]; + + const SwsOpExec *base = &p->exec_base; + const SwsCompiledOp *comp = &p->comp; + const int tail_size_in = p->tail_size_in; + const int tail_size_out = p->tail_size_out; + const int bx = p->num_blocks - 1; + + const uint8_t *in_data[4]; + uint8_t *out_data[4]; + get_row_data(p, y, in_data, out_data); + + for (int i = 0; i < p->planes_in; i++) { + in_data[i] += p->tail_off_in; + if (copy_in) { + exec->in[i] = (void *) tmp[0][i]; + exec->in_stride[i] = sizeof(tmp[0][i]); + } else { + exec->in[i] = in_data[i]; + } + } + + for (int i = 0; i < p->planes_out; i++) { + out_data[i] += p->tail_off_out; + if (copy_out) { + exec->out[i] = (void *) tmp[1][i]; + exec->out_stride[i] = sizeof(tmp[1][i]); + } else { + exec->out[i] = out_data[i]; + } + } + + for (int y_end = y + h; y < y_end; y++) { + if (copy_in) { + for (int i = 0; i < p->planes_in; i++) { + av_assert2(tmp[0][i] + tail_size_in < (uint8_t *) tmp[1]); + memcpy(tmp[0][i], in_data[i], tail_size_in); + in_data[i] += base->in_stride[i]; /* exec->in_stride was clobbered */ + } + } + + comp->func(exec, comp->priv, bx, y, p->num_blocks, y + 1); + + if (copy_out) { + for (int i = 0; i < p->planes_out; i++) { + av_assert2(tmp[1][i] + tail_size_out < (uint8_t *) tmp[2]); + memcpy(out_data[i], tmp[1][i], tail_size_out); + out_data[i] += base->out_stride[i]; + } + } + + for (int i = 0; i < 4; i++) { + if (!copy_in && exec->in[i]) + exec->in[i] += exec->in_stride[i]; + if (!copy_out && exec->out[i]) + exec->out[i] += exec->out_stride[i]; + } + } +} + +static void op_pass_run(const SwsFrame *out, const SwsFrame *in, const int y, + const int h, const SwsPass *pass) +{ + const SwsOpPass *p = pass->priv; + const SwsCompiledOp *comp = &p->comp; + + /* Fill exec metadata for this slice */ + DECLARE_ALIGNED_32(SwsOpExec, exec) = p->exec_base; + exec.slice_y = y; + exec.slice_h = h; + + /** + * To ensure safety, we need to consider the following: + * + * 1. We can overread the input, unless this is the last line of an + * unpadded buffer. All defined operations can handle arbitrary pixel + * input, so overread of arbitrary data is fine. + * + * 2. We can overwrite the output, as long as we don't write more than the + * amount of pixels that fit into one linesize. So we always need to + * memcpy the last column on the output side if unpadded. + * + * 3. For the last row, we also need to memcpy the remainder of the input, + * to avoid reading past the end of the buffer. Note that since we know + * the run() function is called on stripes of the same buffer, we don't + * need to worry about this for the end of a slice. + */ + + const int last_slice = y + h == pass->height; + const bool memcpy_in = last_slice && p->memcpy_in; + const bool memcpy_out = p->memcpy_out; + const int num_blocks = p->num_blocks; + const int blocks_main = num_blocks - memcpy_out; + const int h_main = h - memcpy_in; + + /* Handle main section */ + get_row_data(p, y, exec.in, exec.out); + comp->func(&exec, comp->priv, 0, y, blocks_main, y + h_main); + + if (memcpy_in) { + /* Safe part of last row */ + get_row_data(p, y + h_main, exec.in, exec.out); + comp->func(&exec, comp->priv, 0, y + h_main, num_blocks - 1, y + h); + } + + /* Handle last column via memcpy, takes over `exec` so call these last */ + if (memcpy_out) + handle_tail(p, &exec, true, false, y, h_main); + if (memcpy_in) + handle_tail(p, &exec, memcpy_out, true, y + h_main, 1); +} + +static int rw_planes(const SwsOp *op) +{ + return op->rw.packed ? 1 : op->rw.elems; +} + +static int rw_pixel_bits(const SwsOp *op) +{ + const int elems = op->rw.packed ? op->rw.elems : 1; + const int size = ff_sws_pixel_type_size(op->type); + const int bits = 8 >> op->rw.frac; + av_assert1(bits >= 1); + return elems * size * bits; +} + +static int compile(SwsGraph *graph, const SwsOpList *ops, + const SwsFormat *dst, SwsPass *input, SwsPass **output) +{ + SwsContext *ctx = graph->ctx; + SwsOpPass *p = av_mallocz(sizeof(*p)); + if (!p) + return AVERROR(ENOMEM); + + int ret = ff_sws_ops_compile(ctx, ops, &p->comp); + if (ret < 0) + goto fail; + + const SwsOp *read = ff_sws_op_list_input(ops); + const SwsOp *write = ff_sws_op_list_output(ops); + p->planes_in = rw_planes(read); + p->planes_out = rw_planes(write); + p->pixel_bits_in = rw_pixel_bits(read); + p->pixel_bits_out = rw_pixel_bits(write); + p->exec_base = (SwsOpExec) { + .width = dst->width, + .height = dst->height, + .block_size_in = p->comp.block_size * p->pixel_bits_in >> 3, + .block_size_out = p->comp.block_size * p->pixel_bits_out >> 3, + }; + + for (int i = 0; i < 4; i++) { + p->idx_in[i] = i < p->planes_in ? ops->order_src.in[i] : -1; + p->idx_out[i] = i < p->planes_out ? ops->order_dst.in[i] : -1; + } + + SwsPass *pass; + ret = ff_sws_graph_add_pass(graph, dst->format, dst->width, dst->height, + input, p->comp.slice_align, p, op_pass_run, + &pass); + if (ret < 0) + goto fail; + + pass->setup = op_pass_setup; + pass->free = op_pass_free; + + *output = pass; + return 0; + +fail: + op_pass_free(p); + return ret; +} + +int ff_sws_compile_pass(SwsGraph *graph, SwsOpList *ops, int flags, + const SwsFormat *dst, SwsPass *input, SwsPass **output) +{ + SwsContext *ctx = graph->ctx; + int ret; + + /* Check if the whole operation graph is an end-to-end no-op */ + if (ff_sws_op_list_is_noop(ops)) { + *output = input; + return 0; + } + + const SwsOp *read = ff_sws_op_list_input(ops); + const SwsOp *write = ff_sws_op_list_output(ops); + if (!read || !write) { + av_log(ctx, AV_LOG_ERROR, "First and last operations must be a read " + "and write, respectively.\n"); + return AVERROR(EINVAL); + } + + if (flags & SWS_OP_FLAG_OPTIMIZE) { + ret = ff_sws_op_list_optimize(ops); + if (ret < 0) + return ret; + } else { + ff_sws_op_list_update_comps(ops); + } + + return compile(graph, ops, dst, input, output); +} diff --git a/libs/ffmpeg/libswscale/ops_dispatch.h b/libs/ffmpeg/libswscale/ops_dispatch.h new file mode 100644 index 00000000000..270ff09e313 --- /dev/null +++ b/libs/ffmpeg/libswscale/ops_dispatch.h @@ -0,0 +1,94 @@ +/** + * Copyright (C) 2026 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_OPS_DISPATCH_H +#define SWSCALE_OPS_DISPATCH_H + +#include <assert.h> + +#include "libavutil/frame.h" +#include "graph.h" + +/** + * Global execution context for all compiled functions. + * + * Note: This struct is hard-coded in assembly, so do not change the layout + * without updating the corresponding assembly definitions. + */ +typedef struct SwsOpExec { + /* The data pointers point to the first pixel to process */ + const uint8_t *in[4]; + uint8_t *out[4]; + + /* Separation between lines in bytes */ + ptrdiff_t in_stride[4]; + ptrdiff_t out_stride[4]; + + /* Pointer bump, difference between stride and processed line size */ + ptrdiff_t in_bump[4]; + ptrdiff_t out_bump[4]; + + /* Extra metadata, may or may not be useful */ + int32_t width, height; /* Overall image dimensions */ + int32_t slice_y, slice_h; /* Start and height of current slice */ + int32_t block_size_in; /* Size of a block of pixels in bytes */ + int32_t block_size_out; + + /* Subsampling factors for each plane */ + uint8_t in_sub_y[4], out_sub_y[4]; + uint8_t in_sub_x[4], out_sub_x[4]; + + /* Pointers back to the original SwsFrame */ + const SwsFrame *in_frame; + const SwsFrame *out_frame; +} SwsOpExec; + +static_assert(sizeof(SwsOpExec) == 24 * sizeof(void *) + + 6 * sizeof(int32_t) + + 16 * sizeof(uint8_t) + + 2 * sizeof(void *), + "SwsOpExec layout mismatch"); + +/** + * Process a given range of pixel blocks. + * + * Note: `bx_start` and `bx_end` are in units of `SwsCompiledOp.block_size`. + */ +typedef void (*SwsOpFunc)(const SwsOpExec *exec, const void *priv, + int bx_start, int y_start, int bx_end, int y_end); + +#define SWS_DECL_FUNC(NAME) \ + void NAME(const SwsOpExec *, const void *, int, int, int, int) + +typedef struct SwsCompiledOp { + SwsOpFunc func; + + int slice_align; /* slice height alignment */ + int block_size; /* number of pixels processed per iteration */ + int over_read; /* implementation over-reads input by this many bytes */ + int over_write; /* implementation over-writes output by this many bytes */ + int cpu_flags; /* active set of CPU flags (informative) */ + + /* Arbitrary private data */ + void *priv; + void (*free)(void *priv); +} SwsCompiledOp; + +#endif /* SWSCALE_OPS_DISPATCH_H */ diff --git a/libs/ffmpeg/libswscale/ops_internal.h b/libs/ffmpeg/libswscale/ops_internal.h new file mode 100644 index 00000000000..3db850c290e --- /dev/null +++ b/libs/ffmpeg/libswscale/ops_internal.h @@ -0,0 +1,120 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_OPS_INTERNAL_H +#define SWSCALE_OPS_INTERNAL_H + +#include "libavutil/mem_internal.h" + +#include "ops.h" +#include "ops_dispatch.h" + +#define Q(N) ((AVRational) { N, 1 }) + +static inline AVRational ff_sws_pixel_expand(SwsPixelType from, SwsPixelType to) +{ + const int src = ff_sws_pixel_type_size(from); + const int dst = ff_sws_pixel_type_size(to); + if (src > dst) + return Q(0); + int scale = 1; + for (int i = 1; i < dst / src; i++) + scale = (scale << (src * 8)) | 1; + return Q(scale); +} + +static inline void ff_sws_pack_op_decode(const SwsOp *op, uint64_t mask[4], int shift[4]) +{ + int size = 0; + for (int i = 0; i < 4; i++) + size += op->pack.pattern[i]; + for (int i = 0; i < 4; i++) { + const int bits = op->pack.pattern[i]; + mask[i] = (UINT64_C(1) << bits) - 1; + shift[i] = (i ? shift[i - 1] : size) - bits; + } +} + +typedef struct SwsOpBackend { + const char *name; /* Descriptive name for this backend */ + + /** + * Compile an operation list to an implementation chain. May modify `ops` + * freely; the original list will be freed automatically by the caller. + * + * Returns 0 or a negative error code. + */ + int (*compile)(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out); + + /** + * If NONE, backend only supports software frames. + * Otherwise, frame hardware format must match hw_format for the backend + * to be used. + */ + enum AVPixelFormat hw_format; +} SwsOpBackend; + +/* List of all backends, terminated by NULL */ +extern const SwsOpBackend *const ff_sws_op_backends[]; + +/** + * Attempt to compile a list of operations using a specific backend. + * + * Returns 0 on success, or a negative error code on failure. + */ +int ff_sws_ops_compile_backend(SwsContext *ctx, const SwsOpBackend *backend, + const SwsOpList *ops, SwsCompiledOp *out); + +/** + * Compile a list of operations using the best available backend. + * + * Returns 0 on success, or a negative error code on failure. + */ +int ff_sws_ops_compile(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out); + +/** + * "Solve" an op list into a fixed shuffle mask, with an optional ability to + * also directly clear the output value (for e.g. rgb24 -> rgb0). This can + * accept any operation chain that only consists of the following operations: + * + * - SWS_OP_READ (non-planar, non-fractional) + * - SWS_OP_SWIZZLE + * - SWS_OP_SWAP_BYTES + * - SWS_OP_CLEAR to zero (when clear_val is specified) + * - SWS_OP_CONVERT (integer expand) + * - SWS_OP_WRITE (non-planar, non-fractional) + * + * Basically, any operation that purely consists of moving around and reordering + * bytes within a single plane, can be turned into a shuffle mask. + * + * @param ops The operation list to decompose. + * @param shuffle The output shuffle mask. + * @param size The size (in bytes) of the output shuffle mask. + * @param clear_val If nonzero, this index will be used to clear the output. + * @param read_bytes Returns the number of bytes read per shuffle iteration. + * @param write_bytes Returns the number of bytes written per shuffle iteration. + * + * @return The number of pixels processed per iteration, or a negative error + code; in particular AVERROR(ENOTSUP) for unsupported operations. + */ +int ff_sws_solve_shuffle(const SwsOpList *ops, uint8_t shuffle[], int size, + uint8_t clear_val, int *read_bytes, int *write_bytes); + +#endif /* SWSCALE_OPS_INTERNAL_H */ diff --git a/libs/ffmpeg/libswscale/ops_memcpy.c b/libs/ffmpeg/libswscale/ops_memcpy.c new file mode 100644 index 00000000000..fd8b79ec343 --- /dev/null +++ b/libs/ffmpeg/libswscale/ops_memcpy.c @@ -0,0 +1,134 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" + +#include "ops_backend.h" + +typedef struct MemcpyPriv { + int num_planes; + int index[4]; /* or -1 to clear plane */ + uint8_t clear_value[4]; +} MemcpyPriv; + +/* Memcpy backend for trivial cases */ + +static void process(const SwsOpExec *exec, const void *priv, + int x_start, int y_start, int x_end, int y_end) +{ + const MemcpyPriv *p = priv; + const int lines = y_end - y_start; + av_assert1(x_start == 0 && x_end == exec->width); + + for (int i = 0; i < p->num_planes; i++) { + uint8_t *out = exec->out[i]; + const int idx = p->index[i]; + if (idx < 0) { + memset(out, p->clear_value[i], exec->out_stride[i] * lines); + } else if (exec->out_stride[i] == exec->in_stride[idx]) { + memcpy(out, exec->in[idx], exec->out_stride[i] * lines); + } else { + const int bytes = x_end * exec->block_size_out; + const uint8_t *in = exec->in[idx]; + for (int y = y_start; y < y_end; y++) { + memcpy(out, in, bytes); + out += exec->out_stride[i]; + in += exec->in_stride[idx]; + } + } + } +} + +static int compile(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out) +{ + MemcpyPriv p = {0}; + + for (int n = 0; n < ops->num_ops; n++) { + const SwsOp *op = &ops->ops[n]; + switch (op->op) { + case SWS_OP_READ: + if ((op->rw.packed && op->rw.elems != 1) || op->rw.frac) + return AVERROR(ENOTSUP); + for (int i = 0; i < op->rw.elems; i++) + p.index[i] = i; + break; + + case SWS_OP_SWIZZLE: { + const MemcpyPriv orig = p; + for (int i = 0; i < 4; i++) { + /* Explicitly exclude swizzle masks that contain duplicates, + * because these are wasteful to implement as a memcpy */ + for (int j = 0; j < i; j++) { + if (op->swizzle.in[i] == op->swizzle.in[j]) + return AVERROR(ENOTSUP); + } + p.index[i] = orig.index[op->swizzle.in[i]]; + } + break; + } + + case SWS_OP_CLEAR: + for (int i = 0; i < 4; i++) { + if (!op->c.q4[i].den) + continue; + if (op->c.q4[i].den != 1) + return AVERROR(ENOTSUP); + + /* Ensure all bytes to be cleared are the same, because we + * can't memset on multi-byte sequences */ + uint8_t val = op->c.q4[i].num & 0xFF; + uint32_t ref = val; + switch (ff_sws_pixel_type_size(op->type)) { + case 2: ref *= 0x101; break; + case 4: ref *= 0x1010101; break; + } + if (ref != op->c.q4[i].num) + return AVERROR(ENOTSUP); + p.clear_value[i] = val; + p.index[i] = -1; + } + break; + + case SWS_OP_WRITE: + if ((op->rw.packed && op->rw.elems != 1) || op->rw.frac) + return AVERROR(ENOTSUP); + p.num_planes = op->rw.elems; + break; + + default: + return AVERROR(ENOTSUP); + } + } + + *out = (SwsCompiledOp) { + .slice_align = 1, + .block_size = 1, + .func = process, + .priv = av_memdup(&p, sizeof(p)), + .free = av_free, + }; + return out->priv ? 0 : AVERROR(ENOMEM); +} + +const SwsOpBackend backend_murder = { + .name = "memcpy", + .compile = compile, + .hw_format = AV_PIX_FMT_NONE, +}; diff --git a/libs/ffmpeg/libswscale/ops_optimizer.c b/libs/ffmpeg/libswscale/ops_optimizer.c new file mode 100644 index 00000000000..abba9df2ffc --- /dev/null +++ b/libs/ffmpeg/libswscale/ops_optimizer.c @@ -0,0 +1,778 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/bswap.h" +#include "libavutil/rational.h" + +#include "ops.h" +#include "ops_internal.h" + +#define RET(x) \ + do { \ + if ((ret = (x)) < 0) \ + return ret; \ + } while (0) + +/** + * Try to commute a clear op with the next operation. Makes any adjustments + * to the operations as needed, but does not perform the actual commutation. + * + * Returns whether successful. + */ +static bool op_commute_clear(SwsOp *op, SwsOp *next) +{ + SwsOp tmp; + + av_assert1(op->op == SWS_OP_CLEAR); + switch (next->op) { + case SWS_OP_CONVERT: + op->type = next->convert.to; + /* fall through */ + case SWS_OP_LSHIFT: + case SWS_OP_RSHIFT: + case SWS_OP_DITHER: + case SWS_OP_MIN: + case SWS_OP_MAX: + case SWS_OP_SCALE: + case SWS_OP_READ: + case SWS_OP_SWIZZLE: + ff_sws_apply_op_q(next, op->c.q4); + return true; + case SWS_OP_SWAP_BYTES: + switch (next->type) { + case SWS_PIXEL_U16: + ff_sws_apply_op_q(next, op->c.q4); /* always works */ + return true; + case SWS_PIXEL_U32: + for (int i = 0; i < 4; i++) { + uint32_t v = av_bswap32(op->c.q4[i].num); + if (v > INT_MAX) + return false; /* can't represent as AVRational anymore */ + tmp.c.q4[i] = Q(v); + } + op->c = tmp.c; + return true; + default: + return false; + } + case SWS_OP_INVALID: + case SWS_OP_WRITE: + case SWS_OP_LINEAR: + case SWS_OP_PACK: + case SWS_OP_UNPACK: + case SWS_OP_CLEAR: + return false; + case SWS_OP_TYPE_NB: + break; + } + + av_unreachable("Invalid operation type!"); + return false; +} + + /** + * Try to commute a swizzle op with the next operation. Makes any adjustments + * to the operations as needed, but does not perform the actual commutation. + * + * Returns whether successful. + */ +static bool op_commute_swizzle(SwsOp *op, SwsOp *next) +{ + bool seen[4] = {0}; + + av_assert1(op->op == SWS_OP_SWIZZLE); + switch (next->op) { + case SWS_OP_CONVERT: + op->type = next->convert.to; + /* fall through */ + case SWS_OP_SWAP_BYTES: + case SWS_OP_LSHIFT: + case SWS_OP_RSHIFT: + case SWS_OP_SCALE: + return true; + + /** + * We can commute per-channel ops only if the per-channel constants are the + * same for all duplicated channels; e.g.: + * SWIZZLE {0, 0, 0, 3} + * NEXT {x, x, x, w} + * -> + * NEXT {x, _, _, w} + * SWIZZLE {0, 0, 0, 3} + */ + case SWS_OP_MIN: + case SWS_OP_MAX: { + const SwsConst c = next->c; + for (int i = 0; i < 4; i++) { + if (next->comps.unused[i]) + continue; + const int j = op->swizzle.in[i]; + if (seen[j] && av_cmp_q(next->c.q4[j], c.q4[i])) + return false; + next->c.q4[j] = c.q4[i]; + seen[j] = true; + } + return true; + } + + case SWS_OP_DITHER: { + const SwsDitherOp d = next->dither; + for (int i = 0; i < 4; i++) { + if (next->comps.unused[i]) + continue; + const int j = op->swizzle.in[i]; + if (seen[j] && next->dither.y_offset[j] != d.y_offset[i]) + return false; + next->dither.y_offset[j] = d.y_offset[i]; + seen[j] = true; + } + return true; + } + + case SWS_OP_INVALID: + case SWS_OP_READ: + case SWS_OP_WRITE: + case SWS_OP_SWIZZLE: + case SWS_OP_CLEAR: + case SWS_OP_LINEAR: + case SWS_OP_PACK: + case SWS_OP_UNPACK: + return false; + case SWS_OP_TYPE_NB: + break; + } + + av_unreachable("Invalid operation type!"); + return false; +} + +/* returns log2(x) only if x is a power of two, or 0 otherwise */ +static int exact_log2(const int x) +{ + int p; + if (x <= 0) + return 0; + p = av_log2(x); + return (1 << p) == x ? p : 0; +} + +static int exact_log2_q(const AVRational x) +{ + if (x.den == 1) + return exact_log2(x.num); + else if (x.num == 1) + return -exact_log2(x.den); + else + return 0; +} + +/** + * If a linear operation can be reduced to a scalar multiplication, returns + * the corresponding scaling factor, or 0 otherwise. + */ +static bool extract_scalar(const SwsLinearOp *c, SwsComps prev, SwsComps next, + SwsConst *out_scale) +{ + SwsConst scale = {0}; + + /* There are components not on the main diagonal */ + if (c->mask & ~SWS_MASK_DIAG4) + return false; + + for (int i = 0; i < 4; i++) { + const AVRational s = c->m[i][i]; + if ((prev.flags[i] & SWS_COMP_ZERO) || next.unused[i]) + continue; + if (scale.q.den && av_cmp_q(s, scale.q)) + return false; + scale.q = s; + } + + if (scale.q.den) + *out_scale = scale; + return scale.q.den; +} + +/* Extracts an integer clear operation (subset) from the given linear op. */ +static bool extract_constant_rows(SwsLinearOp *c, SwsComps prev, + SwsConst *out_clear) +{ + SwsConst clear = {0}; + bool ret = false; + + for (int i = 0; i < 4; i++) { + bool const_row = c->m[i][4].den == 1; /* offset is integer */ + for (int j = 0; j < 4; j++) { + const_row &= c->m[i][j].num == 0 || /* scalar is zero */ + (prev.flags[j] & SWS_COMP_ZERO); /* input is zero */ + } + if (const_row && (c->mask & SWS_MASK_ROW(i))) { + clear.q4[i] = c->m[i][4]; + for (int j = 0; j < 5; j++) + c->m[i][j] = Q(i == j); + c->mask &= ~SWS_MASK_ROW(i); + ret = true; + } + } + + if (ret) + *out_clear = clear; + return ret; +} + +/* Unswizzle a linear operation by aligning single-input rows with + * their corresponding diagonal */ +static bool extract_swizzle(SwsLinearOp *op, SwsComps prev, SwsSwizzleOp *out_swiz) +{ + SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3); + SwsLinearOp c = *op; + + /* Find non-zero coefficients in the main 4x4 matrix */ + uint32_t nonzero = 0; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + if (!c.m[i][j].num || (prev.flags[j] & SWS_COMP_ZERO)) + continue; + nonzero |= SWS_MASK(i, j); + } + } + + /* If a value is unique in its row and the target column is + * empty, move it there and update the input swizzle */ + for (int i = 0; i < 4; i++) { + if (nonzero & SWS_MASK_COL(i)) + continue; /* target column is not empty */ + for (int j = 0; j < 4; j++) { + if ((nonzero & SWS_MASK_ROW(i)) == SWS_MASK(i, j)) { + /* Move coefficient to the diagonal */ + c.m[i][i] = c.m[i][j]; + c.m[i][j] = Q(0); + swiz.in[i] = j; + break; + } + } + } + + if (swiz.mask == SWS_SWIZZLE(0, 1, 2, 3).mask) + return false; /* no swizzle was identified */ + + c.mask = ff_sws_linear_mask(c); + *out_swiz = swiz; + *op = c; + return true; +} + +int ff_sws_op_list_optimize(SwsOpList *ops) +{ + int ret; + +retry: + ff_sws_op_list_update_comps(ops); + + /* Apply all in-place optimizations (that do not re-order the list) */ + for (int n = 0; n < ops->num_ops; n++) { + SwsOp dummy = {0}; + SwsOp *op = &ops->ops[n]; + SwsOp *prev = n ? &ops->ops[n - 1] : &dummy; + SwsOp *next = n + 1 < ops->num_ops ? &ops->ops[n + 1] : &dummy; + + /* common helper variable */ + bool noop = true; + + if (next->comps.unused[0] && next->comps.unused[1] && + next->comps.unused[2] && next->comps.unused[3]) + { + /* Remove completely unused operations */ + ff_sws_op_list_remove_at(ops, n, 1); + goto retry; + } + + switch (op->op) { + case SWS_OP_READ: + /* "Compress" planar reads where not all components are needed */ + if (!op->rw.packed) { + SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3); + int nb_planes = 0; + for (int i = 0; i < op->rw.elems; i++) { + if (next->comps.unused[i]) { + swiz.in[i] = 3 - (i - nb_planes); /* map to unused plane */ + continue; + } + + const int idx = nb_planes++; + av_assert1(idx <= i); + ops->order_src.in[idx] = ops->order_src.in[i]; + swiz.in[i] = idx; + } + + if (nb_planes < op->rw.elems) { + op->rw.elems = nb_planes; + RET(ff_sws_op_list_insert_at(ops, n + 1, &(SwsOp) { + .op = SWS_OP_SWIZZLE, + .type = op->type, + .swizzle = swiz, + })); + goto retry; + } + } + break; + + case SWS_OP_SWAP_BYTES: + /* Redundant (double) swap */ + if (next->op == SWS_OP_SWAP_BYTES) { + ff_sws_op_list_remove_at(ops, n, 2); + goto retry; + } + break; + + case SWS_OP_UNPACK: + /* Redundant unpack+pack */ + if (next->op == SWS_OP_PACK && next->type == op->type && + next->pack.pattern[0] == op->pack.pattern[0] && + next->pack.pattern[1] == op->pack.pattern[1] && + next->pack.pattern[2] == op->pack.pattern[2] && + next->pack.pattern[3] == op->pack.pattern[3]) + { + ff_sws_op_list_remove_at(ops, n, 2); + goto retry; + } + break; + + case SWS_OP_LSHIFT: + case SWS_OP_RSHIFT: + /* Two shifts in the same direction */ + if (next->op == op->op) { + op->c.u += next->c.u; + ff_sws_op_list_remove_at(ops, n + 1, 1); + goto retry; + } + + /* No-op shift */ + if (!op->c.u) { + ff_sws_op_list_remove_at(ops, n, 1); + goto retry; + } + break; + + case SWS_OP_CLEAR: + for (int i = 0; i < 4; i++) { + if (!op->c.q4[i].den) + continue; + + if ((prev->comps.flags[i] & SWS_COMP_ZERO) && + !(prev->comps.flags[i] & SWS_COMP_GARBAGE) && + op->c.q4[i].num == 0) + { + /* Redundant clear-to-zero of zero component */ + op->c.q4[i].den = 0; + } else if (next->comps.unused[i]) { + /* Unnecessary clear of unused component */ + op->c.q4[i] = (AVRational) {0, 0}; + } else if (op->c.q4[i].den) { + noop = false; + } + } + + if (noop) { + ff_sws_op_list_remove_at(ops, n, 1); + goto retry; + } + + /* Transitive clear */ + if (next->op == SWS_OP_CLEAR) { + for (int i = 0; i < 4; i++) { + if (next->c.q4[i].den) + op->c.q4[i] = next->c.q4[i]; + } + ff_sws_op_list_remove_at(ops, n + 1, 1); + goto retry; + } + break; + + case SWS_OP_SWIZZLE: + for (int i = 0; i < 4; i++) { + if (next->comps.unused[i]) + continue; + if (op->swizzle.in[i] != i) + noop = false; + } + + /* Identity swizzle */ + if (noop) { + ff_sws_op_list_remove_at(ops, n, 1); + goto retry; + } + + /* Transitive swizzle */ + if (next->op == SWS_OP_SWIZZLE) { + const SwsSwizzleOp orig = op->swizzle; + for (int i = 0; i < 4; i++) + op->swizzle.in[i] = orig.in[next->swizzle.in[i]]; + ff_sws_op_list_remove_at(ops, n + 1, 1); + goto retry; + } + + /* Swizzle planes instead of components, if possible */ + if (prev->op == SWS_OP_READ && !prev->rw.packed) { + for (int dst = 0; dst < prev->rw.elems; dst++) { + const int src = op->swizzle.in[dst]; + if (src > dst && src < prev->rw.elems) { + FFSWAP(int, ops->order_src.in[dst], ops->order_src.in[src]); + for (int i = dst; i < 4; i++) { + if (op->swizzle.in[i] == dst) + op->swizzle.in[i] = src; + else if (op->swizzle.in[i] == src) + op->swizzle.in[i] = dst; + } + goto retry; + } + } + } + + if (next->op == SWS_OP_WRITE && !next->rw.packed) { + for (int dst = 0; dst < next->rw.elems; dst++) { + const int src = op->swizzle.in[dst]; + if (src > dst && src < next->rw.elems) { + FFSWAP(int, ops->order_dst.in[dst], ops->order_dst.in[src]); + FFSWAP(int, op->swizzle.in[dst], op->swizzle.in[src]); + goto retry; + } + } + } + break; + + case SWS_OP_CONVERT: + /* No-op conversion */ + if (op->type == op->convert.to) { + ff_sws_op_list_remove_at(ops, n, 1); + goto retry; + } + + /* Transitive conversion */ + if (next->op == SWS_OP_CONVERT && + op->convert.expand == next->convert.expand) + { + av_assert1(op->convert.to == next->type); + op->convert.to = next->convert.to; + ff_sws_op_list_remove_at(ops, n + 1, 1); + goto retry; + } + + /* Conversion followed by integer expansion */ + if (next->op == SWS_OP_SCALE && !op->convert.expand && + ff_sws_pixel_type_is_int(op->type) && + ff_sws_pixel_type_is_int(op->convert.to) && + !av_cmp_q(next->c.q, ff_sws_pixel_expand(op->type, op->convert.to))) + { + op->convert.expand = true; + ff_sws_op_list_remove_at(ops, n + 1, 1); + goto retry; + } + break; + + case SWS_OP_MIN: + for (int i = 0; i < 4; i++) { + if (next->comps.unused[i] || !op->c.q4[i].den) + continue; + if (av_cmp_q(op->c.q4[i], prev->comps.max[i]) < 0) + noop = false; + } + + if (noop) { + ff_sws_op_list_remove_at(ops, n, 1); + goto retry; + } + break; + + case SWS_OP_MAX: + for (int i = 0; i < 4; i++) { + if (next->comps.unused[i] || !op->c.q4[i].den) + continue; + if (av_cmp_q(prev->comps.min[i], op->c.q4[i]) < 0) + noop = false; + } + + if (noop) { + ff_sws_op_list_remove_at(ops, n, 1); + goto retry; + } + break; + + case SWS_OP_DITHER: + for (int i = 0; i < 4; i++) { + if (next->comps.unused[i] || op->dither.y_offset[i] < 0) + continue; + if (prev->comps.flags[i] & SWS_COMP_EXACT) { + op->dither.y_offset[i] = -1; /* unnecessary dither */ + goto retry; + } else { + noop = false; + } + } + + if (noop) { + ff_sws_op_list_remove_at(ops, n, 1); + goto retry; + } + break; + + case SWS_OP_LINEAR: { + SwsSwizzleOp swizzle; + SwsConst c; + + /* No-op (identity) linear operation */ + if (!op->lin.mask) { + ff_sws_op_list_remove_at(ops, n, 1); + goto retry; + } + + if (next->op == SWS_OP_LINEAR) { + /* 5x5 matrix multiplication after appending [ 0 0 0 0 1 ] */ + const SwsLinearOp m1 = op->lin; + const SwsLinearOp m2 = next->lin; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 5; j++) { + AVRational sum = Q(0); + for (int k = 0; k < 4; k++) + sum = av_add_q(sum, av_mul_q(m2.m[i][k], m1.m[k][j])); + if (j == 4) /* m1.m[4][j] == 1 */ + sum = av_add_q(sum, m2.m[i][4]); + op->lin.m[i][j] = sum; + } + } + op->lin.mask = ff_sws_linear_mask(op->lin); + ff_sws_op_list_remove_at(ops, n + 1, 1); + goto retry; + } + + /* Optimize away zero columns */ + for (int j = 0; j < 4; j++) { + const uint32_t col = SWS_MASK_COL(j); + if (!(prev->comps.flags[j] & SWS_COMP_ZERO) || !(op->lin.mask & col)) + continue; + for (int i = 0; i < 4; i++) + op->lin.m[i][j] = Q(i == j); + op->lin.mask &= ~col; + goto retry; + } + + /* Optimize away unused rows */ + for (int i = 0; i < 4; i++) { + const uint32_t row = SWS_MASK_ROW(i); + if (!next->comps.unused[i] || !(op->lin.mask & row)) + continue; + for (int j = 0; j < 5; j++) + op->lin.m[i][j] = Q(i == j); + op->lin.mask &= ~row; + goto retry; + } + + /* Convert constant rows to explicit clear instruction */ + if (extract_constant_rows(&op->lin, prev->comps, &c)) { + RET(ff_sws_op_list_insert_at(ops, n + 1, &(SwsOp) { + .op = SWS_OP_CLEAR, + .type = op->type, + .comps = op->comps, + .c = c, + })); + goto retry; + } + + /* Multiplication by scalar constant */ + if (extract_scalar(&op->lin, prev->comps, next->comps, &c)) { + op->op = SWS_OP_SCALE; + op->c = c; + goto retry; + } + + /* Swizzle by fixed pattern */ + if (extract_swizzle(&op->lin, prev->comps, &swizzle)) { + RET(ff_sws_op_list_insert_at(ops, n, &(SwsOp) { + .op = SWS_OP_SWIZZLE, + .type = op->type, + .swizzle = swizzle, + })); + goto retry; + } + break; + } + + case SWS_OP_SCALE: { + const int factor2 = exact_log2_q(op->c.q); + + /* No-op scaling */ + if (op->c.q.num == 1 && op->c.q.den == 1) { + ff_sws_op_list_remove_at(ops, n, 1); + goto retry; + } + + /* Scaling by exact power of two */ + if (factor2 && ff_sws_pixel_type_is_int(op->type)) { + op->op = factor2 > 0 ? SWS_OP_LSHIFT : SWS_OP_RSHIFT; + op->c.u = FFABS(factor2); + goto retry; + } + break; + } + } + } + + /* Push clears to the back to void any unused components */ + for (int n = 0; n < ops->num_ops - 1; n++) { + SwsOp *op = &ops->ops[n]; + SwsOp *next = &ops->ops[n + 1]; + + switch (op->op) { + case SWS_OP_CLEAR: + if (op_commute_clear(op, next)) { + FFSWAP(SwsOp, *op, *next); + goto retry; + } + break; + } + } + + /* Apply any remaining preferential re-ordering optimizations; do these + * last because they are more likely to block other optimizations if done + * too aggressively */ + for (int n = 0; n < ops->num_ops - 1; n++) { + SwsOp *op = &ops->ops[n]; + SwsOp *next = &ops->ops[n + 1]; + + switch (op->op) { + case SWS_OP_SWIZZLE: { + /* Try to push swizzles towards the output */ + if (op_commute_swizzle(op, next)) { + FFSWAP(SwsOp, *op, *next); + goto retry; + } + break; + } + + case SWS_OP_SCALE: + /* Scaling by integer before conversion to int */ + if (op->c.q.den == 1 && next->op == SWS_OP_CONVERT && + ff_sws_pixel_type_is_int(next->convert.to)) + { + op->type = next->convert.to; + FFSWAP(SwsOp, *op, *next); + goto retry; + } + break; + } + } + + return 0; +} + +int ff_sws_solve_shuffle(const SwsOpList *const ops, uint8_t shuffle[], + int size, uint8_t clear_val, + int *read_bytes, int *write_bytes) +{ + if (!ops->num_ops) + return AVERROR(EINVAL); + + const SwsOp *read = ff_sws_op_list_input(ops); + if (!read || read->rw.frac || (!read->rw.packed && read->rw.elems > 1)) + return AVERROR(ENOTSUP); + + const int read_size = ff_sws_pixel_type_size(read->type); + uint32_t mask[4] = {0}; + for (int i = 0; i < read->rw.elems; i++) + mask[i] = 0x01010101 * i * read_size + 0x03020100; + + for (int opidx = 1; opidx < ops->num_ops; opidx++) { + const SwsOp *op = &ops->ops[opidx]; + switch (op->op) { + case SWS_OP_SWIZZLE: { + uint32_t orig[4] = { mask[0], mask[1], mask[2], mask[3] }; + for (int i = 0; i < 4; i++) + mask[i] = orig[op->swizzle.in[i]]; + break; + } + + case SWS_OP_SWAP_BYTES: + for (int i = 0; i < 4; i++) { + switch (ff_sws_pixel_type_size(op->type)) { + case 2: mask[i] = av_bswap16(mask[i]); break; + case 4: mask[i] = av_bswap32(mask[i]); break; + } + } + break; + + case SWS_OP_CLEAR: + for (int i = 0; i < 4; i++) { + if (!op->c.q4[i].den) + continue; + if (op->c.q4[i].num != 0 || !clear_val) + return AVERROR(ENOTSUP); + mask[i] = 0x1010101ul * clear_val; + } + break; + + case SWS_OP_CONVERT: { + if (!op->convert.expand) + return AVERROR(ENOTSUP); + for (int i = 0; i < 4; i++) { + switch (ff_sws_pixel_type_size(op->type)) { + case 1: mask[i] = 0x01010101 * (mask[i] & 0xFF); break; + case 2: mask[i] = 0x00010001 * (mask[i] & 0xFFFF); break; + } + } + break; + } + + case SWS_OP_WRITE: { + if (op->rw.frac || (!op->rw.packed && op->rw.elems > 1)) + return AVERROR(ENOTSUP); + + /* Initialize to no-op */ + memset(shuffle, clear_val, size); + + const int write_size = ff_sws_pixel_type_size(op->type); + const int read_chunk = read->rw.elems * read_size; + const int write_chunk = op->rw.elems * write_size; + const int num_groups = size / FFMAX(read_chunk, write_chunk); + for (int n = 0; n < num_groups; n++) { + const int base_in = n * read_chunk; + const int base_out = n * write_chunk; + for (int i = 0; i < op->rw.elems; i++) { + const int offset = base_out + i * write_size; + for (int b = 0; b < write_size; b++) { + const uint8_t idx = mask[i] >> (b * 8); + if (idx != clear_val) + shuffle[offset + b] = base_in + idx; + } + } + } + + *read_bytes = num_groups * read_chunk; + *write_bytes = num_groups * write_chunk; + return num_groups; + } + + default: + return AVERROR(ENOTSUP); + } + } + + return AVERROR(EINVAL); +} diff --git a/libs/ffmpeg/libswscale/ops_tmpl_common.c b/libs/ffmpeg/libswscale/ops_tmpl_common.c new file mode 100644 index 00000000000..1b1df2c7a0f --- /dev/null +++ b/libs/ffmpeg/libswscale/ops_tmpl_common.c @@ -0,0 +1,205 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if 0 +#pragma makedep header +#endif + +#include "ops_backend.h" + +#ifndef BIT_DEPTH +# error Should only be included from ops_tmpl_*.c! +#endif + +#define WRAP_CONVERT_UINT(N) \ +DECL_PATTERN(convert_uint##N) \ +{ \ + u##N##block_t xu, yu, zu, wu; \ + \ + SWS_LOOP \ + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { \ + if (X) \ + xu[i] = x[i]; \ + if (Y) \ + yu[i] = y[i]; \ + if (Z) \ + zu[i] = z[i]; \ + if (W) \ + wu[i] = w[i]; \ + } \ + \ + CONTINUE(u##N##block_t, xu, yu, zu, wu); \ +} \ + \ +WRAP_COMMON_PATTERNS(convert_uint##N, \ + .op = SWS_OP_CONVERT, \ + .convert.to = SWS_PIXEL_U##N, \ +); + +#if BIT_DEPTH != 8 +WRAP_CONVERT_UINT(8) +#endif + +#if BIT_DEPTH != 16 +WRAP_CONVERT_UINT(16) +#endif + +#if BIT_DEPTH != 32 || defined(IS_FLOAT) +WRAP_CONVERT_UINT(32) +#endif + +DECL_PATTERN(clear) +{ + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + if (!X) + x[i] = impl->priv.px[0]; + if (!Y) + y[i] = impl->priv.px[1]; + if (!Z) + z[i] = impl->priv.px[2]; + if (!W) + w[i] = impl->priv.px[3]; + } + + CONTINUE(block_t, x, y, z, w); +} + +#define WRAP_CLEAR(X, Y, Z, W) \ +DECL_IMPL(clear##_##X##Y##Z##W) \ +{ \ + CALL(clear, X, Y, Z, W); \ +} \ + \ +DECL_ENTRY(clear##_##X##Y##Z##W, \ + .setup = ff_sws_setup_q4, \ + .op = SWS_OP_CLEAR, \ + .flexible = true, \ + .unused = { !X, !Y, !Z, !W }, \ +); + +WRAP_CLEAR(1, 1, 1, 0) /* rgba alpha */ +WRAP_CLEAR(0, 1, 1, 1) /* argb alpha */ +WRAP_CLEAR(1, 0, 1, 1) /* ya alpha */ + +WRAP_CLEAR(0, 0, 1, 1) /* vuya chroma */ +WRAP_CLEAR(1, 0, 0, 1) /* yuva chroma */ +WRAP_CLEAR(1, 1, 0, 0) /* ayuv chroma */ +WRAP_CLEAR(0, 1, 0, 1) /* uyva chroma */ +WRAP_CLEAR(1, 0, 1, 0) /* xvyu chroma */ + +WRAP_CLEAR(1, 0, 0, 0) /* gray -> yuva */ +WRAP_CLEAR(0, 1, 0, 0) /* gray -> ayuv */ +WRAP_CLEAR(0, 0, 1, 0) /* gray -> vuya */ + +DECL_PATTERN(min) +{ + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + if (X) + x[i] = FFMIN(x[i], impl->priv.px[0]); + if (Y) + y[i] = FFMIN(y[i], impl->priv.px[1]); + if (Z) + z[i] = FFMIN(z[i], impl->priv.px[2]); + if (W) + w[i] = FFMIN(w[i], impl->priv.px[3]); + } + + CONTINUE(block_t, x, y, z, w); +} + +DECL_PATTERN(max) +{ + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + if (X) + x[i] = FFMAX(x[i], impl->priv.px[0]); + if (Y) + y[i] = FFMAX(y[i], impl->priv.px[1]); + if (Z) + z[i] = FFMAX(z[i], impl->priv.px[2]); + if (W) + w[i] = FFMAX(w[i], impl->priv.px[3]); + } + + CONTINUE(block_t, x, y, z, w); +} + +WRAP_COMMON_PATTERNS(min, + .op = SWS_OP_MIN, + .setup = ff_sws_setup_q4, + .flexible = true, +); + +WRAP_COMMON_PATTERNS(max, + .op = SWS_OP_MAX, + .setup = ff_sws_setup_q4, + .flexible = true, +); + +DECL_PATTERN(scale) +{ + const pixel_t scale = impl->priv.px[0]; + + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + if (X) + x[i] *= scale; + if (Y) + y[i] *= scale; + if (Z) + z[i] *= scale; + if (W) + w[i] *= scale; + } + + CONTINUE(block_t, x, y, z, w); +} + +WRAP_COMMON_PATTERNS(scale, + .op = SWS_OP_SCALE, + .setup = ff_sws_setup_q, + .flexible = true, +); + +static void fn(process)(const SwsOpExec *exec, const void *priv, + const int bx_start, const int y_start, + int bx_end, int y_end) +{ + const SwsOpChain *chain = priv; + const SwsOpImpl *impl = chain->impl; + u32block_t x, y, z, w; /* allocate enough space for any intermediate */ + + SwsOpIter iterdata; + SwsOpIter *iter = &iterdata; /* for CONTINUE() macro to work */ + + for (iter->y = y_start; iter->y < y_end; iter->y++) { + for (int i = 0; i < 4; i++) { + iter->in[i] = exec->in[i] + (iter->y - y_start) * exec->in_stride[i]; + iter->out[i] = exec->out[i] + (iter->y - y_start) * exec->out_stride[i]; + } + + for (int block = bx_start; block < bx_end; block++) { + iter->x = block * SWS_BLOCK_SIZE; + CONTINUE(block_t, (void *) x, (void *) y, (void *) z, (void *) w); + } + } +} diff --git a/libs/ffmpeg/libswscale/ops_tmpl_float.c b/libs/ffmpeg/libswscale/ops_tmpl_float.c new file mode 100644 index 00000000000..254077e126d --- /dev/null +++ b/libs/ffmpeg/libswscale/ops_tmpl_float.c @@ -0,0 +1,272 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if 0 +#pragma makedep header +#endif + +#include "libavutil/avassert.h" + +#include "ops_backend.h" + +#ifndef BIT_DEPTH +# define BIT_DEPTH 32 +#endif + +#if BIT_DEPTH == 32 +# define PIXEL_TYPE SWS_PIXEL_F32 +# define PIXEL_MAX FLT_MAX +# define PIXEL_MIN FLT_MIN +# define pixel_t float +# define block_t f32block_t +# define px f32 +#else +# error Invalid BIT_DEPTH +#endif + +#define IS_FLOAT 1 +#define FMT_CHAR f +#include "ops_tmpl_common.c" + +DECL_SETUP(setup_dither) +{ + const int size = 1 << op->dither.size_log2; + if (size == 1) { + /* We special case this value */ + av_assert1(!av_cmp_q(op->dither.matrix[0], av_make_q(1, 2))); + out->ptr = NULL; + return 0; + } + + const int width = FFMAX(size, SWS_BLOCK_SIZE); + pixel_t *matrix = out->ptr = av_malloc(sizeof(pixel_t) * size * width); + if (!matrix) + return AVERROR(ENOMEM); + + static_assert(sizeof(out->ptr) <= sizeof(uint8_t[8]), ">8 byte pointers not supported"); + int8_t *offset = &out->i8[8]; + for (int i = 0; i < 4; i++) + offset[i] = op->dither.y_offset[i]; + + for (int y = 0; y < size; y++) { + for (int x = 0; x < size; x++) + matrix[y * width + x] = av_q2pixel(op->dither.matrix[y * size + x]); + for (int x = size; x < width; x++) /* pad to block size */ + matrix[y * width + x] = matrix[y * width + (x % size)]; + } + + return 0; +} + +DECL_FUNC(dither, const int size_log2) +{ + const pixel_t *restrict matrix = impl->priv.ptr; + const int8_t *restrict offset = &impl->priv.i8[8]; + const int mask = (1 << size_log2) - 1; + const int y_line = iter->y; + const int size = 1 << size_log2; + const int width = FFMAX(size, SWS_BLOCK_SIZE); + const int base = iter->x & ~(SWS_BLOCK_SIZE - 1) & (size - 1); + +#define DITHER_COMP(VAR, IDX) \ + if (offset[IDX] >= 0) { \ + const int row = (y_line + offset[IDX]) & mask; \ + SWS_LOOP \ + for (int i = 0; i < SWS_BLOCK_SIZE; i++) \ + VAR[i] += size_log2 ? matrix[row * width + base + i] : (pixel_t) 0.5; \ + } + + DITHER_COMP(x, 0) + DITHER_COMP(y, 1) + DITHER_COMP(z, 2) + DITHER_COMP(w, 3) + + CONTINUE(block_t, x, y, z, w); +} + +#define WRAP_DITHER(N) \ +DECL_IMPL(dither##N) \ +{ \ + CALL(dither, N); \ +} \ + \ +DECL_ENTRY(dither##N, \ + .op = SWS_OP_DITHER, \ + .dither_size = N, \ + .setup = fn(setup_dither), \ + .free = av_free, \ +); + +WRAP_DITHER(0) +WRAP_DITHER(1) +WRAP_DITHER(2) +WRAP_DITHER(3) +WRAP_DITHER(4) +WRAP_DITHER(5) +WRAP_DITHER(6) +WRAP_DITHER(7) +WRAP_DITHER(8) + +typedef struct { + /* Stored in split form for convenience */ + pixel_t m[4][4]; + pixel_t k[4]; +} fn(LinCoeffs); + +DECL_SETUP(setup_linear) +{ + fn(LinCoeffs) c; + + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) + c.m[i][j] = av_q2pixel(op->lin.m[i][j]); + c.k[i] = av_q2pixel(op->lin.m[i][4]); + } + + return SETUP_MEMDUP(c); +} + +/** + * Fully general case for a 5x5 linear affine transformation. Should never be + * called without constant `mask`. This function will compile down to the + * appropriately optimized version for the required subset of operations when + * called with a constant mask. + */ +DECL_FUNC(linear_mask, const uint32_t mask) +{ + const fn(LinCoeffs) c = *(const fn(LinCoeffs) *) impl->priv.ptr; + + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + const pixel_t xx = x[i]; + const pixel_t yy = y[i]; + const pixel_t zz = z[i]; + const pixel_t ww = w[i]; + + x[i] = (mask & SWS_MASK_OFF(0)) ? c.k[0] : 0; + x[i] += (mask & SWS_MASK(0, 0)) ? c.m[0][0] * xx : xx; + x[i] += (mask & SWS_MASK(0, 1)) ? c.m[0][1] * yy : 0; + x[i] += (mask & SWS_MASK(0, 2)) ? c.m[0][2] * zz : 0; + x[i] += (mask & SWS_MASK(0, 3)) ? c.m[0][3] * ww : 0; + + y[i] = (mask & SWS_MASK_OFF(1)) ? c.k[1] : 0; + y[i] += (mask & SWS_MASK(1, 0)) ? c.m[1][0] * xx : 0; + y[i] += (mask & SWS_MASK(1, 1)) ? c.m[1][1] * yy : yy; + y[i] += (mask & SWS_MASK(1, 2)) ? c.m[1][2] * zz : 0; + y[i] += (mask & SWS_MASK(1, 3)) ? c.m[1][3] * ww : 0; + + z[i] = (mask & SWS_MASK_OFF(2)) ? c.k[2] : 0; + z[i] += (mask & SWS_MASK(2, 0)) ? c.m[2][0] * xx : 0; + z[i] += (mask & SWS_MASK(2, 1)) ? c.m[2][1] * yy : 0; + z[i] += (mask & SWS_MASK(2, 2)) ? c.m[2][2] * zz : zz; + z[i] += (mask & SWS_MASK(2, 3)) ? c.m[2][3] * ww : 0; + + w[i] = (mask & SWS_MASK_OFF(3)) ? c.k[3] : 0; + w[i] += (mask & SWS_MASK(3, 0)) ? c.m[3][0] * xx : 0; + w[i] += (mask & SWS_MASK(3, 1)) ? c.m[3][1] * yy : 0; + w[i] += (mask & SWS_MASK(3, 2)) ? c.m[3][2] * zz : 0; + w[i] += (mask & SWS_MASK(3, 3)) ? c.m[3][3] * ww : ww; + } + + CONTINUE(block_t, x, y, z, w); +} + +#define WRAP_LINEAR(NAME, MASK) \ +DECL_IMPL(linear_##NAME) \ +{ \ + CALL(linear_mask, MASK); \ +} \ + \ +DECL_ENTRY(linear_##NAME, \ + .op = SWS_OP_LINEAR, \ + .setup = fn(setup_linear), \ + .free = av_free, \ + .linear_mask = (MASK), \ +); + +WRAP_LINEAR(luma, SWS_MASK_LUMA) +WRAP_LINEAR(alpha, SWS_MASK_ALPHA) +WRAP_LINEAR(lumalpha, SWS_MASK_LUMA | SWS_MASK_ALPHA) +WRAP_LINEAR(dot3, 0x7) +WRAP_LINEAR(row0, SWS_MASK_ROW(0)) +WRAP_LINEAR(row0a, SWS_MASK_ROW(0) | SWS_MASK_ALPHA) +WRAP_LINEAR(diag3, SWS_MASK_DIAG3) +WRAP_LINEAR(diag4, SWS_MASK_DIAG4) +WRAP_LINEAR(diagoff3, SWS_MASK_DIAG3 | SWS_MASK_OFF3) +WRAP_LINEAR(matrix3, SWS_MASK_MAT3) +WRAP_LINEAR(affine3, SWS_MASK_MAT3 | SWS_MASK_OFF3) +WRAP_LINEAR(affine3a, SWS_MASK_MAT3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA) +WRAP_LINEAR(matrix4, SWS_MASK_MAT4) +WRAP_LINEAR(affine4, SWS_MASK_MAT4 | SWS_MASK_OFF4) + +static const SwsOpTable fn(op_table_float) = { + .block_size = SWS_BLOCK_SIZE, + .entries = { + REF_COMMON_PATTERNS(convert_uint8), + REF_COMMON_PATTERNS(convert_uint16), + REF_COMMON_PATTERNS(convert_uint32), + + &fn(op_clear_1110), + REF_COMMON_PATTERNS(min), + REF_COMMON_PATTERNS(max), + REF_COMMON_PATTERNS(scale), + + &fn(op_dither0), + &fn(op_dither1), + &fn(op_dither2), + &fn(op_dither3), + &fn(op_dither4), + &fn(op_dither5), + &fn(op_dither6), + &fn(op_dither7), + &fn(op_dither8), + + &fn(op_clear_1110), + &fn(op_clear_0111), + &fn(op_clear_0011), + + &fn(op_linear_luma), + &fn(op_linear_alpha), + &fn(op_linear_lumalpha), + &fn(op_linear_dot3), + &fn(op_linear_row0), + &fn(op_linear_row0a), + &fn(op_linear_diag3), + &fn(op_linear_diag4), + &fn(op_linear_diagoff3), + &fn(op_linear_matrix3), + &fn(op_linear_affine3), + &fn(op_linear_affine3a), + &fn(op_linear_matrix4), + &fn(op_linear_affine4), + + NULL + }, +}; + +#undef PIXEL_TYPE +#undef PIXEL_MAX +#undef PIXEL_MIN +#undef pixel_t +#undef block_t +#undef px + +#undef FMT_CHAR +#undef IS_FLOAT diff --git a/libs/ffmpeg/libswscale/ops_tmpl_int.c b/libs/ffmpeg/libswscale/ops_tmpl_int.c new file mode 100644 index 00000000000..4ce86e3ad9f --- /dev/null +++ b/libs/ffmpeg/libswscale/ops_tmpl_int.c @@ -0,0 +1,600 @@ +/** + * Copyright (C) 2025 Niklas Haas + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if 0 +#pragma makedep header +#endif + +#include "libavutil/avassert.h" +#include "libavutil/bswap.h" + +#include "ops_backend.h" + +#ifndef BIT_DEPTH +# define BIT_DEPTH 8 +#endif + +#if BIT_DEPTH == 32 +# define PIXEL_TYPE SWS_PIXEL_U32 +# define PIXEL_MAX 0xFFFFFFFFu +# define SWAP_BYTES av_bswap32 +# define pixel_t uint32_t +# define block_t u32block_t +# define px u32 +#elif BIT_DEPTH == 16 +# define PIXEL_TYPE SWS_PIXEL_U16 +# define PIXEL_MAX 0xFFFFu +# define SWAP_BYTES av_bswap16 +# define pixel_t uint16_t +# define block_t u16block_t +# define px u16 +#elif BIT_DEPTH == 8 +# define PIXEL_TYPE SWS_PIXEL_U8 +# define PIXEL_MAX 0xFFu +# define pixel_t uint8_t +# define block_t u8block_t +# define px u8 +#else +# error Invalid BIT_DEPTH +#endif + +#define IS_FLOAT 0 +#define FMT_CHAR u +#define PIXEL_MIN 0 +#include "ops_tmpl_common.c" + +DECL_READ(read_planar, const int elems) +{ + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + x[i] = in0[i]; + if (elems > 1) + y[i] = in1[i]; + if (elems > 2) + z[i] = in2[i]; + if (elems > 3) + w[i] = in3[i]; + } + + CONTINUE(block_t, x, y, z, w); +} + +DECL_READ(read_packed, const int elems) +{ + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + x[i] = in0[elems * i + 0]; + if (elems > 1) + y[i] = in0[elems * i + 1]; + if (elems > 2) + z[i] = in0[elems * i + 2]; + if (elems > 3) + w[i] = in0[elems * i + 3]; + } + + CONTINUE(block_t, x, y, z, w); +} + +DECL_WRITE(write_planar, const int elems) +{ + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + out0[i] = x[i]; + if (elems > 1) + out1[i] = y[i]; + if (elems > 2) + out2[i] = z[i]; + if (elems > 3) + out3[i] = w[i]; + } +} + +DECL_WRITE(write_packed, const int elems) +{ + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + out0[elems * i + 0] = x[i]; + if (elems > 1) + out0[elems * i + 1] = y[i]; + if (elems > 2) + out0[elems * i + 2] = z[i]; + if (elems > 3) + out0[elems * i + 3] = w[i]; + } +} + +#define WRAP_READ(FUNC, ELEMS, FRAC, PACKED) \ +DECL_IMPL(FUNC##ELEMS) \ +{ \ + CALL_READ(FUNC, ELEMS); \ + for (int i = 0; i < (PACKED ? 1 : ELEMS); i++) \ + iter->in[i] += sizeof(block_t) * (PACKED ? ELEMS : 1) >> FRAC; \ +} \ + \ +DECL_ENTRY(FUNC##ELEMS, \ + .op = SWS_OP_READ, \ + .rw = { \ + .elems = ELEMS, \ + .packed = PACKED, \ + .frac = FRAC, \ + }, \ +); + +WRAP_READ(read_planar, 1, 0, false) +WRAP_READ(read_planar, 2, 0, false) +WRAP_READ(read_planar, 3, 0, false) +WRAP_READ(read_planar, 4, 0, false) +WRAP_READ(read_packed, 2, 0, true) +WRAP_READ(read_packed, 3, 0, true) +WRAP_READ(read_packed, 4, 0, true) + +#define WRAP_WRITE(FUNC, ELEMS, FRAC, PACKED) \ +DECL_IMPL(FUNC##ELEMS) \ +{ \ + CALL_WRITE(FUNC, ELEMS); \ + for (int i = 0; i < (PACKED ? 1 : ELEMS); i++) \ + iter->out[i] += sizeof(block_t) * (PACKED ? ELEMS : 1) >> FRAC; \ +} \ + \ +DECL_ENTRY(FUNC##ELEMS, \ + .op = SWS_OP_WRITE, \ + .rw = { \ + .elems = ELEMS, \ + .packed = PACKED, \ + .frac = FRAC, \ + }, \ +); + +WRAP_WRITE(write_planar, 1, 0, false) +WRAP_WRITE(write_planar, 2, 0, false) +WRAP_WRITE(write_planar, 3, 0, false) +WRAP_WRITE(write_planar, 4, 0, false) +WRAP_WRITE(write_packed, 2, 0, true) +WRAP_WRITE(write_packed, 3, 0, true) +WRAP_WRITE(write_packed, 4, 0, true) + +#if BIT_DEPTH == 8 +DECL_READ(read_nibbles, const int elems) +{ + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i += 2) { + const pixel_t val = ((const pixel_t *) in0)[i >> 1]; + x[i + 0] = val >> 4; /* high nibble */ + x[i + 1] = val & 0xF; /* low nibble */ + } + + CONTINUE(block_t, x, y, z, w); +} + +DECL_READ(read_bits, const int elems) +{ + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i += 8) { + const pixel_t val = ((const pixel_t *) in0)[i >> 3]; + x[i + 0] = (val >> 7) & 1; + x[i + 1] = (val >> 6) & 1; + x[i + 2] = (val >> 5) & 1; + x[i + 3] = (val >> 4) & 1; + x[i + 4] = (val >> 3) & 1; + x[i + 5] = (val >> 2) & 1; + x[i + 6] = (val >> 1) & 1; + x[i + 7] = (val >> 0) & 1; + } + + CONTINUE(block_t, x, y, z, w); +} + +WRAP_READ(read_nibbles, 1, 1, false) +WRAP_READ(read_bits, 1, 3, false) + +DECL_WRITE(write_nibbles, const int elems) +{ + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i += 2) + out0[i >> 1] = x[i] << 4 | x[i + 1]; +} + +DECL_WRITE(write_bits, const int elems) +{ + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i += 8) { + out0[i >> 3] = x[i + 0] << 7 | + x[i + 1] << 6 | + x[i + 2] << 5 | + x[i + 3] << 4 | + x[i + 4] << 3 | + x[i + 5] << 2 | + x[i + 6] << 1 | + x[i + 7]; + } +} + +WRAP_WRITE(write_nibbles, 1, 1, false) +WRAP_WRITE(write_bits, 1, 3, false) +#endif /* BIT_DEPTH == 8 */ + +#ifdef SWAP_BYTES +DECL_PATTERN(swap_bytes) +{ + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + if (X) + x[i] = SWAP_BYTES(x[i]); + if (Y) + y[i] = SWAP_BYTES(y[i]); + if (Z) + z[i] = SWAP_BYTES(z[i]); + if (W) + w[i] = SWAP_BYTES(w[i]); + } + + CONTINUE(block_t, x, y, z, w); +} + +WRAP_COMMON_PATTERNS(swap_bytes, .op = SWS_OP_SWAP_BYTES); +#endif /* SWAP_BYTES */ + +#if BIT_DEPTH == 8 +DECL_PATTERN(expand16) +{ + u16block_t x16, y16, z16, w16; + + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + if (X) + x16[i] = x[i] << 8 | x[i]; + if (Y) + y16[i] = y[i] << 8 | y[i]; + if (Z) + z16[i] = z[i] << 8 | z[i]; + if (W) + w16[i] = w[i] << 8 | w[i]; + } + + CONTINUE(u16block_t, x16, y16, z16, w16); +} + +WRAP_COMMON_PATTERNS(expand16, + .op = SWS_OP_CONVERT, + .convert.to = SWS_PIXEL_U16, + .convert.expand = true, +); + +DECL_PATTERN(expand32) +{ + u32block_t x32, y32, z32, w32; + + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + x32[i] = (uint32_t)x[i] << 24 | x[i] << 16 | x[i] << 8 | x[i]; + y32[i] = (uint32_t)y[i] << 24 | y[i] << 16 | y[i] << 8 | y[i]; + z32[i] = (uint32_t)z[i] << 24 | z[i] << 16 | z[i] << 8 | z[i]; + w32[i] = (uint32_t)w[i] << 24 | w[i] << 16 | w[i] << 8 | w[i]; + } + + CONTINUE(u32block_t, x32, y32, z32, w32); +} + +WRAP_COMMON_PATTERNS(expand32, + .op = SWS_OP_CONVERT, + .convert.to = SWS_PIXEL_U32, + .convert.expand = true, +); +#endif + +#define WRAP_PACK_UNPACK(X, Y, Z, W) \ +inline DECL_IMPL(pack_##X##Y##Z##W) \ +{ \ + SWS_LOOP \ + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { \ + x[i] = x[i] << (Y+Z+W); \ + if (Y) \ + x[i] |= y[i] << (Z+W); \ + if (Z) \ + x[i] |= z[i] << W; \ + if (W) \ + x[i] |= w[i]; \ + } \ + \ + CONTINUE(block_t, x, y, z, w); \ +} \ + \ +DECL_ENTRY(pack_##X##Y##Z##W, \ + .op = SWS_OP_PACK, \ + .pack.pattern = { X, Y, Z, W }, \ +); \ + \ +inline DECL_IMPL(unpack_##X##Y##Z##W) \ +{ \ + SWS_LOOP \ + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { \ + const pixel_t val = x[i]; \ + x[i] = val >> (Y+Z+W); \ + if (Y) \ + y[i] = (val >> (Z+W)) & ((1 << Y) - 1); \ + if (Z) \ + z[i] = (val >> W) & ((1 << Z) - 1); \ + if (W) \ + w[i] = val & ((1 << W) - 1); \ + } \ + \ + CONTINUE(block_t, x, y, z, w); \ +} \ + \ +DECL_ENTRY(unpack_##X##Y##Z##W, \ + .op = SWS_OP_UNPACK, \ + .pack.pattern = { X, Y, Z, W }, \ +); + +WRAP_PACK_UNPACK( 3, 3, 2, 0) +WRAP_PACK_UNPACK( 2, 3, 3, 0) +WRAP_PACK_UNPACK( 1, 2, 1, 0) +WRAP_PACK_UNPACK( 5, 6, 5, 0) +WRAP_PACK_UNPACK( 5, 5, 5, 0) +WRAP_PACK_UNPACK( 4, 4, 4, 0) +WRAP_PACK_UNPACK( 2, 10, 10, 10) +WRAP_PACK_UNPACK(10, 10, 10, 2) + +#if BIT_DEPTH != 8 +DECL_PATTERN(lshift) +{ + const uint8_t amount = impl->priv.u8[0]; + + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + x[i] <<= amount; + y[i] <<= amount; + z[i] <<= amount; + w[i] <<= amount; + } + + CONTINUE(block_t, x, y, z, w); +} + +DECL_PATTERN(rshift) +{ + const uint8_t amount = impl->priv.u8[0]; + + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + x[i] >>= amount; + y[i] >>= amount; + z[i] >>= amount; + w[i] >>= amount; + } + + CONTINUE(block_t, x, y, z, w); +} + +WRAP_COMMON_PATTERNS(lshift, + .op = SWS_OP_LSHIFT, + .setup = ff_sws_setup_u8, + .flexible = true, +); + +WRAP_COMMON_PATTERNS(rshift, + .op = SWS_OP_RSHIFT, + .setup = ff_sws_setup_u8, + .flexible = true, +); +#endif /* BIT_DEPTH != 8 */ + +DECL_PATTERN(convert_float) +{ + f32block_t xf, yf, zf, wf; + + SWS_LOOP + for (int i = 0; i < SWS_BLOCK_SIZE; i++) { + xf[i] = x[i]; + yf[i] = y[i]; + zf[i] = z[i]; + wf[i] = w[i]; + } + + CONTINUE(f32block_t, xf, yf, zf, wf); +} + +WRAP_COMMON_PATTERNS(convert_float, + .op = SWS_OP_CONVERT, + .convert.to = SWS_PIXEL_F32, +); + +/** + * Swizzle by directly swapping the order of arguments to the continuation. + * Note that this is only safe to do if no arguments are duplicated. + */ +#define DECL_SWIZZLE(X, Y, Z, W) \ +static SWS_FUNC void \ +fn(swizzle_##X##Y##Z##W)(SwsOpIter *restrict iter, \ + const SwsOpImpl *restrict impl, \ + block_t c0, block_t c1, block_t c2, block_t c3) \ +{ \ + CONTINUE(block_t, c##X, c##Y, c##Z, c##W); \ +} \ + \ +DECL_ENTRY(swizzle_##X##Y##Z##W, \ + .op = SWS_OP_SWIZZLE, \ + .swizzle.in = { X, Y, Z, W }, \ +); + +DECL_SWIZZLE(3, 0, 1, 2) +DECL_SWIZZLE(3, 0, 2, 1) +DECL_SWIZZLE(2, 1, 0, 3) +DECL_SWIZZLE(3, 2, 1, 0) +DECL_SWIZZLE(3, 1, 0, 2) +DECL_SWIZZLE(3, 2, 0, 1) +DECL_SWIZZLE(1, 2, 0, 3) +DECL_SWIZZLE(1, 0, 2, 3) +DECL_SWIZZLE(2, 0, 1, 3) +DECL_SWIZZLE(2, 3, 1, 0) +DECL_SWIZZLE(2, 1, 3, 0) +DECL_SWIZZLE(1, 2, 3, 0) +DECL_SWIZZLE(1, 3, 2, 0) +DECL_SWIZZLE(0, 2, 1, 3) +DECL_SWIZZLE(0, 2, 3, 1) +DECL_SWIZZLE(0, 3, 1, 2) +DECL_SWIZZLE(3, 1, 2, 0) +DECL_SWIZZLE(0, 3, 2, 1) + +/* Broadcast luma -> rgb (only used for y(a) -> rgb(a)) */ +#define DECL_EXPAND_LUMA(X, W, T0, T1) \ +static SWS_FUNC void \ +fn(expand_luma_##X##W)(SwsOpIter *restrict iter, \ + const SwsOpImpl *restrict impl, \ + block_t c0, block_t c1, block_t c2, block_t c3) \ +{ \ + SWS_LOOP \ + for (int i = 0; i < SWS_BLOCK_SIZE; i++) \ + T0[i] = T1[i] = c0[i]; \ + \ + CONTINUE(block_t, c##X, T0, T1, c##W); \ +} \ + \ +DECL_ENTRY(expand_luma_##X##W, \ + .op = SWS_OP_SWIZZLE, \ + .swizzle.in = { X, 0, 0, W }, \ +); + +DECL_EXPAND_LUMA(0, 3, c1, c2) +DECL_EXPAND_LUMA(3, 0, c1, c2) +DECL_EXPAND_LUMA(1, 0, c2, c3) +DECL_EXPAND_LUMA(0, 1, c2, c3) + +static const SwsOpTable fn(op_table_int) = { + .block_size = SWS_BLOCK_SIZE, + .entries = { + &fn(op_read_planar1), + &fn(op_read_planar2), + &fn(op_read_planar3), + &fn(op_read_planar4), + &fn(op_read_packed2), + &fn(op_read_packed3), + &fn(op_read_packed4), + + &fn(op_write_planar1), + &fn(op_write_planar2), + &fn(op_write_planar3), + &fn(op_write_planar4), + &fn(op_write_packed2), + &fn(op_write_packed3), + &fn(op_write_packed4), + +#if BIT_DEPTH == 8 + &fn(op_read_bits1), + &fn(op_read_nibbles1), + &fn(op_write_bits1), + &fn(op_write_nibbles1), + + &fn(op_pack_1210), + &fn(op_pack_2330), + &fn(op_pack_3320), + + &fn(op_unpack_1210), + &fn(op_unpack_2330), + &fn(op_unpack_3320), + + REF_COMMON_PATTERNS(expand16), + REF_COMMON_PATTERNS(expand32), +#elif BIT_DEPTH == 16 + &fn(op_pack_4440), + &fn(op_pack_5550), + &fn(op_pack_5650), + &fn(op_unpack_4440), + &fn(op_unpack_5550), + &fn(op_unpack_5650), +#elif BIT_DEPTH == 32 + &fn(op_pack_2101010), + &fn(op_pack_1010102), + &fn(op_unpack_2101010), + &fn(op_unpack_1010102), +#endif + +#ifdef SWAP_BYTES + REF_COMMON_PATTERNS(swap_bytes), +#endif + + REF_COMMON_PATTERNS(min), + REF_COMMON_PATTERNS(max), + REF_COMMON_PATTERNS(scale), + REF_COMMON_PATTERNS(convert_float), + + &fn(op_clear_1110), + &fn(op_clear_0111), + &fn(op_clear_0011), + &fn(op_clear_1011), + &fn(op_clear_1001), + &fn(op_clear_1100), + &fn(op_clear_0101), + &fn(op_clear_1010), + &fn(op_clear_1000), + &fn(op_clear_0100), + &fn(op_clear_0010), + + &fn(op_swizzle_3012), + &fn(op_swizzle_3021), + &fn(op_swizzle_2103), + &fn(op_swizzle_3210), + &fn(op_swizzle_3102), + &fn(op_swizzle_3201), + &fn(op_swizzle_1203), + &fn(op_swizzle_1023), + &fn(op_swizzle_2013), + &fn(op_swizzle_2310), + &fn(op_swizzle_2130), + &fn(op_swizzle_1230), + &fn(op_swizzle_1320), + &fn(op_swizzle_0213), + &fn(op_swizzle_0231), + &fn(op_swizzle_0312), + &fn(op_swizzle_3120), + &fn(op_swizzle_0321), + + &fn(op_expand_luma_03), + &fn(op_expand_luma_30), + &fn(op_expand_luma_10), + &fn(op_expand_luma_01), + +#if BIT_DEPTH != 8 + REF_COMMON_PATTERNS(lshift), + REF_COMMON_PATTERNS(rshift), + REF_COMMON_PATTERNS(convert_uint8), +#endif /* BIT_DEPTH != 8 */ + +#if BIT_DEPTH != 16 + REF_COMMON_PATTERNS(convert_uint16), +#endif +#if BIT_DEPTH != 32 + REF_COMMON_PATTERNS(convert_uint32), +#endif + + NULL + }, +}; + +#undef PIXEL_TYPE +#undef PIXEL_MAX +#undef PIXEL_MIN +#undef SWAP_BYTES +#undef pixel_t +#undef block_t +#undef px + +#undef FMT_CHAR +#undef IS_FLOAT diff --git a/libs/ffmpeg/libswscale/options.c b/libs/ffmpeg/libswscale/options.c new file mode 100644 index 00000000000..06e51dcfe9b --- /dev/null +++ b/libs/ffmpeg/libswscale/options.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/opt.h" +#include "swscale.h" +#include "swscale_internal.h" + +static const char *sws_context_to_name(void *ptr) +{ + return "swscaler"; +} + +#define OFFSET(x) offsetof(SwsContext, x) +#define DEFAULT 0 +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM + +static const AVOption swscale_options[] = { + { "sws_flags", "swscale flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, { .i64 = SWS_BICUBIC }, .flags = VE, .unit = "sws_flags", .max = UINT_MAX }, + { "fast_bilinear", "fast bilinear", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_FAST_BILINEAR }, .flags = VE, .unit = "sws_flags" }, + { "bilinear", "bilinear", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BILINEAR }, .flags = VE, .unit = "sws_flags" }, + { "bicubic", "bicubic", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BICUBIC }, .flags = VE, .unit = "sws_flags" }, + { "experimental", "experimental", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_X }, .flags = VE, .unit = "sws_flags" }, + { "neighbor", "nearest neighbor", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_POINT }, .flags = VE, .unit = "sws_flags" }, + { "area", "averaging area", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_AREA }, .flags = VE, .unit = "sws_flags" }, + { "bicublin", "luma bicubic, chroma bilinear", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BICUBLIN }, .flags = VE, .unit = "sws_flags" }, + { "gauss", "gaussian approximation", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_GAUSS }, .flags = VE, .unit = "sws_flags" }, + { "sinc", "sinc", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_SINC }, .flags = VE, .unit = "sws_flags" }, + { "lanczos", "lanczos (sinc/sinc)", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_LANCZOS }, .flags = VE, .unit = "sws_flags" }, + { "spline", "natural bicubic spline", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_SPLINE }, .flags = VE, .unit = "sws_flags" }, + { "print_info", "print info", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_PRINT_INFO }, .flags = VE, .unit = "sws_flags" }, + { "accurate_rnd", "accurate rounding", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ACCURATE_RND }, .flags = VE, .unit = "sws_flags" }, + { "full_chroma_int", "full chroma interpolation", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_FULL_CHR_H_INT }, .flags = VE, .unit = "sws_flags" }, + { "full_chroma_inp", "full chroma input", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_FULL_CHR_H_INP }, .flags = VE, .unit = "sws_flags" }, + { "bitexact", "bit-exact mode", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_BITEXACT }, .flags = VE, .unit = "sws_flags" }, + { "error_diffusion", "error diffusion dither", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ERROR_DIFFUSION}, .flags = VE, .unit = "sws_flags" }, + { "unstable", "allow experimental new code", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_UNSTABLE }, .flags = VE, .unit = "sws_flags" }, + + { "param0", "scaler param 0", OFFSET(scaler_params[0]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, VE }, + { "param1", "scaler param 1", OFFSET(scaler_params[1]), AV_OPT_TYPE_DOUBLE, { .dbl = SWS_PARAM_DEFAULT }, INT_MIN, INT_MAX, VE }, + + { "srcw", "source width", OFFSET(src_w), AV_OPT_TYPE_INT, { .i64 = 16 }, 1, INT_MAX, VE }, + { "srch", "source height", OFFSET(src_h), AV_OPT_TYPE_INT, { .i64 = 16 }, 1, INT_MAX, VE }, + { "dstw", "destination width", OFFSET(dst_w), AV_OPT_TYPE_INT, { .i64 = 16 }, 1, INT_MAX, VE }, + { "dsth", "destination height", OFFSET(dst_h), AV_OPT_TYPE_INT, { .i64 = 16 }, 1, INT_MAX, VE }, + { "src_format", "source format", OFFSET(src_format), AV_OPT_TYPE_PIXEL_FMT, { .i64 = DEFAULT }, 0, INT_MAX, VE }, + { "dst_format", "destination format", OFFSET(dst_format), AV_OPT_TYPE_PIXEL_FMT, { .i64 = DEFAULT }, 0, INT_MAX, VE }, + { "src_range", "source is full range", OFFSET(src_range), AV_OPT_TYPE_BOOL, { .i64 = DEFAULT }, 0, 1, VE }, + { "dst_range", "destination is full range", OFFSET(dst_range), AV_OPT_TYPE_BOOL, { .i64 = DEFAULT }, 0, 1, VE }, + { "gamma", "gamma correct scaling", OFFSET(gamma_flag), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + + { "src_v_chr_pos", "source vertical chroma position in luma grid/256" , OFFSET(src_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513 }, -513, 1024, VE }, + { "src_h_chr_pos", "source horizontal chroma position in luma grid/256", OFFSET(src_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513 }, -513, 1024, VE }, + { "dst_v_chr_pos", "destination vertical chroma position in luma grid/256" , OFFSET(dst_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513 }, -513, 1024, VE }, + { "dst_h_chr_pos", "destination horizontal chroma position in luma grid/256", OFFSET(dst_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513 }, -513, 1024, VE }, + + { "sws_dither", "set dithering algorithm", OFFSET(dither), AV_OPT_TYPE_INT, { .i64 = SWS_DITHER_AUTO }, .flags = VE, .unit = "sws_dither", .max = SWS_DITHER_NB - 1 }, + { "auto", "automatic selection", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_DITHER_AUTO }, .flags = VE, .unit = "sws_dither" }, + { "none", "no dithering", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_DITHER_NONE }, .flags = VE, .unit = "sws_dither" }, + { "bayer", "ordered matrix dither", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_DITHER_BAYER }, .flags = VE, .unit = "sws_dither" }, + { "ed", "full error diffusion", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_DITHER_ED }, .flags = VE, .unit = "sws_dither" }, + { "a_dither", "arithmetic addition dither", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_DITHER_A_DITHER }, .flags = VE, .unit = "sws_dither" }, + { "x_dither", "arithmetic xor dither", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_DITHER_X_DITHER }, .flags = VE, .unit = "sws_dither" }, + + { "alphablend", "mode for alpha -> non alpha", OFFSET(alpha_blend), AV_OPT_TYPE_INT, { .i64 = SWS_ALPHA_BLEND_NONE}, .flags = VE, .unit = "alphablend", .max = SWS_ALPHA_BLEND_NB - 1 }, + { "none", "ignore alpha", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ALPHA_BLEND_NONE}, .flags = VE, .unit = "alphablend" }, + { "uniform_color", "blend onto a uniform color", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ALPHA_BLEND_UNIFORM}, .flags = VE, .unit = "alphablend" }, + { "checkerboard", "blend onto a checkerboard", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ALPHA_BLEND_CHECKERBOARD}, .flags = VE, .unit = "alphablend" }, + + { "threads", "number of threads", OFFSET(threads), AV_OPT_TYPE_INT, {.i64 = 1 }, .flags = VE, .unit = "threads", .max = INT_MAX }, + { "auto", "automatic selection", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, .flags = VE, .unit = "threads" }, + + { "intent", "color mapping intent", OFFSET(intent), AV_OPT_TYPE_INT, { .i64 = SWS_INTENT_RELATIVE_COLORIMETRIC }, .flags = VE, .unit = "intent", .max = SWS_INTENT_NB - 1 }, + { "perceptual", "perceptual tone mapping", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_INTENT_PERCEPTUAL }, .flags = VE, .unit = "intent" }, + { "relative_colorimetric", "relative colorimetric clipping", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_INTENT_RELATIVE_COLORIMETRIC }, .flags = VE, .unit = "intent" }, + { "saturation", "saturation mapping", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_INTENT_SATURATION }, .flags = VE, .unit = "intent" }, + { "absolute_colorimetric", "absolute colorimetric clipping", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_INTENT_ABSOLUTE_COLORIMETRIC }, .flags = VE, .unit = "intent" }, + + { NULL } +}; + +const AVClass ff_sws_context_class = { + .class_name = "SWScaler", + .item_name = sws_context_to_name, + .option = swscale_options, + .parent_log_context_offset = offsetof(SwsInternal, parent), + .category = AV_CLASS_CATEGORY_SWSCALER, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVClass *sws_get_class(void) +{ + return &ff_sws_context_class; +} diff --git a/libs/ffmpeg/libswscale/output.c b/libs/ffmpeg/libswscale/output.c new file mode 100644 index 00000000000..396380ac72d --- /dev/null +++ b/libs/ffmpeg/libswscale/output.c @@ -0,0 +1,3885 @@ +/* + * Copyright (C) 2001-2012 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <math.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include "libavutil/attributes.h" +#include "libavutil/avutil.h" +#include "libavutil/avassert.h" +#include "libavutil/bswap.h" +#include "libavutil/intfloat.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mathematics.h" +#include "libavutil/mem_internal.h" +#include "libavutil/pixdesc.h" +#include "config.h" +#include "rgb2rgb.h" +#include "swscale.h" +#include "swscale_internal.h" + +DECLARE_ALIGNED(8, const uint8_t, ff_dither_2x2_4)[][8] = { +{ 1, 3, 1, 3, 1, 3, 1, 3, }, +{ 2, 0, 2, 0, 2, 0, 2, 0, }, +{ 1, 3, 1, 3, 1, 3, 1, 3, }, +}; + +DECLARE_ALIGNED(8, const uint8_t, ff_dither_2x2_8)[][8] = { +{ 6, 2, 6, 2, 6, 2, 6, 2, }, +{ 0, 4, 0, 4, 0, 4, 0, 4, }, +{ 6, 2, 6, 2, 6, 2, 6, 2, }, +}; + +DECLARE_ALIGNED(8, const uint8_t, ff_dither_4x4_16)[][8] = { +{ 8, 4, 11, 7, 8, 4, 11, 7, }, +{ 2, 14, 1, 13, 2, 14, 1, 13, }, +{ 10, 6, 9, 5, 10, 6, 9, 5, }, +{ 0, 12, 3, 15, 0, 12, 3, 15, }, +{ 8, 4, 11, 7, 8, 4, 11, 7, }, +}; + +DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_32)[][8] = { +{ 17, 9, 23, 15, 16, 8, 22, 14, }, +{ 5, 29, 3, 27, 4, 28, 2, 26, }, +{ 21, 13, 19, 11, 20, 12, 18, 10, }, +{ 0, 24, 6, 30, 1, 25, 7, 31, }, +{ 16, 8, 22, 14, 17, 9, 23, 15, }, +{ 4, 28, 2, 26, 5, 29, 3, 27, }, +{ 20, 12, 18, 10, 21, 13, 19, 11, }, +{ 1, 25, 7, 31, 0, 24, 6, 30, }, +{ 17, 9, 23, 15, 16, 8, 22, 14, }, +}; + +DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_73)[][8] = { +{ 0, 55, 14, 68, 3, 58, 17, 72, }, +{ 37, 18, 50, 32, 40, 22, 54, 35, }, +{ 9, 64, 5, 59, 13, 67, 8, 63, }, +{ 46, 27, 41, 23, 49, 31, 44, 26, }, +{ 2, 57, 16, 71, 1, 56, 15, 70, }, +{ 39, 21, 52, 34, 38, 19, 51, 33, }, +{ 11, 66, 7, 62, 10, 65, 6, 60, }, +{ 48, 30, 43, 25, 47, 29, 42, 24, }, +{ 0, 55, 14, 68, 3, 58, 17, 72, }, +}; + +#if 1 +DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[][8] = { +{117, 62, 158, 103, 113, 58, 155, 100, }, +{ 34, 199, 21, 186, 31, 196, 17, 182, }, +{144, 89, 131, 76, 141, 86, 127, 72, }, +{ 0, 165, 41, 206, 10, 175, 52, 217, }, +{110, 55, 151, 96, 120, 65, 162, 107, }, +{ 28, 193, 14, 179, 38, 203, 24, 189, }, +{138, 83, 124, 69, 148, 93, 134, 79, }, +{ 7, 172, 48, 213, 3, 168, 45, 210, }, +{117, 62, 158, 103, 113, 58, 155, 100, }, +}; +#elif 1 +// tries to correct a gamma of 1.5 +DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[][8] = { +{ 0, 143, 18, 200, 2, 156, 25, 215, }, +{ 78, 28, 125, 64, 89, 36, 138, 74, }, +{ 10, 180, 3, 161, 16, 195, 8, 175, }, +{109, 51, 93, 38, 121, 60, 105, 47, }, +{ 1, 152, 23, 210, 0, 147, 20, 205, }, +{ 85, 33, 134, 71, 81, 30, 130, 67, }, +{ 14, 190, 6, 171, 12, 185, 5, 166, }, +{117, 57, 101, 44, 113, 54, 97, 41, }, +{ 0, 143, 18, 200, 2, 156, 25, 215, }, +}; +#elif 1 +// tries to correct a gamma of 2.0 +DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[][8] = { +{ 0, 124, 8, 193, 0, 140, 12, 213, }, +{ 55, 14, 104, 42, 66, 19, 119, 52, }, +{ 3, 168, 1, 145, 6, 187, 3, 162, }, +{ 86, 31, 70, 21, 99, 39, 82, 28, }, +{ 0, 134, 11, 206, 0, 129, 9, 200, }, +{ 62, 17, 114, 48, 58, 16, 109, 45, }, +{ 5, 181, 2, 157, 4, 175, 1, 151, }, +{ 95, 36, 78, 26, 90, 34, 74, 24, }, +{ 0, 124, 8, 193, 0, 140, 12, 213, }, +}; +#else +// tries to correct a gamma of 2.5 +DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_220)[][8] = { +{ 0, 107, 3, 187, 0, 125, 6, 212, }, +{ 39, 7, 86, 28, 49, 11, 102, 36, }, +{ 1, 158, 0, 131, 3, 180, 1, 151, }, +{ 68, 19, 52, 12, 81, 25, 64, 17, }, +{ 0, 119, 5, 203, 0, 113, 4, 195, }, +{ 45, 9, 96, 33, 42, 8, 91, 30, }, +{ 2, 172, 1, 144, 2, 165, 0, 137, }, +{ 77, 23, 60, 15, 72, 21, 56, 14, }, +{ 0, 107, 3, 187, 0, 125, 6, 212, }, +}; +#endif + +#define IS_BE_LE 0 +#define IS_BE_BE 1 +/* ENDIAN_IDENTIFIER needs to be "BE" or "LE". */ +#define IS_BE(ENDIAN_IDENTIFIER) IS_BE_ ## ENDIAN_IDENTIFIER + +#define output_pixel(pos, val, bias, signedness) \ + if (big_endian) { \ + AV_WB16(pos, bias + av_clip_ ## signedness ## 16(val >> shift)); \ + } else { \ + AV_WL16(pos, bias + av_clip_ ## signedness ## 16(val >> shift)); \ + } + +static av_always_inline void +yuv2plane1_16_c_template(const int32_t *src, uint16_t *dest, int dstW, + int big_endian, int output_bits) +{ + int i; + int shift = 3; + av_assert0(output_bits == 16); + + for (i = 0; i < dstW; i++) { + int val = src[i] + (1 << (shift - 1)); + output_pixel(&dest[i], val, 0, uint); + } +} + +static av_always_inline void +yuv2planeX_16_c_template(const int16_t *filter, int filterSize, + const int32_t **src, uint16_t *dest, int dstW, + int big_endian, int output_bits) +{ + int i; + int shift = 15; + av_assert0(output_bits == 16); + + for (i = 0; i < dstW; i++) { + int val = 1 << (shift - 1); + int j; + + /* range of val is [0,0x7FFFFFFF], so 31 bits, but with lanczos/spline + * filters (or anything with negative coeffs, the range can be slightly + * wider in both directions. To account for this overflow, we subtract + * a constant so it always fits in the signed range (assuming a + * reasonable filterSize), and re-add that at the end. */ + val -= 0x40000000; + for (j = 0; j < filterSize; j++) + val += src[j][i] * (unsigned)filter[j]; + + output_pixel(&dest[i], val, 0x8000, int); + } +} + +static av_always_inline void +yuv2nv12cX_16_c_template(int big_endian, const uint8_t *chrDither, + const int16_t *chrFilter, int chrFilterSize, + const int16_t **chrUSrc, const int16_t **chrVSrc, + uint8_t *dest8, int chrDstW, int output_bits) +{ + uint16_t *dest = (uint16_t*)dest8; + const int32_t **uSrc = (const int32_t **)chrUSrc; + const int32_t **vSrc = (const int32_t **)chrVSrc; + int shift = 15; + int i, j; + av_assert0(output_bits == 16); + + for (i = 0; i < chrDstW; i++) { + int u = 1 << (shift - 1); + int v = 1 << (shift - 1); + + /* See yuv2planeX_16_c_template for details. */ + u -= 0x40000000; + v -= 0x40000000; + for (j = 0; j < chrFilterSize; j++) { + u += uSrc[j][i] * (unsigned)chrFilter[j]; + v += vSrc[j][i] * (unsigned)chrFilter[j]; + } + + output_pixel(&dest[2*i] , u, 0x8000, int); + output_pixel(&dest[2*i+1], v, 0x8000, int); + } +} + +static av_always_inline void +yuv2plane1_float_c_template(const int32_t *src, float *dest, int dstW) +{ + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 3; + static const float float_mult = 1.0f / 65535.0f; + int i, val; + uint16_t val_uint; + + for (i = 0; i < dstW; ++i){ + val = src[i] + (1 << (shift - 1)); + output_pixel(&val_uint, val, 0, uint); + dest[i] = float_mult * (float)val_uint; + } +} + +static av_always_inline void +yuv2plane1_float_bswap_c_template(const int32_t *src, uint32_t *dest, int dstW) +{ + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 3; + static const float float_mult = 1.0f / 65535.0f; + int i, val; + uint16_t val_uint; + + for (i = 0; i < dstW; ++i){ + val = src[i] + (1 << (shift - 1)); + output_pixel(&val_uint, val, 0, uint); + dest[i] = av_bswap32(av_float2int(float_mult * (float)val_uint)); + } +} + +static av_always_inline void +yuv2planeX_float_c_template(const int16_t *filter, int filterSize, const int32_t **src, + float *dest, int dstW) +{ + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 15; + static const float float_mult = 1.0f / 65535.0f; + int i, j, val; + uint16_t val_uint; + + for (i = 0; i < dstW; ++i){ + val = (1 << (shift - 1)) - 0x40000000; + for (j = 0; j < filterSize; ++j){ + val += src[j][i] * (unsigned)filter[j]; + } + output_pixel(&val_uint, val, 0x8000, int); + dest[i] = float_mult * (float)val_uint; + } +} + +static av_always_inline void +yuv2planeX_float_bswap_c_template(const int16_t *filter, int filterSize, const int32_t **src, + uint32_t *dest, int dstW) +{ + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 15; + static const float float_mult = 1.0f / 65535.0f; + int i, j, val; + uint16_t val_uint; + + for (i = 0; i < dstW; ++i){ + val = (1 << (shift - 1)) - 0x40000000; + for (j = 0; j < filterSize; ++j){ + val += src[j][i] * (unsigned)filter[j]; + } + output_pixel(&val_uint, val, 0x8000, int); + dest[i] = av_bswap32(av_float2int(float_mult * (float)val_uint)); + } +} + +#define yuv2plane1_float(template, dest_type, BE_LE) \ +static void yuv2plane1_float ## BE_LE ## _c(const int16_t *src, uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset) \ +{ \ + template((const int32_t *)src, (dest_type *)dest, dstW); \ +} + +#define yuv2planeX_float(template, dest_type, BE_LE) \ +static void yuv2planeX_float ## BE_LE ## _c(const int16_t *filter, int filterSize, \ + const int16_t **src, uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset) \ +{ \ + template(filter, filterSize, (const int32_t **)src, (dest_type *)dest, dstW); \ +} + +#if HAVE_BIGENDIAN +yuv2plane1_float(yuv2plane1_float_c_template, float, BE) +yuv2plane1_float(yuv2plane1_float_bswap_c_template, uint32_t, LE) +yuv2planeX_float(yuv2planeX_float_c_template, float, BE) +yuv2planeX_float(yuv2planeX_float_bswap_c_template, uint32_t, LE) +#else +yuv2plane1_float(yuv2plane1_float_c_template, float, LE) +yuv2plane1_float(yuv2plane1_float_bswap_c_template, uint32_t, BE) +yuv2planeX_float(yuv2planeX_float_c_template, float, LE) +yuv2planeX_float(yuv2planeX_float_bswap_c_template, uint32_t, BE) +#endif + +#undef output_pixel + +#define output_pixel(pos, val) \ + if (big_endian) { \ + AV_WB16(pos, av_clip_uintp2(val >> shift, output_bits)); \ + } else { \ + AV_WL16(pos, av_clip_uintp2(val >> shift, output_bits)); \ + } + +static av_always_inline void +yuv2plane1_10_c_template(const int16_t *src, uint16_t *dest, int dstW, + int big_endian, int output_bits) +{ + int i; + int shift = 15 - output_bits; + + for (i = 0; i < dstW; i++) { + int val = src[i] + (1 << (shift - 1)); + output_pixel(&dest[i], val); + } +} + +static av_always_inline void +yuv2planeX_10_c_template(const int16_t *filter, int filterSize, + const int16_t **src, uint16_t *dest, int dstW, + int big_endian, int output_bits) +{ + int i; + int shift = 11 + 16 - output_bits; + + for (i = 0; i < dstW; i++) { + int val = 1 << (shift - 1); + int j; + + for (j = 0; j < filterSize; j++) + val += src[j][i] * filter[j]; + + output_pixel(&dest[i], val); + } +} + +#undef output_pixel + +#define yuv2NBPS(bits, BE_LE, is_be, template_size, typeX_t) \ +static void yuv2plane1_ ## bits ## BE_LE ## _c(const int16_t *src, \ + uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset)\ +{ \ + yuv2plane1_ ## template_size ## _c_template((const typeX_t *) src, \ + (uint16_t *) dest, dstW, is_be, bits); \ +}\ +static void yuv2planeX_ ## bits ## BE_LE ## _c(const int16_t *filter, int filterSize, \ + const int16_t **src, uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset)\ +{ \ + yuv2planeX_## template_size ## _c_template(filter, \ + filterSize, (const typeX_t **) src, \ + (uint16_t *) dest, dstW, is_be, bits); \ +} + +yuv2NBPS( 9, BE, 1, 10, int16_t) +yuv2NBPS( 9, LE, 0, 10, int16_t) +yuv2NBPS(10, BE, 1, 10, int16_t) +yuv2NBPS(10, LE, 0, 10, int16_t) +yuv2NBPS(12, BE, 1, 10, int16_t) +yuv2NBPS(12, LE, 0, 10, int16_t) +yuv2NBPS(14, BE, 1, 10, int16_t) +yuv2NBPS(14, LE, 0, 10, int16_t) +yuv2NBPS(16, BE, 1, 16, int32_t) +yuv2NBPS(16, LE, 0, 16, int32_t) + +#define output_pixel(pos, val) \ + if (big_endian) { \ + AV_WB16(pos, av_clip_uintp2(val >> shift, output_bits) << (16 - output_bits)); \ + } else { \ + AV_WL16(pos, av_clip_uintp2(val >> shift, output_bits) << (16 - output_bits)); \ + } + +static av_always_inline void +yuv2msbplane1_10_c_template(const int16_t *src, uint16_t *dest, int dstW, + int big_endian, int output_bits) +{ + int i; + int shift = 15 - output_bits; + + for (i = 0; i < dstW; i++) { + int val = src[i] + (1 << (shift - 1)); + output_pixel(&dest[i], val); + } +} + +static av_always_inline void +yuv2msbplaneX_10_c_template(const int16_t *filter, int filterSize, + const int16_t **src, uint16_t *dest, int dstW, + int big_endian, int output_bits) +{ + int i; + int shift = 11 + 16 - output_bits; + + for (i = 0; i < dstW; i++) { + int val = 1 << (shift - 1); + int j; + + for (j = 0; j < filterSize; j++) + val += src[j][i] * filter[j]; + + output_pixel(&dest[i], val); + } +} + +#define yuv2MSBNBPS(bits, BE_LE, is_be, template_size, typeX_t) \ +static void yuv2msbplane1_ ## bits ## BE_LE ## _c(const int16_t *src, \ + uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset)\ +{ \ + yuv2msbplane1_ ## template_size ## _c_template((const typeX_t *) src, \ + (uint16_t *) dest, dstW, is_be, bits); \ +}\ +static void yuv2msbplaneX_ ## bits ## BE_LE ## _c(const int16_t *filter, int filterSize, \ + const int16_t **src, uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset)\ +{ \ + yuv2msbplaneX_## template_size ## _c_template(filter, \ + filterSize, (const typeX_t **) src, \ + (uint16_t *) dest, dstW, is_be, bits); \ +} + +yuv2MSBNBPS(10, BE, 1, 10, int16_t) +yuv2MSBNBPS(10, LE, 0, 10, int16_t) +yuv2MSBNBPS(12, BE, 1, 10, int16_t) +yuv2MSBNBPS(12, LE, 0, 10, int16_t) + +#undef output_pixel + +static void yuv2nv12cX_16LE_c(enum AVPixelFormat dstFormat, const uint8_t *chrDither, + const int16_t *chrFilter, int chrFilterSize, + const int16_t **chrUSrc, const int16_t **chrVSrc, + uint8_t *dest8, int chrDstW) +{ + yuv2nv12cX_16_c_template(0, chrDither, chrFilter, chrFilterSize, chrUSrc, chrVSrc, dest8, chrDstW, 16); +} + +static void yuv2nv12cX_16BE_c(enum AVPixelFormat dstFormat, const uint8_t *chrDither, + const int16_t *chrFilter, int chrFilterSize, + const int16_t **chrUSrc, const int16_t **chrVSrc, + uint8_t *dest8, int chrDstW) +{ + yuv2nv12cX_16_c_template(1, chrDither, chrFilter, chrFilterSize, chrUSrc, chrVSrc, dest8, chrDstW, 16); +} + +static void yuv2planeX_8_c(const int16_t *filter, int filterSize, + const int16_t **src, uint8_t *dest, int dstW, + const uint8_t *dither, int offset) +{ + int i; + for (i=0; i<dstW; i++) { + int val = dither[(i + offset) & 7] << 12; + int j; + for (j=0; j<filterSize; j++) { + val += (unsigned)(src[j][i] * filter[j]); + + } + + dest[i]= av_clip_uint8(val>>19); + } +} + +static void yuv2plane1_8_c(const int16_t *src, uint8_t *dest, int dstW, + const uint8_t *dither, int offset) +{ + int i; + for (i=0; i<dstW; i++) { + int val = (src[i] + dither[(i + offset) & 7]) >> 7; + dest[i]= av_clip_uint8(val); + } +} + +static void yuv2nv12cX_c(enum AVPixelFormat dstFormat, const uint8_t *chrDither, + const int16_t *chrFilter, int chrFilterSize, + const int16_t **chrUSrc, const int16_t **chrVSrc, + uint8_t *dest, int chrDstW) +{ + int i; + + if (!isSwappedChroma(dstFormat)) + for (i=0; i<chrDstW; i++) { + int u = chrDither[i & 7] << 12; + int v = chrDither[(i + 3) & 7] << 12; + int j; + for (j=0; j<chrFilterSize; j++) { + u += chrUSrc[j][i] * (unsigned)chrFilter[j]; + v += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + + dest[2*i]= av_clip_uint8(u>>19); + dest[2*i+1]= av_clip_uint8(v>>19); + } + else + for (i=0; i<chrDstW; i++) { + int u = chrDither[i & 7] << 12; + int v = chrDither[(i + 3) & 7] << 12; + int j; + for (j=0; j<chrFilterSize; j++) { + u += chrUSrc[j][i] * (unsigned)chrFilter[j]; + v += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + + dest[2*i]= av_clip_uint8(v>>19); + dest[2*i+1]= av_clip_uint8(u>>19); + } +} + + +#define output_pixel(pos, val) \ + if (big_endian) { \ + AV_WB16(pos, av_clip_uintp2(val >> shift, output_bits) << output_shift); \ + } else { \ + AV_WL16(pos, av_clip_uintp2(val >> shift, output_bits) << output_shift); \ + } + +static void yuv2p01xl1_c(const int16_t *src, + uint16_t *dest, int dstW, + int big_endian, int output_bits, int output_shift) +{ + int i; + int shift = 15 - output_bits; + + for (i = 0; i < dstW; i++) { + int val = src[i] + (1 << (shift - 1)); + output_pixel(&dest[i], val); + } +} + +static void yuv2p01xlX_c(const int16_t *filter, int filterSize, + const int16_t **src, uint16_t *dest, int dstW, + int big_endian, int output_bits, int output_shift) +{ + int i, j; + int shift = 11 + 16 - output_bits; + + for (i = 0; i < dstW; i++) { + int val = 1 << (shift - 1); + + for (j = 0; j < filterSize; j++) + val += src[j][i] * filter[j]; + + output_pixel(&dest[i], val); + } +} + +static void yuv2p01xcX_c(int big_endian, const uint8_t *chrDither, + const int16_t *chrFilter, int chrFilterSize, + const int16_t **chrUSrc, const int16_t **chrVSrc, + uint8_t *dest8, int chrDstW, int output_bits, int output_shift) +{ + uint16_t *dest = (uint16_t*)dest8; + int i, j; + int shift = 11 + 16 - output_bits; + + for (i = 0; i < chrDstW; i++) { + int u = 1 << (shift - 1); + int v = 1 << (shift - 1); + + for (j = 0; j < chrFilterSize; j++) { + u += chrUSrc[j][i] * (unsigned)chrFilter[j]; + v += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + + output_pixel(&dest[2*i] , u); + output_pixel(&dest[2*i+1], v); + } +} + +#undef output_pixel + +#define yuv2p01x_wrapper(fmt, bits, shift) \ + static void yuv2 ## fmt ## l1_LE_c(const int16_t *src, \ + uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset) \ + { \ + yuv2p01xl1_c(src, (uint16_t*)dest, dstW, 0, bits, shift); \ + } \ + \ + static void yuv2 ## fmt ## l1_BE_c(const int16_t *src, \ + uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset) \ + { \ + yuv2p01xl1_c(src, (uint16_t*)dest, dstW, 1, bits, shift); \ + } \ + \ + static void yuv2 ## fmt ## lX_LE_c(const int16_t *filter, \ + int filterSize, const int16_t **src, \ + uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset) \ + { \ + yuv2p01xlX_c(filter, filterSize, src, (uint16_t*)dest, dstW, 0, \ + bits, shift); \ + } \ + \ + static void yuv2 ## fmt ## lX_BE_c(const int16_t *filter, \ + int filterSize, const int16_t **src, \ + uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset) \ + { \ + yuv2p01xlX_c(filter, filterSize, src, (uint16_t*)dest, dstW, 1, \ + bits, shift); \ + } \ + \ + static void yuv2 ## fmt ## cX_LE_c(enum AVPixelFormat dstFormat, \ + const uint8_t *chrDither, \ + const int16_t *chrFilter, \ + int chrFilterSize, \ + const int16_t **chrUSrc, \ + const int16_t **chrVSrc, \ + uint8_t *dest8, int chrDstW) \ + { \ + yuv2p01xcX_c(0, chrDither, chrFilter, chrFilterSize, chrUSrc, chrVSrc, \ + dest8, chrDstW, bits, shift); \ + } \ + \ + static void yuv2 ## fmt ## cX_BE_c(enum AVPixelFormat dstFormat, \ + const uint8_t *chrDither, \ + const int16_t *chrFilter, \ + int chrFilterSize, \ + const int16_t **chrUSrc, \ + const int16_t **chrVSrc, \ + uint8_t *dest8, int chrDstW) \ + { \ + yuv2p01xcX_c(1, chrDither, chrFilter, chrFilterSize, chrUSrc, chrVSrc, \ + dest8, chrDstW, bits, shift); \ + } + +yuv2p01x_wrapper(p010, 10, 6) +yuv2p01x_wrapper(p012, 12, 4) +yuv2p01x_wrapper(nv20, 10, 0) + +#define accumulate_bit(acc, val) \ + acc <<= 1; \ + acc |= (val) >= 234 +#define output_pixel(pos, acc) \ + if (target == AV_PIX_FMT_MONOBLACK) { \ + pos = acc; \ + } else { \ + pos = ~acc; \ + } + +static av_always_inline void +yuv2mono_X_c_template(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t *dest, int dstW, + int y, enum AVPixelFormat target) +{ + const uint8_t * const d128 = ff_dither_8x8_220[y&7]; + int i; + unsigned acc = 0; + int err = 0; + + for (i = 0; i < dstW; i += 2) { + int j; + int Y1 = 1 << 18; + int Y2 = 1 << 18; + + for (j = 0; j < lumFilterSize; j++) { + Y1 += lumSrc[j][i] * (unsigned)lumFilter[j]; + Y2 += lumSrc[j][i+1] * (unsigned)lumFilter[j]; + } + Y1 >>= 19; + Y2 >>= 19; + if ((Y1 | Y2) & 0x100) { + Y1 = av_clip_uint8(Y1); + Y2 = av_clip_uint8(Y2); + } + if (c->opts.dither == SWS_DITHER_ED) { + Y1 += (7*err + 1*c->dither_error[0][i] + 5*c->dither_error[0][i+1] + 3*c->dither_error[0][i+2] + 8 - 256)>>4; + c->dither_error[0][i] = err; + acc = 2*acc + (Y1 >= 128); + Y1 -= 220*(acc&1); + + err = Y2 + ((7*Y1 + 1*c->dither_error[0][i+1] + 5*c->dither_error[0][i+2] + 3*c->dither_error[0][i+3] + 8 - 256)>>4); + c->dither_error[0][i+1] = Y1; + acc = 2*acc + (err >= 128); + err -= 220*(acc&1); + } else { + accumulate_bit(acc, Y1 + d128[(i + 0) & 7]); + accumulate_bit(acc, Y2 + d128[(i + 1) & 7]); + } + if ((i & 7) == 6) { + output_pixel(*dest++, acc); + } + } + c->dither_error[0][i] = err; + + if (i & 6) { + output_pixel(*dest, acc); + } +} + +static av_always_inline void +yuv2mono_2_c_template(SwsInternal *c, const int16_t *buf[2], + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf[2], uint8_t *dest, int dstW, + int yalpha, int uvalpha, int y, + enum AVPixelFormat target) +{ + const int16_t *buf0 = buf[0], *buf1 = buf[1]; + const uint8_t * const d128 = ff_dither_8x8_220[y & 7]; + int yalpha1 = 4096 - yalpha; + int i; + av_assert2(yalpha <= 4096U); + + if (c->opts.dither == SWS_DITHER_ED) { + int err = 0; + unsigned acc = 0; + for (i = 0; i < dstW; i +=2) { + int Y; + + Y = (buf0[i + 0] * yalpha1 + buf1[i + 0] * yalpha) >> 19; + Y += (7*err + 1*c->dither_error[0][i] + 5*c->dither_error[0][i+1] + 3*c->dither_error[0][i+2] + 8 - 256)>>4; + c->dither_error[0][i] = err; + acc = 2*acc + (Y >= 128); + Y -= 220*(acc&1); + + err = (buf0[i + 1] * yalpha1 + buf1[i + 1] * yalpha) >> 19; + err += (7*Y + 1*c->dither_error[0][i+1] + 5*c->dither_error[0][i+2] + 3*c->dither_error[0][i+3] + 8 - 256)>>4; + c->dither_error[0][i+1] = Y; + acc = 2*acc + (err >= 128); + err -= 220*(acc&1); + + if ((i & 7) == 6) + output_pixel(*dest++, acc); + } + c->dither_error[0][i] = err; + } else { + for (i = 0; i < dstW; i += 8) { + int Y; + unsigned acc = 0; + + Y = (buf0[i + 0] * yalpha1 + buf1[i + 0] * yalpha) >> 19; + accumulate_bit(acc, Y + d128[0]); + Y = (buf0[i + 1] * yalpha1 + buf1[i + 1] * yalpha) >> 19; + accumulate_bit(acc, Y + d128[1]); + Y = (buf0[i + 2] * yalpha1 + buf1[i + 2] * yalpha) >> 19; + accumulate_bit(acc, Y + d128[2]); + Y = (buf0[i + 3] * yalpha1 + buf1[i + 3] * yalpha) >> 19; + accumulate_bit(acc, Y + d128[3]); + Y = (buf0[i + 4] * yalpha1 + buf1[i + 4] * yalpha) >> 19; + accumulate_bit(acc, Y + d128[4]); + Y = (buf0[i + 5] * yalpha1 + buf1[i + 5] * yalpha) >> 19; + accumulate_bit(acc, Y + d128[5]); + Y = (buf0[i + 6] * yalpha1 + buf1[i + 6] * yalpha) >> 19; + accumulate_bit(acc, Y + d128[6]); + Y = (buf0[i + 7] * yalpha1 + buf1[i + 7] * yalpha) >> 19; + accumulate_bit(acc, Y + d128[7]); + + output_pixel(*dest++, acc); + } + } +} + +static av_always_inline void +yuv2mono_1_c_template(SwsInternal *c, const int16_t *buf0, + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf0, uint8_t *dest, int dstW, + int uvalpha, int y, enum AVPixelFormat target) +{ + const uint8_t * const d128 = ff_dither_8x8_220[y & 7]; + int i; + + if (c->opts.dither == SWS_DITHER_ED) { + int err = 0; + unsigned acc = 0; + for (i = 0; i < dstW; i +=2) { + int Y; + + Y = ((buf0[i + 0] + 64) >> 7); + Y += (7*err + 1*c->dither_error[0][i] + 5*c->dither_error[0][i+1] + 3*c->dither_error[0][i+2] + 8 - 256)>>4; + c->dither_error[0][i] = err; + acc = 2*acc + (Y >= 128); + Y -= 220*(acc&1); + + err = ((buf0[i + 1] + 64) >> 7); + err += (7*Y + 1*c->dither_error[0][i+1] + 5*c->dither_error[0][i+2] + 3*c->dither_error[0][i+3] + 8 - 256)>>4; + c->dither_error[0][i+1] = Y; + acc = 2*acc + (err >= 128); + err -= 220*(acc&1); + + if ((i & 7) == 6) + output_pixel(*dest++, acc); + } + c->dither_error[0][i] = err; + } else { + for (i = 0; i < dstW; i += 8) { + unsigned acc = 0; + accumulate_bit(acc, ((buf0[i + 0] + 64) >> 7) + d128[0]); + accumulate_bit(acc, ((buf0[i + 1] + 64) >> 7) + d128[1]); + accumulate_bit(acc, ((buf0[i + 2] + 64) >> 7) + d128[2]); + accumulate_bit(acc, ((buf0[i + 3] + 64) >> 7) + d128[3]); + accumulate_bit(acc, ((buf0[i + 4] + 64) >> 7) + d128[4]); + accumulate_bit(acc, ((buf0[i + 5] + 64) >> 7) + d128[5]); + accumulate_bit(acc, ((buf0[i + 6] + 64) >> 7) + d128[6]); + accumulate_bit(acc, ((buf0[i + 7] + 64) >> 7) + d128[7]); + + output_pixel(*dest++, acc); + } + } +} + +#undef output_pixel +#undef accumulate_bit + +#define YUV2PACKEDWRAPPER(name, base, ext, fmt) \ +static void name ## ext ## _X_c(SwsInternal *c, const int16_t *lumFilter, \ + const int16_t **lumSrc, int lumFilterSize, \ + const int16_t *chrFilter, const int16_t **chrUSrc, \ + const int16_t **chrVSrc, int chrFilterSize, \ + const int16_t **alpSrc, uint8_t *dest, int dstW, \ + int y) \ +{ \ + name ## base ## _X_c_template(c, lumFilter, lumSrc, lumFilterSize, \ + chrFilter, chrUSrc, chrVSrc, chrFilterSize, \ + alpSrc, dest, dstW, y, fmt); \ +} \ + \ +static void name ## ext ## _2_c(SwsInternal *c, const int16_t *buf[2], \ + const int16_t *ubuf[2], const int16_t *vbuf[2], \ + const int16_t *abuf[2], uint8_t *dest, int dstW, \ + int yalpha, int uvalpha, int y) \ +{ \ + name ## base ## _2_c_template(c, buf, ubuf, vbuf, abuf, \ + dest, dstW, yalpha, uvalpha, y, fmt); \ +} \ + \ +static void name ## ext ## _1_c(SwsInternal *c, const int16_t *buf0, \ + const int16_t *ubuf[2], const int16_t *vbuf[2], \ + const int16_t *abuf0, uint8_t *dest, int dstW, \ + int uvalpha, int y) \ +{ \ + name ## base ## _1_c_template(c, buf0, ubuf, vbuf, \ + abuf0, dest, dstW, uvalpha, \ + y, fmt); \ +} + +YUV2PACKEDWRAPPER(yuv2mono,, white, AV_PIX_FMT_MONOWHITE) +YUV2PACKEDWRAPPER(yuv2mono,, black, AV_PIX_FMT_MONOBLACK) + +#define output_pixels(pos, Y1, U, Y2, V) \ + if (target == AV_PIX_FMT_YUYV422) { \ + dest[pos + 0] = Y1; \ + dest[pos + 1] = U; \ + dest[pos + 2] = Y2; \ + dest[pos + 3] = V; \ + } else if (target == AV_PIX_FMT_YVYU422) { \ + dest[pos + 0] = Y1; \ + dest[pos + 1] = V; \ + dest[pos + 2] = Y2; \ + dest[pos + 3] = U; \ + } else { /* AV_PIX_FMT_UYVY422 */ \ + dest[pos + 0] = U; \ + dest[pos + 1] = Y1; \ + dest[pos + 2] = V; \ + dest[pos + 3] = Y2; \ + } + +static av_always_inline void +yuv2422_X_c_template(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t *dest, int dstW, + int y, enum AVPixelFormat target) +{ + int i; + + for (i = 0; i < ((dstW + 1) >> 1); i++) { + int j; + int Y1 = 1 << 18; + int Y2 = 1 << 18; + int U = 1 << 18; + int V = 1 << 18; + + for (j = 0; j < lumFilterSize; j++) { + Y1 += lumSrc[j][i * 2] * (unsigned)lumFilter[j]; + Y2 += lumSrc[j][i * 2 + 1] * (unsigned)lumFilter[j]; + } + for (j = 0; j < chrFilterSize; j++) { + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + Y1 >>= 19; + Y2 >>= 19; + U >>= 19; + V >>= 19; + if ((Y1 | Y2 | U | V) & 0x100) { + Y1 = av_clip_uint8(Y1); + Y2 = av_clip_uint8(Y2); + U = av_clip_uint8(U); + V = av_clip_uint8(V); + } + output_pixels(4*i, Y1, U, Y2, V); + } +} + +static av_always_inline void +yuv2422_2_c_template(SwsInternal *c, const int16_t *buf[2], + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf[2], uint8_t *dest, int dstW, + int yalpha, int uvalpha, int y, + enum AVPixelFormat target) +{ + const int16_t *buf0 = buf[0], *buf1 = buf[1], + *ubuf0 = ubuf[0], *ubuf1 = ubuf[1], + *vbuf0 = vbuf[0], *vbuf1 = vbuf[1]; + int yalpha1 = 4096 - yalpha; + int uvalpha1 = 4096 - uvalpha; + int i; + av_assert2(yalpha <= 4096U); + av_assert2(uvalpha <= 4096U); + + for (i = 0; i < ((dstW + 1) >> 1); i++) { + int Y1 = (buf0[i * 2] * yalpha1 + buf1[i * 2] * yalpha) >> 19; + int Y2 = (buf0[i * 2 + 1] * yalpha1 + buf1[i * 2 + 1] * yalpha) >> 19; + int U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha) >> 19; + int V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha) >> 19; + + if ((Y1 | Y2 | U | V) & 0x100) { + Y1 = av_clip_uint8(Y1); + Y2 = av_clip_uint8(Y2); + U = av_clip_uint8(U); + V = av_clip_uint8(V); + } + + output_pixels(i * 4, Y1, U, Y2, V); + } +} + +static av_always_inline void +yuv2422_1_c_template(SwsInternal *c, const int16_t *buf0, + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf0, uint8_t *dest, int dstW, + int uvalpha, int y, enum AVPixelFormat target) +{ + const int16_t *ubuf0 = ubuf[0], *vbuf0 = vbuf[0]; + int i; + + if (uvalpha < 2048) { + for (i = 0; i < ((dstW + 1) >> 1); i++) { + int Y1 = (buf0[i * 2 ]+64) >> 7; + int Y2 = (buf0[i * 2 + 1]+64) >> 7; + int U = (ubuf0[i] +64) >> 7; + int V = (vbuf0[i] +64) >> 7; + + if ((Y1 | Y2 | U | V) & 0x100) { + Y1 = av_clip_uint8(Y1); + Y2 = av_clip_uint8(Y2); + U = av_clip_uint8(U); + V = av_clip_uint8(V); + } + + output_pixels(i * 4, Y1, U, Y2, V); + } + } else { + const int16_t *ubuf1 = ubuf[1], *vbuf1 = vbuf[1]; + for (i = 0; i < ((dstW + 1) >> 1); i++) { + int Y1 = (buf0[i * 2 ] + 64) >> 7; + int Y2 = (buf0[i * 2 + 1] + 64) >> 7; + int U = (ubuf0[i] + ubuf1[i]+128) >> 8; + int V = (vbuf0[i] + vbuf1[i]+128) >> 8; + + if ((Y1 | Y2 | U | V) & 0x100) { + Y1 = av_clip_uint8(Y1); + Y2 = av_clip_uint8(Y2); + U = av_clip_uint8(U); + V = av_clip_uint8(V); + } + + output_pixels(i * 4, Y1, U, Y2, V); + } + } +} + +#undef output_pixels + +YUV2PACKEDWRAPPER(yuv2, 422, yuyv422, AV_PIX_FMT_YUYV422) +YUV2PACKEDWRAPPER(yuv2, 422, yvyu422, AV_PIX_FMT_YVYU422) +YUV2PACKEDWRAPPER(yuv2, 422, uyvy422, AV_PIX_FMT_UYVY422) + +#define R_B ((target == AV_PIX_FMT_RGB48LE || target == AV_PIX_FMT_RGB48BE || target == AV_PIX_FMT_RGBA64LE || target == AV_PIX_FMT_RGBA64BE) ? R : B) +#define B_R ((target == AV_PIX_FMT_RGB48LE || target == AV_PIX_FMT_RGB48BE || target == AV_PIX_FMT_RGBA64LE || target == AV_PIX_FMT_RGBA64BE) ? B : R) +#define output_pixel(pos, val) \ + if (is_be) { \ + AV_WB16(pos, val); \ + } else { \ + AV_WL16(pos, val); \ + } + +static av_always_inline void +yuv2ya16_X_c_template(SwsInternal *c, const int16_t *lumFilter, + const int32_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int32_t **unused_chrUSrc, + const int32_t **unused_chrVSrc, int unused_chrFilterSize, + const int32_t **alpSrc, uint16_t *dest, int dstW, + int y, enum AVPixelFormat target, + int unused_hasAlpha, int unused_eightbytes, int is_be) +{ + int hasAlpha = !!alpSrc; + int i; + + for (i = 0; i < dstW; i++) { + int j; + int Y = -0x40000000; + int A = 0xffff; + + for (j = 0; j < lumFilterSize; j++) + Y += lumSrc[j][i] * (unsigned)lumFilter[j]; + + Y >>= 15; + Y += (1<<3) + 0x8000; + Y = av_clip_uint16(Y); + + if (hasAlpha) { + A = -0x40000000 + (1<<14); + for (j = 0; j < lumFilterSize; j++) + A += alpSrc[j][i] * (unsigned)lumFilter[j]; + + A >>= 15; + A += 0x8000; + A = av_clip_uint16(A); + } + + output_pixel(&dest[2 * i ], Y); + output_pixel(&dest[2 * i + 1], A); + } +} + +static av_always_inline void +yuv2ya16_2_c_template(SwsInternal *c, const int32_t *buf[2], + const int32_t *unused_ubuf[2], const int32_t *unused_vbuf[2], + const int32_t *abuf[2], uint16_t *dest, int dstW, + int yalpha_param, int unused_uvalpha, int y, + enum AVPixelFormat target, int unused_hasAlpha, + int unused_eightbytes, int is_be) +{ + unsigned yalpha = yalpha_param; + int hasAlpha = abuf && abuf[0] && abuf[1]; + const int32_t *buf0 = buf[0], *buf1 = buf[1], + *abuf0 = hasAlpha ? abuf[0] : NULL, + *abuf1 = hasAlpha ? abuf[1] : NULL; + unsigned yalpha1 = 4096 - yalpha; + int i; + + av_assert2(yalpha <= 4096U); + + for (i = 0; i < dstW; i++) { + int Y = (int)(buf0[i] * yalpha1 + buf1[i] * yalpha) >> 15; + int A; + + Y = av_clip_uint16(Y); + + if (hasAlpha) { + A = (int)(abuf0[i] * yalpha1 + abuf1[i] * yalpha) >> 15; + A = av_clip_uint16(A); + } + + output_pixel(&dest[2 * i ], Y); + output_pixel(&dest[2 * i + 1], hasAlpha ? A : 65535); + } +} + +static av_always_inline void +yuv2ya16_1_c_template(SwsInternal *c, const int32_t *buf0, + const int32_t *unused_ubuf[2], const int32_t *unused_vbuf[2], + const int32_t *abuf0, uint16_t *dest, int dstW, + int unused_uvalpha, int y, enum AVPixelFormat target, + int unused_hasAlpha, int unused_eightbytes, int is_be) +{ + int hasAlpha = !!abuf0; + int i; + + for (i = 0; i < dstW; i++) { + int Y = buf0[i] >> 3;/* 19 - 16 */ + int A; + + Y = av_clip_uint16(Y); + + if (hasAlpha) { + A = abuf0[i] >> 3; + if (A & 0x100) + A = av_clip_uint16(A); + } + + output_pixel(&dest[2 * i ], Y); + output_pixel(&dest[2 * i + 1], hasAlpha ? A : 65535); + } +} + +static av_always_inline void +yuv2rgba64_X_c_template(SwsInternal *c, const int16_t *lumFilter, + const int32_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int32_t **chrUSrc, + const int32_t **chrVSrc, int chrFilterSize, + const int32_t **alpSrc, uint16_t *dest, int dstW, + int y, enum AVPixelFormat target, int hasAlpha, int eightbytes, + int is_be) +{ + int i; + int A1 = 0xffff<<14, A2 = 0xffff<<14; + + for (i = 0; i < ((dstW + 1) >> 1); i++) { + int j; + unsigned Y1 = -0x40000000; + unsigned Y2 = -0x40000000; + unsigned U = -(128 << 23); // 19 + unsigned V = -(128 << 23); + int R, G, B; + + for (j = 0; j < lumFilterSize; j++) { + Y1 += lumSrc[j][i * 2] * (unsigned)lumFilter[j]; + Y2 += lumSrc[j][i * 2 + 1] * (unsigned)lumFilter[j]; + } + for (j = 0; j < chrFilterSize; j++) {; + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + + if (hasAlpha) { + A1 = -0x40000000; + A2 = -0x40000000; + for (j = 0; j < lumFilterSize; j++) { + A1 += alpSrc[j][i * 2] * (unsigned)lumFilter[j]; + A2 += alpSrc[j][i * 2 + 1] * (unsigned)lumFilter[j]; + } + A1 >>= 1; + A1 += 0x20002000; + A2 >>= 1; + A2 += 0x20002000; + } + + // 8 bits: 12+15=27; 16 bits: 12+19=31 + Y1 = (int)Y1 >> 14; // 10 + Y1 += 0x10000; + Y2 = (int)Y2 >> 14; + Y2 += 0x10000; + U = (int)U >> 14; + V = (int)V >> 14; + + // 8 bits: 27 -> 17 bits, 16 bits: 31 - 14 = 17 bits + Y1 -= c->yuv2rgb_y_offset; + Y2 -= c->yuv2rgb_y_offset; + Y1 *= c->yuv2rgb_y_coeff; + Y2 *= c->yuv2rgb_y_coeff; + Y1 += (1 << 13) - (1 << 29); // 21 + Y2 += (1 << 13) - (1 << 29); + // 8 bits: 17 + 13 bits = 30 bits, 16 bits: 17 + 13 bits = 30 bits + + R = V * c->yuv2rgb_v2r_coeff; + G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff; + B = U * c->yuv2rgb_u2b_coeff; + + // 8 bits: 30 - 22 = 8 bits, 16 bits: 30 bits - 14 = 16 bits + output_pixel(&dest[0], av_clip_uintp2(((int)(R_B + Y1) >> 14) + (1<<15), 16)); + output_pixel(&dest[1], av_clip_uintp2(((int)( G + Y1) >> 14) + (1<<15), 16)); + output_pixel(&dest[2], av_clip_uintp2(((int)(B_R + Y1) >> 14) + (1<<15), 16)); + if (eightbytes) { + output_pixel(&dest[3], av_clip_uintp2(A1 , 30) >> 14); + output_pixel(&dest[4], av_clip_uintp2(((int)(R_B + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[5], av_clip_uintp2(((int)( G + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[6], av_clip_uintp2(((int)(B_R + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[7], av_clip_uintp2(A2 , 30) >> 14); + dest += 8; + } else { + output_pixel(&dest[3], av_clip_uintp2(((int)(R_B + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[4], av_clip_uintp2(((int)( G + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[5], av_clip_uintp2(((int)(B_R + Y2) >> 14) + (1<<15), 16)); + dest += 6; + } + } +} + +static av_always_inline void +yuv2rgba64_2_c_template(SwsInternal *c, const int32_t *buf[2], + const int32_t *ubuf[2], const int32_t *vbuf[2], + const int32_t *abuf[2], uint16_t *dest, int dstW, + int yalpha_param, int uvalpha_param, int y, + enum AVPixelFormat target, int hasAlpha, int eightbytes, + int is_be) +{ + unsigned yalpha = yalpha_param; + unsigned uvalpha = uvalpha_param; + const int32_t *buf0 = buf[0], *buf1 = buf[1], + *ubuf0 = ubuf[0], *ubuf1 = ubuf[1], + *vbuf0 = vbuf[0], *vbuf1 = vbuf[1], + *abuf0 = hasAlpha ? abuf[0] : NULL, + *abuf1 = hasAlpha ? abuf[1] : NULL; + unsigned yalpha1 = 4096 - yalpha; + unsigned uvalpha1 = 4096 - uvalpha; + int i; + int A1 = 0xffff<<14, A2 = 0xffff<<14; + + av_assert2(yalpha <= 4096U); + av_assert2(uvalpha <= 4096U); + + for (i = 0; i < ((dstW + 1) >> 1); i++) { + unsigned Y1 = (int)(buf0[i * 2] * yalpha1 + buf1[i * 2] * yalpha) >> 14; + unsigned Y2 = (int)(buf0[i * 2 + 1] * yalpha1 + buf1[i * 2 + 1] * yalpha) >> 14; + int U = (int)(ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha - (128 << 23)) >> 14; + int V = (int)(vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha - (128 << 23)) >> 14; + int R, G, B; + + Y1 -= c->yuv2rgb_y_offset; + Y2 -= c->yuv2rgb_y_offset; + Y1 *= c->yuv2rgb_y_coeff; + Y2 *= c->yuv2rgb_y_coeff; + Y1 += (1 << 13) - (1 << 29); + Y2 += (1 << 13) - (1 << 29); + + R = (SUINT)V * c->yuv2rgb_v2r_coeff; + G = (SUINT)V * c->yuv2rgb_v2g_coeff + (SUINT)U * c->yuv2rgb_u2g_coeff; + B = (SUINT)U * c->yuv2rgb_u2b_coeff; + + if (hasAlpha) { + A1 = (int)(abuf0[i * 2 ] * yalpha1 + abuf1[i * 2 ] * yalpha) >> 1; + A2 = (int)(abuf0[i * 2 + 1] * yalpha1 + abuf1[i * 2 + 1] * yalpha) >> 1; + + A1 += 1 << 13; + A2 += 1 << 13; + } + + output_pixel(&dest[0], av_clip_uintp2(((int)(R_B + Y1) >> 14) + (1<<15), 16)); + output_pixel(&dest[1], av_clip_uintp2(((int)( G + Y1) >> 14) + (1<<15), 16)); + output_pixel(&dest[2], av_clip_uintp2(((int)(B_R + Y1) >> 14) + (1<<15), 16)); + if (eightbytes) { + output_pixel(&dest[3], av_clip_uintp2(A1 , 30) >> 14); + output_pixel(&dest[4], av_clip_uintp2(((int)(R_B + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[5], av_clip_uintp2(((int)( G + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[6], av_clip_uintp2(((int)(B_R + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[7], av_clip_uintp2(A2 , 30) >> 14); + dest += 8; + } else { + output_pixel(&dest[3], av_clip_uintp2(((int)(R_B + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[4], av_clip_uintp2(((int)( G + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[5], av_clip_uintp2(((int)(B_R + Y2) >> 14) + (1<<15), 16)); + dest += 6; + } + } +} + +static av_always_inline void +yuv2rgba64_1_c_template(SwsInternal *c, const int32_t *buf0, + const int32_t *ubuf[2], const int32_t *vbuf[2], + const int32_t *abuf0, uint16_t *dest, int dstW, + int uvalpha, int y, enum AVPixelFormat target, + int hasAlpha, int eightbytes, int is_be) +{ + const int32_t *ubuf0 = ubuf[0], *vbuf0 = vbuf[0]; + int i; + SUINT A1 = 0xffff<<14, A2= 0xffff<<14; + + if (uvalpha == 0) { + for (i = 0; i < ((dstW + 1) >> 1); i++) { + SUINT Y1 = (buf0[i * 2] ) >> 2; + SUINT Y2 = (buf0[i * 2 + 1]) >> 2; + SUINT U = (ubuf0[i] - (128 << 11)) >> 2; + SUINT V = (vbuf0[i] - (128 << 11)) >> 2; + int R, G, B; + + Y1 -= c->yuv2rgb_y_offset; + Y2 -= c->yuv2rgb_y_offset; + Y1 *= c->yuv2rgb_y_coeff; + Y2 *= c->yuv2rgb_y_coeff; + Y1 += (1 << 13) - (1 << 29); + Y2 += (1 << 13) - (1 << 29); + + if (hasAlpha) { + A1 = abuf0[i * 2 ] * (SUINT)(1 << 11); + A2 = abuf0[i * 2 + 1] * (SUINT)(1 << 11); + + A1 += 1 << 13; + A2 += 1 << 13; + } + + R = V * c->yuv2rgb_v2r_coeff; + G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff; + B = U * c->yuv2rgb_u2b_coeff; + + output_pixel(&dest[0], av_clip_uintp2(((int)(R_B + Y1) >> 14) + (1<<15), 16)); + output_pixel(&dest[1], av_clip_uintp2(((int)( G + Y1) >> 14) + (1<<15), 16)); + output_pixel(&dest[2], av_clip_uintp2(((int)(B_R + Y1) >> 14) + (1<<15), 16)); + if (eightbytes) { + output_pixel(&dest[3], av_clip_uintp2(A1 , 30) >> 14); + output_pixel(&dest[4], av_clip_uintp2(((int)(R_B + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[5], av_clip_uintp2(((int)( G + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[6], av_clip_uintp2(((int)(B_R + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[7], av_clip_uintp2(A2 , 30) >> 14); + dest += 8; + } else { + output_pixel(&dest[3], av_clip_uintp2(((int)(R_B + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[4], av_clip_uintp2(((int)( G + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[5], av_clip_uintp2(((int)(B_R + Y2) >> 14) + (1<<15), 16)); + dest += 6; + } + } + } else { + const int32_t *ubuf1 = ubuf[1], *vbuf1 = vbuf[1]; + int A1 = 0xffff<<14, A2 = 0xffff<<14; + unsigned uvalpha1 = 4096 - uvalpha; + av_assert2(uvalpha <= 4096U); + + for (i = 0; i < ((dstW + 1) >> 1); i++) { + SUINT Y1 = (buf0[i * 2] ) >> 2; + SUINT Y2 = (buf0[i * 2 + 1]) >> 2; + SUINT U = (int)((SUINT)ubuf0[i] * uvalpha1 + (SUINT)ubuf1[i] * uvalpha - (128 << 23)) >> 14; + SUINT V = (int)((SUINT)vbuf0[i] * uvalpha1 + (SUINT)vbuf1[i] * uvalpha - (128 << 23)) >> 14; + int R, G, B; + + Y1 -= c->yuv2rgb_y_offset; + Y2 -= c->yuv2rgb_y_offset; + Y1 *= c->yuv2rgb_y_coeff; + Y2 *= c->yuv2rgb_y_coeff; + Y1 += (1 << 13) - (1 << 29); + Y2 += (1 << 13) - (1 << 29); + + if (hasAlpha) { + A1 = abuf0[i * 2 ] * (1 << 11); + A2 = abuf0[i * 2 + 1] * (1 << 11); + + A1 += 1 << 13; + A2 += 1 << 13; + } + + R = V * c->yuv2rgb_v2r_coeff; + G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff; + B = U * c->yuv2rgb_u2b_coeff; + + output_pixel(&dest[0], av_clip_uintp2(((int)(R_B + Y1) >> 14) + (1<<15), 16)); + output_pixel(&dest[1], av_clip_uintp2(((int)( G + Y1) >> 14) + (1<<15), 16)); + output_pixel(&dest[2], av_clip_uintp2(((int)(B_R + Y1) >> 14) + (1<<15), 16)); + if (eightbytes) { + output_pixel(&dest[3], av_clip_uintp2(A1 , 30) >> 14); + output_pixel(&dest[4], av_clip_uintp2(((int)(R_B + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[5], av_clip_uintp2(((int)( G + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[6], av_clip_uintp2(((int)(B_R + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[7], av_clip_uintp2(A2 , 30) >> 14); + dest += 8; + } else { + output_pixel(&dest[3], av_clip_uintp2(((int)(R_B + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[4], av_clip_uintp2(((int)( G + Y2) >> 14) + (1<<15), 16)); + output_pixel(&dest[5], av_clip_uintp2(((int)(B_R + Y2) >> 14) + (1<<15), 16)); + dest += 6; + } + } + } +} + +static av_always_inline void +yuv2rgba64_full_X_c_template(SwsInternal *c, const int16_t *lumFilter, + const int32_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int32_t **chrUSrc, + const int32_t **chrVSrc, int chrFilterSize, + const int32_t **alpSrc, uint16_t *dest, int dstW, + int y, enum AVPixelFormat target, int hasAlpha, + int eightbytes, int is_be) +{ + int i; + int A = 0xffff<<14; + + for (i = 0; i < dstW; i++) { + int j; + int Y = -0x40000000; + int U = -(128 << 23); // 19 + int V = -(128 << 23); + int R, G, B; + + for (j = 0; j < lumFilterSize; j++) { + Y += lumSrc[j][i] * (unsigned)lumFilter[j]; + } + for (j = 0; j < chrFilterSize; j++) {; + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + + if (hasAlpha) { + A = -0x40000000; + for (j = 0; j < lumFilterSize; j++) { + A += alpSrc[j][i] * (unsigned)lumFilter[j]; + } + A >>= 1; + A += 0x20002000; + } + + // 8bit: 12+15=27; 16-bit: 12+19=31 + Y >>= 14; // 10 + Y += 0x10000; + U >>= 14; + V >>= 14; + + // 8bit: 27 -> 17bit, 16bit: 31 - 14 = 17bit + Y -= c->yuv2rgb_y_offset; + Y *= c->yuv2rgb_y_coeff; + Y += (1 << 13) - (1<<29); // 21 + // 8bit: 17 + 13bit = 30bit, 16bit: 17 + 13bit = 30bit + + R = (unsigned)V * c->yuv2rgb_v2r_coeff; + G = (unsigned)V * c->yuv2rgb_v2g_coeff + (unsigned)U * c->yuv2rgb_u2g_coeff; + B = (unsigned)U * c->yuv2rgb_u2b_coeff; + + // 8bit: 30 - 22 = 8bit, 16bit: 30bit - 14 = 16bit + output_pixel(&dest[0], av_clip_uintp2(((int)(R_B + (unsigned)Y)>>14) + (1<<15), 16)); + output_pixel(&dest[1], av_clip_uintp2(((int)( G + (unsigned)Y)>>14) + (1<<15), 16)); + output_pixel(&dest[2], av_clip_uintp2(((int)(B_R + (unsigned)Y)>>14) + (1<<15), 16)); + if (eightbytes) { + output_pixel(&dest[3], av_clip_uintp2(A, 30) >> 14); + dest += 4; + } else { + dest += 3; + } + } +} + +static av_always_inline void +yuv2rgba64_full_2_c_template(SwsInternal *c, const int32_t *buf[2], + const int32_t *ubuf[2], const int32_t *vbuf[2], + const int32_t *abuf[2], uint16_t *dest, int dstW, + int yalpha_param, int uvalpha_param, int y, + enum AVPixelFormat target, int hasAlpha, int eightbytes, + int is_be) +{ + unsigned yalpha = yalpha_param; + unsigned uvalpha = uvalpha_param; + const int32_t *buf0 = buf[0], *buf1 = buf[1], + *ubuf0 = ubuf[0], *ubuf1 = ubuf[1], + *vbuf0 = vbuf[0], *vbuf1 = vbuf[1], + *abuf0 = hasAlpha ? abuf[0] : NULL, + *abuf1 = hasAlpha ? abuf[1] : NULL; + unsigned yalpha1 = 4096 - yalpha; + unsigned uvalpha1 = 4096 - uvalpha; + int i; + int A = 0xffff<<14; + + av_assert2(yalpha <= 4096U); + av_assert2(uvalpha <= 4096U); + + for (i = 0; i < dstW; i++) { + unsigned Y = (int)(buf0[i] * yalpha1 + buf1[i] * yalpha) >> 14; + unsigned U = (int)(ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha - (128 << 23)) >> 14; + unsigned V = (int)(vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha - (128 << 23)) >> 14; + int R, G, B; + + Y -= c->yuv2rgb_y_offset; + Y *= c->yuv2rgb_y_coeff; + Y += (1 << 13) - (1 << 29); + + R = V * c->yuv2rgb_v2r_coeff; + G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff; + B = U * c->yuv2rgb_u2b_coeff; + + if (hasAlpha) { + A = (int)(abuf0[i] * yalpha1 + abuf1[i] * yalpha) >> 1; + + A += 1 << 13; + } + + output_pixel(&dest[0], av_clip_uintp2(((int)(R_B + Y) >> 14) + (1<<15), 16)); + output_pixel(&dest[1], av_clip_uintp2(((int)( G + Y) >> 14) + (1<<15), 16)); + output_pixel(&dest[2], av_clip_uintp2(((int)(B_R + Y) >> 14) + (1<<15), 16)); + if (eightbytes) { + output_pixel(&dest[3], av_clip_uintp2(A, 30) >> 14); + dest += 4; + } else { + dest += 3; + } + } +} + +static av_always_inline void +yuv2rgba64_full_1_c_template(SwsInternal *c, const int32_t *buf0, + const int32_t *ubuf[2], const int32_t *vbuf[2], + const int32_t *abuf0, uint16_t *dest, int dstW, + int uvalpha, int y, enum AVPixelFormat target, + int hasAlpha, int eightbytes, int is_be) +{ + const int32_t *ubuf0 = ubuf[0], *vbuf0 = vbuf[0]; + int i; + int A = 0xffff<<14; + + if (uvalpha == 0) { + for (i = 0; i < dstW; i++) { + SUINT Y = (buf0[i]) >> 2; + SUINT U = (ubuf0[i] - (128 << 11)) >> 2; + SUINT V = (vbuf0[i] - (128 << 11)) >> 2; + int R, G, B; + + Y -= c->yuv2rgb_y_offset; + Y *= c->yuv2rgb_y_coeff; + Y += (1 << 13) - (1 << 29); + + if (hasAlpha) { + A = abuf0[i] * (1 << 11); + + A += 1 << 13; + } + + R = V * c->yuv2rgb_v2r_coeff; + G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff; + B = U * c->yuv2rgb_u2b_coeff; + + output_pixel(&dest[0], av_clip_uintp2(((int)(R_B + Y) >> 14) + (1<<15), 16)); + output_pixel(&dest[1], av_clip_uintp2(((int)( G + Y) >> 14) + (1<<15), 16)); + output_pixel(&dest[2], av_clip_uintp2(((int)(B_R + Y) >> 14) + (1<<15), 16)); + if (eightbytes) { + output_pixel(&dest[3], av_clip_uintp2(A, 30) >> 14); + dest += 4; + } else { + dest += 3; + } + } + } else { + const int32_t *ubuf1 = ubuf[1], *vbuf1 = vbuf[1]; + unsigned uvalpha1 = 4096 - uvalpha; + int A = 0xffff<<14; + av_assert2(uvalpha <= 4096U); + + for (i = 0; i < dstW; i++) { + SUINT Y = (buf0[i] ) >> 2; + SUINT U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha - (128 << 23)) >> 14; + SUINT V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha - (128 << 23)) >> 14; + int R, G, B; + + Y -= c->yuv2rgb_y_offset; + Y *= c->yuv2rgb_y_coeff; + Y += (1 << 13) - (1 << 29); + + if (hasAlpha) { + A = abuf0[i] * (1 << 11); + + A += 1 << 13; + } + + R = V * c->yuv2rgb_v2r_coeff; + G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff; + B = U * c->yuv2rgb_u2b_coeff; + + output_pixel(&dest[0], av_clip_uintp2(((int)(R_B + Y) >> 14) + (1<<15), 16)); + output_pixel(&dest[1], av_clip_uintp2(((int)( G + Y) >> 14) + (1<<15), 16)); + output_pixel(&dest[2], av_clip_uintp2(((int)(B_R + Y) >> 14) + (1<<15), 16)); + if (eightbytes) { + output_pixel(&dest[3], av_clip_uintp2(A, 30) >> 14); + dest += 4; + } else { + dest += 3; + } + } + } +} + +#undef output_pixel +#undef r_b +#undef b_r + +#define YUV2PACKED16WRAPPER_EXT(name, base, ext, fmt, is_be, hasAlpha, eightbytes) \ +static void name ## ext ## _X_c(SwsInternal *c, const int16_t *lumFilter, \ + const int16_t **_lumSrc, int lumFilterSize, \ + const int16_t *chrFilter, const int16_t **_chrUSrc, \ + const int16_t **_chrVSrc, int chrFilterSize, \ + const int16_t **_alpSrc, uint8_t *_dest, int dstW, \ + int y) \ +{ \ + const int32_t **lumSrc = (const int32_t **) _lumSrc, \ + **chrUSrc = (const int32_t **) _chrUSrc, \ + **chrVSrc = (const int32_t **) _chrVSrc, \ + **alpSrc = (const int32_t **) _alpSrc; \ + uint16_t *dest = (uint16_t *) _dest; \ + name ## base ## _X_c_template(c, lumFilter, lumSrc, lumFilterSize, \ + chrFilter, chrUSrc, chrVSrc, chrFilterSize, \ + alpSrc, dest, dstW, y, fmt, hasAlpha, eightbytes, is_be); \ +} \ + \ +static void name ## ext ## _2_c(SwsInternal *c, const int16_t *_buf[2], \ + const int16_t *_ubuf[2], const int16_t *_vbuf[2], \ + const int16_t *_abuf[2], uint8_t *_dest, int dstW, \ + int yalpha, int uvalpha, int y) \ +{ \ + const int32_t **buf = (const int32_t **) _buf, \ + **ubuf = (const int32_t **) _ubuf, \ + **vbuf = (const int32_t **) _vbuf, \ + **abuf = (const int32_t **) _abuf; \ + uint16_t *dest = (uint16_t *) _dest; \ + name ## base ## _2_c_template(c, buf, ubuf, vbuf, abuf, \ + dest, dstW, yalpha, uvalpha, y, fmt, hasAlpha, eightbytes, is_be); \ +} \ + \ +static void name ## ext ## _1_c(SwsInternal *c, const int16_t *_buf0, \ + const int16_t *_ubuf[2], const int16_t *_vbuf[2], \ + const int16_t *_abuf0, uint8_t *_dest, int dstW, \ + int uvalpha, int y) \ +{ \ + const int32_t *buf0 = (const int32_t *) _buf0, \ + **ubuf = (const int32_t **) _ubuf, \ + **vbuf = (const int32_t **) _vbuf, \ + *abuf0 = (const int32_t *) _abuf0; \ + uint16_t *dest = (uint16_t *) _dest; \ + name ## base ## _1_c_template(c, buf0, ubuf, vbuf, abuf0, dest, \ + dstW, uvalpha, y, fmt, hasAlpha, eightbytes, is_be); \ +} +#define YUV2PACKED16WRAPPER(name, base, ext, base_fmt, endianness, hasAlpha, eightbytes) \ + YUV2PACKED16WRAPPER_EXT(name, base, ext, base_fmt ## endianness, IS_BE(endianness), hasAlpha, eightbytes) + +YUV2PACKED16WRAPPER(yuv2, rgba64, rgb48be, AV_PIX_FMT_RGB48, BE, 0, 0) +YUV2PACKED16WRAPPER(yuv2, rgba64, rgb48le, AV_PIX_FMT_RGB48, LE, 0, 0) +YUV2PACKED16WRAPPER(yuv2, rgba64, bgr48be, AV_PIX_FMT_BGR48, BE, 0, 0) +YUV2PACKED16WRAPPER(yuv2, rgba64, bgr48le, AV_PIX_FMT_BGR48, LE, 0, 0) +YUV2PACKED16WRAPPER(yuv2, rgba64, rgba64be, AV_PIX_FMT_RGBA64, BE, 1, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64, rgba64le, AV_PIX_FMT_RGBA64, LE, 1, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64, rgbx64be, AV_PIX_FMT_RGBA64, BE, 0, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64, rgbx64le, AV_PIX_FMT_RGBA64, LE, 0, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64, bgra64be, AV_PIX_FMT_BGRA64, BE, 1, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64, bgra64le, AV_PIX_FMT_BGRA64, LE, 1, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64, bgrx64be, AV_PIX_FMT_BGRA64, BE, 0, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64, bgrx64le, AV_PIX_FMT_BGRA64, LE, 0, 1) +YUV2PACKED16WRAPPER(yuv2, ya16, ya16be, AV_PIX_FMT_YA16, BE, 1, 0) +YUV2PACKED16WRAPPER(yuv2, ya16, ya16le, AV_PIX_FMT_YA16, LE, 1, 0) + +YUV2PACKED16WRAPPER(yuv2, rgba64_full, rgb48be_full, AV_PIX_FMT_RGB48, BE, 0, 0) +YUV2PACKED16WRAPPER(yuv2, rgba64_full, rgb48le_full, AV_PIX_FMT_RGB48, LE, 0, 0) +YUV2PACKED16WRAPPER(yuv2, rgba64_full, bgr48be_full, AV_PIX_FMT_BGR48, BE, 0, 0) +YUV2PACKED16WRAPPER(yuv2, rgba64_full, bgr48le_full, AV_PIX_FMT_BGR48, LE, 0, 0) +YUV2PACKED16WRAPPER(yuv2, rgba64_full, rgba64be_full, AV_PIX_FMT_RGBA64, BE, 1, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64_full, rgba64le_full, AV_PIX_FMT_RGBA64, LE, 1, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64_full, rgbx64be_full, AV_PIX_FMT_RGBA64, BE, 0, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64_full, rgbx64le_full, AV_PIX_FMT_RGBA64, LE, 0, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64_full, bgra64be_full, AV_PIX_FMT_BGRA64, BE, 1, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64_full, bgra64le_full, AV_PIX_FMT_BGRA64, LE, 1, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64_full, bgrx64be_full, AV_PIX_FMT_BGRA64, BE, 0, 1) +YUV2PACKED16WRAPPER(yuv2, rgba64_full, bgrx64le_full, AV_PIX_FMT_BGRA64, LE, 0, 1) + +/* + * Write out 2 RGB pixels in the target pixel format. This function takes a + * R/G/B LUT as generated by ff_yuv2rgb_c_init_tables(), which takes care of + * things like endianness conversion and shifting. The caller takes care of + * setting the correct offset in these tables from the chroma (U/V) values. + * This function then uses the luminance (Y1/Y2) values to write out the + * correct RGB values into the destination buffer. + */ +static av_always_inline void +yuv2rgb_write(uint8_t *_dest, int i, int Y1, int Y2, + unsigned A1, unsigned A2, + const void *_r, const void *_g, const void *_b, int y, + enum AVPixelFormat target, int hasAlpha) +{ + if (target == AV_PIX_FMT_ARGB || target == AV_PIX_FMT_RGBA || + target == AV_PIX_FMT_ABGR || target == AV_PIX_FMT_BGRA) { + uint32_t *dest = (uint32_t *) _dest; + const uint32_t *r = (const uint32_t *) _r; + const uint32_t *g = (const uint32_t *) _g; + const uint32_t *b = (const uint32_t *) _b; + +#if CONFIG_SMALL + int sh = hasAlpha ? ((target == AV_PIX_FMT_RGB32_1 || target == AV_PIX_FMT_BGR32_1) ? 0 : 24) : 0; + + dest[i * 2 + 0] = r[Y1] + g[Y1] + b[Y1] + (hasAlpha ? A1 << sh : 0); + dest[i * 2 + 1] = r[Y2] + g[Y2] + b[Y2] + (hasAlpha ? A2 << sh : 0); +#else + if (hasAlpha) { + int sh = (target == AV_PIX_FMT_RGB32_1 || target == AV_PIX_FMT_BGR32_1) ? 0 : 24; + + av_assert2((((r[Y1] + g[Y1] + b[Y1]) >> sh) & 0xFF) == 0); + dest[i * 2 + 0] = r[Y1] + g[Y1] + b[Y1] + (A1 << sh); + dest[i * 2 + 1] = r[Y2] + g[Y2] + b[Y2] + (A2 << sh); + } else { +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 + int sh = (target == AV_PIX_FMT_RGB32_1 || target == AV_PIX_FMT_BGR32_1) ? 0 : 24; + + av_assert2((((r[Y1] + g[Y1] + b[Y1]) >> sh) & 0xFF) == 0xFF); +#endif + dest[i * 2 + 0] = r[Y1] + g[Y1] + b[Y1]; + dest[i * 2 + 1] = r[Y2] + g[Y2] + b[Y2]; + } +#endif + } else if (target == AV_PIX_FMT_RGB24 || target == AV_PIX_FMT_BGR24) { + uint8_t *dest = (uint8_t *) _dest; + const uint8_t *r = (const uint8_t *) _r; + const uint8_t *g = (const uint8_t *) _g; + const uint8_t *b = (const uint8_t *) _b; + +#define r_b ((target == AV_PIX_FMT_RGB24) ? r : b) +#define b_r ((target == AV_PIX_FMT_RGB24) ? b : r) + + dest[i * 6 + 0] = r_b[Y1]; + dest[i * 6 + 1] = g[Y1]; + dest[i * 6 + 2] = b_r[Y1]; + dest[i * 6 + 3] = r_b[Y2]; + dest[i * 6 + 4] = g[Y2]; + dest[i * 6 + 5] = b_r[Y2]; +#undef r_b +#undef b_r + } else if (target == AV_PIX_FMT_RGB565 || target == AV_PIX_FMT_BGR565 || + target == AV_PIX_FMT_RGB555 || target == AV_PIX_FMT_BGR555 || + target == AV_PIX_FMT_RGB444 || target == AV_PIX_FMT_BGR444) { + uint16_t *dest = (uint16_t *) _dest; + const uint16_t *r = (const uint16_t *) _r; + const uint16_t *g = (const uint16_t *) _g; + const uint16_t *b = (const uint16_t *) _b; + int dr1, dg1, db1, dr2, dg2, db2; + + if (target == AV_PIX_FMT_RGB565 || target == AV_PIX_FMT_BGR565) { + dr1 = ff_dither_2x2_8[ y & 1 ][0]; + dg1 = ff_dither_2x2_4[ y & 1 ][0]; + db1 = ff_dither_2x2_8[(y & 1) ^ 1][0]; + dr2 = ff_dither_2x2_8[ y & 1 ][1]; + dg2 = ff_dither_2x2_4[ y & 1 ][1]; + db2 = ff_dither_2x2_8[(y & 1) ^ 1][1]; + } else if (target == AV_PIX_FMT_RGB555 || target == AV_PIX_FMT_BGR555) { + dr1 = ff_dither_2x2_8[ y & 1 ][0]; + dg1 = ff_dither_2x2_8[ y & 1 ][1]; + db1 = ff_dither_2x2_8[(y & 1) ^ 1][0]; + dr2 = ff_dither_2x2_8[ y & 1 ][1]; + dg2 = ff_dither_2x2_8[ y & 1 ][0]; + db2 = ff_dither_2x2_8[(y & 1) ^ 1][1]; + } else { + dr1 = ff_dither_4x4_16[ y & 3 ][0]; + dg1 = ff_dither_4x4_16[ y & 3 ][1]; + db1 = ff_dither_4x4_16[(y & 3) ^ 3][0]; + dr2 = ff_dither_4x4_16[ y & 3 ][1]; + dg2 = ff_dither_4x4_16[ y & 3 ][0]; + db2 = ff_dither_4x4_16[(y & 3) ^ 3][1]; + } + + dest[i * 2 + 0] = r[Y1 + dr1] + g[Y1 + dg1] + b[Y1 + db1]; + dest[i * 2 + 1] = r[Y2 + dr2] + g[Y2 + dg2] + b[Y2 + db2]; + } else if (target == AV_PIX_FMT_X2RGB10 || target == AV_PIX_FMT_X2BGR10) { + uint32_t *dest = (uint32_t *) _dest; + const uint32_t *r = (const uint32_t *) _r; + const uint32_t *g = (const uint32_t *) _g; + const uint32_t *b = (const uint32_t *) _b; + dest[i * 2 + 0] = r[Y1] + g[Y1] + b[Y1]; + dest[i * 2 + 1] = r[Y2] + g[Y2] + b[Y2]; + } else /* 8/4 bits */ { + uint8_t *dest = (uint8_t *) _dest; + const uint8_t *r = (const uint8_t *) _r; + const uint8_t *g = (const uint8_t *) _g; + const uint8_t *b = (const uint8_t *) _b; + int dr1, dg1, db1, dr2, dg2, db2; + + if (target == AV_PIX_FMT_RGB8 || target == AV_PIX_FMT_BGR8) { + const uint8_t * const d64 = ff_dither_8x8_73[y & 7]; + const uint8_t * const d32 = ff_dither_8x8_32[y & 7]; + dr1 = dg1 = d32[(i * 2 + 0) & 7]; + db1 = d64[(i * 2 + 0) & 7]; + dr2 = dg2 = d32[(i * 2 + 1) & 7]; + db2 = d64[(i * 2 + 1) & 7]; + } else { + const uint8_t * const d64 = ff_dither_8x8_73 [y & 7]; + const uint8_t * const d128 = ff_dither_8x8_220[y & 7]; + dr1 = db1 = d128[(i * 2 + 0) & 7]; + dg1 = d64[(i * 2 + 0) & 7]; + dr2 = db2 = d128[(i * 2 + 1) & 7]; + dg2 = d64[(i * 2 + 1) & 7]; + } + + if (target == AV_PIX_FMT_RGB4 || target == AV_PIX_FMT_BGR4) { + dest[i] = r[Y1 + dr1] + g[Y1 + dg1] + b[Y1 + db1] + + ((r[Y2 + dr2] + g[Y2 + dg2] + b[Y2 + db2]) << 4); + } else { + dest[i * 2 + 0] = r[Y1 + dr1] + g[Y1 + dg1] + b[Y1 + db1]; + dest[i * 2 + 1] = r[Y2 + dr2] + g[Y2 + dg2] + b[Y2 + db2]; + } + } +} + +static av_always_inline void +yuv2rgb_X_c_template(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t *dest, int dstW, + int y, enum AVPixelFormat target, int hasAlpha) +{ + int i; + + for (i = 0; i < ((dstW + 1) >> 1); i++) { + int j, A1, A2; + int Y1 = 1 << 18; + int Y2 = 1 << 18; + int U = 1 << 18; + int V = 1 << 18; + const void *r, *g, *b; + + for (j = 0; j < lumFilterSize; j++) { + Y1 += lumSrc[j][i * 2] * (unsigned)lumFilter[j]; + Y2 += lumSrc[j][i * 2 + 1] * (unsigned)lumFilter[j]; + } + for (j = 0; j < chrFilterSize; j++) { + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + Y1 >>= 19; + Y2 >>= 19; + U >>= 19; + V >>= 19; + if (hasAlpha) { + A1 = 1 << 18; + A2 = 1 << 18; + for (j = 0; j < lumFilterSize; j++) { + A1 += alpSrc[j][i * 2 ] * (unsigned)lumFilter[j]; + A2 += alpSrc[j][i * 2 + 1] * (unsigned)lumFilter[j]; + } + A1 >>= 19; + A2 >>= 19; + if ((A1 | A2) & 0x100) { + A1 = av_clip_uint8(A1); + A2 = av_clip_uint8(A2); + } + } + + r = c->table_rV[V + YUVRGB_TABLE_HEADROOM]; + g = (c->table_gU[U + YUVRGB_TABLE_HEADROOM] + c->table_gV[V + YUVRGB_TABLE_HEADROOM]); + b = c->table_bU[U + YUVRGB_TABLE_HEADROOM]; + + yuv2rgb_write(dest, i, Y1, Y2, hasAlpha ? A1 : 0, hasAlpha ? A2 : 0, + r, g, b, y, target, hasAlpha); + } +} + +static av_always_inline void +yuv2rgb_2_c_template(SwsInternal *c, const int16_t *buf[2], + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf[2], uint8_t *dest, int dstW, + int yalpha, int uvalpha, int y, + enum AVPixelFormat target, int hasAlpha) +{ + const int16_t *buf0 = buf[0], *buf1 = buf[1], + *ubuf0 = ubuf[0], *ubuf1 = ubuf[1], + *vbuf0 = vbuf[0], *vbuf1 = vbuf[1], + *abuf0 = hasAlpha ? abuf[0] : NULL, + *abuf1 = hasAlpha ? abuf[1] : NULL; + int yalpha1 = 4096 - yalpha; + int uvalpha1 = 4096 - uvalpha; + int i; + av_assert2(yalpha <= 4096U); + av_assert2(uvalpha <= 4096U); + + for (i = 0; i < ((dstW + 1) >> 1); i++) { + int Y1 = (buf0[i * 2] * yalpha1 + buf1[i * 2] * yalpha) >> 19; + int Y2 = (buf0[i * 2 + 1] * yalpha1 + buf1[i * 2 + 1] * yalpha) >> 19; + int U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha) >> 19; + int V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha) >> 19; + int A1, A2; + const void *r = c->table_rV[V + YUVRGB_TABLE_HEADROOM], + *g = (c->table_gU[U + YUVRGB_TABLE_HEADROOM] + c->table_gV[V + YUVRGB_TABLE_HEADROOM]), + *b = c->table_bU[U + YUVRGB_TABLE_HEADROOM]; + + if (hasAlpha) { + A1 = (abuf0[i * 2 ] * yalpha1 + abuf1[i * 2 ] * yalpha) >> 19; + A2 = (abuf0[i * 2 + 1] * yalpha1 + abuf1[i * 2 + 1] * yalpha) >> 19; + A1 = av_clip_uint8(A1); + A2 = av_clip_uint8(A2); + } + + yuv2rgb_write(dest, i, Y1, Y2, hasAlpha ? A1 : 0, hasAlpha ? A2 : 0, + r, g, b, y, target, hasAlpha); + } +} + +static av_always_inline void +yuv2rgb_1_c_template(SwsInternal *c, const int16_t *buf0, + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf0, uint8_t *dest, int dstW, + int uvalpha, int y, enum AVPixelFormat target, + int hasAlpha) +{ + const int16_t *ubuf0 = ubuf[0], *vbuf0 = vbuf[0]; + int i; + + if (uvalpha == 0) { + for (i = 0; i < ((dstW + 1) >> 1); i++) { + int Y1 = (buf0[i * 2 ] + 64) >> 7; + int Y2 = (buf0[i * 2 + 1] + 64) >> 7; + int U = (ubuf0[i] + 64) >> 7; + int V = (vbuf0[i] + 64) >> 7; + int A1, A2; + const void *r = c->table_rV[V + YUVRGB_TABLE_HEADROOM], + *g = (c->table_gU[U + YUVRGB_TABLE_HEADROOM] + c->table_gV[V + YUVRGB_TABLE_HEADROOM]), + *b = c->table_bU[U + YUVRGB_TABLE_HEADROOM]; + + if (hasAlpha) { + A1 = abuf0[i * 2 ] * 255 + 16384 >> 15; + A2 = abuf0[i * 2 + 1] * 255 + 16384 >> 15; + A1 = av_clip_uint8(A1); + A2 = av_clip_uint8(A2); + } + + yuv2rgb_write(dest, i, Y1, Y2, hasAlpha ? A1 : 0, hasAlpha ? A2 : 0, + r, g, b, y, target, hasAlpha); + } + } else { + const int16_t *ubuf1 = ubuf[1], *vbuf1 = vbuf[1]; + int uvalpha1 = 4096 - uvalpha; + av_assert2(uvalpha <= 4096U); + + for (i = 0; i < ((dstW + 1) >> 1); i++) { + int Y1 = (buf0[i * 2 ] + 64) >> 7; + int Y2 = (buf0[i * 2 + 1] + 64) >> 7; + int U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha + (128 << 11)) >> 19; + int V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha + (128 << 11)) >> 19; + int A1, A2; + const void *r = c->table_rV[V + YUVRGB_TABLE_HEADROOM], + *g = (c->table_gU[U + YUVRGB_TABLE_HEADROOM] + c->table_gV[V + YUVRGB_TABLE_HEADROOM]), + *b = c->table_bU[U + YUVRGB_TABLE_HEADROOM]; + + if (hasAlpha) { + A1 = (abuf0[i * 2 ] + 64) >> 7; + A2 = (abuf0[i * 2 + 1] + 64) >> 7; + A1 = av_clip_uint8(A1); + A2 = av_clip_uint8(A2); + } + + yuv2rgb_write(dest, i, Y1, Y2, hasAlpha ? A1 : 0, hasAlpha ? A2 : 0, + r, g, b, y, target, hasAlpha); + } + } +} + +#define YUV2RGBWRAPPERX(name, base, ext, fmt, hasAlpha) \ +static void name ## ext ## _X_c(SwsInternal *c, const int16_t *lumFilter, \ + const int16_t **lumSrc, int lumFilterSize, \ + const int16_t *chrFilter, const int16_t **chrUSrc, \ + const int16_t **chrVSrc, int chrFilterSize, \ + const int16_t **alpSrc, uint8_t *dest, int dstW, \ + int y) \ +{ \ + name ## base ## _X_c_template(c, lumFilter, lumSrc, lumFilterSize, \ + chrFilter, chrUSrc, chrVSrc, chrFilterSize, \ + alpSrc, dest, dstW, y, fmt, hasAlpha); \ +} + +#define YUV2RGBWRAPPERX2(name, base, ext, fmt, hasAlpha) \ +YUV2RGBWRAPPERX(name, base, ext, fmt, hasAlpha) \ +static void name ## ext ## _2_c(SwsInternal *c, const int16_t *buf[2], \ + const int16_t *ubuf[2], const int16_t *vbuf[2], \ + const int16_t *abuf[2], uint8_t *dest, int dstW, \ + int yalpha, int uvalpha, int y) \ +{ \ + name ## base ## _2_c_template(c, buf, ubuf, vbuf, abuf, \ + dest, dstW, yalpha, uvalpha, y, fmt, hasAlpha); \ +} + +#define YUV2RGBWRAPPER(name, base, ext, fmt, hasAlpha) \ +YUV2RGBWRAPPERX2(name, base, ext, fmt, hasAlpha) \ +static void name ## ext ## _1_c(SwsInternal *c, const int16_t *buf0, \ + const int16_t *ubuf[2], const int16_t *vbuf[2], \ + const int16_t *abuf0, uint8_t *dest, int dstW, \ + int uvalpha, int y) \ +{ \ + name ## base ## _1_c_template(c, buf0, ubuf, vbuf, abuf0, dest, \ + dstW, uvalpha, y, fmt, hasAlpha); \ +} + +#if CONFIG_SMALL +YUV2RGBWRAPPER(yuv2rgb,, 32_1, AV_PIX_FMT_RGB32_1, CONFIG_SWSCALE_ALPHA && c->needAlpha) +YUV2RGBWRAPPER(yuv2rgb,, 32, AV_PIX_FMT_RGB32, CONFIG_SWSCALE_ALPHA && c->needAlpha) +#else +#if CONFIG_SWSCALE_ALPHA +YUV2RGBWRAPPER(yuv2rgb,, a32_1, AV_PIX_FMT_RGB32_1, 1) +YUV2RGBWRAPPER(yuv2rgb,, a32, AV_PIX_FMT_RGB32, 1) +#endif +YUV2RGBWRAPPER(yuv2rgb,, x32_1, AV_PIX_FMT_RGB32_1, 0) +YUV2RGBWRAPPER(yuv2rgb,, x32, AV_PIX_FMT_RGB32, 0) +#endif +YUV2RGBWRAPPER(yuv2, rgb, rgb24, AV_PIX_FMT_RGB24, 0) +YUV2RGBWRAPPER(yuv2, rgb, bgr24, AV_PIX_FMT_BGR24, 0) +YUV2RGBWRAPPER(yuv2rgb,, 16, AV_PIX_FMT_RGB565, 0) +YUV2RGBWRAPPER(yuv2rgb,, 15, AV_PIX_FMT_RGB555, 0) +YUV2RGBWRAPPER(yuv2rgb,, 12, AV_PIX_FMT_RGB444, 0) +YUV2RGBWRAPPER(yuv2rgb,, 8, AV_PIX_FMT_RGB8, 0) +YUV2RGBWRAPPER(yuv2rgb,, 4, AV_PIX_FMT_RGB4, 0) +YUV2RGBWRAPPER(yuv2rgb,, 4b, AV_PIX_FMT_RGB4_BYTE, 0) +YUV2RGBWRAPPER(yuv2, rgb, x2rgb10, AV_PIX_FMT_X2RGB10, 0) +YUV2RGBWRAPPER(yuv2, rgb, x2bgr10, AV_PIX_FMT_X2BGR10, 0) + +static av_always_inline void yuv2rgb_write_full(SwsInternal *c, + uint8_t *dest, int i, int Y, int A, int U, int V, + int y, enum AVPixelFormat target, int hasAlpha, int err[4]) +{ + int R, G, B; + int isrgb8 = target == AV_PIX_FMT_BGR8 || target == AV_PIX_FMT_RGB8; + + Y -= c->yuv2rgb_y_offset; + Y *= c->yuv2rgb_y_coeff; + Y += 1 << 21; + R = (unsigned)Y + V*(unsigned)c->yuv2rgb_v2r_coeff; + G = (unsigned)Y + V*(unsigned)c->yuv2rgb_v2g_coeff + U*(unsigned)c->yuv2rgb_u2g_coeff; + B = (unsigned)Y + U*(unsigned)c->yuv2rgb_u2b_coeff; + if ((R | G | B) & 0xC0000000) { + R = av_clip_uintp2(R, 30); + G = av_clip_uintp2(G, 30); + B = av_clip_uintp2(B, 30); + } + + switch(target) { + case AV_PIX_FMT_ARGB: + dest[0] = hasAlpha ? A : 255; + dest[1] = R >> 22; + dest[2] = G >> 22; + dest[3] = B >> 22; + break; + case AV_PIX_FMT_RGB24: + dest[0] = R >> 22; + dest[1] = G >> 22; + dest[2] = B >> 22; + break; + case AV_PIX_FMT_RGBA: + dest[0] = R >> 22; + dest[1] = G >> 22; + dest[2] = B >> 22; + dest[3] = hasAlpha ? A : 255; + break; + case AV_PIX_FMT_ABGR: + dest[0] = hasAlpha ? A : 255; + dest[1] = B >> 22; + dest[2] = G >> 22; + dest[3] = R >> 22; + break; + case AV_PIX_FMT_BGR24: + dest[0] = B >> 22; + dest[1] = G >> 22; + dest[2] = R >> 22; + break; + case AV_PIX_FMT_BGRA: + dest[0] = B >> 22; + dest[1] = G >> 22; + dest[2] = R >> 22; + dest[3] = hasAlpha ? A : 255; + break; + case AV_PIX_FMT_X2RGB10LE: + R >>= 20; + G >>= 20; + B >>= 20; + AV_WL32(dest, (3U << 30) + (R << 20) + (G << 10) + B); + break; + case AV_PIX_FMT_X2BGR10LE: + R >>= 20; + G >>= 20; + B >>= 20; + AV_WL32(dest, (3U << 30) + (B << 20) + (G << 10) + R); + break; + case AV_PIX_FMT_BGR4_BYTE: + case AV_PIX_FMT_RGB4_BYTE: + case AV_PIX_FMT_BGR8: + case AV_PIX_FMT_RGB8: + { + int r,g,b; + + switch (c->opts.dither) { + case SWS_DITHER_NONE: + if (isrgb8) { + r = av_clip_uintp2(R >> 27, 3); + g = av_clip_uintp2(G >> 27, 3); + b = av_clip_uintp2(B >> 28, 2); + } else { + r = av_clip_uintp2(R >> 29, 1); + g = av_clip_uintp2(G >> 28, 2); + b = av_clip_uintp2(B >> 29, 1); + } + break; + default: + case SWS_DITHER_AUTO: + case SWS_DITHER_ED: + R >>= 22; + G >>= 22; + B >>= 22; + R += (7*err[0] + 1*c->dither_error[0][i] + 5*c->dither_error[0][i+1] + 3*c->dither_error[0][i+2])>>4; + G += (7*err[1] + 1*c->dither_error[1][i] + 5*c->dither_error[1][i+1] + 3*c->dither_error[1][i+2])>>4; + B += (7*err[2] + 1*c->dither_error[2][i] + 5*c->dither_error[2][i+1] + 3*c->dither_error[2][i+2])>>4; + c->dither_error[0][i] = err[0]; + c->dither_error[1][i] = err[1]; + c->dither_error[2][i] = err[2]; + r = R >> (isrgb8 ? 5 : 7); + g = G >> (isrgb8 ? 5 : 6); + b = B >> (isrgb8 ? 6 : 7); + r = av_clip(r, 0, isrgb8 ? 7 : 1); + g = av_clip(g, 0, isrgb8 ? 7 : 3); + b = av_clip(b, 0, isrgb8 ? 3 : 1); + err[0] = R - r*(isrgb8 ? 36 : 255); + err[1] = G - g*(isrgb8 ? 36 : 85); + err[2] = B - b*(isrgb8 ? 85 : 255); + break; + case SWS_DITHER_A_DITHER: + if (isrgb8) { + /* see http://pippin.gimp.org/a_dither/ for details/origin */ +#define A_DITHER(u,v) (((((u)+((v)*236))*119)&0xff)) + r = (((R >> 19) + A_DITHER(i,y) -96)>>8); + g = (((G >> 19) + A_DITHER(i + 17,y) - 96)>>8); + b = (((B >> 20) + A_DITHER(i + 17*2,y) -96)>>8); + r = av_clip_uintp2(r, 3); + g = av_clip_uintp2(g, 3); + b = av_clip_uintp2(b, 2); + } else { + r = (((R >> 21) + A_DITHER(i,y)-256)>>8); + g = (((G >> 19) + A_DITHER(i + 17,y)-256)>>8); + b = (((B >> 21) + A_DITHER(i + 17*2,y)-256)>>8); + r = av_clip_uintp2(r, 1); + g = av_clip_uintp2(g, 2); + b = av_clip_uintp2(b, 1); + } + break; + case SWS_DITHER_X_DITHER: + if (isrgb8) { + /* see http://pippin.gimp.org/a_dither/ for details/origin */ +#define X_DITHER(u,v) (((((u)^((v)*237))*181)&0x1ff)/2) + r = (((R >> 19) + X_DITHER(i,y) - 96)>>8); + g = (((G >> 19) + X_DITHER(i + 17,y) - 96)>>8); + b = (((B >> 20) + X_DITHER(i + 17*2,y) - 96)>>8); + r = av_clip_uintp2(r, 3); + g = av_clip_uintp2(g, 3); + b = av_clip_uintp2(b, 2); + } else { + r = (((R >> 21) + X_DITHER(i,y)-256)>>8); + g = (((G >> 19) + X_DITHER(i + 17,y)-256)>>8); + b = (((B >> 21) + X_DITHER(i + 17*2,y)-256)>>8); + r = av_clip_uintp2(r, 1); + g = av_clip_uintp2(g, 2); + b = av_clip_uintp2(b, 1); + } + + break; + } + + if(target == AV_PIX_FMT_BGR4_BYTE) { + dest[0] = r + 2*g + 8*b; + } else if(target == AV_PIX_FMT_RGB4_BYTE) { + dest[0] = b + 2*g + 8*r; + } else if(target == AV_PIX_FMT_BGR8) { + dest[0] = r + 8*g + 64*b; + } else if(target == AV_PIX_FMT_RGB8) { + dest[0] = b + 4*g + 32*r; + } else + av_assert2(0); + break;} + } +} + +static av_always_inline void +yuv2rgb_full_X_c_template(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t *dest, + int dstW, int y, enum AVPixelFormat target, int hasAlpha) +{ + int i; + int step = (target == AV_PIX_FMT_RGB24 || target == AV_PIX_FMT_BGR24) ? 3 : 4; + int err[4] = {0}; + int A = 0; //init to silence warning + + if( target == AV_PIX_FMT_BGR4_BYTE || target == AV_PIX_FMT_RGB4_BYTE + || target == AV_PIX_FMT_BGR8 || target == AV_PIX_FMT_RGB8) + step = 1; + + for (i = 0; i < dstW; i++) { + int j; + int Y = 1<<9; + int U = (1<<9)-(128 << 19); + int V = (1<<9)-(128 << 19); + + for (j = 0; j < lumFilterSize; j++) { + Y += lumSrc[j][i] * (unsigned)lumFilter[j]; + } + for (j = 0; j < chrFilterSize; j++) { + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + Y >>= 10; + U >>= 10; + V >>= 10; + if (hasAlpha) { + A = 1 << 18; + for (j = 0; j < lumFilterSize; j++) { + A += alpSrc[j][i] * (unsigned)lumFilter[j]; + } + A >>= 19; + if (A & 0x100) + A = av_clip_uint8(A); + } + yuv2rgb_write_full(c, dest, i, Y, A, U, V, y, target, hasAlpha, err); + dest += step; + } + c->dither_error[0][i] = err[0]; + c->dither_error[1][i] = err[1]; + c->dither_error[2][i] = err[2]; +} + +static av_always_inline void +yuv2rgb_full_2_c_template(SwsInternal *c, const int16_t *buf[2], + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf[2], uint8_t *dest, int dstW, + int yalpha, int uvalpha, int y, + enum AVPixelFormat target, int hasAlpha) +{ + const int16_t *buf0 = buf[0], *buf1 = buf[1], + *ubuf0 = ubuf[0], *ubuf1 = ubuf[1], + *vbuf0 = vbuf[0], *vbuf1 = vbuf[1], + *abuf0 = hasAlpha ? abuf[0] : NULL, + *abuf1 = hasAlpha ? abuf[1] : NULL; + int yalpha1 = 4096 - yalpha; + int uvalpha1 = 4096 - uvalpha; + int i; + int step = (target == AV_PIX_FMT_RGB24 || target == AV_PIX_FMT_BGR24) ? 3 : 4; + int err[4] = {0}; + int A = 0; // init to silcene warning + + av_assert2(yalpha <= 4096U); + av_assert2(uvalpha <= 4096U); + + if( target == AV_PIX_FMT_BGR4_BYTE || target == AV_PIX_FMT_RGB4_BYTE + || target == AV_PIX_FMT_BGR8 || target == AV_PIX_FMT_RGB8) + step = 1; + + for (i = 0; i < dstW; i++) { + int Y = ( buf0[i] * yalpha1 + buf1[i] * yalpha ) >> 10; //FIXME rounding + int U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha-(128 << 19)) >> 10; + int V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha-(128 << 19)) >> 10; + + if (hasAlpha) { + A = (abuf0[i] * yalpha1 + abuf1[i] * yalpha + (1<<18)) >> 19; + if (A & 0x100) + A = av_clip_uint8(A); + } + + yuv2rgb_write_full(c, dest, i, Y, A, U, V, y, target, hasAlpha, err); + dest += step; + } + c->dither_error[0][i] = err[0]; + c->dither_error[1][i] = err[1]; + c->dither_error[2][i] = err[2]; +} + +static av_always_inline void +yuv2rgb_full_1_c_template(SwsInternal *c, const int16_t *buf0, + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf0, uint8_t *dest, int dstW, + int uvalpha, int y, enum AVPixelFormat target, + int hasAlpha) +{ + const int16_t *ubuf0 = ubuf[0], *vbuf0 = vbuf[0]; + int i; + int step = (target == AV_PIX_FMT_RGB24 || target == AV_PIX_FMT_BGR24) ? 3 : 4; + int err[4] = {0}; + + if( target == AV_PIX_FMT_BGR4_BYTE || target == AV_PIX_FMT_RGB4_BYTE + || target == AV_PIX_FMT_BGR8 || target == AV_PIX_FMT_RGB8) + step = 1; + + if (uvalpha == 0) { + int A = 0; //init to silence warning + for (i = 0; i < dstW; i++) { + int Y = buf0[i] * 4; + int U = (ubuf0[i] - (128<<7)) * 4; + int V = (vbuf0[i] - (128<<7)) * 4; + + if (hasAlpha) { + A = (abuf0[i] + 64) >> 7; + if (A & 0x100) + A = av_clip_uint8(A); + } + + yuv2rgb_write_full(c, dest, i, Y, A, U, V, y, target, hasAlpha, err); + dest += step; + } + } else { + const int16_t *ubuf1 = ubuf[1], *vbuf1 = vbuf[1]; + int A = 0; //init to silence warning + int uvalpha1 = 4096 - uvalpha; + av_assert2(uvalpha <= 4096U); + + for (i = 0; i < dstW; i++) { + int Y = buf0[i] * 4; + int U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha - (128 << 19)) >> 10; + int V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha - (128 << 19)) >> 10; + + if (hasAlpha) { + A = (abuf0[i] + 64) >> 7; + if (A & 0x100) + A = av_clip_uint8(A); + } + + yuv2rgb_write_full(c, dest, i, Y, A, U, V, y, target, hasAlpha, err); + dest += step; + } + } + + c->dither_error[0][i] = err[0]; + c->dither_error[1][i] = err[1]; + c->dither_error[2][i] = err[2]; +} + +#if CONFIG_SMALL +YUV2RGBWRAPPER(yuv2, rgb_full, bgra32_full, AV_PIX_FMT_BGRA, CONFIG_SWSCALE_ALPHA && c->needAlpha) +YUV2RGBWRAPPER(yuv2, rgb_full, abgr32_full, AV_PIX_FMT_ABGR, CONFIG_SWSCALE_ALPHA && c->needAlpha) +YUV2RGBWRAPPER(yuv2, rgb_full, rgba32_full, AV_PIX_FMT_RGBA, CONFIG_SWSCALE_ALPHA && c->needAlpha) +YUV2RGBWRAPPER(yuv2, rgb_full, argb32_full, AV_PIX_FMT_ARGB, CONFIG_SWSCALE_ALPHA && c->needAlpha) +#else +#if CONFIG_SWSCALE_ALPHA +YUV2RGBWRAPPER(yuv2, rgb_full, bgra32_full, AV_PIX_FMT_BGRA, 1) +YUV2RGBWRAPPER(yuv2, rgb_full, abgr32_full, AV_PIX_FMT_ABGR, 1) +YUV2RGBWRAPPER(yuv2, rgb_full, rgba32_full, AV_PIX_FMT_RGBA, 1) +YUV2RGBWRAPPER(yuv2, rgb_full, argb32_full, AV_PIX_FMT_ARGB, 1) +#endif +YUV2RGBWRAPPER(yuv2, rgb_full, bgrx32_full, AV_PIX_FMT_BGRA, 0) +YUV2RGBWRAPPER(yuv2, rgb_full, xbgr32_full, AV_PIX_FMT_ABGR, 0) +YUV2RGBWRAPPER(yuv2, rgb_full, rgbx32_full, AV_PIX_FMT_RGBA, 0) +YUV2RGBWRAPPER(yuv2, rgb_full, xrgb32_full, AV_PIX_FMT_ARGB, 0) +#endif +YUV2RGBWRAPPER(yuv2, rgb_full, bgr24_full, AV_PIX_FMT_BGR24, 0) +YUV2RGBWRAPPER(yuv2, rgb_full, rgb24_full, AV_PIX_FMT_RGB24, 0) + +YUV2RGBWRAPPER(yuv2, rgb_full, bgr4_byte_full, AV_PIX_FMT_BGR4_BYTE, 0) +YUV2RGBWRAPPER(yuv2, rgb_full, rgb4_byte_full, AV_PIX_FMT_RGB4_BYTE, 0) +YUV2RGBWRAPPER(yuv2, rgb_full, bgr8_full, AV_PIX_FMT_BGR8, 0) +YUV2RGBWRAPPER(yuv2, rgb_full, rgb8_full, AV_PIX_FMT_RGB8, 0) + +YUV2RGBWRAPPER(yuv2, rgb_full, x2rgb10_full, AV_PIX_FMT_X2RGB10LE, 0) +YUV2RGBWRAPPER(yuv2, rgb_full, x2bgr10_full, AV_PIX_FMT_X2BGR10LE, 0) + +static void +yuv2gbrp_full_X_c(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t **dest, + int dstW, int y) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.dst_format); + int i; + int hasAlpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) && alpSrc; + uint16_t **dest16 = (uint16_t**)dest; + int SH = 22 + 8 - desc->comp[0].depth; + int A = 0; // init to silence warning + + for (i = 0; i < dstW; i++) { + int j; + int Y = 1 << 9; + int U = (1 << 9) - (128 << 19); + int V = (1 << 9) - (128 << 19); + int R, G, B; + + for (j = 0; j < lumFilterSize; j++) + Y += lumSrc[j][i] * (unsigned)lumFilter[j]; + + for (j = 0; j < chrFilterSize; j++) { + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + + Y >>= 10; + U >>= 10; + V >>= 10; + + if (hasAlpha) { + A = 1 << 18; + + for (j = 0; j < lumFilterSize; j++) + A += alpSrc[j][i] * (unsigned)lumFilter[j]; + + if (A & 0xF8000000) + A = av_clip_uintp2(A, 27); + } + + Y -= c->yuv2rgb_y_offset; + Y *= c->yuv2rgb_y_coeff; + Y += 1 << (SH-1); + R = Y + V * (unsigned)c->yuv2rgb_v2r_coeff; + G = Y + V * (unsigned)c->yuv2rgb_v2g_coeff + U * (unsigned)c->yuv2rgb_u2g_coeff; + B = Y + U * (unsigned)c->yuv2rgb_u2b_coeff; + + if ((R | G | B) & 0xC0000000) { + R = av_clip_uintp2(R, 30); + G = av_clip_uintp2(G, 30); + B = av_clip_uintp2(B, 30); + } + + if (SH != 22) { + dest16[0][i] = G >> SH; + dest16[1][i] = B >> SH; + dest16[2][i] = R >> SH; + if (hasAlpha) + dest16[3][i] = A >> (SH - 3); + } else { + dest[0][i] = G >> 22; + dest[1][i] = B >> 22; + dest[2][i] = R >> 22; + if (hasAlpha) + dest[3][i] = A >> 19; + } + } + if (SH != 22 && (!isBE(c->opts.dst_format)) != (!HAVE_BIGENDIAN)) { + for (i = 0; i < dstW; i++) { + dest16[0][i] = av_bswap16(dest16[0][i]); + dest16[1][i] = av_bswap16(dest16[1][i]); + dest16[2][i] = av_bswap16(dest16[2][i]); + if (hasAlpha) + dest16[3][i] = av_bswap16(dest16[3][i]); + } + } +} + +static void +yuv2gbrpmsb_full_X_c(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t **dest, + int dstW, int y) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.dst_format); + int hasAlpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) && alpSrc; + uint16_t **dest16 = (uint16_t**)dest; + int shift = 16 - desc->comp[0].depth; + int i; + + yuv2gbrp_full_X_c(c, lumFilter, lumSrc, lumFilterSize, + chrFilter, chrUSrc, chrVSrc, chrFilterSize, + alpSrc, dest, dstW, y); + + if (desc->comp[0].depth <= 8) + return; + + if ((!isBE(c->opts.dst_format)) != (!HAVE_BIGENDIAN)) { + for (i = 0; i < dstW; i++) { + dest16[0][i] = av_bswap16(av_bswap16(dest16[0][i]) << shift); + dest16[1][i] = av_bswap16(av_bswap16(dest16[1][i]) << shift); + dest16[2][i] = av_bswap16(av_bswap16(dest16[2][i]) << shift); + if (hasAlpha) + dest16[3][i] = av_bswap16(av_bswap16(dest16[3][i]) << shift); + } + } else { + for (i = 0; i < dstW; i++) { + dest16[0][i] = dest16[0][i] << shift; + dest16[1][i] = dest16[1][i] << shift; + dest16[2][i] = dest16[2][i] << shift; + if (hasAlpha) + dest16[3][i] = dest16[3][i] << shift; + } + } +} + +static void +yuv2gbrp16_full_X_c(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrcx, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrcx, + const int16_t **chrVSrcx, int chrFilterSize, + const int16_t **alpSrcx, uint8_t **dest, + int dstW, int y) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.dst_format); + int i; + int hasAlpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) && alpSrcx; + uint16_t **dest16 = (uint16_t**)dest; + const int32_t **lumSrc = (const int32_t**)lumSrcx; + const int32_t **chrUSrc = (const int32_t**)chrUSrcx; + const int32_t **chrVSrc = (const int32_t**)chrVSrcx; + const int32_t **alpSrc = (const int32_t**)alpSrcx; + + for (i = 0; i < dstW; i++) { + int j; + int Y = -0x40000000; + int U = -(128 << 23); + int V = -(128 << 23); + int R, G, B, A; + + for (j = 0; j < lumFilterSize; j++) + Y += lumSrc[j][i] * (unsigned)lumFilter[j]; + + for (j = 0; j < chrFilterSize; j++) { + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + + Y >>= 14; + Y += 0x10000; + U >>= 14; + V >>= 14; + + if (hasAlpha) { + A = -0x40000000; + + for (j = 0; j < lumFilterSize; j++) + A += alpSrc[j][i] * (unsigned)lumFilter[j]; + + A >>= 1; + A += 0x20002000; + } + + Y -= c->yuv2rgb_y_offset; + Y *= c->yuv2rgb_y_coeff; + Y += (1 << 13) - (1 << 29); + R = V * c->yuv2rgb_v2r_coeff; + G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff; + B = U * c->yuv2rgb_u2b_coeff; + + dest16[2][i] = av_clip_uintp2(((Y + (int64_t)R) >> 14) + (1<<15), 16); + dest16[0][i] = av_clip_uintp2(((Y + (int64_t)G) >> 14) + (1<<15), 16); + dest16[1][i] = av_clip_uintp2(((Y + (int64_t)B) >> 14) + (1<<15), 16); + + if (hasAlpha) + dest16[3][i] = av_clip_uintp2(A, 30) >> 14; + } + if ((!isBE(c->opts.dst_format)) != (!HAVE_BIGENDIAN)) { + for (i = 0; i < dstW; i++) { + dest16[0][i] = av_bswap16(dest16[0][i]); + dest16[1][i] = av_bswap16(dest16[1][i]); + dest16[2][i] = av_bswap16(dest16[2][i]); + if (hasAlpha) + dest16[3][i] = av_bswap16(dest16[3][i]); + } + } +} + +static void +yuv2gbrpf32_full_X_c(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrcx, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrcx, + const int16_t **chrVSrcx, int chrFilterSize, + const int16_t **alpSrcx, uint8_t **dest, + int dstW, int y) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.dst_format); + int i; + int hasAlpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA) && alpSrcx; + uint32_t **dest32 = (uint32_t**)dest; + const int32_t **lumSrc = (const int32_t**)lumSrcx; + const int32_t **chrUSrc = (const int32_t**)chrUSrcx; + const int32_t **chrVSrc = (const int32_t**)chrVSrcx; + const int32_t **alpSrc = (const int32_t**)alpSrcx; + static const float float_mult = 1.0f / 65535.0f; + + for (i = 0; i < dstW; i++) { + int j; + int Y = -0x40000000; + int U = -(128 << 23); + int V = -(128 << 23); + int R, G, B, A; + + for (j = 0; j < lumFilterSize; j++) + Y += lumSrc[j][i] * (unsigned)lumFilter[j]; + + for (j = 0; j < chrFilterSize; j++) { + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + + Y >>= 14; + Y += 0x10000; + U >>= 14; + V >>= 14; + + if (hasAlpha) { + A = -0x40000000; + + for (j = 0; j < lumFilterSize; j++) + A += alpSrc[j][i] * (unsigned)lumFilter[j]; + + A >>= 1; + A += 0x20002000; + } + + Y -= c->yuv2rgb_y_offset; + Y *= c->yuv2rgb_y_coeff; + Y += (1 << 13) - (1 << 29); + R = V * c->yuv2rgb_v2r_coeff; + G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff; + B = U * c->yuv2rgb_u2b_coeff; + + R = av_clip_uintp2(((Y + R) >> 14) + (1<<15), 16); + G = av_clip_uintp2(((Y + G) >> 14) + (1<<15), 16); + B = av_clip_uintp2(((Y + B) >> 14) + (1<<15), 16); + + dest32[0][i] = av_float2int(float_mult * (float)G); + dest32[1][i] = av_float2int(float_mult * (float)B); + dest32[2][i] = av_float2int(float_mult * (float)R); + if (hasAlpha) + dest32[3][i] = av_float2int(float_mult * (float)(av_clip_uintp2(A, 30) >> 14)); + } + if ((!isBE(c->opts.dst_format)) != (!HAVE_BIGENDIAN)) { + for (i = 0; i < dstW; i++) { + dest32[0][i] = av_bswap32(dest32[0][i]); + dest32[1][i] = av_bswap32(dest32[1][i]); + dest32[2][i] = av_bswap32(dest32[2][i]); + if (hasAlpha) + dest32[3][i] = av_bswap32(dest32[3][i]); + } + } +} + +static void +yuv2ya8_1_c(SwsInternal *c, const int16_t *buf0, + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf0, uint8_t *dest, int dstW, + int uvalpha, int y) +{ + int hasAlpha = !!abuf0; + int i; + + for (i = 0; i < dstW; i++) { + int Y = (buf0[i] + 64) >> 7; + int A; + + Y = av_clip_uint8(Y); + + if (hasAlpha) { + A = (abuf0[i] + 64) >> 7; + if (A & 0x100) + A = av_clip_uint8(A); + } + + dest[i * 2 ] = Y; + dest[i * 2 + 1] = hasAlpha ? A : 255; + } +} + +static void +yuv2ya8_2_c(SwsInternal *c, const int16_t *buf[2], + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf[2], uint8_t *dest, int dstW, + int yalpha, int uvalpha, int y) +{ + int hasAlpha = abuf && abuf[0] && abuf[1]; + const int16_t *buf0 = buf[0], *buf1 = buf[1], + *abuf0 = hasAlpha ? abuf[0] : NULL, + *abuf1 = hasAlpha ? abuf[1] : NULL; + int yalpha1 = 4096 - yalpha; + int i; + + av_assert2(yalpha <= 4096U); + + for (i = 0; i < dstW; i++) { + int Y = (buf0[i] * yalpha1 + buf1[i] * yalpha) >> 19; + int A; + + Y = av_clip_uint8(Y); + + if (hasAlpha) { + A = (abuf0[i] * yalpha1 + abuf1[i] * yalpha) >> 19; + A = av_clip_uint8(A); + } + + dest[i * 2 ] = Y; + dest[i * 2 + 1] = hasAlpha ? A : 255; + } +} + +static void +yuv2ya8_X_c(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t *dest, int dstW, int y) +{ + int hasAlpha = !!alpSrc; + int i; + + for (i = 0; i < dstW; i++) { + int j; + int Y = 1 << 18, A = 1 << 18; + + for (j = 0; j < lumFilterSize; j++) + Y += lumSrc[j][i] * (unsigned)lumFilter[j]; + + Y >>= 19; + if (Y & 0x100) + Y = av_clip_uint8(Y); + + if (hasAlpha) { + for (j = 0; j < lumFilterSize; j++) + A += alpSrc[j][i] * (unsigned)lumFilter[j]; + + A >>= 19; + + if (A & 0x100) + A = av_clip_uint8(A); + } + + dest[2 * i ] = Y; + dest[2 * i + 1] = hasAlpha ? A : 255; + } +} + +#define output_pixels(pos, val) \ + if (is_be) { \ + AV_WB16(pos, val); \ + } else { \ + AV_WL16(pos, val); \ + } + +static av_always_inline void +yuv2ayuv64_X_c(SwsInternal *c, const int16_t *lumFilter, + const int16_t **_lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **_chrUSrc, + const int16_t **_chrVSrc, int chrFilterSize, + const int16_t **_alpSrc, uint8_t *dest, int dstW, int y, + int A_offset, int Y_offset, int U_offset, int V_offset, int is_be) +{ + const int32_t **lumSrc = (const int32_t **) _lumSrc, + **chrUSrc = (const int32_t **) _chrUSrc, + **chrVSrc = (const int32_t **) _chrVSrc, + **alpSrc = (const int32_t **) _alpSrc; + int hasAlpha = !!alpSrc; + int i; + + for (i = 0; i < dstW; i++) { + int Y = 1 << 14, U = 1 << 14; + int V = 1 << 14, A = 1 << 14; + int j; + + Y -= 0x40000000; + U -= 0x40000000; + V -= 0x40000000; + A -= 0x40000000; + + for (j = 0; j < lumFilterSize; j++) + Y += lumSrc[j][i] * (unsigned)lumFilter[j]; + + for (j = 0; j < chrFilterSize; j++) + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + + for (j = 0; j < chrFilterSize; j++) + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + + if (hasAlpha) + for (j = 0; j < lumFilterSize; j++) + A += alpSrc[j][i] * (unsigned)lumFilter[j]; + + Y = 0x8000 + av_clip_int16(Y >> 15); + U = 0x8000 + av_clip_int16(U >> 15); + V = 0x8000 + av_clip_int16(V >> 15); + if (hasAlpha) + A = 0x8000 + av_clip_int16(A >> 15); + + output_pixels(dest + 8 * i + A_offset, hasAlpha ? A : 65535); + output_pixels(dest + 8 * i + Y_offset, Y); + output_pixels(dest + 8 * i + U_offset, U); + output_pixels(dest + 8 * i + V_offset, V); + } +} + +#define YUV2AYUV64(pixfmt, BE_LE, A, Y, U, V, is_be) \ +static void \ +yuv2 ## pixfmt ## BE_LE ##_X_c(SwsInternal *c, const int16_t *lumFilter, \ + const int16_t **lumSrc, int lumFilterSize, \ + const int16_t *chrFilter, const int16_t **chrUSrc, \ + const int16_t **chrVSrc, int chrFilterSize, \ + const int16_t **alpSrc, uint8_t *dest, int dstW, int y) \ +{ \ + yuv2ayuv64_X_c(c, lumFilter, lumSrc, lumFilterSize, \ + chrFilter, chrUSrc, chrVSrc, chrFilterSize, \ + alpSrc, dest, dstW, y, A, Y, U, V, is_be); \ +} + +YUV2AYUV64(ayuv64, le, 0, 2, 4, 6, 0) +YUV2AYUV64(ayuv64, be, 0, 2, 4, 6, 1) + +YUV2AYUV64(xv48, le, 6, 2, 0, 4, 0) +YUV2AYUV64(xv48, be, 6, 2, 0, 4, 1) + +#undef output_pixels + +static av_always_inline void +yuv2v30_X_c_template(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t *dest, int dstW, int y, + int shift) +{ + int i; + for (i = 0; i < dstW; i++) { + int Y = 1 << 16, U = 1 << 16, V = 1 << 16, A = 0x3; + int j; + + for (j = 0; j < lumFilterSize; j++) + Y += lumSrc[j][i] * (unsigned)lumFilter[j]; + + for (j = 0; j < chrFilterSize; j++) { + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + + Y = av_clip_uintp2(Y >> 17, 10); + U = av_clip_uintp2(U >> 17, 10); + V = av_clip_uintp2(V >> 17, 10); + + AV_WL32(dest + 4 * i, U << (shift + 0) | + Y << (shift + 10) | + (unsigned)V << (shift + 20) | + (unsigned)A << (shift ? 0 : 30 /* xv30le = 30, v30xle = 0 */)); + } +} + +#define V30LE_WRAPPER(name, shift) \ +static void yuv2 ## name ## _X_c(SwsInternal *c, const int16_t *lumFilter, \ + const int16_t **lumSrc, int lumFilterSize, \ + const int16_t *chrFilter, const int16_t **chrUSrc, \ + const int16_t **chrVSrc, int chrFilterSize, \ + const int16_t **alpSrc, uint8_t *dest, int dstW, \ + int y) \ +{ \ + yuv2v30_X_c_template(c, lumFilter, lumSrc, lumFilterSize, \ + chrFilter, chrUSrc, chrVSrc, chrFilterSize, \ + alpSrc, dest, dstW, y, shift); \ +} + +V30LE_WRAPPER(xv30le, 0) +V30LE_WRAPPER(v30xle, 2) + +#define output_pixels(pos, val, shift, bits, output_shift) \ + if (is_be) { \ + AV_WB16(pos, av_clip_uintp2(val >> shift, bits) << output_shift); \ + } else { \ + AV_WL16(pos, av_clip_uintp2(val >> shift, bits) << output_shift); \ + } + +static void +yuv2xv36_X_c(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t *dest, int dstW, int y, int is_be) +{ + int i; + for (i = 0; i < dstW; i++) { + int Y = 1 << 14, U = 1 << 14, V = 1 << 14, A = 65535; + int j; + + for (j = 0; j < lumFilterSize; j++) + Y += lumSrc[j][i] * (unsigned)lumFilter[j]; + + for (j = 0; j < chrFilterSize; j++) { + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + + output_pixels(dest + 8 * i + 2, Y, 15, 12, 4) + output_pixels(dest + 8 * i + 0, U, 15, 12, 4) + output_pixels(dest + 8 * i + 4, V, 15, 12, 4) + output_pixels(dest + 8 * i + 6, A, 0, 12, 4); + } +} + +#undef output_pixels + +#define YUV2XV36(BE_LE, is_be) \ +static void \ +yuv2xv36 ## BE_LE ##_X_c(SwsInternal *c, const int16_t *lumFilter, \ + const int16_t **lumSrc, int lumFilterSize, \ + const int16_t *chrFilter, const int16_t **chrUSrc, \ + const int16_t **chrVSrc, int chrFilterSize, \ + const int16_t **alpSrc, uint8_t *dest, int dstW, int y) \ +{ \ + yuv2xv36_X_c(c, lumFilter, lumSrc, lumFilterSize, \ + chrFilter, chrUSrc, chrVSrc, chrFilterSize, \ + alpSrc, dest, dstW, y, is_be); \ +} + +YUV2XV36(le, 0) +YUV2XV36(be, 1) + +#define output_pixels(pos, A, Y, U, V) \ + if (target == AV_PIX_FMT_AYUV) { \ + dest[pos + 0] = A; \ + dest[pos + 1] = Y; \ + dest[pos + 2] = U; \ + dest[pos + 3] = V; \ + } else if (target == AV_PIX_FMT_UYVA) { \ + dest[pos + 0] = U; \ + dest[pos + 1] = Y; \ + dest[pos + 2] = V; \ + dest[pos + 3] = A; \ + } else { /* AV_PIX_FMT_VUYA || AV_PIX_FMT_VUYX */ \ + dest[pos + 0] = V; \ + dest[pos + 1] = U; \ + dest[pos + 2] = Y; \ + dest[pos + 3] = A; \ + } + +static av_always_inline void +yuv2ayuv_1_c_template(SwsInternal *c, const int16_t *buf0, + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf0, uint8_t *dest, int dstW, + int uvalpha, int y, enum AVPixelFormat target) +{ + int hasAlpha = !!abuf0; + int i; + + if (uvalpha < 2048) { + for (i = 0; i < dstW; i++) { + int Y = (buf0[i] + 64) >> 7; + int U = (ubuf[0][i] + 64) >> 7; + int V = (vbuf[0][i] + 64) >> 7; + int A = 255; + + if (Y & 0x100) + Y = av_clip_uint8(Y); + if (U & 0x100) + U = av_clip_uint8(U); + if (V & 0x100) + V = av_clip_uint8(V); + + if (hasAlpha) { + A = (abuf0[i] + 64) >> 7; + if (A & 0x100) + A = av_clip_uint8(A); + } + + output_pixels(i * 4, A, Y, U, V) + } + } else { + for (i = 0; i < dstW; i++) { + int Y = (buf0[i] + 64) >> 7; + int U = (ubuf[0][i] + ubuf[1][i] + 128) >> 8; + int V = (vbuf[0][i] + vbuf[1][i] + 128) >> 8; + int A = 255; + + if (Y & 0x100) + Y = av_clip_uint8(Y); + if (U & 0x100) + U = av_clip_uint8(U); + if (V & 0x100) + V = av_clip_uint8(V); + + if (hasAlpha) { + A = (abuf0[i] + 64) >> 7; + if (A & 0x100) + A = av_clip_uint8(A); + } + + output_pixels(i * 4, A, Y, U, V) + } + } +} + +static av_always_inline void +yuv2ayuv_2_c_template(SwsInternal *c, const int16_t *buf[2], + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf[2], uint8_t *dest, int dstW, + int yalpha, int uvalpha, int y, + enum AVPixelFormat target) +{ + int hasAlpha = abuf && abuf[0] && abuf[1]; + const int16_t *buf0 = buf[0], *buf1 = buf[1], + *ubuf0 = ubuf[0], *ubuf1 = ubuf[1], + *vbuf0 = vbuf[0], *vbuf1 = vbuf[1], + *abuf0 = hasAlpha ? abuf[0] : NULL, + *abuf1 = hasAlpha ? abuf[1] : NULL; + int yalpha1 = 4096 - yalpha; + int uvalpha1 = 4096 - uvalpha; + int i; + + av_assert2(yalpha <= 4096U); + av_assert2(uvalpha <= 4096U); + + for (i = 0; i < dstW; i++) { + int Y = (buf0[i] * yalpha1 + buf1[i] * yalpha) >> 19; + int U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha) >> 19; + int V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha) >> 19; + int A = 255; + + if (Y & 0x100) + Y = av_clip_uint8(Y); + if (U & 0x100) + U = av_clip_uint8(U); + if (V & 0x100) + V = av_clip_uint8(V); + + if (hasAlpha) { + A = (abuf0[i] * yalpha1 + abuf1[i] * yalpha) >> 19; + A = av_clip_uint8(A); + } + + output_pixels(i * 4, A, Y, U, V) + } +} + +static av_always_inline void +yuv2ayuv_X_c_template(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t *dest, int dstW, + int y, enum AVPixelFormat target) +{ + int i; + + for (i = 0; i < dstW; i++) { + int j; + int Y = 1 << 18, U = 1 << 18; + int V = 1 << 18, A = 255; + + for (j = 0; j < lumFilterSize; j++) + Y += lumSrc[j][i] * (unsigned)lumFilter[j]; + + for (j = 0; j < chrFilterSize; j++) + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + + for (j = 0; j < chrFilterSize; j++) + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + + Y >>= 19; + U >>= 19; + V >>= 19; + + if (Y & 0x100) + Y = av_clip_uint8(Y); + if (U & 0x100) + U = av_clip_uint8(U); + if (V & 0x100) + V = av_clip_uint8(V); + + if (alpSrc) { + A = 1 << 18; + + for (j = 0; j < lumFilterSize; j++) + A += alpSrc[j][i] * (unsigned)lumFilter[j]; + + A >>= 19; + + if (A & 0x100) + A = av_clip_uint8(A); + } + + output_pixels(i * 4, A, Y, U, V) + } +} + +#undef output_pixels + +#define AYUVPACKEDWRAPPER(name, fmt) \ +static void yuv2 ## name ## _X_c(SwsInternal *c, const int16_t *lumFilter, \ + const int16_t **lumSrc, int lumFilterSize, \ + const int16_t *chrFilter, const int16_t **chrUSrc, \ + const int16_t **chrVSrc, int chrFilterSize, \ + const int16_t **alpSrc, uint8_t *dest, int dstW, \ + int y) \ +{ \ + yuv2ayuv_X_c_template(c, lumFilter, lumSrc, lumFilterSize, \ + chrFilter, chrUSrc, chrVSrc, chrFilterSize, \ + alpSrc, dest, dstW, y, fmt); \ +} \ + \ +static void yuv2 ## name ## _2_c(SwsInternal *c, const int16_t *buf[2], \ + const int16_t *ubuf[2], const int16_t *vbuf[2], \ + const int16_t *abuf[2], uint8_t *dest, int dstW, \ + int yalpha, int uvalpha, int y) \ +{ \ + yuv2ayuv_2_c_template(c, buf, ubuf, vbuf, abuf, \ + dest, dstW, yalpha, uvalpha, y, fmt); \ +} \ + \ +static void yuv2 ## name ## _1_c(SwsInternal *c, const int16_t *buf0, \ + const int16_t *ubuf[2], const int16_t *vbuf[2], \ + const int16_t *abuf0, uint8_t *dest, int dstW, \ + int uvalpha, int y) \ +{ \ + yuv2ayuv_1_c_template(c, buf0, ubuf, vbuf, \ + abuf0, dest, dstW, uvalpha, \ + y, fmt); \ +} + +AYUVPACKEDWRAPPER(vuyX, AV_PIX_FMT_VUYX) +AYUVPACKEDWRAPPER(ayuv, AV_PIX_FMT_AYUV) +AYUVPACKEDWRAPPER(uyva, AV_PIX_FMT_UYVA) + +#define output_pixel(pos, val, bits) \ + AV_WL16(pos, av_clip_uintp2(val >> shift, bits) << output_shift); + +#define yuv2y2xx_wrapper(bits) \ + static void \ + yuv2y2 ## bits ## le_X_c(SwsInternal *c, const int16_t *lumFilter, \ + const int16_t **lumSrc, int lumFilterSize, \ + const int16_t *chrFilter, \ + const int16_t **chrUSrc, \ + const int16_t **chrVSrc, int chrFilterSize, \ + const int16_t **alpSrc, \ + uint8_t *dest, int dstW, int y) \ + { \ + int i, j; \ + int shift = 11 + 16 - bits; \ + int output_shift = 16 - bits; \ + for (i = 0; i < ((dstW + 1) >> 1); i++) { \ + int Y1 = 1 << (shift - 1), Y2 = 1 << (shift - 1); \ + int U = 1 << (shift - 1), V = 1 << (shift - 1); \ + \ + for (j = 0; j < lumFilterSize; j++) { \ + Y1 += lumSrc[j][i * 2] * (unsigned)lumFilter[j]; \ + Y2 += lumSrc[j][i * 2 + 1] * (unsigned)lumFilter[j]; \ + } \ + \ + for (j = 0; j < chrFilterSize; j++) { \ + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; \ + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; \ + } \ + \ + output_pixel(dest + 8 * i + 0, Y1, bits); \ + output_pixel(dest + 8 * i + 2, U, bits); \ + output_pixel(dest + 8 * i + 4, Y2, bits); \ + output_pixel(dest + 8 * i + 6, V, bits); \ + } \ + } + +yuv2y2xx_wrapper(10) +yuv2y2xx_wrapper(12) + +static void +yuv2y216le_X_c(SwsInternal *c, const int16_t *lumFilter, + const int16_t **_lumSrc, int lumFilterSize, + const int16_t *chrFilter, + const int16_t **_chrUSrc, + const int16_t **_chrVSrc, int chrFilterSize, + const int16_t **_alpSrc, + uint8_t *dest, int dstW, int y) +{ + const int32_t **lumSrc = (const int32_t **)_lumSrc; + const int32_t **chrUSrc = (const int32_t **)_chrUSrc; + const int32_t **chrVSrc = (const int32_t **)_chrVSrc; + int shift = 15; + + for (int i = 0; i < ((dstW + 1) >> 1); i++) { + int Y1 = 1 << (shift - 1), Y2 = 1 << (shift - 1); + int U = 1 << (shift - 1), V = 1 << (shift - 1); + + /* See yuv2planeX_16_c_template for details. */ + Y1 -= 0x40000000; + U -= 0x40000000; + Y2 -= 0x40000000; + V -= 0x40000000; + + for (int j = 0; j < lumFilterSize; j++) { + Y1 += lumSrc[j][i * 2] * (unsigned)lumFilter[j]; + Y2 += lumSrc[j][i * 2 + 1] * (unsigned)lumFilter[j]; + } + + for (int j = 0; j < chrFilterSize; j++) { + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + } + + AV_WL16(dest + 8 * i + 0, 0x8000 + av_clip_int16(Y1 >> shift)); + AV_WL16(dest + 8 * i + 2, 0x8000 + av_clip_int16(U >> shift)); + AV_WL16(dest + 8 * i + 4, 0x8000 + av_clip_int16(Y2 >> shift)); + AV_WL16(dest + 8 * i + 6, 0x8000 + av_clip_int16(V >> shift)); + } +} + +static void +yuv2vyu444_1_c(SwsInternal *c, const int16_t *buf0, + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf0, uint8_t *dest, int dstW, + int uvalpha, int y) +{ + int i; + + if (uvalpha < 2048) { + for (i = 0; i < dstW; i++) { + int Y = (buf0[i] + 64) >> 7; + int U = (ubuf[0][i] + 64) >> 7; + int V = (vbuf[0][i] + 64) >> 7; + + if (Y & 0x100) + Y = av_clip_uint8(Y); + if (U & 0x100) + U = av_clip_uint8(U); + if (V & 0x100) + V = av_clip_uint8(V); + + dest[3 * i ] = V; + dest[3 * i + 1] = Y; + dest[3 * i + 2] = U; + } + } else { + for (i = 0; i < dstW; i++) { + int Y = (buf0[i] + 64) >> 7; + int U = (ubuf[0][i] + ubuf[1][i] + 128) >> 8; + int V = (vbuf[0][i] + vbuf[1][i] + 128) >> 8; + + if (Y & 0x100) + Y = av_clip_uint8(Y); + if (U & 0x100) + U = av_clip_uint8(U); + if (V & 0x100) + V = av_clip_uint8(V); + + dest[3 * i ] = V; + dest[3 * i + 1] = Y; + dest[3 * i + 2] = U; + } + } +} + +static void +yuv2vyu444_2_c(SwsInternal *c, const int16_t *buf[2], + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf[2], uint8_t *dest, int dstW, + int yalpha, int uvalpha, int y) +{ + const int16_t *buf0 = buf[0], *buf1 = buf[1], + *ubuf0 = ubuf[0], *ubuf1 = ubuf[1], + *vbuf0 = vbuf[0], *vbuf1 = vbuf[1]; + int yalpha1 = 4096 - yalpha; + int uvalpha1 = 4096 - uvalpha; + int i; + + av_assert2(yalpha <= 4096U); + av_assert2(uvalpha <= 4096U); + + for (i = 0; i < dstW; i++) { + int Y = (buf0[i] * yalpha1 + buf1[i] * yalpha) >> 19; + int U = (ubuf0[i] * uvalpha1 + ubuf1[i] * uvalpha) >> 19; + int V = (vbuf0[i] * uvalpha1 + vbuf1[i] * uvalpha) >> 19; + + if (Y & 0x100) + Y = av_clip_uint8(Y); + if (U & 0x100) + U = av_clip_uint8(U); + if (V & 0x100) + V = av_clip_uint8(V); + + dest[3 * i ] = V; + dest[3 * i + 1] = Y; + dest[3 * i + 2] = U; + } +} + +static void +yuv2vyu444_X_c(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t *dest, int dstW, int y) +{ + int i; + + for (i = 0; i < dstW; i++) { + int j; + int Y = 1 << 18, U = 1 << 18; + int V = 1 << 18; + + for (j = 0; j < lumFilterSize; j++) + Y += lumSrc[j][i] * (unsigned)lumFilter[j]; + + for (j = 0; j < chrFilterSize; j++) + U += chrUSrc[j][i] * (unsigned)chrFilter[j]; + + for (j = 0; j < chrFilterSize; j++) + V += chrVSrc[j][i] * (unsigned)chrFilter[j]; + + Y >>= 19; + U >>= 19; + V >>= 19; + + if (Y & 0x100) + Y = av_clip_uint8(Y); + if (U & 0x100) + U = av_clip_uint8(U); + if (V & 0x100) + V = av_clip_uint8(V); + + dest[3 * i ] = V; + dest[3 * i + 1] = Y; + dest[3 * i + 2] = U; + } +} + +#undef output_pixel + +av_cold void ff_sws_init_output_funcs(SwsInternal *c, + yuv2planar1_fn *yuv2plane1, + yuv2planarX_fn *yuv2planeX, + yuv2interleavedX_fn *yuv2nv12cX, + yuv2packed1_fn *yuv2packed1, + yuv2packed2_fn *yuv2packed2, + yuv2packedX_fn *yuv2packedX, + yuv2anyX_fn *yuv2anyX) +{ + enum AVPixelFormat dstFormat = c->opts.dst_format; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(dstFormat); + + if (isSemiPlanarYUV(dstFormat) && isDataInHighBits(dstFormat)) { + if (desc->comp[0].depth == 10) { + *yuv2plane1 = isBE(dstFormat) ? yuv2p010l1_BE_c : yuv2p010l1_LE_c; + *yuv2planeX = isBE(dstFormat) ? yuv2p010lX_BE_c : yuv2p010lX_LE_c; + *yuv2nv12cX = isBE(dstFormat) ? yuv2p010cX_BE_c : yuv2p010cX_LE_c; + } else if (desc->comp[0].depth == 12) { + *yuv2plane1 = isBE(dstFormat) ? yuv2p012l1_BE_c : yuv2p012l1_LE_c; + *yuv2planeX = isBE(dstFormat) ? yuv2p012lX_BE_c : yuv2p012lX_LE_c; + *yuv2nv12cX = isBE(dstFormat) ? yuv2p012cX_BE_c : yuv2p012cX_LE_c; + } else + av_assert0(0); + } else if (isSemiPlanarYUV(dstFormat) && isNBPS(dstFormat)) { + if (desc->comp[0].depth == 10) { + *yuv2plane1 = isBE(dstFormat) ? yuv2nv20l1_BE_c : yuv2nv20l1_LE_c; + *yuv2planeX = isBE(dstFormat) ? yuv2nv20lX_BE_c : yuv2nv20lX_LE_c; + *yuv2nv12cX = isBE(dstFormat) ? yuv2nv20cX_BE_c : yuv2nv20cX_LE_c; + } else + av_assert0(0); + } else if (is16BPS(dstFormat)) { + *yuv2planeX = isBE(dstFormat) ? yuv2planeX_16BE_c : yuv2planeX_16LE_c; + *yuv2plane1 = isBE(dstFormat) ? yuv2plane1_16BE_c : yuv2plane1_16LE_c; + if (isSemiPlanarYUV(dstFormat)) { + *yuv2nv12cX = isBE(dstFormat) ? yuv2nv12cX_16BE_c : yuv2nv12cX_16LE_c; + } + } else if (isDataInHighBits(dstFormat) && isNBPS(dstFormat)) { + if (desc->comp[0].depth == 10) { + *yuv2planeX = isBE(dstFormat) ? yuv2msbplaneX_10BE_c : yuv2msbplaneX_10LE_c; + *yuv2plane1 = isBE(dstFormat) ? yuv2msbplane1_10BE_c : yuv2msbplane1_10LE_c; + } else if (desc->comp[0].depth == 12) { + *yuv2planeX = isBE(dstFormat) ? yuv2msbplaneX_12BE_c : yuv2msbplaneX_12LE_c; + *yuv2plane1 = isBE(dstFormat) ? yuv2msbplane1_12BE_c : yuv2msbplane1_12LE_c; + } else + av_assert0(0); + } else if (isNBPS(dstFormat)) { + if (desc->comp[0].depth == 9) { + *yuv2planeX = isBE(dstFormat) ? yuv2planeX_9BE_c : yuv2planeX_9LE_c; + *yuv2plane1 = isBE(dstFormat) ? yuv2plane1_9BE_c : yuv2plane1_9LE_c; + } else if (desc->comp[0].depth == 10) { + *yuv2planeX = isBE(dstFormat) ? yuv2planeX_10BE_c : yuv2planeX_10LE_c; + *yuv2plane1 = isBE(dstFormat) ? yuv2plane1_10BE_c : yuv2plane1_10LE_c; + } else if (desc->comp[0].depth == 12) { + *yuv2planeX = isBE(dstFormat) ? yuv2planeX_12BE_c : yuv2planeX_12LE_c; + *yuv2plane1 = isBE(dstFormat) ? yuv2plane1_12BE_c : yuv2plane1_12LE_c; + } else if (desc->comp[0].depth == 14) { + *yuv2planeX = isBE(dstFormat) ? yuv2planeX_14BE_c : yuv2planeX_14LE_c; + *yuv2plane1 = isBE(dstFormat) ? yuv2plane1_14BE_c : yuv2plane1_14LE_c; + } else + av_assert0(0); + } else if (dstFormat == AV_PIX_FMT_GRAYF32BE) { + *yuv2planeX = yuv2planeX_floatBE_c; + *yuv2plane1 = yuv2plane1_floatBE_c; + } else if (dstFormat == AV_PIX_FMT_GRAYF32LE) { + *yuv2planeX = yuv2planeX_floatLE_c; + *yuv2plane1 = yuv2plane1_floatLE_c; + } else { + *yuv2plane1 = yuv2plane1_8_c; + *yuv2planeX = yuv2planeX_8_c; + if (isSemiPlanarYUV(dstFormat)) + *yuv2nv12cX = yuv2nv12cX_c; + } + + if(c->opts.flags & SWS_FULL_CHR_H_INT) { + switch (dstFormat) { + case AV_PIX_FMT_RGBA: +#if CONFIG_SMALL + *yuv2packedX = yuv2rgba32_full_X_c; + *yuv2packed2 = yuv2rgba32_full_2_c; + *yuv2packed1 = yuv2rgba32_full_1_c; +#else +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packedX = yuv2rgba32_full_X_c; + *yuv2packed2 = yuv2rgba32_full_2_c; + *yuv2packed1 = yuv2rgba32_full_1_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packedX = yuv2rgbx32_full_X_c; + *yuv2packed2 = yuv2rgbx32_full_2_c; + *yuv2packed1 = yuv2rgbx32_full_1_c; + } +#endif /* !CONFIG_SMALL */ + break; + case AV_PIX_FMT_ARGB: +#if CONFIG_SMALL + *yuv2packedX = yuv2argb32_full_X_c; + *yuv2packed2 = yuv2argb32_full_2_c; + *yuv2packed1 = yuv2argb32_full_1_c; +#else +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packedX = yuv2argb32_full_X_c; + *yuv2packed2 = yuv2argb32_full_2_c; + *yuv2packed1 = yuv2argb32_full_1_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packedX = yuv2xrgb32_full_X_c; + *yuv2packed2 = yuv2xrgb32_full_2_c; + *yuv2packed1 = yuv2xrgb32_full_1_c; + } +#endif /* !CONFIG_SMALL */ + break; + case AV_PIX_FMT_BGRA: +#if CONFIG_SMALL + *yuv2packedX = yuv2bgra32_full_X_c; + *yuv2packed2 = yuv2bgra32_full_2_c; + *yuv2packed1 = yuv2bgra32_full_1_c; +#else +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packedX = yuv2bgra32_full_X_c; + *yuv2packed2 = yuv2bgra32_full_2_c; + *yuv2packed1 = yuv2bgra32_full_1_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packedX = yuv2bgrx32_full_X_c; + *yuv2packed2 = yuv2bgrx32_full_2_c; + *yuv2packed1 = yuv2bgrx32_full_1_c; + } +#endif /* !CONFIG_SMALL */ + break; + case AV_PIX_FMT_ABGR: +#if CONFIG_SMALL + *yuv2packedX = yuv2abgr32_full_X_c; + *yuv2packed2 = yuv2abgr32_full_2_c; + *yuv2packed1 = yuv2abgr32_full_1_c; +#else +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packedX = yuv2abgr32_full_X_c; + *yuv2packed2 = yuv2abgr32_full_2_c; + *yuv2packed1 = yuv2abgr32_full_1_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packedX = yuv2xbgr32_full_X_c; + *yuv2packed2 = yuv2xbgr32_full_2_c; + *yuv2packed1 = yuv2xbgr32_full_1_c; + } +#endif /* !CONFIG_SMALL */ + break; + case AV_PIX_FMT_RGBA64LE: +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packedX = yuv2rgba64le_full_X_c; + *yuv2packed2 = yuv2rgba64le_full_2_c; + *yuv2packed1 = yuv2rgba64le_full_1_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packedX = yuv2rgbx64le_full_X_c; + *yuv2packed2 = yuv2rgbx64le_full_2_c; + *yuv2packed1 = yuv2rgbx64le_full_1_c; + } + break; + case AV_PIX_FMT_RGBA64BE: +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packedX = yuv2rgba64be_full_X_c; + *yuv2packed2 = yuv2rgba64be_full_2_c; + *yuv2packed1 = yuv2rgba64be_full_1_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packedX = yuv2rgbx64be_full_X_c; + *yuv2packed2 = yuv2rgbx64be_full_2_c; + *yuv2packed1 = yuv2rgbx64be_full_1_c; + } + break; + case AV_PIX_FMT_BGRA64LE: +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packedX = yuv2bgra64le_full_X_c; + *yuv2packed2 = yuv2bgra64le_full_2_c; + *yuv2packed1 = yuv2bgra64le_full_1_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packedX = yuv2bgrx64le_full_X_c; + *yuv2packed2 = yuv2bgrx64le_full_2_c; + *yuv2packed1 = yuv2bgrx64le_full_1_c; + } + break; + case AV_PIX_FMT_BGRA64BE: +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packedX = yuv2bgra64be_full_X_c; + *yuv2packed2 = yuv2bgra64be_full_2_c; + *yuv2packed1 = yuv2bgra64be_full_1_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packedX = yuv2bgrx64be_full_X_c; + *yuv2packed2 = yuv2bgrx64be_full_2_c; + *yuv2packed1 = yuv2bgrx64be_full_1_c; + } + break; + + case AV_PIX_FMT_RGB24: + *yuv2packedX = yuv2rgb24_full_X_c; + *yuv2packed2 = yuv2rgb24_full_2_c; + *yuv2packed1 = yuv2rgb24_full_1_c; + break; + case AV_PIX_FMT_BGR24: + *yuv2packedX = yuv2bgr24_full_X_c; + *yuv2packed2 = yuv2bgr24_full_2_c; + *yuv2packed1 = yuv2bgr24_full_1_c; + break; + case AV_PIX_FMT_RGB48LE: + *yuv2packedX = yuv2rgb48le_full_X_c; + *yuv2packed2 = yuv2rgb48le_full_2_c; + *yuv2packed1 = yuv2rgb48le_full_1_c; + break; + case AV_PIX_FMT_BGR48LE: + *yuv2packedX = yuv2bgr48le_full_X_c; + *yuv2packed2 = yuv2bgr48le_full_2_c; + *yuv2packed1 = yuv2bgr48le_full_1_c; + break; + case AV_PIX_FMT_RGB48BE: + *yuv2packedX = yuv2rgb48be_full_X_c; + *yuv2packed2 = yuv2rgb48be_full_2_c; + *yuv2packed1 = yuv2rgb48be_full_1_c; + break; + case AV_PIX_FMT_BGR48BE: + *yuv2packedX = yuv2bgr48be_full_X_c; + *yuv2packed2 = yuv2bgr48be_full_2_c; + *yuv2packed1 = yuv2bgr48be_full_1_c; + break; + case AV_PIX_FMT_BGR4_BYTE: + *yuv2packedX = yuv2bgr4_byte_full_X_c; + *yuv2packed2 = yuv2bgr4_byte_full_2_c; + *yuv2packed1 = yuv2bgr4_byte_full_1_c; + break; + case AV_PIX_FMT_RGB4_BYTE: + *yuv2packedX = yuv2rgb4_byte_full_X_c; + *yuv2packed2 = yuv2rgb4_byte_full_2_c; + *yuv2packed1 = yuv2rgb4_byte_full_1_c; + break; + case AV_PIX_FMT_BGR8: + *yuv2packedX = yuv2bgr8_full_X_c; + *yuv2packed2 = yuv2bgr8_full_2_c; + *yuv2packed1 = yuv2bgr8_full_1_c; + break; + case AV_PIX_FMT_RGB8: + *yuv2packedX = yuv2rgb8_full_X_c; + *yuv2packed2 = yuv2rgb8_full_2_c; + *yuv2packed1 = yuv2rgb8_full_1_c; + break; + case AV_PIX_FMT_X2RGB10LE: + *yuv2packedX = yuv2x2rgb10_full_X_c; + *yuv2packed2 = yuv2x2rgb10_full_2_c; + *yuv2packed1 = yuv2x2rgb10_full_1_c; + break; + case AV_PIX_FMT_X2BGR10LE: + *yuv2packedX = yuv2x2bgr10_full_X_c; + *yuv2packed2 = yuv2x2bgr10_full_2_c; + *yuv2packed1 = yuv2x2bgr10_full_1_c; + break; + case AV_PIX_FMT_GBRP: + case AV_PIX_FMT_GBRP9BE: + case AV_PIX_FMT_GBRP9LE: + case AV_PIX_FMT_GBRP10BE: + case AV_PIX_FMT_GBRP10LE: + case AV_PIX_FMT_GBRP12BE: + case AV_PIX_FMT_GBRP12LE: + case AV_PIX_FMT_GBRP14BE: + case AV_PIX_FMT_GBRP14LE: + case AV_PIX_FMT_GBRAP: + case AV_PIX_FMT_GBRAP10BE: + case AV_PIX_FMT_GBRAP10LE: + case AV_PIX_FMT_GBRAP12BE: + case AV_PIX_FMT_GBRAP12LE: + case AV_PIX_FMT_GBRAP14BE: + case AV_PIX_FMT_GBRAP14LE: + *yuv2anyX = yuv2gbrp_full_X_c; + break; + case AV_PIX_FMT_GBRP10MSBBE: + case AV_PIX_FMT_GBRP10MSBLE: + case AV_PIX_FMT_GBRP12MSBBE: + case AV_PIX_FMT_GBRP12MSBLE: + *yuv2anyX = yuv2gbrpmsb_full_X_c; + break; + case AV_PIX_FMT_GBRP16BE: + case AV_PIX_FMT_GBRP16LE: + case AV_PIX_FMT_GBRAP16BE: + case AV_PIX_FMT_GBRAP16LE: + *yuv2anyX = yuv2gbrp16_full_X_c; + break; + case AV_PIX_FMT_GBRPF32BE: + case AV_PIX_FMT_GBRPF32LE: + case AV_PIX_FMT_GBRAPF32BE: + case AV_PIX_FMT_GBRAPF32LE: + *yuv2anyX = yuv2gbrpf32_full_X_c; + break; + } + if (!*yuv2packedX && !*yuv2anyX) + goto YUV_PACKED; + } else { + YUV_PACKED: + switch (dstFormat) { + case AV_PIX_FMT_RGBA64LE: +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packed1 = yuv2rgba64le_1_c; + *yuv2packed2 = yuv2rgba64le_2_c; + *yuv2packedX = yuv2rgba64le_X_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packed1 = yuv2rgbx64le_1_c; + *yuv2packed2 = yuv2rgbx64le_2_c; + *yuv2packedX = yuv2rgbx64le_X_c; + } + break; + case AV_PIX_FMT_RGBA64BE: +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packed1 = yuv2rgba64be_1_c; + *yuv2packed2 = yuv2rgba64be_2_c; + *yuv2packedX = yuv2rgba64be_X_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packed1 = yuv2rgbx64be_1_c; + *yuv2packed2 = yuv2rgbx64be_2_c; + *yuv2packedX = yuv2rgbx64be_X_c; + } + break; + case AV_PIX_FMT_BGRA64LE: +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packed1 = yuv2bgra64le_1_c; + *yuv2packed2 = yuv2bgra64le_2_c; + *yuv2packedX = yuv2bgra64le_X_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packed1 = yuv2bgrx64le_1_c; + *yuv2packed2 = yuv2bgrx64le_2_c; + *yuv2packedX = yuv2bgrx64le_X_c; + } + break; + case AV_PIX_FMT_BGRA64BE: +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packed1 = yuv2bgra64be_1_c; + *yuv2packed2 = yuv2bgra64be_2_c; + *yuv2packedX = yuv2bgra64be_X_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packed1 = yuv2bgrx64be_1_c; + *yuv2packed2 = yuv2bgrx64be_2_c; + *yuv2packedX = yuv2bgrx64be_X_c; + } + break; + case AV_PIX_FMT_RGB48LE: + *yuv2packed1 = yuv2rgb48le_1_c; + *yuv2packed2 = yuv2rgb48le_2_c; + *yuv2packedX = yuv2rgb48le_X_c; + break; + case AV_PIX_FMT_RGB48BE: + *yuv2packed1 = yuv2rgb48be_1_c; + *yuv2packed2 = yuv2rgb48be_2_c; + *yuv2packedX = yuv2rgb48be_X_c; + break; + case AV_PIX_FMT_BGR48LE: + *yuv2packed1 = yuv2bgr48le_1_c; + *yuv2packed2 = yuv2bgr48le_2_c; + *yuv2packedX = yuv2bgr48le_X_c; + break; + case AV_PIX_FMT_BGR48BE: + *yuv2packed1 = yuv2bgr48be_1_c; + *yuv2packed2 = yuv2bgr48be_2_c; + *yuv2packedX = yuv2bgr48be_X_c; + break; + case AV_PIX_FMT_RGB32: + case AV_PIX_FMT_BGR32: +#if CONFIG_SMALL + *yuv2packed1 = yuv2rgb32_1_c; + *yuv2packed2 = yuv2rgb32_2_c; + *yuv2packedX = yuv2rgb32_X_c; +#else +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packed1 = yuv2rgba32_1_c; + *yuv2packed2 = yuv2rgba32_2_c; + *yuv2packedX = yuv2rgba32_X_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packed1 = yuv2rgbx32_1_c; + *yuv2packed2 = yuv2rgbx32_2_c; + *yuv2packedX = yuv2rgbx32_X_c; + } +#endif /* !CONFIG_SMALL */ + break; + case AV_PIX_FMT_RGB32_1: + case AV_PIX_FMT_BGR32_1: +#if CONFIG_SMALL + *yuv2packed1 = yuv2rgb32_1_1_c; + *yuv2packed2 = yuv2rgb32_1_2_c; + *yuv2packedX = yuv2rgb32_1_X_c; +#else +#if CONFIG_SWSCALE_ALPHA + if (c->needAlpha) { + *yuv2packed1 = yuv2rgba32_1_1_c; + *yuv2packed2 = yuv2rgba32_1_2_c; + *yuv2packedX = yuv2rgba32_1_X_c; + } else +#endif /* CONFIG_SWSCALE_ALPHA */ + { + *yuv2packed1 = yuv2rgbx32_1_1_c; + *yuv2packed2 = yuv2rgbx32_1_2_c; + *yuv2packedX = yuv2rgbx32_1_X_c; + } +#endif /* !CONFIG_SMALL */ + break; + case AV_PIX_FMT_RGB24: + *yuv2packed1 = yuv2rgb24_1_c; + *yuv2packed2 = yuv2rgb24_2_c; + *yuv2packedX = yuv2rgb24_X_c; + break; + case AV_PIX_FMT_BGR24: + *yuv2packed1 = yuv2bgr24_1_c; + *yuv2packed2 = yuv2bgr24_2_c; + *yuv2packedX = yuv2bgr24_X_c; + break; + case AV_PIX_FMT_RGB565LE: + case AV_PIX_FMT_RGB565BE: + case AV_PIX_FMT_BGR565LE: + case AV_PIX_FMT_BGR565BE: + *yuv2packed1 = yuv2rgb16_1_c; + *yuv2packed2 = yuv2rgb16_2_c; + *yuv2packedX = yuv2rgb16_X_c; + break; + case AV_PIX_FMT_RGB555LE: + case AV_PIX_FMT_RGB555BE: + case AV_PIX_FMT_BGR555LE: + case AV_PIX_FMT_BGR555BE: + *yuv2packed1 = yuv2rgb15_1_c; + *yuv2packed2 = yuv2rgb15_2_c; + *yuv2packedX = yuv2rgb15_X_c; + break; + case AV_PIX_FMT_RGB444LE: + case AV_PIX_FMT_RGB444BE: + case AV_PIX_FMT_BGR444LE: + case AV_PIX_FMT_BGR444BE: + *yuv2packed1 = yuv2rgb12_1_c; + *yuv2packed2 = yuv2rgb12_2_c; + *yuv2packedX = yuv2rgb12_X_c; + break; + case AV_PIX_FMT_RGB8: + case AV_PIX_FMT_BGR8: + *yuv2packed1 = yuv2rgb8_1_c; + *yuv2packed2 = yuv2rgb8_2_c; + *yuv2packedX = yuv2rgb8_X_c; + break; + case AV_PIX_FMT_RGB4: + case AV_PIX_FMT_BGR4: + *yuv2packed1 = yuv2rgb4_1_c; + *yuv2packed2 = yuv2rgb4_2_c; + *yuv2packedX = yuv2rgb4_X_c; + break; + case AV_PIX_FMT_RGB4_BYTE: + case AV_PIX_FMT_BGR4_BYTE: + *yuv2packed1 = yuv2rgb4b_1_c; + *yuv2packed2 = yuv2rgb4b_2_c; + *yuv2packedX = yuv2rgb4b_X_c; + break; + case AV_PIX_FMT_X2RGB10LE: + case AV_PIX_FMT_X2RGB10BE: + *yuv2packed1 = yuv2x2rgb10_1_c; + *yuv2packed2 = yuv2x2rgb10_2_c; + *yuv2packedX = yuv2x2rgb10_X_c; + break; + case AV_PIX_FMT_X2BGR10LE: + case AV_PIX_FMT_X2BGR10BE: + *yuv2packed1 = yuv2x2bgr10_1_c; + *yuv2packed2 = yuv2x2bgr10_2_c; + *yuv2packedX = yuv2x2bgr10_X_c; + break; + } + } + switch (dstFormat) { + case AV_PIX_FMT_MONOWHITE: + *yuv2packed1 = yuv2monowhite_1_c; + *yuv2packed2 = yuv2monowhite_2_c; + *yuv2packedX = yuv2monowhite_X_c; + break; + case AV_PIX_FMT_MONOBLACK: + *yuv2packed1 = yuv2monoblack_1_c; + *yuv2packed2 = yuv2monoblack_2_c; + *yuv2packedX = yuv2monoblack_X_c; + break; + case AV_PIX_FMT_YUYV422: + *yuv2packed1 = yuv2yuyv422_1_c; + *yuv2packed2 = yuv2yuyv422_2_c; + *yuv2packedX = yuv2yuyv422_X_c; + break; + case AV_PIX_FMT_YVYU422: + *yuv2packed1 = yuv2yvyu422_1_c; + *yuv2packed2 = yuv2yvyu422_2_c; + *yuv2packedX = yuv2yvyu422_X_c; + break; + case AV_PIX_FMT_UYVY422: + *yuv2packed1 = yuv2uyvy422_1_c; + *yuv2packed2 = yuv2uyvy422_2_c; + *yuv2packedX = yuv2uyvy422_X_c; + break; + case AV_PIX_FMT_VYU444: + *yuv2packed1 = yuv2vyu444_1_c; + *yuv2packed2 = yuv2vyu444_2_c; + *yuv2packedX = yuv2vyu444_X_c; + break; + case AV_PIX_FMT_YA8: + *yuv2packed1 = yuv2ya8_1_c; + *yuv2packed2 = yuv2ya8_2_c; + *yuv2packedX = yuv2ya8_X_c; + break; + case AV_PIX_FMT_YA16LE: + *yuv2packed1 = yuv2ya16le_1_c; + *yuv2packed2 = yuv2ya16le_2_c; + *yuv2packedX = yuv2ya16le_X_c; + break; + case AV_PIX_FMT_YA16BE: + *yuv2packed1 = yuv2ya16be_1_c; + *yuv2packed2 = yuv2ya16be_2_c; + *yuv2packedX = yuv2ya16be_X_c; + break; + case AV_PIX_FMT_V30XLE: + *yuv2packedX = yuv2v30xle_X_c; + break; + case AV_PIX_FMT_AYUV64LE: + *yuv2packedX = yuv2ayuv64le_X_c; + break; + case AV_PIX_FMT_AYUV64BE: + *yuv2packedX = yuv2ayuv64be_X_c; + break; + case AV_PIX_FMT_AYUV: + *yuv2packed1 = yuv2ayuv_1_c; + *yuv2packed2 = yuv2ayuv_2_c; + *yuv2packedX = yuv2ayuv_X_c; + break; + case AV_PIX_FMT_VUYA: + case AV_PIX_FMT_VUYX: + *yuv2packed1 = yuv2vuyX_1_c; + *yuv2packed2 = yuv2vuyX_2_c; + *yuv2packedX = yuv2vuyX_X_c; + break; + case AV_PIX_FMT_UYVA: + *yuv2packed1 = yuv2uyva_1_c; + *yuv2packed2 = yuv2uyva_2_c; + *yuv2packedX = yuv2uyva_X_c; + break; + case AV_PIX_FMT_XV30LE: + *yuv2packedX = yuv2xv30le_X_c; + break; + case AV_PIX_FMT_XV36LE: + *yuv2packedX = yuv2xv36le_X_c; + break; + case AV_PIX_FMT_XV36BE: + *yuv2packedX = yuv2xv36be_X_c; + break; + case AV_PIX_FMT_XV48LE: + *yuv2packedX = yuv2xv48le_X_c; + break; + case AV_PIX_FMT_XV48BE: + *yuv2packedX = yuv2xv48be_X_c; + break; + case AV_PIX_FMT_Y210LE: + *yuv2packedX = yuv2y210le_X_c; + break; + case AV_PIX_FMT_Y212LE: + *yuv2packedX = yuv2y212le_X_c; + break; + case AV_PIX_FMT_Y216LE: + *yuv2packedX = yuv2y216le_X_c; + break; + } +} diff --git a/libs/ffmpeg/libswscale/rgb2rgb.c b/libs/ffmpeg/libswscale/rgb2rgb.c new file mode 100644 index 00000000000..4bba657bd14 --- /dev/null +++ b/libs/ffmpeg/libswscale/rgb2rgb.c @@ -0,0 +1,471 @@ +/* + * software RGB to RGB converter + * pluralize by software PAL8 to RGB converter + * software YUV to YUV converter + * software YUV to RGB converter + * Written by Nick Kurshev. + * palette & YUV & runtime CPU stuff by Michael (michaelni@gmx.at) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <inttypes.h> + +#include "libavutil/attributes.h" +#include "libavutil/bswap.h" +#include "config.h" +#include "rgb2rgb.h" +#include "swscale.h" +#include "swscale_internal.h" + +void (*rgb32tobgr24)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb32tobgr16)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb32tobgr15)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb24tobgr32)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb24tobgr24)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb24tobgr16)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb24tobgr15)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb16tobgr24)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb15tobgr24)(const uint8_t *src, uint8_t *dst, int src_size); + +void (*rgb32to16)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb32to15)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb24to16)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb24to15)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb16to32)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb16to15)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb15to16)(const uint8_t *src, uint8_t *dst, int src_size); +void (*rgb15to32)(const uint8_t *src, uint8_t *dst, int src_size); + +void (*shuffle_bytes_0321)(const uint8_t *src, uint8_t *dst, int src_size); +void (*shuffle_bytes_2103)(const uint8_t *src, uint8_t *dst, int src_size); +void (*shuffle_bytes_1230)(const uint8_t *src, uint8_t *dst, int src_size); +void (*shuffle_bytes_3012)(const uint8_t *src, uint8_t *dst, int src_size); +void (*shuffle_bytes_3210)(const uint8_t *src, uint8_t *dst, int src_size); +void (*shuffle_bytes_3102)(const uint8_t *src, uint8_t *dst, int src_size); +void (*shuffle_bytes_2013)(const uint8_t *src, uint8_t *dst, int src_size); +void (*shuffle_bytes_2130)(const uint8_t *src, uint8_t *dst, int src_size); +void (*shuffle_bytes_1203)(const uint8_t *src, uint8_t *dst, int src_size); + + +void (*yv12toyuy2)(const uint8_t *ysrc, const uint8_t *usrc, + const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride); +void (*yv12touyvy)(const uint8_t *ysrc, const uint8_t *usrc, + const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride); +void (*yuv422ptoyuy2)(const uint8_t *ysrc, const uint8_t *usrc, + const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride); +void (*yuv422ptouyvy)(const uint8_t *ysrc, const uint8_t *usrc, + const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride); +void (*ff_rgb24toyv12)(const uint8_t *src, uint8_t *ydst, + uint8_t *udst, uint8_t *vdst, + int width, int height, + int lumStride, int chromStride, int srcStride, + const int32_t *rgb2yuv); +void (*planar2x)(const uint8_t *src, uint8_t *dst, int width, int height, + int srcStride, int dstStride); +void (*interleaveBytes)(const uint8_t *src1, const uint8_t *src2, uint8_t *dst, + int width, int height, int src1Stride, + int src2Stride, int dstStride); +void (*deinterleaveBytes)(const uint8_t *src, uint8_t *dst1, uint8_t *dst2, + int width, int height, int srcStride, + int dst1Stride, int dst2Stride); +void (*uyvytoyuv420)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + const uint8_t *src, int width, int height, + int lumStride, int chromStride, int srcStride); +void (*uyvytoyuv422)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + const uint8_t *src, int width, int height, + int lumStride, int chromStride, int srcStride); +void (*yuyvtoyuv420)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + const uint8_t *src, int width, int height, + int lumStride, int chromStride, int srcStride); +void (*yuyvtoyuv422)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + const uint8_t *src, int width, int height, + int lumStride, int chromStride, int srcStride); + +#define BY ((int)( 0.098 * (1 << RGB2YUV_SHIFT) + 0.5)) +#define BV ((int)(-0.071 * (1 << RGB2YUV_SHIFT) + 0.5)) +#define BU ((int)( 0.439 * (1 << RGB2YUV_SHIFT) + 0.5)) +#define GY ((int)( 0.504 * (1 << RGB2YUV_SHIFT) + 0.5)) +#define GV ((int)(-0.368 * (1 << RGB2YUV_SHIFT) + 0.5)) +#define GU ((int)(-0.291 * (1 << RGB2YUV_SHIFT) + 0.5)) +#define RY ((int)( 0.257 * (1 << RGB2YUV_SHIFT) + 0.5)) +#define RV ((int)( 0.439 * (1 << RGB2YUV_SHIFT) + 0.5)) +#define RU ((int)(-0.148 * (1 << RGB2YUV_SHIFT) + 0.5)) + +//plain C versions +#include "rgb2rgb_template.c" + +/* + * RGB15->RGB16 original by Strepto/Astral + * ported to gcc & bugfixed : A'rpi + * MMXEXT, 3DNOW optimization by Nick Kurshev + * 32-bit C version, and and&add trick by Michael Niedermayer + */ + +av_cold void ff_sws_rgb2rgb_init(void) +{ + rgb2rgb_init_c(); +#if ARCH_AARCH64 + rgb2rgb_init_aarch64(); +#elif ARCH_RISCV + rgb2rgb_init_riscv(); +#elif ARCH_X86 + rgb2rgb_init_x86(); +#elif ARCH_LOONGARCH64 + rgb2rgb_init_loongarch(); +#endif +} + +void rgb32to24(const uint8_t *src, uint8_t *dst, int src_size) +{ + int i, num_pixels = src_size >> 2; + + for (i = 0; i < num_pixels; i++) { +#if HAVE_BIGENDIAN + /* RGB32 (= A,B,G,R) -> BGR24 (= B,G,R) */ + dst[3 * i + 0] = src[4 * i + 1]; + dst[3 * i + 1] = src[4 * i + 2]; + dst[3 * i + 2] = src[4 * i + 3]; +#else + dst[3 * i + 0] = src[4 * i + 2]; + dst[3 * i + 1] = src[4 * i + 1]; + dst[3 * i + 2] = src[4 * i + 0]; +#endif + } +} + +void rgb24to32(const uint8_t *src, uint8_t *dst, int src_size) +{ + int i; + + for (i = 0; 3 * i < src_size; i++) { +#if HAVE_BIGENDIAN + /* RGB24 (= R, G, B) -> BGR32 (= A, R, G, B) */ + dst[4 * i + 0] = 255; + dst[4 * i + 1] = src[3 * i + 0]; + dst[4 * i + 2] = src[3 * i + 1]; + dst[4 * i + 3] = src[3 * i + 2]; +#else + dst[4 * i + 0] = src[3 * i + 2]; + dst[4 * i + 1] = src[3 * i + 1]; + dst[4 * i + 2] = src[3 * i + 0]; + dst[4 * i + 3] = 255; +#endif + } +} + +void rgb16tobgr32(const uint8_t *src, uint8_t *dst, int src_size) +{ + uint8_t *d = dst; + const uint16_t *s = (const uint16_t *)src; + const uint16_t *end = s + src_size / 2; + + while (s < end) { + register uint16_t bgr = *s++; +#if HAVE_BIGENDIAN + *d++ = 255; + *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2); + *d++ = ((bgr&0x07E0)>>3) | ((bgr&0x07E0)>> 9); + *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13); +#else + *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13); + *d++ = ((bgr&0x07E0)>>3) | ((bgr&0x07E0)>> 9); + *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2); + *d++ = 255; +#endif + } +} + +void rgb12to15(const uint8_t *src, uint8_t *dst, int src_size) +{ + uint16_t rgb, r, g, b; + uint16_t *d = (uint16_t *)dst; + const uint16_t *s = (const uint16_t *)src; + const uint16_t *end = s + src_size / 2; + + while (s < end) { + rgb = *s++; + r = rgb & 0xF00; + g = rgb & 0x0F0; + b = rgb & 0x00F; + r = (r << 3) | ((r & 0x800) >> 1); + g = (g << 2) | ((g & 0x080) >> 2); + b = (b << 1) | ( b >> 3); + *d++ = r | g | b; + } +} + +void rgb16to24(const uint8_t *src, uint8_t *dst, int src_size) +{ + uint8_t *d = dst; + const uint16_t *s = (const uint16_t *)src; + const uint16_t *end = s + src_size / 2; + + while (s < end) { + register uint16_t bgr = *s++; + *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13); + *d++ = ((bgr&0x07E0)>>3) | ((bgr&0x07E0)>> 9); + *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2); + } +} + +void rgb16tobgr16(const uint8_t *src, uint8_t *dst, int src_size) +{ + int i, num_pixels = src_size >> 1; + + for (i = 0; i < num_pixels; i++) { + unsigned rgb = ((const uint16_t *)src)[i]; + ((uint16_t *)dst)[i] = (rgb >> 11) | (rgb & 0x7E0) | (rgb << 11); + } +} + +void rgb16tobgr15(const uint8_t *src, uint8_t *dst, int src_size) +{ + int i, num_pixels = src_size >> 1; + + for (i = 0; i < num_pixels; i++) { + unsigned rgb = ((const uint16_t *)src)[i]; + ((uint16_t *)dst)[i] = (rgb >> 11) | ((rgb & 0x7C0) >> 1) | ((rgb & 0x1F) << 10); + } +} + +void rgb15tobgr32(const uint8_t *src, uint8_t *dst, int src_size) +{ + uint8_t *d = dst; + const uint16_t *s = (const uint16_t *)src; + const uint16_t *end = s + src_size / 2; + + while (s < end) { + register uint16_t bgr = *s++; +#if HAVE_BIGENDIAN + *d++ = 255; + *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2); + *d++ = ((bgr&0x03E0)>>2) | ((bgr&0x03E0)>> 7); + *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12); +#else + *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12); + *d++ = ((bgr&0x03E0)>>2) | ((bgr&0x03E0)>> 7); + *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2); + *d++ = 255; +#endif + } +} + +void rgb15to24(const uint8_t *src, uint8_t *dst, int src_size) +{ + uint8_t *d = dst; + const uint16_t *s = (const uint16_t *)src; + const uint16_t *end = s + src_size / 2; + + while (s < end) { + register uint16_t bgr = *s++; + *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12); + *d++ = ((bgr&0x03E0)>>2) | ((bgr&0x03E0)>> 7); + *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2); + } +} + +void rgb15tobgr16(const uint8_t *src, uint8_t *dst, int src_size) +{ + int i, num_pixels = src_size >> 1; + + for (i = 0; i < num_pixels; i++) { + unsigned rgb = ((const uint16_t *)src)[i]; + ((uint16_t *)dst)[i] = ((rgb & 0x7C00) >> 10) | ((rgb & 0x3E0) << 1) | (rgb << 11); + } +} + +void rgb15tobgr15(const uint8_t *src, uint8_t *dst, int src_size) +{ + int i, num_pixels = src_size >> 1; + + for (i = 0; i < num_pixels; i++) { + unsigned rgb = ((const uint16_t *)src)[i]; + unsigned br = rgb & 0x7C1F; + ((uint16_t *)dst)[i] = (br >> 10) | (rgb & 0x3E0) | (br << 10); + } +} + +void rgb12tobgr12(const uint8_t *src, uint8_t *dst, int src_size) +{ + uint16_t *d = (uint16_t *)dst; + const uint16_t *s = (const uint16_t *)src; + int i, num_pixels = src_size >> 1; + + for (i = 0; i < num_pixels; i++) { + unsigned rgb = s[i]; + d[i] = (rgb << 8 | rgb & 0xF0 | rgb >> 8) & 0xFFF; + } +} + +#define DEFINE_RGB48TOBGR48(need_bswap, swap) \ +void rgb48tobgr48_ ## need_bswap(const uint8_t *src, \ + uint8_t *dst, int src_size) \ +{ \ + uint16_t *d = (uint16_t *)dst; \ + const uint16_t *s = (const uint16_t *)src; \ + int i, num_pixels = src_size >> 1; \ + \ + for (i = 0; i < num_pixels; i += 3) { \ + d[i ] = swap ? av_bswap16(s[i + 2]) : s[i + 2]; \ + d[i + 1] = swap ? av_bswap16(s[i + 1]) : s[i + 1]; \ + d[i + 2] = swap ? av_bswap16(s[i ]) : s[i ]; \ + } \ +} + +DEFINE_RGB48TOBGR48(nobswap, 0) +DEFINE_RGB48TOBGR48(bswap, 1) + +#define DEFINE_RGB64TOBGR48(need_bswap, swap) \ +void rgb64tobgr48_ ## need_bswap(const uint8_t *src, \ + uint8_t *dst, int src_size) \ +{ \ + uint16_t *d = (uint16_t *)dst; \ + const uint16_t *s = (const uint16_t *)src; \ + int i, num_pixels = src_size >> 3; \ + \ + for (i = 0; i < num_pixels; i++) { \ + d[3 * i ] = swap ? av_bswap16(s[4 * i + 2]) : s[4 * i + 2]; \ + d[3 * i + 1] = swap ? av_bswap16(s[4 * i + 1]) : s[4 * i + 1]; \ + d[3 * i + 2] = swap ? av_bswap16(s[4 * i ]) : s[4 * i ]; \ + } \ +} + +DEFINE_RGB64TOBGR48(nobswap, 0) +DEFINE_RGB64TOBGR48(bswap, 1) + +#define DEFINE_RGB64TO48(need_bswap, swap) \ +void rgb64to48_ ## need_bswap(const uint8_t *src, \ + uint8_t *dst, int src_size) \ +{ \ + uint16_t *d = (uint16_t *)dst; \ + const uint16_t *s = (const uint16_t *)src; \ + int i, num_pixels = src_size >> 3; \ + \ + for (i = 0; i < num_pixels; i++) { \ + d[3 * i ] = swap ? av_bswap16(s[4 * i ]) : s[4 * i ]; \ + d[3 * i + 1] = swap ? av_bswap16(s[4 * i + 1]) : s[4 * i + 1]; \ + d[3 * i + 2] = swap ? av_bswap16(s[4 * i + 2]) : s[4 * i + 2]; \ + } \ +} + +DEFINE_RGB64TO48(nobswap, 0) +DEFINE_RGB64TO48(bswap, 1) + +#define DEFINE_RGB48TOBGR64(need_bswap, swap) \ +void rgb48tobgr64_ ## need_bswap(const uint8_t *src, \ + uint8_t *dst, int src_size) \ +{ \ + uint16_t *d = (uint16_t *)dst; \ + const uint16_t *s = (const uint16_t *)src; \ + int i, num_pixels = src_size / 6; \ + \ + for (i = 0; i < num_pixels; i++) { \ + d[4 * i ] = swap ? av_bswap16(s[3 * i + 2]) : s[3 * i + 2]; \ + d[4 * i + 1] = swap ? av_bswap16(s[3 * i + 1]) : s[3 * i + 1]; \ + d[4 * i + 2] = swap ? av_bswap16(s[3 * i ]) : s[3 * i ]; \ + d[4 * i + 3] = 0xFFFF; \ + } \ +} + +DEFINE_RGB48TOBGR64(nobswap, 0) +DEFINE_RGB48TOBGR64(bswap, 1) + +#define DEFINE_RGB48TO64(need_bswap, swap) \ +void rgb48to64_ ## need_bswap(const uint8_t *src, \ + uint8_t *dst, int src_size) \ +{ \ + uint16_t *d = (uint16_t *)dst; \ + const uint16_t *s = (const uint16_t *)src; \ + int i, num_pixels = src_size / 6; \ + \ + for (i = 0; i < num_pixels; i++) { \ + d[4 * i ] = swap ? av_bswap16(s[3 * i ]) : s[3 * i ]; \ + d[4 * i + 1] = swap ? av_bswap16(s[3 * i + 1]) : s[3 * i + 1]; \ + d[4 * i + 2] = swap ? av_bswap16(s[3 * i + 2]) : s[3 * i + 2]; \ + d[4 * i + 3] = 0xFFFF; \ + } \ +} + +DEFINE_RGB48TO64(nobswap, 0) +DEFINE_RGB48TO64(bswap, 1) + +#define DEFINE_X2RGB10TO16(need_bswap, swap, bits, alpha) \ +void x2rgb10to ## bits ## _ ## need_bswap(const uint8_t *src, \ + uint8_t *dst, int src_size) \ +{ \ + uint16_t *d = (uint16_t *)dst; \ + const uint32_t *s = (const uint32_t *)src; \ + int i, num_pixels = src_size >> 2; \ + unsigned component; \ + \ + for (i = 0; i < num_pixels; i++) { \ + unsigned p = AV_RL32(s + i); \ + component = (p >> 20) & 0x3FF; \ + d[(3 + alpha) * i + 0] = swap ? av_bswap16(component << 6 | component >> 4) \ + : component << 6 | component >> 4; \ + component = (p >> 10) & 0x3FF; \ + d[(3 + alpha) * i + 1] = swap ? av_bswap16(component << 6 | component >> 4) \ + : component << 6 | component >> 4; \ + component = p & 0x3FF; \ + d[(3 + alpha) * i + 2] = swap ? av_bswap16(component << 6 | component >> 4) \ + : component << 6 | component >> 4; \ + if (alpha) d[(3 + alpha) * i + 3] = 0xffff; \ + } \ +} + +DEFINE_X2RGB10TO16(nobswap, 0, 48, 0) +DEFINE_X2RGB10TO16(bswap, 1, 48, 0) +DEFINE_X2RGB10TO16(nobswap, 0, 64, 1) +DEFINE_X2RGB10TO16(bswap, 1, 64, 1) + +#define DEFINE_X2RGB10TOBGR16(need_bswap, swap, bits, alpha) \ +void x2rgb10tobgr ## bits ## _ ## need_bswap(const uint8_t *src, \ + uint8_t *dst, int src_size) \ +{ \ + uint16_t *d = (uint16_t *)dst; \ + const uint32_t *s = (const uint32_t *)src; \ + int i, num_pixels = src_size >> 2; \ + unsigned component; \ + \ + for (i = 0; i < num_pixels; i++) { \ + unsigned p = AV_RL32(s + i); \ + component = p & 0x3FF; \ + d[(3 + alpha) * i + 0] = swap ? av_bswap16(component << 6 | component >> 4) \ + : component << 6 | component >> 4; \ + component = (p >> 10) & 0x3FF; \ + d[(3 + alpha) * i + 1] = swap ? av_bswap16(component << 6 | component >> 4) \ + : component << 6 | component >> 4; \ + component = (p >> 20) & 0x3FF; \ + d[(3 + alpha) * i + 2] = swap ? av_bswap16(component << 6 | component >> 4) \ + : component << 6 | component >> 4; \ + if (alpha) d[(3 + alpha) * i + 3] = 0xffff; \ + } \ +} + +DEFINE_X2RGB10TOBGR16(nobswap, 0, 48, 0) +DEFINE_X2RGB10TOBGR16(bswap, 1, 48, 0) +DEFINE_X2RGB10TOBGR16(nobswap, 0, 64, 1) +DEFINE_X2RGB10TOBGR16(bswap, 1, 64, 1) diff --git a/libs/ffmpeg/libswscale/rgb2rgb.h b/libs/ffmpeg/libswscale/rgb2rgb.h new file mode 100644 index 00000000000..ed6e08a565c --- /dev/null +++ b/libs/ffmpeg/libswscale/rgb2rgb.h @@ -0,0 +1,165 @@ +/* + * software RGB to RGB converter + * pluralize by Software PAL8 to RGB converter + * Software YUV to YUV converter + * Software YUV to RGB converter + * Written by Nick Kurshev. + * YUV & runtime CPU stuff by Michael (michaelni@gmx.at) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_RGB2RGB_H +#define SWSCALE_RGB2RGB_H + +#include <stdint.h> + +/* A full collection of RGB to RGB(BGR) converters */ +extern void (*rgb24tobgr32)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb24tobgr16)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb24tobgr15)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb32tobgr24)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb32to16)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb32to15)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb15to16)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb15tobgr24)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb15to32)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb16to15)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb16tobgr24)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb16to32)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb24tobgr24)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb24to16)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb24to15)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb32tobgr16)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*rgb32tobgr15)(const uint8_t *src, uint8_t *dst, int src_size); + +extern void (*shuffle_bytes_0321)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*shuffle_bytes_2103)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*shuffle_bytes_1230)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*shuffle_bytes_3012)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*shuffle_bytes_3210)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*shuffle_bytes_3102)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*shuffle_bytes_2013)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*shuffle_bytes_2130)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*shuffle_bytes_1203)(const uint8_t *src, uint8_t *dst, int src_size); + +void rgb64tobgr48_nobswap(const uint8_t *src, uint8_t *dst, int src_size); +void rgb64tobgr48_bswap(const uint8_t *src, uint8_t *dst, int src_size); +void rgb48tobgr48_nobswap(const uint8_t *src, uint8_t *dst, int src_size); +void rgb48tobgr48_bswap(const uint8_t *src, uint8_t *dst, int src_size); +void rgb64to48_nobswap(const uint8_t *src, uint8_t *dst, int src_size); +void rgb64to48_bswap(const uint8_t *src, uint8_t *dst, int src_size); +void rgb48tobgr64_nobswap(const uint8_t *src, uint8_t *dst, int src_size); +void rgb48tobgr64_bswap(const uint8_t *src, uint8_t *dst, int src_size); +void rgb48to64_nobswap(const uint8_t *src, uint8_t *dst, int src_size); +void rgb48to64_bswap(const uint8_t *src, uint8_t *dst, int src_size); +void rgb24to32(const uint8_t *src, uint8_t *dst, int src_size); +void rgb32to24(const uint8_t *src, uint8_t *dst, int src_size); +void rgb16tobgr32(const uint8_t *src, uint8_t *dst, int src_size); +void rgb16to24(const uint8_t *src, uint8_t *dst, int src_size); +void rgb16tobgr16(const uint8_t *src, uint8_t *dst, int src_size); +void rgb16tobgr15(const uint8_t *src, uint8_t *dst, int src_size); +void rgb15tobgr32(const uint8_t *src, uint8_t *dst, int src_size); +void rgb15to24(const uint8_t *src, uint8_t *dst, int src_size); +void rgb15tobgr16(const uint8_t *src, uint8_t *dst, int src_size); +void rgb15tobgr15(const uint8_t *src, uint8_t *dst, int src_size); +void rgb12tobgr12(const uint8_t *src, uint8_t *dst, int src_size); +void rgb12to15(const uint8_t *src, uint8_t *dst, int src_size); + +void x2rgb10to48_nobswap(const uint8_t *src, uint8_t *dst, int src_size); +void x2rgb10to48_bswap(const uint8_t *src, uint8_t *dst, int src_size); +void x2rgb10tobgr48_nobswap(const uint8_t *src, uint8_t *dst, int src_size); +void x2rgb10tobgr48_bswap(const uint8_t *src, uint8_t *dst, int src_size); +void x2rgb10to64_nobswap(const uint8_t *src, uint8_t *dst, int src_size); +void x2rgb10to64_bswap(const uint8_t *src, uint8_t *dst, int src_size); +void x2rgb10tobgr64_nobswap(const uint8_t *src, uint8_t *dst, int src_size); +void x2rgb10tobgr64_bswap(const uint8_t *src, uint8_t *dst, int src_size); + +void ff_rgb24toyv12_c(const uint8_t *src, uint8_t *ydst, uint8_t *udst, + uint8_t *vdst, int width, int height, int lumStride, + int chromStride, int srcStride, const int32_t *rgb2yuv); + +/** + * Height should be a multiple of 2 and width should be a multiple of 16. + * (If this is a problem for anyone then tell me, and I will fix it.) + */ +extern void (*yv12toyuy2)(const uint8_t *ysrc, const uint8_t *usrc, const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride); + +/** + * Width should be a multiple of 16. + */ +extern void (*yuv422ptoyuy2)(const uint8_t *ysrc, const uint8_t *usrc, const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride); + +/** + * Height should be a multiple of 2 and width should be a multiple of 16. + * (If this is a problem for anyone then tell me, and I will fix it.) + */ +extern void (*yv12touyvy)(const uint8_t *ysrc, const uint8_t *usrc, const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride); + +/** + * Width should be a multiple of 16. + */ +extern void (*yuv422ptouyvy)(const uint8_t *ysrc, const uint8_t *usrc, const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, int dstStride); + +/** + * Height should be a multiple of 2 and width should be a multiple of 2. + * (If this is a problem for anyone then tell me, and I will fix it.) + */ +extern void (*ff_rgb24toyv12)(const uint8_t *src, uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + int width, int height, + int lumStride, int chromStride, int srcStride, + const int32_t *rgb2yuv); +extern void (*planar2x)(const uint8_t *src, uint8_t *dst, int width, int height, + int srcStride, int dstStride); + +extern void (*interleaveBytes)(const uint8_t *src1, const uint8_t *src2, uint8_t *dst, + int width, int height, int src1Stride, + int src2Stride, int dstStride); + +extern void (*deinterleaveBytes)(const uint8_t *src, uint8_t *dst1, uint8_t *dst2, + int width, int height, int srcStride, + int dst1Stride, int dst2Stride); + +extern void (*uyvytoyuv420)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src, + int width, int height, + int lumStride, int chromStride, int srcStride); +extern void (*uyvytoyuv422)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src, + int width, int height, + int lumStride, int chromStride, int srcStride); +extern void (*yuyvtoyuv420)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src, + int width, int height, + int lumStride, int chromStride, int srcStride); +extern void (*yuyvtoyuv422)(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src, + int width, int height, + int lumStride, int chromStride, int srcStride); + +void ff_sws_rgb2rgb_init(void); + +void rgb2rgb_init_aarch64(void); +void rgb2rgb_init_riscv(void); +void rgb2rgb_init_x86(void); +void rgb2rgb_init_loongarch(void); + +#endif /* SWSCALE_RGB2RGB_H */ diff --git a/libs/ffmpeg/libswscale/rgb2rgb_template.c b/libs/ffmpeg/libswscale/rgb2rgb_template.c new file mode 100644 index 00000000000..c36bbccea9f --- /dev/null +++ b/libs/ffmpeg/libswscale/rgb2rgb_template.c @@ -0,0 +1,877 @@ +/* + * software RGB to RGB converter + * pluralize by software PAL8 to RGB converter + * software YUV to YUV converter + * software YUV to RGB converter + * Written by Nick Kurshev. + * palette & YUV & runtime CPU stuff by Michael (michaelni@gmx.at) + * lot of big-endian byte order fixes by Alex Beregszaszi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if 0 +#pragma makedep header +#endif + +#include <stddef.h> + +#include "libavutil/attributes.h" + +static inline void rgb24tobgr32_c(const uint8_t *src, uint8_t *dst, + int src_size) +{ + uint8_t *dest = dst; + const uint8_t *s = src; + const uint8_t *end = s + src_size; + + while (s < end) { +#if HAVE_BIGENDIAN + /* RGB24 (= R, G, B) -> RGB32 (= A, B, G, R) */ + *dest++ = 255; + *dest++ = s[2]; + *dest++ = s[1]; + *dest++ = s[0]; + s += 3; +#else + *dest++ = *s++; + *dest++ = *s++; + *dest++ = *s++; + *dest++ = 255; +#endif + } +} + +static inline void rgb32tobgr24_c(const uint8_t *src, uint8_t *dst, + int src_size) +{ + uint8_t *dest = dst; + const uint8_t *s = src; + const uint8_t *end = s + src_size; + + while (s < end) { +#if HAVE_BIGENDIAN + /* RGB32 (= A, B, G, R) -> RGB24 (= R, G, B) */ + s++; + dest[2] = *s++; + dest[1] = *s++; + dest[0] = *s++; + dest += 3; +#else + *dest++ = *s++; + *dest++ = *s++; + *dest++ = *s++; + s++; +#endif + } +} + +/* + * original by Strepto/Astral + * ported to gcc & bugfixed: A'rpi + * MMXEXT, 3DNOW optimization by Nick Kurshev + * 32-bit C version, and and&add trick by Michael Niedermayer + */ +static inline void rgb15to16_c(const uint8_t *src, uint8_t *dst, int src_size) +{ + register uint8_t *d = dst; + register const uint8_t *s = src; + register const uint8_t *end = s + src_size; + const uint8_t *mm_end = end - 3; + + while (s < mm_end) { + register unsigned x = *((const uint32_t *)s); + *((uint32_t *)d) = (x & 0x7FFF7FFF) + (x & 0x7FE07FE0); + d += 4; + s += 4; + } + if (s < end) { + register unsigned short x = *((const uint16_t *)s); + *((uint16_t *)d) = (x & 0x7FFF) + (x & 0x7FE0); + } +} + +static inline void rgb16to15_c(const uint8_t *src, uint8_t *dst, int src_size) +{ + register uint8_t *d = dst; + register const uint8_t *s = src; + register const uint8_t *end = s + src_size; + const uint8_t *mm_end = end - 3; + + while (s < mm_end) { + register uint32_t x = *((const uint32_t *)s); + *((uint32_t *)d) = ((x >> 1) & 0x7FE07FE0) | (x & 0x001F001F); + s += 4; + d += 4; + } + if (s < end) { + register uint16_t x = *((const uint16_t *)s); + *((uint16_t *)d) = ((x >> 1) & 0x7FE0) | (x & 0x001F); + } +} + +static inline void rgb32to16_c(const uint8_t *src, uint8_t *dst, int src_size) +{ + uint16_t *d = (uint16_t *)dst; + const uint8_t *s = src; + const uint8_t *end = s + src_size; + + while (s < end) { + register int rgb = *(const uint32_t *)s; + s += 4; + *d++ = ((rgb & 0xFF) >> 3) + + ((rgb & 0xFC00) >> 5) + + ((rgb & 0xF80000) >> 8); + } +} + +static inline void rgb32tobgr16_c(const uint8_t *src, uint8_t *dst, + int src_size) +{ + uint16_t *d = (uint16_t *)dst; + const uint8_t *s = src; + const uint8_t *end = s + src_size; + + while (s < end) { + register int rgb = *(const uint32_t *)s; + s += 4; + *d++ = ((rgb & 0xF8) << 8) + + ((rgb & 0xFC00) >> 5) + + ((rgb & 0xF80000) >> 19); + } +} + +static inline void rgb32to15_c(const uint8_t *src, uint8_t *dst, int src_size) +{ + uint16_t *d = (uint16_t *)dst; + const uint8_t *s = src; + const uint8_t *end = s + src_size; + + while (s < end) { + register int rgb = *(const uint32_t *)s; + s += 4; + *d++ = ((rgb & 0xFF) >> 3) + + ((rgb & 0xF800) >> 6) + + ((rgb & 0xF80000) >> 9); + } +} + +static inline void rgb32tobgr15_c(const uint8_t *src, uint8_t *dst, + int src_size) +{ + uint16_t *d = (uint16_t *)dst; + const uint8_t *s = src; + const uint8_t *end = s + src_size; + + while (s < end) { + register int rgb = *(const uint32_t *)s; + s += 4; + *d++ = ((rgb & 0xF8) << 7) + + ((rgb & 0xF800) >> 6) + + ((rgb & 0xF80000) >> 19); + } +} + +static inline void rgb24tobgr16_c(const uint8_t *src, uint8_t *dst, + int src_size) +{ + uint16_t *d = (uint16_t *)dst; + const uint8_t *s = src; + const uint8_t *end = s + src_size; + + while (s < end) { + const int b = *s++; + const int g = *s++; + const int r = *s++; + *d++ = (b >> 3) | ((g & 0xFC) << 3) | ((r & 0xF8) << 8); + } +} + +static inline void rgb24to16_c(const uint8_t *src, uint8_t *dst, int src_size) +{ + uint16_t *d = (uint16_t *)dst; + const uint8_t *s = src; + const uint8_t *end = s + src_size; + + while (s < end) { + const int r = *s++; + const int g = *s++; + const int b = *s++; + *d++ = (b >> 3) | ((g & 0xFC) << 3) | ((r & 0xF8) << 8); + } +} + +static inline void rgb24tobgr15_c(const uint8_t *src, uint8_t *dst, + int src_size) +{ + uint16_t *d = (uint16_t *)dst; + const uint8_t *s = src; + const uint8_t *end = s + src_size; + + while (s < end) { + const int b = *s++; + const int g = *s++; + const int r = *s++; + *d++ = (b >> 3) | ((g & 0xF8) << 2) | ((r & 0xF8) << 7); + } +} + +static inline void rgb24to15_c(const uint8_t *src, uint8_t *dst, int src_size) +{ + uint16_t *d = (uint16_t *)dst; + const uint8_t *s = src; + const uint8_t *end = s + src_size; + + while (s < end) { + const int r = *s++; + const int g = *s++; + const int b = *s++; + *d++ = (b >> 3) | ((g & 0xF8) << 2) | ((r & 0xF8) << 7); + } +} + +static inline void rgb15tobgr24_c(const uint8_t *src, uint8_t *dst, + int src_size) +{ + uint8_t *d = dst; + const uint16_t *s = (const uint16_t *)src; + const uint16_t *end = s + src_size / 2; + + while (s < end) { + register uint16_t bgr = *s++; + *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2); + *d++ = ((bgr&0x03E0)>>2) | ((bgr&0x03E0)>> 7); + *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12); + } +} + +static inline void rgb16tobgr24_c(const uint8_t *src, uint8_t *dst, + int src_size) +{ + uint8_t *d = (uint8_t *)dst; + const uint16_t *s = (const uint16_t *)src; + const uint16_t *end = s + src_size / 2; + + while (s < end) { + register uint16_t bgr = *s++; + *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2); + *d++ = ((bgr&0x07E0)>>3) | ((bgr&0x07E0)>> 9); + *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13); + } +} + +static inline void rgb15to32_c(const uint8_t *src, uint8_t *dst, int src_size) +{ + uint8_t *d = dst; + const uint16_t *s = (const uint16_t *)src; + const uint16_t *end = s + src_size / 2; + + while (s < end) { + register uint16_t bgr = *s++; +#if HAVE_BIGENDIAN + *d++ = 255; + *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12); + *d++ = ((bgr&0x03E0)>>2) | ((bgr&0x03E0)>> 7); + *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2); +#else + *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2); + *d++ = ((bgr&0x03E0)>>2) | ((bgr&0x03E0)>> 7); + *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12); + *d++ = 255; +#endif + } +} + +static inline void rgb16to32_c(const uint8_t *src, uint8_t *dst, int src_size) +{ + uint8_t *d = dst; + const uint16_t *s = (const uint16_t *)src; + const uint16_t *end = s + src_size / 2; + + while (s < end) { + register uint16_t bgr = *s++; +#if HAVE_BIGENDIAN + *d++ = 255; + *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13); + *d++ = ((bgr&0x07E0)>>3) | ((bgr&0x07E0)>> 9); + *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2); +#else + *d++ = ((bgr&0x001F)<<3) | ((bgr&0x001F)>> 2); + *d++ = ((bgr&0x07E0)>>3) | ((bgr&0x07E0)>> 9); + *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13); + *d++ = 255; +#endif + } +} + +static inline void shuffle_bytes_2103_c(const uint8_t *src, uint8_t *dst, + int src_size) +{ + int idx = 15 - src_size; + const uint8_t *s = src - idx; + uint8_t *d = dst - idx; + + for (; idx < 15; idx += 4) { + register unsigned v = *(const uint32_t *)&s[idx], g = v & 0xff00ff00; + v &= 0xff00ff; + *(uint32_t *)&d[idx] = (v >> 16) + g + (v << 16); + } +} + +static inline void shuffle_bytes_0321_c(const uint8_t *src, uint8_t *dst, + int src_size) +{ + int idx = 15 - src_size; + const uint8_t *s = src - idx; + uint8_t *d = dst - idx; + + for (; idx < 15; idx += 4) { + register unsigned v = *(const uint32_t *)&s[idx], g = v & 0x00ff00ff; + v &= 0xff00ff00; + *(uint32_t *)&d[idx] = (v >> 16) + g + (v << 16); + } +} + +#define DEFINE_SHUFFLE_BYTES(name, a, b, c, d) \ +static void shuffle_bytes_##name (const uint8_t *src, \ + uint8_t *dst, int src_size) \ +{ \ + int i; \ + \ + for (i = 0; i < src_size; i += 4) { \ + dst[i + 0] = src[i + a]; \ + dst[i + 1] = src[i + b]; \ + dst[i + 2] = src[i + c]; \ + dst[i + 3] = src[i + d]; \ + } \ +} + +DEFINE_SHUFFLE_BYTES(1230_c, 1, 2, 3, 0) +DEFINE_SHUFFLE_BYTES(3012_c, 3, 0, 1, 2) +DEFINE_SHUFFLE_BYTES(3210_c, 3, 2, 1, 0) +DEFINE_SHUFFLE_BYTES(3102_c, 3, 1, 0, 2) +DEFINE_SHUFFLE_BYTES(2013_c, 2, 0, 1, 3) +DEFINE_SHUFFLE_BYTES(2130_c, 2, 1, 3, 0) +DEFINE_SHUFFLE_BYTES(1203_c, 1, 2, 0, 3) + +static inline void rgb24tobgr24_c(const uint8_t *src, uint8_t *dst, int src_size) +{ + unsigned i; + + for (i = 0; i < src_size; i += 3) { + register uint8_t x = src[i + 2]; + dst[i + 1] = src[i + 1]; + dst[i + 2] = src[i + 0]; + dst[i + 0] = x; + } +} + +static inline void yuvPlanartoyuy2_c(const uint8_t *ysrc, const uint8_t *usrc, + const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, + int dstStride, int vertLumPerChroma) +{ + int y, i; + const int chromWidth = width >> 1; + + for (y = 0; y < height; y++) { +#if HAVE_FAST_64BIT + uint64_t *ldst = (uint64_t *)dst; + const uint8_t *yc = ysrc, *uc = usrc, *vc = vsrc; + for (i = 0; i < chromWidth; i += 2) { + uint64_t k = yc[0] + (uc[0] << 8) + + (yc[1] << 16) + ((unsigned) vc[0] << 24); + uint64_t l = yc[2] + (uc[1] << 8) + + (yc[3] << 16) + ((unsigned) vc[1] << 24); + *ldst++ = k + (l << 32); + yc += 4; + uc += 2; + vc += 2; + } + +#else + int *idst = (int32_t *)dst; + const uint8_t *yc = ysrc, *uc = usrc, *vc = vsrc; + + for (i = 0; i < chromWidth; i++) { +#if HAVE_BIGENDIAN + *idst++ = (yc[0] << 24) + (uc[0] << 16) + + (yc[1] << 8) + (vc[0] << 0); +#else + *idst++ = yc[0] + (uc[0] << 8) + + (yc[1] << 16) + (vc[0] << 24); +#endif + yc += 2; + uc++; + vc++; + } +#endif + if ((y & (vertLumPerChroma - 1)) == vertLumPerChroma - 1) { + usrc += chromStride; + vsrc += chromStride; + } + ysrc += lumStride; + dst += dstStride; + } +} + +/** + * Height should be a multiple of 2 and width should be a multiple of 16. + * (If this is a problem for anyone then tell me, and I will fix it.) + */ +static inline void yv12toyuy2_c(const uint8_t *ysrc, const uint8_t *usrc, + const uint8_t *vsrc, uint8_t *dst, + int width, int height, int lumStride, + int chromStride, int dstStride) +{ + //FIXME interpolate chroma + yuvPlanartoyuy2_c(ysrc, usrc, vsrc, dst, width, height, lumStride, + chromStride, dstStride, 2); +} + +static inline void yuvPlanartouyvy_c(const uint8_t *ysrc, const uint8_t *usrc, + const uint8_t *vsrc, uint8_t *dst, + int width, int height, + int lumStride, int chromStride, + int dstStride, int vertLumPerChroma) +{ + int y, i; + const int chromWidth = width >> 1; + + for (y = 0; y < height; y++) { +#if HAVE_FAST_64BIT + uint64_t *ldst = (uint64_t *)dst; + const uint8_t *yc = ysrc, *uc = usrc, *vc = vsrc; + for (i = 0; i < chromWidth; i += 2) { + uint64_t k = uc[0] + (yc[0] << 8) + + (vc[0] << 16) + ((unsigned) yc[1] << 24); + uint64_t l = uc[1] + (yc[2] << 8) + + (vc[1] << 16) + ((unsigned) yc[3] << 24); + *ldst++ = k + (l << 32); + yc += 4; + uc += 2; + vc += 2; + } + +#else + int *idst = (int32_t *)dst; + const uint8_t *yc = ysrc, *uc = usrc, *vc = vsrc; + + for (i = 0; i < chromWidth; i++) { +#if HAVE_BIGENDIAN + *idst++ = ((unsigned)uc[0] << 24) + (yc[0] << 16) + + (vc[0] << 8) + (yc[1] << 0); +#else + *idst++ = uc[0] + (yc[0] << 8) + + (vc[0] << 16) + ((unsigned)yc[1] << 24); +#endif + yc += 2; + uc++; + vc++; + } +#endif + if ((y & (vertLumPerChroma - 1)) == vertLumPerChroma - 1) { + usrc += chromStride; + vsrc += chromStride; + } + ysrc += lumStride; + dst += dstStride; + } +} + +/** + * Height should be a multiple of 2 and width should be a multiple of 16 + * (If this is a problem for anyone then tell me, and I will fix it.) + */ +static inline void yv12touyvy_c(const uint8_t *ysrc, const uint8_t *usrc, + const uint8_t *vsrc, uint8_t *dst, + int width, int height, int lumStride, + int chromStride, int dstStride) +{ + //FIXME interpolate chroma + yuvPlanartouyvy_c(ysrc, usrc, vsrc, dst, width, height, lumStride, + chromStride, dstStride, 2); +} + +/** + * Width should be a multiple of 16. + */ +static inline void yuv422ptouyvy_c(const uint8_t *ysrc, const uint8_t *usrc, + const uint8_t *vsrc, uint8_t *dst, + int width, int height, int lumStride, + int chromStride, int dstStride) +{ + yuvPlanartouyvy_c(ysrc, usrc, vsrc, dst, width, height, lumStride, + chromStride, dstStride, 1); +} + +/** + * Width should be a multiple of 16. + */ +static inline void yuv422ptoyuy2_c(const uint8_t *ysrc, const uint8_t *usrc, + const uint8_t *vsrc, uint8_t *dst, + int width, int height, int lumStride, + int chromStride, int dstStride) +{ + yuvPlanartoyuy2_c(ysrc, usrc, vsrc, dst, width, height, lumStride, + chromStride, dstStride, 1); +} + +static inline void planar2x_c(const uint8_t *src, uint8_t *dst, int srcWidth, + int srcHeight, int srcStride, int dstStride) +{ + int x, y; + + dst[0] = src[0]; + + // first line + for (x = 0; x < srcWidth - 1; x++) { + dst[2 * x + 1] = (3 * src[x] + src[x + 1]) >> 2; + dst[2 * x + 2] = (src[x] + 3 * src[x + 1]) >> 2; + } + dst[2 * srcWidth - 1] = src[srcWidth - 1]; + + dst += dstStride; + + for (y = 1; y < srcHeight; y++) { + const int mmxSize = 1; + + dst[0] = (src[0] * 3 + src[srcStride]) >> 2; + dst[dstStride] = (src[0] + 3 * src[srcStride]) >> 2; + + for (x = mmxSize - 1; x < srcWidth - 1; x++) { + dst[2 * x + 1] = (src[x + 0] * 3 + src[x + srcStride + 1]) >> 2; + dst[2 * x + dstStride + 2] = (src[x + 0] + 3 * src[x + srcStride + 1]) >> 2; + dst[2 * x + dstStride + 1] = (src[x + 1] + 3 * src[x + srcStride]) >> 2; + dst[2 * x + 2] = (src[x + 1] * 3 + src[x + srcStride]) >> 2; + } + dst[srcWidth * 2 - 1] = (src[srcWidth - 1] * 3 + src[srcWidth - 1 + srcStride]) >> 2; + dst[srcWidth * 2 - 1 + dstStride] = (src[srcWidth - 1] + 3 * src[srcWidth - 1 + srcStride]) >> 2; + + dst += dstStride * 2; + src += srcStride; + } + + // last line + dst[0] = src[0]; + + for (x = 0; x < srcWidth - 1; x++) { + dst[2 * x + 1] = (src[x] * 3 + src[x + 1]) >> 2; + dst[2 * x + 2] = (src[x] + 3 * src[x + 1]) >> 2; + } + dst[2 * srcWidth - 1] = src[srcWidth - 1]; +} + +/** + * width should be a multiple of 2. + * (If this is a problem for anyone then tell me, and I will fix it.) + */ +void ff_rgb24toyv12_c(const uint8_t *src, uint8_t *ydst, uint8_t *udst, + uint8_t *vdst, int width, int height, int lumStride, + int chromStride, int srcStride, const int32_t *rgb2yuv) +{ + int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX]; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + int y; + const int chromWidth = width >> 1; + const uint8_t *src1 = src; + const uint8_t *src2 = src1 + srcStride; + uint8_t *ydst1 = ydst; + uint8_t *ydst2 = ydst + lumStride; + + for (y = 0; y < height; y += 2) { + int i; + if (y + 1 == height) { + ydst2 = ydst1; + src2 = src1; + } + + for (i = 0; i < chromWidth; i++) { + unsigned int b11 = src1[6 * i + 0]; + unsigned int g11 = src1[6 * i + 1]; + unsigned int r11 = src1[6 * i + 2]; + unsigned int b12 = src1[6 * i + 3]; + unsigned int g12 = src1[6 * i + 4]; + unsigned int r12 = src1[6 * i + 5]; + unsigned int b21 = src2[6 * i + 0]; + unsigned int g21 = src2[6 * i + 1]; + unsigned int r21 = src2[6 * i + 2]; + unsigned int b22 = src2[6 * i + 3]; + unsigned int g22 = src2[6 * i + 4]; + unsigned int r22 = src2[6 * i + 5]; + + unsigned int Y11 = ((ry * r11 + gy * g11 + by * b11) >> RGB2YUV_SHIFT) + 16; + unsigned int Y12 = ((ry * r12 + gy * g12 + by * b12) >> RGB2YUV_SHIFT) + 16; + unsigned int Y21 = ((ry * r21 + gy * g21 + by * b21) >> RGB2YUV_SHIFT) + 16; + unsigned int Y22 = ((ry * r22 + gy * g22 + by * b22) >> RGB2YUV_SHIFT) + 16; + + unsigned int bx = (b11 + b12 + b21 + b22) >> 2; + unsigned int gx = (g11 + g12 + g21 + g22) >> 2; + unsigned int rx = (r11 + r12 + r21 + r22) >> 2; + + unsigned int U = ((ru * rx + gu * gx + bu * bx) >> RGB2YUV_SHIFT) + 128; + unsigned int V = ((rv * rx + gv * gx + bv * bx) >> RGB2YUV_SHIFT) + 128; + + ydst1[2 * i + 0] = Y11; + ydst1[2 * i + 1] = Y12; + ydst2[2 * i + 0] = Y21; + ydst2[2 * i + 1] = Y22; + udst[i] = U; + vdst[i] = V; + } + src1 += srcStride * 2; + src2 += srcStride * 2; + ydst1 += lumStride * 2; + ydst2 += lumStride * 2; + udst += chromStride; + vdst += chromStride; + } +} + +static void interleaveBytes_c(const uint8_t *src1, const uint8_t *src2, + uint8_t *dest, int width, int height, + int src1Stride, int src2Stride, int dstStride) +{ + int h; + + for (h = 0; h < height; h++) { + int w; + for (w = 0; w < width; w++) { + dest[2 * w + 0] = src1[w]; + dest[2 * w + 1] = src2[w]; + } + dest += dstStride; + src1 += src1Stride; + src2 += src2Stride; + } +} + +static void deinterleaveBytes_c(const uint8_t *src, uint8_t *dst1, uint8_t *dst2, + int width, int height, int srcStride, + int dst1Stride, int dst2Stride) +{ + int h; + + for (h = 0; h < height; h++) { + int w; + for (w = 0; w < width; w++) { + dst1[w] = src[2 * w + 0]; + dst2[w] = src[2 * w + 1]; + } + src += srcStride; + dst1 += dst1Stride; + dst2 += dst2Stride; + } +} + +static void extract_even_c(const uint8_t *src, uint8_t *dst, int count) +{ + dst += count; + src += count * 2; + count = -count; + while (count < 0) { + dst[count] = src[2 * count]; + count++; + } +} + +static void extract_even2_c(const uint8_t *src, uint8_t *dst0, uint8_t *dst1, + int count) +{ + dst0 += count; + dst1 += count; + src += count * 4; + count = -count; + while (count < 0) { + dst0[count] = src[4 * count + 0]; + dst1[count] = src[4 * count + 2]; + count++; + } +} + +static void extract_even2avg_c(const uint8_t *src0, const uint8_t *src1, + uint8_t *dst0, uint8_t *dst1, int count) +{ + dst0 += count; + dst1 += count; + src0 += count * 4; + src1 += count * 4; + count = -count; + while (count < 0) { + dst0[count] = (src0[4 * count + 0] + src1[4 * count + 0]) >> 1; + dst1[count] = (src0[4 * count + 2] + src1[4 * count + 2]) >> 1; + count++; + } +} + +static void extract_odd2_c(const uint8_t *src, uint8_t *dst0, uint8_t *dst1, + int count) +{ + dst0 += count; + dst1 += count; + src += count * 4; + count = -count; + src++; + while (count < 0) { + dst0[count] = src[4 * count + 0]; + dst1[count] = src[4 * count + 2]; + count++; + } +} + +static void extract_odd2avg_c(const uint8_t *src0, const uint8_t *src1, + uint8_t *dst0, uint8_t *dst1, int count) +{ + dst0 += count; + dst1 += count; + src0 += count * 4; + src1 += count * 4; + count = -count; + src0++; + src1++; + while (count < 0) { + dst0[count] = (src0[4 * count + 0] + src1[4 * count + 0]) >> 1; + dst1[count] = (src0[4 * count + 2] + src1[4 * count + 2]) >> 1; + count++; + } +} + +static void yuyvtoyuv420_c(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + const uint8_t *src, int width, int height, + int lumStride, int chromStride, int srcStride) +{ + int y; + const int chromWidth = AV_CEIL_RSHIFT(width, 1); + + for (y = 0; y < height; y++) { + extract_even_c(src, ydst, width); + if (y & 1) { + extract_odd2avg_c(src - srcStride, src, udst, vdst, chromWidth); + udst += chromStride; + vdst += chromStride; + } + + src += srcStride; + ydst += lumStride; + } +} + +static void yuyvtoyuv422_c(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + const uint8_t *src, int width, int height, + int lumStride, int chromStride, int srcStride) +{ + int y; + const int chromWidth = AV_CEIL_RSHIFT(width, 1); + + for (y = 0; y < height; y++) { + extract_even_c(src, ydst, width); + extract_odd2_c(src, udst, vdst, chromWidth); + + src += srcStride; + ydst += lumStride; + udst += chromStride; + vdst += chromStride; + } +} + +static void uyvytoyuv420_c(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + const uint8_t *src, int width, int height, + int lumStride, int chromStride, int srcStride) +{ + int y; + const int chromWidth = AV_CEIL_RSHIFT(width, 1); + + for (y = 0; y < height; y++) { + extract_even_c(src + 1, ydst, width); + if (y & 1) { + extract_even2avg_c(src - srcStride, src, udst, vdst, chromWidth); + udst += chromStride; + vdst += chromStride; + } + + src += srcStride; + ydst += lumStride; + } +} + +static void uyvytoyuv422_c(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + const uint8_t *src, int width, int height, + int lumStride, int chromStride, int srcStride) +{ + int y; + const int chromWidth = AV_CEIL_RSHIFT(width, 1); + + for (y = 0; y < height; y++) { + extract_even_c(src + 1, ydst, width); + extract_even2_c(src, udst, vdst, chromWidth); + + src += srcStride; + ydst += lumStride; + udst += chromStride; + vdst += chromStride; + } +} + +static av_cold void rgb2rgb_init_c(void) +{ + rgb15to16 = rgb15to16_c; + rgb15tobgr24 = rgb15tobgr24_c; + rgb15to32 = rgb15to32_c; + rgb16tobgr24 = rgb16tobgr24_c; + rgb16to32 = rgb16to32_c; + rgb16to15 = rgb16to15_c; + rgb24tobgr16 = rgb24tobgr16_c; + rgb24tobgr15 = rgb24tobgr15_c; + rgb24tobgr32 = rgb24tobgr32_c; + rgb32to16 = rgb32to16_c; + rgb32to15 = rgb32to15_c; + rgb32tobgr24 = rgb32tobgr24_c; + rgb24to15 = rgb24to15_c; + rgb24to16 = rgb24to16_c; + rgb24tobgr24 = rgb24tobgr24_c; +#if HAVE_BIGENDIAN + shuffle_bytes_0321 = shuffle_bytes_2103_c; + shuffle_bytes_2103 = shuffle_bytes_0321_c; +#else + shuffle_bytes_0321 = shuffle_bytes_0321_c; + shuffle_bytes_2103 = shuffle_bytes_2103_c; +#endif + shuffle_bytes_1230 = shuffle_bytes_1230_c; + shuffle_bytes_3012 = shuffle_bytes_3012_c; + shuffle_bytes_3210 = shuffle_bytes_3210_c; + shuffle_bytes_3102 = shuffle_bytes_3102_c; + shuffle_bytes_2013 = shuffle_bytes_2013_c; + shuffle_bytes_2130 = shuffle_bytes_2130_c; + shuffle_bytes_1203 = shuffle_bytes_1203_c; + rgb32tobgr16 = rgb32tobgr16_c; + rgb32tobgr15 = rgb32tobgr15_c; + yv12toyuy2 = yv12toyuy2_c; + yv12touyvy = yv12touyvy_c; + yuv422ptoyuy2 = yuv422ptoyuy2_c; + yuv422ptouyvy = yuv422ptouyvy_c; + planar2x = planar2x_c; + ff_rgb24toyv12 = ff_rgb24toyv12_c; + interleaveBytes = interleaveBytes_c; + deinterleaveBytes = deinterleaveBytes_c; + + uyvytoyuv420 = uyvytoyuv420_c; + uyvytoyuv422 = uyvytoyuv422_c; + yuyvtoyuv420 = yuyvtoyuv420_c; + yuyvtoyuv422 = yuyvtoyuv422_c; +} diff --git a/libs/ffmpeg/libswscale/slice.c b/libs/ffmpeg/libswscale/slice.c new file mode 100644 index 00000000000..44c3bd74b44 --- /dev/null +++ b/libs/ffmpeg/libswscale/slice.c @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2015 Pedro Arthur <bygrandao@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/mem.h" +#include "swscale_internal.h" + +static void free_lines(SwsSlice *s) +{ + int i; + for (i = 0; i < 2; ++i) { + int n = s->plane[i].available_lines; + int j; + for (j = 0; j < n; ++j) { + av_freep(&s->plane[i].line[j]); + if (s->is_ring) + s->plane[i].line[j+n] = NULL; + } + } + + for (i = 0; i < 4; ++i) + memset(s->plane[i].line, 0, sizeof(uint8_t*) * s->plane[i].available_lines * (s->is_ring ? 3 : 1)); + s->should_free_lines = 0; +} + +/* + slice lines contains extra bytes for vectorial code thus @size + is the allocated memory size and @width is the number of pixels +*/ +static int alloc_lines(SwsSlice *s, int size, int width) +{ + int i; + int idx[2] = {3, 2}; + + s->should_free_lines = 1; + s->width = width; + + for (i = 0; i < 2; ++i) { + int n = s->plane[i].available_lines; + int j; + int ii = idx[i]; + + av_assert0(n == s->plane[ii].available_lines); + for (j = 0; j < n; ++j) { + // chroma plane line U and V are expected to be contiguous in memory + // by mmx vertical scaler code + s->plane[i].line[j] = av_mallocz(size * 2 + 32); + if (!s->plane[i].line[j]) { + free_lines(s); + return AVERROR(ENOMEM); + } + s->plane[ii].line[j] = s->plane[i].line[j] + size + 16; + if (s->is_ring) { + s->plane[i].line[j+n] = s->plane[i].line[j]; + s->plane[ii].line[j+n] = s->plane[ii].line[j]; + } + } + } + + return 0; +} + +static int alloc_slice(SwsSlice *s, enum AVPixelFormat fmt, int lumLines, int chrLines, int h_sub_sample, int v_sub_sample, int ring) +{ + int i; + int size[4] = { lumLines, + chrLines, + chrLines, + lumLines }; + + s->h_chr_sub_sample = h_sub_sample; + s->v_chr_sub_sample = v_sub_sample; + s->fmt = fmt; + s->is_ring = ring; + s->should_free_lines = 0; + + for (i = 0; i < 4; ++i) { + int n = size[i] * ( ring == 0 ? 1 : 3); + s->plane[i].line = av_calloc(n, sizeof(*s->plane[i].line)); + if (!s->plane[i].line) + return AVERROR(ENOMEM); + + s->plane[i].tmp = ring ? s->plane[i].line + size[i] * 2 : NULL; + s->plane[i].available_lines = size[i]; + s->plane[i].sliceY = 0; + s->plane[i].sliceH = 0; + } + return 0; +} + +static void free_slice(SwsSlice *s) +{ + int i; + if (s) { + if (s->should_free_lines) + free_lines(s); + for (i = 0; i < 4; ++i) { + av_freep(&s->plane[i].line); + s->plane[i].tmp = NULL; + } + } +} + +int ff_rotate_slice(SwsSlice *s, int lum, int chr) +{ + int i; + if (lum) { + for (i = 0; i < 4; i+=3) { + int n = s->plane[i].available_lines; + int l = lum - s->plane[i].sliceY; + + if (l >= n * 2) { + s->plane[i].sliceY += n; + s->plane[i].sliceH -= n; + } + } + } + if (chr) { + for (i = 1; i < 3; ++i) { + int n = s->plane[i].available_lines; + int l = chr - s->plane[i].sliceY; + + if (l >= n * 2) { + s->plane[i].sliceY += n; + s->plane[i].sliceH -= n; + } + } + } + return 0; +} + +int ff_init_slice_from_src(SwsSlice * s, uint8_t *const src[4], const int stride[4], + int srcW, int lumY, int lumH, int chrY, int chrH, int relative) +{ + int i = 0; + + const int start[4] = {lumY, + chrY, + chrY, + lumY}; + + const int end[4] = {lumY +lumH, + chrY + chrH, + chrY + chrH, + lumY + lumH}; + + s->width = srcW; + + for (i = 0; i < 4 && src[i] != NULL; ++i) { + uint8_t *const src_i = src[i] + (relative ? 0 : start[i]) * stride[i]; + int j; + int first = s->plane[i].sliceY; + int n = s->plane[i].available_lines; + int lines = end[i] - start[i]; + int tot_lines = end[i] - first; + + if (start[i] >= first && n >= tot_lines) { + s->plane[i].sliceH = FFMAX(tot_lines, s->plane[i].sliceH); + for (j = 0; j < lines; j+= 1) + s->plane[i].line[start[i] - first + j] = src_i + j * stride[i]; + } else { + s->plane[i].sliceY = start[i]; + lines = lines > n ? n : lines; + s->plane[i].sliceH = lines; + for (j = 0; j < lines; j+= 1) + s->plane[i].line[j] = src_i + j * stride[i]; + } + + } + + return 0; +} + +static void fill_ones(SwsSlice *s, int n, int bpc) +{ + int i, j, k, size, end; + + for (i = 0; i < 4; ++i) { + size = s->plane[i].available_lines; + for (j = 0; j < size; ++j) { + if (bpc >= 16) { + end = (n>>1) + 1; + for (k = 0; k < end; ++k) + ((int32_t*)(s->plane[i].line[j]))[k] = 1<<18; + } else { + end = n + 1; + for (k = 0; k < end; ++k) + ((int16_t*)(s->plane[i].line[j]))[k] = 1<<14; + } + } + } +} + +/* + Calculates the minimum ring buffer size, it should be able to store vFilterSize + more n lines where n is the max difference between each adjacent slice which + outputs a line. + The n lines are needed only when there is not enough src lines to output a single + dst line, then we should buffer these lines to process them on the next call to scale. +*/ +static void get_min_buffer_size(SwsInternal *c, int *out_lum_size, int *out_chr_size) +{ + int lumY; + int dstH = c->opts.dst_h; + int chrDstH = c->chrDstH; + int *lumFilterPos = c->vLumFilterPos; + int *chrFilterPos = c->vChrFilterPos; + int lumFilterSize = c->vLumFilterSize; + int chrFilterSize = c->vChrFilterSize; + int chrSubSample = c->chrSrcVSubSample; + + *out_lum_size = lumFilterSize; + *out_chr_size = chrFilterSize; + + for (lumY = 0; lumY < dstH; lumY++) { + int chrY = (int64_t)lumY * chrDstH / dstH; + int nextSlice = FFMAX(lumFilterPos[lumY] + lumFilterSize - 1, + ((chrFilterPos[chrY] + chrFilterSize - 1) + << chrSubSample)); + + nextSlice >>= chrSubSample; + nextSlice <<= chrSubSample; + (*out_lum_size) = FFMAX((*out_lum_size), nextSlice - lumFilterPos[lumY]); + (*out_chr_size) = FFMAX((*out_chr_size), (nextSlice >> chrSubSample) - chrFilterPos[chrY]); + } +} + + + +int ff_init_filters(SwsInternal * c) +{ + int i; + int index; + int num_ydesc; + int num_cdesc; + int num_vdesc = isPlanarYUV(c->opts.dst_format) && !isGray(c->opts.dst_format) ? 2 : 1; + int need_lum_conv = c->lumToYV12 || c->readLumPlanar || c->alpToYV12 || c->readAlpPlanar; + int need_chr_conv = c->chrToYV12 || c->readChrPlanar; + int need_gamma = c->is_internal_gamma; + int srcIdx, dstIdx; + int dst_stride = FFALIGN(c->opts.dst_w * sizeof(int16_t) + 66, 16); + + uint32_t * pal = usePal(c->opts.src_format) ? c->pal_yuv : (uint32_t*)c->input_rgb2yuv_table; + int res = 0; + + int lumBufSize; + int chrBufSize; + + get_min_buffer_size(c, &lumBufSize, &chrBufSize); + lumBufSize = FFMAX(lumBufSize, c->vLumFilterSize + MAX_LINES_AHEAD); + chrBufSize = FFMAX(chrBufSize, c->vChrFilterSize + MAX_LINES_AHEAD); + + if (c->dstBpc == 16) + dst_stride <<= 1; + + if (c->dstBpc == 32) + dst_stride <<= 2; + + num_ydesc = need_lum_conv ? 2 : 1; + num_cdesc = need_chr_conv ? 2 : 1; + + c->numSlice = FFMAX(num_ydesc, num_cdesc) + 2; + c->numDesc = num_ydesc + num_cdesc + num_vdesc + (need_gamma ? 2 : 0); + c->descIndex[0] = num_ydesc + (need_gamma ? 1 : 0); + c->descIndex[1] = num_ydesc + num_cdesc + (need_gamma ? 1 : 0); + + if (isFloat16(c->opts.src_format)) { + c->h2f_tables = av_malloc(sizeof(*c->h2f_tables)); + if (!c->h2f_tables) + return AVERROR(ENOMEM); + ff_init_half2float_tables(c->h2f_tables); + c->input_opaque = c->h2f_tables; + } + + c->desc = av_calloc(c->numDesc, sizeof(*c->desc)); + if (!c->desc) + return AVERROR(ENOMEM); + c->slice = av_calloc(c->numSlice, sizeof(*c->slice)); + if (!c->slice) { + res = AVERROR(ENOMEM); + goto cleanup; + } + + res = alloc_slice(&c->slice[0], c->opts.src_format, c->opts.src_h, c->chrSrcH, c->chrSrcHSubSample, c->chrSrcVSubSample, 0); + if (res < 0) goto cleanup; + for (i = 1; i < c->numSlice-2; ++i) { + res = alloc_slice(&c->slice[i], c->opts.src_format, lumBufSize, chrBufSize, c->chrSrcHSubSample, c->chrSrcVSubSample, 0); + if (res < 0) goto cleanup; + res = alloc_lines(&c->slice[i], FFALIGN(c->opts.src_w*2+78, 16), c->opts.src_w); + if (res < 0) goto cleanup; + } + // horizontal scaler output + res = alloc_slice(&c->slice[i], c->opts.src_format, lumBufSize, chrBufSize, c->chrDstHSubSample, c->chrDstVSubSample, 1); + if (res < 0) goto cleanup; + res = alloc_lines(&c->slice[i], dst_stride, c->opts.dst_w); + if (res < 0) goto cleanup; + + fill_ones(&c->slice[i], dst_stride>>1, c->dstBpc); + + // vertical scaler output + ++i; + res = alloc_slice(&c->slice[i], c->opts.dst_format, c->opts.dst_h, c->chrDstH, c->chrDstHSubSample, c->chrDstVSubSample, 0); + if (res < 0) goto cleanup; + + index = 0; + srcIdx = 0; + dstIdx = 1; + + if (need_gamma) { + res = ff_init_gamma_convert(c->desc + index, c->slice + srcIdx, c->inv_gamma); + if (res < 0) goto cleanup; + ++index; + } + + if (need_lum_conv) { + res = ff_init_desc_fmt_convert(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], pal); + if (res < 0) goto cleanup; + c->desc[index].alpha = c->needAlpha; + ++index; + srcIdx = dstIdx; + } + + + dstIdx = FFMAX(num_ydesc, num_cdesc); + res = ff_init_desc_hscale(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], c->hLumFilter, c->hLumFilterPos, c->hLumFilterSize, c->lumXInc); + if (res < 0) goto cleanup; + c->desc[index].alpha = c->needAlpha; + + + ++index; + { + srcIdx = 0; + dstIdx = 1; + if (need_chr_conv) { + res = ff_init_desc_cfmt_convert(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], pal); + if (res < 0) goto cleanup; + ++index; + srcIdx = dstIdx; + } + + dstIdx = FFMAX(num_ydesc, num_cdesc); + if (c->needs_hcscale) + res = ff_init_desc_chscale(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx], c->hChrFilter, c->hChrFilterPos, c->hChrFilterSize, c->chrXInc); + else + res = ff_init_desc_no_chr(&c->desc[index], &c->slice[srcIdx], &c->slice[dstIdx]); + if (res < 0) goto cleanup; + } + + ++index; + { + srcIdx = c->numSlice - 2; + dstIdx = c->numSlice - 1; + res = ff_init_vscale(c, c->desc + index, c->slice + srcIdx, c->slice + dstIdx); + if (res < 0) goto cleanup; + } + + ++index; + if (need_gamma) { + res = ff_init_gamma_convert(c->desc + index, c->slice + dstIdx, c->gamma); + if (res < 0) goto cleanup; + } + + return 0; + +cleanup: + ff_free_filters(c); + return res; +} + +int ff_free_filters(SwsInternal *c) +{ + int i; + if (c->desc) { + for (i = 0; i < c->numDesc; ++i) + av_freep(&c->desc[i].instance); + av_freep(&c->desc); + } + + if (c->slice) { + for (i = 0; i < c->numSlice; ++i) + free_slice(&c->slice[i]); + av_freep(&c->slice); + } + av_freep(&c->h2f_tables); + return 0; +} diff --git a/libs/ffmpeg/libswscale/swscale.c b/libs/ffmpeg/libswscale/swscale.c new file mode 100644 index 00000000000..cd4ef9676bb --- /dev/null +++ b/libs/ffmpeg/libswscale/swscale.c @@ -0,0 +1,1572 @@ +/* + * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include "libavutil/avassert.h" +#include "libavutil/bswap.h" +#include "libavutil/common.h" +#include "libavutil/cpu.h" +#include "libavutil/emms.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" +#include "libavutil/mem_internal.h" +#include "libavutil/pixdesc.h" +#include "libavutil/hwcontext.h" +#include "config.h" +#include "swscale_internal.h" +#include "swscale.h" +#if CONFIG_VULKAN +#include "vulkan/ops.h" +#endif + +DECLARE_ALIGNED(8, const uint8_t, ff_dither_8x8_128)[9][8] = { + { 36, 68, 60, 92, 34, 66, 58, 90, }, + { 100, 4, 124, 28, 98, 2, 122, 26, }, + { 52, 84, 44, 76, 50, 82, 42, 74, }, + { 116, 20, 108, 12, 114, 18, 106, 10, }, + { 32, 64, 56, 88, 38, 70, 62, 94, }, + { 96, 0, 120, 24, 102, 6, 126, 30, }, + { 48, 80, 40, 72, 54, 86, 46, 78, }, + { 112, 16, 104, 8, 118, 22, 110, 14, }, + { 36, 68, 60, 92, 34, 66, 58, 90, }, +}; + +DECLARE_ALIGNED(8, static const uint8_t, sws_pb_64)[8] = { + 64, 64, 64, 64, 64, 64, 64, 64 +}; + +static av_always_inline void fillPlane(uint8_t *plane, int stride, int width, + int height, int y, uint8_t val) +{ + int i; + uint8_t *ptr = plane + stride * y; + for (i = 0; i < height; i++) { + memset(ptr, val, width); + ptr += stride; + } +} + +static void hScale16To19_c(SwsInternal *c, int16_t *_dst, int dstW, + const uint8_t *_src, const int16_t *filter, + const int32_t *filterPos, int filterSize) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format); + int i; + int32_t *dst = (int32_t *) _dst; + const uint16_t *src = (const uint16_t *) _src; + int bits = desc->comp[0].depth - 1; + int sh = bits - 4; + + if ((isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8) && desc->comp[0].depth<16) { + sh = 9; + } else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */ + sh = 16 - 1 - 4; + } + + for (i = 0; i < dstW; i++) { + int j; + int srcPos = filterPos[i]; + int val = 0; + + for (j = 0; j < filterSize; j++) { + val += src[srcPos + j] * filter[filterSize * i + j]; + } + // filter=14 bit, input=16 bit, output=30 bit, >> 11 makes 19 bit + dst[i] = FFMIN(val >> sh, (1 << 19) - 1); + } +} + +static void hScale16To15_c(SwsInternal *c, int16_t *dst, int dstW, + const uint8_t *_src, const int16_t *filter, + const int32_t *filterPos, int filterSize) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format); + int i; + const uint16_t *src = (const uint16_t *) _src; + int sh = desc->comp[0].depth - 1; + + if (sh<15) { + sh = isAnyRGB(c->opts.src_format) || c->opts.src_format==AV_PIX_FMT_PAL8 ? 13 : (desc->comp[0].depth - 1); + } else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */ + sh = 16 - 1; + } + + for (i = 0; i < dstW; i++) { + int j; + int srcPos = filterPos[i]; + int val = 0; + + for (j = 0; j < filterSize; j++) { + val += src[srcPos + j] * filter[filterSize * i + j]; + } + // filter=14 bit, input=16 bit, output=30 bit, >> 15 makes 15 bit + dst[i] = FFMIN(val >> sh, (1 << 15) - 1); + } +} + +// bilinear / bicubic scaling +static void hScale8To15_c(SwsInternal *c, int16_t *dst, int dstW, + const uint8_t *src, const int16_t *filter, + const int32_t *filterPos, int filterSize) +{ + int i; + for (i = 0; i < dstW; i++) { + int j; + int srcPos = filterPos[i]; + int val = 0; + for (j = 0; j < filterSize; j++) { + val += ((int)src[srcPos + j]) * filter[filterSize * i + j]; + } + dst[i] = FFMIN(val >> 7, (1 << 15) - 1); // the cubic equation does overflow ... + } +} + +static void hScale8To19_c(SwsInternal *c, int16_t *_dst, int dstW, + const uint8_t *src, const int16_t *filter, + const int32_t *filterPos, int filterSize) +{ + int i; + int32_t *dst = (int32_t *) _dst; + for (i = 0; i < dstW; i++) { + int j; + int srcPos = filterPos[i]; + int val = 0; + for (j = 0; j < filterSize; j++) { + val += ((int)src[srcPos + j]) * filter[filterSize * i + j]; + } + dst[i] = FFMIN(val >> 3, (1 << 19) - 1); // the cubic equation does overflow ... + } +} + +// FIXME all pal and rgb srcFormats could do this conversion as well +// FIXME all scalers more complex than bilinear could do half of this transform +static void chrRangeToJpeg_c(int16_t *dstU, int16_t *dstV, int width, + uint32_t _coeff, int64_t _offset) +{ + uint16_t coeff = _coeff; + int32_t offset = _offset; + int i; + for (i = 0; i < width; i++) { + int U = (dstU[i] * coeff + offset) >> 14; + int V = (dstV[i] * coeff + offset) >> 14; + dstU[i] = FFMIN(U, (1 << 15) - 1); + dstV[i] = FFMIN(V, (1 << 15) - 1); + } +} + +static void chrRangeFromJpeg_c(int16_t *dstU, int16_t *dstV, int width, + uint32_t _coeff, int64_t _offset) +{ + uint16_t coeff = _coeff; + int32_t offset = _offset; + int i; + for (i = 0; i < width; i++) { + dstU[i] = (dstU[i] * coeff + offset) >> 14; + dstV[i] = (dstV[i] * coeff + offset) >> 14; + } +} + +static void lumRangeToJpeg_c(int16_t *dst, int width, + uint32_t _coeff, int64_t _offset) +{ + uint16_t coeff = _coeff; + int32_t offset = _offset; + int i; + for (i = 0; i < width; i++) { + int Y = (dst[i] * coeff + offset) >> 14; + dst[i] = FFMIN(Y, (1 << 15) - 1); + } +} + +static void lumRangeFromJpeg_c(int16_t *dst, int width, + uint32_t _coeff, int64_t _offset) +{ + uint16_t coeff = _coeff; + int32_t offset = _offset; + int i; + for (i = 0; i < width; i++) + dst[i] = (dst[i] * coeff + offset) >> 14; +} + +static void chrRangeToJpeg16_c(int16_t *_dstU, int16_t *_dstV, int width, + uint32_t coeff, int64_t offset) +{ + int i; + int32_t *dstU = (int32_t *) _dstU; + int32_t *dstV = (int32_t *) _dstV; + for (i = 0; i < width; i++) { + int U = ((int64_t) dstU[i] * coeff + offset) >> 18; + int V = ((int64_t) dstV[i] * coeff + offset) >> 18; + dstU[i] = FFMIN(U, (1 << 19) - 1); + dstV[i] = FFMIN(V, (1 << 19) - 1); + } +} + +static void chrRangeFromJpeg16_c(int16_t *_dstU, int16_t *_dstV, int width, + uint32_t coeff, int64_t offset) +{ + int i; + int32_t *dstU = (int32_t *) _dstU; + int32_t *dstV = (int32_t *) _dstV; + for (i = 0; i < width; i++) { + dstU[i] = ((int64_t) dstU[i] * coeff + offset) >> 18; + dstV[i] = ((int64_t) dstV[i] * coeff + offset) >> 18; + } +} + +static void lumRangeToJpeg16_c(int16_t *_dst, int width, + uint32_t coeff, int64_t offset) +{ + int i; + int32_t *dst = (int32_t *) _dst; + for (i = 0; i < width; i++) { + int Y = ((int64_t) dst[i] * coeff + offset) >> 18; + dst[i] = FFMIN(Y, (1 << 19) - 1); + } +} + +static void lumRangeFromJpeg16_c(int16_t *_dst, int width, + uint32_t coeff, int64_t offset) +{ + int i; + int32_t *dst = (int32_t *) _dst; + for (i = 0; i < width; i++) + dst[i] = ((int64_t) dst[i] * coeff + offset) >> 18; +} + + +#define DEBUG_SWSCALE_BUFFERS 0 +#define DEBUG_BUFFERS(...) \ + if (DEBUG_SWSCALE_BUFFERS) \ + av_log(c, AV_LOG_DEBUG, __VA_ARGS__) + +int ff_swscale(SwsInternal *c, const uint8_t *const src[], const int srcStride[], + int srcSliceY, int srcSliceH, uint8_t *const dst[], + const int dstStride[], int dstSliceY, int dstSliceH) +{ + const int scale_dst = dstSliceY > 0 || dstSliceH < c->opts.dst_h; + + /* load a few things into local vars to make the code more readable? + * and faster */ + const int dstW = c->opts.dst_w; + int dstH = c->opts.dst_h; + + const enum AVPixelFormat dstFormat = c->opts.dst_format; + const int flags = c->opts.flags; + int32_t *vLumFilterPos = c->vLumFilterPos; + int32_t *vChrFilterPos = c->vChrFilterPos; + + const int vLumFilterSize = c->vLumFilterSize; + const int vChrFilterSize = c->vChrFilterSize; + + yuv2planar1_fn yuv2plane1 = c->yuv2plane1; + yuv2planarX_fn yuv2planeX = c->yuv2planeX; + yuv2interleavedX_fn yuv2nv12cX = c->yuv2nv12cX; + yuv2packed1_fn yuv2packed1 = c->yuv2packed1; + yuv2packed2_fn yuv2packed2 = c->yuv2packed2; + yuv2packedX_fn yuv2packedX = c->yuv2packedX; + yuv2anyX_fn yuv2anyX = c->yuv2anyX; + const int chrSrcSliceY = srcSliceY >> c->chrSrcVSubSample; + const int chrSrcSliceH = AV_CEIL_RSHIFT(srcSliceH, c->chrSrcVSubSample); + int should_dither = isNBPS(c->opts.src_format) || + is16BPS(c->opts.src_format); + int lastDstY; + + /* vars which will change and which we need to store back in the context */ + int dstY = c->dstY; + int lastInLumBuf = c->lastInLumBuf; + int lastInChrBuf = c->lastInChrBuf; + + int lumStart = 0; + int lumEnd = c->descIndex[0]; + int chrStart = lumEnd; + int chrEnd = c->descIndex[1]; + int vStart = chrEnd; + int vEnd = c->numDesc; + SwsSlice *src_slice = &c->slice[lumStart]; + SwsSlice *hout_slice = &c->slice[c->numSlice-2]; + SwsSlice *vout_slice = &c->slice[c->numSlice-1]; + SwsFilterDescriptor *desc = c->desc; + + int needAlpha = c->needAlpha; + + int hasLumHoles = 1; + int hasChrHoles = 1; + + const uint8_t *src2[4]; + int srcStride2[4]; + + if (isPacked(c->opts.src_format)) { + src2[0] = + src2[1] = + src2[2] = + src2[3] = src[0]; + srcStride2[0] = + srcStride2[1] = + srcStride2[2] = + srcStride2[3] = srcStride[0]; + } else { + memcpy(src2, src, sizeof(src2)); + memcpy(srcStride2, srcStride, sizeof(srcStride2)); + } + + srcStride2[1] *= 1 << c->vChrDrop; + srcStride2[2] *= 1 << c->vChrDrop; + + DEBUG_BUFFERS("swscale() %p[%d] %p[%d] %p[%d] %p[%d] -> %p[%d] %p[%d] %p[%d] %p[%d]\n", + src2[0], srcStride2[0], src2[1], srcStride2[1], + src2[2], srcStride2[2], src2[3], srcStride2[3], + dst[0], dstStride[0], dst[1], dstStride[1], + dst[2], dstStride[2], dst[3], dstStride[3]); + DEBUG_BUFFERS("srcSliceY: %d srcSliceH: %d dstY: %d dstH: %d\n", + srcSliceY, srcSliceH, dstY, dstH); + DEBUG_BUFFERS("vLumFilterSize: %d vChrFilterSize: %d\n", + vLumFilterSize, vChrFilterSize); + + if (dstStride[0]&15 || dstStride[1]&15 || + dstStride[2]&15 || dstStride[3]&15) { + SwsInternal *const ctx = c->parent ? sws_internal(c->parent) : c; + if (flags & SWS_PRINT_INFO && + !atomic_exchange_explicit(&ctx->stride_unaligned_warned, 1, memory_order_relaxed)) { + av_log(c, AV_LOG_WARNING, + "Warning: dstStride is not aligned!\n" + " ->cannot do aligned memory accesses anymore\n"); + } + } + +#if ARCH_X86 + if ( (uintptr_t) dst[0]&15 || (uintptr_t) dst[1]&15 || (uintptr_t) dst[2]&15 + || (uintptr_t)src2[0]&15 || (uintptr_t)src2[1]&15 || (uintptr_t)src2[2]&15 + || dstStride[0]&15 || dstStride[1]&15 || dstStride[2]&15 || dstStride[3]&15 + || srcStride2[0]&15 || srcStride2[1]&15 || srcStride2[2]&15 || srcStride2[3]&15 + ) { + SwsInternal *const ctx = c->parent ? sws_internal(c->parent) : c; + int cpu_flags = av_get_cpu_flags(); + if (flags & SWS_PRINT_INFO && HAVE_MMXEXT && (cpu_flags & AV_CPU_FLAG_SSE2) && + !atomic_exchange_explicit(&ctx->stride_unaligned_warned,1, memory_order_relaxed)) { + av_log(c, AV_LOG_WARNING, "Warning: data is not aligned! This can lead to a speed loss\n"); + } + } +#endif + + if (scale_dst) { + dstY = dstSliceY; + dstH = dstY + dstSliceH; + lastInLumBuf = -1; + lastInChrBuf = -1; + } else if (srcSliceY == 0) { + /* Note the user might start scaling the picture in the middle so this + * will not get executed. This is not really intended but works + * currently, so people might do it. */ + dstY = 0; + lastInLumBuf = -1; + lastInChrBuf = -1; + } + + if (!should_dither) { + c->chrDither8 = c->lumDither8 = sws_pb_64; + } + lastDstY = dstY; + + ff_init_vscale_pfn(c, yuv2plane1, yuv2planeX, yuv2nv12cX, + yuv2packed1, yuv2packed2, yuv2packedX, yuv2anyX, c->use_mmx_vfilter); + + ff_init_slice_from_src(src_slice, (uint8_t**)src2, srcStride2, c->opts.src_w, + srcSliceY, srcSliceH, chrSrcSliceY, chrSrcSliceH, 1); + + ff_init_slice_from_src(vout_slice, (uint8_t**)dst, dstStride, c->opts.dst_w, + dstY, dstSliceH, dstY >> c->chrDstVSubSample, + AV_CEIL_RSHIFT(dstSliceH, c->chrDstVSubSample), scale_dst); + if (srcSliceY == 0) { + hout_slice->plane[0].sliceY = lastInLumBuf + 1; + hout_slice->plane[1].sliceY = lastInChrBuf + 1; + hout_slice->plane[2].sliceY = lastInChrBuf + 1; + hout_slice->plane[3].sliceY = lastInLumBuf + 1; + + hout_slice->plane[0].sliceH = + hout_slice->plane[1].sliceH = + hout_slice->plane[2].sliceH = + hout_slice->plane[3].sliceH = 0; + hout_slice->width = dstW; + } + + for (; dstY < dstH; dstY++) { + const int chrDstY = dstY >> c->chrDstVSubSample; + int use_mmx_vfilter= c->use_mmx_vfilter; + + // First line needed as input + const int firstLumSrcY = FFMAX(1 - vLumFilterSize, vLumFilterPos[dstY]); + const int firstLumSrcY2 = FFMAX(1 - vLumFilterSize, vLumFilterPos[FFMIN(dstY | ((1 << c->chrDstVSubSample) - 1), c->opts.dst_h - 1)]); + // First line needed as input + const int firstChrSrcY = FFMAX(1 - vChrFilterSize, vChrFilterPos[chrDstY]); + + // Last line needed as input + int lastLumSrcY = FFMIN(c->opts.src_h, firstLumSrcY + vLumFilterSize) - 1; + int lastLumSrcY2 = FFMIN(c->opts.src_h, firstLumSrcY2 + vLumFilterSize) - 1; + int lastChrSrcY = FFMIN(c->chrSrcH, firstChrSrcY + vChrFilterSize) - 1; + int enough_lines; + + int i; + int posY, cPosY, firstPosY, lastPosY, firstCPosY, lastCPosY; + + // handle holes (FAST_BILINEAR & weird filters) + if (firstLumSrcY > lastInLumBuf) { + + hasLumHoles = lastInLumBuf != firstLumSrcY - 1; + if (hasLumHoles) { + hout_slice->plane[0].sliceY = firstLumSrcY; + hout_slice->plane[3].sliceY = firstLumSrcY; + hout_slice->plane[0].sliceH = + hout_slice->plane[3].sliceH = 0; + } + + lastInLumBuf = firstLumSrcY - 1; + } + if (firstChrSrcY > lastInChrBuf) { + + hasChrHoles = lastInChrBuf != firstChrSrcY - 1; + if (hasChrHoles) { + hout_slice->plane[1].sliceY = firstChrSrcY; + hout_slice->plane[2].sliceY = firstChrSrcY; + hout_slice->plane[1].sliceH = + hout_slice->plane[2].sliceH = 0; + } + + lastInChrBuf = firstChrSrcY - 1; + } + + DEBUG_BUFFERS("dstY: %d\n", dstY); + DEBUG_BUFFERS("\tfirstLumSrcY: %d lastLumSrcY: %d lastInLumBuf: %d\n", + firstLumSrcY, lastLumSrcY, lastInLumBuf); + DEBUG_BUFFERS("\tfirstChrSrcY: %d lastChrSrcY: %d lastInChrBuf: %d\n", + firstChrSrcY, lastChrSrcY, lastInChrBuf); + + // Do we have enough lines in this slice to output the dstY line + enough_lines = lastLumSrcY2 < srcSliceY + srcSliceH && + lastChrSrcY < AV_CEIL_RSHIFT(srcSliceY + srcSliceH, c->chrSrcVSubSample); + + if (!enough_lines) { + lastLumSrcY = srcSliceY + srcSliceH - 1; + lastChrSrcY = chrSrcSliceY + chrSrcSliceH - 1; + DEBUG_BUFFERS("buffering slice: lastLumSrcY %d lastChrSrcY %d\n", + lastLumSrcY, lastChrSrcY); + } + + av_assert0((lastLumSrcY - firstLumSrcY + 1) <= hout_slice->plane[0].available_lines); + av_assert0((lastChrSrcY - firstChrSrcY + 1) <= hout_slice->plane[1].available_lines); + + + posY = hout_slice->plane[0].sliceY + hout_slice->plane[0].sliceH; + if (posY <= lastLumSrcY && !hasLumHoles) { + firstPosY = FFMAX(firstLumSrcY, posY); + lastPosY = FFMIN(firstLumSrcY + hout_slice->plane[0].available_lines - 1, srcSliceY + srcSliceH - 1); + } else { + firstPosY = posY; + lastPosY = lastLumSrcY; + } + + cPosY = hout_slice->plane[1].sliceY + hout_slice->plane[1].sliceH; + if (cPosY <= lastChrSrcY && !hasChrHoles) { + firstCPosY = FFMAX(firstChrSrcY, cPosY); + lastCPosY = FFMIN(firstChrSrcY + hout_slice->plane[1].available_lines - 1, AV_CEIL_RSHIFT(srcSliceY + srcSliceH, c->chrSrcVSubSample) - 1); + } else { + firstCPosY = cPosY; + lastCPosY = lastChrSrcY; + } + + ff_rotate_slice(hout_slice, lastPosY, lastCPosY); + + if (posY < lastLumSrcY + 1) { + for (i = lumStart; i < lumEnd; ++i) + desc[i].process(c, &desc[i], firstPosY, lastPosY - firstPosY + 1); + } + + lastInLumBuf = lastLumSrcY; + + if (cPosY < lastChrSrcY + 1) { + for (i = chrStart; i < chrEnd; ++i) + desc[i].process(c, &desc[i], firstCPosY, lastCPosY - firstCPosY + 1); + } + + lastInChrBuf = lastChrSrcY; + + if (!enough_lines) + break; // we can't output a dstY line so let's try with the next slice + +#if HAVE_MMX_INLINE + ff_updateMMXDitherTables(c, dstY); + c->dstW_mmx = c->opts.dst_w; +#endif + if (should_dither) { + c->chrDither8 = ff_dither_8x8_128[chrDstY & 7]; + c->lumDither8 = ff_dither_8x8_128[dstY & 7]; + } + if (dstY >= c->opts.dst_h - 2) { + /* hmm looks like we can't use MMX here without overwriting + * this array's tail */ + ff_sws_init_output_funcs(c, &yuv2plane1, &yuv2planeX, &yuv2nv12cX, + &yuv2packed1, &yuv2packed2, &yuv2packedX, &yuv2anyX); + use_mmx_vfilter= 0; + ff_init_vscale_pfn(c, yuv2plane1, yuv2planeX, yuv2nv12cX, + yuv2packed1, yuv2packed2, yuv2packedX, yuv2anyX, use_mmx_vfilter); + } + + for (i = vStart; i < vEnd; ++i) + desc[i].process(c, &desc[i], dstY, 1); + } + if (isPlanar(dstFormat) && isALPHA(dstFormat) && !needAlpha) { + int offset = lastDstY - dstSliceY; + int length = dstW; + int height = dstY - lastDstY; + + if (is16BPS(dstFormat) || isNBPS(dstFormat)) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(dstFormat); + fillPlane16(dst[3], dstStride[3], length, height, offset, + 1, desc->comp[3].depth, + isBE(dstFormat)); + } else if (is32BPS(dstFormat)) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(dstFormat); + fillPlane32(dst[3], dstStride[3], length, height, offset, + 1, desc->comp[3].depth, + isBE(dstFormat), desc->flags & AV_PIX_FMT_FLAG_FLOAT); + } else + fillPlane(dst[3], dstStride[3], length, height, offset, 255); + } + +#if HAVE_MMXEXT_INLINE + if (av_get_cpu_flags() & AV_CPU_FLAG_MMXEXT) + __asm__ volatile ("sfence" ::: "memory"); +#endif + emms_c(); + + /* store changed local vars back in the context */ + c->dstY = dstY; + c->lastInLumBuf = lastInLumBuf; + c->lastInChrBuf = lastInChrBuf; + + return dstY - lastDstY; +} + +/* + * Solve for coeff and offset: + * dst = ((src << src_shift) * coeff + offset) >> (mult_shift + src_shift) + * + * If SwsInternal->dstBpc is > 14, coeff is uint16_t and offset is int32_t, + * otherwise (SwsInternal->dstBpc is <= 14) coeff is uint32_t and offset is + * int64_t. + */ +static void solve_range_convert(uint16_t src_min, uint16_t src_max, + uint16_t dst_min, uint16_t dst_max, + int src_bits, int src_shift, int mult_shift, + uint32_t *coeff, int64_t *offset) +{ + uint16_t src_range = src_max - src_min; + uint16_t dst_range = dst_max - dst_min; + int total_shift = mult_shift + src_shift; + *coeff = AV_CEIL_RSHIFT(((uint64_t) dst_range << total_shift) / src_range, src_shift); + *offset = ((int64_t) dst_max << total_shift) - + ((int64_t) src_max << src_shift) * *coeff + + (1U << (mult_shift - 1)); +} + +static void init_range_convert_constants(SwsInternal *c) +{ + const int bit_depth = c->dstBpc ? FFMIN(c->dstBpc, 16) : 8; + const int src_bits = bit_depth <= 14 ? 15 : 19; + const int src_shift = src_bits - bit_depth; + const int mult_shift = bit_depth <= 14 ? 14 : 18; + const uint16_t mpeg_min = 16U << (bit_depth - 8); + const uint16_t mpeg_max_lum = 235U << (bit_depth - 8); + const uint16_t mpeg_max_chr = 240U << (bit_depth - 8); + const uint16_t jpeg_max = (1U << bit_depth) - 1; + uint16_t src_min, src_max_lum, src_max_chr; + uint16_t dst_min, dst_max_lum, dst_max_chr; + if (c->opts.src_range) { + src_min = 0; + src_max_lum = jpeg_max; + src_max_chr = jpeg_max; + dst_min = mpeg_min; + dst_max_lum = mpeg_max_lum; + dst_max_chr = mpeg_max_chr; + } else { + src_min = mpeg_min; + src_max_lum = mpeg_max_lum; + src_max_chr = mpeg_max_chr; + dst_min = 0; + dst_max_lum = jpeg_max; + dst_max_chr = jpeg_max; + } + solve_range_convert(src_min, src_max_lum, dst_min, dst_max_lum, + src_bits, src_shift, mult_shift, + &c->lumConvertRange_coeff, &c->lumConvertRange_offset); + solve_range_convert(src_min, src_max_chr, dst_min, dst_max_chr, + src_bits, src_shift, mult_shift, + &c->chrConvertRange_coeff, &c->chrConvertRange_offset); +} + +av_cold void ff_sws_init_range_convert(SwsInternal *c) +{ + c->lumConvertRange = NULL; + c->chrConvertRange = NULL; + if (c->opts.src_range != c->opts.dst_range && !isAnyRGB(c->opts.dst_format) && c->dstBpc < 32) { + init_range_convert_constants(c); + if (c->dstBpc <= 14) { + if (c->opts.src_range) { + c->lumConvertRange = lumRangeFromJpeg_c; + c->chrConvertRange = chrRangeFromJpeg_c; + } else { + c->lumConvertRange = lumRangeToJpeg_c; + c->chrConvertRange = chrRangeToJpeg_c; + } + } else { + if (c->opts.src_range) { + c->lumConvertRange = lumRangeFromJpeg16_c; + c->chrConvertRange = chrRangeFromJpeg16_c; + } else { + c->lumConvertRange = lumRangeToJpeg16_c; + c->chrConvertRange = chrRangeToJpeg16_c; + } + } + +#if ARCH_AARCH64 + ff_sws_init_range_convert_aarch64(c); +#elif ARCH_LOONGARCH64 + ff_sws_init_range_convert_loongarch(c); +#elif ARCH_RISCV + ff_sws_init_range_convert_riscv(c); +#elif ARCH_X86 + ff_sws_init_range_convert_x86(c); +#endif + } +} + +static av_cold void sws_init_swscale(SwsInternal *c) +{ + enum AVPixelFormat srcFormat = c->opts.src_format; + + ff_sws_init_xyzdsp(c); + + ff_sws_init_output_funcs(c, &c->yuv2plane1, &c->yuv2planeX, + &c->yuv2nv12cX, &c->yuv2packed1, + &c->yuv2packed2, &c->yuv2packedX, &c->yuv2anyX); + + ff_sws_init_input_funcs(c, &c->lumToYV12, &c->alpToYV12, &c->chrToYV12, + &c->readLumPlanar, &c->readAlpPlanar, &c->readChrPlanar); + + if (c->srcBpc == 8) { + if (c->dstBpc <= 14) { + c->hyScale = c->hcScale = hScale8To15_c; + if (c->opts.flags & SWS_FAST_BILINEAR) { + c->hyscale_fast = ff_hyscale_fast_c; + c->hcscale_fast = ff_hcscale_fast_c; + } + } else { + c->hyScale = c->hcScale = hScale8To19_c; + } + } else { + c->hyScale = c->hcScale = c->dstBpc > 14 ? hScale16To19_c + : hScale16To15_c; + } + + ff_sws_init_range_convert(c); + + if (!(isGray(srcFormat) || isGray(c->opts.dst_format) || + srcFormat == AV_PIX_FMT_MONOBLACK || srcFormat == AV_PIX_FMT_MONOWHITE)) + c->needs_hcscale = 1; +} + +void ff_sws_init_scale(SwsInternal *c) +{ + sws_init_swscale(c); + +#if ARCH_PPC + ff_sws_init_swscale_ppc(c); +#elif ARCH_X86 + ff_sws_init_swscale_x86(c); +#elif ARCH_AARCH64 + ff_sws_init_swscale_aarch64(c); +#elif ARCH_ARM + ff_sws_init_swscale_arm(c); +#elif ARCH_LOONGARCH64 + ff_sws_init_swscale_loongarch(c); +#elif ARCH_RISCV + ff_sws_init_swscale_riscv(c); +#endif +} + +static void reset_ptr(const uint8_t *src[], enum AVPixelFormat format) +{ + if (!isALPHA(format)) + src[3] = NULL; + if (!isPlanar(format)) { + src[3] = src[2] = NULL; + + if (!usePal(format)) + src[1] = NULL; + } +} + +static int check_image_pointers(const uint8_t * const data[4], enum AVPixelFormat pix_fmt, + const int linesizes[4]) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + int i; + + av_assert2(desc); + + for (i = 0; i < 4; i++) { + int plane = desc->comp[i].plane; + if (!data[plane] || !linesizes[plane]) + return 0; + } + + return 1; +} + +static void xyz12Torgb48_c(const SwsInternal *c, uint8_t *dst, int dst_stride, + const uint8_t *src, int src_stride, int w, int h) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.src_format); + + for (int yp = 0; yp < h; yp++) { + const uint16_t *src16 = (const uint16_t *) src; + uint16_t *dst16 = (uint16_t *) dst; + + for (int xp = 0; xp < 3 * w; xp += 3) { + int x, y, z, r, g, b; + + if (desc->flags & AV_PIX_FMT_FLAG_BE) { + x = AV_RB16(src16 + xp + 0); + y = AV_RB16(src16 + xp + 1); + z = AV_RB16(src16 + xp + 2); + } else { + x = AV_RL16(src16 + xp + 0); + y = AV_RL16(src16 + xp + 1); + z = AV_RL16(src16 + xp + 2); + } + + x = c->xyz2rgb.gamma.in[x >> 4]; + y = c->xyz2rgb.gamma.in[y >> 4]; + z = c->xyz2rgb.gamma.in[z >> 4]; + + // convert from XYZlinear to sRGBlinear + r = c->xyz2rgb.mat[0][0] * x + + c->xyz2rgb.mat[0][1] * y + + c->xyz2rgb.mat[0][2] * z >> 12; + g = c->xyz2rgb.mat[1][0] * x + + c->xyz2rgb.mat[1][1] * y + + c->xyz2rgb.mat[1][2] * z >> 12; + b = c->xyz2rgb.mat[2][0] * x + + c->xyz2rgb.mat[2][1] * y + + c->xyz2rgb.mat[2][2] * z >> 12; + + // limit values to 16-bit depth + r = av_clip_uint16(r); + g = av_clip_uint16(g); + b = av_clip_uint16(b); + + // convert from sRGBlinear to RGB and scale from 12bit to 16bit + if (desc->flags & AV_PIX_FMT_FLAG_BE) { + AV_WB16(dst16 + xp + 0, c->xyz2rgb.gamma.out[r] << 4); + AV_WB16(dst16 + xp + 1, c->xyz2rgb.gamma.out[g] << 4); + AV_WB16(dst16 + xp + 2, c->xyz2rgb.gamma.out[b] << 4); + } else { + AV_WL16(dst16 + xp + 0, c->xyz2rgb.gamma.out[r] << 4); + AV_WL16(dst16 + xp + 1, c->xyz2rgb.gamma.out[g] << 4); + AV_WL16(dst16 + xp + 2, c->xyz2rgb.gamma.out[b] << 4); + } + } + + src += src_stride; + dst += dst_stride; + } +} + +static void rgb48Toxyz12_c(const SwsInternal *c, uint8_t *dst, int dst_stride, + const uint8_t *src, int src_stride, int w, int h) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->opts.dst_format); + + for (int yp = 0; yp < h; yp++) { + uint16_t *src16 = (uint16_t *) src; + uint16_t *dst16 = (uint16_t *) dst; + + for (int xp = 0; xp < 3 * w; xp += 3) { + int x, y, z, r, g, b; + + if (desc->flags & AV_PIX_FMT_FLAG_BE) { + r = AV_RB16(src16 + xp + 0); + g = AV_RB16(src16 + xp + 1); + b = AV_RB16(src16 + xp + 2); + } else { + r = AV_RL16(src16 + xp + 0); + g = AV_RL16(src16 + xp + 1); + b = AV_RL16(src16 + xp + 2); + } + + r = c->rgb2xyz.gamma.in[r >> 4]; + g = c->rgb2xyz.gamma.in[g >> 4]; + b = c->rgb2xyz.gamma.in[b >> 4]; + + // convert from sRGBlinear to XYZlinear + x = c->rgb2xyz.mat[0][0] * r + + c->rgb2xyz.mat[0][1] * g + + c->rgb2xyz.mat[0][2] * b >> 12; + y = c->rgb2xyz.mat[1][0] * r + + c->rgb2xyz.mat[1][1] * g + + c->rgb2xyz.mat[1][2] * b >> 12; + z = c->rgb2xyz.mat[2][0] * r + + c->rgb2xyz.mat[2][1] * g + + c->rgb2xyz.mat[2][2] * b >> 12; + + // limit values to 16-bit depth + x = av_clip_uint16(x); + y = av_clip_uint16(y); + z = av_clip_uint16(z); + + // convert from XYZlinear to X'Y'Z' and scale from 12bit to 16bit + if (desc->flags & AV_PIX_FMT_FLAG_BE) { + AV_WB16(dst16 + xp + 0, c->rgb2xyz.gamma.out[x] << 4); + AV_WB16(dst16 + xp + 1, c->rgb2xyz.gamma.out[y] << 4); + AV_WB16(dst16 + xp + 2, c->rgb2xyz.gamma.out[z] << 4); + } else { + AV_WL16(dst16 + xp + 0, c->rgb2xyz.gamma.out[x] << 4); + AV_WL16(dst16 + xp + 1, c->rgb2xyz.gamma.out[y] << 4); + AV_WL16(dst16 + xp + 2, c->rgb2xyz.gamma.out[z] << 4); + } + } + + src += src_stride; + dst += dst_stride; + } +} + +av_cold void ff_sws_init_xyzdsp(SwsInternal *c) +{ + c->xyz12Torgb48 = xyz12Torgb48_c; + c->rgb48Toxyz12 = rgb48Toxyz12_c; + +#if ARCH_AARCH64 + ff_sws_init_xyzdsp_aarch64(c); +#endif +} + +void ff_update_palette(SwsInternal *c, const uint32_t *pal) +{ + uint32_t *rgb2yuv = c->input_rgb2yuv_table; + + int32_t ry = rgb2yuv[RY_IDX], gy = rgb2yuv[GY_IDX], by = rgb2yuv[BY_IDX]; + int32_t ru = rgb2yuv[RU_IDX], gu = rgb2yuv[GU_IDX], bu = rgb2yuv[BU_IDX]; + int32_t rv = rgb2yuv[RV_IDX], gv = rgb2yuv[GV_IDX], bv = rgb2yuv[BV_IDX]; + + for (int i = 0; i < 256; i++) { + int r, g, b, y, u, v, a = 0xff; + if (c->opts.src_format == AV_PIX_FMT_PAL8) { + uint32_t p = pal[i]; + a = (p >> 24) & 0xFF; + r = (p >> 16) & 0xFF; + g = (p >> 8) & 0xFF; + b = p & 0xFF; + } else if (c->opts.src_format == AV_PIX_FMT_RGB8) { + r = ( i >> 5 ) * 36; + g = ((i >> 2) & 7) * 36; + b = ( i & 3) * 85; + } else if (c->opts.src_format == AV_PIX_FMT_BGR8) { + b = ( i >> 6 ) * 85; + g = ((i >> 3) & 7) * 36; + r = ( i & 7) * 36; + } else if (c->opts.src_format == AV_PIX_FMT_RGB4_BYTE) { + r = ( i >> 3 ) * 255; + g = ((i >> 1) & 3) * 85; + b = ( i & 1) * 255; + } else if (c->opts.src_format == AV_PIX_FMT_GRAY8 || c->opts.src_format == AV_PIX_FMT_GRAY8A) { + r = g = b = i; + } else { + av_assert1(c->opts.src_format == AV_PIX_FMT_BGR4_BYTE); + b = ( i >> 3 ) * 255; + g = ((i >> 1) & 3) * 85; + r = ( i & 1) * 255; + } + + y = av_clip_uint8((ry * r + gy * g + by * b + ( 33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT); + u = av_clip_uint8((ru * r + gu * g + bu * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT); + v = av_clip_uint8((rv * r + gv * g + bv * b + (257 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT); + + c->pal_yuv[i]= y + (u<<8) + (v<<16) + ((unsigned)a<<24); + + switch (c->opts.dst_format) { + case AV_PIX_FMT_BGR32: +#if !HAVE_BIGENDIAN + case AV_PIX_FMT_RGB24: +#endif + c->pal_rgb[i]= r + (g<<8) + (b<<16) + ((unsigned)a<<24); + break; + case AV_PIX_FMT_BGR32_1: +#if HAVE_BIGENDIAN + case AV_PIX_FMT_BGR24: +#endif + c->pal_rgb[i]= a + (r<<8) + (g<<16) + ((unsigned)b<<24); + break; + case AV_PIX_FMT_RGB32_1: +#if HAVE_BIGENDIAN + case AV_PIX_FMT_RGB24: +#endif + c->pal_rgb[i]= a + (b<<8) + (g<<16) + ((unsigned)r<<24); + break; + case AV_PIX_FMT_GBRP: + case AV_PIX_FMT_GBRAP: +#if HAVE_BIGENDIAN + c->pal_rgb[i]= a + (r<<8) + (b<<16) + ((unsigned)g<<24); +#else + c->pal_rgb[i]= g + (b<<8) + (r<<16) + ((unsigned)a<<24); +#endif + break; + case AV_PIX_FMT_RGB32: +#if !HAVE_BIGENDIAN + case AV_PIX_FMT_BGR24: +#endif + default: + c->pal_rgb[i]= b + (g<<8) + (r<<16) + ((unsigned)a<<24); + } + } +} + +static int scale_internal(SwsContext *sws, + const uint8_t * const srcSlice[], const int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *const dstSlice[], const int dstStride[], + int dstSliceY, int dstSliceH); + +static int scale_gamma(SwsInternal *c, + const uint8_t * const srcSlice[], const int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t * const dstSlice[], const int dstStride[], + int dstSliceY, int dstSliceH) +{ + int ret = scale_internal(c->cascaded_context[0], + srcSlice, srcStride, srcSliceY, srcSliceH, + c->cascaded_tmp[0], c->cascaded_tmpStride[0], 0, c->opts.src_h); + + if (ret < 0) + return ret; + + if (c->cascaded_context[2]) + ret = scale_internal(c->cascaded_context[1], (const uint8_t * const *)c->cascaded_tmp[0], + c->cascaded_tmpStride[0], srcSliceY, srcSliceH, + c->cascaded_tmp[1], c->cascaded_tmpStride[1], 0, c->opts.dst_h); + else + ret = scale_internal(c->cascaded_context[1], (const uint8_t * const *)c->cascaded_tmp[0], + c->cascaded_tmpStride[0], srcSliceY, srcSliceH, + dstSlice, dstStride, dstSliceY, dstSliceH); + + if (ret < 0) + return ret; + + if (c->cascaded_context[2]) { + const int dstY1 = sws_internal(c->cascaded_context[1])->dstY; + ret = scale_internal(c->cascaded_context[2], (const uint8_t * const *)c->cascaded_tmp[1], + c->cascaded_tmpStride[1], dstY1 - ret, dstY1, + dstSlice, dstStride, dstSliceY, dstSliceH); + } + return ret; +} + +static int scale_cascaded(SwsInternal *c, + const uint8_t * const srcSlice[], const int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t * const dstSlice[], const int dstStride[], + int dstSliceY, int dstSliceH) +{ + const int dstH0 = c->cascaded_context[0]->dst_h; + int ret = scale_internal(c->cascaded_context[0], + srcSlice, srcStride, srcSliceY, srcSliceH, + c->cascaded_tmp[0], c->cascaded_tmpStride[0], + 0, dstH0); + if (ret < 0) + return ret; + ret = scale_internal(c->cascaded_context[1], + (const uint8_t * const * )c->cascaded_tmp[0], c->cascaded_tmpStride[0], + 0, dstH0, dstSlice, dstStride, dstSliceY, dstSliceH); + return ret; +} + +static int scale_internal(SwsContext *sws, + const uint8_t * const srcSlice[], const int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *const dstSlice[], const int dstStride[], + int dstSliceY, int dstSliceH) +{ + SwsInternal *c = sws_internal(sws); + const int scale_dst = dstSliceY > 0 || dstSliceH < sws->dst_h; + const int frame_start = scale_dst || !c->sliceDir; + int i, ret; + const uint8_t *src2[4]; + uint8_t *dst2[4]; + int macro_height_src = isBayer(sws->src_format) ? 2 : (1 << c->chrSrcVSubSample); + int macro_height_dst = isBayer(sws->dst_format) ? 2 : (1 << c->chrDstVSubSample); + // copy strides, so they can safely be modified + int srcStride2[4]; + int dstStride2[4]; + int srcSliceY_internal = srcSliceY; + + if (!srcStride || !dstStride || !dstSlice || !srcSlice) { + av_log(c, AV_LOG_ERROR, "One of the input parameters to sws_scale() is NULL, please check the calling code\n"); + return AVERROR(EINVAL); + } + + if ((srcSliceY & (macro_height_src - 1)) || + ((srcSliceH & (macro_height_src - 1)) && srcSliceY + srcSliceH != sws->src_h) || + srcSliceY + srcSliceH > sws->src_h || + srcSliceY < 0 || + srcSliceH < 0 || + (isBayer(sws->src_format) && srcSliceH <= 1)) { + av_log(c, AV_LOG_ERROR, "Slice parameters %d, %d are invalid\n", srcSliceY, srcSliceH); + return AVERROR(EINVAL); + } + + if ((dstSliceY & (macro_height_dst - 1)) || + ((dstSliceH & (macro_height_dst - 1)) && dstSliceY + dstSliceH != sws->dst_h) || + dstSliceY + dstSliceH > sws->dst_h) { + av_log(c, AV_LOG_ERROR, "Slice parameters %d, %d are invalid\n", dstSliceY, dstSliceH); + return AVERROR(EINVAL); + } + + if (!check_image_pointers(srcSlice, sws->src_format, srcStride)) { + av_log(c, AV_LOG_ERROR, "bad src image pointers\n"); + return AVERROR(EINVAL); + } + if (!check_image_pointers((const uint8_t* const*)dstSlice, sws->dst_format, dstStride)) { + av_log(c, AV_LOG_ERROR, "bad dst image pointers\n"); + return AVERROR(EINVAL); + } + + // do not mess up sliceDir if we have a "trailing" 0-size slice + if (srcSliceH == 0) + return 0; + + if (sws->gamma_flag && c->cascaded_context[0]) + return scale_gamma(c, srcSlice, srcStride, srcSliceY, srcSliceH, + dstSlice, dstStride, dstSliceY, dstSliceH); + + if (c->cascaded_context[0] && srcSliceY == 0 && srcSliceH == c->cascaded_context[0]->src_h) + return scale_cascaded(c, srcSlice, srcStride, srcSliceY, srcSliceH, + dstSlice, dstStride, dstSliceY, dstSliceH); + + if (!srcSliceY && (sws->flags & SWS_BITEXACT) && sws->dither == SWS_DITHER_ED && c->dither_error[0]) + for (i = 0; i < 4; i++) + memset(c->dither_error[i], 0, sizeof(c->dither_error[0][0]) * (sws->dst_w+2)); + + if (usePal(sws->src_format)) + ff_update_palette(c, (const uint32_t *)srcSlice[1]); + + memcpy(src2, srcSlice, sizeof(src2)); + memcpy(dst2, dstSlice, sizeof(dst2)); + memcpy(srcStride2, srcStride, sizeof(srcStride2)); + memcpy(dstStride2, dstStride, sizeof(dstStride2)); + + if (frame_start && !scale_dst) { + if (srcSliceY != 0 && srcSliceY + srcSliceH != sws->src_h) { + av_log(c, AV_LOG_ERROR, "Slices start in the middle!\n"); + return AVERROR(EINVAL); + } + + c->sliceDir = (srcSliceY == 0) ? 1 : -1; + } else if (scale_dst) + c->sliceDir = 1; + + if (c->src0Alpha && !c->dst0Alpha && isALPHA(sws->dst_format)) { + uint8_t *base; + int x,y; + + av_fast_malloc(&c->rgb0_scratch, &c->rgb0_scratch_allocated, + FFABS(srcStride[0]) * srcSliceH + 32); + if (!c->rgb0_scratch) + return AVERROR(ENOMEM); + + base = srcStride[0] < 0 ? c->rgb0_scratch - srcStride[0] * (srcSliceH-1) : + c->rgb0_scratch; + for (y=0; y<srcSliceH; y++){ + memcpy(base + srcStride[0]*y, src2[0] + srcStride[0]*y, 4*sws->src_w); + for (x=c->src0Alpha-1; x<4*sws->src_w; x+=4) { + base[ srcStride[0]*y + x] = 0xFF; + } + } + src2[0] = base; + } + + if (c->srcXYZ && !(c->dstXYZ && sws->src_w==sws->dst_w && sws->src_h==sws->dst_h)) { + uint8_t *base; + + av_fast_malloc(&c->xyz_scratch, &c->xyz_scratch_allocated, + FFABS(srcStride[0]) * srcSliceH + 32); + if (!c->xyz_scratch) + return AVERROR(ENOMEM); + + base = srcStride[0] < 0 ? c->xyz_scratch - srcStride[0] * (srcSliceH-1) : + c->xyz_scratch; + + c->xyz12Torgb48(c, base, srcStride[0], src2[0], srcStride[0], sws->src_w, srcSliceH); + src2[0] = base; + } + + if (c->sliceDir != 1) { + // slices go from bottom to top => we flip the image internally + for (i=0; i<4; i++) { + srcStride2[i] *= -1; + dstStride2[i] *= -1; + } + + src2[0] += (srcSliceH - 1) * srcStride[0]; + if (!usePal(sws->src_format)) + src2[1] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[1]; + src2[2] += ((srcSliceH >> c->chrSrcVSubSample) - 1) * srcStride[2]; + src2[3] += (srcSliceH - 1) * srcStride[3]; + dst2[0] += ( sws->dst_h - 1) * dstStride[0]; + dst2[1] += ((sws->dst_h >> c->chrDstVSubSample) - 1) * dstStride[1]; + dst2[2] += ((sws->dst_h >> c->chrDstVSubSample) - 1) * dstStride[2]; + dst2[3] += ( sws->dst_h - 1) * dstStride[3]; + + srcSliceY_internal = sws->src_h-srcSliceY-srcSliceH; + } + reset_ptr(src2, sws->src_format); + reset_ptr((void*)dst2, sws->dst_format); + + if (c->convert_unscaled) { + int offset = srcSliceY_internal; + int slice_h = srcSliceH; + + // for dst slice scaling, offset the pointers to match the unscaled API + if (scale_dst) { + av_assert0(offset == 0); + for (i = 0; i < 4 && src2[i]; i++) { + if (!src2[i] || (i > 0 && usePal(sws->src_format))) + break; + src2[i] += (dstSliceY >> ((i == 1 || i == 2) ? c->chrSrcVSubSample : 0)) * srcStride2[i]; + } + + for (i = 0; i < 4 && dst2[i]; i++) { + if (!dst2[i] || (i > 0 && usePal(sws->dst_format))) + break; + dst2[i] -= (dstSliceY >> ((i == 1 || i == 2) ? c->chrDstVSubSample : 0)) * dstStride2[i]; + } + offset = dstSliceY; + slice_h = dstSliceH; + } + + ret = c->convert_unscaled(c, src2, srcStride2, offset, slice_h, + dst2, dstStride2); + if (scale_dst) + dst2[0] += dstSliceY * dstStride2[0]; + } else { + ret = ff_swscale(c, src2, srcStride2, srcSliceY_internal, srcSliceH, + dst2, dstStride2, dstSliceY, dstSliceH); + } + + if (c->dstXYZ && !(c->srcXYZ && sws->src_w==sws->dst_w && sws->src_h==sws->dst_h)) { + uint8_t *dst; + + if (scale_dst) { + dst = dst2[0]; + } else { + int dstY = c->dstY ? c->dstY : srcSliceY + srcSliceH; + + av_assert0(dstY >= ret); + av_assert0(ret >= 0); + av_assert0(sws->dst_h >= dstY); + dst = dst2[0] + (dstY - ret) * dstStride2[0]; + } + + /* replace on the same data */ + c->rgb48Toxyz12(c, dst, dstStride2[0], dst, dstStride2[0], sws->dst_w, ret); + } + + /* reset slice direction at end of frame */ + if ((srcSliceY_internal + srcSliceH == sws->src_h) || scale_dst) + c->sliceDir = 0; + + return ret; +} + +void sws_frame_end(SwsContext *sws) +{ + SwsInternal *c = sws_internal(sws); + if (!c->is_legacy_init) + return; + av_frame_unref(c->frame_src); + av_frame_unref(c->frame_dst); + c->src_ranges.nb_ranges = 0; +} + +int sws_frame_start(SwsContext *sws, AVFrame *dst, const AVFrame *src) +{ + SwsInternal *c = sws_internal(sws); + int ret, allocated = 0; + if (!c->is_legacy_init) + return AVERROR(EINVAL); + + ret = av_frame_ref(c->frame_src, src); + if (ret < 0) + return ret; + + if (!dst->buf[0]) { + dst->width = sws->dst_w; + dst->height = sws->dst_h; + dst->format = sws->dst_format; + + ret = av_frame_get_buffer(dst, 0); + if (ret < 0) + return ret; + allocated = 1; + } + + ret = av_frame_ref(c->frame_dst, dst); + if (ret < 0) { + if (allocated) + av_frame_unref(dst); + + return ret; + } + + return 0; +} + +int sws_send_slice(SwsContext *sws, unsigned int slice_start, + unsigned int slice_height) +{ + SwsInternal *c = sws_internal(sws); + int ret; + if (!c->is_legacy_init) + return AVERROR(EINVAL); + + ret = ff_range_add(&c->src_ranges, slice_start, slice_height); + if (ret < 0) + return ret; + + return 0; +} + +unsigned int sws_receive_slice_alignment(const SwsContext *sws) +{ + SwsInternal *c = sws_internal(sws); + if (c->slice_ctx) + return sws_internal(c->slice_ctx[0])->dst_slice_align; + + return c->dst_slice_align; +} + +int sws_receive_slice(SwsContext *sws, unsigned int slice_start, + unsigned int slice_height) +{ + SwsInternal *c = sws_internal(sws); + unsigned int align = sws_receive_slice_alignment(sws); + uint8_t *dst[4]; + if (!c->is_legacy_init) + return AVERROR(EINVAL); + + /* wait until complete input has been received */ + if (!(c->src_ranges.nb_ranges == 1 && + c->src_ranges.ranges[0].start == 0 && + c->src_ranges.ranges[0].len == sws->src_h)) + return AVERROR(EAGAIN); + + if ((slice_start > 0 || slice_height < sws->dst_h) && + (slice_start % align || slice_height % align)) { + av_log(c, AV_LOG_ERROR, + "Incorrectly aligned output: %u/%u not multiples of %u\n", + slice_start, slice_height, align); + return AVERROR(EINVAL); + } + + if (c->slicethread) { + int nb_jobs = c->nb_slice_ctx; + int ret = 0; + + if (c->slice_ctx[0]->dither == SWS_DITHER_ED) + nb_jobs = 1; + + c->dst_slice_start = slice_start; + c->dst_slice_height = slice_height; + + avpriv_slicethread_execute(c->slicethread, nb_jobs, 0); + + for (int i = 0; i < c->nb_slice_ctx; i++) { + if (c->slice_err[i] < 0) { + ret = c->slice_err[i]; + break; + } + } + + memset(c->slice_err, 0, c->nb_slice_ctx * sizeof(*c->slice_err)); + + return ret; + } + + for (int i = 0; i < FF_ARRAY_ELEMS(dst); i++) { + ptrdiff_t offset = c->frame_dst->linesize[i] * (ptrdiff_t)(slice_start >> c->chrDstVSubSample); + dst[i] = FF_PTR_ADD(c->frame_dst->data[i], offset); + } + + return scale_internal(sws, (const uint8_t * const *)c->frame_src->data, + c->frame_src->linesize, 0, sws->src_h, + dst, c->frame_dst->linesize, slice_start, slice_height); +} + +/* Subset of av_frame_ref() that only references (video) data buffers */ +static int frame_ref(AVFrame *dst, const AVFrame *src) +{ + /* ref the buffers */ + for (int i = 0; i < FF_ARRAY_ELEMS(src->buf); i++) { + if (!src->buf[i]) + continue; + dst->buf[i] = av_buffer_ref(src->buf[i]); + if (!dst->buf[i]) + return AVERROR(ENOMEM); + } + + memcpy(dst->data, src->data, sizeof(src->data)); + memcpy(dst->linesize, src->linesize, sizeof(src->linesize)); + return 0; +} + +int sws_scale_frame(SwsContext *sws, AVFrame *dst, const AVFrame *src) +{ + int ret; + SwsInternal *c = sws_internal(sws); + if (!src || !dst) + return AVERROR(EINVAL); + + if (c->is_legacy_init) { + /* Context has been initialized with explicit values, fall back to + * legacy API behavior. */ + ret = sws_frame_start(sws, dst, src); + if (ret < 0) + return ret; + + ret = sws_send_slice(sws, 0, src->height); + if (ret >= 0) + ret = sws_receive_slice(sws, 0, dst->height); + + sws_frame_end(sws); + + return ret; + } + + ret = sws_frame_setup(sws, dst, src); + if (ret < 0) + return ret; + + if (!src->data[0]) + return 0; + + if (c->graph[FIELD_TOP]->noop && + (!c->graph[FIELD_BOTTOM] || c->graph[FIELD_BOTTOM]->noop) && + src->buf[0] && !dst->buf[0] && !dst->data[0]) + { + /* Lightweight refcopy */ + ret = frame_ref(dst, src); + if (ret < 0) + return ret; + } else { + if (!dst->data[0]) { + ret = av_frame_get_buffer(dst, 0); + if (ret < 0) + return ret; + } + + for (int field = 0; field < 2; field++) { + SwsGraph *graph = c->graph[field]; + ff_sws_graph_run(graph, dst, src); + if (!graph->dst.interlaced) + break; + } + } + + return 0; +} + +static int validate_params(SwsContext *ctx) +{ +#define VALIDATE(field, min, max) \ + if (ctx->field < min || ctx->field > max) { \ + av_log(ctx, AV_LOG_ERROR, "'%s' (%d) out of range [%d, %d]\n", \ + #field, (int) ctx->field, min, max); \ + return AVERROR(EINVAL); \ + } + + VALIDATE(threads, 0, SWS_MAX_THREADS); + VALIDATE(dither, 0, SWS_DITHER_NB - 1) + VALIDATE(alpha_blend, 0, SWS_ALPHA_BLEND_NB - 1) + return 0; +} + +int sws_frame_setup(SwsContext *ctx, const AVFrame *dst, const AVFrame *src) +{ + SwsInternal *s = sws_internal(ctx); + const char *err_msg; + int ret; + + if (!src || !dst) + return AVERROR(EINVAL); + if ((ret = validate_params(ctx)) < 0) + return ret; + + /* For now, if a single frame has a context, then both need a context */ + if (!!src->hw_frames_ctx != !!dst->hw_frames_ctx) { + return AVERROR(ENOTSUP); + } else if (!!src->hw_frames_ctx) { + /* Both hardware frames must already be allocated */ + if (!src->data[0] || !dst->data[0]) + return AVERROR(EINVAL); + + AVHWFramesContext *src_hwfc, *dst_hwfc; + src_hwfc = (AVHWFramesContext *)src->hw_frames_ctx->data; + dst_hwfc = (AVHWFramesContext *)dst->hw_frames_ctx->data; + + /* Both frames must live on the same device */ + if (src_hwfc->device_ref->data != dst_hwfc->device_ref->data) + return AVERROR(EINVAL); + + /* Only Vulkan devices are supported */ + AVHWDeviceContext *dev_ctx; + dev_ctx = (AVHWDeviceContext *)src_hwfc->device_ref->data; + if (dev_ctx->type != AV_HWDEVICE_TYPE_VULKAN) + return AVERROR(ENOTSUP); + +#if CONFIG_UNSTABLE && CONFIG_VULKAN + ret = ff_sws_vk_init(ctx, src_hwfc->device_ref); + if (ret < 0) + return ret; +#endif + } + + for (int field = 0; field < 2; field++) { + SwsFormat src_fmt = ff_fmt_from_frame(src, field); + SwsFormat dst_fmt = ff_fmt_from_frame(dst, field); + int src_ok, dst_ok; + + if ((src->flags ^ dst->flags) & AV_FRAME_FLAG_INTERLACED) { + err_msg = "Cannot convert interlaced to progressive frames or vice versa.\n"; + ret = AVERROR(EINVAL); + goto fail; + } + + src_ok = ff_test_fmt(&src_fmt, 0); + dst_ok = ff_test_fmt(&dst_fmt, 1); + if ((!src_ok || !dst_ok) && !ff_props_equal(&src_fmt, &dst_fmt)) { + err_msg = src_ok ? "Unsupported output" : "Unsupported input"; + ret = AVERROR(ENOTSUP); + goto fail; + } + + ret = ff_sws_graph_reinit(ctx, &dst_fmt, &src_fmt, field, &s->graph[field]); + if (ret < 0) { + err_msg = "Failed initializing scaling graph"; + goto fail; + } + + if (s->graph[field]->incomplete && ctx->flags & SWS_STRICT) { + err_msg = "Incomplete scaling graph"; + ret = AVERROR(EINVAL); + goto fail; + } + + if (!src_fmt.interlaced) { + ff_sws_graph_free(&s->graph[FIELD_BOTTOM]); + break; + } + + continue; + + fail: + av_log(ctx, AV_LOG_ERROR, "%s (%s): fmt:%s csp:%s prim:%s trc:%s ->" + " fmt:%s csp:%s prim:%s trc:%s\n", + err_msg, av_err2str(ret), + av_get_pix_fmt_name(src_fmt.format), av_color_space_name(src_fmt.csp), + av_color_primaries_name(src_fmt.color.prim), av_color_transfer_name(src_fmt.color.trc), + av_get_pix_fmt_name(dst_fmt.format), av_color_space_name(dst_fmt.csp), + av_color_primaries_name(dst_fmt.color.prim), av_color_transfer_name(dst_fmt.color.trc)); + + for (int i = 0; i < FF_ARRAY_ELEMS(s->graph); i++) + ff_sws_graph_free(&s->graph[i]); + + return ret; + } + + return 0; +} + +/** + * swscale wrapper, so we don't need to export the SwsContext. + * Assumes planar YUV to be in YUV order instead of YVU. + */ +int attribute_align_arg sws_scale(SwsContext *sws, + const uint8_t * const srcSlice[], + const int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *const dst[], + const int dstStride[]) +{ + SwsInternal *c = sws_internal(sws); + if (!c->is_legacy_init) + return AVERROR(EINVAL); + + if (c->nb_slice_ctx) { + sws = c->slice_ctx[0]; + c = sws_internal(sws); + } + + return scale_internal(sws, srcSlice, srcStride, srcSliceY, srcSliceH, + dst, dstStride, 0, sws->dst_h); +} + +void ff_sws_slice_worker(void *priv, int jobnr, int threadnr, + int nb_jobs, int nb_threads) +{ + SwsInternal *parent = priv; + SwsContext *sws = parent->slice_ctx[threadnr]; + SwsInternal *c = sws_internal(sws); + + const int slice_height = FFALIGN(FFMAX((parent->dst_slice_height + nb_jobs - 1) / nb_jobs, 1), + c->dst_slice_align); + const int slice_start = jobnr * slice_height; + const int slice_end = FFMIN((jobnr + 1) * slice_height, parent->dst_slice_height); + int err = 0; + + if (slice_end > slice_start) { + uint8_t *dst[4] = { NULL }; + + for (int i = 0; i < FF_ARRAY_ELEMS(dst) && parent->frame_dst->data[i]; i++) { + const int vshift = (i == 1 || i == 2) ? c->chrDstVSubSample : 0; + const ptrdiff_t offset = parent->frame_dst->linesize[i] * + (ptrdiff_t)((slice_start + parent->dst_slice_start) >> vshift); + + dst[i] = parent->frame_dst->data[i] + offset; + } + + err = scale_internal(sws, (const uint8_t * const *)parent->frame_src->data, + parent->frame_src->linesize, 0, sws->src_h, + dst, parent->frame_dst->linesize, + parent->dst_slice_start + slice_start, slice_end - slice_start); + } + + parent->slice_err[threadnr] = err; +} diff --git a/libs/ffmpeg/libswscale/swscale.h b/libs/ffmpeg/libswscale/swscale.h new file mode 100644 index 00000000000..1cfd4068f9d --- /dev/null +++ b/libs/ffmpeg/libswscale/swscale.h @@ -0,0 +1,700 @@ +/* + * Copyright (C) 2024 Niklas Haas + * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_SWSCALE_H +#define SWSCALE_SWSCALE_H + +/** + * @file + * @ingroup libsws + * external API header + */ + +#include <stdint.h> + +#include "libavutil/avutil.h" +#include "libavutil/frame.h" +#include "libavutil/log.h" +#include "libavutil/pixfmt.h" +#include "version_major.h" +#ifndef HAVE_AV_CONFIG_H +/* When included as part of the ffmpeg build, only include the major version + * to avoid unnecessary rebuilds. When included externally, keep including + * the full version information. */ +#include "version.h" +#endif + +/** + * @defgroup libsws libswscale + * Color conversion and scaling library. + * + * @{ + * + * Return the LIBSWSCALE_VERSION_INT constant. + */ +unsigned swscale_version(void); + +/** + * Return the libswscale build-time configuration. + */ +const char *swscale_configuration(void); + +/** + * Return the libswscale license. + */ +const char *swscale_license(void); + +/** + * Get the AVClass for SwsContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *sws_get_class(void); + +/****************************** + * Flags and quality settings * + ******************************/ + +typedef enum SwsDither { + SWS_DITHER_NONE = 0, /* disable dithering */ + SWS_DITHER_AUTO, /* auto-select from preset */ + SWS_DITHER_BAYER, /* ordered dither matrix */ + SWS_DITHER_ED, /* error diffusion */ + SWS_DITHER_A_DITHER, /* arithmetic addition */ + SWS_DITHER_X_DITHER, /* arithmetic xor */ + SWS_DITHER_NB, /* not part of the ABI */ + SWS_DITHER_MAX_ENUM = 0x7FFFFFFF, /* force size to 32 bits, not a valid dither type */ +} SwsDither; + +typedef enum SwsAlphaBlend { + SWS_ALPHA_BLEND_NONE = 0, + SWS_ALPHA_BLEND_UNIFORM, + SWS_ALPHA_BLEND_CHECKERBOARD, + SWS_ALPHA_BLEND_NB, /* not part of the ABI */ + SWS_ALPHA_BLEND_MAX_ENUM = 0x7FFFFFFF, /* force size to 32 bits, not a valid blend mode */ +} SwsAlphaBlend; + +typedef enum SwsFlags { + /** + * Scaler selection options. Only one may be active at a time. + */ + SWS_FAST_BILINEAR = 1 << 0, ///< fast bilinear filtering + SWS_BILINEAR = 1 << 1, ///< bilinear filtering + SWS_BICUBIC = 1 << 2, ///< 2-tap cubic B-spline + SWS_X = 1 << 3, ///< experimental + SWS_POINT = 1 << 4, ///< nearest neighbor + SWS_AREA = 1 << 5, ///< area averaging + SWS_BICUBLIN = 1 << 6, ///< bicubic luma, bilinear chroma + SWS_GAUSS = 1 << 7, ///< gaussian approximation + SWS_SINC = 1 << 8, ///< unwindowed sinc + SWS_LANCZOS = 1 << 9, ///< 3-tap sinc/sinc + SWS_SPLINE = 1 << 10, ///< cubic Keys spline + + /** + * Return an error on underspecified conversions. Without this flag, + * unspecified fields are defaulted to sensible values. + */ + SWS_STRICT = 1 << 11, + + /** + * Emit verbose log of scaling parameters. + */ + SWS_PRINT_INFO = 1 << 12, + + /** + * Perform full chroma upsampling when upscaling to RGB. + * + * For example, when converting 50x50 yuv420p to 100x100 rgba, setting this flag + * will scale the chroma plane from 25x25 to 100x100 (4:4:4), and then convert + * the 100x100 yuv444p image to rgba in the final output step. + * + * Without this flag, the chroma plane is instead scaled to 50x100 (4:2:2), + * with a single chroma sample being reused for both of the horizontally + * adjacent RGBA output pixels. + */ + SWS_FULL_CHR_H_INT = 1 << 13, + + /** + * Perform full chroma interpolation when downscaling RGB sources. + * + * For example, when converting a 100x100 rgba source to 50x50 yuv444p, setting + * this flag will generate a 100x100 (4:4:4) chroma plane, which is then + * downscaled to the required 50x50. + * + * Without this flag, the chroma plane is instead generated at 50x100 (dropping + * every other pixel), before then being downscaled to the required 50x50 + * resolution. + */ + SWS_FULL_CHR_H_INP = 1 << 14, + + /** + * Force bit-exact output. This will prevent the use of platform-specific + * optimizations that may lead to slight difference in rounding, in favor + * of always maintaining exact bit output compatibility with the reference + * C code. + * + * Note: It is recommended to set both of these flags simultaneously. + */ + SWS_ACCURATE_RND = 1 << 18, + SWS_BITEXACT = 1 << 19, + + /** + * Allow using experimental new code paths. This may be faster, slower, + * or produce different output, with semantics subject to change at any + * point in time. For testing and debugging purposes only. + */ + SWS_UNSTABLE = 1 << 20, + + /** + * Deprecated flags. + */ + SWS_DIRECT_BGR = 1 << 15, ///< This flag has no effect + SWS_ERROR_DIFFUSION = 1 << 23, ///< Set `SwsContext.dither` instead +} SwsFlags; + +typedef enum SwsIntent { + SWS_INTENT_PERCEPTUAL = 0, ///< Perceptual tone mapping + SWS_INTENT_RELATIVE_COLORIMETRIC = 1, ///< Relative colorimetric clipping + SWS_INTENT_SATURATION = 2, ///< Saturation mapping + SWS_INTENT_ABSOLUTE_COLORIMETRIC = 3, ///< Absolute colorimetric clipping + SWS_INTENT_NB, ///< not part of the ABI +} SwsIntent; + +/*********************************** + * Context creation and management * + ***********************************/ + +/** + * Main external API structure. New fields can be added to the end with + * minor version bumps. Removal, reordering and changes to existing fields + * require a major version bump. sizeof(SwsContext) is not part of the ABI. + */ +typedef struct SwsContext { + const AVClass *av_class; + + /** + * Private data of the user, can be used to carry app specific stuff. + */ + void *opaque; + + /** + * Bitmask of SWS_*. See `SwsFlags` for details. + */ + unsigned flags; + + /** + * Extra parameters for fine-tuning certain scalers. + */ + double scaler_params[2]; + + /** + * How many threads to use for processing, or 0 for automatic selection. + */ + int threads; + + /** + * Dither mode. + */ + SwsDither dither; + + /** + * Alpha blending mode. See `SwsAlphaBlend` for details. + */ + SwsAlphaBlend alpha_blend; + + /** + * Use gamma correct scaling. + */ + int gamma_flag; + + /** + * Deprecated frame property overrides, for the legacy API only. + * + * Ignored by sws_scale_frame() when used in dynamic mode, in which + * case all properties are instead taken from the frame directly. + */ + int src_w, src_h; ///< Width and height of the source frame + int dst_w, dst_h; ///< Width and height of the destination frame + int src_format; ///< Source pixel format + int dst_format; ///< Destination pixel format + int src_range; ///< Source is full range + int dst_range; ///< Destination is full range + int src_v_chr_pos; ///< Source vertical chroma position in luma grid / 256 + int src_h_chr_pos; ///< Source horizontal chroma position + int dst_v_chr_pos; ///< Destination vertical chroma position + int dst_h_chr_pos; ///< Destination horizontal chroma position + + /** + * Desired ICC intent for color space conversions. + */ + int intent; + + /* Remember to add new fields to graph.c:opts_equal() */ +} SwsContext; + +/** + * Allocate an empty SwsContext and set its fields to default values. + */ +SwsContext *sws_alloc_context(void); + +/** + * Free the context and everything associated with it, and write NULL + * to the provided pointer. + */ +void sws_free_context(SwsContext **ctx); + +/*************************** + * Supported frame formats * + ***************************/ + +/** + * Test if a given (software) pixel format is supported. + * + * @param output If 0, test if compatible with the source/input frame; + * otherwise, with the destination/output frame. + * @param format The format to check. + * + * @return A positive integer if supported, 0 otherwise. + */ +int sws_test_format(enum AVPixelFormat format, int output); + +/** + * Test if a given hardware pixel format is supported. + * + * @param format The hardware format to check, or AV_PIX_FMT_NONE. + * + * @return A positive integer if supported or AV_PIX_FMT_NONE, 0 otherwise. + */ +int sws_test_hw_format(enum AVPixelFormat format); + +/** + * Test if a given color space is supported. + * + * @param output If 0, test if compatible with the source/input frame; + * otherwise, with the destination/output frame. + * @param colorspace The colorspace to check. + * + * @return A positive integer if supported, 0 otherwise. + */ +int sws_test_colorspace(enum AVColorSpace colorspace, int output); + +/** + * Test if a given set of color primaries is supported. + * + * @param output If 0, test if compatible with the source/input frame; + * otherwise, with the destination/output frame. + * @param primaries The color primaries to check. + * + * @return A positive integer if supported, 0 otherwise. + */ +int sws_test_primaries(enum AVColorPrimaries primaries, int output); + +/** + * Test if a given color transfer function is supported. + * + * @param output If 0, test if compatible with the source/input frame; + * otherwise, with the destination/output frame. + * @param trc The color transfer function to check. + * + * @return A positive integer if supported, 0 otherwise. + */ +int sws_test_transfer(enum AVColorTransferCharacteristic trc, int output); + +/** + * Helper function to run all sws_test_* against a frame, as well as testing + * the basic frame properties for sanity. Ignores irrelevant properties - for + * example, AVColorSpace is not checked for RGB frames. + */ +int sws_test_frame(const AVFrame *frame, int output); + +/** + * Like `sws_scale_frame`, but without actually scaling. It will instead + * merely initialize internal state that *would* be required to perform the + * operation, as well as returning the correct error code for unsupported + * frame combinations. + * + * @param ctx The scaling context. + * @param dst The destination frame to consider. + * @param src The source frame to consider. + * @return 0 on success, a negative AVERROR code on failure. + */ +int sws_frame_setup(SwsContext *ctx, const AVFrame *dst, const AVFrame *src); + +/******************** + * Main scaling API * + ********************/ + +/** + * Check if a given conversion is a noop. Returns a positive integer if + * no operation needs to be performed, 0 otherwise. + */ +int sws_is_noop(const AVFrame *dst, const AVFrame *src); + +/** + * Scale source data from `src` and write the output to `dst`. + * + * This function can be used directly on an allocated context, without setting + * up any frame properties or calling `sws_init_context()`. Such usage is fully + * dynamic and does not require reallocation if the frame properties change. + * + * Alternatively, this function can be called on a context that has been + * explicitly initialized. However, this is provided only for backwards + * compatibility. In this usage mode, all frame properties must be correctly + * set at init time, and may no longer change after initialization. + * + * @param ctx The scaling context. + * @param dst The destination frame. The data buffers may either be already + * allocated by the caller or left clear, in which case they will + * be allocated by the scaler. The latter may have performance + * advantages - e.g. in certain cases some (or all) output planes + * may be references to input planes, rather than copies. + * @param src The source frame. If the data buffers are set to NULL, then + * this function behaves identically to `sws_frame_setup`. + * @return >= 0 on success, a negative AVERROR code on failure. + */ +int sws_scale_frame(SwsContext *c, AVFrame *dst, const AVFrame *src); + +/************************* + * Legacy (stateful) API * + *************************/ + +#define SWS_SRC_V_CHR_DROP_MASK 0x30000 +#define SWS_SRC_V_CHR_DROP_SHIFT 16 + +#define SWS_PARAM_DEFAULT 123456 + +#define SWS_MAX_REDUCE_CUTOFF 0.002 + +#define SWS_CS_ITU709 1 +#define SWS_CS_FCC 4 +#define SWS_CS_ITU601 5 +#define SWS_CS_ITU624 5 +#define SWS_CS_SMPTE170M 5 +#define SWS_CS_SMPTE240M 7 +#define SWS_CS_DEFAULT 5 +#define SWS_CS_BT2020 9 + +/** + * Return a pointer to yuv<->rgb coefficients for the given colorspace + * suitable for sws_setColorspaceDetails(). + * + * @param colorspace One of the SWS_CS_* macros. If invalid, + * SWS_CS_DEFAULT is used. + */ +const int *sws_getCoefficients(int colorspace); + +// when used for filters they must have an odd number of elements +// coeffs cannot be shared between vectors +typedef struct SwsVector { + double *coeff; ///< pointer to the list of coefficients + int length; ///< number of coefficients in the vector +} SwsVector; + +// vectors can be shared +typedef struct SwsFilter { + SwsVector *lumH; + SwsVector *lumV; + SwsVector *chrH; + SwsVector *chrV; +} SwsFilter; + +/** + * Return a positive value if pix_fmt is a supported input format, 0 + * otherwise. + */ +int sws_isSupportedInput(enum AVPixelFormat pix_fmt); + +/** + * Return a positive value if pix_fmt is a supported output format, 0 + * otherwise. + */ +int sws_isSupportedOutput(enum AVPixelFormat pix_fmt); + +/** + * @param[in] pix_fmt the pixel format + * @return a positive value if an endianness conversion for pix_fmt is + * supported, 0 otherwise. + */ +int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt); + +/** + * Initialize the swscaler context sws_context. + * + * This function is considered deprecated, and provided only for backwards + * compatibility with sws_scale() and sws_frame_start(). The preferred way to + * use libswscale is to set all frame properties correctly and call + * sws_scale_frame() directly, without explicitly initializing the context. + * + * @return zero or positive value on success, a negative value on + * error + */ +av_warn_unused_result +int sws_init_context(SwsContext *sws_context, SwsFilter *srcFilter, SwsFilter *dstFilter); + +/** + * Free the swscaler context swsContext. + * If swsContext is NULL, then does nothing. + */ +void sws_freeContext(SwsContext *swsContext); + +/** + * Allocate and return an SwsContext. You need it to perform + * scaling/conversion operations using sws_scale(). + * + * @param srcW the width of the source image + * @param srcH the height of the source image + * @param srcFormat the source image format + * @param dstW the width of the destination image + * @param dstH the height of the destination image + * @param dstFormat the destination image format + * @param flags specify which algorithm and options to use for rescaling + * @param param extra parameters to tune the used scaler + * For SWS_BICUBIC param[0] and [1] tune the shape of the basis + * function, param[0] tunes f(1) and param[1] f´(1) + * For SWS_GAUSS param[0] tunes the exponent and thus cutoff + * frequency + * For SWS_LANCZOS param[0] tunes the width of the window function + * @return a pointer to an allocated context, or NULL in case of error + * @note this function is to be removed after a saner alternative is + * written + */ +SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, + int dstW, int dstH, enum AVPixelFormat dstFormat, + int flags, SwsFilter *srcFilter, + SwsFilter *dstFilter, const double *param); + +/** + * Scale the image slice in srcSlice and put the resulting scaled + * slice in the image in dst. A slice is a sequence of consecutive + * rows in an image. Requires a context that has previously been + * initialized with sws_init_context(). + * + * Slices have to be provided in sequential order, either in + * top-bottom or bottom-top order. If slices are provided in + * non-sequential order the behavior of the function is undefined. + * + * @param c the scaling context previously created with + * sws_getContext() + * @param srcSlice the array containing the pointers to the planes of + * the source slice + * @param srcStride the array containing the strides for each plane of + * the source image + * @param srcSliceY the position in the source image of the slice to + * process, that is the number (counted starting from + * zero) in the image of the first row of the slice + * @param srcSliceH the height of the source slice, that is the number + * of rows in the slice + * @param dst the array containing the pointers to the planes of + * the destination image + * @param dstStride the array containing the strides for each plane of + * the destination image + * @return the height of the output slice + */ +int sws_scale(SwsContext *c, const uint8_t *const srcSlice[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]); + +/** + * Initialize the scaling process for a given pair of source/destination frames. + * Must be called before any calls to sws_send_slice() and sws_receive_slice(). + * Requires a context that has previously been initialized with sws_init_context(). + * + * This function will retain references to src and dst, so they must both use + * refcounted buffers (if allocated by the caller, in case of dst). + * + * @param c The scaling context + * @param dst The destination frame. + * + * The data buffers may either be already allocated by the caller or + * left clear, in which case they will be allocated by the scaler. + * The latter may have performance advantages - e.g. in certain cases + * some output planes may be references to input planes, rather than + * copies. + * + * Output data will be written into this frame in successful + * sws_receive_slice() calls. + * @param src The source frame. The data buffers must be allocated, but the + * frame data does not have to be ready at this point. Data + * availability is then signalled by sws_send_slice(). + * @return 0 on success, a negative AVERROR code on failure + * + * @see sws_frame_end() + */ +int sws_frame_start(SwsContext *c, AVFrame *dst, const AVFrame *src); + +/** + * Finish the scaling process for a pair of source/destination frames previously + * submitted with sws_frame_start(). Must be called after all sws_send_slice() + * and sws_receive_slice() calls are done, before any new sws_frame_start() + * calls. + * + * @param c The scaling context + */ +void sws_frame_end(SwsContext *c); + +/** + * Indicate that a horizontal slice of input data is available in the source + * frame previously provided to sws_frame_start(). The slices may be provided in + * any order, but may not overlap. For vertically subsampled pixel formats, the + * slices must be aligned according to subsampling. + * + * @param c The scaling context + * @param slice_start first row of the slice + * @param slice_height number of rows in the slice + * + * @return a non-negative number on success, a negative AVERROR code on failure. + */ +int sws_send_slice(SwsContext *c, unsigned int slice_start, + unsigned int slice_height); + +/** + * Request a horizontal slice of the output data to be written into the frame + * previously provided to sws_frame_start(). + * + * @param c The scaling context + * @param slice_start first row of the slice; must be a multiple of + * sws_receive_slice_alignment() + * @param slice_height number of rows in the slice; must be a multiple of + * sws_receive_slice_alignment(), except for the last slice + * (i.e. when slice_start+slice_height is equal to output + * frame height) + * + * @return a non-negative number if the data was successfully written into the output + * AVERROR(EAGAIN) if more input data needs to be provided before the + * output can be produced + * another negative AVERROR code on other kinds of scaling failure + */ +int sws_receive_slice(SwsContext *c, unsigned int slice_start, + unsigned int slice_height); + +/** + * Get the alignment required for slices. Requires a context that has + * previously been initialized with sws_init_context(). + * + * @param c The scaling context + * @return alignment required for output slices requested with sws_receive_slice(). + * Slice offsets and sizes passed to sws_receive_slice() must be + * multiples of the value returned from this function. + */ +unsigned int sws_receive_slice_alignment(const SwsContext *c); + +/** + * @param c the scaling context + * @param dstRange flag indicating the white-black range of the output (1=jpeg / 0=mpeg) + * @param srcRange flag indicating the white-black range of the input (1=jpeg / 0=mpeg) + * @param table the yuv2rgb coefficients describing the output yuv space, normally ff_yuv2rgb_coeffs[x] + * @param inv_table the yuv2rgb coefficients describing the input yuv space, normally ff_yuv2rgb_coeffs[x] + * @param brightness 16.16 fixed point brightness correction + * @param contrast 16.16 fixed point contrast correction + * @param saturation 16.16 fixed point saturation correction + * + * @return A negative error code on error, non negative otherwise. + * If `LIBSWSCALE_VERSION_MAJOR < 7`, returns -1 if not supported. + */ +int sws_setColorspaceDetails(SwsContext *c, const int inv_table[4], + int srcRange, const int table[4], int dstRange, + int brightness, int contrast, int saturation); + +/** + * @return A negative error code on error, non negative otherwise. + * If `LIBSWSCALE_VERSION_MAJOR < 7`, returns -1 if not supported. + */ +int sws_getColorspaceDetails(SwsContext *c, int **inv_table, + int *srcRange, int **table, int *dstRange, + int *brightness, int *contrast, int *saturation); + +/** + * Allocate and return an uninitialized vector with length coefficients. + */ +SwsVector *sws_allocVec(int length); + +/** + * Return a normalized Gaussian curve used to filter stuff + * quality = 3 is high quality, lower is lower quality. + */ +SwsVector *sws_getGaussianVec(double variance, double quality); + +/** + * Scale all the coefficients of a by the scalar value. + */ +void sws_scaleVec(SwsVector *a, double scalar); + +/** + * Scale all the coefficients of a so that their sum equals height. + */ +void sws_normalizeVec(SwsVector *a, double height); + +void sws_freeVec(SwsVector *a); + +SwsFilter *sws_getDefaultFilter(float lumaGBlur, float chromaGBlur, + float lumaSharpen, float chromaSharpen, + float chromaHShift, float chromaVShift, + int verbose); +void sws_freeFilter(SwsFilter *filter); + +/** + * Check if context can be reused, otherwise reallocate a new one. + * + * If context is NULL, just calls sws_getContext() to get a new + * context. Otherwise, checks if the parameters are the ones already + * saved in context. If that is the case, returns the current + * context. Otherwise, frees context and gets a new context with + * the new parameters. + * + * Be warned that srcFilter and dstFilter are not checked, they + * are assumed to remain the same. + */ +SwsContext *sws_getCachedContext(SwsContext *context, int srcW, int srcH, + enum AVPixelFormat srcFormat, int dstW, int dstH, + enum AVPixelFormat dstFormat, int flags, + SwsFilter *srcFilter, SwsFilter *dstFilter, + const double *param); + +/** + * Convert an 8-bit paletted frame into a frame with a color depth of 32 bits. + * + * The output frame will have the same packed format as the palette. + * + * @param src source frame buffer + * @param dst destination frame buffer + * @param num_pixels number of pixels to convert + * @param palette array with [256] entries, which must match color arrangement (RGB or BGR) of src + */ +void sws_convertPalette8ToPacked32(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette); + +/** + * Convert an 8-bit paletted frame into a frame with a color depth of 24 bits. + * + * With the palette format "ABCD", the destination frame ends up with the format "ABC". + * + * @param src source frame buffer + * @param dst destination frame buffer + * @param num_pixels number of pixels to convert + * @param palette array with [256] entries, which must match color arrangement (RGB or BGR) of src + */ +void sws_convertPalette8ToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels, const uint8_t *palette); + +/** + * @} + */ + +#endif /* SWSCALE_SWSCALE_H */ diff --git a/libs/ffmpeg/libswscale/swscale_internal.h b/libs/ffmpeg/libswscale/swscale_internal.h new file mode 100644 index 00000000000..7d5eeae2032 --- /dev/null +++ b/libs/ffmpeg/libswscale/swscale_internal.h @@ -0,0 +1,1200 @@ +/* + * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_SWSCALE_INTERNAL_H +#define SWSCALE_SWSCALE_INTERNAL_H + +#include <stdatomic.h> +#include <assert.h> + +#include "config.h" +#include "swscale.h" +#include "graph.h" + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/frame.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/log.h" +#include "libavutil/mem_internal.h" +#include "libavutil/pixfmt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/slicethread.h" +#include "libavutil/half2float.h" + +#if HAVE_ALTIVEC +#define SWSINTERNAL_ADDITIONAL_ASM_SIZE (7*16 + 2*8 + /* alignment */ 16) +#endif +#ifndef SWSINTERNAL_ADDITIONAL_ASM_SIZE +#define SWSINTERNAL_ADDITIONAL_ASM_SIZE 0 +#endif + +#define STR(s) AV_TOSTRING(s) // AV_STRINGIFY is too long + +#define YUVRGB_TABLE_HEADROOM 512 +#define YUVRGB_TABLE_LUMA_HEADROOM 512 + +#define MAX_FILTER_SIZE SWS_MAX_FILTER_SIZE + +#define SWS_MAX_THREADS 8192 /* sanity clamp */ + +#if HAVE_BIGENDIAN +#define ALT32_CORR (-1) +#else +#define ALT32_CORR 1 +#endif + +#if ARCH_X86_64 +# define APCK_PTR2 8 +# define APCK_COEF 16 +# define APCK_SIZE 24 +#else +# define APCK_PTR2 4 +# define APCK_COEF 8 +# define APCK_SIZE 16 +#endif + +#define RETCODE_USE_CASCADE -12345 + +typedef struct SwsInternal SwsInternal; + +static inline SwsInternal *sws_internal(const SwsContext *sws) +{ + return (SwsInternal *) sws; +} + +typedef struct Range { + unsigned int start; + unsigned int len; +} Range; + +typedef struct RangeList { + Range *ranges; + unsigned int nb_ranges; + int ranges_allocated; +} RangeList; + +int ff_range_add(RangeList *r, unsigned int start, unsigned int len); + +typedef int (*SwsFunc)(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]); + +typedef void (*SwsColorFunc)(const SwsInternal *c, uint8_t *dst, int dst_stride, + const uint8_t *src, int src_stride, int w, int h); + +typedef struct SwsLuts { + uint16_t *in; + uint16_t *out; +} SwsLuts; + +typedef struct SwsColorXform { + SwsLuts gamma; + int16_t mat[3][3]; +} SwsColorXform; + +/** + * Write one line of horizontally scaled data to planar output + * without any additional vertical scaling (or point-scaling). + * + * @param src scaled source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param dest pointer to the output plane. For >8-bit + * output, this is in uint16_t + * @param dstW width of destination in pixels + * @param dither ordered dither array of type int16_t and size 8 + * @param offset Dither offset + */ +typedef void (*yuv2planar1_fn)(const int16_t *src, uint8_t *dest, int dstW, + const uint8_t *dither, int offset); + +/** + * Write one line of horizontally scaled data to planar output + * with multi-point vertical scaling between input pixels. + * + * @param filter vertical luma/alpha scaling coefficients, 12 bits [0,4096] + * @param src scaled luma (Y) or alpha (A) source data, 15 bits for + * 8-10-bit output, 19 bits for 16-bit output (in int32_t) + * @param filterSize number of vertical input lines to scale + * @param dest pointer to output plane. For >8-bit + * output, this is in uint16_t + * @param dstW width of destination pixels + * @param offset Dither offset + */ +typedef void (*yuv2planarX_fn)(const int16_t *filter, int filterSize, + const int16_t **src, uint8_t *dest, int dstW, + const uint8_t *dither, int offset); + +/** + * Write one line of horizontally scaled chroma to interleaved output + * with multi-point vertical scaling between input pixels. + * + * @param dstFormat destination pixel format + * @param chrDither ordered dither array of type uint8_t and size 8 + * @param chrFilter vertical chroma scaling coefficients, 12 bits [0,4096] + * @param chrUSrc scaled chroma (U) source data, 15 bits for 8-10-bit + * output, 19 bits for 16-bit output (in int32_t) + * @param chrVSrc scaled chroma (V) source data, 15 bits for 8-10-bit + * output, 19 bits for 16-bit output (in int32_t) + * @param chrFilterSize number of vertical chroma input lines to scale + * @param dest pointer to the output plane. For >8-bit + * output, this is in uint16_t + * @param dstW width of chroma planes + */ +typedef void (*yuv2interleavedX_fn)(enum AVPixelFormat dstFormat, + const uint8_t *chrDither, + const int16_t *chrFilter, + int chrFilterSize, + const int16_t **chrUSrc, + const int16_t **chrVSrc, + uint8_t *dest, int dstW); + +/** + * Write one line of horizontally scaled Y/U/V/A to packed-pixel YUV/RGB + * output without any additional vertical scaling (or point-scaling). Note + * that this function may do chroma scaling, see the "uvalpha" argument. + * + * @param c SWS scaling context + * @param lumSrc scaled luma (Y) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param chrUSrc scaled chroma (U) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param chrVSrc scaled chroma (V) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param alpSrc scaled alpha (A) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param dest pointer to the output plane. For 16-bit output, this is + * uint16_t + * @param dstW width of lumSrc and alpSrc in pixels, number of pixels + * to write into dest[] + * @param uvalpha chroma scaling coefficient for the second line of chroma + * pixels, either 2048 or 0. If 0, one chroma input is used + * for 2 output pixels (or if the SWS_FULL_CHR_H_INT flag + * is set, it generates 1 output pixel). If 2048, two chroma + * input pixels should be averaged for 2 output pixels (this + * only happens if SWS_FULL_CHR_H_INT is not set) + * @param y vertical line number for this output. This does not need + * to be used to calculate the offset in the destination, + * but can be used to generate comfort noise using dithering + * for some output formats. + */ +typedef void (*yuv2packed1_fn)(SwsInternal *c, const int16_t *lumSrc, + const int16_t *chrUSrc[2], + const int16_t *chrVSrc[2], + const int16_t *alpSrc, uint8_t *dest, + int dstW, int uvalpha, int y); +/** + * Write one line of horizontally scaled Y/U/V/A to packed-pixel YUV/RGB + * output by doing bilinear scaling between two input lines. + * + * @param c SWS scaling context + * @param lumSrc scaled luma (Y) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param chrUSrc scaled chroma (U) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param chrVSrc scaled chroma (V) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param alpSrc scaled alpha (A) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param dest pointer to the output plane. For 16-bit output, this is + * uint16_t + * @param dstW width of lumSrc and alpSrc in pixels, number of pixels + * to write into dest[] + * @param yalpha luma/alpha scaling coefficients for the second input line. + * The first line's coefficients can be calculated by using + * 4096 - yalpha + * @param uvalpha chroma scaling coefficient for the second input line. The + * first line's coefficients can be calculated by using + * 4096 - uvalpha + * @param y vertical line number for this output. This does not need + * to be used to calculate the offset in the destination, + * but can be used to generate comfort noise using dithering + * for some output formats. + */ +typedef void (*yuv2packed2_fn)(SwsInternal *c, const int16_t *lumSrc[2], + const int16_t *chrUSrc[2], + const int16_t *chrVSrc[2], + const int16_t *alpSrc[2], + uint8_t *dest, + int dstW, int yalpha, int uvalpha, int y); +/** + * Write one line of horizontally scaled Y/U/V/A to packed-pixel YUV/RGB + * output by doing multi-point vertical scaling between input pixels. + * + * @param c SWS scaling context + * @param lumFilter vertical luma/alpha scaling coefficients, 12 bits [0,4096] + * @param lumSrc scaled luma (Y) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param lumFilterSize number of vertical luma/alpha input lines to scale + * @param chrFilter vertical chroma scaling coefficients, 12 bits [0,4096] + * @param chrUSrc scaled chroma (U) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param chrVSrc scaled chroma (V) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param chrFilterSize number of vertical chroma input lines to scale + * @param alpSrc scaled alpha (A) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param dest pointer to the output plane. For 16-bit output, this is + * uint16_t + * @param dstW width of lumSrc and alpSrc in pixels, number of pixels + * to write into dest[] + * @param y vertical line number for this output. This does not need + * to be used to calculate the offset in the destination, + * but can be used to generate comfort noise using dithering + * or some output formats. + */ +typedef void (*yuv2packedX_fn)(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, + const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t *dest, + int dstW, int y); + +/** + * Write one line of horizontally scaled Y/U/V/A to YUV/RGB + * output by doing multi-point vertical scaling between input pixels. + * + * @param c SWS scaling context + * @param lumFilter vertical luma/alpha scaling coefficients, 12 bits [0,4096] + * @param lumSrc scaled luma (Y) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param lumFilterSize number of vertical luma/alpha input lines to scale + * @param chrFilter vertical chroma scaling coefficients, 12 bits [0,4096] + * @param chrUSrc scaled chroma (U) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param chrVSrc scaled chroma (V) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param chrFilterSize number of vertical chroma input lines to scale + * @param alpSrc scaled alpha (A) source data, 15 bits for 8-10-bit output, + * 19 bits for 16-bit output (in int32_t) + * @param dest pointer to the output planes. For 16-bit output, this is + * uint16_t + * @param dstW width of lumSrc and alpSrc in pixels, number of pixels + * to write into dest[] + * @param y vertical line number for this output. This does not need + * to be used to calculate the offset in the destination, + * but can be used to generate comfort noise using dithering + * or some output formats. + */ +typedef void (*yuv2anyX_fn)(SwsInternal *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, + const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t **dest, + int dstW, int y); + +/** + * Unscaled conversion of luma/alpha plane to YV12 for horizontal scaler. + */ +typedef void (*planar1_YV12_fn)(uint8_t *dst, const uint8_t *src, const uint8_t *src2, + const uint8_t *src3, int width, uint32_t *pal, + void *opaque); + +/** + * Unscaled conversion of chroma plane to YV12 for horizontal scaler. + */ +typedef void (*planar2_YV12_fn)(uint8_t *dst, uint8_t *dst2, const uint8_t *src, + const uint8_t *src2, const uint8_t *src3, + int width, uint32_t *pal, void *opaque); + +/** + * Unscaled conversion of arbitrary planar data (e.g. RGBA) to YV12, through + * conversion using the given color matrix. + */ +typedef void (*planarX_YV12_fn)(uint8_t *dst, const uint8_t *src[4], int width, + int32_t *rgb2yuv, void *opaque); + +typedef void (*planarX2_YV12_fn)(uint8_t *dst, uint8_t *dst2, + const uint8_t *src[4], int width, + int32_t *rgb2yuv, void *opaque); + +struct SwsSlice; +struct SwsFilterDescriptor; + +/* This struct should be aligned on at least a 32-byte boundary. */ +struct SwsInternal { + /* Currently active user-facing options. Also contains AVClass */ + SwsContext opts; + + /* Parent context (for slice contexts) */ + SwsContext *parent; + + AVSliceThread *slicethread; + SwsContext **slice_ctx; + int *slice_err; + int nb_slice_ctx; + + /* Scaling graph, reinitialized dynamically as needed. */ + SwsGraph *graph[2]; /* top, bottom fields */ + + // values passed to current sws_receive_slice() call + int dst_slice_start; + int dst_slice_height; + + /** + * Note that src, dst, srcStride, dstStride will be copied in the + * sws_scale() wrapper so they can be freely modified here. + */ + SwsFunc convert_unscaled; + int chrSrcW; ///< Width of source chroma planes. + int chrSrcH; ///< Height of source chroma planes. + int chrDstW; ///< Width of destination chroma planes. + int chrDstH; ///< Height of destination chroma planes. + int lumXInc, chrXInc; + int lumYInc, chrYInc; + int dstFormatBpp; ///< Number of bits per pixel of the destination pixel format. + int srcFormatBpp; ///< Number of bits per pixel of the source pixel format. + int dstBpc, srcBpc; + int chrSrcHSubSample; ///< Binary logarithm of horizontal subsampling factor between luma/alpha and chroma planes in source image. + int chrSrcVSubSample; ///< Binary logarithm of vertical subsampling factor between luma/alpha and chroma planes in source image. + int chrDstHSubSample; ///< Binary logarithm of horizontal subsampling factor between luma/alpha and chroma planes in destination image. + int chrDstVSubSample; ///< Binary logarithm of vertical subsampling factor between luma/alpha and chroma planes in destination image. + int vChrDrop; ///< Binary logarithm of extra vertical subsampling factor in source image chroma planes specified by user. + int sliceDir; ///< Direction that slices are fed to the scaler (1 = top-to-bottom, -1 = bottom-to-top). + + AVFrame *frame_src; + AVFrame *frame_dst; + + RangeList src_ranges; + + /* The cascaded_* fields allow splitting a scaler task into multiple + * sequential steps, this is for example used to limit the maximum + * downscaling factor that needs to be supported in one scaler. + */ + SwsContext *cascaded_context[3]; + int cascaded_tmpStride[2][4]; + uint8_t *cascaded_tmp[2][4]; + int cascaded_mainindex; + + double gamma_value; + int is_internal_gamma; + uint16_t *gamma; + uint16_t *inv_gamma; + + int numDesc; + int descIndex[2]; + int numSlice; + struct SwsSlice *slice; + struct SwsFilterDescriptor *desc; + + uint32_t pal_yuv[256]; + uint32_t pal_rgb[256]; + + float uint2float_lut[256]; + + /** + * @name Scaled horizontal lines ring buffer. + * The horizontal scaler keeps just enough scaled lines in a ring buffer + * so they may be passed to the vertical scaler. The pointers to the + * allocated buffers for each line are duplicated in sequence in the ring + * buffer to simplify indexing and avoid wrapping around between lines + * inside the vertical scaler code. The wrapping is done before the + * vertical scaler is called. + */ + //@{ + int lastInLumBuf; ///< Last scaled horizontal luma/alpha line from source in the ring buffer. + int lastInChrBuf; ///< Last scaled horizontal chroma line from source in the ring buffer. + //@} + + uint8_t *formatConvBuffer; + int needAlpha; + + /** + * @name Horizontal and vertical filters. + * To better understand the following fields, here is a pseudo-code of + * their usage in filtering a horizontal line: + * @code + * for (i = 0; i < width; i++) { + * dst[i] = 0; + * for (j = 0; j < filterSize; j++) + * dst[i] += src[ filterPos[i] + j ] * filter[ filterSize * i + j ]; + * dst[i] >>= FRAC_BITS; // The actual implementation is fixed-point. + * } + * @endcode + */ + //@{ + int16_t *hLumFilter; ///< Array of horizontal filter coefficients for luma/alpha planes. + int16_t *hChrFilter; ///< Array of horizontal filter coefficients for chroma planes. + int16_t *vLumFilter; ///< Array of vertical filter coefficients for luma/alpha planes. + int16_t *vChrFilter; ///< Array of vertical filter coefficients for chroma planes. + int32_t *hLumFilterPos; ///< Array of horizontal filter starting positions for each dst[i] for luma/alpha planes. + int32_t *hChrFilterPos; ///< Array of horizontal filter starting positions for each dst[i] for chroma planes. + int32_t *vLumFilterPos; ///< Array of vertical filter starting positions for each dst[i] for luma/alpha planes. + int32_t *vChrFilterPos; ///< Array of vertical filter starting positions for each dst[i] for chroma planes. + int hLumFilterSize; ///< Horizontal filter size for luma/alpha pixels. + int hChrFilterSize; ///< Horizontal filter size for chroma pixels. + int vLumFilterSize; ///< Vertical filter size for luma/alpha pixels. + int vChrFilterSize; ///< Vertical filter size for chroma pixels. + //@} + + int lumMmxextFilterCodeSize; ///< Runtime-generated MMXEXT horizontal fast bilinear scaler code size for luma/alpha planes. + int chrMmxextFilterCodeSize; ///< Runtime-generated MMXEXT horizontal fast bilinear scaler code size for chroma planes. + uint8_t *lumMmxextFilterCode; ///< Runtime-generated MMXEXT horizontal fast bilinear scaler code for luma/alpha planes. + uint8_t *chrMmxextFilterCode; ///< Runtime-generated MMXEXT horizontal fast bilinear scaler code for chroma planes. + + int canMMXEXTBeUsed; + int warned_unuseable_bilinear; + + int dstY; ///< Last destination vertical line output from last slice. + void *yuvTable; // pointer to the yuv->rgb table start so it can be freed() + // alignment ensures the offset can be added in a single + // instruction on e.g. ARM + DECLARE_ALIGNED(16, int, table_gV)[256 + 2*YUVRGB_TABLE_HEADROOM]; + uint8_t *table_rV[256 + 2*YUVRGB_TABLE_HEADROOM]; + uint8_t *table_gU[256 + 2*YUVRGB_TABLE_HEADROOM]; + uint8_t *table_bU[256 + 2*YUVRGB_TABLE_HEADROOM]; + DECLARE_ALIGNED(16, int32_t, input_rgb2yuv_table)[16+40*4]; // This table can contain both C and SIMD formatted values, the C vales are always at the XY_IDX points +#define RY_IDX 0 +#define GY_IDX 1 +#define BY_IDX 2 +#define RU_IDX 3 +#define GU_IDX 4 +#define BU_IDX 5 +#define RV_IDX 6 +#define GV_IDX 7 +#define BV_IDX 8 +#define RGB2YUV_SHIFT 15 + + int *dither_error[4]; + + //Colorspace stuff + int contrast, brightness, saturation; // for sws_getColorspaceDetails + int srcColorspaceTable[4]; + int dstColorspaceTable[4]; + int src0Alpha; + int dst0Alpha; + int srcXYZ; + int dstXYZ; + int yuv2rgb_y_offset; + int yuv2rgb_y_coeff; + int yuv2rgb_v2r_coeff; + int yuv2rgb_v2g_coeff; + int yuv2rgb_u2g_coeff; + int yuv2rgb_u2b_coeff; + +#define RED_DITHER "0*8" +#define GREEN_DITHER "1*8" +#define BLUE_DITHER "2*8" +#define Y_COEFF "3*8" +#define VR_COEFF "4*8" +#define UB_COEFF "5*8" +#define VG_COEFF "6*8" +#define UG_COEFF "7*8" +#define Y_OFFSET "8*8" +#define U_OFFSET "9*8" +#define V_OFFSET "10*8" +#define LUM_MMX_FILTER_OFFSET "11*8" +#define CHR_MMX_FILTER_OFFSET "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE) +#define DSTW_OFFSET "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2" +#define ESP_OFFSET "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2+8" +#define VROUNDER_OFFSET "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2+16" +#define U_TEMP "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2+24" +#define V_TEMP "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2+32" +#define Y_TEMP "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2+40" +#define ALP_MMX_FILTER_OFFSET "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*2+48" +#define UV_OFF_PX "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*3+48" +#define UV_OFF_BYTE "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*3+56" +#define DITHER16 "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*3+64" +#define DITHER32 "11*8+4*4*"AV_STRINGIFY(MAX_FILTER_SIZE)"*3+80" +#define DITHER32_INT (11*8+4*4*MAX_FILTER_SIZE*3+80) // value equal to above, used for checking that the struct hasn't been changed by mistake + + DECLARE_ALIGNED(8, uint64_t, redDither); + DECLARE_ALIGNED(8, uint64_t, greenDither); + DECLARE_ALIGNED(8, uint64_t, blueDither); + + DECLARE_ALIGNED(8, uint64_t, yCoeff); + DECLARE_ALIGNED(8, uint64_t, vrCoeff); + DECLARE_ALIGNED(8, uint64_t, ubCoeff); + DECLARE_ALIGNED(8, uint64_t, vgCoeff); + DECLARE_ALIGNED(8, uint64_t, ugCoeff); + DECLARE_ALIGNED(8, uint64_t, yOffset); + DECLARE_ALIGNED(8, uint64_t, uOffset); + DECLARE_ALIGNED(8, uint64_t, vOffset); + int32_t lumMmxFilter[4 * MAX_FILTER_SIZE]; + int32_t chrMmxFilter[4 * MAX_FILTER_SIZE]; + int dstW_mmx; + DECLARE_ALIGNED(8, uint64_t, esp); + DECLARE_ALIGNED(8, uint64_t, vRounder); + DECLARE_ALIGNED(8, uint64_t, u_temp); + DECLARE_ALIGNED(8, uint64_t, v_temp); + DECLARE_ALIGNED(8, uint64_t, y_temp); + int32_t alpMmxFilter[4 * MAX_FILTER_SIZE]; + // alignment of these values is not necessary, but merely here + // to maintain the same offset across x8632 and x86-64. Once we + // use proper offset macros in the asm, they can be removed. + DECLARE_ALIGNED(8, ptrdiff_t, uv_off); ///< offset (in pixels) between u and v planes + DECLARE_ALIGNED(8, ptrdiff_t, uv_offx2); ///< offset (in bytes) between u and v planes + DECLARE_ALIGNED(8, uint16_t, dither16)[8]; + DECLARE_ALIGNED(8, uint32_t, dither32)[8]; + + const uint8_t *chrDither8, *lumDither8; + + int use_mmx_vfilter; + +/* pre defined color-spaces gamma */ +#define XYZ_GAMMA (2.6) +#define RGB_GAMMA (2.2) + SwsColorFunc xyz12Torgb48; + SwsColorFunc rgb48Toxyz12; + SwsColorXform xyz2rgb; + SwsColorXform rgb2xyz; + + /* function pointers for swscale() */ + yuv2planar1_fn yuv2plane1; + yuv2planarX_fn yuv2planeX; + yuv2interleavedX_fn yuv2nv12cX; + yuv2packed1_fn yuv2packed1; + yuv2packed2_fn yuv2packed2; + yuv2packedX_fn yuv2packedX; + yuv2anyX_fn yuv2anyX; + + /// Opaque data pointer passed to all input functions. + void *input_opaque; + + planar1_YV12_fn lumToYV12; + planar1_YV12_fn alpToYV12; + planar2_YV12_fn chrToYV12; + + /** + * Functions to read planar input, such as planar RGB, and convert + * internally to Y/UV/A. + */ + /** @{ */ + planarX_YV12_fn readLumPlanar; + planarX_YV12_fn readAlpPlanar; + planarX2_YV12_fn readChrPlanar; + /** @} */ + + /** + * Scale one horizontal line of input data using a bilinear filter + * to produce one line of output data. Compared to SwsInternal->hScale(), + * please take note of the following caveats when using these: + * - Scaling is done using only 7 bits instead of 14-bit coefficients. + * - You can use no more than 5 input pixels to produce 4 output + * pixels. Therefore, this filter should not be used for downscaling + * by more than ~20% in width (because that equals more than 5/4th + * downscaling and thus more than 5 pixels input per 4 pixels output). + * - In general, bilinear filters create artifacts during downscaling + * (even when <20%), because one output pixel will span more than one + * input pixel, and thus some pixels will need edges of both neighbor + * pixels to interpolate the output pixel. Since you can use at most + * two input pixels per output pixel in bilinear scaling, this is + * impossible and thus downscaling by any size will create artifacts. + * To enable this type of scaling, set SWS_FAST_BILINEAR + * in SwsInternal->flags. + */ + /** @{ */ + void (*hyscale_fast)(SwsInternal *c, + int16_t *dst, int dstWidth, + const uint8_t *src, int srcW, int xInc); + void (*hcscale_fast)(SwsInternal *c, + int16_t *dst1, int16_t *dst2, int dstWidth, + const uint8_t *src1, const uint8_t *src2, + int srcW, int xInc); + /** @} */ + + /** + * Scale one horizontal line of input data using a filter over the input + * lines, to produce one (differently sized) line of output data. + * + * @param dst pointer to destination buffer for horizontally scaled + * data. If the number of bits per component of one + * destination pixel (SwsInternal->dstBpc) is <= 10, data + * will be 15 bpc in 16 bits (int16_t) width. Else (i.e. + * SwsInternal->dstBpc == 16), data will be 19bpc in + * 32 bits (int32_t) width. + * @param dstW width of destination image + * @param src pointer to source data to be scaled. If the number of + * bits per component of a source pixel (SwsInternal->srcBpc) + * is 8, this is 8bpc in 8 bits (uint8_t) width. Else + * (i.e. SwsInternal->dstBpc > 8), this is native depth + * in 16 bits (uint16_t) width. In other words, for 9-bit + * YUV input, this is 9bpc, for 10-bit YUV input, this is + * 10bpc, and for 16-bit RGB or YUV, this is 16bpc. + * @param filter filter coefficients to be used per output pixel for + * scaling. This contains 14bpp filtering coefficients. + * Guaranteed to contain dstW * filterSize entries. + * @param filterPos position of the first input pixel to be used for + * each output pixel during scaling. Guaranteed to + * contain dstW entries. + * @param filterSize the number of input coefficients to be used (and + * thus the number of input pixels to be used) for + * creating a single output pixel. Is aligned to 4 + * (and input coefficients thus padded with zeroes) + * to simplify creating SIMD code. + */ + /** @{ */ + void (*hyScale)(SwsInternal *c, int16_t *dst, int dstW, + const uint8_t *src, const int16_t *filter, + const int32_t *filterPos, int filterSize); + void (*hcScale)(SwsInternal *c, int16_t *dst, int dstW, + const uint8_t *src, const int16_t *filter, + const int32_t *filterPos, int filterSize); + /** @} */ + + /** + * Color range conversion functions if needed. + * If SwsInternal->dstBpc is > 14: + * - int16_t *dst (data is 15 bpc) + * - uint16_t coeff + * - int32_t offset + * Otherwise (SwsInternal->dstBpc is <= 14): + * - int32_t *dst (data is 19 bpc) + * - uint32_t coeff + * - int64_t offset + */ + /** @{ */ + void (*lumConvertRange)(int16_t *dst, int width, + uint32_t coeff, int64_t offset); + void (*chrConvertRange)(int16_t *dst1, int16_t *dst2, int width, + uint32_t coeff, int64_t offset); + /** @} */ + + uint32_t lumConvertRange_coeff; + uint32_t chrConvertRange_coeff; + int64_t lumConvertRange_offset; + int64_t chrConvertRange_offset; + + int needs_hcscale; ///< Set if there are chroma planes to be converted. + + // scratch buffer for converting packed rgb0 sources + // filled with a copy of the input frame + fully opaque alpha, + // then passed as input to further conversion + uint8_t *rgb0_scratch; + unsigned int rgb0_scratch_allocated; + + // scratch buffer for converting XYZ sources + // filled with the input converted to rgb48 + // then passed as input to further conversion + uint8_t *xyz_scratch; + unsigned int xyz_scratch_allocated; + + unsigned int dst_slice_align; + atomic_int stride_unaligned_warned; + atomic_int data_unaligned_warned; + int color_conversion_warned; + + Half2FloatTables *h2f_tables; + + // Hardware specific private data + void *hw_priv; /* refstruct */ + + int is_legacy_init; +}; +//FIXME check init (where 0) + +static_assert(offsetof(SwsInternal, redDither) + DITHER32_INT == offsetof(SwsInternal, dither32), + "dither32 must be at the same offset as redDither + DITHER32_INT"); + +#if ARCH_X86_64 +/* x86 yuv2gbrp uses the SwsInternal for yuv coefficients + if struct offsets change the asm needs to be updated too */ +static_assert(offsetof(SwsInternal, yuv2rgb_y_offset) == 40348, + "yuv2rgb_y_offset must be updated in x86 asm"); +#endif + +SwsFunc ff_yuv2rgb_get_func_ptr(SwsInternal *c); +int ff_yuv2rgb_c_init_tables(SwsInternal *c, const int inv_table[4], + int fullRange, int brightness, + int contrast, int saturation); +void ff_yuv2rgb_init_tables_ppc(SwsInternal *c, const int inv_table[4], + int brightness, int contrast, int saturation); + +void ff_updateMMXDitherTables(SwsInternal *c, int dstY); + +void ff_update_palette(SwsInternal *c, const uint32_t *pal); + +av_cold void ff_sws_init_range_convert(SwsInternal *c); +av_cold void ff_sws_init_range_convert_aarch64(SwsInternal *c); +av_cold void ff_sws_init_range_convert_loongarch(SwsInternal *c); +av_cold void ff_sws_init_range_convert_riscv(SwsInternal *c); +av_cold void ff_sws_init_range_convert_x86(SwsInternal *c); + +av_cold void ff_sws_init_xyzdsp(SwsInternal *c); +av_cold void ff_sws_init_xyzdsp_aarch64(SwsInternal *c); + +av_cold int ff_sws_fill_xyztables(SwsInternal *c); + +SwsFunc ff_yuv2rgb_init_x86(SwsInternal *c); +SwsFunc ff_yuv2rgb_init_ppc(SwsInternal *c); +SwsFunc ff_yuv2rgb_init_loongarch(SwsInternal *c); +SwsFunc ff_yuv2rgb_init_aarch64(SwsInternal *c); + +static av_always_inline int is16BPS(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return desc->comp[0].depth == 16; +} + +static av_always_inline int is32BPS(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return desc->comp[0].depth == 32; +} + +static av_always_inline int isNBPS(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return desc->comp[0].depth >= 9 && desc->comp[0].depth <= 14; +} + +static av_always_inline int isBE(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return desc->flags & AV_PIX_FMT_FLAG_BE; +} + +static av_always_inline int isYUV(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return !(desc->flags & AV_PIX_FMT_FLAG_RGB) && desc->nb_components >= 2; +} + +static av_always_inline int isPlanarYUV(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return ((desc->flags & AV_PIX_FMT_FLAG_PLANAR) && isYUV(pix_fmt)); +} + +/* + * Identity semi-planar YUV formats. Specifically, those are YUV formats + * where the second and third components (U & V) are on the same plane. + */ +static av_always_inline int isSemiPlanarYUV(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return (isPlanarYUV(pix_fmt) && desc->comp[1].plane == desc->comp[2].plane); +} + +static av_always_inline int isRGB(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return (desc->flags & AV_PIX_FMT_FLAG_RGB); +} + +static av_always_inline int isGray(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return !(desc->flags & AV_PIX_FMT_FLAG_PAL) && + !(desc->flags & AV_PIX_FMT_FLAG_HWACCEL) && + desc->nb_components <= 2 && + pix_fmt != AV_PIX_FMT_MONOBLACK && + pix_fmt != AV_PIX_FMT_MONOWHITE; +} + +static av_always_inline int isRGBinInt(enum AVPixelFormat pix_fmt) +{ + return pix_fmt == AV_PIX_FMT_RGB48BE || + pix_fmt == AV_PIX_FMT_RGB48LE || + pix_fmt == AV_PIX_FMT_RGB32 || + pix_fmt == AV_PIX_FMT_RGB32_1 || + pix_fmt == AV_PIX_FMT_RGB24 || + pix_fmt == AV_PIX_FMT_RGB565BE || + pix_fmt == AV_PIX_FMT_RGB565LE || + pix_fmt == AV_PIX_FMT_RGB555BE || + pix_fmt == AV_PIX_FMT_RGB555LE || + pix_fmt == AV_PIX_FMT_RGB444BE || + pix_fmt == AV_PIX_FMT_RGB444LE || + pix_fmt == AV_PIX_FMT_RGB8 || + pix_fmt == AV_PIX_FMT_RGB4 || + pix_fmt == AV_PIX_FMT_RGB4_BYTE || + pix_fmt == AV_PIX_FMT_RGBA64BE || + pix_fmt == AV_PIX_FMT_RGBA64LE || + pix_fmt == AV_PIX_FMT_MONOBLACK || + pix_fmt == AV_PIX_FMT_MONOWHITE; +} + +static av_always_inline int isBGRinInt(enum AVPixelFormat pix_fmt) +{ + return pix_fmt == AV_PIX_FMT_BGR48BE || + pix_fmt == AV_PIX_FMT_BGR48LE || + pix_fmt == AV_PIX_FMT_BGR32 || + pix_fmt == AV_PIX_FMT_BGR32_1 || + pix_fmt == AV_PIX_FMT_BGR24 || + pix_fmt == AV_PIX_FMT_BGR565BE || + pix_fmt == AV_PIX_FMT_BGR565LE || + pix_fmt == AV_PIX_FMT_BGR555BE || + pix_fmt == AV_PIX_FMT_BGR555LE || + pix_fmt == AV_PIX_FMT_BGR444BE || + pix_fmt == AV_PIX_FMT_BGR444LE || + pix_fmt == AV_PIX_FMT_BGR8 || + pix_fmt == AV_PIX_FMT_BGR4 || + pix_fmt == AV_PIX_FMT_BGR4_BYTE || + pix_fmt == AV_PIX_FMT_BGRA64BE || + pix_fmt == AV_PIX_FMT_BGRA64LE || + pix_fmt == AV_PIX_FMT_MONOBLACK || + pix_fmt == AV_PIX_FMT_MONOWHITE; +} + +static av_always_inline int isBayer(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return !!(desc->flags & AV_PIX_FMT_FLAG_BAYER); +} + +static av_always_inline int isBayer16BPS(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return desc->comp[1].depth == 8; +} + +static av_always_inline int isAnyRGB(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return (desc->flags & AV_PIX_FMT_FLAG_RGB) || + pix_fmt == AV_PIX_FMT_MONOBLACK || pix_fmt == AV_PIX_FMT_MONOWHITE; +} + +static av_always_inline int isFloat(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return desc->flags & AV_PIX_FMT_FLAG_FLOAT; +} + +static av_always_inline int isFloat16(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return (desc->flags & AV_PIX_FMT_FLAG_FLOAT) && desc->comp[0].depth == 16; +} + +static av_always_inline int isALPHA(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + if (pix_fmt == AV_PIX_FMT_PAL8) + return 1; + return desc->flags & AV_PIX_FMT_FLAG_ALPHA; +} + +static av_always_inline int isPacked(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return (desc->nb_components >= 2 && !(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) || + pix_fmt == AV_PIX_FMT_PAL8 || + pix_fmt == AV_PIX_FMT_MONOBLACK || pix_fmt == AV_PIX_FMT_MONOWHITE; +} + +static av_always_inline int isPlanar(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return (desc->nb_components >= 2 && (desc->flags & AV_PIX_FMT_FLAG_PLANAR)); +} + +static av_always_inline int isPackedRGB(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return ((desc->flags & (AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB)) == AV_PIX_FMT_FLAG_RGB); +} + +static av_always_inline int isPlanarRGB(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return ((desc->flags & (AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB)) == + (AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB)); +} + +static av_always_inline int usePal(enum AVPixelFormat pix_fmt) +{ + switch (pix_fmt) { + case AV_PIX_FMT_PAL8: + case AV_PIX_FMT_BGR4_BYTE: + case AV_PIX_FMT_BGR8: + case AV_PIX_FMT_GRAY8: + case AV_PIX_FMT_RGB4_BYTE: + case AV_PIX_FMT_RGB8: + return 1; + default: + return 0; + } +} + +/* + * Identity formats where the data is in the high bits, and the low bits are shifted away. + */ +static av_always_inline int isDataInHighBits(enum AVPixelFormat pix_fmt) +{ + int i; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_HWACCEL)) + return 0; + for (i = 0; i < desc->nb_components; i++) { + if (!desc->comp[i].shift) + return 0; + if ((desc->comp[i].shift + desc->comp[i].depth) & 0x7) + return 0; + } + return 1; +} + +/* + * Identity formats where the chroma planes are swapped (CrCb order). + */ +static av_always_inline int isSwappedChroma(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + if (!isYUV(pix_fmt)) + return 0; + if ((desc->flags & AV_PIX_FMT_FLAG_ALPHA) && desc->nb_components < 4) + return 0; + if (desc->nb_components < 3) + return 0; + if (!isPlanarYUV(pix_fmt) || isSemiPlanarYUV(pix_fmt)) + return desc->comp[1].offset > desc->comp[2].offset; + else + return desc->comp[1].plane > desc->comp[2].plane; +} + +extern const uint64_t ff_dither4[2]; +extern const uint64_t ff_dither8[2]; + +extern const uint8_t ff_dither_2x2_4[3][8]; +extern const uint8_t ff_dither_2x2_8[3][8]; +extern const uint8_t ff_dither_4x4_16[5][8]; +extern const uint8_t ff_dither_8x8_32[9][8]; +extern const uint8_t ff_dither_8x8_73[9][8]; +extern const uint8_t ff_dither_8x8_128[9][8]; +extern const uint8_t ff_dither_8x8_220[9][8]; + +extern const int32_t ff_yuv2rgb_coeffs[11][4]; + +extern const AVClass ff_sws_context_class; + +int ff_sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter, + SwsFilter *dstFilter); + +/** + * Set c->convert_unscaled to an unscaled converter if one exists for the + * specific source and destination formats, bit depths, flags, etc. + */ +void ff_get_unscaled_swscale(SwsInternal *c); +void ff_get_unscaled_swscale_ppc(SwsInternal *c); +void ff_get_unscaled_swscale_arm(SwsInternal *c); +void ff_get_unscaled_swscale_aarch64(SwsInternal *c); + +void ff_sws_init_scale(SwsInternal *c); + +void ff_sws_init_input_funcs(SwsInternal *c, + planar1_YV12_fn *lumToYV12, + planar1_YV12_fn *alpToYV12, + planar2_YV12_fn *chrToYV12, + planarX_YV12_fn *readLumPlanar, + planarX_YV12_fn *readAlpPlanar, + planarX2_YV12_fn *readChrPlanar); +void ff_sws_init_output_funcs(SwsInternal *c, + yuv2planar1_fn *yuv2plane1, + yuv2planarX_fn *yuv2planeX, + yuv2interleavedX_fn *yuv2nv12cX, + yuv2packed1_fn *yuv2packed1, + yuv2packed2_fn *yuv2packed2, + yuv2packedX_fn *yuv2packedX, + yuv2anyX_fn *yuv2anyX); +void ff_sws_init_swscale_ppc(SwsInternal *c); +void ff_sws_init_swscale_vsx(SwsInternal *c); +void ff_sws_init_swscale_x86(SwsInternal *c); +void ff_sws_init_swscale_aarch64(SwsInternal *c); +void ff_sws_init_swscale_arm(SwsInternal *c); +void ff_sws_init_swscale_loongarch(SwsInternal *c); +void ff_sws_init_swscale_riscv(SwsInternal *c); + +int ff_sws_init_altivec_bufs(SwsInternal *c); +void ff_sws_free_altivec_bufs(SwsInternal *c); + +void ff_hyscale_fast_c(SwsInternal *c, int16_t *dst, int dstWidth, + const uint8_t *src, int srcW, int xInc); +void ff_hcscale_fast_c(SwsInternal *c, int16_t *dst1, int16_t *dst2, + int dstWidth, const uint8_t *src1, + const uint8_t *src2, int srcW, int xInc); +int ff_init_hscaler_mmxext(int dstW, int xInc, uint8_t *filterCode, + int16_t *filter, int32_t *filterPos, + int numSplits); +void ff_hyscale_fast_mmxext(SwsInternal *c, int16_t *dst, + int dstWidth, const uint8_t *src, + int srcW, int xInc); +void ff_hcscale_fast_mmxext(SwsInternal *c, int16_t *dst1, int16_t *dst2, + int dstWidth, const uint8_t *src1, + const uint8_t *src2, int srcW, int xInc); + +int ff_sws_alphablendaway(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]); + +void ff_copyPlane(const uint8_t *src, int srcStride, + int srcSliceY, int srcSliceH, int width, + uint8_t *dst, int dstStride); + +static inline void fillPlane16(uint8_t *plane, int stride, int width, int height, int y, + int alpha, int bits, const int big_endian) +{ + uint8_t *ptr = plane + stride * y; + int v = alpha ? 0xFFFF>>(16-bits) : (1<<(bits-1)); + if (big_endian != HAVE_BIGENDIAN) + v = av_bswap16(v); + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) + AV_WN16(ptr + 2 * j, v); + ptr += stride; + } +} + +static inline void fillPlane32(uint8_t *plane, int stride, int width, int height, int y, + int alpha, int bits, const int big_endian, int is_float) +{ + uint8_t *ptr = plane + stride * y; + uint32_t v; + uint32_t onef32 = 0x3f800000; + if (is_float) + v = alpha ? onef32 : 0; + else + v = alpha ? 0xFFFFFFFF>>(32-bits) : (1<<(bits-1)); + if (big_endian != HAVE_BIGENDIAN) + v = av_bswap32(v); + + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) + AV_WN32(ptr + 4 * j, v); + ptr += stride; + } +} + + +#define MAX_SLICE_PLANES 4 + +/// Slice plane +typedef struct SwsPlane +{ + int available_lines; ///< max number of lines that can be hold by this plane + int sliceY; ///< index of first line + int sliceH; ///< number of lines + uint8_t **line; ///< line buffer + uint8_t **tmp; ///< Tmp line buffer used by mmx code +} SwsPlane; + +/** + * Struct which defines a slice of an image to be scaled or an output for + * a scaled slice. + * A slice can also be used as intermediate ring buffer for scaling steps. + */ +typedef struct SwsSlice +{ + int width; ///< Slice line width + int h_chr_sub_sample; ///< horizontal chroma subsampling factor + int v_chr_sub_sample; ///< vertical chroma subsampling factor + int is_ring; ///< flag to identify if this slice is a ring buffer + int should_free_lines; ///< flag to identify if there are dynamic allocated lines + enum AVPixelFormat fmt; ///< planes pixel format + SwsPlane plane[MAX_SLICE_PLANES]; ///< color planes +} SwsSlice; + +/** + * Struct which holds all necessary data for processing a slice. + * A processing step can be a color conversion or horizontal/vertical scaling. + */ +typedef struct SwsFilterDescriptor +{ + SwsSlice *src; ///< Source slice + SwsSlice *dst; ///< Output slice + + int alpha; ///< Flag for processing alpha channel + void *instance; ///< Filter instance data + + /// Function for processing input slice sliceH lines starting from line sliceY + int (*process)(SwsInternal *c, struct SwsFilterDescriptor *desc, int sliceY, int sliceH); +} SwsFilterDescriptor; + +// warp input lines in the form (src + width*i + j) to slice format (line[i][j]) +// relative=true means first line src[x][0] otherwise first line is src[x][lum/crh Y] +int ff_init_slice_from_src(SwsSlice * s, uint8_t *const src[4], const int stride[4], + int srcW, int lumY, int lumH, int chrY, int chrH, int relative); + +// Initialize scaler filter descriptor chain +int ff_init_filters(SwsInternal *c); + +// Free all filter data +int ff_free_filters(SwsInternal *c); + +/* + function for applying ring buffer logic into slice s + It checks if the slice can hold more @lum lines, if yes + do nothing otherwise remove @lum least used lines. + It applies the same procedure for @chr lines. +*/ +int ff_rotate_slice(SwsSlice *s, int lum, int chr); + +/// initializes gamma conversion descriptor +int ff_init_gamma_convert(SwsFilterDescriptor *desc, SwsSlice * src, uint16_t *table); + +/// initializes lum pixel format conversion descriptor +int ff_init_desc_fmt_convert(SwsFilterDescriptor *desc, SwsSlice * src, SwsSlice *dst, uint32_t *pal); + +/// initializes lum horizontal scaling descriptor +int ff_init_desc_hscale(SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst, uint16_t *filter, int * filter_pos, int filter_size, int xInc); + +/// initializes chr pixel format conversion descriptor +int ff_init_desc_cfmt_convert(SwsFilterDescriptor *desc, SwsSlice * src, SwsSlice *dst, uint32_t *pal); + +/// initializes chr horizontal scaling descriptor +int ff_init_desc_chscale(SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst, uint16_t *filter, int * filter_pos, int filter_size, int xInc); + +int ff_init_desc_no_chr(SwsFilterDescriptor *desc, SwsSlice * src, SwsSlice *dst); + +/// initializes vertical scaling descriptors +int ff_init_vscale(SwsInternal *c, SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst); + +/// setup vertical scaler functions +void ff_init_vscale_pfn(SwsInternal *c, yuv2planar1_fn yuv2plane1, yuv2planarX_fn yuv2planeX, + yuv2interleavedX_fn yuv2nv12cX, yuv2packed1_fn yuv2packed1, yuv2packed2_fn yuv2packed2, + yuv2packedX_fn yuv2packedX, yuv2anyX_fn yuv2anyX, int use_mmx); + +void ff_sws_slice_worker(void *priv, int jobnr, int threadnr, + int nb_jobs, int nb_threads); + +int ff_swscale(SwsInternal *c, const uint8_t *const src[], const int srcStride[], + int srcSliceY, int srcSliceH, uint8_t *const dst[], + const int dstStride[], int dstSliceY, int dstSliceH); + + +//number of extra lines to process +#define MAX_LINES_AHEAD 4 + +//shuffle filter and filterPos for hyScale and hcScale filters in avx2 +int ff_shuffle_filter_coefficients(SwsInternal *c, int* filterPos, int filterSize, int16_t *filter, int dstW); +#endif /* SWSCALE_SWSCALE_INTERNAL_H */ diff --git a/libs/ffmpeg/libswscale/swscale_unscaled.c b/libs/ffmpeg/libswscale/swscale_unscaled.c new file mode 100644 index 00000000000..cd5e76cfc74 --- /dev/null +++ b/libs/ffmpeg/libswscale/swscale_unscaled.c @@ -0,0 +1,2720 @@ +/* + * Copyright (C) 2001-2011 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <inttypes.h> +#include <string.h> +#include <math.h> +#include <stdio.h> +#include "config.h" +#include "swscale.h" +#include "swscale_internal.h" +#include "rgb2rgb.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/avutil.h" +#include "libavutil/mathematics.h" +#include "libavutil/mem_internal.h" +#include "libavutil/bswap.h" +#include "libavutil/pixdesc.h" +#include "libavutil/avassert.h" +#include "libavutil/avconfig.h" + +DECLARE_ALIGNED(8, static const uint8_t, dithers)[8][8][8]={ +{ + { 0, 1, 0, 1, 0, 1, 0, 1,}, + { 1, 0, 1, 0, 1, 0, 1, 0,}, + { 0, 1, 0, 1, 0, 1, 0, 1,}, + { 1, 0, 1, 0, 1, 0, 1, 0,}, + { 0, 1, 0, 1, 0, 1, 0, 1,}, + { 1, 0, 1, 0, 1, 0, 1, 0,}, + { 0, 1, 0, 1, 0, 1, 0, 1,}, + { 1, 0, 1, 0, 1, 0, 1, 0,}, +},{ + { 1, 2, 1, 2, 1, 2, 1, 2,}, + { 3, 0, 3, 0, 3, 0, 3, 0,}, + { 1, 2, 1, 2, 1, 2, 1, 2,}, + { 3, 0, 3, 0, 3, 0, 3, 0,}, + { 1, 2, 1, 2, 1, 2, 1, 2,}, + { 3, 0, 3, 0, 3, 0, 3, 0,}, + { 1, 2, 1, 2, 1, 2, 1, 2,}, + { 3, 0, 3, 0, 3, 0, 3, 0,}, +},{ + { 2, 4, 3, 5, 2, 4, 3, 5,}, + { 6, 0, 7, 1, 6, 0, 7, 1,}, + { 3, 5, 2, 4, 3, 5, 2, 4,}, + { 7, 1, 6, 0, 7, 1, 6, 0,}, + { 2, 4, 3, 5, 2, 4, 3, 5,}, + { 6, 0, 7, 1, 6, 0, 7, 1,}, + { 3, 5, 2, 4, 3, 5, 2, 4,}, + { 7, 1, 6, 0, 7, 1, 6, 0,}, +},{ + { 4, 8, 7, 11, 4, 8, 7, 11,}, + { 12, 0, 15, 3, 12, 0, 15, 3,}, + { 6, 10, 5, 9, 6, 10, 5, 9,}, + { 14, 2, 13, 1, 14, 2, 13, 1,}, + { 4, 8, 7, 11, 4, 8, 7, 11,}, + { 12, 0, 15, 3, 12, 0, 15, 3,}, + { 6, 10, 5, 9, 6, 10, 5, 9,}, + { 14, 2, 13, 1, 14, 2, 13, 1,}, +},{ + { 9, 17, 15, 23, 8, 16, 14, 22,}, + { 25, 1, 31, 7, 24, 0, 30, 6,}, + { 13, 21, 11, 19, 12, 20, 10, 18,}, + { 29, 5, 27, 3, 28, 4, 26, 2,}, + { 8, 16, 14, 22, 9, 17, 15, 23,}, + { 24, 0, 30, 6, 25, 1, 31, 7,}, + { 12, 20, 10, 18, 13, 21, 11, 19,}, + { 28, 4, 26, 2, 29, 5, 27, 3,}, +},{ + { 18, 34, 30, 46, 17, 33, 29, 45,}, + { 50, 2, 62, 14, 49, 1, 61, 13,}, + { 26, 42, 22, 38, 25, 41, 21, 37,}, + { 58, 10, 54, 6, 57, 9, 53, 5,}, + { 16, 32, 28, 44, 19, 35, 31, 47,}, + { 48, 0, 60, 12, 51, 3, 63, 15,}, + { 24, 40, 20, 36, 27, 43, 23, 39,}, + { 56, 8, 52, 4, 59, 11, 55, 7,}, +},{ + { 18, 34, 30, 46, 17, 33, 29, 45,}, + { 50, 2, 62, 14, 49, 1, 61, 13,}, + { 26, 42, 22, 38, 25, 41, 21, 37,}, + { 58, 10, 54, 6, 57, 9, 53, 5,}, + { 16, 32, 28, 44, 19, 35, 31, 47,}, + { 48, 0, 60, 12, 51, 3, 63, 15,}, + { 24, 40, 20, 36, 27, 43, 23, 39,}, + { 56, 8, 52, 4, 59, 11, 55, 7,}, +},{ + { 36, 68, 60, 92, 34, 66, 58, 90,}, + { 100, 4,124, 28, 98, 2,122, 26,}, + { 52, 84, 44, 76, 50, 82, 42, 74,}, + { 116, 20,108, 12,114, 18,106, 10,}, + { 32, 64, 56, 88, 38, 70, 62, 94,}, + { 96, 0,120, 24,102, 6,126, 30,}, + { 48, 80, 40, 72, 54, 86, 46, 78,}, + { 112, 16,104, 8,118, 22,110, 14,}, +}}; + + +static void fillPlane(uint8_t *plane, int stride, int width, int height, int y, + uint8_t val) +{ + int i; + uint8_t *ptr = plane + stride * y; + for (i = 0; i < height; i++) { + memset(ptr, val, width); + ptr += stride; + } +} + +void ff_copyPlane(const uint8_t *src, int srcStride, + int srcSliceY, int srcSliceH, int width, + uint8_t *dst, int dstStride) +{ + if (!srcSliceH) + return; + av_assert0(srcSliceH > 0); + + dst += dstStride * srcSliceY; + if (dstStride == srcStride && srcStride > 0) { + memcpy(dst, src, (srcSliceH - 1) * dstStride + width); + } else { + int i; + for (i = 0; i < srcSliceH; i++) { + memcpy(dst, src, width); + src += srcStride; + dst += dstStride; + } + } +} + +static int planarToNv12Wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *const dstParam[], + const int dstStride[]) +{ + uint8_t *dst = dstParam[1] + dstStride[1] * srcSliceY / 2; + + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->opts.src_w, + dstParam[0], dstStride[0]); + + if (c->opts.dst_format == AV_PIX_FMT_NV12) + interleaveBytes(src[1], src[2], dst, c->chrSrcW, (srcSliceH + 1) / 2, + srcStride[1], srcStride[2], dstStride[1]); + else + interleaveBytes(src[2], src[1], dst, c->chrSrcW, (srcSliceH + 1) / 2, + srcStride[2], srcStride[1], dstStride[1]); + + return srcSliceH; +} + +static int nv12ToPlanarWrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *const dstParam[], + const int dstStride[]) +{ + uint8_t *dst1 = dstParam[1] + dstStride[1] * srcSliceY / 2; + uint8_t *dst2 = dstParam[2] + dstStride[2] * srcSliceY / 2; + + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->opts.src_w, + dstParam[0], dstStride[0]); + + if (c->opts.src_format == AV_PIX_FMT_NV12) + deinterleaveBytes(src[1], dst1, dst2, c->chrSrcW, (srcSliceH + 1) / 2, + srcStride[1], dstStride[1], dstStride[2]); + else + deinterleaveBytes(src[1], dst2, dst1, c->chrSrcW, (srcSliceH + 1) / 2, + srcStride[1], dstStride[2], dstStride[1]); + + return srcSliceH; +} + +static int planarToNv24Wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *const dstParam[], + const int dstStride[]) +{ + uint8_t *dst = dstParam[1] + dstStride[1] * srcSliceY; + + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->opts.src_w, + dstParam[0], dstStride[0]); + + if (c->opts.dst_format == AV_PIX_FMT_NV24) + interleaveBytes(src[1], src[2], dst, c->chrSrcW, srcSliceH, + srcStride[1], srcStride[2], dstStride[1]); + else + interleaveBytes(src[2], src[1], dst, c->chrSrcW, srcSliceH, + srcStride[2], srcStride[1], dstStride[1]); + + return srcSliceH; +} + +static int nv24ToPlanarWrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *const dstParam[], + const int dstStride[]) +{ + uint8_t *dst1 = dstParam[1] + dstStride[1] * srcSliceY; + uint8_t *dst2 = dstParam[2] + dstStride[2] * srcSliceY; + + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->opts.src_w, + dstParam[0], dstStride[0]); + + if (c->opts.src_format == AV_PIX_FMT_NV24) + deinterleaveBytes(src[1], dst1, dst2, c->chrSrcW, srcSliceH, + srcStride[1], dstStride[1], dstStride[2]); + else + deinterleaveBytes(src[1], dst2, dst1, c->chrSrcW, srcSliceH, + srcStride[1], dstStride[2], dstStride[1]); + + return srcSliceH; +} + +static void nv24_to_yuv420p_chroma(uint8_t *dst1, int dstStride1, + uint8_t *dst2, int dstStride2, + const uint8_t *src, int srcStride, + int w, int h) +{ + const uint8_t *src1 = src; + const uint8_t *src2 = src + srcStride; + // average 4 pixels into 1 (interleaved U and V) + for (int y = 0; y < h; y += 2) { + if (y + 1 == h) + src2 = src1; + for (int x = 0; x < w; x++) { + dst1[x] = (src1[4 * x + 0] + src1[4 * x + 2] + + src2[4 * x + 0] + src2[4 * x + 2]) >> 2; + dst2[x] = (src1[4 * x + 1] + src1[4 * x + 3] + + src2[4 * x + 1] + src2[4 * x + 3]) >> 2; + } + src1 += srcStride * 2; + src2 += srcStride * 2; + dst1 += dstStride1; + dst2 += dstStride2; + } +} + +static int nv24ToYuv420Wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dstParam[], const int dstStride[]) +{ + uint8_t *dst1 = dstParam[1] + dstStride[1] * srcSliceY / 2; + uint8_t *dst2 = dstParam[2] + dstStride[2] * srcSliceY / 2; + + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->opts.src_w, + dstParam[0], dstStride[0]); + + if (c->opts.src_format == AV_PIX_FMT_NV24) + nv24_to_yuv420p_chroma(dst1, dstStride[1], dst2, dstStride[2], + src[1], srcStride[1], c->opts.src_w / 2, srcSliceH); + else + nv24_to_yuv420p_chroma(dst2, dstStride[2], dst1, dstStride[1], + src[1], srcStride[1], c->opts.src_w / 2, srcSliceH); + + return srcSliceH; +} + +static int planarToP01xWrapper(SwsInternal *c, const uint8_t *const src8[], + const int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *const dstParam8[], + const int dstStride[]) +{ + const AVPixFmtDescriptor *src_format = av_pix_fmt_desc_get(c->opts.src_format); + const AVPixFmtDescriptor *dst_format = av_pix_fmt_desc_get(c->opts.dst_format); + const uint16_t **src = (const uint16_t**)src8; + uint16_t *dstY = (uint16_t*)(dstParam8[0] + dstStride[0] * srcSliceY); + uint16_t *dstUV = (uint16_t*)(dstParam8[1] + dstStride[1] * srcSliceY / 2); + int x, y; + + /* Calculate net shift required for values. */ + const int shift[3] = { + dst_format->comp[0].depth + dst_format->comp[0].shift - + src_format->comp[0].depth - src_format->comp[0].shift, + dst_format->comp[1].depth + dst_format->comp[1].shift - + src_format->comp[1].depth - src_format->comp[1].shift, + dst_format->comp[2].depth + dst_format->comp[2].shift - + src_format->comp[2].depth - src_format->comp[2].shift, + }; + + av_assert0(!(srcStride[0] % 2 || srcStride[1] % 2 || srcStride[2] % 2 || + dstStride[0] % 2 || dstStride[1] % 2)); + + for (y = 0; y < srcSliceH; y++) { + uint16_t *tdstY = dstY; + const uint16_t *tsrc0 = src[0]; + for (x = c->opts.src_w; x > 0; x--) { + *tdstY++ = *tsrc0++ << shift[0]; + } + src[0] += srcStride[0] / 2; + dstY += dstStride[0] / 2; + + if (!(y & 1)) { + uint16_t *tdstUV = dstUV; + const uint16_t *tsrc1 = src[1]; + const uint16_t *tsrc2 = src[2]; + for (x = c->opts.src_w / 2; x > 0; x--) { + *tdstUV++ = *tsrc1++ << shift[1]; + *tdstUV++ = *tsrc2++ << shift[2]; + } + src[1] += srcStride[1] / 2; + src[2] += srcStride[2] / 2; + dstUV += dstStride[1] / 2; + } + } + + return srcSliceH; +} + +#if AV_HAVE_BIGENDIAN +#define output_pixel(p, v) do { \ + uint16_t *pp = (p); \ + AV_WL16(pp, (v)); \ + } while(0) +#else +#define output_pixel(p, v) (*p) = (v) +#endif + +static int planar8ToP01xleWrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *const dstParam8[], + const int dstStride[]) +{ + const uint8_t *src0 = src[0], *src1 = src[1], *src2 = src[2]; + uint16_t *dstY = (uint16_t*)(dstParam8[0] + dstStride[0] * srcSliceY); + uint16_t *dstUV = (uint16_t*)(dstParam8[1] + dstStride[1] * srcSliceY / 2); + int x, y, t; + + av_assert0(!(dstStride[0] % 2 || dstStride[1] % 2)); + + for (y = 0; y < srcSliceH; y++) { + uint16_t *tdstY = dstY; + const uint8_t *tsrc0 = src0; + for (x = c->opts.src_w; x > 0; x--) { + t = *tsrc0++; + output_pixel(tdstY++, t << 8); + } + src0 += srcStride[0]; + dstY += dstStride[0] / 2; + + if (!(y & 1)) { + uint16_t *tdstUV = dstUV; + const uint8_t *tsrc1 = src1; + const uint8_t *tsrc2 = src2; + for (x = c->opts.src_w / 2; x > 0; x--) { + t = *tsrc1++; + output_pixel(tdstUV++, t << 8); + t = *tsrc2++; + output_pixel(tdstUV++, t << 8); + } + src1 += srcStride[1]; + src2 += srcStride[2]; + dstUV += dstStride[1] / 2; + } + } + + return srcSliceH; +} + +#undef output_pixel + +static int planarToYuy2Wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dstParam[], const int dstStride[]) +{ + uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY; + + yv12toyuy2(src[0], src[1], src[2], dst, c->opts.src_w, srcSliceH, srcStride[0], + srcStride[1], dstStride[0]); + + return srcSliceH; +} + +static int planarToUyvyWrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dstParam[], const int dstStride[]) +{ + uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY; + + yv12touyvy(src[0], src[1], src[2], dst, c->opts.src_w, srcSliceH, srcStride[0], + srcStride[1], dstStride[0]); + + return srcSliceH; +} + +static int yuv422pToYuy2Wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dstParam[], const int dstStride[]) +{ + uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY; + + yuv422ptoyuy2(src[0], src[1], src[2], dst, c->opts.src_w, srcSliceH, srcStride[0], + srcStride[1], dstStride[0]); + + return srcSliceH; +} + +static int yuv422pToUyvyWrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dstParam[], const int dstStride[]) +{ + uint8_t *dst = dstParam[0] + dstStride[0] * srcSliceY; + + yuv422ptouyvy(src[0], src[1], src[2], dst, c->opts.src_w, srcSliceH, srcStride[0], + srcStride[1], dstStride[0]); + + return srcSliceH; +} + +static int yuyvToYuv420Wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dstParam[], const int dstStride[]) +{ + uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY; + uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY / 2; + uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY / 2; + + yuyvtoyuv420(ydst, udst, vdst, src[0], c->opts.src_w, srcSliceH, dstStride[0], + dstStride[1], srcStride[0]); + + if (dstParam[3]) + fillPlane(dstParam[3], dstStride[3], c->opts.src_w, srcSliceH, srcSliceY, 255); + + return srcSliceH; +} + +static int yuyvToYuv422Wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dstParam[], const int dstStride[]) +{ + uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY; + uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY; + uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY; + + yuyvtoyuv422(ydst, udst, vdst, src[0], c->opts.src_w, srcSliceH, dstStride[0], + dstStride[1], srcStride[0]); + + return srcSliceH; +} + +static int uyvyToYuv420Wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dstParam[], const int dstStride[]) +{ + uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY; + uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY / 2; + uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY / 2; + + uyvytoyuv420(ydst, udst, vdst, src[0], c->opts.src_w, srcSliceH, dstStride[0], + dstStride[1], srcStride[0]); + + if (dstParam[3]) + fillPlane(dstParam[3], dstStride[3], c->opts.src_w, srcSliceH, srcSliceY, 255); + + return srcSliceH; +} + +static int uyvyToYuv422Wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dstParam[], const int dstStride[]) +{ + uint8_t *ydst = dstParam[0] + dstStride[0] * srcSliceY; + uint8_t *udst = dstParam[1] + dstStride[1] * srcSliceY; + uint8_t *vdst = dstParam[2] + dstStride[2] * srcSliceY; + + uyvytoyuv422(ydst, udst, vdst, src[0], c->opts.src_w, srcSliceH, dstStride[0], + dstStride[1], srcStride[0]); + + return srcSliceH; +} + +static void gray8aToPacked32(const uint8_t *src, uint8_t *dst, int num_pixels, + const uint8_t *palette) +{ + int i; + for (i = 0; i < num_pixels; i++) + ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i << 1]] | (src[(i << 1) + 1] << 24); +} + +static void gray8aToPacked32_1(const uint8_t *src, uint8_t *dst, int num_pixels, + const uint8_t *palette) +{ + int i; + + for (i = 0; i < num_pixels; i++) + ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i << 1]] | src[(i << 1) + 1]; +} + +static void gray8aToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels, + const uint8_t *palette) +{ + int i; + + for (i = 0; i < num_pixels; i++) { + //FIXME slow? + dst[0] = palette[src[i << 1] * 4 + 0]; + dst[1] = palette[src[i << 1] * 4 + 1]; + dst[2] = palette[src[i << 1] * 4 + 2]; + dst += 3; + } +} + +static void gray8aToPlanar8(const uint8_t *src, uint8_t *dst0, uint8_t *dst1, + uint8_t *dst2, uint8_t *dstA, int num_pixels, + const uint8_t *palette) +{ + for (int i = 0; i < num_pixels; i++) { + const uint8_t *rgb = &palette[src[i << 1] * 4]; + dst0[i] = rgb[0]; + dst1[i] = rgb[1]; + dst2[i] = rgb[2]; + if (dstA) + dstA[i] = src[(i << 1) + 1]; + } +} + +static void pal8ToPlanar8(const uint8_t *src, uint8_t *dst0, uint8_t *dst1, + uint8_t *dst2, uint8_t *dstA, int num_pixels, + const uint8_t *palette) +{ + for (int i = 0; i < num_pixels; i++) { + const uint8_t *rgba = &palette[src[i] * 4]; + dst0[i] = rgba[0]; + dst1[i] = rgba[1]; + dst2[i] = rgba[2]; + if (dstA) + dstA[i] = rgba[3]; + } +} + +static int bswap_16bpc(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + int i, j, p; + + for (p = 0; p < 4; p++) { + int srcstr = srcStride[p] / 2; + int dststr = dstStride[p] / 2; + uint16_t *dstPtr = (uint16_t *) dst[p]; + const uint16_t *srcPtr = (const uint16_t *) src[p]; + int min_stride = FFMIN(FFABS(srcstr), FFABS(dststr)); + if(!dstPtr || !srcPtr) + continue; + dstPtr += (srcSliceY >> c->chrDstVSubSample) * dststr; + for (i = 0; i < (srcSliceH >> c->chrDstVSubSample); i++) { + for (j = 0; j < min_stride; j++) { + dstPtr[j] = av_bswap16(srcPtr[j]); + } + srcPtr += srcstr; + dstPtr += dststr; + } + } + + return srcSliceH; +} + +static int bswap_32bpc(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + int i, j, p; + + for (p = 0; p < 4; p++) { + int srcstr = srcStride[p] / 4; + int dststr = dstStride[p] / 4; + uint32_t *dstPtr = (uint32_t *) dst[p]; + const uint32_t *srcPtr = (const uint32_t *) src[p]; + int min_stride = FFMIN(FFABS(srcstr), FFABS(dststr)); + if(!dstPtr || !srcPtr) + continue; + dstPtr += (srcSliceY >> c->chrDstVSubSample) * dststr; + for (i = 0; i < (srcSliceH >> c->chrDstVSubSample); i++) { + for (j = 0; j < min_stride; j++) { + dstPtr[j] = av_bswap32(srcPtr[j]); + } + srcPtr += srcstr; + dstPtr += dststr; + } + } + + return srcSliceH; +} + + +static int palToRgbWrapper(SwsInternal *c, const uint8_t *const src[], const int srcStride[], + int srcSliceY, int srcSliceH, uint8_t *const dst[], + const int dstStride[]) +{ + const enum AVPixelFormat srcFormat = c->opts.src_format; + const enum AVPixelFormat dstFormat = c->opts.dst_format; + void (*conv)(const uint8_t *src, uint8_t *dst, int num_pixels, + const uint8_t *palette) = NULL; + int i; + uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY; + const uint8_t *srcPtr = src[0]; + + if (srcFormat == AV_PIX_FMT_YA8) { + switch (dstFormat) { + case AV_PIX_FMT_RGB32 : conv = gray8aToPacked32; break; + case AV_PIX_FMT_BGR32 : conv = gray8aToPacked32; break; + case AV_PIX_FMT_BGR32_1: conv = gray8aToPacked32_1; break; + case AV_PIX_FMT_RGB32_1: conv = gray8aToPacked32_1; break; + case AV_PIX_FMT_RGB24 : conv = gray8aToPacked24; break; + case AV_PIX_FMT_BGR24 : conv = gray8aToPacked24; break; + } + } else if (usePal(srcFormat)) { + switch (dstFormat) { + case AV_PIX_FMT_RGB32 : conv = sws_convertPalette8ToPacked32; break; + case AV_PIX_FMT_BGR32 : conv = sws_convertPalette8ToPacked32; break; + case AV_PIX_FMT_BGR32_1: conv = sws_convertPalette8ToPacked32; break; + case AV_PIX_FMT_RGB32_1: conv = sws_convertPalette8ToPacked32; break; + case AV_PIX_FMT_RGB24 : conv = sws_convertPalette8ToPacked24; break; + case AV_PIX_FMT_BGR24 : conv = sws_convertPalette8ToPacked24; break; + } + } + + if (!conv) + av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n", + av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat)); + else { + for (i = 0; i < srcSliceH; i++) { + conv(srcPtr, dstPtr, c->opts.src_w, (uint8_t *) c->pal_rgb); + srcPtr += srcStride[0]; + dstPtr += dstStride[0]; + } + } + + return srcSliceH; +} + +static int palToGbrpWrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + const enum AVPixelFormat srcFormat = c->opts.src_format; + const enum AVPixelFormat dstFormat = c->opts.dst_format; + void (*conv)(const uint8_t *src, uint8_t *dstG, uint8_t *dstB, uint8_t *dstR, + uint8_t *dstA, int num_pixels, const uint8_t *palette) = NULL; + + const int num_planes = isALPHA(dstFormat) ? 4 : 3; + const uint8_t *srcPtr = src[0]; + uint8_t *dstPtr[4] = {0}; + for (int i = 0; i < num_planes; i++) + dstPtr[i] = dst[i] + dstStride[i] * srcSliceY; + + if (srcFormat == AV_PIX_FMT_YA8) { + switch (dstFormat) { + case AV_PIX_FMT_GBRP: conv = gray8aToPlanar8; break; + case AV_PIX_FMT_GBRAP: conv = gray8aToPlanar8; break; + } + } else if (usePal(srcFormat)) { + switch (dstFormat) { + case AV_PIX_FMT_GBRP: conv = pal8ToPlanar8; break; + case AV_PIX_FMT_GBRAP: conv = pal8ToPlanar8; break; + } + } + + av_assert1(conv); + for (int y = 0; y < srcSliceH; y++) { + conv(srcPtr, dstPtr[0], dstPtr[1], dstPtr[2], dstPtr[3], c->opts.src_w, + (uint8_t *) c->pal_rgb); + srcPtr += srcStride[0]; + for (int i = 0; i < num_planes; i++) + dstPtr[i] += dstStride[i]; + } + + return srcSliceH; +} + +static void packed16togbra16(const uint8_t *src, int srcStride, + uint16_t *dst[], const int dstStride[], int srcSliceH, + int src_alpha, int swap, int shift, int width) +{ + int x, h, i; + int dst_alpha = dst[3] != NULL; + for (h = 0; h < srcSliceH; h++) { + uint16_t *src_line = (uint16_t *)(src + srcStride * h); + switch (swap) { + case 3: + if (src_alpha && dst_alpha) { + for (x = 0; x < width; x++) { + dst[0][x] = av_bswap16(av_bswap16(*src_line++) >> shift); + dst[1][x] = av_bswap16(av_bswap16(*src_line++) >> shift); + dst[2][x] = av_bswap16(av_bswap16(*src_line++) >> shift); + dst[3][x] = av_bswap16(av_bswap16(*src_line++) >> shift); + } + } else if (dst_alpha) { + for (x = 0; x < width; x++) { + dst[0][x] = av_bswap16(av_bswap16(*src_line++) >> shift); + dst[1][x] = av_bswap16(av_bswap16(*src_line++) >> shift); + dst[2][x] = av_bswap16(av_bswap16(*src_line++) >> shift); + dst[3][x] = av_bswap16(0xFFFF >> shift); + } + } else if (src_alpha) { + for (x = 0; x < width; x++) { + dst[0][x] = av_bswap16(av_bswap16(*src_line++) >> shift); + dst[1][x] = av_bswap16(av_bswap16(*src_line++) >> shift); + dst[2][x] = av_bswap16(av_bswap16(*src_line++) >> shift); + src_line++; + } + } else { + for (x = 0; x < width; x++) { + dst[0][x] = av_bswap16(av_bswap16(*src_line++) >> shift); + dst[1][x] = av_bswap16(av_bswap16(*src_line++) >> shift); + dst[2][x] = av_bswap16(av_bswap16(*src_line++) >> shift); + } + } + break; + case 2: + if (src_alpha && dst_alpha) { + for (x = 0; x < width; x++) { + dst[0][x] = av_bswap16(*src_line++ >> shift); + dst[1][x] = av_bswap16(*src_line++ >> shift); + dst[2][x] = av_bswap16(*src_line++ >> shift); + dst[3][x] = av_bswap16(*src_line++ >> shift); + } + } else if (dst_alpha) { + for (x = 0; x < width; x++) { + dst[0][x] = av_bswap16(*src_line++ >> shift); + dst[1][x] = av_bswap16(*src_line++ >> shift); + dst[2][x] = av_bswap16(*src_line++ >> shift); + dst[3][x] = av_bswap16(0xFFFF >> shift); + } + } else if (src_alpha) { + for (x = 0; x < width; x++) { + dst[0][x] = av_bswap16(*src_line++ >> shift); + dst[1][x] = av_bswap16(*src_line++ >> shift); + dst[2][x] = av_bswap16(*src_line++ >> shift); + src_line++; + } + } else { + for (x = 0; x < width; x++) { + dst[0][x] = av_bswap16(*src_line++ >> shift); + dst[1][x] = av_bswap16(*src_line++ >> shift); + dst[2][x] = av_bswap16(*src_line++ >> shift); + } + } + break; + case 1: + if (src_alpha && dst_alpha) { + for (x = 0; x < width; x++) { + dst[0][x] = av_bswap16(*src_line++) >> shift; + dst[1][x] = av_bswap16(*src_line++) >> shift; + dst[2][x] = av_bswap16(*src_line++) >> shift; + dst[3][x] = av_bswap16(*src_line++) >> shift; + } + } else if (dst_alpha) { + for (x = 0; x < width; x++) { + dst[0][x] = av_bswap16(*src_line++) >> shift; + dst[1][x] = av_bswap16(*src_line++) >> shift; + dst[2][x] = av_bswap16(*src_line++) >> shift; + dst[3][x] = 0xFFFF >> shift; + } + } else if (src_alpha) { + for (x = 0; x < width; x++) { + dst[0][x] = av_bswap16(*src_line++) >> shift; + dst[1][x] = av_bswap16(*src_line++) >> shift; + dst[2][x] = av_bswap16(*src_line++) >> shift; + src_line++; + } + } else { + for (x = 0; x < width; x++) { + dst[0][x] = av_bswap16(*src_line++) >> shift; + dst[1][x] = av_bswap16(*src_line++) >> shift; + dst[2][x] = av_bswap16(*src_line++) >> shift; + } + } + break; + default: + if (src_alpha && dst_alpha) { + for (x = 0; x < width; x++) { + dst[0][x] = *src_line++ >> shift; + dst[1][x] = *src_line++ >> shift; + dst[2][x] = *src_line++ >> shift; + dst[3][x] = *src_line++ >> shift; + } + } else if (dst_alpha) { + for (x = 0; x < width; x++) { + dst[0][x] = *src_line++ >> shift; + dst[1][x] = *src_line++ >> shift; + dst[2][x] = *src_line++ >> shift; + dst[3][x] = 0xFFFF >> shift; + } + } else if (src_alpha) { + for (x = 0; x < width; x++) { + dst[0][x] = *src_line++ >> shift; + dst[1][x] = *src_line++ >> shift; + dst[2][x] = *src_line++ >> shift; + src_line++; + } + } else { + for (x = 0; x < width; x++) { + dst[0][x] = *src_line++ >> shift; + dst[1][x] = *src_line++ >> shift; + dst[2][x] = *src_line++ >> shift; + } + } + } + for (i = 0; i < 4 && dst[i]; i++) + dst[i] += dstStride[i] >> 1; + } +} + +static void packed30togbra10(const uint8_t *src, int srcStride, + uint16_t *dst[], const int dstStride[], int srcSliceH, + int swap, int bpc, int width) +{ + int x, h, i; + int dst_alpha = dst[3] != NULL; + int scale_high = bpc - 10, scale_low = 10 - scale_high; + uint16_t alpha_val = (1U << bpc) - 1; + for (h = 0; h < srcSliceH; h++) { + uint32_t *src_line = (uint32_t *)(src + srcStride * h); + unsigned component; + + switch (swap) { + case 3: + case 2: + if (dst_alpha) { + for (x = 0; x < width; x++) { + unsigned p = AV_RL32(src_line); + component = (p >> 20) & 0x3FF; + dst[0][x] = av_bswap16(component << scale_high | component >> scale_low); + component = (p >> 10) & 0x3FF; + dst[1][x] = av_bswap16(component << scale_high | component >> scale_low); + component = p & 0x3FF; + dst[2][x] = av_bswap16(component << scale_high | component >> scale_low); + dst[3][x] = av_bswap16(alpha_val); + src_line++; + } + } else { + for (x = 0; x < width; x++) { + unsigned p = AV_RL32(src_line); + component = (p >> 20) & 0x3FF; + dst[0][x] = av_bswap16(component << scale_high | component >> scale_low); + component = (p >> 10) & 0x3FF; + dst[1][x] = av_bswap16(component << scale_high | component >> scale_low); + component = p & 0x3FF; + dst[2][x] = av_bswap16(component << scale_high | component >> scale_low); + src_line++; + } + } + break; + default: + if (dst_alpha) { + for (x = 0; x < width; x++) { + unsigned p = AV_RL32(src_line); + component = (p >> 20) & 0x3FF; + dst[0][x] = component << scale_high | component >> scale_low; + component = (p >> 10) & 0x3FF; + dst[1][x] = component << scale_high | component >> scale_low; + component = p & 0x3FF; + dst[2][x] = component << scale_high | component >> scale_low; + dst[3][x] = alpha_val; + src_line++; + } + } else { + for (x = 0; x < width; x++) { + unsigned p = AV_RL32(src_line); + component = (p >> 20) & 0x3FF; + dst[0][x] = component << scale_high | component >> scale_low; + component = (p >> 10) & 0x3FF; + dst[1][x] = component << scale_high | component >> scale_low; + component = p & 0x3FF; + dst[2][x] = component << scale_high | component >> scale_low; + src_line++; + } + } + break; + } + for (i = 0; i < 4 && dst[i]; i++) + dst[i] += dstStride[i] >> 1; + } +} + +static int Rgb16ToPlanarRgb16Wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + uint16_t *dst2013[] = { (uint16_t *)dst[2], (uint16_t *)dst[0], (uint16_t *)dst[1], (uint16_t *)dst[3] }; + uint16_t *dst1023[] = { (uint16_t *)dst[1], (uint16_t *)dst[0], (uint16_t *)dst[2], (uint16_t *)dst[3] }; + int stride2013[] = { dstStride[2], dstStride[0], dstStride[1], dstStride[3] }; + int stride1023[] = { dstStride[1], dstStride[0], dstStride[2], dstStride[3] }; + const AVPixFmtDescriptor *src_format = av_pix_fmt_desc_get(c->opts.src_format); + const AVPixFmtDescriptor *dst_format = av_pix_fmt_desc_get(c->opts.dst_format); + int bpc = dst_format->comp[0].depth; + int alpha = src_format->flags & AV_PIX_FMT_FLAG_ALPHA; + int swap = 0; + int i; + + if ( HAVE_BIGENDIAN && !(src_format->flags & AV_PIX_FMT_FLAG_BE) || + !HAVE_BIGENDIAN && src_format->flags & AV_PIX_FMT_FLAG_BE) + swap++; + if ( HAVE_BIGENDIAN && !(dst_format->flags & AV_PIX_FMT_FLAG_BE) || + !HAVE_BIGENDIAN && dst_format->flags & AV_PIX_FMT_FLAG_BE) + swap += 2; + + if ((dst_format->flags & (AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB)) != + (AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB) || bpc < 9) { + av_log(c, AV_LOG_ERROR, "unsupported conversion to planar RGB %s -> %s\n", + src_format->name, dst_format->name); + return srcSliceH; + } + + for (i = 0; i < 4 && dst[i]; i++) { + dst2013[i] += stride2013[i] * srcSliceY / 2; + dst1023[i] += stride1023[i] * srcSliceY / 2; + } + + switch (c->opts.src_format) { + case AV_PIX_FMT_RGB48LE: + case AV_PIX_FMT_RGB48BE: + case AV_PIX_FMT_RGBA64LE: + case AV_PIX_FMT_RGBA64BE: + packed16togbra16(src[0], srcStride[0], + dst2013, stride2013, srcSliceH, alpha, swap, + 16 - bpc, c->opts.src_w); + break; + case AV_PIX_FMT_X2RGB10LE: + av_assert0(bpc >= 10); + packed30togbra10(src[0], srcStride[0], + dst2013, stride2013, srcSliceH, swap, + bpc, c->opts.src_w); + break; + case AV_PIX_FMT_BGR48LE: + case AV_PIX_FMT_BGR48BE: + case AV_PIX_FMT_BGRA64LE: + case AV_PIX_FMT_BGRA64BE: + packed16togbra16(src[0], srcStride[0], + dst1023, stride1023, srcSliceH, alpha, swap, + 16 - bpc, c->opts.src_w); + break; + case AV_PIX_FMT_X2BGR10LE: + av_assert0(bpc >= 10); + packed30togbra10(src[0], srcStride[0], + dst1023, stride1023, srcSliceH, swap, + bpc, c->opts.src_w); + break; + default: + av_log(c, AV_LOG_ERROR, + "unsupported conversion to planar RGB %s -> %s\n", + src_format->name, dst_format->name); + } + + return srcSliceH; +} + +static void gbr16ptopacked16(const uint16_t *src[], const int srcStride[], + uint8_t *dst, int dstStride, int srcSliceH, + int alpha, int swap, int bpp, int width) +{ + int x, h, i; + int src_alpha = src[3] != NULL; + int scale_high = 16 - bpp, scale_low = (bpp - 8) * 2; + for (h = 0; h < srcSliceH; h++) { + uint16_t *dest = (uint16_t *)(dst + dstStride * h); + uint16_t component; + + switch(swap) { + case 3: + if (alpha && !src_alpha) { + for (x = 0; x < width; x++) { + component = av_bswap16(src[0][x]); + *dest++ = av_bswap16(component << scale_high | component >> scale_low); + component = av_bswap16(src[1][x]); + *dest++ = av_bswap16(component << scale_high | component >> scale_low); + component = av_bswap16(src[2][x]); + *dest++ = av_bswap16(component << scale_high | component >> scale_low); + *dest++ = 0xffff; + } + } else if (alpha && src_alpha) { + for (x = 0; x < width; x++) { + component = av_bswap16(src[0][x]); + *dest++ = av_bswap16(component << scale_high | component >> scale_low); + component = av_bswap16(src[1][x]); + *dest++ = av_bswap16(component << scale_high | component >> scale_low); + component = av_bswap16(src[2][x]); + *dest++ = av_bswap16(component << scale_high | component >> scale_low); + component = av_bswap16(src[3][x]); + *dest++ = av_bswap16(component << scale_high | component >> scale_low); + } + } else { + for (x = 0; x < width; x++) { + component = av_bswap16(src[0][x]); + *dest++ = av_bswap16(component << scale_high | component >> scale_low); + component = av_bswap16(src[1][x]); + *dest++ = av_bswap16(component << scale_high | component >> scale_low); + component = av_bswap16(src[2][x]); + *dest++ = av_bswap16(component << scale_high | component >> scale_low); + } + } + break; + case 2: + if (alpha && !src_alpha) { + for (x = 0; x < width; x++) { + *dest++ = av_bswap16(src[0][x] << scale_high | src[0][x] >> scale_low); + *dest++ = av_bswap16(src[1][x] << scale_high | src[1][x] >> scale_low); + *dest++ = av_bswap16(src[2][x] << scale_high | src[2][x] >> scale_low); + *dest++ = 0xffff; + } + } else if (alpha && src_alpha) { + for (x = 0; x < width; x++) { + *dest++ = av_bswap16(src[0][x] << scale_high | src[0][x] >> scale_low); + *dest++ = av_bswap16(src[1][x] << scale_high | src[1][x] >> scale_low); + *dest++ = av_bswap16(src[2][x] << scale_high | src[2][x] >> scale_low); + *dest++ = av_bswap16(src[3][x] << scale_high | src[3][x] >> scale_low); + } + } else { + for (x = 0; x < width; x++) { + *dest++ = av_bswap16(src[0][x] << scale_high | src[0][x] >> scale_low); + *dest++ = av_bswap16(src[1][x] << scale_high | src[1][x] >> scale_low); + *dest++ = av_bswap16(src[2][x] << scale_high | src[2][x] >> scale_low); + } + } + break; + case 1: + if (alpha && !src_alpha) { + for (x = 0; x < width; x++) { + *dest++ = av_bswap16(src[0][x]) << scale_high | av_bswap16(src[0][x]) >> scale_low; + *dest++ = av_bswap16(src[1][x]) << scale_high | av_bswap16(src[1][x]) >> scale_low; + *dest++ = av_bswap16(src[2][x]) << scale_high | av_bswap16(src[2][x]) >> scale_low; + *dest++ = 0xffff; + } + } else if (alpha && src_alpha) { + for (x = 0; x < width; x++) { + *dest++ = av_bswap16(src[0][x]) << scale_high | av_bswap16(src[0][x]) >> scale_low; + *dest++ = av_bswap16(src[1][x]) << scale_high | av_bswap16(src[1][x]) >> scale_low; + *dest++ = av_bswap16(src[2][x]) << scale_high | av_bswap16(src[2][x]) >> scale_low; + *dest++ = av_bswap16(src[3][x]) << scale_high | av_bswap16(src[3][x]) >> scale_low; + } + } else { + for (x = 0; x < width; x++) { + *dest++ = av_bswap16(src[0][x]) << scale_high | av_bswap16(src[0][x]) >> scale_low; + *dest++ = av_bswap16(src[1][x]) << scale_high | av_bswap16(src[1][x]) >> scale_low; + *dest++ = av_bswap16(src[2][x]) << scale_high | av_bswap16(src[2][x]) >> scale_low; + } + } + break; + default: + if (alpha && !src_alpha) { + for (x = 0; x < width; x++) { + *dest++ = src[0][x] << scale_high | src[0][x] >> scale_low; + *dest++ = src[1][x] << scale_high | src[1][x] >> scale_low; + *dest++ = src[2][x] << scale_high | src[2][x] >> scale_low; + *dest++ = 0xffff; + } + } else if (alpha && src_alpha) { + for (x = 0; x < width; x++) { + *dest++ = src[0][x] << scale_high | src[0][x] >> scale_low; + *dest++ = src[1][x] << scale_high | src[1][x] >> scale_low; + *dest++ = src[2][x] << scale_high | src[2][x] >> scale_low; + *dest++ = src[3][x] << scale_high | src[3][x] >> scale_low; + } + } else { + for (x = 0; x < width; x++) { + *dest++ = src[0][x] << scale_high | src[0][x] >> scale_low; + *dest++ = src[1][x] << scale_high | src[1][x] >> scale_low; + *dest++ = src[2][x] << scale_high | src[2][x] >> scale_low; + } + } + } + for (i = 0; i < 3 + src_alpha; i++) + src[i] += srcStride[i] >> 1; + } +} + +static void gbr16ptopacked30(const uint16_t *src[], const int srcStride[], + uint8_t *dst, int dstStride, int srcSliceH, + int swap, int bpp, int width) +{ + int x, h, i; + int shift = bpp - 10; + av_assert0(bpp >= 0); + for (h = 0; h < srcSliceH; h++) { + uint8_t *dest = dst + dstStride * h; + + switch(swap) { + case 3: + case 1: + for (x = 0; x < width; x++) { + unsigned C0 = av_bswap16(src[0][x]) >> shift; + unsigned C1 = av_bswap16(src[1][x]) >> shift; + unsigned C2 = av_bswap16(src[2][x]) >> shift; + AV_WL32(dest + 4 * x, (3U << 30) + (C0 << 20) + (C1 << 10) + C2); + } + break; + default: + for (x = 0; x < width; x++) { + unsigned C0 = src[0][x] >> shift; + unsigned C1 = src[1][x] >> shift; + unsigned C2 = src[2][x] >> shift; + AV_WL32(dest + 4 * x, (3U << 30) + (C0 << 20) + (C1 << 10) + C2); + } + break; + } + for (i = 0; i < 3; i++) + src[i] += srcStride[i] >> 1; + } +} + + +static int planarRgb16ToRgb16Wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + const uint16_t *src102[] = { (uint16_t *)src[1], (uint16_t *)src[0], (uint16_t *)src[2], (uint16_t *)src[3] }; + const uint16_t *src201[] = { (uint16_t *)src[2], (uint16_t *)src[0], (uint16_t *)src[1], (uint16_t *)src[3] }; + int stride102[] = { srcStride[1], srcStride[0], srcStride[2], srcStride[3] }; + int stride201[] = { srcStride[2], srcStride[0], srcStride[1], srcStride[3] }; + const AVPixFmtDescriptor *src_format = av_pix_fmt_desc_get(c->opts.src_format); + const AVPixFmtDescriptor *dst_format = av_pix_fmt_desc_get(c->opts.dst_format); + int bits_per_sample = src_format->comp[0].depth; + int swap = 0; + if ( HAVE_BIGENDIAN && !(src_format->flags & AV_PIX_FMT_FLAG_BE) || + !HAVE_BIGENDIAN && src_format->flags & AV_PIX_FMT_FLAG_BE) + swap++; + if ( HAVE_BIGENDIAN && !(dst_format->flags & AV_PIX_FMT_FLAG_BE) || + !HAVE_BIGENDIAN && dst_format->flags & AV_PIX_FMT_FLAG_BE) + swap += 2; + + if ((src_format->flags & (AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB)) != + (AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB) || + bits_per_sample <= 8) { + av_log(c, AV_LOG_ERROR, "unsupported planar RGB conversion %s -> %s\n", + src_format->name, dst_format->name); + return srcSliceH; + } + switch (c->opts.dst_format) { + case AV_PIX_FMT_BGR48LE: + case AV_PIX_FMT_BGR48BE: + gbr16ptopacked16(src102, stride102, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, 0, swap, bits_per_sample, c->opts.src_w); + break; + case AV_PIX_FMT_RGB48LE: + case AV_PIX_FMT_RGB48BE: + gbr16ptopacked16(src201, stride201, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, 0, swap, bits_per_sample, c->opts.src_w); + break; + case AV_PIX_FMT_RGBA64LE: + case AV_PIX_FMT_RGBA64BE: + gbr16ptopacked16(src201, stride201, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, 1, swap, bits_per_sample, c->opts.src_w); + break; + case AV_PIX_FMT_BGRA64LE: + case AV_PIX_FMT_BGRA64BE: + gbr16ptopacked16(src102, stride102, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, 1, swap, bits_per_sample, c->opts.src_w); + break; + case AV_PIX_FMT_X2RGB10LE: + gbr16ptopacked30(src201, stride201, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, swap, bits_per_sample, c->opts.src_w); + break; + case AV_PIX_FMT_X2BGR10LE: + gbr16ptopacked30(src102, stride102, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, swap, bits_per_sample, c->opts.src_w); + break; + default: + av_log(c, AV_LOG_ERROR, + "unsupported planar RGB conversion %s -> %s\n", + src_format->name, dst_format->name); + } + + return srcSliceH; +} + +static void gbr24ptopacked24(const uint8_t *src[], const int srcStride[], + uint8_t *dst, int dstStride, int srcSliceH, + int width) +{ + int x, h, i; + for (h = 0; h < srcSliceH; h++) { + uint8_t *dest = dst + dstStride * h; + for (x = 0; x < width; x++) { + *dest++ = src[0][x]; + *dest++ = src[1][x]; + *dest++ = src[2][x]; + } + + for (i = 0; i < 3; i++) + src[i] += srcStride[i]; + } +} + +static void gbr24ptopacked32(const uint8_t *src[], const int srcStride[], + uint8_t *dst, int dstStride, int srcSliceH, + int alpha_first, int width) +{ + int x, h, i; + for (h = 0; h < srcSliceH; h++) { + uint8_t *dest = dst + dstStride * h; + + if (alpha_first) { + for (x = 0; x < width; x++) { + *dest++ = 0xff; + *dest++ = src[0][x]; + *dest++ = src[1][x]; + *dest++ = src[2][x]; + } + } else { + for (x = 0; x < width; x++) { + *dest++ = src[0][x]; + *dest++ = src[1][x]; + *dest++ = src[2][x]; + *dest++ = 0xff; + } + } + + for (i = 0; i < 3; i++) + src[i] += srcStride[i]; + } +} + +static void gbraptopacked32(const uint8_t *src[], const int srcStride[], + uint8_t *dst, int dstStride, int srcSliceH, + int alpha_first, int width) +{ + int x, h, i; + for (h = 0; h < srcSliceH; h++) { + uint8_t *dest = dst + dstStride * h; + + if (alpha_first) { + for (x = 0; x < width; x++) { + *dest++ = src[3][x]; + *dest++ = src[0][x]; + *dest++ = src[1][x]; + *dest++ = src[2][x]; + } + } else { + for (x = 0; x < width; x++) { + *dest++ = src[0][x]; + *dest++ = src[1][x]; + *dest++ = src[2][x]; + *dest++ = src[3][x]; + } + } + + for (i = 0; i < 4; i++) + src[i] += srcStride[i]; + } +} + +static int planarRgbaToRgbWrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + int alpha_first = 0; + const uint8_t *src102[] = { src[1], src[0], src[2], src[3] }; + const uint8_t *src201[] = { src[2], src[0], src[1], src[3] }; + int stride102[] = { srcStride[1], srcStride[0], srcStride[2], srcStride[3] }; + int stride201[] = { srcStride[2], srcStride[0], srcStride[1], srcStride[3] }; + + if (c->opts.src_format != AV_PIX_FMT_GBRAP) { + av_log(c, AV_LOG_ERROR, "unsupported planar RGB conversion %s -> %s\n", + av_get_pix_fmt_name(c->opts.src_format), + av_get_pix_fmt_name(c->opts.dst_format)); + return srcSliceH; + } + + switch (c->opts.dst_format) { + case AV_PIX_FMT_BGR24: + gbr24ptopacked24(src102, stride102, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, c->opts.src_w); + break; + + case AV_PIX_FMT_RGB24: + gbr24ptopacked24(src201, stride201, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, c->opts.src_w); + break; + + case AV_PIX_FMT_ARGB: + alpha_first = 1; + case AV_PIX_FMT_RGBA: + gbraptopacked32(src201, stride201, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, alpha_first, c->opts.src_w); + break; + + case AV_PIX_FMT_ABGR: + alpha_first = 1; + case AV_PIX_FMT_BGRA: + gbraptopacked32(src102, stride102, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, alpha_first, c->opts.src_w); + break; + + default: + av_log(c, AV_LOG_ERROR, + "unsupported planar RGB conversion %s -> %s\n", + av_get_pix_fmt_name(c->opts.src_format), + av_get_pix_fmt_name(c->opts.dst_format)); + } + + return srcSliceH; +} + +static int planarRgbToRgbWrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + int alpha_first = 0; + const uint8_t *src102[] = { src[1], src[0], src[2] }; + const uint8_t *src201[] = { src[2], src[0], src[1] }; + int stride102[] = { srcStride[1], srcStride[0], srcStride[2] }; + int stride201[] = { srcStride[2], srcStride[0], srcStride[1] }; + + if (c->opts.src_format != AV_PIX_FMT_GBRP) { + av_log(c, AV_LOG_ERROR, "unsupported planar RGB conversion %s -> %s\n", + av_get_pix_fmt_name(c->opts.src_format), + av_get_pix_fmt_name(c->opts.dst_format)); + return srcSliceH; + } + + switch (c->opts.dst_format) { + case AV_PIX_FMT_BGR24: + gbr24ptopacked24(src102, stride102, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, c->opts.src_w); + break; + + case AV_PIX_FMT_RGB24: + gbr24ptopacked24(src201, stride201, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, c->opts.src_w); + break; + + case AV_PIX_FMT_ARGB: + alpha_first = 1; + case AV_PIX_FMT_RGBA: + gbr24ptopacked32(src201, stride201, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, alpha_first, c->opts.src_w); + break; + + case AV_PIX_FMT_ABGR: + alpha_first = 1; + case AV_PIX_FMT_BGRA: + gbr24ptopacked32(src102, stride102, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, alpha_first, c->opts.src_w); + break; + + default: + av_log(c, AV_LOG_ERROR, + "unsupported planar RGB conversion %s -> %s\n", + av_get_pix_fmt_name(c->opts.src_format), + av_get_pix_fmt_name(c->opts.dst_format)); + } + + return srcSliceH; +} + +static int planarRgbToplanarRgbWrapper(SwsInternal *c, + const uint8_t *const src[], const int srcStride[], + int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->opts.src_w, + dst[0], dstStride[0]); + ff_copyPlane(src[1], srcStride[1], srcSliceY, srcSliceH, c->opts.src_w, + dst[1], dstStride[1]); + ff_copyPlane(src[2], srcStride[2], srcSliceY, srcSliceH, c->opts.src_w, + dst[2], dstStride[2]); + if (dst[3]) { + if (is16BPS(c->opts.dst_format) || isNBPS(c->opts.dst_format)) { + const AVPixFmtDescriptor *desc_dst = av_pix_fmt_desc_get(c->opts.dst_format); + fillPlane16(dst[3], dstStride[3], c->opts.src_w, srcSliceH, srcSliceY, 1, + desc_dst->comp[3].depth, isBE(c->opts.dst_format)); + } else { + fillPlane(dst[3], dstStride[3], c->opts.src_w, srcSliceH, srcSliceY, 255); + } + } + + return srcSliceH; +} + +static void packedtogbr24p(const uint8_t *src, int srcStride, + uint8_t *const dst[], const int dstStride[], int srcSliceH, + int alpha_first, int inc_size, int width) +{ + uint8_t *dest[3]; + int x, h; + + dest[0] = dst[0]; + dest[1] = dst[1]; + dest[2] = dst[2]; + + if (alpha_first) + src++; + + for (h = 0; h < srcSliceH; h++) { + for (x = 0; x < width; x++) { + dest[0][x] = src[0]; + dest[1][x] = src[1]; + dest[2][x] = src[2]; + + src += inc_size; + } + src += srcStride - width * inc_size; + dest[0] += dstStride[0]; + dest[1] += dstStride[1]; + dest[2] += dstStride[2]; + } +} + +static int rgbToPlanarRgbWrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + int alpha_first = 0; + int stride102[] = { dstStride[1], dstStride[0], dstStride[2] }; + int stride201[] = { dstStride[2], dstStride[0], dstStride[1] }; + uint8_t *dst102[] = { dst[1] + srcSliceY * dstStride[1], + dst[0] + srcSliceY * dstStride[0], + dst[2] + srcSliceY * dstStride[2] }; + uint8_t *dst201[] = { dst[2] + srcSliceY * dstStride[2], + dst[0] + srcSliceY * dstStride[0], + dst[1] + srcSliceY * dstStride[1] }; + + switch (c->opts.src_format) { + case AV_PIX_FMT_RGB24: + packedtogbr24p((const uint8_t *) src[0], srcStride[0], dst201, + stride201, srcSliceH, alpha_first, 3, c->opts.src_w); + break; + case AV_PIX_FMT_BGR24: + packedtogbr24p((const uint8_t *) src[0], srcStride[0], dst102, + stride102, srcSliceH, alpha_first, 3, c->opts.src_w); + break; + case AV_PIX_FMT_ARGB: + alpha_first = 1; + case AV_PIX_FMT_RGBA: + packedtogbr24p((const uint8_t *) src[0], srcStride[0], dst201, + stride201, srcSliceH, alpha_first, 4, c->opts.src_w); + break; + case AV_PIX_FMT_ABGR: + alpha_first = 1; + case AV_PIX_FMT_BGRA: + packedtogbr24p((const uint8_t *) src[0], srcStride[0], dst102, + stride102, srcSliceH, alpha_first, 4, c->opts.src_w); + break; + default: + av_log(c, AV_LOG_ERROR, + "unsupported planar RGB conversion %s -> %s\n", + av_get_pix_fmt_name(c->opts.src_format), + av_get_pix_fmt_name(c->opts.dst_format)); + } + + return srcSliceH; +} + +static void packed24togbrap(const uint8_t *src, int srcStride, + uint8_t *const dst[], const int dstStride[], + int srcSliceH, int width) +{ + uint8_t *dest[4]; + int x, h; + + dest[0] = dst[0]; + dest[1] = dst[1]; + dest[2] = dst[2]; + dest[3] = dst[3]; + + for (h = 0; h < srcSliceH; h++) { + for (x = 0; x < width; x++) { + dest[0][x] = src[x * 3 + 0]; + dest[1][x] = src[x * 3 + 1]; + dest[2][x] = src[x * 3 + 2]; + dest[3][x] = 0xff; + } + src += srcStride; + dest[0] += dstStride[0]; + dest[1] += dstStride[1]; + dest[2] += dstStride[2]; + dest[3] += dstStride[3]; + } +} + +static void packed32togbrap(const uint8_t *src, int srcStride, + uint8_t *const dst[], const int dstStride[], + int srcSliceH, int alpha_first, int width) +{ + uint8_t *dest[4]; + int x, h; + + dest[0] = dst[0]; + dest[1] = dst[1]; + dest[2] = dst[2]; + dest[3] = dst[3]; + + for (h = 0; h < srcSliceH; h++) { + if (alpha_first) { + for (x = 0; x < width; x++) { + dest[0][x] = src[x * 4 + 1]; + dest[1][x] = src[x * 4 + 2]; + dest[2][x] = src[x * 4 + 3]; + dest[3][x] = src[x * 4 + 0]; + } + } else { + for (x = 0; x < width; x++) { + dest[0][x] = src[x * 4 + 0]; + dest[1][x] = src[x * 4 + 1]; + dest[2][x] = src[x * 4 + 2]; + dest[3][x] = src[x * 4 + 3]; + } + } + src += srcStride; + dest[0] += dstStride[0]; + dest[1] += dstStride[1]; + dest[2] += dstStride[2]; + dest[3] += dstStride[3]; + } +} + +static int rgbToPlanarRgbaWrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + int alpha_first = 0; + int stride102[] = { dstStride[1], dstStride[0], dstStride[2], dstStride[3] }; + int stride201[] = { dstStride[2], dstStride[0], dstStride[1], dstStride[3] }; + uint8_t *dst102[] = { dst[1] + srcSliceY * dstStride[1], + dst[0] + srcSliceY * dstStride[0], + dst[2] + srcSliceY * dstStride[2], + dst[3] + srcSliceY * dstStride[3] }; + uint8_t *dst201[] = { dst[2] + srcSliceY * dstStride[2], + dst[0] + srcSliceY * dstStride[0], + dst[1] + srcSliceY * dstStride[1], + dst[3] + srcSliceY * dstStride[3] }; + + switch (c->opts.src_format) { + case AV_PIX_FMT_RGB24: + packed24togbrap((const uint8_t *) src[0], srcStride[0], dst201, + stride201, srcSliceH, c->opts.src_w); + break; + case AV_PIX_FMT_BGR24: + packed24togbrap((const uint8_t *) src[0], srcStride[0], dst102, + stride102, srcSliceH, c->opts.src_w); + break; + case AV_PIX_FMT_ARGB: + alpha_first = 1; + case AV_PIX_FMT_RGBA: + packed32togbrap((const uint8_t *) src[0], srcStride[0], dst201, + stride201, srcSliceH, alpha_first, c->opts.src_w); + break; + case AV_PIX_FMT_ABGR: + alpha_first = 1; + case AV_PIX_FMT_BGRA: + packed32togbrap((const uint8_t *) src[0], srcStride[0], dst102, + stride102, srcSliceH, alpha_first, c->opts.src_w); + break; + default: + av_log(c, AV_LOG_ERROR, + "unsupported planar RGB conversion %s -> %s\n", + av_get_pix_fmt_name(c->opts.src_format), + av_get_pix_fmt_name(c->opts.dst_format)); + } + + return srcSliceH; +} + +#define BAYER_GBRG +#define BAYER_8 +#define BAYER_RENAME(x) bayer_gbrg8_to_##x +#include "bayer_template.c" + +#define BAYER_GBRG +#define BAYER_16LE +#define BAYER_RENAME(x) bayer_gbrg16le_to_##x +#include "bayer_template.c" + +#define BAYER_GBRG +#define BAYER_16BE +#define BAYER_RENAME(x) bayer_gbrg16be_to_##x +#include "bayer_template.c" + +#define BAYER_GRBG +#define BAYER_8 +#define BAYER_RENAME(x) bayer_grbg8_to_##x +#include "bayer_template.c" + +#define BAYER_GRBG +#define BAYER_16LE +#define BAYER_RENAME(x) bayer_grbg16le_to_##x +#include "bayer_template.c" + +#define BAYER_GRBG +#define BAYER_16BE +#define BAYER_RENAME(x) bayer_grbg16be_to_##x +#include "bayer_template.c" + +#define BAYER_BGGR +#define BAYER_8 +#define BAYER_RENAME(x) bayer_bggr8_to_##x +#include "bayer_template.c" + +#define BAYER_BGGR +#define BAYER_16LE +#define BAYER_RENAME(x) bayer_bggr16le_to_##x +#include "bayer_template.c" + +#define BAYER_BGGR +#define BAYER_16BE +#define BAYER_RENAME(x) bayer_bggr16be_to_##x +#include "bayer_template.c" + +#define BAYER_RGGB +#define BAYER_8 +#define BAYER_RENAME(x) bayer_rggb8_to_##x +#include "bayer_template.c" + +#define BAYER_RGGB +#define BAYER_16LE +#define BAYER_RENAME(x) bayer_rggb16le_to_##x +#include "bayer_template.c" + +#define BAYER_RGGB +#define BAYER_16BE +#define BAYER_RENAME(x) bayer_rggb16be_to_##x +#include "bayer_template.c" + +static int bayer_to_rgb24_wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + uint8_t *dstPtr= dst[0] + srcSliceY * dstStride[0]; + const uint8_t *srcPtr= src[0]; + int i; + void (*copy) (const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width); + void (*interpolate)(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width); + + switch(c->opts.src_format) { +#define CASE(pixfmt, prefix) \ + case pixfmt: copy = bayer_##prefix##_to_rgb24_copy; \ + interpolate = bayer_##prefix##_to_rgb24_interpolate; \ + break; + CASE(AV_PIX_FMT_BAYER_BGGR8, bggr8) + CASE(AV_PIX_FMT_BAYER_BGGR16LE, bggr16le) + CASE(AV_PIX_FMT_BAYER_BGGR16BE, bggr16be) + CASE(AV_PIX_FMT_BAYER_RGGB8, rggb8) + CASE(AV_PIX_FMT_BAYER_RGGB16LE, rggb16le) + CASE(AV_PIX_FMT_BAYER_RGGB16BE, rggb16be) + CASE(AV_PIX_FMT_BAYER_GBRG8, gbrg8) + CASE(AV_PIX_FMT_BAYER_GBRG16LE, gbrg16le) + CASE(AV_PIX_FMT_BAYER_GBRG16BE, gbrg16be) + CASE(AV_PIX_FMT_BAYER_GRBG8, grbg8) + CASE(AV_PIX_FMT_BAYER_GRBG16LE, grbg16le) + CASE(AV_PIX_FMT_BAYER_GRBG16BE, grbg16be) +#undef CASE + default: return 0; + } + + av_assert0(srcSliceH > 1); + + copy(srcPtr, srcStride[0], dstPtr, dstStride[0], c->opts.src_w); + srcPtr += 2 * srcStride[0]; + dstPtr += 2 * dstStride[0]; + + for (i = 2; i < srcSliceH - 2; i += 2) { + interpolate(srcPtr, srcStride[0], dstPtr, dstStride[0], c->opts.src_w); + srcPtr += 2 * srcStride[0]; + dstPtr += 2 * dstStride[0]; + } + + if (i + 1 == srcSliceH) { + copy(srcPtr, -srcStride[0], dstPtr, -dstStride[0], c->opts.src_w); + } else if (i < srcSliceH) + copy(srcPtr, srcStride[0], dstPtr, dstStride[0], c->opts.src_w); + return srcSliceH; +} + +static int bayer_to_rgb48_wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + uint8_t *dstPtr= dst[0] + srcSliceY * dstStride[0]; + const uint8_t *srcPtr= src[0]; + int i; + void (*copy) (const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width); + void (*interpolate)(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width); + + switch(c->opts.src_format) { +#define CASE(pixfmt, prefix) \ + case pixfmt: copy = bayer_##prefix##_to_rgb48_copy; \ + interpolate = bayer_##prefix##_to_rgb48_interpolate; \ + break; + CASE(AV_PIX_FMT_BAYER_BGGR8, bggr8) + CASE(AV_PIX_FMT_BAYER_BGGR16LE, bggr16le) + CASE(AV_PIX_FMT_BAYER_BGGR16BE, bggr16be) + CASE(AV_PIX_FMT_BAYER_RGGB8, rggb8) + CASE(AV_PIX_FMT_BAYER_RGGB16LE, rggb16le) + CASE(AV_PIX_FMT_BAYER_RGGB16BE, rggb16be) + CASE(AV_PIX_FMT_BAYER_GBRG8, gbrg8) + CASE(AV_PIX_FMT_BAYER_GBRG16LE, gbrg16le) + CASE(AV_PIX_FMT_BAYER_GBRG16BE, gbrg16be) + CASE(AV_PIX_FMT_BAYER_GRBG8, grbg8) + CASE(AV_PIX_FMT_BAYER_GRBG16LE, grbg16le) + CASE(AV_PIX_FMT_BAYER_GRBG16BE, grbg16be) +#undef CASE + default: return 0; + } + + av_assert0(srcSliceH > 1); + + copy(srcPtr, srcStride[0], dstPtr, dstStride[0], c->opts.src_w); + srcPtr += 2 * srcStride[0]; + dstPtr += 2 * dstStride[0]; + + for (i = 2; i < srcSliceH - 2; i += 2) { + interpolate(srcPtr, srcStride[0], dstPtr, dstStride[0], c->opts.src_w); + srcPtr += 2 * srcStride[0]; + dstPtr += 2 * dstStride[0]; + } + + if (i + 1 == srcSliceH) { + copy(srcPtr, -srcStride[0], dstPtr, -dstStride[0], c->opts.src_w); + } else if (i < srcSliceH) + copy(srcPtr, srcStride[0], dstPtr, dstStride[0], c->opts.src_w); + return srcSliceH; +} + +static int bayer_to_yv12_wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + const uint8_t *srcPtr= src[0]; + uint8_t *dstY= dst[0] + srcSliceY * dstStride[0]; + uint8_t *dstU= dst[1] + srcSliceY * dstStride[1] / 2; + uint8_t *dstV= dst[2] + srcSliceY * dstStride[2] / 2; + int i; + void (*copy) (const uint8_t *src, int src_stride, uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, int luma_stride, int width, const int32_t *rgb2yuv); + void (*interpolate)(const uint8_t *src, int src_stride, uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, int luma_stride, int width, const int32_t *rgb2yuv); + + switch(c->opts.src_format) { +#define CASE(pixfmt, prefix) \ + case pixfmt: copy = bayer_##prefix##_to_yv12_copy; \ + interpolate = bayer_##prefix##_to_yv12_interpolate; \ + break; + CASE(AV_PIX_FMT_BAYER_BGGR8, bggr8) + CASE(AV_PIX_FMT_BAYER_BGGR16LE, bggr16le) + CASE(AV_PIX_FMT_BAYER_BGGR16BE, bggr16be) + CASE(AV_PIX_FMT_BAYER_RGGB8, rggb8) + CASE(AV_PIX_FMT_BAYER_RGGB16LE, rggb16le) + CASE(AV_PIX_FMT_BAYER_RGGB16BE, rggb16be) + CASE(AV_PIX_FMT_BAYER_GBRG8, gbrg8) + CASE(AV_PIX_FMT_BAYER_GBRG16LE, gbrg16le) + CASE(AV_PIX_FMT_BAYER_GBRG16BE, gbrg16be) + CASE(AV_PIX_FMT_BAYER_GRBG8, grbg8) + CASE(AV_PIX_FMT_BAYER_GRBG16LE, grbg16le) + CASE(AV_PIX_FMT_BAYER_GRBG16BE, grbg16be) +#undef CASE + default: return 0; + } + + av_assert0(srcSliceH > 1); + + copy(srcPtr, srcStride[0], dstY, dstU, dstV, dstStride[0], c->opts.src_w, c->input_rgb2yuv_table); + srcPtr += 2 * srcStride[0]; + dstY += 2 * dstStride[0]; + dstU += dstStride[1]; + dstV += dstStride[1]; + + for (i = 2; i < srcSliceH - 2; i += 2) { + interpolate(srcPtr, srcStride[0], dstY, dstU, dstV, dstStride[0], c->opts.src_w, c->input_rgb2yuv_table); + srcPtr += 2 * srcStride[0]; + dstY += 2 * dstStride[0]; + dstU += dstStride[1]; + dstV += dstStride[1]; + } + + if (i + 1 == srcSliceH) { + copy(srcPtr, -srcStride[0], dstY, dstU, dstV, -dstStride[0], c->opts.src_w, c->input_rgb2yuv_table); + } else if (i < srcSliceH) + copy(srcPtr, srcStride[0], dstY, dstU, dstV, dstStride[0], c->opts.src_w, c->input_rgb2yuv_table); + return srcSliceH; +} + +#define isRGBA32(x) ( \ + (x) == AV_PIX_FMT_ARGB \ + || (x) == AV_PIX_FMT_RGBA \ + || (x) == AV_PIX_FMT_BGRA \ + || (x) == AV_PIX_FMT_ABGR \ + ) + +#define isRGBA64(x) ( \ + (x) == AV_PIX_FMT_RGBA64LE \ + || (x) == AV_PIX_FMT_RGBA64BE \ + || (x) == AV_PIX_FMT_BGRA64LE \ + || (x) == AV_PIX_FMT_BGRA64BE \ + ) + +#define isRGB48(x) ( \ + (x) == AV_PIX_FMT_RGB48LE \ + || (x) == AV_PIX_FMT_RGB48BE \ + || (x) == AV_PIX_FMT_BGR48LE \ + || (x) == AV_PIX_FMT_BGR48BE \ + ) + +#define isAYUV(x) ( \ + (x) == AV_PIX_FMT_AYUV \ + || (x) == AV_PIX_FMT_VUYA \ + || (x) == AV_PIX_FMT_VUYX \ + || (x) == AV_PIX_FMT_UYVA \ + ) + +#define isX2RGB(x) ( \ + (x) == AV_PIX_FMT_X2RGB10LE \ + || (x) == AV_PIX_FMT_X2BGR10LE \ + ) + +/* {RGB,BGR}{15,16,24,32,32_1} -> {RGB,BGR}{15,16,24,32} */ +typedef void (* rgbConvFn) (const uint8_t *, uint8_t *, int); +static rgbConvFn findRgbConvFn(SwsInternal *c) +{ + const enum AVPixelFormat srcFormat = c->opts.src_format; + const enum AVPixelFormat dstFormat = c->opts.dst_format; + const int srcId = c->srcFormatBpp; + const int dstId = c->dstFormatBpp; + rgbConvFn conv = NULL; + +#define IS_NOT_NE(bpp, desc) \ + (((bpp + 7) >> 3) == 2 && \ + (!(desc->flags & AV_PIX_FMT_FLAG_BE) != !HAVE_BIGENDIAN)) + +#define CONV_IS(src, dst) (srcFormat == AV_PIX_FMT_##src && dstFormat == AV_PIX_FMT_##dst) + + if (isRGBA32(srcFormat) && isRGBA32(dstFormat)) { + if ( CONV_IS(ABGR, RGBA) + || CONV_IS(ARGB, BGRA) + || CONV_IS(BGRA, ARGB) + || CONV_IS(RGBA, ABGR)) conv = shuffle_bytes_3210; + else if (CONV_IS(ABGR, ARGB) + || CONV_IS(ARGB, ABGR)) conv = shuffle_bytes_0321; + else if (CONV_IS(ABGR, BGRA) + || CONV_IS(ARGB, RGBA)) conv = shuffle_bytes_1230; + else if (CONV_IS(BGRA, RGBA) + || CONV_IS(RGBA, BGRA)) conv = shuffle_bytes_2103; + else if (CONV_IS(BGRA, ABGR) + || CONV_IS(RGBA, ARGB)) conv = shuffle_bytes_3012; + } else if (isRGB48(srcFormat) && isRGB48(dstFormat)) { + if (CONV_IS(RGB48LE, BGR48LE) + || CONV_IS(BGR48LE, RGB48LE) + || CONV_IS(RGB48BE, BGR48BE) + || CONV_IS(BGR48BE, RGB48BE)) conv = rgb48tobgr48_nobswap; + else if (CONV_IS(RGB48LE, BGR48BE) + || CONV_IS(BGR48LE, RGB48BE) + || CONV_IS(RGB48BE, BGR48LE) + || CONV_IS(BGR48BE, RGB48LE)) conv = rgb48tobgr48_bswap; + } else if (isRGB48(srcFormat) && isRGBA64(dstFormat)) { + if (CONV_IS(RGB48LE, BGRA64LE) + || CONV_IS(BGR48LE, RGBA64LE) + || CONV_IS(RGB48BE, BGRA64BE) + || CONV_IS(BGR48BE, RGBA64BE)) conv = rgb48tobgr64_nobswap; + else if (CONV_IS(RGB48LE, BGRA64BE) + || CONV_IS(BGR48LE, RGBA64BE) + || CONV_IS(RGB48BE, BGRA64LE) + || CONV_IS(BGR48BE, RGBA64LE)) conv = rgb48tobgr64_bswap; + if (CONV_IS(RGB48LE, RGBA64LE) + || CONV_IS(BGR48LE, BGRA64LE) + || CONV_IS(RGB48BE, RGBA64BE) + || CONV_IS(BGR48BE, BGRA64BE)) conv = rgb48to64_nobswap; + else if (CONV_IS(RGB48LE, RGBA64BE) + || CONV_IS(BGR48LE, BGRA64BE) + || CONV_IS(RGB48BE, RGBA64LE) + || CONV_IS(BGR48BE, BGRA64LE)) conv = rgb48to64_bswap; + } else if (isRGBA64(srcFormat) && isRGB48(dstFormat)) { + if (CONV_IS(RGBA64LE, BGR48LE) + || CONV_IS(BGRA64LE, RGB48LE) + || CONV_IS(RGBA64BE, BGR48BE) + || CONV_IS(BGRA64BE, RGB48BE)) conv = rgb64tobgr48_nobswap; + else if (CONV_IS(RGBA64LE, BGR48BE) + || CONV_IS(BGRA64LE, RGB48BE) + || CONV_IS(RGBA64BE, BGR48LE) + || CONV_IS(BGRA64BE, RGB48LE)) conv = rgb64tobgr48_bswap; + else if (CONV_IS(RGBA64LE, RGB48LE) + || CONV_IS(BGRA64LE, BGR48LE) + || CONV_IS(RGBA64BE, RGB48BE) + || CONV_IS(BGRA64BE, BGR48BE)) conv = rgb64to48_nobswap; + else if (CONV_IS(RGBA64LE, RGB48BE) + || CONV_IS(BGRA64LE, BGR48BE) + || CONV_IS(RGBA64BE, RGB48LE) + || CONV_IS(BGRA64BE, BGR48LE)) conv = rgb64to48_bswap; + } else if (isX2RGB(srcFormat) && isRGB48(dstFormat)) { + if (CONV_IS(X2RGB10LE, RGB48LE) + || CONV_IS(X2BGR10LE, BGR48LE)) conv = HAVE_BIGENDIAN ? x2rgb10to48_bswap + : x2rgb10to48_nobswap; + else if (CONV_IS(X2RGB10LE, RGB48BE) + || CONV_IS(X2BGR10LE, BGR48BE)) conv = HAVE_BIGENDIAN ? x2rgb10to48_nobswap + : x2rgb10to48_bswap; + else if (CONV_IS(X2RGB10LE, BGR48LE) + || CONV_IS(X2BGR10LE, RGB48LE)) conv = HAVE_BIGENDIAN ? x2rgb10tobgr48_bswap + : x2rgb10tobgr48_nobswap; + else if (CONV_IS(X2RGB10LE, BGR48BE) + || CONV_IS(X2BGR10LE, RGB48BE)) conv = HAVE_BIGENDIAN ? x2rgb10tobgr48_nobswap + : x2rgb10tobgr48_bswap; + } else if (isX2RGB(srcFormat) && isRGBA64(dstFormat)) { + if (CONV_IS(X2RGB10LE, RGBA64LE) + || CONV_IS(X2BGR10LE, BGRA64LE)) conv = HAVE_BIGENDIAN ? x2rgb10to64_bswap + : x2rgb10to64_nobswap; + else if (CONV_IS(X2RGB10LE, RGBA64BE) + || CONV_IS(X2BGR10LE, BGRA64BE)) conv = HAVE_BIGENDIAN ? x2rgb10to64_nobswap + : x2rgb10to64_bswap; + else if (CONV_IS(X2RGB10LE, BGRA64LE) + || CONV_IS(X2BGR10LE, RGBA64LE)) conv = HAVE_BIGENDIAN ? x2rgb10tobgr64_bswap + : x2rgb10tobgr64_nobswap; + else if (CONV_IS(X2RGB10LE, BGRA64BE) + || CONV_IS(X2BGR10LE, RGBA64BE)) conv = HAVE_BIGENDIAN ? x2rgb10tobgr64_nobswap + : x2rgb10tobgr64_bswap; + } else if (isAYUV(srcFormat) && isAYUV(dstFormat)) { + /* VUYX only for dst, to avoid copying undefined bytes */ + if ( CONV_IS(AYUV, VUYA) + || CONV_IS(AYUV, VUYX) + || CONV_IS(VUYA, AYUV)) conv = shuffle_bytes_3210; + else if (CONV_IS(AYUV, UYVA)) conv = shuffle_bytes_2130; + else if (CONV_IS(VUYA, UYVA)) conv = shuffle_bytes_1203; + else if (CONV_IS(UYVA, AYUV)) conv = shuffle_bytes_3102; + else if (CONV_IS(UYVA, VUYA) + || CONV_IS(UYVA, VUYX)) conv = shuffle_bytes_2013; + } else + /* BGR -> BGR */ + if ((isBGRinInt(srcFormat) && isBGRinInt(dstFormat)) || + (isRGBinInt(srcFormat) && isRGBinInt(dstFormat))) { + switch (srcId | (dstId << 16)) { + case 0x000F000C: conv = rgb12to15; break; + case 0x000F0010: conv = rgb16to15; break; + case 0x000F0018: conv = rgb24to15; break; + case 0x000F0020: conv = rgb32to15; break; + case 0x0010000F: conv = rgb15to16; break; + case 0x00100018: conv = rgb24to16; break; + case 0x00100020: conv = rgb32to16; break; + case 0x0018000F: conv = rgb15to24; break; + case 0x00180010: conv = rgb16to24; break; + case 0x00180020: conv = rgb32to24; break; + case 0x0020000F: conv = rgb15to32; break; + case 0x00200010: conv = rgb16to32; break; + case 0x00200018: conv = rgb24to32; break; + } + } else if ((isBGRinInt(srcFormat) && isRGBinInt(dstFormat)) || + (isRGBinInt(srcFormat) && isBGRinInt(dstFormat))) { + switch (srcId | (dstId << 16)) { + case 0x000C000C: conv = rgb12tobgr12; break; + case 0x000F000F: conv = rgb15tobgr15; break; + case 0x000F0010: conv = rgb16tobgr15; break; + case 0x000F0018: conv = rgb24tobgr15; break; + case 0x000F0020: conv = rgb32tobgr15; break; + case 0x0010000F: conv = rgb15tobgr16; break; + case 0x00100010: conv = rgb16tobgr16; break; + case 0x00100018: conv = rgb24tobgr16; break; + case 0x00100020: conv = rgb32tobgr16; break; + case 0x0018000F: conv = rgb15tobgr24; break; + case 0x00180010: conv = rgb16tobgr24; break; + case 0x00180018: conv = rgb24tobgr24; break; + case 0x00180020: conv = rgb32tobgr24; break; + case 0x0020000F: conv = rgb15tobgr32; break; + case 0x00200010: conv = rgb16tobgr32; break; + case 0x00200018: conv = rgb24tobgr32; break; + } + } + + if ((dstFormat == AV_PIX_FMT_RGB32_1 || dstFormat == AV_PIX_FMT_BGR32_1) && !isRGBA32(srcFormat) && ALT32_CORR<0) + return NULL; + + // Maintain symmetry between endianness + if (c->opts.flags & SWS_BITEXACT) + if ((dstFormat == AV_PIX_FMT_RGB32 || dstFormat == AV_PIX_FMT_BGR32 ) && !isRGBA32(srcFormat) && ALT32_CORR>0) + return NULL; + + return conv; +} + +/* {RGB,BGR}{15,16,24,32,32_1} -> {RGB,BGR}{15,16,24,32} */ +static int rgbToRgbWrapper(SwsInternal *c, const uint8_t *const src[], const int srcStride[], + int srcSliceY, int srcSliceH, uint8_t *const dst[], + const int dstStride[]) + +{ + const enum AVPixelFormat srcFormat = c->opts.src_format; + const enum AVPixelFormat dstFormat = c->opts.dst_format; + const AVPixFmtDescriptor *desc_src = av_pix_fmt_desc_get(c->opts.src_format); + const AVPixFmtDescriptor *desc_dst = av_pix_fmt_desc_get(c->opts.dst_format); + const int srcBpp = desc_src->comp[0].step; + const int dstBpp = desc_dst->comp[0].step; + rgbConvFn conv = findRgbConvFn(c); + + if (!conv) { + av_log(c, AV_LOG_ERROR, "internal error %s -> %s converter\n", + av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat)); + } else { + const uint8_t *srcPtr = src[0]; + uint8_t *dstPtr = dst[0]; + int src_bswap = IS_NOT_NE(srcBpp, desc_src); + int dst_bswap = IS_NOT_NE(dstBpp, desc_dst); + + if ((srcFormat == AV_PIX_FMT_RGB32_1 || srcFormat == AV_PIX_FMT_BGR32_1) && + !isRGBA32(dstFormat)) + srcPtr += ALT32_CORR; + + if ((dstFormat == AV_PIX_FMT_RGB32_1 || dstFormat == AV_PIX_FMT_BGR32_1) && + !isRGBA32(srcFormat)) { + int i; + av_assert0(ALT32_CORR == 1); + for (i = 0; i < srcSliceH; i++) + dstPtr[dstStride[0] * (srcSliceY + i)] = 255; + dstPtr += ALT32_CORR; + } + + if (dstStride[0] * srcBpp == srcStride[0] * dstBpp && srcStride[0] > 0 && + !(srcStride[0] % srcBpp) && !dst_bswap && !src_bswap) + conv(srcPtr, dstPtr + dstStride[0] * srcSliceY, + (srcSliceH - 1) * srcStride[0] + c->opts.src_w * srcBpp); + else { + int i, j; + dstPtr += dstStride[0] * srcSliceY; + + for (i = 0; i < srcSliceH; i++) { + if(src_bswap) { + for(j=0; j<c->opts.src_w; j++) + ((uint16_t*)c->formatConvBuffer)[j] = av_bswap16(((uint16_t*)srcPtr)[j]); + conv(c->formatConvBuffer, dstPtr, c->opts.src_w * srcBpp); + }else + conv(srcPtr, dstPtr, c->opts.src_w * srcBpp); + if(dst_bswap) + for(j=0; j<c->opts.src_w; j++) + ((uint16_t*)dstPtr)[j] = av_bswap16(((uint16_t*)dstPtr)[j]); + srcPtr += srcStride[0]; + dstPtr += dstStride[0]; + } + } + } + return srcSliceH; +} + +static int bgr24ToYv12Wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + ff_rgb24toyv12( + src[0], + dst[0] + srcSliceY * dstStride[0], + dst[1] + (srcSliceY >> 1) * dstStride[1], + dst[2] + (srcSliceY >> 1) * dstStride[2], + c->opts.src_w, srcSliceH, + dstStride[0], dstStride[1], srcStride[0], + c->input_rgb2yuv_table); + if (dst[3]) + fillPlane(dst[3], dstStride[3], c->opts.src_w, srcSliceH, srcSliceY, 255); + return srcSliceH; +} + +static int yvu9ToYv12Wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->opts.src_w, + dst[0], dstStride[0]); + + planar2x(src[1], dst[1] + dstStride[1] * (srcSliceY >> 1), c->chrSrcW, + srcSliceH >> 2, srcStride[1], dstStride[1]); + planar2x(src[2], dst[2] + dstStride[2] * (srcSliceY >> 1), c->chrSrcW, + srcSliceH >> 2, srcStride[2], dstStride[2]); + if (dst[3]) + fillPlane(dst[3], dstStride[3], c->opts.src_w, srcSliceH, srcSliceY, 255); + return srcSliceH; +} + +static int uint_y_to_float_y_wrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *const dst[], const int dstStride[]) +{ + int y, x; + ptrdiff_t dstStrideFloat = dstStride[0] >> 2; + const uint8_t *srcPtr = src[0]; + float *dstPtr = (float *)(dst[0] + dstStride[0] * srcSliceY); + + for (y = 0; y < srcSliceH; ++y){ + for (x = 0; x < c->opts.src_w; ++x){ + dstPtr[x] = c->uint2float_lut[srcPtr[x]]; + } + srcPtr += srcStride[0]; + dstPtr += dstStrideFloat; + } + + return srcSliceH; +} + +static int float_y_to_uint_y_wrapper(SwsInternal *c, + const uint8_t *const src[], + const int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *const dst[], + const int dstStride[]) +{ + int y, x; + ptrdiff_t srcStrideFloat = srcStride[0] >> 2; + const float *srcPtr = (const float *)src[0]; + uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY; + + for (y = 0; y < srcSliceH; ++y){ + for (x = 0; x < c->opts.src_w; ++x){ + dstPtr[x] = av_clip_uint8(lrintf(255.0f * srcPtr[x])); + } + srcPtr += srcStrideFloat; + dstPtr += dstStride[0]; + } + + return srcSliceH; +} + +/* unscaled copy like stuff (assumes nearly identical formats) */ +static int packedCopyWrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + if (dstStride[0] == srcStride[0] && srcStride[0] > 0) + memcpy(dst[0] + dstStride[0] * srcSliceY, src[0], srcSliceH * dstStride[0]); + else { + int i; + const uint8_t *srcPtr = src[0]; + uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY; + + const int length = FFMIN(FFABS(dstStride[0]), FFABS(srcStride[0])); + for (i = 0; i < srcSliceH; i++) { + memcpy(dstPtr, srcPtr, length); + srcPtr += srcStride[0]; + dstPtr += dstStride[0]; + } + } + return srcSliceH; +} + +#define DITHER_COPY(dst, dstStride, src, srcStride, bswap, dbswap)\ + unsigned shift= src_depth-dst_depth, tmp;\ + unsigned bias = 1 << (shift - 1);\ + if (c->opts.dither == SWS_DITHER_NONE) {\ + for (i = 0; i < height; i++) {\ + for (j = 0; j < length-7; j+=8) {\ + tmp = ((bswap(src[j+0]) >> src_shift) + bias)>>shift; dst[j+0] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+1]) >> src_shift) + bias)>>shift; dst[j+1] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+2]) >> src_shift) + bias)>>shift; dst[j+2] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+3]) >> src_shift) + bias)>>shift; dst[j+3] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+4]) >> src_shift) + bias)>>shift; dst[j+4] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+5]) >> src_shift) + bias)>>shift; dst[j+5] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+6]) >> src_shift) + bias)>>shift; dst[j+6] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+7]) >> src_shift) + bias)>>shift; dst[j+7] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + }\ + for (; j < length; j++) {\ + tmp = (bswap(src[j]) + bias)>>shift; dst[j] = dbswap(tmp - (tmp>>dst_depth) << dst_shift);\ + }\ + dst += dstStride;\ + src += srcStride;\ + }\ + } else if (shiftonly) {\ + for (i = 0; i < height; i++) {\ + const uint8_t *dither= dithers[shift-1][i&7];\ + for (j = 0; j < length-7; j+=8) {\ + tmp = ((bswap(src[j+0]) >> src_shift) + dither[0])>>shift; dst[j+0] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+1]) >> src_shift) + dither[1])>>shift; dst[j+1] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+2]) >> src_shift) + dither[2])>>shift; dst[j+2] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+3]) >> src_shift) + dither[3])>>shift; dst[j+3] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+4]) >> src_shift) + dither[4])>>shift; dst[j+4] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+5]) >> src_shift) + dither[5])>>shift; dst[j+5] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+6]) >> src_shift) + dither[6])>>shift; dst[j+6] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + tmp = ((bswap(src[j+7]) >> src_shift) + dither[7])>>shift; dst[j+7] = dbswap((tmp - (tmp>>dst_depth)) << dst_shift);\ + }\ + for (; j < length; j++) {\ + tmp = (bswap(src[j]) + dither[j&7])>>shift; dst[j] = dbswap(tmp - (tmp>>dst_depth) << dst_shift);\ + }\ + dst += dstStride;\ + src += srcStride;\ + }\ + } else {\ + for (i = 0; i < height; i++) {\ + const uint8_t *dither= dithers[shift-1][i&7];\ + for (j = 0; j < length-7; j+=8) {\ + tmp = bswap(src[j+0]) >> src_shift; dst[j+0] = dbswap(((tmp - (tmp>>dst_depth) + dither[0])>>shift) << dst_shift);\ + tmp = bswap(src[j+1]) >> src_shift; dst[j+1] = dbswap(((tmp - (tmp>>dst_depth) + dither[1])>>shift) << dst_shift);\ + tmp = bswap(src[j+2]) >> src_shift; dst[j+2] = dbswap(((tmp - (tmp>>dst_depth) + dither[2])>>shift) << dst_shift);\ + tmp = bswap(src[j+3]) >> src_shift; dst[j+3] = dbswap(((tmp - (tmp>>dst_depth) + dither[3])>>shift) << dst_shift);\ + tmp = bswap(src[j+4]) >> src_shift; dst[j+4] = dbswap(((tmp - (tmp>>dst_depth) + dither[4])>>shift) << dst_shift);\ + tmp = bswap(src[j+5]) >> src_shift; dst[j+5] = dbswap(((tmp - (tmp>>dst_depth) + dither[5])>>shift) << dst_shift);\ + tmp = bswap(src[j+6]) >> src_shift; dst[j+6] = dbswap(((tmp - (tmp>>dst_depth) + dither[6])>>shift) << dst_shift);\ + tmp = bswap(src[j+7]) >> src_shift; dst[j+7] = dbswap(((tmp - (tmp>>dst_depth) + dither[7])>>shift) << dst_shift);\ + }\ + for (; j < length; j++) {\ + tmp = bswap(src[j]); dst[j] = dbswap((tmp - (tmp>>dst_depth) + dither[j&7])>>shift);\ + }\ + dst += dstStride;\ + src += srcStride;\ + }\ + } + +static int planarCopyWrapper(SwsInternal *c, const uint8_t *const src[], + const int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *const dst[], const int dstStride[]) +{ + const AVPixFmtDescriptor *desc_src = av_pix_fmt_desc_get(c->opts.src_format); + const AVPixFmtDescriptor *desc_dst = av_pix_fmt_desc_get(c->opts.dst_format); + int plane, i, j; + for (plane = 0; plane < 4 && dst[plane] != NULL; plane++) { + int length = (plane == 0 || plane == 3) ? c->opts.src_w : AV_CEIL_RSHIFT(c->opts.src_w, c->chrDstHSubSample); + int y = (plane == 0 || plane == 3) ? srcSliceY: AV_CEIL_RSHIFT(srcSliceY, c->chrDstVSubSample); + int height = (plane == 0 || plane == 3) ? srcSliceH: AV_CEIL_RSHIFT(srcSliceH, c->chrDstVSubSample); + const uint8_t *srcPtr = src[plane]; + uint8_t *dstPtr = dst[plane] + dstStride[plane] * y; + int shiftonly = plane == 1 || plane == 2 || (!c->opts.src_range && plane == 0); + if (plane == 1 && isSemiPlanarYUV(c->opts.dst_format)) + length *= 2; + + // ignore palette for GRAY8 + if (plane == 1 && desc_dst->nb_components < 3) continue; + if (!src[plane] || (plane == 1 && desc_src->nb_components < 3) || (plane == 3 && desc_src->nb_components <= 3)) { + if (is16BPS(c->opts.dst_format) || isNBPS(c->opts.dst_format)) { + fillPlane16(dst[plane], dstStride[plane], length, height, y, + plane == 3, desc_dst->comp[plane].depth, + isBE(c->opts.dst_format)); + } else { + fillPlane(dst[plane], dstStride[plane], length, height, y, + (plane == 3) ? 255 : 128); + } + } else { + if(isNBPS(c->opts.src_format) || isNBPS(c->opts.dst_format) + || (is16BPS(c->opts.src_format) != is16BPS(c->opts.dst_format)) + ) { + const int src_depth = desc_src->comp[plane].depth; + const int dst_depth = desc_dst->comp[plane].depth; + const int src_shift = desc_src->comp[plane].shift; + const int dst_shift = desc_dst->comp[plane].shift; + const uint16_t *srcPtr2 = (const uint16_t *) srcPtr; + uint16_t *dstPtr2 = (uint16_t*)dstPtr; + + if (dst_depth == 8) { + av_assert1(src_depth > 8); + if(isBE(c->opts.src_format) == HAVE_BIGENDIAN){ + DITHER_COPY(dstPtr, dstStride[plane], srcPtr2, srcStride[plane]/2, , ) + } else { + DITHER_COPY(dstPtr, dstStride[plane], srcPtr2, srcStride[plane]/2, av_bswap16, ) + } + } else if (src_depth == 8) { + for (i = 0; i < height; i++) { + #define COPY816(w)\ + if (shiftonly) {\ + for (j = 0; j < length; j++)\ + w(&dstPtr2[j], (srcPtr[j]<<(dst_depth-8)) << dst_shift);\ + } else {\ + for (j = 0; j < length; j++)\ + w(&dstPtr2[j], ((srcPtr[j]<<(dst_depth-8)) |\ + (srcPtr[j]>>(2*8-dst_depth))) << dst_shift);\ + } + if(isBE(c->opts.dst_format)){ + COPY816(AV_WB16) + } else { + COPY816(AV_WL16) + } + dstPtr2 += dstStride[plane]/2; + srcPtr += srcStride[plane]; + } + } else if (src_depth <= dst_depth) { + unsigned shift = dst_depth - src_depth; + for (i = 0; i < height; i++) { + j = 0; + if(isBE(c->opts.src_format) == HAVE_BIGENDIAN && + isBE(c->opts.dst_format) == HAVE_BIGENDIAN && + shiftonly) { +#if HAVE_FAST_64BIT + for (; j < length - 3; j += 4) { + uint64_t v = AV_RN64A(srcPtr2 + j) >> src_shift; + AV_WN64A(dstPtr2 + j, (v << shift) << dst_shift); + } +#else + for (; j < length - 1; j += 2) { + uint32_t v = AV_RN32A(srcPtr2 + j) >> src_shift; + AV_WN32A(dstPtr2 + j, (v << shift) << dst_shift); + } +#endif + } +#define COPY_UP(r,w) \ + if(shiftonly){\ + for (; j < length; j++){ \ + unsigned int v= r(&srcPtr2[j]) >> src_shift;\ + w(&dstPtr2[j], (v << shift) << dst_shift);\ + }\ + }else{\ + for (; j < length; j++){ \ + unsigned int v= r(&srcPtr2[j]) >> src_shift;\ + w(&dstPtr2[j], ((v << shift) | (v>>(2*src_depth-dst_depth))) << dst_shift);\ + }\ + } + if(isBE(c->opts.src_format)){ + if(isBE(c->opts.dst_format)){ + COPY_UP(AV_RB16, AV_WB16) + } else { + COPY_UP(AV_RB16, AV_WL16) + } + } else { + if(isBE(c->opts.dst_format)){ + COPY_UP(AV_RL16, AV_WB16) + } else { + COPY_UP(AV_RL16, AV_WL16) + } + } + dstPtr2 += dstStride[plane]/2; + srcPtr2 += srcStride[plane]/2; + } + } else { /* src_depth > dst_depth */ + if(isBE(c->opts.src_format) == HAVE_BIGENDIAN){ + if(isBE(c->opts.dst_format) == HAVE_BIGENDIAN){ + DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, , ) + } else { + DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, , av_bswap16) + } + }else{ + if(isBE(c->opts.dst_format) == HAVE_BIGENDIAN){ + DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, av_bswap16, ) + } else { + DITHER_COPY(dstPtr2, dstStride[plane]/2, srcPtr2, srcStride[plane]/2, av_bswap16, av_bswap16) + } + } + } + } else if (is16BPS(c->opts.src_format) && is16BPS(c->opts.dst_format) && + isBE(c->opts.src_format) != isBE(c->opts.dst_format)) { + + for (i = 0; i < height; i++) { + for (j = 0; j < length; j++) + ((uint16_t *) dstPtr)[j] = av_bswap16(((const uint16_t *) srcPtr)[j]); + srcPtr += srcStride[plane]; + dstPtr += dstStride[plane]; + } + } else if (isFloat(c->opts.src_format) && isFloat(c->opts.dst_format) && + isBE(c->opts.src_format) != isBE(c->opts.dst_format)) { /* swap float plane */ + for (i = 0; i < height; i++) { + for (j = 0; j < length; j++) + ((uint32_t *) dstPtr)[j] = av_bswap32(((const uint32_t *) srcPtr)[j]); + srcPtr += srcStride[plane]; + dstPtr += dstStride[plane]; + } + } else if (dstStride[plane] == srcStride[plane] && + srcStride[plane] > 0 && srcStride[plane] == length) { + memcpy(dst[plane] + dstStride[plane] * y, src[plane], + height * dstStride[plane]); + } else { + if (is16BPS(c->opts.src_format) && is16BPS(c->opts.dst_format)) + length *= 2; + else if (desc_src->comp[0].depth == 1) + length >>= 3; // monowhite/black + for (i = 0; i < height; i++) { + memcpy(dstPtr, srcPtr, length); + srcPtr += srcStride[plane]; + dstPtr += dstStride[plane]; + } + } + } + } + return srcSliceH; +} + + +#define IS_DIFFERENT_ENDIANESS(src_fmt, dst_fmt, pix_fmt) \ + ((src_fmt == pix_fmt ## BE && dst_fmt == pix_fmt ## LE) || \ + (src_fmt == pix_fmt ## LE && dst_fmt == pix_fmt ## BE)) + + +void ff_get_unscaled_swscale(SwsInternal *c) +{ + const enum AVPixelFormat srcFormat = c->opts.src_format; + const enum AVPixelFormat dstFormat = c->opts.dst_format; + const int flags = c->opts.flags; + const int dstH = c->opts.dst_h; + const int dstW = c->opts.dst_w; + int needsDither; + + needsDither = isAnyRGB(dstFormat) && + c->dstFormatBpp < 24 && + (c->dstFormatBpp < c->srcFormatBpp || (!isAnyRGB(srcFormat))); + + /* yv12_to_nv12 */ + if ((srcFormat == AV_PIX_FMT_YUV420P || srcFormat == AV_PIX_FMT_YUVA420P) && + (dstFormat == AV_PIX_FMT_NV12 || dstFormat == AV_PIX_FMT_NV21)) { + c->convert_unscaled = planarToNv12Wrapper; + } + /* yv24_to_nv24 */ + if ((srcFormat == AV_PIX_FMT_YUV444P || srcFormat == AV_PIX_FMT_YUVA444P) && + (dstFormat == AV_PIX_FMT_NV24 || dstFormat == AV_PIX_FMT_NV42)) { + c->convert_unscaled = planarToNv24Wrapper; + } + /* nv12_to_yv12 */ + if (dstFormat == AV_PIX_FMT_YUV420P && + (srcFormat == AV_PIX_FMT_NV12 || srcFormat == AV_PIX_FMT_NV21)) { + c->convert_unscaled = nv12ToPlanarWrapper; + } + /* nv24_to_yv24 */ + if (dstFormat == AV_PIX_FMT_YUV444P && + (srcFormat == AV_PIX_FMT_NV24 || srcFormat == AV_PIX_FMT_NV42)) { + c->convert_unscaled = nv24ToPlanarWrapper; + } + /* yuv2bgr */ + if ((srcFormat == AV_PIX_FMT_YUV420P || srcFormat == AV_PIX_FMT_YUV422P || + srcFormat == AV_PIX_FMT_YUVA420P) && isAnyRGB(dstFormat) && + !(flags & SWS_ACCURATE_RND) && (c->opts.dither == SWS_DITHER_BAYER || c->opts.dither == SWS_DITHER_AUTO) && !(dstH & 1)) { + c->convert_unscaled = ff_yuv2rgb_get_func_ptr(c); + c->dst_slice_align = 2; + } + /* yuv420p1x_to_p01x */ + if ((srcFormat == AV_PIX_FMT_YUV420P10 || srcFormat == AV_PIX_FMT_YUVA420P10 || + srcFormat == AV_PIX_FMT_YUV420P12 || + srcFormat == AV_PIX_FMT_YUV420P14 || + srcFormat == AV_PIX_FMT_YUV420P16 || srcFormat == AV_PIX_FMT_YUVA420P16) && + (dstFormat == AV_PIX_FMT_P010 || dstFormat == AV_PIX_FMT_P016)) { + c->convert_unscaled = planarToP01xWrapper; + } + /* yuv420p_to_p01xle */ + if ((srcFormat == AV_PIX_FMT_YUV420P || srcFormat == AV_PIX_FMT_YUVA420P) && + (dstFormat == AV_PIX_FMT_P010LE || dstFormat == AV_PIX_FMT_P016LE)) { + c->convert_unscaled = planar8ToP01xleWrapper; + } + + if (srcFormat == AV_PIX_FMT_YUV410P && !(dstH & 3) && + (dstFormat == AV_PIX_FMT_YUV420P || dstFormat == AV_PIX_FMT_YUVA420P) && + !(flags & SWS_BITEXACT)) { + c->convert_unscaled = yvu9ToYv12Wrapper; + c->dst_slice_align = 4; + } + + /* bgr24toYV12 */ + if (srcFormat == AV_PIX_FMT_BGR24 && + (dstFormat == AV_PIX_FMT_YUV420P || dstFormat == AV_PIX_FMT_YUVA420P) && + !(flags & SWS_ACCURATE_RND) && !(dstW&1)) + c->convert_unscaled = bgr24ToYv12Wrapper; + + /* AYUV/VUYA/UYVA -> AYUV/VUYA/UYVA */ + if (isAYUV(srcFormat) && isAYUV(dstFormat) && findRgbConvFn(c)) + c->convert_unscaled = rgbToRgbWrapper; + + /* RGB/BGR -> RGB/BGR (no dither needed forms) */ + if (isAnyRGB(srcFormat) && isAnyRGB(dstFormat) && findRgbConvFn(c) + && (!needsDither || (c->opts.flags&(SWS_FAST_BILINEAR|SWS_POINT)))) + c->convert_unscaled = rgbToRgbWrapper; + + /* RGB to planar RGB */ + if ((srcFormat == AV_PIX_FMT_GBRP && dstFormat == AV_PIX_FMT_GBRAP) || + (srcFormat == AV_PIX_FMT_GBRP10 && dstFormat == AV_PIX_FMT_GBRAP10) || + (srcFormat == AV_PIX_FMT_GBRP12 && dstFormat == AV_PIX_FMT_GBRAP12) || + (srcFormat == AV_PIX_FMT_GBRP14 && dstFormat == AV_PIX_FMT_GBRAP14) || + (srcFormat == AV_PIX_FMT_GBRP16 && dstFormat == AV_PIX_FMT_GBRAP16) || + (srcFormat == AV_PIX_FMT_GBRAP && dstFormat == AV_PIX_FMT_GBRP) || + (srcFormat == AV_PIX_FMT_GBRAP10 && dstFormat == AV_PIX_FMT_GBRP10) || + (srcFormat == AV_PIX_FMT_GBRAP12 && dstFormat == AV_PIX_FMT_GBRP12) || + (srcFormat == AV_PIX_FMT_GBRAP14 && dstFormat == AV_PIX_FMT_GBRP14) || + (srcFormat == AV_PIX_FMT_GBRAP16 && dstFormat == AV_PIX_FMT_GBRP16)) + c->convert_unscaled = planarRgbToplanarRgbWrapper; + +#define isByteRGB(f) ( \ + f == AV_PIX_FMT_RGB32 || \ + f == AV_PIX_FMT_RGB32_1 || \ + f == AV_PIX_FMT_RGB24 || \ + f == AV_PIX_FMT_BGR32 || \ + f == AV_PIX_FMT_BGR32_1 || \ + f == AV_PIX_FMT_BGR24) + + if (srcFormat == AV_PIX_FMT_GBRP && isPlanar(srcFormat) && isByteRGB(dstFormat)) + c->convert_unscaled = planarRgbToRgbWrapper; + + if (srcFormat == AV_PIX_FMT_GBRAP && isByteRGB(dstFormat)) + c->convert_unscaled = planarRgbaToRgbWrapper; + + if ((srcFormat == AV_PIX_FMT_RGB48LE || srcFormat == AV_PIX_FMT_RGB48BE || + srcFormat == AV_PIX_FMT_BGR48LE || srcFormat == AV_PIX_FMT_BGR48BE || + srcFormat == AV_PIX_FMT_RGBA64LE || srcFormat == AV_PIX_FMT_RGBA64BE || + srcFormat == AV_PIX_FMT_BGRA64LE || srcFormat == AV_PIX_FMT_BGRA64BE) && + (dstFormat == AV_PIX_FMT_GBRP9LE || dstFormat == AV_PIX_FMT_GBRP9BE || + dstFormat == AV_PIX_FMT_GBRP10LE || dstFormat == AV_PIX_FMT_GBRP10BE || + dstFormat == AV_PIX_FMT_GBRP12LE || dstFormat == AV_PIX_FMT_GBRP12BE || + dstFormat == AV_PIX_FMT_GBRP14LE || dstFormat == AV_PIX_FMT_GBRP14BE || + dstFormat == AV_PIX_FMT_GBRP16LE || dstFormat == AV_PIX_FMT_GBRP16BE || + dstFormat == AV_PIX_FMT_GBRAP10LE || dstFormat == AV_PIX_FMT_GBRAP10BE || + dstFormat == AV_PIX_FMT_GBRAP12LE || dstFormat == AV_PIX_FMT_GBRAP12BE || + dstFormat == AV_PIX_FMT_GBRAP14LE || dstFormat == AV_PIX_FMT_GBRAP14BE || + dstFormat == AV_PIX_FMT_GBRAP16LE || dstFormat == AV_PIX_FMT_GBRAP16BE )) + c->convert_unscaled = Rgb16ToPlanarRgb16Wrapper; + + if (av_pix_fmt_desc_get(dstFormat)->comp[0].depth >= 10 && + isPlanarRGB(dstFormat) && !isFloat(dstFormat) && + (srcFormat == AV_PIX_FMT_X2RGB10LE || srcFormat == AV_PIX_FMT_X2BGR10LE)) + c->convert_unscaled = Rgb16ToPlanarRgb16Wrapper; + + if ((srcFormat == AV_PIX_FMT_GBRP9LE || srcFormat == AV_PIX_FMT_GBRP9BE || + srcFormat == AV_PIX_FMT_GBRP16LE || srcFormat == AV_PIX_FMT_GBRP16BE || + srcFormat == AV_PIX_FMT_GBRP10LE || srcFormat == AV_PIX_FMT_GBRP10BE || + srcFormat == AV_PIX_FMT_GBRP12LE || srcFormat == AV_PIX_FMT_GBRP12BE || + srcFormat == AV_PIX_FMT_GBRP14LE || srcFormat == AV_PIX_FMT_GBRP14BE || + srcFormat == AV_PIX_FMT_GBRAP10LE || srcFormat == AV_PIX_FMT_GBRAP10BE || + srcFormat == AV_PIX_FMT_GBRAP12LE || srcFormat == AV_PIX_FMT_GBRAP12BE || + srcFormat == AV_PIX_FMT_GBRAP14LE || srcFormat == AV_PIX_FMT_GBRAP14BE || + srcFormat == AV_PIX_FMT_GBRAP16LE || srcFormat == AV_PIX_FMT_GBRAP16BE) && + (dstFormat == AV_PIX_FMT_RGB48LE || dstFormat == AV_PIX_FMT_RGB48BE || + dstFormat == AV_PIX_FMT_BGR48LE || dstFormat == AV_PIX_FMT_BGR48BE || + dstFormat == AV_PIX_FMT_RGBA64LE || dstFormat == AV_PIX_FMT_RGBA64BE || + dstFormat == AV_PIX_FMT_BGRA64LE || dstFormat == AV_PIX_FMT_BGRA64BE)) + c->convert_unscaled = planarRgb16ToRgb16Wrapper; + + if (av_pix_fmt_desc_get(srcFormat)->comp[0].depth >= 10 && + isPlanarRGB(srcFormat) && !isFloat(srcFormat) && + (dstFormat == AV_PIX_FMT_X2RGB10LE || dstFormat == AV_PIX_FMT_X2BGR10LE)) + c->convert_unscaled = planarRgb16ToRgb16Wrapper; + + if (av_pix_fmt_desc_get(srcFormat)->comp[0].depth == 8 && + isPackedRGB(srcFormat) && dstFormat == AV_PIX_FMT_GBRP) + c->convert_unscaled = rgbToPlanarRgbWrapper; + + if (av_pix_fmt_desc_get(srcFormat)->comp[0].depth == 8 && + isPackedRGB(srcFormat) && dstFormat == AV_PIX_FMT_GBRAP) + c->convert_unscaled = rgbToPlanarRgbaWrapper; + + if (isBayer(srcFormat)) { + c->dst_slice_align = 2; + if (dstFormat == AV_PIX_FMT_RGB24) + c->convert_unscaled = bayer_to_rgb24_wrapper; + else if (dstFormat == AV_PIX_FMT_RGB48) + c->convert_unscaled = bayer_to_rgb48_wrapper; + else if (dstFormat == AV_PIX_FMT_YUV420P) + c->convert_unscaled = bayer_to_yv12_wrapper; + else if (!isBayer(dstFormat)) { + av_log(c, AV_LOG_ERROR, "unsupported bayer conversion\n"); + av_assert0(0); + } + } + + /* bswap 16 bits per pixel/component packed formats */ + if (IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BAYER_BGGR16) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BAYER_RGGB16) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BAYER_GBRG16) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BAYER_GRBG16) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGR444) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGR48) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGR555) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGR565) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGRA64) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GRAY9) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GRAY10) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GRAY12) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GRAY14) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GRAY16) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YA16) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_AYUV64) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRP9) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRP10) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRP12) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRP14) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRP16) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRP10MSB) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRP12MSB) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRAP10) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRAP12) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRAP14) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRAP16) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_RGB444) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_RGB48) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_RGB555) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_RGB565) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_RGBA64) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_XV36) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_XV48) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_XYZ12) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV420P9) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV420P10) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV420P12) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV420P14) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV420P16) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV422P9) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV422P10) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV422P12) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV422P14) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV422P16) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV440P10) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV440P12) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P9) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P10) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P12) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P14) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P16) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P10MSB) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P12MSB)) + c->convert_unscaled = bswap_16bpc; + + /* bswap 32 bits per pixel/component formats */ + if (IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRPF32) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GBRAPF32)) + c->convert_unscaled = bswap_32bpc; + + if (usePal(srcFormat)) { + switch (dstFormat) { + case AV_PIX_FMT_GBRP: + case AV_PIX_FMT_GBRAP: + c->convert_unscaled = palToGbrpWrapper; + break; + default: + if (isByteRGB(dstFormat)) + c->convert_unscaled = palToRgbWrapper; + break; + } + } + + if (srcFormat == AV_PIX_FMT_YUV422P) { + if (dstFormat == AV_PIX_FMT_YUYV422) + c->convert_unscaled = yuv422pToYuy2Wrapper; + else if (dstFormat == AV_PIX_FMT_UYVY422) + c->convert_unscaled = yuv422pToUyvyWrapper; + } + + /* uint Y to float Y */ + if (srcFormat == AV_PIX_FMT_GRAY8 && dstFormat == AV_PIX_FMT_GRAYF32){ + c->convert_unscaled = uint_y_to_float_y_wrapper; + } + + /* float Y to uint Y */ + if (srcFormat == AV_PIX_FMT_GRAYF32 && dstFormat == AV_PIX_FMT_GRAY8){ + c->convert_unscaled = float_y_to_uint_y_wrapper; + } + + /* LQ converters if -sws 0 or -sws 4*/ + if (c->opts.flags&(SWS_FAST_BILINEAR|SWS_POINT)) { + /* yv12_to_yuy2 */ + if (srcFormat == AV_PIX_FMT_YUV420P || srcFormat == AV_PIX_FMT_YUVA420P) { + if (dstFormat == AV_PIX_FMT_YUYV422) + c->convert_unscaled = planarToYuy2Wrapper; + else if (dstFormat == AV_PIX_FMT_UYVY422) + c->convert_unscaled = planarToUyvyWrapper; + } + } + if (srcFormat == AV_PIX_FMT_YUYV422 && + (dstFormat == AV_PIX_FMT_YUV420P || dstFormat == AV_PIX_FMT_YUVA420P)) + c->convert_unscaled = yuyvToYuv420Wrapper; + if (srcFormat == AV_PIX_FMT_UYVY422 && + (dstFormat == AV_PIX_FMT_YUV420P || dstFormat == AV_PIX_FMT_YUVA420P)) + c->convert_unscaled = uyvyToYuv420Wrapper; + if (srcFormat == AV_PIX_FMT_YUYV422 && dstFormat == AV_PIX_FMT_YUV422P) + c->convert_unscaled = yuyvToYuv422Wrapper; + if (srcFormat == AV_PIX_FMT_UYVY422 && dstFormat == AV_PIX_FMT_YUV422P) + c->convert_unscaled = uyvyToYuv422Wrapper; + if (dstFormat == AV_PIX_FMT_YUV420P && + (srcFormat == AV_PIX_FMT_NV24 || srcFormat == AV_PIX_FMT_NV42)) + c->convert_unscaled = nv24ToYuv420Wrapper; + +#define isPlanarGray(x) (isGray(x) && (x) != AV_PIX_FMT_YA8 && (x) != AV_PIX_FMT_YA16LE && (x) != AV_PIX_FMT_YA16BE) + + /* simple copy */ + if ( srcFormat == dstFormat || + (srcFormat == AV_PIX_FMT_YUVA420P && dstFormat == AV_PIX_FMT_YUV420P) || + (srcFormat == AV_PIX_FMT_YUV420P && dstFormat == AV_PIX_FMT_YUVA420P) || + (isFloat(srcFormat) == isFloat(dstFormat) && isFloat16(srcFormat) == isFloat16(dstFormat)) && ((isPlanarYUV(srcFormat) && isPlanarGray(dstFormat)) || + (isPlanarYUV(dstFormat) && isPlanarGray(srcFormat)) || + (isPlanarGray(dstFormat) && isPlanarGray(srcFormat)) || + (isPlanarYUV(srcFormat) && isPlanarYUV(dstFormat) && + c->chrDstHSubSample == c->chrSrcHSubSample && + c->chrDstVSubSample == c->chrSrcVSubSample && + isSemiPlanarYUV(srcFormat) == isSemiPlanarYUV(dstFormat) && + isSwappedChroma(srcFormat) == isSwappedChroma(dstFormat)))) + { + if (isPacked(c->opts.src_format)) { + c->convert_unscaled = packedCopyWrapper; + } else { /* Planar YUV or gray */ + c->convert_unscaled = planarCopyWrapper; + if (c->opts.dither != SWS_DITHER_NONE) + c->dst_slice_align = 8 << c->chrDstVSubSample; + } + } + + ff_sws_init_xyzdsp(c); + +#if ARCH_PPC + ff_get_unscaled_swscale_ppc(c); +#elif ARCH_ARM + ff_get_unscaled_swscale_arm(c); +#elif ARCH_AARCH64 + ff_get_unscaled_swscale_aarch64(c); +#endif +} + +/* Convert the palette to the same packed 32-bit format as the palette */ +void sws_convertPalette8ToPacked32(const uint8_t *src, uint8_t *dst, + int num_pixels, const uint8_t *palette) +{ + int i; + + for (i = 0; i < num_pixels; i++) + ((uint32_t *) dst)[i] = ((const uint32_t *) palette)[src[i]]; +} + +/* Palette format: ABCD -> dst format: ABC */ +void sws_convertPalette8ToPacked24(const uint8_t *src, uint8_t *dst, + int num_pixels, const uint8_t *palette) +{ + int i; + + for (i = 0; i < num_pixels; i++) { + //FIXME slow? + dst[0] = palette[src[i] * 4 + 0]; + dst[1] = palette[src[i] * 4 + 1]; + dst[2] = palette[src[i] * 4 + 2]; + dst += 3; + } +} diff --git a/libs/ffmpeg/libswscale/utils.c b/libs/ffmpeg/libswscale/utils.c new file mode 100644 index 00000000000..2b233cf0e67 --- /dev/null +++ b/libs/ffmpeg/libswscale/utils.c @@ -0,0 +1,2467 @@ +/* + * Copyright (C) 2024 Niklas Haas + * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#define _DEFAULT_SOURCE +#define _SVID_SOURCE // needed for MAP_ANONYMOUS +#define _DARWIN_C_SOURCE // needed for MAP_ANON +#include <inttypes.h> +#include <math.h> +#include <stdio.h> +#include <string.h> +#if HAVE_MMAP +#include <sys/mman.h> +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) +#define MAP_ANONYMOUS MAP_ANON +#endif +#endif +#if HAVE_VIRTUALALLOC +#include <windows.h> +#endif + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" +#include "libavutil/cpu.h" +#include "libavutil/csp.h" +#include "libavutil/emms.h" +#include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/libm.h" +#include "libavutil/mathematics.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/refstruct.h" +#include "libavutil/slicethread.h" +#include "libavutil/thread.h" +#include "libavutil/aarch64/cpu.h" +#include "libavutil/ppc/cpu.h" +#include "libavutil/x86/asm.h" +#include "libavutil/x86/cpu.h" +#include "libavutil/loongarch/cpu.h" + +#include "rgb2rgb.h" +#include "swscale.h" +#include "swscale_internal.h" +#include "graph.h" + +#if CONFIG_VULKAN +#include "vulkan/ops.h" +#endif + +/** + * Allocate and return an SwsContext without performing initialization. + */ +static SwsContext *alloc_set_opts(int srcW, int srcH, enum AVPixelFormat srcFormat, + int dstW, int dstH, enum AVPixelFormat dstFormat, + int flags, const double *param) +{ + SwsContext *sws = sws_alloc_context(); + if (!sws) + return NULL; + + sws->flags = flags; + sws->src_w = srcW; + sws->src_h = srcH; + sws->dst_w = dstW; + sws->dst_h = dstH; + sws->src_format = srcFormat; + sws->dst_format = dstFormat; + + if (param) { + sws->scaler_params[0] = param[0]; + sws->scaler_params[1] = param[1]; + } + + return sws; +} + +int ff_shuffle_filter_coefficients(SwsInternal *c, int *filterPos, + int filterSize, int16_t *filter, + int dstW) +{ +#if ARCH_X86_64 + int i, j, k; + int cpu_flags = av_get_cpu_flags(); + if (!filter) + return 0; + if (EXTERNAL_AVX2_FAST(cpu_flags) && !(cpu_flags & AV_CPU_FLAG_SLOW_GATHER)) { + if ((c->srcBpc == 8) && (c->dstBpc <= 14)) { + int16_t *filterCopy = NULL; + if (filterSize > 4) { + filterCopy = av_malloc_array(dstW, filterSize * sizeof(*filterCopy)); + if (!filterCopy) + return AVERROR(ENOMEM); + memcpy(filterCopy, filter, dstW * filterSize * sizeof(int16_t)); + } + // Do not swap filterPos for pixels which won't be processed by + // the main loop. + for (i = 0; i + 16 <= dstW; i += 16) { + FFSWAP(int, filterPos[i + 2], filterPos[i + 4]); + FFSWAP(int, filterPos[i + 3], filterPos[i + 5]); + FFSWAP(int, filterPos[i + 10], filterPos[i + 12]); + FFSWAP(int, filterPos[i + 11], filterPos[i + 13]); + } + if (filterSize > 4) { + // 16 pixels are processed at a time. + for (i = 0; i + 16 <= dstW; i += 16) { + // 4 filter coeffs are processed at a time. + for (k = 0; k + 4 <= filterSize; k += 4) { + for (j = 0; j < 16; ++j) { + int from = (i + j) * filterSize + k; + int to = i * filterSize + j * 4 + k * 16; + memcpy(&filter[to], &filterCopy[from], 4 * sizeof(int16_t)); + } + } + } + // 4 pixels are processed at a time in the tail. + for (; i < dstW; i += 4) { + // 4 filter coeffs are processed at a time. + int rem = dstW - i >= 4 ? 4 : dstW - i; + for (k = 0; k + 4 <= filterSize; k += 4) { + for (j = 0; j < rem; ++j) { + int from = (i + j) * filterSize + k; + int to = i * filterSize + j * 4 + k * 4; + memcpy(&filter[to], &filterCopy[from], 4 * sizeof(int16_t)); + } + } + } + } + av_free(filterCopy); + } + } +#endif + return 0; +} + +static double getSplineCoeff(double a, double b, double c, double d, + double dist) +{ + if (dist <= 1.0) + return ((d * dist + c) * dist + b) * dist + a; + else + return getSplineCoeff(0.0, + b + 2.0 * c + 3.0 * d, + c + 3.0 * d, + -b - 3.0 * c - 6.0 * d, + dist - 1.0); +} + +static av_cold int get_local_pos(SwsInternal *s, int chr_subsample, int pos, int dir) +{ + if (pos == -1 || pos <= -513) { + pos = (128 << chr_subsample) - 128; + } + pos += 128; // relative to ideal left edge + return pos >> chr_subsample; +} + +typedef struct { + int flag; ///< flag associated to the algorithm + const char *description; ///< human-readable description + int size_factor; ///< size factor used when initing the filters +} ScaleAlgorithm; + +static const ScaleAlgorithm scale_algorithms[] = { + { SWS_AREA, "area averaging", 1 /* downscale only, for upscale it is bilinear */ }, + { SWS_BICUBIC, "bicubic", 4 }, + { SWS_BICUBLIN, "luma bicubic / chroma bilinear", -1 }, + { SWS_BILINEAR, "bilinear", 2 }, + { SWS_FAST_BILINEAR, "fast bilinear", -1 }, + { SWS_GAUSS, "Gaussian", 8 /* infinite ;) */ }, + { SWS_LANCZOS, "Lanczos", -1 /* custom */ }, + { SWS_POINT, "nearest neighbor / point", -1 }, + { SWS_SINC, "sinc", 20 /* infinite ;) */ }, + { SWS_SPLINE, "bicubic spline", 20 /* infinite :)*/ }, + { SWS_X, "experimental", 8 }, +}; + +static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos, + int *outFilterSize, int xInc, int srcW, + int dstW, int filterAlign, int one, + int flags, int cpu_flags, + SwsVector *srcFilter, SwsVector *dstFilter, + double param[2], int srcPos, int dstPos) +{ + int i; + int filterSize; + int filter2Size; + int minFilterSize; + int64_t *filter = NULL; + int64_t *filter2 = NULL; + const int64_t fone = 1LL << (54 - FFMIN(av_log2(srcW/dstW), 8)); + int ret = -1; + + emms_c(); // FIXME should not be required but IS (even for non-MMX versions) + + // NOTE: the +3 is for the MMX(+1) / SSE(+3) scaler which reads over the end + if (!FF_ALLOC_TYPED_ARRAY(*filterPos, dstW + 3)) + goto nomem; + + if (FFABS(xInc - 0x10000) < 10 && srcPos == dstPos) { // unscaled + int i; + filterSize = 1; + if (!FF_ALLOCZ_TYPED_ARRAY(filter, dstW * filterSize)) + goto nomem; + + for (i = 0; i < dstW; i++) { + filter[i * filterSize] = fone; + (*filterPos)[i] = i; + } + } else if (flags & SWS_POINT) { // lame looking point sampling mode + int i; + int64_t xDstInSrc; + filterSize = 1; + if (!FF_ALLOC_TYPED_ARRAY(filter, dstW * filterSize)) + goto nomem; + + xDstInSrc = ((dstPos*(int64_t)xInc)>>8) - ((srcPos*0x8000LL)>>7); + for (i = 0; i < dstW; i++) { + int xx = (xDstInSrc - ((filterSize - 1) << 15) + (1 << 15)) >> 16; + + (*filterPos)[i] = xx; + filter[i] = fone; + xDstInSrc += xInc; + } + } else if ((xInc <= (1 << 16) && (flags & SWS_AREA)) || + (flags & SWS_FAST_BILINEAR)) { // bilinear upscale + int i; + int64_t xDstInSrc; + filterSize = 2; + if (!FF_ALLOC_TYPED_ARRAY(filter, dstW * filterSize)) + goto nomem; + + xDstInSrc = ((dstPos*(int64_t)xInc)>>8) - ((srcPos*0x8000LL)>>7); + for (i = 0; i < dstW; i++) { + int xx = (xDstInSrc - ((filterSize - 1) << 15) + (1 << 15)) >> 16; + int j; + + (*filterPos)[i] = xx; + // bilinear upscale / linear interpolate / area averaging + for (j = 0; j < filterSize; j++) { + int64_t coeff = fone - FFABS((int64_t)xx * (1 << 16) - xDstInSrc) * (fone >> 16); + if (coeff < 0) + coeff = 0; + filter[i * filterSize + j] = coeff; + xx++; + } + xDstInSrc += xInc; + } + } else { + int64_t xDstInSrc; + int sizeFactor = -1; + + for (i = 0; i < FF_ARRAY_ELEMS(scale_algorithms); i++) { + if (flags & scale_algorithms[i].flag && scale_algorithms[i].size_factor > 0) { + sizeFactor = scale_algorithms[i].size_factor; + break; + } + } + if (flags & SWS_LANCZOS) + sizeFactor = param[0] != SWS_PARAM_DEFAULT ? ceil(2 * param[0]) : 6; + av_assert0(sizeFactor > 0); + + if (sizeFactor > 50) { + ret = AVERROR(EINVAL); + goto fail; + } + + if (xInc <= 1 << 16) + filterSize = 1 + sizeFactor; // upscale + else + filterSize = 1 + (sizeFactor * srcW + dstW - 1) / dstW; + + filterSize = FFMIN(filterSize, srcW - 2); + filterSize = FFMAX(filterSize, 1); + + filter = av_malloc_array(dstW, filterSize * sizeof(*filter)); + if (!filter) + goto nomem; + xDstInSrc = ((dstPos*(int64_t)xInc)>>7) - ((srcPos*0x10000LL)>>7); + for (i = 0; i < dstW; i++) { + int xx = (xDstInSrc - (filterSize - 2) * (1LL<<16)) / (1 << 17); + int j; + (*filterPos)[i] = xx; + for (j = 0; j < filterSize; j++) { + int64_t d = (FFABS(((int64_t)xx * (1 << 17)) - xDstInSrc)) << 13; + double floatd; + int64_t coeff; + + if (xInc > 1 << 16) + d = d * dstW / srcW; + floatd = d * (1.0 / (1 << 30)); + + if (flags & SWS_BICUBIC) { + int64_t B = (param[0] != SWS_PARAM_DEFAULT ? param[0] : 0) * (1 << 24); + int64_t C = (param[1] != SWS_PARAM_DEFAULT ? param[1] : 0.6) * (1 << 24); + + if (d >= 1LL << 31) { + coeff = 0.0; + } else { + int64_t dd = (d * d) >> 30; + int64_t ddd = (dd * d) >> 30; + + if (d < 1LL << 30) + coeff = (12 * (1 << 24) - 9 * B - 6 * C) * ddd + + (-18 * (1 << 24) + 12 * B + 6 * C) * dd + + (6 * (1 << 24) - 2 * B) * (1 << 30); + else + coeff = (-B - 6 * C) * ddd + + (6 * B + 30 * C) * dd + + (-12 * B - 48 * C) * d + + (8 * B + 24 * C) * (1 << 30); + } + coeff /= (1LL<<54)/fone; + } else if (flags & SWS_X) { + double A = param[0] != SWS_PARAM_DEFAULT ? param[0] : 1.0; + double c; + + if (floatd < 1.0) + c = cos(floatd * M_PI); + else + c = -1.0; + if (c < 0.0) + c = -pow(-c, A); + else + c = pow(c, A); + coeff = (c * 0.5 + 0.5) * fone; + } else if (flags & SWS_AREA) { + int64_t d2 = d - (1 << 29); + if (d2 * xInc < -(1LL << (29 + 16))) + coeff = 1.0 * (1LL << (30 + 16)); + else if (d2 * xInc < (1LL << (29 + 16))) + coeff = -d2 * xInc + (1LL << (29 + 16)); + else + coeff = 0.0; + coeff *= fone >> (30 + 16); + } else if (flags & SWS_GAUSS) { + double p = param[0] != SWS_PARAM_DEFAULT ? param[0] : 3.0; + coeff = exp2(-p * floatd * floatd) * fone; + } else if (flags & SWS_SINC) { + coeff = (d ? sin(floatd * M_PI) / (floatd * M_PI) : 1.0) * fone; + } else if (flags & SWS_LANCZOS) { + double p = param[0] != SWS_PARAM_DEFAULT ? param[0] : 3.0; + coeff = (d ? sin(floatd * M_PI) * sin(floatd * M_PI / p) / + (floatd * floatd * M_PI * M_PI / p) : 1.0) * fone; + if (floatd > p) + coeff = 0; + } else if (flags & SWS_BILINEAR) { + coeff = (1 << 30) - d; + if (coeff < 0) + coeff = 0; + coeff *= fone >> 30; + } else if (flags & SWS_SPLINE) { + double p = -2.196152422706632; + coeff = getSplineCoeff(1.0, 0.0, p, -p - 1.0, floatd) * fone; + } else { + av_assert0(0); + } + + filter[i * filterSize + j] = coeff; + xx++; + } + xDstInSrc += 2LL * xInc; + } + } + + /* apply src & dst Filter to filter -> filter2 + * av_free(filter); + */ + av_assert0(filterSize > 0); + filter2Size = filterSize; + if (srcFilter) + filter2Size += srcFilter->length - 1; + if (dstFilter) + filter2Size += dstFilter->length - 1; + av_assert0(filter2Size > 0); + filter2 = av_calloc(dstW, filter2Size * sizeof(*filter2)); + if (!filter2) + goto nomem; + for (i = 0; i < dstW; i++) { + int j, k; + + if (srcFilter) { + for (k = 0; k < srcFilter->length; k++) { + for (j = 0; j < filterSize; j++) + filter2[i * filter2Size + k + j] += + srcFilter->coeff[k] * filter[i * filterSize + j]; + } + } else { + for (j = 0; j < filterSize; j++) + filter2[i * filter2Size + j] = filter[i * filterSize + j]; + } + // FIXME dstFilter + + (*filterPos)[i] += (filterSize - 1) / 2 - (filter2Size - 1) / 2; + } + av_freep(&filter); + + /* try to reduce the filter-size (step1 find size and shift left) */ + // Assume it is near normalized (*0.5 or *2.0 is OK but * 0.001 is not). + minFilterSize = 0; + for (i = dstW - 1; i >= 0; i--) { + int min = filter2Size; + int j; + int64_t cutOff = 0.0; + + /* get rid of near zero elements on the left by shifting left */ + for (j = 0; j < filter2Size; j++) { + int k; + cutOff += FFABS(filter2[i * filter2Size]); + + if (cutOff > SWS_MAX_REDUCE_CUTOFF * fone) + break; + + /* preserve monotonicity because the core can't handle the + * filter otherwise */ + if (i < dstW - 1 && (*filterPos)[i] >= (*filterPos)[i + 1]) + break; + + // move filter coefficients left + for (k = 1; k < filter2Size; k++) + filter2[i * filter2Size + k - 1] = filter2[i * filter2Size + k]; + filter2[i * filter2Size + k - 1] = 0; + (*filterPos)[i]++; + } + + cutOff = 0; + /* count near zeros on the right */ + for (j = filter2Size - 1; j > 0; j--) { + cutOff += FFABS(filter2[i * filter2Size + j]); + + if (cutOff > SWS_MAX_REDUCE_CUTOFF * fone) + break; + min--; + } + + if (min > minFilterSize) + minFilterSize = min; + } + + if (PPC_ALTIVEC(cpu_flags)) { + // we can handle the special case 4, so we don't want to go the full 8 + if (minFilterSize < 5) + filterAlign = 4; + + /* We really don't want to waste our time doing useless computation, so + * fall back on the scalar C code for very small filters. + * Vectorizing is worth it only if you have a decent-sized vector. */ + if (minFilterSize < 3) + filterAlign = 1; + } + + if (HAVE_MMX && cpu_flags & AV_CPU_FLAG_MMX || have_neon(cpu_flags)) { + // special case for unscaled vertical filtering + if (minFilterSize == 1 && filterAlign == 2) + filterAlign = 1; + } + + if (have_lasx(cpu_flags) || have_lsx(cpu_flags)) { + int reNum = minFilterSize & (0x07); + + if (minFilterSize < 5) + filterAlign = 4; + if (reNum < 3) + filterAlign = 1; + } + + av_assert0(minFilterSize > 0); + filterSize = (minFilterSize + (filterAlign - 1)) & (~(filterAlign - 1)); + av_assert0(filterSize > 0); + filter = av_malloc_array(dstW, filterSize * sizeof(*filter)); + if (!filter) + goto nomem; + if (filterSize >= MAX_FILTER_SIZE * 16 / + ((flags & SWS_ACCURATE_RND) ? APCK_SIZE : 16)) { + ret = RETCODE_USE_CASCADE; + goto fail; + } + *outFilterSize = filterSize; + + if (flags & SWS_PRINT_INFO) + av_log(NULL, AV_LOG_VERBOSE, + "SwScaler: reducing / aligning filtersize %d -> %d\n", + filter2Size, filterSize); + /* try to reduce the filter-size (step2 reduce it) */ + for (i = 0; i < dstW; i++) { + int j; + + for (j = 0; j < filterSize; j++) { + if (j >= filter2Size) + filter[i * filterSize + j] = 0; + else + filter[i * filterSize + j] = filter2[i * filter2Size + j]; + if ((flags & SWS_BITEXACT) && j >= minFilterSize) + filter[i * filterSize + j] = 0; + } + } + + // FIXME try to align filterPos if possible + + // fix borders + for (i = 0; i < dstW; i++) { + int j; + if ((*filterPos)[i] < 0) { + // move filter coefficients left to compensate for filterPos + for (j = 1; j < filterSize; j++) { + int left = FFMAX(j + (*filterPos)[i], 0); + filter[i * filterSize + left] += filter[i * filterSize + j]; + filter[i * filterSize + j] = 0; + } + (*filterPos)[i]= 0; + } + + if ((*filterPos)[i] + filterSize > srcW) { + int shift = (*filterPos)[i] + FFMIN(filterSize - srcW, 0); + int64_t acc = 0; + + for (j = filterSize - 1; j >= 0; j--) { + if ((*filterPos)[i] + j >= srcW) { + acc += filter[i * filterSize + j]; + filter[i * filterSize + j] = 0; + } + } + for (j = filterSize - 1; j >= 0; j--) { + if (j < shift) { + filter[i * filterSize + j] = 0; + } else { + filter[i * filterSize + j] = filter[i * filterSize + j - shift]; + } + } + + (*filterPos)[i]-= shift; + filter[i * filterSize + srcW - 1 - (*filterPos)[i]] += acc; + } + av_assert0((*filterPos)[i] >= 0); + av_assert0((*filterPos)[i] < srcW); + if ((*filterPos)[i] + filterSize > srcW) { + for (j = 0; j < filterSize; j++) { + av_assert0((*filterPos)[i] + j < srcW || !filter[i * filterSize + j]); + } + } + } + + // Note the +1 is for the MMX scaler which reads over the end + /* align at 16 for AltiVec (needed by hScale_altivec_real) */ + *outFilter = av_calloc(dstW + 3, *outFilterSize * sizeof(**outFilter)); + if (!*outFilter) + goto nomem; + + /* normalize & store in outFilter */ + for (i = 0; i < dstW; i++) { + int j; + int64_t error = 0; + int64_t sum = 0; + + for (j = 0; j < filterSize; j++) { + sum += filter[i * filterSize + j]; + } + sum = (sum + one / 2) / one; + if (!sum) { + av_log(NULL, AV_LOG_WARNING, "SwScaler: zero vector in scaling\n"); + sum = 1; + } + for (j = 0; j < *outFilterSize; j++) { + int64_t v = filter[i * filterSize + j] + error; + int intV = ROUNDED_DIV(v, sum); + (*outFilter)[i * (*outFilterSize) + j] = intV; + error = v - intV * sum; + } + } + + (*filterPos)[dstW + 0] = + (*filterPos)[dstW + 1] = + (*filterPos)[dstW + 2] = (*filterPos)[dstW - 1]; /* the MMX/SSE scaler will + * read over the end */ + for (i = 0; i < *outFilterSize; i++) { + int k = (dstW - 1) * (*outFilterSize) + i; + (*outFilter)[k + 1 * (*outFilterSize)] = + (*outFilter)[k + 2 * (*outFilterSize)] = + (*outFilter)[k + 3 * (*outFilterSize)] = (*outFilter)[k]; + } + + ret = 0; + goto done; +nomem: + ret = AVERROR(ENOMEM); +fail: + if(ret < 0) + av_log(NULL, ret == RETCODE_USE_CASCADE ? AV_LOG_DEBUG : AV_LOG_ERROR, "sws: initFilter failed\n"); +done: + av_free(filter); + av_free(filter2); + return ret; +} + +static void fill_rgb2yuv_table(SwsInternal *c, const int table[4], int dstRange) +{ + int64_t W, V, Z, Cy, Cu, Cv; + int64_t vr = table[0]; + int64_t ub = table[1]; + int64_t ug = -table[2]; + int64_t vg = -table[3]; + int64_t ONE = 65536; + int64_t cy = ONE; + uint8_t *p = (uint8_t*)c->input_rgb2yuv_table; + int i; + static const int8_t map[] = { + BY_IDX, GY_IDX, -1 , BY_IDX, BY_IDX, GY_IDX, -1 , BY_IDX, + RY_IDX, -1 , GY_IDX, RY_IDX, RY_IDX, -1 , GY_IDX, RY_IDX, + RY_IDX, GY_IDX, -1 , RY_IDX, RY_IDX, GY_IDX, -1 , RY_IDX, + BY_IDX, -1 , GY_IDX, BY_IDX, BY_IDX, -1 , GY_IDX, BY_IDX, + BU_IDX, GU_IDX, -1 , BU_IDX, BU_IDX, GU_IDX, -1 , BU_IDX, + RU_IDX, -1 , GU_IDX, RU_IDX, RU_IDX, -1 , GU_IDX, RU_IDX, + RU_IDX, GU_IDX, -1 , RU_IDX, RU_IDX, GU_IDX, -1 , RU_IDX, + BU_IDX, -1 , GU_IDX, BU_IDX, BU_IDX, -1 , GU_IDX, BU_IDX, + BV_IDX, GV_IDX, -1 , BV_IDX, BV_IDX, GV_IDX, -1 , BV_IDX, + RV_IDX, -1 , GV_IDX, RV_IDX, RV_IDX, -1 , GV_IDX, RV_IDX, + RV_IDX, GV_IDX, -1 , RV_IDX, RV_IDX, GV_IDX, -1 , RV_IDX, + BV_IDX, -1 , GV_IDX, BV_IDX, BV_IDX, -1 , GV_IDX, BV_IDX, + RY_IDX, BY_IDX, RY_IDX, BY_IDX, RY_IDX, BY_IDX, RY_IDX, BY_IDX, + BY_IDX, RY_IDX, BY_IDX, RY_IDX, BY_IDX, RY_IDX, BY_IDX, RY_IDX, + GY_IDX, -1 , GY_IDX, -1 , GY_IDX, -1 , GY_IDX, -1 , + -1 , GY_IDX, -1 , GY_IDX, -1 , GY_IDX, -1 , GY_IDX, + RU_IDX, BU_IDX, RU_IDX, BU_IDX, RU_IDX, BU_IDX, RU_IDX, BU_IDX, + BU_IDX, RU_IDX, BU_IDX, RU_IDX, BU_IDX, RU_IDX, BU_IDX, RU_IDX, + GU_IDX, -1 , GU_IDX, -1 , GU_IDX, -1 , GU_IDX, -1 , + -1 , GU_IDX, -1 , GU_IDX, -1 , GU_IDX, -1 , GU_IDX, + RV_IDX, BV_IDX, RV_IDX, BV_IDX, RV_IDX, BV_IDX, RV_IDX, BV_IDX, + BV_IDX, RV_IDX, BV_IDX, RV_IDX, BV_IDX, RV_IDX, BV_IDX, RV_IDX, + GV_IDX, -1 , GV_IDX, -1 , GV_IDX, -1 , GV_IDX, -1 , + -1 , GV_IDX, -1 , GV_IDX, -1 , GV_IDX, -1 , GV_IDX, //23 + -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //24 + -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //25 + -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //26 + -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //27 + -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //28 + -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //29 + -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //30 + -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , //31 + BY_IDX, GY_IDX, RY_IDX, -1 , -1 , -1 , -1 , -1 , //32 + BU_IDX, GU_IDX, RU_IDX, -1 , -1 , -1 , -1 , -1 , //33 + BV_IDX, GV_IDX, RV_IDX, -1 , -1 , -1 , -1 , -1 , //34 + }; + + dstRange = 0; //FIXME range = 1 is handled elsewhere + + if (!dstRange) { + cy = cy * 255 / 219; + } else { + vr = vr * 224 / 255; + ub = ub * 224 / 255; + ug = ug * 224 / 255; + vg = vg * 224 / 255; + } + W = ROUNDED_DIV(ONE*ONE*ug, ub); + V = ROUNDED_DIV(ONE*ONE*vg, vr); + Z = ONE*ONE-W-V; + + Cy = ROUNDED_DIV(cy*Z, ONE); + Cu = ROUNDED_DIV(ub*Z, ONE); + Cv = ROUNDED_DIV(vr*Z, ONE); + + c->input_rgb2yuv_table[RY_IDX] = -ROUNDED_DIV((1 << RGB2YUV_SHIFT)*V , Cy); + c->input_rgb2yuv_table[GY_IDX] = ROUNDED_DIV((1 << RGB2YUV_SHIFT)*ONE*ONE , Cy); + c->input_rgb2yuv_table[BY_IDX] = -ROUNDED_DIV((1 << RGB2YUV_SHIFT)*W , Cy); + + c->input_rgb2yuv_table[RU_IDX] = ROUNDED_DIV((1 << RGB2YUV_SHIFT)*V , Cu); + c->input_rgb2yuv_table[GU_IDX] = -ROUNDED_DIV((1 << RGB2YUV_SHIFT)*ONE*ONE , Cu); + c->input_rgb2yuv_table[BU_IDX] = ROUNDED_DIV((1 << RGB2YUV_SHIFT)*(Z+W) , Cu); + + c->input_rgb2yuv_table[RV_IDX] = ROUNDED_DIV((1 << RGB2YUV_SHIFT)*(V+Z) , Cv); + c->input_rgb2yuv_table[GV_IDX] = -ROUNDED_DIV((1 << RGB2YUV_SHIFT)*ONE*ONE , Cv); + c->input_rgb2yuv_table[BV_IDX] = ROUNDED_DIV((1 << RGB2YUV_SHIFT)*W , Cv); + + if(/*!dstRange && */!memcmp(table, ff_yuv2rgb_coeffs[SWS_CS_DEFAULT], sizeof(ff_yuv2rgb_coeffs[SWS_CS_DEFAULT]))) { + c->input_rgb2yuv_table[BY_IDX] = ((int)(0.114 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5)); + c->input_rgb2yuv_table[BV_IDX] = (-(int)(0.081 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5)); + c->input_rgb2yuv_table[BU_IDX] = ((int)(0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5)); + c->input_rgb2yuv_table[GY_IDX] = ((int)(0.587 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5)); + c->input_rgb2yuv_table[GV_IDX] = (-(int)(0.419 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5)); + c->input_rgb2yuv_table[GU_IDX] = (-(int)(0.331 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5)); + c->input_rgb2yuv_table[RY_IDX] = ((int)(0.299 * 219 / 255 * (1 << RGB2YUV_SHIFT) + 0.5)); + c->input_rgb2yuv_table[RV_IDX] = ((int)(0.500 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5)); + c->input_rgb2yuv_table[RU_IDX] = (-(int)(0.169 * 224 / 255 * (1 << RGB2YUV_SHIFT) + 0.5)); + } + for(i=0; i<FF_ARRAY_ELEMS(map); i++) + AV_WL16(p + 16*4 + 2*i, map[i] >= 0 ? c->input_rgb2yuv_table[map[i]] : 0); +} + +#if CONFIG_SMALL +static void init_xyz_tables(uint16_t xyzgamma_tab[4096], uint16_t xyzgammainv_tab[65536], + uint16_t rgbgamma_tab[65536], uint16_t rgbgammainv_tab[4096]) +#else +static uint16_t xyzgamma_tab[4096], rgbgammainv_tab[4096]; +static uint16_t rgbgamma_tab[65536], xyzgammainv_tab[65536]; +static av_cold void init_xyz_tables(void) +#endif +{ + double xyzgamma = XYZ_GAMMA; + double rgbgamma = 1.0 / RGB_GAMMA; + double xyzgammainv = 1.0 / XYZ_GAMMA; + double rgbgammainv = RGB_GAMMA; + + /* set input gamma vectors */ + for (int i = 0; i < 4096; i++) { + xyzgamma_tab[i] = lrint(pow(i / 4095.0, xyzgamma) * 65535.0); + rgbgammainv_tab[i] = lrint(pow(i / 4095.0, rgbgammainv) * 65535.0); + } + + /* set output gamma vectors */ + for (int i = 0; i < 65536; i++) { + rgbgamma_tab[i] = lrint(pow(i / 65535.0, rgbgamma) * 4095.0); + xyzgammainv_tab[i] = lrint(pow(i / 65535.0, xyzgammainv) * 4095.0); + } +} + +av_cold int ff_sws_fill_xyztables(SwsInternal *c) +{ + static const int16_t xyz2rgb_matrix[3][3] = { + {13270, -6295, -2041}, + {-3969, 7682, 170}, + { 228, -835, 4329} }; + static const int16_t rgb2xyz_matrix[3][3] = { + {1689, 1464, 739}, + { 871, 2929, 296}, + { 79, 488, 3891} }; + + if (c->xyz2rgb.gamma.in) + return 0; + + memcpy(c->xyz2rgb.mat, xyz2rgb_matrix, sizeof(c->xyz2rgb.mat)); + memcpy(c->rgb2xyz.mat, rgb2xyz_matrix, sizeof(c->rgb2xyz.mat)); + +#if CONFIG_SMALL + c->xyz2rgb.gamma.in = av_malloc(sizeof(uint16_t) * 2 * (4096 + 65536)); + if (!c->xyz2rgb.gamma.in) + return AVERROR(ENOMEM); + c->rgb2xyz.gamma.in = c->xyz2rgb.gamma.in + 4096; + c->xyz2rgb.gamma.out = c->rgb2xyz.gamma.in + 4096; + c->rgb2xyz.gamma.out = c->xyz2rgb.gamma.out + 65536; + init_xyz_tables(c->xyz2rgb.gamma.in, c->rgb2xyz.gamma.out, + c->xyz2rgb.gamma.out, c->rgb2xyz.gamma.in); +#else + c->xyz2rgb.gamma.in = xyzgamma_tab; + c->xyz2rgb.gamma.out = rgbgamma_tab; + c->rgb2xyz.gamma.in = rgbgammainv_tab; + c->rgb2xyz.gamma.out = xyzgammainv_tab; + + static AVOnce xyz_init_static_once = AV_ONCE_INIT; + ff_thread_once(&xyz_init_static_once, init_xyz_tables); +#endif + return 0; +} + +static int handle_jpeg(/* enum AVPixelFormat */ int *format) +{ + switch (*format) { + case AV_PIX_FMT_YUVJ420P: + *format = AV_PIX_FMT_YUV420P; + return 1; + case AV_PIX_FMT_YUVJ411P: + *format = AV_PIX_FMT_YUV411P; + return 1; + case AV_PIX_FMT_YUVJ422P: + *format = AV_PIX_FMT_YUV422P; + return 1; + case AV_PIX_FMT_YUVJ444P: + *format = AV_PIX_FMT_YUV444P; + return 1; + case AV_PIX_FMT_YUVJ440P: + *format = AV_PIX_FMT_YUV440P; + return 1; + case AV_PIX_FMT_GRAY8: + case AV_PIX_FMT_YA8: + case AV_PIX_FMT_GRAY9LE: + case AV_PIX_FMT_GRAY9BE: + case AV_PIX_FMT_GRAY10LE: + case AV_PIX_FMT_GRAY10BE: + case AV_PIX_FMT_GRAY12LE: + case AV_PIX_FMT_GRAY12BE: + case AV_PIX_FMT_GRAY14LE: + case AV_PIX_FMT_GRAY14BE: + case AV_PIX_FMT_GRAY16LE: + case AV_PIX_FMT_GRAY16BE: + case AV_PIX_FMT_YA16BE: + case AV_PIX_FMT_YA16LE: + return 1; + default: + return 0; + } +} + +static int handle_0alpha(/* enum AVPixelFormat */ int *format) +{ + switch (*format) { + case AV_PIX_FMT_0BGR : *format = AV_PIX_FMT_ABGR ; return 1; + case AV_PIX_FMT_BGR0 : *format = AV_PIX_FMT_BGRA ; return 4; + case AV_PIX_FMT_0RGB : *format = AV_PIX_FMT_ARGB ; return 1; + case AV_PIX_FMT_RGB0 : *format = AV_PIX_FMT_RGBA ; return 4; + default: return 0; + } +} + +static int handle_xyz(/* enum AVPixelFormat */ int *format) +{ + switch (*format) { + case AV_PIX_FMT_XYZ12BE : *format = AV_PIX_FMT_RGB48BE; return 1; + case AV_PIX_FMT_XYZ12LE : *format = AV_PIX_FMT_RGB48LE; return 1; + default: return 0; + } +} + +static int handle_formats(SwsContext *sws) +{ + SwsInternal *c = sws_internal(sws); + c->src0Alpha |= handle_0alpha(&sws->src_format); + c->dst0Alpha |= handle_0alpha(&sws->dst_format); + c->srcXYZ |= handle_xyz(&sws->src_format); + c->dstXYZ |= handle_xyz(&sws->dst_format); + if (c->srcXYZ || c->dstXYZ) + return ff_sws_fill_xyztables(c); + else + return 0; +} + +static int range_override_needed(enum AVPixelFormat format) +{ + return !isYUV(format) && !isGray(format); +} + +int sws_setColorspaceDetails(SwsContext *sws, const int inv_table[4], + int srcRange, const int table[4], int dstRange, + int brightness, int contrast, int saturation) +{ + SwsInternal *c = sws_internal(sws); + const AVPixFmtDescriptor *desc_dst; + const AVPixFmtDescriptor *desc_src; + int ret, need_reinit = 0; + + if (c->nb_slice_ctx) { + int parent_ret = 0; + for (int i = 0; i < c->nb_slice_ctx; i++) { + int ret = sws_setColorspaceDetails(c->slice_ctx[i], inv_table, + srcRange, table, dstRange, + brightness, contrast, saturation); + if (ret < 0) + parent_ret = ret; + } + + return parent_ret; + } + + ret = handle_formats(sws); + if (ret < 0) + return ret; + desc_dst = av_pix_fmt_desc_get(sws->dst_format); + desc_src = av_pix_fmt_desc_get(sws->src_format); + + if(range_override_needed(sws->dst_format)) + dstRange = 0; + if(range_override_needed(sws->src_format)) + srcRange = 0; + + if (sws->src_range != srcRange || + sws->dst_range != dstRange || + c->brightness != brightness || + c->contrast != contrast || + c->saturation != saturation || + memcmp(c->srcColorspaceTable, inv_table, sizeof(int) * 4) || + memcmp(c->dstColorspaceTable, table, sizeof(int) * 4) + ) + need_reinit = 1; + + memmove(c->srcColorspaceTable, inv_table, sizeof(int) * 4); + memmove(c->dstColorspaceTable, table, sizeof(int) * 4); + + + + c->brightness = brightness; + c->contrast = contrast; + c->saturation = saturation; + sws->src_range = srcRange; + sws->dst_range = dstRange; + + if (need_reinit) + ff_sws_init_range_convert(c); + + c->dstFormatBpp = av_get_bits_per_pixel(desc_dst); + c->srcFormatBpp = av_get_bits_per_pixel(desc_src); + + if (c->cascaded_context[c->cascaded_mainindex]) + return sws_setColorspaceDetails(c->cascaded_context[c->cascaded_mainindex],inv_table, srcRange,table, dstRange, brightness, contrast, saturation); + + if (!need_reinit) + return 0; + + if ((isYUV(sws->dst_format) || isGray(sws->dst_format)) && (isYUV(sws->src_format) || isGray(sws->src_format))) { + if (!c->cascaded_context[0] && + memcmp(c->dstColorspaceTable, c->srcColorspaceTable, sizeof(int) * 4) && + sws->src_w && sws->src_h && sws->dst_w && sws->dst_h) { + enum AVPixelFormat tmp_format; + int tmp_width, tmp_height; + int srcW = sws->src_w; + int srcH = sws->src_h; + int dstW = sws->dst_w; + int dstH = sws->dst_h; + int ret; + av_log(c, AV_LOG_VERBOSE, "YUV color matrix differs for YUV->YUV, using intermediate RGB to convert\n"); + + if (isNBPS(sws->dst_format) || is16BPS(sws->dst_format)) { + if (isALPHA(sws->src_format) && isALPHA(sws->dst_format)) { + tmp_format = AV_PIX_FMT_BGRA64; + } else { + tmp_format = AV_PIX_FMT_BGR48; + } + } else { + if (isALPHA(sws->src_format) && isALPHA(sws->dst_format)) { + tmp_format = AV_PIX_FMT_BGRA; + } else { + tmp_format = AV_PIX_FMT_BGR24; + } + } + + if (srcW*srcH > dstW*dstH) { + tmp_width = dstW; + tmp_height = dstH; + } else { + tmp_width = srcW; + tmp_height = srcH; + } + + ret = av_image_alloc(c->cascaded_tmp[0], c->cascaded_tmpStride[0], + tmp_width, tmp_height, tmp_format, 64); + if (ret < 0) + return ret; + + c->cascaded_context[0] = alloc_set_opts(srcW, srcH, sws->src_format, + tmp_width, tmp_height, tmp_format, + sws->flags, sws->scaler_params); + if (!c->cascaded_context[0]) + return -1; + + c->cascaded_context[0]->alpha_blend = sws->alpha_blend; + ret = sws_init_context(c->cascaded_context[0], NULL , NULL); + if (ret < 0) + return ret; + //we set both src and dst depending on that the RGB side will be ignored + sws_setColorspaceDetails(c->cascaded_context[0], inv_table, + srcRange, table, dstRange, + brightness, contrast, saturation); + + c->cascaded_context[1] = alloc_set_opts(tmp_width, tmp_height, tmp_format, + dstW, dstH, sws->dst_format, + sws->flags, sws->scaler_params); + if (!c->cascaded_context[1]) + return -1; + c->cascaded_context[1]->src_range = srcRange; + c->cascaded_context[1]->dst_range = dstRange; + ret = sws_init_context(c->cascaded_context[1], NULL , NULL); + if (ret < 0) + return ret; + sws_setColorspaceDetails(c->cascaded_context[1], inv_table, + srcRange, table, dstRange, + 0, 1 << 16, 1 << 16); + return 0; + } + //We do not support this combination currently, we need to cascade more contexts to compensate + if (c->cascaded_context[0] && memcmp(c->dstColorspaceTable, c->srcColorspaceTable, sizeof(int) * 4)) + return -1; //AVERROR_PATCHWELCOME; + return 0; + } + + if (!isYUV(sws->dst_format) && !isGray(sws->dst_format)) { + ff_yuv2rgb_c_init_tables(c, inv_table, srcRange, brightness, + contrast, saturation); + // FIXME factorize + +#if ARCH_PPC + ff_yuv2rgb_init_tables_ppc(c, inv_table, brightness, + contrast, saturation); +#endif + } + + fill_rgb2yuv_table(c, table, dstRange); + + return 0; +} + +int sws_getColorspaceDetails(SwsContext *sws, int **inv_table, + int *srcRange, int **table, int *dstRange, + int *brightness, int *contrast, int *saturation) +{ + SwsInternal *c = sws_internal(sws); + if (!c) + return -1; + + if (c->nb_slice_ctx) { + return sws_getColorspaceDetails(c->slice_ctx[0], inv_table, srcRange, + table, dstRange, brightness, contrast, + saturation); + } + + *inv_table = c->srcColorspaceTable; + *table = c->dstColorspaceTable; + *srcRange = range_override_needed(sws->src_format) ? 1 : sws->src_range; + *dstRange = range_override_needed(sws->dst_format) ? 1 : sws->dst_range; + *brightness = c->brightness; + *contrast = c->contrast; + *saturation = c->saturation; + + return 0; +} + +SwsContext *sws_alloc_context(void) +{ + SwsInternal *c = av_mallocz(sizeof(*c) + SWSINTERNAL_ADDITIONAL_ASM_SIZE); + if (!c) + return NULL; + + c->opts.av_class = &ff_sws_context_class; + av_opt_set_defaults(c); + atomic_init(&c->stride_unaligned_warned, 0); + atomic_init(&c->data_unaligned_warned, 0); + + return &c->opts; +} + +static uint16_t * alloc_gamma_tbl(double e) +{ + int i = 0; + uint16_t * tbl; + tbl = (uint16_t*)av_malloc(sizeof(uint16_t) * 1 << 16); + if (!tbl) + return NULL; + + for (i = 0; i < 65536; ++i) { + tbl[i] = pow(i / 65535.0, e) * 65535.0; + } + return tbl; +} + +static enum AVPixelFormat alphaless_fmt(enum AVPixelFormat fmt) +{ + switch(fmt) { + case AV_PIX_FMT_ARGB: return AV_PIX_FMT_RGB24; + case AV_PIX_FMT_RGBA: return AV_PIX_FMT_RGB24; + case AV_PIX_FMT_ABGR: return AV_PIX_FMT_BGR24; + case AV_PIX_FMT_BGRA: return AV_PIX_FMT_BGR24; + case AV_PIX_FMT_YA8: return AV_PIX_FMT_GRAY8; + + case AV_PIX_FMT_YUVA420P: return AV_PIX_FMT_YUV420P; + case AV_PIX_FMT_YUVA422P: return AV_PIX_FMT_YUV422P; + case AV_PIX_FMT_YUVA444P: return AV_PIX_FMT_YUV444P; + + case AV_PIX_FMT_GBRAP: return AV_PIX_FMT_GBRP; + + case AV_PIX_FMT_GBRAP10LE: return AV_PIX_FMT_GBRP10; + case AV_PIX_FMT_GBRAP10BE: return AV_PIX_FMT_GBRP10; + + case AV_PIX_FMT_GBRAP12LE: return AV_PIX_FMT_GBRP12; + case AV_PIX_FMT_GBRAP12BE: return AV_PIX_FMT_GBRP12; + + case AV_PIX_FMT_GBRAP14LE: return AV_PIX_FMT_GBRP14; + case AV_PIX_FMT_GBRAP14BE: return AV_PIX_FMT_GBRP14; + + case AV_PIX_FMT_GBRAP16LE: return AV_PIX_FMT_GBRP16; + case AV_PIX_FMT_GBRAP16BE: return AV_PIX_FMT_GBRP16; + + case AV_PIX_FMT_RGBA64LE: return AV_PIX_FMT_RGB48; + case AV_PIX_FMT_RGBA64BE: return AV_PIX_FMT_RGB48; + case AV_PIX_FMT_BGRA64LE: return AV_PIX_FMT_BGR48; + case AV_PIX_FMT_BGRA64BE: return AV_PIX_FMT_BGR48; + + case AV_PIX_FMT_YA16BE: return AV_PIX_FMT_GRAY16; + case AV_PIX_FMT_YA16LE: return AV_PIX_FMT_GRAY16; + + case AV_PIX_FMT_YUVA420P9BE: return AV_PIX_FMT_YUV420P9; + case AV_PIX_FMT_YUVA422P9BE: return AV_PIX_FMT_YUV422P9; + case AV_PIX_FMT_YUVA444P9BE: return AV_PIX_FMT_YUV444P9; + case AV_PIX_FMT_YUVA420P9LE: return AV_PIX_FMT_YUV420P9; + case AV_PIX_FMT_YUVA422P9LE: return AV_PIX_FMT_YUV422P9; + case AV_PIX_FMT_YUVA444P9LE: return AV_PIX_FMT_YUV444P9; + case AV_PIX_FMT_YUVA420P10BE: return AV_PIX_FMT_YUV420P10; + case AV_PIX_FMT_YUVA422P10BE: return AV_PIX_FMT_YUV422P10; + case AV_PIX_FMT_YUVA444P10BE: return AV_PIX_FMT_YUV444P10; + case AV_PIX_FMT_YUVA420P10LE: return AV_PIX_FMT_YUV420P10; + case AV_PIX_FMT_YUVA422P10LE: return AV_PIX_FMT_YUV422P10; + case AV_PIX_FMT_YUVA444P10LE: return AV_PIX_FMT_YUV444P10; + case AV_PIX_FMT_YUVA420P16BE: return AV_PIX_FMT_YUV420P16; + case AV_PIX_FMT_YUVA422P16BE: return AV_PIX_FMT_YUV422P16; + case AV_PIX_FMT_YUVA444P16BE: return AV_PIX_FMT_YUV444P16; + case AV_PIX_FMT_YUVA420P16LE: return AV_PIX_FMT_YUV420P16; + case AV_PIX_FMT_YUVA422P16LE: return AV_PIX_FMT_YUV422P16; + case AV_PIX_FMT_YUVA444P16LE: return AV_PIX_FMT_YUV444P16; + +// case AV_PIX_FMT_AYUV64LE: +// case AV_PIX_FMT_AYUV64BE: +// case AV_PIX_FMT_PAL8: + default: return AV_PIX_FMT_NONE; + } +} + +av_cold int ff_sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter, + SwsFilter *dstFilter) +{ + int i; + int usesVFilter, usesHFilter; + int unscaled; + SwsInternal *c = sws_internal(sws); + SwsFilter dummyFilter = { NULL, NULL, NULL, NULL }; + int srcW = sws->src_w; + int srcH = sws->src_h; + int dstW = sws->dst_w; + int dstH = sws->dst_h; + int dst_stride = FFALIGN(dstW * sizeof(int16_t) + 66, 16); + int flags, cpu_flags; + enum AVPixelFormat srcFormat, dstFormat; + const AVPixFmtDescriptor *desc_src; + const AVPixFmtDescriptor *desc_dst; + int ret = 0; + enum AVPixelFormat tmpFmt; + static const float float_mult = 1.0f / 255.0f; + + cpu_flags = av_get_cpu_flags(); + flags = sws->flags; + emms_c(); + + unscaled = (srcW == dstW && srcH == dstH); + + if (!c->contrast && !c->saturation && !c->dstFormatBpp) + sws_setColorspaceDetails(sws, ff_yuv2rgb_coeffs[SWS_CS_DEFAULT], sws->src_range, + ff_yuv2rgb_coeffs[SWS_CS_DEFAULT], + sws->dst_range, 0, 1 << 16, 1 << 16); + + ret = handle_formats(sws); + if (ret < 0) + return ret; + srcFormat = sws->src_format; + dstFormat = sws->dst_format; + desc_src = av_pix_fmt_desc_get(srcFormat); + desc_dst = av_pix_fmt_desc_get(dstFormat); + + // If the source has no alpha then disable alpha blendaway + if (c->src0Alpha) + sws->alpha_blend = SWS_ALPHA_BLEND_NONE; + + if (!(unscaled && sws_isSupportedEndiannessConversion(srcFormat) && + av_pix_fmt_swap_endianness(srcFormat) == dstFormat)) { + if (!sws_isSupportedInput(srcFormat)) { + av_log(c, AV_LOG_ERROR, "%s is not supported as input pixel format\n", + av_get_pix_fmt_name(srcFormat)); + return AVERROR(EINVAL); + } + if (!sws_isSupportedOutput(dstFormat)) { + av_log(c, AV_LOG_ERROR, "%s is not supported as output pixel format\n", + av_get_pix_fmt_name(dstFormat)); + return AVERROR(EINVAL); + } + } + av_assert2(desc_src && desc_dst); + + i = flags & (SWS_POINT | + SWS_AREA | + SWS_BILINEAR | + SWS_FAST_BILINEAR | + SWS_BICUBIC | + SWS_X | + SWS_GAUSS | + SWS_LANCZOS | + SWS_SINC | + SWS_SPLINE | + SWS_BICUBLIN); + + /* provide a default scaler if not set by caller */ + if (!i) { + if (dstW < srcW && dstH < srcH) + flags |= SWS_BICUBIC; + else if (dstW > srcW && dstH > srcH) + flags |= SWS_BICUBIC; + else + flags |= SWS_BICUBIC; + sws->flags = flags; + } else if (i & (i - 1)) { + av_log(c, AV_LOG_ERROR, + "Exactly one scaler algorithm must be chosen, got %X\n", i); + return AVERROR(EINVAL); + } + /* sanity check */ + if (srcW < 1 || srcH < 1 || dstW < 1 || dstH < 1) { + /* FIXME check if these are enough and try to lower them after + * fixing the relevant parts of the code */ + av_log(c, AV_LOG_ERROR, "%dx%d -> %dx%d is invalid scaling dimension\n", + srcW, srcH, dstW, dstH); + return AVERROR(EINVAL); + } + if (flags & SWS_FAST_BILINEAR) { + if (srcW < 8 || dstW <= 8) { + flags ^= SWS_FAST_BILINEAR | SWS_BILINEAR; + sws->flags = flags; + } + } + + if (!dstFilter) + dstFilter = &dummyFilter; + if (!srcFilter) + srcFilter = &dummyFilter; + + int64_t lumXInc = (((int64_t)srcW << 16) + (dstW >> 1)) / dstW; + int64_t lumYInc = (((int64_t)srcH << 16) + (dstH >> 1)) / dstH; + c->dstFormatBpp = av_get_bits_per_pixel(desc_dst); + c->srcFormatBpp = av_get_bits_per_pixel(desc_src); + c->vRounder = 4 * 0x0001000100010001ULL; + + usesVFilter = (srcFilter->lumV && srcFilter->lumV->length > 1) || + (srcFilter->chrV && srcFilter->chrV->length > 1) || + (dstFilter->lumV && dstFilter->lumV->length > 1) || + (dstFilter->chrV && dstFilter->chrV->length > 1); + usesHFilter = (srcFilter->lumH && srcFilter->lumH->length > 1) || + (srcFilter->chrH && srcFilter->chrH->length > 1) || + (dstFilter->lumH && dstFilter->lumH->length > 1) || + (dstFilter->chrH && dstFilter->chrH->length > 1); + + av_pix_fmt_get_chroma_sub_sample(srcFormat, &c->chrSrcHSubSample, &c->chrSrcVSubSample); + av_pix_fmt_get_chroma_sub_sample(dstFormat, &c->chrDstHSubSample, &c->chrDstVSubSample); + + c->dst_slice_align = 1 << c->chrDstVSubSample; + + if (isAnyRGB(dstFormat) && !(flags&SWS_FULL_CHR_H_INT)) { + if (dstW&1) { + av_log(c, AV_LOG_DEBUG, "Forcing full internal H chroma due to odd output size\n"); + flags |= SWS_FULL_CHR_H_INT; + sws->flags = flags; + } + + if ( c->chrSrcHSubSample == 0 + && c->chrSrcVSubSample == 0 + && sws->dither != SWS_DITHER_BAYER //SWS_FULL_CHR_H_INT is currently not supported with SWS_DITHER_BAYER + && !(sws->flags & SWS_FAST_BILINEAR) + ) { + av_log(c, AV_LOG_DEBUG, "Forcing full internal H chroma due to input having non subsampled chroma\n"); + flags |= SWS_FULL_CHR_H_INT; + sws->flags = flags; + } + } + + if (sws->dither == SWS_DITHER_AUTO) { + if (flags & SWS_ERROR_DIFFUSION) + sws->dither = SWS_DITHER_ED; + } + + if(dstFormat == AV_PIX_FMT_BGR4_BYTE || + dstFormat == AV_PIX_FMT_RGB4_BYTE || + dstFormat == AV_PIX_FMT_BGR8 || + dstFormat == AV_PIX_FMT_RGB8) { + if (sws->dither == SWS_DITHER_AUTO) + sws->dither = (flags & SWS_FULL_CHR_H_INT) ? SWS_DITHER_ED : SWS_DITHER_BAYER; + if (!(flags & SWS_FULL_CHR_H_INT)) { + if (sws->dither == SWS_DITHER_ED || sws->dither == SWS_DITHER_A_DITHER || sws->dither == SWS_DITHER_X_DITHER || sws->dither == SWS_DITHER_NONE) { + av_log(c, AV_LOG_DEBUG, + "Desired dithering only supported in full chroma interpolation for destination format '%s'\n", + av_get_pix_fmt_name(dstFormat)); + flags |= SWS_FULL_CHR_H_INT; + sws->flags = flags; + } + } + if (flags & SWS_FULL_CHR_H_INT) { + if (sws->dither == SWS_DITHER_BAYER) { + av_log(c, AV_LOG_DEBUG, + "Ordered dither is not supported in full chroma interpolation for destination format '%s'\n", + av_get_pix_fmt_name(dstFormat)); + sws->dither = SWS_DITHER_ED; + } + } + } + if (isPlanarRGB(dstFormat)) { + if (!(flags & SWS_FULL_CHR_H_INT)) { + av_log(c, AV_LOG_DEBUG, + "%s output is not supported with half chroma resolution, switching to full\n", + av_get_pix_fmt_name(dstFormat)); + flags |= SWS_FULL_CHR_H_INT; + sws->flags = flags; + } + } + + /* reuse chroma for 2 pixels RGB/BGR unless user wants full + * chroma interpolation */ + if (flags & SWS_FULL_CHR_H_INT && + isAnyRGB(dstFormat) && + !isPlanarRGB(dstFormat) && + dstFormat != AV_PIX_FMT_RGBA64LE && + dstFormat != AV_PIX_FMT_RGBA64BE && + dstFormat != AV_PIX_FMT_BGRA64LE && + dstFormat != AV_PIX_FMT_BGRA64BE && + dstFormat != AV_PIX_FMT_RGB48LE && + dstFormat != AV_PIX_FMT_RGB48BE && + dstFormat != AV_PIX_FMT_BGR48LE && + dstFormat != AV_PIX_FMT_BGR48BE && + dstFormat != AV_PIX_FMT_RGBA && + dstFormat != AV_PIX_FMT_ARGB && + dstFormat != AV_PIX_FMT_BGRA && + dstFormat != AV_PIX_FMT_ABGR && + dstFormat != AV_PIX_FMT_RGB24 && + dstFormat != AV_PIX_FMT_BGR24 && + dstFormat != AV_PIX_FMT_BGR4_BYTE && + dstFormat != AV_PIX_FMT_RGB4_BYTE && + dstFormat != AV_PIX_FMT_BGR8 && + dstFormat != AV_PIX_FMT_RGB8 && + dstFormat != AV_PIX_FMT_X2RGB10LE && + dstFormat != AV_PIX_FMT_X2BGR10LE + ) { + av_log(c, AV_LOG_WARNING, + "full chroma interpolation for destination format '%s' not yet implemented\n", + av_get_pix_fmt_name(dstFormat)); + flags &= ~SWS_FULL_CHR_H_INT; + sws->flags = flags; + } + if (isAnyRGB(dstFormat) && !(flags & SWS_FULL_CHR_H_INT)) + c->chrDstHSubSample = 1; + + // drop some chroma lines if the user wants it + c->vChrDrop = (flags & SWS_SRC_V_CHR_DROP_MASK) >> + SWS_SRC_V_CHR_DROP_SHIFT; + c->chrSrcVSubSample += c->vChrDrop; + + /* drop every other pixel for chroma calculation unless user + * wants full chroma */ + if (isAnyRGB(srcFormat) && !(srcW & 1) && !(flags & SWS_FULL_CHR_H_INP) && + srcFormat != AV_PIX_FMT_RGB8 && srcFormat != AV_PIX_FMT_BGR8 && + srcFormat != AV_PIX_FMT_RGB4 && srcFormat != AV_PIX_FMT_BGR4 && + srcFormat != AV_PIX_FMT_RGB4_BYTE && srcFormat != AV_PIX_FMT_BGR4_BYTE && + srcFormat != AV_PIX_FMT_GBRP9BE && srcFormat != AV_PIX_FMT_GBRP9LE && + srcFormat != AV_PIX_FMT_GBRP10BE && srcFormat != AV_PIX_FMT_GBRP10LE && + srcFormat != AV_PIX_FMT_GBRP10MSBBE && srcFormat != AV_PIX_FMT_GBRP10MSBLE && + srcFormat != AV_PIX_FMT_GBRAP10BE && srcFormat != AV_PIX_FMT_GBRAP10LE && + srcFormat != AV_PIX_FMT_GBRP12BE && srcFormat != AV_PIX_FMT_GBRP12LE && + srcFormat != AV_PIX_FMT_GBRP12MSBBE && srcFormat != AV_PIX_FMT_GBRP12MSBLE && + srcFormat != AV_PIX_FMT_GBRAP12BE && srcFormat != AV_PIX_FMT_GBRAP12LE && + srcFormat != AV_PIX_FMT_GBRAP14BE && srcFormat != AV_PIX_FMT_GBRAP14LE && + srcFormat != AV_PIX_FMT_GBRP14BE && srcFormat != AV_PIX_FMT_GBRP14LE && + srcFormat != AV_PIX_FMT_GBRP16BE && srcFormat != AV_PIX_FMT_GBRP16LE && + srcFormat != AV_PIX_FMT_GBRAP16BE && srcFormat != AV_PIX_FMT_GBRAP16LE && + srcFormat != AV_PIX_FMT_GBRPF32BE && srcFormat != AV_PIX_FMT_GBRPF32LE && + srcFormat != AV_PIX_FMT_GBRAPF32BE && srcFormat != AV_PIX_FMT_GBRAPF32LE && + srcFormat != AV_PIX_FMT_GBRPF16BE && srcFormat != AV_PIX_FMT_GBRPF16LE && + srcFormat != AV_PIX_FMT_GBRAPF16BE && srcFormat != AV_PIX_FMT_GBRAPF16LE && + ((dstW >> c->chrDstHSubSample) <= (srcW >> 1) || + (flags & SWS_FAST_BILINEAR))) + c->chrSrcHSubSample = 1; + + // Note the AV_CEIL_RSHIFT is so that we always round toward +inf. + c->chrSrcW = AV_CEIL_RSHIFT(srcW, c->chrSrcHSubSample); + c->chrSrcH = AV_CEIL_RSHIFT(srcH, c->chrSrcVSubSample); + c->chrDstW = AV_CEIL_RSHIFT(dstW, c->chrDstHSubSample); + c->chrDstH = AV_CEIL_RSHIFT(dstH, c->chrDstVSubSample); + + if (!FF_ALLOCZ_TYPED_ARRAY(c->formatConvBuffer, FFALIGN(srcW * 2 + 78, 16) * 2)) + goto nomem; + + c->srcBpc = desc_src->comp[0].depth; + if (c->srcBpc < 8) + c->srcBpc = 8; + c->dstBpc = desc_dst->comp[0].depth; + if (c->dstBpc < 8) + c->dstBpc = 8; + if (isAnyRGB(srcFormat) || srcFormat == AV_PIX_FMT_PAL8) + c->srcBpc = 16; + if (c->dstBpc == 16) + dst_stride <<= 1; + + if (INLINE_MMXEXT(cpu_flags) && c->srcBpc == 8 && c->dstBpc <= 14) { + c->canMMXEXTBeUsed = dstW >= srcW && (dstW & 31) == 0 && + c->chrDstW >= c->chrSrcW && + (srcW & 15) == 0; + if (!c->canMMXEXTBeUsed && dstW >= srcW && c->chrDstW >= c->chrSrcW && (srcW & 15) == 0 + + && (flags & SWS_FAST_BILINEAR)) { + if (flags & SWS_PRINT_INFO) + av_log(c, AV_LOG_INFO, + "output width is not a multiple of 32 -> no MMXEXT scaler\n"); + } + if (usesHFilter || isNBPS(sws->src_format) || is16BPS(sws->src_format) || isAnyRGB(sws->src_format)) + c->canMMXEXTBeUsed = 0; + } else + c->canMMXEXTBeUsed = 0; + + int64_t chrXInc = (((int64_t)c->chrSrcW << 16) + (c->chrDstW >> 1)) / c->chrDstW; + int64_t chrYInc = (((int64_t)c->chrSrcH << 16) + (c->chrDstH >> 1)) / c->chrDstH; + + /* Match pixel 0 of the src to pixel 0 of dst and match pixel n-2 of src + * to pixel n-2 of dst, but only for the FAST_BILINEAR mode otherwise do + * correct scaling. + * n-2 is the last chrominance sample available. + * This is not perfect, but no one should notice the difference, the more + * correct variant would be like the vertical one, but that would require + * some special code for the first and last pixel */ + if (flags & SWS_FAST_BILINEAR) { + if (c->canMMXEXTBeUsed) { + lumXInc += 20; + chrXInc += 20; + } + // we don't use the x86 asm scaler if MMX is available + else if (INLINE_MMX(cpu_flags) && c->dstBpc <= 14) { + lumXInc = ((int64_t)(srcW - 2) << 16) / (dstW - 2) - 20; + chrXInc = ((int64_t)(c->chrSrcW - 2) << 16) / (c->chrDstW - 2) - 20; + } + } + if (chrXInc < 10 || chrXInc > INT_MAX || + chrYInc < 10 || chrYInc > INT_MAX || + lumXInc < 10 || lumXInc > INT_MAX || + lumYInc < 10 || lumYInc > INT_MAX) + return AVERROR_PATCHWELCOME; + + c->lumXInc = lumXInc; + c->lumYInc = lumYInc; + c->chrXInc = chrXInc; + c->chrYInc = chrYInc; + + + // hardcoded for now + c->gamma_value = 2.2; + tmpFmt = AV_PIX_FMT_RGBA64LE; + + if (!unscaled && sws->gamma_flag && (srcFormat != tmpFmt || dstFormat != tmpFmt)) { + SwsInternal *c2; + c->cascaded_context[0] = NULL; + + ret = av_image_alloc(c->cascaded_tmp[0], c->cascaded_tmpStride[0], + srcW, srcH, tmpFmt, 64); + if (ret < 0) + return ret; + + c->cascaded_context[0] = sws_getContext(srcW, srcH, srcFormat, + srcW, srcH, tmpFmt, + flags, NULL, NULL, + sws->scaler_params); + if (!c->cascaded_context[0]) { + return AVERROR(ENOMEM); + } + + c->cascaded_context[1] = sws_getContext(srcW, srcH, tmpFmt, + dstW, dstH, tmpFmt, + flags, srcFilter, dstFilter, + sws->scaler_params); + + if (!c->cascaded_context[1]) + return AVERROR(ENOMEM); + + c2 = sws_internal(c->cascaded_context[1]); + c2->is_internal_gamma = 1; + c2->gamma = alloc_gamma_tbl( c->gamma_value); + c2->inv_gamma = alloc_gamma_tbl(1.f/c->gamma_value); + if (!c2->gamma || !c2->inv_gamma) + return AVERROR(ENOMEM); + + // is_internal_flag is set after creating the context + // to properly create the gamma convert FilterDescriptor + // we have to re-initialize it + ff_free_filters(c2); + if ((ret = ff_init_filters(c2)) < 0) { + sws_freeContext(c->cascaded_context[1]); + c->cascaded_context[1] = NULL; + return ret; + } + + c->cascaded_context[2] = NULL; + if (dstFormat != tmpFmt) { + ret = av_image_alloc(c->cascaded_tmp[1], c->cascaded_tmpStride[1], + dstW, dstH, tmpFmt, 64); + if (ret < 0) + return ret; + + c->cascaded_context[2] = sws_getContext(dstW, dstH, tmpFmt, + dstW, dstH, dstFormat, + flags, NULL, NULL, + sws->scaler_params); + if (!c->cascaded_context[2]) + return AVERROR(ENOMEM); + } + return 0; + } + + if (isBayer(srcFormat)) { + if (!unscaled || + (dstFormat != AV_PIX_FMT_RGB24 && dstFormat != AV_PIX_FMT_YUV420P && + dstFormat != AV_PIX_FMT_RGB48)) { + enum AVPixelFormat tmpFormat = isBayer16BPS(srcFormat) ? AV_PIX_FMT_RGB48 : AV_PIX_FMT_RGB24; + + ret = av_image_alloc(c->cascaded_tmp[0], c->cascaded_tmpStride[0], + srcW, srcH, tmpFormat, 64); + if (ret < 0) + return ret; + + c->cascaded_context[0] = sws_getContext(srcW, srcH, srcFormat, + srcW, srcH, tmpFormat, + flags, srcFilter, NULL, + sws->scaler_params); + if (!c->cascaded_context[0]) + return AVERROR(ENOMEM); + + c->cascaded_context[1] = sws_getContext(srcW, srcH, tmpFormat, + dstW, dstH, dstFormat, + flags, NULL, dstFilter, + sws->scaler_params); + if (!c->cascaded_context[1]) + return AVERROR(ENOMEM); + return 0; + } + } + + if (unscaled && c->srcBpc == 8 && dstFormat == AV_PIX_FMT_GRAYF32){ + for (i = 0; i < 256; ++i){ + c->uint2float_lut[i] = (float)i * float_mult; + } + } + + // float will be converted to uint16_t + if ((srcFormat == AV_PIX_FMT_GRAYF32BE || srcFormat == AV_PIX_FMT_GRAYF32LE) && + (!unscaled || unscaled && dstFormat != srcFormat && (srcFormat != AV_PIX_FMT_GRAYF32 || + dstFormat != AV_PIX_FMT_GRAY8))){ + c->srcBpc = 16; + } + + if (CONFIG_SWSCALE_ALPHA && isALPHA(srcFormat) && !isALPHA(dstFormat)) { + enum AVPixelFormat tmpFormat = alphaless_fmt(srcFormat); + + if (tmpFormat != AV_PIX_FMT_NONE && sws->alpha_blend != SWS_ALPHA_BLEND_NONE) { + if (!unscaled || + dstFormat != tmpFormat || + usesHFilter || usesVFilter || + sws->src_range != sws->dst_range + ) { + c->cascaded_mainindex = 1; + ret = av_image_alloc(c->cascaded_tmp[0], c->cascaded_tmpStride[0], + srcW, srcH, tmpFormat, 64); + if (ret < 0) + return ret; + + c->cascaded_context[0] = alloc_set_opts(srcW, srcH, srcFormat, + srcW, srcH, tmpFormat, + flags, sws->scaler_params); + if (!c->cascaded_context[0]) + return AVERROR(EINVAL); + c->cascaded_context[0]->alpha_blend = sws->alpha_blend; + ret = sws_init_context(c->cascaded_context[0], NULL , NULL); + if (ret < 0) + return ret; + + c->cascaded_context[1] = alloc_set_opts(srcW, srcH, tmpFormat, + dstW, dstH, dstFormat, + flags, sws->scaler_params); + if (!c->cascaded_context[1]) + return AVERROR(EINVAL); + + c->cascaded_context[1]->src_range = sws->src_range; + c->cascaded_context[1]->dst_range = sws->dst_range; + ret = sws_init_context(c->cascaded_context[1], srcFilter , dstFilter); + if (ret < 0) + return ret; + + return 0; + } + } + } + + /* alpha blend special case, note this has been split via cascaded contexts if its scaled */ + if (unscaled && !usesHFilter && !usesVFilter && + sws->alpha_blend != SWS_ALPHA_BLEND_NONE && + isALPHA(srcFormat) && + (sws->src_range == sws->dst_range || isAnyRGB(dstFormat)) && + alphaless_fmt(srcFormat) == dstFormat + ) { + c->convert_unscaled = ff_sws_alphablendaway; + + if (flags & SWS_PRINT_INFO) + av_log(c, AV_LOG_INFO, + "using alpha blendaway %s -> %s special converter\n", + av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat)); + return 0; + } + + /* unscaled special cases */ + if (unscaled && !usesHFilter && !usesVFilter && + (sws->src_range == sws->dst_range || isAnyRGB(dstFormat) || + isFloat(srcFormat) || isFloat(dstFormat) || isBayer(srcFormat))){ + + ff_get_unscaled_swscale(c); + + if (c->convert_unscaled) { + if (flags & SWS_PRINT_INFO) + av_log(c, AV_LOG_INFO, + "using unscaled %s -> %s special converter\n", + av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat)); + return 0; + } + } + +#if HAVE_MMAP && HAVE_MPROTECT && defined(MAP_ANONYMOUS) +#define USE_MMAP 1 +#else +#define USE_MMAP 0 +#endif + + /* precalculate horizontal scaler filter coefficients */ + { +#if HAVE_MMXEXT_INLINE +// can't downscale !!! + if (c->canMMXEXTBeUsed && (flags & SWS_FAST_BILINEAR)) { + c->lumMmxextFilterCodeSize = ff_init_hscaler_mmxext(dstW, c->lumXInc, NULL, + NULL, NULL, 8); + c->chrMmxextFilterCodeSize = ff_init_hscaler_mmxext(c->chrDstW, c->chrXInc, + NULL, NULL, NULL, 4); + +#if USE_MMAP + c->lumMmxextFilterCode = mmap(NULL, c->lumMmxextFilterCodeSize, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + c->chrMmxextFilterCode = mmap(NULL, c->chrMmxextFilterCodeSize, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); +#elif HAVE_VIRTUALALLOC + c->lumMmxextFilterCode = VirtualAlloc(NULL, + c->lumMmxextFilterCodeSize, + MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + c->chrMmxextFilterCode = VirtualAlloc(NULL, + c->chrMmxextFilterCodeSize, + MEM_COMMIT, + PAGE_EXECUTE_READWRITE); +#else + c->lumMmxextFilterCode = av_malloc(c->lumMmxextFilterCodeSize); + c->chrMmxextFilterCode = av_malloc(c->chrMmxextFilterCodeSize); +#endif + +#ifdef MAP_ANONYMOUS + if (c->lumMmxextFilterCode == MAP_FAILED || c->chrMmxextFilterCode == MAP_FAILED) +#else + if (!c->lumMmxextFilterCode || !c->chrMmxextFilterCode) +#endif + { + av_log(c, AV_LOG_ERROR, "Failed to allocate MMX2FilterCode\n"); + return AVERROR(ENOMEM); + } + + if (!FF_ALLOCZ_TYPED_ARRAY(c->hLumFilter, dstW / 8 + 8) || + !FF_ALLOCZ_TYPED_ARRAY(c->hChrFilter, c->chrDstW / 4 + 8) || + !FF_ALLOCZ_TYPED_ARRAY(c->hLumFilterPos, dstW / 2 / 8 + 8) || + !FF_ALLOCZ_TYPED_ARRAY(c->hChrFilterPos, c->chrDstW / 2 / 4 + 8)) + goto nomem; + + ff_init_hscaler_mmxext( dstW, c->lumXInc, c->lumMmxextFilterCode, + c->hLumFilter, (uint32_t*)c->hLumFilterPos, 8); + ff_init_hscaler_mmxext(c->chrDstW, c->chrXInc, c->chrMmxextFilterCode, + c->hChrFilter, (uint32_t*)c->hChrFilterPos, 4); + +#if USE_MMAP + if ( mprotect(c->lumMmxextFilterCode, c->lumMmxextFilterCodeSize, PROT_EXEC | PROT_READ) == -1 + || mprotect(c->chrMmxextFilterCode, c->chrMmxextFilterCodeSize, PROT_EXEC | PROT_READ) == -1) { + av_log(c, AV_LOG_ERROR, "mprotect failed, cannot use fast bilinear scaler\n"); + ret = AVERROR(EINVAL); + goto fail; + } +#endif + } else +#endif /* HAVE_MMXEXT_INLINE */ + { + const int filterAlign = X86_MMX(cpu_flags) ? 4 : + PPC_ALTIVEC(cpu_flags) ? 8 : + have_neon(cpu_flags) ? 4 : + have_lsx(cpu_flags) ? 8 : + have_lasx(cpu_flags) ? 8 : 1; + + if ((ret = initFilter(&c->hLumFilter, &c->hLumFilterPos, + &c->hLumFilterSize, c->lumXInc, + srcW, dstW, filterAlign, 1 << 14, + (flags & SWS_BICUBLIN) ? (flags | SWS_BICUBIC) : flags, + cpu_flags, srcFilter->lumH, dstFilter->lumH, + sws->scaler_params, + get_local_pos(c, 0, 0, 0), + get_local_pos(c, 0, 0, 0))) < 0) + goto fail; + if (ff_shuffle_filter_coefficients(c, c->hLumFilterPos, c->hLumFilterSize, c->hLumFilter, dstW) < 0) + goto nomem; + if ((ret = initFilter(&c->hChrFilter, &c->hChrFilterPos, + &c->hChrFilterSize, c->chrXInc, + c->chrSrcW, c->chrDstW, filterAlign, 1 << 14, + (flags & SWS_BICUBLIN) ? (flags | SWS_BILINEAR) : flags, + cpu_flags, srcFilter->chrH, dstFilter->chrH, + sws->scaler_params, + get_local_pos(c, c->chrSrcHSubSample, sws->src_h_chr_pos, 0), + get_local_pos(c, c->chrDstHSubSample, sws->dst_h_chr_pos, 0))) < 0) + goto fail; + if (ff_shuffle_filter_coefficients(c, c->hChrFilterPos, c->hChrFilterSize, c->hChrFilter, c->chrDstW) < 0) + goto nomem; + } + } // initialize horizontal stuff + + /* precalculate vertical scaler filter coefficients */ + { + const int filterAlign = X86_MMX(cpu_flags) ? 2 : + PPC_ALTIVEC(cpu_flags) ? 8 : + have_neon(cpu_flags) ? 2 : 1; + + ret = initFilter(&c->vLumFilter, &c->vLumFilterPos, &c->vLumFilterSize, + c->lumYInc, srcH, dstH, filterAlign, (1 << 12), + (flags & SWS_BICUBLIN) ? (flags | SWS_BICUBIC) : flags, + cpu_flags, srcFilter->lumV, dstFilter->lumV, + sws->scaler_params, + get_local_pos(c, 0, 0, 1), + get_local_pos(c, 0, 0, 1)); + int usecascade = (ret == RETCODE_USE_CASCADE); + if (ret < 0 && !usecascade) + goto fail; + if ((ret = initFilter(&c->vChrFilter, &c->vChrFilterPos, &c->vChrFilterSize, + c->chrYInc, c->chrSrcH, c->chrDstH, + filterAlign, (1 << 12), + (flags & SWS_BICUBLIN) ? (flags | SWS_BILINEAR) : flags, + cpu_flags, srcFilter->chrV, dstFilter->chrV, + sws->scaler_params, + get_local_pos(c, c->chrSrcVSubSample, sws->src_v_chr_pos, 1), + get_local_pos(c, c->chrDstVSubSample, sws->dst_v_chr_pos, 1))) < 0) + + goto fail; + if (usecascade) { + ret = RETCODE_USE_CASCADE; + goto fail; + } + +#if HAVE_ALTIVEC + ret = ff_sws_init_altivec_bufs(c); + if (ret < 0) + goto fail; +#endif + } + + for (i = 0; i < 4; i++) + if (!FF_ALLOCZ_TYPED_ARRAY(c->dither_error[i], sws->dst_w + 3)) + goto nomem; + + c->needAlpha = (CONFIG_SWSCALE_ALPHA && isALPHA(sws->src_format) && isALPHA(sws->dst_format)) ? 1 : 0; + + // 64 / c->scalingBpp is the same as 16 / sizeof(scaling_intermediate) + c->uv_off = (dst_stride>>1) + 64 / (c->dstBpc &~ 7); + c->uv_offx2 = dst_stride + 16; + + av_assert0(c->chrDstH <= dstH); + + if (flags & SWS_PRINT_INFO) { + const char *scaler = NULL, *cpucaps; + + for (i = 0; i < FF_ARRAY_ELEMS(scale_algorithms); i++) { + if (flags & scale_algorithms[i].flag) { + scaler = scale_algorithms[i].description; + break; + } + } + if (!scaler) + scaler = "ehh flags invalid?!"; + av_log(c, AV_LOG_INFO, "%s scaler, from %s to %s%s ", + scaler, + av_get_pix_fmt_name(srcFormat), + dstFormat == AV_PIX_FMT_BGR555 || dstFormat == AV_PIX_FMT_BGR565 || + dstFormat == AV_PIX_FMT_RGB444BE || dstFormat == AV_PIX_FMT_RGB444LE || + dstFormat == AV_PIX_FMT_BGR444BE || dstFormat == AV_PIX_FMT_BGR444LE ? + "dithered " : "", + av_get_pix_fmt_name(dstFormat)); + + if (INLINE_MMXEXT(cpu_flags)) + cpucaps = "MMXEXT"; + else if (INLINE_MMX(cpu_flags)) + cpucaps = "MMX"; + else if (PPC_ALTIVEC(cpu_flags)) + cpucaps = "AltiVec"; + else + cpucaps = "C"; + + av_log(c, AV_LOG_INFO, "using %s\n", cpucaps); + + av_log(c, AV_LOG_VERBOSE, "%dx%d -> %dx%d\n", srcW, srcH, dstW, dstH); + av_log(c, AV_LOG_DEBUG, + "lum srcW=%d srcH=%d dstW=%d dstH=%d xInc=%d yInc=%d\n", + sws->src_w, sws->src_h, sws->dst_w, sws->dst_h, c->lumXInc, c->lumYInc); + av_log(c, AV_LOG_DEBUG, + "chr srcW=%d srcH=%d dstW=%d dstH=%d xInc=%d yInc=%d\n", + c->chrSrcW, c->chrSrcH, c->chrDstW, c->chrDstH, + c->chrXInc, c->chrYInc); + } + + ff_sws_init_scale(c); + + return ff_init_filters(c); +nomem: + ret = AVERROR(ENOMEM); +fail: // FIXME replace things by appropriate error codes + if (ret == RETCODE_USE_CASCADE) { + int tmpW = sqrt(srcW * (int64_t)dstW); + int tmpH = sqrt(srcH * (int64_t)dstH); + enum AVPixelFormat tmpFormat = AV_PIX_FMT_YUV420P; + + if (isALPHA(srcFormat)) + tmpFormat = AV_PIX_FMT_YUVA420P; + + if (srcW*(int64_t)srcH <= 4LL*dstW*dstH) + return AVERROR(EINVAL); + + ret = av_image_alloc(c->cascaded_tmp[0], c->cascaded_tmpStride[0], + tmpW, tmpH, tmpFormat, 64); + if (ret < 0) + return ret; + + c->cascaded_context[0] = sws_getContext(srcW, srcH, srcFormat, + tmpW, tmpH, tmpFormat, + flags, srcFilter, NULL, + sws->scaler_params); + if (!c->cascaded_context[0]) + return AVERROR(ENOMEM); + + c->cascaded_context[1] = sws_getContext(tmpW, tmpH, tmpFormat, + dstW, dstH, dstFormat, + flags, NULL, dstFilter, + sws->scaler_params); + if (!c->cascaded_context[1]) + return AVERROR(ENOMEM); + return 0; + } + return ret; +} + +static int context_init_threaded(SwsContext *sws, + SwsFilter *src_filter, SwsFilter *dst_filter) +{ + SwsInternal *c = sws_internal(sws); + int ret; + + ret = avpriv_slicethread_create(&c->slicethread, (void*) sws, + ff_sws_slice_worker, NULL, sws->threads); + if (ret == AVERROR(ENOSYS)) { + sws->threads = 1; + return 0; + } else if (ret < 0) + return ret; + + sws->threads = ret; + + c->slice_ctx = av_calloc(sws->threads, sizeof(*c->slice_ctx)); + c->slice_err = av_calloc(sws->threads, sizeof(*c->slice_err)); + if (!c->slice_ctx || !c->slice_err) + return AVERROR(ENOMEM); + + for (int i = 0; i < sws->threads; i++) { + SwsContext *slice; + slice = c->slice_ctx[i] = sws_alloc_context(); + if (!slice) + return AVERROR(ENOMEM); + sws_internal(slice)->parent = sws; + c->nb_slice_ctx++; + + ret = av_opt_copy(slice, sws); + if (ret < 0) + return ret; + slice->threads = 1; + + ret = ff_sws_init_single_context(slice, src_filter, dst_filter); + if (ret < 0) + return ret; + + if (slice->dither == SWS_DITHER_ED) { + av_log(c, AV_LOG_VERBOSE, + "Error-diffusion dither is in use, scaling will be single-threaded."); + break; + } + } + + return 0; +} + +av_cold int sws_init_context(SwsContext *sws, SwsFilter *srcFilter, + SwsFilter *dstFilter) +{ + SwsInternal *c = sws_internal(sws); + static AVOnce rgb2rgb_once = AV_ONCE_INIT; + enum AVPixelFormat src_format, dst_format; + int ret; + + c->is_legacy_init = 1; + c->frame_src = av_frame_alloc(); + c->frame_dst = av_frame_alloc(); + if (!c->frame_src || !c->frame_dst) + return AVERROR(ENOMEM); + + if (ff_thread_once(&rgb2rgb_once, ff_sws_rgb2rgb_init) != 0) + return AVERROR_UNKNOWN; + + src_format = sws->src_format; + dst_format = sws->dst_format; + sws->src_range |= handle_jpeg(&sws->src_format); + sws->dst_range |= handle_jpeg(&sws->dst_format); + + if (src_format != sws->src_format || dst_format != sws->dst_format) + av_log(c, AV_LOG_WARNING, "deprecated pixel format used, make sure you did set range correctly\n"); + + if (sws->threads != 1) { + ret = context_init_threaded(sws, srcFilter, dstFilter); + if (ret < 0 || sws->threads > 1) + return ret; + // threading disabled in this build, init as single-threaded + } + + return ff_sws_init_single_context(sws, srcFilter, dstFilter); +} + +SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat, + int dstW, int dstH, enum AVPixelFormat dstFormat, + int flags, SwsFilter *srcFilter, + SwsFilter *dstFilter, const double *param) +{ + SwsContext *sws; + + sws = alloc_set_opts(srcW, srcH, srcFormat, + dstW, dstH, dstFormat, + flags, param); + if (!sws) + return NULL; + + if (sws_init_context(sws, srcFilter, dstFilter) < 0) { + sws_freeContext(sws); + return NULL; + } + + return sws; +} + +static int isnan_vec(SwsVector *a) +{ + int i; + for (i=0; i<a->length; i++) + if (isnan(a->coeff[i])) + return 1; + return 0; +} + +static void makenan_vec(SwsVector *a) +{ + int i; + for (i=0; i<a->length; i++) + a->coeff[i] = NAN; +} + +SwsVector *sws_allocVec(int length) +{ + SwsVector *vec; + + if(length <= 0 || length > INT_MAX/ sizeof(double)) + return NULL; + + vec = av_malloc(sizeof(SwsVector)); + if (!vec) + return NULL; + vec->length = length; + vec->coeff = av_malloc(sizeof(double) * length); + if (!vec->coeff) + av_freep(&vec); + return vec; +} + +SwsVector *sws_getGaussianVec(double variance, double quality) +{ + const int length = (int)(variance * quality + 0.5) | 1; + int i; + double middle = (length - 1) * 0.5; + SwsVector *vec; + + if(variance < 0 || quality < 0) + return NULL; + + vec = sws_allocVec(length); + + if (!vec) + return NULL; + + for (i = 0; i < length; i++) { + double dist = i - middle; + vec->coeff[i] = exp(-dist * dist / (2 * variance * variance)) / + sqrt(2 * variance * M_PI); + } + + sws_normalizeVec(vec, 1.0); + + return vec; +} + +/** + * Allocate and return a vector with length coefficients, all + * with the same value c. + */ +static +SwsVector *sws_getConstVec(double c, int length) +{ + int i; + SwsVector *vec = sws_allocVec(length); + + if (!vec) + return NULL; + + for (i = 0; i < length; i++) + vec->coeff[i] = c; + + return vec; +} + +/** + * Allocate and return a vector with just one coefficient, with + * value 1.0. + */ +static +SwsVector *sws_getIdentityVec(void) +{ + return sws_getConstVec(1.0, 1); +} + +static double sws_dcVec(SwsVector *a) +{ + int i; + double sum = 0; + + for (i = 0; i < a->length; i++) + sum += a->coeff[i]; + + return sum; +} + +void sws_scaleVec(SwsVector *a, double scalar) +{ + int i; + + for (i = 0; i < a->length; i++) + a->coeff[i] *= scalar; +} + +void sws_normalizeVec(SwsVector *a, double height) +{ + sws_scaleVec(a, height / sws_dcVec(a)); +} + +static SwsVector *sws_sumVec(SwsVector *a, SwsVector *b) +{ + int length = FFMAX(a->length, b->length); + int i; + SwsVector *vec = sws_getConstVec(0.0, length); + + if (!vec) + return NULL; + + for (i = 0; i < a->length; i++) + vec->coeff[i + (length - 1) / 2 - (a->length - 1) / 2] += a->coeff[i]; + for (i = 0; i < b->length; i++) + vec->coeff[i + (length - 1) / 2 - (b->length - 1) / 2] += b->coeff[i]; + + return vec; +} + +/* shift left / or right if "shift" is negative */ +static SwsVector *sws_getShiftedVec(SwsVector *a, int shift) +{ + int length = a->length + FFABS(shift) * 2; + int i; + SwsVector *vec = sws_getConstVec(0.0, length); + + if (!vec) + return NULL; + + for (i = 0; i < a->length; i++) { + vec->coeff[i + (length - 1) / 2 - + (a->length - 1) / 2 - shift] = a->coeff[i]; + } + + return vec; +} + +static +void sws_shiftVec(SwsVector *a, int shift) +{ + SwsVector *shifted = sws_getShiftedVec(a, shift); + if (!shifted) { + makenan_vec(a); + return; + } + av_free(a->coeff); + a->coeff = shifted->coeff; + a->length = shifted->length; + av_free(shifted); +} + +static +void sws_addVec(SwsVector *a, SwsVector *b) +{ + SwsVector *sum = sws_sumVec(a, b); + if (!sum) { + makenan_vec(a); + return; + } + av_free(a->coeff); + a->coeff = sum->coeff; + a->length = sum->length; + av_free(sum); +} + +/** + * Print with av_log() a textual representation of the vector a + * if log_level <= av_log_level. + */ +static +void sws_printVec2(SwsVector *a, AVClass *log_ctx, int log_level) +{ + int i; + double max = 0; + double min = 0; + double range; + + for (i = 0; i < a->length; i++) + if (a->coeff[i] > max) + max = a->coeff[i]; + + for (i = 0; i < a->length; i++) + if (a->coeff[i] < min) + min = a->coeff[i]; + + range = max - min; + + for (i = 0; i < a->length; i++) { + int x = (int)((a->coeff[i] - min) * 60.0 / range + 0.5); + av_log(log_ctx, log_level, "%1.3f ", a->coeff[i]); + for (; x > 0; x--) + av_log(log_ctx, log_level, " "); + av_log(log_ctx, log_level, "|\n"); + } +} + +void sws_freeVec(SwsVector *a) +{ + if (!a) + return; + av_freep(&a->coeff); + a->length = 0; + av_free(a); +} + +void sws_freeFilter(SwsFilter *filter) +{ + if (!filter) + return; + + sws_freeVec(filter->lumH); + sws_freeVec(filter->lumV); + sws_freeVec(filter->chrH); + sws_freeVec(filter->chrV); + av_free(filter); +} + +SwsFilter *sws_getDefaultFilter(float lumaGBlur, float chromaGBlur, + float lumaSharpen, float chromaSharpen, + float chromaHShift, float chromaVShift, + int verbose) +{ + SwsFilter *filter = av_malloc(sizeof(SwsFilter)); + if (!filter) + return NULL; + + if (lumaGBlur != 0.0) { + filter->lumH = sws_getGaussianVec(lumaGBlur, 3.0); + filter->lumV = sws_getGaussianVec(lumaGBlur, 3.0); + } else { + filter->lumH = sws_getIdentityVec(); + filter->lumV = sws_getIdentityVec(); + } + + if (chromaGBlur != 0.0) { + filter->chrH = sws_getGaussianVec(chromaGBlur, 3.0); + filter->chrV = sws_getGaussianVec(chromaGBlur, 3.0); + } else { + filter->chrH = sws_getIdentityVec(); + filter->chrV = sws_getIdentityVec(); + } + + if (!filter->lumH || !filter->lumV || !filter->chrH || !filter->chrV) + goto fail; + + if (chromaSharpen != 0.0) { + SwsVector *id = sws_getIdentityVec(); + if (!id) + goto fail; + sws_scaleVec(filter->chrH, -chromaSharpen); + sws_scaleVec(filter->chrV, -chromaSharpen); + sws_addVec(filter->chrH, id); + sws_addVec(filter->chrV, id); + sws_freeVec(id); + } + + if (lumaSharpen != 0.0) { + SwsVector *id = sws_getIdentityVec(); + if (!id) + goto fail; + sws_scaleVec(filter->lumH, -lumaSharpen); + sws_scaleVec(filter->lumV, -lumaSharpen); + sws_addVec(filter->lumH, id); + sws_addVec(filter->lumV, id); + sws_freeVec(id); + } + + if (chromaHShift != 0.0) + sws_shiftVec(filter->chrH, (int)(chromaHShift + 0.5)); + + if (chromaVShift != 0.0) + sws_shiftVec(filter->chrV, (int)(chromaVShift + 0.5)); + + sws_normalizeVec(filter->chrH, 1.0); + sws_normalizeVec(filter->chrV, 1.0); + sws_normalizeVec(filter->lumH, 1.0); + sws_normalizeVec(filter->lumV, 1.0); + + if (isnan_vec(filter->chrH) || + isnan_vec(filter->chrV) || + isnan_vec(filter->lumH) || + isnan_vec(filter->lumV)) + goto fail; + + if (verbose) + sws_printVec2(filter->chrH, NULL, AV_LOG_DEBUG); + if (verbose) + sws_printVec2(filter->lumH, NULL, AV_LOG_DEBUG); + + return filter; + +fail: + sws_freeVec(filter->lumH); + sws_freeVec(filter->lumV); + sws_freeVec(filter->chrH); + sws_freeVec(filter->chrV); + av_freep(&filter); + return NULL; +} + +void sws_freeContext(SwsContext *sws) +{ + SwsInternal *c = sws_internal(sws); + int i; + if (!c) + return; + + av_refstruct_unref(&c->hw_priv); + + for (i = 0; i < FF_ARRAY_ELEMS(c->graph); i++) + ff_sws_graph_free(&c->graph[i]); + + for (i = 0; i < c->nb_slice_ctx; i++) + sws_freeContext(c->slice_ctx[i]); + av_freep(&c->slice_ctx); + av_freep(&c->slice_err); + + avpriv_slicethread_free(&c->slicethread); + + for (i = 0; i < 4; i++) + av_freep(&c->dither_error[i]); + + av_frame_free(&c->frame_src); + av_frame_free(&c->frame_dst); + + av_freep(&c->src_ranges.ranges); + + av_freep(&c->vLumFilter); + av_freep(&c->vChrFilter); + av_freep(&c->hLumFilter); + av_freep(&c->hChrFilter); +#if HAVE_ALTIVEC + ff_sws_free_altivec_bufs(c); +#endif + + av_freep(&c->vLumFilterPos); + av_freep(&c->vChrFilterPos); + av_freep(&c->hLumFilterPos); + av_freep(&c->hChrFilterPos); + +#if HAVE_MMX_INLINE +#if USE_MMAP + if (c->lumMmxextFilterCode) + munmap(c->lumMmxextFilterCode, c->lumMmxextFilterCodeSize); + if (c->chrMmxextFilterCode) + munmap(c->chrMmxextFilterCode, c->chrMmxextFilterCodeSize); +#elif HAVE_VIRTUALALLOC + if (c->lumMmxextFilterCode) + VirtualFree(c->lumMmxextFilterCode, 0, MEM_RELEASE); + if (c->chrMmxextFilterCode) + VirtualFree(c->chrMmxextFilterCode, 0, MEM_RELEASE); +#else + av_free(c->lumMmxextFilterCode); + av_free(c->chrMmxextFilterCode); +#endif + c->lumMmxextFilterCode = NULL; + c->chrMmxextFilterCode = NULL; +#endif /* HAVE_MMX_INLINE */ + + av_freep(&c->yuvTable); + av_freep(&c->formatConvBuffer); + + sws_freeContext(c->cascaded_context[0]); + sws_freeContext(c->cascaded_context[1]); + sws_freeContext(c->cascaded_context[2]); + memset(c->cascaded_context, 0, sizeof(c->cascaded_context)); + av_freep(&c->cascaded_tmp[0][0]); + av_freep(&c->cascaded_tmp[1][0]); + + av_freep(&c->gamma); + av_freep(&c->inv_gamma); +#if CONFIG_SMALL + av_freep(&c->xyz2rgb.gamma.in); +#endif + + av_freep(&c->rgb0_scratch); + av_freep(&c->xyz_scratch); + + ff_free_filters(c); + + av_free(c); +} + +void sws_free_context(SwsContext **pctx) +{ + SwsContext *ctx = *pctx; + if (!ctx) + return; + + sws_freeContext(ctx); + *pctx = NULL; +} + +SwsContext *sws_getCachedContext(SwsContext *prev, int srcW, + int srcH, enum AVPixelFormat srcFormat, + int dstW, int dstH, + enum AVPixelFormat dstFormat, int flags, + SwsFilter *srcFilter, + SwsFilter *dstFilter, + const double *param) +{ + SwsContext *sws; + static const double default_param[2] = { SWS_PARAM_DEFAULT, + SWS_PARAM_DEFAULT }; + + if (!param) + param = default_param; + + if (prev && (prev->src_w == srcW && + prev->src_h == srcH && + prev->src_format == srcFormat && + prev->dst_w == dstW && + prev->dst_h == dstH && + prev->dst_format == dstFormat && + prev->flags == flags && + prev->scaler_params[0] == param[0] && + prev->scaler_params[1] == param[1])) { + return prev; + } + + if (!(sws = sws_alloc_context())) { + sws_free_context(&prev); + return NULL; + } + + if (prev) { + av_opt_copy(sws, prev); + sws_free_context(&prev); + } + + sws->src_w = srcW; + sws->src_h = srcH; + sws->src_format = srcFormat; + sws->dst_w = dstW; + sws->dst_h = dstH; + sws->dst_format = dstFormat; + sws->flags = flags; + sws->scaler_params[0] = param[0]; + sws->scaler_params[1] = param[1]; + + if (sws_init_context(sws, srcFilter, dstFilter) < 0) + sws_free_context(&sws); + + return sws; +} + +int ff_range_add(RangeList *rl, unsigned int start, unsigned int len) +{ + Range *tmp; + unsigned int idx; + + /* find the first existing range after the new one */ + for (idx = 0; idx < rl->nb_ranges; idx++) + if (rl->ranges[idx].start > start) + break; + + /* check for overlap */ + if (idx > 0) { + Range *prev = &rl->ranges[idx - 1]; + if (prev->start + prev->len > start) + return AVERROR(EINVAL); + } + if (idx < rl->nb_ranges) { + Range *next = &rl->ranges[idx]; + if (start + len > next->start) + return AVERROR(EINVAL); + } + + tmp = av_fast_realloc(rl->ranges, &rl->ranges_allocated, + (rl->nb_ranges + 1) * sizeof(*rl->ranges)); + if (!tmp) + return AVERROR(ENOMEM); + rl->ranges = tmp; + + memmove(rl->ranges + idx + 1, rl->ranges + idx, + sizeof(*rl->ranges) * (rl->nb_ranges - idx)); + rl->ranges[idx].start = start; + rl->ranges[idx].len = len; + rl->nb_ranges++; + + /* merge ranges */ + if (idx > 0) { + Range *prev = &rl->ranges[idx - 1]; + Range *cur = &rl->ranges[idx]; + if (prev->start + prev->len == cur->start) { + prev->len += cur->len; + memmove(rl->ranges + idx - 1, rl->ranges + idx, + sizeof(*rl->ranges) * (rl->nb_ranges - idx)); + rl->nb_ranges--; + idx--; + } + } + if (idx < rl->nb_ranges - 1) { + Range *cur = &rl->ranges[idx]; + Range *next = &rl->ranges[idx + 1]; + if (cur->start + cur->len == next->start) { + cur->len += next->len; + memmove(rl->ranges + idx, rl->ranges + idx + 1, + sizeof(*rl->ranges) * (rl->nb_ranges - idx - 1)); + rl->nb_ranges--; + } + } + + return 0; +} diff --git a/libs/ffmpeg/libswscale/version.c b/libs/ffmpeg/libswscale/version.c new file mode 100644 index 00000000000..31135f9cb18 --- /dev/null +++ b/libs/ffmpeg/libswscale/version.c @@ -0,0 +1,42 @@ +/* + * Version functions. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <assert.h> + +#include "config.h" +#include "swscale.h" +#include "version.h" + +unsigned swscale_version(void) +{ + static_assert(LIBSWSCALE_VERSION_MICRO >= 100, "micro version starts at 100"); + return LIBSWSCALE_VERSION_INT; +} + +const char *swscale_configuration(void) +{ + return FFMPEG_CONFIGURATION; +} + +const char *swscale_license(void) +{ +#define LICENSE_PREFIX "libswscale license: " + return &LICENSE_PREFIX FFMPEG_LICENSE[sizeof(LICENSE_PREFIX) - 1]; +} diff --git a/libs/ffmpeg/libswscale/version.h b/libs/ffmpeg/libswscale/version.h new file mode 100644 index 00000000000..0129e168546 --- /dev/null +++ b/libs/ffmpeg/libswscale/version.h @@ -0,0 +1,44 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_VERSION_H +#define SWSCALE_VERSION_H + +/** + * @file + * swscale version macros + */ + +#include "libavutil/version.h" + +#include "version_major.h" + +#define LIBSWSCALE_VERSION_MINOR 5 +#define LIBSWSCALE_VERSION_MICRO 101 + +#define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ + LIBSWSCALE_VERSION_MINOR, \ + LIBSWSCALE_VERSION_MICRO) +#define LIBSWSCALE_VERSION AV_VERSION(LIBSWSCALE_VERSION_MAJOR, \ + LIBSWSCALE_VERSION_MINOR, \ + LIBSWSCALE_VERSION_MICRO) +#define LIBSWSCALE_BUILD LIBSWSCALE_VERSION_INT + +#define LIBSWSCALE_IDENT "SwS" AV_STRINGIFY(LIBSWSCALE_VERSION) + +#endif /* SWSCALE_VERSION_H */ diff --git a/libs/ffmpeg/libswscale/version_major.h b/libs/ffmpeg/libswscale/version_major.h new file mode 100644 index 00000000000..0dc507921ed --- /dev/null +++ b/libs/ffmpeg/libswscale/version_major.h @@ -0,0 +1,35 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SWSCALE_VERSION_MAJOR_H +#define SWSCALE_VERSION_MAJOR_H + +/** + * @file + * swscale version macros + */ + +#define LIBSWSCALE_VERSION_MAJOR 9 + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + */ + +#endif /* SWSCALE_VERSION_MAJOR_H */ diff --git a/libs/ffmpeg/libswscale/vscale.c b/libs/ffmpeg/libswscale/vscale.c new file mode 100644 index 00000000000..e972bd70e28 --- /dev/null +++ b/libs/ffmpeg/libswscale/vscale.c @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2015 Pedro Arthur <bygrandao@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "libavutil/mem.h" +#include "swscale_internal.h" + +typedef struct VScalerContext +{ + uint16_t *filter[2]; + int32_t *filter_pos; + int filter_size; + int isMMX; + union { + yuv2planar1_fn yuv2planar1; + yuv2planarX_fn yuv2planarX; + yuv2interleavedX_fn yuv2interleavedX; + yuv2packed1_fn yuv2packed1; + yuv2packed2_fn yuv2packed2; + yuv2anyX_fn yuv2anyX; + } pfn; + yuv2packedX_fn yuv2packedX; +} VScalerContext; + + +static int lum_planar_vscale(SwsInternal *c, SwsFilterDescriptor *desc, int sliceY, int sliceH) +{ + VScalerContext *inst = desc->instance; + int dstW = desc->dst->width; + + int first = FFMAX(1-inst->filter_size, inst->filter_pos[sliceY]); + int sp = first - desc->src->plane[0].sliceY; + int dp = sliceY - desc->dst->plane[0].sliceY; + uint8_t **src = desc->src->plane[0].line + sp; + uint8_t **dst = desc->dst->plane[0].line + dp; + uint16_t *filter = inst->filter[0] + (inst->isMMX ? 0 : sliceY * inst->filter_size); + + if (inst->filter_size == 1) + inst->pfn.yuv2planar1((const int16_t*)src[0], dst[0], dstW, c->lumDither8, 0); + else + inst->pfn.yuv2planarX(filter, inst->filter_size, (const int16_t**)src, dst[0], dstW, c->lumDither8, 0); + + if (desc->alpha) { + int sp = first - desc->src->plane[3].sliceY; + int dp = sliceY - desc->dst->plane[3].sliceY; + uint8_t **src = desc->src->plane[3].line + sp; + uint8_t **dst = desc->dst->plane[3].line + dp; + uint16_t *filter = inst->filter[1] + (inst->isMMX ? 0 : sliceY * inst->filter_size); + + if (inst->filter_size == 1) + inst->pfn.yuv2planar1((const int16_t*)src[0], dst[0], dstW, c->lumDither8, 0); + else + inst->pfn.yuv2planarX(filter, inst->filter_size, (const int16_t**)src, dst[0], dstW, c->lumDither8, 0); + } + + return 1; +} + +static int chr_planar_vscale(SwsInternal *c, SwsFilterDescriptor *desc, int sliceY, int sliceH) +{ + const int chrSkipMask = (1 << desc->dst->v_chr_sub_sample) - 1; + if (sliceY & chrSkipMask) + return 0; + else { + VScalerContext *inst = desc->instance; + int dstW = AV_CEIL_RSHIFT(desc->dst->width, desc->dst->h_chr_sub_sample); + int chrSliceY = sliceY >> desc->dst->v_chr_sub_sample; + + int first = FFMAX(1-inst->filter_size, inst->filter_pos[chrSliceY]); + int sp1 = first - desc->src->plane[1].sliceY; + int sp2 = first - desc->src->plane[2].sliceY; + int dp1 = chrSliceY - desc->dst->plane[1].sliceY; + int dp2 = chrSliceY - desc->dst->plane[2].sliceY; + uint8_t **src1 = desc->src->plane[1].line + sp1; + uint8_t **src2 = desc->src->plane[2].line + sp2; + uint8_t **dst1 = desc->dst->plane[1].line + dp1; + uint8_t **dst2 = desc->dst->plane[2].line + dp2; + uint16_t *filter = inst->filter[0] + (inst->isMMX ? 0 : chrSliceY * inst->filter_size); + + if (c->yuv2nv12cX) { + inst->pfn.yuv2interleavedX(c->opts.dst_format, c->chrDither8, filter, inst->filter_size, (const int16_t**)src1, (const int16_t**)src2, dst1[0], dstW); + } else if (inst->filter_size == 1) { + inst->pfn.yuv2planar1((const int16_t*)src1[0], dst1[0], dstW, c->chrDither8, 0); + inst->pfn.yuv2planar1((const int16_t*)src2[0], dst2[0], dstW, c->chrDither8, 3); + } else { + inst->pfn.yuv2planarX(filter, inst->filter_size, (const int16_t**)src1, dst1[0], dstW, c->chrDither8, 0); + inst->pfn.yuv2planarX(filter, inst->filter_size, (const int16_t**)src2, dst2[0], dstW, c->chrDither8, inst->isMMX ? (c->uv_offx2 >> 1) : 3); + } + } + + return 1; +} + +static int packed_vscale(SwsInternal *c, SwsFilterDescriptor *desc, int sliceY, int sliceH) +{ + VScalerContext *inst = desc->instance; + int dstW = desc->dst->width; + int chrSliceY = sliceY >> desc->dst->v_chr_sub_sample; + + int lum_fsize = inst[0].filter_size; + int chr_fsize = inst[1].filter_size; + uint16_t *lum_filter = inst[0].filter[0]; + uint16_t *chr_filter = inst[1].filter[0]; + + int firstLum = FFMAX(1-lum_fsize, inst[0].filter_pos[ sliceY]); + int firstChr = FFMAX(1-chr_fsize, inst[1].filter_pos[chrSliceY]); + + int sp0 = firstLum - desc->src->plane[0].sliceY; + int sp1 = firstChr - desc->src->plane[1].sliceY; + int sp2 = firstChr - desc->src->plane[2].sliceY; + int sp3 = firstLum - desc->src->plane[3].sliceY; + int dp = sliceY - desc->dst->plane[0].sliceY; + uint8_t **src0 = desc->src->plane[0].line + sp0; + uint8_t **src1 = desc->src->plane[1].line + sp1; + uint8_t **src2 = desc->src->plane[2].line + sp2; + uint8_t **src3 = desc->alpha ? desc->src->plane[3].line + sp3 : NULL; + uint8_t **dst = desc->dst->plane[0].line + dp; + + + if (c->yuv2packed1 && lum_fsize == 1 && chr_fsize == 1) { // unscaled RGB + inst->pfn.yuv2packed1(c, (const int16_t*)*src0, (const int16_t**)src1, (const int16_t**)src2, + (const int16_t*)(desc->alpha ? *src3 : NULL), *dst, dstW, 0, sliceY); + } else if (c->yuv2packed1 && lum_fsize == 1 && chr_fsize == 2 && + chr_filter[2 * chrSliceY + 1] + chr_filter[2 * chrSliceY] == 4096 && + chr_filter[2 * chrSliceY + 1] <= 4096U) { // unscaled RGB + int chrAlpha = chr_filter[2 * chrSliceY + 1]; + inst->pfn.yuv2packed1(c, (const int16_t*)*src0, (const int16_t**)src1, (const int16_t**)src2, + (const int16_t*)(desc->alpha ? *src3 : NULL), *dst, dstW, chrAlpha, sliceY); + } else if (c->yuv2packed2 && lum_fsize == 2 && chr_fsize == 2 && + lum_filter[2 * sliceY + 1] + lum_filter[2 * sliceY] == 4096 && + lum_filter[2 * sliceY + 1] <= 4096U && + chr_filter[2 * chrSliceY + 1] + chr_filter[2 * chrSliceY] == 4096 && + chr_filter[2 * chrSliceY + 1] <= 4096U + ) { // bilinear upscale RGB + int lumAlpha = lum_filter[2 * sliceY + 1]; + int chrAlpha = chr_filter[2 * chrSliceY + 1]; + c->lumMmxFilter[2] = + c->lumMmxFilter[3] = lum_filter[2 * sliceY] * 0x10001; + c->chrMmxFilter[2] = + c->chrMmxFilter[3] = chr_filter[2 * chrSliceY] * 0x10001; + inst->pfn.yuv2packed2(c, (const int16_t**)src0, (const int16_t**)src1, (const int16_t**)src2, (const int16_t**)src3, + *dst, dstW, lumAlpha, chrAlpha, sliceY); + } else { // general RGB + if ((c->yuv2packed1 && lum_fsize == 1 && chr_fsize == 2) || + (c->yuv2packed2 && lum_fsize == 2 && chr_fsize == 2)) { + if (!c->warned_unuseable_bilinear) + av_log(c, AV_LOG_INFO, "Optimized 2 tap filter code cannot be used\n"); + c->warned_unuseable_bilinear = 1; + } + + inst->yuv2packedX(c, lum_filter + sliceY * lum_fsize, + (const int16_t**)src0, lum_fsize, chr_filter + chrSliceY * chr_fsize, + (const int16_t**)src1, (const int16_t**)src2, chr_fsize, (const int16_t**)src3, *dst, dstW, sliceY); + } + return 1; +} + +static int any_vscale(SwsInternal *c, SwsFilterDescriptor *desc, int sliceY, int sliceH) +{ + VScalerContext *inst = desc->instance; + int dstW = desc->dst->width; + int chrSliceY = sliceY >> desc->dst->v_chr_sub_sample; + + int lum_fsize = inst[0].filter_size; + int chr_fsize = inst[1].filter_size; + uint16_t *lum_filter = inst[0].filter[0]; + uint16_t *chr_filter = inst[1].filter[0]; + + int firstLum = FFMAX(1-lum_fsize, inst[0].filter_pos[ sliceY]); + int firstChr = FFMAX(1-chr_fsize, inst[1].filter_pos[chrSliceY]); + + int sp0 = firstLum - desc->src->plane[0].sliceY; + int sp1 = firstChr - desc->src->plane[1].sliceY; + int sp2 = firstChr - desc->src->plane[2].sliceY; + int sp3 = firstLum - desc->src->plane[3].sliceY; + int dp0 = sliceY - desc->dst->plane[0].sliceY; + int dp1 = chrSliceY - desc->dst->plane[1].sliceY; + int dp2 = chrSliceY - desc->dst->plane[2].sliceY; + int dp3 = sliceY - desc->dst->plane[3].sliceY; + + uint8_t **src0 = desc->src->plane[0].line + sp0; + uint8_t **src1 = desc->src->plane[1].line + sp1; + uint8_t **src2 = desc->src->plane[2].line + sp2; + uint8_t **src3 = desc->alpha ? desc->src->plane[3].line + sp3 : NULL; + uint8_t *dst[4] = { desc->dst->plane[0].line[dp0], + desc->dst->plane[1].line[dp1], + desc->dst->plane[2].line[dp2], + desc->alpha ? desc->dst->plane[3].line[dp3] : NULL }; + + av_assert1(!c->yuv2packed1 && !c->yuv2packed2); + inst->pfn.yuv2anyX(c, lum_filter + sliceY * lum_fsize, + (const int16_t**)src0, lum_fsize, chr_filter + sliceY * chr_fsize, + (const int16_t**)src1, (const int16_t**)src2, chr_fsize, (const int16_t**)src3, dst, dstW, sliceY); + + return 1; + +} + +int ff_init_vscale(SwsInternal *c, SwsFilterDescriptor *desc, SwsSlice *src, SwsSlice *dst) +{ + VScalerContext *lumCtx = NULL; + VScalerContext *chrCtx = NULL; + + if (isPlanarYUV(c->opts.dst_format) || (isGray(c->opts.dst_format) && !isALPHA(c->opts.dst_format))) { + lumCtx = av_mallocz(sizeof(VScalerContext)); + if (!lumCtx) + return AVERROR(ENOMEM); + + + desc[0].process = lum_planar_vscale; + desc[0].instance = lumCtx; + desc[0].src = src; + desc[0].dst = dst; + desc[0].alpha = c->needAlpha; + + if (!isGray(c->opts.dst_format)) { + chrCtx = av_mallocz(sizeof(VScalerContext)); + if (!chrCtx) + return AVERROR(ENOMEM); + desc[1].process = chr_planar_vscale; + desc[1].instance = chrCtx; + desc[1].src = src; + desc[1].dst = dst; + } + } else { + lumCtx = av_calloc(2, sizeof(*lumCtx)); + if (!lumCtx) + return AVERROR(ENOMEM); + chrCtx = &lumCtx[1]; + + desc[0].process = c->yuv2packedX ? packed_vscale : any_vscale; + desc[0].instance = lumCtx; + desc[0].src = src; + desc[0].dst = dst; + desc[0].alpha = c->needAlpha; + } + + ff_init_vscale_pfn(c, c->yuv2plane1, c->yuv2planeX, c->yuv2nv12cX, + c->yuv2packed1, c->yuv2packed2, c->yuv2packedX, c->yuv2anyX, c->use_mmx_vfilter); + return 0; +} + +void ff_init_vscale_pfn(SwsInternal *c, + yuv2planar1_fn yuv2plane1, + yuv2planarX_fn yuv2planeX, + yuv2interleavedX_fn yuv2nv12cX, + yuv2packed1_fn yuv2packed1, + yuv2packed2_fn yuv2packed2, + yuv2packedX_fn yuv2packedX, + yuv2anyX_fn yuv2anyX, int use_mmx) +{ + VScalerContext *lumCtx = NULL; + VScalerContext *chrCtx = NULL; + int idx = c->numDesc - (c->is_internal_gamma ? 2 : 1); //FIXME avoid hardcoding indexes + + if (isPlanarYUV(c->opts.dst_format) || (isGray(c->opts.dst_format) && !isALPHA(c->opts.dst_format))) { + if (!isGray(c->opts.dst_format)) { + chrCtx = c->desc[idx].instance; + + chrCtx->filter[0] = use_mmx ? (int16_t*)c->chrMmxFilter : c->vChrFilter; + chrCtx->filter_size = c->vChrFilterSize; + chrCtx->filter_pos = c->vChrFilterPos; + chrCtx->isMMX = use_mmx; + + --idx; + if (yuv2nv12cX) chrCtx->pfn.yuv2interleavedX = yuv2nv12cX; + else if (c->vChrFilterSize == 1) chrCtx->pfn.yuv2planar1 = yuv2plane1; + else chrCtx->pfn.yuv2planarX = yuv2planeX; + } + + lumCtx = c->desc[idx].instance; + + lumCtx->filter[0] = use_mmx ? (int16_t*)c->lumMmxFilter : c->vLumFilter; + lumCtx->filter[1] = use_mmx ? (int16_t*)c->alpMmxFilter : c->vLumFilter; + lumCtx->filter_size = c->vLumFilterSize; + lumCtx->filter_pos = c->vLumFilterPos; + lumCtx->isMMX = use_mmx; + + if (c->vLumFilterSize == 1) lumCtx->pfn.yuv2planar1 = yuv2plane1; + else lumCtx->pfn.yuv2planarX = yuv2planeX; + + } else { + lumCtx = c->desc[idx].instance; + chrCtx = &lumCtx[1]; + + lumCtx->filter[0] = c->vLumFilter; + lumCtx->filter_size = c->vLumFilterSize; + lumCtx->filter_pos = c->vLumFilterPos; + + chrCtx->filter[0] = c->vChrFilter; + chrCtx->filter_size = c->vChrFilterSize; + chrCtx->filter_pos = c->vChrFilterPos; + + lumCtx->isMMX = use_mmx; + chrCtx->isMMX = use_mmx; + + if (yuv2packedX) { + if (c->yuv2packed1 && c->vLumFilterSize == 1 && c->vChrFilterSize <= 2) + lumCtx->pfn.yuv2packed1 = yuv2packed1; + else if (c->yuv2packed2 && c->vLumFilterSize == 2 && c->vChrFilterSize == 2) + lumCtx->pfn.yuv2packed2 = yuv2packed2; + lumCtx->yuv2packedX = yuv2packedX; + } else + lumCtx->pfn.yuv2anyX = yuv2anyX; + } +} diff --git a/libs/ffmpeg/libswscale/yuv2rgb.c b/libs/ffmpeg/libswscale/yuv2rgb.c new file mode 100644 index 00000000000..c62201856d1 --- /dev/null +++ b/libs/ffmpeg/libswscale/yuv2rgb.c @@ -0,0 +1,963 @@ +/* + * software YUV to RGB converter + * + * Copyright (C) 2009 Konstantin Shishkov + * + * 1,4,8bpp support and context / deglobalize stuff + * by Michael Niedermayer (michaelni@gmx.at) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stddef.h> +#include <stdint.h> + +#include "libavutil/bswap.h" +#include "libavutil/mem.h" +#include "config.h" +#include "swscale.h" +#include "swscale_internal.h" +#include "libavutil/pixdesc.h" + +/* Color space conversion coefficients for YCbCr -> RGB mapping. + * + * Entries are {crv, cbu, cgu, cgv} + * + * crv = (255 / 224) * 65536 * (1 - cr) / 0.5 + * cbu = (255 / 224) * 65536 * (1 - cb) / 0.5 + * cgu = (255 / 224) * 65536 * (cb / cg) * (1 - cb) / 0.5 + * cgv = (255 / 224) * 65536 * (cr / cg) * (1 - cr) / 0.5 + * + * where Y = cr * R + cg * G + cb * B and cr + cg + cb = 1. + */ +const int32_t ff_yuv2rgb_coeffs[11][4] = { + { 104597, 132201, 25675, 53279 }, /* no sequence_display_extension */ + { 117489, 138438, 13975, 34925 }, /* ITU-R Rec. 709 (1990) */ + { 104597, 132201, 25675, 53279 }, /* unspecified */ + { 104597, 132201, 25675, 53279 }, /* reserved */ + { 104448, 132798, 24759, 53109 }, /* FCC */ + { 104597, 132201, 25675, 53279 }, /* ITU-R Rec. 624-4 System B, G */ + { 104597, 132201, 25675, 53279 }, /* SMPTE 170M */ + { 117579, 136230, 16907, 35559 }, /* SMPTE 240M (1987) */ + { 0 }, /* YCgCo */ + { 110013, 140363, 12277, 42626 }, /* Bt-2020-NCL */ + { 110013, 140363, 12277, 42626 }, /* Bt-2020-CL */ +}; + +const int *sws_getCoefficients(int colorspace) +{ + if (colorspace > 10 || colorspace < 0 || colorspace == 8) + colorspace = SWS_CS_DEFAULT; + return ff_yuv2rgb_coeffs[colorspace]; +} + +#define LOADCHROMA(l, i) \ + U = pu_##l[i]; \ + V = pv_##l[i]; \ + r = (void *)c->table_rV[V+YUVRGB_TABLE_HEADROOM]; \ + g = (void *)(c->table_gU[U+YUVRGB_TABLE_HEADROOM] + c->table_gV[V+YUVRGB_TABLE_HEADROOM]); \ + b = (void *)c->table_bU[U+YUVRGB_TABLE_HEADROOM]; + +#define PUTRGB(l, i, abase) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y] + g[Y] + b[Y]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y] + g[Y] + b[Y]; + +#define PUTRGB24(l, i, abase) \ + Y = py_##l[2 * i]; \ + dst_##l[6 * i + 0] = r[Y]; \ + dst_##l[6 * i + 1] = g[Y]; \ + dst_##l[6 * i + 2] = b[Y]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[6 * i + 3] = r[Y]; \ + dst_##l[6 * i + 4] = g[Y]; \ + dst_##l[6 * i + 5] = b[Y]; + +#define PUTBGR24(l, i, abase) \ + Y = py_##l[2 * i]; \ + dst_##l[6 * i + 0] = b[Y]; \ + dst_##l[6 * i + 1] = g[Y]; \ + dst_##l[6 * i + 2] = r[Y]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[6 * i + 3] = b[Y]; \ + dst_##l[6 * i + 4] = g[Y]; \ + dst_##l[6 * i + 5] = r[Y]; + +#define PUTRGBA(l, i, abase) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y] + g[Y] + b[Y] + ((uint32_t)(pa_##l[2 * i]) << abase); \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y] + g[Y] + b[Y] + ((uint32_t)(pa_##l[2 * i + 1]) << abase); + +#define PUTRGB48(l, i, abase) \ + Y = py_##l[ 2 * i]; \ + dst_##l[12 * i + 0] = dst_##l[12 * i + 1] = r[Y]; \ + dst_##l[12 * i + 2] = dst_##l[12 * i + 3] = g[Y]; \ + dst_##l[12 * i + 4] = dst_##l[12 * i + 5] = b[Y]; \ + Y = py_##l[ 2 * i + 1]; \ + dst_##l[12 * i + 6] = dst_##l[12 * i + 7] = r[Y]; \ + dst_##l[12 * i + 8] = dst_##l[12 * i + 9] = g[Y]; \ + dst_##l[12 * i + 10] = dst_##l[12 * i + 11] = b[Y]; + +#define PUTBGR48(l, i, abase) \ + Y = py_##l[2 * i]; \ + dst_##l[12 * i + 0] = dst_##l[12 * i + 1] = b[Y]; \ + dst_##l[12 * i + 2] = dst_##l[12 * i + 3] = g[Y]; \ + dst_##l[12 * i + 4] = dst_##l[12 * i + 5] = r[Y]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[12 * i + 6] = dst_##l[12 * i + 7] = b[Y]; \ + dst_##l[12 * i + 8] = dst_##l[12 * i + 9] = g[Y]; \ + dst_##l[12 * i + 10] = dst_##l[12 * i + 11] = r[Y]; + +#define PUTGBRP(l, i, abase) \ + Y = py_##l[2 * i]; \ + dst_##l [2 * i + 0] = g[Y]; \ + dst1_##l[2 * i + 0] = b[Y]; \ + dst2_##l[2 * i + 0] = r[Y]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l [2 * i + 1] = g[Y]; \ + dst1_##l[2 * i + 1] = b[Y]; \ + dst2_##l[2 * i + 1] = r[Y]; + +#define YUV2RGBFUNC(func_name, dst_type, alpha, yuv422, nb_dst_planes) \ + static int func_name(SwsInternal *c, const uint8_t *const src[], \ + const int srcStride[], int srcSliceY, int srcSliceH, \ + uint8_t *const dst[], const int dstStride[]) \ + { \ + int y; \ + \ + for (y = 0; y < srcSliceH; y += 2) { \ + int yd = y + srcSliceY; \ + dst_type *dst_1 = \ + (dst_type *)(dst[0] + (yd) * dstStride[0]); \ + dst_type *dst_2 = \ + (dst_type *)(dst[0] + (yd + 1) * dstStride[0]); \ + av_unused dst_type *dst1_1, *dst1_2, *dst2_1, *dst2_2; \ + av_unused dst_type *r, *g, *b; \ + const uint8_t *py_1 = src[0] + y * srcStride[0]; \ + const uint8_t *py_2 = py_1 + srcStride[0]; \ + av_unused const uint8_t *pu_1 = src[1] + (y >> !yuv422) * srcStride[1]; \ + av_unused const uint8_t *pv_1 = src[2] + (y >> !yuv422) * srcStride[2]; \ + av_unused const uint8_t *pu_2, *pv_2; \ + av_unused const uint8_t *pa_1, *pa_2; \ + unsigned int h_size = c->opts.dst_w >> 3; \ + if (nb_dst_planes > 1) { \ + dst1_1 = (dst_type *)(dst[1] + (yd) * dstStride[1]); \ + dst1_2 = (dst_type *)(dst[1] + (yd + 1) * dstStride[1]); \ + dst2_1 = (dst_type *)(dst[2] + (yd) * dstStride[2]); \ + dst2_2 = (dst_type *)(dst[2] + (yd + 1) * dstStride[2]); \ + } \ + if (yuv422) { \ + pu_2 = pu_1 + srcStride[1]; \ + pv_2 = pv_1 + srcStride[2]; \ + } \ + if (alpha) { \ + pa_1 = src[3] + y * srcStride[3]; \ + pa_2 = pa_1 + srcStride[3]; \ + } \ + while (h_size--) { \ + av_unused int U, V, Y; \ + +#define ENDYUV2RGBLINE(dst_delta, ss, alpha, yuv422, nb_dst_planes) \ + pu_1 += 4 >> ss; \ + pv_1 += 4 >> ss; \ + if (yuv422) { \ + pu_2 += 4 >> ss; \ + pv_2 += 4 >> ss; \ + } \ + py_1 += 8 >> ss; \ + py_2 += 8 >> ss; \ + if (alpha) { \ + pa_1 += 8 >> ss; \ + pa_2 += 8 >> ss; \ + } \ + dst_1 += dst_delta >> ss; \ + dst_2 += dst_delta >> ss; \ + if (nb_dst_planes > 1) { \ + dst1_1 += dst_delta >> ss; \ + dst1_2 += dst_delta >> ss; \ + dst2_1 += dst_delta >> ss; \ + dst2_2 += dst_delta >> ss; \ + } \ + } \ + if (c->opts.dst_w & (4 >> ss)) { \ + av_unused int Y, U, V; \ + +#define ENDYUV2RGBFUNC() \ + } \ + } \ + return srcSliceH; \ + } + +#define YUV420FUNC(func_name, dst_type, alpha, abase, PUTFUNC, dst_delta, nb_dst_planes) \ + YUV2RGBFUNC(func_name, dst_type, alpha, 0, nb_dst_planes) \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, abase); \ + PUTFUNC(2, 0, abase); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(2, 1, abase); \ + PUTFUNC(1, 1, abase); \ + \ + LOADCHROMA(1, 2); \ + PUTFUNC(1, 2, abase); \ + PUTFUNC(2, 2, abase); \ + \ + LOADCHROMA(1, 3); \ + PUTFUNC(2, 3, abase); \ + PUTFUNC(1, 3, abase); \ + ENDYUV2RGBLINE(dst_delta, 0, alpha, 0, nb_dst_planes) \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, abase); \ + PUTFUNC(2, 0, abase); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(2, 1, abase); \ + PUTFUNC(1, 1, abase); \ + ENDYUV2RGBLINE(dst_delta, 1, alpha, 0, nb_dst_planes) \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, abase); \ + PUTFUNC(2, 0, abase); \ + ENDYUV2RGBFUNC() + +#define YUV422FUNC(func_name, dst_type, alpha, abase, PUTFUNC, dst_delta, nb_dst_planes) \ + YUV2RGBFUNC(func_name, dst_type, alpha, 1, nb_dst_planes) \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, abase); \ + \ + LOADCHROMA(2, 0); \ + PUTFUNC(2, 0, abase); \ + \ + LOADCHROMA(2, 1); \ + PUTFUNC(2, 1, abase); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(1, 1, abase); \ + \ + LOADCHROMA(1, 2); \ + PUTFUNC(1, 2, abase); \ + \ + LOADCHROMA(2, 2); \ + PUTFUNC(2, 2, abase); \ + \ + LOADCHROMA(2, 3); \ + PUTFUNC(2, 3, abase); \ + \ + LOADCHROMA(1, 3); \ + PUTFUNC(1, 3, abase); \ + ENDYUV2RGBLINE(dst_delta, 0, alpha, 1, nb_dst_planes) \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, abase); \ + \ + LOADCHROMA(2, 0); \ + PUTFUNC(2, 0, abase); \ + \ + LOADCHROMA(2, 1); \ + PUTFUNC(2, 1, abase); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(1, 1, abase); \ + ENDYUV2RGBLINE(dst_delta, 1, alpha, 1, nb_dst_planes) \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, abase); \ + \ + LOADCHROMA(2, 0); \ + PUTFUNC(2, 0, abase); \ + ENDYUV2RGBFUNC() + +#define YUV420FUNC_DITHER(func_name, dst_type, LOADDITHER, PUTFUNC, dst_delta) \ + YUV2RGBFUNC(func_name, dst_type, 0, 0, 1) \ + LOADDITHER \ + \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, 0); \ + PUTFUNC(2, 0, 0 + 8); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(2, 1, 2 + 8); \ + PUTFUNC(1, 1, 2); \ + \ + LOADCHROMA(1, 2); \ + PUTFUNC(1, 2, 4); \ + PUTFUNC(2, 2, 4 + 8); \ + \ + LOADCHROMA(1, 3); \ + PUTFUNC(2, 3, 6 + 8); \ + PUTFUNC(1, 3, 6); \ + ENDYUV2RGBLINE(dst_delta, 0, 0, 0, 1) \ + LOADDITHER \ + \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, 0); \ + PUTFUNC(2, 0, 0 + 8); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(2, 1, 2 + 8); \ + PUTFUNC(1, 1, 2); \ + ENDYUV2RGBLINE(dst_delta, 1, 0, 0, 1) \ + LOADDITHER \ + \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, 0); \ + PUTFUNC(2, 0, 0 + 8); \ + ENDYUV2RGBFUNC() + +#define YUV422FUNC_DITHER(func_name, dst_type, LOADDITHER, PUTFUNC, dst_delta) \ + YUV2RGBFUNC(func_name, dst_type, 0, 1, 1) \ + LOADDITHER \ + \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, 0); \ + \ + LOADCHROMA(2, 0); \ + PUTFUNC(2, 0, 0 + 8); \ + \ + LOADCHROMA(2, 1); \ + PUTFUNC(2, 1, 2 + 8); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(1, 1, 2); \ + \ + LOADCHROMA(1, 2); \ + PUTFUNC(1, 2, 4); \ + \ + LOADCHROMA(2, 2); \ + PUTFUNC(2, 2, 4 + 8); \ + \ + LOADCHROMA(2, 3); \ + PUTFUNC(2, 3, 6 + 8); \ + \ + LOADCHROMA(1, 3); \ + PUTFUNC(1, 3, 6); \ + ENDYUV2RGBLINE(dst_delta, 0, 0, 1, 1) \ + LOADDITHER \ + \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, 0); \ + \ + LOADCHROMA(2, 0); \ + PUTFUNC(2, 0, 0 + 8); \ + \ + LOADCHROMA(2, 1); \ + PUTFUNC(2, 1, 2 + 8); \ + \ + LOADCHROMA(1, 1); \ + PUTFUNC(1, 1, 2); \ + ENDYUV2RGBLINE(dst_delta, 1, 0, 1, 1) \ + LOADDITHER \ + \ + LOADCHROMA(1, 0); \ + PUTFUNC(1, 0, 0); \ + \ + LOADCHROMA(2, 0); \ + PUTFUNC(2, 0, 0 + 8); \ + ENDYUV2RGBFUNC() + +#define LOADDITHER16 \ + const uint8_t *d16 = ff_dither_2x2_8[y & 1]; \ + const uint8_t *e16 = ff_dither_2x2_4[y & 1]; \ + const uint8_t *f16 = ff_dither_2x2_8[(y & 1)^1]; + +#define PUTRGB16(l, i, o) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y + d16[0 + o]] + \ + g[Y + e16[0 + o]] + \ + b[Y + f16[0 + o]]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y + d16[1 + o]] + \ + g[Y + e16[1 + o]] + \ + b[Y + f16[1 + o]]; + +#define LOADDITHER15 \ + const uint8_t *d16 = ff_dither_2x2_8[y & 1]; \ + const uint8_t *e16 = ff_dither_2x2_8[(y & 1)^1]; + +#define PUTRGB15(l, i, o) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y + d16[0 + o]] + \ + g[Y + d16[1 + o]] + \ + b[Y + e16[0 + o]]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y + d16[1 + o]] + \ + g[Y + d16[0 + o]] + \ + b[Y + e16[1 + o]]; + +#define LOADDITHER12 \ + const uint8_t *d16 = ff_dither_4x4_16[y & 3]; + +#define PUTRGB12(l, i, o) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y + d16[0 + o]] + \ + g[Y + d16[0 + o]] + \ + b[Y + d16[0 + o]]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y + d16[1 + o]] + \ + g[Y + d16[1 + o]] + \ + b[Y + d16[1 + o]]; + +#define LOADDITHER8 \ + const uint8_t *d32 = ff_dither_8x8_32[yd & 7]; \ + const uint8_t *d64 = ff_dither_8x8_73[yd & 7]; + +#define PUTRGB8(l, i, o) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y + d32[0 + o]] + \ + g[Y + d32[0 + o]] + \ + b[Y + d64[0 + o]]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y + d32[1 + o]] + \ + g[Y + d32[1 + o]] + \ + b[Y + d64[1 + o]]; + +#define LOADDITHER4D \ + const uint8_t * d64 = ff_dither_8x8_73[yd & 7]; \ + const uint8_t *d128 = ff_dither_8x8_220[yd & 7]; \ + int acc; + +#define PUTRGB4D(l, i, o) \ + Y = py_##l[2 * i]; \ + acc = r[Y + d128[0 + o]] + \ + g[Y + d64[0 + o]] + \ + b[Y + d128[0 + o]]; \ + Y = py_##l[2 * i + 1]; \ + acc |= (r[Y + d128[1 + o]] + \ + g[Y + d64[1 + o]] + \ + b[Y + d128[1 + o]]) << 4; \ + dst_##l[i] = acc; + +#define LOADDITHER4DB \ + const uint8_t *d64 = ff_dither_8x8_73[yd & 7]; \ + const uint8_t *d128 = ff_dither_8x8_220[yd & 7]; + +#define PUTRGB4DB(l, i, o) \ + Y = py_##l[2 * i]; \ + dst_##l[2 * i] = r[Y + d128[0 + o]] + \ + g[Y + d64[0 + o]] + \ + b[Y + d128[0 + o]]; \ + Y = py_##l[2 * i + 1]; \ + dst_##l[2 * i + 1] = r[Y + d128[1 + o]] + \ + g[Y + d64[1 + o]] + \ + b[Y + d128[1 + o]]; + +YUV2RGBFUNC(yuv2rgb_c_1_ordered_dither, uint8_t, 0, 0, 1) + const uint8_t *d128 = ff_dither_8x8_220[yd & 7]; + char out_1 = 0, out_2 = 0; + g = c->table_gU[128 + YUVRGB_TABLE_HEADROOM] + c->table_gV[128 + YUVRGB_TABLE_HEADROOM]; + +#define PUTRGB1(out, src, i, o) \ + Y = src[2 * i]; \ + out += out + g[Y + d128[0 + o]]; \ + Y = src[2 * i + 1]; \ + out += out + g[Y + d128[1 + o]]; + + PUTRGB1(out_1, py_1, 0, 0); + PUTRGB1(out_2, py_2, 0, 0 + 8); + + PUTRGB1(out_2, py_2, 1, 2 + 8); + PUTRGB1(out_1, py_1, 1, 2); + + PUTRGB1(out_1, py_1, 2, 4); + PUTRGB1(out_2, py_2, 2, 4 + 8); + + PUTRGB1(out_2, py_2, 3, 6 + 8); + PUTRGB1(out_1, py_1, 3, 6); + + dst_1[0] = out_1; + dst_2[0] = out_2; + + py_1 += 8; + py_2 += 8; + dst_1 += 1; + dst_2 += 1; + } + if (c->opts.dst_w & 7) { + av_unused int Y, U, V; + int pixels_left = c->opts.dst_w & 7; + const uint8_t *d128 = ff_dither_8x8_220[yd & 7]; + char out_1 = 0, out_2 = 0; + g = c->table_gU[128 + YUVRGB_TABLE_HEADROOM] + c->table_gV[128 + YUVRGB_TABLE_HEADROOM]; + +#define PUTRGB1_OR00(out, src, i, o) \ + if (pixels_left) { \ + PUTRGB1(out, src, i, o) \ + pixels_left--; \ + } else { \ + out <<= 2; \ + } + + PUTRGB1_OR00(out_1, py_1, 0, 0); + PUTRGB1_OR00(out_2, py_2, 0, 0 + 8); + + PUTRGB1_OR00(out_2, py_2, 1, 2 + 8); + PUTRGB1_OR00(out_1, py_1, 1, 2); + + PUTRGB1_OR00(out_1, py_1, 2, 4); + PUTRGB1_OR00(out_2, py_2, 2, 4 + 8); + + PUTRGB1_OR00(out_2, py_2, 3, 6 + 8); + PUTRGB1_OR00(out_1, py_1, 3, 6); + + dst_1[0] = out_1; + dst_2[0] = out_2; +ENDYUV2RGBFUNC() + +// YUV420 +YUV420FUNC(yuv2rgb_c_48, uint8_t, 0, 0, PUTRGB48, 48, 1) +YUV420FUNC(yuv2rgb_c_bgr48, uint8_t, 0, 0, PUTBGR48, 48, 1) +YUV420FUNC(yuv2rgb_c_32, uint32_t, 0, 0, PUTRGB, 8, 1) +#if HAVE_BIGENDIAN +YUV420FUNC(yuva2argb_c, uint32_t, 1, 24, PUTRGBA, 8, 1) +YUV420FUNC(yuva2rgba_c, uint32_t, 1, 0, PUTRGBA, 8, 1) +#else +YUV420FUNC(yuva2rgba_c, uint32_t, 1, 24, PUTRGBA, 8, 1) +YUV420FUNC(yuva2argb_c, uint32_t, 1, 0, PUTRGBA, 8, 1) +#endif +YUV420FUNC(yuv2rgb_c_24_rgb, uint8_t, 0, 0, PUTRGB24, 24, 1) +YUV420FUNC(yuv2rgb_c_24_bgr, uint8_t, 0, 0, PUTBGR24, 24, 1) +YUV420FUNC(yuv420p_gbrp_c, uint8_t, 0, 0, PUTGBRP, 8, 3) +YUV420FUNC_DITHER(yuv2rgb_c_16_ordered_dither, uint16_t, LOADDITHER16, PUTRGB16, 8) +YUV420FUNC_DITHER(yuv2rgb_c_15_ordered_dither, uint16_t, LOADDITHER15, PUTRGB15, 8) +YUV420FUNC_DITHER(yuv2rgb_c_12_ordered_dither, uint16_t, LOADDITHER12, PUTRGB12, 8) +YUV420FUNC_DITHER(yuv2rgb_c_8_ordered_dither, uint8_t, LOADDITHER8, PUTRGB8, 8) +YUV420FUNC_DITHER(yuv2rgb_c_4_ordered_dither, uint8_t, LOADDITHER4D, PUTRGB4D, 4) +YUV420FUNC_DITHER(yuv2rgb_c_4b_ordered_dither, uint8_t, LOADDITHER4DB, PUTRGB4DB, 8) + +// YUV422 +YUV422FUNC(yuv422p_rgb48_c, uint8_t, 0, 0, PUTRGB48, 48, 1) +YUV422FUNC(yuv422p_bgr48_c, uint8_t, 0, 0, PUTBGR48, 48, 1) +YUV422FUNC(yuv422p_rgb32_c, uint32_t, 0, 0, PUTRGB, 8, 1) +#if HAVE_BIGENDIAN +YUV422FUNC(yuva422p_argb_c, uint32_t, 1, 24, PUTRGBA, 8, 1) +YUV422FUNC(yuva422p_rgba_c, uint32_t, 1, 0, PUTRGBA, 8, 1) +#else +YUV422FUNC(yuva422p_rgba_c, uint32_t, 1, 24, PUTRGBA, 8, 1) +YUV422FUNC(yuva422p_argb_c, uint32_t, 1, 0, PUTRGBA, 8, 1) +#endif +YUV422FUNC(yuv422p_rgb24_c, uint8_t, 0, 0, PUTRGB24, 24, 1) +YUV422FUNC(yuv422p_bgr24_c, uint8_t, 0, 0, PUTBGR24, 24, 1) +YUV422FUNC(yuv422p_gbrp_c, uint8_t, 0, 0, PUTGBRP, 8, 3) +YUV422FUNC_DITHER(yuv422p_bgr16, uint16_t, LOADDITHER16, PUTRGB16, 8) +YUV422FUNC_DITHER(yuv422p_bgr15, uint16_t, LOADDITHER15, PUTRGB15, 8) +YUV422FUNC_DITHER(yuv422p_bgr12, uint16_t, LOADDITHER12, PUTRGB12, 8) +YUV422FUNC_DITHER(yuv422p_bgr8, uint8_t, LOADDITHER8, PUTRGB8, 8) +YUV422FUNC_DITHER(yuv422p_bgr4, uint8_t, LOADDITHER4D, PUTRGB4D, 4) +YUV422FUNC_DITHER(yuv422p_bgr4_byte, uint8_t, LOADDITHER4DB, PUTRGB4DB, 8) + +SwsFunc ff_yuv2rgb_get_func_ptr(SwsInternal *c) +{ + SwsFunc t = NULL; + +#if ARCH_PPC + t = ff_yuv2rgb_init_ppc(c); +#elif ARCH_X86 + t = ff_yuv2rgb_init_x86(c); +#elif ARCH_LOONGARCH64 + t = ff_yuv2rgb_init_loongarch(c); +#elif ARCH_AARCH64 + t = ff_yuv2rgb_init_aarch64(c); +#endif + + if (t) + return t; + + av_log(c, AV_LOG_WARNING, + "No accelerated colorspace conversion found from %s to %s.\n", + av_get_pix_fmt_name(c->opts.src_format), av_get_pix_fmt_name(c->opts.dst_format)); + + if (c->opts.src_format == AV_PIX_FMT_YUV422P) { + switch (c->opts.dst_format) { + case AV_PIX_FMT_BGR48BE: + case AV_PIX_FMT_BGR48LE: + return yuv422p_bgr48_c; + case AV_PIX_FMT_RGB48BE: + case AV_PIX_FMT_RGB48LE: + return yuv422p_rgb48_c; + case AV_PIX_FMT_ARGB: + case AV_PIX_FMT_ABGR: + if (CONFIG_SWSCALE_ALPHA && isALPHA(c->opts.src_format)) + return yuva422p_argb_c; + case AV_PIX_FMT_RGBA: + case AV_PIX_FMT_BGRA: + return (CONFIG_SWSCALE_ALPHA && isALPHA(c->opts.src_format)) ? yuva422p_rgba_c : yuv422p_rgb32_c; + case AV_PIX_FMT_RGB24: + return yuv422p_rgb24_c; + case AV_PIX_FMT_BGR24: + return yuv422p_bgr24_c; + case AV_PIX_FMT_RGB565: + case AV_PIX_FMT_BGR565: + return yuv422p_bgr16; + case AV_PIX_FMT_RGB555: + case AV_PIX_FMT_BGR555: + return yuv422p_bgr15; + case AV_PIX_FMT_RGB444: + case AV_PIX_FMT_BGR444: + return yuv422p_bgr12; + case AV_PIX_FMT_RGB8: + case AV_PIX_FMT_BGR8: + return yuv422p_bgr8; + case AV_PIX_FMT_RGB4: + case AV_PIX_FMT_BGR4: + return yuv422p_bgr4; + case AV_PIX_FMT_RGB4_BYTE: + case AV_PIX_FMT_BGR4_BYTE: + return yuv422p_bgr4_byte; + case AV_PIX_FMT_MONOBLACK: + return yuv2rgb_c_1_ordered_dither; + case AV_PIX_FMT_GBRP: + return yuv422p_gbrp_c; + } + } else { + switch (c->opts.dst_format) { + case AV_PIX_FMT_BGR48BE: + case AV_PIX_FMT_BGR48LE: + return yuv2rgb_c_bgr48; + case AV_PIX_FMT_RGB48BE: + case AV_PIX_FMT_RGB48LE: + return yuv2rgb_c_48; + case AV_PIX_FMT_ARGB: + case AV_PIX_FMT_ABGR: + if (CONFIG_SWSCALE_ALPHA && isALPHA(c->opts.src_format)) + return yuva2argb_c; + case AV_PIX_FMT_RGBA: + case AV_PIX_FMT_BGRA: + return (CONFIG_SWSCALE_ALPHA && isALPHA(c->opts.src_format)) ? yuva2rgba_c : yuv2rgb_c_32; + case AV_PIX_FMT_RGB24: + return yuv2rgb_c_24_rgb; + case AV_PIX_FMT_BGR24: + return yuv2rgb_c_24_bgr; + case AV_PIX_FMT_RGB565: + case AV_PIX_FMT_BGR565: + return yuv2rgb_c_16_ordered_dither; + case AV_PIX_FMT_RGB555: + case AV_PIX_FMT_BGR555: + return yuv2rgb_c_15_ordered_dither; + case AV_PIX_FMT_RGB444: + case AV_PIX_FMT_BGR444: + return yuv2rgb_c_12_ordered_dither; + case AV_PIX_FMT_RGB8: + case AV_PIX_FMT_BGR8: + return yuv2rgb_c_8_ordered_dither; + case AV_PIX_FMT_RGB4: + case AV_PIX_FMT_BGR4: + return yuv2rgb_c_4_ordered_dither; + case AV_PIX_FMT_RGB4_BYTE: + case AV_PIX_FMT_BGR4_BYTE: + return yuv2rgb_c_4b_ordered_dither; + case AV_PIX_FMT_MONOBLACK: + return yuv2rgb_c_1_ordered_dither; + case AV_PIX_FMT_GBRP: + return yuv420p_gbrp_c; + } + } + return NULL; +} + +static void fill_table(uint8_t* table[256 + 2*YUVRGB_TABLE_HEADROOM], const int elemsize, + const int64_t inc, void *y_tab) +{ + int i; + uint8_t *y_table = y_tab; + + y_table -= elemsize * (inc >> 9); + + for (i = 0; i < 256 + 2*YUVRGB_TABLE_HEADROOM; i++) { + int64_t cb = av_clip_uint8(i-YUVRGB_TABLE_HEADROOM)*inc; + table[i] = y_table + elemsize * (cb >> 16); + } +} + +static void fill_gv_table(int table[256 + 2*YUVRGB_TABLE_HEADROOM], const int elemsize, const int64_t inc) +{ + int i; + int off = -(inc >> 9); + + for (i = 0; i < 256 + 2*YUVRGB_TABLE_HEADROOM; i++) { + int64_t cb = av_clip_uint8(i-YUVRGB_TABLE_HEADROOM)*inc; + table[i] = elemsize * (off + (cb >> 16)); + } +} + +static uint16_t roundToInt16(int64_t f) +{ + int r = (f + (1 << 15)) >> 16; + + if (r < -0x7FFF) + return 0x8000; + else if (r > 0x7FFF) + return 0x7FFF; + else + return r; +} + +av_cold int ff_yuv2rgb_c_init_tables(SwsInternal *c, const int inv_table[4], + int fullRange, int brightness, + int contrast, int saturation) +{ + const int isRgb = c->opts.dst_format == AV_PIX_FMT_RGB32 || + c->opts.dst_format == AV_PIX_FMT_RGB32_1 || + c->opts.dst_format == AV_PIX_FMT_BGR24 || + c->opts.dst_format == AV_PIX_FMT_RGB565BE || + c->opts.dst_format == AV_PIX_FMT_RGB565LE || + c->opts.dst_format == AV_PIX_FMT_RGB555BE || + c->opts.dst_format == AV_PIX_FMT_RGB555LE || + c->opts.dst_format == AV_PIX_FMT_RGB444BE || + c->opts.dst_format == AV_PIX_FMT_RGB444LE || + c->opts.dst_format == AV_PIX_FMT_X2RGB10BE || + c->opts.dst_format == AV_PIX_FMT_X2RGB10LE || + c->opts.dst_format == AV_PIX_FMT_RGB8 || + c->opts.dst_format == AV_PIX_FMT_RGB4 || + c->opts.dst_format == AV_PIX_FMT_RGB4_BYTE || + c->opts.dst_format == AV_PIX_FMT_MONOBLACK; + const int isNotNe = c->opts.dst_format == AV_PIX_FMT_NE(RGB565LE, RGB565BE) || + c->opts.dst_format == AV_PIX_FMT_NE(RGB555LE, RGB555BE) || + c->opts.dst_format == AV_PIX_FMT_NE(RGB444LE, RGB444BE) || + c->opts.dst_format == AV_PIX_FMT_NE(BGR565LE, BGR565BE) || + c->opts.dst_format == AV_PIX_FMT_NE(BGR555LE, BGR555BE) || + c->opts.dst_format == AV_PIX_FMT_NE(BGR444LE, BGR444BE) || + c->opts.dst_format == AV_PIX_FMT_NE(X2RGB10LE, X2RGB10BE) || + c->opts.dst_format == AV_PIX_FMT_NE(X2BGR10LE, X2BGR10BE); + const int bpp = c->dstFormatBpp; + uint8_t *y_table; + uint16_t *y_table16; + uint32_t *y_table32; + int i, base, rbase, gbase, bbase, av_uninit(abase), needAlpha; + const int yoffs = (fullRange ? 384 : 326) + YUVRGB_TABLE_LUMA_HEADROOM; + const int table_plane_size = 1024 + 2*YUVRGB_TABLE_LUMA_HEADROOM; + + int64_t crv = inv_table[0]; + int64_t cbu = inv_table[1]; + int64_t cgu = -inv_table[2]; + int64_t cgv = -inv_table[3]; + int64_t cy = 1 << 16; + int64_t oy = 0; + int64_t yb = 0; + + if (!fullRange) { + cy = (cy * 255) / 219; + oy = 16 << 16; + } else { + crv = (crv * 224) / 255; + cbu = (cbu * 224) / 255; + cgu = (cgu * 224) / 255; + cgv = (cgv * 224) / 255; + } + + cy = (cy * contrast) >> 16; + crv = (crv * contrast * saturation) >> 32; + cbu = (cbu * contrast * saturation) >> 32; + cgu = (cgu * contrast * saturation) >> 32; + cgv = (cgv * contrast * saturation) >> 32; + oy -= 256LL * brightness; + + c->uOffset = 0x0400040004000400LL; + c->vOffset = 0x0400040004000400LL; + c->yCoeff = roundToInt16(cy * (1 << 13)) * 0x0001000100010001ULL; + c->vrCoeff = roundToInt16(crv * (1 << 13)) * 0x0001000100010001ULL; + c->ubCoeff = roundToInt16(cbu * (1 << 13)) * 0x0001000100010001ULL; + c->vgCoeff = roundToInt16(cgv * (1 << 13)) * 0x0001000100010001ULL; + c->ugCoeff = roundToInt16(cgu * (1 << 13)) * 0x0001000100010001ULL; + c->yOffset = roundToInt16(oy * (1 << 3)) * 0x0001000100010001ULL; + + c->yuv2rgb_y_coeff = (int16_t)roundToInt16(cy * (1 << 13)); + c->yuv2rgb_y_offset = (int16_t)roundToInt16(oy * (1 << 9)); + c->yuv2rgb_v2r_coeff = (int16_t)roundToInt16(crv * (1 << 13)); + c->yuv2rgb_v2g_coeff = (int16_t)roundToInt16(cgv * (1 << 13)); + c->yuv2rgb_u2g_coeff = (int16_t)roundToInt16(cgu * (1 << 13)); + c->yuv2rgb_u2b_coeff = (int16_t)roundToInt16(cbu * (1 << 13)); + + //scale coefficients by cy + crv = ((crv * (1 << 16)) + 0x8000) / FFMAX(cy, 1); + cbu = ((cbu * (1 << 16)) + 0x8000) / FFMAX(cy, 1); + cgu = ((cgu * (1 << 16)) + 0x8000) / FFMAX(cy, 1); + cgv = ((cgv * (1 << 16)) + 0x8000) / FFMAX(cy, 1); + + av_freep(&c->yuvTable); + +#define ALLOC_YUV_TABLE(x) \ + c->yuvTable = av_malloc(x); \ + if (!c->yuvTable) \ + return AVERROR(ENOMEM); + switch (bpp) { + case 1: + ALLOC_YUV_TABLE(table_plane_size); + y_table = c->yuvTable; + yb = -(384 << 16) - YUVRGB_TABLE_LUMA_HEADROOM*cy - oy; + for (i = 0; i < table_plane_size - 110; i++) { + y_table[i + 110] = av_clip_uint8((yb + 0x8000) >> 16) >> 7; + yb += cy; + } + fill_table(c->table_gU, 1, cgu, y_table + yoffs); + fill_gv_table(c->table_gV, 1, cgv); + break; + case 4: + case 4 | 128: + rbase = isRgb ? 3 : 0; + gbase = 1; + bbase = isRgb ? 0 : 3; + ALLOC_YUV_TABLE(table_plane_size * 3); + y_table = c->yuvTable; + yb = -(384 << 16) - YUVRGB_TABLE_LUMA_HEADROOM*cy - oy; + for (i = 0; i < table_plane_size - 110; i++) { + int yval = av_clip_uint8((yb + 0x8000) >> 16); + y_table[i + 110] = (yval >> 7) << rbase; + y_table[i + 37 + table_plane_size] = ((yval + 43) / 85) << gbase; + y_table[i + 110 + 2*table_plane_size] = (yval >> 7) << bbase; + yb += cy; + } + fill_table(c->table_rV, 1, crv, y_table + yoffs); + fill_table(c->table_gU, 1, cgu, y_table + yoffs + table_plane_size); + fill_table(c->table_bU, 1, cbu, y_table + yoffs + 2*table_plane_size); + fill_gv_table(c->table_gV, 1, cgv); + break; + case 8: + rbase = isRgb ? 5 : 0; + gbase = isRgb ? 2 : 3; + bbase = isRgb ? 0 : 6; + ALLOC_YUV_TABLE(table_plane_size * 3); + y_table = c->yuvTable; + yb = -(384 << 16) - YUVRGB_TABLE_LUMA_HEADROOM*cy - oy; + for (i = 0; i < table_plane_size - 38; i++) { + int yval = av_clip_uint8((yb + 0x8000) >> 16); + y_table[i + 16] = ((yval + 18) / 36) << rbase; + y_table[i + 16 + table_plane_size] = ((yval + 18) / 36) << gbase; + y_table[i + 37 + 2*table_plane_size] = ((yval + 43) / 85) << bbase; + yb += cy; + } + fill_table(c->table_rV, 1, crv, y_table + yoffs); + fill_table(c->table_gU, 1, cgu, y_table + yoffs + table_plane_size); + fill_table(c->table_bU, 1, cbu, y_table + yoffs + 2*table_plane_size); + fill_gv_table(c->table_gV, 1, cgv); + break; + case 12: + rbase = isRgb ? 8 : 0; + gbase = 4; + bbase = isRgb ? 0 : 8; + ALLOC_YUV_TABLE(table_plane_size * 3 * 2); + y_table16 = c->yuvTable; + yb = -(384 << 16) - YUVRGB_TABLE_LUMA_HEADROOM*cy - oy; + for (i = 0; i < table_plane_size; i++) { + uint8_t yval = av_clip_uint8((yb + 0x8000) >> 16); + y_table16[i] = (yval >> 4) << rbase; + y_table16[i + table_plane_size] = (yval >> 4) << gbase; + y_table16[i + 2*table_plane_size] = (yval >> 4) << bbase; + yb += cy; + } + if (isNotNe) + for (i = 0; i < table_plane_size * 3; i++) + y_table16[i] = av_bswap16(y_table16[i]); + fill_table(c->table_rV, 2, crv, y_table16 + yoffs); + fill_table(c->table_gU, 2, cgu, y_table16 + yoffs + table_plane_size); + fill_table(c->table_bU, 2, cbu, y_table16 + yoffs + 2*table_plane_size); + fill_gv_table(c->table_gV, 2, cgv); + break; + case 15: + case 16: + rbase = isRgb ? bpp - 5 : 0; + gbase = 5; + bbase = isRgb ? 0 : (bpp - 5); + ALLOC_YUV_TABLE(table_plane_size * 3 * 2); + y_table16 = c->yuvTable; + yb = -(384 << 16) - YUVRGB_TABLE_LUMA_HEADROOM*cy - oy; + for (i = 0; i < table_plane_size; i++) { + uint8_t yval = av_clip_uint8((yb + 0x8000) >> 16); + y_table16[i] = (yval >> 3) << rbase; + y_table16[i + table_plane_size] = (yval >> (18 - bpp)) << gbase; + y_table16[i + 2*table_plane_size] = (yval >> 3) << bbase; + yb += cy; + } + if (isNotNe) + for (i = 0; i < table_plane_size * 3; i++) + y_table16[i] = av_bswap16(y_table16[i]); + fill_table(c->table_rV, 2, crv, y_table16 + yoffs); + fill_table(c->table_gU, 2, cgu, y_table16 + yoffs + table_plane_size); + fill_table(c->table_bU, 2, cbu, y_table16 + yoffs + 2*table_plane_size); + fill_gv_table(c->table_gV, 2, cgv); + break; + case 24: + case 48: + ALLOC_YUV_TABLE(table_plane_size); + y_table = c->yuvTable; + yb = -(384 << 16) - YUVRGB_TABLE_LUMA_HEADROOM*cy - oy; + for (i = 0; i < table_plane_size; i++) { + y_table[i] = av_clip_uint8((yb + 0x8000) >> 16); + yb += cy; + } + fill_table(c->table_rV, 1, crv, y_table + yoffs); + fill_table(c->table_gU, 1, cgu, y_table + yoffs); + fill_table(c->table_bU, 1, cbu, y_table + yoffs); + fill_gv_table(c->table_gV, 1, cgv); + break; + case 30: + rbase = isRgb ? 20 : 0; + gbase = 10; + bbase = isRgb ? 0 : 20; + needAlpha = CONFIG_SWSCALE_ALPHA && isALPHA(c->opts.src_format); + if (!needAlpha) + abase = 30; + ALLOC_YUV_TABLE(table_plane_size * 3 * 4); + y_table32 = c->yuvTable; + yb = -(384 << 16) - YUVRGB_TABLE_LUMA_HEADROOM*cy - oy; + for (i = 0; i < table_plane_size; i++) { + unsigned yval = av_clip_uintp2((yb + 0x8000) >> 14, 10); + y_table32[i]= (yval << rbase) + (needAlpha ? 0 : (255u << abase)); + y_table32[i + table_plane_size] = yval << gbase; + y_table32[i + 2 * table_plane_size] = yval << bbase; + yb += cy; + } + if (isNotNe) { + for (i = 0; i < table_plane_size * 3; i++) + y_table32[i] = av_bswap32(y_table32[i]); + } + fill_table(c->table_rV, 4, crv, y_table32 + yoffs); + fill_table(c->table_gU, 4, cgu, y_table32 + yoffs + table_plane_size); + fill_table(c->table_bU, 4, cbu, y_table32 + yoffs + 2 * table_plane_size); + fill_gv_table(c->table_gV, 4, cgv); + break; + case 32: + case 64: + base = (c->opts.dst_format == AV_PIX_FMT_RGB32_1 || + c->opts.dst_format == AV_PIX_FMT_BGR32_1) ? 8 : 0; + rbase = base + (isRgb ? 16 : 0); + gbase = base + 8; + bbase = base + (isRgb ? 0 : 16); + needAlpha = CONFIG_SWSCALE_ALPHA && isALPHA(c->opts.src_format); + if (!needAlpha) + abase = (base + 24) & 31; + ALLOC_YUV_TABLE(table_plane_size * 3 * 4); + y_table32 = c->yuvTable; + yb = -(384 << 16) - YUVRGB_TABLE_LUMA_HEADROOM*cy - oy; + for (i = 0; i < table_plane_size; i++) { + unsigned yval = av_clip_uint8((yb + 0x8000) >> 16); + y_table32[i] = (yval << rbase) + + (needAlpha ? 0 : (255u << abase)); + y_table32[i + table_plane_size] = yval << gbase; + y_table32[i + 2*table_plane_size] = yval << bbase; + yb += cy; + } + fill_table(c->table_rV, 4, crv, y_table32 + yoffs); + fill_table(c->table_gU, 4, cgu, y_table32 + yoffs + table_plane_size); + fill_table(c->table_bU, 4, cbu, y_table32 + yoffs + 2*table_plane_size); + fill_gv_table(c->table_gV, 4, cgv); + break; + default: + if(!isPlanar(c->opts.dst_format) || bpp <= 24) + av_log(c, AV_LOG_ERROR, "%ibpp not supported by yuv2rgb\n", bpp); + return AVERROR(EINVAL); + } + return 0; +} -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11111